@tea-agent/loop-agent 0.13.0-alpha.0 → 0.13.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 +4 -0
- package/CHANGELOG.md +57 -53
- package/README.md +12 -3
- package/dist/application/dag/generate-task-dag.js +28 -58
- package/dist/application/evaluation/candidate-hash.js +75 -0
- package/dist/application/evaluation/candidate.js +52 -0
- package/dist/application/evaluation/replay.js +289 -0
- package/dist/application/evaluation/types.js +130 -0
- package/dist/cli/command-definitions.js +17 -4
- package/dist/cli/program.js +8 -4
- package/dist/commands/eval.js +235 -0
- package/dist/commands/init.js +131 -24
- package/dist/executors/pi-sdk-executor.js +38 -24
- package/dist/executors/shell-executor.js +226 -15
- package/dist/executors/shell-presets.js +20 -0
- package/dist/executors/shell-verification.js +7 -0
- package/dist/governance/manifest-types.js +1 -0
- package/dist/infrastructure/evaluation/candidate-store.js +439 -0
- package/dist/infrastructure/evaluation/store.js +40 -0
- package/dist/task/config-types.js +23 -0
- package/dist/worker/observe/routes.js +18 -3
- package/dist/worker/observe/spec-evidence.js +1 -1
- package/dist/worker/observe/static/dom.js +160 -1
- package/dist/worker/observe/static/state.js +14 -0
- package/dist/worker/observe/static/views/dag-inspector.js +35 -4
- package/dist/worker/observe/static/views/dag.js +9 -0
- package/dist/worker/observe/static/views/dashboard.js +702 -445
- package/dist/worker/observe/static/views/session-timeline.js +15 -1
- package/dist/workflows/dag/backend-test-analysis-contract.js +120 -0
- 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/dynamic-runtime/map.js +90 -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 +2407 -297
- package/dist/workflows/dag/node-execution.js +9 -0
- package/dist/workflows/dag/prompt.js +9 -0
- package/dist/workflows/dag/repair-artifact.js +43 -3
- package/dist/workflows/dag/report.js +35 -1
- package/dist/workflows/dag/runner.js +28 -2
- package/dist/workflows/dag/skill-instructions.js +4 -2
- package/dist/workflows/dag/task-demand-routing.js +383 -0
- package/dist/workflows/dag/types.js +71 -13
- package/dist/workflows/dag/upstream-artifacts.js +1 -0
- package/dist/workflows/dag/validate.js +59 -1
- package/docs/README.md +6 -3
- package/docs/agent-dag-recovery-playbook.md +5 -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 +124 -42
- package/docs/development-principles.md +4 -4
- package/docs/exec-plans/active/README.md +12 -11
- package/docs/exec-plans/completed/README.md +33 -0
- package/docs/feature-workflow.md +114 -39
- package/docs/init-surface.manifest.json +30 -3
- package/docs/loop-agent-harness.md +9 -8
- package/docs/production-readiness.md +1 -1
- package/docs/progress/README.md +23 -1
- package/docs/reports/README.md +65 -6
- package/docs/skills/vetted-skill-registry.md +2 -0
- package/docs/templates/agent-dag.schema.json +29 -1
- package/docs/templates/agent-dag.supervised-implementation.json +127 -8
- package/docs/templates/backend-test-analysis.schema.json +44 -0
- 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 +81 -16
- package/docs/templates/backend-test-dag.json +311 -40
- package/docs/templates/backend-test-dag.retrospect.prompt.md +44 -30
- package/docs/templates/backend-test-dag.review-cases.prompt.md +10 -8
- 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-design-contract.md +9 -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/templates/frontend-task-constraints.md +10 -0
- package/docs/templates/frontend-task-requirement.md +9 -0
- package/docs/templates/frontend-test-dag.generate-cases.prompt.md +5 -0
- package/docs/templates/frontend-test-dag.json +23 -0
- package/docs/templates/frontend-test-dag.retrieve-context.prompt.md +3 -0
- package/docs/templates/frontend-test-dag.retrospect.prompt.md +3 -0
- package/docs/templates/frontend-test-dag.review-cases.prompt.md +3 -0
- package/docs/templates/frontend-test-dag.review-execution.prompt.md +3 -0
- package/docs/templates/knowledge-graph-bootstrap-dag.json +1 -1
- package/docs/templates/knowledge-sync-dag.json +1 -0
- package/docs/verification-matrix.md +4 -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/scripts/kb-bootstrap-init-skeleton.sh +2 -1
- package/scripts/kb-graph-incremental-prepare.mjs +19 -5
- package/scripts/kb-graph-promote.mjs +12 -1
- package/skills/ai-engineering-context/SKILL.md +2 -2
- package/skills/analyze-product-dependencies/SKILL.md +67 -0
- package/skills/analyze-product-dependencies/agents/openai.yaml +4 -0
- package/skills/analyze-product-dependencies/references/api-documentation-schema.md +30 -0
- package/skills/analyze-product-dependencies/references/dependency-analysis-schema.md +28 -0
- package/skills/analyze-product-dependencies/references/example.md +76 -0
- package/skills/analyze-product-dependencies/references/forward-test-cases.md +35 -0
- package/skills/analyze-product-dependencies/references/input-contract.md +11 -0
- package/skills/analyze-product-dependencies/references/scouting-rules.md +61 -0
- package/skills/analyze-product-dependencies/scripts/test-validators.mjs +267 -0
- package/skills/analyze-product-dependencies/scripts/validate-api-documentation.mjs +101 -0
- package/skills/analyze-product-dependencies/scripts/validate-dependency-analysis.mjs +142 -0
- package/skills/analyze-product-dependencies/scripts/validate-product-requirement-input.mjs +76 -0
- package/skills/analyze-product-dependencies/scripts/validation-helpers.mjs +146 -0
- package/skills/analyze-product-requirements/SKILL.md +90 -0
- package/skills/analyze-product-requirements/agents/openai.yaml +4 -0
- package/skills/analyze-product-requirements/references/acceptance-criteria.md +91 -0
- package/skills/analyze-product-requirements/references/clarification-and-knowledge.md +56 -0
- package/skills/analyze-product-requirements/references/example.md +86 -0
- package/skills/analyze-product-requirements/references/forward-test-cases.md +66 -0
- package/skills/analyze-product-requirements/references/product-analysis-schema.md +32 -0
- package/skills/analyze-product-requirements/references/product-requirement-schema.md +33 -0
- package/skills/analyze-product-requirements/references/requirement-clarification-schema.md +35 -0
- package/skills/analyze-product-requirements/scripts/test-validators.mjs +193 -0
- package/skills/analyze-product-requirements/scripts/validate-product-analysis.mjs +69 -0
- package/skills/analyze-product-requirements/scripts/validate-product-requirement.mjs +97 -0
- package/skills/analyze-product-requirements/scripts/validate-requirement-clarification.mjs +98 -0
- package/skills/analyze-product-requirements/scripts/validation-helpers.mjs +156 -0
- 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-design-review/SKILL.md +6 -1
- package/skills/frontend-design-review/references/review-checklist.md +25 -4
- package/skills/frontend-implementation/SKILL.md +25 -30
- package/skills/frontend-implementation/references/code-standards.md +20 -22
- package/skills/frontend-implementation/references/node-contracts.md +17 -53
- package/skills/frontend-review/SKILL.md +10 -4
- package/skills/frontend-review/references/review-findings.md +8 -3
- package/skills/frontend-verification/SKILL.md +22 -9
- package/skills/frontend-verification/references/verification-checklist.md +17 -5
- 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 +98 -24
- 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 +32 -22
- 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/playwright-cli/SKILL.md +420 -0
- package/skills/playwright-cli/references/element-attributes.md +23 -0
- package/skills/playwright-cli/references/playwright-tests.md +39 -0
- package/skills/playwright-cli/references/request-mocking.md +87 -0
- package/skills/playwright-cli/references/running-code.md +241 -0
- package/skills/playwright-cli/references/session-management.md +225 -0
- package/skills/playwright-cli/references/storage-state.md +275 -0
- package/skills/playwright-cli/references/test-generation.md +433 -0
- package/skills/playwright-cli/references/tracing.md +139 -0
- package/skills/playwright-cli/references/video-recording.md +143 -0
- package/skills/playwright-cli-case-generator/SKILL.md +74 -0
- 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
|
@@ -3,7 +3,14 @@ import { appendFileSync, existsSync, mkdirSync, writeFileSync } from "node:fs";
|
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import { writeDagNodeTextArtifact } from "../infrastructure/harness/artifact-store.js";
|
|
5
5
|
import { truncateOutput } from "../shared/output-truncation.js";
|
|
6
|
-
import { expandShellPreset, buildVerdictGateShellCommand } from "./shell-presets.js";
|
|
6
|
+
import { buildRequirementCoverageGateShellCommand, expandShellPreset, buildVerdictGateShellCommand, } from "./shell-presets.js";
|
|
7
|
+
import { materializeBackendTestAnalysisContract } from "../workflows/dag/backend-test-analysis-contract.js";
|
|
8
|
+
import { materializeFrontendImplementationContract } from "../workflows/dag/frontend-implementation-contract.js";
|
|
9
|
+
import { formatFrontendVerificationTraceStdout, runFrontendVerificationTraceGate, } from "../workflows/dag/frontend-verification-trace.js";
|
|
10
|
+
import { formatFrontendFailureAssessStdout, formatFrontendRepairContractStdout, runFrontendFailureAssessGate, runFrontendRepairContractGate, } from "../workflows/dag/frontend-repair.js";
|
|
11
|
+
import { formatTraceabilityGateStdout, materializeBackendTestCaseManifest, runBackendTestTraceabilityGate, } from "../workflows/dag/backend-test-case-manifest.js";
|
|
12
|
+
import { materializeBackendTestExecutionContract } from "../workflows/dag/backend-test-execution-contract.js";
|
|
13
|
+
import { materializeBackendTestResultFromRunDir } from "../workflows/dag/backend-test-result-contract.js";
|
|
7
14
|
import { pathsChangedDuringRun, snapshotGitStatusPorcelain, validateShellWriteGuard, } from "./shell-write-guard.js";
|
|
8
15
|
import { buildShellProcessEnv } from "./shell-verification.js";
|
|
9
16
|
const DEFAULT_SHELL_TIMEOUT_MS = 300_000;
|
|
@@ -23,7 +30,9 @@ function resolveBashExecutable() {
|
|
|
23
30
|
path.join(process.env["ProgramFiles(x86)"] ?? "C:\\Program Files (x86)", "Git", "bin", "bash.exe"),
|
|
24
31
|
path.join(process.env.LocalAppData ?? "", "Programs", "Git", "bin", "bash.exe"),
|
|
25
32
|
].filter(Boolean);
|
|
26
|
-
return candidates.find((candidate) => existsSync(candidate)) ??
|
|
33
|
+
return (candidates.find((candidate) => existsSync(candidate)) ??
|
|
34
|
+
envCandidate ??
|
|
35
|
+
"bash");
|
|
27
36
|
}
|
|
28
37
|
function isWithinRoot(root, candidate) {
|
|
29
38
|
const relative = path.relative(root, candidate);
|
|
@@ -44,7 +53,15 @@ export function resolveShellCommands(shell) {
|
|
|
44
53
|
const fromVerdictGate = shell.verdictGate
|
|
45
54
|
? [buildVerdictGateShellCommand(shell.verdictGate)]
|
|
46
55
|
: [];
|
|
47
|
-
|
|
56
|
+
const fromRequirementCoverageGate = shell.requirementCoverageGate
|
|
57
|
+
? [buildRequirementCoverageGateShellCommand(shell.requirementCoverageGate)]
|
|
58
|
+
: [];
|
|
59
|
+
return [
|
|
60
|
+
...fromPreset,
|
|
61
|
+
...explicit,
|
|
62
|
+
...fromVerdictGate,
|
|
63
|
+
...fromRequirementCoverageGate,
|
|
64
|
+
];
|
|
48
65
|
}
|
|
49
66
|
async function readGitStatusPorcelain(cwd) {
|
|
50
67
|
return new Promise((resolve, reject) => {
|
|
@@ -141,13 +158,16 @@ export async function executeShellCommand(input) {
|
|
|
141
158
|
});
|
|
142
159
|
});
|
|
143
160
|
child.on("close", (code) => {
|
|
161
|
+
let failureCategory = "nonzero-exit";
|
|
162
|
+
if (timedOut) {
|
|
163
|
+
failureCategory = "timeout";
|
|
164
|
+
}
|
|
165
|
+
else if (code === 0) {
|
|
166
|
+
failureCategory = "success";
|
|
167
|
+
}
|
|
144
168
|
finish({
|
|
145
169
|
exitCode: code,
|
|
146
|
-
failureCategory
|
|
147
|
-
? "timeout"
|
|
148
|
-
: code === 0
|
|
149
|
-
? "success"
|
|
150
|
-
: "nonzero-exit",
|
|
170
|
+
failureCategory,
|
|
151
171
|
ok: code === 0 && !timedOut,
|
|
152
172
|
});
|
|
153
173
|
});
|
|
@@ -279,6 +299,182 @@ async function runShellWriteGuard(input) {
|
|
|
279
299
|
}
|
|
280
300
|
export async function executeDagShellNode(input, meta) {
|
|
281
301
|
const shell = input.task.shell;
|
|
302
|
+
if (shell?.jsonArtifactGate) {
|
|
303
|
+
const started = Date.now();
|
|
304
|
+
try {
|
|
305
|
+
const gate = shell.jsonArtifactGate;
|
|
306
|
+
let artifact;
|
|
307
|
+
switch (gate.schemaId) {
|
|
308
|
+
case "backend-test-analysis-v1":
|
|
309
|
+
artifact = await materializeBackendTestAnalysisContract({
|
|
310
|
+
runDir: meta.runDir,
|
|
311
|
+
fromNodeId: gate.fromNodeId,
|
|
312
|
+
artifactName: gate.artifactName,
|
|
313
|
+
outputDir: gate.outputDir,
|
|
314
|
+
sourceBinding: meta.spec.sourceBinding,
|
|
315
|
+
});
|
|
316
|
+
break;
|
|
317
|
+
case "backend-test-execution-v1":
|
|
318
|
+
artifact = await materializeBackendTestExecutionContract({
|
|
319
|
+
runDir: meta.runDir,
|
|
320
|
+
fromNodeId: gate.fromNodeId,
|
|
321
|
+
artifactName: gate.artifactName,
|
|
322
|
+
outputDir: gate.outputDir,
|
|
323
|
+
});
|
|
324
|
+
break;
|
|
325
|
+
case "backend-test-result-v1":
|
|
326
|
+
artifact = await materializeBackendTestResultFromRunDir({
|
|
327
|
+
runDir: meta.runDir,
|
|
328
|
+
fromNodeId: gate.fromNodeId,
|
|
329
|
+
artifactName: gate.artifactName,
|
|
330
|
+
outputDir: gate.outputDir,
|
|
331
|
+
});
|
|
332
|
+
break;
|
|
333
|
+
case "backend-test-case-manifest-v1":
|
|
334
|
+
artifact = await materializeBackendTestCaseManifest({
|
|
335
|
+
runDir: meta.runDir,
|
|
336
|
+
fromNodeId: gate.fromNodeId,
|
|
337
|
+
artifactName: gate.artifactName,
|
|
338
|
+
outputDir: gate.outputDir,
|
|
339
|
+
sourceBinding: meta.spec.sourceBinding,
|
|
340
|
+
});
|
|
341
|
+
break;
|
|
342
|
+
case "frontend-implementation-contract-v1":
|
|
343
|
+
artifact = await materializeFrontendImplementationContract({
|
|
344
|
+
runDir: meta.runDir,
|
|
345
|
+
fromNodeId: gate.fromNodeId,
|
|
346
|
+
artifactName: gate.artifactName,
|
|
347
|
+
outputDir: gate.outputDir,
|
|
348
|
+
sourceBinding: meta.spec.sourceBinding,
|
|
349
|
+
});
|
|
350
|
+
break;
|
|
351
|
+
default:
|
|
352
|
+
throw new Error(`unsupported jsonArtifactGate.schemaId: ${String(gate.schemaId)}`);
|
|
353
|
+
}
|
|
354
|
+
return {
|
|
355
|
+
ok: true,
|
|
356
|
+
stdout: `Structured artifact: ${artifact.path}\nSchema: ${artifact.schemaId}\nSHA-256: ${artifact.sha256}`,
|
|
357
|
+
stderr: "",
|
|
358
|
+
failureCategory: "success",
|
|
359
|
+
durationMs: Date.now() - started,
|
|
360
|
+
};
|
|
361
|
+
}
|
|
362
|
+
catch (error) {
|
|
363
|
+
return {
|
|
364
|
+
ok: false,
|
|
365
|
+
stdout: "",
|
|
366
|
+
stderr: error instanceof Error ? error.message : String(error),
|
|
367
|
+
failureCategory: "invalid-output",
|
|
368
|
+
durationMs: Date.now() - started,
|
|
369
|
+
};
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
if (shell?.commands?.length === 1 &&
|
|
373
|
+
shell.commands[0] === "backend-test-traceability-gate") {
|
|
374
|
+
const started = Date.now();
|
|
375
|
+
try {
|
|
376
|
+
const result = await runBackendTestTraceabilityGate({
|
|
377
|
+
runDir: meta.runDir,
|
|
378
|
+
workspaceRoot: input.cwd,
|
|
379
|
+
});
|
|
380
|
+
return {
|
|
381
|
+
ok: true,
|
|
382
|
+
stdout: formatTraceabilityGateStdout(result),
|
|
383
|
+
stderr: "",
|
|
384
|
+
failureCategory: "success",
|
|
385
|
+
durationMs: Date.now() - started,
|
|
386
|
+
};
|
|
387
|
+
}
|
|
388
|
+
catch (error) {
|
|
389
|
+
return {
|
|
390
|
+
ok: false,
|
|
391
|
+
stdout: "",
|
|
392
|
+
stderr: error instanceof Error ? error.message : String(error),
|
|
393
|
+
failureCategory: "invalid-output",
|
|
394
|
+
durationMs: Date.now() - started,
|
|
395
|
+
};
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
if (shell?.commands?.length === 1 &&
|
|
399
|
+
shell.commands[0] === "frontend-verification-trace-gate") {
|
|
400
|
+
const started = Date.now();
|
|
401
|
+
try {
|
|
402
|
+
const result = await runFrontendVerificationTraceGate({
|
|
403
|
+
runDir: meta.runDir,
|
|
404
|
+
workspaceRoot: input.cwd,
|
|
405
|
+
});
|
|
406
|
+
return {
|
|
407
|
+
ok: true,
|
|
408
|
+
stdout: formatFrontendVerificationTraceStdout(result),
|
|
409
|
+
stderr: "",
|
|
410
|
+
failureCategory: "success",
|
|
411
|
+
durationMs: Date.now() - started,
|
|
412
|
+
};
|
|
413
|
+
}
|
|
414
|
+
catch (error) {
|
|
415
|
+
const stderr = error instanceof Error ? error.message : String(error);
|
|
416
|
+
const recordNonZero = shell.nonZeroExitPolicy === "record";
|
|
417
|
+
return {
|
|
418
|
+
ok: recordNonZero,
|
|
419
|
+
stdout: recordNonZero
|
|
420
|
+
? "nonZeroExitPolicy=record failureCategory=invalid-output\n"
|
|
421
|
+
: "",
|
|
422
|
+
stderr,
|
|
423
|
+
failureCategory: "invalid-output",
|
|
424
|
+
durationMs: Date.now() - started,
|
|
425
|
+
};
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
if (shell?.commands?.length === 1 &&
|
|
429
|
+
shell.commands[0] === "frontend-failure-assess-gate") {
|
|
430
|
+
const started = Date.now();
|
|
431
|
+
try {
|
|
432
|
+
const result = await runFrontendFailureAssessGate({
|
|
433
|
+
runDir: meta.runDir,
|
|
434
|
+
});
|
|
435
|
+
return {
|
|
436
|
+
ok: true,
|
|
437
|
+
stdout: formatFrontendFailureAssessStdout(result),
|
|
438
|
+
stderr: "",
|
|
439
|
+
failureCategory: "success",
|
|
440
|
+
durationMs: Date.now() - started,
|
|
441
|
+
};
|
|
442
|
+
}
|
|
443
|
+
catch (error) {
|
|
444
|
+
return {
|
|
445
|
+
ok: false,
|
|
446
|
+
stdout: "",
|
|
447
|
+
stderr: error instanceof Error ? error.message : String(error),
|
|
448
|
+
failureCategory: "invalid-output",
|
|
449
|
+
durationMs: Date.now() - started,
|
|
450
|
+
};
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
if (shell?.commands?.length === 1 &&
|
|
454
|
+
shell.commands[0] === "frontend-repair-contract-gate") {
|
|
455
|
+
const started = Date.now();
|
|
456
|
+
try {
|
|
457
|
+
const result = await runFrontendRepairContractGate({
|
|
458
|
+
runDir: meta.runDir,
|
|
459
|
+
});
|
|
460
|
+
return {
|
|
461
|
+
ok: true,
|
|
462
|
+
stdout: formatFrontendRepairContractStdout(result.assessment),
|
|
463
|
+
stderr: "",
|
|
464
|
+
failureCategory: "success",
|
|
465
|
+
durationMs: Date.now() - started,
|
|
466
|
+
};
|
|
467
|
+
}
|
|
468
|
+
catch (error) {
|
|
469
|
+
return {
|
|
470
|
+
ok: false,
|
|
471
|
+
stdout: "",
|
|
472
|
+
stderr: error instanceof Error ? error.message : String(error),
|
|
473
|
+
failureCategory: "invalid-output",
|
|
474
|
+
durationMs: Date.now() - started,
|
|
475
|
+
};
|
|
476
|
+
}
|
|
477
|
+
}
|
|
282
478
|
const commands = shell ? resolveShellCommands(shell) : [];
|
|
283
479
|
if (!shell || commands.length === 0) {
|
|
284
480
|
throw new Error(`shell task ${input.task.id} requires shell.preset, shell.verdictGate, and/or non-empty shell.commands`);
|
|
@@ -330,7 +526,8 @@ export async function executeDagShellNode(input, meta) {
|
|
|
330
526
|
}
|
|
331
527
|
}
|
|
332
528
|
const commandsOk = results.every((result) => result.ok);
|
|
333
|
-
const
|
|
529
|
+
const recordNonZero = shell.nonZeroExitPolicy === "record";
|
|
530
|
+
const ok = (commandsOk || recordNonZero) && writeGuardOk;
|
|
334
531
|
const firstFailure = results.find((result) => !result.ok);
|
|
335
532
|
await writeDagNodeTextArtifact(meta.runDir, input.task.id, "result.summary.md", buildShellResultSummaryMarkdown({
|
|
336
533
|
nodeId: input.task.id,
|
|
@@ -344,15 +541,29 @@ export async function executeDagShellNode(input, meta) {
|
|
|
344
541
|
if (!writeGuardOk) {
|
|
345
542
|
stderrParts.push(`write guard failed: ${writeGuardViolations.join(", ")}`);
|
|
346
543
|
}
|
|
544
|
+
let failureCategory = "success";
|
|
545
|
+
if (!commandsOk) {
|
|
546
|
+
failureCategory = firstFailure?.failureCategory ?? "nonzero-exit";
|
|
547
|
+
}
|
|
548
|
+
else if (!writeGuardOk) {
|
|
549
|
+
failureCategory = "write-guard";
|
|
550
|
+
}
|
|
551
|
+
const commandResults = results.map((result) => ({
|
|
552
|
+
ok: result.ok,
|
|
553
|
+
exitCode: result.exitCode,
|
|
554
|
+
failureCategory: result.failureCategory,
|
|
555
|
+
command: result.command,
|
|
556
|
+
}));
|
|
557
|
+
const recordPrefix = recordNonZero && !commandsOk
|
|
558
|
+
? `nonZeroExitPolicy=record exitCode=${firstFailure?.exitCode ?? "null"}\n`
|
|
559
|
+
: "";
|
|
347
560
|
return {
|
|
348
561
|
ok,
|
|
349
|
-
stdout: aggregate.stdout
|
|
562
|
+
stdout: `${recordPrefix}${aggregate.stdout}`,
|
|
350
563
|
stderr: stderrParts.filter(Boolean).join("\n\n"),
|
|
351
|
-
failureCategory
|
|
352
|
-
? (firstFailure?.failureCategory ?? "nonzero-exit")
|
|
353
|
-
: !writeGuardOk
|
|
354
|
-
? "write-guard"
|
|
355
|
-
: "success",
|
|
564
|
+
failureCategory,
|
|
356
565
|
durationMs: Date.now() - started,
|
|
566
|
+
// extra field consumed by node-execution if supported; also embedded in stdout marker
|
|
567
|
+
...{ commandResults },
|
|
357
568
|
};
|
|
358
569
|
}
|
|
@@ -45,3 +45,23 @@ export function buildVerdictGateShellCommand(gate) {
|
|
|
45
45
|
.join("|");
|
|
46
46
|
return `${preamble}; case "\${FIRST}" in ${acceptPattern}) exit 0 ;; *) echo "${blockedMessage}" >&2; exit 1 ;; esac`;
|
|
47
47
|
}
|
|
48
|
+
/** Build a deterministic current-run gate over exact REQ-/BR-/AC- ids in node facts. */
|
|
49
|
+
export function buildRequirementCoverageGateShellCommand(gate) {
|
|
50
|
+
const label = gate.label ?? "requirement coverage";
|
|
51
|
+
const requiredJson = escapeShellSingleQuoted(JSON.stringify(gate.requiredIds.map((id) => id.toUpperCase())));
|
|
52
|
+
const fileArgs = gate.fromNodeIds.map((nodeId) => `"\${HARNESS_DAG_RUN_DIR}/${nodeId}.json"`).join(" ");
|
|
53
|
+
const program = [
|
|
54
|
+
'const fs=require("fs");',
|
|
55
|
+
"const required=JSON.parse(process.argv[1]);",
|
|
56
|
+
"let text='';",
|
|
57
|
+
"for(const file of process.argv.slice(2)){",
|
|
58
|
+
" if(!fs.existsSync(file)){console.error('missing requirement coverage node output: '+file);process.exit(1);}",
|
|
59
|
+
" const raw=JSON.parse(fs.readFileSync(file,'utf8')); text+='\\n'+String(raw.assistantText ?? raw.stdout ?? '');",
|
|
60
|
+
"}",
|
|
61
|
+
"const found=new Set((text.toUpperCase().match(/\\b(?:REQ|BR|AC)-[A-Z0-9]+(?:-[A-Z0-9]+)*\\b/g)||[]));",
|
|
62
|
+
"const missing=required.filter((id)=>!found.has(id));",
|
|
63
|
+
`if(missing.length){console.error(${JSON.stringify(`${label} gate blocked: missing `)}+missing.join(', '));process.exit(1);}`,
|
|
64
|
+
`console.log(${JSON.stringify(`${label} gate passed: `)}+required.join(', '));`,
|
|
65
|
+
].join("");
|
|
66
|
+
return `test -n "\${HARNESS_DAG_RUN_DIR:-}" || { echo "missing HARNESS_DAG_RUN_DIR for ${label} gate" >&2; exit 1; }; node -e '${escapeShellSingleQuoted(program)}' '${requiredJson}' ${fileArgs}`;
|
|
67
|
+
}
|
|
@@ -20,6 +20,13 @@ const VERIFY_ENV_ALLOWLIST = [
|
|
|
20
20
|
"COREPACK_ENABLE",
|
|
21
21
|
"COREPACK_ENABLE_AUTO_PIN",
|
|
22
22
|
"COREPACK_HOME",
|
|
23
|
+
// Windows DLL 加载必需
|
|
24
|
+
"SystemRoot",
|
|
25
|
+
"SYSTEMROOT",
|
|
26
|
+
"windir",
|
|
27
|
+
"WINDIR",
|
|
28
|
+
"ComSpec",
|
|
29
|
+
"PATHEXT",
|
|
23
30
|
];
|
|
24
31
|
export function buildVerifyProcessEnv(mode = "clean") {
|
|
25
32
|
if (mode === "inherit") {
|