claude-nomad 0.68.0 → 0.69.0

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/nomad.mjs CHANGED
@@ -41,7 +41,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
41
41
  mod
42
42
  ));
43
43
 
44
- // src/config.never-sync.ts
44
+ // src/core/config.never-sync.ts
45
45
  function stripTrailingDotsAndWhitespace(name) {
46
46
  let end = name.length;
47
47
  while (end > 0 && (name[end - 1] === "." || /\s/.test(name[end - 1]))) end -= 1;
@@ -97,7 +97,7 @@ function isNeverSync(path) {
97
97
  }
98
98
  var NEVER_SYNC, CLAUDE_EXTRA_NEVER_SYNC, ALWAYS_NEVER_SYNC, SECRET_FILE_PATTERNS, UNFILTERED_SHARED_REGIONS;
99
99
  var init_config_never_sync = __esm({
100
- "src/config.never-sync.ts"() {
100
+ "src/core/config.never-sync.ts"() {
101
101
  "use strict";
102
102
  NEVER_SYNC = /* @__PURE__ */ new Set([
103
103
  ".claude.json",
@@ -222,10 +222,10 @@ var require_picocolors = __commonJS({
222
222
  }
223
223
  });
224
224
 
225
- // src/color.ts
225
+ // src/render/color.ts
226
226
  var import_picocolors, enabled, red, yellow, green, cyan, blue, dim, bold, wslNarrowPad, okGlyph, failGlyph, warnGlyph, infoGlyph;
227
227
  var init_color = __esm({
228
- "src/color.ts"() {
228
+ "src/render/color.ts"() {
229
229
  "use strict";
230
230
  import_picocolors = __toESM(require_picocolors(), 1);
231
231
  enabled = import_picocolors.default.isColorSupported;
@@ -244,10 +244,10 @@ var init_color = __esm({
244
244
  }
245
245
  });
246
246
 
247
- // src/exit-codes.ts
247
+ // src/core/exit-codes.ts
248
248
  var EXIT;
249
249
  var init_exit_codes = __esm({
250
- "src/exit-codes.ts"() {
250
+ "src/core/exit-codes.ts"() {
251
251
  "use strict";
252
252
  EXIT = {
253
253
  /** Completed successfully. Also returned when a held lock causes a no-op skip. */
@@ -269,7 +269,7 @@ var init_exit_codes = __esm({
269
269
  }
270
270
  });
271
271
 
272
- // src/utils.ts
272
+ // src/core/utils.ts
273
273
  import { execFileSync } from "node:child_process";
274
274
  function isProcessExit(err) {
275
275
  if (typeof err !== "object" || err === null) return false;
@@ -304,7 +304,7 @@ function gitOrFatal(args, context, cwd) {
304
304
  }
305
305
  var log, ok, warn, fail, item, NomadFatal, PROCESS_EXIT_BRAND, ProcessExit, die, gitStatusPorcelainZ;
306
306
  var init_utils = __esm({
307
- "src/utils.ts"() {
307
+ "src/core/utils.ts"() {
308
308
  "use strict";
309
309
  init_color();
310
310
  init_exit_codes();
@@ -349,7 +349,7 @@ var init_utils = __esm({
349
349
  }
350
350
  });
351
351
 
352
- // src/config.sharedDirs.guard.ts
352
+ // src/core/config.sharedDirs.guard.ts
353
353
  function assertSafeLogical(logical) {
354
354
  if (!SAFE_LOGICAL.test(logical) || logical === "." || logical === "..") {
355
355
  throw new NomadFatal(
@@ -419,7 +419,7 @@ function isValidSharedDir(entry) {
419
419
  }
420
420
  var SAFE_LOGICAL, SAFE_SEGMENT, RESERVED_SHARED, RESERVED_SHARED_FOLDED, WIN32_DEVICE_NAMES, UNJOINABLE_REASONS;
421
421
  var init_config_sharedDirs_guard = __esm({
422
- "src/config.sharedDirs.guard.ts"() {
422
+ "src/core/config.sharedDirs.guard.ts"() {
423
423
  "use strict";
424
424
  init_config_never_sync();
425
425
  init_utils();
@@ -455,10 +455,10 @@ var init_config_sharedDirs_guard = __esm({
455
455
  }
456
456
  });
457
457
 
458
- // src/settings-keys.ts
458
+ // src/core/settings-keys.ts
459
459
  var SCHEMA_KEYS, APP_ONLY_KEYS, KNOWN_SETTINGS_KEYS;
460
460
  var init_settings_keys = __esm({
461
- "src/settings-keys.ts"() {
461
+ "src/core/settings-keys.ts"() {
462
462
  "use strict";
463
463
  SCHEMA_KEYS = [
464
464
  "$schema",
@@ -635,7 +635,7 @@ var init_settings_keys = __esm({
635
635
  }
636
636
  });
637
637
 
638
- // src/config.ts
638
+ // src/core/config.ts
639
639
  import { homedir, hostname } from "node:os";
640
640
  import { join, resolve } from "node:path";
641
641
  function home() {
@@ -686,7 +686,7 @@ function sharedDirEntries(map) {
686
686
  }
687
687
  var SETTINGS_SCHEMA_URL, NPM_REGISTRY_LATEST_URL, GITLEAKS_PINNED_VERSION, GITLEAKS_SCAN_TIMEOUT_MS, HOST, SHARED_LINKS, GSD_PREFIX, GSD_DROPPED_NAMES, SUPPORTED_EXTRAS, PUSH_ALLOWED_STATIC;
688
688
  var init_config = __esm({
689
- "src/config.ts"() {
689
+ "src/core/config.ts"() {
690
690
  "use strict";
691
691
  init_config_sharedDirs_guard();
692
692
  init_utils();
@@ -721,7 +721,7 @@ var init_config = __esm({
721
721
  }
722
722
  });
723
723
 
724
- // src/error-text.ts
724
+ // src/core/error-text.ts
725
725
  function errorText(err) {
726
726
  try {
727
727
  const message = err?.message;
@@ -731,12 +731,12 @@ function errorText(err) {
731
731
  }
732
732
  }
733
733
  var init_error_text = __esm({
734
- "src/error-text.ts"() {
734
+ "src/core/error-text.ts"() {
735
735
  "use strict";
736
736
  }
737
737
  });
738
738
 
739
- // src/utils.json.ts
739
+ // src/core/utils.json.ts
740
740
  import { readFileSync } from "node:fs";
741
741
  function readJson(path) {
742
742
  const data = JSON.parse(readFileSync(path, "utf8"));
@@ -774,10 +774,13 @@ function validatePathMapShape(raw) {
774
774
  }
775
775
  return null;
776
776
  }
777
+ function isProtoPollutionKey(key) {
778
+ return key === "__proto__" || key === "constructor" || key === "prototype";
779
+ }
777
780
  function deepMerge(target, source) {
778
781
  const out = { ...target };
779
782
  for (const [key, value] of Object.entries(source)) {
780
- if (key === "__proto__" || key === "constructor" || key === "prototype") continue;
783
+ if (isProtoPollutionKey(key)) continue;
781
784
  const existing = out[key];
782
785
  const bothObjects = value !== null && typeof value === "object" && !Array.isArray(value) && existing !== null && typeof existing === "object" && !Array.isArray(existing);
783
786
  out[key] = bothObjects ? deepMerge(existing, value) : value;
@@ -789,6 +792,7 @@ function sortKeysDeep(value) {
789
792
  if (value !== null && typeof value === "object") {
790
793
  const out = {};
791
794
  for (const key of Object.keys(value).sort((a, b) => a.localeCompare(b, "en"))) {
795
+ if (isProtoPollutionKey(key)) continue;
792
796
  out[key] = sortKeysDeep(value[key]);
793
797
  }
794
798
  return out;
@@ -797,7 +801,7 @@ function sortKeysDeep(value) {
797
801
  }
798
802
  var ENCODE_MAX, hashPath, encodePath;
799
803
  var init_utils_json = __esm({
800
- "src/utils.json.ts"() {
804
+ "src/core/utils.json.ts"() {
801
805
  "use strict";
802
806
  init_config();
803
807
  init_utils();
@@ -815,7 +819,7 @@ var init_utils_json = __esm({
815
819
  }
816
820
  });
817
821
 
818
- // src/utils.fs.ts
822
+ // src/core/utils.fs.ts
819
823
  import {
820
824
  closeSync,
821
825
  cpSync as cpSync3,
@@ -886,6 +890,12 @@ function freshBackupTs(backupRoot) {
886
890
  while (existsSync3(join5(backupRoot, `${base}-${n}`))) n++;
887
891
  return `${base}-${n}`;
888
892
  }
893
+ function prunableByAge(dirs, olderThanMs, nowMs) {
894
+ return dirs.filter((d) => nowMs - d.mtimeMs > olderThanMs).map((d) => d.name);
895
+ }
896
+ function prunableByCount(dirs, keep) {
897
+ return dirs.slice(keep).map((d) => d.name);
898
+ }
889
899
  function discardEmptyBackupDir(backupRoot) {
890
900
  try {
891
901
  rmdirSync(backupRoot);
@@ -926,7 +936,7 @@ function backupExtrasWrite(absPath, ts, projectRoot) {
926
936
  }
927
937
  var RENAME_RETRY_MAX_ATTEMPTS, RENAME_RETRY_BACKOFF_MS;
928
938
  var init_utils_fs = __esm({
929
- "src/utils.fs.ts"() {
939
+ "src/core/utils.fs.ts"() {
930
940
  "use strict";
931
941
  init_config();
932
942
  init_error_text();
@@ -937,7 +947,7 @@ var init_utils_fs = __esm({
937
947
  }
938
948
  });
939
949
 
940
- // src/commands.pull.wedge.ts
950
+ // src/commands/pull/wedge.ts
941
951
  import { execFileSync as execFileSync3 } from "node:child_process";
942
952
  import { existsSync as existsSync15 } from "node:fs";
943
953
  import { join as join21 } from "node:path";
@@ -1006,23 +1016,54 @@ function orphanedAutostashPresent(repo) {
1006
1016
  return raw.split("\n").some((line) => /:\s*autostash$/.test(line));
1007
1017
  }
1008
1018
  var INDEX_PROBE_TIMEOUT_MS;
1009
- var init_commands_pull_wedge = __esm({
1010
- "src/commands.pull.wedge.ts"() {
1019
+ var init_wedge = __esm({
1020
+ "src/commands/pull/wedge.ts"() {
1011
1021
  "use strict";
1012
1022
  INDEX_PROBE_TIMEOUT_MS = 3e4;
1013
1023
  }
1014
1024
  });
1015
1025
 
1016
- // src/push-gitleaks.config.ts
1017
- import { existsSync as existsSync16, mkdtempSync, readFileSync as readFileSync5, writeFileSync as writeFileSync3 } from "node:fs";
1018
- import { tmpdir } from "node:os";
1019
- import { join as join22 } from "node:path";
1026
+ // src/core/package-root.ts
1027
+ import { existsSync as existsSync16 } from "node:fs";
1028
+ import { basename as basename3, dirname as dirname4, join as join22 } from "node:path";
1020
1029
  import { fileURLToPath } from "node:url";
1030
+ function packageRoot(from = HERE) {
1031
+ let dir = from;
1032
+ for (; ; ) {
1033
+ if (existsSync16(join22(dir, "package.json"))) return dir;
1034
+ if (basename3(dir) === "node_modules") {
1035
+ throw new Error(`no package.json above ${from} within its own package`);
1036
+ }
1037
+ const parent = dirname4(dir);
1038
+ if (parent === dir) throw new Error(`no package.json above ${from}`);
1039
+ dir = parent;
1040
+ }
1041
+ }
1042
+ var HERE;
1043
+ var init_package_root = __esm({
1044
+ "src/core/package-root.ts"() {
1045
+ "use strict";
1046
+ HERE = dirname4(fileURLToPath(import.meta.url));
1047
+ }
1048
+ });
1049
+
1050
+ // src/commands/push/gitleaks.config.ts
1051
+ import { existsSync as existsSync17, mkdtempSync, readFileSync as readFileSync5, writeFileSync as writeFileSync3 } from "node:fs";
1052
+ import { tmpdir } from "node:os";
1053
+ import { join as join23 } from "node:path";
1021
1054
  function resolveTomlPath(repo = repoHome()) {
1022
- const repoToml = join22(repo, ".gitleaks.toml");
1023
- if (existsSync16(repoToml)) return repoToml;
1024
- const bundled = fileURLToPath(new URL("../.gitleaks.toml", import.meta.url));
1025
- return existsSync16(bundled) ? bundled : null;
1055
+ const repoToml = join23(repo, ".gitleaks.toml");
1056
+ if (existsSync17(repoToml)) return repoToml;
1057
+ let root;
1058
+ try {
1059
+ root = packageRoot();
1060
+ } catch {
1061
+ throw new NomadFatal(
1062
+ "claude-nomad install looks incomplete (no package.json above the CLI); reinstall with `npm i -g claude-nomad`"
1063
+ );
1064
+ }
1065
+ const bundled = join23(root, ".gitleaks.toml");
1066
+ return existsSync17(bundled) ? bundled : null;
1026
1067
  }
1027
1068
  function assertOverlayAllowlistsScoped(overlayBody) {
1028
1069
  if (OVERLAY_INLINE_ALLOWLIST_RE.test(overlayBody)) {
@@ -1060,17 +1101,17 @@ function buildOverlayTempConfig(overlayBody, bundled) {
1060
1101
  path = ${JSON.stringify(bundled)}
1061
1102
 
1062
1103
  ${overlayBody}`;
1063
- const tempPath = mkdtempSync(join22(tmpdir(), "nomad-gitleaks-cfg-"));
1064
- const configPath = join22(tempPath, "config.toml");
1104
+ const tempPath = mkdtempSync(join23(tmpdir(), "nomad-gitleaks-cfg-"));
1105
+ const configPath = join23(tempPath, "config.toml");
1065
1106
  writeFileSync3(configPath, tempBody, { mode: 384, flag: "wx" });
1066
1107
  return { configPath, tempPath };
1067
1108
  }
1068
1109
  function resolveTomlConfig() {
1069
1110
  const repo = repoHome();
1070
- const overlayPath = join22(repo, ".gitleaks.overlay.toml");
1071
- const repoToml = join22(repo, ".gitleaks.toml");
1111
+ const overlayPath = join23(repo, ".gitleaks.overlay.toml");
1112
+ const repoToml = join23(repo, ".gitleaks.toml");
1072
1113
  const bundled = resolveTomlPath(repo);
1073
- if (!existsSync16(overlayPath)) {
1114
+ if (!existsSync17(overlayPath)) {
1074
1115
  return { path: bundled, tempPath: null };
1075
1116
  }
1076
1117
  if (bundled === repoToml) {
@@ -1101,10 +1142,11 @@ function resolveTomlConfig() {
1101
1142
  }
1102
1143
  }
1103
1144
  var OVERLAY_EXTEND_RE, TABLE_HEADER_RE, OVERLAY_ALLOWLIST_HEADER_RE, OVERLAY_INLINE_ALLOWLIST_RE, PATHS_KEY_RE, CATCH_ALL_RE;
1104
- var init_push_gitleaks_config = __esm({
1105
- "src/push-gitleaks.config.ts"() {
1145
+ var init_gitleaks_config = __esm({
1146
+ "src/commands/push/gitleaks.config.ts"() {
1106
1147
  "use strict";
1107
1148
  init_config();
1149
+ init_package_root();
1108
1150
  init_utils();
1109
1151
  OVERLAY_EXTEND_RE = /^[ \t]*(?:\[[ \t]*extend[ \t]*\]|extend[ \t]*[.=])/m;
1110
1152
  TABLE_HEADER_RE = /^\s*\[/;
@@ -1115,7 +1157,7 @@ var init_push_gitleaks_config = __esm({
1115
1157
  }
1116
1158
  });
1117
1159
 
1118
- // src/autostash-guard.ts
1160
+ // src/commands/autostash-guard.ts
1119
1161
  function autostashConflictRunbookText(resumeCmd2, stashRetained) {
1120
1162
  const head = `${resumeCmd2} reported success, but the autostash pop it ran internally conflicted. The working tree now holds conflict markers and the index is unmerged. Nothing has been copied to ~/.claude/ yet, and there is no rebase or merge in progress to abort.`;
1121
1163
  if (stashRetained) {
@@ -1146,19 +1188,19 @@ function assertNoAutostashConflict(repo, resumeCmd2) {
1146
1188
  });
1147
1189
  }
1148
1190
  var init_autostash_guard = __esm({
1149
- "src/autostash-guard.ts"() {
1191
+ "src/commands/autostash-guard.ts"() {
1150
1192
  "use strict";
1151
- init_commands_pull_wedge();
1193
+ init_wedge();
1152
1194
  init_exit_codes();
1153
1195
  init_utils();
1154
1196
  }
1155
1197
  });
1156
1198
 
1157
- // src/push-checks.ts
1199
+ // src/commands/push/checks.ts
1158
1200
  import { execFileSync as execFileSync5 } from "node:child_process";
1159
1201
  import { readdirSync as readdirSync8, rmSync as rmSync7 } from "node:fs";
1160
1202
  import { homedir as homedir2, platform } from "node:os";
1161
- import { delimiter, join as join23 } from "node:path";
1203
+ import { delimiter, join as join24 } from "node:path";
1162
1204
  function gitleaksInstallHint() {
1163
1205
  const head = "gitleaks not on PATH (required for nomad push). Install:";
1164
1206
  const plat = platform();
@@ -1206,7 +1248,7 @@ function findGitlinks(dir) {
1206
1248
  return;
1207
1249
  }
1208
1250
  for (const e of entries) {
1209
- const p = join23(current, e.name);
1251
+ const p = join24(current, e.name);
1210
1252
  if (e.name === ".git") {
1211
1253
  hits.push(p);
1212
1254
  continue;
@@ -1255,22 +1297,22 @@ function rebaseBeforePush(repo) {
1255
1297
  }
1256
1298
  assertNoAutostashConflict(repo, "nomad push");
1257
1299
  }
1258
- var init_push_checks = __esm({
1259
- "src/push-checks.ts"() {
1300
+ var init_checks = __esm({
1301
+ "src/commands/push/checks.ts"() {
1260
1302
  "use strict";
1261
- init_push_gitleaks_config();
1303
+ init_gitleaks_config();
1262
1304
  init_autostash_guard();
1263
- init_commands_pull_wedge();
1305
+ init_wedge();
1264
1306
  init_exit_codes();
1265
1307
  init_utils();
1266
1308
  }
1267
1309
  });
1268
1310
 
1269
- // src/push-gitleaks.scan.ts
1311
+ // src/commands/push/gitleaks.scan.ts
1270
1312
  import { execFileSync as execFileSync9 } from "node:child_process";
1271
1313
  import { mkdirSync as mkdirSync3, mkdtempSync as mkdtempSync2, readFileSync as readFileSync6, rmSync as rmSync8 } from "node:fs";
1272
1314
  import { homedir as homedir3 } from "node:os";
1273
- import { join as join27 } from "node:path";
1315
+ import { join as join28 } from "node:path";
1274
1316
  function toFinding(entry) {
1275
1317
  if (typeof entry !== "object" || entry === null) return null;
1276
1318
  const e = entry;
@@ -1318,9 +1360,9 @@ function resolveScanFailure(reportPath, e, forwardStreams) {
1318
1360
  return report;
1319
1361
  }
1320
1362
  function scanStagedTree(repoDir, forwardStreams = false) {
1321
- const cacheDir = join27(homedir3(), ".cache", "claude-nomad");
1363
+ const cacheDir = join28(homedir3(), ".cache", "claude-nomad");
1322
1364
  mkdirSync3(cacheDir, { recursive: true });
1323
- const reportPath = join27(cacheDir, `gitleaks-${nowTimestamp()}-${process.pid}.json`);
1365
+ const reportPath = join28(cacheDir, `gitleaks-${nowTimestamp()}-${process.pid}.json`);
1324
1366
  const { path: toml, tempPath } = resolveTomlConfig();
1325
1367
  const args = [
1326
1368
  "protect",
@@ -1348,14 +1390,14 @@ function scanStagedTree(repoDir, forwardStreams = false) {
1348
1390
  }
1349
1391
  }
1350
1392
  function scanFile(filePath, forwardStreams = false, timeoutMs = GITLEAKS_SCAN_TIMEOUT_MS) {
1351
- const cacheDir = join27(homedir3(), ".cache", "claude-nomad");
1393
+ const cacheDir = join28(homedir3(), ".cache", "claude-nomad");
1352
1394
  mkdirSync3(cacheDir, { recursive: true });
1353
1395
  const { path: toml, tempPath } = resolveTomlConfig();
1354
1396
  let reportDir;
1355
1397
  let reportPath;
1356
1398
  try {
1357
- reportDir = mkdtempSync2(join27(cacheDir, `gitleaks-file-${nowTimestamp()}-${process.pid}-`));
1358
- reportPath = join27(reportDir, "report.json");
1399
+ reportDir = mkdtempSync2(join28(cacheDir, `gitleaks-file-${nowTimestamp()}-${process.pid}-`));
1400
+ reportPath = join28(reportDir, "report.json");
1359
1401
  const args = [
1360
1402
  "detect",
1361
1403
  "--no-git",
@@ -1380,16 +1422,16 @@ function scanFile(filePath, forwardStreams = false, timeoutMs = GITLEAKS_SCAN_TI
1380
1422
  if (reportDir !== void 0) rmSync8(reportDir, { recursive: true, force: true });
1381
1423
  }
1382
1424
  }
1383
- var init_push_gitleaks_scan = __esm({
1384
- "src/push-gitleaks.scan.ts"() {
1425
+ var init_gitleaks_scan = __esm({
1426
+ "src/commands/push/gitleaks.scan.ts"() {
1385
1427
  "use strict";
1386
1428
  init_config();
1387
- init_push_gitleaks_config();
1429
+ init_gitleaks_config();
1388
1430
  init_utils_fs();
1389
1431
  }
1390
1432
  });
1391
1433
 
1392
- // src/push-gitleaks.ts
1434
+ // src/commands/push/gitleaks.ts
1393
1435
  function findingIdentityKey(f) {
1394
1436
  const fp = f.Fingerprint;
1395
1437
  return typeof fp === "string" && fp.length > 0 ? fp : `${f.File}:${f.RuleID}:${f.StartLine}:${f.StartColumn}`;
@@ -1477,13 +1519,13 @@ function buildSessionAwareFatal(bySession, other) {
1477
1519
  return lines.join("\n");
1478
1520
  }
1479
1521
  var SESSION_PATH, SUBAGENT_SESSION_PATH, LEGACY_FATAL;
1480
- var init_push_gitleaks = __esm({
1481
- "src/push-gitleaks.ts"() {
1522
+ var init_gitleaks = __esm({
1523
+ "src/commands/push/gitleaks.ts"() {
1482
1524
  "use strict";
1483
1525
  init_config();
1484
1526
  init_exit_codes();
1485
- init_push_checks();
1486
- init_push_gitleaks_scan();
1527
+ init_checks();
1528
+ init_gitleaks_scan();
1487
1529
  init_utils();
1488
1530
  SESSION_PATH = /^shared\/projects\/[^/]+\/([^/]+)\.jsonl$/;
1489
1531
  SUBAGENT_SESSION_PATH = /^shared\/projects\/[^/]+\/([^/]+)\/.*\.jsonl$/;
@@ -1491,9 +1533,9 @@ var init_push_gitleaks = __esm({
1491
1533
  }
1492
1534
  });
1493
1535
 
1494
- // src/push-leak-verdict.ts
1495
- var push_leak_verdict_exports = {};
1496
- __export(push_leak_verdict_exports, {
1536
+ // src/commands/push/leak-verdict.ts
1537
+ var leak_verdict_exports = {};
1538
+ __export(leak_verdict_exports, {
1497
1539
  failRow: () => failRow,
1498
1540
  leakVerdictRow: () => leakVerdictRow,
1499
1541
  noLeaksRow: () => noLeaksRow,
@@ -1566,27 +1608,27 @@ function scanPushVerdict(repo) {
1566
1608
  return leakFound(findings);
1567
1609
  }
1568
1610
  var noLeaksRow, failRow;
1569
- var init_push_leak_verdict = __esm({
1570
- "src/push-leak-verdict.ts"() {
1611
+ var init_leak_verdict = __esm({
1612
+ "src/commands/push/leak-verdict.ts"() {
1571
1613
  "use strict";
1572
1614
  init_color();
1573
1615
  init_exit_codes();
1574
- init_push_checks();
1575
- init_push_gitleaks();
1616
+ init_checks();
1617
+ init_gitleaks();
1576
1618
  noLeaksRow = () => `${green(okGlyph)} no leaks`;
1577
1619
  failRow = (text) => `${red(failGlyph)} ${text}`;
1578
1620
  }
1579
1621
  });
1580
1622
 
1581
- // src/commands.adopt.ts
1623
+ // src/commands/adopt.ts
1582
1624
  import { existsSync as existsSync5, lstatSync as lstatSync7 } from "node:fs";
1583
1625
  import { join as join9 } from "node:path";
1584
1626
 
1585
- // src/commands.adopt.recover.ts
1627
+ // src/commands/adopt.recover.ts
1586
1628
  import { rmSync as rmSync4 } from "node:fs";
1587
1629
  import { dirname as dirname2, join as join7, resolve as resolve2 } from "node:path";
1588
1630
 
1589
- // src/commands.adopt.scan.ts
1631
+ // src/commands/adopt.scan.ts
1590
1632
  init_config();
1591
1633
  init_error_text();
1592
1634
  init_exit_codes();
@@ -1665,17 +1707,17 @@ function refuseDeniedEntries(name, root) {
1665
1707
  });
1666
1708
  }
1667
1709
 
1668
- // src/commands.adopt.recover.ts
1710
+ // src/commands/adopt.recover.ts
1669
1711
  init_config();
1670
1712
  init_error_text();
1671
1713
  init_exit_codes();
1672
1714
 
1673
- // src/extras-sync.core.ts
1715
+ // src/sync/extras/core.ts
1674
1716
  init_config();
1675
1717
  import { cpSync as cpSync2, existsSync as existsSync2, lstatSync as lstatSync3, readdirSync as readdirSync3, readFileSync as readFileSync2, rmSync as rmSync2 } from "node:fs";
1676
1718
  import { basename as basename2, join as join4, relative as relative2 } from "node:path";
1677
1719
 
1678
- // src/extras-sync.collision.ts
1720
+ // src/sync/extras/collision.ts
1679
1721
  init_utils();
1680
1722
  import { cpSync, existsSync, lstatSync as lstatSync2, readdirSync as readdirSync2, rmSync } from "node:fs";
1681
1723
  import { basename, join as join3 } from "node:path";
@@ -1750,7 +1792,7 @@ function copyExtrasFilteredPreservingBy(src, dst, isPreserved, isRootPreserved)
1750
1792
  });
1751
1793
  }
1752
1794
 
1753
- // src/extras-sync.guards.ts
1795
+ // src/sync/extras/guards.ts
1754
1796
  init_utils();
1755
1797
  init_config_sharedDirs_guard();
1756
1798
  import { isAbsolute, normalize, sep } from "node:path";
@@ -1768,7 +1810,7 @@ function assertSafeLocalRoot(localRoot, logical) {
1768
1810
  }
1769
1811
  }
1770
1812
 
1771
- // src/extras-sync.core.ts
1813
+ // src/sync/extras/core.ts
1772
1814
  init_utils();
1773
1815
  init_utils_json();
1774
1816
  function loadValidatedExtras(opts) {
@@ -1797,12 +1839,12 @@ function* eachExtrasTarget(v, counts) {
1797
1839
  counts.unmapped++;
1798
1840
  continue;
1799
1841
  }
1800
- for (const dirname15 of dirnames) {
1801
- if (!whitelist.includes(dirname15)) {
1842
+ for (const dirname16 of dirnames) {
1843
+ if (!whitelist.includes(dirname16)) {
1802
1844
  counts.skipped++;
1803
1845
  continue;
1804
1846
  }
1805
- yield { logical, localRoot, dirname: dirname15 };
1847
+ yield { logical, localRoot, dirname: dirname16 };
1806
1848
  }
1807
1849
  }
1808
1850
  }
@@ -1844,8 +1886,8 @@ function copyExtrasFileSkipDiverged(src, dst) {
1844
1886
  }
1845
1887
  copyExtras(src, dst);
1846
1888
  }
1847
- function extrasDenySet(dirname15) {
1848
- return isClaudeExtraName(dirname15) ? CLAUDE_EXTRA_NEVER_SYNC : ALWAYS_NEVER_SYNC;
1889
+ function extrasDenySet(dirname16) {
1890
+ return isClaudeExtraName(dirname16) ? CLAUDE_EXTRA_NEVER_SYNC : ALWAYS_NEVER_SYNC;
1849
1891
  }
1850
1892
  function copyExtrasFiltered(src, dst, blockSet) {
1851
1893
  rmSync2(dst, { recursive: true, force: true });
@@ -1888,7 +1930,7 @@ function copyExtrasFilteredPreserving(src, dst, blockSet) {
1888
1930
  });
1889
1931
  }
1890
1932
 
1891
- // src/fs-presence.ts
1933
+ // src/core/fs-presence.ts
1892
1934
  import { lstatSync as lstatSync4, statSync } from "node:fs";
1893
1935
  var ABSENT_CODES = /* @__PURE__ */ new Set(["ENOENT", "ENOTDIR", "ENAMETOOLONG"]);
1894
1936
  function classifyPresence(p) {
@@ -1913,14 +1955,110 @@ function lexists(p) {
1913
1955
  return classifyPresence(p) !== "absent";
1914
1956
  }
1915
1957
 
1916
- // src/links.ts
1958
+ // src/sync/links.ts
1917
1959
  init_config();
1918
1960
  import { existsSync as existsSync4, lstatSync as lstatSync6, rmSync as rmSync3 } from "node:fs";
1919
1961
  import { join as join6 } from "node:path";
1920
1962
 
1921
- // src/hooks-filter.ts
1963
+ // src/commands/capture-settings/core.ts
1964
+ init_utils_json();
1965
+
1966
+ // src/sync/hooks-filter.ts
1922
1967
  init_config();
1923
- var KNOWN_LAUNCHER_BASENAMES = /* @__PURE__ */ new Set(["node", "bash", "sh"]);
1968
+ init_utils_json();
1969
+
1970
+ // src/sync/hooks-filter.command-sub.ts
1971
+ var SUB_START = /^"?(?:\$\(|`)/;
1972
+ function opensSubstitution(token) {
1973
+ return SUB_START.test(token);
1974
+ }
1975
+ function stepChar(token, i, scan) {
1976
+ const c = token[i];
1977
+ const top = scan.stack.at(-1);
1978
+ if (top === "sq") {
1979
+ if (c === "'") scan.stack.pop();
1980
+ return i + 1;
1981
+ }
1982
+ if (scan.escaped) {
1983
+ scan.escaped = false;
1984
+ return i + 1;
1985
+ }
1986
+ if (c === "\\") {
1987
+ scan.escaped = true;
1988
+ return i + 1;
1989
+ }
1990
+ if (c === "$" && token[i + 1] === "(") {
1991
+ scan.stack.push("cmd");
1992
+ scan.depth++;
1993
+ return i + 2;
1994
+ }
1995
+ if (c === "'" && top === "cmd") scan.stack.push("sq");
1996
+ else if (c === "`") toggleBacktick(scan, top);
1997
+ else if (c === '"') toggleDoubleQuote(scan, top);
1998
+ else if (top === "cmd") stepParen(c, scan);
1999
+ return i + 1;
2000
+ }
2001
+ function toggleBacktick(scan, top) {
2002
+ if (top === "bt") scan.stack.pop();
2003
+ else scan.stack.push("bt");
2004
+ }
2005
+ function toggleDoubleQuote(scan, top) {
2006
+ if (top === "dq") scan.stack.pop();
2007
+ else scan.stack.push("dq");
2008
+ }
2009
+ function stepParen(c, scan) {
2010
+ if (c === "(") {
2011
+ scan.stack.push("cmd");
2012
+ scan.depth++;
2013
+ } else if (c === ")") {
2014
+ scan.stack.pop();
2015
+ scan.depth--;
2016
+ }
2017
+ }
2018
+ function skipDollarParen(tokens, start, from) {
2019
+ const scan = { stack: ["cmd"], depth: 1, escaped: false };
2020
+ let i = from;
2021
+ for (let j = start; j < tokens.length; j++) {
2022
+ const token = tokens[j];
2023
+ while (i < token.length) {
2024
+ i = stepChar(token, i, scan);
2025
+ if (scan.depth === 0) return { next: j + 1, rest: token.slice(i) };
2026
+ }
2027
+ i = 0;
2028
+ scan.escaped = false;
2029
+ }
2030
+ return unterminated(tokens, start);
2031
+ }
2032
+ function skipBacktick(tokens, start, from) {
2033
+ let i = from;
2034
+ for (let j = start; j < tokens.length; j++) {
2035
+ const token = tokens[j];
2036
+ while (i < token.length) {
2037
+ if (token[i] === "\\") i += 2;
2038
+ else if (token[i] === "`") return { next: j + 1, rest: token.slice(i + 1) };
2039
+ else i++;
2040
+ }
2041
+ i = 0;
2042
+ }
2043
+ return unterminated(tokens, start);
2044
+ }
2045
+ function unterminated(tokens, start) {
2046
+ return { next: start + 1, rest: tokens[start] };
2047
+ }
2048
+ function skipSubstitution(tokens, start) {
2049
+ const token = tokens[start] ?? "";
2050
+ const paren = token.indexOf("$(");
2051
+ const tick = token.indexOf("`");
2052
+ if (paren < 0 && tick < 0) return { next: start + 1, rest: token };
2053
+ if (tick >= 0 && (paren < 0 || tick < paren)) return skipBacktick(tokens, start, tick + 1);
2054
+ return skipDollarParen(tokens, start, paren + 2);
2055
+ }
2056
+
2057
+ // src/sync/hooks-filter.ts
2058
+ var KNOWN_LAUNCHER_BASENAMES = /* @__PURE__ */ new Set(["env", "node", "bash", "sh"]);
2059
+ var SUBSTITUTION_ARTIFACT = /[`()'"]/;
2060
+ var ENV_ASSIGNMENT = /^[A-Za-z_]\w*=/;
2061
+ var SHELL_OPERATORS = /* @__PURE__ */ new Set(["&&", "||", ";", "|", "&"]);
1924
2062
  function scriptBasename(token) {
1925
2063
  const lastSlash = Math.max(token.lastIndexOf("/"), token.lastIndexOf("\\"));
1926
2064
  return lastSlash >= 0 ? token.slice(lastSlash + 1) : token;
@@ -1935,25 +2073,56 @@ function stripQuotes(token) {
1935
2073
  }
1936
2074
  return token;
1937
2075
  }
2076
+ var NO_CANDIDATE = { index: -1, word: "" };
2077
+ function nextScriptWord(tokens, from, inScriptSlot) {
2078
+ let slot = inScriptSlot;
2079
+ let i = from;
2080
+ while (i < tokens.length) {
2081
+ const token = tokens[i];
2082
+ if (SHELL_OPERATORS.has(token)) {
2083
+ slot = false;
2084
+ i++;
2085
+ } else if (token.startsWith("-")) {
2086
+ i++;
2087
+ } else if (!opensSubstitution(token)) {
2088
+ return { index: i, word: token };
2089
+ } else {
2090
+ const end = skipSubstitution(tokens, i);
2091
+ if (end.rest !== "") return { index: end.next - 1, word: end.rest };
2092
+ if (slot && !SHELL_OPERATORS.has(tokens[end.next] ?? "")) return NO_CANDIDATE;
2093
+ i = end.next;
2094
+ }
2095
+ }
2096
+ return NO_CANDIDATE;
2097
+ }
2098
+ function resolveScriptWord(tokens, from, underEnv) {
2099
+ let candidate = nextScriptWord(tokens, from, true);
2100
+ while (underEnv && candidate.index >= 0) {
2101
+ const word = stripQuotes(candidate.word);
2102
+ const isBareInterpreter = !word.includes("/") && !word.includes("\\") && KNOWN_LAUNCHER_BASENAMES.has(word);
2103
+ if (!isBareInterpreter && !ENV_ASSIGNMENT.test(word)) return candidate;
2104
+ candidate = nextScriptWord(tokens, candidate.index + 1, true);
2105
+ }
2106
+ return candidate;
2107
+ }
1938
2108
  function isGsdHookEntry(command) {
1939
2109
  const tokens = command.trim().split(/\s+/);
1940
- if (tokens.length === 0 || tokens[0] === "") return false;
1941
- const envAssign = /^[A-Za-z_]\w*=/;
2110
+ if (tokens[0] === "") return false;
1942
2111
  let i = 0;
1943
- while (i < tokens.length && envAssign.test(tokens[i])) {
2112
+ while (i < tokens.length && ENV_ASSIGNMENT.test(tokens[i])) {
1944
2113
  i++;
1945
2114
  }
1946
- const first = stripQuotes(tokens[i] ?? "");
2115
+ const launcher = nextScriptWord(tokens, i, false);
2116
+ if (launcher.index < 0) return false;
2117
+ const first = stripQuotes(launcher.word);
1947
2118
  const firstBase = scriptBasename(first);
1948
2119
  const firstHasPath = first.includes("/") || first.includes("\\");
1949
- if (firstHasPath && !KNOWN_LAUNCHER_BASENAMES.has(firstBase) || first.startsWith(GSD_PREFIX)) {
2120
+ if (!KNOWN_LAUNCHER_BASENAMES.has(firstBase) && (firstHasPath || !SUBSTITUTION_ARTIFACT.test(first))) {
1950
2121
  return firstBase.startsWith(GSD_PREFIX);
1951
2122
  }
1952
- for (let j = i + 1; j < tokens.length; j++) {
1953
- if (tokens[j].startsWith("-")) continue;
1954
- return scriptBasename(stripQuotes(tokens[j])).startsWith(GSD_PREFIX);
1955
- }
1956
- return false;
2123
+ const script = resolveScriptWord(tokens, launcher.index + 1, firstBase === "env");
2124
+ if (script.index < 0) return false;
2125
+ return scriptBasename(stripQuotes(script.word)).startsWith(GSD_PREFIX);
1957
2126
  }
1958
2127
  function filterMatcherEntry(entry) {
1959
2128
  if (entry === null || typeof entry !== "object" || Array.isArray(entry)) return entry;
@@ -1981,24 +2150,26 @@ function filterEventMatchers(matchers) {
1981
2150
  function stripGsdHookEntries(settings) {
1982
2151
  const out = {};
1983
2152
  for (const [key, value] of Object.entries(settings)) {
1984
- if (key !== "hooks") {
1985
- out[key] = value;
1986
- continue;
1987
- }
1988
- if (value === null || typeof value !== "object" || Array.isArray(value)) {
2153
+ if (isProtoPollutionKey(key)) continue;
2154
+ const hooksObj = key === "hooks" ? asPlainObject(value) : null;
2155
+ if (hooksObj === null) {
1989
2156
  out[key] = value;
1990
2157
  continue;
1991
2158
  }
1992
- const hooksObj = value;
1993
- const filteredHooks = {};
1994
- for (const [event, matchers] of Object.entries(hooksObj)) {
1995
- const filtered = filterEventMatchers(matchers);
1996
- if (filtered !== null) filteredHooks[event] = filtered;
1997
- }
1998
- if (Object.keys(filteredHooks).length > 0) out[key] = filteredHooks;
2159
+ const filteredHooks = filterHooksBlock(hooksObj);
2160
+ if (filteredHooks !== null) out[key] = filteredHooks;
1999
2161
  }
2000
2162
  return out;
2001
2163
  }
2164
+ function filterHooksBlock(hooksObj) {
2165
+ const filteredHooks = {};
2166
+ for (const [event, matchers] of Object.entries(hooksObj)) {
2167
+ if (isProtoPollutionKey(event)) continue;
2168
+ const filtered = filterEventMatchers(matchers);
2169
+ if (filtered !== null) filteredHooks[event] = filtered;
2170
+ }
2171
+ return Object.keys(filteredHooks).length > 0 ? filteredHooks : null;
2172
+ }
2002
2173
  function keepMatcherEntry(entry) {
2003
2174
  if (entry === null || typeof entry !== "object" || Array.isArray(entry)) return null;
2004
2175
  const entryObj = entry;
@@ -2028,6 +2199,7 @@ function keepGsdHookEntries(settings) {
2028
2199
  const hooksObj = hooksVal;
2029
2200
  const keptHooks = {};
2030
2201
  for (const [event, matchers] of Object.entries(hooksObj)) {
2202
+ if (isProtoPollutionKey(event)) continue;
2031
2203
  const kept = keepEventMatchers(matchers);
2032
2204
  if (kept !== null) keptHooks[event] = kept;
2033
2205
  }
@@ -2062,7 +2234,7 @@ function graftGsdHookEntries(base, gsdOnly) {
2062
2234
  const baseHooks = asPlainObject(base.hooks);
2063
2235
  const mergedHooks = baseHooks ? { ...baseHooks } : {};
2064
2236
  for (const [event, gsdMatchers] of Object.entries(gsdHooks)) {
2065
- if (!Array.isArray(gsdMatchers)) continue;
2237
+ if (isProtoPollutionKey(event) || !Array.isArray(gsdMatchers)) continue;
2066
2238
  const baseMatchers = mergedHooks[event];
2067
2239
  mergedHooks[event] = Array.isArray(baseMatchers) ? unionMatcherArrays(baseMatchers, gsdMatchers) : gsdMatchers;
2068
2240
  }
@@ -2093,7 +2265,7 @@ function baseHasGsdHookEntries(settings) {
2093
2265
  return false;
2094
2266
  }
2095
2267
 
2096
- // src/commands.capture-settings.core.ts
2268
+ // src/commands/capture-settings/core.ts
2097
2269
  function arraysEqual(a, b) {
2098
2270
  if (a.length !== b.length) return false;
2099
2271
  for (let i = 0; i < a.length; i++) {
@@ -2187,6 +2359,7 @@ function normalizeNodePathsDeep(value) {
2187
2359
  if (value !== null && typeof value === "object") {
2188
2360
  const out = {};
2189
2361
  for (const [k, v] of Object.entries(value)) {
2362
+ if (isProtoPollutionKey(k)) continue;
2190
2363
  out[k] = normalizeNodePathsDeep(v);
2191
2364
  }
2192
2365
  return out;
@@ -2205,7 +2378,7 @@ function buildCaptureSubset(merged, settings, opts) {
2205
2378
  return out;
2206
2379
  }
2207
2380
 
2208
- // src/links.ts
2381
+ // src/sync/links.ts
2209
2382
  init_utils();
2210
2383
  init_utils_fs();
2211
2384
  init_utils_json();
@@ -2391,7 +2564,7 @@ function regenerateSettings(ts, opts = {}) {
2391
2564
  return { label: overrideLabel };
2392
2565
  }
2393
2566
 
2394
- // src/commands.adopt.recover.ts
2567
+ // src/commands/adopt.recover.ts
2395
2568
  init_utils();
2396
2569
  function isDirectChildOf(root, abs) {
2397
2570
  return dirname2(resolve2(abs)) === resolve2(root);
@@ -2503,14 +2676,14 @@ function reportSourceRemovalFailure(name, linkPath, message, stage) {
2503
2676
  );
2504
2677
  }
2505
2678
 
2506
- // src/commands.adopt.ts
2679
+ // src/commands/adopt.ts
2507
2680
  init_config();
2508
2681
  init_config_sharedDirs_guard();
2509
2682
  init_exit_codes();
2510
2683
  init_utils();
2511
2684
  init_utils_fs();
2512
2685
 
2513
- // src/utils.lockfile.ts
2686
+ // src/core/utils.lockfile.ts
2514
2687
  init_config();
2515
2688
  init_utils();
2516
2689
  import { closeSync as closeSync2, mkdirSync as mkdirSync2, openSync as openSync2, readFileSync as readFileSync3, unlinkSync, writeFileSync as writeFileSync2 } from "node:fs";
@@ -2623,7 +2796,7 @@ function retryOnce(verb, lp) {
2623
2796
  }
2624
2797
  }
2625
2798
 
2626
- // src/commands.adopt.ts
2799
+ // src/commands/adopt.ts
2627
2800
  init_utils_json();
2628
2801
  var ADOPT_PUSH_HINT = "run `nomad push` to share with other hosts";
2629
2802
  function readMapIfPresent(repoHome2) {
@@ -2787,11 +2960,11 @@ function adoptPreflightAndMove(name, linkPath, sharedTarget, repo, backup, dryRu
2787
2960
  }
2788
2961
  }
2789
2962
 
2790
- // src/commands.allow.ts
2963
+ // src/commands/allow.ts
2791
2964
  init_config();
2792
2965
  import { existsSync as existsSync6 } from "node:fs";
2793
2966
 
2794
- // src/commands.redact.core.ts
2967
+ // src/commands/redact/core.ts
2795
2968
  import { appendFileSync, readFileSync as readFileSync4 } from "node:fs";
2796
2969
  import { join as join10 } from "node:path";
2797
2970
  function collectMatchIntervals(content, findings) {
@@ -2865,7 +3038,7 @@ function appendGitleaksIgnore(fingerprint, repo) {
2865
3038
  appendFileSync(ignPath, prefix + formatFingerprint(sanitized), "utf8");
2866
3039
  }
2867
3040
 
2868
- // src/commands.allow.ts
3041
+ // src/commands/allow.ts
2869
3042
  init_exit_codes();
2870
3043
  init_utils();
2871
3044
  function cmdAllow(fingerprints) {
@@ -2885,7 +3058,7 @@ function cmdAllow(fingerprints) {
2885
3058
  log(`allowed ${fingerprints.length} fingerprint(s)`);
2886
3059
  }
2887
3060
 
2888
- // src/commands.capture-settings.ts
3061
+ // src/commands/capture-settings/capture-settings.ts
2889
3062
  init_config();
2890
3063
  import { existsSync as existsSync7 } from "node:fs";
2891
3064
  import { join as join11 } from "node:path";
@@ -2967,10 +3140,11 @@ async function cmdCaptureSettings(opts) {
2967
3140
  }
2968
3141
  }
2969
3142
 
2970
- // src/commands.clean.ts
3143
+ // src/commands/clean.ts
2971
3144
  init_config();
2972
3145
  init_exit_codes();
2973
3146
  init_utils();
3147
+ init_utils_fs();
2974
3148
  import { existsSync as existsSync8, lstatSync as lstatSync8, readdirSync as readdirSync4, rmSync as rmSync5, statSync as statSync3 } from "node:fs";
2975
3149
  import { join as join12 } from "node:path";
2976
3150
  var TS_SHAPE = /^\d{8}-\d{6}(-\d+)?$/;
@@ -3005,12 +3179,6 @@ function holdsNoContent(dir) {
3005
3179
  }
3006
3180
  return true;
3007
3181
  }
3008
- function prunableByAge(dirs, olderThanMs, nowMs) {
3009
- return dirs.filter((d) => nowMs - d.mtimeMs > olderThanMs).map((d) => d.name);
3010
- }
3011
- function prunableByCount(dirs, keep) {
3012
- return dirs.slice(keep).map((d) => d.name);
3013
- }
3014
3182
  function safeDelete(backupBase2, name) {
3015
3183
  if (!isTsDir(name)) return;
3016
3184
  const full = join12(backupBase2, name);
@@ -3070,7 +3238,7 @@ function pruneBackups(opts, backupBase2) {
3070
3238
  log(`removed ${targets.length} backup(s)`);
3071
3239
  }
3072
3240
 
3073
- // src/commands.eject.ts
3241
+ // src/commands/eject.ts
3074
3242
  init_config();
3075
3243
  init_config_sharedDirs_guard();
3076
3244
  init_utils();
@@ -3270,20 +3438,20 @@ function cmdEject(opts = {}, roots = defaultEjectRoots()) {
3270
3438
  }
3271
3439
  }
3272
3440
 
3273
- // src/commands.doctor.ts
3274
- import { existsSync as existsSync35 } from "node:fs";
3275
- import { join as join49 } from "node:path";
3441
+ // src/commands/doctor/doctor.ts
3442
+ import { existsSync as existsSync36 } from "node:fs";
3443
+ import { join as join52 } from "node:path";
3276
3444
 
3277
- // src/commands.doctor.checks.repo.ts
3445
+ // src/commands/doctor/checks/repo.ts
3278
3446
  init_color();
3279
3447
  init_config();
3280
3448
  import { existsSync as existsSync11, lstatSync as lstatSync10, readdirSync as readdirSync5, statSync as statSync4 } from "node:fs";
3281
3449
  import { join as join17 } from "node:path";
3282
3450
 
3283
- // src/commands.doctor.format.ts
3451
+ // src/commands/doctor/format.ts
3284
3452
  init_color();
3285
3453
 
3286
- // src/output-tree.ts
3454
+ // src/render/output-tree.ts
3287
3455
  init_color();
3288
3456
  var FAIL_GLYPH_BARE = "\u2717";
3289
3457
  function section(header, raw = false) {
@@ -3341,7 +3509,7 @@ function renderTree(sections) {
3341
3509
  }
3342
3510
  var renderDoctor = renderTree;
3343
3511
 
3344
- // src/commands.doctor.format.ts
3512
+ // src/commands/doctor/format.ts
3345
3513
  init_utils_json();
3346
3514
  function readJsonSafe(path, label, section2) {
3347
3515
  try {
@@ -3353,12 +3521,12 @@ function readJsonSafe(path, label, section2) {
3353
3521
  }
3354
3522
  }
3355
3523
 
3356
- // src/commands.doctor.checks.repo.win32.ts
3524
+ // src/commands/doctor/checks/repo.win32.ts
3357
3525
  init_color();
3358
3526
  init_config();
3359
3527
  import { join as join14, win32 as win32Path } from "node:path";
3360
3528
 
3361
- // src/extras-sync.diff.ts
3529
+ // src/sync/extras/diff.ts
3362
3530
  init_utils();
3363
3531
  import { execFileSync as execFileSync2 } from "node:child_process";
3364
3532
  import { relative as relative4 } from "node:path";
@@ -3413,7 +3581,7 @@ function listDivergingModified(a, b) {
3413
3581
  return runNameStatusDiff(a, b, (stdout) => parseModifiedPaths(stdout, a));
3414
3582
  }
3415
3583
 
3416
- // src/commands.doctor.checks.repo.win32.ts
3584
+ // src/commands/doctor/checks/repo.win32.ts
3417
3585
  function win32CopyOkRow(name, exempt = 0) {
3418
3586
  const note = exempt > 0 ? dim(` (${exempt} never-synced path(s) not compared)`) : "";
3419
3587
  return { line: `${green(okGlyph)} ${name}: real copy (win32 copy-sync)${note}`, fail: false };
@@ -3465,7 +3633,7 @@ function classifyWin32Copy(name, p) {
3465
3633
  };
3466
3634
  }
3467
3635
 
3468
- // src/commands.doctor.checks.repo.source.ts
3636
+ // src/commands/doctor/checks/repo.source.ts
3469
3637
  init_color();
3470
3638
  init_config();
3471
3639
  import { join as join15 } from "node:path";
@@ -3516,7 +3684,7 @@ function repoSourceRow(name, present, absent) {
3516
3684
  return state === "resolves" ? present : absent;
3517
3685
  }
3518
3686
 
3519
- // src/init.classify.ts
3687
+ // src/commands/init/classify.ts
3520
3688
  init_config();
3521
3689
  init_utils_json();
3522
3690
  import { existsSync as existsSync10 } from "node:fs";
@@ -3559,7 +3727,7 @@ function reasonForPartial(repoHome2, host) {
3559
3727
  return "- partial state (unknown gap)";
3560
3728
  }
3561
3729
 
3562
- // src/commands.doctor.checks.repo.ts
3730
+ // src/commands/doctor/checks/repo.ts
3563
3731
  init_utils_json();
3564
3732
  function isOverrideActive() {
3565
3733
  return Boolean(process.env.NOMAD_REPO);
@@ -3718,7 +3886,7 @@ function reportDroppedNamesMigration(section2) {
3718
3886
  }
3719
3887
  }
3720
3888
 
3721
- // src/commands.doctor.checks.settings.ts
3889
+ // src/commands/doctor/checks/settings.ts
3722
3890
  init_color();
3723
3891
  init_config();
3724
3892
  import { existsSync as existsSync12, readdirSync as readdirSync6 } from "node:fs";
@@ -3779,7 +3947,7 @@ function reportHostOverrides(section2, base, settings) {
3779
3947
  }
3780
3948
  }
3781
3949
 
3782
- // src/commands.doctor.checks.pathmap.ts
3950
+ // src/commands/doctor/checks/pathmap.ts
3783
3951
  init_color();
3784
3952
  init_config();
3785
3953
  init_config_sharedDirs_guard();
@@ -3965,7 +4133,7 @@ function reportNeverSync(section2) {
3965
4133
  );
3966
4134
  }
3967
4135
 
3968
- // src/commands.doctor.checks.skills.ts
4136
+ // src/commands/doctor/checks/skills.ts
3969
4137
  init_color();
3970
4138
  import { existsSync as existsSync14 } from "node:fs";
3971
4139
  import { join as join20 } from "node:path";
@@ -4013,15 +4181,15 @@ function reportSkillsDivergence(section2) {
4013
4181
  }
4014
4182
  }
4015
4183
 
4016
- // src/commands.doctor.checks.git-state.ts
4184
+ // src/commands/doctor/checks/git-state.ts
4017
4185
  init_color();
4018
4186
  init_config();
4019
4187
  import { execFileSync as execFileSync6 } from "node:child_process";
4020
- import { existsSync as existsSync17 } from "node:fs";
4021
- import { join as join24, relative as relative5 } from "node:path";
4022
- init_commands_pull_wedge();
4188
+ import { existsSync as existsSync18 } from "node:fs";
4189
+ import { join as join25, relative as relative5 } from "node:path";
4190
+ init_wedge();
4023
4191
 
4024
- // src/git-probe.ts
4192
+ // src/core/git-probe.ts
4025
4193
  import { execFileSync as execFileSync4 } from "node:child_process";
4026
4194
  var PROBE_TIMEOUT_MS = 1e4;
4027
4195
  var PROBE_MAX_BUFFER = 64 * 1024 * 1024;
@@ -4038,8 +4206,8 @@ function gitProbe(args, repo) {
4038
4206
  }
4039
4207
  }
4040
4208
 
4041
- // src/commands.doctor.checks.git-state.ts
4042
- init_push_checks();
4209
+ // src/commands/doctor/checks/git-state.ts
4210
+ init_checks();
4043
4211
  init_utils();
4044
4212
  function reportGitleaksProbe(section2) {
4045
4213
  try {
@@ -4060,8 +4228,8 @@ function reportGitleaksProbe(section2) {
4060
4228
  }
4061
4229
  function reportGitlinks(section2) {
4062
4230
  const repo = repoHome();
4063
- const sharedDir = join24(repo, "shared");
4064
- if (existsSync17(sharedDir)) {
4231
+ const sharedDir = join25(repo, "shared");
4232
+ if (existsSync18(sharedDir)) {
4065
4233
  const gitlinks = findGitlinks(sharedDir);
4066
4234
  for (const p of gitlinks) {
4067
4235
  const rel = relative5(repo, p).replaceAll("\\", "/");
@@ -4196,10 +4364,10 @@ function reportTrackedDeniedShared(section2) {
4196
4364
  );
4197
4365
  }
4198
4366
 
4199
- // src/commands.doctor.checks.backups.ts
4367
+ // src/commands/doctor/checks/backups.ts
4200
4368
  init_color();
4201
- import { existsSync as existsSync18, lstatSync as lstatSync12, readdirSync as readdirSync9 } from "node:fs";
4202
- import { join as join25 } from "node:path";
4369
+ import { existsSync as existsSync19, lstatSync as lstatSync12, readdirSync as readdirSync9 } from "node:fs";
4370
+ import { join as join26 } from "node:path";
4203
4371
  init_config();
4204
4372
  var TS_SHAPE2 = /^\d{8}-\d{6}(-\d+)?$/;
4205
4373
  function safeReaddir(dir) {
@@ -4215,7 +4383,7 @@ var BYTES_PER_MB = 1024 * 1024;
4215
4383
  function dirSizeBytes(dir) {
4216
4384
  let bytes = 0;
4217
4385
  for (const entry of safeReaddir(dir)) {
4218
- const full = join25(dir, entry);
4386
+ const full = join26(dir, entry);
4219
4387
  const st = lstatSync12(full, { throwIfNoEntry: false });
4220
4388
  if (!st) continue;
4221
4389
  if (st.isSymbolicLink()) continue;
@@ -4226,11 +4394,11 @@ function dirSizeBytes(dir) {
4226
4394
  }
4227
4395
  function totalSizeMb(backupBase2, dirs) {
4228
4396
  let bytes = 0;
4229
- for (const name of dirs) bytes += dirSizeBytes(join25(backupBase2, name));
4397
+ for (const name of dirs) bytes += dirSizeBytes(join26(backupBase2, name));
4230
4398
  return bytes / BYTES_PER_MB;
4231
4399
  }
4232
4400
  function reportBackupsCheck(section2, backupBase2 = backupBase()) {
4233
- if (!existsSync18(backupBase2)) return;
4401
+ if (!existsSync19(backupBase2)) return;
4234
4402
  const dirs = safeReaddir(backupBase2).filter((n) => TS_SHAPE2.test(n));
4235
4403
  const count = dirs.length;
4236
4404
  const sizeMb = totalSizeMb(backupBase2, dirs);
@@ -4242,7 +4410,7 @@ function reportBackupsCheck(section2, backupBase2 = backupBase()) {
4242
4410
  }
4243
4411
  }
4244
4412
 
4245
- // src/commands.doctor.check-remote.ts
4413
+ // src/commands/doctor/checks/remote.ts
4246
4414
  init_color();
4247
4415
  import { execFileSync as execFileSync7 } from "node:child_process";
4248
4416
  init_config();
@@ -4309,13 +4477,13 @@ function reportCheckRemote(section2) {
4309
4477
  addItem(section2, `${green(okGlyph)} remote: origin/main has shared/ and a valid path-map.json`);
4310
4478
  }
4311
4479
 
4312
- // src/commands.doctor.check-schema.ts
4480
+ // src/commands/doctor/checks/schema.ts
4313
4481
  init_color();
4314
- import { existsSync as existsSync19 } from "node:fs";
4315
- import { join as join26 } from "node:path";
4482
+ import { existsSync as existsSync20 } from "node:fs";
4483
+ import { join as join27 } from "node:path";
4316
4484
  init_config();
4317
4485
 
4318
- // src/http-fetch.ts
4486
+ // src/core/http-fetch.ts
4319
4487
  import { execFileSync as execFileSync8 } from "node:child_process";
4320
4488
  var FETCH_TIMEOUT_MS = 3e3;
4321
4489
  function fetchUrl(url, run = execFileSync8) {
@@ -4336,7 +4504,7 @@ function fetchUrl(url, run = execFileSync8) {
4336
4504
  }
4337
4505
  }
4338
4506
 
4339
- // src/commands.doctor.check-schema.ts
4507
+ // src/commands/doctor/checks/schema.ts
4340
4508
  function fetchSchemaKeys() {
4341
4509
  try {
4342
4510
  const raw = fetchUrl(SETTINGS_SCHEMA_URL);
@@ -4349,8 +4517,8 @@ function fetchSchemaKeys() {
4349
4517
  }
4350
4518
  }
4351
4519
  function reportCheckSchema(section2) {
4352
- const settingsPath = join26(claudeHome(), "settings.json");
4353
- if (!existsSync19(settingsPath)) {
4520
+ const settingsPath = join27(claudeHome(), "settings.json");
4521
+ if (!existsSync20(settingsPath)) {
4354
4522
  addItem(section2, `${dim(infoGlyph)} no ~/.claude/settings.json to check`);
4355
4523
  return;
4356
4524
  }
@@ -4376,23 +4544,23 @@ function reportCheckSchema(section2) {
4376
4544
  }
4377
4545
  }
4378
4546
 
4379
- // src/commands.doctor.check-shared.ts
4547
+ // src/commands/doctor/checks/shared.ts
4380
4548
  init_color();
4381
4549
  import { randomBytes as randomBytes3 } from "node:crypto";
4382
4550
  import { execFileSync as execFileSync12 } from "node:child_process";
4383
- import { existsSync as existsSync22, mkdirSync as mkdirSync8, readdirSync as readdirSync12, rmSync as rmSync12 } from "node:fs";
4551
+ import { existsSync as existsSync23, mkdirSync as mkdirSync8, readdirSync as readdirSync12, rmSync as rmSync12 } from "node:fs";
4384
4552
  import { homedir as homedir6 } from "node:os";
4385
- import { join as join33 } from "node:path";
4553
+ import { join as join34 } from "node:path";
4386
4554
 
4387
- // src/commands.doctor.check-shared.memory.ts
4555
+ // src/commands/doctor/checks/shared.memory.ts
4388
4556
  init_color();
4389
4557
  import { execFileSync as execFileSync10 } from "node:child_process";
4390
4558
  import { randomBytes } from "node:crypto";
4391
4559
  import { mkdirSync as mkdirSync4, rmSync as rmSync9, writeFileSync as writeFileSync4 } from "node:fs";
4392
4560
  import { homedir as homedir4 } from "node:os";
4393
- import { dirname as dirname4, join as join28 } from "node:path";
4561
+ import { dirname as dirname5, join as join29 } from "node:path";
4394
4562
  init_config();
4395
- init_push_gitleaks();
4563
+ init_gitleaks();
4396
4564
  init_utils_fs();
4397
4565
  var MEMORY_MD_PATH = /^shared\/projects\/([^/]+)\/memory\/[^/]+\.md$/;
4398
4566
  function buildMemoryScanTree(tmpRoot) {
@@ -4423,8 +4591,8 @@ function buildMemoryScanTree(tmpRoot) {
4423
4591
  incomplete = true;
4424
4592
  continue;
4425
4593
  }
4426
- const dest = join28(tmpRoot, rel);
4427
- mkdirSync4(dirname4(dest), { recursive: true });
4594
+ const dest = join29(tmpRoot, rel);
4595
+ mkdirSync4(dirname5(dest), { recursive: true });
4428
4596
  writeFileSync4(dest, blob);
4429
4597
  logicals.add(m[1]);
4430
4598
  }
@@ -4442,10 +4610,10 @@ function reportMemoryFindings(section2, findings) {
4442
4610
  function reportCommittedMemory(section2) {
4443
4611
  let tmpRoot;
4444
4612
  try {
4445
- const cacheDir = join28(homedir4(), ".cache", "claude-nomad");
4613
+ const cacheDir = join29(homedir4(), ".cache", "claude-nomad");
4446
4614
  mkdirSync4(cacheDir, { recursive: true });
4447
4615
  const stamp = `${nowTimestamp()}-${process.pid}-${randomBytes(4).toString("hex")}`;
4448
- tmpRoot = join28(cacheDir, `check-shared-memory-tree-${stamp}`);
4616
+ tmpRoot = join29(cacheDir, `check-shared-memory-tree-${stamp}`);
4449
4617
  mkdirSync4(tmpRoot, { recursive: true, mode: 448 });
4450
4618
  const { staged, incomplete } = buildMemoryScanTree(tmpRoot);
4451
4619
  if (incomplete) {
@@ -4490,14 +4658,14 @@ function reportCommittedMemory(section2) {
4490
4658
  }
4491
4659
  }
4492
4660
 
4493
- // src/commands.doctor.check-shared.scan.ts
4661
+ // src/commands/doctor/checks/shared.scan.ts
4494
4662
  init_color();
4495
- import { join as join29 } from "node:path";
4663
+ import { join as join30 } from "node:path";
4496
4664
  init_config();
4497
- init_push_gitleaks();
4665
+ init_gitleaks();
4498
4666
  function scrubPath(logical, sid, logicalToEncoded) {
4499
4667
  const encoded = logicalToEncoded.get(logical) ?? logical;
4500
- return join29(claudeHome(), "projects", encoded, `${sid}.jsonl`);
4668
+ return join30(claudeHome(), "projects", encoded, `${sid}.jsonl`);
4501
4669
  }
4502
4670
  function reportSessionFindings(section2, bySession) {
4503
4671
  for (const [sid, counts] of bySession) {
@@ -4580,15 +4748,15 @@ function scanAndReport(section2, tmpRoot, staged, logicalToEncoded) {
4580
4748
  emitDescriptionLegend(section2, findings);
4581
4749
  }
4582
4750
 
4583
- // src/commands.doctor.check-shared.skills.ts
4751
+ // src/commands/doctor/checks/shared.skills.ts
4584
4752
  init_color();
4585
4753
  import { execFileSync as execFileSync11 } from "node:child_process";
4586
4754
  import { randomBytes as randomBytes2 } from "node:crypto";
4587
4755
  import { mkdirSync as mkdirSync5, rmSync as rmSync10, writeFileSync as writeFileSync5 } from "node:fs";
4588
4756
  import { homedir as homedir5 } from "node:os";
4589
- import { dirname as dirname5, join as join30 } from "node:path";
4757
+ import { dirname as dirname6, join as join31 } from "node:path";
4590
4758
  init_config();
4591
- init_push_gitleaks();
4759
+ init_gitleaks();
4592
4760
  init_utils_fs();
4593
4761
  var SKILL_PATH = /^shared\/skills\/([^/]+)\/(.+)$/;
4594
4762
  function buildSkillScanTree(tmpRoot) {
@@ -4619,8 +4787,8 @@ function buildSkillScanTree(tmpRoot) {
4619
4787
  incomplete = true;
4620
4788
  continue;
4621
4789
  }
4622
- const dest = join30(tmpRoot, rel);
4623
- mkdirSync5(dirname5(dest), { recursive: true });
4790
+ const dest = join31(tmpRoot, rel);
4791
+ mkdirSync5(dirname6(dest), { recursive: true });
4624
4792
  writeFileSync5(dest, blob);
4625
4793
  names.add(m[1]);
4626
4794
  }
@@ -4642,10 +4810,10 @@ function reportSkillFindings(section2, findings) {
4642
4810
  function reportCommittedSkills(section2) {
4643
4811
  let tmpRoot;
4644
4812
  try {
4645
- const cacheDir = join30(homedir5(), ".cache", "claude-nomad");
4813
+ const cacheDir = join31(homedir5(), ".cache", "claude-nomad");
4646
4814
  mkdirSync5(cacheDir, { recursive: true });
4647
4815
  const stamp = `${nowTimestamp()}-${process.pid}-${randomBytes2(4).toString("hex")}`;
4648
- tmpRoot = join30(cacheDir, `check-shared-skills-tree-${stamp}`);
4816
+ tmpRoot = join31(cacheDir, `check-shared-skills-tree-${stamp}`);
4649
4817
  mkdirSync5(tmpRoot, { recursive: true, mode: 448 });
4650
4818
  const { staged, incomplete } = buildSkillScanTree(tmpRoot);
4651
4819
  if (incomplete) {
@@ -4690,22 +4858,22 @@ function reportCommittedSkills(section2) {
4690
4858
  }
4691
4859
  }
4692
4860
 
4693
- // src/commands.doctor.check-shared.ts
4861
+ // src/commands/doctor/checks/shared.ts
4694
4862
  init_config();
4695
4863
 
4696
- // src/remap.ts
4864
+ // src/sync/remap.ts
4697
4865
  init_config_sharedDirs_guard();
4698
- import { cpSync as cpSync5, existsSync as existsSync21, lstatSync as lstatSync13, mkdirSync as mkdirSync7, readdirSync as readdirSync11, rmSync as rmSync11, statSync as statSync6 } from "node:fs";
4699
- import { dirname as dirname7, join as join32, relative as relative6, sep as sep5 } from "node:path";
4866
+ import { cpSync as cpSync5, existsSync as existsSync22, lstatSync as lstatSync13, mkdirSync as mkdirSync7, readdirSync as readdirSync11, rmSync as rmSync11, statSync as statSync6 } from "node:fs";
4867
+ import { dirname as dirname8, join as join33, relative as relative6, sep as sep5 } from "node:path";
4700
4868
  init_config();
4701
4869
 
4702
- // src/push-manifest.ts
4870
+ // src/commands/push/manifest.ts
4703
4871
  init_config();
4704
- init_push_gitleaks_config();
4872
+ init_gitleaks_config();
4705
4873
  init_utils_fs();
4706
4874
  import { createHash } from "node:crypto";
4707
- import { existsSync as existsSync20, mkdirSync as mkdirSync6, readdirSync as readdirSync10, readFileSync as readFileSync7, statSync as statSync5 } from "node:fs";
4708
- import { dirname as dirname6, join as join31 } from "node:path";
4875
+ import { existsSync as existsSync21, mkdirSync as mkdirSync6, readdirSync as readdirSync10, readFileSync as readFileSync7, statSync as statSync5 } from "node:fs";
4876
+ import { dirname as dirname7, join as join32 } from "node:path";
4709
4877
  function isChanged(prev, cur, hash) {
4710
4878
  if (prev === void 0) return true;
4711
4879
  if (prev.size !== cur.size) return true;
@@ -4746,7 +4914,7 @@ function hashFile(absPath) {
4746
4914
  }
4747
4915
  function enumerateDir(dir, results) {
4748
4916
  for (const entry of readdirSync10(dir)) {
4749
- const fullPath = join31(dir, entry);
4917
+ const fullPath = join32(dir, entry);
4750
4918
  const st = statSync5(fullPath);
4751
4919
  if (st.isDirectory()) {
4752
4920
  enumerateDir(fullPath, results);
@@ -4758,7 +4926,7 @@ function enumerateDir(dir, results) {
4758
4926
  function enumerateSourceFiles(projectDir) {
4759
4927
  const results = [];
4760
4928
  for (const entry of readdirSync10(projectDir)) {
4761
- const fullPath = join31(projectDir, entry);
4929
+ const fullPath = join32(projectDir, entry);
4762
4930
  const st = statSync5(fullPath);
4763
4931
  if (st.isDirectory()) {
4764
4932
  enumerateDir(fullPath, results);
@@ -4770,15 +4938,15 @@ function enumerateSourceFiles(projectDir) {
4770
4938
  }
4771
4939
  function fileIdentity(p) {
4772
4940
  if (p === null) return "none::absent";
4773
- if (!existsSync20(p)) return `${p}::absent`;
4941
+ if (!existsSync21(p)) return `${p}::absent`;
4774
4942
  return `${p}::${createHash("sha256").update(readFileSync7(p)).digest("hex")}`;
4775
4943
  }
4776
4944
  function computeConfigHash() {
4777
4945
  const repo = repoHome();
4778
4946
  const parts = [
4779
4947
  fileIdentity(resolveTomlPath(repo)),
4780
- fileIdentity(join31(repo, ".gitleaks.overlay.toml")),
4781
- fileIdentity(join31(repo, ".gitleaksignore"))
4948
+ fileIdentity(join32(repo, ".gitleaks.overlay.toml")),
4949
+ fileIdentity(join32(repo, ".gitleaksignore"))
4782
4950
  ];
4783
4951
  return createHash("sha256").update(parts.join("\n")).digest("hex");
4784
4952
  }
@@ -4798,14 +4966,14 @@ function readManifest(path) {
4798
4966
  }
4799
4967
  }
4800
4968
  function writeManifest(path, manifest) {
4801
- mkdirSync6(dirname6(path), { recursive: true });
4969
+ mkdirSync6(dirname7(path), { recursive: true });
4802
4970
  writeJsonAtomic(path, manifest);
4803
4971
  }
4804
4972
  function buildManifest(files, scannerVersion, configHash) {
4805
4973
  return { schema: 1, scannerVersion, configHash, files };
4806
4974
  }
4807
4975
 
4808
- // src/remap.ts
4976
+ // src/sync/remap.ts
4809
4977
  init_utils();
4810
4978
  init_utils_fs();
4811
4979
  init_utils_json();
@@ -4822,16 +4990,15 @@ function overlaySessionDir(src, dst) {
4822
4990
  cpSyncGuarded(src, dst, void 0, "overlaySessionDir");
4823
4991
  }
4824
4992
  function copyFileAtomic(src, dst) {
4825
- mkdirSync7(dirname7(dst), { recursive: true });
4993
+ mkdirSync7(dirname8(dst), { recursive: true });
4826
4994
  const tmp = `${dst}.tmp.${process.pid}`;
4827
4995
  cpSync5(src, tmp, { force: true, preserveTimestamps: true });
4828
4996
  renameAtomicRetry(tmp, dst);
4829
4997
  }
4830
4998
  function hasDeltaForDir(sel, localDir) {
4831
4999
  const prefix = `${localDir}${sep5}`;
4832
- for (const p of sel.changed) if (p.startsWith(prefix)) return true;
4833
- for (const p of sel.deleted) if (p.startsWith(prefix)) return true;
4834
- return false;
5000
+ const underDir = (p) => p.startsWith(prefix);
5001
+ return [...sel.changed].some(underDir) || sel.deleted.some(underDir);
4835
5002
  }
4836
5003
  function skipForSelection(sel, localDir) {
4837
5004
  return sel !== void 0 && !hasDeltaForDir(sel, localDir);
@@ -4840,12 +5007,12 @@ function applySelective(sel, localDir, repoDst) {
4840
5007
  const prefix = `${localDir}${sep5}`;
4841
5008
  for (const src of sel.changed) {
4842
5009
  if (!src.startsWith(prefix)) continue;
4843
- copyFileAtomic(src, join32(repoDst, relative6(localDir, src)));
5010
+ copyFileAtomic(src, join33(repoDst, relative6(localDir, src)));
4844
5011
  }
4845
5012
  for (const src of sel.deleted) {
4846
5013
  if (!src.startsWith(prefix)) continue;
4847
- const dst = join32(repoDst, relative6(localDir, src));
4848
- if (existsSync21(dst)) rmSync11(dst);
5014
+ const dst = join33(repoDst, relative6(localDir, src));
5015
+ if (existsSync22(dst)) rmSync11(dst);
4849
5016
  }
4850
5017
  }
4851
5018
  function copyDirJsonlOnly(src, dst) {
@@ -4874,15 +5041,15 @@ function remapPull(ts, opts = {}) {
4874
5041
  const wouldPull = [];
4875
5042
  const repo = repoHome();
4876
5043
  const claude = claudeHome();
4877
- const mapPath = join32(repo, "path-map.json");
4878
- const repoProjects = join32(repo, "shared", "projects");
4879
- if (!existsSync21(mapPath) || !existsSync21(repoProjects)) {
5044
+ const mapPath = join33(repo, "path-map.json");
5045
+ const repoProjects = join33(repo, "shared", "projects");
5046
+ if (!existsSync22(mapPath) || !existsSync22(repoProjects)) {
4880
5047
  const text = "no path-map or repo projects dir; skipping session remap";
4881
5048
  emitPreview(opts.onPreview, { kind: "note", text }, text);
4882
5049
  return { unmapped: 0, pulled, wouldPull };
4883
5050
  }
4884
5051
  const map = readPathMap(mapPath);
4885
- const localProjects = join32(claude, "projects");
5052
+ const localProjects = join33(claude, "projects");
4886
5053
  if (!dryRun) mkdirSync7(localProjects, { recursive: true });
4887
5054
  for (const [logical, hosts] of Object.entries(map.projects)) {
4888
5055
  assertSafeLogical(logical);
@@ -4892,9 +5059,9 @@ function remapPull(ts, opts = {}) {
4892
5059
  continue;
4893
5060
  }
4894
5061
  assertSafeLocalRoot(localPath, logical);
4895
- const src = join32(repoProjects, logical);
4896
- if (!existsSync21(src)) continue;
4897
- const dst = join32(localProjects, encodePath(localPath));
5062
+ const src = join33(repoProjects, logical);
5063
+ if (!existsSync22(src)) continue;
5064
+ const dst = join33(localProjects, encodePath(localPath));
4898
5065
  if (dryRun) {
4899
5066
  wouldPull.push(logical);
4900
5067
  emitPreview(
@@ -4913,8 +5080,8 @@ function remapPull(ts, opts = {}) {
4913
5080
  function countLocalOnly(src, dst) {
4914
5081
  let count = 0;
4915
5082
  for (const name of readdirSync11(dst)) {
4916
- const dstPath = join32(dst, name);
4917
- const srcPath = join32(src, name);
5083
+ const dstPath = join33(dst, name);
5084
+ const srcPath = join33(src, name);
4918
5085
  if (lstatSync13(dstPath).isDirectory()) {
4919
5086
  count += countLocalOnly(srcPath, dstPath);
4920
5087
  } else if (lstatSync13(srcPath, { throwIfNoEntry: false }) === void 0) {
@@ -4926,20 +5093,20 @@ function countLocalOnly(src, dst) {
4926
5093
  function scanLocalOnly() {
4927
5094
  const repo = repoHome();
4928
5095
  const claude = claudeHome();
4929
- const mapPath = join32(repo, "path-map.json");
4930
- const repoProjects = join32(repo, "shared", "projects");
4931
- if (!existsSync21(mapPath) || !existsSync21(repoProjects)) return 0;
5096
+ const mapPath = join33(repo, "path-map.json");
5097
+ const repoProjects = join33(repo, "shared", "projects");
5098
+ if (!existsSync22(mapPath) || !existsSync22(repoProjects)) return 0;
4932
5099
  const map = readPathMap(mapPath);
4933
- const localProjects = join32(claude, "projects");
5100
+ const localProjects = join33(claude, "projects");
4934
5101
  let count = 0;
4935
5102
  for (const [logical, hosts] of Object.entries(map.projects)) {
4936
5103
  assertSafeLogical(logical);
4937
5104
  const localPath = hosts[HOST];
4938
5105
  if (!localPath || localPath === "TBD") continue;
4939
5106
  assertSafeLocalRoot(localPath, logical);
4940
- const dst = join32(localProjects, encodePath(localPath));
4941
- if (!existsSync21(dst)) continue;
4942
- count += countLocalOnly(join32(repoProjects, logical), dst);
5107
+ const dst = join33(localProjects, encodePath(localPath));
5108
+ if (!existsSync22(dst)) continue;
5109
+ count += countLocalOnly(join33(repoProjects, logical), dst);
4943
5110
  }
4944
5111
  return count;
4945
5112
  }
@@ -4974,16 +5141,16 @@ function remapPush(ts, opts = {}) {
4974
5141
  const wouldPush = [];
4975
5142
  const repo = repoHome();
4976
5143
  const claude = claudeHome();
4977
- const mapPath = join32(repo, "path-map.json");
4978
- if (!existsSync21(mapPath)) {
5144
+ const mapPath = join33(repo, "path-map.json");
5145
+ if (!existsSync22(mapPath)) {
4979
5146
  log("no path-map.json; skipping session export");
4980
5147
  return { unmapped: 0, collisions: 0, pushed, wouldPush };
4981
5148
  }
4982
5149
  const map = readPathMap(mapPath);
4983
- const localProjects = join32(claude, "projects");
4984
- const repoProjects = join32(repo, "shared", "projects");
5150
+ const localProjects = join33(claude, "projects");
5151
+ const repoProjects = join33(repo, "shared", "projects");
4985
5152
  const reverse = buildReverseMap(map);
4986
- if (!existsSync21(localProjects)) return { unmapped, collisions: 0, pushed, wouldPush };
5153
+ if (!existsSync22(localProjects)) return { unmapped, collisions: 0, pushed, wouldPush };
4987
5154
  if (!dryRun) mkdirSync7(repoProjects, { recursive: true });
4988
5155
  for (const dir of readdirSync11(localProjects)) {
4989
5156
  if (dir.endsWith(TMP_SUFFIX)) continue;
@@ -4992,8 +5159,8 @@ function remapPush(ts, opts = {}) {
4992
5159
  unmapped++;
4993
5160
  continue;
4994
5161
  }
4995
- const localDir = join32(localProjects, dir);
4996
- const repoDst = join32(repoProjects, logical);
5162
+ const localDir = join33(localProjects, dir);
5163
+ const repoDst = join33(repoProjects, logical);
4997
5164
  if (skipForSelection(opts.selection, localDir)) continue;
4998
5165
  if (dryRun) {
4999
5166
  wouldPush.push(logical);
@@ -5010,15 +5177,15 @@ function remapPush(ts, opts = {}) {
5010
5177
  return { unmapped, collisions: 0, pushed, wouldPush };
5011
5178
  }
5012
5179
 
5013
- // src/commands.doctor.check-shared.ts
5180
+ // src/commands/doctor/checks/shared.ts
5014
5181
  init_utils_fs();
5015
5182
  init_utils_json();
5016
5183
  function buildScanTree(tmpRoot) {
5017
5184
  const logicalToEncoded = /* @__PURE__ */ new Map();
5018
5185
  let staged = 0;
5019
5186
  const repo = repoHome();
5020
- const mapPath = join33(repo, "path-map.json");
5021
- if (!existsSync22(mapPath)) return { logicalToEncoded, staged, malformed: false };
5187
+ const mapPath = join34(repo, "path-map.json");
5188
+ if (!existsSync23(mapPath)) return { logicalToEncoded, staged, malformed: false };
5022
5189
  let map;
5023
5190
  try {
5024
5191
  map = readJson(mapPath);
@@ -5035,12 +5202,12 @@ function buildScanTree(tmpRoot) {
5035
5202
  if (!p || p === "TBD") continue;
5036
5203
  reverse.set(encodePath(p), logical);
5037
5204
  }
5038
- const localProjects = join33(claudeHome(), "projects");
5039
- if (!existsSync22(localProjects)) return { logicalToEncoded, staged, malformed: false };
5205
+ const localProjects = join34(claudeHome(), "projects");
5206
+ if (!existsSync23(localProjects)) return { logicalToEncoded, staged, malformed: false };
5040
5207
  for (const dir of readdirSync12(localProjects)) {
5041
5208
  const logical = reverse.get(dir);
5042
5209
  if (!logical) continue;
5043
- copyDirJsonlOnly(join33(localProjects, dir), join33(tmpRoot, "shared", "projects", logical));
5210
+ copyDirJsonlOnly(join34(localProjects, dir), join34(tmpRoot, "shared", "projects", logical));
5044
5211
  logicalToEncoded.set(logical, dir);
5045
5212
  staged++;
5046
5213
  }
@@ -5070,11 +5237,11 @@ function ensureGitleaksReady(section2, gitleaksReady) {
5070
5237
  return true;
5071
5238
  }
5072
5239
  function runLocalPreviewScan(section2) {
5073
- const cacheDir = join33(homedir6(), ".cache", "claude-nomad");
5240
+ const cacheDir = join34(homedir6(), ".cache", "claude-nomad");
5074
5241
  mkdirSync8(cacheDir, { recursive: true });
5075
5242
  const stamp = `${nowTimestamp()}-${process.pid}-${randomBytes3(4).toString("hex")}`;
5076
- const reportPath = join33(cacheDir, `check-shared-${stamp}.json`);
5077
- const tmpRoot = join33(cacheDir, `check-shared-tree-${stamp}`);
5243
+ const reportPath = join34(cacheDir, `check-shared-${stamp}.json`);
5244
+ const tmpRoot = join34(cacheDir, `check-shared-tree-${stamp}`);
5078
5245
  try {
5079
5246
  const { logicalToEncoded, staged, malformed } = buildScanTree(tmpRoot);
5080
5247
  if (malformed) {
@@ -5105,10 +5272,10 @@ function reportCheckShared(section2, gitleaksReady) {
5105
5272
  }
5106
5273
  }
5107
5274
 
5108
- // src/commands.doctor.checks.hooks.scope.ts
5275
+ // src/commands/doctor/checks/hooks.scope.ts
5109
5276
  init_color();
5110
- import { existsSync as existsSync23, readFileSync as readFileSync8, readdirSync as readdirSync13, realpathSync as realpathSync3 } from "node:fs";
5111
- import { dirname as dirname8, extname, join as join34 } from "node:path";
5277
+ import { existsSync as existsSync24, readFileSync as readFileSync8, readdirSync as readdirSync13, realpathSync as realpathSync3 } from "node:fs";
5278
+ import { dirname as dirname9, extname, join as join35 } from "node:path";
5112
5279
  init_config();
5113
5280
  function typeFromPackageJson(pkgPath) {
5114
5281
  try {
@@ -5128,11 +5295,11 @@ function effectiveType(hookPath) {
5128
5295
  } catch {
5129
5296
  return null;
5130
5297
  }
5131
- let dir = dirname8(real);
5298
+ let dir = dirname9(real);
5132
5299
  for (; ; ) {
5133
- const pkg = join34(dir, "package.json");
5134
- if (existsSync23(pkg)) return typeFromPackageJson(pkg);
5135
- const parent = dirname8(dir);
5300
+ const pkg = join35(dir, "package.json");
5301
+ if (existsSync24(pkg)) return typeFromPackageJson(pkg);
5302
+ const parent = dirname9(dir);
5136
5303
  if (parent === dir) return "cjs";
5137
5304
  dir = parent;
5138
5305
  }
@@ -5173,15 +5340,15 @@ function safeRead(path) {
5173
5340
  }
5174
5341
  }
5175
5342
  function reportHookScopeCheck(section2) {
5176
- const hooksDir = join34(claudeHome(), "hooks");
5177
- if (!existsSync23(hooksDir)) {
5343
+ const hooksDir = join35(claudeHome(), "hooks");
5344
+ if (!existsSync24(hooksDir)) {
5178
5345
  addItem(section2, `${dim(infoGlyph)} no ~/.claude/hooks; skipping module-scope check`);
5179
5346
  return;
5180
5347
  }
5181
5348
  let anyWarn = false;
5182
5349
  for (const name of safeReaddir2(hooksDir)) {
5183
5350
  if (extname(name) !== ".js") continue;
5184
- const abs = join34(hooksDir, name);
5351
+ const abs = join35(hooksDir, name);
5185
5352
  const eff = effectiveType(abs);
5186
5353
  if (eff === null) continue;
5187
5354
  const src = safeRead(abs);
@@ -5199,10 +5366,10 @@ function reportHookScopeCheck(section2) {
5199
5366
  }
5200
5367
  }
5201
5368
 
5202
- // src/commands.doctor.checks.hooks.ts
5369
+ // src/commands/doctor/checks/hooks.ts
5203
5370
  init_color();
5204
- import { existsSync as existsSync24 } from "node:fs";
5205
- import { join as join35 } from "node:path";
5371
+ import { existsSync as existsSync25 } from "node:fs";
5372
+ import { join as join36 } from "node:path";
5206
5373
  init_config();
5207
5374
  function expandHome(token) {
5208
5375
  const h2 = home();
@@ -5245,7 +5412,7 @@ function checkEventGroups(section2, event, groups) {
5245
5412
  for (const group of groups) {
5246
5413
  for (const cmd of commandsFromGroup(group)) {
5247
5414
  for (const resolved of claudePathsIn(cmd)) {
5248
- if (existsSync24(resolved)) continue;
5415
+ if (existsSync25(resolved)) continue;
5249
5416
  addItem(
5250
5417
  section2,
5251
5418
  `${red(failGlyph)} hooks/${event}: command target missing: ${resolved} (run nomad pull)`
@@ -5258,8 +5425,8 @@ function checkEventGroups(section2, event, groups) {
5258
5425
  return anyFail;
5259
5426
  }
5260
5427
  function reportHooksTargetCheck(section2) {
5261
- const settingsPath = join35(claudeHome(), "settings.json");
5262
- if (!existsSync24(settingsPath)) {
5428
+ const settingsPath = join36(claudeHome(), "settings.json");
5429
+ if (!existsSync25(settingsPath)) {
5263
5430
  addItem(section2, `${dim(infoGlyph)} no ~/.claude/settings.json; skipping hook target check`);
5264
5431
  return;
5265
5432
  }
@@ -5280,17 +5447,17 @@ function reportHooksTargetCheck(section2) {
5280
5447
  }
5281
5448
  }
5282
5449
 
5283
- // src/commands.doctor.checks.hooks.preserve-symlinks.ts
5450
+ // src/commands/doctor/checks/hooks.preserve-symlinks.ts
5284
5451
  init_color();
5285
- import { existsSync as existsSync26, readFileSync as readFileSync9 } from "node:fs";
5286
- import { join as join37 } from "node:path";
5452
+ import { existsSync as existsSync27, readFileSync as readFileSync9 } from "node:fs";
5453
+ import { join as join38 } from "node:path";
5287
5454
 
5288
- // src/commands.doctor.checks.hooks.preserve-symlinks.probe.ts
5289
- import { closeSync as closeSync3, existsSync as existsSync25, openSync as openSync3, readSync, realpathSync as realpathSync4 } from "node:fs";
5290
- import { dirname as dirname9, join as join36, resolve as resolve3 } from "node:path";
5455
+ // src/commands/doctor/checks/hooks.preserve-symlinks.probe.ts
5456
+ import { closeSync as closeSync3, existsSync as existsSync26, openSync as openSync3, readSync, realpathSync as realpathSync4 } from "node:fs";
5457
+ import { dirname as dirname10, join as join37, resolve as resolve3 } from "node:path";
5291
5458
  function suppressedRanges(src) {
5292
5459
  const ranges = [];
5293
- const re = /\/\*[\s\S]*?\*\/|\/\/[^\n]*|'[^']*'|"[^"]*"|`[^`]*`/g;
5460
+ const re = /\/\*[^]*?\*\/|\/\/[^\n]*|(['"`])(?:\\[^]|[^\\])*?\1/g;
5294
5461
  let m;
5295
5462
  while ((m = re.exec(src)) !== null) {
5296
5463
  ranges.push([m.index, m.index + m[0].length]);
@@ -5303,7 +5470,7 @@ function inSuppressedRange(pos, ranges) {
5303
5470
  }
5304
5471
  return false;
5305
5472
  }
5306
- function topRelativeSpecifiers(src) {
5473
+ function relativeSpecifiers(src) {
5307
5474
  const ranges = suppressedRanges(src);
5308
5475
  const specifiers = [];
5309
5476
  const reqRe = /\brequire\s*\(\s*(['"])(\.\.?\/[^'"]*)\1\s*\)/g;
@@ -5319,12 +5486,12 @@ function topRelativeSpecifiers(src) {
5319
5486
  }
5320
5487
  function specifierIsMissing(specifier, baseDir) {
5321
5488
  const base = resolve3(baseDir, specifier);
5322
- if (existsSync25(base)) return false;
5489
+ if (existsSync26(base)) return false;
5323
5490
  for (const ext of [".js", ".cjs", ".mjs"]) {
5324
- if (existsSync25(base + ext)) return false;
5491
+ if (existsSync26(base + ext)) return false;
5325
5492
  }
5326
5493
  for (const idx of ["index.js", "index.cjs", "index.mjs"]) {
5327
- if (existsSync25(join36(base, idx))) return false;
5494
+ if (existsSync26(join37(base, idx))) return false;
5328
5495
  }
5329
5496
  return true;
5330
5497
  }
@@ -5348,16 +5515,16 @@ function relativeRequireTargetsBroken(scriptPath) {
5348
5515
  } catch {
5349
5516
  return false;
5350
5517
  }
5351
- const specifiers = topRelativeSpecifiers(raw);
5518
+ const specifiers = relativeSpecifiers(raw);
5352
5519
  if (specifiers.length === 0) return false;
5353
- const baseDir = dirname9(realPath);
5520
+ const baseDir = dirname10(realPath);
5354
5521
  for (const spec of specifiers) {
5355
5522
  if (specifierIsMissing(spec, baseDir)) return true;
5356
5523
  }
5357
5524
  return false;
5358
5525
  }
5359
5526
 
5360
- // src/commands.doctor.checks.hooks.preserve-symlinks.ts
5527
+ // src/commands/doctor/checks/hooks.preserve-symlinks.ts
5361
5528
  init_config();
5362
5529
  function expandHome2(token) {
5363
5530
  const h2 = home();
@@ -5379,8 +5546,8 @@ function commandTokens(command) {
5379
5546
  return tokens;
5380
5547
  }
5381
5548
  function readPathMapSafe() {
5382
- const mapPath = join37(repoHome(), "path-map.json");
5383
- if (!existsSync26(mapPath)) return { projects: {} };
5549
+ const mapPath = join38(repoHome(), "path-map.json");
5550
+ if (!existsSync27(mapPath)) return { projects: {} };
5384
5551
  try {
5385
5552
  return JSON.parse(readFileSync9(mapPath, "utf8"));
5386
5553
  } catch {
@@ -5454,8 +5621,8 @@ function checkEventForPreserveSymlinks(section2, event, groups, sharedLinkNames)
5454
5621
  return anyWarn;
5455
5622
  }
5456
5623
  function reportPreserveSymlinksCheck(section2) {
5457
- const settingsPath = join37(claudeHome(), "settings.json");
5458
- if (!existsSync26(settingsPath)) {
5624
+ const settingsPath = join38(claudeHome(), "settings.json");
5625
+ if (!existsSync27(settingsPath)) {
5459
5626
  addItem(
5460
5627
  section2,
5461
5628
  `${dim(infoGlyph)} no ~/.claude/settings.json; skipping preserve-symlinks-main check`
@@ -5486,10 +5653,10 @@ function reportPreserveSymlinksCheck(section2) {
5486
5653
  }
5487
5654
  }
5488
5655
 
5489
- // src/commands.doctor.checks.settings-drift.ts
5656
+ // src/commands/doctor/checks/settings-drift.ts
5490
5657
  init_color();
5491
- import { existsSync as existsSync27, readFileSync as readFileSync10 } from "node:fs";
5492
- import { join as join38 } from "node:path";
5658
+ import { existsSync as existsSync28, readFileSync as readFileSync10 } from "node:fs";
5659
+ import { join as join39 } from "node:path";
5493
5660
  init_config();
5494
5661
  init_utils_json();
5495
5662
  function diffMergedSettings(merged, settings) {
@@ -5507,7 +5674,7 @@ function tryReadJson(filePath) {
5507
5674
  }
5508
5675
  }
5509
5676
  function reportHooksBaseSelfCleanNote(section2) {
5510
- const basePath = join38(repoHome(), "shared", "settings.base.json");
5677
+ const basePath = join39(repoHome(), "shared", "settings.base.json");
5511
5678
  const base = tryReadJson(basePath);
5512
5679
  if (base === null) return;
5513
5680
  if (!baseHasGsdHookEntries(base)) return;
@@ -5520,14 +5687,14 @@ function reportSettingsDriftCheck(section2) {
5520
5687
  const claude = claudeHome();
5521
5688
  const repo = repoHome();
5522
5689
  const host = HOST;
5523
- const settingsPath = join38(claude, "settings.json");
5524
- const basePath = join38(repo, "shared", "settings.base.json");
5525
- const hostPath = join38(repo, "hosts", `${host}.json`);
5526
- if (!existsSync27(settingsPath)) {
5690
+ const settingsPath = join39(claude, "settings.json");
5691
+ const basePath = join39(repo, "shared", "settings.base.json");
5692
+ const hostPath = join39(repo, "hosts", `${host}.json`);
5693
+ if (!existsSync28(settingsPath)) {
5527
5694
  addItem(section2, `${dim(infoGlyph)} no ~/.claude/settings.json; skipping merge-drift check`);
5528
5695
  return;
5529
5696
  }
5530
- if (!existsSync27(basePath)) {
5697
+ if (!existsSync28(basePath)) {
5531
5698
  addItem(
5532
5699
  section2,
5533
5700
  `${dim(infoGlyph)} shared/settings.base.json missing; skipping merge-drift check`
@@ -5546,7 +5713,7 @@ function reportSettingsDriftCheck(section2) {
5546
5713
  if (settings === null) {
5547
5714
  return;
5548
5715
  }
5549
- const hostExists = existsSync27(hostPath);
5716
+ const hostExists = existsSync28(hostPath);
5550
5717
  const hostObj = hostExists ? tryReadJson(hostPath) : null;
5551
5718
  if (hostExists && hostObj === null) {
5552
5719
  addItem(
@@ -5590,19 +5757,20 @@ function emitDriftRows(section2, missing, changed, promotable, excluded, hostFil
5590
5757
  }
5591
5758
  }
5592
5759
 
5593
- // src/commands.doctor.ts
5760
+ // src/commands/doctor/doctor.ts
5594
5761
  init_config();
5595
5762
 
5596
- // src/commands.doctor.engine.ts
5763
+ // src/commands/doctor/engine.ts
5597
5764
  init_color();
5598
5765
  import { readFileSync as readFileSync12 } from "node:fs";
5599
- import { fileURLToPath as fileURLToPath3 } from "node:url";
5766
+ import { join as join41 } from "node:path";
5600
5767
 
5601
- // src/commands.doctor.version.ts
5768
+ // src/commands/doctor/version.ts
5602
5769
  init_color();
5603
5770
  import { readFileSync as readFileSync11 } from "node:fs";
5604
- import { fileURLToPath as fileURLToPath2 } from "node:url";
5771
+ import { join as join40 } from "node:path";
5605
5772
  init_config();
5773
+ init_package_root();
5606
5774
  var STRICT_SEMVER = /^\d+\.\d+\.\d+$/;
5607
5775
  var STRICT_SEMVER_PREFIX = /^(\d+\.\d+\.\d+)(?:[-+]|$)/;
5608
5776
  function compareSemver(a, b) {
@@ -5616,7 +5784,7 @@ function compareSemver(a, b) {
5616
5784
  }
5617
5785
  function readLocalVersion() {
5618
5786
  try {
5619
- const pkgPath = fileURLToPath2(new URL("../package.json", import.meta.url));
5787
+ const pkgPath = join40(packageRoot(), "package.json");
5620
5788
  const parsed = JSON.parse(readFileSync11(pkgPath, "utf8"));
5621
5789
  if (typeof parsed.version === "string" && parsed.version.length > 0) {
5622
5790
  return parsed.version;
@@ -5667,7 +5835,8 @@ function reportVersionCheck(section2) {
5667
5835
  }
5668
5836
  }
5669
5837
 
5670
- // src/commands.doctor.engine.ts
5838
+ // src/commands/doctor/engine.ts
5839
+ init_package_root();
5671
5840
  var ENGINES_GTE = /^>=\s*(\d+\.\d+\.\d+)$/;
5672
5841
  function parseMinVersion(spec) {
5673
5842
  const m = ENGINES_GTE.exec(spec);
@@ -5675,7 +5844,7 @@ function parseMinVersion(spec) {
5675
5844
  }
5676
5845
  function readEnginesNode() {
5677
5846
  try {
5678
- const pkgPath = fileURLToPath3(new URL("../package.json", import.meta.url));
5847
+ const pkgPath = join41(packageRoot(), "package.json");
5679
5848
  const parsed = JSON.parse(readFileSync12(pkgPath, "utf8"));
5680
5849
  const node = parsed.engines?.node;
5681
5850
  if (typeof node === "string" && node.length > 0) return node;
@@ -5702,7 +5871,7 @@ function reportNodeEngineCheck(section2) {
5702
5871
  addItem(section2, `${green(okGlyph)} node: ${process.version}`);
5703
5872
  }
5704
5873
 
5705
- // src/commands.doctor.checks.longpaths.ts
5874
+ // src/commands/doctor/checks/longpaths.ts
5706
5875
  init_color();
5707
5876
  import { execFileSync as execFileSync13 } from "node:child_process";
5708
5877
  init_config();
@@ -5760,18 +5929,18 @@ function reportSyncModality(section2) {
5760
5929
  addItem(section2, `${dim(infoGlyph)} sync modality: ${modality}`);
5761
5930
  }
5762
5931
 
5763
- // src/commands.doctor.checks.crlf.ts
5932
+ // src/commands/doctor/checks/crlf.ts
5764
5933
  init_color();
5765
5934
  import { execFileSync as execFileSync14 } from "node:child_process";
5766
- import { existsSync as existsSync28, readFileSync as readFileSync13 } from "node:fs";
5767
- import { join as join39 } from "node:path";
5935
+ import { existsSync as existsSync29, readFileSync as readFileSync13 } from "node:fs";
5936
+ import { join as join42 } from "node:path";
5768
5937
  init_config();
5769
5938
  var PROBE_TIMEOUT_MS3 = 3e3;
5770
5939
  var GUARD_LINE = /^\*\s+-text\b/;
5771
5940
  function hasGitattributesGuard(repo) {
5772
5941
  try {
5773
- const path = join39(repo, ".gitattributes");
5774
- if (!existsSync28(path)) return false;
5942
+ const path = join42(repo, ".gitattributes");
5943
+ if (!existsSync29(path)) return false;
5775
5944
  const content = readFileSync13(path, "utf8");
5776
5945
  return content.split("\n").map((line) => line.trim()).some((line) => line !== "" && !line.startsWith("#") && GUARD_LINE.test(line));
5777
5946
  } catch {
@@ -5810,24 +5979,24 @@ function reportCrlfGuardCheck(section2, run = execFileSync14) {
5810
5979
  addExposedRow(section2, repo, probeAutocrlf(repo, run));
5811
5980
  }
5812
5981
 
5813
- // src/spinner.ts
5982
+ // src/render/spinner.ts
5814
5983
  init_color();
5815
- import { existsSync as existsSync33 } from "node:fs";
5816
- import { fileURLToPath as fileURLToPath4 } from "node:url";
5984
+ import { existsSync as existsSync34 } from "node:fs";
5985
+ import { fileURLToPath as fileURLToPath2 } from "node:url";
5817
5986
  import { Worker } from "node:worker_threads";
5818
5987
 
5819
- // src/commands.push.recovery.ts
5988
+ // src/commands/push/recovery/recovery.ts
5820
5989
  init_config();
5821
5990
  import { readFileSync as readFileSync18, rmSync as rmSync15, writeFileSync as writeFileSync9 } from "node:fs";
5822
- import { join as join47 } from "node:path";
5991
+ import { join as join50 } from "node:path";
5823
5992
  import { createInterface as createInterface2 } from "node:readline/promises";
5824
5993
 
5825
- // src/commands.push.recovery.actions.ts
5994
+ // src/commands/push/recovery/actions.ts
5826
5995
  init_config();
5827
5996
  import { readFileSync as readFileSync17 } from "node:fs";
5828
5997
  import { isAbsolute as isAbsolute2, resolve as resolve4, sep as sep9 } from "node:path";
5829
5998
 
5830
- // src/commands.push.recovery.memory.ts
5999
+ // src/commands/push/recovery/memory.ts
5831
6000
  init_config();
5832
6001
  init_config_sharedDirs_guard();
5833
6002
  import {
@@ -5839,17 +6008,17 @@ import {
5839
6008
  statSync as statSync7,
5840
6009
  writeFileSync as writeFileSync6
5841
6010
  } from "node:fs";
5842
- import { dirname as dirname10, join as join40, sep as sep6 } from "node:path";
5843
- init_push_gitleaks_scan();
6011
+ import { dirname as dirname11, join as join43, sep as sep6 } from "node:path";
6012
+ init_gitleaks_scan();
5844
6013
 
5845
- // src/rel-path-guard.ts
6014
+ // src/core/rel-path-guard.ts
5846
6015
  function isSafeRelPath(relPath) {
5847
6016
  if (relPath.length === 0 || relPath.startsWith("/") || relPath.includes("\\")) return false;
5848
6017
  const segments = relPath.split("/");
5849
6018
  return segments.every((s) => s.length > 0 && s !== "." && s !== "..");
5850
6019
  }
5851
6020
 
5852
- // src/commands.push.recovery.memory.ts
6021
+ // src/commands/push/recovery/memory.ts
5853
6022
  init_utils_fs();
5854
6023
  init_utils_json();
5855
6024
  init_utils();
@@ -5868,8 +6037,8 @@ function resolveMemoryLocalPath(logical, relPath, map) {
5868
6037
  if (!isSafeRelPath(relPath)) return null;
5869
6038
  const abs = map.projects[logical]?.[HOST];
5870
6039
  if (abs === void 0) return null;
5871
- const memoryRoot = join40(claudeHome(), "projects", encodePath(abs), "memory");
5872
- const localPath = join40(memoryRoot, ...relPath.split("/"));
6040
+ const memoryRoot = join43(claudeHome(), "projects", encodePath(abs), "memory");
6041
+ const localPath = join43(memoryRoot, ...relPath.split("/"));
5873
6042
  if (localPath !== memoryRoot && !localPath.startsWith(memoryRoot + sep6)) return null;
5874
6043
  try {
5875
6044
  if (lstatSync14(localPath).isSymbolicLink()) return null;
@@ -5923,13 +6092,13 @@ function applyMemoryRedact(f, ts, map, scan = scanFile) {
5923
6092
  );
5924
6093
  }
5925
6094
  writeFileSync6(localPath, after, "utf8");
5926
- const dest = join40(repoHome(), "shared", "projects", logical, "memory", ...relPath.split("/"));
5927
- mkdirSync9(dirname10(dest), { recursive: true });
6095
+ const dest = join43(repoHome(), "shared", "projects", logical, "memory", ...relPath.split("/"));
6096
+ mkdirSync9(dirname11(dest), { recursive: true });
5928
6097
  cpSync6(localPath, dest, { force: true });
5929
6098
  return true;
5930
6099
  }
5931
6100
 
5932
- // src/commands.push.recovery.skills.ts
6101
+ // src/commands/push/recovery/skills.ts
5933
6102
  init_config();
5934
6103
  import {
5935
6104
  cpSync as cpSync7,
@@ -5940,27 +6109,27 @@ import {
5940
6109
  statSync as statSync8,
5941
6110
  writeFileSync as writeFileSync7
5942
6111
  } from "node:fs";
5943
- import { dirname as dirname11, join as join42, sep as sep7 } from "node:path";
6112
+ import { dirname as dirname12, join as join45, sep as sep7 } from "node:path";
5944
6113
 
5945
- // src/skills-sync.ts
6114
+ // src/sync/skills-sync.ts
5946
6115
  init_config();
5947
- import { existsSync as existsSync29, lstatSync as lstatSync15, mkdirSync as mkdirSync10, readdirSync as readdirSync14, rmSync as rmSync13 } from "node:fs";
5948
- import { join as join41 } from "node:path";
6116
+ import { existsSync as existsSync30, lstatSync as lstatSync15, mkdirSync as mkdirSync10, readdirSync as readdirSync14, rmSync as rmSync13 } from "node:fs";
6117
+ import { join as join44 } from "node:path";
5949
6118
 
5950
- // src/skills-sync.tracked.ts
6119
+ // src/sync/skills-sync.tracked.ts
5951
6120
  init_utils();
5952
- import { basename as basename3 } from "node:path";
6121
+ import { basename as basename4 } from "node:path";
5953
6122
  function trackedRootSkillsAt(ref, repo) {
5954
6123
  try {
5955
6124
  const raw = gitCaptureRaw(["ls-tree", "--name-only", "-z", ref, "--", "shared/skills/"], repo);
5956
6125
  const entries = raw.split("\0").filter((entry) => entry !== "");
5957
- return new Set(entries.map((entry) => basename3(entry)));
6126
+ return new Set(entries.map((entry) => basename4(entry)));
5958
6127
  } catch {
5959
6128
  return /* @__PURE__ */ new Set();
5960
6129
  }
5961
6130
  }
5962
6131
 
5963
- // src/skills-sync.ts
6132
+ // src/sync/skills-sync.ts
5964
6133
  init_utils_fs();
5965
6134
  function isGsdOwned(name) {
5966
6135
  return name.startsWith(GSD_PREFIX);
@@ -5980,9 +6149,9 @@ function copySkillsPull(src, dst, isRootPreserved) {
5980
6149
  copyExtrasFilteredPreservingBy(src, dst, isSkillExcluded, isRootPreserved);
5981
6150
  }
5982
6151
  function syncSkillsPull(ts, prePostHeads) {
5983
- const sharedSkills = join41(repoHome(), "shared", "skills");
5984
- if (!existsSync29(sharedSkills)) return;
5985
- const localSkills = join41(claudeHome(), "skills");
6152
+ const sharedSkills = join44(repoHome(), "shared", "skills");
6153
+ if (!existsSync30(sharedSkills)) return;
6154
+ const localSkills = join44(claudeHome(), "skills");
5986
6155
  backupBeforeWrite(localSkills, ts);
5987
6156
  const dstStat = lstatSync15(localSkills, { throwIfNoEntry: false });
5988
6157
  if (dstStat?.isSymbolicLink() === true) {
@@ -5993,16 +6162,16 @@ function syncSkillsPull(ts, prePostHeads) {
5993
6162
  copySkillsPull(sharedSkills, localSkills, (name) => !tracked.has(name));
5994
6163
  }
5995
6164
  function syncSkillsPush() {
5996
- const localSkills = join41(claudeHome(), "skills");
6165
+ const localSkills = join44(claudeHome(), "skills");
5997
6166
  const stat = lstatSync15(localSkills, { throwIfNoEntry: false });
5998
6167
  if (stat === void 0) return;
5999
6168
  if (stat.isSymbolicLink()) return;
6000
- const sharedSkills = join41(repoHome(), "shared", "skills");
6169
+ const sharedSkills = join44(repoHome(), "shared", "skills");
6001
6170
  copySkillsPush(localSkills, sharedSkills);
6002
6171
  }
6003
6172
 
6004
- // src/commands.push.recovery.skills.ts
6005
- init_push_gitleaks_scan();
6173
+ // src/commands/push/recovery/skills.ts
6174
+ init_gitleaks_scan();
6006
6175
  init_utils_fs();
6007
6176
  init_utils();
6008
6177
  var SKILL_FINDING_PATH = /^shared\/skills\/([^/]+)\/(.+)$/;
@@ -6020,9 +6189,9 @@ function resolveSkillLocalPath(name, relPath) {
6020
6189
  if (!SAFE_SKILL_NAME.test(name) || name === "." || name === "..") return null;
6021
6190
  if (isGsdOwned(name)) return null;
6022
6191
  if (!isSafeRelPath(relPath)) return null;
6023
- const skillsRoot = join42(claudeHome(), "skills");
6024
- const skillRoot = join42(skillsRoot, name);
6025
- const localPath = join42(skillRoot, ...relPath.split("/"));
6192
+ const skillsRoot = join45(claudeHome(), "skills");
6193
+ const skillRoot = join45(skillsRoot, name);
6194
+ const localPath = join45(skillRoot, ...relPath.split("/"));
6026
6195
  if (localPath !== skillRoot && !localPath.startsWith(skillRoot + sep7)) return null;
6027
6196
  try {
6028
6197
  if (lstatSync16(localPath).isSymbolicLink()) return null;
@@ -6074,17 +6243,17 @@ function applySkillRedact(f, ts, scan = scanFile) {
6074
6243
  );
6075
6244
  }
6076
6245
  writeFileSync7(localPath, after, "utf8");
6077
- const dest = join42(repoHome(), "shared", "skills", name, ...relPath.split("/"));
6078
- mkdirSync11(dirname11(dest), { recursive: true });
6246
+ const dest = join45(repoHome(), "shared", "skills", name, ...relPath.split("/"));
6247
+ mkdirSync11(dirname12(dest), { recursive: true });
6079
6248
  cpSync7(localPath, dest, { force: true });
6080
6249
  return true;
6081
6250
  }
6082
6251
 
6083
- // src/commands.push.recovery.allow-gate.ts
6252
+ // src/commands/push/recovery/allow-gate.ts
6084
6253
  init_utils();
6085
6254
 
6086
- // src/commands.push.recovery.seams.ts
6087
- init_push_gitleaks();
6255
+ // src/commands/push/recovery/seams.ts
6256
+ init_gitleaks();
6088
6257
  function findingKey(f) {
6089
6258
  return `${f.File}:${f.StartLine}:${f.StartColumn}:${f.RuleID}`;
6090
6259
  }
@@ -6105,7 +6274,7 @@ function parseAction(raw) {
6105
6274
  return "skip";
6106
6275
  }
6107
6276
 
6108
- // src/commands.push.recovery.allow-gate.ts
6277
+ // src/commands/push/recovery/allow-gate.ts
6109
6278
  function isCleared(f, state) {
6110
6279
  const action = state.actions.get(findingKey(f)) ?? "skip";
6111
6280
  if (action === "allow") return true;
@@ -6149,28 +6318,28 @@ function applyDeferredAllows(findings, state, repo) {
6149
6318
  }
6150
6319
  }
6151
6320
 
6152
- // src/commands.push.recovery.redact.ts
6321
+ // src/commands/push/recovery/redact.ts
6153
6322
  init_config();
6154
6323
  init_config_sharedDirs_guard();
6155
- import { cpSync as cpSync8, existsSync as existsSync32, mkdirSync as mkdirSync12 } from "node:fs";
6156
- import { dirname as dirname13, join as join45, sep as sep8 } from "node:path";
6324
+ import { cpSync as cpSync8, existsSync as existsSync33, mkdirSync as mkdirSync12 } from "node:fs";
6325
+ import { dirname as dirname14, join as join48, sep as sep8 } from "node:path";
6157
6326
 
6158
- // src/commands.redact.ts
6327
+ // src/commands/redact/redact.ts
6159
6328
  init_config();
6160
- import { existsSync as existsSync31 } from "node:fs";
6161
- import { dirname as dirname12, join as join44 } from "node:path";
6329
+ import { existsSync as existsSync32 } from "node:fs";
6330
+ import { dirname as dirname13, join as join47 } from "node:path";
6162
6331
 
6163
- // src/commands.redact.subtree.ts
6164
- import { existsSync as existsSync30, lstatSync as lstatSync17, readFileSync as readFileSync16, readdirSync as readdirSync15, statSync as statSync9, writeFileSync as writeFileSync8 } from "node:fs";
6165
- import { join as join43 } from "node:path";
6332
+ // src/commands/redact/subtree.ts
6333
+ import { existsSync as existsSync31, lstatSync as lstatSync17, readFileSync as readFileSync16, readdirSync as readdirSync15, statSync as statSync9, writeFileSync as writeFileSync8 } from "node:fs";
6334
+ import { join as join46 } from "node:path";
6166
6335
  init_utils_fs();
6167
6336
  init_utils();
6168
6337
  function collectFiles(dir, out) {
6169
- if (!existsSync30(dir)) return;
6338
+ if (!existsSync31(dir)) return;
6170
6339
  const st = lstatSync17(dir);
6171
6340
  if (!st.isDirectory()) return;
6172
6341
  for (const entry of readdirSync15(dir)) {
6173
- const abs = join43(dir, entry);
6342
+ const abs = join46(dir, entry);
6174
6343
  const lst = lstatSync17(abs);
6175
6344
  if (lst.isSymbolicLink()) continue;
6176
6345
  if (lst.isDirectory()) {
@@ -6224,7 +6393,7 @@ function applySubtreeRedactions(mainPath, mainFindings, subtreeFiles, rule, ts,
6224
6393
  return { total, dirty };
6225
6394
  }
6226
6395
 
6227
- // src/commands.pushed-history.ts
6396
+ // src/commands/pushed-history.ts
6228
6397
  init_utils();
6229
6398
  import { execFileSync as execFileSync15 } from "node:child_process";
6230
6399
  function pushedRef(repo) {
@@ -6272,23 +6441,23 @@ function warnIfSessionPushed(id, repo) {
6272
6441
  );
6273
6442
  }
6274
6443
 
6275
- // src/commands.redact.ts
6276
- init_push_gitleaks_scan();
6444
+ // src/commands/redact/redact.ts
6445
+ init_gitleaks_scan();
6277
6446
  init_exit_codes();
6278
6447
  init_utils_fs();
6279
6448
  init_utils_json();
6280
6449
  init_utils();
6281
6450
  function resolveLiveTranscript(id) {
6282
6451
  try {
6283
- const mapPath = join44(repoHome(), "path-map.json");
6284
- if (!existsSync31(mapPath)) return null;
6452
+ const mapPath = join47(repoHome(), "path-map.json");
6453
+ if (!existsSync32(mapPath)) return null;
6285
6454
  const projects = readJson(mapPath).projects;
6286
6455
  const claude = claudeHome();
6287
6456
  for (const hostMap of Object.values(projects)) {
6288
6457
  const abs = hostMap[HOST];
6289
6458
  if (abs === void 0) continue;
6290
- const live = join44(claude, "projects", encodePath(abs), `${id}.jsonl`);
6291
- if (existsSync31(live)) return live;
6459
+ const live = join47(claude, "projects", encodePath(abs), `${id}.jsonl`);
6460
+ if (existsSync32(live)) return live;
6292
6461
  }
6293
6462
  return null;
6294
6463
  } catch {
@@ -6308,17 +6477,17 @@ function cmdRedact(opts, nowMs = Date.now, scan = scanFile) {
6308
6477
  }
6309
6478
  const repo = repoHome();
6310
6479
  const backup = backupBase();
6311
- if (!existsSync31(repo)) die(`repo not cloned at ${repo}`);
6480
+ if (!existsSync32(repo)) die(`repo not cloned at ${repo}`);
6312
6481
  const handle = acquireLock("redact");
6313
6482
  if (handle === null) process.exit(0);
6314
6483
  try {
6315
6484
  const localPath = resolveLiveTranscript(id);
6316
- if (localPath === null || !existsSync31(localPath)) {
6485
+ if (localPath === null || !existsSync32(localPath)) {
6317
6486
  fail(`could not resolve local transcript for session ${id} on this host`);
6318
6487
  process.exitCode = 1;
6319
6488
  return;
6320
6489
  }
6321
- const sessionDir = join44(dirname12(localPath), id);
6490
+ const sessionDir = join47(dirname13(localPath), id);
6322
6491
  const subtreeFiles = listSubtreeFiles(sessionDir);
6323
6492
  if (isSubtreeActive(localPath, subtreeFiles, nowMs())) {
6324
6493
  log(
@@ -6370,8 +6539,8 @@ ${lines}`);
6370
6539
  }
6371
6540
  }
6372
6541
 
6373
- // src/commands.push.recovery.redact.ts
6374
- init_push_gitleaks_scan();
6542
+ // src/commands/push/recovery/redact.ts
6543
+ init_gitleaks_scan();
6375
6544
  init_utils_json();
6376
6545
  init_utils();
6377
6546
  function resolveStagedDir(localPath, map, claude, repo) {
@@ -6379,8 +6548,8 @@ function resolveStagedDir(localPath, map, claude, repo) {
6379
6548
  assertSafeLogical(logical);
6380
6549
  const abs = hostMap[HOST];
6381
6550
  if (abs === void 0) continue;
6382
- if (localPath.startsWith(join45(claude, "projects", encodePath(abs)) + sep8)) {
6383
- return join45(repo, "shared", "projects", logical);
6551
+ if (localPath.startsWith(join48(claude, "projects", encodePath(abs)) + sep8)) {
6552
+ return join48(repo, "shared", "projects", logical);
6384
6553
  }
6385
6554
  }
6386
6555
  return null;
@@ -6390,7 +6559,7 @@ function preflightRedactable(f, map, nowMs) {
6390
6559
  if (sid === null) return "a finding has no resolvable session id (not a session transcript)";
6391
6560
  const localPath = resolveLiveTranscript(sid);
6392
6561
  if (localPath === null) return `session ${sid}: local transcript not found`;
6393
- const sessionDir = join45(dirname13(localPath), sid);
6562
+ const sessionDir = join48(dirname14(localPath), sid);
6394
6563
  const subtreeFiles = listSubtreeFiles(sessionDir);
6395
6564
  if (isSubtreeActive(localPath, subtreeFiles, nowMs())) {
6396
6565
  return `session ${sid}: looks active (modified within the last 5 minutes)`;
@@ -6419,7 +6588,7 @@ function applyRedact(f, ts, map, nowMs, scan = scanFile) {
6419
6588
  `could not locate the local transcript for session ${sid}; choose Skip or Drop session.`
6420
6589
  );
6421
6590
  }
6422
- const sessionDir = join45(dirname13(localPath), sid);
6591
+ const sessionDir = join48(dirname14(localPath), sid);
6423
6592
  const subtreeFiles = listSubtreeFiles(sessionDir);
6424
6593
  if (isSubtreeActive(localPath, subtreeFiles, nowMs())) {
6425
6594
  return refuse(
@@ -6452,35 +6621,35 @@ function applyRedact(f, ts, map, nowMs, scan = scanFile) {
6452
6621
  );
6453
6622
  }
6454
6623
  mkdirSync12(stagedProjectDir, { recursive: true });
6455
- cpSync8(localPath, join45(stagedProjectDir, `${sid}.jsonl`), { force: true });
6456
- if (existsSync32(sessionDir)) {
6457
- cpSync8(sessionDir, join45(stagedProjectDir, sid), { force: true, recursive: true });
6624
+ cpSync8(localPath, join48(stagedProjectDir, `${sid}.jsonl`), { force: true });
6625
+ if (existsSync33(sessionDir)) {
6626
+ cpSync8(sessionDir, join48(stagedProjectDir, sid), { force: true, recursive: true });
6458
6627
  }
6459
6628
  return true;
6460
6629
  }
6461
6630
 
6462
- // src/commands.push.recovery.drop.ts
6631
+ // src/commands/push/recovery/drop.ts
6463
6632
  init_config();
6464
6633
  import { rmSync as rmSync14 } from "node:fs";
6465
- import { join as join46 } from "node:path";
6634
+ import { join as join49 } from "node:path";
6466
6635
  function dropSessionFromStaged(sid, map) {
6467
6636
  const logicals = Object.keys(map.projects);
6468
6637
  if (logicals.length === 0) return false;
6469
6638
  const repo = repoHome();
6470
6639
  for (const logical of logicals) {
6471
- const jsonl = join46(repo, "shared", "projects", logical, `${sid}.jsonl`);
6472
- const dir = join46(repo, "shared", "projects", logical, sid);
6640
+ const jsonl = join49(repo, "shared", "projects", logical, `${sid}.jsonl`);
6641
+ const dir = join49(repo, "shared", "projects", logical, sid);
6473
6642
  rmSync14(jsonl, { force: true });
6474
6643
  rmSync14(dir, { recursive: true, force: true });
6475
6644
  }
6476
6645
  return true;
6477
6646
  }
6478
6647
 
6479
- // src/commands.push.recovery.actions.ts
6480
- init_push_gitleaks_scan();
6648
+ // src/commands/push/recovery/actions.ts
6649
+ init_gitleaks_scan();
6481
6650
  init_utils();
6482
6651
 
6483
- // src/commands.push.recovery.span-align.ts
6652
+ // src/commands/push/recovery/span-align.ts
6484
6653
  var REDACTED_TOKEN = "REDACTED";
6485
6654
  var SHIFT_WINDOW = [0, -1, 1, -2, 2];
6486
6655
  var ENTROPY_TOLERANCE = 1e-4;
@@ -6567,7 +6736,7 @@ function alignFindingSpan(finding, buf) {
6567
6736
  return breakTie(hits, finding);
6568
6737
  }
6569
6738
 
6570
- // src/commands.push.recovery.secret-shape.ts
6739
+ // src/commands/push/recovery/secret-shape.ts
6571
6740
  var VALUE_HEAD = 4;
6572
6741
  var VALUE_TAIL = 4;
6573
6742
  var MIN_ELIDE_LEN = 16;
@@ -6663,15 +6832,15 @@ function elideTokenRuns(text) {
6663
6832
  });
6664
6833
  }
6665
6834
 
6666
- // src/commands.push.recovery.display.ts
6835
+ // src/commands/push/recovery/display.ts
6667
6836
  var RULE_PAD = 24;
6668
6837
  var GROUP_SEP = "\0";
6669
6838
  function sessionSuffix(finding) {
6670
6839
  const sid = sessionIdFromFinding(finding);
6671
6840
  if (sid === null) return "";
6672
6841
  const rawBasename = finding.File.replace(/^.*\//, "");
6673
- const basename4 = rawBasename.endsWith(".jsonl") ? rawBasename.slice(0, -".jsonl".length) : rawBasename;
6674
- return basename4 === sid ? "" : ` (session: ${sid})`;
6842
+ const basename5 = rawBasename.endsWith(".jsonl") ? rawBasename.slice(0, -".jsonl".length) : rawBasename;
6843
+ return basename5 === sid ? "" : ` (session: ${sid})`;
6675
6844
  }
6676
6845
  function renderFindingBlock(finding, readLine, siblings = []) {
6677
6846
  const lines = [` file: ${finding.File}:${finding.StartLine}${sessionSuffix(finding)}`];
@@ -6721,7 +6890,7 @@ function buildPromptHeader(group, index, total, readLine, peers = 0, siblings =
6721
6890
  return ["", headerLine, ...body, menu, ""].join("\n");
6722
6891
  }
6723
6892
 
6724
- // src/commands.push.recovery.actions.ts
6893
+ // src/commands/push/recovery/actions.ts
6725
6894
  function allowAllFindings(findings, repo) {
6726
6895
  for (const f of findings) {
6727
6896
  appendGitleaksIgnore(f.Fingerprint, repo);
@@ -6854,8 +7023,8 @@ function dispatchActions(findings, actions, opts) {
6854
7023
  applyDeferredAllows(findings, ctx, repo);
6855
7024
  }
6856
7025
 
6857
- // src/commands.push.recovery.redact-all.ts
6858
- init_push_gitleaks_scan();
7026
+ // src/commands/push/recovery/redact-all.ts
7027
+ init_gitleaks_scan();
6859
7028
  init_utils();
6860
7029
  function redactAllDedupeKey(f) {
6861
7030
  const sid = sessionIdFromFinding(f);
@@ -6920,10 +7089,10 @@ function redactAllFindings(findings, ts, map, nowMs, scan = scanFile) {
6920
7089
  }
6921
7090
  }
6922
7091
 
6923
- // src/commands.push.recovery.ts
7092
+ // src/commands/push/recovery/recovery.ts
6924
7093
  init_exit_codes();
6925
- init_push_gitleaks_scan();
6926
- init_push_gitleaks();
7094
+ init_gitleaks_scan();
7095
+ init_gitleaks();
6927
7096
  init_utils();
6928
7097
  function isTTY(stdin = process.stdin, stdout = process.stdout) {
6929
7098
  return stdin.isTTY === true && stdout.isTTY === true;
@@ -6954,7 +7123,7 @@ function applyThenRescan(scanVerdict, repoHome2) {
6954
7123
  return next;
6955
7124
  }
6956
7125
  function allowThenRescan(append, scanVerdict, repoHome2) {
6957
- const ignPath = join47(repoHome2, ".gitleaksignore");
7126
+ const ignPath = join50(repoHome2, ".gitleaksignore");
6958
7127
  let before;
6959
7128
  try {
6960
7129
  before = readFileSync18(ignPath, "utf8");
@@ -6998,7 +7167,7 @@ async function resolveLeakFindings(verdict, ts, map, deps = {}) {
6998
7167
  scan = scanFile,
6999
7168
  printLegend = printRecoveryLegend
7000
7169
  } = deps;
7001
- const scanVerdict = deps.scanVerdict ?? (await Promise.resolve().then(() => (init_push_leak_verdict(), push_leak_verdict_exports))).scanPushVerdict;
7170
+ const scanVerdict = deps.scanVerdict ?? (await Promise.resolve().then(() => (init_leak_verdict(), leak_verdict_exports))).scanPushVerdict;
7002
7171
  const repo = repoHome();
7003
7172
  let current = verdict;
7004
7173
  if (redactAll) {
@@ -7041,7 +7210,7 @@ async function resolveLeakFindings(verdict, ts, map, deps = {}) {
7041
7210
  return current;
7042
7211
  }
7043
7212
 
7044
- // src/spinner.ts
7213
+ // src/render/spinner.ts
7045
7214
  function formatElapsed(ms) {
7046
7215
  return `${(ms / 1e3).toFixed(1)}s`;
7047
7216
  }
@@ -7060,11 +7229,11 @@ function writeAnimatedDone(out, label, ms, useTTY) {
7060
7229
  `);
7061
7230
  }
7062
7231
  function resolveWorkerPath(deps = {}) {
7063
- const check = deps.existsSyncFn ?? existsSync33;
7232
+ const check = deps.existsSyncFn ?? existsSync34;
7064
7233
  const base = deps.baseUrl ?? import.meta.url;
7065
- const mjs = fileURLToPath4(new URL("./nomad.worker.mjs", base));
7234
+ const mjs = fileURLToPath2(new URL("./nomad.worker.mjs", base));
7066
7235
  if (check(mjs)) return mjs;
7067
- return fileURLToPath4(new URL("./spinner.worker.ts", base));
7236
+ return fileURLToPath2(new URL("./spinner.worker.ts", base));
7068
7237
  }
7069
7238
  function makeRealWorker() {
7070
7239
  return new Worker(resolveWorkerPath());
@@ -7124,11 +7293,11 @@ function withSpinner(label, fn, deps) {
7124
7293
  }
7125
7294
  }
7126
7295
 
7127
- // src/commands.doctor.gitleaks-version.ts
7296
+ // src/commands/doctor/gitleaks-version.ts
7128
7297
  init_color();
7129
7298
  import { execFileSync as execFileSync16 } from "node:child_process";
7130
- import { existsSync as existsSync34 } from "node:fs";
7131
- import { join as join48 } from "node:path";
7299
+ import { existsSync as existsSync35 } from "node:fs";
7300
+ import { join as join51 } from "node:path";
7132
7301
  init_config();
7133
7302
  var SEMVER_MAJOR_MINOR = /^(\d+)\.(\d+)\.\d+$/;
7134
7303
  var GITLEAKS_TIMEOUT_MS = 5e3;
@@ -7137,7 +7306,7 @@ function majorMinorOf(value) {
7137
7306
  return m === null ? null : [m[1], m[2]];
7138
7307
  }
7139
7308
  function readGitleaksVersion(run, tomlExists) {
7140
- const tomlPath = join48(repoHome(), ".gitleaks.toml");
7309
+ const tomlPath = join51(repoHome(), ".gitleaks.toml");
7141
7310
  const args = ["version"];
7142
7311
  if (tomlExists(tomlPath)) args.push("--config", tomlPath);
7143
7312
  try {
@@ -7149,7 +7318,7 @@ function readGitleaksVersion(run, tomlExists) {
7149
7318
  return null;
7150
7319
  }
7151
7320
  }
7152
- function reportGitleaksVersionCheck(section2, run = execFileSync16, tomlExists = existsSync34) {
7321
+ function reportGitleaksVersionCheck(section2, run = execFileSync16, tomlExists = existsSync35) {
7153
7322
  const raw = readGitleaksVersion(run, tomlExists);
7154
7323
  if (raw === null) return;
7155
7324
  const local = majorMinorOf(raw);
@@ -7167,7 +7336,7 @@ function reportGitleaksVersionCheck(section2, run = execFileSync16, tomlExists =
7167
7336
  );
7168
7337
  }
7169
7338
 
7170
- // src/commands.doctor.checks.deps.ts
7339
+ // src/commands/doctor/checks/deps.ts
7171
7340
  init_color();
7172
7341
  import { execFileSync as execFileSync17 } from "node:child_process";
7173
7342
  var VERSION_TOKEN = /(\d{1,9}\.\d{1,9}\.\d{1,9})/;
@@ -7219,12 +7388,12 @@ function reportOptionalDeps(section2, run = execFileSync17) {
7219
7388
  reportFetcherRow(section2, run);
7220
7389
  }
7221
7390
 
7222
- // src/commands.doctor.actions-drift.ts
7391
+ // src/commands/doctor/actions-drift.ts
7223
7392
  init_color();
7224
7393
  import { execFileSync as execFileSync19 } from "node:child_process";
7225
7394
  init_config();
7226
7395
 
7227
- // src/gh-actions.ts
7396
+ // src/commands/init/gh-actions.ts
7228
7397
  import { execFileSync as execFileSync18 } from "node:child_process";
7229
7398
  var GH_TIMEOUT_MS = 5e3;
7230
7399
  function parseGitHubRemote(remoteUrl) {
@@ -7284,7 +7453,7 @@ function readOriginRemote(cwd, run = execFileSync18) {
7284
7453
  }).toString().trim();
7285
7454
  }
7286
7455
 
7287
- // src/commands.doctor.actions-drift.ts
7456
+ // src/commands/doctor/actions-drift.ts
7288
7457
  function reportActionsDrift(section2, run = execFileSync19) {
7289
7458
  let remote;
7290
7459
  try {
@@ -7316,7 +7485,7 @@ function reportActionsDrift(section2, run = execFileSync19) {
7316
7485
  );
7317
7486
  }
7318
7487
 
7319
- // src/commands.doctor.verdict.ts
7488
+ // src/commands/doctor/verdict.ts
7320
7489
  init_color();
7321
7490
  function isFailLine(item2) {
7322
7491
  return item2.includes(failGlyph);
@@ -7340,7 +7509,7 @@ function buildVerdictSection(sections) {
7340
7509
  return summary;
7341
7510
  }
7342
7511
 
7343
- // src/commands.doctor.banner.ts
7512
+ // src/commands/doctor/banner.ts
7344
7513
  var NOMAD_BANNER = [
7345
7514
  " __",
7346
7515
  " ____ ____ ____ ___ ____ _ ____/ /",
@@ -7354,7 +7523,7 @@ function printBanner(log2, stdout) {
7354
7523
  log2("");
7355
7524
  }
7356
7525
 
7357
- // src/commands.doctor.compact.ts
7526
+ // src/commands/doctor/compact.ts
7358
7527
  init_color();
7359
7528
  var ALWAYS_FULL = /* @__PURE__ */ new Set([
7360
7529
  "Nomad Version",
@@ -7396,7 +7565,7 @@ function compactSections(sections) {
7396
7565
  });
7397
7566
  }
7398
7567
 
7399
- // src/commands.doctor.ts
7568
+ // src/commands/doctor/doctor.ts
7400
7569
  function gatherDoctorSections(opts) {
7401
7570
  const host = section("Environment");
7402
7571
  reportHostAndPaths(host);
@@ -7406,8 +7575,8 @@ function gatherDoctorSections(opts) {
7406
7575
  reportLongPathsCheck(host);
7407
7576
  reportCrlfGuardCheck(host);
7408
7577
  const links = section("Shared links");
7409
- const mapPath = join49(repoHome(), "path-map.json");
7410
- const rawMap = existsSync35(mapPath) ? readJsonSafe(mapPath, mapPath, links) : null;
7578
+ const mapPath = join52(repoHome(), "path-map.json");
7579
+ const rawMap = existsSync36(mapPath) ? readJsonSafe(mapPath, mapPath, links) : null;
7411
7580
  const map = rawMap ?? { projects: {} };
7412
7581
  reportSharedLinks(links, map);
7413
7582
  reportDroppedNamesMigration(links);
@@ -7482,7 +7651,7 @@ function cmdDoctor(opts = {}) {
7482
7651
  renderDoctor(opts.verbose === true ? report : compactSections(report));
7483
7652
  }
7484
7653
 
7485
- // src/nomad.dispatch.doctor.ts
7654
+ // src/cli/dispatch.doctor.ts
7486
7655
  function parseDoctorArgs(args) {
7487
7656
  if (args[0] === "--resume-cmd") {
7488
7657
  const id = args[1];
@@ -7503,13 +7672,13 @@ function parseDoctorArgs(args) {
7503
7672
  return { kind: "run", checkShared, checkSchema, checkRemote, verbose };
7504
7673
  }
7505
7674
 
7506
- // src/commands.drop-session.ts
7675
+ // src/commands/drop-session/drop-session.ts
7507
7676
  init_config();
7508
7677
  import { execFileSync as execFileSync21 } from "node:child_process";
7509
- import { existsSync as existsSync37, readdirSync as readdirSync16, statSync as statSync10 } from "node:fs";
7510
- import { join as join51, relative as relative7 } from "node:path";
7678
+ import { existsSync as existsSync38, readdirSync as readdirSync16, statSync as statSync10 } from "node:fs";
7679
+ import { join as join54, relative as relative7 } from "node:path";
7511
7680
 
7512
- // src/commands.drop-session.git.ts
7681
+ // src/commands/drop-session/git.ts
7513
7682
  import { execFileSync as execFileSync20 } from "node:child_process";
7514
7683
  function expandStagedDir(dirRel, repo) {
7515
7684
  try {
@@ -7546,12 +7715,12 @@ function isInIndex(rel, repo) {
7546
7715
  }
7547
7716
  }
7548
7717
 
7549
- // src/commands.drop-session.scrub-hint.ts
7718
+ // src/commands/drop-session/scrub-hint.ts
7550
7719
  init_config();
7551
7720
  init_utils();
7552
7721
  init_utils_json();
7553
- import { existsSync as existsSync36 } from "node:fs";
7554
- import { join as join50 } from "node:path";
7722
+ import { existsSync as existsSync37 } from "node:fs";
7723
+ import { join as join53 } from "node:path";
7555
7724
  var SHARED_PROJECT_LOGICAL = /^shared\/projects\/([^/]+)\//;
7556
7725
  function reportScrubHint(id, matches) {
7557
7726
  const live = resolveLiveTranscript2(id, matches);
@@ -7567,8 +7736,8 @@ function reportScrubHint(id, matches) {
7567
7736
  }
7568
7737
  function resolveLiveTranscript2(id, matches) {
7569
7738
  try {
7570
- const mapPath = join50(repoHome(), "path-map.json");
7571
- if (!existsSync36(mapPath)) return null;
7739
+ const mapPath = join53(repoHome(), "path-map.json");
7740
+ if (!existsSync37(mapPath)) return null;
7572
7741
  const projects = readJson(mapPath).projects;
7573
7742
  const claude = claudeHome();
7574
7743
  for (const rel of matches) {
@@ -7576,8 +7745,8 @@ function resolveLiveTranscript2(id, matches) {
7576
7745
  if (logical === void 0) continue;
7577
7746
  const abs = projects[logical]?.[HOST];
7578
7747
  if (abs === void 0) continue;
7579
- const live = join50(claude, "projects", encodePath(abs), `${id}.jsonl`);
7580
- if (existsSync36(live)) return live;
7748
+ const live = join53(claude, "projects", encodePath(abs), `${id}.jsonl`);
7749
+ if (existsSync37(live)) return live;
7581
7750
  }
7582
7751
  return null;
7583
7752
  } catch {
@@ -7585,7 +7754,7 @@ function resolveLiveTranscript2(id, matches) {
7585
7754
  }
7586
7755
  }
7587
7756
 
7588
- // src/commands.drop-session.ts
7757
+ // src/commands/drop-session/drop-session.ts
7589
7758
  init_utils();
7590
7759
  function cmdDropSession(id) {
7591
7760
  if (id.length === 0 || id.length > 128 || !/^[A-Za-z0-9_-]+$/.test(id)) {
@@ -7593,12 +7762,12 @@ function cmdDropSession(id) {
7593
7762
  process.exit(1);
7594
7763
  }
7595
7764
  const repo = repoHome();
7596
- if (!existsSync37(repo)) die(`repo not cloned at ${repo}`);
7765
+ if (!existsSync38(repo)) die(`repo not cloned at ${repo}`);
7597
7766
  const handle = acquireLock("drop-session");
7598
7767
  if (handle === null) process.exit(0);
7599
7768
  try {
7600
- const repoProjects = join51(repo, "shared", "projects");
7601
- if (!existsSync37(repoProjects)) {
7769
+ const repoProjects = join54(repo, "shared", "projects");
7770
+ if (!existsSync38(repoProjects)) {
7602
7771
  throw new NomadFatal(`no staged session matches ${id}`);
7603
7772
  }
7604
7773
  const matches = collectMatches(repoProjects, id, repo);
@@ -7621,12 +7790,12 @@ function cmdDropSession(id) {
7621
7790
  function collectMatches(repoProjects, id, repo) {
7622
7791
  const matches = [];
7623
7792
  for (const logical of readdirSync16(repoProjects)) {
7624
- const candidate = join51(repoProjects, logical, `${id}.jsonl`);
7625
- if (existsSync37(candidate)) {
7793
+ const candidate = join54(repoProjects, logical, `${id}.jsonl`);
7794
+ if (existsSync38(candidate)) {
7626
7795
  matches.push(relative7(repo, candidate));
7627
7796
  }
7628
- const dir = join51(repoProjects, logical, id);
7629
- if (existsSync37(dir) && statSync10(dir).isDirectory()) {
7797
+ const dir = join54(repoProjects, logical, id);
7798
+ if (existsSync38(dir) && statSync10(dir).isDirectory()) {
7630
7799
  const dirRel = relative7(repo, dir);
7631
7800
  const staged = expandStagedDir(dirRel, repo);
7632
7801
  if (staged.length > 0) matches.push(...staged);
@@ -7660,15 +7829,15 @@ function unstageOne(rel, repo) {
7660
7829
  item(`dropped ${rel}`);
7661
7830
  }
7662
7831
 
7663
- // src/commands.pull.ts
7832
+ // src/commands/pull/pull.ts
7664
7833
  init_autostash_guard();
7665
- import { existsSync as existsSync46, mkdirSync as mkdirSync14 } from "node:fs";
7666
- import { join as join62 } from "node:path";
7834
+ import { existsSync as existsSync47, mkdirSync as mkdirSync14 } from "node:fs";
7835
+ import { join as join65 } from "node:path";
7667
7836
 
7668
- // src/commands.push.sections.ts
7837
+ // src/commands/push/sections.ts
7669
7838
  init_color();
7670
7839
 
7671
- // src/summary.ts
7840
+ // src/render/summary.ts
7672
7841
  init_utils();
7673
7842
  function summaryText(verb, unmapped, collisions = 0, extrasSkipped = 0, localOnly = 0) {
7674
7843
  const extras = extrasSkipped > 0 ? `, ${extrasSkipped} extras skipped` : "";
@@ -7693,7 +7862,7 @@ function summaryRow(verb, unmapped, collisions = 0, extrasSkipped = 0, localOnly
7693
7862
  return text.replace(/^summary: /, "");
7694
7863
  }
7695
7864
 
7696
- // src/commands.push.sections.ts
7865
+ // src/commands/push/sections.ts
7697
7866
  function collapsedSkipRow(n, noun) {
7698
7867
  if (n <= 0) return null;
7699
7868
  return `${dim(infoGlyph)} ${n} ${noun}`;
@@ -7766,23 +7935,23 @@ function renderNoScanTree(st, opts = {}) {
7766
7935
  renderTree(buildNoScanSections(st, opts));
7767
7936
  }
7768
7937
 
7769
- // src/commands.pull.ts
7938
+ // src/commands/pull/pull.ts
7770
7939
  init_config();
7771
7940
 
7772
- // src/extras-sync.ts
7941
+ // src/sync/extras/extras.ts
7773
7942
  init_config();
7774
- import { existsSync as existsSync39, statSync as statSync11 } from "node:fs";
7775
- import { join as join54 } from "node:path";
7943
+ import { existsSync as existsSync40, statSync as statSync11 } from "node:fs";
7944
+ import { join as join57 } from "node:path";
7776
7945
  init_utils();
7777
7946
  init_utils_json();
7778
7947
 
7779
- // src/extras-sync.remap.ts
7948
+ // src/sync/extras/remap.ts
7780
7949
  init_config();
7781
- import { existsSync as existsSync38, mkdirSync as mkdirSync13, readdirSync as readdirSync17, readFileSync as readFileSync19, realpathSync as realpathSync7, rmSync as rmSync16 } from "node:fs";
7782
- import { dirname as dirname14, join as join53, sep as sep11 } from "node:path";
7950
+ import { existsSync as existsSync39, mkdirSync as mkdirSync13, readdirSync as readdirSync17, readFileSync as readFileSync19, realpathSync as realpathSync7, rmSync as rmSync16 } from "node:fs";
7951
+ import { dirname as dirname15, join as join56, sep as sep11 } from "node:path";
7783
7952
 
7784
- // src/extras-sync.planning-diff.ts
7785
- import { join as join52, normalize as normalize2, sep as sep10 } from "node:path";
7953
+ // src/sync/extras/planning-diff.ts
7954
+ import { join as join55, normalize as normalize2, sep as sep10 } from "node:path";
7786
7955
  init_utils();
7787
7956
  function processRecord(fields, i, changed, deleted) {
7788
7957
  const status = fields[i];
@@ -7834,7 +8003,7 @@ function planningDeleteTargets(opts) {
7834
8003
  const { deleted } = parsePlanningDiff(raw);
7835
8004
  const logicalPrefix = "shared/extras/" + logical + "/";
7836
8005
  const prefix = logicalPrefix + ".planning/";
7837
- const planningRoot = join52(localRoot, ".planning");
8006
+ const planningRoot = join55(localRoot, ".planning");
7838
8007
  const planningRootBoundary = planningRoot + sep10;
7839
8008
  const targets = [];
7840
8009
  for (const repoPath of deleted) {
@@ -7842,7 +8011,7 @@ function planningDeleteTargets(opts) {
7842
8011
  continue;
7843
8012
  }
7844
8013
  const remainder = repoPath.slice(logicalPrefix.length);
7845
- const candidate = join52(localRoot, remainder);
8014
+ const candidate = join55(localRoot, remainder);
7846
8015
  const resolved = normalize2(candidate);
7847
8016
  if (!resolved.startsWith(planningRootBoundary)) {
7848
8017
  throw new NomadFatal(
@@ -7854,7 +8023,7 @@ function planningDeleteTargets(opts) {
7854
8023
  return targets;
7855
8024
  }
7856
8025
 
7857
- // src/extras-sync.remap.ts
8026
+ // src/sync/extras/remap.ts
7858
8027
  init_utils_fs();
7859
8028
  init_utils();
7860
8029
  function runExtrasOp(v, dryRun, paths, backup, copy) {
@@ -7863,7 +8032,7 @@ function runExtrasOp(v, dryRun, paths, backup, copy) {
7863
8032
  const would = [];
7864
8033
  for (const t of eachExtrasTarget(v, counts)) {
7865
8034
  const { src, dst } = paths(t);
7866
- if (!existsSync38(src)) continue;
8035
+ if (!existsSync39(src)) continue;
7867
8036
  const item2 = `${t.logical}/${t.dirname}`;
7868
8037
  if (dryRun) {
7869
8038
  would.push(item2);
@@ -7876,7 +8045,7 @@ function runExtrasOp(v, dryRun, paths, backup, copy) {
7876
8045
  return { ...counts, done, would };
7877
8046
  }
7878
8047
  function pruneEmptyAncestors(target, planningRoot) {
7879
- let dir = dirname14(target);
8048
+ let dir = dirname15(target);
7880
8049
  while (dir !== planningRoot && dir.startsWith(planningRoot + sep11)) {
7881
8050
  try {
7882
8051
  if (readdirSync17(dir).length > 0) break;
@@ -7884,7 +8053,7 @@ function pruneEmptyAncestors(target, planningRoot) {
7884
8053
  } catch {
7885
8054
  break;
7886
8055
  }
7887
- dir = dirname14(dir);
8056
+ dir = dirname15(dir);
7888
8057
  }
7889
8058
  }
7890
8059
  function tryRealpath(dir) {
@@ -7898,8 +8067,8 @@ function isInsidePlanningRoot(parentReal, rootReal) {
7898
8067
  return parentReal === rootReal || parentReal.startsWith(rootReal + sep11);
7899
8068
  }
7900
8069
  function deletePlanningTarget(target, planningRoot, repoCounterpart) {
7901
- if (existsSync38(repoCounterpart)) return;
7902
- const parentReal = tryRealpath(dirname14(target));
8070
+ if (existsSync39(repoCounterpart)) return;
8071
+ const parentReal = tryRealpath(dirname15(target));
7903
8072
  if (parentReal === void 0) return;
7904
8073
  const rootReal = tryRealpath(planningRoot);
7905
8074
  if (rootReal === void 0) return;
@@ -7908,7 +8077,7 @@ function deletePlanningTarget(target, planningRoot, repoCounterpart) {
7908
8077
  pruneEmptyAncestors(target, planningRoot);
7909
8078
  }
7910
8079
  function localDivergesFromPreDelete(target, pre, repoRel, repo) {
7911
- if (!existsSync38(target)) return false;
8080
+ if (!existsSync39(target)) return false;
7912
8081
  try {
7913
8082
  const preBlob = gitCaptureBuffer(["show", `${pre}:${repoRel}`], repo);
7914
8083
  return !readFileSync19(target).equals(preBlob);
@@ -7953,7 +8122,7 @@ function keptDeletePreview(v, prePostHeads, repo) {
7953
8122
  return kept;
7954
8123
  }
7955
8124
  function propagatePlanningDeletes(v, ts, prePostHeads, repo) {
7956
- const repoExtras = join53(repo, "shared", "extras");
8125
+ const repoExtras = join56(repo, "shared", "extras");
7957
8126
  for (const t of eachExtrasTarget(v, { unmapped: 0, skipped: 0 })) {
7958
8127
  if (t.dirname !== ".planning") continue;
7959
8128
  let raw;
@@ -7968,14 +8137,14 @@ function propagatePlanningDeletes(v, ts, prePostHeads, repo) {
7968
8137
  }
7969
8138
  const pairs = deletePairsFor(t, raw);
7970
8139
  if (pairs.length === 0) continue;
7971
- backupExtrasWrite(join53(t.localRoot, t.dirname), ts, t.localRoot);
7972
- const planningRoot = join53(t.localRoot, ".planning");
8140
+ backupExtrasWrite(join56(t.localRoot, t.dirname), ts, t.localRoot);
8141
+ const planningRoot = join56(t.localRoot, ".planning");
7973
8142
  for (const { target, relToLocal, repoRel } of pairs) {
7974
8143
  if (localDivergesFromPreDelete(target, prePostHeads.pre, repoRel, repo)) {
7975
8144
  warn(keptDeleteWarnLine(t.logical, relToLocal));
7976
8145
  continue;
7977
8146
  }
7978
- deletePlanningTarget(target, planningRoot, join53(repoExtras, t.logical, relToLocal));
8147
+ deletePlanningTarget(target, planningRoot, join56(repoExtras, t.logical, relToLocal));
7979
8148
  }
7980
8149
  }
7981
8150
  }
@@ -7984,14 +8153,14 @@ function remapExtrasPush(ts, opts = {}) {
7984
8153
  const v = loadValidatedExtras({ missingMsg: "no path-map.json; skipping extras push" });
7985
8154
  if (v === null) return { unmapped: 0, skipped: 0, pushed: [], wouldPush: [] };
7986
8155
  const repo = repoHome();
7987
- const repoExtras = join53(repo, "shared", "extras");
8156
+ const repoExtras = join56(repo, "shared", "extras");
7988
8157
  if (!dryRun) mkdirSync13(repoExtras, { recursive: true });
7989
8158
  const { unmapped, skipped, done, would } = runExtrasOp(
7990
8159
  v,
7991
8160
  dryRun,
7992
- ({ localRoot, logical, dirname: dirname15 }) => ({
7993
- src: join53(localRoot, dirname15),
7994
- dst: join53(repoExtras, logical, dirname15)
8161
+ ({ localRoot, logical, dirname: dirname16 }) => ({
8162
+ src: join56(localRoot, dirname16),
8163
+ dst: join56(repoExtras, logical, dirname16)
7995
8164
  }),
7996
8165
  (dst) => backupRepoWrite(dst, ts, repo),
7997
8166
  // Push copy routing per extra type:
@@ -8000,11 +8169,11 @@ function remapExtrasPush(ts, opts = {}) {
8000
8169
  // The filter prevents ALWAYS_NEVER_SYNC files from landing in the repo
8001
8170
  // working tree before the allow-list gate fires, eliminating the
8002
8171
  // "residue wedges repeat push" regression. The allow-list gate
8003
- // (enforceAllowList in commands.push.allowlist.ts, blockSetFor in
8172
+ // (enforceAllowList in commands/push/allowlist.ts, blockSetFor in
8004
8173
  // config.never-sync.ts)
8005
8174
  // remains the hard security boundary.
8006
8175
  // All others: copyExtrasFiltered with per-extra denylist.
8007
- (src, dst, dirname15) => dirname15 === ".planning" ? copyExtrasOverlayFiltered(src, dst, extrasDenySet(dirname15)) : copyExtrasFiltered(src, dst, extrasDenySet(dirname15))
8176
+ (src, dst, dirname16) => dirname16 === ".planning" ? copyExtrasOverlayFiltered(src, dst, extrasDenySet(dirname16)) : copyExtrasFiltered(src, dst, extrasDenySet(dirname16))
8008
8177
  );
8009
8178
  return { unmapped, skipped, pushed: done, wouldPush: would };
8010
8179
  }
@@ -8020,9 +8189,9 @@ function remapExtrasPull(ts, opts = {}) {
8020
8189
  const { unmapped, skipped, done, would } = runExtrasOp(
8021
8190
  v,
8022
8191
  dryRun,
8023
- ({ localRoot, logical, dirname: dirname15 }) => ({
8024
- src: join53(repo, "shared", "extras", logical, dirname15),
8025
- dst: join53(localRoot, dirname15)
8192
+ ({ localRoot, logical, dirname: dirname16 }) => ({
8193
+ src: join56(repo, "shared", "extras", logical, dirname16),
8194
+ dst: join56(localRoot, dirname16)
8026
8195
  }),
8027
8196
  // Snapshot the host-side dst BEFORE the copy step touches it. Anchor on
8028
8197
  // localRoot so the backup tree mirrors the project layout.
@@ -8040,12 +8209,12 @@ function remapExtrasPull(ts, opts = {}) {
8040
8209
  // copyExtrasFileSkipDiverged keeps a locally-edited file rather than
8041
8210
  // clobbering it, so the divergence WARN's keep-local promise holds for
8042
8211
  // every extra, not just `.planning`.
8043
- (src, dst, dirname15) => {
8044
- if (dirname15 === ".claude")
8045
- return copyExtrasFilteredPreserving(src, dst, extrasDenySet(dirname15));
8046
- if (dirname15 === ".planning") {
8212
+ (src, dst, dirname16) => {
8213
+ if (dirname16 === ".claude")
8214
+ return copyExtrasFilteredPreserving(src, dst, extrasDenySet(dirname16));
8215
+ if (dirname16 === ".planning") {
8047
8216
  const divergedSet = new Set(listDivergingModified(dst, src));
8048
- return copyExtrasOverlaySkipDiverged(src, dst, extrasDenySet(dirname15), divergedSet);
8217
+ return copyExtrasOverlaySkipDiverged(src, dst, extrasDenySet(dirname16), divergedSet);
8049
8218
  }
8050
8219
  return copyExtrasFileSkipDiverged(src, dst);
8051
8220
  }
@@ -8056,7 +8225,7 @@ function remapExtrasPull(ts, opts = {}) {
8056
8225
  return { unmapped, skipped, pulled: done, wouldPull: would };
8057
8226
  }
8058
8227
 
8059
- // src/extras-sync.ts
8228
+ // src/sync/extras/extras.ts
8060
8229
  function divergenceWarnLine(o) {
8061
8230
  const kind = o.isDir ? "folder" : "file";
8062
8231
  const name = o.isDir ? `${o.dirname}/` : o.dirname;
@@ -8069,20 +8238,20 @@ function divergenceCheckExtras(ts, prePostHeads) {
8069
8238
  const v = loadValidatedExtras({});
8070
8239
  if (v === null) return 0;
8071
8240
  const counts = { unmapped: 0, skipped: 0 };
8072
- const backupRoot = join54(backupBase(), ts, "extras");
8241
+ const backupRoot = join57(backupBase(), ts, "extras");
8073
8242
  const repo = repoHome();
8074
8243
  let divergedCount = 0;
8075
- for (const { logical, localRoot, dirname: dirname15 } of eachExtrasTarget(v, counts)) {
8076
- const local = join54(localRoot, dirname15);
8077
- const repoEntry = join54(repo, "shared", "extras", logical, dirname15);
8078
- if (!existsSync39(local) || !existsSync39(repoEntry)) continue;
8244
+ for (const { logical, localRoot, dirname: dirname16 } of eachExtrasTarget(v, counts)) {
8245
+ const local = join57(localRoot, dirname16);
8246
+ const repoEntry = join57(repo, "shared", "extras", logical, dirname16);
8247
+ if (!existsSync40(local) || !existsSync40(repoEntry)) continue;
8079
8248
  const modified = listDivergingModified(local, repoEntry);
8080
8249
  if (modified.length === 0) continue;
8081
8250
  divergedCount += modified.length;
8082
- const projectBackupRoot = join54(backupRoot, encodePath(localRoot));
8251
+ const projectBackupRoot = join57(backupRoot, encodePath(localRoot));
8083
8252
  warn(
8084
8253
  divergenceWarnLine({
8085
- dirname: dirname15,
8254
+ dirname: dirname16,
8086
8255
  logical,
8087
8256
  isDir: statSync11(local).isDirectory(),
8088
8257
  count: modified.length,
@@ -8099,10 +8268,10 @@ function divergenceCheckExtras(ts, prePostHeads) {
8099
8268
  return divergedCount;
8100
8269
  }
8101
8270
 
8102
- // src/links.baseline.ts
8271
+ // src/sync/links.baseline.ts
8103
8272
  init_config();
8104
8273
  import { lstatSync as lstatSync18, readdirSync as readdirSync18 } from "node:fs";
8105
- import { join as join55, relative as relative8, sep as sep12 } from "node:path";
8274
+ import { join as join58, relative as relative8, sep as sep12 } from "node:path";
8106
8275
  init_utils();
8107
8276
  var SHARED_BASELINE_KIND = "shared-links-baseline/1";
8108
8277
  var SHARED_BASELINE_CONFIG_HASH = "not-applicable";
@@ -8144,7 +8313,7 @@ function collectSharedFiles(dir, claude, scan) {
8144
8313
  return;
8145
8314
  }
8146
8315
  for (const entry of entries) {
8147
- const abs = join55(dir, entry);
8316
+ const abs = join58(dir, entry);
8148
8317
  if (isDeniedName(ALWAYS_NEVER_SYNC, entry)) {
8149
8318
  scan.declined.push(baselineKey(claude, abs));
8150
8319
  continue;
@@ -8160,7 +8329,7 @@ function enumerateLocalSharedScan(map, opts = {}) {
8160
8329
  scan.declined.push(name);
8161
8330
  continue;
8162
8331
  }
8163
- addLocalPath(join55(claude, name), claude, scan);
8332
+ addLocalPath(join58(claude, name), claude, scan);
8164
8333
  }
8165
8334
  return scan;
8166
8335
  }
@@ -8172,7 +8341,7 @@ function buildSharedBaseline(map, opts = {}) {
8172
8341
  const files = {};
8173
8342
  for (const [key, st] of Object.entries(enumerateLocalSharedFiles(map, opts))) {
8174
8343
  try {
8175
- files[key] = { size: st.size, mtime: st.mtime, hash: hashFile(join55(claude, key)) };
8344
+ files[key] = { size: st.size, mtime: st.mtime, hash: hashFile(join58(claude, key)) };
8176
8345
  } catch {
8177
8346
  }
8178
8347
  }
@@ -8187,12 +8356,12 @@ function writeSharedBaseline(map, opts = {}) {
8187
8356
  }
8188
8357
  }
8189
8358
 
8190
- // src/commands.pull.win32.ts
8359
+ // src/commands/pull/win32.ts
8191
8360
  init_color();
8192
- import { existsSync as existsSync44 } from "node:fs";
8193
- import { join as join60 } from "node:path";
8361
+ import { existsSync as existsSync45 } from "node:fs";
8362
+ import { join as join63 } from "node:path";
8194
8363
 
8195
- // src/commands.pull.recovery.git.ts
8364
+ // src/commands/pull/recovery.git.ts
8196
8365
  init_utils();
8197
8366
  import { execFileSync as execFileSync22 } from "node:child_process";
8198
8367
  function gitCapture(args, cwd) {
@@ -8231,13 +8400,13 @@ function parseDirtyPaths(repo, opts = {}) {
8231
8400
  return parsePorcelainZ(gitStatusPorcelainZ(repo, opts));
8232
8401
  }
8233
8402
 
8234
- // src/commands.pull.win32.ts
8403
+ // src/commands/pull/win32.ts
8235
8404
  init_config();
8236
8405
 
8237
- // src/links.deletions.ts
8406
+ // src/sync/links.deletions.ts
8238
8407
  init_config();
8239
- import { existsSync as existsSync40, lstatSync as lstatSync19, rmSync as rmSync17 } from "node:fs";
8240
- import { join as join56, relative as relative9, resolve as resolve5, sep as sep13 } from "node:path";
8408
+ import { existsSync as existsSync41, lstatSync as lstatSync19, rmSync as rmSync17 } from "node:fs";
8409
+ import { join as join59, relative as relative9, resolve as resolve5, sep as sep13 } from "node:path";
8241
8410
  init_utils();
8242
8411
  init_utils_fs();
8243
8412
  function isUnknown(declined, key) {
@@ -8247,15 +8416,15 @@ function deletionFor(key, names, claude, sharedRoot) {
8247
8416
  const segments = key.split("/");
8248
8417
  const name = segments[0];
8249
8418
  if (!names.has(name)) return null;
8250
- if (!existsSync40(join56(claude, name))) return null;
8419
+ if (!existsSync41(join59(claude, name))) return null;
8251
8420
  if (segments.some((segment) => isDeniedName(ALWAYS_NEVER_SYNC, segment))) return null;
8252
8421
  const repoPath = resolve5(sharedRoot, key);
8253
- const rel = relative9(join56(sharedRoot, name), repoPath);
8422
+ const rel = relative9(join59(sharedRoot, name), repoPath);
8254
8423
  if (rel === "" || rel === ".." || rel.startsWith(`..${sep13}`)) return null;
8255
8424
  if (segments.some((segment) => segment === "" || segment === "." || segment === ".."))
8256
8425
  return null;
8257
- if (!existsSync40(repoPath)) return null;
8258
- return { kind: "deletion", name, localPath: join56(claude, key), repoPath };
8426
+ if (!existsSync41(repoPath)) return null;
8427
+ return { kind: "deletion", name, localPath: join59(claude, key), repoPath };
8259
8428
  }
8260
8429
  function planSharedLinkDeletions(map, opts = {}) {
8261
8430
  if (process.platform !== "win32") return [];
@@ -8263,7 +8432,7 @@ function planSharedLinkDeletions(map, opts = {}) {
8263
8432
  const baseline = readSharedBaseline();
8264
8433
  if (baseline === null) return [];
8265
8434
  const claude = claudeHome();
8266
- const sharedRoot = join56(repoHome(), "shared");
8435
+ const sharedRoot = join59(repoHome(), "shared");
8267
8436
  const linkNames = opts.linkNames ?? allSharedLinks(map);
8268
8437
  const scan = enumerateLocalSharedScan(map, { linkNames });
8269
8438
  const present = new Set(Object.keys(scan.files).map((key) => key.toLowerCase()));
@@ -8295,11 +8464,11 @@ function applySharedLinkDeletions(map, ts, opts = {}) {
8295
8464
  return removed;
8296
8465
  }
8297
8466
 
8298
- // src/links.mirror.ts
8467
+ // src/sync/links.mirror.ts
8299
8468
  init_config();
8300
8469
  init_error_text();
8301
- import { existsSync as existsSync41, lstatSync as lstatSync20, rmSync as rmSync18, statSync as statSync12 } from "node:fs";
8302
- import { join as join57 } from "node:path";
8470
+ import { existsSync as existsSync42, lstatSync as lstatSync20, rmSync as rmSync18, statSync as statSync12 } from "node:fs";
8471
+ import { join as join60 } from "node:path";
8303
8472
  init_utils();
8304
8473
  init_utils_fs();
8305
8474
  function emitMirror(onPreview, name, localPath, repoPath) {
@@ -8313,7 +8482,7 @@ function emitMirrorWet(onPreview, name, localPath, repoPath) {
8313
8482
  if (onPreview) onPreview({ kind: "mirror", name, localPath, repoPath });
8314
8483
  }
8315
8484
  function notShared(target) {
8316
- return !existsSync41(target);
8485
+ return !existsSync42(target);
8317
8486
  }
8318
8487
  function warnUnusableSharedTarget(name, dryRun, state) {
8319
8488
  const reason = state === "dangling" ? `shared/${name} does not resolve to anything usable in the sync repo. Remove it, or restore what it points at` : `shared/${name} could not be read in the sync repo, so whether it is usable could not be determined. Check its permissions there`;
@@ -8341,8 +8510,8 @@ function warnUnreadableLocalName(name, target, err, dryRun) {
8341
8510
  );
8342
8511
  }
8343
8512
  function mirrorOneSharedName(name, claude, repo, policy, opts) {
8344
- const localPath = join57(claude, name);
8345
- const target = join57(repo, "shared", name);
8513
+ const localPath = join60(claude, name);
8514
+ const target = join60(repo, "shared", name);
8346
8515
  let stat;
8347
8516
  try {
8348
8517
  stat = lstatSync20(localPath, { throwIfNoEntry: false });
@@ -8402,7 +8571,7 @@ function mirrorSharedNames(map, policy, opts = {}) {
8402
8571
  if (map === null) return;
8403
8572
  const claude = claudeHome();
8404
8573
  const repo = repoHome();
8405
- const sharedPath = join57(repo, "shared");
8574
+ const sharedPath = join60(repo, "shared");
8406
8575
  const sharedState = classifyPresence(sharedPath);
8407
8576
  if (isUnusableTarget(sharedState)) {
8408
8577
  warnUnusableSharedDir(opts.dryRun === true, sharedState);
@@ -8431,7 +8600,7 @@ function presentAt(abs) {
8431
8600
  }
8432
8601
  }
8433
8602
  function removeUntrackedDenied(repo, path, segment, ts) {
8434
- const abs = join57(repo, path);
8603
+ const abs = join60(repo, path);
8435
8604
  const denied = `the path segment "${segment}" is on the never-sync list`;
8436
8605
  if (!presentAt(abs)) {
8437
8606
  warn(
@@ -8439,7 +8608,7 @@ function removeUntrackedDenied(repo, path, segment, ts) {
8439
8608
  );
8440
8609
  return;
8441
8610
  }
8442
- const snapshotted = existsSync41(abs);
8611
+ const snapshotted = existsSync42(abs);
8443
8612
  try {
8444
8613
  backupRepoWrite(abs, ts, repo);
8445
8614
  } catch (err) {
@@ -8475,7 +8644,7 @@ function reportTrackedDenied(repo, path, segment) {
8475
8644
  );
8476
8645
  return;
8477
8646
  }
8478
- if (!existsSync41(join57(repo, path))) return;
8647
+ if (!existsSync42(join60(repo, path))) return;
8479
8648
  warn(
8480
8649
  `${path} is tracked and has changes against HEAD: ${denied}. Nothing was changed. Run git checkout HEAD -- "${path}" to put the committed content back, or move the file outside shared/ if you want to keep it. Neither of those takes the committed copy out of the repo: git rm -- "${path}" and a commit does that going forward, and if it holds a real secret, rotate it and rewrite history, because nomad only changes your local worktree and index and cannot scrub what a previous push already sent to the remote`
8481
8650
  );
@@ -8491,10 +8660,10 @@ function revertDeniedMirrorPaths(repo, status, ts) {
8491
8660
  }
8492
8661
  }
8493
8662
 
8494
- // src/preview.ts
8663
+ // src/render/preview.ts
8495
8664
  init_config();
8496
- import { existsSync as existsSync43 } from "node:fs";
8497
- import { join as join59 } from "node:path";
8665
+ import { existsSync as existsSync44 } from "node:fs";
8666
+ import { join as join62 } from "node:path";
8498
8667
 
8499
8668
  // node_modules/diff/libesm/diff/base.js
8500
8669
  var Diff = class {
@@ -8746,7 +8915,7 @@ function tokenize(value, options) {
8746
8915
  return retLines;
8747
8916
  }
8748
8917
 
8749
- // src/diff-lines.ts
8918
+ // src/render/diff-lines.ts
8750
8919
  init_color();
8751
8920
  function diffLinesToUnified(oldStr, newStr) {
8752
8921
  const parts = diffLines(oldStr, newStr);
@@ -8767,18 +8936,18 @@ function diffLinesToUnified(oldStr, newStr) {
8767
8936
  return lines;
8768
8937
  }
8769
8938
 
8770
- // src/preview.skills.ts
8939
+ // src/render/preview.skills.ts
8771
8940
  init_config();
8772
- import { existsSync as existsSync42, readdirSync as readdirSync19 } from "node:fs";
8773
- import { join as join58 } from "node:path";
8941
+ import { existsSync as existsSync43, readdirSync as readdirSync19 } from "node:fs";
8942
+ import { join as join61 } from "node:path";
8774
8943
  function buildSkillsPreviewSection() {
8775
8944
  const s = section("Skills");
8776
- const sharedSkills = join58(repoHome(), "shared", "skills");
8777
- if (!existsSync42(sharedSkills)) return s;
8945
+ const sharedSkills = join61(repoHome(), "shared", "skills");
8946
+ if (!existsSync43(sharedSkills)) return s;
8778
8947
  const sharedNames = readdirSync19(sharedSkills, { encoding: "utf8" }).filter((name) => !isSkillExcluded(name)).sort((a, b) => a.localeCompare(b, "en"));
8779
8948
  for (const name of sharedNames) addItem(s, name);
8780
- const localSkills = join58(claudeHome(), "skills");
8781
- const localOnly = existsSync42(localSkills) ? readdirSync19(localSkills, { encoding: "utf8" }).filter(
8949
+ const localSkills = join61(claudeHome(), "skills");
8950
+ const localOnly = existsSync43(localSkills) ? readdirSync19(localSkills, { encoding: "utf8" }).filter(
8782
8951
  (name) => !isSkillExcluded(name) && !sharedNames.includes(name)
8783
8952
  ).length : 0;
8784
8953
  if (localOnly > 0) {
@@ -8787,7 +8956,7 @@ function buildSkillsPreviewSection() {
8787
8956
  return s;
8788
8957
  }
8789
8958
 
8790
- // src/preview.ts
8959
+ // src/render/preview.ts
8791
8960
  init_utils_json();
8792
8961
  var CANONICAL_ORDER_NOTE = "settings.json will be rewritten in canonical key order; no value changes";
8793
8962
  function diffJsonStrings(currentJsonText, newJsonText) {
@@ -8800,7 +8969,7 @@ function diffJsonStrings(currentJsonText, newJsonText) {
8800
8969
  return lines.join("\n");
8801
8970
  }
8802
8971
  function readJsonOrNull(path) {
8803
- if (!existsSync43(path)) return null;
8972
+ if (!existsSync44(path)) return null;
8804
8973
  try {
8805
8974
  return readJson(path);
8806
8975
  } catch {
@@ -8814,12 +8983,12 @@ function previewSettings(basePath, hostPath, settingsPath) {
8814
8983
  }
8815
8984
  const notes = [];
8816
8985
  const hostOverrides = readJsonOrNull(hostPath);
8817
- if (hostOverrides === null && existsSync43(hostPath)) {
8986
+ if (hostOverrides === null && existsSync44(hostPath)) {
8818
8987
  notes.push(`malformed hosts/${HOST}.json; ignoring overrides`);
8819
8988
  }
8820
8989
  const merged = stripGsdHookEntries(deepMerge(base, hostOverrides ?? {}));
8821
8990
  const current = readJsonOrNull(settingsPath);
8822
- if (current === null && existsSync43(settingsPath)) {
8991
+ if (current === null && existsSync44(settingsPath)) {
8823
8992
  return { diff: "", notes: [...notes, "malformed; skipping diff"] };
8824
8993
  }
8825
8994
  const strippedCurrent = stripGsdHookEntries(current ?? {});
@@ -8886,9 +9055,9 @@ function computePreview(ts, map, verb = "pull", plans) {
8886
9055
  onPreview: (e) => addItem(links, formatLinkRow(e))
8887
9056
  });
8888
9057
  const settingsResult = previewSettings(
8889
- join59(repo, "shared", "settings.base.json"),
8890
- join59(repo, "hosts", `${HOST}.json`),
8891
- join59(claude, "settings.json")
9058
+ join62(repo, "shared", "settings.base.json"),
9059
+ join62(repo, "hosts", `${HOST}.json`),
9060
+ join62(claude, "settings.json")
8892
9061
  );
8893
9062
  const settingsSection = buildSettingsSectionForPreview(settingsResult);
8894
9063
  const sessions = section("Sessions");
@@ -8904,7 +9073,7 @@ function computePreview(ts, map, verb = "pull", plans) {
8904
9073
  const extras = section("Extras");
8905
9074
  let extrasSkipped = 0;
8906
9075
  let extrasUnmapped = 0;
8907
- if (existsSync43(join59(repo, "path-map.json")) && existsSync43(join59(repo, "shared", "extras"))) {
9076
+ if (existsSync44(join62(repo, "path-map.json")) && existsSync44(join62(repo, "shared", "extras"))) {
8908
9077
  const extrasResult = remapExtrasPull(ts, { dryRun: true });
8909
9078
  for (const entry of extrasResult.wouldPull) {
8910
9079
  addItem(extras, entry);
@@ -8921,11 +9090,11 @@ function computePreview(ts, map, verb = "pull", plans) {
8921
9090
  return { unmapped: remapResult.unmapped, collisions: 0, localOnly };
8922
9091
  }
8923
9092
 
8924
- // src/commands.pull.win32.ts
9093
+ // src/commands/pull/win32.ts
8925
9094
  init_utils();
8926
9095
  init_utils_json();
8927
9096
  function readMapForMirror(mapPath) {
8928
- if (!existsSync44(mapPath)) return { projects: {} };
9097
+ if (!existsSync45(mapPath)) return { projects: {} };
8929
9098
  try {
8930
9099
  return readPathMap(mapPath);
8931
9100
  } catch {
@@ -8989,7 +9158,7 @@ function reconcileSharedLinksBeforePull(repo, ts) {
8989
9158
  let namesDerived = false;
8990
9159
  let derivedSharedDirs;
8991
9160
  try {
8992
- const map = readMapForMirror(join60(repo, "path-map.json"));
9161
+ const map = readMapForMirror(join63(repo, "path-map.json"));
8993
9162
  if (map !== null) {
8994
9163
  linkNames = allSharedLinks(map);
8995
9164
  namesDerived = true;
@@ -9028,7 +9197,7 @@ function buildMirrorSection(events, discard) {
9028
9197
  function describeSkippedMirrorDiscard(repo, ts) {
9029
9198
  if (process.platform !== "win32") return null;
9030
9199
  try {
9031
- const map = readMapForMirror(join60(repo, "path-map.json"));
9200
+ const map = readMapForMirror(join63(repo, "path-map.json"));
9032
9201
  const linkNames = map !== null ? allSharedLinks(map, { quiet: true }) : void 0;
9033
9202
  const captures = [];
9034
9203
  stageLocalSharedEdits(map, ts, {
@@ -9037,13 +9206,13 @@ function describeSkippedMirrorDiscard(repo, ts) {
9037
9206
  linkNames
9038
9207
  });
9039
9208
  if (captures.length === 0) return null;
9040
- return { count: captures.length, backupPath: join60(backupBase(), ts) };
9209
+ return { count: captures.length, backupPath: join63(backupBase(), ts) };
9041
9210
  } catch {
9042
9211
  return null;
9043
9212
  }
9044
9213
  }
9045
9214
  function planSharedReconcileBeforePull(repo, ts) {
9046
- const map = readMapForMirror(join60(repo, "path-map.json"));
9215
+ const map = readMapForMirror(join63(repo, "path-map.json"));
9047
9216
  const captures = [];
9048
9217
  const linkNames = process.platform === "win32" && map !== null ? allSharedLinks(map) : void 0;
9049
9218
  stageLocalSharedEdits(map, ts, { dryRun: true, onPreview: (e) => captures.push(e), linkNames });
@@ -9055,11 +9224,11 @@ function planSharedReconcileBeforePull(repo, ts) {
9055
9224
  };
9056
9225
  }
9057
9226
 
9058
- // src/commands.pull.collision.ts
9227
+ // src/commands/pull/collision.ts
9059
9228
  init_config();
9060
9229
  init_exit_codes();
9061
- import { existsSync as existsSync45, lstatSync as lstatSync21, readFileSync as readFileSync20, rmSync as rmSync19 } from "node:fs";
9062
- import { join as join61 } from "node:path";
9230
+ import { existsSync as existsSync46, lstatSync as lstatSync21, readFileSync as readFileSync20, rmSync as rmSync19 } from "node:fs";
9231
+ import { join as join64 } from "node:path";
9063
9232
  init_utils();
9064
9233
  var SHARED_PREFIX = /^shared\//;
9065
9234
  var EXTENSION = /(\.[^.]+)?$/;
@@ -9115,15 +9284,15 @@ function isContainedMirrorPath(rel) {
9115
9284
  }
9116
9285
  function matchesLocalOriginal(repo, rel) {
9117
9286
  try {
9118
- const local = join61(claudeHome(), rel.replace(SHARED_PREFIX, ""));
9119
- return readFileSync20(join61(repo, rel)).equals(readFileSync20(local));
9287
+ const local = join64(claudeHome(), rel.replace(SHARED_PREFIX, ""));
9288
+ return readFileSync20(join64(repo, rel)).equals(readFileSync20(local));
9120
9289
  } catch {
9121
9290
  return false;
9122
9291
  }
9123
9292
  }
9124
9293
  function removeMirroredCopies(repo, repoRelPaths) {
9125
9294
  for (const rel of repoRelPaths.filter(isContainedMirrorPath)) {
9126
- const abs = join61(repo, rel);
9295
+ const abs = join64(repo, rel);
9127
9296
  try {
9128
9297
  if (lstatSync21(abs, { throwIfNoEntry: false })?.isFile() !== true) continue;
9129
9298
  if (!matchesLocalOriginal(repo, rel)) continue;
@@ -9132,7 +9301,7 @@ function removeMirroredCopies(repo, repoRelPaths) {
9132
9301
  warn(`could not remove nomad's copy at ${abs}: ${err.message}`);
9133
9302
  }
9134
9303
  }
9135
- return repoRelPaths.every((rel) => !existsSync45(join61(repo, rel)));
9304
+ return repoRelPaths.every((rel) => !existsSync46(join64(repo, rel)));
9136
9305
  }
9137
9306
  function pullWithCollisionRunbook(repo, mirrored) {
9138
9307
  try {
@@ -9147,10 +9316,10 @@ function pullWithCollisionRunbook(repo, mirrored) {
9147
9316
  }
9148
9317
  }
9149
9318
 
9150
- // src/commands.pull.ts
9151
- init_commands_pull_wedge();
9319
+ // src/commands/pull/pull.ts
9320
+ init_wedge();
9152
9321
 
9153
- // src/commands.pull.recovery.ts
9322
+ // src/commands/pull/recovery.ts
9154
9323
  init_config();
9155
9324
  init_utils();
9156
9325
  init_utils_fs();
@@ -9244,9 +9413,9 @@ an ordinary pull.
9244
9413
  log(buildRecoverySummary(branchName, strandedLog, untracked));
9245
9414
  }
9246
9415
 
9247
- // src/commands.pull.recovery.unmerged.ts
9416
+ // src/commands/pull/recovery.unmerged.ts
9248
9417
  init_exit_codes();
9249
- init_commands_pull_wedge();
9418
+ init_wedge();
9250
9419
  init_utils();
9251
9420
  function recoverUnmergedIndex(repo) {
9252
9421
  const conflicted = new Set(
@@ -9269,7 +9438,7 @@ function recoverUnmergedIndex(repo) {
9269
9438
  }
9270
9439
  }
9271
9440
 
9272
- // src/commands.pull.ts
9441
+ // src/commands/pull/pull.ts
9273
9442
  init_exit_codes();
9274
9443
  init_utils();
9275
9444
  init_utils_fs();
@@ -9339,7 +9508,7 @@ function runPullCore(opts = {}) {
9339
9508
  try {
9340
9509
  return runPullWithBackupTs(ts, opts);
9341
9510
  } finally {
9342
- discardEmptyBackupDir(join62(backup, ts));
9511
+ discardEmptyBackupDir(join65(backup, ts));
9343
9512
  }
9344
9513
  }
9345
9514
  function runPullWithBackupTs(ts, opts) {
@@ -9350,7 +9519,7 @@ function runPullWithBackupTs(ts, opts) {
9350
9519
  const backup = backupBase();
9351
9520
  const recovered = handleWedge(repo, forceRemote);
9352
9521
  if (!dryRun) {
9353
- const backupRoot = join62(backup, ts);
9522
+ const backupRoot = join65(backup, ts);
9354
9523
  try {
9355
9524
  mkdirSync14(backupRoot, { recursive: true });
9356
9525
  } catch (err) {
@@ -9373,8 +9542,8 @@ function runPullWithBackupTs(ts, opts) {
9373
9542
  pullWithCollisionRunbook(repo, mirrored);
9374
9543
  });
9375
9544
  assertNoAutostashConflict(repo, "nomad pull");
9376
- const mapPath = join62(repo, "path-map.json");
9377
- const map = existsSync46(mapPath) ? readPathMap(mapPath) : { projects: {} };
9545
+ const mapPath = join65(repo, "path-map.json");
9546
+ const map = existsSync47(mapPath) ? readPathMap(mapPath) : { projects: {} };
9378
9547
  const divergedKeptLocal = divergenceCheckExtras(ts, dryRun ? prePostHeads : void 0);
9379
9548
  if (dryRun) {
9380
9549
  computePreview(ts, map, "pull", plansAgainst(sharedPlans, map));
@@ -9401,8 +9570,8 @@ function runPullWithBackupTs(ts, opts) {
9401
9570
  }
9402
9571
  function cmdPull(opts = {}) {
9403
9572
  const repo = repoHome();
9404
- if (!existsSync46(repo)) die(`repo not cloned at ${repo}`);
9405
- if (!existsSync46(join62(repo, "shared", "settings.base.json"))) {
9573
+ if (!existsSync47(repo)) die(`repo not cloned at ${repo}`);
9574
+ if (!existsSync47(join65(repo, "shared", "settings.base.json"))) {
9406
9575
  die("repo not initialized; run 'nomad init' to scaffold");
9407
9576
  }
9408
9577
  const handle = acquireLock("pull");
@@ -9423,15 +9592,15 @@ function cmdPull(opts = {}) {
9423
9592
  }
9424
9593
  }
9425
9594
 
9426
- // src/commands.push.ts
9595
+ // src/commands/push/push.ts
9427
9596
  init_config();
9428
- import { existsSync as existsSync50 } from "node:fs";
9429
- import { join as join67 } from "node:path";
9597
+ import { existsSync as existsSync51 } from "node:fs";
9598
+ import { join as join70 } from "node:path";
9430
9599
 
9431
- // src/commands.push.selection.ts
9600
+ // src/commands/push/selection.ts
9432
9601
  init_config();
9433
- import { existsSync as existsSync47, statSync as statSync13 } from "node:fs";
9434
- import { join as join63 } from "node:path";
9602
+ import { existsSync as existsSync48, statSync as statSync13 } from "node:fs";
9603
+ import { join as join66 } from "node:path";
9435
9604
  init_utils_json();
9436
9605
  function buildCurrentMap(map) {
9437
9606
  const current = {};
@@ -9440,8 +9609,8 @@ function buildCurrentMap(map) {
9440
9609
  for (const [, hostMap] of Object.entries(map.projects)) {
9441
9610
  const localPath = hostMap[HOST];
9442
9611
  if (!localPath) continue;
9443
- const localDir = join63(claude, "projects", encodePath(localPath));
9444
- if (!existsSync47(localDir)) continue;
9612
+ const localDir = join66(claude, "projects", encodePath(localPath));
9613
+ if (!existsSync48(localDir)) continue;
9445
9614
  for (const f of enumerateSourceFiles(localDir)) {
9446
9615
  const st = statSync13(f);
9447
9616
  current[f] = { size: st.size, mtime: st.mtimeMs };
@@ -9472,7 +9641,7 @@ function computePushSelection(map, old, scannerVersion, configHash, fullScan) {
9472
9641
  };
9473
9642
  }
9474
9643
  function loadSelectionForPush(mapPath, old, scannerVersion, configHash, fullScan) {
9475
- const map = existsSync47(mapPath) ? readPathMap(mapPath) : null;
9644
+ const map = existsSync48(mapPath) ? readPathMap(mapPath) : null;
9476
9645
  const { selection, newManifest } = computePushSelection(
9477
9646
  map,
9478
9647
  old,
@@ -9483,7 +9652,7 @@ function loadSelectionForPush(mapPath, old, scannerVersion, configHash, fullScan
9483
9652
  return { map, selection, newManifest };
9484
9653
  }
9485
9654
 
9486
- // src/commands.push.allowlist.ts
9655
+ // src/commands/push/allowlist.ts
9487
9656
  init_config();
9488
9657
  init_config_sharedDirs_guard();
9489
9658
  init_utils();
@@ -9558,21 +9727,21 @@ function enforceAllowList(statusPorcelain, map) {
9558
9727
  fail(`${p} is in NEVER_SYNC and must never be pushed`);
9559
9728
  }
9560
9729
  for (const p of violations) {
9561
- fail(`to sync ${p}, add to PUSH_ALLOWED in src/config.ts`);
9730
+ fail(`to sync ${p}, add to PUSH_ALLOWED in src/core/config.ts`);
9562
9731
  }
9563
9732
  throw new NomadFatal("push allow-list violations");
9564
9733
  }
9565
9734
 
9566
- // src/commands.push.settings.ts
9735
+ // src/commands/push/settings.ts
9567
9736
  init_config();
9568
- import { existsSync as existsSync48 } from "node:fs";
9569
- import { join as join64 } from "node:path";
9737
+ import { existsSync as existsSync49 } from "node:fs";
9738
+ import { join as join67 } from "node:path";
9570
9739
  init_utils();
9571
9740
  init_utils_fs();
9572
9741
  init_utils_json();
9573
9742
  function stripGsdHooksFromBase(repo, backup) {
9574
- const basePath = join64(repo, "shared", "settings.base.json");
9575
- if (!existsSync48(basePath)) return;
9743
+ const basePath = join67(repo, "shared", "settings.base.json");
9744
+ if (!existsSync49(basePath)) return;
9576
9745
  let base;
9577
9746
  try {
9578
9747
  base = readJson(basePath);
@@ -9586,14 +9755,14 @@ function stripGsdHooksFromBase(repo, backup) {
9586
9755
  writeJsonAtomic(basePath, stripped);
9587
9756
  }
9588
9757
  function reportSettingsAheadDrift(repo) {
9589
- const basePath = join64(repo, "shared", "settings.base.json");
9590
- if (!existsSync48(basePath)) return;
9591
- const settingsPath = join64(claudeHome(), "settings.json");
9592
- if (!existsSync48(settingsPath)) return;
9758
+ const basePath = join67(repo, "shared", "settings.base.json");
9759
+ if (!existsSync49(basePath)) return;
9760
+ const settingsPath = join67(claudeHome(), "settings.json");
9761
+ if (!existsSync49(settingsPath)) return;
9593
9762
  try {
9594
9763
  const base = readJson(basePath);
9595
- const hostPath = join64(repo, "hosts", `${HOST}.json`);
9596
- const overrides = existsSync48(hostPath) ? readJson(hostPath) : {};
9764
+ const hostPath = join67(repo, "hosts", `${HOST}.json`);
9765
+ const overrides = existsSync49(hostPath) ? readJson(hostPath) : {};
9597
9766
  const merged = deepMerge(base, overrides);
9598
9767
  const settings = readJson(settingsPath);
9599
9768
  const { ahead } = classifySettingsDrift(merged, settings);
@@ -9607,12 +9776,12 @@ function reportSettingsAheadDrift(repo) {
9607
9776
  }
9608
9777
  }
9609
9778
 
9610
- // src/commands.push.guards.ts
9611
- init_push_checks();
9779
+ // src/commands/push/guards.ts
9780
+ init_checks();
9612
9781
  init_utils();
9613
- import { join as join65, relative as relative10 } from "node:path";
9782
+ import { join as join68, relative as relative10 } from "node:path";
9614
9783
  function guardGitlinks(repo) {
9615
- const gitlinks = findGitlinks(join65(repo, "shared"));
9784
+ const gitlinks = findGitlinks(join68(repo, "shared"));
9616
9785
  if (gitlinks.length === 0) return;
9617
9786
  for (const p of gitlinks) {
9618
9787
  const rel = relative10(repo, p).replaceAll("\\", "/");
@@ -9639,10 +9808,10 @@ function guardResolutionModeConflicts(dryRun, redactAll, allowAll, allowRule) {
9639
9808
  }
9640
9809
  }
9641
9810
 
9642
- // src/commands.push.steps.ts
9811
+ // src/commands/push/steps.ts
9643
9812
  init_config();
9644
9813
 
9645
- // src/push-global-config.ts
9814
+ // src/commands/push/global-config.ts
9646
9815
  init_config();
9647
9816
  import { execFileSync as execFileSync23 } from "node:child_process";
9648
9817
  var STATUS_LABELS = {
@@ -9714,19 +9883,19 @@ function collectGlobalConfigChanges(repoHome2, hostname2, opts) {
9714
9883
  return changes;
9715
9884
  }
9716
9885
 
9717
- // src/commands.push.steps.ts
9718
- init_push_leak_verdict();
9886
+ // src/commands/push/steps.ts
9887
+ init_leak_verdict();
9719
9888
 
9720
- // src/push-preview.ts
9889
+ // src/commands/push/preview.ts
9721
9890
  init_color();
9722
9891
  init_config();
9723
9892
  init_config_sharedDirs_guard();
9724
9893
  import { randomBytes as randomBytes4 } from "node:crypto";
9725
- import { copyFileSync, existsSync as existsSync49, lstatSync as lstatSync22, mkdirSync as mkdirSync15, readdirSync as readdirSync20, rmSync as rmSync20 } from "node:fs";
9894
+ import { copyFileSync, existsSync as existsSync50, lstatSync as lstatSync22, mkdirSync as mkdirSync15, readdirSync as readdirSync20, rmSync as rmSync20 } from "node:fs";
9726
9895
  import { homedir as homedir7 } from "node:os";
9727
- import { join as join66, relative as relative11, sep as sep14 } from "node:path";
9728
- init_push_leak_verdict();
9729
- init_push_gitleaks();
9896
+ import { join as join69, relative as relative11, sep as sep14 } from "node:path";
9897
+ init_leak_verdict();
9898
+ init_gitleaks();
9730
9899
  init_utils_fs();
9731
9900
  init_utils_json();
9732
9901
  var NOTHING_TO_SCAN_ROW = `${dim(infoGlyph)} nothing to scan, no leaks`;
@@ -9736,7 +9905,7 @@ function stageSessionDir(localDir, dstDir, changed) {
9736
9905
  const matching = [...changed].filter((p) => p.startsWith(prefix));
9737
9906
  if (matching.length === 0) return false;
9738
9907
  for (const src of matching) {
9739
- copyFileAtomic(src, join66(dstDir, relative11(localDir, src)));
9908
+ copyFileAtomic(src, join69(dstDir, relative11(localDir, src)));
9740
9909
  }
9741
9910
  return true;
9742
9911
  }
@@ -9752,14 +9921,14 @@ function stageSessions(tmpRoot, map, changed) {
9752
9921
  if (!p || p === "TBD") continue;
9753
9922
  reverse.set(encodePath(p), logical);
9754
9923
  }
9755
- const localProjects = join66(claudeHome(), "projects");
9756
- if (!existsSync49(localProjects)) return 0;
9924
+ const localProjects = join69(claudeHome(), "projects");
9925
+ if (!existsSync50(localProjects)) return 0;
9757
9926
  let staged = 0;
9758
9927
  for (const dir of readdirSync20(localProjects)) {
9759
9928
  const logical = reverse.get(dir);
9760
9929
  if (!logical) continue;
9761
- const localDir = join66(localProjects, dir);
9762
- const dstDir = join66(tmpRoot, "shared", "projects", logical);
9930
+ const localDir = join69(localProjects, dir);
9931
+ const dstDir = join69(tmpRoot, "shared", "projects", logical);
9763
9932
  if (stageSessionDir(localDir, dstDir, changed)) staged++;
9764
9933
  }
9765
9934
  return staged;
@@ -9773,11 +9942,11 @@ function stageExtras(tmpRoot, map) {
9773
9942
  assertSafeLogical(logical);
9774
9943
  const localRoot = map.projects[logical]?.[HOST];
9775
9944
  if (!localRoot || localRoot === "TBD") continue;
9776
- for (const dirname15 of dirnames) {
9777
- if (!whitelist.includes(dirname15)) continue;
9778
- const src = join66(localRoot, dirname15);
9779
- if (!existsSync49(src)) continue;
9780
- const dst = join66(tmpRoot, "shared", "extras", logical, dirname15);
9945
+ for (const dirname16 of dirnames) {
9946
+ if (!whitelist.includes(dirname16)) continue;
9947
+ const src = join69(localRoot, dirname16);
9948
+ if (!existsSync50(src)) continue;
9949
+ const dst = join69(tmpRoot, "shared", "extras", logical, dirname16);
9781
9950
  copyExtras(src, dst);
9782
9951
  staged++;
9783
9952
  }
@@ -9785,19 +9954,19 @@ function stageExtras(tmpRoot, map) {
9785
9954
  return staged;
9786
9955
  }
9787
9956
  function stageSkills(tmpRoot) {
9788
- const localSkills = join66(claudeHome(), "skills");
9957
+ const localSkills = join69(claudeHome(), "skills");
9789
9958
  const stat = lstatSync22(localSkills, { throwIfNoEntry: false });
9790
9959
  if (stat === void 0 || stat.isSymbolicLink()) return 0;
9791
9960
  const names = readdirSync20(localSkills, { encoding: "utf8" }).filter((n) => !isSkillExcluded(n));
9792
9961
  if (names.length === 0) return 0;
9793
- copySkillsPush(localSkills, join66(tmpRoot, "shared", "skills"));
9962
+ copySkillsPush(localSkills, join69(tmpRoot, "shared", "skills"));
9794
9963
  return names.length;
9795
9964
  }
9796
9965
  function previewPushLeaks(map, opts = {}) {
9797
- const cacheDir = join66(homedir7(), ".cache", "claude-nomad");
9966
+ const cacheDir = join69(homedir7(), ".cache", "claude-nomad");
9798
9967
  mkdirSync15(cacheDir, { recursive: true });
9799
9968
  const stamp = `${nowTimestamp()}-${process.pid}-${randomBytes4(4).toString("hex")}`;
9800
- const tmpRoot = join66(cacheDir, `push-preview-tree-${stamp}`);
9969
+ const tmpRoot = join69(cacheDir, `push-preview-tree-${stamp}`);
9801
9970
  try {
9802
9971
  const sessionCount = stageSessions(tmpRoot, map, opts.selection?.changed);
9803
9972
  const extrasCount = stageExtras(tmpRoot, map);
@@ -9805,9 +9974,9 @@ function previewPushLeaks(map, opts = {}) {
9805
9974
  if (sessionCount + extrasCount + skillCount === 0) {
9806
9975
  return { leak: false, verdictRow: NOTHING_TO_SCAN_ROW, recovery: null, findings: [] };
9807
9976
  }
9808
- const ignoreFile = join66(repoHome(), ".gitleaksignore");
9809
- if (existsSync49(ignoreFile)) {
9810
- copyFileSync(ignoreFile, join66(tmpRoot, ".gitleaksignore"));
9977
+ const ignoreFile = join69(repoHome(), ".gitleaksignore");
9978
+ if (existsSync50(ignoreFile)) {
9979
+ copyFileSync(ignoreFile, join69(tmpRoot, ".gitleaksignore"));
9811
9980
  }
9812
9981
  let findings;
9813
9982
  try {
@@ -9824,7 +9993,7 @@ function previewPushLeaks(map, opts = {}) {
9824
9993
  }
9825
9994
  }
9826
9995
 
9827
- // src/commands.push.steps.ts
9996
+ // src/commands/push/steps.ts
9828
9997
  init_utils();
9829
9998
  async function commitAndPush(st, ts, map, resolution, repo, newManifest, render) {
9830
9999
  gitOrFatal(["add", "-A"], "git add", repo);
@@ -9876,8 +10045,8 @@ function runDryRunPreview(st, map, repo, selection) {
9876
10045
  if (verdict.recovery !== null) fail(verdict.recovery);
9877
10046
  }
9878
10047
 
9879
- // src/commands.push.ts
9880
- init_push_checks();
10048
+ // src/commands/push/push.ts
10049
+ init_checks();
9881
10050
  init_utils();
9882
10051
  init_utils_fs();
9883
10052
  function aheadOfUpstream(repo) {
@@ -9935,7 +10104,7 @@ async function runPushCore(opts = {}) {
9935
10104
  const scannerVersion = probeGitleaks();
9936
10105
  const configHash = computeConfigHash();
9937
10106
  const old = readManifest(manifestPath());
9938
- const mapPath = join67(repo, "path-map.json");
10107
+ const mapPath = join70(repo, "path-map.json");
9939
10108
  const { map, selection, newManifest } = loadSelectionForPush(
9940
10109
  mapPath,
9941
10110
  old,
@@ -9988,7 +10157,7 @@ async function cmdPush(opts = {}) {
9988
10157
  opts.allowRule
9989
10158
  );
9990
10159
  const repo = repoHome();
9991
- if (!existsSync50(repo)) die(`repo not cloned at ${repo}`);
10160
+ if (!existsSync51(repo)) die(`repo not cloned at ${repo}`);
9992
10161
  const handle = acquireLock("push");
9993
10162
  if (handle === null) process.exit(0);
9994
10163
  try {
@@ -10005,9 +10174,9 @@ async function cmdPush(opts = {}) {
10005
10174
  }
10006
10175
  }
10007
10176
 
10008
- // src/commands.sync.ts
10009
- import { existsSync as existsSync51 } from "node:fs";
10010
- import { join as join68 } from "node:path";
10177
+ // src/commands/sync.ts
10178
+ import { existsSync as existsSync52 } from "node:fs";
10179
+ import { join as join71 } from "node:path";
10011
10180
  init_config();
10012
10181
  init_color();
10013
10182
  init_utils();
@@ -10148,8 +10317,8 @@ async function cmdSync(opts = {}) {
10148
10317
  const dryRun = opts.dryRun === true;
10149
10318
  const verbose = opts.verbose === true;
10150
10319
  const repo = repoHome();
10151
- if (!existsSync51(repo)) die(`repo not cloned at ${repo}`);
10152
- if (!existsSync51(join68(repo, "shared", "settings.base.json"))) {
10320
+ if (!existsSync52(repo)) die(`repo not cloned at ${repo}`);
10321
+ if (!existsSync52(join71(repo, "shared", "settings.base.json"))) {
10153
10322
  die("repo not initialized; run 'nomad init' to scaffold");
10154
10323
  }
10155
10324
  const handle = acquireLock("sync");
@@ -10172,9 +10341,11 @@ async function cmdSync(opts = {}) {
10172
10341
  }
10173
10342
  }
10174
10343
 
10175
- // src/commands.update.ts
10176
- import { execFileSync as execFileSync24 } from "node:child_process";
10344
+ // src/commands/update.ts
10177
10345
  init_utils();
10346
+ import { execFileSync as execFileSync24 } from "node:child_process";
10347
+ var RELEASE_NOTES_TAG_URL = "https://github.com/funkadelic/claude-nomad/releases/tag";
10348
+ var SEMVER = /^\d+\.\d+\.\d+(?:[-+][\w.-]+)?$/;
10178
10349
  function readInstalledVersion(run = execFileSync24) {
10179
10350
  const isWin = process.platform === "win32";
10180
10351
  try {
@@ -10186,6 +10357,10 @@ function readInstalledVersion(run = execFileSync24) {
10186
10357
  return null;
10187
10358
  }
10188
10359
  }
10360
+ function readOwnVersion(run) {
10361
+ const version = readInstalledVersion(run);
10362
+ return version !== null && SEMVER.test(version) ? version : null;
10363
+ }
10189
10364
  function cmdUpdate(currentVersion, run = execFileSync24) {
10190
10365
  console.log(`Updating claude-nomad v${currentVersion}...`);
10191
10366
  const isWin = process.platform === "win32";
@@ -10209,26 +10384,27 @@ function cmdUpdate(currentVersion, run = execFileSync24) {
10209
10384
  ${detail}` : "";
10210
10385
  throw new NomadFatal(`npm update -g claude-nomad failed: ${e.message}${suffix}`);
10211
10386
  }
10212
- const version = readInstalledVersion(run);
10387
+ const version = readOwnVersion(run);
10213
10388
  if (!version) {
10214
10389
  console.log('Update complete. Run "nomad --version" to confirm the new version.');
10215
- } else if (version === currentVersion) {
10216
- console.log(`claude-nomad is already at the latest version (v${version}).`);
10217
- } else {
10218
- console.log(`claude-nomad is now at v${version}`);
10390
+ return;
10219
10391
  }
10392
+ console.log(
10393
+ version === currentVersion ? `claude-nomad is already at the latest version (v${version}).` : `claude-nomad is now at v${version}`
10394
+ );
10395
+ console.log(`Release notes: ${RELEASE_NOTES_TAG_URL}/v${version}`);
10220
10396
  }
10221
10397
 
10222
10398
  // src/nomad.ts
10223
10399
  init_config();
10224
10400
 
10225
- // src/crash-report.write.ts
10401
+ // src/core/crash-report.write.ts
10226
10402
  init_config();
10227
10403
  import { randomBytes as randomBytes5 } from "node:crypto";
10228
10404
  import { mkdirSync as mkdirSync16, readdirSync as readdirSync21, statSync as statSync14, unlinkSync as unlinkSync2, writeFileSync as writeFileSync11 } from "node:fs";
10229
- import { join as join70 } from "node:path";
10405
+ import { join as join73 } from "node:path";
10230
10406
 
10231
- // src/crash-report.ts
10407
+ // src/core/crash-report.ts
10232
10408
  var CRASH_MAX_STACK_LINES = 50;
10233
10409
  var CRASH_MAX_ARGV = 32;
10234
10410
  var CRASH_MAX_ARGV_TOKEN_LENGTH = 200;
@@ -10308,18 +10484,18 @@ function buildCrashReport(input) {
10308
10484
  return truncateToBytes(scrubbed, CRASH_MAX_REPORT_BYTES);
10309
10485
  }
10310
10486
 
10311
- // src/crash-report.redact.ts
10487
+ // src/core/crash-report.redact.ts
10312
10488
  import { mkdtempSync as mkdtempSync3, rmSync as rmSync21, writeFileSync as writeFileSync10 } from "node:fs";
10313
10489
  import { tmpdir as tmpdir2 } from "node:os";
10314
- import { join as join69 } from "node:path";
10315
- init_push_gitleaks_scan();
10490
+ import { join as join72 } from "node:path";
10491
+ init_gitleaks_scan();
10316
10492
  var CRASH_SCAN_TIMEOUT_MS = 3e3;
10317
10493
  var SCAN_UNAVAILABLE_ADVISORY = "\n\n[gitleaks value-based scan unavailable; only structural redaction applied. Review before sharing this file publicly.]\n";
10318
10494
  function redactWithGitleaks(text, scan = scanFile) {
10319
10495
  let dir;
10320
10496
  try {
10321
- dir = mkdtempSync3(join69(tmpdir2(), "nomad-crash-scan-"));
10322
- const tmp = join69(dir, "crash.txt");
10497
+ dir = mkdtempSync3(join72(tmpdir2(), "nomad-crash-scan-"));
10498
+ const tmp = join72(dir, "crash.txt");
10323
10499
  writeFileSync10(tmp, text, { mode: 384 });
10324
10500
  const findings = scan(tmp, false, CRASH_SCAN_TIMEOUT_MS);
10325
10501
  if (findings === null) return text + SCAN_UNAVAILABLE_ADVISORY;
@@ -10336,7 +10512,7 @@ function redactWithGitleaks(text, scan = scanFile) {
10336
10512
  }
10337
10513
  }
10338
10514
 
10339
- // src/crash-report.write.ts
10515
+ // src/core/crash-report.write.ts
10340
10516
  init_utils_fs();
10341
10517
  init_utils();
10342
10518
  var CRASH_RETENTION_KEEP = 20;
@@ -10344,7 +10520,7 @@ function listCrashFiles(dir = crashDir()) {
10344
10520
  try {
10345
10521
  return readdirSync21(dir).flatMap((name) => {
10346
10522
  try {
10347
- return [{ name, mtimeMs: statSync14(join70(dir, name)).mtimeMs }];
10523
+ return [{ name, mtimeMs: statSync14(join73(dir, name)).mtimeMs }];
10348
10524
  } catch {
10349
10525
  return [];
10350
10526
  }
@@ -10358,7 +10534,7 @@ function pruneCrashDir(dir, keep = CRASH_RETENTION_KEEP) {
10358
10534
  const targets = prunableByCount(files, keep);
10359
10535
  for (const name of targets) {
10360
10536
  try {
10361
- unlinkSync2(join70(dir, name));
10537
+ unlinkSync2(join73(dir, name));
10362
10538
  } catch {
10363
10539
  }
10364
10540
  }
@@ -10366,7 +10542,7 @@ function pruneCrashDir(dir, keep = CRASH_RETENTION_KEEP) {
10366
10542
  function writeCrashReport(text, dir = crashDir()) {
10367
10543
  mkdirSync16(dir, { recursive: true, mode: 448 });
10368
10544
  const stamp = `${nowTimestamp()}-${process.pid}-${randomBytes5(4).toString("hex")}`;
10369
- const path = join70(dir, `crash-${stamp}.txt`);
10545
+ const path = join73(dir, `crash-${stamp}.txt`);
10370
10546
  writeFileSync11(path, text, { mode: 384 });
10371
10547
  pruneCrashDir(dir);
10372
10548
  return path;
@@ -10396,20 +10572,20 @@ function handleCrash(err, argv, opts) {
10396
10572
  }
10397
10573
  }
10398
10574
 
10399
- // src/diff.ts
10575
+ // src/commands/diff.ts
10400
10576
  init_config();
10401
- import { existsSync as existsSync52 } from "node:fs";
10402
- import { join as join71 } from "node:path";
10577
+ import { existsSync as existsSync53 } from "node:fs";
10578
+ import { join as join74 } from "node:path";
10403
10579
  init_utils();
10404
10580
  init_utils_fs();
10405
10581
  init_utils_json();
10406
10582
  function cmdDiff() {
10407
10583
  try {
10408
10584
  const repo = repoHome();
10409
- if (!existsSync52(repo)) die(`repo not cloned at ${repo}`);
10585
+ if (!existsSync53(repo)) die(`repo not cloned at ${repo}`);
10410
10586
  const ts = freshBackupTs(backupBase());
10411
- const mapPath = join71(repo, "path-map.json");
10412
- const map = existsSync52(mapPath) ? readPathMap(mapPath) : { projects: {} };
10587
+ const mapPath = join74(repo, "path-map.json");
10588
+ const map = existsSync53(mapPath) ? readPathMap(mapPath) : { projects: {} };
10413
10589
  divergenceCheckExtras(ts);
10414
10590
  computePreview(ts, map, "diff");
10415
10591
  } catch (err) {
@@ -10422,12 +10598,12 @@ function cmdDiff() {
10422
10598
  }
10423
10599
  }
10424
10600
 
10425
- // src/init.ts
10601
+ // src/commands/init/init.ts
10426
10602
  init_config();
10427
- import { existsSync as existsSync54, mkdirSync as mkdirSync17, writeFileSync as writeFileSync12 } from "node:fs";
10428
- import { join as join73 } from "node:path";
10603
+ import { existsSync as existsSync55, mkdirSync as mkdirSync17, writeFileSync as writeFileSync12 } from "node:fs";
10604
+ import { join as join76 } from "node:path";
10429
10605
 
10430
- // src/init.gh-onboard.ts
10606
+ // src/commands/init/gh-onboard.ts
10431
10607
  init_config();
10432
10608
  import { execFileSync as execFileSync25 } from "node:child_process";
10433
10609
  init_utils();
@@ -10502,44 +10678,44 @@ function ensureOriginRepo(repoName, run = execFileSync25) {
10502
10678
  log(`created private repo ${owner}/${repoName} and wired origin`);
10503
10679
  }
10504
10680
 
10505
- // src/init.snapshot.ts
10681
+ // src/commands/init/snapshot.ts
10506
10682
  init_config();
10507
10683
  init_utils();
10508
10684
  init_utils_fs();
10509
10685
  init_utils_json();
10510
- import { copyFileSync as copyFileSync2, cpSync as cpSync9, existsSync as existsSync53, rmSync as rmSync22, statSync as statSync15 } from "node:fs";
10511
- import { join as join72 } from "node:path";
10686
+ import { copyFileSync as copyFileSync2, cpSync as cpSync9, existsSync as existsSync54, rmSync as rmSync22, statSync as statSync15 } from "node:fs";
10687
+ import { join as join75 } from "node:path";
10512
10688
  function snapshotIntoShared(map) {
10513
10689
  const repo = repoHome();
10514
10690
  const claude = claudeHome();
10515
10691
  for (const name of allSharedLinks(map)) {
10516
- const src = join72(claude, name);
10517
- if (!existsSync53(src)) continue;
10518
- const dst = join72(repo, "shared", name);
10692
+ const src = join75(claude, name);
10693
+ if (!existsSync54(src)) continue;
10694
+ const dst = join75(repo, "shared", name);
10519
10695
  if (statSync15(src).isDirectory()) {
10520
- const gk = join72(dst, ".gitkeep");
10521
- if (existsSync53(gk)) rmSync22(gk);
10696
+ const gk = join75(dst, ".gitkeep");
10697
+ if (existsSync54(gk)) rmSync22(gk);
10522
10698
  cpSync9(src, dst, { recursive: true, force: false, errorOnExist: true });
10523
10699
  } else {
10524
10700
  copyFileSync2(src, dst);
10525
10701
  }
10526
10702
  log(`snapshotted shared/${name} from ${src}`);
10527
10703
  }
10528
- const userSettings = join72(claude, "settings.json");
10529
- if (existsSync53(userSettings)) {
10704
+ const userSettings = join75(claude, "settings.json");
10705
+ if (existsSync54(userSettings)) {
10530
10706
  let parsed;
10531
10707
  try {
10532
10708
  parsed = readJson(userSettings);
10533
10709
  } catch (err) {
10534
10710
  return die(`malformed ${userSettings}: ${err.message}`);
10535
10711
  }
10536
- const hostFile = join72(repo, "hosts", `${HOST}.json`);
10712
+ const hostFile = join75(repo, "hosts", `${HOST}.json`);
10537
10713
  writeJsonAtomic(hostFile, parsed);
10538
10714
  log(`snapshotted hosts/${HOST}.json from ${userSettings}`);
10539
10715
  }
10540
10716
  }
10541
10717
 
10542
- // src/init.ts
10718
+ // src/commands/init/init.ts
10543
10719
  init_utils();
10544
10720
  init_utils_fs();
10545
10721
  var SHARED_CLAUDE_MD = "<!-- claude-nomad shared CLAUDE.md; symlinked into ~/.claude/CLAUDE.md by nomad pull -->\n";
@@ -10547,14 +10723,14 @@ var GITATTRIBUTES = "# nomad: sync content is byte-managed, disable all line-end
10547
10723
  var SHARED_KEEP_DIRS = ["agents", "skills", "commands", "rules", "hooks"];
10548
10724
  function preflightConflict(repoHome2) {
10549
10725
  const candidates = [
10550
- join73(repoHome2, "shared", "settings.base.json"),
10551
- join73(repoHome2, "shared", "CLAUDE.md"),
10552
- join73(repoHome2, "path-map.json"),
10553
- join73(repoHome2, "hosts"),
10554
- join73(repoHome2, "shared")
10726
+ join76(repoHome2, "shared", "settings.base.json"),
10727
+ join76(repoHome2, "shared", "CLAUDE.md"),
10728
+ join76(repoHome2, "path-map.json"),
10729
+ join76(repoHome2, "hosts"),
10730
+ join76(repoHome2, "shared")
10555
10731
  ];
10556
10732
  for (const c of candidates) {
10557
- if (existsSync54(c)) return c;
10733
+ if (existsSync55(c)) return c;
10558
10734
  }
10559
10735
  return null;
10560
10736
  }
@@ -10572,27 +10748,27 @@ function cmdInit(opts = {}) {
10572
10748
  die(`already initialized; refusing to clobber ${conflict}`);
10573
10749
  }
10574
10750
  ensureOriginRepo(opts.repoName ?? DEFAULT_REPO_NAME, opts.run);
10575
- mkdirSync17(join73(repo, "shared"), { recursive: true });
10576
- mkdirSync17(join73(repo, "hosts"), { recursive: true });
10751
+ mkdirSync17(join76(repo, "shared"), { recursive: true });
10752
+ mkdirSync17(join76(repo, "hosts"), { recursive: true });
10577
10753
  for (const name of SHARED_KEEP_DIRS) {
10578
- mkdirSync17(join73(repo, "shared", name), { recursive: true });
10754
+ mkdirSync17(join76(repo, "shared", name), { recursive: true });
10579
10755
  }
10580
- const userClaudeMd = join73(claude, "CLAUDE.md");
10581
- if (!snapshot || !existsSync54(userClaudeMd)) {
10582
- writeFileSync12(join73(repo, "shared", "CLAUDE.md"), SHARED_CLAUDE_MD);
10756
+ const userClaudeMd = join76(claude, "CLAUDE.md");
10757
+ if (!snapshot || !existsSync55(userClaudeMd)) {
10758
+ writeFileSync12(join76(repo, "shared", "CLAUDE.md"), SHARED_CLAUDE_MD);
10583
10759
  item("created shared/CLAUDE.md");
10584
10760
  }
10585
10761
  for (const name of SHARED_KEEP_DIRS) {
10586
- writeFileSync12(join73(repo, "shared", name, ".gitkeep"), "");
10762
+ writeFileSync12(join76(repo, "shared", name, ".gitkeep"), "");
10587
10763
  item(`created shared/${name}/.gitkeep`);
10588
10764
  }
10589
- writeFileSync12(join73(repo, "hosts", ".gitkeep"), "");
10765
+ writeFileSync12(join76(repo, "hosts", ".gitkeep"), "");
10590
10766
  item("created hosts/.gitkeep");
10591
- writeJsonAtomic(join73(repo, "shared", "settings.base.json"), {});
10767
+ writeJsonAtomic(join76(repo, "shared", "settings.base.json"), {});
10592
10768
  item("created shared/settings.base.json");
10593
- writeJsonAtomic(join73(repo, "path-map.json"), { projects: {} });
10769
+ writeJsonAtomic(join76(repo, "path-map.json"), { projects: {} });
10594
10770
  item("created path-map.json");
10595
- writeFileSync12(join73(repo, ".gitattributes"), GITATTRIBUTES);
10771
+ writeFileSync12(join76(repo, ".gitattributes"), GITATTRIBUTES);
10596
10772
  item("created .gitattributes");
10597
10773
  if (snapshot) {
10598
10774
  snapshotIntoShared({ projects: {} });
@@ -10655,14 +10831,14 @@ function maybeDisableRepoActions(repoHome2, run) {
10655
10831
  }
10656
10832
  }
10657
10833
 
10658
- // src/init.prompt.ts
10834
+ // src/commands/init/prompt.ts
10659
10835
  init_config();
10660
10836
  init_utils();
10661
- import { existsSync as existsSync55, readdirSync as readdirSync22, statSync as statSync16 } from "node:fs";
10662
- import { join as join74 } from "node:path";
10837
+ import { existsSync as existsSync56, readdirSync as readdirSync22, statSync as statSync16 } from "node:fs";
10838
+ import { join as join77 } from "node:path";
10663
10839
  import { createInterface as createInterface3 } from "node:readline/promises";
10664
10840
  function nonEmptyExists(path) {
10665
- if (!existsSync55(path)) return false;
10841
+ if (!existsSync56(path)) return false;
10666
10842
  try {
10667
10843
  if (statSync16(path).isDirectory()) return readdirSync22(path).length > 0;
10668
10844
  return true;
@@ -10671,8 +10847,8 @@ function nonEmptyExists(path) {
10671
10847
  }
10672
10848
  }
10673
10849
  function hasExistingClaudeConfig(claudeHome2) {
10674
- if (existsSync55(join74(claudeHome2, "settings.json"))) return true;
10675
- return SHARED_LINKS.some((name) => nonEmptyExists(join74(claudeHome2, name)));
10850
+ if (existsSync56(join77(claudeHome2, "settings.json"))) return true;
10851
+ return SHARED_LINKS.some((name) => nonEmptyExists(join77(claudeHome2, name)));
10676
10852
  }
10677
10853
  async function confirmSnapshotDefault(claudeHome2) {
10678
10854
  if (process.stdin.isTTY !== true || process.stdout.isTTY !== true) {
@@ -10696,7 +10872,7 @@ async function resolveSnapshotChoice(flagSnapshot, claudeHome2, confirm = confir
10696
10872
  return confirm(claudeHome2);
10697
10873
  }
10698
10874
 
10699
- // src/nomad.dispatch.helpers.ts
10875
+ // src/cli/dispatch.helpers.ts
10700
10876
  var REJECT = { ok: false, advance: 0 };
10701
10877
  function applyBool(seen, set) {
10702
10878
  if (seen) return REJECT;
@@ -10709,7 +10885,7 @@ function extractFlagValue(argv, i) {
10709
10885
  return val;
10710
10886
  }
10711
10887
 
10712
- // src/nomad.dispatch.clean.ts
10888
+ // src/cli/dispatch.clean.ts
10713
10889
  function applyOlderThan(argv, i, st) {
10714
10890
  if (st.olderThan !== void 0) return REJECT;
10715
10891
  const val = extractFlagValue(argv, i);
@@ -10756,7 +10932,7 @@ function parseCleanArgs(argv) {
10756
10932
  return { dryRun: st.dryRun, olderThan: st.olderThan, keep: st.keep };
10757
10933
  }
10758
10934
 
10759
- // src/nomad.dispatch.capture-settings.ts
10935
+ // src/cli/dispatch.capture-settings.ts
10760
10936
  function parseCaptureSettingsArgs(argv) {
10761
10937
  let host = false;
10762
10938
  let dryRun = false;
@@ -10781,7 +10957,7 @@ function parseCaptureSettingsArgs(argv) {
10781
10957
  return { host, dryRun, yes };
10782
10958
  }
10783
10959
 
10784
- // src/nomad.dispatch.eject.ts
10960
+ // src/cli/dispatch.eject.ts
10785
10961
  function parseEjectArgs(argv) {
10786
10962
  let dryRun = false;
10787
10963
  let i = 3;
@@ -10798,7 +10974,7 @@ function parseEjectArgs(argv) {
10798
10974
  return { dryRun };
10799
10975
  }
10800
10976
 
10801
- // src/nomad.dispatch.ts
10977
+ // src/cli/dispatch.ts
10802
10978
  function applyInitToken(argv, i, st) {
10803
10979
  const token = argv[i];
10804
10980
  if (token === "--snapshot") {
@@ -10871,7 +11047,7 @@ function parseRedactArgs(argv) {
10871
11047
  return { id, rule, dryRun };
10872
11048
  }
10873
11049
 
10874
- // src/nomad.dispatch.allow.ts
11050
+ // src/cli/dispatch.allow.ts
10875
11051
  function parseAllowArgs(argv) {
10876
11052
  const positionals = argv.slice(3);
10877
11053
  if (positionals.length === 0) return null;
@@ -10881,7 +11057,7 @@ function parseAllowArgs(argv) {
10881
11057
  return positionals;
10882
11058
  }
10883
11059
 
10884
- // src/nomad.dispatch.pull.ts
11060
+ // src/cli/dispatch.pull.ts
10885
11061
  function parsePullArgs(argv) {
10886
11062
  let dryRun = false;
10887
11063
  let forceRemote = false;
@@ -10903,7 +11079,7 @@ function parsePullArgs(argv) {
10903
11079
  return { dryRun, forceRemote };
10904
11080
  }
10905
11081
 
10906
- // src/nomad.dispatch.push.ts
11082
+ // src/cli/dispatch.push.ts
10907
11083
  var RULE_ID_RE = /^\w[\w-]*$/;
10908
11084
  function applyAllow(argv, i, st) {
10909
11085
  if (st.allowRule !== void 0) return REJECT;
@@ -10956,7 +11132,7 @@ function parsePushArgs(argv) {
10956
11132
  };
10957
11133
  }
10958
11134
 
10959
- // src/nomad.dispatch.sync.ts
11135
+ // src/cli/dispatch.sync.ts
10960
11136
  function parseSyncArgs(argv) {
10961
11137
  let dryRun = false;
10962
11138
  let verbose = false;
@@ -10979,7 +11155,7 @@ function parseSyncArgs(argv) {
10979
11155
  // package.json
10980
11156
  var package_default = {
10981
11157
  name: "claude-nomad",
10982
- version: "0.68.0",
11158
+ version: "0.69.0",
10983
11159
  type: "module",
10984
11160
  description: "Sync Claude Code config (~/.claude/) across machines via a private Git repo, with path remapping and per-host settings overrides.",
10985
11161
  keywords: [
@@ -11046,7 +11222,8 @@ var package_default = {
11046
11222
  overrides: {
11047
11223
  "@conventional-changelog/git-client": {
11048
11224
  "conventional-commits-parser": "^7.0.0"
11049
- }
11225
+ },
11226
+ "smol-toml": "^1.7.1"
11050
11227
  },
11051
11228
  devDependencies: {
11052
11229
  "@commitlint/cli": "^21.0.1",
@@ -11055,7 +11232,7 @@ var package_default = {
11055
11232
  "@stryker-mutator/core": "10.0.0",
11056
11233
  "@stryker-mutator/vitest-runner": "10.0.0",
11057
11234
  "@types/node": "^22.0.0",
11058
- "@vitest/coverage-v8": "^4.1.6",
11235
+ "@vitest/coverage-v8": "^5.0.0",
11059
11236
  "conventional-changelog-conventionalcommits": "^10.2.1",
11060
11237
  diff: "^9.0.0",
11061
11238
  esbuild: "^0.28.0",
@@ -11071,11 +11248,11 @@ var package_default = {
11071
11248
  prettier: "^3.8.3",
11072
11249
  typescript: "^6.0.3",
11073
11250
  "typescript-eslint": "^8.59.4",
11074
- vitest: "^4.1.6"
11251
+ vitest: "^5.0.0"
11075
11252
  }
11076
11253
  };
11077
11254
 
11078
- // src/nomad.help.ts
11255
+ // src/cli/help.ts
11079
11256
  var DESC_COL = 26;
11080
11257
  var row = (label, desc) => label.padEnd(DESC_COL) + desc;
11081
11258
  var cont = (text) => " ".repeat(DESC_COL) + text;
@@ -11223,19 +11400,19 @@ var DEFAULT_HELP = [
11223
11400
  "every pull)."
11224
11401
  ].join("\n");
11225
11402
 
11226
- // src/resume.ts
11403
+ // src/sync/resume.ts
11227
11404
  init_config();
11228
11405
  init_utils();
11229
11406
  init_utils_json();
11230
- import { existsSync as existsSync56, readFileSync as readFileSync21, readdirSync as readdirSync23 } from "node:fs";
11231
- import { join as join75 } from "node:path";
11407
+ import { existsSync as existsSync57, readFileSync as readFileSync21, readdirSync as readdirSync23 } from "node:fs";
11408
+ import { join as join78 } from "node:path";
11232
11409
  function resumeCmd(sessionId) {
11233
11410
  if (!/^[A-Za-z0-9_-]+$/.test(sessionId) || sessionId.length > 128) {
11234
11411
  fail(`invalid session id: ${sessionId}`);
11235
11412
  process.exit(1);
11236
11413
  }
11237
- const projectsRoot = join75(claudeHome(), "projects");
11238
- if (!existsSync56(projectsRoot)) {
11414
+ const projectsRoot = join78(claudeHome(), "projects");
11415
+ if (!existsSync57(projectsRoot)) {
11239
11416
  fail(`${projectsRoot} does not exist`);
11240
11417
  process.exit(1);
11241
11418
  }
@@ -11249,8 +11426,8 @@ function resumeCmd(sessionId) {
11249
11426
  fail(`no cwd field found in ${jsonlPath}`);
11250
11427
  process.exit(1);
11251
11428
  }
11252
- const mapPath = join75(repoHome(), "path-map.json");
11253
- if (!existsSync56(mapPath)) {
11429
+ const mapPath = join78(repoHome(), "path-map.json");
11430
+ if (!existsSync57(mapPath)) {
11254
11431
  fail("path-map.json missing");
11255
11432
  process.exit(1);
11256
11433
  }
@@ -11273,8 +11450,8 @@ function resumeCmd(sessionId) {
11273
11450
  }
11274
11451
  function findTranscriptPath(projectsRoot, sessionId) {
11275
11452
  for (const dir of readdirSync23(projectsRoot)) {
11276
- const candidate = join75(projectsRoot, dir, `${sessionId}.jsonl`);
11277
- if (existsSync56(candidate)) return candidate;
11453
+ const candidate = join78(projectsRoot, dir, `${sessionId}.jsonl`);
11454
+ if (existsSync57(candidate)) return candidate;
11278
11455
  }
11279
11456
  return null;
11280
11457
  }
@@ -11307,7 +11484,7 @@ function shQuote(s) {
11307
11484
  return `'${escaped}'`;
11308
11485
  }
11309
11486
 
11310
- // src/user-abort.ts
11487
+ // src/core/user-abort.ts
11311
11488
  var ABORT_NAMES = /* @__PURE__ */ new Set(["AbortError", "ExitPromptError"]);
11312
11489
  var ABORT_CODE = "ABORT_ERR";
11313
11490
  function isUserAbort(err) {