@indigoai-us/hq-cloud 6.13.2 → 6.13.4

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 (47) hide show
  1. package/dist/bin/sync-runner-company.d.ts.map +1 -1
  2. package/dist/bin/sync-runner-company.js +15 -0
  3. package/dist/bin/sync-runner-company.js.map +1 -1
  4. package/dist/bin/sync-runner-rollup.d.ts +7 -0
  5. package/dist/bin/sync-runner-rollup.d.ts.map +1 -1
  6. package/dist/bin/sync-runner-rollup.js +15 -0
  7. package/dist/bin/sync-runner-rollup.js.map +1 -1
  8. package/dist/bin/sync-runner.d.ts +7 -0
  9. package/dist/bin/sync-runner.d.ts.map +1 -1
  10. package/dist/bin/sync-runner.js +27 -3
  11. package/dist/bin/sync-runner.js.map +1 -1
  12. package/dist/bin/sync-runner.test.js +73 -0
  13. package/dist/bin/sync-runner.test.js.map +1 -1
  14. package/dist/cli/reindex.d.ts.map +1 -1
  15. package/dist/cli/reindex.js +38 -0
  16. package/dist/cli/reindex.js.map +1 -1
  17. package/dist/cli/reindex.test.js +77 -0
  18. package/dist/cli/reindex.test.js.map +1 -1
  19. package/dist/cli/share.js +15 -2
  20. package/dist/cli/share.js.map +1 -1
  21. package/dist/cli/share.test.js +39 -0
  22. package/dist/cli/share.test.js.map +1 -1
  23. package/dist/cli/sync.d.ts +22 -0
  24. package/dist/cli/sync.d.ts.map +1 -1
  25. package/dist/cli/sync.js +60 -1
  26. package/dist/cli/sync.js.map +1 -1
  27. package/dist/cli/sync.test.js +88 -0
  28. package/dist/cli/sync.test.js.map +1 -1
  29. package/dist/qmd-reindex.d.ts +14 -0
  30. package/dist/qmd-reindex.d.ts.map +1 -1
  31. package/dist/qmd-reindex.js +93 -19
  32. package/dist/qmd-reindex.js.map +1 -1
  33. package/dist/qmd-reindex.test.js +47 -0
  34. package/dist/qmd-reindex.test.js.map +1 -1
  35. package/package.json +1 -1
  36. package/src/bin/sync-runner-company.ts +21 -0
  37. package/src/bin/sync-runner-rollup.ts +23 -0
  38. package/src/bin/sync-runner.test.ts +90 -0
  39. package/src/bin/sync-runner.ts +37 -5
  40. package/src/cli/reindex.test.ts +92 -0
  41. package/src/cli/reindex.ts +35 -0
  42. package/src/cli/share.test.ts +46 -0
  43. package/src/cli/share.ts +14 -2
  44. package/src/cli/sync.test.ts +105 -0
  45. package/src/cli/sync.ts +101 -1
  46. package/src/qmd-reindex.test.ts +50 -0
  47. package/src/qmd-reindex.ts +124 -18
@@ -37,6 +37,7 @@ const defaultExec = (args) => {
37
37
  });
38
38
  return { status: res.status, stdout: res.stdout ?? "" };
39
39
  };
