@nexrall/code-core 1.4.76 → 1.4.78

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 (143) hide show
  1. package/dist/agent/effortCap.d.ts +24 -0
  2. package/dist/agent/effortCap.d.ts.map +1 -0
  3. package/dist/agent/effortCap.js +66 -0
  4. package/dist/agent/goal.d.ts +55 -0
  5. package/dist/agent/goal.d.ts.map +1 -0
  6. package/dist/agent/goal.js +120 -0
  7. package/dist/agent/handoffBrief.d.ts +82 -0
  8. package/dist/agent/handoffBrief.d.ts.map +1 -0
  9. package/dist/agent/handoffBrief.js +121 -0
  10. package/dist/agent/hooks.d.ts +10 -2
  11. package/dist/agent/hooks.d.ts.map +1 -1
  12. package/dist/agent/hooks.js +9 -3
  13. package/dist/agent/modelCatalogue.d.ts +23 -0
  14. package/dist/agent/modelCatalogue.d.ts.map +1 -1
  15. package/dist/agent/modelCatalogue.js +28 -0
  16. package/dist/agent/outputStyles.d.ts +27 -0
  17. package/dist/agent/outputStyles.d.ts.map +1 -0
  18. package/dist/agent/outputStyles.js +174 -0
  19. package/dist/agent/skills.d.ts.map +1 -1
  20. package/dist/agent/skills.js +21 -1
  21. package/dist/api/billingLines.d.ts +11 -0
  22. package/dist/api/billingLines.d.ts.map +1 -0
  23. package/dist/api/billingLines.js +56 -0
  24. package/dist/api/client.d.ts +2 -0
  25. package/dist/api/client.d.ts.map +1 -1
  26. package/dist/api/scheduleLines.d.ts +53 -0
  27. package/dist/api/scheduleLines.d.ts.map +1 -0
  28. package/dist/api/scheduleLines.js +150 -0
  29. package/dist/context/contextFiles.d.ts +81 -0
  30. package/dist/context/contextFiles.d.ts.map +1 -0
  31. package/dist/context/contextFiles.js +310 -0
  32. package/dist/diff/collect.d.ts +25 -0
  33. package/dist/diff/collect.d.ts.map +1 -0
  34. package/dist/diff/collect.js +169 -0
  35. package/dist/diff/diffView.d.ts +57 -0
  36. package/dist/diff/diffView.d.ts.map +1 -0
  37. package/dist/diff/diffView.js +231 -0
  38. package/dist/diff/reviewQueue.d.ts +53 -0
  39. package/dist/diff/reviewQueue.d.ts.map +1 -0
  40. package/dist/diff/reviewQueue.js +349 -0
  41. package/dist/events/recap.d.ts +54 -0
  42. package/dist/events/recap.d.ts.map +1 -0
  43. package/dist/events/recap.js +161 -0
  44. package/dist/events/sessionEvents.d.ts +54 -0
  45. package/dist/events/sessionEvents.d.ts.map +1 -0
  46. package/dist/events/sessionEvents.js +324 -0
  47. package/dist/events/sessionStats.d.ts +89 -0
  48. package/dist/events/sessionStats.d.ts.map +1 -0
  49. package/dist/events/sessionStats.js +264 -0
  50. package/dist/import/claudeImport.d.ts +44 -0
  51. package/dist/import/claudeImport.d.ts.map +1 -0
  52. package/dist/import/claudeImport.js +337 -0
  53. package/dist/index.d.ts +38 -0
  54. package/dist/index.d.ts.map +1 -1
  55. package/dist/index.js +38 -0
  56. package/dist/mcp/manager.d.ts +8 -0
  57. package/dist/mcp/manager.d.ts.map +1 -1
  58. package/dist/mcp/manager.js +64 -57
  59. package/dist/permissions/destructiveTokens.d.ts +1 -0
  60. package/dist/permissions/destructiveTokens.d.ts.map +1 -1
  61. package/dist/permissions/destructiveTokens.js +93 -0
  62. package/dist/permissions/rules.d.ts +12 -0
  63. package/dist/permissions/rules.d.ts.map +1 -1
  64. package/dist/permissions/rules.js +89 -7
  65. package/dist/plugins/configStore.d.ts +43 -0
  66. package/dist/plugins/configStore.d.ts.map +1 -0
  67. package/dist/plugins/configStore.js +253 -0
  68. package/dist/plugins/files.d.ts +10 -0
  69. package/dist/plugins/files.d.ts.map +1 -0
  70. package/dist/plugins/files.js +85 -0
  71. package/dist/plugins/index.d.ts +3 -22
  72. package/dist/plugins/index.d.ts.map +1 -1
  73. package/dist/plugins/index.js +30 -40
  74. package/dist/plugins/resolve.d.ts +18 -0
  75. package/dist/plugins/resolve.d.ts.map +1 -0
  76. package/dist/plugins/resolve.js +152 -0
  77. package/dist/plugins/userConfig.d.ts +90 -0
  78. package/dist/plugins/userConfig.d.ts.map +1 -0
  79. package/dist/plugins/userConfig.js +332 -0
  80. package/dist/plugins/validate.d.ts +14 -0
  81. package/dist/plugins/validate.d.ts.map +1 -0
  82. package/dist/plugins/validate.js +222 -0
  83. package/dist/project/projectCommands.d.ts +33 -0
  84. package/dist/project/projectCommands.d.ts.map +1 -0
  85. package/dist/project/projectCommands.js +246 -0
  86. package/dist/search/conversationTurns.d.ts +53 -0
  87. package/dist/search/conversationTurns.d.ts.map +1 -0
  88. package/dist/search/conversationTurns.js +170 -0
  89. package/dist/search/globalSearch.d.ts +144 -0
  90. package/dist/search/globalSearch.d.ts.map +1 -0
  91. package/dist/search/globalSearch.js +350 -0
  92. package/dist/share/sessionChannel.d.ts +136 -0
  93. package/dist/share/sessionChannel.d.ts.map +1 -0
  94. package/dist/share/sessionChannel.js +373 -0
  95. package/dist/share/sessionShare.d.ts +104 -0
  96. package/dist/share/sessionShare.d.ts.map +1 -0
  97. package/dist/share/sessionShare.js +336 -0
  98. package/dist/ui/configCmd.d.ts +48 -0
  99. package/dist/ui/configCmd.d.ts.map +1 -0
  100. package/dist/ui/configCmd.js +146 -0
  101. package/dist/ui/deployPanel.d.ts +91 -0
  102. package/dist/ui/deployPanel.d.ts.map +1 -0
  103. package/dist/ui/deployPanel.js +442 -0
  104. package/dist/ui/mergeAssistant.d.ts +120 -0
  105. package/dist/ui/mergeAssistant.d.ts.map +1 -0
  106. package/dist/ui/mergeAssistant.js +391 -0
  107. package/dist/ui/notify.d.ts +114 -0
  108. package/dist/ui/notify.d.ts.map +1 -0
  109. package/dist/ui/notify.js +235 -0
  110. package/dist/ui/promptSuggest.d.ts +56 -0
  111. package/dist/ui/promptSuggest.d.ts.map +1 -0
  112. package/dist/ui/promptSuggest.js +160 -0
  113. package/dist/ui/taskGraph.d.ts +44 -0
  114. package/dist/ui/taskGraph.d.ts.map +1 -0
  115. package/dist/ui/taskGraph.js +289 -0
  116. package/dist/util/addDir.d.ts +31 -0
  117. package/dist/util/addDir.d.ts.map +1 -0
  118. package/dist/util/addDir.js +124 -0
  119. package/dist/util/batch.d.ts +16 -0
  120. package/dist/util/batch.d.ts.map +1 -0
  121. package/dist/util/batch.js +92 -0
  122. package/dist/util/cellWidth.d.ts +12 -0
  123. package/dist/util/cellWidth.d.ts.map +1 -0
  124. package/dist/util/cellWidth.js +161 -0
  125. package/dist/util/duration.d.ts +8 -0
  126. package/dist/util/duration.d.ts.map +1 -0
  127. package/dist/util/duration.js +50 -0
  128. package/dist/util/loopJobs.d.ts +67 -0
  129. package/dist/util/loopJobs.d.ts.map +1 -0
  130. package/dist/util/loopJobs.js +169 -0
  131. package/dist/util/settingsFile.d.ts +14 -0
  132. package/dist/util/settingsFile.d.ts.map +1 -0
  133. package/dist/util/settingsFile.js +99 -0
  134. package/dist/util/toolLabel.d.ts +2 -0
  135. package/dist/util/toolLabel.d.ts.map +1 -0
  136. package/dist/util/toolLabel.js +17 -0
  137. package/dist/verify/failureTimeline.d.ts +100 -0
  138. package/dist/verify/failureTimeline.d.ts.map +1 -0
  139. package/dist/verify/failureTimeline.js +253 -0
  140. package/dist/verify/verification.d.ts +75 -0
  141. package/dist/verify/verification.d.ts.map +1 -0
  142. package/dist/verify/verification.js +315 -0
  143. package/package.json +5 -4
