@tea-agent/loop-agent 0.39.1 → 0.40.0-next.10

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 (156) hide show
  1. package/CHANGELOG.md +106 -116
  2. package/dist/build-stamp.json +3 -3
  3. package/dist/executors/dag-pi-executor.js +69 -7
  4. package/dist/executors/pi-executor.js +4 -2
  5. package/dist/executors/pi-sdk-executor.js +46 -1
  6. package/dist/executors/pi-writer-tool-policy.js +57 -1
  7. package/dist/executors/shell-executor.js +42 -2
  8. package/dist/executors/workspace-write-snapshot.js +68 -0
  9. package/dist/infrastructure/harness/atomic-write.js +23 -0
  10. package/dist/task/config-types.js +10 -0
  11. package/dist/worker/console/chat/chat-event-store.js +75 -5
  12. package/dist/worker/console/chat/context-panel.js +7 -0
  13. package/dist/worker/console/chat/deferred-turn.js +12 -0
  14. package/dist/worker/console/chat/pi-runtime.js +331 -18
  15. package/dist/worker/console/chat/provider-error.js +98 -0
  16. package/dist/worker/console/chat/routes.js +389 -56
  17. package/dist/worker/console/chat/session-stats.js +179 -0
  18. package/dist/worker/console/chat/session-store.js +93 -63
  19. package/dist/worker/console/chat/todos.js +115 -0
  20. package/dist/worker/console/chat/tool-preview.js +42 -0
  21. package/dist/worker/console/chat/turn-process.js +20 -55
  22. package/dist/worker/console/chat/user-questions.js +266 -0
  23. package/dist/worker/console/chat/workspace-landing.js +79 -0
  24. package/dist/worker/console/native-directory-picker.js +13 -0
  25. package/dist/worker/console/routes.js +309 -1
  26. package/dist/worker/console/security.js +4 -4
  27. package/dist/worker/console/server.js +529 -186
  28. package/dist/worker/console/static/assets/{abnfDiagram-N423BO3Z-CTx1TrNa.js → abnfDiagram-N423BO3Z-Bs-CDAXM.js} +1 -1
  29. package/dist/worker/console/static/assets/{arc-B4i9cVxX.js → arc-CAkA3We3.js} +1 -1
  30. package/dist/worker/console/static/assets/{architectureDiagram-T3A2C74G-BAXE8_Rl.js → architectureDiagram-T3A2C74G-DEmI_zqr.js} +1 -1
  31. package/dist/worker/console/static/assets/{blockDiagram-VBNYF7ZC-C5Xh59at.js → blockDiagram-VBNYF7ZC-uDHANebE.js} +1 -1
  32. package/dist/worker/console/static/assets/{c4Diagram-5PPSVZJV-B_asOzAu.js → c4Diagram-5PPSVZJV-Bv97b4_B.js} +1 -1
  33. package/dist/worker/console/static/assets/channel-amxUpk7o.js +1 -0
  34. package/dist/worker/console/static/assets/{chunk-2GRJ4B5K-wRO_iRNc.js → chunk-2GRJ4B5K-shmQKsFz.js} +1 -1
  35. package/dist/worker/console/static/assets/{chunk-2Q5K7J3B-ByOaSh_G.js → chunk-2Q5K7J3B-BAraNvcN.js} +1 -1
  36. package/dist/worker/console/static/assets/{chunk-5RXB4S5H-DjLzudan.js → chunk-5RXB4S5H-BirhxUop.js} +1 -1
  37. package/dist/worker/console/static/assets/{chunk-5VM5RSS4-JCNGkXYT.js → chunk-5VM5RSS4-C9LgUJpR.js} +1 -1
  38. package/dist/worker/console/static/assets/{chunk-6Q2QTUOP-BhrPXXMZ.js → chunk-6Q2QTUOP-DrU-s-t7.js} +1 -1
  39. package/dist/worker/console/static/assets/{chunk-GF5L2VYU-TJ5JuEBT.js → chunk-GF5L2VYU-Tx-H_FA2.js} +1 -1
  40. package/dist/worker/console/static/assets/{chunk-JWPE2WC7-VVthn_mD.js → chunk-JWPE2WC7-BjLtNFrR.js} +1 -1
  41. package/dist/worker/console/static/assets/{chunk-KBJHAD2P-D60-Mny4.js → chunk-KBJHAD2P-UNLVwSsy.js} +1 -1
  42. package/dist/worker/console/static/assets/{chunk-RYQCIY6F-zXv7aVye.js → chunk-RYQCIY6F-CBEUX8XD.js} +1 -1
  43. package/dist/worker/console/static/assets/{chunk-XXDRQBXY-By9VQoi1.js → chunk-XXDRQBXY-WTL7IZOq.js} +1 -1
  44. package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-bejwBVIz.js +1 -0
  45. package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-bejwBVIz.js +1 -0
  46. package/dist/worker/console/static/assets/{cose-bilkent-JH36ORCC-C4zQLe-M.js → cose-bilkent-JH36ORCC-CkHG6W3s.js} +1 -1
  47. package/dist/worker/console/static/assets/{cynefin-VYW2F7L2-wh5N2ReN.js → cynefin-VYW2F7L2-BRzFqTaL.js} +1 -1
  48. package/dist/worker/console/static/assets/{cynefinDiagram-MW4NZA55-Dlu5wIqs.js → cynefinDiagram-MW4NZA55-2_CFp_i7.js} +1 -1
  49. package/dist/worker/console/static/assets/{dagre-VZM6K2ZE-CrDgthc6.js → dagre-VZM6K2ZE-BJtsmdkE.js} +1 -1
  50. package/dist/worker/console/static/assets/{diagram-7IWD3JNH-zN1clg27.js → diagram-7IWD3JNH-DNEFFo6w.js} +1 -1
  51. package/dist/worker/console/static/assets/{diagram-B4RE2ZJO-BN-o7J7-.js → diagram-B4RE2ZJO-B_IWV7eo.js} +1 -1
  52. package/dist/worker/console/static/assets/{diagram-LBJQPF4R-C8SuPt0d.js → diagram-LBJQPF4R-DvvRx2dz.js} +1 -1
  53. package/dist/worker/console/static/assets/{diagram-Q27KOJAE-BoizuHbZ.js → diagram-Q27KOJAE-CsibsWLg.js} +1 -1
  54. package/dist/worker/console/static/assets/{diagram-UB23O5K3-BzUzXixG.js → diagram-UB23O5K3-les_djBQ.js} +1 -1
  55. package/dist/worker/console/static/assets/{ebnfDiagram-BXEA7PRR-Ev3lA4Cf.js → ebnfDiagram-BXEA7PRR-BEm2n7qJ.js} +1 -1
  56. package/dist/worker/console/static/assets/{erDiagram-JOGREHBK-GALUzRbs.js → erDiagram-JOGREHBK-BI7vHHVm.js} +1 -1
  57. package/dist/worker/console/static/assets/{flowDiagram-UKHOOZJN-CZJN65Sb.js → flowDiagram-UKHOOZJN-CUFCERrB.js} +1 -1
  58. package/dist/worker/console/static/assets/{ganttDiagram-PKOTCBZU-JLB9OESl.js → ganttDiagram-PKOTCBZU-wxyLiGWt.js} +1 -1
  59. package/dist/worker/console/static/assets/{gitGraphDiagram-DS77QQ5N-CcvCr4GD.js → gitGraphDiagram-DS77QQ5N-Bt897K8Z.js} +1 -1
  60. package/dist/worker/console/static/assets/index-BHhUOTri.css +1 -0
  61. package/dist/worker/console/static/assets/index-DqJbO3-p.js +407 -0
  62. package/dist/worker/console/static/assets/{infoDiagram-6WML65LV-HG5z7aVg.js → infoDiagram-6WML65LV-DYNx_IPv.js} +1 -1
  63. package/dist/worker/console/static/assets/{ishikawaDiagram-WSZJBQD7-BHEu9chR.js → ishikawaDiagram-WSZJBQD7-CzpLNEu6.js} +1 -1
  64. package/dist/worker/console/static/assets/{journeyDiagram-NVQOT4AX-Cp_Up8-a.js → journeyDiagram-NVQOT4AX-97f9owNU.js} +1 -1
  65. package/dist/worker/console/static/assets/{kanban-definition-27J2QSJJ-DvVeY-em.js → kanban-definition-27J2QSJJ-BxM9hyBn.js} +1 -1
  66. package/dist/worker/console/static/assets/{linear-aGmcjgTn.js → linear-ByuxcHvp.js} +1 -1
  67. package/dist/worker/console/static/assets/{mermaid.core-Biyo-tqA.js → mermaid.core-DwPGvpCv.js} +5 -5
  68. package/dist/worker/console/static/assets/{mindmap-definition-FAOFIHXS-DyxY2pIb.js → mindmap-definition-FAOFIHXS-DCoqG9RT.js} +1 -1
  69. package/dist/worker/console/static/assets/{pegDiagram-VL7TDLO6-CkdGuc50.js → pegDiagram-VL7TDLO6-BLSBmBMx.js} +1 -1
  70. package/dist/worker/console/static/assets/{pieDiagram-7S7Q4E2Y-NNQI9xVR.js → pieDiagram-7S7Q4E2Y-B0t_0oJW.js} +1 -1
  71. package/dist/worker/console/static/assets/{quadrantDiagram-CIZ2JOQS-PAJkuz_G.js → quadrantDiagram-CIZ2JOQS-sTzDk7Nt.js} +1 -1
  72. package/dist/worker/console/static/assets/{railroadDiagram-AXF67PYL-ZwrQod0O.js → railroadDiagram-AXF67PYL-B3jRdATC.js} +1 -1
  73. package/dist/worker/console/static/assets/{requirementDiagram-LRYGKXZP-D3ZfrzM2.js → requirementDiagram-LRYGKXZP-D-cTtXEN.js} +1 -1
  74. package/dist/worker/console/static/assets/{sankeyDiagram-W5VNT64P-DDGFmWk5.js → sankeyDiagram-W5VNT64P-B25igJRE.js} +1 -1
  75. package/dist/worker/console/static/assets/{sequenceDiagram-SI44F4Z6-DO6mmXTA.js → sequenceDiagram-SI44F4Z6-jW_lM1_D.js} +1 -1
  76. package/dist/worker/console/static/assets/{sizeCapture-X5ZJPWSS-DMbCQiJt.js → sizeCapture-X5ZJPWSS-CrzTgsHE.js} +1 -1
  77. package/dist/worker/console/static/assets/{stateDiagram-OKZ733FA-Di_YUEfC.js → stateDiagram-OKZ733FA-B01MvlqE.js} +1 -1
  78. package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-BvFKEtm2.js +1 -0
  79. package/dist/worker/console/static/assets/{swimlanes-SLNWSIFB-Bn2PphNJ.js → swimlanes-SLNWSIFB-YcF12FiU.js} +2 -2
  80. package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-DIB2eVg-.js +8 -0
  81. package/dist/worker/console/static/assets/{timeline-definition-Z64GVDOM-DPh8pRsp.js → timeline-definition-Z64GVDOM-ClnRcg2s.js} +1 -1
  82. package/dist/worker/console/static/assets/{vennDiagram-T6HMQDX7-GMfl26pW.js → vennDiagram-T6HMQDX7-B6gr_z-q.js} +1 -1
  83. package/dist/worker/console/static/assets/{wardleyDiagram-T6FBY63Y-DTlmVrmF.js → wardleyDiagram-T6FBY63Y-CvSgguGH.js} +1 -1
  84. package/dist/worker/console/static/assets/{xychartDiagram-ELKLHX3M-YGBjKAS5.js → xychartDiagram-ELKLHX3M-23OtSZCb.js} +1 -1
  85. package/dist/worker/console/static/index.html +2 -2
  86. package/dist/worker/console/static-src/app/console-types.js +29 -4
  87. package/dist/worker/console/static-src/app/useConsoleShell.js +30 -12
  88. package/dist/worker/console/static-src/app/useOperatorActions.js +36 -6
  89. package/dist/worker/console/static-src/app/useRecoveryConsole.js +10 -11
  90. package/dist/worker/console/static-src/app/useRunProgress.js +2 -1
  91. package/dist/worker/console/static-src/app/useTaskWizard.js +2 -2
  92. package/dist/worker/console/static-src/night/useNightBoard.js +8 -5
  93. package/dist/worker/console/static-src/operator-chat/chat-sse-events.js +141 -8
  94. package/dist/worker/console/static-src/operator-chat/compaction-message.js +79 -0
  95. package/dist/worker/console/static-src/operator-chat/details-dag-actions.js +122 -0
  96. package/dist/worker/console/static-src/operator-chat/refs.js +3 -0
  97. package/dist/worker/console/static-src/operator-chat/runtime-selection-labels.js +27 -0
  98. package/dist/worker/console/static-src/operator-chat/spatial-overlay.js +1 -2
  99. package/dist/worker/console/static-src/operator-chat/turn-stream-controller.js +25 -0
  100. package/dist/worker/console/static-src/operator-chat/turn-submission.js +3 -2
  101. package/dist/worker/console/static-src/operator-chat/useChatSessions.js +181 -87
  102. package/dist/worker/console/static-src/operator-chat/useChatStream.js +159 -44
  103. package/dist/worker/console/static-src/operator-chat/useChatThread.js +177 -8
  104. package/dist/worker/console/static-src/operator-chat/useRepoBrowser.js +63 -9
  105. package/dist/worker/console/static-src/operator-chat/useWorkspaceBrowserGate.js +4 -0
  106. package/dist/worker/console/static-src/operator-chat/workspace-layout-mode.js +3 -3
  107. package/dist/worker/console/static-src/shell/useWorkspaces.js +299 -0
  108. package/dist/worker/console/static-src/shell/workspace-route.js +339 -0
  109. package/dist/worker/console/workspace-context.js +234 -0
  110. package/dist/worker/console/workspace-registry.js +214 -0
  111. package/dist/worker/observe/server.js +4 -0
  112. package/dist/worker/observe/static/api.js +26 -6
  113. package/dist/worker/observe/static/app.js +18 -70
  114. package/dist/worker/observe/static/dag-node-purpose.d.ts +6 -0
  115. package/dist/worker/observe/static/dag-node-purpose.js +203 -0
  116. package/dist/worker/observe/static/index.html +1 -1
  117. package/dist/worker/observe/static/inspect-workspace.js +307 -0
  118. package/dist/worker/observe/static/operator-chrome.css +145 -20
  119. package/dist/worker/observe/static/operator-chrome.d.ts +20 -3
  120. package/dist/worker/observe/static/operator-chrome.js +330 -100
  121. package/dist/worker/observe/static/router.d.ts +46 -0
  122. package/dist/worker/observe/static/router.js +25 -1
  123. package/dist/worker/observe/static/state.d.ts +50 -0
  124. package/dist/worker/observe/static/state.js +174 -2
  125. package/dist/worker/observe/static/styles.css +348 -38
  126. package/dist/worker/observe/static/views/dag-graph.js +4 -2
  127. package/dist/worker/observe/static/views/dag-inspector.js +310 -156
  128. package/dist/worker/observe/static/views/dag.d.ts +13 -0
  129. package/dist/worker/observe/static/views/dag.js +6 -4
  130. package/dist/worker/observe/static/views/dashboard.js +6 -4
  131. package/dist/worker/observe/static/views/night.js +2 -2
  132. package/dist/worker/observe/static/views/pool.js +1 -0
  133. package/dist/worker/observe/static/views/run.js +3 -1
  134. package/dist/worker/observe/static/views/task.js +1 -1
  135. package/dist/workflows/dag/backend-test-pytest-collection.js +11 -10
  136. package/dist/workflows/dag/backend-test-writer-completeness.js +7 -12
  137. package/dist/workflows/dag/dynamic-runtime/map.js +1 -0
  138. package/dist/workflows/dag/init-hybrid.js +113 -47
  139. package/dist/workflows/dag/interrupt-request.js +3 -3
  140. package/dist/workflows/dag/lifecycle.js +3 -3
  141. package/dist/workflows/dag/types.js +20 -1
  142. package/docs/README.md +1 -0
  143. package/docs/operations/local-development-environment.md +21 -0
  144. package/docs/templates/agent-dag.schema.json +18 -0
  145. package/docs/templates/backend-test-dag.json +265 -237
  146. package/harness.json +3 -3
  147. package/package.json +3 -1
  148. package/dist/worker/console/static/assets/channel-Dj_4Moei.js +0 -1
  149. package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-C0YYAyCa.js +0 -1
  150. package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-C0YYAyCa.js +0 -1
  151. package/dist/worker/console/static/assets/index-CW88Fjbw.js +0 -406
  152. package/dist/worker/console/static/assets/index-DP0ZJl39.css +0 -1
  153. package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-DrdDvela.js +0 -1
  154. package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-DPkEAULl.js +0 -8
  155. package/dist/worker/console/static-src/operator-chat/activity-rail-presentation.js +0 -73
  156. package/dist/worker/console/static-src/operator-chat/useActivityRailTransition.js +0 -59
