@warlock.js/ai-workspace 5.30.0 → 5.32.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 (120) hide show
  1. package/CHANGELOG.md +52 -2
  2. package/README.md +34 -21
  3. package/cjs/index.cjs +3134 -315
  4. package/cjs/index.cjs.map +1 -1
  5. package/esm/backends/local.d.mts +1 -3
  6. package/esm/backends/local.d.mts.map +1 -1
  7. package/esm/backends/local.mjs +166 -28
  8. package/esm/backends/local.mjs.map +1 -1
  9. package/esm/backends/mock.d.mts +14 -9
  10. package/esm/backends/mock.d.mts.map +1 -1
  11. package/esm/backends/mock.mjs +34 -0
  12. package/esm/backends/mock.mjs.map +1 -1
  13. package/esm/contracts/index.d.mts +5 -4
  14. package/esm/contracts/tool-io.type.d.mts +216 -19
  15. package/esm/contracts/tool-io.type.d.mts.map +1 -1
  16. package/esm/contracts/workspace-backend.contract.d.mts +62 -4
  17. package/esm/contracts/workspace-backend.contract.d.mts.map +1 -1
  18. package/esm/contracts/workspace-ops.contract.d.mts +33 -6
  19. package/esm/contracts/workspace-ops.contract.d.mts.map +1 -1
  20. package/esm/contracts/workspace-policy.type.d.mts +136 -16
  21. package/esm/contracts/workspace-policy.type.d.mts.map +1 -1
  22. package/esm/contracts/workspace.contract.d.mts +65 -13
  23. package/esm/contracts/workspace.contract.d.mts.map +1 -1
  24. package/esm/errors.d.mts +103 -17
  25. package/esm/errors.d.mts.map +1 -1
  26. package/esm/errors.mjs +22 -1
  27. package/esm/errors.mjs.map +1 -1
  28. package/esm/index.d.mts +14 -5
  29. package/esm/index.mjs +10 -2
  30. package/esm/ops.d.mts +21 -3
  31. package/esm/ops.d.mts.map +1 -1
  32. package/esm/ops.mjs +230 -64
  33. package/esm/ops.mjs.map +1 -1
  34. package/esm/policy/jail.mjs +73 -0
  35. package/esm/policy/jail.mjs.map +1 -0
  36. package/esm/policy/policy.d.mts +30 -20
  37. package/esm/policy/policy.d.mts.map +1 -1
  38. package/esm/policy/policy.mjs +64 -87
  39. package/esm/policy/policy.mjs.map +1 -1
  40. package/esm/policy/shell-check.d.mts +63 -0
  41. package/esm/policy/shell-check.d.mts.map +1 -0
  42. package/esm/policy/shell-check.mjs +638 -0
  43. package/esm/policy/shell-check.mjs.map +1 -0
  44. package/esm/policy/shell-parser.mjs +802 -0
  45. package/esm/policy/shell-parser.mjs.map +1 -0
  46. package/esm/policy/tokenize-command.d.mts +62 -0
  47. package/esm/policy/tokenize-command.d.mts.map +1 -0
  48. package/esm/policy/tokenize-command.mjs +76 -24
  49. package/esm/policy/tokenize-command.mjs.map +1 -1
  50. package/esm/shell-jobs.d.mts +45 -0
  51. package/esm/shell-jobs.d.mts.map +1 -0
  52. package/esm/shell-jobs.mjs +247 -0
  53. package/esm/shell-jobs.mjs.map +1 -0
  54. package/esm/todos.d.mts +22 -0
  55. package/esm/todos.d.mts.map +1 -0
  56. package/esm/todos.mjs +73 -0
  57. package/esm/todos.mjs.map +1 -0
  58. package/esm/tools/edit-file.d.mts +2 -3
  59. package/esm/tools/edit-file.d.mts.map +1 -1
  60. package/esm/tools/edit-file.mjs +2 -1
  61. package/esm/tools/edit-file.mjs.map +1 -1
  62. package/esm/tools/glob.d.mts +3 -4
  63. package/esm/tools/glob.d.mts.map +1 -1
  64. package/esm/tools/glob.mjs +2 -1
  65. package/esm/tools/glob.mjs.map +1 -1
  66. package/esm/tools/grep.d.mts +3 -4
  67. package/esm/tools/grep.d.mts.map +1 -1
  68. package/esm/tools/grep.mjs +2 -1
  69. package/esm/tools/grep.mjs.map +1 -1
  70. package/esm/tools/json-schemas.mjs +175 -0
  71. package/esm/tools/json-schemas.mjs.map +1 -0
  72. package/esm/tools/list-dir.d.mts +31 -0
  73. package/esm/tools/list-dir.d.mts.map +1 -0
  74. package/esm/tools/list-dir.mjs +50 -0
  75. package/esm/tools/list-dir.mjs.map +1 -0
  76. package/esm/tools/multi-edit.d.mts +37 -0
  77. package/esm/tools/multi-edit.d.mts.map +1 -0
  78. package/esm/tools/multi-edit.mjs +121 -0
  79. package/esm/tools/multi-edit.mjs.map +1 -0
  80. package/esm/tools/read-file.d.mts +2 -3
  81. package/esm/tools/read-file.d.mts.map +1 -1
  82. package/esm/tools/read-file.mjs +2 -1
  83. package/esm/tools/read-file.mjs.map +1 -1
  84. package/esm/tools/run-shell.d.mts +36 -15
  85. package/esm/tools/run-shell.d.mts.map +1 -1
  86. package/esm/tools/run-shell.mjs +59 -53
  87. package/esm/tools/run-shell.mjs.map +1 -1
  88. package/esm/tools/run-tests.d.mts +11 -4
  89. package/esm/tools/run-tests.d.mts.map +1 -1
  90. package/esm/tools/run-tests.mjs +10 -3
  91. package/esm/tools/run-tests.mjs.map +1 -1
  92. package/esm/tools/schema.mjs +23 -18
  93. package/esm/tools/schema.mjs.map +1 -1
  94. package/esm/tools/shell-kill.d.mts +24 -0
  95. package/esm/tools/shell-kill.d.mts.map +1 -0
  96. package/esm/tools/shell-kill.mjs +36 -0
  97. package/esm/tools/shell-kill.mjs.map +1 -0
  98. package/esm/tools/shell-output.d.mts +29 -0
  99. package/esm/tools/shell-output.d.mts.map +1 -0
  100. package/esm/tools/shell-output.mjs +49 -0
  101. package/esm/tools/shell-output.mjs.map +1 -0
  102. package/esm/tools/todo.d.mts +42 -0
  103. package/esm/tools/todo.d.mts.map +1 -0
  104. package/esm/tools/todo.mjs +126 -0
  105. package/esm/tools/todo.mjs.map +1 -0
  106. package/esm/tools/write-file.d.mts +2 -3
  107. package/esm/tools/write-file.d.mts.map +1 -1
  108. package/esm/tools/write-file.mjs +2 -1
  109. package/esm/tools/write-file.mjs.map +1 -1
  110. package/esm/workspace.d.mts +14 -11
  111. package/esm/workspace.d.mts.map +1 -1
  112. package/esm/workspace.mjs +108 -27
  113. package/esm/workspace.mjs.map +1 -1
  114. package/llms-full.txt +155 -34
  115. package/llms.txt +1 -1
  116. package/package.json +3 -3
  117. package/skills/README.md +2 -2
  118. package/skills/build-loop-agent/SKILL.md +7 -7
  119. package/skills/index.md +6 -1
  120. package/skills/use-a-workspace/SKILL.md +148 -27
