create-agdf 0.30.0 → 0.32.0
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/generated/.agdf/control/README.md +5 -0
- package/generated/.agdf/control/templates/BRAND.md +28 -0
- package/generated/.agdf/control/templates/artefacts/PRD.md +11 -0
- package/generated/.agdf/control/templates/artefacts/SD.md +4 -0
- package/generated/.agdf/control/templates/artefacts/UX_INTENT_DEFINITION.md +1 -1
- package/generated/.opencode/agdf-interaction-locales.json +436 -2
- package/generated/.opencode/contracts/gate-artifact-preparation.md +9 -3
- package/generated/.opencode/contracts/interaction.md +10 -4
- package/generated/.opencode/contracts/modes.md +5 -0
- package/generated/.opencode/contracts/prd-definition.md +40 -1
- package/generated/.opencode/contracts/quality.md +35 -0
- package/generated/.opencode/contracts/request-activation.md +6 -3
- package/generated/.opencode/contracts/sd-definition.md +46 -0
- package/generated/.opencode/contracts/tp-definition.md +8 -0
- package/generated/.opencode/contracts/ur-definition.md +9 -5
- package/generated/.opencode/skills/agdf-ux-intent-definition/SKILL.md +31 -2
- package/generated/plugins/agdf/.claude-plugin/plugin.json +1 -1
- package/generated/plugins/agdf/.codex-plugin/plugin.json +1 -1
- package/generated/plugins/agdf/companion/events.mjs +119 -0
- package/generated/plugins/agdf/companion/figure.mjs +242 -111
- package/generated/plugins/agdf/companion/gate-bar.mjs +10 -28
- package/generated/plugins/agdf/companion/localization.mjs +15 -32
- package/generated/plugins/agdf/companion/notice.mjs +20 -10
- package/generated/plugins/agdf/companion/register.mjs +310 -66
- package/generated/plugins/agdf/companion/run-state.mjs +89 -90
- package/generated/plugins/agdf/companion/state.mjs +6 -32
- package/generated/plugins/agdf/companion/view.mjs +199 -24
- package/generated/plugins/agdf/control/README.md +5 -0
- package/generated/plugins/agdf/control/templates/BRAND.md +28 -0
- package/generated/plugins/agdf/control/templates/artefacts/PRD.md +11 -0
- package/generated/plugins/agdf/control/templates/artefacts/SD.md +4 -0
- package/generated/plugins/agdf/control/templates/artefacts/UX_INTENT_DEFINITION.md +1 -1
- package/generated/plugins/agdf/mcp/server/README.md +26 -2
- package/generated/plugins/agdf/mcp/server/package.json +3 -3
- package/generated/plugins/agdf/mcp/server/src/generation-runtime.js +14 -3
- package/generated/plugins/agdf/mcp/server/src/generation.js +8 -2
- package/generated/plugins/agdf/mcp/server/src/main.js +5 -1
- package/generated/plugins/agdf/mcp/server/src/next-action.js +227 -0
- package/generated/plugins/agdf/mcp/server/src/prepared-call-transport.js +306 -0
- package/generated/plugins/agdf/mcp/server/src/safe-read-continuation.js +62 -0
- package/generated/plugins/agdf/mcp/server/src/server.js +155 -37
- package/generated/plugins/agdf/mcp/server/ui/cockpit.html +130 -33
- package/generated/plugins/agdf/mcp/server/ui/decision-manifest.json +3 -3
- package/generated/plugins/agdf/mcp/server/ui/decision.html +3 -3
- package/generated/plugins/agdf/mcp/server/ui/manifest.json +3 -3
- package/generated/plugins/agdf/meta/agdf-interaction-locales.json +436 -2
- package/generated/plugins/agdf/meta/agdf-mcp-capability.json +1 -1
- package/generated/plugins/agdf/meta/agdf-plugin.definition.json +1 -1
- package/generated/plugins/agdf/meta/contracts/gate-artifact-preparation.md +9 -3
- package/generated/plugins/agdf/meta/contracts/interaction.md +10 -4
- package/generated/plugins/agdf/meta/contracts/modes.md +5 -0
- package/generated/plugins/agdf/meta/contracts/prd-definition.md +40 -1
- package/generated/plugins/agdf/meta/contracts/quality.md +35 -0
- package/generated/plugins/agdf/meta/contracts/request-activation.md +6 -3
- package/generated/plugins/agdf/meta/contracts/sd-definition.md +46 -0
- package/generated/plugins/agdf/meta/contracts/tp-definition.md +8 -0
- package/generated/plugins/agdf/meta/contracts/ur-definition.md +9 -5
- package/generated/plugins/agdf/meta/copilot-payload-baseline.json +3 -3
- package/generated/plugins/agdf/meta/distribution-profile-history.json +14 -0
- package/generated/plugins/agdf/runtime/create-agdf/generated/plugins/agdf/meta/agdf-interaction-locales.json +436 -2
- package/generated/plugins/agdf/runtime/create-agdf/generated/plugins/agdf/meta/agdf-plugin.definition.json +1 -1
- package/generated/plugins/agdf/runtime/create-agdf/generated/plugins/agdf/meta/contracts/gate-artifact-preparation.md +9 -3
- package/generated/plugins/agdf/runtime/create-agdf/generated/plugins/agdf/meta/contracts/interaction.md +10 -4
- package/generated/plugins/agdf/runtime/create-agdf/generated/plugins/agdf/meta/contracts/modes.md +5 -0
- package/generated/plugins/agdf/runtime/create-agdf/generated/plugins/agdf/meta/contracts/prd-definition.md +40 -1
- package/generated/plugins/agdf/runtime/create-agdf/generated/plugins/agdf/meta/contracts/quality.md +35 -0
- package/generated/plugins/agdf/runtime/create-agdf/generated/plugins/agdf/meta/contracts/request-activation.md +6 -3
- package/generated/plugins/agdf/runtime/create-agdf/generated/plugins/agdf/meta/contracts/sd-definition.md +46 -0
- package/generated/plugins/agdf/runtime/create-agdf/generated/plugins/agdf/meta/contracts/tp-definition.md +8 -0
- package/generated/plugins/agdf/runtime/create-agdf/generated/plugins/agdf/meta/contracts/ur-definition.md +9 -5
- package/generated/plugins/agdf/runtime/create-agdf/lib/cli/command-registry.js +2 -1
- package/generated/plugins/agdf/runtime/create-agdf/lib/cli/parse-args.js +7 -4
- package/generated/plugins/agdf/runtime/create-agdf/lib/cli/project-read-command.js +29 -0
- package/generated/plugins/agdf/runtime/create-agdf/lib/cli/validation-handlers.js +2 -1
- package/generated/plugins/agdf/runtime/create-agdf/lib/mcp-dispatch-runtime.js +36 -7
- package/generated/plugins/agdf/runtime/create-agdf/lib/mcp-lifecycle/package.js +7 -0
- package/generated/plugins/agdf/runtime/create-agdf/lib/mcp-lifecycle/plugin-runtime.js +34 -6
- package/generated/plugins/agdf/runtime/create-agdf/lib/mcp-lifecycle/prepared-call-journal.js +269 -0
- package/generated/plugins/agdf/runtime/create-agdf/lib/mcp-worker-runtime.js +86 -83
- package/generated/plugins/agdf/runtime/create-agdf/lib/runtime/validator-application.js +2 -2
- package/generated/plugins/agdf/runtime/create-agdf/package.json +1 -1
- package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/companion/events.js +157 -0
- package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/companion/figure-state.js +38 -0
- package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/companion/journal.js +186 -0
- package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/companion/run-view.js +227 -0
- package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/control-evaluation/acceptance-criteria.js +2 -0
- package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/control-evaluation/closeout-readiness.js +24 -6
- package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/control-evaluation/decision-content-placeholder.js +4 -1
- package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/control-evaluation/gate-check.js +49 -7
- package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/control-evaluation/gate-policy-inputs.js +2 -0
- package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/control-evaluation/gate-policy-pure.js +7 -3
- package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/control-evaluation/prd-readiness.js +7 -2
- package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/control-evaluation/report-decision.js +9 -0
- package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/control-evaluation/traceability-readiness.js +57 -8
- package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/control-evaluation/ur-readiness.js +15 -2
- package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/control-inspect/artifact-readiness.js +5 -3
- package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/control-inspect/authoring-inputs.js +107 -22
- package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/control-inspect/cockpit-list.js +10 -8
- package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/control-inspect/cockpit-session.js +11 -3
- package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/control-inspect/cockpit-work.js +4 -2
- package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/control-inspect/cockpit.js +47 -33
- package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/control-inspect/contract.js +64 -24
- package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/control-inspect/material-recording-calls.js +54 -0
- package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/control-inspect/project-state.js +2 -1
- package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/control-inspect/run-classification.js +31 -0
- package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/control-inspect/selection.js +6 -0
- package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/control-inspect/service.js +32 -5
- package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/control-inspect/work-situation.js +25 -0
- package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/control-read/cockpit-worker.js +1 -0
- package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/control-state/authoring-text-handoff.js +3 -0
- package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/control-state/input-resolution.js +7 -5
- package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/control-state/material-limits.js +4 -0
- package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/control-state/prepared-control-calls.js +137 -0
- package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/control-state/presentation-delivery.js +4 -1
- package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/control-state/run-command-contract.js +10 -4
- package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/control-state/run-command-schema.js +9 -3
- package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/control-state/run-command-service.js +35 -11
- package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/control-state/run-create-command.js +6 -1
- package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/control-state/run-identity.js +2 -0
- package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/control-state/run-inventory-reader.js +54 -5
- package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/control-state/run-inventory.js +12 -27
- package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/control-state/run-material.js +25 -7
- package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/control-state/run-presentation-render.js +113 -28
- package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/control-state/run-revision.js +38 -20
- package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/control-state/run-source-revisions.js +37 -17
- package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/control-state/run-state-reader.js +10 -3
- package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/control-state/run-steps.js +8 -5
- package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/control-state/run-title.js +43 -0
- package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/index.js +3 -1
- package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/interaction-catalog-validation.js +7 -1
- package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/interaction-catalog.js +8 -0
- package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/interaction-presentation.js +31 -10
- package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/mcp-input-hints.js +30 -1
- package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/mcp-tool-errors.js +5 -3
- package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/resources/canonical-init-plan.js +1 -1
- package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/runtime/plugin-provenance.js +9 -2
- package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/skill-dispatch/contract.js +6 -4
- package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/skill-dispatch/delivery-intake.js +3 -1
- package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/skill-dispatch/mcp-continuation.js +25 -2
- package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/skill-dispatch/prd-definition.js +3 -2
- package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/skill-dispatch/readiness-findings.js +7 -0
- package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/skill-dispatch/sd-definition.js +4 -2
- package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/skill-dispatch/service.js +17 -4
- package/generated/plugins/agdf/runtime/create-agdf/runtime/core/lib/skill-dispatch/tp-definition.js +4 -2
- package/generated/plugins/agdf/runtime/runtime-manifest.json +2 -2
- package/generated/plugins/agdf/scripts/check-runtime-integrity.mjs +4 -3
- package/generated/plugins/agdf/skills/ux-intent-definition/SKILL.md +31 -2
- package/generated/plugins/agdf/skills/ux-intent-definition/help.md +8 -1
- package/generated/plugins/agdf/submission/openai/availability.md +1 -1
- package/generated/plugins/agdf/submission/openai/capability-matrix.json +1 -1
- package/generated/plugins/agdf/submission/openai/release-notes.md +5 -8
- package/generated/plugins/agdf/submission/openai/reviewer-cases.json +1 -1
- package/generated/plugins/agdf-planning/.codex-plugin/plugin.json +1 -1
- package/generated/plugins/agdf-planning/plugin.json +1 -1
- package/generated/plugins/copilot/agdf/.agdf-payload-inventory.json +358 -203
- package/generated/plugins/copilot/agdf/control/README.md +5 -0
- package/generated/plugins/copilot/agdf/control/templates/BRAND.md +28 -0
- package/generated/plugins/copilot/agdf/control/templates/artefacts/PRD.md +11 -0
- package/generated/plugins/copilot/agdf/control/templates/artefacts/SD.md +4 -0
- package/generated/plugins/copilot/agdf/control/templates/artefacts/UX_INTENT_DEFINITION.md +1 -1
- package/generated/plugins/copilot/agdf/mcp/server/README.md +26 -2
- package/generated/plugins/copilot/agdf/mcp/server/package.json +3 -3
- package/generated/plugins/copilot/agdf/mcp/server/src/generation-runtime.js +14 -3
- package/generated/plugins/copilot/agdf/mcp/server/src/generation.js +8 -2
- package/generated/plugins/copilot/agdf/mcp/server/src/main.js +5 -1
- package/generated/plugins/copilot/agdf/mcp/server/src/next-action.js +227 -0
- package/generated/plugins/copilot/agdf/mcp/server/src/prepared-call-transport.js +306 -0
- package/generated/plugins/copilot/agdf/mcp/server/src/safe-read-continuation.js +62 -0
- package/generated/plugins/copilot/agdf/mcp/server/src/server.js +155 -37
- package/generated/plugins/copilot/agdf/meta/agdf-plugin.definition.json +1 -1
- package/generated/plugins/copilot/agdf/meta/distribution-profile-history.json +14 -0
- package/generated/plugins/copilot/agdf/plugin.json +1 -1
- package/generated/plugins/copilot/agdf/runtime/create-agdf/generated/plugins/agdf/meta/agdf-interaction-locales.json +436 -2
- package/generated/plugins/copilot/agdf/runtime/create-agdf/generated/plugins/agdf/meta/agdf-plugin.definition.json +1 -1
- package/generated/plugins/copilot/agdf/runtime/create-agdf/generated/plugins/agdf/meta/contracts/gate-artifact-preparation.md +9 -3
- package/generated/plugins/copilot/agdf/runtime/create-agdf/generated/plugins/agdf/meta/contracts/interaction.md +10 -4
- package/generated/plugins/copilot/agdf/runtime/create-agdf/generated/plugins/agdf/meta/contracts/modes.md +5 -0
- package/generated/plugins/copilot/agdf/runtime/create-agdf/generated/plugins/agdf/meta/contracts/prd-definition.md +40 -1
- package/generated/plugins/copilot/agdf/runtime/create-agdf/generated/plugins/agdf/meta/contracts/quality.md +35 -0
- package/generated/plugins/copilot/agdf/runtime/create-agdf/generated/plugins/agdf/meta/contracts/request-activation.md +6 -3
- package/generated/plugins/copilot/agdf/runtime/create-agdf/generated/plugins/agdf/meta/contracts/sd-definition.md +46 -0
- package/generated/plugins/copilot/agdf/runtime/create-agdf/generated/plugins/agdf/meta/contracts/tp-definition.md +8 -0
- package/generated/plugins/copilot/agdf/runtime/create-agdf/generated/plugins/agdf/meta/contracts/ur-definition.md +9 -5
- package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/cli/command-registry.js +2 -1
- package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/cli/parse-args.js +7 -4
- package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/cli/project-read-command.js +29 -0
- package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/cli/validation-handlers.js +2 -1
- package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/mcp-dispatch-runtime.js +36 -7
- package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/mcp-lifecycle/package.js +7 -0
- package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/mcp-lifecycle/plugin-runtime.js +34 -6
- package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/mcp-lifecycle/prepared-call-journal.js +269 -0
- package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/mcp-worker-runtime.js +81 -78
- package/generated/plugins/copilot/agdf/runtime/create-agdf/lib/runtime/validator-application.js +2 -2
- package/generated/plugins/copilot/agdf/runtime/create-agdf/package.json +1 -1
- package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/companion/events.js +157 -0
- package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/companion/figure-state.js +38 -0
- package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/companion/journal.js +186 -0
- package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/companion/run-view.js +227 -0
- package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/control-evaluation/acceptance-criteria.js +2 -0
- package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/control-evaluation/closeout-readiness.js +24 -6
- package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/control-evaluation/decision-content-placeholder.js +4 -1
- package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/control-evaluation/gate-check.js +49 -7
- package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/control-evaluation/gate-policy-inputs.js +2 -0
- package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/control-evaluation/gate-policy-pure.js +7 -3
- package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/control-evaluation/prd-readiness.js +7 -2
- package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/control-evaluation/report-decision.js +9 -0
- package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/control-evaluation/traceability-readiness.js +57 -8
- package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/control-evaluation/ur-readiness.js +15 -2
- package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/control-inspect/artifact-readiness.js +5 -3
- package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/control-inspect/authoring-inputs.js +107 -22
- package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/control-inspect/contract.js +64 -24
- package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/control-inspect/material-recording-calls.js +54 -0
- package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/control-inspect/project-state.js +2 -1
- package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/control-inspect/run-classification.js +31 -0
- package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/control-inspect/selection.js +6 -0
- package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/control-inspect/service.js +32 -5
- package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/control-inspect/work-situation.js +25 -0
- package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/control-state/authoring-text-handoff.js +3 -0
- package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/control-state/input-resolution.js +7 -5
- package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/control-state/material-limits.js +4 -0
- package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/control-state/prepared-control-calls.js +137 -0
- package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/control-state/presentation-delivery.js +4 -1
- package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/control-state/run-command-contract.js +10 -4
- package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/control-state/run-command-schema.js +9 -3
- package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/control-state/run-command-service.js +35 -11
- package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/control-state/run-create-command.js +6 -1
- package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/control-state/run-identity.js +2 -0
- package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/control-state/run-inventory-reader.js +54 -5
- package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/control-state/run-inventory.js +12 -27
- package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/control-state/run-material.js +25 -7
- package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/control-state/run-presentation-render.js +113 -28
- package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/control-state/run-revision.js +38 -20
- package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/control-state/run-source-revisions.js +37 -17
- package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/control-state/run-state-reader.js +10 -3
- package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/control-state/run-steps.js +8 -5
- package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/control-state/run-title.js +43 -0
- package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/index.js +3 -1
- package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/interaction-catalog-validation.js +7 -1
- package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/interaction-catalog.js +8 -0
- package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/interaction-presentation.js +31 -10
- package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/mcp-input-hints.js +30 -1
- package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/mcp-tool-errors.js +5 -3
- package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/resources/canonical-init-plan.js +1 -1
- package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/runtime/plugin-provenance.js +9 -2
- package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/skill-dispatch/contract.js +6 -4
- package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/skill-dispatch/delivery-intake.js +3 -1
- package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/skill-dispatch/mcp-continuation.js +25 -2
- package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/skill-dispatch/prd-definition.js +3 -2
- package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/skill-dispatch/readiness-findings.js +7 -0
- package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/skill-dispatch/sd-definition.js +4 -2
- package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/skill-dispatch/service.js +17 -4
- package/generated/plugins/copilot/agdf/runtime/create-agdf/runtime/core/lib/skill-dispatch/tp-definition.js +4 -2
- package/generated/plugins/copilot/agdf/runtime/runtime-manifest.json +2 -2
- package/generated/plugins/copilot/agdf/skills/agdf-interaction-locales.json +1 -1
- package/generated/plugins/copilot/agdf/skills/agdf-ux-intent-definition/SKILL.md +31 -2
- package/generated/plugins/copilot/agdf/skills/contracts/gate-artifact-preparation.md +9 -3
- package/generated/plugins/copilot/agdf/skills/contracts/interaction.md +10 -4
- package/generated/plugins/copilot/agdf/skills/contracts/modes.md +5 -0
- package/generated/plugins/copilot/agdf/skills/contracts/prd-definition.md +40 -1
- package/generated/plugins/copilot/agdf/skills/contracts/quality.md +35 -0
- package/generated/plugins/copilot/agdf/skills/contracts/request-activation.md +6 -3
- package/generated/plugins/copilot/agdf/skills/contracts/sd-definition.md +46 -0
- package/generated/plugins/copilot/agdf/skills/contracts/tp-definition.md +8 -0
- package/generated/plugins/copilot/agdf/skills/contracts/ur-definition.md +9 -5
- package/generated/submissions/openai/agdf/.codex-plugin/plugin.json +1 -1
- package/generated/submissions/openai/agdf/meta/agdf-interaction-locales.json +436 -2
- package/generated/submissions/openai/agdf/meta/agdf-plugin.definition.json +1 -1
- package/generated/submissions/openai/agdf/meta/contracts/gate-artifact-preparation.md +9 -3
- package/generated/submissions/openai/agdf/meta/contracts/interaction.md +10 -4
- package/generated/submissions/openai/agdf/meta/contracts/modes.md +5 -0
- package/generated/submissions/openai/agdf/meta/contracts/prd-definition.md +40 -1
- package/generated/submissions/openai/agdf/meta/contracts/quality.md +35 -0
- package/generated/submissions/openai/agdf/meta/contracts/request-activation.md +6 -3
- package/generated/submissions/openai/agdf/meta/contracts/sd-definition.md +46 -0
- package/generated/submissions/openai/agdf/meta/contracts/tp-definition.md +8 -0
- package/generated/submissions/openai/agdf/meta/contracts/ur-definition.md +9 -5
- package/generated/submissions/openai/agdf/meta/copilot-payload-baseline.json +3 -3
- package/generated/submissions/openai/agdf/meta/distribution-profile-history.json +14 -0
- package/generated/submissions/openai/agdf/plugin.json +1 -1
- package/generated/submissions/openai/agdf/skills/ux-intent-definition/SKILL.md +31 -2
- package/generated/submissions/openai/agdf/skills/ux-intent-definition/help.md +8 -1
- package/generated/submissions/openai/agdf/submission/openai/availability.md +1 -1
- package/generated/submissions/openai/agdf/submission/openai/capability-matrix.json +1 -1
- package/generated/submissions/openai/agdf/submission/openai/inventory.json +24 -24
- package/generated/submissions/openai/agdf/submission/openai/listing.json +1 -1
- package/generated/submissions/openai/agdf/submission/openai/readiness.json +2 -2
- package/generated/submissions/openai/agdf/submission/openai/readiness.md +2 -2
- package/generated/submissions/openai/agdf/submission/openai/release-notes.md +5 -8
- package/generated/submissions/openai/agdf/submission/openai/reviewer-cases.json +1 -1
- package/lib/cli/command-registry.js +2 -1
- package/lib/cli/parse-args.js +7 -4
- package/lib/cli/project-read-command.js +29 -0
- package/lib/cli/validation-handlers.js +2 -1
- package/lib/mcp-dispatch-runtime.js +36 -7
- package/lib/mcp-lifecycle/package.js +7 -0
- package/lib/mcp-lifecycle/plugin-runtime.js +34 -6
- package/lib/mcp-lifecycle/prepared-call-journal.js +269 -0
- package/lib/mcp-worker-runtime.js +86 -83
- package/lib/runtime/validator-application.js +2 -2
- package/lib/scaffold/plan.js +2 -0
- package/package.json +1 -1
- package/runtime/core/lib/companion/events.js +157 -0
- package/runtime/core/lib/companion/figure-state.js +38 -0
- package/runtime/core/lib/companion/journal.js +186 -0
- package/runtime/core/lib/companion/run-view.js +227 -0
- package/runtime/core/lib/control-evaluation/acceptance-criteria.js +2 -0
- package/runtime/core/lib/control-evaluation/closeout-readiness.js +24 -6
- package/runtime/core/lib/control-evaluation/decision-content-placeholder.js +4 -1
- package/runtime/core/lib/control-evaluation/gate-check.js +49 -7
- package/runtime/core/lib/control-evaluation/gate-policy-inputs.js +2 -0
- package/runtime/core/lib/control-evaluation/gate-policy-pure.js +7 -3
- package/runtime/core/lib/control-evaluation/prd-readiness.js +7 -2
- package/runtime/core/lib/control-evaluation/report-decision.js +9 -0
- package/runtime/core/lib/control-evaluation/traceability-readiness.js +57 -8
- package/runtime/core/lib/control-evaluation/ur-readiness.js +15 -2
- package/runtime/core/lib/control-inspect/artifact-readiness.js +5 -3
- package/runtime/core/lib/control-inspect/authoring-inputs.js +107 -22
- package/runtime/core/lib/control-inspect/cockpit-list.js +10 -8
- package/runtime/core/lib/control-inspect/cockpit-session.js +11 -3
- package/runtime/core/lib/control-inspect/cockpit-work.js +4 -2
- package/runtime/core/lib/control-inspect/cockpit.js +47 -33
- package/runtime/core/lib/control-inspect/contract.js +64 -24
- package/runtime/core/lib/control-inspect/material-recording-calls.js +54 -0
- package/runtime/core/lib/control-inspect/project-state.js +2 -1
- package/runtime/core/lib/control-inspect/run-classification.js +31 -0
- package/runtime/core/lib/control-inspect/selection.js +6 -0
- package/runtime/core/lib/control-inspect/service.js +32 -5
- package/runtime/core/lib/control-inspect/work-situation.js +25 -0
- package/runtime/core/lib/control-read/cockpit-worker.js +1 -0
- package/runtime/core/lib/control-state/authoring-text-handoff.js +3 -0
- package/runtime/core/lib/control-state/input-resolution.js +7 -5
- package/runtime/core/lib/control-state/material-limits.js +4 -0
- package/runtime/core/lib/control-state/prepared-control-calls.js +137 -0
- package/runtime/core/lib/control-state/presentation-delivery.js +4 -1
- package/runtime/core/lib/control-state/run-command-contract.js +10 -4
- package/runtime/core/lib/control-state/run-command-schema.js +9 -3
- package/runtime/core/lib/control-state/run-command-service.js +35 -11
- package/runtime/core/lib/control-state/run-create-command.js +6 -1
- package/runtime/core/lib/control-state/run-identity.js +2 -0
- package/runtime/core/lib/control-state/run-inventory-reader.js +54 -5
- package/runtime/core/lib/control-state/run-inventory.js +12 -27
- package/runtime/core/lib/control-state/run-material.js +25 -7
- package/runtime/core/lib/control-state/run-presentation-render.js +113 -28
- package/runtime/core/lib/control-state/run-revision.js +38 -20
- package/runtime/core/lib/control-state/run-source-revisions.js +37 -17
- package/runtime/core/lib/control-state/run-state-reader.js +10 -3
- package/runtime/core/lib/control-state/run-steps.js +8 -5
- package/runtime/core/lib/control-state/run-title.js +43 -0
- package/runtime/core/lib/index.js +3 -1
- package/runtime/core/lib/interaction-catalog-validation.js +7 -1
- package/runtime/core/lib/interaction-catalog.js +8 -0
- package/runtime/core/lib/interaction-presentation.js +31 -10
- package/runtime/core/lib/mcp-input-hints.js +30 -1
- package/runtime/core/lib/mcp-tool-errors.js +5 -3
- package/runtime/core/lib/resources/canonical-init-plan.js +1 -1
- package/runtime/core/lib/runtime/plugin-provenance.js +9 -2
- package/runtime/core/lib/skill-dispatch/contract.js +6 -4
- package/runtime/core/lib/skill-dispatch/delivery-intake.js +3 -1
- package/runtime/core/lib/skill-dispatch/mcp-continuation.js +25 -2
- package/runtime/core/lib/skill-dispatch/prd-definition.js +3 -2
- package/runtime/core/lib/skill-dispatch/readiness-findings.js +7 -0
- package/runtime/core/lib/skill-dispatch/sd-definition.js +4 -2
- package/runtime/core/lib/skill-dispatch/service.js +17 -4
- package/runtime/core/lib/skill-dispatch/tp-definition.js +4 -2
- package/generated/plugins/agdf/companion/core.mjs +0 -16
- package/generated/plugins/agdf/companion/locales.json +0 -200
package/lib/cli/parse-args.js
CHANGED
|
@@ -68,6 +68,7 @@ export function parseArgs(argv, dependencies = {}) {
|
|
|
68
68
|
let generationTimeoutMs = 30000;
|
|
69
69
|
let generationCostUnits = 5;
|
|
70
70
|
let runId;
|
|
71
|
+
const runIds = [];
|
|
71
72
|
let gate;
|
|
72
73
|
let revisionId;
|
|
73
74
|
let response;
|
|
@@ -161,6 +162,7 @@ export function parseArgs(argv, dependencies = {}) {
|
|
|
161
162
|
|
|
162
163
|
if (arg === "--run") {
|
|
163
164
|
runId = requiredValue(args, i, arg);
|
|
165
|
+
runIds.push(runId);
|
|
164
166
|
i += 1;
|
|
165
167
|
continue;
|
|
166
168
|
}
|
|
@@ -363,10 +365,10 @@ export function parseArgs(argv, dependencies = {}) {
|
|
|
363
365
|
throw new CliUsageError("Source revision identity and evidence flags may not repeat");
|
|
364
366
|
}
|
|
365
367
|
if (documentServer !== undefined && target !== 'render-document') throw new CliUsageError('--server requires render-document');
|
|
366
|
-
if (['project-state', 'operation-status'].includes(target)) {
|
|
367
|
-
const allowed = new Set(['--dir', '--json', '--language', '--lang', ...(target === 'operation-status' ? ['--module'] : [])]);
|
|
368
|
-
if ([...flagCounts].some(([flag, count]) => count !== 1 || !allowed.has(flag)))
|
|
369
|
-
throw new CliUsageError('Project reads accept only unique --dir, --json, --language
|
|
368
|
+
if (['project-state', 'operation-status', 'run-view'].includes(target)) {
|
|
369
|
+
const allowed = new Set(['--dir', '--json', '--language', '--lang', ...(target === 'operation-status' ? ['--module'] : []), ...(target === 'run-view' ? ['--run'] : [])]);
|
|
370
|
+
if ([...flagCounts].some(([flag, count]) => (count !== 1 && flag !== '--run') || !allowed.has(flag)))
|
|
371
|
+
throw new CliUsageError('Project reads accept only unique --dir, --json, --language, operation-status --module and repeatable run-view --run selectors.');
|
|
370
372
|
}
|
|
371
373
|
if (documentRequest && target !== 'render-document') throw new CliUsageError('--request requires render-document');
|
|
372
374
|
if (target === 'render-document') {
|
|
@@ -462,6 +464,7 @@ export function parseArgs(argv, dependencies = {}) {
|
|
|
462
464
|
model,
|
|
463
465
|
generateCandidates,
|
|
464
466
|
runId,
|
|
467
|
+
...(target === 'run-view' ? { runIds } : {}),
|
|
465
468
|
gate,
|
|
466
469
|
revisionId,
|
|
467
470
|
response,
|
|
@@ -1,6 +1,35 @@
|
|
|
1
1
|
import { createCoreServices } from '#agdf-core';
|
|
2
|
+
import { readRunView } from '#agdf-core/companion/run-view.js';
|
|
2
3
|
import { resources, resolveConfiguredChatLanguage } from '../runtime/control-context.js';
|
|
3
4
|
import { cliGitObservation } from '../control-evaluation/git-observation.js';
|
|
5
|
+
import { RUN_ID_PATTERN } from '#agdf-core/control-state/run-identity.js';
|
|
6
|
+
import { CliUsageError } from './parse-args.js';
|
|
7
|
+
|
|
8
|
+
// An explicit --language wins; otherwise the configured chat language. A configuration that cannot be
|
|
9
|
+
// resolved (unsupported layout, invalid value) must not hide the store diagnosis (PRD AC-002), so the
|
|
10
|
+
// language is left to Core as executeProjectRead does: an unsupported store is reported in `store`,
|
|
11
|
+
// an invalid configuration as the evaluation error of every evaluated run (CR finding CIR-05; both
|
|
12
|
+
// cases are covered by run-view-command-test.js).
|
|
13
|
+
const readLanguage = options => {
|
|
14
|
+
if (options.languageExplicit) return options.language?.chat_language;
|
|
15
|
+
try { return resolveConfiguredChatLanguage(options.dir); } catch { return undefined; }
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
// Read-only companion run view (SD SDD-001): the status card fields of every active or unreadable
|
|
19
|
+
// run of one project root plus every run named with --run, versioned run-view/1. Writes nothing.
|
|
20
|
+
// Exit 0 for a complete view, 2 when the store is unavailable or has no control folder.
|
|
21
|
+
export function executeRunView(options, io = console) {
|
|
22
|
+
// A malformed run id is a usage error, never an evaluated run of its own (CR finding C3).
|
|
23
|
+
const invalid = (options.runIds ?? []).find(runId => !RUN_ID_PATTERN.test(runId));
|
|
24
|
+
if (invalid !== undefined) throw new CliUsageError(`run-view --run requires a run id (${RUN_ID_PATTERN}); got ${JSON.stringify(invalid)}.`);
|
|
25
|
+
const view = readRunView(options.dir, { language: readLanguage(options), runIds: options.runIds ?? [] });
|
|
26
|
+
if (options.json) io.log(JSON.stringify(view, null, 2));
|
|
27
|
+
else {
|
|
28
|
+
io.log(`AGDF run-view: ${view.store.status}${view.store.reason ? ` (${view.store.reason})` : ''}`);
|
|
29
|
+
for (const run of view.runs) io.log(`- ${run.run_id}: ${run.evaluated ? `${run.status} · ${run.current_gate} · ${run.next_step_text}` : run.lifecycle ?? 'unreadable'}`);
|
|
30
|
+
}
|
|
31
|
+
return view.store.status === 'ok' ? 0 : 2;
|
|
32
|
+
}
|
|
4
33
|
|
|
5
34
|
// CLI syntax only. Target confirmation, facts and original-operation semantics
|
|
6
35
|
// stay with the same inspect owner used by MCP.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { executeRunAlias } from './run-command-aliases.js';
|
|
2
|
-
import { executeProjectRead } from './project-read-command.js';
|
|
2
|
+
import { executeProjectRead, executeRunView } from './project-read-command.js';
|
|
3
3
|
import { localePack } from '#agdf-core/interaction-presentation.js';
|
|
4
4
|
import { renderCodexDocument } from './codex-document-command.js';
|
|
5
5
|
import { readFileSync, lstatSync, openSync, fstatSync, closeSync, constants } from "node:fs";
|
|
@@ -46,6 +46,7 @@ export function createValidationHandlers(io = console) {
|
|
|
46
46
|
} }).dispatch;
|
|
47
47
|
return new Map([
|
|
48
48
|
...['project-state', 'operation-status'].map(name => [name, options => executeProjectRead(options, io)]),
|
|
49
|
+
['run-view', options => executeRunView(options, io)],
|
|
49
50
|
['render-document', options => renderCodexDocument(options)],
|
|
50
51
|
...['run-create', 'run-present', 'run-approve', 'run-step', 'run-revise', 'run-close'].map(name => [name, options => executeRunAlias(options, io)]),
|
|
51
52
|
...Object.entries(commandGroupRoutes).map(([route, group]) => [route, options => {
|
|
@@ -7,11 +7,30 @@ import { createPresentationDelivery } from '#agdf-core/control-state/presentatio
|
|
|
7
7
|
import { mcpControlContinuation } from '#agdf-core/skill-dispatch/mcp-continuation.js';
|
|
8
8
|
import { inspectRunInputResolution } from '#agdf-core/control-state/run-input-resolution.js';
|
|
9
9
|
import { assertMcpControlReadBoundary } from "#agdf-core/control-read-boundary.js";
|
|
10
|
+
import { knownExecutionCode, validExecutionFacts } from '#agdf-core/mcp-tool-errors.js';
|
|
11
|
+
import { createCompanionJournal } from '#agdf-core/companion/journal.js';
|
|
10
12
|
import { existsSync, lstatSync, realpathSync } from 'node:fs';
|
|
11
13
|
import { isAbsolute } from 'node:path';
|
|
12
14
|
import { composeMcpProtocolRuntime, errorSupport, inspectMcpDispatcherRuntime, configuredMcpCommandGroups } from './mcp-protocol-runtime.js';
|
|
13
15
|
export { inspectMcpDispatcherRuntime, configuredMcpCommandGroups, CONTROL_INSPECT_FUNCTION_DEFINITION, SKILL_DISPATCH_FUNCTION_DEFINITION,
|
|
14
16
|
parseControlInspectFunctionArguments, parseSkillDispatchFunctionArguments, serializeSkillDispatchResult, DECISION_UI_URI, OWNED_LOCK_CHANNEL, releaseAbandonedOwnedLock } from './mcp-protocol-runtime.js';
|
|
17
|
+
// Core reasons that the tool-error contract names differently. Core's command service maps
|
|
18
|
+
// RECOVERY_REQUIRED the same way and rejects the others under these existing codes.
|
|
19
|
+
const PREPARATION_REASONS = Object.freeze([
|
|
20
|
+
[/RECOVERY_REQUIRED/iu, 'recovery_required'],
|
|
21
|
+
[/^AGDF_PLANNED_SOURCE_STALE$/u, 'planning_source_stale'],
|
|
22
|
+
[/^(?:run_state_invalid|run_id_invalid)$/u, 'invalid_run'],
|
|
23
|
+
[/^AGDF_CONTROL_LAYOUT_MIGRATION_REQUIRED$/u, 'control_layout_unsupported'],
|
|
24
|
+
]);
|
|
25
|
+
// Dispatch preparation only reads the input context and grants staged material; no command has
|
|
26
|
+
// been dispatched yet. Its failures therefore carry typed not_dispatched facts, so the facade and
|
|
27
|
+
// generation call sites report a rejected command with its classified reason, never an unknown effect.
|
|
28
|
+
export function preDispatchFailure(error) {
|
|
29
|
+
if (validExecutionFacts(error?.facts)) return Object.assign(error, { facts: { ...error.facts, dispatch: 'not_dispatched' } });
|
|
30
|
+
const reason = String(error?.message ?? '');
|
|
31
|
+
const code = knownExecutionCode(PREPARATION_REASONS.find(([pattern]) => pattern.test(reason))?.[1] ?? reason);
|
|
32
|
+
return Object.assign(new Error(code), { facts: { code, dispatch: 'not_dispatched' } });
|
|
33
|
+
}
|
|
15
34
|
export async function createMcpCockpitRuntime({ surface, cockpitDir, cockpitMode, inspected = inspectMcpDispatcherRuntime() } = {}) {
|
|
16
35
|
const pluginMode = cockpitMode === 'plugin';
|
|
17
36
|
if (cockpitMode !== undefined && !pluginMode || pluginMode && (surface !== 'codex' || cockpitDir !== undefined)
|
|
@@ -25,7 +44,7 @@ export async function createMcpCockpitRuntime({ surface, cockpitDir, cockpitMode
|
|
|
25
44
|
import("#agdf-core/control-inspect/cockpit-session.js"),
|
|
26
45
|
import("#agdf-core/control-read/snapshot.js"),
|
|
27
46
|
]);
|
|
28
|
-
const session = createCockpitSessionService(root, { pluginMode });
|
|
47
|
+
const session = createCockpitSessionService(root, { pluginMode, integrationSurface: surface });
|
|
29
48
|
const renderDefinition = pluginMode ? COCKPIT_PLUGIN_RENDER_DEFINITION : COCKPIT_RENDER_DEFINITION;
|
|
30
49
|
const tools = [
|
|
31
50
|
{ name: renderDefinition.name, definition: renderDefinition,
|
|
@@ -35,6 +54,7 @@ export async function createMcpCockpitRuntime({ surface, cockpitDir, cockpitMode
|
|
|
35
54
|
];
|
|
36
55
|
// Claude Code renders no MCP app UI today; its cockpit stays hidden until a client declares support.
|
|
37
56
|
return Object.freeze({ ...errorSupport(true), mode: 'cockpit', definition: renderDefinition, tools,
|
|
57
|
+
bindResourceIdentity: identity => session.bindResourceIdentity(identity),
|
|
38
58
|
producerIdentity: inspected.generationIdentity ?? null,
|
|
39
59
|
uiCapabilityRequired: pluginMode || surface === 'claude', responseLimit: READ_LIMITS.response,
|
|
40
60
|
...(pluginMode ? { unsupportedUiCode: 'host_ui_unsupported' } : {}),
|
|
@@ -66,6 +86,9 @@ export function createMcpDispatchRuntime({ surface, inspected = inspectMcpDispat
|
|
|
66
86
|
commandGroups, runtimeControl, materialGrants, gitObservation: cliGitObservation,
|
|
67
87
|
observeDoctor: (root, input, signal) => diagnostic.observe(root, input, signal),
|
|
68
88
|
} });
|
|
89
|
+
// Companion events (companion core SDD-006): the executing process journals each final command result
|
|
90
|
+
// once, below the data root the launcher hands over; review facts read the sealed material here.
|
|
91
|
+
const journal = createCompanionJournal({ sealedFiles: transferId => services.material.sealedFiles(transferId) });
|
|
69
92
|
const execute = input => mcpControlContinuation(input, services.dispatch(input), commandGroups);
|
|
70
93
|
const executeInspect = services.inspect;
|
|
71
94
|
const protocol = composeMcpProtocolRuntime({ surface, inspected, commandGroups, execute, executeInspect, inputContext, executionContext,
|
|
@@ -76,25 +99,29 @@ export function createMcpDispatchRuntime({ surface, inspected = inspectMcpDispat
|
|
|
76
99
|
: input.command.kind === 'presentation.deliver' ? delivery.deliver(input, host) : services.command(group, input) });
|
|
77
100
|
return Object.freeze({ ...protocol,
|
|
78
101
|
verifyProducer,
|
|
79
|
-
prepareDispatch(name, input) {
|
|
102
|
+
prepareDispatch(name, input) {
|
|
103
|
+
try {
|
|
104
|
+
return { inputContext: protocol.inputContextFor(input), materialGrants: ['agdf_record', 'agdf_revise', 'agdf_closeout'].includes(name) ? services.material.grants(input) : [] };
|
|
105
|
+
} catch (error) { throw preDispatchFailure(error); }
|
|
106
|
+
},
|
|
80
107
|
readBudget,
|
|
81
108
|
delivery,
|
|
109
|
+
observeOutcome: (name, input, result) => journal.observe(name, input, result),
|
|
110
|
+
observesOutcome: (name, input, result) => journal.observes(name, input, result),
|
|
82
111
|
async postprocessToolResult(name, input, result) {
|
|
83
112
|
const configuration = protocol.configurationProjection(input);
|
|
84
113
|
if (configuration && name === 'agdf_inspect' && result.report) result = { ...result, report: { ...result.report, effective_configuration: configuration } };
|
|
85
114
|
if (['agdf_record', 'agdf_revise', 'agdf_closeout'].includes(name)) services.material.settle(input, result);
|
|
86
115
|
if (name !== 'agdf_prepare' || input.command?.kind !== 'presentation.prepare' || !result.family_result?.text) return result;
|
|
87
116
|
delivery.remember(input, result);
|
|
88
|
-
const prepared = result.family_result
|
|
117
|
+
const prepared = result.family_result;
|
|
89
118
|
return { ...result, presentation_delivery: { mode: 'prepared', text: '', presentation_id: prepared.presentation_id,
|
|
90
119
|
document_digest: prepared.document_digest, authorizes: false,
|
|
91
120
|
...(prepared.preview_review ? { preview_review: { operation: 'presentation-preview', version: prepared.preview_review.descriptor.version,
|
|
92
121
|
content_digest: prepared.preview_review.rendered_digest, access_state: 'not_observed', target_id: input.target_id,
|
|
93
122
|
run_id: input.run_id, gate: 'PRD', expected_revision_id: input.expected_revision_id, presentation_id: prepared.presentation_id } } : {}),
|
|
94
|
-
instruction: 'Prepared, not delivered. Optionally open agdf_decision_view as a non-primary preview.
|
|
95
|
-
|
|
96
|
-
payload: { gate: input.command.payload.gate, presentation_id: prepared.presentation_id, route: 'markdown' } } },
|
|
97
|
-
required_input: { operation_id: 'Generate a new UUID for delivery; no gate approval is required.' } }] } };
|
|
123
|
+
instruction: 'Prepared, not delivered. Optionally open agdf_decision_view as a non-primary preview. Follow the authoritative top-level next action for presentation.deliver; its original UUID and binding are already supplied. No second summary and no generated delivery UUID.',
|
|
124
|
+
next_action_source: 'next_calls' } };
|
|
98
125
|
},
|
|
99
126
|
async close() { services.material.close(); delivery.close(); await diagnostic.close(); },
|
|
100
127
|
inspectOwnership() { const d = diagnostic.inspectOwnership(); return { diagnostic: d, read_workers: readBudget.inspect(),
|
|
@@ -116,6 +143,8 @@ export async function createMcpDecisionRuntime({ runtime, ui, appOnlyMediationQu
|
|
|
116
143
|
open: (input, result, host) => session.open(input, result, host), read: (input, signal, host) => session.read(input, signal, host),
|
|
117
144
|
action: (input, host) => session.action(input, host), close: () => session.close() });
|
|
118
145
|
return Object.freeze({ ...protocol,
|
|
146
|
+
observeOutcome: (name, input, result) => runtime.observeOutcome?.(name, input, result) ?? false,
|
|
147
|
+
observesOutcome: (name, input, result) => runtime.observesOutcome?.(name, input, result) ?? false,
|
|
119
148
|
async postprocessToolResult(name, input, result, { uiSupported, client } = {}) {
|
|
120
149
|
if (name === 'agdf_inspect' && input.operation === 'native-qualification' && result.report?.available) {
|
|
121
150
|
return { ...result, report: { ...result.report, ui_rendering_support: uiSupported ? 'supported' : 'unsupported',
|
|
@@ -27,6 +27,7 @@ import {
|
|
|
27
27
|
import { defaultNpmInstallRoot, npmInvocation } from "../npm-invocation.js";
|
|
28
28
|
import { renameSyncWithRetry } from "#agdf-core/fs-swap.js";
|
|
29
29
|
import { fsyncDirectory, withOwnedFileLock } from '#agdf-core/owned-file-lock.js';
|
|
30
|
+
import { createPreparedCallJournal } from './prepared-call-journal.js';
|
|
30
31
|
|
|
31
32
|
const CLAIMS = '.agdf-executable-claims';
|
|
32
33
|
|
|
@@ -440,6 +441,12 @@ export function createMcpGenerationPublisher(base, { publicationDeadline = Infin
|
|
|
440
441
|
if (canonical !== base.publisher_root || !base.immutable) throw Error('runtime_publication_unowned');
|
|
441
442
|
return Object.freeze({
|
|
442
443
|
initial: base,
|
|
444
|
+
// Only a freshly owned publisher supplies persistent transport storage.
|
|
445
|
+
// This is lazy: constructing/discovering the SDK creates no journal files.
|
|
446
|
+
preparedCallStore({ surface }) {
|
|
447
|
+
return createPreparedCallJournal({ publisherRoot: canonical, identity: { surface, version: base.version,
|
|
448
|
+
server_digest: base.digest, dispatcher_digest: base.dispatcherDigest, sdk_digest: base.sdkDigest } });
|
|
449
|
+
},
|
|
443
450
|
resolve(candidate) {
|
|
444
451
|
const keys = ['schema_version', 'publication_id', 'version', 'server_digest', 'dispatcher_digest', 'sdk_digest'];
|
|
445
452
|
if (!candidate || Object.keys(candidate).sort().join() !== keys.sort().join()
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { execFileSync, spawn, fork } from "node:child_process";
|
|
2
|
-
import { cpSync, existsSync, lstatSync, mkdirSync, readFileSync, readdirSync, realpathSync, writeFileSync, rmdirSync } from "node:fs";
|
|
2
|
+
import { cpSync, existsSync, lstatSync, mkdirSync, readFileSync, readdirSync, realpathSync, writeFileSync, rmdirSync, unlinkSync } from "node:fs";
|
|
3
3
|
import { dirname, isAbsolute, join, resolve } from "node:path";
|
|
4
4
|
import process from "node:process";
|
|
5
5
|
import { createHash, randomUUID } from 'node:crypto';
|
|
6
6
|
import { digestDirectory, digestPluginMcpDispatcherSource, mcpDispatcherRuntimeEntries, mcpDispatcherPackageExports } from "#agdf-core/runtime/plugin-provenance.js";
|
|
7
7
|
import { acquireMcpExecutableClaim, inspectMcpServerPackage, mcpPackageConstants, mcpRuntimeRetirementState, prepareMcpServerPackage, createMcpRuntimeRetirementTransaction } from "./package.js";
|
|
8
|
+
import { inspectPreparedCallJournals, retirePreparedCallJournals } from './prepared-call-journal.js';
|
|
8
9
|
|
|
9
10
|
// Plugin-local AGDF MCP runtime shared by the hosts whose runtime plugin declares the server itself:
|
|
10
11
|
// Claude Code passes ${CLAUDE_PLUGIN_DATA}, which it deletes on uninstall; Codex receives an absolute
|
|
@@ -15,6 +16,12 @@ const SDK_PACKAGE_SPEC = "@modelcontextprotocol/server@2.0.0";
|
|
|
15
16
|
// the shipped digest; the override deliberately restores the unverified install and is recorded.
|
|
16
17
|
export const SDK_BUNDLE = Object.freeze({ manifest: "package.json", lock: "package-lock.json", expected: "expected-sdk.json" });
|
|
17
18
|
export const SDK_OVERRIDE_ENV = "AGDF_MCP_ALLOW_UNVERIFIED_SDK";
|
|
19
|
+
// The journal's data-root variable (COMPANION_DATA_ROOT_ENV of core companion/journal.js), kept as a
|
|
20
|
+
// literal so the launcher stays free of the journal module; the journal test asserts both agree.
|
|
21
|
+
export const COMPANION_DATA_ROOT_ENV = "AGDF_COMPANION_DATA_ROOT";
|
|
22
|
+
// The journal's directory and its two files below the data root (JOURNAL_DIRECTORY, JOURNAL_FILE and
|
|
23
|
+
// JOURNAL_ROTATED_FILE of core companion/journal.js), owned and removed with the runtime (SD SDD-006).
|
|
24
|
+
export const COMPANION_JOURNAL = Object.freeze({ directory: "companion", files: Object.freeze(["events.jsonl", "events.1.jsonl"]) });
|
|
18
25
|
export const SDK_VERIFICATION = Object.freeze({ verified: "verified", override: "unverified_override" });
|
|
19
26
|
|
|
20
27
|
function readJson(path) {
|
|
@@ -249,6 +256,10 @@ export async function launchPluginMcpServer({
|
|
|
249
256
|
return null;
|
|
250
257
|
}
|
|
251
258
|
const { surface, dataRoot, cockpitDir, cockpitMode, prepareOnly } = invocation;
|
|
259
|
+
// Companion events (companion core SDD-006): the facade and its generations journal final tool
|
|
260
|
+
// results below the data root this launcher received; the variable reaches them with the facade's
|
|
261
|
+
// environment only. Preparation keeps the launcher's own environment.
|
|
262
|
+
const facadeEnv = typeof dataRoot === 'string' && dataRoot ? { ...env, [COMPANION_DATA_ROOT_ENV]: resolve(dataRoot) } : env;
|
|
252
263
|
const publicationDeadline = performance.now() + CONCURRENT_PUBLICATION_WAIT_MS;
|
|
253
264
|
let runtime, waitingOwner;
|
|
254
265
|
try {
|
|
@@ -256,7 +267,7 @@ export async function launchPluginMcpServer({
|
|
|
256
267
|
// preparation. It cannot claim or start a facade until the private message
|
|
257
268
|
// carries the successfully verified publication.
|
|
258
269
|
if (!prepareOnly && !startFacade && acquireClaim === acquireMcpExecutableClaim && ensure === ensurePluginMcpRuntime)
|
|
259
|
-
waitingOwner = startFacadeOwner({ surface, cockpitDir, cockpitMode, pluginRoot, env, publicationDeadline });
|
|
270
|
+
waitingOwner = startFacadeOwner({ surface, cockpitDir, cockpitMode, pluginRoot, env: facadeEnv, publicationDeadline });
|
|
260
271
|
// Reject a damaged installed dispatcher before publication, claim acquisition
|
|
261
272
|
// or SDK execution. Its downstream resource context cannot qualify a facade;
|
|
262
273
|
// starting one first would correctly retain its unconfirmed executable use.
|
|
@@ -285,7 +296,7 @@ export async function launchPluginMcpServer({
|
|
|
285
296
|
// executable before fork and releases only after orderly teardown AND exit.
|
|
286
297
|
if (!startFacade && acquireClaim === acquireMcpExecutableClaim) {
|
|
287
298
|
try {
|
|
288
|
-
const owner = waitingOwner ?? startFacadeOwner({ runtime, surface, cockpitDir, cockpitMode, pluginRoot, env, publicationDeadline });
|
|
299
|
+
const owner = waitingOwner ?? startFacadeOwner({ runtime, surface, cockpitDir, cockpitMode, pluginRoot, env: facadeEnv, publicationDeadline });
|
|
289
300
|
waitingOwner?.activate(runtime);
|
|
290
301
|
return await owner.settled;
|
|
291
302
|
}
|
|
@@ -299,7 +310,7 @@ export async function launchPluginMcpServer({
|
|
|
299
310
|
? error.message : 'AGDF_MCP_EXECUTABLE_CLAIM_INVALID';
|
|
300
311
|
stderr.write(`${launcherFailureLine(code)}\n`); process.exitCode = 1; return null;
|
|
301
312
|
}
|
|
302
|
-
try { return await (startFacade ?? supervisePluginMcpFacade)({ runtime, surface, cockpitDir, cockpitMode, pluginRoot, env, publicationDeadline, claim }); }
|
|
313
|
+
try { return await (startFacade ?? supervisePluginMcpFacade)({ runtime, surface, cockpitDir, cockpitMode, pluginRoot, env: facadeEnv, publicationDeadline, claim }); }
|
|
303
314
|
catch (error) {
|
|
304
315
|
const code = Object.hasOwn(LAUNCHER_FAILURES, error?.message) ? error.message : 'AGDF_MCP_PLUGIN_RUNTIME_FAILED';
|
|
305
316
|
stderr.write(`${launcherFailureLine(code, 'facade')}\n`); process.exitCode = 1; return null;
|
|
@@ -376,12 +387,18 @@ export const claudePluginMcpConstants = Object.freeze({ sdkPackageSpec: SDK_PACK
|
|
|
376
387
|
|
|
377
388
|
// Codex keeps the plugin-local MCP runtime in an AGDF-owned data root because it passes no plugin data
|
|
378
389
|
// directory; `codex plugin remove` cannot delete it. `dataRoot` is the launcher data root (--data);
|
|
379
|
-
// uninstall removes it only when it holds nothing but owned runtimes and abandoned stages under mcp
|
|
390
|
+
// uninstall removes it only when it holds nothing but owned runtimes and abandoned stages under mcp/
|
|
391
|
+
// and the companion journal (a plain directory holding only its own regular files).
|
|
392
|
+
function ownedCompanionJournal(dataRoot) {
|
|
393
|
+
const directory = join(dataRoot, COMPANION_JOURNAL.directory), stats = lstatSync(directory);
|
|
394
|
+
if (!stats.isDirectory() || stats.isSymbolicLink()) return false;
|
|
395
|
+
return readdirSync(directory).every(name => COMPANION_JOURNAL.files.includes(name) && lstatSync(join(directory, name)).isFile());
|
|
396
|
+
}
|
|
380
397
|
export function inspectPluginMcpDataRoot(dataRoot) {
|
|
381
398
|
if (!existsSync(dataRoot)) return "absent";
|
|
382
399
|
try {
|
|
383
400
|
if (!lstatSync(dataRoot).isDirectory() || lstatSync(dataRoot).isSymbolicLink()) return "foreign";
|
|
384
|
-
if (readdirSync(dataRoot).some((name) => name !== "mcp")) return "foreign";
|
|
401
|
+
if (readdirSync(dataRoot).some((name) => name !== "mcp" && !(name === COMPANION_JOURNAL.directory && ownedCompanionJournal(dataRoot)))) return "foreign";
|
|
385
402
|
const mcpDataRoot = join(realpathSync(dataRoot), "mcp");
|
|
386
403
|
if (!existsSync(mcpDataRoot)) return "owned";
|
|
387
404
|
if (!lstatSync(mcpDataRoot).isDirectory() || lstatSync(mcpDataRoot).isSymbolicLink()) return "foreign";
|
|
@@ -390,6 +407,10 @@ export function inspectPluginMcpDataRoot(dataRoot) {
|
|
|
390
407
|
const path = join(mcpDataRoot, name);
|
|
391
408
|
const stats = lstatSync(path);
|
|
392
409
|
if (!stats.isDirectory() || stats.isSymbolicLink()) return "foreign";
|
|
410
|
+
if (name === 'prepared-calls') {
|
|
411
|
+
if (inspectPreparedCallJournals(mcpDataRoot) !== 'owned') return 'foreign';
|
|
412
|
+
continue;
|
|
413
|
+
}
|
|
393
414
|
if (name !== 'generations') {
|
|
394
415
|
if (!ownedRoot(path) && !name.startsWith('.stage-')) return 'foreign';
|
|
395
416
|
protectedFiles = true; continue;
|
|
@@ -430,7 +451,14 @@ export function retirePluginMcpDataRoot(dataRoot, revalidate = () => {}) {
|
|
|
430
451
|
rmdirSync(publication);
|
|
431
452
|
}
|
|
432
453
|
if (existsSync(generations)) rmdirSync(generations);
|
|
454
|
+
retirePreparedCallJournals(mcp);
|
|
433
455
|
if (existsSync(mcp)) rmdirSync(mcp);
|
|
456
|
+
const journal = join(dataRoot, COMPANION_JOURNAL.directory);
|
|
457
|
+
if (existsSync(journal)) {
|
|
458
|
+
revalidate();
|
|
459
|
+
for (const name of COMPANION_JOURNAL.files) if (existsSync(join(journal, name))) unlinkSync(join(journal, name));
|
|
460
|
+
rmdirSync(journal);
|
|
461
|
+
}
|
|
434
462
|
revalidate(); rmdirSync(dataRoot);
|
|
435
463
|
return true;
|
|
436
464
|
} catch (error) {
|
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
import { createHash, createHmac, randomBytes, randomUUID, timingSafeEqual } from 'node:crypto';
|
|
2
|
+
import { existsSync, lstatSync, mkdirSync, readFileSync, readdirSync, realpathSync, rmdirSync, unlinkSync } from 'node:fs';
|
|
3
|
+
import { dirname, join, resolve } from 'node:path';
|
|
4
|
+
import { atomicWrite, fsyncDirectory, withOwnedFileLock } from '#agdf-core/owned-file-lock.js';
|
|
5
|
+
import { renameSyncWithRetry } from '#agdf-core/fs-swap.js';
|
|
6
|
+
|
|
7
|
+
const OWNER = 'agdf-prepared-calls-v1', DIRECTORY = 'prepared-calls';
|
|
8
|
+
const MARKER = 'owner.json', KEY = 'key', RECORD = /^[0-9a-f]{8}(?:-[0-9a-f]{4}){3}-[0-9a-f]{12}\.json$/u;
|
|
9
|
+
// Each live connection still has its original 256-entry Map. The shared
|
|
10
|
+
// journal accommodates four such producers without silently evicting live IDs.
|
|
11
|
+
const DIGEST = /^[0-9a-f]{64}$/u, LIMIT = 65_536, LIFETIME = 30 * 60_000, CAPACITY = 1024;
|
|
12
|
+
const MAX_NAMESPACES = 16, MAX_BYTES = 64 * 1024 * 1024;
|
|
13
|
+
const bad = () => { throw Error('runtime_provenance_invalid'); };
|
|
14
|
+
const sha = text => createHash('sha256').update(text).digest('hex');
|
|
15
|
+
const json = value => JSON.stringify(value);
|
|
16
|
+
function privatePath(path, directory = false) {
|
|
17
|
+
const stat = lstatSync(path);
|
|
18
|
+
if (stat.isSymbolicLink() || (directory ? !stat.isDirectory() : !stat.isFile() || stat.nlink !== 1)
|
|
19
|
+
|| realpathSync(path) !== resolve(path)
|
|
20
|
+
|| process.getuid && stat.uid !== process.getuid()
|
|
21
|
+
|| process.platform !== 'win32' && (stat.mode & 0o077)) bad();
|
|
22
|
+
return stat;
|
|
23
|
+
}
|
|
24
|
+
function boundedRead(path, limit) {
|
|
25
|
+
if (privatePath(path).size > limit) bad();
|
|
26
|
+
return readFileSync(path);
|
|
27
|
+
}
|
|
28
|
+
function identityOf(identity) {
|
|
29
|
+
if (!identity || Object.keys(identity).sort().join() !== 'dispatcher_digest,sdk_digest,server_digest,surface,version'
|
|
30
|
+
|| !['codex', 'claude', 'copilot', 'opencode'].includes(identity.surface)
|
|
31
|
+
|| typeof identity.version !== 'string' || !identity.version || identity.version.length > 128
|
|
32
|
+
|| !['server_digest', 'dispatcher_digest', 'sdk_digest'].every(key => DIGEST.test(identity[key] ?? ''))) bad();
|
|
33
|
+
return { surface: identity.surface, version: identity.version, server_digest: identity.server_digest,
|
|
34
|
+
dispatcher_digest: identity.dispatcher_digest, sdk_digest: identity.sdk_digest };
|
|
35
|
+
}
|
|
36
|
+
function assertOwner(root) {
|
|
37
|
+
privatePath(root, true);
|
|
38
|
+
if (boundedRead(join(root, MARKER), 256).toString() !== json({ schema_version: 1, owner: OWNER })) bad();
|
|
39
|
+
}
|
|
40
|
+
function readNamespace(root, namespace) {
|
|
41
|
+
const dir = join(root, namespace); privatePath(dir, true);
|
|
42
|
+
const identity = JSON.parse(boundedRead(join(dir, MARKER), 2048));
|
|
43
|
+
if (identity.schema_version !== 1 || identity.owner !== OWNER || Object.keys(identity).sort().join() !== 'created,identity,owner,schema_version'
|
|
44
|
+
|| !Number.isSafeInteger(identity.created) || identity.created < 0
|
|
45
|
+
|| sha(json(identityOf(identity.identity))) !== namespace) bad();
|
|
46
|
+
const key = boundedRead(join(dir, KEY), 32); if (key.length !== 32) bad();
|
|
47
|
+
return { dir, key, created: identity.created };
|
|
48
|
+
}
|
|
49
|
+
const signature = (key, row) => createHmac('sha256', key).update(json(row)).digest('hex');
|
|
50
|
+
function readEntry(dir, name, key, namespace) {
|
|
51
|
+
if (!RECORD.test(name)) bad();
|
|
52
|
+
const record = JSON.parse(boundedRead(join(dir, name), 2 * LIMIT + 4096));
|
|
53
|
+
const { mac, ...row } = record;
|
|
54
|
+
if (!DIGEST.test(mac ?? '') || !timingSafeEqual(Buffer.from(mac, 'hex'), Buffer.from(signature(key, row), 'hex'))
|
|
55
|
+
|| row.schema_version !== 1 || row.namespace !== namespace || name !== row.id + '.json'
|
|
56
|
+
|| !Number.isSafeInteger(row.created) || row.created < 0 || !['available', 'expired'].includes(row.state)) bad();
|
|
57
|
+
const fields = row.state === 'available' ? 'created,id,namespace,schema_version,signature,state,value'
|
|
58
|
+
: 'created,id,namespace,schema_version,state';
|
|
59
|
+
if (Object.keys(row).sort().join() !== fields) bad();
|
|
60
|
+
if (row.state === 'available' && (typeof row.value !== 'string' || Buffer.byteLength(row.value) > LIMIT
|
|
61
|
+
|| !DIGEST.test(row.signature ?? '') || sha(row.value) !== row.signature)) bad();
|
|
62
|
+
return row;
|
|
63
|
+
}
|
|
64
|
+
function inspectRoot(publisherRoot) {
|
|
65
|
+
assertPublisherRoot(publisherRoot);
|
|
66
|
+
const root = join(publisherRoot, DIRECTORY);
|
|
67
|
+
if (!existsSync(root)) return 'absent';
|
|
68
|
+
assertOwner(root);
|
|
69
|
+
const namespaces = readdirSync(root).filter(name => name !== MARKER);
|
|
70
|
+
if (namespaces.length > MAX_NAMESPACES) bad();
|
|
71
|
+
let bytes = privatePath(join(root, MARKER)).size;
|
|
72
|
+
for (const namespace of namespaces) {
|
|
73
|
+
if (namespace === MARKER) continue;
|
|
74
|
+
if (!DIGEST.test(namespace)) bad();
|
|
75
|
+
const { dir, key } = readNamespace(root, namespace);
|
|
76
|
+
const names = readdirSync(dir);
|
|
77
|
+
if (names.length > 2 * CAPACITY + 2) bad();
|
|
78
|
+
let active = 0, expired = 0;
|
|
79
|
+
for (const name of names) {
|
|
80
|
+
bytes += privatePath(join(dir, name)).size;
|
|
81
|
+
if ([MARKER, KEY].includes(name)) continue;
|
|
82
|
+
const row = readEntry(dir, name, key, namespace);
|
|
83
|
+
row.state === 'available' ? active++ : expired++;
|
|
84
|
+
}
|
|
85
|
+
if (active > CAPACITY || expired > CAPACITY) bad();
|
|
86
|
+
}
|
|
87
|
+
if (bytes > MAX_BYTES) bad();
|
|
88
|
+
return 'owned';
|
|
89
|
+
}
|
|
90
|
+
export function inspectPreparedCallJournals(publisherRoot) {
|
|
91
|
+
try { return inspectRoot(publisherRoot); } catch { return 'foreign'; }
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function locked(publisherRoot, operation) {
|
|
95
|
+
assertPublisherRoot(publisherRoot);
|
|
96
|
+
const deadline = performance.now() + 5550;
|
|
97
|
+
for (;;) {
|
|
98
|
+
try { return withOwnedFileLock(join(publisherRoot, '.agdf-prepared-calls'), () => { assertPublisherRoot(publisherRoot); return operation(); }); }
|
|
99
|
+
catch (error) {
|
|
100
|
+
if (error?.message !== 'AGDF_RUN_WRITE_LOCKED') throw error;
|
|
101
|
+
if (error.lock_owner_status !== 'live') bad();
|
|
102
|
+
if (performance.now() >= deadline) throw Error('dispatch_busy');
|
|
103
|
+
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, 10);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
function assertPublisherRoot(root) {
|
|
108
|
+
const stat = lstatSync(root);
|
|
109
|
+
if (!stat.isDirectory() || stat.isSymbolicLink() || realpathSync(root) !== root
|
|
110
|
+
|| process.getuid && stat.uid !== process.getuid()) bad();
|
|
111
|
+
}
|
|
112
|
+
function normalizedError(error) {
|
|
113
|
+
if (['runtime_provenance_invalid', 'dispatch_busy'].includes(error?.message)) return error;
|
|
114
|
+
return Error('prepared_call_store_unavailable');
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// The publisher supplies the root and immutable producer identity. No tool
|
|
118
|
+
// argument can select this storage; constructing/discovering a server writes nothing.
|
|
119
|
+
export function createPreparedCallJournal({ publisherRoot, identity, now = Date.now,
|
|
120
|
+
lifetimeMs = LIFETIME, maxEntries = CAPACITY, maxBytes = MAX_BYTES, checkpoint = () => {} } = {}) {
|
|
121
|
+
const canonical = realpathSync(publisherRoot);
|
|
122
|
+
if (canonical !== publisherRoot || lstatSync(canonical).isSymbolicLink()
|
|
123
|
+
|| !Number.isSafeInteger(lifetimeMs) || lifetimeMs <= 0 || lifetimeMs > LIFETIME
|
|
124
|
+
|| !Number.isSafeInteger(maxEntries) || maxEntries <= 0 || maxEntries > CAPACITY
|
|
125
|
+
|| !Number.isSafeInteger(maxBytes) || maxBytes <= 0 || maxBytes > MAX_BYTES) bad();
|
|
126
|
+
assertPublisherRoot(canonical);
|
|
127
|
+
identity = identityOf(identity);
|
|
128
|
+
const namespace = sha(json(identity)), root = join(canonical, DIRECTORY), dir = join(root, namespace);
|
|
129
|
+
const publish = (row, key) => atomicWrite(join(dir, row.id + '.json'), json({ ...row, mac: signature(key, row) }));
|
|
130
|
+
function publishDirectory(target, contents, point) {
|
|
131
|
+
const stage = join(canonical, '.agdf-prepared-stage-' + randomUUID());
|
|
132
|
+
mkdirSync(stage, { mode: 0o700 }); const owned = lstatSync(stage);
|
|
133
|
+
try {
|
|
134
|
+
for (const [name, value] of Object.entries(contents)) atomicWrite(join(stage, name), value);
|
|
135
|
+
checkpoint(point);
|
|
136
|
+
if (existsSync(target)) bad();
|
|
137
|
+
renameSyncWithRetry(stage, target); fsyncDirectory(dirname(target));
|
|
138
|
+
} finally {
|
|
139
|
+
if (existsSync(stage)) {
|
|
140
|
+
const current = lstatSync(stage);
|
|
141
|
+
// A hard-killed unconfirmed sibling stage is retained by lifecycle
|
|
142
|
+
// inspection. Ordinary rollback removes only our same, unchanged inode
|
|
143
|
+
// and the exact initialization bytes authored by this invocation.
|
|
144
|
+
if (!current.isSymbolicLink() && current.dev === owned.dev && current.ino === owned.ino) {
|
|
145
|
+
for (const [name, value] of Object.entries(contents)) {
|
|
146
|
+
const file = join(stage, name);
|
|
147
|
+
if (existsSync(file) && boundedRead(file, 4096).equals(Buffer.from(value))) unlinkSync(file);
|
|
148
|
+
}
|
|
149
|
+
if (!readdirSync(stage).length) rmdirSync(stage);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
function removeNamespace(target) {
|
|
155
|
+
for (const name of readdirSync(target)) unlinkSync(join(target, name));
|
|
156
|
+
rmdirSync(target);
|
|
157
|
+
}
|
|
158
|
+
function pruneNamespaces(time) {
|
|
159
|
+
if (inspectRoot(canonical) !== 'owned') bad();
|
|
160
|
+
for (const name of readdirSync(root).filter(name => name !== MARKER)) {
|
|
161
|
+
const scope = readNamespace(root, name), rows = readdirSync(scope.dir).filter(file => ![MARKER, KEY].includes(file))
|
|
162
|
+
.map(file => readEntry(scope.dir, file, scope.key, name));
|
|
163
|
+
// Keep one further lifetime of signed tombstones. Never delete a live
|
|
164
|
+
// call from another candidate merely to make room for the current one.
|
|
165
|
+
const latest = Math.max(scope.created, ...rows.map(row => row.created));
|
|
166
|
+
if (name !== namespace && time - latest >= 2 * LIFETIME) removeNamespace(scope.dir);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
function size() {
|
|
170
|
+
return privatePath(join(root, MARKER)).size + readdirSync(root).filter(name => name !== MARKER).reduce((total, name) => {
|
|
171
|
+
const target = join(root, name);
|
|
172
|
+
return total + readdirSync(target).reduce((bytes, file) => bytes + privatePath(join(target, file)).size, 0);
|
|
173
|
+
}, 0);
|
|
174
|
+
}
|
|
175
|
+
function open(create = false, reserveBytes = 0) {
|
|
176
|
+
if (!existsSync(root)) {
|
|
177
|
+
if (!create) return null;
|
|
178
|
+
publishDirectory(root, { [MARKER]: json({ schema_version: 1, owner: OWNER }) }, 'root_staged');
|
|
179
|
+
}
|
|
180
|
+
assertOwner(root);
|
|
181
|
+
if (!existsSync(dir)) {
|
|
182
|
+
if (!create) return null;
|
|
183
|
+
// Verifying and pruning every namespace is costly; it runs only when a new
|
|
184
|
+
// namespace competes for the shared budget, not on every registration.
|
|
185
|
+
pruneNamespaces(now());
|
|
186
|
+
const marker = json({ schema_version: 1, owner: OWNER, identity, created: now() });
|
|
187
|
+
if (readdirSync(root).length - 1 >= MAX_NAMESPACES || size() + Buffer.byteLength(marker) + 32 + reserveBytes > maxBytes) return null;
|
|
188
|
+
publishDirectory(dir, { [MARKER]: marker, [KEY]: randomBytes(32) }, 'namespace_staged');
|
|
189
|
+
}
|
|
190
|
+
return readNamespace(root, namespace);
|
|
191
|
+
}
|
|
192
|
+
function entries(key) {
|
|
193
|
+
const names = readdirSync(dir).filter(name => ![MARKER, KEY].includes(name));
|
|
194
|
+
if (names.length > 2 * CAPACITY) bad();
|
|
195
|
+
return names.map(name => readEntry(dir, name, key, namespace));
|
|
196
|
+
}
|
|
197
|
+
function expire(rows, key, time) {
|
|
198
|
+
for (let index = 0; index < rows.length; index++) if (rows[index].state === 'available' && time - rows[index].created >= lifetimeMs) {
|
|
199
|
+
const old = rows[index], row = { schema_version: 1, namespace, id: old.id, created: old.created, state: 'expired' };
|
|
200
|
+
publish(row, key); rows[index] = row;
|
|
201
|
+
}
|
|
202
|
+
const expired = rows.filter(row => row.state === 'expired').sort((a, b) => b.created - a.created || a.id.localeCompare(b.id));
|
|
203
|
+
for (const row of expired.slice(maxEntries)) { unlinkSync(join(dir, row.id + '.json')); rows.splice(rows.indexOf(row), 1); }
|
|
204
|
+
}
|
|
205
|
+
function run(create, operation, reserveBytes = 0) {
|
|
206
|
+
try {
|
|
207
|
+
// Absent reads do not create lock/marker directories during discovery.
|
|
208
|
+
if (!create && !existsSync(root)) return { state: 'reference_unknown' };
|
|
209
|
+
return locked(canonical, () => { const opened = open(create, reserveBytes); return opened ? operation(opened.key) : create ? null : { state: 'reference_unknown' }; });
|
|
210
|
+
} catch (error) { throw normalizedError(error); }
|
|
211
|
+
}
|
|
212
|
+
return Object.freeze({
|
|
213
|
+
register({ value, signature: digest, created }) {
|
|
214
|
+
if (typeof value !== 'string' || Buffer.byteLength(value) > LIMIT || digest !== sha(value)
|
|
215
|
+
|| !Number.isSafeInteger(created) || created < 0) bad();
|
|
216
|
+
const estimate = Buffer.byteLength(json({ schema_version: 1, namespace, id: '00000000-0000-4000-8000-000000000000', created,
|
|
217
|
+
state: 'available', signature: digest, value, mac: '0'.repeat(64) }));
|
|
218
|
+
return run(true, key => {
|
|
219
|
+
const rows = entries(key), time = now(); expire(rows, key, time);
|
|
220
|
+
const previous = rows.find(row => row.state === 'available' && row.signature === digest && row.value === value);
|
|
221
|
+
if (previous) return { id: previous.id, created: previous.created };
|
|
222
|
+
if (rows.filter(row => row.state === 'available').length >= maxEntries) return null;
|
|
223
|
+
// Stale candidate namespaces are reclaimed only when the shared byte budget is reached.
|
|
224
|
+
if (size() + estimate > maxBytes) pruneNamespaces(time);
|
|
225
|
+
if (size() + estimate > maxBytes) return null;
|
|
226
|
+
const row = { schema_version: 1, namespace, id: randomUUID(), created, state: 'available', signature: digest, value };
|
|
227
|
+
publish(row, key); return { id: row.id, created: row.created };
|
|
228
|
+
}, estimate);
|
|
229
|
+
},
|
|
230
|
+
load(id) {
|
|
231
|
+
if (!RECORD.test(id + '.json')) return { state: 'reference_unknown' };
|
|
232
|
+
return run(false, key => {
|
|
233
|
+
const file = join(dir, id + '.json');
|
|
234
|
+
if (!existsSync(file)) return { state: 'reference_unknown' };
|
|
235
|
+
let row = readEntry(dir, id + '.json', key, namespace);
|
|
236
|
+
if (row.state === 'available' && now() - row.created >= lifetimeMs) {
|
|
237
|
+
const rows = entries(key); expire(rows, key, now()); row = rows.find(value => value.id === id);
|
|
238
|
+
}
|
|
239
|
+
return row?.state === 'available' ? { state: 'available', value: row.value, signature: row.signature, created: row.created }
|
|
240
|
+
: { state: 'reference_expired' };
|
|
241
|
+
});
|
|
242
|
+
},
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
// Called only after the plugin owner has retired its executable generations.
|
|
247
|
+
// Never adopts unknown records or follows a foreign/symlink entry for cleanup.
|
|
248
|
+
export function retirePreparedCallJournals(publisherRoot) {
|
|
249
|
+
const root = join(publisherRoot, DIRECTORY);
|
|
250
|
+
if (!existsSync(root)) return;
|
|
251
|
+
locked(publisherRoot, () => {
|
|
252
|
+
// The lifecycle owner removed generations before acquiring this lock. A
|
|
253
|
+
// concurrent preparer can recreate it in that gap; retain every reference
|
|
254
|
+
// if any new generation node is present, even before it is fully published.
|
|
255
|
+
let generations;
|
|
256
|
+
try { generations = lstatSync(join(publisherRoot, 'generations')); }
|
|
257
|
+
catch (error) { if (error.code !== 'ENOENT') throw error; }
|
|
258
|
+
if (generations) throw Error('AGDF_MCP_RUNTIME_RETAINED');
|
|
259
|
+
if (inspectRoot(publisherRoot) !== 'owned') bad();
|
|
260
|
+
for (const namespace of readdirSync(root).filter(name => name !== MARKER)) {
|
|
261
|
+
const dir = join(root, namespace);
|
|
262
|
+
for (const name of readdirSync(dir)) unlinkSync(join(dir, name));
|
|
263
|
+
rmdirSync(dir);
|
|
264
|
+
}
|
|
265
|
+
// The owner marker goes last: an interrupted cleanup still leaves a
|
|
266
|
+
// verifiable owned root instead of unmarked namespaces.
|
|
267
|
+
unlinkSync(join(root, MARKER)); rmdirSync(root);
|
|
268
|
+
});
|
|
269
|
+
}
|