@damaall/ccx 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 (127) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +267 -0
  3. package/dist/commands/report.d.ts +8 -0
  4. package/dist/commands/report.d.ts.map +1 -0
  5. package/dist/commands/report.js +115 -0
  6. package/dist/commands/report.js.map +1 -0
  7. package/dist/commands/reuse.d.ts +7 -0
  8. package/dist/commands/reuse.d.ts.map +1 -0
  9. package/dist/commands/reuse.js +167 -0
  10. package/dist/commands/reuse.js.map +1 -0
  11. package/dist/commands/watch.d.ts +10 -0
  12. package/dist/commands/watch.d.ts.map +1 -0
  13. package/dist/commands/watch.js +201 -0
  14. package/dist/commands/watch.js.map +1 -0
  15. package/dist/core/cursor-reader.d.ts +24 -0
  16. package/dist/core/cursor-reader.d.ts.map +1 -0
  17. package/dist/core/cursor-reader.js +128 -0
  18. package/dist/core/cursor-reader.js.map +1 -0
  19. package/dist/core/data-source-adapter.d.ts +239 -0
  20. package/dist/core/data-source-adapter.d.ts.map +1 -0
  21. package/dist/core/data-source-adapter.js +85 -0
  22. package/dist/core/data-source-adapter.js.map +1 -0
  23. package/dist/core/identity-resolver.d.ts +27 -0
  24. package/dist/core/identity-resolver.d.ts.map +1 -0
  25. package/dist/core/identity-resolver.js +55 -0
  26. package/dist/core/identity-resolver.js.map +1 -0
  27. package/dist/core/inbox-reader.d.ts +20 -0
  28. package/dist/core/inbox-reader.d.ts.map +1 -0
  29. package/dist/core/inbox-reader.js +105 -0
  30. package/dist/core/inbox-reader.js.map +1 -0
  31. package/dist/core/paths.d.ts +28 -0
  32. package/dist/core/paths.d.ts.map +1 -0
  33. package/dist/core/paths.js +46 -0
  34. package/dist/core/paths.js.map +1 -0
  35. package/dist/core/pricing.d.ts +25 -0
  36. package/dist/core/pricing.d.ts.map +1 -0
  37. package/dist/core/pricing.js +108 -0
  38. package/dist/core/pricing.js.map +1 -0
  39. package/dist/core/redact.d.ts +15 -0
  40. package/dist/core/redact.d.ts.map +1 -0
  41. package/dist/core/redact.js +60 -0
  42. package/dist/core/redact.js.map +1 -0
  43. package/dist/core/session-discovery.d.ts +26 -0
  44. package/dist/core/session-discovery.d.ts.map +1 -0
  45. package/dist/core/session-discovery.js +89 -0
  46. package/dist/core/session-discovery.js.map +1 -0
  47. package/dist/core/snapshot-manager.d.ts +29 -0
  48. package/dist/core/snapshot-manager.d.ts.map +1 -0
  49. package/dist/core/snapshot-manager.js +120 -0
  50. package/dist/core/snapshot-manager.js.map +1 -0
  51. package/dist/core/snapshot-reader.d.ts +23 -0
  52. package/dist/core/snapshot-reader.d.ts.map +1 -0
  53. package/dist/core/snapshot-reader.js +142 -0
  54. package/dist/core/snapshot-reader.js.map +1 -0
  55. package/dist/core/state-aggregator.d.ts +36 -0
  56. package/dist/core/state-aggregator.d.ts.map +1 -0
  57. package/dist/core/state-aggregator.js +218 -0
  58. package/dist/core/state-aggregator.js.map +1 -0
  59. package/dist/core/task-reader.d.ts +14 -0
  60. package/dist/core/task-reader.d.ts.map +1 -0
  61. package/dist/core/task-reader.js +55 -0
  62. package/dist/core/task-reader.js.map +1 -0
  63. package/dist/core/team-reader.d.ts +18 -0
  64. package/dist/core/team-reader.d.ts.map +1 -0
  65. package/dist/core/team-reader.js +68 -0
  66. package/dist/core/team-reader.js.map +1 -0
  67. package/dist/core/types.d.ts +105 -0
  68. package/dist/core/types.d.ts.map +1 -0
  69. package/dist/core/types.js +2 -0
  70. package/dist/core/types.js.map +1 -0
  71. package/dist/core/watcher.d.ts +16 -0
  72. package/dist/core/watcher.d.ts.map +1 -0
  73. package/dist/core/watcher.js +194 -0
  74. package/dist/core/watcher.js.map +1 -0
  75. package/dist/guard/hard-limit.d.ts +13 -0
  76. package/dist/guard/hard-limit.d.ts.map +1 -0
  77. package/dist/guard/hard-limit.js +79 -0
  78. package/dist/guard/hard-limit.js.map +1 -0
  79. package/dist/guard/soft-limit.d.ts +5 -0
  80. package/dist/guard/soft-limit.d.ts.map +1 -0
  81. package/dist/guard/soft-limit.js +22 -0
  82. package/dist/guard/soft-limit.js.map +1 -0
  83. package/dist/index.d.ts +3 -0
  84. package/dist/index.d.ts.map +1 -0
  85. package/dist/index.js +171 -0
  86. package/dist/index.js.map +1 -0
  87. package/dist/report/json.d.ts +6 -0
  88. package/dist/report/json.d.ts.map +1 -0
  89. package/dist/report/json.js +4 -0
  90. package/dist/report/json.js.map +1 -0
  91. package/dist/report/markdown.d.ts +6 -0
  92. package/dist/report/markdown.d.ts.map +1 -0
  93. package/dist/report/markdown.js +57 -0
  94. package/dist/report/markdown.js.map +1 -0
  95. package/dist/report/redact-snapshot.d.ts +3 -0
  96. package/dist/report/redact-snapshot.d.ts.map +1 -0
  97. package/dist/report/redact-snapshot.js +21 -0
  98. package/dist/report/redact-snapshot.js.map +1 -0
  99. package/dist/report/terminal.d.ts +3 -0
  100. package/dist/report/terminal.d.ts.map +1 -0
  101. package/dist/report/terminal.js +85 -0
  102. package/dist/report/terminal.js.map +1 -0
  103. package/dist/ui/AgentPanel.d.ts +13 -0
  104. package/dist/ui/AgentPanel.d.ts.map +1 -0
  105. package/dist/ui/AgentPanel.js +61 -0
  106. package/dist/ui/AgentPanel.js.map +1 -0
  107. package/dist/ui/AlertBanner.d.ts +11 -0
  108. package/dist/ui/AlertBanner.d.ts.map +1 -0
  109. package/dist/ui/AlertBanner.js +19 -0
  110. package/dist/ui/AlertBanner.js.map +1 -0
  111. package/dist/ui/CompletionBanner.d.ts +12 -0
  112. package/dist/ui/CompletionBanner.d.ts.map +1 -0
  113. package/dist/ui/CompletionBanner.js +11 -0
  114. package/dist/ui/CompletionBanner.js.map +1 -0
  115. package/dist/ui/CostBar.d.ts +12 -0
  116. package/dist/ui/CostBar.d.ts.map +1 -0
  117. package/dist/ui/CostBar.js +29 -0
  118. package/dist/ui/CostBar.js.map +1 -0
  119. package/dist/ui/Dashboard.d.ts +10 -0
  120. package/dist/ui/Dashboard.d.ts.map +1 -0
  121. package/dist/ui/Dashboard.js +70 -0
  122. package/dist/ui/Dashboard.js.map +1 -0
  123. package/dist/ui/TaskPanel.d.ts +11 -0
  124. package/dist/ui/TaskPanel.d.ts.map +1 -0
  125. package/dist/ui/TaskPanel.js +41 -0
  126. package/dist/ui/TaskPanel.js.map +1 -0
  127. package/package.json +61 -0
