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
@@ -13,7 +13,13 @@ export type ForgeKind =
13
13
  | "workflow"
14
14
  | "agent"
15
15
  | "aiTool"
16
- | "telemetryEvent";
16
+ | "telemetryEvent"
17
+ | "code.function"
18
+ | "code.class"
19
+ | "code.interface"
20
+ | "code.type"
21
+ | "code.const"
22
+ | "code.enum";
17
23
 
18
24
  export interface ForgeSymbol {
19
25
  id: string;
@@ -26,7 +32,7 @@ export interface ForgeSymbol {
26
32
  meta: Record<string, JsonValue>;
27
33
  }
28
34
 
29
- export type ForgeEdgeKind = "references" | "registers" | "guards" | "emits";
35
+ export type ForgeEdgeKind = "references" | "registers" | "guards" | "emits" | "imports";
30
36
 
31
37
  export interface ForgeEdge {
32
38
  from: string;
@@ -25,6 +25,24 @@ export interface GenerateResult {
25
25
 
26
26
  export interface ForgeAddResult extends GenerateResult {
27
27
  alias?: string;
28
+ mode?: "integration" | "package";
29
+ targetKind?: "forge-integration" | "npm-package";
30
+ target?: string;
31
+ packageTarget?: "root" | "frontend" | "backend" | "workspace";
32
+ packageTargetReason?: string;
33
+ explanation?: string;
34
+ recipeVersion?: string;
35
+ recipePackages?: string[];
36
+ requiredSecrets?: string[];
37
+ optionalSecrets?: string[];
38
+ packageSpec?: string;
39
+ packageName?: string;
40
+ packageManager?: string;
41
+ installCommand?: string[];
42
+ nativeInstallCommand?: string[];
43
+ avoidedManualCommand?: string;
44
+ installCwd?: string;
45
+ installWorkspace?: string;
28
46
  }
29
47
 
30
48
  export interface InspectResult {
@@ -45,6 +63,10 @@ export interface AddOptions extends CliCommonOptions {
45
63
  runtimeInspect: boolean;
46
64
  sandboxBackend: SandboxBackend;
47
65
  allowScripts: boolean;
66
+ withFga?: boolean;
67
+ mode?: "auto" | "integration" | "package";
68
+ installWorkspace?: string;
69
+ packageTarget?: "frontend" | "backend";
48
70
  }
49
71
 
50
72
  export type InspectTarget =
@@ -64,6 +86,7 @@ export type InspectTarget =
64
86
  | "ai"
65
87
  | "queries"
66
88
  | "api"
89
+ | "external"
67
90
  | "client"
68
91
  | "frontend"
69
92
  | "auth"
@@ -82,7 +105,12 @@ export type InspectTarget =
82
105
  | "agent-tools"
83
106
  | "agent-adapters"
84
107
  | "capability-map"
108
+ | "summary"
109
+ | "schema"
110
+ | "drift"
111
+ | "handoff"
85
112
  | "framework"
113
+ | "imported"
86
114
  | "ui"
87
115
  | "ui-scenarios"
88
116
  | "ui-routes"
@@ -105,6 +133,7 @@ export interface RunResult {
105
133
  export interface PmAddOptions {
106
134
  ignoreScripts: boolean;
107
135
  cwd: string;
136
+ workspace?: string;
108
137
  }
109
138
 
110
139
  export interface PmAddResult {
@@ -146,15 +175,61 @@ export interface VerifyOptions {
146
175
  smoke?: boolean;
147
176
  standard?: boolean;
148
177
  scriptTimeoutMs?: number;
178
+ testJobs?: number;
179
+ typechecker?: "tsc" | "native" | "ts7" | "tsgo" | "auto";
180
+ fullTests?: boolean;
181
+ testPlan?: boolean;
182
+ internal?: boolean;
149
183
  }
150
184
 
151
- export type VerifyProfile = "default" | "smoke" | "standard" | "strict" | "changed";
185
+ export type VerifyProfile = "default" | "smoke" | "standard" | "strict" | "changed" | "internal";
186
+
187
+ export type VerifyTestGraphLane = "parallel" | "isolated" | "serial";
188
+ export type VerifyTestGraphLaneMode = "overlap" | "sequential";
189
+
190
+ export type VerifyTestGraphDurationSource = "profile" | "fallback";
191
+
192
+ export interface VerifyTestGraphPlanChunk {
193
+ index: number;
194
+ lane: VerifyTestGraphLane;
195
+ files: string[];
196
+ estimatedMs: number;
197
+ durationSource: VerifyTestGraphDurationSource;
198
+ }
199
+
200
+ export interface VerifyTestGraphPlan {
201
+ schemaVersion: "0.1.0";
202
+ fileCount: number;
203
+ chunkCount: number;
204
+ totalJobs: number;
205
+ laneMode: VerifyTestGraphLaneMode;
206
+ jobs: number;
207
+ isolatedJobs: number;
208
+ lanes: Record<VerifyTestGraphLane, {
209
+ fileCount: number;
210
+ chunkCount: number;
211
+ estimatedMs: number;
212
+ }>;
213
+ chunks: VerifyTestGraphPlanChunk[];
214
+ criticalPathEstimateMs: number;
215
+ profilePath: string;
216
+ profileFound: boolean;
217
+ slowestFiles: Array<{
218
+ file: string;
219
+ lane: VerifyTestGraphLane;
220
+ estimatedMs: number;
221
+ source: VerifyTestGraphDurationSource;
222
+ }>;
223
+ recommendations: string[];
224
+ }
152
225
 
153
226
  export interface VerifyResult {
154
227
  ok: boolean;
155
228
  profile?: VerifyProfile;
156
229
  steps: VerifyStep[];
157
230
  diagnostics: Diagnostic[];
231
+ testGraphPlan?: VerifyTestGraphPlan;
232
+ testCoverageReason?: string;
158
233
  durationMs?: number;
159
234
  exitCode: 0 | 1;
160
235
  }
@@ -14,6 +14,10 @@ export interface DevRoute {
14
14
  | "ai-agent-chat"
15
15
  | "ai-agent-run"
16
16
  | "ai-providers"
17
+ | "auth"
18
+ | "auth-md"
19
+ | "auth-metadata"
20
+ | "webhook"
17
21
  | "queries"
18
22
  | "query";
19
23
  entryName?: string;
@@ -7,6 +7,8 @@ export interface EmitFile {
7
7
  contentHash: string;
8
8
  /** Skip JSON canonicalization round-trip when content is already canonical. */
9
9
  canonical?: boolean;
10
+ /** Skip the Forge deterministic header for files whose syntax does not allow // comments. */
11
+ header?: "deterministic" | "none";
10
12
  }
11
13
 
12
14
  export interface EmitPlan {
@@ -31,7 +31,7 @@ export interface FrontendProviderInfo {
31
31
 
32
32
  export interface FrontendWebManifest {
33
33
  present: boolean;
34
- framework: "next" | "vite" | "static" | "unknown" | "none";
34
+ framework: "next" | "nuxt" | "vite" | "static" | "unknown" | "none";
35
35
  root?: string;
36
36
  packageManager?: "bun" | "npm" | "pnpm" | "yarn" | "unknown";
37
37
  scripts: {
@@ -63,7 +63,7 @@ export interface FrontendClientBindingInfo {
63
63
  export interface FrontendGraph {
64
64
  schemaVersion: "0.1.0";
65
65
  present: boolean;
66
- framework: "next" | "vite" | "static" | "unknown" | "none";
66
+ framework: "next" | "nuxt" | "vite" | "static" | "unknown" | "none";
67
67
  root?: string;
68
68
  dev?: {
69
69
  command: string;
@@ -18,6 +18,7 @@ export interface IntegrationRecipe {
18
18
  secrets: SecretRequirement[];
19
19
  adapters: string[];
20
20
  integrations?: string[];
21
+ rootFiles?: string[];
21
22
  testkits: string[];
22
23
  docs: string[];
23
24
  frameworkTarget?: string;
@@ -92,7 +92,13 @@ export interface Entrypoint {
92
92
  }
93
93
 
94
94
  export interface PackageApi {
95
+ /**
96
+ * Import/dependency name used by the app, which may be an npm alias such as
97
+ * "forge" for "npm:forgeos@...".
98
+ */
95
99
  name: string;
100
+ /** Real package.json name when it differs from the dependency/import name. */
101
+ packageName?: string;
96
102
  version: string;
97
103
  packageManager: PackageManager;
98
104
  resolutionMode: ResolutionMode;
@@ -2,8 +2,9 @@ import type { Diagnostic } from "./diagnostic.ts";
2
2
 
3
3
  export interface PolicyRule {
4
4
  name: string;
5
- kind: "roles" | "public" | "system";
5
+ kind: "roles" | "permissions" | "public" | "system";
6
6
  roles: string[];
7
+ permissions: string[];
7
8
  file: string;
8
9
  symbolId: string;
9
10
  }
@@ -33,6 +34,7 @@ export interface QueryAuthBinding {
33
34
  export interface PermissionMatrixEntry {
34
35
  policy: string;
35
36
  roles: string[];
37
+ permissions: string[];
36
38
  }
37
39
 
38
40
  export interface TenantScopeEntry {
@@ -0,0 +1,5 @@
1
+ import { register } from "tsx/esm/api";
2
+
3
+ register();
4
+ const { runDeltaBroker } = await import("./broker.ts");
5
+ await runDeltaBroker(process.argv[2]);
@@ -0,0 +1,429 @@
1
+ import { createHash, randomBytes, timingSafeEqual } from "node:crypto";
2
+ import { spawn } from "node:child_process";
3
+ import { existsSync, lstatSync, mkdirSync, readFileSync, realpathSync, statSync, unlinkSync, writeFileSync, chmodSync } from "node:fs";
4
+ import { createServer, connect, type Server, type Socket } from "node:net";
5
+ import { dirname, join } from "node:path";
6
+ import { tmpdir } from "node:os";
7
+ import { fileURLToPath } from "node:url";
8
+ import { DeltaStoreBusyError, type DeltaStore } from "./store.ts";
9
+ import { inspectDeltaAgentQueue } from "./queue-status.ts";
10
+ import { pidWasReused } from "./process-identity.ts";
11
+
12
+ const START_TIMEOUT_MS = 15_000;
13
+ const REQUEST_TIMEOUT_MS = 30_000;
14
+ const MAX_MESSAGE_BYTES = 8 * 1024 * 1024;
15
+ const IDLE_MS = 120_000;
16
+ const ENDPOINT_NAME = "broker-endpoint.json";
17
+
18
+ export const DELTA_BROKER_METHODS = new Set([
19
+ "init", "ensureActor", "createSession", "endSession", "appendOperation", "recordAgentMemoryEvent",
20
+ "listAgentMemoryEvents", "status", "statusDetails", "timeline", "semanticTimeline",
21
+ "rebuildSemanticTimeline", "explain", "recordFilePath", "currentWorkSession", "listWorkSessions",
22
+ "getWorkSessionDetails", "renameWorkSession", "detachWorkSessionOperation", "mergeWorkSessions",
23
+ "splitWorkSession",
24
+ ]);
25
+
26
+ interface BrokerEndpoint {
27
+ version: 1;
28
+ root: string;
29
+ pid: number;
30
+ createdAt: string;
31
+ pipe: string;
32
+ token: string;
33
+ }
34
+
35
+ interface BrokerResponse {
36
+ ok: boolean;
37
+ value?: unknown;
38
+ isUndefined?: boolean;
39
+ error?: { name: string; message: string; code?: string; stack?: string; lockPath?: string; holder?: Record<string, unknown> | null };
40
+ }
41
+
42
+ function endpointPath(root: string): string { return join(root, ".forge", "delta", ENDPOINT_NAME); }
43
+ function failurePath(root: string, pid: number): string { return join(root, ".forge", "delta", `broker-start-${pid}.json`); }
44
+ function pipePath(root: string): string {
45
+ const id = createHash("sha256").update(root).digest("hex").slice(0, 24);
46
+ return process.platform === "win32" ? `\\\\.\\pipe\\forge-delta-${id}` : join(tmpdir(), `forge-delta-${process.getuid?.() ?? "user"}-${id}.sock`);
47
+ }
48
+ function alive(pid: number): boolean {
49
+ try { process.kill(pid, 0); return true; } catch (error) { return (error as NodeJS.ErrnoException).code === "EPERM"; }
50
+ }
51
+ function unlinkUnchanged(path: string, bytes: Buffer): void {
52
+ try { if (readFileSync(path).equals(bytes)) unlinkSync(path); } catch { /* replacement or already gone */ }
53
+ }
54
+ function readEndpoint(root: string): BrokerEndpoint | null {
55
+ const path = endpointPath(root);
56
+ let bytes: Buffer;
57
+ try {
58
+ if (lstatSync(path).isSymbolicLink()) throw new Error("Delta broker endpoint must not be a symbolic link");
59
+ bytes = readFileSync(path);
60
+ } catch (error) {
61
+ if ((error as NodeJS.ErrnoException).code === "ENOENT") return null;
62
+ throw error;
63
+ }
64
+ if (bytes.length > 2048) throw new Error("Delta broker endpoint is oversized");
65
+ let value: Partial<BrokerEndpoint>;
66
+ try { value = JSON.parse(bytes.toString("utf8")) as Partial<BrokerEndpoint>; }
67
+ catch { throw new Error("Delta broker endpoint is invalid JSON"); }
68
+ if (value.version !== 1 || value.root !== root || !Number.isSafeInteger(value.pid) ||
69
+ (value.pid ?? 0) <= 0 || value.pipe !== pipePath(root) ||
70
+ typeof value.createdAt !== "string" || !Number.isFinite(Date.parse(value.createdAt)) ||
71
+ typeof value.token !== "string" || !/^[0-9a-f]{64}$/u.test(value.token)) {
72
+ throw new Error("Delta broker endpoint is inconsistent");
73
+ }
74
+ if (!alive(value.pid!)) {
75
+ unlinkUnchanged(path, bytes); return null;
76
+ }
77
+ if (process.platform !== "win32" && (statSync(path).mode & 0o077) !== 0) {
78
+ throw new Error("Delta broker endpoint permissions are too broad");
79
+ }
80
+ return value as BrokerEndpoint;
81
+ }
82
+ function serializeError(error: unknown): NonNullable<BrokerResponse["error"]> {
83
+ const item = error instanceof Error ? error : new Error(String(error));
84
+ const code = "code" in item && typeof item.code === "string" ? item.code : undefined;
85
+ return {
86
+ name: item.name, message: item.message, ...(code ? { code } : {}), ...(item.stack ? { stack: item.stack } : {}),
87
+ ...(item instanceof DeltaStoreBusyError ? { lockPath: item.lockPath, holder: item.holder } : {}),
88
+ };
89
+ }
90
+ function reviveError(error: NonNullable<BrokerResponse["error"]> | undefined): Error {
91
+ const revived = error?.code === "FORGE_DELTA_BUSY" && error.lockPath
92
+ ? new DeltaStoreBusyError(error.lockPath, error.holder ?? null)
93
+ : new Error(error?.message ?? "Delta broker request failed");
94
+ revived.name = error?.name ?? "DeltaBrokerError";
95
+ if (error?.code) Object.assign(revived, { code: error.code });
96
+ if (error?.stack) revived.stack = error.stack;
97
+ return revived;
98
+ }
99
+
100
+ async function send(endpoint: BrokerEndpoint, method: string, args: unknown[], timeoutMs = REQUEST_TIMEOUT_MS): Promise<unknown> {
101
+ return new Promise((resolve, reject) => {
102
+ const socket = connect(endpoint.pipe);
103
+ const chunks: Buffer[] = [];
104
+ let size = 0;
105
+ let settled = false;
106
+ const finish = (error?: Error, value?: unknown) => {
107
+ if (settled) return;
108
+ settled = true;
109
+ socket.destroy();
110
+ if (error) reject(error); else resolve(value);
111
+ };
112
+ socket.setTimeout(timeoutMs, () => finish(new Error(`Delta broker ${method} timed out after ${timeoutMs} ms`)));
113
+ socket.once("error", (error) => finish(error));
114
+ socket.once("close", () => finish(new Error(`Delta broker closed ${method} without a response`)));
115
+ socket.on("data", (chunk: Buffer) => {
116
+ chunks.push(chunk);
117
+ size += chunk.length;
118
+ if (size > MAX_MESSAGE_BYTES) { finish(new Error("Delta broker response exceeded limit")); return; }
119
+ const data = Buffer.concat(chunks);
120
+ const newline = data.indexOf(10);
121
+ if (newline < 0) return;
122
+ try {
123
+ const result = JSON.parse(data.subarray(0, newline).toString("utf8")) as BrokerResponse;
124
+ if (!result.ok) finish(reviveError(result.error));
125
+ else finish(undefined, result.isUndefined ? undefined : result.value);
126
+ } catch (error) { finish(error instanceof Error ? error : new Error(String(error))); }
127
+ });
128
+ socket.once("connect", () => {
129
+ socket.write(`${JSON.stringify({ token: endpoint.token, method, args })}\n`);
130
+ });
131
+ });
132
+ }
133
+
134
+ let starting = new Map<string, Promise<BrokerEndpoint>>();
135
+ export async function ensureDeltaBroker(workspaceRoot: string): Promise<BrokerEndpoint> {
136
+ const root = realpathSync(workspaceRoot);
137
+ const existing = starting.get(root);
138
+ if (existing) return existing;
139
+ const task = (async () => {
140
+ let endpoint = readEndpoint(root);
141
+ if (endpoint) {
142
+ const former = endpoint;
143
+ try { await send(former, "ping", [], 1_500); return former; }
144
+ catch (error) {
145
+ if (pidWasReused(former.pid, former.createdAt)) {
146
+ const path = endpointPath(root);
147
+ if (existsSync(path)) {
148
+ const bytes = readFileSync(path);
149
+ try {
150
+ const current = JSON.parse(bytes.toString("utf8")) as Partial<BrokerEndpoint>;
151
+ if (current.pid === former.pid && current.token === former.token) unlinkUnchanged(path, bytes);
152
+ } catch { /* invalid endpoint is reported by the next read */ }
153
+ }
154
+ endpoint = null;
155
+ }
156
+ await new Promise((resolve) => setTimeout(resolve, 100));
157
+ const current = readEndpoint(root);
158
+ if (current?.pid === former.pid && current.token === former.token && alive(former.pid)) {
159
+ throw new Error(`Delta broker pid ${former.pid} is unresponsive`, { cause: error });
160
+ }
161
+ }
162
+ }
163
+ const runner = fileURLToPath(new URL("./broker-runner.mjs", import.meta.url));
164
+ const runningTest = process.env.NODE_ENV === "test" || process.argv.some((arg) => /\.test\.[cm]?[jt]sx?$/u.test(arg));
165
+ const child = spawn(process.execPath, [runner, root], {
166
+ // Windows cannot remove a workspace while a child keeps it as cwd.
167
+ cwd: dirname(runner), detached: true, windowsHide: true, stdio: "ignore",
168
+ env: {
169
+ ...process.env,
170
+ FORGE_DELTA_BACKGROUND_DRAIN: process.env.FORGE_DELTA_BACKGROUND_DRAIN ?? (runningTest ? "0" : "1"),
171
+ },
172
+ });
173
+ let childExited = false;
174
+ let spawnError: Error | undefined;
175
+ child.once("exit", () => { childExited = true; });
176
+ child.once("error", (error) => { spawnError = error; childExited = true; });
177
+ child.unref();
178
+ const started = Date.now();
179
+ for (;;) {
180
+ endpoint = readEndpoint(root);
181
+ if (endpoint) {
182
+ try { await send(endpoint, "ping", [], 1_500); return endpoint; }
183
+ catch { /* owner may still be publishing */ }
184
+ }
185
+ if (childExited) break;
186
+ if (Date.now() - started >= START_TIMEOUT_MS) break;
187
+ await new Promise((resolve) => setTimeout(resolve, 100));
188
+ }
189
+ const path = child.pid ? failurePath(root, child.pid) : undefined;
190
+ if (path && existsSync(path)) {
191
+ const result = JSON.parse(readFileSync(path, "utf8")) as NonNullable<BrokerResponse["error"]>;
192
+ unlinkSync(path);
193
+ throw reviveError(result);
194
+ }
195
+ if (spawnError) throw spawnError;
196
+ throw new Error("Delta broker did not become ready within 15 seconds");
197
+ })();
198
+ starting.set(root, task);
199
+ try { return await task; } finally { starting.delete(root); }
200
+ }
201
+
202
+ export async function requestDeltaBroker(workspaceRoot: string, method: string, args: unknown[]): Promise<unknown> {
203
+ if (!DELTA_BROKER_METHODS.has(method) && method !== "openHandle" && method !== "closeHandle" && method !== "stop") {
204
+ throw new Error(`Delta broker method is unavailable: ${method}`);
205
+ }
206
+ const root = realpathSync(workspaceRoot);
207
+ const endpoint = await ensureDeltaBroker(root);
208
+ // A timed-out write may already have committed. Never replay it automatically.
209
+ return send(endpoint, method, args);
210
+ }
211
+
212
+ /** Stop this workspace's verified owner and release its PGlite files. */
213
+ export async function shutdownDeltaBroker(workspaceRoot: string): Promise<void> {
214
+ const root = realpathSync(workspaceRoot);
215
+ const endpoint = readEndpoint(root);
216
+ if (!endpoint) return;
217
+ await send(endpoint, "stop", [], 10_000);
218
+ }
219
+
220
+ export async function probeDeltaBroker(workspaceRoot: string): Promise<{ active: boolean; pid?: number; error?: string }> {
221
+ const root = realpathSync(workspaceRoot);
222
+ let endpoint: BrokerEndpoint | null;
223
+ try { endpoint = readEndpoint(root); }
224
+ catch (error) { return { active: false, error: error instanceof Error ? error.message : String(error) }; }
225
+ if (!endpoint) return { active: false };
226
+ try { await send(endpoint, "ping", [], 1_500); return { active: true, pid: endpoint.pid }; }
227
+ catch (error) { return { active: false, pid: endpoint.pid, error: error instanceof Error ? error.message : String(error) }; }
228
+ }
229
+
230
+ export async function runDeltaBroker(workspaceRoot: string | undefined): Promise<void> {
231
+ if (!workspaceRoot) throw new Error("Delta broker requires a workspace root");
232
+ const root = realpathSync(workspaceRoot);
233
+ const pipe = pipePath(root);
234
+ const path = endpointPath(root);
235
+ let store: DeltaStore | undefined;
236
+ let server: Server | undefined;
237
+ const sockets = new Set<Socket>();
238
+ let published: BrokerEndpoint | undefined;
239
+ let lastActivity = Date.now();
240
+ let pending = 0;
241
+ const handles = new Set<string>();
242
+ let closing = false;
243
+ const backgroundDrain = process.env.FORGE_DELTA_BACKGROUND_DRAIN !== "0";
244
+ let queuePendingBytes = backgroundDrain ? (inspectDeltaAgentQueue(root).pendingBytes ?? 1) : 0;
245
+ let serial = Promise.resolve();
246
+ try {
247
+ const { DeltaStore, markDeltaBrokerOwnerProcess } = await import("./store.ts");
248
+ markDeltaBrokerOwnerProcess();
249
+ store = await DeltaStore.open(root, { waitMs: 10_000, retryDelayMs: 100 });
250
+ const oldEndpoint = readEndpoint(root);
251
+ if (oldEndpoint) {
252
+ try {
253
+ if (await send(oldEndpoint, "ping", [], 1_500) === true) {
254
+ throw new Error("A Delta broker owner already answers for this workspace");
255
+ }
256
+ } catch (error) {
257
+ if (!pidWasReused(oldEndpoint.pid, oldEndpoint.createdAt)) throw error;
258
+ const bytes = readFileSync(path);
259
+ const current = JSON.parse(bytes.toString("utf8")) as Partial<BrokerEndpoint>;
260
+ if (current.pid === oldEndpoint.pid && current.token === oldEndpoint.token) unlinkUnchanged(path, bytes);
261
+ }
262
+ }
263
+ if (process.platform !== "win32" && existsSync(pipe)) {
264
+ const existing = readEndpoint(root);
265
+ if (existing) throw new Error("Delta broker pipe is owned by another process");
266
+ unlinkSync(pipe);
267
+ }
268
+ const token = randomBytes(32).toString("hex");
269
+ published = { version: 1, root, pid: process.pid, createdAt: new Date().toISOString(), pipe, token };
270
+ const equalToken = (value: unknown): boolean => typeof value === "string" && value.length === token.length &&
271
+ timingSafeEqual(Buffer.from(value), Buffer.from(token));
272
+ server = createServer((socket) => {
273
+ sockets.add(socket);
274
+ socket.once("close", () => sockets.delete(socket));
275
+ // A caller can time out after its request was accepted. A deferred
276
+ // response may then raise EPIPE; the sole PGlite owner must survive.
277
+ socket.on("error", () => { /* disconnected caller handles its own timeout */ });
278
+ const chunks: Buffer[] = [];
279
+ let size = 0;
280
+ socket.setTimeout(REQUEST_TIMEOUT_MS + 5_000, () => socket.destroy());
281
+ socket.on("data", (chunk: Buffer) => {
282
+ chunks.push(chunk);
283
+ size += chunk.length;
284
+ if (size > MAX_MESSAGE_BYTES) { socket.destroy(); return; }
285
+ const body = Buffer.concat(chunks);
286
+ const newline = body.indexOf(10);
287
+ if (newline < 0) return;
288
+ socket.removeAllListeners("data");
289
+ let request: { token?: unknown; method?: unknown; args?: unknown };
290
+ try { request = JSON.parse(body.subarray(0, newline).toString("utf8")) as typeof request; }
291
+ catch { socket.end(`${JSON.stringify({ ok: false, error: { name: "Error", message: "Invalid Delta broker JSON" } })}\n`); return; }
292
+ if (!equalToken(request.token) || typeof request.method !== "string" ||
293
+ (request.method !== "ping" && request.method !== "wake" && request.method !== "openHandle" && request.method !== "closeHandle" &&
294
+ request.method !== "stop" &&
295
+ !DELTA_BROKER_METHODS.has(request.method)) || !Array.isArray(request.args)) {
296
+ socket.end(`${JSON.stringify({ ok: false, error: { name: "Error", message: "Unauthorized Delta broker request" } })}\n`);
297
+ return;
298
+ }
299
+ lastActivity = Date.now();
300
+ // Health and wake signals do not touch PGlite. A large queue replay
301
+ // must not make a healthy owner fail its short liveness probe.
302
+ if (request.method === "ping" || request.method === "wake") {
303
+ if (closing) {
304
+ socket.end(`${JSON.stringify({ ok: false, error: { name: "Error", message: "Delta broker is closing" } })}\n`);
305
+ } else {
306
+ if (request.method === "wake") {
307
+ queuePendingBytes = 1;
308
+ setImmediate(drainQueue);
309
+ }
310
+ socket.end(`${JSON.stringify({ ok: true, value: true })}\n`);
311
+ }
312
+ return;
313
+ }
314
+ pending += 1;
315
+ const method = request.method;
316
+ const args = request.args;
317
+ const work = serial.then(async () => {
318
+ if (closing) throw new Error("Delta broker is closing");
319
+ if (method === "stop") {
320
+ closing = true;
321
+ await store!.close();
322
+ if (published && existsSync(path)) unlinkUnchanged(path, Buffer.from(JSON.stringify(published)));
323
+ setImmediate(() => { shutdownAndExit(); });
324
+ return true;
325
+ }
326
+ if (method === "openHandle") {
327
+ if (typeof args[0] !== "string" || !/^[0-9a-f-]{36}$/u.test(args[0])) throw new Error("Invalid Delta handle ID");
328
+ handles.add(args[0]);
329
+ return true;
330
+ }
331
+ if (method === "closeHandle") {
332
+ if (typeof args[0] !== "string" || !/^[0-9a-f-]{36}$/u.test(args[0])) throw new Error("Invalid Delta handle ID");
333
+ handles.delete(args[0]);
334
+ if (handles.size === 0 && queuePendingBytes === 0 && pending === 1) {
335
+ closing = true;
336
+ await store!.close();
337
+ if (published && existsSync(path)) unlinkUnchanged(path, Buffer.from(JSON.stringify(published)));
338
+ setImmediate(() => { shutdownAndExit(); });
339
+ }
340
+ return true;
341
+ }
342
+ return (store as unknown as Record<string, (...values: unknown[]) => Promise<unknown>>)[method](...args);
343
+ });
344
+ serial = work.then(() => undefined, () => undefined);
345
+ void work.then((value) => {
346
+ if (!socket.destroyed) socket.end(`${JSON.stringify({ ok: true, value: value ?? null, isUndefined: value === undefined })}\n`);
347
+ }, (error) => {
348
+ if (!socket.destroyed) socket.end(`${JSON.stringify({ ok: false, error: serializeError(error) })}\n`);
349
+ }).finally(() => { pending -= 1; lastActivity = Date.now(); });
350
+ });
351
+ });
352
+ await new Promise<void>((resolve, reject) => { server!.once("error", reject); server!.listen(pipe, resolve); });
353
+ if (process.platform !== "win32") chmodSync(pipe, 0o600);
354
+ mkdirSync(dirname(path), { recursive: true });
355
+ writeFileSync(path, JSON.stringify(published), { flag: "wx", mode: 0o600 });
356
+ let drainScheduled = false;
357
+ const drainQueue = () => {
358
+ if (!backgroundDrain || drainScheduled || closing) return;
359
+ drainScheduled = true;
360
+ const work = serial.then(async () => {
361
+ const { drainAgentMemoryQueueFile } = await import("../agent-memory/bridge.ts");
362
+ return drainAgentMemoryQueueFile({
363
+ workspaceRoot: root,
364
+ watchFile: join(root, ".forge", "agent", "events.ndjson"),
365
+ source: "codex", maxEvents: 32, maxDurationMs: 500, store: store!,
366
+ });
367
+ });
368
+ serial = work.then(() => undefined, () => undefined);
369
+ void work.then((result) => {
370
+ queuePendingBytes = result.pendingBytes;
371
+ if (result.eventsIngested > 0) lastActivity = Date.now();
372
+ if (result.pendingBytes > 0 && result.eventsIngested > 0) setTimeout(drainQueue, 25);
373
+ }, () => { queuePendingBytes = 1; }).finally(() => { drainScheduled = false; });
374
+ };
375
+ const drainTimer = backgroundDrain ? setInterval(drainQueue, 2_000) : undefined;
376
+ if (backgroundDrain) setTimeout(drainQueue, 0);
377
+ const timer = setInterval(() => {
378
+ if (pending !== 0 || queuePendingBytes !== 0 || Date.now() - lastActivity <= IDLE_MS) return;
379
+ // The hook can append between periodic drains. Recheck the durable queue
380
+ // before dropping its last local owner; an authenticated wake races
381
+ // safely with closing and starts a replacement owner if rejected.
382
+ queuePendingBytes = inspectDeltaAgentQueue(root).pendingBytes ?? 1;
383
+ if (queuePendingBytes === 0) shutdownAndExit();
384
+ else drainQueue();
385
+ }, 10_000);
386
+ let shutdownTask: Promise<void> | undefined;
387
+ const shutdown = (): Promise<void> => {
388
+ if (shutdownTask) return shutdownTask;
389
+ shutdownTask = (async () => {
390
+ clearInterval(timer);
391
+ if (drainTimer) clearInterval(drainTimer);
392
+ await serial;
393
+ await store!.close();
394
+ if (published && existsSync(path)) unlinkUnchanged(path, Buffer.from(JSON.stringify(published)));
395
+ if (server!.listening) {
396
+ const closed = new Promise<void>((resolve) => server!.close(() => resolve()));
397
+ // Some Bun/Windows clients retain a half-open pipe after reading the
398
+ // response. The owner has already released PGlite, so bound shutdown.
399
+ const force = setTimeout(() => { for (const socket of sockets) socket.destroy(); }, 100);
400
+ await Promise.race([closed, new Promise<void>((resolve) => setTimeout(resolve, 2_000))]);
401
+ clearTimeout(force);
402
+ for (const socket of sockets) socket.destroy();
403
+ }
404
+ if (process.platform !== "win32" && existsSync(pipe)) unlinkSync(pipe);
405
+ })();
406
+ return shutdownTask;
407
+ };
408
+ let exiting = false;
409
+ const shutdownAndExit = (): void => {
410
+ if (exiting) return;
411
+ exiting = true;
412
+ void shutdown().then(() => process.exit(0), () => process.exit(1));
413
+ };
414
+ process.once("SIGTERM", shutdownAndExit);
415
+ process.once("SIGINT", shutdownAndExit);
416
+ } catch (error) {
417
+ if (server?.listening) await new Promise<void>((resolve) => server!.close(() => resolve()));
418
+ await store?.close().catch(() => undefined);
419
+ // Concurrent hook and CLI wakeups can launch two candidates. The process
420
+ // that loses the physical store lock exits quietly once a real owner answers.
421
+ try {
422
+ const other = readEndpoint(root);
423
+ if (other && other.pid !== process.pid && await send(other, "ping", [], 1_500) === true) return;
424
+ } catch { /* preserve the original startup failure below */ }
425
+ const failure = failurePath(root, process.pid);
426
+ try { writeFileSync(failure, JSON.stringify(serializeError(error)), { mode: 0o600 }); } catch { /* diagnostic is best effort */ }
427
+ throw error;
428
+ }
429
+ }