40
+ const DEFAULT_CHANGED_PATH_DEBOUNCE_MS = 60_000;
40
41
  /**
41
42
  * Reindex qmd for an HQ tree after a sync. Never throws — all failures are
42
43
  * swallowed so a reindex problem can never mask or fail the sync result.
@@ -46,11 +47,29 @@ const defaultExec = (args) => {
46
47
  export function reindexAfterSync(hqRoot, opts = {}) {
47
48
  const exec = opts.exec ?? defaultExec;
48
49
  const existsSync = opts.existsSync ?? fs.existsSync;
49
- const result = { qmdAvailable: false, collectionsAdded: [], updated: false, embedded: false };
50
+ const result = {
51
+ qmdAvailable: false,
52
+ collectionsAdded: [],
53
+ updated: false,
54
+ embedded: false,
55
+ pendingDirty: false,
56
+ };
50
57
  try {
51
58
  // Guard: only operate on a real HQ tree.
52
59
  if (!existsSync(path.join(hqRoot, "core", "core.yaml")))
53
60
  return result;
61
+ const statePath = opts.statePath ?? path.join(hqRoot, ".hq", "qmd-reindex-state.json");
62
+ const state = readState(statePath);
63
+ const changedPaths = opts.changedPaths;
64
+ const dirtyFromChanges = changedPaths === undefined ||
65
+ changedPaths.some(isKnowledgeMarkdownPath);
66
+ const registrationMayBeStale = opts.forceCollectionRefresh === true ||
67
+ changedPaths === undefined ||
68
+ dirtyFromChanges;
69
+ const pendingDirty = state.pendingDirty === true;
70
+ if (!dirtyFromChanges && !registrationMayBeStale && !pendingDirty) {
71
+ return result;
72
+ }
54
73
  // Guard: qmd must be installed. `qmd collection list` doubles as the
55
74
  // availability probe AND the source for which collections already exist.
56
75
  const list = exec(["collection", "list"]);
@@ -59,27 +78,61 @@ export function reindexAfterSync(hqRoot, opts = {}) {
59
78
  result.qmdAvailable = true;
60
79
  const existingCollections = list.stdout;
61
80
  // 1. Auto-register missing company knowledge collections.
62
- const companiesDir = path.join(hqRoot, "companies");
63
- const slugs = (opts.readCompanies ?? defaultReadCompanies)(companiesDir);
64
- for (const slug of slugs) {
65
- const knowledgeDir = path.join(companiesDir, slug, "knowledge");
66
- if (!existsSync(knowledgeDir))
67
- continue;
68
- const hasMd = (opts.hasIndexableMarkdown ?? defaultHasIndexableMarkdown)(knowledgeDir);
69
- if (!hasMd)
70
- continue;
71
- // Already registered? qmd collection URIs look like `qmd://<slug>/`.
72
- if (existingCollections.includes(`qmd://${slug}/`))
73
- continue;
74
- const add = exec(["collection", "add", knowledgeDir, "--name", slug, "--mask", "**/*.md"]);
75
- if (add.status === 0) {
76
- exec(["context", "add", `qmd://${slug}`, `Knowledge base for ${slug}.`]);
77
- result.collectionsAdded.push(slug);
81
+ if (registrationMayBeStale) {
82
+ const companiesDir = path.join(hqRoot, "companies");
83
+ const slugs = (opts.readCompanies ?? defaultReadCompanies)(companiesDir);
84
+ for (const slug of slugs) {
85
+ const knowledgeDir = path.join(companiesDir, slug, "knowledge");
86
+ if (!existsSync(knowledgeDir))
87
+ continue;
88
+ const hasMd = (opts.hasIndexableMarkdown ?? defaultHasIndexableMarkdown)(knowledgeDir);
89
+ if (!hasMd)
90
+ continue;
91
+ // Already registered? qmd collection URIs look like `qmd://<slug>/`.
92
+ if (existingCollections.includes(`qmd://${slug}/`))
93
+ continue;
94
+ const add = exec(["collection", "add", knowledgeDir, "--name", slug, "--mask", "**/*.md"]);
95
+ if (add.status === 0) {
96
+ exec(["context", "add", `qmd://${slug}`, `Knowledge base for ${slug}.`]);
97
+ result.collectionsAdded.push(slug);
98
+ }
78
99
  }
79
100
  }
80
101
  // 2. Incremental lexical reindex.
81
- const update = exec(["update"]);
82
- result.updated = update.status === 0;
102
+ const shouldUpdate = dirtyFromChanges || pendingDirty;
103
+ if (shouldUpdate) {
104
+ const nowMs = opts.nowMs ?? Date.now();
105
+ const debounceMs = opts.debounceMs ??
106
+ (changedPaths === undefined ? 0 : DEFAULT_CHANGED_PATH_DEBOUNCE_MS);
107
+ const pendingSinceMs = pendingDirty && typeof state.pendingSinceMs === "number"
108
+ ? state.pendingSinceMs
109
+ : nowMs;
110
+ if (debounceMs > 0 && nowMs - pendingSinceMs < debounceMs) {
111
+ writeState(statePath, {
112
+ ...state,
113
+ pendingDirty: true,
114
+ pendingSinceMs,
115
+ });
116
+ result.pendingDirty = true;
117
+ return result;
118
+ }
119
+ const update = exec(["update"]);
120
+ result.updated = update.status === 0;
121
+ if (result.updated) {
122
+ writeState(statePath, {
123
+ pendingDirty: false,
124
+ lastSuccessMs: nowMs,
125
+ });
126
+ }
127
+ else {
128
+ writeState(statePath, {
129
+ ...state,
130
+ pendingDirty: true,
131
+ pendingSinceMs,
132
+ });
133
+ result.pendingDirty = true;
134
+ }
135
+ }
83
136
  // 3. Embeddings only on explicit request.
84
137
  if (opts.embed) {
85
138
  const embed = exec(["embed"]);
@@ -102,6 +155,27 @@ export function reindexAfterSync(hqRoot, opts = {}) {
102
155
  }
103
156
  return result;
104
157
  }
158
+ function readState(statePath) {
159
+ try {
160
+ return JSON.parse(fs.readFileSync(statePath, "utf8"));
161
+ }
162
+ catch {
163
+ return {};
164
+ }
165
+ }
166
+ function writeState(statePath, state) {
167
+ try {
168
+ fs.mkdirSync(path.dirname(statePath), { recursive: true });
169
+ fs.writeFileSync(statePath, JSON.stringify(state, null, 2) + "\n");
170
+ }
171
+ catch {
172
+ // State is an optimization/guarantee aid; QMD failures must not fail sync.
173
+ }
174
+ }
175
+ function isKnowledgeMarkdownPath(relPath) {
176
+ const normalized = relPath.split(path.sep).join("/");
177
+ return /^companies\/[^/]+\/knowledge\/.+\.md$/i.test(normalized);
178
+ }
105
179
  function defaultReadCompanies(companiesDir) {
106
180
  try {
107
181
  return fs
@@ -1 +1 @@
1
- {"version":3,"file":"qmd-reindex.js","sourceRoot":"","sources":["../src/qmd-reindex.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"qmd-reindex.js","sourceRoot":"","sources":["../src/qmd-reindex.ts"],"names":[],"mappings":"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"}
@@ -89,6 +89,53 @@ describe("reindexAfterSync", () => {
89
89
  expect(r.collectionsAdded).toEqual([]);
90
90
  expect(calls).toEqual([["collection", "list"], ["update"]]);
91
91
  });
92
+ it("skips qmd entirely when provided changed paths do not touch knowledge markdown", () => {
93
+ const { exec, calls } = fakeExec({ listStdout: "" });
94
+ const r = reindexAfterSync("/hq", {
95
+ exec,
96
+ existsSync: () => true,
97
+ changedPaths: ["companies/acme/docs/readme.txt"],
98
+ });
99
+ expect(r.qmdAvailable).toBe(false);
100
+ expect(r.updated).toBe(false);
101
+ expect(calls).toEqual([]);
102
+ });
103
+ it("debounces dirty updates with a pending marker and flushes the final update later", () => {
104
+ const dir = fs.mkdtempSync(path.join(os.tmpdir(), "hq-qmd-debounce-"));
105
+ try {
106
+ const statePath = path.join(dir, "qmd-state.json");
107
+ const { exec, calls } = fakeExec({ listStdout: "acme (qmd://acme/)\n" });
108
+ const first = reindexAfterSync("/hq", {
109
+ exec,
110
+ existsSync: () => true,
111
+ changedPaths: ["companies/acme/knowledge/note.md"],
112
+ debounceMs: 60_000,
113
+ nowMs: 100_000,
114
+ statePath,
115
+ });
116
+ expect(first.updated).toBe(false);
117
+ expect(first.pendingDirty).toBe(true);
118
+ expect(calls).toEqual([["collection", "list"]]);
119
+ const second = reindexAfterSync("/hq", {
120
+ exec,
121
+ existsSync: () => true,
122
+ changedPaths: [],
123
+ debounceMs: 60_000,
124
+ nowMs: 161_000,
125
+ statePath,
126
+ });
127
+ expect(second.updated).toBe(true);
128
+ expect(second.pendingDirty).toBe(false);
129
+ expect(calls).toEqual([
130
+ ["collection", "list"],
131
+ ["collection", "list"],
132
+ ["update"],
133
+ ]);
134
+ }
135
+ finally {
136
+ fs.rmSync(dir, { recursive: true, force: true });
137
+ }
138
+ });
92
139
  it("runs embed only when embed:true", () => {
93
140
  const { exec, calls } = fakeExec({ listStdout: "" });
94
141
  const r = reindexAfterSync("/hq", {
@@ -1 +1 @@
1
- {"version":3,"file":"qmd-reindex.test.js","sourceRoot":"","sources":["../src/qmd-reindex.test.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"qmd-reindex.test.js","sourceRoot":"","sources":["../src/qmd-reindex.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.13.2",
3
+ "version": "6.13.4",
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",
@@ -168,6 +168,7 @@ export async function executeCompanyFanout(options: {
168
168
  filesOutOfScope: 0,
169
169
  scopeOrphansRemoved: 0,
170
170
  scopeOrphansBlocked: 0,
171
+ changedPaths: [],
171
172
  };
172
173
 
173
174
  // Local (non-cloud) companies always sync to the personal vault. The
@@ -255,6 +256,7 @@ export async function executeCompanyFanout(options: {
255
256
  ...(options.operationLockAlreadyHeld
256
257
  ? { operationLockAlreadyHeld: true }
257
258
  : {}),
259
+ skipReindex: true,
258
260
  onEvent: tagAndEmit,
259
261
  });
260
262
  }
@@ -273,6 +275,12 @@ export async function executeCompanyFanout(options: {
273
275
 
274
276
  state.filesDownloaded = pullResult.filesDownloaded;
275
277
  state.bytesDownloaded = pullResult.bytesDownloaded;
278
+ state.filesTombstoned = pullResult.filesTombstoned;
279
+ state.scopeOrphansRemoved = pullResult.scopeOrphansRemoved;
280
+ state.changedPaths = normalizePullChangedPaths(
281
+ target,
282
+ pullResult.changedPaths,
283
+ );
276
284
  state.filesUploaded = pushResult.filesUploaded;
277
285
  state.bytesUploaded = pushResult.bytesUploaded;
278
286
  state.status = companyHadTransferError
@@ -342,6 +350,7 @@ export async function executeCompanyFanout(options: {
342
350
  filesOutOfScope: 0,
343
351
  scopeOrphansRemoved: 0,
344
352
  scopeOrphansBlocked: 0,
353
+ changedPaths: [],
345
354
  });
346
355
  options.emit({
347
356
  type: "error",
@@ -354,3 +363,15 @@ export async function executeCompanyFanout(options: {
354
363
 
355
364
  return { stateByCompany, errors, allConflicts };
356
365
  }
366
+
367
+ function normalizePullChangedPaths(
368
+ target: RunnerTarget,
369
+ changedPaths: string[] | undefined,
370
+ ): string[] {
371
+ const paths = changedPaths ?? [];
372
+ return paths.map((p) => {
373
+ const normalized = p.split(path.sep).join("/");
374
+ if (target.personalMode === true) return normalized;
375
+ return `companies/${target.slug}/${normalized}`;
376
+ });
377
+ }
@@ -8,6 +8,9 @@ export interface CompanyState {
8
8
  status: CompanyStatus;
9
9
  filesDownloaded: number;
10
10
  bytesDownloaded: number;
11
+ filesTombstoned: number;
12
+ scopeOrphansRemoved: number;
13
+ changedPaths: string[];
11
14
  filesUploaded: number;
12
15
  bytesUploaded: number;
13
16
  }
@@ -15,8 +18,12 @@ export interface CompanyState {
15
18
  export interface AllCompleteRollup {
16
19
  totalDownloaded: number;
17
20
  totalDownloadedBytes: number;
21
+ totalTombstoned: number;
22
+ totalScopeOrphansRemoved: number;
18
23
  totalUploaded: number;
19
24
  totalUploadedBytes: number;
25
+ changedPaths: string[];
26
+ needsReindex: boolean;
20
27
  partial: boolean;
21
28
  companies: Extract<RunnerEvent, { type: "all-complete" }>["companies"];
22
29
  }
@@ -27,6 +34,9 @@ export function createCompanyState(company: string): CompanyState {
27
34
  status: "errored",
28
35
  filesDownloaded: 0,
29
36
  bytesDownloaded: 0,
37
+ filesTombstoned: 0,
38
+ scopeOrphansRemoved: 0,
39
+ changedPaths: [],
30
40
  filesUploaded: 0,
31
41
  bytesUploaded: 0,
32
42
  };
@@ -38,8 +48,11 @@ export function rollupAllComplete(
38
48
  ): AllCompleteRollup {
39
49
  let totalDownloaded = 0;
40
50
  let totalDownloadedBytes = 0;
51
+ let totalTombstoned = 0;
52
+ let totalScopeOrphansRemoved = 0;
41
53
  let totalUploaded = 0;
42
54
  let totalUploadedBytes = 0;
55
+ const changedPaths: string[] = [];
43
56
  let partial = false;
44
57
  const companies: AllCompleteRollup["companies"] = [];
45
58
 
@@ -48,8 +61,11 @@ export function rollupAllComplete(
48
61
  if (!s) continue;
49
62
  totalDownloaded += s.filesDownloaded;
50
63
  totalDownloadedBytes += s.bytesDownloaded;
64
+ totalTombstoned += s.filesTombstoned;
65
+ totalScopeOrphansRemoved += s.scopeOrphansRemoved;
51
66
  totalUploaded += s.filesUploaded;
52
67
  totalUploadedBytes += s.bytesUploaded;
68
+ changedPaths.push(...s.changedPaths);
53
69
  if (s.status !== "complete") partial = true;
54
70
  companies.push({
55
71
  company: s.company,
@@ -64,8 +80,15 @@ export function rollupAllComplete(
64
80
  return {
65
81
  totalDownloaded,
66
82
  totalDownloadedBytes,
83
+ totalTombstoned,
84
+ totalScopeOrphansRemoved,
67
85
  totalUploaded,
68
86
  totalUploadedBytes,
87
+ changedPaths,
88
+ needsReindex:
89
+ totalDownloaded > 0 ||
90
+ totalTombstoned > 0 ||
91
+ totalScopeOrphansRemoved > 0,
69
92
  partial,
70
93
  companies,
71
94
  };
@@ -112,6 +112,7 @@ function defaultSyncResult(overrides: Partial<SyncResult> = {}): SyncResult {
112
112
  filesOutOfScope: 0,
113
113
  scopeOrphansRemoved: 0,
114
114
  scopeOrphansBlocked: 0,
115
+ changedPaths: [],
115
116
  ...overrides,
116
117
  };
117
118
  }
@@ -205,6 +206,14 @@ function makeDeps(overrides: Partial<RunnerDeps> = {}): TestDeps {
205
206
  getAccessToken: vi.fn().mockResolvedValue("test-access-token"),
206
207
  createVaultClient: vi.fn().mockImplementation(() => makeVaultStub()),
207
208
  sync: vi.fn().mockResolvedValue(defaultSyncResult()),
209
+ reindex: vi.fn(() => ({ status: 0 })),
210
+ qmdReindex: vi.fn(() => ({
211
+ qmdAvailable: true,
212
+ collectionsAdded: [],
213
+ updated: true,
214
+ embedded: false,
215
+ pendingDirty: false,
216
+ })),
208
217
  ...overrides,
209
218
  stdout,
210
219
  stderr,
@@ -1602,6 +1611,87 @@ describe("all-complete aggregate", () => {
1602
1611
  });
1603
1612
  });
1604
1613
 
1614
+ it("skips per-target native reindex and runs one final reindex for tombstones or scope orphans", async () => {
1615
+ const slugs: Record<string, string> = { cmp_a: "acme", cmp_b: "beta" };
1616
+ const reindex = vi.fn(() => ({ status: 0 }));
1617
+ const syncSpy = vi
1618
+ .fn<(opts: SyncOptions) => Promise<SyncResult>>()
1619
+ .mockResolvedValueOnce(defaultSyncResult({ filesTombstoned: 1 }))
1620
+ .mockResolvedValueOnce(defaultSyncResult({ scopeOrphansRemoved: 1 }));
1621
+ const deps = makeDeps({
1622
+ operationLockAlreadyHeld: true,
1623
+ createVaultClient: () =>
1624
+ makeVaultStub({
1625
+ memberships: [{ companyUid: "cmp_a" }, { companyUid: "cmp_b" }],
1626
+ entityGet: (uid: string) =>
1627
+ Promise.resolve({ uid, slug: slugs[uid] ?? uid } as unknown as EntityInfo),
1628
+ }),
1629
+ sync: syncSpy,
1630
+ reindex,
1631
+ } as Partial<RunnerDeps>);
1632
+
1633
+ const code = await runRunner(["--companies", "--hq-root", "/tmp/fake-hq"], deps);
1634
+
1635
+ expect(code).toBe(0);
1636
+ expect(syncSpy).toHaveBeenCalledTimes(2);
1637
+ expect(syncSpy.mock.calls.map(([opts]) => opts.skipReindex)).toEqual([
1638
+ true,
1639
+ true,
1640
+ ]);
1641
+ expect(reindex).toHaveBeenCalledTimes(1);
1642
+ expect(reindex).toHaveBeenCalledWith({
1643
+ repoRoot: "/tmp/fake-hq",
1644
+ skipLock: true,
1645
+ });
1646
+ });
1647
+
1648
+ it("gates qmd to knowledge markdown changes and propagates hq-relative changed paths", async () => {
1649
+ const slugs: Record<string, string> = { cmp_a: "acme", cmp_b: "beta" };
1650
+ const qmdReindex = vi.fn(() => ({
1651
+ qmdAvailable: true,
1652
+ collectionsAdded: [],
1653
+ updated: true,
1654
+ embedded: false,
1655
+ pendingDirty: false,
1656
+ }));
1657
+ const deps = makeDeps({
1658
+ createVaultClient: () =>
1659
+ makeVaultStub({
1660
+ memberships: [{ companyUid: "cmp_a" }, { companyUid: "cmp_b" }],
1661
+ entityGet: (uid: string) =>
1662
+ Promise.resolve({ uid, slug: slugs[uid] ?? uid } as unknown as EntityInfo),
1663
+ }),
1664
+ sync: vi
1665
+ .fn<(opts: SyncOptions) => Promise<SyncResult>>()
1666
+ .mockResolvedValueOnce(
1667
+ defaultSyncResult({
1668
+ filesDownloaded: 1,
1669
+ changedPaths: ["docs/readme.txt"],
1670
+ } as Partial<SyncResult>),
1671
+ )
1672
+ .mockResolvedValueOnce(
1673
+ defaultSyncResult({
1674
+ filesTombstoned: 1,
1675
+ changedPaths: ["knowledge/old.md"],
1676
+ } as Partial<SyncResult>),
1677
+ ),
1678
+ reindex: vi.fn(() => ({ status: 0 })),
1679
+ qmdReindex,
1680
+ } as Partial<RunnerDeps>);
1681
+
1682
+ const code = await runRunner(["--companies", "--hq-root", "/tmp/fake-hq"], deps);
1683
+
1684
+ expect(code).toBe(0);
1685
+ expect(qmdReindex).toHaveBeenCalledTimes(1);
1686
+ expect(qmdReindex).toHaveBeenCalledWith(
1687
+ "/tmp/fake-hq",
1688
+ expect.objectContaining({
1689
+ changedPaths: ["companies/beta/knowledge/old.md"],
1690
+ forceCollectionRefresh: true,
1691
+ }),
1692
+ );
1693
+ });
1694
+
1605
1695
  it("collects company-level errors into the all-complete errors array", async () => {
1606
1696
  const slugs: Record<string, string> = { cmp_a: "acme", cmp_b: "beta" };
1607
1697
  const deps = makeDeps({
@@ -104,6 +104,9 @@ import { HQ_CLOUD_VERSION } from "../version.js";
104
104
  import { collectAndSendTelemetry } from "../telemetry.js";
105
105
  import { collectAndSendSkillTelemetry } from "../skill-telemetry.js";
106
106
  import { reindexAfterSync } from "../qmd-reindex.js";
107
+ import type { ReindexOptions as QmdReindexOptions } from "../qmd-reindex.js";
108
+ import { reindex as defaultReindex } from "../cli/reindex.js";
109
+ import type { ReindexOptions, ReindexResult } from "../cli/reindex.js";
107
110
  import { pruneConflictIndex } from "../lib/conflict-index.js";
108
111
  import { materializeCodexAgents } from "../agent-codex-instructions.js";
109
112
  import { getOrCreateMachineId } from "../lib/machine-id.js";
@@ -577,6 +580,13 @@ export interface RunnerDeps {
577
580
  createVaultClient?: (config: VaultServiceConfig) => VaultClientSurface;
578
581
  /** Sync function. Defaults to `cli/sync.sync`. */
579
582
  sync?: (options: SyncOptions) => Promise<SyncResult>;
583
+ /** Native post-fanout reindex function. Defaults to `cli/reindex.reindex`. */
584
+ reindex?: (options: ReindexOptions) => ReindexResult;
585
+ /** QMD post-sync reindex function. Defaults to `qmd-reindex.reindexAfterSync`. */
586
+ qmdReindex?: (
587
+ hqRoot: string,
588
+ options: QmdReindexOptions,
589
+ ) => ReturnType<typeof reindexAfterSync>;
580
590
  /** Internal: set when runRunner is invoked under the per-root operation lock. */
581
591
  operationLockAlreadyHeld?: boolean;
582
592
  /** Share function (push phase). Defaults to `cli/share.share`. */
@@ -622,6 +632,11 @@ function defaultGetIdTokenClaims(): IdTokenClaims | null {
622
632
  return decodeJwtClaims(tokens.idToken);
623
633
  }
624
634
 
635
+ function isKnowledgeMarkdownPath(relPath: string): boolean {
636
+ const normalized = relPath.split(path.sep).join("/");
637
+ return /^companies\/[^/]+\/knowledge\/.+\.md$/i.test(normalized);
638
+ }
639
+
625
640
  /**
626
641
  * Best-effort: claim any email-keyed pending invites that were sent before
627
642
  * this user had a person entity. Mirrors the installer's vault-handoff flow.
@@ -1200,6 +1215,23 @@ export async function runRunner(
1200
1215
  const { errors, allConflicts } = fanout;
1201
1216
  const rollup = rollupAllComplete(plan, fanout.stateByCompany);
1202
1217
 
1218
+ if (rollup.needsReindex) {
1219
+ try {
1220
+ (deps.reindex ?? defaultReindex)({
1221
+ repoRoot: parsed.hqRoot,
1222
+ ...(deps.operationLockAlreadyHeld === true ? { skipLock: true } : {}),
1223
+ });
1224
+ } catch (err) {
1225
+ reportDiagnostic({
1226
+ component: "native-reindex",
1227
+ event: "runner.native_reindex.failed",
1228
+ message: "post-fanout native reindex failed",
1229
+ err,
1230
+ context: { hqRoot: parsed.hqRoot },
1231
+ });
1232
+ }
1233
+ }
1234
+
1203
1235
  // Fire telemetry collector before the all-complete emit so the cursor at
1204
1236
  // `~/.hq/telemetry-cursor.json` is consistent with what the menubar sees.
1205
1237
  await awaitTelemetryWithTimeout(
@@ -1250,12 +1282,12 @@ export async function runRunner(
1250
1282
  // pulled in (nothing to reindex otherwise) and not explicitly disabled.
1251
1283
  // Self-contained: shells out to the global `qmd` binary, no dependency on
1252
1284
  // any (possibly stale) script inside the synced HQ tree. See qmd-reindex.ts.
1253
- if (
1254
- rollup.totalDownloaded > 0 &&
1255
- process.env.HQ_QMD_REINDEX_ON_SYNC !== "0"
1256
- ) {
1285
+ const qmdChangedPaths = rollup.changedPaths.filter(isKnowledgeMarkdownPath);
1286
+ if (qmdChangedPaths.length > 0 && process.env.HQ_QMD_REINDEX_ON_SYNC !== "0") {
1257
1287
  try {
1258
- reindexAfterSync(parsed.hqRoot, {
1288
+ (deps.qmdReindex ?? reindexAfterSync)(parsed.hqRoot, {
1289
+ changedPaths: qmdChangedPaths,
1290
+ forceCollectionRefresh: true,
1259
1291
  log: ({ event, message, err, context }) =>
1260
1292
  reportDiagnostic({
1261
1293
  component: "qmd-reindex",