@indigoai-us/hq-cloud 6.1.0 → 6.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. package/dist/bin/sync-runner.d.ts.map +1 -1
  2. package/dist/bin/sync-runner.js +18 -0
  3. package/dist/bin/sync-runner.js.map +1 -1
  4. package/dist/cli/index.d.ts +2 -2
  5. package/dist/cli/index.d.ts.map +1 -1
  6. package/dist/cli/index.js +2 -2
  7. package/dist/cli/index.js.map +1 -1
  8. package/dist/cli/reindex.d.ts +4 -11
  9. package/dist/cli/reindex.d.ts.map +1 -1
  10. package/dist/cli/reindex.js +336 -30
  11. package/dist/cli/reindex.js.map +1 -1
  12. package/dist/cli/reindex.test.d.ts +3 -3
  13. package/dist/cli/reindex.test.js +36 -11
  14. package/dist/cli/reindex.test.js.map +1 -1
  15. package/dist/cli/rescue-core.d.ts +36 -0
  16. package/dist/cli/rescue-core.d.ts.map +1 -0
  17. package/dist/cli/rescue-core.js +1589 -0
  18. package/dist/cli/rescue-core.js.map +1 -0
  19. package/dist/cli/rescue-drift-reconcile.test.js +33 -10
  20. package/dist/cli/rescue-drift-reconcile.test.js.map +1 -1
  21. package/dist/cli/rescue-journal-reconcile.test.d.ts +2 -0
  22. package/dist/cli/rescue-journal-reconcile.test.d.ts.map +1 -0
  23. package/dist/cli/rescue-journal-reconcile.test.js +135 -0
  24. package/dist/cli/rescue-journal-reconcile.test.js.map +1 -0
  25. package/dist/cli/rescue-mtime-preserve.test.js +36 -12
  26. package/dist/cli/rescue-mtime-preserve.test.js.map +1 -1
  27. package/dist/cli/rescue.d.ts +4 -10
  28. package/dist/cli/rescue.d.ts.map +1 -1
  29. package/dist/cli/rescue.js +14 -37
  30. package/dist/cli/rescue.js.map +1 -1
  31. package/dist/cli/rescue.reindex.test.js +9 -8
  32. package/dist/cli/rescue.reindex.test.js.map +1 -1
  33. package/dist/cli/rescue.test.js +1 -10
  34. package/dist/cli/rescue.test.js.map +1 -1
  35. package/dist/index.d.ts +2 -2
  36. package/dist/index.d.ts.map +1 -1
  37. package/dist/index.js +2 -2
  38. package/dist/index.js.map +1 -1
  39. package/dist/lib/conflict-index.d.ts +40 -0
  40. package/dist/lib/conflict-index.d.ts.map +1 -1
  41. package/dist/lib/conflict-index.js +121 -0
  42. package/dist/lib/conflict-index.js.map +1 -1
  43. package/dist/lib/conflict.test.js +145 -1
  44. package/dist/lib/conflict.test.js.map +1 -1
  45. package/package.json +1 -1
  46. package/src/bin/sync-runner.ts +18 -0
  47. package/src/cli/index.ts +2 -2
  48. package/src/cli/reindex.test.ts +45 -12
  49. package/src/cli/reindex.ts +345 -36
  50. package/src/cli/rescue-core.ts +1719 -0
  51. package/src/cli/rescue-drift-reconcile.test.ts +33 -12
  52. package/src/cli/rescue-journal-reconcile.test.ts +156 -0
  53. package/src/cli/rescue-mtime-preserve.test.ts +36 -15
  54. package/src/cli/rescue.reindex.test.ts +9 -8
  55. package/src/cli/rescue.test.ts +1 -11
  56. package/src/cli/rescue.ts +15 -40
  57. package/src/index.ts +2 -2
  58. package/src/lib/conflict-index.ts +146 -0
  59. package/src/lib/conflict.test.ts +171 -0
  60. package/scripts/reindex.sh +0 -318
  61. package/scripts/replace-rescue.sh +0 -1522