@@ -0,0 +1,50 @@
1
+ /** 与 state.js 对应的类型声明(供 vitest/TS 侧导入契约测试)。 */
2
+
3
+ export type ViewStateKind = "loading" | "empty" | "degraded" | "error";
4
+
5
+ export type ViewStateDescriptor = {
6
+ kind: ViewStateKind;
7
+ className: string;
8
+ role: string | null;
9
+ ariaLive: string | null;
10
+ message: string;
11
+ detail: string | null;
12
+ messageClass: string | null;
13
+ };
14
+
15
+ export const uiState: {
16
+ lastSnapshot: unknown;
17
+ specEvidenceDetail: {
18
+ source: string;
19
+ path: string;
20
+ loading: boolean;
21
+ error: string | null;
22
+ data: unknown;
23
+ triggerId: string | null;
24
+ } | null;
25
+ dagNodeExecutionOutputCache: Map<string, unknown> | null;
26
+ [key: string]: unknown;
27
+ };
28
+
29
+ export function setWorkspaceScope(workspaceId: string | null): void;
30
+ export function workspaceScope(): string | null;
31
+ export function scopedApiUrl(url: string): string;
32
+ export function workspaceRequestSignal(): AbortSignal | undefined;
33
+ export function fetchWithWorkspaceScope(
34
+ url: string,
35
+ init?: RequestInit,
36
+ ): Promise<Response>;
37
+ export function abortWorkspaceRequests(): void;
38
+ export function setWorkspaceActive(active: boolean): void;
39
+ export function stopTimers(): void;
40
+ export function pauseForegroundTimers(): void;
41
+
42
+ /** Multi-workspace atomic scope switch (2026-08-26, AC-006). */
43
+ export function applyWorkspaceScopeSwitch(
44
+ nextWorkspaceId: string | null,
45
+ routeValue?: (() => void) | string,
46
+ options?: {
47
+ route?: (hashValue: string) => void;
48
+ onTrace?: (trace: string[]) => void;
49
+ },
50
+ ): string[];
@@ -82,8 +82,8 @@ export const uiState = {
82
82
  dagNodeExecutionOutputLoading: false,
83
83
  dagNodeExecutionOutputError: null,
84
84
  dagNodeExecutionOutputKey: null,
85
- /** When true,「执行过程」展开 message_start/end 原始协议事件。默认展开,用户可点选隐藏。 */
86
- sessionTimelineShowProtocol: true,
85
+ /** When true,「执行过程」展开 message_start/end 原始协议事件。默认隐藏,用户可点选展开。 */
86
+ sessionTimelineShowProtocol: false,
87
87
  /** Open <details> keys restored across timeline re-renders. */
88
88
  sessionTimelineOpenDetails: null,
89
89
  lastSnapshot: null,
@@ -116,6 +116,8 @@ export const uiState = {
116
116
  /** Last-rendered spec-evidence list, used to restore the list synchronously. */
117
117
  specEvidenceListEvidence: null,
118
118
  pollingGeneration: 0,
119
+ /** Hosted Inspect workspace is foreground. Standalone defaults to active. */
120
+ workspaceActive: true,
119
121
  };
120
122
 
121
123
  /** Per-dagRunId graph viewport restore map (stable Map instance). */
@@ -279,16 +281,186 @@ export function isPageVisible() {
279
281
  );
280
282
  }
