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
|
@@ -1,31 +1 @@
|
|
|
1
|
-
|
|
2
|
-
import { runSnapshotPackageKind } from './schema.js';
|
|
3
|
-
export class RunSnapshotExportService {
|
|
4
|
-
runs;
|
|
5
|
-
constructor(runs) {
|
|
6
|
-
this.runs = runs;
|
|
7
|
-
}
|
|
8
|
-
exportSnapshot(input) {
|
|
9
|
-
const details = this.runs.getRun(input.runId);
|
|
10
|
-
if (!details.ok)
|
|
11
|
-
return details;
|
|
12
|
-
if (details.value.project !== input.project) {
|
|
13
|
-
return validationFailure(`Run project mismatch: expected ${input.project}, got ${details.value.project}`);
|
|
14
|
-
}
|
|
15
|
-
const redactedRun = redactJsonValue(details.value);
|
|
16
|
-
return {
|
|
17
|
-
ok: true,
|
|
18
|
-
value: {
|
|
19
|
-
kind: runSnapshotPackageKind,
|
|
20
|
-
version: 1,
|
|
21
|
-
exportedAt: new Date().toISOString(),
|
|
22
|
-
project: input.project,
|
|
23
|
-
runId: input.runId,
|
|
24
|
-
run: redactedRun,
|
|
25
|
-
},
|
|
26
|
-
};
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
function validationFailure(message) {
|
|
30
|
-
return { ok: false, error: { code: 'validation_failed', message } };
|
|
31
|
-
}
|
|
1
|
+
export * from '../application/runs/run-snapshot-export-service.js';
|
|
@@ -1,240 +1 @@
|
|
|
1
|
-
|
|
2
|
-
import { isAbsolute, sep } from 'node:path';
|
|
3
|
-
import { canonicalizeExistingPath, isPathInside, isProviderConfigPath } from '../permissions/path-boundaries.js';
|
|
4
|
-
const defaultTimeoutMs = 10_000;
|
|
5
|
-
const defaultOutputLimitBytes = 64 * 1024;
|
|
6
|
-
const allowedEnvKey = /^[A-Z_][A-Z0-9_]*$/u;
|
|
7
|
-
const shellMetaCharacters = /[\s;&|<>$`\\]/u;
|
|
8
|
-
export function buildSandboxExecutionPlan(request) {
|
|
9
|
-
const workspaceRoot = realpathOrUndefined(request.workspaceRoot);
|
|
10
|
-
if (workspaceRoot === undefined)
|
|
11
|
-
return rejected('workspace-root-not-found', `Workspace root does not exist: ${request.workspaceRoot}`);
|
|
12
|
-
const cwd = realpathOrUndefined(request.cwd ?? request.workspaceRoot);
|
|
13
|
-
if (cwd === undefined)
|
|
14
|
-
return rejected('cwd-not-found', `Process cwd does not exist: ${request.cwd ?? request.workspaceRoot}`, workspaceRoot);
|
|
15
|
-
const externalCwd = externalCwdAuthorization({ cwd, workspaceRoot, request });
|
|
16
|
-
if (!externalCwd.ok)
|
|
17
|
-
return rejected(externalCwd.code, externalCwd.message, workspaceRoot, cwd, externalCwd.approvedExternalRoot, request.externalAuthorization);
|
|
18
|
-
if (isProviderConfigPathForAnyRoot(cwd, workspaceRoot, externalCwd.approvedExternalRoot))
|
|
19
|
-
return rejected('provider-config-cwd-rejected', `Process cwd targets provider/OpenCode config: ${request.cwd ?? request.workspaceRoot}`, workspaceRoot, cwd, externalCwd.approvedExternalRoot, request.externalAuthorization);
|
|
20
|
-
if (request.command.length === 0)
|
|
21
|
-
return rejected('empty-command', 'Process command is required.', workspaceRoot, cwd);
|
|
22
|
-
if (isAbsolute(request.command) || request.command.includes(sep) || shellMetaCharacters.test(request.command)) {
|
|
23
|
-
return rejected('shell-or-path-command-rejected', 'Command must be a single allowlisted executable name; shell strings and paths are rejected.', workspaceRoot, cwd);
|
|
24
|
-
}
|
|
25
|
-
if (!request.allowedCommands.includes(request.command)) {
|
|
26
|
-
return rejected('command-not-allowlisted', `Command is not allowlisted: ${request.command}`, workspaceRoot, cwd);
|
|
27
|
-
}
|
|
28
|
-
const argv = request.args ?? [];
|
|
29
|
-
if (!argv.every((arg) => typeof arg === 'string'))
|
|
30
|
-
return rejected('invalid-argv', 'Arguments must be an argv array of strings.', workspaceRoot, cwd);
|
|
31
|
-
const targetPaths = request.targetPaths ?? [];
|
|
32
|
-
if (!targetPaths.every((targetPath) => typeof targetPath === 'string'))
|
|
33
|
-
return rejected('invalid-target-paths', 'Target paths must be an array of strings.', workspaceRoot, cwd);
|
|
34
|
-
const providerConfigTargetPath = targetPaths.find((targetPath) => isProviderConfigPathForAnyRoot(targetPath, workspaceRoot, cwd, externalCwd.approvedExternalRoot));
|
|
35
|
-
if (providerConfigTargetPath !== undefined)
|
|
36
|
-
return rejected('provider-config-target-path-rejected', `Process plan target path targets provider/OpenCode config: ${providerConfigTargetPath}`, workspaceRoot, cwd, externalCwd.approvedExternalRoot, request.externalAuthorization);
|
|
37
|
-
const env = request.env ?? {};
|
|
38
|
-
const envKeys = Object.keys(env).sort();
|
|
39
|
-
const invalidEnvKey = envKeys.find((key) => !allowedEnvKey.test(key));
|
|
40
|
-
if (invalidEnvKey !== undefined)
|
|
41
|
-
return rejected('invalid-env-key', `Environment key is not in the limited allow shape: ${invalidEnvKey}`, workspaceRoot, cwd);
|
|
42
|
-
const timeoutMs = request.timeoutMs ?? defaultTimeoutMs;
|
|
43
|
-
if (!Number.isInteger(timeoutMs) || timeoutMs < 1 || timeoutMs > 60_000)
|
|
44
|
-
return rejected('invalid-timeout', 'Timeout must be an integer between 1 and 60000 ms.', workspaceRoot, cwd);
|
|
45
|
-
const outputLimitBytes = request.outputLimitBytes ?? defaultOutputLimitBytes;
|
|
46
|
-
if (!Number.isInteger(outputLimitBytes) || outputLimitBytes < 1 || outputLimitBytes > 1024 * 1024)
|
|
47
|
-
return rejected('invalid-output-limit', 'Output limit must be an integer between 1 byte and 1 MiB.', workspaceRoot, cwd);
|
|
48
|
-
const evidence = acceptedEvidence(workspaceRoot, cwd, externalCwd.approvedExternalRoot, request.externalAuthorization, [
|
|
49
|
-
'workspace-root-realpath-resolved',
|
|
50
|
-
externalCwd.approvedExternalRoot === undefined ? 'cwd-realpath-inside-workspace' : 'cwd-realpath-inside-approved-external-root',
|
|
51
|
-
'command-is-executable-name-not-shell-string',
|
|
52
|
-
'command-allowlisted',
|
|
53
|
-
'argv-array-only',
|
|
54
|
-
'limited-env-keys-validated',
|
|
55
|
-
'timeout-configured',
|
|
56
|
-
'output-cap-configured',
|
|
57
|
-
'provider-config-paths-not-targeted-by-process-plan',
|
|
58
|
-
]);
|
|
59
|
-
return {
|
|
60
|
-
ok: true,
|
|
61
|
-
value: {
|
|
62
|
-
strategy: 'bounded-process',
|
|
63
|
-
executable: true,
|
|
64
|
-
request: { workspaceRoot, cwd, command: request.command, argv, envKeys, timeoutMs, outputLimitBytes },
|
|
65
|
-
evidence,
|
|
66
|
-
},
|
|
67
|
-
};
|
|
68
|
-
}
|
|
69
|
-
export async function executeSandboxedProcess(request) {
|
|
70
|
-
const plan = buildSandboxExecutionPlan(request);
|
|
71
|
-
if (!plan.ok)
|
|
72
|
-
return plan;
|
|
73
|
-
const { command, argv, cwd, timeoutMs, outputLimitBytes } = plan.value.request;
|
|
74
|
-
const env = limitedEnv(request.env ?? {});
|
|
75
|
-
return await new Promise((resolvePromise) => {
|
|
76
|
-
const child = spawn(command, argv, { cwd, env, shell: false, stdio: ['ignore', 'pipe', 'pipe'] });
|
|
77
|
-
let stdout = '';
|
|
78
|
-
let stderr = '';
|
|
79
|
-
let outputBytes = 0;
|
|
80
|
-
let outputTruncated = false;
|
|
81
|
-
let timedOut = false;
|
|
82
|
-
const timer = setTimeout(() => {
|
|
83
|
-
timedOut = true;
|
|
84
|
-
child.kill('SIGTERM');
|
|
85
|
-
}, timeoutMs);
|
|
86
|
-
const append = (chunk, target) => {
|
|
87
|
-
if (outputBytes >= outputLimitBytes) {
|
|
88
|
-
outputTruncated = true;
|
|
89
|
-
return;
|
|
90
|
-
}
|
|
91
|
-
const remaining = outputLimitBytes - outputBytes;
|
|
92
|
-
const slice = chunk.subarray(0, Math.max(0, remaining));
|
|
93
|
-
outputBytes += slice.byteLength;
|
|
94
|
-
if (slice.byteLength < chunk.byteLength)
|
|
95
|
-
outputTruncated = true;
|
|
96
|
-
if (target === 'stdout')
|
|
97
|
-
stdout += slice.toString('utf8');
|
|
98
|
-
else
|
|
99
|
-
stderr += slice.toString('utf8');
|
|
100
|
-
};
|
|
101
|
-
child.stdout?.on('data', (chunk) => append(chunk, 'stdout'));
|
|
102
|
-
child.stderr?.on('data', (chunk) => append(chunk, 'stderr'));
|
|
103
|
-
child.on('error', (error) => {
|
|
104
|
-
clearTimeout(timer);
|
|
105
|
-
resolvePromise({ ok: false, error: { code: 'process-launch-failed', message: error.message, evidence: plan.value.evidence } });
|
|
106
|
-
});
|
|
107
|
-
child.on('close', (exitCode, signal) => {
|
|
108
|
-
clearTimeout(timer);
|
|
109
|
-
resolvePromise({ ok: true, value: { exitCode, signal, stdout, stderr, timedOut, outputTruncated, evidence: plan.value.evidence } });
|
|
110
|
-
});
|
|
111
|
-
});
|
|
112
|
-
}
|
|
113
|
-
export function executeSandboxedProcessSync(request) {
|
|
114
|
-
const plan = buildSandboxExecutionPlan(request);
|
|
115
|
-
if (!plan.ok)
|
|
116
|
-
return plan;
|
|
117
|
-
const { command, argv, cwd, timeoutMs, outputLimitBytes } = plan.value.request;
|
|
118
|
-
const executed = spawnSync(command, argv, {
|
|
119
|
-
cwd,
|
|
120
|
-
env: limitedEnv(request.env ?? {}),
|
|
121
|
-
shell: false,
|
|
122
|
-
stdio: ['ignore', 'pipe', 'pipe'],
|
|
123
|
-
timeout: timeoutMs,
|
|
124
|
-
encoding: 'buffer',
|
|
125
|
-
maxBuffer: outputLimitBytes,
|
|
126
|
-
});
|
|
127
|
-
if (executed.error?.message.includes('maxBuffer')) {
|
|
128
|
-
// Keep the bounded-process contract explicit: output beyond maxBuffer is truncated.
|
|
129
|
-
}
|
|
130
|
-
else if (executed.error !== undefined && !isTimeoutError(executed.error)) {
|
|
131
|
-
return { ok: false, error: { code: 'process-launch-failed', message: executed.error.message, evidence: plan.value.evidence } };
|
|
132
|
-
}
|
|
133
|
-
const stdout = bufferToLimitedString(executed.stdout, outputLimitBytes);
|
|
134
|
-
const remaining = Math.max(0, outputLimitBytes - Buffer.byteLength(stdout));
|
|
135
|
-
const stderr = bufferToLimitedString(executed.stderr, remaining);
|
|
136
|
-
const outputTruncated = Buffer.byteLength(stdout) + Buffer.byteLength(stderr) >= outputLimitBytes || (executed.error?.message.includes('maxBuffer') ?? false);
|
|
137
|
-
return {
|
|
138
|
-
ok: true,
|
|
139
|
-
value: {
|
|
140
|
-
exitCode: executed.status,
|
|
141
|
-
signal: executed.signal,
|
|
142
|
-
stdout,
|
|
143
|
-
stderr,
|
|
144
|
-
timedOut: isTimeoutError(executed.error),
|
|
145
|
-
outputTruncated,
|
|
146
|
-
evidence: plan.value.evidence,
|
|
147
|
-
},
|
|
148
|
-
};
|
|
149
|
-
}
|
|
150
|
-
function isTimeoutError(error) {
|
|
151
|
-
return error?.code === 'ETIMEDOUT';
|
|
152
|
-
}
|
|
153
|
-
function bufferToLimitedString(buffer, limit) {
|
|
154
|
-
if (buffer === null || buffer === undefined || limit <= 0)
|
|
155
|
-
return '';
|
|
156
|
-
const source = typeof buffer === 'string' ? Buffer.from(buffer) : buffer;
|
|
157
|
-
return source.subarray(0, limit).toString('utf8');
|
|
158
|
-
}
|
|
159
|
-
function acceptedEvidence(workspaceRoot, cwd, approvedExternalRoot, externalAuthorization, checks) {
|
|
160
|
-
return {
|
|
161
|
-
strategy: 'bounded-process',
|
|
162
|
-
enforceable: true,
|
|
163
|
-
createsSandbox: false,
|
|
164
|
-
createsWorktree: false,
|
|
165
|
-
filesystemIsolation: false,
|
|
166
|
-
networkIsolation: false,
|
|
167
|
-
shellDisabled: true,
|
|
168
|
-
argvArrayOnly: true,
|
|
169
|
-
providerConfigWritesBlocked: true,
|
|
170
|
-
workspaceRoot,
|
|
171
|
-
cwd,
|
|
172
|
-
externalCwdAuthorized: approvedExternalRoot !== undefined,
|
|
173
|
-
...(approvedExternalRoot === undefined ? {} : { approvedExternalRoot }),
|
|
174
|
-
...(externalAuthorization === undefined || approvedExternalRoot === undefined ? {} : { externalAuthorization }),
|
|
175
|
-
capabilities: {
|
|
176
|
-
sandboxEnforceable: false,
|
|
177
|
-
processExecutionEnforceable: true,
|
|
178
|
-
workspaceBoundaryEnforced: true,
|
|
179
|
-
providerConfigWritesBlocked: true,
|
|
180
|
-
shellDisabled: true,
|
|
181
|
-
argvArrayOnly: true,
|
|
182
|
-
limitedEnvironment: true,
|
|
183
|
-
timeoutEnforced: true,
|
|
184
|
-
outputCapEnforced: true,
|
|
185
|
-
createsSandbox: false,
|
|
186
|
-
createsWorktree: false,
|
|
187
|
-
filesystemIsolation: false,
|
|
188
|
-
networkIsolation: false,
|
|
189
|
-
},
|
|
190
|
-
limitations: [
|
|
191
|
-
'bounded-process does not create an OS-level sandbox',
|
|
192
|
-
'bounded-process does not create or manage a git worktree',
|
|
193
|
-
'bounded-process enforces local process launch constraints only; it is not an OS-level filesystem sandbox',
|
|
194
|
-
'bounded-process does not prove network isolation',
|
|
195
|
-
],
|
|
196
|
-
validation: { accepted: true, checks },
|
|
197
|
-
};
|
|
198
|
-
}
|
|
199
|
-
function rejected(code, message, workspaceRoot, cwd, approvedExternalRoot, externalAuthorization) {
|
|
200
|
-
const evidence = workspaceRoot === undefined || cwd === undefined
|
|
201
|
-
? undefined
|
|
202
|
-
: { ...acceptedEvidence(workspaceRoot, cwd, approvedExternalRoot, externalAuthorization, []), enforceable: false, validation: { accepted: false, checks: [code] } };
|
|
203
|
-
return { ok: false, error: { code, message, ...(evidence === undefined ? {} : { evidence }) } };
|
|
204
|
-
}
|
|
205
|
-
function externalCwdAuthorization(input) {
|
|
206
|
-
if (isInside(input.cwd, input.workspaceRoot))
|
|
207
|
-
return { ok: true };
|
|
208
|
-
if (input.request.externalAuthorization === undefined) {
|
|
209
|
-
return { ok: false, code: 'cwd-escapes-workspace', message: `Process cwd escapes workspace boundary: ${input.request.cwd ?? input.request.workspaceRoot}` };
|
|
210
|
-
}
|
|
211
|
-
const roots = input.request.approvedExternalRoots ?? [];
|
|
212
|
-
for (const root of roots) {
|
|
213
|
-
const canonicalRoot = realpathOrUndefined(root);
|
|
214
|
-
if (canonicalRoot !== undefined && isInside(input.cwd, canonicalRoot))
|
|
215
|
-
return { ok: true, approvedExternalRoot: canonicalRoot };
|
|
216
|
-
}
|
|
217
|
-
return {
|
|
218
|
-
ok: false,
|
|
219
|
-
code: 'cwd-not-approved-external-root',
|
|
220
|
-
message: `Process cwd is outside the workspace and not inside an approved external root: ${input.request.cwd ?? input.request.workspaceRoot}`,
|
|
221
|
-
};
|
|
222
|
-
}
|
|
223
|
-
function isProviderConfigPathForAnyRoot(path, workspaceRoot, ...additionalRoots) {
|
|
224
|
-
if (isProviderConfigPath(path, workspaceRoot))
|
|
225
|
-
return true;
|
|
226
|
-
return additionalRoots.some((root) => root !== undefined && isProviderConfigPath(path, root));
|
|
227
|
-
}
|
|
228
|
-
function realpathOrUndefined(path) {
|
|
229
|
-
return canonicalizeExistingPath(path);
|
|
230
|
-
}
|
|
231
|
-
function isInside(path, workspaceRoot) {
|
|
232
|
-
return isPathInside(path, workspaceRoot);
|
|
233
|
-
}
|
|
234
|
-
function limitedEnv(input) {
|
|
235
|
-
const env = { PATH: process.env.PATH ?? '' };
|
|
236
|
-
for (const [key, value] of Object.entries(input))
|
|
237
|
-
if (value !== undefined)
|
|
238
|
-
env[key] = value;
|
|
239
|
-
return env;
|
|
240
|
-
}
|
|
1
|
+
export * from '../application/runs/sandbox-process-execution.js';
|
|
@@ -1,59 +1 @@
|
|
|
1
|
-
|
|
2
|
-
import { resolveWorkspaceContainedPath } from '../permissions/policy-evaluator.js';
|
|
3
|
-
const uncheckedGitBoundary = {
|
|
4
|
-
status: 'uncertain',
|
|
5
|
-
reason: 'git boundary validation was not reached',
|
|
6
|
-
};
|
|
7
|
-
export function planWorktreeSandbox(input) {
|
|
8
|
-
const contained = resolveWorkspaceContainedPath(input.workspaceRoot, input.targetPath);
|
|
9
|
-
if (!contained.ok)
|
|
10
|
-
return rejected(input.workspaceRoot, uncheckedGitBoundary, 'sandbox_boundary', contained.reason);
|
|
11
|
-
const configPath = providerConfigPath(contained.targetPath, contained.workspaceRoot);
|
|
12
|
-
if (configPath !== undefined) {
|
|
13
|
-
return rejected(contained.workspaceRoot, uncheckedGitBoundary, 'provider_config_write', `Provider config target is prohibited: ${configPath}`);
|
|
14
|
-
}
|
|
15
|
-
const gitBoundary = input.gitBoundaryInspector({ workspaceRoot: contained.workspaceRoot, targetPath: contained.targetPath });
|
|
16
|
-
if (gitBoundary.status !== 'compatible')
|
|
17
|
-
return rejected(contained.workspaceRoot, gitBoundary, 'git_boundary', gitBoundary.reason);
|
|
18
|
-
return {
|
|
19
|
-
strategy: 'worktree',
|
|
20
|
-
decision: 'accepted',
|
|
21
|
-
workspaceRoot: contained.workspaceRoot,
|
|
22
|
-
targetPath: contained.targetPath,
|
|
23
|
-
gitBoundary,
|
|
24
|
-
providerConfigMutation: false,
|
|
25
|
-
createsWorktree: false,
|
|
26
|
-
executesProvider: false,
|
|
27
|
-
audit: {
|
|
28
|
-
workspaceRoot: contained.workspaceRoot,
|
|
29
|
-
strategy: 'worktree',
|
|
30
|
-
decision: 'accepted',
|
|
31
|
-
validationSummary: gitBoundary.reason,
|
|
32
|
-
},
|
|
33
|
-
};
|
|
34
|
-
}
|
|
35
|
-
function rejected(workspaceRoot, gitBoundary, reason, validationSummary) {
|
|
36
|
-
return {
|
|
37
|
-
strategy: 'worktree',
|
|
38
|
-
decision: 'rejected',
|
|
39
|
-
workspaceRoot,
|
|
40
|
-
gitBoundary,
|
|
41
|
-
providerConfigMutation: false,
|
|
42
|
-
createsWorktree: false,
|
|
43
|
-
executesProvider: false,
|
|
44
|
-
reason,
|
|
45
|
-
audit: {
|
|
46
|
-
workspaceRoot,
|
|
47
|
-
strategy: 'worktree',
|
|
48
|
-
decision: 'rejected',
|
|
49
|
-
validationSummary,
|
|
50
|
-
},
|
|
51
|
-
};
|
|
52
|
-
}
|
|
53
|
-
function providerConfigPath(targetPath, workspaceRoot) {
|
|
54
|
-
const relative = targetPath.slice(workspaceRoot.length).split(sep).filter(Boolean);
|
|
55
|
-
const firstSegment = relative[0];
|
|
56
|
-
if (firstSegment === '.opencode' || firstSegment === '.claude')
|
|
57
|
-
return firstSegment;
|
|
58
|
-
return undefined;
|
|
59
|
-
}
|
|
1
|
+
export * from '../application/runs/sandbox-worktree-planning.js';
|
package/dist/runs/schema.js
CHANGED
|
@@ -1,5 +1 @@
|
|
|
1
|
-
export
|
|
2
|
-
export function isTerminalRunStatus(status) {
|
|
3
|
-
return TERMINAL_RUN_STATUSES.includes(status);
|
|
4
|
-
}
|
|
5
|
-
export const runSnapshotPackageKind = 'vgxness.run-snapshot-package';
|
|
1
|
+
export * from '../domain/runs/schema.js';
|
|
@@ -1,216 +1 @@
|
|
|
1
|
-
|
|
2
|
-
import { validateTaskScopedCommandGrantCreationInput } from '../permissions/task-scoped-command-grant-validation.js';
|
|
3
|
-
import { commandAllowlistIds } from '../workflows/command-allowlist-adapter.js';
|
|
4
|
-
import { TaskScopedCommandGrantRepository } from './repositories/task-scoped-command-grants.js';
|
|
5
|
-
import { RunRepository } from './repositories/runs.js';
|
|
6
|
-
import { isTerminalRunStatus } from './schema.js';
|
|
7
|
-
const grantableCategories = new Set(['shell', 'test-run', 'git']);
|
|
8
|
-
export class TaskScopedCommandGrantService {
|
|
9
|
-
runs;
|
|
10
|
-
grants;
|
|
11
|
-
constructor(database) {
|
|
12
|
-
this.runs = new RunRepository(database);
|
|
13
|
-
this.grants = new TaskScopedCommandGrantRepository(database);
|
|
14
|
-
}
|
|
15
|
-
create(input) {
|
|
16
|
-
const run = this.runs.getById(input.runId);
|
|
17
|
-
if (!run.ok)
|
|
18
|
-
return run;
|
|
19
|
-
if (isTerminalRunStatus(run.value.status))
|
|
20
|
-
return validationFailure(`Cannot create task-scoped command grants for terminal run status: ${run.value.status}`);
|
|
21
|
-
if (input.agentId !== run.value.selectedAgentId)
|
|
22
|
-
return validationFailure('Grant agentId must match the run selected agent');
|
|
23
|
-
const validated = validateTaskScopedCommandGrantCreationInput(input, { knownAllowlistIds: commandAllowlistIds(), now: input.createdAt === undefined ? new Date() : new Date(input.createdAt) });
|
|
24
|
-
if (!validated.ok)
|
|
25
|
-
return validated;
|
|
26
|
-
const createInput = validated.value;
|
|
27
|
-
return this.grants.create(createInput);
|
|
28
|
-
}
|
|
29
|
-
list(filters = {}) {
|
|
30
|
-
return this.grants.list(filters);
|
|
31
|
-
}
|
|
32
|
-
get(id) {
|
|
33
|
-
return this.grants.get(id);
|
|
34
|
-
}
|
|
35
|
-
revoke(input) {
|
|
36
|
-
return this.grants.revoke(input);
|
|
37
|
-
}
|
|
38
|
-
previewMatch(input) {
|
|
39
|
-
return this.evaluateMatch(input, false);
|
|
40
|
-
}
|
|
41
|
-
tryAuthorizeAsk(input) {
|
|
42
|
-
if (input.baseDecision.decision !== 'ask')
|
|
43
|
-
return { ok: true, value: { authorized: false, evaluation: emptyEvaluation(false, ['base-decision-not-ask']) } };
|
|
44
|
-
const preview = this.evaluateMatch({
|
|
45
|
-
runId: input.run.id,
|
|
46
|
-
agentId: input.request.agentId ?? input.request.agent?.id ?? input.run.selectedAgentId,
|
|
47
|
-
category: input.request.category,
|
|
48
|
-
operation: input.request.operation,
|
|
49
|
-
...(input.request.taskFingerprint === undefined ? {} : { taskFingerprint: input.request.taskFingerprint }),
|
|
50
|
-
...(input.request.commandId === undefined ? {} : { commandId: input.request.commandId }),
|
|
51
|
-
...(input.request.workspaceRoot === undefined ? {} : { workspaceRoot: input.request.workspaceRoot }),
|
|
52
|
-
...(input.request.cwd === undefined ? {} : { cwd: input.request.cwd }),
|
|
53
|
-
...taskGrantTargetPaths(input.request),
|
|
54
|
-
...(input.request.destructive === undefined ? {} : { destructive: input.request.destructive }),
|
|
55
|
-
...(input.request.privileged === undefined ? {} : { privileged: input.request.privileged }),
|
|
56
|
-
...(input.request.ambiguous === undefined ? {} : { ambiguous: input.request.ambiguous }),
|
|
57
|
-
...(input.now === undefined ? {} : { now: input.now }),
|
|
58
|
-
}, true);
|
|
59
|
-
if (!preview.ok)
|
|
60
|
-
return preview;
|
|
61
|
-
if (preview.value.selectedGrantId === undefined)
|
|
62
|
-
return { ok: true, value: { authorized: false, evaluation: preview.value } };
|
|
63
|
-
const before = this.grants.get(preview.value.selectedGrantId);
|
|
64
|
-
if (!before.ok)
|
|
65
|
-
return before;
|
|
66
|
-
const consumeInput = {
|
|
67
|
-
grantId: preview.value.selectedGrantId,
|
|
68
|
-
now: (input.now ?? new Date()).toISOString(),
|
|
69
|
-
...(preview.value.commandId === undefined ? {} : { commandId: preview.value.commandId }),
|
|
70
|
-
...(preview.value.canonicalCwd === undefined ? {} : { canonicalCwd: preview.value.canonicalCwd }),
|
|
71
|
-
...(preview.value.matchedExternalRoot === undefined ? {} : { matchedExternalRoot: preview.value.matchedExternalRoot }),
|
|
72
|
-
};
|
|
73
|
-
const consumed = this.grants.consumeUse(consumeInput);
|
|
74
|
-
if (!consumed.ok) {
|
|
75
|
-
return {
|
|
76
|
-
ok: true,
|
|
77
|
-
value: {
|
|
78
|
-
authorized: false,
|
|
79
|
-
evaluation: { ...preview.value, matched: false, missReasons: [...new Set([...preview.value.missReasons, 'concurrent-consume-lost'])].sort() },
|
|
80
|
-
},
|
|
81
|
-
};
|
|
82
|
-
}
|
|
83
|
-
const evaluation = {
|
|
84
|
-
...preview.value,
|
|
85
|
-
matched: true,
|
|
86
|
-
useCountBefore: before.value.usedCount,
|
|
87
|
-
useCountAfter: consumed.value.usedCount,
|
|
88
|
-
};
|
|
89
|
-
const event = this.runs.appendEvent({
|
|
90
|
-
runId: input.run.id,
|
|
91
|
-
kind: 'evidence',
|
|
92
|
-
title: 'Task-scoped command grant authorized preflight ask',
|
|
93
|
-
payload: grantEvaluationPayload(evaluation),
|
|
94
|
-
relatedType: 'task-scoped-command-grant',
|
|
95
|
-
relatedId: consumed.value.id,
|
|
96
|
-
});
|
|
97
|
-
if (!event.ok)
|
|
98
|
-
return { ok: false, error: event.error };
|
|
99
|
-
const decision = {
|
|
100
|
-
...input.baseDecision,
|
|
101
|
-
decision: 'allow',
|
|
102
|
-
reason: 'task_scoped_grant',
|
|
103
|
-
message: `Task-scoped grant ${consumed.value.id} authorizes this bounded external command preflight.`,
|
|
104
|
-
auditEvidence: [...(input.baseDecision.auditEvidence ?? []), `taskScopedGrant:${consumed.value.id}`, ...(evaluation.commandId === undefined ? [] : [`commandAllowlistId:${evaluation.commandId}`])],
|
|
105
|
-
};
|
|
106
|
-
return { ok: true, value: { authorized: true, decision, grant: consumed.value, evaluation, event: event.value } };
|
|
107
|
-
}
|
|
108
|
-
evaluateMatch(input, requireEligibleAskMetadata) {
|
|
109
|
-
const missing = requiredMissReasons(input);
|
|
110
|
-
if (missing.length > 0)
|
|
111
|
-
return { ok: true, value: emptyEvaluation(true, missing) };
|
|
112
|
-
if (!grantableCategories.has(input.category))
|
|
113
|
-
return { ok: true, value: emptyEvaluation(true, ['unsupported-category']) };
|
|
114
|
-
if (requireEligibleAskMetadata && (input.destructive === true || input.privileged === true || input.ambiguous === true)) {
|
|
115
|
-
return { ok: true, value: emptyEvaluation(true, ['hard-risk-override']) };
|
|
116
|
-
}
|
|
117
|
-
const run = this.runs.getById(input.runId);
|
|
118
|
-
if (!run.ok)
|
|
119
|
-
return run;
|
|
120
|
-
if (input.agentId !== run.value.selectedAgentId)
|
|
121
|
-
return { ok: true, value: emptyEvaluation(true, ['agent-mismatch']) };
|
|
122
|
-
const agentId = input.agentId;
|
|
123
|
-
const taskFingerprint = input.taskFingerprint;
|
|
124
|
-
const cwd = input.cwd;
|
|
125
|
-
const workspaceRoot = input.workspaceRoot;
|
|
126
|
-
if (agentId === undefined || taskFingerprint === undefined || cwd === undefined || workspaceRoot === undefined) {
|
|
127
|
-
return { ok: true, value: emptyEvaluation(true, requiredMissReasons(input)) };
|
|
128
|
-
}
|
|
129
|
-
const candidates = this.grants.list({ runId: input.runId, agentId, status: 'active' });
|
|
130
|
-
if (!candidates.ok)
|
|
131
|
-
return candidates;
|
|
132
|
-
const matched = matchTaskScopedCommandGrant({
|
|
133
|
-
request: {
|
|
134
|
-
runId: input.runId,
|
|
135
|
-
agentId,
|
|
136
|
-
taskFingerprint,
|
|
137
|
-
category: input.category,
|
|
138
|
-
operation: input.operation,
|
|
139
|
-
...(input.commandId === undefined ? {} : { commandId: input.commandId }),
|
|
140
|
-
cwd,
|
|
141
|
-
...(input.targetPaths === undefined ? {} : { targetPaths: input.targetPaths }),
|
|
142
|
-
...(input.destructive === undefined ? {} : { destructive: input.destructive }),
|
|
143
|
-
...(input.privileged === undefined ? {} : { privileged: input.privileged }),
|
|
144
|
-
...(input.ambiguous === undefined ? {} : { ambiguous: input.ambiguous }),
|
|
145
|
-
},
|
|
146
|
-
candidates: candidates.value,
|
|
147
|
-
knownAllowlistIds: commandAllowlistIds(),
|
|
148
|
-
now: input.now ?? new Date(),
|
|
149
|
-
workspaceRoot,
|
|
150
|
-
});
|
|
151
|
-
return { ok: true, value: evaluationFromMatch(matched) };
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
export function grantEvaluationPayload(evaluation) {
|
|
155
|
-
return {
|
|
156
|
-
evaluated: evaluation.evaluated,
|
|
157
|
-
matched: evaluation.matched,
|
|
158
|
-
selectedGrantId: evaluation.selectedGrantId ?? null,
|
|
159
|
-
matchedGrantIds: evaluation.matchedGrantIds,
|
|
160
|
-
missReasons: evaluation.missReasons,
|
|
161
|
-
commandId: evaluation.commandId ?? null,
|
|
162
|
-
canonicalCwd: evaluation.canonicalCwd ?? null,
|
|
163
|
-
matchedExternalRoot: evaluation.matchedExternalRoot ?? null,
|
|
164
|
-
useCountBefore: evaluation.useCountBefore ?? null,
|
|
165
|
-
useCountAfter: evaluation.useCountAfter ?? null,
|
|
166
|
-
candidates: evaluation.candidates,
|
|
167
|
-
};
|
|
168
|
-
}
|
|
169
|
-
function evaluationFromMatch(match) {
|
|
170
|
-
return {
|
|
171
|
-
evaluated: true,
|
|
172
|
-
matched: match.selectedGrantId !== undefined,
|
|
173
|
-
...(match.selectedGrantId === undefined ? {} : { selectedGrantId: match.selectedGrantId }),
|
|
174
|
-
matchedGrantIds: match.matchedGrantIds,
|
|
175
|
-
missReasons: match.missReasons,
|
|
176
|
-
...(match.canonicalCwd === undefined ? {} : { canonicalCwd: match.canonicalCwd }),
|
|
177
|
-
...(match.matchedExternalRoot === undefined ? {} : { matchedExternalRoot: match.matchedExternalRoot }),
|
|
178
|
-
...(match.commandId === undefined ? {} : { commandId: match.commandId }),
|
|
179
|
-
candidates: match.candidates.map((candidate) => ({
|
|
180
|
-
grantId: candidate.grantId,
|
|
181
|
-
matched: candidate.matched,
|
|
182
|
-
selected: candidate.selected,
|
|
183
|
-
missReasons: candidate.missReasons,
|
|
184
|
-
commandId: candidate.commandId ?? null,
|
|
185
|
-
canonicalCwd: candidate.canonicalCwd ?? null,
|
|
186
|
-
matchedExternalRoot: candidate.matchedExternalRoot ?? null,
|
|
187
|
-
})),
|
|
188
|
-
};
|
|
189
|
-
}
|
|
190
|
-
function emptyEvaluation(evaluated, missReasons) {
|
|
191
|
-
return { evaluated, matched: false, matchedGrantIds: [], missReasons, candidates: [] };
|
|
192
|
-
}
|
|
193
|
-
function requiredMissReasons(input) {
|
|
194
|
-
const reasons = [];
|
|
195
|
-
if (input.runId.trim().length === 0)
|
|
196
|
-
reasons.push('missing-run-id');
|
|
197
|
-
if (input.agentId === undefined || input.agentId.trim().length === 0)
|
|
198
|
-
reasons.push('missing-agent-id');
|
|
199
|
-
if (input.taskFingerprint === undefined || input.taskFingerprint.trim().length === 0)
|
|
200
|
-
reasons.push('missing-task-fingerprint');
|
|
201
|
-
if (input.workspaceRoot === undefined || input.workspaceRoot.trim().length === 0)
|
|
202
|
-
reasons.push('missing-workspace-root');
|
|
203
|
-
if (input.cwd === undefined || input.cwd.trim().length === 0)
|
|
204
|
-
reasons.push('missing-cwd');
|
|
205
|
-
return reasons;
|
|
206
|
-
}
|
|
207
|
-
function taskGrantTargetPaths(request) {
|
|
208
|
-
if (request.targetPaths !== undefined)
|
|
209
|
-
return { targetPaths: request.targetPaths };
|
|
210
|
-
if (request.targetPath !== undefined)
|
|
211
|
-
return { targetPaths: [request.targetPath] };
|
|
212
|
-
return {};
|
|
213
|
-
}
|
|
214
|
-
function validationFailure(message) {
|
|
215
|
-
return { ok: false, error: { code: 'validation_failed', message } };
|
|
216
|
-
}
|
|
1
|
+
export * from '../application/runs/task-scoped-command-grant-service.js';
|