@ordewell/core 0.7.1 → 0.8.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 (52) hide show
  1. package/README.md +5 -2
  2. package/dist/{IFileSystem-BnLh-_SK.d.mts → IFileSystem-D96mT-bm.d.ts} +1 -1
  3. package/dist/{IFileSystem-DofiRcCo.d.ts → IFileSystem-DXJCRw5x.d.mts} +1 -1
  4. package/dist/IRunner-CGCihlGQ.d.ts +1165 -0
  5. package/dist/IRunner-XVUddYVX.d.mts +1165 -0
  6. package/dist/{ModeResolver-DkMYf4uS.d.ts → ModeResolver-DE-o2lRF.d.mts} +2 -2
  7. package/dist/{ModeResolver-DZzJSdIU.d.mts → ModeResolver-EWlpmVAy.d.ts} +2 -2
  8. package/dist/Task-1Q19y7sZ.d.mts +1122 -0
  9. package/dist/Task-1Q19y7sZ.d.ts +1122 -0
  10. package/dist/{chunk-ZV5LDNCO.mjs → chunk-2M4X3VB7.mjs} +18 -6
  11. package/dist/chunk-2M4X3VB7.mjs.map +1 -0
  12. package/dist/{chunk-Y36NIASW.mjs → chunk-BLLIBCCS.mjs} +153 -264
  13. package/dist/chunk-BLLIBCCS.mjs.map +1 -0
  14. package/dist/chunk-H5O74L77.mjs +185 -0
  15. package/dist/chunk-H5O74L77.mjs.map +1 -0
  16. package/dist/{chunk-LGQNXPBX.mjs → chunk-UUU46PVQ.mjs} +72 -192
  17. package/dist/chunk-UUU46PVQ.mjs.map +1 -0
  18. package/dist/index.d.mts +1119 -930
  19. package/dist/index.d.ts +1119 -930
  20. package/dist/index.js +8361 -8849
  21. package/dist/index.js.map +1 -1
  22. package/dist/index.mjs +8197 -8614
  23. package/dist/index.mjs.map +1 -1
  24. package/dist/order-labels.d.mts +1 -4
  25. package/dist/order-labels.d.ts +1 -4
  26. package/dist/{parsing-ddZXZFP4.d.ts → parsing-CZdp2p_n.d.ts} +5 -3
  27. package/dist/{parsing-B6ctfF80.d.mts → parsing-GgUJoYKs.d.mts} +5 -3
  28. package/dist/parsing.d.mts +3 -6
  29. package/dist/parsing.d.ts +3 -6
  30. package/dist/parsing.js +25 -4
  31. package/dist/parsing.js.map +1 -1
  32. package/dist/parsing.mjs +3 -2
  33. package/dist/{plan-utils-CKgNtDwQ.d.mts → plan-utils-BMayhGBj.d.mts} +89 -14
  34. package/dist/{plan-utils--kQRzSE-.d.ts → plan-utils-Cv48fe7r.d.ts} +89 -14
  35. package/dist/plan-utils.d.mts +4 -4
  36. package/dist/plan-utils.d.ts +4 -4
  37. package/dist/plan-utils.js +128 -65
  38. package/dist/plan-utils.js.map +1 -1
  39. package/dist/plan-utils.mjs +10 -2
  40. package/dist/testing.d.mts +12 -24
  41. package/dist/testing.d.ts +12 -24
  42. package/dist/testing.js +29 -29
  43. package/dist/testing.js.map +1 -1
  44. package/dist/testing.mjs +21 -27
  45. package/dist/testing.mjs.map +1 -1
  46. package/package.json +1 -1
  47. package/skills/tdd/SKILL.md +19 -0
  48. package/dist/Task-BnLxkVQF.d.mts +0 -2594
  49. package/dist/Task-BnLxkVQF.d.ts +0 -2594
  50. package/dist/chunk-LGQNXPBX.mjs.map +0 -1
  51. package/dist/chunk-Y36NIASW.mjs.map +0 -1
  52. package/dist/chunk-ZV5LDNCO.mjs.map +0 -1
