@tea-agent/loop-agent 0.9.0 → 0.10.0-alpha.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 +8 -0
- package/CHANGELOG.md +92 -11
- package/README.md +69 -5
- package/dist/application/dag/args.js +4 -14
- package/dist/application/dag/generate-task-dag.js +32 -2
- package/dist/application/dag/run-dag.js +1 -27
- package/dist/application/dag/validate-dag.js +2 -2
- package/dist/application/loop/run-action.js +0 -4
- package/dist/cli/command-definitions.js +7 -11
- package/dist/cli/program.js +9 -21
- package/dist/commands/cursor-prompt.js +42 -82
- package/dist/commands/dag-approve.js +36 -0
- package/dist/commands/dag-reconcile-run.js +118 -0
- package/dist/commands/delegate.js +75 -77
- package/dist/commands/doctor.js +0 -18
- package/dist/commands/init.js +60 -40
- package/dist/commands/instructions.js +7 -10
- package/dist/commands/loop.js +4 -20
- package/dist/executors/config-core.js +0 -51
- package/dist/executors/dag-pi-executor.js +1 -1
- package/dist/executors/dag.js +0 -1
- package/dist/executors/index.js +0 -2
- package/dist/executors/model-routing.js +9 -9
- package/dist/executors/shell-executor.js +1 -1
- package/dist/governance/checks.js +6 -3
- package/dist/governance/manifest-types.js +33 -2
- package/dist/infrastructure/harness/loop-action-store.js +0 -3
- package/dist/records/harvest.js +2 -23
- package/dist/records/one-shot-runs.js +1 -1
- package/dist/shared/artifacts-core.js +24 -5
- package/dist/shared/output-truncation.js +37 -0
- package/dist/shared/package-metadata.js +353 -0
- package/dist/{executors/cursor-executor.js → sidecars/cursor-prompt/executor.js} +2 -42
- package/dist/sidecars/cursor-prompt/index.js +3 -0
- package/dist/sidecars/cursor-prompt/stream.js +121 -0
- package/dist/task/config-types.js +29 -12
- package/dist/task/delegate.js +9 -21
- package/dist/task/runtime.js +1 -2
- package/dist/worker/cli.js +243 -0
- package/dist/worker/closeout/apply.js +73 -0
- package/dist/worker/closeout/preview.js +30 -0
- package/dist/worker/delivery/final-verification.js +194 -0
- package/dist/worker/delivery/git-transaction.js +354 -0
- package/dist/worker/delivery/package.js +502 -0
- package/dist/worker/feature/decision-loader.js +68 -0
- package/dist/worker/feature/discover.js +14 -0
- package/dist/worker/feature/next-action.js +74 -0
- package/dist/worker/feature/reducer.js +133 -0
- package/dist/worker/feature/review.js +502 -0
- package/dist/worker/feature/run.js +365 -0
- package/dist/worker/feature/types.js +1 -0
- package/dist/worker/follow-up/approve.js +270 -0
- package/dist/worker/follow-up/factory.js +234 -0
- package/dist/worker/follow-up/paths.js +25 -0
- package/dist/worker/follow-up/policy.js +26 -0
- package/dist/worker/follow-up/schema.js +93 -0
- package/dist/worker/follow-up/store.js +96 -0
- package/dist/worker/loop-agent/loop-agent-client.js +329 -126
- package/dist/worker/metrics/projector.js +139 -0
- package/dist/worker/observability/read-model.js +282 -15
- package/dist/worker/observe/paths.js +17 -5
- package/dist/worker/observe/static/app.js +443 -61
- package/dist/worker/observe/static/index.html +3 -1
- package/dist/worker/observe/static/styles.css +85 -18
- package/dist/worker/pool/run-store.js +14 -2
- package/dist/worker/pool/validation.js +59 -0
- package/dist/worker/preflight.js +49 -1
- package/dist/worker/report/morning-report.js +41 -6
- package/dist/worker/run-task/run-task.js +23 -13
- package/dist/worker/runner/run-ready.js +89 -11
- package/dist/worker/task-spec/schema.js +0 -1
- package/dist/workflows/dag/convergence/controller.js +1 -1
- package/dist/workflows/dag/executor-registry.js +0 -2
- package/dist/workflows/dag/governance-profile.js +10 -0
- package/dist/workflows/dag/init-hybrid.js +601 -26
- package/dist/workflows/dag/lifecycle.js +146 -0
- package/dist/workflows/dag/node-execution.js +64 -7
- package/dist/workflows/dag/prompt.js +16 -0
- package/dist/workflows/dag/report.js +2 -0
- package/dist/workflows/dag/runner.js +176 -119
- package/dist/workflows/dag/scheduler.js +7 -2
- package/dist/workflows/dag/skill-snapshot.js +527 -0
- package/dist/workflows/dag/types.js +45 -9
- package/dist/workflows/dag/validate.js +5 -8
- package/dist/workflows/loop/actions/dag-action.js +0 -2
- package/dist/workflows/loop/actions/shared.js +1 -1
- package/dist/workflows/loop/actions.js +14 -31
- package/dist/workflows/loop/benchmark.js +1 -1
- package/dist/workflows/loop/index.js +1 -1
- package/dist/workflows/loop/policy/auto-policy.js +22 -14
- package/dist/workflows/loop/policy/path-patterns.js +13 -0
- package/docs/README.md +35 -16
- package/docs/agent-dag-recovery-playbook.md +1 -1
- package/docs/architecture/README.md +26 -0
- package/docs/architecture/dag-execution.md +134 -0
- package/docs/architecture/evolution.md +52 -0
- package/docs/architecture/facts-and-state.md +58 -0
- package/docs/architecture/runtime-boundaries.md +41 -15
- package/docs/architecture/system-overview.md +93 -0
- package/docs/architecture/worker-and-feature.md +81 -0
- package/docs/cursor-prompt-sidecar.md +36 -0
- package/docs/decisions/README.md +13 -1
- package/docs/design/README.md +39 -13
- package/docs/development-principles.md +1 -1
- package/docs/exec-plans/active/README.md +2 -2
- package/docs/exec-plans/completed/README.md +14 -1
- package/docs/feature-workflow.md +44 -4
- package/docs/init-surface.manifest.json +63 -1
- package/docs/loop-agent-harness.md +65 -3
- package/docs/progress/README.md +27 -0
- package/docs/reports/README.md +74 -8
- package/docs/skills/README.md +2 -1
- package/docs/skills/vetted-skill-registry.md +2 -1
- package/docs/templates/agent-dag-report.schema.json +4 -2
- package/docs/templates/agent-dag.base.json +0 -5
- package/docs/templates/agent-dag.final-verification.json +0 -5
- package/docs/templates/agent-dag.schema.json +1 -2
- package/docs/templates/agent-dag.supervised-implementation.json +1 -6
- package/docs/templates/backend-test-dag.generate-pytest.prompt.md +131 -0
- package/docs/templates/backend-test-dag.json +213 -0
- package/docs/templates/backend-test-dag.retrospect.prompt.md +128 -0
- package/docs/templates/backend-test-dag.review-cases.prompt.md +85 -0
- package/docs/templates/frontend-design-contract.md +33 -0
- package/docs/templates/frontend-task-constraints.md +25 -0
- package/docs/templates/frontend-task-requirement.md +61 -0
- package/docs/templates/harness.schema.json +8 -5
- package/docs/templates/hybrid-dag.json +1 -6
- package/docs/templates/init-evolution-review.md +4 -2
- package/docs/templates/interactive-ui-round2-experiment.md +1 -1
- package/docs/templates/product-line/task.yaml +0 -1
- package/docs/templates/worker-dogfood-evidence.md +28 -0
- package/docs/templates/worker-dogfood-setup.md +20 -0
- package/docs/verification-matrix.md +17 -0
- package/examples/decision-gate-agent-dag.json +87 -33
- package/examples/example-dag.json +0 -5
- package/examples/hybrid-loop-agent-dag.json +0 -5
- package/harness.json +6 -11
- package/package.json +22 -44
- package/scripts/check-product-line-docs.sh +10 -3
- package/skills/agent-worker/SKILL.md +37 -0
- package/skills/agent-worker/references/agent-worker-operator.md +43 -0
- package/skills/frontend-design-review/SKILL.md +59 -0
- package/skills/frontend-design-review/references/review-checklist.md +37 -0
- package/skills/frontend-implementation/SKILL.md +48 -0
- package/skills/frontend-implementation/references/code-standards.md +34 -0
- package/skills/frontend-implementation/references/design-spec.md +46 -0
- package/skills/frontend-implementation/references/node-contracts.md +32 -0
- package/skills/frontend-review/SKILL.md +53 -0
- package/skills/frontend-review/references/review-findings.md +42 -0
- package/skills/frontend-verification/SKILL.md +40 -0
- package/skills/frontend-verification/references/verification-checklist.md +56 -0
- package/skills/grill-me/SKILL.md +10 -0
- package/skills/grill-with-docs/SKILL.md +88 -0
- package/skills/grill-with-docs/adr-format.md +47 -0
- package/skills/grill-with-docs/context-format.md +60 -0
- package/skills/init-capability-evolution/SKILL.md +1 -0
- package/skills/loop-agent/SKILL.md +11 -9
- package/skills/loop-agent/references/command-reference.md +28 -15
- package/skills/loop-agent/references/docs-converge.md +126 -0
- package/skills/loop-agent/references/harness-policy.md +7 -7
- package/skills/loop-agent/references/hybrid-dag.md +13 -15
- package/skills/loop-agent/references/long-running-loop.md +4 -6
- package/skills/loop-agent/references/multi-worktree.md +6 -6
- package/skills/loop-agent/references/orchestrator-and-interventions.md +3 -3
- package/skills/loop-agent/references/pi-subagent-assisted-mode.md +14 -11
- package/skills/using-git-worktrees/SKILL.md +215 -0
- package/dist/commands/cursor-worker.js +0 -43
- package/dist/cursor-worker-entry.js +0 -8
- package/dist/executors/cursor-artifacts.js +0 -33
- package/dist/executors/cursor-execution-log.js +0 -81
- package/dist/executors/cursor-executor-artifacts.js +0 -134
- package/dist/executors/cursor-run.js +0 -115
- package/dist/executors/cursor-tool.js +0 -94
- package/dist/executors/cursor-worker-client.js +0 -223
- package/dist/executors/cursor-worker-protocol.js +0 -18
- package/dist/executors/cursor-worker-server.js +0 -54
- package/dist/executors/cursor-worker.js +0 -3
- package/dist/executors/cursor.js +0 -6
- package/dist/executors/dag-cursor-executor.js +0 -87
- package/dist/workflows/loop/actions/cursor-fix.js +0 -191
- package/dist/workflows/loop/policy/cursor-fix-policy.js +0 -31
- package/docs/cursor-executor-usage.md +0 -25
- package/docs/dynamic-workflow-dag-engine-roadmap.md +0 -1749
|
@@ -35,7 +35,9 @@
|
|
|
35
35
|
<h2>运行总览</h2>
|
|
36
36
|
<p>聚焦正在推进的 DAG、需要处理的风险与近期运行记录。</p>
|
|
37
37
|
</div>
|
|
38
|
-
<
|
|
38
|
+
<div id="dashboard-repo" class="repo-banner" aria-label="当前仓库"></div>
|
|
39
|
+
<section id="dashboard-features" class="panel panel-features" aria-label="Feature 决策"></section>
|
|
40
|
+
<section id="dashboard-kpi" class="panel panel-kpi" aria-label="运行摘要"></section>
|
|
39
41
|
<div class="dashboard-workspace">
|
|
40
42
|
<section id="dashboard-active-dags" class="panel panel-primary"></section>
|
|
41
43
|
<aside id="dashboard-risk" class="panel panel-risk" aria-label="运行风险"></aside>
|
|
@@ -238,12 +238,22 @@ td:first-child,
|
|
|
238
238
|
|
|
239
239
|
.view-dashboard { display: grid; gap: var(--space-4); }
|
|
240
240
|
|
|
241
|
+
.repo-banner { display: flex; align-items: center; gap: var(--space-3); padding: 10px 14px; border: 1px solid var(--hairline-strong); border-radius: var(--radius-lg); background: var(--surface); }
|
|
242
|
+
.repo-banner > i { color: var(--muted); font-size: 18px; }
|
|
243
|
+
.repo-banner-text { display: grid; gap: 2px; min-width: 0; }
|
|
244
|
+
.repo-banner-name { color: var(--ink); font-size: 14px; font-weight: 700; overflow-wrap: anywhere; }
|
|
245
|
+
.repo-banner-path { color: var(--muted); font-size: 11px; overflow-wrap: anywhere; }
|
|
246
|
+
|
|
241
247
|
.panel-kpi { padding: 0; background: transparent; border: 0; }
|
|
242
248
|
|
|
249
|
+
.kpi-group { margin: 0; padding: 0; border: 0; display: grid; gap: var(--space-3); }
|
|
250
|
+
.kpi-group + .kpi-group { margin-top: var(--space-3); }
|
|
251
|
+
.kpi-group-legend { padding: 0; color: var(--muted); font-size: 11px; font-weight: 700; letter-spacing: .04em; text-transform: uppercase; }
|
|
252
|
+
|
|
243
253
|
.kpi-grid {
|
|
244
254
|
display: grid;
|
|
245
255
|
grid-template-columns: repeat(6, minmax(0, 1fr));
|
|
246
|
-
overflow:
|
|
256
|
+
overflow: visible;
|
|
247
257
|
border: 1px solid var(--hairline-strong);
|
|
248
258
|
border-radius: var(--radius-lg);
|
|
249
259
|
background: var(--surface);
|
|
@@ -259,8 +269,15 @@ td:first-child,
|
|
|
259
269
|
|
|
260
270
|
.kpi-card:first-child { border-left: 0; }
|
|
261
271
|
.kpi-label { margin-bottom: 9px; color: var(--muted); font-size: 11px; font-weight: 650; }
|
|
272
|
+
.kpi-value-row { display: flex; align-items: baseline; gap: 6px; }
|
|
262
273
|
.kpi-value { color: var(--ink); font-size: 26px; font-weight: 500; line-height: 1; font-variant-numeric: tabular-nums; }
|
|
263
274
|
|
|
275
|
+
.kpi-help { display: inline-flex; align-items: center; justify-content: center; width: 16px; height: 16px; padding: 0; border: 0; border-radius: 50%; background: transparent; color: var(--muted-soft); cursor: help; font-size: 13px; line-height: 1; }
|
|
276
|
+
.kpi-help:hover, .kpi-help:focus-visible { color: var(--ink); background: var(--surface-muted); outline: none; }
|
|
277
|
+
.kpi-help:focus-visible { box-shadow: 0 0 0 2px var(--hairline-strong); }
|
|
278
|
+
.kpi-tip { position: absolute; left: 12px; right: 12px; top: calc(100% - 8px); z-index: 10; max-width: 280px; padding: 8px 10px; border: 1px solid var(--hairline-strong); border-radius: var(--radius-md); background: var(--surface-ink); color: var(--canvas); font-size: 11px; font-weight: 400; line-height: 1.5; box-shadow: var(--shadow-panel); opacity: 0; visibility: hidden; pointer-events: none; transition: opacity var(--transition-fast); }
|
|
279
|
+
.kpi-help:hover + .kpi-tip, .kpi-help:focus-visible + .kpi-tip { opacity: 1; visibility: visible; }
|
|
280
|
+
|
|
264
281
|
.dashboard-workspace,
|
|
265
282
|
.dashboard-secondary {
|
|
266
283
|
display: grid;
|
|
@@ -272,19 +289,29 @@ td:first-child,
|
|
|
272
289
|
.dashboard-secondary { grid-template-columns: repeat(2, minmax(0, 1fr)); }
|
|
273
290
|
|
|
274
291
|
.panel-risk {
|
|
275
|
-
display:
|
|
276
|
-
grid-template-columns: minmax(130px, .28fr) minmax(0, 1fr) auto;
|
|
277
|
-
align-items: center;
|
|
278
|
-
gap: var(--space-4);
|
|
292
|
+
display: block;
|
|
279
293
|
background: var(--canvas-soft);
|
|
280
294
|
}
|
|
281
295
|
|
|
282
296
|
.panel-risk-attention { border-color: color-mix(in srgb, var(--red) 50%, var(--hairline)); background: #fff8f9; }
|
|
283
|
-
.panel-risk .section-heading { margin: 0; }
|
|
284
|
-
.risk-
|
|
297
|
+
.panel-risk .section-heading { margin: 0 0 var(--space-3); }
|
|
298
|
+
.risk-blocks { display: grid; gap: var(--space-4); }
|
|
299
|
+
.risk-block { display: grid; grid-template-columns: minmax(120px, .25fr) minmax(0, 1fr); align-items: start; gap: var(--space-3); padding-top: var(--space-3); border-top: 1px solid var(--hairline); }
|
|
300
|
+
.risk-block:first-child { padding-top: 0; border-top: 0; }
|
|
301
|
+
.risk-block-label { color: var(--muted); font-size: 11px; font-weight: 700; letter-spacing: .04em; text-transform: uppercase; }
|
|
302
|
+
.risk-block-dag .risk-block-label { color: var(--ink); }
|
|
303
|
+
.risk-block-worker .risk-block-label { color: var(--ink); }
|
|
304
|
+
.risk-total { margin: 0; color: var(--amber); font-size: 32px; font-weight: 500; line-height: 1; font-variant-numeric: tabular-nums; }
|
|
285
305
|
.panel-risk-attention .risk-total { color: var(--red); }
|
|
286
306
|
.risk-summary { margin: 0; color: var(--body); font-size: 12px; line-height: 1.6; }
|
|
287
|
-
.panel-risk .risk-empty {
|
|
307
|
+
.panel-risk .risk-empty { margin: 0; }
|
|
308
|
+
|
|
309
|
+
.projection-fault { display: flex; align-items: flex-start; gap: var(--space-3); padding: 14px 16px; border: 1px solid color-mix(in srgb, var(--red) 50%, var(--hairline)); border-radius: var(--radius-lg); background: #fff8f9; }
|
|
310
|
+
.projection-fault > i { color: var(--red); font-size: 20px; line-height: 1.4; }
|
|
311
|
+
.projection-fault-body { display: grid; gap: 4px; min-width: 0; }
|
|
312
|
+
.projection-fault-title { margin: 0; color: var(--ink); font-size: 14px; font-weight: 700; }
|
|
313
|
+
.projection-fault-message { margin: 0; color: var(--body); font-size: 12px; overflow-wrap: anywhere; }
|
|
314
|
+
.projection-fault-at { margin: 0; color: var(--muted); font-size: 11px; }
|
|
288
315
|
|
|
289
316
|
.risk-link,
|
|
290
317
|
.active-dag-link,
|
|
@@ -383,7 +410,7 @@ tr.clickable:focus-within { outline: 2px solid var(--orange); outline-offset: -2
|
|
|
383
410
|
bottom: 24px;
|
|
384
411
|
display: grid;
|
|
385
412
|
grid-template-rows: auto minmax(0, 1fr);
|
|
386
|
-
width: min(440px, calc(100vw - 48px));
|
|
413
|
+
width: min(var(--dag-inspector-width, 440px), calc(100vw - 48px));
|
|
387
414
|
min-width: 0;
|
|
388
415
|
padding: 0;
|
|
389
416
|
overflow: hidden;
|
|
@@ -393,9 +420,37 @@ tr.clickable:focus-within { outline: 2px solid var(--orange); outline-offset: -2
|
|
|
393
420
|
pointer-events: none;
|
|
394
421
|
transform: translateX(calc(100% + 24px));
|
|
395
422
|
visibility: hidden;
|
|
396
|
-
transition: transform var(--transition-base), opacity var(--transition-base);
|
|
423
|
+
transition: transform var(--transition-base), opacity var(--transition-base), visibility 0s linear 240ms;
|
|
424
|
+
}
|
|
425
|
+
.dag-inspector.is-open { opacity: 1; pointer-events: auto; transform: translateX(0); visibility: visible; transition-delay: 0s, 0s, 0s; }
|
|
426
|
+
.dag-inspector-resize-handle {
|
|
427
|
+
position: absolute;
|
|
428
|
+
z-index: 1;
|
|
429
|
+
top: 0;
|
|
430
|
+
bottom: 0;
|
|
431
|
+
left: 0;
|
|
432
|
+
width: 18px;
|
|
433
|
+
cursor: col-resize;
|
|
434
|
+
touch-action: none;
|
|
435
|
+
outline: none;
|
|
436
|
+
}
|
|
437
|
+
.dag-inspector-resize-handle::before {
|
|
438
|
+
content: "";
|
|
439
|
+
position: absolute;
|
|
440
|
+
top: 50%;
|
|
441
|
+
left: 7px;
|
|
442
|
+
width: 3px;
|
|
443
|
+
height: 52px;
|
|
444
|
+
transform: translateY(-50%);
|
|
445
|
+
border-radius: 2px;
|
|
446
|
+
background: var(--hairline-strong);
|
|
447
|
+
opacity: 0;
|
|
448
|
+
transition: opacity var(--transition-base), background var(--transition-base);
|
|
397
449
|
}
|
|
398
|
-
.dag-inspector
|
|
450
|
+
.dag-inspector-resize-handle:hover::before,
|
|
451
|
+
.dag-inspector-resize-handle:focus-visible::before { background: var(--orange); opacity: 1; }
|
|
452
|
+
.dag-inspector-resize-handle:focus-visible { outline: 2px solid var(--orange); outline-offset: -2px; }
|
|
453
|
+
body.is-resizing-dag-inspector { cursor: col-resize; user-select: none; }
|
|
399
454
|
.dag-inspector-header { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: var(--space-3); align-items: start; padding: var(--space-4) var(--space-4) var(--space-3); border-bottom: 1px solid var(--hairline); background: var(--canvas-soft); }
|
|
400
455
|
.dag-inspector-title { display: grid; gap: 6px; min-width: 0; }
|
|
401
456
|
.dag-inspector-title h3 { margin: 0; font-size: 14px; }
|
|
@@ -489,11 +544,23 @@ tr.clickable:focus-within { outline: 2px solid var(--orange); outline-offset: -2
|
|
|
489
544
|
.rank-node-id { color: var(--ink); font-size: 11px; }
|
|
490
545
|
.rank-node-dur { color: var(--muted); font-size: 11px; }
|
|
491
546
|
|
|
492
|
-
.process-timeline {
|
|
493
|
-
.process-timeline
|
|
494
|
-
.process-timeline-item
|
|
495
|
-
.process-timeline-time {
|
|
496
|
-
.process-timeline-
|
|
547
|
+
.process-timeline-note { margin: 0 0 var(--space-2); color: var(--muted); font-size: 11px; }
|
|
548
|
+
.process-timeline { display: grid; gap: 0; margin: 0; padding: var(--space-2) 0; list-style: none; }
|
|
549
|
+
.process-timeline-item { display: grid; grid-template-columns: 20px minmax(0, 1fr); align-items: stretch; min-height: 34px; }
|
|
550
|
+
.process-timeline-item.has-time { grid-template-columns: 20px 92px minmax(0, 1fr); }
|
|
551
|
+
.process-timeline-rail { position: relative; display: grid; place-items: center; min-height: 34px; }
|
|
552
|
+
.process-timeline-rail::before { position: absolute; top: 0; bottom: 0; width: 1px; background: var(--hairline-strong); content: ""; }
|
|
553
|
+
.process-timeline-item.is-first .process-timeline-rail::before { top: 50%; }
|
|
554
|
+
.process-timeline-item.is-last .process-timeline-rail::before { bottom: 50%; }
|
|
555
|
+
.process-timeline-dot { position: relative; z-index: 1; width: 8px; height: 8px; border: 2px solid var(--surface); border-radius: 50%; background: var(--muted-soft); }
|
|
556
|
+
.process-timeline-lifecycle .process-timeline-dot { background: var(--lavender); }
|
|
557
|
+
.process-timeline-tool-start .process-timeline-dot { background: var(--orange); }
|
|
558
|
+
.process-timeline-tool-end .process-timeline-dot { background: var(--green); }
|
|
559
|
+
.process-timeline-assistant .process-timeline-dot { background: var(--blue); }
|
|
560
|
+
.process-timeline-protocol .process-timeline-dot { background: var(--muted-soft); }
|
|
561
|
+
.process-timeline-time { padding: 9px 0; color: var(--muted); font-size: 10px; font-variant-numeric: tabular-nums; }
|
|
562
|
+
.process-timeline-label { min-width: 0; padding: 8px 0 8px var(--space-2); color: var(--body); font-size: 12px; line-height: 1.5; overflow-wrap: anywhere; }
|
|
563
|
+
.process-timeline-protocol .process-timeline-label { color: var(--muted); font-size: 11px; }
|
|
497
564
|
|
|
498
565
|
.markdown-output { display: grid; gap: var(--space-3); color: var(--body); font-size: 13px; line-height: 1.65; }
|
|
499
566
|
.markdown-output > :first-child { margin-top: 0; }
|
|
@@ -579,9 +646,9 @@ tr.clickable:focus-within { outline: 2px solid var(--orange); outline-offset: -2
|
|
|
579
646
|
.kpi-card:nth-child(1), .kpi-card:nth-child(2) { border-top: 0; }
|
|
580
647
|
.kpi-card:nth-child(odd) { border-left: 0; }
|
|
581
648
|
.dag-inspector { top: 76px; right: 12px; bottom: 12px; width: calc(100vw - 24px); }
|
|
649
|
+
.dag-inspector-resize-handle { display: none; }
|
|
582
650
|
.dashboard-secondary { grid-template-columns: 1fr; }
|
|
583
|
-
.
|
|
584
|
-
.panel-risk .risk-empty { grid-column: auto; }
|
|
651
|
+
.risk-block { grid-template-columns: 1fr; gap: var(--space-2); }
|
|
585
652
|
.panel { padding: var(--space-4); }
|
|
586
653
|
.panel-table { overflow-x: auto; padding: 0; }
|
|
587
654
|
table { min-width: 680px; }
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
import { appendFile, mkdir, readFile, readdir, rename, unlink, writeFile } from "node:fs/promises";
|
|
2
3
|
import path from "node:path";
|
|
3
4
|
export const TASK_POOL_RELATIVE_ROOT = ".harness/task-pool";
|
|
4
5
|
export function getTaskPoolRoot(repoRoot) {
|
|
@@ -19,6 +20,10 @@ export async function recordTaskPoolRun(input) {
|
|
|
19
20
|
await writeTaskPoolState(input.repoRoot, stateFromRun(input.run));
|
|
20
21
|
await appendJsonlFile(getEventsJsonlPath(input.repoRoot), eventFromRun(input.run));
|
|
21
22
|
}
|
|
23
|
+
export async function appendTaskPoolEvent(repoRoot, event) {
|
|
24
|
+
await ensurePoolDirs(repoRoot);
|
|
25
|
+
await appendJsonlFile(getEventsJsonlPath(repoRoot), event);
|
|
26
|
+
}
|
|
22
27
|
export async function findRunByWorkerRunId(repoRoot, workerRunId) {
|
|
23
28
|
const runs = await readJsonlFile(getRunsJsonlPath(repoRoot));
|
|
24
29
|
return runs.find((run) => run.workerRunId === workerRunId);
|
|
@@ -99,7 +104,14 @@ export async function readAllTaskPoolStates(repoRoot) {
|
|
|
99
104
|
export async function writeTaskPoolState(repoRoot, state) {
|
|
100
105
|
const statePath = getTaskStatePath(repoRoot, state.taskId);
|
|
101
106
|
await mkdir(path.dirname(statePath), { recursive: true });
|
|
102
|
-
|
|
107
|
+
const tempPath = path.join(path.dirname(statePath), `.${path.basename(statePath)}.${randomUUID()}.tmp`);
|
|
108
|
+
try {
|
|
109
|
+
await writeFile(tempPath, `${JSON.stringify({ schemaVersion: 1, ...state }, null, 2)}\n`, "utf-8");
|
|
110
|
+
await rename(tempPath, statePath);
|
|
111
|
+
}
|
|
112
|
+
finally {
|
|
113
|
+
await unlink(tempPath).catch(() => { });
|
|
114
|
+
}
|
|
103
115
|
}
|
|
104
116
|
export async function readJsonlFile(filePath) {
|
|
105
117
|
try {
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { readFile, readdir } from "node:fs/promises";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { getRunsJsonlPath, getTaskPoolRoot } from "./run-store.js";
|
|
5
|
+
export const taskPoolRunFactSchema = z.object({
|
|
6
|
+
schemaVersion: z.literal(1), batchRunId: z.string().min(1), workerRunId: z.string().min(1), taskId: z.string().min(1), featureId: z.string().min(1),
|
|
7
|
+
status: z.enum(["succeeded", "failed", "run-error"]), recordedAt: z.string().datetime(),
|
|
8
|
+
}).passthrough();
|
|
9
|
+
export const taskPoolStateFactSchema = z.object({
|
|
10
|
+
taskId: z.string().min(1), status: z.enum(["Draft", "Ready", "Queued", "Running", "AgentCompleted", "VerificationRunning", "HumanReview", "Done", "Failed", "Blocked", "Abandoned"]), updatedAt: z.string().datetime(),
|
|
11
|
+
}).passthrough();
|
|
12
|
+
export async function readValidTaskPoolRuns(repoRoot) {
|
|
13
|
+
const records = [];
|
|
14
|
+
const warnings = [];
|
|
15
|
+
try {
|
|
16
|
+
const raw = await readFile(getRunsJsonlPath(repoRoot), "utf-8");
|
|
17
|
+
for (const [index, line] of raw.split(/\r?\n/).filter(Boolean).entries())
|
|
18
|
+
try {
|
|
19
|
+
const parsed = taskPoolRunFactSchema.safeParse(JSON.parse(line));
|
|
20
|
+
if (parsed.success)
|
|
21
|
+
records.push(parsed.data);
|
|
22
|
+
else
|
|
23
|
+
warnings.push(`Task Pool runs.jsonl line ${index + 1} is semantically invalid`);
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
warnings.push(`Task Pool runs.jsonl line ${index + 1} is corrupt`);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
catch (error) {
|
|
30
|
+
if (!isNotFound(error))
|
|
31
|
+
warnings.push("Task Pool runs.jsonl is unreadable");
|
|
32
|
+
}
|
|
33
|
+
return { records, warnings };
|
|
34
|
+
}
|
|
35
|
+
export async function readValidTaskPoolStates(repoRoot) {
|
|
36
|
+
const records = {};
|
|
37
|
+
const warnings = [];
|
|
38
|
+
const stateDir = path.join(getTaskPoolRoot(repoRoot), "states");
|
|
39
|
+
try {
|
|
40
|
+
for (const entry of await readdir(stateDir))
|
|
41
|
+
if (entry.endsWith(".json"))
|
|
42
|
+
try {
|
|
43
|
+
const parsed = taskPoolStateFactSchema.safeParse(JSON.parse(await readFile(path.join(stateDir, entry), "utf-8")));
|
|
44
|
+
if (parsed.success && parsed.data.taskId === entry.slice(0, -5))
|
|
45
|
+
records[parsed.data.taskId] = parsed.data;
|
|
46
|
+
else
|
|
47
|
+
warnings.push(`Task Pool state is semantically invalid: ${entry}`);
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
warnings.push(`Task Pool state is corrupt: ${entry}`);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
catch (error) {
|
|
54
|
+
if (!isNotFound(error))
|
|
55
|
+
warnings.push("Task Pool states are unreadable");
|
|
56
|
+
}
|
|
57
|
+
return { records, warnings };
|
|
58
|
+
}
|
|
59
|
+
function isNotFound(error) { return Boolean(error && typeof error === "object" && "code" in error && error.code === "ENOENT"); }
|
package/dist/worker/preflight.js
CHANGED
|
@@ -1,14 +1,27 @@
|
|
|
1
1
|
import { access } from "node:fs/promises";
|
|
2
2
|
import path from "node:path";
|
|
3
|
+
import { controllerIdentityExpectationFailure, resolveControllerIdentity, } from "./loop-agent/loop-agent-client.js";
|
|
3
4
|
export const DEFAULT_CHECK_REPO_TIMEOUT_MS = 300_000;
|
|
4
5
|
export async function preflightTargetRepo(input) {
|
|
5
6
|
const commands = [];
|
|
7
|
+
const identity = resolveControllerIdentity(input.client);
|
|
8
|
+
const expectationFailure = controllerIdentityExpectationFailure(identity, input.expectation);
|
|
9
|
+
if (expectationFailure) {
|
|
10
|
+
return {
|
|
11
|
+
ok: false,
|
|
12
|
+
code: expectationFailure.code,
|
|
13
|
+
message: expectationFailure.message,
|
|
14
|
+
commands,
|
|
15
|
+
controllerIdentity: identity,
|
|
16
|
+
};
|
|
17
|
+
}
|
|
6
18
|
if (!(await exists(path.join(input.repoRoot, "harness.json")))) {
|
|
7
19
|
return {
|
|
8
20
|
ok: false,
|
|
9
21
|
code: "target-not-initialized",
|
|
10
22
|
message: "target repo is missing harness.json",
|
|
11
23
|
commands,
|
|
24
|
+
controllerIdentity: identity,
|
|
12
25
|
};
|
|
13
26
|
}
|
|
14
27
|
if (!(await exists(path.join(input.repoRoot, ".harness")))) {
|
|
@@ -17,6 +30,7 @@ export async function preflightTargetRepo(input) {
|
|
|
17
30
|
code: "target-not-initialized",
|
|
18
31
|
message: "target repo is missing .harness",
|
|
19
32
|
commands,
|
|
33
|
+
controllerIdentity: identity,
|
|
20
34
|
};
|
|
21
35
|
}
|
|
22
36
|
const version = await input.client.run(["--version"], {
|
|
@@ -30,8 +44,36 @@ export async function preflightTargetRepo(input) {
|
|
|
30
44
|
code: "version-failed",
|
|
31
45
|
message: "loop-agent --version failed",
|
|
32
46
|
commands,
|
|
47
|
+
controllerIdentity: identity,
|
|
33
48
|
};
|
|
34
49
|
}
|
|
50
|
+
const reportedVersion = version.stdout.trim();
|
|
51
|
+
let controllerIdentity = identity
|
|
52
|
+
? { ...identity, reportedVersion }
|
|
53
|
+
: undefined;
|
|
54
|
+
if (identity && reportedVersion !== identity.packageVersion) {
|
|
55
|
+
return {
|
|
56
|
+
ok: false,
|
|
57
|
+
code: "reported-version-mismatch",
|
|
58
|
+
message: `reported version ${reportedVersion} does not match package version ${identity.packageVersion}`,
|
|
59
|
+
commands,
|
|
60
|
+
controllerIdentity,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
if (identity && input.client.observeReportedVersion) {
|
|
64
|
+
try {
|
|
65
|
+
controllerIdentity = input.client.observeReportedVersion(reportedVersion) ?? controllerIdentity;
|
|
66
|
+
}
|
|
67
|
+
catch (error) {
|
|
68
|
+
return {
|
|
69
|
+
ok: false,
|
|
70
|
+
code: "reported-version-mismatch",
|
|
71
|
+
message: error instanceof Error ? error.message : String(error),
|
|
72
|
+
commands,
|
|
73
|
+
controllerIdentity,
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
}
|
|
35
77
|
const inspect = await input.client.run(["inspect"], {
|
|
36
78
|
cwd: input.repoRoot,
|
|
37
79
|
artifactName: "inspect",
|
|
@@ -44,6 +86,7 @@ export async function preflightTargetRepo(input) {
|
|
|
44
86
|
code: "inspect-failed",
|
|
45
87
|
message: "loop-agent inspect failed or did not return JSON",
|
|
46
88
|
commands,
|
|
89
|
+
controllerIdentity,
|
|
47
90
|
};
|
|
48
91
|
}
|
|
49
92
|
const docsAudit = await input.client.run(["docs", "audit"], {
|
|
@@ -57,6 +100,7 @@ export async function preflightTargetRepo(input) {
|
|
|
57
100
|
code: "docs-audit-failed",
|
|
58
101
|
message: "loop-agent docs audit failed",
|
|
59
102
|
commands,
|
|
103
|
+
controllerIdentity,
|
|
60
104
|
};
|
|
61
105
|
}
|
|
62
106
|
const gitStatus = await input.client.runExternal("git", ["status", "--short", "--branch"], {
|
|
@@ -70,6 +114,7 @@ export async function preflightTargetRepo(input) {
|
|
|
70
114
|
code: "git-status-failed",
|
|
71
115
|
message: "git status --short --branch failed",
|
|
72
116
|
commands,
|
|
117
|
+
controllerIdentity,
|
|
73
118
|
};
|
|
74
119
|
}
|
|
75
120
|
if (input.runCheckRepo) {
|
|
@@ -86,15 +131,18 @@ export async function preflightTargetRepo(input) {
|
|
|
86
131
|
code: "check-repo-failed",
|
|
87
132
|
message: `${[command, ...args].join(" ")} failed`,
|
|
88
133
|
commands,
|
|
134
|
+
controllerIdentity,
|
|
89
135
|
};
|
|
90
136
|
}
|
|
91
137
|
}
|
|
92
138
|
return {
|
|
93
139
|
ok: true,
|
|
94
|
-
version:
|
|
140
|
+
version: reportedVersion,
|
|
141
|
+
reportedVersion: controllerIdentity?.reportedVersion,
|
|
95
142
|
inspect: inspect.json,
|
|
96
143
|
gitStatus: gitStatus.stdout,
|
|
97
144
|
commands,
|
|
145
|
+
controllerIdentity,
|
|
98
146
|
};
|
|
99
147
|
}
|
|
100
148
|
async function exists(filePath) {
|
|
@@ -1,17 +1,30 @@
|
|
|
1
|
-
import { access, writeFile, mkdir } from "node:fs/promises";
|
|
1
|
+
import { access, writeFile, mkdir, readFile } from "node:fs/promises";
|
|
2
2
|
import path from "node:path";
|
|
3
|
-
import
|
|
3
|
+
import YAML from "yaml";
|
|
4
|
+
import { followUpActionCardSchema } from "../follow-up/schema.js";
|
|
5
|
+
import { readFollowUpIndex, resolveRepoFile } from "../follow-up/store.js";
|
|
6
|
+
import { loadFeatureDecisionModels } from "../feature/decision-loader.js";
|
|
7
|
+
import { readValidTaskPoolRuns, readValidTaskPoolStates } from "../pool/validation.js";
|
|
4
8
|
export async function renderMorningReport(options) {
|
|
5
|
-
const
|
|
9
|
+
const { features } = await loadFeatureDecisionModels(options.repoRoot);
|
|
10
|
+
const allRuns = (await readValidTaskPoolRuns(options.repoRoot)).records;
|
|
11
|
+
const runs = allRuns.filter((run) => !options.batchRunId || run.batchRunId === options.batchRunId);
|
|
6
12
|
const total = runs.length;
|
|
7
13
|
const succeeded = runs.filter((run) => run.status === "succeeded").length;
|
|
8
14
|
const failed = runs.filter((run) => run.status === "failed").length;
|
|
9
15
|
const followUps = runs.filter((run) => run.failure).length;
|
|
10
|
-
const states = await
|
|
16
|
+
const states = (await readValidTaskPoolStates(options.repoRoot)).records;
|
|
11
17
|
const blocked = Object.values(states).filter((state) => state.status === "Blocked").length;
|
|
12
18
|
const lines = [
|
|
13
19
|
"# Nightly Worker Report",
|
|
14
20
|
"",
|
|
21
|
+
"## Feature Decision Summary",
|
|
22
|
+
"",
|
|
23
|
+
...(features.length === 0 ? ["- Status: no Feature Packet discovered", "- Next Action: add or locate a Feature Packet", "- Why: no shared Feature read model is available", "- Evidence: none"] : features.flatMap((feature) => {
|
|
24
|
+
const why = feature.blockingItems[0]?.message ?? `${feature.summary.tasksSucceeded}/${feature.summary.tasksTotal} tasks; ${feature.summary.requiredAcCovered}/${feature.summary.requiredAcTotal} required AC`;
|
|
25
|
+
const evidence = [feature.evidence.delivery, feature.evidence.closeout, feature.evidence.morningReport, feature.evidence.observeSnapshot, ...feature.blockingItems.flatMap((item) => item.evidence)].find(Boolean) ?? "none";
|
|
26
|
+
return [`### ${feature.featureId}`, "", `- Status: ${feature.status}`, `- Next Action: ${feature.nextAction?.command ?? feature.nextAction?.label ?? "none"}`, `- Why: ${why}`, `- Evidence: ${evidence}`, ""];
|
|
27
|
+
})),
|
|
15
28
|
"## Summary",
|
|
16
29
|
"",
|
|
17
30
|
`- Total: ${total}`,
|
|
@@ -26,16 +39,38 @@ export async function renderMorningReport(options) {
|
|
|
26
39
|
"|---|---|---|---|---|---|",
|
|
27
40
|
];
|
|
28
41
|
for (const run of runs) {
|
|
29
|
-
|
|
42
|
+
const followUp = await followUpSummary(run, options.repoRoot);
|
|
43
|
+
lines.push(`| ${run.taskId} | ${run.status} | ${run.workerRunId} | ${run.failure?.category ?? "-"} | ${followUp ?? run.failure?.derivedFollowUpTaskId ?? "-"} | ${await artifactSummary(run)} |`);
|
|
30
44
|
}
|
|
31
45
|
if (followUps > 0) {
|
|
32
46
|
lines.push("", "## Human Actions", "");
|
|
33
47
|
for (const run of runs.filter((candidate) => candidate.failure)) {
|
|
34
|
-
|
|
48
|
+
const followUp = await followUpSummary(run, options.repoRoot);
|
|
49
|
+
lines.push(`- ${followUp ?? `${run.failure?.derivedFollowUpTaskId}: ${run.failure?.recommendedFollowUpKind} for ${run.taskId}`}`);
|
|
35
50
|
}
|
|
36
51
|
}
|
|
37
52
|
return `${lines.join("\n")}\n`;
|
|
38
53
|
}
|
|
54
|
+
async function followUpSummary(run, repoRoot) {
|
|
55
|
+
if (!run.failure)
|
|
56
|
+
return undefined;
|
|
57
|
+
try {
|
|
58
|
+
const index = await readFollowUpIndex(repoRoot, run.featureId);
|
|
59
|
+
const entry = index.entries.find((candidate) => candidate.workerRunId === run.workerRunId && candidate.status !== "Superseded" && candidate.status !== "Rejected");
|
|
60
|
+
if (!entry)
|
|
61
|
+
return undefined;
|
|
62
|
+
if (entry.kind === "TaskDraft") {
|
|
63
|
+
return entry.status === "Approved"
|
|
64
|
+
? `${entry.followUpId}: approved as ${entry.proposedTaskId}`
|
|
65
|
+
: `${entry.followUpId}: approve ${entry.proposedTaskId}`;
|
|
66
|
+
}
|
|
67
|
+
const card = followUpActionCardSchema.parse(YAML.parse(await readFile(await resolveRepoFile(repoRoot, entry.draftPath), "utf-8")));
|
|
68
|
+
return `${entry.followUpId}: ${card.command ?? card.label}`;
|
|
69
|
+
}
|
|
70
|
+
catch {
|
|
71
|
+
return undefined;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
39
74
|
export async function writeMorningReport(input) {
|
|
40
75
|
const markdown = await renderMorningReport(input);
|
|
41
76
|
await mkdir(path.dirname(input.outputPath), { recursive: true });
|
|
@@ -3,12 +3,18 @@ import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import { formatDuration, noopProgressReporter } from "../progress-reporter.js";
|
|
5
5
|
import { redactForPreview, truncatePreview } from "../observability/events.js";
|
|
6
|
+
import { controllerIdentityExpectationFailure, resolveControllerIdentity, } from "../loop-agent/loop-agent-client.js";
|
|
6
7
|
import { materializeTaskSpec, } from "../materialize/harness-task-materializer.js";
|
|
7
8
|
import { preflightTargetRepo } from "../preflight.js";
|
|
8
9
|
import { getTaskPoolRoot } from "../pool/run-store.js";
|
|
9
10
|
export const DEFAULT_RUN_DAG_TIMEOUT_MS = 1_800_000;
|
|
10
11
|
export const MAX_WORKER_TIMEOUT_MS = 7_200_000;
|
|
11
12
|
export async function runTaskSpec(options) {
|
|
13
|
+
let controllerIdentity = resolveControllerIdentity(options.client, options.controllerIdentity);
|
|
14
|
+
const identityFailure = controllerIdentityExpectationFailure(controllerIdentity, options.controllerExpectation);
|
|
15
|
+
if (identityFailure) {
|
|
16
|
+
throw new Error(`${identityFailure.code}: ${identityFailure.message}`);
|
|
17
|
+
}
|
|
12
18
|
const now = options.now ?? new Date();
|
|
13
19
|
const workerRunId = options.workerRunId ?? buildWorkerRunId(options.taskSpec.id, now);
|
|
14
20
|
const commands = [];
|
|
@@ -26,11 +32,13 @@ export async function runTaskSpec(options) {
|
|
|
26
32
|
repoRoot: options.repoRoot,
|
|
27
33
|
client,
|
|
28
34
|
...(typeof options.preflight === "object" ? options.preflight : {}),
|
|
35
|
+
...(options.controllerExpectation ? { expectation: options.controllerExpectation } : {}),
|
|
29
36
|
});
|
|
30
37
|
if (!preflight.ok) {
|
|
31
38
|
progress.note(`preflight FAILED: ${preflight.code}`);
|
|
32
39
|
throw new Error(`target repo preflight failed: ${preflight.code}: ${preflight.message}`);
|
|
33
40
|
}
|
|
41
|
+
controllerIdentity = preflight.controllerIdentity ?? controllerIdentity;
|
|
34
42
|
});
|
|
35
43
|
progress.step(`preflight ok in ${formatDuration(Date.now() - preflightStartedAt)}`);
|
|
36
44
|
}
|
|
@@ -66,7 +74,6 @@ export async function runTaskSpec(options) {
|
|
|
66
74
|
dagPath,
|
|
67
75
|
"--cwd",
|
|
68
76
|
options.repoRoot,
|
|
69
|
-
...noCursorArgs(options.taskSpec),
|
|
70
77
|
], true, undefined, eventCtx);
|
|
71
78
|
});
|
|
72
79
|
progress.step(`dag generated in ${formatDuration(Date.now() - dagGenStartedAt)}`);
|
|
@@ -90,7 +97,6 @@ export async function runTaskSpec(options) {
|
|
|
90
97
|
"--strict-governance",
|
|
91
98
|
"--spine-task",
|
|
92
99
|
materializeManifest.harnessTaskId,
|
|
93
|
-
...forbidCursorArgs(options.taskSpec),
|
|
94
100
|
], true, undefined, eventCtx);
|
|
95
101
|
});
|
|
96
102
|
progress.step(`dag validated in ${formatDuration(Date.now() - validateStartedAt)}`);
|
|
@@ -111,7 +117,6 @@ export async function runTaskSpec(options) {
|
|
|
111
117
|
"--events-jsonl",
|
|
112
118
|
dagEventsPath,
|
|
113
119
|
...maxConcurrentArgs(options.taskSpec),
|
|
114
|
-
...noCursorArgs(options.taskSpec),
|
|
115
120
|
], resolveRunDagTimeoutMs(options.taskSpec), eventCtx);
|
|
116
121
|
});
|
|
117
122
|
progress.step(`run-dag finished in ${formatDuration(Date.now() - runDagStartedAt)}`);
|
|
@@ -156,7 +161,7 @@ export async function runTaskSpec(options) {
|
|
|
156
161
|
taskArtifactsDir,
|
|
157
162
|
eventCtx,
|
|
158
163
|
});
|
|
159
|
-
if (reportDecision.succeeded) {
|
|
164
|
+
if (reportDecision.succeeded && !options.skipSuccessFinalization) {
|
|
160
165
|
await runObservedStep(eventCtx, "promote-run", async () => {
|
|
161
166
|
progress.step("promote run");
|
|
162
167
|
await runRequiredCommand(options.repoRoot, client, "promote-run", ["promote-run", materializeManifest.harnessTaskId, "--run-id", workerRunId], true, undefined, eventCtx);
|
|
@@ -180,6 +185,7 @@ export async function runTaskSpec(options) {
|
|
|
180
185
|
reportDecision,
|
|
181
186
|
commands,
|
|
182
187
|
...(failureArtifacts ? { failureArtifacts } : {}),
|
|
188
|
+
...(controllerIdentity ? { controllerIdentity } : {}),
|
|
183
189
|
};
|
|
184
190
|
await writeFile(runRecordPath, `${JSON.stringify(record, null, 2)}\n`, "utf-8");
|
|
185
191
|
emit(progress, {
|
|
@@ -407,6 +413,12 @@ class RecordingRunTaskClient {
|
|
|
407
413
|
this.delegate = delegate;
|
|
408
414
|
this.records = records;
|
|
409
415
|
}
|
|
416
|
+
getIdentity() {
|
|
417
|
+
return this.delegate.getIdentity?.();
|
|
418
|
+
}
|
|
419
|
+
observeReportedVersion(reportedVersion) {
|
|
420
|
+
return this.delegate.observeReportedVersion?.(reportedVersion);
|
|
421
|
+
}
|
|
410
422
|
async run(args, options) {
|
|
411
423
|
const result = await this.delegate.run(args, options);
|
|
412
424
|
this.records.push({
|
|
@@ -452,6 +464,12 @@ class ObservedRunTaskClient {
|
|
|
452
464
|
this.delegate = delegate;
|
|
453
465
|
this.eventCtx = eventCtx;
|
|
454
466
|
}
|
|
467
|
+
getIdentity() {
|
|
468
|
+
return this.delegate.getIdentity();
|
|
469
|
+
}
|
|
470
|
+
observeReportedVersion(reportedVersion) {
|
|
471
|
+
return this.delegate.observeReportedVersion(reportedVersion);
|
|
472
|
+
}
|
|
455
473
|
run(args, options) {
|
|
456
474
|
return this.runObserved(args, options, (observedOptions) => this.delegate.run(args, observedOptions));
|
|
457
475
|
}
|
|
@@ -544,12 +562,6 @@ function commandRecordName(args, artifactName) {
|
|
|
544
562
|
return "new-task";
|
|
545
563
|
return artifactName;
|
|
546
564
|
}
|
|
547
|
-
function noCursorArgs(taskSpec) {
|
|
548
|
-
return taskSpec.loop_agent.no_cursor ? ["--no-cursor"] : [];
|
|
549
|
-
}
|
|
550
|
-
function forbidCursorArgs(taskSpec) {
|
|
551
|
-
return taskSpec.loop_agent.no_cursor ? ["--forbid-executor", "cursor"] : [];
|
|
552
|
-
}
|
|
553
565
|
function maxConcurrentArgs(taskSpec) {
|
|
554
566
|
return ["--max-concurrent", String(taskSpec.loop_agent.max_concurrent)];
|
|
555
567
|
}
|
|
@@ -563,14 +575,12 @@ function strictModelsArgs(piModel) {
|
|
|
563
575
|
}
|
|
564
576
|
/**
|
|
565
577
|
* Rewrite `executorModels.pi.{LOW,MED,HIGH}` in an already-generated DAG JSON
|
|
566
|
-
* so every pi executor node resolves to the smoke override model.
|
|
567
|
-
* slots are left untouched.
|
|
578
|
+
* so every pi executor node resolves to the smoke override model.
|
|
568
579
|
*/
|
|
569
580
|
export async function applyPiModelOverride(dagPath, piModel) {
|
|
570
581
|
const raw = await readFile(dagPath, "utf-8");
|
|
571
582
|
const spec = JSON.parse(raw);
|
|
572
583
|
spec.executorModels = {
|
|
573
|
-
...(spec.executorModels?.cursor ? { cursor: spec.executorModels.cursor } : {}),
|
|
574
584
|
pi: {
|
|
575
585
|
LOW: piModel,
|
|
576
586
|
MED: piModel,
|