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
|
@@ -351,6 +351,166 @@ export default function ${pascal}Page() {
|
|
|
351
351
|
`;
|
|
352
352
|
}
|
|
353
353
|
|
|
354
|
+
export function renderAiAgentFile(name: string): string {
|
|
355
|
+
const camel = camelCase(name);
|
|
356
|
+
const pascal = pascalCase(name);
|
|
357
|
+
return `import { agent, aiTool } from "forge/server";
|
|
358
|
+
import { z } from "zod";
|
|
359
|
+
|
|
360
|
+
export const ${camel}ProjectContext = aiTool({
|
|
361
|
+
description: "Return concise project context for the ${pascal} agent.",
|
|
362
|
+
inputSchema: z.object({
|
|
363
|
+
topic: z.string().optional(),
|
|
364
|
+
}),
|
|
365
|
+
outputSchema: z.object({
|
|
366
|
+
context: z.string(),
|
|
367
|
+
}),
|
|
368
|
+
risk: "read",
|
|
369
|
+
strict: true,
|
|
370
|
+
needsApproval: false,
|
|
371
|
+
handler: async (_ctx, input) => ({
|
|
372
|
+
context: \`ForgeOS project context for \${input.topic ?? "the current request"}.\`,
|
|
373
|
+
}),
|
|
374
|
+
});
|
|
375
|
+
|
|
376
|
+
export const ${camel}Agent = agent({
|
|
377
|
+
provider: "gateway",
|
|
378
|
+
model: "openai/gpt-5.4",
|
|
379
|
+
instructions: "You are a ForgeOS app agent. Use Forge tools before answering when runtime data is needed.",
|
|
380
|
+
tools: { ${camel}ProjectContext },
|
|
381
|
+
stopWhen: { kind: "stepCount", maxSteps: 8 },
|
|
382
|
+
});
|
|
383
|
+
`;
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
export function renderAiChatComponent(name: string): string {
|
|
387
|
+
const pascal = pascalCase(name);
|
|
388
|
+
return `"use client";
|
|
389
|
+
|
|
390
|
+
import { DefaultChatTransport } from "ai";
|
|
391
|
+
import { useChat } from "@ai-sdk/react";
|
|
392
|
+
import { FormEvent, useMemo, useState } from "react";
|
|
393
|
+
import { forgeUrl } from "../lib/forge";
|
|
394
|
+
|
|
395
|
+
export function ${pascal}AiChat() {
|
|
396
|
+
const [input, setInput] = useState("");
|
|
397
|
+
const transport = useMemo(
|
|
398
|
+
() =>
|
|
399
|
+
new DefaultChatTransport({
|
|
400
|
+
api: \`\${forgeUrl}/ai/agents/chat\`,
|
|
401
|
+
headers: {
|
|
402
|
+
"x-forge-user-id": "dev-user",
|
|
403
|
+
"x-forge-tenant-id": "dev-tenant",
|
|
404
|
+
"x-forge-role": "owner",
|
|
405
|
+
},
|
|
406
|
+
body: {
|
|
407
|
+
agent: "${camelCase(name)}Agent",
|
|
408
|
+
provider: "gateway",
|
|
409
|
+
model: "openai/gpt-5.4",
|
|
410
|
+
instructions: "Answer as a ForgeOS app agent. Use available Forge tools when useful.",
|
|
411
|
+
maxSteps: 8,
|
|
412
|
+
},
|
|
413
|
+
}),
|
|
414
|
+
[],
|
|
415
|
+
);
|
|
416
|
+
const { messages, sendMessage, status, error, addToolApprovalResponse } = useChat({
|
|
417
|
+
transport,
|
|
418
|
+
});
|
|
419
|
+
const busy = status === "submitted" || status === "streaming";
|
|
420
|
+
|
|
421
|
+
async function submit(event: FormEvent<HTMLFormElement>) {
|
|
422
|
+
event.preventDefault();
|
|
423
|
+
const prompt = input.trim();
|
|
424
|
+
if (!prompt || busy) return;
|
|
425
|
+
setInput("");
|
|
426
|
+
sendMessage({ text: prompt });
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
return (
|
|
430
|
+
<section>
|
|
431
|
+
<div>
|
|
432
|
+
{messages.map((message) => (
|
|
433
|
+
<article key={message.id}>
|
|
434
|
+
<strong>{message.role}</strong>
|
|
435
|
+
{message.parts.map((part, index) => {
|
|
436
|
+
if (part.type === "text") {
|
|
437
|
+
return <p key={index}>{part.text}</p>;
|
|
438
|
+
}
|
|
439
|
+
if (part.type.startsWith("tool-")) {
|
|
440
|
+
const toolPart = part as typeof part & {
|
|
441
|
+
input?: unknown;
|
|
442
|
+
output?: unknown;
|
|
443
|
+
approval?: { id: string; state: string };
|
|
444
|
+
};
|
|
445
|
+
return (
|
|
446
|
+
<div key={index}>
|
|
447
|
+
<code>{part.type.replace(/^tool-/, "")}</code>
|
|
448
|
+
{toolPart.approval?.state === "approval-requested" ? (
|
|
449
|
+
<span>
|
|
450
|
+
<button
|
|
451
|
+
type="button"
|
|
452
|
+
onClick={() =>
|
|
453
|
+
addToolApprovalResponse({
|
|
454
|
+
id: toolPart.approval!.id,
|
|
455
|
+
approved: true,
|
|
456
|
+
})
|
|
457
|
+
}
|
|
458
|
+
>
|
|
459
|
+
Approve
|
|
460
|
+
</button>
|
|
461
|
+
<button
|
|
462
|
+
type="button"
|
|
463
|
+
onClick={() =>
|
|
464
|
+
addToolApprovalResponse({
|
|
465
|
+
id: toolPart.approval!.id,
|
|
466
|
+
approved: false,
|
|
467
|
+
})
|
|
468
|
+
}
|
|
469
|
+
>
|
|
470
|
+
Deny
|
|
471
|
+
</button>
|
|
472
|
+
</span>
|
|
473
|
+
) : null}
|
|
474
|
+
</div>
|
|
475
|
+
);
|
|
476
|
+
}
|
|
477
|
+
return null;
|
|
478
|
+
})}
|
|
479
|
+
</article>
|
|
480
|
+
))}
|
|
481
|
+
</div>
|
|
482
|
+
<form onSubmit={submit}>
|
|
483
|
+
<input
|
|
484
|
+
value={input}
|
|
485
|
+
onChange={(event) => setInput(event.currentTarget.value)}
|
|
486
|
+
placeholder="Ask the Forge agent"
|
|
487
|
+
/>
|
|
488
|
+
<button type="submit" disabled={busy}>{busy ? "Running" : "Send"}</button>
|
|
489
|
+
</form>
|
|
490
|
+
{error ? <p>{error.message}</p> : null}
|
|
491
|
+
</section>
|
|
492
|
+
);
|
|
493
|
+
}
|
|
494
|
+
`;
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
export function renderAiChatPage(name: string): string {
|
|
498
|
+
const pascal = pascalCase(name);
|
|
499
|
+
return `"use client";
|
|
500
|
+
|
|
501
|
+
import { ${pascal}AiChat } from "../../components/${pascal}AiChat";
|
|
502
|
+
|
|
503
|
+
export default function ${pascal}AiPage() {
|
|
504
|
+
return (
|
|
505
|
+
<main>
|
|
506
|
+
<h1>${titleCase(name)} AI</h1>
|
|
507
|
+
<${pascal}AiChat />
|
|
508
|
+
</main>
|
|
509
|
+
);
|
|
510
|
+
}
|
|
511
|
+
`;
|
|
512
|
+
}
|
|
513
|
+
|
|
354
514
|
export function renderWebBridge(): string {
|
|
355
515
|
return `export const forgeUrl =
|
|
356
516
|
import.meta.env.VITE_FORGE_URL ?? "http://127.0.0.1:3765";
|
|
@@ -476,8 +636,189 @@ export function renderVitePackage(appName: string): string {
|
|
|
476
636
|
"typecheck": "tsc --noEmit"
|
|
477
637
|
},
|
|
478
638
|
"dependencies": {
|
|
479
|
-
"@
|
|
480
|
-
"
|
|
639
|
+
"@ai-sdk/react": "^3.0.0",
|
|
640
|
+
"@vitejs/plugin-react": "^6.0.2",
|
|
641
|
+
"ai": "^6.0.0",
|
|
642
|
+
"vite": "^8.0.16",
|
|
643
|
+
"react": "^19.0.0",
|
|
644
|
+
"react-dom": "^19.0.0"
|
|
645
|
+
},
|
|
646
|
+
"devDependencies": {
|
|
647
|
+
"@types/react": "^19.0.0",
|
|
648
|
+
"@types/react-dom": "^19.0.0",
|
|
649
|
+
"typescript": "^5.7.3"
|
|
650
|
+
}
|
|
651
|
+
}
|
|
652
|
+
`;
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
export function renderNuxtPackage(appName: string): string {
|
|
656
|
+
return `{
|
|
657
|
+
"name": "${kebabCase(appName)}-web",
|
|
658
|
+
"private": true,
|
|
659
|
+
"type": "module",
|
|
660
|
+
"scripts": {
|
|
661
|
+
"dev": "nuxt dev --host 127.0.0.1",
|
|
662
|
+
"build": "nuxt build",
|
|
663
|
+
"typecheck": "nuxt typecheck"
|
|
664
|
+
},
|
|
665
|
+
"dependencies": {
|
|
666
|
+
"nuxt": "^4.0.0",
|
|
667
|
+
"vue": "^3.5.38"
|
|
668
|
+
},
|
|
669
|
+
"devDependencies": {
|
|
670
|
+
"typescript": "^5.7.3"
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
`;
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
export function renderNuxtConfig(): string {
|
|
677
|
+
return `export default defineNuxtConfig({
|
|
678
|
+
compatibilityDate: "2026-06-18",
|
|
679
|
+
runtimeConfig: {
|
|
680
|
+
public: {
|
|
681
|
+
forgeUrl: process.env.NUXT_PUBLIC_FORGE_URL ?? "http://127.0.0.1:3765",
|
|
682
|
+
},
|
|
683
|
+
},
|
|
684
|
+
typescript: {
|
|
685
|
+
strict: true,
|
|
686
|
+
},
|
|
687
|
+
});
|
|
688
|
+
`;
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
export function renderNuxtTsconfig(): string {
|
|
692
|
+
return `{
|
|
693
|
+
"extends": "./.nuxt/tsconfig.json"
|
|
694
|
+
}
|
|
695
|
+
`;
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
export function renderNuxtForgeComposable(): string {
|
|
699
|
+
return `export const forgeUrl = "http://127.0.0.1:3765";
|
|
700
|
+
|
|
701
|
+
export { api } from "../../src/forge/_generated/api";
|
|
702
|
+
export { createForgeClient, ForgeError } from "../../src/forge/_generated/client";
|
|
703
|
+
export {
|
|
704
|
+
ForgeVuePlugin,
|
|
705
|
+
provideForge,
|
|
706
|
+
useForgeAuth,
|
|
707
|
+
useForgeClient,
|
|
708
|
+
useForgeCommand,
|
|
709
|
+
useForgeLiveQuery,
|
|
710
|
+
useForgeQuery,
|
|
711
|
+
} from "../../src/forge/_generated/vue";
|
|
712
|
+
`;
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
export function renderNuxtForgePlugin(): string {
|
|
716
|
+
return `import { ForgeVuePlugin } from "../composables/forge";
|
|
717
|
+
|
|
718
|
+
export default defineNuxtPlugin((nuxtApp) => {
|
|
719
|
+
const config = useRuntimeConfig();
|
|
720
|
+
|
|
721
|
+
nuxtApp.vueApp.use(ForgeVuePlugin, {
|
|
722
|
+
url: String(config.public.forgeUrl),
|
|
723
|
+
devAuth: true,
|
|
724
|
+
});
|
|
725
|
+
});
|
|
726
|
+
`;
|
|
727
|
+
}
|
|
728
|
+
|
|
729
|
+
export function renderNuxtApp(): string {
|
|
730
|
+
return `<script setup lang="ts">
|
|
731
|
+
import ForgeStatus from "./components/ForgeStatus.vue";
|
|
732
|
+
</script>
|
|
733
|
+
|
|
734
|
+
<template>
|
|
735
|
+
<main class="shell">
|
|
736
|
+
<p class="eyebrow">ForgeOS Nuxt app</p>
|
|
737
|
+
<h1>Full-stack loop ready</h1>
|
|
738
|
+
<ForgeStatus />
|
|
739
|
+
</main>
|
|
740
|
+
</template>
|
|
741
|
+
|
|
742
|
+
<style scoped>
|
|
743
|
+
.shell {
|
|
744
|
+
width: min(760px, calc(100vw - 32px));
|
|
745
|
+
margin: 0 auto;
|
|
746
|
+
padding: 48px 0;
|
|
747
|
+
}
|
|
748
|
+
|
|
749
|
+
.eyebrow {
|
|
750
|
+
color: #58655f;
|
|
751
|
+
font-size: 0.82rem;
|
|
752
|
+
font-weight: 800;
|
|
753
|
+
text-transform: uppercase;
|
|
754
|
+
}
|
|
755
|
+
|
|
756
|
+
h1 {
|
|
757
|
+
margin: 0 0 12px;
|
|
758
|
+
color: #17211d;
|
|
759
|
+
font-size: 2.2rem;
|
|
760
|
+
}
|
|
761
|
+
</style>
|
|
762
|
+
`;
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
export function renderNuxtStatusComponent(): string {
|
|
766
|
+
return `<script setup lang="ts">
|
|
767
|
+
import { computed } from "vue";
|
|
768
|
+
import { useForgeAuth } from "../composables/forge";
|
|
769
|
+
|
|
770
|
+
const auth = useForgeAuth();
|
|
771
|
+
const tenantLabel = computed(() => auth?.tenantId ?? "dev-tenant");
|
|
772
|
+
const roleLabel = computed(() => auth?.role ?? "owner");
|
|
773
|
+
</script>
|
|
774
|
+
|
|
775
|
+
<template>
|
|
776
|
+
<section class="status-panel">
|
|
777
|
+
<span class="status-dot" aria-hidden="true" />
|
|
778
|
+
<p>
|
|
779
|
+
Connected as <strong>{{ roleLabel }}</strong> on
|
|
780
|
+
<strong>{{ tenantLabel }}</strong>.
|
|
781
|
+
</p>
|
|
782
|
+
</section>
|
|
783
|
+
</template>
|
|
784
|
+
|
|
785
|
+
<style scoped>
|
|
786
|
+
.status-panel {
|
|
787
|
+
display: flex;
|
|
788
|
+
align-items: center;
|
|
789
|
+
gap: 10px;
|
|
790
|
+
margin-top: 24px;
|
|
791
|
+
color: #26332d;
|
|
792
|
+
}
|
|
793
|
+
|
|
794
|
+
.status-dot {
|
|
795
|
+
width: 10px;
|
|
796
|
+
height: 10px;
|
|
797
|
+
border-radius: 999px;
|
|
798
|
+
background: #1f9d55;
|
|
799
|
+
}
|
|
800
|
+
|
|
801
|
+
p {
|
|
802
|
+
margin: 0;
|
|
803
|
+
}
|
|
804
|
+
</style>
|
|
805
|
+
`;
|
|
806
|
+
}
|
|
807
|
+
|
|
808
|
+
export function renderNextAiPackage(appName: string): string {
|
|
809
|
+
return `{
|
|
810
|
+
"name": "${kebabCase(appName)}-web",
|
|
811
|
+
"private": true,
|
|
812
|
+
"type": "module",
|
|
813
|
+
"scripts": {
|
|
814
|
+
"dev": "next dev --hostname 127.0.0.1",
|
|
815
|
+
"build": "next build",
|
|
816
|
+
"typecheck": "tsc --noEmit"
|
|
817
|
+
},
|
|
818
|
+
"dependencies": {
|
|
819
|
+
"@ai-sdk/react": "^3.0.0",
|
|
820
|
+
"ai": "^6.0.0",
|
|
821
|
+
"next": "^15.5.9",
|
|
481
822
|
"react": "^19.0.0",
|
|
482
823
|
"react-dom": "^19.0.0"
|
|
483
824
|
},
|
package/src/forge/make/types.ts
CHANGED
|
@@ -14,6 +14,7 @@ export type MakePrimitive =
|
|
|
14
14
|
| "component"
|
|
15
15
|
| "page"
|
|
16
16
|
| "ui"
|
|
17
|
+
| "ai-chat"
|
|
17
18
|
| "resource"
|
|
18
19
|
| "apply"
|
|
19
20
|
| "rollback";
|
|
@@ -60,6 +61,7 @@ export interface MakeIntent {
|
|
|
60
61
|
trigger?: string;
|
|
61
62
|
component?: string;
|
|
62
63
|
route?: string;
|
|
64
|
+
framework?: "vite" | "next" | "nuxt";
|
|
63
65
|
withAi: boolean;
|
|
64
66
|
withCreateForm: boolean;
|
|
65
67
|
}
|
|
@@ -129,7 +131,7 @@ export interface MakeCommandOptions {
|
|
|
129
131
|
event?: string;
|
|
130
132
|
trigger?: string;
|
|
131
133
|
component?: string;
|
|
132
|
-
framework?: "vite" | "next";
|
|
134
|
+
framework?: "vite" | "next" | "nuxt";
|
|
133
135
|
withAi: boolean;
|
|
134
136
|
withCrud: boolean;
|
|
135
137
|
withLiveQuery: boolean;
|
|
@@ -228,7 +228,7 @@ export const repairRules: RepairRule[] = [
|
|
|
228
228
|
failureKind: "secrets",
|
|
229
229
|
code: "FORGE_SECRET_DIRECT_PROCESS_ENV",
|
|
230
230
|
summary: `Secret/config usage is unsafe or missing for ${secret}.`,
|
|
231
|
-
likelyCause: "Code reads process.env
|
|
231
|
+
likelyCause: "Code reads secret/config values through process.env in Forge runtime code, accesses secrets in a forbidden runtime, or the environment lacks a required secret.",
|
|
232
232
|
confidence: "high",
|
|
233
233
|
suggestedRepairs: [
|
|
234
234
|
{
|
|
@@ -466,7 +466,7 @@ export function explainDiagnostic(code: string): string {
|
|
|
466
466
|
FORGE_GUARD_VIOLATION: "A package or capability is used in a runtime context where it is forbidden. Move side effects to actions/workflows.",
|
|
467
467
|
FORGE_POLICY_UNKNOWN: "A runtime entry references a missing policy. Create or correct the policy, then simulate expected roles.",
|
|
468
468
|
FORGE_POLICY_DENIED: "The caller auth context does not satisfy the policy. Fix test auth or intentionally update policy roles.",
|
|
469
|
-
FORGE_SECRET_DIRECT_PROCESS_ENV: "Code reads process.env
|
|
469
|
+
FORGE_SECRET_DIRECT_PROCESS_ENV: "Code reads secret/config values through process.env in Forge runtime code. Use ctx.secrets/ctx.config in allowed runtime contexts.",
|
|
470
470
|
FORGE_AI_FORBIDDEN_CONTEXT: "AI is being used in a deterministic context. Move AI calls to action/workflow/server runtime.",
|
|
471
471
|
FORGE_WORKFLOW_STEP_FAILED: "A workflow step failed. Inspect the workflow run and trace before retrying.",
|
|
472
472
|
FORGE_OUTBOX_PROCESS_FAILED: "An outbox delivery failed. Inspect the subscribed action and retry after fixing the cause.",
|
|
@@ -6,6 +6,8 @@ import { serializeCanonical } from "../compiler/primitives/serialize.ts";
|
|
|
6
6
|
import { stripDeterministicHeader } from "../compiler/primitives/header.ts";
|
|
7
7
|
import { analyzeImpact, buildImpactTestPlan, detectChangedFiles } from "../impact/index.ts";
|
|
8
8
|
import type { ImpactCommandOptions, ImpactSource } from "../impact/types.ts";
|
|
9
|
+
import { buildDiffPlanFromChangeSummary, categorizeFiles } from "../workspace/change-summary.ts";
|
|
10
|
+
import type { CategorizedFileSummary, ChangeType } from "../workspace/change-summary.ts";
|
|
9
11
|
import type {
|
|
10
12
|
ReviewChanged,
|
|
11
13
|
ReviewCommandOptions,
|
|
@@ -14,6 +16,8 @@ import type {
|
|
|
14
16
|
ReviewFinding,
|
|
15
17
|
ReviewFindingCategory,
|
|
16
18
|
ReviewFindingSeverity,
|
|
19
|
+
ReviewFocus,
|
|
20
|
+
ReviewDiffPlan,
|
|
17
21
|
ReviewReport,
|
|
18
22
|
ReviewResult,
|
|
19
23
|
ReviewRisk,
|
|
@@ -41,6 +45,21 @@ const ALL_CATEGORIES: ReviewFindingCategory[] = [
|
|
|
41
45
|
"agent",
|
|
42
46
|
];
|
|
43
47
|
|
|
48
|
+
const SYSTEM_ENV_NAMES = new Set([
|
|
49
|
+
"CI",
|
|
50
|
+
"HOME",
|
|
51
|
+
"PATH",
|
|
52
|
+
"PWD",
|
|
53
|
+
"SHELL",
|
|
54
|
+
"TEMP",
|
|
55
|
+
"TMP",
|
|
56
|
+
"USER",
|
|
57
|
+
"USERNAME",
|
|
58
|
+
"USERPROFILE",
|
|
59
|
+
]);
|
|
60
|
+
|
|
61
|
+
const SECRET_ENV_PATTERN = /(^|_)(API_KEY|AUTH_TOKEN|CLIENT_SECRET|CREDENTIALS|JWT_SECRET|PASSWORD|PRIVATE_KEY|SECRET|SECRET_KEY|TOKEN|WEBHOOK_SECRET)$/;
|
|
62
|
+
|
|
44
63
|
const RULE_DOCS: ReviewRuleDoc[] = [
|
|
45
64
|
{
|
|
46
65
|
id: "runtime-command-forbidden-import",
|
|
@@ -124,6 +143,32 @@ function changedFromFiles(files: string[]): ReviewChanged {
|
|
|
124
143
|
};
|
|
125
144
|
}
|
|
126
145
|
|
|
146
|
+
function buildReviewFocus(changeSummary: CategorizedFileSummary): ReviewFocus {
|
|
147
|
+
const authoredOrder = ([
|
|
148
|
+
"source",
|
|
149
|
+
"tests",
|
|
150
|
+
"docs",
|
|
151
|
+
"config",
|
|
152
|
+
"operational",
|
|
153
|
+
"assets",
|
|
154
|
+
"other",
|
|
155
|
+
] satisfies ChangeType[])
|
|
156
|
+
.filter((type) => changeSummary.byType[type].count > 0);
|
|
157
|
+
const suggestedOrder: ChangeType[] = [...authoredOrder];
|
|
158
|
+
if (changeSummary.byType.generated.count > 0) {
|
|
159
|
+
suggestedOrder.push("generated");
|
|
160
|
+
}
|
|
161
|
+
return {
|
|
162
|
+
first: "authoredChanges",
|
|
163
|
+
then: "derivedArtifacts",
|
|
164
|
+
generatedIsDerived: true,
|
|
165
|
+
suggestedOrder,
|
|
166
|
+
summary: changeSummary.byType.generated.count > 0
|
|
167
|
+
? "Review authored changes first; inspect generated artifacts after the source cause is understood."
|
|
168
|
+
: "Review authored changes directly; no generated artifacts changed.",
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
|
|
127
172
|
function loadContext(options: ReviewCommandOptions): ReviewContext {
|
|
128
173
|
const source = sourceFromOptions(options);
|
|
129
174
|
const impactSource = impactSourceFromReview(source);
|
|
@@ -190,9 +235,22 @@ function isTestFile(file: string): boolean {
|
|
|
190
235
|
return /\.(test|spec)\.(ts|tsx|js|jsx)$/.test(file) || normalize(file).startsWith("tests/");
|
|
191
236
|
}
|
|
192
237
|
|
|
238
|
+
function isDocumentationFile(file: string): boolean {
|
|
239
|
+
const normalized = normalize(file);
|
|
240
|
+
return normalized.startsWith("docs/") ||
|
|
241
|
+
normalized.startsWith("marketing/") ||
|
|
242
|
+
normalized.endsWith(".md") ||
|
|
243
|
+
normalized.endsWith(".mdx");
|
|
244
|
+
}
|
|
245
|
+
|
|
193
246
|
function isForgeToolingFile(file: string): boolean {
|
|
194
247
|
const normalized = normalize(file);
|
|
195
|
-
return normalized.startsWith("src/forge/cli/") ||
|
|
248
|
+
return normalized.startsWith("src/forge/cli/") ||
|
|
249
|
+
normalized.startsWith("src/forge/review/") ||
|
|
250
|
+
normalized.startsWith("src/forge/dev/") ||
|
|
251
|
+
normalized.startsWith("src/forge/dev-console/") ||
|
|
252
|
+
normalized.startsWith("src/forge/compiler/package-manager/") ||
|
|
253
|
+
normalized.startsWith("src/forge/compiler/integration/");
|
|
196
254
|
}
|
|
197
255
|
|
|
198
256
|
function includesCategory(options: ReviewCommandOptions, category: ReviewFindingCategory): boolean {
|
|
@@ -200,20 +258,47 @@ function includesCategory(options: ReviewCommandOptions, category: ReviewFinding
|
|
|
200
258
|
return options.include.length === 0 || options.include.includes(category);
|
|
201
259
|
}
|
|
202
260
|
|
|
203
|
-
function
|
|
261
|
+
function processEnvNamesFromText(text: string): string[] {
|
|
204
262
|
const names = new Set<string>();
|
|
205
|
-
for (const regex of [/process\.env\.([A-Z0-9_]+)/g, /process\.env\[['"]([A-Z0-9_]+)['"]\]/g
|
|
263
|
+
for (const regex of [/process\.env\.([A-Z0-9_]+)/g, /process\.env\[['"]([A-Z0-9_]+)['"]\]/g]) {
|
|
206
264
|
let match: RegExpExecArray | null;
|
|
207
265
|
while ((match = regex.exec(text))) names.add(match[1]);
|
|
208
266
|
}
|
|
209
267
|
return [...names].sort();
|
|
210
268
|
}
|
|
211
269
|
|
|
212
|
-
function
|
|
270
|
+
function ctxSecretNamesFromText(text: string): string[] {
|
|
271
|
+
const names = new Set<string>();
|
|
272
|
+
const regex = /ctx\.secrets\.get\(['"]([A-Z0-9_]+)['"]\)/g;
|
|
273
|
+
let match: RegExpExecArray | null;
|
|
274
|
+
while ((match = regex.exec(text))) names.add(match[1]);
|
|
275
|
+
return [...names].sort();
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
function isSecretEnvName(name: string): boolean {
|
|
279
|
+
if (SYSTEM_ENV_NAMES.has(name)) return false;
|
|
280
|
+
return SECRET_ENV_PATTERN.test(name);
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
function secretNamesFromText(text: string): string[] {
|
|
284
|
+
const names = new Set<string>();
|
|
285
|
+
for (const name of processEnvNamesFromText(text)) {
|
|
286
|
+
if (isSecretEnvName(name)) names.add(name);
|
|
287
|
+
}
|
|
288
|
+
for (const name of ctxSecretNamesFromText(text)) names.add(name);
|
|
289
|
+
return [...names].sort();
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
function publicSecretNamesFromText(text: string): string[] {
|
|
213
293
|
const names = new Set<string>();
|
|
214
294
|
for (const regex of [/process\.env\.([A-Z0-9_]+)/g, /process\.env\[['"]([A-Z0-9_]+)['"]\]/g]) {
|
|
215
295
|
let match: RegExpExecArray | null;
|
|
216
|
-
while ((match = regex.exec(text)))
|
|
296
|
+
while ((match = regex.exec(text))) {
|
|
297
|
+
const name = match[1];
|
|
298
|
+
if ((name.startsWith("PUBLIC_") || name.startsWith("NEXT_PUBLIC_")) && isSecretEnvName(name)) {
|
|
299
|
+
names.add(name);
|
|
300
|
+
}
|
|
301
|
+
}
|
|
217
302
|
}
|
|
218
303
|
return [...names].sort();
|
|
219
304
|
}
|
|
@@ -352,15 +437,16 @@ function secretRules(ctx: ReviewContext): ReviewFinding[] {
|
|
|
352
437
|
const findings: ReviewFinding[] = [];
|
|
353
438
|
const documented = ctx.envExample;
|
|
354
439
|
for (const [file, text] of ctx.fileTexts) {
|
|
355
|
-
if (isTestFile(file) ||
|
|
440
|
+
if (isTestFile(file) || isDocumentationFile(file)) continue;
|
|
356
441
|
const names = secretNamesFromText(text);
|
|
357
|
-
|
|
442
|
+
const directSecretEnvNames = processEnvNamesFromText(text).filter(isSecretEnvName);
|
|
443
|
+
if (directSecretEnvNames.length > 0 && !isForgeToolingFile(file)) {
|
|
358
444
|
findings.push(finding({
|
|
359
445
|
severity: "error",
|
|
360
446
|
category: "secrets",
|
|
361
447
|
code: "secret-direct-process-env",
|
|
362
448
|
title: "Direct process.env usage introduced",
|
|
363
|
-
message: "
|
|
449
|
+
message: `${directSecretEnvNames.join(", ")} should be accessed through ctx.secrets or generated config context.`,
|
|
364
450
|
file,
|
|
365
451
|
suggestedCommands: ["forge secrets check", "forge refactor replace-process-env <ENV_VAR>"],
|
|
366
452
|
autoRepair: { available: true, command: "forge refactor replace-process-env <ENV_VAR>", confidence: "medium" },
|
|
@@ -378,7 +464,7 @@ function secretRules(ctx: ReviewContext): ReviewFinding[] {
|
|
|
378
464
|
suggestedCommands: ["forge secrets check"],
|
|
379
465
|
}));
|
|
380
466
|
}
|
|
381
|
-
if (
|
|
467
|
+
if (publicSecretNamesFromText(text).includes(name)) {
|
|
382
468
|
findings.push(finding({
|
|
383
469
|
severity: "blocking",
|
|
384
470
|
category: "secrets",
|
|
@@ -693,6 +779,9 @@ function buildReport(options: ReviewCommandOptions): ReviewReport {
|
|
|
693
779
|
findings: findings.map((item) => [item.code, item.file, item.severity]),
|
|
694
780
|
})).slice(0, 12)}`;
|
|
695
781
|
const generatedPaths = ctx.changed.generated;
|
|
782
|
+
const changeSummary = categorizeFiles(ctx.changed.files);
|
|
783
|
+
const reviewFocus = buildReviewFocus(changeSummary);
|
|
784
|
+
const diffPlan: ReviewDiffPlan = buildDiffPlanFromChangeSummary(changeSummary);
|
|
696
785
|
return {
|
|
697
786
|
schemaVersion: "0.1.0",
|
|
698
787
|
reviewVersion: REVIEW_VERSION,
|
|
@@ -709,6 +798,9 @@ function buildReport(options: ReviewCommandOptions): ReviewReport {
|
|
|
709
798
|
risk,
|
|
710
799
|
findings,
|
|
711
800
|
changed: ctx.changed,
|
|
801
|
+
changeSummary,
|
|
802
|
+
reviewFocus,
|
|
803
|
+
diffPlan,
|
|
712
804
|
impacted: ctx.impacted,
|
|
713
805
|
checks: [
|
|
714
806
|
{ name: "impact-analysis", ok: true, message: `risk ${risk.level}` },
|
|
@@ -755,7 +847,13 @@ ${report.summary.bullets.map((bullet) => `- ${bullet}`).join("\n")}
|
|
|
755
847
|
|
|
756
848
|
## Changed Files
|
|
757
849
|
|
|
758
|
-
${report.changed.files.map((file) => `- ${file}`).join("\n") || "- none"}
|
|
850
|
+
${report.changed.files.filter((file) => !file.startsWith(`${GENERATED}/`) && file !== "forge.lock").map((file) => `- ${file}`).join("\n") || "- none"}
|
|
851
|
+
|
|
852
|
+
Generated artifacts are derived and collapsed by default.
|
|
853
|
+
|
|
854
|
+
- Generated files: ${report.diffPlan.generatedFiles}
|
|
855
|
+
- Authored diff: \`${report.diffPlan.authoredDiffCommand}\`
|
|
856
|
+
- Generated diff: \`${report.diffPlan.generatedDiffCommand}\`
|
|
759
857
|
|
|
760
858
|
## Findings
|
|
761
859
|
|
|
@@ -958,8 +1056,54 @@ export function runReviewCommand(options: ReviewCommandOptions): ReviewResult {
|
|
|
958
1056
|
}
|
|
959
1057
|
}
|
|
960
1058
|
|
|
961
|
-
|
|
962
|
-
|
|
1059
|
+
function compactReviewReport(result: ReviewResult): unknown {
|
|
1060
|
+
const report = result.report;
|
|
1061
|
+
if (!report) return result.reports ?? result.explanation ?? result;
|
|
1062
|
+
const impacted = {
|
|
1063
|
+
...report.impacted,
|
|
1064
|
+
generatedArtifacts: report.impacted.generatedArtifacts.length,
|
|
1065
|
+
};
|
|
1066
|
+
return {
|
|
1067
|
+
schemaVersion: report.schemaVersion,
|
|
1068
|
+
reviewVersion: report.reviewVersion,
|
|
1069
|
+
ok: result.ok,
|
|
1070
|
+
id: report.id,
|
|
1071
|
+
source: report.source,
|
|
1072
|
+
summary: report.summary,
|
|
1073
|
+
risk: report.risk,
|
|
1074
|
+
findings: report.findings,
|
|
1075
|
+
changed: {
|
|
1076
|
+
files: report.changed.files.length,
|
|
1077
|
+
tests: report.changed.tests.length,
|
|
1078
|
+
sourceFiles: report.changed.sourceFiles.length,
|
|
1079
|
+
generated: report.changed.generated.length,
|
|
1080
|
+
packageFiles: report.changed.packageFiles.length,
|
|
1081
|
+
deployFiles: report.changed.deployFiles.length,
|
|
1082
|
+
},
|
|
1083
|
+
changeSummary: report.changeSummary,
|
|
1084
|
+
reviewFocus: report.reviewFocus,
|
|
1085
|
+
diffPlan: report.diffPlan,
|
|
1086
|
+
impacted,
|
|
1087
|
+
checks: report.checks,
|
|
1088
|
+
recommendedCommands: report.recommendedCommands,
|
|
1089
|
+
humanChecklist: report.humanChecklist,
|
|
1090
|
+
agentInstructions: report.agentInstructions,
|
|
1091
|
+
generatedArtifacts: {
|
|
1092
|
+
paths: report.generatedArtifacts.paths.length,
|
|
1093
|
+
stale: report.generatedArtifacts.stale,
|
|
1094
|
+
},
|
|
1095
|
+
writeResult: result.writeResult,
|
|
1096
|
+
diagnostics: result.diagnostics,
|
|
1097
|
+
exitCode: result.exitCode,
|
|
1098
|
+
fullCommand: "forge review run --changed --full --json",
|
|
1099
|
+
};
|
|
1100
|
+
}
|
|
1101
|
+
|
|
1102
|
+
export function formatReviewJson(result: ReviewResult, options: { full?: boolean } = {}): string {
|
|
1103
|
+
const payload = options.full
|
|
1104
|
+
? result.report ?? result.reports ?? result.explanation ?? result
|
|
1105
|
+
: compactReviewReport(result);
|
|
1106
|
+
return `${JSON.stringify(payload, null, 2)}\n`;
|
|
963
1107
|
}
|
|
964
1108
|
|
|
965
1109
|
export function formatReviewHuman(result: ReviewResult): string {
|
|
@@ -978,6 +1122,8 @@ ${result.reports.map((report) => `- ${report.id}: ${report.dir}`).join("\n") ||
|
|
|
978
1122
|
|
|
979
1123
|
Risk: ${report.risk.level} (${report.risk.score})
|
|
980
1124
|
Findings: ${report.findings.length}
|
|
1125
|
+
Review focus: ${report.reviewFocus.summary}
|
|
1126
|
+
Review order: ${report.reviewFocus.suggestedOrder.join(" -> ") || "none"}
|
|
981
1127
|
|
|
982
1128
|
Blocking issues:
|
|
983
1129
|
${report.findings.filter((finding) => finding.severity === "blocking").map((finding) => ` - ${finding.code}: ${finding.message}`).join("\n") || " - none"}
|