forgeos 0.1.0-alpha.2 → 0.1.0-alpha.20
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 +199 -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 +212 -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 +1192 -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 +84 -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 +736 -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/README.md
CHANGED
|
@@ -2,9 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
Agent-native application framework and compiler for building Forge apps without a mandatory dashboard. ForgeOS turns application source into deterministic runtime contracts, generated clients, safety checks, and machine-readable context that humans and AI coding agents can use safely.
|
|
4
4
|
|
|
5
|
-
**Status:** private/public alpha MVP, implemented through
|
|
5
|
+
**Status:** private/public alpha MVP, implemented through H49. ForgeOS already includes the compiler, local runtime, frontend SDK, production auth, RLS compiler, liveQuery, self-host artifacts, generated agent contract, guided dev loop, repair/review/test tooling, AST-aware codemods, package intelligence, native AI tools/agents, DeltaDB work memory, external agent memory ingestion, brownfield import analysis, npm alpha publishing, and Read the Docs public docs. Public release hardening is still focused on deeper semantic codemods, broader field reports, and more production mileage.
|
|
6
6
|
|
|
7
|
-
Public docs
|
|
7
|
+
Public docs live at [forgeos.readthedocs.io](https://forgeos.readthedocs.io/). The repo builds them with `.readthedocs.yaml`, `mkdocs.yml`, and `docs/index.md`.
|
|
8
|
+
|
|
9
|
+
Start with [Why ForgeOS](https://forgeos.readthedocs.io/en/latest/why-forgeos/) to understand the agent-native design.
|
|
10
|
+
|
|
11
|
+
For the short version, read [The Five-Minute ForgeOS Model](https://forgeos.readthedocs.io/en/latest/five-minute-model/) and [Alpha Golden Path](https://forgeos.readthedocs.io/en/latest/golden-path/). The important distinction is that external coding agents are the primary ForgeOS workflow; integrated AI SDK features are available for apps that need in-product AI, but they are not the main development loop.
|
|
8
12
|
|
|
9
13
|
## Agent-First Quickstart
|
|
10
14
|
|
|
@@ -47,7 +51,7 @@ These files describe the app surface, runtime rules, generated files, policies,
|
|
|
47
51
|
Public one-command app creation:
|
|
48
52
|
|
|
49
53
|
```bash
|
|
50
|
-
npm create
|
|
54
|
+
npm create forgeos-app@alpha notes-app -- --template minimal-web
|
|
51
55
|
cd notes-app
|
|
52
56
|
npm run dev
|
|
53
57
|
```
|
|
@@ -89,6 +93,39 @@ npm run field:test -- --package-managers npm --templates minimal-web --forge-spe
|
|
|
89
93
|
|
|
90
94
|
The scheduled/manual `Field Tests` workflow expands that coverage across Linux, macOS, Windows, Node 22, Node 24, and npm/pnpm/yarn/bun.
|
|
91
95
|
|
|
96
|
+
## External Runtimes And Adapters
|
|
97
|
+
|
|
98
|
+
ForgeOS can import services written outside TypeScript through the Forge Protocol.
|
|
99
|
+
External runtimes publish a `forge.manifest.json` that describes commands, queries,
|
|
100
|
+
transport, policies, risk metadata, tenant scope, and schemas. Forge then emits
|
|
101
|
+
the same machine-readable app/API/agent artifacts and exposes runtime bridge
|
|
102
|
+
endpoints for those entries.
|
|
103
|
+
|
|
104
|
+
The Go example starts a manifest-backed service:
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
cd examples/go-billing
|
|
108
|
+
go run . --manifest --base-url http://127.0.0.1:8787 > forge.manifest.json
|
|
109
|
+
go run . --addr 127.0.0.1:8787 --base-url http://127.0.0.1:8787
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
In a Forge app:
|
|
113
|
+
|
|
114
|
+
```bash
|
|
115
|
+
forge manifest validate ./forge.manifest.json --json
|
|
116
|
+
forge manifest import ./forge.manifest.json --json
|
|
117
|
+
forge generate
|
|
118
|
+
forge run billing.createInvoice --args '{"title":"Invoice"}' --user-id u1 --tenant-id tenant-a --role admin
|
|
119
|
+
forge query billing.listInvoices --args '{}' --user-id u1 --tenant-id tenant-a --role admin
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
For Java, see [`adapters/java`](adapters/java/README.md),
|
|
123
|
+
[`adapters/java-spring-boot-starter`](adapters/java-spring-boot-starter/README.md),
|
|
124
|
+
and [`examples/java-billing`](examples/java-billing/README.md).
|
|
125
|
+
|
|
126
|
+
See [`docs/forge-protocol.md`](docs/forge-protocol.md), [`schemas/forge-manifest.schema.json`](schemas/forge-manifest.schema.json),
|
|
127
|
+
and [`adapters/go`](adapters/go/README.md).
|
|
128
|
+
|
|
92
129
|
## What ForgeOS Generates
|
|
93
130
|
|
|
94
131
|
```txt
|
|
@@ -138,14 +175,17 @@ forge.lock
|
|
|
138
175
|
| Auth | dev headers, JWT, OIDC discovery/JWKS verification via `jose`, production-mode guardrails |
|
|
139
176
|
| RLS | Postgres RLS SQL compiler/checks for DB-enforced tenant isolation |
|
|
140
177
|
| Secrets/env | secret registry, env schema, redaction, strict `process.env` checks |
|
|
141
|
-
| AI | provider registry, `ctx.ai`, mock mode, telemetry without prompt/output retention by default |
|
|
178
|
+
| AI | Vercel AI SDK v6 engine, provider registry, `ctx.ai`, `ctx.agent.run`, `aiTool`, `agent`, `/ai/agents/run` JSON automation, `/ai/agents/chat` UIMessage streaming, `forge ai trace`, structural and model-level redteam probes, mock mode, telemetry without prompt/output retention by default |
|
|
142
179
|
| Frontend | generated client SDK, React/Next hooks, template app, liveQuery client support |
|
|
143
180
|
| LiveQuery | durable invalidation log, reconnect/resume semantics, production hardening checks |
|
|
181
|
+
| DeltaDB | ambient local recorder plus inferred work sessions and semantic timelines for Forge commands, dev file saves, generated artifacts, runtime calls, policies, proofs, diagnostics, `forge timeline`, `forge explain`, and optional `forge session` correction |
|
|
182
|
+
| Agent memory | opt-in Codex and Claude Code hooks, Cursor MCP/rules setup, normalized external agent events, redacted local memory, and `forge mcp serve` |
|
|
183
|
+
| Brownfield import | static TypeScript/JavaScript app inventory with routes, frontend calls, env usage, candidate entries, risk report, migration plan, and hidden-by-default imported agent contract |
|
|
144
184
|
| Self-host | compose/deploy artifacts and self-host checks |
|
|
145
185
|
| Agent contract | `AGENTS.md`, `agentContract.json`, app maps, runtime rules, playbooks, inspect/doctor |
|
|
146
186
|
| Authoring | `forge make`, feature blueprints, safe refactor plans, package upgrade plans |
|
|
147
187
|
| Testing/repair | impact-based test planner, repair loop, structured review, UI/browser test bridge |
|
|
148
|
-
| Adapters |
|
|
188
|
+
| Adapters | Forge Protocol manifest import plus Go, Java, and Spring Boot adapter support for executable external commands and queries |
|
|
149
189
|
| Intent router | `forge do` maps objectives like fix, verify, connect UI, and add feature into plans, files, risks, and next commands |
|
|
150
190
|
| Full-stack map | `frontendGraph` + `capabilityMap` connect routes, components, hooks, runtime entries, tables, policies, and gaps |
|
|
151
191
|
| Dev loop | `forge dev` prints API/Web URLs, phase health, capability coverage, cache status, diagnostics, and next action |
|
|
@@ -166,6 +206,16 @@ forge dev
|
|
|
166
206
|
forge inspect all --json
|
|
167
207
|
forge inspect framework --json
|
|
168
208
|
forge inspect capabilities --json
|
|
209
|
+
forge delta status
|
|
210
|
+
forge timeline
|
|
211
|
+
forge timeline --session current
|
|
212
|
+
forge explain <thing>
|
|
213
|
+
forge explain session current
|
|
214
|
+
forge session list
|
|
215
|
+
forge agent memory --json
|
|
216
|
+
forge mcp serve
|
|
217
|
+
forge import analyze --json
|
|
218
|
+
forge inspect imported --json
|
|
169
219
|
forge doctor
|
|
170
220
|
forge verify --standard
|
|
171
221
|
forge verify --strict
|
|
@@ -187,8 +237,10 @@ Common command groups:
|
|
|
187
237
|
| `forge check --json` | Validate guardrails and emit diagnostics with fix hints |
|
|
188
238
|
| `forge verify --smoke` | Fast local gate: generated drift, Forge checks, typecheck when present, no tests/lint |
|
|
189
239
|
| `forge verify --standard` | Agent development gate: generated drift, Forge/security checks, typecheck, and impact-selected tests |
|
|
190
|
-
| `forge verify --strict` | Full handoff/CI gate: generated drift, Forge/security checks, typecheck, full
|
|
240
|
+
| `forge verify --strict` | Full handoff/CI gate: generated drift, Forge/security checks, typecheck, full TestGraph in bounded parallel/isolated chunks, lint |
|
|
191
241
|
| `forge verify --script-timeout-ms <ms>` | Run package scripts with a predictable timeout and machine-readable timeout diagnostics |
|
|
242
|
+
| `forge verify --test-jobs <n>` | Tune strict TestGraph chunk parallelism; `FORGE_VERIFY_TEST_JOBS` is also supported |
|
|
243
|
+
| `forge verify --strict --test-plan --json` | Print the strict TestGraph scheduler plan without running tests |
|
|
192
244
|
| `forge do "<objective>" --json` | Guided intent router: choose the right workflow, files, risks, and next action |
|
|
193
245
|
| `forge inspect <target> --json` | Inspect generated app/data/runtime/policy/client/agent/UI surfaces |
|
|
194
246
|
| `forge inspect framework --json` | Inspect ForgeOS framework modules, CLI commands, templates, examples, tests, and preferred entrypoints |
|
|
@@ -208,12 +260,16 @@ Common command groups:
|
|
|
208
260
|
| `forge ui` | Browser/UI smoke, scenario, route, snapshot, doctor, and reports |
|
|
209
261
|
| `forge deps` | Package upgrade planning and application |
|
|
210
262
|
| `forge release` | Release/source-map bridge and symbolication |
|
|
211
|
-
| `forge agent`, `forge agent-contract` | Agent-facing contract
|
|
263
|
+
| `forge agent`, `forge agent-contract` | Agent-facing contract, adapter exports, context, install, ingest, and memory commands |
|
|
264
|
+
| `forge mcp serve` | MCP server for external agents to read Forge context, memory, timeline, and inspect surfaces |
|
|
265
|
+
| `forge import analyze`, `forge import inspect` | Brownfield TypeScript/JavaScript app inventory and reviewed migration planning |
|
|
266
|
+
| `forge inspect imported --json` | Inspect `.forge/import` analysis artifacts |
|
|
212
267
|
| `forge self-host` | Self-host packaging and checks |
|
|
213
268
|
|
|
214
269
|
Refactor codemods are AST-aware where safety matters most:
|
|
215
270
|
|
|
216
271
|
- `forge refactor extract-action` is binding-aware and preserves unrelated imports, type-only imports, and shadowed locals.
|
|
272
|
+
- `forge refactor rename command <oldName> <newName>` rewrites command declarations, generated client references, React hook usage, tests, and safe string references while preserving unrelated symbols.
|
|
217
273
|
- `forge refactor rename field <table.field> <table.field>` rewrites structured TS/JS/JSX/TSX and JSON references, preserves locals, and scopes the field change to files/objects linked to the target table. For example, `tickets.priority -> tickets.urgency` does not rewrite a generic `priority` prop in a component with no `tickets` binding.
|
|
218
274
|
- `forge refactor rename table <from> <to>` rewrites table definitions, `ctx.db.<table>` access, policy strings, JSON/blueprints, and import/export specifiers while preserving unrelated locals with the same name.
|
|
219
275
|
|
|
@@ -242,12 +298,23 @@ See [`examples/showcase-forge-app`](examples/showcase-forge-app/README.md).
|
|
|
242
298
|
|
|
243
299
|
```bash
|
|
244
300
|
cd examples/showcase-forge-app
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
301
|
+
npm install
|
|
302
|
+
npm run generate
|
|
303
|
+
npm run dev
|
|
248
304
|
```
|
|
249
305
|
|
|
250
|
-
|
|
306
|
+
For the reproducible public proof path:
|
|
307
|
+
|
|
308
|
+
```bash
|
|
309
|
+
npm run proof:inspect
|
|
310
|
+
npm run proof:dev
|
|
311
|
+
npm run proof:capabilities
|
|
312
|
+
npm run proof:verify
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
Read [`examples/showcase-forge-app/PUBLIC_PROOF.md`](examples/showcase-forge-app/PUBLIC_PROOF.md) for the full walkthrough.
|
|
316
|
+
|
|
317
|
+
Examples are source-only where practical: generated artifacts, `forge.lock`, package lockfiles, and operational `.forge/**` state are recreated locally. The showcase demonstrates tenant-scoped data, policies, commands, queries, liveQueries, outbox actions, workflows, mock AI, telemetry trace IDs, generated React hooks, `agentContract`, `frontendGraph`, `capabilityMap`, and the standard agent handoff loop.
|
|
251
318
|
|
|
252
319
|
## Platform Support
|
|
253
320
|
|
|
@@ -323,7 +390,7 @@ For the first prerelease publish, use the alpha dist-tag explicitly:
|
|
|
323
390
|
|
|
324
391
|
```bash
|
|
325
392
|
npm run release:publish-local-alpha -- --dry-run
|
|
326
|
-
npm run release:publish-
|
|
393
|
+
npm run release:publish-alpha
|
|
327
394
|
```
|
|
328
395
|
|
|
329
396
|
The normal path is:
|
|
@@ -346,7 +413,7 @@ Configure npm Trusted Publisher for package `forgeos`:
|
|
|
346
413
|
| Environment | blank |
|
|
347
414
|
| Allowed action | `npm publish` |
|
|
348
415
|
|
|
349
|
-
Do not add `NPM_TOKEN` for normal releases. Alpha releases publish with the `alpha` dist-tag so prerelease builds do not become `latest` accidentally.
|
|
416
|
+
Do not add `NPM_TOKEN` for normal releases. Alpha releases publish with the `alpha` dist-tag so prerelease builds do not become `latest` accidentally. Use `release:publish-local-alpha -- --dry-run` only to validate the staged tarball locally; real npm publishing should go through `release:publish-alpha`, which dispatches `publish.yml` and uses npm OIDC Trusted Publisher. The workflow checks whether the package version already exists before installing dependencies or running tests, then uses `id-token: write`, Node 24/npm 11+, and provenance for the actual publish. `npm run release:smoke` runs `npm pack`, creates a fresh app with the packed tarball, installs dependencies, runs `forge dev --once --json`, and verifies the app smoke path.
|
|
350
417
|
|
|
351
418
|
## Milestone History
|
|
352
419
|
|
|
@@ -393,11 +460,18 @@ H39 Showcase app
|
|
|
393
460
|
H40 Windows/runtime hardening
|
|
394
461
|
H41 Node-compatible CLI/runtime
|
|
395
462
|
H42 Verify observability and quieter app workspaces
|
|
463
|
+
H43 Native AI tools and agent loop
|
|
464
|
+
H44 Ambient DeltaDB recorder
|
|
465
|
+
H45 Automatic work-session inference
|
|
466
|
+
H46 Automatic change grouping
|
|
467
|
+
H47 Semantic timeline
|
|
468
|
+
H48 Agent Memory Bridge
|
|
469
|
+
H49 Brownfield import analysis
|
|
396
470
|
```
|
|
397
471
|
|
|
398
472
|
## Remaining Hardening Before Public Release
|
|
399
473
|
|
|
400
|
-
- Keep expanding semantic codemods beyond the current AST-aware `extract-action`, `rename field`, and `rename table` paths.
|
|
474
|
+
- Keep expanding semantic codemods beyond the current AST-aware `extract-action`, `rename command`, `rename field`, and `rename table` paths.
|
|
401
475
|
- Reduce command-selection risk with more task routers and richer inline diagnostics.
|
|
402
476
|
- Keep hardening native Windows setup beyond diagnostics and safe automatic environment fixes.
|
|
403
477
|
- Keep broadening package manager CI from template smoke toward install/build smoke for pnpm and yarn apps.
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# Forge Go Adapter
|
|
2
|
+
|
|
3
|
+
`adapters/go` is the minimal Go SDK for external Forge runtimes. It registers
|
|
4
|
+
commands and queries, emits `forge.manifest.json`, and exposes a Forge-compatible
|
|
5
|
+
HTTP handler.
|
|
6
|
+
|
|
7
|
+
```go
|
|
8
|
+
app := forge.New("billing", forge.BaseURL("http://127.0.0.1:8787"))
|
|
9
|
+
|
|
10
|
+
app.Command("createInvoice", forge.Handle(createInvoice),
|
|
11
|
+
forge.Policy("billing.manage"),
|
|
12
|
+
forge.TenantScoped(true),
|
|
13
|
+
forge.NeedsApproval(true),
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
app.Query("listInvoices", forge.Handle(listInvoices),
|
|
17
|
+
forge.Policy("billing.manage"),
|
|
18
|
+
forge.TenantScoped(true),
|
|
19
|
+
)
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
The HTTP handler accepts Forge runtime envelopes on `/commands/:name` and
|
|
23
|
+
`/queries/:name`, then returns `{ "ok": true, "result": ... }` envelopes.
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
package forge
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"encoding/json"
|
|
5
|
+
"errors"
|
|
6
|
+
"net/http"
|
|
7
|
+
"strings"
|
|
8
|
+
)
|
|
9
|
+
|
|
10
|
+
func (registry *Registry) HTTPHandler() http.Handler {
|
|
11
|
+
mux := http.NewServeMux()
|
|
12
|
+
mux.HandleFunc(registry.service.Health, registry.handleHealth)
|
|
13
|
+
mux.HandleFunc("/manifest", registry.handleManifest)
|
|
14
|
+
mux.HandleFunc("/commands/", registry.handleRuntime(KindCommand, "/commands/"))
|
|
15
|
+
mux.HandleFunc("/queries/", registry.handleRuntime(KindQuery, "/queries/"))
|
|
16
|
+
return mux
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
func (registry *Registry) handleHealth(response http.ResponseWriter, request *http.Request) {
|
|
20
|
+
writeJSON(response, http.StatusOK, map[string]any{
|
|
21
|
+
"ok": true,
|
|
22
|
+
"service": registry.service.Name,
|
|
23
|
+
})
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
func (registry *Registry) handleManifest(response http.ResponseWriter, request *http.Request) {
|
|
27
|
+
baseURL := request.URL.Query().Get("baseUrl")
|
|
28
|
+
if baseURL == "" {
|
|
29
|
+
baseURL = registry.service.BaseURL
|
|
30
|
+
}
|
|
31
|
+
writeJSON(response, http.StatusOK, registry.Manifest(baseURL))
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
func (registry *Registry) handleRuntime(kind EntryKind, prefix string) http.HandlerFunc {
|
|
35
|
+
return func(response http.ResponseWriter, request *http.Request) {
|
|
36
|
+
name := strings.TrimPrefix(request.URL.Path, prefix)
|
|
37
|
+
registered, ok := registry.lookup[lookupKey(kind, name)]
|
|
38
|
+
if !ok {
|
|
39
|
+
writeError(response, http.StatusNotFound, "", "FORGE_GO_ENTRY_NOT_FOUND", "external entry not found")
|
|
40
|
+
return
|
|
41
|
+
}
|
|
42
|
+
if request.Method != http.MethodPost && request.Method != http.MethodGet {
|
|
43
|
+
writeError(response, http.StatusMethodNotAllowed, "", "FORGE_GO_METHOD_NOT_ALLOWED", "external entry only accepts GET or POST")
|
|
44
|
+
return
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
envelope, err := readRequestEnvelope(request)
|
|
48
|
+
traceID := traceIDFrom(request, envelope)
|
|
49
|
+
if err != nil {
|
|
50
|
+
writeError(response, http.StatusBadRequest, traceID, "FORGE_GO_BAD_REQUEST", err.Error())
|
|
51
|
+
return
|
|
52
|
+
}
|
|
53
|
+
if envelope.Forge.Service == "" {
|
|
54
|
+
envelope.Forge.Service = registry.service.Name
|
|
55
|
+
}
|
|
56
|
+
if envelope.Forge.Entry == "" {
|
|
57
|
+
envelope.Forge.Entry = name
|
|
58
|
+
}
|
|
59
|
+
if envelope.Forge.Kind == "" {
|
|
60
|
+
envelope.Forge.Kind = string(kind)
|
|
61
|
+
}
|
|
62
|
+
if envelope.Forge.TraceID == "" {
|
|
63
|
+
envelope.Forge.TraceID = traceID
|
|
64
|
+
}
|
|
65
|
+
if envelope.Auth.Kind == "" {
|
|
66
|
+
envelope.Auth = authFromHeaders(request.Header)
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
call := &Context{
|
|
70
|
+
Auth: envelope.Auth,
|
|
71
|
+
Forge: envelope.Forge,
|
|
72
|
+
Headers: request.Header,
|
|
73
|
+
}
|
|
74
|
+
result, err := registered.handler(request.Context(), call, envelope.Args)
|
|
75
|
+
if err != nil {
|
|
76
|
+
writeError(response, http.StatusInternalServerError, envelope.Forge.TraceID, "FORGE_GO_HANDLER_FAILED", err.Error())
|
|
77
|
+
return
|
|
78
|
+
}
|
|
79
|
+
writeJSON(response, http.StatusOK, ResponseEnvelope{
|
|
80
|
+
OK: true,
|
|
81
|
+
Result: result,
|
|
82
|
+
TraceID: envelope.Forge.TraceID,
|
|
83
|
+
})
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
func readRequestEnvelope(request *http.Request) (RequestEnvelope, error) {
|
|
88
|
+
if request.Method == http.MethodGet {
|
|
89
|
+
args := request.URL.Query().Get("args")
|
|
90
|
+
if args == "" {
|
|
91
|
+
args = "{}"
|
|
92
|
+
}
|
|
93
|
+
return RequestEnvelope{Args: json.RawMessage(args)}, nil
|
|
94
|
+
}
|
|
95
|
+
defer request.Body.Close()
|
|
96
|
+
var envelope RequestEnvelope
|
|
97
|
+
decoder := json.NewDecoder(request.Body)
|
|
98
|
+
if err := decoder.Decode(&envelope); err != nil {
|
|
99
|
+
return envelope, err
|
|
100
|
+
}
|
|
101
|
+
if len(envelope.Args) == 0 {
|
|
102
|
+
envelope.Args = json.RawMessage("{}")
|
|
103
|
+
}
|
|
104
|
+
if !json.Valid(envelope.Args) {
|
|
105
|
+
return envelope, errors.New("request args must be valid JSON")
|
|
106
|
+
}
|
|
107
|
+
return envelope, nil
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
func authFromHeaders(headers http.Header) Auth {
|
|
111
|
+
auth := Auth{Kind: headers.Get("x-forge-auth-kind")}
|
|
112
|
+
if auth.Kind == "" {
|
|
113
|
+
auth.Kind = "anonymous"
|
|
114
|
+
}
|
|
115
|
+
auth.UserID = headers.Get("x-forge-user-id")
|
|
116
|
+
auth.TenantID = headers.Get("x-forge-tenant-id")
|
|
117
|
+
auth.Role = headers.Get("x-forge-role")
|
|
118
|
+
return auth
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
func traceIDFrom(request *http.Request, envelope RequestEnvelope) string {
|
|
122
|
+
if envelope.Forge.TraceID != "" {
|
|
123
|
+
return envelope.Forge.TraceID
|
|
124
|
+
}
|
|
125
|
+
return request.Header.Get("x-forge-trace-id")
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
func writeError(response http.ResponseWriter, status int, traceID string, code string, message string) {
|
|
129
|
+
writeJSON(response, status, ResponseEnvelope{
|
|
130
|
+
OK: false,
|
|
131
|
+
Diagnostics: []Diagnostic{{
|
|
132
|
+
Severity: "error",
|
|
133
|
+
Code: code,
|
|
134
|
+
Message: message,
|
|
135
|
+
Docs: []string{"docs/forge-protocol.md"},
|
|
136
|
+
}},
|
|
137
|
+
Error: &ErrorInfo{
|
|
138
|
+
Code: code,
|
|
139
|
+
Message: message,
|
|
140
|
+
},
|
|
141
|
+
TraceID: traceID,
|
|
142
|
+
})
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
func writeJSON(response http.ResponseWriter, status int, body any) {
|
|
146
|
+
response.Header().Set("content-type", "application/json")
|
|
147
|
+
response.WriteHeader(status)
|
|
148
|
+
_ = json.NewEncoder(response).Encode(body)
|
|
149
|
+
}
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
package forge
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"encoding/json"
|
|
5
|
+
"io"
|
|
6
|
+
)
|
|
7
|
+
|
|
8
|
+
type Registry struct {
|
|
9
|
+
service Service
|
|
10
|
+
framework string
|
|
11
|
+
schemas map[string]any
|
|
12
|
+
entries []registeredEntry
|
|
13
|
+
lookup map[string]registeredEntry
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
type registeredEntry struct {
|
|
17
|
+
entry Entry
|
|
18
|
+
handler HandlerFunc
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
type RegistryOption func(*Registry)
|
|
22
|
+
type EntryOption func(*Entry)
|
|
23
|
+
|
|
24
|
+
func New(serviceName string, options ...RegistryOption) *Registry {
|
|
25
|
+
registry := &Registry{
|
|
26
|
+
service: Service{
|
|
27
|
+
Name: serviceName,
|
|
28
|
+
Transport: "http",
|
|
29
|
+
Health: "/health",
|
|
30
|
+
},
|
|
31
|
+
framework: "net/http",
|
|
32
|
+
schemas: map[string]any{},
|
|
33
|
+
lookup: map[string]registeredEntry{},
|
|
34
|
+
}
|
|
35
|
+
for _, option := range options {
|
|
36
|
+
option(registry)
|
|
37
|
+
}
|
|
38
|
+
return registry
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
func Framework(value string) RegistryOption {
|
|
42
|
+
return func(registry *Registry) {
|
|
43
|
+
registry.framework = value
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
func BaseURL(value string) RegistryOption {
|
|
48
|
+
return func(registry *Registry) {
|
|
49
|
+
registry.service.BaseURL = value
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
func Health(path string) RegistryOption {
|
|
54
|
+
return func(registry *Registry) {
|
|
55
|
+
registry.service.Health = path
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
func SchemaRef(name string, schema any) RegistryOption {
|
|
60
|
+
return func(registry *Registry) {
|
|
61
|
+
registry.schemas[name] = schema
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
func (registry *Registry) Command(name string, handler HandlerFunc, options ...EntryOption) {
|
|
66
|
+
entry := Entry{
|
|
67
|
+
Name: name,
|
|
68
|
+
Kind: KindCommand,
|
|
69
|
+
Path: "/commands/" + name,
|
|
70
|
+
Method: "POST",
|
|
71
|
+
Transaction: TransactionExternalManaged,
|
|
72
|
+
Risk: RiskWrite,
|
|
73
|
+
}
|
|
74
|
+
registry.add(entry, handler, options...)
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
func (registry *Registry) Query(name string, handler HandlerFunc, options ...EntryOption) {
|
|
78
|
+
entry := Entry{
|
|
79
|
+
Name: name,
|
|
80
|
+
Kind: KindQuery,
|
|
81
|
+
Path: "/queries/" + name,
|
|
82
|
+
Method: "POST",
|
|
83
|
+
Transaction: TransactionReadOnly,
|
|
84
|
+
Risk: RiskRead,
|
|
85
|
+
}
|
|
86
|
+
registry.add(entry, handler, options...)
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
func (registry *Registry) add(entry Entry, handler HandlerFunc, options ...EntryOption) {
|
|
90
|
+
for _, option := range options {
|
|
91
|
+
option(&entry)
|
|
92
|
+
}
|
|
93
|
+
registered := registeredEntry{entry: entry, handler: handler}
|
|
94
|
+
registry.entries = append(registry.entries, registered)
|
|
95
|
+
registry.lookup[lookupKey(entry.Kind, entry.Name)] = registered
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
func Description(value string) EntryOption {
|
|
99
|
+
return func(entry *Entry) {
|
|
100
|
+
entry.Description = value
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
func Path(value string) EntryOption {
|
|
105
|
+
return func(entry *Entry) {
|
|
106
|
+
entry.Path = value
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
func Method(value string) EntryOption {
|
|
111
|
+
return func(entry *Entry) {
|
|
112
|
+
entry.Method = value
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
func InputSchema(schema any) EntryOption {
|
|
117
|
+
return func(entry *Entry) {
|
|
118
|
+
entry.InputSchema = schema
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
func OutputSchema(schema any) EntryOption {
|
|
123
|
+
return func(entry *Entry) {
|
|
124
|
+
entry.OutputSchema = schema
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
func Policy(value string) EntryOption {
|
|
129
|
+
return func(entry *Entry) {
|
|
130
|
+
entry.Policy = value
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
func TenantScoped(value bool) EntryOption {
|
|
135
|
+
return func(entry *Entry) {
|
|
136
|
+
entry.TenantScoped = value
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
func TransactionMode(value Transaction) EntryOption {
|
|
141
|
+
return func(entry *Entry) {
|
|
142
|
+
entry.Transaction = value
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
func EntryRisk(value Risk) EntryOption {
|
|
147
|
+
return func(entry *Entry) {
|
|
148
|
+
entry.Risk = value
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
func NeedsApproval(value bool) EntryOption {
|
|
153
|
+
return func(entry *Entry) {
|
|
154
|
+
entry.NeedsApproval = &value
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
func Effects(values ...string) EntryOption {
|
|
159
|
+
return func(entry *Entry) {
|
|
160
|
+
entry.Effects = append([]string{}, values...)
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
func ReadOnly() EntryOption {
|
|
165
|
+
return func(entry *Entry) {
|
|
166
|
+
entry.Transaction = TransactionReadOnly
|
|
167
|
+
entry.Risk = RiskRead
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
func (registry *Registry) Manifest(baseURL string) Manifest {
|
|
172
|
+
service := registry.service
|
|
173
|
+
if baseURL != "" {
|
|
174
|
+
service.BaseURL = baseURL
|
|
175
|
+
}
|
|
176
|
+
entries := make([]Entry, 0, len(registry.entries))
|
|
177
|
+
for _, registered := range registry.entries {
|
|
178
|
+
entries = append(entries, registered.entry)
|
|
179
|
+
}
|
|
180
|
+
manifest := Manifest{
|
|
181
|
+
ForgeProtocol: ProtocolVersion,
|
|
182
|
+
Language: "go",
|
|
183
|
+
Framework: registry.framework,
|
|
184
|
+
Service: service,
|
|
185
|
+
Entries: entries,
|
|
186
|
+
}
|
|
187
|
+
if len(registry.schemas) > 0 {
|
|
188
|
+
manifest.Schemas = registry.schemas
|
|
189
|
+
}
|
|
190
|
+
return manifest
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
func (registry *Registry) MarshalManifest(baseURL string) ([]byte, error) {
|
|
194
|
+
return json.MarshalIndent(registry.Manifest(baseURL), "", " ")
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
func (registry *Registry) WriteManifest(writer io.Writer, baseURL string) error {
|
|
198
|
+
encoded, err := registry.MarshalManifest(baseURL)
|
|
199
|
+
if err != nil {
|
|
200
|
+
return err
|
|
201
|
+
}
|
|
202
|
+
if _, err := writer.Write(encoded); err != nil {
|
|
203
|
+
return err
|
|
204
|
+
}
|
|
205
|
+
_, err = writer.Write([]byte("\n"))
|
|
206
|
+
return err
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
func Object(properties map[string]any, required ...string) Schema {
|
|
210
|
+
schema := Schema{
|
|
211
|
+
"type": "object",
|
|
212
|
+
"properties": properties,
|
|
213
|
+
}
|
|
214
|
+
if len(required) > 0 {
|
|
215
|
+
schema["required"] = required
|
|
216
|
+
}
|
|
217
|
+
return schema
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
func String() Schema {
|
|
221
|
+
return Schema{"type": "string"}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
func Boolean() Schema {
|
|
225
|
+
return Schema{"type": "boolean"}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
func Array(items any) Schema {
|
|
229
|
+
return Schema{"type": "array", "items": items}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
func lookupKey(kind EntryKind, name string) string {
|
|
233
|
+
return string(kind) + ":" + name
|
|
234
|
+
}
|