@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,201 @@
1
+ /**
2
+ * watch command:ink Dashboard UI
3
+ *
4
+ * --plain 回退到純文字模式(Day 1 的實作)
5
+ */
6
+ import React from 'react';
7
+ import { render } from 'ink';
8
+ import chalk from 'chalk';
9
+ import { startWatch } from '../core/watcher.js';
10
+ import { listTeamNames } from '../core/team-reader.js';
11
+ import { Dashboard } from '../ui/Dashboard.js';
12
+ import { sendOsNotification } from '../guard/soft-limit.js';
13
+ import { killAllMembers } from '../guard/hard-limit.js';
14
+ import { formatCost, formatTokens, totalTokenCount, formatDuration, formatTimeSince } from '../core/pricing.js';
15
+ export async function runWatch(options) {
16
+ const teamName = options.team ?? await autoDetectTeam();
17
+ if (!teamName) {
18
+ console.error(chalk.red('No active team found.'));
19
+ console.error('Usage: ccx watch <team-name>');
20
+ console.error('Run "ccx ls --active" to see active teams.');
21
+ process.exit(1);
22
+ }
23
+ // --kill 啟動確認
24
+ if (options.kill && options.budget) {
25
+ console.log(chalk.yellow.bold(`⚠ Hard Limit enabled.`));
26
+ console.log(chalk.yellow(` When cost exceeds $${options.budget}, ccx will send C-c to agent tmux panes.`));
27
+ console.log(chalk.yellow(` This may cause unfinished work to be lost.`));
28
+ console.log();
29
+ }
30
+ let handle;
31
+ try {
32
+ handle = await startWatch({
33
+ teamName,
34
+ budget: options.budget,
35
+ stuckTimeoutMs: options.stuckTimeout ? options.stuckTimeout * 1000 : undefined,
36
+ });
37
+ }
38
+ catch (err) {
39
+ console.error(chalk.red(err instanceof Error ? err.message : 'Failed to start watch'));
40
+ process.exit(1);
41
+ }
42
+ // Guard: OS notification + hard limit
43
+ if (options.notify || options.kill) {
44
+ handle.aggregator.on('event', async (event) => {
45
+ if (event.type === 'cost_threshold') {
46
+ if (options.notify) {
47
+ await sendOsNotification('ccx budget alert', `${teamName}: ${formatCost(event.current)} / ${formatCost(event.budget)}`);
48
+ }
49
+ if (options.kill && event.current >= event.budget) {
50
+ const state = handle.aggregator.getState();
51
+ const paneIds = getPaneIds(state);
52
+ if (paneIds.length > 0) {
53
+ await killAllMembers(paneIds);
54
+ }
55
+ }
56
+ }
57
+ });
58
+ }
59
+ if (options.plain) {
60
+ // ─── Plain text mode ───
61
+ let shuttingDown = false;
62
+ const gracefulShutdown = async () => {
63
+ if (shuttingDown) {
64
+ process.exit(1);
65
+ }
66
+ shuttingDown = true;
67
+ try {
68
+ await handle.stop();
69
+ console.log(chalk.dim(`\nSaved to: ${handle.snapshotManager.sessionPath}`));
70
+ }
71
+ catch {
72
+ console.error(chalk.dim('\nSnapshot save failed.'));
73
+ }
74
+ process.exit(0);
75
+ };
76
+ process.on('SIGINT', gracefulShutdown);
77
+ process.on('SIGTERM', gracefulShutdown);
78
+ runPlainMode(handle);
79
+ }
80
+ else {
81
+ // ─── ink mode ───
82
+ // 需要 TTY 支援 raw mode,否則 fallback 到 plain mode
83
+ if (!process.stdin.isTTY) {
84
+ console.error(chalk.yellow('stdin is not a TTY — falling back to --plain mode.'));
85
+ let shuttingDown = false;
86
+ const gracefulShutdown = async () => {
87
+ if (shuttingDown) {
88
+ process.exit(1);
89
+ }
90
+ shuttingDown = true;
91
+ try {
92
+ await handle.stop();
93
+ console.log(chalk.dim(`\nSaved to: ${handle.snapshotManager.sessionPath}`));
94
+ }
95
+ catch {
96
+ console.error(chalk.dim('\nSnapshot save failed.'));
97
+ }
98
+ process.exit(0);
99
+ };
100
+ process.on('SIGINT', gracefulShutdown);
101
+ process.on('SIGTERM', gracefulShutdown);
102
+ runPlainMode(handle);
103
+ return;
104
+ }
105
+ // ink 在 raw mode 下攔截 Ctrl+C(作為 \x03 byte),自動呼叫 exit()
106
+ // 按 q / Escape 也會在 Dashboard 內呼叫 exit()
107
+ // waitUntilExit() 在 ink 退出後 resolve → 清理 → process.exit
108
+ const instance = render(React.createElement(Dashboard, {
109
+ aggregator: handle.aggregator,
110
+ budget: options.budget ?? null,
111
+ hardLimit: options.kill ?? false,
112
+ sessionPath: handle.snapshotManager.sessionPath,
113
+ }));
114
+ // SIGTERM(kill 指令)→ 觸發 ink unmount
115
+ process.on('SIGTERM', () => instance.unmount());
116
+ await instance.waitUntilExit();
117
+ // ink 已釋放 raw mode,Ctrl+C 恢復為 SIGINT
118
+ // 如果清理過程中使用者按 Ctrl+C → force exit
119
+ process.on('SIGINT', () => process.exit(1));
120
+ try {
121
+ await handle.stop();
122
+ console.log(chalk.dim(`Saved to: ${handle.snapshotManager.sessionPath}`));
123
+ }
124
+ catch {
125
+ console.error(chalk.dim('Snapshot save failed.'));
126
+ }
127
+ process.exit(0);
128
+ }
129
+ }
130
+ // ─── Plain text mode (Day 1 fallback) ───
131
+ function runPlainMode(handle) {
132
+ const renderPlain = () => {
133
+ const state = handle.aggregator.getState();
134
+ process.stdout.write('\x1B[2J\x1B[H');
135
+ process.stdout.write(formatPlainDashboard(state));
136
+ };
137
+ renderPlain();
138
+ setInterval(renderPlain, 2000);
139
+ handle.aggregator.on('event', async (event) => {
140
+ if (event.type === 'team_deleted') {
141
+ console.log(chalk.yellow(`\nTeam deleted. Snapshot saved to: ${handle.snapshotManager.sessionPath}`));
142
+ await handle.stop();
143
+ process.exit(0);
144
+ }
145
+ if (event.type === 'watcher_error') {
146
+ console.error(chalk.dim(`[watcher] ${event.source}: ${event.message}`));
147
+ }
148
+ });
149
+ }
150
+ function formatPlainDashboard(state) {
151
+ const lines = [];
152
+ const elapsed = formatDuration(state.elapsedMs);
153
+ lines.push(`ccx watch: ${state.teamName} (${elapsed}) Cost: ${formatCost(state.totalCost)}`);
154
+ lines.push('─'.repeat(72));
155
+ lines.push(`${'AGENTS'.padEnd(30)}${'STATUS'.padEnd(12)}${'ACTIVE'.padEnd(10)}${'TOKENS'.padEnd(10)}COST`);
156
+ for (let i = 0; i < state.agents.length; i++) {
157
+ const a = state.agents[i];
158
+ const prefix = i === state.agents.length - 1 ? '└─' : '├─';
159
+ const name = `${a.name} (${a.model})`.slice(0, 26);
160
+ const active = a.lastActivityAt > 0
161
+ ? formatTimeSince(a.lastActivityAt) : '──';
162
+ const tokens = formatTokens(totalTokenCount(a.tokenUsage));
163
+ lines.push(`${prefix} ${name.padEnd(28)}${a.status.padEnd(12)}${active.padEnd(10)}${tokens.padEnd(10)}${formatCost(a.cost)}`);
164
+ }
165
+ lines.push(`${''.padEnd(30)}${'TOTAL'.padEnd(12)}${''.padEnd(10)}${formatTokens(totalTokenCount(state.totalTokens)).padEnd(10)}${formatCost(state.totalCost)}`);
166
+ lines.push('');
167
+ lines.push('TASKS');
168
+ for (const t of state.tasks) {
169
+ const status = t.status === 'in_progress' ? '[working]' : t.status === 'completed' ? '[done]' : `[${t.status}]`;
170
+ lines.push(`#${t.id.padEnd(5)} ${status.padEnd(12)} ${t.subject.slice(0, 30).padEnd(32)} ${t.owner || '──'}`);
171
+ }
172
+ if (state.alerts.length > 0) {
173
+ lines.push('');
174
+ lines.push('ALERTS');
175
+ for (const a of state.alerts.slice(-3)) {
176
+ lines.push(`⚠ ${a.message}`);
177
+ }
178
+ }
179
+ lines.push('');
180
+ return lines.join('\n');
181
+ }
182
+ // ─── Auto-detect ───
183
+ async function autoDetectTeam() {
184
+ const teams = await listTeamNames();
185
+ if (teams.length === 1)
186
+ return teams[0];
187
+ if (teams.length === 0)
188
+ return null;
189
+ console.log(chalk.yellow('Multiple active teams found:'));
190
+ for (const name of teams) {
191
+ console.log(` - ${name}`);
192
+ }
193
+ console.log(chalk.dim('Specify one: ccx watch <team-name>'));
194
+ process.exit(1);
195
+ }
196
+ function getPaneIds(state) {
197
+ // 目前沒有直接拿到 paneId 的方式(config.json 的 tmuxPaneId 通常是空的)
198
+ // 這是 v1.5 hard limit 的限制
199
+ return [];
200
+ }
201
+ //# sourceMappingURL=watch.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"watch.js","sourceRoot":"","sources":["../../src/commands/watch.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ import type { FileCursor, JournalEntry } from './types.js';
2
+ export interface CursorReadResult {
3
+ readonly newEntries: readonly JournalEntry[];
4
+ readonly rawLines: readonly string[];
5
+ readonly cursor: FileCursor;
6
+ }
7
+ /**
8
+ * 建立新的 FileCursor
9
+ */
10
+ export declare function createCursor(path: string, agentId: string): FileCursor;
11
+ /**
12
+ * 從 cursor 的 lastByteOffset 開始讀取新增內容
13
+ * 回傳 parsed entries(有 usage 的行)和 raw lines(全部行,用於 identity resolve)
14
+ */
15
+ export declare function readIncremental(cursor: FileCursor): Promise<CursorReadResult>;
16
+ /**
17
+ * Full scan:從頭讀取整個檔案(startup 用)
18
+ */
19
+ export declare function readFull(path: string, agentId: string): Promise<CursorReadResult>;
20
+ /**
21
+ * 更新 cursor 的 identity 狀態
22
+ */
23
+ export declare function resolveCursorIdentity(cursor: FileCursor, name: string): FileCursor;
24
+ //# sourceMappingURL=cursor-reader.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cursor-reader.d.ts","sourceRoot":"","sources":["../../src/core/cursor-reader.ts"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAAE,UAAU,EAAc,YAAY,EAAe,MAAM,YAAY,CAAA;AAInF,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,UAAU,EAAE,SAAS,YAAY,EAAE,CAAA;IAC5C,QAAQ,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAA;IACpC,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAA;CAC5B;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,UAAU,CAYtE;AAED;;;GAGG;AACH,wBAAsB,eAAe,CAAC,MAAM,EAAE,UAAU,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAyDnF;AAED;;GAEG;AACH,wBAAsB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAGvF;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,UAAU,EAClB,IAAI,EAAE,MAAM,GACX,UAAU,CAMZ"}
@@ -0,0 +1,128 @@
1
+ /**
2
+ * CursorReader:byte-offset based JSONL 差量讀取
3
+ *
4
+ * 每個 JSONL 檔案維護獨立狀態:
5
+ * - UNRESOLVED: 每行的 raw text 都傳給 IdentityResolver 直到找到 teammate_id
6
+ * - RESOLVED: 只累加 token counts + 維護 ring buffer
7
+ *
8
+ * 設計原則:
9
+ * - 只存 offset + aggregated counts,不存全部 parsed records
10
+ * - Line-boundary parsing:記錄 lastCompleteLineEndOffset
11
+ * - Truncation detection:newSize < lastOffset → reset to 0
12
+ */
13
+ import { stat } from 'node:fs/promises';
14
+ import { createReadStream } from 'node:fs';
15
+ import { createInterface } from 'node:readline';
16
+ import { parseJournalLine } from './data-source-adapter.js';
17
+ import { addUsage, emptyUsage } from './pricing.js';
18
+ const RING_BUFFER_SIZE = 20;
19
+ /**
20
+ * 建立新的 FileCursor
21
+ */
22
+ export function createCursor(path, agentId) {
23
+ return {
24
+ path,
25
+ agentId,
26
+ lastByteOffset: 0,
27
+ lastInode: 0,
28
+ state: 'UNRESOLVED',
29
+ resolvedName: null,
30
+ accumulated: emptyUsage(),
31
+ model: null,
32
+ recentEntries: [],
33
+ };
34
+ }
35
+ /**
36
+ * 從 cursor 的 lastByteOffset 開始讀取新增內容
37
+ * 回傳 parsed entries(有 usage 的行)和 raw lines(全部行,用於 identity resolve)
38
+ */
39
+ export async function readIncremental(cursor) {
40
+ const fileStat = await stat(cursor.path).catch(() => null);
41
+ if (!fileStat) {
42
+ return { newEntries: [], rawLines: [], cursor };
43
+ }
44
+ const currentInode = fileStat.ino;
45
+ const currentSize = fileStat.size;
46
+ // Truncation/replacement detection
47
+ const wasReplaced = cursor.lastInode !== 0 && currentInode !== cursor.lastInode;
48
+ const wasTruncated = currentSize < cursor.lastByteOffset;
49
+ let startOffset = cursor.lastByteOffset;
50
+ let resetAccumulated = cursor.accumulated;
51
+ if (wasReplaced || wasTruncated) {
52
+ startOffset = 0;
53
+ resetAccumulated = emptyUsage();
54
+ }
55
+ if (currentSize <= startOffset) {
56
+ return {
57
+ newEntries: [],
58
+ rawLines: [],
59
+ cursor: { ...cursor, lastInode: currentInode },
60
+ };
61
+ }
62
+ // 讀取新增部分
63
+ const { entries, rawLines, bytesRead } = await readLines(cursor.path, startOffset, currentSize);
64
+ // 累加 token usage
65
+ let accumulated = resetAccumulated;
66
+ let model = cursor.model;
67
+ for (const entry of entries) {
68
+ accumulated = addUsage(accumulated, entry.message.usage);
69
+ if (!model && entry.message.model) {
70
+ model = entry.message.model;
71
+ }
72
+ }
73
+ // 更新 ring buffer
74
+ const existingRecent = wasReplaced || wasTruncated ? [] : [...cursor.recentEntries];
75
+ const allRecent = [...existingRecent, ...entries];
76
+ const recentEntries = allRecent.slice(-RING_BUFFER_SIZE);
77
+ const updatedCursor = {
78
+ ...cursor,
79
+ lastByteOffset: startOffset + bytesRead,
80
+ lastInode: currentInode,
81
+ accumulated,
82
+ model,
83
+ recentEntries,
84
+ };
85
+ return { newEntries: entries, rawLines, cursor: updatedCursor };
86
+ }
87
+ /**
88
+ * Full scan:從頭讀取整個檔案(startup 用)
89
+ */
90
+ export async function readFull(path, agentId) {
91
+ const cursor = createCursor(path, agentId);
92
+ return readIncremental(cursor);
93
+ }
94
+ /**
95
+ * 更新 cursor 的 identity 狀態
96
+ */
97
+ export function resolveCursorIdentity(cursor, name) {
98
+ return {
99
+ ...cursor,
100
+ state: 'RESOLVED',
101
+ resolvedName: name,
102
+ };
103
+ }
104
+ async function readLines(filePath, startOffset, endOffset) {
105
+ const entries = [];
106
+ const rawLines = [];
107
+ let bytesRead = 0;
108
+ const stream = createReadStream(filePath, {
109
+ start: startOffset,
110
+ end: endOffset - 1,
111
+ encoding: 'utf-8',
112
+ });
113
+ const rl = createInterface({ input: stream, crlfDelay: Infinity });
114
+ let lastCompleteLineEnd = 0;
115
+ for await (const line of rl) {
116
+ const lineBytes = Buffer.byteLength(line, 'utf-8') + 1; // +1 for newline
117
+ lastCompleteLineEnd += lineBytes;
118
+ rawLines.push(line);
119
+ const result = parseJournalLine(line);
120
+ if (result.ok) {
121
+ entries.push(result.data);
122
+ }
123
+ }
124
+ stream.destroy();
125
+ bytesRead = lastCompleteLineEnd;
126
+ return { entries, rawLines, bytesRead };
127
+ }
128
+ //# sourceMappingURL=cursor-reader.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cursor-reader.js","sourceRoot":"","sources":["../../src/core/cursor-reader.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,239 @@
1
+ /**
2
+ * 資料來源適配層:zod schema validation + 容錯 JSON 解析
3
+ */
4
+ import { z } from 'zod';
5
+ export declare const TeamMemberSchema: z.ZodObject<{
6
+ agentId: z.ZodString;
7
+ name: z.ZodString;
8
+ agentType: z.ZodString;
9
+ model: z.ZodDefault<z.ZodString>;
10
+ joinedAt: z.ZodNumber;
11
+ tmuxPaneId: z.ZodDefault<z.ZodString>;
12
+ cwd: z.ZodDefault<z.ZodString>;
13
+ subscriptions: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
14
+ }, "strip", z.ZodTypeAny, {
15
+ agentId: string;
16
+ name: string;
17
+ agentType: string;
18
+ model: string;
19
+ joinedAt: number;
20
+ tmuxPaneId: string;
21
+ cwd: string;
22
+ subscriptions: string[];
23
+ }, {
24
+ agentId: string;
25
+ name: string;
26
+ agentType: string;
27
+ joinedAt: number;
28
+ model?: string | undefined;
29
+ tmuxPaneId?: string | undefined;
30
+ cwd?: string | undefined;
31
+ subscriptions?: string[] | undefined;
32
+ }>;
33
+ export declare const TeamConfigSchema: z.ZodObject<{
34
+ name: z.ZodString;
35
+ description: z.ZodDefault<z.ZodString>;
36
+ createdAt: z.ZodNumber;
37
+ leadAgentId: z.ZodString;
38
+ leadSessionId: z.ZodString;
39
+ members: z.ZodDefault<z.ZodArray<z.ZodObject<{
40
+ agentId: z.ZodString;
41
+ name: z.ZodString;
42
+ agentType: z.ZodString;
43
+ model: z.ZodDefault<z.ZodString>;
44
+ joinedAt: z.ZodNumber;
45
+ tmuxPaneId: z.ZodDefault<z.ZodString>;
46
+ cwd: z.ZodDefault<z.ZodString>;
47
+ subscriptions: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
48
+ }, "strip", z.ZodTypeAny, {
49
+ agentId: string;
50
+ name: string;
51
+ agentType: string;
52
+ model: string;
53
+ joinedAt: number;
54
+ tmuxPaneId: string;
55
+ cwd: string;
56
+ subscriptions: string[];
57
+ }, {
58
+ agentId: string;
59
+ name: string;
60
+ agentType: string;
61
+ joinedAt: number;
62
+ model?: string | undefined;
63
+ tmuxPaneId?: string | undefined;
64
+ cwd?: string | undefined;
65
+ subscriptions?: string[] | undefined;
66
+ }>, "many">>;
67
+ }, "strip", z.ZodTypeAny, {
68
+ name: string;
69
+ description: string;
70
+ createdAt: number;
71
+ leadAgentId: string;
72
+ leadSessionId: string;
73
+ members: {
74
+ agentId: string;
75
+ name: string;
76
+ agentType: string;
77
+ model: string;
78
+ joinedAt: number;
79
+ tmuxPaneId: string;
80
+ cwd: string;
81
+ subscriptions: string[];
82
+ }[];
83
+ }, {
84
+ name: string;
85
+ createdAt: number;
86
+ leadAgentId: string;
87
+ leadSessionId: string;
88
+ description?: string | undefined;
89
+ members?: {
90
+ agentId: string;
91
+ name: string;
92
+ agentType: string;
93
+ joinedAt: number;
94
+ model?: string | undefined;
95
+ tmuxPaneId?: string | undefined;
96
+ cwd?: string | undefined;
97
+ subscriptions?: string[] | undefined;
98
+ }[] | undefined;
99
+ }>;
100
+ export declare const TaskDataSchema: z.ZodObject<{
101
+ id: z.ZodString;
102
+ subject: z.ZodDefault<z.ZodString>;
103
+ description: z.ZodDefault<z.ZodString>;
104
+ activeForm: z.ZodDefault<z.ZodString>;
105
+ owner: z.ZodDefault<z.ZodString>;
106
+ status: z.ZodDefault<z.ZodEnum<["pending", "in_progress", "completed", "deleted"]>>;
107
+ blocks: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
108
+ blockedBy: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
109
+ }, "strip", z.ZodTypeAny, {
110
+ status: "pending" | "in_progress" | "completed" | "deleted";
111
+ description: string;
112
+ id: string;
113
+ subject: string;
114
+ activeForm: string;
115
+ owner: string;
116
+ blocks: string[];
117
+ blockedBy: string[];
118
+ }, {
119
+ id: string;
120
+ status?: "pending" | "in_progress" | "completed" | "deleted" | undefined;
121
+ description?: string | undefined;
122
+ subject?: string | undefined;
123
+ activeForm?: string | undefined;
124
+ owner?: string | undefined;
125
+ blocks?: string[] | undefined;
126
+ blockedBy?: string[] | undefined;
127
+ }>;
128
+ export declare const InboxMessageSchema: z.ZodObject<{
129
+ from: z.ZodString;
130
+ text: z.ZodDefault<z.ZodString>;
131
+ summary: z.ZodDefault<z.ZodString>;
132
+ timestamp: z.ZodString;
133
+ color: z.ZodDefault<z.ZodString>;
134
+ read: z.ZodDefault<z.ZodBoolean>;
135
+ }, "strip", z.ZodTypeAny, {
136
+ from: string;
137
+ text: string;
138
+ summary: string;
139
+ timestamp: string;
140
+ color: string;
141
+ read: boolean;
142
+ }, {
143
+ from: string;
144
+ timestamp: string;
145
+ text?: string | undefined;
146
+ summary?: string | undefined;
147
+ color?: string | undefined;
148
+ read?: boolean | undefined;
149
+ }>;
150
+ export declare const JournalEntrySchema: z.ZodObject<{
151
+ sessionId: z.ZodOptional<z.ZodString>;
152
+ agentId: z.ZodOptional<z.ZodString>;
153
+ timestamp: z.ZodString;
154
+ message: z.ZodObject<{
155
+ model: z.ZodDefault<z.ZodString>;
156
+ usage: z.ZodObject<{
157
+ input_tokens: z.ZodDefault<z.ZodNumber>;
158
+ output_tokens: z.ZodDefault<z.ZodNumber>;
159
+ cache_creation_input_tokens: z.ZodDefault<z.ZodNumber>;
160
+ cache_read_input_tokens: z.ZodDefault<z.ZodNumber>;
161
+ }, "strip", z.ZodTypeAny, {
162
+ input_tokens: number;
163
+ output_tokens: number;
164
+ cache_creation_input_tokens: number;
165
+ cache_read_input_tokens: number;
166
+ }, {
167
+ input_tokens?: number | undefined;
168
+ output_tokens?: number | undefined;
169
+ cache_creation_input_tokens?: number | undefined;
170
+ cache_read_input_tokens?: number | undefined;
171
+ }>;
172
+ }, "strip", z.ZodTypeAny, {
173
+ model: string;
174
+ usage: {
175
+ input_tokens: number;
176
+ output_tokens: number;
177
+ cache_creation_input_tokens: number;
178
+ cache_read_input_tokens: number;
179
+ };
180
+ }, {
181
+ usage: {
182
+ input_tokens?: number | undefined;
183
+ output_tokens?: number | undefined;
184
+ cache_creation_input_tokens?: number | undefined;
185
+ cache_read_input_tokens?: number | undefined;
186
+ };
187
+ model?: string | undefined;
188
+ }>;
189
+ }, "strip", z.ZodTypeAny, {
190
+ message: {
191
+ model: string;
192
+ usage: {
193
+ input_tokens: number;
194
+ output_tokens: number;
195
+ cache_creation_input_tokens: number;
196
+ cache_read_input_tokens: number;
197
+ };
198
+ };
199
+ timestamp: string;
200
+ agentId?: string | undefined;
201
+ sessionId?: string | undefined;
202
+ }, {
203
+ message: {
204
+ usage: {
205
+ input_tokens?: number | undefined;
206
+ output_tokens?: number | undefined;
207
+ cache_creation_input_tokens?: number | undefined;
208
+ cache_read_input_tokens?: number | undefined;
209
+ };
210
+ model?: string | undefined;
211
+ };
212
+ timestamp: string;
213
+ agentId?: string | undefined;
214
+ sessionId?: string | undefined;
215
+ }>;
216
+ export declare function safeParseJson<S extends z.ZodTypeAny>(raw: string, schema: S): {
217
+ ok: true;
218
+ data: z.output<S>;
219
+ } | {
220
+ ok: false;
221
+ error: string;
222
+ };
223
+ export declare function safeParseJsonArray<S extends z.ZodTypeAny>(raw: string, itemSchema: S): {
224
+ ok: true;
225
+ data: Array<z.output<S>>;
226
+ } | {
227
+ ok: false;
228
+ error: string;
229
+ };
230
+ /**
231
+ * 解析 JSONL 的單一行 — 忽略不完整的行
232
+ */
233
+ export declare function parseJournalLine(line: string): {
234
+ ok: true;
235
+ data: z.output<typeof JournalEntrySchema>;
236
+ } | {
237
+ ok: false;
238
+ };
239
+ //# sourceMappingURL=data-source-adapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"data-source-adapter.d.ts","sourceRoot":"","sources":["../../src/core/data-source-adapter.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAIvB,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;EAS3B,CAAA;AAEF,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAO3B,CAAA;AAEF,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;EASzB,CAAA;AAEF,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;EAO7B,CAAA;AAEF,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAa7B,CAAA;AAIF,wBAAgB,aAAa,CAAC,CAAC,SAAS,CAAC,CAAC,UAAU,EAClD,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,CAAC,GACR;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAWhE;AAED,wBAAgB,kBAAkB,CAAC,CAAC,SAAS,CAAC,CAAC,UAAU,EACvD,GAAG,EAAE,MAAM,EACX,UAAU,EAAE,CAAC,GACZ;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAEvE;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,MAAM,GACX;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,OAAO,kBAAkB,CAAC,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAA;CAAE,CAMzE"}