@tea-agent/loop-agent 0.42.0-next.15 → 0.42.0-next.17

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 (97) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/dist/application/task-lifecycle/advance.js +9 -4
  3. package/dist/build-stamp.json +3 -3
  4. package/dist/commands/task-source-prepare.js +3 -1
  5. package/dist/executors/dag-pi-executor.js +825 -65
  6. package/dist/executors/shell-executor.js +103 -35
  7. package/dist/shared/dag-failure-category.js +6 -0
  8. package/dist/task/contract/apply.js +36 -2
  9. package/dist/task/source-prepare/parse-intent.js +7 -0
  10. package/dist/worker/console/chat/chat-event-store.js +4 -2
  11. package/dist/worker/console/static/assets/{abnfDiagram-N423BO3Z-CgXb0EVO.js → abnfDiagram-N423BO3Z-B0Q0nClf.js} +1 -1
  12. package/dist/worker/console/static/assets/{arc-DN59MZqN.js → arc-DCPjC19G.js} +1 -1
  13. package/dist/worker/console/static/assets/{architectureDiagram-T3A2C74G-BUk3sWpn.js → architectureDiagram-T3A2C74G-CP5n9jmG.js} +1 -1
  14. package/dist/worker/console/static/assets/{blockDiagram-VBNYF7ZC-IH-cPBFE.js → blockDiagram-VBNYF7ZC-CmaWi_Wg.js} +1 -1
  15. package/dist/worker/console/static/assets/{c4Diagram-5PPSVZJV-BJWf1nGo.js → c4Diagram-5PPSVZJV-Ct5tcMfZ.js} +1 -1
  16. package/dist/worker/console/static/assets/channel-DAS07MdS.js +1 -0
  17. package/dist/worker/console/static/assets/{chunk-2GRJ4B5K-BCPb5H0y.js → chunk-2GRJ4B5K-C0osm1Zf.js} +1 -1
  18. package/dist/worker/console/static/assets/{chunk-2Q5K7J3B-Cfs3jeW2.js → chunk-2Q5K7J3B-CDWviED7.js} +1 -1
  19. package/dist/worker/console/static/assets/{chunk-5RXB4S5H-BhQI1B_T.js → chunk-5RXB4S5H-mtSk1-j7.js} +1 -1
  20. package/dist/worker/console/static/assets/{chunk-5VM5RSS4-Cc_m4gyV.js → chunk-5VM5RSS4-D5J9PHC7.js} +1 -1
  21. package/dist/worker/console/static/assets/{chunk-6Q2QTUOP-JPqDS3IV.js → chunk-6Q2QTUOP-Begg4WAa.js} +1 -1
  22. package/dist/worker/console/static/assets/{chunk-GF5L2VYU-AeGX6EAg.js → chunk-GF5L2VYU-sF1AEy7T.js} +1 -1
  23. package/dist/worker/console/static/assets/{chunk-JWPE2WC7-pEyTjekV.js → chunk-JWPE2WC7-BqbsWXZb.js} +1 -1
  24. package/dist/worker/console/static/assets/{chunk-KBJHAD2P-Bi5UopKd.js → chunk-KBJHAD2P-BKJrPcJ6.js} +1 -1
  25. package/dist/worker/console/static/assets/{chunk-RYQCIY6F-FkGFJxgQ.js → chunk-RYQCIY6F-CcwNMRho.js} +1 -1
  26. package/dist/worker/console/static/assets/{chunk-XXDRQBXY-D-7LGrV2.js → chunk-XXDRQBXY-BEJi3iIs.js} +1 -1
  27. package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-Cwk-5jiW.js +1 -0
  28. package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-Cwk-5jiW.js +1 -0
  29. package/dist/worker/console/static/assets/{cose-bilkent-JH36ORCC-CCEDNDaX.js → cose-bilkent-JH36ORCC-DRLgTvVu.js} +1 -1
  30. package/dist/worker/console/static/assets/{cynefin-VYW2F7L2-DDd-t7fm.js → cynefin-VYW2F7L2-BoAVG3cs.js} +1 -1
  31. package/dist/worker/console/static/assets/{cynefinDiagram-MW4NZA55-LWe4Ikzr.js → cynefinDiagram-MW4NZA55-Bzol06hR.js} +1 -1
  32. package/dist/worker/console/static/assets/{dagre-VZM6K2ZE-BBCZScc-.js → dagre-VZM6K2ZE-UmliJM77.js} +1 -1
  33. package/dist/worker/console/static/assets/{diagram-7IWD3JNH-B6liRVig.js → diagram-7IWD3JNH-BWLcJkFo.js} +1 -1
  34. package/dist/worker/console/static/assets/{diagram-B4RE2ZJO-DO_hIrpW.js → diagram-B4RE2ZJO-CgApOm-O.js} +1 -1
  35. package/dist/worker/console/static/assets/{diagram-LBJQPF4R-dmCy93uR.js → diagram-LBJQPF4R-Bh3RgTLs.js} +1 -1
  36. package/dist/worker/console/static/assets/{diagram-Q27KOJAE-D6mFTIxP.js → diagram-Q27KOJAE-Dsh-D5nE.js} +1 -1
  37. package/dist/worker/console/static/assets/{diagram-UB23O5K3-DCteVUfY.js → diagram-UB23O5K3-Dkbbpcpb.js} +1 -1
  38. package/dist/worker/console/static/assets/{ebnfDiagram-BXEA7PRR-DTv530VK.js → ebnfDiagram-BXEA7PRR-3EBaA3t3.js} +1 -1
  39. package/dist/worker/console/static/assets/{erDiagram-JOGREHBK-DCXDMxCr.js → erDiagram-JOGREHBK-Bq2Dc5ok.js} +1 -1
  40. package/dist/worker/console/static/assets/{flowDiagram-UKHOOZJN-BwEBLOJh.js → flowDiagram-UKHOOZJN-De7y55ha.js} +1 -1
  41. package/dist/worker/console/static/assets/{ganttDiagram-PKOTCBZU-Ck-Vymjm.js → ganttDiagram-PKOTCBZU-fLiDbQRh.js} +1 -1
  42. package/dist/worker/console/static/assets/{gitGraphDiagram-DS77QQ5N-Hqs6X_3L.js → gitGraphDiagram-DS77QQ5N-Du617mp1.js} +1 -1
  43. package/dist/worker/console/static/assets/{index-BmMi-Bve.js → index-C0O48S_P.js} +50 -50
  44. package/dist/worker/console/static/assets/index-CzKf4U8P.css +1 -0
  45. package/dist/worker/console/static/assets/{infoDiagram-6WML65LV-Cjc6M9eg.js → infoDiagram-6WML65LV-BwmlF-XP.js} +1 -1
  46. package/dist/worker/console/static/assets/{ishikawaDiagram-WSZJBQD7-CPchYZMl.js → ishikawaDiagram-WSZJBQD7-zsGtS59u.js} +1 -1
  47. package/dist/worker/console/static/assets/{journeyDiagram-NVQOT4AX-BABdJNNC.js → journeyDiagram-NVQOT4AX-DTTPTe3f.js} +1 -1
  48. package/dist/worker/console/static/assets/{kanban-definition-27J2QSJJ-1oXhbM4j.js → kanban-definition-27J2QSJJ-BkXg9aP-.js} +1 -1
  49. package/dist/worker/console/static/assets/{linear-PTmQ9LkV.js → linear-7U2ue5IE.js} +1 -1
  50. package/dist/worker/console/static/assets/{mermaid.core-B6Lxil0V.js → mermaid.core-BUuGHmWO.js} +5 -5
  51. package/dist/worker/console/static/assets/{mindmap-definition-FAOFIHXS-BUqjNGEw.js → mindmap-definition-FAOFIHXS-7q6fX0Sv.js} +1 -1
  52. package/dist/worker/console/static/assets/{pegDiagram-VL7TDLO6-8D1N-orJ.js → pegDiagram-VL7TDLO6-CkQPJN55.js} +1 -1
  53. package/dist/worker/console/static/assets/{pieDiagram-7S7Q4E2Y-BlPMN9d9.js → pieDiagram-7S7Q4E2Y-CCal_tfX.js} +1 -1
  54. package/dist/worker/console/static/assets/{quadrantDiagram-CIZ2JOQS-BIL5YDes.js → quadrantDiagram-CIZ2JOQS-B7bpxyAZ.js} +1 -1
  55. package/dist/worker/console/static/assets/{railroadDiagram-AXF67PYL-Dqmil3ie.js → railroadDiagram-AXF67PYL-CJmww7D-.js} +1 -1
  56. package/dist/worker/console/static/assets/{requirementDiagram-LRYGKXZP-C_-Dp4mH.js → requirementDiagram-LRYGKXZP-D6ldWJEv.js} +1 -1
  57. package/dist/worker/console/static/assets/{sankeyDiagram-W5VNT64P-C0s5-bQS.js → sankeyDiagram-W5VNT64P-VGh33I9e.js} +1 -1
  58. package/dist/worker/console/static/assets/{sequenceDiagram-SI44F4Z6-DiVCHPfi.js → sequenceDiagram-SI44F4Z6-CCkDrIjU.js} +1 -1
  59. package/dist/worker/console/static/assets/{sizeCapture-X5ZJPWSS-CxQ9WVvx.js → sizeCapture-X5ZJPWSS-NC8f5Otb.js} +1 -1
  60. package/dist/worker/console/static/assets/{stateDiagram-OKZ733FA-D9mFHA-Y.js → stateDiagram-OKZ733FA-_92ezZdF.js} +1 -1
  61. package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-DyJg5gzW.js +1 -0
  62. package/dist/worker/console/static/assets/{swimlanes-SLNWSIFB-DDnC5l-M.js → swimlanes-SLNWSIFB-BdUCGtbP.js} +2 -2
  63. package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-B1cw_0Uy.js +8 -0
  64. package/dist/worker/console/static/assets/{timeline-definition-Z64GVDOM-C8QySPC-.js → timeline-definition-Z64GVDOM-CdD1H8ia.js} +1 -1
  65. package/dist/worker/console/static/assets/{vennDiagram-T6HMQDX7-BeYdDiz6.js → vennDiagram-T6HMQDX7-Dkdk3oFo.js} +1 -1
  66. package/dist/worker/console/static/assets/{wardleyDiagram-T6FBY63Y-D8hjFWLH.js → wardleyDiagram-T6FBY63Y-CKu2uPPY.js} +1 -1
  67. package/dist/worker/console/static/assets/{xychartDiagram-ELKLHX3M-ClqG_JGK.js → xychartDiagram-ELKLHX3M-ClqAnuG8.js} +1 -1
  68. package/dist/worker/console/static/index.html +2 -2
  69. package/dist/workflows/dag/dag-retry-schema.js +3 -0
  70. package/dist/workflows/dag/frontend-design-policy.js +1 -1
  71. package/dist/workflows/dag/frontend-risk.js +2 -0
  72. package/dist/workflows/dag/frontend-shadow-dual-write.js +16 -1
  73. package/dist/workflows/dag/frontend-shape.js +16 -6
  74. package/dist/workflows/dag/frontend-test-execution-evidence.js +48 -0
  75. package/dist/workflows/dag/frontend-verification-trace.js +32 -0
  76. package/dist/workflows/dag/init-hybrid.js +9 -10
  77. package/dist/workflows/dag/node-execution.js +124 -72
  78. package/dist/workflows/dag/rerun-feedback.js +1 -0
  79. package/dist/workflows/dag/rerun-plan.js +90 -4
  80. package/dist/workflows/dag/rerun-run.js +7 -0
  81. package/dist/workflows/dag/retry-policy.js +16 -10
  82. package/dist/workflows/dag/runner-exit-diagnostics.js +125 -0
  83. package/dist/workflows/dag/runner.js +67 -7
  84. package/dist/workflows/dag/structured-output-repair.js +4 -1
  85. package/dist/workflows/dag/validate.js +10 -8
  86. package/dist/workflows/dag/workspace-checkpoint.js +66 -0
  87. package/docs/templates/agent-dag.schema.json +2 -2
  88. package/package.json +1 -1
  89. package/skills/frontend-plan/SKILL.md +6 -1
  90. package/skills/frontend-plan/references/decision-contract.md +69 -18
  91. package/skills/frontend-plan/references/design-decisions.md +32 -0
  92. package/dist/worker/console/static/assets/channel-i1DjpDIw.js +0 -1
  93. package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-DgDRdE1V.js +0 -1
  94. package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-DgDRdE1V.js +0 -1
  95. package/dist/worker/console/static/assets/index-Dh0Gh4X0.css +0 -1
  96. package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-BqXQxfFC.js +0 -1
  97. package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-CXwWNRJl.js +0 -8
