@danielsimonjr/memoryjs 2.2.0 → 2.4.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/README.md +1 -1
- package/dist/cli/index.js +555 -3
- package/dist/cli/index.js.map +1 -1
- package/dist/index.cjs +24 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +24 -1
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# MemoryJS
|
|
2
2
|
|
|
3
|
-
[](https://github.com/danielsimonjr/memoryjs)
|
|
4
4
|
[](https://www.npmjs.com/package/@danielsimonjr/memoryjs)
|
|
5
5
|
[](LICENSE)
|
|
6
6
|
[](https://www.typescriptlang.org/)
|
package/dist/cli/index.js
CHANGED
|
@@ -959,12 +959,34 @@ var init_indexes = __esm({
|
|
|
959
959
|
});
|
|
960
960
|
|
|
961
961
|
// src/utils/searchCache.ts
|
|
962
|
+
var searchCache_exports = {};
|
|
963
|
+
__export(searchCache_exports, {
|
|
964
|
+
SearchCache: () => SearchCache,
|
|
965
|
+
cleanupAllCaches: () => cleanupAllCaches,
|
|
966
|
+
clearAllSearchCaches: () => clearAllSearchCaches,
|
|
967
|
+
getAllCacheStats: () => getAllCacheStats,
|
|
968
|
+
searchCaches: () => searchCaches
|
|
969
|
+
});
|
|
962
970
|
function clearAllSearchCaches() {
|
|
963
971
|
searchCaches.basic.clear();
|
|
964
972
|
searchCaches.ranked.clear();
|
|
965
973
|
searchCaches.boolean.clear();
|
|
966
974
|
searchCaches.fuzzy.clear();
|
|
967
975
|
}
|
|
976
|
+
function getAllCacheStats() {
|
|
977
|
+
return {
|
|
978
|
+
basic: searchCaches.basic.getStats(),
|
|
979
|
+
ranked: searchCaches.ranked.getStats(),
|
|
980
|
+
boolean: searchCaches.boolean.getStats(),
|
|
981
|
+
fuzzy: searchCaches.fuzzy.getStats()
|
|
982
|
+
};
|
|
983
|
+
}
|
|
984
|
+
function cleanupAllCaches() {
|
|
985
|
+
searchCaches.basic.cleanupExpired();
|
|
986
|
+
searchCaches.ranked.cleanupExpired();
|
|
987
|
+
searchCaches.boolean.cleanupExpired();
|
|
988
|
+
searchCaches.fuzzy.cleanupExpired();
|
|
989
|
+
}
|
|
968
990
|
var SearchCache, searchCaches;
|
|
969
991
|
var init_searchCache = __esm({
|
|
970
992
|
"src/utils/searchCache.ts"() {
|
|
@@ -6730,7 +6752,30 @@ var init_GraphStorage = __esm({
|
|
|
6730
6752
|
// ArtifactEntity extension (types/artifact.ts)
|
|
6731
6753
|
"artifactType",
|
|
6732
6754
|
"toolName",
|
|
6733
|
-
"shortId"
|
|
6755
|
+
"shortId",
|
|
6756
|
+
// v2.1.0 subclass-manager record fields (sibling to the v2.1.1
|
|
6757
|
+
// UpdateEntitySchema.passthrough fix — same root cause: subclass managers
|
|
6758
|
+
// attach domain records that the persistence allowlist must also admit,
|
|
6759
|
+
// otherwise the records are silently dropped on save and the managers'
|
|
6760
|
+
// list/match/get operations return empty on next load).
|
|
6761
|
+
"heuristicRecord",
|
|
6762
|
+
// HeuristicEntity
|
|
6763
|
+
"decisionRecord",
|
|
6764
|
+
// DecisionEntity (includes nested lifecycle)
|
|
6765
|
+
"exclusionRule",
|
|
6766
|
+
// ExclusionEntity
|
|
6767
|
+
"projectContextRecord",
|
|
6768
|
+
// ProjectContextEntity
|
|
6769
|
+
"toolAffordanceRecord",
|
|
6770
|
+
// ToolAffordanceEntity
|
|
6771
|
+
"prospectiveRecord",
|
|
6772
|
+
// ProspectiveEntity
|
|
6773
|
+
"failureRecord",
|
|
6774
|
+
// FailureEntity
|
|
6775
|
+
"planRecord",
|
|
6776
|
+
// PlanEntity
|
|
6777
|
+
"reflectionRecord"
|
|
6778
|
+
// ReflectionEntity
|
|
6734
6779
|
];
|
|
6735
6780
|
GraphStorage = class {
|
|
6736
6781
|
/**
|
|
@@ -35740,6 +35785,105 @@ var init_inspect = __esm({
|
|
|
35740
35785
|
}
|
|
35741
35786
|
});
|
|
35742
35787
|
|
|
35788
|
+
// src/cli/commands/check.ts
|
|
35789
|
+
var check_exports = {};
|
|
35790
|
+
__export(check_exports, {
|
|
35791
|
+
applyFixes: () => applyFixes,
|
|
35792
|
+
detectIssues: () => detectIssues,
|
|
35793
|
+
registerCheckCommand: () => registerCheckCommand
|
|
35794
|
+
});
|
|
35795
|
+
async function detectIssues(ctx) {
|
|
35796
|
+
const graph = await ctx.storage.loadGraph();
|
|
35797
|
+
const names = new Set(graph.entities.map((e) => e.name));
|
|
35798
|
+
const orphans = [];
|
|
35799
|
+
for (const r of graph.relations) {
|
|
35800
|
+
const fromMissing = !names.has(r.from);
|
|
35801
|
+
const toMissing = !names.has(r.to);
|
|
35802
|
+
if (fromMissing || toMissing) {
|
|
35803
|
+
orphans.push({
|
|
35804
|
+
from: r.from,
|
|
35805
|
+
to: r.to,
|
|
35806
|
+
relationType: r.relationType,
|
|
35807
|
+
reason: fromMissing && toMissing ? "both-missing" : fromMissing ? "from-missing" : "to-missing"
|
|
35808
|
+
});
|
|
35809
|
+
}
|
|
35810
|
+
}
|
|
35811
|
+
const missing = [];
|
|
35812
|
+
const cycles = [];
|
|
35813
|
+
const byName = /* @__PURE__ */ new Map();
|
|
35814
|
+
for (const e of graph.entities) byName.set(e.name, { name: e.name, parentId: e.parentId });
|
|
35815
|
+
for (const e of graph.entities) {
|
|
35816
|
+
if (!e.parentId) continue;
|
|
35817
|
+
if (!byName.has(e.parentId)) {
|
|
35818
|
+
missing.push({ entity: e.name, parentId: e.parentId });
|
|
35819
|
+
continue;
|
|
35820
|
+
}
|
|
35821
|
+
const visited = /* @__PURE__ */ new Set([e.name]);
|
|
35822
|
+
let cur = byName.get(e.parentId);
|
|
35823
|
+
while (cur && cur.parentId) {
|
|
35824
|
+
if (visited.has(cur.name)) {
|
|
35825
|
+
cycles.push({ entityInCycle: e.name, cycleThrough: cur.name });
|
|
35826
|
+
break;
|
|
35827
|
+
}
|
|
35828
|
+
visited.add(cur.name);
|
|
35829
|
+
cur = byName.get(cur.parentId);
|
|
35830
|
+
}
|
|
35831
|
+
}
|
|
35832
|
+
return { orphans, missing, cycles };
|
|
35833
|
+
}
|
|
35834
|
+
async function applyFixes(ctx, orphans, missing) {
|
|
35835
|
+
let deleted = 0;
|
|
35836
|
+
let cleared = 0;
|
|
35837
|
+
if (orphans.length > 0) {
|
|
35838
|
+
await ctx.relationManager.deleteRelations(
|
|
35839
|
+
orphans.map((o) => ({ from: o.from, to: o.to, relationType: o.relationType }))
|
|
35840
|
+
);
|
|
35841
|
+
deleted = orphans.length;
|
|
35842
|
+
}
|
|
35843
|
+
for (const m of missing) {
|
|
35844
|
+
try {
|
|
35845
|
+
await ctx.hierarchyManager.setEntityParent(m.entity, null);
|
|
35846
|
+
cleared += 1;
|
|
35847
|
+
} catch {
|
|
35848
|
+
}
|
|
35849
|
+
}
|
|
35850
|
+
return { orphanRelationsDeleted: deleted, missingParentsCleared: cleared };
|
|
35851
|
+
}
|
|
35852
|
+
function registerCheckCommand(program2) {
|
|
35853
|
+
program2.command("check").description("Detect orphan relations + missing parents + hierarchy cycles. Dry-run by default.").option("--apply", "Actually delete orphan relations + clear missing parentIds (cycles always left for human review)").action(async (opts) => {
|
|
35854
|
+
const options = getOptions(program2);
|
|
35855
|
+
const logger2 = createLogger(options);
|
|
35856
|
+
const ctx = createContext(options);
|
|
35857
|
+
try {
|
|
35858
|
+
const { orphans, missing, cycles } = await detectIssues(ctx);
|
|
35859
|
+
const ok = orphans.length === 0 && missing.length === 0 && cycles.length === 0;
|
|
35860
|
+
const report = {
|
|
35861
|
+
ok,
|
|
35862
|
+
applied: Boolean(opts.apply),
|
|
35863
|
+
orphanRelations: orphans,
|
|
35864
|
+
missingParents: missing,
|
|
35865
|
+
hierarchyCycles: cycles
|
|
35866
|
+
};
|
|
35867
|
+
if (opts.apply && (orphans.length > 0 || missing.length > 0)) {
|
|
35868
|
+
report.actions = await applyFixes(ctx, orphans, missing);
|
|
35869
|
+
}
|
|
35870
|
+
console.log(JSON.stringify(report, null, 2));
|
|
35871
|
+
if (!ok && !opts.apply) process.exit(1);
|
|
35872
|
+
} catch (error) {
|
|
35873
|
+
logger2.error(formatError(error.message));
|
|
35874
|
+
process.exit(1);
|
|
35875
|
+
}
|
|
35876
|
+
});
|
|
35877
|
+
}
|
|
35878
|
+
var init_check = __esm({
|
|
35879
|
+
"src/cli/commands/check.ts"() {
|
|
35880
|
+
"use strict";
|
|
35881
|
+
init_esm_shims();
|
|
35882
|
+
init_helpers();
|
|
35883
|
+
init_formatters2();
|
|
35884
|
+
}
|
|
35885
|
+
});
|
|
35886
|
+
|
|
35743
35887
|
// src/cli/interactive.ts
|
|
35744
35888
|
var interactive_exports = {};
|
|
35745
35889
|
__export(interactive_exports, {
|
|
@@ -36048,6 +36192,57 @@ Path (${pathResult.length} hops): ${pathResult.path.join(" -> ")}`);
|
|
|
36048
36192
|
console.log(JSON.stringify(report, null, 2));
|
|
36049
36193
|
break;
|
|
36050
36194
|
}
|
|
36195
|
+
case "check": {
|
|
36196
|
+
const apply = args[0] === "--apply";
|
|
36197
|
+
const { detectIssues: detectIssues2, applyFixes: applyFixes2 } = await Promise.resolve().then(() => (init_check(), check_exports));
|
|
36198
|
+
const { orphans, missing, cycles } = await detectIssues2(ctx);
|
|
36199
|
+
const ok = orphans.length === 0 && missing.length === 0 && cycles.length === 0;
|
|
36200
|
+
const result = {
|
|
36201
|
+
ok,
|
|
36202
|
+
applied: apply,
|
|
36203
|
+
orphanRelations: orphans,
|
|
36204
|
+
missingParents: missing,
|
|
36205
|
+
hierarchyCycles: cycles
|
|
36206
|
+
};
|
|
36207
|
+
if (apply && (orphans.length > 0 || missing.length > 0)) {
|
|
36208
|
+
result.actions = await applyFixes2(ctx, orphans, missing);
|
|
36209
|
+
}
|
|
36210
|
+
console.log(JSON.stringify(result, null, 2));
|
|
36211
|
+
break;
|
|
36212
|
+
}
|
|
36213
|
+
case "heuristics": {
|
|
36214
|
+
const heuristics = await ctx.heuristicManager.list();
|
|
36215
|
+
console.log(JSON.stringify({ heuristics, count: heuristics.length }, null, 2));
|
|
36216
|
+
break;
|
|
36217
|
+
}
|
|
36218
|
+
case "spell": {
|
|
36219
|
+
const query = args.join(" ");
|
|
36220
|
+
if (!query) {
|
|
36221
|
+
console.log(chalk2.yellow("Usage: spell <query>"));
|
|
36222
|
+
break;
|
|
36223
|
+
}
|
|
36224
|
+
const suggestions = await ctx.spellChecker.suggest(query);
|
|
36225
|
+
console.log(JSON.stringify({ query, suggestions, count: suggestions.length }, null, 2));
|
|
36226
|
+
break;
|
|
36227
|
+
}
|
|
36228
|
+
case "cache": {
|
|
36229
|
+
const sub = args[0];
|
|
36230
|
+
const { getAllCacheStats: getAllCacheStats2, clearAllSearchCaches: clearAllSearchCaches2 } = await Promise.resolve().then(() => (init_searchCache(), searchCache_exports));
|
|
36231
|
+
if (sub === "clear") {
|
|
36232
|
+
clearAllSearchCaches2();
|
|
36233
|
+
console.log(JSON.stringify({ cleared: true }, null, 2));
|
|
36234
|
+
} else {
|
|
36235
|
+
console.log(JSON.stringify({ stats: getAllCacheStats2() }, null, 2));
|
|
36236
|
+
}
|
|
36237
|
+
break;
|
|
36238
|
+
}
|
|
36239
|
+
case "reindex": {
|
|
36240
|
+
const t = Date.now();
|
|
36241
|
+
await ctx.rankedSearch.buildIndex();
|
|
36242
|
+
await ctx.spellChecker.rebuild();
|
|
36243
|
+
console.log(JSON.stringify({ ok: true, ranked: "rebuilt", spell: "rebuilt", durationMs: Date.now() - t }, null, 2));
|
|
36244
|
+
break;
|
|
36245
|
+
}
|
|
36051
36246
|
default:
|
|
36052
36247
|
console.log(chalk2.yellow(`Unknown command: ${command}. Type "help" for available commands.`));
|
|
36053
36248
|
}
|
|
@@ -36071,6 +36266,11 @@ ${chalk2.green("Available Commands:")}
|
|
|
36071
36266
|
${chalk2.cyan("neighbors <name>")} Incoming + outgoing relations + degree counts
|
|
36072
36267
|
${chalk2.cyan("diag")} / ${chalk2.cyan("health")} Quick integrity summary
|
|
36073
36268
|
${chalk2.cyan("size")} Graph + storage footprint
|
|
36269
|
+
${chalk2.cyan("check [--apply]")} Orphan + missing-parent + cycle detect/repair
|
|
36270
|
+
${chalk2.cyan("heuristics")} List all heuristics
|
|
36271
|
+
${chalk2.cyan("spell <query>")} Spell suggestions for a query
|
|
36272
|
+
${chalk2.cyan("cache [clear]")} Search-cache stats; "cache clear" to bust
|
|
36273
|
+
${chalk2.cyan("reindex")} Rebuild ranked-search + spell vocabulary
|
|
36074
36274
|
${chalk2.cyan("history")} Show command history
|
|
36075
36275
|
${chalk2.cyan("clear")} Clear screen
|
|
36076
36276
|
${chalk2.cyan("help")} Show this help
|
|
@@ -37767,6 +37967,352 @@ function registerDiagCommand(program2) {
|
|
|
37767
37967
|
|
|
37768
37968
|
// src/cli/commands/index.ts
|
|
37769
37969
|
init_inspect();
|
|
37970
|
+
|
|
37971
|
+
// src/cli/commands/heuristic.ts
|
|
37972
|
+
init_esm_shims();
|
|
37973
|
+
init_helpers();
|
|
37974
|
+
init_formatters2();
|
|
37975
|
+
function emitJson(payload) {
|
|
37976
|
+
console.log(JSON.stringify(payload, null, 2));
|
|
37977
|
+
}
|
|
37978
|
+
function registerHeuristicCommands(program2) {
|
|
37979
|
+
const h = program2.command("heuristic").description("Manage condition\u2192action heuristic guidelines (add, match, reinforce, conflicts)");
|
|
37980
|
+
h.command("add <condition> <action>").description("Add a heuristic guideline. Returns the assigned id.").option("-p, --priority <n>", "Priority (numeric; higher wins ties)", parseFloat).option("-c, --confidence <n>", "Initial confidence 0\u20131", parseFloat).option("-i, --importance <n>", "Importance 0\u201310", parseFloat).option("-a, --agent-id <id>", "Owning agent ID").action(async (condition, action, opts) => {
|
|
37981
|
+
const options = getOptions(program2);
|
|
37982
|
+
const logger2 = createLogger(options);
|
|
37983
|
+
const ctx = createContext(options);
|
|
37984
|
+
try {
|
|
37985
|
+
const id = await ctx.heuristicManager.add({
|
|
37986
|
+
condition,
|
|
37987
|
+
action,
|
|
37988
|
+
priority: opts.priority,
|
|
37989
|
+
initialConfidence: opts.confidence,
|
|
37990
|
+
importance: opts.importance,
|
|
37991
|
+
agentId: opts.agentId
|
|
37992
|
+
});
|
|
37993
|
+
emitJson({ id });
|
|
37994
|
+
} catch (error) {
|
|
37995
|
+
logger2.error(formatError(error.message));
|
|
37996
|
+
process.exit(1);
|
|
37997
|
+
}
|
|
37998
|
+
});
|
|
37999
|
+
h.command("list").description("List all heuristics").action(async () => {
|
|
38000
|
+
const options = getOptions(program2);
|
|
38001
|
+
const logger2 = createLogger(options);
|
|
38002
|
+
const ctx = createContext(options);
|
|
38003
|
+
try {
|
|
38004
|
+
const heuristics = await ctx.heuristicManager.list();
|
|
38005
|
+
emitJson({ heuristics, count: heuristics.length });
|
|
38006
|
+
} catch (error) {
|
|
38007
|
+
logger2.error(formatError(error.message));
|
|
38008
|
+
process.exit(1);
|
|
38009
|
+
}
|
|
38010
|
+
});
|
|
38011
|
+
h.command("count").description("Print the current heuristic count").action(async () => {
|
|
38012
|
+
const options = getOptions(program2);
|
|
38013
|
+
const logger2 = createLogger(options);
|
|
38014
|
+
const ctx = createContext(options);
|
|
38015
|
+
try {
|
|
38016
|
+
const count = await ctx.heuristicManager.size();
|
|
38017
|
+
emitJson({ count });
|
|
38018
|
+
} catch (error) {
|
|
38019
|
+
logger2.error(formatError(error.message));
|
|
38020
|
+
process.exit(1);
|
|
38021
|
+
}
|
|
38022
|
+
});
|
|
38023
|
+
h.command("get <id>").description("Get a heuristic by id").action(async (id) => {
|
|
38024
|
+
const options = getOptions(program2);
|
|
38025
|
+
const logger2 = createLogger(options);
|
|
38026
|
+
const ctx = createContext(options);
|
|
38027
|
+
try {
|
|
38028
|
+
const heuristic = ctx.heuristicManager.get(id);
|
|
38029
|
+
emitJson({ id, heuristic: heuristic ?? null });
|
|
38030
|
+
} catch (error) {
|
|
38031
|
+
logger2.error(formatError(error.message));
|
|
38032
|
+
process.exit(1);
|
|
38033
|
+
}
|
|
38034
|
+
});
|
|
38035
|
+
h.command("match <input...>").description("Match heuristics whose condition fits the given input").option("-l, --limit <n>", "Max matches to return", (v) => parseInt(v, 10)).option("-s, --min-score <n>", "Minimum match score 0\u20131", parseFloat).action(async (inputParts, opts) => {
|
|
38036
|
+
const options = getOptions(program2);
|
|
38037
|
+
const logger2 = createLogger(options);
|
|
38038
|
+
const ctx = createContext(options);
|
|
38039
|
+
const input = inputParts.join(" ");
|
|
38040
|
+
try {
|
|
38041
|
+
const matches2 = await ctx.heuristicManager.match(input, {
|
|
38042
|
+
limit: opts.limit,
|
|
38043
|
+
minScore: opts.minScore
|
|
38044
|
+
});
|
|
38045
|
+
emitJson({ input, matches: matches2, count: matches2.length });
|
|
38046
|
+
} catch (error) {
|
|
38047
|
+
logger2.error(formatError(error.message));
|
|
38048
|
+
process.exit(1);
|
|
38049
|
+
}
|
|
38050
|
+
});
|
|
38051
|
+
h.command("reinforce <id>").description("Reinforce a heuristic (bump confidence toward 1)").action(async (id) => {
|
|
38052
|
+
const options = getOptions(program2);
|
|
38053
|
+
const logger2 = createLogger(options);
|
|
38054
|
+
const ctx = createContext(options);
|
|
38055
|
+
try {
|
|
38056
|
+
const result = await ctx.heuristicManager.reinforce(id);
|
|
38057
|
+
emitJson({ id, result });
|
|
38058
|
+
} catch (error) {
|
|
38059
|
+
logger2.error(formatError(error.message));
|
|
38060
|
+
process.exit(1);
|
|
38061
|
+
}
|
|
38062
|
+
});
|
|
38063
|
+
h.command("contradict <id>").description("Record a contradiction (decreases confidence)").action(async (id) => {
|
|
38064
|
+
const options = getOptions(program2);
|
|
38065
|
+
const logger2 = createLogger(options);
|
|
38066
|
+
const ctx = createContext(options);
|
|
38067
|
+
try {
|
|
38068
|
+
const result = await ctx.heuristicManager.recordContradiction(id);
|
|
38069
|
+
emitJson({ id, result });
|
|
38070
|
+
} catch (error) {
|
|
38071
|
+
logger2.error(formatError(error.message));
|
|
38072
|
+
process.exit(1);
|
|
38073
|
+
}
|
|
38074
|
+
});
|
|
38075
|
+
h.command("conflicts").description("Detect heuristics with conflicting actions for similar conditions").action(async () => {
|
|
38076
|
+
const options = getOptions(program2);
|
|
38077
|
+
const logger2 = createLogger(options);
|
|
38078
|
+
const ctx = createContext(options);
|
|
38079
|
+
try {
|
|
38080
|
+
const conflicts = await ctx.heuristicManager.detectConflicts();
|
|
38081
|
+
emitJson({ conflicts, count: conflicts.length });
|
|
38082
|
+
} catch (error) {
|
|
38083
|
+
logger2.error(formatError(error.message));
|
|
38084
|
+
process.exit(1);
|
|
38085
|
+
}
|
|
38086
|
+
});
|
|
38087
|
+
h.command("remove <id>").description("Remove a heuristic by id").action(async (id) => {
|
|
38088
|
+
const options = getOptions(program2);
|
|
38089
|
+
const logger2 = createLogger(options);
|
|
38090
|
+
const ctx = createContext(options);
|
|
38091
|
+
try {
|
|
38092
|
+
const removed = await ctx.heuristicManager.remove(id);
|
|
38093
|
+
emitJson({ id, removed });
|
|
38094
|
+
} catch (error) {
|
|
38095
|
+
logger2.error(formatError(error.message));
|
|
38096
|
+
process.exit(1);
|
|
38097
|
+
}
|
|
38098
|
+
});
|
|
38099
|
+
h.command("clear").description("Remove all heuristics. Destructive; no --dry-run yet.").action(async () => {
|
|
38100
|
+
const options = getOptions(program2);
|
|
38101
|
+
const logger2 = createLogger(options);
|
|
38102
|
+
const ctx = createContext(options);
|
|
38103
|
+
try {
|
|
38104
|
+
await ctx.heuristicManager.clear();
|
|
38105
|
+
emitJson({ cleared: true });
|
|
38106
|
+
} catch (error) {
|
|
38107
|
+
logger2.error(formatError(error.message));
|
|
38108
|
+
process.exit(1);
|
|
38109
|
+
}
|
|
38110
|
+
});
|
|
38111
|
+
}
|
|
38112
|
+
|
|
38113
|
+
// src/cli/commands/observationDedup.ts
|
|
38114
|
+
init_esm_shims();
|
|
38115
|
+
init_helpers();
|
|
38116
|
+
init_formatters2();
|
|
38117
|
+
function buildFilter(opts) {
|
|
38118
|
+
const filter = {};
|
|
38119
|
+
const entityType = opts.entityType;
|
|
38120
|
+
if (entityType) {
|
|
38121
|
+
filter.entityType = entityType.includes(",") ? entityType.split(",").map((s) => s.trim()).filter(Boolean) : entityType;
|
|
38122
|
+
}
|
|
38123
|
+
if (typeof opts.projectId === "string") filter.projectId = opts.projectId;
|
|
38124
|
+
if (typeof opts.sessionId === "string") filter.sessionId = opts.sessionId;
|
|
38125
|
+
if (typeof opts.minOccurrences === "number" && opts.minOccurrences >= 2) {
|
|
38126
|
+
filter.minOccurrences = opts.minOccurrences;
|
|
38127
|
+
}
|
|
38128
|
+
if (typeof opts.maxGroups === "number" && opts.maxGroups > 0) {
|
|
38129
|
+
filter.maxGroups = opts.maxGroups;
|
|
38130
|
+
}
|
|
38131
|
+
return filter;
|
|
38132
|
+
}
|
|
38133
|
+
function emitJson2(payload) {
|
|
38134
|
+
console.log(JSON.stringify(payload, null, 2));
|
|
38135
|
+
}
|
|
38136
|
+
function registerObservationDedupCommands(program2) {
|
|
38137
|
+
const od = program2.command("obs-dedup").description("Cross-entity observation duplicate detection (exact and Jaccard similarity)");
|
|
38138
|
+
od.command("find").description("Find observations that appear verbatim across multiple entities").option("--entity-type <type>", "Filter to one entityType (or comma-separated list)").option("--project-id <id>", "Filter to one projectId").option("--session-id <id>", "Filter to one sessionId").option("--min-occurrences <n>", "Minimum occurrences per group (\u22652)", (v) => parseInt(v, 10)).option("--max-groups <n>", "Maximum groups to return", (v) => parseInt(v, 10)).action(async (opts) => {
|
|
38139
|
+
const options = getOptions(program2);
|
|
38140
|
+
const logger2 = createLogger(options);
|
|
38141
|
+
const ctx = createContext(options);
|
|
38142
|
+
try {
|
|
38143
|
+
const filter = buildFilter(opts);
|
|
38144
|
+
const groups = await ctx.observationDedupManager.findDuplicateObservations(filter);
|
|
38145
|
+
emitJson2({ filter, groups, count: groups.length });
|
|
38146
|
+
} catch (error) {
|
|
38147
|
+
logger2.error(formatError(error.message));
|
|
38148
|
+
process.exit(1);
|
|
38149
|
+
}
|
|
38150
|
+
});
|
|
38151
|
+
od.command("find-jaccard").description("Find near-duplicate observations across entities by Jaccard similarity").option("--entity-type <type>", "Filter to one entityType (or comma-separated list)").option("--project-id <id>", "Filter to one projectId").option("--session-id <id>", "Filter to one sessionId").option("--min-occurrences <n>", "Minimum occurrences per group (\u22652)", (v) => parseInt(v, 10)).option("--max-groups <n>", "Maximum groups to return", (v) => parseInt(v, 10)).action(async (opts) => {
|
|
38152
|
+
const options = getOptions(program2);
|
|
38153
|
+
const logger2 = createLogger(options);
|
|
38154
|
+
const ctx = createContext(options);
|
|
38155
|
+
try {
|
|
38156
|
+
const filter = buildFilter(opts);
|
|
38157
|
+
const groups = await ctx.observationDedupManager.findJaccardDuplicates(filter);
|
|
38158
|
+
emitJson2({ filter, groups, count: groups.length });
|
|
38159
|
+
} catch (error) {
|
|
38160
|
+
logger2.error(formatError(error.message));
|
|
38161
|
+
process.exit(1);
|
|
38162
|
+
}
|
|
38163
|
+
});
|
|
38164
|
+
}
|
|
38165
|
+
|
|
38166
|
+
// src/cli/commands/spell.ts
|
|
38167
|
+
init_esm_shims();
|
|
38168
|
+
init_helpers();
|
|
38169
|
+
init_formatters2();
|
|
38170
|
+
function emitJson3(payload) {
|
|
38171
|
+
console.log(JSON.stringify(payload, null, 2));
|
|
38172
|
+
}
|
|
38173
|
+
function registerSpellCommands(program2) {
|
|
38174
|
+
const sp = program2.command("spell").description("Spell-suggest queries against the graph vocabulary");
|
|
38175
|
+
sp.command("suggest <query>").description("Suggest corrections for a (possibly misspelled) query").option("-l, --limit <n>", "Max suggestions to return", (v) => parseInt(v, 10)).option("-s, --min-score <n>", "Minimum match score 0\u20131", parseFloat).option("-d, --max-distance <n>", "Maximum Levenshtein distance", parseFloat).action(async (query, opts) => {
|
|
38176
|
+
const options = getOptions(program2);
|
|
38177
|
+
const logger2 = createLogger(options);
|
|
38178
|
+
const ctx = createContext(options);
|
|
38179
|
+
try {
|
|
38180
|
+
const suggestions = await ctx.spellChecker.suggest(query, {
|
|
38181
|
+
limit: opts.limit,
|
|
38182
|
+
minScore: opts.minScore,
|
|
38183
|
+
maxDistance: opts.maxDistance
|
|
38184
|
+
});
|
|
38185
|
+
emitJson3({ query, suggestions, count: suggestions.length });
|
|
38186
|
+
} catch (error) {
|
|
38187
|
+
logger2.error(formatError(error.message));
|
|
38188
|
+
process.exit(1);
|
|
38189
|
+
}
|
|
38190
|
+
});
|
|
38191
|
+
sp.command("rebuild").description("Rebuild the spell-checker vocabulary index from the graph").action(async () => {
|
|
38192
|
+
const options = getOptions(program2);
|
|
38193
|
+
const logger2 = createLogger(options);
|
|
38194
|
+
const ctx = createContext(options);
|
|
38195
|
+
try {
|
|
38196
|
+
await ctx.spellChecker.rebuild();
|
|
38197
|
+
emitJson3({ rebuilt: true, vocabularySize: ctx.spellChecker.vocabularySize() });
|
|
38198
|
+
} catch (error) {
|
|
38199
|
+
logger2.error(formatError(error.message));
|
|
38200
|
+
process.exit(1);
|
|
38201
|
+
}
|
|
38202
|
+
});
|
|
38203
|
+
sp.command("size").description("Print the current vocabulary size").action(async () => {
|
|
38204
|
+
const options = getOptions(program2);
|
|
38205
|
+
const logger2 = createLogger(options);
|
|
38206
|
+
const ctx = createContext(options);
|
|
38207
|
+
try {
|
|
38208
|
+
emitJson3({ vocabularySize: ctx.spellChecker.vocabularySize() });
|
|
38209
|
+
} catch (error) {
|
|
38210
|
+
logger2.error(formatError(error.message));
|
|
38211
|
+
process.exit(1);
|
|
38212
|
+
}
|
|
38213
|
+
});
|
|
38214
|
+
}
|
|
38215
|
+
|
|
38216
|
+
// src/cli/commands/index.ts
|
|
38217
|
+
init_check();
|
|
38218
|
+
|
|
38219
|
+
// src/cli/commands/cache.ts
|
|
38220
|
+
init_esm_shims();
|
|
38221
|
+
init_searchCache();
|
|
38222
|
+
init_helpers();
|
|
38223
|
+
init_formatters2();
|
|
38224
|
+
function emitJson4(payload) {
|
|
38225
|
+
console.log(JSON.stringify(payload, null, 2));
|
|
38226
|
+
}
|
|
38227
|
+
function registerCacheCommands(program2) {
|
|
38228
|
+
const cache = program2.command("cache").description("Inspect or bust the per-tier search caches (basic / ranked / boolean / fuzzy)");
|
|
38229
|
+
cache.command("stats").description("Per-cache hits/misses/size/hitRate snapshot. Stats are process-local \u2014 fresh CLI invocations start at zero.").action(() => {
|
|
38230
|
+
try {
|
|
38231
|
+
const stats = getAllCacheStats();
|
|
38232
|
+
emitJson4({ stats });
|
|
38233
|
+
} catch (error) {
|
|
38234
|
+
const logger2 = createLogger(getOptions(program2));
|
|
38235
|
+
logger2.error(formatError(error.message));
|
|
38236
|
+
process.exit(1);
|
|
38237
|
+
}
|
|
38238
|
+
});
|
|
38239
|
+
cache.command("clear").description("Clear all four search caches. Idempotent; safe to call any time.").action(() => {
|
|
38240
|
+
try {
|
|
38241
|
+
clearAllSearchCaches();
|
|
38242
|
+
emitJson4({ cleared: true, caches: ["basic", "ranked", "boolean", "fuzzy"] });
|
|
38243
|
+
} catch (error) {
|
|
38244
|
+
const logger2 = createLogger(getOptions(program2));
|
|
38245
|
+
logger2.error(formatError(error.message));
|
|
38246
|
+
process.exit(1);
|
|
38247
|
+
}
|
|
38248
|
+
});
|
|
38249
|
+
cache.command("cleanup").description("Sweep expired entries (TTL) across all caches without dropping live entries.").action(() => {
|
|
38250
|
+
try {
|
|
38251
|
+
cleanupAllCaches();
|
|
38252
|
+
emitJson4({ cleaned: true, caches: ["basic", "ranked", "boolean", "fuzzy"] });
|
|
38253
|
+
} catch (error) {
|
|
38254
|
+
const logger2 = createLogger(getOptions(program2));
|
|
38255
|
+
logger2.error(formatError(error.message));
|
|
38256
|
+
process.exit(1);
|
|
38257
|
+
}
|
|
38258
|
+
});
|
|
38259
|
+
}
|
|
38260
|
+
|
|
38261
|
+
// src/cli/commands/reindex.ts
|
|
38262
|
+
init_esm_shims();
|
|
38263
|
+
init_RankedSearch();
|
|
38264
|
+
init_helpers();
|
|
38265
|
+
init_formatters2();
|
|
38266
|
+
import { dirname as dirname10 } from "path";
|
|
38267
|
+
import { performance as performance3 } from "perf_hooks";
|
|
38268
|
+
function emitJson5(payload) {
|
|
38269
|
+
console.log(JSON.stringify(payload, null, 2));
|
|
38270
|
+
}
|
|
38271
|
+
function registerReindexCommand(program2) {
|
|
38272
|
+
program2.command("reindex").description("Rebuild search-side indexes (TF-IDF/BM25 ranked + spell vocabulary).").option("--ranked", "Rebuild only the ranked-search (TF-IDF/BM25) index").option("--spell", "Rebuild only the spell-checker vocabulary").action(async (opts) => {
|
|
38273
|
+
const options = getOptions(program2);
|
|
38274
|
+
const logger2 = createLogger(options);
|
|
38275
|
+
const ctx = createContext(options);
|
|
38276
|
+
const targets = opts.ranked === true || opts.spell === true ? { ranked: Boolean(opts.ranked), spell: Boolean(opts.spell) } : { ranked: true, spell: true };
|
|
38277
|
+
const result = {};
|
|
38278
|
+
if (targets.ranked) {
|
|
38279
|
+
const t = performance3.now();
|
|
38280
|
+
try {
|
|
38281
|
+
const storageDir = dirname10(options.storage);
|
|
38282
|
+
const ranked = new RankedSearch(ctx.storage, storageDir);
|
|
38283
|
+
await ranked.buildIndex();
|
|
38284
|
+
result.ranked = { ok: true, durationMs: performance3.now() - t };
|
|
38285
|
+
} catch (e) {
|
|
38286
|
+
result.ranked = {
|
|
38287
|
+
ok: false,
|
|
38288
|
+
durationMs: performance3.now() - t,
|
|
38289
|
+
detail: e instanceof Error ? e.message : String(e)
|
|
38290
|
+
};
|
|
38291
|
+
}
|
|
38292
|
+
}
|
|
38293
|
+
if (targets.spell) {
|
|
38294
|
+
const t = performance3.now();
|
|
38295
|
+
try {
|
|
38296
|
+
await ctx.spellChecker.rebuild();
|
|
38297
|
+
result.spell = { ok: true, durationMs: performance3.now() - t };
|
|
38298
|
+
} catch (e) {
|
|
38299
|
+
result.spell = {
|
|
38300
|
+
ok: false,
|
|
38301
|
+
durationMs: performance3.now() - t,
|
|
38302
|
+
detail: e instanceof Error ? e.message : String(e)
|
|
38303
|
+
};
|
|
38304
|
+
}
|
|
38305
|
+
}
|
|
38306
|
+
const failed = Object.values(result).filter((r) => !r.ok).length;
|
|
38307
|
+
emitJson5({ ok: failed === 0, failed, result });
|
|
38308
|
+
if (failed > 0) {
|
|
38309
|
+
logger2.error(formatError(`${failed} index(es) failed to rebuild`));
|
|
38310
|
+
process.exit(1);
|
|
38311
|
+
}
|
|
38312
|
+
});
|
|
38313
|
+
}
|
|
38314
|
+
|
|
38315
|
+
// src/cli/commands/index.ts
|
|
37770
38316
|
function registerCommands(program2) {
|
|
37771
38317
|
registerEntityCommands(program2);
|
|
37772
38318
|
registerRelationCommands(program2);
|
|
@@ -37784,6 +38330,12 @@ function registerCommands(program2) {
|
|
|
37784
38330
|
registerSmokeCommand(program2);
|
|
37785
38331
|
registerDiagCommand(program2);
|
|
37786
38332
|
registerInspectCommands(program2);
|
|
38333
|
+
registerHeuristicCommands(program2);
|
|
38334
|
+
registerObservationDedupCommands(program2);
|
|
38335
|
+
registerSpellCommands(program2);
|
|
38336
|
+
registerCheckCommand(program2);
|
|
38337
|
+
registerCacheCommands(program2);
|
|
38338
|
+
registerReindexCommand(program2);
|
|
37787
38339
|
}
|
|
37788
38340
|
|
|
37789
38341
|
// src/cli/index.ts
|
|
@@ -37791,7 +38343,7 @@ init_logger();
|
|
|
37791
38343
|
import { readFileSync as readFileSync5 } from "fs";
|
|
37792
38344
|
import { createInterface as createInterface2 } from "readline";
|
|
37793
38345
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
37794
|
-
import { dirname as
|
|
38346
|
+
import { dirname as dirname11, join as join10 } from "path";
|
|
37795
38347
|
process.on("unhandledRejection", (reason) => {
|
|
37796
38348
|
logger.error("Unhandled promise rejection:", reason);
|
|
37797
38349
|
});
|
|
@@ -37801,7 +38353,7 @@ process.on("uncaughtException", (err) => {
|
|
|
37801
38353
|
function getVersion() {
|
|
37802
38354
|
try {
|
|
37803
38355
|
const __filename2 = fileURLToPath4(import.meta.url);
|
|
37804
|
-
const __dirname2 =
|
|
38356
|
+
const __dirname2 = dirname11(__filename2);
|
|
37805
38357
|
const pkgPath = join10(__dirname2, "..", "..", "package.json");
|
|
37806
38358
|
const pkg = JSON.parse(readFileSync5(pkgPath, "utf-8"));
|
|
37807
38359
|
return pkg.version;
|