magi-ai 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.ja.md +377 -0
- package/README.md +377 -0
- package/dist/bin/magi-benchmark.d.ts +14 -0
- package/dist/bin/magi-benchmark.js +93 -0
- package/dist/bin/magi-mcp.d.ts +8 -0
- package/dist/bin/magi-mcp.js +28 -0
- package/dist/bin/magi.d.ts +2 -0
- package/dist/bin/magi.js +634 -0
- package/dist/src/adapters/base.d.ts +34 -0
- package/dist/src/adapters/base.js +149 -0
- package/dist/src/adapters/claude.d.ts +29 -0
- package/dist/src/adapters/claude.js +65 -0
- package/dist/src/adapters/codex.d.ts +21 -0
- package/dist/src/adapters/codex.js +41 -0
- package/dist/src/adapters/gemini.d.ts +18 -0
- package/dist/src/adapters/gemini.js +31 -0
- package/dist/src/adapters/registry.d.ts +19 -0
- package/dist/src/adapters/registry.js +59 -0
- package/dist/src/audit/hash-chain.d.ts +21 -0
- package/dist/src/audit/hash-chain.js +70 -0
- package/dist/src/audit/types.d.ts +25 -0
- package/dist/src/audit/types.js +1 -0
- package/dist/src/audit/writer.d.ts +18 -0
- package/dist/src/audit/writer.js +100 -0
- package/dist/src/benchmark/golden-tasks.d.ts +9 -0
- package/dist/src/benchmark/golden-tasks.js +476 -0
- package/dist/src/benchmark/reporter.d.ts +5 -0
- package/dist/src/benchmark/reporter.js +107 -0
- package/dist/src/benchmark/runner.d.ts +30 -0
- package/dist/src/benchmark/runner.js +224 -0
- package/dist/src/benchmark/scorer.d.ts +12 -0
- package/dist/src/benchmark/scorer.js +124 -0
- package/dist/src/benchmark/types.d.ts +54 -0
- package/dist/src/benchmark/types.js +1 -0
- package/dist/src/cache/deliberation-cache.d.ts +49 -0
- package/dist/src/cache/deliberation-cache.js +127 -0
- package/dist/src/cli/commands/config-cmd.d.ts +11 -0
- package/dist/src/cli/commands/config-cmd.js +190 -0
- package/dist/src/cli/commands/demo.d.ts +12 -0
- package/dist/src/cli/commands/demo.js +66 -0
- package/dist/src/cli/commands/setup.d.ts +7 -0
- package/dist/src/cli/commands/setup.js +182 -0
- package/dist/src/cli/i18n.d.ts +89 -0
- package/dist/src/cli/i18n.js +176 -0
- package/dist/src/cli/interactive-select.d.ts +27 -0
- package/dist/src/cli/interactive-select.js +130 -0
- package/dist/src/cli/tui-setup.d.ts +24 -0
- package/dist/src/cli/tui-setup.js +42 -0
- package/dist/src/config/cli-detector.d.ts +37 -0
- package/dist/src/config/cli-detector.js +99 -0
- package/dist/src/config/user-config.d.ts +81 -0
- package/dist/src/config/user-config.js +134 -0
- package/dist/src/context/auto-collector.d.ts +43 -0
- package/dist/src/context/auto-collector.js +337 -0
- package/dist/src/context/manager.d.ts +35 -0
- package/dist/src/context/manager.js +162 -0
- package/dist/src/context/serializer.d.ts +20 -0
- package/dist/src/context/serializer.js +52 -0
- package/dist/src/demo/recorded-deliberation.d.ts +13 -0
- package/dist/src/demo/recorded-deliberation.js +277 -0
- package/dist/src/engine/angel-detector.d.ts +83 -0
- package/dist/src/engine/angel-detector.js +334 -0
- package/dist/src/engine/at-field.d.ts +40 -0
- package/dist/src/engine/at-field.js +195 -0
- package/dist/src/engine/berserk-orchestrator.d.ts +66 -0
- package/dist/src/engine/berserk-orchestrator.js +378 -0
- package/dist/src/engine/change-metrics.d.ts +56 -0
- package/dist/src/engine/change-metrics.js +214 -0
- package/dist/src/engine/consensus.d.ts +20 -0
- package/dist/src/engine/consensus.js +146 -0
- package/dist/src/engine/dead-sea-scrolls.d.ts +132 -0
- package/dist/src/engine/dead-sea-scrolls.js +610 -0
- package/dist/src/engine/drift-detector.d.ts +39 -0
- package/dist/src/engine/drift-detector.js +225 -0
- package/dist/src/engine/dummy-plug.d.ts +44 -0
- package/dist/src/engine/dummy-plug.js +190 -0
- package/dist/src/engine/engram-manager.d.ts +55 -0
- package/dist/src/engine/engram-manager.js +306 -0
- package/dist/src/engine/events.d.ts +130 -0
- package/dist/src/engine/events.js +44 -0
- package/dist/src/engine/gospel.d.ts +30 -0
- package/dist/src/engine/gospel.js +129 -0
- package/dist/src/engine/hallucination-detector.d.ts +33 -0
- package/dist/src/engine/hallucination-detector.js +215 -0
- package/dist/src/engine/human-resolver.d.ts +19 -0
- package/dist/src/engine/human-resolver.js +89 -0
- package/dist/src/engine/instrumentality.d.ts +64 -0
- package/dist/src/engine/instrumentality.js +297 -0
- package/dist/src/engine/iruel-battle.d.ts +79 -0
- package/dist/src/engine/iruel-battle.js +319 -0
- package/dist/src/engine/kernel/deliberation-kernel.d.ts +12 -0
- package/dist/src/engine/kernel/deliberation-kernel.js +303 -0
- package/dist/src/engine/kernel/index.d.ts +8 -0
- package/dist/src/engine/kernel/index.js +7 -0
- package/dist/src/engine/kernel/phase-runner.d.ts +10 -0
- package/dist/src/engine/kernel/phase-runner.js +155 -0
- package/dist/src/engine/kernel/post-processor.d.ts +17 -0
- package/dist/src/engine/kernel/post-processor.js +131 -0
- package/dist/src/engine/kernel/types.d.ts +107 -0
- package/dist/src/engine/kernel/types.js +1 -0
- package/dist/src/engine/kernel/unit-executor.d.ts +6 -0
- package/dist/src/engine/kernel/unit-executor.js +132 -0
- package/dist/src/engine/lcl-manager.d.ts +44 -0
- package/dist/src/engine/lcl-manager.js +143 -0
- package/dist/src/engine/middleware/cache.d.ts +7 -0
- package/dist/src/engine/middleware/cache.js +29 -0
- package/dist/src/engine/middleware/chain.d.ts +18 -0
- package/dist/src/engine/middleware/chain.js +45 -0
- package/dist/src/engine/middleware/firewall.d.ts +8 -0
- package/dist/src/engine/middleware/firewall.js +24 -0
- package/dist/src/engine/middleware/index.d.ts +4 -0
- package/dist/src/engine/middleware/index.js +3 -0
- package/dist/src/engine/middleware/types.d.ts +43 -0
- package/dist/src/engine/middleware/types.js +1 -0
- package/dist/src/engine/nebuchadnezzar-key.d.ts +61 -0
- package/dist/src/engine/nebuchadnezzar-key.js +203 -0
- package/dist/src/engine/neon-genesis.d.ts +52 -0
- package/dist/src/engine/neon-genesis.js +203 -0
- package/dist/src/engine/objective-judge.d.ts +53 -0
- package/dist/src/engine/objective-judge.js +214 -0
- package/dist/src/engine/offline-mode.d.ts +18 -0
- package/dist/src/engine/offline-mode.js +46 -0
- package/dist/src/engine/orchestrator.d.ts +79 -0
- package/dist/src/engine/orchestrator.js +58 -0
- package/dist/src/engine/secret-cipher.d.ts +26 -0
- package/dist/src/engine/secret-cipher.js +114 -0
- package/dist/src/engine/seele-council.d.ts +90 -0
- package/dist/src/engine/seele-council.js +482 -0
- package/dist/src/engine/self-destruct.d.ts +61 -0
- package/dist/src/engine/self-destruct.js +231 -0
- package/dist/src/engine/self-evolution.d.ts +64 -0
- package/dist/src/engine/self-evolution.js +368 -0
- package/dist/src/engine/sync-rate.d.ts +45 -0
- package/dist/src/engine/sync-rate.js +151 -0
- package/dist/src/engine/type666-firewall.d.ts +76 -0
- package/dist/src/engine/type666-firewall.js +343 -0
- package/dist/src/engine/umbilical-cable.d.ts +41 -0
- package/dist/src/engine/umbilical-cable.js +192 -0
- package/dist/src/index.d.ts +106 -0
- package/dist/src/index.js +426 -0
- package/dist/src/mcp/server.d.ts +38 -0
- package/dist/src/mcp/server.js +196 -0
- package/dist/src/metrics/token-tracker.d.ts +38 -0
- package/dist/src/metrics/token-tracker.js +112 -0
- package/dist/src/parsers/json-extractor.d.ts +9 -0
- package/dist/src/parsers/json-extractor.js +239 -0
- package/dist/src/parsers/opinion-schema.d.ts +81 -0
- package/dist/src/parsers/opinion-schema.js +147 -0
- package/dist/src/parsers/unstructured-parser.d.ts +20 -0
- package/dist/src/parsers/unstructured-parser.js +122 -0
- package/dist/src/pipelines/architecture.d.ts +10 -0
- package/dist/src/pipelines/architecture.js +9 -0
- package/dist/src/pipelines/bug-analysis.d.ts +9 -0
- package/dist/src/pipelines/bug-analysis.js +8 -0
- package/dist/src/pipelines/code-review.d.ts +10 -0
- package/dist/src/pipelines/code-review.js +30 -0
- package/dist/src/pipelines/custom.d.ts +14 -0
- package/dist/src/pipelines/custom.js +29 -0
- package/dist/src/pipelines/registry.d.ts +9 -0
- package/dist/src/pipelines/registry.js +20 -0
- package/dist/src/prompts/personas.d.ts +6 -0
- package/dist/src/prompts/personas.js +44 -0
- package/dist/src/prompts/schemas.d.ts +4 -0
- package/dist/src/prompts/schemas.js +24 -0
- package/dist/src/prompts/templates.d.ts +6 -0
- package/dist/src/prompts/templates.js +91 -0
- package/dist/src/repl/accessibility.d.ts +23 -0
- package/dist/src/repl/accessibility.js +46 -0
- package/dist/src/repl/banner.d.ts +4 -0
- package/dist/src/repl/banner.js +28 -0
- package/dist/src/repl/boot-animation.d.ts +13 -0
- package/dist/src/repl/boot-animation.js +143 -0
- package/dist/src/repl/completer.d.ts +21 -0
- package/dist/src/repl/completer.js +168 -0
- package/dist/src/repl/context.d.ts +24 -0
- package/dist/src/repl/context.js +42 -0
- package/dist/src/repl/display-utils.d.ts +13 -0
- package/dist/src/repl/display-utils.js +65 -0
- package/dist/src/repl/event-listener.d.ts +18 -0
- package/dist/src/repl/event-listener.js +112 -0
- package/dist/src/repl/export-formatter.d.ts +8 -0
- package/dist/src/repl/export-formatter.js +73 -0
- package/dist/src/repl/ghost-text.d.ts +31 -0
- package/dist/src/repl/ghost-text.js +119 -0
- package/dist/src/repl/handoff-animation.d.ts +15 -0
- package/dist/src/repl/handoff-animation.js +65 -0
- package/dist/src/repl/history.d.ts +16 -0
- package/dist/src/repl/history.js +130 -0
- package/dist/src/repl/job-registry.d.ts +26 -0
- package/dist/src/repl/job-registry.js +80 -0
- package/dist/src/repl/magi-repl.d.ts +72 -0
- package/dist/src/repl/magi-repl.js +1008 -0
- package/dist/src/repl/multiline-input.d.ts +45 -0
- package/dist/src/repl/multiline-input.js +78 -0
- package/dist/src/repl/prompt-builder.d.ts +19 -0
- package/dist/src/repl/prompt-builder.js +36 -0
- package/dist/src/repl/repl-state.d.ts +5 -0
- package/dist/src/repl/repl-state.js +19 -0
- package/dist/src/repl/result-display.d.ts +8 -0
- package/dist/src/repl/result-display.js +195 -0
- package/dist/src/repl/session-stats.d.ts +26 -0
- package/dist/src/repl/session-stats.js +119 -0
- package/dist/src/repl/slash-commands.d.ts +60 -0
- package/dist/src/repl/slash-commands.js +725 -0
- package/dist/src/repl/terminal-sanitize.d.ts +14 -0
- package/dist/src/repl/terminal-sanitize.js +19 -0
- package/dist/src/reporters/console.d.ts +7 -0
- package/dist/src/reporters/console.js +78 -0
- package/dist/src/reporters/json.d.ts +2 -0
- package/dist/src/reporters/json.js +3 -0
- package/dist/src/reporters/markdown.d.ts +2 -0
- package/dist/src/reporters/markdown.js +65 -0
- package/dist/src/reporters/streaming.d.ts +20 -0
- package/dist/src/reporters/streaming.js +178 -0
- package/dist/src/tui/activity-log.d.ts +23 -0
- package/dist/src/tui/activity-log.js +67 -0
- package/dist/src/tui/animations.d.ts +39 -0
- package/dist/src/tui/animations.js +167 -0
- package/dist/src/tui/ansi.d.ts +28 -0
- package/dist/src/tui/ansi.js +51 -0
- package/dist/src/tui/boot-sequence.d.ts +11 -0
- package/dist/src/tui/boot-sequence.js +98 -0
- package/dist/src/tui/colors.d.ts +101 -0
- package/dist/src/tui/colors.js +71 -0
- package/dist/src/tui/header.d.ts +24 -0
- package/dist/src/tui/header.js +122 -0
- package/dist/src/tui/index.d.ts +3 -0
- package/dist/src/tui/index.js +3 -0
- package/dist/src/tui/keypress.d.ts +25 -0
- package/dist/src/tui/keypress.js +95 -0
- package/dist/src/tui/layout.d.ts +74 -0
- package/dist/src/tui/layout.js +171 -0
- package/dist/src/tui/magi-tui.d.ts +101 -0
- package/dist/src/tui/magi-tui.js +754 -0
- package/dist/src/tui/panel.d.ts +45 -0
- package/dist/src/tui/panel.js +292 -0
- package/dist/src/tui/screen-buffer.d.ts +54 -0
- package/dist/src/tui/screen-buffer.js +262 -0
- package/dist/src/tui/status-bar.d.ts +25 -0
- package/dist/src/tui/status-bar.js +124 -0
- package/dist/src/tui/terminal-detect.d.ts +26 -0
- package/dist/src/tui/terminal-detect.js +44 -0
- package/dist/src/tui/tui-helpers.d.ts +12 -0
- package/dist/src/tui/tui-helpers.js +37 -0
- package/dist/src/types/adapter.d.ts +75 -0
- package/dist/src/types/adapter.js +36 -0
- package/dist/src/types/config.d.ts +108 -0
- package/dist/src/types/config.js +85 -0
- package/dist/src/types/consensus.d.ts +55 -0
- package/dist/src/types/consensus.js +17 -0
- package/dist/src/types/core.d.ts +178 -0
- package/dist/src/types/core.js +85 -0
- package/dist/src/types/magi-api.d.ts +62 -0
- package/dist/src/types/magi-api.js +7 -0
- package/dist/src/types/phase-h.d.ts +142 -0
- package/dist/src/types/phase-h.js +7 -0
- package/dist/src/types/phase-i.d.ts +186 -0
- package/dist/src/types/phase-i.js +6 -0
- package/dist/src/types/phase-k.d.ts +259 -0
- package/dist/src/types/phase-k.js +6 -0
- package/dist/src/types/phase-l.d.ts +199 -0
- package/dist/src/types/phase-l.js +6 -0
- package/dist/src/types/pipeline.d.ts +37 -0
- package/dist/src/types/pipeline.js +2 -0
- package/dist/src/utils/abstain-factory.d.ts +2 -0
- package/dist/src/utils/abstain-factory.js +18 -0
- package/dist/src/utils/errors.d.ts +34 -0
- package/dist/src/utils/errors.js +59 -0
- package/dist/src/utils/file-validator.d.ts +50 -0
- package/dist/src/utils/file-validator.js +124 -0
- package/dist/src/utils/fire-and-forget.d.ts +5 -0
- package/dist/src/utils/fire-and-forget.js +10 -0
- package/dist/src/utils/flag-validator.d.ts +21 -0
- package/dist/src/utils/flag-validator.js +79 -0
- package/dist/src/utils/freeze.d.ts +8 -0
- package/dist/src/utils/freeze.js +16 -0
- package/dist/src/utils/language-detector.d.ts +16 -0
- package/dist/src/utils/language-detector.js +159 -0
- package/dist/src/utils/latency-tracker.d.ts +45 -0
- package/dist/src/utils/latency-tracker.js +100 -0
- package/dist/src/utils/logger.d.ts +33 -0
- package/dist/src/utils/logger.js +112 -0
- package/dist/src/utils/process.d.ts +40 -0
- package/dist/src/utils/process.js +253 -0
- package/dist/src/utils/retry.d.ts +12 -0
- package/dist/src/utils/retry.js +30 -0
- package/dist/src/utils/safe-fs.d.ts +38 -0
- package/dist/src/utils/safe-fs.js +56 -0
- package/dist/src/utils/safe-json-parse.d.ts +15 -0
- package/dist/src/utils/safe-json-parse.js +49 -0
- package/dist/src/utils/sanitize.d.ts +14 -0
- package/dist/src/utils/sanitize.js +186 -0
- package/dist/src/utils/semaphore.d.ts +22 -0
- package/dist/src/utils/semaphore.js +57 -0
- package/dist/src/utils/shutdown.d.ts +6 -0
- package/dist/src/utils/shutdown.js +51 -0
- package/dist/src/utils/tty.d.ts +5 -0
- package/dist/src/utils/tty.js +7 -0
- package/package.json +82 -0
|
@@ -0,0 +1,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
|
+
}
|