@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
|
@@ -37,17 +37,17 @@ export function parseLoopBenchmarkArgs(args) {
|
|
|
37
37
|
return { json, markdown, outputPath };
|
|
38
38
|
}
|
|
39
39
|
export function printLoopBenchmarkUsage() {
|
|
40
|
-
console.log(`usage: loop-benchmark [options]
|
|
41
|
-
|
|
42
|
-
Deterministic loop-agent loop benchmark baseline (no live Pi/Cursor calls).
|
|
43
|
-
|
|
44
|
-
Options:
|
|
45
|
-
--json Emit JSON (default when no format flag is set)
|
|
46
|
-
--markdown Emit Markdown report
|
|
47
|
-
--output <path> Write Markdown report to a repo-relative or absolute path
|
|
48
|
-
-h, --help Show this help
|
|
49
|
-
|
|
50
|
-
Control groups: single-repair, 3-pass-convergence, 3-pass-convergence+quota.
|
|
40
|
+
console.log(`usage: loop-benchmark [options]
|
|
41
|
+
|
|
42
|
+
Deterministic loop-agent loop benchmark baseline (no live Pi/Cursor calls).
|
|
43
|
+
|
|
44
|
+
Options:
|
|
45
|
+
--json Emit JSON (default when no format flag is set)
|
|
46
|
+
--markdown Emit Markdown report
|
|
47
|
+
--output <path> Write Markdown report to a repo-relative or absolute path
|
|
48
|
+
-h, --help Show this help
|
|
49
|
+
|
|
50
|
+
Control groups: single-repair, 3-pass-convergence, 3-pass-convergence+quota.
|
|
51
51
|
Recommendation never changes convergence.enabled default.`);
|
|
52
52
|
}
|
|
53
53
|
export async function runLoopBenchmark(repoRoot, rawArgs) {
|
|
@@ -106,22 +106,22 @@ export function parsePiReuseBenchmarkArgs(args) {
|
|
|
106
106
|
};
|
|
107
107
|
}
|
|
108
108
|
export function printPiReuseBenchmarkUsage() {
|
|
109
|
-
console.log(`usage: pi-reuse-benchmark [options]
|
|
110
|
-
|
|
111
|
-
Deterministic Pi runtime reuse benchmark/decision summary (no live Pi calls).
|
|
112
|
-
|
|
113
|
-
Options:
|
|
114
|
-
--report <path> Benchmark report markdown (approval status)
|
|
115
|
-
--approval <path> Explicit approval JSON artifact
|
|
116
|
-
--off-executor <path> Baseline executor.jsonl (reuse off)
|
|
117
|
-
--on-executor <path> Treatment executor.jsonl (reuse on)
|
|
118
|
-
--off-task <task-id> Resolve baseline from .harness/tasks/<id>/logs/executor.jsonl
|
|
119
|
-
--on-task <task-id> Resolve treatment from .harness/tasks/<id>/logs/executor.jsonl
|
|
120
|
-
--json Emit JSON (default when no format flag is set)
|
|
121
|
-
--markdown Emit Markdown summary
|
|
122
|
-
-h, --help Show this help
|
|
123
|
-
|
|
124
|
-
Recommendations: defer | maintain-opt-in | eligible-for-human-review
|
|
109
|
+
console.log(`usage: pi-reuse-benchmark [options]
|
|
110
|
+
|
|
111
|
+
Deterministic Pi runtime reuse benchmark/decision summary (no live Pi calls).
|
|
112
|
+
|
|
113
|
+
Options:
|
|
114
|
+
--report <path> Benchmark report markdown (approval status)
|
|
115
|
+
--approval <path> Explicit approval JSON artifact
|
|
116
|
+
--off-executor <path> Baseline executor.jsonl (reuse off)
|
|
117
|
+
--on-executor <path> Treatment executor.jsonl (reuse on)
|
|
118
|
+
--off-task <task-id> Resolve baseline from .harness/tasks/<id>/logs/executor.jsonl
|
|
119
|
+
--on-task <task-id> Resolve treatment from .harness/tasks/<id>/logs/executor.jsonl
|
|
120
|
+
--json Emit JSON (default when no format flag is set)
|
|
121
|
+
--markdown Emit Markdown summary
|
|
122
|
+
-h, --help Show this help
|
|
123
|
+
|
|
124
|
+
Recommendations: defer | maintain-opt-in | eligible-for-human-review
|
|
125
125
|
Never changes CODE_AGENT_PI_REUSE_RUNTIME default (off).`);
|
|
126
126
|
}
|
|
127
127
|
function resolveRepoRelative(repoRoot, filePath) {
|
|
@@ -29,7 +29,7 @@ export function resolveArtifactWriteDir(options) {
|
|
|
29
29
|
}
|
|
30
30
|
export function buildArtifactPathPrompt(writeDir) {
|
|
31
31
|
if (!writeDir)
|
|
32
|
-
return `After changes, write artifacts/修改记录.md and artifacts/验证结果.md with verification evidence.
|
|
32
|
+
return `After changes, write artifacts/修改记录.md and artifacts/验证结果.md with verification evidence.
|
|
33
33
|
${ARTIFACT_INSTRUCTIONS}`;
|
|
34
34
|
return [
|
|
35
35
|
`After changes, write the following files:`,
|
|
@@ -46,7 +46,7 @@ export const workflowPolicySchema = z
|
|
|
46
46
|
.object({
|
|
47
47
|
/** Preferred implementation workflow for recoverable loop-agent work. Declarative policy; callers may still require explicit CLI flags. */
|
|
48
48
|
defaultImplementationWorkflow: z
|
|
49
|
-
.enum(["agent-dag"
|
|
49
|
+
.enum(["agent-dag"])
|
|
50
50
|
.optional()
|
|
51
51
|
.default("agent-dag"),
|
|
52
52
|
dag: z
|
package/dist/task/runtime.js
CHANGED
|
@@ -237,35 +237,35 @@ export function shouldInjectSubagentGuidance(step, mode) {
|
|
|
237
237
|
return false;
|
|
238
238
|
}
|
|
239
239
|
/** Advisory guidance for `analyze-plan` mode. */
|
|
240
|
-
export const SUBAGENT_GUIDANCE_STANDARD = `<subagent_guidance>
|
|
241
|
-
You have access to the \`subagent\` tool for lightweight delegation within this step.
|
|
242
|
-
Use it only for read-only tasks:
|
|
243
|
-
- Parallel scout: dispatch multiple subagents to search/read different areas simultaneously
|
|
244
|
-
- Chain: scout -> planner (one subagent scouts, another plans based on findings)
|
|
245
|
-
- Reviewer: have a subagent review your analysis/plan before finalizing
|
|
246
|
-
Do NOT use subagent for writing, editing, or executing commands.
|
|
247
|
-
Subagent output is advisory only; always verify and incorporate findings into your own output.
|
|
248
|
-
Do NOT treat subagent results as authoritative state or artifact sources.
|
|
240
|
+
export const SUBAGENT_GUIDANCE_STANDARD = `<subagent_guidance>
|
|
241
|
+
You have access to the \`subagent\` tool for lightweight delegation within this step.
|
|
242
|
+
Use it only for read-only tasks:
|
|
243
|
+
- Parallel scout: dispatch multiple subagents to search/read different areas simultaneously
|
|
244
|
+
- Chain: scout -> planner (one subagent scouts, another plans based on findings)
|
|
245
|
+
- Reviewer: have a subagent review your analysis/plan before finalizing
|
|
246
|
+
Do NOT use subagent for writing, editing, or executing commands.
|
|
247
|
+
Subagent output is advisory only; always verify and incorporate findings into your own output.
|
|
248
|
+
Do NOT treat subagent results as authoritative state or artifact sources.
|
|
249
249
|
</subagent_guidance>`;
|
|
250
250
|
/** Strong guidance for `full` mode — prescriptive when to delegate. */
|
|
251
|
-
export const SUBAGENT_GUIDANCE_STRONG = `<subagent_guidance>
|
|
252
|
-
You have access to the \`subagent\` tool for lightweight delegation within this step.
|
|
253
|
-
|
|
254
|
-
You SHOULD delegate to subagent scouts when:
|
|
255
|
-
- The task requires scanning 3+ directories or comparing implementations across modules
|
|
256
|
-
- You would otherwise need 5+ sequential read/grep calls to gather context
|
|
257
|
-
- A reviewer subagent can independently catch scope drift before you finalize your output
|
|
258
|
-
|
|
259
|
-
Delegation saves context tokens and produces better results.
|
|
260
|
-
|
|
261
|
-
Allowed patterns:
|
|
262
|
-
- Parallel scout: dispatch 2-3 subagents simultaneously to cover different file trees
|
|
263
|
-
- Chain: scout -> planner (one subagent scouts, another plans based on findings)
|
|
264
|
-
- Reviewer: have a subagent review your analysis/plan before finalizing
|
|
265
|
-
|
|
266
|
-
Do NOT use subagent for writing, editing, or executing commands.
|
|
267
|
-
Subagent output is advisory only; always verify and incorporate findings into your own output.
|
|
268
|
-
Do NOT treat subagent results as authoritative state or artifact sources.
|
|
251
|
+
export const SUBAGENT_GUIDANCE_STRONG = `<subagent_guidance>
|
|
252
|
+
You have access to the \`subagent\` tool for lightweight delegation within this step.
|
|
253
|
+
|
|
254
|
+
You SHOULD delegate to subagent scouts when:
|
|
255
|
+
- The task requires scanning 3+ directories or comparing implementations across modules
|
|
256
|
+
- You would otherwise need 5+ sequential read/grep calls to gather context
|
|
257
|
+
- A reviewer subagent can independently catch scope drift before you finalize your output
|
|
258
|
+
|
|
259
|
+
Delegation saves context tokens and produces better results.
|
|
260
|
+
|
|
261
|
+
Allowed patterns:
|
|
262
|
+
- Parallel scout: dispatch 2-3 subagents simultaneously to cover different file trees
|
|
263
|
+
- Chain: scout -> planner (one subagent scouts, another plans based on findings)
|
|
264
|
+
- Reviewer: have a subagent review your analysis/plan before finalizing
|
|
265
|
+
|
|
266
|
+
Do NOT use subagent for writing, editing, or executing commands.
|
|
267
|
+
Subagent output is advisory only; always verify and incorporate findings into your own output.
|
|
268
|
+
Do NOT treat subagent results as authoritative state or artifact sources.
|
|
269
269
|
</subagent_guidance>`;
|
|
270
270
|
/** Preserved for backward compatibility (alias of STANDARD). */
|
|
271
271
|
export const SUBAGENT_GUIDANCE = SUBAGENT_GUIDANCE_STANDARD;
|
package/dist/worker/cli.js
CHANGED
|
@@ -13,7 +13,7 @@ import { createCompositeProgressReporter } from "./observability/progress-compos
|
|
|
13
13
|
import { createRoutedWorkerEventStore } from "./observability/event-store.js";
|
|
14
14
|
import { buildGlobalSnapshot } from "./observability/read-model.js";
|
|
15
15
|
import { createObserveServer } from "./observe/server.js";
|
|
16
|
-
import { prepareTaskPoolRetry } from "./pool/run-store.js";
|
|
16
|
+
import { getTaskPoolRoot, prepareTaskPoolRetry } from "./pool/run-store.js";
|
|
17
17
|
import { taskSpecSchema } from "./task-spec/schema.js";
|
|
18
18
|
import { validateTaskSpec } from "./task-spec/validate.js";
|
|
19
19
|
import { validateFeatureTaskGraph } from "./task-graph/validate.js";
|
|
@@ -91,7 +91,7 @@ export function buildAgentWorkerProgram() {
|
|
|
91
91
|
const batchRunId = options.batchRunId ?? buildBatchRunId(new Date());
|
|
92
92
|
const client = new LoopAgentClient({
|
|
93
93
|
loopAgentBin: options.loopAgentBin,
|
|
94
|
-
artifactRoot: path.join(repoRoot, "
|
|
94
|
+
artifactRoot: path.join(getTaskPoolRoot(repoRoot), "artifacts", batchRunId),
|
|
95
95
|
});
|
|
96
96
|
let progress;
|
|
97
97
|
try {
|
|
@@ -161,7 +161,7 @@ export function buildAgentWorkerProgram() {
|
|
|
161
161
|
.action(async (options) => {
|
|
162
162
|
const repoRoot = path.resolve(options.repo);
|
|
163
163
|
const outputPath = options.output ??
|
|
164
|
-
path.join(repoRoot, "
|
|
164
|
+
path.join(getTaskPoolRoot(repoRoot), "reports", "morning-report.md");
|
|
165
165
|
await writeMorningReport({
|
|
166
166
|
repoRoot,
|
|
167
167
|
...(options.batchRunId ? { batchRunId: options.batchRunId } : {}),
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { appendFile, mkdir } from "node:fs/promises";
|
|
2
2
|
import { appendFileSync, mkdirSync } from "node:fs";
|
|
3
3
|
import path from "node:path";
|
|
4
|
+
import { getTaskPoolRoot } from "../pool/run-store.js";
|
|
4
5
|
function writeDiagnostic(context, error) {
|
|
5
6
|
const message = error instanceof Error ? error.message : String(error);
|
|
6
7
|
process.stderr.write(`[worker-event-store] ${context}: ${message}\n`);
|
|
@@ -43,7 +44,7 @@ export function createWorkerEventStore(jsonlPath) {
|
|
|
43
44
|
};
|
|
44
45
|
}
|
|
45
46
|
export function createRoutedWorkerEventStore(repoRoot) {
|
|
46
|
-
const observabilityRoot = path.join(path.resolve(repoRoot), "
|
|
47
|
+
const observabilityRoot = path.join(getTaskPoolRoot(path.resolve(repoRoot)), "observability");
|
|
47
48
|
const globalStore = createWorkerEventStore(path.join(observabilityRoot, "events.jsonl"));
|
|
48
49
|
let queue = Promise.resolve();
|
|
49
50
|
function storesFor(event) {
|
|
@@ -3,6 +3,7 @@ import { readdir, readFile } from "node:fs/promises";
|
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import { truncateUtf8Preview } from "../../shared/preview.js";
|
|
5
5
|
import { parseWorkerEventLine } from "./events.js";
|
|
6
|
+
import { getTaskPoolRoot } from "../pool/run-store.js";
|
|
6
7
|
const ACTIVE_TASK_STATUSES = new Set(["running", "pending"]);
|
|
7
8
|
const ACTIVE_BATCH_STATUSES = new Set(["running", "pending"]);
|
|
8
9
|
export async function buildGlobalSnapshot(options) {
|
|
@@ -474,7 +475,7 @@ function mapBatchStatus(status) {
|
|
|
474
475
|
}
|
|
475
476
|
async function loadObservabilityEvents(repoRoot) {
|
|
476
477
|
const events = [];
|
|
477
|
-
const obsRoot = path.join(repoRoot, "
|
|
478
|
+
const obsRoot = path.join(getTaskPoolRoot(repoRoot), "observability");
|
|
478
479
|
await appendJsonlEvents(path.join(obsRoot, "events.jsonl"), events);
|
|
479
480
|
const batchesDir = path.join(obsRoot, "batches");
|
|
480
481
|
await forEachSubdirJsonl(batchesDir, "events.jsonl", events);
|
|
@@ -510,7 +511,7 @@ async function appendJsonlEvents(filePath, events) {
|
|
|
510
511
|
}
|
|
511
512
|
async function loadLedgerRuns(repoRoot) {
|
|
512
513
|
const runs = [];
|
|
513
|
-
const raw = await safeReadText(path.join(repoRoot, "
|
|
514
|
+
const raw = await safeReadText(path.join(getTaskPoolRoot(repoRoot), "runs.jsonl"));
|
|
514
515
|
if (!raw)
|
|
515
516
|
return runs;
|
|
516
517
|
for (const line of raw.split("\n")) {
|
|
@@ -553,14 +554,15 @@ async function loadLedgerRuns(repoRoot) {
|
|
|
553
554
|
}
|
|
554
555
|
async function loadLedgerBatches(repoRoot) {
|
|
555
556
|
const batches = [];
|
|
556
|
-
const
|
|
557
|
+
const artifactsDir = path.join(getTaskPoolRoot(repoRoot), "artifacts");
|
|
557
558
|
try {
|
|
558
|
-
const entries = await readdir(
|
|
559
|
+
const entries = await readdir(artifactsDir, { withFileTypes: true });
|
|
559
560
|
for (const entry of entries) {
|
|
560
|
-
if (!entry.
|
|
561
|
+
if (!entry.isDirectory())
|
|
561
562
|
continue;
|
|
562
|
-
const batchRunId = entry.name
|
|
563
|
-
const
|
|
563
|
+
const batchRunId = entry.name;
|
|
564
|
+
const batchRunPath = path.join(artifactsDir, batchRunId, "batch-run.json");
|
|
565
|
+
const parsed = await safeReadJson(batchRunPath);
|
|
564
566
|
if (!parsed)
|
|
565
567
|
continue;
|
|
566
568
|
const summaryObj = readObject(parsed, "summary");
|
|
@@ -579,7 +581,7 @@ async function loadLedgerBatches(repoRoot) {
|
|
|
579
581
|
}
|
|
580
582
|
: undefined,
|
|
581
583
|
tasks: [],
|
|
582
|
-
batchRunPath
|
|
584
|
+
batchRunPath,
|
|
583
585
|
});
|
|
584
586
|
}
|
|
585
587
|
}
|
|
@@ -590,7 +592,7 @@ async function loadLedgerBatches(repoRoot) {
|
|
|
590
592
|
}
|
|
591
593
|
async function loadStateRecords(repoRoot) {
|
|
592
594
|
const states = [];
|
|
593
|
-
const stateDir = path.join(repoRoot, "
|
|
595
|
+
const stateDir = path.join(getTaskPoolRoot(repoRoot), "states");
|
|
594
596
|
try {
|
|
595
597
|
const entries = await readdir(stateDir, { withFileTypes: true });
|
|
596
598
|
for (const entry of entries) {
|
|
@@ -621,7 +623,7 @@ async function loadStateRecords(repoRoot) {
|
|
|
621
623
|
}
|
|
622
624
|
async function loadFailureHandoffs(repoRoot) {
|
|
623
625
|
const handoffs = [];
|
|
624
|
-
const handoffDir = path.join(repoRoot, "
|
|
626
|
+
const handoffDir = path.join(getTaskPoolRoot(repoRoot), "failure-handoffs");
|
|
625
627
|
try {
|
|
626
628
|
const entries = await readdir(handoffDir, { withFileTypes: true });
|
|
627
629
|
for (const entry of entries) {
|
|
@@ -736,7 +738,7 @@ function nodeErrorPreview(node, status) {
|
|
|
736
738
|
return truncateUtf8Preview(stderr);
|
|
737
739
|
}
|
|
738
740
|
async function loadDagEventFiles(repoRoot) {
|
|
739
|
-
const runsDir = path.join(repoRoot, "
|
|
741
|
+
const runsDir = path.join(getTaskPoolRoot(repoRoot), "observability", "runs");
|
|
740
742
|
let entries;
|
|
741
743
|
try {
|
|
742
744
|
entries = await readdir(runsDir, { withFileTypes: true });
|
|
@@ -33,8 +33,8 @@ export function resolveArtifactPath(repoRoot, relative) {
|
|
|
33
33
|
function isAllowedArtifactRelativePath(relative) {
|
|
34
34
|
const normalized = path.normalize(relative);
|
|
35
35
|
const segments = normalized.split(path.sep).filter(Boolean);
|
|
36
|
-
if (segments[0] === ".task-pool") {
|
|
37
|
-
return ["artifacts", "failure-handoffs", "reports"].includes(segments[
|
|
36
|
+
if (segments[0] === ".harness" && segments[1] === "task-pool") {
|
|
37
|
+
return ["artifacts", "failure-handoffs", "reports"].includes(segments[2] ?? "");
|
|
38
38
|
}
|
|
39
39
|
if (segments[0] === ".harness" && segments[1] === "tasks") {
|
|
40
40
|
return segments.includes("artifacts");
|
|
@@ -4,6 +4,7 @@ import path from "node:path";
|
|
|
4
4
|
import { parseWorkerEventLine } from "../observability/events.js";
|
|
5
5
|
import { isSafeObservabilityIdentifier } from "../observability/event-store.js";
|
|
6
6
|
import { buildGlobalSnapshot } from "../observability/read-model.js";
|
|
7
|
+
import { getTaskPoolRoot } from "../pool/run-store.js";
|
|
7
8
|
import { resolveArtifactPath, toRepoRelativeArtifactPath, } from "./paths.js";
|
|
8
9
|
const ROUTES = [
|
|
9
10
|
{ method: "GET", pattern: /^\/api\/health$/, handler: handleHealth },
|
|
@@ -148,7 +149,7 @@ async function handleRunEvents(_req, res, match, ctx) {
|
|
|
148
149
|
return;
|
|
149
150
|
}
|
|
150
151
|
const after = parseNonNegativeInt(match.query.get("after"), 0);
|
|
151
|
-
const eventsPath = path.join(ctx.repoRoot, "
|
|
152
|
+
const eventsPath = path.join(getTaskPoolRoot(ctx.repoRoot), "observability", "runs", workerRunId, "events.jsonl");
|
|
152
153
|
const events = (await readJsonlLines(eventsPath, after)).map((event) => normalizeEventArtifactRefs(ctx.repoRoot, event));
|
|
153
154
|
sendJson(res, 200, { events });
|
|
154
155
|
}
|
|
@@ -170,7 +171,7 @@ async function handleRunArtifacts(_req, res, match, ctx) {
|
|
|
170
171
|
artifacts.push({ path: artifactPath, label });
|
|
171
172
|
}
|
|
172
173
|
}
|
|
173
|
-
const eventsPath = path.join(ctx.repoRoot, "
|
|
174
|
+
const eventsPath = path.join(getTaskPoolRoot(ctx.repoRoot), "observability", "runs", workerRunId, "events.jsonl");
|
|
174
175
|
const runEvents = await readJsonlLines(eventsPath, 0);
|
|
175
176
|
for (const event of runEvents) {
|
|
176
177
|
const parsed = event;
|
|
@@ -254,7 +255,7 @@ async function handleEventStream(req, res, match, ctx) {
|
|
|
254
255
|
"Cache-Control": "no-cache",
|
|
255
256
|
Connection: "keep-alive",
|
|
256
257
|
});
|
|
257
|
-
const observabilityRoot = path.join(ctx.repoRoot, "
|
|
258
|
+
const observabilityRoot = path.join(getTaskPoolRoot(ctx.repoRoot), "observability");
|
|
258
259
|
const eventsPath = path.join(observabilityRoot, "events.jsonl");
|
|
259
260
|
let offset = 0;
|
|
260
261
|
const sendMatchingEvents = async (initial) => {
|