@theihtisham/agent-shadow-brain 6.0.0 → 6.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +107 -7
- 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-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/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/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/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/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/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/cli.js +881 -2
- package/dist/cli.js.map +1 -1
- package/package.json +2 -2
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.2';
|
|
12
12
|
const config = new Conf({
|
|
13
13
|
projectName: 'shadow-brain',
|
|
14
14
|
defaults: {
|
|
@@ -3913,5 +3913,884 @@ program.addCommand(gardenCmd);
|
|
|
3913
3913
|
program.addCommand(prReviewCmd);
|
|
3914
3914
|
program.addCommand(teamSyncCmd);
|
|
3915
3915
|
program.addCommand(exchangeCmd);
|
|
3916
|
+
// ════════════════════════════════════════════════════════════════════
|
|
3917
|
+
// v6.0.2 "Singularity" — 5 viral features + infrastructure + DX
|
|
3918
|
+
// ════════════════════════════════════════════════════════════════════
|
|
3919
|
+
// ── 🎬 Brain Replay ─────────────────────────────────────────────────
|
|
3920
|
+
const replayCmd = new Command('replay')
|
|
3921
|
+
.description('Brain Replay — scrubbable timeline of every brain event since day zero')
|
|
3922
|
+
.option('--project <name>', 'Project name', 'default');
|
|
3923
|
+
replayCmd.addCommand(new Command('export')
|
|
3924
|
+
.description('Export the timeline as svg | jsonl | csv')
|
|
3925
|
+
.option('--project <name>', 'Project name', 'default')
|
|
3926
|
+
.option('--format <fmt>', 'svg|jsonl|csv', 'svg')
|
|
3927
|
+
.option('--out <path>', 'Output path (default: stdout for svg/csv, file for jsonl)')
|
|
3928
|
+
.action(async (opts) => {
|
|
3929
|
+
const { getBrainReplay } = await import('./brain/brain-replay.js');
|
|
3930
|
+
const out = getBrainReplay().export(opts.project, opts.format);
|
|
3931
|
+
if (opts.out) {
|
|
3932
|
+
fs.writeFileSync(opts.out, typeof out === 'string' ? out : out);
|
|
3933
|
+
console.log(chalk.green(` ✓ ${opts.format} written to ${opts.out}`));
|
|
3934
|
+
}
|
|
3935
|
+
else {
|
|
3936
|
+
process.stdout.write(typeof out === 'string' ? out : out.toString());
|
|
3937
|
+
}
|
|
3938
|
+
}));
|
|
3939
|
+
replayCmd.addCommand(new Command('frame-at')
|
|
3940
|
+
.description('Show the brain state at a specific timestamp')
|
|
3941
|
+
.requiredOption('--ts <epoch>', 'Unix epoch ms')
|
|
3942
|
+
.option('--project <name>', 'Project name', 'default')
|
|
3943
|
+
.action(async (opts) => {
|
|
3944
|
+
const { getBrainReplay } = await import('./brain/brain-replay.js');
|
|
3945
|
+
const frame = getBrainReplay().frameAt(opts.project, parseInt(opts.ts, 10));
|
|
3946
|
+
console.log(JSON.stringify(frame, null, 2));
|
|
3947
|
+
}));
|
|
3948
|
+
replayCmd.addCommand(new Command('compress')
|
|
3949
|
+
.description('Compact old events into snapshots to bound disk use')
|
|
3950
|
+
.option('--project <name>', 'Project name', 'default')
|
|
3951
|
+
.action(async (opts) => {
|
|
3952
|
+
const { getBrainReplay } = await import('./brain/brain-replay.js');
|
|
3953
|
+
getBrainReplay().compress(opts.project);
|
|
3954
|
+
console.log(chalk.green(' ✓ replay log compressed'));
|
|
3955
|
+
}));
|
|
3956
|
+
// ── 🧬 Brain DNA ─────────────────────────────────────────────────────
|
|
3957
|
+
const brainDnaCmd = new Command('brain-dna')
|
|
3958
|
+
.description('Brain DNA — Spotify-Wrapped-style shareable fingerprint card');
|
|
3959
|
+
brainDnaCmd.addCommand(new Command('card')
|
|
3960
|
+
.description('Generate a DNA card for a project')
|
|
3961
|
+
.option('--project <name>', 'Project name', 'default')
|
|
3962
|
+
.option('--style <s>', 'card|poster|banner', 'card')
|
|
3963
|
+
.option('--out <path>', 'Output SVG path (default stdout)')
|
|
3964
|
+
.action(async (opts) => {
|
|
3965
|
+
const { getBrainDna } = await import('./brain/brain-dna.js');
|
|
3966
|
+
const { svg, stats } = getBrainDna().generate(opts.project, { style: opts.style });
|
|
3967
|
+
if (opts.out) {
|
|
3968
|
+
fs.writeFileSync(opts.out, svg);
|
|
3969
|
+
console.log(chalk.green(` ✓ ${opts.style} written to ${opts.out}`));
|
|
3970
|
+
console.log(chalk.dim(` archetype: ${stats.archetype} · entities: ${stats.totalEntities} · age: ${stats.ageDays}d`));
|
|
3971
|
+
}
|
|
3972
|
+
else
|
|
3973
|
+
process.stdout.write(svg);
|
|
3974
|
+
}));
|
|
3975
|
+
brainDnaCmd.addCommand(new Command('compare')
|
|
3976
|
+
.description('Side-by-side DNA cards for two projects')
|
|
3977
|
+
.requiredOption('--a <projectA>', 'First project name')
|
|
3978
|
+
.requiredOption('--b <projectB>', 'Second project name')
|
|
3979
|
+
.option('--out <path>', 'Output SVG path (default stdout)')
|
|
3980
|
+
.action(async (opts) => {
|
|
3981
|
+
const { getBrainDna } = await import('./brain/brain-dna.js');
|
|
3982
|
+
const { svg } = getBrainDna().compareCards(opts.a, opts.b);
|
|
3983
|
+
if (opts.out) {
|
|
3984
|
+
fs.writeFileSync(opts.out, svg);
|
|
3985
|
+
console.log(chalk.green(` ✓ comparison written to ${opts.out}`));
|
|
3986
|
+
}
|
|
3987
|
+
else
|
|
3988
|
+
process.stdout.write(svg);
|
|
3989
|
+
}));
|
|
3990
|
+
brainDnaCmd.addCommand(new Command('archetypes')
|
|
3991
|
+
.description('List all personality archetypes')
|
|
3992
|
+
.action(async () => {
|
|
3993
|
+
const { getBrainDna } = await import('./brain/brain-dna.js');
|
|
3994
|
+
for (const a of getBrainDna().topArchetypes())
|
|
3995
|
+
console.log(` • ${a}`);
|
|
3996
|
+
}));
|
|
3997
|
+
// ── 🗳️ Hive Voice ───────────────────────────────────────────────────
|
|
3998
|
+
const hiveVoiceCmd = new Command('hive-voice')
|
|
3999
|
+
.description('Hive Voice — multi-model debate-vote with dissent + confidence distribution');
|
|
4000
|
+
hiveVoiceCmd.addCommand(new Command('ask')
|
|
4001
|
+
.description('Ask a question; multiple local models vote')
|
|
4002
|
+
.argument('<question...>', 'Question to ask')
|
|
4003
|
+
.option('--rounds <n>', 'Number of debate rounds', '1')
|
|
4004
|
+
.option('--mode <m>', 'unanimous|majority|weighted', 'weighted')
|
|
4005
|
+
.option('--svg <path>', 'Save bar-chart SVG to this path')
|
|
4006
|
+
.option('--json', 'Output full JSON')
|
|
4007
|
+
.action(async (questionParts, opts) => {
|
|
4008
|
+
const { getHiveVoice } = await import('./brain/hive-voice.js');
|
|
4009
|
+
const question = questionParts.join(' ');
|
|
4010
|
+
const result = await getHiveVoice().ask(question, {
|
|
4011
|
+
rounds: parseInt(opts.rounds, 10),
|
|
4012
|
+
mode: opts.mode,
|
|
4013
|
+
});
|
|
4014
|
+
if (opts.svg)
|
|
4015
|
+
fs.writeFileSync(opts.svg, result.svg);
|
|
4016
|
+
if (opts.json)
|
|
4017
|
+
return console.log(JSON.stringify(result, null, 2));
|
|
4018
|
+
console.log(chalk.magenta.bold(`\n HIVE VOTE — ${result.mode}`));
|
|
4019
|
+
console.log(` ${chalk.cyan('consensus:')} ${result.consensus}`);
|
|
4020
|
+
console.log(` ${chalk.cyan('confidence:')} ${(result.confidence * 100).toFixed(0)}%`);
|
|
4021
|
+
console.log(` ${chalk.cyan('voters:')} ${result.votes.length} ${chalk.dim('dissents:')} ${result.dissents.length}`);
|
|
4022
|
+
if (opts.svg)
|
|
4023
|
+
console.log(chalk.green(` ✓ chart written to ${opts.svg}`));
|
|
4024
|
+
}));
|
|
4025
|
+
// ── ⏰ Brain Time Capsule ────────────────────────────────────────────
|
|
4026
|
+
const capsuleCmd = new Command('capsule')
|
|
4027
|
+
.description('Brain Time Capsule — freeze, label, and resurrect brain snapshots');
|
|
4028
|
+
capsuleCmd.addCommand(new Command('freeze')
|
|
4029
|
+
.description('Freeze the current brain into a labelled capsule')
|
|
4030
|
+
.requiredOption('--label <label>', 'Human-readable label')
|
|
4031
|
+
.option('--project <name>', 'Project name', 'default')
|
|
4032
|
+
.option('--description <text>', 'Longer description')
|
|
4033
|
+
.action(async (opts) => {
|
|
4034
|
+
const { getBrainTimeCapsule } = await import('./brain/brain-time-capsule.js');
|
|
4035
|
+
const r = await getBrainTimeCapsule().freeze(opts.project, opts.label, { description: opts.description });
|
|
4036
|
+
console.log(chalk.green(` ✓ capsule frozen: ${r.capsuleId}`));
|
|
4037
|
+
console.log(chalk.dim(` path: ${r.path} size: ${(r.sizeBytes / 1024).toFixed(1)}KB`));
|
|
4038
|
+
}));
|
|
4039
|
+
capsuleCmd.addCommand(new Command('list')
|
|
4040
|
+
.description('List capsules for a project')
|
|
4041
|
+
.option('--project <name>', 'Project name', 'default')
|
|
4042
|
+
.action(async (opts) => {
|
|
4043
|
+
const { getBrainTimeCapsule } = await import('./brain/brain-time-capsule.js');
|
|
4044
|
+
const list = await getBrainTimeCapsule().list(opts.project);
|
|
4045
|
+
for (const c of list)
|
|
4046
|
+
console.log(` ${chalk.cyan(c.capsuleId.padEnd(24))} ${c.label.padEnd(30)} ${chalk.dim(c.createdAt)}`);
|
|
4047
|
+
}));
|
|
4048
|
+
capsuleCmd.addCommand(new Command('restore')
|
|
4049
|
+
.description('Restore a frozen capsule into the active brain')
|
|
4050
|
+
.argument('<capsuleId>', 'Capsule id from `capsule list`')
|
|
4051
|
+
.action(async (capsuleId) => {
|
|
4052
|
+
const { getBrainTimeCapsule } = await import('./brain/brain-time-capsule.js');
|
|
4053
|
+
const r = await getBrainTimeCapsule().restore(capsuleId);
|
|
4054
|
+
console.log(chalk.green(` ✓ restored at ${new Date(r.restoredAt).toISOString()}`));
|
|
4055
|
+
console.log(chalk.dim(` ${r.replacedFiles.length} files replaced`));
|
|
4056
|
+
}));
|
|
4057
|
+
capsuleCmd.addCommand(new Command('inspect')
|
|
4058
|
+
.description('Read-only inspection of a capsule')
|
|
4059
|
+
.argument('<capsuleId>')
|
|
4060
|
+
.action(async (capsuleId) => {
|
|
4061
|
+
const { getBrainTimeCapsule } = await import('./brain/brain-time-capsule.js');
|
|
4062
|
+
const r = await getBrainTimeCapsule().inspect(capsuleId);
|
|
4063
|
+
console.log(JSON.stringify(r, null, 2));
|
|
4064
|
+
}));
|
|
4065
|
+
capsuleCmd.addCommand(new Command('diff')
|
|
4066
|
+
.description('Diff two capsules')
|
|
4067
|
+
.argument('<a>')
|
|
4068
|
+
.argument('<b>')
|
|
4069
|
+
.action(async (a, b) => {
|
|
4070
|
+
const { getBrainTimeCapsule } = await import('./brain/brain-time-capsule.js');
|
|
4071
|
+
const r = await getBrainTimeCapsule().diff(a, b);
|
|
4072
|
+
console.log(JSON.stringify(r, null, 2));
|
|
4073
|
+
}));
|
|
4074
|
+
// ── 🔬 Brain Diff (between two brains) ───────────────────────────────
|
|
4075
|
+
const brainDiffCmd = new Command('brain-diff')
|
|
4076
|
+
.description('Brain Diff — semantic diff between two brains (paths or capsule ids)');
|
|
4077
|
+
brainDiffCmd.addCommand(new Command('compare')
|
|
4078
|
+
.description('Compare brainA vs brainB')
|
|
4079
|
+
.argument('<brainA>', 'Path or capsule id')
|
|
4080
|
+
.argument('<brainB>', 'Path or capsule id')
|
|
4081
|
+
.option('--svg <path>', 'Save Venn-diagram SVG')
|
|
4082
|
+
.option('--narrative', 'Print the English narrative summary')
|
|
4083
|
+
.option('--json', 'Output full JSON report')
|
|
4084
|
+
.action(async (a, b, opts) => {
|
|
4085
|
+
const { getBrainDiff } = await import('./brain/brain-diff.js');
|
|
4086
|
+
const r = await getBrainDiff().diff(a, b);
|
|
4087
|
+
if (opts.svg)
|
|
4088
|
+
fs.writeFileSync(opts.svg, r.svg);
|
|
4089
|
+
if (opts.json)
|
|
4090
|
+
return console.log(JSON.stringify(r, null, 2));
|
|
4091
|
+
console.log(chalk.magenta.bold(`\n BRAIN DIFF`));
|
|
4092
|
+
console.log(chalk.dim(` only in A: ${r.onlyInA.length} only in B: ${r.onlyInB.length} shared: ${r.bothShared.length} conflicting: ${r.conflicting.length}`));
|
|
4093
|
+
console.log(chalk.dim(` similarity: ${(r.stats.similarityScore * 100).toFixed(0)}%`));
|
|
4094
|
+
if (opts.narrative)
|
|
4095
|
+
console.log('\n ' + r.narrative);
|
|
4096
|
+
if (opts.svg)
|
|
4097
|
+
console.log(chalk.green(` ✓ Venn written to ${opts.svg}`));
|
|
4098
|
+
}));
|
|
4099
|
+
// ── 📜 Constitution layer ────────────────────────────────────────────
|
|
4100
|
+
const constitutionCmd = new Command('constitution')
|
|
4101
|
+
.description('Constitution — project invariants the brain enforces');
|
|
4102
|
+
constitutionCmd.addCommand(new Command('init')
|
|
4103
|
+
.description('Create .shadow-brain/constitution.md with a template')
|
|
4104
|
+
.action(async () => {
|
|
4105
|
+
const cwd = process.cwd();
|
|
4106
|
+
const dir = path.join(cwd, '.shadow-brain');
|
|
4107
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
4108
|
+
const target = path.join(dir, 'constitution.md');
|
|
4109
|
+
if (fs.existsSync(target))
|
|
4110
|
+
return console.log(chalk.yellow(' constitution.md already exists.'));
|
|
4111
|
+
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`);
|
|
4112
|
+
console.log(chalk.green(` ✓ ${target}`));
|
|
4113
|
+
}));
|
|
4114
|
+
constitutionCmd.addCommand(new Command('rules')
|
|
4115
|
+
.description('List all parsed rules')
|
|
4116
|
+
.action(async () => {
|
|
4117
|
+
const { getConstitution } = await import('./brain/constitution.js');
|
|
4118
|
+
const c = getConstitution(process.cwd());
|
|
4119
|
+
for (const r of c.listRules()) {
|
|
4120
|
+
const sev = r.severity === 'must' ? chalk.red('MUST') : r.severity === 'should' ? chalk.yellow('SHOULD') : chalk.green('NEVER');
|
|
4121
|
+
console.log(` [${sev}] (${r.scope}) ${r.text}`);
|
|
4122
|
+
}
|
|
4123
|
+
c.dispose();
|
|
4124
|
+
}));
|
|
4125
|
+
constitutionCmd.addCommand(new Command('validate')
|
|
4126
|
+
.description('Check a text snippet against constitution rules')
|
|
4127
|
+
.argument('<text...>')
|
|
4128
|
+
.action(async (parts) => {
|
|
4129
|
+
const { getConstitution } = await import('./brain/constitution.js');
|
|
4130
|
+
const c = getConstitution(process.cwd());
|
|
4131
|
+
const r = await c.validate(parts.join(' '));
|
|
4132
|
+
console.log(chalk.cyan(` violations: ${r.violations.length} passed: ${r.passed.length}`));
|
|
4133
|
+
for (const v of r.violations)
|
|
4134
|
+
console.log(chalk.red(` × ${v.rule.text}`));
|
|
4135
|
+
c.dispose();
|
|
4136
|
+
}));
|
|
4137
|
+
// ── 🚦 Confidence Gate ───────────────────────────────────────────────
|
|
4138
|
+
const gateCmd = new Command('gate')
|
|
4139
|
+
.description('Confidence Gate — active output filter based on calibrated confidence');
|
|
4140
|
+
gateCmd.addCommand(new Command('threshold')
|
|
4141
|
+
.description('Show or set the gate threshold')
|
|
4142
|
+
.option('--set <n>', 'Set threshold (0.0-1.0)')
|
|
4143
|
+
.action(async (opts) => {
|
|
4144
|
+
const { getConfidenceGate } = await import('./brain/confidence-gate.js');
|
|
4145
|
+
const g = getConfidenceGate();
|
|
4146
|
+
if (opts.set) {
|
|
4147
|
+
g.setThreshold(parseFloat(opts.set));
|
|
4148
|
+
console.log(chalk.green(` ✓ threshold = ${opts.set}`));
|
|
4149
|
+
}
|
|
4150
|
+
else {
|
|
4151
|
+
console.log(` threshold: ${chalk.cyan(String(g.getThreshold()))}`);
|
|
4152
|
+
}
|
|
4153
|
+
}));
|
|
4154
|
+
gateCmd.addCommand(new Command('stats')
|
|
4155
|
+
.description('Show calibration stats (Brier score + ECE)')
|
|
4156
|
+
.action(async () => {
|
|
4157
|
+
const { getConfidenceGate } = await import('./brain/confidence-gate.js');
|
|
4158
|
+
const s = getConfidenceGate().stats();
|
|
4159
|
+
console.log(JSON.stringify(s, null, 2));
|
|
4160
|
+
}));
|
|
4161
|
+
gateCmd.addCommand(new Command('test')
|
|
4162
|
+
.description('Test the gate on a {text, confidence} pair')
|
|
4163
|
+
.requiredOption('--text <t>', 'Input text')
|
|
4164
|
+
.requiredOption('--confidence <c>', 'Predicted confidence 0..1')
|
|
4165
|
+
.option('--mode <m>', 'block|downgrade|flag', 'downgrade')
|
|
4166
|
+
.action(async (opts) => {
|
|
4167
|
+
const { getConfidenceGate } = await import('./brain/confidence-gate.js');
|
|
4168
|
+
const result = await getConfidenceGate().gate({ text: opts.text, confidence: parseFloat(opts.confidence) }, { mode: opts.mode });
|
|
4169
|
+
console.log(JSON.stringify(result, null, 2));
|
|
4170
|
+
}));
|
|
4171
|
+
// ── 🧠 Embeddings v2 (real ANN index) ────────────────────────────────
|
|
4172
|
+
const embedCmd = new Command('embed')
|
|
4173
|
+
.description('EmbeddingsV2 — real ANN vector index (HNSW-style, sub-100ms recall)');
|
|
4174
|
+
embedCmd.addCommand(new Command('add')
|
|
4175
|
+
.description('Add a document to the index')
|
|
4176
|
+
.requiredOption('--id <id>', 'Document id')
|
|
4177
|
+
.requiredOption('--text <text>', 'Text to embed')
|
|
4178
|
+
.action(async (opts) => {
|
|
4179
|
+
const { getEmbeddingsV2 } = await import('./brain/embeddings-v2.js');
|
|
4180
|
+
await getEmbeddingsV2().addDocument(opts.id, opts.text);
|
|
4181
|
+
console.log(chalk.green(` ✓ added ${opts.id}`));
|
|
4182
|
+
}));
|
|
4183
|
+
embedCmd.addCommand(new Command('search')
|
|
4184
|
+
.description('Semantic search across the index')
|
|
4185
|
+
.requiredOption('--query <q>', 'Query text')
|
|
4186
|
+
.option('--top <n>', 'Top K results', '10')
|
|
4187
|
+
.action(async (opts) => {
|
|
4188
|
+
const { getEmbeddingsV2 } = await import('./brain/embeddings-v2.js');
|
|
4189
|
+
const hits = await getEmbeddingsV2().search(opts.query, parseInt(opts.top, 10));
|
|
4190
|
+
for (const h of hits)
|
|
4191
|
+
console.log(` ${chalk.cyan(h.score.toFixed(3))} ${h.id}`);
|
|
4192
|
+
}));
|
|
4193
|
+
embedCmd.addCommand(new Command('stats')
|
|
4194
|
+
.description('Index statistics')
|
|
4195
|
+
.action(async () => {
|
|
4196
|
+
const { getEmbeddingsV2 } = await import('./brain/embeddings-v2.js');
|
|
4197
|
+
console.log(JSON.stringify(getEmbeddingsV2().stats(), null, 2));
|
|
4198
|
+
}));
|
|
4199
|
+
// ── 🖼️ Multimodal vision ─────────────────────────────────────────────
|
|
4200
|
+
const visionCmd = new Command('vision')
|
|
4201
|
+
.description('Multimodal vision — ingest screenshots, diagrams, photos via Ollama llava');
|
|
4202
|
+
visionCmd.addCommand(new Command('ingest')
|
|
4203
|
+
.description('Ingest one image into the brain')
|
|
4204
|
+
.argument('<path>', 'Image file path')
|
|
4205
|
+
.option('--project <name>', 'Project name', 'default')
|
|
4206
|
+
.option('--tags <csv>', 'Comma-separated tags', '')
|
|
4207
|
+
.option('--prompt <p>', 'Override vision prompt')
|
|
4208
|
+
.action(async (filePath, opts) => {
|
|
4209
|
+
const { getMultimodalVision } = await import('./brain/multimodal-vision.js');
|
|
4210
|
+
const v = await getMultimodalVision().ingestImage(filePath, {
|
|
4211
|
+
project: opts.project,
|
|
4212
|
+
tags: opts.tags ? opts.tags.split(',').map((s) => s.trim()) : [],
|
|
4213
|
+
prompt: opts.prompt,
|
|
4214
|
+
});
|
|
4215
|
+
console.log(chalk.green(` ✓ ingested ${v.id}`));
|
|
4216
|
+
console.log(chalk.dim(` ${v.description.slice(0, 200)}${v.description.length > 200 ? '…' : ''}`));
|
|
4217
|
+
}));
|
|
4218
|
+
visionCmd.addCommand(new Command('search')
|
|
4219
|
+
.description('Semantic search across stored image descriptions')
|
|
4220
|
+
.requiredOption('--query <q>')
|
|
4221
|
+
.option('--top <n>', 'Top K', '5')
|
|
4222
|
+
.option('--project <name>', 'Project name', 'default')
|
|
4223
|
+
.action(async (opts) => {
|
|
4224
|
+
const { getMultimodalVision } = await import('./brain/multimodal-vision.js');
|
|
4225
|
+
const hits = await getMultimodalVision().search(opts.query, parseInt(opts.top, 10), opts.project);
|
|
4226
|
+
for (const h of hits)
|
|
4227
|
+
console.log(` ${chalk.cyan(h.id.padEnd(20))} ${h.description.slice(0, 100)}`);
|
|
4228
|
+
}));
|
|
4229
|
+
visionCmd.addCommand(new Command('recent')
|
|
4230
|
+
.description('Recently ingested images')
|
|
4231
|
+
.option('-n <count>', 'How many', '10')
|
|
4232
|
+
.option('--project <name>', 'Project name', 'default')
|
|
4233
|
+
.action(async (opts) => {
|
|
4234
|
+
const { getMultimodalVision } = await import('./brain/multimodal-vision.js');
|
|
4235
|
+
const list = await getMultimodalVision().recent(parseInt(opts.n, 10), opts.project);
|
|
4236
|
+
for (const v of list)
|
|
4237
|
+
console.log(` ${chalk.dim(new Date(v.capturedAt).toISOString())} ${v.id} ${v.description.slice(0, 80)}`);
|
|
4238
|
+
}));
|
|
4239
|
+
// ── 📤 Markdown export / 📥 import ───────────────────────────────────
|
|
4240
|
+
const exportMdCmd = new Command('export-md')
|
|
4241
|
+
.description('Export the brain to a git-trackable Markdown file')
|
|
4242
|
+
.option('--project <name>', 'Project name', 'default')
|
|
4243
|
+
.option('--out <path>', 'Output path', '.shadow-brain.md')
|
|
4244
|
+
.option('--sections <csv>', 'memories,patterns,decisions,entities,rules')
|
|
4245
|
+
.action(async (opts) => {
|
|
4246
|
+
const { getMarkdownExport } = await import('./brain/markdown-export.js');
|
|
4247
|
+
const sections = opts.sections ? opts.sections.split(',') : undefined;
|
|
4248
|
+
const r = await getMarkdownExport().exportBrain(opts.project, { sections, outPath: opts.out });
|
|
4249
|
+
console.log(chalk.green(` ✓ ${r.path}`));
|
|
4250
|
+
console.log(chalk.dim(` ${(r.sizeBytes / 1024).toFixed(1)}KB · ${Object.entries(r.sectionCounts).map(([k, v]) => `${k}:${v}`).join(' ')}`));
|
|
4251
|
+
});
|
|
4252
|
+
const importMdCmd = new Command('import-md')
|
|
4253
|
+
.description('Import a brain from a previously exported Markdown file')
|
|
4254
|
+
.argument('<path>', 'Path to .shadow-brain.md')
|
|
4255
|
+
.option('--merge <strategy>', 'replace|addNew|overwrite', 'addNew')
|
|
4256
|
+
.option('--dry-run', 'Print diff without writing')
|
|
4257
|
+
.action(async (mdPath, opts) => {
|
|
4258
|
+
const { getMarkdownExport } = await import('./brain/markdown-export.js');
|
|
4259
|
+
if (opts.dryRun) {
|
|
4260
|
+
const d = await getMarkdownExport().diff(mdPath);
|
|
4261
|
+
return console.log(JSON.stringify(d, null, 2));
|
|
4262
|
+
}
|
|
4263
|
+
const r = await getMarkdownExport().importBrain(mdPath, { merge: opts.merge });
|
|
4264
|
+
console.log(chalk.green(` ✓ added: ${r.added} modified: ${r.modified} skipped: ${r.skipped} errors: ${r.errors}`));
|
|
4265
|
+
});
|
|
4266
|
+
// ── 🔭 OTel-lite traces ──────────────────────────────────────────────
|
|
4267
|
+
const tracesCmd = new Command('traces')
|
|
4268
|
+
.description('OTel-lite — JSONL trace viewer for brain operations');
|
|
4269
|
+
tracesCmd.addCommand(new Command('tail')
|
|
4270
|
+
.description('Tail the most recent trace lines')
|
|
4271
|
+
.option('-n <count>', 'Number of lines', '50')
|
|
4272
|
+
.option('--json', 'Raw JSONL')
|
|
4273
|
+
.action(async (opts) => {
|
|
4274
|
+
const { OtelLite } = await import('./brain/otel-lite.js');
|
|
4275
|
+
const lines = await OtelLite.tail(parseInt(opts.n, 10));
|
|
4276
|
+
if (opts.json)
|
|
4277
|
+
return lines.forEach(l => console.log(JSON.stringify(l)));
|
|
4278
|
+
for (const l of lines) {
|
|
4279
|
+
const dur = ((l.end_ns - l.start_ns) / 1000000).toFixed(1);
|
|
4280
|
+
console.log(` ${chalk.dim(new Date(l.start_ns / 1000000).toISOString())} ${chalk.cyan(l.name.padEnd(28))} ${dur}ms`);
|
|
4281
|
+
}
|
|
4282
|
+
}));
|
|
4283
|
+
tracesCmd.addCommand(new Command('today')
|
|
4284
|
+
.description('Print today\'s trace file path')
|
|
4285
|
+
.action(async () => {
|
|
4286
|
+
const { OtelLite } = await import('./brain/otel-lite.js');
|
|
4287
|
+
console.log(OtelLite.todayFilePath());
|
|
4288
|
+
}));
|
|
4289
|
+
tracesCmd.addCommand(new Command('cleanup')
|
|
4290
|
+
.description('Drop trace files older than 14 days')
|
|
4291
|
+
.action(async () => {
|
|
4292
|
+
const { OtelLite } = await import('./brain/otel-lite.js');
|
|
4293
|
+
OtelLite.cleanup();
|
|
4294
|
+
console.log(chalk.green(' ✓ cleanup done'));
|
|
4295
|
+
}));
|
|
4296
|
+
// ── 🎉 Demo — 30-second hello-world ──────────────────────────────────
|
|
4297
|
+
const demoCmd = new Command('demo')
|
|
4298
|
+
.description('30-second Hello Brain — ingest sample data, run sample queries, open dashboard')
|
|
4299
|
+
.option('--no-open', 'Skip launching the dashboard')
|
|
4300
|
+
.option('--port <port>', 'Dashboard port', '7341')
|
|
4301
|
+
.action(async (opts) => {
|
|
4302
|
+
console.log(chalk.magenta.bold(`\n 🧠 SHADOW BRAIN v${VERSION} — 30-Second Demo\n`));
|
|
4303
|
+
// 1. seed a few sample memories
|
|
4304
|
+
const { getEmbeddingsV2 } = await import('./brain/embeddings-v2.js');
|
|
4305
|
+
const ev2 = getEmbeddingsV2();
|
|
4306
|
+
const samples = [
|
|
4307
|
+
['mem-1', 'Always parameterize SQL queries to prevent injection.'],
|
|
4308
|
+
['mem-2', 'React useEffect cleanup functions must cancel pending async work.'],
|
|
4309
|
+
['mem-3', 'When a test flakes, look for time-of-day dependencies first.'],
|
|
4310
|
+
['mem-4', 'Postgres connection pooling: max 100 connections in production.'],
|
|
4311
|
+
['mem-5', 'In dual-mode work, the Opus brain plans and Codex implements.'],
|
|
4312
|
+
];
|
|
4313
|
+
console.log(chalk.cyan(' ▶ seeding sample memories'));
|
|
4314
|
+
for (const [id, text] of samples)
|
|
4315
|
+
await ev2.addDocument(id, text);
|
|
4316
|
+
// 2. run sample searches
|
|
4317
|
+
console.log(chalk.cyan(' ▶ semantic search: "how do I prevent SQL injection?"'));
|
|
4318
|
+
const hits = await ev2.search('how do I prevent SQL injection', 3);
|
|
4319
|
+
for (const h of hits)
|
|
4320
|
+
console.log(` ${chalk.cyan(h.score.toFixed(3))} ${h.id}`);
|
|
4321
|
+
// 3. generate Brain DNA card
|
|
4322
|
+
console.log(chalk.cyan('\n ▶ generating Brain DNA card'));
|
|
4323
|
+
const { getBrainDna } = await import('./brain/brain-dna.js');
|
|
4324
|
+
const dna = getBrainDna().generate('demo', { style: 'card' });
|
|
4325
|
+
const dnaPath = path.join(os.tmpdir(), 'shadow-brain-demo-dna.svg');
|
|
4326
|
+
fs.writeFileSync(dnaPath, dna.svg);
|
|
4327
|
+
console.log(` ${chalk.dim('archetype:')} ${dna.stats.archetype}`);
|
|
4328
|
+
console.log(` ${chalk.green('✓')} card written: ${dnaPath}`);
|
|
4329
|
+
// 4. record some replay events so timeline isn't empty
|
|
4330
|
+
const { getBrainReplay } = await import('./brain/brain-replay.js');
|
|
4331
|
+
for (const [id, text] of samples) {
|
|
4332
|
+
getBrainReplay().record({ type: 'memory.add', payload: { id, text }, project: 'demo' });
|
|
4333
|
+
}
|
|
4334
|
+
const replaySvg = getBrainReplay().export('demo', 'svg');
|
|
4335
|
+
const replayPath = path.join(os.tmpdir(), 'shadow-brain-demo-replay.svg');
|
|
4336
|
+
fs.writeFileSync(replayPath, typeof replaySvg === 'string' ? replaySvg : replaySvg);
|
|
4337
|
+
console.log(` ${chalk.green('✓')} replay timeline written: ${replayPath}`);
|
|
4338
|
+
// 5. optionally launch dashboard
|
|
4339
|
+
if (opts.open !== false) {
|
|
4340
|
+
console.log(chalk.cyan('\n ▶ launching dashboard'));
|
|
4341
|
+
const { Orchestrator } = await import('./brain/orchestrator.js');
|
|
4342
|
+
const { DashboardServer } = await import('./dashboard/server.js');
|
|
4343
|
+
const orchestrator = new Orchestrator(mergeConfig({}));
|
|
4344
|
+
const dashboard = new DashboardServer(orchestrator, { port: parseInt(opts.port, 10), openBrowser: true });
|
|
4345
|
+
const url = await dashboard.start();
|
|
4346
|
+
console.log(chalk.green(` ✓ ${url}`));
|
|
4347
|
+
console.log(chalk.dim('\n Press Ctrl+C to stop.'));
|
|
4348
|
+
}
|
|
4349
|
+
else {
|
|
4350
|
+
console.log(chalk.dim('\n Done. Run with --no-open=false to launch the dashboard.'));
|
|
4351
|
+
}
|
|
4352
|
+
});
|
|
4353
|
+
program.addCommand(replayCmd);
|
|
4354
|
+
program.addCommand(brainDnaCmd);
|
|
4355
|
+
program.addCommand(hiveVoiceCmd);
|
|
4356
|
+
program.addCommand(capsuleCmd);
|
|
4357
|
+
program.addCommand(brainDiffCmd);
|
|
4358
|
+
program.addCommand(constitutionCmd);
|
|
4359
|
+
program.addCommand(gateCmd);
|
|
4360
|
+
program.addCommand(embedCmd);
|
|
4361
|
+
program.addCommand(visionCmd);
|
|
4362
|
+
program.addCommand(exportMdCmd);
|
|
4363
|
+
program.addCommand(importMdCmd);
|
|
4364
|
+
program.addCommand(tracesCmd);
|
|
4365
|
+
program.addCommand(demoCmd);
|
|
4366
|
+
// ════════════════════════════════════════════════════════════════════
|
|
4367
|
+
// v6.0.2 Wave 2 — 14 advanced viral features
|
|
4368
|
+
// ════════════════════════════════════════════════════════════════════
|
|
4369
|
+
// ── 🎵 Brain Cinema ──────────────────────────────────────────────────
|
|
4370
|
+
const cinemaCmd = new Command('cinema')
|
|
4371
|
+
.description('Brain Cinema — auto 60-second SVG-animated video of brain growth')
|
|
4372
|
+
.option('--project <name>', 'Project name', 'default')
|
|
4373
|
+
.option('--style <s>', 'minimal|rich|arcade', 'rich')
|
|
4374
|
+
.option('--duration <s>', 'Duration in seconds', '60')
|
|
4375
|
+
.option('--out <path>', 'Output SVG path')
|
|
4376
|
+
.action(async (opts) => {
|
|
4377
|
+
const { getBrainCinema } = await import('./brain/brain-cinema.js');
|
|
4378
|
+
const { svg, manifest } = await getBrainCinema().generate(opts.project, {
|
|
4379
|
+
style: opts.style,
|
|
4380
|
+
durationS: parseInt(opts.duration, 10),
|
|
4381
|
+
});
|
|
4382
|
+
if (opts.out) {
|
|
4383
|
+
fs.writeFileSync(opts.out, svg);
|
|
4384
|
+
console.log(chalk.green(` ✓ ${opts.out} (${manifest.eventsRendered} events, ${manifest.durationMs}ms)`));
|
|
4385
|
+
}
|
|
4386
|
+
else
|
|
4387
|
+
process.stdout.write(svg);
|
|
4388
|
+
});
|
|
4389
|
+
// ── 🎼 Brain Sonification ────────────────────────────────────────────
|
|
4390
|
+
const sonifyCmd = new Command('sonify')
|
|
4391
|
+
.description('Brain Sonification — your codebase as music (WAV)')
|
|
4392
|
+
.option('--project <name>', 'Project name', 'default')
|
|
4393
|
+
.option('--mode <m>', 'major|minor|phrygian', 'phrygian')
|
|
4394
|
+
.option('--duration <s>', 'Duration in seconds', '60')
|
|
4395
|
+
.option('--tempo <bpm>', 'Tempo BPM', '110')
|
|
4396
|
+
.option('--out <path>', 'Output WAV path (required)')
|
|
4397
|
+
.action(async (opts) => {
|
|
4398
|
+
const { getBrainSonification } = await import('./brain/brain-sonification.js');
|
|
4399
|
+
const { wav, manifest } = await getBrainSonification().generate(opts.project, {
|
|
4400
|
+
mode: opts.mode,
|
|
4401
|
+
durationS: parseInt(opts.duration, 10),
|
|
4402
|
+
tempo: parseInt(opts.tempo, 10),
|
|
4403
|
+
});
|
|
4404
|
+
const out = opts.out || `brain-sonification-${opts.project}-${Date.now()}.wav`;
|
|
4405
|
+
fs.writeFileSync(out, wav);
|
|
4406
|
+
console.log(chalk.green(` ✓ ${out} (${manifest.eventsRendered} events, ${manifest.durationMs}ms, ${manifest.mode})`));
|
|
4407
|
+
});
|
|
4408
|
+
// ── 🏆 Brain Trophies ────────────────────────────────────────────────
|
|
4409
|
+
const trophiesCmd = new Command('trophies')
|
|
4410
|
+
.description('Brain Trophies — 25 unlockable achievements with shareable cards');
|
|
4411
|
+
trophiesCmd.addCommand(new Command('list')
|
|
4412
|
+
.description('List achievements + progress')
|
|
4413
|
+
.option('--project <name>', 'Project name', 'default')
|
|
4414
|
+
.action(async (opts) => {
|
|
4415
|
+
const { getBrainTrophies } = await import('./brain/brain-trophies.js');
|
|
4416
|
+
const r = await getBrainTrophies().checkProgress(opts.project);
|
|
4417
|
+
console.log(chalk.magenta.bold(`\n TROPHIES — ${opts.project}`));
|
|
4418
|
+
console.log(chalk.green(` Unlocked: ${r.unlocked.length}/25`));
|
|
4419
|
+
for (const a of r.unlocked)
|
|
4420
|
+
console.log(` ${a.icon} ${chalk.cyan(a.name)} ${chalk.dim(a.rarity)}`);
|
|
4421
|
+
console.log(chalk.dim(`\n In progress: ${r.inProgress.length}`));
|
|
4422
|
+
for (const p of r.inProgress.slice(0, 5))
|
|
4423
|
+
console.log(` ${chalk.dim((p.progressPct * 100).toFixed(0) + '%')} ${p.achievement.name}`);
|
|
4424
|
+
}));
|
|
4425
|
+
trophiesCmd.addCommand(new Command('card')
|
|
4426
|
+
.description('Generate a share card for an unlocked trophy')
|
|
4427
|
+
.requiredOption('--id <achievementId>', 'Achievement ID (e.g., first-spark)')
|
|
4428
|
+
.option('--project <name>', 'Project name', 'default')
|
|
4429
|
+
.option('--style <s>', 'card|badge|trophy', 'card')
|
|
4430
|
+
.option('--out <path>', 'Output SVG path')
|
|
4431
|
+
.action(async (opts) => {
|
|
4432
|
+
const { getBrainTrophies } = await import('./brain/brain-trophies.js');
|
|
4433
|
+
const { svg } = await getBrainTrophies().generateCard(opts.project, opts.id, { style: opts.style });
|
|
4434
|
+
if (opts.out) {
|
|
4435
|
+
fs.writeFileSync(opts.out, svg);
|
|
4436
|
+
console.log(chalk.green(` ✓ ${opts.out}`));
|
|
4437
|
+
}
|
|
4438
|
+
else
|
|
4439
|
+
process.stdout.write(svg);
|
|
4440
|
+
}));
|
|
4441
|
+
trophiesCmd.addCommand(new Command('wall')
|
|
4442
|
+
.description('Wall-of-trophies SVG (1200×800)')
|
|
4443
|
+
.option('--project <name>', 'Project name', 'default')
|
|
4444
|
+
.option('--out <path>', 'Output SVG path')
|
|
4445
|
+
.action(async (opts) => {
|
|
4446
|
+
const { getBrainTrophies } = await import('./brain/brain-trophies.js');
|
|
4447
|
+
const { svg } = await getBrainTrophies().wallSvg(opts.project);
|
|
4448
|
+
if (opts.out) {
|
|
4449
|
+
fs.writeFileSync(opts.out, svg);
|
|
4450
|
+
console.log(chalk.green(` ✓ ${opts.out}`));
|
|
4451
|
+
}
|
|
4452
|
+
else
|
|
4453
|
+
process.stdout.write(svg);
|
|
4454
|
+
}));
|
|
4455
|
+
// ── 🎁 Brain Holiday Card ────────────────────────────────────────────
|
|
4456
|
+
const holidayCmd = new Command('holiday')
|
|
4457
|
+
.description('Brain Holiday Card — Spotify-Wrapped-style year-in-review')
|
|
4458
|
+
.option('--project <name>', 'Project name', 'default')
|
|
4459
|
+
.option('--year <yyyy>', 'Year', String(new Date().getFullYear()))
|
|
4460
|
+
.option('--style <s>', 'wrapped|classic|minimalist', 'wrapped')
|
|
4461
|
+
.option('--out <path>', 'Output SVG path')
|
|
4462
|
+
.action(async (opts) => {
|
|
4463
|
+
const { getBrainHolidayCard } = await import('./brain/brain-holiday-card.js');
|
|
4464
|
+
const { svg } = await getBrainHolidayCard().generate(opts.project, {
|
|
4465
|
+
year: parseInt(opts.year, 10),
|
|
4466
|
+
style: opts.style,
|
|
4467
|
+
});
|
|
4468
|
+
if (opts.out) {
|
|
4469
|
+
fs.writeFileSync(opts.out, svg);
|
|
4470
|
+
console.log(chalk.green(` ✓ ${opts.out}`));
|
|
4471
|
+
}
|
|
4472
|
+
else
|
|
4473
|
+
process.stdout.write(svg);
|
|
4474
|
+
});
|
|
4475
|
+
// ── 🧭 Brain Coach ───────────────────────────────────────────────────
|
|
4476
|
+
const coachCmd = new Command('coach')
|
|
4477
|
+
.description('Brain Coach — proactive idle suggestions');
|
|
4478
|
+
coachCmd.addCommand(new Command('suggestions')
|
|
4479
|
+
.description('Show current suggestions')
|
|
4480
|
+
.option('--project <name>', 'Project name', 'default')
|
|
4481
|
+
.option('--top <n>', 'Top N', '5')
|
|
4482
|
+
.action(async (opts) => {
|
|
4483
|
+
const { getBrainCoach } = await import('./brain/brain-coach.js');
|
|
4484
|
+
const list = await getBrainCoach().suggestions(opts.project, { topN: parseInt(opts.top, 10) });
|
|
4485
|
+
for (const s of list) {
|
|
4486
|
+
console.log(` ${s.emoji} ${chalk.cyan(s.title)}`);
|
|
4487
|
+
console.log(` ${chalk.dim(s.body)}`);
|
|
4488
|
+
}
|
|
4489
|
+
if (!list.length)
|
|
4490
|
+
console.log(chalk.dim(' No suggestions right now.'));
|
|
4491
|
+
}));
|
|
4492
|
+
coachCmd.addCommand(new Command('idle')
|
|
4493
|
+
.description('Run idle-check (call this when user has been idle)')
|
|
4494
|
+
.option('--project <name>', 'Project name', 'default')
|
|
4495
|
+
.option('--since <ms>', 'Idle for this many ms', '300000')
|
|
4496
|
+
.action(async (opts) => {
|
|
4497
|
+
const { getBrainCoach } = await import('./brain/brain-coach.js');
|
|
4498
|
+
const list = await getBrainCoach().idleCheck(opts.project, parseInt(opts.since, 10));
|
|
4499
|
+
for (const s of list)
|
|
4500
|
+
console.log(` ${s.emoji} ${s.title}`);
|
|
4501
|
+
}));
|
|
4502
|
+
coachCmd.addCommand(new Command('dismiss')
|
|
4503
|
+
.description('Dismiss a suggestion by id')
|
|
4504
|
+
.argument('<id>')
|
|
4505
|
+
.action(async (id) => {
|
|
4506
|
+
const { getBrainCoach } = await import('./brain/brain-coach.js');
|
|
4507
|
+
getBrainCoach().dismiss(id);
|
|
4508
|
+
console.log(chalk.green(' ✓ dismissed'));
|
|
4509
|
+
}));
|
|
4510
|
+
coachCmd.addCommand(new Command('pin')
|
|
4511
|
+
.description('Pin a suggestion')
|
|
4512
|
+
.argument('<id>')
|
|
4513
|
+
.action(async (id) => {
|
|
4514
|
+
const { getBrainCoach } = await import('./brain/brain-coach.js');
|
|
4515
|
+
getBrainCoach().pin(id);
|
|
4516
|
+
console.log(chalk.green(' ✓ pinned'));
|
|
4517
|
+
}));
|
|
4518
|
+
// ── 🗺️ Brain Quest ──────────────────────────────────────────────────
|
|
4519
|
+
const questCmd = new Command('quest')
|
|
4520
|
+
.description('Brain Quest — gamified onboarding adventures');
|
|
4521
|
+
questCmd.addCommand(new Command('list')
|
|
4522
|
+
.description('List available quests')
|
|
4523
|
+
.action(async () => {
|
|
4524
|
+
const { getBrainQuest } = await import('./brain/brain-quest.js');
|
|
4525
|
+
for (const q of getBrainQuest().availableQuests()) {
|
|
4526
|
+
console.log(` ${chalk.cyan(q.id.padEnd(20))} ${q.emoji} ${q.title}`);
|
|
4527
|
+
console.log(` ${chalk.dim(q.subtitle)} ${chalk.dim(`~${q.estimatedMinutes}m, ${q.steps.length} steps`)}`);
|
|
4528
|
+
}
|
|
4529
|
+
}));
|
|
4530
|
+
questCmd.addCommand(new Command('start')
|
|
4531
|
+
.description('Start a quest')
|
|
4532
|
+
.argument('<questId>')
|
|
4533
|
+
.option('--project <name>', 'Project name', 'default')
|
|
4534
|
+
.action(async (questId, opts) => {
|
|
4535
|
+
const { getBrainQuest } = await import('./brain/brain-quest.js');
|
|
4536
|
+
const state = await getBrainQuest().start(questId, opts.project);
|
|
4537
|
+
console.log(chalk.magenta.bold(`\n Quest started: ${questId}`));
|
|
4538
|
+
console.log(chalk.dim(` Step: ${state.currentStepId} (${state.completedSteps.length} steps completed)`));
|
|
4539
|
+
}));
|
|
4540
|
+
questCmd.addCommand(new Command('step')
|
|
4541
|
+
.description('Advance the current quest')
|
|
4542
|
+
.option('--project <name>', 'Project name', 'default')
|
|
4543
|
+
.option('--choice <c>', 'Branch choice if step has options')
|
|
4544
|
+
.action(async (opts) => {
|
|
4545
|
+
const { getBrainQuest } = await import('./brain/brain-quest.js');
|
|
4546
|
+
const r = await getBrainQuest().step(opts.project, opts.choice);
|
|
4547
|
+
console.log('\n' + r.narrative + '\n');
|
|
4548
|
+
if (r.options)
|
|
4549
|
+
for (const opt of r.options)
|
|
4550
|
+
console.log(` [${chalk.cyan(opt)}]`);
|
|
4551
|
+
if (r.complete)
|
|
4552
|
+
console.log(chalk.green(`\n ✓ Quest complete! ${r.reward?.message || ''}`));
|
|
4553
|
+
}));
|
|
4554
|
+
questCmd.addCommand(new Command('current')
|
|
4555
|
+
.description('Show the active quest state')
|
|
4556
|
+
.option('--project <name>', 'Project name', 'default')
|
|
4557
|
+
.action(async (opts) => {
|
|
4558
|
+
const { getBrainQuest } = await import('./brain/brain-quest.js');
|
|
4559
|
+
const s = getBrainQuest().current(opts.project);
|
|
4560
|
+
console.log(s ? JSON.stringify(s, null, 2) : chalk.dim(' No active quest. Run `quest list` to pick one.'));
|
|
4561
|
+
}));
|
|
4562
|
+
// ── 📓 Brain Notebook ────────────────────────────────────────────────
|
|
4563
|
+
const notebookCmd = new Command('notebook')
|
|
4564
|
+
.description('Brain Notebook — Jupyter-style interactive brain explorer');
|
|
4565
|
+
notebookCmd.addCommand(new Command('new')
|
|
4566
|
+
.description('Create a starter notebook')
|
|
4567
|
+
.option('--project <name>', 'Project name', 'default')
|
|
4568
|
+
.option('--title <t>', 'Notebook title', 'My Investigation')
|
|
4569
|
+
.action(async (opts) => {
|
|
4570
|
+
const { getBrainNotebook } = await import('./brain/brain-notebook.js');
|
|
4571
|
+
const r = await getBrainNotebook().createNotebook(opts.project, opts.title);
|
|
4572
|
+
console.log(chalk.green(` ✓ ${r.path}`));
|
|
4573
|
+
}));
|
|
4574
|
+
notebookCmd.addCommand(new Command('run')
|
|
4575
|
+
.description('Run all query cells, save inline results')
|
|
4576
|
+
.argument('<path>', 'Path to notebook .md')
|
|
4577
|
+
.action(async (notebookPath) => {
|
|
4578
|
+
const { getBrainNotebook } = await import('./brain/brain-notebook.js');
|
|
4579
|
+
const nb = await getBrainNotebook().parse(notebookPath);
|
|
4580
|
+
const r = await getBrainNotebook().runAll(nb);
|
|
4581
|
+
await getBrainNotebook().save(nb, notebookPath);
|
|
4582
|
+
const ran = r.cells.filter(c => c.result || c.error).length;
|
|
4583
|
+
console.log(chalk.green(` ✓ ran ${ran}/${r.cells.length} cells in ${r.totalDurationMs}ms`));
|
|
4584
|
+
}));
|
|
4585
|
+
// ── ⚡ Brain Reflex ──────────────────────────────────────────────────
|
|
4586
|
+
const reflexCmd = new Command('reflex')
|
|
4587
|
+
.description('Brain Reflex — local-model inline next-line completion');
|
|
4588
|
+
reflexCmd.addCommand(new Command('complete')
|
|
4589
|
+
.description('Complete a code snippet')
|
|
4590
|
+
.requiredOption('--prefix <p>', 'Prefix code to complete')
|
|
4591
|
+
.option('--language <l>', 'Language hint', 'typescript')
|
|
4592
|
+
.option('--project <name>', 'Project name', 'default')
|
|
4593
|
+
.option('--max-tokens <n>', 'Max tokens', '128')
|
|
4594
|
+
.action(async (opts) => {
|
|
4595
|
+
const { getBrainReflex } = await import('./brain/brain-reflex.js');
|
|
4596
|
+
const r = await getBrainReflex().complete({ prefix: opts.prefix, language: opts.language, project: opts.project }, { maxTokens: parseInt(opts.maxTokens, 10) });
|
|
4597
|
+
console.log(chalk.dim(` source: ${r.source} latency: ${r.latencyMs}ms citations: ${r.citations.join(', ')}\n`));
|
|
4598
|
+
console.log(r.completion);
|
|
4599
|
+
}));
|
|
4600
|
+
reflexCmd.addCommand(new Command('precache')
|
|
4601
|
+
.description('Warm brain memories before a session')
|
|
4602
|
+
.option('--project <name>', 'Project name', 'default')
|
|
4603
|
+
.option('--files <csv>', 'Comma-separated file paths', '')
|
|
4604
|
+
.action(async (opts) => {
|
|
4605
|
+
const { getBrainReflex } = await import('./brain/brain-reflex.js');
|
|
4606
|
+
const files = opts.files.split(',').map((s) => s.trim()).filter((x) => x);
|
|
4607
|
+
const r = await getBrainReflex().precache(opts.project, files);
|
|
4608
|
+
console.log(chalk.green(` ✓ cached ${r.cached} memories in ${r.durationMs}ms`));
|
|
4609
|
+
}));
|
|
4610
|
+
// ── 🔥 Brain Roast ───────────────────────────────────────────────────
|
|
4611
|
+
const roastCmd = new Command('roast')
|
|
4612
|
+
.description('Brain Roast — comedy code review (6 personas)')
|
|
4613
|
+
.option('--project <name>', 'Project name', 'default')
|
|
4614
|
+
.option('--persona <p>', 'gordon-ramsay|simon-cowell|mom|comedian|critic|philosopher', 'gordon-ramsay')
|
|
4615
|
+
.option('--intensity <i>', 'gentle|medium|savage', 'medium')
|
|
4616
|
+
.option('--svg <path>', 'Save roast card SVG')
|
|
4617
|
+
.action(async (opts) => {
|
|
4618
|
+
const { getBrainRoast } = await import('./brain/brain-roast.js');
|
|
4619
|
+
const r = await getBrainRoast().roast(opts.project, { persona: opts.persona, intensity: opts.intensity });
|
|
4620
|
+
console.log(chalk.magenta.bold(`\n ROAST · ${r.persona} · ${r.intensity} · grade ${r.grade}\n`));
|
|
4621
|
+
for (const line of r.lines)
|
|
4622
|
+
console.log(' ' + line);
|
|
4623
|
+
if (opts.svg) {
|
|
4624
|
+
const card = await getBrainRoast().roastCard(r);
|
|
4625
|
+
fs.writeFileSync(opts.svg, card.svg);
|
|
4626
|
+
console.log(chalk.green(`\n ✓ card written to ${opts.svg}`));
|
|
4627
|
+
}
|
|
4628
|
+
});
|
|
4629
|
+
// ── 🔮 Brain Tarot ───────────────────────────────────────────────────
|
|
4630
|
+
const tarotCmd = new Command('tarot')
|
|
4631
|
+
.description('Brain Tarot — 78-card divination from your codebase');
|
|
4632
|
+
tarotCmd.addCommand(new Command('draw')
|
|
4633
|
+
.description('Draw a reading')
|
|
4634
|
+
.option('--project <name>', 'Project name', 'default')
|
|
4635
|
+
.option('--spread <s>', 'one-card|three-card|celtic-cross', 'three-card')
|
|
4636
|
+
.option('--question <q>', 'Optional question')
|
|
4637
|
+
.option('--svg <path>', 'Save reading SVG')
|
|
4638
|
+
.action(async (opts) => {
|
|
4639
|
+
const { getBrainTarot } = await import('./brain/brain-tarot.js');
|
|
4640
|
+
const r = await getBrainTarot().draw(opts.project, { spread: opts.spread, question: opts.question });
|
|
4641
|
+
console.log(chalk.magenta.bold(`\n TAROT · ${r.spread}\n`));
|
|
4642
|
+
for (const c of r.cards) {
|
|
4643
|
+
console.log(` ${chalk.cyan(c.name.padEnd(28))} (${c.orientation}) ${chalk.dim(c.position)}`);
|
|
4644
|
+
console.log(` ${chalk.dim(c.meaning)}`);
|
|
4645
|
+
}
|
|
4646
|
+
console.log('\n ' + r.synthesis);
|
|
4647
|
+
if (r.advice)
|
|
4648
|
+
console.log('\n ' + chalk.yellow('Advice: ') + r.advice);
|
|
4649
|
+
if (opts.svg) {
|
|
4650
|
+
fs.writeFileSync(opts.svg, r.svg);
|
|
4651
|
+
console.log(chalk.green(`\n ✓ reading written to ${opts.svg}`));
|
|
4652
|
+
}
|
|
4653
|
+
}));
|
|
4654
|
+
// ── 🎨 Brain ASCII ───────────────────────────────────────────────────
|
|
4655
|
+
const asciiCmd = new Command('ascii')
|
|
4656
|
+
.description('Brain ASCII — terminal-art brain visualizations');
|
|
4657
|
+
asciiCmd.addCommand(new Command('render')
|
|
4658
|
+
.description('Render brain as ASCII art')
|
|
4659
|
+
.option('--project <name>', 'Project name', 'default')
|
|
4660
|
+
.option('--style <s>', 'galaxy|tree|matrix|pixel|banner|sparkline', 'galaxy')
|
|
4661
|
+
.option('--width <w>', 'Width', '80')
|
|
4662
|
+
.option('--height <h>', 'Height', '20')
|
|
4663
|
+
.action(async (opts) => {
|
|
4664
|
+
const { getBrainAscii } = await import('./brain/brain-ascii.js');
|
|
4665
|
+
const out = await getBrainAscii().render(opts.project, {
|
|
4666
|
+
style: opts.style,
|
|
4667
|
+
width: parseInt(opts.width, 10),
|
|
4668
|
+
height: parseInt(opts.height, 10),
|
|
4669
|
+
});
|
|
4670
|
+
console.log(out);
|
|
4671
|
+
}));
|
|
4672
|
+
asciiCmd.addCommand(new Command('sparkline')
|
|
4673
|
+
.description('Activity sparkline over the last N days')
|
|
4674
|
+
.option('--project <name>', 'Project name', 'default')
|
|
4675
|
+
.option('--days <n>', 'Days', '30')
|
|
4676
|
+
.action(async (opts) => {
|
|
4677
|
+
const { getBrainAscii } = await import('./brain/brain-ascii.js');
|
|
4678
|
+
const s = await getBrainAscii().dailySparkline(opts.project, parseInt(opts.days, 10));
|
|
4679
|
+
console.log(s);
|
|
4680
|
+
}));
|
|
4681
|
+
asciiCmd.addCommand(new Command('mascot')
|
|
4682
|
+
.description('ASCII mascot for an archetype')
|
|
4683
|
+
.option('--archetype <a>', 'Archetype name')
|
|
4684
|
+
.action(async (opts) => {
|
|
4685
|
+
const { getBrainAscii } = await import('./brain/brain-ascii.js');
|
|
4686
|
+
console.log(getBrainAscii().mascot(opts.archetype));
|
|
4687
|
+
}));
|
|
4688
|
+
// ── 😂 Brain Memes ───────────────────────────────────────────────────
|
|
4689
|
+
const memesCmd = new Command('memes')
|
|
4690
|
+
.description('Brain Memes — auto-generated dev memes from brain patterns');
|
|
4691
|
+
memesCmd.addCommand(new Command('generate')
|
|
4692
|
+
.description('Generate one or more memes')
|
|
4693
|
+
.option('--project <name>', 'Project name', 'default')
|
|
4694
|
+
.option('--template <t>', 'Specific template (else random)')
|
|
4695
|
+
.option('--count <n>', 'How many', '5')
|
|
4696
|
+
.option('--save', 'Save SVGs to disk')
|
|
4697
|
+
.action(async (opts) => {
|
|
4698
|
+
const { getBrainMemes } = await import('./brain/brain-memes.js');
|
|
4699
|
+
const results = await getBrainMemes().generate(opts.project, {
|
|
4700
|
+
template: opts.template,
|
|
4701
|
+
count: parseInt(opts.count, 10),
|
|
4702
|
+
save: opts.save,
|
|
4703
|
+
});
|
|
4704
|
+
for (const m of results) {
|
|
4705
|
+
console.log(` ${chalk.cyan(m.template.padEnd(28))}`);
|
|
4706
|
+
console.log(` TOP: ${m.topText}`);
|
|
4707
|
+
console.log(` BOT: ${m.bottomText}`);
|
|
4708
|
+
if (m.sharePath)
|
|
4709
|
+
console.log(` ${chalk.dim(m.sharePath)}`);
|
|
4710
|
+
}
|
|
4711
|
+
}));
|
|
4712
|
+
memesCmd.addCommand(new Command('templates')
|
|
4713
|
+
.description('List meme templates')
|
|
4714
|
+
.action(async () => {
|
|
4715
|
+
const { getBrainMemes } = await import('./brain/brain-memes.js');
|
|
4716
|
+
for (const t of getBrainMemes().listTemplates())
|
|
4717
|
+
console.log(` • ${t}`);
|
|
4718
|
+
}));
|
|
4719
|
+
// ── 🌌 Brain 3D ──────────────────────────────────────────────────────
|
|
4720
|
+
const brain3dCmd = new Command('brain-3d')
|
|
4721
|
+
.description('Brain 3D — rotatable 3D graph viewer (Three.js)');
|
|
4722
|
+
brain3dCmd.addCommand(new Command('export')
|
|
4723
|
+
.description('Export scene as JSON / glTF / HTML viewer')
|
|
4724
|
+
.option('--project <name>', 'Project name', 'default')
|
|
4725
|
+
.option('--layout <l>', 'force-directed|sphere|helix|galaxy', 'force-directed')
|
|
4726
|
+
.option('--format <f>', 'json|gltf|html', 'html')
|
|
4727
|
+
.option('--out <path>', 'Output path')
|
|
4728
|
+
.action(async (opts) => {
|
|
4729
|
+
const { getBrain3d } = await import('./brain/brain-3d.js');
|
|
4730
|
+
const scene = await getBrain3d().exportScene(opts.project, { layout: opts.layout });
|
|
4731
|
+
let payload;
|
|
4732
|
+
if (opts.format === 'gltf')
|
|
4733
|
+
payload = getBrain3d().glTfExport(scene);
|
|
4734
|
+
else if (opts.format === 'html')
|
|
4735
|
+
payload = getBrain3d().htmlViewer(scene);
|
|
4736
|
+
else
|
|
4737
|
+
payload = JSON.stringify(scene, null, 2);
|
|
4738
|
+
if (opts.out) {
|
|
4739
|
+
fs.writeFileSync(opts.out, payload);
|
|
4740
|
+
console.log(chalk.green(` ✓ ${opts.out} (${scene.nodes.length} nodes, ${scene.edges.length} edges)`));
|
|
4741
|
+
}
|
|
4742
|
+
else
|
|
4743
|
+
process.stdout.write(payload);
|
|
4744
|
+
}));
|
|
4745
|
+
// ── 💞 Brain Doppelganger ────────────────────────────────────────────
|
|
4746
|
+
const doppelgangerCmd = new Command('doppelganger')
|
|
4747
|
+
.description('Brain Doppelganger — find your codebase\'s twin');
|
|
4748
|
+
doppelgangerCmd.addCommand(new Command('find')
|
|
4749
|
+
.description('Find similar projects')
|
|
4750
|
+
.option('--project <name>', 'Project name', 'default')
|
|
4751
|
+
.option('--pool <p>', 'local|exchange|all', 'local')
|
|
4752
|
+
.option('--top <n>', 'Top K', '5')
|
|
4753
|
+
.action(async (opts) => {
|
|
4754
|
+
const { getBrainDoppelganger } = await import('./brain/brain-doppelganger.js');
|
|
4755
|
+
const matches = await getBrainDoppelganger().findMatches(opts.project, {
|
|
4756
|
+
pool: opts.pool,
|
|
4757
|
+
topK: parseInt(opts.top, 10),
|
|
4758
|
+
});
|
|
4759
|
+
for (const m of matches) {
|
|
4760
|
+
console.log(` ${chalk.cyan((m.similarity * 100).toFixed(0) + '%').padEnd(14)} ${m.otherProject}`);
|
|
4761
|
+
console.log(` ${chalk.dim(m.blurb)}`);
|
|
4762
|
+
}
|
|
4763
|
+
if (!matches.length)
|
|
4764
|
+
console.log(chalk.dim(' No matches found.'));
|
|
4765
|
+
}));
|
|
4766
|
+
doppelgangerCmd.addCommand(new Command('card')
|
|
4767
|
+
.description('Compatibility share card for two projects')
|
|
4768
|
+
.requiredOption('--mine <p>', 'Your project name')
|
|
4769
|
+
.requiredOption('--other <p>', 'Other project name')
|
|
4770
|
+
.option('--out <path>', 'Output SVG path')
|
|
4771
|
+
.action(async (opts) => {
|
|
4772
|
+
const { getBrainDoppelganger } = await import('./brain/brain-doppelganger.js');
|
|
4773
|
+
const { svg } = await getBrainDoppelganger().compatibilityCard(opts.mine, opts.other);
|
|
4774
|
+
if (opts.out) {
|
|
4775
|
+
fs.writeFileSync(opts.out, svg);
|
|
4776
|
+
console.log(chalk.green(` ✓ ${opts.out}`));
|
|
4777
|
+
}
|
|
4778
|
+
else
|
|
4779
|
+
process.stdout.write(svg);
|
|
4780
|
+
}));
|
|
4781
|
+
program.addCommand(cinemaCmd);
|
|
4782
|
+
program.addCommand(sonifyCmd);
|
|
4783
|
+
program.addCommand(trophiesCmd);
|
|
4784
|
+
program.addCommand(holidayCmd);
|
|
4785
|
+
program.addCommand(coachCmd);
|
|
4786
|
+
program.addCommand(questCmd);
|
|
4787
|
+
program.addCommand(notebookCmd);
|
|
4788
|
+
program.addCommand(reflexCmd);
|
|
4789
|
+
program.addCommand(roastCmd);
|
|
4790
|
+
program.addCommand(tarotCmd);
|
|
4791
|
+
program.addCommand(asciiCmd);
|
|
4792
|
+
program.addCommand(memesCmd);
|
|
4793
|
+
program.addCommand(brain3dCmd);
|
|
4794
|
+
program.addCommand(doppelgangerCmd);
|
|
3916
4795
|
program.parse();
|
|
3917
4796
|
//# sourceMappingURL=cli.js.map
|