perttool 0.5.5 → 0.7.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 (265) hide show
  1. package/CHANGELOG.md +71 -1
  2. package/README.md +128 -30
  3. package/dist/application/advance-history.d.ts +48 -0
  4. package/dist/application/advance-history.d.ts.map +1 -0
  5. package/dist/application/advance-history.js +263 -0
  6. package/dist/application/advance-history.js.map +1 -0
  7. package/dist/application/contract6-mutation.d.ts +3 -2
  8. package/dist/application/contract6-mutation.d.ts.map +1 -1
  9. package/dist/application/contract6-mutation.js +2 -1
  10. package/dist/application/contract6-mutation.js.map +1 -1
  11. package/dist/application/contract6-projection.d.ts +2 -1
  12. package/dist/application/contract6-projection.d.ts.map +1 -1
  13. package/dist/application/contract6-projection.js +31 -1
  14. package/dist/application/contract6-projection.js.map +1 -1
  15. package/dist/application/contract7-assurance.d.ts +57 -0
  16. package/dist/application/contract7-assurance.d.ts.map +1 -0
  17. package/dist/application/contract7-assurance.js +248 -0
  18. package/dist/application/contract7-assurance.js.map +1 -0
  19. package/dist/application/contract7-mermaid.d.ts +9 -0
  20. package/dist/application/contract7-mermaid.d.ts.map +1 -0
  21. package/dist/application/contract7-mermaid.js +73 -0
  22. package/dist/application/contract7-mermaid.js.map +1 -0
  23. package/dist/application/contract7-mutation.d.ts +21 -0
  24. package/dist/application/contract7-mutation.d.ts.map +1 -0
  25. package/dist/application/contract7-mutation.js +181 -0
  26. package/dist/application/contract7-mutation.js.map +1 -0
  27. package/dist/application/contract7-project.d.ts +10 -0
  28. package/dist/application/contract7-project.d.ts.map +1 -0
  29. package/dist/application/contract7-project.js +29 -0
  30. package/dist/application/contract7-project.js.map +1 -0
  31. package/dist/application/contract7-projection.d.ts +9 -0
  32. package/dist/application/contract7-projection.d.ts.map +1 -0
  33. package/dist/application/contract7-projection.js +100 -0
  34. package/dist/application/contract7-projection.js.map +1 -0
  35. package/dist/application/contract7-source.d.ts +24 -0
  36. package/dist/application/contract7-source.d.ts.map +1 -0
  37. package/dist/application/contract7-source.js +54 -0
  38. package/dist/application/contract7-source.js.map +1 -0
  39. package/dist/application/contract7-unit-migration.d.ts +13 -0
  40. package/dist/application/contract7-unit-migration.d.ts.map +1 -0
  41. package/dist/application/contract7-unit-migration.js +13 -0
  42. package/dist/application/contract7-unit-migration.js.map +1 -0
  43. package/dist/application/init.d.ts +1 -1
  44. package/dist/application/init.js +3 -3
  45. package/dist/application/mutate.d.ts +5 -1
  46. package/dist/application/mutate.d.ts.map +1 -1
  47. package/dist/application/mutate.js +2 -2
  48. package/dist/application/mutate.js.map +1 -1
  49. package/dist/application/target-actuals-analysis.d.ts +5 -4
  50. package/dist/application/target-actuals-analysis.d.ts.map +1 -1
  51. package/dist/application/target-actuals-analysis.js +18 -11
  52. package/dist/application/target-actuals-analysis.js.map +1 -1
  53. package/dist/application/target-actuals-mutation.d.ts +5 -3
  54. package/dist/application/target-actuals-mutation.d.ts.map +1 -1
  55. package/dist/application/target-actuals-mutation.js +16 -8
  56. package/dist/application/target-actuals-mutation.js.map +1 -1
  57. package/dist/application/target-actuals-write.d.ts +2 -1
  58. package/dist/application/target-actuals-write.d.ts.map +1 -1
  59. package/dist/application/target-actuals-write.js.map +1 -1
  60. package/dist/application/target-assurance-advance-history.d.ts +19 -0
  61. package/dist/application/target-assurance-advance-history.d.ts.map +1 -0
  62. package/dist/application/target-assurance-advance-history.js +61 -0
  63. package/dist/application/target-assurance-advance-history.js.map +1 -0
  64. package/dist/application/target-assurance-analysis.d.ts +34 -0
  65. package/dist/application/target-assurance-analysis.d.ts.map +1 -0
  66. package/dist/application/target-assurance-analysis.js +103 -0
  67. package/dist/application/target-assurance-analysis.js.map +1 -0
  68. package/dist/application/target-assurance-inspection.d.ts +38 -0
  69. package/dist/application/target-assurance-inspection.d.ts.map +1 -0
  70. package/dist/application/target-assurance-inspection.js +356 -0
  71. package/dist/application/target-assurance-inspection.js.map +1 -0
  72. package/dist/application/target-assurance-write.d.ts +22 -0
  73. package/dist/application/target-assurance-write.d.ts.map +1 -0
  74. package/dist/application/target-assurance-write.js +73 -0
  75. package/dist/application/target-assurance-write.js.map +1 -0
  76. package/dist/application/target-governance-init.d.ts +3 -3
  77. package/dist/application/target-governance-init.d.ts.map +1 -1
  78. package/dist/application/target-governance-init.js +14 -10
  79. package/dist/application/target-governance-init.js.map +1 -1
  80. package/dist/application/target-governance-project.d.ts +6 -4
  81. package/dist/application/target-governance-project.d.ts.map +1 -1
  82. package/dist/application/target-governance-project.js +18 -4
  83. package/dist/application/target-governance-project.js.map +1 -1
  84. package/dist/application/target-mutate.d.ts +7 -1
  85. package/dist/application/target-mutate.d.ts.map +1 -1
  86. package/dist/application/target-mutate.js +50 -3
  87. package/dist/application/target-mutate.js.map +1 -1
  88. package/dist/application/target-project-history.d.ts +4 -4
  89. package/dist/application/target-project-history.d.ts.map +1 -1
  90. package/dist/application/target-project-history.js +1 -1
  91. package/dist/application/target-project-history.js.map +1 -1
  92. package/dist/application/target-unit-migration-candidate.d.ts +29 -6
  93. package/dist/application/target-unit-migration-candidate.d.ts.map +1 -1
  94. package/dist/application/target-unit-migration-candidate.js +204 -3
  95. package/dist/application/target-unit-migration-candidate.js.map +1 -1
  96. package/dist/application/target-unit-migration-result.d.ts +2 -2
  97. package/dist/application/target-unit-migration-result.d.ts.map +1 -1
  98. package/dist/application/target-unit-migration-result.js +4 -2
  99. package/dist/application/target-unit-migration-result.js.map +1 -1
  100. package/dist/application/target-velocity-observation.d.ts +1 -1
  101. package/dist/application/target-velocity-observation.js +1 -1
  102. package/dist/assurance/advance.d.ts +45 -0
  103. package/dist/assurance/advance.d.ts.map +1 -0
  104. package/dist/assurance/advance.js +507 -0
  105. package/dist/assurance/advance.js.map +1 -0
  106. package/dist/assurance/authority.d.ts +86 -0
  107. package/dist/assurance/authority.d.ts.map +1 -0
  108. package/dist/assurance/authority.js +269 -0
  109. package/dist/assurance/authority.js.map +1 -0
  110. package/dist/assurance/canonical.d.ts +13 -0
  111. package/dist/assurance/canonical.d.ts.map +1 -0
  112. package/dist/assurance/canonical.js +320 -0
  113. package/dist/assurance/canonical.js.map +1 -0
  114. package/dist/assurance/compatibility.d.ts +62 -0
  115. package/dist/assurance/compatibility.d.ts.map +1 -0
  116. package/dist/assurance/compatibility.js +163 -0
  117. package/dist/assurance/compatibility.js.map +1 -0
  118. package/dist/assurance/evaluate.d.ts +4 -0
  119. package/dist/assurance/evaluate.d.ts.map +1 -0
  120. package/dist/assurance/evaluate.js +631 -0
  121. package/dist/assurance/evaluate.js.map +1 -0
  122. package/dist/assurance/governance.d.ts +42 -0
  123. package/dist/assurance/governance.d.ts.map +1 -0
  124. package/dist/assurance/governance.js +95 -0
  125. package/dist/assurance/governance.js.map +1 -0
  126. package/dist/assurance/mermaid.d.ts +40 -0
  127. package/dist/assurance/mermaid.d.ts.map +1 -0
  128. package/dist/assurance/mermaid.js +401 -0
  129. package/dist/assurance/mermaid.js.map +1 -0
  130. package/dist/assurance/mutation.d.ts +96 -0
  131. package/dist/assurance/mutation.d.ts.map +1 -0
  132. package/dist/assurance/mutation.js +757 -0
  133. package/dist/assurance/mutation.js.map +1 -0
  134. package/dist/assurance/source.d.ts +20 -0
  135. package/dist/assurance/source.d.ts.map +1 -0
  136. package/dist/assurance/source.js +313 -0
  137. package/dist/assurance/source.js.map +1 -0
  138. package/dist/assurance/types.d.ts +166 -0
  139. package/dist/assurance/types.d.ts.map +1 -0
  140. package/dist/assurance/types.js +3 -0
  141. package/dist/assurance/types.js.map +1 -0
  142. package/dist/cli.js +431 -72
  143. package/dist/cli.js.map +1 -1
  144. package/dist/command/actuals-discovery.d.ts.map +1 -1
  145. package/dist/command/actuals-discovery.js +50 -4
  146. package/dist/command/actuals-discovery.js.map +1 -1
  147. package/dist/command/assurance-discovery.d.ts +17 -0
  148. package/dist/command/assurance-discovery.d.ts.map +1 -0
  149. package/dist/command/assurance-discovery.js +287 -0
  150. package/dist/command/assurance-discovery.js.map +1 -0
  151. package/dist/command/assurance-usage.d.ts +20 -0
  152. package/dist/command/assurance-usage.d.ts.map +1 -0
  153. package/dist/command/assurance-usage.js +66 -0
  154. package/dist/command/assurance-usage.js.map +1 -0
  155. package/dist/conversion/mermaid.d.ts +2 -1
  156. package/dist/conversion/mermaid.d.ts.map +1 -1
  157. package/dist/conversion/mermaid.js +2 -2
  158. package/dist/conversion/mermaid.js.map +1 -1
  159. package/dist/formatter/source-formatter.d.ts +1 -1
  160. package/dist/formatter/source-formatter.d.ts.map +1 -1
  161. package/dist/formatter/source-formatter.js +56 -4
  162. package/dist/formatter/source-formatter.js.map +1 -1
  163. package/dist/formatter/target-source-formatter.d.ts +2 -1
  164. package/dist/formatter/target-source-formatter.d.ts.map +1 -1
  165. package/dist/formatter/target-source-formatter.js +18 -2
  166. package/dist/formatter/target-source-formatter.js.map +1 -1
  167. package/dist/help/assurance-guide.d.ts +10 -0
  168. package/dist/help/assurance-guide.d.ts.map +1 -0
  169. package/dist/help/assurance-guide.js +115 -0
  170. package/dist/help/assurance-guide.js.map +1 -0
  171. package/dist/help/guide.d.ts +1 -1
  172. package/dist/help/guide.d.ts.map +1 -1
  173. package/dist/help/registry.d.ts.map +1 -1
  174. package/dist/help/registry.js +11 -1
  175. package/dist/help/registry.js.map +1 -1
  176. package/dist/history/advance-history.d.ts +46 -0
  177. package/dist/history/advance-history.d.ts.map +1 -0
  178. package/dist/history/advance-history.js +425 -0
  179. package/dist/history/advance-history.js.map +1 -0
  180. package/dist/history/git-probe.d.ts +40 -0
  181. package/dist/history/git-probe.d.ts.map +1 -1
  182. package/dist/history/git-probe.js +330 -0
  183. package/dist/history/git-probe.js.map +1 -1
  184. package/dist/history/project-history.d.ts +14 -5
  185. package/dist/history/project-history.d.ts.map +1 -1
  186. package/dist/history/project-history.js +25 -18
  187. package/dist/history/project-history.js.map +1 -1
  188. package/dist/index.d.ts +31 -25
  189. package/dist/index.d.ts.map +1 -1
  190. package/dist/index.js +12 -14
  191. package/dist/index.js.map +1 -1
  192. package/dist/io/target-safe-write.d.ts +4 -1
  193. package/dist/io/target-safe-write.d.ts.map +1 -1
  194. package/dist/io/target-safe-write.js +19 -1
  195. package/dist/io/target-safe-write.js.map +1 -1
  196. package/dist/migration/grammar-boundary.d.ts +1 -1
  197. package/dist/migration/grammar-boundary.d.ts.map +1 -1
  198. package/dist/migration/grammar-boundary.js +7 -3
  199. package/dist/migration/grammar-boundary.js.map +1 -1
  200. package/dist/model/declaration-fields.d.ts +12 -0
  201. package/dist/model/declaration-fields.d.ts.map +1 -1
  202. package/dist/model/declaration-fields.js +45 -0
  203. package/dist/model/declaration-fields.js.map +1 -1
  204. package/dist/model/syntax.d.ts +17 -1
  205. package/dist/model/syntax.d.ts.map +1 -1
  206. package/dist/model/syntax.js.map +1 -1
  207. package/dist/mutation/actuals.js +1 -1
  208. package/dist/mutation/actuals.js.map +1 -1
  209. package/dist/mutation/advance-deletion.d.ts +14 -0
  210. package/dist/mutation/advance-deletion.d.ts.map +1 -0
  211. package/dist/mutation/advance-deletion.js +53 -0
  212. package/dist/mutation/advance-deletion.js.map +1 -0
  213. package/dist/mutation/advance.d.ts +18 -1
  214. package/dist/mutation/advance.d.ts.map +1 -1
  215. package/dist/mutation/advance.js +28 -25
  216. package/dist/mutation/advance.js.map +1 -1
  217. package/dist/mutation/project.d.ts +2 -1
  218. package/dist/mutation/project.d.ts.map +1 -1
  219. package/dist/mutation/project.js +21 -0
  220. package/dist/mutation/project.js.map +1 -1
  221. package/dist/parser/document-parser.d.ts +7 -0
  222. package/dist/parser/document-parser.d.ts.map +1 -1
  223. package/dist/parser/document-parser.js +227 -12
  224. package/dist/parser/document-parser.js.map +1 -1
  225. package/dist/recommendation/override-types.d.ts +2 -2
  226. package/dist/recommendation/override.d.ts +2 -2
  227. package/dist/recommendation/override.d.ts.map +1 -1
  228. package/dist/recommendation/override.js +13 -5
  229. package/dist/recommendation/override.js.map +1 -1
  230. package/dist/schema/registry.d.ts +1 -1
  231. package/dist/schema/registry.d.ts.map +1 -1
  232. package/dist/schema/registry.js +8 -6
  233. package/dist/schema/registry.js.map +1 -1
  234. package/dist/semantic/target-validator.d.ts +12 -1
  235. package/dist/semantic/target-validator.d.ts.map +1 -1
  236. package/dist/semantic/target-validator.js +47 -2
  237. package/dist/semantic/target-validator.js.map +1 -1
  238. package/dist/semantic/validator.d.ts +1 -0
  239. package/dist/semantic/validator.d.ts.map +1 -1
  240. package/dist/semantic/validator.js +304 -0
  241. package/dist/semantic/validator.js.map +1 -1
  242. package/dist/version.d.ts +1 -1
  243. package/dist/version.js +1 -1
  244. package/package.json +1 -1
  245. package/schemas/Perttool.AdvanceResult.v2.schema.json +334 -0
  246. package/schemas/Perttool.AgentGuidanceResult.v1.schema.json +1 -1
  247. package/schemas/{Perttool.AnalysisResult.v4.schema.json → Perttool.AnalysisResult.v5.schema.json} +10 -6
  248. package/schemas/{Perttool.CheckResult.v3.schema.json → Perttool.CheckResult.v4.schema.json} +14 -6
  249. package/schemas/Perttool.CliError.v1.schema.json +1 -1
  250. package/schemas/Perttool.CommandHelpResult.v1.schema.json +2 -2
  251. package/schemas/Perttool.Common.v1.schema.json +300 -4
  252. package/schemas/Perttool.ExportResult.v1.schema.json +1 -1
  253. package/schemas/Perttool.FormatResult.v1.schema.json +1 -1
  254. package/schemas/Perttool.GuideResult.v1.schema.json +1 -1
  255. package/schemas/Perttool.ImportResult.v1.schema.json +1 -1
  256. package/schemas/Perttool.InitResult.v1.schema.json +1 -1
  257. package/schemas/{Perttool.MutationResult.v3.schema.json → Perttool.MutationResult.v4.schema.json} +16 -5
  258. package/schemas/{Perttool.NextResult.v5.schema.json → Perttool.NextResult.v6.schema.json} +53 -8
  259. package/schemas/Perttool.OverrideDecision.v1.schema.json +1 -1
  260. package/schemas/Perttool.PlanAssuranceResult.v1.schema.json +77 -0
  261. package/schemas/Perttool.ProjectHistoryResult.v1.schema.json +1 -1
  262. package/schemas/{Perttool.ProjectResult.v3.schema.json → Perttool.ProjectResult.v4.schema.json} +15 -7
  263. package/schemas/Perttool.SchemaResult.v1.schema.json +1 -1
  264. package/schemas/Perttool.UnitMigrationResult.v3.schema.json +5 -3
  265. package/schemas/Perttool.VelocityObservationResult.v1.schema.json +1 -1
