@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.
- package/dist/bin/sync-runner-company.d.ts.map +1 -1
- package/dist/bin/sync-runner-company.js +15 -0
- package/dist/bin/sync-runner-company.js.map +1 -1
- package/dist/bin/sync-runner-rollup.d.ts +7 -0
- package/dist/bin/sync-runner-rollup.d.ts.map +1 -1
- package/dist/bin/sync-runner-rollup.js +15 -0
- package/dist/bin/sync-runner-rollup.js.map +1 -1
- package/dist/bin/sync-runner.d.ts +7 -0
- package/dist/bin/sync-runner.d.ts.map +1 -1
- package/dist/bin/sync-runner.js +27 -3
- package/dist/bin/sync-runner.js.map +1 -1
- package/dist/bin/sync-runner.test.js +73 -0
- package/dist/bin/sync-runner.test.js.map +1 -1
- package/dist/cli/reindex.d.ts.map +1 -1
- package/dist/cli/reindex.js +38 -0
- package/dist/cli/reindex.js.map +1 -1
- package/dist/cli/reindex.test.js +77 -0
- package/dist/cli/reindex.test.js.map +1 -1
- package/dist/cli/share.js +15 -2
- package/dist/cli/share.js.map +1 -1
- package/dist/cli/share.test.js +39 -0
- package/dist/cli/share.test.js.map +1 -1
- package/dist/cli/sync.d.ts +22 -0
- package/dist/cli/sync.d.ts.map +1 -1
- package/dist/cli/sync.js +60 -1
- package/dist/cli/sync.js.map +1 -1
- package/dist/cli/sync.test.js +88 -0
- package/dist/cli/sync.test.js.map +1 -1
- package/dist/qmd-reindex.d.ts +14 -0
- package/dist/qmd-reindex.d.ts.map +1 -1
- package/dist/qmd-reindex.js +93 -19
- package/dist/qmd-reindex.js.map +1 -1
- package/dist/qmd-reindex.test.js +47 -0
- package/dist/qmd-reindex.test.js.map +1 -1
- package/package.json +1 -1
- package/src/bin/sync-runner-company.ts +21 -0
- package/src/bin/sync-runner-rollup.ts +23 -0
- package/src/bin/sync-runner.test.ts +90 -0
- package/src/bin/sync-runner.ts +37 -5
- package/src/cli/reindex.test.ts +92 -0
- package/src/cli/reindex.ts +35 -0
- package/src/cli/share.test.ts +46 -0
- package/src/cli/share.ts +14 -2
- package/src/cli/sync.test.ts +105 -0
- package/src/cli/sync.ts +101 -1
- package/src/qmd-reindex.test.ts +50 -0
- package/src/qmd-reindex.ts +124 -18
package/src/qmd-reindex.ts
CHANGED
|
@@ -45,9 +45,24 @@ const defaultExec: QmdExec = (args) => {
|
|
|
45
45
|
return { status: res.status, stdout: res.stdout ?? "" };
|
|
46
46
|
};
|
|
47
47
|
|
|
48
|
+
const DEFAULT_CHANGED_PATH_DEBOUNCE_MS = 60_000;
|
|
49
|
+
|
|
48
50
|
export interface ReindexOptions {
|
|
49
51
|
/** Rebuild embeddings too (slow). Default false — lexical-only. */
|
|
50
52
|
embed?: boolean;
|
|
53
|
+
/**
|
|
54
|
+
* HQ-relative paths changed by sync. When omitted, preserves the historical
|
|
55
|
+
* behavior and runs QMD for any sync caller that invokes this function.
|
|
56
|
+
*/
|
|
57
|
+
changedPaths?: string[];
|
|
58
|
+
/** Force a collection registration refresh even when content is not dirty. */
|
|
59
|
+
forceCollectionRefresh?: boolean;
|
|
60
|
+
/** Delay dirty updates by this many ms while keeping a persistent marker. */
|
|
61
|
+
debounceMs?: number;
|
|
62
|
+
/** Clock override for deterministic debounce tests. */
|
|
63
|
+
nowMs?: number;
|
|
64
|
+
/** State file override for tests. */
|
|
65
|
+
statePath?: string;
|
|
51
66
|
/** Command runner override for tests. */
|
|
52
67
|
exec?: QmdExec;
|
|
53
68
|
/** `existsSync` override for tests. */
|
|
@@ -74,15 +89,42 @@ export interface ReindexOptions {
|
|
|
74
89
|
export function reindexAfterSync(
|
|
75
90
|
hqRoot: string,
|
|
76
91
|
opts: ReindexOptions = {},
|
|
77
|
-
): {
|
|
92
|
+
): {
|
|
93
|
+
qmdAvailable: boolean;
|
|
94
|
+
collectionsAdded: string[];
|
|
95
|
+
updated: boolean;
|
|
96
|
+
embedded: boolean;
|
|
97
|
+
pendingDirty: boolean;
|
|
98
|
+
} {
|
|
78
99
|
const exec = opts.exec ?? defaultExec;
|
|
79
100
|
const existsSync = opts.existsSync ?? fs.existsSync;
|
|
80
|
-
const result = {
|
|
101
|
+
const result = {
|
|
102
|
+
qmdAvailable: false,
|
|
103
|
+
collectionsAdded: [] as string[],
|
|
104
|
+
updated: false,
|
|
105
|
+
embedded: false,
|
|
106
|
+
pendingDirty: false,
|
|
107
|
+
};
|
|
81
108
|
|
|
82
109
|
try {
|
|
83
110
|
// Guard: only operate on a real HQ tree.
|
|
84
111
|
if (!existsSync(path.join(hqRoot, "core", "core.yaml"))) return result;
|
|
85
112
|
|
|
113
|
+
const statePath = opts.statePath ?? path.join(hqRoot, ".hq", "qmd-reindex-state.json");
|
|
114
|
+
const state = readState(statePath);
|
|
115
|
+
const changedPaths = opts.changedPaths;
|
|
116
|
+
const dirtyFromChanges =
|
|
117
|
+
changedPaths === undefined ||
|
|
118
|
+
changedPaths.some(isKnowledgeMarkdownPath);
|
|
119
|
+
const registrationMayBeStale =
|
|
120
|
+
opts.forceCollectionRefresh === true ||
|
|
121
|
+
changedPaths === undefined ||
|
|
122
|
+
dirtyFromChanges;
|
|
123
|
+
const pendingDirty = state.pendingDirty === true;
|
|
124
|
+
if (!dirtyFromChanges && !registrationMayBeStale && !pendingDirty) {
|
|
125
|
+
return result;
|
|
126
|
+
}
|
|
127
|
+
|
|
86
128
|
// Guard: qmd must be installed. `qmd collection list` doubles as the
|
|
87
129
|
// availability probe AND the source for which collections already exist.
|
|
88
130
|
const list = exec(["collection", "list"]);
|
|
@@ -91,26 +133,62 @@ export function reindexAfterSync(
|
|
|
91
133
|
const existingCollections = list.stdout;
|
|
92
134
|
|
|
93
135
|
// 1. Auto-register missing company knowledge collections.
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
136
|
+
if (registrationMayBeStale) {
|
|
137
|
+
const companiesDir = path.join(hqRoot, "companies");
|
|
138
|
+
const slugs = (opts.readCompanies ?? defaultReadCompanies)(companiesDir);
|
|
139
|
+
for (const slug of slugs) {
|
|
140
|
+
const knowledgeDir = path.join(companiesDir, slug, "knowledge");
|
|
141
|
+
if (!existsSync(knowledgeDir)) continue;
|
|
142
|
+
const hasMd = (opts.hasIndexableMarkdown ?? defaultHasIndexableMarkdown)(knowledgeDir);
|
|
143
|
+
if (!hasMd) continue;
|
|
144
|
+
// Already registered? qmd collection URIs look like `qmd://<slug>/`.
|
|
145
|
+
if (existingCollections.includes(`qmd://${slug}/`)) continue;
|
|
146
|
+
|
|
147
|
+
const add = exec(["collection", "add", knowledgeDir, "--name", slug, "--mask", "**/*.md"]);
|
|
148
|
+
if (add.status === 0) {
|
|
149
|
+
exec(["context", "add", `qmd://${slug}`, `Knowledge base for ${slug}.`]);
|
|
150
|
+
result.collectionsAdded.push(slug);
|
|
151
|
+
}
|
|
108
152
|
}
|
|
109
153
|
}
|
|
110
154
|
|
|
111
155
|
// 2. Incremental lexical reindex.
|
|
112
|
-
const
|
|
113
|
-
|
|
156
|
+
const shouldUpdate = dirtyFromChanges || pendingDirty;
|
|
157
|
+
if (shouldUpdate) {
|
|
158
|
+
const nowMs = opts.nowMs ?? Date.now();
|
|
159
|
+
const debounceMs =
|
|
160
|
+
opts.debounceMs ??
|
|
161
|
+
(changedPaths === undefined ? 0 : DEFAULT_CHANGED_PATH_DEBOUNCE_MS);
|
|
162
|
+
const pendingSinceMs =
|
|
163
|
+
pendingDirty && typeof state.pendingSinceMs === "number"
|
|
164
|
+
? state.pendingSinceMs
|
|
165
|
+
: nowMs;
|
|
166
|
+
if (debounceMs > 0 && nowMs - pendingSinceMs < debounceMs) {
|
|
167
|
+
writeState(statePath, {
|
|
168
|
+
...state,
|
|
169
|
+
pendingDirty: true,
|
|
170
|
+
pendingSinceMs,
|
|
171
|
+
});
|
|
172
|
+
result.pendingDirty = true;
|
|
173
|
+
return result;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
const update = exec(["update"]);
|
|
177
|
+
result.updated = update.status === 0;
|
|
178
|
+
if (result.updated) {
|
|
179
|
+
writeState(statePath, {
|
|
180
|
+
pendingDirty: false,
|
|
181
|
+
lastSuccessMs: nowMs,
|
|
182
|
+
});
|
|
183
|
+
} else {
|
|
184
|
+
writeState(statePath, {
|
|
185
|
+
...state,
|
|
186
|
+
pendingDirty: true,
|
|
187
|
+
pendingSinceMs,
|
|
188
|
+
});
|
|
189
|
+
result.pendingDirty = true;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
114
192
|
|
|
115
193
|
// 3. Embeddings only on explicit request.
|
|
116
194
|
if (opts.embed) {
|
|
@@ -134,6 +212,34 @@ export function reindexAfterSync(
|
|
|
134
212
|
return result;
|
|
135
213
|
}
|
|
136
214
|
|
|
215
|
+
interface QmdReindexState {
|
|
216
|
+
pendingDirty?: boolean;
|
|
217
|
+
pendingSinceMs?: number;
|
|
218
|
+
lastSuccessMs?: number;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
function readState(statePath: string): QmdReindexState {
|
|
222
|
+
try {
|
|
223
|
+
return JSON.parse(fs.readFileSync(statePath, "utf8")) as QmdReindexState;
|
|
224
|
+
} catch {
|
|
225
|
+
return {};
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
function writeState(statePath: string, state: QmdReindexState): void {
|
|
230
|
+
try {
|
|
231
|
+
fs.mkdirSync(path.dirname(statePath), { recursive: true });
|
|
232
|
+
fs.writeFileSync(statePath, JSON.stringify(state, null, 2) + "\n");
|
|
233
|
+
} catch {
|
|
234
|
+
// State is an optimization/guarantee aid; QMD failures must not fail sync.
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
function isKnowledgeMarkdownPath(relPath: string): boolean {
|
|
239
|
+
const normalized = relPath.split(path.sep).join("/");
|
|
240
|
+
return /^companies\/[^/]+\/knowledge\/.+\.md$/i.test(normalized);
|
|
241
|
+
}
|
|
242
|
+
|
|
137
243
|
function defaultReadCompanies(companiesDir: string): string[] {
|
|
138
244
|
try {
|
|
139
245
|
return fs
|