281
283
 
284
+ export function isWorkspaceActive() {
285
+ return uiState.workspaceActive !== false;
286
+ }
287
+
288
+ export function setWorkspaceActive(active) {
289
+ uiState.workspaceActive = Boolean(active);
290
+ }
291
+
292
+ /**
293
+ * Multi-workspace scope (2026-08-23): every Observe GET must carry the
294
+ * current workspaceId (AC-002/AC-003). The scope is synced from the parent
295
+ * Console shell hash (`?workspaceId=`) or via postMessage for hosted mode;
296
+ * standalone pages default to null and all workspace-scoped routes fail closed
297
+ * until the host or hash publishes an explicit workspace id.
298
+ */
299
+ let currentWorkspaceScope = null;
300
+ let currentWorkspaceRequestController =
301
+ typeof AbortController === "undefined" ? null : new AbortController();
302
+
303
+ export function setWorkspaceScope(workspaceId) {
304
+ currentWorkspaceScope =
305
+ typeof workspaceId === "string" && workspaceId.trim()
306
+ ? workspaceId.trim()
307
+ : null;
308
+ }
309
+
310
+ export function workspaceScope() {
311
+ return currentWorkspaceScope;
312
+ }
313
+
314
+ /** Signal shared by every workspace-scoped Observe request in the active scope. */
315
+ export function workspaceRequestSignal() {
316
+ if (
317
+ typeof AbortController !== "undefined" &&
318
+ (!currentWorkspaceRequestController ||
319
+ currentWorkspaceRequestController.signal.aborted)
320
+ ) {
321
+ currentWorkspaceRequestController = new AbortController();
322
+ }
323
+ return currentWorkspaceRequestController?.signal;
324
+ }
325
+
326
+ function combinedRequestSignal(scopeSignal, requestSignal) {
327
+ const signals = [scopeSignal, requestSignal].filter(Boolean);
328
+ if (signals.length <= 1) return { signal: signals[0], cleanup: () => {} };
329
+ const controller = new AbortController();
330
+ const abort = () => controller.abort();
331
+ for (const signal of signals) {
332
+ if (signal.aborted) abort();
333
+ else signal.addEventListener("abort", abort, { once: true });
334
+ }
335
+ return {
336
+ signal: controller.signal,
337
+ cleanup: () => {
338
+ for (const signal of signals) signal.removeEventListener("abort", abort);
339
+ },
340
+ };
341
+ }
342
+
343
+ /** Fetch through the current workspace boundary and abort on any scope swap. */
344
+ export async function fetchWithWorkspaceScope(url, init = {}) {
345
+ const { signal: requestSignal, ...rest } = init;
346
+ const combined = combinedRequestSignal(
347
+ workspaceRequestSignal(),
348
+ requestSignal,
349
+ );
350
+ try {
351
+ return await fetch(scopedApiUrl(url), {
352
+ ...rest,
353
+ ...(combined.signal ? { signal: combined.signal } : {}),
354
+ });
355
+ } finally {
356
+ combined.cleanup();
357
+ }
358
+ }
359
+
360
+ /** Abort every old-scope request and invalidate request identity guards. */
361
+ export function abortWorkspaceRequests() {
362
+ currentWorkspaceRequestController?.abort();
363
+ currentWorkspaceRequestController =
364
+ typeof AbortController === "undefined" ? null : new AbortController();
365
+ uiState.dagHistoryAbortController?.abort?.();
366
+ uiState.dagHistoryAbortController = null;
367
+ uiState.dagHistoryRequestSeq += 1;
368
+ uiState.dagHistoryPrefetchGeneration += 1;
369
+ uiState.dagNodeInputRequestSeq += 1;
370
+ uiState.dagNodeProcessRequestSeq += 1;
371
+ uiState.dagNodeExecutionOutputRequestSeq += 1;
372
+ }
373
+
374
+ /** Multi-workspace atomic scope switch (2026-08-26, AC-006).
375
+ *
376
+ * Contract order — strictly sequential, no interleaving:
377
+ * 1. abort old — stop every poll/SSE so no late request can race the swap;
378
+ * 2. clear old — drop cached run/task/selection state of the old scope;
379
+ * 3. set scope — publish the new workspaceId for scopedApiUrl;
380
+ * 4. reload new — re-route/re-render with the new scope active.
381
+ *
382
+ * Observability: each stage appends to the returned trace so tests (and
383
+ * diagnostics) can assert the exact ordering; there is no window in which a
384
+ * new route is requested with the old scope or vice versa.
385
+ */
386
+ export function applyWorkspaceScopeSwitch(
387
+ nextWorkspaceId,
388
+ routeValue,
389
+ options = {},
390
+ ) {
391
+ const trace = [];
392
+ // 1. abort old
393
+ abortWorkspaceRequests();
394
+ stopTimers();
395
+ pauseForegroundTimers();
396
+ trace.push("abort-old");
397
+ // 2. clear old
398
+ uiState.lastSnapshot = null;
399
+ uiState.specEvidenceDetail = null;
400
+ uiState.specEvidenceListEvidence = null;
401
+ clearDagNodeExecutionOutputCache();
402
+ trace.push("clear-old");
403
+ // 3. set scope
404
+ setWorkspaceScope(nextWorkspaceId);
405
+ trace.push(`set-scope:${workspaceScope() ?? ""}`);
406
+ // 4. route/reload new
407
+ if (typeof routeValue === "function") routeValue();
408
+ else if (typeof routeValue === "string") options.route?.(routeValue);
409
+ trace.push("route-new");
410
+ if (options.onTrace) options.onTrace(trace);
411
+ return trace;
412
+ }
413
+
414
+ /** Append ?workspaceId= to an observe API URL (real request path kept). */
415
+ export function scopedApiUrl(url) {
416
+ const raw = String(url ?? "");
417
+ if (!currentWorkspaceScope || !raw.startsWith("/api/")) return raw;
418
+ const qIndex = raw.indexOf("?");
419
+ if (qIndex >= 0) {
420
+ const params = new URLSearchParams(raw.slice(qIndex + 1));
421
+ if (params.has("workspaceId")) return raw;
422
+ params.set("workspaceId", currentWorkspaceScope);
423
+ return `${raw.slice(0, qIndex)}?${params.toString()}`;
424
+ }
425
+ return `${raw}?workspaceId=${encodeURIComponent(currentWorkspaceScope)}`;
426
+ }
427
+
282
428
  export function detailPollDelay(status, isVisible) {
283
429
  const normalizedStatus = (status ?? "").toLowerCase().replace(/-/g, "_");
284
430
  if (TERMINAL_RUN_STATUSES.has(normalizedStatus)) return null;
431
+ if (!isWorkspaceActive()) return null;
285
432
  return isVisible ? ACTIVE_DETAIL_POLL_MS : HIDDEN_POLL_MS;
286
433
  }
