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
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
/**
|
|
3
|
+
* In-memory cache for deliberation results.
|
|
4
|
+
* Keyed by a SHA-256 hash of task attributes (type + title + description + artifacts).
|
|
5
|
+
*/
|
|
6
|
+
export class DeliberationCache {
|
|
7
|
+
ttlMs;
|
|
8
|
+
maxEntries;
|
|
9
|
+
store = new Map();
|
|
10
|
+
inflight = new Map();
|
|
11
|
+
constructor(ttlMs = 3_600_000, // 1 hour default
|
|
12
|
+
maxEntries = 100) {
|
|
13
|
+
this.ttlMs = ttlMs;
|
|
14
|
+
this.maxEntries = maxEntries;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Compute a deterministic cache key from a MagiTask.
|
|
18
|
+
*/
|
|
19
|
+
computeKey(task) {
|
|
20
|
+
const hash = createHash('sha256');
|
|
21
|
+
hash.update(task.type);
|
|
22
|
+
hash.update(task.title);
|
|
23
|
+
hash.update(task.description);
|
|
24
|
+
if (task.artifacts) {
|
|
25
|
+
hash.update(JSON.stringify(task.artifacts));
|
|
26
|
+
}
|
|
27
|
+
return hash.digest('hex');
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Get a cached deliberation result.
|
|
31
|
+
* Returns null on miss or TTL expiry.
|
|
32
|
+
* Restores Date objects and sets fromCache=true.
|
|
33
|
+
*/
|
|
34
|
+
get(task) {
|
|
35
|
+
const key = this.computeKey(task);
|
|
36
|
+
const entry = this.store.get(key);
|
|
37
|
+
if (!entry)
|
|
38
|
+
return null;
|
|
39
|
+
// TTL check (per-entry effectiveTtl includes jitter)
|
|
40
|
+
if (Date.now() - entry.cachedAt > entry.effectiveTtl) {
|
|
41
|
+
this.store.delete(key);
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
44
|
+
// Restore Date objects and mark as cached
|
|
45
|
+
return {
|
|
46
|
+
...entry.deliberation,
|
|
47
|
+
startedAt: new Date(entry.deliberation.startedAt),
|
|
48
|
+
completedAt: new Date(entry.deliberation.completedAt),
|
|
49
|
+
rounds: entry.deliberation.rounds.map((r) => ({
|
|
50
|
+
...r,
|
|
51
|
+
startedAt: new Date(r.startedAt),
|
|
52
|
+
completedAt: new Date(r.completedAt),
|
|
53
|
+
})),
|
|
54
|
+
fromCache: true,
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Store a deliberation result in the cache.
|
|
59
|
+
*/
|
|
60
|
+
set(task, deliberation) {
|
|
61
|
+
const key = this.computeKey(task);
|
|
62
|
+
if (this.store.size >= this.maxEntries && !this.store.has(key)) {
|
|
63
|
+
const oldestKey = this.store.keys().next().value;
|
|
64
|
+
if (oldestKey !== undefined)
|
|
65
|
+
this.store.delete(oldestKey);
|
|
66
|
+
}
|
|
67
|
+
// Add 0-10% jitter to stagger TTL expiry (cache stampede prevention)
|
|
68
|
+
const jitter = Math.floor(Math.random() * 0.1 * this.ttlMs);
|
|
69
|
+
this.store.set(key, {
|
|
70
|
+
deliberation,
|
|
71
|
+
cachedAt: Date.now(),
|
|
72
|
+
effectiveTtl: this.ttlMs + jitter,
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Get from cache or compute. Prevents cache stampede by coalescing
|
|
77
|
+
* concurrent requests for the same cache key.
|
|
78
|
+
*/
|
|
79
|
+
getOrCompute(task, compute) {
|
|
80
|
+
// Check cache first
|
|
81
|
+
const cached = this.get(task);
|
|
82
|
+
if (cached)
|
|
83
|
+
return Promise.resolve(cached);
|
|
84
|
+
const key = this.computeKey(task);
|
|
85
|
+
// Check inflight — coalesce if same key is already being computed
|
|
86
|
+
const existing = this.inflight.get(key);
|
|
87
|
+
if (existing)
|
|
88
|
+
return existing;
|
|
89
|
+
// Start computation and track it
|
|
90
|
+
const promise = compute().then(result => {
|
|
91
|
+
this.set(task, result);
|
|
92
|
+
this.inflight.delete(key);
|
|
93
|
+
return result;
|
|
94
|
+
}).catch(err => {
|
|
95
|
+
this.inflight.delete(key);
|
|
96
|
+
throw err;
|
|
97
|
+
});
|
|
98
|
+
this.inflight.set(key, promise);
|
|
99
|
+
return promise;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Remove all entries from the cache.
|
|
103
|
+
*/
|
|
104
|
+
clear() {
|
|
105
|
+
this.store.clear();
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Remove expired entries.
|
|
109
|
+
*/
|
|
110
|
+
prune() {
|
|
111
|
+
const now = Date.now();
|
|
112
|
+
let pruned = 0;
|
|
113
|
+
for (const [key, entry] of this.store) {
|
|
114
|
+
if (now - entry.cachedAt > entry.effectiveTtl) {
|
|
115
|
+
this.store.delete(key);
|
|
116
|
+
pruned++;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
return pruned;
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Cache statistics.
|
|
123
|
+
*/
|
|
124
|
+
stats() {
|
|
125
|
+
return { size: this.store.size, ttlMs: this.ttlMs, maxEntries: this.maxEntries, inflightCount: this.inflight.size };
|
|
126
|
+
}
|
|
127
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `magi config` — View and edit user configuration.
|
|
3
|
+
*
|
|
4
|
+
* /config — Show current settings
|
|
5
|
+
* /config set <key> <value> — Change a setting
|
|
6
|
+
* /config reset — Delete config file
|
|
7
|
+
*/
|
|
8
|
+
export declare function handleConfigShow(): Promise<void>;
|
|
9
|
+
export declare function handleConfigSet(key: string, value: string): Promise<void>;
|
|
10
|
+
export declare function handleConfigReset(): Promise<void>;
|
|
11
|
+
export declare function handleConfig(action?: string, key?: string, value?: string): Promise<void>;
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `magi config` — View and edit user configuration.
|
|
3
|
+
*
|
|
4
|
+
* /config — Show current settings
|
|
5
|
+
* /config set <key> <value> — Change a setting
|
|
6
|
+
* /config reset — Delete config file
|
|
7
|
+
*/
|
|
8
|
+
import chalk from 'chalk';
|
|
9
|
+
import { unlink } from 'node:fs/promises';
|
|
10
|
+
import { loadUserConfig, saveUserConfig, getUserConfigPath } from '../../config/user-config.js';
|
|
11
|
+
import { t, setLocale } from '../i18n.js';
|
|
12
|
+
import { logger } from '../../utils/logger.js';
|
|
13
|
+
const _S = { BAR: '│', BAR_END: '└', STEP_DONE: '◇' };
|
|
14
|
+
void _S;
|
|
15
|
+
const DEADLOCK_LABELS = {
|
|
16
|
+
ja: {
|
|
17
|
+
'melchior-tiebreak': 'MELCHIOR優先',
|
|
18
|
+
'highest-confidence': '確信度で決定',
|
|
19
|
+
escalate: 'エスカレーション',
|
|
20
|
+
'human-in-the-loop': '人間に聞く',
|
|
21
|
+
},
|
|
22
|
+
en: {
|
|
23
|
+
'melchior-tiebreak': 'MELCHIOR decides',
|
|
24
|
+
'highest-confidence': 'Highest confidence',
|
|
25
|
+
escalate: 'Escalate',
|
|
26
|
+
'human-in-the-loop': 'Ask human',
|
|
27
|
+
},
|
|
28
|
+
};
|
|
29
|
+
// ── Show ─────────────────────────────────────────────────────────
|
|
30
|
+
export async function handleConfigShow() {
|
|
31
|
+
const config = await loadUserConfig().catch(() => undefined);
|
|
32
|
+
if (config?.language)
|
|
33
|
+
setLocale(config.language);
|
|
34
|
+
if (!config) {
|
|
35
|
+
console.log('');
|
|
36
|
+
console.log(chalk.yellow(` ${t('config_no_file')}`));
|
|
37
|
+
console.log(chalk.dim(` ${t('config_no_file_hint')}`));
|
|
38
|
+
console.log('');
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
const lang = config.language ?? 'en';
|
|
42
|
+
console.log('');
|
|
43
|
+
console.log(chalk.cyan.bold(` ${t('config_title')}`));
|
|
44
|
+
console.log(chalk.dim(` ${t('config_file')}: ${getUserConfigPath()}`));
|
|
45
|
+
console.log('');
|
|
46
|
+
if (config.enabledUnits) {
|
|
47
|
+
row(t('config_units'), config.enabledUnits.join(', '));
|
|
48
|
+
}
|
|
49
|
+
if (config.language) {
|
|
50
|
+
row(t('config_language'), config.language === 'ja' ? '日本語' : 'English');
|
|
51
|
+
}
|
|
52
|
+
const pl = config.defaultPipeline;
|
|
53
|
+
if (pl) {
|
|
54
|
+
if (pl.maxRounds !== undefined)
|
|
55
|
+
row(t('config_max_rounds'), String(pl.maxRounds));
|
|
56
|
+
if (pl.earlyConsensusExit !== undefined)
|
|
57
|
+
row(t('config_early_exit'), pl.earlyConsensusExit ? t('on') : t('off'));
|
|
58
|
+
if (pl.consensus?.deadlockStrategy) {
|
|
59
|
+
const label = DEADLOCK_LABELS[lang]?.[pl.consensus.deadlockStrategy] ?? pl.consensus.deadlockStrategy;
|
|
60
|
+
row(t('config_deadlock'), label);
|
|
61
|
+
}
|
|
62
|
+
if (pl.consensus?.quorum !== undefined)
|
|
63
|
+
row(t('config_quorum'), String(pl.consensus.quorum));
|
|
64
|
+
if (pl.phaseTimeoutMs !== undefined)
|
|
65
|
+
row(t('config_phase_timeout'), `${pl.phaseTimeoutMs / 1000}s`);
|
|
66
|
+
}
|
|
67
|
+
if (config.tui) {
|
|
68
|
+
if (config.tui.enabled !== undefined)
|
|
69
|
+
row(t('config_tui'), config.tui.enabled ? t('on') : t('off'));
|
|
70
|
+
if (config.tui.soundEnabled !== undefined)
|
|
71
|
+
row(t('config_sound'), config.tui.soundEnabled ? t('on') : t('off'));
|
|
72
|
+
}
|
|
73
|
+
if (config.logLevel)
|
|
74
|
+
row(t('config_log_level'), config.logLevel);
|
|
75
|
+
if (config.outputFormat)
|
|
76
|
+
row(t('config_output_format'), config.outputFormat);
|
|
77
|
+
if (config.cacheEnabled !== undefined)
|
|
78
|
+
row(t('config_cache'), config.cacheEnabled ? t('on') : t('off'));
|
|
79
|
+
if (config.fileAccess)
|
|
80
|
+
row(t('config_file_access'), config.fileAccess.enabled ? t('on') : t('off'));
|
|
81
|
+
console.log('');
|
|
82
|
+
console.log(chalk.dim(` ${t('config_change_hint')}`));
|
|
83
|
+
console.log(chalk.dim(` ${t('config_reset_hint')}`));
|
|
84
|
+
console.log('');
|
|
85
|
+
}
|
|
86
|
+
/** Compute display width accounting for CJK full-width characters. */
|
|
87
|
+
function displayWidth(str) {
|
|
88
|
+
let w = 0;
|
|
89
|
+
for (const ch of str) {
|
|
90
|
+
const cp = ch.codePointAt(0) ?? 0;
|
|
91
|
+
// CJK Unified Ideographs, Hiragana, Katakana, Fullwidth forms, CJK symbols
|
|
92
|
+
if ((cp >= 0x3000 && cp <= 0x9FFF) ||
|
|
93
|
+
(cp >= 0xF900 && cp <= 0xFAFF) ||
|
|
94
|
+
(cp >= 0xFF01 && cp <= 0xFF60) ||
|
|
95
|
+
(cp >= 0xFFE0 && cp <= 0xFFE6) ||
|
|
96
|
+
(cp >= 0x20000 && cp <= 0x2FA1F)) {
|
|
97
|
+
w += 2;
|
|
98
|
+
}
|
|
99
|
+
else {
|
|
100
|
+
w += 1;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
return w;
|
|
104
|
+
}
|
|
105
|
+
function row(label, value) {
|
|
106
|
+
const targetWidth = 24;
|
|
107
|
+
const pad = Math.max(0, targetWidth - displayWidth(label));
|
|
108
|
+
console.log(` ${chalk.dim(label + ' '.repeat(pad))} ${chalk.white(value)}`);
|
|
109
|
+
}
|
|
110
|
+
// ── Set ──────────────────────────────────────────────────────────
|
|
111
|
+
export async function handleConfigSet(key, value) {
|
|
112
|
+
const config = (await loadUserConfig().catch(() => undefined)) ?? {};
|
|
113
|
+
if (config.language)
|
|
114
|
+
setLocale(config.language);
|
|
115
|
+
try {
|
|
116
|
+
const parsed = parseValue(value);
|
|
117
|
+
setByPath(config, key, parsed);
|
|
118
|
+
await saveUserConfig(config);
|
|
119
|
+
console.log(chalk.green(`\n ${t('config_set_ok')}: ${key} = ${JSON.stringify(parsed)}\n`));
|
|
120
|
+
}
|
|
121
|
+
catch (err) {
|
|
122
|
+
console.error(chalk.red(`\n ${t('config_set_invalid')}`));
|
|
123
|
+
console.error(chalk.dim(` ${err instanceof Error ? err.message : String(err)}\n`));
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
function parseValue(value) {
|
|
127
|
+
if (value === 'true')
|
|
128
|
+
return true;
|
|
129
|
+
if (value === 'false')
|
|
130
|
+
return false;
|
|
131
|
+
const num = Number(value);
|
|
132
|
+
if (!Number.isNaN(num) && Number.isFinite(num) && value.trim() !== '')
|
|
133
|
+
return num;
|
|
134
|
+
if (value.includes(','))
|
|
135
|
+
return value.split(',').map(s => s.trim());
|
|
136
|
+
return value;
|
|
137
|
+
}
|
|
138
|
+
const DANGEROUS_KEYS = new Set(['__proto__', 'constructor', 'prototype']);
|
|
139
|
+
function setByPath(obj, path, value) {
|
|
140
|
+
const parts = path.split('.');
|
|
141
|
+
if (parts.some(p => DANGEROUS_KEYS.has(p))) {
|
|
142
|
+
throw new Error(`Invalid config path: "${path}" contains a forbidden property name`);
|
|
143
|
+
}
|
|
144
|
+
let current = obj;
|
|
145
|
+
for (let i = 0; i < parts.length - 1; i++) {
|
|
146
|
+
const part = parts[i];
|
|
147
|
+
if (current[part] === undefined || typeof current[part] !== 'object' || current[part] === null) {
|
|
148
|
+
current[part] = {};
|
|
149
|
+
}
|
|
150
|
+
current = current[part];
|
|
151
|
+
}
|
|
152
|
+
current[parts[parts.length - 1]] = value;
|
|
153
|
+
}
|
|
154
|
+
// ── Reset ────────────────────────────────────────────────────────
|
|
155
|
+
export async function handleConfigReset() {
|
|
156
|
+
const configPath = getUserConfigPath();
|
|
157
|
+
try {
|
|
158
|
+
await unlink(configPath);
|
|
159
|
+
console.log(chalk.green(`\n ${t('config_reset_ok')}\n`));
|
|
160
|
+
}
|
|
161
|
+
catch (err) {
|
|
162
|
+
if (err.code === 'ENOENT') {
|
|
163
|
+
console.log(chalk.yellow(`\n ${t('config_reset_none')}\n`));
|
|
164
|
+
}
|
|
165
|
+
else {
|
|
166
|
+
logger.error('Failed to delete config', err);
|
|
167
|
+
console.error(chalk.red(`\n Error\n`));
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
// ── Router ───────────────────────────────────────────────────────
|
|
172
|
+
export async function handleConfig(action, key, value) {
|
|
173
|
+
switch (action) {
|
|
174
|
+
case undefined:
|
|
175
|
+
case 'show':
|
|
176
|
+
return handleConfigShow();
|
|
177
|
+
case 'set':
|
|
178
|
+
if (!key || value === undefined) {
|
|
179
|
+
console.log(chalk.dim(`\n ${t('config_set_usage')}`));
|
|
180
|
+
console.log(chalk.dim(' e.g. /config set enabledUnits MELCHIOR,BALTHASAR'));
|
|
181
|
+
console.log(chalk.dim(' /config set defaultPipeline.maxRounds 5\n'));
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
return handleConfigSet(key, value);
|
|
185
|
+
case 'reset':
|
|
186
|
+
return handleConfigReset();
|
|
187
|
+
default:
|
|
188
|
+
console.error(chalk.red(`\n ${t('config_unknown_action')}: ${action}\n`));
|
|
189
|
+
}
|
|
190
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `magi demo` — Watch a pre-recorded deliberation.
|
|
3
|
+
*
|
|
4
|
+
* Replays recorded MAGI events through the TUI or streaming reporter,
|
|
5
|
+
* allowing users to experience the deliberation flow without CLI setup.
|
|
6
|
+
*/
|
|
7
|
+
export interface DemoOptions {
|
|
8
|
+
speed?: string;
|
|
9
|
+
tui?: boolean;
|
|
10
|
+
sound?: boolean;
|
|
11
|
+
}
|
|
12
|
+
export declare function runDemo(opts: DemoOptions): Promise<void>;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `magi demo` — Watch a pre-recorded deliberation.
|
|
3
|
+
*
|
|
4
|
+
* Replays recorded MAGI events through the TUI or streaming reporter,
|
|
5
|
+
* allowing users to experience the deliberation flow without CLI setup.
|
|
6
|
+
*/
|
|
7
|
+
import chalk from 'chalk';
|
|
8
|
+
import { MagiEventBus } from '../../engine/events.js';
|
|
9
|
+
import { DEMO_EVENTS } from '../../demo/recorded-deliberation.js';
|
|
10
|
+
import { initializeTui } from '../tui-setup.js';
|
|
11
|
+
function sleep(ms) {
|
|
12
|
+
return new Promise(resolve => setTimeout(resolve, ms));
|
|
13
|
+
}
|
|
14
|
+
export async function runDemo(opts) {
|
|
15
|
+
const speed = Math.max(0.1, Math.min(10, parseFloat(opts.speed ?? '1')));
|
|
16
|
+
const useTui = opts.tui !== false;
|
|
17
|
+
const eventBus = new MagiEventBus();
|
|
18
|
+
const { tuiInstance } = await initializeTui(eventBus, useTui, { soundEnabled: opts.sound });
|
|
19
|
+
if (!tuiInstance) {
|
|
20
|
+
console.log(chalk.cyan.bold('\n MAGI Demo — REST vs GraphQL\n'));
|
|
21
|
+
console.log(chalk.gray(` 再生速度: ${speed}x\n`));
|
|
22
|
+
// Text-mode event listener
|
|
23
|
+
eventBus.on('deliberation:start', (e) => {
|
|
24
|
+
console.log(chalk.cyan(` [START] ${e.taskTitle}`));
|
|
25
|
+
});
|
|
26
|
+
eventBus.on('phase:start', (e) => {
|
|
27
|
+
console.log(chalk.yellow(` [PHASE] ${e.phase} (Round ${e.roundNumber})`));
|
|
28
|
+
});
|
|
29
|
+
eventBus.on('unit:start', (e) => {
|
|
30
|
+
console.log(chalk.gray(` ${e.unit} thinking...`));
|
|
31
|
+
});
|
|
32
|
+
eventBus.on('unit:complete', (e) => {
|
|
33
|
+
const voteColor = e.vote === 'APPROVE' ? chalk.green
|
|
34
|
+
: e.vote === 'REJECT' ? chalk.red
|
|
35
|
+
: chalk.yellow;
|
|
36
|
+
console.log(voteColor(` ${e.unit}: ${e.vote} (${(e.confidence * 100).toFixed(0)}%)`));
|
|
37
|
+
if (e.reasoningSummary) {
|
|
38
|
+
console.log(chalk.gray(` ${e.reasoningSummary.slice(0, 120)}${e.reasoningSummary.length > 120 ? '...' : ''}`));
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
eventBus.on('deliberation:complete', (e) => {
|
|
42
|
+
const d = String(e.decision);
|
|
43
|
+
const color = d.includes('APPROVE') ? chalk.green.bold
|
|
44
|
+
: d.includes('REJECT') ? chalk.red.bold
|
|
45
|
+
: chalk.yellow.bold;
|
|
46
|
+
console.log(color(`\n [RESULT] ${String(e.decision)} — 全会一致`));
|
|
47
|
+
console.log(chalk.gray(` Duration: ${(e.totalDurationMs / 1000).toFixed(1)}s (demo)\n`));
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
// Replay events
|
|
51
|
+
for (const event of DEMO_EVENTS) {
|
|
52
|
+
if (event.delayMs > 0) {
|
|
53
|
+
await sleep(event.delayMs / speed);
|
|
54
|
+
}
|
|
55
|
+
// Update emittedAt to current time for realistic display
|
|
56
|
+
const payload = { ...event.payload, emittedAt: new Date() };
|
|
57
|
+
const eventName = event.type;
|
|
58
|
+
// Safe cast: pre-recorded events are trusted
|
|
59
|
+
eventBus.emit(eventName, payload);
|
|
60
|
+
}
|
|
61
|
+
// Wait for TUI dismissal
|
|
62
|
+
if (tuiInstance) {
|
|
63
|
+
await tuiInstance.waitForDismiss();
|
|
64
|
+
tuiInstance.dispose();
|
|
65
|
+
}
|
|
66
|
+
}
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `magi setup` — Guided initial setup.
|
|
3
|
+
*
|
|
4
|
+
* @clack/prompts inspired box-drawing UI.
|
|
5
|
+
* Detects AI CLIs, lets user choose configuration, saves to config.
|
|
6
|
+
*/
|
|
7
|
+
import chalk from 'chalk';
|
|
8
|
+
import { detectAvailableCLIs, getAvailableUnits, suggestConfigurations } from '../../config/cli-detector.js';
|
|
9
|
+
import { saveUserConfig, loadUserConfigSafe } from '../../config/user-config.js';
|
|
10
|
+
import { interactiveSelect, interactiveConfirm, UserCancelledError } from '../interactive-select.js';
|
|
11
|
+
import { t, setLocale, detectLocale, getLocale } from '../i18n.js';
|
|
12
|
+
// ── Box-drawing ──────────────────────────────────────────────────
|
|
13
|
+
const S = {
|
|
14
|
+
BAR: '│',
|
|
15
|
+
BAR_END: '└',
|
|
16
|
+
CORNER_TL: '┌',
|
|
17
|
+
STEP_ACTIVE: '◆',
|
|
18
|
+
STEP_DONE: '◇',
|
|
19
|
+
INFO: '●',
|
|
20
|
+
};
|
|
21
|
+
// ── Unit names ───────────────────────────────────────────────────
|
|
22
|
+
const UNIT_NAMES = {
|
|
23
|
+
MELCHIOR: 'MELCHIOR (Claude)',
|
|
24
|
+
BALTHASAR: 'BALTHASAR (Codex)',
|
|
25
|
+
CASPER: 'CASPER (Gemini)',
|
|
26
|
+
};
|
|
27
|
+
// ── Main ─────────────────────────────────────────────────────────
|
|
28
|
+
export async function runSetup() {
|
|
29
|
+
if (!process.stdin.isTTY) {
|
|
30
|
+
console.error(chalk.red(` ${t('needs_tty')}`));
|
|
31
|
+
process.exit(1);
|
|
32
|
+
}
|
|
33
|
+
// Load existing config to detect saved language
|
|
34
|
+
const existing = await loadUserConfigSafe();
|
|
35
|
+
if (existing?.language) {
|
|
36
|
+
setLocale(existing.language);
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
setLocale(detectLocale());
|
|
40
|
+
}
|
|
41
|
+
try {
|
|
42
|
+
await runSetupFlow(existing);
|
|
43
|
+
}
|
|
44
|
+
catch (err) {
|
|
45
|
+
if (err instanceof UserCancelledError) {
|
|
46
|
+
console.log('');
|
|
47
|
+
console.log(chalk.yellow(` ${t('setup_cancelled')}`));
|
|
48
|
+
console.log('');
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
throw err;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
async function runSetupFlow(_existing) {
|
|
55
|
+
// ── Language selection (first) ─────────────────────────────
|
|
56
|
+
console.log('');
|
|
57
|
+
console.log(chalk.gray(S.CORNER_TL));
|
|
58
|
+
const langOptions = [
|
|
59
|
+
{ label: 'English', value: 'en' },
|
|
60
|
+
{ label: '日本語', value: 'ja' },
|
|
61
|
+
];
|
|
62
|
+
const langDefault = getLocale() === 'ja' ? 1 : 0;
|
|
63
|
+
const langIdx = await interactiveSelect(t('setup_language'), langOptions, langDefault);
|
|
64
|
+
const language = langOptions[langIdx].value;
|
|
65
|
+
setLocale(language);
|
|
66
|
+
// ── Title ──────────────────────────────────────────────────
|
|
67
|
+
console.log(chalk.gray(S.BAR));
|
|
68
|
+
console.log(chalk.gray(S.BAR) + chalk.cyan.bold(` ${t('setup_title')}`));
|
|
69
|
+
console.log(chalk.gray(S.BAR));
|
|
70
|
+
// ── Step 1: CLI Detection ──────────────────────────────────
|
|
71
|
+
console.log(chalk.cyan(S.STEP_ACTIVE) + chalk.bold(` ${t('setup_step_detect')}`));
|
|
72
|
+
const detection = await detectAvailableCLIs();
|
|
73
|
+
const status = (name, available) => {
|
|
74
|
+
const icon = available ? chalk.green('✓') : chalk.dim('✗');
|
|
75
|
+
const label = available ? t('setup_installed') : t('setup_not_installed');
|
|
76
|
+
return `${chalk.gray(S.BAR)} ${icon} ${chalk.white(name)} ${chalk.dim(label)}`;
|
|
77
|
+
};
|
|
78
|
+
console.log(status('Claude Code', detection.claude.available));
|
|
79
|
+
console.log(status('Codex CLI ', detection.codex.available));
|
|
80
|
+
console.log(status('Gemini CLI ', detection.gemini.available));
|
|
81
|
+
const available = getAvailableUnits(detection);
|
|
82
|
+
if (available.length === 0) {
|
|
83
|
+
console.log(chalk.gray(S.BAR));
|
|
84
|
+
console.log(chalk.gray(S.BAR_END) + chalk.red(` ${t('setup_no_cli')}`));
|
|
85
|
+
console.log(chalk.dim(` ${t('setup_no_cli_hint')}`));
|
|
86
|
+
console.log('');
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
console.log(chalk.gray(S.BAR));
|
|
90
|
+
// ── Step 2: Configuration ──────────────────────────────────
|
|
91
|
+
const suggestions = suggestConfigurations(detection);
|
|
92
|
+
let enabledUnits;
|
|
93
|
+
if (suggestions.length <= 1) {
|
|
94
|
+
enabledUnits = suggestions[0]?.enabledUnits ?? available;
|
|
95
|
+
const display = enabledUnits.map(u => UNIT_NAMES[u]).join(' + ');
|
|
96
|
+
console.log(chalk.cyan(S.STEP_DONE) + chalk.dim(` ${t('setup_select_config')} `) + chalk.white(display));
|
|
97
|
+
}
|
|
98
|
+
else {
|
|
99
|
+
const configOptions = suggestions.map(s => ({
|
|
100
|
+
label: s.enabledUnits.map(u => UNIT_NAMES[u]).join(' + '),
|
|
101
|
+
value: String(s.unitCount),
|
|
102
|
+
hint: s.unitCount === 3 ? t('setup_all_ai')
|
|
103
|
+
: s.unitCount === 2 ? t('setup_two_ai')
|
|
104
|
+
: t('setup_single'),
|
|
105
|
+
recommended: s.recommended,
|
|
106
|
+
}));
|
|
107
|
+
const recIdx = suggestions.findIndex(s => s.recommended);
|
|
108
|
+
const selected = await interactiveSelect(t('setup_select_config'), configOptions, Math.max(0, recIdx));
|
|
109
|
+
enabledUnits = suggestions[selected].enabledUnits;
|
|
110
|
+
}
|
|
111
|
+
// ── Step 3: Settings ───────────────────────────────────────
|
|
112
|
+
console.log(chalk.gray(S.BAR));
|
|
113
|
+
console.log(chalk.gray(S.BAR) + chalk.dim(` ${t('setup_defaults_ok')}`));
|
|
114
|
+
console.log(chalk.gray(S.BAR));
|
|
115
|
+
// Rounds
|
|
116
|
+
const roundOptions = [
|
|
117
|
+
{ label: '1', value: '1', hint: t('setup_rounds_1') },
|
|
118
|
+
{ label: '2', value: '2', hint: t('setup_rounds_2') },
|
|
119
|
+
{ label: '3', value: '3', hint: t('setup_rounds_3'), recommended: true },
|
|
120
|
+
{ label: '5', value: '5', hint: t('setup_rounds_5') },
|
|
121
|
+
];
|
|
122
|
+
const roundIdx = await interactiveSelect(t('setup_rounds'), roundOptions, 2);
|
|
123
|
+
const maxRounds = parseInt(roundOptions[roundIdx].value, 10);
|
|
124
|
+
// Early exit
|
|
125
|
+
const earlyConsensusExit = await interactiveConfirm(t('setup_early_exit'), true);
|
|
126
|
+
// Deadlock
|
|
127
|
+
const deadlockOptions = buildDeadlockOptions(enabledUnits);
|
|
128
|
+
const deadlockIdx = await interactiveSelect(t('setup_deadlock'), deadlockOptions, 0);
|
|
129
|
+
const deadlockStrategy = deadlockOptions[deadlockIdx].value;
|
|
130
|
+
// TUI
|
|
131
|
+
const tuiEnabled = await interactiveConfirm(t('setup_tui'), true);
|
|
132
|
+
// File access
|
|
133
|
+
const fileAccessEnabled = await interactiveConfirm(t('setup_file_access'), false);
|
|
134
|
+
// ── Save ───────────────────────────────────────────────────
|
|
135
|
+
console.log(chalk.gray(S.BAR));
|
|
136
|
+
const config = {
|
|
137
|
+
enabledUnits,
|
|
138
|
+
defaultPipeline: {
|
|
139
|
+
maxRounds,
|
|
140
|
+
earlyConsensusExit,
|
|
141
|
+
consensus: { deadlockStrategy: deadlockStrategy },
|
|
142
|
+
},
|
|
143
|
+
tui: { enabled: tuiEnabled },
|
|
144
|
+
fileAccess: { enabled: fileAccessEnabled },
|
|
145
|
+
language,
|
|
146
|
+
};
|
|
147
|
+
await saveUserConfig(config);
|
|
148
|
+
console.log(chalk.gray(S.BAR_END) + chalk.green(` ${t('setup_saved')} `) + chalk.dim(t('setup_saved_path')));
|
|
149
|
+
console.log('');
|
|
150
|
+
console.log(chalk.dim(` ${t('setup_hint_config')}`));
|
|
151
|
+
console.log(chalk.dim(` ${t('setup_hint_reset')}`));
|
|
152
|
+
console.log('');
|
|
153
|
+
}
|
|
154
|
+
// ── Helpers ──────────────────────────────────────────────────────
|
|
155
|
+
function buildDeadlockOptions(enabledUnits) {
|
|
156
|
+
const options = [];
|
|
157
|
+
if (enabledUnits.includes('MELCHIOR')) {
|
|
158
|
+
options.push({
|
|
159
|
+
label: t('setup_deadlock_melchior'),
|
|
160
|
+
value: 'melchior-tiebreak',
|
|
161
|
+
hint: t('setup_deadlock_melchior_hint'),
|
|
162
|
+
recommended: true,
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
options.push({
|
|
166
|
+
label: t('setup_deadlock_confidence'),
|
|
167
|
+
value: 'highest-confidence',
|
|
168
|
+
hint: t('setup_deadlock_confidence_hint'),
|
|
169
|
+
recommended: !enabledUnits.includes('MELCHIOR'),
|
|
170
|
+
});
|
|
171
|
+
options.push({
|
|
172
|
+
label: t('setup_deadlock_escalate'),
|
|
173
|
+
value: 'escalate',
|
|
174
|
+
hint: t('setup_deadlock_escalate_hint'),
|
|
175
|
+
});
|
|
176
|
+
options.push({
|
|
177
|
+
label: t('setup_deadlock_human'),
|
|
178
|
+
value: 'human-in-the-loop',
|
|
179
|
+
hint: t('setup_deadlock_human_hint'),
|
|
180
|
+
});
|
|
181
|
+
return options;
|
|
182
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minimal i18n for CLI commands (setup, config, etc.)
|
|
3
|
+
*
|
|
4
|
+
* TUI stays Japanese (Eva world-building).
|
|
5
|
+
* CLI setup/config supports ja/en.
|
|
6
|
+
*/
|
|
7
|
+
export type Locale = 'ja' | 'en';
|
|
8
|
+
export declare function getLocale(): Locale;
|
|
9
|
+
export declare function setLocale(locale: Locale): void;
|
|
10
|
+
/** Detect locale from environment or system settings. */
|
|
11
|
+
export declare function detectLocale(): Locale;
|
|
12
|
+
interface Messages {
|
|
13
|
+
setup_title: string;
|
|
14
|
+
setup_step_detect: string;
|
|
15
|
+
setup_step_config: string;
|
|
16
|
+
setup_step_settings: string;
|
|
17
|
+
setup_detecting: string;
|
|
18
|
+
setup_installed: string;
|
|
19
|
+
setup_not_installed: string;
|
|
20
|
+
setup_no_cli: string;
|
|
21
|
+
setup_no_cli_hint: string;
|
|
22
|
+
setup_select_config: string;
|
|
23
|
+
setup_select_config_hint: string;
|
|
24
|
+
setup_all_ai: string;
|
|
25
|
+
setup_two_ai: string;
|
|
26
|
+
setup_single: string;
|
|
27
|
+
setup_recommended: string;
|
|
28
|
+
setup_rounds: string;
|
|
29
|
+
setup_rounds_1: string;
|
|
30
|
+
setup_rounds_2: string;
|
|
31
|
+
setup_rounds_3: string;
|
|
32
|
+
setup_rounds_5: string;
|
|
33
|
+
setup_early_exit: string;
|
|
34
|
+
setup_early_exit_hint: string;
|
|
35
|
+
setup_deadlock: string;
|
|
36
|
+
setup_deadlock_melchior: string;
|
|
37
|
+
setup_deadlock_melchior_hint: string;
|
|
38
|
+
setup_deadlock_confidence: string;
|
|
39
|
+
setup_deadlock_confidence_hint: string;
|
|
40
|
+
setup_deadlock_escalate: string;
|
|
41
|
+
setup_deadlock_escalate_hint: string;
|
|
42
|
+
setup_deadlock_human: string;
|
|
43
|
+
setup_deadlock_human_hint: string;
|
|
44
|
+
setup_tui: string;
|
|
45
|
+
setup_tui_hint: string;
|
|
46
|
+
setup_file_access: string;
|
|
47
|
+
setup_file_access_hint: string;
|
|
48
|
+
setup_language: string;
|
|
49
|
+
setup_saved: string;
|
|
50
|
+
setup_saved_path: string;
|
|
51
|
+
setup_hint_config: string;
|
|
52
|
+
setup_hint_reset: string;
|
|
53
|
+
setup_defaults_ok: string;
|
|
54
|
+
setup_cancelled: string;
|
|
55
|
+
yes: string;
|
|
56
|
+
no: string;
|
|
57
|
+
config_title: string;
|
|
58
|
+
config_no_file: string;
|
|
59
|
+
config_no_file_hint: string;
|
|
60
|
+
config_file: string;
|
|
61
|
+
config_units: string;
|
|
62
|
+
config_max_rounds: string;
|
|
63
|
+
config_early_exit: string;
|
|
64
|
+
config_deadlock: string;
|
|
65
|
+
config_quorum: string;
|
|
66
|
+
config_phase_timeout: string;
|
|
67
|
+
config_tui: string;
|
|
68
|
+
config_sound: string;
|
|
69
|
+
config_log_level: string;
|
|
70
|
+
config_output_format: string;
|
|
71
|
+
config_cache: string;
|
|
72
|
+
config_file_access: string;
|
|
73
|
+
config_language: string;
|
|
74
|
+
config_change_hint: string;
|
|
75
|
+
config_reset_hint: string;
|
|
76
|
+
config_set_ok: string;
|
|
77
|
+
config_set_invalid: string;
|
|
78
|
+
config_set_usage: string;
|
|
79
|
+
config_reset_ok: string;
|
|
80
|
+
config_reset_none: string;
|
|
81
|
+
config_unknown_action: string;
|
|
82
|
+
on: string;
|
|
83
|
+
off: string;
|
|
84
|
+
nav_hint: string;
|
|
85
|
+
needs_tty: string;
|
|
86
|
+
}
|
|
87
|
+
/** Get localized message. */
|
|
88
|
+
export declare function t(key: keyof Messages): string;
|
|
89
|
+
export {};
|