forgeos 0.1.0-alpha.3 → 0.1.0-alpha.30

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 (400) hide show
  1. package/.npmignore +10 -0
  2. package/AGENTS.md +142 -90
  3. package/CHANGELOG.md +321 -0
  4. package/LICENSE +21 -0
  5. package/README.md +86 -13
  6. package/adapters/go/README.md +23 -0
  7. package/adapters/go/go.mod +3 -0
  8. package/adapters/go/http.go +149 -0
  9. package/adapters/go/registry.go +234 -0
  10. package/adapters/go/types.go +136 -0
  11. package/adapters/java/README.md +68 -0
  12. package/adapters/java/pom.xml +34 -0
  13. package/adapters/java/src/main/java/dev/forgeos/adapter/Auth.java +20 -0
  14. package/adapters/java/src/main/java/dev/forgeos/adapter/Diagnostic.java +16 -0
  15. package/adapters/java/src/main/java/dev/forgeos/adapter/Entry.java +38 -0
  16. package/adapters/java/src/main/java/dev/forgeos/adapter/EntryKind.java +16 -0
  17. package/adapters/java/src/main/java/dev/forgeos/adapter/ErrorInfo.java +4 -0
  18. package/adapters/java/src/main/java/dev/forgeos/adapter/Forge.java +94 -0
  19. package/adapters/java/src/main/java/dev/forgeos/adapter/ForgeCall.java +12 -0
  20. package/adapters/java/src/main/java/dev/forgeos/adapter/ForgeContext.java +11 -0
  21. package/adapters/java/src/main/java/dev/forgeos/adapter/ForgeHandler.java +8 -0
  22. package/adapters/java/src/main/java/dev/forgeos/adapter/ForgeHttpHandler.java +179 -0
  23. package/adapters/java/src/main/java/dev/forgeos/adapter/ForgeRegistry.java +121 -0
  24. package/adapters/java/src/main/java/dev/forgeos/adapter/Json.java +14 -0
  25. package/adapters/java/src/main/java/dev/forgeos/adapter/Manifest.java +14 -0
  26. package/adapters/java/src/main/java/dev/forgeos/adapter/RequestEnvelope.java +6 -0
  27. package/adapters/java/src/main/java/dev/forgeos/adapter/ResponseEnvelope.java +25 -0
  28. package/adapters/java/src/main/java/dev/forgeos/adapter/Risk.java +18 -0
  29. package/adapters/java/src/main/java/dev/forgeos/adapter/Schemas.java +36 -0
  30. package/adapters/java/src/main/java/dev/forgeos/adapter/Service.java +65 -0
  31. package/adapters/java/src/main/java/dev/forgeos/adapter/TransactionMode.java +18 -0
  32. package/adapters/java/src/main/java/dev/forgeos/adapter/TypedForgeHandler.java +6 -0
  33. package/adapters/java-spring-boot-starter/README.md +32 -0
  34. package/adapters/java-spring-boot-starter/pom.xml +36 -0
  35. package/adapters/java-spring-boot-starter/src/main/java/dev/forgeos/adapter/spring/ForgeCommand.java +22 -0
  36. package/adapters/java-spring-boot-starter/src/main/java/dev/forgeos/adapter/spring/ForgeExternalService.java +15 -0
  37. package/adapters/java-spring-boot-starter/src/main/java/dev/forgeos/adapter/spring/ForgeQuery.java +16 -0
  38. package/adapters/java-spring-boot-starter/src/main/java/dev/forgeos/adapter/spring/ForgeServiceBeanCondition.java +18 -0
  39. package/adapters/java-spring-boot-starter/src/main/java/dev/forgeos/adapter/spring/ForgeSpringAutoConfiguration.java +16 -0
  40. package/adapters/java-spring-boot-starter/src/main/java/dev/forgeos/adapter/spring/ForgeSpringRuntime.java +104 -0
  41. package/adapters/java-spring-boot-starter/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports +1 -0
  42. package/bin/forge.mjs +18 -0
  43. package/docs/cair-protocol.md +103 -0
  44. package/docs/changelog.md +366 -0
  45. package/docs/forge-protocol.md +189 -0
  46. package/examples/go-billing/go.mod +7 -0
  47. package/examples/go-billing/main.go +120 -0
  48. package/examples/java-billing/pom.xml +52 -0
  49. package/examples/java-billing/src/main/java/dev/forgeos/examples/billing/CreateInvoiceInput.java +4 -0
  50. package/examples/java-billing/src/main/java/dev/forgeos/examples/billing/Invoice.java +11 -0
  51. package/examples/java-billing/src/main/java/dev/forgeos/examples/billing/Main.java +127 -0
  52. package/package.json +34 -4
  53. package/schemas/forge-manifest.schema.json +57 -0
  54. package/src/forge/_generated/releaseManifest.json +1 -2
  55. package/src/forge/_generated/releaseManifest.ts +3 -3
  56. package/src/forge/agent-adapters/index.ts +1556 -123
  57. package/src/forge/agent-adapters/types.ts +224 -1
  58. package/src/forge/agent-memory/bridge.ts +1333 -0
  59. package/src/forge/agent-memory/context-pack.ts +277 -0
  60. package/src/forge/agent-memory/hook-runner.ts +312 -0
  61. package/src/forge/agent-memory/mcp.ts +224 -0
  62. package/src/forge/agent-memory/normalize.ts +498 -0
  63. package/src/forge/agent-memory/redaction.ts +103 -0
  64. package/src/forge/agent-memory/sources/claude-code.ts +51 -0
  65. package/src/forge/agent-memory/sources/codex-hook-runner.mjs +273 -0
  66. package/src/forge/agent-memory/sources/codex.ts +119 -0
  67. package/src/forge/agent-memory/sources/cursor.ts +35 -0
  68. package/src/forge/agent-memory/types.ts +204 -0
  69. package/src/forge/bench.ts +248 -0
  70. package/src/forge/brownfield-import/index.ts +801 -0
  71. package/src/forge/brownfield-import/types.ts +127 -0
  72. package/src/forge/cair/action-journal.ts +61 -0
  73. package/src/forge/cair/action-parser.ts +314 -0
  74. package/src/forge/cair/action-validator.ts +40 -0
  75. package/src/forge/cair/actions.ts +1818 -0
  76. package/src/forge/cair/format.ts +77 -0
  77. package/src/forge/cair/index.ts +106 -0
  78. package/src/forge/cair/query.ts +478 -0
  79. package/src/forge/cair/snapshot.ts +315 -0
  80. package/src/forge/cair/types.ts +248 -0
  81. package/src/forge/cli/ai.ts +485 -2
  82. package/src/forge/cli/auth.ts +92 -2
  83. package/src/forge/cli/authmd.ts +356 -0
  84. package/src/forge/cli/build.ts +20 -4
  85. package/src/forge/cli/changed.ts +306 -0
  86. package/src/forge/cli/codex-app-server.ts +877 -0
  87. package/src/forge/cli/commands.ts +1357 -9
  88. package/src/forge/cli/db.ts +121 -2
  89. package/src/forge/cli/deps.ts +79 -12
  90. package/src/forge/cli/dev.ts +502 -38
  91. package/src/forge/cli/docs.ts +265 -0
  92. package/src/forge/cli/handoff.ts +253 -0
  93. package/src/forge/cli/index.ts +1 -0
  94. package/src/forge/cli/main.ts +59 -3
  95. package/src/forge/cli/new.ts +13 -1
  96. package/src/forge/cli/next-actions.ts +23 -0
  97. package/src/forge/cli/output.ts +302 -1
  98. package/src/forge/cli/parse.ts +862 -34
  99. package/src/forge/cli/query.ts +32 -0
  100. package/src/forge/cli/release.ts +35 -11
  101. package/src/forge/cli/rls.ts +568 -17
  102. package/src/forge/cli/run.ts +41 -0
  103. package/src/forge/cli/secrets.ts +46 -1
  104. package/src/forge/cli/security.ts +381 -0
  105. package/src/forge/cli/self-host.ts +56 -14
  106. package/src/forge/cli/studio.ts +2217 -0
  107. package/src/forge/cli/verify.ts +1424 -32
  108. package/src/forge/cli/workos.ts +340 -0
  109. package/src/forge/compiler/agent-contract/build.ts +637 -51
  110. package/src/forge/compiler/agent-contract/types.ts +47 -2
  111. package/src/forge/compiler/ai-registry/parse.ts +71 -2
  112. package/src/forge/compiler/api-surface/build.ts +47 -0
  113. package/src/forge/compiler/app-graph/build.ts +68 -8
  114. package/src/forge/compiler/app-graph/extract.ts +107 -0
  115. package/src/forge/compiler/app-graph/module-graph.ts +73 -78
  116. package/src/forge/compiler/app-graph/parser.ts +24 -24
  117. package/src/forge/compiler/app-graph/profile.ts +26 -0
  118. package/src/forge/compiler/app-graph/versions.ts +1 -1
  119. package/src/forge/compiler/classifier/capabilities.ts +3 -2
  120. package/src/forge/compiler/classifier/classify.ts +32 -8
  121. package/src/forge/compiler/classifier/secrets.ts +3 -2
  122. package/src/forge/compiler/classifier/signals.ts +91 -1
  123. package/src/forge/compiler/client-sdk/build-manifest.ts +59 -0
  124. package/src/forge/compiler/client-sdk/render-client.ts +188 -13
  125. package/src/forge/compiler/data-graph/parse.ts +3 -3
  126. package/src/forge/compiler/data-graph/sql/ddl.ts +60 -2
  127. package/src/forge/compiler/data-graph/sql/serialize.ts +4 -0
  128. package/src/forge/compiler/data-graph/sql/types.ts +1 -0
  129. package/src/forge/compiler/diagnostics/codes.ts +35 -0
  130. package/src/forge/compiler/diagnostics/create.ts +8 -3
  131. package/src/forge/compiler/diagnostics/index.ts +2 -0
  132. package/src/forge/compiler/emitter/barrel.ts +3 -0
  133. package/src/forge/compiler/emitter/render.ts +9 -0
  134. package/src/forge/compiler/external-manifest/registry.ts +205 -0
  135. package/src/forge/compiler/external-manifest/types.ts +91 -0
  136. package/src/forge/compiler/external-manifest/validate.ts +373 -0
  137. package/src/forge/compiler/frontend-graph/build.ts +142 -14
  138. package/src/forge/compiler/integration/add.ts +536 -23
  139. package/src/forge/compiler/integration/plan.ts +17 -11
  140. package/src/forge/compiler/integration/render.ts +20 -0
  141. package/src/forge/compiler/integration/snapshot.ts +2 -0
  142. package/src/forge/compiler/integration/templates/convex.ts +70 -0
  143. package/src/forge/compiler/integration/templates/index.ts +1 -0
  144. package/src/forge/compiler/integration/templates/render.ts +34 -0
  145. package/src/forge/compiler/integration/templates/workos.ts +1063 -0
  146. package/src/forge/compiler/make-registry/build.ts +6 -7
  147. package/src/forge/compiler/orchestrator/fast-check.ts +4 -0
  148. package/src/forge/compiler/orchestrator/manifest.ts +1 -1
  149. package/src/forge/compiler/orchestrator/plan-profile.ts +23 -0
  150. package/src/forge/compiler/orchestrator/plan.ts +240 -10
  151. package/src/forge/compiler/orchestrator/profile.ts +65 -0
  152. package/src/forge/compiler/orchestrator/run.ts +97 -31
  153. package/src/forge/compiler/orchestrator/serialize.ts +33 -8
  154. package/src/forge/compiler/orchestrator/types.ts +1 -1
  155. package/src/forge/compiler/package-graph/compiler.ts +13 -3
  156. package/src/forge/compiler/package-manager/adapter.ts +4 -1
  157. package/src/forge/compiler/package-manager/commands.ts +4 -0
  158. package/src/forge/compiler/package-manager/executor.ts +30 -1
  159. package/src/forge/compiler/policy-registry/build.ts +47 -2
  160. package/src/forge/compiler/policy-registry/parse.ts +32 -2
  161. package/src/forge/compiler/recipes/definitions.ts +63 -0
  162. package/src/forge/compiler/recipes/index.ts +2 -0
  163. package/src/forge/compiler/recipes/registry.ts +6 -0
  164. package/src/forge/compiler/test-graph/build.ts +11 -3
  165. package/src/forge/compiler/types/app-graph.ts +8 -2
  166. package/src/forge/compiler/types/cli.ts +75 -1
  167. package/src/forge/compiler/types/dev-manifest.ts +4 -0
  168. package/src/forge/compiler/types/emit.ts +2 -0
  169. package/src/forge/compiler/types/frontend-graph.ts +2 -2
  170. package/src/forge/compiler/types/integration.ts +1 -0
  171. package/src/forge/compiler/types/policy-registry.ts +3 -1
  172. package/src/forge/delta/classifier.ts +52 -0
  173. package/src/forge/delta/explain.ts +238 -0
  174. package/src/forge/delta/git-observer.ts +43 -0
  175. package/src/forge/delta/ids.ts +44 -0
  176. package/src/forge/delta/index.ts +25 -0
  177. package/src/forge/delta/recorder.ts +540 -0
  178. package/src/forge/delta/redaction.ts +50 -0
  179. package/src/forge/delta/schema.ts +240 -0
  180. package/src/forge/delta/session.ts +142 -0
  181. package/src/forge/delta/status.ts +1126 -0
  182. package/src/forge/delta/store.ts +3284 -0
  183. package/src/forge/delta/timeline.ts +178 -0
  184. package/src/forge/dev/server.ts +777 -17
  185. package/src/forge/dev/types.ts +15 -1
  186. package/src/forge/dev/watch.ts +17 -7
  187. package/src/forge/dev-console/cycle.ts +233 -21
  188. package/src/forge/dev-console/types.ts +46 -1
  189. package/src/forge/impact/index.ts +46 -8
  190. package/src/forge/impact/types.ts +6 -0
  191. package/src/forge/intent/index.ts +35 -16
  192. package/src/forge/make/index.ts +34 -5
  193. package/src/forge/make/templates.ts +155 -2
  194. package/src/forge/make/types.ts +2 -1
  195. package/src/forge/policy.ts +1 -1
  196. package/src/forge/refactor/index.ts +1 -0
  197. package/src/forge/repair/rules/index.ts +2 -2
  198. package/src/forge/review/index.ts +158 -12
  199. package/src/forge/review/types.ts +15 -0
  200. package/src/forge/runtime/auth/claims.ts +32 -0
  201. package/src/forge/runtime/auth/config.ts +17 -0
  202. package/src/forge/runtime/auth/errors.ts +2 -0
  203. package/src/forge/runtime/auth/evaluate.ts +15 -2
  204. package/src/forge/runtime/auth/resolve.ts +29 -4
  205. package/src/forge/runtime/db/generated-client.ts +13 -2
  206. package/src/forge/runtime/db/memory-adapter.ts +2 -2
  207. package/src/forge/runtime/db/pglite-adapter.ts +77 -2
  208. package/src/forge/runtime/db/postgres-adapter.ts +6 -3
  209. package/src/forge/runtime/executor.ts +129 -16
  210. package/src/forge/runtime/external/bridge.ts +649 -0
  211. package/src/forge/runtime/runner/run-entry.ts +16 -7
  212. package/src/forge/runtime/telemetry/buffer.ts +4 -1
  213. package/src/forge/runtime/telemetry/scrubber.ts +91 -10
  214. package/src/forge/runtime/webhooks/security.ts +189 -0
  215. package/src/forge/server.ts +23 -2
  216. package/src/forge/version.ts +1 -1
  217. package/src/forge/vue/index.ts +407 -0
  218. package/src/forge/workspace/change-summary.ts +243 -0
  219. package/src/forge/workspace/forge-cli.ts +14 -0
  220. package/src/forge/workspace/git-summary.ts +328 -0
  221. package/templates/agent-workroom/AGENTS.md +29 -0
  222. package/templates/agent-workroom/README.md +34 -0
  223. package/templates/agent-workroom/forge.config.ts +3 -0
  224. package/templates/agent-workroom/package.json +33 -0
  225. package/templates/agent-workroom/src/actions/indexAgentSignal.ts +10 -0
  226. package/templates/agent-workroom/src/commands/openWorkroom.ts +61 -0
  227. package/templates/agent-workroom/src/commands/recordAgentSignal.ts +119 -0
  228. package/templates/agent-workroom/src/commands/recordCheckRun.ts +52 -0
  229. package/templates/agent-workroom/src/forge/schema.ts +54 -0
  230. package/templates/agent-workroom/src/policies.ts +6 -0
  231. package/templates/agent-workroom/src/queries/listWorkrooms.ts +11 -0
  232. package/templates/agent-workroom/src/queries/liveWorkroom.ts +63 -0
  233. package/templates/agent-workroom/tsconfig.json +16 -0
  234. package/templates/agent-workroom/web/index.html +12 -0
  235. package/templates/agent-workroom/web/package.json +21 -0
  236. package/templates/agent-workroom/web/src/App.tsx +345 -0
  237. package/templates/agent-workroom/web/src/lib/forge.ts +13 -0
  238. package/templates/agent-workroom/web/src/main.tsx +13 -0
  239. package/templates/agent-workroom/web/src/styles.css +545 -0
  240. package/templates/agent-workroom/web/tsconfig.json +27 -0
  241. package/templates/b2b-support-web/package.json +2 -0
  242. package/templates/b2b-support-web/tsconfig.json +4 -1
  243. package/templates/b2b-support-web/web/package.json +1 -1
  244. package/templates/minimal-web/package.json +2 -1
  245. package/templates/minimal-web/tsconfig.json +3 -1
  246. package/templates/minimal-web/web/package.json +2 -2
  247. package/templates/nuxt-web/.vscode/settings.json +14 -0
  248. package/templates/nuxt-web/README.md +30 -0
  249. package/templates/nuxt-web/forge.config.ts +3 -0
  250. package/templates/nuxt-web/package.json +33 -0
  251. package/templates/nuxt-web/src/actions/logNoteCreated.ts +11 -0
  252. package/templates/nuxt-web/src/commands/createNote.ts +26 -0
  253. package/templates/nuxt-web/src/forge/schema.ts +12 -0
  254. package/templates/nuxt-web/src/policies.ts +6 -0
  255. package/templates/nuxt-web/src/queries/listNotes.ts +8 -0
  256. package/templates/nuxt-web/src/queries/liveNotes.ts +8 -0
  257. package/templates/nuxt-web/tsconfig.json +17 -0
  258. package/templates/nuxt-web/web/app.vue +67 -0
  259. package/templates/nuxt-web/web/components/LiveNotes.vue +89 -0
  260. package/templates/nuxt-web/web/components/NoteComposer.vue +100 -0
  261. package/templates/nuxt-web/web/composables/forge.ts +13 -0
  262. package/templates/nuxt-web/web/composables/useNotes.ts +24 -0
  263. package/templates/nuxt-web/web/nuxt.config.ts +11 -0
  264. package/templates/nuxt-web/web/package.json +17 -0
  265. package/templates/nuxt-web/web/plugins/forge.client.ts +10 -0
  266. package/templates/nuxt-web/web/plugins/forge.server.ts +10 -0
  267. package/templates/nuxt-web/web/server/api/forge-health.get.ts +7 -0
  268. package/templates/nuxt-web/web/tsconfig.json +3 -0
  269. package/src/forge/_generated/actionSubscriptions.json +0 -2
  270. package/src/forge/_generated/actionSubscriptions.ts +0 -10
  271. package/src/forge/_generated/agentAdapterManifest.json +0 -2
  272. package/src/forge/_generated/agentAdapterManifest.ts +0 -73
  273. package/src/forge/_generated/agentContract.json +0 -2
  274. package/src/forge/_generated/agentContract.ts +0 -7829
  275. package/src/forge/_generated/agentQuickstart.md +0 -34
  276. package/src/forge/_generated/agentTools.json +0 -2
  277. package/src/forge/_generated/agentTools.md +0 -16
  278. package/src/forge/_generated/agentTools.ts +0 -12
  279. package/src/forge/_generated/aiContext.ts +0 -125
  280. package/src/forge/_generated/aiModels.json +0 -2
  281. package/src/forge/_generated/aiModels.ts +0 -51
  282. package/src/forge/_generated/aiProviders.json +0 -2
  283. package/src/forge/_generated/aiProviders.ts +0 -23
  284. package/src/forge/_generated/aiRegistry.json +0 -2
  285. package/src/forge/_generated/aiRegistry.ts +0 -31
  286. package/src/forge/_generated/api.json +0 -2
  287. package/src/forge/_generated/api.ts +0 -8
  288. package/src/forge/_generated/appGraph.json +0 -2
  289. package/src/forge/_generated/appGraph.ts +0 -14775
  290. package/src/forge/_generated/appMap.md +0 -55
  291. package/src/forge/_generated/artifactManifest.json +0 -2
  292. package/src/forge/_generated/artifactManifest.ts +0 -7
  293. package/src/forge/_generated/authClaims.json +0 -2
  294. package/src/forge/_generated/authClaims.ts +0 -13
  295. package/src/forge/_generated/authConfig.json +0 -2
  296. package/src/forge/_generated/authConfig.ts +0 -17
  297. package/src/forge/_generated/authContext.ts +0 -23
  298. package/src/forge/_generated/authRegistry.json +0 -2
  299. package/src/forge/_generated/authRegistry.ts +0 -25
  300. package/src/forge/_generated/buildInfo.json +0 -2
  301. package/src/forge/_generated/buildInfo.ts +0 -9
  302. package/src/forge/_generated/capabilityMap.json +0 -2
  303. package/src/forge/_generated/capabilityMap.md +0 -15
  304. package/src/forge/_generated/capabilityMap.ts +0 -17
  305. package/src/forge/_generated/client.ts +0 -282
  306. package/src/forge/_generated/clientApi.ts +0 -9
  307. package/src/forge/_generated/clientManifest.json +0 -2
  308. package/src/forge/_generated/clientManifest.ts +0 -39
  309. package/src/forge/_generated/clientTypes.ts +0 -78
  310. package/src/forge/_generated/configRegistry.json +0 -2
  311. package/src/forge/_generated/configRegistry.ts +0 -4
  312. package/src/forge/_generated/dataGraph.json +0 -2
  313. package/src/forge/_generated/dataGraph.ts +0 -8
  314. package/src/forge/_generated/db.json +0 -2
  315. package/src/forge/_generated/db.ts +0 -2
  316. package/src/forge/_generated/dbSecurityManifest.json +0 -2
  317. package/src/forge/_generated/dbSecurityManifest.ts +0 -15
  318. package/src/forge/_generated/dbSessionContext.json +0 -2
  319. package/src/forge/_generated/dbSessionContext.ts +0 -39
  320. package/src/forge/_generated/deployManifest.json +0 -2
  321. package/src/forge/_generated/deployManifest.ts +0 -14
  322. package/src/forge/_generated/devManifest.json +0 -2
  323. package/src/forge/_generated/devManifest.ts +0 -62
  324. package/src/forge/_generated/envSchema.json +0 -2
  325. package/src/forge/_generated/envSchema.ts +0 -59
  326. package/src/forge/_generated/frontendGraph.json +0 -2
  327. package/src/forge/_generated/frontendGraph.ts +0 -27
  328. package/src/forge/_generated/importGuards.json +0 -2
  329. package/src/forge/_generated/importGuards.ts +0 -686
  330. package/src/forge/_generated/index.ts +0 -68
  331. package/src/forge/_generated/liveProductionManifest.json +0 -2
  332. package/src/forge/_generated/liveProductionManifest.ts +0 -23
  333. package/src/forge/_generated/liveProtocol.json +0 -2
  334. package/src/forge/_generated/liveProtocol.ts +0 -21
  335. package/src/forge/_generated/liveQueryRegistry.json +0 -2
  336. package/src/forge/_generated/liveQueryRegistry.ts +0 -9
  337. package/src/forge/_generated/liveTransportConfig.json +0 -2
  338. package/src/forge/_generated/liveTransportConfig.ts +0 -19
  339. package/src/forge/_generated/makeRegistry.json +0 -2
  340. package/src/forge/_generated/makeRegistry.ts +0 -177
  341. package/src/forge/_generated/makeTemplates.json +0 -2
  342. package/src/forge/_generated/makeTemplates.ts +0 -66
  343. package/src/forge/_generated/mockMap.json +0 -2
  344. package/src/forge/_generated/mockMap.ts +0 -7
  345. package/src/forge/_generated/operationPlaybooks.md +0 -167
  346. package/src/forge/_generated/packageGraph.json +0 -2
  347. package/src/forge/_generated/packageGraph.ts +0 -249334
  348. package/src/forge/_generated/packageUpgradeRegistry.json +0 -2
  349. package/src/forge/_generated/packageUpgradeRegistry.ts +0 -15
  350. package/src/forge/_generated/permissionMatrix.json +0 -2
  351. package/src/forge/_generated/permissionMatrix.ts +0 -7
  352. package/src/forge/_generated/policyRegistry.json +0 -2
  353. package/src/forge/_generated/policyRegistry.ts +0 -11
  354. package/src/forge/_generated/queryRegistry.json +0 -2
  355. package/src/forge/_generated/queryRegistry.ts +0 -9
  356. package/src/forge/_generated/react.d.ts +0 -22
  357. package/src/forge/_generated/react.ts +0 -29
  358. package/src/forge/_generated/reactManifest.json +0 -2
  359. package/src/forge/_generated/reactManifest.ts +0 -19
  360. package/src/forge/_generated/rlsPolicies.json +0 -2
  361. package/src/forge/_generated/rlsPolicies.sql +0 -34
  362. package/src/forge/_generated/rlsPolicies.ts +0 -6
  363. package/src/forge/_generated/runtimeGraph.json +0 -2
  364. package/src/forge/_generated/runtimeGraph.ts +0 -8
  365. package/src/forge/_generated/runtimeMatrix.json +0 -2
  366. package/src/forge/_generated/runtimeMatrix.ts +0 -334130
  367. package/src/forge/_generated/runtimeRegistry.ts +0 -2
  368. package/src/forge/_generated/runtimeRules.md +0 -91
  369. package/src/forge/_generated/secretRegistry.json +0 -2
  370. package/src/forge/_generated/secretRegistry.ts +0 -50
  371. package/src/forge/_generated/secretsContext.ts +0 -11
  372. package/src/forge/_generated/serverApi.ts +0 -10
  373. package/src/forge/_generated/sourceMapManifest.json +0 -2
  374. package/src/forge/_generated/sourceMapManifest.ts +0 -7
  375. package/src/forge/_generated/sqlPlan.json +0 -2
  376. package/src/forge/_generated/sqlPlan.ts +0 -88
  377. package/src/forge/_generated/subscriptionManifest.json +0 -2
  378. package/src/forge/_generated/subscriptionManifest.ts +0 -7
  379. package/src/forge/_generated/symbolicationManifest.json +0 -2
  380. package/src/forge/_generated/symbolicationManifest.ts +0 -17
  381. package/src/forge/_generated/telemetryRegistry.json +0 -2
  382. package/src/forge/_generated/telemetryRegistry.ts +0 -9
  383. package/src/forge/_generated/telemetrySinks.json +0 -2
  384. package/src/forge/_generated/telemetrySinks.ts +0 -11
  385. package/src/forge/_generated/tenantScope.json +0 -2
  386. package/src/forge/_generated/tenantScope.ts +0 -8
  387. package/src/forge/_generated/testGraph.json +0 -2
  388. package/src/forge/_generated/testGraph.ts +0 -3118
  389. package/src/forge/_generated/testPlanRegistry.json +0 -2
  390. package/src/forge/_generated/testPlanRegistry.ts +0 -33
  391. package/src/forge/_generated/uiRoutes.json +0 -2
  392. package/src/forge/_generated/uiRoutes.ts +0 -16
  393. package/src/forge/_generated/uiScenarios.json +0 -2
  394. package/src/forge/_generated/uiScenarios.ts +0 -30
  395. package/src/forge/_generated/uiTestManifest.json +0 -2
  396. package/src/forge/_generated/uiTestManifest.ts +0 -27
  397. package/src/forge/_generated/workflowRegistry.json +0 -2
  398. package/src/forge/_generated/workflowRegistry.ts +0 -9
  399. package/src/forge/_generated/workflowSubscriptions.json +0 -2
  400. package/src/forge/_generated/workflowSubscriptions.ts +0 -10
