sneakoscope 6.0.3 → 6.1.2
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/README.md +29 -12
- package/config/codex-releases/{rust-v0.142.0.json → rust-v0.144.1.json} +6 -6
- package/crates/sks-core/Cargo.lock +1 -1
- package/crates/sks-core/Cargo.toml +1 -1
- package/dist/bin/fast-inline.js +18 -14
- package/dist/bin/sks-dispatch.js +2 -4
- package/dist/cli/args.js +2 -0
- package/dist/cli/command-manifest-lite.js +2 -3
- package/dist/cli/command-registry.js +3 -4
- package/dist/cli/help-fast.js +1 -1
- package/dist/cli/install-helpers.js +348 -763
- package/dist/cli/install-tool-helpers.js +287 -0
- package/dist/cli/router.js +91 -6
- package/dist/commands/codex-lb.js +188 -53
- package/dist/commands/codex.js +44 -5
- package/dist/commands/doctor.js +302 -46
- package/dist/commands/tmux.js +5 -1
- package/dist/commands/versioning.js +7 -0
- package/dist/commands/zellij-monitor-pane.js +2 -0
- package/dist/commands/zellij-viewport-pane.js +3 -1
- package/dist/commands/zellij.js +1 -1
- package/dist/config/skills-manifest.json +59 -59
- package/dist/core/agent-bridge/agent-manifest.js +48 -0
- package/dist/core/agents/agent-central-ledger.js +9 -0
- package/dist/core/agents/agent-cleanup-executor.js +334 -41
- package/dist/core/agents/agent-cleanup.js +20 -1
- package/dist/core/agents/agent-command-surface.js +3 -1
- package/dist/core/agents/agent-effort-policy.js +30 -38
- package/dist/core/agents/agent-janitor.js +9 -10
- package/dist/core/agents/agent-namespace-safety.js +56 -0
- package/dist/core/agents/agent-orchestrator.js +25 -3
- package/dist/core/agents/agent-output-validator.js +1 -1
- package/dist/core/agents/agent-plan.js +100 -21
- package/dist/core/agents/agent-role-config.js +43 -49
- package/dist/core/agents/agent-runner-codex-exec.js +18 -3
- package/dist/core/agents/agent-runner-process.js +1 -0
- package/dist/core/agents/agent-schema.js +3 -2
- package/dist/core/agents/fast-mode-policy.js +3 -5
- package/dist/core/agents/native-cli-session-swarm.js +1 -1
- package/dist/core/agents/native-worker-backend-router.js +2 -1
- package/dist/core/agents/work-partition/repo-inventory.js +68 -7
- package/dist/core/agents/zellij-right-lane-cockpit.js +2 -2
- package/dist/core/code-structure.js +5 -4
- package/dist/core/codex/agent-config-file-repair.js +94 -193
- package/dist/core/codex/codex-cli-update.js +723 -0
- package/dist/core/codex/codex-config-guard.js +38 -11
- package/dist/core/codex/codex-project-config-policy.js +3 -6
- package/dist/core/codex/codex-startup-config-postcheck.js +52 -42
- package/dist/core/codex-adapter.js +35 -22
- package/dist/core/codex-app/codex-agent-role-sync.js +13 -54
- package/dist/core/codex-app/codex-app-fast-ui-repair.js +51 -20
- package/dist/core/codex-app/codex-app-launcher.js +48 -17
- package/dist/core/codex-app/codex-app-restart.js +23 -2
- package/dist/core/codex-app/codex-app-ui-state-snapshot.js +11 -3
- package/dist/core/codex-app/sks-menubar.js +136 -5
- package/dist/core/codex-app.js +35 -14
- package/dist/core/codex-compat/codex-hook-warning-detector.js +10 -1
- package/dist/core/codex-compat/codex-release-manifest.js +6 -6
- package/dist/core/codex-control/codex-0139-doctor-real-probe.js +7 -1
- package/dist/core/codex-control/codex-0139-image-path-real-probe.js +29 -12
- package/dist/core/codex-control/codex-0139-probe-runner.js +103 -28
- package/dist/core/codex-control/codex-0139-real-probe-summary.js +7 -3
- package/dist/core/codex-control/codex-0139-real-probes.js +21 -6
- package/dist/core/codex-control/codex-0139-sandbox-real-probe.js +39 -13
- package/dist/core/codex-control/codex-0139-web-search-probe.js +28 -14
- package/dist/core/codex-control/{codex-0142-capability.js → codex-0144-capability.js} +22 -22
- package/dist/core/codex-control/codex-0144-collab-agent-real-probe.js +63 -0
- package/dist/core/codex-control/codex-lb-launch-recovery.js +278 -0
- package/dist/core/codex-control/codex-multi-agent-event-normalizer.js +5 -1
- package/dist/core/codex-control/codex-reliability-shield.js +93 -30
- package/dist/core/codex-control/codex-sdk-adapter.js +96 -13
- package/dist/core/codex-control/codex-sdk-config-policy.js +2 -1
- package/dist/core/codex-control/codex-sdk-sandbox-policy.js +6 -3
- package/dist/core/codex-control/codex-task-runner.js +62 -9
- package/dist/core/codex-control/python-codex-sdk-adapter.js +30 -3
- package/dist/core/codex-exec-output-schema.js +35 -6
- package/dist/core/codex-lb/codex-lb-env.js +30 -1
- package/dist/core/codex-lb/codex-lb-tool-catalog.js +478 -0
- package/dist/core/codex-lb/codex-lb-tool-output-recovery.js +291 -0
- package/dist/core/codex-native/codex-native-feature-broker.js +31 -38
- package/dist/core/codex-native/codex-native-feature-matrix.js +2 -2
- package/dist/core/codex-native/codex-native-repair-transaction.js +1 -1
- package/dist/core/codex-native/core-skill-manifest.js +8 -4
- package/dist/core/codex-native/native-capability-postcheck.js +16 -8
- package/dist/core/codex-native/native-capability-repair-matrix.js +76 -27
- package/dist/core/codex-plugins/codex-plugin-json.js +67 -21
- package/dist/core/codex-plugins/codex-plugin-repair.js +118 -0
- package/dist/core/codex-runtime/codex-desktop-config-policy.js +305 -0
- package/dist/core/commands/agent-bridge-command.js +23 -2
- package/dist/core/commands/agent-command.js +38 -5
- package/dist/core/commands/basic-cli.js +77 -30
- package/dist/core/commands/command-utils.js +1 -1
- package/dist/core/commands/gc-command.js +27 -4
- package/dist/core/commands/image-ux-review-command.js +55 -24
- package/dist/core/commands/mad-sks-command.js +182 -137
- package/dist/core/commands/naruto-command.js +643 -1153
- package/dist/core/commands/pipeline-command.js +1 -0
- package/dist/core/commands/research-command.js +293 -231
- package/dist/core/commands/run-command.js +100 -23
- package/dist/core/commands/team-command.js +2 -3
- package/dist/core/commands/team-legacy-observe-command.js +94 -359
- package/dist/core/commands/wiki-command.js +179 -83
- package/dist/core/computer-use-live-evidence.js +166 -3
- package/dist/core/computer-use-status.js +5 -2
- package/dist/core/daemon/sksd-hook-daemon-entrypoint.js +2 -2
- package/dist/core/daemon/sksd-hook-daemon.js +171 -28
- package/dist/core/daemon/sksd-hook-dispatch.js +2 -2
- package/dist/core/db-safety.js +2 -2
- package/dist/core/decision-lattice.js +6 -6
- package/dist/core/dfix/verification-selector.js +6 -4
- package/dist/core/doctor/browser-use-repair.js +54 -13
- package/dist/core/doctor/codex-0139-doctor.js +3 -2
- package/dist/core/doctor/codex-startup-config-repair.js +8 -3
- package/dist/core/doctor/computer-use-repair.js +28 -39
- package/dist/core/doctor/doctor-codex-startup-repair.js +24 -149
- package/dist/core/doctor/doctor-context7-repair.js +1 -1
- package/dist/core/doctor/doctor-dirty-planner.js +1 -1
- package/dist/core/doctor/doctor-native-capability-repair.js +74 -3
- package/dist/core/doctor/imagegen-repair.js +47 -12
- package/dist/core/doctor/legacy-global-hook-cleanup.js +179 -0
- package/dist/core/feature-fixture-executor.js +71 -7
- package/dist/core/feature-fixture-runner.js +53 -12
- package/dist/core/feature-fixtures.js +47 -14
- package/dist/core/feature-registry.js +53 -58
- package/dist/core/fsx.js +54 -6
- package/dist/core/harness-conflicts.js +19 -10
- package/dist/core/hooks-runtime/code-pack-freshness-preflight.js +5 -4
- package/dist/core/hooks-runtime/hook-invocation-dedupe.js +147 -0
- package/dist/core/hooks-runtime/hook-io.js +14 -4
- package/dist/core/hooks-runtime/light-turn.js +70 -0
- package/dist/core/hooks-runtime/payload-signals.js +270 -0
- package/dist/core/hooks-runtime/team-digest.js +0 -1
- package/dist/core/hooks-runtime/tool-output-quarantine.js +93 -0
- package/dist/core/hooks-runtime.js +418 -250
- package/dist/core/image/image-artifact-path-contract.js +8 -6
- package/dist/core/image/image-artifact-registry.js +5 -1
- package/dist/core/image-ux-review/imagegen-adapter.js +5 -2
- package/dist/core/imagegen/imagegen-capability.js +10 -13
- package/dist/core/imagegen/require-imagegen.js +37 -11
- package/dist/core/init/skills.js +16 -30
- package/dist/core/init.js +144 -36
- package/dist/core/managed-assets/managed-assets-manifest.js +417 -14
- package/dist/core/mission.js +24 -1
- package/dist/core/naruto/naruto-work-graph.js +70 -4
- package/dist/core/ops/reporting.js +3 -0
- package/dist/core/pipeline-internals/runtime-core.js +578 -180
- package/dist/core/pipeline-internals/runtime-gates.js +191 -49
- package/dist/core/ppt/style-tokens.js +1 -1
- package/dist/core/ppt-review/index.js +1 -1
- package/dist/core/ppt-review/slide-exporter.js +23 -17
- package/dist/core/ppt-review/slide-imagegen-review.js +1 -1
- package/dist/core/ppt-review/slide-issue-extraction.js +4 -2
- package/dist/core/preflight/parallel-preflight-engine.js +50 -1
- package/dist/core/product-design-plugin.js +2 -2
- package/dist/core/proof/route-finalizer.js +1 -1
- package/dist/core/proof/route-proof-gate.js +7 -2
- package/dist/core/proof-field.js +3 -3
- package/dist/core/provider/model-router.js +38 -32
- package/dist/core/recallpulse/policy.js +12 -28
- package/dist/core/recallpulse.js +11 -6
- package/dist/core/release/gate-manifest.js +18 -12
- package/dist/core/release/gate-pack-manifest.js +1 -1
- package/dist/core/release/npm-pack-proof.js +247 -0
- package/dist/core/release/package-dist-snapshot.js +151 -0
- package/dist/core/release/package-size-budget.js +5 -0
- package/dist/core/release/release-authorization-snapshot.js +115 -0
- package/dist/core/release/release-gate-affected-selector.js +15 -3
- package/dist/core/release/release-gate-cache-v2.js +30 -0
- package/dist/core/release/release-gate-contract.js +161 -0
- package/dist/core/release/release-gate-dag.js +44 -3
- package/dist/core/release/release-gate-hermetic-env.js +28 -17
- package/dist/core/release/release-real-contract.js +496 -0
- package/dist/core/release-parallel-full-coverage.js +31 -143
- package/dist/core/research/claim-evidence-matrix.js +41 -6
- package/dist/core/research/experiment-plan.js +14 -10
- package/dist/core/research/falsification.js +9 -2
- package/dist/core/research/implementation-blueprint-densifier.js +82 -60
- package/dist/core/research/implementation-blueprint.js +32 -26
- package/dist/core/research/mock-result.js +122 -11
- package/dist/core/research/replication-pack.js +15 -8
- package/dist/core/research/research-adversarial-review.js +1068 -0
- package/dist/core/research/research-claim-builder.js +69 -17
- package/dist/core/research/research-claim-synthesizer.js +343 -0
- package/dist/core/research/research-cycle-runner.js +53 -3
- package/dist/core/research/research-falsification-runner.js +176 -0
- package/dist/core/research/research-final-reviewer.js +44 -125
- package/dist/core/research/research-realistic-report.js +14 -6
- package/dist/core/research/research-review-artifact-digest.js +66 -0
- package/dist/core/research/research-source-evidence.js +144 -0
- package/dist/core/research/research-source-layer-catalog.js +68 -0
- package/dist/core/research/research-source-ledger-merge.js +250 -12
- package/dist/core/research/research-source-shards.js +26 -70
- package/dist/core/research/research-stage-runner.js +237 -247
- package/dist/core/research/research-super-search.js +184 -0
- package/dist/core/research/research-synthesis-prompt.js +20 -1
- package/dist/core/research/research-synthesis-writer.js +86 -5
- package/dist/core/research/research-work-graph.js +25 -18
- package/dist/core/research/source-quality-report.js +21 -0
- package/dist/core/research.js +429 -280
- package/dist/core/retention/retention-budget.js +25 -6
- package/dist/core/retention.js +980 -101
- package/dist/core/routes/constants.js +1 -1
- package/dist/core/routes/dollar-manifest-lite.js +11 -11
- package/dist/core/routes/evidence.js +4 -4
- package/dist/core/routes/ppt-policy.js +1 -1
- package/dist/core/routes.js +92 -64
- package/dist/core/runtime/task-profile.js +66 -0
- package/dist/core/runtime/verification-budget.js +12 -0
- package/dist/core/secret-redaction.js +4 -0
- package/dist/core/security/high-risk-contracts.js +6 -6
- package/dist/core/stop-gate/stop-gate-check.js +49 -12
- package/dist/core/subagents/agent-catalog.js +215 -0
- package/dist/core/subagents/model-policy.js +118 -0
- package/dist/core/subagents/naruto-help-contract.js +40 -0
- package/dist/core/subagents/official-subagent-config.js +488 -0
- package/dist/core/subagents/official-subagent-preparation.js +251 -0
- package/dist/core/subagents/official-subagent-prompt.js +137 -0
- package/dist/core/subagents/official-subagent-runner.js +129 -0
- package/dist/core/subagents/subagent-evidence.js +663 -0
- package/dist/core/subagents/terminology.js +16 -0
- package/dist/core/subagents/thread-budget.js +21 -0
- package/dist/core/subagents/triwiki-attention.js +65 -0
- package/dist/core/super-search/runtime-helpers.js +173 -19
- package/dist/core/super-search/runtime.js +140 -15
- package/dist/core/super-search/source-records.js +49 -8
- package/dist/core/team-review-policy.js +15 -0
- package/dist/core/triwiki/code-pack.js +8 -2
- package/dist/core/triwiki/triwiki-cache-key.js +108 -29
- package/dist/core/triwiki/triwiki-module-card.js +1 -1
- package/dist/core/triwiki-attention.js +13 -6
- package/dist/core/triwiki-provenance.js +274 -0
- package/dist/core/triwiki-runtime.js +21 -7
- package/dist/core/triwiki-wrongness/wrongness-ledger.js +187 -61
- package/dist/core/triwiki-wrongness/wrongness-retrieval.js +11 -2
- package/dist/core/triwiki-wrongness/wrongness-trust-policy.js +2 -0
- package/dist/core/update-check.js +23 -15
- package/dist/core/version-manager.js +51 -1
- package/dist/core/version.js +1 -1
- package/dist/core/wiki-coordinate.js +128 -12
- package/dist/core/work-order-ledger.js +208 -10
- package/dist/core/zellij/zellij-command.js +12 -1
- package/dist/core/zellij/zellij-dashboard-pane.js +3 -3
- package/dist/core/zellij/zellij-fake-adapter.js +3 -1
- package/dist/core/zellij/zellij-launcher.js +51 -21
- package/dist/core/zellij/zellij-layout-builder.js +14 -5
- package/dist/core/zellij/zellij-official-subagent-activity.js +477 -0
- package/dist/core/zellij/zellij-official-subagent-telemetry.js +264 -0
- package/dist/core/zellij/zellij-pane-proof.js +32 -6
- package/dist/core/zellij/zellij-slot-pane-renderer.js +17 -5
- package/dist/core/zellij/zellij-slot-telemetry.js +15 -3
- package/dist/core/zellij/zellij-ui-mode.js +1 -1
- package/dist/core/zellij/zellij-viewport-binder.js +3 -0
- package/dist/core/zellij/zellij-worker-pane-manager.js +5 -3
- package/dist/scripts/agent-fast-mode-default-check.js +48 -29
- package/dist/scripts/agent-role-config-repair-check.js +34 -15
- package/dist/scripts/agent-wiki-context-proof-check.js +16 -2
- package/dist/scripts/all-feature-deep-completion-check.js +14 -4
- package/dist/scripts/architecture-guard-check.js +8 -1
- package/dist/scripts/build-dist.js +17 -5
- package/dist/scripts/canonical-test-runner.js +188 -0
- package/dist/scripts/check-command-module-budget.js +38 -16
- package/dist/scripts/check-legacy-free.js +1 -1
- package/dist/scripts/check-route-modularity.js +0 -1
- package/dist/scripts/check-ts-contracts.js +1 -1
- package/dist/scripts/codex-0139-interrupt-agent-check.js +5 -1
- package/dist/scripts/{codex-0142-app-server-v2-check.js → codex-0144-app-server-v2-check.js} +11 -10
- package/dist/scripts/{codex-0142-binary-identity-check.js → codex-0144-binary-identity-check.js} +4 -4
- package/dist/scripts/codex-0144-capability-check.js +21 -0
- package/dist/scripts/{codex-0139-real-probes-check.js → codex-0144-core-real-probes-check.js} +19 -5
- package/dist/scripts/{codex-0142-doctor-wiring-check.js → codex-0144-doctor-wiring-check.js} +6 -6
- package/dist/scripts/{codex-0142-manifest-check.js → codex-0144-manifest-check.js} +11 -3
- package/dist/scripts/{codex-0142-policy-check.js → codex-0144-policy-check.js} +2 -2
- package/dist/scripts/{codex-0142-thread-store-check.js → codex-0144-thread-store-check.js} +3 -3
- package/dist/scripts/codex-app-provider-model-ui-check.js +53 -19
- package/dist/scripts/codex-app-ui-preservation-check.js +35 -4
- package/dist/scripts/codex-control-all-pipelines-check.js +7 -3
- package/dist/scripts/codex-control-side-effect-scope-check.js +2 -2
- package/dist/scripts/codex-control-tool-output-continuity-audit-check.js +27 -0
- package/dist/scripts/codex-effort-auto-discovery-check.js +1 -1
- package/dist/scripts/codex-lb-fast-mode-truth-check.js +1 -0
- package/dist/scripts/{codex-lb-gpt55-fast-profile-check.js → codex-lb-gpt56-fast-profile-check.js} +56 -5
- package/dist/scripts/codex-model-metadata-check.js +1 -1
- package/dist/scripts/codex-native-agent-role-content-check.js +15 -7
- package/dist/scripts/codex-native-repair-transaction-check.js +3 -1
- package/dist/scripts/codex-sdk-all-pipelines-check.js +7 -4
- package/dist/scripts/codex-sdk-research-pipeline-check.js +30 -8
- package/dist/scripts/codex-sdk-sandbox-policy-check.js +5 -1
- package/dist/scripts/codex-sdk-version-compat-check.js +2 -1
- package/dist/scripts/db-route-materialization-check.js +33 -0
- package/dist/scripts/dfix-fixture-check.js +1 -1
- package/dist/scripts/docs-truthfulness-check.js +4 -2
- package/dist/scripts/doctor-codex-startup-repair-check.js +47 -25
- package/dist/scripts/doctor-context7-repair-check.js +2 -1
- package/dist/scripts/doctor-fix-production-blackbox.js +12 -2
- package/dist/scripts/doctor-fixes-codex-app-fast-ui-check.js +34 -7
- package/dist/scripts/doctor-imagegen-repair-check.js +14 -4
- package/dist/scripts/doctor-startup-config-repair-blackbox.js +9 -3
- package/dist/scripts/doctor-startup-config-repair-check.js +13 -3
- package/dist/scripts/install-update-preserves-config-check.js +7 -2
- package/dist/scripts/legacy-gate-inventory-check.js +7 -5
- package/dist/scripts/legacy-strong-inventory-check.js +7 -5
- package/dist/scripts/legacy-upgrade-matrix-check.js +4 -4
- package/dist/scripts/lib/native-cli-session-swarm-check-lib.js +173 -13
- package/dist/scripts/mad-sks-app-ui-no-mutation-check.js +165 -6
- package/dist/scripts/managed-role-manifest-parity-check.js +5 -4
- package/dist/scripts/mutation-callsite-coverage-check.js +0 -11
- package/dist/scripts/naruto-codex-e2e-check.js +14 -7
- package/dist/scripts/naruto-shadow-clone-swarm-check.js +4 -201
- package/dist/scripts/npm-publish-performance-check.js +20 -12
- package/dist/scripts/official-subagent-workflow-check.js +145 -0
- package/dist/scripts/package-published-contract-check.js +6 -20
- package/dist/scripts/packlist-performance-check.js +17 -3
- package/dist/scripts/parallel-verification-engine-check.js +2 -2
- package/dist/scripts/postinstall-safe-side-effects-check.js +8 -3
- package/dist/scripts/ppt-no-mock-as-real-check.js +3 -1
- package/dist/scripts/prepublish-release-check-or-fast.js +23 -86
- package/dist/scripts/product-design-plugin-routing-check.js +1 -1
- package/dist/scripts/release-affected-selector-check.js +74 -1
- package/dist/scripts/release-check-stamp.js +324 -239
- package/dist/scripts/release-dag-full-coverage-check.js +7 -15
- package/dist/scripts/release-dynamic-presets-check.js +10 -1
- package/dist/scripts/release-gate-dag-runner-check.js +3 -3
- package/dist/scripts/release-gate-dag-runner.js +35 -11
- package/dist/scripts/release-gate-existence-audit.js +1 -2
- package/dist/scripts/release-gate-script-parity-check.js +1 -1
- package/dist/scripts/release-parallel-full-coverage-check.js +12 -6
- package/dist/scripts/release-parallel-speed-budget-check.js +18 -2
- package/dist/scripts/release-real-check.js +390 -157
- package/dist/scripts/release-registry-check.js +61 -16
- package/dist/scripts/release-runtime-truth-matrix-check.js +22 -0
- package/dist/scripts/research-blueprint-densifier-check.js +2 -2
- package/dist/scripts/research-real-cycle-no-legacy-final-md-check.js +11 -7
- package/dist/scripts/route-proof-artifact-structure-check.js +1 -0
- package/dist/scripts/search-visibility-gate-lib.js +1 -1
- package/dist/scripts/seo-geo-route-identity-check.js +30 -4
- package/dist/scripts/sizecheck.js +4 -4
- package/dist/scripts/sks-1-11-gate-lib.js +53 -6
- package/dist/scripts/sks-3-1-4-directive-check-lib.js +8 -2
- package/dist/scripts/sks-3-1-5-directive-check-lib.js +3 -2
- package/dist/scripts/sks-3-1-6-directive-check-lib.js +5 -3
- package/dist/scripts/sks-menubar-install-check.js +8 -0
- package/dist/scripts/sks-uninstall-regression-check.js +1 -1
- package/dist/scripts/sksd-daemon-check.js +16 -6
- package/dist/scripts/trust-fixture-check.js +32 -10
- package/dist/scripts/write-build-manifest.js +2 -1
- package/dist/scripts/wrongness-fixture-check.js +1 -1
- package/dist/scripts/zellij-layout-valid-check.js +36 -11
- package/dist/scripts/zellij-pane-proof-check.js +33 -2
- package/dist/scripts/zellij-real-session-cleanup-check.js +122 -2
- package/dist/scripts/zellij-real-session-launch-check.js +76 -5
- package/dist/scripts/zellij-slot-pane-renderer-check.js +4 -4
- package/dist/scripts/zellij-spawn-on-demand-layout-check.js +3 -3
- package/docs/demo.tape +1 -1
- package/infra-harness-gates.json +1486 -0
- package/package.json +32 -19
- package/release-gates.v2.json +4060 -0
- package/runtime-required-scripts.json +9 -0
- package/schemas/codex/{app-server-0.142 → app-server-0.144}/codex_app_server_protocol.v2.schemas.json +1146 -781
- package/schemas/codex/codex-0139-real-probe-result.schema.json +39 -5
- package/schemas/codex/ppt-slide-issue-ledger.schema.json +2 -1
- package/dist/commands/db.js +0 -6
- package/dist/core/codex-control/codex-0139-multi-agent-real-probe.js +0 -107
- package/dist/core/commands/db-command.js +0 -146
- package/dist/core/research/prompt.js +0 -15
- package/dist/scripts/agent-native-release-gate.js +0 -274
- package/dist/scripts/codex-0142-capability-check.js +0 -21
- package/dist/scripts/codex-control-tool-call-sequence-repair-check.js +0 -14
- package/dist/scripts/command-performance-scorecard-check.js +0 -204
- package/dist/scripts/config-managed-merge-callsite-coverage-check.js +0 -212
- package/dist/scripts/dollar-performance-scorecard-check.js +0 -257
- package/dist/scripts/gate-timing-check.js +0 -16
- package/dist/scripts/ops-maturity-scorecard-check.js +0 -12
- package/dist/scripts/performance-baseline-check.js +0 -12
- package/dist/scripts/performance-improvement-report-check.js +0 -58
- package/dist/scripts/release-parallel-check.js +0 -389
- package/dist/scripts/release-runner-efficiency-check.js +0 -15
- package/dist/scripts/retention-long-run-smoke-check.js +0 -299
- package/docs/assets/sneakoscope-architecture-pipeline.jpg +0 -0
|
@@ -3,10 +3,15 @@ import path from 'node:path';
|
|
|
3
3
|
import { appendJsonl, exists, nowIso, packageRoot, readJson, writeJsonAtomic } from '../fsx.js';
|
|
4
4
|
import { drainZellijLaneSupervisor } from './zellij-lane-supervisor.js';
|
|
5
5
|
import { normalizeAgentSessionRows } from './agent-session-rows.js';
|
|
6
|
+
import { isAgentTerminalSessionStatus, writeAgentCleanupReport } from './agent-cleanup.js';
|
|
6
7
|
import { closeZellijPaneById } from '../zellij/zellij-worker-pane-manager.js';
|
|
8
|
+
import { processReportMatchesProjectNamespace, resolveOwnedNamespacePath, validProjectNamespaceHash } from './agent-namespace-safety.js';
|
|
9
|
+
import { appendAgentLedgerEvent } from './agent-central-ledger.js';
|
|
10
|
+
import { closeAgentSession } from './agent-lifecycle.js';
|
|
11
|
+
import { closeAgentSessionGeneration } from './agent-session-generation.js';
|
|
12
|
+
import { closeAgentTerminalSession } from './agent-terminal-session.js';
|
|
7
13
|
export const AGENT_CLEANUP_PROOF_SCHEMA = 'sks.agent-cleanup-proof.v2';
|
|
8
14
|
export const AGENT_CLEANUP_ACTION_LEDGER_SCHEMA = 'sks.agent-cleanup-action-ledger.v1';
|
|
9
|
-
const TERMINAL_STATUSES = new Set(['closed', 'completed', 'done', 'failed', 'blocked', 'killed', 'timed_out']);
|
|
10
15
|
export async function runAgentCleanupExecutor(opts) {
|
|
11
16
|
const agentRoot = path.join(opts.missionDir, 'agents');
|
|
12
17
|
const action = opts.action || 'cleanup';
|
|
@@ -16,30 +21,61 @@ export async function runAgentCleanupExecutor(opts) {
|
|
|
16
21
|
const namespace = await readJson(path.join(opts.missionDir, 'project-session-namespace.json'), null);
|
|
17
22
|
const sessionsRaw = await readJson(path.join(agentRoot, 'agent-sessions.json'), { sessions: {} });
|
|
18
23
|
const sessions = normalizeAgentSessionRows(sessionsRaw);
|
|
24
|
+
const sessionById = new Map(sessions.map((row) => [String(row.session_id || row.id || row.agent_id || ''), row]));
|
|
19
25
|
const activeSessionIds = new Set(sessions
|
|
20
|
-
.filter((row) => !
|
|
26
|
+
.filter((row) => !isAgentTerminalSessionStatus(row.status || row.lifecycle_state))
|
|
21
27
|
.map((row) => String(row.session_id || row.id || row.agent_id || ''))
|
|
22
28
|
.filter(Boolean));
|
|
23
29
|
const now = Date.now();
|
|
24
|
-
const
|
|
30
|
+
const requestedStaleMs = Number(opts.staleMs ?? 30 * 60 * 1000);
|
|
31
|
+
const staleMs = Number.isFinite(requestedStaleMs) ? Math.max(0, requestedStaleMs) : 30 * 60 * 1000;
|
|
25
32
|
const projectHash = String(namespace?.root_hash || '');
|
|
33
|
+
const namespaceAuthorized = validProjectNamespaceHash(projectHash);
|
|
26
34
|
const actions = [];
|
|
27
35
|
const graceMs = opts.graceMs ?? Number(process.env.SKS_CLEANUP_GRACE_MS || 750);
|
|
28
36
|
const killEscalation = opts.killEscalation !== false && process.env.SKS_CLEANUP_KILL_ESCALATION !== '0';
|
|
29
|
-
const
|
|
37
|
+
const sessionFiles = await listFiles(path.join(agentRoot, 'sessions'));
|
|
38
|
+
for (const session of sessions) {
|
|
39
|
+
if (isAgentTerminalSessionStatus(session.status || session.lifecycle_state))
|
|
40
|
+
continue;
|
|
41
|
+
const staleAction = await reconcileStaleSession({
|
|
42
|
+
agentRoot,
|
|
43
|
+
session,
|
|
44
|
+
sessionFiles,
|
|
45
|
+
projectHash,
|
|
46
|
+
namespaceAuthorized,
|
|
47
|
+
missionId: opts.missionId || namespace?.mission_id || null,
|
|
48
|
+
now,
|
|
49
|
+
staleMs,
|
|
50
|
+
apply
|
|
51
|
+
});
|
|
52
|
+
if (!staleAction)
|
|
53
|
+
continue;
|
|
54
|
+
actions.push(staleAction);
|
|
55
|
+
if (staleAction.kind === 'terminalize_stale_session' && (staleAction.status === 'planned' || staleAction.status === 'applied')) {
|
|
56
|
+
activeSessionIds.delete(String(session.session_id || session.session_key || session.id || session.agent_id || ''));
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
const processReports = sessionFiles.filter((file) => path.basename(file) === 'agent-process-report.json');
|
|
30
60
|
for (const file of processReports) {
|
|
31
61
|
const report = await readJson(file, null);
|
|
32
62
|
const pid = Number(report?.pid || 0);
|
|
33
63
|
const sessionId = String(report?.session_id || '');
|
|
34
|
-
const status = String(
|
|
35
|
-
const terminal =
|
|
64
|
+
const status = String(sessionById.get(sessionId)?.status || '');
|
|
65
|
+
const terminal = isAgentTerminalSessionStatus(status);
|
|
36
66
|
if (!pid || !processIsAlive(pid))
|
|
37
67
|
continue;
|
|
68
|
+
// A non-null exit code proves the recorded process already exited. If the
|
|
69
|
+
// PID is alive now it has been reused and must never be killed.
|
|
70
|
+
if (report?.exit_code !== null && report?.exit_code !== undefined) {
|
|
71
|
+
actions.push({ kind: 'skip_foreign_namespace', target: String(pid), status: 'skipped', reason: 'recorded_process_already_exited_pid_reused' });
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
38
74
|
if (activeSessionIds.has(sessionId) && !terminal) {
|
|
39
75
|
actions.push({ kind: 'skip_active_session', target: sessionId || String(pid), status: 'skipped', reason: 'session_active' });
|
|
40
76
|
continue;
|
|
41
77
|
}
|
|
42
|
-
if (!
|
|
78
|
+
if (!processReportMatchesProjectNamespace(report, projectHash)) {
|
|
43
79
|
actions.push({ kind: 'skip_foreign_namespace', target: String(pid), status: 'skipped', reason: 'process_outside_project_namespace' });
|
|
44
80
|
continue;
|
|
45
81
|
}
|
|
@@ -52,7 +88,7 @@ export async function runAgentCleanupExecutor(opts) {
|
|
|
52
88
|
}));
|
|
53
89
|
}
|
|
54
90
|
const seenZellijPaneIds = new Set();
|
|
55
|
-
const zellijReports =
|
|
91
|
+
const zellijReports = sessionFiles.filter((file) => path.basename(file) === 'agent-zellij-report.json');
|
|
56
92
|
for (const file of zellijReports) {
|
|
57
93
|
const report = await readJson(file, null);
|
|
58
94
|
const paneId = String(report?.pane_id || '');
|
|
@@ -60,7 +96,7 @@ export async function runAgentCleanupExecutor(opts) {
|
|
|
60
96
|
if (!paneId)
|
|
61
97
|
continue;
|
|
62
98
|
seenZellijPaneIds.add(paneId);
|
|
63
|
-
if (!
|
|
99
|
+
if (!processReportMatchesProjectNamespace(report, projectHash)) {
|
|
64
100
|
actions.push({ kind: 'skip_foreign_namespace', target: paneId, status: 'skipped', reason: 'zellij_pane_outside_project_namespace' });
|
|
65
101
|
continue;
|
|
66
102
|
}
|
|
@@ -80,7 +116,7 @@ export async function runAgentCleanupExecutor(opts) {
|
|
|
80
116
|
}
|
|
81
117
|
}));
|
|
82
118
|
}
|
|
83
|
-
const workerPaneReports =
|
|
119
|
+
const workerPaneReports = sessionFiles.filter((file) => path.basename(file) === 'zellij-worker-pane.json');
|
|
84
120
|
for (const file of workerPaneReports) {
|
|
85
121
|
const report = await readJson(file, null);
|
|
86
122
|
const paneId = String(report?.pane_id || '');
|
|
@@ -90,11 +126,15 @@ export async function runAgentCleanupExecutor(opts) {
|
|
|
90
126
|
if (!paneId || !sessionName || seenZellijPaneIds.has(paneId))
|
|
91
127
|
continue;
|
|
92
128
|
seenZellijPaneIds.add(paneId);
|
|
129
|
+
if (!namespaceAuthorized) {
|
|
130
|
+
actions.push({ kind: 'skip_foreign_namespace', target: paneId, status: 'skipped', reason: 'project_namespace_missing_or_invalid' });
|
|
131
|
+
continue;
|
|
132
|
+
}
|
|
93
133
|
if (opts.missionId && report?.mission_id && String(report.mission_id) !== String(opts.missionId)) {
|
|
94
134
|
actions.push({ kind: 'skip_foreign_namespace', target: paneId, status: 'skipped', reason: 'zellij_pane_wrong_mission' });
|
|
95
135
|
continue;
|
|
96
136
|
}
|
|
97
|
-
const terminal =
|
|
137
|
+
const terminal = isAgentTerminalSessionStatus(status) || Boolean(report?.closed_at);
|
|
98
138
|
if (activeSessionIds.has(sessionId) && !terminal && opts.drain !== true) {
|
|
99
139
|
actions.push({ kind: 'skip_active_session', target: sessionId || paneId, status: 'skipped', reason: 'managed_zellij_worker_active' });
|
|
100
140
|
continue;
|
|
@@ -132,6 +172,10 @@ export async function runAgentCleanupExecutor(opts) {
|
|
|
132
172
|
if (seenZellijPaneIds.has(paneId))
|
|
133
173
|
continue;
|
|
134
174
|
seenZellijPaneIds.add(paneId);
|
|
175
|
+
if (!namespaceAuthorized) {
|
|
176
|
+
actions.push({ kind: 'skip_foreign_namespace', target: paneId, status: 'skipped', reason: 'project_namespace_missing_or_invalid' });
|
|
177
|
+
continue;
|
|
178
|
+
}
|
|
135
179
|
if ((visibleActive || headlessActive) && opts.drain !== true) {
|
|
136
180
|
actions.push({ kind: 'skip_active_session', target: paneId, status: 'skipped', reason: 'zellij_right_column_anchor_active' });
|
|
137
181
|
continue;
|
|
@@ -152,22 +196,21 @@ export async function runAgentCleanupExecutor(opts) {
|
|
|
152
196
|
}
|
|
153
197
|
}
|
|
154
198
|
for (const dir of Array.isArray(namespace?.orphan_temp_dirs) ? namespace.orphan_temp_dirs.map(String) : []) {
|
|
155
|
-
|
|
199
|
+
const ownedDir = await resolveOwnedNamespacePath(dir, projectHash, namespace?.temp_dir ? [namespace.temp_dir] : []);
|
|
200
|
+
if (!ownedDir) {
|
|
156
201
|
actions.push({ kind: 'skip_foreign_namespace', target: dir, status: 'skipped', reason: 'path_outside_project_namespace' });
|
|
157
202
|
continue;
|
|
158
203
|
}
|
|
159
|
-
if (!(await exists(dir)))
|
|
160
|
-
continue;
|
|
161
204
|
actions.push(await applyAction({
|
|
162
205
|
kind: 'remove_temp_dir',
|
|
163
|
-
target:
|
|
206
|
+
target: ownedDir,
|
|
164
207
|
reason: 'orphan_temp_dir',
|
|
165
208
|
apply,
|
|
166
|
-
before: async () => ({ exists: await exists(
|
|
167
|
-
after: async () => ({ exists: await exists(
|
|
209
|
+
before: async () => ({ exists: await exists(ownedDir) }),
|
|
210
|
+
after: async () => ({ exists: await exists(ownedDir) }),
|
|
168
211
|
run: async () => {
|
|
169
|
-
await fsp.rm(
|
|
170
|
-
if (await exists(
|
|
212
|
+
await fsp.rm(ownedDir, { recursive: true, force: true });
|
|
213
|
+
if (await exists(ownedDir))
|
|
171
214
|
throw new Error('temp_dir_still_exists_after_remove');
|
|
172
215
|
}
|
|
173
216
|
}));
|
|
@@ -187,9 +230,10 @@ export async function runAgentCleanupExecutor(opts) {
|
|
|
187
230
|
}
|
|
188
231
|
}));
|
|
189
232
|
}
|
|
190
|
-
for (const transcript of
|
|
233
|
+
for (const transcript of sessionFiles.filter((file) => path.basename(file) === 'agent-terminal-session.json')) {
|
|
191
234
|
actions.push({ kind: 'archive_transcript_keep', target: transcript, status: 'skipped', reason: 'terminal_transcripts_are_preserved' });
|
|
192
235
|
}
|
|
236
|
+
const sessionCleanup = await writeAgentCleanupReport(agentRoot);
|
|
193
237
|
const proof = buildCleanupProof({
|
|
194
238
|
generatedAt: nowIso(),
|
|
195
239
|
missionId: opts.missionId || namespace?.mission_id || null,
|
|
@@ -198,7 +242,8 @@ export async function runAgentCleanupExecutor(opts) {
|
|
|
198
242
|
apply,
|
|
199
243
|
dryRun: !apply,
|
|
200
244
|
actions,
|
|
201
|
-
activeSessionIds: [...activeSessionIds]
|
|
245
|
+
activeSessionIds: [...activeSessionIds],
|
|
246
|
+
sessionCleanup
|
|
202
247
|
});
|
|
203
248
|
await writeJsonAtomic(path.join(agentRoot, 'agent-cleanup-proof.json'), proof);
|
|
204
249
|
await writeJsonAtomic(path.join(agentRoot, 'agent-command-cleanup.json'), {
|
|
@@ -220,6 +265,257 @@ export async function runAgentCleanupExecutor(opts) {
|
|
|
220
265
|
}
|
|
221
266
|
return proof;
|
|
222
267
|
}
|
|
268
|
+
const STALE_SESSION_REASON = 'stale_nonterminal_session_without_live_process';
|
|
269
|
+
const SESSION_PROCESS_REPORT_NAMES = new Set(['agent-process-report.json', 'worker-process-report.json']);
|
|
270
|
+
async function reconcileStaleSession(input) {
|
|
271
|
+
const initial = await assessStaleSession(input);
|
|
272
|
+
if (!initial.stale)
|
|
273
|
+
return null;
|
|
274
|
+
const sessionId = initial.session_id;
|
|
275
|
+
if (!sessionId || !initial.artifact_dir || !input.namespaceAuthorized) {
|
|
276
|
+
return {
|
|
277
|
+
kind: 'skip_foreign_namespace',
|
|
278
|
+
target: sessionId || 'unknown-session',
|
|
279
|
+
status: 'skipped',
|
|
280
|
+
reason: !input.namespaceAuthorized ? 'stale_session_project_namespace_missing_or_invalid' : 'stale_session_artifact_path_invalid',
|
|
281
|
+
before: initial.evidence
|
|
282
|
+
};
|
|
283
|
+
}
|
|
284
|
+
if (initial.foreign_process_reports.length > 0) {
|
|
285
|
+
return {
|
|
286
|
+
kind: 'skip_foreign_namespace',
|
|
287
|
+
target: sessionId,
|
|
288
|
+
status: 'skipped',
|
|
289
|
+
reason: 'stale_session_foreign_process_report',
|
|
290
|
+
before: initial.evidence
|
|
291
|
+
};
|
|
292
|
+
}
|
|
293
|
+
if (initial.live_pids.length > 0) {
|
|
294
|
+
return {
|
|
295
|
+
kind: 'skip_active_session',
|
|
296
|
+
target: sessionId,
|
|
297
|
+
status: 'skipped',
|
|
298
|
+
reason: 'stale_session_live_process',
|
|
299
|
+
before: initial.evidence
|
|
300
|
+
};
|
|
301
|
+
}
|
|
302
|
+
if (!input.apply) {
|
|
303
|
+
return {
|
|
304
|
+
kind: 'terminalize_stale_session',
|
|
305
|
+
target: sessionId,
|
|
306
|
+
status: 'planned',
|
|
307
|
+
reason: STALE_SESSION_REASON,
|
|
308
|
+
before: initial.evidence,
|
|
309
|
+
after: initial.evidence
|
|
310
|
+
};
|
|
311
|
+
}
|
|
312
|
+
const latestSession = await readLatestSessionRecord(input.agentRoot, input.session, initial.artifact_dir);
|
|
313
|
+
const latestFiles = await listFiles(path.join(input.agentRoot, 'sessions'));
|
|
314
|
+
const latest = await assessStaleSession({ ...input, session: latestSession, sessionFiles: latestFiles });
|
|
315
|
+
if (!latest.stale) {
|
|
316
|
+
return {
|
|
317
|
+
kind: 'skip_active_session',
|
|
318
|
+
target: sessionId,
|
|
319
|
+
status: 'skipped',
|
|
320
|
+
reason: 'stale_session_activity_refreshed_before_apply',
|
|
321
|
+
before: initial.evidence,
|
|
322
|
+
after: latest.evidence
|
|
323
|
+
};
|
|
324
|
+
}
|
|
325
|
+
if (latest.foreign_process_reports.length > 0) {
|
|
326
|
+
return {
|
|
327
|
+
kind: 'skip_foreign_namespace',
|
|
328
|
+
target: sessionId,
|
|
329
|
+
status: 'skipped',
|
|
330
|
+
reason: 'stale_session_foreign_process_report',
|
|
331
|
+
before: initial.evidence,
|
|
332
|
+
after: latest.evidence
|
|
333
|
+
};
|
|
334
|
+
}
|
|
335
|
+
if (latest.live_pids.length > 0) {
|
|
336
|
+
return {
|
|
337
|
+
kind: 'skip_active_session',
|
|
338
|
+
target: sessionId,
|
|
339
|
+
status: 'skipped',
|
|
340
|
+
reason: 'stale_session_live_process',
|
|
341
|
+
before: initial.evidence,
|
|
342
|
+
after: latest.evidence
|
|
343
|
+
};
|
|
344
|
+
}
|
|
345
|
+
try {
|
|
346
|
+
const after = await terminalizeStaleSession(input.agentRoot, latestSession, latest, input.missionId);
|
|
347
|
+
return {
|
|
348
|
+
kind: 'terminalize_stale_session',
|
|
349
|
+
target: sessionId,
|
|
350
|
+
status: 'applied',
|
|
351
|
+
reason: STALE_SESSION_REASON,
|
|
352
|
+
before: initial.evidence,
|
|
353
|
+
after
|
|
354
|
+
};
|
|
355
|
+
}
|
|
356
|
+
catch (err) {
|
|
357
|
+
return {
|
|
358
|
+
kind: 'terminalize_stale_session',
|
|
359
|
+
target: sessionId,
|
|
360
|
+
status: 'failed',
|
|
361
|
+
reason: STALE_SESSION_REASON,
|
|
362
|
+
before: initial.evidence,
|
|
363
|
+
error: err instanceof Error ? err.message : String(err)
|
|
364
|
+
};
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
async function assessStaleSession(input) {
|
|
368
|
+
const sessionId = String(input.session?.session_id || input.session?.session_key || input.session?.id || input.session?.agent_id || '');
|
|
369
|
+
const artifact = resolveSessionArtifactDir(input.agentRoot, input.session);
|
|
370
|
+
const activity = latestSessionActivity(input.session);
|
|
371
|
+
const ageMs = activity ? Math.max(0, input.now - activity.timestamp) : null;
|
|
372
|
+
const stale = ageMs !== null && ageMs > input.staleMs;
|
|
373
|
+
const reportFiles = input.sessionFiles.filter((file) => SESSION_PROCESS_REPORT_NAMES.has(path.basename(file)));
|
|
374
|
+
const reports = [];
|
|
375
|
+
for (const file of reportFiles) {
|
|
376
|
+
const row = await readJson(file, null).catch(() => null);
|
|
377
|
+
if (row && String(row.session_id || '') === sessionId)
|
|
378
|
+
reports.push({ file, row });
|
|
379
|
+
}
|
|
380
|
+
const foreignProcessReports = reports
|
|
381
|
+
.filter(({ row }) => !processReportMatchesProjectNamespace(row, input.projectHash))
|
|
382
|
+
.map(({ file }) => path.relative(input.agentRoot, file));
|
|
383
|
+
const pids = [...new Set([
|
|
384
|
+
Number(input.session?.pid || input.session?.process_id || input.session?.worker_pid || 0),
|
|
385
|
+
...reports.flatMap(({ row }) => [Number(row?.pid || row?.process_id || row?.worker_pid || 0), ...(Array.isArray(row?.child_process_ids) ? row.child_process_ids.map(Number) : [])])
|
|
386
|
+
].filter((pid) => Number.isSafeInteger(pid) && pid > 0))];
|
|
387
|
+
const livePids = pids.filter(processIsAlive);
|
|
388
|
+
const evidence = {
|
|
389
|
+
session_id: sessionId || null,
|
|
390
|
+
observed_status: String(input.session?.status || input.session?.lifecycle_state || ''),
|
|
391
|
+
last_activity_at: activity?.iso || null,
|
|
392
|
+
last_activity_source: activity?.source || null,
|
|
393
|
+
age_ms: ageMs,
|
|
394
|
+
stale_ms: input.staleMs,
|
|
395
|
+
stale,
|
|
396
|
+
process_report_count: reports.length,
|
|
397
|
+
process_reports: reports.map(({ file }) => path.relative(input.agentRoot, file)),
|
|
398
|
+
observed_pids: pids,
|
|
399
|
+
live_pids: livePids,
|
|
400
|
+
foreign_process_reports: foreignProcessReports,
|
|
401
|
+
artifact_dir: artifact?.relative || null,
|
|
402
|
+
checked_at: new Date(input.now).toISOString()
|
|
403
|
+
};
|
|
404
|
+
return {
|
|
405
|
+
stale,
|
|
406
|
+
session_id: sessionId,
|
|
407
|
+
artifact_dir: artifact,
|
|
408
|
+
foreign_process_reports: foreignProcessReports,
|
|
409
|
+
live_pids: livePids,
|
|
410
|
+
evidence
|
|
411
|
+
};
|
|
412
|
+
}
|
|
413
|
+
function latestSessionActivity(session) {
|
|
414
|
+
const candidates = [
|
|
415
|
+
['heartbeat_at', session?.heartbeat_at],
|
|
416
|
+
['last_heartbeat_at', session?.last_heartbeat_at],
|
|
417
|
+
['updated_at', session?.updated_at],
|
|
418
|
+
['opened_at', session?.opened_at]
|
|
419
|
+
].map(([source, value]) => ({ source: String(source), iso: String(value || ''), timestamp: Date.parse(String(value || '')) }))
|
|
420
|
+
.filter((row) => Number.isFinite(row.timestamp))
|
|
421
|
+
.sort((a, b) => b.timestamp - a.timestamp);
|
|
422
|
+
return candidates[0] || null;
|
|
423
|
+
}
|
|
424
|
+
function resolveSessionArtifactDir(agentRoot, session) {
|
|
425
|
+
const slotId = String(session?.slot_id || session?.worker_slot_id || '');
|
|
426
|
+
const generationIndex = Number(session?.generation_index);
|
|
427
|
+
const raw = String(session?.session_artifact_dir || (slotId && Number.isFinite(generationIndex) ? path.join('sessions', slotId, `gen-${generationIndex}`) : ''));
|
|
428
|
+
if (!raw || path.isAbsolute(raw) || raw.split(/[\\/]+/).includes('..'))
|
|
429
|
+
return null;
|
|
430
|
+
const resolved = path.resolve(agentRoot, raw);
|
|
431
|
+
const relative = path.relative(path.resolve(agentRoot), resolved);
|
|
432
|
+
if (!relative || relative.startsWith('..') || path.isAbsolute(relative))
|
|
433
|
+
return null;
|
|
434
|
+
return { absolute: resolved, relative: relative.split(path.sep).join('/') };
|
|
435
|
+
}
|
|
436
|
+
async function readLatestSessionRecord(agentRoot, fallback, artifact) {
|
|
437
|
+
const sessionKey = String(fallback?.session_key || fallback?.session_id || fallback?.agent_id || 'session').replace(/[^A-Za-z0-9._-]+/g, '_');
|
|
438
|
+
const shard = await readJson(path.join(agentRoot, 'sessions', `${sessionKey}.json`), null).catch(() => null);
|
|
439
|
+
if (shard)
|
|
440
|
+
return shard;
|
|
441
|
+
const artifactRecord = await readJson(path.join(artifact.absolute, 'agent-session-record.json'), null).catch(() => null);
|
|
442
|
+
return artifactRecord || fallback;
|
|
443
|
+
}
|
|
444
|
+
async function terminalizeStaleSession(agentRoot, session, assessment, missionId) {
|
|
445
|
+
const artifact = assessment.artifact_dir;
|
|
446
|
+
if (!artifact)
|
|
447
|
+
throw new Error('stale_session_artifact_path_invalid');
|
|
448
|
+
const sessionId = String(session.session_id || session.session_key || session.agent_id || '');
|
|
449
|
+
if (!sessionId)
|
|
450
|
+
throw new Error('stale_session_id_missing');
|
|
451
|
+
const closedAt = nowIso();
|
|
452
|
+
const evidencePath = path.join(artifact.relative, 'agent-stale-session-terminalization.json');
|
|
453
|
+
const closeReportPath = path.join(artifact.relative, 'agent-terminal-close-report.json');
|
|
454
|
+
const transactionId = `stale-${Date.now()}-${sessionId.slice(0, 80)}`;
|
|
455
|
+
const evidence = {
|
|
456
|
+
schema: 'sks.agent-stale-session-terminalization.v1',
|
|
457
|
+
transaction_id: transactionId,
|
|
458
|
+
mission_id: missionId,
|
|
459
|
+
session_id: sessionId,
|
|
460
|
+
status: 'timed_out',
|
|
461
|
+
generation_status: 'blocked',
|
|
462
|
+
reason: STALE_SESSION_REASON,
|
|
463
|
+
applied_at: closedAt,
|
|
464
|
+
assessment: assessment.evidence
|
|
465
|
+
};
|
|
466
|
+
const sessionKey = String(session.session_key || sessionId).replace(/[^A-Za-z0-9._-]+/g, '_');
|
|
467
|
+
const reasonedSession = {
|
|
468
|
+
...session,
|
|
469
|
+
session_key: sessionKey,
|
|
470
|
+
timed_out_at: closedAt,
|
|
471
|
+
cleanup_terminalized_at: closedAt,
|
|
472
|
+
terminal_reason: STALE_SESSION_REASON,
|
|
473
|
+
terminalization_evidence: evidencePath
|
|
474
|
+
};
|
|
475
|
+
const agent = {
|
|
476
|
+
...reasonedSession,
|
|
477
|
+
id: String(session.agent_id || session.id || sessionId),
|
|
478
|
+
session_id: sessionId,
|
|
479
|
+
session_generation_id: String(session.session_key || sessionId),
|
|
480
|
+
session_artifact_dir: artifact.relative
|
|
481
|
+
};
|
|
482
|
+
await writeJsonAtomic(path.join(agentRoot, evidencePath), evidence);
|
|
483
|
+
await writeJsonAtomic(path.join(agentRoot, 'sessions', `${sessionKey}.json`), { ...reasonedSession, schema: 'sks.agent-session-record.v1' });
|
|
484
|
+
await writeJsonAtomic(path.join(artifact.absolute, 'agent-session-record.json'), { ...reasonedSession, schema: 'sks.agent-session-record.v1' });
|
|
485
|
+
const closeReport = await closeAgentTerminalSession(agentRoot, agent, {
|
|
486
|
+
exitCode: 124,
|
|
487
|
+
status: 'timed_out',
|
|
488
|
+
...(session.slot_id ? { slotId: String(session.slot_id) } : {}),
|
|
489
|
+
...(Number.isFinite(Number(session.generation_index)) ? { generationIndex: Number(session.generation_index) } : {}),
|
|
490
|
+
requireGeneration: Boolean(session.slot_id && Number.isFinite(Number(session.generation_index)))
|
|
491
|
+
});
|
|
492
|
+
const terminalPath = path.join(artifact.absolute, 'agent-terminal-session.json');
|
|
493
|
+
const terminalRecord = await readJson(terminalPath, null);
|
|
494
|
+
await writeJsonAtomic(terminalPath, { ...terminalRecord, close_status: 'timed_out', close_reason: STALE_SESSION_REASON, terminalization_evidence: evidencePath });
|
|
495
|
+
await writeJsonAtomic(path.join(agentRoot, closeReportPath), { ...closeReport, status: 'timed_out', reason: STALE_SESSION_REASON, terminalization_evidence: evidencePath });
|
|
496
|
+
const generation = await closeAgentSessionGeneration(agentRoot, sessionId, { status: 'blocked', terminalCloseReportPath: closeReportPath });
|
|
497
|
+
await appendAgentLedgerEvent(agentRoot, {
|
|
498
|
+
agent_id: agent.id,
|
|
499
|
+
session_id: sessionId,
|
|
500
|
+
event_type: 'stale_session_terminalized',
|
|
501
|
+
payload: evidence
|
|
502
|
+
});
|
|
503
|
+
// closeAgentSession atomically replaces the session shard and then the
|
|
504
|
+
// canonical aggregate, so registry state is the final commit point.
|
|
505
|
+
const canonical = await closeAgentSession(agentRoot, agent, 'timed_out');
|
|
506
|
+
return {
|
|
507
|
+
session_id: sessionId,
|
|
508
|
+
status: canonical.status,
|
|
509
|
+
generation_status: generation?.status || null,
|
|
510
|
+
closed_at: canonical.closed_at,
|
|
511
|
+
transaction_id: transactionId,
|
|
512
|
+
canonical_registry: 'agent-sessions.json',
|
|
513
|
+
session_record: path.join(artifact.relative, 'agent-session-record.json'),
|
|
514
|
+
terminal_record: path.join(artifact.relative, 'agent-terminal-session.json'),
|
|
515
|
+
terminal_close_report: closeReportPath,
|
|
516
|
+
evidence: evidencePath
|
|
517
|
+
};
|
|
518
|
+
}
|
|
223
519
|
function buildCleanupProof(input) {
|
|
224
520
|
const byKind = (kind, status) => input.actions.filter((row) => row.kind === kind && (!status || row.status === status));
|
|
225
521
|
const failed = input.actions.filter((row) => row.status === 'failed');
|
|
@@ -234,6 +530,10 @@ function buildCleanupProof(input) {
|
|
|
234
530
|
apply: input.apply,
|
|
235
531
|
stale_processes_found: byKind('terminate_process').map((row) => row.target),
|
|
236
532
|
stale_processes_killed: byKind('terminate_process', 'applied').map((row) => row.target),
|
|
533
|
+
stale_sessions_found: byKind('terminalize_stale_session').map((row) => row.target),
|
|
534
|
+
stale_sessions_terminalization_planned: byKind('terminalize_stale_session', 'planned').map((row) => row.target),
|
|
535
|
+
stale_sessions_terminalized: byKind('terminalize_stale_session', 'applied').map((row) => row.target),
|
|
536
|
+
stale_session_terminalization_failures: byKind('terminalize_stale_session', 'failed').map((row) => row.target),
|
|
237
537
|
process_trees: byKind('terminate_process').map((row) => ({ target: row.target, tree: row.process_tree || [] })),
|
|
238
538
|
process_tree_count: byKind('terminate_process').filter((row) => (row.process_tree || []).length > 0).length,
|
|
239
539
|
sigterm_planned: input.actions.filter((row) => row.status === 'planned' && row.signal_sequence?.includes('SIGTERM')).map((row) => row.target),
|
|
@@ -255,6 +555,7 @@ function buildCleanupProof(input) {
|
|
|
255
555
|
skipped_active_sessions: [...new Set([...input.activeSessionIds, ...byKind('skip_active_session').map((row) => row.target)])].filter(Boolean),
|
|
256
556
|
skipped_foreign_namespace: byKind('skip_foreign_namespace').map((row) => row.target),
|
|
257
557
|
terminal_transcripts_preserved: byKind('archive_transcript_keep').map((row) => row.target),
|
|
558
|
+
session_cleanup: input.sessionCleanup,
|
|
258
559
|
action_count: input.actions.length,
|
|
259
560
|
applied_count: input.actions.filter((row) => row.status === 'applied').length,
|
|
260
561
|
failed_count: failed.length,
|
|
@@ -344,9 +645,10 @@ async function applyAction(input) {
|
|
|
344
645
|
}
|
|
345
646
|
async function staleLockFiles(lockDir, projectHash, now, staleMs) {
|
|
346
647
|
const out = [];
|
|
347
|
-
|
|
648
|
+
const ownedLockDir = await resolveOwnedNamespacePath(lockDir, projectHash);
|
|
649
|
+
if (!ownedLockDir)
|
|
348
650
|
return out;
|
|
349
|
-
for (const file of await listFiles(
|
|
651
|
+
for (const file of await listFiles(ownedLockDir)) {
|
|
350
652
|
const stat = await fsp.stat(file).catch(() => null);
|
|
351
653
|
if (stat && now - stat.mtimeMs > staleMs)
|
|
352
654
|
out.push(file);
|
|
@@ -369,22 +671,6 @@ async function listFiles(dir) {
|
|
|
369
671
|
}
|
|
370
672
|
return out;
|
|
371
673
|
}
|
|
372
|
-
function namespaceOwnsPath(candidate, projectHash) {
|
|
373
|
-
return Boolean(candidate && (!projectHash || candidate.includes(projectHash)));
|
|
374
|
-
}
|
|
375
|
-
function processReportInNamespace(report, projectHash) {
|
|
376
|
-
if (!projectHash)
|
|
377
|
-
return true;
|
|
378
|
-
const raw = JSON.stringify({
|
|
379
|
-
project_hash: report?.project_hash,
|
|
380
|
-
root_hash: report?.root_hash,
|
|
381
|
-
project_namespace: report?.project_namespace,
|
|
382
|
-
cwd: report?.cwd,
|
|
383
|
-
stdout_log: report?.stdout_log,
|
|
384
|
-
stderr_log: report?.stderr_log
|
|
385
|
-
});
|
|
386
|
-
return raw === '{}' || raw.includes(projectHash) || (!report?.project_hash && !report?.root_hash && !report?.project_namespace);
|
|
387
|
-
}
|
|
388
674
|
function processIsAlive(pid) {
|
|
389
675
|
try {
|
|
390
676
|
process.kill(pid, 0);
|
|
@@ -405,12 +691,19 @@ async function readProcessTree(rootPid) {
|
|
|
405
691
|
return { pid: Number(match[1]), ppid: Number(match[2]), command: match[3] || '' };
|
|
406
692
|
}).filter(Boolean);
|
|
407
693
|
const byParent = new Map();
|
|
694
|
+
const byPid = new Map();
|
|
408
695
|
for (const row of rows)
|
|
409
696
|
byParent.set(row.ppid, [...(byParent.get(row.ppid) || []), row]);
|
|
697
|
+
for (const row of rows)
|
|
698
|
+
byPid.set(row.pid, row);
|
|
410
699
|
const out = [];
|
|
700
|
+
const visited = new Set();
|
|
411
701
|
const visit = (pid) => {
|
|
412
|
-
|
|
413
|
-
|
|
702
|
+
if (visited.has(pid))
|
|
703
|
+
return;
|
|
704
|
+
visited.add(pid);
|
|
705
|
+
const current = byPid.get(pid);
|
|
706
|
+
if (current)
|
|
414
707
|
out.push(current);
|
|
415
708
|
for (const child of byParent.get(pid) || [])
|
|
416
709
|
visit(child.pid);
|
|
@@ -1,10 +1,29 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
2
|
import { nowIso, readJson, writeJsonAtomic } from '../fsx.js';
|
|
3
|
+
export const AGENT_TERMINAL_SESSION_STATUSES = new Set([
|
|
4
|
+
'blocked',
|
|
5
|
+
'cancelled',
|
|
6
|
+
'canceled',
|
|
7
|
+
'closed',
|
|
8
|
+
'complete',
|
|
9
|
+
'completed',
|
|
10
|
+
'done',
|
|
11
|
+
'exited',
|
|
12
|
+
'failed',
|
|
13
|
+
'killed',
|
|
14
|
+
'stopped',
|
|
15
|
+
'terminated',
|
|
16
|
+
'timed_out',
|
|
17
|
+
'timeout'
|
|
18
|
+
]);
|
|
19
|
+
export function isAgentTerminalSessionStatus(value) {
|
|
20
|
+
return AGENT_TERMINAL_SESSION_STATUSES.has(String(value || '').toLowerCase());
|
|
21
|
+
}
|
|
3
22
|
export async function writeAgentCleanupReport(root) {
|
|
4
23
|
const sessions = await readJson(path.join(root, 'agent-sessions.json'), { sessions: {} });
|
|
5
24
|
const rows = Object.values(sessions.sessions || {});
|
|
6
25
|
const closed = rows.filter((session) => String(session.status) === 'closed');
|
|
7
|
-
const terminal = rows.filter((session) =>
|
|
26
|
+
const terminal = rows.filter((session) => isAgentTerminalSessionStatus(session.status));
|
|
8
27
|
const report = {
|
|
9
28
|
schema: 'sks.agent-cleanup.v1',
|
|
10
29
|
generated_at: nowIso(),
|
|
@@ -51,6 +51,7 @@ export function parseAgentCommandArgs(command, args = []) {
|
|
|
51
51
|
const graceMs = Number(readOption(args, '--grace-ms', 750));
|
|
52
52
|
const killEscalation = hasFlag(args, '--kill-escalation') || !hasFlag(args, '--no-kill-escalation');
|
|
53
53
|
const codexApp = hasFlag(args, '--codex-app');
|
|
54
|
+
const legacyNativeRuntime = hasFlag(args, '--legacy-native-runtime');
|
|
54
55
|
const positionals = positionalArgs(rest, new Set(['--agents', '--target-active-slots', '--work-items', '--minimum-work-items', '--max-queue-expansion', '--concurrency', '--backend', '--route', '--mission', '--mission-id', '--agent', '--lane', '--stale-ms', '--grace-ms', '--profile', '--write-mode', '--max-write-agents', '--patch-entry-id', '--patch-entry', '--service-tier', '--zellij-session-name', '--worker-placement', '--zellij-visible-pane-cap', '--intake', '--agent-root', '--artifact-dir', '--result-path', '--heartbeat-path', '--patch-envelope-path', '--ollama-model', '--local-model-model', '--ollama-base-url', '--local-model-base-url']));
|
|
55
56
|
const missionDefault = action === 'run' || action === 'spawn' || action === 'plan' ? '' : 'latest';
|
|
56
57
|
const positionalMission = action === 'run' || action === 'spawn' || action === 'plan' ? '' : (positionals[0] || '');
|
|
@@ -58,8 +59,9 @@ export function parseAgentCommandArgs(command, args = []) {
|
|
|
58
59
|
const lane = String(readOption(args, '--agent', readOption(args, '--lane', '')));
|
|
59
60
|
const patchEntryId = String(readOption(args, '--patch-entry-id', readOption(args, '--patch-entry', '')));
|
|
60
61
|
const promptPositionals = positionalMission ? positionals.slice(1) : positionals;
|
|
62
|
+
const promptExplicit = promptPositionals.length > 0;
|
|
61
63
|
const prompt = promptPositionals.join(' ').trim() || 'Native agent run';
|
|
62
|
-
return { command, action, prompt, route, agents, targetActiveSlots, desiredWorkItemCount, minimumWorkItems, maxQueueExpansion, concurrency, backend, backendExplicit, mock, real, readonly, profile, writeMode, applyPatches, dryRunPatches, maxWriteAgents, fastMode, serviceTier, noFast, ollamaEnabled: useOllama && !noOllama, noOllama, ollamaModel, ollamaBaseUrl, zellijSessionName, zellijPaneWorker, workerPlacement, zellijVisiblePaneCap, apply, dryRun, drain, staleMs, graceMs, killEscalation, json, missionId, lane, codexApp, patchEntryId };
|
|
64
|
+
return { command, action, prompt, promptExplicit, route, agents, targetActiveSlots, desiredWorkItemCount, minimumWorkItems, maxQueueExpansion, concurrency, backend, backendExplicit, mock, real, readonly, profile, writeMode, applyPatches, dryRunPatches, maxWriteAgents, fastMode, serviceTier, noFast, ollamaEnabled: useOllama && !noOllama, noOllama, ollamaModel, ollamaBaseUrl, zellijSessionName, zellijPaneWorker, workerPlacement, zellijVisiblePaneCap, apply, dryRun, drain, staleMs, graceMs, killEscalation, json, missionId, lane, codexApp, patchEntryId, legacyNativeRuntime };
|
|
63
65
|
}
|
|
64
66
|
export function resolveZellijVisiblePaneCap(value = '', explicit = false) {
|
|
65
67
|
const requested = Number(value);
|