forgeos 0.1.0-alpha.7 → 0.1.0-alpha.71
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/.agents/skills/forge-agent-fabric/SKILL.md +178 -0
- package/.agents/skills/forge-agent-fabric/references/managed-workflows.md +95 -0
- package/.agents/skills/forge-agent-fabric/references/repository-analysis.md +102 -0
- package/.agents/skills/forge-agent-fabric/scripts/fabric.mjs +46 -0
- package/.agents/skills/forge-agent-fabric/scripts/repository.mjs +44 -0
- package/.npmignore +10 -0
- package/AGENTS.md +142 -90
- package/CHANGELOG.md +870 -9
- package/LICENSE +21 -0
- package/README.md +121 -6
- 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 +47 -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-spring-boot-starter/README.md +32 -0
- package/adapters/java-spring-boot-starter/pom.xml +49 -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/bin/forge.mjs +18 -0
- package/docs/agent-fabric-programs.md +151 -0
- package/docs/agent-fabric.md +582 -0
- package/docs/architecture/agent-fabric/PORTABLE_PROJECTS_PLAN.md +136 -0
- package/docs/architecture/agent-fabric/README.md +180 -0
- package/docs/architecture/agent-fabric/REPOSITORY_MANIFEST_PLAN.md +284 -0
- package/docs/architecture/agent-fabric/WORKFLOW_PROGRAM_V2_ADR.md +81 -0
- package/docs/architecture/agent-fabric/WORKFLOW_PROGRAM_V2_CORRECTIONS.md +39 -0
- package/docs/architecture/agent-fabric/WORKFLOW_PROGRAM_V2_CORRECTIONS_EVIDENCE.md +53 -0
- package/docs/architecture/agent-fabric/WORKFLOW_PROGRAM_V2_EVIDENCE.md +49 -0
- package/docs/architecture/agent-fabric/WORKFLOW_PROGRAM_V2_PLAN.md +590 -0
- package/docs/cair-protocol.md +103 -0
- package/docs/changelog.md +1070 -0
- package/docs/forge-protocol.md +189 -0
- package/docs/repository-agent-benchmark.md +179 -0
- package/docs/repository-analysis.md +139 -0
- package/docs/repository-context-quality.md +179 -0
- package/docs/repository-runtime-observation.md +82 -0
- package/examples/agent-fabric-v2/README.md +70 -0
- package/examples/agent-fabric-v2/item-child.workflow.ts +11 -0
- package/examples/agent-fabric-v2/make-request.mjs +4 -0
- package/examples/agent-fabric-v2/map-child.workflow.ts +10 -0
- package/examples/agent-fabric-v2/migrate.workflow.ts +35 -0
- package/examples/agent-fabric-v2/registry.example.json +256 -0
- package/examples/agent-fabric-v2/run-ui-fixture.ts +48 -0
- package/examples/agent-fabric-v2/ui-audit.workflow.ts +28 -0
- package/examples/agent-fabric-v2/ui-fixture-worker.cjs +36 -0
- package/examples/agent-fabric-v2/visual-population.json +13 -0
- package/examples/agent-fabric-v2/workers/check.mjs +2 -0
- package/examples/agent-fabric-v2/workers/common.mjs +7 -0
- package/examples/agent-fabric-v2/workers/discover.mjs +2 -0
- package/examples/agent-fabric-v2/workers/migrate.mjs +4 -0
- package/examples/agent-fabric-v2/workers/review.mjs +3 -0
- package/examples/go-billing/go.mod +7 -0
- package/examples/go-billing/main.go +120 -0
- package/examples/java-billing/pom.xml +60 -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/package.json +60 -5
- package/schemas/agent-fabric/v0.1/control-event.schema.json +281 -0
- package/schemas/forge-manifest.schema.json +389 -0
- package/scripts/field-test-forgeos.mjs +1021 -0
- package/scripts/install-agent-fabric-skill.mjs +105 -0
- package/src/forge/_generated/releaseManifest.json +1 -2
- package/src/forge/_generated/releaseManifest.ts +3 -3
- package/src/forge/agent-adapters/index.ts +1592 -125
- package/src/forge/agent-adapters/types.ts +225 -1
- package/src/forge/agent-fabric/adapter.ts +131 -0
- package/src/forge/agent-fabric/attached-snapshot.ts +55 -0
- package/src/forge/agent-fabric/attached-task-contract.ts +105 -0
- package/src/forge/agent-fabric/attached-task-service.ts +127 -0
- package/src/forge/agent-fabric/attached-task-store.ts +109 -0
- package/src/forge/agent-fabric/authority.ts +298 -0
- package/src/forge/agent-fabric/canonical.ts +135 -0
- package/src/forge/agent-fabric/codex-adversarial-review.ts +229 -0
- package/src/forge/agent-fabric/codex-sdk-worker.ts +203 -0
- package/src/forge/agent-fabric/conductor.ts +754 -0
- package/src/forge/agent-fabric/dictionary.ts +12 -0
- package/src/forge/agent-fabric/errors.ts +32 -0
- package/src/forge/agent-fabric/hardened-conductor.ts +485 -0
- package/src/forge/agent-fabric/hardened-reducer.ts +211 -0
- package/src/forge/agent-fabric/index.ts +48 -0
- package/src/forge/agent-fabric/journal.ts +116 -0
- package/src/forge/agent-fabric/local-adaptive-digest-worker.mjs +26 -0
- package/src/forge/agent-fabric/local-adaptive-harness.ts +343 -0
- package/src/forge/agent-fabric/local-adaptive-service.ts +398 -0
- package/src/forge/agent-fabric/local-adaptive-worker.ts +146 -0
- package/src/forge/agent-fabric/local-approval-window.ts +211 -0
- package/src/forge/agent-fabric/local-change-review-service.ts +374 -0
- package/src/forge/agent-fabric/local-coding-worker.ts +285 -0
- package/src/forge/agent-fabric/local-control-store.ts +239 -0
- package/src/forge/agent-fabric/local-effect-broker.ts +348 -0
- package/src/forge/agent-fabric/local-evolution-approval.ts +81 -0
- package/src/forge/agent-fabric/local-evolution-profile.ts +87 -0
- package/src/forge/agent-fabric/local-evolution-registry.ts +427 -0
- package/src/forge/agent-fabric/local-evolution-service.ts +200 -0
- package/src/forge/agent-fabric/local-intelligence.ts +281 -0
- package/src/forge/agent-fabric/local-paths.ts +18 -0
- package/src/forge/agent-fabric/local-task-contract.ts +203 -0
- package/src/forge/agent-fabric/local-task-inbox.ts +543 -0
- package/src/forge/agent-fabric/local-task-server.ts +374 -0
- package/src/forge/agent-fabric/local-task-service.ts +982 -0
- package/src/forge/agent-fabric/local-verification.ts +551 -0
- package/src/forge/agent-fabric/managed-environment.ts +205 -0
- package/src/forge/agent-fabric/managed-run-contract.ts +103 -0
- package/src/forge/agent-fabric/managed-run-service.ts +401 -0
- package/src/forge/agent-fabric/managed-run-store.ts +165 -0
- package/src/forge/agent-fabric/managed-workspace.ts +253 -0
- package/src/forge/agent-fabric/p0a.ts +104 -0
- package/src/forge/agent-fabric/p0b-model-adapter.ts +434 -0
- package/src/forge/agent-fabric/planning.ts +155 -0
- package/src/forge/agent-fabric/program-api.ts +37 -0
- package/src/forge/agent-fabric/program-contract.ts +283 -0
- package/src/forge/agent-fabric/program-dsl.ts +126 -0
- package/src/forge/agent-fabric/program-evidence.ts +22 -0
- package/src/forge/agent-fabric/program-image.ts +15 -0
- package/src/forge/agent-fabric/program-lock.ts +50 -0
- package/src/forge/agent-fabric/program-owner.ts +16 -0
- package/src/forge/agent-fabric/program-scheduler.ts +38 -0
- package/src/forge/agent-fabric/program-service.ts +793 -0
- package/src/forge/agent-fabric/program-store.ts +142 -0
- package/src/forge/agent-fabric/program-structure.ts +65 -0
- package/src/forge/agent-fabric/program-types.ts +110 -0
- package/src/forge/agent-fabric/program-view.ts +12 -0
- package/src/forge/agent-fabric/program-worker.ts +108 -0
- package/src/forge/agent-fabric/project-profile.ts +50 -0
- package/src/forge/agent-fabric/project-registry.ts +120 -0
- package/src/forge/agent-fabric/project-runtime.ts +85 -0
- package/src/forge/agent-fabric/readiness.ts +26 -0
- package/src/forge/agent-fabric/reducer.ts +863 -0
- package/src/forge/agent-fabric/repository-context.ts +83 -0
- package/src/forge/agent-fabric/resource-ledger.ts +266 -0
- package/src/forge/agent-fabric/serialized-local-adapter.ts +60 -0
- package/src/forge/agent-fabric/types.ts +424 -0
- package/src/forge/agent-fabric/validation.ts +500 -0
- package/src/forge/agent-fabric/workflow-engine.ts +218 -0
- package/src/forge/agent-fabric/workflow-task-actions.ts +104 -0
- package/src/forge/agent-fabric/workflow-templates.ts +11 -0
- package/src/forge/agent-memory/bridge.ts +1728 -0
- package/src/forge/agent-memory/context-pack.ts +284 -0
- package/src/forge/agent-memory/hook-runner.ts +331 -0
- package/src/forge/agent-memory/mcp.ts +597 -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 +343 -0
- package/src/forge/agent-memory/sources/codex.ts +161 -0
- package/src/forge/agent-memory/sources/cursor.ts +35 -0
- package/src/forge/agent-memory/types.ts +215 -0
- package/src/forge/bench.ts +248 -0
- package/src/forge/brownfield-import/index.ts +896 -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 +118 -0
- package/src/forge/cair/query.ts +478 -0
- package/src/forge/cair/snapshot.ts +315 -0
- package/src/forge/cair/types.ts +255 -0
- package/src/forge/cli/adaptive.ts +51 -0
- package/src/forge/cli/ai.ts +16 -1
- package/src/forge/cli/auth.ts +459 -15
- package/src/forge/cli/authmd.ts +441 -0
- package/src/forge/cli/baseline.ts +112 -0
- package/src/forge/cli/build.ts +20 -4
- package/src/forge/cli/changed.ts +418 -0
- package/src/forge/cli/codex-app-server.ts +877 -0
- package/src/forge/cli/commands.ts +1859 -20
- package/src/forge/cli/db.ts +209 -2
- package/src/forge/cli/deploy.ts +1339 -0
- package/src/forge/cli/deps.ts +150 -23
- package/src/forge/cli/dev.ts +1137 -53
- package/src/forge/cli/docs.ts +265 -0
- package/src/forge/cli/doctor.ts +297 -0
- package/src/forge/cli/env-placeholders.ts +62 -0
- package/src/forge/cli/evolution.ts +40 -0
- package/src/forge/cli/fabric.ts +253 -0
- package/src/forge/cli/field-test.ts +568 -0
- package/src/forge/cli/golden-path.ts +487 -0
- package/src/forge/cli/handoff.ts +336 -0
- package/src/forge/cli/index.ts +1 -0
- package/src/forge/cli/last-run.ts +84 -0
- package/src/forge/cli/main.ts +196 -3
- package/src/forge/cli/new.ts +169 -17
- package/src/forge/cli/next-actions.ts +23 -0
- package/src/forge/cli/output.ts +398 -6
- package/src/forge/cli/parse.ts +1377 -38
- package/src/forge/cli/progress.ts +51 -0
- package/src/forge/cli/query.ts +32 -0
- package/src/forge/cli/release.ts +35 -11
- package/src/forge/cli/repository.ts +151 -0
- package/src/forge/cli/run.ts +42 -0
- package/src/forge/cli/secrets.ts +137 -1
- package/src/forge/cli/seed.ts +581 -0
- package/src/forge/cli/self-host.ts +56 -14
- package/src/forge/cli/studio.ts +2282 -0
- package/src/forge/cli/verify.ts +1458 -32
- package/src/forge/cli/windows.ts +23 -0
- package/src/forge/cli/workos.ts +3509 -0
- package/src/forge/compiler/agent-contract/build.ts +728 -64
- package/src/forge/compiler/agent-contract/types.ts +45 -2
- package/src/forge/compiler/ai-registry/parse.ts +71 -2
- package/src/forge/compiler/api-surface/build.ts +47 -0
- package/src/forge/compiler/app-graph/build.ts +112 -9
- package/src/forge/compiler/app-graph/extract.ts +107 -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/tsconfig-hash.ts +41 -4
- 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 +295 -13
- package/src/forge/compiler/data-graph/build.ts +29 -1
- package/src/forge/compiler/data-graph/parse.ts +20 -4
- package/src/forge/compiler/data-graph/sql/ddl.ts +144 -31
- 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/diagnostics/codes.ts +38 -0
- package/src/forge/compiler/diagnostics/create.ts +28 -2
- 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 +9 -0
- package/src/forge/compiler/external-manifest/registry.ts +217 -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 +142 -14
- package/src/forge/compiler/integration/add.ts +991 -33
- package/src/forge/compiler/integration/plan.ts +43 -12
- package/src/forge/compiler/integration/render.ts +29 -0
- package/src/forge/compiler/integration/snapshot.ts +2 -0
- package/src/forge/compiler/integration/templates/convex.ts +70 -0
- package/src/forge/compiler/integration/templates/index.ts +1 -0
- package/src/forge/compiler/integration/templates/render.ts +38 -0
- package/src/forge/compiler/integration/templates/types.ts +3 -0
- package/src/forge/compiler/integration/templates/workos.ts +1439 -0
- package/src/forge/compiler/make-registry/build.ts +8 -9
- package/src/forge/compiler/orchestrator/fast-check.ts +4 -0
- package/src/forge/compiler/orchestrator/generate-lock.ts +14 -3
- package/src/forge/compiler/orchestrator/manifest.ts +1 -1
- package/src/forge/compiler/orchestrator/plan-profile.ts +23 -0
- package/src/forge/compiler/orchestrator/plan.ts +249 -10
- package/src/forge/compiler/orchestrator/profile.ts +65 -0
- package/src/forge/compiler/orchestrator/run.ts +101 -33
- package/src/forge/compiler/orchestrator/serialize.ts +33 -8
- package/src/forge/compiler/orchestrator/types.ts +1 -1
- package/src/forge/compiler/package-graph/compiler.ts +3 -1
- package/src/forge/compiler/package-graph/constants.ts +1 -1
- package/src/forge/compiler/package-graph/dts-extractor.ts +14 -1
- 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/package-manager/version.ts +36 -12
- package/src/forge/compiler/package-upgrades/planner.ts +155 -18
- package/src/forge/compiler/package-upgrades/types.ts +2 -0
- package/src/forge/compiler/policy-registry/build.ts +47 -2
- package/src/forge/compiler/policy-registry/parse.ts +32 -2
- package/src/forge/compiler/recipes/definitions.ts +63 -0
- package/src/forge/compiler/recipes/index.ts +2 -0
- package/src/forge/compiler/recipes/profiles.ts +81 -0
- package/src/forge/compiler/recipes/registry.ts +6 -0
- package/src/forge/compiler/test-graph/build.ts +11 -3
- package/src/forge/compiler/types/app-graph.ts +8 -2
- package/src/forge/compiler/types/cli.ts +76 -1
- package/src/forge/compiler/types/dev-manifest.ts +4 -0
- package/src/forge/compiler/types/emit.ts +2 -0
- package/src/forge/compiler/types/frontend-graph.ts +2 -2
- package/src/forge/compiler/types/integration.ts +1 -0
- package/src/forge/compiler/types/package-graph.ts +6 -0
- package/src/forge/compiler/types/policy-registry.ts +3 -1
- package/src/forge/delta/broker-runner.mjs +5 -0
- package/src/forge/delta/broker.ts +429 -0
- package/src/forge/delta/classifier.ts +52 -0
- package/src/forge/delta/explain.ts +238 -0
- package/src/forge/delta/git-observer.ts +67 -0
- package/src/forge/delta/ids.ts +44 -0
- package/src/forge/delta/index.ts +25 -0
- package/src/forge/delta/process-identity.ts +37 -0
- package/src/forge/delta/queue-status.ts +190 -0
- package/src/forge/delta/recorder.ts +540 -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 +1139 -0
- package/src/forge/delta/store.ts +3329 -0
- package/src/forge/delta/timeline.ts +178 -0
- package/src/forge/dev/server.ts +1061 -22
- package/src/forge/dev/types.ts +15 -1
- package/src/forge/dev/watch.ts +17 -7
- package/src/forge/dev-console/cycle.ts +285 -33
- package/src/forge/dev-console/types.ts +47 -1
- package/src/forge/impact/index.ts +222 -30
- package/src/forge/impact/types.ts +33 -1
- package/src/forge/intent/index.ts +35 -16
- package/src/forge/make/fields.ts +26 -0
- package/src/forge/make/index.ts +42 -6
- package/src/forge/make/templates.ts +211 -4
- package/src/forge/make/types.ts +2 -1
- package/src/forge/policy.ts +1 -1
- package/src/forge/react/index.ts +160 -2
- package/src/forge/refactor/index.ts +1 -0
- package/src/forge/repair/rules/index.ts +2 -2
- package/src/forge/repository-analysis/adapters/common.ts +72 -0
- package/src/forge/repository-analysis/adapters/docker.ts +185 -0
- package/src/forge/repository-analysis/adapters/java.ts +133 -0
- package/src/forge/repository-analysis/adapters/typescript.ts +350 -0
- package/src/forge/repository-analysis/adapters/vue.ts +71 -0
- package/src/forge/repository-analysis/analyze.ts +434 -0
- package/src/forge/repository-analysis/benchmark.ts +336 -0
- package/src/forge/repository-analysis/cache-gc.ts +154 -0
- package/src/forge/repository-analysis/check-selection.ts +123 -0
- package/src/forge/repository-analysis/context-node.ts +17 -0
- package/src/forge/repository-analysis/context.ts +456 -0
- package/src/forge/repository-analysis/http-resolution.ts +135 -0
- package/src/forge/repository-analysis/identity.ts +45 -0
- package/src/forge/repository-analysis/index.ts +18 -0
- package/src/forge/repository-analysis/nuxt-resolution.ts +188 -0
- package/src/forge/repository-analysis/quality.ts +60 -0
- package/src/forge/repository-analysis/retrieval.ts +309 -0
- package/src/forge/repository-analysis/runtime-artifacts.ts +195 -0
- package/src/forge/repository-analysis/runtime-observation.ts +325 -0
- package/src/forge/repository-analysis/scanner.ts +174 -0
- package/src/forge/repository-analysis/storage.ts +193 -0
- package/src/forge/repository-analysis/test-associations.ts +59 -0
- package/src/forge/repository-analysis/types.ts +99 -0
- package/src/forge/repository-manifest/index.ts +178 -0
- package/src/forge/repository-manifest/types.ts +63 -0
- package/src/forge/review/index.ts +162 -12
- package/src/forge/review/types.ts +15 -0
- package/src/forge/runtime/ai/providers.ts +19 -4
- package/src/forge/runtime/auth/config.ts +17 -0
- package/src/forge/runtime/auth/evaluate.ts +15 -2
- package/src/forge/runtime/auth/resolve.ts +61 -6
- package/src/forge/runtime/auth/types.ts +1 -0
- package/src/forge/runtime/db/factory.ts +1 -3
- package/src/forge/runtime/db/generated-client.ts +13 -2
- package/src/forge/runtime/db/memory-adapter.ts +139 -32
- package/src/forge/runtime/db/pglite-adapter.ts +285 -2
- package/src/forge/runtime/executor.ts +129 -16
- package/src/forge/runtime/external/bridge.ts +663 -0
- package/src/forge/runtime/runner/run-entry.ts +16 -7
- package/src/forge/runtime/telemetry/buffer.ts +4 -1
- package/src/forge/runtime/telemetry/scrubber.ts +35 -5
- package/src/forge/runtime/webhooks/security.ts +12 -7
- package/src/forge/server.ts +71 -7
- package/src/forge/ui/index.ts +831 -19
- package/src/forge/ui/types.ts +3 -1
- package/src/forge/version.ts +1 -1
- package/src/forge/vue/index.ts +422 -0
- package/src/forge/workspace/baseline.ts +112 -0
- package/src/forge/workspace/change-summary.ts +292 -0
- package/src/forge/workspace/forge-cli.ts +42 -0
- package/src/forge/workspace/git-summary.ts +393 -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 +34 -0
- package/templates/agent-workroom/pnpm-workspace.yaml +2 -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 +13 -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 +20 -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/agent-workroom/web/vite.config.ts +36 -0
- package/templates/b2b-support-web/package.json +2 -0
- package/templates/b2b-support-web/pnpm-workspace.yaml +2 -0
- package/templates/b2b-support-web/web/app/page.tsx +2 -2
- package/templates/b2b-support-web/web/lib/forge.ts +9 -2
- package/templates/b2b-support-web/web/next.config.ts +24 -0
- package/templates/b2b-support-web/web/package.json +1 -1
- package/templates/minimal-web/package.json +2 -1
- package/templates/minimal-web/pnpm-workspace.yaml +2 -0
- package/templates/minimal-web/web/index.html +1 -0
- package/templates/minimal-web/web/src/App.tsx +12 -6
- package/templates/minimal-web/web/src/lib/forge.ts +9 -2
- package/templates/minimal-web/web/src/styles.css +34 -0
- package/templates/minimal-web/web/vite.config.ts +36 -0
- package/templates/nuxt-web/.vscode/settings.json +14 -0
- package/templates/nuxt-web/.yarnrc.yml +1 -0
- package/templates/nuxt-web/README.md +30 -0
- package/templates/nuxt-web/forge.config.ts +3 -0
- package/templates/nuxt-web/package.json +37 -0
- package/templates/nuxt-web/pnpm-workspace.yaml +2 -0
- package/templates/nuxt-web/src/actions/logNoteCreated.ts +11 -0
- package/templates/nuxt-web/src/commands/createNote.ts +26 -0
- package/templates/nuxt-web/src/forge/schema.ts +12 -0
- package/templates/nuxt-web/src/policies.ts +6 -0
- package/templates/nuxt-web/src/queries/listNotes.ts +8 -0
- package/templates/nuxt-web/src/queries/liveNotes.ts +8 -0
- package/templates/nuxt-web/tsconfig.json +17 -0
- package/templates/nuxt-web/web/app.vue +67 -0
- package/templates/nuxt-web/web/components/LiveNotes.vue +89 -0
- package/templates/nuxt-web/web/components/NoteComposer.vue +100 -0
- package/templates/nuxt-web/web/composables/forge.ts +13 -0
- package/templates/nuxt-web/web/composables/useNotes.ts +24 -0
- package/templates/nuxt-web/web/nuxt.config.ts +11 -0
- package/templates/nuxt-web/web/package.json +22 -0
- package/templates/nuxt-web/web/plugins/forge.client.ts +10 -0
- package/templates/nuxt-web/web/plugins/forge.server.ts +10 -0
- package/templates/nuxt-web/web/server/api/forge-health.get.ts +7 -0
- package/templates/nuxt-web/web/tsconfig.json +6 -0
- package/templates/vendor-access/.vscode/settings.json +14 -0
- package/templates/vendor-access/README.md +30 -0
- package/templates/vendor-access/forge.config.ts +3 -0
- package/templates/vendor-access/package.json +35 -0
- package/templates/vendor-access/pnpm-workspace.yaml +2 -0
- package/templates/vendor-access/src/commands/addEvidence.ts +42 -0
- package/templates/vendor-access/src/commands/approveAccessRequest.ts +43 -0
- package/templates/vendor-access/src/commands/createAccessRequest.ts +49 -0
- package/templates/vendor-access/src/commands/seedVendorAccessDemo.ts +200 -0
- package/templates/vendor-access/src/forge/schema.ts +74 -0
- package/templates/vendor-access/src/policies.ts +11 -0
- package/templates/vendor-access/src/queries/listVendorAccessDashboard.ts +24 -0
- package/templates/vendor-access/src/queries/liveVendorAccessDashboard.ts +24 -0
- package/templates/vendor-access/tsconfig.json +17 -0
- package/templates/vendor-access/web/index.html +13 -0
- package/templates/vendor-access/web/package.json +21 -0
- package/templates/vendor-access/web/src/App.tsx +573 -0
- package/templates/vendor-access/web/src/lib/forge.ts +20 -0
- package/templates/vendor-access/web/src/main.tsx +205 -0
- package/templates/vendor-access/web/src/styles.css +682 -0
- package/templates/vendor-access/web/tsconfig.json +18 -0
- package/templates/vendor-access/web/vite.config.ts +36 -0
- 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 -7829
- package/src/forge/_generated/agentQuickstart.md +0 -34
- package/src/forge/_generated/agentTools.json +0 -2
- package/src/forge/_generated/agentTools.md +0 -16
- package/src/forge/_generated/agentTools.ts +0 -12
- package/src/forge/_generated/aiContext.ts +0 -125
- package/src/forge/_generated/aiModels.json +0 -2
- package/src/forge/_generated/aiModels.ts +0 -51
- 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 -31
- 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 -14937
- package/src/forge/_generated/appMap.md +0 -55
- 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 -62
- 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 -68
- 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 -177
- package/src/forge/_generated/makeTemplates.json +0 -2
- package/src/forge/_generated/makeTemplates.ts +0 -66
- package/src/forge/_generated/mockMap.json +0 -2
- package/src/forge/_generated/mockMap.ts +0 -7
- package/src/forge/_generated/operationPlaybooks.md +0 -167
- package/src/forge/_generated/packageGraph.json +0 -2
- package/src/forge/_generated/packageGraph.ts +0 -249334
- 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 -334130
- package/src/forge/_generated/runtimeRegistry.ts +0 -2
- package/src/forge/_generated/runtimeRules.md +0 -91
- 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 -3452
- 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
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { join } from "node:path";
|
|
1
|
+
import { dirname, extname, isAbsolute, join, relative, resolve } from "node:path";
|
|
2
2
|
import { nodeFileSystem } from "../fs/index.ts";
|
|
3
3
|
import type { ApiSurface } from "../api-surface/build.ts";
|
|
4
4
|
import type { ClassifiedPackage } from "../classifier/runtime-matrix.ts";
|
|
@@ -7,6 +7,7 @@ import { detectSecrets } from "../classifier/secrets.ts";
|
|
|
7
7
|
import { GENERATOR_VERSION } from "../emitter/constants.ts";
|
|
8
8
|
import { stripDeterministicHeader } from "../primitives/header.ts";
|
|
9
9
|
import { canonicalJson, normalizeNewlines, serializeCanonical } from "../primitives/serialize.ts";
|
|
10
|
+
import { toSnakeCase } from "../data-graph/sql/naming.ts";
|
|
10
11
|
import { resolveByPackageName } from "../recipes/registry.ts";
|
|
11
12
|
import {
|
|
12
13
|
defaultRuntimeCompatibility,
|
|
@@ -34,18 +35,30 @@ import type { QueryRegistry } from "../types/query-registry.ts";
|
|
|
34
35
|
import type { LiveQueryRegistry } from "../types/live-query-registry.ts";
|
|
35
36
|
import type { ClientManifest } from "../client-sdk/build-manifest.ts";
|
|
36
37
|
import type { FrontendGraph } from "../types/frontend-graph.ts";
|
|
38
|
+
import type {
|
|
39
|
+
ForgeExternalServiceEntry,
|
|
40
|
+
ForgeExternalServiceGraph,
|
|
41
|
+
} from "../external-manifest/types.ts";
|
|
37
42
|
import { createDiagnostic } from "../diagnostics/create.ts";
|
|
43
|
+
import { CAIR_SCHEMA_VERSION } from "../../cair/types.ts";
|
|
38
44
|
import { AUTH_ENV, DEFAULT_AUTH_CLAIMS } from "../../runtime/auth/config.ts";
|
|
45
|
+
import {
|
|
46
|
+
forgeCliCommandForWorkspace,
|
|
47
|
+
forgeCliCommandsForWorkspace,
|
|
48
|
+
shouldUseLocalForgeCli,
|
|
49
|
+
} from "../../workspace/forge-cli.ts";
|
|
39
50
|
import type {
|
|
40
51
|
AgentCapabilityMap,
|
|
41
52
|
AgentCapabilityMapEntry,
|
|
42
53
|
AgentContract,
|
|
43
54
|
AgentDependencyApiInfo,
|
|
55
|
+
AgentExternalEntryInfo,
|
|
44
56
|
AgentFrontendRuntimeBindingInfo,
|
|
45
57
|
AgentFrontendUsageInfo,
|
|
46
58
|
AgentHttpEndpointInfo,
|
|
47
59
|
AgentIntegrationInfo,
|
|
48
60
|
AgentRuntimeRule,
|
|
61
|
+
AgentProtocolInfo,
|
|
49
62
|
AgentToolRegistry,
|
|
50
63
|
AgentPlaybook,
|
|
51
64
|
} from "./types.ts";
|
|
@@ -53,6 +66,7 @@ import type {
|
|
|
53
66
|
const AGENTS_USER_START = "<!-- user-notes:start -->";
|
|
54
67
|
const AGENTS_USER_END = "<!-- user-notes:end -->";
|
|
55
68
|
const DEFAULT_USER_NOTES = "Project-specific notes can go here.";
|
|
69
|
+
const AGENTS_USER_NOTES_TOKEN = "__FORGE_AGENTS_USER_NOTES__";
|
|
56
70
|
|
|
57
71
|
export interface AgentContractInput {
|
|
58
72
|
workspaceRoot: string;
|
|
@@ -74,6 +88,7 @@ export interface AgentContractInput {
|
|
|
74
88
|
apiSurface: ApiSurface;
|
|
75
89
|
clientManifest: ClientManifest;
|
|
76
90
|
frontendGraph: FrontendGraph;
|
|
91
|
+
externalServices?: ForgeExternalServiceGraph;
|
|
77
92
|
}
|
|
78
93
|
|
|
79
94
|
export interface AgentContractArtifacts {
|
|
@@ -87,6 +102,7 @@ export interface AgentContractArtifacts {
|
|
|
87
102
|
runtimeRulesMd: string;
|
|
88
103
|
operationPlaybooksMd: string;
|
|
89
104
|
agentQuickstartMd: string;
|
|
105
|
+
agentCairGuideMd: string;
|
|
90
106
|
diagnostics: Diagnostic[];
|
|
91
107
|
}
|
|
92
108
|
|
|
@@ -170,17 +186,246 @@ function sourceText(workspaceRoot: string, file: string | undefined): string {
|
|
|
170
186
|
return nodeFileSystem.readText(absolute) ?? "";
|
|
171
187
|
}
|
|
172
188
|
|
|
189
|
+
function normalizeProjectPath(path: string): string {
|
|
190
|
+
return path.replace(/\\/g, "/").replace(/^\.\//, "");
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
function isWorkspaceChild(workspaceRoot: string, absolutePath: string): boolean {
|
|
194
|
+
const relativePath = relative(resolve(workspaceRoot), absolutePath);
|
|
195
|
+
return relativePath === "" || (!relativePath.startsWith("..") && !isAbsolute(relativePath));
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
function localImportSpecifiers(text: string): string[] {
|
|
199
|
+
const specifiers: string[] = [];
|
|
200
|
+
const importPattern =
|
|
201
|
+
/\b(?:import|export)\s+(type\s+)?(?:[^"'`]*?\s+from\s+)?["'`](\.{1,2}\/[^"'`]+)["'`]/g;
|
|
202
|
+
for (const match of text.matchAll(importPattern)) {
|
|
203
|
+
if (match[1]) {
|
|
204
|
+
continue;
|
|
205
|
+
}
|
|
206
|
+
const specifier = match[2] ?? "";
|
|
207
|
+
if (specifier) {
|
|
208
|
+
specifiers.push(specifier);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
return uniqueSorted(specifiers);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
function resolveLocalImport(workspaceRoot: string, fromFile: string, specifier: string): string | undefined {
|
|
215
|
+
const basePath = normalizeProjectPath(join(dirname(fromFile), specifier));
|
|
216
|
+
const candidates = extname(basePath)
|
|
217
|
+
? [basePath]
|
|
218
|
+
: [
|
|
219
|
+
`${basePath}.ts`,
|
|
220
|
+
`${basePath}.tsx`,
|
|
221
|
+
`${basePath}.js`,
|
|
222
|
+
`${basePath}.jsx`,
|
|
223
|
+
`${basePath}.mjs`,
|
|
224
|
+
`${basePath}.cjs`,
|
|
225
|
+
join(basePath, "index.ts"),
|
|
226
|
+
join(basePath, "index.tsx"),
|
|
227
|
+
join(basePath, "index.js"),
|
|
228
|
+
];
|
|
229
|
+
for (const candidate of candidates.map(normalizeProjectPath)) {
|
|
230
|
+
if (candidate.includes("/node_modules/") || candidate.startsWith("node_modules/")) {
|
|
231
|
+
continue;
|
|
232
|
+
}
|
|
233
|
+
if (candidate.startsWith("src/forge/_generated/")) {
|
|
234
|
+
continue;
|
|
235
|
+
}
|
|
236
|
+
const absolute = resolve(workspaceRoot, candidate);
|
|
237
|
+
if (!isWorkspaceChild(workspaceRoot, absolute) || !nodeFileSystem.exists(absolute)) {
|
|
238
|
+
continue;
|
|
239
|
+
}
|
|
240
|
+
return normalizeProjectPath(relative(resolve(workspaceRoot), absolute));
|
|
241
|
+
}
|
|
242
|
+
return undefined;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
function sourceTextWithLocalImports(
|
|
246
|
+
workspaceRoot: string,
|
|
247
|
+
file: string | undefined,
|
|
248
|
+
maxDepth = 2,
|
|
249
|
+
): string {
|
|
250
|
+
if (!file) {
|
|
251
|
+
return "";
|
|
252
|
+
}
|
|
253
|
+
const chunks: string[] = [];
|
|
254
|
+
const visited = new Set<string>();
|
|
255
|
+
|
|
256
|
+
const visit = (currentFile: string, depth: number): void => {
|
|
257
|
+
const normalizedFile = normalizeProjectPath(currentFile);
|
|
258
|
+
if (visited.has(normalizedFile)) {
|
|
259
|
+
return;
|
|
260
|
+
}
|
|
261
|
+
visited.add(normalizedFile);
|
|
262
|
+
const text = sourceText(workspaceRoot, normalizedFile);
|
|
263
|
+
if (!text) {
|
|
264
|
+
return;
|
|
265
|
+
}
|
|
266
|
+
chunks.push(text);
|
|
267
|
+
if (depth >= maxDepth) {
|
|
268
|
+
return;
|
|
269
|
+
}
|
|
270
|
+
for (const specifier of localImportSpecifiers(text)) {
|
|
271
|
+
const imported = resolveLocalImport(workspaceRoot, normalizedFile, specifier);
|
|
272
|
+
if (imported) {
|
|
273
|
+
visit(imported, depth + 1);
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
};
|
|
277
|
+
|
|
278
|
+
visit(file, 0);
|
|
279
|
+
return chunks.join("\n");
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
function escapeRegExp(value: string): string {
|
|
283
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
function toSnakeCaseName(name: string): string {
|
|
287
|
+
return name
|
|
288
|
+
.replace(/([a-z0-9])([A-Z])/g, "$1_$2")
|
|
289
|
+
.replace(/[-\s]+/g, "_")
|
|
290
|
+
.toLowerCase();
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
function toCamelCaseName(name: string): string {
|
|
294
|
+
return name.replace(/[_-]([a-zA-Z0-9])/g, (_match, char: string) => char.toUpperCase());
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
function dbTableLookup(dataGraph: AgentContractInput["dataGraph"]): Map<string, string> {
|
|
298
|
+
const lookup = new Map<string, string>();
|
|
299
|
+
for (const table of dataGraph.tables) {
|
|
300
|
+
lookup.set(table.name, table.name);
|
|
301
|
+
lookup.set(table.exportName, table.name);
|
|
302
|
+
lookup.set(toSnakeCaseName(table.name), table.name);
|
|
303
|
+
lookup.set(toSnakeCaseName(table.exportName), table.name);
|
|
304
|
+
lookup.set(toCamelCaseName(table.name), table.name);
|
|
305
|
+
lookup.set(toCamelCaseName(table.exportName), table.name);
|
|
306
|
+
}
|
|
307
|
+
return lookup;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
function addDbAliasesForText(
|
|
311
|
+
text: string,
|
|
312
|
+
tableLookup: Map<string, string>,
|
|
313
|
+
aliases: Map<string, string>,
|
|
314
|
+
): void {
|
|
315
|
+
for (const match of text.matchAll(
|
|
316
|
+
/\b(?:const|let|var)\s+([A-Za-z_$][A-Za-z0-9_$]*)\s*=\s*ctx\.db(?:\.([A-Za-z_$][A-Za-z0-9_$]*)|\[\s*["'`]([^"'`]+)["'`]\s*\])/g,
|
|
317
|
+
)) {
|
|
318
|
+
const alias = match[1] ?? "";
|
|
319
|
+
const table = match[2] ?? match[3] ?? "";
|
|
320
|
+
const canonicalTable = tableLookup.get(table);
|
|
321
|
+
if (alias && canonicalTable) {
|
|
322
|
+
aliases.set(alias, canonicalTable);
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
for (const match of text.matchAll(/\b(?:const|let|var)\s*\{([^}]+)\}\s*=\s*ctx\.db/g)) {
|
|
327
|
+
const body = match[1] ?? "";
|
|
328
|
+
for (const part of body.split(",")) {
|
|
329
|
+
const [rawTable, rawAlias] = part.split(":").map((value) => value.trim());
|
|
330
|
+
const table = rawTable?.replace(/["'`]/g, "") ?? "";
|
|
331
|
+
const alias = (rawAlias ?? rawTable ?? "").replace(/\s*=.*$/, "").trim();
|
|
332
|
+
const canonicalTable = tableLookup.get(table);
|
|
333
|
+
if (canonicalTable && alias) {
|
|
334
|
+
aliases.set(alias, canonicalTable);
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
function dbHelperOpsForText(text: string): Map<string, Set<string>> {
|
|
341
|
+
const helpers = new Map<string, Set<string>>();
|
|
342
|
+
const patterns = [
|
|
343
|
+
/\b(?:async\s+)?function\s+([A-Za-z_$][A-Za-z0-9_$]*)\s*(?:<[^>{}]*>)?\s*\(\s*([A-Za-z_$][A-Za-z0-9_$]*)[\s\S]*?\)\s*(?::[^{]+)?\{/g,
|
|
344
|
+
/\b(?:const|let|var)\s+([A-Za-z_$][A-Za-z0-9_$]*)\s*=\s*(?:async\s*)?(?:<[^>{}]*>\s*)?\(\s*([A-Za-z_$][A-Za-z0-9_$]*)[\s\S]*?\)\s*(?::[^=]+)?=>\s*\{/g,
|
|
345
|
+
];
|
|
346
|
+
|
|
347
|
+
for (const pattern of patterns) {
|
|
348
|
+
for (const match of text.matchAll(pattern)) {
|
|
349
|
+
const name = match[1] ?? "";
|
|
350
|
+
const tableParam = match[2] ?? "";
|
|
351
|
+
const start = match.index === undefined ? -1 : match.index + match[0].length;
|
|
352
|
+
if (!name || !tableParam || start < 0) {
|
|
353
|
+
continue;
|
|
354
|
+
}
|
|
355
|
+
let depth = 1;
|
|
356
|
+
let end = start;
|
|
357
|
+
for (; end < text.length; end++) {
|
|
358
|
+
const char = text[end];
|
|
359
|
+
if (char === "{") depth += 1;
|
|
360
|
+
if (char === "}") depth -= 1;
|
|
361
|
+
if (depth === 0) break;
|
|
362
|
+
}
|
|
363
|
+
const body = text.slice(start, end);
|
|
364
|
+
const ops = helpers.get(name) ?? new Set<string>();
|
|
365
|
+
const opPattern = new RegExp(`\\b${escapeRegExp(tableParam)}\\s*\\.\\s*([A-Za-z_$][A-Za-z0-9_$]*)`, "g");
|
|
366
|
+
for (const opMatch of body.matchAll(opPattern)) {
|
|
367
|
+
const op = opMatch[1] ?? "";
|
|
368
|
+
if (DB_READ_OPS.has(op) || DB_WRITE_OPS.has(op)) {
|
|
369
|
+
ops.add(op);
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
if (ops.size > 0) {
|
|
373
|
+
helpers.set(name, ops);
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
return helpers;
|
|
379
|
+
}
|
|
380
|
+
|
|
173
381
|
function dbTablesForText(
|
|
174
382
|
text: string,
|
|
175
|
-
|
|
383
|
+
tableLookup: Map<string, string>,
|
|
176
384
|
ops: Set<string>,
|
|
177
385
|
): string[] {
|
|
178
386
|
const tables: string[] = [];
|
|
179
387
|
for (const match of text.matchAll(/ctx\.db\.([A-Za-z_$][A-Za-z0-9_$]*)\s*\.\s*([A-Za-z_$][A-Za-z0-9_$]*)/g)) {
|
|
180
388
|
const table = match[1] ?? "";
|
|
181
389
|
const op = match[2] ?? "";
|
|
182
|
-
|
|
183
|
-
|
|
390
|
+
const canonicalTable = tableLookup.get(table);
|
|
391
|
+
if (canonicalTable && ops.has(op)) {
|
|
392
|
+
tables.push(canonicalTable);
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
for (const match of text.matchAll(/ctx\.db\s*\[\s*["'`]([^"'`]+)["'`]\s*\]\s*\.\s*([A-Za-z_$][A-Za-z0-9_$]*)/g)) {
|
|
396
|
+
const table = match[1] ?? "";
|
|
397
|
+
const op = match[2] ?? "";
|
|
398
|
+
const canonicalTable = tableLookup.get(table);
|
|
399
|
+
if (canonicalTable && ops.has(op)) {
|
|
400
|
+
tables.push(canonicalTable);
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
const aliases = new Map<string, string>();
|
|
404
|
+
addDbAliasesForText(text, tableLookup, aliases);
|
|
405
|
+
for (const [alias, table] of aliases) {
|
|
406
|
+
const aliasPattern = new RegExp(`\\b${escapeRegExp(alias)}\\s*\\.\\s*([A-Za-z_$][A-Za-z0-9_$]*)`, "g");
|
|
407
|
+
for (const match of text.matchAll(aliasPattern)) {
|
|
408
|
+
const op = match[1] ?? "";
|
|
409
|
+
if (ops.has(op)) {
|
|
410
|
+
tables.push(table);
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
const helperOps = dbHelperOpsForText(text);
|
|
415
|
+
for (const [helperName, helperTableOps] of helperOps) {
|
|
416
|
+
if (![...helperTableOps].some((op) => ops.has(op))) {
|
|
417
|
+
continue;
|
|
418
|
+
}
|
|
419
|
+
const helperCallPattern = new RegExp(
|
|
420
|
+
`\\b${escapeRegExp(helperName)}\\s*\\(\\s*ctx\\.db(?:\\.([A-Za-z_$][A-Za-z0-9_$]*)|\\[\\s*["'\`]([^"'\`]+)["'\`]\\s*\\])`,
|
|
421
|
+
"g",
|
|
422
|
+
);
|
|
423
|
+
for (const match of text.matchAll(helperCallPattern)) {
|
|
424
|
+
const table = match[1] ?? match[2] ?? "";
|
|
425
|
+
const canonicalTable = tableLookup.get(table);
|
|
426
|
+
if (canonicalTable) {
|
|
427
|
+
tables.push(canonicalTable);
|
|
428
|
+
}
|
|
184
429
|
}
|
|
185
430
|
}
|
|
186
431
|
return uniqueSorted(tables);
|
|
@@ -189,14 +434,14 @@ function dbTablesForText(
|
|
|
189
434
|
function dbTablesForFile(
|
|
190
435
|
workspaceRoot: string,
|
|
191
436
|
file: string | undefined,
|
|
192
|
-
|
|
437
|
+
tableLookup: Map<string, string>,
|
|
193
438
|
ops: Set<string>,
|
|
194
439
|
): string[] {
|
|
195
|
-
return dbTablesForText(
|
|
440
|
+
return dbTablesForText(sourceTextWithLocalImports(workspaceRoot, file), tableLookup, ops);
|
|
196
441
|
}
|
|
197
442
|
|
|
198
443
|
function emittedEventsForFile(workspaceRoot: string, file: string | undefined): string[] {
|
|
199
|
-
const text =
|
|
444
|
+
const text = sourceTextWithLocalImports(workspaceRoot, file);
|
|
200
445
|
return uniqueSorted(
|
|
201
446
|
[...text.matchAll(/ctx\.emit\s*\(\s*["'`]([^"'`]+)["'`]/g)]
|
|
202
447
|
.map((match) => match[1] ?? ""),
|
|
@@ -248,7 +493,7 @@ function runtimeRules(): AgentRuntimeRule[] {
|
|
|
248
493
|
{
|
|
249
494
|
context: "command",
|
|
250
495
|
allowed: ["ctx.db writes", "ctx.emit", "ctx.telemetry buffered events"],
|
|
251
|
-
forbidden: ["network packages", "ctx.secrets", "ctx.ai", "ctx.ai.runAgent", "ctx.agent.run", "
|
|
496
|
+
forbidden: ["network packages", "ctx.secrets", "ctx.ai", "ctx.ai.runAgent", "ctx.agent.run", "direct secret/env access", "filesystem access"],
|
|
252
497
|
},
|
|
253
498
|
{
|
|
254
499
|
context: "query",
|
|
@@ -273,6 +518,104 @@ function runtimeRules(): AgentRuntimeRule[] {
|
|
|
273
518
|
];
|
|
274
519
|
}
|
|
275
520
|
|
|
521
|
+
type TenantTableInfo = {
|
|
522
|
+
tenantIdColumn: string;
|
|
523
|
+
tenantField: string;
|
|
524
|
+
};
|
|
525
|
+
|
|
526
|
+
function buildTenantTableLookup(tenantScope: TenantScope, dataGraph: DataGraph): Map<string, TenantTableInfo> {
|
|
527
|
+
const lookup = new Map<string, TenantTableInfo>();
|
|
528
|
+
for (const scoped of tenantScope.tables) {
|
|
529
|
+
const table = dataGraph.tables.find((candidate) =>
|
|
530
|
+
candidate.name === scoped.table ||
|
|
531
|
+
candidate.exportName === scoped.exportName ||
|
|
532
|
+
toSnakeCase(candidate.name) === scoped.table ||
|
|
533
|
+
toSnakeCase(candidate.exportName) === scoped.table
|
|
534
|
+
);
|
|
535
|
+
const tenantField = table?.fields.find((field) => toSnakeCase(field.name) === scoped.tenantIdColumn)?.name ??
|
|
536
|
+
scoped.tenantIdColumn;
|
|
537
|
+
const info = { tenantIdColumn: scoped.tenantIdColumn, tenantField };
|
|
538
|
+
for (const key of uniqueSorted([
|
|
539
|
+
scoped.table,
|
|
540
|
+
scoped.exportName,
|
|
541
|
+
table?.name,
|
|
542
|
+
table?.exportName,
|
|
543
|
+
].filter((key): key is string => typeof key === "string" && key.length > 0))) {
|
|
544
|
+
lookup.set(key, info);
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
return lookup;
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
function agentProtocols(workspaceRoot: string): AgentProtocolInfo[] {
|
|
551
|
+
return [
|
|
552
|
+
{
|
|
553
|
+
id: "cair",
|
|
554
|
+
kind: "agent-protocol",
|
|
555
|
+
version: CAIR_SCHEMA_VERSION,
|
|
556
|
+
guide: "src/forge/_generated/agentCairGuide.md",
|
|
557
|
+
commands: forgeCliCommandsForWorkspace(workspaceRoot, [
|
|
558
|
+
"forge cair snapshot",
|
|
559
|
+
"forge cair query \"Q ST\"",
|
|
560
|
+
"forge cair query \"Q S name=<symbol>\"",
|
|
561
|
+
"forge cair query \"Q D S#1\"",
|
|
562
|
+
"forge cair query \"Q R S#1\"",
|
|
563
|
+
"forge cair query \"Q I S#1\"",
|
|
564
|
+
"forge cair action --plan \"A RN t=S#1 nn=<newName>\"",
|
|
565
|
+
"forge cair action \"A APPLY plan=<P#|path>\"",
|
|
566
|
+
"forge cair action \"A ROLLBACK journal=<path>\"",
|
|
567
|
+
]),
|
|
568
|
+
preferredFor: [
|
|
569
|
+
"compact repository orientation",
|
|
570
|
+
"symbol lookup before file reads",
|
|
571
|
+
"semantic code edits",
|
|
572
|
+
"guarded refactors",
|
|
573
|
+
"Forge-native feature creation",
|
|
574
|
+
"impact-aware test selection",
|
|
575
|
+
"token-efficient programming",
|
|
576
|
+
],
|
|
577
|
+
readQueries: [
|
|
578
|
+
"Q ST",
|
|
579
|
+
"Q S name=<symbol>",
|
|
580
|
+
"Q D S#1",
|
|
581
|
+
"Q R S#1",
|
|
582
|
+
"Q I S#1",
|
|
583
|
+
"Q T S#1",
|
|
584
|
+
"Q DEP.API package=<pkg> symbol=<export>",
|
|
585
|
+
],
|
|
586
|
+
mutationActions: [
|
|
587
|
+
"A RN t=S#1 nn=<newName>",
|
|
588
|
+
"A MV t=S#1 to=<path>",
|
|
589
|
+
"A OI f=M#1",
|
|
590
|
+
"A FMT f=M#1",
|
|
591
|
+
"A MC n=<command>",
|
|
592
|
+
"A MQ n=<query>",
|
|
593
|
+
"A MA n=<action>",
|
|
594
|
+
"A MT n=<table> fields=<fields>",
|
|
595
|
+
"A AT t=S#1 kind=unit",
|
|
596
|
+
"A WX t=S#1 file=src/index.ts",
|
|
597
|
+
"A APPLY plan=<P#|path>",
|
|
598
|
+
"A ROLLBACK journal=<path>",
|
|
599
|
+
],
|
|
600
|
+
compactAliases: [
|
|
601
|
+
"Q ST=Q STATUS",
|
|
602
|
+
"Q S=Q SYMBOL",
|
|
603
|
+
"Q D=Q DEF",
|
|
604
|
+
"Q R=Q REFS",
|
|
605
|
+
"Q I=Q IMPACT",
|
|
606
|
+
"A RN=A RENAME.SYMBOL",
|
|
607
|
+
"A MV=A MOVE.SYMBOL",
|
|
608
|
+
"A OI=A ORGANIZE.IMPORTS",
|
|
609
|
+
"A FMT=A FORMAT",
|
|
610
|
+
"A MC=A MAKE.COMMAND",
|
|
611
|
+
"A MT=A MAKE.TABLE",
|
|
612
|
+
"A AT=A ADD.TEST",
|
|
613
|
+
"A WX=A WIRE.EXPORT",
|
|
614
|
+
],
|
|
615
|
+
},
|
|
616
|
+
];
|
|
617
|
+
}
|
|
618
|
+
|
|
276
619
|
function playbooks(): AgentPlaybook[] {
|
|
277
620
|
return [
|
|
278
621
|
{
|
|
@@ -341,7 +684,7 @@ function playbooks(): AgentPlaybook[] {
|
|
|
341
684
|
"Prefer AI SDK ToolLoopAgent semantics through ctx.agent.run or ctx.ai.runAgent instead of custom loops.",
|
|
342
685
|
"Use stopWhen with stepCount or terminal tool calls to prevent unbounded loops.",
|
|
343
686
|
"Run agents only in actions, workflows, endpoints, or server code.",
|
|
344
|
-
"Run forge inspect
|
|
687
|
+
"Run forge inspect ai --json or forge agent print-context --json and confirm the generated context lists the agent.",
|
|
345
688
|
"Use forge ai trace <traceId> --json to inspect agent runs and tool calls.",
|
|
346
689
|
],
|
|
347
690
|
},
|
|
@@ -358,7 +701,7 @@ function playbooks(): AgentPlaybook[] {
|
|
|
358
701
|
{
|
|
359
702
|
title: "Scaffold a resource",
|
|
360
703
|
steps: [
|
|
361
|
-
"Run forge make resource <name> --fields name:type,status:enum
|
|
704
|
+
"Run forge make resource <name> --fields name:type,status:enum=open+closed --dry-run --json.",
|
|
362
705
|
"Review the plan and diagnostics.",
|
|
363
706
|
"Run forge make resource <name> --fields name:type --with-ui --yes when the resource should be visible in the web app.",
|
|
364
707
|
"Run forge generate.",
|
|
@@ -447,17 +790,17 @@ function playbooks(): AgentPlaybook[] {
|
|
|
447
790
|
"Run forge dev --once --json for a one-shot diagnostic cycle.",
|
|
448
791
|
"Use --api-only, --web-only, --no-watch, or --no-worker only when narrowing the loop intentionally.",
|
|
449
792
|
"When a web app exists, forge dev starts the API runtime and the web dev server together and prints both URLs.",
|
|
450
|
-
"Use generated client
|
|
793
|
+
"Use generated client bindings through web/lib/forge.ts, web/src/lib/forge.ts, or Nuxt web/composables/forge.ts.",
|
|
451
794
|
],
|
|
452
795
|
},
|
|
453
796
|
{
|
|
454
797
|
title: "Add or update frontend",
|
|
455
798
|
steps: [
|
|
456
|
-
"Run forge make ui --framework vite --dry-run --json when the app does not have a web root.",
|
|
799
|
+
"Run forge make ui --framework vite --dry-run --json or forge make ui --framework nuxt --dry-run --json when the app does not have a web root.",
|
|
457
800
|
"Run forge make ai-chat support --dry-run --json to add a chat surface backed by /ai/agents/chat streaming and /ai/agents/run JSON automation.",
|
|
458
|
-
"Use web/lib/forge.ts as the generated client bridge.",
|
|
459
|
-
"Mount ForgeProvider once in the web app provider/layout layer; use devAuth for local development.",
|
|
460
|
-
"Use useQuery
|
|
801
|
+
"Use web/lib/forge.ts, web/src/lib/forge.ts, or web/composables/forge.ts as the generated client bridge.",
|
|
802
|
+
"Mount ForgeProvider or install the Nuxt Forge plugin once in the web app provider/layout layer; use devAuth for local development.",
|
|
803
|
+
"Use useQuery/useCommand/useLiveQuery or useForgeQuery/useForgeCommand/useForgeLiveQuery instead of raw /commands or /queries fetches.",
|
|
461
804
|
"Run forge generate so frontendGraph and agentContract include routes and bindings.",
|
|
462
805
|
"Run forge inspect capabilities --json to confirm UI actions map to runtime capabilities.",
|
|
463
806
|
"Run forge dev --once --json and forge doctor --json.",
|
|
@@ -536,7 +879,11 @@ function runtimeEntriesWithoutFrontend(contract: AgentContract): AgentCapability
|
|
|
536
879
|
emits: commandEntry.emits,
|
|
537
880
|
dependencies: [],
|
|
538
881
|
},
|
|
539
|
-
notes: [
|
|
882
|
+
notes: [
|
|
883
|
+
commandEntry.source === "external"
|
|
884
|
+
? "External runtime entry is imported from a Forge manifest; execution requires an external runtime bridge."
|
|
885
|
+
: "Runtime entry is available to agents even though no frontend usage was detected.",
|
|
886
|
+
],
|
|
540
887
|
});
|
|
541
888
|
}
|
|
542
889
|
}
|
|
@@ -557,7 +904,11 @@ function runtimeEntriesWithoutFrontend(contract: AgentContract): AgentCapability
|
|
|
557
904
|
emits: [],
|
|
558
905
|
dependencies: [],
|
|
559
906
|
},
|
|
560
|
-
notes: [
|
|
907
|
+
notes: [
|
|
908
|
+
queryEntry.source === "external"
|
|
909
|
+
? "External runtime entry is imported from a Forge manifest; execution requires an external runtime bridge."
|
|
910
|
+
: "Runtime entry is available to agents even though no frontend usage was detected.",
|
|
911
|
+
],
|
|
561
912
|
});
|
|
562
913
|
}
|
|
563
914
|
}
|
|
@@ -703,9 +1054,15 @@ function buildAgentToolRegistry(contract: AgentContract): AgentToolRegistry {
|
|
|
703
1054
|
dependencies: [],
|
|
704
1055
|
readOnly: false,
|
|
705
1056
|
risk: "write" as const,
|
|
706
|
-
needsApproval:
|
|
1057
|
+
needsApproval: command.source === "external"
|
|
1058
|
+
? command.external?.needsApproval ?? (command.external?.risk !== "read")
|
|
1059
|
+
: true,
|
|
707
1060
|
requiresAuth: command.policy !== undefined && command.policy !== "public",
|
|
708
|
-
|
|
1061
|
+
...(command.source ? { source: command.source } : {}),
|
|
1062
|
+
...(command.external ? { external: command.external } : {}),
|
|
1063
|
+
execution: command.source === "external"
|
|
1064
|
+
? "external-runtime-endpoint" as const
|
|
1065
|
+
: "forge-runtime-endpoint" as const,
|
|
709
1066
|
})),
|
|
710
1067
|
...contract.queries.map((query) => ({
|
|
711
1068
|
name: autoToolName("query", query.name),
|
|
@@ -723,7 +1080,11 @@ function buildAgentToolRegistry(contract: AgentContract): AgentToolRegistry {
|
|
|
723
1080
|
risk: "read" as const,
|
|
724
1081
|
needsApproval: false,
|
|
725
1082
|
requiresAuth: query.policy !== undefined && query.policy !== "public",
|
|
726
|
-
|
|
1083
|
+
...(query.source ? { source: query.source } : {}),
|
|
1084
|
+
...(query.external ? { external: query.external } : {}),
|
|
1085
|
+
execution: query.source === "external"
|
|
1086
|
+
? "external-runtime-endpoint" as const
|
|
1087
|
+
: "forge-runtime-endpoint" as const,
|
|
727
1088
|
})),
|
|
728
1089
|
...contract.liveQueries.map((liveQuery) => ({
|
|
729
1090
|
name: autoToolName("liveQuery", liveQuery.name),
|
|
@@ -741,6 +1102,7 @@ function buildAgentToolRegistry(contract: AgentContract): AgentToolRegistry {
|
|
|
741
1102
|
risk: "read" as const,
|
|
742
1103
|
needsApproval: false,
|
|
743
1104
|
requiresAuth: liveQuery.policy !== undefined && liveQuery.policy !== "public",
|
|
1105
|
+
source: "local" as const,
|
|
744
1106
|
execution: "forge-runtime-endpoint" as const,
|
|
745
1107
|
})),
|
|
746
1108
|
].sort((a, b) => a.name.localeCompare(b.name));
|
|
@@ -794,6 +1156,39 @@ function httpEndpointFor(
|
|
|
794
1156
|
};
|
|
795
1157
|
}
|
|
796
1158
|
|
|
1159
|
+
function externalEndpointFor(entry: ForgeExternalServiceEntry): AgentHttpEndpointInfo {
|
|
1160
|
+
const encodedService = encodeURIComponent(entry.service);
|
|
1161
|
+
const encodedName = encodeURIComponent(entry.name);
|
|
1162
|
+
const collection = entry.kind === "query" ? "queries" : "commands";
|
|
1163
|
+
return {
|
|
1164
|
+
method: entry.method ?? "POST",
|
|
1165
|
+
path: entry.path ?? `/external/${encodedService}/${collection}/${encodedName}`,
|
|
1166
|
+
exampleBody: { args: {} },
|
|
1167
|
+
};
|
|
1168
|
+
}
|
|
1169
|
+
|
|
1170
|
+
function externalEntryInfo(entry: ForgeExternalServiceEntry): AgentExternalEntryInfo {
|
|
1171
|
+
return {
|
|
1172
|
+
service: entry.service,
|
|
1173
|
+
language: entry.language,
|
|
1174
|
+
...(entry.framework ? { framework: entry.framework } : {}),
|
|
1175
|
+
transport: entry.transport,
|
|
1176
|
+
...(entry.transaction ? { transaction: entry.transaction } : {}),
|
|
1177
|
+
...(entry.risk ? { risk: entry.risk } : {}),
|
|
1178
|
+
...(typeof entry.needsApproval === "boolean" ? { needsApproval: entry.needsApproval } : {}),
|
|
1179
|
+
effects: entry.effects ?? [],
|
|
1180
|
+
...(entry.description ? { description: entry.description } : {}),
|
|
1181
|
+
};
|
|
1182
|
+
}
|
|
1183
|
+
|
|
1184
|
+
function externalFrontendUsage(entry: ForgeExternalServiceEntry): AgentFrontendUsageInfo {
|
|
1185
|
+
return {
|
|
1186
|
+
hook: `external manifest '${entry.service}.${entry.name}'; runtime bridge required before client invocation`,
|
|
1187
|
+
routes: [],
|
|
1188
|
+
components: [],
|
|
1189
|
+
};
|
|
1190
|
+
}
|
|
1191
|
+
|
|
797
1192
|
function frontendUsageFor(
|
|
798
1193
|
frontendGraph: FrontendGraph,
|
|
799
1194
|
kind: "command" | "query" | "liveQuery" | "action",
|
|
@@ -901,9 +1296,7 @@ export function buildAgentContractArtifacts(
|
|
|
901
1296
|
input: AgentContractInput,
|
|
902
1297
|
): AgentContractArtifacts {
|
|
903
1298
|
const project = readPackageInfo(input.workspaceRoot);
|
|
904
|
-
const tenantTables =
|
|
905
|
-
input.tenantScope.tables.map((table) => [table.table, table.tenantIdColumn]),
|
|
906
|
-
);
|
|
1299
|
+
const tenantTables = buildTenantTableLookup(input.tenantScope, input.dataGraph);
|
|
907
1300
|
const commandAuth = new Map(
|
|
908
1301
|
input.policyRegistry.commandAuth.map((binding) => [binding.commandName, binding.auth]),
|
|
909
1302
|
);
|
|
@@ -915,16 +1308,18 @@ export function buildAgentContractArtifacts(
|
|
|
915
1308
|
);
|
|
916
1309
|
|
|
917
1310
|
const runtimeEntries = new Map(input.runtimeGraph.entries.map((entry) => [entry.name, entry]));
|
|
918
|
-
const
|
|
919
|
-
const
|
|
1311
|
+
const tableLookup = dbTableLookup(input.dataGraph);
|
|
1312
|
+
const externalEntries = input.externalServices?.services.flatMap((service) => service.entries) ?? [];
|
|
1313
|
+
const localCommandInfos: AgentContract["commands"] = sorted(Object.keys(input.apiSurface.commands), (name) => name).map((name) => {
|
|
920
1314
|
const entry = runtimeEntries.get(name);
|
|
921
1315
|
const file = entry?.file ?? "";
|
|
922
1316
|
return {
|
|
923
1317
|
name,
|
|
924
1318
|
file,
|
|
1319
|
+
source: "local" as const,
|
|
925
1320
|
policy: authPolicy(commandAuth.get(name)),
|
|
926
|
-
tablesRead: dbTablesForFile(input.workspaceRoot, file,
|
|
927
|
-
tablesWritten: dbTablesForFile(input.workspaceRoot, file,
|
|
1321
|
+
tablesRead: dbTablesForFile(input.workspaceRoot, file, tableLookup, DB_READ_OPS),
|
|
1322
|
+
tablesWritten: dbTablesForFile(input.workspaceRoot, file, tableLookup, DB_WRITE_OPS),
|
|
928
1323
|
emits: emittedEventsForFile(input.workspaceRoot, file),
|
|
929
1324
|
allowedPackages: entry ? packageNamesForModule(input.appGraph, entry.moduleId) : [],
|
|
930
1325
|
forbiddenCapabilities: forbiddenForContext(input.classified, "command"),
|
|
@@ -932,21 +1327,62 @@ export function buildAgentContractArtifacts(
|
|
|
932
1327
|
frontend: frontendUsageFor(input.frontendGraph, "command", name),
|
|
933
1328
|
};
|
|
934
1329
|
});
|
|
935
|
-
const
|
|
1330
|
+
const externalCommandInfos: AgentContract["commands"] = externalEntries
|
|
1331
|
+
.filter((entry) => entry.kind === "command")
|
|
1332
|
+
.map((entry) => ({
|
|
1333
|
+
name: `${entry.service}.${entry.name}`,
|
|
1334
|
+
file: `external:${entry.service}`,
|
|
1335
|
+
source: "external" as const,
|
|
1336
|
+
external: externalEntryInfo(entry),
|
|
1337
|
+
...(entry.policy ? { policy: entry.policy } : {}),
|
|
1338
|
+
tablesRead: [],
|
|
1339
|
+
tablesWritten: entry.transaction === "read-only" ? [] : [`external:${entry.service}`],
|
|
1340
|
+
emits: entry.effects ?? [],
|
|
1341
|
+
allowedPackages: [],
|
|
1342
|
+
forbiddenCapabilities: [],
|
|
1343
|
+
http: externalEndpointFor(entry),
|
|
1344
|
+
frontend: externalFrontendUsage(entry),
|
|
1345
|
+
}));
|
|
1346
|
+
const commandInfos: AgentContract["commands"] = sorted(
|
|
1347
|
+
[...localCommandInfos, ...externalCommandInfos],
|
|
1348
|
+
(command) => command.name,
|
|
1349
|
+
);
|
|
1350
|
+
const localQueryInfos: AgentContract["queries"] = sorted(input.queryRegistry.queries, (query) => query.name).map((query) => ({
|
|
936
1351
|
name: query.name,
|
|
937
1352
|
file: query.file,
|
|
1353
|
+
source: "local" as const,
|
|
938
1354
|
policy: authPolicy(queryAuth.get(query.name)),
|
|
939
1355
|
readOnly: true,
|
|
940
1356
|
tenantScoped: input.tenantScope.tables.length > 0,
|
|
941
|
-
tablesRead: dbTablesForFile(input.workspaceRoot, query.file,
|
|
1357
|
+
tablesRead: dbTablesForFile(input.workspaceRoot, query.file, tableLookup, DB_READ_OPS),
|
|
942
1358
|
allowedPackages: packageNamesForModule(input.appGraph, query.moduleId),
|
|
943
1359
|
forbiddenCapabilities: forbiddenForContext(input.classified, "query"),
|
|
944
1360
|
http: httpEndpointFor("query", query.name),
|
|
945
1361
|
frontend: frontendUsageFor(input.frontendGraph, "query", query.name),
|
|
946
1362
|
}));
|
|
1363
|
+
const externalQueryInfos: AgentContract["queries"] = externalEntries
|
|
1364
|
+
.filter((entry) => entry.kind === "query")
|
|
1365
|
+
.map((entry) => ({
|
|
1366
|
+
name: `${entry.service}.${entry.name}`,
|
|
1367
|
+
file: `external:${entry.service}`,
|
|
1368
|
+
source: "external" as const,
|
|
1369
|
+
external: externalEntryInfo(entry),
|
|
1370
|
+
...(entry.policy ? { policy: entry.policy } : {}),
|
|
1371
|
+
readOnly: true as const,
|
|
1372
|
+
tenantScoped: entry.tenantScoped ?? false,
|
|
1373
|
+
tablesRead: [`external:${entry.service}`],
|
|
1374
|
+
allowedPackages: [],
|
|
1375
|
+
forbiddenCapabilities: [],
|
|
1376
|
+
http: externalEndpointFor(entry),
|
|
1377
|
+
frontend: externalFrontendUsage(entry),
|
|
1378
|
+
}));
|
|
1379
|
+
const queryInfos: AgentContract["queries"] = sorted(
|
|
1380
|
+
[...localQueryInfos, ...externalQueryInfos],
|
|
1381
|
+
(query) => query.name,
|
|
1382
|
+
);
|
|
947
1383
|
const liveQueryInfos: AgentContract["liveQueries"] = sorted(input.liveQueryRegistry.liveQueries, (liveQuery) => liveQuery.name).map(
|
|
948
1384
|
(liveQuery) => {
|
|
949
|
-
const tablesRead = dbTablesForFile(input.workspaceRoot, liveQuery.file,
|
|
1385
|
+
const tablesRead = dbTablesForFile(input.workspaceRoot, liveQuery.file, tableLookup, DB_READ_OPS);
|
|
950
1386
|
return {
|
|
951
1387
|
name: liveQuery.name,
|
|
952
1388
|
file: liveQuery.file,
|
|
@@ -968,6 +1404,7 @@ export function buildAgentContractArtifacts(
|
|
|
968
1404
|
queries: queryInfos,
|
|
969
1405
|
liveQueries: liveQueryInfos,
|
|
970
1406
|
});
|
|
1407
|
+
const protocols = agentProtocols(input.workspaceRoot);
|
|
971
1408
|
const contract: AgentContract = {
|
|
972
1409
|
schemaVersion: "0.1.0",
|
|
973
1410
|
generatorVersion: GENERATOR_VERSION,
|
|
@@ -1003,18 +1440,22 @@ export function buildAgentContractArtifacts(
|
|
|
1003
1440
|
}),
|
|
1004
1441
|
),
|
|
1005
1442
|
data: {
|
|
1006
|
-
tables: sorted(input.dataGraph.tables, (table) => table.name).map((table) =>
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1443
|
+
tables: sorted(input.dataGraph.tables, (table) => table.name).map((table) => {
|
|
1444
|
+
const tenantInfo = tenantTables.get(table.name);
|
|
1445
|
+
return {
|
|
1446
|
+
name: table.name,
|
|
1447
|
+
file: table.file,
|
|
1448
|
+
tenantScoped: Boolean(tenantInfo),
|
|
1449
|
+
...(tenantInfo ? { tenantField: tenantInfo.tenantField } : {}),
|
|
1450
|
+
fields: uniqueSorted(table.fields.map((field) => field.name)),
|
|
1451
|
+
};
|
|
1452
|
+
}),
|
|
1013
1453
|
},
|
|
1014
1454
|
policies: sorted(input.policyRegistry.policies, (policy) => policy.name).map((policy) => ({
|
|
1015
1455
|
name: policy.name,
|
|
1016
1456
|
kind: policy.kind,
|
|
1017
1457
|
roles: uniqueSorted(policy.roles),
|
|
1458
|
+
permissions: uniqueSorted(policy.permissions ?? []),
|
|
1018
1459
|
file: policy.file,
|
|
1019
1460
|
})),
|
|
1020
1461
|
packages: sorted(input.packageGraph.packages, (pkg) => pkg.name).map((pkg) => {
|
|
@@ -1028,6 +1469,19 @@ export function buildAgentContractArtifacts(
|
|
|
1028
1469
|
}),
|
|
1029
1470
|
dependencyApis: buildDependencyApis(input.packageGraph),
|
|
1030
1471
|
integrations: buildIntegrations(input.classified),
|
|
1472
|
+
externalServices: (input.externalServices?.services ?? []).map((service) => ({
|
|
1473
|
+
name: service.name,
|
|
1474
|
+
language: service.language,
|
|
1475
|
+
...(service.framework ? { framework: service.framework } : {}),
|
|
1476
|
+
transport: service.transport,
|
|
1477
|
+
...(service.baseUrl ? { baseUrl: service.baseUrl } : {}),
|
|
1478
|
+
...(service.command ? { command: service.command } : {}),
|
|
1479
|
+
...(service.health ? { health: service.health } : {}),
|
|
1480
|
+
commands: sorted(service.entries.filter((entry) => entry.kind === "command"), (entry) => entry.name)
|
|
1481
|
+
.map((entry) => `${service.name}.${entry.name}`),
|
|
1482
|
+
queries: sorted(service.entries.filter((entry) => entry.kind === "query"), (entry) => entry.name)
|
|
1483
|
+
.map((entry) => `${service.name}.${entry.name}`),
|
|
1484
|
+
})),
|
|
1031
1485
|
secrets: sorted(input.secretRegistry.secrets, (secret) => secret.name).map((secret) => ({
|
|
1032
1486
|
name: secret.name,
|
|
1033
1487
|
integration: secret.integration,
|
|
@@ -1141,10 +1595,11 @@ export function buildAgentContractArtifacts(
|
|
|
1141
1595
|
},
|
|
1142
1596
|
rules: runtimeRules(),
|
|
1143
1597
|
playbooks: playbooks(),
|
|
1598
|
+
agentProtocols: protocols,
|
|
1144
1599
|
commandsToRun: {
|
|
1145
|
-
beforeEditing: ["forge do inspect --json", "forge dev --once --json", "forge
|
|
1146
|
-
afterEditing: ["forge generate", "forge check", "forge verify --standard",
|
|
1147
|
-
dev: ["forge dev", "forge dev --once --json", "forge do fix --json", "forge do verify --json", "forge dev --api-only", "forge dev --web-only"],
|
|
1600
|
+
beforeEditing: forgeCliCommandsForWorkspace(input.workspaceRoot, ["forge agent onboard --target codex --json", "forge status --json", "forge changed --json", "forge handoff --json", "forge do inspect --json", "forge cair snapshot", "forge cair query \"Q ST\"", "forge dev --once --json", "forge agent print-context --json", "forge check --json"]),
|
|
1601
|
+
afterEditing: forgeCliCommandsForWorkspace(input.workspaceRoot, ["forge generate", "forge check", "forge verify --standard", finalVerifyCommand(input.workspaceRoot)]),
|
|
1602
|
+
dev: forgeCliCommandsForWorkspace(input.workspaceRoot, ["forge dev", "forge dev --once --json", "forge handoff --json", "forge do fix --json", "forge do verify --json", "forge dev --api-only", "forge dev --web-only"]),
|
|
1148
1603
|
},
|
|
1149
1604
|
};
|
|
1150
1605
|
|
|
@@ -1153,7 +1608,7 @@ export function buildAgentContractArtifacts(
|
|
|
1153
1608
|
? (nodeFileSystem.readText(existingAgentsPath) ?? "")
|
|
1154
1609
|
: null;
|
|
1155
1610
|
const userNotes = extractUserNotes(existingAgents);
|
|
1156
|
-
const agentsMd = renderAgentsMd(contract, userNotes);
|
|
1611
|
+
const agentsMd = renderAgentsMd(contract, userNotes, input.workspaceRoot);
|
|
1157
1612
|
const toolRegistry = buildAgentToolRegistry(contract);
|
|
1158
1613
|
const capabilityMap = buildCapabilityMap(contract);
|
|
1159
1614
|
const capabilityMapMd = renderCapabilityMapMd(capabilityMap);
|
|
@@ -1161,7 +1616,8 @@ export function buildAgentContractArtifacts(
|
|
|
1161
1616
|
const appMapMd = renderAppMapMd(contract);
|
|
1162
1617
|
const runtimeRulesMd = renderRuntimeRulesMd(contract.rules);
|
|
1163
1618
|
const operationPlaybooksMd = renderOperationPlaybooksMd(contract.playbooks);
|
|
1164
|
-
const agentQuickstartMd = renderAgentQuickstartMd();
|
|
1619
|
+
const agentQuickstartMd = renderAgentQuickstartMd(input.workspaceRoot);
|
|
1620
|
+
const agentCairGuideMd = renderAgentCairGuideMd(contract, input.workspaceRoot);
|
|
1165
1621
|
const diagnostics = scanAgentContractForLeaks(contract, [
|
|
1166
1622
|
agentsMd,
|
|
1167
1623
|
agentToolsMd,
|
|
@@ -1170,6 +1626,7 @@ export function buildAgentContractArtifacts(
|
|
|
1170
1626
|
runtimeRulesMd,
|
|
1171
1627
|
operationPlaybooksMd,
|
|
1172
1628
|
agentQuickstartMd,
|
|
1629
|
+
agentCairGuideMd,
|
|
1173
1630
|
]);
|
|
1174
1631
|
|
|
1175
1632
|
return {
|
|
@@ -1183,6 +1640,7 @@ export function buildAgentContractArtifacts(
|
|
|
1183
1640
|
runtimeRulesMd,
|
|
1184
1641
|
operationPlaybooksMd,
|
|
1185
1642
|
agentQuickstartMd,
|
|
1643
|
+
agentCairGuideMd,
|
|
1186
1644
|
diagnostics: [...diagnostics, ...capabilityMap.diagnostics],
|
|
1187
1645
|
};
|
|
1188
1646
|
}
|
|
@@ -1229,7 +1687,22 @@ export function serializeAgentToolRegistryTs(registry: AgentToolRegistry): strin
|
|
|
1229
1687
|
return `export const agentTools = ${JSON.stringify(parsed, null, 2)} as const;\n`;
|
|
1230
1688
|
}
|
|
1231
1689
|
|
|
1232
|
-
function
|
|
1690
|
+
function localizeForgeCliMarkdown(workspaceRoot: string, markdown: string): string {
|
|
1691
|
+
return shouldUseLocalForgeCli(workspaceRoot)
|
|
1692
|
+
? markdown.replace(/\bforge (?=[a-z])/g, "node bin/forge.mjs ")
|
|
1693
|
+
: markdown;
|
|
1694
|
+
}
|
|
1695
|
+
|
|
1696
|
+
function finalVerifyCommand(workspaceRoot: string): string {
|
|
1697
|
+
const command = shouldUseLocalForgeCli(workspaceRoot) ? "forge verify framework" : "forge verify --strict";
|
|
1698
|
+
return forgeCliCommandForWorkspace(workspaceRoot, command);
|
|
1699
|
+
}
|
|
1700
|
+
|
|
1701
|
+
function renderAgentsMd(contract: AgentContract, userNotes: string, workspaceRoot: string): string {
|
|
1702
|
+
const finalVerify = finalVerifyCommand(workspaceRoot);
|
|
1703
|
+
const cliEntrypoint = shouldUseLocalForgeCli(workspaceRoot)
|
|
1704
|
+
? "This is the ForgeOS framework checkout. Use `node bin/forge.mjs ...` so maintainer commands run against this source tree; reserve the global `forge` command for installed-package smoke tests."
|
|
1705
|
+
: "Use the installed `forge` command for app workflows.";
|
|
1233
1706
|
const tenantTables = contract.data.tables
|
|
1234
1707
|
.filter((table) => table.tenantScoped)
|
|
1235
1708
|
.map((table) => `${table.name} via ${table.tenantField}`);
|
|
@@ -1244,7 +1717,7 @@ function renderAgentsMd(contract: AgentContract, userNotes: string): string {
|
|
|
1244
1717
|
`${agent.name}: ${agent.provider}/${agent.model} with ${agent.tools.length > 0 ? agent.tools.join(", ") : "no tools"}`,
|
|
1245
1718
|
);
|
|
1246
1719
|
|
|
1247
|
-
|
|
1720
|
+
const generated = localizeForgeCliMarkdown(workspaceRoot, `# AGENTS.md
|
|
1248
1721
|
|
|
1249
1722
|
<!-- forge-generated:start -->
|
|
1250
1723
|
|
|
@@ -1252,23 +1725,51 @@ function renderAgentsMd(contract: AgentContract, userNotes: string): string {
|
|
|
1252
1725
|
|
|
1253
1726
|
This is a ForgeOS application named \`${contract.project.name}\`.
|
|
1254
1727
|
|
|
1728
|
+
## CLI entrypoint
|
|
1729
|
+
|
|
1730
|
+
${cliEntrypoint}
|
|
1731
|
+
|
|
1255
1732
|
## Required workflow
|
|
1256
1733
|
|
|
1257
1734
|
Before editing:
|
|
1258
1735
|
|
|
1259
1736
|
\`\`\`bash
|
|
1737
|
+
forge agent onboard --target codex --json
|
|
1738
|
+
forge status --json
|
|
1739
|
+
forge changed --json
|
|
1740
|
+
forge handoff --json
|
|
1260
1741
|
forge do inspect --json
|
|
1261
1742
|
forge dev --once --json
|
|
1262
|
-
forge
|
|
1743
|
+
forge agent print-context --json
|
|
1263
1744
|
forge check --json
|
|
1264
1745
|
\`\`\`
|
|
1265
1746
|
|
|
1747
|
+
## CAIR first
|
|
1748
|
+
|
|
1749
|
+
Before reading large files or hand-writing patches, prefer the generated CAIR guide:
|
|
1750
|
+
|
|
1751
|
+
\`\`\`bash
|
|
1752
|
+
forge cair snapshot
|
|
1753
|
+
forge cair query "Q ST"
|
|
1754
|
+
forge cair query "Q S name=<symbol>"
|
|
1755
|
+
forge cair query "Q D S#1"
|
|
1756
|
+
forge cair query "Q R S#1"
|
|
1757
|
+
forge cair query "Q I S#1"
|
|
1758
|
+
\`\`\`
|
|
1759
|
+
|
|
1760
|
+
Use \`src/forge/_generated/agentCairGuide.md\` for the full compact protocol. Plan CAIR mutations before applying them:
|
|
1761
|
+
|
|
1762
|
+
\`\`\`bash
|
|
1763
|
+
forge cair action --plan "A RN t=S#1 nn=<newName>"
|
|
1764
|
+
forge cair action "A APPLY plan=<returned-plan-path>"
|
|
1765
|
+
\`\`\`
|
|
1766
|
+
|
|
1266
1767
|
After editing:
|
|
1267
1768
|
|
|
1268
1769
|
\`\`\`bash
|
|
1269
1770
|
forge generate
|
|
1270
1771
|
forge check
|
|
1271
|
-
|
|
1772
|
+
${finalVerify}
|
|
1272
1773
|
\`\`\`
|
|
1273
1774
|
|
|
1274
1775
|
## Do not edit
|
|
@@ -1296,7 +1797,7 @@ Template apps may ignore \`src/forge/_generated/**\` and \`forge.lock\` in git t
|
|
|
1296
1797
|
## Runtime rules
|
|
1297
1798
|
|
|
1298
1799
|
- Do not import network packages inside \`command\`, \`query\`, or \`liveQuery\`.
|
|
1299
|
-
- Do not
|
|
1800
|
+
- Do not read secrets or server runtime config through \`process.env\` in Forge runtime code; use \`ctx.secrets\` or generated config context. Public frontend bridge env such as \`NEXT_PUBLIC_*\` and \`NUXT_PUBLIC_*\` is allowed in web bridge files.
|
|
1300
1801
|
- Do not access cross-tenant data.
|
|
1301
1802
|
- Commands must use \`ctx.emit\` for side effects.
|
|
1302
1803
|
- Actions and workflows handle side effects after commit.
|
|
@@ -1310,8 +1811,10 @@ forge do fix --json
|
|
|
1310
1811
|
forge do verify --json
|
|
1311
1812
|
forge dev --once --json
|
|
1312
1813
|
forge dev
|
|
1814
|
+
forge handoff --json
|
|
1313
1815
|
forge inspect app --json
|
|
1314
1816
|
forge inspect all --json
|
|
1817
|
+
forge inspect all --full --json
|
|
1315
1818
|
forge inspect frontend --json
|
|
1316
1819
|
forge inspect capabilities --json
|
|
1317
1820
|
forge inspect agent-tools --json
|
|
@@ -1328,12 +1831,13 @@ forge doctor
|
|
|
1328
1831
|
forge doctor windows --json
|
|
1329
1832
|
forge setup windows --json
|
|
1330
1833
|
forge agent print-context --json
|
|
1834
|
+
forge agent doctor --target codex --json
|
|
1331
1835
|
forge ai tools --json
|
|
1332
1836
|
forge ai agents --json
|
|
1333
1837
|
forge ai trace <traceId> --json
|
|
1334
1838
|
forge verify --smoke
|
|
1335
1839
|
forge verify --standard
|
|
1336
|
-
|
|
1840
|
+
${finalVerify}
|
|
1337
1841
|
\`\`\`
|
|
1338
1842
|
|
|
1339
1843
|
## Data
|
|
@@ -1388,9 +1892,9 @@ ${contract.frontend.dev ? `- Web URL: ${contract.frontend.dev.url}
|
|
|
1388
1892
|
|
|
1389
1893
|
Rules:
|
|
1390
1894
|
|
|
1391
|
-
- Use the local \`web/**/lib/forge.ts\` bridge to generated
|
|
1392
|
-
- Mount \`<ForgeProvider devAuth>\` in local development.
|
|
1393
|
-
- Use \`useQuery
|
|
1895
|
+
- Use the local \`web/**/lib/forge.ts\` or Nuxt \`web/composables/forge.ts\` bridge to generated bindings.
|
|
1896
|
+
- Mount \`<ForgeProvider devAuth>\` or install the Nuxt Forge plugin in local development.
|
|
1897
|
+
- Use \`useQuery\`/\`useCommand\`/\`useLiveQuery\` or \`useForgeQuery\`/\`useForgeCommand\`/\`useForgeLiveQuery\` instead of raw Forge endpoint fetches in components.
|
|
1394
1898
|
- Keep frontend routes reflected in \`src/forge/_generated/frontendGraph.json\`.
|
|
1395
1899
|
|
|
1396
1900
|
## Common tasks
|
|
@@ -1413,16 +1917,17 @@ forge do verify --json
|
|
|
1413
1917
|
1. Add file in \`src/commands\`.
|
|
1414
1918
|
2. Declare \`auth: can("...")\`.
|
|
1415
1919
|
3. Run \`forge generate\`.
|
|
1416
|
-
4. Run
|
|
1920
|
+
4. Run \`${finalVerify}\`.
|
|
1417
1921
|
|
|
1418
1922
|
### Scaffold a resource
|
|
1419
1923
|
|
|
1420
1924
|
Use:
|
|
1421
1925
|
|
|
1422
1926
|
\`\`\`bash
|
|
1423
|
-
forge make resource <name> --fields title:text,status:enum
|
|
1424
|
-
forge make resource <name> --fields title:text,status:enum
|
|
1927
|
+
forge make resource <name> --fields title:text,status:enum=open+closed --dry-run --json
|
|
1928
|
+
forge make resource <name> --fields title:text,status:enum=open+closed --with-ui --yes
|
|
1425
1929
|
forge make ui --framework vite --dry-run --json
|
|
1930
|
+
forge make ui --framework nuxt --dry-run --json
|
|
1426
1931
|
forge make ai-chat support --dry-run --json
|
|
1427
1932
|
\`\`\`
|
|
1428
1933
|
|
|
@@ -1439,7 +1944,7 @@ forge inspect frontend --json
|
|
|
1439
1944
|
forge inspect capabilities --json
|
|
1440
1945
|
\`\`\`
|
|
1441
1946
|
|
|
1442
|
-
\`forge dev\` starts the API runtime and web app together when \`web/\` exists. \`forge dev --once --json\` reports routes, components,
|
|
1947
|
+
\`forge dev\` starts the API runtime and web app together when \`web/\` exists. \`forge dev --once --json\` reports routes, components, providers/plugins, bridge files, generated client bindings, direct runtime fetch warnings, capability-map parity warnings, and fix hints.
|
|
1443
1948
|
|
|
1444
1949
|
### Apply a feature blueprint
|
|
1445
1950
|
|
|
@@ -1479,7 +1984,7 @@ forge test run --changed --timeout-ms 120000 --json
|
|
|
1479
1984
|
forge verify --standard
|
|
1480
1985
|
\`\`\`
|
|
1481
1986
|
|
|
1482
|
-
Use \`forge verify --standard\` for the normal agent development loop. Finish handoffs with \`
|
|
1987
|
+
Use \`forge verify --standard\` for the normal agent development loop. Finish handoffs with \`${finalVerify}\` when the change is ready.
|
|
1483
1988
|
|
|
1484
1989
|
### Repair a failing check
|
|
1485
1990
|
|
|
@@ -1498,7 +2003,8 @@ Use:
|
|
|
1498
2003
|
|
|
1499
2004
|
\`\`\`bash
|
|
1500
2005
|
forge generate
|
|
1501
|
-
forge inspect
|
|
2006
|
+
forge inspect ai --json
|
|
2007
|
+
forge agent print-context --json
|
|
1502
2008
|
forge ai check --json
|
|
1503
2009
|
forge ai trace <traceId> --json
|
|
1504
2010
|
\`\`\`
|
|
@@ -1537,7 +2043,7 @@ forge deps upgrade-plan <package> --to latest
|
|
|
1537
2043
|
forge deps inspect <package> --json
|
|
1538
2044
|
forge deps api <package> <symbol> --json
|
|
1539
2045
|
forge deps upgrade-apply <plan>
|
|
1540
|
-
|
|
2046
|
+
${finalVerify}
|
|
1541
2047
|
\`\`\`
|
|
1542
2048
|
|
|
1543
2049
|
Do not manually edit \`package.json\` for package upgrades unless necessary.
|
|
@@ -1558,10 +2064,11 @@ Durable invalidations live in \`_forge_live_invalidations\`.
|
|
|
1558
2064
|
|
|
1559
2065
|
${AGENTS_USER_START}
|
|
1560
2066
|
|
|
1561
|
-
${
|
|
2067
|
+
${AGENTS_USER_NOTES_TOKEN}
|
|
1562
2068
|
|
|
1563
2069
|
${AGENTS_USER_END}
|
|
1564
2070
|
`);
|
|
2071
|
+
return normalizeNewlines(generated.replace(AGENTS_USER_NOTES_TOKEN, () => userNotes));
|
|
1565
2072
|
}
|
|
1566
2073
|
|
|
1567
2074
|
function renderAppMapMd(contract: AgentContract): string {
|
|
@@ -1922,21 +2429,27 @@ function renderOperationPlaybooksMd(playbookEntries: AgentPlaybook[]): string {
|
|
|
1922
2429
|
return normalizeNewlines(lines.join("\n"));
|
|
1923
2430
|
}
|
|
1924
2431
|
|
|
1925
|
-
function renderAgentQuickstartMd(): string {
|
|
1926
|
-
|
|
2432
|
+
function renderAgentQuickstartMd(workspaceRoot: string): string {
|
|
2433
|
+
const finalVerify = finalVerifyCommand(workspaceRoot);
|
|
2434
|
+
return normalizeNewlines(localizeForgeCliMarkdown(workspaceRoot, `# Agent Quickstart
|
|
1927
2435
|
|
|
1928
2436
|
Run:
|
|
1929
2437
|
|
|
1930
2438
|
\`\`\`bash
|
|
2439
|
+
forge agent onboard --target codex --json
|
|
2440
|
+
forge status --json
|
|
2441
|
+
forge changed --json
|
|
2442
|
+
forge handoff --json
|
|
1931
2443
|
forge do inspect --json
|
|
1932
2444
|
forge do fix --json
|
|
1933
2445
|
forge do verify --json
|
|
1934
2446
|
forge dev --once --json
|
|
1935
2447
|
forge dev
|
|
1936
|
-
forge
|
|
2448
|
+
forge agent print-context --json
|
|
1937
2449
|
forge inspect frontend --json
|
|
1938
2450
|
forge inspect capabilities --json
|
|
1939
2451
|
forge inspect agent-tools --json
|
|
2452
|
+
forge inspect all --json
|
|
1940
2453
|
forge check --json
|
|
1941
2454
|
forge ai trace <traceId> --json
|
|
1942
2455
|
\`\`\`
|
|
@@ -1954,7 +2467,158 @@ Always finish with:
|
|
|
1954
2467
|
|
|
1955
2468
|
\`\`\`bash
|
|
1956
2469
|
forge generate
|
|
1957
|
-
|
|
2470
|
+
${finalVerify}
|
|
1958
2471
|
\`\`\`
|
|
1959
|
-
`);
|
|
2472
|
+
`));
|
|
2473
|
+
}
|
|
2474
|
+
|
|
2475
|
+
function renderAgentCairGuideMd(contract: AgentContract, workspaceRoot: string): string {
|
|
2476
|
+
const cair = contract.agentProtocols.find((protocol) => protocol.id === "cair");
|
|
2477
|
+
const finalVerify = finalVerifyCommand(workspaceRoot);
|
|
2478
|
+
const summary = [
|
|
2479
|
+
`commands=${contract.commands.length}`,
|
|
2480
|
+
`queries=${contract.queries.length}`,
|
|
2481
|
+
`liveQueries=${contract.liveQueries.length}`,
|
|
2482
|
+
`actions=${contract.actions.length}`,
|
|
2483
|
+
`workflows=${contract.workflows.length}`,
|
|
2484
|
+
`tables=${contract.data.tables.length}`,
|
|
2485
|
+
].join(" ");
|
|
2486
|
+
return normalizeNewlines(localizeForgeCliMarkdown(workspaceRoot, `# CAIR Agent Guide
|
|
2487
|
+
|
|
2488
|
+
Project: ${contract.project.name}
|
|
2489
|
+
CAIR version: ${cair?.version ?? CAIR_SCHEMA_VERSION}
|
|
2490
|
+
Surface: ${summary}
|
|
2491
|
+
|
|
2492
|
+
CAIR is the compact agent protocol for reading and changing this Forge workspace. Use it before opening whole files when symbol, module, dependency, test, or impact context is enough.
|
|
2493
|
+
|
|
2494
|
+
## First commands
|
|
2495
|
+
|
|
2496
|
+
\`\`\`bash
|
|
2497
|
+
forge cair snapshot
|
|
2498
|
+
forge cair query "Q ST"
|
|
2499
|
+
\`\`\`
|
|
2500
|
+
|
|
2501
|
+
The snapshot emits compact ids:
|
|
2502
|
+
|
|
2503
|
+
- \`M#\` modules/files
|
|
2504
|
+
- \`S#\` symbols
|
|
2505
|
+
- \`P#\` packages
|
|
2506
|
+
- \`API#\` dependency APIs
|
|
2507
|
+
- \`T#\` tests
|
|
2508
|
+
|
|
2509
|
+
## Read before editing
|
|
2510
|
+
|
|
2511
|
+
\`\`\`bash
|
|
2512
|
+
forge cair query "Q S name=<symbol>"
|
|
2513
|
+
forge cair query "Q D S#1"
|
|
2514
|
+
forge cair query "Q R S#1"
|
|
2515
|
+
forge cair query "Q I S#1"
|
|
2516
|
+
forge cair query "Q T S#1"
|
|
2517
|
+
forge cair query "Q DEP.API package=<pkg> symbol=<export>"
|
|
2518
|
+
\`\`\`
|
|
2519
|
+
|
|
2520
|
+
Only open source files after CAIR shows that the exact file or body is needed.
|
|
2521
|
+
|
|
2522
|
+
## Plan, apply, rollback
|
|
2523
|
+
|
|
2524
|
+
Never apply semantic mutations first. Create a plan:
|
|
2525
|
+
|
|
2526
|
+
\`\`\`bash
|
|
2527
|
+
forge cair action --plan "A RN t=S#1 nn=<newName>"
|
|
2528
|
+
\`\`\`
|
|
2529
|
+
|
|
2530
|
+
Apply the returned plan path:
|
|
2531
|
+
|
|
2532
|
+
\`\`\`bash
|
|
2533
|
+
forge cair action "A APPLY plan=<P#|.forge/cair/plans/...json>"
|
|
2534
|
+
\`\`\`
|
|
2535
|
+
|
|
2536
|
+
Keep returned journal paths for rollback:
|
|
2537
|
+
|
|
2538
|
+
\`\`\`bash
|
|
2539
|
+
forge cair action "A ROLLBACK journal=.forge/cair/journal/<journal>.json"
|
|
2540
|
+
\`\`\`
|
|
2541
|
+
|
|
2542
|
+
## Semantic actions
|
|
2543
|
+
|
|
2544
|
+
\`\`\`txt
|
|
2545
|
+
A RN t=S#1 nn=<newName>
|
|
2546
|
+
A MV t=S#1 to=src/target.ts
|
|
2547
|
+
A SIG t=S#1 signature="export function x(input: string): boolean"
|
|
2548
|
+
A PARAM t=S#1 name=tenantId type=string default="defaultTenant"
|
|
2549
|
+
A CALLS t=S#1 appendArg="defaultTenant"
|
|
2550
|
+
A OI f=M#1
|
|
2551
|
+
A FMT f=M#1
|
|
2552
|
+
\`\`\`
|
|
2553
|
+
|
|
2554
|
+
For high-risk semantic actions, include expectations when available:
|
|
2555
|
+
|
|
2556
|
+
\`\`\`txt
|
|
2557
|
+
expect.file=src/path.ts
|
|
2558
|
+
expect.kind=command
|
|
2559
|
+
expect.hash=<sha256>
|
|
2560
|
+
\`\`\`
|
|
2561
|
+
|
|
2562
|
+
## Forge-native actions
|
|
2563
|
+
|
|
2564
|
+
Prefer Forge-native CAIR actions over hand-writing boilerplate:
|
|
2565
|
+
|
|
2566
|
+
\`\`\`txt
|
|
2567
|
+
A MC n=createTicket
|
|
2568
|
+
A MQ n=listTickets
|
|
2569
|
+
A MA n=chargeCustomer
|
|
2570
|
+
A MT n=tickets fields=title:text,status:text
|
|
2571
|
+
A AT t=S#1 kind=unit
|
|
2572
|
+
A WX t=S#1 file=src/index.ts
|
|
2573
|
+
\`\`\`
|
|
2574
|
+
|
|
2575
|
+
## Compact aliases
|
|
2576
|
+
|
|
2577
|
+
Queries:
|
|
2578
|
+
|
|
2579
|
+
\`\`\`txt
|
|
2580
|
+
Q ST = Q STATUS
|
|
2581
|
+
Q S = Q SYMBOL
|
|
2582
|
+
Q D = Q DEF
|
|
2583
|
+
Q R = Q REFS
|
|
2584
|
+
Q I = Q IMPACT
|
|
2585
|
+
Q M = Q MODULE
|
|
2586
|
+
Q T = Q TESTS
|
|
2587
|
+
Q API = Q DEP.API
|
|
2588
|
+
\`\`\`
|
|
2589
|
+
|
|
2590
|
+
Actions:
|
|
2591
|
+
|
|
2592
|
+
\`\`\`txt
|
|
2593
|
+
A RN = A RENAME.SYMBOL
|
|
2594
|
+
A MV = A MOVE.SYMBOL
|
|
2595
|
+
A OI = A ORGANIZE.IMPORTS
|
|
2596
|
+
A FMT = A FORMAT
|
|
2597
|
+
A MC = A MAKE.COMMAND
|
|
2598
|
+
A MQ = A MAKE.QUERY
|
|
2599
|
+
A MA = A MAKE.ACTION
|
|
2600
|
+
A MT = A MAKE.TABLE
|
|
2601
|
+
A AT = A ADD.TEST
|
|
2602
|
+
A WX = A WIRE.EXPORT
|
|
2603
|
+
A AP = A APPLY
|
|
2604
|
+
A RB = A ROLLBACK
|
|
2605
|
+
\`\`\`
|
|
2606
|
+
|
|
2607
|
+
## Verification
|
|
2608
|
+
|
|
2609
|
+
After CAIR edits, run the narrowest useful checks:
|
|
2610
|
+
|
|
2611
|
+
\`\`\`bash
|
|
2612
|
+
forge check --json
|
|
2613
|
+
forge verify --standard
|
|
2614
|
+
${finalVerify}
|
|
2615
|
+
\`\`\`
|
|
2616
|
+
|
|
2617
|
+
## Constraints
|
|
2618
|
+
|
|
2619
|
+
- Do not edit \`src/forge/_generated/**\` unless explicitly allowed.
|
|
2620
|
+
- Do not bypass \`--plan\` for semantic edits.
|
|
2621
|
+
- Do not use CAIR as blind text replacement when a semantic action exists.
|
|
2622
|
+
- Use TypeScript language service, ast-grep, ts-morph, or raw file reads only as implementation backends or fallbacks. CAIR is the agent-facing protocol.
|
|
2623
|
+
`));
|
|
1960
2624
|
}
|