@chances-ai/engine 26.0.0 → 28.0.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 (84) hide show
  1. package/dist/agents/bundled.d.ts +5 -0
  2. package/dist/agents/bundled.d.ts.map +1 -0
  3. package/dist/agents/bundled.js +66 -0
  4. package/dist/agents/bundled.js.map +1 -0
  5. package/dist/agents/index.d.ts +1 -0
  6. package/dist/agents/index.d.ts.map +1 -1
  7. package/dist/agents/index.js +1 -0
  8. package/dist/agents/index.js.map +1 -1
  9. package/dist/agents/parse.d.ts +3 -0
  10. package/dist/agents/parse.d.ts.map +1 -1
  11. package/dist/agents/parse.js +17 -0
  12. package/dist/agents/parse.js.map +1 -1
  13. package/dist/agents/types.d.ts +8 -0
  14. package/dist/agents/types.d.ts.map +1 -1
  15. package/dist/ai/adapters/ai-sdk-stream.d.ts.map +1 -1
  16. package/dist/ai/adapters/ai-sdk-stream.js +6 -1
  17. package/dist/ai/adapters/ai-sdk-stream.js.map +1 -1
  18. package/dist/ai/index.d.ts +1 -0
  19. package/dist/ai/index.d.ts.map +1 -1
  20. package/dist/ai/index.js +1 -0
  21. package/dist/ai/index.js.map +1 -1
  22. package/dist/ai/overflow.d.ts +40 -0
  23. package/dist/ai/overflow.d.ts.map +1 -0
  24. package/dist/ai/overflow.js +84 -0
  25. package/dist/ai/overflow.js.map +1 -0
  26. package/dist/ai/types.d.ts +8 -1
  27. package/dist/ai/types.d.ts.map +1 -1
  28. package/dist/core/coordinator-mode.d.ts +32 -0
  29. package/dist/core/coordinator-mode.d.ts.map +1 -0
  30. package/dist/core/coordinator-mode.js +98 -0
  31. package/dist/core/coordinator-mode.js.map +1 -0
  32. package/dist/core/coordinator-tools.d.ts +22 -0
  33. package/dist/core/coordinator-tools.d.ts.map +1 -0
  34. package/dist/core/coordinator-tools.js +262 -0
  35. package/dist/core/coordinator-tools.js.map +1 -0
  36. package/dist/core/engine.d.ts +235 -10
  37. package/dist/core/engine.d.ts.map +1 -1
  38. package/dist/core/engine.js +585 -274
  39. package/dist/core/engine.js.map +1 -1
  40. package/dist/core/index.d.ts +4 -2
  41. package/dist/core/index.d.ts.map +1 -1
  42. package/dist/core/index.js +3 -1
  43. package/dist/core/index.js.map +1 -1
  44. package/dist/core/task-tool.d.ts +85 -1
  45. package/dist/core/task-tool.d.ts.map +1 -1
  46. package/dist/core/task-tool.js +456 -494
  47. package/dist/core/task-tool.js.map +1 -1
  48. package/dist/session/index.d.ts +11 -0
  49. package/dist/session/index.d.ts.map +1 -1
  50. package/dist/session/index.js +22 -1
  51. package/dist/session/index.js.map +1 -1
  52. package/dist/tools/bash-readonly.d.ts +26 -0
  53. package/dist/tools/bash-readonly.d.ts.map +1 -0
  54. package/dist/tools/bash-readonly.js +130 -0
  55. package/dist/tools/bash-readonly.js.map +1 -0
  56. package/dist/tools/builtins/bash.d.ts.map +1 -1
  57. package/dist/tools/builtins/bash.js +12 -0
  58. package/dist/tools/builtins/bash.js.map +1 -1
  59. package/dist/tools/builtins/edit.d.ts.map +1 -1
  60. package/dist/tools/builtins/edit.js +18 -12
  61. package/dist/tools/builtins/edit.js.map +1 -1
  62. package/dist/tools/builtins/todo.d.ts +33 -0
  63. package/dist/tools/builtins/todo.d.ts.map +1 -0
  64. package/dist/tools/builtins/todo.js +245 -0
  65. package/dist/tools/builtins/todo.js.map +1 -0
  66. package/dist/tools/builtins/write.d.ts.map +1 -1
  67. package/dist/tools/builtins/write.js +10 -5
  68. package/dist/tools/builtins/write.js.map +1 -1
  69. package/dist/tools/concurrency.d.ts +37 -0
  70. package/dist/tools/concurrency.d.ts.map +1 -0
  71. package/dist/tools/concurrency.js +50 -0
  72. package/dist/tools/concurrency.js.map +1 -0
  73. package/dist/tools/file-lock.d.ts +22 -0
  74. package/dist/tools/file-lock.d.ts.map +1 -0
  75. package/dist/tools/file-lock.js +85 -0
  76. package/dist/tools/file-lock.js.map +1 -0
  77. package/dist/tools/index.d.ts +4 -0
  78. package/dist/tools/index.d.ts.map +1 -1
  79. package/dist/tools/index.js +4 -0
  80. package/dist/tools/index.js.map +1 -1
  81. package/dist/tools/types.d.ts +31 -0
  82. package/dist/tools/types.d.ts.map +1 -1
  83. package/dist/tools/types.js.map +1 -1
  84. package/package.json +3 -3