package/dist/cli.js CHANGED
@@ -1,36 +1,43 @@
1
1
  #!/usr/bin/env node
2
- import { readFile } from "node:fs/promises";
2
+ import { lstat, readFile } from "node:fs/promises";
3
3
  import process from "node:process";
4
4
  import { TextDecoder } from "node:util";
5
- import { analyzeDocument, selectNextTasks, } from "./application/contract6-actuals.js";
6
- import { checkDocument } from "./application/check.js";
7
- import { planFormat } from "./application/format.js";
5
+ import { analyzeDocument, checkDocument, selectNextTasks, } from "./application/contract7-assurance.js";
6
+ import { planFormat, } from "./application/contract7-source.js";
8
7
  import { planProjectInit, projectInitResultToJson, renderProjectInitResult, withProjectInitOutput, } from "./application/init.js";
9
- import { planUnitMigration, withUnitMigrationWrite, } from "./application/unit-migration.js";
10
- import { getProjectMetadata, } from "./application/project.js";
11
- import { planAdvance, planBatchMutation, planFinishActuals, planLifecycle, planMutation, } from "./application/contract6-mutation.js";
12
- import { renderTargetGovernanceDecision, renderTargetGovernanceProjectText, } from "./application/target-governance-projection.js";
13
- import { contract6MutationResultToJson, contract6ProjectResultToJson, contract6WorkEventToJson, } from "./application/contract6-projection.js";
14
- import { persistTargetActualsResult, } from "./application/target-actuals-write.js";
8
+ import { planUnitMigration, withUnitMigrationWrite, } from "./application/contract7-unit-migration.js";
9
+ import { getProjectMetadata, } from "./application/contract7-project.js";
10
+ import { planAdvance, planBatchMutation, planFinishActuals, planLifecycle, planMutation, planAssuranceMutation, } from "./application/contract7-mutation.js";
11
+ import { renderTargetGovernanceDecision, } from "./application/target-governance-projection.js";
12
+ import { contract7InspectionResultToJson, contract7MutationResultToJson, contract7SnakeJson, } from "./application/contract7-projection.js";
13
+ import { contract7ProjectResultToJson, renderContract7ProjectText, } from "./application/contract7-project.js";
14
+ import { contract6WorkEventToJson, } from "./application/contract6-projection.js";
15
+ import { renderAdvanceHistoryGuard, } from "./application/advance-history.js";
16
+ import { prepareTargetPlanAssuranceAdvanceHistory, withTargetPlanAssuranceAdvanceHistoryRace, } from "./application/target-assurance-advance-history.js";
17
+ import { persistTargetPlanAssuranceResult, } from "./application/target-assurance-write.js";
18
+ import { inspectTargetPlanAssurance, } from "./application/target-assurance-inspection.js";
15
19
  import { inspectTargetProjectHistoryFile, renderTargetProjectHistoryText, targetProjectHistoryResultToJson, } from "./application/target-project-history.js";
