agentera 3.0.0-dev.7 → 3.0.0-dev.72

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 (723) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +118 -22
  3. package/bundle/CHANGELOG.md +1361 -0
  4. package/bundle/DESIGN.md +229 -0
  5. package/bundle/LICENSE +201 -0
  6. package/bundle/README.md +143 -0
  7. package/bundle/UPGRADE.md +252 -0
  8. package/bundle/extract-corpus-parity.json +2 -4
  9. package/bundle/fixtures/routing/hybrid-corpus.yaml +154 -0
  10. package/bundle/references/adapters/package-publication.json +488 -0
  11. package/bundle/references/adapters/package-registry.yaml +435 -188
  12. package/bundle/references/adapters/package-surface-characterization.md +66 -34
  13. package/bundle/references/adapters/runtime-lifecycle-adapters.yaml +74 -0
  14. package/bundle/references/adapters/runtime-lifecycle-authority.yaml +62 -0
  15. package/bundle/references/adapters/runtime-lifecycle-operation-contract.yaml +84 -0
  16. package/bundle/references/adapters/runtime-retired-resources.yaml +333 -0
  17. package/bundle/references/analysis/evidence-tier-authority.yaml +518 -0
  18. package/bundle/references/analysis/verification-policy.yaml +266 -0
  19. package/bundle/references/artifacts/artifact-registry-interface-model.yaml +17 -8
  20. package/bundle/references/artifacts/glossary-entry-contract.yaml +1254 -0
  21. package/bundle/references/artifacts/state-storage-authority.yaml +3061 -0
  22. package/bundle/references/artifacts/verbosity-budget-authority.yaml +42 -0
  23. package/bundle/references/cli/app-lifecycle-vocabulary.yaml +3 -4
  24. package/bundle/references/cli/capability-instruction-contract.yaml +11 -14
  25. package/bundle/references/cli/hybrid-route-contract.yaml +438 -0
  26. package/bundle/references/cli/routing-model.md +152 -93
  27. package/bundle/references/cli/trigger-schema-enrichment.md +57 -46
  28. package/bundle/references/cli/update-channels.yaml +4 -2
  29. package/bundle/references/cli/vocabulary-index.yaml +5 -7
  30. package/bundle/references/cli/vocabulary.md +51 -93
  31. package/bundle/references/meta/retained-reference-authority.yaml +151 -0
  32. package/bundle/skills/agentera/SKILL.md +183 -63
  33. package/bundle/skills/agentera/capabilities/audit/schemas/artifacts.yaml +27 -19
  34. package/bundle/skills/agentera/capabilities/audit/schemas/exit.yaml +2 -2
  35. package/bundle/skills/agentera/capabilities/audit/schemas/triggers.yaml +13 -35
  36. package/bundle/skills/agentera/capabilities/audit/schemas/validation.yaml +30 -11
  37. package/bundle/skills/agentera/capabilities/build/schemas/artifacts.yaml +44 -21
  38. package/bundle/skills/agentera/capabilities/build/schemas/exit.yaml +8 -6
  39. package/bundle/skills/agentera/capabilities/build/schemas/triggers.yaml +14 -36
  40. package/bundle/skills/agentera/capabilities/build/schemas/validation.yaml +95 -21
  41. package/bundle/skills/agentera/capabilities/design/schemas/artifacts.yaml +6 -6
  42. package/bundle/skills/agentera/capabilities/design/schemas/exit.yaml +5 -5
  43. package/bundle/skills/agentera/capabilities/design/schemas/triggers.yaml +5 -34
  44. package/bundle/skills/agentera/capabilities/design/schemas/validation.yaml +2 -2
  45. package/bundle/skills/agentera/capabilities/discuss/schemas/artifacts.yaml +17 -13
  46. package/bundle/skills/agentera/capabilities/discuss/schemas/exit.yaml +2 -2
  47. package/bundle/skills/agentera/capabilities/discuss/schemas/triggers.yaml +6 -40
  48. package/bundle/skills/agentera/capabilities/discuss/schemas/validation.yaml +72 -5
  49. package/bundle/skills/agentera/capabilities/document/schemas/artifacts.yaml +24 -17
  50. package/bundle/skills/agentera/capabilities/document/schemas/triggers.yaml +5 -35
  51. package/bundle/skills/agentera/capabilities/document/schemas/validation.yaml +13 -13
  52. package/bundle/skills/agentera/capabilities/optimize/schemas/artifacts.yaml +10 -10
  53. package/bundle/skills/agentera/capabilities/optimize/schemas/exit.yaml +2 -2
  54. package/bundle/skills/agentera/capabilities/optimize/schemas/triggers.yaml +4 -35
  55. package/bundle/skills/agentera/capabilities/optimize/schemas/validation.yaml +3 -3
  56. package/bundle/skills/agentera/capabilities/orchestrate/schemas/artifacts.yaml +34 -22
  57. package/bundle/skills/agentera/capabilities/orchestrate/schemas/exit.yaml +9 -7
  58. package/bundle/skills/agentera/capabilities/orchestrate/schemas/triggers.yaml +5 -37
  59. package/bundle/skills/agentera/capabilities/orchestrate/schemas/validation.yaml +38 -37
  60. package/bundle/skills/agentera/capabilities/plan/schemas/artifacts.yaml +20 -16
  61. package/bundle/skills/agentera/capabilities/plan/schemas/triggers.yaml +8 -31
  62. package/bundle/skills/agentera/capabilities/plan/schemas/validation.yaml +66 -6
  63. package/bundle/skills/agentera/capabilities/profile/schemas/artifacts.yaml +9 -4
  64. package/bundle/skills/agentera/capabilities/profile/schemas/exit.yaml +4 -4
  65. package/bundle/skills/agentera/capabilities/profile/schemas/triggers.yaml +8 -37
  66. package/bundle/skills/agentera/capabilities/profile/schemas/validation.yaml +61 -3
  67. package/bundle/skills/agentera/capabilities/research/schemas/artifacts.yaml +6 -6
  68. package/bundle/skills/agentera/capabilities/research/schemas/triggers.yaml +5 -29
  69. package/bundle/skills/agentera/capabilities/status/schemas/artifacts.yaml +13 -12
  70. package/bundle/skills/agentera/capabilities/status/schemas/triggers.yaml +7 -49
  71. package/bundle/skills/agentera/capabilities/vision/schemas/artifacts.yaml +8 -8
  72. package/bundle/skills/agentera/capabilities/vision/schemas/exit.yaml +7 -6
  73. package/bundle/skills/agentera/capabilities/vision/schemas/triggers.yaml +7 -39
  74. package/bundle/skills/agentera/capabilities/vision/schemas/validation.yaml +14 -16
  75. package/bundle/skills/agentera/capability_schema_contract.yaml +32 -32
  76. package/bundle/skills/agentera/protocol.yaml +4 -4
  77. package/bundle/skills/agentera/route-phrases.yaml +81 -0
  78. package/bundle/skills/agentera/schemas/artifacts/changelog.yaml +1 -0
  79. package/bundle/skills/agentera/schemas/artifacts/decisions.yaml +30 -12
  80. package/bundle/skills/agentera/schemas/artifacts/design.yaml +1 -0
  81. package/bundle/skills/agentera/schemas/artifacts/docs.yaml +7 -12
  82. package/bundle/skills/agentera/schemas/artifacts/experiments.yaml +140 -9
  83. package/bundle/skills/agentera/schemas/artifacts/glossary.yaml +82 -0
  84. package/bundle/skills/agentera/schemas/artifacts/health.yaml +56 -19
  85. package/bundle/skills/agentera/schemas/artifacts/objective.yaml +18 -4
  86. package/bundle/skills/agentera/schemas/artifacts/plan.yaml +457 -32
  87. package/bundle/skills/agentera/schemas/artifacts/progress.yaml +131 -18
  88. package/bundle/skills/agentera/schemas/artifacts/todo.yaml +302 -7
  89. package/dist/analytics/extractCorpus/cli.js +52 -11
  90. package/dist/analytics/extractCorpus/copilotSessions.js +6 -4
  91. package/dist/analytics/extractCorpus/core.js +40 -12
  92. package/dist/analytics/extractCorpus/corpus.js +39 -17
  93. package/dist/analytics/extractCorpus/coverageAudit.js +44 -45
  94. package/dist/analytics/extractCorpus/cursorSessions.js +6 -4
  95. package/dist/analytics/extractCorpus/evidenceTiers.js +603 -0
  96. package/dist/analytics/extractCorpus/extractCorpusParity.js +4 -4
  97. package/dist/analytics/extractCorpus/filesystemSources.js +1 -5
  98. package/dist/analytics/extractCorpus/index.js +3 -1
  99. package/dist/analytics/extractCorpus/jsonlSessions.js +24 -5
  100. package/dist/analytics/extractCorpus/sqliteCaps.js +0 -1
  101. package/dist/analytics/extractCorpus/sqliteSessions.js +0 -1
  102. package/dist/analytics/extractCorpus/tierReader.js +108 -0
  103. package/dist/analytics/extractCorpus.js +0 -1
  104. package/dist/analytics/glossaryAdviceResolution.js +166 -0
  105. package/dist/analytics/glossaryInputAcquisition.js +319 -0
  106. package/dist/analytics/personalGlossaryAdmission.js +133 -0
  107. package/dist/analytics/personalGlossaryProfile.js +219 -0
  108. package/dist/analytics/profileSignals.js +211 -0
  109. package/dist/analytics/usageStats.js +150 -23
  110. package/dist/audit/terminologyDrift.js +281 -0
  111. package/dist/bin/agentera.js +3 -2
  112. package/dist/capabilities/audit/instructions.js +16 -6
  113. package/dist/capabilities/build/instructions.js +59 -6
  114. package/dist/capabilities/design/instructions.js +3 -4
  115. package/dist/capabilities/discuss/instructions.js +29 -6
  116. package/dist/capabilities/document/instructions.js +11 -6
  117. package/dist/capabilities/index.js +16 -14
  118. package/dist/capabilities/optimize/instructions.js +14 -6
  119. package/dist/capabilities/orchestrate/instructions.js +42 -6
  120. package/dist/capabilities/plan/instructions.js +30 -3
  121. package/dist/capabilities/profile/instructions.js +70 -6
  122. package/dist/capabilities/research/instructions.js +4 -5
  123. package/dist/capabilities/status/instructions.js +15 -6
  124. package/dist/capabilities/status/startupInstructions.js +34 -0
  125. package/dist/capabilities/vision/instructions.js +3 -5
  126. package/dist/cli/appContext.js +14 -7
  127. package/dist/cli/argvalidate.js +0 -1
  128. package/dist/cli/capabilityContext/benchmark.js +5 -4
  129. package/dist/cli/capabilityContext/bespoke.js +14 -6
  130. package/dist/cli/capabilityContext/build.js +116 -42
  131. package/dist/cli/capabilityContext/closeout.js +30 -27
  132. package/dist/cli/capabilityContext/contract.js +18 -27
  133. package/dist/cli/capabilityContext/evidence.js +84 -77
  134. package/dist/cli/capabilityContext/index.js +0 -1
  135. package/dist/cli/capabilityContext/orchestration.js +42 -18
  136. package/dist/cli/capabilityContext/planState.js +89 -96
  137. package/dist/cli/capabilityContext/progress.js +51 -12
  138. package/dist/cli/capabilityContext/projectVerification.js +409 -0
  139. package/dist/cli/capabilityContext/shared.js +9 -20
  140. package/dist/cli/capabilityContext/slim.js +52 -8
  141. package/dist/cli/capabilityContext/startup.js +51 -114
  142. package/dist/cli/capabilityContext/startupAggregation.js +68 -0
  143. package/dist/cli/capabilityContext/types.js +26 -10
  144. package/dist/cli/capabilityContext.js +0 -1
  145. package/dist/cli/commands/appHome.js +0 -1
  146. package/dist/cli/commands/capability.js +2 -2
  147. package/dist/cli/commands/compact.js +163 -13
  148. package/dist/cli/commands/doctor.js +117 -11
  149. package/dist/cli/commands/durability.js +81 -0
  150. package/dist/cli/commands/glossaryAdvice.js +138 -0
  151. package/dist/cli/commands/lint.js +22 -8
  152. package/dist/cli/commands/personalGlossary.js +176 -0
  153. package/dist/cli/commands/prime/briefOrientation.js +746 -0
  154. package/dist/cli/commands/prime/buildExecutionRequest.js +165 -0
  155. package/dist/cli/commands/prime/bundleStatus.js +54 -4
  156. package/dist/cli/commands/prime/collectEntityOrientation.js +326 -0
  157. package/dist/cli/commands/prime/collectOrientationState.js +126 -63
  158. package/dist/cli/commands/prime/orientationOutput.js +267 -56
  159. package/dist/cli/commands/prime/types.js +0 -1
  160. package/dist/cli/commands/prime/v1Migration.js +0 -1
  161. package/dist/cli/commands/prime.js +76 -11
  162. package/dist/cli/commands/profileGrounding.js +55 -0
  163. package/dist/cli/commands/query.js +74 -52
  164. package/dist/cli/commands/report.js +73 -19
  165. package/dist/cli/commands/route.js +142 -0
  166. package/dist/cli/commands/schema.js +257 -138
  167. package/dist/cli/commands/state/decisions.js +40 -56
  168. package/dist/cli/commands/state/docs.js +58 -85
  169. package/dist/cli/commands/state/experimentRecords.js +151 -0
  170. package/dist/cli/commands/state/experiments.js +11 -65
  171. package/dist/cli/commands/state/get.js +129 -0
  172. package/dist/cli/commands/state/health.js +11 -113
  173. package/dist/cli/commands/state/index.js +6 -41
  174. package/dist/cli/commands/state/list.js +194 -0
  175. package/dist/cli/commands/state/objective.js +21 -65
  176. package/dist/cli/commands/state/plan.js +11 -170
  177. package/dist/cli/commands/state/planTasks.js +154 -0
  178. package/dist/cli/commands/state/plans.js +154 -0
  179. package/dist/cli/commands/state/progress.js +11 -45
  180. package/dist/cli/commands/state/shared.js +0 -1
  181. package/dist/cli/commands/state/todo.js +28 -107
  182. package/dist/cli/commands/state/write.js +433 -0
  183. package/dist/cli/commands/upgrade.js +146 -5
  184. package/dist/cli/commands/upgradeVerify.js +118 -0
  185. package/dist/cli/commands/validate.js +235 -136
  186. package/dist/cli/commands/verify.js +23 -8
  187. package/dist/cli/contracts/bundleStatus.js +0 -1
  188. package/dist/cli/contracts/orientationState.js +0 -1
  189. package/dist/cli/dispatch/argvParser.js +0 -1
  190. package/dist/cli/dispatch/check.js +84 -40
  191. package/dist/cli/dispatch/commands.js +3 -3
  192. package/dist/cli/dispatch/index.js +77 -52
  193. package/dist/cli/dispatch/lifecycle.js +117 -62
  194. package/dist/cli/dispatch/prime.js +37 -2
  195. package/dist/cli/dispatch/projections.js +17 -0
  196. package/dist/cli/dispatch/shared.js +1 -2
  197. package/dist/cli/dispatch/state.js +62 -66
  198. package/dist/cli/dispatch.js +0 -1
  199. package/dist/cli/errors.js +16 -17
  200. package/dist/cli/help.js +358 -39
  201. package/dist/cli/migrationRequired.js +122 -0
  202. package/dist/cli/orientation/attention.js +19 -19
  203. package/dist/cli/orientation/corpusCoverage.js +32 -1
  204. package/dist/cli/orientation.js +346 -129
  205. package/dist/cli/planArtifacts.js +350 -0
  206. package/dist/cli/planEvidence.js +157 -0
  207. package/dist/cli/planLifecycleState.js +36 -0
  208. package/dist/cli/planTaskIndex.js +11 -0
  209. package/dist/cli/preCutoverCommand.js +32 -0
  210. package/dist/cli/prime-blob.js +71 -3
  211. package/dist/cli/profileAcquisition.js +167 -0
  212. package/dist/cli/startupCompletenessContract.js +11 -8
  213. package/dist/cli/stateQuery.js +47 -12
  214. package/dist/cli/structured.js +0 -1
  215. package/dist/cli/todoMarkdown.js +25 -12
  216. package/dist/cli/todoReadinessSelection.js +192 -0
  217. package/dist/cli/todoSeverity.js +0 -1
  218. package/dist/core/atomicWriter.js +20 -0
  219. package/dist/core/developmentChannel.js +1 -0
  220. package/dist/core/developmentInvocation.js +374 -0
  221. package/dist/core/difflib.js +0 -1
  222. package/dist/core/envPaths.js +0 -1
  223. package/dist/core/jsonValue.js +0 -1
  224. package/dist/core/paths.js +0 -1
  225. package/dist/core/pyjson.js +0 -1
  226. package/dist/core/shell.js +4 -0
  227. package/dist/core/skillIdentity.js +23 -0
  228. package/dist/core/sourceRoot.js +9 -12
  229. package/dist/core/text.js +10 -0
  230. package/dist/core/toml.js +0 -1
  231. package/dist/core/yaml.js +8 -1
  232. package/dist/eval/evalSkills.js +13 -14
  233. package/dist/eval/hybridRouteEvaluation.js +155 -0
  234. package/dist/eval/semanticEval.js +0 -1
  235. package/dist/eval/semanticFixtures.js +0 -1
  236. package/dist/hooks/common.js +3 -56
  237. package/dist/hooks/compaction/apply.js +224 -47
  238. package/dist/hooks/compaction/dryRun.js +2 -1
  239. package/dist/hooks/compaction/index.js +5 -6
  240. package/dist/hooks/compaction/parse.js +73 -6
  241. package/dist/hooks/compaction/retention.js +28 -25
  242. package/dist/hooks/compaction/status.js +145 -26
  243. package/dist/hooks/compaction/types.js +0 -1
  244. package/dist/hooks/validateArtifact/agentFacing.js +0 -1
  245. package/dist/hooks/validateArtifact/index.js +6 -65
  246. package/dist/hooks/validateArtifact/markdown.js +9 -10
  247. package/dist/hooks/validateArtifact/schema.js +96 -9
  248. package/dist/hooks/validateArtifact/traversal.js +12 -11
  249. package/dist/hooks/validateArtifact/violations.js +5 -3
  250. package/dist/migrate/v2HandoffManifest.js +8 -3
  251. package/dist/registries/activationContract.js +2 -0
  252. package/dist/registries/activationTuples.js +108 -0
  253. package/dist/registries/artifactProtocolIds.js +2 -1
  254. package/dist/registries/artifactRegistry.js +207 -60
  255. package/dist/registries/artifactSchemaProjection.js +45 -0
  256. package/dist/registries/capabilityContract.js +5 -21
  257. package/dist/registries/evaluatorHandoffContract.js +0 -1
  258. package/dist/registries/evidenceTierContract.js +371 -0
  259. package/dist/registries/glossaryAdviceContract.js +79 -0
  260. package/dist/registries/glossaryCaveatContract.js +67 -0
  261. package/dist/registries/glossaryConsumerContractValidation.js +787 -0
  262. package/dist/registries/glossaryEntryContract.js +757 -0
  263. package/dist/registries/glossaryTermIdentity.js +17 -0
  264. package/dist/registries/glossaryTermOccurrence.js +20 -0
  265. package/dist/registries/hybridRoute.js +274 -0
  266. package/dist/registries/hybridRouteReceipt.js +221 -0
  267. package/dist/registries/packagePublication.js +273 -0
  268. package/dist/registries/packageRegistry.js +184 -209
  269. package/dist/registries/todoReadinessContract.js +448 -0
  270. package/dist/registries/triggerLoader.js +7 -44
  271. package/dist/registries/verbosityBudgetContract.js +205 -0
  272. package/dist/release/releaseMetadata.js +155 -5
  273. package/dist/runtime/lifecycleAdapterContract.js +457 -0
  274. package/dist/runtime/lifecycleAdapters.js +777 -0
  275. package/dist/runtime/lifecycleAuthority.js +453 -0
  276. package/dist/runtime/lifecycleOperationContract.js +123 -0
  277. package/dist/runtime/lifecycleOperations.js +634 -0
  278. package/dist/runtime/lifecycleOwnershipJournal.js +622 -0
  279. package/dist/runtime/lifecyclePublication.js +415 -0
  280. package/dist/runtime/lifecycleSnapshot.js +438 -0
  281. package/dist/runtime/nativeResourceCleanup.js +502 -0
  282. package/dist/setup/opencode.js +20 -13
  283. package/dist/setup/opencodeConstants.js +1 -0
  284. package/dist/setup/sharedSkill.js +45 -0
  285. package/dist/setup/smokeChecks.js +14 -75
  286. package/dist/state/archiveDiscovery.js +580 -0
  287. package/dist/state/archivePublication.js +225 -0
  288. package/dist/state/archiveRecovery.js +237 -0
  289. package/dist/state/archiveReplay.js +53 -0
  290. package/dist/state/canonicalMigrationRecord.js +36 -0
  291. package/dist/state/changelog.js +221 -0
  292. package/dist/state/decisionEntities.js +367 -0
  293. package/dist/state/decisionLegacyValidation.js +215 -0
  294. package/dist/state/decisionMigrationProvenance.js +199 -0
  295. package/dist/state/decisionOverlay.js +254 -0
  296. package/dist/state/decisionRevision.js +256 -0
  297. package/dist/state/decisionRevisionMigration.js +89 -0
  298. package/dist/state/directRetrieval.js +323 -0
  299. package/dist/state/durability.js +324 -0
  300. package/dist/state/entityCutover.js +459 -0
  301. package/dist/state/entityCutoverGit.js +127 -0
  302. package/dist/state/entityGlossaryAuthority.js +13 -0
  303. package/dist/state/entityListProjection.js +187 -0
  304. package/dist/state/entityListRuntimeRegistry.js +85 -0
  305. package/dist/state/entityMigrationCausality.js +97 -0
  306. package/dist/state/entityMigrationIdentity.js +5 -0
  307. package/dist/state/entityMigrationPreview.js +840 -0
  308. package/dist/state/entityMigrationTodo.js +133 -0
  309. package/dist/state/entityPublicationContext.js +859 -0
  310. package/dist/state/entityRetrievalHelp.js +506 -0
  311. package/dist/state/entityStorage.js +899 -0
  312. package/dist/state/exactReplacementRecovery.js +18 -0
  313. package/dist/state/experimentArchive.js +63 -0
  314. package/dist/state/experimentIdentity.js +202 -0
  315. package/dist/state/healthEntities.js +262 -0
  316. package/dist/state/healthEntityValidation.js +18 -0
  317. package/dist/state/healthRepair.js +69 -0
  318. package/dist/state/installRoot.js +15 -7
  319. package/dist/state/legacyEntityCutoverEvidence.js +65 -0
  320. package/dist/state/legacyIdentity.js +47 -0
  321. package/dist/state/legacySummaryRecord.js +6 -0
  322. package/dist/state/listAccounting.js +54 -0
  323. package/dist/state/listClassification.js +17 -0
  324. package/dist/state/listCursor.js +42 -0
  325. package/dist/state/listRetrieval.js +781 -0
  326. package/dist/state/migrationSourceBinding.js +30 -0
  327. package/dist/state/objectiveExperimentEntities.js +322 -0
  328. package/dist/state/planEntities.js +1027 -0
  329. package/dist/state/planIdentity.js +47 -0
  330. package/dist/state/planLineageValidation.js +52 -0
  331. package/dist/state/planReplacementTransaction.js +475 -0
  332. package/dist/state/planRetrieval.js +313 -0
  333. package/dist/state/planTaskRetrieval.js +294 -0
  334. package/dist/state/progressEntities.js +512 -0
  335. package/dist/state/progressGlossaryCaveat.js +168 -0
  336. package/dist/state/progressPublicationOrder.js +19 -0
  337. package/dist/state/progressWritePolicy.js +33 -0
  338. package/dist/state/projectRoot.js +62 -0
  339. package/dist/state/projectionPolicy.js +190 -0
  340. package/dist/state/retrievalAuthority.js +156 -0
  341. package/dist/state/safeProjectFile.js +155 -0
  342. package/dist/state/startupAnalysis/benchmark.js +70 -9
  343. package/dist/state/startupAnalysis/contract.js +44 -10
  344. package/dist/state/startupAnalysis/helpers.js +1 -2
  345. package/dist/state/startupAnalysis/index.js +0 -1
  346. package/dist/state/startupAnalysis/metrics.js +0 -1
  347. package/dist/state/startupAnalysis/records.js +0 -1
  348. package/dist/state/startupAnalysis/report.js +0 -1
  349. package/dist/state/startupAnalysis/threshold.js +13 -1
  350. package/dist/state/startupAnalysis.js +0 -1
  351. package/dist/state/startupProjection.js +499 -0
  352. package/dist/state/stateMode.js +222 -0
  353. package/dist/state/stateStorageAuthority.js +47 -0
  354. package/dist/state/summaryEntityRead.js +25 -0
  355. package/dist/state/summaryMigrationProvenance.js +66 -0
  356. package/dist/state/summarySourceRowAuthority.js +36 -0
  357. package/dist/state/todoActivationSafety.js +58 -0
  358. package/dist/state/todoDocsEntities.js +1124 -0
  359. package/dist/state/todoDocsEntityValidation.js +158 -0
  360. package/dist/state/todoMarkdownProjection.js +51 -0
  361. package/dist/state/todoReconciliationActivation.js +182 -0
  362. package/dist/state/todoReconciliationInspection.js +171 -0
  363. package/dist/state/todoReconciliationRepair.js +318 -0
  364. package/dist/state/todoReconciliationTransaction.js +595 -0
  365. package/dist/state/write/assign.js +20 -0
  366. package/dist/state/write/candidateMutation.js +269 -0
  367. package/dist/state/write/errors.js +11 -0
  368. package/dist/state/write/experimentPublication.js +192 -0
  369. package/dist/state/write/explain.js +377 -0
  370. package/dist/state/write/fields.js +61 -0
  371. package/dist/state/write/glossaryPublication.js +263 -0
  372. package/dist/state/write/grammar.js +285 -0
  373. package/dist/state/write/helpers.js +29 -0
  374. package/dist/state/write/index.js +12 -0
  375. package/dist/state/write/input.js +391 -0
  376. package/dist/state/write/lock.js +837 -0
  377. package/dist/state/write/mutation.js +234 -0
  378. package/dist/state/write/operations.js +170 -0
  379. package/dist/state/write/planEvaluation.js +128 -0
  380. package/dist/state/write/planPublication.js +179 -0
  381. package/dist/state/write/runtimeOperations.js +146 -0
  382. package/dist/state/write/serialize.js +1 -0
  383. package/dist/state/write/transaction.js +57 -0
  384. package/dist/state/write/validate.js +7 -0
  385. package/dist/upgrade/appContentRefresh.js +77 -36
  386. package/dist/upgrade/appModel.js +0 -1
  387. package/dist/upgrade/atomicWriter.js +1 -0
  388. package/dist/upgrade/bundleEvidence.js +0 -1
  389. package/dist/upgrade/channels.js +6 -9
  390. package/dist/upgrade/compatibility.js +43 -17
  391. package/dist/upgrade/doctor.js +55 -32
  392. package/dist/upgrade/doctorClassifier.js +11 -1
  393. package/dist/upgrade/installedHooksRetirement.js +46 -40
  394. package/dist/upgrade/legacyAgentCleanup.js +187 -21
  395. package/dist/upgrade/lifecycleUpgrade.js +113 -0
  396. package/dist/upgrade/migrateArtifactsV2ToV3.js +334 -64
  397. package/dist/upgrade/migrationPublication.js +122 -0
  398. package/dist/upgrade/nextMajorDoctor.js +0 -1
  399. package/dist/upgrade/npxPlatformStatus.js +0 -1
  400. package/dist/upgrade/projectIntegration.js +121 -159
  401. package/dist/upgrade/projectIntegrationDecision.js +42 -85
  402. package/dist/upgrade/retiredResourceDiagnostics.js +117 -0
  403. package/dist/upgrade/runtimeMigration.js +262 -453
  404. package/dist/upgrade/upgradeCommands.js +14 -1
  405. package/dist/upgrade/upgradeLock.js +85 -0
  406. package/dist/upgrade/upgradeOrchestrator.js +263 -59
  407. package/dist/upgrade/v3CapabilitySurface.js +2 -3
  408. package/dist/upgrade/versionResolution.js +0 -1
  409. package/dist/validate/activationArtifactEvidence.js +852 -0
  410. package/dist/validate/activationArtifactEvidenceTypes.js +12 -0
  411. package/dist/validate/activationConjunction.js +816 -0
  412. package/dist/validate/activationEvidenceManifest.js +531 -0
  413. package/dist/validate/activationPackageSemantics.js +29 -0
  414. package/dist/validate/appHomeContract.js +1 -7
  415. package/dist/validate/bootstrapAuthority.js +44 -0
  416. package/dist/validate/capability.js +11 -3
  417. package/dist/validate/crossCapability.js +14 -9
  418. package/dist/validate/retainedReferenceAuthority.js +879 -0
  419. package/dist/validate/selfAudit.js +39 -45
  420. package/dist/validate/v1LegacyCruft.js +131 -0
  421. package/dist/validate/vocabularyAuthority.js +8 -8
  422. package/package.json +41 -13
  423. package/bundle/references/adapters/cursor.md +0 -214
  424. package/bundle/references/adapters/opencode.md +0 -530
  425. package/bundle/references/adapters/package-manifest-interface-model.yaml +0 -337
  426. package/bundle/references/adapters/runtime-adapter-characterization.md +0 -79
  427. package/bundle/references/adapters/runtime-adapter-interface-model.yaml +0 -200
  428. package/bundle/references/adapters/runtime-adapter-registry.yaml +0 -554
  429. package/bundle/references/adapters/runtime-feature-parity.md +0 -189
  430. package/bundle/references/analysis/benchmark.md +0 -267
  431. package/bundle/references/analysis/startup-measurement-contract.yaml +0 -424
  432. package/bundle/references/cli/agent-ready-state-contract.yaml +0 -953
  433. package/bundle/references/cli/audience-namespace-cli-migration.yaml +0 -369
  434. package/bundle/references/cli/bundle-skill-vocabulary.yaml +0 -250
  435. package/bundle/references/cli/capability-tool-classification.yaml +0 -53
  436. package/bundle/references/cli/coexistence-probe.yaml +0 -13
  437. package/bundle/references/cli/parity-expected-actual-template.md +0 -30
  438. package/bundle/references/cli/routing-execution-vocabulary.yaml +0 -281
  439. package/bundle/references/cli/single-name-protocol.yaml +0 -42
  440. package/bundle/references/cli/upgrade-repair-wording.md +0 -45
  441. package/bundle/references/cli/v3-handoff-manifest.schema.yaml +0 -98
  442. package/bundle/references/meta/documentation-inventory.md +0 -49
  443. package/bundle/skills/agentera/.claude-plugin/plugin.json +0 -27
  444. package/bundle/skills/agentera/agents/audit.toml +0 -6
  445. package/bundle/skills/agentera/agents/build.toml +0 -6
  446. package/bundle/skills/agentera/agents/design.toml +0 -6
  447. package/bundle/skills/agentera/agents/discuss.toml +0 -6
  448. package/bundle/skills/agentera/agents/document.toml +0 -6
  449. package/bundle/skills/agentera/agents/optimize.toml +0 -6
  450. package/bundle/skills/agentera/agents/orchestrate.toml +0 -6
  451. package/bundle/skills/agentera/agents/plan.toml +0 -6
  452. package/bundle/skills/agentera/agents/profile.toml +0 -6
  453. package/bundle/skills/agentera/agents/research.toml +0 -6
  454. package/bundle/skills/agentera/agents/status.toml +0 -6
  455. package/bundle/skills/agentera/agents/vision.toml +0 -6
  456. package/bundle/skills/agentera/references/contract.md +0 -1048
  457. package/dist/analytics/extractCorpus/cli.js.map +0 -1
  458. package/dist/analytics/extractCorpus/copilotSessions.js.map +0 -1
  459. package/dist/analytics/extractCorpus/core.js.map +0 -1
  460. package/dist/analytics/extractCorpus/corpus.js.map +0 -1
  461. package/dist/analytics/extractCorpus/coverageAudit.js.map +0 -1
  462. package/dist/analytics/extractCorpus/cursorSessions.js.map +0 -1
  463. package/dist/analytics/extractCorpus/extractCorpusParity.js.map +0 -1
  464. package/dist/analytics/extractCorpus/filesystemSources.js.map +0 -1
  465. package/dist/analytics/extractCorpus/index.js.map +0 -1
  466. package/dist/analytics/extractCorpus/jsonlSessions.js.map +0 -1
  467. package/dist/analytics/extractCorpus/sqliteCaps.js.map +0 -1
  468. package/dist/analytics/extractCorpus/sqliteSessions.js.map +0 -1
  469. package/dist/analytics/extractCorpus.js.map +0 -1
  470. package/dist/analytics/usageStats.js.map +0 -1
  471. package/dist/bin/agentera.js.map +0 -1
  472. package/dist/capabilities/audit/instructions.js.map +0 -1
  473. package/dist/capabilities/build/instructions.js.map +0 -1
  474. package/dist/capabilities/design/instructions.js.map +0 -1
  475. package/dist/capabilities/discuss/instructions.js.map +0 -1
  476. package/dist/capabilities/document/instructions.js.map +0 -1
  477. package/dist/capabilities/dokumentera/instructions.js +0 -6
  478. package/dist/capabilities/dokumentera/instructions.js.map +0 -1
  479. package/dist/capabilities/hej/instructions.js +0 -6
  480. package/dist/capabilities/hej/instructions.js.map +0 -1
  481. package/dist/capabilities/index.js.map +0 -1
  482. package/dist/capabilities/inspektera/instructions.js +0 -6
  483. package/dist/capabilities/inspektera/instructions.js.map +0 -1
  484. package/dist/capabilities/inspirera/instructions.js +0 -6
  485. package/dist/capabilities/inspirera/instructions.js.map +0 -1
  486. package/dist/capabilities/optimera/instructions.js +0 -6
  487. package/dist/capabilities/optimera/instructions.js.map +0 -1
  488. package/dist/capabilities/optimize/instructions.js.map +0 -1
  489. package/dist/capabilities/orchestrate/instructions.js.map +0 -1
  490. package/dist/capabilities/orkestrera/instructions.js +0 -6
  491. package/dist/capabilities/orkestrera/instructions.js.map +0 -1
  492. package/dist/capabilities/plan/instructions.js.map +0 -1
  493. package/dist/capabilities/planera/instructions.js +0 -6
  494. package/dist/capabilities/planera/instructions.js.map +0 -1
  495. package/dist/capabilities/profile/instructions.js.map +0 -1
  496. package/dist/capabilities/profilera/instructions.js +0 -6
  497. package/dist/capabilities/profilera/instructions.js.map +0 -1
  498. package/dist/capabilities/realisera/instructions.js +0 -6
  499. package/dist/capabilities/realisera/instructions.js.map +0 -1
  500. package/dist/capabilities/research/instructions.js.map +0 -1
  501. package/dist/capabilities/resonera/instructions.js +0 -6
  502. package/dist/capabilities/resonera/instructions.js.map +0 -1
  503. package/dist/capabilities/status/instructions.js.map +0 -1
  504. package/dist/capabilities/vision/instructions.js.map +0 -1
  505. package/dist/capabilities/visionera/instructions.js +0 -6
  506. package/dist/capabilities/visionera/instructions.js.map +0 -1
  507. package/dist/capabilities/visualisera/instructions.js +0 -5
  508. package/dist/capabilities/visualisera/instructions.js.map +0 -1
  509. package/dist/cli/appContext.js.map +0 -1
  510. package/dist/cli/argvalidate.js.map +0 -1
  511. package/dist/cli/capabilityContext/benchmark.js.map +0 -1
  512. package/dist/cli/capabilityContext/bespoke.js.map +0 -1
  513. package/dist/cli/capabilityContext/build.js.map +0 -1
  514. package/dist/cli/capabilityContext/closeout.js.map +0 -1
  515. package/dist/cli/capabilityContext/contract.js.map +0 -1
  516. package/dist/cli/capabilityContext/evidence.js.map +0 -1
  517. package/dist/cli/capabilityContext/index.js.map +0 -1
  518. package/dist/cli/capabilityContext/orchestration.js.map +0 -1
  519. package/dist/cli/capabilityContext/planState.js.map +0 -1
  520. package/dist/cli/capabilityContext/progress.js.map +0 -1
  521. package/dist/cli/capabilityContext/realisera.js +0 -174
  522. package/dist/cli/capabilityContext/realisera.js.map +0 -1
  523. package/dist/cli/capabilityContext/shared.js.map +0 -1
  524. package/dist/cli/capabilityContext/slim.js.map +0 -1
  525. package/dist/cli/capabilityContext/startup.js.map +0 -1
  526. package/dist/cli/capabilityContext/types.js.map +0 -1
  527. package/dist/cli/capabilityContext.js.map +0 -1
  528. package/dist/cli/commands/appHome.js.map +0 -1
  529. package/dist/cli/commands/backfill.js +0 -84
  530. package/dist/cli/commands/backfill.js.map +0 -1
  531. package/dist/cli/commands/capability.js.map +0 -1
  532. package/dist/cli/commands/compact.js.map +0 -1
  533. package/dist/cli/commands/doctor.js.map +0 -1
  534. package/dist/cli/commands/lint.js.map +0 -1
  535. package/dist/cli/commands/prime/bundleStatus.js.map +0 -1
  536. package/dist/cli/commands/prime/collectOrientationState.js.map +0 -1
  537. package/dist/cli/commands/prime/orientationOutput.js.map +0 -1
  538. package/dist/cli/commands/prime/routeOutput.js +0 -50
  539. package/dist/cli/commands/prime/routeOutput.js.map +0 -1
  540. package/dist/cli/commands/prime/types.js.map +0 -1
  541. package/dist/cli/commands/prime/v1Migration.js.map +0 -1
  542. package/dist/cli/commands/prime.js.map +0 -1
  543. package/dist/cli/commands/query.js.map +0 -1
  544. package/dist/cli/commands/report.js.map +0 -1
  545. package/dist/cli/commands/schema.js.map +0 -1
  546. package/dist/cli/commands/state/decisions.js.map +0 -1
  547. package/dist/cli/commands/state/docs.js.map +0 -1
  548. package/dist/cli/commands/state/experiments.js.map +0 -1
  549. package/dist/cli/commands/state/health.js.map +0 -1
  550. package/dist/cli/commands/state/index.js.map +0 -1
  551. package/dist/cli/commands/state/objective.js.map +0 -1
  552. package/dist/cli/commands/state/plan.js.map +0 -1
  553. package/dist/cli/commands/state/progress.js.map +0 -1
  554. package/dist/cli/commands/state/shared.js.map +0 -1
  555. package/dist/cli/commands/state/todo.js.map +0 -1
  556. package/dist/cli/commands/state.js +0 -1023
  557. package/dist/cli/commands/state.js.map +0 -1
  558. package/dist/cli/commands/upgrade.js.map +0 -1
  559. package/dist/cli/commands/validate.js.map +0 -1
  560. package/dist/cli/commands/verify.js.map +0 -1
  561. package/dist/cli/contracts/bundleStatus.js.map +0 -1
  562. package/dist/cli/contracts/orientationState.js.map +0 -1
  563. package/dist/cli/dispatch/argvParser.js.map +0 -1
  564. package/dist/cli/dispatch/check.js.map +0 -1
  565. package/dist/cli/dispatch/commands.js.map +0 -1
  566. package/dist/cli/dispatch/index.js.map +0 -1
  567. package/dist/cli/dispatch/lifecycle.js.map +0 -1
  568. package/dist/cli/dispatch/prime.js.map +0 -1
  569. package/dist/cli/dispatch/shared.js.map +0 -1
  570. package/dist/cli/dispatch/state.js.map +0 -1
  571. package/dist/cli/dispatch.js.map +0 -1
  572. package/dist/cli/errors.js.map +0 -1
  573. package/dist/cli/help.js.map +0 -1
  574. package/dist/cli/orientation/attention.js.map +0 -1
  575. package/dist/cli/orientation/corpusCoverage.js.map +0 -1
  576. package/dist/cli/orientation.js.map +0 -1
  577. package/dist/cli/prime-blob.js.map +0 -1
  578. package/dist/cli/startupCompletenessContract.js.map +0 -1
  579. package/dist/cli/stateQuery.js.map +0 -1
  580. package/dist/cli/structured.js.map +0 -1
  581. package/dist/cli/todoMarkdown.js.map +0 -1
  582. package/dist/cli/todoSeverity.js.map +0 -1
  583. package/dist/core/difflib.js.map +0 -1
  584. package/dist/core/envPaths.js.map +0 -1
  585. package/dist/core/git.js +0 -43
  586. package/dist/core/git.js.map +0 -1
  587. package/dist/core/jsonValue.js.map +0 -1
  588. package/dist/core/paths.js.map +0 -1
  589. package/dist/core/pyjson.js.map +0 -1
  590. package/dist/core/sourceRoot.js.map +0 -1
  591. package/dist/core/toml.js.map +0 -1
  592. package/dist/core/yaml.js.map +0 -1
  593. package/dist/eval/evalSkills.js.map +0 -1
  594. package/dist/eval/semanticEval.js.map +0 -1
  595. package/dist/eval/semanticFixtures.js.map +0 -1
  596. package/dist/hooks/common.js.map +0 -1
  597. package/dist/hooks/compaction/apply.js.map +0 -1
  598. package/dist/hooks/compaction/dryRun.js.map +0 -1
  599. package/dist/hooks/compaction/index.js.map +0 -1
  600. package/dist/hooks/compaction/parse.js.map +0 -1
  601. package/dist/hooks/compaction/retention.js.map +0 -1
  602. package/dist/hooks/compaction/status.js.map +0 -1
  603. package/dist/hooks/compaction/todoResolved.js +0 -137
  604. package/dist/hooks/compaction/todoResolved.js.map +0 -1
  605. package/dist/hooks/compaction/types.js.map +0 -1
  606. package/dist/hooks/compaction.js +0 -935
  607. package/dist/hooks/compaction.js.map +0 -1
  608. package/dist/hooks/cursorPreToolUse.js +0 -19
  609. package/dist/hooks/cursorPreToolUse.js.map +0 -1
  610. package/dist/hooks/cursorSessionStart.js +0 -79
  611. package/dist/hooks/cursorSessionStart.js.map +0 -1
  612. package/dist/hooks/sessionStart.js +0 -216
  613. package/dist/hooks/sessionStart.js.map +0 -1
  614. package/dist/hooks/sessionStop.js +0 -206
  615. package/dist/hooks/sessionStop.js.map +0 -1
  616. package/dist/hooks/todoLayout.js +0 -177
  617. package/dist/hooks/todoLayout.js.map +0 -1
  618. package/dist/hooks/validateArtifact/agentFacing.js.map +0 -1
  619. package/dist/hooks/validateArtifact/index.js.map +0 -1
  620. package/dist/hooks/validateArtifact/markdown.js.map +0 -1
  621. package/dist/hooks/validateArtifact/runtime.js +0 -86
  622. package/dist/hooks/validateArtifact/runtime.js.map +0 -1
  623. package/dist/hooks/validateArtifact/schema.js.map +0 -1
  624. package/dist/hooks/validateArtifact/traversal.js.map +0 -1
  625. package/dist/hooks/validateArtifact/violations.js.map +0 -1
  626. package/dist/hooks/validateArtifact.js +0 -924
  627. package/dist/hooks/validateArtifact.js.map +0 -1
  628. package/dist/migrate/v2HandoffManifest.js.map +0 -1
  629. package/dist/registries/artifactProtocolIds.js.map +0 -1
  630. package/dist/registries/artifactRegistry.js.map +0 -1
  631. package/dist/registries/capabilityContract.js.map +0 -1
  632. package/dist/registries/evaluatorHandoffContract.js.map +0 -1
  633. package/dist/registries/packageRegistry.js.map +0 -1
  634. package/dist/registries/runtimeAdapterRegistry.js +0 -316
  635. package/dist/registries/runtimeAdapterRegistry.js.map +0 -1
  636. package/dist/registries/triggerLoader.js.map +0 -1
  637. package/dist/release/releaseMetadata.js.map +0 -1
  638. package/dist/routing/index.js +0 -2
  639. package/dist/routing/index.js.map +0 -1
  640. package/dist/routing/routeEngine.js +0 -189
  641. package/dist/routing/routeEngine.js.map +0 -1
  642. package/dist/setup/codex/agents.js +0 -96
  643. package/dist/setup/codex/agents.js.map +0 -1
  644. package/dist/setup/codex/cli.js +0 -161
  645. package/dist/setup/codex/cli.js.map +0 -1
  646. package/dist/setup/codex/configToml.js +0 -639
  647. package/dist/setup/codex/configToml.js.map +0 -1
  648. package/dist/setup/codex/constants.js +0 -29
  649. package/dist/setup/codex/constants.js.map +0 -1
  650. package/dist/setup/codex/installRoot.js +0 -64
  651. package/dist/setup/codex/installRoot.js.map +0 -1
  652. package/dist/setup/codex/state.js +0 -270
  653. package/dist/setup/codex/state.js.map +0 -1
  654. package/dist/setup/codex.js +0 -12
  655. package/dist/setup/codex.js.map +0 -1
  656. package/dist/setup/copilot.js +0 -227
  657. package/dist/setup/copilot.js.map +0 -1
  658. package/dist/setup/cursor.js +0 -129
  659. package/dist/setup/cursor.js.map +0 -1
  660. package/dist/setup/cursorSurfaces.js +0 -67
  661. package/dist/setup/cursorSurfaces.js.map +0 -1
  662. package/dist/setup/doctor/core.js +0 -300
  663. package/dist/setup/doctor/core.js.map +0 -1
  664. package/dist/setup/doctor/diagnostics.js +0 -240
  665. package/dist/setup/doctor/diagnostics.js.map +0 -1
  666. package/dist/setup/doctor/opencode.js +0 -313
  667. package/dist/setup/doctor/opencode.js.map +0 -1
  668. package/dist/setup/doctor/report.js +0 -425
  669. package/dist/setup/doctor/report.js.map +0 -1
  670. package/dist/setup/doctor.js +0 -10
  671. package/dist/setup/doctor.js.map +0 -1
  672. package/dist/setup/opencode.js.map +0 -1
  673. package/dist/setup/smokeChecks.js.map +0 -1
  674. package/dist/state/installRoot.js.map +0 -1
  675. package/dist/state/progressCommit.js +0 -289
  676. package/dist/state/progressCommit.js.map +0 -1
  677. package/dist/state/startupAnalysis/benchmark.js.map +0 -1
  678. package/dist/state/startupAnalysis/contract.js.map +0 -1
  679. package/dist/state/startupAnalysis/helpers.js.map +0 -1
  680. package/dist/state/startupAnalysis/index.js.map +0 -1
  681. package/dist/state/startupAnalysis/metrics.js.map +0 -1
  682. package/dist/state/startupAnalysis/records.js.map +0 -1
  683. package/dist/state/startupAnalysis/report.js.map +0 -1
  684. package/dist/state/startupAnalysis/threshold.js.map +0 -1
  685. package/dist/state/startupAnalysis.js.map +0 -1
  686. package/dist/upgrade/appContentRefresh.js.map +0 -1
  687. package/dist/upgrade/appModel.js.map +0 -1
  688. package/dist/upgrade/bundleEvidence.js.map +0 -1
  689. package/dist/upgrade/channels.js.map +0 -1
  690. package/dist/upgrade/cliProbe.js +0 -22
  691. package/dist/upgrade/cliProbe.js.map +0 -1
  692. package/dist/upgrade/coexistenceProbe.js +0 -107
  693. package/dist/upgrade/coexistenceProbe.js.map +0 -1
  694. package/dist/upgrade/compatibility.js.map +0 -1
  695. package/dist/upgrade/doctor.js.map +0 -1
  696. package/dist/upgrade/doctorClassifier.js.map +0 -1
  697. package/dist/upgrade/installedHooksRetirement.js.map +0 -1
  698. package/dist/upgrade/legacyAgentCleanup.js.map +0 -1
  699. package/dist/upgrade/migrateArtifactsV1ToV2.js +0 -570
  700. package/dist/upgrade/migrateArtifactsV1ToV2.js.map +0 -1
  701. package/dist/upgrade/migrateArtifactsV2ToV3.js.map +0 -1
  702. package/dist/upgrade/nextMajorDoctor.js.map +0 -1
  703. package/dist/upgrade/npxPlatformStatus.js.map +0 -1
  704. package/dist/upgrade/projectIntegration.js.map +0 -1
  705. package/dist/upgrade/projectIntegrationDecision.js.map +0 -1
  706. package/dist/upgrade/runtimeMigration.js.map +0 -1
  707. package/dist/upgrade/upgradeCommands.js.map +0 -1
  708. package/dist/upgrade/upgradeOrchestrator.js.map +0 -1
  709. package/dist/upgrade/v3CapabilitySurface.js.map +0 -1
  710. package/dist/upgrade/versionResolution.js.map +0 -1
  711. package/dist/validate/appHomeContract.js.map +0 -1
  712. package/dist/validate/capability.js.map +0 -1
  713. package/dist/validate/crossCapability.js.map +0 -1
  714. package/dist/validate/lifecycleAdapters/legacyPythonParity.js +0 -93
  715. package/dist/validate/lifecycleAdapters/legacyPythonParity.js.map +0 -1
  716. package/dist/validate/lifecycleAdapters/nodeFormChecks.js +0 -488
  717. package/dist/validate/lifecycleAdapters/nodeFormChecks.js.map +0 -1
  718. package/dist/validate/lifecycleAdapters/shared.js +0 -198
  719. package/dist/validate/lifecycleAdapters/shared.js.map +0 -1
  720. package/dist/validate/lifecycleAdapters.js +0 -62
  721. package/dist/validate/lifecycleAdapters.js.map +0 -1
  722. package/dist/validate/selfAudit.js.map +0 -1
  723. package/dist/validate/vocabularyAuthority.js.map +0 -1
