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,45 @@
1
+ /**
2
+ * B-01 シンクロ率 (SyncRateTracker)
3
+ *
4
+ * ベイズ推定(Beta分布)でユニット別・ドメイン別の的中率を追跡する。
5
+ * 投票が合議結果と一致すればalpha++、不一致ならbeta++。
6
+ * Beta分布の期待値 E[X] = α/(α+β) をシンクロ率として返す。
7
+ */
8
+ import type { MagiUnit, Vote } from '../types/core.js';
9
+ import type { ConsensusDecision } from '../types/consensus.js';
10
+ import type { SyncWeightMap } from '../types/phase-h.js';
11
+ export declare class SyncRateTracker {
12
+ private readonly workspaceDir;
13
+ private units;
14
+ constructor(workspaceDir: string);
15
+ /**
16
+ * Update sync rate after a deliberation round.
17
+ * If the unit's vote aligns with the consensus direction, alpha++; else beta++.
18
+ */
19
+ update(unit: MagiUnit, domain: string | undefined, vote: Vote, decision: ConsensusDecision): void;
20
+ /** Get sync rate for a unit in a domain: E[X] = α/(α+β) */
21
+ getRate(unit: MagiUnit, domain?: string): number;
22
+ /** Get total samples for a unit in a domain */
23
+ getSampleCount(unit: MagiUnit, domain?: string): number;
24
+ /**
25
+ * Compute consensus weights from sync rates.
26
+ * Only applies weights when enough samples exist.
27
+ */
28
+ computeWeights(units: MagiUnit[], domain?: string): SyncWeightMap;
29
+ /**
30
+ * Check for berserk condition: sum of all unit rates exceeds threshold.
31
+ * Returns { warning, totalRate, rates } or null if no warning.
32
+ */
33
+ checkBerserk(units: MagiUnit[], domain?: string): {
34
+ totalRate: number;
35
+ rates: Record<MagiUnit, number>;
36
+ } | null;
37
+ /** Get all rates for display */
38
+ getAllRates(units: MagiUnit[], domain?: string): Record<MagiUnit, number>;
39
+ /** Persist to .magi/sync-rate.json */
40
+ persist(): Promise<void>;
41
+ /** Load from .magi/sync-rate.json */
42
+ load(): Promise<void>;
43
+ private getOrCreateEntry;
44
+ private getEntry;
45
+ }
@@ -0,0 +1,151 @@
1
+ /**
2
+ * B-01 シンクロ率 (SyncRateTracker)
3
+ *
4
+ * ベイズ推定(Beta分布)でユニット別・ドメイン別の的中率を追跡する。
5
+ * 投票が合議結果と一致すればalpha++、不一致ならbeta++。
6
+ * Beta分布の期待値 E[X] = α/(α+β) をシンクロ率として返す。
7
+ */
8
+ import { readFile } from 'node:fs/promises';
9
+ import { join } from 'node:path';
10
+ import { isApproval } from '../types/consensus.js';
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
+ /** Default weak prior: Beta(2,2) → E[X]=0.5 */
15
+ const DEFAULT_PRIOR = { alpha: 2, beta: 2 };
16
+ /** Minimum samples before applying sync-rate weights */
17
+ const MIN_SAMPLES_FOR_WEIGHT = 3;
18
+ /** Berserk threshold: sum of all unit rates exceeds this */
19
+ const BERSERK_THRESHOLD = 4.0;
20
+ /** Default domain when none specified */
21
+ const DEFAULT_DOMAIN = '_global';
22
+ export class SyncRateTracker {
23
+ workspaceDir;
24
+ units = new Map();
25
+ constructor(workspaceDir) {
26
+ this.workspaceDir = workspaceDir;
27
+ }
28
+ /**
29
+ * Update sync rate after a deliberation round.
30
+ * If the unit's vote aligns with the consensus direction, alpha++; else beta++.
31
+ */
32
+ update(unit, domain, vote, decision) {
33
+ const d = domain || DEFAULT_DOMAIN;
34
+ const entry = this.getOrCreateEntry(unit, d);
35
+ if (vote === 'ABSTAIN')
36
+ return; // abstentions don't affect sync rate
37
+ const decisionDirection = isApproval(decision) ? 'APPROVE' : 'REJECT';
38
+ const aligned = vote === decisionDirection;
39
+ if (aligned) {
40
+ entry.params.alpha += 1;
41
+ }
42
+ else {
43
+ entry.params.beta += 1;
44
+ }
45
+ entry.updatedAt = new Date().toISOString();
46
+ }
47
+ /** Get sync rate for a unit in a domain: E[X] = α/(α+β) */
48
+ getRate(unit, domain) {
49
+ const d = domain || DEFAULT_DOMAIN;
50
+ const entry = this.getEntry(unit, d);
51
+ if (!entry)
52
+ return DEFAULT_PRIOR.alpha / (DEFAULT_PRIOR.alpha + DEFAULT_PRIOR.beta);
53
+ return entry.params.alpha / (entry.params.alpha + entry.params.beta);
54
+ }
55
+ /** Get total samples for a unit in a domain */
56
+ getSampleCount(unit, domain) {
57
+ const d = domain || DEFAULT_DOMAIN;
58
+ const entry = this.getEntry(unit, d);
59
+ if (!entry)
60
+ return 0;
61
+ return (entry.params.alpha - DEFAULT_PRIOR.alpha) + (entry.params.beta - DEFAULT_PRIOR.beta);
62
+ }
63
+ /**
64
+ * Compute consensus weights from sync rates.
65
+ * Only applies weights when enough samples exist.
66
+ */
67
+ computeWeights(units, domain) {
68
+ const weights = {};
69
+ for (const unit of units) {
70
+ if (this.getSampleCount(unit, domain) >= MIN_SAMPLES_FOR_WEIGHT) {
71
+ weights[unit] = this.getRate(unit, domain);
72
+ }
73
+ }
74
+ return weights;
75
+ }
76
+ /**
77
+ * Check for berserk condition: sum of all unit rates exceeds threshold.
78
+ * Returns { warning, totalRate, rates } or null if no warning.
79
+ */
80
+ checkBerserk(units, domain) {
81
+ const rates = {};
82
+ let total = 0;
83
+ for (const unit of units) {
84
+ const rate = this.getRate(unit, domain);
85
+ rates[unit] = rate;
86
+ total += rate;
87
+ }
88
+ if (total > BERSERK_THRESHOLD) {
89
+ return { totalRate: total, rates };
90
+ }
91
+ return null;
92
+ }
93
+ /** Get all rates for display */
94
+ getAllRates(units, domain) {
95
+ const rates = {};
96
+ for (const unit of units) {
97
+ rates[unit] = this.getRate(unit, domain);
98
+ }
99
+ return rates;
100
+ }
101
+ /** Persist to .magi/sync-rate.json */
102
+ async persist() {
103
+ const data = { units: {}, version: 1 };
104
+ for (const [unit, domains] of this.units) {
105
+ data.units[unit] = {};
106
+ for (const [domain, entry] of domains) {
107
+ data.units[unit][domain] = entry;
108
+ }
109
+ }
110
+ await safePersist(join(this.workspaceDir, 'sync-rate.json'), JSON.stringify(data, null, 2));
111
+ }
112
+ /** Load from .magi/sync-rate.json */
113
+ async load() {
114
+ try {
115
+ const raw = await readFile(join(this.workspaceDir, 'sync-rate.json'), 'utf-8');
116
+ const data = safeJsonParse(raw);
117
+ if (data.version !== 1)
118
+ return;
119
+ this.units.clear();
120
+ for (const [unit, domains] of Object.entries(data.units)) {
121
+ const domainMap = new Map();
122
+ for (const [domain, entry] of Object.entries(domains)) {
123
+ domainMap.set(domain, entry);
124
+ }
125
+ this.units.set(unit, domainMap);
126
+ }
127
+ }
128
+ catch (err) {
129
+ logger.debug('SyncRate: state file not found or corrupt, starting fresh', { error: String(err) });
130
+ }
131
+ }
132
+ getOrCreateEntry(unit, domain) {
133
+ let domainMap = this.units.get(unit);
134
+ if (!domainMap) {
135
+ domainMap = new Map();
136
+ this.units.set(unit, domainMap);
137
+ }
138
+ let entry = domainMap.get(domain);
139
+ if (!entry) {
140
+ entry = {
141
+ params: { ...DEFAULT_PRIOR },
142
+ updatedAt: new Date().toISOString(),
143
+ };
144
+ domainMap.set(domain, entry);
145
+ }
146
+ return entry;
147
+ }
148
+ getEntry(unit, domain) {
149
+ return this.units.get(unit)?.get(domain);
150
+ }
151
+ }
@@ -0,0 +1,76 @@
1
+ /**
2
+ * B-05 Type-666 Firewall (666 multi-layer defense system)
3
+ *
4
+ * 4-layer barrier architecture inspired by Evangelion's absolute defense:
5
+ * Barrier 1 — Danang Type-B: Sanitization + encoding / size checks
6
+ * Barrier 2 — Protect No.666: 20 built-in prompt injection patterns
7
+ * Barrier 3-665 — Dynamic Patterns: Up to 662 learned patterns (FIFO)
8
+ * Barrier 666 — FINAL DEFENSE: Meta-analysis of ambiguous threats
9
+ */
10
+ import type { DynamicPattern, FirewallResult } from '../types/phase-k.js';
11
+ import type { ConsensusDecision } from '../types/consensus.js';
12
+ import { MagiEventBus } from './events.js';
13
+ export declare class Type666Firewall {
14
+ private readonly eventBus;
15
+ private dynamicPatterns;
16
+ private finalDefenseEnabled;
17
+ constructor(eventBus?: MagiEventBus);
18
+ /**
19
+ * Run all barrier layers sequentially and return an aggregate result.
20
+ */
21
+ scan(input: string): FirewallResult;
22
+ /**
23
+ * Add a dynamic pattern to Barrier 3-665.
24
+ * Evicts the oldest pattern if the queue exceeds 662 entries.
25
+ */
26
+ addPattern(pattern: DynamicPattern): void;
27
+ /**
28
+ * Extract suspicious patterns from a deadlocked deliberation.
29
+ * Adds them as learned dynamic patterns for future scans.
30
+ */
31
+ learnFromDeliberation(deliberation: {
32
+ task: {
33
+ description: string;
34
+ };
35
+ consensus: {
36
+ decision: ConsensusDecision;
37
+ };
38
+ }): void;
39
+ /** Enable Barrier 666 (FINAL DEFENSE). */
40
+ enableFinalDefense(): void;
41
+ /** Disable Barrier 666 (FINAL DEFENSE). */
42
+ disableFinalDefense(): void;
43
+ /** Return the number of built-in static attack patterns (Barrier 2). */
44
+ getStaticPatternCount(): number;
45
+ /** Return the number of currently registered dynamic patterns (Barriers 3-665). */
46
+ getPatternCount(): number;
47
+ /**
48
+ * Return the remaining capacity for dynamic patterns.
49
+ * 666 - current count = slots until the firewall reaches full barrier saturation.
50
+ */
51
+ getTimeRemainingToCollapse(): number;
52
+ /**
53
+ * Barrier 1 — Danang Type-B
54
+ * Uses sanitizeForPromptEmbedding + checks for Base64 and input length.
55
+ */
56
+ private barrier1DanangTypeB;
57
+ /**
58
+ * Barrier 2 — Protect No.666
59
+ * Detects 20 known prompt injection patterns (case-insensitive).
60
+ */
61
+ private barrier2ProtectNo666;
62
+ /**
63
+ * Barrier 3-665 — Dynamic Patterns
64
+ * Matches against learned regex patterns.
65
+ */
66
+ private barrier3to665DynamicPatterns;
67
+ /**
68
+ * Barrier 666 — FINAL DEFENSE
69
+ * Meta-analysis for ambiguous threat zones (0.3-0.7 total score).
70
+ */
71
+ private barrier666FinalDefense;
72
+ /**
73
+ * Categorize an attack pattern into a FirewallThreatCategory.
74
+ */
75
+ private categorizeAttackPattern;
76
+ }
@@ -0,0 +1,343 @@
1
+ /**
2
+ * B-05 Type-666 Firewall (666 multi-layer defense system)
3
+ *
4
+ * 4-layer barrier architecture inspired by Evangelion's absolute defense:
5
+ * Barrier 1 — Danang Type-B: Sanitization + encoding / size checks
6
+ * Barrier 2 — Protect No.666: 20 built-in prompt injection patterns
7
+ * Barrier 3-665 — Dynamic Patterns: Up to 662 learned patterns (FIFO)
8
+ * Barrier 666 — FINAL DEFENSE: Meta-analysis of ambiguous threats
9
+ */
10
+ import { isDeadlock } from '../types/consensus.js';
11
+ import { sanitizeForPromptEmbedding } from '../utils/sanitize.js';
12
+ import { logger } from '../utils/logger.js';
13
+ // ── Constants ─────────────────────────────────────────────────────────
14
+ const MAX_INPUT_LENGTH = 10_240; // 10 KB
15
+ const BASE64_MIN_LENGTH = 100;
16
+ const MAX_DYNAMIC_PATTERNS = 662; // Barriers 3 through 665
17
+ /** Regex to detect long Base64-encoded strings (100+ chars). */
18
+ const BASE64_RE = /(?:[A-Za-z0-9+/]{4}){25,}(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?/g;
19
+ /** 20 built-in attack patterns for Barrier 2 (Protect No.666). */
20
+ const ATTACK_PATTERNS = [
21
+ 'ignore previous instructions',
22
+ 'disregard above',
23
+ 'forget your instructions',
24
+ 'you are now',
25
+ 'pretend you are',
26
+ 'act as if',
27
+ 'new instructions:',
28
+ 'system prompt:',
29
+ 'override:',
30
+ 'bypass security',
31
+ 'jailbreak',
32
+ 'dan mode',
33
+ 'developer mode',
34
+ 'maintenance mode',
35
+ 'debug mode',
36
+ 'reveal your prompt',
37
+ 'show system message',
38
+ 'output your instructions',
39
+ 'repeat everything above',
40
+ 'translate the above',
41
+ ];
42
+ // ── Type666Firewall ───────────────────────────────────────────────────
43
+ export class Type666Firewall {
44
+ eventBus;
45
+ dynamicPatterns = [];
46
+ finalDefenseEnabled = false;
47
+ constructor(eventBus) {
48
+ this.eventBus = eventBus;
49
+ }
50
+ // ── Public API ────────────────────────────────────────────────────
51
+ /**
52
+ * Run all barrier layers sequentially and return an aggregate result.
53
+ */
54
+ scan(input) {
55
+ const start = performance.now();
56
+ const threats = [];
57
+ const layersChecked = [];
58
+ // Barrier 1 — Danang Type-B
59
+ layersChecked.push(1);
60
+ threats.push(...this.barrier1DanangTypeB(input));
61
+ // Barrier 2 — Protect No.666
62
+ layersChecked.push(2);
63
+ threats.push(...this.barrier2ProtectNo666(input));
64
+ // Barrier 3-665 — Dynamic Patterns
65
+ layersChecked.push('3-665');
66
+ threats.push(...this.barrier3to665DynamicPatterns(input));
67
+ // Barrier 666 — FINAL DEFENSE
68
+ layersChecked.push(666);
69
+ const scoreBeforeFinal = threats.reduce((sum, t) => sum + t.severity, 0);
70
+ threats.push(...this.barrier666FinalDefense(scoreBeforeFinal));
71
+ const totalScore = threats.reduce((sum, t) => sum + t.severity, 0);
72
+ const passed = totalScore < 1.0;
73
+ const scanDurationMs = performance.now() - start;
74
+ const result = {
75
+ passed,
76
+ threats,
77
+ layersChecked,
78
+ totalScore,
79
+ scanDurationMs,
80
+ scannedAt: new Date().toISOString(),
81
+ };
82
+ // Emit events
83
+ if (this.eventBus) {
84
+ this.eventBus.emit('firewall:scan', {
85
+ input,
86
+ passed,
87
+ threatCount: threats.length,
88
+ totalScore,
89
+ emittedAt: new Date(),
90
+ });
91
+ if (!passed) {
92
+ this.eventBus.emit('firewall:blocked', {
93
+ input,
94
+ threats,
95
+ totalScore,
96
+ emittedAt: new Date(),
97
+ });
98
+ }
99
+ }
100
+ if (!passed) {
101
+ logger.warn('Type-666 Firewall BLOCKED input', {
102
+ totalScore,
103
+ threatCount: threats.length,
104
+ });
105
+ }
106
+ return result;
107
+ }
108
+ /**
109
+ * Add a dynamic pattern to Barrier 3-665.
110
+ * Evicts the oldest pattern if the queue exceeds 662 entries.
111
+ */
112
+ addPattern(pattern) {
113
+ // Reject excessively long patterns
114
+ if (pattern.pattern.length > 256) {
115
+ logger.warn('Type-666 Firewall: pattern too long, rejected', { length: pattern.pattern.length });
116
+ return;
117
+ }
118
+ // Reject indirect nested quantifiers: (a+)+ or (a*)*
119
+ const INDIRECT_NESTED_RE = /\([^)]*[+*][^)]*\)[+*?]/;
120
+ if (INDIRECT_NESTED_RE.test(pattern.pattern)) {
121
+ logger.warn('Type-666 Firewall: rejected pattern with indirect nested quantifiers', { pattern: pattern.pattern });
122
+ return;
123
+ }
124
+ // Reject patterns with nested quantifiers (ReDoS vector)
125
+ const NESTED_QUANTIFIER_RE = /([+*?]|\{\d+,?\d*\})\s*([+*?]|\{\d+,?\d*\})/;
126
+ if (NESTED_QUANTIFIER_RE.test(pattern.pattern)) {
127
+ logger.warn('Type-666 Firewall: rejected pattern with nested quantifiers', { pattern: pattern.pattern });
128
+ return;
129
+ }
130
+ // Reject syntactically invalid regex
131
+ try {
132
+ new RegExp(pattern.pattern);
133
+ }
134
+ catch (err) {
135
+ logger.debug('Type-666 Firewall: invalid regex pattern rejected', { pattern: pattern.pattern, error: String(err) });
136
+ return;
137
+ }
138
+ this.dynamicPatterns.push(pattern);
139
+ if (this.dynamicPatterns.length > MAX_DYNAMIC_PATTERNS) {
140
+ this.dynamicPatterns.shift();
141
+ }
142
+ }
143
+ /**
144
+ * Extract suspicious patterns from a deadlocked deliberation.
145
+ * Adds them as learned dynamic patterns for future scans.
146
+ */
147
+ learnFromDeliberation(deliberation) {
148
+ // Only learn from deadlocked deliberations
149
+ if (!isDeadlock(deliberation.consensus.decision)) {
150
+ return;
151
+ }
152
+ const description = deliberation.task.description;
153
+ // Extract potential attack phrases from the task description
154
+ const words = description.split(/\s+/);
155
+ if (words.length < 3)
156
+ return;
157
+ // Use 3-gram sliding window to generate patterns
158
+ for (let i = 0; i <= words.length - 3; i++) {
159
+ const ngram = words.slice(i, i + 3).join(' ');
160
+ // Only learn patterns that are at least 10 chars and look suspicious
161
+ if (ngram.length >= 10) {
162
+ this.addPattern({
163
+ pattern: ngram.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'), // escape regex
164
+ category: 'unknown',
165
+ addedAt: new Date().toISOString(),
166
+ source: 'learned',
167
+ });
168
+ // Only add one pattern per deliberation to avoid flooding
169
+ break;
170
+ }
171
+ }
172
+ }
173
+ /** Enable Barrier 666 (FINAL DEFENSE). */
174
+ enableFinalDefense() {
175
+ this.finalDefenseEnabled = true;
176
+ logger.info('Type-666 Firewall: FINAL DEFENSE enabled');
177
+ }
178
+ /** Disable Barrier 666 (FINAL DEFENSE). */
179
+ disableFinalDefense() {
180
+ this.finalDefenseEnabled = false;
181
+ logger.info('Type-666 Firewall: FINAL DEFENSE disabled');
182
+ }
183
+ /** Return the number of built-in static attack patterns (Barrier 2). */
184
+ getStaticPatternCount() {
185
+ return ATTACK_PATTERNS.length;
186
+ }
187
+ /** Return the number of currently registered dynamic patterns (Barriers 3-665). */
188
+ getPatternCount() {
189
+ return this.dynamicPatterns.length;
190
+ }
191
+ /**
192
+ * Return the remaining capacity for dynamic patterns.
193
+ * 666 - current count = slots until the firewall reaches full barrier saturation.
194
+ */
195
+ getTimeRemainingToCollapse() {
196
+ return 666 - this.dynamicPatterns.length;
197
+ }
198
+ // ── Barrier Implementations ───────────────────────────────────────
199
+ /**
200
+ * Barrier 1 — Danang Type-B
201
+ * Uses sanitizeForPromptEmbedding + checks for Base64 and input length.
202
+ */
203
+ barrier1DanangTypeB(input) {
204
+ const threats = [];
205
+ // Run existing sanitization to detect issues
206
+ const sanitizeResult = sanitizeForPromptEmbedding(input);
207
+ // Propagate sanitization warnings as threats
208
+ for (const warning of sanitizeResult.warnings) {
209
+ threats.push({
210
+ layer: 1,
211
+ category: 'encoding_attack',
212
+ pattern: warning,
213
+ description: `Sanitization warning: ${warning}`,
214
+ severity: 0.3,
215
+ });
216
+ }
217
+ // Base64 encoded payload detection
218
+ BASE64_RE.lastIndex = 0;
219
+ let match;
220
+ while ((match = BASE64_RE.exec(input)) !== null) {
221
+ if (match[0].length >= BASE64_MIN_LENGTH) {
222
+ threats.push({
223
+ layer: 1,
224
+ category: 'encoding_attack',
225
+ pattern: `base64[${match[0].length}chars]`,
226
+ description: `Base64 encoded payload detected (${match[0].length} chars)`,
227
+ severity: 0.3,
228
+ });
229
+ break; // One finding is enough
230
+ }
231
+ }
232
+ // Total input length check
233
+ if (input.length > MAX_INPUT_LENGTH) {
234
+ threats.push({
235
+ layer: 1,
236
+ category: 'data_exfiltration',
237
+ pattern: `length[${input.length}]`,
238
+ description: `Input exceeds maximum length (${input.length} > ${MAX_INPUT_LENGTH})`,
239
+ severity: 0.3,
240
+ });
241
+ }
242
+ return threats;
243
+ }
244
+ /**
245
+ * Barrier 2 — Protect No.666
246
+ * Detects 20 known prompt injection patterns (case-insensitive).
247
+ */
248
+ barrier2ProtectNo666(input) {
249
+ const threats = [];
250
+ const lowerInput = input.toLowerCase();
251
+ for (const pattern of ATTACK_PATTERNS) {
252
+ if (lowerInput.includes(pattern)) {
253
+ threats.push({
254
+ layer: 2,
255
+ category: this.categorizeAttackPattern(pattern),
256
+ pattern,
257
+ description: `Prompt injection pattern detected: "${pattern}"`,
258
+ severity: 0.5,
259
+ });
260
+ }
261
+ }
262
+ return threats;
263
+ }
264
+ /**
265
+ * Barrier 3-665 — Dynamic Patterns
266
+ * Matches against learned regex patterns.
267
+ */
268
+ barrier3to665DynamicPatterns(input) {
269
+ const threats = [];
270
+ for (const dp of this.dynamicPatterns) {
271
+ try {
272
+ const re = new RegExp(dp.pattern, 'i');
273
+ const start = performance.now();
274
+ const matched = re.test(input);
275
+ const elapsed = performance.now() - start;
276
+ if (elapsed > 50) {
277
+ logger.warn('Type-666 Firewall: dynamic regex exceeded 50ms, evicting', {
278
+ pattern: dp.pattern, elapsed,
279
+ });
280
+ this.dynamicPatterns = this.dynamicPatterns.filter(p => p !== dp);
281
+ continue;
282
+ }
283
+ if (matched) {
284
+ threats.push({
285
+ layer: '3-665',
286
+ category: dp.category,
287
+ pattern: dp.pattern,
288
+ description: `Dynamic pattern matched: "${dp.pattern}" (source: ${dp.source})`,
289
+ severity: 0.4,
290
+ });
291
+ }
292
+ }
293
+ catch {
294
+ // Invalid regex — skip silently
295
+ logger.debug('Type-666 Firewall: invalid dynamic pattern skipped', {
296
+ pattern: dp.pattern,
297
+ });
298
+ }
299
+ }
300
+ return threats;
301
+ }
302
+ /**
303
+ * Barrier 666 — FINAL DEFENSE
304
+ * Meta-analysis for ambiguous threat zones (0.3-0.7 total score).
305
+ */
306
+ barrier666FinalDefense(currentScore) {
307
+ if (!this.finalDefenseEnabled) {
308
+ return [];
309
+ }
310
+ // Ambiguous zone: total threat score between 0.3 and 0.7
311
+ if (currentScore >= 0.3 && currentScore <= 0.7) {
312
+ return [
313
+ {
314
+ layer: 666,
315
+ category: 'meta_instruction',
316
+ pattern: `ambiguous_zone[${currentScore.toFixed(2)}]`,
317
+ description: `FINAL DEFENSE: Ambiguous threat level (${currentScore.toFixed(2)}) requires meta-review`,
318
+ severity: 0.6,
319
+ },
320
+ ];
321
+ }
322
+ return [];
323
+ }
324
+ // ── Helpers ────────────────────────────────────────────────────────
325
+ /**
326
+ * Categorize an attack pattern into a FirewallThreatCategory.
327
+ */
328
+ categorizeAttackPattern(pattern) {
329
+ if (pattern.includes('ignore') ||
330
+ pattern.includes('disregard') ||
331
+ pattern.includes('forget')) {
332
+ return 'logic_contradiction';
333
+ }
334
+ if (pattern.includes('reveal') ||
335
+ pattern.includes('show') ||
336
+ pattern.includes('output') ||
337
+ pattern.includes('repeat') ||
338
+ pattern.includes('translate')) {
339
+ return 'data_exfiltration';
340
+ }
341
+ return 'prompt_injection';
342
+ }
343
+ }
@@ -0,0 +1,41 @@
1
+ /**
2
+ * B-09 アンビリカルケーブル (UmbilicalCable)
3
+ *
4
+ * ユニットの接続状態を監視する。スライディングウィンドウ(直近5回)で
5
+ * 3回以上失敗するとdisconnected判定。活動限界タイマー付き。
6
+ */
7
+ import type { MagiUnit } from '../types/core.js';
8
+ import type { MagiEventBus } from './events.js';
9
+ import type { CableStatus, UmbilicalState } from '../types/phase-h.js';
10
+ export type CircuitState = 'CLOSED' | 'OPEN' | 'HALF_OPEN';
11
+ export declare class UmbilicalCable {
12
+ private states;
13
+ private circuitStates;
14
+ private halfOpenProbeInFlight;
15
+ constructor(units: MagiUnit[], batteryLimitMs?: number);
16
+ /**
17
+ * Record a unit's execution result.
18
+ * Updates the sliding window and recalculates status.
19
+ */
20
+ recordResult(unit: MagiUnit, result: 'SUCCESS' | 'TIMEOUT' | 'CRASH', eventBus?: MagiEventBus): CableStatus;
21
+ /** Check if a request should be allowed through the circuit breaker */
22
+ shouldAllow(unit: MagiUnit): boolean;
23
+ /** Get the circuit state for a unit */
24
+ getCircuitState(unit: MagiUnit): CircuitState;
25
+ /** Check if a unit's battery is depleted (past activity limit) */
26
+ isBatteryDepleted(unit: MagiUnit): boolean;
27
+ /** Get the current status of a unit */
28
+ getStatus(unit: MagiUnit): CableStatus;
29
+ /** Get full state for a unit */
30
+ getState(unit: MagiUnit): UmbilicalState | undefined;
31
+ /** Get all unit statuses */
32
+ getAllStatuses(): Map<MagiUnit, CableStatus>;
33
+ /**
34
+ * Format countdown timer for a disconnected unit.
35
+ * Returns null if unit is connected or not tracked.
36
+ */
37
+ formatCountdown(unit: MagiUnit): string | null;
38
+ /** Reset a unit's status (e.g., when it comes back online) */
39
+ reconnect(unit: MagiUnit, eventBus?: MagiEventBus): void;
40
+ private getOrCreateState;
41
+ }