chainlesschain 0.37.10 → 0.37.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/README.md +166 -10
  2. package/package.json +1 -1
  3. package/src/commands/a2a.js +374 -0
  4. package/src/commands/bi.js +240 -0
  5. package/src/commands/cowork.js +317 -0
  6. package/src/commands/economy.js +375 -0
  7. package/src/commands/evolution.js +398 -0
  8. package/src/commands/hmemory.js +273 -0
  9. package/src/commands/hook.js +260 -0
  10. package/src/commands/init.js +184 -0
  11. package/src/commands/lowcode.js +320 -0
  12. package/src/commands/plugin.js +55 -2
  13. package/src/commands/sandbox.js +366 -0
  14. package/src/commands/skill.js +254 -201
  15. package/src/commands/workflow.js +359 -0
  16. package/src/commands/zkp.js +277 -0
  17. package/src/index.js +44 -0
  18. package/src/lib/a2a-protocol.js +371 -0
  19. package/src/lib/agent-coordinator.js +273 -0
  20. package/src/lib/agent-economy.js +369 -0
  21. package/src/lib/app-builder.js +377 -0
  22. package/src/lib/bi-engine.js +299 -0
  23. package/src/lib/cowork/ab-comparator-cli.js +180 -0
  24. package/src/lib/cowork/code-knowledge-graph-cli.js +232 -0
  25. package/src/lib/cowork/debate-review-cli.js +144 -0
  26. package/src/lib/cowork/decision-kb-cli.js +153 -0
  27. package/src/lib/cowork/project-style-analyzer-cli.js +168 -0
  28. package/src/lib/cowork-adapter.js +106 -0
  29. package/src/lib/evolution-system.js +508 -0
  30. package/src/lib/hierarchical-memory.js +471 -0
  31. package/src/lib/hook-manager.js +387 -0
  32. package/src/lib/plugin-manager.js +118 -0
  33. package/src/lib/project-detector.js +53 -0
  34. package/src/lib/sandbox-v2.js +503 -0
  35. package/src/lib/service-container.js +183 -0
  36. package/src/lib/skill-loader.js +274 -0
  37. package/src/lib/workflow-engine.js +503 -0
  38. package/src/lib/zkp-engine.js +241 -0
  39. package/src/repl/agent-repl.js +117 -112
