@tea-agent/loop-agent 0.36.3-beta.0 → 0.37.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 (115) hide show
  1. package/CHANGELOG.md +56 -55
  2. package/dist/build-stamp.json +3 -3
  3. package/dist/task/contract/project.js +4 -0
  4. package/dist/task/source-prepare/completeness.js +36 -0
  5. package/dist/task/source-prepare/parse-intent.js +67 -11
  6. package/dist/task/source-prepare/prepare.js +102 -5
  7. package/dist/worker/console/chat/chat-event-store.js +91 -0
  8. package/dist/worker/console/chat/pi-runtime.js +25 -0
  9. package/dist/worker/console/chat/routes.js +7 -2
  10. package/dist/worker/console/chat/semantic-activity.js +7 -1
  11. package/dist/worker/console/chat/session-store.js +6 -1
  12. package/dist/worker/console/chat/turn-process.js +119 -12
  13. package/dist/worker/console/operator-actions.js +18 -1
  14. package/dist/worker/console/static/assets/abnfDiagram-N423BO3Z-DSvF6RXQ.js +1 -0
  15. package/dist/worker/console/static/assets/arc-DuI4ogtJ.js +1 -0
  16. package/dist/worker/console/static/assets/architectureDiagram-T3A2C74G-DdBbgD4y.js +36 -0
  17. package/dist/worker/console/static/assets/blockDiagram-VBNYF7ZC-xQC2HELm.js +132 -0
  18. package/dist/worker/console/static/assets/c4Diagram-5PPSVZJV-DPMSgwIZ.js +10 -0
  19. package/dist/worker/console/static/assets/channel-DLVz9TYW.js +1 -0
  20. package/dist/worker/console/static/assets/chunk-2GRJ4B5K-WTEKTxin.js +1 -0
  21. package/dist/worker/console/static/assets/chunk-2Q5K7J3B-B6vZ0Pv_.js +1 -0
  22. package/dist/worker/console/static/assets/chunk-5RXB4S5H-BrerNAix.js +231 -0
  23. package/dist/worker/console/static/assets/chunk-5VM5RSS4-D_ch2aaI.js +15 -0
  24. package/dist/worker/console/static/assets/chunk-6Q2QTUOP-VvfacNrq.js +88 -0
  25. package/dist/worker/console/static/assets/chunk-GF5L2VYU-B-uGFIg2.js +206 -0
  26. package/dist/worker/console/static/assets/chunk-JWPE2WC7-BlysCtod.js +1 -0
  27. package/dist/worker/console/static/assets/chunk-KBJHAD2P-BjAUAfcT.js +1 -0
  28. package/dist/worker/console/static/assets/chunk-RYQCIY6F-BeZnBmb-.js +1 -0
  29. package/dist/worker/console/static/assets/chunk-XXDRQBXY-Bbfe3UJG.js +1 -0
  30. package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-BeAuGcO9.js +1 -0
  31. package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-BeAuGcO9.js +1 -0
  32. package/dist/worker/console/static/assets/cose-bilkent-JH36ORCC-BKJQnYVM.js +1 -0
  33. package/dist/worker/console/static/assets/cynefin-VYW2F7L2-B1wtI3hU.js +166 -0
  34. package/dist/worker/console/static/assets/cynefinDiagram-MW4NZA55-DCF6DBSu.js +62 -0
  35. package/dist/worker/console/static/assets/cytoscape.esm-yzknjiTM.js +321 -0
  36. package/dist/worker/console/static/assets/dagre-VZM6K2ZE-BJyNGRlP.js +4 -0
  37. package/dist/worker/console/static/assets/defaultLocale-DX6XiGOO.js +1 -0
  38. package/dist/worker/console/static/assets/diagram-7IWD3JNH-B7j1-VsZ.js +30 -0
  39. package/dist/worker/console/static/assets/diagram-B4RE2ZJO-BREJ140a.js +3 -0
  40. package/dist/worker/console/static/assets/diagram-LBJQPF4R-CDPHmHGH.js +24 -0
  41. package/dist/worker/console/static/assets/diagram-Q27KOJAE-BtZLrez1.js +24 -0
  42. package/dist/worker/console/static/assets/diagram-UB23O5K3-mzybu8oU.js +41 -0
  43. package/dist/worker/console/static/assets/ebnfDiagram-BXEA7PRR-Dk3I2uO6.js +1 -0
  44. package/dist/worker/console/static/assets/erDiagram-JOGREHBK-BT97u_tQ.js +85 -0
  45. package/dist/worker/console/static/assets/flowDiagram-UKHOOZJN-CMOtYzui.js +156 -0
  46. package/dist/worker/console/static/assets/ganttDiagram-PKOTCBZU-DiNydkuY.js +292 -0
  47. package/dist/worker/console/static/assets/gitGraphDiagram-DS77QQ5N-Cwt6fLkl.js +106 -0
  48. package/dist/worker/console/static/assets/graph-DOmOIIwC.js +1 -0
  49. package/dist/worker/console/static/assets/index-DQxiso1w.js +325 -0
  50. package/dist/worker/console/static/assets/index-_j0Hzo69.css +1 -0
  51. package/dist/worker/console/static/assets/infoDiagram-6WML65LV-AsGIGKKB.js +2 -0
  52. package/dist/worker/console/static/assets/init-Gi6I4Gst.js +1 -0
  53. package/dist/worker/console/static/assets/ishikawaDiagram-WSZJBQD7-BL8ITZh3.js +70 -0
  54. package/dist/worker/console/static/assets/journeyDiagram-NVQOT4AX-VPKAUX8M.js +139 -0
  55. package/dist/worker/console/static/assets/kanban-definition-27J2QSJJ-BL56hfGp.js +89 -0
  56. package/dist/worker/console/static/assets/layout-D-LzfAck.js +1 -0
  57. package/dist/worker/console/static/assets/linear-BmSG3nIZ.js +1 -0
  58. package/dist/worker/console/static/assets/map-DxJ2ADlA.js +1 -0
  59. package/dist/worker/console/static/assets/mermaid.core-DWGK9kwP.js +308 -0
  60. package/dist/worker/console/static/assets/mindmap-definition-FAOFIHXS--vvKLjo0.js +96 -0
  61. package/dist/worker/console/static/assets/ordinal-Cboi1Yqb.js +1 -0
  62. package/dist/worker/console/static/assets/pegDiagram-VL7TDLO6-B41mxb2-.js +1 -0
  63. package/dist/worker/console/static/assets/pieDiagram-7S7Q4E2Y-DTlu77sw.js +39 -0
  64. package/dist/worker/console/static/assets/quadrantDiagram-CIZ2JOQS-Bk5A7alv.js +7 -0
  65. package/dist/worker/console/static/assets/railroadDiagram-AXF67PYL-Csf9jzQy.js +1 -0
  66. package/dist/worker/console/static/assets/requirementDiagram-LRYGKXZP-CeptoSNx.js +84 -0
  67. package/dist/worker/console/static/assets/sankeyDiagram-W5VNT64P-A-DLCLer.js +40 -0
  68. package/dist/worker/console/static/assets/sequenceDiagram-SI44F4Z6-22VbPdOI.js +162 -0
  69. package/dist/worker/console/static/assets/sizeCapture-X5ZJPWSS-DWvAyBC9.js +1 -0
  70. package/dist/worker/console/static/assets/stateDiagram-OKZ733FA-qICZ75yT.js +1 -0
  71. package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-DzKvfHTX.js +1 -0
  72. package/dist/worker/console/static/assets/swimlanes-SLNWSIFB-xi7lcMyp.js +2 -0
  73. package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-Cxqr_qM1.js +8 -0
  74. package/dist/worker/console/static/assets/timeline-definition-Z64GVDOM-Bu6Nl6O2.js +120 -0
  75. package/dist/worker/console/static/assets/vennDiagram-T6HMQDX7-BzMz4Bn9.js +34 -0
  76. package/dist/worker/console/static/assets/wardleyDiagram-T6FBY63Y-CxaJnzc5.js +78 -0
  77. package/dist/worker/console/static/assets/xychartDiagram-ELKLHX3M-5JK-omQK.js +7 -0
  78. package/dist/worker/console/static/fonts/katex/KaTeX_AMS-Regular.woff2 +0 -0
  79. package/dist/worker/console/static/fonts/katex/KaTeX_Caligraphic-Bold.woff2 +0 -0
  80. package/dist/worker/console/static/fonts/katex/KaTeX_Caligraphic-Regular.woff2 +0 -0
  81. package/dist/worker/console/static/fonts/katex/KaTeX_Fraktur-Bold.woff2 +0 -0
  82. package/dist/worker/console/static/fonts/katex/KaTeX_Fraktur-Regular.woff2 +0 -0
  83. package/dist/worker/console/static/fonts/katex/KaTeX_Main-Bold.woff2 +0 -0
  84. package/dist/worker/console/static/fonts/katex/KaTeX_Main-BoldItalic.woff2 +0 -0
  85. package/dist/worker/console/static/fonts/katex/KaTeX_Main-Italic.woff2 +0 -0
  86. package/dist/worker/console/static/fonts/katex/KaTeX_Main-Regular.woff2 +0 -0
  87. package/dist/worker/console/static/fonts/katex/KaTeX_Math-BoldItalic.woff2 +0 -0
  88. package/dist/worker/console/static/fonts/katex/KaTeX_Math-Italic.woff2 +0 -0
  89. package/dist/worker/console/static/fonts/katex/KaTeX_SansSerif-Bold.woff2 +0 -0
  90. package/dist/worker/console/static/fonts/katex/KaTeX_SansSerif-Italic.woff2 +0 -0
  91. package/dist/worker/console/static/fonts/katex/KaTeX_SansSerif-Regular.woff2 +0 -0
  92. package/dist/worker/console/static/fonts/katex/KaTeX_Script-Regular.woff2 +0 -0
  93. package/dist/worker/console/static/fonts/katex/KaTeX_Size1-Regular.woff2 +0 -0
  94. package/dist/worker/console/static/fonts/katex/KaTeX_Size2-Regular.woff2 +0 -0
  95. package/dist/worker/console/static/fonts/katex/KaTeX_Size3-Regular.woff2 +0 -0
  96. package/dist/worker/console/static/fonts/katex/KaTeX_Size4-Regular.woff2 +0 -0
  97. package/dist/worker/console/static/fonts/katex/KaTeX_Typewriter-Regular.woff2 +0 -0
  98. package/dist/worker/console/static/index.html +2 -2
  99. package/dist/worker/console/static-src/operator-chat/chat-sse-events.js +25 -0
  100. package/dist/worker/console/static-src/operator-chat/useChatSessions.js +37 -2
  101. package/dist/worker/observe/static/operator-chrome.js +4 -2
  102. package/dist/workflows/dag/failure-routing.js +4 -9
  103. package/dist/workflows/dag/init-hybrid.js +2 -47
  104. package/dist/workflows/dag/lifecycle.js +0 -4
  105. package/dist/workflows/dag/node-execution.js +6 -16
  106. package/dist/workflows/dag/report.js +0 -6
  107. package/dist/workflows/dag/retry-policy.js +0 -11
  108. package/dist/workflows/dag/runner.js +19 -3
  109. package/dist/workflows/dag/types.js +0 -2
  110. package/dist/workflows/dag/validate.js +2 -7
  111. package/docs/templates/frontend-task-constraints.md +7 -13
  112. package/package.json +6 -1
  113. package/skills/loop-agent/references/command-reference.md +1 -0
  114. package/dist/worker/console/static/assets/index-D83DYAFG.css +0 -1
  115. package/dist/worker/console/static/assets/index-IXm7oYjL.js +0 -59
