forgeos 0.1.0-alpha.7 → 0.1.0-alpha.71

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 (598) hide show
  1. package/.agents/skills/forge-agent-fabric/SKILL.md +178 -0
  2. package/.agents/skills/forge-agent-fabric/references/managed-workflows.md +95 -0
  3. package/.agents/skills/forge-agent-fabric/references/repository-analysis.md +102 -0
  4. package/.agents/skills/forge-agent-fabric/scripts/fabric.mjs +46 -0
  5. package/.agents/skills/forge-agent-fabric/scripts/repository.mjs +44 -0
  6. package/.npmignore +10 -0
  7. package/AGENTS.md +142 -90
  8. package/CHANGELOG.md +870 -9
  9. package/LICENSE +21 -0
  10. package/README.md +121 -6
  11. package/adapters/go/README.md +23 -0
  12. package/adapters/go/go.mod +3 -0
  13. package/adapters/go/http.go +149 -0
  14. package/adapters/go/registry.go +234 -0
  15. package/adapters/go/types.go +136 -0
  16. package/adapters/java/README.md +68 -0
  17. package/adapters/java/pom.xml +47 -0
  18. package/adapters/java/src/main/java/dev/forgeos/adapter/Auth.java +20 -0
  19. package/adapters/java/src/main/java/dev/forgeos/adapter/Diagnostic.java +16 -0
  20. package/adapters/java/src/main/java/dev/forgeos/adapter/Entry.java +38 -0
  21. package/adapters/java/src/main/java/dev/forgeos/adapter/EntryKind.java +16 -0
  22. package/adapters/java/src/main/java/dev/forgeos/adapter/ErrorInfo.java +4 -0
  23. package/adapters/java/src/main/java/dev/forgeos/adapter/Forge.java +94 -0
  24. package/adapters/java/src/main/java/dev/forgeos/adapter/ForgeCall.java +12 -0
  25. package/adapters/java/src/main/java/dev/forgeos/adapter/ForgeContext.java +11 -0
  26. package/adapters/java/src/main/java/dev/forgeos/adapter/ForgeHandler.java +8 -0
  27. package/adapters/java/src/main/java/dev/forgeos/adapter/ForgeHttpHandler.java +179 -0
  28. package/adapters/java/src/main/java/dev/forgeos/adapter/ForgeRegistry.java +121 -0
  29. package/adapters/java/src/main/java/dev/forgeos/adapter/Json.java +14 -0
  30. package/adapters/java/src/main/java/dev/forgeos/adapter/Manifest.java +14 -0
  31. package/adapters/java/src/main/java/dev/forgeos/adapter/RequestEnvelope.java +6 -0
  32. package/adapters/java/src/main/java/dev/forgeos/adapter/ResponseEnvelope.java +25 -0
  33. package/adapters/java/src/main/java/dev/forgeos/adapter/Risk.java +18 -0
  34. package/adapters/java/src/main/java/dev/forgeos/adapter/Schemas.java +36 -0
  35. package/adapters/java/src/main/java/dev/forgeos/adapter/Service.java +65 -0
  36. package/adapters/java/src/main/java/dev/forgeos/adapter/TransactionMode.java +18 -0
  37. package/adapters/java/src/main/java/dev/forgeos/adapter/TypedForgeHandler.java +6 -0
  38. package/adapters/java-spring-boot-starter/README.md +32 -0
  39. package/adapters/java-spring-boot-starter/pom.xml +49 -0
  40. package/adapters/java-spring-boot-starter/src/main/java/dev/forgeos/adapter/spring/ForgeCommand.java +22 -0
  41. package/adapters/java-spring-boot-starter/src/main/java/dev/forgeos/adapter/spring/ForgeExternalService.java +15 -0
  42. package/adapters/java-spring-boot-starter/src/main/java/dev/forgeos/adapter/spring/ForgeQuery.java +16 -0
  43. package/adapters/java-spring-boot-starter/src/main/java/dev/forgeos/adapter/spring/ForgeServiceBeanCondition.java +18 -0
  44. package/adapters/java-spring-boot-starter/src/main/java/dev/forgeos/adapter/spring/ForgeSpringAutoConfiguration.java +16 -0
  45. package/adapters/java-spring-boot-starter/src/main/java/dev/forgeos/adapter/spring/ForgeSpringRuntime.java +104 -0
  46. package/adapters/java-spring-boot-starter/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports +1 -0
  47. package/bin/forge.mjs +18 -0
  48. package/docs/agent-fabric-programs.md +151 -0
  49. package/docs/agent-fabric.md +582 -0
  50. package/docs/architecture/agent-fabric/PORTABLE_PROJECTS_PLAN.md +136 -0
  51. package/docs/architecture/agent-fabric/README.md +180 -0
  52. package/docs/architecture/agent-fabric/REPOSITORY_MANIFEST_PLAN.md +284 -0
  53. package/docs/architecture/agent-fabric/WORKFLOW_PROGRAM_V2_ADR.md +81 -0
  54. package/docs/architecture/agent-fabric/WORKFLOW_PROGRAM_V2_CORRECTIONS.md +39 -0
  55. package/docs/architecture/agent-fabric/WORKFLOW_PROGRAM_V2_CORRECTIONS_EVIDENCE.md +53 -0
  56. package/docs/architecture/agent-fabric/WORKFLOW_PROGRAM_V2_EVIDENCE.md +49 -0
  57. package/docs/architecture/agent-fabric/WORKFLOW_PROGRAM_V2_PLAN.md +590 -0
  58. package/docs/cair-protocol.md +103 -0
  59. package/docs/changelog.md +1070 -0
  60. package/docs/forge-protocol.md +189 -0
  61. package/docs/repository-agent-benchmark.md +179 -0
  62. package/docs/repository-analysis.md +139 -0
  63. package/docs/repository-context-quality.md +179 -0
  64. package/docs/repository-runtime-observation.md +82 -0
  65. package/examples/agent-fabric-v2/README.md +70 -0
  66. package/examples/agent-fabric-v2/item-child.workflow.ts +11 -0
  67. package/examples/agent-fabric-v2/make-request.mjs +4 -0
  68. package/examples/agent-fabric-v2/map-child.workflow.ts +10 -0
  69. package/examples/agent-fabric-v2/migrate.workflow.ts +35 -0
  70. package/examples/agent-fabric-v2/registry.example.json +256 -0
  71. package/examples/agent-fabric-v2/run-ui-fixture.ts +48 -0
  72. package/examples/agent-fabric-v2/ui-audit.workflow.ts +28 -0
  73. package/examples/agent-fabric-v2/ui-fixture-worker.cjs +36 -0
  74. package/examples/agent-fabric-v2/visual-population.json +13 -0
  75. package/examples/agent-fabric-v2/workers/check.mjs +2 -0
  76. package/examples/agent-fabric-v2/workers/common.mjs +7 -0
  77. package/examples/agent-fabric-v2/workers/discover.mjs +2 -0
  78. package/examples/agent-fabric-v2/workers/migrate.mjs +4 -0
  79. package/examples/agent-fabric-v2/workers/review.mjs +3 -0
  80. package/examples/go-billing/go.mod +7 -0
  81. package/examples/go-billing/main.go +120 -0
  82. package/examples/java-billing/pom.xml +60 -0
  83. package/examples/java-billing/src/main/java/dev/forgeos/examples/billing/CreateInvoiceInput.java +4 -0
  84. package/examples/java-billing/src/main/java/dev/forgeos/examples/billing/Invoice.java +11 -0
  85. package/examples/java-billing/src/main/java/dev/forgeos/examples/billing/Main.java +127 -0
  86. package/package.json +60 -5
  87. package/schemas/agent-fabric/v0.1/control-event.schema.json +281 -0
  88. package/schemas/forge-manifest.schema.json +389 -0
  89. package/scripts/field-test-forgeos.mjs +1021 -0
  90. package/scripts/install-agent-fabric-skill.mjs +105 -0
  91. package/src/forge/_generated/releaseManifest.json +1 -2
  92. package/src/forge/_generated/releaseManifest.ts +3 -3
  93. package/src/forge/agent-adapters/index.ts +1592 -125
  94. package/src/forge/agent-adapters/types.ts +225 -1
  95. package/src/forge/agent-fabric/adapter.ts +131 -0
  96. package/src/forge/agent-fabric/attached-snapshot.ts +55 -0
  97. package/src/forge/agent-fabric/attached-task-contract.ts +105 -0
  98. package/src/forge/agent-fabric/attached-task-service.ts +127 -0
  99. package/src/forge/agent-fabric/attached-task-store.ts +109 -0
  100. package/src/forge/agent-fabric/authority.ts +298 -0
  101. package/src/forge/agent-fabric/canonical.ts +135 -0
  102. package/src/forge/agent-fabric/codex-adversarial-review.ts +229 -0
  103. package/src/forge/agent-fabric/codex-sdk-worker.ts +203 -0
  104. package/src/forge/agent-fabric/conductor.ts +754 -0
  105. package/src/forge/agent-fabric/dictionary.ts +12 -0
  106. package/src/forge/agent-fabric/errors.ts +32 -0
  107. package/src/forge/agent-fabric/hardened-conductor.ts +485 -0
  108. package/src/forge/agent-fabric/hardened-reducer.ts +211 -0
  109. package/src/forge/agent-fabric/index.ts +48 -0
  110. package/src/forge/agent-fabric/journal.ts +116 -0
  111. package/src/forge/agent-fabric/local-adaptive-digest-worker.mjs +26 -0
  112. package/src/forge/agent-fabric/local-adaptive-harness.ts +343 -0
  113. package/src/forge/agent-fabric/local-adaptive-service.ts +398 -0
  114. package/src/forge/agent-fabric/local-adaptive-worker.ts +146 -0
  115. package/src/forge/agent-fabric/local-approval-window.ts +211 -0
  116. package/src/forge/agent-fabric/local-change-review-service.ts +374 -0
  117. package/src/forge/agent-fabric/local-coding-worker.ts +285 -0
  118. package/src/forge/agent-fabric/local-control-store.ts +239 -0
  119. package/src/forge/agent-fabric/local-effect-broker.ts +348 -0
  120. package/src/forge/agent-fabric/local-evolution-approval.ts +81 -0
  121. package/src/forge/agent-fabric/local-evolution-profile.ts +87 -0
  122. package/src/forge/agent-fabric/local-evolution-registry.ts +427 -0
  123. package/src/forge/agent-fabric/local-evolution-service.ts +200 -0
  124. package/src/forge/agent-fabric/local-intelligence.ts +281 -0
  125. package/src/forge/agent-fabric/local-paths.ts +18 -0
  126. package/src/forge/agent-fabric/local-task-contract.ts +203 -0
  127. package/src/forge/agent-fabric/local-task-inbox.ts +543 -0
  128. package/src/forge/agent-fabric/local-task-server.ts +374 -0
  129. package/src/forge/agent-fabric/local-task-service.ts +982 -0
  130. package/src/forge/agent-fabric/local-verification.ts +551 -0
  131. package/src/forge/agent-fabric/managed-environment.ts +205 -0
  132. package/src/forge/agent-fabric/managed-run-contract.ts +103 -0
  133. package/src/forge/agent-fabric/managed-run-service.ts +401 -0
  134. package/src/forge/agent-fabric/managed-run-store.ts +165 -0
  135. package/src/forge/agent-fabric/managed-workspace.ts +253 -0
  136. package/src/forge/agent-fabric/p0a.ts +104 -0
  137. package/src/forge/agent-fabric/p0b-model-adapter.ts +434 -0
  138. package/src/forge/agent-fabric/planning.ts +155 -0
  139. package/src/forge/agent-fabric/program-api.ts +37 -0
  140. package/src/forge/agent-fabric/program-contract.ts +283 -0
  141. package/src/forge/agent-fabric/program-dsl.ts +126 -0
  142. package/src/forge/agent-fabric/program-evidence.ts +22 -0
  143. package/src/forge/agent-fabric/program-image.ts +15 -0
  144. package/src/forge/agent-fabric/program-lock.ts +50 -0
  145. package/src/forge/agent-fabric/program-owner.ts +16 -0
  146. package/src/forge/agent-fabric/program-scheduler.ts +38 -0
  147. package/src/forge/agent-fabric/program-service.ts +793 -0
  148. package/src/forge/agent-fabric/program-store.ts +142 -0
  149. package/src/forge/agent-fabric/program-structure.ts +65 -0
  150. package/src/forge/agent-fabric/program-types.ts +110 -0
  151. package/src/forge/agent-fabric/program-view.ts +12 -0
  152. package/src/forge/agent-fabric/program-worker.ts +108 -0
  153. package/src/forge/agent-fabric/project-profile.ts +50 -0
  154. package/src/forge/agent-fabric/project-registry.ts +120 -0
  155. package/src/forge/agent-fabric/project-runtime.ts +85 -0
  156. package/src/forge/agent-fabric/readiness.ts +26 -0
  157. package/src/forge/agent-fabric/reducer.ts +863 -0
  158. package/src/forge/agent-fabric/repository-context.ts +83 -0
  159. package/src/forge/agent-fabric/resource-ledger.ts +266 -0
  160. package/src/forge/agent-fabric/serialized-local-adapter.ts +60 -0
  161. package/src/forge/agent-fabric/types.ts +424 -0
  162. package/src/forge/agent-fabric/validation.ts +500 -0
  163. package/src/forge/agent-fabric/workflow-engine.ts +218 -0
  164. package/src/forge/agent-fabric/workflow-task-actions.ts +104 -0
  165. package/src/forge/agent-fabric/workflow-templates.ts +11 -0
  166. package/src/forge/agent-memory/bridge.ts +1728 -0
  167. package/src/forge/agent-memory/context-pack.ts +284 -0
  168. package/src/forge/agent-memory/hook-runner.ts +331 -0
  169. package/src/forge/agent-memory/mcp.ts +597 -0
  170. package/src/forge/agent-memory/normalize.ts +498 -0
  171. package/src/forge/agent-memory/redaction.ts +103 -0
  172. package/src/forge/agent-memory/sources/claude-code.ts +51 -0
  173. package/src/forge/agent-memory/sources/codex-hook-runner.mjs +343 -0
  174. package/src/forge/agent-memory/sources/codex.ts +161 -0
  175. package/src/forge/agent-memory/sources/cursor.ts +35 -0
  176. package/src/forge/agent-memory/types.ts +215 -0
  177. package/src/forge/bench.ts +248 -0
  178. package/src/forge/brownfield-import/index.ts +896 -0
  179. package/src/forge/brownfield-import/types.ts +127 -0
  180. package/src/forge/cair/action-journal.ts +61 -0
  181. package/src/forge/cair/action-parser.ts +314 -0
  182. package/src/forge/cair/action-validator.ts +40 -0
  183. package/src/forge/cair/actions.ts +1818 -0
  184. package/src/forge/cair/format.ts +77 -0
  185. package/src/forge/cair/index.ts +118 -0
  186. package/src/forge/cair/query.ts +478 -0
  187. package/src/forge/cair/snapshot.ts +315 -0
  188. package/src/forge/cair/types.ts +255 -0
  189. package/src/forge/cli/adaptive.ts +51 -0
  190. package/src/forge/cli/ai.ts +16 -1
  191. package/src/forge/cli/auth.ts +459 -15
  192. package/src/forge/cli/authmd.ts +441 -0
  193. package/src/forge/cli/baseline.ts +112 -0
  194. package/src/forge/cli/build.ts +20 -4
  195. package/src/forge/cli/changed.ts +418 -0
  196. package/src/forge/cli/codex-app-server.ts +877 -0
  197. package/src/forge/cli/commands.ts +1859 -20
  198. package/src/forge/cli/db.ts +209 -2
  199. package/src/forge/cli/deploy.ts +1339 -0
  200. package/src/forge/cli/deps.ts +150 -23
  201. package/src/forge/cli/dev.ts +1137 -53
  202. package/src/forge/cli/docs.ts +265 -0
  203. package/src/forge/cli/doctor.ts +297 -0
  204. package/src/forge/cli/env-placeholders.ts +62 -0
  205. package/src/forge/cli/evolution.ts +40 -0
  206. package/src/forge/cli/fabric.ts +253 -0
  207. package/src/forge/cli/field-test.ts +568 -0
  208. package/src/forge/cli/golden-path.ts +487 -0
  209. package/src/forge/cli/handoff.ts +336 -0
  210. package/src/forge/cli/index.ts +1 -0
  211. package/src/forge/cli/last-run.ts +84 -0
  212. package/src/forge/cli/main.ts +196 -3
  213. package/src/forge/cli/new.ts +169 -17
  214. package/src/forge/cli/next-actions.ts +23 -0
  215. package/src/forge/cli/output.ts +398 -6
  216. package/src/forge/cli/parse.ts +1377 -38
  217. package/src/forge/cli/progress.ts +51 -0
  218. package/src/forge/cli/query.ts +32 -0
  219. package/src/forge/cli/release.ts +35 -11
  220. package/src/forge/cli/repository.ts +151 -0
  221. package/src/forge/cli/run.ts +42 -0
  222. package/src/forge/cli/secrets.ts +137 -1
  223. package/src/forge/cli/seed.ts +581 -0
  224. package/src/forge/cli/self-host.ts +56 -14
  225. package/src/forge/cli/studio.ts +2282 -0
  226. package/src/forge/cli/verify.ts +1458 -32
  227. package/src/forge/cli/windows.ts +23 -0
  228. package/src/forge/cli/workos.ts +3509 -0
  229. package/src/forge/compiler/agent-contract/build.ts +728 -64
  230. package/src/forge/compiler/agent-contract/types.ts +45 -2
  231. package/src/forge/compiler/ai-registry/parse.ts +71 -2
  232. package/src/forge/compiler/api-surface/build.ts +47 -0
  233. package/src/forge/compiler/app-graph/build.ts +112 -9
  234. package/src/forge/compiler/app-graph/extract.ts +107 -0
  235. package/src/forge/compiler/app-graph/module-graph.ts +73 -78
  236. package/src/forge/compiler/app-graph/parser.ts +24 -24
  237. package/src/forge/compiler/app-graph/profile.ts +26 -0
  238. package/src/forge/compiler/app-graph/tsconfig-hash.ts +41 -4
  239. package/src/forge/compiler/app-graph/versions.ts +1 -1
  240. package/src/forge/compiler/classifier/capabilities.ts +3 -2
  241. package/src/forge/compiler/classifier/classify.ts +32 -8
  242. package/src/forge/compiler/classifier/secrets.ts +3 -2
  243. package/src/forge/compiler/classifier/signals.ts +91 -1
  244. package/src/forge/compiler/client-sdk/build-manifest.ts +59 -0
  245. package/src/forge/compiler/client-sdk/render-client.ts +295 -13
  246. package/src/forge/compiler/data-graph/build.ts +29 -1
  247. package/src/forge/compiler/data-graph/parse.ts +20 -4
  248. package/src/forge/compiler/data-graph/sql/ddl.ts +144 -31
  249. package/src/forge/compiler/data-graph/sql/serialize.ts +4 -0
  250. package/src/forge/compiler/data-graph/sql/types.ts +1 -0
  251. package/src/forge/compiler/diagnostics/codes.ts +38 -0
  252. package/src/forge/compiler/diagnostics/create.ts +28 -2
  253. package/src/forge/compiler/diagnostics/index.ts +2 -0
  254. package/src/forge/compiler/emitter/barrel.ts +3 -0
  255. package/src/forge/compiler/emitter/render.ts +9 -0
  256. package/src/forge/compiler/external-manifest/registry.ts +217 -0
  257. package/src/forge/compiler/external-manifest/types.ts +91 -0
  258. package/src/forge/compiler/external-manifest/validate.ts +373 -0
  259. package/src/forge/compiler/frontend-graph/build.ts +142 -14
  260. package/src/forge/compiler/integration/add.ts +991 -33
  261. package/src/forge/compiler/integration/plan.ts +43 -12
  262. package/src/forge/compiler/integration/render.ts +29 -0
  263. package/src/forge/compiler/integration/snapshot.ts +2 -0
  264. package/src/forge/compiler/integration/templates/convex.ts +70 -0
  265. package/src/forge/compiler/integration/templates/index.ts +1 -0
  266. package/src/forge/compiler/integration/templates/render.ts +38 -0
  267. package/src/forge/compiler/integration/templates/types.ts +3 -0
  268. package/src/forge/compiler/integration/templates/workos.ts +1439 -0
  269. package/src/forge/compiler/make-registry/build.ts +8 -9
  270. package/src/forge/compiler/orchestrator/fast-check.ts +4 -0
  271. package/src/forge/compiler/orchestrator/generate-lock.ts +14 -3
  272. package/src/forge/compiler/orchestrator/manifest.ts +1 -1
  273. package/src/forge/compiler/orchestrator/plan-profile.ts +23 -0
  274. package/src/forge/compiler/orchestrator/plan.ts +249 -10
  275. package/src/forge/compiler/orchestrator/profile.ts +65 -0
  276. package/src/forge/compiler/orchestrator/run.ts +101 -33
  277. package/src/forge/compiler/orchestrator/serialize.ts +33 -8
  278. package/src/forge/compiler/orchestrator/types.ts +1 -1
  279. package/src/forge/compiler/package-graph/compiler.ts +3 -1
  280. package/src/forge/compiler/package-graph/constants.ts +1 -1
  281. package/src/forge/compiler/package-graph/dts-extractor.ts +14 -1
  282. package/src/forge/compiler/package-manager/adapter.ts +4 -1
  283. package/src/forge/compiler/package-manager/commands.ts +4 -0
  284. package/src/forge/compiler/package-manager/executor.ts +30 -1
  285. package/src/forge/compiler/package-manager/version.ts +36 -12
  286. package/src/forge/compiler/package-upgrades/planner.ts +155 -18
  287. package/src/forge/compiler/package-upgrades/types.ts +2 -0
  288. package/src/forge/compiler/policy-registry/build.ts +47 -2
  289. package/src/forge/compiler/policy-registry/parse.ts +32 -2
  290. package/src/forge/compiler/recipes/definitions.ts +63 -0
  291. package/src/forge/compiler/recipes/index.ts +2 -0
  292. package/src/forge/compiler/recipes/profiles.ts +81 -0
  293. package/src/forge/compiler/recipes/registry.ts +6 -0
  294. package/src/forge/compiler/test-graph/build.ts +11 -3
  295. package/src/forge/compiler/types/app-graph.ts +8 -2
  296. package/src/forge/compiler/types/cli.ts +76 -1
  297. package/src/forge/compiler/types/dev-manifest.ts +4 -0
  298. package/src/forge/compiler/types/emit.ts +2 -0
  299. package/src/forge/compiler/types/frontend-graph.ts +2 -2
  300. package/src/forge/compiler/types/integration.ts +1 -0
  301. package/src/forge/compiler/types/package-graph.ts +6 -0
  302. package/src/forge/compiler/types/policy-registry.ts +3 -1
  303. package/src/forge/delta/broker-runner.mjs +5 -0
  304. package/src/forge/delta/broker.ts +429 -0
  305. package/src/forge/delta/classifier.ts +52 -0
  306. package/src/forge/delta/explain.ts +238 -0
  307. package/src/forge/delta/git-observer.ts +67 -0
  308. package/src/forge/delta/ids.ts +44 -0
  309. package/src/forge/delta/index.ts +25 -0
  310. package/src/forge/delta/process-identity.ts +37 -0
  311. package/src/forge/delta/queue-status.ts +190 -0
  312. package/src/forge/delta/recorder.ts +540 -0
  313. package/src/forge/delta/redaction.ts +50 -0
  314. package/src/forge/delta/schema.ts +240 -0
  315. package/src/forge/delta/session.ts +142 -0
  316. package/src/forge/delta/status.ts +1139 -0
  317. package/src/forge/delta/store.ts +3329 -0
  318. package/src/forge/delta/timeline.ts +178 -0
  319. package/src/forge/dev/server.ts +1061 -22
  320. package/src/forge/dev/types.ts +15 -1
  321. package/src/forge/dev/watch.ts +17 -7
  322. package/src/forge/dev-console/cycle.ts +285 -33
  323. package/src/forge/dev-console/types.ts +47 -1
  324. package/src/forge/impact/index.ts +222 -30
  325. package/src/forge/impact/types.ts +33 -1
  326. package/src/forge/intent/index.ts +35 -16
  327. package/src/forge/make/fields.ts +26 -0
  328. package/src/forge/make/index.ts +42 -6
  329. package/src/forge/make/templates.ts +211 -4
  330. package/src/forge/make/types.ts +2 -1
  331. package/src/forge/policy.ts +1 -1
  332. package/src/forge/react/index.ts +160 -2
  333. package/src/forge/refactor/index.ts +1 -0
  334. package/src/forge/repair/rules/index.ts +2 -2
  335. package/src/forge/repository-analysis/adapters/common.ts +72 -0
  336. package/src/forge/repository-analysis/adapters/docker.ts +185 -0
  337. package/src/forge/repository-analysis/adapters/java.ts +133 -0
  338. package/src/forge/repository-analysis/adapters/typescript.ts +350 -0
  339. package/src/forge/repository-analysis/adapters/vue.ts +71 -0
  340. package/src/forge/repository-analysis/analyze.ts +434 -0
  341. package/src/forge/repository-analysis/benchmark.ts +336 -0
  342. package/src/forge/repository-analysis/cache-gc.ts +154 -0
  343. package/src/forge/repository-analysis/check-selection.ts +123 -0
  344. package/src/forge/repository-analysis/context-node.ts +17 -0
  345. package/src/forge/repository-analysis/context.ts +456 -0
  346. package/src/forge/repository-analysis/http-resolution.ts +135 -0
  347. package/src/forge/repository-analysis/identity.ts +45 -0
  348. package/src/forge/repository-analysis/index.ts +18 -0
  349. package/src/forge/repository-analysis/nuxt-resolution.ts +188 -0
  350. package/src/forge/repository-analysis/quality.ts +60 -0
  351. package/src/forge/repository-analysis/retrieval.ts +309 -0
  352. package/src/forge/repository-analysis/runtime-artifacts.ts +195 -0
  353. package/src/forge/repository-analysis/runtime-observation.ts +325 -0
  354. package/src/forge/repository-analysis/scanner.ts +174 -0
  355. package/src/forge/repository-analysis/storage.ts +193 -0
  356. package/src/forge/repository-analysis/test-associations.ts +59 -0
  357. package/src/forge/repository-analysis/types.ts +99 -0
  358. package/src/forge/repository-manifest/index.ts +178 -0
  359. package/src/forge/repository-manifest/types.ts +63 -0
  360. package/src/forge/review/index.ts +162 -12
  361. package/src/forge/review/types.ts +15 -0
  362. package/src/forge/runtime/ai/providers.ts +19 -4
  363. package/src/forge/runtime/auth/config.ts +17 -0
  364. package/src/forge/runtime/auth/evaluate.ts +15 -2
  365. package/src/forge/runtime/auth/resolve.ts +61 -6
  366. package/src/forge/runtime/auth/types.ts +1 -0
  367. package/src/forge/runtime/db/factory.ts +1 -3
  368. package/src/forge/runtime/db/generated-client.ts +13 -2
  369. package/src/forge/runtime/db/memory-adapter.ts +139 -32
  370. package/src/forge/runtime/db/pglite-adapter.ts +285 -2
  371. package/src/forge/runtime/executor.ts +129 -16
  372. package/src/forge/runtime/external/bridge.ts +663 -0
  373. package/src/forge/runtime/runner/run-entry.ts +16 -7
  374. package/src/forge/runtime/telemetry/buffer.ts +4 -1
  375. package/src/forge/runtime/telemetry/scrubber.ts +35 -5
  376. package/src/forge/runtime/webhooks/security.ts +12 -7
  377. package/src/forge/server.ts +71 -7
  378. package/src/forge/ui/index.ts +831 -19
  379. package/src/forge/ui/types.ts +3 -1
  380. package/src/forge/version.ts +1 -1
  381. package/src/forge/vue/index.ts +422 -0
  382. package/src/forge/workspace/baseline.ts +112 -0
  383. package/src/forge/workspace/change-summary.ts +292 -0
  384. package/src/forge/workspace/forge-cli.ts +42 -0
  385. package/src/forge/workspace/git-summary.ts +393 -0
  386. package/templates/agent-workroom/AGENTS.md +29 -0
  387. package/templates/agent-workroom/README.md +34 -0
  388. package/templates/agent-workroom/forge.config.ts +3 -0
  389. package/templates/agent-workroom/package.json +34 -0
  390. package/templates/agent-workroom/pnpm-workspace.yaml +2 -0
  391. package/templates/agent-workroom/src/actions/indexAgentSignal.ts +10 -0
  392. package/templates/agent-workroom/src/commands/openWorkroom.ts +61 -0
  393. package/templates/agent-workroom/src/commands/recordAgentSignal.ts +119 -0
  394. package/templates/agent-workroom/src/commands/recordCheckRun.ts +52 -0
  395. package/templates/agent-workroom/src/forge/schema.ts +54 -0
  396. package/templates/agent-workroom/src/policies.ts +6 -0
  397. package/templates/agent-workroom/src/queries/listWorkrooms.ts +11 -0
  398. package/templates/agent-workroom/src/queries/liveWorkroom.ts +63 -0
  399. package/templates/agent-workroom/tsconfig.json +16 -0
  400. package/templates/agent-workroom/web/index.html +13 -0
  401. package/templates/agent-workroom/web/package.json +21 -0
  402. package/templates/agent-workroom/web/src/App.tsx +345 -0
  403. package/templates/agent-workroom/web/src/lib/forge.ts +20 -0
  404. package/templates/agent-workroom/web/src/main.tsx +13 -0
  405. package/templates/agent-workroom/web/src/styles.css +545 -0
  406. package/templates/agent-workroom/web/tsconfig.json +27 -0
  407. package/templates/agent-workroom/web/vite.config.ts +36 -0
  408. package/templates/b2b-support-web/package.json +2 -0
  409. package/templates/b2b-support-web/pnpm-workspace.yaml +2 -0
  410. package/templates/b2b-support-web/web/app/page.tsx +2 -2
  411. package/templates/b2b-support-web/web/lib/forge.ts +9 -2
  412. package/templates/b2b-support-web/web/next.config.ts +24 -0
  413. package/templates/b2b-support-web/web/package.json +1 -1
  414. package/templates/minimal-web/package.json +2 -1
  415. package/templates/minimal-web/pnpm-workspace.yaml +2 -0
  416. package/templates/minimal-web/web/index.html +1 -0
  417. package/templates/minimal-web/web/src/App.tsx +12 -6
  418. package/templates/minimal-web/web/src/lib/forge.ts +9 -2
  419. package/templates/minimal-web/web/src/styles.css +34 -0
  420. package/templates/minimal-web/web/vite.config.ts +36 -0
  421. package/templates/nuxt-web/.vscode/settings.json +14 -0
  422. package/templates/nuxt-web/.yarnrc.yml +1 -0
  423. package/templates/nuxt-web/README.md +30 -0
  424. package/templates/nuxt-web/forge.config.ts +3 -0
  425. package/templates/nuxt-web/package.json +37 -0
  426. package/templates/nuxt-web/pnpm-workspace.yaml +2 -0
  427. package/templates/nuxt-web/src/actions/logNoteCreated.ts +11 -0
  428. package/templates/nuxt-web/src/commands/createNote.ts +26 -0
  429. package/templates/nuxt-web/src/forge/schema.ts +12 -0
  430. package/templates/nuxt-web/src/policies.ts +6 -0
  431. package/templates/nuxt-web/src/queries/listNotes.ts +8 -0
  432. package/templates/nuxt-web/src/queries/liveNotes.ts +8 -0
  433. package/templates/nuxt-web/tsconfig.json +17 -0
  434. package/templates/nuxt-web/web/app.vue +67 -0
  435. package/templates/nuxt-web/web/components/LiveNotes.vue +89 -0
  436. package/templates/nuxt-web/web/components/NoteComposer.vue +100 -0
  437. package/templates/nuxt-web/web/composables/forge.ts +13 -0
  438. package/templates/nuxt-web/web/composables/useNotes.ts +24 -0
  439. package/templates/nuxt-web/web/nuxt.config.ts +11 -0
  440. package/templates/nuxt-web/web/package.json +22 -0
  441. package/templates/nuxt-web/web/plugins/forge.client.ts +10 -0
  442. package/templates/nuxt-web/web/plugins/forge.server.ts +10 -0
  443. package/templates/nuxt-web/web/server/api/forge-health.get.ts +7 -0
  444. package/templates/nuxt-web/web/tsconfig.json +6 -0
  445. package/templates/vendor-access/.vscode/settings.json +14 -0
  446. package/templates/vendor-access/README.md +30 -0
  447. package/templates/vendor-access/forge.config.ts +3 -0
  448. package/templates/vendor-access/package.json +35 -0
  449. package/templates/vendor-access/pnpm-workspace.yaml +2 -0
  450. package/templates/vendor-access/src/commands/addEvidence.ts +42 -0
  451. package/templates/vendor-access/src/commands/approveAccessRequest.ts +43 -0
  452. package/templates/vendor-access/src/commands/createAccessRequest.ts +49 -0
  453. package/templates/vendor-access/src/commands/seedVendorAccessDemo.ts +200 -0
  454. package/templates/vendor-access/src/forge/schema.ts +74 -0
  455. package/templates/vendor-access/src/policies.ts +11 -0
  456. package/templates/vendor-access/src/queries/listVendorAccessDashboard.ts +24 -0
  457. package/templates/vendor-access/src/queries/liveVendorAccessDashboard.ts +24 -0
  458. package/templates/vendor-access/tsconfig.json +17 -0
  459. package/templates/vendor-access/web/index.html +13 -0
  460. package/templates/vendor-access/web/package.json +21 -0
  461. package/templates/vendor-access/web/src/App.tsx +573 -0
  462. package/templates/vendor-access/web/src/lib/forge.ts +20 -0
  463. package/templates/vendor-access/web/src/main.tsx +205 -0
  464. package/templates/vendor-access/web/src/styles.css +682 -0
  465. package/templates/vendor-access/web/tsconfig.json +18 -0
  466. package/templates/vendor-access/web/vite.config.ts +36 -0
  467. package/src/forge/_generated/actionSubscriptions.json +0 -2
  468. package/src/forge/_generated/actionSubscriptions.ts +0 -10
  469. package/src/forge/_generated/agentAdapterManifest.json +0 -2
  470. package/src/forge/_generated/agentAdapterManifest.ts +0 -73
  471. package/src/forge/_generated/agentContract.json +0 -2
  472. package/src/forge/_generated/agentContract.ts +0 -7829
  473. package/src/forge/_generated/agentQuickstart.md +0 -34
  474. package/src/forge/_generated/agentTools.json +0 -2
  475. package/src/forge/_generated/agentTools.md +0 -16
  476. package/src/forge/_generated/agentTools.ts +0 -12
  477. package/src/forge/_generated/aiContext.ts +0 -125
  478. package/src/forge/_generated/aiModels.json +0 -2
  479. package/src/forge/_generated/aiModels.ts +0 -51
  480. package/src/forge/_generated/aiProviders.json +0 -2
  481. package/src/forge/_generated/aiProviders.ts +0 -23
  482. package/src/forge/_generated/aiRegistry.json +0 -2
  483. package/src/forge/_generated/aiRegistry.ts +0 -31
  484. package/src/forge/_generated/api.json +0 -2
  485. package/src/forge/_generated/api.ts +0 -8
  486. package/src/forge/_generated/appGraph.json +0 -2
  487. package/src/forge/_generated/appGraph.ts +0 -14937
  488. package/src/forge/_generated/appMap.md +0 -55
  489. package/src/forge/_generated/artifactManifest.json +0 -2
  490. package/src/forge/_generated/artifactManifest.ts +0 -7
  491. package/src/forge/_generated/authClaims.json +0 -2
  492. package/src/forge/_generated/authClaims.ts +0 -13
  493. package/src/forge/_generated/authConfig.json +0 -2
  494. package/src/forge/_generated/authConfig.ts +0 -17
  495. package/src/forge/_generated/authContext.ts +0 -23
  496. package/src/forge/_generated/authRegistry.json +0 -2
  497. package/src/forge/_generated/authRegistry.ts +0 -25
  498. package/src/forge/_generated/buildInfo.json +0 -2
  499. package/src/forge/_generated/buildInfo.ts +0 -9
  500. package/src/forge/_generated/capabilityMap.json +0 -2
  501. package/src/forge/_generated/capabilityMap.md +0 -15
  502. package/src/forge/_generated/capabilityMap.ts +0 -17
  503. package/src/forge/_generated/client.ts +0 -282
  504. package/src/forge/_generated/clientApi.ts +0 -9
  505. package/src/forge/_generated/clientManifest.json +0 -2
  506. package/src/forge/_generated/clientManifest.ts +0 -39
  507. package/src/forge/_generated/clientTypes.ts +0 -78
  508. package/src/forge/_generated/configRegistry.json +0 -2
  509. package/src/forge/_generated/configRegistry.ts +0 -4
  510. package/src/forge/_generated/dataGraph.json +0 -2
  511. package/src/forge/_generated/dataGraph.ts +0 -8
  512. package/src/forge/_generated/db.json +0 -2
  513. package/src/forge/_generated/db.ts +0 -2
  514. package/src/forge/_generated/dbSecurityManifest.json +0 -2
  515. package/src/forge/_generated/dbSecurityManifest.ts +0 -15
  516. package/src/forge/_generated/dbSessionContext.json +0 -2
  517. package/src/forge/_generated/dbSessionContext.ts +0 -39
  518. package/src/forge/_generated/deployManifest.json +0 -2
  519. package/src/forge/_generated/deployManifest.ts +0 -14
  520. package/src/forge/_generated/devManifest.json +0 -2
  521. package/src/forge/_generated/devManifest.ts +0 -62
  522. package/src/forge/_generated/envSchema.json +0 -2
  523. package/src/forge/_generated/envSchema.ts +0 -59
  524. package/src/forge/_generated/frontendGraph.json +0 -2
  525. package/src/forge/_generated/frontendGraph.ts +0 -27
  526. package/src/forge/_generated/importGuards.json +0 -2
  527. package/src/forge/_generated/importGuards.ts +0 -686
  528. package/src/forge/_generated/index.ts +0 -68
  529. package/src/forge/_generated/liveProductionManifest.json +0 -2
  530. package/src/forge/_generated/liveProductionManifest.ts +0 -23
  531. package/src/forge/_generated/liveProtocol.json +0 -2
  532. package/src/forge/_generated/liveProtocol.ts +0 -21
  533. package/src/forge/_generated/liveQueryRegistry.json +0 -2
  534. package/src/forge/_generated/liveQueryRegistry.ts +0 -9
  535. package/src/forge/_generated/liveTransportConfig.json +0 -2
  536. package/src/forge/_generated/liveTransportConfig.ts +0 -19
  537. package/src/forge/_generated/makeRegistry.json +0 -2
  538. package/src/forge/_generated/makeRegistry.ts +0 -177
  539. package/src/forge/_generated/makeTemplates.json +0 -2
  540. package/src/forge/_generated/makeTemplates.ts +0 -66
  541. package/src/forge/_generated/mockMap.json +0 -2
  542. package/src/forge/_generated/mockMap.ts +0 -7
  543. package/src/forge/_generated/operationPlaybooks.md +0 -167
  544. package/src/forge/_generated/packageGraph.json +0 -2
  545. package/src/forge/_generated/packageGraph.ts +0 -249334
  546. package/src/forge/_generated/packageUpgradeRegistry.json +0 -2
  547. package/src/forge/_generated/packageUpgradeRegistry.ts +0 -15
  548. package/src/forge/_generated/permissionMatrix.json +0 -2
  549. package/src/forge/_generated/permissionMatrix.ts +0 -7
  550. package/src/forge/_generated/policyRegistry.json +0 -2
  551. package/src/forge/_generated/policyRegistry.ts +0 -11
  552. package/src/forge/_generated/queryRegistry.json +0 -2
  553. package/src/forge/_generated/queryRegistry.ts +0 -9
  554. package/src/forge/_generated/react.d.ts +0 -22
  555. package/src/forge/_generated/react.ts +0 -29
  556. package/src/forge/_generated/reactManifest.json +0 -2
  557. package/src/forge/_generated/reactManifest.ts +0 -19
  558. package/src/forge/_generated/rlsPolicies.json +0 -2
  559. package/src/forge/_generated/rlsPolicies.sql +0 -34
  560. package/src/forge/_generated/rlsPolicies.ts +0 -6
  561. package/src/forge/_generated/runtimeGraph.json +0 -2
  562. package/src/forge/_generated/runtimeGraph.ts +0 -8
  563. package/src/forge/_generated/runtimeMatrix.json +0 -2
  564. package/src/forge/_generated/runtimeMatrix.ts +0 -334130
  565. package/src/forge/_generated/runtimeRegistry.ts +0 -2
  566. package/src/forge/_generated/runtimeRules.md +0 -91
  567. package/src/forge/_generated/secretRegistry.json +0 -2
  568. package/src/forge/_generated/secretRegistry.ts +0 -50
  569. package/src/forge/_generated/secretsContext.ts +0 -11
  570. package/src/forge/_generated/serverApi.ts +0 -10
  571. package/src/forge/_generated/sourceMapManifest.json +0 -2
  572. package/src/forge/_generated/sourceMapManifest.ts +0 -7
  573. package/src/forge/_generated/sqlPlan.json +0 -2
  574. package/src/forge/_generated/sqlPlan.ts +0 -88
  575. package/src/forge/_generated/subscriptionManifest.json +0 -2
  576. package/src/forge/_generated/subscriptionManifest.ts +0 -7
  577. package/src/forge/_generated/symbolicationManifest.json +0 -2
  578. package/src/forge/_generated/symbolicationManifest.ts +0 -17
  579. package/src/forge/_generated/telemetryRegistry.json +0 -2
  580. package/src/forge/_generated/telemetryRegistry.ts +0 -9
  581. package/src/forge/_generated/telemetrySinks.json +0 -2
  582. package/src/forge/_generated/telemetrySinks.ts +0 -11
  583. package/src/forge/_generated/tenantScope.json +0 -2
  584. package/src/forge/_generated/tenantScope.ts +0 -8
  585. package/src/forge/_generated/testGraph.json +0 -2
  586. package/src/forge/_generated/testGraph.ts +0 -3452
  587. package/src/forge/_generated/testPlanRegistry.json +0 -2
  588. package/src/forge/_generated/testPlanRegistry.ts +0 -33
  589. package/src/forge/_generated/uiRoutes.json +0 -2
  590. package/src/forge/_generated/uiRoutes.ts +0 -16
  591. package/src/forge/_generated/uiScenarios.json +0 -2
  592. package/src/forge/_generated/uiScenarios.ts +0 -30
  593. package/src/forge/_generated/uiTestManifest.json +0 -2
  594. package/src/forge/_generated/uiTestManifest.ts +0 -27
  595. package/src/forge/_generated/workflowRegistry.json +0 -2
  596. package/src/forge/_generated/workflowRegistry.ts +0 -9
  597. package/src/forge/_generated/workflowSubscriptions.json +0 -2
  598. package/src/forge/_generated/workflowSubscriptions.ts +0 -10
