@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.
Files changed (199) hide show
  1. package/AGENTS.md +4 -0
  2. package/CHANGELOG.md +57 -53
  3. package/README.md +12 -3
  4. package/dist/application/dag/generate-task-dag.js +28 -58
  5. package/dist/application/evaluation/candidate-hash.js +75 -0
  6. package/dist/application/evaluation/candidate.js +52 -0
  7. package/dist/application/evaluation/replay.js +289 -0
  8. package/dist/application/evaluation/types.js +130 -0
  9. package/dist/cli/command-definitions.js +17 -4
  10. package/dist/cli/program.js +8 -4
  11. package/dist/commands/eval.js +235 -0
  12. package/dist/commands/init.js +131 -24
  13. package/dist/executors/pi-sdk-executor.js +38 -24
  14. package/dist/executors/shell-executor.js +226 -15
  15. package/dist/executors/shell-presets.js +20 -0
  16. package/dist/executors/shell-verification.js +7 -0
  17. package/dist/governance/manifest-types.js +1 -0
  18. package/dist/infrastructure/evaluation/candidate-store.js +439 -0
  19. package/dist/infrastructure/evaluation/store.js +40 -0
  20. package/dist/task/config-types.js +23 -0
  21. package/dist/worker/observe/routes.js +18 -3
  22. package/dist/worker/observe/spec-evidence.js +1 -1
  23. package/dist/worker/observe/static/dom.js +160 -1
  24. package/dist/worker/observe/static/state.js +14 -0
  25. package/dist/worker/observe/static/views/dag-inspector.js +35 -4
  26. package/dist/worker/observe/static/views/dag.js +9 -0
  27. package/dist/worker/observe/static/views/dashboard.js +702 -445
  28. package/dist/worker/observe/static/views/session-timeline.js +15 -1
  29. package/dist/workflows/dag/backend-test-analysis-contract.js +120 -0
  30. package/dist/workflows/dag/backend-test-case-manifest.js +503 -0
  31. package/dist/workflows/dag/backend-test-execution-contract.js +353 -0
  32. package/dist/workflows/dag/backend-test-result-contract.js +568 -0
  33. package/dist/workflows/dag/decision-envelope.js +57 -2
  34. package/dist/workflows/dag/dynamic-runtime/map.js +90 -2
  35. package/dist/workflows/dag/frontend-implementation-contract.js +240 -0
  36. package/dist/workflows/dag/frontend-project-capability.js +309 -0
  37. package/dist/workflows/dag/frontend-repair.js +341 -0
  38. package/dist/workflows/dag/frontend-risk.js +161 -0
  39. package/dist/workflows/dag/frontend-verification-trace.js +190 -0
  40. package/dist/workflows/dag/init-hybrid.js +2407 -297
  41. package/dist/workflows/dag/node-execution.js +9 -0
  42. package/dist/workflows/dag/prompt.js +9 -0
  43. package/dist/workflows/dag/repair-artifact.js +43 -3
  44. package/dist/workflows/dag/report.js +35 -1
  45. package/dist/workflows/dag/runner.js +28 -2
  46. package/dist/workflows/dag/skill-instructions.js +4 -2
  47. package/dist/workflows/dag/task-demand-routing.js +383 -0
  48. package/dist/workflows/dag/types.js +71 -13
  49. package/dist/workflows/dag/upstream-artifacts.js +1 -0
  50. package/dist/workflows/dag/validate.js +59 -1
  51. package/docs/README.md +6 -3
  52. package/docs/agent-dag-recovery-playbook.md +5 -3
  53. package/docs/agent-dag-runner.md +3 -3
  54. package/docs/architecture/README.md +3 -3
  55. package/docs/architecture/dag-execution.md +1 -1
  56. package/docs/architecture/evolution.md +13 -13
  57. package/docs/architecture/facts-and-state.md +1 -1
  58. package/docs/architecture/runtime-boundaries.md +7 -7
  59. package/docs/architecture/system-overview.md +3 -3
  60. package/docs/architecture/worker-and-feature.md +3 -3
  61. package/docs/design/README.md +124 -42
  62. package/docs/development-principles.md +4 -4
  63. package/docs/exec-plans/active/README.md +12 -11
  64. package/docs/exec-plans/completed/README.md +33 -0
  65. package/docs/feature-workflow.md +114 -39
  66. package/docs/init-surface.manifest.json +30 -3
  67. package/docs/loop-agent-harness.md +9 -8
  68. package/docs/production-readiness.md +1 -1
  69. package/docs/progress/README.md +23 -1
  70. package/docs/reports/README.md +65 -6
  71. package/docs/skills/vetted-skill-registry.md +2 -0
  72. package/docs/templates/agent-dag.schema.json +29 -1
  73. package/docs/templates/agent-dag.supervised-implementation.json +127 -8
  74. package/docs/templates/backend-test-analysis.schema.json +44 -0
  75. package/docs/templates/backend-test-case-manifest.schema.json +190 -0
  76. package/docs/templates/backend-test-dag.classify.prompt.md +75 -0
  77. package/docs/templates/backend-test-dag.generate-pytest.prompt.md +81 -16
  78. package/docs/templates/backend-test-dag.json +311 -40
  79. package/docs/templates/backend-test-dag.retrospect.prompt.md +44 -30
  80. package/docs/templates/backend-test-dag.review-cases.prompt.md +10 -8
  81. package/docs/templates/backend-test-execution.schema.json +133 -0
  82. package/docs/templates/backend-test-result.schema.json +99 -0
  83. package/docs/templates/branch-merge-report.md +93 -0
  84. package/docs/templates/frontend-design-contract.md +9 -0
  85. package/docs/templates/frontend-eval/fixtures/failures/01-type-build-error.md +17 -0
  86. package/docs/templates/frontend-eval/fixtures/failures/02-unit-component-test-fail.md +16 -0
  87. package/docs/templates/frontend-eval/fixtures/failures/03-fixture-schema-drift.md +16 -0
  88. package/docs/templates/frontend-eval/fixtures/failures/04-missing-loading-empty-error-state.md +16 -0
  89. package/docs/templates/frontend-eval/fixtures/failures/05-forbidden-write-writeset-expansion.md +16 -0
  90. package/docs/templates/frontend-eval/fixtures/failures/06-unapproved-dependency-add.md +16 -0
  91. package/docs/templates/frontend-eval/fixtures/failures/07-mock-production-on.md +21 -0
  92. package/docs/templates/frontend-eval/fixtures/functional/01-simple-component-style.md +29 -0
  93. package/docs/templates/frontend-eval/fixtures/functional/02-form-validation.md +28 -0
  94. package/docs/templates/frontend-eval/fixtures/functional/03-list-detail-page.md +28 -0
  95. package/docs/templates/frontend-eval/fixtures/functional/04-api-mock.md +29 -0
  96. package/docs/templates/frontend-eval/fixtures/functional/05-permission-auth-gated-ui.md +27 -0
  97. package/docs/templates/frontend-eval/fixtures/functional/06-ssr-server-client-boundary.md +28 -0
  98. package/docs/templates/frontend-eval/fixtures/functional/07-shared-public-component-api.md +28 -0
  99. package/docs/templates/frontend-eval/fixtures/functional/08-pure-local-no-remote.md +27 -0
  100. package/docs/templates/frontend-eval/metrics.md +138 -0
  101. package/docs/templates/frontend-eval/smoke-targets.md +53 -0
  102. package/docs/templates/frontend-implementation-contract.schema.json +27 -0
  103. package/docs/templates/frontend-task-constraints.md +10 -0
  104. package/docs/templates/frontend-task-requirement.md +9 -0
  105. package/docs/templates/frontend-test-dag.generate-cases.prompt.md +5 -0
  106. package/docs/templates/frontend-test-dag.json +23 -0
  107. package/docs/templates/frontend-test-dag.retrieve-context.prompt.md +3 -0
  108. package/docs/templates/frontend-test-dag.retrospect.prompt.md +3 -0
  109. package/docs/templates/frontend-test-dag.review-cases.prompt.md +3 -0
  110. package/docs/templates/frontend-test-dag.review-execution.prompt.md +3 -0
  111. package/docs/templates/knowledge-graph-bootstrap-dag.json +1 -1
  112. package/docs/templates/knowledge-sync-dag.json +1 -0
  113. package/docs/verification-matrix.md +4 -1
  114. package/examples/decision-gate-agent-dag.json +4 -4
  115. package/examples/hybrid-loop-agent-dag.json +1 -1
  116. package/package.json +2 -2
  117. package/scripts/kb-bootstrap-init-skeleton.sh +2 -1
  118. package/scripts/kb-graph-incremental-prepare.mjs +19 -5
  119. package/scripts/kb-graph-promote.mjs +12 -1
  120. package/skills/ai-engineering-context/SKILL.md +2 -2
  121. package/skills/analyze-product-dependencies/SKILL.md +67 -0
  122. package/skills/analyze-product-dependencies/agents/openai.yaml +4 -0
  123. package/skills/analyze-product-dependencies/references/api-documentation-schema.md +30 -0
  124. package/skills/analyze-product-dependencies/references/dependency-analysis-schema.md +28 -0
  125. package/skills/analyze-product-dependencies/references/example.md +76 -0
  126. package/skills/analyze-product-dependencies/references/forward-test-cases.md +35 -0
  127. package/skills/analyze-product-dependencies/references/input-contract.md +11 -0
  128. package/skills/analyze-product-dependencies/references/scouting-rules.md +61 -0
  129. package/skills/analyze-product-dependencies/scripts/test-validators.mjs +267 -0
  130. package/skills/analyze-product-dependencies/scripts/validate-api-documentation.mjs +101 -0
  131. package/skills/analyze-product-dependencies/scripts/validate-dependency-analysis.mjs +142 -0
  132. package/skills/analyze-product-dependencies/scripts/validate-product-requirement-input.mjs +76 -0
  133. package/skills/analyze-product-dependencies/scripts/validation-helpers.mjs +146 -0
  134. package/skills/analyze-product-requirements/SKILL.md +90 -0
  135. package/skills/analyze-product-requirements/agents/openai.yaml +4 -0
  136. package/skills/analyze-product-requirements/references/acceptance-criteria.md +91 -0
  137. package/skills/analyze-product-requirements/references/clarification-and-knowledge.md +56 -0
  138. package/skills/analyze-product-requirements/references/example.md +86 -0
  139. package/skills/analyze-product-requirements/references/forward-test-cases.md +66 -0
  140. package/skills/analyze-product-requirements/references/product-analysis-schema.md +32 -0
  141. package/skills/analyze-product-requirements/references/product-requirement-schema.md +33 -0
  142. package/skills/analyze-product-requirements/references/requirement-clarification-schema.md +35 -0
  143. package/skills/analyze-product-requirements/scripts/test-validators.mjs +193 -0
  144. package/skills/analyze-product-requirements/scripts/validate-product-analysis.mjs +69 -0
  145. package/skills/analyze-product-requirements/scripts/validate-product-requirement.mjs +97 -0
  146. package/skills/analyze-product-requirements/scripts/validate-requirement-clarification.mjs +98 -0
  147. package/skills/analyze-product-requirements/scripts/validation-helpers.mjs +156 -0
  148. package/skills/browser-tools/SKILL.md +196 -0
  149. package/skills/browser-tools/browser-content.js +103 -0
  150. package/skills/browser-tools/browser-cookies.js +35 -0
  151. package/skills/browser-tools/browser-eval.js +53 -0
  152. package/skills/browser-tools/browser-hn-scraper.js +108 -0
  153. package/skills/browser-tools/browser-nav.js +44 -0
  154. package/skills/browser-tools/browser-pick.js +162 -0
  155. package/skills/browser-tools/browser-screenshot.js +34 -0
  156. package/skills/browser-tools/browser-start.js +86 -0
  157. package/skills/browser-tools/package-lock.json +2556 -0
  158. package/skills/browser-tools/package.json +19 -0
  159. package/skills/frontend-design-review/SKILL.md +6 -1
  160. package/skills/frontend-design-review/references/review-checklist.md +25 -4
  161. package/skills/frontend-implementation/SKILL.md +25 -30
  162. package/skills/frontend-implementation/references/code-standards.md +20 -22
  163. package/skills/frontend-implementation/references/node-contracts.md +17 -53
  164. package/skills/frontend-review/SKILL.md +10 -4
  165. package/skills/frontend-review/references/review-findings.md +8 -3
  166. package/skills/frontend-verification/SKILL.md +22 -9
  167. package/skills/frontend-verification/references/verification-checklist.md +17 -5
  168. package/skills/grill-with-docs/SKILL.md +5 -5
  169. package/skills/grill-with-docs/adr-format.md +3 -3
  170. package/skills/init-capability-evolution/SKILL.md +5 -5
  171. package/skills/loop-agent/SKILL.md +5 -5
  172. package/skills/loop-agent/references/README.md +3 -3
  173. package/skills/loop-agent/references/command-reference.md +98 -24
  174. package/skills/loop-agent/references/docs-converge.md +15 -15
  175. package/skills/loop-agent/references/harness-policy.md +2 -2
  176. package/skills/loop-agent/references/hybrid-dag.md +32 -22
  177. package/skills/loop-agent/references/multi-worktree.md +1 -1
  178. package/skills/loop-agent/references/orchestrator-and-interventions.md +8 -8
  179. package/skills/loop-agent/references/task-workflow.md +1 -1
  180. package/skills/loop-agent/references/verification-and-failure-handling.md +6 -4
  181. package/skills/playwright-cli/SKILL.md +420 -0
  182. package/skills/playwright-cli/references/element-attributes.md +23 -0
  183. package/skills/playwright-cli/references/playwright-tests.md +39 -0
  184. package/skills/playwright-cli/references/request-mocking.md +87 -0
  185. package/skills/playwright-cli/references/running-code.md +241 -0
  186. package/skills/playwright-cli/references/session-management.md +225 -0
  187. package/skills/playwright-cli/references/storage-state.md +275 -0
  188. package/skills/playwright-cli/references/test-generation.md +433 -0
  189. package/skills/playwright-cli/references/tracing.md +139 -0
  190. package/skills/playwright-cli/references/video-recording.md +143 -0
  191. package/skills/playwright-cli-case-generator/SKILL.md +74 -0
  192. package/skills/requesting-code-review/SKILL.md +1 -1
  193. package/skills/systematic-debugging/CREATION-LOG.md +3 -3
  194. package/skills/systematic-debugging/SKILL.md +1 -1
  195. package/skills/systematic-debugging/test-academic.md +1 -1
  196. package/skills/systematic-debugging/test-pressure-1.md +1 -1
  197. package/skills/systematic-debugging/test-pressure-2.md +1 -1
  198. package/skills/systematic-debugging/test-pressure-3.md +1 -1
  199. 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)) ?? envCandidate ?? "bash";
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
- return [...fromPreset, ...explicit, ...fromVerdictGate];
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: timedOut
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 ok = commandsOk && writeGuardOk;
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: !commandsOk
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") {
@@ -43,6 +43,7 @@ export const workflowPolicyDagTemplateSchema = z.enum([
43
43
  "review-gated-dag",
44
44
  "supervised-implementation",
45
45
  "frontend-implementation",
46
+ "frontend-test-dag",
46
47
  "backend-test-dag",
47
48
  "knowledge-sync-dag",
48
49
  "knowledge-graph-bootstrap-dag",