Workspace.md
Workspace
type: module path: "@root/src/PuduLangMcp/Services/Workspace.pudu" fidelity: Active domain: "[[domain/Workspace]]" grammar: "[[grammar/pudu]]" depth_score: 0.6 depth_status: DEEP coupling: 2 interface_stability: 0.85 tags: [module, deep, critical] aliases: [Workspace]
Purpose
Confine path arguments to the workspace, show paths relative to it, and give inline source a private place to exist for the length of one command ([[decisions/ADR-0004-workspace-confinement]]).
Interface
Signatures
export type Workspace = { root: Str }
export type Target = { directory: Str, file: Str, source: Str, scratch: Bool } // absolute paths
export fn fromEnvironment() -> Workspace
export fn at(root: Str) -> Workspace
export fn resolve(workspace: &Workspace, path: Str) -> Result[Str, ToolError.ToolFailure]
export fn relative(workspace: &Workspace, path: Str) -> Str
export fn withTarget[T](workspace: &Workspace, source: Option[Str], path: Option[Str], use: fn(Target) -> T) -> Result[T, ToolError.ToolFailure]Linkage
- Requires: [[src/PuduLangMcp/Domain/Code/SourceFile]], [[src/PuduLangMcp/Errors/ToolError]], [[src/PuduLangMcp/Constants/Server]],
Std.Fs,Std.Io,Std.Env,Std.Path. - Consumed by: [[src/Main]],
App/Tools/*.
Algorithm
fromEnvironment:PUDU_MCP_ROOTwhen set, else.; canonicalized.resolve:Fs.resolveInside(root, path); any refusal or missing path isOutsideWorkspace(path).relative:Path.relativeTowhen the path is inside the root, else the path unchanged.withTarget:path: resolved as above; the file must end in.pudu(OutsideWorkspaceotherwise, since only source files are read);directoryis the workspace root, and the file's text is read.source: a new directory under the system temporary directory, prefixpudu-mcp-; the source is written at the path its module name implies ([[src/PuduLangMcp/Domain/Code/SourceFile]]),Main.puduwhen it declares none.useruns with that target and the directory is removed afterwards, whateveruseanswered.
Negative Logic (Prohibited Paths)
- Nothing is ever written inside the workspace.
- A symbolic link inside the workspace pointing outside it is refused (resolution follows links).
Edge Cases
pathnaming a directory is refused here;pudu_testresolves directories itself withresolve.
Depth
DEPTH 0.6 (DEEP).
Grill Log
- Q: Delete the scratch directory even when the command failed? A: Yes;
useanswers a value rather than failing, so removal always runs after it.
Referenced by
[[src/PuduLangMcp/Services/_MOC]] · [[domain/Workspace]]