@@ -0,0 +1,398 @@
1
+ /**
2
+ * Self-Evolving System commands
3
+ * chainlesschain evolution assess|learn|diagnose|repair|predict|growth|stats|export
4
+ */
5
+
6
+ import chalk from "chalk";
7
+ import ora from "ora";
8
+ import { logger } from "../lib/logger.js";
9
+ import { bootstrap, shutdown } from "../runtime/bootstrap.js";
10
+ import {
11
+ assessCapability,
12
+ trainIncremental,
13
+ selfDiagnose,
14
+ selfRepair,
15
+ predictBehavior,
16
+ getGrowthLog,
17
+ getCapabilities,
18
+ getModels,
19
+ exportModel,
20
+ } from "../lib/evolution-system.js";
21
+
22
+ export function registerEvolutionCommand(program) {
23
+ const evolution = program
24
+ .command("evolution")
25
+ .description("Self-evolving AI system — capabilities, learning, diagnosis");
26
+
27
+ // evolution assess <name> <score>
28
+ evolution
29
+ .command("assess")
30
+ .description("Assess and track a capability")
31
+ .argument("<name>", "Capability name")
32
+ .argument("<score>", "Score (0-1)")
33
+ .option("--category <cat>", "Capability category", "general")
34
+ .option("--json", "Output as JSON")
35
+ .action(async (name, score, options) => {
36
+ try {
37
+ const ctx = await bootstrap({ verbose: program.opts().verbose });
38
+ if (!ctx.db) {
39
+ logger.error("Database not available");
40
+ process.exit(1);
41
+ }
42
+ const db = ctx.db.getDatabase();
43
+ const spinner = ora(`Assessing capability: ${name}...`).start();
44
+
45
+ const result = assessCapability(
46
+ db,
47
+ name,
48
+ parseFloat(score),
49
+ options.category,
50
+ );
51
+ spinner.succeed("Capability assessed");
52
+
53
+ if (options.json) {
54
+ console.log(JSON.stringify(result, null, 2));
55
+ } else {
56
+ const trendIcon =
57
+ result.trend === "improving"
58
+ ? chalk.green("improving")
59
+ : result.trend === "declining"
60
+ ? chalk.red("declining")
61
+ : chalk.gray("stable");
62
+ logger.log(chalk.bold(`Capability: ${result.name}`));
63
+ logger.log(` Score: ${chalk.cyan(result.score)}`);
64
+ logger.log(` Trend: ${trendIcon}`);
65
+ logger.log(` History: ${result.history.length} assessments`);
66
+ }
67
+
68
+ await shutdown();
69
+ } catch (err) {
70
+ logger.error(`Failed: ${err.message}`);
71
+ process.exit(1);
72
+ }
73
+ });
74
+
75
+ // evolution learn <model-id>
76
+ evolution
77
+ .command("learn")
78
+ .description("Train a model with incremental data")
79
+ .argument("<model-id>", "Model ID to train")
80
+ .option("--data <json>", "Training data as JSON array")
81
+ .option(
82
+ "--type <type>",
83
+ "Model type (classification|regression)",
84
+ "classification",
85
+ )
86
+ .option("--json", "Output as JSON")
87
+ .action(async (modelId, options) => {
88
+ try {
89
+ const ctx = await bootstrap({ verbose: program.opts().verbose });
90
+ if (!ctx.db) {
91
+ logger.error("Database not available");
92
+ process.exit(1);
93
+ }
94
+ const db = ctx.db.getDatabase();
95
+ const spinner = ora(`Training model: ${modelId}...`).start();
96
+
97
+ let data = [{ sample: true }];
98
+ if (options.data) {
99
+ try {
100
+ data = JSON.parse(options.data);
101
+ } catch (_err) {
102
+ // Use data string as single data point
103
+ data = [options.data];
104
+ }
105
+ }
106
+
107
+ const result = trainIncremental(db, modelId, data, {
108
+ type: options.type,
109
+ });
110
+ spinner.succeed("Model trained");
111
+
112
+ if (options.json) {
113
+ console.log(JSON.stringify(result, null, 2));
114
+ } else {
115
+ logger.log(chalk.bold(`Model: ${result.name}`));
116
+ logger.log(` Type: ${result.type}`);
117
+ logger.log(` Accuracy: ${chalk.cyan(result.accuracy.toFixed(4))}`);
118
+ logger.log(` Data Points: ${result.dataPoints}`);
119
+ }
120
+
121
+ await shutdown();
122
+ } catch (err) {
123
+ logger.error(`Failed: ${err.message}`);
124
+ process.exit(1);
125
+ }
126
+ });
127
+
128
+ // evolution diagnose
129
+ evolution
130
+ .command("diagnose")
131
+ .description("Run self-diagnosis on the system")
132
+ .option("--json", "Output as JSON")
133
+ .action(async (options) => {
134
+ try {
135
+ const ctx = await bootstrap({ verbose: program.opts().verbose });
136
+ if (!ctx.db) {
137
+ logger.error("Database not available");
138
+ process.exit(1);
139
+ }
140
+ const db = ctx.db.getDatabase();
141
+ const spinner = ora("Running self-diagnosis...").start();
142
+
143
+ const result = selfDiagnose(db);
144
+ spinner.succeed("Diagnosis complete");
145
+
146
+ if (options.json) {
147
+ console.log(JSON.stringify(result, null, 2));
148
+ } else {
149
+ const statusColor =
150
+ result.overallStatus === "healthy" ? chalk.green : chalk.yellow;
151
+ logger.log(
152
+ chalk.bold(`Overall Status: ${statusColor(result.overallStatus)}`),
153
+ );
154
+
155
+ logger.log(chalk.bold("\nComponents:"));
156
+ for (const c of result.components) {
157
+ const icon =
158
+ c.status === "healthy" ? chalk.green("OK") : chalk.yellow("WARN");
159
+ logger.log(` ${icon} ${c.name}`);
160
+ }
161
+
162
+ if (result.issues.length > 0) {
163
+ logger.log(chalk.bold("\nIssues:"));
164
+ for (const issue of result.issues) {
165
+ logger.log(` - ${chalk.yellow(issue.type)}: ${issue.details}`);
166
+ }
167
+ }
168
+
169
+ if (result.recommendations.length > 0) {
170
+ logger.log(chalk.bold("\nRecommendations:"));
171
+ for (const rec of result.recommendations) {
172
+ logger.log(` - ${rec}`);
173
+ }
174
+ }
175
+ }
176
+
177
+ await shutdown();
178
+ } catch (err) {
179
+ logger.error(`Failed: ${err.message}`);
180
+ process.exit(1);
181
+ }
182
+ });
183
+
184
+ // evolution repair <issue>
185
+ evolution
186
+ .command("repair")
187
+ .description("Self-repair a diagnosed issue")
188
+ .argument("<issue>", "Issue type (high-memory|stale-cache|degraded-model)")
189
+ .option("--json", "Output as JSON")
190
+ .action(async (issue, options) => {
191
+ try {
192
+ const ctx = await bootstrap({ verbose: program.opts().verbose });
193
+ if (!ctx.db) {
194
+ logger.error("Database not available");
195
+ process.exit(1);
196
+ }
197
+ const db = ctx.db.getDatabase();
198
+ const spinner = ora(`Repairing: ${issue}...`).start();
199
+
200
+ const result = selfRepair(db, issue);
201
+ spinner.succeed("Repair complete");
202
+
203
+ if (options.json) {
204
+ console.log(JSON.stringify(result, null, 2));
205
+ } else {
206
+ logger.log(chalk.bold(`Repaired: ${result.issue}`));
207
+ logger.log(chalk.bold("Actions taken:"));
208
+ for (const action of result.actions) {
209
+ logger.log(` - ${chalk.green(action)}`);
210
+ }
211
+ }
212
+
213
+ await shutdown();
214
+ } catch (err) {
215
+ logger.error(`Failed: ${err.message}`);
216
+ process.exit(1);
217
+ }
218
+ });
219
+
220
+ // evolution predict [user-id]
221
+ evolution
222
+ .command("predict")
223
+ .description("Predict user behavior")
224
+ .argument("[user-id]", "User ID (optional)")
225
+ .option("--json", "Output as JSON")
226
+ .action(async (userId, options) => {
227
+ try {
228
+ const ctx = await bootstrap({ verbose: program.opts().verbose });
229
+ if (!ctx.db) {
230
+ logger.error("Database not available");
231
+ process.exit(1);
232
+ }
233
+ const db = ctx.db.getDatabase();
234
+ const spinner = ora("Predicting behavior...").start();
235
+
236
+ const result = predictBehavior(db, userId);
237
+ spinner.succeed("Prediction complete");
238
+
239
+ if (options.json) {
240
+ console.log(JSON.stringify(result, null, 2));
241
+ } else {
242
+ logger.log(
243
+ chalk.bold(`Behavior Prediction (user: ${result.userId})`),
244
+ );
245
+ logger.log(` Confidence: ${chalk.cyan(result.confidence)}`);
246
+ logger.log(` Based on: ${result.basedOnEvents} events\n`);
247
+
248
+ if (result.predictions.length > 0) {
249
+ logger.log(chalk.bold(" Predicted Actions:"));
250
+ for (const p of result.predictions) {
251
+ const bar = "=".repeat(Math.round(p.probability * 20));
252
+ logger.log(
253
+ ` ${p.action.padEnd(25)} ${chalk.cyan(bar)} ${(p.probability * 100).toFixed(1)}%`,
254
+ );
255
+ }
256
+ } else {
257
+ logger.log(chalk.gray(" No predictions available yet."));
258
+ }
259
+ }
260
+
261
+ await shutdown();
262
+ } catch (err) {
263
+ logger.error(`Failed: ${err.message}`);
264
+ process.exit(1);
265
+ }
266
+ });
267
+
268
+ // evolution growth
269
+ evolution
270
+ .command("growth")
271
+ .description("Show growth log")
272
+ .option("--type <filter>", "Filter by event type")
273
+ .option("--limit <n>", "Limit entries", parseInt)
274
+ .option("--json", "Output as JSON")
275
+ .action(async (options) => {
276
+ try {
277
+ const ctx = await bootstrap({ verbose: program.opts().verbose });
278
+ if (!ctx.db) {
279
+ logger.error("Database not available");
280
+ process.exit(1);
281
+ }
282
+ const db = ctx.db.getDatabase();
283
+ const entries = getGrowthLog(db, {
284
+ type: options.type,
285
+ limit: options.limit,
286
+ });
287
+
288
+ if (options.json) {
289
+ console.log(JSON.stringify(entries, null, 2));
290
+ } else if (entries.length === 0) {
291
+ logger.info("No growth events recorded yet.");
292
+ } else {
293
+ logger.log(chalk.bold(`Growth Log (${entries.length} entries):\n`));
294
+ for (const e of entries) {
295
+ const ts = chalk.gray(e.timestamp);
296
+ const type = chalk.yellow(e.eventType);
297
+ logger.log(` ${ts} ${type}`);
298
+ logger.log(` ${e.description}`);
299
+ }
300
+ }
301
+
302
+ await shutdown();
303
+ } catch (err) {
304
+ logger.error(`Failed: ${err.message}`);
305
+ process.exit(1);
306
+ }
307
+ });
308
+
309
+ // evolution stats
310
+ evolution
311
+ .command("stats")
312
+ .description("Show capabilities and models overview")
313
+ .option("--json", "Output as JSON")
314
+ .action(async (options) => {
315
+ try {
316
+ const ctx = await bootstrap({ verbose: program.opts().verbose });
317
+ if (!ctx.db) {
318
+ logger.error("Database not available");
319
+ process.exit(1);
320
+ }
321
+ const db = ctx.db.getDatabase();
322
+ const caps = getCapabilities(db);
323
+ const mdls = getModels(db);
324
+
325
+ if (options.json) {
326
+ console.log(
327
+ JSON.stringify({ capabilities: caps, models: mdls }, null, 2),
328
+ );
329
+ } else {
330
+ logger.log(chalk.bold(`Capabilities (${caps.length}):\n`));
331
+ if (caps.length === 0) {
332
+ logger.log(chalk.gray(" No capabilities tracked yet."));
333
+ }
334
+ for (const c of caps) {
335
+ const trendColor =
336
+ c.trend === "improving"
337
+ ? chalk.green
338
+ : c.trend === "declining"
339
+ ? chalk.red
340
+ : chalk.gray;
341
+ logger.log(
342
+ ` ${chalk.cyan(c.name.padEnd(20))} score=${c.score.toFixed(2)} trend=${trendColor(c.trend)} [${c.category}]`,
343
+ );
344
+ }
345
+
346
+ logger.log(chalk.bold(`\nModels (${mdls.length}):\n`));
347
+ if (mdls.length === 0) {
348
+ logger.log(chalk.gray(" No models registered yet."));
349
+ }
350
+ for (const m of mdls) {
351
+ logger.log(
352
+ ` ${chalk.cyan(m.id.padEnd(20))} type=${m.type} accuracy=${m.accuracy.toFixed(4)} data=${m.dataPoints}`,
353
+ );
354
+ }
355
+ }
356
+
357
+ await shutdown();
358
+ } catch (err) {
359
+ logger.error(`Failed: ${err.message}`);
360
+ process.exit(1);
361
+ }
362
+ });
363
+
364
+ // evolution export <model-id>
365
+ evolution
366
+ .command("export")
367
+ .description("Export a model for portability")
368
+ .argument("<model-id>", "Model ID to export")
369
+ .option("--json", "Output as JSON")
370
+ .action(async (modelId, options) => {
371
+ try {
372
+ const ctx = await bootstrap({ verbose: program.opts().verbose });
373
+ if (!ctx.db) {
374
+ logger.error("Database not available");
375
+ process.exit(1);
376
+ }
377
+ const db = ctx.db.getDatabase();
378
+
379
+ const result = exportModel(db, modelId);
380
+
381
+ if (options.json) {
382
+ console.log(JSON.stringify(result, null, 2));
383
+ } else {
384
+ logger.log(chalk.bold(`Exported Model: ${result.name}`));
385
+ logger.log(` ID: ${result.id}`);
386
+ logger.log(` Type: ${result.type}`);
387
+ logger.log(` Accuracy: ${result.accuracy.toFixed(4)}`);
388
+ logger.log(` Data Points: ${result.dataPoints}`);
389
+ logger.log(` Exported: ${result.exportedAt}`);
390
+ }
391
+
392
+ await shutdown();
393
+ } catch (err) {
394
+ logger.error(`Failed: ${err.message}`);
395
+ process.exit(1);
396
+ }
397
+ });
398
+ }
@@ -0,0 +1,273 @@
1
+ /**
2
+ * Hierarchical Memory 2.0 commands
3
+ * chainlesschain hmemory store|recall|consolidate|search|stats|share|prune
4
+ */
5
+
6
+ import chalk from "chalk";
7
+ import ora from "ora";
8
+ import { logger } from "../lib/logger.js";
9
+ import { bootstrap, shutdown } from "../runtime/bootstrap.js";
10
+ import {
11
+ storeMemory,
12
+ recallMemory,
13
+ consolidateMemory,
14
+ searchEpisodic,
15
+ searchSemantic,
16
+ getMemoryStats,
17
+ shareMemory,
18
+ pruneMemory,
19
+ } from "../lib/hierarchical-memory.js";
20
+
21
+ export function registerHmemoryCommand(program) {
22
+ const hmemory = program
23
+ .command("hmemory")
24
+ .description("Hierarchical Memory 2.0 — four-layer memory system");
25
+
26
+ // hmemory store <content>
27
+ hmemory
28
+ .command("store")
29
+ .description("Store a memory at the appropriate layer")
30
+ .argument("<content>", "Memory content")
31
+ .option("--importance <n>", "Importance 0.0-1.0", "0.5")
32
+ .option("--type <type>", "Memory type (episodic|semantic)", "episodic")
33
+ .option("--core", "Force store as core memory (importance=1.0)")
34
+ .option("--json", "Output as JSON")
35
+ .action(async (content, options) => {
36
+ try {
37
+ const ctx = await bootstrap({ verbose: program.opts().verbose });
38
+ if (!ctx.db) {
39
+ logger.error("Database not available");
40
+ process.exit(1);
41
+ }
42
+ const db = ctx.db.getDatabase();
43
+ const importance = options.core
44
+ ? 1.0
45
+ : parseFloat(options.importance) || 0.5;
46
+ const entry = storeMemory(db, content, {
47
+ importance,
48
+ type: options.type,
49
+ });
50
+
51
+ if (options.json) {
52
+ console.log(JSON.stringify(entry, null, 2));
53
+ } else {
54
+ logger.success(
55
+ `Memory stored: ${chalk.gray(entry.id.slice(0, 16))} → ${chalk.cyan(entry.layer)}`,
56
+ );
57
+ }
58
+
59
+ await shutdown();
60
+ } catch (err) {
61
+ logger.error(`Failed: ${err.message}`);
62
+ process.exit(1);
63
+ }
64
+ });
65
+
66
+ // hmemory recall <query>
67
+ hmemory
68
+ .command("recall")
69
+ .description("Recall memories with forgetting curve")
70
+ .argument("<query>", "Search query")
71
+ .option("-n, --limit <n>", "Max results", "20")
72
+ .option("--json", "Output as JSON")
73
+ .action(async (query, options) => {
74
+ try {
75
+ const ctx = await bootstrap({ verbose: program.opts().verbose });
76
+ if (!ctx.db) {
77
+ logger.error("Database not available");
78
+ process.exit(1);
79
+ }
80
+ const db = ctx.db.getDatabase();
81
+ const results = recallMemory(db, query, {
82
+ limit: parseInt(options.limit) || 20,
83
+ });
84
+
85
+ if (options.json) {
86
+ console.log(JSON.stringify(results, null, 2));
87
+ } else if (results.length === 0) {
88
+ logger.info(`No memories matching "${query}" above recall threshold`);
89
+ } else {
90
+ logger.log(chalk.bold(`Recalled ${results.length} memories:\n`));
91
+ for (const r of results) {
92
+ const retention = (r.retention * 100).toFixed(0);
93
+ logger.log(
94
+ ` ${chalk.gray(r.id.slice(0, 16))} [${chalk.cyan(r.layer)}] retention=${chalk.yellow(retention + "%")}`,
95
+ );
96
+ logger.log(
97
+ ` ${chalk.white(r.content.substring(0, 120).replace(/\n/g, " "))}`,
98
+ );
99
+ }
100
+ }
101
+
102
+ await shutdown();
103
+ } catch (err) {
104
+ logger.error(`Failed: ${err.message}`);
105
+ process.exit(1);
106
+ }
107
+ });
108
+
109
+ // hmemory consolidate
110
+ hmemory
111
+ .command("consolidate")
112
+ .description("Promote and forget memories across layers")
113
+ .action(async () => {
114
+ try {
115
+ const ctx = await bootstrap({ verbose: program.opts().verbose });
116
+ if (!ctx.db) {
117
+ logger.error("Database not available");
118
+ process.exit(1);
119
+ }
120
+ const db = ctx.db.getDatabase();
121
+ const spinner = ora("Consolidating memories...").start();
122
+ const result = consolidateMemory(db);
123
+ spinner.succeed(
124
+ `Consolidation complete: ${chalk.green(result.promoted)} promoted, ${chalk.red(result.forgotten)} forgotten`,
125
+ );
126
+
127
+ await shutdown();
128
+ } catch (err) {
129
+ logger.error(`Failed: ${err.message}`);
130
+ process.exit(1);
131
+ }
132
+ });
133
+
134
+ // hmemory search <query>
135
+ hmemory
136
+ .command("search")
137
+ .description("Search memories by type")
138
+ .argument("<query>", "Search query")
139
+ .option("--type <type>", "Memory type (episodic|semantic)", "episodic")
140
+ .option("-n, --limit <n>", "Max results", "20")
141
+ .option("--json", "Output as JSON")
142
+ .action(async (query, options) => {
143
+ try {
144
+ const ctx = await bootstrap({ verbose: program.opts().verbose });
145
+ if (!ctx.db) {
146
+ logger.error("Database not available");
147
+ process.exit(1);
148
+ }
149
+ const db = ctx.db.getDatabase();
150
+ const searchFn =
151
+ options.type === "semantic" ? searchSemantic : searchEpisodic;
152
+ const results = searchFn(db, query, {
153
+ limit: parseInt(options.limit) || 20,
154
+ });
155
+
156
+ if (options.json) {
157
+ console.log(JSON.stringify(results, null, 2));
158
+ } else if (results.length === 0) {
159
+ logger.info(`No ${options.type} memories matching "${query}"`);
160
+ } else {
161
+ logger.log(
162
+ chalk.bold(`${options.type} search (${results.length} results):\n`),
163
+ );
164
+ for (const r of results) {
165
+ logger.log(
166
+ ` ${chalk.gray(r.id.slice(0, 16))} [${chalk.cyan(r.layer)}] importance=${chalk.yellow(r.importance)}`,
167
+ );
168
+ logger.log(
169
+ ` ${chalk.white(r.content.substring(0, 120).replace(/\n/g, " "))}`,
170
+ );
171
+ }
172
+ }
173
+
174
+ await shutdown();
175
+ } catch (err) {
176
+ logger.error(`Failed: ${err.message}`);
177
+ process.exit(1);
178
+ }
179
+ });
180
+
181
+ // hmemory stats
182
+ hmemory
183
+ .command("stats")
184
+ .description("Show memory statistics")
185
+ .option("--json", "Output as JSON")
186
+ .action(async (options) => {
187
+ try {
188
+ const ctx = await bootstrap({ verbose: program.opts().verbose });
189
+ if (!ctx.db) {
190
+ logger.error("Database not available");
191
+ process.exit(1);
192
+ }
193
+ const db = ctx.db.getDatabase();
194
+ const stats = getMemoryStats(db);
195
+
196
+ if (options.json) {
197
+ console.log(JSON.stringify(stats, null, 2));
198
+ } else {
199
+ logger.log(chalk.bold("Hierarchical Memory Stats:\n"));
200
+ logger.log(` Working: ${chalk.yellow(stats.working)}`);
201
+ logger.log(` Short-term: ${chalk.yellow(stats.shortTerm)}`);
202
+ logger.log(` Long-term: ${chalk.yellow(stats.longTerm)}`);
203
+ logger.log(` Core: ${chalk.yellow(stats.core)}`);
204
+ logger.log(` Shared: ${chalk.yellow(stats.shared)}`);
205
+ logger.log(
206
+ ` ${chalk.bold("Total:")} ${chalk.green(stats.total)}`,
207
+ );
208
+ }
209
+
210
+ await shutdown();
211
+ } catch (err) {
212
+ logger.error(`Failed: ${err.message}`);
213
+ process.exit(1);
214
+ }
215
+ });
216
+
217
+ // hmemory share <id> <agent-id>
218
+ hmemory
219
+ .command("share")
220
+ .description("Share a memory with another agent")
221
+ .argument("<id>", "Memory ID")
222
+ .argument("<agent-id>", "Target agent ID")
223
+ .option("--privacy <level>", "Privacy level (full|filtered)", "filtered")
224
+ .option("--json", "Output as JSON")
225
+ .action(async (id, agentId, options) => {
226
+ try {
227
+ const ctx = await bootstrap({ verbose: program.opts().verbose });
228
+ if (!ctx.db) {
229
+ logger.error("Database not available");
230
+ process.exit(1);
231
+ }
232
+ const db = ctx.db.getDatabase();
233
+ const result = shareMemory(db, id, agentId, options.privacy);
234
+
235
+ if (options.json) {
236
+ console.log(JSON.stringify(result, null, 2));
237
+ } else {
238
+ logger.success(
239
+ `Memory ${chalk.gray(id.slice(0, 16))} shared with ${chalk.cyan(agentId)} [${options.privacy}]`,
240
+ );
241
+ }
242
+
243
+ await shutdown();
244
+ } catch (err) {
245
+ logger.error(`Failed: ${err.message}`);
246
+ process.exit(1);
247
+ }
248
+ });
249
+
250
+ // hmemory prune
251
+ hmemory
252
+ .command("prune")
253
+ .description("Remove weak old memories")
254
+ .option("--max-age <hours>", "Maximum age in hours", "720")
255
+ .action(async (options) => {
256
+ try {
257
+ const ctx = await bootstrap({ verbose: program.opts().verbose });
258
+ if (!ctx.db) {
259
+ logger.error("Database not available");
260
+ process.exit(1);
261
+ }
262
+ const db = ctx.db.getDatabase();
263
+ const spinner = ora("Pruning stale memories...").start();
264
+ const result = pruneMemory(db, { maxAge: options.maxAge });
265
+ spinner.succeed(`Pruned ${chalk.red(result.pruned)} stale memories`);
266
+
267
+ await shutdown();
268
+ } catch (err) {
269
+ logger.error(`Failed: ${err.message}`);
270
+ process.exit(1);
271
+ }
272
+ });
273
+ }