autonomous-flow-daemon 1.1.0 → 1.9.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 (75) hide show
  1. package/CHANGELOG.md +85 -46
  2. package/LICENSE +21 -21
  3. package/README-ko.md +282 -0
  4. package/README.md +282 -337
  5. package/mcp-config.json +10 -10
  6. package/package.json +14 -6
  7. package/src/adapters/index.ts +370 -159
  8. package/src/cli.ts +162 -57
  9. package/src/commands/benchmark.ts +187 -0
  10. package/src/commands/correlate.ts +180 -0
  11. package/src/commands/dashboard.ts +404 -0
  12. package/src/commands/diagnose.ts +56 -14
  13. package/src/commands/doctor.ts +243 -0
  14. package/src/commands/evolution.ts +190 -0
  15. package/src/commands/fix.ts +158 -138
  16. package/src/commands/hooks.ts +136 -0
  17. package/src/commands/lang.ts +41 -41
  18. package/src/commands/mcp.ts +129 -0
  19. package/src/commands/plugin.ts +110 -0
  20. package/src/commands/restart.ts +14 -0
  21. package/src/commands/score.ts +276 -208
  22. package/src/commands/start.ts +155 -96
  23. package/src/commands/stats.ts +103 -0
  24. package/src/commands/status.ts +157 -0
  25. package/src/commands/stop.ts +68 -49
  26. package/src/commands/suggest.ts +211 -0
  27. package/src/commands/sync.ts +567 -21
  28. package/src/commands/vaccine.ts +177 -0
  29. package/src/constants.ts +32 -8
  30. package/src/core/boast.ts +280 -265
  31. package/src/core/config.ts +49 -49
  32. package/src/core/correlation-engine.ts +265 -0
  33. package/src/core/db.ts +145 -46
  34. package/src/core/discovery.ts +65 -65
  35. package/src/core/evolution.ts +215 -0
  36. package/src/core/federation.ts +129 -0
  37. package/src/core/hologram/engine.ts +71 -0
  38. package/src/core/hologram/fallback.ts +11 -0
  39. package/src/core/hologram/go-extractor.ts +203 -0
  40. package/src/core/hologram/incremental.ts +227 -0
  41. package/src/core/hologram/py-extractor.ts +132 -0
  42. package/src/core/hologram/rust-extractor.ts +244 -0
  43. package/src/core/hologram/ts-extractor.ts +406 -0
  44. package/src/core/hologram/types.ts +27 -0
  45. package/src/core/hologram.ts +73 -243
  46. package/src/core/hook-manager.ts +259 -0
  47. package/src/core/i18n/messages.ts +309 -266
  48. package/src/core/immune.ts +8 -123
  49. package/src/core/locale.ts +88 -88
  50. package/src/core/log-rotate.ts +33 -0
  51. package/src/core/log-utils.ts +38 -0
  52. package/src/core/lru-map.ts +61 -0
  53. package/src/core/notify.ts +74 -66
  54. package/src/core/plugin-manager.ts +225 -0
  55. package/src/core/rule-engine.ts +287 -0
  56. package/src/core/rule-suggestion.ts +127 -0
  57. package/src/core/semantic-diff.ts +432 -0
  58. package/src/core/telemetry.ts +94 -0
  59. package/src/core/vaccine-registry.ts +212 -0
  60. package/src/core/validator-generator.ts +224 -0
  61. package/src/core/workspace.ts +28 -0
  62. package/src/core/yaml-minimal.ts +176 -0
  63. package/src/daemon/client.ts +78 -37
  64. package/src/daemon/event-batcher.ts +108 -0
  65. package/src/daemon/guards.ts +13 -0
  66. package/src/daemon/http-routes.ts +376 -0
  67. package/src/daemon/mcp-handler.ts +575 -0
  68. package/src/daemon/mcp-subscriptions.ts +81 -0
  69. package/src/daemon/mesh.ts +51 -0
  70. package/src/daemon/server.ts +655 -504
  71. package/src/daemon/types.ts +121 -0
  72. package/src/daemon/workspace-map.ts +104 -0
  73. package/src/platform.ts +60 -39
  74. package/src/version.ts +15 -0
  75. package/README.ko.md +0 -306
