@mulmoclaude/core 0.28.0 → 0.29.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/assets/helps/collection-skills.md +4 -2
- package/dist/collection/core/ontologyGraph.d.ts +6 -2
- package/dist/collection/index.cjs.map +1 -1
- package/dist/collection/index.js.map +1 -1
- package/dist/collection/registry/server/index.cjs +2 -2
- package/dist/collection/registry/server/index.js +2 -2
- package/dist/collection/server/backendAvailability.d.ts +5 -0
- package/dist/collection/server/index.cjs +4 -2
- package/dist/collection/server/index.d.ts +1 -0
- package/dist/collection/server/index.js +3 -3
- package/dist/collection/server/manageTool.d.ts +4 -0
- package/dist/collection/server/schemaDocs.d.ts +21 -0
- package/dist/collection/server/store.d.ts +37 -0
- package/dist/collection/server/watchFs.d.ts +17 -0
- package/dist/collection-watchers/index.cjs +113 -202
- package/dist/collection-watchers/index.cjs.map +1 -1
- package/dist/collection-watchers/index.d.ts +1 -1
- package/dist/collection-watchers/index.js +113 -201
- package/dist/collection-watchers/index.js.map +1 -1
- package/dist/collection-watchers/watcher.d.ts +8 -13
- package/dist/{discovery-BVdCgBFN.js → discovery-BbsJwVEq.js} +109 -8
- package/dist/discovery-BbsJwVEq.js.map +1 -0
- package/dist/{discovery-BKovdRpZ.cjs → discovery-Bklck7Ck.cjs} +119 -6
- package/dist/discovery-Bklck7Ck.cjs.map +1 -0
- package/dist/feeds/server/index.cjs +2 -2
- package/dist/feeds/server/index.js +2 -2
- package/dist/google/index.cjs +1 -1
- package/dist/google/index.js +1 -1
- package/dist/remote-view/index.cjs +8 -0
- package/dist/remote-view/index.cjs.map +1 -1
- package/dist/remote-view/index.d.ts +7 -0
- package/dist/remote-view/index.js +8 -1
- package/dist/remote-view/index.js.map +1 -1
- package/dist/{server-rRQkNBvO.cjs → server-CghbYZFY.cjs} +179 -14
- package/dist/server-CghbYZFY.cjs.map +1 -0
- package/dist/{server-B8mvfZSF.js → server-DlG6ydHO.js} +179 -14
- package/dist/server-DlG6ydHO.js.map +1 -0
- package/dist/whisper/client.cjs.map +1 -1
- package/dist/whisper/client.js.map +1 -1
- package/package.json +1 -1
- package/dist/discovery-BKovdRpZ.cjs.map +0 -1
- package/dist/discovery-BVdCgBFN.js.map +0 -1
- package/dist/server-B8mvfZSF.js.map +0 -1
- package/dist/server-rRQkNBvO.cjs.map +0 -1
|
@@ -640,6 +640,18 @@ ${dataJson}
|
|
|
640
640
|
${templateText}`;
|
|
641
641
|
}
|
|
642
642
|
//#endregion
|
|
643
|
+
//#region src/collection/server/backendAvailability.ts
|
|
644
|
+
/** Thrown by a store when its engine or session cannot serve the request. */
|
|
645
|
+
var BackendUnavailableError = class extends Error {
|
|
646
|
+
constructor(message) {
|
|
647
|
+
super(message);
|
|
648
|
+
this.name = "BackendUnavailableError";
|
|
649
|
+
}
|
|
650
|
+
};
|
|
651
|
+
function isBackendUnavailable(err) {
|
|
652
|
+
return err instanceof BackendUnavailableError;
|
|
653
|
+
}
|
|
654
|
+
//#endregion
|
|
643
655
|
//#region src/collection/core/queryZ.ts
|
|
644
656
|
/** Result-column aliases double as SQL identifiers and JSON keys — keep
|
|
645
657
|
* them to a conservative identifier charset so neither side needs
|
|
@@ -1050,7 +1062,7 @@ async function duckDbInstance() {
|
|
|
1050
1062
|
return await instancePromise;
|
|
1051
1063
|
} catch (err) {
|
|
1052
1064
|
instancePromise = null;
|
|
1053
|
-
throw new
|
|
1065
|
+
throw new BackendUnavailableError(`DuckDB is unavailable on this host (@duckdb/node-api failed to load: ${String(err)}) — dataSource collections cannot be read`);
|
|
1054
1066
|
}
|
|
1055
1067
|
}
|
|
1056
1068
|
async function queryCsv(sql, params) {
|
|
@@ -1135,6 +1147,89 @@ async function csvRunQuery(absPath, primaryKey, query, workspaceRoot) {
|
|
|
1135
1147
|
return (await queryCsv(sql, [utf8Path, ...params])).map((row) => Object.fromEntries(Object.entries(row).map(([key, value]) => [key, normalizeCsvValue(value)])));
|
|
1136
1148
|
}
|
|
1137
1149
|
//#endregion
|
|
1150
|
+
//#region src/collection/server/watchFs.ts
|
|
1151
|
+
/** An atomic file replace (editor save, `mv` over the target) surfaces as
|
|
1152
|
+
* 2-3 events. Collapse them so one user action reports one change. */
|
|
1153
|
+
var REPLACE_DEBOUNCE_MS = 300;
|
|
1154
|
+
/** The path to hand `watch()`, with Windows 8.3 short names resolved away.
|
|
1155
|
+
*
|
|
1156
|
+
* ReadDirectoryChangesW reports filenames against the LONG path, but a watch
|
|
1157
|
+
* opened on a short path (`C:\Users\RUNNER~1\…` — what `os.tmpdir()` returns
|
|
1158
|
+
* on GitHub's Windows runners) keeps the short form. libuv's
|
|
1159
|
+
* `assert(!_wcsnicmp(filename, dir, dirlen))` in `src/win/fs-event.c` then
|
|
1160
|
+
* aborts the PROCESS on the first event — a native assert, so neither
|
|
1161
|
+
* `watcher.on("error")` nor a try/catch can contain it.
|
|
1162
|
+
*
|
|
1163
|
+
* POSIX is deliberately left alone: `realpath` there also collapses symlinks
|
|
1164
|
+
* (`/var` → `/private/var` on macOS), which we neither need nor want to
|
|
1165
|
+
* change. A failure falls back to the original path — worst case we are no
|
|
1166
|
+
* worse off than before. */
|
|
1167
|
+
function watchablePath(dir) {
|
|
1168
|
+
if (process.platform !== "win32") return dir;
|
|
1169
|
+
try {
|
|
1170
|
+
return node_fs.realpathSync.native(dir);
|
|
1171
|
+
} catch {
|
|
1172
|
+
return dir;
|
|
1173
|
+
}
|
|
1174
|
+
}
|
|
1175
|
+
/** Watch `dir`, reporting each accepted filename. `accept` decides what is
|
|
1176
|
+
* noise; a null filename always passes (the platform didn't tell us which
|
|
1177
|
+
* file, so the caller must assume the worst). */
|
|
1178
|
+
async function watchDirectory(dir, accept, onHit) {
|
|
1179
|
+
try {
|
|
1180
|
+
await (0, node_fs_promises.mkdir)(dir, { recursive: true });
|
|
1181
|
+
const watcher = (0, node_fs.watch)(watchablePath(dir), { persistent: false }, (_eventType, rawFilename) => {
|
|
1182
|
+
const filename = rawFilename === null ? null : String(rawFilename);
|
|
1183
|
+
if (filename !== null && !accept(filename)) return;
|
|
1184
|
+
onHit(filename);
|
|
1185
|
+
});
|
|
1186
|
+
watcher.on("error", (err) => {
|
|
1187
|
+
log.warn("collections", "fs watch error", {
|
|
1188
|
+
dir,
|
|
1189
|
+
error: String(err)
|
|
1190
|
+
});
|
|
1191
|
+
});
|
|
1192
|
+
return { close: () => watcher.close() };
|
|
1193
|
+
} catch (err) {
|
|
1194
|
+
log.warn("collections", "fs watch start failed", {
|
|
1195
|
+
dir,
|
|
1196
|
+
error: String(err)
|
|
1197
|
+
});
|
|
1198
|
+
return null;
|
|
1199
|
+
}
|
|
1200
|
+
}
|
|
1201
|
+
/** Watch the single file `absPath` by watching its PARENT directory, so an
|
|
1202
|
+
* atomic replace can't strand the watch on a dead inode. `alsoAccept`
|
|
1203
|
+
* widens the filter beyond the exact basename (sqlite's `-wal`/`-journal`
|
|
1204
|
+
* sidecars). Reports are debounced: one replace, one call. */
|
|
1205
|
+
async function watchSingleFile(absPath, alsoAccept, onChange) {
|
|
1206
|
+
const dir = node_path.default.dirname(absPath);
|
|
1207
|
+
const base = node_path.default.basename(absPath);
|
|
1208
|
+
let timer = null;
|
|
1209
|
+
const fire = () => {
|
|
1210
|
+
if (timer) clearTimeout(timer);
|
|
1211
|
+
timer = setTimeout(() => {
|
|
1212
|
+
timer = null;
|
|
1213
|
+
onChange();
|
|
1214
|
+
}, REPLACE_DEBOUNCE_MS);
|
|
1215
|
+
timer.unref?.();
|
|
1216
|
+
};
|
|
1217
|
+
const handle = await watchDirectory(dir, (filename) => filename === base || alsoAccept(base, filename), fire);
|
|
1218
|
+
if (!handle) return null;
|
|
1219
|
+
return { close: () => {
|
|
1220
|
+
if (timer) clearTimeout(timer);
|
|
1221
|
+
timer = null;
|
|
1222
|
+
handle.close();
|
|
1223
|
+
} };
|
|
1224
|
+
}
|
|
1225
|
+
/** An `FsWatchHandle` as a bare unsubscribe — `null` straight through, so an
|
|
1226
|
+
* unarmed watch stays distinguishable from an armed one. Lives here rather
|
|
1227
|
+
* than beside the store contract so both `store.ts` and the backends it
|
|
1228
|
+
* registers can reach it without importing each other. */
|
|
1229
|
+
function closerFor(handle) {
|
|
1230
|
+
return handle === null ? null : () => handle.close();
|
|
1231
|
+
}
|
|
1232
|
+
//#endregion
|
|
1138
1233
|
//#region src/collection/server/storePage.ts
|
|
1139
1234
|
/** Project `fields` (+ the primary key, always) out of each record. Thin
|
|
1140
1235
|
* server-typed alias over the shared isomorphic `projectRecordFields`
|
|
@@ -1162,7 +1257,7 @@ var sqliteModule = null;
|
|
|
1162
1257
|
function loadSqlite() {
|
|
1163
1258
|
sqliteModule ??= import("node:sqlite").then((mod) => mod, (err) => {
|
|
1164
1259
|
sqliteModule = null;
|
|
1165
|
-
throw new
|
|
1260
|
+
throw new BackendUnavailableError(`sqlite storage needs the node:sqlite module (Node.js >= 22.5) — this runtime cannot load it: ${String(err)}`);
|
|
1166
1261
|
});
|
|
1167
1262
|
return sqliteModule;
|
|
1168
1263
|
}
|
|
@@ -1399,7 +1494,8 @@ function sqliteStoreFor(collection, opts) {
|
|
|
1399
1494
|
delete: (itemId) => sqliteDelete(file, itemId, {
|
|
1400
1495
|
workspaceRoot: root(),
|
|
1401
1496
|
slug
|
|
1402
|
-
})
|
|
1497
|
+
}),
|
|
1498
|
+
watch: async (onChange) => closerFor(await watchSingleFile(file, (base, name) => name.startsWith(base), () => onChange({ kind: "collection" })))
|
|
1403
1499
|
};
|
|
1404
1500
|
}
|
|
1405
1501
|
//#endregion
|
|
@@ -1446,7 +1542,8 @@ function csvStoreFor(collection, opts) {
|
|
|
1446
1542
|
list: () => listAll().then((result) => result.items),
|
|
1447
1543
|
page: (pageOpts = {}) => listAll().then((result) => pageFromFullRead(result.items, pageOpts, key, result.truncated)),
|
|
1448
1544
|
read: (itemId) => file === void 0 ? Promise.resolve(null) : csvRead(file, key, itemId, opts.workspaceRoot),
|
|
1449
|
-
query: (query) => file === void 0 ? Promise.resolve([]) : csvRunQuery(file, key, query, opts.workspaceRoot)
|
|
1545
|
+
query: (query) => file === void 0 ? Promise.resolve([]) : csvRunQuery(file, key, query, opts.workspaceRoot),
|
|
1546
|
+
...file === void 0 ? {} : { watch: async (onChange) => closerFor(await watchSingleFile(file, () => false, () => onChange({ kind: "collection" }))) }
|
|
1450
1547
|
};
|
|
1451
1548
|
}
|
|
1452
1549
|
/** The classic file store over `<dataDir>/<itemId>.json` records. */
|
|
@@ -1469,7 +1566,11 @@ function fileStoreFor(collection, opts) {
|
|
|
1469
1566
|
...ioOpts,
|
|
1470
1567
|
refuseOverwrite: writeOpts.refuseOverwrite
|
|
1471
1568
|
}),
|
|
1472
|
-
delete: (itemId) => deleteItem(collection.dataDir, itemId, ioOpts)
|
|
1569
|
+
delete: (itemId) => deleteItem(collection.dataDir, itemId, ioOpts),
|
|
1570
|
+
watch: async (onChange) => closerFor(await watchDirectory(collection.dataDir, (name) => name.endsWith(".json") && !name.startsWith("."), (filename) => onChange(filename === null ? { kind: "collection" } : {
|
|
1571
|
+
kind: "item",
|
|
1572
|
+
itemId: filename.slice(0, -5)
|
|
1573
|
+
})))
|
|
1473
1574
|
};
|
|
1474
1575
|
}
|
|
1475
1576
|
var storeFactories = /* @__PURE__ */ new Map([
|
|
@@ -2521,6 +2622,12 @@ function toDetail(collection) {
|
|
|
2521
2622
|
};
|
|
2522
2623
|
}
|
|
2523
2624
|
//#endregion
|
|
2625
|
+
Object.defineProperty(exports, "BackendUnavailableError", {
|
|
2626
|
+
enumerable: true,
|
|
2627
|
+
get: function() {
|
|
2628
|
+
return BackendUnavailableError;
|
|
2629
|
+
}
|
|
2630
|
+
});
|
|
2524
2631
|
Object.defineProperty(exports, "CollectionQueryZ", {
|
|
2525
2632
|
enumerable: true,
|
|
2526
2633
|
get: function() {
|
|
@@ -2671,6 +2778,12 @@ Object.defineProperty(exports, "getWorkspaceRoot", {
|
|
|
2671
2778
|
return getWorkspaceRoot;
|
|
2672
2779
|
}
|
|
2673
2780
|
});
|
|
2781
|
+
Object.defineProperty(exports, "isBackendUnavailable", {
|
|
2782
|
+
enumerable: true,
|
|
2783
|
+
get: function() {
|
|
2784
|
+
return isBackendUnavailable;
|
|
2785
|
+
}
|
|
2786
|
+
});
|
|
2674
2787
|
Object.defineProperty(exports, "isContainedInRoot", {
|
|
2675
2788
|
enumerable: true,
|
|
2676
2789
|
get: function() {
|
|
@@ -2864,4 +2977,4 @@ Object.defineProperty(exports, "writeItem", {
|
|
|
2864
2977
|
}
|
|
2865
2978
|
});
|
|
2866
2979
|
|
|
2867
|
-
//# sourceMappingURL=discovery-
|
|
2980
|
+
//# sourceMappingURL=discovery-Bklck7Ck.cjs.map
|