@tea-agent/loop-agent 0.7.5 → 0.8.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 +143 -142
- package/CHANGELOG.md +148 -164
- package/README.md +206 -204
- package/bin/agent-worker.js +22 -22
- package/bin/loop-agent.js +21 -21
- package/dist/commands/init.js +518 -488
- package/dist/commands/loop-benchmark.js +11 -11
- package/dist/commands/pi-reuse-benchmark.js +16 -16
- package/dist/executors/cursor-executor.js +1 -1
- package/dist/governance/manifest-types.js +1 -1
- package/dist/task/runtime.js +27 -27
- package/dist/worker/cli.js +3 -3
- package/dist/worker/observability/event-store.js +2 -1
- package/dist/worker/observability/read-model.js +13 -11
- package/dist/worker/observe/paths.js +2 -2
- package/dist/worker/observe/routes.js +4 -3
- package/dist/worker/observe/static/app.js +1479 -1480
- package/dist/worker/observe/static/dag-layout.d.ts +31 -31
- package/dist/worker/observe/static/dag-layout.js +83 -83
- package/dist/worker/observe/static/index.html +63 -63
- package/dist/worker/observe/static/styles.css +722 -722
- package/dist/worker/pool/run-store.js +7 -8
- package/dist/worker/run-task/run-task.js +11 -2
- package/dist/worker/runner/run-ready.js +1 -1
- package/dist/workflows/dag/canvas-observer.js +275 -275
- package/docs/README.md +80 -79
- package/docs/agent-dag-recovery-playbook.md +184 -184
- package/docs/agent-dag-runner.md +42 -42
- package/docs/architecture/runtime-boundaries.md +162 -162
- package/docs/cursor-executor-usage.md +25 -25
- package/docs/decisions/README.md +3 -3
- package/docs/design/README.md +49 -49
- package/docs/development-principles.md +73 -73
- package/docs/dynamic-workflow-dag-engine-roadmap.md +1749 -1749
- package/docs/exec-plans/README.md +6 -6
- package/docs/exec-plans/active/README.md +11 -11
- package/docs/exec-plans/completed/README.md +35 -34
- package/docs/feature-workflow.md +187 -187
- package/docs/harness-methodology-debugging.md +153 -153
- package/docs/harness-methodology-tdd.md +130 -130
- package/docs/harness-methodology-verification.md +27 -27
- package/docs/init-surface.manifest.json +245 -241
- package/docs/loop-agent-harness.md +63 -55
- package/docs/production-readiness.md +96 -96
- package/docs/progress/README.md +3 -3
- package/docs/reports/README.md +9 -9
- package/docs/skills/README.md +6 -6
- package/docs/skills/vetted-skill-registry.md +26 -26
- package/docs/templates/adr.md +60 -60
- package/docs/templates/agent-dag-authority-surface-audit.prompt.md +94 -94
- package/docs/templates/agent-dag-decision-envelope.schema.json +213 -213
- package/docs/templates/agent-dag-decision-gate-dogfood-report.md +117 -117
- package/docs/templates/agent-dag-decision-gate.prompt.md +246 -246
- package/docs/templates/agent-dag-process-supervisor.prompt.md +98 -98
- package/docs/templates/agent-dag-report.schema.json +454 -454
- package/docs/templates/agent-dag-review-verdict.prompt.md +68 -68
- package/docs/templates/agent-dag.base.json +195 -195
- package/docs/templates/agent-dag.final-verification.json +190 -190
- package/docs/templates/agent-dag.schema.json +316 -316
- package/docs/templates/agent-dag.supervised-implementation.json +500 -500
- package/docs/templates/exec-plan.md +64 -64
- package/docs/templates/feature-spec.md +53 -53
- package/docs/templates/harness.schema.json +218 -0
- package/docs/templates/hybrid-dag.json +193 -193
- package/docs/templates/init-evolution-review.md +33 -33
- package/docs/templates/interactive-ui-round2-experiment.md +66 -66
- package/docs/templates/product-line/AGENTS.md +8 -8
- package/docs/templates/product-line/README.md +9 -9
- package/docs/templates/product-line/acceptance.yaml +14 -14
- package/docs/templates/product-line/closeout.yaml +9 -9
- package/docs/templates/product-line/design.md +13 -13
- package/docs/templates/product-line/links.md +10 -10
- package/docs/templates/product-line/requirement.md +17 -17
- package/docs/templates/product-line/task-graph.yaml +15 -15
- package/docs/templates/product-line/task.yaml +65 -65
- package/docs/templates/product-line/test-plan.md +7 -7
- package/docs/templates/production-readiness-checklist.md +57 -57
- package/docs/templates/progress-log.md +17 -17
- package/docs/templates/project-start-checklist.md +9 -9
- package/docs/templates/qa-report.md +48 -48
- package/docs/templates/sprint-contract.md +29 -29
- package/docs/templates/worker-dogfood-evidence.md +52 -52
- package/docs/templates/worker-dogfood-setup.md +48 -48
- package/docs/verification-matrix.md +49 -49
- package/examples/decision-gate-agent-dag.json +123 -123
- package/examples/example-dag.json +51 -51
- package/examples/hybrid-loop-agent-dag.json +194 -194
- package/harness.json +73 -71
- package/package.json +68 -67
- package/scripts/check-product-line-docs.sh +22 -22
- package/scripts/check-task-pool-root.sh +32 -0
- package/skills/ai-engineering-context/SKILL.md +48 -48
- package/skills/code-review-core/SKILL.md +20 -20
- package/skills/codebase-scout/SKILL.md +19 -19
- package/skills/init-capability-evolution/SKILL.md +69 -69
- package/skills/loop-agent/SKILL.md +149 -149
- package/skills/loop-agent/references/README.md +67 -67
- package/skills/loop-agent/references/command-reference.md +432 -412
- package/skills/loop-agent/references/harness-policy.md +263 -263
- package/skills/loop-agent/references/hybrid-dag.md +216 -216
- package/skills/loop-agent/references/learned/README.md +21 -21
- package/skills/loop-agent/references/long-running-loop.md +59 -59
- package/skills/loop-agent/references/model-routing.md +36 -36
- package/skills/loop-agent/references/multi-worktree.md +54 -54
- package/skills/loop-agent/references/one-shot-runs.md +85 -85
- package/skills/loop-agent/references/orchestrator-and-interventions.md +169 -169
- package/skills/loop-agent/references/pi-prompt.md +23 -23
- package/skills/loop-agent/references/pi-subagent-assisted-mode.md +81 -81
- package/skills/loop-agent/references/post-implementation-and-patterns.md +44 -44
- package/skills/loop-agent/references/task-workflow.md +89 -89
- package/skills/loop-agent/references/verification-and-failure-handling.md +128 -128
- package/skills/requesting-code-review/SKILL.md +101 -101
- package/skills/requesting-code-review/code-reviewer.md +168 -168
- package/skills/systematic-debugging/CREATION-LOG.md +119 -119
- package/skills/systematic-debugging/SKILL.md +296 -296
- package/skills/systematic-debugging/condition-based-waiting-example.ts +158 -158
- package/skills/systematic-debugging/condition-based-waiting.md +115 -115
- package/skills/systematic-debugging/defense-in-depth.md +122 -122
- package/skills/systematic-debugging/find-polluter.sh +63 -63
- package/skills/systematic-debugging/root-cause-tracing.md +169 -169
- package/skills/systematic-debugging/test-academic.md +14 -14
- package/skills/systematic-debugging/test-pressure-1.md +58 -58
- package/skills/systematic-debugging/test-pressure-2.md +68 -68
- package/skills/systematic-debugging/test-pressure-3.md +69 -69
- package/skills/test-driven-development/SKILL.md +20 -20
- package/skills/verification-before-completion/SKILL.md +154 -154
- package/skills/webapp-testing/SKILL.md +19 -19
|
@@ -1,31 +1,31 @@
|
|
|
1
|
-
export type DagLayoutNodeInput = { nodeId: string };
|
|
2
|
-
export type DagLayoutEdgeInput = { from: string; to: string };
|
|
3
|
-
export type DagLayoutNode = {
|
|
4
|
-
nodeId: string;
|
|
5
|
-
rank: number;
|
|
6
|
-
index: number;
|
|
7
|
-
x: number;
|
|
8
|
-
y: number;
|
|
9
|
-
width: number;
|
|
10
|
-
height: number;
|
|
11
|
-
};
|
|
12
|
-
export type DagLayoutEdge = DagLayoutEdgeInput & { path: string };
|
|
13
|
-
export type DagLayout = {
|
|
14
|
-
width: number;
|
|
15
|
-
height: number;
|
|
16
|
-
nodes: DagLayoutNode[];
|
|
17
|
-
edges: DagLayoutEdge[];
|
|
18
|
-
};
|
|
19
|
-
|
|
20
|
-
export function layoutDag(
|
|
21
|
-
nodes?: DagLayoutNodeInput[],
|
|
22
|
-
edges?: DagLayoutEdgeInput[],
|
|
23
|
-
ranks?: string[][],
|
|
24
|
-
options?: Partial<{
|
|
25
|
-
nodeWidth: number;
|
|
26
|
-
nodeHeight: number;
|
|
27
|
-
rankGap: number;
|
|
28
|
-
nodeGap: number;
|
|
29
|
-
padding: number;
|
|
30
|
-
}>,
|
|
31
|
-
): DagLayout;
|
|
1
|
+
export type DagLayoutNodeInput = { nodeId: string };
|
|
2
|
+
export type DagLayoutEdgeInput = { from: string; to: string };
|
|
3
|
+
export type DagLayoutNode = {
|
|
4
|
+
nodeId: string;
|
|
5
|
+
rank: number;
|
|
6
|
+
index: number;
|
|
7
|
+
x: number;
|
|
8
|
+
y: number;
|
|
9
|
+
width: number;
|
|
10
|
+
height: number;
|
|
11
|
+
};
|
|
12
|
+
export type DagLayoutEdge = DagLayoutEdgeInput & { path: string };
|
|
13
|
+
export type DagLayout = {
|
|
14
|
+
width: number;
|
|
15
|
+
height: number;
|
|
16
|
+
nodes: DagLayoutNode[];
|
|
17
|
+
edges: DagLayoutEdge[];
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export function layoutDag(
|
|
21
|
+
nodes?: DagLayoutNodeInput[],
|
|
22
|
+
edges?: DagLayoutEdgeInput[],
|
|
23
|
+
ranks?: string[][],
|
|
24
|
+
options?: Partial<{
|
|
25
|
+
nodeWidth: number;
|
|
26
|
+
nodeHeight: number;
|
|
27
|
+
rankGap: number;
|
|
28
|
+
nodeGap: number;
|
|
29
|
+
padding: number;
|
|
30
|
+
}>,
|
|
31
|
+
): DagLayout;
|
|
@@ -1,83 +1,83 @@
|
|
|
1
|
-
const DEFAULTS = {
|
|
2
|
-
nodeWidth: 216,
|
|
3
|
-
nodeHeight: 92,
|
|
4
|
-
rankGap: 104,
|
|
5
|
-
nodeGap: 28,
|
|
6
|
-
padding: 32,
|
|
7
|
-
};
|
|
8
|
-
|
|
9
|
-
export function layoutDag(nodes = [], edges = [], ranks = [], options = {}) {
|
|
10
|
-
const config = { ...DEFAULTS, ...options };
|
|
11
|
-
const nodeIds = [...new Set(nodes.map((node) => node.nodeId).filter(Boolean))].sort();
|
|
12
|
-
if (nodeIds.length === 0) return { width: 320, height: 160, nodes: [], edges: [] };
|
|
13
|
-
const known = new Set(nodeIds);
|
|
14
|
-
const validEdges = edges
|
|
15
|
-
.filter((edge) => known.has(edge.from) && known.has(edge.to) && edge.from !== edge.to)
|
|
16
|
-
.sort((a, b) => a.from.localeCompare(b.from) || a.to.localeCompare(b.to));
|
|
17
|
-
const layers = normalizeLayers(nodeIds, validEdges, ranks);
|
|
18
|
-
const positioned = [];
|
|
19
|
-
for (let rank = 0; rank < layers.length; rank++) {
|
|
20
|
-
const ids = layers[rank];
|
|
21
|
-
for (let index = 0; index < ids.length; index++) {
|
|
22
|
-
positioned.push({
|
|
23
|
-
nodeId: ids[index], rank, index,
|
|
24
|
-
x: config.padding + rank * (config.nodeWidth + config.rankGap),
|
|
25
|
-
y: config.padding + index * (config.nodeHeight + config.nodeGap),
|
|
26
|
-
width: config.nodeWidth, height: config.nodeHeight,
|
|
27
|
-
});
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
const byId = new Map(positioned.map((node) => [node.nodeId, node]));
|
|
31
|
-
const routed = validEdges.map((edge) => {
|
|
32
|
-
const from = byId.get(edge.from);
|
|
33
|
-
const to = byId.get(edge.to);
|
|
34
|
-
const x1 = from.x + from.width;
|
|
35
|
-
const y1 = from.y + from.height / 2;
|
|
36
|
-
const x2 = to.x;
|
|
37
|
-
const y2 = to.y + to.height / 2;
|
|
38
|
-
const bend = Math.max(36, (x2 - x1) / 2);
|
|
39
|
-
return { ...edge, path: `M ${x1} ${y1} C ${x1 + bend} ${y1}, ${x2 - bend} ${y2}, ${x2} ${y2}` };
|
|
40
|
-
});
|
|
41
|
-
const maxRows = Math.max(...layers.map((layer) => layer.length), 1);
|
|
42
|
-
return {
|
|
43
|
-
width: config.padding * 2 + layers.length * config.nodeWidth + (layers.length - 1) * config.rankGap,
|
|
44
|
-
height: config.padding * 2 + maxRows * config.nodeHeight + (maxRows - 1) * config.nodeGap,
|
|
45
|
-
nodes: positioned,
|
|
46
|
-
edges: routed,
|
|
47
|
-
};
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
function normalizeLayers(nodeIds, edges, ranks) {
|
|
51
|
-
const known = new Set(nodeIds);
|
|
52
|
-
const seen = new Set();
|
|
53
|
-
const layers = [];
|
|
54
|
-
if (Array.isArray(ranks)) {
|
|
55
|
-
for (const rank of ranks) {
|
|
56
|
-
if (!Array.isArray(rank)) continue;
|
|
57
|
-
const ids = [...new Set(rank.filter((id) => known.has(id) && !seen.has(id)))].sort();
|
|
58
|
-
ids.forEach((id) => seen.add(id));
|
|
59
|
-
if (ids.length > 0) layers.push(ids);
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
if (layers.length === 0 && edges.length > 0) {
|
|
63
|
-
const level = new Map(nodeIds.map((id) => [id, 0]));
|
|
64
|
-
for (let pass = 0; pass < nodeIds.length; pass++) {
|
|
65
|
-
let changed = false;
|
|
66
|
-
for (const edge of edges) {
|
|
67
|
-
const next = Math.min(nodeIds.length - 1, level.get(edge.from) + 1);
|
|
68
|
-
if (next > level.get(edge.to)) { level.set(edge.to, next); changed = true; }
|
|
69
|
-
}
|
|
70
|
-
if (!changed) break;
|
|
71
|
-
}
|
|
72
|
-
for (const id of nodeIds) {
|
|
73
|
-
const rank = level.get(id);
|
|
74
|
-
(layers[rank] ??= []).push(id);
|
|
75
|
-
seen.add(id);
|
|
76
|
-
}
|
|
77
|
-
for (const layer of layers) layer?.sort();
|
|
78
|
-
}
|
|
79
|
-
for (const id of nodeIds) {
|
|
80
|
-
if (!seen.has(id)) (layers[0] ??= []).push(id);
|
|
81
|
-
}
|
|
82
|
-
return layers.filter(Boolean);
|
|
83
|
-
}
|
|
1
|
+
const DEFAULTS = {
|
|
2
|
+
nodeWidth: 216,
|
|
3
|
+
nodeHeight: 92,
|
|
4
|
+
rankGap: 104,
|
|
5
|
+
nodeGap: 28,
|
|
6
|
+
padding: 32,
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
export function layoutDag(nodes = [], edges = [], ranks = [], options = {}) {
|
|
10
|
+
const config = { ...DEFAULTS, ...options };
|
|
11
|
+
const nodeIds = [...new Set(nodes.map((node) => node.nodeId).filter(Boolean))].sort();
|
|
12
|
+
if (nodeIds.length === 0) return { width: 320, height: 160, nodes: [], edges: [] };
|
|
13
|
+
const known = new Set(nodeIds);
|
|
14
|
+
const validEdges = edges
|
|
15
|
+
.filter((edge) => known.has(edge.from) && known.has(edge.to) && edge.from !== edge.to)
|
|
16
|
+
.sort((a, b) => a.from.localeCompare(b.from) || a.to.localeCompare(b.to));
|
|
17
|
+
const layers = normalizeLayers(nodeIds, validEdges, ranks);
|
|
18
|
+
const positioned = [];
|
|
19
|
+
for (let rank = 0; rank < layers.length; rank++) {
|
|
20
|
+
const ids = layers[rank];
|
|
21
|
+
for (let index = 0; index < ids.length; index++) {
|
|
22
|
+
positioned.push({
|
|
23
|
+
nodeId: ids[index], rank, index,
|
|
24
|
+
x: config.padding + rank * (config.nodeWidth + config.rankGap),
|
|
25
|
+
y: config.padding + index * (config.nodeHeight + config.nodeGap),
|
|
26
|
+
width: config.nodeWidth, height: config.nodeHeight,
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
const byId = new Map(positioned.map((node) => [node.nodeId, node]));
|
|
31
|
+
const routed = validEdges.map((edge) => {
|
|
32
|
+
const from = byId.get(edge.from);
|
|
33
|
+
const to = byId.get(edge.to);
|
|
34
|
+
const x1 = from.x + from.width;
|
|
35
|
+
const y1 = from.y + from.height / 2;
|
|
36
|
+
const x2 = to.x;
|
|
37
|
+
const y2 = to.y + to.height / 2;
|
|
38
|
+
const bend = Math.max(36, (x2 - x1) / 2);
|
|
39
|
+
return { ...edge, path: `M ${x1} ${y1} C ${x1 + bend} ${y1}, ${x2 - bend} ${y2}, ${x2} ${y2}` };
|
|
40
|
+
});
|
|
41
|
+
const maxRows = Math.max(...layers.map((layer) => layer.length), 1);
|
|
42
|
+
return {
|
|
43
|
+
width: config.padding * 2 + layers.length * config.nodeWidth + (layers.length - 1) * config.rankGap,
|
|
44
|
+
height: config.padding * 2 + maxRows * config.nodeHeight + (maxRows - 1) * config.nodeGap,
|
|
45
|
+
nodes: positioned,
|
|
46
|
+
edges: routed,
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function normalizeLayers(nodeIds, edges, ranks) {
|
|
51
|
+
const known = new Set(nodeIds);
|
|
52
|
+
const seen = new Set();
|
|
53
|
+
const layers = [];
|
|
54
|
+
if (Array.isArray(ranks)) {
|
|
55
|
+
for (const rank of ranks) {
|
|
56
|
+
if (!Array.isArray(rank)) continue;
|
|
57
|
+
const ids = [...new Set(rank.filter((id) => known.has(id) && !seen.has(id)))].sort();
|
|
58
|
+
ids.forEach((id) => seen.add(id));
|
|
59
|
+
if (ids.length > 0) layers.push(ids);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
if (layers.length === 0 && edges.length > 0) {
|
|
63
|
+
const level = new Map(nodeIds.map((id) => [id, 0]));
|
|
64
|
+
for (let pass = 0; pass < nodeIds.length; pass++) {
|
|
65
|
+
let changed = false;
|
|
66
|
+
for (const edge of edges) {
|
|
67
|
+
const next = Math.min(nodeIds.length - 1, level.get(edge.from) + 1);
|
|
68
|
+
if (next > level.get(edge.to)) { level.set(edge.to, next); changed = true; }
|
|
69
|
+
}
|
|
70
|
+
if (!changed) break;
|
|
71
|
+
}
|
|
72
|
+
for (const id of nodeIds) {
|
|
73
|
+
const rank = level.get(id);
|
|
74
|
+
(layers[rank] ??= []).push(id);
|
|
75
|
+
seen.add(id);
|
|
76
|
+
}
|
|
77
|
+
for (const layer of layers) layer?.sort();
|
|
78
|
+
}
|
|
79
|
+
for (const id of nodeIds) {
|
|
80
|
+
if (!seen.has(id)) (layers[0] ??= []).push(id);
|
|
81
|
+
}
|
|
82
|
+
return layers.filter(Boolean);
|
|
83
|
+
}
|
|
@@ -1,63 +1,63 @@
|
|
|
1
|
-
<!DOCTYPE html>
|
|
2
|
-
<html lang="zh-CN">
|
|
3
|
-
<head>
|
|
4
|
-
<meta charset="UTF-8">
|
|
5
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
-
<title>
|
|
7
|
-
<link rel="stylesheet" href="/styles.css">
|
|
8
|
-
</head>
|
|
9
|
-
<body>
|
|
10
|
-
<div id="app">
|
|
11
|
-
<header class="site-header">
|
|
12
|
-
<a href="#/" class="logo">
|
|
13
|
-
<nav class="top-nav">
|
|
14
|
-
<a href="#/" class="nav-link">总览</a>
|
|
15
|
-
<a href="#/dags" class="nav-link">DAG</a>
|
|
16
|
-
<a href="#/failures" class="nav-link"
|
|
17
|
-
</nav>
|
|
18
|
-
<span id="header-refresh" class="header-refresh"></span>
|
|
19
|
-
<nav id="breadcrumb" class="breadcrumb"></nav>
|
|
20
|
-
</header>
|
|
21
|
-
|
|
22
|
-
<section data-view="dashboard" id="view-dashboard">
|
|
23
|
-
<h2>总览</h2>
|
|
24
|
-
<div id="dashboard-kpi" class="kpi-grid panel"></div>
|
|
25
|
-
<div id="dashboard-active-dags" class="panel"></div>
|
|
26
|
-
<div id="dashboard-dags" class="panel"></div>
|
|
27
|
-
<div id="dashboard-batches" class="panel"></div>
|
|
28
|
-
</section>
|
|
29
|
-
|
|
30
|
-
<section data-view="batch" id="view-batch" hidden>
|
|
31
|
-
<h2>批次详情</h2>
|
|
32
|
-
<div id="batch-meta" class="panel"></div>
|
|
33
|
-
<div id="batch-tasks" class="panel"></div>
|
|
34
|
-
</section>
|
|
35
|
-
|
|
36
|
-
<section data-view="run" id="view-run" hidden>
|
|
37
|
-
<h2>运行详情</h2>
|
|
38
|
-
<div id="run-meta" class="panel"></div>
|
|
39
|
-
<div id="run-dag-progress" class="panel"></div>
|
|
40
|
-
<div id="run-steps" class="panel"></div>
|
|
41
|
-
<div id="run-command" class="panel"></div>
|
|
42
|
-
<div id="run-output" class="panel"></div>
|
|
43
|
-
<div id="run-artifacts" class="panel"></div>
|
|
44
|
-
</section>
|
|
45
|
-
|
|
46
|
-
<section data-view="dag" id="view-dag" hidden>
|
|
47
|
-
<h2>DAG 详情</h2>
|
|
48
|
-
<div id="dag-meta" class="panel"></div>
|
|
49
|
-
<div id="dag-ranks" class="panel"></div>
|
|
50
|
-
<div id="dag-nodes" class="panel"></div>
|
|
51
|
-
<div id="dag-timeline" class="panel"></div>
|
|
52
|
-
<div id="dag-output" class="panel"></div>
|
|
53
|
-
</section>
|
|
54
|
-
|
|
55
|
-
<section data-view="failures" id="view-failures" hidden>
|
|
56
|
-
<h2
|
|
57
|
-
<div id="failures-empty" class="panel" hidden
|
|
58
|
-
<div id="failures-list" class="panel"></div>
|
|
59
|
-
</section>
|
|
60
|
-
</div>
|
|
61
|
-
<script type="module" src="/app.js"></script>
|
|
62
|
-
</body>
|
|
63
|
-
</html>
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="zh-CN">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>Loop Agent运行看板</title>
|
|
7
|
+
<link rel="stylesheet" href="/styles.css">
|
|
8
|
+
</head>
|
|
9
|
+
<body>
|
|
10
|
+
<div id="app">
|
|
11
|
+
<header class="site-header">
|
|
12
|
+
<a href="#/" class="logo">Loop Agent运行看板</a>
|
|
13
|
+
<nav class="top-nav">
|
|
14
|
+
<a href="#/" class="nav-link">总览</a>
|
|
15
|
+
<a href="#/dags" class="nav-link">DAG</a>
|
|
16
|
+
<a href="#/failures" class="nav-link">异常 Task</a>
|
|
17
|
+
</nav>
|
|
18
|
+
<span id="header-refresh" class="header-refresh"></span>
|
|
19
|
+
<nav id="breadcrumb" class="breadcrumb"></nav>
|
|
20
|
+
</header>
|
|
21
|
+
|
|
22
|
+
<section data-view="dashboard" id="view-dashboard">
|
|
23
|
+
<h2>总览</h2>
|
|
24
|
+
<div id="dashboard-kpi" class="kpi-grid panel"></div>
|
|
25
|
+
<div id="dashboard-active-dags" class="panel"></div>
|
|
26
|
+
<div id="dashboard-dags" class="panel"></div>
|
|
27
|
+
<div id="dashboard-batches" class="panel"></div>
|
|
28
|
+
</section>
|
|
29
|
+
|
|
30
|
+
<section data-view="batch" id="view-batch" hidden>
|
|
31
|
+
<h2>批次详情</h2>
|
|
32
|
+
<div id="batch-meta" class="panel"></div>
|
|
33
|
+
<div id="batch-tasks" class="panel"></div>
|
|
34
|
+
</section>
|
|
35
|
+
|
|
36
|
+
<section data-view="run" id="view-run" hidden>
|
|
37
|
+
<h2>运行详情</h2>
|
|
38
|
+
<div id="run-meta" class="panel"></div>
|
|
39
|
+
<div id="run-dag-progress" class="panel"></div>
|
|
40
|
+
<div id="run-steps" class="panel"></div>
|
|
41
|
+
<div id="run-command" class="panel"></div>
|
|
42
|
+
<div id="run-output" class="panel"></div>
|
|
43
|
+
<div id="run-artifacts" class="panel"></div>
|
|
44
|
+
</section>
|
|
45
|
+
|
|
46
|
+
<section data-view="dag" id="view-dag" hidden>
|
|
47
|
+
<h2>DAG 详情</h2>
|
|
48
|
+
<div id="dag-meta" class="panel"></div>
|
|
49
|
+
<div id="dag-ranks" class="panel"></div>
|
|
50
|
+
<div id="dag-nodes" class="panel"></div>
|
|
51
|
+
<div id="dag-timeline" class="panel"></div>
|
|
52
|
+
<div id="dag-output" class="panel"></div>
|
|
53
|
+
</section>
|
|
54
|
+
|
|
55
|
+
<section data-view="failures" id="view-failures" hidden>
|
|
56
|
+
<h2>异常 Task</h2>
|
|
57
|
+
<div id="failures-empty" class="panel" hidden>当前没有异常 Task</div>
|
|
58
|
+
<div id="failures-list" class="panel"></div>
|
|
59
|
+
</section>
|
|
60
|
+
</div>
|
|
61
|
+
<script type="module" src="/app.js"></script>
|
|
62
|
+
</body>
|
|
63
|
+
</html>
|