@hunter-harness/workflow-harness 0.2.42 → 0.2.44
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/harness/bundles/general/claude-code/.harness-build.json +1 -1
- package/harness/bundles/general/claude-code/contracts/build-profile-v3.schema.json +156 -1
- package/harness/bundles/general/claude-code/contracts/fixtures/managed-execution.json +341 -0
- package/harness/bundles/general/claude-code/contracts/process-identity.schema.json +132 -0
- package/harness/bundles/general/claude-code/contracts/run-session.schema.json +142 -0
- package/harness/bundles/general/claude-code/contracts/service-retirement-receipt.schema.json +85 -0
- package/harness/bundles/general/claude-code/contracts/service-session.schema.json +147 -0
- package/harness/bundles/general/claude-code/harness-archive/SKILL.md +1 -1
- package/harness/bundles/general/claude-code/harness-archive/reference.md +1 -0
- package/harness/bundles/general/claude-code/harness-archive/templates/render-summary.mjs +8 -0
- package/harness/bundles/general/claude-code/harness-archive/templates/summary-data-template.json +28 -0
- package/harness/bundles/general/claude-code/harness-codebase-map/SKILL.md +1 -1
- package/harness/bundles/general/claude-code/harness-knowledge-ingest/SKILL.md +1 -1
- package/harness/bundles/general/claude-code/harness-knowledge-query/SKILL.md +1 -1
- package/harness/bundles/general/claude-code/harness-plan/SKILL.md +1 -1
- package/harness/bundles/general/claude-code/harness-review/SKILL.md +1 -1
- package/harness/bundles/general/claude-code/harness-run/SKILL.md +1 -1
- package/harness/bundles/general/claude-code/harness-run/reference.md +6 -1
- package/harness/bundles/general/claude-code/harness-submit/SKILL.md +1 -1
- package/harness/bundles/general/claude-code/harness-submit/checklist.md +12 -0
- package/harness/bundles/general/claude-code/harness-sync/SKILL.md +1 -1
- package/harness/bundles/general/claude-code/harness-test/SKILL.md +8 -2
- package/harness/bundles/general/claude-code/protocols/execution-session-protocol.md +52 -0
- package/harness/bundles/general/claude-code/protocols/state-layout-protocol.md +24 -1
- package/harness/bundles/general/claude-code/protocols/verification-graph-protocol.md +6 -0
- package/harness/bundles/general/claude-code/scripts/harness_archive.py +271 -22
- package/harness/bundles/general/claude-code/scripts/harness_change.py +137 -2
- package/harness/bundles/general/claude-code/scripts/harness_efficiency.py +443 -0
- package/harness/bundles/general/claude-code/scripts/harness_environment.py +760 -46
- package/harness/bundles/general/claude-code/scripts/harness_execution_contracts.py +596 -0
- package/harness/bundles/general/claude-code/scripts/harness_fixback.py +742 -0
- package/harness/bundles/general/claude-code/scripts/harness_integration.py +289 -52
- package/harness/bundles/general/claude-code/scripts/harness_ledger.py +5 -0
- package/harness/bundles/general/claude-code/scripts/harness_orchestration.py +344 -0
- package/harness/bundles/general/claude-code/scripts/harness_process.py +1065 -0
- package/harness/bundles/general/claude-code/scripts/harness_profile.py +278 -4
- package/harness/bundles/general/claude-code/scripts/harness_runtime.py +1576 -3
- package/harness/bundles/general/claude-code/scripts/harness_service.py +1528 -177
- package/harness/bundles/general/claude-code/scripts/harness_test_runner.py +224 -146
- package/harness/bundles/general/claude-code/scripts/harness_verification.py +487 -8
- package/harness/bundles/general/codebuddy/.harness-build.json +1 -1
- package/harness/bundles/general/codebuddy/contracts/build-profile-v3.schema.json +156 -1
- package/harness/bundles/general/codebuddy/contracts/fixtures/managed-execution.json +341 -0
- package/harness/bundles/general/codebuddy/contracts/process-identity.schema.json +132 -0
- package/harness/bundles/general/codebuddy/contracts/run-session.schema.json +142 -0
- package/harness/bundles/general/codebuddy/contracts/service-retirement-receipt.schema.json +85 -0
- package/harness/bundles/general/codebuddy/contracts/service-session.schema.json +147 -0
- package/harness/bundles/general/codebuddy/harness-archive/SKILL.md +1 -1
- package/harness/bundles/general/codebuddy/harness-archive/reference.md +1 -0
- package/harness/bundles/general/codebuddy/harness-archive/templates/render-summary.mjs +8 -0
- package/harness/bundles/general/codebuddy/harness-archive/templates/summary-data-template.json +28 -0
- package/harness/bundles/general/codebuddy/harness-codebase-map/SKILL.md +1 -1
- package/harness/bundles/general/codebuddy/harness-knowledge-ingest/SKILL.md +1 -1
- package/harness/bundles/general/codebuddy/harness-knowledge-query/SKILL.md +1 -1
- package/harness/bundles/general/codebuddy/harness-plan/SKILL.md +1 -1
- package/harness/bundles/general/codebuddy/harness-review/SKILL.md +1 -1
- package/harness/bundles/general/codebuddy/harness-run/SKILL.md +1 -1
- package/harness/bundles/general/codebuddy/harness-run/reference.md +6 -1
- package/harness/bundles/general/codebuddy/harness-submit/SKILL.md +1 -1
- package/harness/bundles/general/codebuddy/harness-submit/checklist.md +12 -0
- package/harness/bundles/general/codebuddy/harness-sync/SKILL.md +1 -1
- package/harness/bundles/general/codebuddy/harness-test/SKILL.md +8 -2
- package/harness/bundles/general/codebuddy/protocols/execution-session-protocol.md +52 -0
- package/harness/bundles/general/codebuddy/protocols/state-layout-protocol.md +24 -1
- package/harness/bundles/general/codebuddy/protocols/verification-graph-protocol.md +6 -0
- package/harness/bundles/general/codebuddy/scripts/harness_archive.py +271 -22
- package/harness/bundles/general/codebuddy/scripts/harness_change.py +137 -2
- package/harness/bundles/general/codebuddy/scripts/harness_efficiency.py +443 -0
- package/harness/bundles/general/codebuddy/scripts/harness_environment.py +760 -46
- package/harness/bundles/general/codebuddy/scripts/harness_execution_contracts.py +596 -0
- package/harness/bundles/general/codebuddy/scripts/harness_fixback.py +742 -0
- package/harness/bundles/general/codebuddy/scripts/harness_integration.py +289 -52
- package/harness/bundles/general/codebuddy/scripts/harness_ledger.py +5 -0
- package/harness/bundles/general/codebuddy/scripts/harness_orchestration.py +344 -0
- package/harness/bundles/general/codebuddy/scripts/harness_process.py +1065 -0
- package/harness/bundles/general/codebuddy/scripts/harness_profile.py +278 -4
- package/harness/bundles/general/codebuddy/scripts/harness_runtime.py +1576 -3
- package/harness/bundles/general/codebuddy/scripts/harness_service.py +1528 -177
- package/harness/bundles/general/codebuddy/scripts/harness_test_runner.py +224 -146
- package/harness/bundles/general/codebuddy/scripts/harness_verification.py +487 -8
- package/harness/bundles/general/codex/.harness-build.json +1 -1
- package/harness/bundles/general/codex/contracts/build-profile-v3.schema.json +156 -1
- package/harness/bundles/general/codex/contracts/fixtures/managed-execution.json +341 -0
- package/harness/bundles/general/codex/contracts/process-identity.schema.json +132 -0
- package/harness/bundles/general/codex/contracts/run-session.schema.json +142 -0
- package/harness/bundles/general/codex/contracts/service-retirement-receipt.schema.json +85 -0
- package/harness/bundles/general/codex/contracts/service-session.schema.json +147 -0
- package/harness/bundles/general/codex/harness-archive/SKILL.md +1 -1
- package/harness/bundles/general/codex/harness-archive/reference.md +1 -0
- package/harness/bundles/general/codex/harness-archive/templates/render-summary.mjs +8 -0
- package/harness/bundles/general/codex/harness-archive/templates/summary-data-template.json +28 -0
- package/harness/bundles/general/codex/harness-codebase-map/SKILL.md +1 -1
- package/harness/bundles/general/codex/harness-knowledge-ingest/SKILL.md +1 -1
- package/harness/bundles/general/codex/harness-knowledge-query/SKILL.md +1 -1
- package/harness/bundles/general/codex/harness-plan/SKILL.md +1 -1
- package/harness/bundles/general/codex/harness-review/SKILL.md +1 -1
- package/harness/bundles/general/codex/harness-run/SKILL.md +1 -1
- package/harness/bundles/general/codex/harness-run/reference.md +6 -1
- package/harness/bundles/general/codex/harness-submit/SKILL.md +1 -1
- package/harness/bundles/general/codex/harness-submit/checklist.md +12 -0
- package/harness/bundles/general/codex/harness-sync/SKILL.md +1 -1
- package/harness/bundles/general/codex/harness-test/SKILL.md +8 -2
- package/harness/bundles/general/codex/protocols/execution-session-protocol.md +52 -0
- package/harness/bundles/general/codex/protocols/state-layout-protocol.md +24 -1
- package/harness/bundles/general/codex/protocols/verification-graph-protocol.md +6 -0
- package/harness/bundles/general/codex/scripts/harness_archive.py +271 -22
- package/harness/bundles/general/codex/scripts/harness_change.py +137 -2
- package/harness/bundles/general/codex/scripts/harness_efficiency.py +443 -0
- package/harness/bundles/general/codex/scripts/harness_environment.py +760 -46
- package/harness/bundles/general/codex/scripts/harness_execution_contracts.py +596 -0
- package/harness/bundles/general/codex/scripts/harness_fixback.py +742 -0
- package/harness/bundles/general/codex/scripts/harness_integration.py +289 -52
- package/harness/bundles/general/codex/scripts/harness_ledger.py +5 -0
- package/harness/bundles/general/codex/scripts/harness_orchestration.py +344 -0
- package/harness/bundles/general/codex/scripts/harness_process.py +1065 -0
- package/harness/bundles/general/codex/scripts/harness_profile.py +278 -4
- package/harness/bundles/general/codex/scripts/harness_runtime.py +1576 -3
- package/harness/bundles/general/codex/scripts/harness_service.py +1528 -177
- package/harness/bundles/general/codex/scripts/harness_test_runner.py +224 -146
- package/harness/bundles/general/codex/scripts/harness_verification.py +487 -8
- package/harness/bundles/general/cursor/.harness-build.json +1 -1
- package/harness/bundles/general/cursor/contracts/build-profile-v3.schema.json +156 -1
- package/harness/bundles/general/cursor/contracts/fixtures/managed-execution.json +341 -0
- package/harness/bundles/general/cursor/contracts/process-identity.schema.json +132 -0
- package/harness/bundles/general/cursor/contracts/run-session.schema.json +142 -0
- package/harness/bundles/general/cursor/contracts/service-retirement-receipt.schema.json +85 -0
- package/harness/bundles/general/cursor/contracts/service-session.schema.json +147 -0
- package/harness/bundles/general/cursor/harness-archive/SKILL.md +1 -1
- package/harness/bundles/general/cursor/harness-archive/reference.md +1 -0
- package/harness/bundles/general/cursor/harness-archive/templates/render-summary.mjs +8 -0
- package/harness/bundles/general/cursor/harness-archive/templates/summary-data-template.json +28 -0
- package/harness/bundles/general/cursor/harness-codebase-map/SKILL.md +1 -1
- package/harness/bundles/general/cursor/harness-knowledge-ingest/SKILL.md +1 -1
- package/harness/bundles/general/cursor/harness-knowledge-query/SKILL.md +1 -1
- package/harness/bundles/general/cursor/harness-plan/SKILL.md +1 -1
- package/harness/bundles/general/cursor/harness-review/SKILL.md +1 -1
- package/harness/bundles/general/cursor/harness-run/SKILL.md +1 -1
- package/harness/bundles/general/cursor/harness-run/reference.md +6 -1
- package/harness/bundles/general/cursor/harness-submit/SKILL.md +1 -1
- package/harness/bundles/general/cursor/harness-submit/checklist.md +12 -0
- package/harness/bundles/general/cursor/harness-sync/SKILL.md +1 -1
- package/harness/bundles/general/cursor/harness-test/SKILL.md +8 -2
- package/harness/bundles/general/cursor/protocols/execution-session-protocol.md +52 -0
- package/harness/bundles/general/cursor/protocols/state-layout-protocol.md +24 -1
- package/harness/bundles/general/cursor/protocols/verification-graph-protocol.md +6 -0
- package/harness/bundles/general/cursor/scripts/harness_archive.py +271 -22
- package/harness/bundles/general/cursor/scripts/harness_change.py +137 -2
- package/harness/bundles/general/cursor/scripts/harness_efficiency.py +443 -0
- package/harness/bundles/general/cursor/scripts/harness_environment.py +760 -46
- package/harness/bundles/general/cursor/scripts/harness_execution_contracts.py +596 -0
- package/harness/bundles/general/cursor/scripts/harness_fixback.py +742 -0
- package/harness/bundles/general/cursor/scripts/harness_integration.py +289 -52
- package/harness/bundles/general/cursor/scripts/harness_ledger.py +5 -0
- package/harness/bundles/general/cursor/scripts/harness_orchestration.py +344 -0
- package/harness/bundles/general/cursor/scripts/harness_process.py +1065 -0
- package/harness/bundles/general/cursor/scripts/harness_profile.py +278 -4
- package/harness/bundles/general/cursor/scripts/harness_runtime.py +1576 -3
- package/harness/bundles/general/cursor/scripts/harness_service.py +1528 -177
- package/harness/bundles/general/cursor/scripts/harness_test_runner.py +224 -146
- package/harness/bundles/general/cursor/scripts/harness_verification.py +487 -8
- package/harness/bundles/java/claude-code/.harness-build.json +1 -1
- package/harness/bundles/java/claude-code/contracts/build-profile-v3.schema.json +156 -1
- package/harness/bundles/java/claude-code/contracts/fixtures/managed-execution.json +341 -0
- package/harness/bundles/java/claude-code/contracts/process-identity.schema.json +132 -0
- package/harness/bundles/java/claude-code/contracts/run-session.schema.json +142 -0
- package/harness/bundles/java/claude-code/contracts/service-retirement-receipt.schema.json +85 -0
- package/harness/bundles/java/claude-code/contracts/service-session.schema.json +147 -0
- package/harness/bundles/java/claude-code/harness-apidoc/SKILL.md +1 -1
- package/harness/bundles/java/claude-code/harness-archive/SKILL.md +1 -1
- package/harness/bundles/java/claude-code/harness-archive/reference.md +1 -0
- package/harness/bundles/java/claude-code/harness-archive/templates/render-summary.mjs +8 -0
- package/harness/bundles/java/claude-code/harness-archive/templates/summary-data-template.json +28 -0
- package/harness/bundles/java/claude-code/harness-codebase-map/SKILL.md +1 -1
- package/harness/bundles/java/claude-code/harness-knowledge-ingest/SKILL.md +1 -1
- package/harness/bundles/java/claude-code/harness-knowledge-query/SKILL.md +1 -1
- package/harness/bundles/java/claude-code/harness-package/SKILL.md +1 -1
- package/harness/bundles/java/claude-code/harness-plan/SKILL.md +1 -1
- package/harness/bundles/java/claude-code/harness-review/SKILL.md +1 -1
- package/harness/bundles/java/claude-code/harness-run/SKILL.md +1 -1
- package/harness/bundles/java/claude-code/harness-submit/SKILL.md +1 -1
- package/harness/bundles/java/claude-code/harness-submit/checklist.md +12 -0
- package/harness/bundles/java/claude-code/harness-sync/SKILL.md +1 -1
- package/harness/bundles/java/claude-code/harness-test/SKILL.md +8 -2
- package/harness/bundles/java/claude-code/protocols/execution-session-protocol.md +52 -0
- package/harness/bundles/java/claude-code/protocols/state-layout-protocol.md +24 -1
- package/harness/bundles/java/claude-code/protocols/verification-graph-protocol.md +6 -0
- package/harness/bundles/java/claude-code/scripts/harness_archive.py +271 -22
- package/harness/bundles/java/claude-code/scripts/harness_change.py +137 -2
- package/harness/bundles/java/claude-code/scripts/harness_efficiency.py +443 -0
- package/harness/bundles/java/claude-code/scripts/harness_environment.py +760 -46
- package/harness/bundles/java/claude-code/scripts/harness_execution_contracts.py +596 -0
- package/harness/bundles/java/claude-code/scripts/harness_fixback.py +742 -0
- package/harness/bundles/java/claude-code/scripts/harness_integration.py +289 -52
- package/harness/bundles/java/claude-code/scripts/harness_ledger.py +5 -0
- package/harness/bundles/java/claude-code/scripts/harness_orchestration.py +344 -0
- package/harness/bundles/java/claude-code/scripts/harness_process.py +1065 -0
- package/harness/bundles/java/claude-code/scripts/harness_profile.py +278 -4
- package/harness/bundles/java/claude-code/scripts/harness_runtime.py +1576 -3
- package/harness/bundles/java/claude-code/scripts/harness_service.py +1528 -177
- package/harness/bundles/java/claude-code/scripts/harness_test_runner.py +224 -146
- package/harness/bundles/java/claude-code/scripts/harness_verification.py +487 -8
- package/harness/bundles/java/codebuddy/.harness-build.json +1 -1
- package/harness/bundles/java/codebuddy/contracts/build-profile-v3.schema.json +156 -1
- package/harness/bundles/java/codebuddy/contracts/fixtures/managed-execution.json +341 -0
- package/harness/bundles/java/codebuddy/contracts/process-identity.schema.json +132 -0
- package/harness/bundles/java/codebuddy/contracts/run-session.schema.json +142 -0
- package/harness/bundles/java/codebuddy/contracts/service-retirement-receipt.schema.json +85 -0
- package/harness/bundles/java/codebuddy/contracts/service-session.schema.json +147 -0
- package/harness/bundles/java/codebuddy/harness-apidoc/SKILL.md +1 -1
- package/harness/bundles/java/codebuddy/harness-archive/SKILL.md +1 -1
- package/harness/bundles/java/codebuddy/harness-archive/reference.md +1 -0
- package/harness/bundles/java/codebuddy/harness-archive/templates/render-summary.mjs +8 -0
- package/harness/bundles/java/codebuddy/harness-archive/templates/summary-data-template.json +28 -0
- package/harness/bundles/java/codebuddy/harness-codebase-map/SKILL.md +1 -1
- package/harness/bundles/java/codebuddy/harness-knowledge-ingest/SKILL.md +1 -1
- package/harness/bundles/java/codebuddy/harness-knowledge-query/SKILL.md +1 -1
- package/harness/bundles/java/codebuddy/harness-package/SKILL.md +1 -1
- package/harness/bundles/java/codebuddy/harness-plan/SKILL.md +1 -1
- package/harness/bundles/java/codebuddy/harness-review/SKILL.md +1 -1
- package/harness/bundles/java/codebuddy/harness-run/SKILL.md +1 -1
- package/harness/bundles/java/codebuddy/harness-submit/SKILL.md +1 -1
- package/harness/bundles/java/codebuddy/harness-submit/checklist.md +12 -0
- package/harness/bundles/java/codebuddy/harness-sync/SKILL.md +1 -1
- package/harness/bundles/java/codebuddy/harness-test/SKILL.md +8 -2
- package/harness/bundles/java/codebuddy/protocols/execution-session-protocol.md +52 -0
- package/harness/bundles/java/codebuddy/protocols/state-layout-protocol.md +24 -1
- package/harness/bundles/java/codebuddy/protocols/verification-graph-protocol.md +6 -0
- package/harness/bundles/java/codebuddy/scripts/harness_archive.py +271 -22
- package/harness/bundles/java/codebuddy/scripts/harness_change.py +137 -2
- package/harness/bundles/java/codebuddy/scripts/harness_efficiency.py +443 -0
- package/harness/bundles/java/codebuddy/scripts/harness_environment.py +760 -46
- package/harness/bundles/java/codebuddy/scripts/harness_execution_contracts.py +596 -0
- package/harness/bundles/java/codebuddy/scripts/harness_fixback.py +742 -0
- package/harness/bundles/java/codebuddy/scripts/harness_integration.py +289 -52
- package/harness/bundles/java/codebuddy/scripts/harness_ledger.py +5 -0
- package/harness/bundles/java/codebuddy/scripts/harness_orchestration.py +344 -0
- package/harness/bundles/java/codebuddy/scripts/harness_process.py +1065 -0
- package/harness/bundles/java/codebuddy/scripts/harness_profile.py +278 -4
- package/harness/bundles/java/codebuddy/scripts/harness_runtime.py +1576 -3
- package/harness/bundles/java/codebuddy/scripts/harness_service.py +1528 -177
- package/harness/bundles/java/codebuddy/scripts/harness_test_runner.py +224 -146
- package/harness/bundles/java/codebuddy/scripts/harness_verification.py +487 -8
- package/harness/bundles/java/codex/.harness-build.json +1 -1
- package/harness/bundles/java/codex/contracts/build-profile-v3.schema.json +156 -1
- package/harness/bundles/java/codex/contracts/fixtures/managed-execution.json +341 -0
- package/harness/bundles/java/codex/contracts/process-identity.schema.json +132 -0
- package/harness/bundles/java/codex/contracts/run-session.schema.json +142 -0
- package/harness/bundles/java/codex/contracts/service-retirement-receipt.schema.json +85 -0
- package/harness/bundles/java/codex/contracts/service-session.schema.json +147 -0
- package/harness/bundles/java/codex/harness-apidoc/SKILL.md +1 -1
- package/harness/bundles/java/codex/harness-archive/SKILL.md +1 -1
- package/harness/bundles/java/codex/harness-archive/reference.md +1 -0
- package/harness/bundles/java/codex/harness-archive/templates/render-summary.mjs +8 -0
- package/harness/bundles/java/codex/harness-archive/templates/summary-data-template.json +28 -0
- package/harness/bundles/java/codex/harness-codebase-map/SKILL.md +1 -1
- package/harness/bundles/java/codex/harness-knowledge-ingest/SKILL.md +1 -1
- package/harness/bundles/java/codex/harness-knowledge-query/SKILL.md +1 -1
- package/harness/bundles/java/codex/harness-package/SKILL.md +1 -1
- package/harness/bundles/java/codex/harness-plan/SKILL.md +1 -1
- package/harness/bundles/java/codex/harness-review/SKILL.md +1 -1
- package/harness/bundles/java/codex/harness-run/SKILL.md +1 -1
- package/harness/bundles/java/codex/harness-submit/SKILL.md +1 -1
- package/harness/bundles/java/codex/harness-submit/checklist.md +12 -0
- package/harness/bundles/java/codex/harness-sync/SKILL.md +1 -1
- package/harness/bundles/java/codex/harness-test/SKILL.md +8 -2
- package/harness/bundles/java/codex/protocols/execution-session-protocol.md +52 -0
- package/harness/bundles/java/codex/protocols/state-layout-protocol.md +24 -1
- package/harness/bundles/java/codex/protocols/verification-graph-protocol.md +6 -0
- package/harness/bundles/java/codex/scripts/harness_archive.py +271 -22
- package/harness/bundles/java/codex/scripts/harness_change.py +137 -2
- package/harness/bundles/java/codex/scripts/harness_efficiency.py +443 -0
- package/harness/bundles/java/codex/scripts/harness_environment.py +760 -46
- package/harness/bundles/java/codex/scripts/harness_execution_contracts.py +596 -0
- package/harness/bundles/java/codex/scripts/harness_fixback.py +742 -0
- package/harness/bundles/java/codex/scripts/harness_integration.py +289 -52
- package/harness/bundles/java/codex/scripts/harness_ledger.py +5 -0
- package/harness/bundles/java/codex/scripts/harness_orchestration.py +344 -0
- package/harness/bundles/java/codex/scripts/harness_process.py +1065 -0
- package/harness/bundles/java/codex/scripts/harness_profile.py +278 -4
- package/harness/bundles/java/codex/scripts/harness_runtime.py +1576 -3
- package/harness/bundles/java/codex/scripts/harness_service.py +1528 -177
- package/harness/bundles/java/codex/scripts/harness_test_runner.py +224 -146
- package/harness/bundles/java/codex/scripts/harness_verification.py +487 -8
- package/harness/bundles/java/cursor/.harness-build.json +1 -1
- package/harness/bundles/java/cursor/contracts/build-profile-v3.schema.json +156 -1
- package/harness/bundles/java/cursor/contracts/fixtures/managed-execution.json +341 -0
- package/harness/bundles/java/cursor/contracts/process-identity.schema.json +132 -0
- package/harness/bundles/java/cursor/contracts/run-session.schema.json +142 -0
- package/harness/bundles/java/cursor/contracts/service-retirement-receipt.schema.json +85 -0
- package/harness/bundles/java/cursor/contracts/service-session.schema.json +147 -0
- package/harness/bundles/java/cursor/harness-apidoc/SKILL.md +1 -1
- package/harness/bundles/java/cursor/harness-archive/SKILL.md +1 -1
- package/harness/bundles/java/cursor/harness-archive/reference.md +1 -0
- package/harness/bundles/java/cursor/harness-archive/templates/render-summary.mjs +8 -0
- package/harness/bundles/java/cursor/harness-archive/templates/summary-data-template.json +28 -0
- package/harness/bundles/java/cursor/harness-codebase-map/SKILL.md +1 -1
- package/harness/bundles/java/cursor/harness-knowledge-ingest/SKILL.md +1 -1
- package/harness/bundles/java/cursor/harness-knowledge-query/SKILL.md +1 -1
- package/harness/bundles/java/cursor/harness-package/SKILL.md +1 -1
- package/harness/bundles/java/cursor/harness-plan/SKILL.md +1 -1
- package/harness/bundles/java/cursor/harness-review/SKILL.md +1 -1
- package/harness/bundles/java/cursor/harness-run/SKILL.md +1 -1
- package/harness/bundles/java/cursor/harness-submit/SKILL.md +1 -1
- package/harness/bundles/java/cursor/harness-submit/checklist.md +12 -0
- package/harness/bundles/java/cursor/harness-sync/SKILL.md +1 -1
- package/harness/bundles/java/cursor/harness-test/SKILL.md +8 -2
- package/harness/bundles/java/cursor/protocols/execution-session-protocol.md +52 -0
- package/harness/bundles/java/cursor/protocols/state-layout-protocol.md +24 -1
- package/harness/bundles/java/cursor/protocols/verification-graph-protocol.md +6 -0
- package/harness/bundles/java/cursor/scripts/harness_archive.py +271 -22
- package/harness/bundles/java/cursor/scripts/harness_change.py +137 -2
- package/harness/bundles/java/cursor/scripts/harness_efficiency.py +443 -0
- package/harness/bundles/java/cursor/scripts/harness_environment.py +760 -46
- package/harness/bundles/java/cursor/scripts/harness_execution_contracts.py +596 -0
- package/harness/bundles/java/cursor/scripts/harness_fixback.py +742 -0
- package/harness/bundles/java/cursor/scripts/harness_integration.py +289 -52
- package/harness/bundles/java/cursor/scripts/harness_ledger.py +5 -0
- package/harness/bundles/java/cursor/scripts/harness_orchestration.py +344 -0
- package/harness/bundles/java/cursor/scripts/harness_process.py +1065 -0
- package/harness/bundles/java/cursor/scripts/harness_profile.py +278 -4
- package/harness/bundles/java/cursor/scripts/harness_runtime.py +1576 -3
- package/harness/bundles/java/cursor/scripts/harness_service.py +1528 -177
- package/harness/bundles/java/cursor/scripts/harness_test_runner.py +224 -146
- package/harness/bundles/java/cursor/scripts/harness_verification.py +487 -8
- package/harness/manifests/general/claude-code.json +76 -31
- package/harness/manifests/general/codebuddy.json +76 -31
- package/harness/manifests/general/codex.json +76 -31
- package/harness/manifests/general/cursor.json +76 -31
- package/harness/manifests/java/claude-code.json +77 -32
- package/harness/manifests/java/codebuddy.json +77 -32
- package/harness/manifests/java/codex.json +77 -32
- package/harness/manifests/java/cursor.json +77 -32
- package/hunter-workflow-family.json +6 -4
- package/package.json +1 -1
|
@@ -29,6 +29,7 @@ if str(SCRIPT_DIR) not in sys.path:
|
|
|
29
29
|
sys.path.insert(0, str(SCRIPT_DIR))
|
|
30
30
|
|
|
31
31
|
import harness_environment as henv
|
|
32
|
+
import harness_process as hprocess
|
|
32
33
|
|
|
33
34
|
DEFAULT_MAX_WORKERS = 2
|
|
34
35
|
DEFAULT_TIMEOUT_SECONDS = 300.0
|
|
@@ -37,7 +38,10 @@ DEFAULT_RESOURCE_MODULES = (
|
|
|
37
38
|
"test_harness_integration.py",
|
|
38
39
|
"test_harness_service.py",
|
|
39
40
|
)
|
|
40
|
-
DEFAULT_DETACHED_SERVICE_MODULES = (
|
|
41
|
+
DEFAULT_DETACHED_SERVICE_MODULES = (
|
|
42
|
+
"test_harness_service.py",
|
|
43
|
+
"test_harness_runtime.py",
|
|
44
|
+
)
|
|
41
45
|
TRUTHY_VALUES = frozenset({"1", "true", "yes", "on"})
|
|
42
46
|
|
|
43
47
|
|
|
@@ -136,35 +140,30 @@ def build_unittest_plan(
|
|
|
136
140
|
|
|
137
141
|
|
|
138
142
|
def _pid_is_running(pid: int) -> bool:
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
kernel32 = ctypes.windll.kernel32
|
|
146
|
-
kernel32.OpenProcess.restype = ctypes.c_void_p
|
|
147
|
-
handle = kernel32.OpenProcess(
|
|
148
|
-
process_query_limited_information,
|
|
149
|
-
False,
|
|
150
|
-
pid,
|
|
151
|
-
)
|
|
152
|
-
if not handle:
|
|
153
|
-
return False
|
|
154
|
-
try:
|
|
155
|
-
exit_code = ctypes.c_uint32()
|
|
156
|
-
if not kernel32.GetExitCodeProcess(handle, ctypes.byref(exit_code)):
|
|
157
|
-
return False
|
|
158
|
-
return int(exit_code.value) == 259
|
|
159
|
-
finally:
|
|
160
|
-
kernel32.CloseHandle(ctypes.c_void_p(handle))
|
|
143
|
+
return hprocess.is_pid_alive(pid)
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
def _verify_recorded_owner(owner: Mapping[str, object]) -> bool | None:
|
|
147
|
+
"""Verify a legacy lock owner through the canonical process provider."""
|
|
148
|
+
|
|
161
149
|
try:
|
|
162
|
-
|
|
163
|
-
except
|
|
164
|
-
return
|
|
165
|
-
|
|
150
|
+
pid = int(owner.get("pid") or 0)
|
|
151
|
+
except (TypeError, ValueError):
|
|
152
|
+
return None
|
|
153
|
+
observed = hprocess.observe_process_identity(pid)
|
|
154
|
+
decision = hprocess.verify_process_identity(
|
|
155
|
+
{
|
|
156
|
+
"pid": pid,
|
|
157
|
+
"createdAt": owner.get("startedAt"),
|
|
158
|
+
"executable": owner.get("executable"),
|
|
159
|
+
},
|
|
160
|
+
observed,
|
|
161
|
+
)
|
|
162
|
+
if decision.get("ok") is True:
|
|
166
163
|
return True
|
|
167
|
-
|
|
164
|
+
if decision.get("reasonCode") == "IDENTITY_UNVERIFIABLE":
|
|
165
|
+
return None
|
|
166
|
+
return False
|
|
168
167
|
|
|
169
168
|
|
|
170
169
|
def classify_test_lock(path: Path) -> dict[str, object]:
|
|
@@ -189,16 +188,17 @@ def classify_test_lock(path: Path) -> dict[str, object]:
|
|
|
189
188
|
"path": str(path),
|
|
190
189
|
"token": payload.get("token"),
|
|
191
190
|
}
|
|
192
|
-
|
|
193
|
-
return {
|
|
194
|
-
"classification": "ACTIVE",
|
|
195
|
-
"path": str(path),
|
|
196
|
-
"token": payload.get("token"),
|
|
197
|
-
"owner": owner,
|
|
198
|
-
}
|
|
191
|
+
unexpired = time.time() < float(expires)
|
|
199
192
|
if not isinstance(owner, dict) or any(
|
|
200
193
|
not owner.get(field) for field in ("pid", "executable", "startedAt")
|
|
201
194
|
):
|
|
195
|
+
if unexpired:
|
|
196
|
+
return {
|
|
197
|
+
"classification": "ACTIVE",
|
|
198
|
+
"path": str(path),
|
|
199
|
+
"token": payload.get("token"),
|
|
200
|
+
"owner": owner,
|
|
201
|
+
}
|
|
202
202
|
return {
|
|
203
203
|
"classification": "OWNER_IDENTITY_INCOMPLETE",
|
|
204
204
|
"path": str(path),
|
|
@@ -207,6 +207,13 @@ def classify_test_lock(path: Path) -> dict[str, object]:
|
|
|
207
207
|
try:
|
|
208
208
|
owner_pid = int(owner["pid"])
|
|
209
209
|
except (TypeError, ValueError):
|
|
210
|
+
if unexpired:
|
|
211
|
+
return {
|
|
212
|
+
"classification": "ACTIVE",
|
|
213
|
+
"path": str(path),
|
|
214
|
+
"token": payload.get("token"),
|
|
215
|
+
"owner": owner,
|
|
216
|
+
}
|
|
210
217
|
return {
|
|
211
218
|
"classification": "OWNER_IDENTITY_INCOMPLETE",
|
|
212
219
|
"path": str(path),
|
|
@@ -219,13 +226,14 @@ def classify_test_lock(path: Path) -> dict[str, object]:
|
|
|
219
226
|
"token": payload.get("token"),
|
|
220
227
|
"owner": owner,
|
|
221
228
|
}
|
|
222
|
-
|
|
223
|
-
{
|
|
224
|
-
"
|
|
225
|
-
"
|
|
226
|
-
"
|
|
229
|
+
if unexpired:
|
|
230
|
+
return {
|
|
231
|
+
"classification": "ACTIVE",
|
|
232
|
+
"path": str(path),
|
|
233
|
+
"token": payload.get("token"),
|
|
234
|
+
"owner": owner,
|
|
227
235
|
}
|
|
228
|
-
)
|
|
236
|
+
verified = _verify_recorded_owner(owner)
|
|
229
237
|
classification = (
|
|
230
238
|
"OWNER_ACTIVE"
|
|
231
239
|
if verified is True
|
|
@@ -244,7 +252,7 @@ def classify_test_lock(path: Path) -> dict[str, object]:
|
|
|
244
252
|
|
|
245
253
|
|
|
246
254
|
def reap_test_lock(path: Path) -> dict[str, object]:
|
|
247
|
-
"""Reap only
|
|
255
|
+
"""Reap only a lock whose exact recorded owner is definitely absent."""
|
|
248
256
|
classification = classify_test_lock(path)
|
|
249
257
|
reaped = classification.get("classification") == "RECLAIMABLE"
|
|
250
258
|
if reaped:
|
|
@@ -330,9 +338,9 @@ class TestRunLock:
|
|
|
330
338
|
)
|
|
331
339
|
else:
|
|
332
340
|
now = time.time()
|
|
333
|
-
created =
|
|
341
|
+
created = hprocess.get_process_create_time(os.getpid())
|
|
334
342
|
executable = (
|
|
335
|
-
|
|
343
|
+
hprocess.get_process_executable(os.getpid())
|
|
336
344
|
or str(Path(sys.executable).resolve())
|
|
337
345
|
)
|
|
338
346
|
payload = {
|
|
@@ -484,6 +492,20 @@ class _WindowsBasicAccountingInformation(ctypes.Structure):
|
|
|
484
492
|
]
|
|
485
493
|
|
|
486
494
|
|
|
495
|
+
_WINDOWS_JOB_PROCESS_ID_CAPACITY = 4096
|
|
496
|
+
|
|
497
|
+
|
|
498
|
+
class _WindowsJobProcessIdList(ctypes.Structure):
|
|
499
|
+
_fields_ = [
|
|
500
|
+
("NumberOfAssignedProcesses", ctypes.c_uint32),
|
|
501
|
+
("NumberOfProcessIdsInList", ctypes.c_uint32),
|
|
502
|
+
(
|
|
503
|
+
"ProcessIdList",
|
|
504
|
+
ctypes.c_size_t * _WINDOWS_JOB_PROCESS_ID_CAPACITY,
|
|
505
|
+
),
|
|
506
|
+
]
|
|
507
|
+
|
|
508
|
+
|
|
487
509
|
class _WindowsKillOnCloseJob:
|
|
488
510
|
"""Best-effort Windows Job Object that kills descendants when closed."""
|
|
489
511
|
|
|
@@ -491,9 +513,11 @@ class _WindowsKillOnCloseJob:
|
|
|
491
513
|
_JOB_OBJECT_LIMIT_BREAKAWAY_OK = 0x00000800
|
|
492
514
|
_JOB_OBJECT_EXTENDED_LIMIT_INFORMATION_CLASS = 9
|
|
493
515
|
_JOB_OBJECT_BASIC_ACCOUNTING_INFORMATION_CLASS = 1
|
|
516
|
+
_JOB_OBJECT_BASIC_PROCESS_ID_LIST_CLASS = 3
|
|
494
517
|
|
|
495
|
-
def __init__(self) -> None:
|
|
518
|
+
def __init__(self, *, allow_breakaway: bool = False) -> None:
|
|
496
519
|
self.handle: int | None = None
|
|
520
|
+
self.allow_breakaway = allow_breakaway
|
|
497
521
|
|
|
498
522
|
def assign(self, process: subprocess.Popen[object]) -> bool:
|
|
499
523
|
if os.name != "nt":
|
|
@@ -506,7 +530,11 @@ class _WindowsKillOnCloseJob:
|
|
|
506
530
|
info = _WindowsExtendedLimitInformation()
|
|
507
531
|
info.BasicLimitInformation.LimitFlags = (
|
|
508
532
|
self._JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE
|
|
509
|
-
|
|
|
533
|
+
| (
|
|
534
|
+
self._JOB_OBJECT_LIMIT_BREAKAWAY_OK
|
|
535
|
+
if self.allow_breakaway
|
|
536
|
+
else 0
|
|
537
|
+
)
|
|
510
538
|
)
|
|
511
539
|
configured = kernel32.SetInformationJobObject(
|
|
512
540
|
ctypes.c_void_p(handle),
|
|
@@ -535,26 +563,73 @@ class _WindowsKillOnCloseJob:
|
|
|
535
563
|
ctypes.windll.kernel32.CloseHandle(ctypes.c_void_p(self.handle))
|
|
536
564
|
self.handle = None
|
|
537
565
|
|
|
538
|
-
def terminate_and_wait(self, timeout_seconds: float = 5.0) ->
|
|
566
|
+
def terminate_and_wait(self, timeout_seconds: float = 5.0) -> bool:
|
|
539
567
|
if self.handle is None:
|
|
540
|
-
return
|
|
568
|
+
return True
|
|
541
569
|
kernel32 = ctypes.windll.kernel32
|
|
542
570
|
handle = ctypes.c_void_p(self.handle)
|
|
543
|
-
kernel32.TerminateJobObject(handle, 1)
|
|
544
571
|
deadline = time.monotonic() + max(0.0, timeout_seconds)
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
572
|
+
process_ids = _WindowsJobProcessIdList()
|
|
573
|
+
process_list_queried = kernel32.QueryInformationJobObject(
|
|
574
|
+
handle,
|
|
575
|
+
self._JOB_OBJECT_BASIC_PROCESS_ID_LIST_CLASS,
|
|
576
|
+
ctypes.byref(process_ids),
|
|
577
|
+
ctypes.sizeof(process_ids),
|
|
578
|
+
None,
|
|
579
|
+
)
|
|
580
|
+
process_list_complete = bool(
|
|
581
|
+
process_list_queried
|
|
582
|
+
and process_ids.NumberOfAssignedProcesses
|
|
583
|
+
== process_ids.NumberOfProcessIdsInList
|
|
584
|
+
)
|
|
585
|
+
kernel32.OpenProcess.restype = ctypes.c_void_p
|
|
586
|
+
process_handles: list[int] = []
|
|
587
|
+
if process_list_complete:
|
|
588
|
+
for index in range(int(process_ids.NumberOfProcessIdsInList)):
|
|
589
|
+
process_handle = kernel32.OpenProcess(
|
|
590
|
+
0x00100000,
|
|
591
|
+
False,
|
|
592
|
+
int(process_ids.ProcessIdList[index]),
|
|
593
|
+
)
|
|
594
|
+
if process_handle:
|
|
595
|
+
process_handles.append(int(process_handle))
|
|
596
|
+
else:
|
|
597
|
+
process_list_complete = False
|
|
598
|
+
terminated = bool(kernel32.TerminateJobObject(handle, 1))
|
|
599
|
+
handles_signaled = process_list_complete
|
|
600
|
+
try:
|
|
601
|
+
for process_handle in process_handles:
|
|
602
|
+
remaining_ms = max(
|
|
603
|
+
0,
|
|
604
|
+
int((deadline - time.monotonic()) * 1000),
|
|
605
|
+
)
|
|
606
|
+
if (
|
|
607
|
+
kernel32.WaitForSingleObject(
|
|
608
|
+
ctypes.c_void_p(process_handle),
|
|
609
|
+
remaining_ms,
|
|
610
|
+
)
|
|
611
|
+
!= 0
|
|
612
|
+
):
|
|
613
|
+
handles_signaled = False
|
|
614
|
+
accounting_drained = False
|
|
615
|
+
while time.monotonic() < deadline:
|
|
616
|
+
accounting = _WindowsBasicAccountingInformation()
|
|
617
|
+
queried = kernel32.QueryInformationJobObject(
|
|
618
|
+
handle,
|
|
619
|
+
self._JOB_OBJECT_BASIC_ACCOUNTING_INFORMATION_CLASS,
|
|
620
|
+
ctypes.byref(accounting),
|
|
621
|
+
ctypes.sizeof(accounting),
|
|
622
|
+
None,
|
|
623
|
+
)
|
|
624
|
+
if queried and accounting.ActiveProcesses == 0:
|
|
625
|
+
accounting_drained = True
|
|
626
|
+
break
|
|
627
|
+
time.sleep(0.02)
|
|
628
|
+
finally:
|
|
629
|
+
for process_handle in process_handles:
|
|
630
|
+
kernel32.CloseHandle(ctypes.c_void_p(process_handle))
|
|
631
|
+
self.close()
|
|
632
|
+
return terminated and handles_signaled and accounting_drained
|
|
558
633
|
|
|
559
634
|
|
|
560
635
|
class _WindowsProcessEntry(ctypes.Structure):
|
|
@@ -709,50 +784,22 @@ def _terminate_process_tree(
|
|
|
709
784
|
*,
|
|
710
785
|
windows_job: _WindowsKillOnCloseJob | None,
|
|
711
786
|
) -> None:
|
|
787
|
+
"""Legacy seam retained for callers; ownership must be provider-backed."""
|
|
788
|
+
|
|
712
789
|
if windows_job is not None and windows_job.handle is not None:
|
|
713
790
|
windows_job.terminate_and_wait()
|
|
714
|
-
elif os.name == "nt":
|
|
715
|
-
subprocess.run(
|
|
716
|
-
["taskkill", "/PID", str(process.pid), "/T", "/F"],
|
|
717
|
-
stdout=subprocess.DEVNULL,
|
|
718
|
-
stderr=subprocess.DEVNULL,
|
|
719
|
-
check=False,
|
|
720
|
-
timeout=10,
|
|
721
|
-
creationflags=getattr(subprocess, "CREATE_NO_WINDOW", 0),
|
|
722
|
-
)
|
|
723
791
|
else:
|
|
724
|
-
|
|
725
|
-
os.killpg(process.pid, signal.SIGTERM)
|
|
726
|
-
except ProcessLookupError:
|
|
727
|
-
pass
|
|
728
|
-
try:
|
|
729
|
-
process.wait(timeout=2)
|
|
730
|
-
except subprocess.TimeoutExpired:
|
|
731
|
-
try:
|
|
732
|
-
os.killpg(process.pid, signal.SIGKILL)
|
|
733
|
-
except ProcessLookupError:
|
|
734
|
-
pass
|
|
735
|
-
if process.poll() is None:
|
|
736
|
-
process.kill()
|
|
737
|
-
try:
|
|
738
|
-
process.wait(timeout=5)
|
|
739
|
-
except subprocess.TimeoutExpired:
|
|
740
|
-
pass
|
|
792
|
+
raise RuntimeError("PROCESS_OWNERSHIP_REQUIRED")
|
|
741
793
|
|
|
742
794
|
|
|
743
795
|
def _cleanup_descendants_after_success(
|
|
744
796
|
process: subprocess.Popen[object],
|
|
745
797
|
*,
|
|
746
798
|
windows_job: _WindowsKillOnCloseJob | None,
|
|
747
|
-
) ->
|
|
799
|
+
) -> bool:
|
|
748
800
|
if windows_job is not None and windows_job.handle is not None:
|
|
749
|
-
windows_job.terminate_and_wait()
|
|
750
|
-
|
|
751
|
-
if os.name != "nt":
|
|
752
|
-
try:
|
|
753
|
-
os.killpg(process.pid, signal.SIGTERM)
|
|
754
|
-
except ProcessLookupError:
|
|
755
|
-
pass
|
|
801
|
+
return windows_job.terminate_and_wait()
|
|
802
|
+
return False
|
|
756
803
|
|
|
757
804
|
|
|
758
805
|
def run_managed_command(
|
|
@@ -774,74 +821,84 @@ def run_managed_command(
|
|
|
774
821
|
child_env.setdefault("PYTHONUNBUFFERED", "1")
|
|
775
822
|
lower_process_priority()
|
|
776
823
|
|
|
777
|
-
popen_kwargs: dict[str, object] = {
|
|
778
|
-
"cwd": str(Path(cwd).resolve()),
|
|
779
|
-
"env": child_env,
|
|
780
|
-
"shell": False,
|
|
781
|
-
}
|
|
782
824
|
output_stream = tempfile.TemporaryFile(mode="w+b") if capture_output else None
|
|
783
|
-
if output_stream is not None:
|
|
784
|
-
popen_kwargs["stdout"] = output_stream
|
|
785
|
-
popen_kwargs["stderr"] = subprocess.STDOUT
|
|
786
|
-
if os.name == "nt":
|
|
787
|
-
popen_kwargs["creationflags"] = getattr(
|
|
788
|
-
subprocess,
|
|
789
|
-
"CREATE_NEW_PROCESS_GROUP",
|
|
790
|
-
0,
|
|
791
|
-
)
|
|
792
|
-
else:
|
|
793
|
-
popen_kwargs["start_new_session"] = True
|
|
794
|
-
|
|
795
825
|
started = time.monotonic()
|
|
826
|
+
spawned = None
|
|
827
|
+
process: subprocess.Popen[object] | None = None
|
|
828
|
+
cleanup_complete = False
|
|
796
829
|
try:
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
830
|
+
spawned = hprocess.spawn_structured_argv(
|
|
831
|
+
list(argv),
|
|
832
|
+
cwd=Path(cwd).resolve(),
|
|
833
|
+
environment=child_env,
|
|
834
|
+
owner_token=f"test-runner:{uuid.uuid4().hex}",
|
|
835
|
+
stdout=output_stream,
|
|
836
|
+
stderr=(subprocess.STDOUT if output_stream is not None else None),
|
|
802
837
|
)
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
838
|
+
process = spawned.process
|
|
839
|
+
isolated = bool(
|
|
840
|
+
isinstance(spawned.ownershipProof, dict)
|
|
841
|
+
and spawned.ownershipProof.get("membersComplete") is True
|
|
842
|
+
)
|
|
843
|
+
|
|
844
|
+
def provider_cleanup() -> bool:
|
|
845
|
+
hprocess.capture_owned_members(spawned)
|
|
846
|
+
result = hprocess.terminate_owned_tree(
|
|
847
|
+
spawned.attestation,
|
|
848
|
+
spawned.ownershipProof,
|
|
849
|
+
{"graceSeconds": 3.0},
|
|
850
|
+
)
|
|
851
|
+
return bool(result.get("cleanupComplete"))
|
|
852
|
+
|
|
853
|
+
def wait_owned_members_gone() -> bool:
|
|
854
|
+
proof = spawned.ownershipProof
|
|
855
|
+
if not isinstance(proof, dict):
|
|
856
|
+
return False
|
|
857
|
+
members = proof.get("members")
|
|
858
|
+
if not isinstance(members, list):
|
|
859
|
+
return False
|
|
860
|
+
pids = {
|
|
861
|
+
int(item["pid"])
|
|
862
|
+
for item in members
|
|
863
|
+
if isinstance(item, dict) and isinstance(item.get("pid"), int)
|
|
864
|
+
}
|
|
865
|
+
deadline = time.monotonic() + 5.0
|
|
866
|
+
while pids and time.monotonic() < deadline:
|
|
867
|
+
pids = {pid for pid in pids if hprocess.is_pid_alive(pid)}
|
|
868
|
+
if pids:
|
|
869
|
+
time.sleep(0.05)
|
|
870
|
+
return not pids
|
|
871
|
+
|
|
808
872
|
timed_out = False
|
|
809
873
|
try:
|
|
810
874
|
deadline = time.monotonic() + max(0.01, float(timeout_seconds))
|
|
811
875
|
while True:
|
|
812
|
-
if os.name == "nt":
|
|
813
|
-
windows_snapshot_ok = (
|
|
814
|
-
_update_windows_descendants(
|
|
815
|
-
process.pid,
|
|
816
|
-
known_windows_descendants,
|
|
817
|
-
)
|
|
818
|
-
and windows_snapshot_ok
|
|
819
|
-
)
|
|
820
876
|
polled = process.poll()
|
|
821
877
|
if polled is not None:
|
|
822
878
|
returncode = polled
|
|
823
879
|
break
|
|
824
880
|
if time.monotonic() >= deadline:
|
|
825
881
|
timed_out = True
|
|
826
|
-
|
|
882
|
+
cleanup_complete = provider_cleanup()
|
|
827
883
|
returncode = 124
|
|
828
884
|
break
|
|
829
885
|
time.sleep(0.05)
|
|
830
886
|
except KeyboardInterrupt:
|
|
831
|
-
|
|
832
|
-
if os.name == "nt":
|
|
833
|
-
_terminate_tracked_windows_descendants(known_windows_descendants)
|
|
887
|
+
cleanup_complete = provider_cleanup()
|
|
834
888
|
raise
|
|
835
889
|
if not timed_out:
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
890
|
+
cleanup_complete = provider_cleanup()
|
|
891
|
+
# A named Windows Job remains an owned capability after the leader
|
|
892
|
+
# exits. Closing that provider handle drains any attested children;
|
|
893
|
+
# PID-only or POSIX group fallbacks stay fail-closed.
|
|
894
|
+
if not cleanup_complete and os.name == "nt":
|
|
895
|
+
spawned.close()
|
|
896
|
+
cleanup_complete = wait_owned_members_gone()
|
|
897
|
+
if process.poll() is None:
|
|
898
|
+
try:
|
|
899
|
+
process.wait(timeout=5)
|
|
900
|
+
except subprocess.TimeoutExpired:
|
|
901
|
+
cleanup_complete = False
|
|
845
902
|
duration = time.monotonic() - started
|
|
846
903
|
output_tail = ""
|
|
847
904
|
if output_stream is not None:
|
|
@@ -854,10 +911,28 @@ def run_managed_command(
|
|
|
854
911
|
returncode=returncode,
|
|
855
912
|
timed_out=timed_out,
|
|
856
913
|
duration_seconds=duration,
|
|
857
|
-
process_tree_isolated=isolated,
|
|
914
|
+
process_tree_isolated=isolated and cleanup_complete,
|
|
858
915
|
output_tail=output_tail,
|
|
859
916
|
)
|
|
860
917
|
finally:
|
|
918
|
+
if (
|
|
919
|
+
not cleanup_complete
|
|
920
|
+
and process is not None
|
|
921
|
+
and process.poll() is None
|
|
922
|
+
and spawned is not None
|
|
923
|
+
):
|
|
924
|
+
try:
|
|
925
|
+
hprocess.capture_owned_members(spawned)
|
|
926
|
+
cleanup = hprocess.terminate_owned_tree(
|
|
927
|
+
spawned.attestation,
|
|
928
|
+
spawned.ownershipProof,
|
|
929
|
+
{"graceSeconds": 3.0},
|
|
930
|
+
)
|
|
931
|
+
cleanup_complete = bool(cleanup.get("cleanupComplete"))
|
|
932
|
+
except Exception:
|
|
933
|
+
cleanup_complete = False
|
|
934
|
+
if spawned is not None:
|
|
935
|
+
spawned.close()
|
|
861
936
|
if output_stream is not None:
|
|
862
937
|
output_stream.close()
|
|
863
938
|
|
|
@@ -1320,7 +1395,10 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
1320
1395
|
exec_parser.add_argument(
|
|
1321
1396
|
"--allow-detached-processes",
|
|
1322
1397
|
action="store_true",
|
|
1323
|
-
help=
|
|
1398
|
+
help=(
|
|
1399
|
+
"Permit explicit Windows Job breakaway while retaining ordinary "
|
|
1400
|
+
"descendants and tracking escaped process lineages."
|
|
1401
|
+
),
|
|
1324
1402
|
)
|
|
1325
1403
|
exec_parser.set_defaults(handler=_run_exec)
|
|
1326
1404
|
|