@tea-agent/loop-agent 0.13.0-beta.0 → 0.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +2 -0
- package/CHANGELOG.md +56 -305
- package/README.md +13 -19
- package/dist/commands/init.js +92 -23
- package/dist/executors/pi-event-serializer.js +33 -11
- package/dist/executors/shell-executor.js +200 -21
- package/dist/infrastructure/evaluation/candidate-store.js +5 -1
- package/dist/worker/observe/spec-evidence.js +19 -10
- package/dist/worker/observe/static/app.js +4 -3
- package/dist/worker/observe/static/constants.js +10 -2
- package/dist/worker/observe/static/dag-helpers.js +37 -8
- package/dist/worker/observe/static/dom.js +159 -0
- package/dist/worker/observe/static/format-pool.d.ts +71 -0
- package/dist/worker/observe/static/format-pool.js +67 -0
- package/dist/worker/observe/static/format.js +27 -2
- package/dist/worker/observe/static/index.html +76 -34
- package/dist/worker/observe/static/kpi.js +12 -6
- package/dist/worker/observe/static/markdown-render.js +124 -0
- package/dist/worker/observe/static/shell-chrome.js +8 -2
- package/dist/worker/observe/static/state.js +20 -0
- package/dist/worker/observe/static/styles.css +662 -60
- package/dist/worker/observe/static/views/dag-inspector.js +65 -142
- package/dist/worker/observe/static/views/dag.js +9 -0
- package/dist/worker/observe/static/views/dashboard.js +512 -269
- package/dist/worker/observe/static/views/pool.js +595 -237
- package/dist/worker/observe/static/views/session-timeline.js +577 -11
- package/dist/workflows/dag/backend-test-case-manifest.js +503 -0
- package/dist/workflows/dag/backend-test-execution-contract.js +353 -0
- package/dist/workflows/dag/backend-test-result-contract.js +568 -0
- package/dist/workflows/dag/decision-envelope.js +57 -2
- package/dist/workflows/dag/frontend-implementation-contract.js +240 -0
- package/dist/workflows/dag/frontend-project-capability.js +309 -0
- package/dist/workflows/dag/frontend-repair.js +341 -0
- package/dist/workflows/dag/frontend-risk.js +161 -0
- package/dist/workflows/dag/frontend-verification-trace.js +190 -0
- package/dist/workflows/dag/init-hybrid.js +1020 -125
- package/dist/workflows/dag/repair-artifact.js +43 -3
- package/dist/workflows/dag/skill-instructions.js +4 -2
- package/dist/workflows/dag/types.js +29 -8
- package/docs/README.md +2 -0
- package/docs/agent-dag-recovery-playbook.md +3 -3
- package/docs/agent-dag-runner.md +3 -3
- package/docs/architecture/README.md +3 -3
- package/docs/architecture/dag-execution.md +1 -1
- package/docs/architecture/evolution.md +13 -13
- package/docs/architecture/facts-and-state.md +1 -1
- package/docs/architecture/runtime-boundaries.md +7 -7
- package/docs/architecture/system-overview.md +3 -3
- package/docs/architecture/worker-and-feature.md +3 -3
- package/docs/design/README.md +7 -7
- package/docs/development-principles.md +4 -4
- package/docs/exec-plans/active/README.md +2 -4
- package/docs/exec-plans/completed/README.md +29 -6
- package/docs/feature-workflow.md +57 -32
- package/docs/init-surface.manifest.json +21 -3
- package/docs/loop-agent-harness.md +8 -8
- package/docs/production-readiness.md +1 -1
- package/docs/progress/README.md +20 -3
- package/docs/reports/README.md +53 -7
- package/docs/templates/agent-dag.supervised-implementation.json +127 -8
- package/docs/templates/backend-test-case-manifest.schema.json +190 -0
- package/docs/templates/backend-test-dag.classify.prompt.md +75 -0
- package/docs/templates/backend-test-dag.generate-pytest.prompt.md +6 -4
- package/docs/templates/backend-test-dag.json +269 -21
- package/docs/templates/backend-test-dag.retrospect.prompt.md +44 -30
- package/docs/templates/backend-test-dag.review-cases.prompt.md +6 -4
- package/docs/templates/backend-test-execution.schema.json +133 -0
- package/docs/templates/backend-test-result.schema.json +99 -0
- package/docs/templates/branch-merge-report.md +93 -0
- package/docs/templates/frontend-eval/fixtures/failures/01-type-build-error.md +17 -0
- package/docs/templates/frontend-eval/fixtures/failures/02-unit-component-test-fail.md +16 -0
- package/docs/templates/frontend-eval/fixtures/failures/03-fixture-schema-drift.md +16 -0
- package/docs/templates/frontend-eval/fixtures/failures/04-missing-loading-empty-error-state.md +16 -0
- package/docs/templates/frontend-eval/fixtures/failures/05-forbidden-write-writeset-expansion.md +16 -0
- package/docs/templates/frontend-eval/fixtures/failures/06-unapproved-dependency-add.md +16 -0
- package/docs/templates/frontend-eval/fixtures/failures/07-mock-production-on.md +21 -0
- package/docs/templates/frontend-eval/fixtures/functional/01-simple-component-style.md +29 -0
- package/docs/templates/frontend-eval/fixtures/functional/02-form-validation.md +28 -0
- package/docs/templates/frontend-eval/fixtures/functional/03-list-detail-page.md +28 -0
- package/docs/templates/frontend-eval/fixtures/functional/04-api-mock.md +29 -0
- package/docs/templates/frontend-eval/fixtures/functional/05-permission-auth-gated-ui.md +27 -0
- package/docs/templates/frontend-eval/fixtures/functional/06-ssr-server-client-boundary.md +28 -0
- package/docs/templates/frontend-eval/fixtures/functional/07-shared-public-component-api.md +28 -0
- package/docs/templates/frontend-eval/fixtures/functional/08-pure-local-no-remote.md +27 -0
- package/docs/templates/frontend-eval/metrics.md +138 -0
- package/docs/templates/frontend-eval/smoke-targets.md +53 -0
- package/docs/templates/frontend-implementation-contract.schema.json +27 -0
- package/docs/verification-matrix.md +1 -1
- package/examples/decision-gate-agent-dag.json +4 -4
- package/examples/hybrid-loop-agent-dag.json +1 -1
- package/package.json +2 -2
- package/skills/ai-engineering-context/SKILL.md +2 -2
- package/skills/browser-tools/SKILL.md +196 -0
- package/skills/browser-tools/browser-content.js +103 -0
- package/skills/browser-tools/browser-cookies.js +35 -0
- package/skills/browser-tools/browser-eval.js +53 -0
- package/skills/browser-tools/browser-hn-scraper.js +108 -0
- package/skills/browser-tools/browser-nav.js +44 -0
- package/skills/browser-tools/browser-pick.js +162 -0
- package/skills/browser-tools/browser-screenshot.js +34 -0
- package/skills/browser-tools/browser-start.js +86 -0
- package/skills/browser-tools/package-lock.json +2556 -0
- package/skills/browser-tools/package.json +19 -0
- package/skills/frontend-implementation/SKILL.md +3 -1
- package/skills/frontend-implementation/references/node-contracts.md +17 -66
- package/skills/frontend-verification/SKILL.md +1 -1
- package/skills/grill-with-docs/SKILL.md +5 -5
- package/skills/grill-with-docs/adr-format.md +3 -3
- package/skills/init-capability-evolution/SKILL.md +5 -5
- package/skills/loop-agent/SKILL.md +5 -5
- package/skills/loop-agent/references/README.md +3 -3
- package/skills/loop-agent/references/command-reference.md +39 -17
- package/skills/loop-agent/references/docs-converge.md +15 -15
- package/skills/loop-agent/references/harness-policy.md +2 -2
- package/skills/loop-agent/references/hybrid-dag.md +20 -15
- package/skills/loop-agent/references/multi-worktree.md +1 -1
- package/skills/loop-agent/references/orchestrator-and-interventions.md +8 -8
- package/skills/loop-agent/references/task-workflow.md +1 -1
- package/skills/loop-agent/references/verification-and-failure-handling.md +6 -4
- package/skills/requesting-code-review/SKILL.md +1 -1
- package/skills/systematic-debugging/CREATION-LOG.md +3 -3
- package/skills/systematic-debugging/SKILL.md +1 -1
- package/skills/systematic-debugging/test-academic.md +1 -1
- package/skills/systematic-debugging/test-pressure-1.md +1 -1
- package/skills/systematic-debugging/test-pressure-2.md +1 -1
- package/skills/systematic-debugging/test-pressure-3.md +1 -1
- package/skills/verification-before-completion/SKILL.md +1 -1
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/** DAG node inspector panel (Observe UI R5). */
|
|
2
2
|
import {
|
|
3
3
|
DAG_INSPECTOR_DEFAULT_WIDTH,
|
|
4
|
+
DAG_INSPECTOR_DEFAULT_WIDTH_RATIO,
|
|
4
5
|
DAG_INSPECTOR_MIN_WIDTH,
|
|
5
6
|
DAG_INSPECTOR_MAX_WIDTH,
|
|
6
7
|
DAG_INSPECTOR_RIGHT_OFFSET,
|
|
@@ -10,9 +11,11 @@ import {
|
|
|
10
11
|
} from "../constants.js";
|
|
11
12
|
import { clearNode, el } from "../dom.js";
|
|
12
13
|
import { fetchJson } from "../api.js";
|
|
13
|
-
import { badge
|
|
14
|
+
import { badge } from "../format.js";
|
|
15
|
+
import { renderMarkdown } from "../markdown-render.js";
|
|
14
16
|
import {
|
|
15
17
|
uiState,
|
|
18
|
+
makeSessionEventIdentity,
|
|
16
19
|
updateDagTimelineViewportState,
|
|
17
20
|
updateDagOutputViewportState,
|
|
18
21
|
computeFollowLatest,
|
|
@@ -23,6 +26,17 @@ import {
|
|
|
23
26
|
renderSessionTimeline,
|
|
24
27
|
} from "./session-timeline.js";
|
|
25
28
|
|
|
29
|
+
// Current inspector selection. Tab handlers reference this mutable slot so a
|
|
30
|
+
// reused inspector shell never keeps stale node closures: every render writes
|
|
31
|
+
// the latest {dagRunId, node} here and tab clicks re-render from the same
|
|
32
|
+
// reference, always resolving the currently selected node identity.
|
|
33
|
+
const inspectorSelection = { dagRunId: null, node: null };
|
|
34
|
+
|
|
35
|
+
function renderDagInspectorForCurrent() {
|
|
36
|
+
if (!inspectorSelection.dagRunId || !inspectorSelection.node) return;
|
|
37
|
+
renderDagInspector(inspectorSelection.dagRunId, inspectorSelection.node, false);
|
|
38
|
+
}
|
|
39
|
+
|
|
26
40
|
export function selectDagNode(dagRunId, nodeId) {
|
|
27
41
|
const nodeChanged = uiState.selectedDagNodeId !== nodeId;
|
|
28
42
|
uiState.selectedDagNodeId = nodeId;
|
|
@@ -30,6 +44,9 @@ export function selectDagNode(dagRunId, nodeId) {
|
|
|
30
44
|
if (nodeChanged) {
|
|
31
45
|
uiState.sessionEventOffset = 0;
|
|
32
46
|
uiState.sessionEvents = [];
|
|
47
|
+
// Bump the session-event identity token so any in-flight response for the
|
|
48
|
+
// previous node is rejected before it can mutate the current node cache.
|
|
49
|
+
uiState.sessionEventIdentity = makeSessionEventIdentity(dagRunId, nodeId);
|
|
33
50
|
}
|
|
34
51
|
void import("./dag.js").then((m) => m.renderDagDetail(dagRunId, false));
|
|
35
52
|
}
|
|
@@ -65,6 +82,17 @@ export function dagInspectorMaximumWidth() {
|
|
|
65
82
|
);
|
|
66
83
|
}
|
|
67
84
|
|
|
85
|
+
/** Default open width: half the viewport, clamped to min/max. */
|
|
86
|
+
export function dagInspectorDefaultWidth() {
|
|
87
|
+
const half = Math.round(
|
|
88
|
+
window.innerWidth * DAG_INSPECTOR_DEFAULT_WIDTH_RATIO,
|
|
89
|
+
);
|
|
90
|
+
return Math.min(
|
|
91
|
+
dagInspectorMaximumWidth(),
|
|
92
|
+
Math.max(DAG_INSPECTOR_MIN_WIDTH, half || DAG_INSPECTOR_DEFAULT_WIDTH),
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
|
|
68
96
|
export function setDagInspectorWidth(panel, requestedWidth) {
|
|
69
97
|
const maximum = dagInspectorMaximumWidth();
|
|
70
98
|
uiState.dagInspectorWidth = Math.min(
|
|
@@ -95,7 +123,7 @@ export function createDagInspectorResizeHandle(panel) {
|
|
|
95
123
|
panel,
|
|
96
124
|
requestedWidth ??
|
|
97
125
|
uiState.dagInspectorWidth ??
|
|
98
|
-
|
|
126
|
+
dagInspectorDefaultWidth(),
|
|
99
127
|
);
|
|
100
128
|
handle.setAttribute("aria-valuemin", String(range.minimum));
|
|
101
129
|
handle.setAttribute("aria-valuemax", String(range.maximum));
|
|
@@ -123,7 +151,7 @@ export function createDagInspectorResizeHandle(panel) {
|
|
|
123
151
|
handle.addEventListener("pointercancel", stopResizing);
|
|
124
152
|
handle.addEventListener("keydown", (event) => {
|
|
125
153
|
const currentWidth =
|
|
126
|
-
uiState.dagInspectorWidth ??
|
|
154
|
+
uiState.dagInspectorWidth ?? dagInspectorDefaultWidth();
|
|
127
155
|
if (event.key === "ArrowLeft") {
|
|
128
156
|
event.preventDefault();
|
|
129
157
|
updateRange(currentWidth + DAG_INSPECTOR_KEYBOARD_STEP);
|
|
@@ -160,118 +188,6 @@ export function captureDagTimelineViewportState(panel) {
|
|
|
160
188
|
}
|
|
161
189
|
}
|
|
162
190
|
|
|
163
|
-
export function appendInlineMarkdown(target, text) {
|
|
164
|
-
const tokenPattern = /(`[^`]*`|\*\*[^*]+\*\*|\*[^*]+\*|\[[^\]]+\]\([^)]+\))/g;
|
|
165
|
-
let cursor = 0;
|
|
166
|
-
for (const match of text.matchAll(tokenPattern)) {
|
|
167
|
-
const index = match.index ?? 0;
|
|
168
|
-
if (index > cursor)
|
|
169
|
-
target.appendChild(document.createTextNode(text.slice(cursor, index)));
|
|
170
|
-
const token = match[0];
|
|
171
|
-
if (token.startsWith("`")) {
|
|
172
|
-
target.appendChild(el("code", null, token.slice(1, -1)));
|
|
173
|
-
} else if (token.startsWith("**")) {
|
|
174
|
-
const strong = document.createElement("strong");
|
|
175
|
-
strong.textContent = token.slice(2, -2);
|
|
176
|
-
target.appendChild(strong);
|
|
177
|
-
} else if (token.startsWith("*")) {
|
|
178
|
-
const emphasis = document.createElement("em");
|
|
179
|
-
emphasis.textContent = token.slice(1, -1);
|
|
180
|
-
target.appendChild(emphasis);
|
|
181
|
-
} else {
|
|
182
|
-
const link = token.match(/^\[([^\]]+)\]\((.+)\)$/);
|
|
183
|
-
const href = markdownLinkHref(link?.[2]);
|
|
184
|
-
if (link && href) {
|
|
185
|
-
const anchor = document.createElement("a");
|
|
186
|
-
anchor.href = href;
|
|
187
|
-
anchor.target = "_blank";
|
|
188
|
-
anchor.rel = "noopener noreferrer";
|
|
189
|
-
anchor.textContent = link[1];
|
|
190
|
-
target.appendChild(anchor);
|
|
191
|
-
} else {
|
|
192
|
-
target.appendChild(document.createTextNode(token));
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
cursor = index + token.length;
|
|
196
|
-
}
|
|
197
|
-
if (cursor < text.length)
|
|
198
|
-
target.appendChild(document.createTextNode(text.slice(cursor)));
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
export function renderMarkdown(content) {
|
|
202
|
-
const article = el("article", "markdown-output");
|
|
203
|
-
for (const block of parseMarkdownBlocks(content)) {
|
|
204
|
-
switch (block.type) {
|
|
205
|
-
case "heading": {
|
|
206
|
-
const heading = document.createElement(`h${block.level}`);
|
|
207
|
-
appendInlineMarkdown(heading, block.text);
|
|
208
|
-
article.appendChild(heading);
|
|
209
|
-
break;
|
|
210
|
-
}
|
|
211
|
-
case "paragraph": {
|
|
212
|
-
const paragraph = document.createElement("p");
|
|
213
|
-
appendInlineMarkdown(paragraph, block.text);
|
|
214
|
-
article.appendChild(paragraph);
|
|
215
|
-
break;
|
|
216
|
-
}
|
|
217
|
-
case "quote": {
|
|
218
|
-
const quote = document.createElement("blockquote");
|
|
219
|
-
appendInlineMarkdown(quote, block.text);
|
|
220
|
-
article.appendChild(quote);
|
|
221
|
-
break;
|
|
222
|
-
}
|
|
223
|
-
case "list": {
|
|
224
|
-
const list = document.createElement(block.ordered ? "ol" : "ul");
|
|
225
|
-
for (const item of block.items) {
|
|
226
|
-
const listItem = document.createElement("li");
|
|
227
|
-
appendInlineMarkdown(listItem, item);
|
|
228
|
-
list.appendChild(listItem);
|
|
229
|
-
}
|
|
230
|
-
article.appendChild(list);
|
|
231
|
-
break;
|
|
232
|
-
}
|
|
233
|
-
case "code": {
|
|
234
|
-
const pre = document.createElement("pre");
|
|
235
|
-
const code = document.createElement("code");
|
|
236
|
-
if (block.language) code.dataset.language = block.language;
|
|
237
|
-
code.textContent = block.text;
|
|
238
|
-
pre.appendChild(code);
|
|
239
|
-
article.appendChild(pre);
|
|
240
|
-
break;
|
|
241
|
-
}
|
|
242
|
-
case "table": {
|
|
243
|
-
const table = document.createElement("table");
|
|
244
|
-
const head = document.createElement("thead");
|
|
245
|
-
const headRow = document.createElement("tr");
|
|
246
|
-
for (const value of block.headers) {
|
|
247
|
-
const cell = document.createElement("th");
|
|
248
|
-
appendInlineMarkdown(cell, value);
|
|
249
|
-
headRow.appendChild(cell);
|
|
250
|
-
}
|
|
251
|
-
head.appendChild(headRow);
|
|
252
|
-
table.appendChild(head);
|
|
253
|
-
const body = document.createElement("tbody");
|
|
254
|
-
for (const row of block.rows) {
|
|
255
|
-
const tableRow = document.createElement("tr");
|
|
256
|
-
for (const value of row) {
|
|
257
|
-
const cell = document.createElement("td");
|
|
258
|
-
appendInlineMarkdown(cell, value);
|
|
259
|
-
tableRow.appendChild(cell);
|
|
260
|
-
}
|
|
261
|
-
body.appendChild(tableRow);
|
|
262
|
-
}
|
|
263
|
-
table.appendChild(body);
|
|
264
|
-
article.appendChild(table);
|
|
265
|
-
break;
|
|
266
|
-
}
|
|
267
|
-
case "rule":
|
|
268
|
-
article.appendChild(document.createElement("hr"));
|
|
269
|
-
break;
|
|
270
|
-
}
|
|
271
|
-
}
|
|
272
|
-
return article;
|
|
273
|
-
}
|
|
274
|
-
|
|
275
191
|
async function renderSpecEvidence(content, dagRunId, nodeId) {
|
|
276
192
|
const evidence = await fetchJson(
|
|
277
193
|
`/api/dag-runs/${encodeURIComponent(dagRunId)}/nodes/${encodeURIComponent(nodeId)}/spec-evidence`,
|
|
@@ -392,33 +308,35 @@ async function renderSpecEvidence(content, dagRunId, nodeId) {
|
|
|
392
308
|
}
|
|
393
309
|
}
|
|
394
310
|
|
|
395
|
-
function fillDagInspectorContent(content, dagRunId, node) {
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
311
|
+
function fillDagInspectorContent(content, dagRunId, node) {
|
|
312
|
+
const activeTab = ["timeline", "spec-evidence"].includes(
|
|
313
|
+
uiState.dagInspectorTab,
|
|
314
|
+
)
|
|
315
|
+
? uiState.dagInspectorTab
|
|
316
|
+
: "output";
|
|
317
|
+
content.id = `dag-inspector-panel-${activeTab}`;
|
|
318
|
+
content.setAttribute("role", "tabpanel");
|
|
319
|
+
content.setAttribute("aria-labelledby", `dag-inspector-tab-${activeTab}`);
|
|
320
|
+
content.dataset.dagNodeId = String(node.nodeId ?? "");
|
|
321
|
+
// Drop timeline-only classes when switching tabs so output layout stays clean.
|
|
322
|
+
content.className = "dag-inspector-content";
|
|
323
|
+
if (activeTab === "spec-evidence") {
|
|
324
|
+
void renderSpecEvidence(content, dagRunId, node.nodeId);
|
|
325
|
+
} else if (activeTab === "timeline") {
|
|
326
|
+
renderSessionTimeline(content, node.nodeId);
|
|
327
|
+
} else if (!node.outputPreview && !node.errorPreview) {
|
|
328
|
+
content.appendChild(el("p", "empty", UI_TEXT.noOutput));
|
|
329
|
+
} else {
|
|
330
|
+
if (node.outputPreview)
|
|
331
|
+
content.appendChild(renderMarkdown(node.outputPreview));
|
|
332
|
+
if (node.errorPreview) {
|
|
333
|
+
const error = el("section", "markdown-error");
|
|
334
|
+
error.appendChild(el("p", "markdown-error-title", "错误输出"));
|
|
335
|
+
error.appendChild(renderMarkdown(node.errorPreview));
|
|
336
|
+
content.appendChild(error);
|
|
337
|
+
}
|
|
419
338
|
}
|
|
420
339
|
}
|
|
421
|
-
}
|
|
422
340
|
|
|
423
341
|
function buildDagInspectorHeader(dagRunId, node) {
|
|
424
342
|
const header = el("div", "dag-inspector-header");
|
|
@@ -468,7 +386,7 @@ function buildDagInspectorHeader(dagRunId, node) {
|
|
|
468
386
|
button.appendChild(document.createTextNode(` ${label}`));
|
|
469
387
|
button.addEventListener("click", () => {
|
|
470
388
|
uiState.dagInspectorTab = tab;
|
|
471
|
-
|
|
389
|
+
renderDagInspectorForCurrent();
|
|
472
390
|
const next = document.getElementById(`dag-inspector-tab-${tab}`);
|
|
473
391
|
next?.focus();
|
|
474
392
|
});
|
|
@@ -482,7 +400,7 @@ function buildDagInspectorHeader(dagRunId, node) {
|
|
|
482
400
|
const delta = event.key === "ArrowRight" ? 1 : -1;
|
|
483
401
|
const nextTab = order[(idx + delta + order.length) % order.length];
|
|
484
402
|
uiState.dagInspectorTab = nextTab;
|
|
485
|
-
|
|
403
|
+
renderDagInspectorForCurrent();
|
|
486
404
|
document.getElementById(`dag-inspector-tab-${nextTab}`)?.focus();
|
|
487
405
|
});
|
|
488
406
|
tabs.appendChild(button);
|
|
@@ -523,6 +441,11 @@ function dagInspectorSignature(dagRunId, node) {
|
|
|
523
441
|
}
|
|
524
442
|
|
|
525
443
|
export function renderDagInspector(dagRunId, node, initial = true) {
|
|
444
|
+
// Record the current selection before any early-return so tab handlers
|
|
445
|
+
// (which reference the mutable inspectorSelection slot) always re-render
|
|
446
|
+
// the currently selected node, never a stale build-time closure.
|
|
447
|
+
inspectorSelection.dagRunId = dagRunId;
|
|
448
|
+
inspectorSelection.node = node;
|
|
526
449
|
const panel = document.getElementById("dag-inspector");
|
|
527
450
|
if (!panel) return;
|
|
528
451
|
captureDagTimelineViewportState(panel);
|
|
@@ -60,6 +60,7 @@ import {
|
|
|
60
60
|
shouldPreserveDiagnosticsOpen,
|
|
61
61
|
renderViewState,
|
|
62
62
|
mountViewState,
|
|
63
|
+
makeSessionEventIdentity,
|
|
63
64
|
} from "../state.js";
|
|
64
65
|
import { uiState, dagGraphViewportStates } from "../state.js";
|
|
65
66
|
import { sortPoolTasks } from "../format-pool.js";
|
|
@@ -104,6 +105,7 @@ export async function renderDagDetail(dagRunId, initial = true) {
|
|
|
104
105
|
uiState.selectedDagNodeId = null;
|
|
105
106
|
uiState.sessionEventOffset = 0;
|
|
106
107
|
uiState.sessionEvents = [];
|
|
108
|
+
uiState.sessionEventIdentity = null;
|
|
107
109
|
uiState.dagInspectorOpen = false;
|
|
108
110
|
uiState.dagInspectorTab = "output";
|
|
109
111
|
uiState.dagGraphViewportState = null;
|
|
@@ -168,6 +170,7 @@ export async function renderDagDetail(dagRunId, initial = true) {
|
|
|
168
170
|
if (initial) {
|
|
169
171
|
uiState.sessionEventOffset = 0;
|
|
170
172
|
uiState.sessionEvents = [];
|
|
173
|
+
uiState.sessionEventIdentity = null;
|
|
171
174
|
}
|
|
172
175
|
}
|
|
173
176
|
|
|
@@ -336,6 +339,12 @@ export async function renderDagDetail(dagRunId, initial = true) {
|
|
|
336
339
|
nodesEl.scrollLeft = nodesScrollLeft;
|
|
337
340
|
|
|
338
341
|
if (uiState.dagInspectorOpen && uiState.selectedDagNodeId) {
|
|
342
|
+
if (!uiState.sessionEventIdentity) {
|
|
343
|
+
uiState.sessionEventIdentity = makeSessionEventIdentity(
|
|
344
|
+
dagRunId,
|
|
345
|
+
uiState.selectedDagNodeId,
|
|
346
|
+
);
|
|
347
|
+
}
|
|
339
348
|
await mergeSessionEvents(dagRunId, uiState.selectedDagNodeId);
|
|
340
349
|
}
|
|
341
350
|
renderDagInspector(
|