287
434
 
288
435
  export function dashboardPollDelay() {
436
+ if (!isWorkspaceActive()) return null;
289
437
  return isPageVisible() ? DASHBOARD_POLL_MS : HIDDEN_POLL_MS;
290
438
  }
291
439
 
440
+ /** Stop pausable timers without destroying route/selection/scroll. */
441
+ export function pauseForegroundTimers() {
442
+ if (uiState.dashboardTimer) {
443
+ clearTimeout(uiState.dashboardTimer);
444
+ uiState.dashboardTimer = null;
445
+ }
446
+ if (uiState.runPollTimer) {
447
+ clearTimeout(uiState.runPollTimer);
448
+ uiState.runPollTimer = null;
449
+ }
450
+ if (uiState.dagPollTimer) {
451
+ clearTimeout(uiState.dagPollTimer);
452
+ uiState.dagPollTimer = null;
453
+ }
454
+ if (uiState.poolTimer) {
455
+ clearTimeout(uiState.poolTimer);
456
+ uiState.poolTimer = null;
457
+ }
458
+ if (uiState.taskPollTimer) {
459
+ clearTimeout(uiState.taskPollTimer);
460
+ uiState.taskPollTimer = null;
461
+ }
462
+ }
463
+
292
464
  export function updateDagGraphViewportState(
293
465
  _previous,
294
466
  dagRunId,
@@ -1222,6 +1222,13 @@ body.is-resizing-dag-graph {
1222
1222
  font-family: "JetBrains Mono", "SFMono-Regular", Consolas, monospace;
1223
1223
  overflow-wrap: anywhere;
1224
1224
  }
1225
+ .dag-inspector-purpose {
1226
+ margin: 0;
1227
+ color: var(--muted);
1228
+ font-size: 12px;
1229
+ line-height: 1.45;
1230
+ overflow-wrap: anywhere;
1231
+ }
1225
1232
  .dag-inspector-controls {
1226
1233
  display: inline-flex;
1227
1234
  align-items: center;
@@ -3570,83 +3577,386 @@ button.copy-command:focus-visible {
3570
3577
  }
3571
3578
 
3572
3579
  /* Experimental prompt-override rerun tab (only rendered with the mutation token). */
3580
+ #dag-inspector-panel-prompt-restart {
3581
+ display: flex;
3582
+ flex-direction: column;
3583
+ min-height: 0;
3584
+ }
3585
+ #dag-inspector-panel-prompt-restart:has(.prompt-restart-panel.is-readonly) {
3586
+ overflow: hidden;
3587
+ }
3588
+ .prompt-restart-panel,
3573
3589
  .prompt-restart-box {
3574
3590
  display: flex;
3575
3591
  flex-direction: column;
3576
- gap: 0.75rem;
3577
- padding: 0.5rem 0.25rem;
3592
+ gap: var(--space-3);
3593
+ min-width: 0;
3594
+ flex: 1;
3595
+ }
3596
+ .prompt-restart-panel.is-readonly {
3597
+ min-height: 0;
3598
+ overflow: hidden;
3599
+ }
3600
+ .prompt-restart-panel.is-readonly .prompt-restart-prompt-card {
3601
+ flex: 1 1 auto;
3602
+ min-height: 12rem;
3603
+ }
3604
+ .prompt-restart-toolbar {
3605
+ display: grid;
3606
+ grid-template-columns: minmax(0, 1fr) auto;
3607
+ gap: var(--space-3);
3608
+ align-items: start;
3609
+ }
3610
+ .prompt-restart-mode-field {
3611
+ min-width: 12.5rem;
3612
+ }
3613
+ .prompt-restart-banner {
3614
+ display: flex;
3615
+ flex-wrap: wrap;
3616
+ align-items: center;
3617
+ gap: 6px 10px;
3618
+ padding: 10px 12px;
3619
+ border: 1px solid var(--hairline);
3620
+ border-radius: var(--radius-lg);
3621
+ background: var(--canvas-soft);
3622
+ }
3623
+ .prompt-restart-banner.is-edit {
3624
+ border-color: color-mix(in srgb, var(--orange) 28%, var(--hairline));
3625
+ background: color-mix(in srgb, var(--orange-soft) 55%, var(--surface));
3626
+ }
3627
+ .prompt-restart-banner-kicker {
3628
+ width: fit-content;
3629
+ padding: 2px 8px;
3630
+ border-radius: var(--radius-pill);
3631
+ background: var(--surface-muted);
3632
+ color: var(--muted);
3633
+ font-size: 11px;
3634
+ font-weight: 700;
3635
+ letter-spacing: 0.02em;
3636
+ }
3637
+ .prompt-restart-banner.is-edit .prompt-restart-banner-kicker {
3638
+ background: var(--orange-soft);
3639
+ color: var(--orange-active);
3640
+ }
3641
+ .prompt-restart-banner-title,
3642
+ .prompt-restart-banner-body {
3643
+ margin: 0;
3644
+ }
3645
+ .prompt-restart-banner-title {
3646
+ color: var(--ink);
3647
+ font-size: 13px;
3648
+ font-weight: 700;
3649
+ line-height: 1.35;
3650
+ }
3651
+ .prompt-restart-banner-body {
3652
+ flex-basis: 100%;
3653
+ color: var(--body);
3654
+ font-size: 12px;
3655
+ line-height: 1.5;
3578
3656
  }
