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.
Files changed (300) hide show
  1. package/LICENSE +21 -0
  2. package/README.ja.md +377 -0
  3. package/README.md +377 -0
  4. package/dist/bin/magi-benchmark.d.ts +14 -0
  5. package/dist/bin/magi-benchmark.js +93 -0
  6. package/dist/bin/magi-mcp.d.ts +8 -0
  7. package/dist/bin/magi-mcp.js +28 -0
  8. package/dist/bin/magi.d.ts +2 -0
  9. package/dist/bin/magi.js +634 -0
  10. package/dist/src/adapters/base.d.ts +34 -0
  11. package/dist/src/adapters/base.js +149 -0
  12. package/dist/src/adapters/claude.d.ts +29 -0
  13. package/dist/src/adapters/claude.js +65 -0
  14. package/dist/src/adapters/codex.d.ts +21 -0
  15. package/dist/src/adapters/codex.js +41 -0
  16. package/dist/src/adapters/gemini.d.ts +18 -0
  17. package/dist/src/adapters/gemini.js +31 -0
  18. package/dist/src/adapters/registry.d.ts +19 -0
  19. package/dist/src/adapters/registry.js +59 -0
  20. package/dist/src/audit/hash-chain.d.ts +21 -0
  21. package/dist/src/audit/hash-chain.js +70 -0
  22. package/dist/src/audit/types.d.ts +25 -0
  23. package/dist/src/audit/types.js +1 -0
  24. package/dist/src/audit/writer.d.ts +18 -0
  25. package/dist/src/audit/writer.js +100 -0
  26. package/dist/src/benchmark/golden-tasks.d.ts +9 -0
  27. package/dist/src/benchmark/golden-tasks.js +476 -0
  28. package/dist/src/benchmark/reporter.d.ts +5 -0
  29. package/dist/src/benchmark/reporter.js +107 -0
  30. package/dist/src/benchmark/runner.d.ts +30 -0
  31. package/dist/src/benchmark/runner.js +224 -0
  32. package/dist/src/benchmark/scorer.d.ts +12 -0
  33. package/dist/src/benchmark/scorer.js +124 -0
  34. package/dist/src/benchmark/types.d.ts +54 -0
  35. package/dist/src/benchmark/types.js +1 -0
  36. package/dist/src/cache/deliberation-cache.d.ts +49 -0
  37. package/dist/src/cache/deliberation-cache.js +127 -0
  38. package/dist/src/cli/commands/config-cmd.d.ts +11 -0
  39. package/dist/src/cli/commands/config-cmd.js +190 -0
  40. package/dist/src/cli/commands/demo.d.ts +12 -0
  41. package/dist/src/cli/commands/demo.js +66 -0
  42. package/dist/src/cli/commands/setup.d.ts +7 -0
  43. package/dist/src/cli/commands/setup.js +182 -0
  44. package/dist/src/cli/i18n.d.ts +89 -0
  45. package/dist/src/cli/i18n.js +176 -0
  46. package/dist/src/cli/interactive-select.d.ts +27 -0
  47. package/dist/src/cli/interactive-select.js +130 -0
  48. package/dist/src/cli/tui-setup.d.ts +24 -0
  49. package/dist/src/cli/tui-setup.js +42 -0
  50. package/dist/src/config/cli-detector.d.ts +37 -0
  51. package/dist/src/config/cli-detector.js +99 -0
  52. package/dist/src/config/user-config.d.ts +81 -0
  53. package/dist/src/config/user-config.js +134 -0
  54. package/dist/src/context/auto-collector.d.ts +43 -0
  55. package/dist/src/context/auto-collector.js +337 -0
  56. package/dist/src/context/manager.d.ts +35 -0
  57. package/dist/src/context/manager.js +162 -0
  58. package/dist/src/context/serializer.d.ts +20 -0
  59. package/dist/src/context/serializer.js +52 -0
  60. package/dist/src/demo/recorded-deliberation.d.ts +13 -0
  61. package/dist/src/demo/recorded-deliberation.js +277 -0
  62. package/dist/src/engine/angel-detector.d.ts +83 -0
  63. package/dist/src/engine/angel-detector.js +334 -0
  64. package/dist/src/engine/at-field.d.ts +40 -0
  65. package/dist/src/engine/at-field.js +195 -0
  66. package/dist/src/engine/berserk-orchestrator.d.ts +66 -0
  67. package/dist/src/engine/berserk-orchestrator.js +378 -0
  68. package/dist/src/engine/change-metrics.d.ts +56 -0
  69. package/dist/src/engine/change-metrics.js +214 -0
  70. package/dist/src/engine/consensus.d.ts +20 -0
  71. package/dist/src/engine/consensus.js +146 -0
  72. package/dist/src/engine/dead-sea-scrolls.d.ts +132 -0
  73. package/dist/src/engine/dead-sea-scrolls.js +610 -0
  74. package/dist/src/engine/drift-detector.d.ts +39 -0
  75. package/dist/src/engine/drift-detector.js +225 -0
  76. package/dist/src/engine/dummy-plug.d.ts +44 -0
  77. package/dist/src/engine/dummy-plug.js +190 -0
  78. package/dist/src/engine/engram-manager.d.ts +55 -0
  79. package/dist/src/engine/engram-manager.js +306 -0
  80. package/dist/src/engine/events.d.ts +130 -0
  81. package/dist/src/engine/events.js +44 -0
  82. package/dist/src/engine/gospel.d.ts +30 -0
  83. package/dist/src/engine/gospel.js +129 -0
  84. package/dist/src/engine/hallucination-detector.d.ts +33 -0
  85. package/dist/src/engine/hallucination-detector.js +215 -0
  86. package/dist/src/engine/human-resolver.d.ts +19 -0
  87. package/dist/src/engine/human-resolver.js +89 -0
  88. package/dist/src/engine/instrumentality.d.ts +64 -0
  89. package/dist/src/engine/instrumentality.js +297 -0
  90. package/dist/src/engine/iruel-battle.d.ts +79 -0
  91. package/dist/src/engine/iruel-battle.js +319 -0
  92. package/dist/src/engine/kernel/deliberation-kernel.d.ts +12 -0
  93. package/dist/src/engine/kernel/deliberation-kernel.js +303 -0
  94. package/dist/src/engine/kernel/index.d.ts +8 -0
  95. package/dist/src/engine/kernel/index.js +7 -0
  96. package/dist/src/engine/kernel/phase-runner.d.ts +10 -0
  97. package/dist/src/engine/kernel/phase-runner.js +155 -0
  98. package/dist/src/engine/kernel/post-processor.d.ts +17 -0
  99. package/dist/src/engine/kernel/post-processor.js +131 -0
  100. package/dist/src/engine/kernel/types.d.ts +107 -0
  101. package/dist/src/engine/kernel/types.js +1 -0
  102. package/dist/src/engine/kernel/unit-executor.d.ts +6 -0
  103. package/dist/src/engine/kernel/unit-executor.js +132 -0
  104. package/dist/src/engine/lcl-manager.d.ts +44 -0
  105. package/dist/src/engine/lcl-manager.js +143 -0
  106. package/dist/src/engine/middleware/cache.d.ts +7 -0
  107. package/dist/src/engine/middleware/cache.js +29 -0
  108. package/dist/src/engine/middleware/chain.d.ts +18 -0
  109. package/dist/src/engine/middleware/chain.js +45 -0
  110. package/dist/src/engine/middleware/firewall.d.ts +8 -0
  111. package/dist/src/engine/middleware/firewall.js +24 -0
  112. package/dist/src/engine/middleware/index.d.ts +4 -0
  113. package/dist/src/engine/middleware/index.js +3 -0
  114. package/dist/src/engine/middleware/types.d.ts +43 -0
  115. package/dist/src/engine/middleware/types.js +1 -0
  116. package/dist/src/engine/nebuchadnezzar-key.d.ts +61 -0
  117. package/dist/src/engine/nebuchadnezzar-key.js +203 -0
  118. package/dist/src/engine/neon-genesis.d.ts +52 -0
  119. package/dist/src/engine/neon-genesis.js +203 -0
  120. package/dist/src/engine/objective-judge.d.ts +53 -0
  121. package/dist/src/engine/objective-judge.js +214 -0
  122. package/dist/src/engine/offline-mode.d.ts +18 -0
  123. package/dist/src/engine/offline-mode.js +46 -0
  124. package/dist/src/engine/orchestrator.d.ts +79 -0
  125. package/dist/src/engine/orchestrator.js +58 -0
  126. package/dist/src/engine/secret-cipher.d.ts +26 -0
  127. package/dist/src/engine/secret-cipher.js +114 -0
  128. package/dist/src/engine/seele-council.d.ts +90 -0
  129. package/dist/src/engine/seele-council.js +482 -0
  130. package/dist/src/engine/self-destruct.d.ts +61 -0
  131. package/dist/src/engine/self-destruct.js +231 -0
  132. package/dist/src/engine/self-evolution.d.ts +64 -0
  133. package/dist/src/engine/self-evolution.js +368 -0
  134. package/dist/src/engine/sync-rate.d.ts +45 -0
  135. package/dist/src/engine/sync-rate.js +151 -0
  136. package/dist/src/engine/type666-firewall.d.ts +76 -0
  137. package/dist/src/engine/type666-firewall.js +343 -0
  138. package/dist/src/engine/umbilical-cable.d.ts +41 -0
  139. package/dist/src/engine/umbilical-cable.js +192 -0
  140. package/dist/src/index.d.ts +106 -0
  141. package/dist/src/index.js +426 -0
  142. package/dist/src/mcp/server.d.ts +38 -0
  143. package/dist/src/mcp/server.js +196 -0
  144. package/dist/src/metrics/token-tracker.d.ts +38 -0
  145. package/dist/src/metrics/token-tracker.js +112 -0
  146. package/dist/src/parsers/json-extractor.d.ts +9 -0
  147. package/dist/src/parsers/json-extractor.js +239 -0
  148. package/dist/src/parsers/opinion-schema.d.ts +81 -0
  149. package/dist/src/parsers/opinion-schema.js +147 -0
  150. package/dist/src/parsers/unstructured-parser.d.ts +20 -0
  151. package/dist/src/parsers/unstructured-parser.js +122 -0
  152. package/dist/src/pipelines/architecture.d.ts +10 -0
  153. package/dist/src/pipelines/architecture.js +9 -0
  154. package/dist/src/pipelines/bug-analysis.d.ts +9 -0
  155. package/dist/src/pipelines/bug-analysis.js +8 -0
  156. package/dist/src/pipelines/code-review.d.ts +10 -0
  157. package/dist/src/pipelines/code-review.js +30 -0
  158. package/dist/src/pipelines/custom.d.ts +14 -0
  159. package/dist/src/pipelines/custom.js +29 -0
  160. package/dist/src/pipelines/registry.d.ts +9 -0
  161. package/dist/src/pipelines/registry.js +20 -0
  162. package/dist/src/prompts/personas.d.ts +6 -0
  163. package/dist/src/prompts/personas.js +44 -0
  164. package/dist/src/prompts/schemas.d.ts +4 -0
  165. package/dist/src/prompts/schemas.js +24 -0
  166. package/dist/src/prompts/templates.d.ts +6 -0
  167. package/dist/src/prompts/templates.js +91 -0
  168. package/dist/src/repl/accessibility.d.ts +23 -0
  169. package/dist/src/repl/accessibility.js +46 -0
  170. package/dist/src/repl/banner.d.ts +4 -0
  171. package/dist/src/repl/banner.js +28 -0
  172. package/dist/src/repl/boot-animation.d.ts +13 -0
  173. package/dist/src/repl/boot-animation.js +143 -0
  174. package/dist/src/repl/completer.d.ts +21 -0
  175. package/dist/src/repl/completer.js +168 -0
  176. package/dist/src/repl/context.d.ts +24 -0
  177. package/dist/src/repl/context.js +42 -0
  178. package/dist/src/repl/display-utils.d.ts +13 -0
  179. package/dist/src/repl/display-utils.js +65 -0
  180. package/dist/src/repl/event-listener.d.ts +18 -0
  181. package/dist/src/repl/event-listener.js +112 -0
  182. package/dist/src/repl/export-formatter.d.ts +8 -0
  183. package/dist/src/repl/export-formatter.js +73 -0
  184. package/dist/src/repl/ghost-text.d.ts +31 -0
  185. package/dist/src/repl/ghost-text.js +119 -0
  186. package/dist/src/repl/handoff-animation.d.ts +15 -0
  187. package/dist/src/repl/handoff-animation.js +65 -0
  188. package/dist/src/repl/history.d.ts +16 -0
  189. package/dist/src/repl/history.js +130 -0
  190. package/dist/src/repl/job-registry.d.ts +26 -0
  191. package/dist/src/repl/job-registry.js +80 -0
  192. package/dist/src/repl/magi-repl.d.ts +72 -0
  193. package/dist/src/repl/magi-repl.js +1008 -0
  194. package/dist/src/repl/multiline-input.d.ts +45 -0
  195. package/dist/src/repl/multiline-input.js +78 -0
  196. package/dist/src/repl/prompt-builder.d.ts +19 -0
  197. package/dist/src/repl/prompt-builder.js +36 -0
  198. package/dist/src/repl/repl-state.d.ts +5 -0
  199. package/dist/src/repl/repl-state.js +19 -0
  200. package/dist/src/repl/result-display.d.ts +8 -0
  201. package/dist/src/repl/result-display.js +195 -0
  202. package/dist/src/repl/session-stats.d.ts +26 -0
  203. package/dist/src/repl/session-stats.js +119 -0
  204. package/dist/src/repl/slash-commands.d.ts +60 -0
  205. package/dist/src/repl/slash-commands.js +725 -0
  206. package/dist/src/repl/terminal-sanitize.d.ts +14 -0
  207. package/dist/src/repl/terminal-sanitize.js +19 -0
  208. package/dist/src/reporters/console.d.ts +7 -0
  209. package/dist/src/reporters/console.js +78 -0
  210. package/dist/src/reporters/json.d.ts +2 -0
  211. package/dist/src/reporters/json.js +3 -0
  212. package/dist/src/reporters/markdown.d.ts +2 -0
  213. package/dist/src/reporters/markdown.js +65 -0
  214. package/dist/src/reporters/streaming.d.ts +20 -0
  215. package/dist/src/reporters/streaming.js +178 -0
  216. package/dist/src/tui/activity-log.d.ts +23 -0
  217. package/dist/src/tui/activity-log.js +67 -0
  218. package/dist/src/tui/animations.d.ts +39 -0
  219. package/dist/src/tui/animations.js +167 -0
  220. package/dist/src/tui/ansi.d.ts +28 -0
  221. package/dist/src/tui/ansi.js +51 -0
  222. package/dist/src/tui/boot-sequence.d.ts +11 -0
  223. package/dist/src/tui/boot-sequence.js +98 -0
  224. package/dist/src/tui/colors.d.ts +101 -0
  225. package/dist/src/tui/colors.js +71 -0
  226. package/dist/src/tui/header.d.ts +24 -0
  227. package/dist/src/tui/header.js +122 -0
  228. package/dist/src/tui/index.d.ts +3 -0
  229. package/dist/src/tui/index.js +3 -0
  230. package/dist/src/tui/keypress.d.ts +25 -0
  231. package/dist/src/tui/keypress.js +95 -0
  232. package/dist/src/tui/layout.d.ts +74 -0
  233. package/dist/src/tui/layout.js +171 -0
  234. package/dist/src/tui/magi-tui.d.ts +101 -0
  235. package/dist/src/tui/magi-tui.js +754 -0
  236. package/dist/src/tui/panel.d.ts +45 -0
  237. package/dist/src/tui/panel.js +292 -0
  238. package/dist/src/tui/screen-buffer.d.ts +54 -0
  239. package/dist/src/tui/screen-buffer.js +262 -0
  240. package/dist/src/tui/status-bar.d.ts +25 -0
  241. package/dist/src/tui/status-bar.js +124 -0
  242. package/dist/src/tui/terminal-detect.d.ts +26 -0
  243. package/dist/src/tui/terminal-detect.js +44 -0
  244. package/dist/src/tui/tui-helpers.d.ts +12 -0
  245. package/dist/src/tui/tui-helpers.js +37 -0
  246. package/dist/src/types/adapter.d.ts +75 -0
  247. package/dist/src/types/adapter.js +36 -0
  248. package/dist/src/types/config.d.ts +108 -0
  249. package/dist/src/types/config.js +85 -0
  250. package/dist/src/types/consensus.d.ts +55 -0
  251. package/dist/src/types/consensus.js +17 -0
  252. package/dist/src/types/core.d.ts +178 -0
  253. package/dist/src/types/core.js +85 -0
  254. package/dist/src/types/magi-api.d.ts +62 -0
  255. package/dist/src/types/magi-api.js +7 -0
  256. package/dist/src/types/phase-h.d.ts +142 -0
  257. package/dist/src/types/phase-h.js +7 -0
  258. package/dist/src/types/phase-i.d.ts +186 -0
  259. package/dist/src/types/phase-i.js +6 -0
  260. package/dist/src/types/phase-k.d.ts +259 -0
  261. package/dist/src/types/phase-k.js +6 -0
  262. package/dist/src/types/phase-l.d.ts +199 -0
  263. package/dist/src/types/phase-l.js +6 -0
  264. package/dist/src/types/pipeline.d.ts +37 -0
  265. package/dist/src/types/pipeline.js +2 -0
  266. package/dist/src/utils/abstain-factory.d.ts +2 -0
  267. package/dist/src/utils/abstain-factory.js +18 -0
  268. package/dist/src/utils/errors.d.ts +34 -0
  269. package/dist/src/utils/errors.js +59 -0
  270. package/dist/src/utils/file-validator.d.ts +50 -0
  271. package/dist/src/utils/file-validator.js +124 -0
  272. package/dist/src/utils/fire-and-forget.d.ts +5 -0
  273. package/dist/src/utils/fire-and-forget.js +10 -0
  274. package/dist/src/utils/flag-validator.d.ts +21 -0
  275. package/dist/src/utils/flag-validator.js +79 -0
  276. package/dist/src/utils/freeze.d.ts +8 -0
  277. package/dist/src/utils/freeze.js +16 -0
  278. package/dist/src/utils/language-detector.d.ts +16 -0
  279. package/dist/src/utils/language-detector.js +159 -0
  280. package/dist/src/utils/latency-tracker.d.ts +45 -0
  281. package/dist/src/utils/latency-tracker.js +100 -0
  282. package/dist/src/utils/logger.d.ts +33 -0
  283. package/dist/src/utils/logger.js +112 -0
  284. package/dist/src/utils/process.d.ts +40 -0
  285. package/dist/src/utils/process.js +253 -0
  286. package/dist/src/utils/retry.d.ts +12 -0
  287. package/dist/src/utils/retry.js +30 -0
  288. package/dist/src/utils/safe-fs.d.ts +38 -0
  289. package/dist/src/utils/safe-fs.js +56 -0
  290. package/dist/src/utils/safe-json-parse.d.ts +15 -0
  291. package/dist/src/utils/safe-json-parse.js +49 -0
  292. package/dist/src/utils/sanitize.d.ts +14 -0
  293. package/dist/src/utils/sanitize.js +186 -0
  294. package/dist/src/utils/semaphore.d.ts +22 -0
  295. package/dist/src/utils/semaphore.js +57 -0
  296. package/dist/src/utils/shutdown.d.ts +6 -0
  297. package/dist/src/utils/shutdown.js +51 -0
  298. package/dist/src/utils/tty.d.ts +5 -0
  299. package/dist/src/utils/tty.js +7 -0
  300. package/package.json +82 -0
