@theihtisham/agent-shadow-brain 6.0.0 → 6.0.3
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/CHANGELOG.md +372 -0
- package/README.md +366 -355
- package/dist/brain/auto-update.js +1 -1
- package/dist/brain/brain-3d.d.ts +79 -0
- package/dist/brain/brain-3d.d.ts.map +1 -0
- package/dist/brain/brain-3d.js +468 -0
- package/dist/brain/brain-3d.js.map +1 -0
- package/dist/brain/brain-active-learner.d.ts +74 -0
- package/dist/brain/brain-active-learner.d.ts.map +1 -0
- package/dist/brain/brain-active-learner.js +425 -0
- package/dist/brain/brain-active-learner.js.map +1 -0
- package/dist/brain/brain-ascii.d.ts +32 -0
- package/dist/brain/brain-ascii.d.ts.map +1 -0
- package/dist/brain/brain-ascii.js +402 -0
- package/dist/brain/brain-ascii.js.map +1 -0
- package/dist/brain/brain-cinema.d.ts +45 -0
- package/dist/brain/brain-cinema.d.ts.map +1 -0
- package/dist/brain/brain-cinema.js +393 -0
- package/dist/brain/brain-cinema.js.map +1 -0
- package/dist/brain/brain-coach.d.ts +45 -0
- package/dist/brain/brain-coach.d.ts.map +1 -0
- package/dist/brain/brain-coach.js +383 -0
- package/dist/brain/brain-coach.js.map +1 -0
- package/dist/brain/brain-consolidator.d.ts +56 -0
- package/dist/brain/brain-consolidator.d.ts.map +1 -0
- package/dist/brain/brain-consolidator.js +386 -0
- package/dist/brain/brain-consolidator.js.map +1 -0
- package/dist/brain/brain-contradictions.d.ts +57 -0
- package/dist/brain/brain-contradictions.d.ts.map +1 -0
- package/dist/brain/brain-contradictions.js +443 -0
- package/dist/brain/brain-contradictions.js.map +1 -0
- package/dist/brain/brain-diff.d.ts +61 -0
- package/dist/brain/brain-diff.d.ts.map +1 -0
- package/dist/brain/brain-diff.js +439 -0
- package/dist/brain/brain-diff.js.map +1 -0
- package/dist/brain/brain-dna.d.ts +59 -0
- package/dist/brain/brain-dna.d.ts.map +1 -0
- package/dist/brain/brain-dna.js +336 -0
- package/dist/brain/brain-dna.js.map +1 -0
- package/dist/brain/brain-doppelganger.d.ts +32 -0
- package/dist/brain/brain-doppelganger.d.ts.map +1 -0
- package/dist/brain/brain-doppelganger.js +417 -0
- package/dist/brain/brain-doppelganger.js.map +1 -0
- package/dist/brain/brain-graph-walker.d.ts +54 -0
- package/dist/brain/brain-graph-walker.d.ts.map +1 -0
- package/dist/brain/brain-graph-walker.js +412 -0
- package/dist/brain/brain-graph-walker.js.map +1 -0
- package/dist/brain/brain-holiday-card.d.ts +50 -0
- package/dist/brain/brain-holiday-card.d.ts.map +1 -0
- package/dist/brain/brain-holiday-card.js +432 -0
- package/dist/brain/brain-holiday-card.js.map +1 -0
- package/dist/brain/brain-memes.d.ts +44 -0
- package/dist/brain/brain-memes.d.ts.map +1 -0
- package/dist/brain/brain-memes.js +438 -0
- package/dist/brain/brain-memes.js.map +1 -0
- package/dist/brain/brain-memory-tiers.d.ts +67 -0
- package/dist/brain/brain-memory-tiers.d.ts.map +1 -0
- package/dist/brain/brain-memory-tiers.js +292 -0
- package/dist/brain/brain-memory-tiers.js.map +1 -0
- package/dist/brain/brain-notebook.d.ts +68 -0
- package/dist/brain/brain-notebook.d.ts.map +1 -0
- package/dist/brain/brain-notebook.js +379 -0
- package/dist/brain/brain-notebook.js.map +1 -0
- package/dist/brain/brain-portability.js +3 -3
- package/dist/brain/brain-portability.js.map +1 -1
- package/dist/brain/brain-quantize.d.ts +62 -0
- package/dist/brain/brain-quantize.d.ts.map +1 -0
- package/dist/brain/brain-quantize.js +346 -0
- package/dist/brain/brain-quantize.js.map +1 -0
- package/dist/brain/brain-query-expander.d.ts +31 -0
- package/dist/brain/brain-query-expander.d.ts.map +1 -0
- package/dist/brain/brain-query-expander.js +417 -0
- package/dist/brain/brain-query-expander.js.map +1 -0
- package/dist/brain/brain-quest.d.ts +58 -0
- package/dist/brain/brain-quest.d.ts.map +1 -0
- package/dist/brain/brain-quest.js +541 -0
- package/dist/brain/brain-quest.js.map +1 -0
- package/dist/brain/brain-recall-cache.d.ts +73 -0
- package/dist/brain/brain-recall-cache.d.ts.map +1 -0
- package/dist/brain/brain-recall-cache.js +444 -0
- package/dist/brain/brain-recall-cache.js.map +1 -0
- package/dist/brain/brain-reflex.d.ts +55 -0
- package/dist/brain/brain-reflex.d.ts.map +1 -0
- package/dist/brain/brain-reflex.js +364 -0
- package/dist/brain/brain-reflex.js.map +1 -0
- package/dist/brain/brain-replay.d.ts +74 -0
- package/dist/brain/brain-replay.d.ts.map +1 -0
- package/dist/brain/brain-replay.js +336 -0
- package/dist/brain/brain-replay.js.map +1 -0
- package/dist/brain/brain-rerank.d.ts +39 -0
- package/dist/brain/brain-rerank.d.ts.map +1 -0
- package/dist/brain/brain-rerank.js +216 -0
- package/dist/brain/brain-rerank.js.map +1 -0
- package/dist/brain/brain-roast.d.ts +44 -0
- package/dist/brain/brain-roast.d.ts.map +1 -0
- package/dist/brain/brain-roast.js +566 -0
- package/dist/brain/brain-roast.js.map +1 -0
- package/dist/brain/brain-sonification.d.ts +57 -0
- package/dist/brain/brain-sonification.d.ts.map +1 -0
- package/dist/brain/brain-sonification.js +286 -0
- package/dist/brain/brain-sonification.js.map +1 -0
- package/dist/brain/brain-tarot.d.ts +49 -0
- package/dist/brain/brain-tarot.d.ts.map +1 -0
- package/dist/brain/brain-tarot.js +634 -0
- package/dist/brain/brain-tarot.js.map +1 -0
- package/dist/brain/brain-time-capsule.d.ts +80 -0
- package/dist/brain/brain-time-capsule.d.ts.map +1 -0
- package/dist/brain/brain-time-capsule.js +289 -0
- package/dist/brain/brain-time-capsule.js.map +1 -0
- package/dist/brain/brain-trophies.d.ts +60 -0
- package/dist/brain/brain-trophies.d.ts.map +1 -0
- package/dist/brain/brain-trophies.js +431 -0
- package/dist/brain/brain-trophies.js.map +1 -0
- package/dist/brain/brain-working-memory.d.ts +78 -0
- package/dist/brain/brain-working-memory.d.ts.map +1 -0
- package/dist/brain/brain-working-memory.js +367 -0
- package/dist/brain/brain-working-memory.js.map +1 -0
- package/dist/brain/confidence-gate.d.ts +69 -0
- package/dist/brain/confidence-gate.d.ts.map +1 -0
- package/dist/brain/confidence-gate.js +244 -0
- package/dist/brain/confidence-gate.js.map +1 -0
- package/dist/brain/constitution.d.ts +59 -0
- package/dist/brain/constitution.d.ts.map +1 -0
- package/dist/brain/constitution.js +315 -0
- package/dist/brain/constitution.js.map +1 -0
- package/dist/brain/context-continuity.d.ts +78 -0
- package/dist/brain/context-continuity.d.ts.map +1 -0
- package/dist/brain/context-continuity.js +341 -0
- package/dist/brain/context-continuity.js.map +1 -0
- package/dist/brain/embeddings-v2.d.ts +58 -0
- package/dist/brain/embeddings-v2.d.ts.map +1 -0
- package/dist/brain/embeddings-v2.js +344 -0
- package/dist/brain/embeddings-v2.js.map +1 -0
- package/dist/brain/global-brain.d.ts.map +1 -1
- package/dist/brain/global-brain.js +35 -9
- package/dist/brain/global-brain.js.map +1 -1
- package/dist/brain/hive-voice.d.ts +71 -0
- package/dist/brain/hive-voice.d.ts.map +1 -0
- package/dist/brain/hive-voice.js +352 -0
- package/dist/brain/hive-voice.js.map +1 -0
- package/dist/brain/live-brain.d.ts +119 -0
- package/dist/brain/live-brain.d.ts.map +1 -0
- package/dist/brain/live-brain.js +405 -0
- package/dist/brain/live-brain.js.map +1 -0
- package/dist/brain/markdown-export.d.ts +48 -0
- package/dist/brain/markdown-export.d.ts.map +1 -0
- package/dist/brain/markdown-export.js +382 -0
- package/dist/brain/markdown-export.js.map +1 -0
- package/dist/brain/mcp-server.d.ts +4 -0
- package/dist/brain/mcp-server.d.ts.map +1 -1
- package/dist/brain/mcp-server.js +81 -5
- package/dist/brain/mcp-server.js.map +1 -1
- package/dist/brain/memory-seeder.d.ts +78 -0
- package/dist/brain/memory-seeder.d.ts.map +1 -0
- package/dist/brain/memory-seeder.js +326 -0
- package/dist/brain/memory-seeder.js.map +1 -0
- package/dist/brain/multimodal-vision.d.ts +38 -0
- package/dist/brain/multimodal-vision.d.ts.map +1 -0
- package/dist/brain/multimodal-vision.js +257 -0
- package/dist/brain/multimodal-vision.js.map +1 -0
- package/dist/brain/orchestrator.js +1 -1
- package/dist/brain/otel-lite.d.ts +71 -0
- package/dist/brain/otel-lite.d.ts.map +1 -0
- package/dist/brain/otel-lite.js +232 -0
- package/dist/brain/otel-lite.js.map +1 -0
- package/dist/brain/token-economy.d.ts +2 -0
- package/dist/brain/token-economy.d.ts.map +1 -1
- package/dist/brain/token-economy.js +80 -24
- package/dist/brain/token-economy.js.map +1 -1
- package/dist/cli.js +1120 -32
- package/dist/cli.js.map +1 -1
- package/dist/dashboard/server.d.ts +5 -0
- package/dist/dashboard/server.d.ts.map +1 -1
- package/dist/dashboard/server.js +355 -2
- package/dist/dashboard/server.js.map +1 -1
- package/dist/dashboard/v6-dashboard-html.d.ts +1 -1
- package/dist/dashboard/v6-dashboard-html.d.ts.map +1 -1
- package/dist/dashboard/v6-dashboard-html.js +755 -85
- package/dist/dashboard/v6-dashboard-html.js.map +1 -1
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -1
- package/dist/types.d.ts +17 -12
- package/dist/types.d.ts.map +1 -1
- package/docs/launch/README.md +61 -0
- package/docs/launch/RELEASE_CHECKLIST_v6.0.3.md +102 -0
- package/docs/launch/RELEASE_NOTES_v6.0.3.md +111 -0
- package/package.json +25 -13
- package/tools/export-resume-pack.mjs +56 -0
- package/tools/record-global-memory.mjs +72 -0
package/dist/cli.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
// src/cli.ts — CLI entry point for Shadow Brain v6.0.
|
|
2
|
+
// src/cli.ts — CLI entry point for Shadow Brain v6.0.2 "Singularity"
|
|
3
3
|
import { Command } from 'commander';
|
|
4
4
|
import chalk from 'chalk';
|
|
5
5
|
import Conf from 'conf';
|
|
@@ -8,7 +8,7 @@ import * as path from 'path';
|
|
|
8
8
|
import * as os from 'os';
|
|
9
9
|
import { Orchestrator } from './brain/orchestrator.js';
|
|
10
10
|
import { detectRunningAgents, createAdapter } from './adapters/index.js';
|
|
11
|
-
const VERSION = '6.0.
|
|
11
|
+
const VERSION = '6.0.3';
|
|
12
12
|
const config = new Conf({
|
|
13
13
|
projectName: 'shadow-brain',
|
|
14
14
|
defaults: {
|
|
@@ -24,13 +24,16 @@ const config = new Conf({
|
|
|
24
24
|
});
|
|
25
25
|
function mergeConfig(cliOpts) {
|
|
26
26
|
const saved = config.store;
|
|
27
|
+
const watchMode = cliOpts.watchMode === false || cliOpts.watch === false
|
|
28
|
+
? false
|
|
29
|
+
: saved.watchMode !== false;
|
|
27
30
|
return {
|
|
28
31
|
provider: (cliOpts.provider || saved.provider || 'ollama'),
|
|
29
32
|
apiKey: cliOpts.apiKey || saved.apiKey,
|
|
30
33
|
model: cliOpts.model || saved.model,
|
|
31
34
|
agents: (cliOpts.agents?.split(',') || saved.agents || ['claude-code']),
|
|
32
35
|
projectDir: cliOpts.projectDir || cliOpts.args?.[0] || saved.projectDir || process.cwd(),
|
|
33
|
-
watchMode
|
|
36
|
+
watchMode,
|
|
34
37
|
autoInject: cliOpts.inject !== false && (saved.autoInject !== false),
|
|
35
38
|
reviewDepth: (cliOpts.depth || saved.reviewDepth || 'standard'),
|
|
36
39
|
brainPersonality: (cliOpts.personality || saved.brainPersonality || 'balanced'),
|
|
@@ -625,6 +628,8 @@ const dashCmd = new Command('dash')
|
|
|
625
628
|
.option('--depth <depth>', 'Review depth (quick|standard|deep)')
|
|
626
629
|
.option('--agents <agents>', 'Comma-separated list of agents to watch')
|
|
627
630
|
.option('--port <port>', 'Dashboard port', '7341')
|
|
631
|
+
.option('--host <host>', 'Dashboard bind host', '127.0.0.1')
|
|
632
|
+
.option('--no-analysis', 'Start only the dashboard UI/API without background project analysis')
|
|
628
633
|
.option('--no-open', 'Do not open browser automatically')
|
|
629
634
|
.action(async (projectDir, opts) => {
|
|
630
635
|
const brainConfig = mergeConfig({ ...opts, projectDir });
|
|
@@ -666,7 +671,17 @@ const dashCmd = new Command('dash')
|
|
|
666
671
|
}
|
|
667
672
|
catch { /* ignore */ }
|
|
668
673
|
}
|
|
669
|
-
|
|
674
|
+
if (opts.analysis !== false) {
|
|
675
|
+
setTimeout(() => {
|
|
676
|
+
orchestrator.start().catch((err) => {
|
|
677
|
+
console.error(chalk.red(' Background analysis error:'), err?.message || String(err));
|
|
678
|
+
});
|
|
679
|
+
}, 250);
|
|
680
|
+
}
|
|
681
|
+
else {
|
|
682
|
+
console.log(chalk.dim(' Background analysis disabled; dashboard UI/API only.\n'));
|
|
683
|
+
}
|
|
684
|
+
await new Promise(() => { });
|
|
670
685
|
}
|
|
671
686
|
catch (err) {
|
|
672
687
|
console.error(chalk.red(' Error:'), err.message);
|
|
@@ -2442,7 +2457,7 @@ const v5Cmd = new Command('v5')
|
|
|
2442
2457
|
const program = new Command();
|
|
2443
2458
|
program
|
|
2444
2459
|
.name('shadow-brain')
|
|
2445
|
-
.description('Shadow Brain
|
|
2460
|
+
.description('Shadow Brain v6.0.3 - local cross-agent memory, live brain health, resume context, and safety controls')
|
|
2446
2461
|
.version(VERSION);
|
|
2447
2462
|
program.addCommand(startCmd);
|
|
2448
2463
|
program.addCommand(reviewCmd);
|
|
@@ -3048,17 +3063,22 @@ const globalBrainCmd = new Command('global')
|
|
|
3048
3063
|
.action(async () => {
|
|
3049
3064
|
const { getGlobalBrain } = await import('./brain/global-brain.js');
|
|
3050
3065
|
const brain = getGlobalBrain();
|
|
3051
|
-
|
|
3052
|
-
|
|
3053
|
-
|
|
3054
|
-
|
|
3055
|
-
|
|
3056
|
-
|
|
3057
|
-
|
|
3058
|
-
|
|
3059
|
-
|
|
3060
|
-
|
|
3061
|
-
|
|
3066
|
+
try {
|
|
3067
|
+
await brain.init();
|
|
3068
|
+
const s = brain.getStats();
|
|
3069
|
+
console.log(chalk.magenta.bold(`\n SHADOW BRAIN v${VERSION} — Global Brain`));
|
|
3070
|
+
console.log(` Projects: ${chalk.cyan(s.totalProjects)}`);
|
|
3071
|
+
console.log(` Agents: ${chalk.cyan(s.totalAgents)}`);
|
|
3072
|
+
console.log(` Entries: ${chalk.cyan(s.totalEntries)}`);
|
|
3073
|
+
console.log(` Size: ${chalk.cyan(s.totalSizeMB.toFixed(2) + ' MB')}`);
|
|
3074
|
+
console.log(` Hit rate: ${chalk.cyan((s.hitRate * 100).toFixed(1) + '%')} (${s.hits}/${s.hits + s.misses})`);
|
|
3075
|
+
console.log(` Pending: ${chalk.cyan(s.pendingWrites)}`);
|
|
3076
|
+
console.log(` Uptime: ${chalk.cyan(Math.round(s.uptime / 1000) + 's')}`);
|
|
3077
|
+
console.log(` Last sync: ${chalk.dim(s.lastSync.toISOString())}`);
|
|
3078
|
+
}
|
|
3079
|
+
finally {
|
|
3080
|
+
await brain.shutdown();
|
|
3081
|
+
}
|
|
3062
3082
|
}))
|
|
3063
3083
|
.addCommand(new Command('recall')
|
|
3064
3084
|
.description('Recall entries from the global brain — works across projects + agents')
|
|
@@ -3070,20 +3090,25 @@ const globalBrainCmd = new Command('global')
|
|
|
3070
3090
|
.action(async (opts) => {
|
|
3071
3091
|
const { getGlobalBrain } = await import('./brain/global-brain.js');
|
|
3072
3092
|
const brain = getGlobalBrain();
|
|
3073
|
-
|
|
3074
|
-
|
|
3075
|
-
|
|
3076
|
-
|
|
3077
|
-
|
|
3078
|
-
|
|
3079
|
-
|
|
3080
|
-
|
|
3081
|
-
|
|
3082
|
-
|
|
3093
|
+
try {
|
|
3094
|
+
await brain.init();
|
|
3095
|
+
const results = brain.recall({
|
|
3096
|
+
keywords: opts.query ? opts.query.split(/\s+/) : undefined,
|
|
3097
|
+
agentTool: opts.agent,
|
|
3098
|
+
category: opts.category,
|
|
3099
|
+
limit: parseInt(opts.limit, 10),
|
|
3100
|
+
});
|
|
3101
|
+
if (opts.json) {
|
|
3102
|
+
console.log(JSON.stringify(results, null, 2));
|
|
3103
|
+
return;
|
|
3104
|
+
}
|
|
3105
|
+
console.log(chalk.magenta.bold(`\n SHADOW BRAIN v${VERSION} — Global Recall (${results.length})`));
|
|
3106
|
+
for (const r of results) {
|
|
3107
|
+
console.log(` ${chalk.cyan('[' + r.agentTool + ']')} ${chalk.dim(r.category)} ${chalk.white(r.content.slice(0, 100))}`);
|
|
3108
|
+
}
|
|
3083
3109
|
}
|
|
3084
|
-
|
|
3085
|
-
|
|
3086
|
-
console.log(` ${chalk.cyan('[' + r.agentTool + ']')} ${chalk.dim(r.category)} ${chalk.white(r.content.slice(0, 100))}`);
|
|
3110
|
+
finally {
|
|
3111
|
+
await brain.shutdown();
|
|
3087
3112
|
}
|
|
3088
3113
|
}))
|
|
3089
3114
|
.addCommand(new Command('cache')
|
|
@@ -3101,9 +3126,14 @@ const globalBrainCmd = new Command('global')
|
|
|
3101
3126
|
.action(async () => {
|
|
3102
3127
|
const { getGlobalBrain } = await import('./brain/global-brain.js');
|
|
3103
3128
|
const brain = getGlobalBrain();
|
|
3104
|
-
|
|
3105
|
-
|
|
3106
|
-
|
|
3129
|
+
try {
|
|
3130
|
+
await brain.init();
|
|
3131
|
+
await brain.sync();
|
|
3132
|
+
console.log(chalk.green(' ✓ Synced to disk.'));
|
|
3133
|
+
}
|
|
3134
|
+
finally {
|
|
3135
|
+
await brain.shutdown();
|
|
3136
|
+
}
|
|
3107
3137
|
}));
|
|
3108
3138
|
const detachAllCmd = new Command('detach-all')
|
|
3109
3139
|
.description('Remove Shadow Brain hooks from every detected AI agent without creating new hooks')
|
|
@@ -3215,6 +3245,183 @@ const handoffCmd = new Command('handoff')
|
|
|
3215
3245
|
await brain.shutdown();
|
|
3216
3246
|
}
|
|
3217
3247
|
});
|
|
3248
|
+
const resumeSeedCmd = new Command('resume-seed')
|
|
3249
|
+
.description('Generate a source-backed context continuity seed for fresh or compacted agent sessions')
|
|
3250
|
+
.argument('[project-dir]', 'Project directory', process.cwd())
|
|
3251
|
+
.option('--max-memories <n>', 'Maximum recalled memories to include', '12')
|
|
3252
|
+
.option('-o, --output <file>', 'Write markdown seed to this file')
|
|
3253
|
+
.option('--json', 'Output JSON instead of markdown')
|
|
3254
|
+
.action(async (projectDir, opts) => {
|
|
3255
|
+
const { buildContextSeedPack } = await import('./brain/context-continuity.js');
|
|
3256
|
+
const { getGlobalBrain } = await import('./brain/global-brain.js');
|
|
3257
|
+
const resolvedProjectDir = path.resolve(projectDir);
|
|
3258
|
+
try {
|
|
3259
|
+
const pack = await buildContextSeedPack({
|
|
3260
|
+
projectDir: resolvedProjectDir,
|
|
3261
|
+
maxMemories: parseInt(opts.maxMemories || '12', 10),
|
|
3262
|
+
});
|
|
3263
|
+
if (opts.output) {
|
|
3264
|
+
const outPath = path.resolve(resolvedProjectDir, opts.output);
|
|
3265
|
+
fs.mkdirSync(path.dirname(outPath), { recursive: true });
|
|
3266
|
+
fs.writeFileSync(outPath, pack.markdown, 'utf-8');
|
|
3267
|
+
console.log(chalk.green(` ✓ Context continuity seed written: ${outPath}`));
|
|
3268
|
+
return;
|
|
3269
|
+
}
|
|
3270
|
+
if (opts.json)
|
|
3271
|
+
console.log(JSON.stringify(pack, null, 2));
|
|
3272
|
+
else
|
|
3273
|
+
console.log(pack.markdown);
|
|
3274
|
+
}
|
|
3275
|
+
finally {
|
|
3276
|
+
await getGlobalBrain().shutdown().catch(() => { });
|
|
3277
|
+
}
|
|
3278
|
+
});
|
|
3279
|
+
function splitQueries(value) {
|
|
3280
|
+
if (!value)
|
|
3281
|
+
return undefined;
|
|
3282
|
+
return value
|
|
3283
|
+
.split('|')
|
|
3284
|
+
.map(item => item.trim())
|
|
3285
|
+
.filter(Boolean);
|
|
3286
|
+
}
|
|
3287
|
+
const liveBrainCmd = new Command('live-brain')
|
|
3288
|
+
.alias('live')
|
|
3289
|
+
.description('v6.0.3 Live Brain - memory health, agent briefing, recall eval, and training export');
|
|
3290
|
+
liveBrainCmd.addCommand(new Command('status')
|
|
3291
|
+
.description('Show source-backed live brain health for a project')
|
|
3292
|
+
.argument('[project-dir]', 'Project directory', process.cwd())
|
|
3293
|
+
.option('--max-memories <n>', 'Maximum memories to include', '12')
|
|
3294
|
+
.option('--queries <q1|q2>', 'Pipe-separated recall eval queries')
|
|
3295
|
+
.option('--no-global-fallback', 'Do not fall back to latest global memories when project memory is empty')
|
|
3296
|
+
.option('--json', 'Output JSON')
|
|
3297
|
+
.action(async (projectDir, opts) => {
|
|
3298
|
+
const { getLiveBrain } = await import('./brain/live-brain.js');
|
|
3299
|
+
const report = await getLiveBrain().report({
|
|
3300
|
+
projectDir,
|
|
3301
|
+
maxMemories: parseInt(opts.maxMemories || '12', 10),
|
|
3302
|
+
queries: splitQueries(opts.queries),
|
|
3303
|
+
globalFallback: opts.globalFallback,
|
|
3304
|
+
});
|
|
3305
|
+
if (opts.json) {
|
|
3306
|
+
console.log(JSON.stringify(report, null, 2));
|
|
3307
|
+
return;
|
|
3308
|
+
}
|
|
3309
|
+
console.log(chalk.magenta.bold(`\n SHADOW BRAIN v${VERSION} - Live Brain`));
|
|
3310
|
+
console.log(` Project: ${chalk.cyan(report.projectName)} ${chalk.dim(report.projectDir)}`);
|
|
3311
|
+
console.log(` Scope: ${report.projectScoped ? chalk.green('project') : chalk.yellow('global fallback')}`);
|
|
3312
|
+
console.log(` Memory: ${chalk.cyan(report.memoryQuality.totalEntries)} entries, ${chalk.cyan(report.memoryQuality.avgScore + '/100')} avg quality`);
|
|
3313
|
+
console.log(` Sources: ${chalk.cyan(Math.round(report.memoryQuality.sourceCoverage * 100) + '%')} coverage`);
|
|
3314
|
+
console.log(` Recall: ${chalk.cyan(report.recallEval.avgHitCount)} avg hits/query, ${chalk.cyan(Math.round(report.recallEval.sourceBackedHitRate * 100) + '%')} source-backed hits`);
|
|
3315
|
+
if (report.learningActions.length) {
|
|
3316
|
+
console.log(chalk.yellow('\n Recommended actions'));
|
|
3317
|
+
for (const action of report.learningActions) {
|
|
3318
|
+
console.log(` [${action.priority}] ${action.title}`);
|
|
3319
|
+
console.log(chalk.dim(` ${action.reason}`));
|
|
3320
|
+
if (action.command)
|
|
3321
|
+
console.log(chalk.dim(` ${action.command}`));
|
|
3322
|
+
}
|
|
3323
|
+
}
|
|
3324
|
+
else {
|
|
3325
|
+
console.log(chalk.green('\n No immediate hygiene actions.'));
|
|
3326
|
+
}
|
|
3327
|
+
}));
|
|
3328
|
+
liveBrainCmd.addCommand(new Command('brief')
|
|
3329
|
+
.description('Print or write the live agent briefing for fresh sessions and handoffs')
|
|
3330
|
+
.argument('[project-dir]', 'Project directory', process.cwd())
|
|
3331
|
+
.option('-o, --output <file>', 'Write briefing markdown to this file')
|
|
3332
|
+
.option('--max-memories <n>', 'Maximum memories to include', '12')
|
|
3333
|
+
.option('--no-global-fallback', 'Do not fall back to latest global memories when project memory is empty')
|
|
3334
|
+
.action(async (projectDir, opts) => {
|
|
3335
|
+
const { getLiveBrain } = await import('./brain/live-brain.js');
|
|
3336
|
+
const report = await getLiveBrain().report({
|
|
3337
|
+
projectDir,
|
|
3338
|
+
maxMemories: parseInt(opts.maxMemories || '12', 10),
|
|
3339
|
+
globalFallback: opts.globalFallback,
|
|
3340
|
+
});
|
|
3341
|
+
if (opts.output) {
|
|
3342
|
+
const outPath = path.resolve(projectDir, opts.output);
|
|
3343
|
+
fs.mkdirSync(path.dirname(outPath), { recursive: true });
|
|
3344
|
+
fs.writeFileSync(outPath, report.agentBriefing, 'utf-8');
|
|
3345
|
+
console.log(chalk.green(` Live agent briefing written: ${outPath}`));
|
|
3346
|
+
return;
|
|
3347
|
+
}
|
|
3348
|
+
console.log(report.agentBriefing);
|
|
3349
|
+
}));
|
|
3350
|
+
liveBrainCmd.addCommand(new Command('eval')
|
|
3351
|
+
.description('Run recall checks that show whether agents can find the right long-memory context')
|
|
3352
|
+
.argument('[project-dir]', 'Project directory', process.cwd())
|
|
3353
|
+
.option('--queries <q1|q2>', 'Pipe-separated recall eval queries')
|
|
3354
|
+
.option('--json', 'Output JSON')
|
|
3355
|
+
.action(async (projectDir, opts) => {
|
|
3356
|
+
const { getLiveBrain } = await import('./brain/live-brain.js');
|
|
3357
|
+
const report = await getLiveBrain().report({
|
|
3358
|
+
projectDir,
|
|
3359
|
+
queries: splitQueries(opts.queries),
|
|
3360
|
+
});
|
|
3361
|
+
if (opts.json) {
|
|
3362
|
+
console.log(JSON.stringify(report.recallEval, null, 2));
|
|
3363
|
+
return;
|
|
3364
|
+
}
|
|
3365
|
+
console.log(chalk.magenta.bold(`\n SHADOW BRAIN v${VERSION} - Recall Eval`));
|
|
3366
|
+
for (const item of report.recallEval.cases) {
|
|
3367
|
+
const color = item.hitCount ? chalk.green : chalk.red;
|
|
3368
|
+
console.log(color(` ${item.query}: ${item.hitCount} hits (${item.sourceBackedHits} source-backed)`));
|
|
3369
|
+
if (item.topCategories.length)
|
|
3370
|
+
console.log(chalk.dim(` ${item.topCategories.join(', ')}`));
|
|
3371
|
+
for (const warning of item.warnings)
|
|
3372
|
+
console.log(chalk.yellow(` ${warning}`));
|
|
3373
|
+
}
|
|
3374
|
+
}));
|
|
3375
|
+
liveBrainCmd.addCommand(new Command('hygiene')
|
|
3376
|
+
.description('List concrete memory cleanup and learning actions')
|
|
3377
|
+
.argument('[project-dir]', 'Project directory', process.cwd())
|
|
3378
|
+
.option('--json', 'Output JSON')
|
|
3379
|
+
.action(async (projectDir, opts) => {
|
|
3380
|
+
const { getLiveBrain } = await import('./brain/live-brain.js');
|
|
3381
|
+
const report = await getLiveBrain().report({ projectDir });
|
|
3382
|
+
if (opts.json) {
|
|
3383
|
+
console.log(JSON.stringify({
|
|
3384
|
+
actions: report.learningActions,
|
|
3385
|
+
quality: report.memoryQuality,
|
|
3386
|
+
lowQualityMemories: report.lowQualityMemories,
|
|
3387
|
+
staleMemories: report.staleMemories,
|
|
3388
|
+
}, null, 2));
|
|
3389
|
+
return;
|
|
3390
|
+
}
|
|
3391
|
+
console.log(chalk.magenta.bold(`\n SHADOW BRAIN v${VERSION} - Memory Hygiene`));
|
|
3392
|
+
for (const action of report.learningActions) {
|
|
3393
|
+
console.log(` [${action.priority}] ${chalk.cyan(action.title)}`);
|
|
3394
|
+
console.log(chalk.dim(` ${action.reason}`));
|
|
3395
|
+
if (action.command)
|
|
3396
|
+
console.log(chalk.dim(` ${action.command}`));
|
|
3397
|
+
}
|
|
3398
|
+
if (!report.learningActions.length)
|
|
3399
|
+
console.log(chalk.green(' No immediate cleanup actions.'));
|
|
3400
|
+
}));
|
|
3401
|
+
liveBrainCmd.addCommand(new Command('train-pack')
|
|
3402
|
+
.description('Export source-backed memories as JSONL rows for evals, distillation, or local fine-tuning pipelines')
|
|
3403
|
+
.argument('[project-dir]', 'Project directory', process.cwd())
|
|
3404
|
+
.option('-o, --out <file>', 'Output JSONL file')
|
|
3405
|
+
.option('--max-rows <n>', 'Maximum rows', '200')
|
|
3406
|
+
.option('--include-low-quality', 'Include low-quality or source-light memories')
|
|
3407
|
+
.action(async (projectDir, opts) => {
|
|
3408
|
+
const { getLiveBrain } = await import('./brain/live-brain.js');
|
|
3409
|
+
const jsonl = await getLiveBrain().trainingJsonl({
|
|
3410
|
+
projectDir,
|
|
3411
|
+
maxRows: parseInt(opts.maxRows || '200', 10),
|
|
3412
|
+
includeLowQuality: !!opts.includeLowQuality,
|
|
3413
|
+
});
|
|
3414
|
+
if (opts.out) {
|
|
3415
|
+
const outPath = path.resolve(projectDir, opts.out);
|
|
3416
|
+
fs.mkdirSync(path.dirname(outPath), { recursive: true });
|
|
3417
|
+
fs.writeFileSync(outPath, jsonl ? jsonl + '\n' : '', 'utf-8');
|
|
3418
|
+
console.log(chalk.green(` Training pack written: ${outPath}`));
|
|
3419
|
+
return;
|
|
3420
|
+
}
|
|
3421
|
+
process.stdout.write(jsonl);
|
|
3422
|
+
if (jsonl)
|
|
3423
|
+
process.stdout.write('\n');
|
|
3424
|
+
}));
|
|
3218
3425
|
function readStdin() {
|
|
3219
3426
|
return new Promise((resolve) => {
|
|
3220
3427
|
let data = '';
|
|
@@ -3330,6 +3537,8 @@ program.addCommand(detachAllCmd);
|
|
|
3330
3537
|
program.addCommand(auditHooksCmd);
|
|
3331
3538
|
program.addCommand(timelineCmd);
|
|
3332
3539
|
program.addCommand(handoffCmd);
|
|
3540
|
+
program.addCommand(resumeSeedCmd);
|
|
3541
|
+
program.addCommand(liveBrainCmd);
|
|
3333
3542
|
program.addCommand(firewallCmd);
|
|
3334
3543
|
program.addCommand(proofCmd);
|
|
3335
3544
|
// ── v6.0 "Hive Mind" commands ────────────────────────────────────────────────
|
|
@@ -3913,5 +4122,884 @@ program.addCommand(gardenCmd);
|
|
|
3913
4122
|
program.addCommand(prReviewCmd);
|
|
3914
4123
|
program.addCommand(teamSyncCmd);
|
|
3915
4124
|
program.addCommand(exchangeCmd);
|
|
4125
|
+
// ════════════════════════════════════════════════════════════════════
|
|
4126
|
+
// v6.0.2 "Singularity" — 5 viral features + infrastructure + DX
|
|
4127
|
+
// ════════════════════════════════════════════════════════════════════
|
|
4128
|
+
// ── 🎬 Brain Replay ─────────────────────────────────────────────────
|
|
4129
|
+
const replayCmd = new Command('replay')
|
|
4130
|
+
.description('Brain Replay — scrubbable timeline of every brain event since day zero')
|
|
4131
|
+
.option('--project <name>', 'Project name', 'default');
|
|
4132
|
+
replayCmd.addCommand(new Command('export')
|
|
4133
|
+
.description('Export the timeline as svg | jsonl | csv')
|
|
4134
|
+
.option('--project <name>', 'Project name', 'default')
|
|
4135
|
+
.option('--format <fmt>', 'svg|jsonl|csv', 'svg')
|
|
4136
|
+
.option('--out <path>', 'Output path (default: stdout for svg/csv, file for jsonl)')
|
|
4137
|
+
.action(async (opts) => {
|
|
4138
|
+
const { getBrainReplay } = await import('./brain/brain-replay.js');
|
|
4139
|
+
const out = getBrainReplay().export(opts.project, opts.format);
|
|
4140
|
+
if (opts.out) {
|
|
4141
|
+
fs.writeFileSync(opts.out, typeof out === 'string' ? out : out);
|
|
4142
|
+
console.log(chalk.green(` ✓ ${opts.format} written to ${opts.out}`));
|
|
4143
|
+
}
|
|
4144
|
+
else {
|
|
4145
|
+
process.stdout.write(typeof out === 'string' ? out : out.toString());
|
|
4146
|
+
}
|
|
4147
|
+
}));
|
|
4148
|
+
replayCmd.addCommand(new Command('frame-at')
|
|
4149
|
+
.description('Show the brain state at a specific timestamp')
|
|
4150
|
+
.requiredOption('--ts <epoch>', 'Unix epoch ms')
|
|
4151
|
+
.option('--project <name>', 'Project name', 'default')
|
|
4152
|
+
.action(async (opts) => {
|
|
4153
|
+
const { getBrainReplay } = await import('./brain/brain-replay.js');
|
|
4154
|
+
const frame = getBrainReplay().frameAt(opts.project, parseInt(opts.ts, 10));
|
|
4155
|
+
console.log(JSON.stringify(frame, null, 2));
|
|
4156
|
+
}));
|
|
4157
|
+
replayCmd.addCommand(new Command('compress')
|
|
4158
|
+
.description('Compact old events into snapshots to bound disk use')
|
|
4159
|
+
.option('--project <name>', 'Project name', 'default')
|
|
4160
|
+
.action(async (opts) => {
|
|
4161
|
+
const { getBrainReplay } = await import('./brain/brain-replay.js');
|
|
4162
|
+
getBrainReplay().compress(opts.project);
|
|
4163
|
+
console.log(chalk.green(' ✓ replay log compressed'));
|
|
4164
|
+
}));
|
|
4165
|
+
// ── 🧬 Brain DNA ─────────────────────────────────────────────────────
|
|
4166
|
+
const brainDnaCmd = new Command('brain-dna')
|
|
4167
|
+
.description('Brain DNA — Spotify-Wrapped-style shareable fingerprint card');
|
|
4168
|
+
brainDnaCmd.addCommand(new Command('card')
|
|
4169
|
+
.description('Generate a DNA card for a project')
|
|
4170
|
+
.option('--project <name>', 'Project name', 'default')
|
|
4171
|
+
.option('--style <s>', 'card|poster|banner', 'card')
|
|
4172
|
+
.option('--out <path>', 'Output SVG path (default stdout)')
|
|
4173
|
+
.action(async (opts) => {
|
|
4174
|
+
const { getBrainDna } = await import('./brain/brain-dna.js');
|
|
4175
|
+
const { svg, stats } = getBrainDna().generate(opts.project, { style: opts.style });
|
|
4176
|
+
if (opts.out) {
|
|
4177
|
+
fs.writeFileSync(opts.out, svg);
|
|
4178
|
+
console.log(chalk.green(` ✓ ${opts.style} written to ${opts.out}`));
|
|
4179
|
+
console.log(chalk.dim(` archetype: ${stats.archetype} · entities: ${stats.totalEntities} · age: ${stats.ageDays}d`));
|
|
4180
|
+
}
|
|
4181
|
+
else
|
|
4182
|
+
process.stdout.write(svg);
|
|
4183
|
+
}));
|
|
4184
|
+
brainDnaCmd.addCommand(new Command('compare')
|
|
4185
|
+
.description('Side-by-side DNA cards for two projects')
|
|
4186
|
+
.requiredOption('--a <projectA>', 'First project name')
|
|
4187
|
+
.requiredOption('--b <projectB>', 'Second project name')
|
|
4188
|
+
.option('--out <path>', 'Output SVG path (default stdout)')
|
|
4189
|
+
.action(async (opts) => {
|
|
4190
|
+
const { getBrainDna } = await import('./brain/brain-dna.js');
|
|
4191
|
+
const { svg } = getBrainDna().compareCards(opts.a, opts.b);
|
|
4192
|
+
if (opts.out) {
|
|
4193
|
+
fs.writeFileSync(opts.out, svg);
|
|
4194
|
+
console.log(chalk.green(` ✓ comparison written to ${opts.out}`));
|
|
4195
|
+
}
|
|
4196
|
+
else
|
|
4197
|
+
process.stdout.write(svg);
|
|
4198
|
+
}));
|
|
4199
|
+
brainDnaCmd.addCommand(new Command('archetypes')
|
|
4200
|
+
.description('List all personality archetypes')
|
|
4201
|
+
.action(async () => {
|
|
4202
|
+
const { getBrainDna } = await import('./brain/brain-dna.js');
|
|
4203
|
+
for (const a of getBrainDna().topArchetypes())
|
|
4204
|
+
console.log(` • ${a}`);
|
|
4205
|
+
}));
|
|
4206
|
+
// ── 🗳️ Hive Voice ───────────────────────────────────────────────────
|
|
4207
|
+
const hiveVoiceCmd = new Command('hive-voice')
|
|
4208
|
+
.description('Hive Voice — multi-model debate-vote with dissent + confidence distribution');
|
|
4209
|
+
hiveVoiceCmd.addCommand(new Command('ask')
|
|
4210
|
+
.description('Ask a question; multiple local models vote')
|
|
4211
|
+
.argument('<question...>', 'Question to ask')
|
|
4212
|
+
.option('--rounds <n>', 'Number of debate rounds', '1')
|
|
4213
|
+
.option('--mode <m>', 'unanimous|majority|weighted', 'weighted')
|
|
4214
|
+
.option('--svg <path>', 'Save bar-chart SVG to this path')
|
|
4215
|
+
.option('--json', 'Output full JSON')
|
|
4216
|
+
.action(async (questionParts, opts) => {
|
|
4217
|
+
const { getHiveVoice } = await import('./brain/hive-voice.js');
|
|
4218
|
+
const question = questionParts.join(' ');
|
|
4219
|
+
const result = await getHiveVoice().ask(question, {
|
|
4220
|
+
rounds: parseInt(opts.rounds, 10),
|
|
4221
|
+
mode: opts.mode,
|
|
4222
|
+
});
|
|
4223
|
+
if (opts.svg)
|
|
4224
|
+
fs.writeFileSync(opts.svg, result.svg);
|
|
4225
|
+
if (opts.json)
|
|
4226
|
+
return console.log(JSON.stringify(result, null, 2));
|
|
4227
|
+
console.log(chalk.magenta.bold(`\n HIVE VOTE — ${result.mode}`));
|
|
4228
|
+
console.log(` ${chalk.cyan('consensus:')} ${result.consensus}`);
|
|
4229
|
+
console.log(` ${chalk.cyan('confidence:')} ${(result.confidence * 100).toFixed(0)}%`);
|
|
4230
|
+
console.log(` ${chalk.cyan('voters:')} ${result.votes.length} ${chalk.dim('dissents:')} ${result.dissents.length}`);
|
|
4231
|
+
if (opts.svg)
|
|
4232
|
+
console.log(chalk.green(` ✓ chart written to ${opts.svg}`));
|
|
4233
|
+
}));
|
|
4234
|
+
// ── ⏰ Brain Time Capsule ────────────────────────────────────────────
|
|
4235
|
+
const capsuleCmd = new Command('capsule')
|
|
4236
|
+
.description('Brain Time Capsule — freeze, label, and resurrect brain snapshots');
|
|
4237
|
+
capsuleCmd.addCommand(new Command('freeze')
|
|
4238
|
+
.description('Freeze the current brain into a labelled capsule')
|
|
4239
|
+
.requiredOption('--label <label>', 'Human-readable label')
|
|
4240
|
+
.option('--project <name>', 'Project name', 'default')
|
|
4241
|
+
.option('--description <text>', 'Longer description')
|
|
4242
|
+
.action(async (opts) => {
|
|
4243
|
+
const { getBrainTimeCapsule } = await import('./brain/brain-time-capsule.js');
|
|
4244
|
+
const r = await getBrainTimeCapsule().freeze(opts.project, opts.label, { description: opts.description });
|
|
4245
|
+
console.log(chalk.green(` ✓ capsule frozen: ${r.capsuleId}`));
|
|
4246
|
+
console.log(chalk.dim(` path: ${r.path} size: ${(r.sizeBytes / 1024).toFixed(1)}KB`));
|
|
4247
|
+
}));
|
|
4248
|
+
capsuleCmd.addCommand(new Command('list')
|
|
4249
|
+
.description('List capsules for a project')
|
|
4250
|
+
.option('--project <name>', 'Project name', 'default')
|
|
4251
|
+
.action(async (opts) => {
|
|
4252
|
+
const { getBrainTimeCapsule } = await import('./brain/brain-time-capsule.js');
|
|
4253
|
+
const list = await getBrainTimeCapsule().list(opts.project);
|
|
4254
|
+
for (const c of list)
|
|
4255
|
+
console.log(` ${chalk.cyan(c.capsuleId.padEnd(24))} ${c.label.padEnd(30)} ${chalk.dim(c.createdAt)}`);
|
|
4256
|
+
}));
|
|
4257
|
+
capsuleCmd.addCommand(new Command('restore')
|
|
4258
|
+
.description('Restore a frozen capsule into the active brain')
|
|
4259
|
+
.argument('<capsuleId>', 'Capsule id from `capsule list`')
|
|
4260
|
+
.action(async (capsuleId) => {
|
|
4261
|
+
const { getBrainTimeCapsule } = await import('./brain/brain-time-capsule.js');
|
|
4262
|
+
const r = await getBrainTimeCapsule().restore(capsuleId);
|
|
4263
|
+
console.log(chalk.green(` ✓ restored at ${new Date(r.restoredAt).toISOString()}`));
|
|
4264
|
+
console.log(chalk.dim(` ${r.replacedFiles.length} files replaced`));
|
|
4265
|
+
}));
|
|
4266
|
+
capsuleCmd.addCommand(new Command('inspect')
|
|
4267
|
+
.description('Read-only inspection of a capsule')
|
|
4268
|
+
.argument('<capsuleId>')
|
|
4269
|
+
.action(async (capsuleId) => {
|
|
4270
|
+
const { getBrainTimeCapsule } = await import('./brain/brain-time-capsule.js');
|
|
4271
|
+
const r = await getBrainTimeCapsule().inspect(capsuleId);
|
|
4272
|
+
console.log(JSON.stringify(r, null, 2));
|
|
4273
|
+
}));
|
|
4274
|
+
capsuleCmd.addCommand(new Command('diff')
|
|
4275
|
+
.description('Diff two capsules')
|
|
4276
|
+
.argument('<a>')
|
|
4277
|
+
.argument('<b>')
|
|
4278
|
+
.action(async (a, b) => {
|
|
4279
|
+
const { getBrainTimeCapsule } = await import('./brain/brain-time-capsule.js');
|
|
4280
|
+
const r = await getBrainTimeCapsule().diff(a, b);
|
|
4281
|
+
console.log(JSON.stringify(r, null, 2));
|
|
4282
|
+
}));
|
|
4283
|
+
// ── 🔬 Brain Diff (between two brains) ───────────────────────────────
|
|
4284
|
+
const brainDiffCmd = new Command('brain-diff')
|
|
4285
|
+
.description('Brain Diff — semantic diff between two brains (paths or capsule ids)');
|
|
4286
|
+
brainDiffCmd.addCommand(new Command('compare')
|
|
4287
|
+
.description('Compare brainA vs brainB')
|
|
4288
|
+
.argument('<brainA>', 'Path or capsule id')
|
|
4289
|
+
.argument('<brainB>', 'Path or capsule id')
|
|
4290
|
+
.option('--svg <path>', 'Save Venn-diagram SVG')
|
|
4291
|
+
.option('--narrative', 'Print the English narrative summary')
|
|
4292
|
+
.option('--json', 'Output full JSON report')
|
|
4293
|
+
.action(async (a, b, opts) => {
|
|
4294
|
+
const { getBrainDiff } = await import('./brain/brain-diff.js');
|
|
4295
|
+
const r = await getBrainDiff().diff(a, b);
|
|
4296
|
+
if (opts.svg)
|
|
4297
|
+
fs.writeFileSync(opts.svg, r.svg);
|
|
4298
|
+
if (opts.json)
|
|
4299
|
+
return console.log(JSON.stringify(r, null, 2));
|
|
4300
|
+
console.log(chalk.magenta.bold(`\n BRAIN DIFF`));
|
|
4301
|
+
console.log(chalk.dim(` only in A: ${r.onlyInA.length} only in B: ${r.onlyInB.length} shared: ${r.bothShared.length} conflicting: ${r.conflicting.length}`));
|
|
4302
|
+
console.log(chalk.dim(` similarity: ${(r.stats.similarityScore * 100).toFixed(0)}%`));
|
|
4303
|
+
if (opts.narrative)
|
|
4304
|
+
console.log('\n ' + r.narrative);
|
|
4305
|
+
if (opts.svg)
|
|
4306
|
+
console.log(chalk.green(` ✓ Venn written to ${opts.svg}`));
|
|
4307
|
+
}));
|
|
4308
|
+
// ── 📜 Constitution layer ────────────────────────────────────────────
|
|
4309
|
+
const constitutionCmd = new Command('constitution')
|
|
4310
|
+
.description('Constitution — project invariants the brain enforces');
|
|
4311
|
+
constitutionCmd.addCommand(new Command('init')
|
|
4312
|
+
.description('Create .shadow-brain/constitution.md with a template')
|
|
4313
|
+
.action(async () => {
|
|
4314
|
+
const cwd = process.cwd();
|
|
4315
|
+
const dir = path.join(cwd, '.shadow-brain');
|
|
4316
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
4317
|
+
const target = path.join(dir, 'constitution.md');
|
|
4318
|
+
if (fs.existsSync(target))
|
|
4319
|
+
return console.log(chalk.yellow(' constitution.md already exists.'));
|
|
4320
|
+
fs.writeFileSync(target, `# Project Constitution\n\n## Rule 1\nseverity: must\nscope: code\nNever log PII (emails, names, payment info) in production code paths.\n\n## Rule 2\nseverity: must\nscope: code\nAlways use parameterized queries for SQL — no string concatenation.\n\n## Rule 3\nseverity: should\nscope: tests\nAuth flows must have regression tests for token-bypass attempts.\n`);
|
|
4321
|
+
console.log(chalk.green(` ✓ ${target}`));
|
|
4322
|
+
}));
|
|
4323
|
+
constitutionCmd.addCommand(new Command('rules')
|
|
4324
|
+
.description('List all parsed rules')
|
|
4325
|
+
.action(async () => {
|
|
4326
|
+
const { getConstitution } = await import('./brain/constitution.js');
|
|
4327
|
+
const c = getConstitution(process.cwd());
|
|
4328
|
+
for (const r of c.listRules()) {
|
|
4329
|
+
const sev = r.severity === 'must' ? chalk.red('MUST') : r.severity === 'should' ? chalk.yellow('SHOULD') : chalk.green('NEVER');
|
|
4330
|
+
console.log(` [${sev}] (${r.scope}) ${r.text}`);
|
|
4331
|
+
}
|
|
4332
|
+
c.dispose();
|
|
4333
|
+
}));
|
|
4334
|
+
constitutionCmd.addCommand(new Command('validate')
|
|
4335
|
+
.description('Check a text snippet against constitution rules')
|
|
4336
|
+
.argument('<text...>')
|
|
4337
|
+
.action(async (parts) => {
|
|
4338
|
+
const { getConstitution } = await import('./brain/constitution.js');
|
|
4339
|
+
const c = getConstitution(process.cwd());
|
|
4340
|
+
const r = await c.validate(parts.join(' '));
|
|
4341
|
+
console.log(chalk.cyan(` violations: ${r.violations.length} passed: ${r.passed.length}`));
|
|
4342
|
+
for (const v of r.violations)
|
|
4343
|
+
console.log(chalk.red(` × ${v.rule.text}`));
|
|
4344
|
+
c.dispose();
|
|
4345
|
+
}));
|
|
4346
|
+
// ── 🚦 Confidence Gate ───────────────────────────────────────────────
|
|
4347
|
+
const gateCmd = new Command('gate')
|
|
4348
|
+
.description('Confidence Gate — active output filter based on calibrated confidence');
|
|
4349
|
+
gateCmd.addCommand(new Command('threshold')
|
|
4350
|
+
.description('Show or set the gate threshold')
|
|
4351
|
+
.option('--set <n>', 'Set threshold (0.0-1.0)')
|
|
4352
|
+
.action(async (opts) => {
|
|
4353
|
+
const { getConfidenceGate } = await import('./brain/confidence-gate.js');
|
|
4354
|
+
const g = getConfidenceGate();
|
|
4355
|
+
if (opts.set) {
|
|
4356
|
+
g.setThreshold(parseFloat(opts.set));
|
|
4357
|
+
console.log(chalk.green(` ✓ threshold = ${opts.set}`));
|
|
4358
|
+
}
|
|
4359
|
+
else {
|
|
4360
|
+
console.log(` threshold: ${chalk.cyan(String(g.getThreshold()))}`);
|
|
4361
|
+
}
|
|
4362
|
+
}));
|
|
4363
|
+
gateCmd.addCommand(new Command('stats')
|
|
4364
|
+
.description('Show calibration stats (Brier score + ECE)')
|
|
4365
|
+
.action(async () => {
|
|
4366
|
+
const { getConfidenceGate } = await import('./brain/confidence-gate.js');
|
|
4367
|
+
const s = getConfidenceGate().stats();
|
|
4368
|
+
console.log(JSON.stringify(s, null, 2));
|
|
4369
|
+
}));
|
|
4370
|
+
gateCmd.addCommand(new Command('test')
|
|
4371
|
+
.description('Test the gate on a {text, confidence} pair')
|
|
4372
|
+
.requiredOption('--text <t>', 'Input text')
|
|
4373
|
+
.requiredOption('--confidence <c>', 'Predicted confidence 0..1')
|
|
4374
|
+
.option('--mode <m>', 'block|downgrade|flag', 'downgrade')
|
|
4375
|
+
.action(async (opts) => {
|
|
4376
|
+
const { getConfidenceGate } = await import('./brain/confidence-gate.js');
|
|
4377
|
+
const result = await getConfidenceGate().gate({ text: opts.text, confidence: parseFloat(opts.confidence) }, { mode: opts.mode });
|
|
4378
|
+
console.log(JSON.stringify(result, null, 2));
|
|
4379
|
+
}));
|
|
4380
|
+
// ── 🧠 Embeddings v2 (real ANN index) ────────────────────────────────
|
|
4381
|
+
const embedCmd = new Command('embed')
|
|
4382
|
+
.description('EmbeddingsV2 — real ANN vector index (HNSW-style, sub-100ms recall)');
|
|
4383
|
+
embedCmd.addCommand(new Command('add')
|
|
4384
|
+
.description('Add a document to the index')
|
|
4385
|
+
.requiredOption('--id <id>', 'Document id')
|
|
4386
|
+
.requiredOption('--text <text>', 'Text to embed')
|
|
4387
|
+
.action(async (opts) => {
|
|
4388
|
+
const { getEmbeddingsV2 } = await import('./brain/embeddings-v2.js');
|
|
4389
|
+
await getEmbeddingsV2().addDocument(opts.id, opts.text);
|
|
4390
|
+
console.log(chalk.green(` ✓ added ${opts.id}`));
|
|
4391
|
+
}));
|
|
4392
|
+
embedCmd.addCommand(new Command('search')
|
|
4393
|
+
.description('Semantic search across the index')
|
|
4394
|
+
.requiredOption('--query <q>', 'Query text')
|
|
4395
|
+
.option('--top <n>', 'Top K results', '10')
|
|
4396
|
+
.action(async (opts) => {
|
|
4397
|
+
const { getEmbeddingsV2 } = await import('./brain/embeddings-v2.js');
|
|
4398
|
+
const hits = await getEmbeddingsV2().search(opts.query, parseInt(opts.top, 10));
|
|
4399
|
+
for (const h of hits)
|
|
4400
|
+
console.log(` ${chalk.cyan(h.score.toFixed(3))} ${h.id}`);
|
|
4401
|
+
}));
|
|
4402
|
+
embedCmd.addCommand(new Command('stats')
|
|
4403
|
+
.description('Index statistics')
|
|
4404
|
+
.action(async () => {
|
|
4405
|
+
const { getEmbeddingsV2 } = await import('./brain/embeddings-v2.js');
|
|
4406
|
+
console.log(JSON.stringify(getEmbeddingsV2().stats(), null, 2));
|
|
4407
|
+
}));
|
|
4408
|
+
// ── 🖼️ Multimodal vision ─────────────────────────────────────────────
|
|
4409
|
+
const visionCmd = new Command('vision')
|
|
4410
|
+
.description('Multimodal vision — ingest screenshots, diagrams, photos via Ollama llava');
|
|
4411
|
+
visionCmd.addCommand(new Command('ingest')
|
|
4412
|
+
.description('Ingest one image into the brain')
|
|
4413
|
+
.argument('<path>', 'Image file path')
|
|
4414
|
+
.option('--project <name>', 'Project name', 'default')
|
|
4415
|
+
.option('--tags <csv>', 'Comma-separated tags', '')
|
|
4416
|
+
.option('--prompt <p>', 'Override vision prompt')
|
|
4417
|
+
.action(async (filePath, opts) => {
|
|
4418
|
+
const { getMultimodalVision } = await import('./brain/multimodal-vision.js');
|
|
4419
|
+
const v = await getMultimodalVision().ingestImage(filePath, {
|
|
4420
|
+
project: opts.project,
|
|
4421
|
+
tags: opts.tags ? opts.tags.split(',').map((s) => s.trim()) : [],
|
|
4422
|
+
prompt: opts.prompt,
|
|
4423
|
+
});
|
|
4424
|
+
console.log(chalk.green(` ✓ ingested ${v.id}`));
|
|
4425
|
+
console.log(chalk.dim(` ${v.description.slice(0, 200)}${v.description.length > 200 ? '…' : ''}`));
|
|
4426
|
+
}));
|
|
4427
|
+
visionCmd.addCommand(new Command('search')
|
|
4428
|
+
.description('Semantic search across stored image descriptions')
|
|
4429
|
+
.requiredOption('--query <q>')
|
|
4430
|
+
.option('--top <n>', 'Top K', '5')
|
|
4431
|
+
.option('--project <name>', 'Project name', 'default')
|
|
4432
|
+
.action(async (opts) => {
|
|
4433
|
+
const { getMultimodalVision } = await import('./brain/multimodal-vision.js');
|
|
4434
|
+
const hits = await getMultimodalVision().search(opts.query, parseInt(opts.top, 10), opts.project);
|
|
4435
|
+
for (const h of hits)
|
|
4436
|
+
console.log(` ${chalk.cyan(h.id.padEnd(20))} ${h.description.slice(0, 100)}`);
|
|
4437
|
+
}));
|
|
4438
|
+
visionCmd.addCommand(new Command('recent')
|
|
4439
|
+
.description('Recently ingested images')
|
|
4440
|
+
.option('-n <count>', 'How many', '10')
|
|
4441
|
+
.option('--project <name>', 'Project name', 'default')
|
|
4442
|
+
.action(async (opts) => {
|
|
4443
|
+
const { getMultimodalVision } = await import('./brain/multimodal-vision.js');
|
|
4444
|
+
const list = await getMultimodalVision().recent(parseInt(opts.n, 10), opts.project);
|
|
4445
|
+
for (const v of list)
|
|
4446
|
+
console.log(` ${chalk.dim(new Date(v.capturedAt).toISOString())} ${v.id} ${v.description.slice(0, 80)}`);
|
|
4447
|
+
}));
|
|
4448
|
+
// ── 📤 Markdown export / 📥 import ───────────────────────────────────
|
|
4449
|
+
const exportMdCmd = new Command('export-md')
|
|
4450
|
+
.description('Export the brain to a git-trackable Markdown file')
|
|
4451
|
+
.option('--project <name>', 'Project name', 'default')
|
|
4452
|
+
.option('--out <path>', 'Output path', '.shadow-brain.md')
|
|
4453
|
+
.option('--sections <csv>', 'memories,patterns,decisions,entities,rules')
|
|
4454
|
+
.action(async (opts) => {
|
|
4455
|
+
const { getMarkdownExport } = await import('./brain/markdown-export.js');
|
|
4456
|
+
const sections = opts.sections ? opts.sections.split(',') : undefined;
|
|
4457
|
+
const r = await getMarkdownExport().exportBrain(opts.project, { sections, outPath: opts.out });
|
|
4458
|
+
console.log(chalk.green(` ✓ ${r.path}`));
|
|
4459
|
+
console.log(chalk.dim(` ${(r.sizeBytes / 1024).toFixed(1)}KB · ${Object.entries(r.sectionCounts).map(([k, v]) => `${k}:${v}`).join(' ')}`));
|
|
4460
|
+
});
|
|
4461
|
+
const importMdCmd = new Command('import-md')
|
|
4462
|
+
.description('Import a brain from a previously exported Markdown file')
|
|
4463
|
+
.argument('<path>', 'Path to .shadow-brain.md')
|
|
4464
|
+
.option('--merge <strategy>', 'replace|addNew|overwrite', 'addNew')
|
|
4465
|
+
.option('--dry-run', 'Print diff without writing')
|
|
4466
|
+
.action(async (mdPath, opts) => {
|
|
4467
|
+
const { getMarkdownExport } = await import('./brain/markdown-export.js');
|
|
4468
|
+
if (opts.dryRun) {
|
|
4469
|
+
const d = await getMarkdownExport().diff(mdPath);
|
|
4470
|
+
return console.log(JSON.stringify(d, null, 2));
|
|
4471
|
+
}
|
|
4472
|
+
const r = await getMarkdownExport().importBrain(mdPath, { merge: opts.merge });
|
|
4473
|
+
console.log(chalk.green(` ✓ added: ${r.added} modified: ${r.modified} skipped: ${r.skipped} errors: ${r.errors}`));
|
|
4474
|
+
});
|
|
4475
|
+
// ── 🔭 OTel-lite traces ──────────────────────────────────────────────
|
|
4476
|
+
const tracesCmd = new Command('traces')
|
|
4477
|
+
.description('OTel-lite — JSONL trace viewer for brain operations');
|
|
4478
|
+
tracesCmd.addCommand(new Command('tail')
|
|
4479
|
+
.description('Tail the most recent trace lines')
|
|
4480
|
+
.option('-n <count>', 'Number of lines', '50')
|
|
4481
|
+
.option('--json', 'Raw JSONL')
|
|
4482
|
+
.action(async (opts) => {
|
|
4483
|
+
const { OtelLite } = await import('./brain/otel-lite.js');
|
|
4484
|
+
const lines = await OtelLite.tail(parseInt(opts.n, 10));
|
|
4485
|
+
if (opts.json)
|
|
4486
|
+
return lines.forEach(l => console.log(JSON.stringify(l)));
|
|
4487
|
+
for (const l of lines) {
|
|
4488
|
+
const dur = ((l.end_ns - l.start_ns) / 1000000).toFixed(1);
|
|
4489
|
+
console.log(` ${chalk.dim(new Date(l.start_ns / 1000000).toISOString())} ${chalk.cyan(l.name.padEnd(28))} ${dur}ms`);
|
|
4490
|
+
}
|
|
4491
|
+
}));
|
|
4492
|
+
tracesCmd.addCommand(new Command('today')
|
|
4493
|
+
.description('Print today\'s trace file path')
|
|
4494
|
+
.action(async () => {
|
|
4495
|
+
const { OtelLite } = await import('./brain/otel-lite.js');
|
|
4496
|
+
console.log(OtelLite.todayFilePath());
|
|
4497
|
+
}));
|
|
4498
|
+
tracesCmd.addCommand(new Command('cleanup')
|
|
4499
|
+
.description('Drop trace files older than 14 days')
|
|
4500
|
+
.action(async () => {
|
|
4501
|
+
const { OtelLite } = await import('./brain/otel-lite.js');
|
|
4502
|
+
OtelLite.cleanup();
|
|
4503
|
+
console.log(chalk.green(' ✓ cleanup done'));
|
|
4504
|
+
}));
|
|
4505
|
+
// ── 🎉 Demo — 30-second hello-world ──────────────────────────────────
|
|
4506
|
+
const demoCmd = new Command('demo')
|
|
4507
|
+
.description('30-second Hello Brain — ingest sample data, run sample queries, open dashboard')
|
|
4508
|
+
.option('--no-open', 'Skip launching the dashboard')
|
|
4509
|
+
.option('--port <port>', 'Dashboard port', '7341')
|
|
4510
|
+
.action(async (opts) => {
|
|
4511
|
+
console.log(chalk.magenta.bold(`\n 🧠 SHADOW BRAIN v${VERSION} — 30-Second Demo\n`));
|
|
4512
|
+
// 1. seed a few sample memories
|
|
4513
|
+
const { getEmbeddingsV2 } = await import('./brain/embeddings-v2.js');
|
|
4514
|
+
const ev2 = getEmbeddingsV2();
|
|
4515
|
+
const samples = [
|
|
4516
|
+
['mem-1', 'Always parameterize SQL queries to prevent injection.'],
|
|
4517
|
+
['mem-2', 'React useEffect cleanup functions must cancel pending async work.'],
|
|
4518
|
+
['mem-3', 'When a test flakes, look for time-of-day dependencies first.'],
|
|
4519
|
+
['mem-4', 'Postgres connection pooling: max 100 connections in production.'],
|
|
4520
|
+
['mem-5', 'In dual-mode work, the Opus brain plans and Codex implements.'],
|
|
4521
|
+
];
|
|
4522
|
+
console.log(chalk.cyan(' ▶ seeding sample memories'));
|
|
4523
|
+
for (const [id, text] of samples)
|
|
4524
|
+
await ev2.addDocument(id, text);
|
|
4525
|
+
// 2. run sample searches
|
|
4526
|
+
console.log(chalk.cyan(' ▶ semantic search: "how do I prevent SQL injection?"'));
|
|
4527
|
+
const hits = await ev2.search('how do I prevent SQL injection', 3);
|
|
4528
|
+
for (const h of hits)
|
|
4529
|
+
console.log(` ${chalk.cyan(h.score.toFixed(3))} ${h.id}`);
|
|
4530
|
+
// 3. generate Brain DNA card
|
|
4531
|
+
console.log(chalk.cyan('\n ▶ generating Brain DNA card'));
|
|
4532
|
+
const { getBrainDna } = await import('./brain/brain-dna.js');
|
|
4533
|
+
const dna = getBrainDna().generate('demo', { style: 'card' });
|
|
4534
|
+
const dnaPath = path.join(os.tmpdir(), 'shadow-brain-demo-dna.svg');
|
|
4535
|
+
fs.writeFileSync(dnaPath, dna.svg);
|
|
4536
|
+
console.log(` ${chalk.dim('archetype:')} ${dna.stats.archetype}`);
|
|
4537
|
+
console.log(` ${chalk.green('✓')} card written: ${dnaPath}`);
|
|
4538
|
+
// 4. record some replay events so timeline isn't empty
|
|
4539
|
+
const { getBrainReplay } = await import('./brain/brain-replay.js');
|
|
4540
|
+
for (const [id, text] of samples) {
|
|
4541
|
+
getBrainReplay().record({ type: 'memory.add', payload: { id, text }, project: 'demo' });
|
|
4542
|
+
}
|
|
4543
|
+
const replaySvg = getBrainReplay().export('demo', 'svg');
|
|
4544
|
+
const replayPath = path.join(os.tmpdir(), 'shadow-brain-demo-replay.svg');
|
|
4545
|
+
fs.writeFileSync(replayPath, typeof replaySvg === 'string' ? replaySvg : replaySvg);
|
|
4546
|
+
console.log(` ${chalk.green('✓')} replay timeline written: ${replayPath}`);
|
|
4547
|
+
// 5. optionally launch dashboard
|
|
4548
|
+
if (opts.open !== false) {
|
|
4549
|
+
console.log(chalk.cyan('\n ▶ launching dashboard'));
|
|
4550
|
+
const { Orchestrator } = await import('./brain/orchestrator.js');
|
|
4551
|
+
const { DashboardServer } = await import('./dashboard/server.js');
|
|
4552
|
+
const orchestrator = new Orchestrator(mergeConfig({}));
|
|
4553
|
+
const dashboard = new DashboardServer(orchestrator, { port: parseInt(opts.port, 10), openBrowser: true });
|
|
4554
|
+
const url = await dashboard.start();
|
|
4555
|
+
console.log(chalk.green(` ✓ ${url}`));
|
|
4556
|
+
console.log(chalk.dim('\n Press Ctrl+C to stop.'));
|
|
4557
|
+
}
|
|
4558
|
+
else {
|
|
4559
|
+
console.log(chalk.dim('\n Done. Run with --no-open=false to launch the dashboard.'));
|
|
4560
|
+
}
|
|
4561
|
+
});
|
|
4562
|
+
program.addCommand(replayCmd);
|
|
4563
|
+
program.addCommand(brainDnaCmd);
|
|
4564
|
+
program.addCommand(hiveVoiceCmd);
|
|
4565
|
+
program.addCommand(capsuleCmd);
|
|
4566
|
+
program.addCommand(brainDiffCmd);
|
|
4567
|
+
program.addCommand(constitutionCmd);
|
|
4568
|
+
program.addCommand(gateCmd);
|
|
4569
|
+
program.addCommand(embedCmd);
|
|
4570
|
+
program.addCommand(visionCmd);
|
|
4571
|
+
program.addCommand(exportMdCmd);
|
|
4572
|
+
program.addCommand(importMdCmd);
|
|
4573
|
+
program.addCommand(tracesCmd);
|
|
4574
|
+
program.addCommand(demoCmd);
|
|
4575
|
+
// ════════════════════════════════════════════════════════════════════
|
|
4576
|
+
// v6.0.2 Wave 2 — 14 advanced viral features
|
|
4577
|
+
// ════════════════════════════════════════════════════════════════════
|
|
4578
|
+
// ── 🎵 Brain Cinema ──────────────────────────────────────────────────
|
|
4579
|
+
const cinemaCmd = new Command('cinema')
|
|
4580
|
+
.description('Brain Cinema — auto 60-second SVG-animated video of brain growth')
|
|
4581
|
+
.option('--project <name>', 'Project name', 'default')
|
|
4582
|
+
.option('--style <s>', 'minimal|rich|arcade', 'rich')
|
|
4583
|
+
.option('--duration <s>', 'Duration in seconds', '60')
|
|
4584
|
+
.option('--out <path>', 'Output SVG path')
|
|
4585
|
+
.action(async (opts) => {
|
|
4586
|
+
const { getBrainCinema } = await import('./brain/brain-cinema.js');
|
|
4587
|
+
const { svg, manifest } = await getBrainCinema().generate(opts.project, {
|
|
4588
|
+
style: opts.style,
|
|
4589
|
+
durationS: parseInt(opts.duration, 10),
|
|
4590
|
+
});
|
|
4591
|
+
if (opts.out) {
|
|
4592
|
+
fs.writeFileSync(opts.out, svg);
|
|
4593
|
+
console.log(chalk.green(` ✓ ${opts.out} (${manifest.eventsRendered} events, ${manifest.durationMs}ms)`));
|
|
4594
|
+
}
|
|
4595
|
+
else
|
|
4596
|
+
process.stdout.write(svg);
|
|
4597
|
+
});
|
|
4598
|
+
// ── 🎼 Brain Sonification ────────────────────────────────────────────
|
|
4599
|
+
const sonifyCmd = new Command('sonify')
|
|
4600
|
+
.description('Brain Sonification — your codebase as music (WAV)')
|
|
4601
|
+
.option('--project <name>', 'Project name', 'default')
|
|
4602
|
+
.option('--mode <m>', 'major|minor|phrygian', 'phrygian')
|
|
4603
|
+
.option('--duration <s>', 'Duration in seconds', '60')
|
|
4604
|
+
.option('--tempo <bpm>', 'Tempo BPM', '110')
|
|
4605
|
+
.option('--out <path>', 'Output WAV path (required)')
|
|
4606
|
+
.action(async (opts) => {
|
|
4607
|
+
const { getBrainSonification } = await import('./brain/brain-sonification.js');
|
|
4608
|
+
const { wav, manifest } = await getBrainSonification().generate(opts.project, {
|
|
4609
|
+
mode: opts.mode,
|
|
4610
|
+
durationS: parseInt(opts.duration, 10),
|
|
4611
|
+
tempo: parseInt(opts.tempo, 10),
|
|
4612
|
+
});
|
|
4613
|
+
const out = opts.out || `brain-sonification-${opts.project}-${Date.now()}.wav`;
|
|
4614
|
+
fs.writeFileSync(out, wav);
|
|
4615
|
+
console.log(chalk.green(` ✓ ${out} (${manifest.eventsRendered} events, ${manifest.durationMs}ms, ${manifest.mode})`));
|
|
4616
|
+
});
|
|
4617
|
+
// ── 🏆 Brain Trophies ────────────────────────────────────────────────
|
|
4618
|
+
const trophiesCmd = new Command('trophies')
|
|
4619
|
+
.description('Brain Trophies — 25 unlockable achievements with shareable cards');
|
|
4620
|
+
trophiesCmd.addCommand(new Command('list')
|
|
4621
|
+
.description('List achievements + progress')
|
|
4622
|
+
.option('--project <name>', 'Project name', 'default')
|
|
4623
|
+
.action(async (opts) => {
|
|
4624
|
+
const { getBrainTrophies } = await import('./brain/brain-trophies.js');
|
|
4625
|
+
const r = await getBrainTrophies().checkProgress(opts.project);
|
|
4626
|
+
console.log(chalk.magenta.bold(`\n TROPHIES — ${opts.project}`));
|
|
4627
|
+
console.log(chalk.green(` Unlocked: ${r.unlocked.length}/25`));
|
|
4628
|
+
for (const a of r.unlocked)
|
|
4629
|
+
console.log(` ${a.icon} ${chalk.cyan(a.name)} ${chalk.dim(a.rarity)}`);
|
|
4630
|
+
console.log(chalk.dim(`\n In progress: ${r.inProgress.length}`));
|
|
4631
|
+
for (const p of r.inProgress.slice(0, 5))
|
|
4632
|
+
console.log(` ${chalk.dim((p.progressPct * 100).toFixed(0) + '%')} ${p.achievement.name}`);
|
|
4633
|
+
}));
|
|
4634
|
+
trophiesCmd.addCommand(new Command('card')
|
|
4635
|
+
.description('Generate a share card for an unlocked trophy')
|
|
4636
|
+
.requiredOption('--id <achievementId>', 'Achievement ID (e.g., first-spark)')
|
|
4637
|
+
.option('--project <name>', 'Project name', 'default')
|
|
4638
|
+
.option('--style <s>', 'card|badge|trophy', 'card')
|
|
4639
|
+
.option('--out <path>', 'Output SVG path')
|
|
4640
|
+
.action(async (opts) => {
|
|
4641
|
+
const { getBrainTrophies } = await import('./brain/brain-trophies.js');
|
|
4642
|
+
const { svg } = await getBrainTrophies().generateCard(opts.project, opts.id, { style: opts.style });
|
|
4643
|
+
if (opts.out) {
|
|
4644
|
+
fs.writeFileSync(opts.out, svg);
|
|
4645
|
+
console.log(chalk.green(` ✓ ${opts.out}`));
|
|
4646
|
+
}
|
|
4647
|
+
else
|
|
4648
|
+
process.stdout.write(svg);
|
|
4649
|
+
}));
|
|
4650
|
+
trophiesCmd.addCommand(new Command('wall')
|
|
4651
|
+
.description('Wall-of-trophies SVG (1200×800)')
|
|
4652
|
+
.option('--project <name>', 'Project name', 'default')
|
|
4653
|
+
.option('--out <path>', 'Output SVG path')
|
|
4654
|
+
.action(async (opts) => {
|
|
4655
|
+
const { getBrainTrophies } = await import('./brain/brain-trophies.js');
|
|
4656
|
+
const { svg } = await getBrainTrophies().wallSvg(opts.project);
|
|
4657
|
+
if (opts.out) {
|
|
4658
|
+
fs.writeFileSync(opts.out, svg);
|
|
4659
|
+
console.log(chalk.green(` ✓ ${opts.out}`));
|
|
4660
|
+
}
|
|
4661
|
+
else
|
|
4662
|
+
process.stdout.write(svg);
|
|
4663
|
+
}));
|
|
4664
|
+
// ── 🎁 Brain Holiday Card ────────────────────────────────────────────
|
|
4665
|
+
const holidayCmd = new Command('holiday')
|
|
4666
|
+
.description('Brain Holiday Card — Spotify-Wrapped-style year-in-review')
|
|
4667
|
+
.option('--project <name>', 'Project name', 'default')
|
|
4668
|
+
.option('--year <yyyy>', 'Year', String(new Date().getFullYear()))
|
|
4669
|
+
.option('--style <s>', 'wrapped|classic|minimalist', 'wrapped')
|
|
4670
|
+
.option('--out <path>', 'Output SVG path')
|
|
4671
|
+
.action(async (opts) => {
|
|
4672
|
+
const { getBrainHolidayCard } = await import('./brain/brain-holiday-card.js');
|
|
4673
|
+
const { svg } = await getBrainHolidayCard().generate(opts.project, {
|
|
4674
|
+
year: parseInt(opts.year, 10),
|
|
4675
|
+
style: opts.style,
|
|
4676
|
+
});
|
|
4677
|
+
if (opts.out) {
|
|
4678
|
+
fs.writeFileSync(opts.out, svg);
|
|
4679
|
+
console.log(chalk.green(` ✓ ${opts.out}`));
|
|
4680
|
+
}
|
|
4681
|
+
else
|
|
4682
|
+
process.stdout.write(svg);
|
|
4683
|
+
});
|
|
4684
|
+
// ── 🧭 Brain Coach ───────────────────────────────────────────────────
|
|
4685
|
+
const coachCmd = new Command('coach')
|
|
4686
|
+
.description('Brain Coach — proactive idle suggestions');
|
|
4687
|
+
coachCmd.addCommand(new Command('suggestions')
|
|
4688
|
+
.description('Show current suggestions')
|
|
4689
|
+
.option('--project <name>', 'Project name', 'default')
|
|
4690
|
+
.option('--top <n>', 'Top N', '5')
|
|
4691
|
+
.action(async (opts) => {
|
|
4692
|
+
const { getBrainCoach } = await import('./brain/brain-coach.js');
|
|
4693
|
+
const list = await getBrainCoach().suggestions(opts.project, { topN: parseInt(opts.top, 10) });
|
|
4694
|
+
for (const s of list) {
|
|
4695
|
+
console.log(` ${s.emoji} ${chalk.cyan(s.title)}`);
|
|
4696
|
+
console.log(` ${chalk.dim(s.body)}`);
|
|
4697
|
+
}
|
|
4698
|
+
if (!list.length)
|
|
4699
|
+
console.log(chalk.dim(' No suggestions right now.'));
|
|
4700
|
+
}));
|
|
4701
|
+
coachCmd.addCommand(new Command('idle')
|
|
4702
|
+
.description('Run idle-check (call this when user has been idle)')
|
|
4703
|
+
.option('--project <name>', 'Project name', 'default')
|
|
4704
|
+
.option('--since <ms>', 'Idle for this many ms', '300000')
|
|
4705
|
+
.action(async (opts) => {
|
|
4706
|
+
const { getBrainCoach } = await import('./brain/brain-coach.js');
|
|
4707
|
+
const list = await getBrainCoach().idleCheck(opts.project, parseInt(opts.since, 10));
|
|
4708
|
+
for (const s of list)
|
|
4709
|
+
console.log(` ${s.emoji} ${s.title}`);
|
|
4710
|
+
}));
|
|
4711
|
+
coachCmd.addCommand(new Command('dismiss')
|
|
4712
|
+
.description('Dismiss a suggestion by id')
|
|
4713
|
+
.argument('<id>')
|
|
4714
|
+
.action(async (id) => {
|
|
4715
|
+
const { getBrainCoach } = await import('./brain/brain-coach.js');
|
|
4716
|
+
getBrainCoach().dismiss(id);
|
|
4717
|
+
console.log(chalk.green(' ✓ dismissed'));
|
|
4718
|
+
}));
|
|
4719
|
+
coachCmd.addCommand(new Command('pin')
|
|
4720
|
+
.description('Pin a suggestion')
|
|
4721
|
+
.argument('<id>')
|
|
4722
|
+
.action(async (id) => {
|
|
4723
|
+
const { getBrainCoach } = await import('./brain/brain-coach.js');
|
|
4724
|
+
getBrainCoach().pin(id);
|
|
4725
|
+
console.log(chalk.green(' ✓ pinned'));
|
|
4726
|
+
}));
|
|
4727
|
+
// ── 🗺️ Brain Quest ──────────────────────────────────────────────────
|
|
4728
|
+
const questCmd = new Command('quest')
|
|
4729
|
+
.description('Brain Quest — gamified onboarding adventures');
|
|
4730
|
+
questCmd.addCommand(new Command('list')
|
|
4731
|
+
.description('List available quests')
|
|
4732
|
+
.action(async () => {
|
|
4733
|
+
const { getBrainQuest } = await import('./brain/brain-quest.js');
|
|
4734
|
+
for (const q of getBrainQuest().availableQuests()) {
|
|
4735
|
+
console.log(` ${chalk.cyan(q.id.padEnd(20))} ${q.emoji} ${q.title}`);
|
|
4736
|
+
console.log(` ${chalk.dim(q.subtitle)} ${chalk.dim(`~${q.estimatedMinutes}m, ${q.steps.length} steps`)}`);
|
|
4737
|
+
}
|
|
4738
|
+
}));
|
|
4739
|
+
questCmd.addCommand(new Command('start')
|
|
4740
|
+
.description('Start a quest')
|
|
4741
|
+
.argument('<questId>')
|
|
4742
|
+
.option('--project <name>', 'Project name', 'default')
|
|
4743
|
+
.action(async (questId, opts) => {
|
|
4744
|
+
const { getBrainQuest } = await import('./brain/brain-quest.js');
|
|
4745
|
+
const state = await getBrainQuest().start(questId, opts.project);
|
|
4746
|
+
console.log(chalk.magenta.bold(`\n Quest started: ${questId}`));
|
|
4747
|
+
console.log(chalk.dim(` Step: ${state.currentStepId} (${state.completedSteps.length} steps completed)`));
|
|
4748
|
+
}));
|
|
4749
|
+
questCmd.addCommand(new Command('step')
|
|
4750
|
+
.description('Advance the current quest')
|
|
4751
|
+
.option('--project <name>', 'Project name', 'default')
|
|
4752
|
+
.option('--choice <c>', 'Branch choice if step has options')
|
|
4753
|
+
.action(async (opts) => {
|
|
4754
|
+
const { getBrainQuest } = await import('./brain/brain-quest.js');
|
|
4755
|
+
const r = await getBrainQuest().step(opts.project, opts.choice);
|
|
4756
|
+
console.log('\n' + r.narrative + '\n');
|
|
4757
|
+
if (r.options)
|
|
4758
|
+
for (const opt of r.options)
|
|
4759
|
+
console.log(` [${chalk.cyan(opt)}]`);
|
|
4760
|
+
if (r.complete)
|
|
4761
|
+
console.log(chalk.green(`\n ✓ Quest complete! ${r.reward?.message || ''}`));
|
|
4762
|
+
}));
|
|
4763
|
+
questCmd.addCommand(new Command('current')
|
|
4764
|
+
.description('Show the active quest state')
|
|
4765
|
+
.option('--project <name>', 'Project name', 'default')
|
|
4766
|
+
.action(async (opts) => {
|
|
4767
|
+
const { getBrainQuest } = await import('./brain/brain-quest.js');
|
|
4768
|
+
const s = getBrainQuest().current(opts.project);
|
|
4769
|
+
console.log(s ? JSON.stringify(s, null, 2) : chalk.dim(' No active quest. Run `quest list` to pick one.'));
|
|
4770
|
+
}));
|
|
4771
|
+
// ── 📓 Brain Notebook ────────────────────────────────────────────────
|
|
4772
|
+
const notebookCmd = new Command('notebook')
|
|
4773
|
+
.description('Brain Notebook — Jupyter-style interactive brain explorer');
|
|
4774
|
+
notebookCmd.addCommand(new Command('new')
|
|
4775
|
+
.description('Create a starter notebook')
|
|
4776
|
+
.option('--project <name>', 'Project name', 'default')
|
|
4777
|
+
.option('--title <t>', 'Notebook title', 'My Investigation')
|
|
4778
|
+
.action(async (opts) => {
|
|
4779
|
+
const { getBrainNotebook } = await import('./brain/brain-notebook.js');
|
|
4780
|
+
const r = await getBrainNotebook().createNotebook(opts.project, opts.title);
|
|
4781
|
+
console.log(chalk.green(` ✓ ${r.path}`));
|
|
4782
|
+
}));
|
|
4783
|
+
notebookCmd.addCommand(new Command('run')
|
|
4784
|
+
.description('Run all query cells, save inline results')
|
|
4785
|
+
.argument('<path>', 'Path to notebook .md')
|
|
4786
|
+
.action(async (notebookPath) => {
|
|
4787
|
+
const { getBrainNotebook } = await import('./brain/brain-notebook.js');
|
|
4788
|
+
const nb = await getBrainNotebook().parse(notebookPath);
|
|
4789
|
+
const r = await getBrainNotebook().runAll(nb);
|
|
4790
|
+
await getBrainNotebook().save(nb, notebookPath);
|
|
4791
|
+
const ran = r.cells.filter(c => c.result || c.error).length;
|
|
4792
|
+
console.log(chalk.green(` ✓ ran ${ran}/${r.cells.length} cells in ${r.totalDurationMs}ms`));
|
|
4793
|
+
}));
|
|
4794
|
+
// ── ⚡ Brain Reflex ──────────────────────────────────────────────────
|
|
4795
|
+
const reflexCmd = new Command('reflex')
|
|
4796
|
+
.description('Brain Reflex — local-model inline next-line completion');
|
|
4797
|
+
reflexCmd.addCommand(new Command('complete')
|
|
4798
|
+
.description('Complete a code snippet')
|
|
4799
|
+
.requiredOption('--prefix <p>', 'Prefix code to complete')
|
|
4800
|
+
.option('--language <l>', 'Language hint', 'typescript')
|
|
4801
|
+
.option('--project <name>', 'Project name', 'default')
|
|
4802
|
+
.option('--max-tokens <n>', 'Max tokens', '128')
|
|
4803
|
+
.action(async (opts) => {
|
|
4804
|
+
const { getBrainReflex } = await import('./brain/brain-reflex.js');
|
|
4805
|
+
const r = await getBrainReflex().complete({ prefix: opts.prefix, language: opts.language, project: opts.project }, { maxTokens: parseInt(opts.maxTokens, 10) });
|
|
4806
|
+
console.log(chalk.dim(` source: ${r.source} latency: ${r.latencyMs}ms citations: ${r.citations.join(', ')}\n`));
|
|
4807
|
+
console.log(r.completion);
|
|
4808
|
+
}));
|
|
4809
|
+
reflexCmd.addCommand(new Command('precache')
|
|
4810
|
+
.description('Warm brain memories before a session')
|
|
4811
|
+
.option('--project <name>', 'Project name', 'default')
|
|
4812
|
+
.option('--files <csv>', 'Comma-separated file paths', '')
|
|
4813
|
+
.action(async (opts) => {
|
|
4814
|
+
const { getBrainReflex } = await import('./brain/brain-reflex.js');
|
|
4815
|
+
const files = opts.files.split(',').map((s) => s.trim()).filter((x) => x);
|
|
4816
|
+
const r = await getBrainReflex().precache(opts.project, files);
|
|
4817
|
+
console.log(chalk.green(` ✓ cached ${r.cached} memories in ${r.durationMs}ms`));
|
|
4818
|
+
}));
|
|
4819
|
+
// ── 🔥 Brain Roast ───────────────────────────────────────────────────
|
|
4820
|
+
const roastCmd = new Command('roast')
|
|
4821
|
+
.description('Brain Roast — comedy code review (6 personas)')
|
|
4822
|
+
.option('--project <name>', 'Project name', 'default')
|
|
4823
|
+
.option('--persona <p>', 'gordon-ramsay|simon-cowell|mom|comedian|critic|philosopher', 'gordon-ramsay')
|
|
4824
|
+
.option('--intensity <i>', 'gentle|medium|savage', 'medium')
|
|
4825
|
+
.option('--svg <path>', 'Save roast card SVG')
|
|
4826
|
+
.action(async (opts) => {
|
|
4827
|
+
const { getBrainRoast } = await import('./brain/brain-roast.js');
|
|
4828
|
+
const r = await getBrainRoast().roast(opts.project, { persona: opts.persona, intensity: opts.intensity });
|
|
4829
|
+
console.log(chalk.magenta.bold(`\n ROAST · ${r.persona} · ${r.intensity} · grade ${r.grade}\n`));
|
|
4830
|
+
for (const line of r.lines)
|
|
4831
|
+
console.log(' ' + line);
|
|
4832
|
+
if (opts.svg) {
|
|
4833
|
+
const card = await getBrainRoast().roastCard(r);
|
|
4834
|
+
fs.writeFileSync(opts.svg, card.svg);
|
|
4835
|
+
console.log(chalk.green(`\n ✓ card written to ${opts.svg}`));
|
|
4836
|
+
}
|
|
4837
|
+
});
|
|
4838
|
+
// ── 🔮 Brain Tarot ───────────────────────────────────────────────────
|
|
4839
|
+
const tarotCmd = new Command('tarot')
|
|
4840
|
+
.description('Brain Tarot — 78-card divination from your codebase');
|
|
4841
|
+
tarotCmd.addCommand(new Command('draw')
|
|
4842
|
+
.description('Draw a reading')
|
|
4843
|
+
.option('--project <name>', 'Project name', 'default')
|
|
4844
|
+
.option('--spread <s>', 'one-card|three-card|celtic-cross', 'three-card')
|
|
4845
|
+
.option('--question <q>', 'Optional question')
|
|
4846
|
+
.option('--svg <path>', 'Save reading SVG')
|
|
4847
|
+
.action(async (opts) => {
|
|
4848
|
+
const { getBrainTarot } = await import('./brain/brain-tarot.js');
|
|
4849
|
+
const r = await getBrainTarot().draw(opts.project, { spread: opts.spread, question: opts.question });
|
|
4850
|
+
console.log(chalk.magenta.bold(`\n TAROT · ${r.spread}\n`));
|
|
4851
|
+
for (const c of r.cards) {
|
|
4852
|
+
console.log(` ${chalk.cyan(c.name.padEnd(28))} (${c.orientation}) ${chalk.dim(c.position)}`);
|
|
4853
|
+
console.log(` ${chalk.dim(c.meaning)}`);
|
|
4854
|
+
}
|
|
4855
|
+
console.log('\n ' + r.synthesis);
|
|
4856
|
+
if (r.advice)
|
|
4857
|
+
console.log('\n ' + chalk.yellow('Advice: ') + r.advice);
|
|
4858
|
+
if (opts.svg) {
|
|
4859
|
+
fs.writeFileSync(opts.svg, r.svg);
|
|
4860
|
+
console.log(chalk.green(`\n ✓ reading written to ${opts.svg}`));
|
|
4861
|
+
}
|
|
4862
|
+
}));
|
|
4863
|
+
// ── 🎨 Brain ASCII ───────────────────────────────────────────────────
|
|
4864
|
+
const asciiCmd = new Command('ascii')
|
|
4865
|
+
.description('Brain ASCII — terminal-art brain visualizations');
|
|
4866
|
+
asciiCmd.addCommand(new Command('render')
|
|
4867
|
+
.description('Render brain as ASCII art')
|
|
4868
|
+
.option('--project <name>', 'Project name', 'default')
|
|
4869
|
+
.option('--style <s>', 'galaxy|tree|matrix|pixel|banner|sparkline', 'galaxy')
|
|
4870
|
+
.option('--width <w>', 'Width', '80')
|
|
4871
|
+
.option('--height <h>', 'Height', '20')
|
|
4872
|
+
.action(async (opts) => {
|
|
4873
|
+
const { getBrainAscii } = await import('./brain/brain-ascii.js');
|
|
4874
|
+
const out = await getBrainAscii().render(opts.project, {
|
|
4875
|
+
style: opts.style,
|
|
4876
|
+
width: parseInt(opts.width, 10),
|
|
4877
|
+
height: parseInt(opts.height, 10),
|
|
4878
|
+
});
|
|
4879
|
+
console.log(out);
|
|
4880
|
+
}));
|
|
4881
|
+
asciiCmd.addCommand(new Command('sparkline')
|
|
4882
|
+
.description('Activity sparkline over the last N days')
|
|
4883
|
+
.option('--project <name>', 'Project name', 'default')
|
|
4884
|
+
.option('--days <n>', 'Days', '30')
|
|
4885
|
+
.action(async (opts) => {
|
|
4886
|
+
const { getBrainAscii } = await import('./brain/brain-ascii.js');
|
|
4887
|
+
const s = await getBrainAscii().dailySparkline(opts.project, parseInt(opts.days, 10));
|
|
4888
|
+
console.log(s);
|
|
4889
|
+
}));
|
|
4890
|
+
asciiCmd.addCommand(new Command('mascot')
|
|
4891
|
+
.description('ASCII mascot for an archetype')
|
|
4892
|
+
.option('--archetype <a>', 'Archetype name')
|
|
4893
|
+
.action(async (opts) => {
|
|
4894
|
+
const { getBrainAscii } = await import('./brain/brain-ascii.js');
|
|
4895
|
+
console.log(getBrainAscii().mascot(opts.archetype));
|
|
4896
|
+
}));
|
|
4897
|
+
// ── 😂 Brain Memes ───────────────────────────────────────────────────
|
|
4898
|
+
const memesCmd = new Command('memes')
|
|
4899
|
+
.description('Brain Memes — auto-generated dev memes from brain patterns');
|
|
4900
|
+
memesCmd.addCommand(new Command('generate')
|
|
4901
|
+
.description('Generate one or more memes')
|
|
4902
|
+
.option('--project <name>', 'Project name', 'default')
|
|
4903
|
+
.option('--template <t>', 'Specific template (else random)')
|
|
4904
|
+
.option('--count <n>', 'How many', '5')
|
|
4905
|
+
.option('--save', 'Save SVGs to disk')
|
|
4906
|
+
.action(async (opts) => {
|
|
4907
|
+
const { getBrainMemes } = await import('./brain/brain-memes.js');
|
|
4908
|
+
const results = await getBrainMemes().generate(opts.project, {
|
|
4909
|
+
template: opts.template,
|
|
4910
|
+
count: parseInt(opts.count, 10),
|
|
4911
|
+
save: opts.save,
|
|
4912
|
+
});
|
|
4913
|
+
for (const m of results) {
|
|
4914
|
+
console.log(` ${chalk.cyan(m.template.padEnd(28))}`);
|
|
4915
|
+
console.log(` TOP: ${m.topText}`);
|
|
4916
|
+
console.log(` BOT: ${m.bottomText}`);
|
|
4917
|
+
if (m.sharePath)
|
|
4918
|
+
console.log(` ${chalk.dim(m.sharePath)}`);
|
|
4919
|
+
}
|
|
4920
|
+
}));
|
|
4921
|
+
memesCmd.addCommand(new Command('templates')
|
|
4922
|
+
.description('List meme templates')
|
|
4923
|
+
.action(async () => {
|
|
4924
|
+
const { getBrainMemes } = await import('./brain/brain-memes.js');
|
|
4925
|
+
for (const t of getBrainMemes().listTemplates())
|
|
4926
|
+
console.log(` • ${t}`);
|
|
4927
|
+
}));
|
|
4928
|
+
// ── 🌌 Brain 3D ──────────────────────────────────────────────────────
|
|
4929
|
+
const brain3dCmd = new Command('brain-3d')
|
|
4930
|
+
.description('Brain 3D — rotatable 3D graph viewer (Three.js)');
|
|
4931
|
+
brain3dCmd.addCommand(new Command('export')
|
|
4932
|
+
.description('Export scene as JSON / glTF / HTML viewer')
|
|
4933
|
+
.option('--project <name>', 'Project name', 'default')
|
|
4934
|
+
.option('--layout <l>', 'force-directed|sphere|helix|galaxy', 'force-directed')
|
|
4935
|
+
.option('--format <f>', 'json|gltf|html', 'html')
|
|
4936
|
+
.option('--out <path>', 'Output path')
|
|
4937
|
+
.action(async (opts) => {
|
|
4938
|
+
const { getBrain3d } = await import('./brain/brain-3d.js');
|
|
4939
|
+
const scene = await getBrain3d().exportScene(opts.project, { layout: opts.layout });
|
|
4940
|
+
let payload;
|
|
4941
|
+
if (opts.format === 'gltf')
|
|
4942
|
+
payload = getBrain3d().glTfExport(scene);
|
|
4943
|
+
else if (opts.format === 'html')
|
|
4944
|
+
payload = getBrain3d().htmlViewer(scene);
|
|
4945
|
+
else
|
|
4946
|
+
payload = JSON.stringify(scene, null, 2);
|
|
4947
|
+
if (opts.out) {
|
|
4948
|
+
fs.writeFileSync(opts.out, payload);
|
|
4949
|
+
console.log(chalk.green(` ✓ ${opts.out} (${scene.nodes.length} nodes, ${scene.edges.length} edges)`));
|
|
4950
|
+
}
|
|
4951
|
+
else
|
|
4952
|
+
process.stdout.write(payload);
|
|
4953
|
+
}));
|
|
4954
|
+
// ── 💞 Brain Doppelganger ────────────────────────────────────────────
|
|
4955
|
+
const doppelgangerCmd = new Command('doppelganger')
|
|
4956
|
+
.description('Brain Doppelganger — find your codebase\'s twin');
|
|
4957
|
+
doppelgangerCmd.addCommand(new Command('find')
|
|
4958
|
+
.description('Find similar projects')
|
|
4959
|
+
.option('--project <name>', 'Project name', 'default')
|
|
4960
|
+
.option('--pool <p>', 'local|exchange|all', 'local')
|
|
4961
|
+
.option('--top <n>', 'Top K', '5')
|
|
4962
|
+
.action(async (opts) => {
|
|
4963
|
+
const { getBrainDoppelganger } = await import('./brain/brain-doppelganger.js');
|
|
4964
|
+
const matches = await getBrainDoppelganger().findMatches(opts.project, {
|
|
4965
|
+
pool: opts.pool,
|
|
4966
|
+
topK: parseInt(opts.top, 10),
|
|
4967
|
+
});
|
|
4968
|
+
for (const m of matches) {
|
|
4969
|
+
console.log(` ${chalk.cyan((m.similarity * 100).toFixed(0) + '%').padEnd(14)} ${m.otherProject}`);
|
|
4970
|
+
console.log(` ${chalk.dim(m.blurb)}`);
|
|
4971
|
+
}
|
|
4972
|
+
if (!matches.length)
|
|
4973
|
+
console.log(chalk.dim(' No matches found.'));
|
|
4974
|
+
}));
|
|
4975
|
+
doppelgangerCmd.addCommand(new Command('card')
|
|
4976
|
+
.description('Compatibility share card for two projects')
|
|
4977
|
+
.requiredOption('--mine <p>', 'Your project name')
|
|
4978
|
+
.requiredOption('--other <p>', 'Other project name')
|
|
4979
|
+
.option('--out <path>', 'Output SVG path')
|
|
4980
|
+
.action(async (opts) => {
|
|
4981
|
+
const { getBrainDoppelganger } = await import('./brain/brain-doppelganger.js');
|
|
4982
|
+
const { svg } = await getBrainDoppelganger().compatibilityCard(opts.mine, opts.other);
|
|
4983
|
+
if (opts.out) {
|
|
4984
|
+
fs.writeFileSync(opts.out, svg);
|
|
4985
|
+
console.log(chalk.green(` ✓ ${opts.out}`));
|
|
4986
|
+
}
|
|
4987
|
+
else
|
|
4988
|
+
process.stdout.write(svg);
|
|
4989
|
+
}));
|
|
4990
|
+
program.addCommand(cinemaCmd);
|
|
4991
|
+
program.addCommand(sonifyCmd);
|
|
4992
|
+
program.addCommand(trophiesCmd);
|
|
4993
|
+
program.addCommand(holidayCmd);
|
|
4994
|
+
program.addCommand(coachCmd);
|
|
4995
|
+
program.addCommand(questCmd);
|
|
4996
|
+
program.addCommand(notebookCmd);
|
|
4997
|
+
program.addCommand(reflexCmd);
|
|
4998
|
+
program.addCommand(roastCmd);
|
|
4999
|
+
program.addCommand(tarotCmd);
|
|
5000
|
+
program.addCommand(asciiCmd);
|
|
5001
|
+
program.addCommand(memesCmd);
|
|
5002
|
+
program.addCommand(brain3dCmd);
|
|
5003
|
+
program.addCommand(doppelgangerCmd);
|
|
3916
5004
|
program.parse();
|
|
3917
5005
|
//# sourceMappingURL=cli.js.map
|