3579
3657
  .prompt-restart-field {
3580
3658
  display: flex;
3581
3659
  flex-direction: column;
3582
- gap: 0.35rem;
3660
+ gap: 6px;
3661
+ min-width: 0;
3662
+ }
3663
+ .prompt-restart-field.is-hidden,
3664
+ .prompt-restart-prompt-card.is-hidden {
3665
+ display: none;
3666
+ }
3667
+ .prompt-restart-label {
3668
+ color: var(--ink);
3669
+ font-size: 12px;
3670
+ font-weight: 700;
3671
+ letter-spacing: 0.01em;
3672
+ }
3673
+ .prompt-restart-hint {
3674
+ margin: 0;
3675
+ color: var(--muted);
3676
+ font-size: 12px;
3677
+ line-height: 1.45;
3678
+ }
3679
+ .prompt-restart-candidate-select {
3680
+ display: block;
3681
+ width: 100%;
3682
+ min-width: 0;
3683
+ }
3684
+ .prompt-restart-candidate-select .custom-select-trigger {
3685
+ width: 100%;
3686
+ }
3687
+ .prompt-restart-candidate-select .custom-select-menu {
3688
+ z-index: 6;
3689
+ }
3690
+ .prompt-restart-mode-switch {
3691
+ display: flex;
3692
+ width: fit-content;
3693
+ max-width: 100%;
3694
+ gap: 4px;
3695
+ padding: 4px;
3696
+ border: 1px solid var(--hairline);
3697
+ border-radius: var(--radius-pill);
3698
+ background: var(--surface);
3699
+ }
3700
+ #dag-inspector-panel-prompt-restart button.prompt-restart-mode-option,
3701
+ .prompt-restart-mode-option {
3702
+ appearance: none;
3703
+ display: inline-flex;
3704
+ align-items: center;
3705
+ justify-content: center;
3706
+ flex: 0 0 auto;
3707
+ width: auto;
3708
+ min-height: 30px;
3709
+ height: 30px;
3710
+ padding: 0 12px;
3711
+ border: 1px solid transparent;
3712
+ border-radius: var(--radius-pill);
3713
+ background: transparent;
3714
+ color: var(--muted);
3715
+ font-size: 12px;
3716
+ font-weight: 700;
3717
+ line-height: 1;
3718
+ letter-spacing: 0;
3719
+ white-space: nowrap;
3720
+ box-shadow: none;
3721
+ transform: none;
3722
+ cursor: pointer;
3723
+ }
3724
+ #dag-inspector-panel-prompt-restart button.prompt-restart-mode-option:hover,
3725
+ #dag-inspector-panel-prompt-restart button.prompt-restart-mode-option:focus-visible,
3726
+ .prompt-restart-mode-option:hover,
3727
+ .prompt-restart-mode-option:focus-visible {
3728
+ color: var(--ink);
3729
+ background: var(--surface-muted);
3730
+ border-color: transparent;
3731
+ outline: none;
3732
+ box-shadow: none;
3733
+ transform: none;
3734
+ }
3735
+ #dag-inspector-panel-prompt-restart button.prompt-restart-mode-option.is-selected,
3736
+ .prompt-restart-mode-option.is-selected {
3737
+ background: var(--ink);
3738
+ color: #fff;
3739
+ border-color: transparent;
3583
3740
  }
