forgeos 0.1.0-alpha.2 → 0.1.0-alpha.21

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 (406) hide show
  1. package/.npmignore +4 -0
  2. package/AGENTS.md +168 -81
  3. package/CHANGELOG.md +211 -0
  4. package/README.md +88 -14
  5. package/adapters/go/README.md +23 -0
  6. package/adapters/go/go.mod +3 -0
  7. package/adapters/go/http.go +149 -0
  8. package/adapters/go/registry.go +234 -0
  9. package/adapters/go/types.go +136 -0
  10. package/adapters/java/README.md +68 -0
  11. package/adapters/java/pom.xml +34 -0
  12. package/adapters/java/src/main/java/dev/forgeos/adapter/Auth.java +20 -0
  13. package/adapters/java/src/main/java/dev/forgeos/adapter/Diagnostic.java +16 -0
  14. package/adapters/java/src/main/java/dev/forgeos/adapter/Entry.java +38 -0
  15. package/adapters/java/src/main/java/dev/forgeos/adapter/EntryKind.java +16 -0
  16. package/adapters/java/src/main/java/dev/forgeos/adapter/ErrorInfo.java +4 -0
  17. package/adapters/java/src/main/java/dev/forgeos/adapter/Forge.java +94 -0
  18. package/adapters/java/src/main/java/dev/forgeos/adapter/ForgeCall.java +12 -0
  19. package/adapters/java/src/main/java/dev/forgeos/adapter/ForgeContext.java +11 -0
  20. package/adapters/java/src/main/java/dev/forgeos/adapter/ForgeHandler.java +8 -0
  21. package/adapters/java/src/main/java/dev/forgeos/adapter/ForgeHttpHandler.java +179 -0
  22. package/adapters/java/src/main/java/dev/forgeos/adapter/ForgeRegistry.java +121 -0
  23. package/adapters/java/src/main/java/dev/forgeos/adapter/Json.java +14 -0
  24. package/adapters/java/src/main/java/dev/forgeos/adapter/Manifest.java +14 -0
  25. package/adapters/java/src/main/java/dev/forgeos/adapter/RequestEnvelope.java +6 -0
  26. package/adapters/java/src/main/java/dev/forgeos/adapter/ResponseEnvelope.java +25 -0
  27. package/adapters/java/src/main/java/dev/forgeos/adapter/Risk.java +18 -0
  28. package/adapters/java/src/main/java/dev/forgeos/adapter/Schemas.java +36 -0
  29. package/adapters/java/src/main/java/dev/forgeos/adapter/Service.java +65 -0
  30. package/adapters/java/src/main/java/dev/forgeos/adapter/TransactionMode.java +18 -0
  31. package/adapters/java/src/main/java/dev/forgeos/adapter/TypedForgeHandler.java +6 -0
  32. package/adapters/java/target/classes/dev/forgeos/adapter/Auth.class +0 -0
  33. package/adapters/java/target/classes/dev/forgeos/adapter/Diagnostic.class +0 -0
  34. package/adapters/java/target/classes/dev/forgeos/adapter/Entry.class +0 -0
  35. package/adapters/java/target/classes/dev/forgeos/adapter/EntryKind.class +0 -0
  36. package/adapters/java/target/classes/dev/forgeos/adapter/ErrorInfo.class +0 -0
  37. package/adapters/java/target/classes/dev/forgeos/adapter/Forge.class +0 -0
  38. package/adapters/java/target/classes/dev/forgeos/adapter/ForgeCall.class +0 -0
  39. package/adapters/java/target/classes/dev/forgeos/adapter/ForgeContext.class +0 -0
  40. package/adapters/java/target/classes/dev/forgeos/adapter/ForgeHandler.class +0 -0
  41. package/adapters/java/target/classes/dev/forgeos/adapter/ForgeHttpHandler.class +0 -0
  42. package/adapters/java/target/classes/dev/forgeos/adapter/ForgeRegistry$EntryOption.class +0 -0
  43. package/adapters/java/target/classes/dev/forgeos/adapter/ForgeRegistry$RegisteredEntry.class +0 -0
  44. package/adapters/java/target/classes/dev/forgeos/adapter/ForgeRegistry$RegistryOption.class +0 -0
  45. package/adapters/java/target/classes/dev/forgeos/adapter/ForgeRegistry.class +0 -0
  46. package/adapters/java/target/classes/dev/forgeos/adapter/Json.class +0 -0
  47. package/adapters/java/target/classes/dev/forgeos/adapter/Manifest.class +0 -0
  48. package/adapters/java/target/classes/dev/forgeos/adapter/RequestEnvelope.class +0 -0
  49. package/adapters/java/target/classes/dev/forgeos/adapter/ResponseEnvelope.class +0 -0
  50. package/adapters/java/target/classes/dev/forgeos/adapter/Risk.class +0 -0
  51. package/adapters/java/target/classes/dev/forgeos/adapter/Schemas.class +0 -0
  52. package/adapters/java/target/classes/dev/forgeos/adapter/Service.class +0 -0
  53. package/adapters/java/target/classes/dev/forgeos/adapter/TransactionMode.class +0 -0
  54. package/adapters/java/target/classes/dev/forgeos/adapter/TypedForgeHandler.class +0 -0
  55. package/adapters/java/target/forge-java-adapter-0.1.0-alpha.11.jar +0 -0
  56. package/adapters/java/target/maven-archiver/pom.properties +3 -0
  57. package/adapters/java/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst +23 -0
  58. package/adapters/java/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst +20 -0
  59. package/adapters/java-spring-boot-starter/README.md +32 -0
  60. package/adapters/java-spring-boot-starter/pom.xml +36 -0
  61. package/adapters/java-spring-boot-starter/src/main/java/dev/forgeos/adapter/spring/ForgeCommand.java +22 -0
  62. package/adapters/java-spring-boot-starter/src/main/java/dev/forgeos/adapter/spring/ForgeExternalService.java +15 -0
  63. package/adapters/java-spring-boot-starter/src/main/java/dev/forgeos/adapter/spring/ForgeQuery.java +16 -0
  64. package/adapters/java-spring-boot-starter/src/main/java/dev/forgeos/adapter/spring/ForgeServiceBeanCondition.java +18 -0
  65. package/adapters/java-spring-boot-starter/src/main/java/dev/forgeos/adapter/spring/ForgeSpringAutoConfiguration.java +16 -0
  66. package/adapters/java-spring-boot-starter/src/main/java/dev/forgeos/adapter/spring/ForgeSpringRuntime.java +104 -0
  67. package/adapters/java-spring-boot-starter/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports +1 -0
  68. package/adapters/java-spring-boot-starter/target/classes/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports +1 -0
  69. package/adapters/java-spring-boot-starter/target/classes/dev/forgeos/adapter/spring/ForgeCommand.class +0 -0
  70. package/adapters/java-spring-boot-starter/target/classes/dev/forgeos/adapter/spring/ForgeExternalService.class +0 -0
  71. package/adapters/java-spring-boot-starter/target/classes/dev/forgeos/adapter/spring/ForgeQuery.class +0 -0
  72. package/adapters/java-spring-boot-starter/target/classes/dev/forgeos/adapter/spring/ForgeServiceBeanCondition.class +0 -0
  73. package/adapters/java-spring-boot-starter/target/classes/dev/forgeos/adapter/spring/ForgeSpringAutoConfiguration.class +0 -0
  74. package/adapters/java-spring-boot-starter/target/classes/dev/forgeos/adapter/spring/ForgeSpringRuntime.class +0 -0
  75. package/adapters/java-spring-boot-starter/target/forge-java-spring-boot-starter-0.1.0-alpha.11.jar +0 -0
  76. package/adapters/java-spring-boot-starter/target/maven-archiver/pom.properties +3 -0
  77. package/adapters/java-spring-boot-starter/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst +6 -0
  78. package/adapters/java-spring-boot-starter/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst +6 -0
  79. package/bin/forge.mjs +18 -0
  80. package/docs/changelog.md +242 -0
  81. package/docs/forge-protocol.md +189 -0
  82. package/examples/go-billing/go.mod +7 -0
  83. package/examples/go-billing/main.go +120 -0
  84. package/examples/java-billing/pom.xml +52 -0
  85. package/examples/java-billing/src/main/java/dev/forgeos/examples/billing/CreateInvoiceInput.java +4 -0
  86. package/examples/java-billing/src/main/java/dev/forgeos/examples/billing/Invoice.java +11 -0
  87. package/examples/java-billing/src/main/java/dev/forgeos/examples/billing/Main.java +127 -0
  88. package/examples/java-billing/target/classes/dev/forgeos/examples/billing/CreateInvoiceInput.class +0 -0
  89. package/examples/java-billing/target/classes/dev/forgeos/examples/billing/Invoice.class +0 -0
  90. package/examples/java-billing/target/classes/dev/forgeos/examples/billing/Main$EmptyInput.class +0 -0
  91. package/examples/java-billing/target/classes/dev/forgeos/examples/billing/Main$Options.class +0 -0
  92. package/examples/java-billing/target/classes/dev/forgeos/examples/billing/Main.class +0 -0
  93. package/examples/java-billing/target/java-billing-0.1.0-alpha.11-all.jar +0 -0
  94. package/examples/java-billing/target/java-billing-0.1.0-alpha.11.jar +0 -0
  95. package/examples/java-billing/target/maven-archiver/pom.properties +3 -0
  96. package/examples/java-billing/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst +5 -0
  97. package/examples/java-billing/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst +3 -0
  98. package/package.json +29 -7
  99. package/schemas/forge-manifest.schema.json +57 -0
  100. package/src/forge/_generated/releaseManifest.json +1 -2
  101. package/src/forge/_generated/releaseManifest.ts +3 -3
  102. package/src/forge/agent-adapters/index.ts +1511 -123
  103. package/src/forge/agent-adapters/types.ts +216 -1
  104. package/src/forge/agent-memory/bridge.ts +1245 -0
  105. package/src/forge/agent-memory/context-pack.ts +151 -0
  106. package/src/forge/agent-memory/hook-runner.ts +312 -0
  107. package/src/forge/agent-memory/mcp.ts +224 -0
  108. package/src/forge/agent-memory/normalize.ts +498 -0
  109. package/src/forge/agent-memory/redaction.ts +103 -0
  110. package/src/forge/agent-memory/sources/claude-code.ts +51 -0
  111. package/src/forge/agent-memory/sources/codex-hook-runner.mjs +273 -0
  112. package/src/forge/agent-memory/sources/codex.ts +119 -0
  113. package/src/forge/agent-memory/sources/cursor.ts +35 -0
  114. package/src/forge/agent-memory/types.ts +191 -0
  115. package/src/forge/bench.ts +248 -0
  116. package/src/forge/brownfield-import/index.ts +801 -0
  117. package/src/forge/brownfield-import/types.ts +127 -0
  118. package/src/forge/cair/action-journal.ts +61 -0
  119. package/src/forge/cair/action-parser.ts +314 -0
  120. package/src/forge/cair/action-validator.ts +40 -0
  121. package/src/forge/cair/actions.ts +1818 -0
  122. package/src/forge/cair/format.ts +77 -0
  123. package/src/forge/cair/index.ts +106 -0
  124. package/src/forge/cair/query.ts +478 -0
  125. package/src/forge/cair/snapshot.ts +315 -0
  126. package/src/forge/cair/types.ts +248 -0
  127. package/src/forge/cli/ai.ts +671 -3
  128. package/src/forge/cli/auth.ts +36 -1
  129. package/src/forge/cli/build.ts +20 -4
  130. package/src/forge/cli/changed.ts +300 -0
  131. package/src/forge/cli/codex-app-server.ts +877 -0
  132. package/src/forge/cli/commands.ts +1285 -7
  133. package/src/forge/cli/db.ts +121 -2
  134. package/src/forge/cli/deps.ts +79 -12
  135. package/src/forge/cli/dev.ts +502 -38
  136. package/src/forge/cli/docs.ts +265 -0
  137. package/src/forge/cli/handoff.ts +250 -0
  138. package/src/forge/cli/index.ts +1 -0
  139. package/src/forge/cli/main.ts +49 -3
  140. package/src/forge/cli/new.ts +3 -1
  141. package/src/forge/cli/next-actions.ts +23 -0
  142. package/src/forge/cli/output.ts +290 -1
  143. package/src/forge/cli/parse.ts +770 -36
  144. package/src/forge/cli/query.ts +32 -0
  145. package/src/forge/cli/release.ts +35 -11
  146. package/src/forge/cli/rls.ts +568 -17
  147. package/src/forge/cli/run.ts +41 -0
  148. package/src/forge/cli/secrets.ts +46 -1
  149. package/src/forge/cli/security.ts +381 -0
  150. package/src/forge/cli/self-host.ts +56 -14
  151. package/src/forge/cli/studio.ts +2163 -0
  152. package/src/forge/cli/verify.ts +1422 -32
  153. package/src/forge/compiler/agent-contract/build.ts +725 -41
  154. package/src/forge/compiler/agent-contract/types.ts +85 -0
  155. package/src/forge/compiler/ai-registry/build.ts +62 -1
  156. package/src/forge/compiler/ai-registry/constants.ts +1 -1
  157. package/src/forge/compiler/ai-registry/parse.ts +168 -5
  158. package/src/forge/compiler/api-surface/build.ts +47 -0
  159. package/src/forge/compiler/app-graph/build.ts +68 -8
  160. package/src/forge/compiler/app-graph/extract.ts +107 -0
  161. package/src/forge/compiler/app-graph/forge-apis.ts +1 -0
  162. package/src/forge/compiler/app-graph/module-graph.ts +73 -78
  163. package/src/forge/compiler/app-graph/parser.ts +24 -24
  164. package/src/forge/compiler/app-graph/profile.ts +26 -0
  165. package/src/forge/compiler/app-graph/versions.ts +1 -1
  166. package/src/forge/compiler/classifier/capabilities.ts +3 -2
  167. package/src/forge/compiler/classifier/classify.ts +32 -8
  168. package/src/forge/compiler/classifier/secrets.ts +3 -2
  169. package/src/forge/compiler/classifier/signals.ts +91 -1
  170. package/src/forge/compiler/client-sdk/build-manifest.ts +59 -0
  171. package/src/forge/compiler/client-sdk/render-client.ts +188 -13
  172. package/src/forge/compiler/data-graph/parse.ts +3 -3
  173. package/src/forge/compiler/data-graph/sql/ddl.ts +60 -2
  174. package/src/forge/compiler/data-graph/sql/serialize.ts +4 -0
  175. package/src/forge/compiler/data-graph/sql/types.ts +1 -0
  176. package/src/forge/compiler/dev-manifest/build.ts +3 -0
  177. package/src/forge/compiler/diagnostics/codes.ts +35 -0
  178. package/src/forge/compiler/diagnostics/create.ts +8 -3
  179. package/src/forge/compiler/diagnostics/index.ts +2 -0
  180. package/src/forge/compiler/emitter/barrel.ts +3 -0
  181. package/src/forge/compiler/emitter/render.ts +5 -0
  182. package/src/forge/compiler/external-manifest/registry.ts +205 -0
  183. package/src/forge/compiler/external-manifest/types.ts +91 -0
  184. package/src/forge/compiler/external-manifest/validate.ts +373 -0
  185. package/src/forge/compiler/frontend-graph/build.ts +85 -13
  186. package/src/forge/compiler/integration/add.ts +498 -22
  187. package/src/forge/compiler/integration/snapshot.ts +2 -0
  188. package/src/forge/compiler/make-registry/build.ts +19 -7
  189. package/src/forge/compiler/orchestrator/plan-profile.ts +23 -0
  190. package/src/forge/compiler/orchestrator/plan.ts +78 -7
  191. package/src/forge/compiler/orchestrator/profile.ts +65 -0
  192. package/src/forge/compiler/orchestrator/run.ts +97 -31
  193. package/src/forge/compiler/orchestrator/serialize.ts +101 -8
  194. package/src/forge/compiler/package-graph/compiler.ts +13 -3
  195. package/src/forge/compiler/package-manager/adapter.ts +4 -1
  196. package/src/forge/compiler/package-manager/commands.ts +4 -0
  197. package/src/forge/compiler/package-manager/executor.ts +30 -1
  198. package/src/forge/compiler/policy-registry/build.ts +44 -1
  199. package/src/forge/compiler/test-graph/build.ts +11 -3
  200. package/src/forge/compiler/types/ai-registry.ts +25 -1
  201. package/src/forge/compiler/types/app-graph.ts +9 -2
  202. package/src/forge/compiler/types/cli.ts +76 -1
  203. package/src/forge/compiler/types/dev-manifest.ts +3 -0
  204. package/src/forge/compiler/types/frontend-graph.ts +2 -2
  205. package/src/forge/delta/classifier.ts +52 -0
  206. package/src/forge/delta/explain.ts +126 -0
  207. package/src/forge/delta/git-observer.ts +43 -0
  208. package/src/forge/delta/ids.ts +44 -0
  209. package/src/forge/delta/index.ts +13 -0
  210. package/src/forge/delta/recorder.ts +402 -0
  211. package/src/forge/delta/redaction.ts +50 -0
  212. package/src/forge/delta/schema.ts +240 -0
  213. package/src/forge/delta/session.ts +142 -0
  214. package/src/forge/delta/status.ts +489 -0
  215. package/src/forge/delta/store.ts +2975 -0
  216. package/src/forge/delta/timeline.ts +104 -0
  217. package/src/forge/dev/server.ts +768 -15
  218. package/src/forge/dev/types.ts +15 -1
  219. package/src/forge/dev/watch.ts +17 -7
  220. package/src/forge/dev-console/cycle.ts +233 -21
  221. package/src/forge/dev-console/types.ts +46 -1
  222. package/src/forge/impact/index.ts +46 -8
  223. package/src/forge/impact/types.ts +6 -0
  224. package/src/forge/intent/index.ts +35 -16
  225. package/src/forge/make/index.ts +149 -6
  226. package/src/forge/make/templates.ts +343 -2
  227. package/src/forge/make/types.ts +3 -1
  228. package/src/forge/refactor/index.ts +1 -0
  229. package/src/forge/repair/rules/index.ts +2 -2
  230. package/src/forge/review/index.ts +158 -12
  231. package/src/forge/review/types.ts +15 -0
  232. package/src/forge/runtime/ai/context.ts +210 -5
  233. package/src/forge/runtime/ai/types.ts +70 -0
  234. package/src/forge/runtime/auth/claims.ts +32 -0
  235. package/src/forge/runtime/auth/errors.ts +2 -0
  236. package/src/forge/runtime/context/create-context.ts +30 -6
  237. package/src/forge/runtime/db/generated-client.ts +13 -2
  238. package/src/forge/runtime/db/memory-adapter.ts +2 -2
  239. package/src/forge/runtime/db/pglite-adapter.ts +77 -2
  240. package/src/forge/runtime/db/postgres-adapter.ts +6 -3
  241. package/src/forge/runtime/executor.ts +112 -2
  242. package/src/forge/runtime/external/bridge.ts +649 -0
  243. package/src/forge/runtime/runner/run-entry.ts +16 -7
  244. package/src/forge/runtime/telemetry/scrubber.ts +91 -10
  245. package/src/forge/runtime/webhooks/security.ts +184 -0
  246. package/src/forge/server.ts +100 -2
  247. package/src/forge/version.ts +1 -1
  248. package/src/forge/vue/index.ts +407 -0
  249. package/src/forge/workspace/change-summary.ts +209 -0
  250. package/src/forge/workspace/forge-cli.ts +14 -0
  251. package/src/forge/workspace/git-summary.ts +279 -0
  252. package/templates/agent-workroom/AGENTS.md +29 -0
  253. package/templates/agent-workroom/README.md +34 -0
  254. package/templates/agent-workroom/forge.config.ts +3 -0
  255. package/templates/agent-workroom/package.json +33 -0
  256. package/templates/agent-workroom/src/actions/indexAgentSignal.ts +10 -0
  257. package/templates/agent-workroom/src/commands/openWorkroom.ts +61 -0
  258. package/templates/agent-workroom/src/commands/recordAgentSignal.ts +119 -0
  259. package/templates/agent-workroom/src/commands/recordCheckRun.ts +52 -0
  260. package/templates/agent-workroom/src/forge/schema.ts +54 -0
  261. package/templates/agent-workroom/src/policies.ts +6 -0
  262. package/templates/agent-workroom/src/queries/listWorkrooms.ts +11 -0
  263. package/templates/agent-workroom/src/queries/liveWorkroom.ts +63 -0
  264. package/templates/agent-workroom/tsconfig.json +16 -0
  265. package/templates/agent-workroom/web/index.html +12 -0
  266. package/templates/agent-workroom/web/package.json +21 -0
  267. package/templates/agent-workroom/web/src/App.tsx +345 -0
  268. package/templates/agent-workroom/web/src/lib/forge.ts +13 -0
  269. package/templates/agent-workroom/web/src/main.tsx +13 -0
  270. package/templates/agent-workroom/web/src/styles.css +545 -0
  271. package/templates/agent-workroom/web/tsconfig.json +27 -0
  272. package/templates/b2b-support-web/package.json +2 -0
  273. package/templates/b2b-support-web/tsconfig.json +4 -1
  274. package/templates/b2b-support-web/web/package.json +1 -1
  275. package/templates/minimal-web/package.json +2 -1
  276. package/templates/minimal-web/tsconfig.json +3 -1
  277. package/templates/minimal-web/web/package.json +2 -2
  278. package/src/forge/_generated/actionSubscriptions.json +0 -2
  279. package/src/forge/_generated/actionSubscriptions.ts +0 -10
  280. package/src/forge/_generated/agentAdapterManifest.json +0 -2
  281. package/src/forge/_generated/agentAdapterManifest.ts +0 -73
  282. package/src/forge/_generated/agentContract.json +0 -2
  283. package/src/forge/_generated/agentContract.ts +0 -7696
  284. package/src/forge/_generated/agentQuickstart.md +0 -32
  285. package/src/forge/_generated/aiContext.ts +0 -59
  286. package/src/forge/_generated/aiModels.json +0 -2
  287. package/src/forge/_generated/aiModels.ts +0 -35
  288. package/src/forge/_generated/aiProviders.json +0 -2
  289. package/src/forge/_generated/aiProviders.ts +0 -23
  290. package/src/forge/_generated/aiRegistry.json +0 -2
  291. package/src/forge/_generated/aiRegistry.ts +0 -29
  292. package/src/forge/_generated/api.json +0 -2
  293. package/src/forge/_generated/api.ts +0 -8
  294. package/src/forge/_generated/appGraph.json +0 -2
  295. package/src/forge/_generated/appGraph.ts +0 -14667
  296. package/src/forge/_generated/appMap.md +0 -35
  297. package/src/forge/_generated/artifactManifest.json +0 -2
  298. package/src/forge/_generated/artifactManifest.ts +0 -7
  299. package/src/forge/_generated/authClaims.json +0 -2
  300. package/src/forge/_generated/authClaims.ts +0 -13
  301. package/src/forge/_generated/authConfig.json +0 -2
  302. package/src/forge/_generated/authConfig.ts +0 -17
  303. package/src/forge/_generated/authContext.ts +0 -23
  304. package/src/forge/_generated/authRegistry.json +0 -2
  305. package/src/forge/_generated/authRegistry.ts +0 -25
  306. package/src/forge/_generated/buildInfo.json +0 -2
  307. package/src/forge/_generated/buildInfo.ts +0 -9
  308. package/src/forge/_generated/capabilityMap.json +0 -2
  309. package/src/forge/_generated/capabilityMap.md +0 -15
  310. package/src/forge/_generated/capabilityMap.ts +0 -17
  311. package/src/forge/_generated/client.ts +0 -282
  312. package/src/forge/_generated/clientApi.ts +0 -9
  313. package/src/forge/_generated/clientManifest.json +0 -2
  314. package/src/forge/_generated/clientManifest.ts +0 -39
  315. package/src/forge/_generated/clientTypes.ts +0 -78
  316. package/src/forge/_generated/configRegistry.json +0 -2
  317. package/src/forge/_generated/configRegistry.ts +0 -4
  318. package/src/forge/_generated/dataGraph.json +0 -2
  319. package/src/forge/_generated/dataGraph.ts +0 -8
  320. package/src/forge/_generated/db.json +0 -2
  321. package/src/forge/_generated/db.ts +0 -2
  322. package/src/forge/_generated/dbSecurityManifest.json +0 -2
  323. package/src/forge/_generated/dbSecurityManifest.ts +0 -15
  324. package/src/forge/_generated/dbSessionContext.json +0 -2
  325. package/src/forge/_generated/dbSessionContext.ts +0 -39
  326. package/src/forge/_generated/deployManifest.json +0 -2
  327. package/src/forge/_generated/deployManifest.ts +0 -14
  328. package/src/forge/_generated/devManifest.json +0 -2
  329. package/src/forge/_generated/devManifest.ts +0 -47
  330. package/src/forge/_generated/envSchema.json +0 -2
  331. package/src/forge/_generated/envSchema.ts +0 -59
  332. package/src/forge/_generated/frontendGraph.json +0 -2
  333. package/src/forge/_generated/frontendGraph.ts +0 -27
  334. package/src/forge/_generated/importGuards.json +0 -2
  335. package/src/forge/_generated/importGuards.ts +0 -686
  336. package/src/forge/_generated/index.ts +0 -67
  337. package/src/forge/_generated/liveProductionManifest.json +0 -2
  338. package/src/forge/_generated/liveProductionManifest.ts +0 -23
  339. package/src/forge/_generated/liveProtocol.json +0 -2
  340. package/src/forge/_generated/liveProtocol.ts +0 -21
  341. package/src/forge/_generated/liveQueryRegistry.json +0 -2
  342. package/src/forge/_generated/liveQueryRegistry.ts +0 -9
  343. package/src/forge/_generated/liveTransportConfig.json +0 -2
  344. package/src/forge/_generated/liveTransportConfig.ts +0 -19
  345. package/src/forge/_generated/makeRegistry.json +0 -2
  346. package/src/forge/_generated/makeRegistry.ts +0 -163
  347. package/src/forge/_generated/makeTemplates.json +0 -2
  348. package/src/forge/_generated/makeTemplates.ts +0 -61
  349. package/src/forge/_generated/mockMap.json +0 -2
  350. package/src/forge/_generated/mockMap.ts +0 -7
  351. package/src/forge/_generated/operationPlaybooks.md +0 -147
  352. package/src/forge/_generated/packageGraph.json +0 -2
  353. package/src/forge/_generated/packageGraph.ts +0 -245249
  354. package/src/forge/_generated/packageUpgradeRegistry.json +0 -2
  355. package/src/forge/_generated/packageUpgradeRegistry.ts +0 -15
  356. package/src/forge/_generated/permissionMatrix.json +0 -2
  357. package/src/forge/_generated/permissionMatrix.ts +0 -7
  358. package/src/forge/_generated/policyRegistry.json +0 -2
  359. package/src/forge/_generated/policyRegistry.ts +0 -11
  360. package/src/forge/_generated/queryRegistry.json +0 -2
  361. package/src/forge/_generated/queryRegistry.ts +0 -9
  362. package/src/forge/_generated/react.d.ts +0 -22
  363. package/src/forge/_generated/react.ts +0 -29
  364. package/src/forge/_generated/reactManifest.json +0 -2
  365. package/src/forge/_generated/reactManifest.ts +0 -19
  366. package/src/forge/_generated/rlsPolicies.json +0 -2
  367. package/src/forge/_generated/rlsPolicies.sql +0 -34
  368. package/src/forge/_generated/rlsPolicies.ts +0 -6
  369. package/src/forge/_generated/runtimeGraph.json +0 -2
  370. package/src/forge/_generated/runtimeGraph.ts +0 -8
  371. package/src/forge/_generated/runtimeMatrix.json +0 -2
  372. package/src/forge/_generated/runtimeMatrix.ts +0 -327385
  373. package/src/forge/_generated/runtimeRegistry.ts +0 -2
  374. package/src/forge/_generated/runtimeRules.md +0 -79
  375. package/src/forge/_generated/secretRegistry.json +0 -2
  376. package/src/forge/_generated/secretRegistry.ts +0 -50
  377. package/src/forge/_generated/secretsContext.ts +0 -11
  378. package/src/forge/_generated/serverApi.ts +0 -10
  379. package/src/forge/_generated/sourceMapManifest.json +0 -2
  380. package/src/forge/_generated/sourceMapManifest.ts +0 -7
  381. package/src/forge/_generated/sqlPlan.json +0 -2
  382. package/src/forge/_generated/sqlPlan.ts +0 -88
  383. package/src/forge/_generated/subscriptionManifest.json +0 -2
  384. package/src/forge/_generated/subscriptionManifest.ts +0 -7
  385. package/src/forge/_generated/symbolicationManifest.json +0 -2
  386. package/src/forge/_generated/symbolicationManifest.ts +0 -17
  387. package/src/forge/_generated/telemetryRegistry.json +0 -2
  388. package/src/forge/_generated/telemetryRegistry.ts +0 -9
  389. package/src/forge/_generated/telemetrySinks.json +0 -2
  390. package/src/forge/_generated/telemetrySinks.ts +0 -11
  391. package/src/forge/_generated/tenantScope.json +0 -2
  392. package/src/forge/_generated/tenantScope.ts +0 -8
  393. package/src/forge/_generated/testGraph.json +0 -2
  394. package/src/forge/_generated/testGraph.ts +0 -3108
  395. package/src/forge/_generated/testPlanRegistry.json +0 -2
  396. package/src/forge/_generated/testPlanRegistry.ts +0 -33
  397. package/src/forge/_generated/uiRoutes.json +0 -2
  398. package/src/forge/_generated/uiRoutes.ts +0 -16
  399. package/src/forge/_generated/uiScenarios.json +0 -2
  400. package/src/forge/_generated/uiScenarios.ts +0 -30
  401. package/src/forge/_generated/uiTestManifest.json +0 -2
  402. package/src/forge/_generated/uiTestManifest.ts +0 -27
  403. package/src/forge/_generated/workflowRegistry.json +0 -2
  404. package/src/forge/_generated/workflowRegistry.ts +0 -9
  405. package/src/forge/_generated/workflowSubscriptions.json +0 -2
  406. package/src/forge/_generated/workflowSubscriptions.ts +0 -10
