@cleocode/git-shim 2026.4.154 → 2026.4.158

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/shim.js CHANGED
@@ -1,35 +1,40 @@
1
1
  #!/usr/bin/env node
2
2
  /**
3
- * git-shim — harness-agnostic git branch-mutation fence (T1118 L2).
3
+ * git-shim — harness-agnostic git fence (T1118 L2 + T1591 boundary fence).
4
4
  *
5
5
  * Usage: place this binary on PATH BEFORE real git, and export:
6
6
  * CLEO_AGENT_ROLE=worker (or lead|subagent)
7
- * CLEO_WORKTREE_ROOT=<path>
7
+ * CLEO_WORKTREE_ROOT=<path> (optional — auto-detected from cwd)
8
+ * CLEO_TASK_ID=T<NUM> (optional — auto-detected from worktree path)
8
9
  *
9
- * Behaviour:
10
- * - If CLEO_AGENT_ROLE is a restricted role AND the git subcommand is in
11
- * the denylist AND CLEO_ALLOW_BRANCH_OPS is not set: print structured
12
- * error to stderr, exit 1.
13
- * - If CLEO_ALLOW_BRANCH_OPS=1: log a warning and pass through (escape hatch).
14
- * - Otherwise: exec real git with all original args (zero overhead path).
10
+ * Layered enforcement (in order, all under restricted-role gate):
11
+ * 1. T1118 denylist (branch-mutation ops). Bypass: `CLEO_ALLOW_BRANCH_OPS=1`.
12
+ * 2. T1591 boundary fence:
13
+ * (a) git add path inside worktree
14
+ * (b) git commit subject contains T-ID
15
+ * (c) git merge requires CLEO_ORCHESTRATE_MERGE=1
16
+ * (d) git cherry-pick refuses task/T<NUM> source
17
+ * Bypass any of (a)-(d): `CLEO_ALLOW_GIT=1` (audited).
15
18
  *
16
- * The real git binary is resolved from CLEO_REAL_GIT_PATH env (override) or
17
- * discovered by walking PATH and skipping any entry that resolves to this
18
- * shim itself (detected via CLEO_SHIM_MARKER env set by the shim installer).
19
+ * Audit log at `<XDG>/cleo/audit/git-shim.jsonl` (override `CLEO_AUDIT_LOG_PATH`).
19
20
  *
20
21
  * Exit codes:
21
- * 0 — passthrough succeeded (real git exited 0)
22
- * 1 — git op blocked by shim
23
- * 77 — well-known CLEO_GIT_BLOCKED sentinel (same as exit 1 but distinguishable)
22
+ * 0 — passthrough succeeded
23
+ * 1 — generic shim error (real git not found)
24
+ * 77 — CLEO_GIT_BLOCKED sentinel (legacy denylist + new boundary fence)
24
25
  * N — real git exit code propagated
25
26
  *
26
27
  * @task T1118
27
28
  * @task T1121
29
+ * @task T1591
28
30
  */
29
31
  import { spawnSync } from 'node:child_process';
30
32
  import { existsSync } from 'node:fs';
31
33
  import { join } from 'node:path';
34
+ import { writeAuditRecord } from './audit-log.js';
35
+ import { validateAddPaths, validateCherryPickSource, validateCommitSubject, validateMergeAllowed, } from './boundary.js';
32
36
  import { findDeniedOp, RESTRICTED_ROLES } from './denylist.js';
37
+ import { resolveActiveWorktree } from './worktree-path.js';
33
38
  /** Sentinel exit code for a shim-blocked git operation. */
34
39
  const BLOCKED_EXIT_CODE = 77;
