@ordewell/core 0.7.0 → 0.7.1

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 (53) hide show
  1. package/dist/{IFileSystem-DgpX0BU7.d.mts → IFileSystem-BnLh-_SK.d.mts} +1 -1
  2. package/dist/{IFileSystem-D4ADfTrX.d.ts → IFileSystem-DofiRcCo.d.ts} +1 -1
  3. package/dist/{ModeResolver-Cv01ZDd9.d.mts → ModeResolver-DZzJSdIU.d.mts} +1 -1
  4. package/dist/{ModeResolver-BEcRAz1c.d.ts → ModeResolver-DkMYf4uS.d.ts} +1 -1
  5. package/dist/{Task-CoKhvBa1.d.mts → Task-BnLxkVQF.d.mts} +140 -21
  6. package/dist/{Task-CoKhvBa1.d.ts → Task-BnLxkVQF.d.ts} +140 -21
  7. package/dist/{chunk-YU4UKKKI.mjs → chunk-LGQNXPBX.mjs} +10 -2
  8. package/dist/chunk-LGQNXPBX.mjs.map +1 -0
  9. package/dist/{chunk-N66ZHFGN.mjs → chunk-OYUSADFM.mjs} +11 -1
  10. package/dist/chunk-OYUSADFM.mjs.map +1 -0
  11. package/dist/{chunk-HPNUFBIT.mjs → chunk-V3JHS7AX.mjs} +9 -1
  12. package/dist/chunk-V3JHS7AX.mjs.map +1 -0
  13. package/dist/{chunk-LSGY7AIZ.mjs → chunk-Y36NIASW.mjs} +183 -11
  14. package/dist/chunk-Y36NIASW.mjs.map +1 -0
  15. package/dist/{chunk-J3YSTPCE.mjs → chunk-ZV5LDNCO.mjs} +5 -4
  16. package/dist/chunk-ZV5LDNCO.mjs.map +1 -0
  17. package/dist/index.d.mts +287 -223
  18. package/dist/index.d.ts +287 -223
  19. package/dist/index.js +2111 -1086
  20. package/dist/index.js.map +1 -1
  21. package/dist/index.mjs +1973 -1117
  22. package/dist/index.mjs.map +1 -1
  23. package/dist/order-labels.d.mts +15 -2
  24. package/dist/order-labels.d.ts +15 -2
  25. package/dist/order-labels.js +12 -2
  26. package/dist/order-labels.js.map +1 -1
  27. package/dist/order-labels.mjs +7 -3
  28. package/dist/{parsing-B4OCHH1_.d.mts → parsing-B6ctfF80.d.mts} +2 -2
  29. package/dist/{parsing-DMdOq-BV.d.ts → parsing-ddZXZFP4.d.ts} +2 -2
  30. package/dist/parsing.d.mts +3 -3
  31. package/dist/parsing.d.ts +3 -3
  32. package/dist/parsing.js +6 -3
  33. package/dist/parsing.js.map +1 -1
  34. package/dist/parsing.mjs +3 -3
  35. package/dist/{plan-utils-BdYPRBno.d.ts → plan-utils--kQRzSE-.d.ts} +226 -7
  36. package/dist/{plan-utils-CD1Xu65s.d.mts → plan-utils-CKgNtDwQ.d.mts} +226 -7
  37. package/dist/plan-utils.d.mts +4 -3
  38. package/dist/plan-utils.d.ts +4 -3
  39. package/dist/plan-utils.js +202 -3
  40. package/dist/plan-utils.js.map +1 -1
  41. package/dist/plan-utils.mjs +40 -3
  42. package/dist/testing.d.mts +17 -5
  43. package/dist/testing.d.ts +17 -5
  44. package/dist/testing.js +45 -2
  45. package/dist/testing.js.map +1 -1
  46. package/dist/testing.mjs +45 -4
  47. package/dist/testing.mjs.map +1 -1
  48. package/package.json +1 -1
  49. package/dist/chunk-HPNUFBIT.mjs.map +0 -1
  50. package/dist/chunk-J3YSTPCE.mjs.map +0 -1
  51. package/dist/chunk-LSGY7AIZ.mjs.map +0 -1
  52. package/dist/chunk-N66ZHFGN.mjs.map +0 -1
  53. package/dist/chunk-YU4UKKKI.mjs.map +0 -1
