@tea-agent/loop-agent 0.43.0-next.3 → 0.43.0-next.5
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.
- package/CHANGELOG.md +81 -9
- package/dist/application/task-lifecycle/advance.js +17 -4
- package/dist/application/task-lifecycle/observe.js +43 -29
- package/dist/application/task-lifecycle/plan-transitions.js +5 -4
- package/dist/build-stamp.json +3 -3
- package/dist/executors/dag-pi-executor.js +244 -33
- package/dist/executors/pi-executor.js +2 -0
- package/dist/executors/pi-sdk-executor.js +75 -39
- package/dist/task/source-prepare/source-fidelity-pi.js +2 -2
- package/dist/task/source-references.js +48 -23
- package/dist/worker/console/chat/assistant-content.js +23 -2
- package/dist/worker/console/chat/explore-tools.js +13 -0
- package/dist/worker/console/chat/pi-runtime.js +131 -95
- package/dist/worker/console/chat/routes.js +175 -54
- package/dist/worker/console/chat/scm-routes.js +193 -0
- package/dist/worker/console/chat/scm-service.js +253 -0
- package/dist/worker/console/chat/scm-tools.js +111 -0
- package/dist/worker/console/chat/sdd-data-alignment.js +65 -9
- package/dist/worker/console/chat/session-catalog.js +1 -0
- package/dist/worker/console/chat/session-mode-view.js +48 -0
- package/dist/worker/console/chat/session-mode.js +218 -0
- package/dist/worker/console/chat/session-store.js +22 -6
- package/dist/worker/console/chat/shortcuts.js +6 -0
- package/dist/worker/console/chat/terminal-routes.js +216 -0
- package/dist/worker/console/chat/terminal-sessions.js +284 -0
- package/dist/worker/console/chat/terminal-tools.js +199 -0
- package/dist/worker/console/chat/tool-preview.js +11 -0
- package/dist/worker/console/chat/tools.js +2 -0
- package/dist/worker/console/static/assets/{abnfDiagram-N423BO3Z-hUmM_GRf.js → abnfDiagram-N423BO3Z-BuyrlONK.js} +1 -1
- package/dist/worker/console/static/assets/{arc-Bt-xuieW.js → arc-BvCl_wpi.js} +1 -1
- package/dist/worker/console/static/assets/{architectureDiagram-T3A2C74G-DTqkL4DJ.js → architectureDiagram-T3A2C74G-BkBpBaRq.js} +1 -1
- package/dist/worker/console/static/assets/{blockDiagram-VBNYF7ZC-Cy0MNnzV.js → blockDiagram-VBNYF7ZC-yve4Mcb_.js} +1 -1
- package/dist/worker/console/static/assets/{c4Diagram-5PPSVZJV-DDdlT0Pd.js → c4Diagram-5PPSVZJV-9yLGboBx.js} +1 -1
- package/dist/worker/console/static/assets/channel-BRahIhjw.js +1 -0
- package/dist/worker/console/static/assets/{chunk-2GRJ4B5K-3JawwNZ6.js → chunk-2GRJ4B5K-BKP69b8r.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-2Q5K7J3B-DoTp7Cri.js → chunk-2Q5K7J3B-NWFRnXju.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-5RXB4S5H-CcirhZaS.js → chunk-5RXB4S5H-BiweqLEc.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-5VM5RSS4-VrG21gnP.js → chunk-5VM5RSS4-CP9GHmRY.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-6Q2QTUOP-DDOgIS70.js → chunk-6Q2QTUOP-BiGDkBtj.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-GF5L2VYU-CBjmgvJ_.js → chunk-GF5L2VYU-DkJ4ZjQS.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-JWPE2WC7-CCQSht8M.js → chunk-JWPE2WC7-B5jjn7zq.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-KBJHAD2P-BpGMkUUV.js → chunk-KBJHAD2P-C6KoK9O0.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-RYQCIY6F-DNDT41QL.js → chunk-RYQCIY6F-BvNIfyn-.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-XXDRQBXY-euXnDFbn.js → chunk-XXDRQBXY-BZ33iX4W.js} +1 -1
- package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-GOC80mhq.js +1 -0
- package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-GOC80mhq.js +1 -0
- package/dist/worker/console/static/assets/{cose-bilkent-JH36ORCC-BJ6NAeql.js → cose-bilkent-JH36ORCC-CP8eIuZd.js} +1 -1
- package/dist/worker/console/static/assets/{cynefin-VYW2F7L2-F5JKIvIq.js → cynefin-VYW2F7L2-DZECjpOe.js} +1 -1
- package/dist/worker/console/static/assets/{cynefinDiagram-MW4NZA55-Cwmkl_Gi.js → cynefinDiagram-MW4NZA55-CvVJoFqf.js} +1 -1
- package/dist/worker/console/static/assets/{dagre-VZM6K2ZE-BmCZ8815.js → dagre-VZM6K2ZE-D_JTqdAn.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-7IWD3JNH-zWA3hUnX.js → diagram-7IWD3JNH-Db7AQ0z0.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-B4RE2ZJO-BzA-888F.js → diagram-B4RE2ZJO-AZPVo5CZ.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-LBJQPF4R-tPNheoch.js → diagram-LBJQPF4R-BgXqI3E6.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-Q27KOJAE-Cdi7Fyqp.js → diagram-Q27KOJAE-BYjFn3Ba.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-UB23O5K3-DFK9VBf1.js → diagram-UB23O5K3-B4rJgGGO.js} +1 -1
- package/dist/worker/console/static/assets/{ebnfDiagram-BXEA7PRR-xCUr1kpg.js → ebnfDiagram-BXEA7PRR-C6XWZhpw.js} +1 -1
- package/dist/worker/console/static/assets/{erDiagram-JOGREHBK-BANQHY_A.js → erDiagram-JOGREHBK-1YdQRIQW.js} +1 -1
- package/dist/worker/console/static/assets/{flowDiagram-UKHOOZJN-VHJYEMkP.js → flowDiagram-UKHOOZJN-l3a0AwN0.js} +1 -1
- package/dist/worker/console/static/assets/{ganttDiagram-PKOTCBZU-DiyZQ0C6.js → ganttDiagram-PKOTCBZU-CQL96F2Z.js} +1 -1
- package/dist/worker/console/static/assets/{gitGraphDiagram-DS77QQ5N-CZtIeBBa.js → gitGraphDiagram-DS77QQ5N-BxCvafRb.js} +1 -1
- package/dist/worker/console/static/assets/index-4wCGsXuU.js +465 -0
- package/dist/worker/console/static/assets/index-CiF9WBoR.css +1 -0
- package/dist/worker/console/static/assets/{infoDiagram-6WML65LV-BuSspC0X.js → infoDiagram-6WML65LV-BUipIeDO.js} +1 -1
- package/dist/worker/console/static/assets/{ishikawaDiagram-WSZJBQD7-DRJZyPFy.js → ishikawaDiagram-WSZJBQD7-CRfomVMX.js} +1 -1
- package/dist/worker/console/static/assets/{journeyDiagram-NVQOT4AX-DIfXIVuE.js → journeyDiagram-NVQOT4AX-_UFvyviX.js} +1 -1
- package/dist/worker/console/static/assets/{kanban-definition-27J2QSJJ-CT10_7Lt.js → kanban-definition-27J2QSJJ-CKIRoqKv.js} +1 -1
- package/dist/worker/console/static/assets/{linear-ufemj74H.js → linear-CjttJDCM.js} +1 -1
- package/dist/worker/console/static/assets/{mermaid.core-DEQe8-_m.js → mermaid.core-DPvHX155.js} +5 -5
- package/dist/worker/console/static/assets/{mindmap-definition-FAOFIHXS-BRLUrbrC.js → mindmap-definition-FAOFIHXS-Qmj-qwBe.js} +1 -1
- package/dist/worker/console/static/assets/{pegDiagram-VL7TDLO6-BgibKtiF.js → pegDiagram-VL7TDLO6-Auw6DRgq.js} +1 -1
- package/dist/worker/console/static/assets/{pieDiagram-7S7Q4E2Y-D3eyfdV9.js → pieDiagram-7S7Q4E2Y-CqMrfD4c.js} +1 -1
- package/dist/worker/console/static/assets/{quadrantDiagram-CIZ2JOQS-DXeTk5Px.js → quadrantDiagram-CIZ2JOQS-BAddeggH.js} +1 -1
- package/dist/worker/console/static/assets/{railroadDiagram-AXF67PYL-BgXdFEe7.js → railroadDiagram-AXF67PYL-DG1JuOu2.js} +1 -1
- package/dist/worker/console/static/assets/{requirementDiagram-LRYGKXZP-CseC2A7R.js → requirementDiagram-LRYGKXZP-DLYGMKlC.js} +1 -1
- package/dist/worker/console/static/assets/{sankeyDiagram-W5VNT64P-D80PFzfJ.js → sankeyDiagram-W5VNT64P-g68SbLM9.js} +1 -1
- package/dist/worker/console/static/assets/{sequenceDiagram-SI44F4Z6-BWzHW7LS.js → sequenceDiagram-SI44F4Z6-CmszLKv8.js} +1 -1
- package/dist/worker/console/static/assets/{sizeCapture-X5ZJPWSS-xWQYTLAn.js → sizeCapture-X5ZJPWSS-D2tEKUCj.js} +1 -1
- package/dist/worker/console/static/assets/{stateDiagram-OKZ733FA-CLxtpZeL.js → stateDiagram-OKZ733FA-Syc5E_Jf.js} +1 -1
- package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-CwWwuPI-.js +1 -0
- package/dist/worker/console/static/assets/{swimlanes-SLNWSIFB-DwugtmWV.js → swimlanes-SLNWSIFB-Ibn0IRCa.js} +2 -2
- package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-A7fqemr6.js +8 -0
- package/dist/worker/console/static/assets/{timeline-definition-Z64GVDOM-DHEOwHIe.js → timeline-definition-Z64GVDOM-2ZW9W3iS.js} +1 -1
- package/dist/worker/console/static/assets/{vennDiagram-T6HMQDX7-pmbZKlBK.js → vennDiagram-T6HMQDX7-v50HsKUh.js} +1 -1
- package/dist/worker/console/static/assets/{wardleyDiagram-T6FBY63Y-CivHoM5q.js → wardleyDiagram-T6FBY63Y-DqCXEoDH.js} +1 -1
- package/dist/worker/console/static/assets/{xychartDiagram-ELKLHX3M-BfHIE7o6.js → xychartDiagram-ELKLHX3M-vIP8Vo9d.js} +1 -1
- package/dist/worker/console/static/index.html +2 -2
- package/dist/worker/console/static-src/operator-chat/chat-sse-events.js +122 -10
- package/dist/worker/console/static-src/operator-chat/pending-user-message.js +27 -15
- package/dist/worker/console/static-src/operator-chat/process-label.js +41 -0
- package/dist/worker/console/static-src/operator-chat/turn-group-equality.js +13 -0
- package/dist/worker/console/static-src/operator-chat/use-searchable-hidden.js +51 -0
- package/dist/worker/console/static-src/operator-chat/useChatSessions.js +20 -4
- package/dist/worker/console/static-src/operator-chat/useChatStream.js +18 -2
- package/dist/worker/console/static-src/operator-chat/useChatThread.js +39 -4
- package/dist/worker/console/static-src/operator-chat/useComposer.js +13 -7
- package/dist/worker/console/static-src/operator-chat/user-turn-anchor-equality.js +21 -0
- package/dist/worker/console/workspace-context.js +15 -1
- package/dist/workflows/dag/frontend-capacity.js +9 -0
- package/dist/workflows/dag/frontend-design-policy.js +2 -1
- package/dist/workflows/dag/frontend-shape-facts.js +12 -2
- package/package.json +6 -3
- package/skills/frontend-plan/SKILL.md +7 -0
- package/dist/worker/console/static/assets/channel-BpzRnZmU.js +0 -1
- package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-BhlMVqCc.js +0 -1
- package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-BhlMVqCc.js +0 -1
- package/dist/worker/console/static/assets/index-BlN6ytLr.css +0 -1
- package/dist/worker/console/static/assets/index-CA-jfWlE.js +0 -449
- package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-CiVoq4G-.js +0 -1
- package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-BkdgdpfR.js +0 -8
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { useEffect, useLayoutEffect, useRef } from "react";
|
|
2
|
+
/** Whether this browser can reveal `hidden="until-found"` content through
|
|
3
|
+
* `beforematch` (Chrome 102+, Firefox 148+, Safari: not supported at all).
|
|
4
|
+
* `content-visibility` support does NOT imply this — Safari 18+ and
|
|
5
|
+
* Firefox 125–147 have the former without the latter. */
|
|
6
|
+
function supportsUntilFound() {
|
|
7
|
+
return typeof document !== "undefined" && "onbeforematch" in document.body;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Collapse content without removing it from the document: the element gets
|
|
11
|
+
* `hidden="until-found"` so browser find-in-page can still reach the text, and
|
|
12
|
+
* a match fires `beforematch`, which reveals (expands) the disclosure again.
|
|
13
|
+
*
|
|
14
|
+
* Mirrors DSH `useSearchableHidden` (2026-09-08 alignment). Browsers without
|
|
15
|
+
* `until-found` support get a plain `hidden=""` element, which keeps the
|
|
16
|
+
* pre-alignment behavior (collapsed and not searchable).
|
|
17
|
+
*
|
|
18
|
+
* @param hidden - whether the content is collapsed.
|
|
19
|
+
* @param reveal - expand callback invoked on `beforematch` and when the
|
|
20
|
+
* collapsed subtree already owns focus.
|
|
21
|
+
* @returns ref for the collapsible container.
|
|
22
|
+
*/
|
|
23
|
+
export function useSearchableHidden(hidden, reveal) {
|
|
24
|
+
const ref = useRef(null);
|
|
25
|
+
useLayoutEffect(() => {
|
|
26
|
+
const element = ref.current;
|
|
27
|
+
if (element === null)
|
|
28
|
+
return;
|
|
29
|
+
// Focus would otherwise be lost inside a hidden subtree.
|
|
30
|
+
if (hidden && element.contains(element.ownerDocument.activeElement)) {
|
|
31
|
+
reveal();
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
if (hidden) {
|
|
35
|
+
element.setAttribute("hidden", supportsUntilFound() ? "until-found" : "");
|
|
36
|
+
}
|
|
37
|
+
else {
|
|
38
|
+
element.removeAttribute("hidden");
|
|
39
|
+
}
|
|
40
|
+
}, [hidden, reveal]);
|
|
41
|
+
useEffect(() => {
|
|
42
|
+
const element = ref.current;
|
|
43
|
+
if (element === null)
|
|
44
|
+
return;
|
|
45
|
+
element.addEventListener("beforematch", reveal);
|
|
46
|
+
return () => {
|
|
47
|
+
element.removeEventListener("beforematch", reveal);
|
|
48
|
+
};
|
|
49
|
+
}, [reveal]);
|
|
50
|
+
return ref;
|
|
51
|
+
}
|
|
@@ -2,6 +2,7 @@ import { useCallback, useEffect, useRef, useState } from "react";
|
|
|
2
2
|
import { runtimeSelectionFromRecord } from "../../chat/runtime-selection.js";
|
|
3
3
|
import { hydrateSessionThread } from "../../chat/turn-process.js";
|
|
4
4
|
import { forgetActiveChatSession, readActiveChatSessionId, rememberActiveChatSession, } from "../../chat/workspace-landing.js";
|
|
5
|
+
import { DEFAULT_CONSOLE_CHAT_SESSION_MODE } from "../../chat/session-mode-view.js";
|
|
5
6
|
import { confirmationToken } from "./format.js";
|
|
6
7
|
import { isLostChatSessionError } from "./runtime-snapshot-store.js";
|
|
7
8
|
import { upsertCompactionMessage } from "./compaction-message.js";
|
|
@@ -67,6 +68,8 @@ function sameSessionSummary(a, b) {
|
|
|
67
68
|
a.model?.modelId === b.model?.modelId &&
|
|
68
69
|
a.thinkingLevel === b.thinkingLevel &&
|
|
69
70
|
a.isBlank === b.isBlank &&
|
|
71
|
+
(a.sessionMode ?? DEFAULT_CONSOLE_CHAT_SESSION_MODE) ===
|
|
72
|
+
(b.sessionMode ?? DEFAULT_CONSOLE_CHAT_SESSION_MODE) &&
|
|
70
73
|
a.optimisticState === b.optimisticState &&
|
|
71
74
|
sameQueueSummary(a, b));
|
|
72
75
|
}
|
|
@@ -84,7 +87,7 @@ export function stabilizeSessionList(previous, next) {
|
|
|
84
87
|
return changed ? stabilized : previous;
|
|
85
88
|
}
|
|
86
89
|
/** Select a server-confirmed blank session owned by the requested workspace. */
|
|
87
|
-
export function findReusableBlankSession(list, workspaceId) {
|
|
90
|
+
export function findReusableBlankSession(list, workspaceId, sessionMode = DEFAULT_CONSOLE_CHAT_SESSION_MODE) {
|
|
88
91
|
const scope = workspaceId.trim();
|
|
89
92
|
if (!scope)
|
|
90
93
|
return undefined;
|
|
@@ -93,7 +96,8 @@ export function findReusableBlankSession(list, workspaceId) {
|
|
|
93
96
|
item.isBlank === true &&
|
|
94
97
|
item.turnPhase === "idle" &&
|
|
95
98
|
!item.activeTurnId &&
|
|
96
|
-
!item.optimisticState
|
|
99
|
+
!item.optimisticState &&
|
|
100
|
+
(item.sessionMode ?? DEFAULT_CONSOLE_CHAT_SESSION_MODE) === sessionMode);
|
|
97
101
|
}
|
|
98
102
|
export async function createSessionAndPrimeTitleWatcher(input) {
|
|
99
103
|
if (input.creatingRef?.current) {
|
|
@@ -127,7 +131,13 @@ export async function createSessionAndPrimeTitleWatcher(input) {
|
|
|
127
131
|
const body = (await res.json());
|
|
128
132
|
if (!body.session)
|
|
129
133
|
throw new Error("创建会话响应缺少 durable session");
|
|
130
|
-
const durable = {
|
|
134
|
+
const durable = {
|
|
135
|
+
...body.session,
|
|
136
|
+
isBlank: true,
|
|
137
|
+
sessionMode: body.session.sessionMode ??
|
|
138
|
+
input.options?.sessionMode ??
|
|
139
|
+
DEFAULT_CONSOLE_CHAT_SESSION_MODE,
|
|
140
|
+
};
|
|
131
141
|
const created = {
|
|
132
142
|
sessionId: durable.sessionId,
|
|
133
143
|
...(durable.workspaceId || input.options?.workspaceId
|
|
@@ -135,6 +145,7 @@ export async function createSessionAndPrimeTitleWatcher(input) {
|
|
|
135
145
|
workspaceId: durable.workspaceId ?? input.options?.workspaceId,
|
|
136
146
|
}
|
|
137
147
|
: {}),
|
|
148
|
+
sessionMode: durable.sessionMode,
|
|
138
149
|
...runtimeSelectionFromRecord(durable),
|
|
139
150
|
};
|
|
140
151
|
const nextList = replaceOptimisticSession(input.sessionListRef.current, input.options?.optimisticSessionId, durable);
|
|
@@ -545,6 +556,7 @@ export function useChatSessions(params) {
|
|
|
545
556
|
: workspaceId
|
|
546
557
|
? { workspaceId }
|
|
547
558
|
: {}),
|
|
559
|
+
sessionMode: body.session.sessionMode ?? DEFAULT_CONSOLE_CHAT_SESSION_MODE,
|
|
548
560
|
...runtimeSelectionFromRecord(body.session),
|
|
549
561
|
};
|
|
550
562
|
refs.sessionGenerationRef.current += 1;
|
|
@@ -619,6 +631,7 @@ export function useChatSessions(params) {
|
|
|
619
631
|
setError("创建会话需要选择一个有效的工作区(不会回退默认工作区)");
|
|
620
632
|
return Promise.reject(new Error("WORKSPACE_REQUIRED"));
|
|
621
633
|
}
|
|
634
|
+
const sessionMode = options?.sessionMode ?? DEFAULT_CONSOLE_CHAT_SESSION_MODE;
|
|
622
635
|
const optimisticSessionId = `optimistic-chat-${Date.now()}-${Math.random().toString(16).slice(2)}`;
|
|
623
636
|
const now = new Date().toISOString();
|
|
624
637
|
const optimisticRow = {
|
|
@@ -627,6 +640,7 @@ export function useChatSessions(params) {
|
|
|
627
640
|
state: "active",
|
|
628
641
|
updatedAt: now,
|
|
629
642
|
turnPhase: "idle",
|
|
643
|
+
sessionMode,
|
|
630
644
|
optimisticState: "creating",
|
|
631
645
|
};
|
|
632
646
|
pendingCreatedRowsRef.current.set(optimisticSessionId, optimisticRow);
|
|
@@ -669,9 +683,10 @@ export function useChatSessions(params) {
|
|
|
669
683
|
}
|
|
670
684
|
// A caller-provided snapshot is an explicit new-session boundary; reusing
|
|
671
685
|
// an existing shell would silently drop that context suffix.
|
|
686
|
+
const sessionMode = options?.sessionMode ?? DEFAULT_CONSOLE_CHAT_SESSION_MODE;
|
|
672
687
|
const reusable = options?.snapshot
|
|
673
688
|
? undefined
|
|
674
|
-
: findReusableBlankSession(sessionListRef.current, scope);
|
|
689
|
+
: findReusableBlankSession(sessionListRef.current, scope, sessionMode);
|
|
675
690
|
if (reusable) {
|
|
676
691
|
if (previousSession?.sessionId === reusable.sessionId)
|
|
677
692
|
return previousSession;
|
|
@@ -681,6 +696,7 @@ export function useChatSessions(params) {
|
|
|
681
696
|
return {
|
|
682
697
|
sessionId: reusable.sessionId,
|
|
683
698
|
...(reusable.workspaceId ? { workspaceId: reusable.workspaceId } : {}),
|
|
699
|
+
sessionMode: reusable.sessionMode ?? sessionMode,
|
|
684
700
|
...runtimeSelectionFromRecord(reusable),
|
|
685
701
|
};
|
|
686
702
|
}
|
|
@@ -53,7 +53,11 @@ function clearEmptyAssistant(setMessages, assistantId) {
|
|
|
53
53
|
return;
|
|
54
54
|
setMessages((messages) => messages.filter((message) => !(message.id === assistantId &&
|
|
55
55
|
message.role === "assistant" &&
|
|
56
|
-
!message.text.trim()
|
|
56
|
+
!message.text.trim() &&
|
|
57
|
+
// A row carrying only thinking/tool blocks is real content. Deleting
|
|
58
|
+
// it here dropped the turn's process nodes while the settled path in
|
|
59
|
+
// chat-sse-events deliberately keeps them (2026-09-08).
|
|
60
|
+
!(message.content && message.content.length > 0))));
|
|
57
61
|
}
|
|
58
62
|
/** One GET /events stream owns all Chat events. Sending a prompt creates a
|
|
59
63
|
* detached Turn resource only; it never opens a second inline SSE consumer. */
|
|
@@ -140,7 +144,10 @@ export function useChatStream(params) {
|
|
|
140
144
|
current.generation === generation)
|
|
141
145
|
current.ready = true;
|
|
142
146
|
replay = false;
|
|
143
|
-
|
|
147
|
+
// Fall through: the applier owns the buffered-replay flush and
|
|
148
|
+
// returns immediately for this event. `continue` here silently
|
|
149
|
+
// dropped that flush, so a reconnect that landed after the
|
|
150
|
+
// turn settled never restored the answer (2026-09-08).
|
|
144
151
|
}
|
|
145
152
|
const assistantId = refs.assistantIdRef.current ?? fallbackAssistantId;
|
|
146
153
|
const eventId = applySseBlock(block, assistantId, {
|
|
@@ -713,6 +720,15 @@ export function useChatStream(params) {
|
|
|
713
720
|
if (refs.sessionRef.current?.sessionId !== activeSession.sessionId ||
|
|
714
721
|
refs.sessionGenerationRef.current !== generation) {
|
|
715
722
|
releaseSubmitOwnership(clientRequestId);
|
|
723
|
+
if (refs.sessionRef.current?.sessionId === activeSession.sessionId) {
|
|
724
|
+
// Same session, newer generation: the activation snapshot replaced
|
|
725
|
+
// the thread, so the optimistic row is gone. Restore the draft
|
|
726
|
+
// instead of losing the user's text silently (2026-09-08).
|
|
727
|
+
setMessages((messages) => removePendingSubmission(messages, clientRequestId));
|
|
728
|
+
clearEmptyAssistant(setMessages, assistantId);
|
|
729
|
+
setInput(draftText);
|
|
730
|
+
setPendingImages(draftImages);
|
|
731
|
+
}
|
|
716
732
|
return;
|
|
717
733
|
}
|
|
718
734
|
// Attachments stay until accepted (AC/UIS-accepted).
|
|
@@ -1,10 +1,12 @@
|
|
|
1
|
-
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
1
|
+
import { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState, } from "react";
|
|
2
2
|
import { buildTurnProcessGroups, hydrateSessionThread, selectRecentTurnGroups, } from "../../chat/turn-process.js";
|
|
3
|
+
import { isToolFailure } from "../../chat/tool-preview.js";
|
|
3
4
|
import { mergeOperationCardState, } from "../../chat/operation-card.js";
|
|
4
5
|
import { createChatSseEventApplier, } from "./chat-sse-events.js";
|
|
5
6
|
import { mergePendingSubmissionOnHydration } from "./pending-user-message.js";
|
|
6
7
|
import { taskContextUnchanged } from "./format.js";
|
|
7
8
|
import { upsertCompactionMessage } from "./compaction-message.js";
|
|
9
|
+
import { sameTurnGroupInputs } from "./turn-group-equality.js";
|
|
8
10
|
const EMPTY_USAGE = {
|
|
9
11
|
inputTokens: 0,
|
|
10
12
|
outputTokens: 0,
|
|
@@ -115,6 +117,12 @@ export function useChatThread(params) {
|
|
|
115
117
|
// (UI-08); the SSE applier must not open the process panel.
|
|
116
118
|
void params.setProcessOpen;
|
|
117
119
|
const [messages, setMessages] = useState([]);
|
|
120
|
+
/** Rendered-messages mirror for the replay flush: it must resolve its target
|
|
121
|
+
* row synchronously, before React commits the queued updater (2026-09-08). */
|
|
122
|
+
const messagesRef = useRef([]);
|
|
123
|
+
useLayoutEffect(() => {
|
|
124
|
+
messagesRef.current = messages;
|
|
125
|
+
}, [messages]);
|
|
118
126
|
const [toolCalls, setToolCalls] = useState([]);
|
|
119
127
|
const [operationCards, setOperationCards] = useState([]);
|
|
120
128
|
const [artifactCards, setArtifactCards] = useState([]);
|
|
@@ -187,6 +195,7 @@ export function useChatThread(params) {
|
|
|
187
195
|
onTelemetryRefresh: () => void refreshSessionTelemetry(),
|
|
188
196
|
setMessages,
|
|
189
197
|
setToolCalls,
|
|
198
|
+
getMessages: () => messagesRef.current,
|
|
190
199
|
}), [refs, onReconcile, setError, refreshSessionTelemetry]);
|
|
191
200
|
/** Parse + apply one raw SSE block (frames separated by \n\n). Returns the
|
|
192
201
|
* eventId if the block carried an `id:` line (for Last-Event-ID tracking). */
|
|
@@ -285,7 +294,7 @@ export function useChatThread(params) {
|
|
|
285
294
|
if (toolCalls.length === 0)
|
|
286
295
|
return null;
|
|
287
296
|
const running = toolCalls.filter((t) => t.status === "running");
|
|
288
|
-
const errored = toolCalls.filter((t) => t
|
|
297
|
+
const errored = toolCalls.filter((t) => isToolFailure(t));
|
|
289
298
|
const current = running[running.length - 1];
|
|
290
299
|
let statusLabel = "完成";
|
|
291
300
|
let statusKind = "ok";
|
|
@@ -348,7 +357,9 @@ export function useChatThread(params) {
|
|
|
348
357
|
const previous = new Map(completedGroupsRef.current.map((group) => [group.key, group]));
|
|
349
358
|
const all = built.map((group) => {
|
|
350
359
|
const cached = previous.get(group.key);
|
|
351
|
-
return cached && !group.live
|
|
360
|
+
return cached && !group.live && sameTurnGroupInputs(cached, group)
|
|
361
|
+
? cached
|
|
362
|
+
: group;
|
|
352
363
|
});
|
|
353
364
|
completedGroupsRef.current = all.filter((group) => !group.live);
|
|
354
365
|
previousTimelineRef.current = {
|
|
@@ -450,7 +461,31 @@ export function useChatThread(params) {
|
|
|
450
461
|
/** Adopt a freshly activated session's hydrated thread + streaming flags. */
|
|
451
462
|
const applyActivatedSession = useCallback((next) => {
|
|
452
463
|
const visuallyStopped = next.turnPhase === "stopping";
|
|
453
|
-
|
|
464
|
+
// A submission still owned for THIS session keeps its optimistic bubble
|
|
465
|
+
// across an activation snapshot (refresh / reopen); a lease owned by
|
|
466
|
+
// another session must never leak into this thread (2026-09-08).
|
|
467
|
+
const ownedPending = refs.pendingSubmissionRef.current?.sessionId ===
|
|
468
|
+
refs.sessionRef.current?.sessionId
|
|
469
|
+
? refs.pendingSubmissionRef.current
|
|
470
|
+
: undefined;
|
|
471
|
+
setMessages(mergePendingSubmissionOnHydration(next.messages, ownedPending
|
|
472
|
+
? {
|
|
473
|
+
clientRequestId: ownedPending.clientRequestId,
|
|
474
|
+
user: {
|
|
475
|
+
id: ownedPending.userMessageId,
|
|
476
|
+
role: "user",
|
|
477
|
+
text: ownedPending.text,
|
|
478
|
+
createdAt: Date.now(),
|
|
479
|
+
clientRequestId: ownedPending.clientRequestId,
|
|
480
|
+
},
|
|
481
|
+
assistant: {
|
|
482
|
+
id: ownedPending.assistantId,
|
|
483
|
+
role: "assistant",
|
|
484
|
+
text: "",
|
|
485
|
+
createdAt: Date.now(),
|
|
486
|
+
},
|
|
487
|
+
}
|
|
488
|
+
: undefined));
|
|
454
489
|
setToolCalls(next.toolCalls);
|
|
455
490
|
setOperationCards([]);
|
|
456
491
|
setHumanGateCards([]);
|
|
@@ -7,7 +7,7 @@ import { attachRuntimeSnapshotController } from "./useRuntimeSnapshot.js";
|
|
|
7
7
|
/** Composer state: input text, @file palette, image attachments, /shortcuts,
|
|
8
8
|
* IME composition guards, auto-grow and server-side draft sync. */
|
|
9
9
|
export function useComposer(params) {
|
|
10
|
-
const { origin, sessionId, refs, setError, onUnrecoverableSession } = params;
|
|
10
|
+
const { origin, sessionId, sessionMode, refs, setError, onUnrecoverableSession, } = params;
|
|
11
11
|
const [input, setInputState] = useState("");
|
|
12
12
|
const [fileOptions, setFileOptions] = useState([]);
|
|
13
13
|
const [pendingImages, setPendingImages] = useState([]);
|
|
@@ -28,7 +28,10 @@ export function useComposer(params) {
|
|
|
28
28
|
}, []);
|
|
29
29
|
const [shortcutIndex, setShortcutIndex] = useState(0);
|
|
30
30
|
const [dynamicCommands, setDynamicCommands] = useState([]);
|
|
31
|
-
const [commandCapabilities, setCommandCapabilities] = useState({
|
|
31
|
+
const [commandCapabilities, setCommandCapabilities] = useState({
|
|
32
|
+
sddBingo: false,
|
|
33
|
+
sessionMode: undefined,
|
|
34
|
+
});
|
|
32
35
|
const [dynamicCommandsLoading, setDynamicCommandsLoading] = useState(false);
|
|
33
36
|
const [dynamicCommandsError, setDynamicCommandsError] = useState(null);
|
|
34
37
|
const [commandsEpoch, setCommandsEpoch] = useState(0);
|
|
@@ -75,10 +78,10 @@ export function useComposer(params) {
|
|
|
75
78
|
commandsSessionRef.current = sessionId;
|
|
76
79
|
commandsGenerationRef.current += 1;
|
|
77
80
|
setDynamicCommands([]);
|
|
78
|
-
setCommandCapabilities({ sddBingo: false });
|
|
81
|
+
setCommandCapabilities({ sddBingo: false, sessionMode });
|
|
79
82
|
setDynamicCommandsError(null);
|
|
80
83
|
setDynamicCommandsLoading(false);
|
|
81
|
-
}, [sessionId]);
|
|
84
|
+
}, [sessionId, sessionMode]);
|
|
82
85
|
const loadDynamicCommands = useCallback(async () => {
|
|
83
86
|
if (!sessionId) {
|
|
84
87
|
setDynamicCommands([]);
|
|
@@ -124,7 +127,10 @@ export function useComposer(params) {
|
|
|
124
127
|
if (!isCurrent())
|
|
125
128
|
return;
|
|
126
129
|
setDynamicCommands(items);
|
|
127
|
-
setCommandCapabilities({
|
|
130
|
+
setCommandCapabilities({
|
|
131
|
+
sddBingo: body?.capabilities?.sddBingo === true,
|
|
132
|
+
sessionMode: body?.capabilities?.sessionMode ?? sessionMode,
|
|
133
|
+
});
|
|
128
134
|
// Compact server fail-soft / partial-source warning; local Operator/Web still merge.
|
|
129
135
|
const warning = typeof body?.warning === "string" ? body.warning.trim() : "";
|
|
130
136
|
setDynamicCommandsError(warning ? warning.slice(0, 160) : null);
|
|
@@ -134,14 +140,14 @@ export function useComposer(params) {
|
|
|
134
140
|
return;
|
|
135
141
|
setDynamicCommandsError("动态命令加载失败");
|
|
136
142
|
setDynamicCommands([]);
|
|
137
|
-
setCommandCapabilities({ sddBingo: false });
|
|
143
|
+
setCommandCapabilities({ sddBingo: false, sessionMode });
|
|
138
144
|
}
|
|
139
145
|
finally {
|
|
140
146
|
if (isCurrent()) {
|
|
141
147
|
setDynamicCommandsLoading(false);
|
|
142
148
|
}
|
|
143
149
|
}
|
|
144
|
-
}, [origin, sessionId]);
|
|
150
|
+
}, [origin, sessionId, sessionMode]);
|
|
145
151
|
// Lazy-load dynamic commands when slash palette opens or session changes.
|
|
146
152
|
useEffect(() => {
|
|
147
153
|
if (!sessionId)
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/** User anchors only depend on the ordered user-message objects, not on
|
|
2
|
+
* assistant/process updates that rebuild their containing turn groups. */
|
|
3
|
+
export function sameUserMessages(previous, next) {
|
|
4
|
+
let previousIndex = 0;
|
|
5
|
+
let nextIndex = 0;
|
|
6
|
+
for (;;) {
|
|
7
|
+
while (previousIndex < previous.length && !previous[previousIndex].user) {
|
|
8
|
+
previousIndex += 1;
|
|
9
|
+
}
|
|
10
|
+
while (nextIndex < next.length && !next[nextIndex].user) {
|
|
11
|
+
nextIndex += 1;
|
|
12
|
+
}
|
|
13
|
+
if (previousIndex === previous.length || nextIndex === next.length) {
|
|
14
|
+
return previousIndex === previous.length && nextIndex === next.length;
|
|
15
|
+
}
|
|
16
|
+
if (previous[previousIndex].user !== next[nextIndex].user)
|
|
17
|
+
return false;
|
|
18
|
+
previousIndex += 1;
|
|
19
|
+
nextIndex += 1;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -37,6 +37,8 @@ import { UserQuestionRegistry } from "./chat/user-questions.js";
|
|
|
37
37
|
import { TodoListRegistry } from "./chat/todos.js";
|
|
38
38
|
import { GoalRegistry } from "./chat/goals.js";
|
|
39
39
|
import { GoalRoundDriver } from "./chat/goal-round-driver.js";
|
|
40
|
+
import { TerminalSessionRegistry } from "./chat/terminal-sessions.js";
|
|
41
|
+
import { ScmService } from "./chat/scm-service.js";
|
|
40
42
|
import { driveGoalRound, recoverDeferredTurns } from "./chat/routes.js";
|
|
41
43
|
import { createOperationEventStore, } from "./operation-sse.js";
|
|
42
44
|
import { OperationStore } from "../../infrastructure/console/operation-store.js";
|
|
@@ -254,7 +256,9 @@ export async function createWorkspaceContext(record, deps) {
|
|
|
254
256
|
}
|
|
255
257
|
},
|
|
256
258
|
});
|
|
257
|
-
const
|
|
259
|
+
const aimaxAuth = new AimaxAuthReader();
|
|
260
|
+
await aimaxAuth.getToken();
|
|
261
|
+
const sddDataAlignment = new SddDataAlignmentService(chatStore, aimaxAuth, deps.fetchImpl);
|
|
258
262
|
const chatEventEpoch = randomBytes(12).toString("hex");
|
|
259
263
|
const chatEvents = createChatEventStore({
|
|
260
264
|
appData,
|
|
@@ -285,6 +289,12 @@ export async function createWorkspaceContext(record, deps) {
|
|
|
285
289
|
operations,
|
|
286
290
|
operationEvents: events,
|
|
287
291
|
});
|
|
292
|
+
// Persistent PTY terminal sessions shared by the model tool (terminal) and
|
|
293
|
+
// the Console UI terminal panel (HTTP API), keyed per chat session owner.
|
|
294
|
+
const terminalRegistry = new TerminalSessionRegistry();
|
|
295
|
+
// Workspace-scoped git source control shared by the model tool (scm) and
|
|
296
|
+
// the Console UI SCM panel (HTTP API).
|
|
297
|
+
const scmService = new ScmService(repoRoot);
|
|
288
298
|
const chatRuntime = new ConsolePiRuntime({
|
|
289
299
|
cwd: repoRoot,
|
|
290
300
|
sessionDir: appData.chatSessions,
|
|
@@ -294,6 +304,8 @@ export async function createWorkspaceContext(record, deps) {
|
|
|
294
304
|
todoRegistry,
|
|
295
305
|
goalRegistry,
|
|
296
306
|
sddDataAlignment,
|
|
307
|
+
terminalRegistry,
|
|
308
|
+
scmService,
|
|
297
309
|
});
|
|
298
310
|
let chatRouteDeps;
|
|
299
311
|
const goalRoundDriver = new GoalRoundDriver((sessionId) => driveGoalRound(chatRouteDeps, sessionId));
|
|
@@ -308,6 +320,8 @@ export async function createWorkspaceContext(record, deps) {
|
|
|
308
320
|
sddDataAlignment,
|
|
309
321
|
goalRoundDriver,
|
|
310
322
|
operationLinker: chatOperationLinker,
|
|
323
|
+
terminals: terminalRegistry,
|
|
324
|
+
scm: scmService,
|
|
311
325
|
appData,
|
|
312
326
|
bootToken: deps.bootToken,
|
|
313
327
|
getConsoleOrigin: deps.getConsoleOrigin,
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/** Shared Contract/Plan bound. Permissions and directory globs are not files. */
|
|
2
|
+
export const FRONTEND_MAX_IMPLEMENTATION_FILES = 15;
|
|
3
|
+
export function frontendConcreteDeliveryFiles(files) {
|
|
4
|
+
if (!Array.isArray(files))
|
|
5
|
+
return [];
|
|
6
|
+
return [...new Set(files.filter((file) => typeof file === "string")
|
|
7
|
+
.map(file => file.trim().replace(/\\/g, "/").replace(/^(\.\/)+/, ""))
|
|
8
|
+
.filter(file => file.length > 0 && !/[*?{}]/.test(file) && !file.endsWith("/")))];
|
|
9
|
+
}
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { deterministicSha256, } from "./frontend-implementation-contract.js";
|
|
2
2
|
import { pathMatchesPattern } from "../../shared/git-progress.js";
|
|
3
|
+
import { FRONTEND_MAX_IMPLEMENTATION_FILES } from "./frontend-capacity.js";
|
|
3
4
|
const SHA256_HEX = /^[a-f0-9]{64}$/;
|
|
4
5
|
const NPM_PACKAGE_NAME = /^(?:@[a-zA-Z0-9_.-]+\/)?[a-zA-Z0-9][a-zA-Z0-9_.-]*$/;
|
|
5
6
|
/** Max concrete implementation files a single writeSet may carry before the
|
|
6
7
|
* plan is asked to split. Kept at 15: beyond this, a single implement node's
|
|
7
8
|
* read/edit loop inflates provider context toward overflow. */
|
|
8
|
-
const MAX_WRITE_SET_FILES =
|
|
9
|
+
const MAX_WRITE_SET_FILES = FRONTEND_MAX_IMPLEMENTATION_FILES;
|
|
9
10
|
function normalizeRelativePath(value) {
|
|
10
11
|
return value.replace(/\\/g, "/").replace(/^\.\//, "");
|
|
11
12
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { sha256OfCanonicalJson } from "../../task/contract/hash.js";
|
|
2
|
+
import { FRONTEND_MAX_IMPLEMENTATION_FILES, frontendConcreteDeliveryFiles } from "./frontend-capacity.js";
|
|
2
3
|
import { buildFrontendShapeTransitionCapsule, deriveFrontendRuntimeShapeFacts, evaluateFrontendShapeEscalation, parseFrontendShapeTransitionCapsule, } from "./frontend-shape.js";
|
|
3
4
|
import { createTypedEventStore, readCommittedEvents, } from "./frontend-typed-event-store.js";
|
|
4
5
|
import { adoptTypedEventFact, stageTypedEventFact, } from "./frontend-typed-event-transaction.js";
|
|
@@ -222,7 +223,13 @@ function extractRuntimeShapeEvidence(input) {
|
|
|
222
223
|
!sourceText.includes(path) &&
|
|
223
224
|
/(?:\.[A-Za-z0-9]+|\*\*)$/.test(path));
|
|
224
225
|
const routes = canonicalStrings(text.match(/\/(?:[A-Za-z0-9_:[\]-]+\/?)+/g) ?? []);
|
|
225
|
-
|
|
226
|
+
// The frozen delivery inventory is available before Plan. Do not spend
|
|
227
|
+
// coverage/UX sessions building a contract the same capacity gate will reject.
|
|
228
|
+
// allowedPaths and text mentions are permissions/evidence, never this count.
|
|
229
|
+
const skeleton = input.tasksById.get("frontend-plan-pi")?.structuredContractOutput?.skeleton;
|
|
230
|
+
const deliveryFiles = frontendConcreteDeliveryFiles(skeleton?.targets?.files);
|
|
231
|
+
const capacitySplit = deliveryFiles.length > FRONTEND_MAX_IMPLEMENTATION_FILES;
|
|
232
|
+
const splitRequired = capacitySplit || /["']splitRequired["']\s*:\s*true|\bsplit-required\s+shape\b/i.test(text);
|
|
226
233
|
return {
|
|
227
234
|
sourceNodeId: input.sourceNodeId,
|
|
228
235
|
sourceNodeDigest: computeFrontendShapeNodeDigest(node),
|
|
@@ -232,7 +239,10 @@ function extractRuntimeShapeEvidence(input) {
|
|
|
232
239
|
targetPaths,
|
|
233
240
|
routes,
|
|
234
241
|
splitRequired,
|
|
235
|
-
evidenceRefs: [
|
|
242
|
+
evidenceRefs: [
|
|
243
|
+
...(capacitySplit ? ["dag:frontend-plan-pi:structuredContractOutput.skeleton.targets.files"] : []),
|
|
244
|
+
`node:${input.sourceNodeId}:stdout`,
|
|
245
|
+
],
|
|
236
246
|
};
|
|
237
247
|
}
|
|
238
248
|
/** Commit a typed, structured runtime fact immediately after a canonical source
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tea-agent/loop-agent",
|
|
3
|
-
"version": "0.43.0-next.
|
|
3
|
+
"version": "0.43.0-next.5",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"bin": {
|
|
6
6
|
"loop-agent": "bin/loop-agent.js",
|
|
@@ -78,9 +78,12 @@
|
|
|
78
78
|
"@deepseek-ai/dsh-invariants": "0.1.1-rc.2",
|
|
79
79
|
"@earendil-works/pi-ai": "0.83.0",
|
|
80
80
|
"@earendil-works/pi-coding-agent": "0.83.0",
|
|
81
|
+
"@xterm/addon-fit": "^0.11.0",
|
|
82
|
+
"@xterm/xterm": "^6.0.0",
|
|
81
83
|
"commander": "^12.1.0",
|
|
82
84
|
"katex": "^0.16.47",
|
|
83
85
|
"mermaid": "^11.16.1",
|
|
86
|
+
"node-pty": "^1.2.0-beta.15",
|
|
84
87
|
"rehype-highlight": "^7.0.2",
|
|
85
88
|
"rehype-katex": "^7.0.1",
|
|
86
89
|
"remark-math": "^6.0.0",
|
|
@@ -90,8 +93,8 @@
|
|
|
90
93
|
"zod": "^3.25.76"
|
|
91
94
|
},
|
|
92
95
|
"optionalDependencies": {
|
|
93
|
-
"@
|
|
94
|
-
"@
|
|
96
|
+
"@agent-context/sift": "0.0.1-alpha.7",
|
|
97
|
+
"@cursor/sdk": "^1.0.7"
|
|
95
98
|
},
|
|
96
99
|
"devDependencies": {
|
|
97
100
|
"@remixicon/react": "^4.9.0",
|
|
@@ -29,6 +29,13 @@ cite `evidencePath` of an existing file; greenfield is `decision=new`.
|
|
|
29
29
|
Bind every file in the Contract-owned `requiredDeliverables` inventory. It records
|
|
30
30
|
explicit source obligations, not every path mentioned by a requirement.
|
|
31
31
|
|
|
32
|
+
Large UX work runs in bounded scopes against that shared registry. Complete every
|
|
33
|
+
assigned requirement; preserve earlier scopes' shared bindings when correcting an
|
|
34
|
+
entry. Ledger previews are incomplete. Use `read_plan_facts` to retrieve full
|
|
35
|
+
fields, following `nextOffset` with `expectedRevision` pinned. For oversized
|
|
36
|
+
strings use `stringOffset` and follow `nextStringOffset`; restart pagination when
|
|
37
|
+
the revision changes. Never submit a truncated preview as a replacement payload.
|
|
38
|
+
|
|
32
39
|
Cross-slice citations must close in the same session: when a requirement cites a
|
|
33
40
|
verification target committed in another slice's session, re-commit that target
|
|
34
41
|
here with the same id and `replace=true` (union backfill) before finalize. A
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{ag as o,ah as n}from"./mermaid.core-DEQe8-_m.js";const t=(a,r)=>o.lang.round(n.parse(a)[r]);export{t as c};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{s as a,c as s,a as e,C as t}from"./chunk-GF5L2VYU-CBjmgvJ_.js";import{_ as i}from"./mermaid.core-DEQe8-_m.js";import"./chunk-5VM5RSS4-VrG21gnP.js";import"./chunk-XXDRQBXY-euXnDFbn.js";import"./chunk-KBJHAD2P-BpGMkUUV.js";import"./chunk-2GRJ4B5K-3JawwNZ6.js";import"./index-CA-jfWlE.js";var n={parser:e,get db(){return new t},renderer:s,styles:a,init:i(r=>{r.class||(r.class={}),r.class.arrowMarkerAbsolute=r.arrowMarkerAbsolute},"init")};export{n as diagram};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{s as a,c as s,a as e,C as t}from"./chunk-GF5L2VYU-CBjmgvJ_.js";import{_ as i}from"./mermaid.core-DEQe8-_m.js";import"./chunk-5VM5RSS4-VrG21gnP.js";import"./chunk-XXDRQBXY-euXnDFbn.js";import"./chunk-KBJHAD2P-BpGMkUUV.js";import"./chunk-2GRJ4B5K-3JawwNZ6.js";import"./index-CA-jfWlE.js";var n={parser:e,get db(){return new t},renderer:s,styles:a,init:i(r=>{r.class||(r.class={}),r.class.arrowMarkerAbsolute=r.arrowMarkerAbsolute},"init")};export{n as diagram};
|