35
40
  /**
@@ -48,27 +53,24 @@ function getAgentRole() {
48
53
  *
49
54
  * Strategy:
50
55
  * 1. If CLEO_REAL_GIT_PATH env is set, use it (override for testing).
51
- * 2. Walk PATH entries, skip the first one that contains CLEO_SHIM_MARKER.
56
+ * 2. Walk PATH entries, skip any that contain CLEO_SHIM_MARKER.
52
57
  * 3. Fall back to /usr/bin/git, /usr/local/bin/git, /opt/homebrew/bin/git.
53
58
  *
54
59
  * @returns Absolute path to real git, or null if not found.
55
60
  */
56
61
  function resolveRealGit() {
57
- // Explicit override wins — useful for tests.
58
62
  const override = process.env['CLEO_REAL_GIT_PATH'];
59
63
  if (override && existsSync(override))
60
64
  return override;
61
65
  const shimMarker = process.env['CLEO_SHIM_MARKER'] ?? '.cleo/bin/git-shim';
62
66
  const pathDirs = (process.env['PATH'] ?? '').split(':');
63
67
  for (const dir of pathDirs) {
64
- // Skip directories that look like the shim directory.
65
68
  if (dir.includes(shimMarker))
66
69
  continue;
67
70
  const candidate = join(dir, 'git');
68
71
  if (existsSync(candidate))
69
72
  return candidate;
70
73
  }
71
- // Hard fallbacks for common installations.
72
74
  const fallbacks = ['/usr/bin/git', '/usr/local/bin/git', '/opt/homebrew/bin/git'];
73
75
  for (const fb of fallbacks) {
74
76
  if (existsSync(fb))
@@ -86,24 +88,103 @@ function resolveRealGit() {
86
88
  * @param context - Additional key/value context.
87
89
  */
88
90
  function emitBlockedError(code, message, context) {
89
- process.stderr.write(JSON.stringify({
91
+ process.stderr.write(`${JSON.stringify({
90
92
  cleo_error: true,
91
93
  code,
92
94
  message,
93
95
  ...context,
94
- }) + '\n');
95
- // Also emit a plain-text line so human readers can understand without parsing.
96
- process.stderr.write(`[git-shim] BLOCKED: ${message}\n` +
97
- `[git-shim] Set CLEO_ALLOW_BRANCH_OPS=1 to bypass (audited).\n`);
96
+ })}\n`);
97
+ process.stderr.write(`[git-shim] BLOCKED: ${message}\n`);
98
+ }
99
+ /**
100
+ * Emit a boundary violation to stderr in a uniform format.
101
+ *
102
+ * @param violation - Predicate-emitted violation.
103
+ * @param subcommand - Git subcommand under inspection.
104
+ */
105
+ function emitBoundaryViolation(violation, subcommand) {
106
+ emitBlockedError(violation.code, violation.message, {
107
+ boundary: violation.boundary,
108
+ subcommand,
109
+ ...violation.context,
110
+ });
111
+ process.stderr.write(`[git-shim] FIX: ${violation.remediation}\n`);
112
+ }
113
+ /**
114
+ * Apply the four T1591 boundary checks for the given subcommand.
115
+ *
116
+ * @param subcommand - Git subcommand (argv[0]).
117
+ * @param args - Remaining argv entries.
118
+ * @returns A boundary violation when blocked, else null.
119
+ */
120
+ function evaluateBoundaries(subcommand, args) {
121
+ const cwd = process.cwd();
122
+ const active = resolveActiveWorktree(cwd);
123
+ // Boundary (a) — git add path inside worktree (only meaningful when active).
124
+ if (subcommand === 'add' && active) {
125
+ const v = validateAddPaths(args, cwd, active.worktreePath);
126
+ if (v)
127
+ return v;
128
+ }
129
+ // Boundary (b) — commit subject contains a task ID.
130
+ if (subcommand === 'commit') {
131
+ const expected = active ? active.taskId : null;
132
+ const v = validateCommitSubject(args, expected);
133
+ if (v)
134
+ return v;
135
+ }
136
+ // Boundary (c) — merge gated by CLEO_ORCHESTRATE_MERGE.
137
+ if (subcommand === 'merge') {
138
+ const v = validateMergeAllowed(args, {
139
+ CLEO_ORCHESTRATE_MERGE: process.env['CLEO_ORCHESTRATE_MERGE'],
140
+ });
141
+ if (v)
142
+ return v;
143
+ }
144
+ // Boundary (d) — cherry-pick rejects task/T<NUM> sources.
145
+ if (subcommand === 'cherry-pick') {
146
+ const v = validateCherryPickSource(args);
147
+ if (v)
148
+ return v;
149
+ }
150
+ return null;
151
+ }
152
+ /**
153
+ * Build a structured audit record for the current invocation.
154
+ *
155
+ * @param outcome - "blocked" | "bypassed-allow-git" | "bypassed-orchestrate-merge".
156
+ * @param boundary - Which boundary fired (a-d, or "denylist").
157
+ * @param code - CLEO error code.
158
+ * @param subcommand - Git subcommand.
159
+ * @param args - Argv tail.
160
+ * @param context - Free-form per-violation context.
161
+ * @returns Fully populated audit record.
162
+ */
163
+ function buildAuditRecord(outcome, boundary, code, subcommand, args, context) {
164
+ const cwd = process.cwd();
165
+ const active = resolveActiveWorktree(cwd);
166
+ return {
167
+ ts: new Date().toISOString(),
168
+ outcome,
169
+ boundary,
170
+ code,
171
+ subcommand,
172
+ args,
173
+ cwd,
174
+ worktree_path: active?.worktreePath ?? null,
175
+ task_id: active?.taskId ?? null,
176
+ role: process.env['CLEO_AGENT_ROLE'] ?? null,
177
+ context,
178
+ };
98
179
  }
99
180
  /**
100
181
  * Main shim entry point.
101
182
  *
102
- * Reads argv, env, applies the denylist, and either blocks or passes through
103
- * to the real git binary.
183
+ * Reads argv, env, applies the denylist + the boundary fence, and either
184
+ * blocks or passes through to the real git binary.
104
185
  */
105
186
  function main() {
106
- const argv = process.argv.slice(2); // strip "node" and shim path
187
+ const argv = process.argv.slice(2);
107
188
  const subcommand = argv[0];
108
189
  // Fast path: no subcommand → pass through (git with no args shows usage).
109
190
  if (!subcommand) {
@@ -128,11 +209,14 @@ function main() {
128
209
  process.exit(result.status ?? 1);
129
210
  return;
130
211
  }
131
- // Check escape hatch — operator has explicitly permitted this one invocation.
132
- const allowBranchOps = process.env['CLEO_ALLOW_BRANCH_OPS'] === '1';
133
212
  const remainingArgs = argv.slice(1);
213
+ const allowBranchOps = process.env['CLEO_ALLOW_BRANCH_OPS'] === '1';
214
+ const allowGit = process.env['CLEO_ALLOW_GIT'] === '1';
215
+ // ---------------------------------------------------------------------------
216
+ // Layer 1 — T1118 denylist (branch-mutation ops).
217
+ // ---------------------------------------------------------------------------
134
218
  const denied = findDeniedOp(subcommand, remainingArgs);
135
- if (denied && !allowBranchOps) {
219
+ if (denied && !allowBranchOps && !allowGit) {
136
220
  const worktreeRoot = process.env['CLEO_WORKTREE_ROOT'] ?? '(unknown)';
137
221
  emitBlockedError('E_GIT_OP_BLOCKED', `git ${subcommand}${denied.flag ? ` ${denied.flag}` : ''} is not allowed for role '${role}': ${denied.reason}`, {
138
222
  subcommand,
@@ -140,15 +224,36 @@ function main() {
140
224
  role,
141
225
  worktree_root: worktreeRoot,
142
226
  });
227
+ writeAuditRecord(buildAuditRecord('blocked', 'denylist', 'E_GIT_OP_BLOCKED', subcommand, remainingArgs, {
228
+ flag: denied.flag ?? '',
229
+ reason: denied.reason,
230
+ }));
231
+ process.exit(BLOCKED_EXIT_CODE);
232
+ return;
233
+ }
234
+ if (denied && (allowBranchOps || allowGit)) {
235
+ process.stderr.write(`[git-shim] WARNING: ${allowBranchOps ? 'CLEO_ALLOW_BRANCH_OPS' : 'CLEO_ALLOW_GIT'}=1 ` +
236
+ `bypassed denylist for 'git ${subcommand}' (role=${role}). This bypass is audited.\n`);
237
+ writeAuditRecord(buildAuditRecord('bypassed-allow-git', 'denylist', 'E_GIT_OP_BLOCKED', subcommand, remainingArgs, { flag: denied.flag ?? '', reason: denied.reason }));
238
+ }
239
+ // ---------------------------------------------------------------------------
240
+ // Layer 2 — T1591 boundary fence (a/b/c/d).
241
+ // ---------------------------------------------------------------------------
242
+ const violation = evaluateBoundaries(subcommand, remainingArgs);
243
+ if (violation && !allowGit) {
244
+ emitBoundaryViolation(violation, subcommand);
245
+ writeAuditRecord(buildAuditRecord('blocked', violation.boundary, violation.code, subcommand, remainingArgs, violation.context));
143
246
  process.exit(BLOCKED_EXIT_CODE);
144
247
  return;
145
248
  }
146
- if (denied && allowBranchOps) {
147
- // Escape hatch used — log an audit warning.
148
- process.stderr.write(`[git-shim] WARNING: CLEO_ALLOW_BRANCH_OPS=1 bypassed block for ` +
149
- `'git ${subcommand}' (role=${role}). This bypass is audited.\n`);
249
+ if (violation && allowGit) {
250
+ process.stderr.write(`[git-shim] WARNING: CLEO_ALLOW_GIT=1 bypassed boundary ${violation.boundary} ` +
251
+ `(${violation.code}) for 'git ${subcommand}' (role=${role}). This bypass is audited.\n`);
252
+ writeAuditRecord(buildAuditRecord('bypassed-allow-git', violation.boundary, violation.code, subcommand, remainingArgs, violation.context));
150
253
  }
254
+ // ---------------------------------------------------------------------------
151
255
  // Pass through to real git.
256
+ // ---------------------------------------------------------------------------
152
257
  const realGit = resolveRealGit();
153
258
  if (!realGit) {
154
259
  process.stderr.write('[git-shim] ERROR: real git binary not found on PATH\n');
package/dist/shim.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"shim.js","sourceRoot":"","sources":["../src/shim.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC/C,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAE/D,2DAA2D;AAC3D,MAAM,iBAAiB,GAAG,EAAE,CAAC;AAE7B;;;;GAIG;AACH,SAAS,YAAY;IACnB,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC;IAC5C,IAAI,CAAC,IAAI;QAAE,OAAO,IAAI,CAAC;IACvB,OAAO,gBAAgB,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;AAClD,CAAC;AAED;;;;;;;;;GASG;AACH,SAAS,cAAc;IACrB,6CAA6C;IAC7C,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC,CAAC;IACnD,IAAI,QAAQ,IAAI,UAAU,CAAC,QAAQ,CAAC;QAAE,OAAO,QAAQ,CAAC;IAEtD,MAAM,UAAU,GAAG,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC,IAAI,oBAAoB,CAAC;IAC3E,MAAM,QAAQ,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAExD,KAAK,MAAM,GAAG,IAAI,QAAQ,EAAE,CAAC;QAC3B,sDAAsD;QACtD,IAAI,GAAG,CAAC,QAAQ,CAAC,UAAU,CAAC;YAAE,SAAS;QACvC,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;QACnC,IAAI,UAAU,CAAC,SAAS,CAAC;YAAE,OAAO,SAAS,CAAC;IAC9C,CAAC;IAED,2CAA2C;IAC3C,MAAM,SAAS,GAAG,CAAC,cAAc,EAAE,oBAAoB,EAAE,uBAAuB,CAAC,CAAC;IAClF,KAAK,MAAM,EAAE,IAAI,SAAS,EAAE,CAAC;QAC3B,IAAI,UAAU,CAAC,EAAE,CAAC;YAAE,OAAO,EAAE,CAAC;IAChC,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;;;;;GAQG;AACH,SAAS,gBAAgB,CAAC,IAAY,EAAE,OAAe,EAAE,OAA+B;IACtF,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,IAAI,CAAC,SAAS,CAAC;QACb,UAAU,EAAE,IAAI;QAChB,IAAI;QACJ,OAAO;QACP,GAAG,OAAO;KACX,CAAC,GAAG,IAAI,CACV,CAAC;IACF,+EAA+E;IAC/E,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,uBAAuB,OAAO,IAAI;QAChC,+DAA+D,CAClE,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,SAAS,IAAI;IACX,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,6BAA6B;IACjE,MAAM,UAAU,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;IAE3B,0EAA0E;IAC1E,IAAI,CAAC,UAAU,EAAE,CAAC;QAChB,MAAM,OAAO,GAAG,cAAc,EAAE,CAAC;QACjC,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,+CAA+C,CAAC,CAAC;YACtE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QACD,MAAM,MAAM,GAAG,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC,CAAC;QAC9D,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,IAAI,CAAC,CAAC,CAAC;QACjC,OAAO;IACT,CAAC;IAED,MAAM,IAAI,GAAG,YAAY,EAAE,CAAC;IAE5B,gEAAgE;IAChE,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,MAAM,OAAO,GAAG,cAAc,EAAE,CAAC;QACjC,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,+CAA+C,CAAC,CAAC;YACtE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QACD,MAAM,MAAM,GAAG,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC,CAAC;QAC9D,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,IAAI,CAAC,CAAC,CAAC;QACjC,OAAO;IACT,CAAC;IAED,8EAA8E;IAC9E,MAAM,cAAc,GAAG,OAAO,CAAC,GAAG,CAAC,uBAAuB,CAAC,KAAK,GAAG,CAAC;IAEpE,MAAM,aAAa,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACpC,MAAM,MAAM,GAAG,YAAY,CAAC,UAAU,EAAE,aAAa,CAAC,CAAC;IAEvD,IAAI,MAAM,IAAI,CAAC,cAAc,EAAE,CAAC;QAC9B,MAAM,YAAY,GAAG,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC,IAAI,WAAW,CAAC;QACtE,gBAAgB,CACd,kBAAkB,EAClB,OAAO,UAAU,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,6BAA6B,IAAI,MAAM,MAAM,CAAC,MAAM,EAAE,EAC9G;YACE,UAAU;YACV,IAAI,EAAE,MAAM,CAAC,IAAI,IAAI,EAAE;YACvB,IAAI;YACJ,aAAa,EAAE,YAAY;SAC5B,CACF,CAAC;QACF,OAAO,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;QAChC,OAAO;IACT,CAAC;IAED,IAAI,MAAM,IAAI,cAAc,EAAE,CAAC;QAC7B,4CAA4C;QAC5C,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,iEAAiE;YAC/D,QAAQ,UAAU,WAAW,IAAI,8BAA8B,CAClE,CAAC;IACJ,CAAC;IAED,4BAA4B;IAC5B,MAAM,OAAO,GAAG,cAAc,EAAE,CAAC;IACjC,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,uDAAuD,CAAC,CAAC;QAC9E,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,MAAM,MAAM,GAAG,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC,CAAC;IAC9D,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,IAAI,CAAC,CAAC,CAAC;AACnC,CAAC;AAED,IAAI,EAAE,CAAC"}
1
+ {"version":3,"file":"shim.js","sourceRoot":"","sources":["../src/shim.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,69 @@
1
+ /**
2
+ * Compute the canonical worktrees-by-project root used by CLEO.
3
+ *
4
+ * @returns Absolute path to `<XDG>/cleo/worktrees/`.
5
+ *
6
+ * @task T1591
7
+ */
8
+ export declare function resolveCleoWorktreesRoot(): string;
9
+ /**
10
+ * Compute the per-project worktree root.
11
+ *
12
+ * @param projectRoot - Absolute path to the project.
13
+ * @returns Absolute path to `<XDG>/cleo/worktrees/<projectHash>/`.
14
+ *
15
+ * @task T1591
16
+ */
17
+ export declare function resolveProjectWorktreeRoot(projectRoot: string): string;
18
+ /**
19
+ * Check whether the given path is inside the canonical worktrees tree.
20
+ *
21
+ * Project-agnostic: matches the global worktrees root, not a specific project.
22
+ *
23
+ * @param cwdPath - Absolute path to check.
24
+ * @returns true if the path is inside `<XDG>/cleo/worktrees/`.
25
+ *
26
+ * @task T1591
27
+ */
28
+ export declare function isInsideWorktreesRoot(cwdPath: string): boolean;
29
+ /**
30
+ * Extract the task ID from a worktree path.
31
+ *
32
+ * Path layout: `<XDG>/cleo/worktrees/<projectHash>/<taskId>/...`
33
+ * The taskId is the path segment immediately after the projectHash.
34
+ *
35
+ * @param cwdPath - Absolute path inside a worktree.
36
+ * @returns The task ID segment, or null if the path is not inside the worktrees root.
37
+ *
38
+ * @task T1591
39
+ */
40
+ export declare function extractTaskIdFromWorktreePath(cwdPath: string): string | null;
41
+ /**
42
+ * Resolve the agent worktree boundary for the current shim invocation.
43
+ *
44
+ * Strategy (in order):
45
+ * 1. `CLEO_WORKTREE_ROOT` env — explicit worktree path injected by the spawn prompt.
46
+ * 2. Walk up from `cwd` until a directory under `<XDG>/cleo/worktrees/<projectHash>/<taskId>/`
47
+ * is found.
48
+ * 3. Return null when not inside any worktree.
49
+ *
50
+ * @param cwd - Working directory at shim invocation time.
51
+ * @returns The worktree root path + task ID, or null when not inside a worktree.
52
+ *
53
+ * @task T1591
54
+ */
55
+ export declare function resolveActiveWorktree(cwd: string): {
56
+ worktreePath: string;
57
+ taskId: string;
58
+ } | null;
59
+ /**
60
+ * Check whether an absolute path lives inside the given worktree.
61
+ *
62
+ * @param targetPath - Absolute path to test.
63
+ * @param worktreePath - Absolute path to the worktree root.
64
+ * @returns true if `targetPath` is the worktree or a descendant.
65
+ *
66
+ * @task T1591
67
+ */
68
+ export declare function isPathInsideWorktree(targetPath: string, worktreePath: string): boolean;
69
+ //# sourceMappingURL=worktree-path.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"worktree-path.d.ts","sourceRoot":"","sources":["../src/worktree-path.ts"],"names":[],"mappings":"AAqBA;;;;;;GAMG;AACH,wBAAgB,wBAAwB,IAAI,MAAM,CAGjD;AAED;;;;;;;GAOG;AACH,wBAAgB,0BAA0B,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAGtE;AAED;;;;;;;;;GASG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAS9D;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,6BAA6B,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAe5E;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,qBAAqB,CACnC,GAAG,EAAE,MAAM,GACV;IAAE,YAAY,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CA+BjD;AAED;;;;;;;;GAQG;AACH,wBAAgB,oBAAoB,CAAC,UAAU,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,OAAO,CAItF"}
@@ -0,0 +1,146 @@
1
+ /**
2
+ * Worktree-path resolution for the git-shim (T1591 L2 boundary fence).
3
+ *
4
+ * Mirrors `@cleocode/core::resolveAgentWorktreeRoot` so the shim can decide
5
+ * "is this `cwd` inside an agent worktree?" without taking a runtime
6
+ * dependency on `@cleocode/core` (the shim must stay lean — it spawns on every
7
+ * git invocation).
8
+ *
9
+ * The shim resolves the worktree root via XDG env-paths convention:
10
+ * `$XDG_DATA_HOME/cleo/worktrees/<projectHash>/<taskId>/`
11
+ * fallback: `~/.local/share/cleo/worktrees/<projectHash>/<taskId>/`
12
+ *
13
+ * `<projectHash>` is sha256(projectRoot)[:16].
14
+ *
15
+ * @task T1591
16
+ * @adr ADR-062
17
+ */
18
+ import { createHash } from 'node:crypto';
19
+ import { homedir } from 'node:os';
20
+ import { isAbsolute, join, normalize, resolve } from 'node:path';
21
+ /**
22
+ * Compute the canonical worktrees-by-project root used by CLEO.
23
+ *
24
+ * @returns Absolute path to `<XDG>/cleo/worktrees/`.
25
+ *
26
+ * @task T1591
27
+ */
28
+ export function resolveCleoWorktreesRoot() {
29
+ const xdgData = process.env['XDG_DATA_HOME'] ?? join(homedir(), '.local', 'share');
30
+ return join(xdgData, 'cleo', 'worktrees');
31
+ }
32
+ /**
33
+ * Compute the per-project worktree root.
34
+ *
35
+ * @param projectRoot - Absolute path to the project.
36
+ * @returns Absolute path to `<XDG>/cleo/worktrees/<projectHash>/`.
37
+ *
38
+ * @task T1591
39
+ */
40
+ export function resolveProjectWorktreeRoot(projectRoot) {
41
+ const projectHash = createHash('sha256').update(projectRoot).digest('hex').slice(0, 16);
42
+ return join(resolveCleoWorktreesRoot(), projectHash);
43
+ }
44
+ /**
45
+ * Check whether the given path is inside the canonical worktrees tree.
46
+ *
47
+ * Project-agnostic: matches the global worktrees root, not a specific project.
48
+ *
49
+ * @param cwdPath - Absolute path to check.
50
+ * @returns true if the path is inside `<XDG>/cleo/worktrees/`.
51
+ *
52
+ * @task T1591
53
+ */
54
+ export function isInsideWorktreesRoot(cwdPath) {
55
+ const worktreesRoot = resolveCleoWorktreesRoot();
56
+ const normalized = resolve(cwdPath);
57
+ const normalizedRoot = resolve(worktreesRoot);
58
+ return (normalized === normalizedRoot ||
59
+ normalized.startsWith(`${normalizedRoot}/`) ||
60
+ normalized.startsWith(`${normalizedRoot}\\`));
61
+ }
62
+ /**
63
+ * Extract the task ID from a worktree path.
64
+ *
65
+ * Path layout: `<XDG>/cleo/worktrees/<projectHash>/<taskId>/...`
66
+ * The taskId is the path segment immediately after the projectHash.
67
+ *
68
+ * @param cwdPath - Absolute path inside a worktree.
69
+ * @returns The task ID segment, or null if the path is not inside the worktrees root.
70
+ *
71
+ * @task T1591
72
+ */
73
+ export function extractTaskIdFromWorktreePath(cwdPath) {
74
+ const worktreesRoot = resolveCleoWorktreesRoot();
75
+ const normalized = resolve(cwdPath);
76
+ const normalizedRoot = resolve(worktreesRoot);
77
+ if (!normalized.startsWith(`${normalizedRoot}/`) &&
78
+ !normalized.startsWith(`${normalizedRoot}\\`)) {
79
+ return null;
80
+ }
81
+ const remainder = normalized.slice(normalizedRoot.length + 1);
82
+ const segments = remainder.split(/[/\\]/).filter(Boolean);
83
+ // segments = [projectHash, taskId, ...rest]
84
+ if (segments.length < 2)
85
+ return null;
86
+ return segments[1] ?? null;
87
+ }
88
+ /**
89
+ * Resolve the agent worktree boundary for the current shim invocation.
90
+ *
91
+ * Strategy (in order):
92
+ * 1. `CLEO_WORKTREE_ROOT` env — explicit worktree path injected by the spawn prompt.
93
+ * 2. Walk up from `cwd` until a directory under `<XDG>/cleo/worktrees/<projectHash>/<taskId>/`
94
+ * is found.
95
+ * 3. Return null when not inside any worktree.
96
+ *
97
+ * @param cwd - Working directory at shim invocation time.
98
+ * @returns The worktree root path + task ID, or null when not inside a worktree.
99
+ *
100
+ * @task T1591
101
+ */
102
+ export function resolveActiveWorktree(cwd) {
103
+ // Explicit env-driven path wins.
104
+ const envWorktree = process.env['CLEO_WORKTREE_ROOT'];
105
+ if (envWorktree && isAbsolute(envWorktree)) {
106
+ const taskId = process.env['CLEO_TASK_ID'] ?? extractTaskIdFromWorktreePath(envWorktree);
107
+ if (taskId) {
108
+ return { worktreePath: resolve(envWorktree), taskId };
109
+ }
110
+ }
111
+ // Walk up from cwd until we find a path that matches the worktree layout.
112
+ if (!isInsideWorktreesRoot(cwd))
113
+ return null;
114
+ const worktreesRoot = resolve(resolveCleoWorktreesRoot());
115
+ let candidate = resolve(cwd);
116
+ // Climb until parent is the projectHash directory (one level under worktreesRoot).
117
+ while (candidate !== '/' && candidate.length > worktreesRoot.length) {
118
+ const parent = normalize(join(candidate, '..'));
119
+ // parent should be `<worktreesRoot>/<projectHash>`.
120
+ if (parent.startsWith(`${worktreesRoot}/`) &&
121
+ parent.split(/[/\\]/).filter(Boolean).length ===
122
+ worktreesRoot.split(/[/\\]/).filter(Boolean).length + 1) {
123
+ const taskId = candidate.split(/[/\\]/).pop() ?? '';
124
+ return taskId ? { worktreePath: candidate, taskId } : null;
125
+ }
126
+ if (parent === candidate)
127
+ break;
128
+ candidate = parent;
129
+ }
130
+ return null;
131
+ }
132
+ /**
133
+ * Check whether an absolute path lives inside the given worktree.
134
+ *
135
+ * @param targetPath - Absolute path to test.
136
+ * @param worktreePath - Absolute path to the worktree root.
137
+ * @returns true if `targetPath` is the worktree or a descendant.
138
+ *
139
+ * @task T1591
140
+ */
141
+ export function isPathInsideWorktree(targetPath, worktreePath) {
142
+ const t = resolve(targetPath);
143
+ const w = resolve(worktreePath);
144
+ return t === w || t.startsWith(`${w}/`) || t.startsWith(`${w}\\`);
145
+ }
146
+ //# sourceMappingURL=worktree-path.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"worktree-path.js","sourceRoot":"","sources":["../src/worktree-path.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cleocode/git-shim",
3
- "version": "2026.4.154",
3
+ "version": "2026.4.158",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "description": "Harness-agnostic git shim for CLEO agent branch-protection (T1118)",
@@ -32,7 +32,7 @@
32
32
  "author": "CLEO Code <hello@cleocode.dev>",
33
33
  "license": "MIT",
34
34
  "dependencies": {
35
- "@cleocode/contracts": "2026.4.154"
35
+ "@cleocode/contracts": "2026.4.158"
36
36
  },
37
37
  "devDependencies": {
38
38
  "@types/node": "^24.3.0",