@hunter-harness/workflow-harness 0.2.41 → 0.2.43
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 +56 -1
- 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 +42 -16
- package/harness/bundles/general/claude-code/harness-knowledge-ingest/reference.md +57 -6
- package/harness/bundles/general/claude-code/harness-knowledge-ingest/scripts/harness_knowledge.py +1097 -174
- 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-sync/SKILL.md +16 -10
- package/harness/bundles/general/claude-code/harness-sync/reference.md +34 -14
- 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 +4 -0
- package/harness/bundles/general/claude-code/scripts/harness_efficiency.py +290 -0
- package/harness/bundles/general/claude-code/scripts/harness_environment.py +719 -35
- package/harness/bundles/general/claude-code/scripts/harness_fixback.py +742 -0
- package/harness/bundles/general/claude-code/scripts/harness_profile.py +34 -0
- package/harness/bundles/general/claude-code/scripts/harness_runtime.py +1165 -3
- package/harness/bundles/general/claude-code/scripts/harness_service.py +76 -0
- package/harness/bundles/general/claude-code/scripts/harness_test_runner.py +127 -39
- package/harness/bundles/general/claude-code/scripts/harness_verification.py +408 -8
- package/harness/bundles/general/codebuddy/.harness-build.json +1 -1
- package/harness/bundles/general/codebuddy/contracts/build-profile-v3.schema.json +56 -1
- 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 +41 -15
- package/harness/bundles/general/codebuddy/harness-knowledge-ingest/reference.md +57 -6
- package/harness/bundles/general/codebuddy/harness-knowledge-ingest/scripts/harness_knowledge.py +1097 -174
- 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-sync/SKILL.md +16 -10
- package/harness/bundles/general/codebuddy/harness-sync/reference.md +34 -14
- 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 +4 -0
- package/harness/bundles/general/codebuddy/scripts/harness_efficiency.py +290 -0
- package/harness/bundles/general/codebuddy/scripts/harness_environment.py +719 -35
- package/harness/bundles/general/codebuddy/scripts/harness_fixback.py +742 -0
- package/harness/bundles/general/codebuddy/scripts/harness_profile.py +34 -0
- package/harness/bundles/general/codebuddy/scripts/harness_runtime.py +1165 -3
- package/harness/bundles/general/codebuddy/scripts/harness_service.py +76 -0
- package/harness/bundles/general/codebuddy/scripts/harness_test_runner.py +127 -39
- package/harness/bundles/general/codebuddy/scripts/harness_verification.py +408 -8
- package/harness/bundles/general/codex/.harness-build.json +1 -1
- package/harness/bundles/general/codex/contracts/build-profile-v3.schema.json +56 -1
- 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 +41 -15
- package/harness/bundles/general/codex/harness-knowledge-ingest/reference.md +57 -6
- package/harness/bundles/general/codex/harness-knowledge-ingest/scripts/harness_knowledge.py +1097 -174
- 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-sync/SKILL.md +16 -10
- package/harness/bundles/general/codex/harness-sync/reference.md +34 -14
- 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 +4 -0
- package/harness/bundles/general/codex/scripts/harness_efficiency.py +290 -0
- package/harness/bundles/general/codex/scripts/harness_environment.py +719 -35
- package/harness/bundles/general/codex/scripts/harness_fixback.py +742 -0
- package/harness/bundles/general/codex/scripts/harness_profile.py +34 -0
- package/harness/bundles/general/codex/scripts/harness_runtime.py +1165 -3
- package/harness/bundles/general/codex/scripts/harness_service.py +76 -0
- package/harness/bundles/general/codex/scripts/harness_test_runner.py +127 -39
- package/harness/bundles/general/codex/scripts/harness_verification.py +408 -8
- package/harness/bundles/general/cursor/.harness-build.json +1 -1
- package/harness/bundles/general/cursor/contracts/build-profile-v3.schema.json +56 -1
- 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 +41 -15
- package/harness/bundles/general/cursor/harness-knowledge-ingest/reference.md +57 -6
- package/harness/bundles/general/cursor/harness-knowledge-ingest/scripts/harness_knowledge.py +1097 -174
- 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-sync/SKILL.md +16 -10
- package/harness/bundles/general/cursor/harness-sync/reference.md +34 -14
- 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 +4 -0
- package/harness/bundles/general/cursor/scripts/harness_efficiency.py +290 -0
- package/harness/bundles/general/cursor/scripts/harness_environment.py +719 -35
- package/harness/bundles/general/cursor/scripts/harness_fixback.py +742 -0
- package/harness/bundles/general/cursor/scripts/harness_profile.py +34 -0
- package/harness/bundles/general/cursor/scripts/harness_runtime.py +1165 -3
- package/harness/bundles/general/cursor/scripts/harness_service.py +76 -0
- package/harness/bundles/general/cursor/scripts/harness_test_runner.py +127 -39
- package/harness/bundles/general/cursor/scripts/harness_verification.py +408 -8
- package/harness/bundles/java/claude-code/.harness-build.json +1 -1
- package/harness/bundles/java/claude-code/contracts/build-profile-v3.schema.json +56 -1
- 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 +42 -16
- package/harness/bundles/java/claude-code/harness-knowledge-ingest/reference.md +57 -6
- package/harness/bundles/java/claude-code/harness-knowledge-ingest/scripts/harness_knowledge.py +1097 -174
- 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-sync/SKILL.md +16 -10
- package/harness/bundles/java/claude-code/harness-sync/reference.md +34 -14
- 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 +4 -0
- package/harness/bundles/java/claude-code/scripts/harness_efficiency.py +290 -0
- package/harness/bundles/java/claude-code/scripts/harness_environment.py +719 -35
- package/harness/bundles/java/claude-code/scripts/harness_fixback.py +742 -0
- package/harness/bundles/java/claude-code/scripts/harness_profile.py +34 -0
- package/harness/bundles/java/claude-code/scripts/harness_runtime.py +1165 -3
- package/harness/bundles/java/claude-code/scripts/harness_service.py +76 -0
- package/harness/bundles/java/claude-code/scripts/harness_test_runner.py +127 -39
- package/harness/bundles/java/claude-code/scripts/harness_verification.py +408 -8
- package/harness/bundles/java/codebuddy/.harness-build.json +1 -1
- package/harness/bundles/java/codebuddy/contracts/build-profile-v3.schema.json +56 -1
- 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 +41 -15
- package/harness/bundles/java/codebuddy/harness-knowledge-ingest/reference.md +57 -6
- package/harness/bundles/java/codebuddy/harness-knowledge-ingest/scripts/harness_knowledge.py +1097 -174
- 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-sync/SKILL.md +16 -10
- package/harness/bundles/java/codebuddy/harness-sync/reference.md +34 -14
- 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 +4 -0
- package/harness/bundles/java/codebuddy/scripts/harness_efficiency.py +290 -0
- package/harness/bundles/java/codebuddy/scripts/harness_environment.py +719 -35
- package/harness/bundles/java/codebuddy/scripts/harness_fixback.py +742 -0
- package/harness/bundles/java/codebuddy/scripts/harness_profile.py +34 -0
- package/harness/bundles/java/codebuddy/scripts/harness_runtime.py +1165 -3
- package/harness/bundles/java/codebuddy/scripts/harness_service.py +76 -0
- package/harness/bundles/java/codebuddy/scripts/harness_test_runner.py +127 -39
- package/harness/bundles/java/codebuddy/scripts/harness_verification.py +408 -8
- package/harness/bundles/java/codex/.harness-build.json +1 -1
- package/harness/bundles/java/codex/contracts/build-profile-v3.schema.json +56 -1
- 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 +41 -15
- package/harness/bundles/java/codex/harness-knowledge-ingest/reference.md +57 -6
- package/harness/bundles/java/codex/harness-knowledge-ingest/scripts/harness_knowledge.py +1097 -174
- 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-sync/SKILL.md +16 -10
- package/harness/bundles/java/codex/harness-sync/reference.md +34 -14
- 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 +4 -0
- package/harness/bundles/java/codex/scripts/harness_efficiency.py +290 -0
- package/harness/bundles/java/codex/scripts/harness_environment.py +719 -35
- package/harness/bundles/java/codex/scripts/harness_fixback.py +742 -0
- package/harness/bundles/java/codex/scripts/harness_profile.py +34 -0
- package/harness/bundles/java/codex/scripts/harness_runtime.py +1165 -3
- package/harness/bundles/java/codex/scripts/harness_service.py +76 -0
- package/harness/bundles/java/codex/scripts/harness_test_runner.py +127 -39
- package/harness/bundles/java/codex/scripts/harness_verification.py +408 -8
- package/harness/bundles/java/cursor/.harness-build.json +1 -1
- package/harness/bundles/java/cursor/contracts/build-profile-v3.schema.json +56 -1
- 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 +41 -15
- package/harness/bundles/java/cursor/harness-knowledge-ingest/reference.md +57 -6
- package/harness/bundles/java/cursor/harness-knowledge-ingest/scripts/harness_knowledge.py +1097 -174
- 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-sync/SKILL.md +16 -10
- package/harness/bundles/java/cursor/harness-sync/reference.md +34 -14
- 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 +4 -0
- package/harness/bundles/java/cursor/scripts/harness_efficiency.py +290 -0
- package/harness/bundles/java/cursor/scripts/harness_environment.py +719 -35
- package/harness/bundles/java/cursor/scripts/harness_fixback.py +742 -0
- package/harness/bundles/java/cursor/scripts/harness_profile.py +34 -0
- package/harness/bundles/java/cursor/scripts/harness_runtime.py +1165 -3
- package/harness/bundles/java/cursor/scripts/harness_service.py +76 -0
- package/harness/bundles/java/cursor/scripts/harness_test_runner.py +127 -39
- package/harness/bundles/java/cursor/scripts/harness_verification.py +408 -8
- package/harness/manifests/general/claude-code.json +46 -33
- package/harness/manifests/general/codebuddy.json +46 -33
- package/harness/manifests/general/codex.json +46 -33
- package/harness/manifests/general/cursor.json +46 -33
- package/harness/manifests/java/claude-code.json +47 -34
- package/harness/manifests/java/codebuddy.json +47 -34
- package/harness/manifests/java/codex.json +47 -34
- package/harness/manifests/java/cursor.json +47 -34
- package/hunter-workflow-family.json +12 -10
- package/package.json +1 -1
|
@@ -1855,6 +1855,74 @@ def cmd_stop(args: argparse.Namespace) -> int:
|
|
|
1855
1855
|
return 0 if result.get("ok") else 1
|
|
1856
1856
|
|
|
1857
1857
|
|
|
1858
|
+
def retire_stale_session(change_dir: Path) -> dict[str, Any]:
|
|
1859
|
+
"""Retire only Harness state whose recorded process identity is gone.
|
|
1860
|
+
|
|
1861
|
+
This operation never terminates a process or releases a live listener. The
|
|
1862
|
+
original receipt is moved into an immutable evidence directory so a new
|
|
1863
|
+
superseding session may be created safely.
|
|
1864
|
+
"""
|
|
1865
|
+
change_dir = resolve_path(change_dir)
|
|
1866
|
+
try:
|
|
1867
|
+
session = load_session(change_dir)
|
|
1868
|
+
except SessionCorrupt as exc:
|
|
1869
|
+
return {
|
|
1870
|
+
"ok": False,
|
|
1871
|
+
"code": "SERVICE_SESSION_CORRUPT",
|
|
1872
|
+
"action": "retire-refused",
|
|
1873
|
+
"error": str(exc),
|
|
1874
|
+
"unknownProcessUntouched": True,
|
|
1875
|
+
}
|
|
1876
|
+
if session is None:
|
|
1877
|
+
return {
|
|
1878
|
+
"ok": True,
|
|
1879
|
+
"code": "SERVICE_SESSION_ABSENT",
|
|
1880
|
+
"action": "already-retired",
|
|
1881
|
+
"unknownProcessUntouched": True,
|
|
1882
|
+
}
|
|
1883
|
+
identity = verify_process_identity(session)
|
|
1884
|
+
if identity is True:
|
|
1885
|
+
return {
|
|
1886
|
+
"ok": False,
|
|
1887
|
+
"code": "SERVICE_PROCESS_STILL_OWNED",
|
|
1888
|
+
"action": "retire-refused",
|
|
1889
|
+
"unknownProcessUntouched": True,
|
|
1890
|
+
}
|
|
1891
|
+
if identity is None:
|
|
1892
|
+
return {
|
|
1893
|
+
"ok": False,
|
|
1894
|
+
"code": "SERVICE_PROCESS_IDENTITY_UNVERIFIED",
|
|
1895
|
+
"action": "retire-refused",
|
|
1896
|
+
"unknownProcessUntouched": True,
|
|
1897
|
+
}
|
|
1898
|
+
source = session_path(change_dir)
|
|
1899
|
+
raw_id = str(session.get("sessionId") or session.get("session_id") or "")
|
|
1900
|
+
safe_id = re.sub(r"[^A-Za-z0-9._-]+", "-", raw_id).strip("-")
|
|
1901
|
+
if not safe_id:
|
|
1902
|
+
safe_id = sha256_text(json.dumps(session, sort_keys=True))[7:23]
|
|
1903
|
+
retired_root = change_dir / "runtime" / "retired-service-sessions"
|
|
1904
|
+
retired_root.mkdir(parents=True, exist_ok=True)
|
|
1905
|
+
destination = retired_root / f"{safe_id}-{int(time.time() * 1000)}.json"
|
|
1906
|
+
os.replace(source, destination)
|
|
1907
|
+
receipt = {
|
|
1908
|
+
"schemaVersion": 1,
|
|
1909
|
+
"action": "retired-stale",
|
|
1910
|
+
"code": "STALE_IDENTITY_RETIRED",
|
|
1911
|
+
"retiredAt": now_iso(),
|
|
1912
|
+
"retiredEvidence": str(destination),
|
|
1913
|
+
"unknownProcessUntouched": True,
|
|
1914
|
+
"sessionId": raw_id or None,
|
|
1915
|
+
}
|
|
1916
|
+
write_json(retired_root / f"{destination.stem}.receipt.json", receipt)
|
|
1917
|
+
return {"ok": True, **receipt}
|
|
1918
|
+
|
|
1919
|
+
|
|
1920
|
+
def cmd_retire_stale(args: argparse.Namespace) -> int:
|
|
1921
|
+
result = retire_stale_session(resolve_path(args.change_dir))
|
|
1922
|
+
emit_json(result, as_json=bool(args.json))
|
|
1923
|
+
return 0 if result.get("ok") else 1
|
|
1924
|
+
|
|
1925
|
+
|
|
1858
1926
|
def build_parser() -> argparse.ArgumentParser:
|
|
1859
1927
|
parser = argparse.ArgumentParser(
|
|
1860
1928
|
prog="harness_service.py",
|
|
@@ -1934,6 +2002,14 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
1934
2002
|
p_stop.add_argument("--json", action="store_true")
|
|
1935
2003
|
p_stop.set_defaults(func=cmd_stop)
|
|
1936
2004
|
|
|
2005
|
+
p_retire = sub.add_parser(
|
|
2006
|
+
"retire-stale",
|
|
2007
|
+
help="retire stale Harness state without terminating unknown processes",
|
|
2008
|
+
)
|
|
2009
|
+
p_retire.add_argument("--change-dir", required=True)
|
|
2010
|
+
p_retire.add_argument("--json", action="store_true")
|
|
2011
|
+
p_retire.set_defaults(func=cmd_retire_stale)
|
|
2012
|
+
|
|
1937
2013
|
return parser
|
|
1938
2014
|
|
|
1939
2015
|
|
|
@@ -37,7 +37,10 @@ DEFAULT_RESOURCE_MODULES = (
|
|
|
37
37
|
"test_harness_integration.py",
|
|
38
38
|
"test_harness_service.py",
|
|
39
39
|
)
|
|
40
|
-
DEFAULT_DETACHED_SERVICE_MODULES = (
|
|
40
|
+
DEFAULT_DETACHED_SERVICE_MODULES = (
|
|
41
|
+
"test_harness_service.py",
|
|
42
|
+
"test_harness_runtime.py",
|
|
43
|
+
)
|
|
41
44
|
TRUTHY_VALUES = frozenset({"1", "true", "yes", "on"})
|
|
42
45
|
|
|
43
46
|
|
|
@@ -189,16 +192,17 @@ def classify_test_lock(path: Path) -> dict[str, object]:
|
|
|
189
192
|
"path": str(path),
|
|
190
193
|
"token": payload.get("token"),
|
|
191
194
|
}
|
|
192
|
-
|
|
193
|
-
return {
|
|
194
|
-
"classification": "ACTIVE",
|
|
195
|
-
"path": str(path),
|
|
196
|
-
"token": payload.get("token"),
|
|
197
|
-
"owner": owner,
|
|
198
|
-
}
|
|
195
|
+
unexpired = time.time() < float(expires)
|
|
199
196
|
if not isinstance(owner, dict) or any(
|
|
200
197
|
not owner.get(field) for field in ("pid", "executable", "startedAt")
|
|
201
198
|
):
|
|
199
|
+
if unexpired:
|
|
200
|
+
return {
|
|
201
|
+
"classification": "ACTIVE",
|
|
202
|
+
"path": str(path),
|
|
203
|
+
"token": payload.get("token"),
|
|
204
|
+
"owner": owner,
|
|
205
|
+
}
|
|
202
206
|
return {
|
|
203
207
|
"classification": "OWNER_IDENTITY_INCOMPLETE",
|
|
204
208
|
"path": str(path),
|
|
@@ -207,6 +211,13 @@ def classify_test_lock(path: Path) -> dict[str, object]:
|
|
|
207
211
|
try:
|
|
208
212
|
owner_pid = int(owner["pid"])
|
|
209
213
|
except (TypeError, ValueError):
|
|
214
|
+
if unexpired:
|
|
215
|
+
return {
|
|
216
|
+
"classification": "ACTIVE",
|
|
217
|
+
"path": str(path),
|
|
218
|
+
"token": payload.get("token"),
|
|
219
|
+
"owner": owner,
|
|
220
|
+
}
|
|
210
221
|
return {
|
|
211
222
|
"classification": "OWNER_IDENTITY_INCOMPLETE",
|
|
212
223
|
"path": str(path),
|
|
@@ -219,6 +230,13 @@ def classify_test_lock(path: Path) -> dict[str, object]:
|
|
|
219
230
|
"token": payload.get("token"),
|
|
220
231
|
"owner": owner,
|
|
221
232
|
}
|
|
233
|
+
if unexpired:
|
|
234
|
+
return {
|
|
235
|
+
"classification": "ACTIVE",
|
|
236
|
+
"path": str(path),
|
|
237
|
+
"token": payload.get("token"),
|
|
238
|
+
"owner": owner,
|
|
239
|
+
}
|
|
222
240
|
verified = henv.hservice.verify_process_identity(
|
|
223
241
|
{
|
|
224
242
|
"pid": owner_pid,
|
|
@@ -244,7 +262,7 @@ def classify_test_lock(path: Path) -> dict[str, object]:
|
|
|
244
262
|
|
|
245
263
|
|
|
246
264
|
def reap_test_lock(path: Path) -> dict[str, object]:
|
|
247
|
-
"""Reap only
|
|
265
|
+
"""Reap only a lock whose exact recorded owner is definitely absent."""
|
|
248
266
|
classification = classify_test_lock(path)
|
|
249
267
|
reaped = classification.get("classification") == "RECLAIMABLE"
|
|
250
268
|
if reaped:
|
|
@@ -484,6 +502,20 @@ class _WindowsBasicAccountingInformation(ctypes.Structure):
|
|
|
484
502
|
]
|
|
485
503
|
|
|
486
504
|
|
|
505
|
+
_WINDOWS_JOB_PROCESS_ID_CAPACITY = 4096
|
|
506
|
+
|
|
507
|
+
|
|
508
|
+
class _WindowsJobProcessIdList(ctypes.Structure):
|
|
509
|
+
_fields_ = [
|
|
510
|
+
("NumberOfAssignedProcesses", ctypes.c_uint32),
|
|
511
|
+
("NumberOfProcessIdsInList", ctypes.c_uint32),
|
|
512
|
+
(
|
|
513
|
+
"ProcessIdList",
|
|
514
|
+
ctypes.c_size_t * _WINDOWS_JOB_PROCESS_ID_CAPACITY,
|
|
515
|
+
),
|
|
516
|
+
]
|
|
517
|
+
|
|
518
|
+
|
|
487
519
|
class _WindowsKillOnCloseJob:
|
|
488
520
|
"""Best-effort Windows Job Object that kills descendants when closed."""
|
|
489
521
|
|
|
@@ -491,9 +523,11 @@ class _WindowsKillOnCloseJob:
|
|
|
491
523
|
_JOB_OBJECT_LIMIT_BREAKAWAY_OK = 0x00000800
|
|
492
524
|
_JOB_OBJECT_EXTENDED_LIMIT_INFORMATION_CLASS = 9
|
|
493
525
|
_JOB_OBJECT_BASIC_ACCOUNTING_INFORMATION_CLASS = 1
|
|
526
|
+
_JOB_OBJECT_BASIC_PROCESS_ID_LIST_CLASS = 3
|
|
494
527
|
|
|
495
|
-
def __init__(self) -> None:
|
|
528
|
+
def __init__(self, *, allow_breakaway: bool = False) -> None:
|
|
496
529
|
self.handle: int | None = None
|
|
530
|
+
self.allow_breakaway = allow_breakaway
|
|
497
531
|
|
|
498
532
|
def assign(self, process: subprocess.Popen[object]) -> bool:
|
|
499
533
|
if os.name != "nt":
|
|
@@ -506,7 +540,11 @@ class _WindowsKillOnCloseJob:
|
|
|
506
540
|
info = _WindowsExtendedLimitInformation()
|
|
507
541
|
info.BasicLimitInformation.LimitFlags = (
|
|
508
542
|
self._JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE
|
|
509
|
-
|
|
|
543
|
+
| (
|
|
544
|
+
self._JOB_OBJECT_LIMIT_BREAKAWAY_OK
|
|
545
|
+
if self.allow_breakaway
|
|
546
|
+
else 0
|
|
547
|
+
)
|
|
510
548
|
)
|
|
511
549
|
configured = kernel32.SetInformationJobObject(
|
|
512
550
|
ctypes.c_void_p(handle),
|
|
@@ -535,26 +573,73 @@ class _WindowsKillOnCloseJob:
|
|
|
535
573
|
ctypes.windll.kernel32.CloseHandle(ctypes.c_void_p(self.handle))
|
|
536
574
|
self.handle = None
|
|
537
575
|
|
|
538
|
-
def terminate_and_wait(self, timeout_seconds: float = 5.0) ->
|
|
576
|
+
def terminate_and_wait(self, timeout_seconds: float = 5.0) -> bool:
|
|
539
577
|
if self.handle is None:
|
|
540
|
-
return
|
|
578
|
+
return True
|
|
541
579
|
kernel32 = ctypes.windll.kernel32
|
|
542
580
|
handle = ctypes.c_void_p(self.handle)
|
|
543
|
-
kernel32.TerminateJobObject(handle, 1)
|
|
544
581
|
deadline = time.monotonic() + max(0.0, timeout_seconds)
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
582
|
+
process_ids = _WindowsJobProcessIdList()
|
|
583
|
+
process_list_queried = kernel32.QueryInformationJobObject(
|
|
584
|
+
handle,
|
|
585
|
+
self._JOB_OBJECT_BASIC_PROCESS_ID_LIST_CLASS,
|
|
586
|
+
ctypes.byref(process_ids),
|
|
587
|
+
ctypes.sizeof(process_ids),
|
|
588
|
+
None,
|
|
589
|
+
)
|
|
590
|
+
process_list_complete = bool(
|
|
591
|
+
process_list_queried
|
|
592
|
+
and process_ids.NumberOfAssignedProcesses
|
|
593
|
+
== process_ids.NumberOfProcessIdsInList
|
|
594
|
+
)
|
|
595
|
+
kernel32.OpenProcess.restype = ctypes.c_void_p
|
|
596
|
+
process_handles: list[int] = []
|
|
597
|
+
if process_list_complete:
|
|
598
|
+
for index in range(int(process_ids.NumberOfProcessIdsInList)):
|
|
599
|
+
process_handle = kernel32.OpenProcess(
|
|
600
|
+
0x00100000,
|
|
601
|
+
False,
|
|
602
|
+
int(process_ids.ProcessIdList[index]),
|
|
603
|
+
)
|
|
604
|
+
if process_handle:
|
|
605
|
+
process_handles.append(int(process_handle))
|
|
606
|
+
else:
|
|
607
|
+
process_list_complete = False
|
|
608
|
+
terminated = bool(kernel32.TerminateJobObject(handle, 1))
|
|
609
|
+
handles_signaled = process_list_complete
|
|
610
|
+
try:
|
|
611
|
+
for process_handle in process_handles:
|
|
612
|
+
remaining_ms = max(
|
|
613
|
+
0,
|
|
614
|
+
int((deadline - time.monotonic()) * 1000),
|
|
615
|
+
)
|
|
616
|
+
if (
|
|
617
|
+
kernel32.WaitForSingleObject(
|
|
618
|
+
ctypes.c_void_p(process_handle),
|
|
619
|
+
remaining_ms,
|
|
620
|
+
)
|
|
621
|
+
!= 0
|
|
622
|
+
):
|
|
623
|
+
handles_signaled = False
|
|
624
|
+
accounting_drained = False
|
|
625
|
+
while time.monotonic() < deadline:
|
|
626
|
+
accounting = _WindowsBasicAccountingInformation()
|
|
627
|
+
queried = kernel32.QueryInformationJobObject(
|
|
628
|
+
handle,
|
|
629
|
+
self._JOB_OBJECT_BASIC_ACCOUNTING_INFORMATION_CLASS,
|
|
630
|
+
ctypes.byref(accounting),
|
|
631
|
+
ctypes.sizeof(accounting),
|
|
632
|
+
None,
|
|
633
|
+
)
|
|
634
|
+
if queried and accounting.ActiveProcesses == 0:
|
|
635
|
+
accounting_drained = True
|
|
636
|
+
break
|
|
637
|
+
time.sleep(0.02)
|
|
638
|
+
finally:
|
|
639
|
+
for process_handle in process_handles:
|
|
640
|
+
kernel32.CloseHandle(ctypes.c_void_p(process_handle))
|
|
641
|
+
self.close()
|
|
642
|
+
return terminated and handles_signaled and accounting_drained
|
|
558
643
|
|
|
559
644
|
|
|
560
645
|
class _WindowsProcessEntry(ctypes.Structure):
|
|
@@ -744,15 +829,15 @@ def _cleanup_descendants_after_success(
|
|
|
744
829
|
process: subprocess.Popen[object],
|
|
745
830
|
*,
|
|
746
831
|
windows_job: _WindowsKillOnCloseJob | None,
|
|
747
|
-
) ->
|
|
832
|
+
) -> bool:
|
|
748
833
|
if windows_job is not None and windows_job.handle is not None:
|
|
749
|
-
windows_job.terminate_and_wait()
|
|
750
|
-
return
|
|
834
|
+
return windows_job.terminate_and_wait()
|
|
751
835
|
if os.name != "nt":
|
|
752
836
|
try:
|
|
753
837
|
os.killpg(process.pid, signal.SIGTERM)
|
|
754
838
|
except ProcessLookupError:
|
|
755
839
|
pass
|
|
840
|
+
return os.name != "nt"
|
|
756
841
|
|
|
757
842
|
|
|
758
843
|
def run_managed_command(
|
|
@@ -796,8 +881,8 @@ def run_managed_command(
|
|
|
796
881
|
try:
|
|
797
882
|
process = subprocess.Popen(list(argv), **popen_kwargs)
|
|
798
883
|
windows_job = (
|
|
799
|
-
_WindowsKillOnCloseJob()
|
|
800
|
-
if os.name == "nt"
|
|
884
|
+
_WindowsKillOnCloseJob(allow_breakaway=allow_detached_processes)
|
|
885
|
+
if os.name == "nt"
|
|
801
886
|
else None
|
|
802
887
|
)
|
|
803
888
|
isolated = bool(windows_job and windows_job.assign(process))
|
|
@@ -832,16 +917,16 @@ def run_managed_command(
|
|
|
832
917
|
if os.name == "nt":
|
|
833
918
|
_terminate_tracked_windows_descendants(known_windows_descendants)
|
|
834
919
|
raise
|
|
920
|
+
descendants_drained = True
|
|
835
921
|
if not timed_out:
|
|
836
|
-
_cleanup_descendants_after_success(
|
|
922
|
+
descendants_drained = _cleanup_descendants_after_success(
|
|
923
|
+
process,
|
|
924
|
+
windows_job=windows_job,
|
|
925
|
+
)
|
|
837
926
|
if os.name == "nt":
|
|
838
927
|
_update_windows_descendants(process.pid, known_windows_descendants)
|
|
839
928
|
_terminate_tracked_windows_descendants(known_windows_descendants)
|
|
840
|
-
isolated =
|
|
841
|
-
windows_snapshot_ok
|
|
842
|
-
if allow_detached_processes
|
|
843
|
-
else isolated and windows_snapshot_ok
|
|
844
|
-
)
|
|
929
|
+
isolated = isolated and windows_snapshot_ok and descendants_drained
|
|
845
930
|
duration = time.monotonic() - started
|
|
846
931
|
output_tail = ""
|
|
847
932
|
if output_stream is not None:
|
|
@@ -1320,7 +1405,10 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
1320
1405
|
exec_parser.add_argument(
|
|
1321
1406
|
"--allow-detached-processes",
|
|
1322
1407
|
action="store_true",
|
|
1323
|
-
help=
|
|
1408
|
+
help=(
|
|
1409
|
+
"Permit explicit Windows Job breakaway while retaining ordinary "
|
|
1410
|
+
"descendants and tracking escaped process lineages."
|
|
1411
|
+
),
|
|
1324
1412
|
)
|
|
1325
1413
|
exec_parser.set_defaults(handler=_run_exec)
|
|
1326
1414
|
|