3584
3741
  .prompt-restart-prompt-card {
3585
- position: relative;
3742
+ display: flex;
3743
+ flex-direction: column;
3744
+ min-width: 0;
3745
+ overflow: hidden;
3746
+ border: 1px solid var(--hairline);
3747
+ border-radius: var(--radius-lg);
3748
+ background: var(--surface);
3586
3749
  }
3587
3750
  .prompt-restart-prompt-head {
3588
3751
  display: flex;
3589
- align-items: center;
3752
+ align-items: flex-start;
3590
3753
  justify-content: space-between;
3591
- gap: 0.5rem;
3754
+ gap: var(--space-3);
3755
+ padding: 10px 12px;
3756
+ border-bottom: 1px solid var(--hairline);
3757
+ background: var(--canvas-soft);
3758
+ }
3759
+ .prompt-restart-prompt-titles {
3760
+ display: flex;
3761
+ flex-wrap: wrap;
3762
+ align-items: center;
3763
+ gap: 6px 8px;
3764
+ min-width: 0;
3765
+ }
3766
+ .prompt-restart-prompt-title {
3767
+ color: var(--ink);
3768
+ font-size: 13px;
3769
+ font-weight: 700;
3770
+ line-height: 1.3;
3771
+ }
3772
+ .prompt-restart-prompt-badge {
3773
+ padding: 2px 8px;
3774
+ border-radius: var(--radius-pill);
3775
+ background: var(--surface-muted);
3776
+ color: var(--muted);
3777
+ font-size: 11px;
3778
+ font-weight: 700;
3779
+ }
3780
+ .prompt-restart-prompt-meta {
3781
+ flex-basis: 100%;
3782
+ color: var(--muted);
3783
+ font-size: 11px;
3784
+ line-height: 1.3;
3592
3785
  }
