@danielsimonjr/memoryjs 2.1.2 → 2.3.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 +1489 -603
- 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/dist/cli/index.js
CHANGED
|
@@ -6730,7 +6730,30 @@ var init_GraphStorage = __esm({
|
|
|
6730
6730
|
// ArtifactEntity extension (types/artifact.ts)
|
|
6731
6731
|
"artifactType",
|
|
6732
6732
|
"toolName",
|
|
6733
|
-
"shortId"
|
|
6733
|
+
"shortId",
|
|
6734
|
+
// v2.1.0 subclass-manager record fields (sibling to the v2.1.1
|
|
6735
|
+
// UpdateEntitySchema.passthrough fix — same root cause: subclass managers
|
|
6736
|
+
// attach domain records that the persistence allowlist must also admit,
|
|
6737
|
+
// otherwise the records are silently dropped on save and the managers'
|
|
6738
|
+
// list/match/get operations return empty on next load).
|
|
6739
|
+
"heuristicRecord",
|
|
6740
|
+
// HeuristicEntity
|
|
6741
|
+
"decisionRecord",
|
|
6742
|
+
// DecisionEntity (includes nested lifecycle)
|
|
6743
|
+
"exclusionRule",
|
|
6744
|
+
// ExclusionEntity
|
|
6745
|
+
"projectContextRecord",
|
|
6746
|
+
// ProjectContextEntity
|
|
6747
|
+
"toolAffordanceRecord",
|
|
6748
|
+
// ToolAffordanceEntity
|
|
6749
|
+
"prospectiveRecord",
|
|
6750
|
+
// ProspectiveEntity
|
|
6751
|
+
"failureRecord",
|
|
6752
|
+
// FailureEntity
|
|
6753
|
+
"planRecord",
|
|
6754
|
+
// PlanEntity
|
|
6755
|
+
"reflectionRecord"
|
|
6756
|
+
// ReflectionEntity
|
|
6734
6757
|
];
|
|
6735
6758
|
GraphStorage = class {
|
|
6736
6759
|
/**
|
|
@@ -11245,7 +11268,7 @@ var init_GraphTraversal = __esm({
|
|
|
11245
11268
|
Object.entries(options).filter(([, v]) => v !== void 0)
|
|
11246
11269
|
);
|
|
11247
11270
|
const opts = { ...DEFAULT_OPTIONS, ...definedOptions };
|
|
11248
|
-
const
|
|
11271
|
+
const neighbors2 = [];
|
|
11249
11272
|
let relations = [];
|
|
11250
11273
|
if (opts.direction === "outgoing" || opts.direction === "both") {
|
|
11251
11274
|
relations = relations.concat(this.storage.getRelationsFrom(entityName));
|
|
@@ -11266,9 +11289,9 @@ var init_GraphTraversal = __esm({
|
|
|
11266
11289
|
const typeSet = new Set(opts.entityTypes.map((t) => t.toLowerCase()));
|
|
11267
11290
|
if (!typeSet.has(entity.entityType.toLowerCase())) continue;
|
|
11268
11291
|
}
|
|
11269
|
-
|
|
11292
|
+
neighbors2.push({ neighbor, relation });
|
|
11270
11293
|
}
|
|
11271
|
-
return
|
|
11294
|
+
return neighbors2;
|
|
11272
11295
|
}
|
|
11273
11296
|
/**
|
|
11274
11297
|
* Breadth-First Search traversal starting from a given entity.
|
|
@@ -11294,8 +11317,8 @@ var init_GraphTraversal = __esm({
|
|
|
11294
11317
|
if (depth > opts.maxDepth) continue;
|
|
11295
11318
|
nodes.push(node);
|
|
11296
11319
|
depths.set(node, depth);
|
|
11297
|
-
const
|
|
11298
|
-
for (const { neighbor } of
|
|
11320
|
+
const neighbors2 = this.getNeighborsWithRelations(node, opts);
|
|
11321
|
+
for (const { neighbor } of neighbors2) {
|
|
11299
11322
|
if (!visited.has(neighbor)) {
|
|
11300
11323
|
visited.add(neighbor);
|
|
11301
11324
|
queue.push({ node: neighbor, depth: depth + 1 });
|
|
@@ -11330,8 +11353,8 @@ var init_GraphTraversal = __esm({
|
|
|
11330
11353
|
visited.add(node);
|
|
11331
11354
|
nodes.push(node);
|
|
11332
11355
|
depths.set(node, depth);
|
|
11333
|
-
const
|
|
11334
|
-
for (const { neighbor } of
|
|
11356
|
+
const neighbors2 = this.getNeighborsWithRelations(node, opts);
|
|
11357
|
+
for (const { neighbor } of neighbors2) {
|
|
11335
11358
|
if (!visited.has(neighbor)) {
|
|
11336
11359
|
stack.push({ node: neighbor, depth: depth + 1 });
|
|
11337
11360
|
if (!parents.has(neighbor)) {
|
|
@@ -11378,8 +11401,8 @@ var init_GraphTraversal = __esm({
|
|
|
11378
11401
|
}
|
|
11379
11402
|
return result;
|
|
11380
11403
|
}
|
|
11381
|
-
const
|
|
11382
|
-
for (const { neighbor, relation } of
|
|
11404
|
+
const neighbors2 = this.getNeighborsWithRelations(current, opts);
|
|
11405
|
+
for (const { neighbor, relation } of neighbors2) {
|
|
11383
11406
|
if (!visited.has(neighbor)) {
|
|
11384
11407
|
visited.add(neighbor);
|
|
11385
11408
|
queue.push(neighbor);
|
|
@@ -11453,8 +11476,8 @@ var init_GraphTraversal = __esm({
|
|
|
11453
11476
|
});
|
|
11454
11477
|
return;
|
|
11455
11478
|
}
|
|
11456
|
-
const
|
|
11457
|
-
for (const { neighbor, relation } of
|
|
11479
|
+
const neighbors2 = this.getNeighborsWithRelations(current, opts);
|
|
11480
|
+
for (const { neighbor, relation } of neighbors2) {
|
|
11458
11481
|
if (!visited.has(neighbor)) {
|
|
11459
11482
|
visited.add(neighbor);
|
|
11460
11483
|
currentPath.push(neighbor);
|
|
@@ -11498,8 +11521,8 @@ var init_GraphTraversal = __esm({
|
|
|
11498
11521
|
while (queue.length > 0) {
|
|
11499
11522
|
const current = queue.shift();
|
|
11500
11523
|
component.push(current);
|
|
11501
|
-
const
|
|
11502
|
-
for (const { neighbor } of
|
|
11524
|
+
const neighbors2 = this.getNeighborsWithRelations(current, { direction: "both" });
|
|
11525
|
+
for (const { neighbor } of neighbors2) {
|
|
11503
11526
|
if (!visited.has(neighbor)) {
|
|
11504
11527
|
visited.add(neighbor);
|
|
11505
11528
|
queue.push(neighbor);
|
|
@@ -11594,8 +11617,8 @@ var init_GraphTraversal = __esm({
|
|
|
11594
11617
|
while (queue.length > 0) {
|
|
11595
11618
|
const v = queue.shift();
|
|
11596
11619
|
stack.push(v);
|
|
11597
|
-
const
|
|
11598
|
-
for (const { neighbor: w } of
|
|
11620
|
+
const neighbors2 = this.getNeighborsWithRelations(v, { direction: "both" });
|
|
11621
|
+
for (const { neighbor: w } of neighbors2) {
|
|
11599
11622
|
if (distance.get(w) === -1) {
|
|
11600
11623
|
distance.set(w, distance.get(v) + 1);
|
|
11601
11624
|
queue.push(w);
|
|
@@ -33370,11 +33393,11 @@ var init_CausalReasoner = __esm({
|
|
|
33370
33393
|
if (d > depth) return;
|
|
33371
33394
|
inPath.add(node);
|
|
33372
33395
|
path6.push(node);
|
|
33373
|
-
const
|
|
33396
|
+
const neighbors2 = this.traversal.getNeighborsWithRelations(node, {
|
|
33374
33397
|
relationTypes: this.causalTypes,
|
|
33375
33398
|
direction: "outgoing"
|
|
33376
33399
|
});
|
|
33377
|
-
for (const { neighbor, relation } of
|
|
33400
|
+
for (const { neighbor, relation } of neighbors2) {
|
|
33378
33401
|
if (inPath.has(neighbor)) {
|
|
33379
33402
|
const idx = path6.indexOf(neighbor);
|
|
33380
33403
|
if (idx >= 0) {
|
|
@@ -35164,657 +35187,940 @@ var init_ManagerContext = __esm({
|
|
|
35164
35187
|
}
|
|
35165
35188
|
});
|
|
35166
35189
|
|
|
35167
|
-
// src/cli/
|
|
35168
|
-
|
|
35169
|
-
|
|
35170
|
-
|
|
35171
|
-
|
|
35172
|
-
|
|
35173
|
-
|
|
35174
|
-
|
|
35175
|
-
|
|
35176
|
-
const interactiveCtx = {
|
|
35177
|
-
ctx,
|
|
35178
|
-
options,
|
|
35179
|
-
history: []
|
|
35190
|
+
// src/cli/options.ts
|
|
35191
|
+
function parseGlobalOptions(opts) {
|
|
35192
|
+
const rawFormat = opts.outputFormat;
|
|
35193
|
+
const format = rawFormat && ["json", "table", "csv"].includes(rawFormat) ? rawFormat : defaultOptions.format;
|
|
35194
|
+
return {
|
|
35195
|
+
storage: opts.storage || defaultOptions.storage,
|
|
35196
|
+
format,
|
|
35197
|
+
quiet: Boolean(opts.quiet),
|
|
35198
|
+
verbose: Boolean(opts.verbose)
|
|
35180
35199
|
};
|
|
35181
|
-
const graph = await ctx.storage.loadGraph();
|
|
35182
|
-
const entityNames = graph.entities.map((e) => e.name);
|
|
35183
|
-
const rl = readline.createInterface({
|
|
35184
|
-
input: process.stdin,
|
|
35185
|
-
output: process.stdout,
|
|
35186
|
-
prompt: chalk2.cyan("memory> "),
|
|
35187
|
-
completer: (line) => {
|
|
35188
|
-
const completions = [
|
|
35189
|
-
"entities",
|
|
35190
|
-
"relations",
|
|
35191
|
-
"search",
|
|
35192
|
-
"get",
|
|
35193
|
-
"stats",
|
|
35194
|
-
"tags",
|
|
35195
|
-
"path",
|
|
35196
|
-
"observe",
|
|
35197
|
-
"delete",
|
|
35198
|
-
"export",
|
|
35199
|
-
"help",
|
|
35200
|
-
"exit",
|
|
35201
|
-
"clear",
|
|
35202
|
-
"history",
|
|
35203
|
-
...entityNames
|
|
35204
|
-
];
|
|
35205
|
-
const hits = completions.filter((c) => c.toLowerCase().startsWith(line.toLowerCase()));
|
|
35206
|
-
return [hits.length ? hits : completions, line];
|
|
35207
|
-
}
|
|
35208
|
-
});
|
|
35209
|
-
console.log(chalk2.green("MemoryJS Interactive Mode"));
|
|
35210
|
-
console.log(chalk2.gray('Type "help" for commands, "exit" to quit.\n'));
|
|
35211
|
-
rl.prompt();
|
|
35212
|
-
rl.on("line", async (line) => {
|
|
35213
|
-
const trimmed = line.trim();
|
|
35214
|
-
if (!trimmed) {
|
|
35215
|
-
rl.prompt();
|
|
35216
|
-
return;
|
|
35217
|
-
}
|
|
35218
|
-
interactiveCtx.history.push(trimmed);
|
|
35219
|
-
try {
|
|
35220
|
-
await processCommand(trimmed, interactiveCtx, rl);
|
|
35221
|
-
} catch (error) {
|
|
35222
|
-
console.error(chalk2.red(`Error: ${error.message}`));
|
|
35223
|
-
}
|
|
35224
|
-
rl.prompt();
|
|
35225
|
-
});
|
|
35226
|
-
rl.on("close", () => {
|
|
35227
|
-
console.log(chalk2.gray("\nGoodbye!"));
|
|
35228
|
-
process.exit(0);
|
|
35229
|
-
});
|
|
35230
35200
|
}
|
|
35231
|
-
|
|
35232
|
-
|
|
35233
|
-
|
|
35234
|
-
|
|
35235
|
-
|
|
35236
|
-
|
|
35237
|
-
|
|
35238
|
-
|
|
35239
|
-
|
|
35240
|
-
|
|
35241
|
-
|
|
35242
|
-
|
|
35243
|
-
|
|
35244
|
-
|
|
35245
|
-
|
|
35246
|
-
|
|
35247
|
-
|
|
35248
|
-
|
|
35249
|
-
|
|
35250
|
-
|
|
35251
|
-
|
|
35252
|
-
|
|
35253
|
-
|
|
35254
|
-
|
|
35255
|
-
|
|
35256
|
-
|
|
35257
|
-
|
|
35258
|
-
|
|
35201
|
+
function createLogger(options) {
|
|
35202
|
+
return {
|
|
35203
|
+
info: (msg) => !options.quiet && console.log(msg),
|
|
35204
|
+
debug: (msg) => options.verbose && console.log(`[DEBUG] ${msg}`),
|
|
35205
|
+
error: (msg) => console.error(`[ERROR] ${msg}`),
|
|
35206
|
+
warn: (msg) => !options.quiet && console.warn(`[WARN] ${msg}`)
|
|
35207
|
+
};
|
|
35208
|
+
}
|
|
35209
|
+
var defaultOptions;
|
|
35210
|
+
var init_options = __esm({
|
|
35211
|
+
"src/cli/options.ts"() {
|
|
35212
|
+
"use strict";
|
|
35213
|
+
init_esm_shims();
|
|
35214
|
+
defaultOptions = {
|
|
35215
|
+
storage: process.env.MEMORYJS_STORAGE_PATH || "./memory.jsonl",
|
|
35216
|
+
format: process.env.MEMORYJS_OUTPUT_FORMAT || "json",
|
|
35217
|
+
quiet: false,
|
|
35218
|
+
verbose: false
|
|
35219
|
+
};
|
|
35220
|
+
}
|
|
35221
|
+
});
|
|
35222
|
+
|
|
35223
|
+
// src/cli/config.ts
|
|
35224
|
+
import { existsSync as existsSync2, readFileSync } from "fs";
|
|
35225
|
+
import { resolve as resolve2, dirname as dirname8 } from "path";
|
|
35226
|
+
function findConfigFile(startDir = process.cwd()) {
|
|
35227
|
+
let currentDir = startDir;
|
|
35228
|
+
const root = resolve2("/");
|
|
35229
|
+
while (currentDir !== root) {
|
|
35230
|
+
for (const filename of CONFIG_FILES) {
|
|
35231
|
+
const configPath = resolve2(currentDir, filename);
|
|
35232
|
+
if (existsSync2(configPath)) {
|
|
35233
|
+
return configPath;
|
|
35259
35234
|
}
|
|
35260
|
-
break;
|
|
35261
35235
|
}
|
|
35262
|
-
|
|
35263
|
-
|
|
35264
|
-
|
|
35265
|
-
|
|
35266
|
-
|
|
35267
|
-
|
|
35268
|
-
|
|
35269
|
-
|
|
35270
|
-
|
|
35271
|
-
|
|
35272
|
-
|
|
35236
|
+
const parentDir = dirname8(currentDir);
|
|
35237
|
+
if (parentDir === currentDir) break;
|
|
35238
|
+
currentDir = parentDir;
|
|
35239
|
+
}
|
|
35240
|
+
return null;
|
|
35241
|
+
}
|
|
35242
|
+
function loadConfig(configPath) {
|
|
35243
|
+
try {
|
|
35244
|
+
const content = readFileSync(configPath, "utf-8");
|
|
35245
|
+
const config = JSON.parse(content);
|
|
35246
|
+
return validateConfig2(config);
|
|
35247
|
+
} catch (error) {
|
|
35248
|
+
console.warn(`Warning: Failed to load config from ${configPath}`);
|
|
35249
|
+
return {};
|
|
35250
|
+
}
|
|
35251
|
+
}
|
|
35252
|
+
function validateConfig2(config) {
|
|
35253
|
+
const validated = {};
|
|
35254
|
+
if (typeof config.storage === "string") {
|
|
35255
|
+
validated.storage = config.storage;
|
|
35256
|
+
}
|
|
35257
|
+
if (config.format && ["json", "table", "csv"].includes(config.format)) {
|
|
35258
|
+
validated.format = config.format;
|
|
35259
|
+
}
|
|
35260
|
+
if (typeof config.quiet === "boolean") {
|
|
35261
|
+
validated.quiet = config.quiet;
|
|
35262
|
+
}
|
|
35263
|
+
if (typeof config.verbose === "boolean") {
|
|
35264
|
+
validated.verbose = config.verbose;
|
|
35265
|
+
}
|
|
35266
|
+
return validated;
|
|
35267
|
+
}
|
|
35268
|
+
function mergeConfig2(fileConfig, cliOptions) {
|
|
35269
|
+
return {
|
|
35270
|
+
storage: cliOptions.storage ?? fileConfig.storage ?? "./memory.jsonl",
|
|
35271
|
+
format: cliOptions.format ?? fileConfig.format ?? "json",
|
|
35272
|
+
quiet: cliOptions.quiet ?? fileConfig.quiet ?? false,
|
|
35273
|
+
verbose: cliOptions.verbose ?? fileConfig.verbose ?? false
|
|
35274
|
+
};
|
|
35275
|
+
}
|
|
35276
|
+
var CONFIG_FILES;
|
|
35277
|
+
var init_config = __esm({
|
|
35278
|
+
"src/cli/config.ts"() {
|
|
35279
|
+
"use strict";
|
|
35280
|
+
init_esm_shims();
|
|
35281
|
+
CONFIG_FILES = [
|
|
35282
|
+
".memoryjsrc",
|
|
35283
|
+
".memoryjsrc.json",
|
|
35284
|
+
"memoryjs.config.json"
|
|
35285
|
+
];
|
|
35286
|
+
}
|
|
35287
|
+
});
|
|
35288
|
+
|
|
35289
|
+
// src/cli/formatters.ts
|
|
35290
|
+
import Table from "cli-table3";
|
|
35291
|
+
import chalk from "chalk";
|
|
35292
|
+
function getTerminalWidth() {
|
|
35293
|
+
return process.stdout.columns || 80;
|
|
35294
|
+
}
|
|
35295
|
+
function formatEntities(entities, format) {
|
|
35296
|
+
if (entities.length === 0) {
|
|
35297
|
+
return format === "json" ? "[]" : "No entities found.";
|
|
35298
|
+
}
|
|
35299
|
+
switch (format) {
|
|
35300
|
+
case "json":
|
|
35301
|
+
return JSON.stringify(entities, null, 2);
|
|
35302
|
+
case "table": {
|
|
35303
|
+
const table = new Table({
|
|
35304
|
+
head: [chalk.cyan("Name"), chalk.cyan("Type"), chalk.cyan("Observations"), chalk.cyan("Tags")],
|
|
35305
|
+
colWidths: calculateColWidths(getTerminalWidth(), [0.25, 0.15, 0.4, 0.2]),
|
|
35306
|
+
wordWrap: true
|
|
35307
|
+
});
|
|
35308
|
+
for (const entity of entities) {
|
|
35309
|
+
table.push([
|
|
35310
|
+
entity.name,
|
|
35311
|
+
entity.entityType,
|
|
35312
|
+
(entity.observations || []).slice(0, 3).join("; ") + (entity.observations && entity.observations.length > 3 ? "..." : ""),
|
|
35313
|
+
(entity.tags || []).join(", ")
|
|
35314
|
+
]);
|
|
35273
35315
|
}
|
|
35274
|
-
|
|
35316
|
+
return table.toString();
|
|
35275
35317
|
}
|
|
35276
|
-
case "
|
|
35277
|
-
const
|
|
35278
|
-
|
|
35279
|
-
|
|
35280
|
-
|
|
35281
|
-
|
|
35282
|
-
|
|
35283
|
-
|
|
35284
|
-
|
|
35285
|
-
for (const entity of result.entities.slice(0, 10)) {
|
|
35286
|
-
console.log(` ${chalk2.cyan(entity.name)} [${entity.entityType}]`);
|
|
35287
|
-
if (entity.observations && entity.observations.length > 0) {
|
|
35288
|
-
const preview = entity.observations[0].substring(0, 60);
|
|
35289
|
-
console.log(` ${chalk2.gray(preview)}${entity.observations[0].length > 60 ? "..." : ""}`);
|
|
35290
|
-
}
|
|
35291
|
-
}
|
|
35292
|
-
if (result.entities.length > 10) {
|
|
35293
|
-
console.log(` ... and ${result.entities.length - 10} more`);
|
|
35294
|
-
}
|
|
35295
|
-
break;
|
|
35318
|
+
case "csv": {
|
|
35319
|
+
const header = "name,entityType,observations,tags";
|
|
35320
|
+
const rows = entities.map((e) => [
|
|
35321
|
+
escapeCSV(e.name),
|
|
35322
|
+
escapeCSV(e.entityType),
|
|
35323
|
+
escapeCSV((e.observations || []).join("; ")),
|
|
35324
|
+
escapeCSV((e.tags || []).join(", "))
|
|
35325
|
+
].join(","));
|
|
35326
|
+
return [header, ...rows].join("\n");
|
|
35296
35327
|
}
|
|
35297
|
-
|
|
35298
|
-
|
|
35299
|
-
|
|
35300
|
-
|
|
35301
|
-
|
|
35302
|
-
|
|
35303
|
-
|
|
35304
|
-
|
|
35305
|
-
|
|
35306
|
-
|
|
35307
|
-
|
|
35308
|
-
|
|
35309
|
-
|
|
35328
|
+
}
|
|
35329
|
+
}
|
|
35330
|
+
function formatRelations(relations, format) {
|
|
35331
|
+
if (relations.length === 0) {
|
|
35332
|
+
return format === "json" ? "[]" : "No relations found.";
|
|
35333
|
+
}
|
|
35334
|
+
switch (format) {
|
|
35335
|
+
case "json":
|
|
35336
|
+
return JSON.stringify(relations, null, 2);
|
|
35337
|
+
case "table": {
|
|
35338
|
+
const table = new Table({
|
|
35339
|
+
head: [chalk.cyan("From"), chalk.cyan("Relation"), chalk.cyan("To")],
|
|
35340
|
+
colWidths: calculateColWidths(getTerminalWidth(), [0.35, 0.3, 0.35])
|
|
35341
|
+
});
|
|
35310
35342
|
for (const rel of relations) {
|
|
35311
|
-
|
|
35312
|
-
console.log(` ${chalk2.cyan(name)} --[${rel.relationType}]--> ${rel.to}`);
|
|
35313
|
-
} else {
|
|
35314
|
-
console.log(` ${rel.from} --[${rel.relationType}]--> ${chalk2.cyan(name)}`);
|
|
35315
|
-
}
|
|
35343
|
+
table.push([rel.from, rel.relationType, rel.to]);
|
|
35316
35344
|
}
|
|
35317
|
-
|
|
35345
|
+
return table.toString();
|
|
35318
35346
|
}
|
|
35319
|
-
case "
|
|
35320
|
-
const
|
|
35321
|
-
|
|
35322
|
-
|
|
35323
|
-
|
|
35324
|
-
|
|
35325
|
-
|
|
35326
|
-
|
|
35327
|
-
break;
|
|
35347
|
+
case "csv": {
|
|
35348
|
+
const header = "from,relationType,to";
|
|
35349
|
+
const rows = relations.map((r) => [
|
|
35350
|
+
escapeCSV(r.from),
|
|
35351
|
+
escapeCSV(r.relationType),
|
|
35352
|
+
escapeCSV(r.to)
|
|
35353
|
+
].join(","));
|
|
35354
|
+
return [header, ...rows].join("\n");
|
|
35328
35355
|
}
|
|
35329
|
-
|
|
35330
|
-
|
|
35331
|
-
|
|
35332
|
-
|
|
35333
|
-
|
|
35334
|
-
|
|
35335
|
-
|
|
35336
|
-
|
|
35337
|
-
|
|
35338
|
-
|
|
35339
|
-
|
|
35340
|
-
|
|
35341
|
-
|
|
35356
|
+
}
|
|
35357
|
+
}
|
|
35358
|
+
function formatSearchResults(results, format) {
|
|
35359
|
+
if (results.length === 0) {
|
|
35360
|
+
return format === "json" ? "[]" : "No results found.";
|
|
35361
|
+
}
|
|
35362
|
+
switch (format) {
|
|
35363
|
+
case "json":
|
|
35364
|
+
return JSON.stringify(results, null, 2);
|
|
35365
|
+
case "table": {
|
|
35366
|
+
const table = new Table({
|
|
35367
|
+
head: [chalk.cyan("Name"), chalk.cyan("Type"), chalk.cyan("Score"), chalk.cyan("Observations")],
|
|
35368
|
+
colWidths: calculateColWidths(getTerminalWidth(), [0.25, 0.15, 0.1, 0.5]),
|
|
35369
|
+
wordWrap: true
|
|
35370
|
+
});
|
|
35371
|
+
for (const result of results) {
|
|
35372
|
+
table.push([
|
|
35373
|
+
result.entity.name,
|
|
35374
|
+
result.entity.entityType,
|
|
35375
|
+
result.score !== void 0 ? result.score.toFixed(3) : "-",
|
|
35376
|
+
(result.entity.observations || []).slice(0, 2).join("; ") + (result.entity.observations && result.entity.observations.length > 2 ? "..." : "")
|
|
35377
|
+
]);
|
|
35342
35378
|
}
|
|
35343
|
-
|
|
35379
|
+
return table.toString();
|
|
35344
35380
|
}
|
|
35345
|
-
case "
|
|
35346
|
-
|
|
35347
|
-
|
|
35348
|
-
|
|
35349
|
-
|
|
35350
|
-
|
|
35351
|
-
|
|
35352
|
-
|
|
35353
|
-
|
|
35354
|
-
|
|
35355
|
-
|
|
35356
|
-
|
|
35381
|
+
case "csv": {
|
|
35382
|
+
const header = "name,entityType,score,observations";
|
|
35383
|
+
const rows = results.map((r) => [
|
|
35384
|
+
escapeCSV(r.entity.name),
|
|
35385
|
+
escapeCSV(r.entity.entityType),
|
|
35386
|
+
r.score !== void 0 ? r.score.toFixed(3) : "",
|
|
35387
|
+
escapeCSV((r.entity.observations || []).join("; "))
|
|
35388
|
+
].join(","));
|
|
35389
|
+
return [header, ...rows].join("\n");
|
|
35390
|
+
}
|
|
35391
|
+
}
|
|
35392
|
+
}
|
|
35393
|
+
function formatEntityDetail(entity, format) {
|
|
35394
|
+
if (!entity) {
|
|
35395
|
+
return format === "json" ? "null" : "Entity not found.";
|
|
35396
|
+
}
|
|
35397
|
+
switch (format) {
|
|
35398
|
+
case "json":
|
|
35399
|
+
return JSON.stringify(entity, null, 2);
|
|
35400
|
+
case "table": {
|
|
35401
|
+
const lines = [
|
|
35402
|
+
`${chalk.bold("Name:")} ${entity.name}`,
|
|
35403
|
+
`${chalk.bold("Type:")} ${entity.entityType}`,
|
|
35404
|
+
`${chalk.bold("Importance:")} ${entity.importance ?? "N/A"}`,
|
|
35405
|
+
`${chalk.bold("Tags:")} ${(entity.tags || []).join(", ") || "None"}`,
|
|
35406
|
+
`${chalk.bold("Parent:")} ${entity.parentId || "None"}`,
|
|
35407
|
+
`${chalk.bold("Created:")} ${entity.createdAt || "N/A"}`,
|
|
35408
|
+
`${chalk.bold("Modified:")} ${entity.lastModified || "N/A"}`,
|
|
35409
|
+
"",
|
|
35410
|
+
chalk.bold("Observations:"),
|
|
35411
|
+
...(entity.observations || []).map((o, i) => ` ${i + 1}. ${o}`)
|
|
35412
|
+
];
|
|
35413
|
+
return lines.join("\n");
|
|
35414
|
+
}
|
|
35415
|
+
case "csv": {
|
|
35416
|
+
const header = "field,value";
|
|
35417
|
+
const rows = [
|
|
35418
|
+
`name,${escapeCSV(entity.name)}`,
|
|
35419
|
+
`entityType,${escapeCSV(entity.entityType)}`,
|
|
35420
|
+
`importance,${entity.importance ?? ""}`,
|
|
35421
|
+
`tags,${escapeCSV((entity.tags || []).join("; "))}`,
|
|
35422
|
+
`parentId,${escapeCSV(entity.parentId || "")}`,
|
|
35423
|
+
`observations,${escapeCSV((entity.observations || []).join("; "))}`
|
|
35424
|
+
];
|
|
35425
|
+
return [header, ...rows].join("\n");
|
|
35426
|
+
}
|
|
35427
|
+
}
|
|
35428
|
+
}
|
|
35429
|
+
function formatSuccess(message) {
|
|
35430
|
+
return chalk.green("\u2713") + " " + message;
|
|
35431
|
+
}
|
|
35432
|
+
function formatError(message) {
|
|
35433
|
+
return chalk.red("\u2717") + " " + message;
|
|
35434
|
+
}
|
|
35435
|
+
function formatPath(result, format) {
|
|
35436
|
+
switch (format) {
|
|
35437
|
+
case "json":
|
|
35438
|
+
return JSON.stringify(result, null, 2);
|
|
35439
|
+
case "csv": {
|
|
35440
|
+
const header = "step,entity";
|
|
35441
|
+
const rows = result.path.map((name, i) => `${i},${escapeCSV(name)}`);
|
|
35442
|
+
return [header, ...rows].join("\n");
|
|
35443
|
+
}
|
|
35444
|
+
default: {
|
|
35445
|
+
const lines = [
|
|
35446
|
+
`${chalk.bold("Path")} (${result.length} hops):`,
|
|
35447
|
+
result.path.join(" \u2192 ")
|
|
35448
|
+
];
|
|
35449
|
+
if (result.relations.length > 0) {
|
|
35450
|
+
lines.push("", chalk.bold("Relations:"));
|
|
35451
|
+
for (const rel of result.relations) {
|
|
35452
|
+
lines.push(` ${rel.from} --[${rel.relationType}]--> ${rel.to}`);
|
|
35357
35453
|
}
|
|
35358
|
-
} else {
|
|
35359
|
-
console.log(chalk2.yellow(`No path found between "${pathFrom}" and "${pathTo}"`));
|
|
35360
35454
|
}
|
|
35361
|
-
|
|
35455
|
+
return lines.join("\n");
|
|
35456
|
+
}
|
|
35457
|
+
}
|
|
35458
|
+
}
|
|
35459
|
+
function formatCentrality(result, format) {
|
|
35460
|
+
switch (format) {
|
|
35461
|
+
case "json":
|
|
35462
|
+
return JSON.stringify(
|
|
35463
|
+
{ algorithm: result.algorithm, topEntities: result.topEntities },
|
|
35464
|
+
null,
|
|
35465
|
+
2
|
|
35466
|
+
);
|
|
35467
|
+
case "csv": {
|
|
35468
|
+
const header = "rank,name,score";
|
|
35469
|
+
const rows = result.topEntities.map(
|
|
35470
|
+
(e, i) => `${i + 1},${escapeCSV(e.name)},${e.score.toFixed(4)}`
|
|
35471
|
+
);
|
|
35472
|
+
return [header, ...rows].join("\n");
|
|
35473
|
+
}
|
|
35474
|
+
default: {
|
|
35475
|
+
const table = new Table({
|
|
35476
|
+
head: [chalk.cyan("Rank"), chalk.cyan("Entity"), chalk.cyan("Score")],
|
|
35477
|
+
colWidths: calculateColWidths(getTerminalWidth(), [0.1, 0.6, 0.3])
|
|
35478
|
+
});
|
|
35479
|
+
result.topEntities.forEach((e, i) => {
|
|
35480
|
+
table.push([String(i + 1), e.name, e.score.toFixed(4)]);
|
|
35481
|
+
});
|
|
35482
|
+
return `${chalk.bold(`Centrality (${result.algorithm})`)}
|
|
35483
|
+
${table.toString()}`;
|
|
35484
|
+
}
|
|
35485
|
+
}
|
|
35486
|
+
}
|
|
35487
|
+
function formatComponents(result, format) {
|
|
35488
|
+
switch (format) {
|
|
35489
|
+
case "json":
|
|
35490
|
+
return JSON.stringify(result, null, 2);
|
|
35491
|
+
case "csv": {
|
|
35492
|
+
const header = "component,size,entities";
|
|
35493
|
+
const rows = result.components.map(
|
|
35494
|
+
(comp, i) => `${i + 1},${comp.length},${escapeCSV(comp.join("; "))}`
|
|
35495
|
+
);
|
|
35496
|
+
return [header, ...rows].join("\n");
|
|
35362
35497
|
}
|
|
35363
|
-
|
|
35364
|
-
const
|
|
35365
|
-
|
|
35366
|
-
|
|
35367
|
-
|
|
35368
|
-
|
|
35369
|
-
|
|
35370
|
-
|
|
35371
|
-
|
|
35372
|
-
|
|
35373
|
-
}]);
|
|
35374
|
-
console.log(chalk2.green(`Added observation to ${obsEntity}`));
|
|
35375
|
-
break;
|
|
35498
|
+
default: {
|
|
35499
|
+
const lines = [
|
|
35500
|
+
`${chalk.bold("Connected Components")}: ${result.count} found`,
|
|
35501
|
+
`Largest component size: ${result.largestComponentSize}`,
|
|
35502
|
+
""
|
|
35503
|
+
];
|
|
35504
|
+
result.components.forEach((comp, i) => {
|
|
35505
|
+
lines.push(` Component ${i + 1} (${comp.length} nodes): ${comp.join(", ")}`);
|
|
35506
|
+
});
|
|
35507
|
+
return lines.join("\n");
|
|
35376
35508
|
}
|
|
35377
|
-
|
|
35378
|
-
|
|
35379
|
-
|
|
35380
|
-
|
|
35381
|
-
|
|
35509
|
+
}
|
|
35510
|
+
}
|
|
35511
|
+
function formatValidation(result, format) {
|
|
35512
|
+
switch (format) {
|
|
35513
|
+
case "json":
|
|
35514
|
+
return JSON.stringify(result, null, 2);
|
|
35515
|
+
case "csv": {
|
|
35516
|
+
const header = "type,message";
|
|
35517
|
+
const rows = [];
|
|
35518
|
+
for (const issue of result.issues) {
|
|
35519
|
+
rows.push(`error,${escapeCSV(issue.message)}`);
|
|
35382
35520
|
}
|
|
35383
|
-
|
|
35384
|
-
|
|
35385
|
-
|
|
35521
|
+
for (const warn of result.warnings) {
|
|
35522
|
+
rows.push(`warning,${escapeCSV(warn.message)}`);
|
|
35523
|
+
}
|
|
35524
|
+
return [header, ...rows].join("\n");
|
|
35386
35525
|
}
|
|
35387
|
-
|
|
35388
|
-
const
|
|
35389
|
-
const
|
|
35390
|
-
|
|
35391
|
-
|
|
35392
|
-
|
|
35526
|
+
default: {
|
|
35527
|
+
const status = result.isValid ? chalk.green("\u2713 Valid") : chalk.red("\u2717 Invalid");
|
|
35528
|
+
const lines = [
|
|
35529
|
+
`${chalk.bold("Graph Validation")} \u2014 ${status}`,
|
|
35530
|
+
`Errors: ${result.summary.totalErrors} Warnings: ${result.summary.totalWarnings}`
|
|
35531
|
+
];
|
|
35532
|
+
for (const issue of result.issues) {
|
|
35533
|
+
lines.push(` ${chalk.red("ERROR")}: ${issue.message}`);
|
|
35393
35534
|
}
|
|
35394
|
-
const
|
|
35395
|
-
|
|
35396
|
-
|
|
35397
|
-
|
|
35535
|
+
for (const warn of result.warnings) {
|
|
35536
|
+
lines.push(` ${chalk.yellow("WARN")}: ${warn.message}`);
|
|
35537
|
+
}
|
|
35538
|
+
return lines.join("\n");
|
|
35398
35539
|
}
|
|
35399
|
-
case "history":
|
|
35400
|
-
console.log("\nCommand history:");
|
|
35401
|
-
ictx.history.slice(-20).forEach((cmd, i) => {
|
|
35402
|
-
console.log(` ${i + 1}. ${cmd}`);
|
|
35403
|
-
});
|
|
35404
|
-
break;
|
|
35405
|
-
default:
|
|
35406
|
-
console.log(chalk2.yellow(`Unknown command: ${command}. Type "help" for available commands.`));
|
|
35407
35540
|
}
|
|
35408
35541
|
}
|
|
35409
|
-
function
|
|
35410
|
-
|
|
35411
|
-
|
|
35412
|
-
|
|
35413
|
-
${chalk2.cyan("entities")} / ${chalk2.cyan("ls")} List all entities
|
|
35414
|
-
${chalk2.cyan("get <name>")} Get entity details
|
|
35415
|
-
${chalk2.cyan("search <query>")} Search entities
|
|
35416
|
-
${chalk2.cyan("relations <name>")} Show relations for entity
|
|
35417
|
-
${chalk2.cyan("tags <name>")} Show tags for entity
|
|
35418
|
-
${chalk2.cyan("path <from> <to>")} Find shortest path
|
|
35419
|
-
${chalk2.cyan("observe <e> <text>")} Add observation to entity
|
|
35420
|
-
${chalk2.cyan("delete <name>")} Delete entity
|
|
35421
|
-
${chalk2.cyan("export [format]")} Export graph to stdout
|
|
35422
|
-
${chalk2.cyan("stats")} Show graph statistics
|
|
35423
|
-
${chalk2.cyan("history")} Show command history
|
|
35424
|
-
${chalk2.cyan("clear")} Clear screen
|
|
35425
|
-
${chalk2.cyan("help")} Show this help
|
|
35426
|
-
${chalk2.cyan("exit")} Exit interactive mode
|
|
35427
|
-
|
|
35428
|
-
${chalk2.gray("Tab completion available for entity names.")}
|
|
35429
|
-
`);
|
|
35542
|
+
function calculateColWidths(totalWidth, ratios) {
|
|
35543
|
+
const padding = 4;
|
|
35544
|
+
const available = totalWidth - padding;
|
|
35545
|
+
return ratios.map((r) => Math.max(10, Math.floor(available * r)));
|
|
35430
35546
|
}
|
|
35431
|
-
|
|
35432
|
-
"
|
|
35547
|
+
function escapeCSV(value) {
|
|
35548
|
+
if (value.includes(",") || value.includes('"') || value.includes("\n")) {
|
|
35549
|
+
return `"${value.replace(/"/g, '""')}"`;
|
|
35550
|
+
}
|
|
35551
|
+
return value;
|
|
35552
|
+
}
|
|
35553
|
+
var init_formatters2 = __esm({
|
|
35554
|
+
"src/cli/formatters.ts"() {
|
|
35433
35555
|
"use strict";
|
|
35434
35556
|
init_esm_shims();
|
|
35435
|
-
init_ManagerContext();
|
|
35436
35557
|
}
|
|
35437
35558
|
});
|
|
35438
35559
|
|
|
35439
|
-
// src/cli/index.ts
|
|
35440
|
-
init_esm_shims();
|
|
35441
|
-
import { Command as Command2 } from "commander";
|
|
35442
|
-
|
|
35443
|
-
// src/cli/commands/index.ts
|
|
35444
|
-
init_esm_shims();
|
|
35445
|
-
|
|
35446
|
-
// src/cli/commands/entity.ts
|
|
35447
|
-
init_esm_shims();
|
|
35448
|
-
|
|
35449
35560
|
// src/cli/commands/helpers.ts
|
|
35450
|
-
|
|
35451
|
-
|
|
35452
|
-
|
|
35453
|
-
|
|
35454
|
-
|
|
35455
|
-
var defaultOptions = {
|
|
35456
|
-
storage: process.env.MEMORYJS_STORAGE_PATH || "./memory.jsonl",
|
|
35457
|
-
format: process.env.MEMORYJS_OUTPUT_FORMAT || "json",
|
|
35458
|
-
quiet: false,
|
|
35459
|
-
verbose: false
|
|
35460
|
-
};
|
|
35461
|
-
function parseGlobalOptions(opts) {
|
|
35462
|
-
const rawFormat = opts.outputFormat;
|
|
35463
|
-
const format = rawFormat && ["json", "table", "csv"].includes(rawFormat) ? rawFormat : defaultOptions.format;
|
|
35464
|
-
return {
|
|
35465
|
-
storage: opts.storage || defaultOptions.storage,
|
|
35466
|
-
format,
|
|
35467
|
-
quiet: Boolean(opts.quiet),
|
|
35468
|
-
verbose: Boolean(opts.verbose)
|
|
35469
|
-
};
|
|
35561
|
+
function getOptions(program2) {
|
|
35562
|
+
const cliOpts = program2.opts();
|
|
35563
|
+
const configPath = findConfigFile();
|
|
35564
|
+
const fileConfig = configPath ? loadConfig(configPath) : {};
|
|
35565
|
+
return mergeConfig2(fileConfig, parseGlobalOptions(cliOpts));
|
|
35470
35566
|
}
|
|
35471
|
-
function
|
|
35567
|
+
function createContext(options) {
|
|
35568
|
+
return new ManagerContext(options.storage);
|
|
35569
|
+
}
|
|
35570
|
+
var init_helpers = __esm({
|
|
35571
|
+
"src/cli/commands/helpers.ts"() {
|
|
35572
|
+
"use strict";
|
|
35573
|
+
init_esm_shims();
|
|
35574
|
+
init_ManagerContext();
|
|
35575
|
+
init_options();
|
|
35576
|
+
init_config();
|
|
35577
|
+
init_formatters2();
|
|
35578
|
+
}
|
|
35579
|
+
});
|
|
35580
|
+
|
|
35581
|
+
// src/cli/commands/inspect.ts
|
|
35582
|
+
var inspect_exports = {};
|
|
35583
|
+
__export(inspect_exports, {
|
|
35584
|
+
buildSizeReport: () => buildSizeReport,
|
|
35585
|
+
buildTree: () => buildTree,
|
|
35586
|
+
neighbors: () => neighbors,
|
|
35587
|
+
registerInspectCommands: () => registerInspectCommands,
|
|
35588
|
+
renderTreeAscii: () => renderTreeAscii,
|
|
35589
|
+
snapshotEntity: () => snapshotEntity
|
|
35590
|
+
});
|
|
35591
|
+
import { promises as fs17 } from "fs";
|
|
35592
|
+
async function snapshotEntity(ctx, name) {
|
|
35593
|
+
const graph = await ctx.storage.loadGraph();
|
|
35594
|
+
const entity = ctx.storage.getEntityByName(name);
|
|
35595
|
+
if (!entity) throw new Error(`entity not found: ${name}`);
|
|
35596
|
+
const observations = await ctx.observationManager.getObservationsFor(name);
|
|
35597
|
+
const outgoing = graph.relations.filter((r) => r.from === name).map((r) => ({ to: r.to, type: r.relationType }));
|
|
35598
|
+
const incoming = graph.relations.filter((r) => r.to === name).map((r) => ({ from: r.from, type: r.relationType }));
|
|
35599
|
+
const children = (await ctx.hierarchyManager.getChildren(name)).map((c) => c.name);
|
|
35600
|
+
const ancestors = (await ctx.hierarchyManager.getAncestors(name)).map((a) => a.name);
|
|
35472
35601
|
return {
|
|
35473
|
-
|
|
35474
|
-
|
|
35475
|
-
|
|
35476
|
-
|
|
35602
|
+
name: entity.name,
|
|
35603
|
+
entityType: entity.entityType,
|
|
35604
|
+
observations,
|
|
35605
|
+
tags: entity.tags,
|
|
35606
|
+
importance: entity.importance,
|
|
35607
|
+
createdAt: entity.createdAt,
|
|
35608
|
+
lastModified: entity.lastModified,
|
|
35609
|
+
parentId: entity.parentId,
|
|
35610
|
+
children,
|
|
35611
|
+
ancestors,
|
|
35612
|
+
relations: { outgoing, incoming }
|
|
35477
35613
|
};
|
|
35478
35614
|
}
|
|
35479
|
-
|
|
35480
|
-
|
|
35481
|
-
|
|
35482
|
-
|
|
35483
|
-
|
|
35484
|
-
|
|
35485
|
-
|
|
35486
|
-
|
|
35487
|
-
|
|
35488
|
-
|
|
35489
|
-
function findConfigFile(startDir = process.cwd()) {
|
|
35490
|
-
let currentDir = startDir;
|
|
35491
|
-
const root = resolve2("/");
|
|
35492
|
-
while (currentDir !== root) {
|
|
35493
|
-
for (const filename of CONFIG_FILES) {
|
|
35494
|
-
const configPath = resolve2(currentDir, filename);
|
|
35495
|
-
if (existsSync2(configPath)) {
|
|
35496
|
-
return configPath;
|
|
35497
|
-
}
|
|
35615
|
+
async function buildTree(ctx, root) {
|
|
35616
|
+
await ctx.storage.loadGraph();
|
|
35617
|
+
const rootEntity = ctx.storage.getEntityByName(root);
|
|
35618
|
+
if (!rootEntity) throw new Error(`entity not found: ${root}`);
|
|
35619
|
+
async function walk(name) {
|
|
35620
|
+
const entity = ctx.storage.getEntityByName(name);
|
|
35621
|
+
const children = await ctx.hierarchyManager.getChildren(name);
|
|
35622
|
+
const childNodes = [];
|
|
35623
|
+
for (const c of children) {
|
|
35624
|
+
childNodes.push(await walk(c.name));
|
|
35498
35625
|
}
|
|
35499
|
-
|
|
35500
|
-
|
|
35501
|
-
|
|
35626
|
+
return {
|
|
35627
|
+
name,
|
|
35628
|
+
entityType: entity?.entityType ?? "unknown",
|
|
35629
|
+
children: childNodes
|
|
35630
|
+
};
|
|
35502
35631
|
}
|
|
35503
|
-
return
|
|
35632
|
+
return walk(root);
|
|
35504
35633
|
}
|
|
35505
|
-
function
|
|
35506
|
-
|
|
35507
|
-
|
|
35508
|
-
|
|
35509
|
-
|
|
35510
|
-
|
|
35511
|
-
|
|
35512
|
-
return {};
|
|
35634
|
+
function renderTreeAscii(node, prefix = "", isRoot = true, isLast = true) {
|
|
35635
|
+
const connector = isRoot ? "" : isLast ? "\u2514\u2500\u2500 " : "\u251C\u2500\u2500 ";
|
|
35636
|
+
let out = `${prefix}${connector}${node.name} (${node.entityType})
|
|
35637
|
+
`;
|
|
35638
|
+
const childPrefix = isRoot ? "" : prefix + (isLast ? " " : "\u2502 ");
|
|
35639
|
+
for (let i = 0; i < node.children.length; i++) {
|
|
35640
|
+
out += renderTreeAscii(node.children[i], childPrefix, false, i === node.children.length - 1);
|
|
35513
35641
|
}
|
|
35642
|
+
return out;
|
|
35514
35643
|
}
|
|
35515
|
-
function
|
|
35516
|
-
const
|
|
35517
|
-
|
|
35518
|
-
|
|
35519
|
-
|
|
35520
|
-
|
|
35521
|
-
|
|
35522
|
-
}
|
|
35523
|
-
|
|
35524
|
-
|
|
35525
|
-
|
|
35526
|
-
|
|
35527
|
-
|
|
35644
|
+
async function buildSizeReport(ctx, storagePath) {
|
|
35645
|
+
const graph = await ctx.storage.loadGraph();
|
|
35646
|
+
let observationCount = 0;
|
|
35647
|
+
const tagSet = /* @__PURE__ */ new Set();
|
|
35648
|
+
for (const e of graph.entities) {
|
|
35649
|
+
observationCount += e.observations.length;
|
|
35650
|
+
if (e.tags) for (const t of e.tags) tagSet.add(t);
|
|
35651
|
+
}
|
|
35652
|
+
let exists = false;
|
|
35653
|
+
let sizeBytes = 0;
|
|
35654
|
+
let lineCount = 0;
|
|
35655
|
+
try {
|
|
35656
|
+
const stat = await fs17.stat(storagePath);
|
|
35657
|
+
exists = true;
|
|
35658
|
+
sizeBytes = stat.size;
|
|
35659
|
+
if (sizeBytes > 0) {
|
|
35660
|
+
const content = await fs17.readFile(storagePath, "utf8");
|
|
35661
|
+
lineCount = content.split("\n").filter((l) => l.length > 0).length;
|
|
35662
|
+
}
|
|
35663
|
+
} catch {
|
|
35528
35664
|
}
|
|
35529
|
-
return validated;
|
|
35530
|
-
}
|
|
35531
|
-
function mergeConfig2(fileConfig, cliOptions) {
|
|
35532
35665
|
return {
|
|
35533
|
-
|
|
35534
|
-
|
|
35535
|
-
|
|
35536
|
-
|
|
35666
|
+
graph: {
|
|
35667
|
+
entities: graph.entities.length,
|
|
35668
|
+
relations: graph.relations.length,
|
|
35669
|
+
observations: observationCount,
|
|
35670
|
+
distinctTags: tagSet.size,
|
|
35671
|
+
avgObservationsPerEntity: graph.entities.length === 0 ? 0 : Number((observationCount / graph.entities.length).toFixed(2))
|
|
35672
|
+
},
|
|
35673
|
+
storage: {
|
|
35674
|
+
path: storagePath,
|
|
35675
|
+
exists,
|
|
35676
|
+
sizeBytes,
|
|
35677
|
+
lineCount
|
|
35678
|
+
}
|
|
35537
35679
|
};
|
|
35538
35680
|
}
|
|
35539
|
-
|
|
35540
|
-
|
|
35541
|
-
|
|
35542
|
-
|
|
35543
|
-
|
|
35544
|
-
|
|
35545
|
-
return
|
|
35681
|
+
async function neighbors(ctx, name) {
|
|
35682
|
+
const graph = await ctx.storage.loadGraph();
|
|
35683
|
+
const entity = ctx.storage.getEntityByName(name);
|
|
35684
|
+
if (!entity) throw new Error(`entity not found: ${name}`);
|
|
35685
|
+
const outgoing = graph.relations.filter((r) => r.from === name).map((r) => ({ to: r.to, type: r.relationType }));
|
|
35686
|
+
const incoming = graph.relations.filter((r) => r.to === name).map((r) => ({ from: r.from, type: r.relationType }));
|
|
35687
|
+
return {
|
|
35688
|
+
entity: name,
|
|
35689
|
+
outgoing,
|
|
35690
|
+
incoming,
|
|
35691
|
+
outDegree: outgoing.length,
|
|
35692
|
+
inDegree: incoming.length
|
|
35693
|
+
};
|
|
35546
35694
|
}
|
|
35547
|
-
function
|
|
35548
|
-
|
|
35549
|
-
|
|
35550
|
-
|
|
35551
|
-
|
|
35552
|
-
|
|
35553
|
-
|
|
35554
|
-
|
|
35555
|
-
|
|
35556
|
-
|
|
35557
|
-
|
|
35558
|
-
|
|
35559
|
-
|
|
35560
|
-
|
|
35561
|
-
|
|
35562
|
-
|
|
35563
|
-
|
|
35564
|
-
|
|
35565
|
-
|
|
35566
|
-
|
|
35695
|
+
function registerInspectCommands(program2) {
|
|
35696
|
+
program2.command("show <entity>").description("Verbose snapshot of one entity (observations, relations in/out, tags, hierarchy, timestamps)").action(async (entity) => {
|
|
35697
|
+
const options = getOptions(program2);
|
|
35698
|
+
const logger2 = createLogger(options);
|
|
35699
|
+
const ctx = createContext(options);
|
|
35700
|
+
try {
|
|
35701
|
+
const snap = await snapshotEntity(ctx, entity);
|
|
35702
|
+
console.log(JSON.stringify(snap, null, 2));
|
|
35703
|
+
} catch (e) {
|
|
35704
|
+
logger2.error(formatError(e.message));
|
|
35705
|
+
process.exit(1);
|
|
35706
|
+
}
|
|
35707
|
+
});
|
|
35708
|
+
program2.command("tree [root]").description("Hierarchy tree from a root entity (or all roots when omitted)").option("--ascii", "Render as ASCII tree instead of JSON (overrides --output-format)").action(async (root, opts) => {
|
|
35709
|
+
const options = getOptions(program2);
|
|
35710
|
+
const logger2 = createLogger(options);
|
|
35711
|
+
const ctx = createContext(options);
|
|
35712
|
+
try {
|
|
35713
|
+
let trees;
|
|
35714
|
+
if (root) {
|
|
35715
|
+
trees = [await buildTree(ctx, root)];
|
|
35716
|
+
} else {
|
|
35717
|
+
const roots = await ctx.hierarchyManager.getRootEntities();
|
|
35718
|
+
trees = await Promise.all(roots.map((r) => buildTree(ctx, r.name)));
|
|
35567
35719
|
}
|
|
35568
|
-
|
|
35720
|
+
if (opts.ascii) {
|
|
35721
|
+
for (const t of trees) {
|
|
35722
|
+
process.stdout.write(renderTreeAscii(t));
|
|
35723
|
+
}
|
|
35724
|
+
} else {
|
|
35725
|
+
console.log(JSON.stringify(trees, null, 2));
|
|
35726
|
+
}
|
|
35727
|
+
} catch (e) {
|
|
35728
|
+
logger2.error(formatError(e.message));
|
|
35729
|
+
process.exit(1);
|
|
35569
35730
|
}
|
|
35570
|
-
|
|
35571
|
-
|
|
35572
|
-
|
|
35573
|
-
|
|
35574
|
-
|
|
35575
|
-
|
|
35576
|
-
|
|
35577
|
-
|
|
35578
|
-
|
|
35731
|
+
});
|
|
35732
|
+
program2.command("neighbors <entity>").description("Incoming + outgoing relations of one entity (with in/out degree counts)").action(async (entity) => {
|
|
35733
|
+
const options = getOptions(program2);
|
|
35734
|
+
const logger2 = createLogger(options);
|
|
35735
|
+
const ctx = createContext(options);
|
|
35736
|
+
try {
|
|
35737
|
+
const report = await neighbors(ctx, entity);
|
|
35738
|
+
console.log(JSON.stringify(report, null, 2));
|
|
35739
|
+
} catch (e) {
|
|
35740
|
+
logger2.error(formatError(e.message));
|
|
35741
|
+
process.exit(1);
|
|
35579
35742
|
}
|
|
35580
|
-
}
|
|
35743
|
+
});
|
|
35744
|
+
program2.command("size").description("Graph size + storage footprint summary (entity/relation/observation counts, file bytes, line count)").action(async () => {
|
|
35745
|
+
const options = getOptions(program2);
|
|
35746
|
+
const logger2 = createLogger(options);
|
|
35747
|
+
const ctx = createContext(options);
|
|
35748
|
+
try {
|
|
35749
|
+
const report = await buildSizeReport(ctx, options.storage);
|
|
35750
|
+
console.log(JSON.stringify(report, null, 2));
|
|
35751
|
+
} catch (e) {
|
|
35752
|
+
logger2.error(formatError(e.message));
|
|
35753
|
+
process.exit(1);
|
|
35754
|
+
}
|
|
35755
|
+
});
|
|
35581
35756
|
}
|
|
35582
|
-
|
|
35583
|
-
|
|
35584
|
-
|
|
35757
|
+
var init_inspect = __esm({
|
|
35758
|
+
"src/cli/commands/inspect.ts"() {
|
|
35759
|
+
"use strict";
|
|
35760
|
+
init_esm_shims();
|
|
35761
|
+
init_helpers();
|
|
35762
|
+
init_formatters2();
|
|
35585
35763
|
}
|
|
35586
|
-
|
|
35587
|
-
|
|
35588
|
-
|
|
35589
|
-
|
|
35590
|
-
|
|
35591
|
-
|
|
35592
|
-
|
|
35593
|
-
|
|
35594
|
-
|
|
35595
|
-
|
|
35596
|
-
|
|
35597
|
-
|
|
35764
|
+
});
|
|
35765
|
+
|
|
35766
|
+
// src/cli/interactive.ts
|
|
35767
|
+
var interactive_exports = {};
|
|
35768
|
+
__export(interactive_exports, {
|
|
35769
|
+
startInteractiveMode: () => startInteractiveMode
|
|
35770
|
+
});
|
|
35771
|
+
import * as readline from "readline";
|
|
35772
|
+
import chalk2 from "chalk";
|
|
35773
|
+
async function startInteractiveMode(options) {
|
|
35774
|
+
const ctx = new ManagerContext(options.storage);
|
|
35775
|
+
const interactiveCtx = {
|
|
35776
|
+
ctx,
|
|
35777
|
+
options,
|
|
35778
|
+
history: []
|
|
35779
|
+
};
|
|
35780
|
+
const graph = await ctx.storage.loadGraph();
|
|
35781
|
+
const entityNames = graph.entities.map((e) => e.name);
|
|
35782
|
+
const rl = readline.createInterface({
|
|
35783
|
+
input: process.stdin,
|
|
35784
|
+
output: process.stdout,
|
|
35785
|
+
prompt: chalk2.cyan("memory> "),
|
|
35786
|
+
completer: (line) => {
|
|
35787
|
+
const completions = [
|
|
35788
|
+
"entities",
|
|
35789
|
+
"relations",
|
|
35790
|
+
"search",
|
|
35791
|
+
"get",
|
|
35792
|
+
"stats",
|
|
35793
|
+
"tags",
|
|
35794
|
+
"path",
|
|
35795
|
+
"observe",
|
|
35796
|
+
"delete",
|
|
35797
|
+
"export",
|
|
35798
|
+
"help",
|
|
35799
|
+
"exit",
|
|
35800
|
+
"clear",
|
|
35801
|
+
"history",
|
|
35802
|
+
...entityNames
|
|
35803
|
+
];
|
|
35804
|
+
const hits = completions.filter((c) => c.toLowerCase().startsWith(line.toLowerCase()));
|
|
35805
|
+
return [hits.length ? hits : completions, line];
|
|
35598
35806
|
}
|
|
35599
|
-
|
|
35600
|
-
|
|
35601
|
-
|
|
35602
|
-
|
|
35603
|
-
|
|
35604
|
-
|
|
35605
|
-
|
|
35606
|
-
|
|
35807
|
+
});
|
|
35808
|
+
console.log(chalk2.green("MemoryJS Interactive Mode"));
|
|
35809
|
+
console.log(chalk2.gray('Type "help" for commands, "exit" to quit.\n'));
|
|
35810
|
+
rl.prompt();
|
|
35811
|
+
rl.on("line", async (line) => {
|
|
35812
|
+
const trimmed = line.trim();
|
|
35813
|
+
if (!trimmed) {
|
|
35814
|
+
rl.prompt();
|
|
35815
|
+
return;
|
|
35607
35816
|
}
|
|
35608
|
-
|
|
35817
|
+
interactiveCtx.history.push(trimmed);
|
|
35818
|
+
try {
|
|
35819
|
+
await processCommand(trimmed, interactiveCtx, rl);
|
|
35820
|
+
} catch (error) {
|
|
35821
|
+
console.error(chalk2.red(`Error: ${error.message}`));
|
|
35822
|
+
}
|
|
35823
|
+
rl.prompt();
|
|
35824
|
+
});
|
|
35825
|
+
rl.on("close", () => {
|
|
35826
|
+
console.log(chalk2.gray("\nGoodbye!"));
|
|
35827
|
+
process.exit(0);
|
|
35828
|
+
});
|
|
35609
35829
|
}
|
|
35610
|
-
function
|
|
35611
|
-
|
|
35612
|
-
|
|
35613
|
-
|
|
35614
|
-
|
|
35615
|
-
case "
|
|
35616
|
-
|
|
35617
|
-
|
|
35618
|
-
|
|
35619
|
-
|
|
35620
|
-
|
|
35621
|
-
|
|
35622
|
-
|
|
35623
|
-
|
|
35624
|
-
|
|
35625
|
-
|
|
35626
|
-
|
|
35627
|
-
|
|
35628
|
-
|
|
35629
|
-
|
|
35830
|
+
async function processCommand(input, ictx, rl) {
|
|
35831
|
+
const [command, ...args] = input.split(/\s+/);
|
|
35832
|
+
const ctx = ictx.ctx;
|
|
35833
|
+
switch (command.toLowerCase()) {
|
|
35834
|
+
case "help":
|
|
35835
|
+
case ".help":
|
|
35836
|
+
showHelp();
|
|
35837
|
+
break;
|
|
35838
|
+
case "exit":
|
|
35839
|
+
case ".exit":
|
|
35840
|
+
case "quit":
|
|
35841
|
+
rl.close();
|
|
35842
|
+
break;
|
|
35843
|
+
case "clear":
|
|
35844
|
+
case ".clear":
|
|
35845
|
+
console.clear();
|
|
35846
|
+
break;
|
|
35847
|
+
case "entities":
|
|
35848
|
+
case "ls": {
|
|
35849
|
+
const graph = await ctx.storage.loadGraph();
|
|
35850
|
+
const entities = graph.entities;
|
|
35851
|
+
console.log(`
|
|
35852
|
+
Entities (${entities.length}):`);
|
|
35853
|
+
for (const e of entities.slice(0, 20)) {
|
|
35854
|
+
console.log(` ${chalk2.cyan(e.name)} [${e.entityType}]`);
|
|
35630
35855
|
}
|
|
35631
|
-
|
|
35856
|
+
if (entities.length > 20) {
|
|
35857
|
+
console.log(` ... and ${entities.length - 20} more`);
|
|
35858
|
+
}
|
|
35859
|
+
break;
|
|
35632
35860
|
}
|
|
35633
|
-
case "
|
|
35634
|
-
const
|
|
35635
|
-
|
|
35636
|
-
|
|
35637
|
-
|
|
35638
|
-
|
|
35639
|
-
|
|
35640
|
-
|
|
35641
|
-
|
|
35861
|
+
case "get": {
|
|
35862
|
+
const name = args.join(" ");
|
|
35863
|
+
if (!name) {
|
|
35864
|
+
console.log(chalk2.yellow("Usage: get <entity-name>"));
|
|
35865
|
+
break;
|
|
35866
|
+
}
|
|
35867
|
+
const entity = await ctx.entityManager.getEntity(name);
|
|
35868
|
+
if (entity) {
|
|
35869
|
+
console.log(JSON.stringify(entity, null, 2));
|
|
35870
|
+
} else {
|
|
35871
|
+
console.log(chalk2.yellow(`Entity not found: ${name}`));
|
|
35872
|
+
}
|
|
35873
|
+
break;
|
|
35642
35874
|
}
|
|
35643
|
-
|
|
35644
|
-
|
|
35645
|
-
|
|
35646
|
-
|
|
35647
|
-
|
|
35648
|
-
|
|
35649
|
-
|
|
35650
|
-
|
|
35651
|
-
|
|
35652
|
-
|
|
35653
|
-
|
|
35654
|
-
|
|
35655
|
-
|
|
35656
|
-
|
|
35657
|
-
|
|
35658
|
-
|
|
35659
|
-
|
|
35660
|
-
|
|
35661
|
-
|
|
35662
|
-
|
|
35663
|
-
|
|
35664
|
-
|
|
35665
|
-
|
|
35875
|
+
case "search": {
|
|
35876
|
+
const query = args.join(" ");
|
|
35877
|
+
if (!query) {
|
|
35878
|
+
console.log(chalk2.yellow("Usage: search <query>"));
|
|
35879
|
+
break;
|
|
35880
|
+
}
|
|
35881
|
+
const result = await ctx.searchManager.searchNodes(query);
|
|
35882
|
+
console.log(`
|
|
35883
|
+
Search results for "${query}":`);
|
|
35884
|
+
for (const entity of result.entities.slice(0, 10)) {
|
|
35885
|
+
console.log(` ${chalk2.cyan(entity.name)} [${entity.entityType}]`);
|
|
35886
|
+
if (entity.observations && entity.observations.length > 0) {
|
|
35887
|
+
const preview = entity.observations[0].substring(0, 60);
|
|
35888
|
+
console.log(` ${chalk2.gray(preview)}${entity.observations[0].length > 60 ? "..." : ""}`);
|
|
35889
|
+
}
|
|
35890
|
+
}
|
|
35891
|
+
if (result.entities.length > 10) {
|
|
35892
|
+
console.log(` ... and ${result.entities.length - 10} more`);
|
|
35893
|
+
}
|
|
35894
|
+
break;
|
|
35895
|
+
}
|
|
35896
|
+
case "relations": {
|
|
35897
|
+
const name = args.join(" ");
|
|
35898
|
+
if (!name) {
|
|
35899
|
+
console.log(chalk2.yellow("Usage: relations <entity-name>"));
|
|
35900
|
+
break;
|
|
35901
|
+
}
|
|
35902
|
+
const relations = await ctx.relationManager.getRelations(name);
|
|
35903
|
+
if (relations.length === 0) {
|
|
35904
|
+
console.log(chalk2.yellow(`No relations found for: ${name}`));
|
|
35905
|
+
break;
|
|
35906
|
+
}
|
|
35907
|
+
console.log(`
|
|
35908
|
+
Relations for "${name}":`);
|
|
35909
|
+
for (const rel of relations) {
|
|
35910
|
+
if (rel.from === name) {
|
|
35911
|
+
console.log(` ${chalk2.cyan(name)} --[${rel.relationType}]--> ${rel.to}`);
|
|
35912
|
+
} else {
|
|
35913
|
+
console.log(` ${rel.from} --[${rel.relationType}]--> ${chalk2.cyan(name)}`);
|
|
35914
|
+
}
|
|
35915
|
+
}
|
|
35916
|
+
break;
|
|
35666
35917
|
}
|
|
35667
|
-
case "
|
|
35668
|
-
const
|
|
35669
|
-
|
|
35670
|
-
|
|
35671
|
-
|
|
35672
|
-
|
|
35673
|
-
|
|
35674
|
-
|
|
35675
|
-
|
|
35676
|
-
];
|
|
35677
|
-
return [header, ...rows].join("\n");
|
|
35918
|
+
case "stats": {
|
|
35919
|
+
const stats = await ctx.analyticsManager.getGraphStats();
|
|
35920
|
+
console.log(`
|
|
35921
|
+
Knowledge Graph Statistics:`);
|
|
35922
|
+
console.log(` Entities: ${stats.totalEntities}`);
|
|
35923
|
+
console.log(` Relations: ${stats.totalRelations}`);
|
|
35924
|
+
console.log(` Entity Types: ${Object.keys(stats.entityTypesCounts).length}`);
|
|
35925
|
+
console.log(` Relation Types: ${Object.keys(stats.relationTypesCounts).length}`);
|
|
35926
|
+
break;
|
|
35678
35927
|
}
|
|
35679
|
-
|
|
35680
|
-
|
|
35681
|
-
|
|
35682
|
-
|
|
35683
|
-
|
|
35684
|
-
|
|
35685
|
-
|
|
35686
|
-
|
|
35687
|
-
|
|
35688
|
-
|
|
35689
|
-
|
|
35690
|
-
|
|
35691
|
-
|
|
35692
|
-
|
|
35693
|
-
|
|
35694
|
-
return [header, ...rows].join("\n");
|
|
35928
|
+
case "tags": {
|
|
35929
|
+
const tagName = args.join(" ");
|
|
35930
|
+
if (!tagName) {
|
|
35931
|
+
console.log(chalk2.yellow("Usage: tags <entity-name>"));
|
|
35932
|
+
break;
|
|
35933
|
+
}
|
|
35934
|
+
const tagEntity = await ctx.entityManager.getEntity(tagName);
|
|
35935
|
+
if (tagEntity) {
|
|
35936
|
+
const tags = tagEntity.tags || [];
|
|
35937
|
+
console.log(`
|
|
35938
|
+
Tags for "${tagName}": ${tags.length > 0 ? tags.join(", ") : "None"}`);
|
|
35939
|
+
} else {
|
|
35940
|
+
console.log(chalk2.yellow(`Entity not found: ${tagName}`));
|
|
35941
|
+
}
|
|
35942
|
+
break;
|
|
35695
35943
|
}
|
|
35696
|
-
|
|
35697
|
-
|
|
35698
|
-
|
|
35699
|
-
|
|
35700
|
-
|
|
35701
|
-
|
|
35702
|
-
|
|
35703
|
-
|
|
35704
|
-
|
|
35944
|
+
case "path": {
|
|
35945
|
+
if (args.length < 2) {
|
|
35946
|
+
console.log(chalk2.yellow("Usage: path <from> <to>"));
|
|
35947
|
+
break;
|
|
35948
|
+
}
|
|
35949
|
+
const [pathFrom, pathTo] = args;
|
|
35950
|
+
const pathResult = await ctx.graphTraversal.findShortestPath(pathFrom, pathTo);
|
|
35951
|
+
if (pathResult) {
|
|
35952
|
+
console.log(`
|
|
35953
|
+
Path (${pathResult.length} hops): ${pathResult.path.join(" -> ")}`);
|
|
35954
|
+
for (const rel of pathResult.relations) {
|
|
35955
|
+
console.log(` ${rel.from} --[${rel.relationType}]--> ${rel.to}`);
|
|
35705
35956
|
}
|
|
35957
|
+
} else {
|
|
35958
|
+
console.log(chalk2.yellow(`No path found between "${pathFrom}" and "${pathTo}"`));
|
|
35706
35959
|
}
|
|
35707
|
-
|
|
35960
|
+
break;
|
|
35708
35961
|
}
|
|
35709
|
-
|
|
35710
|
-
|
|
35711
|
-
|
|
35712
|
-
|
|
35713
|
-
|
|
35714
|
-
|
|
35715
|
-
|
|
35716
|
-
|
|
35717
|
-
|
|
35718
|
-
|
|
35719
|
-
|
|
35720
|
-
|
|
35721
|
-
|
|
35722
|
-
(e, i) => `${i + 1},${escapeCSV(e.name)},${e.score.toFixed(4)}`
|
|
35723
|
-
);
|
|
35724
|
-
return [header, ...rows].join("\n");
|
|
35962
|
+
case "observe": {
|
|
35963
|
+
const obsEntity = args[0];
|
|
35964
|
+
const obsText = args.slice(1).join(" ");
|
|
35965
|
+
if (!obsEntity || !obsText) {
|
|
35966
|
+
console.log(chalk2.yellow("Usage: observe <entity> <observation text>"));
|
|
35967
|
+
break;
|
|
35968
|
+
}
|
|
35969
|
+
await ctx.observationManager.addObservations([{
|
|
35970
|
+
entityName: obsEntity,
|
|
35971
|
+
contents: [obsText]
|
|
35972
|
+
}]);
|
|
35973
|
+
console.log(chalk2.green(`Added observation to ${obsEntity}`));
|
|
35974
|
+
break;
|
|
35725
35975
|
}
|
|
35726
|
-
|
|
35727
|
-
const
|
|
35728
|
-
|
|
35729
|
-
|
|
35730
|
-
|
|
35731
|
-
|
|
35732
|
-
|
|
35733
|
-
});
|
|
35734
|
-
|
|
35735
|
-
${table.toString()}`;
|
|
35976
|
+
case "delete": {
|
|
35977
|
+
const delName = args.join(" ");
|
|
35978
|
+
if (!delName) {
|
|
35979
|
+
console.log(chalk2.yellow("Usage: delete <entity-name>"));
|
|
35980
|
+
break;
|
|
35981
|
+
}
|
|
35982
|
+
await ctx.entityManager.deleteEntities([delName]);
|
|
35983
|
+
console.log(chalk2.green(`Deleted entity: ${delName}`));
|
|
35984
|
+
break;
|
|
35736
35985
|
}
|
|
35737
|
-
|
|
35738
|
-
|
|
35739
|
-
|
|
35740
|
-
|
|
35741
|
-
|
|
35742
|
-
|
|
35743
|
-
|
|
35744
|
-
const
|
|
35745
|
-
const
|
|
35746
|
-
|
|
35747
|
-
|
|
35748
|
-
return [header, ...rows].join("\n");
|
|
35986
|
+
case "export": {
|
|
35987
|
+
const validFormats = ["json", "csv", "graphml", "gexf", "dot", "markdown", "mermaid", "turtle", "rdf-xml", "json-ld"];
|
|
35988
|
+
const fmt = args[0] || "json";
|
|
35989
|
+
if (!validFormats.includes(fmt)) {
|
|
35990
|
+
console.log(chalk2.yellow(`Invalid format: ${fmt}. Use: ${validFormats.join(", ")}`));
|
|
35991
|
+
break;
|
|
35992
|
+
}
|
|
35993
|
+
const exportGraph = await ctx.storage.loadGraph();
|
|
35994
|
+
const output = ctx.ioManager.exportGraph(exportGraph, fmt);
|
|
35995
|
+
console.log(output);
|
|
35996
|
+
break;
|
|
35749
35997
|
}
|
|
35750
|
-
|
|
35751
|
-
|
|
35752
|
-
|
|
35753
|
-
`
|
|
35754
|
-
""
|
|
35755
|
-
];
|
|
35756
|
-
result.components.forEach((comp, i) => {
|
|
35757
|
-
lines.push(` Component ${i + 1} (${comp.length} nodes): ${comp.join(", ")}`);
|
|
35998
|
+
case "history":
|
|
35999
|
+
console.log("\nCommand history:");
|
|
36000
|
+
ictx.history.slice(-20).forEach((cmd, i) => {
|
|
36001
|
+
console.log(` ${i + 1}. ${cmd}`);
|
|
35758
36002
|
});
|
|
35759
|
-
|
|
35760
|
-
|
|
35761
|
-
|
|
35762
|
-
|
|
35763
|
-
|
|
35764
|
-
|
|
35765
|
-
case "json":
|
|
35766
|
-
return JSON.stringify(result, null, 2);
|
|
35767
|
-
case "csv": {
|
|
35768
|
-
const header = "type,message";
|
|
35769
|
-
const rows = [];
|
|
35770
|
-
for (const issue of result.issues) {
|
|
35771
|
-
rows.push(`error,${escapeCSV(issue.message)}`);
|
|
36003
|
+
break;
|
|
36004
|
+
case "show": {
|
|
36005
|
+
const name = args.join(" ");
|
|
36006
|
+
if (!name) {
|
|
36007
|
+
console.log(chalk2.yellow("Usage: show <entity-name>"));
|
|
36008
|
+
break;
|
|
35772
36009
|
}
|
|
35773
|
-
|
|
35774
|
-
|
|
36010
|
+
const { snapshotEntity: snapshotEntity2 } = await Promise.resolve().then(() => (init_inspect(), inspect_exports));
|
|
36011
|
+
try {
|
|
36012
|
+
const snap = await snapshotEntity2(ctx, name);
|
|
36013
|
+
console.log(JSON.stringify(snap, null, 2));
|
|
36014
|
+
} catch (e) {
|
|
36015
|
+
console.log(chalk2.yellow(e.message));
|
|
35775
36016
|
}
|
|
35776
|
-
|
|
36017
|
+
break;
|
|
35777
36018
|
}
|
|
35778
|
-
|
|
35779
|
-
const
|
|
35780
|
-
const
|
|
35781
|
-
|
|
35782
|
-
|
|
35783
|
-
|
|
35784
|
-
|
|
35785
|
-
|
|
36019
|
+
case "tree": {
|
|
36020
|
+
const root = args[0];
|
|
36021
|
+
const { buildTree: buildTree2, renderTreeAscii: renderTreeAscii2 } = await Promise.resolve().then(() => (init_inspect(), inspect_exports));
|
|
36022
|
+
try {
|
|
36023
|
+
if (root) {
|
|
36024
|
+
const t = await buildTree2(ctx, root);
|
|
36025
|
+
process.stdout.write(renderTreeAscii2(t));
|
|
36026
|
+
} else {
|
|
36027
|
+
const roots = await ctx.hierarchyManager.getRootEntities();
|
|
36028
|
+
for (const r of roots) {
|
|
36029
|
+
const t = await buildTree2(ctx, r.name);
|
|
36030
|
+
process.stdout.write(renderTreeAscii2(t));
|
|
36031
|
+
}
|
|
36032
|
+
}
|
|
36033
|
+
} catch (e) {
|
|
36034
|
+
console.log(chalk2.yellow(e.message));
|
|
35786
36035
|
}
|
|
35787
|
-
|
|
35788
|
-
|
|
36036
|
+
break;
|
|
36037
|
+
}
|
|
36038
|
+
case "neighbors": {
|
|
36039
|
+
const name = args.join(" ");
|
|
36040
|
+
if (!name) {
|
|
36041
|
+
console.log(chalk2.yellow("Usage: neighbors <entity-name>"));
|
|
36042
|
+
break;
|
|
35789
36043
|
}
|
|
35790
|
-
|
|
36044
|
+
const { neighbors: neighbors2 } = await Promise.resolve().then(() => (init_inspect(), inspect_exports));
|
|
36045
|
+
try {
|
|
36046
|
+
const report = await neighbors2(ctx, name);
|
|
36047
|
+
console.log(JSON.stringify(report, null, 2));
|
|
36048
|
+
} catch (e) {
|
|
36049
|
+
console.log(chalk2.yellow(e.message));
|
|
36050
|
+
}
|
|
36051
|
+
break;
|
|
35791
36052
|
}
|
|
36053
|
+
case "diag":
|
|
36054
|
+
case "health": {
|
|
36055
|
+
const graph = await ctx.storage.loadGraph();
|
|
36056
|
+
const names = new Set(graph.entities.map((e) => e.name));
|
|
36057
|
+
const orphans = graph.relations.filter((r) => !names.has(r.from) || !names.has(r.to)).length;
|
|
36058
|
+
const dupNames = graph.entities.length - names.size;
|
|
36059
|
+
console.log(JSON.stringify({
|
|
36060
|
+
entities: graph.entities.length,
|
|
36061
|
+
relations: graph.relations.length,
|
|
36062
|
+
orphan_relations: orphans,
|
|
36063
|
+
duplicate_names: dupNames,
|
|
36064
|
+
storage: ictx.options.storage
|
|
36065
|
+
}, null, 2));
|
|
36066
|
+
break;
|
|
36067
|
+
}
|
|
36068
|
+
case "size": {
|
|
36069
|
+
const { buildSizeReport: buildSizeReport2 } = await Promise.resolve().then(() => (init_inspect(), inspect_exports));
|
|
36070
|
+
const report = await buildSizeReport2(ctx, ictx.options.storage);
|
|
36071
|
+
console.log(JSON.stringify(report, null, 2));
|
|
36072
|
+
break;
|
|
36073
|
+
}
|
|
36074
|
+
default:
|
|
36075
|
+
console.log(chalk2.yellow(`Unknown command: ${command}. Type "help" for available commands.`));
|
|
35792
36076
|
}
|
|
35793
36077
|
}
|
|
35794
|
-
function
|
|
35795
|
-
|
|
35796
|
-
|
|
35797
|
-
return ratios.map((r) => Math.max(10, Math.floor(available * r)));
|
|
35798
|
-
}
|
|
35799
|
-
function escapeCSV(value) {
|
|
35800
|
-
if (value.includes(",") || value.includes('"') || value.includes("\n")) {
|
|
35801
|
-
return `"${value.replace(/"/g, '""')}"`;
|
|
35802
|
-
}
|
|
35803
|
-
return value;
|
|
35804
|
-
}
|
|
36078
|
+
function showHelp() {
|
|
36079
|
+
console.log(`
|
|
36080
|
+
${chalk2.green("Available Commands:")}
|
|
35805
36081
|
|
|
35806
|
-
|
|
35807
|
-
|
|
35808
|
-
|
|
35809
|
-
|
|
35810
|
-
|
|
35811
|
-
|
|
35812
|
-
}
|
|
35813
|
-
|
|
35814
|
-
|
|
36082
|
+
${chalk2.cyan("entities")} / ${chalk2.cyan("ls")} List all entities
|
|
36083
|
+
${chalk2.cyan("get <name>")} Get entity details
|
|
36084
|
+
${chalk2.cyan("search <query>")} Search entities
|
|
36085
|
+
${chalk2.cyan("relations <name>")} Show relations for entity
|
|
36086
|
+
${chalk2.cyan("tags <name>")} Show tags for entity
|
|
36087
|
+
${chalk2.cyan("path <from> <to>")} Find shortest path
|
|
36088
|
+
${chalk2.cyan("observe <e> <text>")} Add observation to entity
|
|
36089
|
+
${chalk2.cyan("delete <name>")} Delete entity
|
|
36090
|
+
${chalk2.cyan("export [format]")} Export graph to stdout
|
|
36091
|
+
${chalk2.cyan("stats")} Show graph statistics
|
|
36092
|
+
${chalk2.cyan("show <name>")} Verbose entity snapshot (obs + relations + hierarchy)
|
|
36093
|
+
${chalk2.cyan("tree [root]")} ASCII hierarchy tree (all roots if omitted)
|
|
36094
|
+
${chalk2.cyan("neighbors <name>")} Incoming + outgoing relations + degree counts
|
|
36095
|
+
${chalk2.cyan("diag")} / ${chalk2.cyan("health")} Quick integrity summary
|
|
36096
|
+
${chalk2.cyan("size")} Graph + storage footprint
|
|
36097
|
+
${chalk2.cyan("history")} Show command history
|
|
36098
|
+
${chalk2.cyan("clear")} Clear screen
|
|
36099
|
+
${chalk2.cyan("help")} Show this help
|
|
36100
|
+
${chalk2.cyan("exit")} Exit interactive mode
|
|
36101
|
+
|
|
36102
|
+
${chalk2.gray("Tab completion available for entity names.")}
|
|
36103
|
+
`);
|
|
35815
36104
|
}
|
|
36105
|
+
var init_interactive = __esm({
|
|
36106
|
+
"src/cli/interactive.ts"() {
|
|
36107
|
+
"use strict";
|
|
36108
|
+
init_esm_shims();
|
|
36109
|
+
init_ManagerContext();
|
|
36110
|
+
}
|
|
36111
|
+
});
|
|
36112
|
+
|
|
36113
|
+
// src/cli/index.ts
|
|
36114
|
+
init_esm_shims();
|
|
36115
|
+
import { Command as Command2 } from "commander";
|
|
36116
|
+
|
|
36117
|
+
// src/cli/commands/index.ts
|
|
36118
|
+
init_esm_shims();
|
|
35816
36119
|
|
|
35817
36120
|
// src/cli/commands/entity.ts
|
|
36121
|
+
init_esm_shims();
|
|
36122
|
+
init_helpers();
|
|
36123
|
+
init_formatters2();
|
|
35818
36124
|
function registerEntityCommands(program2) {
|
|
35819
36125
|
const entity = program2.command("entity").description("Manage entities (create, read, update, delete)");
|
|
35820
36126
|
entity.command("create <name>").description("Create a new entity").option("-t, --type <type>", "Entity type", "generic").option("-o, --observation <obs...>", "Observations to add").option("--tags <tags...>", "Tags to add").option("-i, --importance <n>", "Importance score (0-10)", parseFloat).action(async (name, opts) => {
|
|
@@ -35921,6 +36227,8 @@ function registerEntityCommands(program2) {
|
|
|
35921
36227
|
|
|
35922
36228
|
// src/cli/commands/relation.ts
|
|
35923
36229
|
init_esm_shims();
|
|
36230
|
+
init_helpers();
|
|
36231
|
+
init_formatters2();
|
|
35924
36232
|
function registerRelationCommands(program2) {
|
|
35925
36233
|
const relation = program2.command("relation").description("Manage relations between entities");
|
|
35926
36234
|
relation.command("create <from> <type> <to>").description("Create a new relation").action(async (from, relationType, to) => {
|
|
@@ -35973,6 +36281,8 @@ function registerRelationCommands(program2) {
|
|
|
35973
36281
|
|
|
35974
36282
|
// src/cli/commands/search.ts
|
|
35975
36283
|
init_esm_shims();
|
|
36284
|
+
init_helpers();
|
|
36285
|
+
init_formatters2();
|
|
35976
36286
|
function registerSearchCommands(program2) {
|
|
35977
36287
|
program2.command("search <query>").description("Search entities and observations").option("-l, --limit <n>", "Limit results", parseInt, 10).option("-t, --type <type>", "Filter by entity type").option("--ranked", "Use TF-IDF/BM25 ranked search").option("--boolean", "Use boolean search (AND/OR/NOT)").option("--fuzzy", "Use fuzzy search").option("--threshold <n>", "Fuzzy search threshold (0-1)", parseFloat, 0.6).option("--suggest", "Get search suggestions instead of results").action(async (query, opts) => {
|
|
35978
36288
|
const options = getOptions(program2);
|
|
@@ -36030,6 +36340,8 @@ function registerSearchCommands(program2) {
|
|
|
36030
36340
|
|
|
36031
36341
|
// src/cli/commands/observation.ts
|
|
36032
36342
|
init_esm_shims();
|
|
36343
|
+
init_helpers();
|
|
36344
|
+
init_formatters2();
|
|
36033
36345
|
function registerObservationCommands(program2) {
|
|
36034
36346
|
const observation = program2.command("observation").description("Manage entity observations");
|
|
36035
36347
|
observation.command("add <entity> <text...>").description("Add observation(s) to an entity").action(async (entity, text) => {
|
|
@@ -36102,6 +36414,8 @@ function registerObservationCommands(program2) {
|
|
|
36102
36414
|
|
|
36103
36415
|
// src/cli/commands/tag.ts
|
|
36104
36416
|
init_esm_shims();
|
|
36417
|
+
init_helpers();
|
|
36418
|
+
init_formatters2();
|
|
36105
36419
|
function registerTagCommands(program2) {
|
|
36106
36420
|
const tag = program2.command("tag").description("Manage entity tags and aliases");
|
|
36107
36421
|
tag.command("add <entity> <tags...>").description("Add tags to an entity").action(async (entity, tags) => {
|
|
@@ -36176,6 +36490,8 @@ function registerTagCommands(program2) {
|
|
|
36176
36490
|
|
|
36177
36491
|
// src/cli/commands/hierarchy.ts
|
|
36178
36492
|
init_esm_shims();
|
|
36493
|
+
init_helpers();
|
|
36494
|
+
init_formatters2();
|
|
36179
36495
|
function registerHierarchyCommands(program2) {
|
|
36180
36496
|
const hierarchy = program2.command("hierarchy").description("Manage entity hierarchy (parent/child relationships)");
|
|
36181
36497
|
hierarchy.command("set-parent <entity> <parent>").description('Set parent of an entity (use "none" to remove)').action(async (entity, parent) => {
|
|
@@ -36247,6 +36563,8 @@ function registerHierarchyCommands(program2) {
|
|
|
36247
36563
|
|
|
36248
36564
|
// src/cli/commands/graph.ts
|
|
36249
36565
|
init_esm_shims();
|
|
36566
|
+
init_helpers();
|
|
36567
|
+
init_formatters2();
|
|
36250
36568
|
function registerGraphCommands(program2) {
|
|
36251
36569
|
const graph = program2.command("graph").description("Graph algorithms (shortest path, centrality, components)");
|
|
36252
36570
|
graph.command("shortest-path <from> <to>").description("Find shortest path between two entities").action(async (from, to) => {
|
|
@@ -36317,10 +36635,12 @@ function registerGraphCommands(program2) {
|
|
|
36317
36635
|
|
|
36318
36636
|
// src/cli/commands/io.ts
|
|
36319
36637
|
init_esm_shims();
|
|
36638
|
+
init_helpers();
|
|
36639
|
+
init_formatters2();
|
|
36640
|
+
init_entityUtils();
|
|
36320
36641
|
import { readFileSync as readFileSync2, writeFileSync } from "fs";
|
|
36321
36642
|
import { resolve as resolve3 } from "path";
|
|
36322
36643
|
import { Option } from "commander";
|
|
36323
|
-
init_entityUtils();
|
|
36324
36644
|
var IMPORT_FORMATS = ["json", "csv", "graphml"];
|
|
36325
36645
|
var EXPORT_FORMATS = ["json", "csv", "graphml", "gexf", "dot", "markdown", "mermaid", "turtle", "rdf-xml", "json-ld"];
|
|
36326
36646
|
function registerIOCommands(program2) {
|
|
@@ -36370,6 +36690,8 @@ function registerIOCommands(program2) {
|
|
|
36370
36690
|
|
|
36371
36691
|
// src/cli/commands/maintenance.ts
|
|
36372
36692
|
init_esm_shims();
|
|
36693
|
+
init_helpers();
|
|
36694
|
+
init_formatters2();
|
|
36373
36695
|
function registerMaintenanceCommands(program2) {
|
|
36374
36696
|
program2.command("stats").description("Show knowledge graph statistics").action(async () => {
|
|
36375
36697
|
const options = getOptions(program2);
|
|
@@ -36494,6 +36816,8 @@ Tags Used: ${allTags.size}
|
|
|
36494
36816
|
|
|
36495
36817
|
// src/cli/commands/exclusion.ts
|
|
36496
36818
|
init_esm_shims();
|
|
36819
|
+
init_helpers();
|
|
36820
|
+
init_formatters2();
|
|
36497
36821
|
function registerExclusionCommands(program2) {
|
|
36498
36822
|
const exclude = program2.command("exclude").description("Manage do_not_remember exclusion rules");
|
|
36499
36823
|
exclude.command("add <pattern>").description("Add an exclusion rule (substring match)").option("--scope <scope>", "Rule scope: 'future-only' | 'past-only' | 'both'", "both").option("--entity-type <type>", "Restrict to a single entity type").option("--reason <reason>", "Free-text justification").action(async (pattern2, opts) => {
|
|
@@ -36573,6 +36897,8 @@ function registerExclusionCommands(program2) {
|
|
|
36573
36897
|
// src/cli/commands/decision.ts
|
|
36574
36898
|
init_esm_shims();
|
|
36575
36899
|
init_DecisionManager();
|
|
36900
|
+
init_helpers();
|
|
36901
|
+
init_formatters2();
|
|
36576
36902
|
import { readFileSync as readFileSync3, writeFileSync as writeFileSync2 } from "fs";
|
|
36577
36903
|
function registerDecisionCommands(program2) {
|
|
36578
36904
|
const decision = program2.command("decision").description("Manage decision-rationale records (ADR-equivalent)");
|
|
@@ -36727,6 +37053,8 @@ function registerDecisionCommands(program2) {
|
|
|
36727
37053
|
|
|
36728
37054
|
// src/cli/commands/projectContext.ts
|
|
36729
37055
|
init_esm_shims();
|
|
37056
|
+
init_helpers();
|
|
37057
|
+
init_formatters2();
|
|
36730
37058
|
function registerProjectContextCommands(program2) {
|
|
36731
37059
|
const pc = program2.command("project-context").description("Manage structured per-project knowledge (facts/conventions/commands/glossary)");
|
|
36732
37060
|
pc.command("show <projectId>").description("Show the project-context record as rendered prose").action(async (projectId) => {
|
|
@@ -36821,6 +37149,8 @@ function registerProjectContextCommands(program2) {
|
|
|
36821
37149
|
|
|
36822
37150
|
// src/cli/commands/toolAffordance.ts
|
|
36823
37151
|
init_esm_shims();
|
|
37152
|
+
init_helpers();
|
|
37153
|
+
init_formatters2();
|
|
36824
37154
|
function registerToolAffordanceCommands(program2) {
|
|
36825
37155
|
const ta = program2.command("tool-affordance").description("Inspect per-tool rolling outcome statistics");
|
|
36826
37156
|
ta.command("list").description("List all tools with affordance records").action(async () => {
|
|
@@ -36899,7 +37229,8 @@ function registerToolAffordanceCommands(program2) {
|
|
|
36899
37229
|
// src/cli/commands/smoke.ts
|
|
36900
37230
|
init_esm_shims();
|
|
36901
37231
|
init_ManagerContext();
|
|
36902
|
-
|
|
37232
|
+
init_formatters2();
|
|
37233
|
+
import { promises as fs18 } from "fs";
|
|
36903
37234
|
import { join as join8 } from "path";
|
|
36904
37235
|
import { tmpdir } from "os";
|
|
36905
37236
|
import { performance } from "perf_hooks";
|
|
@@ -37221,7 +37552,7 @@ function registerSmokeCommand(program2) {
|
|
|
37221
37552
|
program2.command("smoke").description("Run a per-category end-to-end smoke test (~30 ops) against a fresh temp graph").option("-s, --storage <path>", "Storage path for the smoke run (default: temp dir)").option("-k, --keep", "Preserve the smoke graph after the run and print its path (default: cleanup)").option("-v, --verbose", "Print each step as it runs (default: print summary only)").action(async (opts) => {
|
|
37222
37553
|
const verbose = Boolean(opts.verbose);
|
|
37223
37554
|
const keep = Boolean(opts.keep);
|
|
37224
|
-
const storagePath = opts.storage ? opts.storage : await
|
|
37555
|
+
const storagePath = opts.storage ? opts.storage : await fs18.mkdtemp(join8(tmpdir(), "memoryjs-smoke-"));
|
|
37225
37556
|
const graphPath = opts.storage ? storagePath : join8(storagePath, "graph.jsonl");
|
|
37226
37557
|
if (verbose) console.log(`Smoke storage: ${graphPath}`);
|
|
37227
37558
|
const ctx = new ManagerContext(graphPath);
|
|
@@ -37235,7 +37566,7 @@ function registerSmokeCommand(program2) {
|
|
|
37235
37566
|
Keeping smoke graph at: ${graphPath}`);
|
|
37236
37567
|
} else if (!opts.storage) {
|
|
37237
37568
|
try {
|
|
37238
|
-
await
|
|
37569
|
+
await fs18.rm(storagePath, { recursive: true, force: true });
|
|
37239
37570
|
} catch {
|
|
37240
37571
|
}
|
|
37241
37572
|
}
|
|
@@ -37244,6 +37575,555 @@ Keeping smoke graph at: ${graphPath}`);
|
|
|
37244
37575
|
});
|
|
37245
37576
|
}
|
|
37246
37577
|
|
|
37578
|
+
// src/cli/commands/diag.ts
|
|
37579
|
+
init_esm_shims();
|
|
37580
|
+
init_helpers();
|
|
37581
|
+
init_formatters2();
|
|
37582
|
+
import { promises as fs19 } from "fs";
|
|
37583
|
+
import { performance as performance2 } from "perf_hooks";
|
|
37584
|
+
import { readFileSync as readFileSync4 } from "fs";
|
|
37585
|
+
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
37586
|
+
import { dirname as dirname9, join as join9 } from "path";
|
|
37587
|
+
var ENV_VAR_CATALOG = [
|
|
37588
|
+
// Core
|
|
37589
|
+
{ name: "MEMORY_STORAGE_TYPE", defaultValue: "jsonl", description: "jsonl | sqlite \u2014 storage backend selector" },
|
|
37590
|
+
{ name: "MEMORY_FILE_PATH", defaultValue: "(repo default)", description: "Custom storage file path" },
|
|
37591
|
+
{ name: "SKIP_BENCHMARKS", defaultValue: "false", description: "Skip performance-benchmark tests" },
|
|
37592
|
+
{ name: "LOG_LEVEL", defaultValue: "(none)", description: "debug | info | warn | error" },
|
|
37593
|
+
// Embeddings
|
|
37594
|
+
{ name: "MEMORY_EMBEDDING_PROVIDER", defaultValue: "local", description: "openai | local | none" },
|
|
37595
|
+
{ name: "MEMORY_OPENAI_API_KEY", defaultValue: "(unset)", description: "OpenAI API key (when provider=openai)" },
|
|
37596
|
+
{ name: "MEMORY_EMBEDDING_MODEL", defaultValue: "(provider default)", description: "Override embedding model name" },
|
|
37597
|
+
{ name: "MEMORY_AUTO_INDEX_EMBEDDINGS", defaultValue: "false", description: "Auto-index new entities for semantic search" },
|
|
37598
|
+
// Read pool / coalescing
|
|
37599
|
+
{ name: "MEMORY_SQLITE_READ_POOL_SIZE", defaultValue: "4", description: "SQLite read-connection pool size" },
|
|
37600
|
+
{ name: "MEMORY_INDEX_COALESCE_MS", defaultValue: "50", description: "TF-IDF event-sync coalescing window (ms)" },
|
|
37601
|
+
// Governance
|
|
37602
|
+
{ name: "MEMORY_GOVERNANCE_ENABLED", defaultValue: "false", description: "Enable governance policy enforcement" },
|
|
37603
|
+
{ name: "MEMORY_AUDIT_LOG_FILE", defaultValue: "(unset)", description: "Path for audit JSONL trail" },
|
|
37604
|
+
{ name: "MEMORY_FRESHNESS_TTL_DEFAULT_HOURS", defaultValue: "168", description: "Default freshness TTL (hours)" },
|
|
37605
|
+
// Agent role + advanced
|
|
37606
|
+
{ name: "MEMORY_AGENT_ROLE", defaultValue: "(unset)", description: "researcher | planner | executor | reviewer | coordinator" },
|
|
37607
|
+
{ name: "MEMORY_ENTROPY_FILTER_ENABLED", defaultValue: "false", description: "Enable low-entropy observation filter" },
|
|
37608
|
+
{ name: "MEMORY_ENTROPY_THRESHOLD", defaultValue: "0.3", description: "Entropy filter threshold (0\u20131)" },
|
|
37609
|
+
{ name: "MEMORY_CONSOLIDATION_SCHEDULER_ENABLED", defaultValue: "false", description: "Enable background consolidation" },
|
|
37610
|
+
{ name: "MEMORY_CONSOLIDATION_INTERVAL_MS", defaultValue: "3600000", description: "Consolidation interval (ms)" },
|
|
37611
|
+
{ name: "MEMORY_DEFAULT_VISIBILITY", defaultValue: "private", description: "private | team | org | shared | public" },
|
|
37612
|
+
// CLI-only
|
|
37613
|
+
{ name: "MEMORYJS_STORAGE_PATH", defaultValue: "./memory.jsonl", description: "CLI: default storage path" },
|
|
37614
|
+
{ name: "MEMORYJS_OUTPUT_FORMAT", defaultValue: "json", description: "CLI: json | table | csv" }
|
|
37615
|
+
];
|
|
37616
|
+
function readPackageVersion() {
|
|
37617
|
+
try {
|
|
37618
|
+
const here = dirname9(fileURLToPath3(import.meta.url));
|
|
37619
|
+
for (const candidate of [
|
|
37620
|
+
join9(here, "../../../package.json"),
|
|
37621
|
+
join9(here, "../../package.json"),
|
|
37622
|
+
join9(here, "../package.json")
|
|
37623
|
+
]) {
|
|
37624
|
+
try {
|
|
37625
|
+
const raw = readFileSync4(candidate, "utf8");
|
|
37626
|
+
const pkg = JSON.parse(raw);
|
|
37627
|
+
if (pkg.name === "@danielsimonjr/memoryjs" && pkg.version) return pkg.version;
|
|
37628
|
+
} catch {
|
|
37629
|
+
}
|
|
37630
|
+
}
|
|
37631
|
+
} catch {
|
|
37632
|
+
}
|
|
37633
|
+
return "unknown";
|
|
37634
|
+
}
|
|
37635
|
+
async function buildSnapshot(ctx, storagePath) {
|
|
37636
|
+
let sizeBytes = 0;
|
|
37637
|
+
let exists = false;
|
|
37638
|
+
try {
|
|
37639
|
+
const stat = await fs19.stat(storagePath);
|
|
37640
|
+
exists = true;
|
|
37641
|
+
sizeBytes = stat.size;
|
|
37642
|
+
} catch {
|
|
37643
|
+
}
|
|
37644
|
+
const stats = await ctx.analyticsManager.getGraphStats();
|
|
37645
|
+
return {
|
|
37646
|
+
memoryjs: { version: readPackageVersion() },
|
|
37647
|
+
runtime: {
|
|
37648
|
+
node: process.version,
|
|
37649
|
+
platform: process.platform,
|
|
37650
|
+
arch: process.arch,
|
|
37651
|
+
pid: process.pid
|
|
37652
|
+
},
|
|
37653
|
+
storage: {
|
|
37654
|
+
path: storagePath,
|
|
37655
|
+
type: process.env.MEMORY_STORAGE_TYPE ?? "jsonl",
|
|
37656
|
+
exists,
|
|
37657
|
+
sizeBytes,
|
|
37658
|
+
entities: stats.totalEntities,
|
|
37659
|
+
relations: stats.totalRelations
|
|
37660
|
+
},
|
|
37661
|
+
loadedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
37662
|
+
};
|
|
37663
|
+
}
|
|
37664
|
+
async function runHealthChecks(ctx) {
|
|
37665
|
+
const checks = [];
|
|
37666
|
+
const t1 = performance2.now();
|
|
37667
|
+
let graph;
|
|
37668
|
+
try {
|
|
37669
|
+
graph = await ctx.storage.loadGraph();
|
|
37670
|
+
checks.push({ name: "storage:loadGraph", ok: true, durationMs: performance2.now() - t1 });
|
|
37671
|
+
} catch (e) {
|
|
37672
|
+
checks.push({
|
|
37673
|
+
name: "storage:loadGraph",
|
|
37674
|
+
ok: false,
|
|
37675
|
+
durationMs: performance2.now() - t1,
|
|
37676
|
+
detail: e instanceof Error ? e.message : String(e)
|
|
37677
|
+
});
|
|
37678
|
+
return checks;
|
|
37679
|
+
}
|
|
37680
|
+
const t2 = performance2.now();
|
|
37681
|
+
const names = /* @__PURE__ */ new Set();
|
|
37682
|
+
const dupes = [];
|
|
37683
|
+
for (const e of graph.entities) {
|
|
37684
|
+
if (names.has(e.name)) dupes.push(e.name);
|
|
37685
|
+
else names.add(e.name);
|
|
37686
|
+
}
|
|
37687
|
+
checks.push({
|
|
37688
|
+
name: "entities:distinct-names",
|
|
37689
|
+
ok: dupes.length === 0,
|
|
37690
|
+
durationMs: performance2.now() - t2,
|
|
37691
|
+
detail: dupes.length === 0 ? void 0 : `duplicates: ${dupes.slice(0, 5).join(", ")}${dupes.length > 5 ? "\u2026" : ""}`
|
|
37692
|
+
});
|
|
37693
|
+
const t3 = performance2.now();
|
|
37694
|
+
const orphans = [];
|
|
37695
|
+
for (const r of graph.relations) {
|
|
37696
|
+
if (!names.has(r.from)) orphans.push(`${r.from} \u2192 ${r.to} (from missing)`);
|
|
37697
|
+
else if (!names.has(r.to)) orphans.push(`${r.from} \u2192 ${r.to} (to missing)`);
|
|
37698
|
+
}
|
|
37699
|
+
checks.push({
|
|
37700
|
+
name: "relations:no-orphans",
|
|
37701
|
+
ok: orphans.length === 0,
|
|
37702
|
+
durationMs: performance2.now() - t3,
|
|
37703
|
+
detail: orphans.length === 0 ? void 0 : `${orphans.length} orphan(s); first: ${orphans.slice(0, 3).join("; ")}`
|
|
37704
|
+
});
|
|
37705
|
+
const t4 = performance2.now();
|
|
37706
|
+
const byName = /* @__PURE__ */ new Map();
|
|
37707
|
+
for (const e of graph.entities) byName.set(e.name, e);
|
|
37708
|
+
const cycleIssues = [];
|
|
37709
|
+
for (const e of graph.entities) {
|
|
37710
|
+
if (!e.parentId) continue;
|
|
37711
|
+
const visited = /* @__PURE__ */ new Set();
|
|
37712
|
+
let cur = byName.get(e.parentId);
|
|
37713
|
+
while (cur && cur.parentId) {
|
|
37714
|
+
if (visited.has(cur.name)) {
|
|
37715
|
+
cycleIssues.push(`cycle through ${cur.name}`);
|
|
37716
|
+
break;
|
|
37717
|
+
}
|
|
37718
|
+
visited.add(cur.name);
|
|
37719
|
+
cur = byName.get(cur.parentId);
|
|
37720
|
+
}
|
|
37721
|
+
if (e.parentId && !byName.has(e.parentId)) {
|
|
37722
|
+
cycleIssues.push(`${e.name}.parentId='${e.parentId}' missing`);
|
|
37723
|
+
}
|
|
37724
|
+
}
|
|
37725
|
+
checks.push({
|
|
37726
|
+
name: "hierarchy:no-cycles-no-missing-parents",
|
|
37727
|
+
ok: cycleIssues.length === 0,
|
|
37728
|
+
durationMs: performance2.now() - t4,
|
|
37729
|
+
detail: cycleIssues.length === 0 ? void 0 : cycleIssues.slice(0, 3).join("; ")
|
|
37730
|
+
});
|
|
37731
|
+
return checks;
|
|
37732
|
+
}
|
|
37733
|
+
function registerDiagCommand(program2) {
|
|
37734
|
+
program2.command("diag").description("One-shot diagnostic snapshot: memoryjs version, runtime, storage, env").action(async () => {
|
|
37735
|
+
const options = getOptions(program2);
|
|
37736
|
+
const logger2 = createLogger(options);
|
|
37737
|
+
const ctx = createContext(options);
|
|
37738
|
+
try {
|
|
37739
|
+
const snapshot = await buildSnapshot(ctx, options.storage);
|
|
37740
|
+
console.log(JSON.stringify(snapshot, null, 2));
|
|
37741
|
+
} catch (e) {
|
|
37742
|
+
logger2.error(formatError(e.message));
|
|
37743
|
+
process.exit(1);
|
|
37744
|
+
}
|
|
37745
|
+
});
|
|
37746
|
+
program2.command("env").description("Print all memoryjs env vars with documented defaults and resolved values").option("--all", "Include vars that are unset and have no documented default override").action(async (opts) => {
|
|
37747
|
+
const showAll = Boolean(opts.all);
|
|
37748
|
+
const rows = ENV_VAR_CATALOG.map((spec) => {
|
|
37749
|
+
const current = process.env[spec.name];
|
|
37750
|
+
return {
|
|
37751
|
+
name: spec.name,
|
|
37752
|
+
value: current ?? null,
|
|
37753
|
+
default: spec.defaultValue,
|
|
37754
|
+
set: current !== void 0,
|
|
37755
|
+
description: spec.description
|
|
37756
|
+
};
|
|
37757
|
+
});
|
|
37758
|
+
const filtered = showAll ? rows : rows.filter((r) => r.set || !r.default.startsWith("("));
|
|
37759
|
+
console.log(JSON.stringify({ count: filtered.length, vars: filtered }, null, 2));
|
|
37760
|
+
});
|
|
37761
|
+
program2.command("health").description("Run fast integrity checks (graph loads, distinct names, no orphan relations, no hierarchy cycles)").action(async () => {
|
|
37762
|
+
const options = getOptions(program2);
|
|
37763
|
+
const logger2 = createLogger(options);
|
|
37764
|
+
const ctx = createContext(options);
|
|
37765
|
+
try {
|
|
37766
|
+
const checks = await runHealthChecks(ctx);
|
|
37767
|
+
const failed = checks.filter((c) => !c.ok).length;
|
|
37768
|
+
const totalMs = checks.reduce((acc, c) => acc + c.durationMs, 0);
|
|
37769
|
+
console.log(JSON.stringify({
|
|
37770
|
+
ok: failed === 0,
|
|
37771
|
+
failed,
|
|
37772
|
+
totalChecks: checks.length,
|
|
37773
|
+
totalMs: Number(totalMs.toFixed(2)),
|
|
37774
|
+
checks
|
|
37775
|
+
}, null, 2));
|
|
37776
|
+
if (failed > 0) process.exit(1);
|
|
37777
|
+
} catch (e) {
|
|
37778
|
+
logger2.error(formatError(e.message));
|
|
37779
|
+
process.exit(1);
|
|
37780
|
+
}
|
|
37781
|
+
});
|
|
37782
|
+
program2.command("version").description("Compact version line: memoryjs, node, platform").action(() => {
|
|
37783
|
+
console.log(JSON.stringify({
|
|
37784
|
+
memoryjs: readPackageVersion(),
|
|
37785
|
+
node: process.version,
|
|
37786
|
+
platform: `${process.platform}/${process.arch}`
|
|
37787
|
+
}));
|
|
37788
|
+
});
|
|
37789
|
+
}
|
|
37790
|
+
|
|
37791
|
+
// src/cli/commands/index.ts
|
|
37792
|
+
init_inspect();
|
|
37793
|
+
|
|
37794
|
+
// src/cli/commands/heuristic.ts
|
|
37795
|
+
init_esm_shims();
|
|
37796
|
+
init_helpers();
|
|
37797
|
+
init_formatters2();
|
|
37798
|
+
function emitJson(payload) {
|
|
37799
|
+
console.log(JSON.stringify(payload, null, 2));
|
|
37800
|
+
}
|
|
37801
|
+
function registerHeuristicCommands(program2) {
|
|
37802
|
+
const h = program2.command("heuristic").description("Manage condition\u2192action heuristic guidelines (add, match, reinforce, conflicts)");
|
|
37803
|
+
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) => {
|
|
37804
|
+
const options = getOptions(program2);
|
|
37805
|
+
const logger2 = createLogger(options);
|
|
37806
|
+
const ctx = createContext(options);
|
|
37807
|
+
try {
|
|
37808
|
+
const id = await ctx.heuristicManager.add({
|
|
37809
|
+
condition,
|
|
37810
|
+
action,
|
|
37811
|
+
priority: opts.priority,
|
|
37812
|
+
initialConfidence: opts.confidence,
|
|
37813
|
+
importance: opts.importance,
|
|
37814
|
+
agentId: opts.agentId
|
|
37815
|
+
});
|
|
37816
|
+
emitJson({ id });
|
|
37817
|
+
} catch (error) {
|
|
37818
|
+
logger2.error(formatError(error.message));
|
|
37819
|
+
process.exit(1);
|
|
37820
|
+
}
|
|
37821
|
+
});
|
|
37822
|
+
h.command("list").description("List all heuristics").action(async () => {
|
|
37823
|
+
const options = getOptions(program2);
|
|
37824
|
+
const logger2 = createLogger(options);
|
|
37825
|
+
const ctx = createContext(options);
|
|
37826
|
+
try {
|
|
37827
|
+
const heuristics = await ctx.heuristicManager.list();
|
|
37828
|
+
emitJson({ heuristics, count: heuristics.length });
|
|
37829
|
+
} catch (error) {
|
|
37830
|
+
logger2.error(formatError(error.message));
|
|
37831
|
+
process.exit(1);
|
|
37832
|
+
}
|
|
37833
|
+
});
|
|
37834
|
+
h.command("count").description("Print the current heuristic count").action(async () => {
|
|
37835
|
+
const options = getOptions(program2);
|
|
37836
|
+
const logger2 = createLogger(options);
|
|
37837
|
+
const ctx = createContext(options);
|
|
37838
|
+
try {
|
|
37839
|
+
const count = await ctx.heuristicManager.size();
|
|
37840
|
+
emitJson({ count });
|
|
37841
|
+
} catch (error) {
|
|
37842
|
+
logger2.error(formatError(error.message));
|
|
37843
|
+
process.exit(1);
|
|
37844
|
+
}
|
|
37845
|
+
});
|
|
37846
|
+
h.command("get <id>").description("Get a heuristic by id").action(async (id) => {
|
|
37847
|
+
const options = getOptions(program2);
|
|
37848
|
+
const logger2 = createLogger(options);
|
|
37849
|
+
const ctx = createContext(options);
|
|
37850
|
+
try {
|
|
37851
|
+
const heuristic = ctx.heuristicManager.get(id);
|
|
37852
|
+
emitJson({ id, heuristic: heuristic ?? null });
|
|
37853
|
+
} catch (error) {
|
|
37854
|
+
logger2.error(formatError(error.message));
|
|
37855
|
+
process.exit(1);
|
|
37856
|
+
}
|
|
37857
|
+
});
|
|
37858
|
+
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) => {
|
|
37859
|
+
const options = getOptions(program2);
|
|
37860
|
+
const logger2 = createLogger(options);
|
|
37861
|
+
const ctx = createContext(options);
|
|
37862
|
+
const input = inputParts.join(" ");
|
|
37863
|
+
try {
|
|
37864
|
+
const matches2 = await ctx.heuristicManager.match(input, {
|
|
37865
|
+
limit: opts.limit,
|
|
37866
|
+
minScore: opts.minScore
|
|
37867
|
+
});
|
|
37868
|
+
emitJson({ input, matches: matches2, count: matches2.length });
|
|
37869
|
+
} catch (error) {
|
|
37870
|
+
logger2.error(formatError(error.message));
|
|
37871
|
+
process.exit(1);
|
|
37872
|
+
}
|
|
37873
|
+
});
|
|
37874
|
+
h.command("reinforce <id>").description("Reinforce a heuristic (bump confidence toward 1)").action(async (id) => {
|
|
37875
|
+
const options = getOptions(program2);
|
|
37876
|
+
const logger2 = createLogger(options);
|
|
37877
|
+
const ctx = createContext(options);
|
|
37878
|
+
try {
|
|
37879
|
+
const result = await ctx.heuristicManager.reinforce(id);
|
|
37880
|
+
emitJson({ id, result });
|
|
37881
|
+
} catch (error) {
|
|
37882
|
+
logger2.error(formatError(error.message));
|
|
37883
|
+
process.exit(1);
|
|
37884
|
+
}
|
|
37885
|
+
});
|
|
37886
|
+
h.command("contradict <id>").description("Record a contradiction (decreases confidence)").action(async (id) => {
|
|
37887
|
+
const options = getOptions(program2);
|
|
37888
|
+
const logger2 = createLogger(options);
|
|
37889
|
+
const ctx = createContext(options);
|
|
37890
|
+
try {
|
|
37891
|
+
const result = await ctx.heuristicManager.recordContradiction(id);
|
|
37892
|
+
emitJson({ id, result });
|
|
37893
|
+
} catch (error) {
|
|
37894
|
+
logger2.error(formatError(error.message));
|
|
37895
|
+
process.exit(1);
|
|
37896
|
+
}
|
|
37897
|
+
});
|
|
37898
|
+
h.command("conflicts").description("Detect heuristics with conflicting actions for similar conditions").action(async () => {
|
|
37899
|
+
const options = getOptions(program2);
|
|
37900
|
+
const logger2 = createLogger(options);
|
|
37901
|
+
const ctx = createContext(options);
|
|
37902
|
+
try {
|
|
37903
|
+
const conflicts = await ctx.heuristicManager.detectConflicts();
|
|
37904
|
+
emitJson({ conflicts, count: conflicts.length });
|
|
37905
|
+
} catch (error) {
|
|
37906
|
+
logger2.error(formatError(error.message));
|
|
37907
|
+
process.exit(1);
|
|
37908
|
+
}
|
|
37909
|
+
});
|
|
37910
|
+
h.command("remove <id>").description("Remove a heuristic by id").action(async (id) => {
|
|
37911
|
+
const options = getOptions(program2);
|
|
37912
|
+
const logger2 = createLogger(options);
|
|
37913
|
+
const ctx = createContext(options);
|
|
37914
|
+
try {
|
|
37915
|
+
const removed = await ctx.heuristicManager.remove(id);
|
|
37916
|
+
emitJson({ id, removed });
|
|
37917
|
+
} catch (error) {
|
|
37918
|
+
logger2.error(formatError(error.message));
|
|
37919
|
+
process.exit(1);
|
|
37920
|
+
}
|
|
37921
|
+
});
|
|
37922
|
+
h.command("clear").description("Remove all heuristics. Destructive; no --dry-run yet.").action(async () => {
|
|
37923
|
+
const options = getOptions(program2);
|
|
37924
|
+
const logger2 = createLogger(options);
|
|
37925
|
+
const ctx = createContext(options);
|
|
37926
|
+
try {
|
|
37927
|
+
await ctx.heuristicManager.clear();
|
|
37928
|
+
emitJson({ cleared: true });
|
|
37929
|
+
} catch (error) {
|
|
37930
|
+
logger2.error(formatError(error.message));
|
|
37931
|
+
process.exit(1);
|
|
37932
|
+
}
|
|
37933
|
+
});
|
|
37934
|
+
}
|
|
37935
|
+
|
|
37936
|
+
// src/cli/commands/observationDedup.ts
|
|
37937
|
+
init_esm_shims();
|
|
37938
|
+
init_helpers();
|
|
37939
|
+
init_formatters2();
|
|
37940
|
+
function buildFilter(opts) {
|
|
37941
|
+
const filter = {};
|
|
37942
|
+
const entityType = opts.entityType;
|
|
37943
|
+
if (entityType) {
|
|
37944
|
+
filter.entityType = entityType.includes(",") ? entityType.split(",").map((s) => s.trim()).filter(Boolean) : entityType;
|
|
37945
|
+
}
|
|
37946
|
+
if (typeof opts.projectId === "string") filter.projectId = opts.projectId;
|
|
37947
|
+
if (typeof opts.sessionId === "string") filter.sessionId = opts.sessionId;
|
|
37948
|
+
if (typeof opts.minOccurrences === "number" && opts.minOccurrences >= 2) {
|
|
37949
|
+
filter.minOccurrences = opts.minOccurrences;
|
|
37950
|
+
}
|
|
37951
|
+
if (typeof opts.maxGroups === "number" && opts.maxGroups > 0) {
|
|
37952
|
+
filter.maxGroups = opts.maxGroups;
|
|
37953
|
+
}
|
|
37954
|
+
return filter;
|
|
37955
|
+
}
|
|
37956
|
+
function emitJson2(payload) {
|
|
37957
|
+
console.log(JSON.stringify(payload, null, 2));
|
|
37958
|
+
}
|
|
37959
|
+
function registerObservationDedupCommands(program2) {
|
|
37960
|
+
const od = program2.command("obs-dedup").description("Cross-entity observation duplicate detection (exact and Jaccard similarity)");
|
|
37961
|
+
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) => {
|
|
37962
|
+
const options = getOptions(program2);
|
|
37963
|
+
const logger2 = createLogger(options);
|
|
37964
|
+
const ctx = createContext(options);
|
|
37965
|
+
try {
|
|
37966
|
+
const filter = buildFilter(opts);
|
|
37967
|
+
const groups = await ctx.observationDedupManager.findDuplicateObservations(filter);
|
|
37968
|
+
emitJson2({ filter, groups, count: groups.length });
|
|
37969
|
+
} catch (error) {
|
|
37970
|
+
logger2.error(formatError(error.message));
|
|
37971
|
+
process.exit(1);
|
|
37972
|
+
}
|
|
37973
|
+
});
|
|
37974
|
+
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) => {
|
|
37975
|
+
const options = getOptions(program2);
|
|
37976
|
+
const logger2 = createLogger(options);
|
|
37977
|
+
const ctx = createContext(options);
|
|
37978
|
+
try {
|
|
37979
|
+
const filter = buildFilter(opts);
|
|
37980
|
+
const groups = await ctx.observationDedupManager.findJaccardDuplicates(filter);
|
|
37981
|
+
emitJson2({ filter, groups, count: groups.length });
|
|
37982
|
+
} catch (error) {
|
|
37983
|
+
logger2.error(formatError(error.message));
|
|
37984
|
+
process.exit(1);
|
|
37985
|
+
}
|
|
37986
|
+
});
|
|
37987
|
+
}
|
|
37988
|
+
|
|
37989
|
+
// src/cli/commands/spell.ts
|
|
37990
|
+
init_esm_shims();
|
|
37991
|
+
init_helpers();
|
|
37992
|
+
init_formatters2();
|
|
37993
|
+
function emitJson3(payload) {
|
|
37994
|
+
console.log(JSON.stringify(payload, null, 2));
|
|
37995
|
+
}
|
|
37996
|
+
function registerSpellCommands(program2) {
|
|
37997
|
+
const sp = program2.command("spell").description("Spell-suggest queries against the graph vocabulary");
|
|
37998
|
+
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) => {
|
|
37999
|
+
const options = getOptions(program2);
|
|
38000
|
+
const logger2 = createLogger(options);
|
|
38001
|
+
const ctx = createContext(options);
|
|
38002
|
+
try {
|
|
38003
|
+
const suggestions = await ctx.spellChecker.suggest(query, {
|
|
38004
|
+
limit: opts.limit,
|
|
38005
|
+
minScore: opts.minScore,
|
|
38006
|
+
maxDistance: opts.maxDistance
|
|
38007
|
+
});
|
|
38008
|
+
emitJson3({ query, suggestions, count: suggestions.length });
|
|
38009
|
+
} catch (error) {
|
|
38010
|
+
logger2.error(formatError(error.message));
|
|
38011
|
+
process.exit(1);
|
|
38012
|
+
}
|
|
38013
|
+
});
|
|
38014
|
+
sp.command("rebuild").description("Rebuild the spell-checker vocabulary index from the graph").action(async () => {
|
|
38015
|
+
const options = getOptions(program2);
|
|
38016
|
+
const logger2 = createLogger(options);
|
|
38017
|
+
const ctx = createContext(options);
|
|
38018
|
+
try {
|
|
38019
|
+
await ctx.spellChecker.rebuild();
|
|
38020
|
+
emitJson3({ rebuilt: true, vocabularySize: ctx.spellChecker.vocabularySize() });
|
|
38021
|
+
} catch (error) {
|
|
38022
|
+
logger2.error(formatError(error.message));
|
|
38023
|
+
process.exit(1);
|
|
38024
|
+
}
|
|
38025
|
+
});
|
|
38026
|
+
sp.command("size").description("Print the current vocabulary size").action(async () => {
|
|
38027
|
+
const options = getOptions(program2);
|
|
38028
|
+
const logger2 = createLogger(options);
|
|
38029
|
+
const ctx = createContext(options);
|
|
38030
|
+
try {
|
|
38031
|
+
emitJson3({ vocabularySize: ctx.spellChecker.vocabularySize() });
|
|
38032
|
+
} catch (error) {
|
|
38033
|
+
logger2.error(formatError(error.message));
|
|
38034
|
+
process.exit(1);
|
|
38035
|
+
}
|
|
38036
|
+
});
|
|
38037
|
+
}
|
|
38038
|
+
|
|
38039
|
+
// src/cli/commands/check.ts
|
|
38040
|
+
init_esm_shims();
|
|
38041
|
+
init_helpers();
|
|
38042
|
+
init_formatters2();
|
|
38043
|
+
async function detectIssues(ctx) {
|
|
38044
|
+
const graph = await ctx.storage.loadGraph();
|
|
38045
|
+
const names = new Set(graph.entities.map((e) => e.name));
|
|
38046
|
+
const orphans = [];
|
|
38047
|
+
for (const r of graph.relations) {
|
|
38048
|
+
const fromMissing = !names.has(r.from);
|
|
38049
|
+
const toMissing = !names.has(r.to);
|
|
38050
|
+
if (fromMissing || toMissing) {
|
|
38051
|
+
orphans.push({
|
|
38052
|
+
from: r.from,
|
|
38053
|
+
to: r.to,
|
|
38054
|
+
relationType: r.relationType,
|
|
38055
|
+
reason: fromMissing && toMissing ? "both-missing" : fromMissing ? "from-missing" : "to-missing"
|
|
38056
|
+
});
|
|
38057
|
+
}
|
|
38058
|
+
}
|
|
38059
|
+
const missing = [];
|
|
38060
|
+
const cycles = [];
|
|
38061
|
+
const byName = /* @__PURE__ */ new Map();
|
|
38062
|
+
for (const e of graph.entities) byName.set(e.name, { name: e.name, parentId: e.parentId });
|
|
38063
|
+
for (const e of graph.entities) {
|
|
38064
|
+
if (!e.parentId) continue;
|
|
38065
|
+
if (!byName.has(e.parentId)) {
|
|
38066
|
+
missing.push({ entity: e.name, parentId: e.parentId });
|
|
38067
|
+
continue;
|
|
38068
|
+
}
|
|
38069
|
+
const visited = /* @__PURE__ */ new Set([e.name]);
|
|
38070
|
+
let cur = byName.get(e.parentId);
|
|
38071
|
+
while (cur && cur.parentId) {
|
|
38072
|
+
if (visited.has(cur.name)) {
|
|
38073
|
+
cycles.push({ entityInCycle: e.name, cycleThrough: cur.name });
|
|
38074
|
+
break;
|
|
38075
|
+
}
|
|
38076
|
+
visited.add(cur.name);
|
|
38077
|
+
cur = byName.get(cur.parentId);
|
|
38078
|
+
}
|
|
38079
|
+
}
|
|
38080
|
+
return { orphans, missing, cycles };
|
|
38081
|
+
}
|
|
38082
|
+
async function applyFixes(ctx, orphans, missing) {
|
|
38083
|
+
let deleted = 0;
|
|
38084
|
+
let cleared = 0;
|
|
38085
|
+
if (orphans.length > 0) {
|
|
38086
|
+
await ctx.relationManager.deleteRelations(
|
|
38087
|
+
orphans.map((o) => ({ from: o.from, to: o.to, relationType: o.relationType }))
|
|
38088
|
+
);
|
|
38089
|
+
deleted = orphans.length;
|
|
38090
|
+
}
|
|
38091
|
+
for (const m of missing) {
|
|
38092
|
+
try {
|
|
38093
|
+
await ctx.hierarchyManager.setEntityParent(m.entity, null);
|
|
38094
|
+
cleared += 1;
|
|
38095
|
+
} catch {
|
|
38096
|
+
}
|
|
38097
|
+
}
|
|
38098
|
+
return { orphanRelationsDeleted: deleted, missingParentsCleared: cleared };
|
|
38099
|
+
}
|
|
38100
|
+
function registerCheckCommand(program2) {
|
|
38101
|
+
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) => {
|
|
38102
|
+
const options = getOptions(program2);
|
|
38103
|
+
const logger2 = createLogger(options);
|
|
38104
|
+
const ctx = createContext(options);
|
|
38105
|
+
try {
|
|
38106
|
+
const { orphans, missing, cycles } = await detectIssues(ctx);
|
|
38107
|
+
const ok = orphans.length === 0 && missing.length === 0 && cycles.length === 0;
|
|
38108
|
+
const report = {
|
|
38109
|
+
ok,
|
|
38110
|
+
applied: Boolean(opts.apply),
|
|
38111
|
+
orphanRelations: orphans,
|
|
38112
|
+
missingParents: missing,
|
|
38113
|
+
hierarchyCycles: cycles
|
|
38114
|
+
};
|
|
38115
|
+
if (opts.apply && (orphans.length > 0 || missing.length > 0)) {
|
|
38116
|
+
report.actions = await applyFixes(ctx, orphans, missing);
|
|
38117
|
+
}
|
|
38118
|
+
console.log(JSON.stringify(report, null, 2));
|
|
38119
|
+
if (!ok && !opts.apply) process.exit(1);
|
|
38120
|
+
} catch (error) {
|
|
38121
|
+
logger2.error(formatError(error.message));
|
|
38122
|
+
process.exit(1);
|
|
38123
|
+
}
|
|
38124
|
+
});
|
|
38125
|
+
}
|
|
38126
|
+
|
|
37247
38127
|
// src/cli/commands/index.ts
|
|
37248
38128
|
function registerCommands(program2) {
|
|
37249
38129
|
registerEntityCommands(program2);
|
|
@@ -37260,14 +38140,20 @@ function registerCommands(program2) {
|
|
|
37260
38140
|
registerProjectContextCommands(program2);
|
|
37261
38141
|
registerToolAffordanceCommands(program2);
|
|
37262
38142
|
registerSmokeCommand(program2);
|
|
38143
|
+
registerDiagCommand(program2);
|
|
38144
|
+
registerInspectCommands(program2);
|
|
38145
|
+
registerHeuristicCommands(program2);
|
|
38146
|
+
registerObservationDedupCommands(program2);
|
|
38147
|
+
registerSpellCommands(program2);
|
|
38148
|
+
registerCheckCommand(program2);
|
|
37263
38149
|
}
|
|
37264
38150
|
|
|
37265
38151
|
// src/cli/index.ts
|
|
37266
38152
|
init_logger();
|
|
37267
|
-
import { readFileSync as
|
|
38153
|
+
import { readFileSync as readFileSync5 } from "fs";
|
|
37268
38154
|
import { createInterface as createInterface2 } from "readline";
|
|
37269
|
-
import { fileURLToPath as
|
|
37270
|
-
import { dirname as
|
|
38155
|
+
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
38156
|
+
import { dirname as dirname10, join as join10 } from "path";
|
|
37271
38157
|
process.on("unhandledRejection", (reason) => {
|
|
37272
38158
|
logger.error("Unhandled promise rejection:", reason);
|
|
37273
38159
|
});
|
|
@@ -37276,10 +38162,10 @@ process.on("uncaughtException", (err) => {
|
|
|
37276
38162
|
});
|
|
37277
38163
|
function getVersion() {
|
|
37278
38164
|
try {
|
|
37279
|
-
const __filename2 =
|
|
37280
|
-
const __dirname2 =
|
|
37281
|
-
const pkgPath =
|
|
37282
|
-
const pkg = JSON.parse(
|
|
38165
|
+
const __filename2 = fileURLToPath4(import.meta.url);
|
|
38166
|
+
const __dirname2 = dirname10(__filename2);
|
|
38167
|
+
const pkgPath = join10(__dirname2, "..", "..", "package.json");
|
|
38168
|
+
const pkg = JSON.parse(readFileSync5(pkgPath, "utf-8"));
|
|
37283
38169
|
return pkg.version;
|
|
37284
38170
|
} catch {
|
|
37285
38171
|
return "0.0.0";
|