@cassiomc1/forgeloop 1.13.0 → 2.0.0-rc.2

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 (395) hide show
  1. package/AGENT_COMPATIBILITY.md +8 -0
  2. package/CONTRIBUTING.md +11 -7
  3. package/DOCS_INDEX.md +37 -4
  4. package/ENG/c-development-eng.md +2 -2
  5. package/ENG/cpp-development-eng.md +2 -2
  6. package/ENG/dotnet-aspnetcore-development-eng.md +7 -1
  7. package/ENG/flutter-development-eng.md +4 -2
  8. package/ENG/go-development-eng.md +2 -2
  9. package/ENG/java-development-eng.md +3 -3
  10. package/ENG/nodejs-backend-development-eng.md +10 -6
  11. package/ENG/php-development-eng.md +3 -3
  12. package/ENG/python-development-eng.md +205 -0
  13. package/ENG/rust-development-eng.md +42 -1
  14. package/ENG/sec-code-eng.md +7 -7
  15. package/ENG/sql-development-eng.md +4 -4
  16. package/ENG/swift-development-eng.md +5 -4
  17. package/ENG/test-code-eng.md +1 -1
  18. package/ENG/typescript-development-eng.md +4 -4
  19. package/EXECUTION_STATE.md +12 -0
  20. package/GUIDE_ROUTER.md +6 -0
  21. package/LICENSE +133 -21
  22. package/LOOP_ENGINEERING.md +28 -2
  23. package/LOOP_SYSTEM_DESIGN.md +10 -10
  24. package/ORCHESTRATOR_INTEGRATION.md +9 -5
  25. package/PROTOCOL_INTEGRATION.md +55 -2
  26. package/README.md +63 -59
  27. package/TERMINOLOGY.md +2 -0
  28. package/THIRD_PARTY_NOTICES.md +3 -4
  29. package/THREAT_MODEL.md +140 -1
  30. package/completions/_forgeloop +29 -3
  31. package/completions/forgeloop.bash +55 -3
  32. package/completions/forgeloop.fish +183 -1
  33. package/docs/ADVISORY_CONTEXT.md +25 -0
  34. package/docs/AGENT_BROWSER_ADAPTER.md +81 -0
  35. package/docs/AGENT_BROWSER_VERIFICATION.md +6 -0
  36. package/docs/AGENT_PROTOCOL_SUMMARY.md +74 -39
  37. package/docs/AGENT_SKILL.md +66 -0
  38. package/docs/ARTIFACT_REFERENCE.md +171 -35
  39. package/docs/AUDIT_UX.md +46 -0
  40. package/docs/BROWSER_VERIFICATION.md +136 -0
  41. package/docs/CLI_REFERENCE.md +512 -8
  42. package/docs/CODE_ATTESTATION.md +2 -2
  43. package/docs/DOCUMENTATION_GUIDE.md +34 -11
  44. package/docs/GETTING_STARTED.md +3 -3
  45. package/docs/JEV_BENCHMARKS.md +31 -0
  46. package/docs/MODEL_ROUTING.md +37 -0
  47. package/docs/OPENSRC_ADAPTER.md +241 -0
  48. package/docs/PACKAGE_CONTENTS.md +46 -18
  49. package/docs/PROVIDERS.md +126 -0
  50. package/docs/PROVIDER_ARCHITECTURE.md +199 -0
  51. package/docs/RECIPES.md +9 -0
  52. package/docs/RELEASE_CHECKLIST.md +116 -12
  53. package/docs/SECURITY_REVIEW.md +71 -0
  54. package/docs/SELF_HOSTED_TESTS.md +121 -0
  55. package/docs/SEMANTIC_DECISION_PLANE.md +71 -0
  56. package/docs/TEST_INTELLIGENCE.md +29 -0
  57. package/docs/TEST_PRUNING.md +14 -0
  58. package/docs/TROUBLESHOOTING.md +198 -1
  59. package/docs/UNIVERSAL_INTEGRATION.md +31 -0
  60. package/docs/assets/diagrams/forgeloop-code-attestation-flow.html +2 -2
  61. package/docs/assets/diagrams/forgeloop-code-attestation-flow.receipt.json +5 -5
  62. package/docs/assets/diagrams/forgeloop-code-attestation-flow.svg +1 -1
  63. package/docs/assets/diagrams/forgeloop-engineering-flow.html +39 -26
  64. package/docs/assets/diagrams/forgeloop-engineering-flow.receipt.json +6 -6
  65. package/docs/assets/diagrams/forgeloop-engineering-flow.svg +26 -26
  66. package/docs/assets/diagrams/forgeloop-verification-trust-flow.html +2 -1
  67. package/docs/assets/diagrams/forgeloop-verification-trust-flow.receipt.json +5 -5
  68. package/docs/assets/diagrams/forgeloop-verification-trust-flow.svg +1 -1
  69. package/docs/diagrams/README.md +13 -9
  70. package/docs/diagrams/forgeloop-code-attestation-flow.workflow.json +1 -1
  71. package/docs/diagrams/forgeloop-engineering-flow.workflow.json +24 -19
  72. package/docs/diagrams/forgeloop-verification-trust-flow.workflow.json +1 -0
  73. package/docs/diagrams/reviews/forgeloop-code-attestation-flow.review.json +4 -4
  74. package/docs/diagrams/reviews/forgeloop-engineering-flow.review.json +4 -4
  75. package/docs/diagrams/reviews/forgeloop-verification-trust-flow.review.json +4 -4
  76. package/docs/documentation-manifest.json +774 -16
  77. package/docs/protocol-requirements.json +24 -0
  78. package/package.json +43 -11
  79. package/schemas/config.schema.json +14 -0
  80. package/schemas/context-plan.schema.json +18 -0
  81. package/schemas/semantic-decision.schema.json +46 -0
  82. package/schemas/task-bundle.schema.json +7 -2
  83. package/schemas/test-utility.schema.json +44 -0
  84. package/scripts/CI_VALIDATORS.md +6 -6
  85. package/scripts/benchmark-jev.mjs +5 -0
  86. package/scripts/benchmark-test-intelligence.mjs +4 -0
  87. package/scripts/generate-agent-protocol-summary.mjs +6 -3
  88. package/scripts/generate-forgeloop-skill.mjs +133 -0
  89. package/scripts/jev-smoke.mjs +19 -0
  90. package/scripts/run-mcp-clean-tests.mjs +30 -0
  91. package/skills/forgeloop/README.md +9 -0
  92. package/skills/forgeloop/SKILL.md +77 -0
  93. package/skills/forgeloop/references/lifecycle.md +9 -0
  94. package/skills/forgeloop/references/recovery.md +7 -0
  95. package/skills/forgeloop/references/verification.md +7 -0
  96. package/src/adapters/agent-browser/assertions.js +47 -0
  97. package/src/adapters/agent-browser/commands.js +54 -0
  98. package/src/adapters/agent-browser/index.js +3 -0
  99. package/src/adapters/agent-browser/locator.js +40 -0
  100. package/src/adapters/agent-browser/process.js +215 -0
  101. package/src/adapters/agent-browser/provider.js +316 -0
  102. package/src/adapters/emulated-services/constants.js +24 -0
  103. package/src/adapters/emulated-services/index.js +7 -0
  104. package/src/adapters/emulated-services/process.js +162 -0
  105. package/src/adapters/emulated-services/provider.js +289 -0
  106. package/src/adapters/opensrc/normalize.js +90 -0
  107. package/src/adapters/opensrc/process.js +248 -0
  108. package/src/adapters/opensrc/provider.js +338 -0
  109. package/src/adapters/opensrc/search.js +264 -0
  110. package/src/adapters/temporary-paths.js +18 -0
  111. package/src/adapters/typesafe/client.js +28 -0
  112. package/src/adapters/typesafe/engine.js +63 -0
  113. package/src/adapters/typesafe/normalize.js +41 -0
  114. package/src/cli.js +218 -174
  115. package/src/commands/action-show.js +5 -2
  116. package/src/commands/advance.js +5 -1
  117. package/src/commands/baseline.js +13 -11
  118. package/src/commands/checkpoint-revalidate.js +192 -0
  119. package/src/commands/complete.js +19 -3
  120. package/src/commands/context-plan.js +38 -0
  121. package/src/commands/contract-create.js +266 -0
  122. package/src/commands/contract-revise.js +236 -0
  123. package/src/commands/decision-show.js +14 -0
  124. package/src/commands/decision-status.js +22 -0
  125. package/src/commands/discover.js +41 -0
  126. package/src/commands/doctor.js +51 -13
  127. package/src/commands/gate-record.js +194 -0
  128. package/src/commands/gate-revalidate.js +135 -0
  129. package/src/commands/handoff-list.js +6 -1
  130. package/src/commands/handoff-show.js +6 -1
  131. package/src/commands/migrate-protocol.js +2 -2
  132. package/src/commands/model-route.js +40 -0
  133. package/src/commands/next.js +7 -1
  134. package/src/commands/policy-diff.js +25 -4
  135. package/src/commands/progress.js +17 -11
  136. package/src/commands/record-diagnosis.js +3 -0
  137. package/src/commands/route.js +146 -18
  138. package/src/commands/semantic-plan.js +41 -0
  139. package/src/commands/status.js +6 -1
  140. package/src/commands/storage-backup.js +15 -0
  141. package/src/commands/storage-migrate.js +5 -0
  142. package/src/commands/storage-migration-resume.js +5 -0
  143. package/src/commands/storage-migration-status.js +44 -0
  144. package/src/commands/storage-restore-resume.js +7 -0
  145. package/src/commands/storage-restore.js +8 -0
  146. package/src/commands/task-abandon.js +224 -0
  147. package/src/commands/task-list.js +8 -43
  148. package/src/commands/task-migrate-contract-bootstrap-repair.js +288 -0
  149. package/src/commands/task-migrate.js +3 -3
  150. package/src/commands/task-recover.js +10 -2
  151. package/src/commands/task-repair-contract-bootstrap.js +263 -0
  152. package/src/commands/task-scope.js +18 -2
  153. package/src/commands/task-show.js +16 -2
  154. package/src/commands/test-inventory.js +5 -0
  155. package/src/commands/test-prune-plan.js +5 -0
  156. package/src/commands/test-prune-probe.js +5 -0
  157. package/src/commands/test-utility.js +5 -0
  158. package/src/commands/validate-protocol.js +39 -15
  159. package/src/commands/validate-receipt.js +8 -1
  160. package/src/config/guides.json +4 -0
  161. package/src/core/action-ledger-projection.js +10 -3
  162. package/src/core/actions.js +38 -75
  163. package/src/core/activation.js +11 -3
  164. package/src/core/approvals.js +17 -51
  165. package/src/core/artifact-registry.js +83 -2
  166. package/src/core/artifacts.js +81 -27
  167. package/src/core/attachment-paths.js +45 -0
  168. package/src/core/attestation-coverage.js +6 -1
  169. package/src/core/attestation-verifier.js +21 -2
  170. package/src/core/attestation.js +17 -6
  171. package/src/core/audit-ux.js +514 -0
  172. package/src/core/audit.js +6 -1
  173. package/src/core/browser-verification/constants.js +149 -0
  174. package/src/core/browser-verification/normalize.js +254 -0
  175. package/src/core/browser-verification/provider.js +519 -0
  176. package/src/core/browser-verification/service.js +115 -0
  177. package/src/core/bundles.js +160 -66
  178. package/src/core/checkpoint-revalidation.js +321 -0
  179. package/src/core/cli-command-definitions.js +350 -7
  180. package/src/core/code-manifest.js +9 -3
  181. package/src/core/command-executors.js +274 -108
  182. package/src/core/command-input.js +136 -44
  183. package/src/core/completion-artifacts.js +85 -34
  184. package/src/core/completion-ownership.js +19 -8
  185. package/src/core/completion-recovery-rebind.js +11 -1
  186. package/src/core/completion.js +64 -15
  187. package/src/core/config.js +3 -0
  188. package/src/core/conformance.js +2 -1
  189. package/src/core/context-compiler/budget.js +9 -0
  190. package/src/core/context-compiler/candidates.js +39 -0
  191. package/src/core/context-compiler/compiler.js +63 -0
  192. package/src/core/context-compiler/fingerprint.js +11 -0
  193. package/src/core/context-compiler/policy.js +13 -0
  194. package/src/core/context-compiler/result.js +23 -0
  195. package/src/core/continuity-lint.js +13 -2
  196. package/src/core/continuity-reconciliation.js +16 -3
  197. package/src/core/continuity.js +16 -8
  198. package/src/core/contract-bootstrap-recovery.js +656 -0
  199. package/src/core/contract-revision.js +209 -0
  200. package/src/core/decision/artifact.js +70 -0
  201. package/src/core/decision/benchmarks.js +103 -0
  202. package/src/core/decision/cache.js +27 -0
  203. package/src/core/decision/constants.js +58 -0
  204. package/src/core/decision/cutover.js +34 -0
  205. package/src/core/decision/engine.js +22 -0
  206. package/src/core/decision/errors.js +68 -0
  207. package/src/core/decision/events.js +104 -0
  208. package/src/core/decision/freshness.js +19 -0
  209. package/src/core/decision/normalizers/index.js +115 -0
  210. package/src/core/decision/policy.js +18 -0
  211. package/src/core/decision/projection.js +16 -0
  212. package/src/core/decision/question-registry.js +201 -0
  213. package/src/core/decision/request.js +26 -0
  214. package/src/core/decision/resolver.js +138 -0
  215. package/src/core/decision/result.js +58 -0
  216. package/src/core/decision/service.js +181 -0
  217. package/src/core/decision/state-builder.js +65 -0
  218. package/src/core/decision/task-bindings.js +35 -0
  219. package/src/core/decision/test-provider.js +32 -0
  220. package/src/core/decision/thresholds.js +15 -0
  221. package/src/core/diagnosis-model.js +11 -0
  222. package/src/core/diagnosis.js +10 -1
  223. package/src/core/diagnostic-projection.js +29 -12
  224. package/src/core/diagnostic-record.js +28 -3
  225. package/src/core/efficiency.js +6 -1
  226. package/src/core/error-codes.js +278 -0
  227. package/src/core/events.js +535 -147
  228. package/src/core/evidence-readiness.js +9 -0
  229. package/src/core/execution-prerequisites.js +36 -13
  230. package/src/core/execution-profile.js +63 -38
  231. package/src/core/execution.js +26 -40
  232. package/src/core/filesystem.js +11 -0
  233. package/src/core/gate-artifact.js +105 -19
  234. package/src/core/gate-provenance.js +125 -0
  235. package/src/core/handoff.js +26 -14
  236. package/src/core/history.js +39 -35
  237. package/src/core/hypothesis-projection.js +32 -0
  238. package/src/core/information-gain-projection.js +104 -100
  239. package/src/core/inspect.js +12 -3
  240. package/src/core/integration-invocation-policy.js +37 -4
  241. package/src/core/integration-resources.js +119 -87
  242. package/src/core/ledger-event-collection.js +189 -0
  243. package/src/core/ledger-relations.js +23 -0
  244. package/src/core/model-router/constants.js +10 -0
  245. package/src/core/model-router/policy.js +103 -0
  246. package/src/core/model-router/router.js +37 -0
  247. package/src/core/native-storage.js +12 -0
  248. package/src/core/next-action-continuity.js +31 -9
  249. package/src/core/next-action-model.js +58 -0
  250. package/src/core/next-action-phases.js +131 -43
  251. package/src/core/next-action-refresh.js +43 -9
  252. package/src/core/next-action-review-phase.js +9 -4
  253. package/src/core/next-action-verification-phase.js +2 -1
  254. package/src/core/next-action.js +56 -9
  255. package/src/core/phase.js +266 -103
  256. package/src/core/policy-engine.js +12 -13
  257. package/src/core/preflight-consistency.js +89 -62
  258. package/src/core/preflight-loaders.js +48 -9
  259. package/src/core/preflight-model.js +6 -1
  260. package/src/core/preflight.js +29 -12
  261. package/src/core/progress.js +21 -10
  262. package/src/core/protocol-info.js +68 -0
  263. package/src/core/protocol-migration.js +7 -6
  264. package/src/core/protocol.js +20 -0
  265. package/src/core/reconcile-closure.js +281 -67
  266. package/src/core/recovery-history.js +67 -47
  267. package/src/core/reflection.js +72 -77
  268. package/src/core/responsibility.js +25 -13
  269. package/src/core/resumability.js +154 -44
  270. package/src/core/route-artifact.js +28 -4
  271. package/src/core/router.js +67 -1
  272. package/src/core/runtime-context.js +123 -61
  273. package/src/core/schema-validation.js +11 -3
  274. package/src/core/security-review/constants.js +64 -0
  275. package/src/core/security-review/normalize.js +245 -0
  276. package/src/core/security-review/provider.js +204 -0
  277. package/src/core/security-review/service.js +134 -0
  278. package/src/core/semantic-planning/constants.js +19 -0
  279. package/src/core/semantic-planning/projection.js +94 -0
  280. package/src/core/semantic-planning/service.js +15 -0
  281. package/src/core/settlement.js +12 -1
  282. package/src/core/signing/bundle-file.js +53 -0
  283. package/src/core/signing/bundle-reference.js +15 -0
  284. package/src/core/signing/sigstore.js +60 -33
  285. package/src/core/signing/statement-file.js +27 -0
  286. package/src/core/sources.js +37 -0
  287. package/src/core/storage-runtime-registry.js +41 -0
  288. package/src/core/structural-quality/artifacts.js +20 -14
  289. package/src/core/structural-quality/service.js +81 -56
  290. package/src/core/target-layout.js +1 -1
  291. package/src/core/task-claim-state.js +249 -15
  292. package/src/core/task-command.js +21 -1
  293. package/src/core/task-conflict-inspection.js +133 -102
  294. package/src/core/task-descriptor.js +29 -22
  295. package/src/core/task-discovery.js +288 -90
  296. package/src/core/task-lock.js +66 -306
  297. package/src/core/task-migration-validation.js +5 -5
  298. package/src/core/task-migration.js +17 -287
  299. package/src/core/task-paths.js +13 -0
  300. package/src/core/task-recovery.js +1 -0
  301. package/src/core/task-snapshot.js +51 -8
  302. package/src/core/task-storage-migration.js +18 -0
  303. package/src/core/templates.js +23 -8
  304. package/src/core/test-intelligence/benchmarks.js +68 -0
  305. package/src/core/test-intelligence/inventory.js +73 -0
  306. package/src/core/test-intelligence/prune.js +94 -0
  307. package/src/core/test-intelligence/semantic-state.js +15 -0
  308. package/src/core/test-intelligence/service.js +40 -0
  309. package/src/core/test-intelligence/utility.js +50 -0
  310. package/src/core/trace.js +164 -105
  311. package/src/core/trajectory-evaluation.js +15 -3
  312. package/src/core/trajectory-metrics.js +47 -32
  313. package/src/core/transaction.js +16 -287
  314. package/src/core/verification-scope.js +20 -12
  315. package/src/core/work-state.js +100 -59
  316. package/src/integration.d.ts +492 -0
  317. package/src/integration.js +54 -0
  318. package/src/providers/README.md +47 -0
  319. package/src/providers/capabilities.js +46 -0
  320. package/src/providers/errors.js +15 -0
  321. package/src/providers/index.js +29 -0
  322. package/src/providers/json-snapshot.js +105 -0
  323. package/src/providers/registry.js +152 -0
  324. package/src/repository-index/binary-manager.js +7 -5
  325. package/src/storage/artifact-bytes.js +22 -0
  326. package/src/storage/attachment-binding.js +11 -0
  327. package/src/storage/attachment-files.js +82 -0
  328. package/src/storage/attachment-references.js +36 -0
  329. package/src/storage/backup.js +53 -0
  330. package/src/storage/capabilities.js +31 -0
  331. package/src/storage/connection-owner.js +119 -0
  332. package/src/storage/connection.js +376 -0
  333. package/src/storage/existing-project-scope.js +45 -0
  334. package/src/storage/export-destination.js +44 -0
  335. package/src/storage/exporter.js +284 -0
  336. package/src/storage/file-durability.js +46 -0
  337. package/src/storage/importer.js +461 -0
  338. package/src/storage/index.js +74 -0
  339. package/src/storage/leases.js +63 -0
  340. package/src/storage/ledger-event-snapshot.js +150 -0
  341. package/src/storage/ledger-relations.js +220 -0
  342. package/src/storage/legacy-maintenance-boundary.js +18 -0
  343. package/src/storage/legacy-signature.js +115 -0
  344. package/src/storage/maintenance-handoff.js +129 -0
  345. package/src/storage/maintenance-owner.js +42 -0
  346. package/src/storage/maintenance.js +310 -0
  347. package/src/storage/metadata-json.js +35 -0
  348. package/src/storage/migration-activate.js +59 -0
  349. package/src/storage/migration-archive.js +57 -0
  350. package/src/storage/migration-attachment-root.js +61 -0
  351. package/src/storage/migration-candidate.js +398 -0
  352. package/src/storage/migration-publication.js +143 -0
  353. package/src/storage/migration-rollback-admission.js +54 -0
  354. package/src/storage/migration-rollback-preparation.js +132 -0
  355. package/src/storage/migration-rollback-publication.js +183 -0
  356. package/src/storage/migration-rollback-release.js +66 -0
  357. package/src/storage/migration-rollback-source-stage.js +103 -0
  358. package/src/storage/migration-rollback.js +43 -0
  359. package/src/storage/migration-source-partition.js +56 -0
  360. package/src/storage/migration-source.js +255 -0
  361. package/src/storage/migration-terminal.js +39 -0
  362. package/src/storage/migration-validation.js +75 -0
  363. package/src/storage/migration.js +43 -0
  364. package/src/storage/operational-attachments.js +49 -0
  365. package/src/storage/operational-context.js +50 -0
  366. package/src/storage/project-backup.js +98 -0
  367. package/src/storage/project-bootstrap.js +24 -0
  368. package/src/storage/project-boundary.js +79 -0
  369. package/src/storage/project-read-snapshot.js +18 -0
  370. package/src/storage/project-replacement.js +137 -0
  371. package/src/storage/project-restore.js +203 -0
  372. package/src/storage/record-definitions.js +45 -0
  373. package/src/storage/repository.js +507 -0
  374. package/src/storage/restore-journal.js +62 -0
  375. package/src/storage/restore-layout.js +30 -0
  376. package/src/storage/restore-preparation.js +84 -0
  377. package/src/storage/restore-replacement-archive.js +162 -0
  378. package/src/storage/restore-replacement-owner.js +31 -0
  379. package/src/storage/restore-replacement-preparation.js +128 -0
  380. package/src/storage/restore-replacement.js +142 -0
  381. package/src/storage/restore-terminal.js +32 -0
  382. package/src/storage/runtime.js +31 -0
  383. package/src/storage/schema.js +214 -0
  384. package/src/storage/singleton-import.js +84 -0
  385. package/src/storage/snapshot-continuity.js +16 -0
  386. package/src/storage/snapshot.js +36 -0
  387. package/src/storage/storage-marker.js +79 -0
  388. package/src/storage/task-guards.js +107 -0
  389. package/src/storage/topology.js +42 -0
  390. package/src/storage/transaction.js +179 -0
  391. package/src/storage/unit-of-work.js +663 -0
  392. package/src/storage/windows-process-incarnation.js +206 -0
  393. package/.forgeloop/forgeloop.gitignore +0 -4
  394. package/LICENSE-DOCS.md +0 -13
  395. package/src/core/transaction-maintenance.js +0 -70