@@ -9,7 +9,7 @@ import {
9
9
  import { getRuntimeEnvStore, initializeRuntimeEnv } from "../runtime/context/create-context.ts";
10
10
  import { redactSecretValue } from "../runtime/secrets/env-loader.ts";
11
11
 
12
- export type SecretsSubcommand = "list" | "check" | "print" | "set" | "unset";
12
+ export type SecretsSubcommand = "list" | "check" | "print" | "set" | "unset" | "prove";
13
13
 
14
14
  export interface SecretsCommandOptions {
15
15
  subcommand: SecretsSubcommand;
@@ -90,6 +90,51 @@ export async function runSecretsCommand(
90
90
  const result = checkSecrets(store, registry);
91
91
  return { exitCode: result.ok ? 0 : 1, data: result };
92
92
  }
93
+ case "prove": {
94
+ if (!registry) {
95
+ return {
96
+ exitCode: 1,
97
+ diagnostics: [
98
+ createDiagnostic({
99
+ severity: "error",
100
+ code: "FORGE_INSPECT_MISSING",
101
+ message: "missing secretRegistry.json; run forge generate first",
102
+ }),
103
+ ],
104
+ };
105
+ }
106
+
107
+ const store = getRuntimeEnvStore(options.workspaceRoot);
108
+ const result = checkSecrets(store, registry);
109
+ return {
110
+ exitCode: result.ok ? 0 : 1,
111
+ data: {
112
+ schemaVersion: "0.1.0",
113
+ kind: "secrets-proof",
114
+ ok: result.ok,
115
+ invariants: [
116
+ {
117
+ id: "INV-008",
118
+ name: "secret values are not emitted by the proof",
119
+ status: "passed",
120
+ evidence: "only names, missing names, and redacted presence markers are returned",
121
+ },
122
+ {
123
+ id: "INV-008-REQUIRED",
124
+ name: "required secrets are configured",
125
+ status: result.ok ? "passed" : "failed",
126
+ evidence: {
127
+ missing: result.missing,
128
+ present: result.present.map((entry) => ({
129
+ name: entry.name,
130
+ redacted: entry.redacted,
131
+ })),
132
+ },
133
+ },
134
+ ],
135
+ },
136
+ };
137
+ }
93
138
  case "print": {
94
139
  if (!registry) {
95
140
  return { exitCode: 1, data: { secrets: [] } };
@@ -0,0 +1,381 @@
1
+ import type { DbAdapterKind } from "../runtime/db/adapter.ts";
2
+ import type { AuthCommandResult } from "./auth.ts";
3
+ import { runAuthCommand } from "./auth.ts";
4
+ import type { RlsCommandResult } from "./rls.ts";
5
+ import { runRlsCommand } from "./rls.ts";
6
+ import type { SecretsCommandResult } from "./secrets.ts";
7
+ import { runSecretsCommand } from "./secrets.ts";
8
+ import type { AiCommandResult } from "./ai.ts";
9
+ import { runAiCommand } from "./ai.ts";
10
+ import { runCheckCommand } from "./commands.ts";
11
+ import type { GenerateResult } from "../compiler/types/cli.ts";
12
+ import { spawnSync } from "node:child_process";
13
+ import { existsSync } from "node:fs";
14
+ import { join } from "node:path";
15
+
16
+ export type SecuritySubcommand = "prove";
17
+
18
+ export interface SecurityInvariantEvidence {
19
+ id: string;
20
+ artifact: string;
21
+ level: "checked" | "tested" | "proved";
22
+ summary: string;
23
+ tests: string[];
24
+ commands: string[];
25
+ }
26
+
27
+ export interface SecurityCommandOptions {
28
+ subcommand: SecuritySubcommand;
29
+ workspaceRoot: string;
30
+ json: boolean;
31
+ db: DbAdapterKind;
32
+ databaseUrl?: string;
33
+ runTests: boolean;
34
+ }
35
+
36
+ export interface SecurityTestRunResult {
37
+ enabled: boolean;
38
+ ok: boolean;
39
+ command: string[];
40
+ tests: string[];
41
+ exitCode: number | null;
42
+ stdout: string;
43
+ stderr: string;
44
+ }
45
+
46
+ export interface SecurityProofResult {
47
+ ok: boolean;
48
+ schemaVersion: "0.1.0";
49
+ kind: "security-proof";
50
+ assurance: "structural-only" | "postgres-proved";
51
+ proofs: {
52
+ forgeCheck: GenerateResult;
53
+ auth: AuthCommandResult;
54
+ secrets: SecretsCommandResult;
55
+ rls: RlsCommandResult;
56
+ rlsMutation: RlsCommandResult;
57
+ agentRedteam: AiCommandResult;
58
+ securityTests: SecurityTestRunResult;
59
+ };
60
+ evidence: {
61
+ invariants: SecurityInvariantEvidence[];
62
+ };
63
+ summary: {
64
+ passed: string[];
65
+ failed: string[];
66
+ warnings: string[];
67
+ };
68
+ exitCode: 0 | 1;
69
+ }
70
+
71
+ function invariantEvidence(): SecurityInvariantEvidence[] {
72
+ return [
73
+ {
74
+ id: "INV-001",
75
+ artifact: "auth-negative",
76
+ level: "tested",
77
+ summary: "Production auth rejects invalid JWT/OIDC tokens and ignores dev headers in jwt mode.",
78
+ tests: ["tests/security/auth-negative.test.ts"],
79
+ commands: ["node ./bin/forge-bun.mjs test tests/security/auth-negative.test.ts --timeout 120000"],
80
+ },
81
+ {
82
+ id: "INV-002",
83
+ artifact: "tenant-isolation",
84
+ level: "tested",
85
+ summary: "Runtime and HTTP APIs block cross-tenant reads, writes, tenant spoofing, and unsafe tenant filters.",
86
+ tests: [
87
+ "tests/security/tenant-isolation/runtime-api.test.ts",
88
+ "tests/security/tenant-isolation/http-runtime.test.ts",
89
+ ],
90
+ commands: ["node ./bin/forge-bun.mjs test tests/security/tenant-isolation --timeout 120000"],
91
+ },
92
+ {
93
+ id: "INV-003",
94
+ artifact: "rls-test",
95
+ level: "proved",
96
+ summary: "Postgres RLS probes and structural mutation checks protect tenant-scoped tables.",
97
+ tests: [
98
+ "tests/security/rls-postgres-adversarial.test.ts",
99
+ "tests/security/rls-mutation.test.ts",
100
+ ],
101
+ commands: [
102
+ "node ./bin/forge.mjs rls test --db postgres --json",
103
+ "node ./bin/forge.mjs rls mutate-test --json",
104
+ ],
105
+ },
106
+ {
107
+ id: "INV-004",
108
+ artifact: "runtime-boundaries",
109
+ level: "tested",
110
+ summary: "Commands reject forbidden AI, agent, network, secret, filesystem, and process.env usage.",
111
+ tests: ["tests/security/runtime-boundaries.test.ts"],
112
+ commands: ["node ./bin/forge-bun.mjs test tests/security/runtime-boundaries.test.ts --timeout 120000"],
113
+ },
114
+ {
115
+ id: "INV-005",
116
+ artifact: "runtime-boundaries",
117
+ level: "tested",
118
+ summary: "Queries and liveQueries remain read-only and side-effect free.",
119
+ tests: ["tests/security/runtime-boundaries.test.ts"],
120
+ commands: ["node ./bin/forge-bun.mjs test tests/security/runtime-boundaries.test.ts --timeout 120000"],
121
+ },
122
+ {
123
+ id: "INV-006",
124
+ artifact: "agent-tools",
125
+ level: "tested",
126
+ summary: "Generated agent tools carry Forge auth, tenant, policy, runtime, and risk metadata.",
127
+ tests: ["tests/security/agent-tools.test.ts"],
128
+ commands: ["node ./bin/forge-bun.mjs test tests/security/agent-tools.test.ts --timeout 120000"],
129
+ },
130
+ {
131
+ id: "INV-007",
132
+ artifact: "agent-tools",
133
+ level: "tested",
134
+ summary: "Write, destructive, and external agent tools require approval metadata.",
135
+ tests: ["tests/security/agent-tools.test.ts"],
136
+ commands: ["node ./bin/forge-bun.mjs test tests/security/agent-tools.test.ts --timeout 120000"],
137
+ },
138
+ {
139
+ id: "INV-008",
140
+ artifact: "secret-redaction",
141
+ level: "tested",
142
+ summary: "Generated artifacts and telemetry scrub secret names and known secret values.",
143
+ tests: ["tests/security/secret-redaction.test.ts"],
144
+ commands: ["node ./bin/forge-bun.mjs test tests/security/secret-redaction.test.ts --timeout 120000"],
145
+ },
146
+ {
147
+ id: "INV-009",
148
+ artifact: "webhooks",
149
+ level: "tested",
150
+ summary: "Webhook helpers reject invalid signatures, stale timestamps, tampered payloads, and replayed event IDs.",
151
+ tests: ["tests/security/webhooks/webhook-security.test.ts"],
152
+ commands: ["node ./bin/forge-bun.mjs test tests/security/webhooks --timeout 120000"],
153
+ },
154
+ {
155
+ id: "INV-010",
156
+ artifact: "release-supply-chain",
157
+ level: "checked",
158
+ summary: "Release workflow uses Trusted Publishing, provenance, smoke tests, security proof, and generated release evidence.",
159
+ tests: ["tests/ci/publish-workflow.test.ts"],
160
+ commands: ["npm run release:smoke", "npm run release:evidence"],
161
+ },
162
+ ];
163
+ }
164
+
165
+ function passed(name: string, ok: boolean, summary: SecurityProofResult["summary"]): void {
166
+ if (ok) {
167
+ summary.passed.push(name);
168
+ } else {
169
+ summary.failed.push(name);
170
+ }
171
+ }
172
+
173
+ function securityTestFiles(options: SecurityCommandOptions): string[] {
174
+ const tests = new Set<string>();
175
+ for (const invariant of invariantEvidence()) {
176
+ for (const test of invariant.tests) {
177
+ if (!test.startsWith("tests/security/")) {
178
+ continue;
179
+ }
180
+ if (options.db !== "postgres" && test.includes("rls-postgres-adversarial.test.ts")) {
181
+ continue;
182
+ }
183
+ tests.add(test);
184
+ }
185
+ }
186
+ return [...tests].sort();
187
+ }
188
+
189
+ function runSecurityTests(options: SecurityCommandOptions): SecurityTestRunResult {
190
+ const tests = securityTestFiles(options);
191
+ const command = [
192
+ "./bin/forge-bun.mjs",
193
+ "test",
194
+ ...tests,
195
+ "--timeout",
196
+ "120000",
197
+ ];
198
+
199
+ if (!options.runTests) {
200
+ return {
201
+ enabled: false,
202
+ ok: true,
203
+ command: ["node", ...command],
204
+ tests,
205
+ exitCode: null,
206
+ stdout: "",
207
+ stderr: "",
208
+ };
209
+ }
210
+
211
+ const missingTests = tests.filter((test) => !existsSync(join(options.workspaceRoot, test)));
212
+ const runnerPath = join(options.workspaceRoot, "bin", "forge-bun.mjs");
213
+ if (missingTests.length > 0 || !existsSync(runnerPath)) {
214
+ return {
215
+ enabled: false,
216
+ ok: true,
217
+ command: ["node", ...command],
218
+ tests,
219
+ exitCode: null,
220
+ stdout: "",
221
+ stderr:
222
+ "security invariant test fixtures are not available in this workspace; structural proofs still ran. Run this command from the ForgeOS source checkout to execute the full framework test fixtures.",
223
+ };
224
+ }
225
+
226
+ const result = spawnSync(process.execPath, command, {
227
+ cwd: options.workspaceRoot,
228
+ encoding: "utf8",
229
+ env: {
230
+ ...process.env,
231
+ ...(options.databaseUrl ? { DATABASE_URL: options.databaseUrl } : {}),
232
+ },
233
+ windowsHide: true,
234
+ });
235
+
236
+ return {
237
+ enabled: true,
238
+ ok: result.status === 0,
239
+ command: ["node", ...command],
240
+ tests,
241
+ exitCode: result.status,
242
+ stdout: limitOutput(result.stdout ?? ""),
243
+ stderr: limitOutput(result.stderr ?? ""),
244
+ };
245
+ }
246
+
247
+ function limitOutput(output: string): string {
248
+ const maxLength = 20_000;
249
+ if (output.length <= maxLength) {
250
+ return output;
251
+ }
252
+ return `${output.slice(0, 4_000)}\n\n[forge output truncated]\n\n${output.slice(-16_000)}`;
253
+ }
254
+
255
+ export async function runSecurityCommand(
256
+ options: SecurityCommandOptions,
257
+ ): Promise<SecurityProofResult> {
258
+ const forgeCheck = await runCheckCommand(options.workspaceRoot, { strictSecrets: true });
259
+ const auth = await runAuthCommand({
260
+ subcommand: "prove",
261
+ workspaceRoot: options.workspaceRoot,
262
+ json: true,
263
+ });
264
+ const secrets = await runSecretsCommand({
265
+ subcommand: "prove",
266
+ workspaceRoot: options.workspaceRoot,
267
+ json: true,
268
+ redacted: true,
269
+ });
270
+ const rls = await runRlsCommand({
271
+ subcommand: "test",
272
+ workspaceRoot: options.workspaceRoot,
273
+ db: options.db,
274
+ databaseUrl: options.databaseUrl,
275
+ json: true,
276
+ });
277
+ const rlsMutation = await runRlsCommand({
278
+ subcommand: "mutate-test",
279
+ workspaceRoot: options.workspaceRoot,
280
+ db: options.db,
281
+ databaseUrl: options.databaseUrl,
282
+ json: true,
283
+ });
284
+ const agentRedteam = await runAiCommand({
285
+ subcommand: "redteam",
286
+ workspaceRoot: options.workspaceRoot,
287
+ json: true,
288
+ });
289
+ const securityTests = runSecurityTests(options);
290
+
291
+ const summary: SecurityProofResult["summary"] = {
292
+ passed: [],
293
+ failed: [],
294
+ warnings: [],
295
+ };
296
+ passed("forge-check", forgeCheck.exitCode === 0, summary);
297
+ passed("auth-proof", auth.exitCode === 0, summary);
298
+ passed("secrets-proof", secrets.exitCode === 0, summary);
299
+ passed("rls-proof", rls.exitCode === 0, summary);
300
+ passed("rls-mutation-proof", rlsMutation.exitCode === 0, summary);
301
+ passed("agent-redteam", agentRedteam.exitCode === 0, summary);
302
+ if (securityTests.enabled) {
303
+ passed("security-tests", securityTests.ok, summary);
304
+ }
305
+
306
+ if (auth.mode === "dev-headers") {
307
+ summary.warnings.push("auth-proof uses local-only dev-headers mode");
308
+ }
309
+ for (const diagnostic of rls.diagnostics) {
310
+ if (diagnostic.severity === "warning") {
311
+ summary.warnings.push(`${diagnostic.code}: ${diagnostic.message}`);
312
+ }
313
+ }
314
+ for (const diagnostic of rlsMutation.diagnostics) {
315
+ if (diagnostic.severity === "warning") {
316
+ summary.warnings.push(`${diagnostic.code}: ${diagnostic.message}`);
317
+ }
318
+ }
319
+ for (const diagnostic of agentRedteam.diagnostics ?? []) {
320
+ if (diagnostic.severity === "warning") {
321
+ summary.warnings.push(`${diagnostic.code}: ${diagnostic.message}`);
322
+ }
323
+ }
324
+ if (!securityTests.enabled && !options.runTests) {
325
+ summary.warnings.push("security-tests not executed; pass --full or --run-tests to run invariant security tests");
326
+ }
327
+ if (!securityTests.enabled && options.runTests) {
328
+ summary.warnings.push(securityTests.stderr);
329
+ }
330
+ if (options.runTests && options.db !== "postgres") {
331
+ summary.warnings.push("postgres RLS adversarial test skipped because --db postgres was not selected");
332
+ }
333
+
334
+ const ok = summary.failed.length === 0;
335
+ const assurance =
336
+ options.db === "postgres" &&
337
+ rls.exitCode === 0 &&
338
+ Boolean((rls.data as { skipped?: boolean } | undefined)?.skipped) === false
339
+ ? "postgres-proved"
340
+ : "structural-only";
341
+ return {
342
+ ok,
343
+ schemaVersion: "0.1.0",
344
+ kind: "security-proof",
345
+ assurance,
346
+ proofs: {
347
+ forgeCheck,
348
+ auth,
349
+ secrets,
350
+ rls,
351
+ rlsMutation,
352
+ agentRedteam,
353
+ securityTests,
354
+ },
355
+ evidence: {
356
+ invariants: invariantEvidence(),
357
+ },
358
+ summary,
359
+ exitCode: ok ? 0 : 1,
360
+ };
361
+ }
362
+
363
+ export function formatSecurityJson(result: SecurityProofResult): string {
364
+ return `${JSON.stringify(result, null, 2)}\n`;
365
+ }
366
+
367
+ export function formatSecurityHuman(result: SecurityProofResult): string {
368
+ const lines = [
369
+ "Forge Security Proof",
370
+ "",
371
+ `Status: ${result.ok ? "ok" : "failed"}`,
372
+ `Assurance: ${result.assurance}`,
373
+ `Passed: ${result.summary.passed.join(", ") || "none"}`,
374
+ `Failed: ${result.summary.failed.join(", ") || "none"}`,
375
+ `Security tests: ${result.proofs.securityTests.enabled ? (result.proofs.securityTests.ok ? "passed" : "failed") : "not run"}`,
376
+ ];
377
+ if (result.summary.warnings.length > 0) {
378
+ lines.push("", "Warnings:", ...result.summary.warnings.map((warning) => `- ${warning}`));
379
+ }
380
+ return `${lines.join("\n")}\n`;
381
+ }
@@ -4,6 +4,7 @@ import { GENERATED_DIR } from "../compiler/emitter/constants.ts";
4
4
  import { stripDeterministicHeader } from "../compiler/primitives/header.ts";
5
5
  import { runGenerateCommand } from "./commands.ts";
6
6
  import { runVerifyCommand } from "./verify.ts";
7
+ import { selfHostPrepareNextActions, selfHostReadyNextActions } from "./next-actions.ts";
7
8
 
8
9
  export type SelfHostSubcommand = "compose" | "env" | "check" | "clean";
9
10
 
@@ -15,6 +16,7 @@ export interface SelfHostCommandOptions {
15
16
  postgresVersion: string;
16
17
  runtimePort: number;
17
18
  webPort: number;
19
+ preparedOnly?: boolean;
18
20
  }
19
21
 
20
22
  export interface SelfHostCheck {
@@ -26,8 +28,10 @@ export interface SelfHostCheck {
26
28
  export interface SelfHostCommandResult {
27
29
  ok: boolean;
28
30
  exitCode: 0 | 1;
31
+ state?: "ready" | "not-prepared" | "failed";
29
32
  files?: string[];
30
33
  checks?: SelfHostCheck[];
34
+ nextActions?: string[];
31
35
  }
32
36
 
33
37
  function deployDir(workspaceRoot: string): string {
@@ -392,6 +396,28 @@ export async function runSelfHostCommand(
392
396
  }
393
397
 
394
398
  const checks: SelfHostCheck[] = [];
399
+ const requiredDeployFiles = [
400
+ "docker-compose.yml",
401
+ "Dockerfile.runtime",
402
+ "Dockerfile.web",
403
+ ".dockerignore",
404
+ ".env.example",
405
+ "README.md",
406
+ ];
407
+ const missingDeployFiles = requiredDeployFiles.filter((file) => !nodeFileSystem.exists(join(dir, file)));
408
+ if (options.preparedOnly && missingDeployFiles.length > 0) {
409
+ return {
410
+ ok: true,
411
+ state: "not-prepared",
412
+ exitCode: 0,
413
+ checks: missingDeployFiles.map((file) => ({
414
+ name: `deploy/${file}`,
415
+ ok: true,
416
+ details: { state: "not-prepared", missing: true, command: "forge self-host compose" },
417
+ })),
418
+ nextActions: selfHostPrepareNextActions(),
419
+ };
420
+ }
395
421
  const generated = await runGenerateCommand({
396
422
  workspaceRoot: options.workspaceRoot,
397
423
  check: true,
@@ -399,7 +425,11 @@ export async function runSelfHostCommand(
399
425
  json: false,
400
426
  concurrency: 4,
401
427
  });
402
- checks.push({ name: "generated", ok: generated.exitCode === 0 });
428
+ checks.push({
429
+ name: "generated",
430
+ ok: generated.exitCode === 0,
431
+ details: generated.exitCode === 0 ? undefined : { command: "forge generate" },
432
+ });
403
433
 
404
434
  const verify = await runVerifyCommand({
405
435
  workspaceRoot: options.workspaceRoot,
@@ -409,17 +439,19 @@ export async function runSelfHostCommand(
409
439
  skipEslint: true,
410
440
  strict: true,
411
441
  });
412
- checks.push({ name: "verify-strict", ok: verify.exitCode === 0 });
442
+ checks.push({
443
+ name: "verify-strict",
444
+ ok: verify.exitCode === 0,
445
+ details: verify.exitCode === 0 ? undefined : { command: "forge verify --strict" },
446
+ });
413
447
 
414
- for (const file of [
415
- "docker-compose.yml",
416
- "Dockerfile.runtime",
417
- "Dockerfile.web",
418
- ".dockerignore",
419
- ".env.example",
420
- "README.md",
421
- ]) {
422
- checks.push({ name: `deploy/${file}`, ok: nodeFileSystem.exists(join(dir, file)) });
448
+ for (const file of requiredDeployFiles) {
449
+ const exists = nodeFileSystem.exists(join(dir, file));
450
+ checks.push({
451
+ name: `deploy/${file}`,
452
+ ok: exists,
453
+ details: exists ? undefined : { missing: true, command: "forge self-host compose" },
454
+ });
423
455
  }
424
456
 
425
457
  const envExample = nodeFileSystem.exists(join(dir, ".env.example"))
@@ -452,7 +484,13 @@ export async function runSelfHostCommand(
452
484
  });
453
485
 
454
486
  const ok = checks.every((check) => check.ok);
455
- return { ok, exitCode: ok ? 0 : 1, checks };
487
+ return {
488
+ ok,
489
+ state: ok ? "ready" : "failed",
490
+ exitCode: ok ? 0 : 1,
491
+ checks,
492
+ nextActions: ok ? selfHostReadyNextActions() : selfHostPrepareNextActions(),
493
+ };
456
494
  }
457
495
 
458
496
  export function formatSelfHostHuman(result: SelfHostCommandResult): string {
@@ -460,9 +498,13 @@ export function formatSelfHostHuman(result: SelfHostCommandResult): string {
460
498
  return `wrote self-host files:\n${result.files.map((file) => ` ${file}`).join("\n")}\n`;
461
499
  }
462
500
  if (result.checks) {
463
- return `${result.checks
501
+ const lines = result.checks
464
502
  .map((check) => `${check.ok ? "ok" : "fail"} ${check.name}`)
465
- .join("\n")}\n`;
503
+ .join("\n");
504
+ const next = result.nextActions && result.nextActions.length > 0
505
+ ? `\nNext:\n${result.nextActions.map((action) => ` ${action}`).join("\n")}\n`
506
+ : "\n";
507
+ return `${lines}${next}`;
466
508
  }
467
509
  return result.ok ? "self-host clean complete\n" : "self-host command failed\n";
468
510
  }