3593
3786
  .prompt-restart-copy-icon {
3594
3787
  flex: 0 0 auto;
3788
+ margin-top: 1px;
3789
+ }
3790
+ .prompt-restart-prompt-actions {
3791
+ display: flex;
3792
+ align-items: center;
3793
+ gap: 6px;
3794
+ flex: 0 0 auto;
3795
+ }
3796
+ #dag-inspector-panel-prompt-restart button.prompt-restart-prompt-fold,
3797
+ .prompt-restart-prompt-fold {
3798
+ appearance: none;
3799
+ display: inline-flex;
3800
+ align-items: center;
3801
+ justify-content: center;
3802
+ min-height: 30px;
3803
+ height: 30px;
3804
+ padding: 0 10px;
3805
+ border: 1px solid var(--hairline);
3806
+ border-radius: var(--radius-pill);
3807
+ background: var(--surface);
3808
+ color: var(--body);
3809
+ font-size: 12px;
3810
+ font-weight: 700;
3811
+ line-height: 1;
3812
+ box-shadow: none;
3813
+ transform: none;
3814
+ cursor: pointer;
3815
+ }
3816
+ #dag-inspector-panel-prompt-restart button.prompt-restart-prompt-fold:hover,
3817
+ .prompt-restart-prompt-fold:hover {
3818
+ border-color: var(--hairline-strong);
3819
+ background: var(--surface-muted);
3820
+ color: var(--ink);
3821
+ transform: none;
3822
+ }
3823
+ .prompt-restart-prompt-card.is-collapsed .prompt-restart-readonly {
3824
+ display: none;
3825
+ }
3826
+ .prompt-restart-readonly {
3827
+ margin: 0;
3828
+ padding: 14px 16px;
3829
+ overflow: auto;
3830
+ background: var(--canvas-soft);
3831
+ color: var(--ink);
3832
+ font-family: "JetBrains Mono", "SFMono-Regular", Consolas, monospace;
3833
+ font-size: 12px;
3834
+ line-height: 1.65;
3835
+ white-space: pre-wrap;
3836
+ overflow-wrap: anywhere;
3837
+ tab-size: 2;
3838
+ }
3839
+ .prompt-restart-panel.is-readonly .prompt-restart-readonly {
3840
+ flex: 1 1 auto;
3841
+ min-height: 0;
3842
+ max-height: none;
3843
+ }
3844
+ .prompt-restart-panel.is-edit .prompt-restart-readonly {
3845
+ max-height: min(36vh, 18rem);
3595
3846
  }
3596
3847
  .prompt-restart-textarea {
3597
3848
  width: 100%;
3598
3849
  min-height: 8rem;
3599
3850
  resize: vertical;
3600
3851
  box-sizing: border-box;
3601
- font-family: var(--mono-font, ui-monospace, SFMono-Regular, Menlo, monospace);
3602
- font-size: 12.5px;
3603
- line-height: 1.5;
3604
- white-space: pre;
3605
- overflow-wrap: normal;
3852
+ padding: 12px 14px;
3853
+ border: 1px solid var(--hairline);
3854
+ border-radius: var(--radius-lg);
3855
+ background: var(--canvas-soft);
3856
+ color: var(--ink);
3857
+ font-family: "JetBrains Mono", "SFMono-Regular", Consolas, monospace;
3858
+ font-size: 12px;
3859
+ line-height: 1.65;
3860
+ white-space: pre-wrap;
3861
+ overflow-wrap: anywhere;
3606
3862
  overflow-x: auto;
3607
3863
  }