@@ -0,0 +1,121 @@
1
+ /**
2
+ * Shared types for the afd daemon modules.
3
+ */
4
+
5
+ import type { DetectionResult } from "../adapters/index";
6
+ import type { PatchOp } from "../core/immune";
7
+ import type { LruStringMap } from "../core/lru-map";
8
+
9
+ // ── Constants ──
10
+ export const DOUBLE_TAP_WINDOW_MS = 30_000;
11
+ export const MASS_EVENT_THRESHOLD = 3;
12
+ export const MASS_EVENT_WINDOW_MS = 1_000;
13
+ export const TAP_CLEANUP_INTERVAL_MS = 60_000;
14
+ export const SELF_WRITE_DEBOUNCE_MS = 100;
15
+ export const MAX_SSE_CLIENTS = 20;
16
+ export const VALIDATOR_TIMEOUT_MS = 500;
17
+ export const VALIDATORS_DIR = ".afd/validators";
18
+
19
+ // ── Types ──
20
+ export type ValidatorFn = (newContent: string, filePath: string) => boolean;
21
+
22
+ export interface HologramStats {
23
+ totalRequests: number;
24
+ totalOriginalChars: number;
25
+ totalHologramChars: number;
26
+ sessionOriginalChars: number;
27
+ sessionHologramChars: number;
28
+ }
29
+
30
+ export interface MistakeEntry {
31
+ mistake_type: string;
32
+ description: string;
33
+ timestamp: number;
34
+ }
35
+
36
+ /** SEAM 이벤트 로그 항목 (afd://events 리소스용) */
37
+ export interface SeamEventEntry {
38
+ phase: string;
39
+ msg: string;
40
+ ts: number;
41
+ }
42
+
43
+ /** 격리(quarantine) 로그 항목 (afd://quarantine 리소스용) */
44
+ export interface QuarantineLogEntry {
45
+ path: string;
46
+ ts: number;
47
+ }
48
+
49
+ export interface DaemonState {
50
+ startedAt: number;
51
+ filesDetected: number;
52
+ lastEvent: string | null;
53
+ lastEventAt: number | null;
54
+ watchedFiles: Set<string>;
55
+ hologramStats: HologramStats;
56
+ ecosystems: DetectionResult[];
57
+ autoHealCount: number;
58
+ autoHealLog: { id: string; at: number; file: string; healMs: number }[];
59
+ recentUnlinks: number[];
60
+ firstTapTimestamps: Map<string, number>;
61
+ suppressionSkippedCount: number;
62
+ dormantTransitions: { antibodyId: string; at: number }[];
63
+ totalFileBytesSaved: number;
64
+ totalSavedTokens: number;
65
+ fileSnapshots: LruStringMap;
66
+ sseClients: Set<ReadableStreamDefaultController<Uint8Array>>;
67
+ customValidators: Map<string, ValidatorFn>;
68
+ mistakeCache: Map<string, MistakeEntry[]>;
69
+ /** v1.9.0: 실시간 SEAM 이벤트 링 버퍼 (최근 200개) */
70
+ seamEventLog: SeamEventEntry[];
71
+ /** v1.9.0: 격리 이벤트 로그 (최근 100개) */
72
+ quarantineLog: QuarantineLogEntry[];
73
+ }
74
+
75
+ export interface DaemonOptions {
76
+ mcp?: boolean;
77
+ }
78
+
79
+ export { type PatchOp, type DetectionResult };
80
+
81
+ /**
82
+ * DaemonContext — shared dependency bag passed to all daemon modules.
83
+ * Created once in main() and threaded through MCP/HTTP handlers.
84
+ */
85
+ export interface DaemonContext {
86
+ state: DaemonState;
87
+ db: { query: (sql: string) => { get: () => unknown }; prepare: (sql: string) => { run: (...args: unknown[]) => void; get: (...args: unknown[]) => unknown; all: () => unknown[] } };
88
+ ws: { root: string; afdDir: string; pidFile: string; portFile: string; dbFile: string; logFile: string; quarantineDir: string };
89
+
90
+ // Prepared statements
91
+ insertEvent: { run: (...args: unknown[]) => void };
92
+ insertAntibody: { run: (...args: unknown[]) => void };
93
+ listAntibodies: { all: () => unknown[] };
94
+ antibodyIds: { all: () => { id: string }[] };
95
+ countAntibodies: { get: () => { cnt: number } };
96
+ getDailyAll: { all: () => { date: string; requests: number; original_chars: number; hologram_chars: number }[] };
97
+ insertTelemetry: { run: (...args: unknown[]) => void };
98
+ insertMistakeHistory: { run: (...args: unknown[]) => void };
99
+ queryMistakesByFile: { all: (...args: unknown[]) => MistakeEntry[] };
100
+ deleteMistakeOverflow: { run: (...args: unknown[]) => void };
101
+
102
+ // Helper functions
103
+ seam: (phase: string, msg: string) => void;
104
+ persistHologramStats: (originalChars: number, hologramChars: number) => void;
105
+ persistCtxSavings: (type: 'wsmap' | 'pinpoint', originalChars: number, savedChars: number) => void;
106
+ safeHologram: (filePath: string, source: string) => Promise<string>;
107
+ getWorkspaceMap: () => string;
108
+ getWorkspaceMapStats: () => { totalProjectBytes: number; mapBytes: number };
109
+ today: () => string;
110
+ getCtxSavingsDaily: { all: () => { date: string; type: string; requests: number; original_chars: number; saved_chars: number }[] };
111
+ getCtxSavingsLifetime: { all: () => { type: string; total_requests: number; total_original_chars: number; total_saved_chars: number }[] };
112
+
113
+ // Discovery
114
+ discoveryTargets: string[];
115
+
116
+ // Options
117
+ options: DaemonOptions;
118
+
119
+ // Mutable port (set after Bun.serve)
120
+ port: number;
121
+ }
@@ -0,0 +1,104 @@
1
+ /**
2
+ * Workspace Map — cached project structure with export signatures.
3
+ * Provides afd://workspace-map MCP resource.
4
+ */
5
+
6
+ import { readdirSync, readFileSync, lstatSync } from "fs";
7
+ import { join } from "path";
8
+
9
+ const MAX_WALK_DEPTH = 8;
10
+ const SKIP_DIRS = new Set(["node_modules", ".afd", ".git", "dist", "coverage"]);
11
+ const CODE_EXTS = /\.[tj]sx?$/;
12
+ const DOC_EXTS = /\.(ts|js|tsx|jsx|json|md)$/;
13
+
14
+ /** Build a workspace map: file tree with sizes and export signatures */
15
+ function buildWorkspaceMap(): { map: string; totalProjectBytes: number } {
16
+ const cwd = process.cwd();
17
+ const lines: string[] = [`# Workspace Map — ${cwd}`, `# Generated: ${new Date().toISOString()}`, ""];
18
+ let totalProjectBytes = 0;
19
+
20
+ function walk(dir: string, prefix: string, depth: number) {
21
+ if (depth > MAX_WALK_DEPTH) return;
22
+ let entries: string[];
23
+ try { entries = readdirSync(dir).sort(); } catch { return; }
24
+ for (const entry of entries) {
25
+ if (SKIP_DIRS.has(entry)) continue;
26
+ const fullPath = join(dir, entry);
27
+ try {
28
+ const lst = lstatSync(fullPath);
29
+ if (lst.isSymbolicLink()) continue;
30
+ if (lst.isDirectory()) {
31
+ lines.push(`${prefix}${entry}/`);
32
+ walk(fullPath, prefix + " ", depth + 1);
33
+ continue;
34
+ }
35
+ if (!DOC_EXTS.test(entry)) continue;
36
+ totalProjectBytes += lst.size;
37
+ const sizeKB = (lst.size / 1024).toFixed(1);
38
+ if (CODE_EXTS.test(entry) && lst.size < 100 * 1024) {
39
+ try {
40
+ const source = readFileSync(fullPath, "utf-8");
41
+ const exports = source.match(/export\s+(?:async\s+)?(?:function|const|class|interface|type|enum)\s+(\w+)/g);
42
+ const sigs = exports ? exports.map(e => e.replace(/^export\s+(async\s+)?/, "").trim()).slice(0, 5).join(", ") : "";
43
+ const extra = exports && exports.length > 5 ? ` +${exports.length - 5} more` : "";
44
+ lines.push(`${prefix}${entry} (${sizeKB}KB)${sigs ? ` → ${sigs}${extra}` : ""}`);
45
+ } catch {
46
+ lines.push(`${prefix}${entry} (${sizeKB}KB)`);
47
+ }
48
+ } else {
49
+ lines.push(`${prefix}${entry} (${sizeKB}KB)`);
50
+ }
51
+ } catch { /* skip */ }
52
+ }
53
+ }
54
+
55
+ walk(join(cwd, "src"), " ", 0);
56
+
57
+ lines.push("", "# Root files");
58
+ for (const f of ["CLAUDE.md", "package.json", ".claudeignore", ".mcp.json"]) {
59
+ try {
60
+ const st = lstatSync(join(cwd, f));
61
+ totalProjectBytes += st.size;
62
+ lines.push(` ${f} (${(st.size / 1024).toFixed(1)}KB)`);
63
+ } catch { /* not found */ }
64
+ }
65
+
66
+ return { map: lines.join("\n"), totalProjectBytes };
67
+ }
68
+
69
+ /**
70
+ * Creates a workspace map manager with lazy caching.
71
+ * Returns getWorkspaceMap() and markMapDirty() functions.
72
+ */
73
+ export function createWorkspaceMap() {
74
+ let cache = "";
75
+ let dirty = true;
76
+ let timer: ReturnType<typeof setTimeout> | null = null;
77
+ let lastTotalProjectBytes = 0;
78
+ let lastMapBytes = 0;
79
+
80
+ function get(): string {
81
+ if (dirty || !cache) {
82
+ const result = buildWorkspaceMap();
83
+ cache = result.map;
84
+ lastTotalProjectBytes = result.totalProjectBytes;
85
+ lastMapBytes = result.map.length;
86
+ dirty = false;
87
+ }
88
+ return cache;
89
+ }
90
+
91
+ function getLastBuildStats() {
92
+ return { totalProjectBytes: lastTotalProjectBytes, mapBytes: lastMapBytes };
93
+ }
94
+
95
+ function markDirty() {
96
+ dirty = true;
97
+ if (timer) clearTimeout(timer);
98
+ timer = setTimeout(() => { get(); }, 5000);
99
+ }
100
+
101
+ function getTimer() { return timer; }
102
+
103
+ return { get, getLastBuildStats, markDirty, getTimer };
104
+ }
package/src/platform.ts CHANGED
@@ -1,39 +1,60 @@
1
- import { platform } from "os";
2
- import type { SpawnOptions } from "child_process";
3
-
4
- export const IS_WINDOWS = platform() === "win32";
5
- export const IS_MACOS = platform() === "darwin";
6
- export const IS_LINUX = platform() === "linux";
7
-
8
- /**
9
- * Returns spawn options appropriate for detaching a background daemon.
10
- * On Windows, `shell: true` is required for `detached` to create a new console.
11
- */
12
- export function detachedSpawnOptions(
13
- logFd: number,
14
- ): SpawnOptions {
15
- const base: SpawnOptions = {
16
- detached: true,
17
- stdio: ["ignore", logFd, logFd],
18
- cwd: process.cwd(),
19
- env: { ...process.env },
20
- };
21
-
22
- if (IS_WINDOWS) {
23
- // Windows needs shell:true for detached to work properly
24
- // and windowsHide to prevent a console flash
25
- return { ...base, shell: true, windowsHide: true };
26
- }
27
-
28
- return base;
29
- }
30
-
31
- /**
32
- * Resolve the hook command for invoking afd diagnose.
33
- * Priority:
34
- * 1. Global `afd` binary (npm/bun global install)
35
- * 2. `bunx afd` fallback
36
- */
37
- export function resolveHookCommand(): string {
38
- return "afd diagnose --format a2a --auto-heal";
39
- }
1
+ import { platform } from "os";
2
+ import type { SpawnOptions } from "child_process";
3
+ import { execSync } from "child_process";
4
+
5
+ export const IS_WINDOWS = platform() === "win32";
6
+ export const IS_MACOS = platform() === "darwin";
7
+ export const IS_LINUX = platform() === "linux";
8
+
9
+ /**
10
+ * Returns spawn options appropriate for detaching a background daemon.
11
+ * On Windows, `shell: true` is required for `detached` to create a new console.
12
+ */
13
+ export function detachedSpawnOptions(
14
+ logFd: number,
15
+ ): SpawnOptions {
16
+ const base: SpawnOptions = {
17
+ detached: true,
18
+ stdio: ["ignore", logFd, logFd],
19
+ cwd: process.cwd(),
20
+ env: { ...process.env },
21
+ };
22
+
23
+ if (IS_WINDOWS) {
24
+ // Windows needs shell:true for detached to work properly
25
+ // and windowsHide to prevent a console flash
26
+ return { ...base, shell: true, windowsHide: true };
27
+ }
28
+
29
+ return base;
30
+ }
31
+
32
+ const DIAGNOSE_ARGS = "diagnose --format a2a --auto-heal";
33
+
34
+ /**
35
+ * Resolve the hook command for invoking afd diagnose.
36
+ * Priority:
37
+ * 1. Global `afd` binary (npm/bun global install)
38
+ * 2. `bunx afd` fallback (Bun environment)
39
+ * 3. `npx afd` fallback (Node environment)
40
+ */
41
+ export function resolveHookCommand(): string {
42
+ if (isCommandAvailable("afd")) {
43
+ return `afd ${DIAGNOSE_ARGS}`;
44
+ }
45
+ if (isCommandAvailable("bunx")) {
46
+ return `bunx afd ${DIAGNOSE_ARGS}`;
47
+ }
48
+ return `npx -y afd ${DIAGNOSE_ARGS}`;
49
+ }
50
+
51
+ /** Check if a command exists on the system PATH */
52
+ function isCommandAvailable(cmd: string): boolean {
53
+ try {
54
+ const check = IS_WINDOWS ? `where ${cmd}` : `command -v ${cmd}`;
55
+ execSync(check, { stdio: "ignore" });
56
+ return true;
57
+ } catch {
58
+ return false;
59
+ }
60
+ }
package/src/version.ts ADDED
@@ -0,0 +1,15 @@
1
+ import { readFileSync } from "node:fs";
2
+ import { resolve } from "node:path";
3
+
4
+ let version = "0.0.0-unknown";
5
+ try {
6
+ const raw = readFileSync(resolve(import.meta.dirname, "..", "package.json"), "utf-8");
7
+ const pkg = JSON.parse(raw);
8
+ if (typeof pkg.version === "string" && pkg.version) {
9
+ version = pkg.version;
10
+ }
11
+ } catch {
12
+ // Bundled binary or missing package.json — fallback silently
13
+ }
14
+
15
+ export const APP_VERSION: string = version;
package/README.ko.md DELETED
@@ -1,306 +0,0 @@
1
- <p align="center">
2
- <img src="https://capsule-render.vercel.app/api?type=soft&color=auto&height=200&section=header&text=afd&fontSize=90" alt="afd" />
3
- </p>
4
-
5
- <h3 align="center">Autonomous Flow Daemon (afd)</h3>
6
- <p align="center"><strong>AI가 스스로 고치는 개발 환경. 복구까지 단 0.2초.</strong></p>
7
-
8
- <p align="center">
9
- <img src="demo.gif" width="850" alt="afd demo" style="border-radius: 12px; box-shadow: 0 20px 40px rgba(0,0,0,0.4);">
10
- <br>
11
- <br>
12
- <b>🛡️ 불멸의 컨텍스트 흐름:</b>
13
- <em>"afd는 지연 시간이 거의 없는 즉각적인 복구를 통해, AI 개발 흐름이 끊기지 않도록 보호하고 토큰 비용을 혁신적으로 절감합니다."</em>
14
- </p>
15
-
16
- <p align="center">
17
- <img src="https://img.shields.io/badge/version-1.1.0-blue?style=flat-square" alt="version" />
18
- <a href="https://www.npmjs.com/package/autonomous-flow-daemon"><img src="https://img.shields.io/npm/v/autonomous-flow-daemon?style=flat-square&logo=npm&color=cb0000" alt="npm" /></a>
19
- <img src="https://img.shields.io/badge/runtime-Bun-f472b6?style=flat-square&logo=bun" alt="Bun" />
20
- <img src="https://img.shields.io/badge/license-MIT-green?style=flat-square" alt="MIT" />
21
- <img src="https://img.shields.io/badge/built%20for-Claude%20Code-7c3aed?style=flat-square" alt="Claude Code" />
22
- </p>
23
-
24
- <p align="center">
25
- <a href="README.md">English</a>
26
- </p>
27
-
28
- ---
29
-
30
- ## 왜 afd인가?
31
-
32
- > [afd] 🛡️ AI가 '.claudeignore'를 삭제했습니다 | 🩹 184ms 만에 자가 복구 완료 | 컨텍스트 보존됨.
33
-
34
- 당신은 지금 몰입의 정점에 있습니다. AI 에이전트가 실수로 설정 파일을 삭제하거나, 훅 파일을 망가뜨립니다. `afd` 없이는 작업을 멈추고, 원인을 진단하고, 직접 고쳐야 합니다: **30분이 날아갑니다**.
35
-
36
- `afd`가 있다면, 데몬이 10ms 만에 이상을 감지하고, 184ms 안에 복구를 완료합니다. **당신은 아무것도 몰랐습니다.**
37
-
38
- | 상황 | afd 없을 때 | afd 있을 때 |
39
- |:-----|:------------|:------------|
40
- | AI가 `.claudeignore` 삭제 | 30분 수동 복구 | **0.2초 자동 치유** |
41
- | 훅 파일 손상 | 훅 재주입, 세션 재시작 | **백그라운드 자동 복구** |
42
- | `git checkout`으로 파일 50개 동시 변경 | AI가 폭주 | **대규모 이벤트 억제기 작동** |
43
- | 신규 팀원, 환경 설정 없음 | 구전으로 전달 | **`afd sync`로 즉시 백신 접종** |
44
-
45
- ---
46
-
47
- ## 🚀 제로-간섭 약속 (Zero-Interference Promise)
48
-
49
- `afd`는 개발 흐름을 방해하는 것이 아니라, 보호하기 위해 설계되었습니다.
50
-
51
- * **성능 저하 없음:** Bun 기반의 네이티브 백그라운드 데몬으로 실행되어, **CPU 점유율 0.1% 미만**, **메모리 약 40MB**만을 사용합니다.
52
- * **매끄러운 복구:** **밀리초 미만(Sub-millisecond)의 복구 속도**를 통해, Claude Code가 컨텍스트 오류를 인지하기도 전에 파일을 원래대로 되돌려 놓습니다.
53
- * **비침습적 설계:** `afd`는 OS 계층에서 파일 시스템 이벤트만 관찰합니다. Claude Code의 내부 실행이나 API 호출을 가로채거나 수정하지 않습니다.
54
-
55
- ---
56
-
57
- ## ✨ 주요 기능 (v1.1.0)
58
-
59
- | 기능 | 설명 |
60
- |:-----|:-----|
61
- | **🛡️ S.E.A.M 자율 치유** | 파일 삭제를 감지하고 270ms 이내에 복구 — AI 에이전트가 눈치채기도 전에 |
62
- | **🔍 스마트 탐색** | `.claude/`, `.cursorrules`, `.mcp.json` 등 AI 설정 파일을 자동 감지 — 설정 필요 없음 |
63
- | **🏥 위트 있는 닥터** | 실시간 가치 추적: 절약한 토큰, 시간, 비용을 매 치유마다 위트 있게 알려줍니다 |
64
- | **🌐 자동 다국어** | 시스템 언어에 따라 한국어/영어를 자동 전환. 직접 설정도 가능: `afd lang ko` |
65
- | **🧬 더블탭 감지** | 실수와 의도를 구분 — 한 번 지우면 복구, 30초 내 다시 지우면 삭제를 존중 |
66
- | **💉 백신 네트워크** | `afd sync`로 학습된 항체를 팀 전체에 전파 |
67
- | **📊 홀로그램 추출** | AI 에이전트에게 80%+ 가벼운 파일 뼈대를 제공해 토큰 비용 절감 |
68
-
69
- ---
70
-
71
- ## 🚀 명령어 한 줄로 끝나는 경험
72
-
73
- > **"더 이상의 설정 삽질은 없습니다. 완전한 방어 환경을 구축하세요."**
74
-
75
- ```bash
76
- npx @dotoricode/afd start
77
- ```
78
-
79
- 로컬에 설치하여 사용하려면:
80
-
81
- ```bash
82
- bun link && afd start
83
- ```
84
-
85
- 이게 전부입니다. 나머지는 `afd`가 알아서 처리합니다:
86
-
87
- - **자동 훅(Hook) 주입** — Claude Code의 `PreToolUse` 훅을 자동으로 설치합니다. 더 이상 `.json` 파일을 직접 수정하며 고생하지 마세요.
88
- - **초고속 실시간 감시** — `.claude/`, `CLAUDE.md`, `.cursorrules`, `.claudeignore`, `.gitignore` 핵심 파일을 10ms 단위로 모니터링합니다.
89
- - **배경 자율 치유** — 파일이 삭제되거나 손상되면 **S.E.A.M 사이클**이 조용히 복구합니다. 사용자가 눈치채기도 전에 모든 상황은 종료됩니다.
90
-
91
- ```
92
- $ afd start
93
- 🛡️ 데몬 시작 (pid 4812, port 52413)
94
- 🛡️ 스마트 탐색 중: AI 컨텍스트 대상 7개 감시 시작
95
- Targets: .claude/, CLAUDE.md, .cursorrules, .claudeignore, .gitignore, mcp-config.json, .mcp.json
96
- ✅ .claude/hooks.json에 감시 훅 주입 완료
97
- ```
98
-
99
- > `afd start`를 치고 나면 그냥 잊어버리세요. 그것이 우리가 추구하는 최고의 UX입니다.
100
-
101
- ---
102
-
103
- ## 🧠 지능형 치유 엔진: S.E.A.M 사이클
104
-
105
- `afd`의 핵심 로직입니다. 모든 파일 변화는 다음의 4단계를 거쳐 즉시 정제됩니다:
106
-
107
- ```mermaid
108
- graph LR
109
- S["Sense<br/><i>변경 감지</i>"] --> E["Extract<br/><i>증상 분석</i>"]
110
- E --> A["Adapt<br/><i>항체 선택</i>"]
111
- A --> M["Mutate<br/><i>치유/복구</i>"]
112
- M -->|"자가 학습"| S
113
- style S fill:#3b82f6,color:#fff,stroke:none
114
- style E fill:#f59e0b,color:#fff,stroke:none
115
- style A fill:#10b981,color:#fff,stroke:none
116
- style M fill:#ef4444,color:#fff,stroke:none
117
- ```
118
-
119
- | 단계 | 주요 동작 | 처리 속도 |
120
- |:------|:-----|:-----|
121
- | **Sense** | Chokidar 와처가 파일의 생성, 변경, 삭제를 즉각 감지 | < 10ms |
122
- | **Extract** | 면역 엔진이 내장된 3단계 건강 검진 실행 (IMM-001..003) | < 5ms |
123
- | **Adapt** | SQLite(WAL 모드) DB에서 최적의 복구 항체(Antibody) 매칭 | < 1ms |
124
- | **Mutate** | RFC 6902 JSON-Patch 기술로 원본 파일을 완벽히 복원 | < 25ms |
125
-
126
- > **최종 성적표:** 파일 삭제 감지부터 복구 완료까지 **270ms 미만**.
127
-
128
- ### 감시 대상 (Watch Targets)
129
-
130
- 아래 파일들이 실시간 감시됩니다. 면역 파일(IMM-*)은 삭제 시 자동으로 복구됩니다:
131
-
132
- | 대상 | 유형 | 항체 | 자동 복구 |
133
- |:-----|:-----|:-----|:----------|
134
- | `.claude/` | 디렉토리 | IMM-002 (`hooks.json`) | ✅ |
135
- | `CLAUDE.md` | 파일 | IMM-003 | ✅ |
136
- | `.claudeignore` | 파일 | IMM-001 | ✅ |
137
- | `.cursorrules` | 파일 | — | 이벤트 로깅만 |
138
- | `.gitignore` | 파일 | — | 이벤트 로깅만 |
139
- | `mcp-config.json` | 파일 | — | 🔍 스마트 탐색 |
140
- | `.mcp.json` | 파일 | — | 🔍 스마트 탐색 |
141
- | `.ai/` | 디렉토리 | — | 🔍 스마트 탐색 |
142
- | `.windsurfrules` | 파일 | — | 🔍 스마트 탐색 |
143
-
144
- > 항체는 **데몬 시작 시 자동으로 학습**되며, **파일 변경 시마다 갱신**됩니다 — 복구 시 항상 최신 내용이 반영됩니다.
145
- >
146
- > 🔍 **스마트 탐색**은 시작 시 12개 이상의 AI 설정 패턴을 0.1ms 미만으로 스캔하여, 발견된 파일을 자동으로 감시 목록에 추가합니다.
147
-
148
- ---
149
-
150
- ## 🛠️ 명령어
151
-
152
- 복잡한 건 빼고, 꼭 필요한 것만 담았습니다.
153
-
154
- | 명령어 | 역할 | 핵심 지능 |
155
- |:-------|:-----|:----------|
156
- | `afd start` | **시동** | 스마트 탐색 + 데몬 가동 + 자동 훅 주입 |
157
- | `afd fix` | **수술** | 현재 프로젝트 진단 및 새로운 항체 학습 |
158
- | `afd score` | **대시보드** | 다국어 건강 검진 리포트 & 가치 분석 |
159
- | `afd sync` | **전파** | 학습된 항체를 백신 파일로 추출 (팀 공유용) |
160
- | `afd lang` | **언어** | 표시 언어 전환 (`afd lang ko` / `afd lang en`) |
161
- | `afd stop` | **종료** | 근무 요약 리포트 + 안전한 종료 |
162
-
163
- ---
164
-
165
- ## 📊 실시간 대시보드: `afd score`
166
-
167
- ```
168
- ┌──────────────────────────────────────────────┐
169
- │ afd score — 프로젝트 건강 검진 │
170
- ├──────────────────────────────────────────────┤
171
- │ 에코시스템 : Claude Code │
172
- ├──────────────────────────────────────────────┤
173
- │ 가동 시간 : 1h 23m │
174
- │ 이벤트 : 156 │
175
- │ 감지된 파일 : 8 │
176
- ├──────────────────────────────────────────────┤
177
- │ 면역 시스템 │
178
- │ ────────────────────────────── │
179
- │ 항체 수 : 7 │
180
- │ 방어 레벨 : 철통 방어 │
181
- │ 자동 치유 : 3건 백그라운드 치유됨 │
182
- ├──────────────────────────────────────────────┤
183
- │ 📈 전달된 가치 │
184
- │ ────────────────────────────── │
185
- │ 절약한 토큰 : ~2.9K │
186
- │ 아낀 시간 : ~40 min │
187
- │ 절감 비용 : ~$0.01 │
188
- ├──────────────────────────────────────────────┤
189
- │ 🗣️ 면역 체계 이상 무. 오늘도 한 건 │
190
- │ 해결했습니다 💪 │
191
- └──────────────────────────────────────────────┘
192
- ```
193
-
194
- > `afd lang en` 을 실행하면 대시보드의 모든 레이블이 영어로 전환됩니다.
195
-
196
- ---
197
-
198
- ## 💎 고도로 설계된 안전 장치
199
-
200
- ### Double-Tap 휴리스틱 (의도와 실수의 구분)
201
-
202
- `afd`는 바보처럼 무조건 되살리지 않습니다. 사용자의 **진짜 의도**를 읽습니다:
203
-
204
- ```bash
205
- $ rm .claudeignore # 1차 삭제: "실수인가 보군." → 즉시 복구
206
- $ rm .claudeignore # 30초 내 재삭제: "진짜 지우고 싶구나?"
207
- 🫡 [afd] 사용자 의도 확인. 항체 IMM-001 휴면 전환. 삭제를 존중합니다.
208
- ```
209
-
210
- - **실수 방어:** 한 번의 삭제는 0.2초 만에 즉시 복구합니다.
211
- - **의도 존중:** 30초 내에 같은 파일을 또 지우면 사용자의 확고한 의지로 판단해 복구를 멈춥니다.
212
- - **Git 쇼크 방지:** `git checkout`처럼 수많은 파일이 한꺼번에 바뀌는 상황(1초 내 3개 이상)은 '대규모 이벤트'로 자동 인식하여 과도한 치유 동작을 멈춥니다.
213
-
214
- ### 백신 네트워크 (팀 전파)
215
-
216
- 나만 똑똑해지는 게 아닙니다. 내가 발견한 해결책을 팀원 모두에게 전파하세요:
217
-
218
- ```bash
219
- afd sync
220
- # → .afd/global-vaccine-payload.json 생성
221
- ```
222
- 이 파일은 정제되어 있어 기밀 정보가 섞이지 않습니다. 다른 프로젝트에 넣기만 하면 `afd`가 해당 프로젝트의 면역력을 즉시 이식받습니다.
223
-
224
- ### Hologram 추출 (토큰 다이어트)
225
-
226
- AI 에이전트가 파일 내용을 요구할 때, `afd`는 **뼈대만 남긴 초경량 요약본**을 제공합니다. 주석과 긴 함수 본문은 걷어내고 타입 정의와 구조만 전달하여 **토큰 비용을 80% 이상 절감**합니다.
227
-
228
- ---
229
-
230
- ## 🔌 Plugin / MCP 설정
231
-
232
- `afd`를 **Model Context Protocol (MCP) 서버**로 등록하면 Claude Code가 시작될 때 데몬이 자동으로 실행됩니다.
233
-
234
- ### 자동 설정 (권장)
235
-
236
- Claude Code MCP 설정(`~/.claude/mcp.json` 또는 프로젝트 `.mcp.json`)에 추가하세요:
237
-
238
- ```json
239
- {
240
- "mcpServers": {
241
- "afd": {
242
- "command": "bun",
243
- "args": ["run", "src/cli.ts", "start"]
244
- }
245
- }
246
- }
247
- ```
248
-
249
- ### 수동 실행
250
-
251
- ```bash
252
- afd start # 백그라운드 데몬 시작 및 훅 자동 주입
253
- ```
254
-
255
- 등록 후 Claude Code 상태 표시줄에서 실시간으로 확인할 수 있습니다:
256
-
257
- ```
258
- 🛡️ afd: ON | 🩹 3 Healed | last: IMM-003
259
- ```
260
-
261
- ---
262
-
263
- ## 🛠️ 기술 스택
264
-
265
- | 계층 | 기술 | 선택 이유 |
266
- |:-----|:-----|:----------|
267
- | 런타임 | **Bun** | 네이티브 TypeScript, 초고속 SQLite, 단일 바이너리 |
268
- | 데이터베이스 | **Bun SQLite (WAL)** | 읽기 0.29ms, 쓰기 24ms, 크래시 안전 |
269
- | 파일 감시 | **Chokidar** | 크로스플랫폼, 실전 검증된 와처 |
270
- | 패칭 | **RFC 6902 JSON-Patch** | 결정론적이고 조합 가능한 파일 변이 |
271
- | CLI | **Commander.js** | 표준적이고 예측 가능한 커맨드 파싱 |
272
- | 다국어 | **자체 i18n 엔진** | 외부 의존성 없이 0.01ms로 언어 전환 |
273
-
274
- ---
275
-
276
- ## 📦 설치 및 시작하기
277
-
278
- ```bash
279
- # Bun 사용 권장
280
- bun install
281
- bun link
282
- afd start
283
-
284
- # 설치 없이 바로 실행하기 (npx)
285
- npx @dotoricode/afd start
286
- ```
287
-
288
- ### 환경 요구 사항
289
- - **Bun** >= 1.0
290
- - **OS**: Windows, macOS, Linux 지원
291
- - **호환 환경**: Claude Code, Cursor 등 (생태계 자동 감지)
292
-
293
- ---
294
-
295
- ## 🛡️ 안도감을 주는 UX
296
-
297
- `afd`의 목표는 명확합니다.
298
-
299
- > **"설정 파일 하나 날아가서 30분을 허비하는 그런 날은 이제 끝났습니다."**
300
-
301
- 당신은 코드에만 집중하세요. 프로젝트 환경의 건강은 `afd`가 24시간 백그라운드에서 지켜드립니다.
302
-
303
- ---
304
-
305
- ## 라이선스
306
- MIT