@tea-agent/loop-agent 0.40.0-next.4 → 0.40.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 +20 -0
- package/dist/build-stamp.json +3 -3
- package/dist/infrastructure/harness/atomic-write.js +23 -0
- package/dist/worker/console/chat/chat-event-store.js +62 -4
- package/dist/worker/console/chat/context-panel.js +7 -0
- package/dist/worker/console/chat/deferred-turn.js +12 -0
- package/dist/worker/console/chat/pi-runtime.js +264 -16
- package/dist/worker/console/chat/provider-error.js +98 -0
- package/dist/worker/console/chat/routes.js +292 -29
- package/dist/worker/console/chat/session-stats.js +179 -0
- package/dist/worker/console/chat/session-store.js +93 -63
- package/dist/worker/console/chat/todos.js +115 -0
- package/dist/worker/console/chat/tool-preview.js +42 -0
- package/dist/worker/console/chat/turn-process.js +20 -55
- package/dist/worker/console/chat/user-questions.js +266 -0
- package/dist/worker/console/chat/workspace-landing.js +14 -0
- package/dist/worker/console/native-directory-picker.js +13 -0
- package/dist/worker/console/routes.js +309 -1
- package/dist/worker/console/security.js +4 -4
- package/dist/worker/console/server.js +529 -186
- package/dist/worker/console/static/assets/{abnfDiagram-N423BO3Z-CTx1TrNa.js → abnfDiagram-N423BO3Z-CGZrpj0K.js} +1 -1
- package/dist/worker/console/static/assets/{arc-B4i9cVxX.js → arc-CwEyA8iq.js} +1 -1
- package/dist/worker/console/static/assets/{architectureDiagram-T3A2C74G-BAXE8_Rl.js → architectureDiagram-T3A2C74G-DLTkrEQ3.js} +1 -1
- package/dist/worker/console/static/assets/{blockDiagram-VBNYF7ZC-C5Xh59at.js → blockDiagram-VBNYF7ZC-4w12zR3t.js} +1 -1
- package/dist/worker/console/static/assets/{c4Diagram-5PPSVZJV-B_asOzAu.js → c4Diagram-5PPSVZJV-BppqLAjk.js} +1 -1
- package/dist/worker/console/static/assets/channel-TzuwQha5.js +1 -0
- package/dist/worker/console/static/assets/{chunk-2GRJ4B5K-wRO_iRNc.js → chunk-2GRJ4B5K-DO6U26Pm.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-2Q5K7J3B-ByOaSh_G.js → chunk-2Q5K7J3B-DC7YEdOy.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-5RXB4S5H-DjLzudan.js → chunk-5RXB4S5H-DtMYVQBw.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-5VM5RSS4-JCNGkXYT.js → chunk-5VM5RSS4-C5Ed-57N.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-6Q2QTUOP-BhrPXXMZ.js → chunk-6Q2QTUOP-BUY4oIzT.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-GF5L2VYU-TJ5JuEBT.js → chunk-GF5L2VYU-VnWHALIV.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-JWPE2WC7-VVthn_mD.js → chunk-JWPE2WC7-COV-RQk4.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-KBJHAD2P-D60-Mny4.js → chunk-KBJHAD2P-dSnLtUiz.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-RYQCIY6F-zXv7aVye.js → chunk-RYQCIY6F-CX6FDzWh.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-XXDRQBXY-By9VQoi1.js → chunk-XXDRQBXY-D3mEgb6W.js} +1 -1
- package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-DCu69b3S.js +1 -0
- package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-DCu69b3S.js +1 -0
- package/dist/worker/console/static/assets/{cose-bilkent-JH36ORCC-C4zQLe-M.js → cose-bilkent-JH36ORCC-QQBMUnAf.js} +1 -1
- package/dist/worker/console/static/assets/{cynefin-VYW2F7L2-wh5N2ReN.js → cynefin-VYW2F7L2-BxSD-LVV.js} +1 -1
- package/dist/worker/console/static/assets/{cynefinDiagram-MW4NZA55-Dlu5wIqs.js → cynefinDiagram-MW4NZA55-DxHNiNbk.js} +1 -1
- package/dist/worker/console/static/assets/{dagre-VZM6K2ZE-CrDgthc6.js → dagre-VZM6K2ZE-C83bYy8E.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-7IWD3JNH-zN1clg27.js → diagram-7IWD3JNH-BhtZu2YY.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-B4RE2ZJO-BN-o7J7-.js → diagram-B4RE2ZJO-K0P_ntRE.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-LBJQPF4R-C8SuPt0d.js → diagram-LBJQPF4R-CXYy1Nib.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-Q27KOJAE-BoizuHbZ.js → diagram-Q27KOJAE-D-CtIFkU.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-UB23O5K3-BzUzXixG.js → diagram-UB23O5K3-BEK9-_7c.js} +1 -1
- package/dist/worker/console/static/assets/{ebnfDiagram-BXEA7PRR-Ev3lA4Cf.js → ebnfDiagram-BXEA7PRR-L0EX-9wn.js} +1 -1
- package/dist/worker/console/static/assets/{erDiagram-JOGREHBK-GALUzRbs.js → erDiagram-JOGREHBK-9pt0fc_5.js} +1 -1
- package/dist/worker/console/static/assets/{flowDiagram-UKHOOZJN-CZJN65Sb.js → flowDiagram-UKHOOZJN-CZVeM_n1.js} +1 -1
- package/dist/worker/console/static/assets/{ganttDiagram-PKOTCBZU-JLB9OESl.js → ganttDiagram-PKOTCBZU-DqUKkAZP.js} +1 -1
- package/dist/worker/console/static/assets/{gitGraphDiagram-DS77QQ5N-CcvCr4GD.js → gitGraphDiagram-DS77QQ5N-BYUuXEgp.js} +1 -1
- package/dist/worker/console/static/assets/index-B0jGzQj6.js +407 -0
- package/dist/worker/console/static/assets/index-BiYbPiTw.css +1 -0
- package/dist/worker/console/static/assets/{infoDiagram-6WML65LV-HG5z7aVg.js → infoDiagram-6WML65LV-DNzKk7ah.js} +1 -1
- package/dist/worker/console/static/assets/{ishikawaDiagram-WSZJBQD7-BHEu9chR.js → ishikawaDiagram-WSZJBQD7-Clbyg5IP.js} +1 -1
- package/dist/worker/console/static/assets/{journeyDiagram-NVQOT4AX-Cp_Up8-a.js → journeyDiagram-NVQOT4AX-zDO_gZNO.js} +1 -1
- package/dist/worker/console/static/assets/{kanban-definition-27J2QSJJ-DvVeY-em.js → kanban-definition-27J2QSJJ-x3LpRYek.js} +1 -1
- package/dist/worker/console/static/assets/{linear-aGmcjgTn.js → linear-CTpwZqKR.js} +1 -1
- package/dist/worker/console/static/assets/{mermaid.core-Biyo-tqA.js → mermaid.core-D_WXK6C7.js} +5 -5
- package/dist/worker/console/static/assets/{mindmap-definition-FAOFIHXS-DyxY2pIb.js → mindmap-definition-FAOFIHXS-CWK-OYP5.js} +1 -1
- package/dist/worker/console/static/assets/{pegDiagram-VL7TDLO6-CkdGuc50.js → pegDiagram-VL7TDLO6-B9gtUPsM.js} +1 -1
- package/dist/worker/console/static/assets/{pieDiagram-7S7Q4E2Y-NNQI9xVR.js → pieDiagram-7S7Q4E2Y-Dj2lzceR.js} +1 -1
- package/dist/worker/console/static/assets/{quadrantDiagram-CIZ2JOQS-PAJkuz_G.js → quadrantDiagram-CIZ2JOQS-Nwljut7m.js} +1 -1
- package/dist/worker/console/static/assets/{railroadDiagram-AXF67PYL-ZwrQod0O.js → railroadDiagram-AXF67PYL-BY-KNt93.js} +1 -1
- package/dist/worker/console/static/assets/{requirementDiagram-LRYGKXZP-D3ZfrzM2.js → requirementDiagram-LRYGKXZP-Vx0wvpPy.js} +1 -1
- package/dist/worker/console/static/assets/{sankeyDiagram-W5VNT64P-DDGFmWk5.js → sankeyDiagram-W5VNT64P-B6grNXUk.js} +1 -1
- package/dist/worker/console/static/assets/{sequenceDiagram-SI44F4Z6-DO6mmXTA.js → sequenceDiagram-SI44F4Z6-CteidBvh.js} +1 -1
- package/dist/worker/console/static/assets/{sizeCapture-X5ZJPWSS-DMbCQiJt.js → sizeCapture-X5ZJPWSS-Du4W8mFK.js} +1 -1
- package/dist/worker/console/static/assets/{stateDiagram-OKZ733FA-Di_YUEfC.js → stateDiagram-OKZ733FA-jyI6Yh81.js} +1 -1
- package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-DyQblISl.js +1 -0
- package/dist/worker/console/static/assets/{swimlanes-SLNWSIFB-Bn2PphNJ.js → swimlanes-SLNWSIFB-DYWs_fRv.js} +2 -2
- package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-DiygmgYP.js +8 -0
- package/dist/worker/console/static/assets/{timeline-definition-Z64GVDOM-DPh8pRsp.js → timeline-definition-Z64GVDOM-DO5LLy47.js} +1 -1
- package/dist/worker/console/static/assets/{vennDiagram-T6HMQDX7-GMfl26pW.js → vennDiagram-T6HMQDX7-CLF2p1_L.js} +1 -1
- package/dist/worker/console/static/assets/{wardleyDiagram-T6FBY63Y-DTlmVrmF.js → wardleyDiagram-T6FBY63Y-AwTaYBxA.js} +1 -1
- package/dist/worker/console/static/assets/{xychartDiagram-ELKLHX3M-YGBjKAS5.js → xychartDiagram-ELKLHX3M-DzbblQRw.js} +1 -1
- package/dist/worker/console/static/index.html +2 -2
- package/dist/worker/console/static-src/app/console-types.js +29 -4
- package/dist/worker/console/static-src/app/useConsoleShell.js +30 -12
- package/dist/worker/console/static-src/app/useOperatorActions.js +36 -6
- package/dist/worker/console/static-src/app/useRecoveryConsole.js +10 -11
- package/dist/worker/console/static-src/app/useRunProgress.js +2 -1
- package/dist/worker/console/static-src/app/useTaskWizard.js +2 -2
- package/dist/worker/console/static-src/night/useNightBoard.js +8 -5
- package/dist/worker/console/static-src/operator-chat/chat-sse-events.js +140 -8
- package/dist/worker/console/static-src/operator-chat/details-dag-actions.js +122 -0
- package/dist/worker/console/static-src/operator-chat/refs.js +3 -0
- package/dist/worker/console/static-src/operator-chat/runtime-selection-labels.js +27 -0
- package/dist/worker/console/static-src/operator-chat/turn-submission.js +3 -2
- package/dist/worker/console/static-src/operator-chat/useChatSessions.js +168 -72
- package/dist/worker/console/static-src/operator-chat/useChatStream.js +78 -17
- package/dist/worker/console/static-src/operator-chat/useChatThread.js +184 -4
- package/dist/worker/console/static-src/operator-chat/useRepoBrowser.js +63 -9
- package/dist/worker/console/static-src/operator-chat/useWorkspaceBrowserGate.js +4 -0
- package/dist/worker/console/static-src/operator-chat/workspace-layout-mode.js +3 -3
- package/dist/worker/console/static-src/shell/useWorkspaces.js +299 -0
- package/dist/worker/console/static-src/shell/workspace-route.js +337 -0
- package/dist/worker/console/workspace-context.js +234 -0
- package/dist/worker/console/workspace-registry.js +214 -0
- package/dist/worker/observe/server.js +4 -0
- package/dist/worker/observe/static/api.js +26 -6
- package/dist/worker/observe/static/app.js +18 -70
- package/dist/worker/observe/static/index.html +1 -1
- package/dist/worker/observe/static/inspect-workspace.js +307 -0
- package/dist/worker/observe/static/operator-chrome.css +145 -20
- package/dist/worker/observe/static/operator-chrome.d.ts +20 -3
- package/dist/worker/observe/static/operator-chrome.js +330 -100
- package/dist/worker/observe/static/router.d.ts +46 -0
- package/dist/worker/observe/static/router.js +25 -1
- package/dist/worker/observe/static/state.d.ts +50 -0
- package/dist/worker/observe/static/state.js +172 -0
- package/dist/worker/observe/static/views/dag-inspector.js +3 -2
- package/dist/worker/observe/static/views/dag.js +2 -1
- package/dist/worker/observe/static/views/dashboard.js +6 -4
- package/dist/worker/observe/static/views/night.js +2 -2
- package/dist/worker/observe/static/views/pool.js +1 -0
- package/dist/worker/observe/static/views/run.js +3 -1
- package/dist/worker/observe/static/views/task.js +1 -1
- package/dist/workflows/dag/interrupt-request.js +3 -3
- package/dist/workflows/dag/lifecycle.js +3 -3
- package/docs/README.md +1 -0
- package/docs/operations/local-development-environment.md +21 -0
- package/harness.json +3 -3
- package/package.json +3 -1
- package/dist/worker/console/static/assets/channel-Dj_4Moei.js +0 -1
- package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-C0YYAyCa.js +0 -1
- package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-C0YYAyCa.js +0 -1
- package/dist/worker/console/static/assets/index-CW88Fjbw.js +0 -406
- package/dist/worker/console/static/assets/index-DP0ZJl39.css +0 -1
- package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-DrdDvela.js +0 -1
- package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-DPkEAULl.js +0 -8
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hosted Inspect workspace adapter.
|
|
3
|
+
*
|
|
4
|
+
* Standalone `/inspect/` documents canonicalize into Console `/#/inspect/...`.
|
|
5
|
+
* Console hosts a single mountInspectWorkspace instance and pauses polls via
|
|
6
|
+
* setActive(false) without destroying selection/scroll.
|
|
7
|
+
*/
|
|
8
|
+
import {
|
|
9
|
+
parseHashRouteWithFilters,
|
|
10
|
+
parseRoute,
|
|
11
|
+
setNavigateHandler,
|
|
12
|
+
inspectPathToCanonicalHref,
|
|
13
|
+
} from "./router.js";
|
|
14
|
+
import {
|
|
15
|
+
isPageVisible,
|
|
16
|
+
pauseForegroundTimers,
|
|
17
|
+
setWorkspaceActive,
|
|
18
|
+
setWorkspaceScope,
|
|
19
|
+
applyWorkspaceScopeSwitch,
|
|
20
|
+
stopTimers,
|
|
21
|
+
uiState,
|
|
22
|
+
workspaceScope,
|
|
23
|
+
} from "./state.js";
|
|
24
|
+
import { renderFailures } from "./views/failures.js";
|
|
25
|
+
import { startPoolView } from "./views/pool.js";
|
|
26
|
+
import { startDashboardPolling } from "./views/dashboard.js";
|
|
27
|
+
import { startDagsView } from "./views/dags.js";
|
|
28
|
+
import { renderFeatureDetail } from "./views/feature.js";
|
|
29
|
+
import { renderBatch } from "./views/batch.js";
|
|
30
|
+
import { startTaskPolling } from "./views/task.js";
|
|
31
|
+
import { startRunPolling } from "./views/run.js";
|
|
32
|
+
import { startDagPolling } from "./views/dag.js";
|
|
33
|
+
import { renderNightJobs } from "./views/night.js";
|
|
34
|
+
import { closeDagInspectorOnOutsideClick } from "./views/dag-inspector.js";
|
|
35
|
+
import { mountOperatorChrome } from "./operator-chrome.js";
|
|
36
|
+
|
|
37
|
+
let instance = null;
|
|
38
|
+
let lastInspectHash = "";
|
|
39
|
+
let listenersBound = false;
|
|
40
|
+
|
|
41
|
+
export function getInspectWorkspaceInstance() {
|
|
42
|
+
return instance && !instance.destroyed ? instance : null;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export function inspectCanonicalFromStandalone(locationLike) {
|
|
46
|
+
const loc = locationLike ?? (typeof location !== "undefined" ? location : null);
|
|
47
|
+
if (!loc) return null;
|
|
48
|
+
const pathname = String(loc.pathname ?? "/").replace(/\/+$/, "") || "/";
|
|
49
|
+
if (pathname !== "/inspect") return null;
|
|
50
|
+
return inspectPathToCanonicalHref(loc.hash || "#/");
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export function tryCanonicalizeStandaloneInspect(locationLike) {
|
|
54
|
+
const loc = locationLike ?? (typeof location !== "undefined" ? location : null);
|
|
55
|
+
const canonical = inspectCanonicalFromStandalone(loc);
|
|
56
|
+
if (!canonical || !loc) return false;
|
|
57
|
+
if (typeof loc.replace === "function") loc.replace(canonical);
|
|
58
|
+
else if (typeof location !== "undefined" && typeof location.replace === "function") {
|
|
59
|
+
location.replace(canonical);
|
|
60
|
+
}
|
|
61
|
+
return true;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export function navigateInspectPath(path) {
|
|
65
|
+
const href = inspectPathToCanonicalHref(path);
|
|
66
|
+
if (instance && typeof instance.onNavigate === "function") {
|
|
67
|
+
instance.onNavigate(href);
|
|
68
|
+
return href;
|
|
69
|
+
}
|
|
70
|
+
if (typeof location !== "undefined") {
|
|
71
|
+
location.hash = href.startsWith("/#") ? href.slice(1) : href;
|
|
72
|
+
}
|
|
73
|
+
return href;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function startView(routeValue) {
|
|
77
|
+
if (routeValue.view === "dashboard") {
|
|
78
|
+
startDashboardPolling(routeValue.scrollTo);
|
|
79
|
+
} else if (routeValue.view === "dags") {
|
|
80
|
+
void startDagsView();
|
|
81
|
+
} else if (routeValue.view === "batch") {
|
|
82
|
+
void renderBatch(routeValue.batchRunId);
|
|
83
|
+
} else if (routeValue.view === "run") {
|
|
84
|
+
startRunPolling(routeValue.workerRunId);
|
|
85
|
+
} else if (routeValue.view === "dag") {
|
|
86
|
+
startDagPolling(routeValue.dagRunId);
|
|
87
|
+
} else if (routeValue.view === "failures") {
|
|
88
|
+
void renderFailures();
|
|
89
|
+
} else if (routeValue.view === "pool") {
|
|
90
|
+
startPoolView();
|
|
91
|
+
} else if (routeValue.view === "night") {
|
|
92
|
+
void renderNightJobs(routeValue.scheduleId);
|
|
93
|
+
} else if (routeValue.view === "task") {
|
|
94
|
+
startTaskPolling(routeValue.featureId, routeValue.taskId);
|
|
95
|
+
} else if (routeValue.view === "feature") {
|
|
96
|
+
void renderFeatureDetail(routeValue.featureId);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export function route(hashValue) {
|
|
101
|
+
stopTimers();
|
|
102
|
+
const parsed = hashValue
|
|
103
|
+
? parseHashRouteWithFilters(hashValue)
|
|
104
|
+
: parseRoute();
|
|
105
|
+
startView(parsed);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function resumeView(hashValue) {
|
|
109
|
+
const parsed = hashValue
|
|
110
|
+
? parseHashRouteWithFilters(hashValue)
|
|
111
|
+
: parseRoute();
|
|
112
|
+
startView(parsed);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function ensureStylesheet(href) {
|
|
116
|
+
if (typeof document === "undefined") return;
|
|
117
|
+
if (document.querySelector(`link[href="${href}"]`)) return;
|
|
118
|
+
const link = document.createElement("link");
|
|
119
|
+
link.rel = "stylesheet";
|
|
120
|
+
link.href = href;
|
|
121
|
+
document.head.appendChild(link);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export async function prepareInspectWorkspace(root) {
|
|
125
|
+
if (!root || typeof document === "undefined") return;
|
|
126
|
+
if (root.querySelector("#main-content")) return;
|
|
127
|
+
ensureStylesheet("/inspect/styles.css");
|
|
128
|
+
ensureStylesheet("/inspect/operator-chrome.css");
|
|
129
|
+
const res = await fetch("/inspect/", { credentials: "same-origin" });
|
|
130
|
+
if (!res.ok) {
|
|
131
|
+
throw new Error(`Inspect markup HTTP ${res.status}`);
|
|
132
|
+
}
|
|
133
|
+
const html = await res.text();
|
|
134
|
+
const doc = new DOMParser().parseFromString(html, "text/html");
|
|
135
|
+
const app = doc.getElementById("app");
|
|
136
|
+
if (!app) throw new Error("Inspect markup missing #app");
|
|
137
|
+
root.appendChild(document.importNode(app, true));
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
function bindStandaloneListeners() {
|
|
141
|
+
if (listenersBound || typeof window === "undefined") return;
|
|
142
|
+
listenersBound = true;
|
|
143
|
+
window.addEventListener("hashchange", () => route());
|
|
144
|
+
window.addEventListener("load", () => route());
|
|
145
|
+
document.addEventListener("pointerdown", closeDagInspectorOnOutsideClick);
|
|
146
|
+
document.addEventListener("visibilitychange", () => {
|
|
147
|
+
if (!isPageVisible()) return;
|
|
148
|
+
const r = parseRoute();
|
|
149
|
+
if (r.view === "dashboard") startDashboardPolling();
|
|
150
|
+
if (r.view === "run") startRunPolling(r.workerRunId, false);
|
|
151
|
+
if (r.view === "dag") startDagPolling(r.dagRunId, false);
|
|
152
|
+
if (r.view === "pool" && uiState.poolAutoRefresh) startPoolView();
|
|
153
|
+
if (r.view === "task") startTaskPolling(r.featureId, r.taskId);
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
export function startStandaloneInspect() {
|
|
158
|
+
if (typeof window === "undefined") return;
|
|
159
|
+
// Multi-workspace (AC-003): sync scope from the URL query before any fetch.
|
|
160
|
+
syncWorkspaceScopeFromLocation();
|
|
161
|
+
window.addEventListener("hashchange", syncWorkspaceScopeFromLocation);
|
|
162
|
+
const chromeHost = document.getElementById("operator-chrome");
|
|
163
|
+
if (chromeHost) {
|
|
164
|
+
mountOperatorChrome(chromeHost, {
|
|
165
|
+
mode: "inspect",
|
|
166
|
+
liveLocation: true,
|
|
167
|
+
healthUrl: "/api/health",
|
|
168
|
+
inspectHref: "/#/inspect",
|
|
169
|
+
operateHref: "/#/operate/tasks",
|
|
170
|
+
chatHref: "/#/chat",
|
|
171
|
+
readinessHref: "/#/operate/models",
|
|
172
|
+
readinessTitle:
|
|
173
|
+
"Pi 状态(只读展示)。模型与认证管理在操作侧,点击进入。",
|
|
174
|
+
onNavigate: (href) => {
|
|
175
|
+
navigateInspectPath(href);
|
|
176
|
+
},
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
setNavigateHandler((href) => {
|
|
180
|
+
if (href.startsWith("/#/operate") || href.startsWith("/#/chat")) {
|
|
181
|
+
window.location.assign(href);
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
window.location.hash = href.startsWith("/#") ? href.slice(1) : href;
|
|
185
|
+
});
|
|
186
|
+
bindStandaloneListeners();
|
|
187
|
+
route();
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
export function mountInspectWorkspace(root, options = {}) {
|
|
191
|
+
const existing = getInspectWorkspaceInstance();
|
|
192
|
+
if (existing) {
|
|
193
|
+
if (typeof options.onNavigate === "function") {
|
|
194
|
+
existing.onNavigate = options.onNavigate;
|
|
195
|
+
setNavigateHandler(options.onNavigate);
|
|
196
|
+
}
|
|
197
|
+
if (options.hash) existing.updateRoute(options.hash);
|
|
198
|
+
if (options.active === false) existing.setActive(false);
|
|
199
|
+
else if (options.active === true) existing.setActive(true);
|
|
200
|
+
return existing;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// Multi-workspace (AC-002/AC-003): hosted mode receives the parent shell's
|
|
204
|
+
// workspaceId via mount options/hash and postMessage updates; every observe
|
|
205
|
+
// GET is then scoped via scopedApiUrl.
|
|
206
|
+
setWorkspaceScope(options.workspaceId ?? workspaceIdFromHash(options.hash));
|
|
207
|
+
window.addEventListener("message", onWorkspaceScopeMessage);
|
|
208
|
+
|
|
209
|
+
const hosted = options.hosted === true || options.hosted !== false;
|
|
210
|
+
const onNavigate =
|
|
211
|
+
typeof options.onNavigate === "function"
|
|
212
|
+
? options.onNavigate
|
|
213
|
+
: (href) => navigateInspectPath(href);
|
|
214
|
+
|
|
215
|
+
setNavigateHandler(onNavigate);
|
|
216
|
+
lastInspectHash = options.hash || (typeof location !== "undefined" ? location.hash : "");
|
|
217
|
+
setWorkspaceActive(options.active !== false);
|
|
218
|
+
|
|
219
|
+
const host = {
|
|
220
|
+
root,
|
|
221
|
+
hosted,
|
|
222
|
+
destroyed: false,
|
|
223
|
+
onNavigate,
|
|
224
|
+
updateRoute(hashValue) {
|
|
225
|
+
if (host.destroyed) return;
|
|
226
|
+
lastInspectHash = hashValue || lastInspectHash;
|
|
227
|
+
if (!uiState.workspaceActive) return;
|
|
228
|
+
// AC-006: a hosted route update that carries a DIFFERENT workspaceId
|
|
229
|
+
// must not route under the old scope. Swap atomically:
|
|
230
|
+
// abort → clear → set scope → route new.
|
|
231
|
+
const nextScope = workspaceIdFromHash(lastInspectHash);
|
|
232
|
+
if (nextScope && nextScope !== workspaceScope()) {
|
|
233
|
+
applyWorkspaceScopeSwitch(nextScope, () => route(lastInspectHash));
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
route(lastInspectHash);
|
|
237
|
+
},
|
|
238
|
+
setActive(active) {
|
|
239
|
+
if (host.destroyed) return;
|
|
240
|
+
const next = Boolean(active);
|
|
241
|
+
const wasActive = uiState.workspaceActive !== false;
|
|
242
|
+
setWorkspaceActive(next);
|
|
243
|
+
if (!next) {
|
|
244
|
+
pauseForegroundTimers();
|
|
245
|
+
return;
|
|
246
|
+
}
|
|
247
|
+
if (!wasActive) resumeView(lastInspectHash);
|
|
248
|
+
},
|
|
249
|
+
destroy() {
|
|
250
|
+
host.destroyed = true;
|
|
251
|
+
pauseForegroundTimers();
|
|
252
|
+
setNavigateHandler(null);
|
|
253
|
+
if (instance === host) instance = null;
|
|
254
|
+
},
|
|
255
|
+
};
|
|
256
|
+
instance = host;
|
|
257
|
+
if (options.autoStart !== false && !hosted) {
|
|
258
|
+
bindStandaloneListeners();
|
|
259
|
+
route(lastInspectHash);
|
|
260
|
+
}
|
|
261
|
+
return host;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
/** Extract ?workspaceId= from a canonical console hash (e.g. #/inspect?workspaceId=ws-a). */
|
|
265
|
+
function workspaceIdFromHash(hashValue) {
|
|
266
|
+
const raw = String(hashValue ?? "").replace(/^#/, "");
|
|
267
|
+
const qIndex = raw.indexOf("?");
|
|
268
|
+
if (qIndex < 0) return null;
|
|
269
|
+
const id = new URLSearchParams(raw.slice(qIndex + 1)).get("workspaceId");
|
|
270
|
+
return id?.trim() || null;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
function syncWorkspaceScopeFromLocation() {
|
|
274
|
+
if (typeof window === "undefined") return;
|
|
275
|
+
const next =
|
|
276
|
+
workspaceIdFromHash(window.location.hash) ??
|
|
277
|
+
workspaceIdFromSearch(window.location.search);
|
|
278
|
+
// Atomic scope swap (AC-006): abort old timers → clear old state → set
|
|
279
|
+
// scope → re-route with the new scope. A no-op change (same scope) only
|
|
280
|
+
// publishes the scope without tearing the live view down.
|
|
281
|
+
if (next === workspaceScope()) {
|
|
282
|
+
setWorkspaceScope(next);
|
|
283
|
+
return;
|
|
284
|
+
}
|
|
285
|
+
applyWorkspaceScopeSwitch(next, () => route());
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
function workspaceIdFromSearch(search) {
|
|
289
|
+
const params = new URLSearchParams(String(search ?? ""));
|
|
290
|
+
const id = params.get("workspaceId");
|
|
291
|
+
return id?.trim() || null;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
function onWorkspaceScopeMessage(event) {
|
|
295
|
+
const data = event?.data;
|
|
296
|
+
if (!data || typeof data !== "object") return;
|
|
297
|
+
if (data.type !== "loop-console:workspace-scope") return;
|
|
298
|
+
const next = typeof data.workspaceId === "string" ? data.workspaceId : null;
|
|
299
|
+
if (next === workspaceScope()) {
|
|
300
|
+
setWorkspaceScope(next);
|
|
301
|
+
return;
|
|
302
|
+
}
|
|
303
|
+
// Atomic scope swap (AC-006): abort → clear → set → re-route. The hosted
|
|
304
|
+
// view is re-routed (remounted from the new scope) so no observe GET can
|
|
305
|
+
// fire with the previous workspaceId after the message lands.
|
|
306
|
+
applyWorkspaceScopeSwitch(next, () => route());
|
|
307
|
+
}
|
|
@@ -9,15 +9,15 @@
|
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
11
|
.och {
|
|
12
|
-
--och-canvas: var(--canvas, #
|
|
13
|
-
--och-surface: var(--surface, #
|
|
14
|
-
--och-surface-muted: var(--surface-muted, #
|
|
15
|
-
--och-ink: var(--ink, #
|
|
16
|
-
--och-body: var(--body, #
|
|
17
|
-
--och-muted: var(--muted, #
|
|
18
|
-
--och-muted-soft: var(--muted-soft, #
|
|
19
|
-
--och-hairline: var(--hairline, #
|
|
20
|
-
--och-hairline-strong: var(--hairline-strong, #
|
|
12
|
+
--och-canvas: var(--canvas, #f3f4f6);
|
|
13
|
+
--och-surface: var(--surface, #fbfcfd);
|
|
14
|
+
--och-surface-muted: var(--surface-muted, #eceef1);
|
|
15
|
+
--och-ink: var(--ink, #202124);
|
|
16
|
+
--och-body: var(--body, #50545b);
|
|
17
|
+
--och-muted: var(--muted, #767b84);
|
|
18
|
+
--och-muted-soft: var(--muted-soft, #9ca1aa);
|
|
19
|
+
--och-hairline: var(--hairline, #e1e3e7);
|
|
20
|
+
--och-hairline-strong: var(--hairline-strong, #cfd2d8);
|
|
21
21
|
--och-orange: var(--orange, #f54e00);
|
|
22
22
|
--och-orange-active: var(--orange-active, #d04200);
|
|
23
23
|
--och-green: var(--green, #1f8a65);
|
|
@@ -40,14 +40,16 @@
|
|
|
40
40
|
top: 0;
|
|
41
41
|
z-index: 50;
|
|
42
42
|
border-bottom: 1px solid var(--och-hairline);
|
|
43
|
-
background:
|
|
43
|
+
background: var(--canvas-soft, var(--och-surface));
|
|
44
44
|
backdrop-filter: blur(12px);
|
|
45
45
|
-webkit-backdrop-filter: blur(12px);
|
|
46
46
|
font-family: inherit;
|
|
47
47
|
}
|
|
48
48
|
|
|
49
49
|
.och-inner {
|
|
50
|
-
|
|
50
|
+
box-sizing: border-box;
|
|
51
|
+
width: 100%;
|
|
52
|
+
padding-inline: 14px;
|
|
51
53
|
margin: 0 auto;
|
|
52
54
|
}
|
|
53
55
|
|
|
@@ -57,7 +59,8 @@
|
|
|
57
59
|
display: flex;
|
|
58
60
|
align-items: center;
|
|
59
61
|
gap: 12px;
|
|
60
|
-
|
|
62
|
+
/* DSH 2026-08-23:约 44px 与内容同色的压缩标题栏。 */
|
|
63
|
+
height: 44px;
|
|
61
64
|
}
|
|
62
65
|
|
|
63
66
|
.och-brand {
|
|
@@ -70,6 +73,7 @@
|
|
|
70
73
|
color: var(--och-ink);
|
|
71
74
|
text-decoration: none;
|
|
72
75
|
white-space: nowrap;
|
|
76
|
+
flex-shrink: 0;
|
|
73
77
|
}
|
|
74
78
|
.och-brand-mark {
|
|
75
79
|
display: block;
|
|
@@ -114,6 +118,19 @@
|
|
|
114
118
|
color: var(--och-muted);
|
|
115
119
|
}
|
|
116
120
|
|
|
121
|
+
.och-workspace-picker {
|
|
122
|
+
position: relative;
|
|
123
|
+
display: inline-flex;
|
|
124
|
+
min-width: 0;
|
|
125
|
+
flex-shrink: 0;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
.och-workspace-trigger .och-repo-name {
|
|
129
|
+
max-width: 180px;
|
|
130
|
+
overflow: hidden;
|
|
131
|
+
text-overflow: ellipsis;
|
|
132
|
+
}
|
|
133
|
+
|
|
117
134
|
.och-pop {
|
|
118
135
|
position: absolute;
|
|
119
136
|
top: 50px;
|
|
@@ -155,21 +172,122 @@
|
|
|
155
172
|
word-break: break-all;
|
|
156
173
|
}
|
|
157
174
|
|
|
175
|
+
.och-workspace-picker .och-pop {
|
|
176
|
+
top: 36px;
|
|
177
|
+
left: 0;
|
|
178
|
+
width: min(340px, calc(100vw - 28px));
|
|
179
|
+
min-width: 260px;
|
|
180
|
+
padding: 8px;
|
|
181
|
+
}
|
|
182
|
+
.och-workspace-picker .och-pop-title {
|
|
183
|
+
padding: 5px 7px 7px;
|
|
184
|
+
margin: 0;
|
|
185
|
+
font-size: 11px;
|
|
186
|
+
font-weight: 700;
|
|
187
|
+
letter-spacing: 0.06em;
|
|
188
|
+
color: var(--och-muted);
|
|
189
|
+
}
|
|
190
|
+
.och-workspace-option {
|
|
191
|
+
appearance: none;
|
|
192
|
+
display: flex;
|
|
193
|
+
align-items: center;
|
|
194
|
+
justify-content: space-between;
|
|
195
|
+
gap: 12px;
|
|
196
|
+
width: 100%;
|
|
197
|
+
min-height: 48px;
|
|
198
|
+
padding: 7px 8px;
|
|
199
|
+
border: 0;
|
|
200
|
+
border-radius: 9px;
|
|
201
|
+
background: transparent;
|
|
202
|
+
color: var(--och-body);
|
|
203
|
+
font: inherit;
|
|
204
|
+
text-align: left;
|
|
205
|
+
cursor: pointer;
|
|
206
|
+
}
|
|
207
|
+
.och-workspace-option:hover,
|
|
208
|
+
.och-workspace-option:focus-visible,
|
|
209
|
+
.och-workspace-option[aria-checked="true"] {
|
|
210
|
+
background: color-mix(in srgb, var(--och-ink) 7%, transparent);
|
|
211
|
+
color: var(--och-ink);
|
|
212
|
+
}
|
|
213
|
+
.och-workspace-option-copy {
|
|
214
|
+
display: grid;
|
|
215
|
+
min-width: 0;
|
|
216
|
+
gap: 2px;
|
|
217
|
+
}
|
|
218
|
+
.och-workspace-option strong,
|
|
219
|
+
.och-workspace-option small {
|
|
220
|
+
overflow: hidden;
|
|
221
|
+
text-overflow: ellipsis;
|
|
222
|
+
white-space: nowrap;
|
|
223
|
+
}
|
|
224
|
+
.och-workspace-option strong {
|
|
225
|
+
font-size: 13px;
|
|
226
|
+
font-weight: 650;
|
|
227
|
+
}
|
|
228
|
+
.och-workspace-option small {
|
|
229
|
+
font-size: 11px;
|
|
230
|
+
color: var(--och-muted);
|
|
231
|
+
}
|
|
232
|
+
.och-workspace-option > .och-icon {
|
|
233
|
+
color: var(--och-orange-active);
|
|
234
|
+
flex-shrink: 0;
|
|
235
|
+
}
|
|
236
|
+
.och-workspace-empty {
|
|
237
|
+
margin: 0;
|
|
238
|
+
padding: 12px 8px;
|
|
239
|
+
color: var(--och-muted);
|
|
240
|
+
}
|
|
241
|
+
|
|
158
242
|
/* 模式分段控件:全局唯一模式入口(重语法:ink 实底) */
|
|
159
243
|
.och-mode {
|
|
160
|
-
|
|
244
|
+
--och-mode-item-width: 92px;
|
|
245
|
+
position: relative;
|
|
246
|
+
display: grid;
|
|
247
|
+
grid-template-columns: repeat(3, var(--och-mode-item-width));
|
|
161
248
|
padding: 3px;
|
|
162
249
|
border: 1px solid var(--och-hairline);
|
|
163
250
|
border-radius: 999px;
|
|
164
251
|
background: var(--och-surface-muted);
|
|
165
252
|
flex-shrink: 0;
|
|
166
253
|
}
|
|
254
|
+
|
|
255
|
+
/* The product-mode switch is viewport-centered in Chat, Operate and Inspect;
|
|
256
|
+
* changing the active workspace must never move this global navigation. */
|
|
257
|
+
@media (min-width: 720px) {
|
|
258
|
+
.och-mode {
|
|
259
|
+
position: fixed;
|
|
260
|
+
top: 3px;
|
|
261
|
+
left: 50vw;
|
|
262
|
+
transform: translateX(-50%);
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
/* DSH 2026-08-23:共享椭圆滑块,160-220ms 移动到选中椭圆。 */
|
|
266
|
+
.och-mode-thumb {
|
|
267
|
+
position: absolute;
|
|
268
|
+
left: 0;
|
|
269
|
+
top: 0;
|
|
270
|
+
border-radius: 999px;
|
|
271
|
+
background: var(--och-ink);
|
|
272
|
+
box-shadow: 0 2px 8px rgba(38, 37, 30, 0.25);
|
|
273
|
+
transition: none;
|
|
274
|
+
pointer-events: none;
|
|
275
|
+
}
|
|
276
|
+
.och-mode-thumb.is-ready {
|
|
277
|
+
transition:
|
|
278
|
+
transform 190ms cubic-bezier(0.22, 1, 0.36, 1),
|
|
279
|
+
width 190ms cubic-bezier(0.22, 1, 0.36, 1),
|
|
280
|
+
height 190ms cubic-bezier(0.22, 1, 0.36, 1),
|
|
281
|
+
opacity 160ms ease;
|
|
282
|
+
}
|
|
167
283
|
.och-mode-btn {
|
|
168
284
|
display: inline-flex;
|
|
169
285
|
align-items: center;
|
|
170
286
|
justify-content: center;
|
|
171
287
|
gap: 6px;
|
|
172
|
-
|
|
288
|
+
box-sizing: border-box;
|
|
289
|
+
width: var(--och-mode-item-width);
|
|
290
|
+
min-width: var(--och-mode-item-width);
|
|
173
291
|
height: 30px;
|
|
174
292
|
padding: 0 14px;
|
|
175
293
|
border-radius: 999px;
|
|
@@ -190,9 +308,14 @@
|
|
|
190
308
|
}
|
|
191
309
|
.och-mode-btn.och-on,
|
|
192
310
|
.och-mode-btn.och-on:hover {
|
|
193
|
-
|
|
311
|
+
/* 滑块提供选中背景;文字反色保持可读。 */
|
|
194
312
|
color: #fff;
|
|
195
|
-
|
|
313
|
+
background: transparent;
|
|
314
|
+
box-shadow: none;
|
|
315
|
+
}
|
|
316
|
+
.och-mode-btn {
|
|
317
|
+
position: relative;
|
|
318
|
+
z-index: 1;
|
|
196
319
|
}
|
|
197
320
|
|
|
198
321
|
/* 对象上下文 chip:跨模式选中连续性 + 显式返回路径 */
|
|
@@ -452,9 +575,6 @@
|
|
|
452
575
|
.och-repo-fp {
|
|
453
576
|
display: none;
|
|
454
577
|
}
|
|
455
|
-
.och-mode-btn {
|
|
456
|
-
min-width: 0;
|
|
457
|
-
}
|
|
458
578
|
.och-workspace {
|
|
459
579
|
overflow-x: auto;
|
|
460
580
|
}
|
|
@@ -481,7 +601,7 @@
|
|
|
481
601
|
|
|
482
602
|
@media (max-width: 760px) {
|
|
483
603
|
.och-inner {
|
|
484
|
-
|
|
604
|
+
padding-inline: 12px;
|
|
485
605
|
}
|
|
486
606
|
.och-global {
|
|
487
607
|
gap: 6px;
|
|
@@ -502,6 +622,9 @@
|
|
|
502
622
|
.och-mode-btn {
|
|
503
623
|
padding-inline: 10px;
|
|
504
624
|
}
|
|
625
|
+
.och-mode {
|
|
626
|
+
--och-mode-item-width: 78px;
|
|
627
|
+
}
|
|
505
628
|
.och-tab {
|
|
506
629
|
padding-inline: 10px;
|
|
507
630
|
}
|
|
@@ -509,6 +632,8 @@
|
|
|
509
632
|
|
|
510
633
|
@media (prefers-reduced-motion: reduce) {
|
|
511
634
|
.och-mode-btn,
|
|
635
|
+
.och-mode-thumb,
|
|
636
|
+
.och-mode-thumb.is-ready,
|
|
512
637
|
.och-tab,
|
|
513
638
|
.och-repo,
|
|
514
639
|
.och-pi {
|
|
@@ -25,20 +25,33 @@ export type ChromeRepoInfo = {
|
|
|
25
25
|
inspectReady?: boolean;
|
|
26
26
|
};
|
|
27
27
|
|
|
28
|
+
export type ChromeWorkspaceSwitcher = {
|
|
29
|
+
activeId: string | null;
|
|
30
|
+
loading: boolean;
|
|
31
|
+
items: Array<{
|
|
32
|
+
workspaceId: string;
|
|
33
|
+
name: string;
|
|
34
|
+
displayPath: string;
|
|
35
|
+
}>;
|
|
36
|
+
};
|
|
37
|
+
|
|
28
38
|
export type ChromeModel = {
|
|
29
|
-
mode: "operate" | "inspect";
|
|
39
|
+
mode: "chat" | "operate" | "inspect";
|
|
30
40
|
homeHref: string;
|
|
31
41
|
brand: string;
|
|
32
42
|
repo: ChromeRepoInfo | null;
|
|
43
|
+
workspaceSwitcher: ChromeWorkspaceSwitcher | null;
|
|
33
44
|
modeButtons: Array<{
|
|
34
|
-
id: "operate" | "inspect";
|
|
45
|
+
id: "chat" | "operate" | "inspect";
|
|
35
46
|
label: string;
|
|
36
47
|
href: string;
|
|
37
48
|
active: boolean;
|
|
38
49
|
}>;
|
|
39
50
|
context: InspectContext | null;
|
|
40
51
|
freshness: boolean;
|
|
52
|
+
statusVisible: boolean;
|
|
41
53
|
pi: { state: string; label: string; href: string; title: string };
|
|
54
|
+
workspaceTabsVisible: boolean;
|
|
42
55
|
tabs: Array<OperatorChromeTab & { active: boolean }>;
|
|
43
56
|
tabsAriaLabel: string;
|
|
44
57
|
};
|
|
@@ -63,16 +76,20 @@ export function chromeStateFromHealth(body: unknown): {
|
|
|
63
76
|
repo: ChromeRepoInfo;
|
|
64
77
|
};
|
|
65
78
|
export function buildOperatorChromeModel(config: {
|
|
66
|
-
mode: "operate" | "inspect";
|
|
79
|
+
mode: "chat" | "operate" | "inspect";
|
|
67
80
|
activeTabHref?: string | null;
|
|
81
|
+
chatHref?: string;
|
|
68
82
|
operateHref?: string;
|
|
69
83
|
inspectHref?: string;
|
|
70
84
|
readinessState?: string;
|
|
71
85
|
readinessHref?: string;
|
|
72
86
|
readinessTitle?: string;
|
|
73
87
|
repo?: ChromeRepoInfo | null;
|
|
88
|
+
workspaceSwitcher?: ChromeWorkspaceSwitcher | null;
|
|
89
|
+
statusVisible?: boolean;
|
|
74
90
|
freshness?: boolean;
|
|
75
91
|
context?: InspectContext | null;
|
|
92
|
+
onSelectWorkspace?: (workspaceId: string) => void;
|
|
76
93
|
}): ChromeModel;
|
|
77
94
|
export function mountOperatorChrome(
|
|
78
95
|
root: HTMLElement,
|