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
@@ -1,14 +1,23 @@
1
1
  import { nodeFileSystem } from "../compiler/fs/index.ts";
2
- import { join } from "node:path";
2
+ import { spawnSync } from "node:child_process";
3
+ import { join, resolve } from "node:path";
3
4
  import { stripDeterministicHeader } from "../compiler/primitives/header.ts";
4
5
  import { classify } from "../compiler/classifier/classify.ts";
5
6
  import { buildRuntimeMatrix } from "../compiler/classifier/runtime-matrix.ts";
7
+ import {
8
+ FORGE_DB_EMPTY_TIMESTAMP_LITERAL,
9
+ FORGE_RELEASE_NPM_DIST_TAG_CHECK_FAILED,
10
+ FORGE_RELEASE_NPM_DIST_TAG_STALE,
11
+ FORGE_RELEASE_PACKAGE_PACK_FAILED,
12
+ } from "../compiler/diagnostics/codes.ts";
6
13
  import { createDiagnostic } from "../compiler/diagnostics/create.ts";
7
14
  import { forgeAdd } from "../compiler/integration/add.ts";
8
15
  import { checkImportGuards } from "../compiler/guards/check-import-guards.ts";
9
16
  import { checkDirectProcessEnvUsage } from "../compiler/guards/check-process-env.ts";
10
17
  import { checkAiUsageInApp } from "../compiler/guards/check-ai-usage.ts";
11
18
  import { checkQueryUsageInApp } from "../compiler/guards/check-query-usage.ts";
19
+ import { buildDataGraph } from "../compiler/data-graph/build.ts";
20
+ import { buildSqlPlan } from "../compiler/data-graph/sql/ddl.ts";
12
21
  import { loadSecretRegistry } from "../runtime/secrets/check.ts";
13
22
  import { run } from "../compiler/orchestrator/run.ts";