@@ -24,13 +24,17 @@ __export(plan_utils_exports, {
24
24
  EMPTY_CONVERSATION: () => EMPTY_CONVERSATION,
25
25
  EMPTY_HOLD: () => EMPTY_HOLD,
26
26
  EMPTY_TASK_LOG: () => EMPTY_TASK_LOG,
27
+ NOT_STARTED: () => NOT_STARTED,
27
28
  NO_TURN: () => NO_TURN,
28
29
  aheadOfDraft: () => aheadOfDraft,
30
+ approvalLabel: () => approvalLabel,
31
+ awaitingLabel: () => awaitingLabel,
29
32
  canMergeTasks: () => canMergeTasks,
30
33
  canSetDependencies: () => canSetDependencies,
31
34
  canSplitTask: () => canSplitTask,
32
35
  capConflictFiles: () => capConflictFiles,
33
36
  dependencyCandidates: () => dependencyCandidates,
37
+ dependentsNotice: () => dependentsNotice,
34
38
  dependentsOf: () => dependentsOf,
35
39
  diffRows: () => diffRows,
36
40
  diffStat: () => diffStat,
@@ -40,15 +44,29 @@ __export(plan_utils_exports, {
40
44
  fromTranscript: () => fromTranscript,
41
45
  hasHiddenDetail: () => hasHiddenDetail,
42
46
  holdPrompt: () => holdPrompt,
47
+ isTaskRunning: () => isTaskRunning,
48
+ markAction: () => markAction,
49
+ markRequestFor: () => markRequestFor,
50
+ namedRepos: () => namedRepos,
51
+ newTaskFields: () => newTaskFields,
52
+ opsEditable: () => opsEditable,
43
53
  outputLines: () => outputLines,
44
54
  outputPreview: () => outputPreview,
55
+ pastGateConfirmation: () => pastGateConfirmation,
45
56
  reduceConversation: () => reduceConversation,
46
57
  reduceTaskLog: () => reduceTaskLog,
47
58
  replayTaskLog: () => replayTaskLog,
48
59
  runnerToolSubject: () => runnerToolSubject,
49
60
  stopTurn: () => stopTurn,
50
61
  summarizeToolCall: () => summarizeToolCall,
62
+ taskOrderLabel: () => taskOrderLabel,
63
+ taskRef: () => taskRef,
64
+ taskRowActions: () => taskRowActions,
65
+ taskRowView: () => taskRowView,
51
66
  taskStartedNotice: () => taskStartedNotice,
67
+ taskStatusKind: () => taskStatusKind,
68
+ titledRefs: () => titledRefs,
69
+ titledTaskRef: () => titledTaskRef,
52
70
  toolHeadline: () => toolHeadline,
53
71
  truncateCheckpointSummary: () => truncateCheckpointSummary,
54
72
  unsendAll: () => unsendAll,
@@ -58,6 +76,50 @@ module.exports = __toCommonJS(plan_utils_exports);
58
76
 
59
77
  // src/services/TaskOps.ts
60
78
  var import_uuid = require("uuid");
79
+
80
+ // src/order-labels.ts
81
+ function taskOrderLabel(task, parent) {
82
+ return parent ? `${parent.order}.${task.order}` : String(task.order);
83
+ }
84
+ function taskRef(task, parent) {
85
+ return `#${taskOrderLabel(task, parent)}`;
86
+ }
87
+ function titledTaskRef(task, parent) {
88
+ return `${taskRef(task, parent)} ${task.title}`;
89
+ }
90
+
91
+ // src/taskRow/status.ts
92
+ var isTaskRunning = (task) => task.status === "in_progress" || task.status === "running";
93
+ var NOT_STARTED = /* @__PURE__ */ new Set(["pending", "approved", "blocked"]);
94
+ function taskStatusKind(task) {
95
+ switch (task.status) {
96
+ case "completed":
97
+ return "done";
98
+ case "failed":
99
+ return "failed";
100
+ case "blocked":
101
+ return "blocked";
102
+ case "awaiting_user":
103
+ return "awaiting";
104
+ }
105
+ if (!isTaskRunning(task)) return "todo";
106
+ return task.status === "in_progress" && task.idleSince ? "quiet" : "running";
107
+ }
108
+ var AWAITING_LABELS = {
109
+ input: "Waiting for your input",
110
+ checkpoint: "Checkpoint",
111
+ conflict: "Merge conflict",
112
+ "files-changed": "Changed tracked files"
113
+ };
114
+ function awaitingLabel(task) {
115
+ return task.status === "awaiting_user" && task.awaitingReason ? AWAITING_LABELS[task.awaitingReason] : null;
116
+ }
117
+ function approvalLabel(count) {
118
+ if (!count) return null;
119
+ return count > 1 ? `Waiting for approval (${count})` : "Waiting for approval";
120
+ }
121
+
122
+ // src/services/TaskOps.ts
61
123
  function detectCycle(tasks) {
62
124
  const byId = new Map(tasks.map((t) => [t.id, t]));
63
125
  const visiting = /* @__PURE__ */ new Set();
@@ -1031,9 +1093,25 @@ function endTurn2(view, { reason }) {
1031
1093
  const closed = closeOpenBlocks({ ...view, working: false, lastTurnEnd: reason, streams: {} }, CUT[reason]);
1032
1094
  return reason === "interrupted" ? append(closed, (id) => settledMessage(id, "system", "Interrupted.")) : closed;
1033
1095
  }
1034
- function queueMessage(view, { messageId, text: text2 }) {
1035
- if (view.queued.some((m) => m.id === messageId)) return view;
1036
- return { ...view, queued: [...view.queued, { id: messageId, text: text2 }] };
1096
+ function queueMessage(view, { messageId, text: text2, forced }) {
1097
+ const listed = view.queued.find((m) => m.id === messageId);
1098
+ if (forced) {
1099
+ const rest = view.queued.filter((m) => m !== listed);
1100
+ const at = rest.findIndex((m) => !m.forced);
1101
+ const placed = at < 0 ? rest.length : at;
1102
+ return { ...view, queued: [...rest.slice(0, placed), { id: messageId, text: text2, forced: true }, ...rest.slice(placed)] };
1103
+ }
1104
+ if (!listed) return { ...view, queued: [...view.queued, { id: messageId, text: text2 }] };
1105
+ if (!listed.handedOver) return view;
1106
+ return { ...view, queued: view.queued.map((m) => m === listed ? { id: m.id, text: m.text } : m) };
1107
+ }
1108
+ function handOver(view, { messageId }) {
1109
+ const listed = view.queued.find((m) => m.id === messageId);
1110
+ if (!listed || listed.handedOver) return view;
1111
+ return { ...view, queued: view.queued.map((m) => m === listed ? { ...m, handedOver: true } : m) };
1112
+ }
1113
+ function deliverMidTurn(view, event) {
1114
+ return appendOutput(unqueueMessage(view, event), null, (id) => settledMessage(id, "user", event.text));
1037
1115
  }
1038
1116
  function unqueueMessage(view, { messageId }) {
1039
1117
  const queued = view.queued.filter((m) => m.id !== messageId);
@@ -1067,6 +1145,12 @@ function reduceTaskLog(view, event) {
1067
1145
  return queueMessage(view, event);
1068
1146
  case "message_removed":
1069
1147
  return unqueueMessage(view, event);
1148
+ case "message_handed_over":
1149
+ return handOver(view, event);
1150
+ case "message_delivered":
1151
+ return deliverMidTurn(view, event);
1152
+ case "message_undelivered":
1153
+ return append(unqueueMessage(view, event), (id) => settledMessage(id, "system", `${event.text} \xB7 not delivered`));
1070
1154
  case "error":
1071
1155
  return appendOutput(view, null, (id) => settledMessage(id, "error", event.message));
1072
1156
  case "approval_requested":
@@ -1155,19 +1239,120 @@ function hasHiddenDetail(blocks) {
1155
1239
  function taskStartedNotice(title, runner) {
1156
1240
  return runner ? `Started "${title}" \xB7 ${runner}` : `Started "${title}"`;
1157
1241
  }
1242
+
1243
+ // src/taskRow/actions.ts
1244
+ var UNSTARTED_AI = (t) => t.type === "ai" && NOT_STARTED.has(t.status);
1245
+ var QUEUED = (t) => t.status === "pending" || t.status === "approved";
1246
+ var TASK_RULES = [
1247
+ ["cancel", (t) => t.status === "in_progress"],
1248
+ ["skip", (t) => t.status === "blocked"],
1249
+ ["force-start", UNSTARTED_AI],
1250
+ // A manual task has no runner to report it done, so it can always be marked.
1251
+ ["complete", (t) => t.status === "awaiting_user" || t.type === "user"],
1252
+ ["uncomplete", (t) => t.status === "completed"]
1253
+ ];
1254
+ var SUBTASK_RULES = [
1255
+ ["cancel", (t) => t.status === "in_progress"],
1256
+ ["complete", (t) => t.status === "in_progress" && t.type === "ai"],
1257
+ ["force-start", (t) => t.type === "ai" && QUEUED(t)],
1258
+ ["skip", QUEUED],
1259
+ ["complete", (t) => t.status === "awaiting_user"],
1260
+ ["uncomplete", (t) => t.status === "completed"]
1261
+ ];
1262
+ function taskRowActions(task, placement = "task") {
1263
+ const rules = placement === "subtask" ? SUBTASK_RULES : TASK_RULES;
1264
+ return rules.filter(([, applies]) => applies(task)).map(([action]) => action);
1265
+ }
1266
+ function markAction(task) {
1267
+ return task.status === "completed" ? "uncomplete" : "complete";
1268
+ }
1269
+ function markRequestFor(action) {
1270
+ if (action === "complete" || action === "skip") return "complete";
1271
+ if (action === "uncomplete") return "uncomplete";
1272
+ return null;
1273
+ }
1274
+ function opsEditable(task) {
1275
+ return UNSTARTED_AI(task);
1276
+ }
1277
+
1278
+ // src/taskRow/view.ts
1279
+ var refsOf = (ids, orderOf) => ids.map((id) => {
1280
+ const order = orderOf?.get(id);
1281
+ return order === void 0 ? id : taskRef({ order });
1282
+ });
1283
+ var namedRepo = (repo) => repo && repo !== "." ? repo : null;
1284
+ var namedRepos = (repos) => (repos ?? []).filter((r) => r !== ".");
1285
+ var filesOf = (files) => files?.length ? capConflictFiles(files) : null;
1286
+ function taskRowView(task, context = {}) {
1287
+ const parent = context.parent ?? void 0;
1288
+ const isolation = task.isolation && task.isolation.state !== "none" ? task.isolation : null;
1289
+ return {
1290
+ orderLabel: taskOrderLabel(task, parent),
1291
+ kind: task.type === "user" ? "user" : task.ops ? "ops" : "ai",
1292
+ status: taskStatusKind(task),
1293
+ running: isTaskRunning(task),
1294
+ awaiting: awaitingLabel(task),
1295
+ approvals: approvalLabel(task.awaitingApproval),
1296
+ autonomous: task.type === "ai" && context.modes?.find((m) => m.id === task.taskMode)?.autonomous === true,
1297
+ repos: namedRepos(isolation?.repos),
1298
+ conflict: isolation?.state === "conflict" ? { repo: namedRepo(isolation.conflictRepo), files: filesOf(isolation.conflictFiles) } : null,
1299
+ repairing: isolation?.state === "repairing" ? { files: filesOf(isolation.conflictFiles), attempt: isolation.repair ?? null } : null,
1300
+ repaired: isolation?.repairedFiles?.length ? { files: capConflictFiles(isolation.repairedFiles), landed: isolation.state === "integrated" } : null,
1301
+ mergeGate: task.mergeGate?.length ? refsOf(task.mergeGate, context.orderOf) : null,
1302
+ opsChangedFiles: task.status === "awaiting_user" && task.awaitingReason === "files-changed",
1303
+ forcedPastGate: task.forcedPastGate?.length ? task.forcedPastGate : null,
1304
+ dependencies: refsOf(task.dependencies, context.orderOf),
1305
+ actions: taskRowActions(task, context.placement ?? (parent ? "subtask" : "task")),
1306
+ mark: markAction(task),
1307
+ opsEditable: opsEditable(task)
1308
+ };
1309
+ }
1310
+
1311
+ // src/taskRow/texts.ts
1312
+ function findNamed(tasks, id) {
1313
+ for (const task of tasks) {
1314
+ if (task.id === id) return task;
1315
+ const nested = findNamed(task.subtasks ?? [], id);
1316
+ if (nested) return nested;
1317
+ }
1318
+ return void 0;
1319
+ }
1320
+ function titledRefs(ids, tasks) {
1321
+ return ids.map((id) => {
1322
+ const task = findNamed(tasks, id);
1323
+ return task ? titledTaskRef(task) : id;
1324
+ });
1325
+ }
1326
+ function dependentsNotice(dependents) {
1327
+ if (dependents.length === 0) return null;
1328
+ const subject = dependents.length === 1 ? "1 task depends" : `${dependents.length} tasks depend`;
1329
+ return `${subject} on it and will lose that dependency: ${dependents.map((t) => titledTaskRef(t)).join(", ")}.`;
1330
+ }
1331
+ function pastGateConfirmation(unmerged, subject = "This task") {
1332
+ return `${subject} waits for Merge all: the work of ${unmerged.join(", ")} is not merged into your branch yet, so it would act without it. Starting it now is kept on the task.`;
1333
+ }
1334
+ function newTaskFields(title, prompt) {
1335
+ const name = title.trim();
1336
+ if (!name) return null;
1337
+ return { title: name, description: name, prompt: prompt?.trim() ? prompt : name, type: "ai" };
1338
+ }
1158
1339
  // Annotate the CommonJS export names for ESM import in node:
1159
1340
  0 && (module.exports = {
1160
1341
  CHECKPOINT_TRUNCATE_LENGTH,
1161
1342
  EMPTY_CONVERSATION,
1162
1343
  EMPTY_HOLD,
1163
1344
  EMPTY_TASK_LOG,
1345
+ NOT_STARTED,
1164
1346
  NO_TURN,
1165
1347
  aheadOfDraft,
1348
+ approvalLabel,
1349
+ awaitingLabel,
1166
1350
  canMergeTasks,
1167
1351
  canSetDependencies,
1168
1352
  canSplitTask,
1169
1353
  capConflictFiles,
1170
1354
  dependencyCandidates,
1355
+ dependentsNotice,
1171
1356
  dependentsOf,
1172
1357
  diffRows,
1173
1358
  diffStat,
@@ -1177,15 +1362,29 @@ function taskStartedNotice(title, runner) {
1177
1362
  fromTranscript,
1178
1363
  hasHiddenDetail,
1179
1364
  holdPrompt,
1365
+ isTaskRunning,
1366
+ markAction,
1367
+ markRequestFor,
1368
+ namedRepos,
1369
+ newTaskFields,
1370
+ opsEditable,
1180
1371
  outputLines,
1181
1372
  outputPreview,
1373
+ pastGateConfirmation,
1182
1374
  reduceConversation,
1183
1375
  reduceTaskLog,
1184
1376
  replayTaskLog,
1185
1377
  runnerToolSubject,
1186
1378
  stopTurn,
1187
1379
  summarizeToolCall,
1380
+ taskOrderLabel,
1381
+ taskRef,
1382
+ taskRowActions,
1383
+ taskRowView,
1188
1384
  taskStartedNotice,
1385
+ taskStatusKind,
1386
+ titledRefs,
1387
+ titledTaskRef,
1189
1388
  toolHeadline,
1190
1389
  truncateCheckpointSummary,
1191
1390
  unsendAll,