@@ -1 +1 @@
1
- {"version":3,"file":"conflict.test.js","sourceRoot":"","sources":["../../src/lib/conflict.test.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"conflict.test.js","sourceRoot":"","sources":["../../src/lib/conflict.test.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@indigoai-us/hq-cloud",
3
- "version": "6.1.0",
3
+ "version": "6.2.1",
4
4
  "description": "HQ by Indigo cloud sync engine — bidirectional S3 sync for mobile access",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -99,6 +99,7 @@ import {
99
99
  import { collectAndSendTelemetry } from "../telemetry.js";
100
100
  import { collectAndSendSkillTelemetry } from "../skill-telemetry.js";
101
101
  import { reindexAfterSync } from "../qmd-reindex.js";
102
+ import { pruneConflictIndex } from "../lib/conflict-index.js";
102
103
  import { describeError } from "../lib/describe-error.js";
103
104
  import { getOrCreateMachineId } from "../lib/machine-id.js";
104
105
  import {
@@ -1639,6 +1640,23 @@ export async function runRunner(
1639
1640
  }
1640
1641
  }
1641
1642
 
1643
+ // Post-sync conflict-ledger prune — also a best-effort tail step (runs AFTER
1644
+ // `all-complete`, never touches the exit code). The producers only append a
1645
+ // conflict row after proving real divergence, but the ledger has no other
1646
+ // self-healing path: rows for byte-identical false positives (legacy or
1647
+ // since-reverted) and orphaned `.conflict-*` mirrors otherwise linger
1648
+ // forever and make `.hq-conflicts/index.json` over-report. One GC pass per
1649
+ // run keeps it converged. Idempotent and cheap on a clean ledger (a no-row
1650
+ // index returns immediately and never rewrites the file). Opt-out via
1651
+ // HQ_CONFLICT_PRUNE_ON_SYNC=0.
1652
+ if (process.env.HQ_CONFLICT_PRUNE_ON_SYNC !== "0") {
1653
+ try {
1654
+ pruneConflictIndex(parsed.hqRoot);
1655
+ } catch {
1656
+ // Defensive: a prune failure must never affect the sync outcome.
1657
+ }
1658
+ }
1659
+
1642
1660
  // Exit 2 only when something actually threw (`errors.length > 0`). A clean
1643
1661
  // conflict-abort sets `partial: true` in the JSON but exits 0 — the Tauri
1644
1662
  // menubar's non-zero-exit Sentry capture would otherwise fire for normal
package/src/cli/index.ts CHANGED
@@ -26,10 +26,10 @@ export type { PromoteOptions, PromoteResult } from "./promote.js";
26
26
 
27
27
  // Skill/personal-overlay mirroring + workers-registry regen (formerly the
28
28
  // hq-core master-sync.sh hook; `hq reindex`).
29
- export { reindex, reindexScriptPath } from "./reindex.js";
29
+ export { reindex } from "./reindex.js";
30
30
  export type { ReindexOptions, ReindexResult } from "./reindex.js";
31
31
 
32
32
  // Drift-preserving HQ-core re-sync (formerly bundled only inside the HQ Sync
33
33
  // menubar app). Now shared between the app and `hq rescue`.
34
- export { rescue, rescueScriptPath, buildRescueArgs } from "./rescue.js";
34
+ export { rescue, buildRescueArgs } from "./rescue.js";
35
35
  export type { RescueOptions, RescueResult } from "./rescue.js";
@@ -2,25 +2,17 @@
2
2
  * Unit tests for `hq reindex` (the formerly-bash hq-core hook, now shipped
3
3
  * in this package and invoked via the CLI).
4
4
  *
5
- * The logic itself lives in scripts/reindex.sh; these tests exercise it via
6
- * the reindex() wrapper against a temp HQ tree, asserting the observable
5
+ * The logic is implemented natively in TypeScript in ./reindex.ts; these tests
6
+ * exercise reindex() directly against a temp HQ tree, asserting the observable
7
7
  * filesystem outcomes (skill wrappers, personal-overlay mirroring) rather than
8
- * re-deriving the bash internals.
8
+ * re-deriving the implementation internals.
9
9
  */
10
10
 
11
11
  import { describe, it, expect, beforeEach, afterEach } from "vitest";
12
12
  import * as fs from "fs";
13
13
  import * as path from "path";
14
14
  import * as os from "os";
15
- import { reindex, reindexScriptPath } from "./reindex.js";
16
-
17
- describe("reindexScriptPath", () => {
18
- it("resolves to the bundled script and the file exists", () => {
19
- const p = reindexScriptPath();
20
- expect(p.endsWith(path.join("scripts", "reindex.sh"))).toBe(true);
21
- expect(fs.existsSync(p)).toBe(true);
22
- });
23
- });
15
+ import { reindex } from "./reindex.js";
24
16
 
25
17
  describe("reindex", () => {
26
18
  let root: string;
@@ -91,4 +83,45 @@ describe("reindex", () => {
91
83
  fs.readlinkSync(path.join(root, ".claude/skills/core:demo/SKILL.md")),
92
84
  ).toBe("../../../core/skills/demo/SKILL.md");
93
85
  });
86
+
87
+ it("skips `_`-prefixed and dotfile skill folders", () => {
88
+ writeSkill("core/skills/_template");
89
+ fs.mkdirSync(path.join(root, "core/skills/.hidden"), { recursive: true });
90
+ fs.writeFileSync(path.join(root, "core/skills/.hidden/SKILL.md"), "x\n");
91
+ writeSkill("core/skills/real");
92
+
93
+ reindex({ repoRoot: root });
94
+
95
+ expect(fs.existsSync(path.join(root, ".claude/skills/core:real"))).toBe(true);
96
+ expect(fs.existsSync(path.join(root, ".claude/skills/core:_template"))).toBe(false);
97
+ expect(fs.existsSync(path.join(root, ".claude/skills/core:.hidden"))).toBe(false);
98
+ });
99
+
100
+ it("removes legacy .claude/commands/<ns>/<skill>.md bridge symlinks", () => {
101
+ const cmdDir = path.join(root, ".claude/commands/core");
102
+ fs.mkdirSync(cmdDir, { recursive: true });
103
+ // Legacy bridge symlink (matches the cleanup pattern) → removed.
104
+ fs.symlinkSync("../../../core/skills/demo/SKILL.md", path.join(cmdDir, "demo.md"));
105
+ // A real file (non-symlink) → preserved.
106
+ fs.writeFileSync(path.join(cmdDir, "keep.md"), "manual\n");
107
+
108
+ reindex({ repoRoot: root });
109
+
110
+ expect(fs.existsSync(path.join(cmdDir, "demo.md"))).toBe(false);
111
+ expect(fs.existsSync(path.join(cmdDir, "keep.md"))).toBe(true);
112
+ });
113
+
114
+ it("leaves hand-authored composite wrappers (unmanaged namespace) alone", () => {
115
+ // A wrapper whose namespace ('vendor') is not a managed namespace and
116
+ // whose target points into core/skills/<other> — must not be pruned.
117
+ const wrapper = path.join(root, ".claude/skills/vendor:tool");
118
+ fs.mkdirSync(wrapper, { recursive: true });
119
+ writeSkill("core/skills/helper");
120
+ fs.symlinkSync("../../../core/skills/helper/SKILL.md", path.join(wrapper, "SKILL.md"));
121
+
122
+ reindex({ repoRoot: root });
123
+
124
+ expect(fs.existsSync(wrapper)).toBe(true);
125
+ expect(fs.lstatSync(path.join(wrapper, "SKILL.md")).isSymbolicLink()).toBe(true);
126
+ });
94
127
  });
@@ -1,30 +1,22 @@
1
1
  /**
2
- * hq reindex — surfaces namespaced skills as Claude Code skill wrappers,
3
- * mirrors personal/{knowledge,policies,workers,settings} into core/, prunes
4
- * orphan wrappers, and regenerates the workers registry.
2
+ * hq reindex — surfaces namespaced skills as Claude Code skill wrappers under
3
+ * .claude/skills/<ns>:<skill>/ (one symlink per source file), mirrors
4
+ * personal/{knowledge,policies,workers,settings}/<entry> into core/<type>/,
5
+ * prunes orphan wrappers + legacy command symlinks, and regenerates the
6
+ * workers registry.
5
7
  *
6
- * The implementation lives in scripts/reindex.sh, shipped with this package.
7
- * This module resolves that script relative to the package (dist/cli → package
8
- * root) and execs it against the caller's HQ root. Historically the script ran
9
- * directly as a Claude Code hook inside hq-core (named "master-sync"); it now
10
- * lives here so a single copy is maintained, and the hq-core hook is a thin
11
- * shim over `hq reindex`.
8
+ * The logic historically lived in a bundled bash script (scripts/reindex.sh)
9
+ * that this module exec'd via `bash`. It is now implemented natively in
10
+ * TypeScript so the package ships a single, testable code path with no runtime
11
+ * dependency on a shipped shell script. Behaviour is preserved exactly: the
12
+ * same skill wrappers, personal-overlay mirrors, legacy-symlink cleanup, and
13
+ * idempotent re-runs as before. Historically the script ran directly as a
14
+ * Claude Code hook inside hq-core (named "master-sync"); the hq-core hook
15
+ * remains a thin shim over `hq reindex`.
12
16
  */
13
17
  import { spawnSync } from "child_process";
14
- import { fileURLToPath } from "url";
15
- import path from "path";
16
-
17
- const __filename = fileURLToPath(import.meta.url);
18
- const __dirname = path.dirname(__filename);
19
-
20
- /**
21
- * Absolute path to the bundled reindex.sh. From the compiled module at
22
- * dist/cli/reindex.js, the package root is two levels up; the script lives
23
- * at <package-root>/scripts/reindex.sh.
24
- */
25
- export function reindexScriptPath(): string {
26
- return path.resolve(__dirname, "..", "..", "scripts", "reindex.sh");
27
- }
18
+ import * as fs from "fs";
19
+ import * as path from "path";
28
20
 
29
21
  export interface ReindexOptions {
30
22
  /** HQ root to operate on. Defaults to process.cwd(). */
@@ -32,26 +24,343 @@ export interface ReindexOptions {
32
24
  }
33
25
 
34
26
  export interface ReindexResult {
35
- /** Exit status of the underlying script (0 = success). */
27
+ /** 0 = success; 1 = invalid repo root (mirrors the old script's exit codes). */
36
28
  status: number;
37
29
  }
38
30
 
31
+ // --- small fs helpers (each mirrors a bash test operator) -------------------
32
+
33
+ /** `[ -d "$p" ]` — exists and is a directory (follows symlinks). */
34
+ function isDir(p: string): boolean {
35
+ try {
36
+ return fs.statSync(p).isDirectory();
37
+ } catch {
38
+ return false;
39
+ }
40
+ }
41
+
42
+ /** `[ -f "$p" ]` — exists and is a regular file (follows symlinks). */
43
+ function isFile(p: string): boolean {
44
+ try {
45
+ return fs.statSync(p).isFile();
46
+ } catch {
47
+ return false;
48
+ }
49
+ }
50
+
51
+ /** `[ -e "$p" ]` — exists, dereferencing symlinks (a broken symlink is false). */
52
+ function existsFollow(p: string): boolean {
53
+ try {
54
+ fs.statSync(p);
55
+ return true;
56
+ } catch {
57
+ return false;
58
+ }
59
+ }
60
+
61
+ /** `[ -x "$p" ]` — exists and is executable. */
62
+ function isExecutable(p: string): boolean {
63
+ try {
64
+ fs.accessSync(p, fs.constants.X_OK);
65
+ return true;
66
+ } catch {
67
+ return false;
68
+ }
69
+ }
70
+
71
+ /** lstat without throwing (null when the path doesn't exist). */
72
+ function lstatOrNull(p: string): fs.Stats | null {
73
+ try {
74
+ return fs.lstatSync(p);
75
+ } catch {
76
+ return null;
77
+ }
78
+ }
79
+
80
+ /** readlink without throwing (null when not a symlink / missing). */
81
+ function readlinkOrNull(p: string): string | null {
82
+ try {
83
+ return fs.readlinkSync(p);
84
+ } catch {
85
+ return null;
86
+ }
87
+ }
88
+
39
89
  /**
40
- * Run reindex against an HQ root. Synchronous the script is cheap and
90
+ * Entries of `dir` matching a bash `dir/*` glob: dotfiles excluded (no
91
+ * dotglob), sorted lexicographically (bash glob order). Missing dir → [].
92
+ */
93
+ function globEntries(dir: string): string[] {
94
+ let names: string[];
95
+ try {
96
+ names = fs.readdirSync(dir);
97
+ } catch {
98
+ return [];
99
+ }
100
+ return names.filter((n) => !n.startsWith(".")).sort();
101
+ }
102
+
103
+ function warn(msg: string): void {
104
+ process.stderr.write(`${msg}\n`);
105
+ }
106
+
107
+ // --- legacy `.claude/commands/<ns>/<skill>.md` symlink matcher --------------
108
+ // Mirrors the bash `case` patterns; `*` matches any chars (including `/`).
109
+ function isLegacyCommandTarget(t: string): boolean {
110
+ return (
111
+ /^\.\.\/\.\.\/\.\.\/companies\/.*\/skills\/.*\/SKILL\.md$/.test(t) ||
112
+ /^\.\.\/\.\.\/\.\.\/core\/skills\/.*\/SKILL\.md$/.test(t) ||
113
+ /^\.\.\/\.\.\/\.\.\/personal\/skills\/.*\/SKILL\.md$/.test(t) ||
114
+ /^\.\.\/\.\.\/\.\.\/core\/packages\/.*\/skills\/.*\/SKILL\.md$/.test(t)
115
+ );
116
+ }
117
+
118
+ /**
119
+ * Run reindex against an HQ root. Synchronous — the work is cheap and
41
120
  * idempotent, and callers (the hook shim, sync/rescue, tests) want the exit
42
- * status. stdout/stderr from the script are forwarded to stderr so the
43
- * caller's stdout stays clean (hooks must not emit stdout that the agent
44
- * interprets).
121
+ * status. Diagnostics are written to stderr so the caller's stdout stays clean
122
+ * (hooks must not emit stdout that the agent interprets).
45
123
  */
46
124
  export function reindex(opts: ReindexOptions = {}): ReindexResult {
47
- const repoRoot = opts.repoRoot ?? process.cwd();
48
- const script = reindexScriptPath();
49
- const res = spawnSync("bash", [script, repoRoot], {
50
- stdio: ["ignore", "inherit", "inherit"],
51
- });
52
- if (res.error) {
53
- process.stderr.write(`reindex: failed to run ${script}: ${res.error.message}\n`);
125
+ const rawRoot = opts.repoRoot ?? process.cwd();
126
+ if (!isDir(rawRoot)) {
127
+ warn(`reindex: REPO_ROOT '${rawRoot}' is not a directory`);
54
128
  return { status: 1 };
55
129
  }
56
- return { status: res.status ?? 1 };
130
+ const root = path.resolve(rawRoot);
131
+
132
+ fs.mkdirSync(path.join(root, ".claude", "skills"), { recursive: true });
133
+
134
+ // --- Build (namespace, src_rel) pairs -------------------------------------
135
+ const pairs: { ns: string; srcRel: string }[] = [];
136
+ const addNs = (ns: string, srcRel: string): void => {
137
+ if (isDir(path.join(root, srcRel))) pairs.push({ ns, srcRel });
138
+ };
139
+
140
+ for (const slug of globEntries(path.join(root, "companies"))) {
141
+ if (isDir(path.join(root, "companies", slug))) {
142
+ addNs(slug, `companies/${slug}/skills`);
143
+ }
144
+ }
145
+ addNs("core", "core/skills");
146
+ addNs("personal", "personal/skills");
147
+ for (const pack of globEntries(path.join(root, "core", "packages"))) {
148
+ if (isDir(path.join(root, "core", "packages", pack))) {
149
+ addNs(pack, `core/packages/${pack}/skills`);
150
+ }
151
+ }
152
+
153
+ // --- Cleanup pass A: drop legacy .claude/commands/<ns>/<skill>.md links ----
154
+ const commandsDir = path.join(root, ".claude", "commands");
155
+ if (isDir(commandsDir)) {
156
+ for (const nsName of globEntries(commandsDir)) {
157
+ const cmdNsDir = path.join(commandsDir, nsName);
158
+ // Only real directories (bash `*/`); folder-level symlinks are left for
159
+ // a human to resolve. lstat().isDirectory() is false for a symlink, so
160
+ // this single check covers both bash guards.
161
+ const st = lstatOrNull(cmdNsDir);
162
+ if (!st || !st.isDirectory()) continue;
163
+
164
+ for (const f of globEntries(cmdNsDir)) {
165
+ if (!f.endsWith(".md")) continue;
166
+ const fp = path.join(cmdNsDir, f);
167
+ const fst = lstatOrNull(fp);
168
+ if (!fst || !fst.isSymbolicLink()) continue;
169
+ const target = readlinkOrNull(fp);
170
+ if (target && isLegacyCommandTarget(target)) {
171
+ try {
172
+ fs.rmSync(fp);
173
+ } catch {
174
+ /* best-effort */
175
+ }
176
+ }
177
+ }
178
+
179
+ // rmdir if empty; ignore "directory not empty".
180
+ try {
181
+ fs.rmdirSync(cmdNsDir);
182
+ } catch {
183
+ /* not empty / gone — fine */
184
+ }
185
+ }
186
+ }
187
+
188
+ // --- Skill wrapper creation -----------------------------------------------
189
+ const expectedWrappers = new Set<string>();
190
+ const seen = new Set<string>();
191
+
192
+ for (const { ns, srcRel } of pairs) {
193
+ // First writer for a namespace wins.
194
+ if (seen.has(ns)) {
195
+ warn(
196
+ `reindex: namespace '${ns}' already claimed by an earlier source; skipping ${srcRel}`,
197
+ );
198
+ continue;
199
+ }
200
+ seen.add(ns);
201
+
202
+ const srcAbs = path.join(root, srcRel);
203
+ for (const skillName of globEntries(srcAbs)) {
204
+ const skillPath = path.join(srcAbs, skillName);
205
+ if (!isDir(skillPath)) continue;
206
+ // Skip `_shared`, `_template`, etc. (dotfiles already excluded by glob).
207
+ if (skillName.startsWith("_")) continue;
208
+ if (!isFile(path.join(skillPath, "SKILL.md"))) continue;
209
+
210
+ const wrapperName = `${ns}:${skillName}`;
211
+ const wrapper = path.join(root, ".claude", "skills", wrapperName);
212
+ expectedWrappers.add(wrapperName);
213
+
214
+ const wst = lstatOrNull(wrapper);
215
+ // If something non-directory, non-symlink occupies the slot, bail.
216
+ if (wst && !wst.isSymbolicLink() && !wst.isDirectory()) {
217
+ warn(`reindex: ${wrapper} exists and is not a directory; skipping`);
218
+ continue;
219
+ }
220
+ // If it's a symlink (legacy directory-symlink form), replace it with a
221
+ // real directory of per-file symlinks.
222
+ if (wst && wst.isSymbolicLink()) {
223
+ try {
224
+ fs.rmSync(wrapper);
225
+ } catch {
226
+ /* best-effort */
227
+ }
228
+ }
229
+ fs.mkdirSync(wrapper, { recursive: true });
230
+
231
+ // Symlink every (non-hidden) entry in the source skill folder. The
232
+ // wrapper lives three levels below REPO_ROOT.
233
+ for (const entry of globEntries(skillPath)) {
234
+ const entryPath = path.join(skillPath, entry);
235
+ if (!existsFollow(entryPath)) continue;
236
+ const linkPath = path.join(wrapper, entry);
237
+ const relativeTarget = `../../../${srcRel}/${skillName}/${entry}`;
238
+
239
+ const lst = lstatOrNull(linkPath);
240
+ if (lst && lst.isSymbolicLink()) {
241
+ const current = readlinkOrNull(linkPath);
242
+ if (current === relativeTarget) continue;
243
+ warn(
244
+ `reindex: .claude/skills/${wrapperName}/${entry} already points to '${current}' (expected '${relativeTarget}'); leaving alone`,
245
+ );
246
+ continue;
247
+ } else if (lst) {
248
+ warn(`reindex: ${linkPath} already exists and is not a symlink; skipping`);
249
+ continue;
250
+ }
251
+
252
+ fs.symlinkSync(relativeTarget, linkPath);
253
+ }
254
+
255
+ // Prune symlinks in the wrapper whose source entry no longer exists.
256
+ for (const entry of globEntries(wrapper)) {
257
+ const linkPath = path.join(wrapper, entry);
258
+ const lst = lstatOrNull(linkPath);
259
+ if (!lst || !lst.isSymbolicLink()) continue;
260
+ if (existsFollow(linkPath)) continue;
261
+ try {
262
+ fs.rmSync(linkPath);
263
+ } catch {
264
+ /* best-effort */
265
+ }
266
+ }
267
+ }
268
+ }
269
+
270
+ // --- Cleanup pass B: drop orphan <ns>:<skill> wrappers --------------------
271
+ const skillsDir = path.join(root, ".claude", "skills");
272
+ for (const entry of globEntries(skillsDir)) {
273
+ const entryPath = path.join(skillsDir, entry);
274
+ const lst = lstatOrNull(entryPath);
275
+ if (!lst) continue; // accept broken symlinks (lstat still succeeds)
276
+ if (!entry.includes(":")) continue; // not a namespaced wrapper
277
+ if (expectedWrappers.has(entry)) continue; // maintained this run
278
+
279
+ // A wrapper is "managed" only when its namespace prefix matches the
280
+ // namespace encoded in its symlink target — this distinguishes
281
+ // script-produced wrappers from hand-authored composite wrappers.
282
+ const ns = entry.slice(0, entry.indexOf(":"));
283
+ const matchTarget = (t: string | null, p: string): boolean => {
284
+ if (!t) return false;
285
+ if (t.startsWith(`${p}/personal/skills/`)) return ns === "personal";
286
+ if (t.startsWith(`${p}/core/skills/`)) return ns === "core";
287
+ if (t.startsWith(`${p}/companies/${ns}/skills/`)) return true;
288
+ if (t.startsWith(`${p}/core/packages/${ns}/skills/`)) return true;
289
+ return false;
290
+ };
291
+
292
+ let isManaged = false;
293
+ if (lst.isSymbolicLink()) {
294
+ // (a) directory-style symlink wrapper (older shape): 2-level target.
295
+ isManaged = matchTarget(readlinkOrNull(entryPath), "../..");
296
+ } else if (lst.isDirectory()) {
297
+ // (b) real directory of per-file symlinks (current shape): 3-level.
298
+ for (const f of globEntries(entryPath)) {
299
+ const fp = path.join(entryPath, f);
300
+ const fst = lstatOrNull(fp);
301
+ if (!fst || !fst.isSymbolicLink()) continue;
302
+ if (matchTarget(readlinkOrNull(fp), "../../..")) {
303
+ isManaged = true;
304
+ break;
305
+ }
306
+ }
307
+ }
308
+ if (!isManaged) continue;
309
+
310
+ // Managed-namespace wrapper with no corresponding live source → drop.
311
+ try {
312
+ if (lst.isSymbolicLink()) {
313
+ fs.rmSync(entryPath);
314
+ } else if (lst.isDirectory()) {
315
+ fs.rmSync(entryPath, { recursive: true, force: true });
316
+ }
317
+ } catch {
318
+ /* best-effort */
319
+ }
320
+ }
321
+
322
+ // --- Personal type mirroring ----------------------------------------------
323
+ // Mirror personal/<type>/<entry> into core/<type>/<entry> as symlinks.
324
+ for (const type of ["knowledge", "policies", "workers", "settings"]) {
325
+ const personalDir = path.join(root, "personal", type);
326
+ const coreDir = path.join(root, "core", type);
327
+
328
+ if (!isDir(personalDir)) continue;
329
+ fs.mkdirSync(coreDir, { recursive: true });
330
+
331
+ for (const entry of globEntries(personalDir)) {
332
+ const entryPath = path.join(personalDir, entry);
333
+ if (!existsFollow(entryPath)) continue;
334
+
335
+ const linkPath = path.join(coreDir, entry);
336
+ const relativeTarget = `../../personal/${type}/${entry}`;
337
+
338
+ const lst = lstatOrNull(linkPath);
339
+ if (lst && lst.isSymbolicLink()) {
340
+ const current = readlinkOrNull(linkPath);
341
+ if (current === relativeTarget) continue;
342
+ warn(
343
+ `reindex: core/${type}/${entry} already points to '${current}' (expected '${relativeTarget}'); leaving alone`,
344
+ );
345
+ continue;
346
+ } else if (lst) {
347
+ warn(`reindex: core/${type}/${entry} already exists and is not a symlink; skipping`);
348
+ continue;
349
+ }
350
+
351
+ fs.symlinkSync(relativeTarget, linkPath);
352
+ }
353
+ }
354
+
355
+ // --- Workers registry regeneration ----------------------------------------
356
+ // Source of truth: each worker.yaml. The registry is a derived index — the
357
+ // generator (when present in the operated-on tree) keeps it in sync.
358
+ // Best-effort and idempotent; never fails the reindex.
359
+ const genScript = path.join(root, "core", "scripts", "generate-workers-registry.sh");
360
+ if (isExecutable(genScript)) {
361
+ // Route the generator's stdout+stderr to our stderr (`>&2 2>&1`).
362
+ spawnSync("bash", [genScript], { stdio: ["ignore", 2, 2] });
363
+ }
364
+
365
+ return { status: 0 };
57
366
  }