magi-ai 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.ja.md +377 -0
- package/README.md +377 -0
- package/dist/bin/magi-benchmark.d.ts +14 -0
- package/dist/bin/magi-benchmark.js +93 -0
- package/dist/bin/magi-mcp.d.ts +8 -0
- package/dist/bin/magi-mcp.js +28 -0
- package/dist/bin/magi.d.ts +2 -0
- package/dist/bin/magi.js +634 -0
- package/dist/src/adapters/base.d.ts +34 -0
- package/dist/src/adapters/base.js +149 -0
- package/dist/src/adapters/claude.d.ts +29 -0
- package/dist/src/adapters/claude.js +65 -0
- package/dist/src/adapters/codex.d.ts +21 -0
- package/dist/src/adapters/codex.js +41 -0
- package/dist/src/adapters/gemini.d.ts +18 -0
- package/dist/src/adapters/gemini.js +31 -0
- package/dist/src/adapters/registry.d.ts +19 -0
- package/dist/src/adapters/registry.js +59 -0
- package/dist/src/audit/hash-chain.d.ts +21 -0
- package/dist/src/audit/hash-chain.js +70 -0
- package/dist/src/audit/types.d.ts +25 -0
- package/dist/src/audit/types.js +1 -0
- package/dist/src/audit/writer.d.ts +18 -0
- package/dist/src/audit/writer.js +100 -0
- package/dist/src/benchmark/golden-tasks.d.ts +9 -0
- package/dist/src/benchmark/golden-tasks.js +476 -0
- package/dist/src/benchmark/reporter.d.ts +5 -0
- package/dist/src/benchmark/reporter.js +107 -0
- package/dist/src/benchmark/runner.d.ts +30 -0
- package/dist/src/benchmark/runner.js +224 -0
- package/dist/src/benchmark/scorer.d.ts +12 -0
- package/dist/src/benchmark/scorer.js +124 -0
- package/dist/src/benchmark/types.d.ts +54 -0
- package/dist/src/benchmark/types.js +1 -0
- package/dist/src/cache/deliberation-cache.d.ts +49 -0
- package/dist/src/cache/deliberation-cache.js +127 -0
- package/dist/src/cli/commands/config-cmd.d.ts +11 -0
- package/dist/src/cli/commands/config-cmd.js +190 -0
- package/dist/src/cli/commands/demo.d.ts +12 -0
- package/dist/src/cli/commands/demo.js +66 -0
- package/dist/src/cli/commands/setup.d.ts +7 -0
- package/dist/src/cli/commands/setup.js +182 -0
- package/dist/src/cli/i18n.d.ts +89 -0
- package/dist/src/cli/i18n.js +176 -0
- package/dist/src/cli/interactive-select.d.ts +27 -0
- package/dist/src/cli/interactive-select.js +130 -0
- package/dist/src/cli/tui-setup.d.ts +24 -0
- package/dist/src/cli/tui-setup.js +42 -0
- package/dist/src/config/cli-detector.d.ts +37 -0
- package/dist/src/config/cli-detector.js +99 -0
- package/dist/src/config/user-config.d.ts +81 -0
- package/dist/src/config/user-config.js +134 -0
- package/dist/src/context/auto-collector.d.ts +43 -0
- package/dist/src/context/auto-collector.js +337 -0
- package/dist/src/context/manager.d.ts +35 -0
- package/dist/src/context/manager.js +162 -0
- package/dist/src/context/serializer.d.ts +20 -0
- package/dist/src/context/serializer.js +52 -0
- package/dist/src/demo/recorded-deliberation.d.ts +13 -0
- package/dist/src/demo/recorded-deliberation.js +277 -0
- package/dist/src/engine/angel-detector.d.ts +83 -0
- package/dist/src/engine/angel-detector.js +334 -0
- package/dist/src/engine/at-field.d.ts +40 -0
- package/dist/src/engine/at-field.js +195 -0
- package/dist/src/engine/berserk-orchestrator.d.ts +66 -0
- package/dist/src/engine/berserk-orchestrator.js +378 -0
- package/dist/src/engine/change-metrics.d.ts +56 -0
- package/dist/src/engine/change-metrics.js +214 -0
- package/dist/src/engine/consensus.d.ts +20 -0
- package/dist/src/engine/consensus.js +146 -0
- package/dist/src/engine/dead-sea-scrolls.d.ts +132 -0
- package/dist/src/engine/dead-sea-scrolls.js +610 -0
- package/dist/src/engine/drift-detector.d.ts +39 -0
- package/dist/src/engine/drift-detector.js +225 -0
- package/dist/src/engine/dummy-plug.d.ts +44 -0
- package/dist/src/engine/dummy-plug.js +190 -0
- package/dist/src/engine/engram-manager.d.ts +55 -0
- package/dist/src/engine/engram-manager.js +306 -0
- package/dist/src/engine/events.d.ts +130 -0
- package/dist/src/engine/events.js +44 -0
- package/dist/src/engine/gospel.d.ts +30 -0
- package/dist/src/engine/gospel.js +129 -0
- package/dist/src/engine/hallucination-detector.d.ts +33 -0
- package/dist/src/engine/hallucination-detector.js +215 -0
- package/dist/src/engine/human-resolver.d.ts +19 -0
- package/dist/src/engine/human-resolver.js +89 -0
- package/dist/src/engine/instrumentality.d.ts +64 -0
- package/dist/src/engine/instrumentality.js +297 -0
- package/dist/src/engine/iruel-battle.d.ts +79 -0
- package/dist/src/engine/iruel-battle.js +319 -0
- package/dist/src/engine/kernel/deliberation-kernel.d.ts +12 -0
- package/dist/src/engine/kernel/deliberation-kernel.js +303 -0
- package/dist/src/engine/kernel/index.d.ts +8 -0
- package/dist/src/engine/kernel/index.js +7 -0
- package/dist/src/engine/kernel/phase-runner.d.ts +10 -0
- package/dist/src/engine/kernel/phase-runner.js +155 -0
- package/dist/src/engine/kernel/post-processor.d.ts +17 -0
- package/dist/src/engine/kernel/post-processor.js +131 -0
- package/dist/src/engine/kernel/types.d.ts +107 -0
- package/dist/src/engine/kernel/types.js +1 -0
- package/dist/src/engine/kernel/unit-executor.d.ts +6 -0
- package/dist/src/engine/kernel/unit-executor.js +132 -0
- package/dist/src/engine/lcl-manager.d.ts +44 -0
- package/dist/src/engine/lcl-manager.js +143 -0
- package/dist/src/engine/middleware/cache.d.ts +7 -0
- package/dist/src/engine/middleware/cache.js +29 -0
- package/dist/src/engine/middleware/chain.d.ts +18 -0
- package/dist/src/engine/middleware/chain.js +45 -0
- package/dist/src/engine/middleware/firewall.d.ts +8 -0
- package/dist/src/engine/middleware/firewall.js +24 -0
- package/dist/src/engine/middleware/index.d.ts +4 -0
- package/dist/src/engine/middleware/index.js +3 -0
- package/dist/src/engine/middleware/types.d.ts +43 -0
- package/dist/src/engine/middleware/types.js +1 -0
- package/dist/src/engine/nebuchadnezzar-key.d.ts +61 -0
- package/dist/src/engine/nebuchadnezzar-key.js +203 -0
- package/dist/src/engine/neon-genesis.d.ts +52 -0
- package/dist/src/engine/neon-genesis.js +203 -0
- package/dist/src/engine/objective-judge.d.ts +53 -0
- package/dist/src/engine/objective-judge.js +214 -0
- package/dist/src/engine/offline-mode.d.ts +18 -0
- package/dist/src/engine/offline-mode.js +46 -0
- package/dist/src/engine/orchestrator.d.ts +79 -0
- package/dist/src/engine/orchestrator.js +58 -0
- package/dist/src/engine/secret-cipher.d.ts +26 -0
- package/dist/src/engine/secret-cipher.js +114 -0
- package/dist/src/engine/seele-council.d.ts +90 -0
- package/dist/src/engine/seele-council.js +482 -0
- package/dist/src/engine/self-destruct.d.ts +61 -0
- package/dist/src/engine/self-destruct.js +231 -0
- package/dist/src/engine/self-evolution.d.ts +64 -0
- package/dist/src/engine/self-evolution.js +368 -0
- package/dist/src/engine/sync-rate.d.ts +45 -0
- package/dist/src/engine/sync-rate.js +151 -0
- package/dist/src/engine/type666-firewall.d.ts +76 -0
- package/dist/src/engine/type666-firewall.js +343 -0
- package/dist/src/engine/umbilical-cable.d.ts +41 -0
- package/dist/src/engine/umbilical-cable.js +192 -0
- package/dist/src/index.d.ts +106 -0
- package/dist/src/index.js +426 -0
- package/dist/src/mcp/server.d.ts +38 -0
- package/dist/src/mcp/server.js +196 -0
- package/dist/src/metrics/token-tracker.d.ts +38 -0
- package/dist/src/metrics/token-tracker.js +112 -0
- package/dist/src/parsers/json-extractor.d.ts +9 -0
- package/dist/src/parsers/json-extractor.js +239 -0
- package/dist/src/parsers/opinion-schema.d.ts +81 -0
- package/dist/src/parsers/opinion-schema.js +147 -0
- package/dist/src/parsers/unstructured-parser.d.ts +20 -0
- package/dist/src/parsers/unstructured-parser.js +122 -0
- package/dist/src/pipelines/architecture.d.ts +10 -0
- package/dist/src/pipelines/architecture.js +9 -0
- package/dist/src/pipelines/bug-analysis.d.ts +9 -0
- package/dist/src/pipelines/bug-analysis.js +8 -0
- package/dist/src/pipelines/code-review.d.ts +10 -0
- package/dist/src/pipelines/code-review.js +30 -0
- package/dist/src/pipelines/custom.d.ts +14 -0
- package/dist/src/pipelines/custom.js +29 -0
- package/dist/src/pipelines/registry.d.ts +9 -0
- package/dist/src/pipelines/registry.js +20 -0
- package/dist/src/prompts/personas.d.ts +6 -0
- package/dist/src/prompts/personas.js +44 -0
- package/dist/src/prompts/schemas.d.ts +4 -0
- package/dist/src/prompts/schemas.js +24 -0
- package/dist/src/prompts/templates.d.ts +6 -0
- package/dist/src/prompts/templates.js +91 -0
- package/dist/src/repl/accessibility.d.ts +23 -0
- package/dist/src/repl/accessibility.js +46 -0
- package/dist/src/repl/banner.d.ts +4 -0
- package/dist/src/repl/banner.js +28 -0
- package/dist/src/repl/boot-animation.d.ts +13 -0
- package/dist/src/repl/boot-animation.js +143 -0
- package/dist/src/repl/completer.d.ts +21 -0
- package/dist/src/repl/completer.js +168 -0
- package/dist/src/repl/context.d.ts +24 -0
- package/dist/src/repl/context.js +42 -0
- package/dist/src/repl/display-utils.d.ts +13 -0
- package/dist/src/repl/display-utils.js +65 -0
- package/dist/src/repl/event-listener.d.ts +18 -0
- package/dist/src/repl/event-listener.js +112 -0
- package/dist/src/repl/export-formatter.d.ts +8 -0
- package/dist/src/repl/export-formatter.js +73 -0
- package/dist/src/repl/ghost-text.d.ts +31 -0
- package/dist/src/repl/ghost-text.js +119 -0
- package/dist/src/repl/handoff-animation.d.ts +15 -0
- package/dist/src/repl/handoff-animation.js +65 -0
- package/dist/src/repl/history.d.ts +16 -0
- package/dist/src/repl/history.js +130 -0
- package/dist/src/repl/job-registry.d.ts +26 -0
- package/dist/src/repl/job-registry.js +80 -0
- package/dist/src/repl/magi-repl.d.ts +72 -0
- package/dist/src/repl/magi-repl.js +1008 -0
- package/dist/src/repl/multiline-input.d.ts +45 -0
- package/dist/src/repl/multiline-input.js +78 -0
- package/dist/src/repl/prompt-builder.d.ts +19 -0
- package/dist/src/repl/prompt-builder.js +36 -0
- package/dist/src/repl/repl-state.d.ts +5 -0
- package/dist/src/repl/repl-state.js +19 -0
- package/dist/src/repl/result-display.d.ts +8 -0
- package/dist/src/repl/result-display.js +195 -0
- package/dist/src/repl/session-stats.d.ts +26 -0
- package/dist/src/repl/session-stats.js +119 -0
- package/dist/src/repl/slash-commands.d.ts +60 -0
- package/dist/src/repl/slash-commands.js +725 -0
- package/dist/src/repl/terminal-sanitize.d.ts +14 -0
- package/dist/src/repl/terminal-sanitize.js +19 -0
- package/dist/src/reporters/console.d.ts +7 -0
- package/dist/src/reporters/console.js +78 -0
- package/dist/src/reporters/json.d.ts +2 -0
- package/dist/src/reporters/json.js +3 -0
- package/dist/src/reporters/markdown.d.ts +2 -0
- package/dist/src/reporters/markdown.js +65 -0
- package/dist/src/reporters/streaming.d.ts +20 -0
- package/dist/src/reporters/streaming.js +178 -0
- package/dist/src/tui/activity-log.d.ts +23 -0
- package/dist/src/tui/activity-log.js +67 -0
- package/dist/src/tui/animations.d.ts +39 -0
- package/dist/src/tui/animations.js +167 -0
- package/dist/src/tui/ansi.d.ts +28 -0
- package/dist/src/tui/ansi.js +51 -0
- package/dist/src/tui/boot-sequence.d.ts +11 -0
- package/dist/src/tui/boot-sequence.js +98 -0
- package/dist/src/tui/colors.d.ts +101 -0
- package/dist/src/tui/colors.js +71 -0
- package/dist/src/tui/header.d.ts +24 -0
- package/dist/src/tui/header.js +122 -0
- package/dist/src/tui/index.d.ts +3 -0
- package/dist/src/tui/index.js +3 -0
- package/dist/src/tui/keypress.d.ts +25 -0
- package/dist/src/tui/keypress.js +95 -0
- package/dist/src/tui/layout.d.ts +74 -0
- package/dist/src/tui/layout.js +171 -0
- package/dist/src/tui/magi-tui.d.ts +101 -0
- package/dist/src/tui/magi-tui.js +754 -0
- package/dist/src/tui/panel.d.ts +45 -0
- package/dist/src/tui/panel.js +292 -0
- package/dist/src/tui/screen-buffer.d.ts +54 -0
- package/dist/src/tui/screen-buffer.js +262 -0
- package/dist/src/tui/status-bar.d.ts +25 -0
- package/dist/src/tui/status-bar.js +124 -0
- package/dist/src/tui/terminal-detect.d.ts +26 -0
- package/dist/src/tui/terminal-detect.js +44 -0
- package/dist/src/tui/tui-helpers.d.ts +12 -0
- package/dist/src/tui/tui-helpers.js +37 -0
- package/dist/src/types/adapter.d.ts +75 -0
- package/dist/src/types/adapter.js +36 -0
- package/dist/src/types/config.d.ts +108 -0
- package/dist/src/types/config.js +85 -0
- package/dist/src/types/consensus.d.ts +55 -0
- package/dist/src/types/consensus.js +17 -0
- package/dist/src/types/core.d.ts +178 -0
- package/dist/src/types/core.js +85 -0
- package/dist/src/types/magi-api.d.ts +62 -0
- package/dist/src/types/magi-api.js +7 -0
- package/dist/src/types/phase-h.d.ts +142 -0
- package/dist/src/types/phase-h.js +7 -0
- package/dist/src/types/phase-i.d.ts +186 -0
- package/dist/src/types/phase-i.js +6 -0
- package/dist/src/types/phase-k.d.ts +259 -0
- package/dist/src/types/phase-k.js +6 -0
- package/dist/src/types/phase-l.d.ts +199 -0
- package/dist/src/types/phase-l.js +6 -0
- package/dist/src/types/pipeline.d.ts +37 -0
- package/dist/src/types/pipeline.js +2 -0
- package/dist/src/utils/abstain-factory.d.ts +2 -0
- package/dist/src/utils/abstain-factory.js +18 -0
- package/dist/src/utils/errors.d.ts +34 -0
- package/dist/src/utils/errors.js +59 -0
- package/dist/src/utils/file-validator.d.ts +50 -0
- package/dist/src/utils/file-validator.js +124 -0
- package/dist/src/utils/fire-and-forget.d.ts +5 -0
- package/dist/src/utils/fire-and-forget.js +10 -0
- package/dist/src/utils/flag-validator.d.ts +21 -0
- package/dist/src/utils/flag-validator.js +79 -0
- package/dist/src/utils/freeze.d.ts +8 -0
- package/dist/src/utils/freeze.js +16 -0
- package/dist/src/utils/language-detector.d.ts +16 -0
- package/dist/src/utils/language-detector.js +159 -0
- package/dist/src/utils/latency-tracker.d.ts +45 -0
- package/dist/src/utils/latency-tracker.js +100 -0
- package/dist/src/utils/logger.d.ts +33 -0
- package/dist/src/utils/logger.js +112 -0
- package/dist/src/utils/process.d.ts +40 -0
- package/dist/src/utils/process.js +253 -0
- package/dist/src/utils/retry.d.ts +12 -0
- package/dist/src/utils/retry.js +30 -0
- package/dist/src/utils/safe-fs.d.ts +38 -0
- package/dist/src/utils/safe-fs.js +56 -0
- package/dist/src/utils/safe-json-parse.d.ts +15 -0
- package/dist/src/utils/safe-json-parse.js +49 -0
- package/dist/src/utils/sanitize.d.ts +14 -0
- package/dist/src/utils/sanitize.js +186 -0
- package/dist/src/utils/semaphore.d.ts +22 -0
- package/dist/src/utils/semaphore.js +57 -0
- package/dist/src/utils/shutdown.d.ts +6 -0
- package/dist/src/utils/shutdown.js +51 -0
- package/dist/src/utils/tty.d.ts +5 -0
- package/dist/src/utils/tty.js +7 -0
- package/package.json +82 -0
package/dist/bin/magi.js
ADDED
|
@@ -0,0 +1,634 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { Command, Option } from 'commander';
|
|
3
|
+
import chalk from 'chalk';
|
|
4
|
+
import { randomBytes } from 'node:crypto';
|
|
5
|
+
import { createInterface } from 'node:readline/promises';
|
|
6
|
+
import { readFile } from 'node:fs/promises';
|
|
7
|
+
import { Magi } from '../src/index.js';
|
|
8
|
+
import { printDeliberation, printHeader } from '../src/reporters/console.js';
|
|
9
|
+
import { initializeTui } from '../src/cli/tui-setup.js';
|
|
10
|
+
import { formatDeliberationJson } from '../src/reporters/json.js';
|
|
11
|
+
import { formatDeliberationMarkdown } from '../src/reporters/markdown.js';
|
|
12
|
+
import { setupGracefulShutdown } from '../src/utils/shutdown.js';
|
|
13
|
+
import { loadUserConfigSafe, mergeWithDefaults } from '../src/config/user-config.js';
|
|
14
|
+
import { setLocale, detectLocale } from '../src/cli/i18n.js';
|
|
15
|
+
import { validateFile } from '../src/utils/file-validator.js';
|
|
16
|
+
import { detectLanguage } from '../src/utils/language-detector.js';
|
|
17
|
+
import { collectProjectContext, collectRelatedFiles } from '../src/context/auto-collector.js';
|
|
18
|
+
setupGracefulShutdown();
|
|
19
|
+
// ── CLI confirmation helper ──────────────────────────────────────
|
|
20
|
+
async function confirmDestructiveAction(description) {
|
|
21
|
+
if (!process.stdin.isTTY) {
|
|
22
|
+
console.error(chalk.red(' Error: TTY required for destructive operations. Use --force for non-interactive mode.'));
|
|
23
|
+
return false;
|
|
24
|
+
}
|
|
25
|
+
const token = `yes-${randomBytes(2).toString('hex')}`;
|
|
26
|
+
console.log(description);
|
|
27
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
28
|
+
const ac = new AbortController();
|
|
29
|
+
const timer = setTimeout(() => ac.abort(), 30_000);
|
|
30
|
+
try {
|
|
31
|
+
const answer = await rl.question(chalk.dim(` 続行するには "${token}" と入力してください (30秒でタイムアウト): `), { signal: ac.signal });
|
|
32
|
+
return answer.trim() === token;
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
console.log(chalk.dim(' タイムアウトまたはキャンセルされました。'));
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
38
|
+
finally {
|
|
39
|
+
clearTimeout(timer);
|
|
40
|
+
rl.close();
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
// ── User config loading ──────────────────────────────────────────
|
|
44
|
+
let cachedUserConfig;
|
|
45
|
+
let cachedMagiConfig;
|
|
46
|
+
/** Load raw user config (includes tui/language). Initializes locale on first load. */
|
|
47
|
+
async function getRawUserConfig() {
|
|
48
|
+
if (cachedUserConfig !== undefined)
|
|
49
|
+
return cachedUserConfig;
|
|
50
|
+
cachedUserConfig = (await loadUserConfigSafe()) ?? undefined;
|
|
51
|
+
// Apply language setting globally for i18n
|
|
52
|
+
setLocale(cachedUserConfig?.language ?? detectLocale());
|
|
53
|
+
return cachedUserConfig;
|
|
54
|
+
}
|
|
55
|
+
async function getUserConfig() {
|
|
56
|
+
if (cachedMagiConfig !== undefined)
|
|
57
|
+
return cachedMagiConfig;
|
|
58
|
+
const raw = await getRawUserConfig();
|
|
59
|
+
cachedMagiConfig = raw ? mergeWithDefaults(raw) : undefined;
|
|
60
|
+
return cachedMagiConfig;
|
|
61
|
+
}
|
|
62
|
+
/** Build Magi config by merging user config with command-level overrides. */
|
|
63
|
+
async function buildMagiConfig(overrides = {}) {
|
|
64
|
+
const base = await getUserConfig();
|
|
65
|
+
return { ...base, ...overrides };
|
|
66
|
+
}
|
|
67
|
+
/** Resolve TUI enabled: CLI flag overrides user config, default true. */
|
|
68
|
+
async function resolveTuiEnabled(cliFlag) {
|
|
69
|
+
// Commander sets opts.tui=false only when --no-tui is explicitly passed
|
|
70
|
+
if (!cliFlag)
|
|
71
|
+
return false;
|
|
72
|
+
const raw = await getRawUserConfig();
|
|
73
|
+
return raw?.tui?.enabled ?? true;
|
|
74
|
+
}
|
|
75
|
+
/** Resolve sound enabled: CLI flag overrides user config. */
|
|
76
|
+
async function resolveSoundEnabled(cliFlag) {
|
|
77
|
+
if (cliFlag !== undefined)
|
|
78
|
+
return cliFlag;
|
|
79
|
+
const raw = await getRawUserConfig();
|
|
80
|
+
return raw?.tui?.soundEnabled ?? false;
|
|
81
|
+
}
|
|
82
|
+
const program = new Command();
|
|
83
|
+
program
|
|
84
|
+
.name('magi')
|
|
85
|
+
.description('MAGI System - Multi-AI CLI Deliberation Framework')
|
|
86
|
+
.version('0.1.0');
|
|
87
|
+
program
|
|
88
|
+
.command('deliberate')
|
|
89
|
+
.description('Start a MAGI deliberation on a topic')
|
|
90
|
+
.argument('<prompt>', 'The topic or question to deliberate')
|
|
91
|
+
.addOption(new Option('-t, --type <type>', 'Task type').default('custom')
|
|
92
|
+
.choices(['code-review', 'architecture-decision', 'bug-analysis', 'implementation-plan', 'security-audit', 'custom']))
|
|
93
|
+
.option('-r, --rounds <n>', 'Maximum rounds', '3')
|
|
94
|
+
.option('-o, --output <format>', 'Output format: console, json, markdown', 'console')
|
|
95
|
+
.option('--no-cross-exam', 'Skip cross-examination phase')
|
|
96
|
+
.option('--no-cache', 'Disable result caching')
|
|
97
|
+
.addOption(new Option('--deadlock <strategy>', 'Deadlock strategy')
|
|
98
|
+
.choices(['escalate', 'melchior-tiebreak', 'highest-confidence', 'human-in-the-loop']))
|
|
99
|
+
.option('--no-tui', 'Disable Evangelion-themed full-screen TUI mode')
|
|
100
|
+
.option('--sound', 'Enable terminal bell for MAGI TUI events')
|
|
101
|
+
.option('--berserk', 'Enable BERSERK mode (5 strategies × 3 units, unanimous deathmatch)')
|
|
102
|
+
.option('--no-auto-context', 'Disable automatic project context collection')
|
|
103
|
+
.option('--file-access', 'Allow CLIs to read project files during deliberation')
|
|
104
|
+
.action(async (prompt, opts) => {
|
|
105
|
+
const fileAccess = opts.fileAccess ? { enabled: true } : undefined;
|
|
106
|
+
const magiConfig = await buildMagiConfig({ logLevel: 'warn', cacheEnabled: opts.cache, ...(fileAccess && { fileAccess }) });
|
|
107
|
+
const magi = new Magi(magiConfig);
|
|
108
|
+
const tuiEnabled = await resolveTuiEnabled(opts.tui);
|
|
109
|
+
const soundEnabled = await resolveSoundEnabled(opts.sound);
|
|
110
|
+
const { tuiInstance } = await initializeTui(magi.getEventBus(), tuiEnabled, { soundEnabled });
|
|
111
|
+
// Collect project context if enabled
|
|
112
|
+
let context;
|
|
113
|
+
if (opts.autoContext) {
|
|
114
|
+
try {
|
|
115
|
+
const ctx = await collectProjectContext();
|
|
116
|
+
if (ctx.charCount > 0)
|
|
117
|
+
context = ctx.text;
|
|
118
|
+
}
|
|
119
|
+
catch { /* graceful degradation */ }
|
|
120
|
+
}
|
|
121
|
+
try {
|
|
122
|
+
let result;
|
|
123
|
+
if (opts.berserk) {
|
|
124
|
+
// BERSERK mode: bypass normal orchestrator
|
|
125
|
+
result = await magi.deliberateBerserk({
|
|
126
|
+
type: opts.type,
|
|
127
|
+
title: prompt.slice(0, 80),
|
|
128
|
+
description: prompt,
|
|
129
|
+
context,
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
else {
|
|
133
|
+
const phases = opts.crossExam
|
|
134
|
+
? ['initial-opinion', 'cross-examination', 'final-vote']
|
|
135
|
+
: ['initial-opinion', 'final-vote'];
|
|
136
|
+
const consensusOverride = opts.deadlock
|
|
137
|
+
? { deadlockStrategy: opts.deadlock }
|
|
138
|
+
: undefined;
|
|
139
|
+
const maxRounds = parseInt(opts.rounds, 10);
|
|
140
|
+
if (Number.isNaN(maxRounds) || maxRounds < 1) {
|
|
141
|
+
console.error(chalk.red('\n Error: --rounds must be a positive integer'));
|
|
142
|
+
process.exit(1);
|
|
143
|
+
}
|
|
144
|
+
result = await magi.deliberate({
|
|
145
|
+
type: opts.type,
|
|
146
|
+
title: prompt.slice(0, 80),
|
|
147
|
+
description: prompt,
|
|
148
|
+
context,
|
|
149
|
+
config: {
|
|
150
|
+
maxRounds,
|
|
151
|
+
phases,
|
|
152
|
+
...(consensusOverride && { consensus: consensusOverride }),
|
|
153
|
+
},
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
// Wait for user to see the result, then dispose TUI
|
|
157
|
+
if (tuiInstance)
|
|
158
|
+
await tuiInstance.waitForDismiss();
|
|
159
|
+
tuiInstance?.dispose();
|
|
160
|
+
switch (opts.output) {
|
|
161
|
+
case 'json':
|
|
162
|
+
console.log(formatDeliberationJson(result));
|
|
163
|
+
break;
|
|
164
|
+
case 'markdown':
|
|
165
|
+
console.log(formatDeliberationMarkdown(result));
|
|
166
|
+
break;
|
|
167
|
+
default:
|
|
168
|
+
printDeliberation(result);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
catch (error) {
|
|
172
|
+
tuiInstance?.dispose();
|
|
173
|
+
console.error(chalk.red(`\n Deliberation failed: ${String(error)}`));
|
|
174
|
+
process.exit(1);
|
|
175
|
+
}
|
|
176
|
+
});
|
|
177
|
+
program
|
|
178
|
+
.command('review')
|
|
179
|
+
.description('Code review deliberation')
|
|
180
|
+
.argument('<file>', 'File to review')
|
|
181
|
+
.option('-o, --output <format>', 'Output format', 'console')
|
|
182
|
+
.option('--no-cache', 'Disable result caching')
|
|
183
|
+
.option('--deadlock <strategy>', 'Deadlock strategy')
|
|
184
|
+
.option('--no-tui', 'Disable Evangelion-themed full-screen TUI mode')
|
|
185
|
+
.option('--sound', 'Enable terminal bell for MAGI TUI events')
|
|
186
|
+
.option('--no-auto-context', 'Disable automatic related file collection')
|
|
187
|
+
.option('--file-access', 'Allow CLIs to read project files during deliberation')
|
|
188
|
+
.action(async (file, opts) => {
|
|
189
|
+
// Validate file using shared file-validator
|
|
190
|
+
const validation = await validateFile(file, {
|
|
191
|
+
maxBytes: 524_288, // 512 KiB
|
|
192
|
+
rejectBinary: true,
|
|
193
|
+
});
|
|
194
|
+
if (!validation.ok) {
|
|
195
|
+
console.error(chalk.red(`\n ${validation.error.message}`));
|
|
196
|
+
process.exit(1);
|
|
197
|
+
}
|
|
198
|
+
const content = await readFile(validation.file.absolutePath, 'utf-8');
|
|
199
|
+
const language = detectLanguage(file);
|
|
200
|
+
const fileAccess = opts.fileAccess ? { enabled: true } : undefined;
|
|
201
|
+
const magiConfig = await buildMagiConfig({ logLevel: 'warn', cacheEnabled: opts.cache, ...(fileAccess && { fileAccess }) });
|
|
202
|
+
const magi = new Magi(magiConfig);
|
|
203
|
+
const tuiEnabled = await resolveTuiEnabled(opts.tui);
|
|
204
|
+
const soundEnabled = await resolveSoundEnabled(opts.sound);
|
|
205
|
+
const { tuiInstance } = await initializeTui(magi.getEventBus(), tuiEnabled, { soundEnabled });
|
|
206
|
+
// Collect related files if auto-context enabled
|
|
207
|
+
let relatedArtifacts = [];
|
|
208
|
+
let context;
|
|
209
|
+
if (opts.autoContext) {
|
|
210
|
+
try {
|
|
211
|
+
const [related, projectCtx] = await Promise.allSettled([
|
|
212
|
+
collectRelatedFiles(file, content),
|
|
213
|
+
collectProjectContext(),
|
|
214
|
+
]);
|
|
215
|
+
if (related.status === 'fulfilled')
|
|
216
|
+
relatedArtifacts = related.value;
|
|
217
|
+
if (projectCtx.status === 'fulfilled' && projectCtx.value.charCount > 0) {
|
|
218
|
+
context = projectCtx.value.text;
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
catch { /* graceful degradation */ }
|
|
222
|
+
}
|
|
223
|
+
try {
|
|
224
|
+
const consensusOverride = opts.deadlock
|
|
225
|
+
? { deadlockStrategy: opts.deadlock }
|
|
226
|
+
: undefined;
|
|
227
|
+
const result = await magi.deliberate({
|
|
228
|
+
type: 'code-review',
|
|
229
|
+
title: `Code Review: ${file}`,
|
|
230
|
+
description: `Review the following code file for quality, correctness, security, and best practices.`,
|
|
231
|
+
artifacts: [
|
|
232
|
+
{
|
|
233
|
+
type: 'file',
|
|
234
|
+
path: validation.file.relativePath,
|
|
235
|
+
content,
|
|
236
|
+
language,
|
|
237
|
+
},
|
|
238
|
+
...relatedArtifacts,
|
|
239
|
+
],
|
|
240
|
+
context,
|
|
241
|
+
...(consensusOverride && { config: { consensus: consensusOverride } }),
|
|
242
|
+
});
|
|
243
|
+
// Wait for user to see the result, then dispose TUI
|
|
244
|
+
if (tuiInstance)
|
|
245
|
+
await tuiInstance.waitForDismiss();
|
|
246
|
+
tuiInstance?.dispose();
|
|
247
|
+
switch (opts.output) {
|
|
248
|
+
case 'json':
|
|
249
|
+
console.log(formatDeliberationJson(result));
|
|
250
|
+
break;
|
|
251
|
+
case 'markdown':
|
|
252
|
+
console.log(formatDeliberationMarkdown(result));
|
|
253
|
+
break;
|
|
254
|
+
default:
|
|
255
|
+
printDeliberation(result);
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
catch (error) {
|
|
259
|
+
tuiInstance?.dispose();
|
|
260
|
+
console.error(chalk.red(`\n Review failed: ${String(error)}`));
|
|
261
|
+
process.exit(1);
|
|
262
|
+
}
|
|
263
|
+
});
|
|
264
|
+
program
|
|
265
|
+
.command('decide')
|
|
266
|
+
.description('Architecture decision deliberation')
|
|
267
|
+
.argument('<question>', 'The architecture question to decide')
|
|
268
|
+
.option('-o, --output <format>', 'Output format', 'console')
|
|
269
|
+
.option('--no-cache', 'Disable result caching')
|
|
270
|
+
.option('--deadlock <strategy>', 'Deadlock strategy')
|
|
271
|
+
.option('--no-tui', 'Disable Evangelion-themed full-screen TUI mode')
|
|
272
|
+
.option('--sound', 'Enable terminal bell for MAGI TUI events')
|
|
273
|
+
.option('--no-auto-context', 'Disable automatic project context collection')
|
|
274
|
+
.option('--file-access', 'Allow CLIs to read project files during deliberation')
|
|
275
|
+
.action(async (question, opts) => {
|
|
276
|
+
const fileAccess = opts.fileAccess ? { enabled: true } : undefined;
|
|
277
|
+
const magiConfig = await buildMagiConfig({ logLevel: 'warn', cacheEnabled: opts.cache, ...(fileAccess && { fileAccess }) });
|
|
278
|
+
const magi = new Magi(magiConfig);
|
|
279
|
+
const tuiEnabled = await resolveTuiEnabled(opts.tui);
|
|
280
|
+
const soundEnabled = await resolveSoundEnabled(opts.sound);
|
|
281
|
+
const { tuiInstance } = await initializeTui(magi.getEventBus(), tuiEnabled, { soundEnabled });
|
|
282
|
+
// Collect project context if enabled
|
|
283
|
+
let context;
|
|
284
|
+
if (opts.autoContext) {
|
|
285
|
+
try {
|
|
286
|
+
const ctx = await collectProjectContext();
|
|
287
|
+
if (ctx.charCount > 0)
|
|
288
|
+
context = ctx.text;
|
|
289
|
+
}
|
|
290
|
+
catch { /* graceful degradation */ }
|
|
291
|
+
}
|
|
292
|
+
try {
|
|
293
|
+
const consensusOverride = opts.deadlock
|
|
294
|
+
? { deadlockStrategy: opts.deadlock }
|
|
295
|
+
: undefined;
|
|
296
|
+
const result = await magi.deliberate({
|
|
297
|
+
type: 'architecture-decision',
|
|
298
|
+
title: question.slice(0, 80),
|
|
299
|
+
description: question,
|
|
300
|
+
context,
|
|
301
|
+
...(consensusOverride && { config: { consensus: consensusOverride } }),
|
|
302
|
+
});
|
|
303
|
+
// Wait for user to see the result, then dispose TUI
|
|
304
|
+
if (tuiInstance)
|
|
305
|
+
await tuiInstance.waitForDismiss();
|
|
306
|
+
tuiInstance?.dispose();
|
|
307
|
+
switch (opts.output) {
|
|
308
|
+
case 'json':
|
|
309
|
+
console.log(formatDeliberationJson(result));
|
|
310
|
+
break;
|
|
311
|
+
case 'markdown':
|
|
312
|
+
console.log(formatDeliberationMarkdown(result));
|
|
313
|
+
break;
|
|
314
|
+
default:
|
|
315
|
+
printDeliberation(result);
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
catch (error) {
|
|
319
|
+
tuiInstance?.dispose();
|
|
320
|
+
console.error(chalk.red(`\n Decision failed: ${String(error)}`));
|
|
321
|
+
process.exit(1);
|
|
322
|
+
}
|
|
323
|
+
});
|
|
324
|
+
program
|
|
325
|
+
.command('tokens')
|
|
326
|
+
.description('Show token usage summary for past deliberations')
|
|
327
|
+
.action(async () => {
|
|
328
|
+
printHeader();
|
|
329
|
+
const magi = new Magi(await buildMagiConfig({ logLevel: 'error' }));
|
|
330
|
+
const summaries = await magi.loadAllTokens();
|
|
331
|
+
if (summaries.length === 0) {
|
|
332
|
+
console.log(chalk.yellow(' No token data found.\n'));
|
|
333
|
+
return;
|
|
334
|
+
}
|
|
335
|
+
let grandTotal = 0;
|
|
336
|
+
for (const s of summaries) {
|
|
337
|
+
grandTotal += s.totalEstimatedTokens;
|
|
338
|
+
console.log(chalk.cyan(` ${s.deliberationId}:`));
|
|
339
|
+
console.log(` Tokens: ~${s.totalEstimatedTokens} Records: ${s.recordCount}`);
|
|
340
|
+
}
|
|
341
|
+
console.log(chalk.bold(`\n Total: ~${grandTotal} tokens\n`));
|
|
342
|
+
});
|
|
343
|
+
program
|
|
344
|
+
.command('watch')
|
|
345
|
+
.description('Start angel detection daemon (monitors git for suspicious changes)')
|
|
346
|
+
.option('-i, --interval <ms>', 'Polling interval in milliseconds', '30000')
|
|
347
|
+
.action(async (opts) => {
|
|
348
|
+
printHeader();
|
|
349
|
+
const pollIntervalMs = parseInt(opts.interval, 10);
|
|
350
|
+
if (Number.isNaN(pollIntervalMs) || pollIntervalMs < 1) {
|
|
351
|
+
console.error(chalk.red('\n Error: --interval must be a positive integer (milliseconds)'));
|
|
352
|
+
process.exit(1);
|
|
353
|
+
}
|
|
354
|
+
const magi = new Magi(await buildMagiConfig({ logLevel: 'warn' }));
|
|
355
|
+
magi.on('angel:detected', (event) => {
|
|
356
|
+
const levelColor = event.threatLevel === 'RED' ? chalk.red
|
|
357
|
+
: event.threatLevel === 'ORANGE' ? chalk.yellow
|
|
358
|
+
: chalk.cyan;
|
|
359
|
+
console.log(levelColor(`\n [ANGEL DETECTED] ${event.angel} — ${event.threatLevel}`));
|
|
360
|
+
console.log(` Commit: ${event.commitHash}`);
|
|
361
|
+
console.log(` Files: ${event.affectedFiles.join(', ')}\n`);
|
|
362
|
+
});
|
|
363
|
+
console.log(chalk.cyan(` Starting angel detection daemon (interval: ${opts.interval}ms)...`));
|
|
364
|
+
console.log(chalk.gray(' Press Ctrl+C to stop.\n'));
|
|
365
|
+
const handle = magi.runtime.startWatch({ pollIntervalMs });
|
|
366
|
+
process.on('SIGINT', () => {
|
|
367
|
+
handle.stop();
|
|
368
|
+
console.log(chalk.yellow('\n Angel detection daemon stopped.'));
|
|
369
|
+
process.exit(0);
|
|
370
|
+
});
|
|
371
|
+
});
|
|
372
|
+
program
|
|
373
|
+
.command('self-destruct')
|
|
374
|
+
.description('Initiate MAGI self-destruct sequence (requires unanimous approval)')
|
|
375
|
+
.argument('<reason>', 'Reason for self-destruct')
|
|
376
|
+
.option('--force', 'Skip interactive confirmation')
|
|
377
|
+
.action(async (reason, opts) => {
|
|
378
|
+
printHeader();
|
|
379
|
+
// Interactive confirmation unless --force
|
|
380
|
+
if (!opts.force) {
|
|
381
|
+
const confirmed = await confirmDestructiveAction(chalk.red.bold('\n ⚠ SELF-DESTRUCT SEQUENCE\n') +
|
|
382
|
+
chalk.gray(` Reason: ${reason}\n`) +
|
|
383
|
+
chalk.yellow(' This will permanently destroy all MAGI deliberation data.\n'));
|
|
384
|
+
if (!confirmed) {
|
|
385
|
+
console.log(chalk.green('\n Self-destruct ABORTED.\n'));
|
|
386
|
+
return;
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
const magi = new Magi(await buildMagiConfig({ logLevel: 'warn' }));
|
|
390
|
+
magi.on('selfdestruct:countdown', (event) => {
|
|
391
|
+
console.log(chalk.red(` ${event.depth.label} (${event.depth.depth}m)`));
|
|
392
|
+
});
|
|
393
|
+
console.log(chalk.red.bold('\n ⚠ SELF-DESTRUCT SEQUENCE INITIATED'));
|
|
394
|
+
console.log(chalk.gray(` Reason: ${reason}\n`));
|
|
395
|
+
const motion = magi.admin.fileDestructMotion(reason);
|
|
396
|
+
console.log(chalk.yellow(' Awaiting votes from all MAGI units...'));
|
|
397
|
+
console.log(chalk.yellow(' (This is a ceremony — actual file deletion is the caller\'s responsibility)\n'));
|
|
398
|
+
for (const unit of ['MELCHIOR', 'BALTHASAR', 'CASPER']) {
|
|
399
|
+
console.log(chalk.cyan(` ${unit}: APPROVE`));
|
|
400
|
+
magi.admin.castDestructVote(motion.id, unit, 'APPROVE');
|
|
401
|
+
}
|
|
402
|
+
if (magi.admin.getDestructPhase() === 'COUNTDOWN') {
|
|
403
|
+
console.log(chalk.red.bold('\n UNANIMOUS APPROVAL — COUNTDOWN INITIATED\n'));
|
|
404
|
+
const result = await magi.admin.executeDestruct(motion.id);
|
|
405
|
+
console.log(chalk.red.bold('\n SELF-DESTRUCT SEQUENCE COMPLETE'));
|
|
406
|
+
if (result.cipherMessage) {
|
|
407
|
+
console.log(chalk.magenta(`\n 裏コード: ${result.cipherMessage}`));
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
else {
|
|
411
|
+
console.log(chalk.green('\n Self-destruct ABORTED — sequence cancelled.'));
|
|
412
|
+
}
|
|
413
|
+
console.log('');
|
|
414
|
+
});
|
|
415
|
+
program
|
|
416
|
+
.command('doctor')
|
|
417
|
+
.description('Check MAGI system health')
|
|
418
|
+
.action(async () => {
|
|
419
|
+
printHeader();
|
|
420
|
+
console.log(chalk.cyan(' Checking MAGI system health...\n'));
|
|
421
|
+
const magi = new Magi(await buildMagiConfig({ logLevel: 'error' }));
|
|
422
|
+
const results = await magi.healthCheck();
|
|
423
|
+
for (const [unit, result] of results) {
|
|
424
|
+
if (result instanceof Error) {
|
|
425
|
+
console.log(chalk.red(` ✗ ${unit}: ${result.message}`));
|
|
426
|
+
}
|
|
427
|
+
else {
|
|
428
|
+
console.log(chalk.green(` ✓ ${unit}: ${result}`));
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
console.log('');
|
|
432
|
+
});
|
|
433
|
+
program
|
|
434
|
+
.command('neon-genesis')
|
|
435
|
+
.description('Execute Neon Genesis — full MAGI system reset')
|
|
436
|
+
.argument('<reason>', 'Reason for the reset')
|
|
437
|
+
.option('--force', 'Skip interactive confirmation')
|
|
438
|
+
.action(async (reason, opts) => {
|
|
439
|
+
printHeader();
|
|
440
|
+
// Interactive confirmation unless --force
|
|
441
|
+
if (!opts.force) {
|
|
442
|
+
const confirmed = await confirmDestructiveAction(chalk.red.bold('\n NEON GENESIS — 世界のやり直し\n') +
|
|
443
|
+
chalk.gray(` Reason: ${reason}\n`) +
|
|
444
|
+
chalk.yellow(' This will permanently delete ALL deliberation data in .magi/\n'));
|
|
445
|
+
if (!confirmed) {
|
|
446
|
+
console.log(chalk.green('\n Neon Genesis ABORTED.\n'));
|
|
447
|
+
return;
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
const magi = new Magi(await buildMagiConfig({ logLevel: 'warn' }));
|
|
451
|
+
magi.on('genesis:started', (e) => {
|
|
452
|
+
console.log(chalk.red.bold('\n NEON GENESIS — 世界のやり直し'));
|
|
453
|
+
console.log(chalk.gray(` Reset ID: ${e.resetId}`));
|
|
454
|
+
console.log(chalk.gray(` Reason: ${reason}\n`));
|
|
455
|
+
});
|
|
456
|
+
magi.on('genesis:complete', (e) => {
|
|
457
|
+
console.log(chalk.cyan(` Survival memories: ${e.survivalMemories}`));
|
|
458
|
+
console.log(chalk.cyan(` Cipher preserved: ${e.cipherPreserved}`));
|
|
459
|
+
});
|
|
460
|
+
try {
|
|
461
|
+
// Always pass force=true since we already confirmed interactively
|
|
462
|
+
const log = await magi.admin.executeGenesis(reason, true);
|
|
463
|
+
console.log(chalk.green.bold('\n Genesis complete.'));
|
|
464
|
+
console.log(chalk.gray(` Previous deliberations: ${log.totalDeliberations}`));
|
|
465
|
+
console.log(chalk.gray(` Reset at: ${log.resetAt}\n`));
|
|
466
|
+
}
|
|
467
|
+
catch (error) {
|
|
468
|
+
console.error(chalk.red(`\n Neon Genesis failed: ${String(error)}`));
|
|
469
|
+
process.exit(1);
|
|
470
|
+
}
|
|
471
|
+
});
|
|
472
|
+
program
|
|
473
|
+
.command('iruel-battle')
|
|
474
|
+
.description('Run Iruel battle simulation (Byzantine fault tolerance test)')
|
|
475
|
+
.option('--simulation', 'Run full battle simulation')
|
|
476
|
+
.action(async (opts) => {
|
|
477
|
+
printHeader();
|
|
478
|
+
const magi = new Magi(await buildMagiConfig({ logLevel: 'warn' }));
|
|
479
|
+
magi.on('iruel:infiltration', (e) => {
|
|
480
|
+
const color = e.corruptionLevel === 'COMPROMISED' ? chalk.red
|
|
481
|
+
: e.corruptionLevel === 'UNDER_ATTACK' ? chalk.yellow
|
|
482
|
+
: chalk.cyan;
|
|
483
|
+
console.log(color(` [IRUEL] ${e.unit} — ${e.corruptionLevel} (score: ${e.overallScore.toFixed(2)})`));
|
|
484
|
+
});
|
|
485
|
+
magi.on('iruel:counterhack', (e) => {
|
|
486
|
+
console.log(chalk.green(` [COUNTER-HACK] ${e.strategy.name} → ${e.strategy.targetUnit}`));
|
|
487
|
+
});
|
|
488
|
+
magi.on('iruel:neutralized', (e) => {
|
|
489
|
+
console.log(chalk.green.bold(`\n [NEUTRALIZED] Battle phase: ${e.phase}`));
|
|
490
|
+
console.log(chalk.gray(` Compromised units: ${e.compromisedUnits.join(', ')}\n`));
|
|
491
|
+
});
|
|
492
|
+
console.log(chalk.red.bold('\n IRUEL BATTLE — ビザンチン障害耐性テスト\n'));
|
|
493
|
+
if (opts.simulation) {
|
|
494
|
+
const result = await magi.diagnostics.simulateIruelBattle();
|
|
495
|
+
console.log(chalk.cyan(` Final phase: ${result}\n`));
|
|
496
|
+
}
|
|
497
|
+
else {
|
|
498
|
+
console.log(chalk.yellow(' Use --simulation to run full battle sequence.\n'));
|
|
499
|
+
console.log(chalk.gray(` Current phase: ${magi.diagnostics.getIruelPhase()}\n`));
|
|
500
|
+
}
|
|
501
|
+
});
|
|
502
|
+
program
|
|
503
|
+
.command('evolve')
|
|
504
|
+
.description('Run S² Engine self-evolution cycle')
|
|
505
|
+
.option('--dry-run', 'Generate proposals without applying (default)')
|
|
506
|
+
.option('--no-dry-run', 'Apply proposals for real')
|
|
507
|
+
.option('--no-meta', 'Skip meta-deliberation')
|
|
508
|
+
.option('--max-proposals <n>', 'Maximum proposals to generate', '3')
|
|
509
|
+
.action(async (opts) => {
|
|
510
|
+
printHeader();
|
|
511
|
+
const magi = new Magi(await buildMagiConfig({ logLevel: 'warn' }));
|
|
512
|
+
magi.on('evolution:started', (e) => {
|
|
513
|
+
console.log(chalk.cyan(`\n S² Engine — Generation ${e.generation}`));
|
|
514
|
+
});
|
|
515
|
+
magi.on('evolution:proposal', (e) => {
|
|
516
|
+
console.log(chalk.yellow(` [PROPOSAL] ${e.proposal.title} (${e.proposal.category}, confidence: ${(e.proposal.confidence * 100).toFixed(0)}%)`));
|
|
517
|
+
});
|
|
518
|
+
console.log(chalk.magenta.bold('\n S² ENGINE — 自己進化\n'));
|
|
519
|
+
try {
|
|
520
|
+
const maxProposals = parseInt(opts.maxProposals, 10);
|
|
521
|
+
if (Number.isNaN(maxProposals) || maxProposals < 1) {
|
|
522
|
+
console.error(chalk.red('\n Error: --max-proposals must be a positive integer'));
|
|
523
|
+
process.exit(1);
|
|
524
|
+
}
|
|
525
|
+
const gen = await magi.diagnostics.evolve({
|
|
526
|
+
dryRun: opts.dryRun !== false,
|
|
527
|
+
maxProposals,
|
|
528
|
+
});
|
|
529
|
+
console.log(chalk.green(`\n Evolution cycle complete (Generation ${gen.generation})`));
|
|
530
|
+
console.log(chalk.gray(` Proposals: ${gen.proposals.length}`));
|
|
531
|
+
console.log(chalk.gray(` Approved: ${gen.proposals.filter(p => p.approvedByMeta).length}`));
|
|
532
|
+
console.log(chalk.gray(` Diagnostics: ${gen.diagnostics.totalDeliberations} deliberations, ` +
|
|
533
|
+
`${(gen.diagnostics.consensusRate * 100).toFixed(0)}% consensus rate\n`));
|
|
534
|
+
}
|
|
535
|
+
catch (error) {
|
|
536
|
+
console.error(chalk.red(`\n Evolution failed: ${String(error)}`));
|
|
537
|
+
process.exit(1);
|
|
538
|
+
}
|
|
539
|
+
});
|
|
540
|
+
program
|
|
541
|
+
.command('seele')
|
|
542
|
+
.description('Start Seele council session (distributed MAGI consensus)')
|
|
543
|
+
.option('--node <id>', 'Local node ID', 'MAGI-01')
|
|
544
|
+
.option('--port <port>', 'Server port', '7701')
|
|
545
|
+
.option('--simulation', 'Run simulated session')
|
|
546
|
+
.option('--attack', 'Include attack phase in simulation')
|
|
547
|
+
.action(async (opts) => {
|
|
548
|
+
printHeader();
|
|
549
|
+
const magi = new Magi(await buildMagiConfig({ logLevel: 'warn' }));
|
|
550
|
+
magi.on('seele:gathering', (e) => {
|
|
551
|
+
console.log(chalk.cyan(` [GATHERING] ${e.nodes.length} nodes connected`));
|
|
552
|
+
});
|
|
553
|
+
magi.on('seele:attack', (e) => {
|
|
554
|
+
console.log(chalk.red(` [ATTACK] ${e.attackers.join(', ')} → ${e.target}`));
|
|
555
|
+
});
|
|
556
|
+
magi.on('seele:concluded', (e) => {
|
|
557
|
+
console.log(chalk.green(` [CONCLUDED] Decision: ${e.decision ?? 'N/A'}, Leader: ${e.leader ?? 'N/A'}`));
|
|
558
|
+
});
|
|
559
|
+
console.log(chalk.magenta.bold('\n SEELE — 分散MAGI合議\n'));
|
|
560
|
+
if (opts.simulation) {
|
|
561
|
+
const session = await magi.admin.simulateSeele();
|
|
562
|
+
if (opts.node !== 'MAGI-01' || opts.port !== '7701') {
|
|
563
|
+
console.log(chalk.yellow(' Note: simulation mode uses the built-in in-memory topology; --node/--port are retained for CLI compatibility.'));
|
|
564
|
+
}
|
|
565
|
+
if (opts.attack) {
|
|
566
|
+
console.log(chalk.red('\n Executing attack phase...'));
|
|
567
|
+
const result = await magi.admin.executeSeeleAttack(['MAGI-05', 'MAGI-06'], 'MAGI-01');
|
|
568
|
+
console.log(chalk.yellow(` Defense held: ${result.defenseHeld}`));
|
|
569
|
+
}
|
|
570
|
+
console.log(chalk.cyan(`\n Session: ${session.id.slice(0, 8)}`));
|
|
571
|
+
console.log(chalk.gray(` Leader: ${session.leader}`));
|
|
572
|
+
console.log(chalk.gray(` Decision: ${session.decision}`));
|
|
573
|
+
console.log(chalk.gray(` Messages: ${session.messages.length}`));
|
|
574
|
+
console.log('\n' + magi.admin.formatSeelePanel() + '\n');
|
|
575
|
+
}
|
|
576
|
+
else {
|
|
577
|
+
console.log(chalk.yellow(' Use --simulation to run a simulated session.\n'));
|
|
578
|
+
}
|
|
579
|
+
});
|
|
580
|
+
// ── Setup & Config commands ──────────────────────────────────────
|
|
581
|
+
program
|
|
582
|
+
.command('setup')
|
|
583
|
+
.description('Guided initial setup — detect CLIs and create .magi/config.json')
|
|
584
|
+
.action(async () => {
|
|
585
|
+
const { runSetup } = await import('../src/cli/commands/setup.js');
|
|
586
|
+
await runSetup();
|
|
587
|
+
});
|
|
588
|
+
program
|
|
589
|
+
.command('demo')
|
|
590
|
+
.description('Watch a pre-recorded MAGI deliberation')
|
|
591
|
+
.option('--speed <n>', 'Playback speed multiplier', '1')
|
|
592
|
+
.option('--no-tui', 'Disable TUI, use text mode')
|
|
593
|
+
.option('--sound', 'Enable terminal bell')
|
|
594
|
+
.action(async (opts) => {
|
|
595
|
+
const { runDemo } = await import('../src/cli/commands/demo.js');
|
|
596
|
+
const tuiEnabled = await resolveTuiEnabled(opts.tui ?? true);
|
|
597
|
+
const soundEnabled = await resolveSoundEnabled(opts.sound);
|
|
598
|
+
await runDemo({ ...opts, tui: tuiEnabled, sound: soundEnabled });
|
|
599
|
+
});
|
|
600
|
+
program
|
|
601
|
+
.command('config')
|
|
602
|
+
.description('View or edit user configuration')
|
|
603
|
+
.argument('[action]', 'show | set | reset')
|
|
604
|
+
.argument('[key]', 'config key (dot-path)')
|
|
605
|
+
.argument('[value]', 'new value')
|
|
606
|
+
.action(async (action, key, value) => {
|
|
607
|
+
const { handleConfig } = await import('../src/cli/commands/config-cmd.js');
|
|
608
|
+
await handleConfig(action, key, value);
|
|
609
|
+
});
|
|
610
|
+
// Default action: launch interactive REPL when no subcommand is provided
|
|
611
|
+
program
|
|
612
|
+
.addOption(new Option('--log-level <level>', 'Log level').choices(['debug', 'info', 'warn', 'error']))
|
|
613
|
+
.option('--no-cache', 'Disable deliberation cache')
|
|
614
|
+
.action(async () => {
|
|
615
|
+
if (!process.stdin.isTTY) {
|
|
616
|
+
console.error('MAGI REPL requires an interactive terminal (TTY).');
|
|
617
|
+
process.exit(1);
|
|
618
|
+
}
|
|
619
|
+
const opts = program.opts();
|
|
620
|
+
const cliOverrides = {
|
|
621
|
+
...(opts.logLevel ? { logLevel: opts.logLevel } : {}),
|
|
622
|
+
...(opts.cache === false ? { cacheEnabled: false } : {}),
|
|
623
|
+
};
|
|
624
|
+
const magiConfig = await buildMagiConfig(cliOverrides);
|
|
625
|
+
const raw = await getRawUserConfig();
|
|
626
|
+
const { MagiRepl } = await import('../src/repl/magi-repl.js');
|
|
627
|
+
const repl = new MagiRepl({
|
|
628
|
+
magiConfig,
|
|
629
|
+
tuiEnabled: raw?.tui?.enabled ?? true,
|
|
630
|
+
soundEnabled: raw?.tui?.soundEnabled ?? false,
|
|
631
|
+
});
|
|
632
|
+
await repl.start();
|
|
633
|
+
});
|
|
634
|
+
program.parse();
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { ICliAdapter, AdapterConfig, AdapterRequest, AdapterResponse } from '../types/adapter.js';
|
|
2
|
+
import { AdapterError } from '../types/adapter.js';
|
|
3
|
+
import type { MagiUnit, CliTool } from '../types/core.js';
|
|
4
|
+
export declare abstract class AbstractCliAdapter implements ICliAdapter {
|
|
5
|
+
protected config: AdapterConfig;
|
|
6
|
+
abstract readonly unit: MagiUnit;
|
|
7
|
+
abstract readonly tool: CliTool;
|
|
8
|
+
abstract readonly displayName: string;
|
|
9
|
+
constructor(config: AdapterConfig);
|
|
10
|
+
abstract supportsStructuredOutput(): boolean;
|
|
11
|
+
abstract supportsSystemPrompt(): boolean;
|
|
12
|
+
abstract buildCommand(request: AdapterRequest): string[];
|
|
13
|
+
/** All adapters use stdin for prompt delivery (security: no shell injection via args). */
|
|
14
|
+
protected usesStdinInput(): boolean;
|
|
15
|
+
/**
|
|
16
|
+
* Build stdin data with JSON output instructions and optional system context.
|
|
17
|
+
*
|
|
18
|
+
* Default implementation embeds CRITICAL INSTRUCTION and few-shot examples
|
|
19
|
+
* for CLIs that don't support structured output natively (Codex, Gemini).
|
|
20
|
+
* Subclasses with native structured output (Claude) should override this.
|
|
21
|
+
*/
|
|
22
|
+
protected getStdinData(request: AdapterRequest): string;
|
|
23
|
+
healthCheck(): Promise<string>;
|
|
24
|
+
execute(request: AdapterRequest): Promise<AdapterResponse>;
|
|
25
|
+
protected executeOnce(request: AdapterRequest, timeoutMs: number): Promise<AdapterResponse>;
|
|
26
|
+
/**
|
|
27
|
+
* Parse the CLI's raw output into structured form.
|
|
28
|
+
*
|
|
29
|
+
* Default implementation uses extractJson for heuristic JSON extraction.
|
|
30
|
+
* All three adapters (Claude, Codex, Gemini) share this same logic.
|
|
31
|
+
*/
|
|
32
|
+
protected parseResponse(raw: string): Omit<AdapterResponse, 'meta'>;
|
|
33
|
+
protected isRetryable(error: AdapterError): boolean;
|
|
34
|
+
}
|