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,61 @@
1
+ /**
2
+ * B-06 Nebuchadnezzar Key (Creator Override)
3
+ *
4
+ * Ed25519 key pair for creator override of MAGI consensus decisions.
5
+ * The private key is returned once at generation and NEVER stored.
6
+ * Only the public key is persisted in `.magi/nebuchadnezzar.json`.
7
+ */
8
+ import type { OverrideRequest, OverrideResult, NebuchadnezzarState } from '../types/phase-k.js';
9
+ import type { MagiEventBus } from './events.js';
10
+ export declare class NebuchadnezzarKey {
11
+ private state;
12
+ private readonly statePath;
13
+ private readonly eventBus?;
14
+ private usedNonces;
15
+ constructor(workspaceDir: string, eventBus?: MagiEventBus);
16
+ /**
17
+ * Generate a new Ed25519 key pair.
18
+ * Public key is stored; private key is returned once and NOT persisted.
19
+ */
20
+ generateKeyPair(): Promise<{
21
+ publicKey: string;
22
+ privateKey: string;
23
+ }>;
24
+ /**
25
+ * Override a consensus decision with a signed request.
26
+ */
27
+ override(request: OverrideRequest, previousDecision: string): Promise<OverrideResult>;
28
+ /**
29
+ * Reset consecutive override counter (called when deliberation completes without override).
30
+ */
31
+ resetConsecutiveOverrides(): void;
32
+ /**
33
+ * Load state from disk.
34
+ */
35
+ load(): Promise<void>;
36
+ /**
37
+ * Persist state to disk with 0o600 permissions.
38
+ */
39
+ persist(): Promise<void>;
40
+ /**
41
+ * Check if public key has been generated/loaded.
42
+ */
43
+ isInitialized(): boolean;
44
+ /**
45
+ * Get current state (or null if not initialized).
46
+ */
47
+ getState(): NebuchadnezzarState | null;
48
+ /**
49
+ * Confidence multiplier based on consecutive override count.
50
+ * 1 override = 1.0, 2 consecutive = 0.9, 3+ consecutive = 0.7
51
+ */
52
+ getConfidenceMultiplier(): number;
53
+ /**
54
+ * Static helper: sign a message for an override request.
55
+ * Returns hex-encoded Ed25519 signature.
56
+ */
57
+ /** Generate a fresh nonce for an override request. */
58
+ static generateNonce(): string;
59
+ private evictExpiredNonces;
60
+ static sign(privateKeyHex: string, deliberationId: string, newDecision: string, reason: string, timestamp: string, nonce: string): string;
61
+ }
@@ -0,0 +1,203 @@
1
+ /**
2
+ * B-06 Nebuchadnezzar Key (Creator Override)
3
+ *
4
+ * Ed25519 key pair for creator override of MAGI consensus decisions.
5
+ * The private key is returned once at generation and NEVER stored.
6
+ * Only the public key is persisted in `.magi/nebuchadnezzar.json`.
7
+ */
8
+ import { generateKeyPairSync, sign as cryptoSign, verify as cryptoVerify, randomUUID } from 'node:crypto';
9
+ import { readFile } from 'node:fs/promises';
10
+ import { join } from 'node:path';
11
+ import { logger } from '../utils/logger.js';
12
+ import { safePersist } from '../utils/safe-fs.js';
13
+ import { safeJsonParse } from '../utils/safe-json-parse.js';
14
+ const STATE_FILENAME = 'nebuchadnezzar.json';
15
+ const REPLAY_WINDOW_MS = 5 * 60 * 1000; // 5 minutes
16
+ const MAX_NONCE_CACHE = 1000;
17
+ const UUID_V4_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
18
+ export class NebuchadnezzarKey {
19
+ state = null;
20
+ statePath;
21
+ eventBus;
22
+ usedNonces = new Map(); // nonce → expiresAt
23
+ constructor(workspaceDir, eventBus) {
24
+ this.statePath = join(workspaceDir, STATE_FILENAME);
25
+ this.eventBus = eventBus;
26
+ }
27
+ /**
28
+ * Generate a new Ed25519 key pair.
29
+ * Public key is stored; private key is returned once and NOT persisted.
30
+ */
31
+ async generateKeyPair() {
32
+ if (this.state !== null) {
33
+ throw new Error('NebuchadnezzarKey: already initialized. Cannot generate a second key pair.');
34
+ }
35
+ const { publicKey, privateKey } = generateKeyPairSync('ed25519', {
36
+ publicKeyEncoding: { type: 'spki', format: 'der' },
37
+ privateKeyEncoding: { type: 'pkcs8', format: 'der' },
38
+ });
39
+ const publicKeyHex = publicKey.toString('hex');
40
+ const privateKeyHex = privateKey.toString('hex');
41
+ this.state = {
42
+ publicKey: publicKeyHex,
43
+ overrideCount: 0,
44
+ consecutiveOverrides: 0,
45
+ createdAt: new Date().toISOString(),
46
+ };
47
+ await this.persist();
48
+ return { publicKey: publicKeyHex, privateKey: privateKeyHex };
49
+ }
50
+ /**
51
+ * Override a consensus decision with a signed request.
52
+ */
53
+ async override(request, previousDecision) {
54
+ if (this.state === null) {
55
+ throw new Error('NebuchadnezzarKey: not initialized. Call generateKeyPair() or load() first.');
56
+ }
57
+ // Replay prevention: timestamp freshness
58
+ const requestTime = new Date(request.timestamp).getTime();
59
+ const now = Date.now();
60
+ if (Number.isNaN(requestTime) || Math.abs(now - requestTime) > REPLAY_WINDOW_MS) {
61
+ throw new Error(`NebuchadnezzarKey: timestamp too stale or invalid. Window: ${REPLAY_WINDOW_MS}ms`);
62
+ }
63
+ // Replay prevention: nonce uniqueness
64
+ if (!request.nonce || !UUID_V4_RE.test(request.nonce)) {
65
+ throw new Error('NebuchadnezzarKey: nonce must be a valid UUID v4.');
66
+ }
67
+ this.evictExpiredNonces();
68
+ if (this.usedNonces.has(request.nonce)) {
69
+ throw new Error('NebuchadnezzarKey: nonce already used. Replay attack rejected.');
70
+ }
71
+ this.usedNonces.set(request.nonce, now + REPLAY_WINDOW_MS);
72
+ // Verify Ed25519 signature (nonce included in signed message)
73
+ const message = `${request.deliberationId}:${request.newDecision}:${request.reason}:${request.timestamp}:${request.nonce}`;
74
+ const publicKeyDer = Buffer.from(this.state.publicKey, 'hex');
75
+ const signatureBuffer = Buffer.from(request.signature, 'hex');
76
+ const valid = cryptoVerify(null, // Ed25519 does not use a separate hash algorithm
77
+ Buffer.from(message, 'utf-8'), { key: publicKeyDer, format: 'der', type: 'spki' }, signatureBuffer);
78
+ if (!valid) {
79
+ throw new Error('NebuchadnezzarKey: invalid signature. Override rejected.');
80
+ }
81
+ // Update state
82
+ this.state.overrideCount += 1;
83
+ this.state.consecutiveOverrides += 1;
84
+ this.state.lastOverrideAt = new Date().toISOString();
85
+ const confidenceMultiplier = this.getConfidenceMultiplier();
86
+ const appliedAt = new Date().toISOString();
87
+ const result = {
88
+ success: true,
89
+ deliberationId: request.deliberationId,
90
+ previousDecision,
91
+ newDecision: request.newDecision,
92
+ confidenceMultiplier,
93
+ consecutiveOverrides: this.state.consecutiveOverrides,
94
+ overrideCount: this.state.overrideCount,
95
+ appliedAt,
96
+ };
97
+ // Audit log
98
+ logger.audit('nebuchadnezzar.override', request.deliberationId, {
99
+ previousDecision,
100
+ newDecision: request.newDecision,
101
+ reason: request.reason,
102
+ overrideCount: this.state.overrideCount,
103
+ consecutiveOverrides: this.state.consecutiveOverrides,
104
+ confidenceMultiplier,
105
+ });
106
+ // Persist updated state
107
+ await this.persist();
108
+ // Emit event
109
+ if (this.eventBus) {
110
+ this.eventBus.emit('nebuchadnezzar:override', {
111
+ deliberationId: request.deliberationId,
112
+ previousDecision,
113
+ newDecision: request.newDecision,
114
+ consecutiveOverrides: this.state.consecutiveOverrides,
115
+ emittedAt: new Date(),
116
+ });
117
+ }
118
+ return result;
119
+ }
120
+ /**
121
+ * Reset consecutive override counter (called when deliberation completes without override).
122
+ */
123
+ resetConsecutiveOverrides() {
124
+ if (this.state !== null) {
125
+ this.state.consecutiveOverrides = 0;
126
+ }
127
+ }
128
+ /**
129
+ * Load state from disk.
130
+ */
131
+ async load() {
132
+ const raw = await readFile(this.statePath, 'utf-8');
133
+ const parsed = safeJsonParse(raw);
134
+ this.state = parsed;
135
+ }
136
+ /**
137
+ * Persist state to disk with 0o600 permissions.
138
+ */
139
+ async persist() {
140
+ if (this.state === null) {
141
+ throw new Error('NebuchadnezzarKey: no state to persist.');
142
+ }
143
+ await safePersist(this.statePath, JSON.stringify(this.state, null, 2));
144
+ }
145
+ /**
146
+ * Check if public key has been generated/loaded.
147
+ */
148
+ isInitialized() {
149
+ return this.state !== null;
150
+ }
151
+ /**
152
+ * Get current state (or null if not initialized).
153
+ */
154
+ getState() {
155
+ if (this.state === null)
156
+ return null;
157
+ return { ...this.state };
158
+ }
159
+ /**
160
+ * Confidence multiplier based on consecutive override count.
161
+ * 1 override = 1.0, 2 consecutive = 0.9, 3+ consecutive = 0.7
162
+ */
163
+ getConfidenceMultiplier() {
164
+ if (this.state === null)
165
+ return 1.0;
166
+ const c = this.state.consecutiveOverrides;
167
+ if (c <= 1)
168
+ return 1.0;
169
+ if (c === 2)
170
+ return 0.9;
171
+ return 0.7;
172
+ }
173
+ /**
174
+ * Static helper: sign a message for an override request.
175
+ * Returns hex-encoded Ed25519 signature.
176
+ */
177
+ /** Generate a fresh nonce for an override request. */
178
+ static generateNonce() {
179
+ return randomUUID();
180
+ }
181
+ evictExpiredNonces() {
182
+ const now = Date.now();
183
+ for (const [nonce, expiresAt] of this.usedNonces) {
184
+ if (expiresAt <= now)
185
+ this.usedNonces.delete(nonce);
186
+ }
187
+ if (this.usedNonces.size > MAX_NONCE_CACHE) {
188
+ this.usedNonces.clear();
189
+ }
190
+ }
191
+ static sign(privateKeyHex, deliberationId, newDecision, reason, timestamp, nonce) {
192
+ const message = `${deliberationId}:${newDecision}:${reason}:${timestamp}:${nonce}`;
193
+ const privateKeyDer = Buffer.from(privateKeyHex, 'hex');
194
+ try {
195
+ const signature = cryptoSign(null, // Ed25519 does not use a separate hash algorithm
196
+ Buffer.from(message, 'utf-8'), { key: privateKeyDer, format: 'der', type: 'pkcs8' });
197
+ return signature.toString('hex');
198
+ }
199
+ finally {
200
+ privateKeyDer.fill(0);
201
+ }
202
+ }
203
+ }
@@ -0,0 +1,52 @@
1
+ /**
2
+ * B-10 Neon Genesis (世界のやり直し)
3
+ *
4
+ * MAGIシステムの完全リセット。全審議記録を消去し、
5
+ * 選ばれた記憶のみを次世代に引き継ぐ。
6
+ *
7
+ * 処理フロー:
8
+ * 1. genesis:started イベント発火
9
+ * 2. preResetDeliberation — MAGI自身が消滅を議論 (optional)
10
+ * 3. collectSnapshot — 審議統計収集
11
+ * 4. selectSurvivalMemories — 10% Fisher-Yatesシャッフル選択
12
+ * 5. .cipher ファイル退避
13
+ * 6. purge — .magi/ 配下削除 (genesis-log.json + .cipher 除外)
14
+ * 7. .cipher 復元
15
+ * 8. writeGenesisLog — genesis-log.json に痕跡記録
16
+ * 9. genesis:complete イベント発火
17
+ */
18
+ import type { GenesisLog } from '../types/phase-l.js';
19
+ import type { MagiEventBus } from './events.js';
20
+ export declare class NeonGenesis {
21
+ private readonly workspaceDir;
22
+ private readonly eventBus;
23
+ constructor(workspaceDir: string, eventBus?: MagiEventBus);
24
+ /**
25
+ * Execute the Neon Genesis — full system reset.
26
+ */
27
+ execute(reason: string, initiator: string, force?: boolean): Promise<GenesisLog>;
28
+ /**
29
+ * Collect snapshot of current MAGI state from chronicle and rounds.
30
+ */
31
+ private collectSnapshot;
32
+ /**
33
+ * Load semantic patterns from engram store.
34
+ */
35
+ private loadSemanticPatterns;
36
+ /**
37
+ * Select survival memories using Fisher-Yates shuffle at given rate.
38
+ */
39
+ selectSurvivalMemories(patterns: string[], rate?: number): string[];
40
+ /**
41
+ * Purge the .magi/ workspace directory, preserving specified files.
42
+ */
43
+ private purge;
44
+ /**
45
+ * Write genesis log to workspace.
46
+ */
47
+ private writeGenesisLog;
48
+ /**
49
+ * Load existing genesis log, if any.
50
+ */
51
+ loadGenesisLog(): Promise<GenesisLog | null>;
52
+ }
@@ -0,0 +1,203 @@
1
+ /**
2
+ * B-10 Neon Genesis (世界のやり直し)
3
+ *
4
+ * MAGIシステムの完全リセット。全審議記録を消去し、
5
+ * 選ばれた記憶のみを次世代に引き継ぐ。
6
+ *
7
+ * 処理フロー:
8
+ * 1. genesis:started イベント発火
9
+ * 2. preResetDeliberation — MAGI自身が消滅を議論 (optional)
10
+ * 3. collectSnapshot — 審議統計収集
11
+ * 4. selectSurvivalMemories — 10% Fisher-Yatesシャッフル選択
12
+ * 5. .cipher ファイル退避
13
+ * 6. purge — .magi/ 配下削除 (genesis-log.json + .cipher 除外)
14
+ * 7. .cipher 復元
15
+ * 8. writeGenesisLog — genesis-log.json に痕跡記録
16
+ * 9. genesis:complete イベント発火
17
+ */
18
+ import { randomUUID, randomInt } from 'node:crypto';
19
+ import { readFile, readdir, rm, copyFile } from 'node:fs/promises';
20
+ import { join } from 'node:path';
21
+ import { logger } from '../utils/logger.js';
22
+ import { safeMkdir, safeWriteFile } from '../utils/safe-fs.js';
23
+ import { safeJsonParse } from '../utils/safe-json-parse.js';
24
+ const GENESIS_LOG_FILE = 'genesis-log.json';
25
+ const CIPHER_FILE = '.cipher';
26
+ const SURVIVAL_RATE = 0.10; // 10% of semantic patterns survive
27
+ export class NeonGenesis {
28
+ workspaceDir;
29
+ eventBus;
30
+ constructor(workspaceDir, eventBus) {
31
+ this.workspaceDir = workspaceDir;
32
+ this.eventBus = eventBus;
33
+ }
34
+ /**
35
+ * Execute the Neon Genesis — full system reset.
36
+ */
37
+ async execute(reason, initiator, force = false) {
38
+ if (!force) {
39
+ throw new Error('Neon Genesis aborted: --force flag required. This permanently deletes all deliberation data.');
40
+ }
41
+ const resetId = randomUUID();
42
+ logger.warn('Neon Genesis initiated', { resetId, reason, initiator });
43
+ this.eventBus?.emit('genesis:started', {
44
+ resetId,
45
+ reason,
46
+ emittedAt: new Date(),
47
+ });
48
+ // Collect snapshot before purge
49
+ const snapshot = await this.collectSnapshot();
50
+ // Select survival memories from engram patterns
51
+ const patterns = await this.loadSemanticPatterns();
52
+ const survivalMemories = this.selectSurvivalMemories(patterns, SURVIVAL_RATE);
53
+ // Check for cipher file
54
+ const cipherPath = join(this.workspaceDir, CIPHER_FILE);
55
+ const cipherBackupPath = join(this.workspaceDir, `.cipher-backup-${resetId}`);
56
+ let cipherPreserved = false;
57
+ // Backup cipher if it exists
58
+ try {
59
+ await copyFile(cipherPath, cipherBackupPath);
60
+ cipherPreserved = true;
61
+ }
62
+ catch (err) {
63
+ logger.debug('Neon Genesis: no cipher file to backup', { error: String(err) });
64
+ }
65
+ // Purge workspace
66
+ await this.purge([GENESIS_LOG_FILE, `.cipher-backup-${resetId}`]);
67
+ // Restore cipher
68
+ if (cipherPreserved) {
69
+ try {
70
+ await safeMkdir(this.workspaceDir);
71
+ await copyFile(cipherBackupPath, cipherPath);
72
+ await rm(cipherBackupPath, { force: true });
73
+ }
74
+ catch {
75
+ logger.warn('Failed to restore cipher file after genesis');
76
+ }
77
+ }
78
+ // Write genesis log
79
+ const log = {
80
+ resetId,
81
+ previousGeneration: snapshot.totalDeliberations,
82
+ totalDeliberations: snapshot.totalDeliberations,
83
+ survivalMemories,
84
+ cipherMessagePreserved: cipherPreserved,
85
+ lastDeliberation: snapshot.lastDeliberation,
86
+ resetAt: new Date().toISOString(),
87
+ initiator,
88
+ };
89
+ await this.writeGenesisLog(log);
90
+ logger.warn('Neon Genesis complete', {
91
+ resetId,
92
+ survived: survivalMemories.length,
93
+ cipherPreserved,
94
+ });
95
+ this.eventBus?.emit('genesis:complete', {
96
+ resetId,
97
+ survivalMemories: survivalMemories.length,
98
+ cipherPreserved,
99
+ emittedAt: new Date(),
100
+ });
101
+ return log;
102
+ }
103
+ /**
104
+ * Collect snapshot of current MAGI state from chronicle and rounds.
105
+ */
106
+ async collectSnapshot() {
107
+ let totalDeliberations = 0;
108
+ let lastDeliberation = null;
109
+ // Read chronicle.jsonl
110
+ const chroniclePath = join(this.workspaceDir, 'gospel', 'chronicle.jsonl');
111
+ try {
112
+ const raw = await readFile(chroniclePath, 'utf-8');
113
+ const lines = raw.trim().split('\n').filter(Boolean);
114
+ totalDeliberations = lines.length;
115
+ if (lines.length > 0) {
116
+ try {
117
+ const lastEntry = safeJsonParse(lines[lines.length - 1]);
118
+ lastDeliberation = lastEntry.timestamp ?? lastEntry.recordedAt ?? null;
119
+ }
120
+ catch (err) {
121
+ logger.debug('Neon Genesis: corrupt chronicle last line', { error: String(err) });
122
+ }
123
+ }
124
+ }
125
+ catch (err) {
126
+ logger.debug('Neon Genesis: no chronicle found, fresh system', { error: String(err) });
127
+ }
128
+ return { totalDeliberations, lastDeliberation };
129
+ }
130
+ /**
131
+ * Load semantic patterns from engram store.
132
+ */
133
+ async loadSemanticPatterns() {
134
+ const engramPath = join(this.workspaceDir, 'engram', 'semantic.json');
135
+ try {
136
+ const raw = await readFile(engramPath, 'utf-8');
137
+ const patterns = safeJsonParse(raw);
138
+ if (Array.isArray(patterns)) {
139
+ return patterns.map((p) => p.pattern ?? p.description ?? JSON.stringify(p));
140
+ }
141
+ return [];
142
+ }
143
+ catch (err) {
144
+ logger.debug('Neon Genesis: failed to load semantic patterns', { error: String(err) });
145
+ return [];
146
+ }
147
+ }
148
+ /**
149
+ * Select survival memories using Fisher-Yates shuffle at given rate.
150
+ */
151
+ selectSurvivalMemories(patterns, rate = SURVIVAL_RATE) {
152
+ if (patterns.length === 0)
153
+ return [];
154
+ const count = Math.max(1, Math.ceil(patterns.length * rate));
155
+ const shuffled = [...patterns];
156
+ // Fisher-Yates shuffle (partial — only need first `count` elements)
157
+ for (let i = shuffled.length - 1; i > 0 && (shuffled.length - 1 - i) < count; i--) {
158
+ const j = randomInt(i + 1);
159
+ [shuffled[i], shuffled[j]] = [shuffled[j], shuffled[i]];
160
+ }
161
+ return shuffled.slice(-count);
162
+ }
163
+ /**
164
+ * Purge the .magi/ workspace directory, preserving specified files.
165
+ */
166
+ async purge(preserveFiles) {
167
+ try {
168
+ const entries = await readdir(this.workspaceDir, { withFileTypes: true });
169
+ for (const entry of entries) {
170
+ const name = entry.name;
171
+ if (preserveFiles.includes(name) || name === CIPHER_FILE)
172
+ continue;
173
+ const fullPath = join(this.workspaceDir, name);
174
+ await rm(fullPath, { recursive: true, force: true });
175
+ }
176
+ }
177
+ catch (err) {
178
+ logger.debug('Neon Genesis: workspace not found, nothing to purge', { error: String(err) });
179
+ }
180
+ }
181
+ /**
182
+ * Write genesis log to workspace.
183
+ */
184
+ async writeGenesisLog(log) {
185
+ await safeMkdir(this.workspaceDir);
186
+ const logPath = join(this.workspaceDir, GENESIS_LOG_FILE);
187
+ await safeWriteFile(logPath, JSON.stringify(log, null, 2));
188
+ }
189
+ /**
190
+ * Load existing genesis log, if any.
191
+ */
192
+ async loadGenesisLog() {
193
+ try {
194
+ const logPath = join(this.workspaceDir, GENESIS_LOG_FILE);
195
+ const raw = await readFile(logPath, 'utf-8');
196
+ return safeJsonParse(raw);
197
+ }
198
+ catch (err) {
199
+ logger.debug('Neon Genesis: genesis log not found', { error: String(err) });
200
+ return null;
201
+ }
202
+ }
203
+ }
@@ -0,0 +1,53 @@
1
+ /** Result from running a single tool */
2
+ export interface ToolResult {
3
+ tool: 'tsc' | 'eslint' | 'vitest';
4
+ available: boolean;
5
+ passed: boolean;
6
+ issues: ToolIssue[];
7
+ summary: string;
8
+ rawOutput?: string;
9
+ }
10
+ /** A single issue found by a tool */
11
+ export interface ToolIssue {
12
+ file?: string;
13
+ line?: number;
14
+ severity: 'error' | 'warning' | 'info';
15
+ message: string;
16
+ rule?: string;
17
+ }
18
+ /** Combined result from all tools */
19
+ export interface ObjectiveResult {
20
+ score: number;
21
+ tools: ToolResult[];
22
+ summary: string;
23
+ evaluatedAt: Date;
24
+ }
25
+ /** Command runner function signature */
26
+ type RunCommandFn = (cmd: string, args: string[], cwd: string) => Promise<{
27
+ stdout: string;
28
+ stderr: string;
29
+ exitCode: number;
30
+ }>;
31
+ /**
32
+ * ObjectiveJudge: runs static analysis and tests to produce an objective
33
+ * quality score that supplements the subjective AI opinions.
34
+ *
35
+ * Graceful degradation: if a tool is not available, it's skipped and
36
+ * the score is calculated from available tools only.
37
+ */
38
+ export declare class ObjectiveJudge {
39
+ private readonly cwd;
40
+ private readonly runCommand;
41
+ constructor(cwd: string, runCommand?: RunCommandFn);
42
+ private static defaultRunCommand;
43
+ evaluate(): Promise<ObjectiveResult>;
44
+ calculateScore(tools: ToolResult[]): number;
45
+ private buildSummary;
46
+ private runTsc;
47
+ private runEslint;
48
+ private runVitest;
49
+ parseTscOutput(output: string): ToolIssue[];
50
+ parseEslintOutput(output: string): ToolIssue[];
51
+ parseVitestOutput(output: string): ToolIssue[];
52
+ }
53
+ export {};