@@ -0,0 +1,214 @@
1
+ import { logger } from '../utils/logger.js';
2
+ /** Weights for each tool in the composite score */
3
+ const TOOL_WEIGHTS = {
4
+ tsc: 0.4,
5
+ eslint: 0.2,
6
+ vitest: 0.4,
7
+ };
8
+ /**
9
+ * ObjectiveJudge: runs static analysis and tests to produce an objective
10
+ * quality score that supplements the subjective AI opinions.
11
+ *
12
+ * Graceful degradation: if a tool is not available, it's skipped and
13
+ * the score is calculated from available tools only.
14
+ */
15
+ export class ObjectiveJudge {
16
+ cwd;
17
+ runCommand;
18
+ constructor(cwd, runCommand) {
19
+ this.cwd = cwd;
20
+ this.runCommand = runCommand ?? ObjectiveJudge.defaultRunCommand;
21
+ }
22
+ static async defaultRunCommand(cmd, args, cwd) {
23
+ const { spawnProcess } = await import('../utils/process.js');
24
+ const result = await spawnProcess({ command: cmd, args, cwd, timeoutMs: 120_000 });
25
+ return { stdout: result.stdout, stderr: result.stderr, exitCode: result.exitCode };
26
+ }
27
+ async evaluate() {
28
+ const results = await Promise.allSettled([
29
+ this.runTsc(),
30
+ this.runEslint(),
31
+ this.runVitest(),
32
+ ]);
33
+ const toolNames = ['tsc', 'eslint', 'vitest'];
34
+ const tools = results.map((r, i) => {
35
+ const toolName = toolNames[i];
36
+ if (r.status === 'fulfilled')
37
+ return r.value;
38
+ logger.warn(`ObjectiveJudge: ${toolName} failed`, { error: String(r.reason) });
39
+ return {
40
+ tool: toolName,
41
+ available: false,
42
+ passed: false,
43
+ issues: [],
44
+ summary: `${toolName} failed to run: ${String(r.reason)}`,
45
+ };
46
+ });
47
+ const score = this.calculateScore(tools);
48
+ const summary = this.buildSummary(tools, score);
49
+ return {
50
+ score,
51
+ tools,
52
+ summary,
53
+ evaluatedAt: new Date(),
54
+ };
55
+ }
56
+ calculateScore(tools) {
57
+ const available = tools.filter(t => t.available);
58
+ if (available.length === 0)
59
+ return 0.5; // No tools available -> neutral score
60
+ const totalWeight = available.reduce((sum, t) => sum + TOOL_WEIGHTS[t.tool], 0);
61
+ const weightedSum = available.reduce((sum, t) => {
62
+ const errorCount = t.issues.filter(i => i.severity === 'error').length;
63
+ const toolScore = t.passed ? 1.0 : Math.max(0, 1.0 - errorCount * 0.1);
64
+ return sum + toolScore * TOOL_WEIGHTS[t.tool];
65
+ }, 0);
66
+ return Math.max(0, Math.min(1, weightedSum / totalWeight));
67
+ }
68
+ buildSummary(tools, score) {
69
+ const lines = [`Objective Score: ${(score * 100).toFixed(1)}%`];
70
+ for (const t of tools) {
71
+ const status = !t.available ? 'N/A' : t.passed ? 'PASS' : 'FAIL';
72
+ const issueCount = t.issues.length;
73
+ lines.push(` ${t.tool}: ${status}${issueCount > 0 ? ` (${issueCount} issues)` : ''}`);
74
+ }
75
+ return lines.join('\n');
76
+ }
77
+ // ---- Tool runners ----
78
+ async runTsc() {
79
+ try {
80
+ const result = await this.runCommand('./node_modules/.bin/tsc', ['--noEmit', '--pretty', 'false'], this.cwd);
81
+ const issues = this.parseTscOutput(result.stdout + result.stderr);
82
+ return {
83
+ tool: 'tsc',
84
+ available: true,
85
+ passed: result.exitCode === 0,
86
+ issues,
87
+ summary: result.exitCode === 0 ? 'No type errors' : `${issues.length} type error(s)`,
88
+ rawOutput: (result.stdout + result.stderr).slice(0, 5000),
89
+ };
90
+ }
91
+ catch (err) {
92
+ logger.debug('ObjectiveJudge: tsc execution failed', { error: String(err) });
93
+ return { tool: 'tsc', available: false, passed: false, issues: [], summary: 'tsc not available' };
94
+ }
95
+ }
96
+ async runEslint() {
97
+ try {
98
+ const result = await this.runCommand('./node_modules/.bin/eslint', ['.', '--format', 'json', '--no-error-on-unmatched-pattern'], this.cwd);
99
+ const issues = this.parseEslintOutput(result.stdout);
100
+ return {
101
+ tool: 'eslint',
102
+ available: true,
103
+ passed: result.exitCode === 0,
104
+ issues,
105
+ summary: result.exitCode === 0 ? 'No lint issues' : `${issues.length} lint issue(s)`,
106
+ rawOutput: result.stdout.slice(0, 5000),
107
+ };
108
+ }
109
+ catch (err) {
110
+ logger.debug('ObjectiveJudge: eslint execution failed', { error: String(err) });
111
+ return { tool: 'eslint', available: false, passed: false, issues: [], summary: 'eslint not available' };
112
+ }
113
+ }
114
+ async runVitest() {
115
+ try {
116
+ const result = await this.runCommand('./node_modules/.bin/vitest', ['run', '--reporter=json'], this.cwd);
117
+ const issues = this.parseVitestOutput(result.stdout);
118
+ return {
119
+ tool: 'vitest',
120
+ available: true,
121
+ passed: result.exitCode === 0,
122
+ issues,
123
+ summary: result.exitCode === 0 ? 'All tests passed' : `${issues.length} test failure(s)`,
124
+ rawOutput: result.stdout.slice(0, 5000),
125
+ };
126
+ }
127
+ catch (err) {
128
+ logger.debug('ObjectiveJudge: vitest execution failed', { error: String(err) });
129
+ return { tool: 'vitest', available: false, passed: false, issues: [], summary: 'vitest not available' };
130
+ }
131
+ }
132
+ // ---- Output parsers ----
133
+ parseTscOutput(output) {
134
+ const issues = [];
135
+ // tsc format: file(line,col): error TSxxxx: message
136
+ const re = /^(.+?)\((\d+),\d+\):\s*(error|warning)\s+TS\d+:\s*(.+)$/gm;
137
+ let match;
138
+ while ((match = re.exec(output)) !== null) {
139
+ issues.push({
140
+ file: match[1],
141
+ line: parseInt(match[2], 10),
142
+ severity: match[3],
143
+ message: match[4],
144
+ rule: undefined,
145
+ });
146
+ }
147
+ return issues;
148
+ }
149
+ parseEslintOutput(output) {
150
+ const issues = [];
151
+ try {
152
+ const parsed = JSON.parse(output);
153
+ if (Array.isArray(parsed)) {
154
+ for (const file of parsed) {
155
+ for (const msg of file.messages ?? []) {
156
+ issues.push({
157
+ file: file.filePath,
158
+ line: msg.line,
159
+ severity: msg.severity === 2 ? 'error' : 'warning',
160
+ message: msg.message,
161
+ rule: msg.ruleId ?? undefined,
162
+ });
163
+ }
164
+ }
165
+ }
166
+ }
167
+ catch (err) {
168
+ logger.debug('ObjectiveJudge: eslint JSON parse failed, trying line-based', { error: String(err) });
169
+ const re = /^\s*(\d+):(\d+)\s+(error|warning)\s+(.+?)\s+(\S+)$/gm;
170
+ let match;
171
+ while ((match = re.exec(output)) !== null) {
172
+ issues.push({
173
+ line: parseInt(match[1], 10),
174
+ severity: match[3],
175
+ message: match[4],
176
+ rule: match[5],
177
+ });
178
+ }
179
+ }
180
+ return issues;
181
+ }
182
+ parseVitestOutput(output) {
183
+ const issues = [];
184
+ try {
185
+ const parsed = JSON.parse(output);
186
+ if (parsed.testResults && Array.isArray(parsed.testResults)) {
187
+ for (const suite of parsed.testResults) {
188
+ for (const test of suite.assertionResults ?? []) {
189
+ if (test.status === 'failed') {
190
+ issues.push({
191
+ file: suite.name,
192
+ severity: 'error',
193
+ message: test.fullName ?? test.title ?? 'Test failed',
194
+ rule: undefined,
195
+ });
196
+ }
197
+ }
198
+ }
199
+ }
200
+ }
201
+ catch (err) {
202
+ logger.debug('ObjectiveJudge: vitest JSON parse failed, trying FAIL line scan', { error: String(err) });
203
+ const re = /FAIL\s+(.+)/g;
204
+ let match;
205
+ while ((match = re.exec(output)) !== null) {
206
+ issues.push({
207
+ severity: 'error',
208
+ message: `Test suite failed: ${match[1]}`,
209
+ });
210
+ }
211
+ }
212
+ return issues;
213
+ }
214
+ }
@@ -0,0 +1,18 @@
1
+ /**
2
+ * B-09 オフラインモード (OfflineMode)
3
+ *
4
+ * 切断されたユニットの代替意見を生成する。
5
+ * DeliberationCacheから類似タスクを検索し、過去の意見をconfidence 0.5倍で再利用する。
6
+ * キャッシュミス時はABSTAIN (confidence=0.1) を返す。
7
+ */
8
+ import type { MagiUnit, MagiOpinion, MagiTask } from '../types/core.js';
9
+ import type { DeliberationCache } from '../cache/deliberation-cache.js';
10
+ export declare class OfflineMode {
11
+ private readonly cache?;
12
+ constructor(cache?: DeliberationCache | undefined);
13
+ /**
14
+ * Generate a fallback opinion for a disconnected unit.
15
+ * Searches cache for a similar task and uses the unit's previous opinion.
16
+ */
17
+ generateFallbackOpinion(unit: MagiUnit, task: MagiTask): MagiOpinion;
18
+ }
@@ -0,0 +1,46 @@
1
+ /**
2
+ * B-09 オフラインモード (OfflineMode)
3
+ *
4
+ * 切断されたユニットの代替意見を生成する。
5
+ * DeliberationCacheから類似タスクを検索し、過去の意見をconfidence 0.5倍で再利用する。
6
+ * キャッシュミス時はABSTAIN (confidence=0.1) を返す。
7
+ */
8
+ import { createAbstainOpinion } from '../utils/abstain-factory.js';
9
+ /** Confidence decay factor for cached opinions */
10
+ const CONFIDENCE_DECAY = 0.5;
11
+ /** Minimum confidence for ABSTAIN fallback */
12
+ const ABSTAIN_CONFIDENCE = 0.1;
13
+ export class OfflineMode {
14
+ cache;
15
+ constructor(cache) {
16
+ this.cache = cache;
17
+ }
18
+ /**
19
+ * Generate a fallback opinion for a disconnected unit.
20
+ * Searches cache for a similar task and uses the unit's previous opinion.
21
+ */
22
+ generateFallbackOpinion(unit, task) {
23
+ if (this.cache) {
24
+ const cached = this.cache.get(task);
25
+ if (cached) {
26
+ // Find the last round's opinion for this unit
27
+ const lastRound = cached.rounds[cached.rounds.length - 1];
28
+ const opinion = lastRound?.opinions.find(o => o.unit === unit);
29
+ if (opinion) {
30
+ return {
31
+ ...opinion,
32
+ confidence: opinion.confidence * CONFIDENCE_DECAY,
33
+ reasoning: `[OFFLINE] キャッシュから復元された意見 (confidence ${CONFIDENCE_DECAY}x減衰): ${opinion.reasoning}`,
34
+ keyPoints: [`[OFFLINE] キャッシュ復元`, ...opinion.keyPoints],
35
+ meta: {
36
+ ...opinion.meta,
37
+ durationMs: 0,
38
+ },
39
+ };
40
+ }
41
+ }
42
+ }
43
+ // Cache miss — return ABSTAIN
44
+ return createAbstainOpinion(unit, `[OFFLINE] ${unit} は切断中。キャッシュに該当する過去の審議結果なし。`, ['[OFFLINE] ユニット切断中', 'キャッシュミス — ABSTAIN'], { confidence: ABSTAIN_CONFIDENCE });
45
+ }
46
+ }
@@ -0,0 +1,79 @@
1
+ /**
2
+ * Orchestrator — Facade for the MAGI deliberation system.
3
+ *
4
+ * Delegates all deliberation logic to the kernel modules while
5
+ * preserving the same public API (OrchestratorOptions + deliberate()).
6
+ *
7
+ * Responsibilities retained here:
8
+ * - Task input validation (trust boundary)
9
+ * - Semaphore concurrency control
10
+ * - KernelDependencies assembly from OrchestratorOptions
11
+ */
12
+ import type { MagiTask, MagiDeliberation } from '../types/core.js';
13
+ import { AdapterRegistry } from '../adapters/registry.js';
14
+ import { PipelineRegistry } from '../pipelines/registry.js';
15
+ import { ContextManager } from '../context/manager.js';
16
+ import type { DeliberationCache } from '../cache/deliberation-cache.js';
17
+ import type { MagiEventBus } from './events.js';
18
+ import type { TokenTracker } from '../metrics/token-tracker.js';
19
+ import type { ObjectiveJudge } from './objective-judge.js';
20
+ import type { SyncRateTracker } from './sync-rate.js';
21
+ import type { ATField } from './at-field.js';
22
+ import type { GospelChronicle } from './gospel.js';
23
+ import type { UmbilicalCable } from './umbilical-cable.js';
24
+ import type { DummyPlugSystem } from './dummy-plug.js';
25
+ import type { OfflineMode } from './offline-mode.js';
26
+ import type { EngramManager } from './engram-manager.js';
27
+ import type { LCLManager } from './lcl-manager.js';
28
+ import type { InstrumentalityEngine } from './instrumentality.js';
29
+ import type { DriftDetector } from './drift-detector.js';
30
+ import type { Type666Firewall } from './type666-firewall.js';
31
+ import type { NebuchadnezzarKey } from './nebuchadnezzar-key.js';
32
+ import type { IruelBattleSystem } from './iruel-battle.js';
33
+ /** Options for constructing an Orchestrator */
34
+ export interface OrchestratorOptions {
35
+ adapters: AdapterRegistry;
36
+ pipelines: PipelineRegistry;
37
+ contextManager: ContextManager;
38
+ maxConcurrentDeliberations?: number;
39
+ cache?: DeliberationCache;
40
+ eventBus?: MagiEventBus;
41
+ tokenTracker?: TokenTracker;
42
+ objectiveJudge?: ObjectiveJudge;
43
+ syncRateTracker?: SyncRateTracker;
44
+ atField?: ATField;
45
+ gospel?: GospelChronicle;
46
+ umbilicalCable?: UmbilicalCable;
47
+ dummyPlug?: DummyPlugSystem;
48
+ offlineMode?: OfflineMode;
49
+ engramManager?: EngramManager;
50
+ lclManager?: LCLManager;
51
+ instrumentality?: InstrumentalityEngine;
52
+ driftDetector?: DriftDetector;
53
+ type666Firewall?: Type666Firewall;
54
+ nebuchadnezzarKey?: NebuchadnezzarKey;
55
+ iruelBattle?: IruelBattleSystem;
56
+ /** Allow CLIs to read project files during deliberation */
57
+ fileAccessEnabled?: boolean;
58
+ }
59
+ /**
60
+ * The heart of the MAGI System.
61
+ *
62
+ * Orchestrates multi-round deliberation between N MAGI units (2-7):
63
+ * 1. Initial Opinion (parallel) - each unit forms independent opinion
64
+ * 2. Cross-Examination (parallel) - each unit reviews others' opinions
65
+ * 3. Final Vote (parallel) - definitive vote with full context
66
+ *
67
+ * Security hardening:
68
+ * - Task input validated at trust boundary via MagiTaskSchema
69
+ * - Opinion output validated via SafeOpinionSchema (control chars stripped, size capped)
70
+ * - Concurrency limited by semaphore to prevent resource exhaustion
71
+ * - Phase-level and deliberation-level timeouts enforced
72
+ * - All lifecycle events emitted to audit log and event bus (fire-and-forget)
73
+ */
74
+ export declare class Orchestrator {
75
+ private readonly semaphore;
76
+ private readonly kernel;
77
+ constructor(options: OrchestratorOptions);
78
+ deliberate(task: MagiTask, signal?: AbortSignal): Promise<MagiDeliberation>;
79
+ }
@@ -0,0 +1,58 @@
1
+ import { MagiTaskSchema } from '../types/core.js';
2
+ import { Semaphore } from '../utils/semaphore.js';
3
+ import { LatencyTracker } from '../utils/latency-tracker.js';
4
+ import { DeliberationKernel } from './kernel/deliberation-kernel.js';
5
+ /**
6
+ * The heart of the MAGI System.
7
+ *
8
+ * Orchestrates multi-round deliberation between N MAGI units (2-7):
9
+ * 1. Initial Opinion (parallel) - each unit forms independent opinion
10
+ * 2. Cross-Examination (parallel) - each unit reviews others' opinions
11
+ * 3. Final Vote (parallel) - definitive vote with full context
12
+ *
13
+ * Security hardening:
14
+ * - Task input validated at trust boundary via MagiTaskSchema
15
+ * - Opinion output validated via SafeOpinionSchema (control chars stripped, size capped)
16
+ * - Concurrency limited by semaphore to prevent resource exhaustion
17
+ * - Phase-level and deliberation-level timeouts enforced
18
+ * - All lifecycle events emitted to audit log and event bus (fire-and-forget)
19
+ */
20
+ export class Orchestrator {
21
+ semaphore;
22
+ kernel;
23
+ constructor(options) {
24
+ this.semaphore = new Semaphore(options.maxConcurrentDeliberations ?? 3);
25
+ const deps = {
26
+ adapters: options.adapters,
27
+ pipelines: options.pipelines,
28
+ contextManager: options.contextManager,
29
+ latencyTracker: new LatencyTracker(),
30
+ eventBus: options.eventBus,
31
+ fileAccessEnabled: options.fileAccessEnabled,
32
+ modules: {
33
+ tokenTracker: options.tokenTracker,
34
+ objectiveJudge: options.objectiveJudge,
35
+ syncRateTracker: options.syncRateTracker,
36
+ atField: options.atField,
37
+ gospel: options.gospel,
38
+ umbilicalCable: options.umbilicalCable,
39
+ dummyPlug: options.dummyPlug,
40
+ offlineMode: options.offlineMode,
41
+ engramManager: options.engramManager,
42
+ lclManager: options.lclManager,
43
+ instrumentality: options.instrumentality,
44
+ driftDetector: options.driftDetector,
45
+ type666Firewall: options.type666Firewall,
46
+ nebuchadnezzarKey: options.nebuchadnezzarKey,
47
+ iruelBattle: options.iruelBattle,
48
+ cache: options.cache,
49
+ },
50
+ };
51
+ this.kernel = new DeliberationKernel(deps);
52
+ }
53
+ async deliberate(task, signal) {
54
+ // Validate task input at trust boundary
55
+ MagiTaskSchema.parse(task);
56
+ return this.semaphore.run(() => this.kernel.deliberate(task, signal));
57
+ }
58
+ }
@@ -0,0 +1,26 @@
1
+ /**
2
+ * B-08 裏コード (SecretCipher)
3
+ *
4
+ * MAGIシステムに隠されたメッセージ。AES-256-GCMで暗号化し、
5
+ * .magi/.cipher にパーミッション0o400で保存する。
6
+ */
7
+ export declare class SecretCipher {
8
+ private readonly workspaceDir;
9
+ private cipherPath;
10
+ constructor(workspaceDir: string);
11
+ /** Check if cipher block exists */
12
+ exists(): Promise<boolean>;
13
+ /**
14
+ * Initialize with an encrypted message.
15
+ * Rejects if already initialized (double init protection).
16
+ */
17
+ initialize(message: string, passphrase: string): Promise<void>;
18
+ /** Decrypt the stored message */
19
+ decrypt(passphrase: string): Promise<string>;
20
+ /**
21
+ * Auto-initialize from environment variables or skip.
22
+ * - MAGI_CIPHER_MESSAGE + MAGI_CIPHER_PASSPHRASE → auto init
23
+ * - Otherwise → skip (no interactive prompt in library code)
24
+ */
25
+ autoInitialize(): Promise<boolean>;
26
+ }
@@ -0,0 +1,114 @@
1
+ /**
2
+ * B-08 裏コード (SecretCipher)
3
+ *
4
+ * MAGIシステムに隠されたメッセージ。AES-256-GCMで暗号化し、
5
+ * .magi/.cipher にパーミッション0o400で保存する。
6
+ */
7
+ import { createCipheriv, createDecipheriv, randomBytes, scryptSync } from 'node:crypto';
8
+ import { readFile, access, unlink, constants } from 'node:fs/promises';
9
+ import { join } from 'node:path';
10
+ import { logger } from '../utils/logger.js';
11
+ import { safeMkdir, safeWriteFile } from '../utils/safe-fs.js';
12
+ import { safeJsonParse } from '../utils/safe-json-parse.js';
13
+ const CIPHER_FILENAME = '.cipher';
14
+ const ALGORITHM = 'aes-256-gcm';
15
+ const KEY_LENGTH = 32;
16
+ const SALT_LENGTH = 16;
17
+ const LEGACY_SALT = 'magi-system-secret-cipher'; // fallback for pre-salt data
18
+ const SCRYPT_PARAMS = { N: 2 ** 17, r: 8, p: 1, maxmem: 256 * 1024 * 1024 };
19
+ export class SecretCipher {
20
+ workspaceDir;
21
+ cipherPath;
22
+ constructor(workspaceDir) {
23
+ this.workspaceDir = workspaceDir;
24
+ this.cipherPath = join(workspaceDir, CIPHER_FILENAME);
25
+ }
26
+ /** Check if cipher block exists */
27
+ async exists() {
28
+ try {
29
+ await access(this.cipherPath, constants.F_OK);
30
+ return true;
31
+ }
32
+ catch (err) {
33
+ logger.debug('SecretCipher: cipher file access check failed', { error: String(err) });
34
+ return false;
35
+ }
36
+ }
37
+ /**
38
+ * Initialize with an encrypted message.
39
+ * Rejects if already initialized (double init protection).
40
+ */
41
+ async initialize(message, passphrase) {
42
+ if (await this.exists()) {
43
+ throw new Error('SecretCipher: already initialized. Double initialization rejected.');
44
+ }
45
+ const salt = randomBytes(SALT_LENGTH);
46
+ const key = scryptSync(passphrase, salt, KEY_LENGTH, SCRYPT_PARAMS);
47
+ const iv = randomBytes(16);
48
+ const cipher = createCipheriv(ALGORITHM, key, iv);
49
+ const encrypted = Buffer.concat([
50
+ cipher.update(message, 'utf-8'),
51
+ cipher.final(),
52
+ ]);
53
+ const authTag = cipher.getAuthTag();
54
+ const block = {
55
+ iv: iv.toString('hex'),
56
+ authTag: authTag.toString('hex'),
57
+ encrypted: encrypted.toString('hex'),
58
+ salt: salt.toString('hex'),
59
+ createdAt: new Date().toISOString(),
60
+ };
61
+ await safeMkdir(this.workspaceDir);
62
+ await safeWriteFile(this.cipherPath, JSON.stringify(block, null, 2), {
63
+ mode: 0o400, // read-only for owner
64
+ });
65
+ }
66
+ /** Decrypt the stored message */
67
+ async decrypt(passphrase) {
68
+ if (!(await this.exists())) {
69
+ throw new Error('SecretCipher: no cipher block found.');
70
+ }
71
+ const raw = await readFile(this.cipherPath, 'utf-8');
72
+ const block = safeJsonParse(raw);
73
+ // Backward compat: legacy data without salt field uses the old fixed salt + old scrypt defaults
74
+ const isLegacy = !block.salt;
75
+ const salt = isLegacy
76
+ ? Buffer.from(LEGACY_SALT, 'utf-8')
77
+ : Buffer.from(block.salt, 'hex');
78
+ const key = isLegacy
79
+ ? scryptSync(passphrase, salt, KEY_LENGTH)
80
+ : scryptSync(passphrase, salt, KEY_LENGTH, SCRYPT_PARAMS);
81
+ const decipher = createDecipheriv(ALGORITHM, key, Buffer.from(block.iv, 'hex'));
82
+ decipher.setAuthTag(Buffer.from(block.authTag, 'hex'));
83
+ const decrypted = Buffer.concat([
84
+ decipher.update(Buffer.from(block.encrypted, 'hex')),
85
+ decipher.final(),
86
+ ]);
87
+ const plaintext = decrypted.toString('utf-8');
88
+ // Auto-upgrade legacy cipher to random salt + hardened scrypt
89
+ if (isLegacy) {
90
+ logger.info('SecretCipher: upgrading legacy cipher to random salt + hardened scrypt');
91
+ await unlink(this.cipherPath);
92
+ await this.initialize(plaintext, passphrase);
93
+ }
94
+ return plaintext;
95
+ }
96
+ /**
97
+ * Auto-initialize from environment variables or skip.
98
+ * - MAGI_CIPHER_MESSAGE + MAGI_CIPHER_PASSPHRASE → auto init
99
+ * - Otherwise → skip (no interactive prompt in library code)
100
+ */
101
+ async autoInitialize() {
102
+ if (await this.exists())
103
+ return false;
104
+ const message = process.env['MAGI_CIPHER_MESSAGE'];
105
+ const passphrase = process.env['MAGI_CIPHER_PASSPHRASE'];
106
+ delete process.env['MAGI_CIPHER_MESSAGE'];
107
+ delete process.env['MAGI_CIPHER_PASSPHRASE'];
108
+ if (message && passphrase) {
109
+ await this.initialize(message, passphrase);
110
+ return true;
111
+ }
112
+ return false; // skip — no env vars, no TTY interaction in library
113
+ }
114
+ }
@@ -0,0 +1,90 @@
1
+ /**
2
+ * B-07 Seele Council (ゼーレ会議)
3
+ *
4
+ * 分散MAGI合議 — 複数のMAGIノード間でPBFT/Raftによるコンセンサスを実現。
5
+ * シミュレーションモード (インメモリ) とネットワークモード (WebSocket) を切替可能。
6
+ *
7
+ * - PBFT (Layer 1): サブグループ内の合意形成
8
+ * - Raft (Layer 2): リーダー選出と提案管理
9
+ * - Ed25519署名: メッセージの真正性検証
10
+ * - SOUND ONLYパネル: 匿名参加者の可視化
11
+ */
12
+ import type { MagiNodeId, MagiNodeInfo, RaftRole, SeeleSession, SeeleConfig } from '../types/phase-l.js';
13
+ import type { MagiEventBus } from './events.js';
14
+ export declare class SeeleCouncil {
15
+ private readonly localNode;
16
+ private readonly eventBus;
17
+ readonly config: SeeleConfig;
18
+ private nodes;
19
+ private keyPairs;
20
+ private session;
21
+ private raftRole;
22
+ private raftTerm;
23
+ private messageSequence;
24
+ constructor(localNode: MagiNodeId, eventBus?: MagiEventBus, config?: Partial<SeeleConfig>);
25
+ /**
26
+ * Initialize nodes for simulation mode.
27
+ */
28
+ initializeNodes(nodeIds?: MagiNodeId[]): void;
29
+ /**
30
+ * Run PBFT consensus among a subgroup of nodes.
31
+ */
32
+ pbftConsensus(subgroup: MagiNodeId[], proposal: string): Promise<{
33
+ agreed: boolean;
34
+ votes: Map<MagiNodeId, boolean>;
35
+ }>;
36
+ /**
37
+ * Perform Raft leader election among all nodes.
38
+ */
39
+ raftElection(): Promise<MagiNodeId>;
40
+ /**
41
+ * Propose a decision through Raft (leader only).
42
+ */
43
+ raftPropose(decision: string): Promise<boolean>;
44
+ /**
45
+ * Simulate an attack from attacker nodes against a target.
46
+ */
47
+ executeAttack(attackers: MagiNodeId[], target: MagiNodeId): Promise<{
48
+ success: boolean;
49
+ defenseHeld: boolean;
50
+ }>;
51
+ /**
52
+ * Start a new Seele council session.
53
+ */
54
+ startSession(): Promise<SeeleSession>;
55
+ /**
56
+ * Conclude a session with a decision.
57
+ */
58
+ concludeSession(decision: string | null): Promise<void>;
59
+ /**
60
+ * Run a full simulated Seele council session.
61
+ */
62
+ simulateSession(): Promise<SeeleSession>;
63
+ /**
64
+ * Create and sign a message.
65
+ */
66
+ private createMessage;
67
+ /**
68
+ * Sign a message with Ed25519 private key.
69
+ */
70
+ private signMessage;
71
+ /**
72
+ * Verify a message signature.
73
+ */
74
+ private verifyMessage;
75
+ /**
76
+ * Generate SOUND ONLY panel visualization (ANSI art).
77
+ */
78
+ formatSoundOnlyPanel(): string;
79
+ /**
80
+ * Securely destroy all private key material.
81
+ * Best-effort: zeros exported DER buffers and clears references.
82
+ */
83
+ destroy(): void;
84
+ getSession(): SeeleSession | null;
85
+ getNodes(): Map<MagiNodeId, MagiNodeInfo>;
86
+ getLocalNode(): MagiNodeId;
87
+ getRaftRole(): RaftRole;
88
+ getRaftTerm(): number;
89
+ private createSession;
90
+ }