@@ -0,0 +1,877 @@
1
+ import { spawn, spawnSync } from "node:child_process";
2
+ import { existsSync, readdirSync, statSync } from "node:fs";
3
+ import { delimiter, extname, isAbsolute, join, relative } from "node:path";
4
+
5
+ export type CodexAppServerState = "ready" | "missing" | "disabled" | "unsupported";
6
+
7
+ export interface CodexAppServerProof {
8
+ schemaVersion: "0.1.0";
9
+ checked: boolean;
10
+ relevant: boolean;
11
+ state: CodexAppServerState;
12
+ available: boolean;
13
+ command: string;
14
+ resolution: {
15
+ requested: string;
16
+ executable: string;
17
+ strategy: "direct" | "path" | "cmd-shim" | "powershell-shim";
18
+ warning?: string;
19
+ };
20
+ versionCommand: string;
21
+ helpCommand: string;
22
+ schemaCommands: {
23
+ typescript: string;
24
+ jsonSchema: string;
25
+ };
26
+ connect: {
27
+ transport: "stdio";
28
+ command: string;
29
+ note: string;
30
+ };
31
+ security: {
32
+ websocket: {
33
+ defaultPosture: string;
34
+ recommendation: string;
35
+ };
36
+ shellCommandRisk: string;
37
+ authoritativeEvents: string;
38
+ };
39
+ checks: Array<{
40
+ name: string;
41
+ ok: boolean;
42
+ status: "ok" | "warning" | "failed" | "skipped";
43
+ message: string;
44
+ suggestedCommands: string[];
45
+ }>;
46
+ version?: string;
47
+ helpSample?: string;
48
+ error?: string;
49
+ handshake?: CodexAppServerHandshakeResult;
50
+ nextActions: string[];
51
+ }
52
+
53
+ export interface CodexAppServerCommands {
54
+ inspect: string;
55
+ generateTypes: string;
56
+ generateJsonSchema: string;
57
+ connectStdio: string;
58
+ probeHandshake: string;
59
+ }
60
+
61
+ export interface CodexAppServerSchemaGenerationResult {
62
+ attempted: boolean;
63
+ dryRun: boolean;
64
+ ok: boolean;
65
+ outDir: string;
66
+ commands: {
67
+ typescript: string;
68
+ jsonSchema: string;
69
+ };
70
+ results: Array<{
71
+ name: "typescript" | "jsonSchema";
72
+ ok: boolean;
73
+ exitCode: number | null;
74
+ command: string;
75
+ stdout?: string;
76
+ stderr?: string;
77
+ error?: string;
78
+ }>;
79
+ files: string[];
80
+ nextActions: string[];
81
+ }
82
+
83
+ export interface CodexAppServerHandshakeResult {
84
+ attempted: boolean;
85
+ dryRun: boolean;
86
+ ok: boolean;
87
+ transport: "stdio";
88
+ command: string;
89
+ initialized: boolean;
90
+ durationMs: number;
91
+ skippedReason?: "not-requested" | "dry-run" | "disabled" | "unavailable";
92
+ clientInfo: {
93
+ name: string;
94
+ title: string;
95
+ version: string;
96
+ };
97
+ messages: {
98
+ responses: number;
99
+ notifications: number;
100
+ firstNotification?: string;
101
+ };
102
+ initializeResult?: {
103
+ keys: string[];
104
+ userAgent?: string;
105
+ platformFamily?: string;
106
+ platformOs?: string;
107
+ };
108
+ readiness?: {
109
+ modelList: {
110
+ attempted: boolean;
111
+ responded: boolean;
112
+ ok: boolean;
113
+ method: "model/list";
114
+ count?: number;
115
+ sampleModels?: string[];
116
+ error?: string;
117
+ };
118
+ accountRead: {
119
+ attempted: boolean;
120
+ responded: boolean;
121
+ ok: boolean;
122
+ method: "account/read";
123
+ accountType?: string;
124
+ requiresOpenaiAuth?: boolean;
125
+ planType?: string;
126
+ error?: string;
127
+ };
128
+ };
129
+ stderrSample?: string[];
130
+ error?: string;
131
+ exitCode?: number | null;
132
+ signal?: NodeJS.Signals | null;
133
+ nextActions: string[];
134
+ }
135
+
136
+ interface ProbeResult {
137
+ ok: boolean;
138
+ exitCode: number | null;
139
+ stdout: string;
140
+ stderr: string;
141
+ error?: string;
142
+ timedOut: boolean;
143
+ }
144
+
145
+ interface ResolvedCodexExecutable {
146
+ requested: string;
147
+ executable: string;
148
+ strategy: CodexAppServerProof["resolution"]["strategy"];
149
+ warning?: string;
150
+ }
151
+
152
+ const DEFAULT_CODEX_BIN = "codex";
153
+ const SCHEMA_DIR = ".forge/codex-app-server-schemas";
154
+ const cache = new Map<string, CodexAppServerProof>();
155
+
156
+ export function codexAppServerCommands(bin = process.env.FORGE_CODEX_BIN || DEFAULT_CODEX_BIN): CodexAppServerCommands {
157
+ return {
158
+ inspect: `${bin} app-server --help`,
159
+ generateTypes: `${bin} app-server generate-ts --out ${SCHEMA_DIR}`,
160
+ generateJsonSchema: `${bin} app-server generate-json-schema --out ${SCHEMA_DIR}`,
161
+ connectStdio: `${bin} app-server`,
162
+ probeHandshake: "forge studio codex-server . --probe --json",
163
+ };
164
+ }
165
+
166
+ function runProbe(command: string, args: string[], cwd: string, timeoutMs: number): ProbeResult {
167
+ const resolved = resolveCodexExecutable(command);
168
+ const invocation = buildProbeInvocation(resolved, args);
169
+ const result = spawnSync(invocation.command, invocation.args, {
170
+ cwd,
171
+ encoding: "utf8",
172
+ stdio: "pipe",
173
+ timeout: timeoutMs,
174
+ windowsHide: true,
175
+ });
176
+ const error = result.error as NodeJS.ErrnoException | undefined;
177
+ return {
178
+ ok: result.status === 0 && !error,
179
+ exitCode: result.status,
180
+ stdout: typeof result.stdout === "string" ? result.stdout : "",
181
+ stderr: typeof result.stderr === "string" ? result.stderr : "",
182
+ error: error?.code === "ETIMEDOUT"
183
+ ? `timed out after ${timeoutMs}ms`
184
+ : error?.message,
185
+ timedOut: error?.code === "ETIMEDOUT",
186
+ };
187
+ }
188
+
189
+ function safeStatFile(path: string): boolean {
190
+ try {
191
+ return statSync(path).isFile();
192
+ } catch {
193
+ return false;
194
+ }
195
+ }
196
+
197
+ function hasPathSeparator(value: string): boolean {
198
+ return value.includes("/") || value.includes("\\");
199
+ }
200
+
201
+ function resolveCodexExecutable(requested: string): ResolvedCodexExecutable {
202
+ if (process.platform !== "win32") {
203
+ return { requested, executable: requested, strategy: "direct" };
204
+ }
205
+
206
+ if (hasPathSeparator(requested) || isAbsolute(requested)) {
207
+ const extension = extname(requested).toLowerCase();
208
+ return {
209
+ requested,
210
+ executable: requested,
211
+ strategy: extension === ".cmd" || extension === ".bat"
212
+ ? "cmd-shim"
213
+ : extension === ".ps1"
214
+ ? "powershell-shim"
215
+ : "direct",
216
+ };
217
+ }
218
+
219
+ const pathEntries = (process.env.PATH ?? "")
220
+ .split(delimiter)
221
+ .map((entry) => entry.trim())
222
+ .filter(Boolean);
223
+ const candidates = [
224
+ `${requested}.cmd`,
225
+ `${requested}.exe`,
226
+ `${requested}.bat`,
227
+ `${requested}.ps1`,
228
+ requested,
229
+ ];
230
+ for (const entry of pathEntries) {
231
+ for (const candidate of candidates) {
232
+ const absolute = join(entry, candidate);
233
+ if (!existsSync(absolute) || !safeStatFile(absolute)) {
234
+ continue;
235
+ }
236
+ const extension = extname(absolute).toLowerCase();
237
+ return {
238
+ requested,
239
+ executable: absolute,
240
+ strategy: extension === ".cmd" || extension === ".bat"
241
+ ? "cmd-shim"
242
+ : extension === ".ps1"
243
+ ? "powershell-shim"
244
+ : "path",
245
+ ...(extension === "" ? { warning: "resolved to an extensionless Windows shim; prefer a .cmd or .exe path with FORGE_CODEX_BIN" } : {}),
246
+ };
247
+ }
248
+ }
249
+ return { requested, executable: requested, strategy: "direct" };
250
+ }
251
+
252
+ function quoteCmdArg(value: string): string {
253
+ if (/^[a-zA-Z0-9_:=\-./\\]+$/.test(value)) {
254
+ return value;
255
+ }
256
+ return `"${value.replace(/"/g, '\\"')}"`;
257
+ }
258
+
259
+ function buildProbeInvocation(resolved: ResolvedCodexExecutable, args: string[]): { command: string; args: string[] } {
260
+ if (process.platform !== "win32") {
261
+ return { command: resolved.executable, args };
262
+ }
263
+ if (resolved.strategy === "cmd-shim") {
264
+ const commandLine = [quoteCmdArg(resolved.executable), ...args.map(quoteCmdArg)].join(" ");
265
+ return {
266
+ command: process.env.ComSpec || "cmd.exe",
267
+ args: ["/d", "/s", "/c", commandLine],
268
+ };
269
+ }
270
+ if (resolved.strategy === "powershell-shim") {
271
+ return {
272
+ command: "powershell.exe",
273
+ args: ["-NoProfile", "-ExecutionPolicy", "Bypass", "-File", resolved.executable, ...args],
274
+ };
275
+ }
276
+ return { command: resolved.executable, args };
277
+ }
278
+
279
+ function sampleText(value: string): string | undefined {
280
+ const normalized = value
281
+ .split(/\r?\n/)
282
+ .map((line) => line.trim())
283
+ .filter(Boolean)
284
+ .slice(0, 4)
285
+ .join("\n");
286
+ return normalized || undefined;
287
+ }
288
+
289
+ function sampleLines(value: string): string[] {
290
+ return value
291
+ .split(/\r?\n/)
292
+ .map((line) => line.trim())
293
+ .filter(Boolean)
294
+ .slice(0, 6)
295
+ .map((line) => line.length > 240 ? `${line.slice(0, 237)}...` : line);
296
+ }
297
+
298
+ function summarizeInitializeResult(value: unknown): CodexAppServerHandshakeResult["initializeResult"] {
299
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
300
+ return undefined;
301
+ }
302
+ const record = value as Record<string, unknown>;
303
+ return {
304
+ keys: Object.keys(record).sort(),
305
+ ...(typeof record.userAgent === "string" ? { userAgent: record.userAgent } : {}),
306
+ ...(typeof record.platformFamily === "string" ? { platformFamily: record.platformFamily } : {}),
307
+ ...(typeof record.platformOs === "string" ? { platformOs: record.platformOs } : {}),
308
+ };
309
+ }
310
+
311
+ function rpcErrorMessage(value: unknown): string | undefined {
312
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
313
+ return undefined;
314
+ }
315
+ const record = value as Record<string, unknown>;
316
+ return typeof record.message === "string" ? record.message : "RPC request failed";
317
+ }
318
+
319
+ function summarizeModelListReadiness(message: {
320
+ result?: unknown;
321
+ error?: unknown;
322
+ }): NonNullable<CodexAppServerHandshakeResult["readiness"]>["modelList"] {
323
+ const error = rpcErrorMessage(message.error);
324
+ if (error) {
325
+ return {
326
+ attempted: true,
327
+ responded: true,
328
+ ok: false,
329
+ method: "model/list",
330
+ error,
331
+ };
332
+ }
333
+ const result = message.result && typeof message.result === "object" && !Array.isArray(message.result)
334
+ ? message.result as Record<string, unknown>
335
+ : {};
336
+ const data = Array.isArray(result.data) ? result.data : [];
337
+ const sampleModels = data
338
+ .map((entry) => {
339
+ if (!entry || typeof entry !== "object" || Array.isArray(entry)) return "";
340
+ const record = entry as Record<string, unknown>;
341
+ return String(record.id || record.model || record.displayName || "").trim();
342
+ })
343
+ .filter(Boolean)
344
+ .slice(0, 5);
345
+ return {
346
+ attempted: true,
347
+ responded: true,
348
+ ok: true,
349
+ method: "model/list",
350
+ count: data.length,
351
+ ...(sampleModels.length > 0 ? { sampleModels } : {}),
352
+ };
353
+ }
354
+
355
+ function summarizeAccountReadReadiness(message: {
356
+ result?: unknown;
357
+ error?: unknown;
358
+ }): NonNullable<CodexAppServerHandshakeResult["readiness"]>["accountRead"] {
359
+ const error = rpcErrorMessage(message.error);
360
+ if (error) {
361
+ return {
362
+ attempted: true,
363
+ responded: true,
364
+ ok: false,
365
+ method: "account/read",
366
+ error,
367
+ };
368
+ }
369
+ const result = message.result && typeof message.result === "object" && !Array.isArray(message.result)
370
+ ? message.result as Record<string, unknown>
371
+ : {};
372
+ const account = result.account && typeof result.account === "object" && !Array.isArray(result.account)
373
+ ? result.account as Record<string, unknown>
374
+ : undefined;
375
+ return {
376
+ attempted: true,
377
+ responded: true,
378
+ ok: true,
379
+ method: "account/read",
380
+ ...(typeof account?.type === "string" ? { accountType: account.type } : {}),
381
+ ...(typeof result.requiresOpenaiAuth === "boolean" ? { requiresOpenaiAuth: result.requiresOpenaiAuth } : {}),
382
+ ...(typeof account?.planType === "string" ? { planType: account.planType } : {}),
383
+ };
384
+ }
385
+
386
+ function initialReadiness(): NonNullable<CodexAppServerHandshakeResult["readiness"]> {
387
+ return {
388
+ modelList: {
389
+ attempted: true,
390
+ responded: false,
391
+ ok: false,
392
+ method: "model/list",
393
+ },
394
+ accountRead: {
395
+ attempted: true,
396
+ responded: false,
397
+ ok: false,
398
+ method: "account/read",
399
+ },
400
+ };
401
+ }
402
+
403
+ function timedOutReadiness(
404
+ readiness: NonNullable<CodexAppServerHandshakeResult["readiness"]>,
405
+ timeoutMs: number,
406
+ ): NonNullable<CodexAppServerHandshakeResult["readiness"]> {
407
+ return {
408
+ modelList: readiness.modelList.responded
409
+ ? readiness.modelList
410
+ : {
411
+ ...readiness.modelList,
412
+ error: `timed out after ${timeoutMs}ms`,
413
+ },
414
+ accountRead: readiness.accountRead.responded
415
+ ? readiness.accountRead
416
+ : {
417
+ ...readiness.accountRead,
418
+ error: `timed out after ${timeoutMs}ms`,
419
+ },
420
+ };
421
+ }
422
+
423
+ function listSchemaFiles(workspaceRoot: string): string[] {
424
+ const absolute = join(workspaceRoot, SCHEMA_DIR);
425
+ if (!existsSync(absolute)) {
426
+ return [];
427
+ }
428
+ const files: string[] = [];
429
+ const visit = (directory: string) => {
430
+ for (const entry of readdirSync(directory, { withFileTypes: true })) {
431
+ const absoluteEntry = join(directory, entry.name);
432
+ if (entry.isDirectory()) {
433
+ visit(absoluteEntry);
434
+ } else if (entry.isFile()) {
435
+ files.push(join(SCHEMA_DIR, relative(absolute, absoluteEntry)).replace(/\\/g, "/"));
436
+ }
437
+ }
438
+ };
439
+ try {
440
+ visit(absolute);
441
+ return files.sort();
442
+ } catch {
443
+ return [];
444
+ }
445
+ }
446
+
447
+ function baseProof(input: { relevant: boolean; bin: string }): Omit<CodexAppServerProof, "state" | "available" | "checks" | "nextActions"> {
448
+ const commands = codexAppServerCommands(input.bin);
449
+ const resolution = resolveCodexExecutable(input.bin);
450
+ return {
451
+ schemaVersion: "0.1.0",
452
+ checked: true,
453
+ relevant: input.relevant,
454
+ command: input.bin,
455
+ resolution,
456
+ versionCommand: `${input.bin} --version`,
457
+ helpCommand: commands.inspect,
458
+ schemaCommands: {
459
+ typescript: commands.generateTypes,
460
+ jsonSchema: commands.generateJsonSchema,
461
+ },
462
+ connect: {
463
+ transport: "stdio",
464
+ command: commands.connectStdio,
465
+ note: "Forge Studio should prefer stdio when it owns the Codex app-server child process; hooks remain the fallback observer path.",
466
+ },
467
+ security: {
468
+ websocket: {
469
+ defaultPosture: "Do not expose a Codex app-server WebSocket listener beyond loopback.",
470
+ recommendation: "Use a token file or signed bearer token before enabling remote WebSocket access.",
471
+ },
472
+ shellCommandRisk: "Methods that execute shell commands outside the normal sandbox must stay tied to explicit user intent.",
473
+ authoritativeEvents: "Treat item/completed events as authoritative; deltas and started events are progress signals.",
474
+ },
475
+ };
476
+ }
477
+
478
+ export function inspectCodexAppServer(options: {
479
+ workspaceRoot: string;
480
+ relevant: boolean;
481
+ bin?: string;
482
+ forceRefresh?: boolean;
483
+ }): CodexAppServerProof {
484
+ const bin = options.bin || process.env.FORGE_CODEX_BIN || DEFAULT_CODEX_BIN;
485
+ const cacheKey = `${bin}:${options.relevant}:${process.env.FORGE_CODEX_APP_SERVER ?? "auto"}`;
486
+ if (!options.forceRefresh) {
487
+ const cached = cache.get(cacheKey);
488
+ if (cached) return cached;
489
+ }
490
+
491
+ const base = baseProof({ relevant: options.relevant, bin });
492
+ if (!options.relevant) {
493
+ const proof: CodexAppServerProof = {
494
+ ...base,
495
+ state: "disabled",
496
+ available: false,
497
+ checks: [{
498
+ name: "codex-target",
499
+ ok: true,
500
+ status: "skipped",
501
+ message: "Codex app-server was not checked because Codex is not one of the selected Studio targets.",
502
+ suggestedCommands: [],
503
+ }],
504
+ nextActions: [],
505
+ };
506
+ cache.set(cacheKey, proof);
507
+ return proof;
508
+ }
509
+
510
+ if (process.env.FORGE_CODEX_APP_SERVER === "off" || process.env.FORGE_CODEX_APP_SERVER === "0") {
511
+ const proof: CodexAppServerProof = {
512
+ ...base,
513
+ state: "disabled",
514
+ available: false,
515
+ checks: [{
516
+ name: "codex-app-server",
517
+ ok: true,
518
+ status: "skipped",
519
+ message: "Codex app-server probing is disabled by FORGE_CODEX_APP_SERVER.",
520
+ suggestedCommands: [base.helpCommand],
521
+ }],
522
+ nextActions: [base.helpCommand],
523
+ };
524
+ cache.set(cacheKey, proof);
525
+ return proof;
526
+ }
527
+
528
+ const version = runProbe(bin, ["--version"], options.workspaceRoot, 900);
529
+ const help = runProbe(bin, ["app-server", "--help"], options.workspaceRoot, 1500);
530
+ const combinedHelp = `${help.stdout}\n${help.stderr}`;
531
+ const supportsAppServer = help.ok || /app-server/i.test(combinedHelp);
532
+ const available = help.ok && supportsAppServer;
533
+ const state: CodexAppServerState = available
534
+ ? "ready"
535
+ : version.error || help.error
536
+ ? "missing"
537
+ : "unsupported";
538
+ const versionText = sampleText(version.stdout || version.stderr);
539
+ const helpSample = sampleText(combinedHelp);
540
+ const error = help.error ?? version.error;
541
+ const checks: CodexAppServerProof["checks"] = [
542
+ {
543
+ name: "codex-cli",
544
+ ok: version.ok || help.ok,
545
+ status: version.ok || help.ok ? "ok" : "failed",
546
+ message: version.ok
547
+ ? `Codex CLI responded: ${versionText ?? "version available"}`
548
+ : `Codex CLI did not respond${version.error ? `: ${version.error}` : ""}`,
549
+ suggestedCommands: [`${bin} --version`],
550
+ },
551
+ {
552
+ name: "codex-app-server",
553
+ ok: available,
554
+ status: available ? "ok" : "warning",
555
+ message: available
556
+ ? "Codex app-server help is available for deep Studio integration."
557
+ : supportsAppServer
558
+ ? "Codex mentions app-server, but the help probe did not exit cleanly."
559
+ : "Codex app-server was not detected; Studio can still use hooks and MCP as the observer path.",
560
+ suggestedCommands: [base.helpCommand],
561
+ },
562
+ {
563
+ name: "codex-app-server-schemas",
564
+ ok: available,
565
+ status: available ? "ok" : "warning",
566
+ message: available
567
+ ? `Generate version-matched schemas into ${SCHEMA_DIR} before implementing a streaming client.`
568
+ : "Schema generation is unavailable until Codex app-server is detected.",
569
+ suggestedCommands: [base.schemaCommands.typescript, base.schemaCommands.jsonSchema],
570
+ },
571
+ ];
572
+ const nextActions = available
573
+ ? [base.schemaCommands.typescript, base.schemaCommands.jsonSchema, base.connect.command]
574
+ : [base.helpCommand, "forge agent hooks status --target codex --json"];
575
+ const proof: CodexAppServerProof = {
576
+ ...base,
577
+ state,
578
+ available,
579
+ checks,
580
+ ...(versionText ? { version: versionText } : {}),
581
+ ...(helpSample ? { helpSample } : {}),
582
+ ...(error ? { error } : {}),
583
+ nextActions,
584
+ };
585
+ cache.set(cacheKey, proof);
586
+ return proof;
587
+ }
588
+
589
+ export function generateCodexAppServerSchemas(options: {
590
+ workspaceRoot: string;
591
+ bin?: string;
592
+ dryRun: boolean;
593
+ }): CodexAppServerSchemaGenerationResult {
594
+ const bin = options.bin || process.env.FORGE_CODEX_BIN || DEFAULT_CODEX_BIN;
595
+ const commands = codexAppServerCommands(bin);
596
+ if (options.dryRun) {
597
+ return {
598
+ attempted: false,
599
+ dryRun: true,
600
+ ok: true,
601
+ outDir: SCHEMA_DIR,
602
+ commands: {
603
+ typescript: commands.generateTypes,
604
+ jsonSchema: commands.generateJsonSchema,
605
+ },
606
+ results: [],
607
+ files: listSchemaFiles(options.workspaceRoot),
608
+ nextActions: [commands.generateTypes, commands.generateJsonSchema],
609
+ };
610
+ }
611
+
612
+ const specs = [
613
+ {
614
+ name: "typescript" as const,
615
+ args: ["app-server", "generate-ts", "--out", SCHEMA_DIR],
616
+ command: commands.generateTypes,
617
+ },
618
+ {
619
+ name: "jsonSchema" as const,
620
+ args: ["app-server", "generate-json-schema", "--out", SCHEMA_DIR],
621
+ command: commands.generateJsonSchema,
622
+ },
623
+ ];
624
+ const results = specs.map((spec) => {
625
+ const run = runProbe(bin, spec.args, options.workspaceRoot, 30_000);
626
+ return {
627
+ name: spec.name,
628
+ ok: run.ok,
629
+ exitCode: run.exitCode,
630
+ command: spec.command,
631
+ ...(sampleText(run.stdout) ? { stdout: sampleText(run.stdout) } : {}),
632
+ ...(sampleText(run.stderr) ? { stderr: sampleText(run.stderr) } : {}),
633
+ ...(run.error ? { error: run.error } : {}),
634
+ };
635
+ });
636
+ const ok = results.every((result) => result.ok);
637
+ return {
638
+ attempted: true,
639
+ dryRun: false,
640
+ ok,
641
+ outDir: SCHEMA_DIR,
642
+ commands: {
643
+ typescript: commands.generateTypes,
644
+ jsonSchema: commands.generateJsonSchema,
645
+ },
646
+ results,
647
+ files: listSchemaFiles(options.workspaceRoot),
648
+ nextActions: ok
649
+ ? [commands.connectStdio]
650
+ : [commands.generateTypes, commands.generateJsonSchema, commands.inspect],
651
+ };
652
+ }
653
+
654
+ export function skippedCodexAppServerHandshake(options: {
655
+ reason: CodexAppServerHandshakeResult["skippedReason"];
656
+ dryRun: boolean;
657
+ bin?: string;
658
+ }): CodexAppServerHandshakeResult {
659
+ const commands = codexAppServerCommands(options.bin);
660
+ return {
661
+ attempted: false,
662
+ dryRun: options.dryRun,
663
+ ok: options.reason !== "unavailable",
664
+ transport: "stdio",
665
+ command: commands.connectStdio,
666
+ initialized: false,
667
+ durationMs: 0,
668
+ skippedReason: options.reason,
669
+ clientInfo: {
670
+ name: "forge_studio",
671
+ title: "Forge Studio",
672
+ version: "0.1.0",
673
+ },
674
+ messages: {
675
+ responses: 0,
676
+ notifications: 0,
677
+ },
678
+ nextActions: options.reason === "not-requested"
679
+ ? [commands.probeHandshake]
680
+ : options.reason === "disabled"
681
+ ? [commands.inspect]
682
+ : [commands.connectStdio, commands.inspect],
683
+ };
684
+ }
685
+
686
+ export async function probeCodexAppServerHandshake(options: {
687
+ workspaceRoot: string;
688
+ bin?: string;
689
+ dryRun: boolean;
690
+ timeoutMs?: number;
691
+ available?: boolean;
692
+ disabled?: boolean;
693
+ }): Promise<CodexAppServerHandshakeResult> {
694
+ const bin = options.bin || process.env.FORGE_CODEX_BIN || DEFAULT_CODEX_BIN;
695
+ const commands = codexAppServerCommands(bin);
696
+ if (options.dryRun) {
697
+ return skippedCodexAppServerHandshake({ reason: "dry-run", dryRun: true, bin });
698
+ }
699
+ if (options.disabled || process.env.FORGE_CODEX_APP_SERVER === "off" || process.env.FORGE_CODEX_APP_SERVER === "0") {
700
+ return skippedCodexAppServerHandshake({ reason: "disabled", dryRun: false, bin });
701
+ }
702
+ if (options.available === false) {
703
+ return skippedCodexAppServerHandshake({ reason: "unavailable", dryRun: false, bin });
704
+ }
705
+
706
+ const clientInfo = {
707
+ name: "forge_studio",
708
+ title: "Forge Studio",
709
+ version: "0.1.0",
710
+ };
711
+ const resolved = resolveCodexExecutable(bin);
712
+ const invocation = buildProbeInvocation(resolved, ["app-server"]);
713
+ const startedAt = Date.now();
714
+
715
+ return new Promise<CodexAppServerHandshakeResult>((resolve) => {
716
+ let settled = false;
717
+ let stdoutBuffer = "";
718
+ let stderrBuffer = "";
719
+ let responses = 0;
720
+ let notifications = 0;
721
+ let firstNotification: string | undefined;
722
+ let initializeResult: CodexAppServerHandshakeResult["initializeResult"];
723
+ let readiness: CodexAppServerHandshakeResult["readiness"];
724
+ let exitCode: number | null | undefined;
725
+ let signal: NodeJS.Signals | null | undefined;
726
+ let child: ReturnType<typeof spawn> | undefined;
727
+ let timer: ReturnType<typeof setTimeout> | undefined;
728
+
729
+ const finish = (partial: Partial<CodexAppServerHandshakeResult>) => {
730
+ if (settled) return;
731
+ settled = true;
732
+ if (timer) clearTimeout(timer);
733
+ try {
734
+ child?.stdin?.end();
735
+ } catch {
736
+ // best effort only
737
+ }
738
+ if (child && !child.killed) {
739
+ child.kill();
740
+ }
741
+ resolve({
742
+ attempted: true,
743
+ dryRun: false,
744
+ ok: partial.ok === true,
745
+ transport: "stdio",
746
+ command: commands.connectStdio,
747
+ initialized: partial.initialized === true,
748
+ durationMs: Date.now() - startedAt,
749
+ clientInfo,
750
+ messages: {
751
+ responses,
752
+ notifications,
753
+ ...(firstNotification ? { firstNotification } : {}),
754
+ },
755
+ ...(initializeResult ? { initializeResult } : {}),
756
+ ...(partial.readiness ?? readiness ? { readiness: partial.readiness ?? readiness } : {}),
757
+ ...(sampleLines(stderrBuffer).length > 0 ? { stderrSample: sampleLines(stderrBuffer) } : {}),
758
+ ...(partial.error ? { error: partial.error } : {}),
759
+ exitCode: partial.exitCode ?? exitCode ?? null,
760
+ signal: partial.signal ?? signal ?? null,
761
+ nextActions: partial.ok === true
762
+ ? [commands.generateTypes, commands.generateJsonSchema]
763
+ : [commands.inspect, commands.connectStdio],
764
+ });
765
+ };
766
+
767
+ child = spawn(invocation.command, invocation.args, {
768
+ cwd: options.workspaceRoot,
769
+ stdio: ["pipe", "pipe", "pipe"],
770
+ windowsHide: true,
771
+ });
772
+
773
+ timer = setTimeout(() => {
774
+ const timeoutMs = options.timeoutMs ?? 5000;
775
+ if (initializeResult && readiness) {
776
+ finish({
777
+ ok: true,
778
+ initialized: true,
779
+ readiness: timedOutReadiness(readiness, timeoutMs),
780
+ });
781
+ return;
782
+ }
783
+ finish({ ok: false, initialized: false, error: `timed out after ${timeoutMs}ms` });
784
+ }, options.timeoutMs ?? 5000);
785
+
786
+ child.once("error", (error) => {
787
+ finish({ ok: false, initialized: false, error: error.message });
788
+ });
789
+ child.once("close", (code, exitSignal) => {
790
+ exitCode = code;
791
+ signal = exitSignal;
792
+ if (!settled) {
793
+ finish({
794
+ ok: false,
795
+ initialized: false,
796
+ exitCode: code,
797
+ signal: exitSignal,
798
+ error: "codex app-server exited before the initialize handshake completed",
799
+ });
800
+ }
801
+ });
802
+ child.stderr?.on("data", (chunk) => {
803
+ stderrBuffer += String(chunk);
804
+ });
805
+ child.stdout?.on("data", (chunk) => {
806
+ stdoutBuffer += String(chunk);
807
+ let newline = stdoutBuffer.indexOf("\n");
808
+ while (newline >= 0) {
809
+ const line = stdoutBuffer.slice(0, newline).trim();
810
+ stdoutBuffer = stdoutBuffer.slice(newline + 1);
811
+ if (line) {
812
+ try {
813
+ const message = JSON.parse(line) as {
814
+ id?: unknown;
815
+ method?: unknown;
816
+ result?: unknown;
817
+ error?: { message?: unknown };
818
+ };
819
+ if (message.id !== undefined) {
820
+ responses += 1;
821
+ } else if (typeof message.method === "string") {
822
+ notifications += 1;
823
+ firstNotification ??= message.method;
824
+ }
825
+ if (message.id === 1) {
826
+ if (message.error) {
827
+ finish({
828
+ ok: false,
829
+ initialized: false,
830
+ error: typeof message.error.message === "string"
831
+ ? message.error.message
832
+ : "initialize failed",
833
+ });
834
+ return;
835
+ }
836
+ initializeResult = summarizeInitializeResult(message.result);
837
+ readiness = initialReadiness();
838
+ child.stdin?.write(`${JSON.stringify({ method: "initialized", params: {} })}\n`);
839
+ child.stdin?.write(`${JSON.stringify({ method: "model/list", id: 2, params: { limit: 5, includeHidden: false } })}\n`);
840
+ child.stdin?.write(`${JSON.stringify({ method: "account/read", id: 3, params: { refreshToken: false } })}\n`);
841
+ return;
842
+ }
843
+ if (message.id === 2 && readiness) {
844
+ readiness = {
845
+ ...readiness,
846
+ modelList: summarizeModelListReadiness(message),
847
+ };
848
+ if (readiness.accountRead.responded) {
849
+ finish({ ok: true, initialized: true, readiness });
850
+ }
851
+ return;
852
+ }
853
+ if (message.id === 3 && readiness) {
854
+ readiness = {
855
+ ...readiness,
856
+ accountRead: summarizeAccountReadReadiness(message),
857
+ };
858
+ if (readiness.modelList.responded) {
859
+ finish({ ok: true, initialized: true, readiness });
860
+ }
861
+ return;
862
+ }
863
+ } catch {
864
+ stderrBuffer += `\nUnparseable app-server stdout line: ${line.slice(0, 200)}`;
865
+ }
866
+ }
867
+ newline = stdoutBuffer.indexOf("\n");
868
+ }
869
+ });
870
+
871
+ child.stdin?.write(`${JSON.stringify({
872
+ method: "initialize",
873
+ id: 1,
874
+ params: { clientInfo },
875
+ })}\n`);
876
+ });
877
+ }