@@ -0,0 +1,194 @@
1
+ /**
2
+ * Watcher:chokidar 檔案監控 → 串接 readers → StateAggregator
3
+ *
4
+ * 負責:
5
+ * 1. 啟動時 full scan(progressive loading)
6
+ * 2. 持續監控檔案變更
7
+ * 3. TeamDelete polling(2 consecutive miss)
8
+ * 4. 新 agent JSONL 偵測
9
+ */
10
+ import { watch as chokidarWatch } from 'chokidar';
11
+ import { join, basename } from 'node:path';
12
+ import { claudePaths } from './paths.js';
13
+ import { readTeamConfig, teamExists } from './team-reader.js';
14
+ import { readAllTasks } from './task-reader.js';
15
+ import { readAllInboxes } from './inbox-reader.js';
16
+ import { createCursor, readFull, readIncremental } from './cursor-reader.js';
17
+ import { tryResolveFromRawLines, batchResolve } from './identity-resolver.js';
18
+ import { discoverSubagents } from './session-discovery.js';
19
+ import { StateAggregator } from './state-aggregator.js';
20
+ import { SnapshotManager } from './snapshot-manager.js';
21
+ export async function startWatch(options) {
22
+ const { teamName, budget, stuckTimeoutMs, onStateChange, onError } = options;
23
+ const aggregator = new StateAggregator({ budget, stuckThresholdMs: stuckTimeoutMs });
24
+ const snapshotManager = new SnapshotManager(aggregator, teamName);
25
+ // State change callback
26
+ if (onStateChange) {
27
+ aggregator.on('event', onStateChange);
28
+ }
29
+ // ─── Phase 1: Initial load ───
30
+ const config = await readTeamConfig(teamName);
31
+ if (!config) {
32
+ throw new Error(`Team "${teamName}" not found. Check ~/.claude/teams/`);
33
+ }
34
+ aggregator.updateTeamConfig(config);
35
+ // 平行讀取 tasks + inboxes
36
+ const [tasks, inboxes] = await Promise.all([
37
+ readAllTasks(teamName),
38
+ readAllInboxes(teamName),
39
+ ]);
40
+ aggregator.updateTasks(tasks);
41
+ for (const inbox of inboxes) {
42
+ aggregator.updateInbox(inbox);
43
+ }
44
+ // 找到 subagents 目錄
45
+ const discovery = await discoverSubagents(config.leadSessionId);
46
+ const cursors = new Map();
47
+ if (discovery) {
48
+ // Progressive loading: 逐一讀取 JSONL + 收集 raw lines 做 batch resolve
49
+ const rawLinesMap = new Map();
50
+ for (const agentFile of discovery.agentFiles) {
51
+ try {
52
+ const result = await readFull(agentFile.filePath, agentFile.agentId);
53
+ let cursor = result.cursor;
54
+ cursor = tryResolveFromRawLines(cursor, result.rawLines);
55
+ cursors.set(agentFile.agentId, cursor);
56
+ aggregator.updateCursor(cursor);
57
+ // 只保留 UNRESOLVED 的 raw lines 給 batch resolve
58
+ if (cursor.state === 'UNRESOLVED') {
59
+ rawLinesMap.set(agentFile.agentId, result.rawLines);
60
+ }
61
+ }
62
+ catch {
63
+ // 忽略單一檔案的讀取錯誤
64
+ }
65
+ }
66
+ // Batch resolve: 用剩餘 raw lines 再試一次
67
+ if (rawLinesMap.size > 0) {
68
+ const unresolved = [...cursors.values()].filter(c => c.state === 'UNRESOLVED');
69
+ const resolvedCursors = batchResolve(unresolved, rawLinesMap);
70
+ for (const cursor of resolvedCursors) {
71
+ cursors.set(cursor.agentId, cursor);
72
+ aggregator.updateCursor(cursor);
73
+ }
74
+ }
75
+ }
76
+ // Initialize snapshot
77
+ await snapshotManager.initialize();
78
+ // ─── Phase 2: Watch for changes ───
79
+ const watchers = [];
80
+ const handleWatcherError = (source) => (err) => {
81
+ const message = err instanceof Error ? err.message : String(err);
82
+ if (onError)
83
+ onError(err instanceof Error ? err : new Error(message));
84
+ else
85
+ aggregator.emit('event', { type: 'watcher_error', source, message });
86
+ };
87
+ // Watch config.json
88
+ const configWatcher = chokidarWatch(claudePaths.teamConfig(teamName), {
89
+ ignoreInitial: true,
90
+ awaitWriteFinish: { stabilityThreshold: 200 },
91
+ });
92
+ configWatcher.on('change', async () => {
93
+ try {
94
+ const updated = await readTeamConfig(teamName);
95
+ if (updated)
96
+ aggregator.updateTeamConfig(updated);
97
+ }
98
+ catch { /* ignore */ }
99
+ });
100
+ configWatcher.on('error', handleWatcherError('config'));
101
+ watchers.push(configWatcher);
102
+ // Watch tasks directory
103
+ const tasksDir = claudePaths.teamTasks(teamName);
104
+ const taskWatcher = chokidarWatch(join(tasksDir, '*.json'), {
105
+ ignoreInitial: true,
106
+ awaitWriteFinish: { stabilityThreshold: 200 },
107
+ });
108
+ taskWatcher.on('all', async () => {
109
+ try {
110
+ const updated = await readAllTasks(teamName);
111
+ aggregator.updateTasks(updated);
112
+ }
113
+ catch { /* ignore */ }
114
+ });
115
+ taskWatcher.on('error', handleWatcherError('tasks'));
116
+ watchers.push(taskWatcher);
117
+ // Watch inboxes directory
118
+ const inboxDir = claudePaths.teamInboxes(teamName);
119
+ const inboxWatcher = chokidarWatch(join(inboxDir, '*.json'), {
120
+ ignoreInitial: true,
121
+ awaitWriteFinish: { stabilityThreshold: 200 },
122
+ });
123
+ inboxWatcher.on('all', async () => {
124
+ try {
125
+ const updated = await readAllInboxes(teamName);
126
+ for (const inbox of updated) {
127
+ aggregator.updateInbox(inbox);
128
+ }
129
+ }
130
+ catch { /* ignore */ }
131
+ });
132
+ inboxWatcher.on('error', handleWatcherError('inboxes'));
133
+ watchers.push(inboxWatcher);
134
+ // Watch subagents JSONL
135
+ let subagentWatcher = null;
136
+ if (discovery) {
137
+ subagentWatcher = chokidarWatch(join(discovery.subagentsDir, 'agent-*.jsonl'), {
138
+ ignoreInitial: true,
139
+ awaitWriteFinish: { stabilityThreshold: 100 },
140
+ });
141
+ subagentWatcher.on('change', async (filePath) => {
142
+ const agentId = basename(filePath).replace('agent-', '').replace('.jsonl', '');
143
+ try {
144
+ let cursor = cursors.get(agentId) ?? createCursor(filePath, agentId);
145
+ const result = await readIncremental(cursor);
146
+ cursor = result.cursor;
147
+ cursor = tryResolveFromRawLines(cursor, result.rawLines);
148
+ cursors.set(agentId, cursor);
149
+ aggregator.updateCursor(cursor);
150
+ }
151
+ catch { /* ignore */ }
152
+ });
153
+ subagentWatcher.on('add', async (filePath) => {
154
+ const agentId = basename(filePath).replace('agent-', '').replace('.jsonl', '');
155
+ if (cursors.has(agentId))
156
+ return;
157
+ try {
158
+ const result = await readFull(filePath, agentId);
159
+ let cursor = result.cursor;
160
+ cursor = tryResolveFromRawLines(cursor, result.rawLines);
161
+ cursors.set(agentId, cursor);
162
+ aggregator.updateCursor(cursor);
163
+ }
164
+ catch { /* ignore */ }
165
+ });
166
+ subagentWatcher.on('error', handleWatcherError('subagents'));
167
+ watchers.push(subagentWatcher);
168
+ }
169
+ // ─── Phase 3: TeamDelete polling ───
170
+ let deleteMissCount = 0;
171
+ const deleteCheckInterval = setInterval(async () => {
172
+ const exists = await teamExists(teamName);
173
+ if (!exists) {
174
+ deleteMissCount++;
175
+ if (deleteMissCount >= 2) {
176
+ aggregator.markTeamDeleted();
177
+ clearInterval(deleteCheckInterval);
178
+ }
179
+ }
180
+ else {
181
+ deleteMissCount = 0;
182
+ }
183
+ }, 30_000); // 每 30 秒檢查
184
+ // ─── Stop handle ───
185
+ const stop = async () => {
186
+ clearInterval(deleteCheckInterval);
187
+ for (const w of watchers) {
188
+ await w.close();
189
+ }
190
+ await snapshotManager.finalize();
191
+ };
192
+ return { aggregator, snapshotManager, stop };
193
+ }
194
+ //# sourceMappingURL=watcher.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"watcher.js","sourceRoot":"","sources":["../../src/core/watcher.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * 安全地向 tmux pane 發送 C-c
3
+ * 回傳 true 表示成功發送,false 表示跳過
4
+ */
5
+ export declare function safeSendCtrlC(paneId: string): Promise<boolean>;
6
+ /**
7
+ * 對所有有 tmuxPaneId 的 member 發送 C-c
8
+ */
9
+ export declare function killAllMembers(paneIds: readonly string[]): Promise<{
10
+ sent: number;
11
+ failed: number;
12
+ }>;
13
+ //# sourceMappingURL=hard-limit.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hard-limit.d.ts","sourceRoot":"","sources":["../../src/guard/hard-limit.ts"],"names":[],"mappings":"AAiBA;;;GAGG;AACH,wBAAsB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAoBpE;AAuBD;;GAEG;AACH,wBAAsB,cAAc,CAClC,OAAO,EAAE,SAAS,MAAM,EAAE,GACzB,OAAO,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CAY3C"}
@@ -0,0 +1,79 @@
1
+ /**
2
+ * Hard Limit:超預算 → tmux send-keys C-c(需 PID 驗證)
3
+ *
4
+ * 安全機制:
5
+ * 1. 必須有 tmuxPaneId
6
+ * 2. PID 驗證:確認 pane 內的前景進程是 node/claude
7
+ * 3. 5 秒冷卻期:避免重複發送
8
+ * 4. 10 秒倒數:讓使用者有機會取消
9
+ */
10
+ import { exec } from 'node:child_process';
11
+ import { promisify } from 'node:util';
12
+ const execAsync = promisify(exec);
13
+ const COOLDOWN_MS = 5000;
14
+ const lastSentAt = new Map();
15
+ /**
16
+ * 安全地向 tmux pane 發送 C-c
17
+ * 回傳 true 表示成功發送,false 表示跳過
18
+ */
19
+ export async function safeSendCtrlC(paneId) {
20
+ if (!paneId)
21
+ return false;
22
+ // 冷卻期
23
+ const last = lastSentAt.get(paneId);
24
+ if (last && Date.now() - last < COOLDOWN_MS) {
25
+ return false;
26
+ }
27
+ // PID 驗證
28
+ const isValid = await verifyPanePid(paneId);
29
+ if (!isValid)
30
+ return false;
31
+ try {
32
+ await execAsync(`tmux send-keys -t ${escapePaneId(paneId)} C-c`);
33
+ lastSentAt.set(paneId, Date.now());
34
+ return true;
35
+ }
36
+ catch {
37
+ return false;
38
+ }
39
+ }
40
+ /**
41
+ * 驗證 pane 內的前景進程是否是 node/claude
42
+ */
43
+ async function verifyPanePid(paneId) {
44
+ try {
45
+ const { stdout: pidStr } = await execAsync(`tmux display-message -p -t ${escapePaneId(paneId)} '#{pane_pid}'`);
46
+ const pid = parseInt(pidStr.trim());
47
+ if (isNaN(pid))
48
+ return false;
49
+ const { stdout: comm } = await execAsync(`ps -p ${pid} -o comm=`);
50
+ const processName = comm.trim();
51
+ // 只允許 node 或 claude 進程
52
+ return /^(node|claude)/.test(processName);
53
+ }
54
+ catch {
55
+ return false;
56
+ }
57
+ }
58
+ /**
59
+ * 對所有有 tmuxPaneId 的 member 發送 C-c
60
+ */
61
+ export async function killAllMembers(paneIds) {
62
+ let sent = 0;
63
+ let failed = 0;
64
+ for (const paneId of paneIds) {
65
+ if (!paneId)
66
+ continue;
67
+ const ok = await safeSendCtrlC(paneId);
68
+ if (ok)
69
+ sent++;
70
+ else
71
+ failed++;
72
+ }
73
+ return { sent, failed };
74
+ }
75
+ function escapePaneId(paneId) {
76
+ // tmux pane ID 應該只包含 %數字 格式,但防禦性 escape
77
+ return paneId.replace(/[^a-zA-Z0-9%_.-]/g, '');
78
+ }
79
+ //# sourceMappingURL=hard-limit.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hard-limit.js","sourceRoot":"","sources":["../../src/guard/hard-limit.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EAAE,IAAI,EAAE,MAAM,oBAAoB,CAAA;AACzC,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAA;AAErC,MAAM,SAAS,GAAG,SAAS,CAAC,IAAI,CAAC,CAAA;AAEjC,MAAM,WAAW,GAAG,IAAI,CAAA;AACxB,MAAM,UAAU,GAAG,IAAI,GAAG,EAAkB,CAAA;AAE5C;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,MAAc;IAChD,IAAI,CAAC,MAAM;QAAE,OAAO,KAAK,CAAA;IAEzB,MAAM;IACN,MAAM,IAAI,GAAG,UAAU,CAAC,GAAG,CAAC,MAAM,CAAC,CAAA;IACnC,IAAI,IAAI,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,GAAG,WAAW,EAAE,CAAC;QAC5C,OAAO,KAAK,CAAA;IACd,CAAC;IAED,SAAS;IACT,MAAM,OAAO,GAAG,MAAM,aAAa,CAAC,MAAM,CAAC,CAAA;IAC3C,IAAI,CAAC,OAAO;QAAE,OAAO,KAAK,CAAA;IAE1B,IAAI,CAAC;QACH,MAAM,SAAS,CAAC,qBAAqB,YAAY,CAAC,MAAM,CAAC,MAAM,CAAC,CAAA;QAChE,UAAU,CAAC,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,GAAG,EAAE,CAAC,CAAA;QAClC,OAAO,IAAI,CAAA;IACb,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAA;IACd,CAAC;AACH,CAAC;AAED;;GAEG;AACH,KAAK,UAAU,aAAa,CAAC,MAAc;IACzC,IAAI,CAAC;QACH,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,SAAS,CACxC,8BAA8B,YAAY,CAAC,MAAM,CAAC,gBAAgB,CACnE,CAAA;QACD,MAAM,GAAG,GAAG,QAAQ,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAA;QACnC,IAAI,KAAK,CAAC,GAAG,CAAC;YAAE,OAAO,KAAK,CAAA;QAE5B,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,SAAS,CAAC,SAAS,GAAG,WAAW,CAAC,CAAA;QACjE,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,EAAE,CAAA;QAE/B,uBAAuB;QACvB,OAAO,gBAAgB,CAAC,IAAI,CAAC,WAAW,CAAC,CAAA;IAC3C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAA;IACd,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,OAA0B;IAE1B,IAAI,IAAI,GAAG,CAAC,CAAA;IACZ,IAAI,MAAM,GAAG,CAAC,CAAA;IAEd,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC7B,IAAI,CAAC,MAAM;YAAE,SAAQ;QACrB,MAAM,EAAE,GAAG,MAAM,aAAa,CAAC,MAAM,CAAC,CAAA;QACtC,IAAI,EAAE;YAAE,IAAI,EAAE,CAAA;;YACT,MAAM,EAAE,CAAA;IACf,CAAC;IAED,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,CAAA;AACzB,CAAC;AAED,SAAS,YAAY,CAAC,MAAc;IAClC,wCAAwC;IACxC,OAAO,MAAM,CAAC,OAAO,CAAC,mBAAmB,EAAE,EAAE,CAAC,CAAA;AAChD,CAAC"}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * 發送 macOS 系統通知
3
+ */
4
+ export declare function sendOsNotification(title: string, message: string): Promise<void>;
5
+ //# sourceMappingURL=soft-limit.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"soft-limit.d.ts","sourceRoot":"","sources":["../../src/guard/soft-limit.ts"],"names":[],"mappings":"AAWA;;GAEG;AACH,wBAAsB,kBAAkB,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAStF"}
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Soft Limit:cost threshold → alert notification
3
+ *
4
+ * 完全由 StateAggregator 處理(checkBudgetThresholds)
5
+ * 這個檔案提供 OS notification 支援
6
+ */
7
+ import { exec } from 'node:child_process';
8
+ import { promisify } from 'node:util';
9
+ const execAsync = promisify(exec);
10
+ /**
11
+ * 發送 macOS 系統通知
12
+ */
13
+ export async function sendOsNotification(title, message) {
14
+ try {
15
+ const escaped = message.replace(/"/g, '\\"');
16
+ await execAsync(`osascript -e 'display notification "${escaped}" with title "${title}"'`);
17
+ }
18
+ catch {
19
+ // 通知失敗不影響主流程
20
+ }
21
+ }
22
+ //# sourceMappingURL=soft-limit.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"soft-limit.js","sourceRoot":"","sources":["../../src/guard/soft-limit.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAE,IAAI,EAAE,MAAM,oBAAoB,CAAA;AACzC,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAA;AAErC,MAAM,SAAS,GAAG,SAAS,CAAC,IAAI,CAAC,CAAA;AAEjC;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,KAAa,EAAE,OAAe;IACrE,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,CAAA;QAC5C,MAAM,SAAS,CACb,uCAAuC,OAAO,iBAAiB,KAAK,IAAI,CACzE,CAAA;IACH,CAAC;IAAC,MAAM,CAAC;QACP,aAAa;IACf,CAAC;AACH,CAAC"}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
package/dist/index.js ADDED
@@ -0,0 +1,171 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * ccx — Agent Teams control plane for Claude Code
4
+ */
5
+ import { Command } from 'commander';
6
+ import { runWatch } from './commands/watch.js';
7
+ import { runReport } from './commands/report.js';
8
+ import { runReuse } from './commands/reuse.js';
9
+ import { listTeamNames } from './core/team-reader.js';
10
+ import { listSessions } from './core/snapshot-reader.js';
11
+ import { formatCost, formatDuration } from './core/pricing.js';
12
+ import { ccxPaths } from './core/paths.js';
13
+ import { rm } from 'node:fs/promises';
14
+ import { join } from 'node:path';
15
+ const program = new Command();
16
+ program
17
+ .name('ccx')
18
+ .description('Agent Teams control plane for Claude Code')
19
+ .version('0.1.0');
20
+ // ─── watch ───
21
+ program
22
+ .command('watch [team]')
23
+ .description('Live dashboard for an active Agent Team')
24
+ .option('--budget <usd>', 'Cost alert threshold in USD', (v) => {
25
+ const n = parseFloat(v);
26
+ if (Number.isNaN(n) || n <= 0) {
27
+ console.error(`Invalid --budget value: "${v}". Must be a positive number.`);
28
+ process.exit(1);
29
+ }
30
+ return n;
31
+ })
32
+ .option('--stuck-timeout <seconds>', 'Seconds before marking agent as stuck (default: 180)', (v) => {
33
+ const n = parseInt(v, 10);
34
+ if (Number.isNaN(n) || n <= 0) {
35
+ console.error(`Invalid --stuck-timeout value: "${v}". Must be a positive integer.`);
36
+ process.exit(1);
37
+ }
38
+ return n;
39
+ })
40
+ .option('--kill', 'Hard limit: send C-c to agents when budget exceeded')
41
+ .option('--notify', 'Send OS notification on budget alerts')
42
+ .option('--plain', 'Accessible text-only mode (no colors)')
43
+ .action(async (team, opts) => {
44
+ if (opts.plain || process.env.NO_COLOR || process.env.TERM === 'dumb') {
45
+ process.env.NO_COLOR = '1';
46
+ opts.plain = true;
47
+ }
48
+ await runWatch({
49
+ team,
50
+ budget: opts.budget,
51
+ stuckTimeout: opts.stuckTimeout,
52
+ plain: opts.plain,
53
+ kill: opts.kill,
54
+ notify: opts.notify,
55
+ });
56
+ });
57
+ // ─── report ───
58
+ program
59
+ .command('report [target]')
60
+ .description('Generate a post-mortem report from a saved session or live team')
61
+ .option('--md', 'Output as Markdown')
62
+ .option('--json', 'Output as JSON')
63
+ .option('--save [name]', 'Also save report as Markdown file')
64
+ .action(async (target, opts) => {
65
+ await runReport({
66
+ target,
67
+ md: opts.md,
68
+ json: opts.json,
69
+ save: opts.save,
70
+ });
71
+ });
72
+ // ─── reuse ───
73
+ program
74
+ .command('reuse [target]')
75
+ .description('Extract team topology from a saved session for reuse')
76
+ .option('--prompt', 'Output only the reuse prompt (no overview)')
77
+ .option('--json', 'Output as JSON')
78
+ .action(async (target, opts) => {
79
+ await runReuse({
80
+ target,
81
+ prompt: opts.prompt,
82
+ json: opts.json,
83
+ });
84
+ });
85
+ // ─── ls ───
86
+ program
87
+ .command('ls')
88
+ .description('List teams and sessions')
89
+ .option('--active', 'Only show active teams')
90
+ .option('--sessions', 'Only show saved sessions')
91
+ .action(async (opts) => {
92
+ const [teams, sessions] = await Promise.all([
93
+ opts.sessions ? Promise.resolve([]) : listTeamNames(),
94
+ opts.active ? Promise.resolve([]) : listSessions(),
95
+ ]);
96
+ if (teams.length === 0 && sessions.length === 0) {
97
+ console.log('No active teams or saved sessions found.');
98
+ console.log('Start a team in Claude Code first, then run "ccx watch".');
99
+ return;
100
+ }
101
+ if (teams.length > 0) {
102
+ console.log(`Active teams (${teams.length}):`);
103
+ for (const name of teams) {
104
+ console.log(` ${name}`);
105
+ }
106
+ }
107
+ if (sessions.length > 0) {
108
+ if (teams.length > 0)
109
+ console.log('');
110
+ console.log(`Saved sessions (${sessions.length}):`);
111
+ console.log(` ${'TEAM'.padEnd(22)} ${'AGENTS'.padEnd(8)} ${'COST'.padEnd(10)} ${'DURATION'.padEnd(10)} ${'STATUS'.padEnd(12)} DATE`);
112
+ for (const s of sessions) {
113
+ const date = new Date(s.lastUpdatedAt).toLocaleDateString();
114
+ const elapsed = formatDuration(s.lastUpdatedAt - s.startedAt);
115
+ const status = s.finalized ? 'finalized' : 'active';
116
+ const cost = formatCost(s.totalCost);
117
+ console.log(` ${s.teamName.padEnd(22)} ${String(s.agentCount).padEnd(8)} ${cost.padEnd(10)} ${elapsed.padEnd(10)} ${status.padEnd(12)} ${date}`);
118
+ }
119
+ }
120
+ });
121
+ // ─── clean ───
122
+ program
123
+ .command('clean')
124
+ .description('Remove old saved sessions')
125
+ .option('--keep <n>', 'Number of recent sessions to keep (default: 5)', (v) => {
126
+ const n = parseInt(v, 10);
127
+ if (Number.isNaN(n) || n < 0) {
128
+ console.error(`Invalid --keep value: "${v}". Must be a non-negative integer.`);
129
+ process.exit(1);
130
+ }
131
+ return n;
132
+ })
133
+ .option('--dry-run', 'Show what would be deleted without actually deleting')
134
+ .action(async (opts) => {
135
+ const keep = opts.keep ?? 5;
136
+ const sessions = await listSessions();
137
+ if (sessions.length <= keep) {
138
+ console.log(`${sessions.length} session(s) found, keeping all (threshold: ${keep}).`);
139
+ return;
140
+ }
141
+ const toKeep = sessions.slice(0, keep);
142
+ const toDelete = sessions.slice(keep);
143
+ if (opts.dryRun) {
144
+ console.log(`Would keep ${toKeep.length} session(s):`);
145
+ for (const s of toKeep) {
146
+ console.log(` [keep] ${s.teamName.padEnd(22)} ${formatCost(s.totalCost).padEnd(10)} ${new Date(s.lastUpdatedAt).toLocaleDateString()}`);
147
+ }
148
+ console.log(`Would delete ${toDelete.length} session(s):`);
149
+ for (const s of toDelete) {
150
+ console.log(` [delete] ${s.teamName.padEnd(22)} ${formatCost(s.totalCost).padEnd(10)} ${new Date(s.lastUpdatedAt).toLocaleDateString()}`);
151
+ }
152
+ return;
153
+ }
154
+ let deleted = 0;
155
+ for (const s of toDelete) {
156
+ try {
157
+ await rm(join(ccxPaths.sessions, s.name), { recursive: true });
158
+ deleted++;
159
+ }
160
+ catch {
161
+ console.error(` Failed to delete: ${s.name}`);
162
+ }
163
+ }
164
+ console.log(`Deleted ${deleted} old session(s), kept ${toKeep.length} most recent.`);
165
+ });
166
+ // ─── No subcommand → show help ───
167
+ program.action(() => {
168
+ program.help();
169
+ });
170
+ program.parseAsync();
171
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * JSON report formatter
3
+ */
4
+ import type { SessionSnapshot } from '../core/types.js';
5
+ export declare function formatJsonReport(snapshot: SessionSnapshot): string;
6
+ //# sourceMappingURL=json.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"json.d.ts","sourceRoot":"","sources":["../../src/report/json.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAA;AAEvD,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,eAAe,GAAG,MAAM,CAElE"}
@@ -0,0 +1,4 @@
1
+ export function formatJsonReport(snapshot) {
2
+ return JSON.stringify(snapshot, null, 2);
3
+ }
4
+ //# sourceMappingURL=json.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"json.js","sourceRoot":"","sources":["../../src/report/json.ts"],"names":[],"mappings":"AAKA,MAAM,UAAU,gBAAgB,CAAC,QAAyB;IACxD,OAAO,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,CAAA;AAC1C,CAAC"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Markdown report formatter
3
+ */
4
+ import type { SessionSnapshot } from '../core/types.js';
5
+ export declare function formatMarkdownReport(snapshot: SessionSnapshot): string;
6
+ //# sourceMappingURL=markdown.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"markdown.d.ts","sourceRoot":"","sources":["../../src/report/markdown.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAA;AAGvD,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,eAAe,GAAG,MAAM,CA+DtE"}
@@ -0,0 +1,57 @@
1
+ import { formatCost, formatTokens, totalTokenCount, formatDuration } from '../core/pricing.js';
2
+ export function formatMarkdownReport(snapshot) {
3
+ const lines = [];
4
+ const elapsed = formatDuration(snapshot.lastUpdatedAt - snapshot.startedAt);
5
+ const startedAt = new Date(snapshot.startedAt).toISOString();
6
+ lines.push(`# ccx Report: ${snapshot.teamName}`);
7
+ lines.push('');
8
+ lines.push(`| Field | Value |`);
9
+ lines.push(`|-------|-------|`);
10
+ lines.push(`| Session | \`${snapshot.sessionId}\` |`);
11
+ lines.push(`| Started | ${startedAt} |`);
12
+ lines.push(`| Duration | ${elapsed} |`);
13
+ lines.push(`| Status | ${snapshot.finalized ? 'finalized' : 'active'} |`);
14
+ lines.push(`| Total Cost | **${formatCost(snapshot.totalCost)}** |`);
15
+ lines.push(`| Agents | ${snapshot.agents.length} |`);
16
+ lines.push(`| Tasks | ${snapshot.tasks.length} |`);
17
+ lines.push('');
18
+ // Agents
19
+ lines.push(`## Agents`);
20
+ lines.push('');
21
+ lines.push(`| Name | Model | Status | Tokens | Cost |`);
22
+ lines.push(`|------|-------|--------|--------|------|`);
23
+ for (const agent of snapshot.agents) {
24
+ const tokens = formatTokens(totalTokenCount(agent.tokenUsage));
25
+ lines.push(`| ${agent.name} | ${agent.model} | ${agent.status} | ${tokens} | ${formatCost(agent.cost)} |`);
26
+ }
27
+ const totalTokens = formatTokens(totalTokenCount(snapshot.totalTokens));
28
+ lines.push(`| **TOTAL** | | | **${totalTokens}** | **${formatCost(snapshot.totalCost)}** |`);
29
+ lines.push('');
30
+ // Tasks
31
+ if (snapshot.tasks.length > 0) {
32
+ lines.push(`## Tasks`);
33
+ lines.push('');
34
+ lines.push(`| # | Status | Subject | Owner |`);
35
+ lines.push(`|---|--------|---------|-------|`);
36
+ for (const task of snapshot.tasks) {
37
+ lines.push(`| ${task.id} | ${task.status} | ${task.subject.slice(0, 50)} | ${task.owner || '—'} |`);
38
+ }
39
+ lines.push('');
40
+ }
41
+ // Alerts
42
+ if (snapshot.alerts.length > 0) {
43
+ lines.push(`## Alerts`);
44
+ lines.push('');
45
+ for (const alert of snapshot.alerts) {
46
+ const time = new Date(alert.timestamp).toISOString();
47
+ const icon = alert.level === 'critical' ? '!!' : '!';
48
+ lines.push(`- ${icon} \`${time}\` ${alert.message}`);
49
+ }
50
+ lines.push('');
51
+ }
52
+ lines.push(`---`);
53
+ lines.push(`*Generated by ccx v0.1.0*`);
54
+ lines.push('');
55
+ return lines.join('\n');
56
+ }
57
+ //# sourceMappingURL=markdown.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"markdown.js","sourceRoot":"","sources":["../../src/report/markdown.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { SessionSnapshot } from '../core/types.js';
2
+ export declare function redactSnapshot(snapshot: SessionSnapshot): SessionSnapshot;
3
+ //# sourceMappingURL=redact-snapshot.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"redact-snapshot.d.ts","sourceRoot":"","sources":["../../src/report/redact-snapshot.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAA;AAEvD,wBAAgB,cAAc,CAAC,QAAQ,EAAE,eAAe,GAAG,eAAe,CAazE"}