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
|
@@ -0,0 +1,543 @@
|
|
|
1
|
+
import type { DbAdapter } from "../runtime/db/adapter.ts";
|
|
2
|
+
import { AgentFabricError } from "./errors.ts";
|
|
3
|
+
import { digestCanonical, sha256Digest, stableStringify } from "./canonical.ts";
|
|
4
|
+
import type { LocalPatchEvidence } from "./local-coding-worker.ts";
|
|
5
|
+
import type { LocalVerificationCommandEvidence, LocalVerificationEvidence } from "./local-verification.ts";
|
|
6
|
+
import {
|
|
7
|
+
validateLocalCodingTaskProposal,
|
|
8
|
+
type ValidatedLocalCodingTaskProposal,
|
|
9
|
+
} from "./local-task-contract.ts";
|
|
10
|
+
import type { Digest } from "./types.ts";
|
|
11
|
+
|
|
12
|
+
const CREATE_TASKS_TABLE = `
|
|
13
|
+
CREATE TABLE IF NOT EXISTS _forge_agent_fabric_local_tasks (
|
|
14
|
+
task_id TEXT PRIMARY KEY,
|
|
15
|
+
repository_root TEXT NOT NULL,
|
|
16
|
+
proposal_digest TEXT NOT NULL UNIQUE,
|
|
17
|
+
proposal_json TEXT NOT NULL,
|
|
18
|
+
state TEXT NOT NULL CHECK (state IN ('proposed', 'rejected')),
|
|
19
|
+
created_at BIGINT NOT NULL,
|
|
20
|
+
decided_at BIGINT
|
|
21
|
+
)`;
|
|
22
|
+
|
|
23
|
+
const CREATE_PATCHES_TABLE = `
|
|
24
|
+
CREATE TABLE IF NOT EXISTS _forge_agent_fabric_local_patches (
|
|
25
|
+
task_id TEXT PRIMARY KEY,
|
|
26
|
+
evidence_json TEXT NOT NULL
|
|
27
|
+
)`;
|
|
28
|
+
|
|
29
|
+
const CREATE_DECISIONS_TABLE = `
|
|
30
|
+
CREATE TABLE IF NOT EXISTS _forge_agent_fabric_local_patch_decisions (
|
|
31
|
+
task_id TEXT PRIMARY KEY,
|
|
32
|
+
diff_digest TEXT NOT NULL,
|
|
33
|
+
decision TEXT NOT NULL CHECK (decision IN ('approved', 'rejected')),
|
|
34
|
+
decided_at BIGINT NOT NULL
|
|
35
|
+
)`;
|
|
36
|
+
|
|
37
|
+
const CREATE_VERIFICATIONS_TABLE = `
|
|
38
|
+
CREATE TABLE IF NOT EXISTS _forge_agent_fabric_local_verifications (
|
|
39
|
+
task_id TEXT PRIMARY KEY,
|
|
40
|
+
diff_digest TEXT NOT NULL,
|
|
41
|
+
request_digest TEXT NOT NULL,
|
|
42
|
+
state TEXT NOT NULL CHECK (state IN ('started', 'finished')),
|
|
43
|
+
evidence_json TEXT,
|
|
44
|
+
evidence_digest TEXT
|
|
45
|
+
)`;
|
|
46
|
+
|
|
47
|
+
const CREATE_VERIFICATION_DISPATCHES_TABLE = `
|
|
48
|
+
CREATE TABLE IF NOT EXISTS _forge_agent_fabric_local_verification_dispatches (
|
|
49
|
+
task_id TEXT PRIMARY KEY,
|
|
50
|
+
request_digest TEXT NOT NULL
|
|
51
|
+
)`;
|
|
52
|
+
|
|
53
|
+
const CREATE_VERIFICATION_COMMANDS_TABLE = `
|
|
54
|
+
CREATE TABLE IF NOT EXISTS _forge_agent_fabric_local_verification_commands (
|
|
55
|
+
task_id TEXT NOT NULL,
|
|
56
|
+
ordinal INTEGER NOT NULL CHECK (ordinal BETWEEN 0 AND 3),
|
|
57
|
+
request_digest TEXT NOT NULL,
|
|
58
|
+
descriptor_digest TEXT NOT NULL,
|
|
59
|
+
effect_kind TEXT CHECK (effect_kind IS NULL OR effect_kind = 'local_docker_node_test_v1'),
|
|
60
|
+
container_name TEXT,
|
|
61
|
+
state TEXT NOT NULL CHECK (state IN ('intent', 'receipted')),
|
|
62
|
+
evidence_json TEXT,
|
|
63
|
+
evidence_digest TEXT,
|
|
64
|
+
PRIMARY KEY (task_id, ordinal)
|
|
65
|
+
)`;
|
|
66
|
+
|
|
67
|
+
const CREATE_MATERIALIZATIONS_TABLE = `
|
|
68
|
+
CREATE TABLE IF NOT EXISTS _forge_agent_fabric_local_materializations (
|
|
69
|
+
task_id TEXT PRIMARY KEY,
|
|
70
|
+
result_digest TEXT NOT NULL,
|
|
71
|
+
state TEXT NOT NULL CHECK (state IN ('started', 'receipted')),
|
|
72
|
+
diff_digest TEXT
|
|
73
|
+
)`;
|
|
74
|
+
|
|
75
|
+
export interface LocalMaterializationRecord {
|
|
76
|
+
resultDigest: Digest;
|
|
77
|
+
state: "started" | "receipted";
|
|
78
|
+
diffDigest?: Digest;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export interface LocalVerificationRecord {
|
|
82
|
+
diffDigest: Digest;
|
|
83
|
+
requestDigest: Digest;
|
|
84
|
+
state: "started" | "finished";
|
|
85
|
+
containerDispatched: boolean;
|
|
86
|
+
evidence?: LocalVerificationEvidence;
|
|
87
|
+
evidenceDigest?: Digest;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export interface LocalVerificationCommandRecord {
|
|
91
|
+
ordinal: number;
|
|
92
|
+
descriptorDigest: Digest;
|
|
93
|
+
containerName: string | null;
|
|
94
|
+
state: "intent" | "receipted";
|
|
95
|
+
evidence?: LocalVerificationCommandEvidence;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export interface LocalTaskRecord extends ValidatedLocalCodingTaskProposal {
|
|
99
|
+
taskId: string;
|
|
100
|
+
repositoryRoot: string;
|
|
101
|
+
state: "proposed" | "rejected";
|
|
102
|
+
createdAt: number;
|
|
103
|
+
decidedAt: number | null;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function taskIdFor(digest: Digest): string {
|
|
107
|
+
return `task:${digest.slice("sha256:".length)}`;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export class LocalTaskInbox {
|
|
111
|
+
private schemaReady?: Promise<unknown>;
|
|
112
|
+
private patchSchemaReady?: Promise<unknown>;
|
|
113
|
+
private decisionSchemaReady?: Promise<unknown>;
|
|
114
|
+
private verificationSchemaReady?: Promise<unknown>;
|
|
115
|
+
private verificationDispatchSchemaReady?: Promise<unknown>;
|
|
116
|
+
private verificationCommandsSchemaReady?: Promise<unknown>;
|
|
117
|
+
private materializationSchemaReady?: Promise<unknown>;
|
|
118
|
+
|
|
119
|
+
constructor(private readonly adapter: DbAdapter) {
|
|
120
|
+
if (adapter.kind !== "pglite") {
|
|
121
|
+
throw new AgentFabricError("AF_INVALID_STATE", "Local task inbox requires PGlite");
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
private async ready(): Promise<void> {
|
|
126
|
+
this.schemaReady ??= this.adapter.query(CREATE_TASKS_TABLE);
|
|
127
|
+
await this.schemaReady;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
async propose(
|
|
131
|
+
input: unknown,
|
|
132
|
+
repositoryRoot: string,
|
|
133
|
+
now = Date.now(),
|
|
134
|
+
): Promise<LocalTaskRecord> {
|
|
135
|
+
const validated = validateLocalCodingTaskProposal(input);
|
|
136
|
+
if (validated.proposal.limits.expiresAt <= now) {
|
|
137
|
+
throw new AgentFabricError("AF_INVALID_STATE", "Local coding task has expired");
|
|
138
|
+
}
|
|
139
|
+
const taskId = taskIdFor(validated.proposalDigest);
|
|
140
|
+
await this.ready();
|
|
141
|
+
await this.adapter.query(
|
|
142
|
+
`INSERT INTO _forge_agent_fabric_local_tasks
|
|
143
|
+
(task_id, repository_root, proposal_digest, proposal_json, state, created_at)
|
|
144
|
+
VALUES ($1, $2, $3, $4, 'proposed', $5)
|
|
145
|
+
ON CONFLICT (task_id) DO NOTHING`,
|
|
146
|
+
[taskId, repositoryRoot, validated.proposalDigest,
|
|
147
|
+
JSON.stringify(validated.proposal), now],
|
|
148
|
+
);
|
|
149
|
+
const record = await this.get(taskId);
|
|
150
|
+
if (!record || record.repositoryRoot !== repositoryRoot ||
|
|
151
|
+
record.proposalDigest !== validated.proposalDigest) {
|
|
152
|
+
throw new AgentFabricError("AF_CONFLICT", "Task identity is already bound to another repository or revision");
|
|
153
|
+
}
|
|
154
|
+
return record;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
async get(taskId: string): Promise<LocalTaskRecord | null> {
|
|
158
|
+
if (!/^task:[0-9a-f]{64}$/u.test(taskId)) {
|
|
159
|
+
throw new AgentFabricError("AF_INVALID_STATE", "Invalid local task identity");
|
|
160
|
+
}
|
|
161
|
+
await this.ready();
|
|
162
|
+
const result = await this.adapter.query(
|
|
163
|
+
`SELECT task_id, repository_root, proposal_digest, proposal_json, state, created_at, decided_at
|
|
164
|
+
FROM _forge_agent_fabric_local_tasks WHERE task_id = $1`,
|
|
165
|
+
[taskId],
|
|
166
|
+
);
|
|
167
|
+
const row = result.rows[0];
|
|
168
|
+
if (!row) return null;
|
|
169
|
+
let parsed: unknown;
|
|
170
|
+
try {
|
|
171
|
+
parsed = JSON.parse(String(row.proposal_json));
|
|
172
|
+
} catch {
|
|
173
|
+
throw new AgentFabricError("AF_INVALID_STATE", "Stored task proposal is not JSON");
|
|
174
|
+
}
|
|
175
|
+
const validated = validateLocalCodingTaskProposal(parsed, "stored");
|
|
176
|
+
if (row.task_id !== taskId || row.proposal_digest !== validated.proposalDigest ||
|
|
177
|
+
taskIdFor(validated.proposalDigest) !== taskId ||
|
|
178
|
+
(row.state !== "proposed" && row.state !== "rejected") ||
|
|
179
|
+
typeof row.repository_root !== "string" || !row.repository_root) {
|
|
180
|
+
throw new AgentFabricError("AF_INVALID_STATE", "Stored task proposal is inconsistent");
|
|
181
|
+
}
|
|
182
|
+
return {
|
|
183
|
+
taskId,
|
|
184
|
+
repositoryRoot: row.repository_root,
|
|
185
|
+
...validated,
|
|
186
|
+
state: row.state,
|
|
187
|
+
createdAt: Number(row.created_at),
|
|
188
|
+
decidedAt: row.decided_at === null ? null : Number(row.decided_at),
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
async reject(taskId: string, expectedDigest: Digest, now = Date.now()): Promise<void> {
|
|
193
|
+
await this.ready();
|
|
194
|
+
const result = await this.adapter.query(
|
|
195
|
+
`UPDATE _forge_agent_fabric_local_tasks SET state = 'rejected', decided_at = $3
|
|
196
|
+
WHERE task_id = $1 AND proposal_digest = $2 AND state = 'proposed'`,
|
|
197
|
+
[taskId, expectedDigest, now],
|
|
198
|
+
);
|
|
199
|
+
if (result.rowCount !== 1) {
|
|
200
|
+
throw new AgentFabricError("AF_CONFLICT", "Task is stale or already reviewed");
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
async recordPatch(taskId: string, evidence: LocalPatchEvidence): Promise<void> {
|
|
205
|
+
await this.ready();
|
|
206
|
+
this.patchSchemaReady ??= this.adapter.query(CREATE_PATCHES_TABLE);
|
|
207
|
+
await this.patchSchemaReady;
|
|
208
|
+
const encoded = stableStringify(evidence);
|
|
209
|
+
await this.adapter.query(
|
|
210
|
+
`INSERT INTO _forge_agent_fabric_local_patches (task_id, evidence_json)
|
|
211
|
+
VALUES ($1, $2) ON CONFLICT (task_id) DO NOTHING`,
|
|
212
|
+
[taskId, encoded],
|
|
213
|
+
);
|
|
214
|
+
const stored = await this.getPatch(taskId);
|
|
215
|
+
if (!stored || stableStringify(stored) !== encoded) {
|
|
216
|
+
throw new AgentFabricError("AF_CONFLICT", "Task already has different patch evidence");
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
async getPatch(taskId: string): Promise<LocalPatchEvidence | null> {
|
|
221
|
+
this.patchSchemaReady ??= this.adapter.query(CREATE_PATCHES_TABLE);
|
|
222
|
+
await this.patchSchemaReady;
|
|
223
|
+
const result = await this.adapter.query(
|
|
224
|
+
`SELECT evidence_json FROM _forge_agent_fabric_local_patches WHERE task_id = $1`,
|
|
225
|
+
[taskId],
|
|
226
|
+
);
|
|
227
|
+
const encoded = result.rows[0]?.evidence_json;
|
|
228
|
+
if (typeof encoded !== "string") return null;
|
|
229
|
+
try {
|
|
230
|
+
return JSON.parse(encoded) as LocalPatchEvidence;
|
|
231
|
+
} catch {
|
|
232
|
+
throw new AgentFabricError("AF_INVALID_STATE", "Stored patch evidence is not JSON");
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
async beginMaterialization(taskId: string, resultDigest: Digest): Promise<void> {
|
|
237
|
+
this.materializationSchemaReady ??= this.adapter.query(CREATE_MATERIALIZATIONS_TABLE);
|
|
238
|
+
await this.materializationSchemaReady;
|
|
239
|
+
const inserted = await this.adapter.query(
|
|
240
|
+
`INSERT INTO _forge_agent_fabric_local_materializations
|
|
241
|
+
(task_id, result_digest, state) VALUES ($1, $2, 'started')
|
|
242
|
+
ON CONFLICT (task_id) DO NOTHING`, [taskId, resultDigest],
|
|
243
|
+
);
|
|
244
|
+
if (inserted.rowCount !== 1) {
|
|
245
|
+
throw new AgentFabricError("AF_CONFLICT", "Patch materialization already started; reconcile its receipt before retrying");
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
async receiptMaterialization(taskId: string, resultDigest: Digest, diffDigest: Digest): Promise<void> {
|
|
250
|
+
const patch = await this.getPatch(taskId);
|
|
251
|
+
if (!patch || patch.diffDigest !== diffDigest) {
|
|
252
|
+
throw new AgentFabricError("AF_CONFLICT", "Materialization receipt has no matching patch readback");
|
|
253
|
+
}
|
|
254
|
+
const updated = await this.adapter.query(
|
|
255
|
+
`UPDATE _forge_agent_fabric_local_materializations SET state = 'receipted', diff_digest = $3
|
|
256
|
+
WHERE task_id = $1 AND result_digest = $2 AND state = 'started'`,
|
|
257
|
+
[taskId, resultDigest, diffDigest],
|
|
258
|
+
);
|
|
259
|
+
if (updated.rowCount !== 1) throw new AgentFabricError("AF_CONFLICT", "Materialization receipt was already recorded or changed");
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
async getMaterialization(taskId: string): Promise<LocalMaterializationRecord | null> {
|
|
263
|
+
this.materializationSchemaReady ??= this.adapter.query(CREATE_MATERIALIZATIONS_TABLE);
|
|
264
|
+
await this.materializationSchemaReady;
|
|
265
|
+
const result = await this.adapter.query(
|
|
266
|
+
`SELECT result_digest, state, diff_digest FROM _forge_agent_fabric_local_materializations WHERE task_id = $1`,
|
|
267
|
+
[taskId],
|
|
268
|
+
);
|
|
269
|
+
const row = result.rows[0];
|
|
270
|
+
if (!row) return null;
|
|
271
|
+
if (typeof row.result_digest !== "string" || !/^sha256:[0-9a-f]{64}$/u.test(row.result_digest) ||
|
|
272
|
+
(row.state !== "started" && row.state !== "receipted") ||
|
|
273
|
+
(row.state === "started" && row.diff_digest !== null) ||
|
|
274
|
+
(row.state === "receipted" && (typeof row.diff_digest !== "string" ||
|
|
275
|
+
!/^sha256:[0-9a-f]{64}$/u.test(row.diff_digest)))) {
|
|
276
|
+
throw new AgentFabricError("AF_INVALID_STATE", "Stored patch materialization is inconsistent");
|
|
277
|
+
}
|
|
278
|
+
return { resultDigest: row.result_digest as Digest, state: row.state,
|
|
279
|
+
...(row.state === "receipted" ? { diffDigest: row.diff_digest as Digest } : {}) };
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
async beginVerification(taskId: string, diffDigest: Digest, requestDigest: Digest): Promise<void> {
|
|
283
|
+
const patch = await this.getPatch(taskId);
|
|
284
|
+
if (!patch || patch.diffDigest !== diffDigest) {
|
|
285
|
+
throw new AgentFabricError("AF_CONFLICT", "Verification patch changed");
|
|
286
|
+
}
|
|
287
|
+
this.verificationSchemaReady ??= this.adapter.query(CREATE_VERIFICATIONS_TABLE);
|
|
288
|
+
await this.verificationSchemaReady;
|
|
289
|
+
const result = await this.adapter.query(
|
|
290
|
+
`INSERT INTO _forge_agent_fabric_local_verifications
|
|
291
|
+
(task_id, diff_digest, request_digest, state) VALUES ($1, $2, $3, 'started')
|
|
292
|
+
ON CONFLICT (task_id) DO NOTHING`, [taskId, diffDigest, requestDigest],
|
|
293
|
+
);
|
|
294
|
+
if (result.rowCount !== 1) {
|
|
295
|
+
throw new AgentFabricError("AF_CONFLICT", "Verification already dispatched; read back its result or reconcile uncertain execution");
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
private async verificationDispatchReady(): Promise<void> {
|
|
300
|
+
this.verificationDispatchSchemaReady ??= this.adapter.query(CREATE_VERIFICATION_DISPATCHES_TABLE);
|
|
301
|
+
await this.verificationDispatchSchemaReady;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
private async verificationCommandsReady(): Promise<void> {
|
|
305
|
+
this.verificationCommandsSchemaReady ??= this.adapter.query(CREATE_VERIFICATION_COMMANDS_TABLE);
|
|
306
|
+
await this.verificationCommandsSchemaReady;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
async beginVerificationDockerCommand(taskId: string, requestDigest: Digest,
|
|
310
|
+
ordinal: number, descriptorDigest: Digest, containerName: string): Promise<void> {
|
|
311
|
+
if (!Number.isSafeInteger(ordinal) || ordinal < 1 || ordinal > 3 ||
|
|
312
|
+
!/^forge-fabric-verify-[0-9a-f]{32}-[1-3]$/u.test(containerName)) {
|
|
313
|
+
throw new AgentFabricError("AF_INVALID_STATE", "Invalid Docker verification command identity");
|
|
314
|
+
}
|
|
315
|
+
await this.verificationCommandsReady();
|
|
316
|
+
const result = await this.adapter.query(
|
|
317
|
+
`INSERT INTO _forge_agent_fabric_local_verification_commands
|
|
318
|
+
(task_id, ordinal, request_digest, descriptor_digest, effect_kind, container_name, state)
|
|
319
|
+
SELECT task_id, $3, request_digest, $4, 'local_docker_node_test_v1', $5, 'intent'
|
|
320
|
+
FROM _forge_agent_fabric_local_verifications
|
|
321
|
+
WHERE task_id = $1 AND request_digest = $2 AND state = 'started'
|
|
322
|
+
ON CONFLICT (task_id, ordinal) DO NOTHING`,
|
|
323
|
+
[taskId, requestDigest, ordinal, descriptorDigest, containerName],
|
|
324
|
+
);
|
|
325
|
+
if (result.rowCount !== 1) {
|
|
326
|
+
throw new AgentFabricError("AF_CONFLICT", "Docker verification command may already have started");
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
async receiptVerificationCommand(taskId: string, requestDigest: Digest,
|
|
331
|
+
ordinal: number, descriptorDigest: Digest,
|
|
332
|
+
evidence: LocalVerificationCommandEvidence): Promise<void> {
|
|
333
|
+
await this.verificationCommandsReady();
|
|
334
|
+
if (digestCanonical(evidence.descriptor, sha256Digest) !== descriptorDigest ||
|
|
335
|
+
(ordinal === 0 && evidence.runtime !== "host-git") ||
|
|
336
|
+
(ordinal > 0 && evidence.runtime !== "docker-node")) {
|
|
337
|
+
throw new AgentFabricError("AF_INVALID_STATE", "Verification receipt does not match command intent");
|
|
338
|
+
}
|
|
339
|
+
const encoded = stableStringify(evidence);
|
|
340
|
+
const digest = digestCanonical(evidence, sha256Digest);
|
|
341
|
+
if (ordinal === 0) {
|
|
342
|
+
const result = await this.adapter.query(
|
|
343
|
+
`INSERT INTO _forge_agent_fabric_local_verification_commands
|
|
344
|
+
(task_id, ordinal, request_digest, descriptor_digest, state, evidence_json, evidence_digest)
|
|
345
|
+
SELECT task_id, 0, request_digest, $3, 'receipted', $4, $5
|
|
346
|
+
FROM _forge_agent_fabric_local_verifications
|
|
347
|
+
WHERE task_id = $1 AND request_digest = $2 AND state = 'started'
|
|
348
|
+
ON CONFLICT (task_id, ordinal) DO NOTHING`,
|
|
349
|
+
[taskId, requestDigest, descriptorDigest, encoded, digest],
|
|
350
|
+
);
|
|
351
|
+
if (result.rowCount !== 1) throw new AgentFabricError("AF_CONFLICT", "Git verification receipt already exists");
|
|
352
|
+
return;
|
|
353
|
+
}
|
|
354
|
+
const result = await this.adapter.query(
|
|
355
|
+
`UPDATE _forge_agent_fabric_local_verification_commands
|
|
356
|
+
SET state = 'receipted', evidence_json = $5, evidence_digest = $6
|
|
357
|
+
WHERE task_id = $1 AND request_digest = $2 AND ordinal = $3
|
|
358
|
+
AND descriptor_digest = $4 AND state = 'intent'
|
|
359
|
+
AND container_name = $7`,
|
|
360
|
+
[taskId, requestDigest, ordinal, descriptorDigest, encoded, digest,
|
|
361
|
+
evidence.argv[evidence.argv.indexOf("--name") + 1]],
|
|
362
|
+
);
|
|
363
|
+
if (result.rowCount !== 1) {
|
|
364
|
+
throw new AgentFabricError("AF_CONFLICT", "Docker verification intent changed before receipt");
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
async getVerificationCommands(taskId: string, requestDigest: Digest): Promise<LocalVerificationCommandRecord[]> {
|
|
369
|
+
await this.verificationCommandsReady();
|
|
370
|
+
const result = await this.adapter.query(
|
|
371
|
+
`SELECT ordinal, request_digest, descriptor_digest, effect_kind, container_name, state,
|
|
372
|
+
evidence_json, evidence_digest
|
|
373
|
+
FROM _forge_agent_fabric_local_verification_commands
|
|
374
|
+
WHERE task_id = $1 ORDER BY ordinal`, [taskId],
|
|
375
|
+
);
|
|
376
|
+
return result.rows.map((row) => {
|
|
377
|
+
const ordinal = Number(row.ordinal);
|
|
378
|
+
if (!Number.isSafeInteger(ordinal) || ordinal < 0 || ordinal > 3 ||
|
|
379
|
+
row.request_digest !== requestDigest ||
|
|
380
|
+
typeof row.descriptor_digest !== "string" ||
|
|
381
|
+
!/^sha256:[0-9a-f]{64}$/u.test(row.descriptor_digest) ||
|
|
382
|
+
(row.state !== "intent" && row.state !== "receipted") ||
|
|
383
|
+
(ordinal === 0 && (row.container_name !== null || row.effect_kind !== null)) ||
|
|
384
|
+
(ordinal > 0 && (typeof row.container_name !== "string" ||
|
|
385
|
+
row.effect_kind !== "local_docker_node_test_v1" ||
|
|
386
|
+
!/^forge-fabric-verify-[0-9a-f]{32}-[1-3]$/u.test(row.container_name)))) {
|
|
387
|
+
throw new AgentFabricError("AF_INVALID_STATE", "Stored verification command intent is invalid");
|
|
388
|
+
}
|
|
389
|
+
if (row.state === "intent") {
|
|
390
|
+
if (row.evidence_json !== null || row.evidence_digest !== null) {
|
|
391
|
+
throw new AgentFabricError("AF_INVALID_STATE", "Unreceipted Docker command has evidence");
|
|
392
|
+
}
|
|
393
|
+
return { ordinal, descriptorDigest: row.descriptor_digest as Digest,
|
|
394
|
+
containerName: row.container_name as string, state: "intent" as const };
|
|
395
|
+
}
|
|
396
|
+
let evidence: LocalVerificationCommandEvidence;
|
|
397
|
+
try { evidence = JSON.parse(String(row.evidence_json)) as LocalVerificationCommandEvidence; }
|
|
398
|
+
catch { throw new AgentFabricError("AF_INVALID_STATE", "Stored verification command receipt is not JSON"); }
|
|
399
|
+
if (digestCanonical(evidence, sha256Digest) !== row.evidence_digest ||
|
|
400
|
+
digestCanonical(evidence.descriptor, sha256Digest) !== row.descriptor_digest ||
|
|
401
|
+
(ordinal === 0 && evidence.runtime !== "host-git") ||
|
|
402
|
+
(ordinal > 0 && (evidence.runtime !== "docker-node" ||
|
|
403
|
+
evidence.argv[evidence.argv.indexOf("--name") + 1] !== row.container_name))) {
|
|
404
|
+
throw new AgentFabricError("AF_INVALID_STATE", "Stored verification command receipt failed readback");
|
|
405
|
+
}
|
|
406
|
+
return { ordinal, descriptorDigest: row.descriptor_digest as Digest,
|
|
407
|
+
containerName: row.container_name as string | null, state: "receipted" as const, evidence };
|
|
408
|
+
});
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
/** Durable barrier: after this commits, a container may have started and retry is forbidden. */
|
|
412
|
+
async markVerificationContainerDispatched(taskId: string, requestDigest: Digest): Promise<void> {
|
|
413
|
+
await this.verificationDispatchReady();
|
|
414
|
+
const result = await this.adapter.query(
|
|
415
|
+
`INSERT INTO _forge_agent_fabric_local_verification_dispatches (task_id, request_digest)
|
|
416
|
+
SELECT task_id, request_digest FROM _forge_agent_fabric_local_verifications
|
|
417
|
+
WHERE task_id = $1 AND request_digest = $2 AND state = 'started'
|
|
418
|
+
ON CONFLICT (task_id) DO NOTHING`, [taskId, requestDigest],
|
|
419
|
+
);
|
|
420
|
+
if (result.rowCount !== 1) {
|
|
421
|
+
throw new AgentFabricError("AF_CONFLICT", "Verification may already have dispatched a container");
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
/** Owner-approved recovery is possible only when no container dispatch barrier exists. */
|
|
426
|
+
async clearUndispatchedVerification(taskId: string, diffDigest: Digest, requestDigest: Digest): Promise<void> {
|
|
427
|
+
await this.verificationDispatchReady();
|
|
428
|
+
await this.verificationCommandsReady();
|
|
429
|
+
const tx = await this.adapter.begin();
|
|
430
|
+
try {
|
|
431
|
+
const result = await tx.query(
|
|
432
|
+
`DELETE FROM _forge_agent_fabric_local_verifications AS intent
|
|
433
|
+
WHERE intent.task_id = $1 AND intent.diff_digest = $2 AND intent.request_digest = $3
|
|
434
|
+
AND intent.state = 'started' AND NOT EXISTS (
|
|
435
|
+
SELECT 1 FROM _forge_agent_fabric_local_verification_dispatches AS dispatch
|
|
436
|
+
WHERE dispatch.task_id = intent.task_id
|
|
437
|
+
) AND NOT EXISTS (
|
|
438
|
+
SELECT 1 FROM _forge_agent_fabric_local_verification_commands AS command
|
|
439
|
+
WHERE command.task_id = intent.task_id AND command.container_name IS NOT NULL
|
|
440
|
+
)`, [taskId, diffDigest, requestDigest],
|
|
441
|
+
);
|
|
442
|
+
if (result.rowCount !== 1) {
|
|
443
|
+
throw new AgentFabricError("AF_CONFLICT", "Verification may have dispatched a container; retry is forbidden");
|
|
444
|
+
}
|
|
445
|
+
await tx.query(
|
|
446
|
+
`DELETE FROM _forge_agent_fabric_local_verification_commands
|
|
447
|
+
WHERE task_id = $1 AND request_digest = $2 AND ordinal = 0 AND container_name IS NULL`,
|
|
448
|
+
[taskId, requestDigest],
|
|
449
|
+
);
|
|
450
|
+
await tx.commit();
|
|
451
|
+
} catch (error) {
|
|
452
|
+
await tx.rollback();
|
|
453
|
+
throw error;
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
async finishVerification(taskId: string, evidence: LocalVerificationEvidence, requestDigest: Digest): Promise<void> {
|
|
458
|
+
const commands = await this.getVerificationCommands(taskId, requestDigest);
|
|
459
|
+
for (const [ordinal, command] of evidence.commands.entries()) {
|
|
460
|
+
if (command.runtime === "docker-node" && !command.argv.includes("create")) continue;
|
|
461
|
+
const saved = commands.find((entry) => entry.ordinal === ordinal);
|
|
462
|
+
if (saved?.state !== "receipted" || !saved.evidence ||
|
|
463
|
+
digestCanonical(saved.evidence, sha256Digest) !== digestCanonical(command, sha256Digest)) {
|
|
464
|
+
throw new AgentFabricError("AF_CONFLICT", "Verification result has no matching command receipt");
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
const evidenceDigest = digestCanonical(evidence, sha256Digest);
|
|
468
|
+
const result = await this.adapter.query(
|
|
469
|
+
`UPDATE _forge_agent_fabric_local_verifications SET state = 'finished',
|
|
470
|
+
evidence_json = $4, evidence_digest = $5
|
|
471
|
+
WHERE task_id = $1 AND diff_digest = $2 AND request_digest = $3 AND state = 'started'`,
|
|
472
|
+
[taskId, evidence.patchDigest, requestDigest, stableStringify(evidence), evidenceDigest],
|
|
473
|
+
);
|
|
474
|
+
if (result.rowCount !== 1) throw new AgentFabricError("AF_CONFLICT", "Verification intent changed before result commit");
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
async getVerification(taskId: string): Promise<LocalVerificationRecord | null> {
|
|
478
|
+
this.verificationSchemaReady ??= this.adapter.query(CREATE_VERIFICATIONS_TABLE);
|
|
479
|
+
await this.verificationSchemaReady;
|
|
480
|
+
await this.verificationDispatchReady();
|
|
481
|
+
await this.verificationCommandsReady();
|
|
482
|
+
const result = await this.adapter.query(
|
|
483
|
+
`SELECT intent.diff_digest, intent.request_digest, intent.state, intent.evidence_json,
|
|
484
|
+
intent.evidence_digest, dispatch.request_digest AS dispatched_digest,
|
|
485
|
+
EXISTS (SELECT 1 FROM _forge_agent_fabric_local_verification_commands AS command
|
|
486
|
+
WHERE command.task_id = intent.task_id AND command.container_name IS NOT NULL) AS has_docker_command
|
|
487
|
+
FROM _forge_agent_fabric_local_verifications AS intent
|
|
488
|
+
LEFT JOIN _forge_agent_fabric_local_verification_dispatches AS dispatch
|
|
489
|
+
ON dispatch.task_id = intent.task_id WHERE intent.task_id = $1`, [taskId],
|
|
490
|
+
);
|
|
491
|
+
const row = result.rows[0];
|
|
492
|
+
if (!row) return null;
|
|
493
|
+
if (typeof row.diff_digest !== "string" || typeof row.request_digest !== "string" ||
|
|
494
|
+
(row.state !== "started" && row.state !== "finished") ||
|
|
495
|
+
(row.dispatched_digest !== null && row.dispatched_digest !== row.request_digest)) {
|
|
496
|
+
throw new AgentFabricError("AF_INVALID_STATE", "Stored verification intent is invalid");
|
|
497
|
+
}
|
|
498
|
+
if (row.state === "started") {
|
|
499
|
+
if (row.evidence_json !== null || row.evidence_digest !== null) throw new AgentFabricError("AF_INVALID_STATE", "Started verification has a result");
|
|
500
|
+
return { diffDigest: row.diff_digest as Digest, requestDigest: row.request_digest as Digest,
|
|
501
|
+
state: "started", containerDispatched: row.dispatched_digest !== null || row.has_docker_command === true };
|
|
502
|
+
}
|
|
503
|
+
let evidence: LocalVerificationEvidence;
|
|
504
|
+
try { evidence = JSON.parse(String(row.evidence_json)) as LocalVerificationEvidence; }
|
|
505
|
+
catch { throw new AgentFabricError("AF_INVALID_STATE", "Stored verification result is not JSON"); }
|
|
506
|
+
if (evidence.patchDigest !== row.diff_digest || digestCanonical(evidence, sha256Digest) !== row.evidence_digest) {
|
|
507
|
+
throw new AgentFabricError("AF_INVALID_STATE", "Stored verification result failed digest readback");
|
|
508
|
+
}
|
|
509
|
+
return { diffDigest: row.diff_digest as Digest, requestDigest: row.request_digest as Digest,
|
|
510
|
+
state: "finished", containerDispatched: row.dispatched_digest !== null || row.has_docker_command === true,
|
|
511
|
+
evidence, evidenceDigest: row.evidence_digest as Digest };
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
async recordPatchDecision(taskId: string, diffDigest: Digest, decision: "approved" | "rejected", now = Date.now()): Promise<void> {
|
|
515
|
+
const patch = await this.getPatch(taskId);
|
|
516
|
+
if (!patch || patch.diffDigest !== diffDigest) {
|
|
517
|
+
throw new AgentFabricError("AF_CONFLICT", "Patch review does not match the recorded diff");
|
|
518
|
+
}
|
|
519
|
+
this.decisionSchemaReady ??= this.adapter.query(CREATE_DECISIONS_TABLE);
|
|
520
|
+
await this.decisionSchemaReady;
|
|
521
|
+
const result = await this.adapter.query(
|
|
522
|
+
`INSERT INTO _forge_agent_fabric_local_patch_decisions (task_id, diff_digest, decision, decided_at)
|
|
523
|
+
VALUES ($1, $2, $3, $4) ON CONFLICT (task_id) DO NOTHING`,
|
|
524
|
+
[taskId, diffDigest, decision, now],
|
|
525
|
+
);
|
|
526
|
+
if (result.rowCount !== 1) {
|
|
527
|
+
throw new AgentFabricError("AF_CONFLICT", "Patch already has an owner decision");
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
async getPatchDecision(taskId: string): Promise<"approved" | "rejected" | null> {
|
|
532
|
+
this.decisionSchemaReady ??= this.adapter.query(CREATE_DECISIONS_TABLE);
|
|
533
|
+
await this.decisionSchemaReady;
|
|
534
|
+
const result = await this.adapter.query(
|
|
535
|
+
`SELECT decision FROM _forge_agent_fabric_local_patch_decisions WHERE task_id = $1`,
|
|
536
|
+
[taskId],
|
|
537
|
+
);
|
|
538
|
+
const decision = result.rows[0]?.decision;
|
|
539
|
+
if (decision === "approved" || decision === "rejected") return decision;
|
|
540
|
+
if (decision === undefined) return null;
|
|
541
|
+
throw new AgentFabricError("AF_INVALID_STATE", "Stored patch decision is invalid");
|
|
542
|
+
}
|
|
543
|
+
}
|