@mstar-harness/engine 3.8.3 → 3.9.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/audit.js CHANGED
@@ -186,6 +186,10 @@ function isAtOrBelow(dir, root) {
186
186
  return rel === "" || !rel.startsWith("..") && !isAbsolute2(rel);
187
187
  }
188
188
 
189
+ // src/status.ts
190
+ import { existsSync as existsSync3, readFileSync as readFileSync3, readdirSync as readdirSync2, realpathSync } from "node:fs";
191
+ import { dirname as dirname4, join as join5, resolve as resolve5, sep } from "node:path";
192
+
189
193
  // src/store.ts
190
194
  import { existsSync as existsSync2, readdirSync, unlinkSync as unlinkSync3 } from "node:fs";
191
195
  import { isAbsolute as isAbsolute3, join as join4, resolve as resolve4 } from "node:path";
@@ -318,10 +322,6 @@ function assertFsStorePath(store, ref, expectedPath) {
318
322
  }
319
323
  }
320
324
 
321
- // src/status.ts
322
- import { existsSync as existsSync3, readFileSync as readFileSync3, readdirSync as readdirSync2, realpathSync } from "node:fs";
323
- import { dirname as dirname4, join as join5, resolve as resolve5, sep } from "node:path";
324
-
325
325
  // src/workflow.ts
326
326
  var WORKFLOW_SNAPSHOT_FILE = "snapshot.json";
327
327
  var WORKFLOW_TERMINAL_STATUSES = ["completed", "failed", "stopped"];
@@ -0,0 +1,90 @@
1
+ /**
2
+ * Engine cleanup module — pure worktree/branch cleanup planner.
3
+ *
4
+ * `planWorktreeCleanup` is the ONE planner ( — no `planBranchCleanup`, no
5
+ * injected callback/git probe, no IO/time/env access): immutable facts in,
6
+ * one stable decision per candidate out, in input order, facts never
7
+ * mutated. The CLI alone probes Git/state and applies current decisions;
8
+ * the planner only classifies.
9
+ *
10
+ * Behavior contract (locked):
11
+ * - Locked interface block, candidate ownership/attribution, decision
12
+ * precedence, two timing lanes and every `cleanup.*` machine code are a
13
+ * stable contract: consumers match on the exact codes, so both codes and
14
+ * precedence may only change as a deliberate contract update.
15
+ * - Reuses the P1 canonical snapshot shape (`WorkflowSnapshot`) and the P2
16
+ * terminal predicate (`isTerminalSnapshot`); snapshot/terminal semantics
17
+ * are never re-derived here.
18
+ *
19
+ * Locked decision precedence (first match wins):
20
+ * 1. main-worktree keep → cleanup.keep.main-worktree
21
+ * 2. default/base-ref keep → cleanup.keep.protected-ref
22
+ * 3. active execution/merge lease → cleanup.refuse.active-lease
23
+ * 4. missing/foreign ownership → cleanup.refuse.foreign-worktree /
24
+ * cleanup.refuse.foreign-branch
25
+ * 5. non-terminal integration or non-Done plan
26
+ * → cleanup.refuse.non-terminal
27
+ * 6. branch checked out anywhere → cleanup.refuse.checked-out
28
+ * 7. unmerged/missing evidence → cleanup.refuse.unmerged
29
+ * 8. dirty/locked worktree → cleanup.refuse.dirty-worktree /
30
+ * cleanup.refuse.locked-worktree
31
+ * 9. eligible → cleanup.remove.merged
32
+ *
33
+ * Guard scoping locked by the spec: the checked-out guard applies to branch
34
+ * deletion (local and remote candidates), never to removal of the eligible
35
+ * owned worktree (otherwise physical cleanup could never remove a normal
36
+ * attached worktree — dry-run correctly prints worktree `remove` plus its
37
+ * branch `refuse` until the post-removal re-plan). Merged evidence is a
38
+ * branch-deletion precondition; removing a clean owned worktree loses no
39
+ * commits, so worktree decisions are gated by ownership/eligibility and
40
+ * cleanliness/lock only. Non-terminal integration branches/worktrees and
41
+ * non-Done plan/track branches stay protected across ALL supplied
42
+ * lifecycles, not only the selected one; a main worktree is never removed
43
+ * and its branch candidate is independently protected by the ordinary
44
+ * rules.
45
+ */
46
+ import { type WorkflowSnapshot } from "./workflow.js";
47
+ export type CleanupTargetKind = "worktree" | "local-branch" | "remote-branch";
48
+ export type CleanupTarget = {
49
+ kind: CleanupTargetKind;
50
+ ref: string;
51
+ branch: string;
52
+ tip: string;
53
+ owner: {
54
+ workflowId: string;
55
+ planId?: string;
56
+ } | null;
57
+ };
58
+ export type CleanupDecision = {
59
+ kind: CleanupTargetKind;
60
+ ref: string;
61
+ verdict: "remove" | "keep" | "refuse";
62
+ reason: string;
63
+ };
64
+ export type CleanupFacts = {
65
+ targets: readonly CleanupTarget[];
66
+ worktrees: readonly {
67
+ path: string;
68
+ branch: string | null;
69
+ isMain: boolean;
70
+ clean: boolean;
71
+ locked: boolean;
72
+ }[];
73
+ snapshots: readonly WorkflowSnapshot[];
74
+ defaultBranch: string;
75
+ mergedLocalBranches: Readonly<Record<string, readonly string[]>>;
76
+ remoteEvidence: readonly {
77
+ branch: string;
78
+ tip: string;
79
+ base: string;
80
+ ancestor: boolean;
81
+ prMerged: boolean | null;
82
+ }[];
83
+ };
84
+ /**
85
+ * Pure cleanup planner ( — locked interface). Consumes immutable facts,
86
+ * returns exactly one decision per candidate in input order, never mutates
87
+ * its inputs and never touches Git, the filesystem, the clock or the
88
+ * environment.
89
+ */
90
+ export declare function planWorktreeCleanup(snapshot: WorkflowSnapshot, facts: CleanupFacts): CleanupDecision[];