14
23
  import {
@@ -29,10 +38,14 @@ import type {
29
38
  } from "../compiler/types/cli.ts";
30
39
  import type { RuntimeMatrix } from "../compiler/types/runtime-matrix.ts";
31
40
  import type { FrontendGraph } from "../compiler/types/frontend-graph.ts";
41
+ import type { DataGraph } from "../compiler/types/data-graph.ts";
42
+ import type { SqlPlan } from "../compiler/data-graph/sql/types.ts";
43
+ import type { TableMapEntry } from "../compiler/data-graph/sql/serialize.ts";
32
44
  import { GENERATED_DIR } from "../compiler/emitter/constants.ts";
33
45
  import {
34
46
  attachFailureKind,
35
47
  buildAddJson,
48
+ buildCheckJson,
36
49
  buildGenerateJson,
37
50
  buildInspectJson,
38
51
  formatJsonResult,
@@ -44,6 +57,28 @@ import {
44
57
  } from "./output.ts";
45
58
  import { INSPECT_TARGETS, TOP_LEVEL_COMMANDS, type ForgeCommand } from "./parse.ts";
46
59
  import { runVerifyCommand } from "./verify.ts";
60
+ import {
61
+ buildExternalServiceGraph,
62
+ importExternalManifest,
63
+ readExternalManifestFile,
64
+ } from "../compiler/external-manifest/registry.ts";
65
+ import {
66
+ resolveExternalQualifiedName,
67
+ runExternalEntry,
68
+ } from "../runtime/external/bridge.ts";
69
+ import {
70
+ formatCompilerBenchHuman,
71
+ formatCompilerBenchJson,
72
+ runCompilerBenchCommand,
73
+ } from "../bench.ts";
74
+ import {
75
+ formatCairHuman,
76
+ formatCairJson,
77
+ runCairCommand,
78
+ } from "../cair/index.ts";
79
+ import { runRepositoryCommand } from "./repository.ts";
80
+ import { readRepositoryManifest, resolveRepositoryRoot } from "../repository-manifest/index.ts";
81
+ import { uniqueNextActions } from "./next-actions.ts";
47
82
  import {
48
83
  formatRunJson,
49
84
  formatRunListHuman,
@@ -51,6 +86,41 @@ import {
51
86
  runRunCommand,
52
87
  } from "./run.ts";
53
88
  import { runDevCommand } from "./dev.ts";
89
+ import {
90
+ formatHandoffHuman,
91
+ formatHandoffJson,
92
+ runHandoffCommand,
93
+ } from "./handoff.ts";
94
+ import {
95
+ formatStudioAttachHuman,
96
+ formatStudioAttachJson,
97
+ formatStudioBridgeEventJson,
98
+ formatStudioBridgeHuman,
99
+ formatStudioBridgeJson,
100
+ formatStudioCodexServerHuman,
101
+ formatStudioCodexServerJson,
102
+ formatStudioDoctorHuman,
103
+ formatStudioDoctorJson,
104
+ formatStudioOpenHuman,
105
+ formatStudioOpenJson,
106
+ formatStudioSnapshotHuman,
107
+ formatStudioSnapshotJson,
108
+ formatStudioWatchHuman,
109
+ formatStudioWatchJson,
110
+ runStudioAttachCommand,
111
+ runStudioBridgeCommand,
112
+ runStudioBridgeLoop,
113
+ runStudioCodexServerCommand,
114
+ runStudioDoctorCommand,
115
+ runStudioOpenCommand,
116
+ runStudioSnapshotCommand,
117
+ runStudioWatchCommand,
118
+ runStudioWatchLoop,
119
+ } from "./studio.ts";
120
+ import {
121
+ formatChangedHuman,
122
+ runChangedCommand,
123
+ } from "./changed.ts";
54
124
  import { initializeRuntimeEnv } from "../runtime/context/create-context.ts";
55
125
  import { formatDbHuman, formatDbJson, runDbCommand } from "./db.ts";
56
126
  import { formatOutboxHuman, formatOutboxJson, runOutboxCommand } from "./outbox.ts";
@@ -64,6 +134,35 @@ import {
64
134
  formatTelemetryJson,
65
135
  runTelemetryCommand,
66
136
  } from "./telemetry.ts";
137
+ import {
138
+ formatDeltaExplainHuman,
139
+ formatDeltaExplainJson,
140
+ formatDeltaCompactHuman,
141
+ formatDeltaCompactJson,
142
+ formatDeltaDoctorHuman,
143
+ formatDeltaDoctorJson,
144
+ formatDeltaExportHuman,
145
+ formatDeltaExportJson,
146
+ formatDeltaPruneHuman,
147
+ formatDeltaPruneJson,
148
+ formatDeltaRepairHuman,
149
+ formatDeltaRepairJson,
150
+ formatDeltaStatusHuman,
151
+ formatDeltaStatusJson,
152
+ formatDeltaSessionHuman,
153
+ formatDeltaSessionJson,
154
+ formatDeltaTimelineHuman,
155
+ formatDeltaTimelineJson,
156
+ runDeltaExplain,
157
+ runDeltaCompact,
158
+ runDeltaDoctor,
159
+ runDeltaExport,
160
+ runDeltaPrune,
161
+ runDeltaRepair,
162
+ runDeltaSessionCommand,
163
+ runDeltaStatus,
164
+ runDeltaTimeline,
165
+ } from "../delta/index.ts";
67
166
  import {
68
167
  formatPolicyHuman,
69
168
  formatPolicyJson,
@@ -78,11 +177,12 @@ import {
78
177
  runSecretsCommand,
79
178
  } from "./secrets.ts";
80
179
  import { formatAiHuman, formatAiJson, runAiCommand } from "./ai.ts";
81
- import { formatNewHuman, runNewCommand } from "./new.ts";
180
+ import { formatNewHuman, formatNewJson, runNewCommand } from "./new.ts";
82
181
  import { formatBuildHuman, runBuildCommand } from "./build.ts";
83
182
  import { runServeCommand } from "./serve.ts";
84
183
  import { runWorkerCommand } from "./worker.ts";
85
- import { formatSelfHostHuman, runSelfHostCommand } from "./self-host.ts";
184
+ import { formatSelfHostHuman, runSelfHostCommand, type SelfHostCommandResult } from "./self-host.ts";
185
+ import { formatDocsCheckHuman, runDocsCheckCommand, type DocsCheckResult } from "./docs.ts";
86
186
  import {
87
187
  formatAgentContractHuman,
88
188
  runAgentContractPrint,
@@ -90,7 +190,13 @@ import {
90
190
  import {
91
191
  formatDoctorHuman,
92
192
  formatDoctorJson,
193
+ formatPgliteDoctorHuman,
194
+ formatPgliteDoctorJson,
195
+ formatRuntimeDoctorHuman,
196
+ formatRuntimeDoctorJson,
197
+ runPgliteDoctorCommand,
93
198
  runDoctorCommand,
199
+ runRuntimeDoctorCommand,
94
200
  } from "./doctor.ts";
95
201
  import {
96
202
  formatWindowsDoctorHuman,
@@ -101,6 +207,47 @@ import {
101
207
  runWindowsSetupCommand,
102
208
  } from "./windows.ts";
103
209
  import { formatAuthHuman, formatAuthJson, runAuthCommand } from "./auth.ts";
210
+ import {
211
+ formatAuthMdHuman,
212
+ formatAuthMdJson,
213
+ runAuthMdCommand,
214
+ } from "./authmd.ts";
215
+ import {
216
+ formatWorkOSHuman,
217
+ formatWorkOSJson,
218
+ runWorkOSCommand,
219
+ } from "./workos.ts";
220
+ import {
221
+ formatDeployHuman,
222
+ formatDeployJson,
223
+ type DeployCommandResult,
224
+ runDeployCommand,
225
+ } from "./deploy.ts";
226
+ import {
227
+ formatFieldTestHuman,
228
+ formatFieldTestJson,
229
+ runFieldTestCommand,
230
+ } from "./field-test.ts";
231
+ import {
232
+ formatGoldenPathHuman,
233
+ formatGoldenPathJson,
234
+ runGoldenPathCommand,
235
+ } from "./golden-path.ts";
236
+ import {
237
+ formatSeedHuman,
238
+ formatSeedJson,
239
+ runSeedCommand,
240
+ } from "./seed.ts";
241
+ import {
242
+ formatLastHuman,
243
+ formatLastJson,
244
+ runLastCommand,
245
+ } from "./last-run.ts";
246
+ import {
247
+ formatBaselineHuman,
248
+ formatBaselineJson,
249
+ runBaselineCommand,
250
+ } from "./baseline.ts";
104
251
  import { formatRlsHuman, formatRlsJson, runRlsCommand } from "./rls.ts";
105
252
  import {
106
253
  formatSecurityHuman,
@@ -111,6 +258,7 @@ import { formatDepsHuman, formatDepsJson, runDepsCommand } from "./deps.ts";
111
258
  import {
112
259
  formatReleaseHuman,
113
260
  formatReleaseJson,
261
+ type ReleaseCommandResult,
114
262
  runReleaseCommand,
115
263
  } from "./release.ts";
116
264
  import { formatMakeHuman, formatMakeJson, runMakeCommand } from "./make.ts";
@@ -132,11 +280,20 @@ import {
132
280
  formatForgeDoJson,
133
281
  runForgeDoCommand,
134
282
  } from "../intent/index.ts";
283
+ import {
284
+ formatBrownfieldImportHuman,
285
+ formatBrownfieldImportJson,
286
+ inspectBrownfieldImport,
287
+ runBrownfieldImportCommand,
288
+ } from "../brownfield-import/index.ts";
135
289
  import {
136
290
  formatAgentHuman,
137
291
  formatAgentJson,
138
292
  runAgentCommand,
139
293
  } from "../agent-adapters/index.ts";
294
+ import { runMcpServe } from "../agent-memory/mcp.ts";
295
+ import { runFabricCommand } from "./fabric.ts";
296
+ import { runEvolutionCommand } from "./evolution.ts";
140
297
  import {
141
298
  formatReviewHuman,
142
299
  formatReviewJson,
@@ -161,6 +318,10 @@ import { runQuery } from "../runtime/query/run-query.ts";
161
318
  import { resolveAuthFromCli } from "../runtime/auth/resolve.ts";
162
319
  import { getActiveDbAdapter } from "../runtime/executor.ts";
163
320
  import { CLI_VERSION, FORGEOS_VERSION } from "../version.ts";
321
+ import { authoredChangePaths, type CategorizedFileSummary } from "../workspace/change-summary.ts";
322
+ import { forgeCliCommandsForWorkspace } from "../workspace/forge-cli.ts";
323
+ import { buildWorkspaceGitSummary } from "../workspace/git-summary.ts";
324
+ import { startCommandHeartbeat } from "./progress.ts";
164
325
 
165
326
  function readGeneratedJson<T>(workspaceRoot: string, relative: string): T | null {
166
327
  const absolute = join(workspaceRoot, relative);
@@ -244,9 +405,14 @@ function buildFrameworkInspect(workspaceRoot: string): Record<string, unknown> {
244
405
  topLevelCommands: [...TOP_LEVEL_COMMANDS],
245
406
  inspectTargets: [...INSPECT_TARGETS],
246
407
  preferredEntryPoints: [
408
+ "forge status --json",
409
+ "forge changed --json",
410
+ "forge agent onboard --target codex --json",
247
411
  "forge do <objective> --json",
248
412
  "forge dev --once --json",
413
+ "forge inspect all --brief --json",
249
414
  "forge inspect all --json",
415
+ "forge agent print-context --json",
250
416
  "forge inspect framework --json",
251
417
  "forge verify --strict",
252
418
  ],
@@ -276,13 +442,571 @@ function buildFrameworkInspect(workspaceRoot: string): Record<string, unknown> {
276
442
  };
277
443
  }
278
444
 
445
+ function readGeneratedArtifactStatus(workspaceRoot: string): Array<{ name: string; path: string; present: boolean }> {
446
+ const artifacts = [
447
+ ["app", `${GENERATED_DIR}/appGraph.json`],
448
+ ["data", `${GENERATED_DIR}/dataGraph.json`],
449
+ ["sql", `${GENERATED_DIR}/sqlPlan.json`],
450
+ ["db", `${GENERATED_DIR}/db.json`],
451
+ ["runtime", `${GENERATED_DIR}/runtimeGraph.json`],
452
+ ["frontend", `${GENERATED_DIR}/frontendGraph.json`],
453
+ ["client", `${GENERATED_DIR}/clientManifest.json`],
454
+ ["agent-contract", `${GENERATED_DIR}/agentContract.json`],
455
+ ["agent-adapters", `${GENERATED_DIR}/agentAdapterManifest.json`],
456
+ ["capability-map", `${GENERATED_DIR}/capabilityMap.json`],
457
+ ["test-graph", `${GENERATED_DIR}/testGraph.json`],
458
+ ["agents-md", "AGENTS.md"],
459
+ ["forge-lock", "forge.lock"],
460
+ ] as const;
461
+
462
+ return artifacts.map(([name, path]) => ({
463
+ name,
464
+ path,
465
+ present: hasPath(workspaceRoot, path),
466
+ }));
467
+ }
468
+
469
+ function buildInspectSummary(workspaceRoot: string): Record<string, unknown> {
470
+ const framework = buildFrameworkInspect(workspaceRoot);
471
+ const dataGraph = readGeneratedJson<DataGraph>(workspaceRoot, `${GENERATED_DIR}/dataGraph.json`);
472
+ const frontend = readGeneratedJson<FrontendGraph>(workspaceRoot, `${GENERATED_DIR}/frontendGraph.json`);
473
+ const agentAdapters = readGeneratedJson<{ targets?: Array<{ name?: string; files?: string[]; default?: boolean; optional?: boolean }> }>(
474
+ workspaceRoot,
475
+ `${GENERATED_DIR}/agentAdapterManifest.json`,
476
+ );
477
+ const artifacts = readGeneratedArtifactStatus(workspaceRoot);
478
+ const missingArtifacts = artifacts.filter((artifact) => !artifact.present);
479
+
480
+ return {
481
+ schemaVersion: "0.1.0",
482
+ summary: {
483
+ project: (framework.project as Record<string, unknown> | undefined)?.name ?? "unknown",
484
+ tables: dataGraph?.tables.length ?? 0,
485
+ frontendPresent: frontend?.present === true,
486
+ routes: frontend?.routes.length ?? 0,
487
+ agentTargets: agentAdapters?.targets?.map((target) => target.name).filter(Boolean) ?? [],
488
+ missingArtifacts: missingArtifacts.length,
489
+ },
490
+ artifacts,
491
+ nextActions: [
492
+ "forge inspect schema --json",
493
+ "forge inspect handoff --json",
494
+ "forge inspect drift --json",
495
+ "forge check --json",
496
+ ],
497
+ };
498
+ }
499
+
500
+ function buildInspectBrief(workspaceRoot: string): Record<string, unknown> {
501
+ const summary = buildInspectSummary(workspaceRoot);
502
+ const framework = buildFrameworkInspect(workspaceRoot);
503
+ const cli = framework.cli as { preferredEntryPoints?: string[]; inspectTargets?: string[] } | undefined;
504
+ const artifacts = readGeneratedArtifactStatus(workspaceRoot);
505
+ const missingArtifacts = artifacts.filter((artifact) => !artifact.present);
506
+ return {
507
+ schemaVersion: "0.1.0",
508
+ brief: true,
509
+ payload: {
510
+ mode: "brief",
511
+ purpose: "orientation",
512
+ includes: ["summary", "entrypoints", "refs", "artifact counts"],
513
+ omitted: ["schema table details", "framework module lists", "generated registries"],
514
+ fullCommand: "forge inspect all --full --json",
515
+ compactCommand: "forge inspect all --json",
516
+ },
517
+ summary: summary.summary,
518
+ entrypoints: {
519
+ preferred: cli?.preferredEntryPoints ?? [],
520
+ inspect: [
521
+ "forge inspect summary --json",
522
+ "forge inspect schema --json",
523
+ "forge inspect handoff --json",
524
+ "forge inspect all --json",
525
+ "forge inspect all --full --json",
526
+ ],
527
+ },
528
+ refs: [
529
+ "AGENTS.md",
530
+ `${GENERATED_DIR}/agentContract.json`,
531
+ `${GENERATED_DIR}/appMap.md`,
532
+ `${GENERATED_DIR}/runtimeRules.md`,
533
+ `${GENERATED_DIR}/operationPlaybooks.md`,
534
+ `${GENERATED_DIR}/frontendGraph.json`,
535
+ ],
536
+ artifacts: {
537
+ total: artifacts.length,
538
+ present: artifacts.length - missingArtifacts.length,
539
+ missing: missingArtifacts,
540
+ },
541
+ nextActions: [
542
+ "forge status --json",
543
+ "forge changed --json",
544
+ "forge agent onboard --target codex --json",
545
+ "forge dev --once --json",
546
+ "forge inspect all --json",
547
+ ],
548
+ };
549
+ }
550
+
551
+ function buildSchemaInspect(workspaceRoot: string): { data: Record<string, unknown>; errors: ReturnType<typeof createDiagnostic>[] } {
552
+ const dataGraph = readGeneratedJson<DataGraph>(workspaceRoot, `${GENERATED_DIR}/dataGraph.json`);
553
+ const sqlPlan = readGeneratedJson<SqlPlan>(workspaceRoot, `${GENERATED_DIR}/sqlPlan.json`);
554
+ const db = readGeneratedJson<{ tableMap?: Record<string, TableMapEntry> }>(workspaceRoot, `${GENERATED_DIR}/db.json`);
555
+ const errors: ReturnType<typeof createDiagnostic>[] = [];
556
+
557
+ if (!dataGraph) {
558
+ errors.push(createDiagnostic({
559
+ severity: "error",
560
+ code: "FORGE_INSPECT_MISSING",
561
+ message: `missing generated artifact: ${GENERATED_DIR}/dataGraph.json; run forge generate first`,
562
+ file: `${GENERATED_DIR}/dataGraph.json`,
563
+ }));
564
+ }
565
+ if (!sqlPlan) {
566
+ errors.push(createDiagnostic({
567
+ severity: "error",
568
+ code: "FORGE_INSPECT_MISSING",
569
+ message: `missing generated artifact: ${GENERATED_DIR}/sqlPlan.json; run forge generate first`,
570
+ file: `${GENERATED_DIR}/sqlPlan.json`,
571
+ }));
572
+ }
573
+ if (!db?.tableMap) {
574
+ errors.push(createDiagnostic({
575
+ severity: "error",
576
+ code: "FORGE_INSPECT_MISSING",
577
+ message: `missing generated artifact: ${GENERATED_DIR}/db.json; run forge generate first`,
578
+ file: `${GENERATED_DIR}/db.json`,
579
+ }));
580
+ }
581
+
582
+ const sqlByAccessName = new Map(
583
+ (sqlPlan?.tables ?? [])
584
+ .filter((table) => table.kind === "create_table")
585
+ .map((table) => [table.accessName ?? table.table ?? "", table]),
586
+ );
587
+ const tableMap = db?.tableMap ?? {};
588
+ const dataGraphDiagnostics = dataGraph?.diagnostics ?? [];
589
+ const sqlPlanDiagnostics = sqlPlan?.diagnostics ?? [];
590
+ const tables = (dataGraph?.tables ?? []).map((table) => {
591
+ const sql = sqlByAccessName.get(table.name);
592
+ const runtime = sql?.table ? tableMap[sql.table] ?? tableMap[table.name] : tableMap[table.name];
593
+ const sourceFields = table.fields.map((field) => field.name).sort();
594
+ const sqlColumns = (sql?.columns ?? []).map((column) => ({
595
+ name: column.name,
596
+ fieldName: column.fieldName,
597
+ sqlType: column.sqlType,
598
+ primaryKey: column.primaryKey === true,
599
+ }));
600
+ const runtimeFields = (runtime?.columns ?? []).map((column) => column.fieldName ?? column.name).sort();
601
+ const missingRuntimeFields = sourceFields.filter((field) => !runtimeFields.includes(field));
602
+
603
+ return {
604
+ name: table.name,
605
+ file: table.file,
606
+ sourceFields,
607
+ sqlTable: sql?.table ?? null,
608
+ sqlColumns,
609
+ runtimeAccessors: Object.entries(tableMap)
610
+ .filter(([, entry]) => entry.tableName === (sql?.table ?? table.name))
611
+ .map(([name]) => name)
612
+ .sort(),
613
+ missingRuntimeFields,
614
+ };
615
+ });
616
+
617
+ return {
618
+ data: {
619
+ schemaVersion: "0.1.0",
620
+ summary: {
621
+ tables: tables.length,
622
+ missingRuntimeFields: tables.reduce(
623
+ (count, table) => count + (table.missingRuntimeFields as string[]).length,
624
+ 0,
625
+ ),
626
+ diagnostics: dataGraphDiagnostics.length + sqlPlanDiagnostics.length + errors.length,
627
+ },
628
+ tables,
629
+ diagnostics: [
630
+ ...dataGraphDiagnostics,
631
+ ...sqlPlanDiagnostics,
632
+ ...errors,
633
+ ],
634
+ },
635
+ errors,
636
+ };
637
+ }
638
+
639
+ function buildDriftInspect(workspaceRoot: string): Record<string, unknown> {
640
+ const schema = buildSchemaInspect(workspaceRoot);
641
+ const artifacts = readGeneratedArtifactStatus(workspaceRoot);
642
+ const missingArtifacts = artifacts.filter((artifact) => !artifact.present);
643
+ const tableDrift = ((schema.data.tables as Array<{ name: string; missingRuntimeFields: string[] }> | undefined) ?? [])
644
+ .filter((table) => table.missingRuntimeFields.length > 0)
645
+ .map((table) => ({
646
+ table: table.name,
647
+ missingRuntimeFields: table.missingRuntimeFields,
648
+ suggestedCommand: "forge generate && forge check --json",
649
+ }));
650
+ const staleAgentContext = hasPath(workspaceRoot, ".forge/agent/context.json")
651
+ ? "run forge agent check --target codex --json or forge agent export --target codex"
652
+ : null;
653
+
654
+ return {
655
+ schemaVersion: "0.1.0",
656
+ summary: {
657
+ ok: missingArtifacts.length === 0 && tableDrift.length === 0,
658
+ missingArtifacts: missingArtifacts.length,
659
+ tableDrift: tableDrift.length,
660
+ agentContextPresent: hasPath(workspaceRoot, ".forge/agent/context.json"),
661
+ },
662
+ missingArtifacts,
663
+ tableDrift,
664
+ agentContext: staleAgentContext,
665
+ nextActions: [
666
+ ...(missingArtifacts.length > 0 || tableDrift.length > 0 ? ["forge generate", "forge check --json"] : []),
667
+ "forge agent check --target codex --json",
668
+ ],
669
+ };
670
+ }
671
+
672
+ function buildHandoffInspect(workspaceRoot: string): Record<string, unknown> {
673
+ const manifest = readGeneratedJson<{
674
+ targets?: Array<{
675
+ name?: string;
676
+ files?: string[];
677
+ default?: boolean;
678
+ optional?: boolean;
679
+ formatVersion?: string;
680
+ adapterVersion?: string;
681
+ }>;
682
+ }>(workspaceRoot, `${GENERATED_DIR}/agentAdapterManifest.json`);
683
+ const targets = (manifest?.targets ?? []).map((target) => {
684
+ const files = target.files ?? [];
685
+ const missingFiles = files.filter((file) => !hasPath(workspaceRoot, file));
686
+ return {
687
+ name: target.name,
688
+ default: target.default === true,
689
+ optional: target.optional === true,
690
+ formatVersion: target.formatVersion,
691
+ adapterVersion: target.adapterVersion,
692
+ files,
693
+ filesPresent: files.length - missingFiles.length,
694
+ missingFiles,
695
+ exportCommand: target.name ? `forge agent export --target ${target.name}` : null,
696
+ checkCommand: target.name ? `forge agent check --target ${target.name} --json` : null,
697
+ prepareCommand: target.name ? `forge agent prepare --target ${target.name} --json` : null,
698
+ };
699
+ });
700
+ const missingRequiredFiles = targets.reduce(
701
+ (count, target) => count + (target.optional ? 0 : target.missingFiles.length),
702
+ 0,
703
+ );
704
+ const missingOptionalFiles = targets.reduce(
705
+ (count, target) => count + (target.optional ? target.missingFiles.length : 0),
706
+ 0,
707
+ );
708
+ const defaultTarget = targets.find((target) => target.default);
709
+ const defaultTargetMissingFiles = defaultTarget?.missingFiles.length ?? missingRequiredFiles;
710
+
711
+ return {
712
+ schemaVersion: "0.1.0",
713
+ summary: {
714
+ targets: targets.length,
715
+ defaultTarget: defaultTarget?.name ?? "generic",
716
+ missingFiles: missingRequiredFiles + missingOptionalFiles,
717
+ missingDefaultFiles: defaultTargetMissingFiles,
718
+ missingRequiredFiles,
719
+ missingOptionalFiles,
720
+ defaultReady: defaultTargetMissingFiles === 0,
721
+ requiredReady: missingRequiredFiles === 0,
722
+ },
723
+ targets,
724
+ commands: [
725
+ "forge agent list-targets --json",
726
+ "forge agent prepare --target codex --json",
727
+ "forge agent hooks smoke --target codex --json",
728
+ "forge agent ingest codex --event PostToolUse --json",
729
+ ],
730
+ };
731
+ }
732
+
733
+ export interface StatusCommandResult {
734
+ ok: boolean;
735
+ data: Record<string, unknown>;
736
+ exitCode: 0 | 1;
737
+ }
738
+
739
+ export async function runStatusCommand(workspaceRoot: string): Promise<StatusCommandResult> {
740
+ const summary = buildInspectSummary(workspaceRoot);
741
+ const drift = buildDriftInspect(workspaceRoot);
742
+ const handoff = buildHandoffInspect(workspaceRoot);
743
+ const gitSummary = buildWorkspaceGitSummary(workspaceRoot);
744
+ const generatedVerification = await runGenerateCommand({
745
+ workspaceRoot,
746
+ check: true,
747
+ dryRun: false,
748
+ json: true,
749
+ concurrency: 4,
750
+ });
751
+ const git = {
752
+ available: gitSummary.available,
753
+ ...(gitSummary.error ? { error: gitSummary.error } : {}),
754
+ changed: gitSummary.changeSummary.changed,
755
+ staged: gitSummary.changeSummary.staged,
756
+ unstaged: gitSummary.changeSummary.unstaged,
757
+ untracked: gitSummary.changeSummary.untracked,
758
+ };
759
+ const summaryBlock = summary.summary as Record<string, unknown>;
760
+ const driftSummary = drift.summary as Record<string, unknown>;
761
+ const handoffSummary = handoff.summary as Record<string, unknown>;
762
+ const missingArtifacts = Number(summaryBlock.missingArtifacts ?? 0);
763
+ const tableDrift = Number(driftSummary.tableDrift ?? 0);
764
+ const generatedReady = missingArtifacts === 0;
765
+ const generatedFresh = generatedVerification.exitCode === 0;
766
+ const driftClean = driftSummary.ok === true && generatedFresh;
767
+ const ok = driftClean && generatedReady;
768
+ const handoffDefaultReady = handoffSummary.defaultReady === true;
769
+ const changed = gitSummary.changeSummary.changed;
770
+ const generatedGitFiles = changed.byType.generated.count;
771
+ const authoredGitFiles = changed.total.count - generatedGitFiles;
772
+ const authoredGeneratedInputs =
773
+ changed.byType.source.count +
774
+ changed.byType.config.count +
775
+ changed.byType.operational.count;
776
+ const generatedState = !generatedReady
777
+ ? "missing-artifacts"
778
+ : driftClean
779
+ ? "ready"
780
+ : "drift";
781
+ const generatedNextActionsRaw = generatedState === "ready"
782
+ ? ["forge dev", "forge dev --once --json", "forge generate --check --json"]
783
+ : ["forge generate", "forge check --json", "forge inspect drift --json"];
784
+ const generatedNextActions = forgeCliCommandsForWorkspace(workspaceRoot, generatedNextActionsRaw);
785
+ const generatedGitExplanation = !generatedFresh
786
+ ? "deterministic generation verification found stale artifacts; git cleanliness does not prove generated freshness"
787
+ : generatedGitFiles === 0
788
+ ? "git status has no generated artifact changes and deterministic generation verification passed"
789
+ : authoredGitFiles === 0
790
+ ? "forge generate --check can be clean while git shows generated artifacts changed: generated files match current workspace inputs but differ from HEAD"
791
+ : "git status includes generated artifacts alongside authored changes; review authored inputs first";
792
+ const [safeDevCommand, generatedCheckCommand, generatedRepairCommand] = forgeCliCommandsForWorkspace(workspaceRoot, [
793
+ "forge dev",
794
+ "forge generate --check --json",
795
+ "forge generate",
796
+ ]);
797
+ const frontendPresent = summaryBlock.frontendPresent === true;
798
+ const [
799
+ studioOpenCommand,
800
+ studioAttachCommand,
801
+ studioSnapshotCommand,
802
+ studioWatchCommand,
803
+ studioBridgeCommand,
804
+ studioDoctorCommand,
805
+ studioStartTargetAppCommand,
806
+ studioProbeCommand,
807
+ ] = forgeCliCommandsForWorkspace(workspaceRoot, [
808
+ "forge studio open . --preview-port 5174 --target codex --json",
809
+ "forge studio attach . --preview-port 5174 --target codex --json",
810
+ "forge studio snapshot . --preview-port 5174 --target codex --json",
811
+ "forge studio watch . --preview-port 5174 --target codex --json",
812
+ "forge studio bridge . --preview-port 5174 --target codex --studio-url http://127.0.0.1:3765 --json",
813
+ "forge studio doctor . --preview-port 5174 --target codex --json",
814
+ "forge dev --port 3766 --web-port 5174",
815
+ "forge dev --once --json",
816
+ ]);
817
+ const studio = {
818
+ openCommand: studioOpenCommand,
819
+ attachCommand: studioAttachCommand,
820
+ snapshotCommand: studioSnapshotCommand,
821
+ watchCommand: studioWatchCommand,
822
+ bridgeCommand: studioBridgeCommand,
823
+ doctorCommand: studioDoctorCommand,
824
+ targetPreviewUrl: "http://127.0.0.1:5174",
825
+ startTargetAppCommand: studioStartTargetAppCommand,
826
+ probeCommand: studioProbeCommand,
827
+ useful: frontendPresent,
828
+ note: frontendPresent
829
+ ? "Attach this app to Forge Studio as an external-agent workroom; Studio should preview the target app on 5174."
830
+ : "No frontend was detected, but Studio can still attach for hooks, posture, and agent context.",
831
+ };
832
+
833
+ return {
834
+ ok,
835
+ data: {
836
+ schemaVersion: "0.1.0",
837
+ ok,
838
+ generated: {
839
+ state: generatedState,
840
+ ready: generatedReady,
841
+ driftClean,
842
+ freshness: generatedState === "ready" ? "verified" : generatedFresh ? "attention" : "stale",
843
+ authoredGeneratedInputs,
844
+ missingArtifacts,
845
+ tableDrift,
846
+ verification: {
847
+ checked: true,
848
+ fresh: generatedFresh,
849
+ changedFiles: generatedVerification.changed.length,
850
+ sampleChanged: generatedVerification.changed.slice(0, 8),
851
+ hiddenChanged: Math.max(0, generatedVerification.changed.length - 8),
852
+ diagnosticCodes: [...new Set(generatedVerification.errors.map((diagnostic) => diagnostic.code))],
853
+ },
854
+ safeDevCommand,
855
+ checkCommand: generatedCheckCommand,
856
+ repairCommand: generatedRepairCommand,
857
+ git: {
858
+ changedFiles: changed.total.count,
859
+ authoredFiles: authoredGitFiles,
860
+ generatedFiles: generatedGitFiles,
861
+ explanation: generatedGitExplanation,
862
+ },
863
+ nextActions: generatedNextActions,
864
+ },
865
+ studio,
866
+ summary: {
867
+ project: summaryBlock.project,
868
+ generated: generatedState,
869
+ tables: summaryBlock.tables,
870
+ frontendPresent,
871
+ routes: summaryBlock.routes,
872
+ drift: driftClean ? "clean" : "attention",
873
+ agentTargets: summaryBlock.agentTargets,
874
+ missingAgentFiles: handoffSummary.missingRequiredFiles,
875
+ missingDefaultAgentFiles: handoffSummary.missingDefaultFiles,
876
+ missingRequiredAgentFiles: handoffSummary.missingRequiredFiles,
877
+ missingOptionalAgentFiles: handoffSummary.missingOptionalFiles,
878
+ },
879
+ checks: {
880
+ artifacts: {
881
+ missing: missingArtifacts,
882
+ },
883
+ schema: {
884
+ tableDrift,
885
+ },
886
+ handoff: {
887
+ targets: handoffSummary.targets,
888
+ missingFiles: handoffSummary.missingFiles,
889
+ missingDefaultFiles: handoffSummary.missingDefaultFiles,
890
+ missingRequiredFiles: handoffSummary.missingRequiredFiles,
891
+ missingOptionalFiles: handoffSummary.missingOptionalFiles,
892
+ defaultReady: handoffSummary.defaultReady,
893
+ requiredReady: handoffSummary.requiredReady,
894
+ },
895
+ },
896
+ git,
897
+ nextActions: forgeCliCommandsForWorkspace(
898
+ workspaceRoot,
899
+ ok
900
+ ? [
901
+ "forge handoff --json",
902
+ "forge changed --json",
903
+ "forge dev",
904
+ ...(frontendPresent ? [studio.openCommand, studio.bridgeCommand, studio.doctorCommand] : []),
905
+ ...(!handoffDefaultReady ? ["forge agent prepare --target generic --json"] : []),
906
+ "forge inspect handoff --json",
907
+ "forge verify --changed",
908
+ ]
909
+ : [
910
+ "forge generate",
911
+ "forge handoff --json",
912
+ "forge changed --json",
913
+ ...(frontendPresent ? [studio.openCommand, studio.bridgeCommand, studio.doctorCommand] : []),
914
+ "forge inspect drift --json",
915
+ "forge agent prepare --target codex --json",
916
+ ],
917
+ ),
918
+ },
919
+ exitCode: ok ? 0 : 1,
920
+ };
921
+ }
922
+
923
+ export function formatStatusHuman(result: StatusCommandResult): string {
924
+ const summary = result.data.summary as Record<string, unknown>;
925
+ const generated = result.data.generated as
926
+ | {
927
+ state?: string;
928
+ missingArtifacts?: number;
929
+ tableDrift?: number;
930
+ safeDevCommand?: string;
931
+ checkCommand?: string;
932
+ repairCommand?: string;
933
+ }
934
+ | undefined;
935
+ const git = result.data.git as
936
+ | {
937
+ available?: boolean;
938
+ changed?: CategorizedFileSummary;
939
+ }
940
+ | undefined;
941
+ const studio = result.data.studio as
942
+ | {
943
+ attachCommand?: string;
944
+ openCommand?: string;
945
+ doctorCommand?: string;
946
+ bridgeCommand?: string;
947
+ targetPreviewUrl?: string;
948
+ startTargetAppCommand?: string;
949
+ useful?: boolean;
950
+ }
951
+ | undefined;
952
+ const lines = [
953
+ `Forge status: ${result.ok ? "ready" : "needs attention"}`,
954
+ `Project: ${summary.project ?? "unknown"}`,
955
+ `Generated: ${summary.generated}`,
956
+ ...(generated
957
+ ? [
958
+ `Generated detail: missing artifacts ${generated.missingArtifacts ?? 0}, table drift ${generated.tableDrift ?? 0}`,
959
+ `Generated check: ${generated.checkCommand ?? "forge generate --check --json"}`,
960
+ `Generated repair: ${generated.repairCommand ?? "forge generate"}`,
961
+ `Generated dev: ${generated.safeDevCommand ?? "forge dev"}`,
962
+ ]
963
+ : []),
964
+ `Drift: ${summary.drift}`,
965
+ `Frontend: ${summary.frontendPresent ? `${summary.routes ?? 0} routes` : "none"}`,
966
+ ...(studio
967
+ ? [
968
+ `Studio open: ${studio.openCommand ?? "forge studio open . --preview-port 5174 --target codex --json"}`,
969
+ `Studio attach: ${studio.attachCommand ?? "forge studio attach . --preview-port 5174 --target codex --json"}`,
970
+ `Studio bridge: ${studio.bridgeCommand ?? "forge studio bridge . --preview-port 5174 --target codex --studio-url http://127.0.0.1:3765 --json"}`,
971
+ `Studio doctor: ${studio.doctorCommand ?? "forge studio doctor . --preview-port 5174 --target codex --json"}`,
972
+ `Studio preview: ${studio.targetPreviewUrl ?? "http://127.0.0.1:5174"}`,
973
+ `Studio start: ${studio.startTargetAppCommand ?? "forge dev --port 3766 --web-port 5174"}`,
974
+ ]
975
+ : []),
976
+ ...(git?.available && git.changed
977
+ ? [`Changed: ${git.changed.total.count}${git.changed.total.count > 0 ? ` (${git.changed.primaryTypes.slice(0, 5).join(", ")})` : ""}`]
978
+ : []),
979
+ `Agent default missing files: ${summary.missingDefaultAgentFiles ?? 0}`,
980
+ `Agent required missing files: ${summary.missingRequiredAgentFiles ?? summary.missingAgentFiles ?? 0}`,
981
+ `Agent optional missing files: ${summary.missingOptionalAgentFiles ?? 0}`,
982
+ "",
983
+ "Next:",
984
+ ...((result.data.nextActions as string[] | undefined) ?? []).map((command) => ` ${command}`),
985
+ ];
986
+ return `${lines.join("\n")}\n`;
987
+ }
988
+
279
989
  export async function runGenerateCommand(
280
990
  options: GenerateOptions,
281
991
  ): Promise<GenerateResult> {
282
- const result = await run(options);
992
+ const result = await withWorkspaceCwd(options.workspaceRoot, () => run(options));
283
993
  return attachFailureKind(result);
284
994
  }
285
995
 
996
+ async function withWorkspaceCwd<T>(workspaceRoot: string, fn: () => Promise<T>): Promise<T> {
997
+ const previous = process.cwd();
998
+ const target = resolve(workspaceRoot);
999
+ if (resolve(previous).toLowerCase() === target.toLowerCase()) {
1000
+ return fn();
1001
+ }
1002
+ process.chdir(target);
1003
+ try {
1004
+ return await fn();
1005
+ } finally {
1006
+ process.chdir(previous);
1007
+ }
1008
+ }
1009
+
286
1010
  export async function runAddCommand(
287
1011
  alias: string,
288
1012
  options: Extract<ForgeCommand, { kind: "add" }>["options"],
@@ -324,12 +1048,70 @@ async function loadRuntimeMatrixForCheck(
324
1048
  return buildRuntimeMatrix(classified);
325
1049
  }
326
1050
 
1051
+ function normalizeSchemaType(type: string): string {
1052
+ return type.trim().replace(/\?$/, "").toLowerCase();
1053
+ }
1054
+
1055
+ function timestampFieldNames(dataGraph: DataGraph): Set<string> {
1056
+ const fields = new Set<string>();
1057
+ for (const table of dataGraph.tables) {
1058
+ for (const field of table.fields) {
1059
+ if (["timestamp", "timestamptz"].includes(normalizeSchemaType(field.type))) {
1060
+ fields.add(field.name);
1061
+ }
1062
+ }
1063
+ }
1064
+ return fields;
1065
+ }
1066
+
1067
+ function checkEmptyTimestampLiterals(
1068
+ appGraph: Awaited<ReturnType<typeof buildAppGraphForSession>>,
1069
+ dataGraph: DataGraph,
1070
+ ): ReturnType<typeof createDiagnostic>[] {
1071
+ const fields = timestampFieldNames(dataGraph);
1072
+ if (fields.size === 0) {
1073
+ return [];
1074
+ }
1075
+ const diagnostics: ReturnType<typeof createDiagnostic>[] = [];
1076
+ const runtimeKinds = new Set(["command", "query", "liveQuery", "action", "workflow"]);
1077
+ for (const symbol of appGraph.symbols) {
1078
+ if (!runtimeKinds.has(symbol.kind)) {
1079
+ continue;
1080
+ }
1081
+ const sourceSlice = typeof symbol.meta.sourceSlice === "string" ? symbol.meta.sourceSlice : "";
1082
+ if (!sourceSlice) {
1083
+ continue;
1084
+ }
1085
+ for (const field of fields) {
1086
+ const escaped = field.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
1087
+ const pattern = new RegExp(`\\b${escaped}\\s*:\\s*(["']{2})`);
1088
+ const emptyTemplatePattern = new RegExp(`\\b${escaped}\\s*:\\s*\`\``);
1089
+ if (!pattern.test(sourceSlice) && !emptyTemplatePattern.test(sourceSlice)) {
1090
+ continue;
1091
+ }
1092
+ diagnostics.push(
1093
+ createDiagnostic({
1094
+ severity: "error",
1095
+ code: FORGE_DB_EMPTY_TIMESTAMP_LITERAL,
1096
+ message:
1097
+ `Forge timestamp field '${field}' is assigned an empty string in ${symbol.kind} '${symbol.name}'.`,
1098
+ file: symbol.file,
1099
+ span: symbol.span,
1100
+ }),
1101
+ );
1102
+ }
1103
+ }
1104
+ return diagnostics;
1105
+ }
1106
+
327
1107
  export async function runCheckCommand(
328
1108
  workspaceRoot: string,
329
1109
  options?: { strictSecrets?: boolean },
330
1110
  ): Promise<GenerateResult> {
331
1111
  const session = getCompileSession(workspaceRoot);
332
1112
  const appGraph = await buildAppGraphForSession(session);
1113
+ const dataGraph = buildDataGraph(appGraph);
1114
+ const sqlPlan = buildSqlPlan(dataGraph);
333
1115
 
334
1116
  const matrix = await loadRuntimeMatrixForCheck(workspaceRoot);
335
1117
  const guardDiagnostics = checkImportGuards(appGraph.moduleGraph, matrix);
@@ -349,14 +1131,21 @@ export async function runCheckCommand(
349
1131
  workspaceRoot,
350
1132
  `${GENERATED_DIR}/capabilityMap.json`,
351
1133
  )?.diagnostics ?? [];
1134
+ const externalDiagnostics = buildExternalServiceGraph(workspaceRoot).diagnostics;
1135
+ const timestampLiteralDiagnostics = checkEmptyTimestampLiterals(appGraph, dataGraph);
352
1136
 
353
1137
  const allDiagnostics = [
1138
+ ...appGraph.diagnostics,
1139
+ ...dataGraph.diagnostics,
1140
+ ...sqlPlan.diagnostics,
354
1141
  ...guardDiagnostics,
355
1142
  ...processEnvDiagnostics,
356
1143
  ...aiDiagnostics,
357
1144
  ...queryDiagnostics,
1145
+ ...timestampLiteralDiagnostics,
358
1146
  ...frontendDiagnostics,
359
1147
  ...capabilityDiagnostics,
1148
+ ...externalDiagnostics,
360
1149
  ];
361
1150
  const errors = allDiagnostics.filter(
362
1151
  (diagnostic) => diagnostic.severity === "error",
@@ -375,9 +1164,474 @@ export async function runCheckCommand(
375
1164
  });
376
1165
  }
377
1166
 
1167
+ interface ReleaseDoctorCheck {
1168
+ name: string;
1169
+ ok: boolean;
1170
+ requiredForPublish: boolean;
1171
+ requiredForProduction?: boolean;
1172
+ state?: string;
1173
+ result: ReleaseCommandResult | SelfHostCommandResult | DocsCheckResult | DeployCommandResult | PackagePackCheckResult | NpmDistTagCheckResult;
1174
+ }
1175
+
1176
+ interface PackagePackCheckResult {
1177
+ ok: boolean;
1178
+ data: {
1179
+ command: "npm pack --dry-run --json";
1180
+ dryRun: true;
1181
+ tarball: string | null;
1182
+ fileCount: number;
1183
+ };
1184
+ diagnostics: ReturnType<typeof createDiagnostic>[];
1185
+ nextActions?: string[];
1186
+ failureKind?: string;
1187
+ exitCode: 0 | 1;
1188
+ }
1189
+
1190
+ interface NpmDistTagCheckResult {
1191
+ ok: boolean;
1192
+ data: {
1193
+ command: string;
1194
+ packageName: string | null;
1195
+ packageVersion: string | null;
1196
+ alphaVersion: string | null;
1197
+ latestVersion: string | null;
1198
+ alphaMatches: boolean;
1199
+ latestMatches: boolean;
1200
+ source: "npm-view" | "env-fixture" | "skipped";
1201
+ };
1202
+ diagnostics: ReturnType<typeof createDiagnostic>[];
1203
+ nextActions?: string[];
1204
+ failureKind?: string;
1205
+ exitCode: 0 | 1;
1206
+ }
1207
+
1208
+ interface ReleaseDoctorResult {
1209
+ schemaVersion: "0.1.0";
1210
+ ok: boolean;
1211
+ readyToPublish: boolean;
1212
+ readyForProductionDeploy: boolean;
1213
+ summary: {
1214
+ checks: number;
1215
+ failed: string[];
1216
+ notPrepared: string[];
1217
+ publishBlockers: string[];
1218
+ productionBlockers: string[];
1219
+ };
1220
+ checks: ReleaseDoctorCheck[];
1221
+ nextActions: string[];
1222
+ exitCode: 0 | 1;
1223
+ }
1224
+
1225
+ function runPackagePackDryRun(workspaceRoot: string): PackagePackCheckResult {
1226
+ const result = spawnSync("npm", ["pack", "--dry-run", "--json"], {
1227
+ cwd: workspaceRoot,
1228
+ encoding: "utf8",
1229
+ windowsHide: true,
1230
+ });
1231
+ const command = "npm pack --dry-run --json" as const;
1232
+ if (result.status !== 0) {
1233
+ const failureDetail = result.error instanceof Error ? result.error.message : null;
1234
+ return {
1235
+ ok: false,
1236
+ data: { command, dryRun: true, tarball: null, fileCount: 0 },
1237
+ diagnostics: [
1238
+ createDiagnostic({
1239
+ severity: "error",
1240
+ code: FORGE_RELEASE_PACKAGE_PACK_FAILED,
1241
+ message: "npm pack dry-run failed; release package contents could not be validated",
1242
+ fixHint: (result.stderr || result.stdout || failureDetail || "Run npm pack --dry-run --json locally for details.").trim(),
1243
+ suggestedCommands: ["npm pack --dry-run --json"],
1244
+ }),
1245
+ ],
1246
+ nextActions: ["npm pack --dry-run --json"],
1247
+ failureKind: "package-pack-failed",
1248
+ exitCode: 1,
1249
+ };
1250
+ }
1251
+ try {
1252
+ const parsed = JSON.parse(result.stdout || "[]") as unknown;
1253
+ const pack = Array.isArray(parsed)
1254
+ ? (parsed[0] as { filename?: unknown; files?: unknown[] } | undefined)
1255
+ : undefined;
1256
+ if (typeof pack?.filename !== "string" || !Array.isArray(pack.files)) {
1257
+ return {
1258
+ ok: false,
1259
+ data: { command, dryRun: true, tarball: null, fileCount: 0 },
1260
+ diagnostics: [
1261
+ createDiagnostic({
1262
+ severity: "error",
1263
+ code: FORGE_RELEASE_PACKAGE_PACK_FAILED,
1264
+ message: "npm pack dry-run did not report package contents",
1265
+ fixHint: "Run npm pack --dry-run --json locally and confirm it returns a tarball with file entries.",
1266
+ suggestedCommands: ["npm pack --dry-run --json"],
1267
+ }),
1268
+ ],
1269
+ nextActions: ["npm pack --dry-run --json"],
1270
+ failureKind: "package-pack-missing-contents",
1271
+ exitCode: 1,
1272
+ };
1273
+ }
1274
+ return {
1275
+ ok: true,
1276
+ data: {
1277
+ command,
1278
+ dryRun: true,
1279
+ tarball: pack.filename,
1280
+ fileCount: pack.files.length,
1281
+ },
1282
+ diagnostics: [],
1283
+ exitCode: 0,
1284
+ };
1285
+ } catch (error) {
1286
+ return {
1287
+ ok: false,
1288
+ data: { command, dryRun: true, tarball: null, fileCount: 0 },
1289
+ diagnostics: [
1290
+ createDiagnostic({
1291
+ severity: "error",
1292
+ code: FORGE_RELEASE_PACKAGE_PACK_FAILED,
1293
+ message: "npm pack dry-run returned invalid JSON",
1294
+ fixHint: error instanceof Error ? error.message : String(error),
1295
+ suggestedCommands: ["npm pack --dry-run --json"],
1296
+ }),
1297
+ ],
1298
+ nextActions: ["npm pack --dry-run --json"],
1299
+ failureKind: "package-pack-invalid-json",
1300
+ exitCode: 1,
1301
+ };
1302
+ }
1303
+ }
1304
+
1305
+ function parseNpmDistTagsJson(raw: string): Record<string, string> | null {
1306
+ try {
1307
+ const parsed = JSON.parse(raw) as unknown;
1308
+ if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
1309
+ return null;
1310
+ }
1311
+ const tags: Record<string, string> = {};
1312
+ for (const [key, value] of Object.entries(parsed)) {
1313
+ if (typeof value === "string") {
1314
+ tags[key] = value;
1315
+ }
1316
+ }
1317
+ return tags;
1318
+ } catch {
1319
+ return null;
1320
+ }
1321
+ }
1322
+
1323
+ function runNpmDistTagCheck(workspaceRoot: string): NpmDistTagCheckResult {
1324
+ const pkg = readPackageJson(workspaceRoot) as {
1325
+ name?: unknown;
1326
+ version?: unknown;
1327
+ private?: unknown;
1328
+ };
1329
+ const packageName = typeof pkg.name === "string" ? pkg.name : null;
1330
+ const packageVersion = typeof pkg.version === "string" ? pkg.version : null;
1331
+ const command = packageName ? `npm view ${packageName} dist-tags --json` : "npm view <package> dist-tags --json";
1332
+ const baseData = {
1333
+ command,
1334
+ packageName,
1335
+ packageVersion,
1336
+ alphaVersion: null,
1337
+ latestVersion: null,
1338
+ alphaMatches: false,
1339
+ latestMatches: false,
1340
+ source: "skipped" as const,
1341
+ };
1342
+
1343
+ if (pkg.private === true) {
1344
+ return {
1345
+ ok: true,
1346
+ data: baseData,
1347
+ diagnostics: [],
1348
+ exitCode: 0,
1349
+ };
1350
+ }
1351
+ if (!packageName || !packageVersion) {
1352
+ return {
1353
+ ok: false,
1354
+ data: baseData,
1355
+ diagnostics: [
1356
+ createDiagnostic({
1357
+ severity: "warning",
1358
+ code: FORGE_RELEASE_NPM_DIST_TAG_CHECK_FAILED,
1359
+ message: "release doctor could not check npm dist-tags because package.json is missing name or version",
1360
+ fixHint: "Set package.json name and version before publishing, then rerun forge release doctor.",
1361
+ suggestedCommands: ["node bin/forge.mjs release doctor --json"],
1362
+ }),
1363
+ ],
1364
+ nextActions: ["node bin/forge.mjs release doctor --json"],
1365
+ failureKind: "npm-dist-tags-package-metadata-missing",
1366
+ exitCode: 1,
1367
+ };
1368
+ }
1369
+
1370
+ const fixture = process.env.FORGE_RELEASE_NPM_DIST_TAGS_JSON;
1371
+ const source = fixture ? "env-fixture" as const : "npm-view" as const;
1372
+ const stdout = fixture ?? spawnSync("npm", ["view", packageName, "dist-tags", "--json"], {
1373
+ cwd: workspaceRoot,
1374
+ encoding: "utf8",
1375
+ timeout: 10_000,
1376
+ windowsHide: true,
1377
+ }).stdout;
1378
+ const tags = parseNpmDistTagsJson(stdout || "");
1379
+ if (!tags) {
1380
+ return {
1381
+ ok: false,
1382
+ data: { ...baseData, source },
1383
+ diagnostics: [
1384
+ createDiagnostic({
1385
+ severity: "warning",
1386
+ code: FORGE_RELEASE_NPM_DIST_TAG_CHECK_FAILED,
1387
+ message: `release doctor could not read npm dist-tags for ${packageName}`,
1388
+ fixHint: `Run ${command}. If the package has not been published yet, publish it with the alpha tag first.`,
1389
+ suggestedCommands: [command, "npm run release:publish-alpha"],
1390
+ }),
1391
+ ],
1392
+ nextActions: [command, "npm run release:publish-alpha"],
1393
+ failureKind: "npm-dist-tags-unavailable",
1394
+ exitCode: 1,
1395
+ };
1396
+ }
1397
+
1398
+ const alphaVersion = tags.alpha ?? null;
1399
+ const latestVersion = tags.latest ?? null;
1400
+ const alphaMatches = alphaVersion === packageVersion;
1401
+ const latestMatches = latestVersion === packageVersion;
1402
+ const data = {
1403
+ command,
1404
+ packageName,
1405
+ packageVersion,
1406
+ alphaVersion,
1407
+ latestVersion,
1408
+ alphaMatches,
1409
+ latestMatches,
1410
+ source,
1411
+ };
1412
+ if (alphaMatches && latestMatches) {
1413
+ return {
1414
+ ok: true,
1415
+ data,
1416
+ diagnostics: [],
1417
+ exitCode: 0,
1418
+ };
1419
+ }
1420
+
1421
+ const nextActions: string[] = [];
1422
+ const diagnostics: ReturnType<typeof createDiagnostic>[] = [];
1423
+ if (!alphaMatches) {
1424
+ nextActions.push("npm run release:publish-alpha");
1425
+ diagnostics.push(createDiagnostic({
1426
+ severity: "warning",
1427
+ code: FORGE_RELEASE_NPM_DIST_TAG_STALE,
1428
+ message: `${packageName}@alpha points to ${alphaVersion ?? "none"}, not local version ${packageVersion}`,
1429
+ fixHint: "Publish the current package with the alpha tag before asking users to install forgeos@alpha.",
1430
+ suggestedCommands: ["npm run release:publish-alpha", command],
1431
+ }));
1432
+ }
1433
+ if (!latestMatches) {
1434
+ const promote = `npm dist-tag add ${packageName}@${packageVersion} latest`;
1435
+ nextActions.push(promote);
1436
+ nextActions.push("configure NPM_TOKEN in GitHub Actions secrets, or run npm login locally before promoting latest");
1437
+ diagnostics.push(createDiagnostic({
1438
+ severity: "warning",
1439
+ code: FORGE_RELEASE_NPM_DIST_TAG_STALE,
1440
+ message: `${packageName}@latest points to ${latestVersion ?? "none"}, not local version ${packageVersion}`,
1441
+ fixHint: `Promote latest after the alpha package is verified: ${promote}`,
1442
+ suggestedCommands: [promote, command],
1443
+ }));
1444
+ }
1445
+ return {
1446
+ ok: false,
1447
+ data,
1448
+ diagnostics,
1449
+ nextActions,
1450
+ failureKind: !alphaMatches ? "npm-alpha-dist-tag-stale" : "npm-latest-dist-tag-stale",
1451
+ exitCode: 1,
1452
+ };
1453
+ }
1454
+
1455
+ export async function runReleaseDoctorCommand(command: Extract<ForgeCommand, { kind: "release" }>): Promise<ReleaseDoctorResult> {
1456
+ const release = await runReleaseCommand({
1457
+ ...command,
1458
+ action: "check",
1459
+ allowMissingLocalRelease: true,
1460
+ provider: command.provider as import("../compiler/release/types.ts").ReleaseExportProvider | undefined,
1461
+ target: command.target as import("../compiler/release/types.ts").ReleaseExportProvider | undefined,
1462
+ });
1463
+ const sourcemaps = await runReleaseCommand({
1464
+ ...command,
1465
+ area: "sourcemaps",
1466
+ action: "check",
1467
+ provider: command.provider as import("../compiler/release/types.ts").ReleaseExportProvider | undefined,
1468
+ target: command.target as import("../compiler/release/types.ts").ReleaseExportProvider | undefined,
1469
+ });
1470
+ const selfHost = await runSelfHostCommand({
1471
+ subcommand: "check",
1472
+ workspaceRoot: command.workspaceRoot,
1473
+ json: command.json,
1474
+ withWeb: true,
1475
+ postgresVersion: "16",
1476
+ runtimePort: 3765,
1477
+ webPort: 3000,
1478
+ preparedOnly: true,
1479
+ });
1480
+ const docs = runDocsCheckCommand({
1481
+ workspaceRoot: command.workspaceRoot,
1482
+ json: command.json,
1483
+ });
1484
+ const deployProduction = await runDeployCommand({
1485
+ subcommand: "check",
1486
+ workspaceRoot: command.workspaceRoot,
1487
+ json: command.json,
1488
+ target: "docker",
1489
+ production: true,
1490
+ });
1491
+ const packagePack = runPackagePackDryRun(command.workspaceRoot);
1492
+ const npmDistTags = runNpmDistTagCheck(command.workspaceRoot);
1493
+ const checks: ReleaseDoctorCheck[] = [
1494
+ {
1495
+ name: "release-prepared",
1496
+ ok: release.ok,
1497
+ requiredForPublish: true,
1498
+ state: (release.data as { state?: string } | undefined)?.state,
1499
+ result: release,
1500
+ },
1501
+ {
1502
+ name: "sourcemaps",
1503
+ ok: sourcemaps.ok,
1504
+ requiredForPublish: true,
1505
+ result: sourcemaps,
1506
+ },
1507
+ {
1508
+ name: "self-host",
1509
+ ok: selfHost.ok,
1510
+ requiredForPublish: false,
1511
+ state: selfHost.state,
1512
+ result: selfHost,
1513
+ },
1514
+ {
1515
+ name: "deploy-production",
1516
+ ok: deployProduction.ok,
1517
+ requiredForPublish: false,
1518
+ requiredForProduction: true,
1519
+ result: deployProduction,
1520
+ },
1521
+ {
1522
+ name: "docs",
1523
+ ok: docs.ok,
1524
+ requiredForPublish: true,
1525
+ result: docs,
1526
+ },
1527
+ {
1528
+ name: "npm-pack-dry-run",
1529
+ ok: packagePack.ok,
1530
+ requiredForPublish: true,
1531
+ result: packagePack,
1532
+ },
1533
+ {
1534
+ name: "npm-dist-tags",
1535
+ ok: npmDistTags.ok,
1536
+ requiredForPublish: false,
1537
+ state: npmDistTags.failureKind ?? (npmDistTags.data.source === "skipped" ? "skipped" : "current"),
1538
+ result: npmDistTags,
1539
+ },
1540
+ ];
1541
+ const failed = checks.filter((check) => !check.ok).map((check) => check.name);
1542
+ const notPrepared = checks
1543
+ .filter((check) => check.state === "missing-prepared-release" || check.state === "not-prepared")
1544
+ .map((check) => check.name);
1545
+ const publishBlockers = checks
1546
+ .filter((check) => check.requiredForPublish && !check.ok)
1547
+ .map((check) => check.name);
1548
+ const productionBlockers = checks
1549
+ .filter((check) => check.requiredForProduction && !check.ok)
1550
+ .map((check) => check.name);
1551
+ const notPreparedPublishBlockers = checks
1552
+ .filter((check) => check.requiredForPublish && (check.state === "missing-prepared-release" || check.state === "not-prepared"))
1553
+ .map((check) => check.name);
1554
+ const readyToPublish = publishBlockers.length === 0 && notPreparedPublishBlockers.length === 0;
1555
+ const readyForProductionDeploy = productionBlockers.length === 0;
1556
+ return {
1557
+ schemaVersion: "0.1.0",
1558
+ ok: readyToPublish,
1559
+ readyToPublish,
1560
+ readyForProductionDeploy,
1561
+ summary: {
1562
+ checks: checks.length,
1563
+ failed,
1564
+ notPrepared,
1565
+ publishBlockers,
1566
+ productionBlockers,
1567
+ },
1568
+ checks,
1569
+ nextActions: uniqueNextActions(checks.flatMap((check) => check.result.nextActions ?? [])),
1570
+ exitCode: readyToPublish ? 0 : 1,
1571
+ };
1572
+ }
1573
+
1574
+ function formatManifestHuman(result: {
1575
+ subcommand: "validate" | "import";
1576
+ path: string;
1577
+ imported?: boolean;
1578
+ serviceCount?: number;
1579
+ diagnostics: import("../compiler/types/diagnostic.ts").Diagnostic[];
1580
+ exitCode: number;
1581
+ }): string {
1582
+ const errors = result.diagnostics.filter((diagnostic) => diagnostic.severity === "error");
1583
+ const warnings = result.diagnostics.filter((diagnostic) => diagnostic.severity === "warning");
1584
+ const lines = [
1585
+ `manifest: ${result.subcommand}`,
1586
+ `path: ${result.path}`,
1587
+ result.subcommand === "import" ? `imported: ${result.imported ? "yes" : "no"}` : null,
1588
+ result.serviceCount !== undefined ? `external services: ${result.serviceCount}` : null,
1589
+ `errors: ${errors.length}`,
1590
+ `warnings: ${warnings.length}`,
1591
+ ].filter((line): line is string => line !== null);
1592
+ for (const diagnostic of result.diagnostics) {
1593
+ lines.push(`${diagnostic.severity} ${diagnostic.code}: ${diagnostic.message}`);
1594
+ }
1595
+ return `${lines.join("\n")}\n`;
1596
+ }
1597
+
1598
+ function runManifestCommand(command: Extract<ForgeCommand, { kind: "manifest" }>): {
1599
+ subcommand: "validate" | "import";
1600
+ path: string;
1601
+ imported?: boolean;
1602
+ serviceCount?: number;
1603
+ diagnostics: import("../compiler/types/diagnostic.ts").Diagnostic[];
1604
+ exitCode: number;
1605
+ } {
1606
+ if (command.subcommand === "validate") {
1607
+ const checked = readRepositoryManifest(command.workspaceRoot, { manifestPath: command.path });
1608
+ if (checked.manifest || checked.diagnostics.length) return { subcommand: "validate", path: command.path, diagnostics: checked.diagnostics.map(message => createDiagnostic({ severity: "error", code: "FORGE_REPOSITORY_MANIFEST", message })), exitCode: checked.manifest ? 0 : 1 };
1609
+ const result = readExternalManifestFile(command.path);
1610
+ const hasErrors = result.diagnostics.some((diagnostic) => diagnostic.severity === "error");
1611
+ return {
1612
+ subcommand: "validate",
1613
+ path: command.path,
1614
+ diagnostics: result.diagnostics,
1615
+ exitCode: hasErrors ? 1 : 0,
1616
+ };
1617
+ }
1618
+
1619
+ const result = importExternalManifest(command.workspaceRoot, command.path);
1620
+ const hasErrors = result.diagnostics.some((diagnostic) => diagnostic.severity === "error");
1621
+ return {
1622
+ subcommand: "import",
1623
+ path: result.path,
1624
+ imported: result.imported,
1625
+ serviceCount: result.graph.services.length,
1626
+ diagnostics: result.diagnostics,
1627
+ exitCode: hasErrors ? 1 : 0,
1628
+ };
1629
+ }
1630
+
378
1631
  export async function runInspectCommand(
379
1632
  target: InspectTarget,
380
1633
  workspaceRoot: string,
1634
+ options: { full?: boolean; brief?: boolean; ergonomics?: boolean } = {},
381
1635
  ): Promise<InspectResult> {
382
1636
  const dataPaths: Partial<Record<InspectTarget, string>> = {
383
1637
  app: `${GENERATED_DIR}/appGraph.json`,
@@ -396,6 +1650,7 @@ export async function runInspectCommand(
396
1650
  ai: `${GENERATED_DIR}/aiRegistry.json`,
397
1651
  queries: `${GENERATED_DIR}/queryRegistry.json`,
398
1652
  api: `${GENERATED_DIR}/api.json`,
1653
+ external: `${GENERATED_DIR}/externalServices.json`,
399
1654
  client: `${GENERATED_DIR}/clientManifest.json`,
400
1655
  frontend: `${GENERATED_DIR}/frontendGraph.json`,
401
1656
  auth: `${GENERATED_DIR}/authRegistry.json`,
@@ -431,7 +1686,155 @@ export async function runInspectCommand(
431
1686
  };
432
1687
  }
433
1688
 
1689
+ if (target === "summary") {
1690
+ return {
1691
+ target,
1692
+ data: buildInspectSummary(workspaceRoot),
1693
+ warnings: [],
1694
+ errors: [],
1695
+ exitCode: 0,
1696
+ };
1697
+ }
1698
+
1699
+ if (target === "schema") {
1700
+ const result = buildSchemaInspect(workspaceRoot);
1701
+ return {
1702
+ target,
1703
+ data: result.data,
1704
+ warnings: [],
1705
+ errors: result.errors,
1706
+ exitCode: result.errors.length > 0 ? 1 : 0,
1707
+ failureKind: result.errors.length > 0 ? "missing_artifact" : undefined,
1708
+ };
1709
+ }
1710
+
1711
+ if (target === "drift") {
1712
+ return {
1713
+ target,
1714
+ data: buildDriftInspect(workspaceRoot),
1715
+ warnings: [],
1716
+ errors: [],
1717
+ exitCode: 0,
1718
+ };
1719
+ }
1720
+
1721
+ if (target === "handoff") {
1722
+ return {
1723
+ target,
1724
+ data: buildHandoffInspect(workspaceRoot),
1725
+ warnings: [],
1726
+ errors: [],
1727
+ exitCode: 0,
1728
+ };
1729
+ }
1730
+
1731
+ if (target === "ui" && options.ergonomics) {
1732
+ const result = await runUiCommand({
1733
+ subcommand: "audit",
1734
+ workspaceRoot,
1735
+ json: true,
1736
+ headed: false,
1737
+ browser: "chromium",
1738
+ trace: "off",
1739
+ screenshot: "off",
1740
+ video: "off",
1741
+ baseUrl: "http://127.0.0.1:3000",
1742
+ runtimeUrl: "http://127.0.0.1:3765",
1743
+ reuseServers: false,
1744
+ startServers: false,
1745
+ all: true,
1746
+ changed: false,
1747
+ ci: false,
1748
+ timeoutMs: 30_000,
1749
+ });
1750
+ return {
1751
+ target,
1752
+ data: {
1753
+ schemaVersion: "0.1.0",
1754
+ mode: "ergonomics",
1755
+ ok: result.ok,
1756
+ manifest: result.manifest,
1757
+ scenarios: result.scenarios ?? [],
1758
+ diagnostics: result.diagnostics,
1759
+ nextActions: [
1760
+ "forge ui audit --json",
1761
+ "forge inspect frontend --json",
1762
+ "forge inspect capabilities --json",
1763
+ ],
1764
+ },
1765
+ warnings: result.diagnostics.filter((diagnostic) => diagnostic.severity === "warning"),
1766
+ errors: result.diagnostics.filter((diagnostic) => diagnostic.severity === "error"),
1767
+ exitCode: result.exitCode,
1768
+ failureKind: result.exitCode === 0 ? undefined : "ui_ergonomics",
1769
+ };
1770
+ }
1771
+
1772
+ if (target === "imported") {
1773
+ const result = inspectBrownfieldImport(workspaceRoot);
1774
+ return {
1775
+ target,
1776
+ data: formatBrownfieldImportJson(result),
1777
+ warnings: [],
1778
+ errors: [],
1779
+ exitCode: result.exitCode,
1780
+ failureKind: result.failureKind,
1781
+ };
1782
+ }
1783
+
434
1784
  if (target === "all") {
1785
+ if (options.brief) {
1786
+ const brief = buildInspectBrief(workspaceRoot);
1787
+ return {
1788
+ target,
1789
+ data: brief,
1790
+ warnings: [],
1791
+ errors: [],
1792
+ exitCode: 0,
1793
+ };
1794
+ }
1795
+ if (!options.full) {
1796
+ const summary = buildInspectSummary(workspaceRoot);
1797
+ const schema = buildSchemaInspect(workspaceRoot);
1798
+ const drift = buildDriftInspect(workspaceRoot);
1799
+ const handoff = buildHandoffInspect(workspaceRoot);
1800
+ const framework = buildFrameworkInspect(workspaceRoot);
1801
+ const errors = [
1802
+ ...schema.errors,
1803
+ ];
1804
+ return {
1805
+ target,
1806
+ data: {
1807
+ schemaVersion: "0.1.0",
1808
+ compact: true,
1809
+ payload: {
1810
+ mode: "compact",
1811
+ purpose: "agent diagnostic bundle",
1812
+ includes: ["summary", "schema", "drift", "handoff", "framework"],
1813
+ omitted: ["large generated registries", "module graph", "full runtime graph payloads"],
1814
+ fullCommand: "forge inspect all --full --json",
1815
+ briefCommand: "forge inspect all --brief --json",
1816
+ },
1817
+ summary: summary.summary,
1818
+ inspections: {
1819
+ summary,
1820
+ schema: schema.data,
1821
+ drift,
1822
+ handoff,
1823
+ framework,
1824
+ },
1825
+ nextActions: [
1826
+ "forge inspect summary --json",
1827
+ "forge inspect schema --json",
1828
+ "forge inspect handoff --json",
1829
+ "forge inspect all --full --json",
1830
+ ],
1831
+ },
1832
+ warnings: [],
1833
+ errors,
1834
+ exitCode: errors.length > 0 ? 1 : 0,
1835
+ failureKind: errors.length > 0 ? "missing_artifact" : undefined,
1836
+ };
1837
+ }
435
1838
  const aggregatePaths: Array<[string, string]> = [
436
1839
  ["app", `${GENERATED_DIR}/appGraph.json`],
437
1840
  ["data", `${GENERATED_DIR}/dataGraph.json`],
@@ -443,6 +1846,7 @@ export async function runInspectCommand(
443
1846
  ["workflows", `${GENERATED_DIR}/workflowRegistry.json`],
444
1847
  ["telemetry", `${GENERATED_DIR}/telemetryRegistry.json`],
445
1848
  ["ai", `${GENERATED_DIR}/aiRegistry.json`],
1849
+ ["externalServices", `${GENERATED_DIR}/externalServices.json`],
446
1850
  ["client", `${GENERATED_DIR}/clientManifest.json`],
447
1851
  ["frontend", `${GENERATED_DIR}/frontendGraph.json`],
448
1852
  ["auth", `${GENERATED_DIR}/authRegistry.json`],
@@ -467,6 +1871,7 @@ export async function runInspectCommand(
467
1871
  ];
468
1872
  const data: Record<string, unknown> = {};
469
1873
  const errors = [];
1874
+ data.summary = buildInspectSummary(workspaceRoot).summary;
470
1875
  for (const [key, relative] of aggregatePaths) {
471
1876
  const value = readGeneratedJson<unknown>(workspaceRoot, relative);
472
1877
  if (value === null) {
@@ -484,6 +1889,17 @@ export async function runInspectCommand(
484
1889
  }
485
1890
  data.framework = buildFrameworkInspect(workspaceRoot);
486
1891
  data.diagnostics = errors;
1892
+ data.compact = false;
1893
+ data.payload = {
1894
+ mode: "full",
1895
+ purpose: "complete generated machine contract",
1896
+ includes: aggregatePaths.map(([key]) => key),
1897
+ compactCommand: "forge inspect all --json",
1898
+ briefCommand: "forge inspect all --brief --json",
1899
+ };
1900
+ data.nextActions = errors.length > 0
1901
+ ? ["forge status --json", "forge generate", "forge check --json"]
1902
+ : ["forge inspect all --json", "forge check --json"];
487
1903
  return {
488
1904
  target,
489
1905
  data,
@@ -557,6 +1973,16 @@ export async function executeCommand(command: ForgeCommand): Promise<number> {
557
1973
  }
558
1974
  return 0;
559
1975
  }
1976
+ case "last": {
1977
+ const result = runLastCommand({ workspaceRoot: command.workspaceRoot });
1978
+ process.stdout.write(command.json ? formatLastJson(result) : formatLastHuman(result));
1979
+ return result.exitCode;
1980
+ }
1981
+ case "baseline": {
1982
+ const result = runBaselineCommand(command);
1983
+ process.stdout.write(command.json ? formatBaselineJson(result) : formatBaselineHuman(result));
1984
+ return result.exitCode;
1985
+ }
560
1986
  case "new": {
561
1987
  const result = await runNewCommand({
562
1988
  name: command.name,
@@ -564,11 +1990,12 @@ export async function executeCommand(command: ForgeCommand): Promise<number> {
564
1990
  packageManager: command.packageManager,
565
1991
  install: command.install,
566
1992
  git: command.git,
1993
+ fieldTest: command.fieldTest,
567
1994
  forgePackageSpec: command.forgePackageSpec,
568
1995
  localForge: command.localForge,
569
1996
  workspaceRoot: command.workspaceRoot,
570
1997
  });
571
- process.stdout.write(formatNewHuman(result));
1998
+ process.stdout.write(command.json ? formatNewJson(result) : formatNewHuman(result));
572
1999
  return result.exitCode;
573
2000
  }
574
2001
  case "build": {
@@ -598,6 +2025,15 @@ export async function executeCommand(command: ForgeCommand): Promise<number> {
598
2025
  }
599
2026
  return result.exitCode;
600
2027
  }
2028
+ case "docs": {
2029
+ const result = runDocsCheckCommand(command);
2030
+ if (command.json) {
2031
+ process.stdout.write(formatJsonResult(result));
2032
+ } else {
2033
+ process.stdout.write(formatDocsCheckHuman(result));
2034
+ }
2035
+ return result.exitCode;
2036
+ }
601
2037
  case "agent-contract": {
602
2038
  if (command.subcommand === "print") {
603
2039
  const result = runAgentContractPrint(command.workspaceRoot);
@@ -617,7 +2053,7 @@ export async function executeCommand(command: ForgeCommand): Promise<number> {
617
2053
  concurrency: 4,
618
2054
  });
619
2055
  if (command.json) {
620
- process.stdout.write(formatJsonResult(buildGenerateJson(result)));
2056
+ process.stdout.write(formatJsonResult(buildGenerateJson(result, { workspaceRoot: command.workspaceRoot })));
621
2057
  } else {
622
2058
  process.stdout.write(formatAgentContractHuman(command.subcommand, result));
623
2059
  writeHumanGenerate(result);
@@ -625,6 +2061,25 @@ export async function executeCommand(command: ForgeCommand): Promise<number> {
625
2061
  return result.exitCode;
626
2062
  }
627
2063
  case "doctor": {
2064
+ if (command.target === "agent") {
2065
+ const result = await runAgentCommand({
2066
+ subcommand: "doctor",
2067
+ workspaceRoot: command.workspaceRoot,
2068
+ json: command.json,
2069
+ target: command.agentTarget ?? "codex",
2070
+ dryRun: false,
2071
+ force: false,
2072
+ preserveUserSections: true,
2073
+ skills: true,
2074
+ rules: true,
2075
+ });
2076
+ if (command.json) {
2077
+ process.stdout.write(formatAgentJson(result));
2078
+ } else {
2079
+ process.stdout.write(formatAgentHuman(result));
2080
+ }
2081
+ return result.exitCode;
2082
+ }
628
2083
  if (command.target === "windows") {
629
2084
  const result = await runWindowsDoctorCommand({ workspaceRoot: command.workspaceRoot });
630
2085
  if (command.json) {
@@ -634,6 +2089,21 @@ export async function executeCommand(command: ForgeCommand): Promise<number> {
634
2089
  }
635
2090
  return result.exitCode;
636
2091
  }
2092
+ if (command.target === "delta") {
2093
+ const result = await runDeltaDoctor(command.workspaceRoot);
2094
+ process.stdout.write(command.json ? formatDeltaDoctorJson(result) : formatDeltaDoctorHuman(result));
2095
+ return result.exitCode;
2096
+ }
2097
+ if (command.target === "pglite") {
2098
+ const result = await runPgliteDoctorCommand({ workspaceRoot: command.workspaceRoot });
2099
+ process.stdout.write(command.json ? formatPgliteDoctorJson(result) : formatPgliteDoctorHuman(result));
2100
+ return result.exitCode;
2101
+ }
2102
+ if (command.target === "runtime") {
2103
+ const result = await runRuntimeDoctorCommand({ workspaceRoot: command.workspaceRoot });
2104
+ process.stdout.write(command.json ? formatRuntimeDoctorJson(result) : formatRuntimeDoctorHuman(result));
2105
+ return result.exitCode;
2106
+ }
637
2107
  const result = await runDoctorCommand({ workspaceRoot: command.workspaceRoot });
638
2108
  if (command.json) {
639
2109
  process.stdout.write(formatDoctorJson(result));
@@ -672,6 +2142,44 @@ export async function executeCommand(command: ForgeCommand): Promise<number> {
672
2142
  }
673
2143
  return result.exitCode;
674
2144
  }
2145
+ case "authmd": {
2146
+ const result = runAuthMdCommand(command);
2147
+ if (command.json) {
2148
+ process.stdout.write(formatAuthMdJson(result));
2149
+ } else {
2150
+ process.stdout.write(formatAuthMdHuman(result));
2151
+ }
2152
+ return result.exitCode;
2153
+ }
2154
+ case "workos": {
2155
+ const result = runWorkOSCommand(command);
2156
+ if (command.json) {
2157
+ process.stdout.write(formatWorkOSJson(result));
2158
+ } else {
2159
+ process.stdout.write(formatWorkOSHuman(result));
2160
+ }
2161
+ return result.exitCode;
2162
+ }
2163
+ case "deploy": {
2164
+ const result = await runDeployCommand(command);
2165
+ process.stdout.write(command.json ? formatDeployJson(result) : formatDeployHuman(result));
2166
+ return result.exitCode;
2167
+ }
2168
+ case "golden-path": {
2169
+ const result = await runGoldenPathCommand(command);
2170
+ process.stdout.write(command.json ? formatGoldenPathJson(result) : formatGoldenPathHuman(result));
2171
+ return result.exitCode;
2172
+ }
2173
+ case "field-test": {
2174
+ const result = await runFieldTestCommand(command);
2175
+ process.stdout.write(command.json ? formatFieldTestJson(result) : formatFieldTestHuman(result));
2176
+ return result.exitCode;
2177
+ }
2178
+ case "seed": {
2179
+ const result = await runSeedCommand(command);
2180
+ process.stdout.write(command.json ? formatSeedJson(result) : formatSeedHuman(result));
2181
+ return result.exitCode;
2182
+ }
675
2183
  case "rls": {
676
2184
  const result = await runRlsCommand(command);
677
2185
  if (command.json) {
@@ -691,6 +2199,30 @@ export async function executeCommand(command: ForgeCommand): Promise<number> {
691
2199
  return result.exitCode;
692
2200
  }
693
2201
  case "release": {
2202
+ if (command.action === "doctor") {
2203
+ const result = await runReleaseDoctorCommand(command);
2204
+ if (command.json) {
2205
+ process.stdout.write(formatJsonResult(result));
2206
+ } else {
2207
+ process.stdout.write(
2208
+ [
2209
+ `release doctor ${result.ok ? "ok" : "failed"}`,
2210
+ `ready to publish: ${result.readyToPublish ? "yes" : "no"}`,
2211
+ `ready for production deploy: ${result.readyForProductionDeploy ? "yes" : "no"}`,
2212
+ ...result.checks.map((check) => {
2213
+ const scope = check.requiredForPublish
2214
+ ? "publish"
2215
+ : check.requiredForProduction
2216
+ ? "production"
2217
+ : "optional";
2218
+ return `${check.ok ? "ok" : "fail"} ${check.name} [${scope}]${check.state ? ` (${check.state})` : ""}`;
2219
+ }),
2220
+ ...(result.nextActions.length > 0 ? ["", "Next:", ...result.nextActions.map((action) => ` ${action}`)] : []),
2221
+ ].join("\n").concat("\n"),
2222
+ );
2223
+ }
2224
+ return result.exitCode;
2225
+ }
694
2226
  const result = await runReleaseCommand({
695
2227
  ...command,
696
2228
  provider: command.provider as import("../compiler/release/types.ts").ReleaseExportProvider | undefined,
@@ -766,19 +2298,143 @@ export async function executeCommand(command: ForgeCommand): Promise<number> {
766
2298
  }
767
2299
  return result.exitCode;
768
2300
  }
769
- case "agent": {
770
- const result = await runAgentCommand(command.options);
771
- if (command.options.json) {
772
- process.stdout.write(formatAgentJson(result));
773
- } else {
774
- process.stdout.write(formatAgentHuman(result));
2301
+ case "bench": {
2302
+ const result = await runCompilerBenchCommand(command.options);
2303
+ process.stdout.write(
2304
+ command.options.json
2305
+ ? formatCompilerBenchJson(result)
2306
+ : formatCompilerBenchHuman(result),
2307
+ );
2308
+ return result.exitCode;
2309
+ }
2310
+ case "cair": {
2311
+ let root: string;
2312
+ try { root = await resolveRepositoryRoot({ cwd: command.options.workspaceRoot, root: command.options.root, projectId: command.options.projectId, manifestPath: command.options.manifestPath }); }
2313
+ catch (error) {
2314
+ const diagnostic = createDiagnostic({ severity: "error", code: "FORGE_REPOSITORY_ROOT", message: (error as Error).message });
2315
+ if (command.options.json || command.options.format === "json") process.stdout.write(formatJsonResult({ ok: false, diagnostics: [diagnostic], exitCode: 1 }));
2316
+ else console.error(`error ${diagnostic.code}: ${diagnostic.message}`);
2317
+ return 1;
2318
+ }
2319
+ const repository = readRepositoryManifest(root, { manifestPath: command.options.manifestPath });
2320
+ if (repository.manifest || repository.diagnostics.length || command.options.root || command.options.projectId) command.options.workspaceRoot = root;
2321
+ const result = runCairCommand(command.options);
2322
+ process.stdout.write(
2323
+ command.options.json || command.options.format === "json"
2324
+ ? formatCairJson(result)
2325
+ : formatCairHuman(result),
2326
+ );
2327
+ return result.exitCode;
2328
+ }
2329
+ case "delta": {
2330
+ if (command.subcommand === "compact") {
2331
+ const result = await runDeltaCompact({
2332
+ workspaceRoot: command.workspaceRoot,
2333
+ dryRun: command.dryRun,
2334
+ });
2335
+ process.stdout.write(command.json ? formatDeltaCompactJson(result) : formatDeltaCompactHuman(result));
2336
+ return result.exitCode;
2337
+ }
2338
+ if (command.subcommand === "prune") {
2339
+ const result = await runDeltaPrune({
2340
+ workspaceRoot: command.workspaceRoot,
2341
+ olderThan: command.olderThan,
2342
+ dryRun: command.dryRun,
2343
+ yes: command.yes,
2344
+ });
2345
+ process.stdout.write(command.json ? formatDeltaPruneJson(result) : formatDeltaPruneHuman(result));
2346
+ return result.exitCode;
775
2347
  }
2348
+ if (command.subcommand === "export") {
2349
+ const result = await runDeltaExport({
2350
+ workspaceRoot: command.workspaceRoot,
2351
+ redacted: command.redacted,
2352
+ output: command.output,
2353
+ limit: command.limit,
2354
+ });
2355
+ process.stdout.write(command.json ? formatDeltaExportJson(result) : formatDeltaExportHuman(result));
2356
+ return result.exitCode;
2357
+ }
2358
+ if (command.subcommand === "repair") {
2359
+ const result = await runDeltaRepair({
2360
+ workspaceRoot: command.workspaceRoot,
2361
+ dryRun: command.dryRun,
2362
+ yes: command.yes,
2363
+ });
2364
+ process.stdout.write(command.json ? formatDeltaRepairJson(result) : formatDeltaRepairHuman(result));
2365
+ return result.exitCode;
2366
+ }
2367
+ const result = await runDeltaStatus(command.workspaceRoot, { verbose: command.verbose });
2368
+ process.stdout.write(command.json ? formatDeltaStatusJson(result) : formatDeltaStatusHuman(result));
2369
+ return result.exitCode;
2370
+ }
2371
+ case "session": {
2372
+ const result = await runDeltaSessionCommand({
2373
+ workspaceRoot: command.workspaceRoot,
2374
+ subcommand: command.subcommand,
2375
+ sessionId: command.sessionId,
2376
+ sourceSessionId: command.sourceSessionId,
2377
+ operationId: command.operationId,
2378
+ title: command.title,
2379
+ limit: command.limit,
2380
+ });
2381
+ process.stdout.write(command.json ? formatDeltaSessionJson(result) : formatDeltaSessionHuman(result));
776
2382
  return result.exitCode;
777
2383
  }
2384
+ case "timeline": {
2385
+ const result = await runDeltaTimeline({
2386
+ workspaceRoot: command.workspaceRoot,
2387
+ target: command.target,
2388
+ kind: command.kindFilter,
2389
+ session: command.sessionId,
2390
+ limit: command.limit,
2391
+ rebuild: command.rebuild,
2392
+ causal: command.causal,
2393
+ staleProofs: command.staleProofs,
2394
+ });
2395
+ process.stdout.write(command.json ? formatDeltaTimelineJson(result) : formatDeltaTimelineHuman(result));
2396
+ return result.exitCode;
2397
+ }
2398
+ case "explain": {
2399
+ const result = await runDeltaExplain({
2400
+ workspaceRoot: command.workspaceRoot,
2401
+ thing: command.thing,
2402
+ });
2403
+ process.stdout.write(command.json ? formatDeltaExplainJson(result) : formatDeltaExplainHuman(result));
2404
+ return result.exitCode;
2405
+ }
2406
+ case "agent": {
2407
+ const heartbeat = command.options.subcommand === "onboard"
2408
+ ? startCommandHeartbeat({
2409
+ label: `agent onboard ${command.options.target ?? "codex"}`,
2410
+ initialPhase: "prepare-hooks-memory-and-dev-snapshot",
2411
+ })
2412
+ : null;
2413
+ try {
2414
+ const result = await runAgentCommand(command.options);
2415
+ if (command.options.json) {
2416
+ process.stdout.write(formatAgentJson(result));
2417
+ } else {
2418
+ process.stdout.write(formatAgentHuman(result));
2419
+ }
2420
+ return result.exitCode;
2421
+ } finally {
2422
+ heartbeat?.stop();
2423
+ }
2424
+ }
2425
+ case "fabric": {
2426
+ return runFabricCommand(command);
2427
+ }
2428
+ case "evolution": {
2429
+ return runEvolutionCommand(command);
2430
+ }
2431
+ case "mcp": {
2432
+ return runMcpServe(command.workspaceRoot);
2433
+ }
778
2434
  case "review": {
779
2435
  const result = runReviewCommand(command.options);
780
2436
  if (command.options.json) {
781
- process.stdout.write(formatReviewJson(result));
2437
+ process.stdout.write(formatReviewJson(result, { full: command.options.full }));
782
2438
  } else if (command.options.md && result.report) {
783
2439
  process.stdout.write(renderReviewMarkdown(result.report));
784
2440
  } else if (command.options.sarif && result.report && !command.options.write) {
@@ -802,7 +2458,7 @@ export async function executeCommand(command: ForgeCommand): Promise<number> {
802
2458
  }
803
2459
  case "generate": {
804
2460
  const result = await runGenerateCommand({
805
- workspaceRoot: process.cwd(),
2461
+ workspaceRoot: command.workspaceRoot,
806
2462
  check: command.check,
807
2463
  dryRun: command.dryRun,
808
2464
  json: command.json,
@@ -810,7 +2466,7 @@ export async function executeCommand(command: ForgeCommand): Promise<number> {
810
2466
  });
811
2467
 
812
2468
  if (command.json) {
813
- process.stdout.write(formatJsonResult(buildGenerateJson(result)));
2469
+ process.stdout.write(formatJsonResult(buildGenerateJson(result, { workspaceRoot: command.workspaceRoot })));
814
2470
  } else {
815
2471
  writeHumanGenerate(result);
816
2472
  }
@@ -820,16 +2476,162 @@ export async function executeCommand(command: ForgeCommand): Promise<number> {
820
2476
  case "add": {
821
2477
  const result = await runAddCommand(command.alias, command.options);
822
2478
  if (command.options.json) {
823
- process.stdout.write(formatJsonResult(buildAddJson(result)));
2479
+ process.stdout.write(formatJsonResult(buildAddJson(result, { workspaceRoot: command.options.workspaceRoot })));
824
2480
  } else {
825
2481
  writeHumanAdd(result);
826
2482
  }
827
2483
  return result.exitCode;
828
2484
  }
2485
+ case "manifest": {
2486
+ const result = runManifestCommand(command);
2487
+ if (command.json) {
2488
+ process.stdout.write(formatJsonResult(result));
2489
+ } else {
2490
+ process.stdout.write(formatManifestHuman(result));
2491
+ }
2492
+ return result.exitCode;
2493
+ }
2494
+ case "repository": {
2495
+ const result = await runRepositoryCommand(command.options);
2496
+ process.stdout.write(`${JSON.stringify(result, null, command.options.json ? 2 : 2)}\n`);
2497
+ return result.exitCode;
2498
+ }
2499
+ case "import": {
2500
+ const result = runBrownfieldImportCommand(command.options);
2501
+ if (command.options.json) {
2502
+ process.stdout.write(formatJsonResult(formatBrownfieldImportJson(result)));
2503
+ } else {
2504
+ process.stdout.write(formatBrownfieldImportHuman(result));
2505
+ }
2506
+ return result.exitCode;
2507
+ }
2508
+ case "status": {
2509
+ const result = await runStatusCommand(command.workspaceRoot);
2510
+ if (command.json) {
2511
+ process.stdout.write(formatJsonResult(result.data));
2512
+ } else {
2513
+ process.stdout.write(formatStatusHuman(result));
2514
+ }
2515
+ return result.exitCode;
2516
+ }
2517
+ case "changed": {
2518
+ const result = runChangedCommand(command.workspaceRoot, {
2519
+ authoredOnly: command.authoredOnly,
2520
+ reviewOnly: command.reviewOnly,
2521
+ commitReady: command.commitReady,
2522
+ });
2523
+ if (command.json) {
2524
+ process.stdout.write(formatJsonResult(result.data));
2525
+ } else {
2526
+ process.stdout.write(formatChangedHuman(result));
2527
+ }
2528
+ return result.exitCode;
2529
+ }
2530
+ case "diff": {
2531
+ const changed = runChangedCommand(command.workspaceRoot);
2532
+ const diffPlan = changed.data.diffPlan as { authoredDiffCommand: string; generatedDiffCommand: string; fullDiffCommand: string };
2533
+ const gitSummary = command.target === "authored" ? buildWorkspaceGitSummary(command.workspaceRoot) : null;
2534
+ const authoredPaths = gitSummary ? authoredChangePaths(gitSummary.changeSummary.changed) : null;
2535
+ const authoredAvailable = command.target !== "authored" || (gitSummary?.available === true && authoredPaths !== null);
2536
+ const exitCode = changed.exitCode === 0 && authoredAvailable ? 0 : 1;
2537
+ const commandText = command.target === "generated"
2538
+ ? diffPlan.generatedDiffCommand
2539
+ : command.target === "full"
2540
+ ? diffPlan.fullDiffCommand
2541
+ : diffPlan.authoredDiffCommand;
2542
+ if (command.json) {
2543
+ process.stdout.write(formatJsonResult({
2544
+ schemaVersion: "0.1.0",
2545
+ ok: exitCode === 0,
2546
+ target: command.target,
2547
+ command: commandText,
2548
+ exitCode,
2549
+ }));
2550
+ return exitCode;
2551
+ }
2552
+ if (command.target === "authored") {
2553
+ if (!authoredAvailable || !authoredPaths) return 1;
2554
+ if (authoredPaths.length === 0) return 0;
2555
+ const result = spawnSync("git", ["diff", "--", ...authoredPaths.map((file) => `:(top,literal)${file}`)], {
2556
+ cwd: command.workspaceRoot,
2557
+ stdio: "inherit",
2558
+ windowsHide: true,
2559
+ });
2560
+ return result.status === 0 ? 0 : 1;
2561
+ }
2562
+ const result = spawnSync(commandText, {
2563
+ cwd: command.workspaceRoot,
2564
+ shell: true,
2565
+ stdio: "inherit",
2566
+ windowsHide: true,
2567
+ });
2568
+ return result.status === 0 ? 0 : 1;
2569
+ }
2570
+ case "handoff": {
2571
+ const result = await runHandoffCommand(command);
2572
+ process.stdout.write(command.json ? formatHandoffJson(result) : formatHandoffHuman(result));
2573
+ return result.exitCode;
2574
+ }
2575
+ case "studio": {
2576
+ if (command.subcommand === "bridge" && !command.once && !command.dryRun) {
2577
+ return runStudioBridgeLoop(command, (result) => {
2578
+ process.stdout.write(command.json ? formatStudioBridgeEventJson(result) : formatStudioBridgeHuman(result));
2579
+ });
2580
+ }
2581
+ if (command.subcommand === "watch" && !command.once && !command.dryRun) {
2582
+ return runStudioWatchLoop(command, (result) => {
2583
+ process.stdout.write(command.json ? formatStudioWatchJson(result) : formatStudioWatchHuman(result));
2584
+ });
2585
+ }
2586
+ const result = command.subcommand === "snapshot"
2587
+ ? await runStudioSnapshotCommand(command)
2588
+ : command.subcommand === "watch"
2589
+ ? await runStudioWatchCommand(command)
2590
+ : command.subcommand === "bridge"
2591
+ ? await runStudioBridgeCommand(command)
2592
+ : command.subcommand === "codex-server"
2593
+ ? await runStudioCodexServerCommand(command)
2594
+ : command.subcommand === "doctor"
2595
+ ? await runStudioDoctorCommand(command)
2596
+ : command.subcommand === "open"
2597
+ ? await runStudioOpenCommand(command)
2598
+ : await runStudioAttachCommand(command);
2599
+ process.stdout.write(
2600
+ command.json
2601
+ ? command.subcommand === "snapshot"
2602
+ ? formatStudioSnapshotJson(result as Awaited<ReturnType<typeof runStudioSnapshotCommand>>)
2603
+ : command.subcommand === "watch"
2604
+ ? formatStudioWatchJson(result as Awaited<ReturnType<typeof runStudioWatchCommand>>)
2605
+ : command.subcommand === "bridge"
2606
+ ? formatStudioBridgeJson(result as Awaited<ReturnType<typeof runStudioBridgeCommand>>)
2607
+ : command.subcommand === "codex-server"
2608
+ ? formatStudioCodexServerJson(result as Awaited<ReturnType<typeof runStudioCodexServerCommand>>)
2609
+ : command.subcommand === "doctor"
2610
+ ? formatStudioDoctorJson(result as Awaited<ReturnType<typeof runStudioDoctorCommand>>)
2611
+ : command.subcommand === "open"
2612
+ ? formatStudioOpenJson(result as Awaited<ReturnType<typeof runStudioOpenCommand>>)
2613
+ : formatStudioAttachJson(result as Awaited<ReturnType<typeof runStudioAttachCommand>>)
2614
+ : command.subcommand === "snapshot"
2615
+ ? formatStudioSnapshotHuman(result as Awaited<ReturnType<typeof runStudioSnapshotCommand>>)
2616
+ : command.subcommand === "watch"
2617
+ ? formatStudioWatchHuman(result as Awaited<ReturnType<typeof runStudioWatchCommand>>)
2618
+ : command.subcommand === "bridge"
2619
+ ? formatStudioBridgeHuman(result as Awaited<ReturnType<typeof runStudioBridgeCommand>>)
2620
+ : command.subcommand === "codex-server"
2621
+ ? formatStudioCodexServerHuman(result as Awaited<ReturnType<typeof runStudioCodexServerCommand>>)
2622
+ : command.subcommand === "doctor"
2623
+ ? formatStudioDoctorHuman(result as Awaited<ReturnType<typeof runStudioDoctorCommand>>)
2624
+ : command.subcommand === "open"
2625
+ ? formatStudioOpenHuman(result as Awaited<ReturnType<typeof runStudioOpenCommand>>)
2626
+ : formatStudioAttachHuman(result as Awaited<ReturnType<typeof runStudioAttachCommand>>),
2627
+ );
2628
+ return result.exitCode;
2629
+ }
829
2630
  case "inspect": {
830
2631
  const result = await runInspectCommand(
831
2632
  command.target,
832
- process.cwd(),
2633
+ command.workspaceRoot,
2634
+ { full: command.full, brief: command.brief, ergonomics: command.ergonomics },
833
2635
  );
834
2636
  if (command.json) {
835
2637
  process.stdout.write(formatJsonResult(buildInspectJson(result)));
@@ -841,11 +2643,12 @@ export async function executeCommand(command: ForgeCommand): Promise<number> {
841
2643
  return result.exitCode;
842
2644
  }
843
2645
  case "check": {
844
- const result = await runCheckCommand(process.cwd(), {
2646
+ const checkWorkspaceRoot = process.cwd();
2647
+ const result = await runCheckCommand(checkWorkspaceRoot, {
845
2648
  strictSecrets: command.strictSecrets,
846
2649
  });
847
2650
  if (command.json) {
848
- process.stdout.write(formatJsonResult(buildGenerateJson(result)));
2651
+ process.stdout.write(formatJsonResult(buildCheckJson(result, { workspaceRoot: checkWorkspaceRoot })));
849
2652
  } else {
850
2653
  writeHumanGenerate(result);
851
2654
  }
@@ -867,6 +2670,32 @@ export async function executeCommand(command: ForgeCommand): Promise<number> {
867
2670
  );
868
2671
 
869
2672
  if (command.queryMode && command.name) {
2673
+ const external = resolveExternalQualifiedName(command.workspaceRoot, command.name, "query");
2674
+ if (external) {
2675
+ const run = await runExternalEntry(command.workspaceRoot, {
2676
+ kind: "query",
2677
+ serviceName: external.serviceName,
2678
+ entryName: external.entryName,
2679
+ args: command.args,
2680
+ auth: resolveAuthFromCli({
2681
+ userId: command.userId,
2682
+ tenantId: command.tenantId,
2683
+ role: command.role,
2684
+ }),
2685
+ });
2686
+ const payload = { run };
2687
+ if (command.json) {
2688
+ process.stdout.write(`${JSON.stringify(payload, null, 2)}\n`);
2689
+ } else {
2690
+ process.stdout.write(
2691
+ run.ok
2692
+ ? `${JSON.stringify(run.result, null, 2)}\n`
2693
+ : `${run.diagnostics.map((diagnostic) => `error ${diagnostic.code}: ${diagnostic.message}`).join("\n")}\n`,
2694
+ );
2695
+ }
2696
+ return run.exitCode;
2697
+ }
2698
+
870
2699
  const tableMap = readGeneratedJson<{ tableMap: Record<string, import("../compiler/data-graph/sql/serialize.ts").TableMapEntry> }>(
871
2700
  command.workspaceRoot,
872
2701
  `${GENERATED_DIR}/db.json`,
@@ -905,6 +2734,7 @@ export async function executeCommand(command: ForgeCommand): Promise<number> {
905
2734
  userId: command.userId,
906
2735
  tenantId: command.tenantId,
907
2736
  role: command.role,
2737
+ args: command.args,
908
2738
  workspaceRoot: command.workspaceRoot,
909
2739
  });
910
2740
 
@@ -940,8 +2770,15 @@ export async function executeCommand(command: ForgeCommand): Promise<number> {
940
2770
  webOnly: command.webOnly,
941
2771
  open: command.open,
942
2772
  webPort: command.webPort,
2773
+ publicApiUrl: command.publicApiUrl,
943
2774
  telemetry: command.telemetry,
944
2775
  envFile: command.envFile,
2776
+ skipStartupConsole: command.skipStartupConsole,
2777
+ detach: command.detach,
2778
+ seed: command.seed,
2779
+ seedCommand: command.seedCommand,
2780
+ seedAllTenants: command.seedAllTenants,
2781
+ lifecycle: command.lifecycle,
945
2782
  });
946
2783
  return result.exitCode;
947
2784
  }
@@ -967,6 +2804,7 @@ export async function executeCommand(command: ForgeCommand): Promise<number> {
967
2804
  workspaceRoot: command.workspaceRoot,
968
2805
  db: command.db,
969
2806
  databaseUrl: command.databaseUrl,
2807
+ local: command.local,
970
2808
  json: command.json,
971
2809
  });
972
2810
 
@@ -1087,6 +2925,7 @@ export async function executeCommand(command: ForgeCommand): Promise<number> {
1087
2925
  workspaceRoot: command.workspaceRoot,
1088
2926
  json: command.json,
1089
2927
  redacted: command.redacted,
2928
+ target: command.target,
1090
2929
  });
1091
2930
 
1092
2931
  if (command.json) {
@@ -1160,5 +2999,5 @@ export async function executeCommand(command: ForgeCommand): Promise<number> {
1160
2999
  }
1161
3000
  }
1162
3001
 
1163
- export { runVerifyCommand };
3002
+ export { runChangedCommand, runVerifyCommand };
1164
3003
  export type { VerifyOptions, VerifyResult };