@@ -1,18 +1,22 @@
1
1
  import {
2
2
  PlanParseError,
3
3
  TASK_OPS_ENVELOPE_KEY,
4
- addTaskToPlan,
5
- createTask,
6
4
  escapeControlCharsInStrings,
7
5
  extractObjectsWithKey,
6
+ stripTrailingCommas
7
+ } from "./chunk-H5O74L77.mjs";
8
+ import {
9
+ addTaskToPlan,
10
+ createTask,
8
11
  flattenTasks,
9
12
  inheritedOps,
13
+ inheritedSkills,
10
14
  opsFlag,
11
15
  removeTaskFromPlan,
12
16
  renumberTasks,
13
- stripTrailingCommas,
17
+ skillNames,
14
18
  updateTaskInPlan
15
- } from "./chunk-LGQNXPBX.mjs";
19
+ } from "./chunk-UUU46PVQ.mjs";
16
20
  import {
17
21
  taskOrderLabel,
18
22
  taskRef,
@@ -118,183 +122,8 @@ function normalizeAgentArgs(tool, args) {
118
122
  return out;
119
123
  }
120
124
 
121
- // src/services/terminalRender.ts
122
- var ANSI_OR_CTRL_RE = /\x1b\[[0-9;?]*[A-Za-z]|\x1b\][^\x07\x1b]*(?:\x07|\x1b\\)?|\x1b[()][AB012]|\x1b[=>]|[\x00-\x08\x0b-\x1f\x7f]/g;
123
- function flattenTerminalOutput(raw) {
124
- return raw.replace(ANSI_OR_CTRL_RE, "").replace(/[─-▟]/g, "").replace(/\s+/g, "");
125
- }
126
- function renderTerminalOutput(raw) {
127
- const rows = /* @__PURE__ */ new Map();
128
- let row = 1;
129
- let col = 1;
130
- let savedRow = 1;
131
- let savedCol = 1;
132
- const cells = (r) => {
133
- let line = rows.get(r);
134
- if (!line) {
135
- line = [];
136
- rows.set(r, line);
137
- }
138
- return line;
139
- };
140
- const firstParam = (params, fallback = 1) => params[0] || fallback;
141
- const eraseLine = (mode) => {
142
- const line = cells(row);
143
- if (mode === 2) {
144
- rows.set(row, []);
145
- } else if (mode === 1) {
146
- for (let c = 0; c < col; c++) line[c] = " ";
147
- } else {
148
- line.length = Math.max(0, col - 1);
149
- }
150
- };
151
- for (let i = 0; i < raw.length; ) {
152
- const ch = raw[i];
153
- if (ch === "\x1B") {
154
- const kind = raw[i + 1];
155
- if (kind === "[") {
156
- let end = i + 2;
157
- while (end < raw.length) {
158
- const code = raw.charCodeAt(end);
159
- if (code >= 64 && code <= 126) break;
160
- end++;
161
- }
162
- if (end >= raw.length) break;
163
- const final = raw[end];
164
- const body = raw.slice(i + 2, end).replace(/^[?<>=!]+/, "");
165
- const params = body.split(";").map((p) => Number.parseInt(p, 10) || 0);
166
- switch (final) {
167
- case "H":
168
- case "f":
169
- row = params[0] || 1;
170
- col = params[1] || 1;
171
- break;
172
- case "G":
173
- col = firstParam(params);
174
- break;
175
- case "d":
176
- row = firstParam(params);
177
- break;
178
- case "A":
179
- row = Math.max(1, row - firstParam(params));
180
- break;
181
- case "B":
182
- row += firstParam(params);
183
- break;
184
- case "C":
185
- col += firstParam(params);
186
- break;
187
- case "D":
188
- col = Math.max(1, col - firstParam(params));
189
- break;
190
- case "E":
191
- row += firstParam(params);
192
- col = 1;
193
- break;
194
- case "F":
195
- row = Math.max(1, row - firstParam(params));
196
- col = 1;
197
- break;
198
- case "s":
199
- savedRow = row;
200
- savedCol = col;
201
- break;
202
- case "u":
203
- row = savedRow;
204
- col = savedCol;
205
- break;
206
- case "K":
207
- eraseLine(params[0] || 0);
208
- break;
209
- case "J":
210
- if ((params[0] || 0) === 2 || (params[0] || 0) === 3) rows.clear();
211
- break;
212
- case "X": {
213
- const line = cells(row);
214
- for (let c = 0; c < firstParam(params); c++) line[col - 1 + c] = " ";
215
- break;
216
- }
217
- case "P": {
218
- cells(row).splice(col - 1, firstParam(params));
219
- break;
220
- }
221
- case "@": {
222
- cells(row).splice(col - 1, 0, ...Array(firstParam(params)).fill(" "));
223
- break;
224
- }
225
- default:
226
- break;
227
- }
228
- i = end + 1;
229
- continue;
230
- }
231
- if (kind === "]" || kind === "P" || kind === "^" || kind === "_") {
232
- let end = i + 2;
233
- while (end < raw.length && raw[end] !== "\x07" && !(raw[end] === "\x1B" && raw[end + 1] === "\\")) end++;
234
- if (end >= raw.length) break;
235
- i = raw[end] === "\x07" ? end + 1 : end + 2;
236
- continue;
237
- }
238
- if (kind === "7") {
239
- savedRow = row;
240
- savedCol = col;
241
- } else if (kind === "8") {
242
- row = savedRow;
243
- col = savedCol;
244
- } else if (kind === "c") {
245
- rows.clear();
246
- row = 1;
247
- col = 1;
248
- }
249
- i += kind === "(" || kind === ")" ? 3 : 2;
250
- continue;
251
- }
252
- if (ch === "\r") {
253
- col = 1;
254
- i++;
255
- continue;
256
- }
257
- if (ch === "\n") {
258
- row++;
259
- i++;
260
- continue;
261
- }
262
- if (ch === "\b") {
263
- col = Math.max(1, col - 1);
264
- i++;
265
- continue;
266
- }
267
- if (ch === " ") {
268
- col += 8 - (col - 1) % 8;
269
- i++;
270
- continue;
271
- }
272
- if (ch < " " || ch === "\x7F") {
273
- i++;
274
- continue;
275
- }
276
- cells(row)[col - 1] = ch;
277
- col++;
278
- i++;
279
- }
280
- const populated = [...rows.keys()].sort((a, b) => a - b);
281
- return populated.map((r) => cells(r).join("")).join("\n");
282
- }
283
- function renderCleanCapture(raw, doneToken) {
284
- const rendered = renderTerminalOutput(raw).replace(/[\s─-▟]+$/gm, "");
285
- if (!doneToken) return rendered.trim();
286
- const lines2 = rendered.split("\n");
287
- const flat = (s) => flattenTerminalOutput(s);
288
- for (let i = 0; i < lines2.length; i++) {
289
- const own = flat(lines2[i]).includes(doneToken);
290
- if (own) return lines2.slice(0, i).join("\n").trim();
291
- const window = flat(lines2[i]) + (i + 1 < lines2.length ? flat(lines2[i + 1]) : "");
292
- if (window.includes(doneToken)) return lines2.slice(0, i + 1).join("\n").trim();
293
- }
294
- return rendered.trim();
295
- }
296
-
297
125
  // src/conversation/format.ts
126
+ var ANSI_OR_CTRL_RE = /\x1b\[[0-9;?]*[A-Za-z]|\x1b\][^\x07\x1b]*(?:\x07|\x1b\\)?|\x1b[()][AB012]|\x1b[=>]|[\x00-\x08\x0b-\x1f\x7f]/g;
298
127
  var DISPLAY_NAMES = {
299
128
  read_file: "Read",
300
129
  read_files: "Read",
@@ -425,6 +254,31 @@ function diffSummary({ added, removed }) {
425
254
  function settledMessage(id, role, text2, turnId) {
426
255
  return { type: "message", id, role, text: text2, streaming: false, ...turnId ? { turnId } : {} };
427
256
  }
257
+ function userMessage(id, text2, skills, turnId) {
258
+ const block = settledMessage(id, "user", text2, turnId);
259
+ return skills.length > 0 ? { ...block, skills: skills.map((s) => s.name) } : block;
260
+ }
261
+ function skillLoadNotice({ invokedBy, name, source, path, attaches }) {
262
+ return { invokedBy, name, source, path, ...attaches ? { attaches } : {} };
263
+ }
264
+ var LOAD_SKILL_TOOL = /(?:^|_)load_skill$/;
265
+ function surfaceStep(step) {
266
+ if (!step.success || !LOAD_SKILL_TOOL.test(step.toolLabel ?? step.tool)) return step;
267
+ const name = loadedSkillName(step.args);
268
+ return { ...step, result: name ? `Loaded skill ${name}.` : "Loaded a skill." };
269
+ }
270
+ function loadedSkillName(args) {
271
+ try {
272
+ const parsed = JSON.parse(args);
273
+ const name = typeof parsed === "object" && parsed !== null && "name" in parsed ? parsed.name : void 0;
274
+ return typeof name === "string" ? name : void 0;
275
+ } catch {
276
+ return void 0;
277
+ }
278
+ }
279
+ function skillLoadBlock(id, { invokedBy, name, source, path, attaches }, turnId) {
280
+ return { type: "skill_load", id, invokedBy, name, source, path, ...attaches ? { attaches } : {}, ...turnId ? { turnId } : {} };
281
+ }
428
282
  function subagentBlock(id, { toolCallId, model, usage, turnId, ...fields }) {
429
283
  return {
430
284
  type: "subagent",
@@ -764,6 +618,8 @@ function unqueueMessage(view, { messageId }) {
764
618
  }
765
619
  function reduceTaskLog(view, event) {
766
620
  switch (event.type) {
621
+ case "task_skills":
622
+ return append(view, (id) => settledMessage(id, "system", `Skills: ${event.skills.map((s) => `${s.name} (${s.path})`).join(", ")}`));
767
623
  case "turn_start":
768
624
  return startTurn(view, event);
769
625
  case "turn_end":
@@ -1041,7 +897,8 @@ var UPDATABLE_FIELDS = [
1041
897
  "userSteps",
1042
898
  "autonomy",
1043
899
  "sliceType",
1044
- "ops"
900
+ "ops",
901
+ "skills"
1045
902
  ];
1046
903
  function taskOpsProtocol(executionNote = "", tools = false) {
1047
904
  const updateChanges = UPDATABLE_FIELDS.map((f) => f === "dependencies" ? '"dependencies"?:["<id or #order>"]' : `"${f}"?`).join(",");
@@ -1064,6 +921,7 @@ function taskOpsProtocol(executionNote = "", tools = false) {
1064
921
  ...tools ? ["edit_plan checks the batch when you call it and answers with what it will change, or with the error to fix \u2014 call it again in the same reply. The edit is applied when your reply ends; edits you make in one reply join one batch."] : [],
1065
922
  'Just declare the dependencies you want \u2014 display order is repaired for you afterwards, so a rewire or a newly added prerequisite never needs a "reorder" op. Only a task that is running or completed cannot be shifted, so an edit that would need one to move is rejected.' + executionNote,
1066
923
  'Flipping "type" between "ai" and "user" is a content change, not just a label: an update to "user" needs "userSteps" in the SAME op, and an update to "ai" needs "prompt" in the SAME op \u2014 the model/mode/effort/autonomy fields (flipping to "user") or the userSteps (flipping to "ai") are cleared automatically.',
924
+ `"skills" in "changes" REPLACES the task's whole skill list. To add one, send the names the plan block shows in its skills:[...] plus the new one; to drop one, send the rest; [] removes them all.`,
1067
925
  '"rearm" puts a failed OR completed task back to pending \u2014 verdict and output summary are cleared, any dependents it had blocked are released, and it may carry field changes (e.g. a corrected "prompt") applied in the same op. A running task cannot be re-armed. Never rearm a task just to relabel it \u2014 only when it should actually run again.'
1068
926
  ];
1069
927
  }
@@ -1159,8 +1017,22 @@ function updatableChanges(raw) {
1159
1017
  if (raw && key in raw) changes[key] = raw[key];
1160
1018
  }
1161
1019
  if ("ops" in changes) changes.ops = opsFlag(changes.ops);
1020
+ if ("skills" in changes) changes.skills = skillNames(changes.skills);
1162
1021
  return changes;
1163
1022
  }
1023
+ function withSkillNames(subtasks) {
1024
+ if (!Array.isArray(subtasks)) return subtasks;
1025
+ return subtasks.map((sub) => {
1026
+ if (typeof sub !== "object" || sub === null) return sub;
1027
+ const { skills, ...rest } = sub;
1028
+ const names = skillNames(skills);
1029
+ return {
1030
+ ...rest,
1031
+ ...names ? { skills: names } : {},
1032
+ ..."subtasks" in rest ? { subtasks: withSkillNames(rest.subtasks) } : {}
1033
+ };
1034
+ });
1035
+ }
1164
1036
  function findInTasks(tasks, id) {
1165
1037
  return flattenTasks(tasks).find((t) => t.id === id);
1166
1038
  }
@@ -1328,41 +1200,38 @@ function applyTaskOps(currentTasks, ops, runners, catalog) {
1328
1200
  }
1329
1201
  return { ids, bad };
1330
1202
  };
1203
+ const prepareEdit = (op, opIndex, label, audience, refuseRunning = false) => {
1204
+ const ref = resolveRef(op.taskId, originalFlatAll, flattenTasks(tasks), handleOwner, handleId, opIndex);
1205
+ if ("error" in ref) return { error: `${label}: ${ref.error}` };
1206
+ const target = findInTasks(tasks, ref.id);
1207
+ if (!target) return { error: `${label}: task "${op.taskId}" no longer exists in this batch (removed, merged, or split by an earlier op)` };
1208
+ if (refuseRunning && target.status === "in_progress") return { error: `${label}: "${target.title}" is running and cannot be re-armed` };
1209
+ const changes = updatableChanges(op.changes);
1210
+ if (changes.assignedRunner && !runners.includes(changes.assignedRunner)) {
1211
+ return { error: `${label}: runner "${changes.assignedRunner}" is not in this plan's runner set [${runners.join(", ")}]` };
1212
+ }
1213
+ const changesForCheck = { ...changes };
1214
+ delete changesForCheck.dependencies;
1215
+ const check = validateTaskEdit(audience, flattenTasks(tasks), target.id, changesForCheck, catalog);
1216
+ if (!check.ok) return { error: `${label}: ${check.error}` };
1217
+ for (const field of check.clear ?? []) changes[field] = void 0;
1218
+ if ("dependencies" in changes) {
1219
+ const { ids, bad } = resolveDeps(changes.dependencies, opIndex);
1220
+ if (bad.length) return { error: `${label}: unknown dependencies: ${bad.join(", ")}` };
1221
+ changes.dependencies = ids.filter((id) => id !== target.id);
1222
+ }
1223
+ return { target, changes, check };
1224
+ };
1331
1225
  for (const [i, op] of ops.entries()) {
1332
1226
  const label = `op ${i + 1} (${op.op})`;
1333
1227
  switch (op.op) {
1334
1228
  case "update": {
1335
- const ref = resolveRef(op.taskId, originalFlatAll, flattenTasks(tasks), handleOwner, handleId, i);
1336
- if ("error" in ref) {
1337
- errors.push(`${label}: ${ref.error}`);
1229
+ const prep = prepareEdit(op, i, label, "planner");
1230
+ if ("error" in prep) {
1231
+ errors.push(prep.error);
1338
1232
  break;
1339
1233
  }
1340
- const target = findInTasks(tasks, ref.id);
1341
- if (!target) {
1342
- errors.push(`${label}: task "${op.taskId}" no longer exists in this batch (removed, merged, or split by an earlier op)`);
1343
- break;
1344
- }
1345
- const changes = updatableChanges(op.changes);
1346
- if (changes.assignedRunner && !runners.includes(changes.assignedRunner)) {
1347
- errors.push(`${label}: runner "${changes.assignedRunner}" is not in this plan's runner set [${runners.join(", ")}]`);
1348
- break;
1349
- }
1350
- const changesForCheck = { ...changes };
1351
- delete changesForCheck.dependencies;
1352
- const check = validateTaskEdit("planner", flattenTasks(tasks), target.id, changesForCheck, catalog);
1353
- if (!check.ok) {
1354
- errors.push(`${label}: ${check.error}`);
1355
- break;
1356
- }
1357
- for (const field of check.clear ?? []) changes[field] = void 0;
1358
- if ("dependencies" in changes) {
1359
- const { ids, bad } = resolveDeps(changes.dependencies, i);
1360
- if (bad.length) {
1361
- errors.push(`${label}: unknown dependencies: ${bad.join(", ")}`);
1362
- break;
1363
- }
1364
- changes.dependencies = ids.filter((id) => id !== target.id);
1365
- }
1234
+ const { target, changes, check } = prep;
1366
1235
  if (Object.keys(changes).length === 0) {
1367
1236
  errors.push(`${label}: no valid changes provided`);
1368
1237
  break;
@@ -1392,6 +1261,7 @@ function applyTaskOps(currentTasks, ops, runners, catalog) {
1392
1261
  const newId = uuidv4();
1393
1262
  tasks = addTaskToPlan(tasks, {
1394
1263
  ...spec,
1264
+ subtasks: withSkillNames(spec.subtasks),
1395
1265
  id: newId,
1396
1266
  dependencies: ids,
1397
1267
  assignedRunner: runner,
@@ -1459,7 +1329,7 @@ function applyTaskOps(currentTasks, ops, runners, catalog) {
1459
1329
  errors.push(`${label}: unknown task in merge list (already removed, merged, or split by an earlier op)`);
1460
1330
  break;
1461
1331
  }
1462
- const toMerge = resolved.map((t) => t).sort((a, b) => a.order - b.order);
1332
+ const toMerge = [...new Map(resolved.map((t) => [t.id, t])).values()].sort((a, b) => a.order - b.order);
1463
1333
  if (toMerge.length < 2) {
1464
1334
  errors.push(`${label}: merge needs at least two tasks`);
1465
1335
  break;
@@ -1495,6 +1365,7 @@ function applyTaskOps(currentTasks, ops, runners, catalog) {
1495
1365
  autonomy: spec.autonomy ?? toMerge.find((t) => t.autonomy)?.autonomy,
1496
1366
  sliceType: spec.sliceType ?? toMerge.find((t) => t.sliceType)?.sliceType,
1497
1367
  ops: inheritedOps(toMerge, spec.ops),
1368
+ skills: inheritedSkills(spec.skills, toMerge.flatMap((t) => t.skills ?? [])),
1498
1369
  userStoriesCovered: spec.userStoriesCovered ?? (toMerge.flatMap((t) => t.userStoriesCovered ?? []).length ? [...new Set(toMerge.flatMap((t) => t.userStoriesCovered ?? []))] : void 0)
1499
1370
  });
1500
1371
  const mergedId = mergedTask.id;
@@ -1576,6 +1447,7 @@ function applyTaskOps(currentTasks, ops, runners, catalog) {
1576
1447
  autonomy: spec.autonomy ?? target.autonomy,
1577
1448
  sliceType: spec.sliceType ?? target.sliceType,
1578
1449
  ops: inheritedOps([target], spec.ops),
1450
+ skills: inheritedSkills(spec.skills, target.skills),
1579
1451
  userStoriesCovered: spec.userStoriesCovered ?? target.userStoriesCovered
1580
1452
  });
1581
1453
  newTasks.push(nt);
@@ -1597,41 +1469,12 @@ function applyTaskOps(currentTasks, ops, runners, catalog) {
1597
1469
  break;
1598
1470
  }
1599
1471
  case "rearm": {
1600
- const ref = resolveRef(op.taskId, originalFlatAll, flattenTasks(tasks), handleOwner, handleId, i);
1601
- if ("error" in ref) {
1602
- errors.push(`${label}: ${ref.error}`);
1472
+ const prep = prepareEdit(op, i, label, "direct", true);
1473
+ if ("error" in prep) {
1474
+ errors.push(prep.error);
1603
1475
  break;
1604
1476
  }
1605
- const target = findInTasks(tasks, ref.id);
1606
- if (!target) {
1607
- errors.push(`${label}: task "${op.taskId}" no longer exists in this batch (removed, merged, or split by an earlier op)`);
1608
- break;
1609
- }
1610
- if (target.status === "in_progress") {
1611
- errors.push(`${label}: "${target.title}" is running and cannot be re-armed`);
1612
- break;
1613
- }
1614
- const changes = updatableChanges(op.changes);
1615
- if (changes.assignedRunner && !runners.includes(changes.assignedRunner)) {
1616
- errors.push(`${label}: runner "${changes.assignedRunner}" is not in this plan's runner set [${runners.join(", ")}]`);
1617
- break;
1618
- }
1619
- const changesForCheck = { ...changes };
1620
- delete changesForCheck.dependencies;
1621
- const check = validateTaskEdit("direct", flattenTasks(tasks), target.id, changesForCheck, catalog);
1622
- if (!check.ok) {
1623
- errors.push(`${label}: ${check.error}`);
1624
- break;
1625
- }
1626
- for (const field of check.clear ?? []) changes[field] = void 0;
1627
- if ("dependencies" in changes) {
1628
- const { ids, bad } = resolveDeps(changes.dependencies, i);
1629
- if (bad.length) {
1630
- errors.push(`${label}: unknown dependencies: ${bad.join(", ")}`);
1631
- break;
1632
- }
1633
- changes.dependencies = ids.filter((id) => id !== target.id);
1634
- }
1477
+ const { target, changes, check } = prep;
1635
1478
  tasks = updateTaskInPlan(tasks, target.id, { ...changes, status: "pending", verdict: void 0, outputSummary: void 0, awaitingReason: void 0 });
1636
1479
  for (const dep of flattenTasks(tasks)) {
1637
1480
  if (dep.status === "blocked" && dep.dependencies.includes(target.id)) {
@@ -1749,9 +1592,8 @@ function continuability(task) {
1749
1592
  return refuse("its work is waiting on a merge conflict. Resolve or repair the conflict instead.");
1750
1593
  }
1751
1594
  if (task.status !== "completed" && task.status !== "failed") return refuse("only a completed or failed task can be.");
1752
- if (task.transport?.kind !== "structured") return refuse("it ran in a terminal, so there is no saved session to resume. Use Retry instead.");
1753
- if (!task.transport.nativeSessionId) return refuse("its runner left no saved session to resume. Use Retry instead.");
1754
- return { ok: true, sessionId: task.transport.nativeSessionId };
1595
+ if (!task.runnerSessionId) return refuse("its runner left no saved session to resume. Use Retry instead.");
1596
+ return { ok: true, sessionId: task.runnerSessionId };
1755
1597
  }
1756
1598
  function canContinue(task) {
1757
1599
  return continuability(task).ok;
@@ -1776,7 +1618,8 @@ function serializeTask(t) {
1776
1618
  autonomy: t.autonomy || void 0,
1777
1619
  sliceType: t.sliceType || void 0,
1778
1620
  userStoriesCovered: t.userStoriesCovered || void 0,
1779
- ...t.ops ? { ops: true } : {}
1621
+ ...t.ops ? { ops: true } : {},
1622
+ ...t.skills?.length ? { skills: [...t.skills] } : {}
1780
1623
  };
1781
1624
  }
1782
1625
  function serializeTaskStatus(t, idleSince = null, isolation = null, queued = [], awaitingApproval = 0, mergeGate = [], checkpoint = "") {
@@ -1786,7 +1629,6 @@ function serializeTaskStatus(t, idleSince = null, isolation = null, queued = [],
1786
1629
  verdict: t.verdict ? { outcome: t.verdict.outcome, reason: t.verdict.reason, checks: t.verdict.checks || [] } : null,
1787
1630
  idleSince,
1788
1631
  ...isolation ? { isolation } : {},
1789
- ...t.transport ? { transport: t.transport.fallback ? { kind: t.transport.kind, fallback: t.transport.fallback } : { kind: t.transport.kind } } : {},
1790
1632
  ...t.status === "awaiting_user" && t.awaitingReason ? { awaitingReason: t.awaitingReason } : {},
1791
1633
  ...t.status === "awaiting_user" && t.awaitingReason === "checkpoint" && checkpoint ? { checkpoint } : {},
1792
1634
  ...queued.length > 0 ? { queued: queued.map((m) => ({ ...m })) } : {},
@@ -1796,14 +1638,39 @@ function serializeTaskStatus(t, idleSince = null, isolation = null, queued = [],
1796
1638
  ...t.forcedPastGate?.length ? { forcedPastGate: [...t.forcedPastGate] } : {}
1797
1639
  };
1798
1640
  }
1641
+ function surfaceConversation(history) {
1642
+ return history?.map(({ skill, ...m }) => skill ? { ...m, skill: skillLoadNotice(skill) } : m);
1643
+ }
1644
+ function surfaceQueued(queued) {
1645
+ return queued?.map(({ skills, ...m }) => skills ? { ...m, skills: skills.map(skillLoadNotice) } : m);
1646
+ }
1647
+ function surfaceTask({ attemptSkills, subtasks, runnerSessionId: _runnerSessionId, ...task }) {
1648
+ return {
1649
+ ...task,
1650
+ ...attemptSkills ? { attemptSkills: attemptSkills.map(({ name, source, path }) => ({ name, source, path })) } : {},
1651
+ subtasks: (subtasks ?? []).map(surfaceTask)
1652
+ };
1653
+ }
1654
+ function surfacePlan(plan) {
1655
+ return {
1656
+ ...plan,
1657
+ tasks: plan.tasks.map(surfaceTask),
1658
+ conversationHistory: surfaceConversation(plan.conversationHistory),
1659
+ queuedMessages: surfaceQueued(plan.queuedMessages),
1660
+ researchLog: plan.researchLog?.map((e) => "type" in e ? e : surfaceStep(e))
1661
+ };
1662
+ }
1663
+ function surfacePlanState(state) {
1664
+ return state.phase === "planning" ? { ...state, pendingTasks: state.pendingTasks.map(surfaceTask) } : { ...state, pendingTasks: state.pendingTasks.map(surfaceTask), executionLog: state.executionLog.map(surfaceTask) };
1665
+ }
1799
1666
  function serializePlan(plan) {
1800
1667
  return {
1801
1668
  tasks: plan.tasks.map(serializeTask),
1802
1669
  runners: plan.runners,
1803
1670
  generatedAt: plan.generatedAt,
1804
- conversationHistory: plan.conversationHistory,
1671
+ conversationHistory: surfaceConversation(plan.conversationHistory),
1805
1672
  prdMarkdown: plan.prdMarkdown,
1806
- queuedMessages: plan.queuedMessages
1673
+ queuedMessages: surfaceQueued(plan.queuedMessages)
1807
1674
  };
1808
1675
  }
1809
1676
  function executionSummary(tasks) {
@@ -1837,13 +1704,15 @@ function finalSegmentIndex(blocks, turnId, pastPlan = false) {
1837
1704
  }
1838
1705
  return -1;
1839
1706
  }
1840
- function openTurn(view, turnId, prompt) {
1707
+ function openTurn(view, { turnId, prompt = "", skills = [] }) {
1841
1708
  const i = findLastIndex(view.blocks, (b) => b.type === "message" && b.role === "user");
1842
1709
  const sent = view.blocks[i];
1843
- if (sent?.type === "message" && sent.turnId === void 0 && sent.text === prompt) {
1844
- return { ...view, blocks: replaceAt(view.blocks, i, { ...sent, turnId }) };
1845
- }
1846
- return append(view, (id) => settledMessage(id, "user", prompt, turnId));
1710
+ const adopted = sent?.type === "message" && sent.turnId === void 0 && sent.text === prompt;
1711
+ const said = adopted ? { ...view, blocks: replaceAt(view.blocks, i, userMessage(sent.id, prompt, skills, turnId)) } : append(view, (id) => userMessage(id, prompt, skills, turnId));
1712
+ if (skills.length === 0) return said;
1713
+ const at = adopted ? i + 1 : findLastIndex(said.blocks, (b) => b.type === "message" && b.role === "user") + 1;
1714
+ const loads = skills.map((skill, n) => skillLoadBlock(`b${said.nextId + n}`, skill, turnId));
1715
+ return { ...said, blocks: [...said.blocks.slice(0, at), ...loads, ...said.blocks.slice(at)], nextId: said.nextId + loads.length };
1847
1716
  }
1848
1717
  function streamText(view, { turnId, segmentId, text: text2 }) {
1849
1718
  const i = findLastIndex(view.blocks, (b) => isUnsettledSegment(b, turnId) && b.segmentId === segmentId);
@@ -1990,7 +1859,9 @@ function reduceConversation(view, input) {
1990
1859
  case "local_entry":
1991
1860
  return append(view, (id) => settledMessage(id, input.role, input.text));
1992
1861
  case "planner_turn_started":
1993
- return input.prompt === void 0 ? view : openTurn(view, input.turnId, input.prompt);
1862
+ return input.prompt === void 0 ? view : openTurn(view, input);
1863
+ case "planner_skill_loaded":
1864
+ return append(sealLane(view, null, -1), (id) => skillLoadBlock(id, input.skill, input.turnId));
1994
1865
  case "planner_text_delta":
1995
1866
  return streamText(view, input);
1996
1867
  case "planner_message":
@@ -2030,11 +1901,27 @@ function reduceConversation(view, input) {
2030
1901
  var USER = 0;
2031
1902
  var RESEARCH = 1;
2032
1903
  var SETTLED = 2;
2033
- function fromEntry(entry) {
1904
+ function fromEntry(entry, loaded = []) {
2034
1905
  if (entry.kind === "plan_generated") return (id) => ({ type: "plan", id: id(), text: "", ...planMarker(entry.content) });
1906
+ if (entry.kind === "skill_load" && entry.skill) {
1907
+ const { skill } = entry;
1908
+ return (id) => skillLoadBlock(id(), skillLoadNotice(skill));
1909
+ }
1910
+ if (entry.role === "user" && !entry.kind) return (id) => userMessage(id(), entry.content, loaded.map(skillLoadNotice));
2035
1911
  const role = entry.kind === "system" || entry.kind === "compaction" ? "system" : entry.role === "user" ? "user" : "planner";
2036
1912
  return (id) => settledMessage(id(), role, entry.content);
2037
1913
  }
1914
+ function loadsAfter(entries, index) {
1915
+ const loads = [];
1916
+ for (let i = index + 1; i < entries.length && entries[i].kind === "skill_load"; i++) {
1917
+ const { skill } = entries[i];
1918
+ if (skill?.invokedBy === "user") loads.push(skill);
1919
+ }
1920
+ return loads;
1921
+ }
1922
+ function rankOf(entry) {
1923
+ return entry.role === "user" && (!entry.kind || entry.kind === "skill_load") ? USER : SETTLED;
1924
+ }
2038
1925
  function spawnBrief(step) {
2039
1926
  try {
2040
1927
  const args = JSON.parse(step.args);
@@ -2097,7 +1984,7 @@ function fromTranscript(conversationHistory, researchLog, plannerUsage) {
2097
1984
  const kept = compacted ? history.slice(1) : history;
2098
1985
  const cutoff = compacted ? kept[0]?.timestamp ?? compacted.timestamp : "";
2099
1986
  const placed = [
2100
- ...kept.map((entry) => ({ at: entry.timestamp, rank: entry.role === "user" && !entry.kind ? USER : SETTLED, build: fromEntry(entry) })),
1987
+ ...kept.map((entry, i) => ({ at: entry.timestamp, rank: rankOf(entry), build: fromEntry(entry, loadsAfter(kept, i)) })),
2101
1988
  ...research(researchLog ?? []).filter((item) => item.at >= cutoff)
2102
1989
  ];
2103
1990
  placed.sort((a, b) => a.at < b.at ? -1 : a.at > b.at ? 1 : a.rank - b.rank);
@@ -2144,7 +2031,8 @@ var TURN_STREAM = /* @__PURE__ */ new Set([
2144
2031
  "research_step_done",
2145
2032
  "subagent_started",
2146
2033
  "subagent_finished",
2147
- "planner_turn_ended"
2034
+ "planner_turn_ended",
2035
+ "planner_skill_loaded"
2148
2036
  ]);
2149
2037
  function cutOff(gate, input) {
2150
2038
  if (gate.stopped === null || !TURN_STREAM.has(input.type)) return false;
@@ -2289,15 +2177,14 @@ export {
2289
2177
  plannerContextFill,
2290
2178
  mapAgentTool,
2291
2179
  normalizeAgentArgs,
2292
- flattenTerminalOutput,
2293
- renderTerminalOutput,
2294
- renderCleanCapture,
2295
2180
  toolHeadline,
2296
2181
  outputLines,
2297
2182
  outputPreview,
2298
2183
  diffStat,
2299
2184
  diffRows,
2300
2185
  diffSummary,
2186
+ skillLoadNotice,
2187
+ surfaceStep,
2301
2188
  EMPTY_TASK_LOG,
2302
2189
  runnerToolSubject,
2303
2190
  reduceTaskLog,
@@ -2330,6 +2217,8 @@ export {
2330
2217
  canContinue,
2331
2218
  serializeTask,
2332
2219
  serializeTaskStatus,
2220
+ surfacePlan,
2221
+ surfacePlanState,
2333
2222
  serializePlan,
2334
2223
  executionSummary,
2335
2224
  CHECKPOINT_TRUNCATE_LENGTH,
@@ -2359,4 +2248,4 @@ export {
2359
2248
  pastGateConfirmation,
2360
2249
  newTaskFields
2361
2250
  };
2362
- //# sourceMappingURL=chunk-Y36NIASW.mjs.map
2251
+ //# sourceMappingURL=chunk-BLLIBCCS.mjs.map