@@ -15,7 +15,7 @@
15
15
  import { parseAssistantContent } from "./assistant-content.js";
16
16
  import { OPERATOR_CHAT_ALLOWED_TOOLS, OPERATOR_CHAT_DENIED_TOOLS, OPERATOR_CHAT_DENIED_OPERATOR_ACTIONS, } from "./tools.js";
17
17
  import { buildModelCallableToolSchemas } from "./tool-adapter.js";
18
- import { cleanChatTitle } from "./session-store.js";
18
+ import { cleanChatTitle, acceptedOperationIdFromResult } from "./session-store.js";
19
19
  import { hashChatTurnPayload, projectChatToolEventPayload, projectCompactSnapshot, } from "./chat-event-store.js";
20
20
  import { THINKING_LEVELS, RuntimeSnapshotUnavailableError, } from "./pi-runtime.js";
21
21
  import { ResourcePreferencesError, setSkillAutoInvocationPreference, } from "./resource-preferences-store.js";
@@ -106,7 +106,10 @@ function turnEventToStorePartial(event) {
106
106
  value: event.args,
107
107
  }),
108
108
  };
109
- case "tool_result":
109
+ case "tool_result": {
110
+ // Plan A (2026-08-16): surface the accepted-operation link on the live
111
+ // SSE frame so the frontend semantic event can resolve operation:<id>.
112
+ const resultOperationId = acceptedOperationIdFromResult(String(event.toolName ?? ""), event.result);
110
113
  return {
111
114
  kind: "tool_result",
112
115
  data: projectChatToolEventPayload({
@@ -115,8 +118,10 @@ function turnEventToStorePartial(event) {
115
118
  toolName: String(event.toolName ?? ""),
116
119
  value: event.result,
117
120
  isError: Boolean(event.isError),
121
+ ...(resultOperationId ? { operationId: resultOperationId } : {}),
118
122
  }),
119
123
  };
124
+ }
120
125
  case "agent_end":
121
126
  return {
122
127
  kind: "agent_end",
@@ -292,7 +292,13 @@ function maxWaitSeconds(args) {
292
292
  return Math.max(1, Math.round(raw / 1000));
293
293
  }
294
294
  function activityRefForTool(tool) {
295
- const operationId = operationIdFromArgs(tool.args);
295
+ // Plan A (2026-08-16): server backfills operationId on the persisted tool
296
+ // entry (and live tool_result frames carry it in the result payload), so
297
+ // prefer the authoritative link before parsing args/result fallbacks.
298
+ const operationId = tool.operationId ??
299
+ operationIdFromArgs(tool.args) ??
300
+ operationIdFromArgs(tool.result) ??
301
+ operationIdFromArgs(tool.resultText);
296
302
  return operationId ? `operation:${operationId}` : `tool:${tool.id}`;
297
303
  }
298
304
  function semanticKindForStatus(status) {
@@ -402,6 +402,11 @@ export async function runChatTurn(options) {
402
402
  toolCallId: event.toolCallId,
403
403
  toolName: event.toolName,
404
404
  isError: event.isError,
405
+ // Durable tool→operation link (plan A): the restored timeline can
406
+ // resolve operation:<id> refs without the live operation-ref event.
407
+ ...(acceptedOperationId
408
+ ? { operationId: acceptedOperationId }
409
+ : {}),
405
410
  }));
406
411
  pending.push(store.recordToolInvocation(sessionId, {
407
412
  toolCallId: event.toolCallId,
@@ -431,7 +436,7 @@ export async function runChatTurn(options) {
431
436
  * huge operator-action payload (e.g. a full dagReport) cannot bloat the chat
432
437
  * history record.
433
438
  */
434
- function acceptedOperationIdFromResult(toolName, result) {
439
+ export function acceptedOperationIdFromResult(toolName, result) {
435
440
  const candidates = [result];
436
441
  if (result && typeof result === "object") {
437
442
  const record = result;
@@ -70,6 +70,7 @@ export function hydrateSessionThread(raw) {
70
70
  createdAt,
71
71
  finishedAt: createdAt,
72
72
  turnId,
73
+ ...(item.operationId ? { operationId: item.operationId } : {}),
73
74
  };
74
75
  toolCalls.push(entry);
75
76
  pendingTools.push(entry);
@@ -77,30 +78,89 @@ export function hydrateSessionThread(raw) {
77
78
  }
78
79
  return { messages, toolCalls };
79
80
  }
80
- function pushToolProcessItem(processItems, tool) {
81
- const activity = semanticActivityForTool(tool);
82
- if (activity)
83
- processItems.push({ kind: "activity", activity });
84
- else
85
- processItems.push({ kind: "tool", tool });
81
+ /** Stable tool order: server eventSeq first, createdAt fallback, id tiebreak. */
82
+ function sortToolsStable(tools) {
83
+ return [...tools].sort((a, b) => {
84
+ if (a.eventSeq !== undefined &&
85
+ b.eventSeq !== undefined &&
86
+ a.eventSeq !== b.eventSeq) {
87
+ return a.eventSeq - b.eventSeq;
88
+ }
89
+ if (a.createdAt !== b.createdAt)
90
+ return a.createdAt - b.createdAt;
91
+ return a.id < b.id ? -1 : 1;
92
+ });
93
+ }
94
+ /**
95
+ * Flush buffered consecutive tools into process items. Semantic operator
96
+ * tools stay as individual activity events; plain tools group into a
97
+ * `tool-group` ("并行调用 · N 项") when two or more land back to back.
98
+ * Thinking/text/activity boundaries break the buffer upstream.
99
+ */
100
+ function flushToolBuffer(processItems, buffer) {
101
+ if (buffer.length === 0)
102
+ return;
103
+ const sorted = sortToolsStable(buffer);
104
+ let plainGroup = [];
105
+ const flushPlain = () => {
106
+ if (plainGroup.length === 1) {
107
+ processItems.push({ kind: "tool", tool: plainGroup[0] });
108
+ }
109
+ else if (plainGroup.length > 1) {
110
+ processItems.push({ kind: "tool-group", tools: plainGroup });
111
+ }
112
+ plainGroup = [];
113
+ };
114
+ for (const tool of sorted) {
115
+ const activity = semanticActivityForTool(tool);
116
+ if (activity) {
117
+ flushPlain();
118
+ processItems.push({ kind: "activity", activity });
119
+ }
120
+ else {
121
+ plainGroup.push(tool);
122
+ }
123
+ }
124
+ flushPlain();
86
125
  }
87
126
  function emitProcessBlocks(blocks, group, processItems, usedToolIds) {
127
+ let buffer = [];
88
128
  for (const block of blocks) {
89
129
  if (block.type === "thinking") {
130
+ flushToolBuffer(processItems, buffer);
131
+ buffer = [];
90
132
  processItems.push({ kind: "thinking", thinking: block.thinking });
91
133
  continue;
92
134
  }
93
135
  if (block.type === "text") {
94
- if (block.text.trim())
136
+ flushToolBuffer(processItems, buffer);
137
+ buffer = [];
138
+ if (block.text.trim()) {
95
139
  processItems.push({ kind: "text", text: block.text });
140
+ }
96
141
  continue;
97
142
  }
98
143
  const tool = group.tools.find((entry) => entry.id === block.toolCallId);
99
- if (tool) {
100
- pushToolProcessItem(processItems, tool);
144
+ if (tool && !usedToolIds.has(tool.id)) {
145
+ buffer.push(tool);
101
146
  usedToolIds.add(tool.id);
102
147
  }
103
148
  }
149
+ flushToolBuffer(processItems, buffer);
150
+ }
151
+ /**
152
+ * Insert tools attributed to this assistant stage but without a matching
153
+ * content toolCall block (live SSE tool_call frames often arrive before the
154
+ * assistant content does). They follow the stage's thinking/text instead of
155
+ * sinking to the end of the whole turn.
156
+ */
157
+ function appendAssistantUnmatchedTools(group, assistant, processItems, usedToolIds) {
158
+ const unmatched = group.tools.filter((tool) => !usedToolIds.has(tool.id) && tool.assistantMessageId === assistant.id);
159
+ if (unmatched.length === 0)
160
+ return;
161
+ for (const tool of unmatched)
162
+ usedToolIds.add(tool.id);
163
+ flushToolBuffer(processItems, unmatched);
104
164
  }
105
165
  function fillProcessDetails(group) {
106
166
  const usedToolIds = new Set();
@@ -109,14 +169,20 @@ function fillProcessDetails(group) {
109
169
  const finalAssistant = group.assistants.at(-1);
110
170
  for (const assistant of prior) {
111
171
  emitProcessBlocks(getDisplayableAssistantBlocks(assistant.content ?? []), group, processItems, usedToolIds);
172
+ appendAssistantUnmatchedTools(group, assistant, processItems, usedToolIds);
112
173
  }
113
174
  const blocks = finalAssistant?.content ?? [];
114
175
  const split = splitFinalAssistantBlocks(blocks, { isStreaming: group.live });
115
176
  emitProcessBlocks(split.processBlocks, group, processItems, usedToolIds);
116
- for (const tool of group.tools) {
117
- if (!usedToolIds.has(tool.id))
118
- pushToolProcessItem(processItems, tool);
177
+ if (finalAssistant) {
178
+ appendAssistantUnmatchedTools(group, finalAssistant, processItems, usedToolIds);
119
179
  }
180
+ // Bounded fallback for legacy restored rows with no assistant attribution:
181
+ // keep them at this turn's end in stable server order instead of randomly
182
+ // interleaving them into earlier stages.
183
+ const orphans = group.tools.filter((tool) => !usedToolIds.has(tool.id));
184
+ if (orphans.length > 0)
185
+ flushToolBuffer(processItems, orphans);
120
186
  group.processItems = processItems;
121
187
  if (!finalAssistant)
122
188
  return;
@@ -149,6 +215,14 @@ export function buildTurnProcessGroups(input) {
149
215
  current.user = message;
150
216
  continue;
151
217
  }
218
+ if (message.kind === "compaction") {
219
+ // Compaction is a standalone timeline event. Starting a fresh group
220
+ // prevents it from replacing the previous turn's assistant answer.
221
+ current = startGroup(`compaction-${message.id}`);
222
+ current.assistants.push(message);
223
+ current = null;
224
+ continue;
225
+ }
152
226
  if (!current)
153
227
  current = startGroup(`assistant-${message.id}`);
154
228
  current.assistants.push(message);
@@ -250,3 +324,36 @@ export function processGroupSummary(tools, options) {
250
324
  parts.push("运行中");
251
325
  return { count, errorCount, runningCount, stepCount, label: parts.join(" · ") };
252
326
  }
327
+ /** Summary over rendered process items (tool-group tools count individually). */
328
+ export function summarizeProcessItems(items) {
329
+ const tools = [];
330
+ let thinkingCount = 0;
331
+ let textCount = 0;
332
+ let activityCount = 0;
333
+ let activityErrorCount = 0;
334
+ let activityRunningCount = 0;
335
+ for (const item of items) {
336
+ if (item.kind === "thinking")
337
+ thinkingCount += 1;
338
+ else if (item.kind === "text")
339
+ textCount += 1;
340
+ else if (item.kind === "activity") {
341
+ activityCount += 1;
342
+ if (item.activity.kind === "error")
343
+ activityErrorCount += 1;
344
+ else if (item.activity.kind === "progress")
345
+ activityRunningCount += 1;
346
+ }
347
+ else if (item.kind === "tool")
348
+ tools.push(item.tool);
349
+ else
350
+ tools.push(...item.tools);
351
+ }
352
+ return processGroupSummary(tools, {
353
+ thinkingCount,
354
+ textCount,
355
+ activityCount,
356
+ activityErrorCount,
357
+ activityRunningCount,
358
+ });
359
+ }
@@ -1,7 +1,7 @@
1
1
  import { access, readFile } from "node:fs/promises";
2
2
  import { buildOperatorCapabilitiesDocument } from "../../shared/operator/capabilities.js";
3
3
  import { buildOperatorResult, operatorFailed, operatorSucceeded, } from "../../shared/operator/envelope.js";
4
- import { getTaskPaths, loadTaskConfig } from "../../task/runtime.js";
4
+ import { CANONICAL_TASK_ID_PATTERN, formatLocalBusinessDate, getTaskPaths, loadTaskConfig, } from "../../task/runtime.js";
5
5
  import { diffTaskContract, validateDraftForTask, } from "../../task/contract/index.js";
6
6
  import { stageUtf8Text } from "./app-data.js";
7
7
  import { ALL_CONFIRMATION_CHALLENGES, hashDagBytes, } from "./dag-confirmation.js";
@@ -63,6 +63,8 @@ function str(v) {
63
63
  return typeof v === "string" && v.trim() ? v.trim() : undefined;
64
64
  }
65
65
  const TASK_ID_PLACEHOLDER_RE = /[<>]|^(?:id|task-?id|your-task-id|todo|tbd)$/i;
66
+ /** Mirror of runtime GENERIC_TASK_SLUGS (not exported there); keep in sync. */
67
+ const GENERIC_SLUG_SET = new Set(["test", "fix", "tmp", "new-task"]);
66
68
  const TASK_ADVANCE_ALIAS_ACTIONS = new Set(["promoteRun", "closeoutTask"]);
67
69
  function taskIdInputError(taskId) {
68
70
  if (!TASK_ID_PLACEHOLDER_RE.test(taskId))
@@ -1502,6 +1504,21 @@ export async function dispatchOperatorAction(ctx, req) {
1502
1504
  const taskIdError = taskIdInputError(taskId);
1503
1505
  if (taskIdError)
1504
1506
  return invalid(action, taskIdError);
1507
+ // Canonical id gate at admission (2026-08-16): non-canonical ids were
1508
+ // accepted here (validateNewTaskId only warns) and every downstream
1509
+ // advance/import then flailed on the malformed task directory. Fail
1510
+ // fast with a concrete suggested id instead.
1511
+ if (!CANONICAL_TASK_ID_PATTERN.test(taskId)) {
1512
+ const slug = taskId
1513
+ .toLowerCase()
1514
+ .replace(/[^a-z0-9]+/g, "-")
1515
+ .replace(/^-+|-+$/g, "")
1516
+ .slice(0, 48);
1517
+ const suggested = slug && !GENERIC_SLUG_SET.has(slug)
1518
+ ? `${formatLocalBusinessDate()}-${slug}`
1519
+ : `${formatLocalBusinessDate()}-${slug || "task"}-r2`;
1520
+ return invalid(action, `taskId must be canonical YYYY-MM-DD-<kebab-slug> (local business date); got "${taskId}" — suggested id: "${suggested}" (e.g. 2026-08-16-tool-preview-edge-test); retry newTask with that id`);
1521
+ }
1505
1522
  return acceptOperation(ctx, {
1506
1523
  action,
1507
1524
  actionParams: p,
@@ -0,0 +1 @@
1
+ import{g as p,r as u,d as a}from"./chunk-6Q2QTUOP-VvfacNrq.js";import{p as f}from"./chunk-JWPE2WC7-BlysCtod.js";import{_ as n,l as o}from"./mermaid.core-DWGK9kwP.js";import{M as c,b as d}from"./cynefin-VYW2F7L2-B1wtI3hU.js";import"./index-DQxiso1w.js";var v=d().RailroadAbnf.parser.LangiumParser,i=n(e=>{const r=e.alternatives.map(g);return r.length===1?r[0]:{type:"choice",alternatives:r}},"transformAlternation"),g=n(e=>{const r=e.elements.map(y);return r.length===1?r[0]:{type:"sequence",elements:r}},"transformConcatenation"),b=n(e=>{if(e.includes("*")){const[t,s]=e.split("*"),l=t?parseInt(t,10):0,m=s?parseInt(s,10):1/0;return{min:l,max:m}}const r=parseInt(e,10);return{min:r,max:r}},"parseRepeat"),y=n(e=>{const r=A(e.primary);if(!e.repeat)return r;const{min:t,max:s}=b(e.repeat);return t===0&&s===1?{type:"optional",element:r}:{type:"repetition",element:r,min:t,max:s}},"transformElement"),A=n(e=>{switch(e.$type){case"AbnfStringLiteral":return{type:"terminal",value:e.value};case"AbnfNumVal":return{type:"terminal",value:e.value};case"AbnfRuleName":return{type:"nonterminal",name:e.name};case"AbnfGroup":return i(e.element);case"AbnfOptionalGroup":return{type:"optional",element:i(e.element)};default:throw new Error(`Unsupported ABNF primary node: ${e.$type}`)}},"transformPrimary"),P=n(e=>({name:e.name,definition:i(e.definition)}),"transformRule"),h=n(e=>{f(e,a),e.title&&a.setTitle(e.title),e.rules.map(r=>a.addRule(P(r)))},"populateDb"),R={parse:n(e=>{a.clear(),o.debug("[ABNF Parser] Starting Langium parse");const r=v.parse(e);if(r.lexerErrors.length>0||r.parserErrors.length>0)throw new c(r);const t=r.value;o.debug("[ABNF Parser] Parsed rules:",t.rules.length),h(t),o.debug("[ABNF Parser] Parse complete")},"parse"),parser:{yy:a}},B={parser:R,db:a,renderer:u,styles:p};export{B as diagram};
@@ -0,0 +1 @@
1
+ import{Y as ln,$ as an,a0 as F,a1 as q,a2 as j,a3 as un,a4 as y,a5 as tn,a6 as J,a7 as _,a8 as rn,a9 as o,aa as on,ab as sn,ac as fn}from"./mermaid.core-DWGK9kwP.js";function cn(l){return l.innerRadius}function yn(l){return l.outerRadius}function gn(l){return l.startAngle}function dn(l){return l.endAngle}function mn(l){return l&&l.padAngle}function pn(l,h,I,D,v,A,z,a){var O=I-l,i=D-h,n=z-v,d=a-A,u=d*O-n*i;if(!(u*u<y))return u=(n*(h-A)-d*(l-v))/u,[l+u*O,h+u*i]}function U(l,h,I,D,v,A,z){var a=l-I,O=h-D,i=(z?A:-A)/J(a*a+O*O),n=i*O,d=-i*a,u=l+n,s=h+d,f=I+n,c=D+d,B=(u+f)/2,t=(s+c)/2,m=f-u,g=c-s,R=m*m+g*g,T=v-A,P=u*c-f*s,S=(g<0?-1:1)*J(on(0,T*T*R-P*P)),Y=(P*g-m*S)/R,$=(-P*m-g*S)/R,w=(P*g+m*S)/R,p=(-P*m+g*S)/R,x=Y-B,e=$-t,r=w-B,C=p-t;return x*x+e*e>r*r+C*C&&(Y=w,$=p),{cx:Y,cy:$,x01:-n,y01:-d,x11:Y*(v/T-1),y11:$*(v/T-1)}}function hn(){var l=cn,h=yn,I=j(0),D=null,v=gn,A=dn,z=mn,a=null,O=ln(i);function i(){var n,d,u=+l.apply(this,arguments),s=+h.apply(this,arguments),f=v.apply(this,arguments)-un,c=A.apply(this,arguments)-un,B=rn(c-f),t=c>f;if(a||(a=n=O()),s<u&&(d=s,s=u,u=d),!(s>y))a.moveTo(0,0);else if(B>tn-y)a.moveTo(s*F(f),s*q(f)),a.arc(0,0,s,f,c,!t),u>y&&(a.moveTo(u*F(c),u*q(c)),a.arc(0,0,u,c,f,t));else{var m=f,g=c,R=f,T=c,P=B,S=B,Y=z.apply(this,arguments)/2,$=Y>y&&(D?+D.apply(this,arguments):J(u*u+s*s)),w=_(rn(s-u)/2,+I.apply(this,arguments)),p=w,x=w,e,r;if($>y){var C=sn($/u*q(Y)),K=sn($/s*q(Y));(P-=C*2)>y?(C*=t?1:-1,R+=C,T-=C):(P=0,R=T=(f+c)/2),(S-=K*2)>y?(K*=t?1:-1,m+=K,g-=K):(S=0,m=g=(f+c)/2)}var G=s*F(m),H=s*q(m),L=u*F(T),M=u*q(T);if(w>y){var N=s*F(g),Q=s*q(g),V=u*F(R),W=u*q(R),E;if(B<an)if(E=pn(G,H,V,W,N,Q,L,M)){var X=G-E[0],Z=H-E[1],b=N-E[0],k=Q-E[1],nn=1/q(fn((X*b+Z*k)/(J(X*X+Z*Z)*J(b*b+k*k)))/2),en=J(E[0]*E[0]+E[1]*E[1]);p=_(w,(u-en)/(nn-1)),x=_(w,(s-en)/(nn+1))}else p=x=0}S>y?x>y?(e=U(V,W,G,H,s,x,t),r=U(N,Q,L,M,s,x,t),a.moveTo(e.cx+e.x01,e.cy+e.y01),x<w?a.arc(e.cx,e.cy,x,o(e.y01,e.x01),o(r.y01,r.x01),!t):(a.arc(e.cx,e.cy,x,o(e.y01,e.x01),o(e.y11,e.x11),!t),a.arc(0,0,s,o(e.cy+e.y11,e.cx+e.x11),o(r.cy+r.y11,r.cx+r.x11),!t),a.arc(r.cx,r.cy,x,o(r.y11,r.x11),o(r.y01,r.x01),!t))):(a.moveTo(G,H),a.arc(0,0,s,m,g,!t)):a.moveTo(G,H),!(u>y)||!(P>y)?a.lineTo(L,M):p>y?(e=U(L,M,N,Q,u,-p,t),r=U(G,H,V,W,u,-p,t),a.lineTo(e.cx+e.x01,e.cy+e.y01),p<w?a.arc(e.cx,e.cy,p,o(e.y01,e.x01),o(r.y01,r.x01),!t):(a.arc(e.cx,e.cy,p,o(e.y01,e.x01),o(e.y11,e.x11),!t),a.arc(0,0,u,o(e.cy+e.y11,e.cx+e.x11),o(r.cy+r.y11,r.cx+r.x11),t),a.arc(r.cx,r.cy,p,o(r.y11,r.x11),o(r.y01,r.x01),!t))):a.arc(0,0,u,T,R,t)}if(a.closePath(),n)return a=null,n+""||null}return i.centroid=function(){var n=(+l.apply(this,arguments)+ +h.apply(this,arguments))/2,d=(+v.apply(this,arguments)+ +A.apply(this,arguments))/2-an/2;return[F(d)*n,q(d)*n]},i.innerRadius=function(n){return arguments.length?(l=typeof n=="function"?n:j(+n),i):l},i.outerRadius=function(n){return arguments.length?(h=typeof n=="function"?n:j(+n),i):h},i.cornerRadius=function(n){return arguments.length?(I=typeof n=="function"?n:j(+n),i):I},i.padRadius=function(n){return arguments.length?(D=n==null?null:typeof n=="function"?n:j(+n),i):D},i.startAngle=function(n){return arguments.length?(v=typeof n=="function"?n:j(+n),i):v},i.endAngle=function(n){return arguments.length?(A=typeof n=="function"?n:j(+n),i):A},i.padAngle=function(n){return arguments.length?(z=typeof n=="function"?n:j(+n),i):z},i.context=function(n){return arguments.length?(a=n??null,i):a},i}export{hn as d};