@@ -1,5 +1,6 @@
1
1
  import { spawn } from "node:child_process";
2
- import { createHash } from "node:crypto";
2
+ import { createHash, randomUUID } from "node:crypto";
3
+ import { withFrontendTestReporter, parseFrontendTestExecutionReport } from "../workflows/dag/frontend-test-execution-evidence.js";
3
4
  import { appendFileSync, existsSync, mkdirSync, writeFileSync } from "node:fs";
4
5
  import { mkdir, readFile, stat, writeFile } from "node:fs/promises";
5
6
  import path from "node:path";
@@ -1950,6 +1951,23 @@ async function executeFrontendVerificationBundle(input, meta) {
1950
1951
  const bundle = shell.frontendVerificationBundle;
1951
1952
  const cwd = resolveShellCwd(input.cwd, shell.cwd);
1952
1953
  const results = [];
1954
+ const commandResultsByKey = new Map();
1955
+ const commandKey = (command) => `${cwd}\u0000${command.trim()}`;
1956
+ const reuseCommandResult = (result, command) => {
1957
+ const reusedAt = new Date().toISOString();
1958
+ return {
1959
+ ...result,
1960
+ command,
1961
+ durationMs: 0,
1962
+ wallDurationMs: 0,
1963
+ executionDurationMs: result.executionDurationMs ?? result.durationMs,
1964
+ startedAt: reusedAt,
1965
+ finishedAt: reusedAt,
1966
+ stdoutArtifactPath: undefined,
1967
+ stderrArtifactPath: undefined,
1968
+ reused: true,
1969
+ };
1970
+ };
1953
1971
  let beforeStatus;
1954
1972
  try {
1955
1973
  beforeStatus = await readGitStatusPorcelain(input.cwd);
@@ -1958,22 +1976,32 @@ async function executeFrontendVerificationBundle(input, meta) {
1958
1976
  beforeStatus = undefined;
1959
1977
  }
1960
1978
  const lintResults = [];
1979
+ const successfulLabels = new Map();
1980
+ const successfulCommandTexts = new Map();
1981
+ const executedTests = new Map();
1982
+ const commandExecutionEvidence = new Map();
1961
1983
  for (const command of bundle.lintCommands ?? []) {
1962
- const commandNumber = results.length + 1;
1963
- const result = await executeShellCommand({
1964
- command,
1965
- cwd,
1966
- timeoutMs: shell.timeoutMs ?? DEFAULT_SHELL_TIMEOUT_MS,
1967
- envAllowlist: shell.envAllowlist,
1968
- dagRunMeta: { runDir: meta.runDir, runId: meta.runId },
1969
- reportActivity: input.reportActivity,
1970
- outputArtifacts: {
1971
- stdoutPath: path.join(meta.runDir, input.task.id, "commands", `${commandNumber}.stdout.txt`),
1972
- stderrPath: path.join(meta.runDir, input.task.id, "commands", `${commandNumber}.stderr.txt`),
1973
- },
1974
- });
1975
- lintResults.push(result);
1984
+ const key = commandKey(command);
1985
+ const cached = commandResultsByKey.get(key);
1986
+ let result = cached ? reuseCommandResult(cached, command) : undefined;
1987
+ if (!result) {
1988
+ const commandNumber = results.length + 1;
1989
+ result = await executeShellCommand({
1990
+ command,
1991
+ cwd,
1992
+ timeoutMs: shell.timeoutMs ?? DEFAULT_SHELL_TIMEOUT_MS,
1993
+ envAllowlist: shell.envAllowlist,
1994
+ dagRunMeta: { runDir: meta.runDir, runId: meta.runId },
1995
+ reportActivity: input.reportActivity,
1996
+ outputArtifacts: {
1997
+ stdoutPath: path.join(meta.runDir, input.task.id, "commands", `${commandNumber}.stdout.txt`),
1998
+ stderrPath: path.join(meta.runDir, input.task.id, "commands", `${commandNumber}.stderr.txt`),
1999
+ },
2000
+ });
2001
+ commandResultsByKey.set(key, result);
2002
+ }
1976
2003
  results.push(result);
2004
+ lintResults.push(result);
1977
2005
  }
1978
2006
  let lintAssessment;
1979
2007
  if ((bundle.lintCommands?.length ?? 0) > 0 &&
@@ -2007,30 +2035,64 @@ async function executeFrontendVerificationBundle(input, meta) {
2007
2035
  labels: bundle.behaviorEvidence.commandLabels,
2008
2036
  },
2009
2037
  ];
2010
- const successfulLabels = new Map();
2038
+ const failedGroups = new Set();
2039
+ const groupFailures = [];
2011
2040
  for (const group of lintBlocked ? [] : groups) {
2012
2041
  for (const [index, command] of group.commands.entries()) {
2013
- const commandNumber = results.length + 1;
2014
- const result = await executeShellCommand({
2015
- command,
2016
- cwd,
2017
- timeoutMs: shell.timeoutMs ?? DEFAULT_SHELL_TIMEOUT_MS,
2018
- envAllowlist: shell.envAllowlist,
2019
- dagRunMeta: { runDir: meta.runDir, runId: meta.runId },
2020
- reportActivity: input.reportActivity,
2021
- outputArtifacts: {
2022
- stdoutPath: path.join(meta.runDir, input.task.id, "commands", `${commandNumber}.stdout.txt`),
2023
- stderrPath: path.join(meta.runDir, input.task.id, "commands", `${commandNumber}.stderr.txt`),
2024
- },
2025
- });
2042
+ if (failedGroups.has(group.name))
2043
+ break;
2044
+ const key = commandKey(command);
2045
+ const cached = commandResultsByKey.get(key);
2046
+ let result = cached ? reuseCommandResult(cached, command) : undefined;
2047
+ if (!result) {
2048
+ const commandNumber = results.length + 1;
2049
+ const reportPath = path.join(meta.runDir, input.task.id, "commands", `${commandNumber}-${randomUUID()}.vitest.json`);
2050
+ const observedCommand = await withFrontendTestReporter({ command, cwd, reportPath });
2051
+ if (observedCommand)
2052
+ await mkdir(path.dirname(reportPath), { recursive: true });
2053
+ result = await executeShellCommand({
2054
+ command: observedCommand ?? command,
2055
+ cwd,
2056
+ timeoutMs: shell.timeoutMs ?? DEFAULT_SHELL_TIMEOUT_MS,
2057
+ envAllowlist: shell.envAllowlist,
2058
+ dagRunMeta: { runDir: meta.runDir, runId: meta.runId },
2059
+ reportActivity: input.reportActivity,
2060
+ outputArtifacts: {
2061
+ stdoutPath: path.join(meta.runDir, input.task.id, "commands", `${commandNumber}.stdout.txt`),
2062
+ stderrPath: path.join(meta.runDir, input.task.id, "commands", `${commandNumber}.stderr.txt`),
2063
+ },
2064
+ });
2065
+ let reportError;
2066
+ if (observedCommand && result.ok) {
2067
+ try {
2068
+ commandExecutionEvidence.set(key, parseFrontendTestExecutionReport(JSON.parse(await readFile(reportPath, "utf8")), cwd));
2069
+ }
2070
+ catch (error) {
2071
+ reportError = `frontend test execution report unavailable: ${error instanceof Error ? error.message : String(error)}`;
2072
+ }
2073
+ }
2074
+ if (reportError) {
2075
+ result = { ...result, ok: false, failureCategory: "invalid-output", stderr: reportError };
2076
+ }
2077
+ commandResultsByKey.set(key, result);
2078
+ }
2026
2079
  results.push(result);
2027
2080
  if (result.ok && group.labels[index]) {
2081
+ const observations = commandExecutionEvidence.get(key);
2082
+ if (observations !== undefined)
2083
+ executedTests.set(group.labels[index], observations);
2028
2084
  const labels = successfulLabels.get(group.name) ?? [];
2029
2085
  labels.push(group.labels[index]);
2030
2086
  successfulLabels.set(group.name, labels);
2087
+ const texts = successfulCommandTexts.get(group.name) ?? [];
2088
+ texts.push(command);
2089
+ successfulCommandTexts.set(group.name, texts);
2031
2090
  }
2032
- if (!result.ok)
2091
+ if (!result.ok) {
2092
+ groupFailures.push(result);
2093
+ failedGroups.add(group.name);
2033
2094
  break;
2095
+ }
2034
2096
  }
2035
2097
  }
2036
2098
  if (beforeStatus !== undefined) {
@@ -2060,12 +2122,15 @@ async function executeFrontendVerificationBundle(input, meta) {
2060
2122
  exitCode: result.exitCode,
2061
2123
  failureCategory: result.failureCategory,
2062
2124
  command: result.command,
2125
+ reused: result.reused === true,
2063
2126
  }));
2127
+ // Lint baseline-debt is tolerated, so a lint-only failure must not become the
2128
+ // verification failure. A shared lint/static or lint/behavior command is
2129
+ // different: once reused by a non-lint lane, its failure belongs to that lane
2130
+ // and must remain the primary failure evidence.
2064
2131
  const firstFailure = lintBlocked
2065
2132
  ? lintResults.find((result) => !result.ok)
2066
- : results
2067
- .filter((result) => !lintResults.includes(result))
2068
- .find((result) => !result.ok);
2133
+ : groupFailures[0];
2069
2134
  const lintSyntheticFailure = lintBlocked && !firstFailure
2070
2135
  ? {
2071
2136
  failureCategory: "invalid-output",
@@ -2082,7 +2147,7 @@ async function executeFrontendVerificationBundle(input, meta) {
2082
2147
  mock: {
2083
2148
  nodeId: input.task.id,
2084
2149
  commandLabels: successfulLabels.get("mock") ?? [],
2085
- commandTexts: bundle.mockCommands.slice(0, successfulLabels.get("mock")?.length ?? 0),
2150
+ commandTexts: successfulCommandTexts.get("mock") ?? [],
2086
2151
  },
2087
2152
  static: {
2088
2153
  nodeId: input.task.id,
@@ -2091,6 +2156,7 @@ async function executeFrontendVerificationBundle(input, meta) {
2091
2156
  behavior: {
2092
2157
  nodeId: input.task.id,
2093
2158
  commandLabels: successfulLabels.get("behavior") ?? [],
2159
+ executedTests,
2094
2160
  },
2095
2161
  },
2096
2162
  });
@@ -2123,7 +2189,9 @@ async function executeFrontendVerificationBundle(input, meta) {
2123
2189
  nodeId: failedNodeId,
2124
2190
  rawFailureCategory: failureCategory,
2125
2191
  });
2126
- const failureOwner = classifiedOwner === "unknown" ? "implement-pi" : classifiedOwner;
2192
+ const failureOwner = classifiedOwner === "unknown" &&
2193
+ ["typecheck", "build", "lint", "component-test", "unit-test", "trace"].includes(failureClass)
2194
+ ? "implementation" : classifiedOwner;
2127
2195
  const restartPhase = classifyRestartPhase(failureOwner);
2128
2196
  // A+B (AC-008): verification-config routing. Produce structured
2129
2197
  // unresolved entrypoint refs from committed plan facts and the frozen
@@ -63,6 +63,12 @@ const RAW_TO_NORMALIZED = {
63
63
  // compaction / fresh context before retrying — an executor-side
64
64
  // environment condition, not a plan-quality defect.
65
65
  "context-overflow": "executor",
66
+ // stopReason=length output-capacity truncation: same executor-side
67
+ // capacity class as context-overflow. Legacy thinking-exhausted labels
68
+ // (pre-output-limit artifacts) map to the same class.
69
+ "output-limit": "executor",
70
+ "writer-thinking-exhausted": "executor",
71
+ "planner-thinking-exhausted": "executor",
66
72
  // Deterministic capability/policy refusal: missing verified launcher JS
67
73
  // entry, capability allowlist rejection, or missing bounded write tool
68
74
  // profile. These are environment/config defects the operator repairs
@@ -147,7 +147,7 @@ export async function applyTaskContract(input) {
147
147
  ref,
148
148
  changedFiles: [],
149
149
  idempotentReplay: true,
150
- txId: existing.txId,
150
+ ...(existing.txId ? { txId: existing.txId } : { noOp: true }),
151
151
  };
152
152
  }
153
153
  const lock = await acquireTaskContractLock({
@@ -175,7 +175,9 @@ export async function applyTaskContract(input) {
175
175
  ref,
176
176
  changedFiles: [],
177
177
  idempotentReplay: true,
178
- txId: existingUnderLock.txId,
178
+ ...(existingUnderLock.txId
179
+ ? { txId: existingUnderLock.txId }
180
+ : { noOp: true }),
179
181
  };
180
182
  }
181
183
  const state = await observeTaskContractState(input.repoRoot, input.taskId);
@@ -251,6 +253,38 @@ export async function applyTaskContract(input) {
251
253
  sourceHashes,
252
254
  taskConfigSha256,
253
255
  });
256
+ // Content-level no-op: when the freshly projected draft hashes
257
+ // identically to both the recorded contract and the on-disk observation,
258
+ // the journaled commit would only churn revision/updatedAt metadata and
259
+ // force downstream consumers (writeSet gate digest binds
260
+ // contractRevision+contractCanonicalHash) to re-issue approvals for
261
+ // zero content change. Return the current ref untouched instead. A
262
+ // drifted disk (observed !== ref) never reaches this short-circuit: the
263
+ // apply is then a repair projection and must run.
264
+ if (state.ref &&
265
+ canonicalHash === state.ref.canonicalHash &&
266
+ state.observedCanonicalHash === state.ref.canonicalHash) {
267
+ await assertLockHeld(lock);
268
+ await appendRequestLedgerEntry({
269
+ repoRoot: input.repoRoot,
270
+ taskId: input.taskId,
271
+ entry: {
272
+ schemaVersion: 1,
273
+ requestId: input.requestId,
274
+ requestPayloadSha256: input.requestPayloadSha256,
275
+ revision: state.ref.revision,
276
+ canonicalHash: state.ref.canonicalHash,
277
+ recordedAt: new Date().toISOString(),
278
+ resultSummary: { ok: true, operation: "apply" },
279
+ },
280
+ });
281
+ return {
282
+ ref: state.ref,
283
+ changedFiles: [],
284
+ idempotentReplay: false,
285
+ noOp: true,
286
+ };
287
+ }
254
288
  const nextRevision = currentRevision + 1;
255
289
  const nextRef = {
256
290
  schemaVersion: TASK_CONTRACT_REF_SCHEMA_VERSION,
@@ -13,6 +13,13 @@ const HEADING_ALIASES = {
13
13
  "需求范围",
14
14
  "已确认范围",
15
15
  "已确认需求",
16
+ // Common zh-CN frontend-PRD variants seen in real PRDs; without these a
17
+ // raw-PRD fallback parse (semantic intake unavailable) yields an empty
18
+ // scope and flips the import to incomplete (EMPTY scope deadlock).
19
+ "目标表面",
20
+ "交付范围",
21
+ "实现范围",
22
+ "交付内容",
16
23
  ]),
17
24
  nonGoals: new Set(["非目标", "out of scope", "non-goals", "non goals"]),
18
25
  acceptance: new Set([
@@ -22,14 +22,16 @@ import path from "node:path";
22
22
  import { ensureSecureDir, writeSecureJsonSync, } from "../../../infrastructure/console/app-data.js";
23
23
  import { isTerminalOperationState, } from "../../../infrastructure/console/operation-store.js";
24
24
  import { scrubSecrets } from "./explore-tools.js";
25
- const OPERATION_PREVIEW_MAX_CHARS = 1200;
25
+ /** Bounded preview stored on the event ring / SSE (not the live tool payload). */
26
+ export const OPERATION_PREVIEW_MAX_CHARS = 4000;
27
+ const OPERATION_PREVIEW_TRUNCATION_SUFFIX = "…[truncated]";
26
28
  function boundedRedactedText(value, maxChars = OPERATION_PREVIEW_MAX_CHARS) {
27
29
  if (typeof value !== "string" || !value.trim())
28
30
  return undefined;
29
31
  const { scrubbed } = scrubSecrets(value);
30
32
  return scrubbed.length <= maxChars
31
33
  ? scrubbed
32
- : `${scrubbed.slice(0, maxChars)}…[truncated]`;
34
+ : `${scrubbed.slice(0, maxChars)}${OPERATION_PREVIEW_TRUNCATION_SUFFIX}`;
33
35
  }
34
36
  function safeIdentity(value) {
35
37
  return boundedRedactedText(value, 240);
@@ -1 +1 @@
1
- import{g as p,r as u,d as a}from"./chunk-6Q2QTUOP-JPqDS3IV.js";import{p as f}from"./chunk-JWPE2WC7-pEyTjekV.js";import{_ as n,l as o}from"./mermaid.core-B6Lxil0V.js";import{M as c,b as d}from"./cynefin-VYW2F7L2-DDd-t7fm.js";import"./index-BmMi-Bve.js";var v=d().RailroadAbnf.parser.LangiumParser,i=n(e=>{const r=e.alternatives.map(g);return r.length===1?r[0]:{type:"choice",alternatives:r}},"transformAlternation"),g=n(e=>{const r=e.elements.map(y);return r.length===1?r[0]:{type:"sequence",elements:r}},"transformConcatenation"),b=n(e=>{if(e.includes("*")){const[t,s]=e.split("*"),l=t?parseInt(t,10):0,m=s?parseInt(s,10):1/0;return{min:l,max:m}}const r=parseInt(e,10);return{min:r,max:r}},"parseRepeat"),y=n(e=>{const r=A(e.primary);if(!e.repeat)return r;const{min:t,max:s}=b(e.repeat);return t===0&&s===1?{type:"optional",element:r}:{type:"repetition",element:r,min:t,max:s}},"transformElement"),A=n(e=>{switch(e.$type){case"AbnfStringLiteral":return{type:"terminal",value:e.value};case"AbnfNumVal":return{type:"terminal",value:e.value};case"AbnfRuleName":return{type:"nonterminal",name:e.name};case"AbnfGroup":return i(e.element);case"AbnfOptionalGroup":return{type:"optional",element:i(e.element)};default:throw new Error(`Unsupported ABNF primary node: ${e.$type}`)}},"transformPrimary"),P=n(e=>({name:e.name,definition:i(e.definition)}),"transformRule"),h=n(e=>{f(e,a),e.title&&a.setTitle(e.title),e.rules.map(r=>a.addRule(P(r)))},"populateDb"),R={parse:n(e=>{a.clear(),o.debug("[ABNF Parser] Starting Langium parse");const r=v.parse(e);if(r.lexerErrors.length>0||r.parserErrors.length>0)throw new c(r);const t=r.value;o.debug("[ABNF Parser] Parsed rules:",t.rules.length),h(t),o.debug("[ABNF Parser] Parse complete")},"parse"),parser:{yy:a}},B={parser:R,db:a,renderer:u,styles:p};export{B as diagram};
1
+ import{g as p,r as u,d as a}from"./chunk-6Q2QTUOP-Begg4WAa.js";import{p as f}from"./chunk-JWPE2WC7-BqbsWXZb.js";import{_ as n,l as o}from"./mermaid.core-BUuGHmWO.js";import{M as c,b as d}from"./cynefin-VYW2F7L2-BoAVG3cs.js";import"./index-C0O48S_P.js";var v=d().RailroadAbnf.parser.LangiumParser,i=n(e=>{const r=e.alternatives.map(g);return r.length===1?r[0]:{type:"choice",alternatives:r}},"transformAlternation"),g=n(e=>{const r=e.elements.map(y);return r.length===1?r[0]:{type:"sequence",elements:r}},"transformConcatenation"),b=n(e=>{if(e.includes("*")){const[t,s]=e.split("*"),l=t?parseInt(t,10):0,m=s?parseInt(s,10):1/0;return{min:l,max:m}}const r=parseInt(e,10);return{min:r,max:r}},"parseRepeat"),y=n(e=>{const r=A(e.primary);if(!e.repeat)return r;const{min:t,max:s}=b(e.repeat);return t===0&&s===1?{type:"optional",element:r}:{type:"repetition",element:r,min:t,max:s}},"transformElement"),A=n(e=>{switch(e.$type){case"AbnfStringLiteral":return{type:"terminal",value:e.value};case"AbnfNumVal":return{type:"terminal",value:e.value};case"AbnfRuleName":return{type:"nonterminal",name:e.name};case"AbnfGroup":return i(e.element);case"AbnfOptionalGroup":return{type:"optional",element:i(e.element)};default:throw new Error(`Unsupported ABNF primary node: ${e.$type}`)}},"transformPrimary"),P=n(e=>({name:e.name,definition:i(e.definition)}),"transformRule"),h=n(e=>{f(e,a),e.title&&a.setTitle(e.title),e.rules.map(r=>a.addRule(P(r)))},"populateDb"),R={parse:n(e=>{a.clear(),o.debug("[ABNF Parser] Starting Langium parse");const r=v.parse(e);if(r.lexerErrors.length>0||r.parserErrors.length>0)throw new c(r);const t=r.value;o.debug("[ABNF Parser] Parsed rules:",t.rules.length),h(t),o.debug("[ABNF Parser] Parse complete")},"parse"),parser:{yy:a}},B={parser:R,db:a,renderer:u,styles:p};export{B as diagram};
@@ -1 +1 @@
1
- import{Y as ln,$ as an,a0 as F,a1 as q,a2 as j,a3 as un,a4 as y,a5 as tn,a6 as J,a7 as _,a8 as rn,a9 as o,aa as on,ab as sn,ac as fn}from"./mermaid.core-B6Lxil0V.js";function cn(l){return l.innerRadius}function yn(l){return l.outerRadius}function gn(l){return l.startAngle}function dn(l){return l.endAngle}function mn(l){return l&&l.padAngle}function pn(l,h,I,D,v,A,z,a){var O=I-l,i=D-h,n=z-v,d=a-A,u=d*O-n*i;if(!(u*u<y))return u=(n*(h-A)-d*(l-v))/u,[l+u*O,h+u*i]}function U(l,h,I,D,v,A,z){var a=l-I,O=h-D,i=(z?A:-A)/J(a*a+O*O),n=i*O,d=-i*a,u=l+n,s=h+d,f=I+n,c=D+d,B=(u+f)/2,t=(s+c)/2,m=f-u,g=c-s,R=m*m+g*g,T=v-A,P=u*c-f*s,S=(g<0?-1:1)*J(on(0,T*T*R-P*P)),Y=(P*g-m*S)/R,$=(-P*m-g*S)/R,w=(P*g+m*S)/R,p=(-P*m+g*S)/R,x=Y-B,e=$-t,r=w-B,C=p-t;return x*x+e*e>r*r+C*C&&(Y=w,$=p),{cx:Y,cy:$,x01:-n,y01:-d,x11:Y*(v/T-1),y11:$*(v/T-1)}}function hn(){var l=cn,h=yn,I=j(0),D=null,v=gn,A=dn,z=mn,a=null,O=ln(i);function i(){var n,d,u=+l.apply(this,arguments),s=+h.apply(this,arguments),f=v.apply(this,arguments)-un,c=A.apply(this,arguments)-un,B=rn(c-f),t=c>f;if(a||(a=n=O()),s<u&&(d=s,s=u,u=d),!(s>y))a.moveTo(0,0);else if(B>tn-y)a.moveTo(s*F(f),s*q(f)),a.arc(0,0,s,f,c,!t),u>y&&(a.moveTo(u*F(c),u*q(c)),a.arc(0,0,u,c,f,t));else{var m=f,g=c,R=f,T=c,P=B,S=B,Y=z.apply(this,arguments)/2,$=Y>y&&(D?+D.apply(this,arguments):J(u*u+s*s)),w=_(rn(s-u)/2,+I.apply(this,arguments)),p=w,x=w,e,r;if($>y){var C=sn($/u*q(Y)),K=sn($/s*q(Y));(P-=C*2)>y?(C*=t?1:-1,R+=C,T-=C):(P=0,R=T=(f+c)/2),(S-=K*2)>y?(K*=t?1:-1,m+=K,g-=K):(S=0,m=g=(f+c)/2)}var G=s*F(m),H=s*q(m),L=u*F(T),M=u*q(T);if(w>y){var N=s*F(g),Q=s*q(g),V=u*F(R),W=u*q(R),E;if(B<an)if(E=pn(G,H,V,W,N,Q,L,M)){var X=G-E[0],Z=H-E[1],b=N-E[0],k=Q-E[1],nn=1/q(fn((X*b+Z*k)/(J(X*X+Z*Z)*J(b*b+k*k)))/2),en=J(E[0]*E[0]+E[1]*E[1]);p=_(w,(u-en)/(nn-1)),x=_(w,(s-en)/(nn+1))}else p=x=0}S>y?x>y?(e=U(V,W,G,H,s,x,t),r=U(N,Q,L,M,s,x,t),a.moveTo(e.cx+e.x01,e.cy+e.y01),x<w?a.arc(e.cx,e.cy,x,o(e.y01,e.x01),o(r.y01,r.x01),!t):(a.arc(e.cx,e.cy,x,o(e.y01,e.x01),o(e.y11,e.x11),!t),a.arc(0,0,s,o(e.cy+e.y11,e.cx+e.x11),o(r.cy+r.y11,r.cx+r.x11),!t),a.arc(r.cx,r.cy,x,o(r.y11,r.x11),o(r.y01,r.x01),!t))):(a.moveTo(G,H),a.arc(0,0,s,m,g,!t)):a.moveTo(G,H),!(u>y)||!(P>y)?a.lineTo(L,M):p>y?(e=U(L,M,N,Q,u,-p,t),r=U(G,H,V,W,u,-p,t),a.lineTo(e.cx+e.x01,e.cy+e.y01),p<w?a.arc(e.cx,e.cy,p,o(e.y01,e.x01),o(r.y01,r.x01),!t):(a.arc(e.cx,e.cy,p,o(e.y01,e.x01),o(e.y11,e.x11),!t),a.arc(0,0,u,o(e.cy+e.y11,e.cx+e.x11),o(r.cy+r.y11,r.cx+r.x11),t),a.arc(r.cx,r.cy,p,o(r.y11,r.x11),o(r.y01,r.x01),!t))):a.arc(0,0,u,T,R,t)}if(a.closePath(),n)return a=null,n+""||null}return i.centroid=function(){var n=(+l.apply(this,arguments)+ +h.apply(this,arguments))/2,d=(+v.apply(this,arguments)+ +A.apply(this,arguments))/2-an/2;return[F(d)*n,q(d)*n]},i.innerRadius=function(n){return arguments.length?(l=typeof n=="function"?n:j(+n),i):l},i.outerRadius=function(n){return arguments.length?(h=typeof n=="function"?n:j(+n),i):h},i.cornerRadius=function(n){return arguments.length?(I=typeof n=="function"?n:j(+n),i):I},i.padRadius=function(n){return arguments.length?(D=n==null?null:typeof n=="function"?n:j(+n),i):D},i.startAngle=function(n){return arguments.length?(v=typeof n=="function"?n:j(+n),i):v},i.endAngle=function(n){return arguments.length?(A=typeof n=="function"?n:j(+n),i):A},i.padAngle=function(n){return arguments.length?(z=typeof n=="function"?n:j(+n),i):z},i.context=function(n){return arguments.length?(a=n??null,i):a},i}export{hn as d};
1
+ import{Y as ln,$ as an,a0 as F,a1 as q,a2 as j,a3 as un,a4 as y,a5 as tn,a6 as J,a7 as _,a8 as rn,a9 as o,aa as on,ab as sn,ac as fn}from"./mermaid.core-BUuGHmWO.js";function cn(l){return l.innerRadius}function yn(l){return l.outerRadius}function gn(l){return l.startAngle}function dn(l){return l.endAngle}function mn(l){return l&&l.padAngle}function pn(l,h,I,D,v,A,z,a){var O=I-l,i=D-h,n=z-v,d=a-A,u=d*O-n*i;if(!(u*u<y))return u=(n*(h-A)-d*(l-v))/u,[l+u*O,h+u*i]}function U(l,h,I,D,v,A,z){var a=l-I,O=h-D,i=(z?A:-A)/J(a*a+O*O),n=i*O,d=-i*a,u=l+n,s=h+d,f=I+n,c=D+d,B=(u+f)/2,t=(s+c)/2,m=f-u,g=c-s,R=m*m+g*g,T=v-A,P=u*c-f*s,S=(g<0?-1:1)*J(on(0,T*T*R-P*P)),Y=(P*g-m*S)/R,$=(-P*m-g*S)/R,w=(P*g+m*S)/R,p=(-P*m+g*S)/R,x=Y-B,e=$-t,r=w-B,C=p-t;return x*x+e*e>r*r+C*C&&(Y=w,$=p),{cx:Y,cy:$,x01:-n,y01:-d,x11:Y*(v/T-1),y11:$*(v/T-1)}}function hn(){var l=cn,h=yn,I=j(0),D=null,v=gn,A=dn,z=mn,a=null,O=ln(i);function i(){var n,d,u=+l.apply(this,arguments),s=+h.apply(this,arguments),f=v.apply(this,arguments)-un,c=A.apply(this,arguments)-un,B=rn(c-f),t=c>f;if(a||(a=n=O()),s<u&&(d=s,s=u,u=d),!(s>y))a.moveTo(0,0);else if(B>tn-y)a.moveTo(s*F(f),s*q(f)),a.arc(0,0,s,f,c,!t),u>y&&(a.moveTo(u*F(c),u*q(c)),a.arc(0,0,u,c,f,t));else{var m=f,g=c,R=f,T=c,P=B,S=B,Y=z.apply(this,arguments)/2,$=Y>y&&(D?+D.apply(this,arguments):J(u*u+s*s)),w=_(rn(s-u)/2,+I.apply(this,arguments)),p=w,x=w,e,r;if($>y){var C=sn($/u*q(Y)),K=sn($/s*q(Y));(P-=C*2)>y?(C*=t?1:-1,R+=C,T-=C):(P=0,R=T=(f+c)/2),(S-=K*2)>y?(K*=t?1:-1,m+=K,g-=K):(S=0,m=g=(f+c)/2)}var G=s*F(m),H=s*q(m),L=u*F(T),M=u*q(T);if(w>y){var N=s*F(g),Q=s*q(g),V=u*F(R),W=u*q(R),E;if(B<an)if(E=pn(G,H,V,W,N,Q,L,M)){var X=G-E[0],Z=H-E[1],b=N-E[0],k=Q-E[1],nn=1/q(fn((X*b+Z*k)/(J(X*X+Z*Z)*J(b*b+k*k)))/2),en=J(E[0]*E[0]+E[1]*E[1]);p=_(w,(u-en)/(nn-1)),x=_(w,(s-en)/(nn+1))}else p=x=0}S>y?x>y?(e=U(V,W,G,H,s,x,t),r=U(N,Q,L,M,s,x,t),a.moveTo(e.cx+e.x01,e.cy+e.y01),x<w?a.arc(e.cx,e.cy,x,o(e.y01,e.x01),o(r.y01,r.x01),!t):(a.arc(e.cx,e.cy,x,o(e.y01,e.x01),o(e.y11,e.x11),!t),a.arc(0,0,s,o(e.cy+e.y11,e.cx+e.x11),o(r.cy+r.y11,r.cx+r.x11),!t),a.arc(r.cx,r.cy,x,o(r.y11,r.x11),o(r.y01,r.x01),!t))):(a.moveTo(G,H),a.arc(0,0,s,m,g,!t)):a.moveTo(G,H),!(u>y)||!(P>y)?a.lineTo(L,M):p>y?(e=U(L,M,N,Q,u,-p,t),r=U(G,H,V,W,u,-p,t),a.lineTo(e.cx+e.x01,e.cy+e.y01),p<w?a.arc(e.cx,e.cy,p,o(e.y01,e.x01),o(r.y01,r.x01),!t):(a.arc(e.cx,e.cy,p,o(e.y01,e.x01),o(e.y11,e.x11),!t),a.arc(0,0,u,o(e.cy+e.y11,e.cx+e.x11),o(r.cy+r.y11,r.cx+r.x11),t),a.arc(r.cx,r.cy,p,o(r.y11,r.x11),o(r.y01,r.x01),!t))):a.arc(0,0,u,T,R,t)}if(a.closePath(),n)return a=null,n+""||null}return i.centroid=function(){var n=(+l.apply(this,arguments)+ +h.apply(this,arguments))/2,d=(+v.apply(this,arguments)+ +A.apply(this,arguments))/2-an/2;return[F(d)*n,q(d)*n]},i.innerRadius=function(n){return arguments.length?(l=typeof n=="function"?n:j(+n),i):l},i.outerRadius=function(n){return arguments.length?(h=typeof n=="function"?n:j(+n),i):h},i.cornerRadius=function(n){return arguments.length?(I=typeof n=="function"?n:j(+n),i):I},i.padRadius=function(n){return arguments.length?(D=n==null?null:typeof n=="function"?n:j(+n),i):D},i.startAngle=function(n){return arguments.length?(v=typeof n=="function"?n:j(+n),i):v},i.endAngle=function(n){return arguments.length?(A=typeof n=="function"?n:j(+n),i):A},i.padAngle=function(n){return arguments.length?(z=typeof n=="function"?n:j(+n),i):z},i.context=function(n){return arguments.length?(a=n??null,i):a},i}export{hn as d};