@@ -0,0 +1,289 @@
1
+ "use strict";
2
+ // Lives in core (moved from the CLI's ui/taskGraph.ts, 2026-10-04) so the VS Code
3
+ // panel draws the same shared-task DAG; the CLI module is a re-export shim.
4
+ // The shared-task DAG (spec §41).
5
+ //
6
+ // WHY a graph and not a list: `list_shared_tasks` already prints the tasks, but a list
7
+ // flattens away the only thing that makes a set of tasks a plan — which ones are waiting
8
+ // on which. `blockedBy` is a real dependency edge written by whoever created the task, so
9
+ // the graph is measured, not inferred. Reading it as layers answers the question a list
10
+ // cannot: what can start RIGHT NOW, and what is stuck behind what.
11
+ //
12
+ // Drawn as a tree from the dependency roots (the spec's own shape), because a terminal
13
+ // has one column to draw in. The limitation that comes with that choice is handled out
14
+ // loud rather than hidden: a task reachable from two blockers is a diamond, and a tree has
15
+ // no place to draw the second edge, so the task is drawn again under the other blocker and
16
+ // marked `↖ also after #id` — naming the edge makes the repeat read as ONE task, not two.
17
+ // Everything drawn under that repeat is a copy of rows above it, so those are marked too.
18
+ //
19
+ // A cycle is not a crash and not a silent loop — it is reported as a named group, since a
20
+ // cycle means nobody can ever claim those tasks and the user needs to know that.
21
+ Object.defineProperty(exports, "__esModule", { value: true });
22
+ exports.STATUS_MARK = void 0;
23
+ exports.roots = roots;
24
+ exports.blockersOf = blockersOf;
25
+ exports.missingBlockers = missingBlockers;
26
+ exports.readyTasks = readyTasks;
27
+ exports.findCycle = findCycle;
28
+ exports.formatTaskGraph = formatTaskGraph;
29
+ /** Local copy of the one-line clip (formerly ui/taskPanel.ts's) so core needs
30
+ * no import from the CLI; identical behaviour. */
31
+ function clip(text, max) {
32
+ const tt = String(text ?? '')
33
+ .replace(/\s+/g, ' ')
34
+ .trim();
35
+ if (max <= 1)
36
+ return tt.slice(0, Math.max(0, max));
37
+ return tt.length <= max ? tt : tt.slice(0, max - 1).trimEnd() + '\u2026';
38
+ }
39
+ const duration_1 = require("../util/duration");
40
+ /** Rows built past the cap before giving up on an exact count (see `buildCap`). */
41
+ const ROW_BUILD_SLACK = 50;
42
+ exports.STATUS_MARK = {
43
+ pending: '○',
44
+ in_progress: '⠋',
45
+ completed: '✓',
46
+ blocked: '⊘',
47
+ };
48
+ /** Tasks that no one has to wait for: no blockers, or blockers we cannot see. */
49
+ function roots(tasks) {
50
+ const known = new Set(tasks.map((t) => t.id));
51
+ return tasks.filter((t) => !(t.blockedBy ?? []).some((b) => known.has(b)));
52
+ }
53
+ function blockersOf(tasks, t) {
54
+ const known = new Set(tasks.map((x) => x.id));
55
+ return (t.blockedBy ?? []).filter((b) => known.has(b));
56
+ }
57
+ /** Blockers that are named but do not exist — a broken edge the user should see. */
58
+ function missingBlockers(tasks, t) {
59
+ const known = new Set(tasks.map((x) => x.id));
60
+ return (t.blockedBy ?? []).filter((b) => !known.has(b));
61
+ }
62
+ /**
63
+ * Tasks that can be claimed this instant: nothing blocking, and nobody holding them.
64
+ *
65
+ * A task blocked by an in-progress or pending dependency is NOT ready even though it is
66
+ * itself `pending` — the whole point of the graph. Claimed-but-abandoned tasks are left
67
+ * out too: core's claim-liveness rules are the authority on whether a claim is dead, and
68
+ * second-guessing them here would print "ready" for something core would refuse.
69
+ */
70
+ function readyTasks(tasks) {
71
+ const byId = new Map(tasks.map((t) => [t.id, t]));
72
+ return tasks.filter((t) => {
73
+ if (t.status !== 'pending' && t.status !== 'blocked')
74
+ return false;
75
+ const blockers = t.blockedBy ?? [];
76
+ return blockers.every((b) => byId.get(b)?.status === 'completed');
77
+ });
78
+ }
79
+ /** Task ids in a dependency cycle (mutual or longer). Empty when the graph is a DAG. */
80
+ function findCycle(tasks) {
81
+ const byId = new Map(tasks.map((t) => [t.id, t]));
82
+ const state = new Map();
83
+ const stack = [];
84
+ const inCycle = new Set();
85
+ const visit = (id) => {
86
+ const st = state.get(id) ?? 0;
87
+ if (st === 2)
88
+ return;
89
+ if (st === 1) {
90
+ // Found a back edge: everything from this node's position on the stack is a cycle.
91
+ const at = stack.indexOf(id);
92
+ for (const x of stack.slice(at === -1 ? 0 : at))
93
+ inCycle.add(x);
94
+ return;
95
+ }
96
+ state.set(id, 1);
97
+ stack.push(id);
98
+ for (const b of byId.get(id)?.blockedBy ?? [])
99
+ if (byId.has(b))
100
+ visit(b);
101
+ stack.pop();
102
+ state.set(id, 2);
103
+ };
104
+ for (const t of tasks)
105
+ visit(t.id);
106
+ return [...inCycle];
107
+ }
108
+ /**
109
+ * Build the forest to print: each root with the tasks it directly unblocks, recursively.
110
+ * Children are ordered by creation-independent input order so two runs print the same
111
+ * picture (`updatedAt` moves as work progresses; sorting by it would reshuffle rows
112
+ * while the user is reading them).
113
+ *
114
+ * Structure only — which copy of a twice-reachable task is the repeat is decided by the
115
+ * caller, because that is the one place that knows what has already been printed.
116
+ */
117
+ function forest(pool) {
118
+ const unblocks = new Map();
119
+ for (const t of pool) {
120
+ for (const b of blockersOf(pool, t)) {
121
+ const list = unblocks.get(b);
122
+ if (list)
123
+ list.push(t);
124
+ else
125
+ unblocks.set(b, [t]);
126
+ }
127
+ }
128
+ const out = [];
129
+ const walked = new Set();
130
+ for (const r of roots(pool)) {
131
+ if (walked.has(r.id))
132
+ continue;
133
+ const kids = new Map();
134
+ const walk = (id) => {
135
+ const list = unblocks.get(id) ?? [];
136
+ kids.set(id, list);
137
+ // Each child is expanded once. Walking it again rebuilds the same lists, and a
138
+ // handful of stacked diamonds would multiply that out towards 2^depth.
139
+ for (const child of list) {
140
+ if (walked.has(child.id))
141
+ continue;
142
+ walked.add(child.id);
143
+ walk(child.id);
144
+ }
145
+ };
146
+ walked.add(r.id);
147
+ walk(r.id);
148
+ out.push({ root: r, kids });
149
+ }
150
+ return out;
151
+ }
152
+ function mark(t) {
153
+ return exports.STATUS_MARK[t.status] ?? '○';
154
+ }
155
+ /**
156
+ * Clip a FINISHED row to `cols` without the whitespace collapse `clip` performs: the leading
157
+ * indent IS the tree structure, and clip() flattens the stem of a grandchild to column zero —
158
+ * which drew a depth-2 task exactly like a depth-1 one. Contents are clipped individually
159
+ * before they get here, so all that is left is the final fit.
160
+ */
161
+ function fit(line, cols) {
162
+ if (line.length <= cols)
163
+ return line;
164
+ return line.slice(0, Math.max(1, cols - 1)).trimEnd() + '…';
165
+ }
166
+ function taskLine(t, now, cols, extra = '') {
167
+ const bits = [];
168
+ bits.push(t.status === 'in_progress' && t.claimedAt
169
+ ? `${t.claimedBy ?? 'someone'} · ${(0, duration_1.formatElapsed)(now - t.claimedAt)}`
170
+ : t.status.replace('_', ' '));
171
+ if (extra)
172
+ bits.push(extra);
173
+ return fit(`${mark(t)} ${clip(t.content, Math.max(16, cols - 40))} · ${bits.join(' · ')}`, cols);
174
+ }
175
+ /**
176
+ * The whole graph, as lines for the caller to print.
177
+ *
178
+ * Empty input is a normal state, not an error — most projects never create shared tasks.
179
+ * The caller pairs this with an explanation of how one gets created, which is why the
180
+ * empty case returns no lines at all rather than a placeholder.
181
+ */
182
+ function formatTaskGraph(input) {
183
+ const cols = Math.max(24, input.cols ?? 100);
184
+ const maxRows = input.maxRows ?? 30;
185
+ const tasks = input.tasks;
186
+ if (!tasks.length)
187
+ return [];
188
+ const cycle = new Set(findCycle(tasks));
189
+ const healthy = tasks.filter((t) => !cycle.has(t.id));
190
+ const out = [];
191
+ const ready = readyTasks(tasks);
192
+ const counts = {
193
+ pending: tasks.filter((t) => t.status === 'pending').length,
194
+ running: tasks.filter((t) => t.status === 'in_progress').length,
195
+ done: tasks.filter((t) => t.status === 'completed').length,
196
+ };
197
+ const workers = new Set(tasks.filter((t) => t.status === 'in_progress' && t.claimedBy).map((t) => t.claimedBy));
198
+ out.push(fit(`Task graph — ${tasks.length} task${tasks.length === 1 ? '' : 's'}: ` +
199
+ `${counts.done} done · ${counts.running} in progress · ${counts.pending} pending` +
200
+ `${workers.size ? ` · ${workers.size} worker${workers.size === 1 ? '' : 's'}` : ''}`, cols));
201
+ if (ready.length) {
202
+ out.push(fit(`${ready.length} ready to claim now: ${ready
203
+ .slice(0, 3)
204
+ .map((t) => `#${t.id}`)
205
+ .join(', ')}${ready.length > 3 ? ` (+${ready.length - 3})` : ''}`, cols));
206
+ }
207
+ const rows = [];
208
+ // Rows are built only as far as the cap can use them. A task reachable two ways is drawn
209
+ // under BOTH, so a plan that fans out and re-joins at every step multiplies the rows:
210
+ // 16 stacked diamonds is 65k rows, which is both a hang and a stack overflow on spread.
211
+ // The slack keeps the exact count for boards of an ordinary size, where the reader is
212
+ // owed a number, and switches to "N+" once the multiplication takes over.
213
+ const buildCap = maxRows + ROW_BUILD_SLACK;
214
+ let capped = false;
215
+ // Ids already printed, so a repeated copy can say so. The set also covers the copies'
216
+ // DESCENDANTS: the whole subtree under a repeat is already on screen above, and a row
217
+ // that looks identical to one three lines up reads as a second, separate task.
218
+ const printed = new Set();
219
+ for (const { root, kids } of forest(healthy)) {
220
+ rows.push(taskLine(root, input.now, cols));
221
+ // A root of the drawn forest can still name blockers from the FULL list: ones inside a
222
+ // cycle (excluded from the forest) and ones that do not exist. Reporting a task printed
223
+ // three lines below as "no such task" would be a plain lie, so the two read differently.
224
+ const cyc = blockersOf(tasks, root).filter((b) => cycle.has(b));
225
+ if (cyc.length)
226
+ rows.push(fit(` ⚠ depends on ${cyc.map((b) => `#${b}`).join(', ')} — inside a dependency cycle (listed below)`, cols));
227
+ const skipped = missingBlockers(tasks, root);
228
+ if (skipped.length)
229
+ rows.push(fit(` ⚠ depends on ${skipped.map((b) => `#${b}`).join(', ')} — no such task`, cols));
230
+ const walk = (id, stem) => {
231
+ const list = kids.get(id) ?? [];
232
+ list.forEach((child, i) => {
233
+ if (rows.length >= buildCap) {
234
+ capped = true;
235
+ return;
236
+ }
237
+ const last = i === list.length - 1;
238
+ const lead = stem + (last ? '└─ ' : '├─ ');
239
+ const bits = [];
240
+ if (child.status === 'in_progress' && child.claimedAt)
241
+ bits.push(`${child.claimedBy ?? 'someone'} · ${(0, duration_1.formatElapsed)(input.now - child.claimedAt)}`);
242
+ else
243
+ bits.push(child.status.replace('_', ' '));
244
+ const seen = printed.has(child.id);
245
+ printed.add(child.id);
246
+ if (seen) {
247
+ // The same task under a second blocker (a tree has no room for the second edge).
248
+ // Name the other edge when there is one, so the repeat reads as ONE task rather
249
+ // than as two tasks with the same content; a descendant of a repeat has no other
250
+ // edge of its own, it is simply the copy above it.
251
+ const others = blockersOf(healthy, child).filter((b) => b !== id);
252
+ bits.push(others.length ? `↖ also after ${others.map((b) => `#${b}`).join(', ')}` : '↖ also drawn above');
253
+ }
254
+ const cycB = blockersOf(tasks, child).filter((b) => cycle.has(b));
255
+ if (cycB.length)
256
+ bits.push(`⚠ needs ${cycB.map((b) => `#${b}`).join(', ')} (cycle)`);
257
+ const miss = missingBlockers(tasks, child);
258
+ if (miss.length)
259
+ bits.push(`⚠ missing ${miss.map((b) => `#${b}`).join(', ')}`);
260
+ const text = clip(child.content, Math.max(16, cols - lead.length - 34));
261
+ rows.push(fit(`${lead}${mark(child)} ${text} · ${bits.join(' · ')}`, cols));
262
+ walk(child.id, stem + (last ? ' ' : '│ '));
263
+ });
264
+ };
265
+ printed.add(root.id);
266
+ walk(root.id, '');
267
+ }
268
+ if (rows.length > maxRows) {
269
+ out.push(...rows.slice(0, maxRows));
270
+ // Both counts are true: the exact one when every row was built, and a lower bound when
271
+ // building stopped early — "1 more row" there would be a lie with a straight face.
272
+ const hidden = `${rows.length - maxRows}${capped ? '+' : ''}`;
273
+ out.push(fit(` … ${hidden} more row(s) not drawn — this view caps at ${maxRows}; the counts above cover every task`, cols));
274
+ }
275
+ else {
276
+ out.push(...rows);
277
+ }
278
+ if (cycle.size) {
279
+ // A cycle is why a task can sit pending forever with every dependency "somewhere in
280
+ // the graph": naming the members is the only actionable way to say that.
281
+ out.push(fit(`⚠ ${cycle.size} task(s) form a dependency cycle — none of them can ever be claimed:`, cols));
282
+ for (const id of cycle) {
283
+ const t = tasks.find((x) => x.id === id);
284
+ out.push(fit(` ⊘ #${id} ${clip(t?.content ?? '', Math.max(10, cols - 24))}`, cols));
285
+ }
286
+ }
287
+ return out;
288
+ }
289
+ //# sourceMappingURL=taskGraph.js.map
@@ -0,0 +1,31 @@
1
+ export type AddDirResult = {
2
+ kind: 'list';
3
+ } | {
4
+ kind: 'error';
5
+ message: string;
6
+ } | {
7
+ kind: 'noop';
8
+ dir: string;
9
+ } | {
10
+ kind: 'added';
11
+ dir: string;
12
+ dirs: string[];
13
+ };
14
+ /**
15
+ * Tool lists arrive as `--allowedTools "Bash(git *)" Edit` (variadic), as one
16
+ * comma-separated string, or both. Commas INSIDE parentheses belong to the rule
17
+ * (`Bash(git log --format=a,b)`), so splitting is paren-aware.
18
+ */
19
+ export declare function parseToolList(values: string[] | string | undefined): string[];
20
+ export type Parsed<T> = {
21
+ ok: true;
22
+ value: T;
23
+ } | {
24
+ ok: false;
25
+ error: string;
26
+ };
27
+ /** Resolve and VALIDATE --add-dir pieces: each must be an existing directory. */
28
+ export declare function parseAddDirs(values: string[] | undefined, cwd: string): Parsed<string[]>;
29
+ export declare function addDirNote(dirs: string[]): string;
30
+ export declare function resolveAddDir(arg: string, cwd: string, current: string[], projectRoot: string): AddDirResult;
31
+ //# sourceMappingURL=addDir.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"addDir.d.ts","sourceRoot":"","sources":["../../src/util/addDir.ts"],"names":[],"mappings":"AAaA,MAAM,MAAM,YAAY,GACpB;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAChB;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAClC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,GAC7B;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC;AAEnD;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,GAAG,SAAS,GAAG,MAAM,EAAE,CAwB7E;AAED,MAAM,MAAM,MAAM,CAAC,CAAC,IAAI;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,CAAC,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAE9E,iFAAiF;AACjF,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,SAAS,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,CAgBxF;AAED,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,MAAM,CAGjD;AAED,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,EAAE,WAAW,EAAE,MAAM,GAAG,YAAY,CAS5G"}
@@ -0,0 +1,124 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.parseToolList = parseToolList;
37
+ exports.parseAddDirs = parseAddDirs;
38
+ exports.addDirNote = addDirNote;
39
+ exports.resolveAddDir = resolveAddDir;
40
+ // /add-dir <path> — widen the session to another directory mid-run (the interactive
41
+ // twin of --add-dir). Moved from the CLI (ui/addDir.ts + the parseToolList /
42
+ // parseAddDirs / addDirNote trio in headlessFlags.ts, 2026-10-04) so the VS Code
43
+ // panel widens its brief with the same rules; the CLI modules re-export.
44
+ const fs = __importStar(require("fs"));
45
+ const os = __importStar(require("os"));
46
+ const path = __importStar(require("path"));
47
+ /** `~` is expanded here: a REPL argument never saw a shell. */
48
+ function expandHome(p) {
49
+ return p === '~' ? os.homedir() : p.startsWith('~/') ? os.homedir() + p.slice(1) : p;
50
+ }
51
+ /**
52
+ * Tool lists arrive as `--allowedTools "Bash(git *)" Edit` (variadic), as one
53
+ * comma-separated string, or both. Commas INSIDE parentheses belong to the rule
54
+ * (`Bash(git log --format=a,b)`), so splitting is paren-aware.
55
+ */
56
+ function parseToolList(values) {
57
+ if (values === undefined)
58
+ return [];
59
+ const list = Array.isArray(values) ? values : [values];
60
+ const out = [];
61
+ for (const v of list) {
62
+ let depth = 0;
63
+ let cur = '';
64
+ const flush = () => {
65
+ const t = cur.trim();
66
+ if (t)
67
+ out.push(t);
68
+ cur = '';
69
+ };
70
+ for (const ch of String(v)) {
71
+ if (ch === '(')
72
+ depth++;
73
+ else if (ch === ')')
74
+ depth = Math.max(0, depth - 1);
75
+ if ((ch === ',' || /\s/.test(ch)) && depth === 0) {
76
+ flush();
77
+ continue;
78
+ }
79
+ cur += ch;
80
+ }
81
+ flush();
82
+ }
83
+ return out;
84
+ }
85
+ /** Resolve and VALIDATE --add-dir pieces: each must be an existing directory. */
86
+ function parseAddDirs(values, cwd) {
87
+ const out = [];
88
+ for (const v of values ?? []) {
89
+ for (const piece of parseToolList(v)) {
90
+ const abs = path.resolve(cwd, piece);
91
+ let ok = false;
92
+ try {
93
+ ok = fs.statSync(abs).isDirectory();
94
+ }
95
+ catch {
96
+ /* fallthrough */
97
+ }
98
+ if (!ok)
99
+ return { ok: false, error: `--add-dir: "${piece}" is not an existing directory` };
100
+ if (!out.includes(abs))
101
+ out.push(abs);
102
+ }
103
+ }
104
+ return { ok: true, value: out };
105
+ }
106
+ function addDirNote(dirs) {
107
+ if (!dirs.length)
108
+ return '';
109
+ return `Additional working directories (you may read and edit files here with absolute paths, same as the main project):\n${dirs.map((d) => `- ${d}`).join('\n')}`;
110
+ }
111
+ function resolveAddDir(arg, cwd, current, projectRoot) {
112
+ const text = String(arg ?? '').trim();
113
+ if (!text)
114
+ return { kind: 'list' };
115
+ const unquoted = text.replace(/^(["'])([\s\S]*)\1$/, '$2');
116
+ const parsed = parseAddDirs([expandHome(unquoted)], cwd);
117
+ if (!parsed.ok)
118
+ return { kind: 'error', message: parsed.error.replace(/^--add-dir: /, '') };
119
+ const dir = parsed.value[0];
120
+ if (dir === projectRoot || current.includes(dir))
121
+ return { kind: 'noop', dir };
122
+ return { kind: 'added', dir, dirs: [...current, dir] };
123
+ }
124
+ //# sourceMappingURL=addDir.js.map
@@ -0,0 +1,16 @@
1
+ export declare const BATCH_MIN_UNITS = 2;
2
+ export declare const BATCH_MAX_UNITS = 12;
3
+ export type BatchArgs = {
4
+ kind: 'usage';
5
+ } | {
6
+ kind: 'error';
7
+ message: string;
8
+ } | {
9
+ kind: 'run';
10
+ instruction: string;
11
+ };
12
+ export declare function parseBatchArgs(arg: string): BatchArgs;
13
+ /** Worktrees need a git repo. Walks up from `dir` looking for .git (file or dir). */
14
+ export declare function isGitRepo(dir: string): boolean;
15
+ export declare function buildBatchPrompt(instruction: string): string;
16
+ //# sourceMappingURL=batch.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"batch.d.ts","sourceRoot":"","sources":["../../src/util/batch.ts"],"names":[],"mappings":"AAWA,eAAO,MAAM,eAAe,IAAI,CAAC;AACjC,eAAO,MAAM,eAAe,KAAK,CAAC;AAElC,MAAM,MAAM,SAAS,GAAG;IAAE,IAAI,EAAE,OAAO,CAAA;CAAE,GAAG;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,IAAI,EAAE,KAAK,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,CAAC;AAEtH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,CAMrD;AAED,qFAAqF;AACrF,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAQ9C;AAED,wBAAgB,gBAAgB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAmB5D"}
@@ -0,0 +1,92 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.BATCH_MAX_UNITS = exports.BATCH_MIN_UNITS = void 0;
37
+ exports.parseBatchArgs = parseBatchArgs;
38
+ exports.isGitRepo = isGitRepo;
39
+ exports.buildBatchPrompt = buildBatchPrompt;
40
+ // Lives in core (moved from the CLI's ui/batch.ts, 2026-10-04) so the VS Code
41
+ // panel runs the same fan-out guards and prompt; the CLI module is a re-export shim.
42
+ // /batch <instruction> — fan a large, mechanical change out across parallel sub-agents, each in
43
+ // its OWN git worktree, so they cannot trample each other. Nothing is merged automatically: the
44
+ // worktrees are handed back for the user to review.
45
+ //
46
+ // This is a prompt, not a new engine: the machinery (the `task` tool with isolation:"worktree",
47
+ // background agents) already exists. Pure here: the argument check and the brief.
48
+ const fs = __importStar(require("fs"));
49
+ const path = __importStar(require("path"));
50
+ exports.BATCH_MIN_UNITS = 2;
51
+ exports.BATCH_MAX_UNITS = 12;
52
+ function parseBatchArgs(arg) {
53
+ const t = String(arg ?? '').trim();
54
+ if (!t)
55
+ return { kind: 'usage' };
56
+ if (t.length > 4000)
57
+ return { kind: 'error', message: `The instruction is ${t.length} characters; keep it under 4000.` };
58
+ return { kind: 'run', instruction: t };
59
+ }
60
+ /** Worktrees need a git repo. Walks up from `dir` looking for .git (file or dir). */
61
+ function isGitRepo(dir) {
62
+ let cur = path.resolve(dir);
63
+ for (;;) {
64
+ if (fs.existsSync(path.join(cur, '.git')))
65
+ return true;
66
+ const up = path.dirname(cur);
67
+ if (up === cur)
68
+ return false;
69
+ cur = up;
70
+ }
71
+ }
72
+ function buildBatchPrompt(instruction) {
73
+ return [
74
+ `Carry out this change across the codebase as a PARALLEL BATCH:`,
75
+ ``,
76
+ `<instruction>`,
77
+ instruction,
78
+ `</instruction>`,
79
+ ``,
80
+ `Method:`,
81
+ `1. RESEARCH first (read-only): find every place the change applies. Do not edit anything yet.`,
82
+ `2. DECOMPOSE into ${exports.BATCH_MIN_UNITS}–${exports.BATCH_MAX_UNITS} independent units that touch DISJOINT files (group by directory or module). `,
83
+ ` If the work cannot be split into independent units, say so and do it directly instead of faking a split.`,
84
+ `3. Show the plan (unit → files) in a short list.`,
85
+ `4. Launch ONE sub-agent per unit with the \`task\` tool, \`isolation: "worktree"\`, all in the SAME message so they run in parallel. `,
86
+ ` Each unit's prompt must be fully self-contained: the instruction, its exact file list, the conventions to follow, and "run the tests/typecheck relevant to your files, then stop".`,
87
+ `5. When they finish, report per unit: what changed, whether its checks passed, and the worktree path/branch holding the result.`,
88
+ ``,
89
+ `Rules: never merge or push anything yourself; never let two units edit the same file; if a unit fails, report it plainly instead of retrying silently.`,
90
+ ].join('\n');
91
+ }
92
+ //# sourceMappingURL=batch.js.map
@@ -0,0 +1,12 @@
1
+ /** Split into user-perceived characters so accents/emoji/CJK are never cut in half. */
2
+ export declare function graphemes(s: string): string[];
3
+ /**
4
+ * Width of `s` in terminal cells, ignoring ANSI styling. A grapheme measures as
5
+ * the sum of its code points' widths, except that any 2-wide code point in the
6
+ * cluster (an emoji base) makes the whole cluster 2 — a ZWJ family sequence is
7
+ * many code points but one two-cell glyph.
8
+ */
9
+ export declare function visibleLen(s: string): number;
10
+ /** Cut `s` to at most `max` terminal cells, ending in `…` when something was dropped. */
11
+ export declare function truncateCells(s: string, max: number): string;
12
+ //# sourceMappingURL=cellWidth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cellWidth.d.ts","sourceRoot":"","sources":["../../src/util/cellWidth.ts"],"names":[],"mappings":"AA2BA,uFAAuF;AACvF,wBAAgB,SAAS,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAE7C;AA4ED;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAa5C;AAkBD,yFAAyF;AACzF,wBAAgB,aAAa,CAAC,CAAC,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAmB5D"}