16
20
  import { observeTargetProjectVelocity, renderTargetVelocityObservationText, targetVelocityObservationResultToJson, } from "./application/target-velocity-observation.js";
17
21
  import { getAgentHelp } from "./application/agent-help.js";
18
22
  import { exportMermaid, } from "./conversion/mermaid.js";
19
23
  import { importMermaid } from "./conversion/mermaid-import.js";
20
- import { getActualsGuide, renderActualsGuideResult, serializeActualsGuideResult, } from "./help/actuals-guide.js";
24
+ import { getAssuranceGuide, renderAssuranceGuideResult, serializeAssuranceGuideResult, } from "./help/assurance-guide.js";
21
25
  import { commandOptionSets, } from "./command/registry.js";
22
- import { ACTUALS_COMMAND_REGISTRY, getActualsCommandDiscovery, renderActualsCommandHelpResult, serializeActualsCommandHelpResult, } from "./command/actuals-discovery.js";
26
+ import { ASSURANCE_COMMAND_REGISTRY, getAssuranceCommandDiscovery, renderAssuranceCommandHelpResult, serializeAssuranceCommandHelpResult, } from "./command/assurance-discovery.js";
23
27
  import { handlerCommandUsageError, } from "./command/usage.js";
24
- import { renderActualsCommandUsageError, serializeActualsCommandUsageError, validateActualsCommandInvocation, } from "./command/actuals-usage.js";
28
+ import { renderAssuranceCommandUsageError, serializeAssuranceCommandUsageError, validateAssuranceCommandInvocation, } from "./command/assurance-usage.js";
25
29
  import { agentGuidanceResultToJson } from "./guidance/projection.js";
26
30
  import { agentGuidanceExitCode, renderAgentGuidanceText, } from "./guidance/text.js";
27
31
  import { documentContentFromBytes, readDocumentFile, } from "./io/document-file.js";
28
- import { createArtifactFile, createDocumentFile, replaceDocumentFile, SafeWriteConflictError, SafeWriteVerificationError, } from "./io/safe-write.js";
32
+ import { recheckAdvanceHistoryBaseline, } from "./history/git-probe.js";
33
+ import { createArtifactFile, SafeWriteConflictError, SafeWriteVerificationError, } from "./io/safe-write.js";
29
34
  import { formatDecimal } from "./model/rational.js";
30
35
  import { convertWithVelocity, durationSuffix } from "./model/units.js";
31
36
  import { recommendationInvariantExitCode } from "./recommendation/failure.js";
32
37
  import { recommendationAnalysisToJson } from "./recommendation/json.js";
33
- import { TARGET_GRAMMAR_5_CAPABILITY, } from "./parser/document-parser.js";
38
+ import { TARGET_GRAMMAR_6_CAPABILITY, } from "./parser/document-parser.js";
39
+ import { createTargetGrammar6DocumentFile, replaceTargetGrammar6DocumentFile, } from "./io/target-safe-write.js";
40
+ import { exportPlanAssuranceMermaid, importPlanAssuranceMermaid, } from "./assurance/mermaid.js";
34
41
  import { getJsonSchemaResult, renderJsonSchemaResult, serializeJsonSchemaResult, } from "./schema/registry.js";
35
42
  import { TOOL_VERSION } from "./version.js";