@@ -1,6 +1,11 @@
1
1
  import { readdir } from "node:fs/promises";
2
+ import { createReadStream } from "node:fs";
3
+ import { createHash } from "node:crypto";
4
+ import { resolveAttestationBundlePath } from "./attachment-paths.js";
5
+ import { withOperationalAttachmentFile } from "../storage/operational-attachments.js";
6
+ import { getOperationalStore, operationalArtifactExists, listOperationalArtifactNames } from "../storage/operational-context.js";
2
7
 
3
- import { ARTIFACT_PATHS, canonicalFingerprint, readJsonArtifact, writeJsonArtifact } from "./artifacts.js";
8
+ import { ARTIFACT_PATHS, canonicalFingerprint, readJsonArtifact, readPortableJsonArtifact, writePortableJsonArtifact } from "./artifacts.js";
4
9
  import { validateContract } from "./contract.js";
5
10
  import { assertSafePath, ensureWithin, fileExists, readBytes, writeFileAtomic } from "./filesystem.js";
6
11
  import { PROTOCOL_VERSION } from "./protocol.js";
@@ -12,11 +17,13 @@ import { taskArtifactPath, taskDirectory, taskStructuralQualityDirectory } from
12
17
  import { resolveTaskClaimState } from "./task-claim-state.js";
