forgeos 0.1.0-alpha.0

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 (540) hide show
  1. package/.npmignore +1 -0
  2. package/AGENTS.md +277 -0
  3. package/CHANGELOG.md +8 -0
  4. package/CONTRIBUTING.md +58 -0
  5. package/README.md +377 -0
  6. package/bin/forge-bun.mjs +110 -0
  7. package/bin/forge.mjs +19 -0
  8. package/package.json +96 -0
  9. package/packages/eslint-plugin-forge/index.ts +15 -0
  10. package/packages/eslint-plugin-forge/package.json +10 -0
  11. package/packages/eslint-plugin-forge/src/check-source.ts +95 -0
  12. package/packages/eslint-plugin-forge/src/load-artifacts.ts +24 -0
  13. package/packages/eslint-plugin-forge/src/rule-no-forge-guard-violation.ts +93 -0
  14. package/src/forge/_generated/actionSubscriptions.json +2 -0
  15. package/src/forge/_generated/actionSubscriptions.ts +10 -0
  16. package/src/forge/_generated/agentAdapterManifest.json +2 -0
  17. package/src/forge/_generated/agentAdapterManifest.ts +73 -0
  18. package/src/forge/_generated/agentContract.json +2 -0
  19. package/src/forge/_generated/agentContract.ts +912 -0
  20. package/src/forge/_generated/agentQuickstart.md +32 -0
  21. package/src/forge/_generated/aiContext.ts +59 -0
  22. package/src/forge/_generated/aiModels.json +2 -0
  23. package/src/forge/_generated/aiModels.ts +35 -0
  24. package/src/forge/_generated/aiProviders.json +2 -0
  25. package/src/forge/_generated/aiProviders.ts +23 -0
  26. package/src/forge/_generated/aiRegistry.json +2 -0
  27. package/src/forge/_generated/aiRegistry.ts +29 -0
  28. package/src/forge/_generated/api.json +2 -0
  29. package/src/forge/_generated/api.ts +8 -0
  30. package/src/forge/_generated/appGraph.json +2 -0
  31. package/src/forge/_generated/appGraph.ts +14511 -0
  32. package/src/forge/_generated/appMap.md +35 -0
  33. package/src/forge/_generated/artifactManifest.json +2 -0
  34. package/src/forge/_generated/artifactManifest.ts +7 -0
  35. package/src/forge/_generated/authClaims.json +2 -0
  36. package/src/forge/_generated/authClaims.ts +13 -0
  37. package/src/forge/_generated/authConfig.json +2 -0
  38. package/src/forge/_generated/authConfig.ts +17 -0
  39. package/src/forge/_generated/authContext.ts +23 -0
  40. package/src/forge/_generated/authRegistry.json +2 -0
  41. package/src/forge/_generated/authRegistry.ts +25 -0
  42. package/src/forge/_generated/buildInfo.json +2 -0
  43. package/src/forge/_generated/buildInfo.ts +9 -0
  44. package/src/forge/_generated/capabilityMap.json +2 -0
  45. package/src/forge/_generated/capabilityMap.md +15 -0
  46. package/src/forge/_generated/capabilityMap.ts +17 -0
  47. package/src/forge/_generated/client.ts +282 -0
  48. package/src/forge/_generated/clientApi.ts +9 -0
  49. package/src/forge/_generated/clientManifest.json +2 -0
  50. package/src/forge/_generated/clientManifest.ts +39 -0
  51. package/src/forge/_generated/clientTypes.ts +78 -0
  52. package/src/forge/_generated/configRegistry.json +2 -0
  53. package/src/forge/_generated/configRegistry.ts +4 -0
  54. package/src/forge/_generated/dataGraph.json +2 -0
  55. package/src/forge/_generated/dataGraph.ts +8 -0
  56. package/src/forge/_generated/db.json +2 -0
  57. package/src/forge/_generated/db.ts +2 -0
  58. package/src/forge/_generated/dbSecurityManifest.json +2 -0
  59. package/src/forge/_generated/dbSecurityManifest.ts +15 -0
  60. package/src/forge/_generated/dbSessionContext.json +2 -0
  61. package/src/forge/_generated/dbSessionContext.ts +39 -0
  62. package/src/forge/_generated/deployManifest.json +2 -0
  63. package/src/forge/_generated/deployManifest.ts +14 -0
  64. package/src/forge/_generated/devManifest.json +2 -0
  65. package/src/forge/_generated/devManifest.ts +47 -0
  66. package/src/forge/_generated/envSchema.json +2 -0
  67. package/src/forge/_generated/envSchema.ts +59 -0
  68. package/src/forge/_generated/frontendGraph.json +2 -0
  69. package/src/forge/_generated/frontendGraph.ts +27 -0
  70. package/src/forge/_generated/importGuards.json +2 -0
  71. package/src/forge/_generated/importGuards.ts +652 -0
  72. package/src/forge/_generated/index.ts +67 -0
  73. package/src/forge/_generated/liveProductionManifest.json +2 -0
  74. package/src/forge/_generated/liveProductionManifest.ts +23 -0
  75. package/src/forge/_generated/liveProtocol.json +2 -0
  76. package/src/forge/_generated/liveProtocol.ts +21 -0
  77. package/src/forge/_generated/liveQueryRegistry.json +2 -0
  78. package/src/forge/_generated/liveQueryRegistry.ts +9 -0
  79. package/src/forge/_generated/liveTransportConfig.json +2 -0
  80. package/src/forge/_generated/liveTransportConfig.ts +19 -0
  81. package/src/forge/_generated/makeRegistry.json +2 -0
  82. package/src/forge/_generated/makeRegistry.ts +163 -0
  83. package/src/forge/_generated/makeTemplates.json +2 -0
  84. package/src/forge/_generated/makeTemplates.ts +61 -0
  85. package/src/forge/_generated/mockMap.json +2 -0
  86. package/src/forge/_generated/mockMap.ts +7 -0
  87. package/src/forge/_generated/operationPlaybooks.md +145 -0
  88. package/src/forge/_generated/packageGraph.json +2 -0
  89. package/src/forge/_generated/packageGraph.ts +168569 -0
  90. package/src/forge/_generated/packageUpgradeRegistry.json +2 -0
  91. package/src/forge/_generated/packageUpgradeRegistry.ts +15 -0
  92. package/src/forge/_generated/permissionMatrix.json +2 -0
  93. package/src/forge/_generated/permissionMatrix.ts +7 -0
  94. package/src/forge/_generated/policyRegistry.json +2 -0
  95. package/src/forge/_generated/policyRegistry.ts +11 -0
  96. package/src/forge/_generated/queryRegistry.json +2 -0
  97. package/src/forge/_generated/queryRegistry.ts +9 -0
  98. package/src/forge/_generated/react.d.ts +22 -0
  99. package/src/forge/_generated/react.ts +29 -0
  100. package/src/forge/_generated/reactManifest.json +2 -0
  101. package/src/forge/_generated/reactManifest.ts +19 -0
  102. package/src/forge/_generated/releaseManifest.json +2 -0
  103. package/src/forge/_generated/releaseManifest.ts +25 -0
  104. package/src/forge/_generated/rlsPolicies.json +2 -0
  105. package/src/forge/_generated/rlsPolicies.sql +34 -0
  106. package/src/forge/_generated/rlsPolicies.ts +6 -0
  107. package/src/forge/_generated/runtimeGraph.json +2 -0
  108. package/src/forge/_generated/runtimeGraph.ts +8 -0
  109. package/src/forge/_generated/runtimeMatrix.json +2 -0
  110. package/src/forge/_generated/runtimeMatrix.ts +229125 -0
  111. package/src/forge/_generated/runtimeRegistry.ts +2 -0
  112. package/src/forge/_generated/runtimeRules.md +79 -0
  113. package/src/forge/_generated/secretRegistry.json +2 -0
  114. package/src/forge/_generated/secretRegistry.ts +50 -0
  115. package/src/forge/_generated/secretsContext.ts +11 -0
  116. package/src/forge/_generated/serverApi.ts +10 -0
  117. package/src/forge/_generated/sourceMapManifest.json +2 -0
  118. package/src/forge/_generated/sourceMapManifest.ts +7 -0
  119. package/src/forge/_generated/sqlPlan.json +2 -0
  120. package/src/forge/_generated/sqlPlan.ts +88 -0
  121. package/src/forge/_generated/subscriptionManifest.json +2 -0
  122. package/src/forge/_generated/subscriptionManifest.ts +7 -0
  123. package/src/forge/_generated/symbolicationManifest.json +2 -0
  124. package/src/forge/_generated/symbolicationManifest.ts +17 -0
  125. package/src/forge/_generated/telemetryRegistry.json +2 -0
  126. package/src/forge/_generated/telemetryRegistry.ts +9 -0
  127. package/src/forge/_generated/telemetrySinks.json +2 -0
  128. package/src/forge/_generated/telemetrySinks.ts +11 -0
  129. package/src/forge/_generated/tenantScope.json +2 -0
  130. package/src/forge/_generated/tenantScope.ts +8 -0
  131. package/src/forge/_generated/testGraph.json +2 -0
  132. package/src/forge/_generated/testGraph.ts +3054 -0
  133. package/src/forge/_generated/testPlanRegistry.json +2 -0
  134. package/src/forge/_generated/testPlanRegistry.ts +33 -0
  135. package/src/forge/_generated/uiRoutes.json +2 -0
  136. package/src/forge/_generated/uiRoutes.ts +16 -0
  137. package/src/forge/_generated/uiScenarios.json +2 -0
  138. package/src/forge/_generated/uiScenarios.ts +30 -0
  139. package/src/forge/_generated/uiTestManifest.json +2 -0
  140. package/src/forge/_generated/uiTestManifest.ts +27 -0
  141. package/src/forge/_generated/workflowRegistry.json +2 -0
  142. package/src/forge/_generated/workflowRegistry.ts +9 -0
  143. package/src/forge/_generated/workflowSubscriptions.json +2 -0
  144. package/src/forge/_generated/workflowSubscriptions.ts +10 -0
  145. package/src/forge/agent-adapters/index.ts +1002 -0
  146. package/src/forge/agent-adapters/types.ts +135 -0
  147. package/src/forge/cli/agent-contract.ts +50 -0
  148. package/src/forge/cli/ai.ts +148 -0
  149. package/src/forge/cli/auth.ts +198 -0
  150. package/src/forge/cli/build.ts +105 -0
  151. package/src/forge/cli/bun-exec.ts +4 -0
  152. package/src/forge/cli/commands.ts +1130 -0
  153. package/src/forge/cli/db.ts +316 -0
  154. package/src/forge/cli/deps.ts +277 -0
  155. package/src/forge/cli/dev.ts +529 -0
  156. package/src/forge/cli/doctor.ts +209 -0
  157. package/src/forge/cli/feature.ts +485 -0
  158. package/src/forge/cli/index.ts +25 -0
  159. package/src/forge/cli/lint-forge.ts +119 -0
  160. package/src/forge/cli/live.ts +179 -0
  161. package/src/forge/cli/main.ts +92 -0
  162. package/src/forge/cli/make.ts +133 -0
  163. package/src/forge/cli/new.ts +505 -0
  164. package/src/forge/cli/outbox.ts +297 -0
  165. package/src/forge/cli/output.ts +114 -0
  166. package/src/forge/cli/parse.ts +2211 -0
  167. package/src/forge/cli/policy.ts +204 -0
  168. package/src/forge/cli/query.ts +91 -0
  169. package/src/forge/cli/refactor.ts +221 -0
  170. package/src/forge/cli/release.ts +285 -0
  171. package/src/forge/cli/rls.ts +322 -0
  172. package/src/forge/cli/run.ts +76 -0
  173. package/src/forge/cli/secrets.ts +274 -0
  174. package/src/forge/cli/self-host.ts +468 -0
  175. package/src/forge/cli/serve.ts +93 -0
  176. package/src/forge/cli/telemetry.ts +219 -0
  177. package/src/forge/cli/verify.ts +587 -0
  178. package/src/forge/cli/version.ts +1 -0
  179. package/src/forge/cli/windows.ts +413 -0
  180. package/src/forge/cli/worker.ts +87 -0
  181. package/src/forge/cli/workflow.ts +424 -0
  182. package/src/forge/compiler/action-subscriptions/build.ts +116 -0
  183. package/src/forge/compiler/action-subscriptions/constants.ts +2 -0
  184. package/src/forge/compiler/action-subscriptions/index.ts +6 -0
  185. package/src/forge/compiler/action-subscriptions/parse.ts +6 -0
  186. package/src/forge/compiler/agent-contract/build.ts +1651 -0
  187. package/src/forge/compiler/agent-contract/types.ts +326 -0
  188. package/src/forge/compiler/ai-registry/build.ts +165 -0
  189. package/src/forge/compiler/ai-registry/constants.ts +2 -0
  190. package/src/forge/compiler/ai-registry/parse.ts +56 -0
  191. package/src/forge/compiler/api-surface/build.ts +107 -0
  192. package/src/forge/compiler/app-graph/build.ts +121 -0
  193. package/src/forge/compiler/app-graph/classify.ts +10 -0
  194. package/src/forge/compiler/app-graph/dup-symbol.ts +29 -0
  195. package/src/forge/compiler/app-graph/extract.ts +124 -0
  196. package/src/forge/compiler/app-graph/forge-apis.ts +29 -0
  197. package/src/forge/compiler/app-graph/index.ts +15 -0
  198. package/src/forge/compiler/app-graph/module-graph.ts +320 -0
  199. package/src/forge/compiler/app-graph/parser.ts +119 -0
  200. package/src/forge/compiler/app-graph/symbols.ts +48 -0
  201. package/src/forge/compiler/app-graph/tsconfig-hash.ts +62 -0
  202. package/src/forge/compiler/app-graph/types.ts +43 -0
  203. package/src/forge/compiler/app-graph/versions.ts +14 -0
  204. package/src/forge/compiler/cache/index.ts +17 -0
  205. package/src/forge/compiler/cache/key.ts +46 -0
  206. package/src/forge/compiler/cache/scheduler.ts +72 -0
  207. package/src/forge/compiler/cache/store.ts +78 -0
  208. package/src/forge/compiler/classifier/capabilities.ts +78 -0
  209. package/src/forge/compiler/classifier/classify.ts +113 -0
  210. package/src/forge/compiler/classifier/contexts.ts +188 -0
  211. package/src/forge/compiler/classifier/index.ts +18 -0
  212. package/src/forge/compiler/classifier/runtime-matrix.ts +45 -0
  213. package/src/forge/compiler/classifier/secrets.ts +41 -0
  214. package/src/forge/compiler/classifier/signals.ts +129 -0
  215. package/src/forge/compiler/client-sdk/build-manifest.ts +151 -0
  216. package/src/forge/compiler/client-sdk/render-client.ts +432 -0
  217. package/src/forge/compiler/data-graph/build.ts +131 -0
  218. package/src/forge/compiler/data-graph/constants.ts +5 -0
  219. package/src/forge/compiler/data-graph/index.ts +6 -0
  220. package/src/forge/compiler/data-graph/parse.ts +176 -0
  221. package/src/forge/compiler/data-graph/rls/build.ts +222 -0
  222. package/src/forge/compiler/data-graph/rls/types.ts +62 -0
  223. package/src/forge/compiler/data-graph/sql/ddl.ts +390 -0
  224. package/src/forge/compiler/data-graph/sql/naming.ts +10 -0
  225. package/src/forge/compiler/data-graph/sql/serialize.ts +85 -0
  226. package/src/forge/compiler/data-graph/sql/types.ts +37 -0
  227. package/src/forge/compiler/dev-manifest/build.ts +170 -0
  228. package/src/forge/compiler/dev-manifest/constants.ts +5 -0
  229. package/src/forge/compiler/diagnostics/codes.ts +611 -0
  230. package/src/forge/compiler/diagnostics/create.ts +245 -0
  231. package/src/forge/compiler/diagnostics/index.ts +55 -0
  232. package/src/forge/compiler/emitter/artifact-kind.ts +14 -0
  233. package/src/forge/compiler/emitter/barrel.ts +44 -0
  234. package/src/forge/compiler/emitter/constants.ts +7 -0
  235. package/src/forge/compiler/emitter/emit.ts +237 -0
  236. package/src/forge/compiler/emitter/index.ts +24 -0
  237. package/src/forge/compiler/emitter/lock.ts +62 -0
  238. package/src/forge/compiler/emitter/render.ts +73 -0
  239. package/src/forge/compiler/emitter/write.ts +35 -0
  240. package/src/forge/compiler/frontend-graph/build.ts +495 -0
  241. package/src/forge/compiler/fs/index.ts +23 -0
  242. package/src/forge/compiler/fs/memory.ts +233 -0
  243. package/src/forge/compiler/fs/node.ts +139 -0
  244. package/src/forge/compiler/fs/profile.ts +108 -0
  245. package/src/forge/compiler/fs/types.ts +52 -0
  246. package/src/forge/compiler/guards/artifacts.ts +96 -0
  247. package/src/forge/compiler/guards/check-ai-usage.ts +98 -0
  248. package/src/forge/compiler/guards/check-import-guards.ts +106 -0
  249. package/src/forge/compiler/guards/check-process-env.ts +98 -0
  250. package/src/forge/compiler/guards/check-query-usage.ts +76 -0
  251. package/src/forge/compiler/guards/index.ts +11 -0
  252. package/src/forge/compiler/guards/propagate-contexts.ts +57 -0
  253. package/src/forge/compiler/index.ts +17 -0
  254. package/src/forge/compiler/integration/add.ts +496 -0
  255. package/src/forge/compiler/integration/index.ts +17 -0
  256. package/src/forge/compiler/integration/plan.ts +283 -0
  257. package/src/forge/compiler/integration/render.ts +189 -0
  258. package/src/forge/compiler/integration/snapshot.ts +52 -0
  259. package/src/forge/compiler/integration/templates/ai.ts +131 -0
  260. package/src/forge/compiler/integration/templates/index.ts +8 -0
  261. package/src/forge/compiler/integration/templates/posthog.ts +145 -0
  262. package/src/forge/compiler/integration/templates/render.ts +113 -0
  263. package/src/forge/compiler/integration/templates/sentry.ts +151 -0
  264. package/src/forge/compiler/integration/templates/stripe.ts +109 -0
  265. package/src/forge/compiler/integration/templates/types.ts +14 -0
  266. package/src/forge/compiler/integration/templates/zod.ts +55 -0
  267. package/src/forge/compiler/live-production/types.ts +122 -0
  268. package/src/forge/compiler/live-query-registry/build.ts +150 -0
  269. package/src/forge/compiler/live-query-registry/constants.ts +2 -0
  270. package/src/forge/compiler/make-registry/build.ts +179 -0
  271. package/src/forge/compiler/orchestrator/discover.ts +214 -0
  272. package/src/forge/compiler/orchestrator/fast-check.ts +117 -0
  273. package/src/forge/compiler/orchestrator/generate-lock.ts +138 -0
  274. package/src/forge/compiler/orchestrator/guards.ts +5 -0
  275. package/src/forge/compiler/orchestrator/index.ts +27 -0
  276. package/src/forge/compiler/orchestrator/manifest-hashes.ts +21 -0
  277. package/src/forge/compiler/orchestrator/manifest.ts +92 -0
  278. package/src/forge/compiler/orchestrator/orphans.ts +51 -0
  279. package/src/forge/compiler/orchestrator/plan.ts +876 -0
  280. package/src/forge/compiler/orchestrator/profile.ts +36 -0
  281. package/src/forge/compiler/orchestrator/run.ts +277 -0
  282. package/src/forge/compiler/orchestrator/serialize.ts +886 -0
  283. package/src/forge/compiler/orchestrator/session.ts +96 -0
  284. package/src/forge/compiler/orchestrator/types.ts +31 -0
  285. package/src/forge/compiler/orchestrator/verify.ts +38 -0
  286. package/src/forge/compiler/orchestrator/workspace-index.ts +154 -0
  287. package/src/forge/compiler/package-graph/capabilities-stub.ts +33 -0
  288. package/src/forge/compiler/package-graph/checksum.ts +97 -0
  289. package/src/forge/compiler/package-graph/compiler.ts +392 -0
  290. package/src/forge/compiler/package-graph/constants.ts +4 -0
  291. package/src/forge/compiler/package-graph/dts-extractor.ts +142 -0
  292. package/src/forge/compiler/package-graph/exports-discovery.ts +84 -0
  293. package/src/forge/compiler/package-graph/extract-dts.ts +32 -0
  294. package/src/forge/compiler/package-graph/index.ts +33 -0
  295. package/src/forge/compiler/package-graph/jsdoc.ts +62 -0
  296. package/src/forge/compiler/package-graph/read-file.ts +21 -0
  297. package/src/forge/compiler/package-graph/resolve.ts +127 -0
  298. package/src/forge/compiler/package-manager/adapter.ts +237 -0
  299. package/src/forge/compiler/package-manager/bun-executable.ts +92 -0
  300. package/src/forge/compiler/package-manager/commands.ts +47 -0
  301. package/src/forge/compiler/package-manager/detect.ts +79 -0
  302. package/src/forge/compiler/package-manager/executor.ts +117 -0
  303. package/src/forge/compiler/package-manager/index.ts +22 -0
  304. package/src/forge/compiler/package-manager/parse-spec.ts +16 -0
  305. package/src/forge/compiler/package-manager/version.ts +27 -0
  306. package/src/forge/compiler/package-upgrades/apply.ts +195 -0
  307. package/src/forge/compiler/package-upgrades/comparator.ts +181 -0
  308. package/src/forge/compiler/package-upgrades/impact.ts +139 -0
  309. package/src/forge/compiler/package-upgrades/markdown.ts +97 -0
  310. package/src/forge/compiler/package-upgrades/planner.ts +532 -0
  311. package/src/forge/compiler/package-upgrades/risk.ts +208 -0
  312. package/src/forge/compiler/package-upgrades/types.ts +174 -0
  313. package/src/forge/compiler/policy-registry/build.ts +266 -0
  314. package/src/forge/compiler/policy-registry/constants.ts +2 -0
  315. package/src/forge/compiler/policy-registry/parse.ts +81 -0
  316. package/src/forge/compiler/primitives/compare.ts +26 -0
  317. package/src/forge/compiler/primitives/hash.ts +40 -0
  318. package/src/forge/compiler/primitives/header.ts +45 -0
  319. package/src/forge/compiler/primitives/index.ts +45 -0
  320. package/src/forge/compiler/primitives/paths.ts +24 -0
  321. package/src/forge/compiler/primitives/result.ts +164 -0
  322. package/src/forge/compiler/primitives/serialize.ts +66 -0
  323. package/src/forge/compiler/primitives/sort.ts +87 -0
  324. package/src/forge/compiler/query-registry/build.ts +114 -0
  325. package/src/forge/compiler/query-registry/constants.ts +2 -0
  326. package/src/forge/compiler/recipes/definitions.ts +289 -0
  327. package/src/forge/compiler/recipes/helpers.ts +37 -0
  328. package/src/forge/compiler/recipes/index.ts +21 -0
  329. package/src/forge/compiler/recipes/registry.ts +102 -0
  330. package/src/forge/compiler/release/build.ts +100 -0
  331. package/src/forge/compiler/release/types.ts +119 -0
  332. package/src/forge/compiler/runtime-graph/build.ts +137 -0
  333. package/src/forge/compiler/runtime-graph/constants.ts +5 -0
  334. package/src/forge/compiler/runtime-graph/index.ts +5 -0
  335. package/src/forge/compiler/sandbox/artifact-sanitize.ts +26 -0
  336. package/src/forge/compiler/sandbox/backends/child.ts +123 -0
  337. package/src/forge/compiler/sandbox/backends/docker.ts +173 -0
  338. package/src/forge/compiler/sandbox/index.ts +51 -0
  339. package/src/forge/compiler/sandbox/inspect.ts +143 -0
  340. package/src/forge/compiler/sandbox/inspector-entry.ts +115 -0
  341. package/src/forge/compiler/sandbox/limits.ts +31 -0
  342. package/src/forge/compiler/sandbox/scrub-env.ts +60 -0
  343. package/src/forge/compiler/sandbox/secret-scan.ts +54 -0
  344. package/src/forge/compiler/sandbox/serialize.ts +106 -0
  345. package/src/forge/compiler/sandbox/types.ts +7 -0
  346. package/src/forge/compiler/secret-registry/build.ts +123 -0
  347. package/src/forge/compiler/telemetry-registry/build.ts +89 -0
  348. package/src/forge/compiler/telemetry-registry/constants.ts +2 -0
  349. package/src/forge/compiler/telemetry-registry/parse.ts +13 -0
  350. package/src/forge/compiler/test-graph/build.ts +277 -0
  351. package/src/forge/compiler/types/action-subscriptions.ts +19 -0
  352. package/src/forge/compiler/types/ai-registry.ts +33 -0
  353. package/src/forge/compiler/types/app-graph.ts +80 -0
  354. package/src/forge/compiler/types/capability.ts +29 -0
  355. package/src/forge/compiler/types/classification.ts +9 -0
  356. package/src/forge/compiler/types/cli.ts +159 -0
  357. package/src/forge/compiler/types/data-graph.ts +24 -0
  358. package/src/forge/compiler/types/dev-manifest.ts +41 -0
  359. package/src/forge/compiler/types/diagnostic.ts +12 -0
  360. package/src/forge/compiler/types/emit.ts +25 -0
  361. package/src/forge/compiler/types/frontend-graph.ts +81 -0
  362. package/src/forge/compiler/types/import-guards.ts +19 -0
  363. package/src/forge/compiler/types/index.ts +98 -0
  364. package/src/forge/compiler/types/integration.ts +25 -0
  365. package/src/forge/compiler/types/json.ts +3 -0
  366. package/src/forge/compiler/types/live-query-registry.ts +32 -0
  367. package/src/forge/compiler/types/lock.ts +37 -0
  368. package/src/forge/compiler/types/package-graph.ts +84 -0
  369. package/src/forge/compiler/types/policy-registry.ts +69 -0
  370. package/src/forge/compiler/types/query-registry.ts +18 -0
  371. package/src/forge/compiler/types/runtime-graph.ts +30 -0
  372. package/src/forge/compiler/types/runtime-matrix.ts +16 -0
  373. package/src/forge/compiler/types/runtime.ts +30 -0
  374. package/src/forge/compiler/types/sandbox.ts +24 -0
  375. package/src/forge/compiler/types/secret-registry.ts +38 -0
  376. package/src/forge/compiler/types/telemetry-registry.ts +26 -0
  377. package/src/forge/compiler/types/test-graph.ts +45 -0
  378. package/src/forge/compiler/types/workflow-registry.ts +42 -0
  379. package/src/forge/compiler/workflow-registry/build.ts +180 -0
  380. package/src/forge/compiler/workflow-registry/constants.ts +2 -0
  381. package/src/forge/compiler/workflow-registry/index.ts +5 -0
  382. package/src/forge/compiler/workflow-registry/parse.ts +19 -0
  383. package/src/forge/dev/server.ts +1379 -0
  384. package/src/forge/dev/types.ts +49 -0
  385. package/src/forge/dev/watch.ts +109 -0
  386. package/src/forge/dev-console/cycle.ts +652 -0
  387. package/src/forge/dev-console/types.ts +99 -0
  388. package/src/forge/feature/compiler.ts +656 -0
  389. package/src/forge/feature/examples.ts +125 -0
  390. package/src/forge/feature/types.ts +177 -0
  391. package/src/forge/impact/index.ts +1160 -0
  392. package/src/forge/impact/types.ts +151 -0
  393. package/src/forge/intent/index.ts +490 -0
  394. package/src/forge/intent/types.ts +73 -0
  395. package/src/forge/make/fields.ts +146 -0
  396. package/src/forge/make/index.ts +1101 -0
  397. package/src/forge/make/naming.ts +42 -0
  398. package/src/forge/make/templates.ts +525 -0
  399. package/src/forge/make/types.ts +151 -0
  400. package/src/forge/platform/module.ts +20 -0
  401. package/src/forge/policy.ts +1 -0
  402. package/src/forge/react/index.ts +418 -0
  403. package/src/forge/refactor/index.ts +1936 -0
  404. package/src/forge/refactor/text-utils.ts +34 -0
  405. package/src/forge/refactor/types.ts +191 -0
  406. package/src/forge/refactor/workspace-fs.ts +171 -0
  407. package/src/forge/repair/index.ts +656 -0
  408. package/src/forge/repair/rules/index.ts +476 -0
  409. package/src/forge/repair/types.ts +175 -0
  410. package/src/forge/review/index.ts +992 -0
  411. package/src/forge/review/types.ts +196 -0
  412. package/src/forge/runtime/ai/check.ts +86 -0
  413. package/src/forge/runtime/ai/context.ts +394 -0
  414. package/src/forge/runtime/ai/cost-estimator.ts +41 -0
  415. package/src/forge/runtime/ai/mock.ts +49 -0
  416. package/src/forge/runtime/ai/providers.ts +78 -0
  417. package/src/forge/runtime/ai/state.ts +17 -0
  418. package/src/forge/runtime/ai/types.ts +67 -0
  419. package/src/forge/runtime/auth/authenticate.ts +58 -0
  420. package/src/forge/runtime/auth/claims.ts +119 -0
  421. package/src/forge/runtime/auth/config.ts +148 -0
  422. package/src/forge/runtime/auth/errors.ts +45 -0
  423. package/src/forge/runtime/auth/evaluate.ts +126 -0
  424. package/src/forge/runtime/auth/resolve.ts +74 -0
  425. package/src/forge/runtime/auth/types.ts +87 -0
  426. package/src/forge/runtime/auth/verifier.ts +138 -0
  427. package/src/forge/runtime/context/create-context.ts +204 -0
  428. package/src/forge/runtime/context/create-query-context.ts +34 -0
  429. package/src/forge/runtime/db/adapter.ts +31 -0
  430. package/src/forge/runtime/db/factory.ts +83 -0
  431. package/src/forge/runtime/db/generated-client.ts +294 -0
  432. package/src/forge/runtime/db/memory-adapter.ts +706 -0
  433. package/src/forge/runtime/db/migrate.ts +132 -0
  434. package/src/forge/runtime/db/outbox.ts +54 -0
  435. package/src/forge/runtime/db/pglite-adapter.ts +51 -0
  436. package/src/forge/runtime/db/postgres-adapter.ts +112 -0
  437. package/src/forge/runtime/db/read-only-client.ts +97 -0
  438. package/src/forge/runtime/db/session-context.ts +62 -0
  439. package/src/forge/runtime/executor.ts +446 -0
  440. package/src/forge/runtime/live/dependency-tracker.ts +57 -0
  441. package/src/forge/runtime/live/invalidation-log.ts +189 -0
  442. package/src/forge/runtime/live/live-query-runner.ts +267 -0
  443. package/src/forge/runtime/live/registry.ts +28 -0
  444. package/src/forge/runtime/live/sse.ts +75 -0
  445. package/src/forge/runtime/live/subscription-manager.ts +443 -0
  446. package/src/forge/runtime/live/types.ts +143 -0
  447. package/src/forge/runtime/outbox/claim.ts +153 -0
  448. package/src/forge/runtime/outbox/process.ts +298 -0
  449. package/src/forge/runtime/outbox/retry.ts +8 -0
  450. package/src/forge/runtime/outbox/subscriptions.ts +33 -0
  451. package/src/forge/runtime/outbox/types.ts +69 -0
  452. package/src/forge/runtime/policy/check.ts +157 -0
  453. package/src/forge/runtime/policy/load.ts +55 -0
  454. package/src/forge/runtime/query/registry.ts +19 -0
  455. package/src/forge/runtime/query/run-query.ts +347 -0
  456. package/src/forge/runtime/release/runtime.ts +322 -0
  457. package/src/forge/runtime/release/symbolicate.ts +175 -0
  458. package/src/forge/runtime/runner/command-transaction.ts +193 -0
  459. package/src/forge/runtime/runner/run-entry.ts +226 -0
  460. package/src/forge/runtime/secrets/check.ts +78 -0
  461. package/src/forge/runtime/secrets/create-context.ts +138 -0
  462. package/src/forge/runtime/secrets/env-loader.ts +94 -0
  463. package/src/forge/runtime/secrets/runtime-bundle.ts +47 -0
  464. package/src/forge/runtime/secrets/types.ts +31 -0
  465. package/src/forge/runtime/telemetry/buffer.ts +87 -0
  466. package/src/forge/runtime/telemetry/context.ts +192 -0
  467. package/src/forge/runtime/telemetry/correlation.ts +13 -0
  468. package/src/forge/runtime/telemetry/flush.ts +190 -0
  469. package/src/forge/runtime/telemetry/process.ts +20 -0
  470. package/src/forge/runtime/telemetry/scrubber.ts +115 -0
  471. package/src/forge/runtime/telemetry/sinks/local-jsonl.ts +39 -0
  472. package/src/forge/runtime/telemetry/sinks/posthog.ts +64 -0
  473. package/src/forge/runtime/telemetry/sinks/sentry.ts +60 -0
  474. package/src/forge/runtime/telemetry/spans.ts +58 -0
  475. package/src/forge/runtime/telemetry/types.ts +64 -0
  476. package/src/forge/runtime/workflows/cancel.ts +26 -0
  477. package/src/forge/runtime/workflows/create-run.ts +98 -0
  478. package/src/forge/runtime/workflows/process-run.ts +182 -0
  479. package/src/forge/runtime/workflows/process-step.ts +190 -0
  480. package/src/forge/runtime/workflows/process.ts +260 -0
  481. package/src/forge/runtime/workflows/registry.ts +51 -0
  482. package/src/forge/runtime/workflows/resolve-step.ts +46 -0
  483. package/src/forge/runtime/workflows/retry-run.ts +44 -0
  484. package/src/forge/runtime/workflows/retry.ts +8 -0
  485. package/src/forge/runtime/workflows/sanitize.ts +19 -0
  486. package/src/forge/runtime/workflows/start-from-outbox.ts +71 -0
  487. package/src/forge/runtime/workflows/types.ts +77 -0
  488. package/src/forge/server.ts +96 -0
  489. package/src/forge/ui/index.ts +770 -0
  490. package/src/forge/ui/types.ts +191 -0
  491. package/templates/b2b-support-web/.env.example +22 -0
  492. package/templates/b2b-support-web/.vscode/settings.json +14 -0
  493. package/templates/b2b-support-web/AGENTS.md +108 -0
  494. package/templates/b2b-support-web/README.md +48 -0
  495. package/templates/b2b-support-web/forge.config.ts +3 -0
  496. package/templates/b2b-support-web/package.json +34 -0
  497. package/templates/b2b-support-web/src/actions/captureTicketCreated.ts +14 -0
  498. package/templates/b2b-support-web/src/commands/closeTicket.ts +20 -0
  499. package/templates/b2b-support-web/src/commands/createTicket.ts +47 -0
  500. package/templates/b2b-support-web/src/commands/manageBilling.ts +9 -0
  501. package/templates/b2b-support-web/src/forge/schema.ts +35 -0
  502. package/templates/b2b-support-web/src/policies.ts +9 -0
  503. package/templates/b2b-support-web/src/queries/getTicket.ts +6 -0
  504. package/templates/b2b-support-web/src/queries/listTickets.ts +6 -0
  505. package/templates/b2b-support-web/src/queries/liveTickets.ts +9 -0
  506. package/templates/b2b-support-web/src/workflows/triageTicketWorkflow.ts +64 -0
  507. package/templates/b2b-support-web/tsconfig.json +14 -0
  508. package/templates/b2b-support-web/web/app/globals.css +77 -0
  509. package/templates/b2b-support-web/web/app/layout.tsx +13 -0
  510. package/templates/b2b-support-web/web/app/page.tsx +13 -0
  511. package/templates/b2b-support-web/web/app/providers.tsx +21 -0
  512. package/templates/b2b-support-web/web/app/tickets/page.tsx +21 -0
  513. package/templates/b2b-support-web/web/components/CreateTicketForm.tsx +43 -0
  514. package/templates/b2b-support-web/web/components/PolicyDeniedDemo.tsx +31 -0
  515. package/templates/b2b-support-web/web/components/TicketList.tsx +52 -0
  516. package/templates/b2b-support-web/web/components/TraceDetails.tsx +18 -0
  517. package/templates/b2b-support-web/web/components/TriageStatus.tsx +13 -0
  518. package/templates/b2b-support-web/web/lib/forge.ts +13 -0
  519. package/templates/b2b-support-web/web/next-env.d.ts +5 -0
  520. package/templates/b2b-support-web/web/next.config.ts +8 -0
  521. package/templates/b2b-support-web/web/package.json +21 -0
  522. package/templates/b2b-support-web/web/tsconfig.json +30 -0
  523. package/templates/minimal-web/.vscode/settings.json +14 -0
  524. package/templates/minimal-web/README.md +21 -0
  525. package/templates/minimal-web/forge.config.ts +3 -0
  526. package/templates/minimal-web/package.json +32 -0
  527. package/templates/minimal-web/src/actions/logNoteCreated.ts +11 -0
  528. package/templates/minimal-web/src/commands/createNote.ts +26 -0
  529. package/templates/minimal-web/src/forge/schema.ts +12 -0
  530. package/templates/minimal-web/src/policies.ts +6 -0
  531. package/templates/minimal-web/src/queries/listNotes.ts +8 -0
  532. package/templates/minimal-web/src/queries/liveNotes.ts +8 -0
  533. package/templates/minimal-web/tsconfig.json +15 -0
  534. package/templates/minimal-web/web/index.html +12 -0
  535. package/templates/minimal-web/web/package.json +21 -0
  536. package/templates/minimal-web/web/src/App.tsx +89 -0
  537. package/templates/minimal-web/web/src/lib/forge.ts +13 -0
  538. package/templates/minimal-web/web/src/main.tsx +13 -0
  539. package/templates/minimal-web/web/src/styles.css +156 -0
  540. package/templates/minimal-web/web/tsconfig.json +18 -0
