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.
- package/.npmignore +4 -0
- package/AGENTS.md +168 -81
- package/CHANGELOG.md +211 -0
- package/README.md +88 -14
- package/adapters/go/README.md +23 -0
- package/adapters/go/go.mod +3 -0
- package/adapters/go/http.go +149 -0
- package/adapters/go/registry.go +234 -0
- package/adapters/go/types.go +136 -0
- package/adapters/java/README.md +68 -0
- package/adapters/java/pom.xml +34 -0
- package/adapters/java/src/main/java/dev/forgeos/adapter/Auth.java +20 -0
- package/adapters/java/src/main/java/dev/forgeos/adapter/Diagnostic.java +16 -0
- package/adapters/java/src/main/java/dev/forgeos/adapter/Entry.java +38 -0
- package/adapters/java/src/main/java/dev/forgeos/adapter/EntryKind.java +16 -0
- package/adapters/java/src/main/java/dev/forgeos/adapter/ErrorInfo.java +4 -0
- package/adapters/java/src/main/java/dev/forgeos/adapter/Forge.java +94 -0
- package/adapters/java/src/main/java/dev/forgeos/adapter/ForgeCall.java +12 -0
- package/adapters/java/src/main/java/dev/forgeos/adapter/ForgeContext.java +11 -0
- package/adapters/java/src/main/java/dev/forgeos/adapter/ForgeHandler.java +8 -0
- package/adapters/java/src/main/java/dev/forgeos/adapter/ForgeHttpHandler.java +179 -0
- package/adapters/java/src/main/java/dev/forgeos/adapter/ForgeRegistry.java +121 -0
- package/adapters/java/src/main/java/dev/forgeos/adapter/Json.java +14 -0
- package/adapters/java/src/main/java/dev/forgeos/adapter/Manifest.java +14 -0
- package/adapters/java/src/main/java/dev/forgeos/adapter/RequestEnvelope.java +6 -0
- package/adapters/java/src/main/java/dev/forgeos/adapter/ResponseEnvelope.java +25 -0
- package/adapters/java/src/main/java/dev/forgeos/adapter/Risk.java +18 -0
- package/adapters/java/src/main/java/dev/forgeos/adapter/Schemas.java +36 -0
- package/adapters/java/src/main/java/dev/forgeos/adapter/Service.java +65 -0
- package/adapters/java/src/main/java/dev/forgeos/adapter/TransactionMode.java +18 -0
- package/adapters/java/src/main/java/dev/forgeos/adapter/TypedForgeHandler.java +6 -0
- package/adapters/java/target/classes/dev/forgeos/adapter/Auth.class +0 -0
- package/adapters/java/target/classes/dev/forgeos/adapter/Diagnostic.class +0 -0
- package/adapters/java/target/classes/dev/forgeos/adapter/Entry.class +0 -0
- package/adapters/java/target/classes/dev/forgeos/adapter/EntryKind.class +0 -0
- package/adapters/java/target/classes/dev/forgeos/adapter/ErrorInfo.class +0 -0
- package/adapters/java/target/classes/dev/forgeos/adapter/Forge.class +0 -0
- package/adapters/java/target/classes/dev/forgeos/adapter/ForgeCall.class +0 -0
- package/adapters/java/target/classes/dev/forgeos/adapter/ForgeContext.class +0 -0
- package/adapters/java/target/classes/dev/forgeos/adapter/ForgeHandler.class +0 -0
- package/adapters/java/target/classes/dev/forgeos/adapter/ForgeHttpHandler.class +0 -0
- package/adapters/java/target/classes/dev/forgeos/adapter/ForgeRegistry$EntryOption.class +0 -0
- package/adapters/java/target/classes/dev/forgeos/adapter/ForgeRegistry$RegisteredEntry.class +0 -0
- package/adapters/java/target/classes/dev/forgeos/adapter/ForgeRegistry$RegistryOption.class +0 -0
- package/adapters/java/target/classes/dev/forgeos/adapter/ForgeRegistry.class +0 -0
- package/adapters/java/target/classes/dev/forgeos/adapter/Json.class +0 -0
- package/adapters/java/target/classes/dev/forgeos/adapter/Manifest.class +0 -0
- package/adapters/java/target/classes/dev/forgeos/adapter/RequestEnvelope.class +0 -0
- package/adapters/java/target/classes/dev/forgeos/adapter/ResponseEnvelope.class +0 -0
- package/adapters/java/target/classes/dev/forgeos/adapter/Risk.class +0 -0
- package/adapters/java/target/classes/dev/forgeos/adapter/Schemas.class +0 -0
- package/adapters/java/target/classes/dev/forgeos/adapter/Service.class +0 -0
- package/adapters/java/target/classes/dev/forgeos/adapter/TransactionMode.class +0 -0
- package/adapters/java/target/classes/dev/forgeos/adapter/TypedForgeHandler.class +0 -0
- package/adapters/java/target/forge-java-adapter-0.1.0-alpha.11.jar +0 -0
- package/adapters/java/target/maven-archiver/pom.properties +3 -0
- package/adapters/java/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst +23 -0
- package/adapters/java/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst +20 -0
- package/adapters/java-spring-boot-starter/README.md +32 -0
- package/adapters/java-spring-boot-starter/pom.xml +36 -0
- package/adapters/java-spring-boot-starter/src/main/java/dev/forgeos/adapter/spring/ForgeCommand.java +22 -0
- package/adapters/java-spring-boot-starter/src/main/java/dev/forgeos/adapter/spring/ForgeExternalService.java +15 -0
- package/adapters/java-spring-boot-starter/src/main/java/dev/forgeos/adapter/spring/ForgeQuery.java +16 -0
- package/adapters/java-spring-boot-starter/src/main/java/dev/forgeos/adapter/spring/ForgeServiceBeanCondition.java +18 -0
- package/adapters/java-spring-boot-starter/src/main/java/dev/forgeos/adapter/spring/ForgeSpringAutoConfiguration.java +16 -0
- package/adapters/java-spring-boot-starter/src/main/java/dev/forgeos/adapter/spring/ForgeSpringRuntime.java +104 -0
- package/adapters/java-spring-boot-starter/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports +1 -0
- package/adapters/java-spring-boot-starter/target/classes/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports +1 -0
- package/adapters/java-spring-boot-starter/target/classes/dev/forgeos/adapter/spring/ForgeCommand.class +0 -0
- package/adapters/java-spring-boot-starter/target/classes/dev/forgeos/adapter/spring/ForgeExternalService.class +0 -0
- package/adapters/java-spring-boot-starter/target/classes/dev/forgeos/adapter/spring/ForgeQuery.class +0 -0
- package/adapters/java-spring-boot-starter/target/classes/dev/forgeos/adapter/spring/ForgeServiceBeanCondition.class +0 -0
- package/adapters/java-spring-boot-starter/target/classes/dev/forgeos/adapter/spring/ForgeSpringAutoConfiguration.class +0 -0
- package/adapters/java-spring-boot-starter/target/classes/dev/forgeos/adapter/spring/ForgeSpringRuntime.class +0 -0
- package/adapters/java-spring-boot-starter/target/forge-java-spring-boot-starter-0.1.0-alpha.11.jar +0 -0
- package/adapters/java-spring-boot-starter/target/maven-archiver/pom.properties +3 -0
- package/adapters/java-spring-boot-starter/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst +6 -0
- package/adapters/java-spring-boot-starter/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst +6 -0
- package/bin/forge.mjs +18 -0
- package/docs/changelog.md +242 -0
- package/docs/forge-protocol.md +189 -0
- package/examples/go-billing/go.mod +7 -0
- package/examples/go-billing/main.go +120 -0
- package/examples/java-billing/pom.xml +52 -0
- package/examples/java-billing/src/main/java/dev/forgeos/examples/billing/CreateInvoiceInput.java +4 -0
- package/examples/java-billing/src/main/java/dev/forgeos/examples/billing/Invoice.java +11 -0
- package/examples/java-billing/src/main/java/dev/forgeos/examples/billing/Main.java +127 -0
- package/examples/java-billing/target/classes/dev/forgeos/examples/billing/CreateInvoiceInput.class +0 -0
- package/examples/java-billing/target/classes/dev/forgeos/examples/billing/Invoice.class +0 -0
- package/examples/java-billing/target/classes/dev/forgeos/examples/billing/Main$EmptyInput.class +0 -0
- package/examples/java-billing/target/classes/dev/forgeos/examples/billing/Main$Options.class +0 -0
- package/examples/java-billing/target/classes/dev/forgeos/examples/billing/Main.class +0 -0
- package/examples/java-billing/target/java-billing-0.1.0-alpha.11-all.jar +0 -0
- package/examples/java-billing/target/java-billing-0.1.0-alpha.11.jar +0 -0
- package/examples/java-billing/target/maven-archiver/pom.properties +3 -0
- package/examples/java-billing/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst +5 -0
- package/examples/java-billing/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst +3 -0
- package/package.json +29 -7
- package/schemas/forge-manifest.schema.json +57 -0
- package/src/forge/_generated/releaseManifest.json +1 -2
- package/src/forge/_generated/releaseManifest.ts +3 -3
- package/src/forge/agent-adapters/index.ts +1511 -123
- package/src/forge/agent-adapters/types.ts +216 -1
- package/src/forge/agent-memory/bridge.ts +1245 -0
- package/src/forge/agent-memory/context-pack.ts +151 -0
- package/src/forge/agent-memory/hook-runner.ts +312 -0
- package/src/forge/agent-memory/mcp.ts +224 -0
- package/src/forge/agent-memory/normalize.ts +498 -0
- package/src/forge/agent-memory/redaction.ts +103 -0
- package/src/forge/agent-memory/sources/claude-code.ts +51 -0
- package/src/forge/agent-memory/sources/codex-hook-runner.mjs +273 -0
- package/src/forge/agent-memory/sources/codex.ts +119 -0
- package/src/forge/agent-memory/sources/cursor.ts +35 -0
- package/src/forge/agent-memory/types.ts +191 -0
- package/src/forge/bench.ts +248 -0
- package/src/forge/brownfield-import/index.ts +801 -0
- package/src/forge/brownfield-import/types.ts +127 -0
- package/src/forge/cair/action-journal.ts +61 -0
- package/src/forge/cair/action-parser.ts +314 -0
- package/src/forge/cair/action-validator.ts +40 -0
- package/src/forge/cair/actions.ts +1818 -0
- package/src/forge/cair/format.ts +77 -0
- package/src/forge/cair/index.ts +106 -0
- package/src/forge/cair/query.ts +478 -0
- package/src/forge/cair/snapshot.ts +315 -0
- package/src/forge/cair/types.ts +248 -0
- package/src/forge/cli/ai.ts +671 -3
- package/src/forge/cli/auth.ts +36 -1
- package/src/forge/cli/build.ts +20 -4
- package/src/forge/cli/changed.ts +300 -0
- package/src/forge/cli/codex-app-server.ts +877 -0
- package/src/forge/cli/commands.ts +1285 -7
- package/src/forge/cli/db.ts +121 -2
- package/src/forge/cli/deps.ts +79 -12
- package/src/forge/cli/dev.ts +502 -38
- package/src/forge/cli/docs.ts +265 -0
- package/src/forge/cli/handoff.ts +250 -0
- package/src/forge/cli/index.ts +1 -0
- package/src/forge/cli/main.ts +49 -3
- package/src/forge/cli/new.ts +3 -1
- package/src/forge/cli/next-actions.ts +23 -0
- package/src/forge/cli/output.ts +290 -1
- package/src/forge/cli/parse.ts +770 -36
- package/src/forge/cli/query.ts +32 -0
- package/src/forge/cli/release.ts +35 -11
- package/src/forge/cli/rls.ts +568 -17
- package/src/forge/cli/run.ts +41 -0
- package/src/forge/cli/secrets.ts +46 -1
- package/src/forge/cli/security.ts +381 -0
- package/src/forge/cli/self-host.ts +56 -14
- package/src/forge/cli/studio.ts +2163 -0
- package/src/forge/cli/verify.ts +1422 -32
- package/src/forge/compiler/agent-contract/build.ts +725 -41
- package/src/forge/compiler/agent-contract/types.ts +85 -0
- package/src/forge/compiler/ai-registry/build.ts +62 -1
- package/src/forge/compiler/ai-registry/constants.ts +1 -1
- package/src/forge/compiler/ai-registry/parse.ts +168 -5
- package/src/forge/compiler/api-surface/build.ts +47 -0
- package/src/forge/compiler/app-graph/build.ts +68 -8
- package/src/forge/compiler/app-graph/extract.ts +107 -0
- package/src/forge/compiler/app-graph/forge-apis.ts +1 -0
- package/src/forge/compiler/app-graph/module-graph.ts +73 -78
- package/src/forge/compiler/app-graph/parser.ts +24 -24
- package/src/forge/compiler/app-graph/profile.ts +26 -0
- package/src/forge/compiler/app-graph/versions.ts +1 -1
- package/src/forge/compiler/classifier/capabilities.ts +3 -2
- package/src/forge/compiler/classifier/classify.ts +32 -8
- package/src/forge/compiler/classifier/secrets.ts +3 -2
- package/src/forge/compiler/classifier/signals.ts +91 -1
- package/src/forge/compiler/client-sdk/build-manifest.ts +59 -0
- package/src/forge/compiler/client-sdk/render-client.ts +188 -13
- package/src/forge/compiler/data-graph/parse.ts +3 -3
- package/src/forge/compiler/data-graph/sql/ddl.ts +60 -2
- package/src/forge/compiler/data-graph/sql/serialize.ts +4 -0
- package/src/forge/compiler/data-graph/sql/types.ts +1 -0
- package/src/forge/compiler/dev-manifest/build.ts +3 -0
- package/src/forge/compiler/diagnostics/codes.ts +35 -0
- package/src/forge/compiler/diagnostics/create.ts +8 -3
- package/src/forge/compiler/diagnostics/index.ts +2 -0
- package/src/forge/compiler/emitter/barrel.ts +3 -0
- package/src/forge/compiler/emitter/render.ts +5 -0
- package/src/forge/compiler/external-manifest/registry.ts +205 -0
- package/src/forge/compiler/external-manifest/types.ts +91 -0
- package/src/forge/compiler/external-manifest/validate.ts +373 -0
- package/src/forge/compiler/frontend-graph/build.ts +85 -13
- package/src/forge/compiler/integration/add.ts +498 -22
- package/src/forge/compiler/integration/snapshot.ts +2 -0
- package/src/forge/compiler/make-registry/build.ts +19 -7
- package/src/forge/compiler/orchestrator/plan-profile.ts +23 -0
- package/src/forge/compiler/orchestrator/plan.ts +78 -7
- package/src/forge/compiler/orchestrator/profile.ts +65 -0
- package/src/forge/compiler/orchestrator/run.ts +97 -31
- package/src/forge/compiler/orchestrator/serialize.ts +101 -8
- package/src/forge/compiler/package-graph/compiler.ts +13 -3
- package/src/forge/compiler/package-manager/adapter.ts +4 -1
- package/src/forge/compiler/package-manager/commands.ts +4 -0
- package/src/forge/compiler/package-manager/executor.ts +30 -1
- package/src/forge/compiler/policy-registry/build.ts +44 -1
- package/src/forge/compiler/test-graph/build.ts +11 -3
- package/src/forge/compiler/types/ai-registry.ts +25 -1
- package/src/forge/compiler/types/app-graph.ts +9 -2
- package/src/forge/compiler/types/cli.ts +76 -1
- package/src/forge/compiler/types/dev-manifest.ts +3 -0
- package/src/forge/compiler/types/frontend-graph.ts +2 -2
- package/src/forge/delta/classifier.ts +52 -0
- package/src/forge/delta/explain.ts +126 -0
- package/src/forge/delta/git-observer.ts +43 -0
- package/src/forge/delta/ids.ts +44 -0
- package/src/forge/delta/index.ts +13 -0
- package/src/forge/delta/recorder.ts +402 -0
- package/src/forge/delta/redaction.ts +50 -0
- package/src/forge/delta/schema.ts +240 -0
- package/src/forge/delta/session.ts +142 -0
- package/src/forge/delta/status.ts +489 -0
- package/src/forge/delta/store.ts +2975 -0
- package/src/forge/delta/timeline.ts +104 -0
- package/src/forge/dev/server.ts +768 -15
- package/src/forge/dev/types.ts +15 -1
- package/src/forge/dev/watch.ts +17 -7
- package/src/forge/dev-console/cycle.ts +233 -21
- package/src/forge/dev-console/types.ts +46 -1
- package/src/forge/impact/index.ts +46 -8
- package/src/forge/impact/types.ts +6 -0
- package/src/forge/intent/index.ts +35 -16
- package/src/forge/make/index.ts +149 -6
- package/src/forge/make/templates.ts +343 -2
- package/src/forge/make/types.ts +3 -1
- package/src/forge/refactor/index.ts +1 -0
- package/src/forge/repair/rules/index.ts +2 -2
- package/src/forge/review/index.ts +158 -12
- package/src/forge/review/types.ts +15 -0
- package/src/forge/runtime/ai/context.ts +210 -5
- package/src/forge/runtime/ai/types.ts +70 -0
- package/src/forge/runtime/auth/claims.ts +32 -0
- package/src/forge/runtime/auth/errors.ts +2 -0
- package/src/forge/runtime/context/create-context.ts +30 -6
- package/src/forge/runtime/db/generated-client.ts +13 -2
- package/src/forge/runtime/db/memory-adapter.ts +2 -2
- package/src/forge/runtime/db/pglite-adapter.ts +77 -2
- package/src/forge/runtime/db/postgres-adapter.ts +6 -3
- package/src/forge/runtime/executor.ts +112 -2
- package/src/forge/runtime/external/bridge.ts +649 -0
- package/src/forge/runtime/runner/run-entry.ts +16 -7
- package/src/forge/runtime/telemetry/scrubber.ts +91 -10
- package/src/forge/runtime/webhooks/security.ts +184 -0
- package/src/forge/server.ts +100 -2
- package/src/forge/version.ts +1 -1
- package/src/forge/vue/index.ts +407 -0
- package/src/forge/workspace/change-summary.ts +209 -0
- package/src/forge/workspace/forge-cli.ts +14 -0
- package/src/forge/workspace/git-summary.ts +279 -0
- package/templates/agent-workroom/AGENTS.md +29 -0
- package/templates/agent-workroom/README.md +34 -0
- package/templates/agent-workroom/forge.config.ts +3 -0
- package/templates/agent-workroom/package.json +33 -0
- package/templates/agent-workroom/src/actions/indexAgentSignal.ts +10 -0
- package/templates/agent-workroom/src/commands/openWorkroom.ts +61 -0
- package/templates/agent-workroom/src/commands/recordAgentSignal.ts +119 -0
- package/templates/agent-workroom/src/commands/recordCheckRun.ts +52 -0
- package/templates/agent-workroom/src/forge/schema.ts +54 -0
- package/templates/agent-workroom/src/policies.ts +6 -0
- package/templates/agent-workroom/src/queries/listWorkrooms.ts +11 -0
- package/templates/agent-workroom/src/queries/liveWorkroom.ts +63 -0
- package/templates/agent-workroom/tsconfig.json +16 -0
- package/templates/agent-workroom/web/index.html +12 -0
- package/templates/agent-workroom/web/package.json +21 -0
- package/templates/agent-workroom/web/src/App.tsx +345 -0
- package/templates/agent-workroom/web/src/lib/forge.ts +13 -0
- package/templates/agent-workroom/web/src/main.tsx +13 -0
- package/templates/agent-workroom/web/src/styles.css +545 -0
- package/templates/agent-workroom/web/tsconfig.json +27 -0
- package/templates/b2b-support-web/package.json +2 -0
- package/templates/b2b-support-web/tsconfig.json +4 -1
- package/templates/b2b-support-web/web/package.json +1 -1
- package/templates/minimal-web/package.json +2 -1
- package/templates/minimal-web/tsconfig.json +3 -1
- package/templates/minimal-web/web/package.json +2 -2
- package/src/forge/_generated/actionSubscriptions.json +0 -2
- package/src/forge/_generated/actionSubscriptions.ts +0 -10
- package/src/forge/_generated/agentAdapterManifest.json +0 -2
- package/src/forge/_generated/agentAdapterManifest.ts +0 -73
- package/src/forge/_generated/agentContract.json +0 -2
- package/src/forge/_generated/agentContract.ts +0 -7696
- package/src/forge/_generated/agentQuickstart.md +0 -32
- package/src/forge/_generated/aiContext.ts +0 -59
- package/src/forge/_generated/aiModels.json +0 -2
- package/src/forge/_generated/aiModels.ts +0 -35
- package/src/forge/_generated/aiProviders.json +0 -2
- package/src/forge/_generated/aiProviders.ts +0 -23
- package/src/forge/_generated/aiRegistry.json +0 -2
- package/src/forge/_generated/aiRegistry.ts +0 -29
- package/src/forge/_generated/api.json +0 -2
- package/src/forge/_generated/api.ts +0 -8
- package/src/forge/_generated/appGraph.json +0 -2
- package/src/forge/_generated/appGraph.ts +0 -14667
- package/src/forge/_generated/appMap.md +0 -35
- package/src/forge/_generated/artifactManifest.json +0 -2
- package/src/forge/_generated/artifactManifest.ts +0 -7
- package/src/forge/_generated/authClaims.json +0 -2
- package/src/forge/_generated/authClaims.ts +0 -13
- package/src/forge/_generated/authConfig.json +0 -2
- package/src/forge/_generated/authConfig.ts +0 -17
- package/src/forge/_generated/authContext.ts +0 -23
- package/src/forge/_generated/authRegistry.json +0 -2
- package/src/forge/_generated/authRegistry.ts +0 -25
- package/src/forge/_generated/buildInfo.json +0 -2
- package/src/forge/_generated/buildInfo.ts +0 -9
- package/src/forge/_generated/capabilityMap.json +0 -2
- package/src/forge/_generated/capabilityMap.md +0 -15
- package/src/forge/_generated/capabilityMap.ts +0 -17
- package/src/forge/_generated/client.ts +0 -282
- package/src/forge/_generated/clientApi.ts +0 -9
- package/src/forge/_generated/clientManifest.json +0 -2
- package/src/forge/_generated/clientManifest.ts +0 -39
- package/src/forge/_generated/clientTypes.ts +0 -78
- package/src/forge/_generated/configRegistry.json +0 -2
- package/src/forge/_generated/configRegistry.ts +0 -4
- package/src/forge/_generated/dataGraph.json +0 -2
- package/src/forge/_generated/dataGraph.ts +0 -8
- package/src/forge/_generated/db.json +0 -2
- package/src/forge/_generated/db.ts +0 -2
- package/src/forge/_generated/dbSecurityManifest.json +0 -2
- package/src/forge/_generated/dbSecurityManifest.ts +0 -15
- package/src/forge/_generated/dbSessionContext.json +0 -2
- package/src/forge/_generated/dbSessionContext.ts +0 -39
- package/src/forge/_generated/deployManifest.json +0 -2
- package/src/forge/_generated/deployManifest.ts +0 -14
- package/src/forge/_generated/devManifest.json +0 -2
- package/src/forge/_generated/devManifest.ts +0 -47
- package/src/forge/_generated/envSchema.json +0 -2
- package/src/forge/_generated/envSchema.ts +0 -59
- package/src/forge/_generated/frontendGraph.json +0 -2
- package/src/forge/_generated/frontendGraph.ts +0 -27
- package/src/forge/_generated/importGuards.json +0 -2
- package/src/forge/_generated/importGuards.ts +0 -686
- package/src/forge/_generated/index.ts +0 -67
- package/src/forge/_generated/liveProductionManifest.json +0 -2
- package/src/forge/_generated/liveProductionManifest.ts +0 -23
- package/src/forge/_generated/liveProtocol.json +0 -2
- package/src/forge/_generated/liveProtocol.ts +0 -21
- package/src/forge/_generated/liveQueryRegistry.json +0 -2
- package/src/forge/_generated/liveQueryRegistry.ts +0 -9
- package/src/forge/_generated/liveTransportConfig.json +0 -2
- package/src/forge/_generated/liveTransportConfig.ts +0 -19
- package/src/forge/_generated/makeRegistry.json +0 -2
- package/src/forge/_generated/makeRegistry.ts +0 -163
- package/src/forge/_generated/makeTemplates.json +0 -2
- package/src/forge/_generated/makeTemplates.ts +0 -61
- package/src/forge/_generated/mockMap.json +0 -2
- package/src/forge/_generated/mockMap.ts +0 -7
- package/src/forge/_generated/operationPlaybooks.md +0 -147
- package/src/forge/_generated/packageGraph.json +0 -2
- package/src/forge/_generated/packageGraph.ts +0 -245249
- package/src/forge/_generated/packageUpgradeRegistry.json +0 -2
- package/src/forge/_generated/packageUpgradeRegistry.ts +0 -15
- package/src/forge/_generated/permissionMatrix.json +0 -2
- package/src/forge/_generated/permissionMatrix.ts +0 -7
- package/src/forge/_generated/policyRegistry.json +0 -2
- package/src/forge/_generated/policyRegistry.ts +0 -11
- package/src/forge/_generated/queryRegistry.json +0 -2
- package/src/forge/_generated/queryRegistry.ts +0 -9
- package/src/forge/_generated/react.d.ts +0 -22
- package/src/forge/_generated/react.ts +0 -29
- package/src/forge/_generated/reactManifest.json +0 -2
- package/src/forge/_generated/reactManifest.ts +0 -19
- package/src/forge/_generated/rlsPolicies.json +0 -2
- package/src/forge/_generated/rlsPolicies.sql +0 -34
- package/src/forge/_generated/rlsPolicies.ts +0 -6
- package/src/forge/_generated/runtimeGraph.json +0 -2
- package/src/forge/_generated/runtimeGraph.ts +0 -8
- package/src/forge/_generated/runtimeMatrix.json +0 -2
- package/src/forge/_generated/runtimeMatrix.ts +0 -327385
- package/src/forge/_generated/runtimeRegistry.ts +0 -2
- package/src/forge/_generated/runtimeRules.md +0 -79
- package/src/forge/_generated/secretRegistry.json +0 -2
- package/src/forge/_generated/secretRegistry.ts +0 -50
- package/src/forge/_generated/secretsContext.ts +0 -11
- package/src/forge/_generated/serverApi.ts +0 -10
- package/src/forge/_generated/sourceMapManifest.json +0 -2
- package/src/forge/_generated/sourceMapManifest.ts +0 -7
- package/src/forge/_generated/sqlPlan.json +0 -2
- package/src/forge/_generated/sqlPlan.ts +0 -88
- package/src/forge/_generated/subscriptionManifest.json +0 -2
- package/src/forge/_generated/subscriptionManifest.ts +0 -7
- package/src/forge/_generated/symbolicationManifest.json +0 -2
- package/src/forge/_generated/symbolicationManifest.ts +0 -17
- package/src/forge/_generated/telemetryRegistry.json +0 -2
- package/src/forge/_generated/telemetryRegistry.ts +0 -9
- package/src/forge/_generated/telemetrySinks.json +0 -2
- package/src/forge/_generated/telemetrySinks.ts +0 -11
- package/src/forge/_generated/tenantScope.json +0 -2
- package/src/forge/_generated/tenantScope.ts +0 -8
- package/src/forge/_generated/testGraph.json +0 -2
- package/src/forge/_generated/testGraph.ts +0 -3108
- package/src/forge/_generated/testPlanRegistry.json +0 -2
- package/src/forge/_generated/testPlanRegistry.ts +0 -33
- package/src/forge/_generated/uiRoutes.json +0 -2
- package/src/forge/_generated/uiRoutes.ts +0 -16
- package/src/forge/_generated/uiScenarios.json +0 -2
- package/src/forge/_generated/uiScenarios.ts +0 -30
- package/src/forge/_generated/uiTestManifest.json +0 -2
- package/src/forge/_generated/uiTestManifest.ts +0 -27
- package/src/forge/_generated/workflowRegistry.json +0 -2
- package/src/forge/_generated/workflowRegistry.ts +0 -9
- package/src/forge/_generated/workflowSubscriptions.json +0 -2
- package/src/forge/_generated/workflowSubscriptions.ts +0 -10
package/src/forge/cli/dev.ts
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { spawn } from "node:child_process";
|
|
2
|
+
import { createServer as createNetServer } from "node:net";
|
|
2
3
|
import { run } from "../compiler/orchestrator/run.ts";
|
|
3
|
-
import { join } from "node:path";
|
|
4
|
+
import { basename, join } from "node:path";
|
|
4
5
|
import { nodeFileSystem } from "../compiler/fs/index.ts";
|
|
5
6
|
import { stripDeterministicHeader } from "../compiler/primitives/header.ts";
|
|
7
|
+
import { hashStable } from "../compiler/primitives/hash.ts";
|
|
6
8
|
import { GENERATED_DIR } from "../compiler/emitter/constants.ts";
|
|
7
9
|
import type { FrontendGraph } from "../compiler/types/frontend-graph.ts";
|
|
8
10
|
import { detectPackageManager } from "../compiler/package-manager/detect.ts";
|
|
@@ -12,6 +14,12 @@ import {
|
|
|
12
14
|
formatDevConsoleJson,
|
|
13
15
|
runDevConsoleCycle,
|
|
14
16
|
} from "../dev-console/cycle.ts";
|
|
17
|
+
import type {
|
|
18
|
+
DevConsoleAgentContext,
|
|
19
|
+
DevConsoleCycle,
|
|
20
|
+
DevConsoleGeneratedSummary,
|
|
21
|
+
DevConsoleSummary,
|
|
22
|
+
} from "../dev-console/types.ts";
|
|
15
23
|
import {
|
|
16
24
|
resolveDevHost,
|
|
17
25
|
resolveDevPort,
|
|
@@ -19,6 +27,8 @@ import {
|
|
|
19
27
|
} from "../dev/server.ts";
|
|
20
28
|
import { startDevWatch } from "../dev/watch.ts";
|
|
21
29
|
import type { DevServerHandle } from "../dev/types.ts";
|
|
30
|
+
import { createAmbientDeltaRecorder } from "../delta/index.ts";
|
|
31
|
+
import { resetCompileSessions } from "../compiler/orchestrator/session.ts";
|
|
22
32
|
|
|
23
33
|
export interface DevCommandOptions {
|
|
24
34
|
workspaceRoot: string;
|
|
@@ -29,7 +39,7 @@ export interface DevCommandOptions {
|
|
|
29
39
|
once?: boolean;
|
|
30
40
|
watch: boolean;
|
|
31
41
|
json: boolean;
|
|
32
|
-
db: "pglite" | "postgres" | "none";
|
|
42
|
+
db: "memory" | "pglite" | "postgres" | "none";
|
|
33
43
|
databaseUrl?: string;
|
|
34
44
|
worker: boolean;
|
|
35
45
|
withWeb?: boolean;
|
|
@@ -41,6 +51,7 @@ export interface DevCommandOptions {
|
|
|
41
51
|
envFile?: string;
|
|
42
52
|
mode?: "dev" | "serve";
|
|
43
53
|
allowDevAuth?: boolean;
|
|
54
|
+
skipStartupConsole?: boolean;
|
|
44
55
|
}
|
|
45
56
|
|
|
46
57
|
export interface DevCommandResult {
|
|
@@ -49,9 +60,30 @@ export interface DevCommandResult {
|
|
|
49
60
|
exitCode: 0 | 1;
|
|
50
61
|
}
|
|
51
62
|
|
|
63
|
+
export interface DevGenerateResult {
|
|
64
|
+
ok: boolean;
|
|
65
|
+
changed: string[];
|
|
66
|
+
unchanged: string[];
|
|
67
|
+
diagnostics: Array<{ severity: string; code: string; message: string }>;
|
|
68
|
+
exitCode: 0 | 1;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
interface DevStartupGeneratedEvidence {
|
|
72
|
+
ok: boolean;
|
|
73
|
+
state: "fresh" | "regenerated" | "stale-risk";
|
|
74
|
+
changedFiles: number;
|
|
75
|
+
sampleChanged: string[];
|
|
76
|
+
hiddenChanged: number;
|
|
77
|
+
message: string;
|
|
78
|
+
command: string;
|
|
79
|
+
checkCommand: string;
|
|
80
|
+
}
|
|
81
|
+
|
|
52
82
|
interface WebDevServerHandle {
|
|
53
83
|
url: string;
|
|
54
84
|
port: number;
|
|
85
|
+
requestedPort?: number;
|
|
86
|
+
autoPortSelected: boolean;
|
|
55
87
|
command: string[];
|
|
56
88
|
stop: () => void;
|
|
57
89
|
}
|
|
@@ -70,14 +102,25 @@ interface DevStartupSummary {
|
|
|
70
102
|
web: null | {
|
|
71
103
|
url: string;
|
|
72
104
|
port: number;
|
|
105
|
+
requestedPort?: number;
|
|
106
|
+
autoPortSelected: boolean;
|
|
73
107
|
command: string[];
|
|
74
108
|
framework: string;
|
|
75
109
|
routes: string[];
|
|
76
110
|
bridgeFiles: string[];
|
|
77
111
|
apiUrlEnv?: string;
|
|
78
112
|
};
|
|
113
|
+
preview: {
|
|
114
|
+
studioUrl?: string;
|
|
115
|
+
targetAppUrl: string;
|
|
116
|
+
targetAppPort: number;
|
|
117
|
+
isStudioSelfPreview: boolean;
|
|
118
|
+
note: string;
|
|
119
|
+
};
|
|
79
120
|
watch: {
|
|
80
121
|
enabled: boolean;
|
|
122
|
+
autoGenerate: boolean;
|
|
123
|
+
reloadsRuntime: boolean;
|
|
81
124
|
};
|
|
82
125
|
runtime: {
|
|
83
126
|
routes: Array<{ method: string; path: string; purpose: string }>;
|
|
@@ -90,6 +133,20 @@ interface DevStartupSummary {
|
|
|
90
133
|
bridgeFiles: string[];
|
|
91
134
|
diagnostics: number;
|
|
92
135
|
};
|
|
136
|
+
generated: {
|
|
137
|
+
state: "fresh" | "regenerated" | "stale-risk";
|
|
138
|
+
generatorVersion?: string;
|
|
139
|
+
inputHash?: string;
|
|
140
|
+
buildInfoHash?: string;
|
|
141
|
+
runtimeLoadedHash?: string;
|
|
142
|
+
runtimeStaleRisk: boolean;
|
|
143
|
+
changedFiles: number;
|
|
144
|
+
sampleChanged: string[];
|
|
145
|
+
hiddenChanged: number;
|
|
146
|
+
command: string;
|
|
147
|
+
checkCommand: string;
|
|
148
|
+
message: string;
|
|
149
|
+
};
|
|
93
150
|
next: {
|
|
94
151
|
browserUrl: string;
|
|
95
152
|
apiIndex: string;
|
|
@@ -99,6 +156,132 @@ interface DevStartupSummary {
|
|
|
99
156
|
pid: number;
|
|
100
157
|
}
|
|
101
158
|
|
|
159
|
+
function nextPreviewPort(webUrl?: string): number {
|
|
160
|
+
if (!webUrl) {
|
|
161
|
+
return 5174;
|
|
162
|
+
}
|
|
163
|
+
try {
|
|
164
|
+
const parsed = new URL(webUrl);
|
|
165
|
+
const port = parsed.port ? Number(parsed.port) : parsed.protocol === "https:" ? 443 : 80;
|
|
166
|
+
return Number.isFinite(port) && port > 0 ? port + 1 : 5174;
|
|
167
|
+
} catch {
|
|
168
|
+
return 5174;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
function isForgeStudioWorkspace(workspaceRoot: string): boolean {
|
|
173
|
+
return basename(workspaceRoot).toLowerCase() === "forge-studio";
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
function previewSummaryFor(input: {
|
|
177
|
+
workspaceRoot: string;
|
|
178
|
+
host: string;
|
|
179
|
+
webUrl?: string;
|
|
180
|
+
}): DevStartupSummary["preview"] {
|
|
181
|
+
if (input.webUrl && !isForgeStudioWorkspace(input.workspaceRoot)) {
|
|
182
|
+
const parsed = new URL(input.webUrl);
|
|
183
|
+
const targetAppPort = parsed.port ? Number(parsed.port) : parsed.protocol === "https:" ? 443 : 80;
|
|
184
|
+
return {
|
|
185
|
+
targetAppUrl: input.webUrl,
|
|
186
|
+
targetAppPort,
|
|
187
|
+
isStudioSelfPreview: false,
|
|
188
|
+
note: `Web app preview is running at ${input.webUrl}.`,
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
const targetAppPort = nextPreviewPort(input.webUrl);
|
|
193
|
+
const targetAppUrl = `http://${input.host}:${targetAppPort}`;
|
|
194
|
+
const isStudioSelfPreview = Boolean(input.webUrl && input.webUrl === targetAppUrl);
|
|
195
|
+
return {
|
|
196
|
+
...(input.webUrl ? { studioUrl: input.webUrl } : {}),
|
|
197
|
+
targetAppUrl,
|
|
198
|
+
targetAppPort,
|
|
199
|
+
isStudioSelfPreview,
|
|
200
|
+
note: input.webUrl
|
|
201
|
+
? `Use ${targetAppUrl} for the app being built when ${input.webUrl} is Forge Studio itself.`
|
|
202
|
+
: `No web app was detected; ${targetAppUrl} is the default target app preview URL for Studio attach flows.`,
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
async function isPortAvailable(host: string, port: number): Promise<boolean> {
|
|
207
|
+
if (port === 0) {
|
|
208
|
+
return true;
|
|
209
|
+
}
|
|
210
|
+
const server = createNetServer();
|
|
211
|
+
return new Promise<boolean>((resolve) => {
|
|
212
|
+
const cleanup = () => {
|
|
213
|
+
server.removeAllListeners();
|
|
214
|
+
};
|
|
215
|
+
server.once("error", () => {
|
|
216
|
+
cleanup();
|
|
217
|
+
resolve(false);
|
|
218
|
+
});
|
|
219
|
+
server.listen(port, host, () => {
|
|
220
|
+
server.close(() => {
|
|
221
|
+
cleanup();
|
|
222
|
+
resolve(true);
|
|
223
|
+
});
|
|
224
|
+
});
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
export async function resolveAvailableWebPort(input: {
|
|
229
|
+
host: string;
|
|
230
|
+
preferredPort: number;
|
|
231
|
+
maxAttempts?: number;
|
|
232
|
+
}): Promise<{ port: number; requestedPort?: number; autoPortSelected: boolean }> {
|
|
233
|
+
const attempts = input.maxAttempts ?? 20;
|
|
234
|
+
const start = Math.max(0, Math.floor(input.preferredPort));
|
|
235
|
+
if (start === 0) {
|
|
236
|
+
return { port: 0, autoPortSelected: false };
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
for (let offset = 0; offset < attempts; offset += 1) {
|
|
240
|
+
const candidate = start + offset;
|
|
241
|
+
if (await isPortAvailable(input.host, candidate)) {
|
|
242
|
+
return {
|
|
243
|
+
port: candidate,
|
|
244
|
+
...(candidate !== start ? { requestedPort: start } : {}),
|
|
245
|
+
autoPortSelected: candidate !== start,
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
return {
|
|
251
|
+
port: 0,
|
|
252
|
+
requestedPort: start,
|
|
253
|
+
autoPortSelected: true,
|
|
254
|
+
};
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
export interface DevWatchGenerateFailureEvent {
|
|
258
|
+
schemaVersion: "0.1.0";
|
|
259
|
+
event: "dev.generate_failed";
|
|
260
|
+
ok: false;
|
|
261
|
+
changedFiles: number;
|
|
262
|
+
changedPaths: string[];
|
|
263
|
+
generated: DevConsoleGeneratedSummary;
|
|
264
|
+
diagnostics: DevGenerateResult["diagnostics"];
|
|
265
|
+
nextActions: string[];
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
export interface DevWatchReloadEvent {
|
|
269
|
+
schemaVersion: "0.1.0";
|
|
270
|
+
event: "dev.reload";
|
|
271
|
+
ok: boolean;
|
|
272
|
+
changedFiles: number;
|
|
273
|
+
changedPaths: string[];
|
|
274
|
+
migrated: boolean;
|
|
275
|
+
routes: number;
|
|
276
|
+
runtimeEntries: number;
|
|
277
|
+
worker: unknown;
|
|
278
|
+
diagnostics: DevGenerateResult["diagnostics"];
|
|
279
|
+
generated: DevConsoleGeneratedSummary;
|
|
280
|
+
preview: DevConsoleSummary["preview"];
|
|
281
|
+
agentContext: DevConsoleAgentContext;
|
|
282
|
+
nextActions: string[];
|
|
283
|
+
}
|
|
284
|
+
|
|
102
285
|
function readGeneratedJson<T>(workspaceRoot: string, relative: string): T | null {
|
|
103
286
|
const absolute = join(workspaceRoot, relative);
|
|
104
287
|
if (!nodeFileSystem.exists(absolute)) {
|
|
@@ -175,6 +358,8 @@ function startWebDevServer(input: {
|
|
|
175
358
|
workspaceRoot: string;
|
|
176
359
|
host: string;
|
|
177
360
|
port: number;
|
|
361
|
+
requestedPort?: number;
|
|
362
|
+
autoPortSelected?: boolean;
|
|
178
363
|
apiUrl: string;
|
|
179
364
|
json: boolean;
|
|
180
365
|
}): WebDevServerHandle | null {
|
|
@@ -209,6 +394,8 @@ function startWebDevServer(input: {
|
|
|
209
394
|
return {
|
|
210
395
|
url: `http://${input.host}:${input.port}`,
|
|
211
396
|
port: input.port,
|
|
397
|
+
...(input.requestedPort !== undefined ? { requestedPort: input.requestedPort } : {}),
|
|
398
|
+
autoPortSelected: input.autoPortSelected ?? false,
|
|
212
399
|
command,
|
|
213
400
|
stop: () => {
|
|
214
401
|
try {
|
|
@@ -225,15 +412,28 @@ function buildStartupSummary(input: {
|
|
|
225
412
|
handle: DevServerHandle;
|
|
226
413
|
web?: WebDevServerHandle | null;
|
|
227
414
|
watch: boolean;
|
|
415
|
+
generated?: DevStartupGeneratedEvidence;
|
|
228
416
|
}): DevStartupSummary {
|
|
229
417
|
const frontend = readGeneratedJson<FrontendGraph>(
|
|
230
418
|
input.workspaceRoot,
|
|
231
419
|
`${GENERATED_DIR}/frontendGraph.json`,
|
|
232
420
|
);
|
|
421
|
+
const buildInfo = readGeneratedJson<{ generatorVersion?: string; inputHash?: string }>(
|
|
422
|
+
input.workspaceRoot,
|
|
423
|
+
`${GENERATED_DIR}/buildInfo.json`,
|
|
424
|
+
);
|
|
425
|
+
const buildInfoRaw = nodeFileSystem.exists(join(input.workspaceRoot, `${GENERATED_DIR}/buildInfo.json`))
|
|
426
|
+
? stripDeterministicHeader(nodeFileSystem.readText(join(input.workspaceRoot, `${GENERATED_DIR}/buildInfo.json`)) ?? "")
|
|
427
|
+
: "";
|
|
233
428
|
const bindings = frontend
|
|
234
429
|
? [...new Set(frontend.clientBindings.map((binding) => `${binding.kind}:${binding.name}`))].sort()
|
|
235
430
|
: [];
|
|
236
431
|
const browserUrl = input.web?.url ?? input.handle.url;
|
|
432
|
+
const preview = previewSummaryFor({
|
|
433
|
+
workspaceRoot: input.workspaceRoot,
|
|
434
|
+
host: input.handle.host,
|
|
435
|
+
...(input.web?.url ? { webUrl: input.web.url } : {}),
|
|
436
|
+
});
|
|
237
437
|
return {
|
|
238
438
|
schemaVersion: "0.1.0",
|
|
239
439
|
ok: true,
|
|
@@ -249,6 +449,8 @@ function buildStartupSummary(input: {
|
|
|
249
449
|
? {
|
|
250
450
|
url: input.web.url,
|
|
251
451
|
port: input.web.port,
|
|
452
|
+
...(input.web.requestedPort !== undefined ? { requestedPort: input.web.requestedPort } : {}),
|
|
453
|
+
autoPortSelected: input.web.autoPortSelected,
|
|
252
454
|
command: input.web.command,
|
|
253
455
|
framework: frontend?.framework ?? "unknown",
|
|
254
456
|
routes: frontend?.routes.map((route) => route.path) ?? [],
|
|
@@ -256,8 +458,11 @@ function buildStartupSummary(input: {
|
|
|
256
458
|
...(frontend?.dev?.apiUrlEnv ? { apiUrlEnv: frontend.dev.apiUrlEnv } : {}),
|
|
257
459
|
}
|
|
258
460
|
: null,
|
|
461
|
+
preview,
|
|
259
462
|
watch: {
|
|
260
463
|
enabled: input.watch,
|
|
464
|
+
autoGenerate: input.watch,
|
|
465
|
+
reloadsRuntime: input.watch,
|
|
261
466
|
},
|
|
262
467
|
runtime: {
|
|
263
468
|
routes: input.handle.routes.map((route) => ({
|
|
@@ -274,10 +479,24 @@ function buildStartupSummary(input: {
|
|
|
274
479
|
bridgeFiles: frontend?.bridgeFiles ?? [],
|
|
275
480
|
diagnostics: frontend?.diagnostics.length ?? 0,
|
|
276
481
|
},
|
|
482
|
+
generated: {
|
|
483
|
+
state: input.generated?.state ?? (buildInfoRaw ? "fresh" : "stale-risk"),
|
|
484
|
+
...(buildInfo?.generatorVersion ? { generatorVersion: buildInfo.generatorVersion } : {}),
|
|
485
|
+
...(buildInfo?.inputHash ? { inputHash: buildInfo.inputHash } : {}),
|
|
486
|
+
...(buildInfoRaw ? { buildInfoHash: hashStable(buildInfoRaw) } : {}),
|
|
487
|
+
...(buildInfoRaw ? { runtimeLoadedHash: hashStable(buildInfoRaw) } : {}),
|
|
488
|
+
runtimeStaleRisk: !buildInfoRaw || input.generated?.state === "stale-risk",
|
|
489
|
+
changedFiles: input.generated?.changedFiles ?? 0,
|
|
490
|
+
sampleChanged: input.generated?.sampleChanged ?? [],
|
|
491
|
+
hiddenChanged: input.generated?.hiddenChanged ?? 0,
|
|
492
|
+
command: input.generated?.command ?? "forge generate",
|
|
493
|
+
checkCommand: input.generated?.checkCommand ?? "forge generate --check --json",
|
|
494
|
+
message: input.generated?.message ?? (buildInfoRaw ? "generated artifacts are loaded" : "generated build info is missing"),
|
|
495
|
+
},
|
|
277
496
|
next: {
|
|
278
497
|
browserUrl,
|
|
279
498
|
apiIndex: input.handle.url,
|
|
280
|
-
inspect: "forge inspect
|
|
499
|
+
inspect: "forge inspect summary --json",
|
|
281
500
|
verify: "forge dev --once --json",
|
|
282
501
|
},
|
|
283
502
|
pid: process.pid,
|
|
@@ -295,11 +514,18 @@ function printStartupHuman(summary: DevStartupSummary): void {
|
|
|
295
514
|
lines.push(` DB: ${summary.api.db.kind} ${summary.api.db.connected ? "connected" : "not connected"}`);
|
|
296
515
|
lines.push(` Worker: ${summary.api.worker}`);
|
|
297
516
|
lines.push(` Watch: ${summary.watch.enabled ? "on" : "off"}`);
|
|
517
|
+
lines.push(` Auto-generate: ${summary.watch.autoGenerate ? "on" : "off"}`);
|
|
518
|
+
lines.push(` Generated: ${summary.generated.state}${summary.generated.changedFiles > 0 ? ` (${summary.generated.changedFiles} changed)` : ""}${summary.generated.runtimeStaleRisk ? " (stale risk)" : ""}`);
|
|
519
|
+
lines.push(` Generated note: ${summary.generated.message}`);
|
|
520
|
+
lines.push(` Generated check: ${summary.generated.checkCommand}`);
|
|
298
521
|
lines.push("");
|
|
299
522
|
|
|
300
523
|
lines.push("Web app");
|
|
301
524
|
if (summary.web) {
|
|
302
525
|
lines.push(` URL: ${summary.web.url}`);
|
|
526
|
+
if (summary.web.autoPortSelected && summary.web.requestedPort) {
|
|
527
|
+
lines.push(` Requested port: ${summary.web.requestedPort} (busy; selected ${summary.web.port})`);
|
|
528
|
+
}
|
|
303
529
|
lines.push(` Framework: ${summary.web.framework}`);
|
|
304
530
|
lines.push(` API env: ${summary.web.apiUrlEnv ?? "unknown"}=${summary.api.url}`);
|
|
305
531
|
lines.push(` Bridge: ${summary.web.bridgeFiles.length > 0 ? summary.web.bridgeFiles.join(", ") : "missing"}`);
|
|
@@ -325,6 +551,15 @@ function printStartupHuman(summary: DevStartupSummary): void {
|
|
|
325
551
|
lines.push("Agent checks");
|
|
326
552
|
lines.push(` ${summary.next.verify}`);
|
|
327
553
|
lines.push(` ${summary.next.inspect}`);
|
|
554
|
+
lines.push(" forge changed --json");
|
|
555
|
+
lines.push("");
|
|
556
|
+
|
|
557
|
+
lines.push("Preview");
|
|
558
|
+
lines.push(` Target app: ${summary.preview.targetAppUrl}`);
|
|
559
|
+
if (summary.preview.studioUrl) {
|
|
560
|
+
lines.push(` Studio: ${summary.preview.studioUrl}`);
|
|
561
|
+
}
|
|
562
|
+
lines.push(` Note: ${summary.preview.note}`);
|
|
328
563
|
lines.push("");
|
|
329
564
|
|
|
330
565
|
process.stdout.write(`${lines.join("\n")}\n`);
|
|
@@ -350,6 +585,122 @@ function openBrowser(url: string): void {
|
|
|
350
585
|
}
|
|
351
586
|
}
|
|
352
587
|
|
|
588
|
+
export async function ensureGeneratedForDev(workspaceRoot: string): Promise<DevGenerateResult> {
|
|
589
|
+
resetCompileSessions();
|
|
590
|
+
const result = await run({
|
|
591
|
+
workspaceRoot,
|
|
592
|
+
check: false,
|
|
593
|
+
dryRun: false,
|
|
594
|
+
json: false,
|
|
595
|
+
concurrency: 4,
|
|
596
|
+
});
|
|
597
|
+
return {
|
|
598
|
+
ok: result.exitCode === 0,
|
|
599
|
+
changed: result.changed,
|
|
600
|
+
unchanged: result.unchanged,
|
|
601
|
+
diagnostics: [...result.errors, ...result.warnings],
|
|
602
|
+
exitCode: result.exitCode,
|
|
603
|
+
};
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
export function generatedEvidenceFromCycle(cycle: DevConsoleCycle): DevStartupGeneratedEvidence {
|
|
607
|
+
const phase = cycle.phases.find((item) => item.name === "generated");
|
|
608
|
+
const changedFiles = Number(phase?.details?.changed ?? 0);
|
|
609
|
+
const sampleChanged = Array.isArray(phase?.details?.sampleChanged)
|
|
610
|
+
? phase.details.sampleChanged.filter((item): item is string => typeof item === "string")
|
|
611
|
+
: [];
|
|
612
|
+
const hiddenChanged = Number(phase?.details?.hiddenChanged ?? 0);
|
|
613
|
+
return {
|
|
614
|
+
ok: phase?.ok === true,
|
|
615
|
+
state: phase?.ok === true
|
|
616
|
+
? changedFiles > 0 ? "regenerated" : "fresh"
|
|
617
|
+
: "stale-risk",
|
|
618
|
+
changedFiles,
|
|
619
|
+
sampleChanged,
|
|
620
|
+
hiddenChanged,
|
|
621
|
+
message: phase?.message ?? "generated phase did not report a message",
|
|
622
|
+
command: "forge generate",
|
|
623
|
+
checkCommand: "forge generate --check --json",
|
|
624
|
+
};
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
export function generatedEvidenceFromGenerateResult(result: DevGenerateResult): DevStartupGeneratedEvidence {
|
|
628
|
+
return {
|
|
629
|
+
ok: result.ok,
|
|
630
|
+
state: result.ok ? result.changed.length > 0 ? "regenerated" : "fresh" : "stale-risk",
|
|
631
|
+
changedFiles: result.changed.length,
|
|
632
|
+
sampleChanged: result.changed.slice(0, 12),
|
|
633
|
+
hiddenChanged: Math.max(0, result.changed.length - 12),
|
|
634
|
+
message: result.ok
|
|
635
|
+
? result.changed.length > 0
|
|
636
|
+
? `regenerated ${result.changed.length} generated artifacts`
|
|
637
|
+
: "generated artifacts are up to date"
|
|
638
|
+
: "generated artifacts could not be regenerated",
|
|
639
|
+
command: "forge generate",
|
|
640
|
+
checkCommand: "forge generate --check --json",
|
|
641
|
+
};
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
function printDevGenerateFailure(result: DevGenerateResult, json: boolean): void {
|
|
645
|
+
if (json) {
|
|
646
|
+
process.stdout.write(`${JSON.stringify({
|
|
647
|
+
ok: false,
|
|
648
|
+
phase: "generated",
|
|
649
|
+
diagnostics: result.diagnostics,
|
|
650
|
+
exitCode: 1,
|
|
651
|
+
})}\n`);
|
|
652
|
+
return;
|
|
653
|
+
}
|
|
654
|
+
console.error("error: forge dev could not regenerate generated artifacts");
|
|
655
|
+
for (const diagnostic of result.diagnostics.filter((item) => item.severity === "error").slice(0, 5)) {
|
|
656
|
+
console.error(`error ${diagnostic.code}: ${diagnostic.message}`);
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
export function buildDevWatchGenerateFailureEvent(input: {
|
|
661
|
+
changedCount: number;
|
|
662
|
+
changedPaths: string[];
|
|
663
|
+
result: DevGenerateResult;
|
|
664
|
+
}): DevWatchGenerateFailureEvent {
|
|
665
|
+
return {
|
|
666
|
+
schemaVersion: "0.1.0",
|
|
667
|
+
event: "dev.generate_failed",
|
|
668
|
+
ok: false,
|
|
669
|
+
changedFiles: input.changedCount,
|
|
670
|
+
changedPaths: input.changedPaths,
|
|
671
|
+
generated: generatedEvidenceFromGenerateResult(input.result),
|
|
672
|
+
diagnostics: input.result.diagnostics,
|
|
673
|
+
nextActions: ["forge dev --once --json", "forge check --json"],
|
|
674
|
+
};
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
export function buildDevWatchReloadEvent(input: {
|
|
678
|
+
changedCount: number;
|
|
679
|
+
changedPaths: string[];
|
|
680
|
+
generated: DevGenerateResult;
|
|
681
|
+
reload: Awaited<ReturnType<DevServerHandle["reload"]>>;
|
|
682
|
+
cycle: DevConsoleCycle;
|
|
683
|
+
}): DevWatchReloadEvent {
|
|
684
|
+
return {
|
|
685
|
+
schemaVersion: "0.1.0",
|
|
686
|
+
event: "dev.reload",
|
|
687
|
+
ok: input.reload.ok,
|
|
688
|
+
changedFiles: input.changedCount,
|
|
689
|
+
changedPaths: input.changedPaths,
|
|
690
|
+
migrated: input.reload.migrated,
|
|
691
|
+
routes: input.reload.routes,
|
|
692
|
+
runtimeEntries: input.reload.runtimeEntries,
|
|
693
|
+
worker: input.reload.worker,
|
|
694
|
+
diagnostics: input.reload.diagnostics,
|
|
695
|
+
generated: generatedEvidenceFromGenerateResult(input.generated),
|
|
696
|
+
preview: input.cycle.summary.preview,
|
|
697
|
+
agentContext: input.cycle.summary.agentContext,
|
|
698
|
+
nextActions: input.reload.ok
|
|
699
|
+
? input.cycle.summary.agentContext.recommendedCommands
|
|
700
|
+
: ["forge dev --once --json", "forge check --json"],
|
|
701
|
+
};
|
|
702
|
+
}
|
|
703
|
+
|
|
353
704
|
export async function runDevCommand(
|
|
354
705
|
options: DevCommandOptions,
|
|
355
706
|
): Promise<DevCommandResult> {
|
|
@@ -368,22 +719,42 @@ export async function runDevCommand(
|
|
|
368
719
|
|
|
369
720
|
const host = resolveDevHost(options.host);
|
|
370
721
|
const port = resolveDevPort(options.port);
|
|
371
|
-
const
|
|
722
|
+
const requestedWebPort = options.webPort ?? detectDefaultWebPort(workspaceRoot);
|
|
372
723
|
const shouldStartWeb =
|
|
373
724
|
options.webOnly === true ||
|
|
374
725
|
(options.withWeb !== false && !options.apiOnly && hasWebApp(workspaceRoot));
|
|
726
|
+
const webPortSelection = shouldStartWeb
|
|
727
|
+
? await resolveAvailableWebPort({ host, preferredPort: requestedWebPort })
|
|
728
|
+
: { port: requestedWebPort, autoPortSelected: false };
|
|
729
|
+
const webPort = webPortSelection.port;
|
|
375
730
|
const webUrl = shouldStartWeb ? `http://${host}:${webPort}` : undefined;
|
|
731
|
+
let startupGenerated: DevStartupGeneratedEvidence | undefined;
|
|
376
732
|
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
733
|
+
if (!options.skipStartupConsole) {
|
|
734
|
+
const startupCycle = await runDevConsoleCycle({
|
|
735
|
+
workspaceRoot,
|
|
736
|
+
mode: "startup",
|
|
737
|
+
strictSecrets: false,
|
|
738
|
+
includeImpact: true,
|
|
739
|
+
apiUrl: `http://${host}:${port}`,
|
|
740
|
+
...(webUrl ? { webUrl } : {}),
|
|
741
|
+
});
|
|
742
|
+
if (options.json) {
|
|
743
|
+
process.stdout.write(formatDevConsoleJson(startupCycle));
|
|
744
|
+
} else {
|
|
745
|
+
process.stdout.write(formatDevConsoleHuman(startupCycle));
|
|
746
|
+
}
|
|
747
|
+
startupGenerated = generatedEvidenceFromCycle(startupCycle);
|
|
748
|
+
if (startupCycle.exitCode !== 0) {
|
|
749
|
+
return { exitCode: 1 };
|
|
750
|
+
}
|
|
385
751
|
} else {
|
|
386
|
-
|
|
752
|
+
const generated = await ensureGeneratedForDev(workspaceRoot);
|
|
753
|
+
startupGenerated = generatedEvidenceFromGenerateResult(generated);
|
|
754
|
+
if (!generated.ok) {
|
|
755
|
+
printDevGenerateFailure(generated, options.json);
|
|
756
|
+
return { exitCode: 1 };
|
|
757
|
+
}
|
|
387
758
|
}
|
|
388
759
|
|
|
389
760
|
if (options.webOnly) {
|
|
@@ -392,6 +763,8 @@ export async function runDevCommand(
|
|
|
392
763
|
workspaceRoot,
|
|
393
764
|
host,
|
|
394
765
|
port: webPort,
|
|
766
|
+
requestedPort: webPortSelection.requestedPort,
|
|
767
|
+
autoPortSelected: webPortSelection.autoPortSelected,
|
|
395
768
|
apiUrl,
|
|
396
769
|
json: options.json,
|
|
397
770
|
});
|
|
@@ -413,6 +786,8 @@ export async function runDevCommand(
|
|
|
413
786
|
web: {
|
|
414
787
|
url: webHandle.url,
|
|
415
788
|
port: webHandle.port,
|
|
789
|
+
...(webHandle.requestedPort !== undefined ? { requestedPort: webHandle.requestedPort } : {}),
|
|
790
|
+
autoPortSelected: webHandle.autoPortSelected,
|
|
416
791
|
command: webHandle.command,
|
|
417
792
|
},
|
|
418
793
|
api: {
|
|
@@ -440,6 +815,8 @@ export async function runDevCommand(
|
|
|
440
815
|
return { web: webHandle, exitCode: 0 };
|
|
441
816
|
}
|
|
442
817
|
|
|
818
|
+
const deltaRecorder = await createAmbientDeltaRecorder(workspaceRoot, "forge-dev", "forge dev");
|
|
819
|
+
|
|
443
820
|
let handle: DevServerHandle;
|
|
444
821
|
try {
|
|
445
822
|
handle = await startDevServer({
|
|
@@ -457,13 +834,38 @@ export async function runDevCommand(
|
|
|
457
834
|
mode: options.mode,
|
|
458
835
|
allowDevAuth: options.allowDevAuth,
|
|
459
836
|
webUrl,
|
|
837
|
+
deltaRecorder,
|
|
460
838
|
});
|
|
461
839
|
} catch (error) {
|
|
462
|
-
|
|
840
|
+
await deltaRecorder.close("forge dev failed to start");
|
|
841
|
+
const rawMessage =
|
|
463
842
|
error instanceof Error ? error.message : "failed to start dev server";
|
|
843
|
+
const lowerMessage = rawMessage.toLowerCase();
|
|
844
|
+
const busy =
|
|
845
|
+
lowerMessage.includes("eaddrinuse") ||
|
|
846
|
+
lowerMessage.includes("address already in use") ||
|
|
847
|
+
/port\s+\d+\s+.*in use/i.test(rawMessage);
|
|
848
|
+
const message = busy
|
|
849
|
+
? `${rawMessage}. Port ${port} appears busy; stop the existing process or rerun with --port 0 / --port <free-port>.`
|
|
850
|
+
: rawMessage;
|
|
464
851
|
if (options.json) {
|
|
465
852
|
process.stdout.write(
|
|
466
|
-
`${JSON.stringify({
|
|
853
|
+
`${JSON.stringify({
|
|
854
|
+
ok: false,
|
|
855
|
+
error: message,
|
|
856
|
+
failureKind: busy ? "port_busy" : "dev_start_failed",
|
|
857
|
+
busy: busy
|
|
858
|
+
? {
|
|
859
|
+
port,
|
|
860
|
+
host,
|
|
861
|
+
suggestedCommands: [
|
|
862
|
+
`forge dev --port 0${options.webPort ? ` --web-port ${options.webPort}` : ""} --json`,
|
|
863
|
+
"forge doctor windows --json",
|
|
864
|
+
],
|
|
865
|
+
}
|
|
866
|
+
: undefined,
|
|
867
|
+
exitCode: 1,
|
|
868
|
+
})}\n`,
|
|
467
869
|
);
|
|
468
870
|
} else {
|
|
469
871
|
console.error(`error: ${message}`);
|
|
@@ -477,6 +879,8 @@ export async function runDevCommand(
|
|
|
477
879
|
workspaceRoot,
|
|
478
880
|
host,
|
|
479
881
|
port: webPort,
|
|
882
|
+
requestedPort: webPortSelection.requestedPort,
|
|
883
|
+
autoPortSelected: webPortSelection.autoPortSelected,
|
|
480
884
|
apiUrl: handle.url,
|
|
481
885
|
json: options.json,
|
|
482
886
|
});
|
|
@@ -486,6 +890,7 @@ export async function runDevCommand(
|
|
|
486
890
|
handle,
|
|
487
891
|
web: webHandle,
|
|
488
892
|
watch: options.watch,
|
|
893
|
+
generated: startupGenerated,
|
|
489
894
|
});
|
|
490
895
|
if (options.json) {
|
|
491
896
|
printStartupJson(startupSummary);
|
|
@@ -503,8 +908,17 @@ export async function runDevCommand(
|
|
|
503
908
|
outboxWorkerHandle = handle.outboxWorker;
|
|
504
909
|
}
|
|
505
910
|
|
|
911
|
+
const devConsoleUrlOptions = (): { apiUrl: string; webUrl?: string } => ({
|
|
912
|
+
apiUrl: handle.url,
|
|
913
|
+
...(webHandle?.url ? { webUrl: webHandle.url } : {}),
|
|
914
|
+
});
|
|
915
|
+
|
|
506
916
|
if (options.watch) {
|
|
507
|
-
watchHandle = startDevWatch(workspaceRoot, async (changedCount) => {
|
|
917
|
+
watchHandle = startDevWatch(workspaceRoot, async (changedCount, changedPaths) => {
|
|
918
|
+
for (const changedPath of changedPaths) {
|
|
919
|
+
await deltaRecorder.recordFileChanged(changedPath);
|
|
920
|
+
}
|
|
921
|
+
resetCompileSessions();
|
|
508
922
|
const result = await run({
|
|
509
923
|
workspaceRoot,
|
|
510
924
|
check: false,
|
|
@@ -514,39 +928,89 @@ export async function runDevCommand(
|
|
|
514
928
|
});
|
|
515
929
|
|
|
516
930
|
if (result.exitCode === 0) {
|
|
931
|
+
const reload = await handle.reload("watch");
|
|
932
|
+
const cycle = await runDevConsoleCycle({
|
|
933
|
+
workspaceRoot,
|
|
934
|
+
mode: "watch",
|
|
935
|
+
strictSecrets: false,
|
|
936
|
+
includeImpact: true,
|
|
937
|
+
...devConsoleUrlOptions(),
|
|
938
|
+
});
|
|
517
939
|
if (!options.json) {
|
|
518
940
|
process.stdout.write(
|
|
519
|
-
`[forge dev] regenerated (${changedCount} changed files)
|
|
941
|
+
`[forge dev] regenerated (${changedCount} changed files), ` +
|
|
942
|
+
`migrations ${reload.migrated ? "applied" : "skipped"}, ` +
|
|
943
|
+
`runtime ${reload.ok ? "reloaded" : "reload failed"}\n`,
|
|
520
944
|
);
|
|
945
|
+
} else {
|
|
946
|
+
process.stdout.write(`${JSON.stringify(buildDevWatchReloadEvent({
|
|
947
|
+
changedCount,
|
|
948
|
+
changedPaths,
|
|
949
|
+
generated: {
|
|
950
|
+
ok: true,
|
|
951
|
+
changed: result.changed,
|
|
952
|
+
unchanged: result.unchanged,
|
|
953
|
+
diagnostics: [...result.errors, ...result.warnings],
|
|
954
|
+
exitCode: 0,
|
|
955
|
+
},
|
|
956
|
+
reload,
|
|
957
|
+
cycle,
|
|
958
|
+
}))}\n`);
|
|
521
959
|
}
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
960
|
+
if (!reload.ok && !options.json) {
|
|
961
|
+
for (const diagnostic of reload.diagnostics.filter((item) => item.severity === "error")) {
|
|
962
|
+
console.error(`error ${diagnostic.code}: ${diagnostic.message}`);
|
|
963
|
+
}
|
|
964
|
+
}
|
|
965
|
+
if (options.json) {
|
|
966
|
+
process.stdout.write(formatDevConsoleJson(cycle));
|
|
967
|
+
} else {
|
|
968
|
+
process.stdout.write(formatDevConsoleHuman(cycle));
|
|
525
969
|
}
|
|
526
|
-
}
|
|
527
|
-
|
|
528
|
-
const cycle = await runDevConsoleCycle({
|
|
529
|
-
workspaceRoot,
|
|
530
|
-
mode: "watch",
|
|
531
|
-
strictSecrets: false,
|
|
532
|
-
includeImpact: true,
|
|
533
|
-
});
|
|
534
|
-
if (options.json) {
|
|
535
|
-
process.stdout.write(formatDevConsoleJson(cycle));
|
|
536
970
|
} else {
|
|
537
|
-
|
|
971
|
+
if (options.json) {
|
|
972
|
+
process.stdout.write(`${JSON.stringify(buildDevWatchGenerateFailureEvent({
|
|
973
|
+
changedCount,
|
|
974
|
+
changedPaths,
|
|
975
|
+
result: {
|
|
976
|
+
ok: false,
|
|
977
|
+
changed: result.changed,
|
|
978
|
+
unchanged: result.unchanged,
|
|
979
|
+
diagnostics: [...result.errors, ...result.warnings],
|
|
980
|
+
exitCode: 1,
|
|
981
|
+
},
|
|
982
|
+
}))}\n`);
|
|
983
|
+
} else {
|
|
984
|
+
console.error(`[forge dev] regeneration failed after ${changedCount} changed files; runtime was not reloaded`);
|
|
985
|
+
for (const diagnostic of [...result.errors, ...result.warnings]) {
|
|
986
|
+
console.error(`${diagnostic.severity} ${diagnostic.code}: ${diagnostic.message}`);
|
|
987
|
+
}
|
|
988
|
+
}
|
|
989
|
+
const cycle = await runDevConsoleCycle({
|
|
990
|
+
workspaceRoot,
|
|
991
|
+
mode: "watch",
|
|
992
|
+
strictSecrets: false,
|
|
993
|
+
includeImpact: true,
|
|
994
|
+
...devConsoleUrlOptions(),
|
|
995
|
+
});
|
|
996
|
+
if (options.json) {
|
|
997
|
+
process.stdout.write(formatDevConsoleJson(cycle));
|
|
998
|
+
} else {
|
|
999
|
+
process.stdout.write(formatDevConsoleHuman(cycle));
|
|
1000
|
+
}
|
|
538
1001
|
}
|
|
539
1002
|
});
|
|
540
1003
|
}
|
|
541
1004
|
|
|
542
1005
|
await new Promise<void>((resolve) => {
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
1006
|
+
const shutdown = () => {
|
|
1007
|
+
watchHandle?.stop();
|
|
1008
|
+
outboxWorkerHandle?.stop();
|
|
1009
|
+
webHandle?.stop();
|
|
1010
|
+
handle.stop();
|
|
1011
|
+
void deltaRecorder.close("forge dev stopped");
|
|
1012
|
+
resolve();
|
|
1013
|
+
};
|
|
550
1014
|
|
|
551
1015
|
process.once("SIGINT", shutdown);
|
|
552
1016
|
process.once("SIGTERM", shutdown);
|