vgxness 1.20.4 → 1.20.6
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/dist/adapters/claude/agent-renderer.js +82 -0
- package/dist/{mcp → adapters/claude/install}/claude-code-agent-config.js +64 -9
- package/dist/{mcp → adapters/claude/install}/claude-code-config.js +28 -6
- package/dist/{mcp → adapters/claude/install}/claude-code-project-memory.js +35 -5
- package/dist/{mcp → adapters/claude/install}/claude-code-scope.js +12 -3
- package/dist/{mcp → adapters/claude/install}/claude-code-user-config.js +26 -5
- package/dist/{mcp → adapters/claude/install}/claude-code-user-memory.js +47 -7
- package/dist/{mcp → adapters/claude/install}/client-install-claude-code-contract.js +45 -8
- package/dist/{mcp → adapters/claude/install}/client-install-claude-code.js +98 -14
- package/dist/adapters/json/agent-renderer.js +104 -0
- package/dist/adapters/opencode/agent-renderer.js +113 -0
- package/dist/{mcp → adapters/opencode/install}/client-install-opencode-contract.js +2 -2
- package/dist/{mcp → adapters/opencode/install}/client-install-opencode.js +1 -1
- package/dist/{mcp → adapters/opencode/install}/opencode-default-agent-config.js +2 -2
- package/dist/{mcp → adapters/opencode/install}/opencode-handoff-preview.js +60 -7
- package/dist/{mcp → adapters/opencode/install}/opencode-visibility.js +1 -1
- package/dist/adapters/provider-renderer.js +6 -0
- package/dist/agents/agent-activation-service.js +1 -263
- package/dist/agents/agent-lookup-contexts.js +1 -28
- package/dist/agents/agent-registry-service.js +1 -81
- package/dist/agents/agent-resolver.js +1 -287
- package/dist/agents/agent-seed-service.js +1 -157
- package/dist/agents/agent-seed-upgrade-service.js +1 -231
- package/dist/agents/agent-selector-resolver.js +1 -28
- package/dist/agents/boot-upgrade.js +1 -59
- package/dist/agents/canonical-agent-manifest.js +1 -245
- package/dist/agents/canonical-agent-projection.js +1 -236
- package/dist/agents/manager-profile-overlay-service.js +1 -60
- package/dist/agents/profile-model-routing.js +1 -30
- package/dist/agents/renderers/claude-renderer.js +1 -82
- package/dist/agents/renderers/index.js +1 -14
- package/dist/agents/renderers/json-renderer.js +1 -104
- package/dist/agents/renderers/opencode-renderer.js +1 -113
- package/dist/agents/renderers/provider-adapter.js +1 -6
- package/dist/agents/repositories/agent-seed-history.js +1 -128
- package/dist/agents/repositories/agents.js +1 -200
- package/dist/agents/repositories/manager-profile-overlays.js +1 -90
- package/dist/agents/schema.js +1 -1
- package/dist/application/agents/agent-activation-service.js +261 -0
- package/dist/application/agents/agent-lookup-contexts.js +28 -0
- package/dist/application/agents/agent-registry-service.js +81 -0
- package/dist/application/agents/agent-resolver.js +287 -0
- package/dist/application/agents/agent-seed-service.js +157 -0
- package/dist/application/agents/agent-seed-upgrade-service.js +231 -0
- package/dist/application/agents/agent-selector-resolver.js +28 -0
- package/dist/application/agents/boot-upgrade.js +59 -0
- package/dist/application/agents/canonical-agent-projection.js +236 -0
- package/dist/application/agents/manager-profile-overlay-service.js +68 -0
- package/dist/application/agents/profile-model-routing.js +30 -0
- package/dist/application/agents/renderers/claude-renderer.js +1 -0
- package/dist/application/agents/renderers/index.js +14 -0
- package/dist/application/agents/renderers/json-renderer.js +1 -0
- package/dist/application/agents/renderers/opencode-renderer.js +1 -0
- package/dist/application/agents/renderers/provider-adapter.js +1 -0
- package/dist/application/memory/active-work-preview.js +75 -0
- package/dist/application/memory/agent-memory-capture-service.js +498 -0
- package/dist/application/memory/import/dry-run-planner.js +58 -0
- package/dist/application/memory/import/index.js +3 -0
- package/dist/application/memory/import/observation-writer.js +226 -0
- package/dist/application/memory/import/package.js +179 -0
- package/dist/application/memory/memory-service.js +202 -0
- package/dist/application/memory/search.js +11 -0
- package/dist/{mcp → application/provider-setup}/provider-change-plan.js +74 -13
- package/dist/{mcp → application/provider-setup}/provider-doctor.js +201 -31
- package/dist/{mcp → application/provider-setup}/provider-health-types.js +1 -1
- package/dist/{mcp → application/provider-setup}/provider-status.js +170 -33
- package/dist/application/runs/execution-planning.js +180 -0
- package/dist/application/runs/operation-execution.js +1 -0
- package/dist/application/runs/operation-retry.js +129 -0
- package/dist/application/runs/resume-after-approval-result.js +88 -0
- package/dist/application/runs/run-insights.js +270 -0
- package/dist/application/runs/run-service.js +1480 -0
- package/dist/application/runs/run-snapshot-export-service.js +31 -0
- package/dist/application/runs/sandbox-process-execution.js +244 -0
- package/dist/application/runs/sandbox-worktree-planning.js +59 -0
- package/dist/application/runs/task-scoped-command-grant-service.js +224 -0
- package/dist/application/sdd/artifact-portability-service.js +137 -0
- package/dist/application/sdd/cockpit-read-model.js +195 -0
- package/dist/application/sdd/sdd-continuation-plan.js +265 -0
- package/dist/application/sdd/sdd-workflow-service.js +892 -0
- package/dist/application/skills/boot-seed.js +42 -0
- package/dist/application/skills/personal-skills.js +41 -0
- package/dist/application/skills/skill-export-service.js +34 -0
- package/dist/application/skills/skill-index-service.js +126 -0
- package/dist/application/skills/skill-payload.js +186 -0
- package/dist/application/skills/skill-registry-service.js +648 -0
- package/dist/application/skills/skill-resolver.js +368 -0
- package/dist/application/skills/skill-seed-service.js +242 -0
- package/dist/application/skills/skill-status-service.js +147 -0
- package/dist/cli/bun-bin.js +0 -0
- package/dist/cli/cli-flags.js +1 -387
- package/dist/cli/cli-help.js +1 -173
- package/dist/cli/cli-helpers.js +1 -77
- package/dist/cli/cli-types.js +1 -1
- package/dist/cli/commands/agent-skill-dispatcher.js +1 -700
- package/dist/cli/commands/index.js +1 -9
- package/dist/cli/commands/interactive-entrypoint-dispatcher.js +1 -14
- package/dist/cli/commands/mcp-dispatcher.js +1 -232
- package/dist/cli/commands/memory-sdd-dispatcher.js +1 -367
- package/dist/cli/commands/run-permission-dispatcher.js +1 -455
- package/dist/cli/commands/setup-dispatcher.js +1 -496
- package/dist/cli/commands/status-dispatcher.js +1 -130
- package/dist/cli/commands/verification-dispatcher.js +1 -47
- package/dist/cli/commands/workflow-dispatcher.js +1 -566
- package/dist/cli/dispatcher.js +1 -247
- package/dist/cli/doctor-renderer.js +1 -26
- package/dist/cli/home-tui-app.js +1 -411
- package/dist/cli/home-tui-controller.js +1 -314
- package/dist/cli/mcp-start-path.js +1 -21
- package/dist/cli/product-resume-renderer.js +1 -32
- package/dist/cli/product-status-renderer.js +1 -81
- package/dist/cli/sdd-renderer.js +1 -247
- package/dist/cli/setup-plan-renderer.js +1 -79
- package/dist/cli/setup-status-renderer.js +1 -50
- package/dist/cli/setup-tui-app.js +1 -130
- package/dist/cli/setup-tui-controller.js +1 -89
- package/dist/cli/tui/focus-reducer.js +1 -0
- package/dist/cli/tui/focus-types.js +1 -0
- package/dist/cli/tui/ink/app-shell.js +1 -0
- package/dist/cli/tui/ink/components.js +1 -38
- package/dist/cli/tui/ink/help-overlay.js +1 -0
- package/dist/cli/tui/ink/state-components.js +1 -0
- package/dist/cli/tui/ink/theme.js +1 -36
- package/dist/cli/tui/key-intents.js +1 -0
- package/dist/cli/tui/keymap.js +1 -20
- package/dist/cli/tui/navigation.js +1 -10
- package/dist/cli/tui/screen-registry.js +1 -0
- package/dist/cli/tui/terminal-capabilities.js +1 -12
- package/dist/cli/tui/tui-types.js +1 -1
- package/dist/cli/tui/visual/badges.js +1 -19
- package/dist/cli/tui/visual/footer.js +1 -27
- package/dist/cli/tui/visual/index.js +1 -3
- package/dist/cli/tui/visual/viewport.js +1 -11
- package/dist/cli/tui-render-helpers.js +1 -200
- package/dist/cli/verification-plan-renderer.js +1 -25
- package/dist/cli/verification-report-renderer.js +1 -19
- package/dist/domain/agents/canonical-agent-manifest.js +355 -0
- package/dist/domain/agents/schema.js +1 -0
- package/dist/domain/memory/active-work-topics.js +64 -0
- package/dist/domain/memory/memory-capture-schema.js +1 -0
- package/dist/domain/memory/schema.js +1 -0
- package/dist/domain/runs/schema.js +5 -0
- package/dist/domain/sdd/cockpit-types.js +1 -0
- package/dist/domain/sdd/schema.js +111 -0
- package/dist/domain/skills/schema.js +1 -0
- package/dist/governance/risk-classifier.js +2 -0
- package/dist/interfaces/cli/bun-bin.js +46 -0
- package/dist/interfaces/cli/cli-flags.js +391 -0
- package/dist/interfaces/cli/cli-help.js +173 -0
- package/dist/interfaces/cli/cli-helpers.js +77 -0
- package/dist/interfaces/cli/cli-types.js +1 -0
- package/dist/interfaces/cli/commands/agent-skill-dispatcher.js +700 -0
- package/dist/interfaces/cli/commands/index.js +9 -0
- package/dist/interfaces/cli/commands/interactive-entrypoint-dispatcher.js +14 -0
- package/dist/interfaces/cli/commands/mcp-dispatcher.js +252 -0
- package/dist/interfaces/cli/commands/memory-sdd-dispatcher.js +367 -0
- package/dist/interfaces/cli/commands/run-permission-dispatcher.js +460 -0
- package/dist/interfaces/cli/commands/setup-dispatcher.js +496 -0
- package/dist/interfaces/cli/commands/status-dispatcher.js +130 -0
- package/dist/interfaces/cli/commands/verification-dispatcher.js +47 -0
- package/dist/interfaces/cli/commands/workflow-dispatcher.js +566 -0
- package/dist/interfaces/cli/dispatcher.js +247 -0
- package/dist/interfaces/cli/doctor-renderer.js +26 -0
- package/dist/interfaces/cli/home-tui-app.js +462 -0
- package/dist/interfaces/cli/home-tui-controller.js +341 -0
- package/dist/interfaces/cli/index.js +27 -0
- package/dist/interfaces/cli/mcp-start-path.js +21 -0
- package/dist/interfaces/cli/product-resume-renderer.js +32 -0
- package/dist/interfaces/cli/product-status-renderer.js +81 -0
- package/dist/interfaces/cli/sdd-renderer.js +247 -0
- package/dist/interfaces/cli/setup-plan-renderer.js +79 -0
- package/dist/interfaces/cli/setup-status-renderer.js +50 -0
- package/dist/interfaces/cli/setup-tui-app.js +135 -0
- package/dist/interfaces/cli/setup-tui-controller.js +89 -0
- package/dist/interfaces/cli/tui/focus-reducer.js +60 -0
- package/dist/interfaces/cli/tui/focus-types.js +10 -0
- package/dist/interfaces/cli/tui/ink/app-shell.js +16 -0
- package/dist/interfaces/cli/tui/ink/components.js +38 -0
- package/dist/interfaces/cli/tui/ink/help-overlay.js +6 -0
- package/dist/interfaces/cli/tui/ink/state-components.js +22 -0
- package/dist/interfaces/cli/tui/ink/theme.js +36 -0
- package/dist/interfaces/cli/tui/key-intents.js +33 -0
- package/dist/interfaces/cli/tui/keymap.js +20 -0
- package/dist/interfaces/cli/tui/navigation.js +10 -0
- package/dist/interfaces/cli/tui/screen-registry.js +43 -0
- package/dist/interfaces/cli/tui/terminal-capabilities.js +12 -0
- package/dist/interfaces/cli/tui/tui-types.js +1 -0
- package/dist/interfaces/cli/tui/visual/badges.js +19 -0
- package/dist/interfaces/cli/tui/visual/footer.js +27 -0
- package/dist/interfaces/cli/tui/visual/index.js +3 -0
- package/dist/interfaces/cli/tui/visual/viewport.js +11 -0
- package/dist/interfaces/cli/tui-render-helpers.js +200 -0
- package/dist/interfaces/cli/verification-plan-renderer.js +25 -0
- package/dist/interfaces/cli/verification-report-renderer.js +19 -0
- package/dist/interfaces/mcp/contracts/agents.js +1 -0
- package/dist/interfaces/mcp/contracts/context.js +1 -0
- package/dist/interfaces/mcp/contracts/governance.js +1 -0
- package/dist/interfaces/mcp/contracts/index.js +1 -0
- package/dist/interfaces/mcp/contracts/memory.js +1 -0
- package/dist/interfaces/mcp/contracts/providers.js +1 -0
- package/dist/interfaces/mcp/contracts/runs.js +1 -0
- package/dist/interfaces/mcp/contracts/sdd.js +1 -0
- package/dist/interfaces/mcp/contracts/sessions.js +1 -0
- package/dist/interfaces/mcp/contracts/skills.js +1 -0
- package/dist/interfaces/mcp/contracts/verification.js +1 -0
- package/dist/interfaces/mcp/control-plane/handlers/agents.js +38 -0
- package/dist/interfaces/mcp/control-plane/handlers/context.js +12 -0
- package/dist/interfaces/mcp/control-plane/handlers/memory.js +95 -0
- package/dist/interfaces/mcp/control-plane/handlers/providers.js +19 -0
- package/dist/interfaces/mcp/control-plane/handlers/runs.js +134 -0
- package/dist/interfaces/mcp/control-plane/handlers/sdd.js +225 -0
- package/dist/interfaces/mcp/control-plane/handlers/sessions.js +39 -0
- package/dist/interfaces/mcp/control-plane/handlers/skills.js +82 -0
- package/dist/interfaces/mcp/control-plane/handlers/verification.js +11 -0
- package/dist/interfaces/mcp/control-plane/types.js +1 -0
- package/dist/interfaces/mcp/control-plane.js +235 -0
- package/dist/interfaces/mcp/schema.js +174 -0
- package/dist/interfaces/mcp/schemas/common.js +121 -0
- package/dist/interfaces/mcp/schemas/inputs/agents.js +69 -0
- package/dist/interfaces/mcp/schemas/inputs/context.js +32 -0
- package/dist/interfaces/mcp/schemas/inputs/governance.js +23 -0
- package/dist/interfaces/mcp/schemas/inputs/index.js +10 -0
- package/dist/interfaces/mcp/schemas/inputs/memory.js +50 -0
- package/dist/interfaces/mcp/schemas/inputs/providers.js +35 -0
- package/dist/interfaces/mcp/schemas/inputs/runs.js +146 -0
- package/dist/interfaces/mcp/schemas/inputs/sdd.js +102 -0
- package/dist/interfaces/mcp/schemas/inputs/sessions.js +32 -0
- package/dist/interfaces/mcp/schemas/inputs/skills.js +231 -0
- package/dist/interfaces/mcp/schemas/inputs/verification.js +9 -0
- package/dist/interfaces/mcp/schemas/outputs/index.js +2 -0
- package/dist/interfaces/mcp/schemas/outputs/providers.js +28 -0
- package/dist/interfaces/mcp/schemas/outputs/sdd.js +166 -0
- package/dist/interfaces/mcp/stdio-server.js +116 -0
- package/dist/interfaces/mcp/validation/agents.js +189 -0
- package/dist/interfaces/mcp/validation/common.js +415 -0
- package/dist/interfaces/mcp/validation/governance.js +50 -0
- package/dist/interfaces/mcp/validation/memory.js +133 -0
- package/dist/interfaces/mcp/validation/providers.js +94 -0
- package/dist/interfaces/mcp/validation/runs.js +514 -0
- package/dist/interfaces/mcp/validation/sdd.js +247 -0
- package/dist/interfaces/mcp/validation/sessions.js +51 -0
- package/dist/interfaces/mcp/validation/skills.js +685 -0
- package/dist/interfaces/mcp/validation/verification.js +24 -0
- package/dist/interfaces/mcp/validation.js +149 -0
- package/dist/mcp/control-plane-snapshot-service.js +65 -2
- package/dist/mcp/control-plane.js +1 -646
- package/dist/mcp/doctor.js +1 -1
- package/dist/mcp/index.js +17 -17
- package/dist/mcp/schema.js +1 -1072
- package/dist/mcp/stdio-server.js +1 -116
- package/dist/mcp/validation.js +1 -2239
- package/dist/memory/active-work-preview.js +1 -75
- package/dist/memory/active-work-topics.js +1 -64
- package/dist/memory/agent-memory-capture-service.js +1 -497
- package/dist/memory/import/dry-run-planner.js +1 -58
- package/dist/memory/import/index.js +1 -3
- package/dist/memory/import/observation-writer.js +1 -226
- package/dist/memory/import/package.js +1 -179
- package/dist/memory/memory-capture-schema.js +1 -1
- package/dist/memory/memory-service.js +1 -201
- package/dist/memory/repositories/artifacts.js +1 -67
- package/dist/memory/repositories/observations.js +1 -217
- package/dist/memory/repositories/sessions.js +1 -125
- package/dist/memory/repositories/traces.js +1 -78
- package/dist/memory/schema.js +1 -1
- package/dist/memory/search.js +1 -11
- package/dist/memory/sqlite/database.js +1 -228
- package/dist/memory/storage-paths.js +1 -72
- package/dist/payload/context-budget-policy.js +10 -0
- package/dist/payload/context-budget-service.js +26 -0
- package/dist/payload/payload-diagnostics.js +50 -0
- package/dist/permissions/explicit-request-authorization.js +126 -0
- package/dist/permissions/policy-evaluator.js +54 -14
- package/dist/runs/execution-planning.js +1 -178
- package/dist/runs/operation-execution.js +1 -1
- package/dist/runs/operation-retry.js +1 -129
- package/dist/runs/repositories/runs.js +1 -676
- package/dist/runs/repositories/task-scoped-command-grants.js +1 -462
- package/dist/runs/resume-after-approval-result.js +1 -84
- package/dist/runs/run-insights.js +1 -270
- package/dist/runs/run-service.js +1 -1439
- package/dist/runs/run-snapshot-export-service.js +1 -31
- package/dist/runs/sandbox-process-execution.js +1 -240
- package/dist/runs/sandbox-worktree-planning.js +1 -59
- package/dist/runs/schema.js +1 -5
- package/dist/runs/task-scoped-command-grant-service.js +1 -216
- package/dist/sdd/artifact-portability-service.js +1 -137
- package/dist/sdd/cockpit-read-model.js +1 -195
- package/dist/sdd/cockpit-types.js +1 -1
- package/dist/sdd/schema.js +1 -111
- package/dist/sdd/sdd-continuation-plan.js +1 -265
- package/dist/sdd/sdd-workflow-service.js +1 -822
- package/dist/setup/providers/claude-setup-adapter.js +11 -4
- package/dist/setup/providers/opencode-setup-adapter.js +10 -7
- package/dist/setup/setup-plan.js +20 -7
- package/dist/skills/boot-seed.js +1 -42
- package/dist/skills/personal-skills.js +1 -41
- package/dist/skills/repositories/skill-evaluation-requests.js +1 -190
- package/dist/skills/repositories/skill-evaluation-scenarios.js +1 -305
- package/dist/skills/repositories/skill-improvement-proposals.js +1 -355
- package/dist/skills/repositories/skills.js +1 -1077
- package/dist/skills/schema.js +1 -1
- package/dist/skills/skill-export-service.js +1 -34
- package/dist/skills/skill-index-service.js +1 -126
- package/dist/skills/skill-payload.js +1 -186
- package/dist/skills/skill-registry-service.js +1 -644
- package/dist/skills/skill-resolver.js +1 -368
- package/dist/skills/skill-seed-service.js +1 -242
- package/dist/skills/skill-status-service.js +1 -147
- package/dist/storage/agents/repositories/agent-seed-history.js +128 -0
- package/dist/storage/agents/repositories/agents.js +200 -0
- package/dist/storage/agents/repositories/manager-profile-overlays.js +90 -0
- package/dist/storage/memory/repositories/artifacts.js +67 -0
- package/dist/storage/memory/repositories/observations.js +217 -0
- package/dist/storage/memory/repositories/sessions.js +125 -0
- package/dist/storage/memory/repositories/traces.js +78 -0
- package/dist/storage/memory/sqlite/database.js +228 -0
- package/dist/storage/memory/storage-paths.js +72 -0
- package/dist/storage/runs/repositories/runs.js +676 -0
- package/dist/storage/runs/repositories/task-scoped-command-grants.js +464 -0
- package/dist/storage/skills/repositories/skill-evaluation-requests.js +190 -0
- package/dist/storage/skills/repositories/skill-evaluation-scenarios.js +305 -0
- package/dist/storage/skills/repositories/skill-improvement-proposals.js +355 -0
- package/dist/storage/skills/repositories/skills.js +1084 -0
- package/docs/architecture.md +2 -2
- package/docs/glossary.md +1 -1
- package/docs/mcp.md +1 -1
- package/docs/module-boundaries.md +114 -0
- package/docs/prd.md +1 -1
- package/docs/project-health-audit-v1.10.x.md +1 -1
- package/docs/providers.md +2 -2
- package/docs/safety.md +3 -3
- package/docs/sdd/archive/2026-06-26-ambitious-structure-reorganization/apply-progress.md +122 -0
- package/docs/sdd/archive/2026-06-26-ambitious-structure-reorganization/archive-report.md +61 -0
- package/docs/sdd/archive/2026-06-26-ambitious-structure-reorganization/design.md +66 -0
- package/docs/sdd/archive/2026-06-26-ambitious-structure-reorganization/proposal.md +79 -0
- package/docs/sdd/archive/2026-06-26-ambitious-structure-reorganization/spec.md +67 -0
- package/docs/sdd/archive/2026-06-26-ambitious-structure-reorganization/tasks.md +63 -0
- package/docs/sdd/archive/2026-06-26-ambitious-structure-reorganization/verify-report.md +71 -0
- package/docs/sdd/archive/2026-06-26-legacy-facade-cleanup/apply-progress.md +68 -0
- package/docs/sdd/archive/2026-06-26-legacy-facade-cleanup/archive-report.md +61 -0
- package/docs/sdd/archive/2026-06-26-legacy-facade-cleanup/design.md +43 -0
- package/docs/sdd/archive/2026-06-26-legacy-facade-cleanup/proposal.md +61 -0
- package/docs/sdd/archive/2026-06-26-legacy-facade-cleanup/spec.md +31 -0
- package/docs/sdd/archive/2026-06-26-legacy-facade-cleanup/tasks.md +27 -0
- package/docs/sdd/archive/2026-06-26-legacy-facade-cleanup/verify-report.md +58 -0
- package/docs/sdd/archive/2026-06-26-provider-install-adapter-boundary/apply-progress.md +65 -0
- package/docs/sdd/archive/2026-06-26-provider-install-adapter-boundary/archive-report.md +53 -0
- package/docs/sdd/archive/2026-06-26-provider-install-adapter-boundary/design.md +64 -0
- package/docs/sdd/archive/2026-06-26-provider-install-adapter-boundary/proposal.md +62 -0
- package/docs/sdd/archive/2026-06-26-provider-install-adapter-boundary/spec.md +51 -0
- package/docs/sdd/archive/2026-06-26-provider-install-adapter-boundary/tasks.md +50 -0
- package/docs/sdd/archive/2026-06-26-provider-install-adapter-boundary/verify-report.md +66 -0
- package/docs/storage.md +2 -2
- package/package.json +2 -2
- /package/dist/{mcp → adapters/claude/install}/claude-code-cli.js +0 -0
- /package/dist/{memory → storage/memory}/sqlite/migrations/001_initial.sql +0 -0
- /package/dist/{memory → storage/memory}/sqlite/migrations/002_observation_revisions.sql +0 -0
- /package/dist/{memory → storage/memory}/sqlite/migrations/003_agent_registry.sql +0 -0
- /package/dist/{memory → storage/memory}/sqlite/migrations/004_run_runtime.sql +0 -0
- /package/dist/{memory → storage/memory}/sqlite/migrations/005_run_approvals.sql +0 -0
- /package/dist/{memory → storage/memory}/sqlite/migrations/006_run_operation_attempts.sql +0 -0
- /package/dist/{memory → storage/memory}/sqlite/migrations/007_abandoned_operation_attempts.sql +0 -0
- /package/dist/{memory → storage/memory}/sqlite/migrations/008_run_execution_plan_events.sql +0 -0
- /package/dist/{memory → storage/memory}/sqlite/migrations/009_multiple_operation_attempts.sql +0 -0
- /package/dist/{memory → storage/memory}/sqlite/migrations/010_skill_registry.sql +0 -0
- /package/dist/{memory → storage/memory}/sqlite/migrations/011_skill_usage_resolution_outcomes.sql +0 -0
- /package/dist/{memory → storage/memory}/sqlite/migrations/012_skill_improvement_proposals.sql +0 -0
- /package/dist/{memory → storage/memory}/sqlite/migrations/013_skill_evaluation_scenarios.sql +0 -0
- /package/dist/{memory → storage/memory}/sqlite/migrations/014_manager_profile_overlays.sql +0 -0
- /package/dist/{memory → storage/memory}/sqlite/migrations/015_artifact_metadata.sql +0 -0
- /package/dist/{memory → storage/memory}/sqlite/migrations/016_agent_seed_history.sql +0 -0
- /package/dist/{memory → storage/memory}/sqlite/migrations/017_intent_signal_skill_targets.sql +0 -0
- /package/dist/{memory → storage/memory}/sqlite/migrations/018_skill_system_v2.sql +0 -0
- /package/dist/{memory → storage/memory}/sqlite/migrations/019_task_scoped_command_grants.sql +0 -0
|
@@ -3,6 +3,7 @@ import { dirname, isAbsolute, resolve, sep } from 'node:path';
|
|
|
3
3
|
import { classifyOperationRisk } from '../governance/risk-classifier.js';
|
|
4
4
|
import { isSddPhase, sddPhases } from '../sdd/schema.js';
|
|
5
5
|
import { commandAllowlistIds } from '../workflows/command-allowlist-adapter.js';
|
|
6
|
+
import { evaluateExplicitRequestAuthorization } from './explicit-request-authorization.js';
|
|
6
7
|
export { isRiskyPermissionCategory, permissionCategories, riskyPermissionCategories } from './schema.js';
|
|
7
8
|
export const permissionDecisions = ['allow', 'ask', 'deny'];
|
|
8
9
|
export const permissionModes = ['allow', 'audit', 'require-preflight', 'deny'];
|
|
@@ -21,8 +22,8 @@ export const defaultPermissionPolicy = {
|
|
|
21
22
|
{ category: 'network', decision: 'ask', reason: 'Network access is external and requires approval by default.' },
|
|
22
23
|
{ category: 'git', decision: 'ask', reason: 'Git operations can affect review state or remotes.' },
|
|
23
24
|
{ category: 'git-write', decision: 'ask', reason: 'Git writes can affect review state or remotes.' },
|
|
24
|
-
{ category: 'memory', decision: 'ask', reason: 'Memory
|
|
25
|
-
{ category: 'memory-write', decision: 'ask', reason: 'Memory writes are durable and
|
|
25
|
+
{ category: 'memory', decision: 'ask', reason: 'Memory reads/writes are durable and audited; ordinary qualifying memory writes may proceed without duplicate confirmation.' },
|
|
26
|
+
{ category: 'memory-write', decision: 'ask', reason: 'Memory writes are durable and audited; ordinary qualifying memory writes may proceed without duplicate confirmation.' },
|
|
26
27
|
{ category: 'external-directory', decision: 'deny', reason: 'External directory access is denied unless a future sandbox grants it explicitly.' },
|
|
27
28
|
{ category: 'provider-tool', decision: 'ask', reason: 'Provider-specific tools stay opaque and require approval by default.' },
|
|
28
29
|
{ category: 'secrets', decision: 'deny', reason: 'Secret access is privileged and denied by default.' },
|
|
@@ -41,8 +42,8 @@ const planningPhaseModes = {
|
|
|
41
42
|
network: 'require-preflight',
|
|
42
43
|
git: 'require-preflight',
|
|
43
44
|
'git-write': 'require-preflight',
|
|
44
|
-
memory: '
|
|
45
|
-
'memory-write': '
|
|
45
|
+
memory: 'audit',
|
|
46
|
+
'memory-write': 'audit',
|
|
46
47
|
'external-directory': 'deny',
|
|
47
48
|
'provider-tool': 'audit',
|
|
48
49
|
secrets: 'deny',
|
|
@@ -69,7 +70,14 @@ export const sddPhasePermissionMatrix = Object.fromEntries(sddPhases.map((phase)
|
|
|
69
70
|
if (phase === 'archive')
|
|
70
71
|
return [
|
|
71
72
|
phase,
|
|
72
|
-
{
|
|
73
|
+
{
|
|
74
|
+
...verifyPhaseModes,
|
|
75
|
+
edit: 'require-preflight',
|
|
76
|
+
git: 'require-preflight',
|
|
77
|
+
'git-write': 'require-preflight',
|
|
78
|
+
memory: 'audit',
|
|
79
|
+
'memory-write': 'audit',
|
|
80
|
+
},
|
|
73
81
|
];
|
|
74
82
|
return [phase, planningPhaseModes];
|
|
75
83
|
}));
|
|
@@ -85,30 +93,30 @@ const filesystemCategories = new Set([
|
|
|
85
93
|
export function evaluatePermission(request, policy = defaultPermissionPolicy) {
|
|
86
94
|
const risk = classifyOperationRisk(request);
|
|
87
95
|
if (request.category === 'secrets')
|
|
88
|
-
return result(request, 'deny', 'secret_access', 'Secret access is denied by default.', {}, risk);
|
|
96
|
+
return withExplicitRequestAuthorization(request, result(request, 'deny', 'secret_access', 'Secret access is denied by default.', {}, risk), risk);
|
|
89
97
|
if (request.category === 'external-directory') {
|
|
90
|
-
return result(request, 'deny', 'workspace_boundary', 'External directory access is denied by the foundation policy.', {}, risk);
|
|
98
|
+
return withExplicitRequestAuthorization(request, result(request, 'deny', 'workspace_boundary', 'External directory access is denied by the foundation policy.', {}, risk), risk);
|
|
91
99
|
}
|
|
92
100
|
const hardRisk = hardRiskDecision(request, risk);
|
|
93
101
|
if (hardRisk !== undefined)
|
|
94
|
-
return hardRisk;
|
|
102
|
+
return withExplicitRequestAuthorization(request, hardRisk, risk);
|
|
95
103
|
const workspaceEscape = workspaceEscapeDecision(request);
|
|
96
104
|
if (workspaceEscape !== undefined)
|
|
97
|
-
return workspaceEscape;
|
|
105
|
+
return withExplicitRequestAuthorization(request, workspaceEscape, risk);
|
|
98
106
|
const verifyAllowlistedCommand = verifyAllowlistedCommandDecision(request, risk);
|
|
99
107
|
if (verifyAllowlistedCommand !== undefined)
|
|
100
108
|
return verifyAllowlistedCommand;
|
|
101
109
|
const sddPhaseDecision = phaseMatrixDecision(request);
|
|
102
110
|
if (sddPhaseDecision !== undefined && sddPhaseDecision.mode !== 'allow' && sddPhaseDecision.mode !== 'audit')
|
|
103
|
-
return sddPhaseDecision;
|
|
111
|
+
return withExplicitRequestAuthorization(request, sddPhaseDecision, risk);
|
|
104
112
|
const explicitValidation = explicitValidationDecision(request, risk);
|
|
105
113
|
if (explicitValidation !== undefined)
|
|
106
|
-
return explicitValidation;
|
|
114
|
+
return withExplicitRequestAuthorization(request, explicitValidation, risk);
|
|
107
115
|
if (sddPhaseDecision !== undefined)
|
|
108
116
|
return sddPhaseDecision;
|
|
109
117
|
const boundary = workspaceBoundaryDecision(request);
|
|
110
118
|
if (boundary !== undefined)
|
|
111
|
-
return boundary;
|
|
119
|
+
return withExplicitRequestAuthorization(request, boundary, risk);
|
|
112
120
|
const agentDecision = request.agent?.permissions[request.category];
|
|
113
121
|
const baseRule = policy.rules.find((rule) => rule.category === request.category);
|
|
114
122
|
const baseDecision = agentDecision ?? baseRule?.decision ?? 'ask';
|
|
@@ -118,7 +126,7 @@ export function evaluatePermission(request, policy = defaultPermissionPolicy) {
|
|
|
118
126
|
: (baseRule?.reason ?? `No explicit rule exists for ${request.category}; ask by default.`);
|
|
119
127
|
const flagRisk = riskDecision(request);
|
|
120
128
|
if (flagRisk !== undefined && isLessRestrictive(baseDecision, flagRisk.decision)) {
|
|
121
|
-
return result(request, flagRisk.decision, flagRisk.reason, flagRisk.message, {}, risk);
|
|
129
|
+
return withExplicitRequestAuthorization(request, result(request, flagRisk.decision, flagRisk.reason, flagRisk.message, {}, risk), risk);
|
|
122
130
|
}
|
|
123
131
|
if (risk.defaultDecision === 'audit' && baseDecision !== 'deny') {
|
|
124
132
|
return result(request, 'allow', risk.reasonCodes.includes('provider_readonly_audit') ? 'provider_readonly_audit' : risk.reasonCodes.includes('allowlisted_verification') ? 'allowlisted_command' : baseReason, baseMessage, {
|
|
@@ -127,7 +135,39 @@ export function evaluatePermission(request, policy = defaultPermissionPolicy) {
|
|
|
127
135
|
warnings: risk.reasonCodes.includes('provider_readonly_audit') ? ['provider-readonly-audit-only'] : ['audit-only'],
|
|
128
136
|
}, risk);
|
|
129
137
|
}
|
|
130
|
-
return result(request, baseDecision, baseReason, baseMessage, {}, risk);
|
|
138
|
+
return withExplicitRequestAuthorization(request, result(request, baseDecision, baseReason, baseMessage, {}, risk), risk);
|
|
139
|
+
}
|
|
140
|
+
function withExplicitRequestAuthorization(request, decision, risk) {
|
|
141
|
+
if (request.explicitRequest === undefined)
|
|
142
|
+
return decision;
|
|
143
|
+
const explicit = evaluateExplicitRequestAuthorization({ request, risk, evaluatedAt: new Date().toISOString() });
|
|
144
|
+
if (decision.decision !== 'ask') {
|
|
145
|
+
return { ...decision, explicitRequestAudit: explicit.audit, auditEvidence: [...(decision.auditEvidence ?? []), `explicitRequest:${explicit.audit.matchStatus}`] };
|
|
146
|
+
}
|
|
147
|
+
if (explicit.decision === 'allow') {
|
|
148
|
+
return {
|
|
149
|
+
...decision,
|
|
150
|
+
decision: 'allow',
|
|
151
|
+
reason: 'explicit_request_authorization',
|
|
152
|
+
message: 'Explicit human request authorizes this exact one-off operation.',
|
|
153
|
+
explicitRequestAudit: explicit.audit,
|
|
154
|
+
authorizationMode: 'explicit-request',
|
|
155
|
+
auditEvidence: [...(decision.auditEvidence ?? []), 'explicitRequest:exact-match'],
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
if (explicit.decision === 'deny') {
|
|
159
|
+
return {
|
|
160
|
+
...decision,
|
|
161
|
+
decision: 'deny',
|
|
162
|
+
reason: explicit.audit.reasonCodes.includes('sdd_human_acceptance_required') ? 'sdd_phase_policy' : 'risk_tier_policy',
|
|
163
|
+
message: explicit.audit.reasonCodes.includes('sdd_human_acceptance_required')
|
|
164
|
+
? 'SDD artifact acceptance is human-only and cannot be inferred from explicit-request preflight.'
|
|
165
|
+
: 'Explicit request contains a hard-stop condition and cannot authorize this operation.',
|
|
166
|
+
explicitRequestAudit: explicit.audit,
|
|
167
|
+
auditEvidence: [...(decision.auditEvidence ?? []), `explicitRequest:${explicit.audit.matchStatus}`],
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
return { ...decision, explicitRequestAudit: explicit.audit, auditEvidence: [...(decision.auditEvidence ?? []), `explicitRequest:${explicit.audit.matchStatus}`] };
|
|
131
171
|
}
|
|
132
172
|
export function isPathInsideWorkspace(workspaceRoot, targetPath) {
|
|
133
173
|
const root = resolve(workspaceRoot);
|
|
@@ -1,178 +1 @@
|
|
|
1
|
-
|
|
2
|
-
import { join } from 'node:path';
|
|
3
|
-
import { recommendWorkspaceStrategy } from '../workspace-strategy/index.js';
|
|
4
|
-
import { planWorktreeSandbox } from './sandbox-worktree-planning.js';
|
|
5
|
-
const filesystemCategories = new Set(['read', 'edit', 'external-directory']);
|
|
6
|
-
export function planExecutionIsolation(input) {
|
|
7
|
-
const { operation, decision } = input;
|
|
8
|
-
const strategy = selectStrategy(operation, decision);
|
|
9
|
-
const sandbox = worktreeSandboxPlan(operation, strategy, input.gitBoundaryInspector);
|
|
10
|
-
const realpathHardeningRequired = requiresRealpathHardening(operation);
|
|
11
|
-
const requiredApprovals = approvalRequirements(operation, decision);
|
|
12
|
-
const requiredConditions = conditionRequirements(operation, decision, realpathHardeningRequired, sandbox);
|
|
13
|
-
const limitations = planLimitations(operation, decision, strategy, sandbox);
|
|
14
|
-
return {
|
|
15
|
-
strategy,
|
|
16
|
-
pathConstraints: pathConstraints(operation),
|
|
17
|
-
...(sandbox === undefined ? {} : { sandbox }),
|
|
18
|
-
realpathHardeningRequired,
|
|
19
|
-
requiredApprovals,
|
|
20
|
-
requiredConditions,
|
|
21
|
-
limitations,
|
|
22
|
-
executable: decision.decision === 'allow' && sandbox?.decision !== 'rejected',
|
|
23
|
-
executesProvider: false,
|
|
24
|
-
createsWorktree: false,
|
|
25
|
-
};
|
|
26
|
-
}
|
|
27
|
-
export function recommendWorkspaceStrategyForExecution(input) {
|
|
28
|
-
return recommendWorkspaceStrategy(workspaceStrategyInputForExecution(input));
|
|
29
|
-
}
|
|
30
|
-
export function workspaceStrategyInputForExecution(input) {
|
|
31
|
-
const categories = workspaceStrategyCategories(input.operation, input.decision);
|
|
32
|
-
const mutationSignal = hasWorkspaceMutationSignal(input.operation, categories);
|
|
33
|
-
return {
|
|
34
|
-
categories,
|
|
35
|
-
intentSignals: workspaceStrategyIntentSignals(input.operation, input.decision),
|
|
36
|
-
risk: workspaceStrategyRisk(input.decision),
|
|
37
|
-
readOnly: isReadOnlyWorkspaceOperation(input.operation, input.decision),
|
|
38
|
-
expectedWrites: mutationSignal,
|
|
39
|
-
mutatesRepository: mutationSignal,
|
|
40
|
-
destructive: input.operation.destructive === true,
|
|
41
|
-
external: input.operation.external === true || input.operation.category === 'external-directory',
|
|
42
|
-
privileged: input.operation.privileged === true,
|
|
43
|
-
ambiguous: input.operation.ambiguous === true,
|
|
44
|
-
changeSize: workspaceStrategyChangeSize(input.decision),
|
|
45
|
-
...(mutationSignal ? { workspace: { checkout: 'unknown' } } : {}),
|
|
46
|
-
};
|
|
47
|
-
}
|
|
48
|
-
function selectStrategy(operation, decision) {
|
|
49
|
-
if (operation.sandboxStrategy === 'worktree')
|
|
50
|
-
return 'worktree';
|
|
51
|
-
if (decision.decision === 'deny') {
|
|
52
|
-
return operation.category === 'external-directory' || operation.external === true ? 'process-sandbox' : 'workspace';
|
|
53
|
-
}
|
|
54
|
-
if (operation.category === 'shell' || operation.category === 'network' || operation.category === 'provider-tool' || operation.privileged === true) {
|
|
55
|
-
return 'process-sandbox';
|
|
56
|
-
}
|
|
57
|
-
if (operation.category === 'edit' || operation.category === 'git' || operation.destructive === true) {
|
|
58
|
-
return 'worktree';
|
|
59
|
-
}
|
|
60
|
-
return 'workspace';
|
|
61
|
-
}
|
|
62
|
-
function pathConstraints(operation) {
|
|
63
|
-
return {
|
|
64
|
-
...(operation.workspaceRoot === undefined ? {} : { workspaceRoot: operation.workspaceRoot }),
|
|
65
|
-
...(operation.targetPath === undefined ? {} : { targetPath: operation.targetPath }),
|
|
66
|
-
enforceWorkspaceBoundary: operation.category !== 'external-directory',
|
|
67
|
-
allowExternalPaths: false,
|
|
68
|
-
};
|
|
69
|
-
}
|
|
70
|
-
function requiresRealpathHardening(operation) {
|
|
71
|
-
return filesystemCategories.has(operation.category) || operation.workspaceRoot !== undefined || operation.targetPath !== undefined;
|
|
72
|
-
}
|
|
73
|
-
function approvalRequirements(operation, decision) {
|
|
74
|
-
const approvals = [];
|
|
75
|
-
if (decision.decision === 'ask')
|
|
76
|
-
approvals.push(`human-approval:${decision.reason}`);
|
|
77
|
-
if (operation.destructive === true)
|
|
78
|
-
approvals.push('destructive-operation-approval');
|
|
79
|
-
if (operation.external === true || operation.category === 'external-directory')
|
|
80
|
-
approvals.push('external-access-approval');
|
|
81
|
-
if (operation.privileged === true)
|
|
82
|
-
approvals.push('privileged-operation-approval');
|
|
83
|
-
if (operation.ambiguous === true)
|
|
84
|
-
approvals.push('clarify-ambiguous-operation');
|
|
85
|
-
return [...new Set(approvals)];
|
|
86
|
-
}
|
|
87
|
-
function conditionRequirements(operation, decision, realpathHardeningRequired, sandbox) {
|
|
88
|
-
const conditions = ['permission-decision-recorded'];
|
|
89
|
-
if (decision.decision === 'deny')
|
|
90
|
-
conditions.push('blocked-by-policy-before-execution');
|
|
91
|
-
if (sandbox?.decision === 'rejected')
|
|
92
|
-
conditions.push(`blocked-by-sandbox-planning:${sandbox.reason ?? 'unknown'}`);
|
|
93
|
-
if (decision.decision === 'ask')
|
|
94
|
-
conditions.push('approved-before-execution');
|
|
95
|
-
if (realpathHardeningRequired)
|
|
96
|
-
conditions.push('resolve-realpath-and-recheck-workspace-boundary-before-execution');
|
|
97
|
-
if (operation.category === 'edit' || operation.category === 'git' || operation.destructive === true)
|
|
98
|
-
conditions.push('isolated-worktree-or-equivalent-before-mutation');
|
|
99
|
-
if (operation.category === 'shell' || operation.category === 'network' || operation.category === 'provider-tool')
|
|
100
|
-
conditions.push('sandboxed-process-or-equivalent-before-provider-execution');
|
|
101
|
-
return conditions;
|
|
102
|
-
}
|
|
103
|
-
function planLimitations(operation, decision, strategy, sandbox) {
|
|
104
|
-
const limitations = ['planning-only: this preflight records an execution plan only; no command, provider tool, worktree, sandbox, directory, or filesystem mutation was performed'];
|
|
105
|
-
if (strategy === 'worktree')
|
|
106
|
-
limitations.push('worktree is only the planned isolation target; no worktree was created and mutations still require a separate executor or manual worktree');
|
|
107
|
-
if (strategy === 'process-sandbox')
|
|
108
|
-
limitations.push('process-sandbox is only the planned isolation target; no sandbox was launched and execution still requires a separate executor');
|
|
109
|
-
if (decision.decision === 'deny')
|
|
110
|
-
limitations.push(`permission policy denies execution: ${decision.reason}`);
|
|
111
|
-
if (sandbox?.decision === 'rejected')
|
|
112
|
-
limitations.push(`sandbox planning rejects execution: ${sandbox.audit.validationSummary}`);
|
|
113
|
-
if (operation.category === 'external-directory')
|
|
114
|
-
limitations.push('external directory execution remains denied by default even when a stronger future sandbox is selected');
|
|
115
|
-
return limitations;
|
|
116
|
-
}
|
|
117
|
-
function worktreeSandboxPlan(operation, strategy, gitBoundaryInspector) {
|
|
118
|
-
if (strategy !== 'worktree')
|
|
119
|
-
return undefined;
|
|
120
|
-
if (operation.workspaceRoot === undefined || operation.targetPath === undefined)
|
|
121
|
-
return undefined;
|
|
122
|
-
return planWorktreeSandbox({
|
|
123
|
-
workspaceRoot: operation.workspaceRoot,
|
|
124
|
-
targetPath: operation.targetPath,
|
|
125
|
-
gitBoundaryInspector: gitBoundaryInspector ?? defaultGitBoundaryInspector,
|
|
126
|
-
});
|
|
127
|
-
}
|
|
128
|
-
const defaultGitBoundaryInspector = ({ workspaceRoot }) => {
|
|
129
|
-
if (existsSync(join(workspaceRoot, '.git'))) {
|
|
130
|
-
return { status: 'compatible', reason: 'workspace git metadata is present' };
|
|
131
|
-
}
|
|
132
|
-
return { status: 'compatible', reason: 'workspace has no git metadata to conflict with a planned worktree boundary' };
|
|
133
|
-
};
|
|
134
|
-
function workspaceStrategyCategories(operation, decision) {
|
|
135
|
-
const categories = [operation.category];
|
|
136
|
-
if (decision.riskReasonCodes?.includes('git_write') === true && !categories.includes('git-write'))
|
|
137
|
-
categories.push('git-write');
|
|
138
|
-
return categories;
|
|
139
|
-
}
|
|
140
|
-
function workspaceStrategyIntentSignals(operation, decision) {
|
|
141
|
-
return [
|
|
142
|
-
`permission:${decision.reason}`,
|
|
143
|
-
...(decision.riskReasonCodes ?? []).map((code) => `risk:${code}`),
|
|
144
|
-
...(operation.workflow === undefined ? [] : [`workflow:${operation.workflow}`]),
|
|
145
|
-
...(operation.phase === undefined ? [] : [`phase:${operation.phase}`]),
|
|
146
|
-
];
|
|
147
|
-
}
|
|
148
|
-
function workspaceStrategyRisk(decision) {
|
|
149
|
-
if (decision.riskTier === 0)
|
|
150
|
-
return 'none';
|
|
151
|
-
if (decision.riskTier === 1)
|
|
152
|
-
return 'low';
|
|
153
|
-
if (decision.riskTier === 2)
|
|
154
|
-
return 'medium';
|
|
155
|
-
if (decision.riskTier === 3)
|
|
156
|
-
return 'high';
|
|
157
|
-
if (decision.riskTier === 4)
|
|
158
|
-
return 'critical';
|
|
159
|
-
return 'unknown';
|
|
160
|
-
}
|
|
161
|
-
function workspaceStrategyChangeSize(decision) {
|
|
162
|
-
if (decision.riskReasonCodes?.some((code) => code === 'architecture_change' || code === 'cross_surface_change' || code === 'governance_change') === true)
|
|
163
|
-
return 'large';
|
|
164
|
-
if (decision.riskTier === 2)
|
|
165
|
-
return 'medium';
|
|
166
|
-
if (decision.riskTier === 1)
|
|
167
|
-
return 'small';
|
|
168
|
-
return 'unknown';
|
|
169
|
-
}
|
|
170
|
-
function isReadOnlyWorkspaceOperation(operation, decision) {
|
|
171
|
-
return decision.riskTier === 0 || operation.category === 'read' || (operation.category === 'git' && decision.riskReasonCodes?.includes('git_write') !== true);
|
|
172
|
-
}
|
|
173
|
-
function hasWorkspaceMutationSignal(operation, categories) {
|
|
174
|
-
if (operation.destructive === true || operation.privileged === true || operation.external === true || operation.ambiguous === true)
|
|
175
|
-
return true;
|
|
176
|
-
return categories.some((category) => workspaceMutationCategories.has(category));
|
|
177
|
-
}
|
|
178
|
-
const workspaceMutationCategories = new Set(['edit', 'implementation-edit', 'spec-write', 'design-write', 'task-write', 'git-write']);
|
|
1
|
+
export * from '../application/runs/execution-planning.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export
|
|
1
|
+
export * from '../application/runs/operation-execution.js';
|
|
@@ -1,129 +1 @@
|
|
|
1
|
-
|
|
2
|
-
const operationRetryPolicyModes = [
|
|
3
|
-
'never',
|
|
4
|
-
'after-abandoned',
|
|
5
|
-
'after-failure',
|
|
6
|
-
'after-failure-or-abandoned',
|
|
7
|
-
];
|
|
8
|
-
const allowedRetryableStatuses = ['failed', 'abandoned'];
|
|
9
|
-
export function defaultOperationRetryPolicy() {
|
|
10
|
-
return defaultRetryPolicy;
|
|
11
|
-
}
|
|
12
|
-
export function parseOperationRetryPolicy(input) {
|
|
13
|
-
if (input === undefined) {
|
|
14
|
-
return { ok: true, policy: defaultRetryPolicy };
|
|
15
|
-
}
|
|
16
|
-
if (!isRecord(input) || Array.isArray(input)) {
|
|
17
|
-
return { ok: false, errors: ['Retry policy must be an object'] };
|
|
18
|
-
}
|
|
19
|
-
const allowedKeys = new Set(['mode', 'retryableStatuses']);
|
|
20
|
-
const unknownKeys = Object.keys(input).filter((key) => !allowedKeys.has(key));
|
|
21
|
-
const errors = unknownKeys.map((key) => `Unknown retry policy field: ${key}`);
|
|
22
|
-
const mode = input.mode;
|
|
23
|
-
if (!isOperationRetryPolicyMode(mode)) {
|
|
24
|
-
errors.push('Retry policy mode must be one of: never, after-abandoned, after-failure, after-failure-or-abandoned');
|
|
25
|
-
}
|
|
26
|
-
if ('retryableStatuses' in input) {
|
|
27
|
-
const retryableStatuses = input.retryableStatuses;
|
|
28
|
-
if (!Array.isArray(retryableStatuses)) {
|
|
29
|
-
errors.push('Retry policy retryableStatuses must be an array');
|
|
30
|
-
}
|
|
31
|
-
else {
|
|
32
|
-
const invalidStatuses = retryableStatuses.filter((status) => !isAllowedRetryableStatus(status));
|
|
33
|
-
if (invalidStatuses.length > 0) {
|
|
34
|
-
errors.push(`Retry policy retryableStatuses contains invalid retryable status: ${invalidStatuses.map(String).join(', ')}`);
|
|
35
|
-
}
|
|
36
|
-
if (new Set(retryableStatuses).size !== retryableStatuses.length) {
|
|
37
|
-
errors.push('Retry policy retryableStatuses must not contain duplicates');
|
|
38
|
-
}
|
|
39
|
-
if (isOperationRetryPolicyMode(mode) && invalidStatuses.length === 0) {
|
|
40
|
-
const expectedStatuses = retryableStatusesFor({ mode });
|
|
41
|
-
if (!sameStatuses(retryableStatuses, expectedStatuses)) {
|
|
42
|
-
errors.push(`Retry policy retryableStatuses must match mode ${mode}: ${expectedStatuses.length === 0 ? '[]' : expectedStatuses.join(', ')}`);
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
if (errors.length > 0 || !isOperationRetryPolicyMode(mode)) {
|
|
48
|
-
return { ok: false, errors };
|
|
49
|
-
}
|
|
50
|
-
return { ok: true, policy: { mode } };
|
|
51
|
-
}
|
|
52
|
-
export function evaluateOperationRetry(input) {
|
|
53
|
-
const policy = input.policy ?? defaultRetryPolicy;
|
|
54
|
-
const retryableStatuses = retryableStatusesFor(policy);
|
|
55
|
-
const attempts = [...input.attempts].sort(compareAttempts);
|
|
56
|
-
const activeAttempt = attempts.find((attempt) => attempt.status === 'reserved');
|
|
57
|
-
if (activeAttempt !== undefined) {
|
|
58
|
-
const latestAttempt = attempts.at(-1);
|
|
59
|
-
return {
|
|
60
|
-
allowed: false,
|
|
61
|
-
policy,
|
|
62
|
-
reasonCode: 'active_attempt_reserved',
|
|
63
|
-
reason: `Retry blocked because attempt ${activeAttempt.id} is still reserved`,
|
|
64
|
-
evaluatedAttemptCount: attempts.length,
|
|
65
|
-
retryableStatuses,
|
|
66
|
-
activeAttempt,
|
|
67
|
-
...(latestAttempt === undefined ? {} : { latestAttempt }),
|
|
68
|
-
};
|
|
69
|
-
}
|
|
70
|
-
const latestAttempt = attempts.at(-1);
|
|
71
|
-
if (latestAttempt === undefined) {
|
|
72
|
-
return {
|
|
73
|
-
allowed: true,
|
|
74
|
-
policy,
|
|
75
|
-
reasonCode: 'initial_attempt_allowed',
|
|
76
|
-
reason: 'No previous operation attempt exists for this approval',
|
|
77
|
-
evaluatedAttemptCount: 0,
|
|
78
|
-
retryableStatuses,
|
|
79
|
-
};
|
|
80
|
-
}
|
|
81
|
-
if (latestAttempt.status === 'succeeded') {
|
|
82
|
-
return block(policy, retryableStatuses, attempts.length, latestAttempt, 'already_succeeded', `Retry blocked because latest attempt ${latestAttempt.id} already succeeded`);
|
|
83
|
-
}
|
|
84
|
-
if (policy.mode === 'never') {
|
|
85
|
-
return block(policy, retryableStatuses, attempts.length, latestAttempt, 'retry_disabled', `Retry blocked by policy never after ${latestAttempt.status}`);
|
|
86
|
-
}
|
|
87
|
-
if (retryableStatuses.includes(latestAttempt.status)) {
|
|
88
|
-
return {
|
|
89
|
-
allowed: true,
|
|
90
|
-
policy,
|
|
91
|
-
reasonCode: 'status_allowed_by_policy',
|
|
92
|
-
reason: `Retry allowed by policy ${policy.mode} after ${latestAttempt.status}`,
|
|
93
|
-
evaluatedAttemptCount: attempts.length,
|
|
94
|
-
retryableStatuses,
|
|
95
|
-
latestAttempt,
|
|
96
|
-
};
|
|
97
|
-
}
|
|
98
|
-
return block(policy, retryableStatuses, attempts.length, latestAttempt, 'status_not_allowed_by_policy', `Retry blocked by policy ${policy.mode} after ${latestAttempt.status}`);
|
|
99
|
-
}
|
|
100
|
-
function block(policy, retryableStatuses, evaluatedAttemptCount, latestAttempt, reasonCode, reason) {
|
|
101
|
-
return { allowed: false, policy, reasonCode, reason, evaluatedAttemptCount, retryableStatuses, latestAttempt };
|
|
102
|
-
}
|
|
103
|
-
function retryableStatusesFor(policy) {
|
|
104
|
-
switch (policy.mode) {
|
|
105
|
-
case 'after-abandoned':
|
|
106
|
-
return ['abandoned'];
|
|
107
|
-
case 'after-failure':
|
|
108
|
-
return ['failed'];
|
|
109
|
-
case 'after-failure-or-abandoned':
|
|
110
|
-
return ['failed', 'abandoned'];
|
|
111
|
-
case 'never':
|
|
112
|
-
return [];
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
function isRecord(value) {
|
|
116
|
-
return typeof value === 'object' && value !== null;
|
|
117
|
-
}
|
|
118
|
-
function isOperationRetryPolicyMode(value) {
|
|
119
|
-
return typeof value === 'string' && operationRetryPolicyModes.includes(value);
|
|
120
|
-
}
|
|
121
|
-
function isAllowedRetryableStatus(value) {
|
|
122
|
-
return typeof value === 'string' && allowedRetryableStatuses.includes(value);
|
|
123
|
-
}
|
|
124
|
-
function sameStatuses(actual, expected) {
|
|
125
|
-
return actual.length === expected.length && actual.every((status) => expected.includes(status));
|
|
126
|
-
}
|
|
127
|
-
function compareAttempts(a, b) {
|
|
128
|
-
return a.attemptSequence - b.attemptSequence || a.reservedAt.localeCompare(b.reservedAt) || a.id.localeCompare(b.id);
|
|
129
|
-
}
|
|
1
|
+
export * from '../application/runs/operation-retry.js';
|