@@ -0,0 +1,656 @@
1
+ import { join } from "node:path";
2
+ import { nodeFileSystem } from "../compiler/fs/index.ts";
3
+ import { spawn } from "node:child_process";
4
+ import { createDiagnostic } from "../compiler/diagnostics/create.ts";
5
+ import { hashStable } from "../compiler/primitives/hash.ts";
6
+ import { canonicalJson, serializeCanonical } from "../compiler/primitives/serialize.ts";
7
+ import type { Diagnostic } from "../compiler/types/diagnostic.ts";
8
+ import { resolveBunExecutable } from "../cli/bun-exec.ts";
9
+ import type { TestRunRecord } from "../impact/types.ts";
10
+ import type { UiRunReport } from "../ui/types.ts";
11
+ import { explainDiagnostic, repairRules } from "./rules/index.ts";
12
+ import type {
13
+ FailureInput,
14
+ RepairApplyRecord,
15
+ RepairCommandOptions,
16
+ RepairDiagnosis,
17
+ RepairPlan,
18
+ RepairResult,
19
+ SuggestedRepair,
20
+ } from "./types.ts";
21
+
22
+ export const REPAIR_DIR = ".forge/repairs";
23
+ const REPAIR_VERSION = "repair-0.1.0";
24
+
25
+ function normalize(path: string): string {
26
+ return path.replace(/\\/g, "/").replace(/^\.\//, "");
27
+ }
28
+
29
+ function diagnostic(
30
+ severity: Diagnostic["severity"],
31
+ code: string,
32
+ message: string,
33
+ file?: string,
34
+ ): Diagnostic {
35
+ return createDiagnostic({ severity, code, message, ...(file ? { file } : {}) });
36
+ }
37
+
38
+ function readJson<T>(workspaceRoot: string, relative: string): T | null {
39
+ const content = nodeFileSystem.readText(join(workspaceRoot, relative));
40
+ if (content === null) {
41
+ return null;
42
+ }
43
+ return JSON.parse(content) as T;
44
+ }
45
+
46
+ function writeJson(workspaceRoot: string, relative: string, value: unknown): void {
47
+ nodeFileSystem.writeText(join(workspaceRoot, relative), serializeCanonical(value));
48
+ }
49
+
50
+ function repairPath(id: string, file: string): string {
51
+ return `${REPAIR_DIR}/${id}/${file}`;
52
+ }
53
+
54
+ function emptyInput(source: FailureInput["source"]): FailureInput {
55
+ return {
56
+ source,
57
+ diagnostics: [],
58
+ failedCommands: [],
59
+ stdout: "",
60
+ stderr: "",
61
+ };
62
+ }
63
+
64
+ function parseDiagnosticsFromText(text: string): Diagnostic[] {
65
+ const diagnostics: Diagnostic[] = [];
66
+ const codeRegex = /\bFORGE_[A-Z0-9_]+\b/g;
67
+ const seen = new Set<string>();
68
+ let match: RegExpExecArray | null;
69
+ while ((match = codeRegex.exec(text))) {
70
+ const code = match[0];
71
+ if (seen.has(code)) {
72
+ continue;
73
+ }
74
+ seen.add(code);
75
+ const line = text
76
+ .slice(Math.max(0, match.index - 160), Math.min(text.length, match.index + 220))
77
+ .split(/\r?\n/)
78
+ .find((candidate) => candidate.includes(code));
79
+ diagnostics.push(
80
+ diagnostic("error", code, line?.trim() || `Detected ${code}`),
81
+ );
82
+ }
83
+ return diagnostics;
84
+ }
85
+
86
+ function inputFromTestRun(record: TestRunRecord, file: string): FailureInput {
87
+ const failedResults = record.results.filter((result) => !result.ok);
88
+ const stdout = failedResults.map((result) => result.stdout ?? "").join("\n");
89
+ const stderr = failedResults.map((result) => result.stderr ?? "").join("\n");
90
+ const diagnostics = parseDiagnosticsFromText(`${stdout}\n${stderr}`);
91
+ return {
92
+ source: { kind: "test-run", id: record.id, file },
93
+ diagnostics,
94
+ failedCommands: failedResults.map((result) => result.command),
95
+ stdout,
96
+ stderr,
97
+ };
98
+ }
99
+
100
+ function inputFromUiRun(record: UiRunReport, file: string): FailureInput {
101
+ const failed = record.scenarios.filter((scenario) => !scenario.ok);
102
+ const stdout = failed
103
+ .map((scenario) => `${scenario.name}: ${scenario.failure?.kind ?? "ui-failure"} ${scenario.failure?.message ?? ""} ${scenario.traceId ?? ""}`)
104
+ .join("\n");
105
+ const diagnostics = failed.map((scenario) =>
106
+ diagnostic(
107
+ "error",
108
+ scenario.failure?.kind === "live-query-no-update"
109
+ ? "FORGE_UI_LIVE_UPDATE_TIMEOUT"
110
+ : scenario.failure?.kind === "network-error"
111
+ ? "FORGE_UI_NETWORK_ERROR"
112
+ : scenario.failure?.kind === "browser-console-error"
113
+ ? "FORGE_UI_CONSOLE_ERROR"
114
+ : "FORGE_UI_EXPECTATION_FAILED",
115
+ scenario.failure?.message ?? `UI scenario failed: ${scenario.name}`,
116
+ file,
117
+ ),
118
+ );
119
+ return {
120
+ source: { kind: "ui-run", id: record.id, file },
121
+ diagnostics,
122
+ failedCommands: ["forge ui smoke"],
123
+ stdout,
124
+ stderr: "",
125
+ };
126
+ }
127
+
128
+ function collectFailureInput(options: RepairCommandOptions): FailureInput | null {
129
+ if (options.diagnosticCode) {
130
+ return {
131
+ ...emptyInput({ kind: "diagnostic", id: options.diagnosticCode }),
132
+ diagnostics: [
133
+ diagnostic(
134
+ "error",
135
+ options.diagnosticCode,
136
+ explainDiagnostic(options.diagnosticCode),
137
+ ),
138
+ ],
139
+ stdout: options.diagnosticCode,
140
+ };
141
+ }
142
+ if (options.traceId) {
143
+ return {
144
+ ...emptyInput({ kind: "trace", id: options.traceId }),
145
+ stdout: `trace ${options.traceId}`,
146
+ };
147
+ }
148
+ if (options.workflowRunId) {
149
+ return {
150
+ ...emptyInput({ kind: "workflow-run", id: options.workflowRunId }),
151
+ diagnostics: [
152
+ diagnostic(
153
+ "error",
154
+ "FORGE_WORKFLOW_STEP_FAILED",
155
+ `Workflow run ${options.workflowRunId} failed or needs inspection`,
156
+ ),
157
+ ],
158
+ stdout: `FORGE_WORKFLOW_STEP_FAILED workflow run ${options.workflowRunId}`,
159
+ };
160
+ }
161
+ if (options.outboxDeliveryId) {
162
+ return {
163
+ ...emptyInput({ kind: "outbox-delivery", id: options.outboxDeliveryId }),
164
+ diagnostics: [
165
+ diagnostic(
166
+ "error",
167
+ "FORGE_OUTBOX_PROCESS_FAILED",
168
+ `Outbox delivery ${options.outboxDeliveryId} failed or is dead-lettered`,
169
+ ),
170
+ ],
171
+ stdout: `FORGE_OUTBOX_PROCESS_FAILED delivery ${options.outboxDeliveryId}`,
172
+ };
173
+ }
174
+
175
+ if (options.fromLastUiRun) {
176
+ const file = ".forge/ui-runs/last.json";
177
+ const record = readJson<UiRunReport>(options.workspaceRoot, file);
178
+ if (!record) {
179
+ return null;
180
+ }
181
+ return inputFromUiRun(record, file);
182
+ }
183
+
184
+ const file = options.fromLastTestRun ? ".forge/test-runs/last.json" : options.from;
185
+ if (file) {
186
+ const record = readJson<TestRunRecord>(options.workspaceRoot, file);
187
+ if (!record) {
188
+ return null;
189
+ }
190
+ return inputFromTestRun(record, file);
191
+ }
192
+
193
+ return emptyInput({ kind: "manual" });
194
+ }
195
+
196
+ function fallbackDiagnosis(input: FailureInput): RepairDiagnosis {
197
+ const id = `repair_${hashStable(canonicalJson(input)).slice(0, 12)}`;
198
+ return {
199
+ schemaVersion: "0.1.0",
200
+ repairVersion: REPAIR_VERSION,
201
+ id,
202
+ failureKind: input.failedCommands.some((command) => command.includes("typecheck"))
203
+ ? "typecheck"
204
+ : input.failedCommands.length > 0
205
+ ? "test-failure"
206
+ : "unknown",
207
+ source: input.source,
208
+ diagnostics:
209
+ input.diagnostics.length > 0
210
+ ? input.diagnostics
211
+ : [
212
+ diagnostic(
213
+ "warning",
214
+ "FORGE_REPAIR_NO_RULE_MATCHED",
215
+ "No deterministic repair rule matched this failure.",
216
+ ),
217
+ ],
218
+ summary: "No deterministic repair rule matched this failure.",
219
+ likelyCause: "The failure does not match a known ForgeOS repair pattern yet. Inspect the failing command output and affected files.",
220
+ affected: {
221
+ files: [],
222
+ commands: [],
223
+ queries: [],
224
+ liveQueries: [],
225
+ actions: [],
226
+ workflows: [],
227
+ tables: [],
228
+ policies: [],
229
+ components: [],
230
+ packages: [],
231
+ },
232
+ suggestedRepairs: [
233
+ {
234
+ id: "manual-review",
235
+ kind: "manual",
236
+ title: "Manual review required",
237
+ description: "Read the failing output, inspect impacted files, then rerun forge test plan --changed.",
238
+ confidence: "low",
239
+ risk: { level: "medium", reasons: ["unknown failure class"] },
240
+ requiresConfirmation: true,
241
+ },
242
+ ],
243
+ recommendedChecks: ["forge test plan --changed", "forge verify --strict"],
244
+ confidence: "low",
245
+ };
246
+ }
247
+
248
+ export function diagnoseRepair(options: RepairCommandOptions): RepairResult {
249
+ const input = collectFailureInput(options);
250
+ if (!input) {
251
+ const source = options.fromLastUiRun
252
+ ? ".forge/ui-runs/last.json"
253
+ : options.fromLastTestRun
254
+ ? ".forge/test-runs/last.json"
255
+ : options.from ?? "<unknown>";
256
+ const diag = diagnostic(
257
+ "error",
258
+ "FORGE_REPAIR_SOURCE_NOT_FOUND",
259
+ `repair source not found: ${source}`,
260
+ source,
261
+ );
262
+ return { ok: false, diagnostics: [diag], exitCode: 1 };
263
+ }
264
+
265
+ const rule = repairRules.find((candidate) => candidate.matches(input));
266
+ const diagnosis = rule?.diagnose(input) ?? fallbackDiagnosis(input);
267
+ return {
268
+ ok: diagnosis.confidence !== "low" || diagnosis.failureKind !== "unknown",
269
+ diagnosis,
270
+ diagnostics: diagnosis.diagnostics,
271
+ exitCode: 0,
272
+ };
273
+ }
274
+
275
+ function planFromDiagnosis(diagnosis: RepairDiagnosis, selectedRepair?: string): RepairPlan {
276
+ const selected =
277
+ diagnosis.suggestedRepairs.find((repair) => repair.id === selectedRepair) ??
278
+ diagnosis.suggestedRepairs[0];
279
+ const commands = selected?.command ? [selected.command] : [];
280
+ const id = diagnosis.id;
281
+ return {
282
+ schemaVersion: "0.1.0",
283
+ repairVersion: REPAIR_VERSION,
284
+ id,
285
+ diagnosis,
286
+ selectedRepair: selected?.id,
287
+ filesToModify: selected?.patchPreview ?? [],
288
+ filesToCreate: [],
289
+ filesToDelete: [],
290
+ commandsToRun: commands,
291
+ verificationPlan: {
292
+ targeted: ["forge test plan --changed", "forge test run --changed"],
293
+ final: ["forge verify --strict"],
294
+ },
295
+ rollback: {
296
+ snapshotFile: repairPath(id, "rollback.json"),
297
+ files: diagnosis.affected.files,
298
+ instructions: [`forge repair rollback ${id}`],
299
+ },
300
+ diagnostics: [],
301
+ };
302
+ }
303
+
304
+ export function writeRepairPlan(workspaceRoot: string, plan: RepairPlan): void {
305
+ writeJson(workspaceRoot, repairPath(plan.id, "diagnosis.json"), plan.diagnosis);
306
+ writeJson(workspaceRoot, repairPath(plan.id, "plan.json"), plan);
307
+ const md = renderRepairPlanMarkdown(plan);
308
+ nodeFileSystem.writeText(join(workspaceRoot, repairPath(plan.id, "plan.md")), md);
309
+ }
310
+
311
+ export function buildRepairPlan(options: RepairCommandOptions): RepairResult {
312
+ const diagnosed = diagnoseRepair(options);
313
+ if (!diagnosed.diagnosis) {
314
+ return diagnosed;
315
+ }
316
+ const plan = planFromDiagnosis(diagnosed.diagnosis, options.selectedRepair);
317
+ if (options.write || options.subcommand === "plan") {
318
+ writeRepairPlan(options.workspaceRoot, plan);
319
+ }
320
+ return {
321
+ ok: true,
322
+ diagnosis: diagnosed.diagnosis,
323
+ plan,
324
+ diagnostics: plan.diagnostics,
325
+ exitCode: 0,
326
+ };
327
+ }
328
+
329
+ function loadRepairPlan(workspaceRoot: string, idOrPath: string): RepairPlan | null {
330
+ const candidates = [
331
+ idOrPath,
332
+ repairPath(idOrPath, "plan.json"),
333
+ ];
334
+ for (const candidate of candidates) {
335
+ const plan = readJson<RepairPlan>(workspaceRoot, candidate);
336
+ if (plan) {
337
+ return plan;
338
+ }
339
+ }
340
+ return null;
341
+ }
342
+
343
+ export function listRepairPlans(workspaceRoot: string): RepairPlan[] {
344
+ const absolute = join(workspaceRoot, REPAIR_DIR);
345
+ return nodeFileSystem
346
+ .readDir(absolute)
347
+ .map((entry) => readJson<RepairPlan>(workspaceRoot, repairPath(entry.name, "plan.json")))
348
+ .filter((plan): plan is RepairPlan => Boolean(plan))
349
+ .sort((a, b) => a.id.localeCompare(b.id));
350
+ }
351
+
352
+ function commandArgs(command: string): { executable: string; args: string[] } {
353
+ const bun = resolveBunExecutable();
354
+ const parts = command.split(/\s+/).filter(Boolean);
355
+ if (parts[0] === "forge") {
356
+ return { executable: bun, args: ["src/forge/cli/main.ts", ...parts.slice(1)] };
357
+ }
358
+ if (parts[0] === "bun") {
359
+ return { executable: bun, args: parts.slice(1) };
360
+ }
361
+ return { executable: parts[0] ?? bun, args: parts.slice(1) };
362
+ }
363
+
364
+ async function runCommand(workspaceRoot: string, command: string): Promise<RepairApplyRecord["results"][number]> {
365
+ const resolved = commandArgs(command);
366
+ return new Promise((resolve) => {
367
+ const child = spawn(resolved.executable, resolved.args, {
368
+ cwd: workspaceRoot,
369
+ env: process.env,
370
+ stdio: ["ignore", "pipe", "pipe"],
371
+ windowsHide: true,
372
+ });
373
+ let stdout = "";
374
+ let stderr = "";
375
+ child.stdout?.on("data", (chunk) => {
376
+ stdout += String(chunk);
377
+ });
378
+ child.stderr?.on("data", (chunk) => {
379
+ stderr += String(chunk);
380
+ });
381
+ child.on("error", (error) => {
382
+ resolve({ command, ok: false, exitCode: 1, stderr: error.message });
383
+ });
384
+ child.on("close", (code) => {
385
+ resolve({ command, ok: (code ?? 1) === 0, exitCode: code ?? 1, stdout, stderr });
386
+ });
387
+ });
388
+ }
389
+
390
+ function snapshotFiles(workspaceRoot: string, plan: RepairPlan): void {
391
+ const files = plan.rollback.files.filter(Boolean);
392
+ const snapshot = files.map((file) => {
393
+ const absolute = join(workspaceRoot, normalize(file));
394
+ const content = nodeFileSystem.readText(absolute);
395
+ return {
396
+ file: normalize(file),
397
+ existed: content !== null,
398
+ content,
399
+ };
400
+ });
401
+ writeJson(workspaceRoot, plan.rollback.snapshotFile, { files: snapshot });
402
+ }
403
+
404
+ function restoreSnapshot(workspaceRoot: string, plan: RepairPlan): void {
405
+ const snapshot = readJson<{ files: Array<{ file: string; existed: boolean; content: string | null }> }>(
406
+ workspaceRoot,
407
+ plan.rollback.snapshotFile,
408
+ );
409
+ if (!snapshot) {
410
+ return;
411
+ }
412
+ for (const file of snapshot.files) {
413
+ const absolute = join(workspaceRoot, normalize(file.file));
414
+ if (!file.existed) {
415
+ nodeFileSystem.remove(absolute);
416
+ continue;
417
+ }
418
+ nodeFileSystem.writeText(absolute, file.content ?? "");
419
+ }
420
+ }
421
+
422
+ function canAutoApply(repair: SuggestedRepair | undefined, options: RepairCommandOptions): boolean {
423
+ if (!repair) {
424
+ return false;
425
+ }
426
+ if (repair.kind === "manual" || repair.kind === "patch") {
427
+ return false;
428
+ }
429
+ if (repair.confidence === "high") {
430
+ return true;
431
+ }
432
+ return repair.confidence === "medium" && options.allowMediumConfidence;
433
+ }
434
+
435
+ export async function applyRepair(options: RepairCommandOptions): Promise<RepairResult> {
436
+ const plan = options.repairId ? loadRepairPlan(options.workspaceRoot, options.repairId) : buildRepairPlan({ ...options, write: true }).plan;
437
+ if (!plan) {
438
+ const diag = diagnostic(
439
+ "error",
440
+ "FORGE_REPAIR_SOURCE_NOT_FOUND",
441
+ `repair plan not found: ${options.repairId ?? "<new plan>"}`,
442
+ );
443
+ return { ok: false, diagnostics: [diag], exitCode: 1 };
444
+ }
445
+ const selected = plan.diagnosis.suggestedRepairs.find((repair) => repair.id === plan.selectedRepair);
446
+ if (!options.yes && selected?.requiresConfirmation) {
447
+ const diag = diagnostic(
448
+ "error",
449
+ "FORGE_REPAIR_UNSAFE_AUTO_APPLY",
450
+ "repair requires confirmation; rerun with --yes",
451
+ );
452
+ return { ok: false, plan, diagnostics: [diag], exitCode: 1 };
453
+ }
454
+ if (!canAutoApply(selected, options)) {
455
+ const diag = diagnostic(
456
+ "error",
457
+ selected?.confidence === "low" ? "FORGE_REPAIR_LOW_CONFIDENCE" : "FORGE_REPAIR_UNSAFE_AUTO_APPLY",
458
+ "repair is not safe for automatic application",
459
+ );
460
+ return { ok: false, plan, diagnostics: [diag], exitCode: 1 };
461
+ }
462
+
463
+ snapshotFiles(options.workspaceRoot, plan);
464
+ const results = [];
465
+ for (const command of plan.commandsToRun) {
466
+ const result = await runCommand(options.workspaceRoot, command);
467
+ results.push(result);
468
+ if (!result.ok) {
469
+ break;
470
+ }
471
+ }
472
+ const failed = results.some((result) => !result.ok);
473
+ if (failed && !options.keepFailed) {
474
+ restoreSnapshot(options.workspaceRoot, plan);
475
+ }
476
+ const record: RepairApplyRecord = {
477
+ schemaVersion: "0.1.0",
478
+ id: `apply_${hashStable(`${plan.id}:${canonicalJson(results)}`).slice(0, 12)}`,
479
+ repairId: plan.id,
480
+ status: failed ? "failed" : "applied",
481
+ commandsRun: plan.commandsToRun,
482
+ results,
483
+ };
484
+ writeJson(options.workspaceRoot, repairPath(plan.id, "applied.json"), record);
485
+ return {
486
+ ok: !failed,
487
+ plan,
488
+ record,
489
+ diagnostics: failed
490
+ ? [
491
+ diagnostic(
492
+ "error",
493
+ "FORGE_REPAIR_APPLY_FAILED",
494
+ "repair command failed; rollback was attempted unless --keep-failed was set",
495
+ ),
496
+ ]
497
+ : [],
498
+ exitCode: failed ? 1 : 0,
499
+ };
500
+ }
501
+
502
+ export async function runRepairLoop(options: RepairCommandOptions): Promise<RepairResult> {
503
+ let last: RepairResult = { ok: false, diagnostics: [], exitCode: 1 };
504
+ const attempts = Math.max(1, options.maxAttempts || 1);
505
+ for (let index = 0; index < attempts; index++) {
506
+ const planned = buildRepairPlan({ ...options, subcommand: "plan", write: true });
507
+ if (!planned.plan) {
508
+ return planned;
509
+ }
510
+ last = await applyRepair({
511
+ ...options,
512
+ subcommand: "apply",
513
+ repairId: planned.plan.id,
514
+ yes: true,
515
+ });
516
+ if (!last.ok) {
517
+ return last;
518
+ }
519
+ break;
520
+ }
521
+ return last;
522
+ }
523
+
524
+ export function rollbackRepair(options: RepairCommandOptions): RepairResult {
525
+ const plan = options.repairId ? loadRepairPlan(options.workspaceRoot, options.repairId) : null;
526
+ if (!plan) {
527
+ const diag = diagnostic("error", "FORGE_REPAIR_SOURCE_NOT_FOUND", `repair plan not found: ${options.repairId ?? ""}`);
528
+ return { ok: false, diagnostics: [diag], exitCode: 1 };
529
+ }
530
+ restoreSnapshot(options.workspaceRoot, plan);
531
+ const record: RepairApplyRecord = {
532
+ schemaVersion: "0.1.0",
533
+ id: `rollback_${hashStable(plan.id).slice(0, 12)}`,
534
+ repairId: plan.id,
535
+ status: "rolled-back",
536
+ commandsRun: [],
537
+ results: [],
538
+ };
539
+ writeJson(options.workspaceRoot, repairPath(plan.id, "applied.json"), record);
540
+ return { ok: true, plan, record, diagnostics: [], exitCode: 0 };
541
+ }
542
+
543
+ export async function runRepairCommand(options: RepairCommandOptions): Promise<RepairResult> {
544
+ if (options.subcommand === "explain") {
545
+ return {
546
+ ok: true,
547
+ explanation: explainDiagnostic(options.diagnosticCode ?? options.repairId ?? ""),
548
+ diagnostics: [],
549
+ exitCode: 0,
550
+ };
551
+ }
552
+ if (options.subcommand === "diagnose") {
553
+ const result = diagnoseRepair(options);
554
+ if (result.diagnosis && options.write) {
555
+ writeJson(options.workspaceRoot, repairPath(result.diagnosis.id, "diagnosis.json"), result.diagnosis);
556
+ }
557
+ return result;
558
+ }
559
+ if (options.subcommand === "plan") {
560
+ return buildRepairPlan(options);
561
+ }
562
+ if (options.subcommand === "apply") {
563
+ return applyRepair(options);
564
+ }
565
+ if (options.subcommand === "run") {
566
+ return runRepairLoop(options);
567
+ }
568
+ if (options.subcommand === "list") {
569
+ return { ok: true, plans: listRepairPlans(options.workspaceRoot), diagnostics: [], exitCode: 0 };
570
+ }
571
+ if (options.subcommand === "inspect") {
572
+ const plan = options.repairId ? loadRepairPlan(options.workspaceRoot, options.repairId) : null;
573
+ if (!plan) {
574
+ const diag = diagnostic("error", "FORGE_REPAIR_SOURCE_NOT_FOUND", `repair plan not found: ${options.repairId ?? ""}`);
575
+ return { ok: false, diagnostics: [diag], exitCode: 1 };
576
+ }
577
+ return { ok: true, plan, diagnosis: plan.diagnosis, diagnostics: [], exitCode: 0 };
578
+ }
579
+ if (options.subcommand === "rollback") {
580
+ return rollbackRepair(options);
581
+ }
582
+ return { ok: false, diagnostics: [diagnostic("error", "FORGE_REPAIR_UNKNOWN_FAILURE", "unknown repair command")], exitCode: 1 };
583
+ }
584
+
585
+ export function renderRepairPlanMarkdown(plan: RepairPlan): string {
586
+ const repair = plan.diagnosis.suggestedRepairs.find((candidate) => candidate.id === plan.selectedRepair);
587
+ return `# Repair Plan: ${plan.diagnosis.summary}
588
+
589
+ Failure kind: ${plan.diagnosis.failureKind}
590
+
591
+ ## Likely Cause
592
+
593
+ ${plan.diagnosis.likelyCause}
594
+
595
+ ## Affected Files
596
+
597
+ ${plan.diagnosis.affected.files.map((file) => `- ${file}`).join("\n") || "- none detected"}
598
+
599
+ ## Suggested Repair
600
+
601
+ ${repair ? `- ${repair.title}: ${repair.description}` : "- manual review"}
602
+
603
+ ${repair?.command ? `\`\`\`bash\n${repair.command}\n\`\`\`` : ""}
604
+
605
+ ## Verification
606
+
607
+ \`\`\`bash
608
+ ${plan.verificationPlan.targeted.concat(plan.verificationPlan.final).join("\n")}
609
+ \`\`\`
610
+ `;
611
+ }
612
+
613
+ export function formatRepairJson(result: RepairResult): string {
614
+ const body = result.record
615
+ ? { ok: result.ok, plan: result.plan, record: result.record, diagnostics: result.diagnostics }
616
+ : result.plan ?? result.diagnosis ?? result.plans ?? { explanation: result.explanation, diagnostics: result.diagnostics };
617
+ return `${JSON.stringify(body, null, 2)}\n`;
618
+ }
619
+
620
+ export function formatRepairHuman(result: RepairResult): string {
621
+ if (result.explanation) {
622
+ return `${result.explanation}\n`;
623
+ }
624
+ if (result.diagnosis && !result.plan) {
625
+ const repair = result.diagnosis.suggestedRepairs[0];
626
+ return `Repair diagnosis
627
+
628
+ Failure kind:
629
+ ${result.diagnosis.failureKind}
630
+
631
+ Summary:
632
+ ${result.diagnosis.summary}
633
+
634
+ Likely cause:
635
+ ${result.diagnosis.likelyCause}
636
+
637
+ Suggested repair:
638
+ ${repair?.command ?? repair?.description ?? "manual review"}
639
+
640
+ Next checks:
641
+ ${result.diagnosis.recommendedChecks.map((check) => ` - ${check}`).join("\n")}
642
+ `;
643
+ }
644
+ if (result.plan) {
645
+ return renderRepairPlanMarkdown(result.plan);
646
+ }
647
+ if (result.plans) {
648
+ return `${result.plans.map((plan) => `${plan.id}: ${plan.diagnosis.summary}`).join("\n")}\n`;
649
+ }
650
+ if (result.record) {
651
+ return `Repair ${result.record.status}: ${result.record.repairId}
652
+ ${result.record.results.map((step) => `${step.ok ? "OK" : "FAIL"} ${step.command}`).join("\n")}
653
+ `;
654
+ }
655
+ return `${result.diagnostics.map((diag) => diag.message).join("\n")}\n`;
656
+ }