@@ -1,6 +1,6 @@
1
1
  //#region ../../packages/ai-workspace/src/contracts/tool-io.type.d.ts
2
2
  /**
3
- * Input/output shapes for the seven workspace tools and the direct
3
+ * Input/output shapes for the workspace tools and the direct
4
4
  * methods that back them. These are the wire contracts the agent sees
5
5
  * (via each tool's schema) and the values the policy-enforced ops layer
6
6
  * returns. Paths in every `*Input` are workspace-relative; the policy
@@ -10,9 +10,9 @@
10
10
  * The discriminating set of tool names a workspace can vend, used by
11
11
  * `tools.pick(...)` to select a least-privilege subset.
12
12
  */
13
- type WorkspaceToolName = "readFile" | "editFile" | "writeFile" | "runShell" | "runTests" | "grep" | "glob";
13
+ export type WorkspaceToolName = "readFile" | "editFile" | "multiEdit" | "writeFile" | "listDir" | "runShell" | "shellOutput" | "shellKill" | "runTests" | "grep" | "glob" | "todoWrite" | "todoRead";
14
14
  /** Input to the `read_file` tool / `readFile()` direct method. */
15
- interface ReadFileInput {
15
+ export interface ReadFileInput {
16
16
  /** Workspace-relative path to read. */
17
17
  path: string;
18
18
  /** 1-based line to start from. Omit to start at the top. */
@@ -32,7 +32,7 @@ interface ReadFileInput {
32
32
  * returned line may be partial — clipped on a character boundary, never
33
33
  * mid-character — and `bytesCapped` is `true`.
34
34
  */
35
- interface ReadFileResult {
35
+ export interface ReadFileResult {
36
36
  /** The returned, line-numbered file content for the requested window. */
37
37
  content: string;
38
38
  /** 1-based first line requested. */
@@ -65,7 +65,7 @@ interface ReadFileResult {
65
65
  * Input to the `edit_file` tool / `editFile()` direct method — an
66
66
  * exact-string replacement with a read-before-edit stale guard.
67
67
  */
68
- interface EditFileInput {
68
+ export interface EditFileInput {
69
69
  /** Workspace-relative path to edit. */
70
70
  path: string;
71
71
  /** Exact substring to replace; must be unique unless `replaceAll`. */
@@ -78,7 +78,7 @@ interface EditFileInput {
78
78
  expectHash?: string;
79
79
  }
80
80
  /** Result of a successful edit. */
81
- interface EditFileResult {
81
+ export interface EditFileResult {
82
82
  /** Workspace-relative path that was edited. */
83
83
  path: string;
84
84
  /** Number of occurrences replaced. */
@@ -86,15 +86,49 @@ interface EditFileResult {
86
86
  /** SHA-256 of the file content after the edit. */
87
87
  hash: string;
88
88
  }
89
+ /** One replacement inside a {@link MultiEditInput}. */
90
+ export interface MultiEditOperation {
91
+ /** Exact substring to replace; must be unique unless `replaceAll`. */
92
+ oldString: string;
93
+ /** Replacement text. */
94
+ newString: string;
95
+ /** Replace every occurrence instead of requiring a single unique match. */
96
+ replaceAll?: boolean;
97
+ }
98
+ /**
99
+ * Input to the `multi_edit` tool / `multiEdit()` direct method — several
100
+ * exact-string replacements in one file, applied in order (each edit sees
101
+ * the result of the previous ones) and written once. All of them apply or
102
+ * none do.
103
+ */
104
+ export interface MultiEditInput {
105
+ /** Workspace-relative path to edit. */
106
+ path: string;
107
+ /** The replacements, applied in order. At least one. */
108
+ edits: MultiEditOperation[];
109
+ /** Expected current SHA-256 of the file; a mismatch rejects every edit as stale. */
110
+ expectHash?: string;
111
+ }
112
+ /** Result of a successful multi-edit. */
113
+ export interface MultiEditResult {
114
+ /** Workspace-relative path that was edited. */
115
+ path: string;
116
+ /** Number of edits applied (always `edits.length`). */
117
+ edits: number;
118
+ /** Total occurrences replaced across every edit. */
119
+ replacements: number;
120
+ /** SHA-256 of the file content after all edits. */
121
+ hash: string;
122
+ }
89
123
  /** Input to the `write_file` tool / `writeFile()` direct method. */
90
- interface WriteFileInput {
124
+ export interface WriteFileInput {
91
125
  /** Workspace-relative path to write (created if absent). */
92
126
  path: string;
93
127
  /** Full file content to write atomically. */
94
128
  content: string;
95
129
  }
96
130
  /** Result of a write. */
97
- interface WriteFileResult {
131
+ export interface WriteFileResult {
98
132
  /** Workspace-relative path that was written. */
99
133
  path: string;
100
134
  /** Number of bytes written. */
@@ -103,7 +137,7 @@ interface WriteFileResult {
103
137
  hash: string;
104
138
  }
105
139
  /** Options for the `exec()` direct method. */
106
- interface ExecOptions {
140
+ export interface ExecOptions {
107
141
  /** Per-call wall-clock cap in ms; overrides the policy `shell.timeoutMs`. */
108
142
  timeoutMs?: number;
109
143
  /**
@@ -114,14 +148,108 @@ interface ExecOptions {
114
148
  signal?: AbortSignal;
115
149
  }
116
150
  /** Input to the `run_shell` tool / `exec()` direct method. */
117
- interface RunShellInput {
118
- /** The command line to run; its leading basename is policy-checked. */
151
+ export interface RunShellInput {
152
+ /** The command line to run; every command in it is policy-checked. */
119
153
  command: string;
120
154
  /** Per-call wall-clock cap (overrides the policy default if lower). */
121
155
  timeoutMs?: number;
156
+ /**
157
+ * Start the command as a background job and return its id at once,
158
+ * instead of waiting for it. Needs `shell.background` in the policy.
159
+ */
160
+ background?: boolean;
161
+ }
162
+ /**
163
+ * Lifecycle state of a background command.
164
+ *
165
+ * - `"running"` — still running.
166
+ * - `"exited"` — finished on its own; `exitCode` holds its exit code.
167
+ * - `"killed"` — stopped by `shell_kill` / `shellKill()` or `dispose()`.
168
+ * - `"timed-out"` — killed for exceeding `shell.background.timeoutMs` (or
169
+ * the per-call `timeoutMs`).
170
+ */
171
+ export type ShellJobStatus = "running" | "exited" | "killed" | "timed-out";
172
+ /** A background command owned by the workspace. */
173
+ export interface ShellJobInfo {
174
+ /** Workspace-unique id (`"job-1"`, `"job-2"`, …) for `shell_output` / `shell_kill`. */
175
+ id: string;
176
+ /** The command line it runs. */
177
+ command: string;
178
+ /** Lifecycle state. */
179
+ status: ShellJobStatus;
180
+ /** Exit code once it has stopped; `null` while running. */
181
+ exitCode: number | null;
182
+ /** OS process id of the direct child, when the backend has one. */
183
+ pid?: number;
184
+ /** ISO timestamp it was started. */
185
+ startedAt: string;
186
+ /** ISO timestamp it stopped, once it has. */
187
+ endedAt?: string;
188
+ }
189
+ /** What `run_shell` returns when called with `background: true`. */
190
+ export interface RunShellBackgroundResult extends ShellJobInfo {
191
+ /** Always `true` — tells this result apart from a foreground {@link RunShellResult}. */
192
+ background: true;
193
+ }
194
+ /** Options for `startShell()`. */
195
+ export interface StartShellOptions {
196
+ /**
197
+ * Wall-clock cap for this background command, in ms. Lowers
198
+ * `shell.background.timeoutMs` (never raises it); absent ⇒ the policy
199
+ * value, or no cap.
200
+ */
201
+ timeoutMs?: number;
202
+ }
203
+ /** Input to the `shell_output` tool. */
204
+ export interface ShellOutputInput {
205
+ /** The background command id `run_shell` returned. */
206
+ id: string;
207
+ /**
208
+ * Return only output produced after this `cursor` (from an earlier
209
+ * result). Omit to get everything since the previous read.
210
+ */
211
+ since?: number;
212
+ /**
213
+ * Wait up to this many ms (capped at 30 000) for new output or for the
214
+ * command to stop, when there is nothing new yet.
215
+ */
216
+ waitMs?: number;
217
+ }
218
+ /** Options for `shellOutput()`. */
219
+ export interface ShellOutputOptions {
220
+ /** See {@link ShellOutputInput.since}. */
221
+ since?: number;
222
+ /** See {@link ShellOutputInput.waitMs}. */
223
+ waitMs?: number;
224
+ /** Stops a `waitMs` wait early. */
225
+ signal?: AbortSignal;
226
+ }
227
+ /** New output of a background command plus its current state. */
228
+ export interface ShellOutputResult extends ShellJobInfo {
229
+ /** Standard output produced after `since`. */
230
+ stdout: string;
231
+ /** Standard error produced after `since`. */
232
+ stderr: string;
233
+ /**
234
+ * Total bytes the command has produced so far (both streams). Pass it as
235
+ * `since` to read only what comes next.
236
+ */
237
+ cursor: number;
238
+ /**
239
+ * Bytes produced after `since` that are no longer kept (the per-command
240
+ * buffer holds the newest `shell.maxOutputBytes`).
241
+ */
242
+ droppedBytes: number;
243
+ /** True when `droppedBytes > 0`. */
244
+ truncated: boolean;
245
+ }
246
+ /** Input to the `shell_kill` tool. */
247
+ export interface ShellKillInput {
248
+ /** The background command id to stop. */
249
+ id: string;
122
250
  }
123
251
  /** Result of a shell command — captured streams plus how it terminated. */
124
- interface RunShellResult {
252
+ export interface RunShellResult {
125
253
  /** Process exit code (non-zero ⇒ the command failed, not the tool). */
126
254
  exitCode: number;
127
255
  /** Captured standard output (byte-capped per policy). */
@@ -144,12 +272,12 @@ interface RunShellResult {
144
272
  * the workspace's configured test command, optionally narrowed to a
145
273
  * pattern (a path/suite filter passed through to the runner).
146
274
  */
147
- interface RunTestsInput {
275
+ export interface RunTestsInput {
148
276
  /** Optional path/name filter forwarded to the test runner. */
149
277
  pattern?: string;
150
278
  }
151
279
  /** Input to the `grep` tool / `grep()` direct method. */
152
- interface GrepInput {
280
+ export interface GrepInput {
153
281
  /** Regular-expression pattern to search file contents for. */
154
282
  pattern: string;
155
283
  /** Glob narrowing which files are scanned (e.g. `"src/api/*.ts"`). */
@@ -158,7 +286,7 @@ interface GrepInput {
158
286
  ignoreCase?: boolean;
159
287
  }
160
288
  /** A single matched line within a file. */
161
- interface GrepMatch {
289
+ export interface GrepMatch {
162
290
  /** Workspace-relative path of the file containing the match. */
163
291
  path: string;
164
292
  /** 1-based line number of the match. */
@@ -167,22 +295,91 @@ interface GrepMatch {
167
295
  text: string;
168
296
  }
169
297
  /** Result of a content search across the jailed file set. */
170
- interface GrepResult {
298
+ export interface GrepResult {
171
299
  /** Every matching line found, in file/line order. */
172
300
  matches: GrepMatch[];
173
301
  /** Total number of matches (== `matches.length` unless capped). */
174
302
  total: number;
175
303
  }
304
+ /** Input to the `list_dir` tool. */
305
+ export interface ListDirInput {
306
+ /** Workspace-relative directory to list. Default `"."` (the root). */
307
+ path?: string;
308
+ /** How many levels deep to list (1 = direct children). Default `1`. */
309
+ depth?: number;
310
+ /** Extra globs to leave out, on top of `list.ignore` and `denyPaths`. */
311
+ ignore?: string[];
312
+ }
313
+ /** Options for `listDir()`. */
314
+ export interface ListDirOptions {
315
+ /** See {@link ListDirInput.depth}. */
316
+ depth?: number;
317
+ /** See {@link ListDirInput.ignore}. */
318
+ ignore?: string[];
319
+ }
320
+ /** Kind of a listed entry. A symlink is reported, never followed. */
321
+ export type ListDirEntryType = "file" | "directory" | "symlink" | "other";
322
+ /** One entry of a directory listing. */
323
+ export interface ListDirEntry {
324
+ /** Workspace-relative path (absolute for a directory outside `cwd` in `allowPaths`). */
325
+ path: string;
326
+ /** Entry kind. */
327
+ type: ListDirEntryType;
328
+ /** Size in bytes, for files (when the backend reports it). */
329
+ size?: number;
330
+ /** 1 for a direct child of the listed directory, 2 for a grandchild, … */
331
+ depth: number;
332
+ }
333
+ /** Result of a directory listing. */
334
+ export interface ListDirResult {
335
+ /** The listed directory, workspace-relative (`"."` for the root). */
336
+ path: string;
337
+ /** Entries, breadth-first, each level sorted by name. */
338
+ entries: ListDirEntry[];
339
+ /** True when `list.maxEntries` cut the listing short. */
340
+ truncated: boolean;
341
+ }
176
342
  /** Input to the `glob` tool / `glob()` direct method. */
177
- interface GlobInput {
343
+ export interface GlobInput {
178
344
  /** Glob pattern resolved relative to `cwd` (e.g. `"src/api/*.ts"`). */
179
345
  pattern: string;
180
346
  }
181
347
  /** Result of a glob — the matched workspace-relative paths. */
182
- interface GlobResult {
348
+ export interface GlobResult {
183
349
  /** Workspace-relative paths matching the pattern, sorted. */
184
350
  paths: string[];
185
351
  }
352
+ /** State of one todo item. */
353
+ export type WorkspaceTodoStatus = "pending" | "in_progress" | "completed";
354
+ /** One item of the workspace's todo list. */
355
+ export interface WorkspaceTodo {
356
+ /** Stable id (assigned `"1"`, `"2"`, … when the writer omits it). */
357
+ id: string;
358
+ /** What the step is. */
359
+ content: string;
360
+ /** Its state. */
361
+ status: WorkspaceTodoStatus;
362
+ }
363
+ /** One item as written by `todo_write` / `writeTodos()` — `id` is optional. */
364
+ export interface WorkspaceTodoInput {
365
+ /** Stable id; omit to have one assigned from the item's position. */
366
+ id?: string;
367
+ /** What the step is (non-empty, at most 1 000 characters). */
368
+ content: string;
369
+ /** Its state. */
370
+ status: WorkspaceTodoStatus;
371
+ }
372
+ /** Input to the `todo_write` tool — the whole new list, replacing the old one. */
373
+ export interface TodoWriteInput {
374
+ /** The complete list (at most 100 items). An empty list clears it. */
375
+ todos: WorkspaceTodoInput[];
376
+ }
377
+ /** The todo list plus a count per status. */
378
+ export interface TodoListResult {
379
+ /** Every item, in order. */
380
+ todos: WorkspaceTodo[];
381
+ /** How many items are in each status. */
382
+ counts: Record<WorkspaceTodoStatus, number>;
383
+ }
186
384
  //#endregion
187
- export { EditFileInput, EditFileResult, ExecOptions, GlobInput, GlobResult, GrepInput, GrepMatch, GrepResult, ReadFileInput, ReadFileResult, RunShellInput, RunShellResult, RunTestsInput, WorkspaceToolName, WriteFileInput, WriteFileResult };
188
385
  //# sourceMappingURL=tool-io.type.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"tool-io.type.d.mts","names":[],"sources":["../../../../../../../../packages/ai-workspace/src/contracts/tool-io.type.ts"],"mappings":";;AAYA;;;;AAA6B;AAU7B;;;;;KAVY,iBAAA;;UAUK,aAAA;EAMV;EAJL,IAAA;EAmB6B;EAjB7B,SAAA;EAiB6B;EAf7B,KAAA;AAAA;;;;;;;;AA0CI;AAON;;;;UAlCiB,cAAA;EAsCf;EApCA,OAAA;EAwCA;EAtCA,SAAA;EAwCU;AAAA;AAIZ;;EAvCE,OAAA;EAuC6B;EArC7B,UAAA;EAyCA;;;AAEI;AAIN;EAzCE,SAAA;;EAEA,WAAA;EA2CO;EAzCP,UAAA;EA6C8B;;;;;EAvC9B,IAAA;AAAA;AA6CI;AAIN;;;AAJM,UAtCW,aAAA;EA4Cf;EA1CA,IAAA;EAgDS;EA9CT,SAAA;EA8CoB;EA5CpB,SAAA;EAgD4B;EA9C5B,UAAA;EAgDA;EA9CA,UAAA;AAAA;;UAIe,cAAA;EAgDc;EA9C7B,IAAA;EAkDA;EAhDA,YAAA;EAoDA;EAlDA,IAAA;AAAA;;UAIe,cAAA;EA8DA;EA5Df,IAAA;;EAEA,OAAO;AAAA;AAgET;AAAA,UA5DiB,eAAA;;EAEf,IAAA;EA4DA;EA1DA,YAAA;EA8DA;EA5DA,IAAA;AAAA;AAgEF;AAAA,UA5DiB,WAAA;;EAEf,SAAA;EA4DA;;;;AAII;EA1DJ,MAAA,GAAS,WAAW;AAAA;;UAIL,aAAA;EA4Df;EA1DA,OAAA;EA4DA;EA1DA,SAAS;AAAA;AA8DX;AAAA,UA1DiB,cAAA;;EAEf,QAAA;EA0DO;EAxDP,MAAA;EA4DyB;EA1DzB,MAAA;EA4DK;EA1DL,SAAA;;EAEA,QAAA;;;;;;EAMA,SAAA;AAAA;;;;;;UAQe,aAAA;;EAEf,OAAO;AAAA;;UAIQ,SAAA;;EAEf,OAAA;;EAEA,IAAA;;EAEA,UAAA;AAAA;;UAIe,SAAA;;EAEf,IAAA;;EAEA,IAAA;;EAEA,IAAA;AAAA;;UAIe,UAAA;;EAEf,OAAA,EAAS,SAAS;;EAElB,KAAA;AAAA;;UAIe,SAAA;;EAEf,OAAO;AAAA;;UAIQ,UAAA;;EAEf,KAAK;AAAA"}
1
+ {"version":3,"file":"tool-io.type.d.mts","names":[],"sources":["../../../../../../../../packages/ai-workspace/src/contracts/tool-io.type.ts"],"mappings":";;;;;;;;;;;;YAYY;;iBAgBK;;EAEf;;EAEA;;EAEA;;;;;;;;;;;;;;iBAee;;EAEf;;EAEA;;;;;EAKA;;EAEA;;;;;;EAMA;;EAEA;;EAEA;;;;;;EAMA;;;;;;iBAOe;;EAEf;;EAEA;;EAEA;;EAEA;;EAEA;;;iBAIe;;EAEf;;EAEA;;EAEA;;;iBAIe;;EAEf;;EAEA;;EAEA;;;;;;;;iBASe;;EAEf;;EAEA,OAAO;;EAEP;;;iBAIe;;EAEf;;EAEA;;EAEA;;EAEA;;;iBAIe;;EAEf;;EAEA;;;iBAIe;;EAEf;;EAEA;;EAEA;;;iBAIe;;EAEf;;;;;;EAMA,SAAS;;;iBAIM;;EAEf;;EAEA;;;;;EAKA;;;;;;;;;;;YAYU;;iBAGK;;EAEf;;EAEA;;EAEA,QAAQ;;EAER;;EAEA;;EAEA;;EAEA;;;iBAIe,iCAAiC;;EAEhD;;;iBAIe;;;;;;EAMf;;;iBAIe;;EAEf;;;;;EAKA;;;;;EAKA;;;iBAIe;;EAEf;;EAEA;;EAEA,SAAS;;;iBAIM,0BAA0B;;EAEzC;;EAEA;;;;;EAKA;;;;;EAKA;;EAEA;;;iBAIe;;EAEf;;;iBAIe;;EAEf;;EAEA;;EAEA;;EAEA;;EAEA;;;;;;EAMA;;;;;;;iBAQe;;EAEf;;;iBAIe;;EAEf;;EAEA;;EAEA;;;iBAIe;;EAEf;;EAEA;;EAEA;;;iBAIe;;EAEf,SAAS;;EAET;;;iBAIe;;EAEf;;EAEA;;EAEA;;;iBAIe;;EAEf;;EAEA;;;YAIU;;iBAGK;;EAEf;;EAEA,MAAM;;EAEN;;EAEA;;;iBAIe;;EAEf;;EAEA,SAAS;;EAET;;;iBAIe;;EAEf;;;iBAIe;;EAEf;;;YAIU;;iBAGK;;EAEf;;EAEA;;EAEA,QAAQ;;;iBAIO;;EAEf;;EAEA;;EAEA,QAAQ;;;iBAIO;;EAEf,OAAO;;;iBAIQ;;EAEf,OAAO;;EAEP,QAAQ,OAAO"}
@@ -1,3 +1,4 @@
1
+ import { WorkspaceShellInterpreter } from "./workspace-policy.type.mjs";
1
2
  //#region ../../packages/ai-workspace/src/contracts/workspace-backend.contract.d.ts
2
3
  /**
3
4
  * Low-level result of a backend command execution. Mirrors the shape the
@@ -5,7 +6,7 @@
5
6
  * byte-cap `truncated` flag (capping is an ops-layer concern, not the
6
7
  * raw executor's).
7
8
  */
8
- interface WorkspaceBackendExecResult {
9
+ export interface WorkspaceBackendExecResult {
9
10
  /** Process exit code. */
10
11
  exitCode: number;
11
12
  /** Captured standard output. */
@@ -27,7 +28,7 @@ interface WorkspaceBackendExecResult {
27
28
  * the effective environment and timeout from policy before handing them
28
29
  * down — the backend just runs what it is told.
29
30
  */
30
- interface WorkspaceBackendExecOptions {
31
+ export interface WorkspaceBackendExecOptions {
31
32
  /** Working directory for the spawned process (already jail-resolved). */
32
33
  cwd?: string;
33
34
  /** Wall-clock cap in ms; on expiry the process is SIGKILLed. */
@@ -43,6 +44,52 @@ interface WorkspaceBackendExecOptions {
43
44
  * backend.
44
45
  */
45
46
  signal?: AbortSignal;
47
+ /**
48
+ * How to run `command`: `"none"` (default) tokenizes it into an argv and
49
+ * spawns it without a shell; `"sh"` hands the whole line to `/bin/sh -c`
50
+ * (`cmd.exe /d /v:off /s /c` on Windows). The ops layer has already
51
+ * checked every command in the line against the policy; a backend that
52
+ * does not support `"sh"` must refuse the command rather than run it
53
+ * another way.
54
+ */
55
+ interpreter?: WorkspaceShellInterpreter;
56
+ }
57
+ /** Which stream a background command's output chunk came from. */
58
+ export type WorkspaceOutputStream = "stdout" | "stderr";
59
+ /** Options for {@link WorkspaceBackend.start}. */
60
+ export interface WorkspaceBackendStartOptions {
61
+ /** Working directory for the spawned process (already jail-resolved). */
62
+ cwd?: string;
63
+ /** Exact environment for the spawned process (NOT merged with process.env). */
64
+ env?: Record<string, string>;
65
+ /** See {@link WorkspaceBackendExecOptions.interpreter}. */
66
+ interpreter?: WorkspaceShellInterpreter;
67
+ /**
68
+ * Receives output as it arrives, decoded as UTF-8 and never split inside a
69
+ * character. Called synchronously or later — never after `done` settles.
70
+ */
71
+ onOutput(stream: WorkspaceOutputStream, chunk: string): void;
72
+ }
73
+ /** A running background command, as a backend hands it to the ops layer. */
74
+ export interface WorkspaceBackendProcess {
75
+ /** OS process id of the direct child, when there is one. */
76
+ readonly pid?: number;
77
+ /**
78
+ * Settles once the process has exited and its output has been delivered.
79
+ * Never rejects: a spawn failure resolves with exit code `127`.
80
+ */
81
+ readonly done: Promise<{
82
+ exitCode: number;
83
+ }>;
84
+ /** Kill the whole process tree. Idempotent; safe after it has exited. */
85
+ kill(): void;
86
+ }
87
+ /** What {@link WorkspaceBackend.stat} reports about a path (symlinks are not followed). */
88
+ export interface WorkspaceBackendStat {
89
+ /** Entry kind. */
90
+ type: "file" | "directory" | "symlink" | "other";
91
+ /** Size in bytes. */
92
+ size: number;
46
93
  }
47
94
  /**
48
95
  * The swappable executor a workspace runs on — the thin, **policy-agnostic**
@@ -62,7 +109,7 @@ interface WorkspaceBackendExecOptions {
62
109
  * const out = await backend.readFile("/srv/acme-api/src/index.ts");
63
110
  * const { exitCode } = await backend.exec("npm test", { cwd: "/srv/acme-api" });
64
111
  */
65
- interface WorkspaceBackend {
112
+ export interface WorkspaceBackend {
66
113
  /** Read a file's full UTF-8 content at an absolute path. */
67
114
  readFile(absPath: string): Promise<string>;
68
115
  /** Write full content to an absolute path (atomically where supported). */
@@ -79,7 +126,18 @@ interface WorkspaceBackend {
79
126
  realpath(absPath: string): Promise<string>;
80
127
  /** Run a command and capture its outcome. */
81
128
  exec(command: string, opts?: WorkspaceBackendExecOptions): Promise<WorkspaceBackendExecResult>;
129
+ /**
130
+ * Describe an absolute path without following a final symlink. Optional:
131
+ * without it, `list_dir` tells files from directories by trying to list
132
+ * them and reports no sizes.
133
+ */
134
+ stat?(absPath: string): Promise<WorkspaceBackendStat>;
135
+ /**
136
+ * Start a long-running command and return at once. Optional: without it,
137
+ * background commands are refused. The process must be its own process
138
+ * group (or equivalent) so `kill()` reaches every descendant.
139
+ */
140
+ start?(command: string, opts: WorkspaceBackendStartOptions): WorkspaceBackendProcess;
82
141
  }
83
142
  //#endregion
84
- export { WorkspaceBackend, WorkspaceBackendExecOptions, WorkspaceBackendExecResult };
85
143
  //# sourceMappingURL=workspace-backend.contract.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"workspace-backend.contract.d.mts","names":[],"sources":["../../../../../../../../packages/ai-workspace/src/contracts/workspace-backend.contract.ts"],"mappings":";;AAMA;;;;;UAAiB,0BAAA;EAMf;EAJA,QAAA;EAaA;EAXA,MAAA;EAWS;EATT,MAAA;EAiB0C;EAf1C,QAAA;EA8BoB;;;;;;EAvBpB,SAAA;AAAA;AAuBoB;AAqBtB;;;;AArBsB,UAfL,2BAAA;EA0CU;EAxCzB,GAAA;EA4CyB;EA1CzB,SAAA;EA8C2B;EA5C3B,GAAA,GAAM,MAAA;EAiDK;;;;;;;;EAxCX,MAAA,GAAS,WAAW;AAAA;;;;;;;;;;;;;;;;;;;UAqBL,gBAAA;EAkBb;EAhBF,QAAA,CAAS,OAAA,WAAkB,OAAA;EAiBhB;EAfX,SAAA,CAAU,OAAA,UAAiB,OAAA,WAAkB,OAAA;EAeR;EAbrC,MAAA,CAAO,OAAA,WAAkB,OAAA;;EAEzB,KAAA,CAAM,OAAA,WAAkB,OAAA;;EAExB,MAAA,CAAO,OAAA,WAAkB,OAAA;;EAEzB,IAAA,CAAK,MAAA,WAAiB,OAAA;;EAEtB,QAAA,CAAS,OAAA,WAAkB,OAAA;;EAE3B,IAAA,CACE,OAAA,UACA,IAAA,GAAO,2BAAA,GACN,OAAA,CAAQ,0BAAA;AAAA"}
1
+ {"version":3,"file":"workspace-backend.contract.d.mts","names":[],"sources":["../../../../../../../../packages/ai-workspace/src/contracts/workspace-backend.contract.ts"],"mappings":";;;;;;;;iBAQiB;;EAEf;;EAEA;;EAEA;;EAEA;;;;;;;EAOA;;;;;;;iBAQe;;EAEf;;EAEA;;EAEA,MAAM;;;;;;;;;EASN,SAAS;;;;;;;;;EAST,cAAc;;;YAIJ;;iBAGK;;EAEf;;EAEA,MAAM;;EAEN,cAAc;;;;;EAKd,SAAS,QAAQ,uBAAuB;;;iBAIzB;;WAEN;;;;;WAKA,MAAM;IAAU;;;EAEzB;;;iBAIe;;EAEf;;EAEA;;;;;;;;;;;;;;;;;;;;iBAqBe;;EAEf,SAAS,kBAAkB;;EAE3B,UAAU,iBAAiB,kBAAkB;;EAE7C,OAAO,kBAAkB;;EAEzB,MAAM,kBAAkB;;EAExB,OAAO,kBAAkB;;EAEzB,KAAK,iBAAiB;;EAEtB,SAAS,kBAAkB;;EAE3B,KAAK,iBAAiB,OAAO,8BAA8B,QAAQ;;;;;;EAMnE,MAAM,kBAAkB,QAAQ;;;;;;EAMhC,OAAO,iBAAiB,MAAM,+BAA+B"}
@@ -1,5 +1,4 @@
1
- import { EditFileInput, EditFileResult, ExecOptions, GrepResult, ReadFileResult, RunShellResult } from "./tool-io.type.mjs";
2
-
1
+ import { EditFileInput, EditFileResult, ExecOptions, GrepResult, ListDirOptions, ListDirResult, MultiEditInput, MultiEditResult, ReadFileResult, RunShellResult, ShellJobInfo, ShellOutputOptions, ShellOutputResult, StartShellOptions } from "./tool-io.type.mjs";
3
2
  //#region ../../packages/ai-workspace/src/contracts/workspace-ops.contract.d.ts
4
3
  /**
5
4
  * The **policy-enforced** operation layer that sits between the dumb
@@ -20,7 +19,7 @@ import { EditFileInput, EditFileResult, ExecOptions, GrepResult, ReadFileResult,
20
19
  * const { content, hash } = await ops.readFile("src/index.ts");
21
20
  * await ops.editFile({ path: "src/index.ts", oldString: "x", newString: "y", expectHash: hash });
22
21
  */
23
- interface WorkspaceOps {
22
+ export interface WorkspaceOps {
24
23
  /**
25
24
  * Read a jailed file, returning a numbered line window, the full file's
26
25
  * hash and the window metadata. `offset`/`limit` select a 1-based line
@@ -43,12 +42,35 @@ interface WorkspaceOps {
43
42
  */
44
43
  editFile(input: EditFileInput): Promise<EditFileResult>;
45
44
  /**
46
- * Run a shell command after gating its leading executable basename
47
- * against the shell allow/deny policy, with the policy environment,
45
+ * Apply several exact-string edits to one file atomically: each edit runs
46
+ * against the result of the previous ones, under the same uniqueness rules
47
+ * as `editFile`, and the file is written once — or, when any edit fails,
48
+ * not at all (`WorkspaceEditError` with `editIndex`).
49
+ */
50
+ multiEdit(input: MultiEditInput): Promise<MultiEditResult>;
51
+ /**
52
+ * Run a command line after checking every command in it against the
53
+ * shell policy (see `WorkspaceShellPolicy`), with the policy environment,
48
54
  * timeout, and output byte cap applied. `signal` cancels this one call
49
55
  * (see {@link ExecOptions}).
50
56
  */
51
57
  exec(command: string, opts?: ExecOptions): Promise<RunShellResult>;
58
+ /**
59
+ * Start a policy-checked command as a background job owned by the
60
+ * workspace and return at once. Needs `shell.background`.
61
+ */
62
+ startShell(command: string, opts?: StartShellOptions): Promise<ShellJobInfo>;
63
+ /** New output of a background command since `since` (default: the last read). */
64
+ shellOutput(id: string, opts?: ShellOutputOptions): Promise<ShellOutputResult>;
65
+ /** Kill a background command's whole process tree and report its final state. */
66
+ shellKill(id: string): Promise<ShellJobInfo>;
67
+ /** Every background command this workspace knows, oldest first. */
68
+ listShells(): ShellJobInfo[];
69
+ /**
70
+ * List a jailed directory — bounded by depth and `list.maxEntries`, with
71
+ * `denyPaths` and `list.ignore` left out and symlinks never followed.
72
+ */
73
+ listDir(path?: string, opts?: ListDirOptions): Promise<ListDirResult>;
52
74
  /** Search jailed file contents for a regex pattern. */
53
75
  grep(pattern: string, opts?: {
54
76
  glob?: string;
@@ -62,7 +84,12 @@ interface WorkspaceOps {
62
84
  mkdir(path: string): Promise<void>;
63
85
  /** Remove a file or directory tree at a jailed path. */
64
86
  remove(path: string): Promise<void>;
87
+ /**
88
+ * Kill every background command (whole process trees) and refuse new
89
+ * commands. A foreground command already running finishes on its own (or
90
+ * by its timeout / signal). Idempotent.
91
+ */
92
+ dispose(): Promise<void>;
65
93
  }
66
94
  //#endregion
67
- export { WorkspaceOps };
68
95
  //# sourceMappingURL=workspace-ops.contract.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"workspace-ops.contract.d.mts","names":[],"sources":["../../../../../../../../packages/ai-workspace/src/contracts/workspace-ops.contract.ts"],"mappings":";;;;;AA4BA;;;;;;;;;;;;;;;;;UAAiB,YAAA;EAiDc;;;;;;EA1C7B,QAAA,CACE,IAAA,UACA,IAAA;IAAS,MAAA;IAAiB,KAAA;EAAA,IACzB,OAAA,CAAQ,cAAA;EAIT;EADF,SAAA,CACE,IAAA,UACA,OAAA,WACC,OAAA;IAAU,IAAA;IAAc,YAAA;EAAA;EAO3B;;;;;EAAA,QAAA,CAAS,KAAA,EAAO,aAAA,GAAgB,OAAA,CAAQ,cAAA;EAQnC;;;;;;EAAL,IAAA,CAAK,OAAA,UAAiB,IAAA,GAAO,WAAA,GAAc,OAAA,CAAQ,cAAA;EAKxC;EAFX,IAAA,CACE,OAAA,UACA,IAAA;IAAS,IAAA;IAAe,UAAA;EAAA,IACvB,OAAA,CAAQ,UAAA;EAGX;EAAA,IAAA,CAAK,OAAA,WAAkB,OAAA;EAAA;EAGvB,MAAA,CAAO,IAAA,WAAe,OAAA;EAAf;EAGP,KAAA,CAAM,IAAA,WAAe,OAAA;EAArB;EAGA,MAAA,CAAO,IAAA,WAAe,OAAA;AAAA"}
1
+ {"version":3,"file":"workspace-ops.contract.d.mts","names":[],"sources":["../../../../../../../../packages/ai-workspace/src/contracts/workspace-ops.contract.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;iBAoCiB;;;;;;;EAOf,SAAS,cAAc;IAAS;IAAiB;MAAmB,QAAQ;;EAG5E,UAAU,cAAc,kBAAkB;IAAU;IAAc;;;;;;;EAOlE,SAAS,OAAO,gBAAgB,QAAQ;;;;;;;EAQxC,UAAU,OAAO,iBAAiB,QAAQ;;;;;;;EAQ1C,KAAK,iBAAiB,OAAO,cAAc,QAAQ;;;;;EAMnD,WAAW,iBAAiB,OAAO,oBAAoB,QAAQ;;EAG/D,YAAY,YAAY,OAAO,qBAAqB,QAAQ;;EAG5D,UAAU,aAAa,QAAQ;;EAG/B,cAAc;;;;;EAMd,QAAQ,eAAe,OAAO,iBAAiB,QAAQ;;EAGvD,KAAK,iBAAiB;IAAS;IAAe;MAAyB,QAAQ;;EAG/E,KAAK,kBAAkB;;EAGvB,OAAO,eAAe;;EAGtB,MAAM,eAAe;;EAGrB,OAAO,eAAe;;;;;;EAOtB,WAAW"}