36
43
  class UsageError extends Error {
@@ -86,7 +93,7 @@ function parseOptions(args, valueOptions, flagOptions, repeatableOptions = new S
86
93
  return { positionals, values, repeatedValues, flags };
87
94
  }
88
95
  function parseCommandOptions(operation, args) {
89
- const descriptor = ACTUALS_COMMAND_REGISTRY.find((candidate) => candidate.operation === operation);
96
+ const descriptor = ASSURANCE_COMMAND_REGISTRY.find((candidate) => candidate.operation === operation);
90
97
  if (descriptor === undefined) {
91
98
  throw new Error(`command descriptor is missing for ${operation}`);
92
99
  }
@@ -177,7 +184,24 @@ async function readDocument(source) {
177
184
  const content = source === "-"
178
185
  ? documentContentFromBytes(await readStdin())
179
186
  : await readDocumentFile(source);
180
- return { text: content.text, digest: content.digest };
187
+ let modifiedAt = null;
188
+ if (source !== "-") {
189
+ try {
190
+ const metadata = await lstat(source, { bigint: true });
191
+ if (metadata.isFile() && !metadata.isSymbolicLink()) {
192
+ modifiedAt = new Date(Number(metadata.mtimeNs / 1000000n)).toISOString();
193
+ }
194
+ }
195
+ catch {
196
+ modifiedAt = null;
197
+ }
198
+ }
199
+ return {
200
+ text: content.text,
201
+ digest: content.digest,
202
+ bytes: content.bytes,
203
+ modifiedAt,
204
+ };
181
205
  }
182
206
  async function readStdin() {
183
207
  const chunks = [];
@@ -224,7 +248,7 @@ function cliError(error, exitCode, operation, json) {
224
248
  if (json) {
225
249
  writeJson({
226
250
  schema_version: "Perttool.CliError.v1",
227
- cli_contract_version: 6,
251
+ cli_contract_version: 7,
228
252
  tool_version: TOOL_VERSION,
229
253
  operation,
230
254
  ok: false,
@@ -260,7 +284,7 @@ async function runCheck(args) {
260
284
  if (format === "json") {
261
285
  writeJson({
262
286
  schema_version: result.schemaVersion,
263
- cli_contract_version: 6,
287
+ cli_contract_version: 7,
264
288
  tool_version: TOOL_VERSION,
265
289
  operation: "document.check",
266
290
  ok,
@@ -278,6 +302,8 @@ async function runCheck(args) {
278
302
  model_version: result.actualsInputs.modelVersion,
279
303
  events: result.actualsInputs.events.map(contract6WorkEventToJson),
280
304
  },
305
+ assurance: contract7SnakeJson(result.assurance),
306
+ assurance_state_counts: contract7SnakeJson(result.assuranceStateCounts),
281
307
  });
282
308
  }
283
309
  else {
@@ -316,11 +342,11 @@ async function runProjectShow(args) {
316
342
  result.diagnostics.some((diagnostic) => diagnostic.severity === "warning"));
317
343
  const ok = result.ok && !warningFailure;
318
344
  if (format === "json") {
319
- writeJson(contract6ProjectResultToJson(result, source, input.digest, ok));
345
+ writeJson(contract7ProjectResultToJson(result, source, input.digest, ok));
320
346
  }
321
347
  else {
322
348
  if (ok && result.project !== null) {
323
- process.stdout.write(renderTargetGovernanceProjectText(result.project));
349
+ process.stdout.write(renderContract7ProjectText(result.project));
324
350
  }
325
351
  for (const diagnostic of result.diagnostics) {
326
352
  process.stderr.write(`${renderDiagnostic(diagnostic, source, color)}\n`);
@@ -377,7 +403,7 @@ async function runProjectInit(args) {
377
403
  const output = parsed.values.get("out");
378
404
  if (result.ok && output !== undefined) {
379
405
  try {
380
- writeResult = await createDocumentFile(output, result.candidateText);
406
+ writeResult = await createTargetGrammar6DocumentFile(output, result.candidateText, TARGET_GRAMMAR_6_CAPABILITY);
381
407
  result = withProjectInitOutput(result, writeResult);
382
408
  }
383
409
  catch (error) {
@@ -494,7 +520,7 @@ async function persistGovernedResult(result, request, sourceOperand) {
494
520
  written: false,
495
521
  });
496
522
  }
497
- return persistTargetActualsResult(result, TARGET_GRAMMAR_5_CAPABILITY, request.mode === "in_place"
523
+ return persistTargetPlanAssuranceResult(result, TARGET_GRAMMAR_6_CAPABILITY, request.mode === "in_place"
498
524
  ? {
499
525
  mode: "in_place",
500
526
  target: request.target,
@@ -520,13 +546,13 @@ async function commitCandidate(request, candidateText, initialDigest) {
520
546
  throw new SafeWriteVerificationError("invalid_candidate", "successful editing result has no candidate text");
521
547
  }
522
548
  return request.mode === "in_place"
523
- ? replaceDocumentFile(request.target, candidateText, {
549
+ ? replaceTargetGrammar6DocumentFile(request.target, candidateText, TARGET_GRAMMAR_6_CAPABILITY, {
524
550
  initialDigest,
525
551
  ...(request.expectedDigest === undefined
526
552
  ? {}
527
553
  : { expectedDigest: request.expectedDigest }),
528
554
  })
529
- : createDocumentFile(request.target, candidateText);
555
+ : createTargetGrammar6DocumentFile(request.target, candidateText, TARGET_GRAMMAR_6_CAPABILITY);
530
556
  }
531
557
  function writeFailureExit(error, operation, json) {
532
558
  const normalized = error instanceof Error ? error : new Error(String(error));
@@ -586,7 +612,7 @@ async function runFormat(args) {
586
612
  if (format === "json") {
587
613
  writeJson({
588
614
  schema_version: "Perttool.FormatResult.v1",
589
- cli_contract_version: 6,
615
+ cli_contract_version: 7,
590
616
  tool_version: TOOL_VERSION,
591
617
  operation: "document.format",
592
618
  ok,
@@ -1195,7 +1221,7 @@ async function runMutation(resource, action, args) {
1195
1221
  }
1196
1222
  }
1197
1223
  if (format === "json") {
1198
- writeJson(contract6MutationResultToJson(ok ? result : Object.freeze({ ...result, ok: false }), operation, source, writeResult));
1224
+ writeJson(contract7MutationResultToJson(ok ? result : Object.freeze({ ...result, ok: false }), operation, source, writeResult));
1199
1225
  }
1200
1226
  else {
1201
1227
  if (ok) {
@@ -1278,7 +1304,7 @@ async function runLifecycleMutation(action, args) {
1278
1304
  }
1279
1305
  }
1280
1306
  if (format === "json") {
1281
- writeJson(contract6MutationResultToJson(ok ? result : Object.freeze({ ...result, ok: false }), operation, source, writeResult));
1307
+ writeJson(contract7MutationResultToJson(ok ? result : Object.freeze({ ...result, ok: false }), operation, source, writeResult));
1282
1308
  }
1283
1309
  else {
1284
1310
  if (ok) {
@@ -1317,7 +1343,7 @@ function unitMigrationJson(result, source, sourceDigest, ok) {
1317
1343
  });
1318
1344
  return {
1319
1345
  schema_version: result.schemaVersion,
1320
- cli_contract_version: 6,
1346
+ cli_contract_version: 7,
1321
1347
  tool_version: TOOL_VERSION,
1322
1348
  operation: "project.migrate-unit",
1323
1349
  ok,
@@ -1462,7 +1488,7 @@ async function readHistoryForCommand(operation, parsed, format) {
1462
1488
  ...(parsed.repeatedValues.get("task") === undefined
1463
1489
  ? {}
1464
1490
  : { taskIds: parsed.repeatedValues.get("task") }),
1465
- }, TARGET_GRAMMAR_5_CAPABILITY);
1491
+ }, TARGET_GRAMMAR_6_CAPABILITY);
1466
1492
  }
1467
1493
  catch (error) {
1468
1494
  return error instanceof Error ? error : new Error(String(error));
@@ -1533,6 +1559,15 @@ function renderAdvanceSummary(details) {
1533
1559
  "",
1534
1560
  ].join("\n");
1535
1561
  }
1562
+ function renderAssuranceGuard(guard) {
1563
+ const list = (values) => values.join(",") || "-";
1564
+ return [
1565
+ `ASSURANCE_GUARD status=${guard.status} cause=${guard.cause}`,
1566
+ `ASSURANCE_GUARD crossing_producers=${list(guard.crossingProducerTaskIds)} created_receipts=${list(guard.createdReceiptIds)} updated_receipts=${list(guard.updatedReceiptIds)} removed_receipts=${list(guard.removedReceiptIds)}`,
1567
+ ...guard.retainedBasisChecks.map((check) => `ASSURANCE_BASIS task=${check.taskId} before=${check.beforeBasisHash ?? "-"} after=${check.afterBasisHash ?? "-"} equal=${check.equal}`),
1568
+ "",
1569
+ ].join("\n");
1570
+ }
1536
1571
  async function runAdvance(args) {
1537
1572
  const parsed = parseCommandOptions("dag.advance", args);
1538
1573
  if (parsed.positionals.length !== 1) {
@@ -1543,6 +1578,10 @@ async function runAdvance(args) {
1543
1578
  const maxDiagnostics = boundedInteger(parsed.values.get("max-diagnostics"), "max-diagnostics", 100, 1, 1000);
1544
1579
  const sourceOperand = parsed.positionals[0];
1545
1580
  const writeRequest = editingWriteRequest(parsed, sourceOperand);
1581
+ const forceRequested = parsed.flags.has("force-history-loss");
1582
+ if (forceRequested && writeRequest.mode !== "in_place") {
1583
+ throw new UsageError("--force-history-loss can only be used with --write");
1584
+ }
1546
1585
  const source = sourceOperand === "-" ? "<stdin>" : sourceOperand;
1547
1586
  let input;
1548
1587
  try {
@@ -1551,23 +1590,54 @@ async function runAdvance(args) {
1551
1590
  catch (error) {
1552
1591
  return cliError(error instanceof Error ? error : new Error(String(error)), 3, "dag.advance", format === "json");
1553
1592
  }
1554
- const result = planAdvance(input.text, {
1593
+ const planned = planAdvance(input.text, {
1555
1594
  maxDiagnostics,
1556
1595
  originalLabel: source,
1557
1596
  updatedLabel: "candidate",
1558
1597
  governance: governanceRequest(parsed, writeRequest),
1559
1598
  });
1599
+ const initialWarningFailure = parsed.flags.has("warnings-as-errors") &&
1600
+ (planned.diagnosticsTruncated ||
1601
+ planned.diagnostics.some((diagnostic) => diagnostic.severity === "warning"));
1602
+ const prepared = await prepareTargetPlanAssuranceAdvanceHistory(input.text, planned, TARGET_GRAMMAR_6_CAPABILITY, {
1603
+ mode: writeRequest.mode === "out"
1604
+ ? "out"
1605
+ : writeRequest.mode,
1606
+ sourceBytes: input.bytes,
1607
+ sourceModifiedAt: input.modifiedAt,
1608
+ ...(writeRequest.mode === "in_place"
1609
+ ? { targetPath: sourceOperand }
1610
+ : {}),
1611
+ forceRequested,
1612
+ warningDenied: initialWarningFailure,
1613
+ maxDiagnostics,
1614
+ });
1615
+ let result = prepared.result;
1560
1616
  const warningFailure = parsed.flags.has("warnings-as-errors") &&
1561
1617
  (result.diagnosticsTruncated ||
1562
1618
  result.diagnostics.some((diagnostic) => diagnostic.severity === "warning"));
1563
- const ok = result.ok && !warningFailure;
1619
+ let ok = result.ok && !warningFailure;
1620
+ let historyRace = false;
1564
1621
  let writeResult = Object.freeze({
1565
1622
  mode: writeRequest.mode,
1566
1623
  target: writeRequest.target,
1567
1624
  written: false,
1568
1625
  });
1569
- if (result.ok) {
1626
+ if (result.updatedText !== null) {
1570
1627
  try {
1628
+ if (ok &&
1629
+ writeRequest.mode === "in_place" &&
1630
+ prepared.baseline !== null &&
1631
+ prepared.baseline.status === "complete" &&
1632
+ (result.historyGuard?.status === "passed" ||
1633
+ result.historyGuard?.status === "forced")) {
1634
+ const recheck = await recheckAdvanceHistoryBaseline(prepared.baseline, sourceOperand);
1635
+ if (!recheck.ok) {
1636
+ result = withTargetPlanAssuranceAdvanceHistoryRace(result, recheck, maxDiagnostics);
1637
+ ok = false;
1638
+ historyRace = true;
1639
+ }
1640
+ }
1571
1641
  if (ok && writeRequest.mode !== "preview") {
1572
1642
  writeResult = await persistGovernedResult(result, writeRequest, sourceOperand);
1573
1643
  }
@@ -1577,20 +1647,32 @@ async function runAdvance(args) {
1577
1647
  }
1578
1648
  }
1579
1649
  if (format === "json") {
1580
- writeJson(contract6MutationResultToJson(ok ? result : Object.freeze({ ...result, ok: false }), "dag.advance", source, writeResult));
1650
+ writeJson(contract7MutationResultToJson(ok ? result : Object.freeze({ ...result, ok: false }), "dag.advance", source, writeResult));
1581
1651
  }
1582
1652
  else {
1583
- if (ok && result.advance !== null) {
1584
- if (writeRequest.mode !== "preview") {
1585
- process.stderr.write(renderGovernanceWriteSummary("dag.advance", writeResult, result.updatedDigest));
1586
- }
1587
- else {
1588
- process.stdout.write(parsed.flags.has("diff") ? (result.diff ?? "") : (result.updatedText ?? ""));
1589
- if (!parsed.flags.has("diff")) {
1590
- process.stderr.write(`PREVIEW dag.advance changed=${result.changed} original_digest=${result.originalDigest} updated_digest=${result.updatedDigest}\n`);
1653
+ if (result.advance !== null) {
1654
+ if (ok) {
1655
+ if (writeRequest.mode !== "preview") {
1656
+ process.stderr.write(renderGovernanceWriteSummary("dag.advance", writeResult, result.updatedDigest));
1591
1657
  }
1658
+ else {
1659
+ process.stdout.write(parsed.flags.has("diff") ? (result.diff ?? "") : (result.updatedText ?? ""));
1660
+ if (!parsed.flags.has("diff")) {
1661
+ process.stderr.write(`PREVIEW dag.advance changed=${result.changed} original_digest=${result.originalDigest} updated_digest=${result.updatedDigest}\n`);
1662
+ }
1663
+ }
1664
+ }
1665
+ if (ok ||
1666
+ result.historyGuard?.status === "blocked" ||
1667
+ result.historyGuard?.status === "forced") {
1668
+ process.stderr.write(renderAdvanceSummary(result.advance));
1592
1669
  }
1593
- process.stderr.write(renderAdvanceSummary(result.advance));
1670
+ }
1671
+ if (result.historyGuard !== null) {
1672
+ process.stderr.write(renderAdvanceHistoryGuard(result.historyGuard));
1673
+ }
1674
+ if (result.assuranceGuard !== null) {
1675
+ process.stderr.write(renderAssuranceGuard(result.assuranceGuard));
1594
1676
  }
1595
1677
  if (result.governance !== null) {
1596
1678
  process.stderr.write(renderTargetGovernanceDecision(result.governance));
@@ -1602,7 +1684,7 @@ async function runAdvance(args) {
1602
1684
  process.stderr.write(`DIAGNOSTICS_TRUNCATED true limit=${maxDiagnostics}\n`);
1603
1685
  }
1604
1686
  }
1605
- return ok ? 0 : 1;
1687
+ return ok ? 0 : historyRace ? 5 : 1;
1606
1688
  }
1607
1689
  function rationalJson(value, unit, precision) {
1608
1690
  return {
@@ -1925,8 +2007,8 @@ async function runAnalyze(args) {
1925
2007
  const ok = result.ok && !warningFailure;
1926
2008
  if (format === "json") {
1927
2009
  writeJson({
1928
- schema_version: "Perttool.AnalysisResult.v4",
1929
- cli_contract_version: 6,
2010
+ schema_version: result.schemaVersion,
2011
+ cli_contract_version: 7,
1930
2012
  tool_version: TOOL_VERSION,
1931
2013
  operation: "dag.analyze",
1932
2014
  ok,
@@ -1958,6 +2040,7 @@ async function runAnalyze(args) {
1958
2040
  ? null
1959
2041
  : resourceJson(result.resource, result.durationUnit, result.precision),
1960
2042
  temporal: snakeJson(result.temporal),
2043
+ assurance: contract7SnakeJson(result.assurance),
1961
2044
  });
1962
2045
  }
1963
2046
  else {
@@ -2020,12 +2103,39 @@ async function runRender(args) {
2020
2103
  catch (error) {
2021
2104
  return cliError(error instanceof Error ? error : new Error(String(error)), 3, "dag.render", format === "json");
2022
2105
  }
2023
- const result = exportMermaid(input.text, {
2024
- profile,
2025
- analysis,
2026
- capacityOverrides: overrides,
2027
- maxDiagnostics,
2028
- });
2106
+ const sourceCheck = checkDocument(input.text, { maxDiagnostics });
2107
+ const grammar6 = sourceCheck.grammarVersion === 6;
2108
+ const assuranceExport = grammar6
2109
+ ? exportPlanAssuranceMermaid(input.text, TARGET_GRAMMAR_6_CAPABILITY, {
2110
+ profile: profile === "perttool" ? 2 : "plain",
2111
+ allowLoss: !parsed.flags.has("strict-loss"),
2112
+ analysis,
2113
+ capacityOverrides: overrides,
2114
+ maxDiagnostics,
2115
+ })
2116
+ : null;
2117
+ const legacyExport = grammar6
2118
+ ? null
2119
+ : exportMermaid(input.text, {
2120
+ profile,
2121
+ analysis,
2122
+ capacityOverrides: overrides,
2123
+ maxDiagnostics,
2124
+ });
2125
+ const result = assuranceExport === null
2126
+ ? legacyExport
2127
+ : Object.freeze({
2128
+ ok: assuranceExport.ok,
2129
+ documentId: assuranceExport.documentId,
2130
+ diagnostics: assuranceExport.diagnostics,
2131
+ diagnosticsTruncated: assuranceExport.diagnosticsTruncated,
2132
+ profile,
2133
+ analysis,
2134
+ capacityOverrides: overrides,
2135
+ artifact: assuranceExport.artifact,
2136
+ artifactDigest: assuranceExport.artifactDigest,
2137
+ lossReport: assuranceExport.lossReport,
2138
+ });
2029
2139
  const warningFailure = parsed.flags.has("warnings-as-errors") &&
2030
2140
  (result.diagnosticsTruncated ||
2031
2141
  result.diagnostics.some((diagnostic) => diagnostic.severity === "warning"));
@@ -2045,7 +2155,7 @@ async function runRender(args) {
2045
2155
  if (format === "json") {
2046
2156
  writeJson({
2047
2157
  schema_version: "Perttool.ExportResult.v1",
2048
- cli_contract_version: 6,
2158
+ cli_contract_version: 7,
2049
2159
  tool_version: TOOL_VERSION,
2050
2160
  operation: "dag.render",
2051
2161
  ok,
@@ -2117,7 +2227,28 @@ async function runImport(args) {
2117
2227
  catch (error) {
2118
2228
  return cliError(error instanceof Error ? error : new Error(String(error)), 3, "dag.import", format === "json");
2119
2229
  }
2120
- const result = importMermaid(input.text, { maxDiagnostics });
2230
+ const profile2 = input.text.startsWith("flowchart LR\n %% perttool:profile {\"schema_version\":\"Perttool.MermaidProfile.v2\"");
2231
+ const assuranceImport = profile2
2232
+ ? importPlanAssuranceMermaid(input.text, TARGET_GRAMMAR_6_CAPABILITY)
2233
+ : null;
2234
+ const legacyImport = profile2
2235
+ ? null
2236
+ : importMermaid(input.text, { maxDiagnostics });
2237
+ const result = assuranceImport === null
2238
+ ? legacyImport
2239
+ : Object.freeze({
2240
+ ok: assuranceImport.ok,
2241
+ documentId: assuranceImport.documentId,
2242
+ diagnostics: assuranceImport.diagnostics,
2243
+ diagnosticsTruncated: assuranceImport.diagnosticsTruncated,
2244
+ profile: "perttool",
2245
+ analysis: assuranceImport.analysis,
2246
+ capacityOverrides: assuranceImport.capacityOverrides,
2247
+ artifact: assuranceImport.sourceText,
2248
+ artifactDigest: assuranceImport.sourceDigest,
2249
+ lossReport: assuranceImport.lossReport,
2250
+ generatedIds: Object.freeze([]),
2251
+ });
2121
2252
  const warningFailure = parsed.flags.has("warnings-as-errors") &&
2122
2253
  (result.diagnosticsTruncated ||
2123
2254
  result.diagnostics.some((diagnostic) => diagnostic.severity === "warning"));
@@ -2128,7 +2259,7 @@ async function runImport(args) {
2128
2259
  let writeResult = null;
2129
2260
  if (ok && out !== null) {
2130
2261
  try {
2131
- writeResult = await createDocumentFile(out, result.artifact);
2262
+ writeResult = await createTargetGrammar6DocumentFile(out, result.artifact, TARGET_GRAMMAR_6_CAPABILITY);
2132
2263
  }
2133
2264
  catch (error) {
2134
2265
  return writeFailureExit(error, "dag.import", format === "json");
@@ -2137,7 +2268,7 @@ async function runImport(args) {
2137
2268
  if (format === "json") {
2138
2269
  writeJson({
2139
2270
  schema_version: "Perttool.ImportResult.v1",
2140
- cli_contract_version: 6,
2271
+ cli_contract_version: 7,
2141
2272
  tool_version: TOOL_VERSION,
2142
2273
  operation: "dag.import",
2143
2274
  ok,
@@ -2446,7 +2577,7 @@ async function runNext(args) {
2446
2577
  if (format === "json") {
2447
2578
  writeJson({
2448
2579
  schema_version: "Perttool.CliError.v1",
2449
- cli_contract_version: 6,
2580
+ cli_contract_version: 7,
2450
2581
  tool_version: TOOL_VERSION,
2451
2582
  operation: "dag.next",
2452
2583
  ok: false,
@@ -2466,8 +2597,8 @@ async function runNext(args) {
2466
2597
  const ok = result.ok && !warningFailure;
2467
2598
  if (format === "json") {
2468
2599
  writeJson({
2469
- schema_version: "Perttool.NextResult.v5",
2470
- cli_contract_version: 6,
2600
+ schema_version: result.schemaVersion,
2601
+ cli_contract_version: 7,
2471
2602
  recommendation_interface_version: 1,
2472
2603
  tool_version: TOOL_VERSION,
2473
2604
  operation: "dag.next",
@@ -2480,6 +2611,7 @@ async function runNext(args) {
2480
2611
  grammar_version: result.grammarVersion,
2481
2612
  ...(result.durationUnit === null ? {} : nextJson(result)),
2482
2613
  temporal: snakeJson(result.temporal),
2614
+ assurance: contract7SnakeJson(result.assurance),
2483
2615
  });
2484
2616
  }
2485
2617
  else {
@@ -2503,12 +2635,12 @@ function runGuide(args) {
2503
2635
  colorMode(parsed.values.get("color"), format);
2504
2636
  const topicId = parsed.positionals.length === 0 ? null : parsed.positionals.join(".");
2505
2637
  const level = helpLevel(parsed.values.get("level"), topicId !== null);
2506
- const result = getActualsGuide(topicId, level);
2638
+ const result = getAssuranceGuide(topicId, level);
2507
2639
  if (format === "json") {
2508
- process.stdout.write(serializeActualsGuideResult(result));
2640
+ process.stdout.write(serializeAssuranceGuideResult(result));
2509
2641
  }
2510
2642
  else {
2511
- const rendered = renderActualsGuideResult(result);
2643
+ const rendered = renderAssuranceGuideResult(result);
2512
2644
  if (result.ok) {
2513
2645
  process.stdout.write(rendered);
2514
2646
  }
@@ -2524,15 +2656,15 @@ function runCommandHelp(args) {
2524
2656
  throw new UsageError("help accepts at most <resource> <action>");
2525
2657
  }
2526
2658
  const format = outputFormat(parsed.values.get("format"));
2527
- const result = getActualsCommandDiscovery({
2659
+ const result = getAssuranceCommandDiscovery({
2528
2660
  resource: parsed.positionals[0] ?? null,
2529
2661
  action: parsed.positionals[1] ?? null,
2530
2662
  });
2531
2663
  if (format === "json") {
2532
- process.stdout.write(serializeActualsCommandHelpResult(result));
2664
+ process.stdout.write(serializeAssuranceCommandHelpResult(result));
2533
2665
  }
2534
2666
  else {
2535
- const rendered = renderActualsCommandHelpResult(result);
2667
+ const rendered = renderAssuranceCommandHelpResult(result);
2536
2668
  if (result.ok) {
2537
2669
  process.stdout.write(rendered);
2538
2670
  }
@@ -2600,7 +2732,7 @@ function runAgentHelp(args) {
2600
2732
  const { schema_version: schemaVersion, ...payload } = projected;
2601
2733
  writeJson({
2602
2734
  schema_version: schemaVersion,
2603
- cli_contract_version: 6,
2735
+ cli_contract_version: 7,
2604
2736
  ...payload,
2605
2737
  });
2606
2738
  }
@@ -2622,6 +2754,223 @@ function runAgentHelp(args) {
2622
2754
  }
2623
2755
  return agentGuidanceExitCode(result.diagnostics);
2624
2756
  }
2757
+ function renderPlanAssuranceProjection(value) {
2758
+ const list = (values) => values.join(",") || "-";
2759
+ const lines = [
2760
+ `PLAN_ASSURANCE model=${value.modelVersion ?? "-"} hash_model=${value.hashModelVersion ?? "-"} coverage=${value.coverage}`,
2761
+ `REPLAN_REQUIRED ${list(value.replanRequiredTaskIds)}`,
2762
+ `ACTIVE_ATTENTION ${list(value.activeAttentionRequiredTaskIds)}`,
2763
+ ];
2764
+ for (const task of value.taskResults) {
2765
+ lines.push(`TASK ${task.taskId} status=${task.status} contract=${task.contractHash ?? "-"} computed_basis=${task.computedBasisHash ?? "-"} accepted_basis=${task.acceptedBasisHash ?? "-"} exported=${task.exportedAssuranceHash ?? "-"}`);
2766
+ }
2767
+ return `${lines.join("\n")}\n`;
2768
+ }
2769
+ async function runPlanAssuranceInspection(action, args) {
2770
+ const operation = `plan-assurance.${action}`;
2771
+ const parsed = parseCommandOptions(operation, args);
2772
+ const format = outputFormat(parsed.values.get("format"));
2773
+ const color = colorMode(parsed.values.get("color"), format);
2774
+ const maxDiagnostics = boundedInteger(parsed.values.get("max-diagnostics"), "max-diagnostics", 100, 1, 1000);
2775
+ const sourceOperand = parsed.positionals[0];
2776
+ const source = sourceOperand === "-" ? "<stdin>" : sourceOperand;
2777
+ let input;
2778
+ try {
2779
+ input = await readDocument(sourceOperand);
2780
+ }
2781
+ catch (error) {
2782
+ return cliError(error instanceof Error ? error : new Error(String(error)), 3, operation, format === "json");
2783
+ }
2784
+ const result = inspectTargetPlanAssurance(input.text, action === "show"
2785
+ ? {
2786
+ operation: "plan-assurance.show",
2787
+ taskIds: parsed.repeatedValues.get("task") ?? Object.freeze([]),
2788
+ }
2789
+ : {
2790
+ operation: "plan-assurance.hash",
2791
+ taskId: parsed.positionals[1],
2792
+ kind: requiredOption(parsed, "kind"),
2793
+ }, TARGET_GRAMMAR_6_CAPABILITY, { maxDiagnostics });
2794
+ const warningFailure = parsed.flags.has("warnings-as-errors") &&
2795
+ (result.diagnosticsTruncated || result.diagnostics.some(({ severity }) => severity === "warning"));
2796
+ const ok = result.ok && !warningFailure;
2797
+ if (format === "json") {
2798
+ writeJson(contract7InspectionResultToJson(ok ? result : Object.freeze({ ...result, ok: false }), source));
2799
+ }
2800
+ else if (ok) {
2801
+ if (action === "hash") {
2802
+ if (result.selectedHash === null) {
2803
+ throw new Error("successful assurance hash result has no digest");
2804
+ }
2805
+ process.stdout.write(`${result.selectedHash}\n`);
2806
+ }
2807
+ else if (result.assurance !== null) {
2808
+ process.stdout.write(renderPlanAssuranceProjection(result.assurance));
2809
+ }
2810
+ }
2811
+ for (const diagnostic of result.diagnostics) {
2812
+ process.stderr.write(`${renderDiagnostic(diagnostic, source, color)}\n`);
2813
+ }
2814
+ if (result.diagnosticsTruncated) {
2815
+ process.stderr.write(`DIAGNOSTICS_TRUNCATED true limit=${maxDiagnostics}\n`);
2816
+ }
2817
+ return ok ? 0 : 1;
2818
+ }
2819
+ function dependencyMode(value) {
2820
+ return value === "execution-only"
2821
+ ? "execution_only"
2822
+ : value === "planning-only"
2823
+ ? "planning_only"
2824
+ : "both";
2825
+ }
2826
+ function assuranceMutationFromOptions(resource, action, parsed) {
2827
+ if (resource === "plan-assurance") {
2828
+ return action === "seal"
2829
+ ? {
2830
+ kind: "plan_assurance.seal",
2831
+ reason: requiredOption(parsed, "reason"),
2832
+ }
2833
+ : {
2834
+ kind: "plan_assurance.reseal",
2835
+ taskIds: uniqueRepeated(parsed, "task"),
2836
+ reason: requiredOption(parsed, "reason"),
2837
+ };
2838
+ }
2839
+ const id = parsed.positionals[1];
2840
+ if (resource === "plan-dependency") {
2841
+ if (action === "add") {
2842
+ return {
2843
+ kind: "plan_dependency.add",
2844
+ id,
2845
+ predecessorTaskId: parsed.positionals[2],
2846
+ successorTaskId: parsed.positionals[3],
2847
+ mode: dependencyMode(requiredOption(parsed, "mode")),
2848
+ ...(parsed.values.get("reason") === undefined
2849
+ ? {}
2850
+ : { reason: parsed.values.get("reason") }),
2851
+ };
2852
+ }
2853
+ if (action === "remove")
2854
+ return { kind: "plan_dependency.remove", id };
2855
+ const clear = uniqueRepeated(parsed, "clear");
2856
+ return {
2857
+ kind: "plan_dependency.set",
2858
+ id,
2859
+ ...(parsed.values.get("predecessor") === undefined
2860
+ ? {}
2861
+ : { predecessorTaskId: parsed.values.get("predecessor") }),
2862
+ ...(parsed.values.get("successor") === undefined
2863
+ ? {}
2864
+ : { successorTaskId: parsed.values.get("successor") }),
2865
+ ...(parsed.values.get("mode") === undefined
2866
+ ? {}
2867
+ : { mode: dependencyMode(parsed.values.get("mode")) }),
2868
+ ...(parsed.values.get("reason") === undefined
2869
+ ? {}
2870
+ : { reason: parsed.values.get("reason") }),
2871
+ ...(clear.includes("reason") ? { clearReason: true } : {}),
2872
+ };
2873
+ }
2874
+ if (action === "add") {
2875
+ return {
2876
+ kind: "task_outcome.add",
2877
+ id,
2878
+ taskId: parsed.positionals[2],
2879
+ status: requiredOption(parsed, "status"),
2880
+ ...(parsed.values.get("summary") === undefined
2881
+ ? {}
2882
+ : { summary: parsed.values.get("summary") }),
2883
+ reason: requiredOption(parsed, "reason"),
2884
+ };
2885
+ }
2886
+ if (action === "remove")
2887
+ return { kind: "task_outcome.remove", id };
2888
+ const clear = uniqueRepeated(parsed, "clear");
2889
+ return {
2890
+ kind: "task_outcome.set",
2891
+ id,
2892
+ ...(parsed.values.get("status") === undefined
2893
+ ? {}
2894
+ : {
2895
+ status: parsed.values.get("status"),
2896
+ }),
2897
+ ...(parsed.values.get("summary") === undefined
2898
+ ? {}
2899
+ : { summary: parsed.values.get("summary") }),
2900
+ ...(clear.includes("summary") ? { clearSummary: true } : {}),
2901
+ ...(parsed.values.get("reason") === undefined
2902
+ ? {}
2903
+ : { reason: parsed.values.get("reason") }),
2904
+ ...(parsed.flags.has("rebind-current-basis")
2905
+ ? { rebindCurrentBasis: true }
2906
+ : {}),
2907
+ };
2908
+ }
2909
+ async function runAssuranceMutation(resource, action, args) {
2910
+ const operation = `${resource}.${action}`;
2911
+ const parsed = parseCommandOptions(operation, args);
2912
+ const format = outputFormat(parsed.values.get("format"));
2913
+ const color = colorMode(parsed.values.get("color"), format);
2914
+ const maxDiagnostics = boundedInteger(parsed.values.get("max-diagnostics"), "max-diagnostics", 100, 1, 1000);
2915
+ const sourceOperand = parsed.positionals[0];
2916
+ const source = sourceOperand === "-" ? "<stdin>" : sourceOperand;
2917
+ const writeRequest = editingWriteRequest(parsed, sourceOperand);
2918
+ let input;
2919
+ try {
2920
+ input = await readDocument(sourceOperand);
2921
+ }
2922
+ catch (error) {
2923
+ return cliError(error instanceof Error ? error : new Error(String(error)), 3, operation, format === "json");
2924
+ }
2925
+ const result = planAssuranceMutation(input.text, assuranceMutationFromOptions(resource, action, parsed), {
2926
+ maxDiagnostics,
2927
+ originalLabel: source,
2928
+ updatedLabel: "candidate",
2929
+ warningsAsErrors: parsed.flags.has("warnings-as-errors"),
2930
+ governance: governanceRequest(parsed, writeRequest),
2931
+ });
2932
+ let writeResult = Object.freeze({
2933
+ mode: writeRequest.mode,
2934
+ target: writeRequest.target,
2935
+ written: false,
2936
+ });
2937
+ if (result.ok && writeRequest.mode !== "preview") {
2938
+ try {
2939
+ writeResult = await persistGovernedResult(result, writeRequest, sourceOperand);
2940
+ }
2941
+ catch (error) {
2942
+ return writeFailureExit(error, operation, format === "json");
2943
+ }
2944
+ }
2945
+ if (format === "json") {
2946
+ writeJson(contract7MutationResultToJson(result, operation, source, writeResult));
2947
+ }
2948
+ else {
2949
+ if (result.ok) {
2950
+ if (writeRequest.mode === "preview") {
2951
+ process.stdout.write(parsed.flags.has("diff")
2952
+ ? (result.diff ?? "")
2953
+ : (result.updatedText ?? ""));
2954
+ if (!parsed.flags.has("diff")) {
2955
+ process.stderr.write(`PREVIEW ${operation} changed=${result.changed} original_digest=${result.originalDigest} updated_digest=${result.updatedDigest}\n`);
2956
+ }
2957
+ }
2958
+ else {
2959
+ process.stderr.write(renderGovernanceWriteSummary(operation, writeResult, result.updatedDigest));
2960
+ }
2961
+ }
2962
+ if (result.governance !== null) {
2963
+ process.stderr.write(renderTargetGovernanceDecision(result.governance));
2964
+ }
2965
+ for (const diagnostic of result.diagnostics) {
2966
+ process.stderr.write(`${renderDiagnostic(diagnostic, source, color)}\n`);
2967
+ }
2968
+ if (result.diagnosticsTruncated) {
2969
+ process.stderr.write(`DIAGNOSTICS_TRUNCATED true limit=${maxDiagnostics}\n`);
2970
+ }
2971
+ }
2972
+ return result.ok ? 0 : 1;
2973
+ }
2625
2974
  async function dispatchCommand(descriptor, args) {
2626
2975
  switch (descriptor.operation) {
2627
2976
  case "help":
@@ -2662,6 +3011,16 @@ async function dispatchCommand(descriptor, args) {
2662
3011
  return runLifecycleMutation("suspend", args);
2663
3012
  case "task.resume":
2664
3013
  return runLifecycleMutation("resume", args);
3014
+ case "plan-assurance.show":
3015
+ return runPlanAssuranceInspection("show", args);
3016
+ case "plan-assurance.hash":
3017
+ return runPlanAssuranceInspection("hash", args);
3018
+ }
3019
+ if (descriptor.path.length === 2 &&
3020
+ (descriptor.path[0] === "plan-assurance" ||
3021
+ descriptor.path[0] === "plan-dependency" ||
3022
+ descriptor.path[0] === "task-outcome")) {
3023
+ return runAssuranceMutation(descriptor.path[0], descriptor.path[1], args);
2665
3024
  }
2666
3025
  if (descriptor.path.length === 2
2667
3026
  && (descriptor.operation === "project.set"
@@ -2670,14 +3029,14 @@ async function dispatchCommand(descriptor, args) {
2670
3029
  const [resource, action] = descriptor.path;
2671
3030
  return runMutation(resource, action, args);
2672
3031
  }
2673
- throw new Error(`no Contract 6 handler for ${descriptor.operation}`);
3032
+ throw new Error(`no Contract 7 handler for ${descriptor.operation}`);
2674
3033
  }
2675
3034
  function emitCommandUsage(error, json) {
2676
3035
  if (json) {
2677
- process.stdout.write(serializeActualsCommandUsageError(error));
3036
+ process.stdout.write(serializeAssuranceCommandUsageError(error));
2678
3037
  }
2679
3038
  else {
2680
- process.stderr.write(renderActualsCommandUsageError(error));
3039
+ process.stderr.write(renderAssuranceCommandUsageError(error));
2681
3040
  }
2682
3041
  return 2;
2683
3042
  }
@@ -2689,13 +3048,13 @@ async function main(argv) {
2689
3048
  if (argv.length === 1 && argv[0] === "--help") {
2690
3049
  return runCommandHelp([]);
2691
3050
  }
2692
- const validation = validateActualsCommandInvocation(argv);
3051
+ const validation = validateAssuranceCommandInvocation(argv);
2693
3052
  if (!validation.ok) {
2694
3053
  if (jsonRequested(argv)) {
2695
- process.stdout.write(serializeActualsCommandUsageError(validation.error));
3054
+ process.stdout.write(serializeAssuranceCommandUsageError(validation.error));
2696
3055
  }
2697
3056
  else {
2698
- process.stderr.write(renderActualsCommandUsageError(validation.error));
3057
+ process.stderr.write(renderAssuranceCommandUsageError(validation.error));
2699
3058
  }
2700
3059
  return 2;
2701
3060
  }