@hunter-harness/workflow-harness 0.2.27 → 0.2.28
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/harness-archive/SKILL.md +1 -1
- package/harness/bundles/general/claude-code/harness-archive/templates/render-summary.mjs +25 -6
- package/harness/bundles/general/claude-code/harness-archive/templates/summary-data-template.json +44 -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-ingest/scripts/harness_knowledge.py +493 -74
- 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-submit/SKILL.md +1 -1
- package/harness/bundles/general/claude-code/harness-sync/SKILL.md +1 -1
- package/harness/bundles/general/claude-code/harness-test/SKILL.md +1 -1
- package/harness/bundles/general/claude-code/scripts/harness_archive.py +2061 -187
- package/harness/bundles/general/claude-code/scripts/harness_events.py +43 -9
- package/harness/bundles/general/claude-code/scripts/harness_gate.py +491 -7
- package/harness/bundles/general/claude-code/scripts/harness_integration.py +232 -0
- package/harness/bundles/general/claude-code/scripts/harness_phase.py +758 -1
- package/harness/bundles/general/claude-code/scripts/harness_plan_finalize.py +74 -0
- package/harness/bundles/general/claude-code/scripts/harness_retry.py +175 -0
- package/harness/bundles/general/claude-code/scripts/harness_test_guard.py +702 -22
- package/harness/bundles/general/codebuddy/.harness-build.json +1 -1
- package/harness/bundles/general/codebuddy/harness-archive/SKILL.md +1 -1
- package/harness/bundles/general/codebuddy/harness-archive/templates/render-summary.mjs +25 -6
- package/harness/bundles/general/codebuddy/harness-archive/templates/summary-data-template.json +44 -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-ingest/scripts/harness_knowledge.py +493 -74
- 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-submit/SKILL.md +1 -1
- package/harness/bundles/general/codebuddy/harness-sync/SKILL.md +1 -1
- package/harness/bundles/general/codebuddy/harness-test/SKILL.md +1 -1
- package/harness/bundles/general/codebuddy/scripts/harness_archive.py +2061 -187
- package/harness/bundles/general/codebuddy/scripts/harness_events.py +43 -9
- package/harness/bundles/general/codebuddy/scripts/harness_gate.py +491 -7
- package/harness/bundles/general/codebuddy/scripts/harness_integration.py +232 -0
- package/harness/bundles/general/codebuddy/scripts/harness_phase.py +758 -1
- package/harness/bundles/general/codebuddy/scripts/harness_plan_finalize.py +74 -0
- package/harness/bundles/general/codebuddy/scripts/harness_retry.py +175 -0
- package/harness/bundles/general/codebuddy/scripts/harness_test_guard.py +702 -22
- package/harness/bundles/general/codex/.harness-build.json +1 -1
- package/harness/bundles/general/codex/harness-archive/SKILL.md +1 -1
- package/harness/bundles/general/codex/harness-archive/templates/render-summary.mjs +25 -6
- package/harness/bundles/general/codex/harness-archive/templates/summary-data-template.json +44 -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-ingest/scripts/harness_knowledge.py +493 -74
- 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-submit/SKILL.md +1 -1
- package/harness/bundles/general/codex/harness-sync/SKILL.md +1 -1
- package/harness/bundles/general/codex/harness-test/SKILL.md +1 -1
- package/harness/bundles/general/codex/scripts/harness_archive.py +2061 -187
- package/harness/bundles/general/codex/scripts/harness_events.py +43 -9
- package/harness/bundles/general/codex/scripts/harness_gate.py +491 -7
- package/harness/bundles/general/codex/scripts/harness_integration.py +232 -0
- package/harness/bundles/general/codex/scripts/harness_phase.py +758 -1
- package/harness/bundles/general/codex/scripts/harness_plan_finalize.py +74 -0
- package/harness/bundles/general/codex/scripts/harness_retry.py +175 -0
- package/harness/bundles/general/codex/scripts/harness_test_guard.py +702 -22
- package/harness/bundles/general/cursor/.harness-build.json +1 -1
- package/harness/bundles/general/cursor/harness-archive/SKILL.md +1 -1
- package/harness/bundles/general/cursor/harness-archive/templates/render-summary.mjs +25 -6
- package/harness/bundles/general/cursor/harness-archive/templates/summary-data-template.json +44 -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-ingest/scripts/harness_knowledge.py +493 -74
- 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-submit/SKILL.md +1 -1
- package/harness/bundles/general/cursor/harness-sync/SKILL.md +1 -1
- package/harness/bundles/general/cursor/harness-test/SKILL.md +1 -1
- package/harness/bundles/general/cursor/scripts/harness_archive.py +2061 -187
- package/harness/bundles/general/cursor/scripts/harness_events.py +43 -9
- package/harness/bundles/general/cursor/scripts/harness_gate.py +491 -7
- package/harness/bundles/general/cursor/scripts/harness_integration.py +232 -0
- package/harness/bundles/general/cursor/scripts/harness_phase.py +758 -1
- package/harness/bundles/general/cursor/scripts/harness_plan_finalize.py +74 -0
- package/harness/bundles/general/cursor/scripts/harness_retry.py +175 -0
- package/harness/bundles/general/cursor/scripts/harness_test_guard.py +702 -22
- package/harness/bundles/java/claude-code/.harness-build.json +1 -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/templates/render-summary.mjs +25 -6
- package/harness/bundles/java/claude-code/harness-archive/templates/summary-data-template.json +44 -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-ingest/scripts/harness_knowledge.py +493 -74
- 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 +1 -1
- package/harness/bundles/java/claude-code/harness-test/SKILL.md +1 -1
- package/harness/bundles/java/claude-code/scripts/harness_archive.py +2061 -187
- package/harness/bundles/java/claude-code/scripts/harness_events.py +43 -9
- package/harness/bundles/java/claude-code/scripts/harness_gate.py +491 -7
- package/harness/bundles/java/claude-code/scripts/harness_integration.py +232 -0
- package/harness/bundles/java/claude-code/scripts/harness_phase.py +758 -1
- package/harness/bundles/java/claude-code/scripts/harness_plan_finalize.py +74 -0
- package/harness/bundles/java/claude-code/scripts/harness_retry.py +175 -0
- package/harness/bundles/java/claude-code/scripts/harness_test_guard.py +702 -22
- package/harness/bundles/java/codebuddy/.harness-build.json +1 -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/templates/render-summary.mjs +25 -6
- package/harness/bundles/java/codebuddy/harness-archive/templates/summary-data-template.json +44 -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-ingest/scripts/harness_knowledge.py +493 -74
- 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 +1 -1
- package/harness/bundles/java/codebuddy/harness-test/SKILL.md +1 -1
- package/harness/bundles/java/codebuddy/scripts/harness_archive.py +2061 -187
- package/harness/bundles/java/codebuddy/scripts/harness_events.py +43 -9
- package/harness/bundles/java/codebuddy/scripts/harness_gate.py +491 -7
- package/harness/bundles/java/codebuddy/scripts/harness_integration.py +232 -0
- package/harness/bundles/java/codebuddy/scripts/harness_phase.py +758 -1
- package/harness/bundles/java/codebuddy/scripts/harness_plan_finalize.py +74 -0
- package/harness/bundles/java/codebuddy/scripts/harness_retry.py +175 -0
- package/harness/bundles/java/codebuddy/scripts/harness_test_guard.py +702 -22
- package/harness/bundles/java/codex/.harness-build.json +1 -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/templates/render-summary.mjs +25 -6
- package/harness/bundles/java/codex/harness-archive/templates/summary-data-template.json +44 -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-ingest/scripts/harness_knowledge.py +493 -74
- 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 +1 -1
- package/harness/bundles/java/codex/harness-test/SKILL.md +1 -1
- package/harness/bundles/java/codex/scripts/harness_archive.py +2061 -187
- package/harness/bundles/java/codex/scripts/harness_events.py +43 -9
- package/harness/bundles/java/codex/scripts/harness_gate.py +491 -7
- package/harness/bundles/java/codex/scripts/harness_integration.py +232 -0
- package/harness/bundles/java/codex/scripts/harness_phase.py +758 -1
- package/harness/bundles/java/codex/scripts/harness_plan_finalize.py +74 -0
- package/harness/bundles/java/codex/scripts/harness_retry.py +175 -0
- package/harness/bundles/java/codex/scripts/harness_test_guard.py +702 -22
- package/harness/bundles/java/cursor/.harness-build.json +1 -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/templates/render-summary.mjs +25 -6
- package/harness/bundles/java/cursor/harness-archive/templates/summary-data-template.json +44 -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-ingest/scripts/harness_knowledge.py +493 -74
- 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 +1 -1
- package/harness/bundles/java/cursor/harness-test/SKILL.md +1 -1
- package/harness/bundles/java/cursor/scripts/harness_archive.py +2061 -187
- package/harness/bundles/java/cursor/scripts/harness_events.py +43 -9
- package/harness/bundles/java/cursor/scripts/harness_gate.py +491 -7
- package/harness/bundles/java/cursor/scripts/harness_integration.py +232 -0
- package/harness/bundles/java/cursor/scripts/harness_phase.py +758 -1
- package/harness/bundles/java/cursor/scripts/harness_plan_finalize.py +74 -0
- package/harness/bundles/java/cursor/scripts/harness_retry.py +175 -0
- package/harness/bundles/java/cursor/scripts/harness_test_guard.py +702 -22
- package/harness/manifests/general/claude-code.json +26 -22
- package/harness/manifests/general/codebuddy.json +26 -22
- package/harness/manifests/general/codex.json +26 -22
- package/harness/manifests/general/cursor.json +26 -22
- package/harness/manifests/java/claude-code.json +28 -24
- package/harness/manifests/java/codebuddy.json +28 -24
- package/harness/manifests/java/codex.json +28 -24
- package/harness/manifests/java/cursor.json +28 -24
- package/hunter-workflow-family.json +2 -2
- package/package.json +1 -1
|
@@ -51,12 +51,227 @@ _FOREIGN_PATTERNS = (
|
|
|
51
51
|
re.compile(r"^\.harness/changes/([^/]+)(/|$)"),
|
|
52
52
|
re.compile(r"^\.harness/state/changes/([^/]+)(/|$)"),
|
|
53
53
|
)
|
|
54
|
+
WORKTREE_LIFECYCLE_STATES = (
|
|
55
|
+
"REGISTERED",
|
|
56
|
+
"MATERIALIZED",
|
|
57
|
+
"AGENT_ATTACHED",
|
|
58
|
+
"ACTIVE",
|
|
59
|
+
"QUIESCING",
|
|
60
|
+
"AGENT_DETACHED",
|
|
61
|
+
"STATE_FINALIZED",
|
|
62
|
+
"REGISTRATION_REMOVED",
|
|
63
|
+
"RESIDUAL_CLEANED",
|
|
64
|
+
"RETIRED",
|
|
65
|
+
)
|
|
54
66
|
|
|
55
67
|
|
|
56
68
|
def now_iso() -> str:
|
|
57
69
|
return dt.datetime.now().astimezone().isoformat(timespec="milliseconds")
|
|
58
70
|
|
|
59
71
|
|
|
72
|
+
def _worktree_registrations(project_root: Path) -> dict[str, dict[str, Any]]:
|
|
73
|
+
proc = subprocess.run(
|
|
74
|
+
["git", "worktree", "list", "--porcelain"],
|
|
75
|
+
cwd=str(project_root),
|
|
76
|
+
capture_output=True,
|
|
77
|
+
text=True,
|
|
78
|
+
encoding="utf-8",
|
|
79
|
+
errors="replace",
|
|
80
|
+
check=False,
|
|
81
|
+
)
|
|
82
|
+
registrations: dict[str, dict[str, Any]] = {}
|
|
83
|
+
current: dict[str, Any] | None = None
|
|
84
|
+
for line in proc.stdout.splitlines() if proc.returncode == 0 else []:
|
|
85
|
+
if line.startswith("worktree "):
|
|
86
|
+
path = str(Path(line.removeprefix("worktree ")).resolve())
|
|
87
|
+
current = {"path": path, "branch": None, "head": None}
|
|
88
|
+
registrations[path] = current
|
|
89
|
+
elif current is not None and line.startswith("branch "):
|
|
90
|
+
current["branch"] = line.removeprefix("branch ")
|
|
91
|
+
elif current is not None and line.startswith("HEAD "):
|
|
92
|
+
current["head"] = line.removeprefix("HEAD ")
|
|
93
|
+
return registrations
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def _active_capsules_for_root(
|
|
97
|
+
project_root: Path,
|
|
98
|
+
target_root: Path,
|
|
99
|
+
change_dir: Path | None,
|
|
100
|
+
) -> list[dict[str, Any]]:
|
|
101
|
+
candidates: list[Path] = []
|
|
102
|
+
change_dirs = [change_dir.resolve()] if change_dir is not None else []
|
|
103
|
+
if not change_dirs:
|
|
104
|
+
for root in (
|
|
105
|
+
project_root / ".harness" / "changes",
|
|
106
|
+
project_root / ".harness" / "state" / "changes",
|
|
107
|
+
):
|
|
108
|
+
if root.is_dir():
|
|
109
|
+
change_dirs.extend(path for path in root.iterdir() if path.is_dir())
|
|
110
|
+
for root in change_dirs:
|
|
111
|
+
for capsule_root in (
|
|
112
|
+
root / "runtime" / "phase-context",
|
|
113
|
+
root / "phase-context",
|
|
114
|
+
):
|
|
115
|
+
if capsule_root.is_dir():
|
|
116
|
+
candidates.extend(sorted(capsule_root.glob("*.json")))
|
|
117
|
+
active: list[dict[str, Any]] = []
|
|
118
|
+
for path in candidates:
|
|
119
|
+
try:
|
|
120
|
+
capsule = json.loads(path.read_text(encoding="utf-8-sig"))
|
|
121
|
+
except (OSError, json.JSONDecodeError):
|
|
122
|
+
continue
|
|
123
|
+
if not isinstance(capsule, dict):
|
|
124
|
+
continue
|
|
125
|
+
raw_root = str(capsule.get("executionRoot") or "").strip()
|
|
126
|
+
if not raw_root:
|
|
127
|
+
continue
|
|
128
|
+
try:
|
|
129
|
+
same_root = Path(raw_root).resolve() == target_root
|
|
130
|
+
except OSError:
|
|
131
|
+
same_root = False
|
|
132
|
+
transaction = capsule.get("closeTransaction")
|
|
133
|
+
transaction_status = (
|
|
134
|
+
str(transaction.get("status") or "").upper()
|
|
135
|
+
if isinstance(transaction, dict)
|
|
136
|
+
else ""
|
|
137
|
+
)
|
|
138
|
+
closed = transaction_status == "CLOSED" or bool(
|
|
139
|
+
capsule.get("closedAt") and capsule.get("closeStatus")
|
|
140
|
+
)
|
|
141
|
+
if same_root and not closed:
|
|
142
|
+
active.append(
|
|
143
|
+
{
|
|
144
|
+
"path": str(path),
|
|
145
|
+
"phase": capsule.get("phase"),
|
|
146
|
+
"runId": capsule.get("runId"),
|
|
147
|
+
"transactionStatus": transaction_status or "OPEN",
|
|
148
|
+
}
|
|
149
|
+
)
|
|
150
|
+
return active
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
def evaluate_worktree_retirement(
|
|
154
|
+
project_root: Path,
|
|
155
|
+
target_root: Path,
|
|
156
|
+
*,
|
|
157
|
+
change_dir: Path | None = None,
|
|
158
|
+
agent_root: Path | None = None,
|
|
159
|
+
junction_dependencies: list[dict[str, Any]] | None = None,
|
|
160
|
+
) -> dict[str, Any]:
|
|
161
|
+
"""Journal a unified, read-only preflight for safe worktree retirement."""
|
|
162
|
+
project_root = project_root.resolve()
|
|
163
|
+
target_root = target_root.resolve()
|
|
164
|
+
registrations = _worktree_registrations(project_root)
|
|
165
|
+
registration = registrations.get(str(target_root))
|
|
166
|
+
active_capsules = _active_capsules_for_root(
|
|
167
|
+
project_root,
|
|
168
|
+
target_root,
|
|
169
|
+
change_dir,
|
|
170
|
+
)
|
|
171
|
+
if junction_dependencies is None:
|
|
172
|
+
junction_path = (
|
|
173
|
+
project_root
|
|
174
|
+
/ ".harness"
|
|
175
|
+
/ "config"
|
|
176
|
+
/ "junction-dependencies.json"
|
|
177
|
+
)
|
|
178
|
+
try:
|
|
179
|
+
loaded = json.loads(junction_path.read_text(encoding="utf-8-sig"))
|
|
180
|
+
except (OSError, json.JSONDecodeError):
|
|
181
|
+
loaded = []
|
|
182
|
+
junction_dependencies = loaded if isinstance(loaded, list) else []
|
|
183
|
+
matching_junctions = []
|
|
184
|
+
for item in junction_dependencies:
|
|
185
|
+
if not isinstance(item, dict):
|
|
186
|
+
continue
|
|
187
|
+
try:
|
|
188
|
+
matches = Path(str(item.get("target") or "")).resolve() == target_root
|
|
189
|
+
except OSError:
|
|
190
|
+
matches = False
|
|
191
|
+
if matches:
|
|
192
|
+
matching_junctions.append(item)
|
|
193
|
+
attached = False
|
|
194
|
+
if agent_root is not None:
|
|
195
|
+
try:
|
|
196
|
+
resolved_agent = agent_root.resolve()
|
|
197
|
+
attached = (
|
|
198
|
+
resolved_agent == target_root
|
|
199
|
+
or target_root in resolved_agent.parents
|
|
200
|
+
)
|
|
201
|
+
except OSError:
|
|
202
|
+
attached = True
|
|
203
|
+
blockers: list[dict[str, Any]] = []
|
|
204
|
+
if active_capsules:
|
|
205
|
+
blockers.append(
|
|
206
|
+
{
|
|
207
|
+
"code": "ACTIVE_PHASE_CAPSULE",
|
|
208
|
+
"message": "phase capsules still reference the worktree",
|
|
209
|
+
"capsules": active_capsules,
|
|
210
|
+
}
|
|
211
|
+
)
|
|
212
|
+
if attached:
|
|
213
|
+
blockers.append(
|
|
214
|
+
{
|
|
215
|
+
"code": "AGENT_STILL_ATTACHED",
|
|
216
|
+
"message": "Agent root/cwd still points into the worktree",
|
|
217
|
+
"agentRoot": str(agent_root.resolve()) if agent_root else None,
|
|
218
|
+
}
|
|
219
|
+
)
|
|
220
|
+
if matching_junctions:
|
|
221
|
+
blockers.append(
|
|
222
|
+
{
|
|
223
|
+
"code": "JUNCTION_DEPENDENCY_ACTIVE",
|
|
224
|
+
"message": "junction dependencies must be removed or migrated",
|
|
225
|
+
"junctions": matching_junctions,
|
|
226
|
+
}
|
|
227
|
+
)
|
|
228
|
+
receipt = {
|
|
229
|
+
"schemaVersion": 1,
|
|
230
|
+
"lifecycleId": hashlib.sha256(
|
|
231
|
+
str(target_root).encode("utf-8")
|
|
232
|
+
).hexdigest()[:20],
|
|
233
|
+
"projectRoot": str(project_root),
|
|
234
|
+
"targetRoot": str(target_root),
|
|
235
|
+
"state": "ACTIVE" if blockers else "QUIESCING",
|
|
236
|
+
"allowedStates": list(WORKTREE_LIFECYCLE_STATES),
|
|
237
|
+
"registration": registration,
|
|
238
|
+
"diskPathPresent": target_root.exists(),
|
|
239
|
+
"agentAttached": attached,
|
|
240
|
+
"activeCapsules": active_capsules,
|
|
241
|
+
"junctionDependencies": matching_junctions,
|
|
242
|
+
"blockers": blockers,
|
|
243
|
+
"ok": not blockers,
|
|
244
|
+
"code": (
|
|
245
|
+
"WORKTREE_RETIREMENT_READY"
|
|
246
|
+
if not blockers
|
|
247
|
+
else "WORKTREE_RETIREMENT_BLOCKED"
|
|
248
|
+
),
|
|
249
|
+
"updatedAt": now_iso(),
|
|
250
|
+
}
|
|
251
|
+
receipt_path = (
|
|
252
|
+
project_root
|
|
253
|
+
/ ".harness"
|
|
254
|
+
/ "runtime"
|
|
255
|
+
/ "worktree-lifecycle"
|
|
256
|
+
/ f"{receipt['lifecycleId']}.json"
|
|
257
|
+
)
|
|
258
|
+
receipt_path.parent.mkdir(parents=True, exist_ok=True)
|
|
259
|
+
temporary = receipt_path.with_name(
|
|
260
|
+
f".{receipt_path.name}.{os.getpid()}.tmp"
|
|
261
|
+
)
|
|
262
|
+
try:
|
|
263
|
+
temporary.write_text(
|
|
264
|
+
json.dumps(receipt, ensure_ascii=False, indent=2) + "\n",
|
|
265
|
+
encoding="utf-8",
|
|
266
|
+
newline="\n",
|
|
267
|
+
)
|
|
268
|
+
os.replace(temporary, receipt_path)
|
|
269
|
+
finally:
|
|
270
|
+
temporary.unlink(missing_ok=True)
|
|
271
|
+
receipt["receiptPath"] = str(receipt_path)
|
|
272
|
+
return receipt
|
|
273
|
+
|
|
274
|
+
|
|
60
275
|
def _split_verify_command(raw: str, *, platform: str = sys.platform) -> list[str]:
|
|
61
276
|
# Harness profile/CLI commands use one portable quoting contract. Keep
|
|
62
277
|
# POSIX tokenization on Windows too; executable normalization happens later.
|
|
@@ -1269,6 +1484,23 @@ class IntegrationTransaction:
|
|
|
1269
1484
|
raise CleanupRefusedError(
|
|
1270
1485
|
f"refusing to clean unregistered worktree path: {resolved}"
|
|
1271
1486
|
)
|
|
1487
|
+
lifecycle = evaluate_worktree_retirement(
|
|
1488
|
+
self.project_root,
|
|
1489
|
+
resolved,
|
|
1490
|
+
agent_root=(
|
|
1491
|
+
Path(os.environ["HUNTER_HARNESS_AGENT_ROOT"])
|
|
1492
|
+
if os.environ.get("HUNTER_HARNESS_AGENT_ROOT")
|
|
1493
|
+
else None
|
|
1494
|
+
),
|
|
1495
|
+
)
|
|
1496
|
+
if not lifecycle.get("ok"):
|
|
1497
|
+
codes = ", ".join(
|
|
1498
|
+
str(item.get("code") or "UNKNOWN")
|
|
1499
|
+
for item in lifecycle.get("blockers") or []
|
|
1500
|
+
)
|
|
1501
|
+
raise CleanupRefusedError(
|
|
1502
|
+
f"worktree lifecycle blocks cleanup: {codes}"
|
|
1503
|
+
)
|
|
1272
1504
|
|
|
1273
1505
|
heavy_removed: list[str] = []
|
|
1274
1506
|
heavy_failures: list[dict[str, str]] = []
|