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,334 @@
1
+ /**
2
+ * AngelDetector -- 使徒検知システム (A-04)
3
+ *
4
+ * Monitors git diffs for 6 types of suspicious patterns (Angels):
5
+ *
6
+ * SACHIEL - Security-sensitive file changes
7
+ * SHAMSHEL - High-coupling hub node changes (co-change graph)
8
+ * RAMIEL - High-entropy (scattered) changes
9
+ * GAGHIEL - Ancient code modification
10
+ * ISRAFEL - Multi-developer conflict zones
11
+ * IRUEL - Boil-frog micro changes (death by a thousand cuts)
12
+ *
13
+ * Each detection returns a ThreatLevel (YELLOW / ORANGE / RED)
14
+ * and emits 'angel:detected' events via the MagiEventBus.
15
+ */
16
+ import { getCommitFiles, computeEntropy, getFileAge, getFileDevCount, getCochangeGraph, computeKameiMetrics, } from './change-metrics.js';
17
+ import { execGit } from './change-metrics.js';
18
+ import { logger } from '../utils/logger.js';
19
+ // ── Default configuration ──────────────────────────────────────
20
+ const DEFAULT_CONFIG = {
21
+ securityPatterns: [
22
+ /\.env/,
23
+ /secret/i,
24
+ /password/i,
25
+ /auth/i,
26
+ /token/i,
27
+ /key/i,
28
+ /\.pem$/,
29
+ /\.key$/,
30
+ ],
31
+ entropyThreshold: 0.8,
32
+ ancientThresholdDays: 365,
33
+ hubDegreeThreshold: 5,
34
+ microChangeThreshold: 10,
35
+ pollIntervalMs: 30_000,
36
+ };
37
+ // ── AngelDetector class ────────────────────────────────────────
38
+ export class AngelDetector {
39
+ config;
40
+ eventBus;
41
+ cochangeGraph = [];
42
+ microChangeHistory = new Map();
43
+ watchTimer;
44
+ lastWatchedCommit;
45
+ constructor(config, eventBus) {
46
+ this.config = { ...DEFAULT_CONFIG, ...config };
47
+ this.eventBus = eventBus;
48
+ }
49
+ // ── Public API ──────────────────────────────────────────────
50
+ /**
51
+ * Run all 6 angel detectors against a single commit.
52
+ * Returns all detected angels (may be empty).
53
+ */
54
+ async detectFromCommit(commitHash, cwd) {
55
+ const files = await getCommitFiles(commitHash, cwd);
56
+ const metrics = await computeKameiMetrics(commitHash, cwd);
57
+ const entropy = computeEntropy(files);
58
+ const detections = [];
59
+ const sachiel = await this.detectSachiel(commitHash, files, metrics);
60
+ if (sachiel)
61
+ detections.push(sachiel);
62
+ const shamshel = this.detectShamshel(commitHash, files, metrics);
63
+ if (shamshel)
64
+ detections.push(shamshel);
65
+ const ramiel = this.detectRamiel(commitHash, files, metrics, entropy);
66
+ if (ramiel)
67
+ detections.push(ramiel);
68
+ const gaghiel = await this.detectGaghiel(commitHash, files, metrics, cwd);
69
+ if (gaghiel)
70
+ detections.push(gaghiel);
71
+ const israfel = await this.detectIsrafel(commitHash, files, metrics, cwd);
72
+ if (israfel)
73
+ detections.push(israfel);
74
+ this.detectIruel(commitHash, files, metrics, detections);
75
+ // Emit events for all detections
76
+ for (const detection of detections) {
77
+ this.eventBus?.emit('angel:detected', {
78
+ commitHash: detection.commitHash,
79
+ angel: detection.angel,
80
+ threatLevel: detection.threatLevel,
81
+ affectedFiles: detection.affectedFiles,
82
+ emittedAt: new Date(),
83
+ });
84
+ }
85
+ return detections;
86
+ }
87
+ /**
88
+ * Start polling for new commits and running detection.
89
+ */
90
+ startWatch(cwd) {
91
+ if (this.watchTimer)
92
+ return; // Already watching
93
+ this.watchTimer = setInterval(async () => {
94
+ try {
95
+ const head = await execGit(['rev-parse', 'HEAD'], cwd);
96
+ if (head && head !== this.lastWatchedCommit) {
97
+ this.lastWatchedCommit = head;
98
+ await this.detectFromCommit(head, cwd);
99
+ }
100
+ }
101
+ catch (err) {
102
+ logger.debug('AngelDetector: git error during watch poll', { error: String(err) });
103
+ }
104
+ }, this.config.pollIntervalMs);
105
+ }
106
+ /**
107
+ * Stop the watch polling.
108
+ */
109
+ stopWatch() {
110
+ if (this.watchTimer) {
111
+ clearInterval(this.watchTimer);
112
+ this.watchTimer = undefined;
113
+ }
114
+ }
115
+ /**
116
+ * Get the current co-change graph.
117
+ */
118
+ getCochangeGraph() {
119
+ return [...this.cochangeGraph];
120
+ }
121
+ /**
122
+ * Rebuild the internal co-change graph from a set of commits.
123
+ */
124
+ async updateCochangeGraph(commitHashes, cwd) {
125
+ this.cochangeGraph = await getCochangeGraph(commitHashes, cwd);
126
+ }
127
+ // ── Private detectors ───────────────────────────────────────
128
+ /**
129
+ * SACHIEL: Detect security-sensitive file changes.
130
+ * Checks if any changed file matches securityPatterns.
131
+ * ThreatLevel based on LA + LD: >100 RED, >30 ORANGE, else YELLOW.
132
+ */
133
+ async detectSachiel(commitHash, files, metrics) {
134
+ const matchedFiles = files.filter(f => this.config.securityPatterns.some(p => p.test(f.filePath)));
135
+ if (matchedFiles.length === 0)
136
+ return null;
137
+ const totalLA = matchedFiles.reduce((sum, f) => sum + f.linesAdded, 0);
138
+ const totalLD = matchedFiles.reduce((sum, f) => sum + f.linesDeleted, 0);
139
+ const totalChanges = totalLA + totalLD;
140
+ let threatLevel;
141
+ if (totalChanges > 100) {
142
+ threatLevel = 'RED';
143
+ }
144
+ else if (totalChanges > 30) {
145
+ threatLevel = 'ORANGE';
146
+ }
147
+ else {
148
+ threatLevel = 'YELLOW';
149
+ }
150
+ return {
151
+ angel: 'SACHIEL',
152
+ threatLevel,
153
+ commitHash,
154
+ description: `Security-sensitive files modified: ${matchedFiles.map(f => f.filePath).join(', ')}`,
155
+ affectedFiles: matchedFiles.map(f => f.filePath),
156
+ metrics,
157
+ detectedAt: new Date().toISOString(),
158
+ };
159
+ }
160
+ /**
161
+ * SHAMSHEL: Detect high-coupling hub node changes.
162
+ * If any changed file has degree >= hubDegreeThreshold in the co-change graph.
163
+ * RED if degree > 2x threshold, ORANGE if > 1.5x.
164
+ */
165
+ detectShamshel(commitHash, files, metrics) {
166
+ if (this.cochangeGraph.length === 0)
167
+ return null;
168
+ // Compute degree for each file in the graph
169
+ const degreeMap = new Map();
170
+ for (const edge of this.cochangeGraph) {
171
+ degreeMap.set(edge.fileA, (degreeMap.get(edge.fileA) ?? 0) + 1);
172
+ degreeMap.set(edge.fileB, (degreeMap.get(edge.fileB) ?? 0) + 1);
173
+ }
174
+ const hubFiles = [];
175
+ let maxDegree = 0;
176
+ for (const f of files) {
177
+ const degree = degreeMap.get(f.filePath) ?? 0;
178
+ if (degree >= this.config.hubDegreeThreshold) {
179
+ hubFiles.push({ filePath: f.filePath, degree });
180
+ if (degree > maxDegree)
181
+ maxDegree = degree;
182
+ }
183
+ }
184
+ if (hubFiles.length === 0)
185
+ return null;
186
+ let threatLevel;
187
+ if (maxDegree > 2 * this.config.hubDegreeThreshold) {
188
+ threatLevel = 'RED';
189
+ }
190
+ else if (maxDegree > 1.5 * this.config.hubDegreeThreshold) {
191
+ threatLevel = 'ORANGE';
192
+ }
193
+ else {
194
+ threatLevel = 'YELLOW';
195
+ }
196
+ return {
197
+ angel: 'SHAMSHEL',
198
+ threatLevel,
199
+ commitHash,
200
+ description: `Hub node(s) modified (max degree ${maxDegree}): ${hubFiles.map(h => h.filePath).join(', ')}`,
201
+ affectedFiles: hubFiles.map(h => h.filePath),
202
+ metrics,
203
+ detectedAt: new Date().toISOString(),
204
+ };
205
+ }
206
+ /**
207
+ * RAMIEL: Detect high-entropy (scattered) changes.
208
+ * If computeEntropy(changes) > entropyThreshold.
209
+ * RED if > 0.95, ORANGE if > threshold.
210
+ */
211
+ detectRamiel(commitHash, files, metrics, entropy) {
212
+ if (entropy <= this.config.entropyThreshold)
213
+ return null;
214
+ let threatLevel;
215
+ if (entropy > 0.95) {
216
+ threatLevel = 'RED';
217
+ }
218
+ else {
219
+ threatLevel = 'ORANGE';
220
+ }
221
+ return {
222
+ angel: 'RAMIEL',
223
+ threatLevel,
224
+ commitHash,
225
+ description: `High entropy change detected (${entropy.toFixed(3)}), changes are widely scattered`,
226
+ affectedFiles: files.map(f => f.filePath),
227
+ metrics,
228
+ detectedAt: new Date().toISOString(),
229
+ };
230
+ }
231
+ /**
232
+ * GAGHIEL: Detect ancient code modification.
233
+ * If any file age > ancientThresholdDays.
234
+ * RED if > 3x threshold, ORANGE if > 2x, else YELLOW.
235
+ */
236
+ async detectGaghiel(commitHash, files, metrics, cwd) {
237
+ const ancientFiles = [];
238
+ let maxAge = 0;
239
+ for (const f of files) {
240
+ const age = await getFileAge(f.filePath, cwd);
241
+ if (age > this.config.ancientThresholdDays) {
242
+ ancientFiles.push({ filePath: f.filePath, ageDays: age });
243
+ if (age > maxAge)
244
+ maxAge = age;
245
+ }
246
+ }
247
+ if (ancientFiles.length === 0)
248
+ return null;
249
+ let threatLevel;
250
+ if (maxAge > 3 * this.config.ancientThresholdDays) {
251
+ threatLevel = 'RED';
252
+ }
253
+ else if (maxAge > 2 * this.config.ancientThresholdDays) {
254
+ threatLevel = 'ORANGE';
255
+ }
256
+ else {
257
+ threatLevel = 'YELLOW';
258
+ }
259
+ return {
260
+ angel: 'GAGHIEL',
261
+ threatLevel,
262
+ commitHash,
263
+ description: `Ancient code modified (max age ${maxAge} days): ${ancientFiles.map(a => a.filePath).join(', ')}`,
264
+ affectedFiles: ancientFiles.map(a => a.filePath),
265
+ metrics,
266
+ detectedAt: new Date().toISOString(),
267
+ };
268
+ }
269
+ /**
270
+ * ISRAFEL: Detect multi-developer conflict zones.
271
+ * If any file has NDEV >= 3 and changes from multiple devs.
272
+ * RED if NDEV >= 5, ORANGE if NDEV >= 3.
273
+ */
274
+ async detectIsrafel(commitHash, files, metrics, cwd) {
275
+ const conflictFiles = [];
276
+ let maxNdev = 0;
277
+ for (const f of files) {
278
+ const ndev = await getFileDevCount(f.filePath, cwd);
279
+ if (ndev >= 3) {
280
+ conflictFiles.push({ filePath: f.filePath, ndev });
281
+ if (ndev > maxNdev)
282
+ maxNdev = ndev;
283
+ }
284
+ }
285
+ if (conflictFiles.length === 0)
286
+ return null;
287
+ let threatLevel;
288
+ if (maxNdev >= 5) {
289
+ threatLevel = 'RED';
290
+ }
291
+ else {
292
+ threatLevel = 'ORANGE';
293
+ }
294
+ return {
295
+ angel: 'ISRAFEL',
296
+ threatLevel,
297
+ commitHash,
298
+ description: `Multi-developer conflict zone (max NDEV ${maxNdev}): ${conflictFiles.map(c => c.filePath).join(', ')}`,
299
+ affectedFiles: conflictFiles.map(c => c.filePath),
300
+ metrics,
301
+ detectedAt: new Date().toISOString(),
302
+ };
303
+ }
304
+ /**
305
+ * IRUEL: Detect boil-frog micro changes.
306
+ * Track commits with < 5 total lines changed.
307
+ * If accumulated micro-change count exceeds threshold, alert.
308
+ */
309
+ detectIruel(commitHash, files, metrics, detections) {
310
+ const totalLines = files.reduce((sum, f) => sum + f.linesAdded + f.linesDeleted, 0);
311
+ // Track all micro-changes (< 5 lines total)
312
+ if (totalLines < 5) {
313
+ this.microChangeHistory.set(commitHash, totalLines);
314
+ }
315
+ if (this.microChangeHistory.size <= this.config.microChangeThreshold)
316
+ return;
317
+ let threatLevel;
318
+ if (this.microChangeHistory.size > 2 * this.config.microChangeThreshold) {
319
+ threatLevel = 'RED';
320
+ }
321
+ else {
322
+ threatLevel = 'ORANGE';
323
+ }
324
+ detections.push({
325
+ angel: 'IRUEL',
326
+ threatLevel,
327
+ commitHash,
328
+ description: `Micro-change accumulation detected: ${this.microChangeHistory.size} micro-commits tracked (threshold: ${this.config.microChangeThreshold})`,
329
+ affectedFiles: files.map(f => f.filePath),
330
+ metrics,
331
+ detectedAt: new Date().toISOString(),
332
+ });
333
+ }
334
+ }
@@ -0,0 +1,40 @@
1
+ /**
2
+ * A-02 A.T.フィールド (ATField)
3
+ *
4
+ * バイアス検出モジュール。全会一致の連続回数、投票エントロピー、
5
+ * keyPointsのJaccard距離、confidence分散を監視し、
6
+ * 集団思考のリスクをA.T.フィールドレベルとして表現する。
7
+ */
8
+ import type { MagiOpinion } from '../types/core.js';
9
+ import type { MagiEventBus } from './events.js';
10
+ import type { BiasDetectionResult } from '../types/phase-h.js';
11
+ export declare class ATField {
12
+ private unanimousStreak;
13
+ /**
14
+ * Analyze a set of opinions for bias indicators.
15
+ * Returns a BiasDetectionResult with level, metrics, and optional catfish advocate.
16
+ */
17
+ analyze(opinions: MagiOpinion[], eventBus: MagiEventBus | undefined, deliberationId: string): BiasDetectionResult;
18
+ /** Reset unanimous streak (e.g., between deliberations) */
19
+ reset(): void;
20
+ /** Get current unanimous streak count */
21
+ getUnanimousStreak(): number;
22
+ /**
23
+ * Shannon entropy of vote distribution.
24
+ * H = -Σ(p_i × log₂(p_i))
25
+ * Max entropy for 3 choices = log₂(3) ≈ 1.585
26
+ */
27
+ voteEntropy(opinions: MagiOpinion[]): number;
28
+ /** Variance of confidence values */
29
+ confidenceVariance(opinions: MagiOpinion[]): number;
30
+ /**
31
+ * Average pairwise Jaccard distance of keyPoints.
32
+ * Jaccard distance = 1 - |A∩B| / |A∪B|
33
+ * Higher distance = more diverse perspectives.
34
+ */
35
+ averageJaccardDistance(opinions: MagiOpinion[]): number;
36
+ /** Generate devil's advocate text based on current opinions */
37
+ private generateCatfishAdvocate;
38
+ private getMajorityVote;
39
+ private buildResult;
40
+ }
@@ -0,0 +1,195 @@
1
+ /**
2
+ * A-02 A.T.フィールド (ATField)
3
+ *
4
+ * バイアス検出モジュール。全会一致の連続回数、投票エントロピー、
5
+ * keyPointsのJaccard距離、confidence分散を監視し、
6
+ * 集団思考のリスクをA.T.フィールドレベルとして表現する。
7
+ */
8
+ /** 5 consecutive unanimous rounds trigger bias warning */
9
+ const UNANIMOUS_STREAK_THRESHOLD = 5;
10
+ /** Confidence discount applied when bias is detected */
11
+ const BIAS_CONFIDENCE_DISCOUNT = 0.3;
12
+ /** Entropy threshold for low diversity */
13
+ const LOW_ENTROPY_THRESHOLD = 0.5;
14
+ /** Jaccard distance threshold for echo-chamber detection */
15
+ const LOW_JACCARD_THRESHOLD = 0.2;
16
+ export class ATField {
17
+ unanimousStreak = 0;
18
+ /**
19
+ * Analyze a set of opinions for bias indicators.
20
+ * Returns a BiasDetectionResult with level, metrics, and optional catfish advocate.
21
+ */
22
+ analyze(opinions, eventBus, deliberationId) {
23
+ if (opinions.length === 0) {
24
+ return this.buildResult(1, 0, 0, 0, deliberationId);
25
+ }
26
+ // Check if all non-abstain votes are the same
27
+ const nonAbstain = opinions.filter(o => o.vote !== 'ABSTAIN');
28
+ const allSame = nonAbstain.length > 1 &&
29
+ nonAbstain.every(o => o.vote === nonAbstain[0].vote);
30
+ if (allSame) {
31
+ this.unanimousStreak++;
32
+ }
33
+ else {
34
+ this.unanimousStreak = 0;
35
+ }
36
+ const entropy = this.voteEntropy(opinions);
37
+ const confVar = this.confidenceVariance(opinions);
38
+ const jaccard = this.averageJaccardDistance(opinions);
39
+ // Determine level
40
+ const biasWarning = this.unanimousStreak >= UNANIMOUS_STREAK_THRESHOLD;
41
+ const lowEntropy = entropy < LOW_ENTROPY_THRESHOLD && opinions.length > 1;
42
+ const lowJaccard = jaccard < LOW_JACCARD_THRESHOLD && opinions.length > 1;
43
+ let level;
44
+ if (biasWarning && lowEntropy && lowJaccard) {
45
+ level = 'MAX';
46
+ }
47
+ else if ((biasWarning && lowEntropy) || (biasWarning && lowJaccard)) {
48
+ level = 3;
49
+ }
50
+ else if (biasWarning || lowEntropy) {
51
+ level = 2;
52
+ }
53
+ else {
54
+ level = 1;
55
+ }
56
+ const confidenceDiscount = biasWarning ? BIAS_CONFIDENCE_DISCOUNT : 0;
57
+ const result = this.buildResult(level, entropy, confVar, jaccard, deliberationId);
58
+ result.biasWarning = biasWarning;
59
+ result.confidenceDiscount = confidenceDiscount;
60
+ if (level !== 1) {
61
+ result.catfishAdvocate = this.generateCatfishAdvocate(opinions, level);
62
+ }
63
+ if (eventBus) {
64
+ eventBus.emit('bias:detected', {
65
+ deliberationId,
66
+ level,
67
+ biasWarning,
68
+ confidenceDiscount,
69
+ voteEntropy: entropy,
70
+ emittedAt: new Date(),
71
+ });
72
+ }
73
+ return result;
74
+ }
75
+ /** Reset unanimous streak (e.g., between deliberations) */
76
+ reset() {
77
+ this.unanimousStreak = 0;
78
+ }
79
+ /** Get current unanimous streak count */
80
+ getUnanimousStreak() {
81
+ return this.unanimousStreak;
82
+ }
83
+ /**
84
+ * Shannon entropy of vote distribution.
85
+ * H = -Σ(p_i × log₂(p_i))
86
+ * Max entropy for 3 choices = log₂(3) ≈ 1.585
87
+ */
88
+ voteEntropy(opinions) {
89
+ if (opinions.length === 0)
90
+ return 0;
91
+ const counts = {};
92
+ for (const o of opinions) {
93
+ counts[o.vote] = (counts[o.vote] ?? 0) + 1;
94
+ }
95
+ let entropy = 0;
96
+ const total = opinions.length;
97
+ for (const count of Object.values(counts)) {
98
+ if (count === 0)
99
+ continue;
100
+ const p = count / total;
101
+ entropy -= p * Math.log2(p);
102
+ }
103
+ return entropy;
104
+ }
105
+ /** Variance of confidence values */
106
+ confidenceVariance(opinions) {
107
+ if (opinions.length <= 1)
108
+ return 0;
109
+ const confs = opinions.map(o => o.confidence);
110
+ const mean = confs.reduce((a, b) => a + b, 0) / confs.length;
111
+ const variance = confs.reduce((sum, c) => sum + (c - mean) ** 2, 0) / confs.length;
112
+ return variance;
113
+ }
114
+ /**
115
+ * Average pairwise Jaccard distance of keyPoints.
116
+ * Jaccard distance = 1 - |A∩B| / |A∪B|
117
+ * Higher distance = more diverse perspectives.
118
+ */
119
+ averageJaccardDistance(opinions) {
120
+ if (opinions.length <= 1)
121
+ return 1; // single opinion → max diversity (no comparison)
122
+ const tokenSets = opinions.map(o => {
123
+ const tokens = new Set();
124
+ for (const kp of o.keyPoints) {
125
+ for (const word of kp.toLowerCase().split(/\s+/)) {
126
+ if (word.length > 2)
127
+ tokens.add(word);
128
+ }
129
+ }
130
+ return tokens;
131
+ });
132
+ let totalDistance = 0;
133
+ let pairs = 0;
134
+ for (let i = 0; i < tokenSets.length; i++) {
135
+ for (let j = i + 1; j < tokenSets.length; j++) {
136
+ const a = tokenSets[i];
137
+ const b = tokenSets[j];
138
+ const intersection = new Set([...a].filter(x => b.has(x)));
139
+ const union = new Set([...a, ...b]);
140
+ if (union.size === 0) {
141
+ totalDistance += 1; // both empty → treat as maximally different
142
+ }
143
+ else {
144
+ totalDistance += 1 - intersection.size / union.size;
145
+ }
146
+ pairs++;
147
+ }
148
+ }
149
+ return pairs > 0 ? totalDistance / pairs : 1;
150
+ }
151
+ /** Generate devil's advocate text based on current opinions */
152
+ generateCatfishAdvocate(opinions, level) {
153
+ const majorityVote = this.getMajorityVote(opinions);
154
+ const levelLabel = level === 'MAX' ? 'MAX' : `Level ${level}`;
155
+ const lines = [
156
+ `[A.T. FIELD ${levelLabel}] 悪魔の代弁者 — バイアス検出`,
157
+ `現在の全会一致ストリーク: ${this.unanimousStreak}回連続`,
158
+ ``,
159
+ ];
160
+ if (majorityVote === 'APPROVE') {
161
+ lines.push(`全ユニットがAPPROVEに傾いています。以下の観点を再検討してください:`, `- この決定のリスクやデメリットは十分に検討されていますか?`, `- 反対意見が出にくい構造的要因はありませんか?`, `- 最悪のケースシナリオは何ですか?`);
162
+ }
163
+ else {
164
+ lines.push(`全ユニットがREJECTに傾いています。以下の観点を再検討してください:`, `- この提案のメリットは十分に評価されていますか?`, `- 修正や条件付き承認の可能性はありませんか?`, `- 却下による機会損失は何ですか?`);
165
+ }
166
+ return lines.join('\n');
167
+ }
168
+ getMajorityVote(opinions) {
169
+ const counts = {};
170
+ for (const o of opinions) {
171
+ counts[o.vote] = (counts[o.vote] ?? 0) + 1;
172
+ }
173
+ let maxVote = 'ABSTAIN';
174
+ let maxCount = 0;
175
+ for (const [vote, count] of Object.entries(counts)) {
176
+ if (count > maxCount) {
177
+ maxVote = vote;
178
+ maxCount = count;
179
+ }
180
+ }
181
+ return maxVote;
182
+ }
183
+ buildResult(level, entropy, confVar, jaccard, deliberationId) {
184
+ return {
185
+ level,
186
+ voteEntropy: entropy,
187
+ confidenceVariance: confVar,
188
+ jaccardDistance: jaccard,
189
+ unanimousStreak: this.unanimousStreak,
190
+ biasWarning: false,
191
+ confidenceDiscount: 0,
192
+ deliberationId,
193
+ };
194
+ }
195
+ }
@@ -0,0 +1,66 @@
1
+ /**
2
+ * A-03 暴走モード (BERSERK) — BerserkOrchestrator
3
+ *
4
+ * Evolutionary deliberation engine that generates 5 strategy variants
5
+ * per unit, scores candidates by fitness, and iterates until UNANIMOUS
6
+ * consensus is reached or maxRounds safety valve triggers.
7
+ *
8
+ * Flow:
9
+ * 1. Generate 5 BerserkStrategy prompts (alpha~epsilon)
10
+ * 2. Execute adapters x strategies in parallel (up to concurrencyLimit)
11
+ * 3. Score candidates by fitness (confidence, reasoning quality, key points)
12
+ * 4. Select top-N survivors
13
+ * 5. Present survivors to ConsensusEngine
14
+ * 6. If UNANIMOUS → done. Else → re-vote with next round.
15
+ *
16
+ * Cache is intentionally disabled — BERSERK demands fresh computation.
17
+ * Timeout overrides are not applied — each adapter uses its own defaults.
18
+ */
19
+ import type { MagiTask, MagiDeliberation } from '../types/core.js';
20
+ import type { BerserkConfig, BerserkCandidate, BerserkStrategy } from '../types/phase-i.js';
21
+ import type { MagiEventBus } from './events.js';
22
+ import type { Type666Firewall } from './type666-firewall.js';
23
+ import type { AdapterRegistry } from '../adapters/registry.js';
24
+ import type { PipelineRegistry } from '../pipelines/registry.js';
25
+ import type { ContextManager } from '../context/manager.js';
26
+ import type { IPipeline } from '../types/pipeline.js';
27
+ /**
28
+ * Generate 5 distinct BerserkStrategy definitions.
29
+ * Each provides a unique analytical perspective to maximize opinion diversity.
30
+ */
31
+ export declare function generateStrategyPrompts(): BerserkStrategy[];
32
+ export declare class BerserkOrchestrator {
33
+ private readonly adapters;
34
+ private readonly pipelines;
35
+ private readonly contextManager;
36
+ private readonly eventBus?;
37
+ private readonly config;
38
+ private readonly semaphore;
39
+ private readonly consensusEngine;
40
+ private readonly strategies;
41
+ private readonly type666Firewall?;
42
+ private readonly unitExecutor;
43
+ private readonly fileAccessEnabled?;
44
+ constructor(adapters: AdapterRegistry, pipelines: PipelineRegistry, contextManager: ContextManager, eventBus?: MagiEventBus, config?: Partial<BerserkConfig>, type666Firewall?: Type666Firewall, fileAccessEnabled?: boolean);
45
+ /**
46
+ * Execute BERSERK deliberation.
47
+ *
48
+ * Generates strategy-varied opinions in parallel, selects by fitness,
49
+ * and iterates until UNANIMOUS or maxRounds.
50
+ */
51
+ deliberate(task: MagiTask, signal?: AbortSignal): Promise<MagiDeliberation>;
52
+ /**
53
+ * Execute all adapter x strategy combinations in parallel,
54
+ * bounded by the Semaphore concurrency limit.
55
+ */
56
+ executeParallel(task: MagiTask, strategies: BerserkStrategy[], pipeline: IPipeline, deliberationId: string): Promise<BerserkCandidate[]>;
57
+ /**
58
+ * Select top-N candidates by fitness score.
59
+ * Returns candidates sorted by fitness descending, capped at survivorCount.
60
+ */
61
+ fitnessSelection(candidates: BerserkCandidate[]): BerserkCandidate[];
62
+ /** Get the strategies used by this orchestrator. */
63
+ getStrategies(): BerserkStrategy[];
64
+ /** Get the current config. */
65
+ getConfig(): Readonly<BerserkConfig>;
66
+ }