@@ -0,0 +1,245 @@
1
+ /** (7.7 §5) The phased todo tool. Op-based edits (init/start/done/rm/drop/
2
+ * append/note) over named phases, normalized to exactly one in_progress,
3
+ * rendered back to the model as markdown. Ported from oh-my-pi
4
+ * `coding-agent/src/tools/todo-write.ts`. State lives on the SessionManager
5
+ * (injected via the factory); the engine emits the `todo` AppEvent after a
6
+ * successful call so all four surfaces render the panel. */
7
+ export const TODO_TOOL_NAME = "todo";
8
+ const STATUS_TO_MARKER = {
9
+ pending: " ",
10
+ in_progress: "/",
11
+ completed: "x",
12
+ abandoned: "-",
13
+ };
14
+ /** Deep-clone phases so op application never mutates the live session array. */
15
+ function clone(phases) {
16
+ return phases.map((p) => ({ name: p.name, tasks: p.tasks.map((t) => ({ ...t, notes: t.notes ? [...t.notes] : undefined })) }));
17
+ }
18
+ function findPhase(phases, name) {
19
+ if (name === undefined)
20
+ return phases[0];
21
+ return phases.find((p) => p.name === name);
22
+ }
23
+ function findTask(phases, content) {
24
+ for (const p of phases) {
25
+ const hit = p.tasks.find((t) => t.content === content);
26
+ if (hit)
27
+ return hit;
28
+ }
29
+ return undefined;
30
+ }
31
+ /** Enforce the invariant: when any task is still open, EXACTLY one is in_progress
32
+ * (oh-my-pi `normalizeInProgressTask`). Keep the first in_progress, demote the
33
+ * rest to pending; if none, promote the first pending. */
34
+ function normalizeInProgress(phases) {
35
+ const open = [];
36
+ for (const p of phases)
37
+ for (const t of p.tasks)
38
+ if (t.status === "in_progress" || t.status === "pending")
39
+ open.push(t);
40
+ const inProgress = open.filter((t) => t.status === "in_progress");
41
+ if (inProgress.length > 1) {
42
+ for (const t of inProgress.slice(1))
43
+ t.status = "pending";
44
+ }
45
+ else if (inProgress.length === 0) {
46
+ const firstPending = open.find((t) => t.status === "pending");
47
+ if (firstPending)
48
+ firstPending.status = "in_progress";
49
+ }
50
+ }
51
+ /** Apply one op. Returns an error string on a bad op, or null on success. */
52
+ function applyOp(phases, e) {
53
+ // Reject synthetic ids — tasks are referenced by content (oh-my-pi).
54
+ if (e.task && /^task-\d+$/.test(e.task)) {
55
+ return `tasks are referenced by their content text, not ids like "${e.task}"`;
56
+ }
57
+ switch (e.op) {
58
+ case "init": {
59
+ const name = e.phase ?? "Tasks";
60
+ const items = e.items ?? [];
61
+ const phase = { name, tasks: items.map((c) => ({ content: c, status: "pending" })) };
62
+ phases.length = 0;
63
+ phases.push(phase);
64
+ return null;
65
+ }
66
+ case "append": {
67
+ const name = e.phase ?? phases[phases.length - 1]?.name ?? "Tasks";
68
+ let phase = findPhase(phases, name);
69
+ if (!phase) {
70
+ phase = { name, tasks: [] };
71
+ phases.push(phase);
72
+ }
73
+ for (const c of e.items ?? []) {
74
+ if (phase.tasks.some((t) => t.content === c))
75
+ continue; // skip duplicates
76
+ phase.tasks.push({ content: c, status: "pending" });
77
+ }
78
+ return null;
79
+ }
80
+ case "start": {
81
+ if (!e.task)
82
+ return "start requires a task";
83
+ const t = findTask(phases, e.task);
84
+ if (!t)
85
+ return `no such task: ${e.task}`;
86
+ for (const p of phases)
87
+ for (const x of p.tasks)
88
+ if (x.status === "in_progress")
89
+ x.status = "pending";
90
+ t.status = "in_progress";
91
+ return null;
92
+ }
93
+ case "done":
94
+ case "drop": {
95
+ if (!e.task)
96
+ return `${e.op} requires a task`;
97
+ const t = findTask(phases, e.task);
98
+ if (!t)
99
+ return `no such task: ${e.task}`;
100
+ t.status = e.op === "done" ? "completed" : "abandoned";
101
+ return null;
102
+ }
103
+ case "rm": {
104
+ if (!e.task)
105
+ return "rm requires a task";
106
+ let removed = false;
107
+ for (const p of phases) {
108
+ const i = p.tasks.findIndex((t) => t.content === e.task);
109
+ if (i >= 0) {
110
+ p.tasks.splice(i, 1);
111
+ removed = true;
112
+ break;
113
+ }
114
+ }
115
+ return removed ? null : `no such task: ${e.task}`;
116
+ }
117
+ case "note": {
118
+ if (!e.task)
119
+ return "note requires a task";
120
+ if (!e.text)
121
+ return "note requires text";
122
+ const t = findTask(phases, e.task);
123
+ if (!t)
124
+ return `no such task: ${e.task}`;
125
+ (t.notes ??= []).push(e.text.trim());
126
+ return null;
127
+ }
128
+ default:
129
+ return `unknown op: ${String(e.op)}`;
130
+ }
131
+ }
132
+ /** Render phases as markdown (model-facing result + the basis for the `/todo`
133
+ * slash editor in task 12). */
134
+ export function phasesToMarkdown(phases) {
135
+ if (phases.length === 0)
136
+ return "(no todos)";
137
+ const out = [];
138
+ for (const p of phases) {
139
+ out.push(`# ${p.name}`);
140
+ for (const t of p.tasks) {
141
+ out.push(`- [${STATUS_TO_MARKER[t.status]}] ${t.content}`);
142
+ for (const n of t.notes ?? [])
143
+ out.push(` > ${n}`);
144
+ }
145
+ }
146
+ return out.join("\n");
147
+ }
148
+ function summarize(phases) {
149
+ let total = 0;
150
+ let done = 0;
151
+ for (const p of phases)
152
+ for (const t of p.tasks) {
153
+ total++;
154
+ if (t.status === "completed" || t.status === "abandoned")
155
+ done++;
156
+ }
157
+ return `${done}/${total} tasks complete\n\n${phasesToMarkdown(phases)}`;
158
+ }
159
+ /** Parse the raw args into ops, tolerating a single-op shorthand. */
160
+ function parseOps(args) {
161
+ const a = args;
162
+ const raw = Array.isArray(a.ops) ? a.ops : null;
163
+ if (!raw)
164
+ return { error: "todo requires an `ops` array" };
165
+ const ops = [];
166
+ for (const r of raw) {
167
+ if (typeof r !== "object" || r === null)
168
+ return { error: "each op must be an object" };
169
+ const o = r;
170
+ if (typeof o.op !== "string")
171
+ return { error: "each op needs an `op` field" };
172
+ ops.push({
173
+ op: o.op,
174
+ phase: typeof o.phase === "string" ? o.phase : undefined,
175
+ task: typeof o.task === "string" ? o.task : undefined,
176
+ items: Array.isArray(o.items) ? o.items.filter((x) => typeof x === "string") : undefined,
177
+ text: typeof o.text === "string" ? o.text : undefined,
178
+ });
179
+ }
180
+ return ops;
181
+ }
182
+ /** (7.7 §5) Apply a batch of ops to a starting state, normalizing once at the
183
+ * end. Exported so the engine reminder + (later) the `/todo` slash share it. */
184
+ export function applyTodoOps(start, ops) {
185
+ const phases = clone(start);
186
+ for (const e of ops) {
187
+ const err = applyOp(phases, e);
188
+ if (err)
189
+ return { phases: start, error: err };
190
+ }
191
+ normalizeInProgress(phases);
192
+ return { phases };
193
+ }
194
+ export function createTodoTool(deps) {
195
+ return {
196
+ name: TODO_TOOL_NAME,
197
+ description: "Track multi-step work as a phased checklist the user sees live. Send op-based edits: " +
198
+ "init {phase, items} (replace the plan), append {phase, items}, start {task}, done {task}, " +
199
+ "drop {task} (abandon), rm {task}, note {task, text}. Reference tasks by their exact content " +
200
+ "text, not ids. Exactly one task is in_progress at a time (auto-normalized). Use this to plan " +
201
+ "before a multi-step task and to mark progress as you go.",
202
+ category: "file-read", // plan mode permits it (read-tier), like oh-my-pi approval:'read'
203
+ parameters: {
204
+ type: "object",
205
+ properties: {
206
+ ops: {
207
+ type: "array",
208
+ description: "Ordered batch of todo operations.",
209
+ items: {
210
+ type: "object",
211
+ properties: {
212
+ op: { type: "string", enum: ["init", "start", "done", "rm", "drop", "append", "note"] },
213
+ phase: { type: "string" },
214
+ task: { type: "string" },
215
+ items: { type: "array", items: { type: "string" } },
216
+ text: { type: "string" },
217
+ },
218
+ required: ["op"],
219
+ },
220
+ },
221
+ },
222
+ required: ["ops"],
223
+ },
224
+ summarize: (args) => {
225
+ const parsed = parseOps(args);
226
+ if ("error" in parsed)
227
+ return "todo (invalid)";
228
+ return `todo: ${parsed.map((o) => o.op).join(", ")}`;
229
+ },
230
+ // (7.7 §3.1) The todo tool is read-tier but state-MUTATING, so it must run
231
+ // exclusively (never coalesced into a parallel batch).
232
+ isConcurrencySafe: () => false,
233
+ async execute(args) {
234
+ const parsed = parseOps(args);
235
+ if ("error" in parsed)
236
+ return { ok: false, output: parsed.error };
237
+ const { phases, error } = applyTodoOps(deps.getPhases(), parsed);
238
+ if (error)
239
+ return { ok: false, output: error };
240
+ deps.setPhases(phases);
241
+ return { ok: true, output: summarize(phases) };
242
+ },
243
+ };
244
+ }
245
+ //# sourceMappingURL=todo.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"todo.js","sourceRoot":"","sources":["../../../src/tools/builtins/todo.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"write.d.ts","sourceRoot":"","sources":["../../../src/tools/builtins/write.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,IAAI,EAAc,MAAM,aAAa,CAAC;AAGpD,eAAO,MAAM,SAAS,EAAE,IAsCvB,CAAC"}
1
+ {"version":3,"file":"write.d.ts","sourceRoot":"","sources":["../../../src/tools/builtins/write.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,IAAI,EAAc,MAAM,aAAa,CAAC;AAGpD,eAAO,MAAM,SAAS,EAAE,IA0CvB,CAAC"}
@@ -2,6 +2,7 @@ import { existsSync, readFileSync, statSync } from "node:fs";
2
2
  import { dirname } from "node:path";
3
3
  import { native } from "@chances-ai/native";
4
4
  import { linesDiff } from "../diff.js";
5
+ import { withFileLock } from "../file-lock.js";
5
6
  import { PREVIEW_BYTE_CAP, containWritePath, guardWrite, str, writeFileAtomic } from "./_shared.js";
6
7
  export const writeTool = {
7
8
  name: "write",
@@ -37,11 +38,15 @@ export const writeTool = {
37
38
  },
38
39
  async execute(args, ctx) {
39
40
  const path = guardWrite(ctx, str(args, "path"));
40
- writeFileAtomic(path, str(args, "content"));
41
- // Drop the shared fs-scan cache for this dir so a later glob/ast in the
42
- // same turn sees the new file ([10.4]).
43
- native.invalidateFsScanCache(dirname(path));
44
- return { ok: true, output: `Wrote ${str(args, "path")}` };
41
+ // (7.7 §3.4) Serialize concurrent writes to the same file via the per-file
42
+ // mutation lock (cross-subagent safety; reads never lock).
43
+ return withFileLock(path, async () => {
44
+ writeFileAtomic(path, str(args, "content"));
45
+ // Drop the shared fs-scan cache for this dir so a later glob/ast in the
46
+ // same turn sees the new file ([10.4]).
47
+ native.invalidateFsScanCache(dirname(path));
48
+ return { ok: true, output: `Wrote ${str(args, "path")}` };
49
+ });
45
50
  },
46
51
  };
47
52
  //# sourceMappingURL=write.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"write.js","sourceRoot":"","sources":["../../../src/tools/builtins/write.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAC7D,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAC5C,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAEvC,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,UAAU,EAAE,GAAG,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAEpG,MAAM,CAAC,MAAM,SAAS,GAAS;IAC7B,IAAI,EAAE,OAAO;IACb,WAAW,EAAE,8CAA8C;IAC3D,QAAQ,EAAE,YAAY;IACtB,UAAU,EAAE;QACV,IAAI,EAAE,QAAQ;QACd,UAAU,EAAE,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE;QACrE,QAAQ,EAAE,CAAC,MAAM,EAAE,SAAS,CAAC;KAC9B;IACD,SAAS,EAAE,CAAC,IAAI,EAAE,GAAG,EAAE,EAAE;QACvB,MAAM,IAAI,GAAG,GAAG,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QAC/B,MAAM,OAAO,GAAG,GAAG,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;QACrC,IAAI,GAAG,GAAkB,IAAI,CAAC;QAC9B,IAAI,CAAC;YACH,GAAG,GAAG,gBAAgB,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;QACpC,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,SAAS,IAAI,KAAK,OAAO,CAAC,MAAM,SAAS,CAAC;QACnD,CAAC;QACD,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;YACrB,MAAM,SAAS,GAAG,OAAO,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC;YAClE,OAAO,UAAU,IAAI,KAAK,OAAO,CAAC,MAAM,WAAW,SAAS,SAAS,CAAC;QACxE,CAAC;QACD,MAAM,SAAS,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;QACrC,IAAI,SAAS,GAAG,gBAAgB,IAAI,OAAO,CAAC,MAAM,GAAG,gBAAgB,EAAE,CAAC;YACtE,OAAO,aAAa,IAAI,KAAK,SAAS,MAAM,OAAO,CAAC,MAAM,+BAA+B,CAAC;QAC5F,CAAC;QACD,MAAM,MAAM,GAAG,YAAY,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;QACzC,IAAI,MAAM,KAAK,OAAO;YAAE,OAAO,aAAa,IAAI,eAAe,CAAC;QAChE,OAAO,aAAa,IAAI,KAAK,SAAS,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC;IAC5D,CAAC;IACD,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG;QACrB,MAAM,IAAI,GAAG,UAAU,CAAC,GAAG,EAAE,GAAG,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC;QAChD,eAAe,CAAC,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC,CAAC;QAC5C,wEAAwE;QACxE,wCAAwC;QACxC,MAAM,CAAC,qBAAqB,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;QAC5C,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,GAAG,CAAC,IAAI,EAAE,MAAM,CAAC,EAAE,EAAE,CAAC;IAC5D,CAAC;CACF,CAAC"}
1
+ {"version":3,"file":"write.js","sourceRoot":"","sources":["../../../src/tools/builtins/write.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,37 @@
1
+ import type { JSONValue } from "@chances-ai/runtime";
2
+ import type { ToolCallRequest } from "../ai/types.js";
3
+ import type { Tool } from "./types.js";
4
+ /** One contiguous run of tool calls that execute together. `safe` batches run
5
+ * concurrently (bounded); `!safe` batches run serially (each unsafe call is its
6
+ * own batch). Batch order — and call order within a batch — is submission
7
+ * order. */
8
+ export interface ToolBatch {
9
+ safe: boolean;
10
+ calls: ToolCallRequest[];
11
+ }
12
+ /**
13
+ * (7.7 §3.3) Order-preserving partition of one assistant turn's tool calls into
14
+ * execution batches (claude-code `partitionToolCalls`,
15
+ * `toolOrchestration.ts:106-131`). A concurrency-safe call coalesces onto the
16
+ * previous batch ONLY if that batch is also safe; any unsafe call starts a fresh
17
+ * batch. Therefore a write is never reordered before a preceding read, and the
18
+ * result order is deterministic.
19
+ */
20
+ export declare function partitionToolCalls(calls: readonly ToolCallRequest[], isSafe: (call: ToolCallRequest) => boolean): ToolBatch[];
21
+ /**
22
+ * (7.7 §3.1) Decide whether a single tool call may run in a parallel batch.
23
+ *
24
+ * Precedence:
25
+ * 1. If the tool implements `isConcurrencySafe(args)`, use it (with a
26
+ * fail-closed try/catch — any throw ⇒ not safe, matching claude-code's
27
+ * `partitionToolCalls`).
28
+ * 2. Otherwise derive from `category`: read-only categories (file-read /
29
+ * search / memory-read / network-read) are safe; write / shell /
30
+ * integration are not.
31
+ *
32
+ * Fail-closed by construction: the worst a wrong answer can do is force a
33
+ * read-only call to run serially (lost parallelism), never run a mutating call
34
+ * concurrently.
35
+ */
36
+ export declare function isCallConcurrencySafe(tool: Tool, args: JSONValue): boolean;
37
+ //# sourceMappingURL=concurrency.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"concurrency.d.ts","sourceRoot":"","sources":["../../src/tools/concurrency.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACtD,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAGvC;;;aAGa;AACb,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,OAAO,CAAC;IACd,KAAK,EAAE,eAAe,EAAE,CAAC;CAC1B;AAED;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,SAAS,eAAe,EAAE,EACjC,MAAM,EAAE,CAAC,IAAI,EAAE,eAAe,KAAK,OAAO,GACzC,SAAS,EAAE,CAYb;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,SAAS,GAAG,OAAO,CAS1E"}
@@ -0,0 +1,50 @@
1
+ import { READONLY_CATEGORIES } from "./types.js";
2
+ /**
3
+ * (7.7 §3.3) Order-preserving partition of one assistant turn's tool calls into
4
+ * execution batches (claude-code `partitionToolCalls`,
5
+ * `toolOrchestration.ts:106-131`). A concurrency-safe call coalesces onto the
6
+ * previous batch ONLY if that batch is also safe; any unsafe call starts a fresh
7
+ * batch. Therefore a write is never reordered before a preceding read, and the
8
+ * result order is deterministic.
9
+ */
10
+ export function partitionToolCalls(calls, isSafe) {
11
+ const batches = [];
12
+ for (const call of calls) {
13
+ const safe = isSafe(call);
14
+ const last = batches[batches.length - 1];
15
+ if (safe && last?.safe) {
16
+ last.calls.push(call);
17
+ }
18
+ else {
19
+ batches.push({ safe, calls: [call] });
20
+ }
21
+ }
22
+ return batches;
23
+ }
24
+ /**
25
+ * (7.7 §3.1) Decide whether a single tool call may run in a parallel batch.
26
+ *
27
+ * Precedence:
28
+ * 1. If the tool implements `isConcurrencySafe(args)`, use it (with a
29
+ * fail-closed try/catch — any throw ⇒ not safe, matching claude-code's
30
+ * `partitionToolCalls`).
31
+ * 2. Otherwise derive from `category`: read-only categories (file-read /
32
+ * search / memory-read / network-read) are safe; write / shell /
33
+ * integration are not.
34
+ *
35
+ * Fail-closed by construction: the worst a wrong answer can do is force a
36
+ * read-only call to run serially (lost parallelism), never run a mutating call
37
+ * concurrently.
38
+ */
39
+ export function isCallConcurrencySafe(tool, args) {
40
+ if (tool.isConcurrencySafe) {
41
+ try {
42
+ return tool.isConcurrencySafe(args) === true;
43
+ }
44
+ catch {
45
+ return false;
46
+ }
47
+ }
48
+ return READONLY_CATEGORIES.has(tool.category);
49
+ }
50
+ //# sourceMappingURL=concurrency.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"concurrency.js","sourceRoot":"","sources":["../../src/tools/concurrency.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAWjD;;;;;;;GAOG;AACH,MAAM,UAAU,kBAAkB,CAChC,KAAiC,EACjC,MAA0C;IAE1C,MAAM,OAAO,GAAgB,EAAE,CAAC;IAChC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC;QAC1B,MAAM,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QACzC,IAAI,IAAI,IAAI,IAAI,EAAE,IAAI,EAAE,CAAC;YACvB,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACxB,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACxC,CAAC;IACH,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,qBAAqB,CAAC,IAAU,EAAE,IAAe;IAC/D,IAAI,IAAI,CAAC,iBAAiB,EAAE,CAAC;QAC3B,IAAI,CAAC;YACH,OAAO,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,KAAK,IAAI,CAAC;QAC/C,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;IACD,OAAO,mBAAmB,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;AAChD,CAAC"}
@@ -0,0 +1,22 @@
1
+ /** Normalises a path to a stable lock key. realpath collapses symlinks; ENOENT
2
+ * (not-yet-created file) falls back to the absolute lexical path. */
3
+ export declare function fileLockKey(path: string): string;
4
+ /**
5
+ * Acquire the mutation lock for `path`. Returns a one-shot `release`. ALWAYS
6
+ * release in a `finally` so a throwing critical section can't deadlock the
7
+ * file:
8
+ *
9
+ * ```ts
10
+ * const release = await acquireFileLock(path);
11
+ * try { ... read-modify-write ... } finally { release(); }
12
+ * ```
13
+ */
14
+ export declare function acquireFileLock(path: string): Promise<() => void>;
15
+ /**
16
+ * Convenience wrapper: run `fn` while holding the lock for `path`, releasing on
17
+ * any exit (success or throw).
18
+ */
19
+ export declare function withFileLock<T>(path: string, fn: () => Promise<T>): Promise<T>;
20
+ /** Test-only: drop all lock state. Not exported from the package barrel. */
21
+ export declare function __resetFileLocks(): void;
22
+ //# sourceMappingURL=file-lock.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-lock.d.ts","sourceRoot":"","sources":["../../src/tools/file-lock.ts"],"names":[],"mappings":"AAsCA;sEACsE;AACtE,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAOhD;AAaD;;;;;;;;;GASG;AACH,wBAAsB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,CAAC,CAEvE;AAED;;;GAGG;AACH,wBAAsB,YAAY,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAOpF;AAED,4EAA4E;AAC5E,wBAAgB,gBAAgB,IAAI,IAAI,CAEvC"}
@@ -0,0 +1,85 @@
1
+ import { realpathSync } from "node:fs";
2
+ import { resolve as resolvePath } from "node:path";
3
+ /**
4
+ * (7.7 §3.4) Process-global per-file mutation lock. Mutating tools (write /
5
+ * edit / mutating bash; task 09 hashline reuses this) wrap their
6
+ * read-modify-write critical section in it so two edits to the SAME file
7
+ * serialize — across concurrent tool batches, across turns, and (the real
8
+ * motivation) across concurrent subagents in task 08. **Read tools never take
9
+ * the lock**: in opencode's words, the read/write partition *is* "did you ask
10
+ * for the lock" (`tool/edit.ts:35-45`).
11
+ *
12
+ * Keyed by realpath so two symlinks / aliases to one inode collapse to a single
13
+ * lock. A not-yet-created file (ENOENT) falls back to its lexically-resolved
14
+ * absolute path, which is stable for the same target string
15
+ * (opencode `filesystem.ts:219-227`).
16
+ *
17
+ * Intra-turn same-file writes are already serialized by the loop's ordered
18
+ * partition (each unsafe call is its own serial batch). This lock covers the
19
+ * cross-turn / cross-agent races the partition can't see.
20
+ */
21
+ /** A single-permit async mutex: `acquire()` resolves to a one-shot release. */
22
+ class Mutex {
23
+ tail = Promise.resolve();
24
+ acquire() {
25
+ let release;
26
+ const next = new Promise((r) => {
27
+ release = r;
28
+ });
29
+ const prior = this.tail;
30
+ this.tail = this.tail.then(() => next);
31
+ // The caller may proceed once everything queued before it has released.
32
+ return prior.then(() => release);
33
+ }
34
+ }
35
+ /** Normalises a path to a stable lock key. realpath collapses symlinks; ENOENT
36
+ * (not-yet-created file) falls back to the absolute lexical path. */
37
+ export function fileLockKey(path) {
38
+ const abs = resolvePath(path);
39
+ try {
40
+ return realpathSync(abs);
41
+ }
42
+ catch {
43
+ return abs;
44
+ }
45
+ }
46
+ const locks = new Map();
47
+ function mutexFor(key) {
48
+ let m = locks.get(key);
49
+ if (!m) {
50
+ m = new Mutex();
51
+ locks.set(key, m);
52
+ }
53
+ return m;
54
+ }
55
+ /**
56
+ * Acquire the mutation lock for `path`. Returns a one-shot `release`. ALWAYS
57
+ * release in a `finally` so a throwing critical section can't deadlock the
58
+ * file:
59
+ *
60
+ * ```ts
61
+ * const release = await acquireFileLock(path);
62
+ * try { ... read-modify-write ... } finally { release(); }
63
+ * ```
64
+ */
65
+ export async function acquireFileLock(path) {
66
+ return mutexFor(fileLockKey(path)).acquire();
67
+ }
68
+ /**
69
+ * Convenience wrapper: run `fn` while holding the lock for `path`, releasing on
70
+ * any exit (success or throw).
71
+ */
72
+ export async function withFileLock(path, fn) {
73
+ const release = await acquireFileLock(path);
74
+ try {
75
+ return await fn();
76
+ }
77
+ finally {
78
+ release();
79
+ }
80
+ }
81
+ /** Test-only: drop all lock state. Not exported from the package barrel. */
82
+ export function __resetFileLocks() {
83
+ locks.clear();
84
+ }
85
+ //# sourceMappingURL=file-lock.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-lock.js","sourceRoot":"","sources":["../../src/tools/file-lock.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,WAAW,CAAC;AAEnD;;;;;;;;;;;;;;;;;GAiBG;AAEH,+EAA+E;AAC/E,MAAM,KAAK;IACD,IAAI,GAAkB,OAAO,CAAC,OAAO,EAAE,CAAC;IAEhD,OAAO;QACL,IAAI,OAAoB,CAAC;QACzB,MAAM,IAAI,GAAG,IAAI,OAAO,CAAO,CAAC,CAAC,EAAE,EAAE;YACnC,OAAO,GAAG,CAAC,CAAC;QACd,CAAC,CAAC,CAAC;QACH,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC;QACxB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;QACvC,wEAAwE;QACxE,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,CAAC;IACnC,CAAC;CACF;AAED;sEACsE;AACtE,MAAM,UAAU,WAAW,CAAC,IAAY;IACtC,MAAM,GAAG,GAAG,WAAW,CAAC,IAAI,CAAC,CAAC;IAC9B,IAAI,CAAC;QACH,OAAO,YAAY,CAAC,GAAG,CAAC,CAAC;IAC3B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,GAAG,CAAC;IACb,CAAC;AACH,CAAC;AAED,MAAM,KAAK,GAAG,IAAI,GAAG,EAAiB,CAAC;AAEvC,SAAS,QAAQ,CAAC,GAAW;IAC3B,IAAI,CAAC,GAAG,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IACvB,IAAI,CAAC,CAAC,EAAE,CAAC;QACP,CAAC,GAAG,IAAI,KAAK,EAAE,CAAC;QAChB,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;IACpB,CAAC;IACD,OAAO,CAAC,CAAC;AACX,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,IAAY;IAChD,OAAO,QAAQ,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC;AAC/C,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAAI,IAAY,EAAE,EAAoB;IACtE,MAAM,OAAO,GAAG,MAAM,eAAe,CAAC,IAAI,CAAC,CAAC;IAC5C,IAAI,CAAC;QACH,OAAO,MAAM,EAAE,EAAE,CAAC;IACpB,CAAC;YAAS,CAAC;QACT,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED,4EAA4E;AAC5E,MAAM,UAAU,gBAAgB;IAC9B,KAAK,CAAC,KAAK,EAAE,CAAC;AAChB,CAAC"}
@@ -1,10 +1,14 @@
1
1
  export type { Tool, ToolContext, ToolLspHost, ToolResult, ToolCategory, PermissionRequest, AuthorizationRequest, QuestionRequest, QuestionSpec, QuestionOption, PermissionResolver, PermissionDecision, AuthorizationDecision, QuestionDecision, } from "./types.js";
2
2
  export { ASK_USER_QUESTION_TOOL_NAME, READONLY_CATEGORIES } from "./types.js";
3
+ export { type ToolBatch, isCallConcurrencySafe, partitionToolCalls } from "./concurrency.js";
4
+ export { isBashCommandReadOnly } from "./bash-readonly.js";
5
+ export { acquireFileLock, fileLockKey, withFileLock } from "./file-lock.js";
3
6
  export { ToolRegistry } from "./registry.js";
4
7
  export { type PermissionCacheScope, type PermissionEvaluation, PermissionGate } from "./permission.js";
5
8
  export { CATEGORY_TIER, isAutoApprovedByMode, isBlockedByMode, modeBlockReason, } from "./approval.js";
6
9
  export { builtinTools } from "./builtins.js";
7
10
  export { type CreatePtyToolDeps, createPtyTool } from "./builtins/pty.js";
11
+ export { type CreateTodoToolDeps, TODO_TOOL_NAME, createTodoTool, applyTodoOps, phasesToMarkdown, } from "./builtins/todo.js";
8
12
  export { cleanOutput, persistFullOutput, stripAnsi } from "./builtins/_shared.js";
9
13
  export { linesDiff, diffStats } from "./diff.js";
10
14
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,IAAI,EACJ,WAAW,EACX,WAAW,EACX,UAAU,EACV,YAAY,EACZ,iBAAiB,EACjB,oBAAoB,EACpB,eAAe,EACf,YAAY,EACZ,cAAc,EACd,kBAAkB,EAClB,kBAAkB,EAClB,qBAAqB,EACrB,gBAAgB,GACjB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,2BAA2B,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAC9E,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC7C,OAAO,EAAE,KAAK,oBAAoB,EAAE,KAAK,oBAAoB,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACvG,OAAO,EACL,aAAa,EACb,oBAAoB,EACpB,eAAe,EACf,eAAe,GAChB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC7C,OAAO,EAAE,KAAK,iBAAiB,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAC1E,OAAO,EAAE,WAAW,EAAE,iBAAiB,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAClF,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,IAAI,EACJ,WAAW,EACX,WAAW,EACX,UAAU,EACV,YAAY,EACZ,iBAAiB,EACjB,oBAAoB,EACpB,eAAe,EACf,YAAY,EACZ,cAAc,EACd,kBAAkB,EAClB,kBAAkB,EAClB,qBAAqB,EACrB,gBAAgB,GACjB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,2BAA2B,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAC9E,OAAO,EAAE,KAAK,SAAS,EAAE,qBAAqB,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAC7F,OAAO,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAC3D,OAAO,EAAE,eAAe,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC5E,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC7C,OAAO,EAAE,KAAK,oBAAoB,EAAE,KAAK,oBAAoB,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACvG,OAAO,EACL,aAAa,EACb,oBAAoB,EACpB,eAAe,EACf,eAAe,GAChB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC7C,OAAO,EAAE,KAAK,iBAAiB,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAC1E,OAAO,EACL,KAAK,kBAAkB,EACvB,cAAc,EACd,cAAc,EACd,YAAY,EACZ,gBAAgB,GACjB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,WAAW,EAAE,iBAAiB,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAClF,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC"}
@@ -1,9 +1,13 @@
1
1
  export { ASK_USER_QUESTION_TOOL_NAME, READONLY_CATEGORIES } from "./types.js";
2
+ export { isCallConcurrencySafe, partitionToolCalls } from "./concurrency.js";
3
+ export { isBashCommandReadOnly } from "./bash-readonly.js";
4
+ export { acquireFileLock, fileLockKey, withFileLock } from "./file-lock.js";
2
5
  export { ToolRegistry } from "./registry.js";
3
6
  export { PermissionGate } from "./permission.js";
4
7
  export { CATEGORY_TIER, isAutoApprovedByMode, isBlockedByMode, modeBlockReason, } from "./approval.js";
5
8
  export { builtinTools } from "./builtins.js";
6
9
  export { createPtyTool } from "./builtins/pty.js";
10
+ export { TODO_TOOL_NAME, createTodoTool, applyTodoOps, phasesToMarkdown, } from "./builtins/todo.js";
7
11
  export { cleanOutput, persistFullOutput, stripAnsi } from "./builtins/_shared.js";
8
12
  export { linesDiff, diffStats } from "./diff.js";
9
13
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AAgBA,OAAO,EAAE,2BAA2B,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAC9E,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC7C,OAAO,EAAwD,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACvG,OAAO,EACL,aAAa,EACb,oBAAoB,EACpB,eAAe,EACf,eAAe,GAChB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC7C,OAAO,EAA0B,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAC1E,OAAO,EAAE,WAAW,EAAE,iBAAiB,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAClF,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AAgBA,OAAO,EAAE,2BAA2B,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAC9E,OAAO,EAAkB,qBAAqB,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAC7F,OAAO,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAC3D,OAAO,EAAE,eAAe,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC5E,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC7C,OAAO,EAAwD,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACvG,OAAO,EACL,aAAa,EACb,oBAAoB,EACpB,eAAe,EACf,eAAe,GAChB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC7C,OAAO,EAA0B,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAC1E,OAAO,EAEL,cAAc,EACd,cAAc,EACd,YAAY,EACZ,gBAAgB,GACjB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,WAAW,EAAE,iBAAiB,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAClF,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC"}
@@ -73,6 +73,16 @@ export interface ToolContext {
73
73
  export interface ToolResult {
74
74
  ok: boolean;
75
75
  output: string;
76
+ /**
77
+ * (7.7 §6.2) Model-signalled loop termination. When every tool result in a
78
+ * single assistant turn's batch carries `terminate: true`, the agent loop
79
+ * ends gracefully after this batch (pi `shouldTerminateToolBatch` semantics —
80
+ * `agent-loop.ts:544`), transcript intact, instead of streaming another
81
+ * assistant turn. Undefined ⇒ false (the default for all existing builtins).
82
+ * Reserved for a future `done`/`final_output` tool; the loop honors the
83
+ * field now so that tool drops in additively.
84
+ */
85
+ terminate?: boolean;
76
86
  }
77
87
  /** Command pattern: each tool is a self-describing, executable unit. */
78
88
  export interface Tool {
@@ -107,6 +117,27 @@ export interface Tool {
107
117
  * destructive ones.
108
118
  */
109
119
  permission?(args: JSONValue, ctx: ToolContext): PermissionRequest | null;
120
+ /**
121
+ * (7.7 §3.1) Whether THIS specific call may run concurrently with other
122
+ * concurrency-safe calls in the same assistant turn's tool batch. The agent
123
+ * loop groups consecutive safe calls into one parallel batch and runs any
124
+ * unsafe call in its own serial batch, preserving submission order so a write
125
+ * is never reordered before a preceding read (claude-code
126
+ * `partitionToolCalls`).
127
+ *
128
+ * When undefined, the loop derives a default from `category`
129
+ * ({@link isCallConcurrencySafe}): read-only categories (file-read / search /
130
+ * memory-read / network-read) are safe, everything else is not. Override to:
131
+ * - widen a default-unsafe tool per-call (e.g. `bash` returns true only when
132
+ * its command is a read-only classifier `allow` — see `bash-readonly.ts`),
133
+ * - or NARROW a default-safe tool that must stay exclusive (e.g. `todo`,
134
+ * `ask_user_question` — read-only category but state-mutating / blocking).
135
+ *
136
+ * Any throw is treated as NOT safe (conservative, matches claude-code's
137
+ * try/catch→false). The whole helper is fail-closed: misclassification only
138
+ * costs parallelism (serial fallback), never correctness.
139
+ */
140
+ isConcurrencySafe?(args: JSONValue): boolean;
110
141
  }
111
142
  /**
112
143
  * (5.10b) A request to AUTHORIZE a side-effecting tool call — the original
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/tools/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/tools/types.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/tools/types.ts"],"names":[],"mappings":"AAqPA;;;4BAG4B;AAC5B,MAAM,CAAC,MAAM,2BAA2B,GAAG,mBAAmB,CAAC;AAE/D;;iEAEiE;AACjE,MAAM,CAAC,MAAM,mBAAmB,GAA8B,IAAI,GAAG,CAAe;IAClF,WAAW;IACX,QAAQ;IACR,aAAa;IACb,cAAc;CACf,CAAC,CAAC"}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/tools/types.ts"],"names":[],"mappings":"AAoRA;;;4BAG4B;AAC5B,MAAM,CAAC,MAAM,2BAA2B,GAAG,mBAAmB,CAAC;AAE/D;;iEAEiE;AACjE,MAAM,CAAC,MAAM,mBAAmB,GAA8B,IAAI,GAAG,CAAe;IAClF,WAAW;IACX,QAAQ;IACR,aAAa;IACb,cAAc;CACf,CAAC,CAAC"}