@@ -0,0 +1,285 @@
1
+ import { execFileSync } from "node:child_process";
2
+ import { closeSync, existsSync, fsyncSync, lstatSync, mkdirSync, openSync, readFileSync, realpathSync, writeFileSync } from "node:fs";
3
+ import { dirname, join, resolve } from "node:path";
4
+ import { sha256Digest } from "./canonical.ts";
5
+ import { AgentFabricError } from "./errors.ts";
6
+ import type { LocalCodingTaskProposal } from "./local-task-contract.ts";
7
+ import type { Digest } from "./types.ts";
8
+ import { localFabricPath } from "./local-paths.ts";
9
+
10
+ function git(root: string, args: readonly string[], maxBuffer = 128 * 1024): string {
11
+ try {
12
+ return execFileSync("git", ["-c", "core.fsmonitor=false", ...args], {
13
+ cwd: root, encoding: "utf8", windowsHide: true,
14
+ timeout: 10_000, maxBuffer, stdio: ["ignore", "pipe", "ignore"],
15
+ });
16
+ } catch {
17
+ throw new AgentFabricError("AF_INVALID_STATE", `Git operation failed: ${args[0] ?? "unknown"}`);
18
+ }
19
+ }
20
+
21
+ /** Git checkout may invoke post-checkout and configured smudge/process filters. */
22
+ function inertCheckoutOptions(repositoryRoot: string, configRoot = repositoryRoot): string[] {
23
+ const hooksDir = localFabricPath(repositoryRoot, "empty-hooks");
24
+ mkdirSync(hooksDir, { recursive: true, mode: 0o700 });
25
+ let names = "";
26
+ try {
27
+ names = execFileSync("git", ["config", "--name-only", "--get-regexp",
28
+ "^filter\\..*\\.(process|smudge|clean)$"], {
29
+ cwd: configRoot, encoding: "utf8", windowsHide: true,
30
+ timeout: 10_000, maxBuffer: 64 * 1024, stdio: ["ignore", "pipe", "ignore"],
31
+ });
32
+ } catch (error) {
33
+ if ((error as { status?: number }).status !== 1) {
34
+ throw new AgentFabricError("AF_INVALID_STATE", "Cannot inspect Git checkout filters");
35
+ }
36
+ }
37
+ const options = ["-c", `core.hooksPath=${hooksDir}`, "-c", "core.fsmonitor=false"];
38
+ for (const name of new Set(names.split(/\r?\n/u).filter(Boolean))) {
39
+ if (!/^filter\.[a-z0-9_.-]+\.(?:process|smudge|clean)$/iu.test(name)) {
40
+ throw new AgentFabricError("AF_INVALID_STATE", "Unsupported Git checkout filter setting");
41
+ }
42
+ options.push("-c", `${name}=`);
43
+ }
44
+ return options;
45
+ }
46
+
47
+ export function buildLocalCodingContext(repositoryRoot: string, task: Readonly<LocalCodingTaskProposal>): string {
48
+ const sources = task.sourcePaths.map((path) => ({
49
+ path,
50
+ content: git(repositoryRoot, ["show", `${task.baseCommit}:${path}`], task.limits.maximumContextBytes + 1),
51
+ }));
52
+ const content = JSON.stringify({ baseCommit: task.baseCommit, sources });
53
+ if (Buffer.byteLength(content, "utf8") > task.limits.maximumContextBytes) {
54
+ throw new AgentFabricError("AF_INVALID_STATE", "Pinned source context exceeds the approved byte limit");
55
+ }
56
+ return content;
57
+ }
58
+
59
+ /** Check the complete proposal before recording a successful result or a patch effect intent. */
60
+ export function validateLocalCodingModelOutput(text: string, task: Readonly<LocalCodingTaskProposal>): readonly { path: string; content: string }[] {
61
+ if (Buffer.byteLength(text, "utf8") > task.limits.maximumPatchBytes) {
62
+ throw new AgentFabricError("AF_INVALID_STATE", "Model output exceeds the approved patch byte limit");
63
+ }
64
+ let parsed: unknown;
65
+ const fenced = /^```(?:json)?\r?\n([\s\S]*?)\r?\n```$/u.exec(text.trim());
66
+ try { parsed = JSON.parse(fenced ? fenced[1]! : text); } catch {
67
+ throw new AgentFabricError("AF_INVALID_STATE", "Model output is not strict JSON");
68
+ }
69
+ if (!parsed || typeof parsed !== "object") {
70
+ throw new AgentFabricError("AF_INVALID_STATE", "Model output is not a file proposal");
71
+ }
72
+ // Small local models sometimes emit the files array directly. Both forms
73
+ // undergo the same strict path, content, count, and size checks below.
74
+ const root = parsed as Record<string, unknown>;
75
+ const rootKeys = Object.keys(root).sort().join(",");
76
+ const fileMap = !Array.isArray(parsed) && rootKeys !== "files" &&
77
+ rootKeys !== "files,schemaVersion" && Object.keys(root).every((path) =>
78
+ task.writablePaths.includes(path) && typeof root[path] === "string");
79
+ const proposedFiles = Array.isArray(parsed) ? parsed : fileMap
80
+ ? Object.entries(root).map(([path, content]) => ({ path, content })) : root.files;
81
+ if ((!Array.isArray(parsed) && !fileMap &&
82
+ (rootKeys !== "files" &&
83
+ (rootKeys !== "files,schemaVersion" ||
84
+ (root.schemaVersion !== 1 && root.schemaVersion !== "1")))) ||
85
+ !Array.isArray(proposedFiles) || proposedFiles.length < 1 || proposedFiles.length > task.writablePaths.length) {
86
+ throw new AgentFabricError("AF_INVALID_STATE", "Model file proposal has unsupported structure");
87
+ }
88
+ const seen = new Set<string>();
89
+ return proposedFiles.map((item: unknown) => {
90
+ if (!item || typeof item !== "object" || Array.isArray(item)) {
91
+ throw new AgentFabricError("AF_INVALID_STATE", "Invalid model file proposal");
92
+ }
93
+ const file = item as Record<string, unknown>;
94
+ if (Object.keys(file).sort().join(",") !== "content,path" ||
95
+ typeof file.path !== "string" || !task.writablePaths.includes(file.path) ||
96
+ seen.has(file.path.toLowerCase()) || typeof file.content !== "string" ||
97
+ file.content.includes("\u0000")) {
98
+ throw new AgentFabricError("AF_INVALID_STATE", "Model proposed an unauthorized file or content");
99
+ }
100
+ seen.add(file.path.toLowerCase());
101
+ return { path: file.path, content: file.content };
102
+ });
103
+ }
104
+
105
+ function checkedTarget(worktreeRoot: string, path: string): string {
106
+ const target = resolve(worktreeRoot, path);
107
+ const prefix = `${worktreeRoot}${process.platform === "win32" ? "\\" : "/"}`;
108
+ if (!target.startsWith(prefix)) {
109
+ throw new AgentFabricError("AF_INVALID_STATE", "Model path escapes the isolated checkout");
110
+ }
111
+ let cursor = worktreeRoot;
112
+ for (const segment of path.split("/")) {
113
+ cursor = join(cursor, segment);
114
+ if (existsSync(cursor) && lstatSync(cursor).isSymbolicLink()) {
115
+ throw new AgentFabricError("AF_INVALID_STATE", "Model path traverses a symbolic link");
116
+ }
117
+ }
118
+ return target;
119
+ }
120
+
121
+ function syncParentDirectories(path: string, root: string): void {
122
+ // Directory fsync is supported on POSIX. Windows file flush persists the file
123
+ // itself; a missing directory entry after a crash remains a readback failure.
124
+ if (process.platform === "win32") return;
125
+ let directory = dirname(path);
126
+ while (directory.startsWith(`${root}/`) || directory === root) {
127
+ const fd = openSync(directory, "r");
128
+ try { fsyncSync(fd); } finally { closeSync(fd); }
129
+ if (directory === root) break;
130
+ directory = dirname(directory);
131
+ }
132
+ }
133
+
134
+ export interface LocalPatchEvidence {
135
+ worktreeRoot: string;
136
+ baseCommit: string;
137
+ changedPaths: readonly string[];
138
+ diffDigest: Digest;
139
+ diffBytes: number;
140
+ diffPath: string;
141
+ verification: "diff_check_passed" | "diff_check_failed";
142
+ }
143
+
144
+ /** Recheck the live checkout before showing or accepting its saved diff. */
145
+ export function verifyLocalPatchEvidence(patch: LocalPatchEvidence): void {
146
+ const canonical = realpathSync(patch.worktreeRoot);
147
+ const checkoutRoot = realpathSync(git(canonical, ["rev-parse", "--show-toplevel"]).trim());
148
+ if (checkoutRoot !== canonical || git(canonical, ["rev-parse", "HEAD"]).trim() !== patch.baseCommit) {
149
+ throw new AgentFabricError("AF_CONFLICT", "Approved patch checkout moved from its recorded base");
150
+ }
151
+ if (git(canonical, ["diff", "--no-ext-diff", "--cached", "--binary"]).length > 0 ||
152
+ git(canonical, ["ls-files", "--others", "--exclude-standard"]).length > 0) {
153
+ throw new AgentFabricError("AF_CONFLICT", "Patch checkout has unrecorded files or staged changes");
154
+ }
155
+ const diff = git(canonical, ["diff", "--no-ext-diff", "--binary"], patch.diffBytes + 1);
156
+ if (sha256Digest(diff) !== patch.diffDigest ||
157
+ sha256Digest(readFileSync(patch.diffPath, "utf8")) !== patch.diffDigest) {
158
+ throw new AgentFabricError("AF_CONFLICT", "Live patch no longer matches its recorded diff");
159
+ }
160
+ }
161
+
162
+ /** Observe an interrupted materialization without creating a checkout or writing files. */
163
+ export function readbackLocalCodingPatch(
164
+ repositoryRoot: string, taskId: string,
165
+ task: Readonly<LocalCodingTaskProposal>, modelText: string,
166
+ ): LocalPatchEvidence {
167
+ const files = validateLocalCodingModelOutput(modelText, task);
168
+ const worktreePath = localFabricPath(repositoryRoot, "worktrees", taskId.replace(/^task:/u, ""));
169
+ if (!existsSync(worktreePath)) throw new AgentFabricError("AF_CONFLICT", "Patch checkout was not materialized");
170
+ const worktreeRoot = realpathSync(worktreePath);
171
+ const normalized = (value: string) => process.platform === "win32" ? value.toLowerCase() : value;
172
+ if (normalized(realpathSync(git(worktreeRoot, ["rev-parse", "--show-toplevel"]).trim())) !== normalized(worktreeRoot) ||
173
+ git(worktreeRoot, ["rev-parse", "HEAD"]).trim() !== task.baseCommit) {
174
+ throw new AgentFabricError("AF_CONFLICT", "Patch checkout does not match its approved base");
175
+ }
176
+ for (const file of files) {
177
+ const target = checkedTarget(worktreeRoot, file.path);
178
+ if (!existsSync(target) || readFileSync(target, "utf8") !== file.content) {
179
+ throw new AgentFabricError("AF_CONFLICT", "Patch checkout differs from the committed model result");
180
+ }
181
+ }
182
+ if (git(worktreeRoot, ["diff", "--no-ext-diff", "--cached", "--binary"]).length > 0 ||
183
+ git(worktreeRoot, ["ls-files", "--others", "--exclude-standard"]).length > 0) {
184
+ throw new AgentFabricError("AF_CONFLICT", "Patch checkout has unrecorded files or staged changes");
185
+ }
186
+ const diff = git(worktreeRoot, ["diff", "--no-ext-diff", "--binary"], task.limits.maximumPatchBytes + 1);
187
+ const diffBytes = Buffer.byteLength(diff, "utf8");
188
+ if (diffBytes === 0 || diffBytes > task.limits.maximumPatchBytes) {
189
+ throw new AgentFabricError("AF_CONFLICT", "Patch readback is empty or exceeds the approved limit");
190
+ }
191
+ const changedPaths = git(worktreeRoot, ["diff", "--no-ext-diff", "--name-only"]).trim().split(/\r?\n/u).filter(Boolean);
192
+ if (changedPaths.length !== files.length ||
193
+ changedPaths.some((path) => !files.some((file) => file.path === path))) {
194
+ throw new AgentFabricError("AF_CONFLICT", "Patch readback changed an unauthorized path");
195
+ }
196
+ const diffPath = localFabricPath(repositoryRoot, "artifacts", `${taskId.replace(/^task:/u, "")}.diff`);
197
+ if (!existsSync(diffPath) || readFileSync(diffPath, "utf8") !== diff) {
198
+ throw new AgentFabricError("AF_CONFLICT", "Patch artifact is missing or differs from checkout");
199
+ }
200
+ let verification: LocalPatchEvidence["verification"] = "diff_check_passed";
201
+ try { git(worktreeRoot, ["diff", "--check"]); }
202
+ catch { verification = "diff_check_failed"; }
203
+ const patch: LocalPatchEvidence = { worktreeRoot, baseCommit: task.baseCommit,
204
+ changedPaths, diffDigest: sha256Digest(diff), diffBytes, diffPath, verification };
205
+ verifyLocalPatchEvidence(patch);
206
+ return patch;
207
+ }
208
+
209
+ /** Apply a model's file proposal only inside a fresh checkout of the pinned commit. */
210
+ export function materializeLocalCodingPatch(
211
+ repositoryRoot: string,
212
+ taskId: string,
213
+ task: Readonly<LocalCodingTaskProposal>,
214
+ modelText: string,
215
+ ): LocalPatchEvidence {
216
+ const files = validateLocalCodingModelOutput(modelText, task);
217
+ const worktreeRoot = localFabricPath(repositoryRoot, "worktrees", taskId.replace(/^task:/u, ""));
218
+ const existing = existsSync(worktreeRoot);
219
+ if (!existing) {
220
+ mkdirSync(dirname(worktreeRoot), { recursive: true });
221
+ git(repositoryRoot, [...inertCheckoutOptions(repositoryRoot),
222
+ "worktree", "add", "--detach", "--no-checkout", "--", worktreeRoot, task.baseCommit]);
223
+ // Resolve includeIf and worktree-specific filter settings from the new
224
+ // worktree before any checkout reads untrusted repository content.
225
+ git(worktreeRoot, [...inertCheckoutOptions(repositoryRoot, worktreeRoot),
226
+ "reset", "--hard", task.baseCommit]);
227
+ }
228
+ const canonical = realpathSync(worktreeRoot);
229
+ const reportedRoot = realpathSync(git(canonical, ["rev-parse", "--show-toplevel"]).trim());
230
+ if ((process.platform === "win32" ? reportedRoot.toLowerCase() : reportedRoot) !==
231
+ (process.platform === "win32" ? canonical.toLowerCase() : canonical)) {
232
+ throw new AgentFabricError("AF_INVALID_STATE", "Isolated checkout root is not its own Git worktree");
233
+ }
234
+ if (git(canonical, ["rev-parse", "HEAD"]).trim() !== task.baseCommit) {
235
+ throw new AgentFabricError("AF_INVALID_STATE", "Isolated checkout is not at the approved base commit");
236
+ }
237
+ for (const file of files) {
238
+ const target = checkedTarget(canonical, file.path);
239
+ if (existing) {
240
+ if (!existsSync(target) || readFileSync(target, "utf8") !== file.content) {
241
+ throw new AgentFabricError("AF_CONFLICT", "Existing checkout differs from the recorded model result");
242
+ }
243
+ } else {
244
+ mkdirSync(dirname(target), { recursive: true });
245
+ writeFileSync(target, file.content, { flag: "w", flush: true });
246
+ syncParentDirectories(target, canonical);
247
+ }
248
+ }
249
+ git(canonical, [...inertCheckoutOptions(repositoryRoot, canonical),
250
+ "add", "-N", "--", ...files.map((file) => file.path)]);
251
+ const diff = git(canonical, ["diff", "--no-ext-diff", "--binary", "--", ...files.map((file) => file.path)],
252
+ task.limits.maximumPatchBytes + 1);
253
+ const diffBytes = Buffer.byteLength(diff, "utf8");
254
+ if (diffBytes === 0 || diffBytes > task.limits.maximumPatchBytes) {
255
+ throw new AgentFabricError("AF_INVALID_STATE", "Resulting diff is empty or exceeds the approved patch limit");
256
+ }
257
+ const changedPaths = git(canonical, ["diff", "--no-ext-diff", "--name-only", "--", ...files.map((file) => file.path)])
258
+ .trim().split(/\r?\n/u).filter(Boolean);
259
+ if (changedPaths.length === 0 || changedPaths.some((path) => !task.writablePaths.includes(path))) {
260
+ throw new AgentFabricError("AF_INVALID_STATE", "Resulting diff contains an unauthorized path");
261
+ }
262
+ const diffPath = localFabricPath(repositoryRoot, "artifacts", `${taskId.replace(/^task:/u, "")}.diff`);
263
+ mkdirSync(dirname(diffPath), { recursive: true });
264
+ if (existsSync(diffPath)) {
265
+ if (readFileSync(diffPath, "utf8") !== diff) {
266
+ throw new AgentFabricError("AF_CONFLICT", "Existing diff artifact differs from the model result");
267
+ }
268
+ } else {
269
+ writeFileSync(diffPath, diff, { flag: "wx", flush: true });
270
+ syncParentDirectories(diffPath, repositoryRoot);
271
+ }
272
+ if (sha256Digest(readFileSync(diffPath, "utf8")) !== sha256Digest(diff)) {
273
+ throw new AgentFabricError("AF_INVALID_STATE", "Diff artifact failed readback");
274
+ }
275
+ let verification: LocalPatchEvidence["verification"] = "diff_check_passed";
276
+ try {
277
+ git(canonical, ["diff", "--check", "--", ...files.map((file) => file.path)]);
278
+ } catch {
279
+ verification = "diff_check_failed";
280
+ }
281
+ const patch = { worktreeRoot: canonical, baseCommit: task.baseCommit, changedPaths,
282
+ diffDigest: sha256Digest(diff), diffBytes, diffPath, verification };
283
+ verifyLocalPatchEvidence(patch);
284
+ return patch;
285
+ }
@@ -0,0 +1,239 @@
1
+ import type { DbAdapter } from "../runtime/db/adapter.ts";
2
+ import { sha256Digest, stableStringify } from "./canonical.ts";
3
+ import { AgentFabricError } from "./errors.ts";
4
+ import { ForgeAgentConductor } from "./hardened-conductor.ts";
5
+ import { MemoryControlJournal } from "./journal.ts";
6
+ import { replayControlState } from "./hardened-reducer.ts";
7
+ import { ResourceLedger } from "./resource-ledger.ts";
8
+ import type {
9
+ Clock, ControlEventEnvelope, OwnerAuthorizationVerifier, ResourceDefinition,
10
+ UncommittedControlEvent,
11
+ } from "./types.ts";
12
+
13
+ const CREATE_EVENTS_TABLE = `
14
+ CREATE TABLE IF NOT EXISTS _forge_agent_fabric_control_events (
15
+ root_execution_id TEXT NOT NULL,
16
+ event_sequence INTEGER NOT NULL,
17
+ event_id TEXT NOT NULL,
18
+ idempotency_key TEXT,
19
+ envelope_json TEXT NOT NULL,
20
+ PRIMARY KEY (root_execution_id, event_sequence),
21
+ UNIQUE (root_execution_id, event_id),
22
+ UNIQUE (root_execution_id, idempotency_key)
23
+ )`;
24
+
25
+ export interface LocalControlStoreOptions {
26
+ adapter: DbAdapter;
27
+ clock: Clock;
28
+ ownerAuthorizationVerifier: OwnerAuthorizationVerifier;
29
+ resourceDefinitions?: readonly ResourceDefinition[];
30
+ }
31
+
32
+ export interface LocalControlTransitionResult<T> {
33
+ result: T;
34
+ events: readonly ControlEventEnvelope[];
35
+ }
36
+
37
+ /**
38
+ * Single-process PGlite transaction boundary around the synchronous P0a Conductor.
39
+ * Only trusted server code may call transition; callbacks must have no external effects.
40
+ */
41
+ export class LocalControlStore {
42
+ private tail: Promise<void> = Promise.resolve();
43
+ private readonly definitions: readonly ResourceDefinition[];
44
+ private schemaReady?: Promise<unknown>;
45
+ private closed = false;
46
+ private readonly externalRoots = new Set<string>();
47
+ private readonly externalRuns = new Set<Promise<unknown>>();
48
+
49
+ constructor(private readonly options: LocalControlStoreOptions) {
50
+ if (options.adapter.kind !== "pglite") {
51
+ throw new AgentFabricError("AF_INVALID_STATE", "Local control store requires the PGlite adapter");
52
+ }
53
+ this.definitions = structuredClone(options.resourceDefinitions ?? []);
54
+ }
55
+
56
+ private async serialized<T>(operation: () => Promise<T>): Promise<T> {
57
+ if (this.closed) throw new AgentFabricError("AF_INVALID_STATE", "Local control store is closed");
58
+ const predecessor = this.tail;
59
+ let release!: () => void;
60
+ this.tail = new Promise<void>((resolve) => { release = resolve; });
61
+ await predecessor;
62
+ try {
63
+ this.schemaReady ??= this.options.adapter.query(CREATE_EVENTS_TABLE);
64
+ await this.schemaReady;
65
+ return await operation();
66
+ } finally {
67
+ release();
68
+ }
69
+ }
70
+
71
+ private async load(rootExecutionId: string): Promise<ControlEventEnvelope[]> {
72
+ if (!rootExecutionId || rootExecutionId.length > 128) {
73
+ throw new AgentFabricError("AF_INVALID_STATE", "Invalid root execution identity");
74
+ }
75
+ const result = await this.options.adapter.query(
76
+ `SELECT event_sequence, envelope_json FROM _forge_agent_fabric_control_events
77
+ WHERE root_execution_id = $1 ORDER BY event_sequence`,
78
+ [rootExecutionId],
79
+ );
80
+ const events: ControlEventEnvelope[] = [];
81
+ for (const row of result.rows) {
82
+ if (typeof row.envelope_json !== "string") {
83
+ throw new AgentFabricError("AF_INVALID_EVENT", "Stored control envelope is missing");
84
+ }
85
+ let event: ControlEventEnvelope;
86
+ try {
87
+ event = JSON.parse(row.envelope_json) as ControlEventEnvelope;
88
+ } catch {
89
+ throw new AgentFabricError("AF_INVALID_EVENT", "Stored control envelope is not JSON");
90
+ }
91
+ if (!event || typeof event !== "object" ||
92
+ event.rootExecutionId !== rootExecutionId || event.sequence !== row.event_sequence) {
93
+ throw new AgentFabricError("AF_INVALID_EVENT", "Stored control envelope is outside its stream");
94
+ }
95
+ events.push(event);
96
+ }
97
+ replayControlState(events, {
98
+ ownerAuthorizationVerifier: this.options.ownerAuthorizationVerifier,
99
+ resourceDefinitions: this.definitions,
100
+ });
101
+ return events;
102
+ }
103
+
104
+ async readAll(rootExecutionId: string): Promise<readonly ControlEventEnvelope[]> {
105
+ return this.serialized(async () => structuredClone(await this.load(rootExecutionId)));
106
+ }
107
+
108
+ private hydrate(rootExecutionId: string, before: readonly ControlEventEnvelope[]): {
109
+ journal: MemoryControlJournal;
110
+ conductor: ForgeAgentConductor;
111
+ } {
112
+ const journal = new MemoryControlJournal();
113
+ for (const stored of before) {
114
+ const {
115
+ sequence: _sequence,
116
+ predecessorEventId: _predecessorEventId,
117
+ predecessorEventDigest: _predecessorEventDigest,
118
+ eventDigest: _eventDigest,
119
+ ...uncommitted
120
+ } = stored;
121
+ const restored = journal.append({
122
+ expectedSequence: journal.readAll().length,
123
+ event: uncommitted as UncommittedControlEvent,
124
+ });
125
+ if (stableStringify(restored) !== stableStringify(stored)) {
126
+ throw new AgentFabricError("AF_INVALID_EVENT", "Stored control event changed during hydration");
127
+ }
128
+ }
129
+ const ledger = this.definitions.length > 0
130
+ ? new ResourceLedger(this.definitions)
131
+ : undefined;
132
+ return {
133
+ journal,
134
+ conductor: new ForgeAgentConductor(
135
+ rootExecutionId, journal, this.options.clock, sha256Digest,
136
+ this.options.ownerAuthorizationVerifier, ledger,
137
+ ),
138
+ };
139
+ }
140
+
141
+ private async persist(rootExecutionId: string, beforeCount: number, additions: readonly ControlEventEnvelope[]): Promise<void> {
142
+ if (additions.length === 0) return;
143
+ const transaction = await this.options.adapter.begin();
144
+ try {
145
+ const cursor = await transaction.query(
146
+ `SELECT COALESCE(MAX(event_sequence), 0) AS current_sequence
147
+ FROM _forge_agent_fabric_control_events WHERE root_execution_id = $1`,
148
+ [rootExecutionId],
149
+ );
150
+ if (Number(cursor.rows[0]?.current_sequence) !== beforeCount) {
151
+ throw new AgentFabricError("AF_CONFLICT", "Local control journal compare-and-swap failed");
152
+ }
153
+ for (const event of additions) {
154
+ await transaction.query(
155
+ `INSERT INTO _forge_agent_fabric_control_events
156
+ (root_execution_id, event_sequence, event_id, idempotency_key, envelope_json)
157
+ VALUES ($1, $2, $3, $4, $5)`,
158
+ [rootExecutionId, event.sequence, event.eventId, event.idempotencyKey ?? null,
159
+ stableStringify(event)],
160
+ );
161
+ }
162
+ await transaction.commit();
163
+ } catch (error) {
164
+ await transaction.rollback().catch(() => undefined);
165
+ throw error;
166
+ }
167
+ }
168
+
169
+ async transition<T>(
170
+ rootExecutionId: string,
171
+ operation: (conductor: ForgeAgentConductor) => T,
172
+ ): Promise<LocalControlTransitionResult<T>> {
173
+ return this.serialized(async () => {
174
+ if (this.externalRoots.has(rootExecutionId)) {
175
+ throw new AgentFabricError("AF_CONFLICT", "External attempt is still in flight for this root");
176
+ }
177
+ const before = await this.load(rootExecutionId);
178
+ const { journal, conductor } = this.hydrate(rootExecutionId, before);
179
+ const result = operation(conductor);
180
+ if (result && typeof result === "object" && "then" in result) {
181
+ throw new AgentFabricError("AF_INVALID_STATE", "Control transitions must be synchronous");
182
+ }
183
+ const after = journal.readAll();
184
+ const additions = after.slice(before.length);
185
+ await this.persist(rootExecutionId, before.length, additions);
186
+ return { result, events: after };
187
+ });
188
+ }
189
+
190
+ /**
191
+ * Keep one external attempt per root while releasing the database writer
192
+ * lock for the model call. The permit is committed in a prior transition.
193
+ * A crash leaves it without an outcome, which recovery classifies as uncertain.
194
+ */
195
+ async runExternal<T>(
196
+ rootExecutionId: string,
197
+ operation: (conductor: ForgeAgentConductor) => Promise<T>,
198
+ ): Promise<LocalControlTransitionResult<T>> {
199
+ const prepared = await this.serialized(async () => {
200
+ if (this.externalRoots.has(rootExecutionId)) {
201
+ throw new AgentFabricError("AF_CONFLICT", "External attempt is already in flight for this root");
202
+ }
203
+ const before = await this.load(rootExecutionId);
204
+ const { journal, conductor } = this.hydrate(rootExecutionId, before);
205
+ this.externalRoots.add(rootExecutionId);
206
+ return { before, journal, conductor };
207
+ });
208
+ // No database transaction or writer lock remains open around the model call.
209
+ // A status read can therefore see only a committed journal prefix.
210
+ const execution = (async (): Promise<LocalControlTransitionResult<T>> => {
211
+ let result: T | undefined;
212
+ let failure: unknown;
213
+ try {
214
+ result = await operation(prepared.conductor);
215
+ } catch (error) {
216
+ failure = error;
217
+ }
218
+ const after = await this.serialized(async () => {
219
+ const events = prepared.journal.readAll();
220
+ await this.persist(rootExecutionId, prepared.before.length, events.slice(prepared.before.length));
221
+ return events;
222
+ });
223
+ if (failure !== undefined) throw failure;
224
+ return { result: result as T, events: after };
225
+ })();
226
+ this.externalRuns.add(execution);
227
+ try { return await execution; } finally {
228
+ this.externalRuns.delete(execution);
229
+ this.externalRoots.delete(rootExecutionId);
230
+ }
231
+ }
232
+
233
+ async close(): Promise<void> {
234
+ await Promise.allSettled([...this.externalRuns]);
235
+ this.closed = true;
236
+ await this.tail;
237
+ await this.options.adapter.close();
238
+ }
239
+ }