13
18
  import { E_TASK_CLAIM_OWNERSHIP_INCONSISTENT } from "./error-codes.js";
14
19
  import { listActions } from "./actions.js";
20
+ import { validateActionArtifact } from "./action-model.js";
15
21
  import { validateCanonicalHandoff } from "./handoff.js";
16
22
  import { validateVerificationScope } from "./verification-scope.js";
17
23
  import { validateResponsibilityContract } from "./responsibility.js";
18
24
  import { validateWorkspaceBinding } from "./workspace-binding.js";
19
25
  import { validateCodeManifest, validateCodeManifestBindings } from "./code-manifest.js";
26
+ import { withNativeReadScope } from "./native-storage.js";
20
27
  import { assertAttestationStatementBindings } from "./attestation-verifier.js";
21
28
  import { validateAttestationStatement } from "./attestation.js";
22
29
  import {
@@ -27,7 +34,16 @@ import {
27
34
  } from "./structural-quality/artifacts.js";
28
35
  import { normalizeStructuralQualityConfig, structuralQualityPolicyFingerprint } from "./structural-quality/policy.js";
29
36
 
30
- export const BUNDLE_SCHEMA_VERSION = 1;
37
+ export const BUNDLE_SCHEMA_VERSION = 2;
38
+
39
+ async function bundleFileBinding(target, relativePath, name) {
40
+ if (typeof name !== "string" || name.includes("\\") || name.includes("\u0000") || name.split("/").some(part => !part || part === "." || part === "..")) throw Object.assign(new Error("Invalid portable bundle artifact path"), { code: "E_BUNDLE_PATH_INVALID" });
41
+ const filename = await assertSafePath(target, relativePath);
42
+ const hash = createHash("sha256");
43
+ let size = 0;
44
+ for await (const bytes of createReadStream(filename)) { hash.update(bytes); size += bytes.length; }
45
+ return { path: name, size, sha256: hash.digest("hex") };
46
+ }
31
47
  const BUNDLE_ROOT = ".forgeloop/tasks";
32
48
 
33
49
  function safeTaskId(taskId) {
@@ -161,10 +177,32 @@ function assertBundledCodeManifestBindings({ loaded, ledger, taskId }) {
161
177
  }
162
178
  }
163
179
 
180
+ /** Export sources may be explicit legacy inputs; selected native authority never falls back. */
181
+ function readBundleSourceJson(target,sourcePath,schemaName,packageRoot){
182
+ const reader=getOperationalStore(target)?readJsonArtifact:readPortableJsonArtifact;
183
+ return reader(target,sourcePath,schemaName,packageRoot);
184
+ }
185
+
186
+ /** Read-only legacy export inspection; operational action listing remains SQLite-only. */
187
+ async function readBundleSourceActions(target,taskId,packageRoot){
188
+ if(getOperationalStore(target))return listActions(target,{taskId,packageRoot});
189
+ const directory=`${taskDirectory(taskId)}/actions`;
190
+ const absolute=await assertSafePath(target,directory);
191
+ if(!(await fileExists(absolute)))return [];
192
+ const actions=[];
193
+ for(const name of (await readdir(absolute)).filter(name=>name.endsWith(".json")).sort()){
194
+ const artifact=await readPortableJsonArtifact(target,`${directory}/${name}`,"action",packageRoot);
195
+ const action=validateActionArtifact(artifact.value);
196
+ if(action.taskId!==taskId || `${action.actionId}.json`!==name)throw bundleBindingError("E_BUNDLE_TASK_MISMATCH","Legacy export action identity differs from its source path");
197
+ actions.push(action);
198
+ }
199
+ return actions.sort((left,right)=>String(left.createdAt).localeCompare(String(right.createdAt)));
200
+ }
201
+
164
202
  async function copyJson(target, sourcePath, destinationPath, schemaName, packageRoot, artifacts, relativeName) {
165
203
  try {
166
- const value = await readJsonArtifact(target, sourcePath, schemaName, packageRoot);
167
- await writeJsonArtifact(target, destinationPath, value.value, schemaName, packageRoot);
204
+ const value = await readBundleSourceJson(target, sourcePath, schemaName, packageRoot);
205
+ await writePortableJsonArtifact(target, destinationPath, value.value, schemaName, packageRoot);
168
206
  artifacts.push(relativeName);
169
207
  return value;
170
208
  } catch (error) {
@@ -176,37 +214,52 @@ async function copyJson(target, sourcePath, destinationPath, schemaName, package
176
214
  async function copyOptionalJson(target, taskPath, legacyPath, destinationPath, schemaName, packageRoot, artifacts, relativeName) {
177
215
  const candidates = [taskPath, legacyPath].filter(Boolean);
178
216
  for (const sourcePath of candidates) {
179
- if (!(await fileExists(ensureWithin(target, sourcePath)))) continue;
217
+ if (getOperationalStore(target) && sourcePath === legacyPath) continue;
218
+ if (!(operationalArtifactExists(target, sourcePath) ?? await fileExists(ensureWithin(target, sourcePath)))) continue;
180
219
  return copyJson(target, sourcePath, destinationPath, schemaName, packageRoot, artifacts, relativeName);
181
220
  }
182
221
  return null;
183
222
  }
184
223
 
185
- async function copyRawFile(target, sourcePath, destinationPath, artifacts, relativeName) {
186
- if (!(await fileExists(ensureWithin(target, sourcePath)))) return false;
187
- await assertSafePath(target, destinationPath);
188
- await writeFileAtomic(ensureWithin(target, destinationPath), await readBytes(ensureWithin(target, sourcePath)));
224
+ async function copyRawFile(target, sourcePath, destinationPath, artifacts, relativeName, taskId) {
225
+ const canonical = getOperationalStore(target) && sourcePath.startsWith(".forgeloop/attachments/objects/");
226
+ if (!canonical && !(await fileExists(ensureWithin(target, sourcePath)))) return false;
227
+ await assertSafePath(target, sourcePath);
228
+ const destination = await assertSafePath(target, destinationPath);
229
+ await withOperationalAttachmentFile(target, sourcePath, taskId, source => writeFileAtomic(destination, createReadStream(source)));
189
230
  artifacts.push(relativeName);
190
231
  return true;
191
232
  }
192
233
 
193
234
  async function tryReadJson(target, taskPath, legacyPath, schemaName, packageRoot) {
194
235
  try {
195
- return await readJsonArtifact(target, taskPath, schemaName, packageRoot);
236
+ return await readBundleSourceJson(target, taskPath, schemaName, packageRoot);
196
237
  } catch (error) {
197
- if (error.code === "ARTIFACT_MISSING" && legacyPath) {
198
- return await readJsonArtifact(target, legacyPath, schemaName, packageRoot);
238
+ if (error.code === "ARTIFACT_MISSING" && legacyPath && !getOperationalStore(target)) {
239
+ return await readBundleSourceJson(target, legacyPath, schemaName, packageRoot);
199
240
  }
200
241
  throw error;
201
242
  }
202
243
  }
203
244
 
204
245
  export async function exportTaskBundle(target, taskId, packageRoot) {
246
+ return withNativeReadScope(target, async () => {
247
+ const store = getOperationalStore(target);
248
+ if (!store) return exportSelectedTaskBundle(target, taskId, packageRoot);
249
+ const [{ withStorageSnapshot }, { withOperationalStore }, { operationalContext }] = await Promise.all([
250
+ import("../storage/snapshot.js"), import("../storage/unit-of-work.js"), import("../storage/operational-context.js"),
251
+ ]);
252
+ return withStorageSnapshot(store.db, snapshot => operationalContext.run(null,
253
+ () => withOperationalStore({ db: snapshot, target }, () => exportSelectedTaskBundle(target, taskId, packageRoot))));
254
+ });
255
+ }
256
+
257
+ async function exportSelectedTaskBundle(target, taskId, packageRoot) {
205
258
  safeTaskId(taskId);
206
259
  const directory = bundleDirectory(taskId);
207
260
  const artifacts = [];
208
261
 
209
- if (await fileExists(ensureWithin(target, taskArtifactPath(taskId, "descriptor")))) {
262
+ if (operationalArtifactExists(target, taskArtifactPath(taskId, "descriptor")) ?? await fileExists(ensureWithin(target, taskArtifactPath(taskId, "descriptor")))) {
210
263
  const claimProjection = await resolveTaskClaimState(target, { taskId, packageRoot });
211
264
  if (!claimProjection.valid) {
212
265
  const error = new Error(`Task ${taskId} claim ownership is inconsistent and cannot be exported safely`);
@@ -255,7 +308,7 @@ export async function exportTaskBundle(target, taskId, packageRoot) {
255
308
  error.code = "E_BUNDLE_TASK_MISMATCH";
256
309
  throw error;
257
310
  }
258
- await writeJsonArtifact(target, `${directory}/${destinationName}`, source.value, schemaName, packageRoot);
311
+ await writePortableJsonArtifact(target, `${directory}/${destinationName}`, source.value, schemaName, packageRoot);
259
312
  artifacts.push(destinationName);
260
313
  }
261
314
 
@@ -295,12 +348,12 @@ export async function exportTaskBundle(target, taskId, packageRoot) {
295
348
  const qualityBaseline = await readStructuralQualityBaseline(target, taskId, packageRoot);
296
349
  const qualityEvaluations = await listStructuralQualityEvaluations(target, taskId, packageRoot);
297
350
  if (qualityBaseline) {
298
- await writeJsonArtifact(target, `${directory}/structural-quality/baseline.json`, qualityBaseline.value, "structural-quality", packageRoot);
351
+ await writePortableJsonArtifact(target, `${directory}/structural-quality/baseline.json`, qualityBaseline.value, "structural-quality", packageRoot);
299
352
  artifacts.push("structural-quality/baseline.json");
300
353
  }
301
354
  for (const evaluation of qualityEvaluations) {
302
355
  const destination = `structural-quality/evaluations/cycle-${evaluation.value.verificationCycle}-attempt-${evaluation.value.attempt}.json`;
303
- await writeJsonArtifact(target, `${directory}/${destination}`, evaluation.value, "structural-quality", packageRoot);
356
+ await writePortableJsonArtifact(target, `${directory}/${destination}`, evaluation.value, "structural-quality", packageRoot);
304
357
  artifacts.push(destination);
305
358
  }
306
359
 
@@ -330,22 +383,23 @@ export async function exportTaskBundle(target, taskId, packageRoot) {
330
383
  }
331
384
 
332
385
  const handoffDirectory = taskArtifactPath(taskId, "handoffs");
333
- if (await fileExists(ensureWithin(target, handoffDirectory))) {
334
- const handoffEntries = await readdir(ensureWithin(target, handoffDirectory), { withFileTypes: true });
386
+ const selectedHandoffs = listOperationalArtifactNames(target, taskId, "handoffs");
387
+ if (selectedHandoffs !== null || await fileExists(ensureWithin(target, handoffDirectory))) {
388
+ const handoffEntries = selectedHandoffs !== null ? selectedHandoffs.map(name => ({ name, isFile: () => true })) : await readdir(ensureWithin(target, handoffDirectory), { withFileTypes: true });
335
389
  for (const entry of handoffEntries
336
390
  .filter((item) => item.isFile() && /^handoff-[A-Za-z0-9_-]+\.json$/u.test(item.name))
337
391
  .sort((left, right) => left.name.localeCompare(right.name))) {
338
392
  const sourcePath = `${handoffDirectory}/${entry.name}`;
339
- const handoff = await readJsonArtifact(target, sourcePath, "handoff-envelope", packageRoot);
393
+ const handoff = await readBundleSourceJson(target, sourcePath, "handoff-envelope", packageRoot);
340
394
  await validateCanonicalHandoff(target, handoff.value, { taskId, packageRoot });
341
395
  const destination = `handoffs/${entry.name}`;
342
- await writeJsonArtifact(target, `${directory}/${destination}`, handoff.value, "handoff-envelope", packageRoot);
396
+ await writePortableJsonArtifact(target, `${directory}/${destination}`, handoff.value, "handoff-envelope", packageRoot);
343
397
  artifacts.push(destination);
344
398
  }
345
399
  }
346
400
 
347
- const rawAttestationBundle = `${taskArtifactPath(taskId, "attestations")}/statement.sigstore.json`;
348
- await copyRawFile(target, rawAttestationBundle, `${directory}/attestations/statement.sigstore.json`, artifacts, "attestations/statement.sigstore.json");
401
+ const rawAttestationBundle = resolveAttestationBundlePath(target, taskId);
402
+ await copyRawFile(target, rawAttestationBundle, `${directory}/attestations/statement.sigstore.json`, artifacts, "attestations/statement.sigstore.json", taskId);
349
403
  if (exportedManifest?.value) {
350
404
  exportedManifest.value = await validateCodeManifest(exportedManifest.value, packageRoot);
351
405
  if (exportedManifest.value.taskId !== taskId) {
@@ -366,10 +420,10 @@ export async function exportTaskBundle(target, taskId, packageRoot) {
366
420
  if (exportedManifest?.value && exportedStatement?.value) {
367
421
  assertAttestationStatementBindings(exportedStatement.value, exportedManifest.value, taskId, canonicalFingerprint(exportedManifest.value));
368
422
  }
369
- const actionArtifacts = await listActions(target, { packageRoot, taskId });
423
+ const actionArtifacts = await readBundleSourceActions(target,taskId,packageRoot);
370
424
  for (const action of actionArtifacts) {
371
425
  const destination = `${directory}/actions/${action.actionId}.json`;
372
- await writeJsonArtifact(target, destination, action, "action", packageRoot);
426
+ await writePortableJsonArtifact(target, destination, action, "action", packageRoot);
373
427
  artifacts.push(`actions/${action.actionId}.json`);
374
428
  }
375
429
 
@@ -380,38 +434,11 @@ export async function exportTaskBundle(target, taskId, packageRoot) {
380
434
  for (const executionRef of executionRefs) {
381
435
  const execution = await readExecutionArtifact({ target, executionRef, packageRoot, taskId });
382
436
  const destination = `${directory}/executions/${execution.value.executionId}.json`;
383
- await writeJsonArtifact(target, destination, execution.value, "execution", packageRoot);
437
+ await writePortableJsonArtifact(target, destination, execution.value, "execution", packageRoot);
384
438
  artifacts.push(`executions/${execution.value.executionId}.json`);
385
439
  }
386
440
 
387
- // Events
388
- let eventsPath = ensureWithin(target, taskArtifactPath(taskId, "events"));
389
- if (!(await fileExists(eventsPath))) {
390
- eventsPath = ensureWithin(target, ARTIFACT_PATHS.events);
391
- }
392
- if (await fileExists(eventsPath)) {
393
- await assertSafePath(target, `${directory}/events.ndjson`);
394
- await writeFileAtomic(ensureWithin(target, `${directory}/events.ndjson`), await readBytes(eventsPath));
395
- artifacts.push("events.ndjson");
396
- }
397
-
398
- // Gates
399
- let gateDirectory = ensureWithin(target, `${taskDirectory(taskId)}/gates`);
400
- if (!(await fileExists(gateDirectory))) {
401
- gateDirectory = ensureWithin(target, ARTIFACT_PATHS.gates);
402
- }
403
- if (await fileExists(gateDirectory)) {
404
- const entries = await readdir(gateDirectory, { withFileTypes: true });
405
- for (const entry of entries.filter((item) => item.isFile() && item.name.endsWith(".json")).sort((left, right) => left.name.localeCompare(right.name))) {
406
- const gateName = entry.name.slice(0, -5);
407
- const sourcePath = `${gateDirectory.replace(target + "/", "")}/${entry.name}`;
408
- const destinationPath = `${directory}/gates/${entry.name}`;
409
- const gate = await readJsonArtifact(target, sourcePath, "gate", packageRoot);
410
- if (gate.value.taskId !== taskId) continue;
411
- await writeJsonArtifact(target, destinationPath, gate.value, "gate", packageRoot);
412
- artifacts.push(`gates/${gateName}.json`);
413
- }
414
- }
441
+ await exportBundleLedgerAndGates(target, taskId, packageRoot, directory, artifacts);
415
442
 
416
443
  artifacts.sort();
417
444
  const manifest = {
@@ -419,14 +446,17 @@ export async function exportTaskBundle(target, taskId, packageRoot) {
419
446
  protocolVersion: PROTOCOL_VERSION,
420
447
  taskId,
421
448
  artifacts,
449
+ files: [],
422
450
  };
423
- await writeJsonArtifact(target, `${directory}/bundle.json`, manifest, "task-bundle", packageRoot);
451
+ for (const artifact of artifacts) manifest.files.push(await bundleFileBinding(target, `${directory}/${artifact}`, artifact));
452
+ await writePortableJsonArtifact(target, `${directory}/bundle.json`, manifest, "task-bundle", packageRoot);
424
453
  return { ...manifest, path: `${directory}/bundle.json` };
425
454
  }
426
455
 
427
456
  export async function readTaskBundle(target, taskId, packageRoot) {
428
457
  const directory = bundleDirectory(taskId);
429
458
  const manifest = await readJsonArtifact(target, `${directory}/bundle.json`, "task-bundle", packageRoot);
459
+ await verifyBundleFileBindings(target, directory, manifest);
430
460
  const loaded = {};
431
461
  const mappings = {
432
462
  "contract.json": ["contract", "current-contract"],
@@ -450,18 +480,7 @@ export async function readTaskBundle(target, taskId, packageRoot) {
450
480
  for (const artifact of manifest.value.artifacts) {
451
481
  const qualityKind = structuralQualityBundleKind(artifact);
452
482
  if (qualityKind) {
453
- const qualityArtifact = await readJsonArtifact(target, `${directory}/${artifact}`, "structural-quality", packageRoot);
454
- validateStructuralQualityArtifact(qualityArtifact.value, artifact);
455
- if (qualityArtifact.value.taskId !== taskId) {
456
- throw bundleBindingError("E_BUNDLE_TASK_MISMATCH", `Structural-quality ${qualityKind} taskId does not match its bundle task`);
457
- }
458
- loaded.structuralQuality ??= { baseline: null, evaluations: [] };
459
- if (qualityKind === "baseline") {
460
- if (loaded.structuralQuality.baseline) throw bundleBindingError("E_STRUCTURAL_QUALITY_EVIDENCE_STALE", "A bundle cannot contain more than one structural-quality baseline");
461
- loaded.structuralQuality.baseline = qualityArtifact.value;
462
- } else {
463
- loaded.structuralQuality.evaluations.push(qualityArtifact.value);
464
- }
483
+ await loadBundleQualityArtifact(target, directory, artifact, packageRoot, taskId, loaded, qualityKind);
465
484
  continue;
466
485
  }
467
486
  if (artifact.startsWith("executions/") && artifact.endsWith(".json")) {
@@ -501,6 +520,9 @@ export async function readTaskBundle(target, taskId, packageRoot) {
501
520
  }
502
521
  if (mapping[1] === "continuity") {
503
522
  assertContinuitySemantics(loadedArtifact.value);
523
+ if (loadedArtifact.value.taskId !== taskId) {
524
+ throw bundleBindingError("E_BUNDLE_TASK_MISMATCH", "Continuity taskId does not match its bundle task");
525
+ }
504
526
  }
505
527
  if (mapping[1] === "workspace-binding" && loadedArtifact.value.taskId !== taskId) {
506
528
  const error = new Error("Workspace binding taskId does not match its bundle task");
@@ -586,3 +608,75 @@ export async function readTaskBundle(target, taskId, packageRoot) {
586
608
  }
587
609
  return { manifest: manifest.value, artifacts: loaded };
588
610
  }
611
+
612
+ async function exportBundleLedgerAndGates(target, taskId, packageRoot, directory, artifacts) {
613
+ // Events
614
+ const selectedStore = getOperationalStore(target);
615
+ if (selectedStore) {
616
+ async function* ledgerBytes() {
617
+ for (const row of selectedStore.db.prepare("SELECT event_json FROM events WHERE task_id = ? ORDER BY seq").iterate(taskId)) yield `${JSON.stringify(JSON.parse(row.event_json))}\n`;
618
+ }
619
+ await writeFileAtomic(await assertSafePath(target, `${directory}/events.ndjson`), ledgerBytes());
620
+ artifacts.push("events.ndjson");
621
+ } else {
622
+ let eventsPath = ensureWithin(target, taskArtifactPath(taskId, "events"));
623
+ if (!(await fileExists(eventsPath))) {
624
+ eventsPath = ensureWithin(target, ARTIFACT_PATHS.events);
625
+ }
626
+ if (await fileExists(eventsPath)) {
627
+ await assertSafePath(target, `${directory}/events.ndjson`);
628
+ await writeFileAtomic(ensureWithin(target, `${directory}/events.ndjson`), await readBytes(eventsPath));
629
+ artifacts.push("events.ndjson");
630
+ }
631
+ }
632
+
633
+ // Gates
634
+ let gateRelativePath = `${taskDirectory(taskId)}/gates`;
635
+ let gateDirectory = ensureWithin(target, gateRelativePath);
636
+ const selectedGates = listOperationalArtifactNames(target, taskId, "gates");
637
+ if (selectedGates === null && !(await fileExists(gateDirectory))) {
638
+ gateRelativePath = ARTIFACT_PATHS.gates;
639
+ gateDirectory = ensureWithin(target, gateRelativePath);
640
+ }
641
+ if (selectedGates !== null || await fileExists(gateDirectory)) {
642
+ const entries = selectedGates !== null ? selectedGates.map(name => ({ name, isFile: () => true })) : await readdir(gateDirectory, { withFileTypes: true });
643
+ for (const entry of entries.filter((item) => item.isFile() && item.name.endsWith(".json")).sort((left, right) => left.name.localeCompare(right.name))) {
644
+ const gateName = entry.name.slice(0, -5);
645
+ const sourcePath = `${gateRelativePath}/${entry.name}`;
646
+ const destinationPath = `${directory}/gates/${entry.name}`;
647
+ const gate = await readBundleSourceJson(target, sourcePath, "gate", packageRoot);
648
+ if (gate.value.taskId !== taskId) continue;
649
+ await writePortableJsonArtifact(target, destinationPath, gate.value, "gate", packageRoot);
650
+ artifacts.push(`gates/${gateName}.json`);
651
+ }
652
+ }
653
+
654
+ }
655
+
656
+ async function verifyBundleFileBindings(target, directory, manifest) {
657
+ if (manifest.value.schemaVersion === 2) {
658
+ const listed = manifest.value.files.map(file => file.path);
659
+ if (new Set(listed).size !== listed.length || canonicalFingerprint([...listed].sort()) !== canonicalFingerprint([...manifest.value.artifacts].sort())) {
660
+ throw Object.assign(new Error("Bundle file bindings disagree with included artifacts"), { code: "E_BUNDLE_DIGEST_INVALID" });
661
+ }
662
+ for (const binding of manifest.value.files) {
663
+ const actual = await bundleFileBinding(target, `${directory}/${binding.path}`, binding.path);
664
+ if (actual.size !== binding.size || actual.sha256 !== binding.sha256) throw Object.assign(new Error(`Bundle bytes disagree with manifest: ${binding.path}`), { code: "E_BUNDLE_DIGEST_INVALID" });
665
+ }
666
+ }
667
+ }
668
+
669
+ async function loadBundleQualityArtifact(target, directory, artifact, packageRoot, taskId, loaded, qualityKind) {
670
+ const qualityArtifact = await readJsonArtifact(target, `${directory}/${artifact}`, "structural-quality", packageRoot);
671
+ validateStructuralQualityArtifact(qualityArtifact.value, artifact);
672
+ if (qualityArtifact.value.taskId !== taskId) {
673
+ throw bundleBindingError("E_BUNDLE_TASK_MISMATCH", `Structural-quality ${qualityKind} taskId does not match its bundle task`);
674
+ }
675
+ loaded.structuralQuality ??= { baseline: null, evaluations: [] };
676
+ if (qualityKind === "baseline") {
677
+ if (loaded.structuralQuality.baseline) throw bundleBindingError("E_STRUCTURAL_QUALITY_EVIDENCE_STALE", "A bundle cannot contain more than one structural-quality baseline");
678
+ loaded.structuralQuality.baseline = qualityArtifact.value;
679
+ } else {
680
+ loaded.structuralQuality.evaluations.push(qualityArtifact.value);
681
+ }
682
+ }