3608
- .prompt-restart-actions {
3864
+ .prompt-restart-textarea-work {
3865
+ min-height: 10rem;
3866
+ }
3867
+ .prompt-restart-textarea:hover {
3868
+ border-color: var(--hairline-strong);
3869
+ }
3870
+ .prompt-restart-textarea:focus-visible {
3871
+ outline: 2px solid color-mix(in srgb, var(--orange) 55%, transparent);
3872
+ outline-offset: 1px;
3873
+ border-color: color-mix(in srgb, var(--orange) 35%, var(--hairline));
3874
+ }
3875
+ .prompt-restart-textarea-compact {
3876
+ min-height: 4.5rem;
3877
+ }
3878
+ .prompt-restart-actions,
3879
+ .prompt-restart-footer {
3609
3880
  display: flex;
3610
- gap: 0.5rem;
3881
+ flex-wrap: wrap;
3882
+ gap: var(--space-2);
3611
3883
  align-items: center;
3884
+ justify-content: flex-end;
3885
+ }
3886
+ .prompt-restart-footer {
3887
+ position: sticky;
3888
+ bottom: calc(-1 * var(--space-4));
3889
+ z-index: 2;
3890
+ margin-top: auto;
3891
+ padding: 10px 0 2px;
3892
+ border-top: 1px solid var(--hairline);
3893
+ background: var(--surface);
3612
3894
  }
3895
+ .prompt-restart-footer .prompt-restart-status {
3896
+ flex: 1 1 12rem;
3897
+ min-width: 0;
3898
+ margin-right: auto;
3899
+ }
3900
+ #dag-inspector-panel-prompt-restart button.prompt-restart-submit,
3613
3901
  .prompt-restart-submit {
3614
- padding: 0.35rem 0.9rem;
3615
- font-size: 13.5px;
3902
+ appearance: none;
3903
+ display: inline-flex;
3904
+ align-items: center;
3905
+ justify-content: center;
3906
+ min-height: 34px;
3907
+ height: 34px;
3908
+ padding: 0 16px;
3909
+ border: 1px solid var(--orange);
3910
+ border-radius: var(--radius-pill);
3911
+ background: var(--orange);
3912
+ color: #fff;
3913
+ font-size: 13px;
3914
+ font-weight: 700;
3915
+ line-height: 1;
3916
+ letter-spacing: 0.01em;
3917
+ box-shadow: none;
3918
+ transform: none;
3616
3919
  cursor: pointer;
3617
3920
  }
3921
+ #dag-inspector-panel-prompt-restart button.prompt-restart-submit:hover,
3922
+ #dag-inspector-panel-prompt-restart button.prompt-restart-submit:focus-visible,
3923
+ .prompt-restart-submit:hover,
3924
+ .prompt-restart-submit:focus-visible {
3925
+ background: var(--orange-active);
3926
+ border-color: var(--orange-active);
3927
+ color: #fff;
3928
+ outline: none;
3929
+ box-shadow: none;
3930
+ transform: none;
3931
+ }
3932
+ #dag-inspector-panel-prompt-restart button.prompt-restart-submit.is-secondary,
3933
+ .prompt-restart-submit.is-secondary {
3934
+ border-color: var(--hairline);
3935
+ background: var(--surface);
3936
+ color: var(--ink);
3937
+ }
3938
+ #dag-inspector-panel-prompt-restart button.prompt-restart-submit.is-secondary:hover,
3939
+ #dag-inspector-panel-prompt-restart button.prompt-restart-submit.is-secondary:focus-visible,
3940
+ .prompt-restart-submit.is-secondary:hover,
3941
+ .prompt-restart-submit.is-secondary:focus-visible {
3942
+ border-color: var(--orange);
3943
+ background: var(--orange-soft);
3944
+ color: var(--orange-active);
3945
+ }
3946
+ #dag-inspector-panel-prompt-restart button.prompt-restart-submit:disabled,
3618
3947
  .prompt-restart-submit:disabled {
3619
3948
  opacity: 0.55;
3620
3949
  cursor: wait;
3950
+ transform: none;
3621
3951
  }
3622
3952
  .prompt-restart-status {
3623
3953
  margin: 0;
3624
- font-size: 13px;
3625
3954
  min-height: 1.2em;
3955
+ color: var(--body);
3956
+ font-size: 13px;
3626
3957
  white-space: pre-wrap;
3627
3958
  word-break: break-word;
3628
3959
  }
3629
3960
  .prompt-restart-status.prompt-restart-error {
3630
- color: var(--red, #c0392b);
3631
- }
3632
- .prompt-restart-readonly {
3633
- margin: 0;
3634
- padding: 0.5rem 0.6rem;
3635
- font-family: var(--mono-font, ui-monospace, SFMono-Regular, Menlo, monospace);
3636
- font-size: 12.5px;
3637
- line-height: 1.5;
3638
- white-space: pre;
3639
- overflow: auto;
3640
- border: 1px solid var(--border-color, rgba(125, 125, 125, 0.35));
3641
- border-radius: 6px;
3642
- max-height: 60vh;
3643
- }
3644
- .prompt-restart-mode {
3645
- display: flex;
3646
- align-items: center;
3647
- gap: 0.5rem;
3648
- }
3649
- .prompt-restart-mode-select {
3650
- max-width: 100%;
3651
- font-size: 13px;
3961
+ color: var(--red);
3652
3962
  }