@@ -0,0 +1,1027 @@
1
+ import { createHash, createHmac, timingSafeEqual } from "node:crypto";
2
+ import fs from "node:fs";
3
+ import path from "node:path";
4
+ import { resolveSourceRoot } from "../core/sourceRoot.js";
5
+ import { dumpYamlMapping } from "../core/yaml.js";
6
+ import { canonicalRecordJson } from "./archiveDiscovery.js";
7
+ import { StateRetrievalFailure } from "./directRetrieval.js";
8
+ import { allocateEntityId, canonicalEntityEnvelopeBytes, entityExactGetMaxBytes, exactDiscoveredEntityBytes, publishEntity, replaceEntity, replaceEntityUnderLock, validateEntityDiscovery, validateEntityState, withEntityWriterLock } from "./entityStorage.js";
9
+ import { EntityPublicationContext } from "./entityPublicationContext.js";
10
+ import { inspectPendingPlanReplacement, publishPlanReplacement, recoverPendingPlanReplacement } from "./planReplacementTransaction.js";
11
+ import { detectStateModeBinding, freshEntityStateMarker, freshPlanInitialization } from "./stateMode.js";
12
+ import { normalizeAndValidatePlanCreateInput, validatePlanPublicationCandidate } from "./write/planPublication.js";
13
+ import { reject } from "./write/errors.js";
14
+ import { mutatePlanTaskEvaluation, planTaskRecordViolations } from "./write/planEvaluation.js";
15
+ import { loadStateStorageAuthority } from "./stateStorageAuthority.js";
16
+ import { entityListSelectorFlags, entityListSelectorKey, projectEntityList, resolveEntityListSelector } from "./entityListProjection.js";
17
+ import { shellQuoteArgument } from "../core/shell.js";
18
+ import { preCutoverCommand } from "../cli/preCutoverCommand.js";
19
+ const ARTIFACT = "plan";
20
+ const PLAN = "plan";
21
+ const TASK = "plan_task";
22
+ const ID = /^[a-z]{10}$/;
23
+ const OPEN = new Set(["open"]);
24
+ const ORDER = "created_desc_then_id_asc";
25
+ const TASK_ORDER = "id_asc";
26
+ function mapping(value) { return value !== null && typeof value === "object" && !Array.isArray(value); }
27
+ function contract(sourceRoot = resolveSourceRoot()) {
28
+ const { authorityPath, document: authority } = loadStateStorageAuthority(sourceRoot);
29
+ const target = mapping(authority.entity_target) ? authority.entity_target : {};
30
+ const storage = mapping(target.storage_boundary) && mapping(target.storage_boundary.shared_primitives) ? target.storage_boundary.shared_primitives : {};
31
+ const definitions = Array.isArray(target.entities) ? target.entities : [];
32
+ const definition = definitions.find((value) => mapping(value) && value.boundary === PLAN);
33
+ const retrieval = mapping(definition) && mapping(definition.retrieval) ? definition.retrieval : {};
34
+ const number = (value, field) => {
35
+ const result = Number(value);
36
+ if (!Number.isSafeInteger(result) || result < 1)
37
+ throw new Error(`invalid plan entity ${field} authority`);
38
+ return result;
39
+ };
40
+ const grammar = mapping(authority.mutation_grammar) ? authority.mutation_grammar : {};
41
+ const operations = Array.isArray(grammar.operations) ? grammar.operations : [];
42
+ const lifecycleLimits = ["create", "archive"].map((verb) => {
43
+ const operation = operations.find((value) => mapping(value) && value.artifact === ARTIFACT && value.verb === verb);
44
+ const bounds = mapping(operation) && mapping(operation.bounds) ? operation.bounds : {};
45
+ return number(bounds.max_collection_items, `plan ${verb} max_collection_items`);
46
+ });
47
+ if (new Set(lifecycleLimits).size !== 1)
48
+ throw new Error("invalid plan lifecycle max_collection_items authority");
49
+ if (typeof storage.canonical_root !== "string")
50
+ throw new Error(`invalid plan entity authority '${authorityPath}'`);
51
+ return { authorityPath, entityRoot: storage.canonical_root, defaultLimit: number(retrieval.default_limit, "default_limit"), maximumLimit: number(retrieval.maximum_limit, "maximum_limit"), maxUtf8Bytes: number(retrieval.max_utf8_bytes, "max_utf8_bytes"), openPlanConflictLimit: lifecycleLimits[0] };
52
+ }
53
+ function failure(kind, message, recovery, id, details) {
54
+ const exampleId = id && ID.test(id) ? id : "qjtrmnpvka";
55
+ return new StateRetrievalFailure({ schemaVersion: "agentera.stateFailure.v1", status: "fail", error: { class: kind, message, syntax: "agentera state plan get --id ID --format json", example: `agentera state plan get --id ${exampleId} --format json`, recovery, artifact: ARTIFACT, ...(id ? { id } : {}), ...(details ? { details } : {}) } }, kind === "invalid_request" ? 2 : 1);
56
+ }
57
+ function relative(root, file) { return path.relative(path.resolve(root), file).split(path.sep).join("/"); }
58
+ function all(root, sourceRoot, discovery) {
59
+ try {
60
+ const pending = inspectPendingPlanReplacement(root);
61
+ if (pending) {
62
+ const recovery = pending.kind === "existing"
63
+ ? `Retry agentera state plan replace --predecessor ${pending.predecessor} --successor ${pending.successor} --format json to recover the exact pending replacement.`
64
+ : `Retry the exact original agentera state plan replace --predecessor ${pending.predecessor} --input PLAN.yaml --format json request to recover the pending replacement.`;
65
+ throw failure("unsupported_state", `plan replacement from '${pending.predecessor}' to '${pending.successor}' is pending durable recovery`, recovery, pending.predecessor);
66
+ }
67
+ }
68
+ catch (error) {
69
+ if (error instanceof StateRetrievalFailure)
70
+ throw error;
71
+ throw failure("unsupported_state", `plan replacement recovery state is unavailable: ${error.message}`, "Preserve '.agentera/.entity-recovery/plan-replacement', restore its last valid journal bytes, then retry the exact plan replacement.");
72
+ }
73
+ const discovered = discovery
74
+ ? validateEntityDiscovery(root, sourceRoot, discovery)
75
+ : validateEntityState(root, sourceRoot);
76
+ const graphIssue = discovered.issues.find((issue) => issue.artifact === ARTIFACT || issue.boundary === PLAN || issue.boundary === TASK);
77
+ if (graphIssue)
78
+ throw failure(graphIssue.code === "duplicate_id" ? "ambiguous" : "corrupt", graphIssue.message, graphIssue.recovery, graphIssue.id);
79
+ const relevant = discovered.entities.filter((entity) => entity.artifact === ARTIFACT || entity.boundary === PLAN || entity.boundary === TASK);
80
+ const bad = relevant.find((entity) => entity.classification !== "valid" || !entity.id || !entity.record);
81
+ if (bad)
82
+ throw failure(bad.classification === "duplicate" ? "ambiguous" : "corrupt", `plan entity '${bad.relativePath}' is not canonical`, "Run agentera check validate state and resolve the reported plan ownership conflict.", bad.id ?? undefined);
83
+ return relevant;
84
+ }
85
+ function planStatus(entity) { return String(mapping(entity.record?.header) ? entity.record.header.status ?? "" : entity.record?.status ?? ""); }
86
+ /**
87
+ * Report competing canonical plans without inferring replacement roles from
88
+ * list order. The targeted replacement command remains the one recovery seam.
89
+ */
90
+ export function openPlanConflictDiagnostic(openIds, sourceRoot = resolveSourceRoot()) {
91
+ const allIds = [...openIds].sort();
92
+ const sampleIds = allIds.slice(0, contract(sourceRoot).openPlanConflictLimit);
93
+ const omittedCount = allIds.length - sampleIds.length;
94
+ return {
95
+ message: `multiple open plans exist: ${sampleIds.join(", ")} (total=${allIds.length}, omitted=${omittedCount}); canonical state does not assign predecessor or successor roles`,
96
+ details: { open_plan_candidates: { total: allIds.length, sample_ids: sampleIds, omitted_count: omittedCount } },
97
+ recovery: preCutoverCommand("state plan replace --predecessor PREDECESSOR_ID --successor SUCCESSOR_ID --format json"),
98
+ };
99
+ }
100
+ function multipleOpenPlanConflict(open, sourceRoot) {
101
+ return openPlanConflictDiagnostic(open.map((entity) => entity.id), sourceRoot);
102
+ }
103
+ function selectedPlan(entities, requested, sourceRoot = resolveSourceRoot()) {
104
+ if (requested !== undefined && !ID.test(requested))
105
+ throw failure("invalid_request", `plan ID '${requested}' must be ten lowercase letters`, "Use a bare plan ID returned by plan create or list.", requested);
106
+ const plans = entities.filter((entity) => entity.boundary === PLAN);
107
+ if (requested) {
108
+ const matches = plans.filter((entity) => entity.id === requested);
109
+ if (matches.length !== 1)
110
+ throw failure(matches.length ? "ambiguous" : "not_found", matches.length ? `plan ID '${requested}' has conflicting ownership` : `plan ID '${requested}' was not found`, "Run agentera state plan list --format json and select one canonical plan ID.", requested);
111
+ return matches[0];
112
+ }
113
+ const open = plans.filter((entity) => OPEN.has(planStatus(entity)));
114
+ if (open.length === 1)
115
+ return open[0];
116
+ if (open.length === 0)
117
+ throw failure("not_found", "no open plan exists", "Create a plan, or use agentera state plan get --id ID for completed plan detail.");
118
+ const conflict = multipleOpenPlanConflict(open, sourceRoot);
119
+ throw failure("ambiguous", conflict.message, conflict.recovery, undefined, conflict.details);
120
+ }
121
+ function archivedPlanRecord(plan) {
122
+ const record = structuredClone(plan.record);
123
+ const header = mapping(record.header) ? record.header : {};
124
+ header.status = "archived";
125
+ record.header = header;
126
+ return record;
127
+ }
128
+ function preservedPlanEffects(plan) {
129
+ return {
130
+ id: plan.id,
131
+ from_status: planStatus(plan),
132
+ to_status: "archived",
133
+ preserved: ["task_records", "task_evaluations", "task_completion"],
134
+ };
135
+ }
136
+ function planLifecycleDecision(entities, intent, sourceRoot) {
137
+ const plans = entities.filter((entity) => entity.boundary === PLAN);
138
+ const open = plans.filter((entity) => planStatus(entity) === "open");
139
+ if (intent.verb === "create") {
140
+ if (open.length > 1) {
141
+ const conflict = multipleOpenPlanConflict(open, sourceRoot);
142
+ reject({
143
+ class: "conflict",
144
+ message: `${conflict.message}; implicit plan create cannot choose a predecessor`,
145
+ diagnosis: conflict.details,
146
+ recovery: conflict.recovery,
147
+ });
148
+ }
149
+ if (open.length === 1) {
150
+ const predecessor = open[0];
151
+ if (!intent.force) {
152
+ reject({
153
+ class: "conflict",
154
+ message: `open plan '${predecessor.id}' blocks plan create`,
155
+ recovery: `Use agentera state plan create --force --input PLAN.yaml --format json only to archive '${predecessor.id}' unchanged and publish a successor.`,
156
+ });
157
+ }
158
+ return {
159
+ predecessor,
160
+ archivedRecord: archivedPlanRecord(predecessor),
161
+ replay: false,
162
+ effects: {
163
+ lifecycle: "forced_replacement",
164
+ force: true,
165
+ archived_predecessor: preservedPlanEffects(predecessor),
166
+ successor_lineage: { field: "previous_plan_archived", predecessor: predecessor.id },
167
+ },
168
+ };
169
+ }
170
+ const completed = plans.filter((entity) => planStatus(entity) === "complete");
171
+ const predecessor = completed.length === 1 ? completed[0] : undefined;
172
+ return {
173
+ ...(predecessor ? { predecessor, archivedRecord: archivedPlanRecord(predecessor) } : {}),
174
+ replay: false,
175
+ effects: {
176
+ lifecycle: predecessor ? "completed_predecessor_replacement" : "create",
177
+ force: intent.force,
178
+ ...(predecessor ? {
179
+ archived_predecessor: preservedPlanEffects(predecessor),
180
+ successor_lineage: { field: "previous_plan_archived", predecessor: predecessor.id },
181
+ } : {}),
182
+ },
183
+ };
184
+ }
185
+ const target = selectedPlan(entities, intent.plan, sourceRoot);
186
+ const status = planStatus(target);
187
+ if (status === "open" && !intent.force) {
188
+ reject({
189
+ class: "conflict",
190
+ message: `open plan '${target.id}' cannot be archived without --force`,
191
+ recovery: `Complete '${target.id}', or use agentera state plan archive --plan ${target.id} --force --format json to preserve unfinished task history without claiming completion.`,
192
+ });
193
+ }
194
+ const archivedRecord = archivedPlanRecord(target);
195
+ const replay = canonicalRecordJson(archivedRecord) === canonicalRecordJson(target.record);
196
+ return {
197
+ target,
198
+ archivedRecord,
199
+ replay,
200
+ effects: {
201
+ lifecycle: status === "open" ? "forced_archive" : "archive",
202
+ force: intent.force,
203
+ archived_plan: preservedPlanEffects(target),
204
+ },
205
+ };
206
+ }
207
+ function taskFor(entities, id, plan) {
208
+ if (!ID.test(id))
209
+ throw failure("invalid_request", `task ID '${id}' must be ten lowercase letters`, "Use a bare task ID returned by plan task append or list.", id);
210
+ if (plan !== undefined && !ID.test(plan))
211
+ throw failure("invalid_request", `plan ID '${plan}' must be ten lowercase letters`, "Use a bare plan ID returned by plan create or list.", plan);
212
+ const matches = entities.filter((entity) => entity.boundary === TASK && entity.id === id);
213
+ if (matches.length !== 1)
214
+ throw failure(matches.length ? "ambiguous" : "not_found", matches.length ? `task ID '${id}' has conflicting ownership` : `task ID '${id}' was not found`, "Run agentera check validate state, or list tasks and retry with one canonical ID.", id);
215
+ if (plan && matches[0].record?.plan !== plan)
216
+ throw failure("not_found", `task ID '${id}' does not belong to plan '${plan}'`, "List tasks for the selected plan and retry.", id);
217
+ return matches[0];
218
+ }
219
+ function entityPath(root, sourceRoot, boundary, id) { return path.join(root, contract(sourceRoot).entityRoot, ARTIFACT, boundary, `${id}.yaml`); }
220
+ function envelope(command, entity, record, dryRun, extra = {}) {
221
+ return { schemaVersion: "agentera.stateWrite.v1", command, status: "pass", path: entity.path, id: entity.id, artifact: ARTIFACT, record, operation: { verb: command.split(" ").at(-1), dry_run: dryRun, idempotent_replay: entity.replay }, validation: { status: "pass", violations: [] }, ...extra };
222
+ }
223
+ function newId(root, sourceRoot, reserved, candidate) {
224
+ for (let attempt = 0; attempt < 1024; attempt += 1) {
225
+ const id = allocateEntityId(root, candidate, sourceRoot);
226
+ if (!reserved.has(id)) {
227
+ reserved.add(id);
228
+ return id;
229
+ }
230
+ }
231
+ throw new Error("could not allocate unique plan entity IDs");
232
+ }
233
+ function preparedPlanCreateInput(req) {
234
+ const input = structuredClone(req.input ?? {});
235
+ normalizeAndValidatePlanCreateInput(input);
236
+ validatePlanPublicationCandidate(dumpYamlMapping(input));
237
+ return input;
238
+ }
239
+ export function createPlanEntities(req, options = {}) {
240
+ if (!options.publicationContext) {
241
+ const binding = detectStateModeBinding(req.projectRoot, options.sourceRoot);
242
+ if (binding.mode !== "entities")
243
+ throw new Error("plan entity creation requires the durable entity-mode marker");
244
+ try {
245
+ return createPlanEntities(req, { ...options, publicationContext: binding.publicationContext });
246
+ }
247
+ finally {
248
+ binding.publicationContext.close();
249
+ }
250
+ }
251
+ return withEntityWriterLock(options.publicationContext, () => createPlanEntitiesUnderLock(req, options));
252
+ }
253
+ /** The first Plan is the sole marker-absent entity initializer. */
254
+ export function createFreshPlanEntities(req, options = {}) {
255
+ const sourceRoot = options.sourceRoot ?? resolveSourceRoot();
256
+ const initialization = freshPlanInitialization(req.projectRoot, sourceRoot);
257
+ if (!initialization)
258
+ return null;
259
+ const publicationContext = EntityPublicationContext.beginInitialization(initialization.root, initialization.markerPath);
260
+ try {
261
+ return createPlanEntities(req, { ...options, sourceRoot, publicationContext });
262
+ }
263
+ finally {
264
+ publicationContext.close();
265
+ }
266
+ }
267
+ function createPlanEntitiesUnderLock(req, options) {
268
+ const sourceRoot = options.sourceRoot ?? resolveSourceRoot();
269
+ const initializing = options.publicationContext.isInitializing();
270
+ const marker = initializing ? freshEntityStateMarker(sourceRoot) : null;
271
+ const input = preparedPlanCreateInput(req);
272
+ const discovery = validateEntityState(options.publicationContext.pinnedPath(), sourceRoot, { kind: "project", projectRoot: options.publicationContext.validatedRoot });
273
+ const entities = all(options.publicationContext.pinnedPath(), sourceRoot, discovery);
274
+ const lifecycle = options.lifecycle ?? planLifecycleDecision(entities, { verb: "create", force: req.force }, sourceRoot);
275
+ const command = options.command ?? "state plan create";
276
+ const tasks = Array.isArray(input.tasks) ? input.tasks.filter(mapping) : [];
277
+ const reserved = new Set();
278
+ const planId = newId(options.publicationContext?.pinnedPath() ?? req.projectRoot, sourceRoot, reserved, options.candidate);
279
+ const taskIds = tasks.map(() => newId(options.publicationContext?.pinnedPath() ?? req.projectRoot, sourceRoot, reserved, options.candidate));
280
+ const byNumber = new Map(tasks.map((task, index) => [Number(task.number), taskIds[index]]));
281
+ const planRecord = structuredClone(input);
282
+ delete planRecord.tasks;
283
+ delete planRecord.previous_plan_archived;
284
+ delete planRecord.replacement_input_sha256;
285
+ const header = mapping(planRecord.header) ? planRecord.header : {};
286
+ delete header.id;
287
+ planRecord.header = header;
288
+ if (header.status === "active")
289
+ header.status = "open";
290
+ if (header.status === "completed")
291
+ header.status = "complete";
292
+ if (lifecycle.predecessor)
293
+ planRecord.previous_plan_archived = lifecycle.predecessor.id;
294
+ if (lifecycle.replacementInputSha256)
295
+ planRecord.replacement_input_sha256 = lifecycle.replacementInputSha256;
296
+ const taskRecords = tasks.map((task, index) => {
297
+ const record = structuredClone(task);
298
+ delete record.number;
299
+ record.plan = planId;
300
+ const dependencies = Array.isArray(record.depends_on) ? record.depends_on : [];
301
+ record.depends_on = dependencies.map((value) => {
302
+ const target = byNumber.get(Number(value));
303
+ if (!target)
304
+ reject({ class: "schema_violation", message: `task ${index + 1} create-local dependency '${String(value)}' does not resolve within the atomic plan input` });
305
+ return target;
306
+ });
307
+ if (!Array.isArray(record.acceptance))
308
+ record.acceptance = [];
309
+ return record;
310
+ });
311
+ const publications = [{ boundary: PLAN, id: planId, record: planRecord }, ...taskRecords.map((record, index) => ({ boundary: TASK, id: taskIds[index], record }))];
312
+ const resultExtra = {
313
+ tasks: taskRecords.map((record, index) => ({ id: taskIds[index], artifact: ARTIFACT, record })),
314
+ effects: lifecycle.effects,
315
+ ...(marker ? {
316
+ initialization: {
317
+ atomic: true,
318
+ marker: {
319
+ path: path.join(req.projectRoot, options.publicationContext.markerPath),
320
+ record: marker,
321
+ },
322
+ },
323
+ } : {}),
324
+ };
325
+ if (req.dryRun)
326
+ return envelope(command, { id: planId, path: entityPath(req.projectRoot, sourceRoot, PLAN, planId), replay: false }, planRecord, true, resultExtra);
327
+ if (command === "state plan replace" && lifecycle.predecessor && lifecycle.archivedRecord && lifecycle.replacementInputSha256) {
328
+ const targets = [
329
+ {
330
+ path: relative(req.projectRoot, lifecycle.predecessor.path),
331
+ before: exactDiscoveredEntityBytes(lifecycle.predecessor),
332
+ after: canonicalEntityEnvelopeBytes({ id: lifecycle.predecessor.id, artifact: ARTIFACT, record: lifecycle.archivedRecord, migrationProvenance: lifecycle.predecessor.migrationProvenance ?? undefined }),
333
+ },
334
+ ...publications.map((item) => ({
335
+ path: relative(req.projectRoot, entityPath(req.projectRoot, sourceRoot, item.boundary, item.id)),
336
+ before: null,
337
+ after: canonicalEntityEnvelopeBytes({ id: item.id, artifact: ARTIFACT, record: item.record }),
338
+ })),
339
+ ];
340
+ publishPlanReplacement(options.publicationContext, sourceRoot, { kind: "create", predecessor: lifecycle.predecessor.id, successor: planId, inputSha256: lifecycle.replacementInputSha256 }, targets, {
341
+ validate: () => {
342
+ const validation = validateEntityState(options.publicationContext.pinnedPath(), sourceRoot, { kind: "project", projectRoot: options.publicationContext.validatedRoot });
343
+ if (!validation.valid)
344
+ throw new Error(`targeted plan replacement graph failed state validation: ${validation.issues.map(({ message }) => message).join("; ")}`);
345
+ },
346
+ });
347
+ return envelope(command, { id: planId, path: entityPath(req.projectRoot, sourceRoot, PLAN, planId), replay: false }, planRecord, false, resultExtra);
348
+ }
349
+ const published = [];
350
+ let predecessor;
351
+ let markerIdentity;
352
+ try {
353
+ if (lifecycle.predecessor && lifecycle.archivedRecord) {
354
+ const archived = replaceEntityUnderLock({ projectRoot: req.projectRoot, sourceRoot, publicationContext: options.publicationContext, artifact: ARTIFACT, boundary: PLAN, id: lifecycle.predecessor.id, expectedRecord: lifecycle.predecessor.record, expectedBytes: exactDiscoveredEntityBytes(lifecycle.predecessor), migrationProvenance: lifecycle.predecessor.migrationProvenance, record: lifecycle.archivedRecord });
355
+ if (!archived.publishedIdentity || archived.previousBytes === undefined)
356
+ throw new Error(`predecessor '${lifecycle.predecessor.id}' archive did not retain its exact recovery identity and bytes`);
357
+ predecessor = { relative: relative(req.projectRoot, archived.path), archivedIdentity: archived.publishedIdentity, bytes: archived.previousBytes };
358
+ }
359
+ for (const item of publications) {
360
+ const result = publishEntity({ projectRoot: req.projectRoot, sourceRoot, publicationContext: options.publicationContext, artifact: ARTIFACT, ...item });
361
+ if (!result.replay) {
362
+ if (!result.publishedIdentity)
363
+ throw new Error(`entity '${item.id}' publication did not return its exact target identity`);
364
+ published.push({ relative: relative(req.projectRoot, result.path), identity: result.publishedIdentity });
365
+ }
366
+ }
367
+ options.publicationContext.assertValid();
368
+ const validation = validateEntityState(options.publicationContext.pinnedPath(), sourceRoot, { kind: "project", projectRoot: options.publicationContext.validatedRoot });
369
+ if (!validation.valid)
370
+ throw new Error(`created plan graph failed state validation: ${validation.issues.map(({ message }) => message).join("; ")}`);
371
+ options.publicationContext.assertValid();
372
+ if (marker) {
373
+ markerIdentity = options.publicationContext.publishStateMarker(dumpYamlMapping(marker));
374
+ options.publicationContext.assertValid();
375
+ }
376
+ }
377
+ catch (error) {
378
+ const recoveryFailures = [];
379
+ for (const item of published.reverse()) {
380
+ try {
381
+ const removed = options.publicationContext.removeExact(item.relative, item.identity, false);
382
+ if (removed === "identity_mismatch")
383
+ recoveryFailures.push(`cleanup ownership changed for replacement entity '${item.relative}'`);
384
+ }
385
+ catch (cleanupError) {
386
+ recoveryFailures.push(`cleanup failed for replacement entity '${item.relative}': ${cleanupError.message}`);
387
+ }
388
+ }
389
+ if (predecessor) {
390
+ try {
391
+ options.publicationContext.restoreExact(predecessor.relative, predecessor.archivedIdentity, predecessor.bytes, entityExactGetMaxBytes(sourceRoot));
392
+ }
393
+ catch (restoreError) {
394
+ recoveryFailures.push(`predecessor restoration failed because ownership changed or publication was unsafe: ${restoreError.message}`);
395
+ }
396
+ }
397
+ if (markerIdentity) {
398
+ try {
399
+ const removed = options.publicationContext.removeExact(options.publicationContext.markerPath, markerIdentity, false);
400
+ if (removed === "identity_mismatch")
401
+ recoveryFailures.push("cleanup ownership changed for fresh state marker");
402
+ }
403
+ catch (cleanupError) {
404
+ recoveryFailures.push(`cleanup failed for fresh state marker: ${cleanupError.message}`);
405
+ }
406
+ }
407
+ if (recoveryFailures.length)
408
+ throw new Error(`plan replacement failed: ${error.message}; recovery failed: ${recoveryFailures.join("; ")}`, { cause: error });
409
+ throw error;
410
+ }
411
+ return envelope(command, { id: planId, path: entityPath(req.projectRoot, sourceRoot, PLAN, planId), replay: false }, planRecord, false, resultExtra);
412
+ }
413
+ function replacementEffects(predecessor, successor) {
414
+ return {
415
+ lifecycle: "targeted_replacement",
416
+ predecessor: {
417
+ id: predecessor.id,
418
+ transition: "archived",
419
+ preserved: ["task_records", "task_evaluations", "task_completion"],
420
+ },
421
+ successor: {
422
+ ...(successor ? { id: successor.id } : {}),
423
+ created: !successor,
424
+ lineage: { field: "previous_plan_archived", predecessor: predecessor.id },
425
+ },
426
+ };
427
+ }
428
+ function successorForPredecessor(entities, predecessor) {
429
+ const matches = entities.filter((entity) => entity.boundary === PLAN && entity.record?.previous_plan_archived === predecessor.id);
430
+ if (matches.length > 1) {
431
+ reject({
432
+ class: "conflict",
433
+ message: `archived predecessor '${predecessor.id}' has multiple canonical successor plans`,
434
+ recovery: "Repair canonical plan lineage so one archived predecessor has one successor before retrying targeted replacement.",
435
+ });
436
+ }
437
+ return matches[0];
438
+ }
439
+ function assertNoUnselectedOpenPlans(entities, selected, sourceRoot) {
440
+ const selectedIds = new Set(selected.map((entity) => entity.id));
441
+ const unselected = entities
442
+ .filter((entity) => entity.boundary === PLAN && planStatus(entity) === "open" && !selectedIds.has(entity.id))
443
+ .map((entity) => entity.id)
444
+ .sort();
445
+ if (unselected.length > 0) {
446
+ const conflict = multipleOpenPlanConflict(entities.filter((entity) => entity.boundary === PLAN && planStatus(entity) === "open"), sourceRoot);
447
+ reject({
448
+ class: "conflict",
449
+ message: `${conflict.message}; targeted plan replacement would leave ${unselected.length} unnamed open plan${unselected.length === 1 ? "" : "s"}`,
450
+ diagnosis: conflict.details,
451
+ recovery: conflict.recovery,
452
+ });
453
+ }
454
+ }
455
+ function existingReplacementDecision(entities, predecessor, successor, sourceRoot) {
456
+ if (predecessor.id === successor.id) {
457
+ reject({ class: "schema_violation", message: "targeted plan replacement requires distinct predecessor and successor IDs" });
458
+ }
459
+ const derived = successorForPredecessor(entities, predecessor);
460
+ if (planStatus(predecessor) === "archived") {
461
+ if (!derived || derived.id !== successor.id) {
462
+ reject({
463
+ class: "conflict",
464
+ message: `archived predecessor '${predecessor.id}' is already replaced by '${derived?.id ?? "no canonical successor"}', not '${successor.id}'`,
465
+ recovery: "Retry with the derived bare successor ID, or correct the divergent replacement request before any lifecycle mutation.",
466
+ });
467
+ }
468
+ return {
469
+ predecessor,
470
+ successor,
471
+ successorRecord: structuredClone(successor.record),
472
+ replay: true,
473
+ effects: replacementEffects(predecessor, successor),
474
+ };
475
+ }
476
+ if (!new Set(["open", "complete"]).has(planStatus(predecessor))) {
477
+ reject({ class: "conflict", message: `plan '${predecessor.id}' is ${planStatus(predecessor)} and cannot be a replacement predecessor` });
478
+ }
479
+ if (derived || successor.record?.previous_plan_archived !== undefined || successor.record?.replacement_input_sha256 !== undefined) {
480
+ reject({ class: "conflict", message: `successor '${successor.id}' already has canonical plan lineage and cannot be reassigned` });
481
+ }
482
+ if (planStatus(successor) !== "open") {
483
+ reject({ class: "conflict", message: `successor '${successor.id}' must be open for targeted replacement` });
484
+ }
485
+ assertNoUnselectedOpenPlans(entities, [predecessor, successor], sourceRoot);
486
+ const successorRecord = structuredClone(successor.record);
487
+ const inputSha256 = replacementSuccessorInputSha256(entities, successor);
488
+ successorRecord.previous_plan_archived = predecessor.id;
489
+ successorRecord.replacement_input_sha256 = inputSha256;
490
+ return {
491
+ predecessor,
492
+ successor,
493
+ archivedRecord: archivedPlanRecord(predecessor),
494
+ successorRecord,
495
+ inputSha256,
496
+ replay: false,
497
+ effects: replacementEffects(predecessor, successor),
498
+ };
499
+ }
500
+ function replacementPlanRecord(input) {
501
+ const record = structuredClone(input);
502
+ delete record.tasks;
503
+ delete record.previous_plan_archived;
504
+ delete record.replacement_input_sha256;
505
+ const header = mapping(record.header) ? record.header : {};
506
+ delete header.id;
507
+ if (header.status === "active")
508
+ header.status = "open";
509
+ if (header.status === "completed")
510
+ header.status = "complete";
511
+ record.header = header;
512
+ return record;
513
+ }
514
+ function uniqueReplacementTaskNames(tasks, context, failureClass) {
515
+ const names = new Map();
516
+ for (const task of tasks) {
517
+ const name = task.name;
518
+ if (typeof name !== "string" || name.length === 0) {
519
+ reject({ class: failureClass, message: `${context} contains a task without a non-empty name` });
520
+ }
521
+ if (names.has(name)) {
522
+ reject({ class: failureClass, message: `${context} contains duplicate task name '${name}', so replacement replay cannot identify a task` });
523
+ }
524
+ names.set(name, task);
525
+ }
526
+ return names;
527
+ }
528
+ function logicalReplacementTask(record, dependencies, resolveDependency) {
529
+ const logical = structuredClone(record);
530
+ for (const field of ["number", "plan", "status", "evaluation", "superseded_by", "superseded_reason"])
531
+ delete logical[field];
532
+ logical.depends_on = dependencies.map(resolveDependency);
533
+ if (!Array.isArray(logical.acceptance))
534
+ logical.acceptance = [];
535
+ return logical;
536
+ }
537
+ function replacementInputFingerprint(input) {
538
+ const tasks = Array.isArray(input.tasks) ? input.tasks.filter(mapping) : [];
539
+ const names = uniqueReplacementTaskNames(tasks, "replacement input", "schema_violation");
540
+ const byOrdinal = new Map(tasks.map((task, index) => [String(index + 1), String(task.name)]));
541
+ const logicalTasks = [...names.entries()].map(([name, task]) => {
542
+ const dependencies = Array.isArray(task.depends_on) ? task.depends_on : [];
543
+ const record = logicalReplacementTask(task, dependencies, (dependency) => {
544
+ const target = byOrdinal.get(String(dependency));
545
+ if (!target)
546
+ throw new Error(`replacement input dependency '${String(dependency)}' was not normalized before replay comparison`);
547
+ return target;
548
+ });
549
+ return [name, record];
550
+ });
551
+ return { plan: replacementPlanRecord(input), tasks: Object.fromEntries(logicalTasks.sort(([left], [right]) => left.localeCompare(right))) };
552
+ }
553
+ function replacementInputSha256(input) {
554
+ return createHash("sha256")
555
+ .update("agentera.planReplacementInput.v1\0")
556
+ .update(canonicalRecordJson(replacementInputFingerprint(input)))
557
+ .digest("hex");
558
+ }
559
+ function replacementSuccessorInputSha256(entities, successor) {
560
+ const tasks = entities.filter((entity) => entity.boundary === TASK && entity.record?.plan === successor.id);
561
+ const records = tasks.map((task) => structuredClone(task.record));
562
+ const names = uniqueReplacementTaskNames(records, `successor '${successor.id}'`, "conflict");
563
+ const namesById = new Map(tasks.map((task) => [task.id, String(task.record.name)]));
564
+ const logicalTasks = [...names.entries()].map(([name, task]) => {
565
+ const dependencies = Array.isArray(task.depends_on) ? task.depends_on : [];
566
+ const record = logicalReplacementTask(task, dependencies, (dependency) => {
567
+ const target = typeof dependency === "string" ? namesById.get(dependency) : undefined;
568
+ if (!target)
569
+ throw new Error(`successor '${successor.id}' has a task dependency outside its canonical task graph`);
570
+ return target;
571
+ });
572
+ return [name, record];
573
+ });
574
+ return createHash("sha256")
575
+ .update("agentera.planReplacementInput.v1\0")
576
+ .update(canonicalRecordJson({ plan: replacementPlanRecord(successor.record), tasks: Object.fromEntries(logicalTasks.sort(([left], [right]) => left.localeCompare(right))) }))
577
+ .digest("hex");
578
+ }
579
+ function assertReplacementInputReplay(input, successor) {
580
+ if (successor.record?.replacement_input_sha256 !== replacementInputSha256(input)) {
581
+ reject({
582
+ class: "conflict",
583
+ message: `replacement input diverges from immutable successor identity '${successor.id}'`,
584
+ recovery: "Retry the exact logical successor plan input, or start a new targeted replacement from an open predecessor; no state was changed.",
585
+ });
586
+ }
587
+ }
588
+ function createReplacementLifecycle(entities, predecessor, inputSha256, sourceRoot) {
589
+ const successor = successorForPredecessor(entities, predecessor);
590
+ if (planStatus(predecessor) === "archived") {
591
+ if (!successor) {
592
+ reject({
593
+ class: "conflict",
594
+ message: `archived predecessor '${predecessor.id}' has no canonical successor to replay`,
595
+ recovery: "Do not create a second successor for an archived predecessor. Select an open predecessor or repair canonical lineage first.",
596
+ });
597
+ }
598
+ return { replaySuccessor: successor };
599
+ }
600
+ if (!new Set(["open", "complete"]).has(planStatus(predecessor))) {
601
+ reject({ class: "conflict", message: `plan '${predecessor.id}' is ${planStatus(predecessor)} and cannot be a replacement predecessor` });
602
+ }
603
+ if (successor) {
604
+ reject({ class: "conflict", message: `predecessor '${predecessor.id}' already has successor '${successor.id}' before archival` });
605
+ }
606
+ assertNoUnselectedOpenPlans(entities, [predecessor], sourceRoot);
607
+ return {
608
+ lifecycle: {
609
+ predecessor,
610
+ archivedRecord: archivedPlanRecord(predecessor),
611
+ replacementInputSha256: inputSha256,
612
+ replay: false,
613
+ effects: replacementEffects(predecessor),
614
+ },
615
+ };
616
+ }
617
+ function publishExistingPlanReplacement(req, options, sourceRoot, decision) {
618
+ const command = "state plan replace";
619
+ if (decision.replay)
620
+ return envelope(command, { id: decision.successor.id, path: decision.successor.path, replay: true }, decision.successorRecord, req.dryRun, { effects: decision.effects });
621
+ if (req.dryRun)
622
+ return envelope(command, { id: decision.successor.id, path: decision.successor.path, replay: false }, decision.successorRecord, true, { effects: decision.effects });
623
+ if (!decision.inputSha256)
624
+ throw new Error(`successor '${decision.successor.id}' has no immutable replacement input identity`);
625
+ publishPlanReplacement(options.publicationContext, sourceRoot, { kind: "existing", predecessor: decision.predecessor.id, successor: decision.successor.id, inputSha256: decision.inputSha256 }, [
626
+ {
627
+ path: relative(req.projectRoot, decision.predecessor.path),
628
+ before: exactDiscoveredEntityBytes(decision.predecessor),
629
+ after: canonicalEntityEnvelopeBytes({ id: decision.predecessor.id, artifact: ARTIFACT, record: decision.archivedRecord, migrationProvenance: decision.predecessor.migrationProvenance ?? undefined }),
630
+ },
631
+ {
632
+ path: relative(req.projectRoot, decision.successor.path),
633
+ before: exactDiscoveredEntityBytes(decision.successor),
634
+ after: canonicalEntityEnvelopeBytes({ id: decision.successor.id, artifact: ARTIFACT, record: decision.successorRecord, migrationProvenance: decision.successor.migrationProvenance ?? undefined }),
635
+ },
636
+ ], {
637
+ validate: () => {
638
+ const validation = validateEntityState(options.publicationContext.pinnedPath(), sourceRoot, { kind: "project", projectRoot: options.publicationContext.validatedRoot });
639
+ if (!validation.valid)
640
+ throw new Error(`targeted plan replacement graph failed state validation: ${validation.issues.map(({ message }) => message).join("; ")}`);
641
+ },
642
+ });
643
+ return envelope(command, { id: decision.successor.id, path: decision.successor.path, replay: false }, decision.successorRecord, false, { effects: decision.effects });
644
+ }
645
+ export function replacePlanEntities(req, options = {}) {
646
+ if (!options.publicationContext) {
647
+ const binding = detectStateModeBinding(req.projectRoot, options.sourceRoot);
648
+ if (binding.mode !== "entities")
649
+ throw new Error("plan entity replacement requires the durable entity-mode marker");
650
+ try {
651
+ return replacePlanEntities(req, { ...options, publicationContext: binding.publicationContext });
652
+ }
653
+ finally {
654
+ binding.publicationContext.close();
655
+ }
656
+ }
657
+ return withEntityWriterLock(options.publicationContext, () => replacePlanEntitiesUnderLock(req, options));
658
+ }
659
+ function replacePlanEntitiesUnderLock(req, options) {
660
+ const command = "state plan replace";
661
+ const predecessorId = req.values.predecessor;
662
+ const successorId = req.values.successor;
663
+ if (typeof predecessorId !== "string")
664
+ reject({ class: "missing_argument", message: "--predecessor is required for plan replace" });
665
+ if (successorId !== undefined && typeof successorId !== "string")
666
+ reject({ class: "schema_violation", message: "--successor must be a bare plan ID when present" });
667
+ if (successorId !== undefined && req.input !== null)
668
+ reject({ class: "mutually_exclusive", message: "plan replace accepts either --successor or --input, not both" });
669
+ if (successorId === undefined && req.input === null)
670
+ reject({ class: "missing_argument", message: "plan replace requires either --successor ID or --input PLAN.yaml" });
671
+ const sourceRoot = options.sourceRoot ?? resolveSourceRoot();
672
+ const input = successorId === undefined ? preparedPlanCreateInput(req) : undefined;
673
+ const inputSha256 = input ? replacementInputSha256(input) : undefined;
674
+ recoverPendingPlanReplacement(options.publicationContext, sourceRoot, typeof successorId === "string"
675
+ ? { predecessor: predecessorId, successor: successorId }
676
+ : { predecessor: predecessorId, inputSha256 }, {
677
+ validate: () => {
678
+ const validation = validateEntityState(options.publicationContext.pinnedPath(), sourceRoot, { kind: "project", projectRoot: options.publicationContext.validatedRoot });
679
+ if (!validation.valid)
680
+ throw new Error(`targeted plan replacement graph failed state validation: ${validation.issues.map(({ message }) => message).join("; ")}`);
681
+ },
682
+ });
683
+ const discovery = validateEntityState(options.publicationContext.pinnedPath(), sourceRoot, { kind: "project", projectRoot: options.publicationContext.validatedRoot });
684
+ const entities = all(options.publicationContext.pinnedPath(), sourceRoot, discovery);
685
+ const predecessor = selectedPlan(entities, predecessorId, sourceRoot);
686
+ if (typeof successorId === "string") {
687
+ const successor = selectedPlan(entities, successorId, sourceRoot);
688
+ return publishExistingPlanReplacement(req, options, sourceRoot, existingReplacementDecision(entities, predecessor, successor, sourceRoot));
689
+ }
690
+ const lifecycle = createReplacementLifecycle(entities, predecessor, inputSha256, sourceRoot);
691
+ if (lifecycle.replaySuccessor) {
692
+ assertReplacementInputReplay(input, lifecycle.replaySuccessor);
693
+ return envelope(command, { id: lifecycle.replaySuccessor.id, path: lifecycle.replaySuccessor.path, replay: true }, lifecycle.replaySuccessor.record, req.dryRun, { effects: replacementEffects(predecessor) });
694
+ }
695
+ return createPlanEntitiesUnderLock(req, { ...options, lifecycle: lifecycle.lifecycle, command });
696
+ }
697
+ function taskRecord(req, plan) {
698
+ const input = req.input ?? {};
699
+ const record = { plan, name: String(input.name), status: "pending", depends_on: structuredClone(input.depends_on), acceptance: structuredClone(input.acceptance) };
700
+ for (const field of ["evidence", "blocked_reason"])
701
+ if (input[field] !== undefined)
702
+ record[field] = structuredClone(input[field]);
703
+ return record;
704
+ }
705
+ function logicalTaskContent(record) {
706
+ const content = {
707
+ name: record.name,
708
+ depends_on: Array.isArray(record.depends_on) ? structuredClone(record.depends_on) : [],
709
+ acceptance: Array.isArray(record.acceptance) ? structuredClone(record.acceptance) : [],
710
+ };
711
+ for (const field of ["evidence", "blocked_reason"])
712
+ if (record[field] !== undefined)
713
+ content[field] = structuredClone(record[field]);
714
+ return content;
715
+ }
716
+ function appendReplayOrConflict(entities, planId, record) {
717
+ const logical = canonicalRecordJson(logicalTaskContent(record));
718
+ const tasks = entities.filter((entity) => entity.boundary === TASK && entity.record?.plan === planId);
719
+ const sameName = tasks.filter((task) => task.record?.name === record.name);
720
+ if (sameName.length === 0)
721
+ return null;
722
+ const identical = sameName.filter((task) => canonicalRecordJson(logicalTaskContent(task.record)) === logical);
723
+ if (identical.length === 1 && identical.length === sameName.length)
724
+ return identical[0];
725
+ if (identical.length > 1)
726
+ reject({ class: "conflict", message: `plan '${planId}' contains multiple identical tasks named '${String(record.name)}'; retry cannot choose one existing task` });
727
+ reject({ class: "conflict", message: `plan task '${String(record.name)}' already exists with different fields; use 'state plan update --id ID --input task-patch.yaml' to modify it` });
728
+ }
729
+ function assertDependencies(root, sourceRoot, record, taskId) {
730
+ const entities = all(root, sourceRoot);
731
+ const dependencies = Array.isArray(record.depends_on) ? record.depends_on : [];
732
+ for (const dependency of dependencies) {
733
+ if (typeof dependency !== "string" || !ID.test(dependency))
734
+ reject({ class: "schema_violation", message: `task dependency '${String(dependency)}' must be a bare task ID` });
735
+ const target = taskFor(entities, dependency);
736
+ if (target.record?.plan !== record.plan)
737
+ reject({ class: "schema_violation", message: `task dependency '${dependency}' belongs to a different plan` });
738
+ if (dependency === taskId)
739
+ reject({ class: "schema_violation", message: "a task cannot depend on itself" });
740
+ }
741
+ }
742
+ function hasSupersededPredecessor(entities, planId, taskId) {
743
+ return entities.some((entity) => entity.boundary === TASK
744
+ && entity.record?.plan === planId
745
+ && entity.record?.status === "superseded"
746
+ && Array.isArray(entity.record.superseded_by)
747
+ && entity.record.superseded_by.includes(taskId));
748
+ }
749
+ function isCompletePassingReplacement(entity) {
750
+ const candidate = entity?.record?.evaluation;
751
+ const evaluation = mapping(candidate) ? candidate : undefined;
752
+ return entity?.record?.status === "complete" && evaluation?.last_verdict === "pass";
753
+ }
754
+ function assertProjectedTask(entities, id, record) {
755
+ const violations = planTaskRecordViolations(record, `plan task '${id}'`);
756
+ if (violations.length)
757
+ reject({ class: "schema_violation", message: `plan task '${id}' would violate the task schema`, violations });
758
+ const planId = String(record.plan);
759
+ const records = new Map(entities.filter((entity) => entity.boundary === TASK && entity.record?.plan === planId && entity.id).map((entity) => [entity.id, entity.id === id ? record : entity.record]));
760
+ if (records.has(id) === false)
761
+ records.set(id, record);
762
+ const visiting = new Set();
763
+ const visited = new Set();
764
+ const visit = (current) => {
765
+ if (visiting.has(current))
766
+ return true;
767
+ if (visited.has(current))
768
+ return false;
769
+ visiting.add(current);
770
+ const value = records.get(current);
771
+ const cyclic = (Array.isArray(value?.depends_on) ? value.depends_on : []).some((dependency) => typeof dependency === "string" && records.has(dependency) && visit(dependency));
772
+ visiting.delete(current);
773
+ visited.add(current);
774
+ return cyclic;
775
+ };
776
+ if ([...records.keys()].some(visit))
777
+ reject({ class: "schema_violation", message: `task '${id}' would create a dependency cycle in plan '${planId}'` });
778
+ if (record.status !== "complete" && hasSupersededPredecessor(entities, planId, id))
779
+ reject({ class: "conflict", message: `task '${id}' must remain complete while it is referenced by a superseded task` });
780
+ const plan = entities.find((entity) => entity.boundary === PLAN && entity.id === planId);
781
+ if (plan && planStatus(plan) === "complete" && !["complete", "superseded"].includes(String(record.status)))
782
+ reject({ class: "conflict", message: `task '${id}' cannot become incomplete while plan '${planId}' is complete` });
783
+ }
784
+ function supersedeTask(entities, task, taskId, planId, values) {
785
+ const reason = String(values.superseded_reason ?? "").trim();
786
+ const replacements = Array.isArray(values.superseded_by) ? values.superseded_by.map(String) : [];
787
+ if (!replacements.length)
788
+ reject({ class: "schema_violation", message: "supersede requires at least one --by replacement task ID" });
789
+ if (new Set(replacements).size !== replacements.length)
790
+ reject({ class: "schema_violation", message: "supersede replacement task IDs must be distinct" });
791
+ if (!reason || reason.length > 500)
792
+ reject({ class: "schema_violation", message: "supersede --reason must be a non-empty explanation of at most 500 characters" });
793
+ const normalized = [...replacements].sort();
794
+ if (task.record?.status === "superseded") {
795
+ const existing = Array.isArray(task.record.superseded_by) ? task.record.superseded_by : [];
796
+ if (canonicalRecordJson(existing) === canonicalRecordJson(normalized) && task.record.superseded_reason === reason)
797
+ return structuredClone(task.record);
798
+ reject({ class: "conflict", message: `task '${taskId}' is already superseded with different replacements or reason` });
799
+ }
800
+ if (task.record?.status !== "blocked")
801
+ reject({ class: "conflict", message: `only a currently blocked task can be superseded; task '${taskId}' is ${String(task.record?.status)}` });
802
+ for (const replacementId of normalized) {
803
+ if (!ID.test(replacementId))
804
+ reject({ class: "schema_violation", message: `supersede replacement task ID '${replacementId}' must be ten lowercase letters` });
805
+ if (replacementId === taskId)
806
+ reject({ class: "schema_violation", message: "a task cannot supersede itself" });
807
+ const replacement = taskFor(entities, replacementId, planId);
808
+ if (!isCompletePassingReplacement(replacement)) {
809
+ const historicallyReferenced = hasSupersededPredecessor(entities, planId, replacementId);
810
+ const hasEvaluation = mapping(replacement.record?.evaluation);
811
+ reject({
812
+ class: "conflict",
813
+ message: `supersede replacement task '${replacementId}' must be complete with latest persisted PASS evidence`,
814
+ recovery: historicallyReferenced
815
+ ? hasEvaluation
816
+ ? `Replacement task '${replacementId}' already has non-PASS evaluation state, so historical first-PASS recovery is unavailable; use another complete latest-PASS replacement, or keep the plan open or archive it without claiming completion as applicable.`
817
+ : `Record the allowed first PASS for historical replacement task '${replacementId}' while it remains complete, then retry supersession; no state was changed.`
818
+ : `Reopen replacement task '${replacementId}', record PASS, complete it, then retry supersession; no state was changed.`,
819
+ });
820
+ }
821
+ }
822
+ const record = structuredClone(task.record);
823
+ record.status = "superseded";
824
+ record.superseded_by = normalized;
825
+ record.superseded_reason = reason;
826
+ return record;
827
+ }
828
+ export function mutatePlanEntities(req, options = {}) {
829
+ if (req.spec.verb === "create")
830
+ return createPlanEntities(req, options);
831
+ if (req.spec.verb === "replace")
832
+ return replacePlanEntities(req, options);
833
+ const sourceRoot = options.sourceRoot ?? resolveSourceRoot();
834
+ const entities = all(req.projectRoot, sourceRoot);
835
+ if (req.spec.verb === "set-plan-status" && req.values.id !== undefined)
836
+ reject({ class: "invalid_request", message: "plan set-plan-status accepts only the --plan selector; --id is a task selector and is not valid for plan lifecycle" });
837
+ if (req.spec.verb === "archive") {
838
+ const lifecycle = planLifecycleDecision(entities, { verb: "archive", force: req.force, ...(typeof req.values.plan === "string" ? { plan: req.values.plan } : {}) }, sourceRoot);
839
+ const plan = lifecycle.target;
840
+ const record = lifecycle.archivedRecord;
841
+ if (lifecycle.replay)
842
+ return envelope("state plan archive", { id: plan.id, path: plan.path, replay: true }, record, req.dryRun, { effects: lifecycle.effects });
843
+ if (req.dryRun)
844
+ return envelope("state plan archive", { id: plan.id, path: plan.path, replay: false }, record, true, { effects: lifecycle.effects });
845
+ const result = replaceEntity({ projectRoot: req.projectRoot, sourceRoot, publicationContext: options.publicationContext, artifact: ARTIFACT, boundary: PLAN, id: plan.id, expectedRecord: plan.record, expectedBytes: exactDiscoveredEntityBytes(plan), migrationProvenance: plan.migrationProvenance, record });
846
+ return envelope("state plan archive", result, record, false, { effects: lifecycle.effects });
847
+ }
848
+ const plan = selectedPlan(entities, typeof req.values.plan === "string" ? req.values.plan : undefined, sourceRoot);
849
+ if (req.spec.verb === "append") {
850
+ if (!OPEN.has(planStatus(plan)))
851
+ reject({ class: "conflict", message: `plan '${plan.id}' is ${planStatus(plan)} and cannot accept a new task` });
852
+ const record = taskRecord(req, plan.id);
853
+ assertDependencies(req.projectRoot, sourceRoot, record);
854
+ const replay = appendReplayOrConflict(entities, plan.id, record);
855
+ if (replay)
856
+ return envelope("state plan append", { id: replay.id, path: replay.path, replay: true }, replay.record, req.dryRun);
857
+ const id = allocateEntityId(options.publicationContext?.pinnedPath() ?? req.projectRoot, options.candidate, sourceRoot);
858
+ assertProjectedTask(entities, id, record);
859
+ if (req.dryRun)
860
+ return envelope("state plan append", { id, path: entityPath(req.projectRoot, sourceRoot, TASK, id), replay: false }, record, true);
861
+ const result = publishEntity({ projectRoot: req.projectRoot, sourceRoot, publicationContext: options.publicationContext, artifact: ARTIFACT, boundary: TASK, id, record });
862
+ return envelope("state plan append", result, record, false);
863
+ }
864
+ if (req.spec.verb === "set-plan-status") {
865
+ const tasks = entities.filter((entity) => entity.boundary === TASK && entity.record?.plan === plan.id);
866
+ const requested = String(req.values.status);
867
+ if (planStatus(plan) === "archived")
868
+ reject({ class: "conflict", message: `archived plan '${plan.id}' is immutable` });
869
+ const record = structuredClone(plan.record);
870
+ const header = mapping(record.header) ? record.header : {};
871
+ header.status = requested;
872
+ record.header = header;
873
+ const command = "state plan set-plan-status";
874
+ if (canonicalRecordJson(record) === canonicalRecordJson(plan.record))
875
+ return envelope(command, { id: plan.id, path: plan.path, replay: true }, record, req.dryRun);
876
+ if (requested === "complete" && tasks.some((task) => !["complete", "superseded"].includes(String(task.record?.status))))
877
+ reject({ class: "conflict", message: "plan cannot be completed while incomplete tasks remain" });
878
+ if (requested === "complete") {
879
+ for (const task of tasks.filter((candidate) => candidate.record?.status === "superseded")) {
880
+ for (const replacementId of Array.isArray(task.record?.superseded_by) ? task.record.superseded_by : []) {
881
+ if (typeof replacementId !== "string")
882
+ continue;
883
+ const replacement = tasks.find((candidate) => candidate.id === replacementId);
884
+ if (!isCompletePassingReplacement(replacement))
885
+ reject({
886
+ class: "conflict",
887
+ message: `plan '${plan.id}' cannot be completed because replacement task '${replacementId}' lacks complete latest persisted PASS evidence`,
888
+ recovery: mapping(replacement?.record?.evaluation)
889
+ ? `Replacement task '${replacementId}' cannot use historical first-PASS recovery because it already has evaluation state; keep the plan open or archive it without claiming completion.`
890
+ : `Record the allowed first PASS for replacement task '${replacementId}' with agentera state plan record-evaluation --id ${replacementId}, then retry plan completion; no state was changed.`,
891
+ });
892
+ }
893
+ }
894
+ }
895
+ if (req.dryRun)
896
+ return envelope(command, { id: plan.id, path: plan.path, replay: false }, record, true);
897
+ const result = replaceEntity({ projectRoot: req.projectRoot, sourceRoot, publicationContext: options.publicationContext, artifact: ARTIFACT, boundary: PLAN, id: plan.id, expectedRecord: plan.record, expectedBytes: exactDiscoveredEntityBytes(plan), migrationProvenance: plan.migrationProvenance, record });
898
+ return envelope(command, result, record, false);
899
+ }
900
+ if (planStatus(plan) === "archived")
901
+ reject({ class: "conflict", message: `archived plan '${plan.id}' is immutable` });
902
+ const taskId = String(req.values.id ?? "");
903
+ const task = taskFor(entities, taskId, plan.id);
904
+ const record = structuredClone(task.record);
905
+ if (req.spec.verb === "supersede") {
906
+ const superseded = supersedeTask(entities, task, taskId, plan.id, req.values);
907
+ if (canonicalRecordJson(superseded) === canonicalRecordJson(task.record))
908
+ return envelope("state plan supersede", { id: taskId, path: task.path, replay: true }, superseded, req.dryRun);
909
+ if (req.dryRun)
910
+ return envelope("state plan supersede", { id: taskId, path: task.path, replay: false }, superseded, true);
911
+ const result = replaceEntity({ projectRoot: req.projectRoot, sourceRoot, publicationContext: options.publicationContext, artifact: ARTIFACT, boundary: TASK, id: taskId, expectedRecord: task.record, expectedBytes: exactDiscoveredEntityBytes(task), migrationProvenance: task.migrationProvenance, record: superseded });
912
+ return envelope("state plan supersede", result, superseded, false);
913
+ }
914
+ if (req.spec.verb === "update") {
915
+ const input = req.input ?? {};
916
+ const taskFields = ["name", "depends_on", "acceptance", "evidence", "blocked_reason"];
917
+ if (input.surprise !== undefined) {
918
+ if (taskFields.some((field) => input[field] !== undefined))
919
+ reject({ class: "conflict", message: "entity mode cannot combine a plan-level surprise with task-field changes in one command; publish them as separate updates" });
920
+ const planRecord = structuredClone(plan.record);
921
+ const current = String(planRecord.surprises ?? "").trim();
922
+ const surprise = String(input.surprise);
923
+ if (!current.split("\n").includes(surprise))
924
+ planRecord.surprises = current ? `${current}\n${surprise}` : surprise;
925
+ if (canonicalRecordJson(planRecord) === canonicalRecordJson(plan.record))
926
+ return envelope("state plan update", { id: plan.id, path: plan.path, replay: true }, planRecord, req.dryRun);
927
+ if (req.dryRun)
928
+ return envelope("state plan update", { id: plan.id, path: plan.path, replay: false }, planRecord, true);
929
+ const result = replaceEntity({ projectRoot: req.projectRoot, sourceRoot, publicationContext: options.publicationContext, artifact: ARTIFACT, boundary: PLAN, id: plan.id, expectedRecord: plan.record, expectedBytes: exactDiscoveredEntityBytes(plan), migrationProvenance: plan.migrationProvenance, record: planRecord });
930
+ return envelope("state plan update", result, planRecord, false);
931
+ }
932
+ for (const field of taskFields)
933
+ if (Object.prototype.hasOwnProperty.call(input, field)) {
934
+ const value = input[field];
935
+ if (value === null) {
936
+ if (field === "depends_on" || field === "acceptance")
937
+ record[field] = [];
938
+ else
939
+ delete record[field];
940
+ }
941
+ else
942
+ record[field] = structuredClone(value);
943
+ }
944
+ assertDependencies(req.projectRoot, sourceRoot, record, taskId);
945
+ }
946
+ else if (req.spec.verb === "set-status")
947
+ record.status = String(req.values.status);
948
+ else if (req.spec.verb === "record-evaluation") {
949
+ const completedReplacementRecovery = OPEN.has(planStatus(plan)) && hasSupersededPredecessor(entities, plan.id, taskId);
950
+ const mutation = mutatePlanTaskEvaluation(record, req.values.evaluation, `plan task '${taskId}'`, completedReplacementRecovery);
951
+ if (mutation.replay)
952
+ return envelope("state plan record-evaluation", { id: taskId, path: task.path, replay: true }, record, req.dryRun);
953
+ }
954
+ assertProjectedTask(entities, taskId, record);
955
+ if (canonicalRecordJson(record) === canonicalRecordJson(task.record))
956
+ return envelope(`state plan ${req.spec.verb}`, { id: taskId, path: task.path, replay: true }, record, req.dryRun);
957
+ if (req.dryRun)
958
+ return envelope(`state plan ${req.spec.verb}`, { id: taskId, path: task.path, replay: false }, record, true);
959
+ const result = replaceEntity({ projectRoot: req.projectRoot, sourceRoot, publicationContext: options.publicationContext, artifact: ARTIFACT, boundary: TASK, id: taskId, expectedRecord: task.record, expectedBytes: exactDiscoveredEntityBytes(task), migrationProvenance: task.migrationProvenance, record });
960
+ return envelope(`state plan ${req.spec.verb}`, result, record, false);
961
+ }
962
+ function snapshot(root, entities) { return createHash("sha256").update(canonicalRecordJson(entities.map(({ id, boundary, record, path: file }) => ({ id, boundary, record, path: relative(root, file) })).sort((a, b) => canonicalRecordJson(a).localeCompare(canonicalRecordJson(b))))).digest("hex"); }
963
+ function secret(root, authorityPath) { return createHash("sha256").update(path.resolve(root)).update("\0").update(fs.readFileSync(authorityPath)).digest(); }
964
+ function encode(value, root, authorityPath) { const bytes = Buffer.from(canonicalRecordJson(value)); return `${bytes.toString("base64url")}.${createHmac("sha256", secret(root, authorityPath)).update(bytes).digest("base64url")}`; }
965
+ function decode(token, root, authorityPath) { try {
966
+ const [body, signature, extra] = token.split(".");
967
+ if (!body || !signature || extra)
968
+ throw new Error();
969
+ const bytes = Buffer.from(body, "base64url");
970
+ const supplied = Buffer.from(signature, "base64url");
971
+ const expected = createHmac("sha256", secret(root, authorityPath)).update(bytes).digest();
972
+ if (supplied.length !== expected.length || !timingSafeEqual(supplied, expected))
973
+ throw new Error();
974
+ const value = JSON.parse(bytes.toString());
975
+ if (!mapping(value))
976
+ throw new Error();
977
+ return value;
978
+ }
979
+ catch {
980
+ throw failure("cursor_invalid", "plan cursor is malformed or belongs to another project", "Copy next_cursor exactly, or omit --cursor to restart.");
981
+ } }
982
+ function entry(root, entity) { return { id: entity.id, artifact: ARTIFACT, record: entity.record, provenance: { storage: "canonical_entity_file", path: relative(root, entity.path) } }; }
983
+ function boundedList(root, sourceRoot, selected, allEntities, limit, cursor, order, command, filter, format = "json", envelope = {}, decodedCursor, selectorInput) {
984
+ const declared = contract(sourceRoot);
985
+ const take = limit ?? declared.defaultLimit;
986
+ if (!Number.isSafeInteger(take) || take < 1 || take > declared.maximumLimit)
987
+ throw failure("invalid_request", `plan list limit must be 1..${declared.maximumLimit}`, "Use a limit in the declared range.");
988
+ const projectionOptions = { family: (command.includes("tasks") ? "plan_tasks" : "plans"), artifact: ARTIFACT, boundary: command.includes("tasks") ? TASK : PLAN, format, maxUtf8Bytes: declared.maxUtf8Bytes, selector: selectorInput };
989
+ const selector = resolveEntityListSelector(selectorInput, selected.map((entity) => entry(root, entity)), projectionOptions);
990
+ const selectorKey = entityListSelectorKey(selector);
991
+ const snap = snapshot(root, allEntities);
992
+ let start = 0;
993
+ if (cursor) {
994
+ const value = decodedCursor ?? decode(cursor, root, declared.authorityPath);
995
+ if (value.selector !== selectorKey)
996
+ throw failure("cursor_invalid", "plan cursor selectors do not match this request", "Repeat the original selector, or omit --cursor to restart from current state.");
997
+ if (value.snapshot_id !== snap || value.order !== order || canonicalRecordJson(value.filter) !== canonicalRecordJson(filter))
998
+ throw failure("cursor_snapshot_unavailable", "plan state or filters changed after this cursor snapshot", "Repeat the original filters, or omit --cursor to restart from current state.");
999
+ const found = selected.findIndex((entity) => entity.id === value.after);
1000
+ if (found < 0)
1001
+ throw failure("cursor_snapshot_unavailable", "plan cursor continuation is unavailable", "Omit --cursor to restart.");
1002
+ start = found + 1;
1003
+ }
1004
+ const page = selected.slice(start, start + take);
1005
+ const remaining = selected.length - start - page.length;
1006
+ const next = remaining && page.length ? encode({ snapshot_id: snap, order, filter, selector: selectorKey, after: page.at(-1).id }, root, declared.authorityPath) : undefined;
1007
+ const familyIdentifier = command.includes("tasks") && typeof filter.plan === "string" ? ` ${shellQuoteArgument(filter.plan)}` : "";
1008
+ const filterFlags = filter.status ? ` --status ${shellQuoteArgument(Array.isArray(filter.status) ? filter.status.join(",") : filter.status)}` : "";
1009
+ const selectorFlags = entityListSelectorFlags(selector);
1010
+ const response = { schemaVersion: "agentera.stateList.v1", command, status: remaining ? "degraded" : "ok", entries: page.map((entity) => entry(root, entity)), counts: { total: selected.length, returned: page.length, remaining }, order, filters: filter, snapshot: { id: snap, first_page: !cursor, has_more: Boolean(remaining), candidate_count: selected.length }, source: { artifact: ARTIFACT, authority: "canonical_entity_files", root: declared.entityRoot }, retrieval: { ...(next ? { continue: `${command.replace("state ", "agentera state ")}${familyIdentifier}${filterFlags}${selectorFlags} --limit ${take} --cursor ${next} --format json` } : {}) }, ...(remaining ? { omitted: true, omitted_count: remaining, omission_reason: "page_limit", next_cursor: next } : {}), ...envelope };
1011
+ return projectEntityList(response, selector, projectionOptions);
1012
+ }
1013
+ export function getPlanEntity(root, id, sourceRoot = resolveSourceRoot()) { const entities = all(root, sourceRoot); const plan = selectedPlan(entities, id, sourceRoot); return { schemaVersion: "agentera.stateGet.v1", command: "state plan get", status: "ok", entry: entry(root, plan), tasks: entities.filter((entity) => entity.boundary === TASK && entity.record?.plan === id).sort((a, b) => a.id.localeCompare(b.id)).map((entity) => entry(root, entity)), source_contract: { authority: "references/artifacts/state-storage-authority.yaml", detail: "full_entities" } }; }
1014
+ export function listPlanEntities(root, limit, cursor, options = {}) { const sourceRoot = options.sourceRoot ?? resolveSourceRoot(); const entities = all(root, sourceRoot, options.discovery); const statuses = options.statuses?.length ? new Set(options.statuses) : undefined; const plans = entities.filter((entity) => entity.boundary === PLAN && (!statuses || statuses.has(planStatus(entity)))).sort((a, b) => String(mapping(b.record?.header) ? b.record.header.created ?? "" : "").localeCompare(String(mapping(a.record?.header) ? a.record.header.created ?? "" : "")) || a.id.localeCompare(b.id)); return boundedList(root, sourceRoot, plans, entities, limit, cursor, ORDER, "state plan list", options.statuses ? { status: options.statuses } : {}, options.format, {}, undefined, options.selector); }
1015
+ export function getPlanTaskEntity(root, id, planId, sourceRoot = resolveSourceRoot()) { const entities = all(root, sourceRoot); const task = taskFor(entities, id, planId); return { schemaVersion: "agentera.stateGet.v1", command: "state plan tasks get", status: "ok", entry: entry(root, task), source_contract: { authority: "references/artifacts/state-storage-authority.yaml", detail: "full_entity" } }; }
1016
+ export function listPlanTaskEntities(root, planId, limit, cursor, options = {}) { const sourceRoot = options.sourceRoot ?? resolveSourceRoot(); const entities = all(root, sourceRoot, options.discovery); const declared = contract(sourceRoot); const decodedCursor = cursor ? decode(cursor, root, declared.authorityPath) : undefined; const cursorFilter = mapping(decodedCursor?.filter) ? decodedCursor.filter : undefined; const cursorPlan = typeof cursorFilter?.plan === "string" && ID.test(cursorFilter.plan) ? cursorFilter.plan : undefined; if (decodedCursor && !cursorPlan)
1017
+ throw failure("cursor_snapshot_unavailable", "plan state changed after this cursor snapshot", "Omit --cursor to restart from current state."); const plan = selectedPlan(entities, planId ?? cursorPlan, sourceRoot); const tasks = entities.filter((entity) => entity.boundary === TASK && entity.record?.plan === plan.id).sort((a, b) => a.id.localeCompare(b.id)); return boundedList(root, sourceRoot, tasks, entities, limit, cursor, TASK_ORDER, "state plan tasks list", { plan: plan.id }, options.format, {}, decodedCursor, options.selector); }
1018
+ export function currentPlanEntityView(root, limit, cursor, status, options = {}) {
1019
+ const sourceRoot = options.sourceRoot ?? resolveSourceRoot();
1020
+ const entities = all(root, sourceRoot);
1021
+ const plan = selectedPlan(entities, undefined, sourceRoot);
1022
+ let tasks = entities.filter((entity) => entity.boundary === TASK && entity.record?.plan === plan.id);
1023
+ if (status)
1024
+ tasks = tasks.filter((entity) => entity.record?.status === status);
1025
+ tasks.sort((a, b) => a.id.localeCompare(b.id));
1026
+ return boundedList(root, sourceRoot, tasks, entities, limit, cursor, TASK_ORDER, "state plan", { plan: plan.id, status: status ?? null }, options.format, { plan: entry(root, plan) });
1027
+ }