@tznthou/ccrecall 0.1.2

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 (87) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +290 -0
  3. package/README_ZH.md +288 -0
  4. package/dist/api/routes.d.ts +13 -0
  5. package/dist/api/routes.d.ts.map +1 -0
  6. package/dist/api/routes.js +428 -0
  7. package/dist/api/routes.js.map +1 -0
  8. package/dist/api/server.d.ts +7 -0
  9. package/dist/api/server.d.ts.map +1 -0
  10. package/dist/api/server.js +44 -0
  11. package/dist/api/server.js.map +1 -0
  12. package/dist/cli/daemon.d.ts +35 -0
  13. package/dist/cli/daemon.d.ts.map +1 -0
  14. package/dist/cli/daemon.js +163 -0
  15. package/dist/cli/daemon.js.map +1 -0
  16. package/dist/core/compression.d.ts +37 -0
  17. package/dist/core/compression.d.ts.map +1 -0
  18. package/dist/core/compression.js +129 -0
  19. package/dist/core/compression.js.map +1 -0
  20. package/dist/core/database.d.ts +219 -0
  21. package/dist/core/database.d.ts.map +1 -0
  22. package/dist/core/database.js +1513 -0
  23. package/dist/core/database.js.map +1 -0
  24. package/dist/core/index.d.ts +9 -0
  25. package/dist/core/index.d.ts.map +1 -0
  26. package/dist/core/index.js +8 -0
  27. package/dist/core/index.js.map +1 -0
  28. package/dist/core/indexer.d.ts +15 -0
  29. package/dist/core/indexer.d.ts.map +1 -0
  30. package/dist/core/indexer.js +224 -0
  31. package/dist/core/indexer.js.map +1 -0
  32. package/dist/core/lint.d.ts +17 -0
  33. package/dist/core/lint.d.ts.map +1 -0
  34. package/dist/core/lint.js +51 -0
  35. package/dist/core/lint.js.map +1 -0
  36. package/dist/core/log-safe.d.ts +6 -0
  37. package/dist/core/log-safe.d.ts.map +1 -0
  38. package/dist/core/log-safe.js +11 -0
  39. package/dist/core/log-safe.js.map +1 -0
  40. package/dist/core/maintenance-coordinator.d.ts +26 -0
  41. package/dist/core/maintenance-coordinator.d.ts.map +1 -0
  42. package/dist/core/maintenance-coordinator.js +67 -0
  43. package/dist/core/maintenance-coordinator.js.map +1 -0
  44. package/dist/core/memory-service.d.ts +31 -0
  45. package/dist/core/memory-service.d.ts.map +1 -0
  46. package/dist/core/memory-service.js +47 -0
  47. package/dist/core/memory-service.js.map +1 -0
  48. package/dist/core/parser.d.ts +17 -0
  49. package/dist/core/parser.d.ts.map +1 -0
  50. package/dist/core/parser.js +205 -0
  51. package/dist/core/parser.js.map +1 -0
  52. package/dist/core/scanner.d.ts +8 -0
  53. package/dist/core/scanner.d.ts.map +1 -0
  54. package/dist/core/scanner.js +123 -0
  55. package/dist/core/scanner.js.map +1 -0
  56. package/dist/core/summarizer.d.ts +12 -0
  57. package/dist/core/summarizer.d.ts.map +1 -0
  58. package/dist/core/summarizer.js +430 -0
  59. package/dist/core/summarizer.js.map +1 -0
  60. package/dist/core/topic-extractor.d.ts +11 -0
  61. package/dist/core/topic-extractor.d.ts.map +1 -0
  62. package/dist/core/topic-extractor.js +51 -0
  63. package/dist/core/topic-extractor.js.map +1 -0
  64. package/dist/core/types.d.ts +329 -0
  65. package/dist/core/types.d.ts.map +1 -0
  66. package/dist/core/types.js +12 -0
  67. package/dist/core/types.js.map +1 -0
  68. package/dist/core/watcher.d.ts +30 -0
  69. package/dist/core/watcher.d.ts.map +1 -0
  70. package/dist/core/watcher.js +146 -0
  71. package/dist/core/watcher.js.map +1 -0
  72. package/dist/index.d.ts +3 -0
  73. package/dist/index.d.ts.map +1 -0
  74. package/dist/index.js +116 -0
  75. package/dist/index.js.map +1 -0
  76. package/dist/mcp/server.d.ts +3 -0
  77. package/dist/mcp/server.d.ts.map +1 -0
  78. package/dist/mcp/server.js +32 -0
  79. package/dist/mcp/server.js.map +1 -0
  80. package/dist/mcp/tools.d.ts +39 -0
  81. package/dist/mcp/tools.d.ts.map +1 -0
  82. package/dist/mcp/tools.js +215 -0
  83. package/dist/mcp/tools.js.map +1 -0
  84. package/hooks/README.md +78 -0
  85. package/hooks/session-end.mjs +92 -0
  86. package/hooks/session-start.mjs +112 -0
  87. package/package.json +54 -0
@@ -0,0 +1,47 @@
1
+ import { scrubErrorMessage } from './log-safe.js';
2
+ /**
3
+ * Phase 4b: thin abstraction on top of Database for memory lifecycle operations
4
+ * (touch / delete / update-content). Centralises policy so HTTP routes, MCP
5
+ * tools, hooks and background maintenance all share the same semantics.
6
+ *
7
+ * Deliberately narrow for now. Compression scheduling, decay tuning and lint
8
+ * orchestration land in Phase 4c–4e and will be added here rather than in the
9
+ * callers.
10
+ */
11
+ export class MemoryService {
12
+ db;
13
+ constructor(db) {
14
+ this.db = db;
15
+ }
16
+ /**
17
+ * Increment access_count and stamp last_accessed for each id. Dedupes
18
+ * automatically so the same memory surfaced in multiple topic clusters is
19
+ * only counted once per request.
20
+ *
21
+ * Fire-and-forget: swallows errors and logs to stderr so query latency is
22
+ * never affected by touch failures.
23
+ */
24
+ touch(ids) {
25
+ const unique = Array.from(new Set(ids));
26
+ if (unique.length === 0)
27
+ return;
28
+ try {
29
+ this.db.touchMemory(unique);
30
+ }
31
+ catch (err) {
32
+ console.warn('[memory-service] touch failed:', scrubErrorMessage(err));
33
+ }
34
+ }
35
+ /** Delete a memory by id. Returns true if a row was deleted. */
36
+ delete(id) {
37
+ return this.db.deleteMemory(id);
38
+ }
39
+ /**
40
+ * Rewrite memory.content and stamp compression metadata atomically. Used by
41
+ * the compression pipeline in Phase 4d.
42
+ */
43
+ updateContent(id, content, level) {
44
+ return this.db.updateMemoryContent(id, content, level, new Date().toISOString());
45
+ }
46
+ }
47
+ //# sourceMappingURL=memory-service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"memory-service.js","sourceRoot":"","sources":["../../src/core/memory-service.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAA;AAEjD;;;;;;;;GAQG;AACH,MAAM,OAAO,aAAa;IACK;IAA7B,YAA6B,EAAY;QAAZ,OAAE,GAAF,EAAE,CAAU;IAAG,CAAC;IAE7C;;;;;;;OAOG;IACH,KAAK,CAAC,GAAa;QACjB,MAAM,MAAM,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC,CAAA;QACvC,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;YAAE,OAAM;QAC/B,IAAI,CAAC;YACH,IAAI,CAAC,EAAE,CAAC,WAAW,CAAC,MAAM,CAAC,CAAA;QAC7B,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,CAAC,IAAI,CAAC,gCAAgC,EAAE,iBAAiB,CAAC,GAAG,CAAC,CAAC,CAAA;QACxE,CAAC;IACH,CAAC;IAED,gEAAgE;IAChE,MAAM,CAAC,EAAU;QACf,OAAO,IAAI,CAAC,EAAE,CAAC,YAAY,CAAC,EAAE,CAAC,CAAA;IACjC,CAAC;IAED;;;OAGG;IACH,aAAa,CAAC,EAAU,EAAE,OAAe,EAAE,KAAa;QACtD,OAAO,IAAI,CAAC,EAAE,CAAC,mBAAmB,CAAC,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,CAAA;IAClF,CAAC;CACF"}
@@ -0,0 +1,17 @@
1
+ import type { ParsedLine, ParsedSession } from './types.js';
2
+ interface ContentResult {
3
+ contentText: string | null;
4
+ hasToolUse: boolean;
5
+ hasToolResult: boolean;
6
+ toolNames: string[];
7
+ }
8
+ /** 移除系統注入的 XML 標籤,保留使用者原始文字。白名單制,不認識的標籤不動 */
9
+ export declare function stripSystemXml(text: string): string;
10
+ /** 解析 message.content 欄位,處理 string 和 array 兩種格式 */
11
+ export declare function parseContent(content: unknown): ContentResult;
12
+ /** 解析單行 JSONL,失敗回傳 null */
13
+ export declare function parseLine(line: string): ParsedLine | null;
14
+ /** 解析整個 JSONL 檔案為結構化 session */
15
+ export declare function parseSession(filePath: string, sessionId: string): Promise<ParsedSession>;
16
+ export {};
17
+ //# sourceMappingURL=parser.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parser.d.ts","sourceRoot":"","sources":["../../src/core/parser.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAE3D,UAAU,aAAa;IACrB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;IAC1B,UAAU,EAAE,OAAO,CAAA;IACnB,aAAa,EAAE,OAAO,CAAA;IACtB,SAAS,EAAE,MAAM,EAAE,CAAA;CACpB;AAcD,6CAA6C;AAC7C,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEnD;AAED,mDAAmD;AACnD,wBAAgB,YAAY,CAAC,OAAO,EAAE,OAAO,GAAG,aAAa,CA+C5D;AA6BD,2BAA2B;AAC3B,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI,CA8EzD;AAID,gCAAgC;AAChC,wBAAsB,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CAmD9F"}
@@ -0,0 +1,205 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ import { readFile } from 'node:fs/promises';
3
+ /** 完全移除的系統標籤(標籤+內容一起刪)*/
4
+ const STRIP_TAGS = ['local-command-caveat', 'task-notification', 'ide_opened_file', 'system-reminder'];
5
+ /** 只移除標籤殼、保留內文的系統標籤 */
6
+ const UNWRAP_TAGS = ['command-name', 'command-message', 'command-args', 'local-command-stdout'];
7
+ const STRIP_RE = new RegExp(STRIP_TAGS.map(t => `<${t}>[\\s\\S]*?</${t}>`).join('|'), 'g');
8
+ const UNWRAP_RE = new RegExp(`<(${UNWRAP_TAGS.join('|')})>([\\s\\S]*?)</\\1>`, 'g');
9
+ /** 移除系統注入的 XML 標籤,保留使用者原始文字。白名單制,不認識的標籤不動 */
10
+ export function stripSystemXml(text) {
11
+ return text.replace(STRIP_RE, '').replace(UNWRAP_RE, (_, _tag, content) => content).trim();
12
+ }
13
+ /** 解析 message.content 欄位,處理 string 和 array 兩種格式 */
14
+ export function parseContent(content) {
15
+ if (content == null) {
16
+ return { contentText: null, hasToolUse: false, hasToolResult: false, toolNames: [] };
17
+ }
18
+ if (typeof content === 'string') {
19
+ const cleaned = stripSystemXml(content);
20
+ return { contentText: cleaned || null, hasToolUse: false, hasToolResult: false, toolNames: [] };
21
+ }
22
+ if (!Array.isArray(content)) {
23
+ return { contentText: null, hasToolUse: false, hasToolResult: false, toolNames: [] };
24
+ }
25
+ const textParts = [];
26
+ let hasToolUse = false;
27
+ let hasToolResult = false;
28
+ const toolNames = [];
29
+ for (const block of content) {
30
+ if (block == null || typeof block !== 'object')
31
+ continue;
32
+ const b = block;
33
+ switch (b.type) {
34
+ case 'text':
35
+ if (typeof b.text === 'string') {
36
+ const cleaned = stripSystemXml(b.text);
37
+ if (cleaned)
38
+ textParts.push(cleaned);
39
+ }
40
+ break;
41
+ case 'tool_use':
42
+ hasToolUse = true;
43
+ if (typeof b.name === 'string')
44
+ toolNames.push(b.name);
45
+ break;
46
+ case 'tool_result':
47
+ hasToolResult = true;
48
+ break;
49
+ // thinking, server_tool_use 等 → 跳過
50
+ }
51
+ }
52
+ return {
53
+ contentText: textParts.length > 0 ? textParts.join('\n') : null,
54
+ hasToolUse,
55
+ hasToolResult,
56
+ toolNames,
57
+ };
58
+ }
59
+ /** 安全轉換為整數,非數字回傳 null */
60
+ function toInt(v) {
61
+ return typeof v === 'number' ? Math.floor(v) : null;
62
+ }
63
+ /** 從 message.usage 抽取 token 資料 */
64
+ function parseUsage(message) {
65
+ const usage = message.usage;
66
+ if (!usage || typeof usage !== 'object') {
67
+ return { inputTokens: null, outputTokens: null, cacheReadTokens: null, cacheCreationTokens: null };
68
+ }
69
+ const base = toInt(usage.input_tokens) ?? 0;
70
+ const cacheRead = toInt(usage.cache_read_input_tokens) ?? 0;
71
+ const cacheCreation = toInt(usage.cache_creation_input_tokens) ?? 0;
72
+ return {
73
+ inputTokens: base + cacheRead + cacheCreation,
74
+ outputTokens: toInt(usage.output_tokens) ?? 0,
75
+ cacheReadTokens: cacheRead,
76
+ cacheCreationTokens: cacheCreation,
77
+ };
78
+ }
79
+ /** 解析單行 JSONL,失敗回傳 null */
80
+ export function parseLine(line) {
81
+ if (!line.trim())
82
+ return null;
83
+ let obj;
84
+ try {
85
+ obj = JSON.parse(line);
86
+ }
87
+ catch {
88
+ return null;
89
+ }
90
+ if (typeof obj !== 'object' || obj === null)
91
+ return null;
92
+ const type = typeof obj.type === 'string' ? obj.type : 'unknown';
93
+ const rawUuid = typeof obj.uuid === 'string' ? obj.uuid.trim() : null;
94
+ const uuid = rawUuid && rawUuid.length <= 128 ? rawUuid : null;
95
+ const parentUuid = typeof obj.parentUuid === 'string' ? obj.parentUuid : null;
96
+ const sessionId = typeof obj.sessionId === 'string' ? obj.sessionId : null;
97
+ const timestamp = typeof obj.timestamp === 'string' ? obj.timestamp : null;
98
+ const rawRequestId = typeof obj.requestId === 'string' ? obj.requestId : null;
99
+ const requestId = rawRequestId && rawRequestId.length <= 128 ? rawRequestId : null;
100
+ let role = null;
101
+ let contentText = null;
102
+ let contentJson = null;
103
+ let hasToolUse = false;
104
+ let hasToolResult = false;
105
+ let toolNames = [];
106
+ let inputTokens = null;
107
+ let outputTokens = null;
108
+ let cacheReadTokens = null;
109
+ let cacheCreationTokens = null;
110
+ let model = null;
111
+ const message = obj.message;
112
+ if (message && typeof message === 'object') {
113
+ if (message.role === 'user' || message.role === 'assistant') {
114
+ role = message.role;
115
+ }
116
+ const result = parseContent(message.content);
117
+ contentText = result.contentText;
118
+ hasToolUse = result.hasToolUse;
119
+ hasToolResult = result.hasToolResult;
120
+ toolNames = result.toolNames;
121
+ contentJson = message.content != null ? JSON.stringify(message.content) : null;
122
+ // Token usage(僅 assistant 訊息有值)
123
+ const tokenData = parseUsage(message);
124
+ inputTokens = tokenData.inputTokens;
125
+ outputTokens = tokenData.outputTokens;
126
+ cacheReadTokens = tokenData.cacheReadTokens;
127
+ cacheCreationTokens = tokenData.cacheCreationTokens;
128
+ model = typeof message.model === 'string' ? message.model : null;
129
+ }
130
+ else if (typeof obj.content === 'string') {
131
+ // queue-operation 等 type 的 prompt 存在頂層 content 欄位
132
+ const cleaned = stripSystemXml(obj.content);
133
+ contentText = cleaned || null;
134
+ }
135
+ return {
136
+ type,
137
+ uuid,
138
+ parentUuid,
139
+ sessionId,
140
+ timestamp,
141
+ role,
142
+ contentText,
143
+ contentJson,
144
+ hasToolUse,
145
+ hasToolResult,
146
+ toolNames,
147
+ rawJson: line,
148
+ inputTokens,
149
+ outputTokens,
150
+ cacheReadTokens,
151
+ cacheCreationTokens,
152
+ model,
153
+ requestId,
154
+ };
155
+ }
156
+ const TITLE_MAX_LENGTH = 80;
157
+ /** 解析整個 JSONL 檔案為結構化 session */
158
+ export async function parseSession(filePath, sessionId) {
159
+ const raw = await readFile(filePath, 'utf-8');
160
+ const lines = raw.split('\n');
161
+ const messages = [];
162
+ let skippedLines = 0;
163
+ let totalLines = 0;
164
+ let title = null;
165
+ let startedAt = null;
166
+ let endedAt = null;
167
+ for (const line of lines) {
168
+ if (!line.trim())
169
+ continue;
170
+ totalLines++;
171
+ const parsed = parseLine(line);
172
+ if (!parsed) {
173
+ skippedLines++;
174
+ continue;
175
+ }
176
+ parsed.sessionId ??= sessionId;
177
+ messages.push(parsed);
178
+ // 追蹤時間範圍
179
+ if (parsed.timestamp) {
180
+ if (!startedAt)
181
+ startedAt = parsed.timestamp;
182
+ endedAt = parsed.timestamp;
183
+ }
184
+ // Title 推導:queue-operation prompt 優先,其次第一筆 user 訊息
185
+ if (!title && parsed.contentText) {
186
+ const isQueuePrompt = parsed.type === 'queue-operation';
187
+ const isFirstUser = parsed.role === 'user';
188
+ if (isQueuePrompt || isFirstUser) {
189
+ title = parsed.contentText.length > TITLE_MAX_LENGTH
190
+ ? parsed.contentText.slice(0, TITLE_MAX_LENGTH) + '…'
191
+ : parsed.contentText;
192
+ }
193
+ }
194
+ }
195
+ return {
196
+ sessionId,
197
+ title: title ?? sessionId,
198
+ messages,
199
+ startedAt,
200
+ endedAt,
201
+ skippedLines,
202
+ totalLines,
203
+ };
204
+ }
205
+ //# sourceMappingURL=parser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parser.js","sourceRoot":"","sources":["../../src/core/parser.ts"],"names":[],"mappings":"AAAA,sCAAsC;AACtC,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAA;AAU3C,yBAAyB;AACzB,MAAM,UAAU,GAAG,CAAC,sBAAsB,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,iBAAiB,CAAC,CAAA;AACtG,uBAAuB;AACvB,MAAM,WAAW,GAAG,CAAC,cAAc,EAAE,iBAAiB,EAAE,cAAc,EAAE,sBAAsB,CAAC,CAAA;AAE/F,MAAM,QAAQ,GAAG,IAAI,MAAM,CACzB,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,GAAG,CAC9D,CAAA;AACD,MAAM,SAAS,GAAG,IAAI,MAAM,CAC1B,KAAK,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC,sBAAsB,EAAE,GAAG,CACtD,CAAA;AAED,6CAA6C;AAC7C,MAAM,UAAU,cAAc,CAAC,IAAY;IACzC,OAAO,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC,EAAE,IAAY,EAAE,OAAe,EAAE,EAAE,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,CAAA;AAC5G,CAAC;AAED,mDAAmD;AACnD,MAAM,UAAU,YAAY,CAAC,OAAgB;IAC3C,IAAI,OAAO,IAAI,IAAI,EAAE,CAAC;QACpB,OAAO,EAAE,WAAW,EAAE,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,aAAa,EAAE,KAAK,EAAE,SAAS,EAAE,EAAE,EAAE,CAAA;IACtF,CAAC;IAED,IAAI,OAAO,OAAO,KAAK,QAAQ,EAAE,CAAC;QAChC,MAAM,OAAO,GAAG,cAAc,CAAC,OAAO,CAAC,CAAA;QACvC,OAAO,EAAE,WAAW,EAAE,OAAO,IAAI,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,aAAa,EAAE,KAAK,EAAE,SAAS,EAAE,EAAE,EAAE,CAAA;IACjG,CAAC;IAED,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;QAC5B,OAAO,EAAE,WAAW,EAAE,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,aAAa,EAAE,KAAK,EAAE,SAAS,EAAE,EAAE,EAAE,CAAA;IACtF,CAAC;IAED,MAAM,SAAS,GAAa,EAAE,CAAA;IAC9B,IAAI,UAAU,GAAG,KAAK,CAAA;IACtB,IAAI,aAAa,GAAG,KAAK,CAAA;IACzB,MAAM,SAAS,GAAa,EAAE,CAAA;IAE9B,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,IAAI,KAAK,IAAI,IAAI,IAAI,OAAO,KAAK,KAAK,QAAQ;YAAE,SAAQ;QACxD,MAAM,CAAC,GAAG,KAAgC,CAAA;QAE1C,QAAQ,CAAC,CAAC,IAAI,EAAE,CAAC;YACf,KAAK,MAAM;gBACT,IAAI,OAAO,CAAC,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;oBAC/B,MAAM,OAAO,GAAG,cAAc,CAAC,CAAC,CAAC,IAAI,CAAC,CAAA;oBACtC,IAAI,OAAO;wBAAE,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;gBACtC,CAAC;gBACD,MAAK;YACP,KAAK,UAAU;gBACb,UAAU,GAAG,IAAI,CAAA;gBACjB,IAAI,OAAO,CAAC,CAAC,IAAI,KAAK,QAAQ;oBAAE,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAA;gBACtD,MAAK;YACP,KAAK,aAAa;gBAChB,aAAa,GAAG,IAAI,CAAA;gBACpB,MAAK;YACP,mCAAmC;QACrC,CAAC;IACH,CAAC;IAED,OAAO;QACL,WAAW,EAAE,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI;QAC/D,UAAU;QACV,aAAa;QACb,SAAS;KACV,CAAA;AACH,CAAC;AAED,yBAAyB;AACzB,SAAS,KAAK,CAAC,CAAU;IACvB,OAAO,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAA;AACrD,CAAC;AAED,kCAAkC;AAClC,SAAS,UAAU,CAAC,OAAgC;IAMlD,MAAM,KAAK,GAAG,OAAO,CAAC,KAA4C,CAAA;IAClE,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QACxC,OAAO,EAAE,WAAW,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,eAAe,EAAE,IAAI,EAAE,mBAAmB,EAAE,IAAI,EAAE,CAAA;IACpG,CAAC;IACD,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,CAAC,CAAA;IAC3C,MAAM,SAAS,GAAG,KAAK,CAAC,KAAK,CAAC,uBAAuB,CAAC,IAAI,CAAC,CAAA;IAC3D,MAAM,aAAa,GAAG,KAAK,CAAC,KAAK,CAAC,2BAA2B,CAAC,IAAI,CAAC,CAAA;IACnE,OAAO;QACL,WAAW,EAAE,IAAI,GAAG,SAAS,GAAG,aAAa;QAC7C,YAAY,EAAE,KAAK,CAAC,KAAK,CAAC,aAAa,CAAC,IAAI,CAAC;QAC7C,eAAe,EAAE,SAAS;QAC1B,mBAAmB,EAAE,aAAa;KACnC,CAAA;AACH,CAAC;AAED,2BAA2B;AAC3B,MAAM,UAAU,SAAS,CAAC,IAAY;IACpC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE;QAAE,OAAO,IAAI,CAAA;IAE7B,IAAI,GAA4B,CAAA;IAChC,IAAI,CAAC;QACH,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;IACxB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAA;IACb,CAAC;IAED,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,IAAI;QAAE,OAAO,IAAI,CAAA;IAExD,MAAM,IAAI,GAAG,OAAO,GAAG,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAA;IAChE,MAAM,OAAO,GAAG,OAAO,GAAG,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAA;IACrE,MAAM,IAAI,GAAG,OAAO,IAAI,OAAO,CAAC,MAAM,IAAI,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAA;IAC9D,MAAM,UAAU,GAAG,OAAO,GAAG,CAAC,UAAU,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAA;IAC7E,MAAM,SAAS,GAAG,OAAO,GAAG,CAAC,SAAS,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAA;IAC1E,MAAM,SAAS,GAAG,OAAO,GAAG,CAAC,SAAS,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAA;IAC1E,MAAM,YAAY,GAAG,OAAO,GAAG,CAAC,SAAS,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAA;IAC7E,MAAM,SAAS,GAAG,YAAY,IAAI,YAAY,CAAC,MAAM,IAAI,GAAG,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,CAAA;IAElF,IAAI,IAAI,GAAgC,IAAI,CAAA;IAC5C,IAAI,WAAW,GAAkB,IAAI,CAAA;IACrC,IAAI,WAAW,GAAkB,IAAI,CAAA;IACrC,IAAI,UAAU,GAAG,KAAK,CAAA;IACtB,IAAI,aAAa,GAAG,KAAK,CAAA;IACzB,IAAI,SAAS,GAAa,EAAE,CAAA;IAC5B,IAAI,WAAW,GAAkB,IAAI,CAAA;IACrC,IAAI,YAAY,GAAkB,IAAI,CAAA;IACtC,IAAI,eAAe,GAAkB,IAAI,CAAA;IACzC,IAAI,mBAAmB,GAAkB,IAAI,CAAA;IAC7C,IAAI,KAAK,GAAkB,IAAI,CAAA;IAE/B,MAAM,OAAO,GAAG,GAAG,CAAC,OAA8C,CAAA;IAClE,IAAI,OAAO,IAAI,OAAO,OAAO,KAAK,QAAQ,EAAE,CAAC;QAC3C,IAAI,OAAO,CAAC,IAAI,KAAK,MAAM,IAAI,OAAO,CAAC,IAAI,KAAK,WAAW,EAAE,CAAC;YAC5D,IAAI,GAAG,OAAO,CAAC,IAAI,CAAA;QACrB,CAAC;QACD,MAAM,MAAM,GAAG,YAAY,CAAC,OAAO,CAAC,OAAO,CAAC,CAAA;QAC5C,WAAW,GAAG,MAAM,CAAC,WAAW,CAAA;QAChC,UAAU,GAAG,MAAM,CAAC,UAAU,CAAA;QAC9B,aAAa,GAAG,MAAM,CAAC,aAAa,CAAA;QACpC,SAAS,GAAG,MAAM,CAAC,SAAS,CAAA;QAC5B,WAAW,GAAG,OAAO,CAAC,OAAO,IAAI,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,CAAA;QAE9E,gCAAgC;QAChC,MAAM,SAAS,GAAG,UAAU,CAAC,OAAO,CAAC,CAAA;QACrC,WAAW,GAAG,SAAS,CAAC,WAAW,CAAA;QACnC,YAAY,GAAG,SAAS,CAAC,YAAY,CAAA;QACrC,eAAe,GAAG,SAAS,CAAC,eAAe,CAAA;QAC3C,mBAAmB,GAAG,SAAS,CAAC,mBAAmB,CAAA;QACnD,KAAK,GAAG,OAAO,OAAO,CAAC,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAA;IAClE,CAAC;SAAM,IAAI,OAAO,GAAG,CAAC,OAAO,KAAK,QAAQ,EAAE,CAAC;QAC3C,kDAAkD;QAClD,MAAM,OAAO,GAAG,cAAc,CAAC,GAAG,CAAC,OAAiB,CAAC,CAAA;QACrD,WAAW,GAAG,OAAO,IAAI,IAAI,CAAA;IAC/B,CAAC;IAED,OAAO;QACL,IAAI;QACJ,IAAI;QACJ,UAAU;QACV,SAAS;QACT,SAAS;QACT,IAAI;QACJ,WAAW;QACX,WAAW;QACX,UAAU;QACV,aAAa;QACb,SAAS;QACT,OAAO,EAAE,IAAI;QACb,WAAW;QACX,YAAY;QACZ,eAAe;QACf,mBAAmB;QACnB,KAAK;QACL,SAAS;KACV,CAAA;AACH,CAAC;AAED,MAAM,gBAAgB,GAAG,EAAE,CAAA;AAE3B,gCAAgC;AAChC,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,QAAgB,EAAE,SAAiB;IACpE,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAA;IAC7C,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;IAE7B,MAAM,QAAQ,GAAiB,EAAE,CAAA;IACjC,IAAI,YAAY,GAAG,CAAC,CAAA;IACpB,IAAI,UAAU,GAAG,CAAC,CAAA;IAClB,IAAI,KAAK,GAAkB,IAAI,CAAA;IAC/B,IAAI,SAAS,GAAkB,IAAI,CAAA;IACnC,IAAI,OAAO,GAAkB,IAAI,CAAA;IAEjC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE;YAAE,SAAQ;QAC1B,UAAU,EAAE,CAAA;QAEZ,MAAM,MAAM,GAAG,SAAS,CAAC,IAAI,CAAC,CAAA;QAC9B,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,YAAY,EAAE,CAAA;YACd,SAAQ;QACV,CAAC;QAED,MAAM,CAAC,SAAS,KAAK,SAAS,CAAA;QAC9B,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;QAErB,SAAS;QACT,IAAI,MAAM,CAAC,SAAS,EAAE,CAAC;YACrB,IAAI,CAAC,SAAS;gBAAE,SAAS,GAAG,MAAM,CAAC,SAAS,CAAA;YAC5C,OAAO,GAAG,MAAM,CAAC,SAAS,CAAA;QAC5B,CAAC;QAED,mDAAmD;QACnD,IAAI,CAAC,KAAK,IAAI,MAAM,CAAC,WAAW,EAAE,CAAC;YACjC,MAAM,aAAa,GAAG,MAAM,CAAC,IAAI,KAAK,iBAAiB,CAAA;YACvD,MAAM,WAAW,GAAG,MAAM,CAAC,IAAI,KAAK,MAAM,CAAA;YAC1C,IAAI,aAAa,IAAI,WAAW,EAAE,CAAC;gBACjC,KAAK,GAAG,MAAM,CAAC,WAAW,CAAC,MAAM,GAAG,gBAAgB;oBAClD,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,EAAE,gBAAgB,CAAC,GAAG,GAAG;oBACrD,CAAC,CAAC,MAAM,CAAC,WAAW,CAAA;YACxB,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO;QACL,SAAS;QACT,KAAK,EAAE,KAAK,IAAI,SAAS;QACzB,QAAQ;QACR,SAAS;QACT,OAAO;QACP,YAAY;QACZ,UAAU;KACX,CAAA;AACH,CAAC"}
@@ -0,0 +1,8 @@
1
+ import type { ScannedProject, ScannedSubagent } from './types.js';
2
+ /** 將編碼後的資料夾名稱還原為可讀路徑(所有 - 替換為 /) */
3
+ export declare function decodeProjectPath(encoded: string): string;
4
+ /** 掃描 ~/.claude/projects/,回傳所有專案及其 JSONL 檔案 */
5
+ export declare function scanProjects(baseDir?: string): Promise<ScannedProject[]>;
6
+ /** 掃描 session 目錄下的 subagents/*.jsonl,回傳 SubagentFile 清單 */
7
+ export declare function scanSubagents(sessionDir: string, parentSessionId: string): Promise<ScannedSubagent[]>;
8
+ //# sourceMappingURL=scanner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scanner.d.ts","sourceRoot":"","sources":["../../src/core/scanner.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,cAAc,EAAkB,eAAe,EAAE,MAAM,YAAY,CAAA;AAIjF,oCAAoC;AACpC,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAEzD;AAED,+CAA+C;AAC/C,wBAAsB,YAAY,CAAC,OAAO,GAAE,MAAyB,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC,CA+DhG;AAED,2DAA2D;AAC3D,wBAAsB,aAAa,CAAC,UAAU,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC,CAmD3G"}
@@ -0,0 +1,123 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ import { readdir, stat, readFile } from 'node:fs/promises';
3
+ import path from 'node:path';
4
+ import os from 'node:os';
5
+ const DEFAULT_BASE_DIR = path.join(os.homedir(), '.claude', 'projects');
6
+ /** 將編碼後的資料夾名稱還原為可讀路徑(所有 - 替換為 /) */
7
+ export function decodeProjectPath(encoded) {
8
+ return encoded.replace(/-/g, '/');
9
+ }
10
+ /** 掃描 ~/.claude/projects/,回傳所有專案及其 JSONL 檔案 */
11
+ export async function scanProjects(baseDir = DEFAULT_BASE_DIR) {
12
+ let entries;
13
+ try {
14
+ entries = await readdir(baseDir);
15
+ }
16
+ catch {
17
+ // 目錄不存在或不可讀 → 回傳空陣列
18
+ return [];
19
+ }
20
+ const projects = [];
21
+ for (const entry of entries) {
22
+ // 專案目錄以 - 開頭(編碼路徑的首字元 / → -)
23
+ if (!entry.startsWith('-'))
24
+ continue;
25
+ const projectDir = path.join(baseDir, entry);
26
+ // 確認是目錄
27
+ let dirStat;
28
+ try {
29
+ dirStat = await stat(projectDir);
30
+ }
31
+ catch {
32
+ continue;
33
+ }
34
+ if (!dirStat.isDirectory())
35
+ continue;
36
+ // 列出根層級 *.jsonl(不遞迴進 subagents/)
37
+ let files;
38
+ try {
39
+ files = await readdir(projectDir);
40
+ }
41
+ catch {
42
+ continue;
43
+ }
44
+ const sessions = [];
45
+ for (const file of files) {
46
+ if (!file.endsWith('.jsonl'))
47
+ continue;
48
+ const filePath = path.join(projectDir, file);
49
+ let fileStat;
50
+ try {
51
+ fileStat = await stat(filePath);
52
+ }
53
+ catch {
54
+ continue;
55
+ }
56
+ if (!fileStat.isFile())
57
+ continue;
58
+ sessions.push({
59
+ filePath,
60
+ fileSize: fileStat.size,
61
+ fileMtime: fileStat.mtime.toISOString(),
62
+ sessionId: file.replace(/\.jsonl$/, ''),
63
+ });
64
+ }
65
+ projects.push({
66
+ projectId: entry,
67
+ displayName: decodeProjectPath(entry),
68
+ sessions,
69
+ });
70
+ }
71
+ return projects;
72
+ }
73
+ /** 掃描 session 目錄下的 subagents/*.jsonl,回傳 SubagentFile 清單 */
74
+ export async function scanSubagents(sessionDir, parentSessionId) {
75
+ const subagentsDir = path.join(sessionDir, 'subagents');
76
+ let entries;
77
+ try {
78
+ entries = await readdir(subagentsDir);
79
+ }
80
+ catch {
81
+ return [];
82
+ }
83
+ const results = [];
84
+ for (const entry of entries) {
85
+ if (!entry.endsWith('.jsonl'))
86
+ continue;
87
+ const filePath = path.join(subagentsDir, entry);
88
+ let fileStat;
89
+ try {
90
+ fileStat = await stat(filePath);
91
+ }
92
+ catch {
93
+ continue;
94
+ }
95
+ if (!fileStat.isFile())
96
+ continue;
97
+ const bareId = entry.replace(/\.jsonl$/, '');
98
+ const subagentId = `${parentSessionId}/${bareId}`;
99
+ // 嘗試讀取對應 meta.json
100
+ let agentType = null;
101
+ const metaPath = path.join(subagentsDir, `${bareId}.meta.json`);
102
+ try {
103
+ const metaRaw = await readFile(metaPath, 'utf-8');
104
+ const meta = JSON.parse(metaRaw);
105
+ if (typeof meta.agentType === 'string') {
106
+ agentType = meta.agentType;
107
+ }
108
+ }
109
+ catch {
110
+ // meta.json 不存在或 JSON 格式錯誤 → agentType 為 null
111
+ }
112
+ results.push({
113
+ filePath,
114
+ fileSize: fileStat.size,
115
+ fileMtime: fileStat.mtime.toISOString(),
116
+ subagentId,
117
+ parentSessionId,
118
+ agentType,
119
+ });
120
+ }
121
+ return results;
122
+ }
123
+ //# sourceMappingURL=scanner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scanner.js","sourceRoot":"","sources":["../../src/core/scanner.ts"],"names":[],"mappings":"AAAA,sCAAsC;AACtC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAA;AAC1D,OAAO,IAAI,MAAM,WAAW,CAAA;AAC5B,OAAO,EAAE,MAAM,SAAS,CAAA;AAGxB,MAAM,gBAAgB,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,UAAU,CAAC,CAAA;AAEvE,oCAAoC;AACpC,MAAM,UAAU,iBAAiB,CAAC,OAAe;IAC/C,OAAO,OAAO,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAA;AACnC,CAAC;AAED,+CAA+C;AAC/C,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,UAAkB,gBAAgB;IACnE,IAAI,OAAiB,CAAA;IACrB,IAAI,CAAC;QACH,OAAO,GAAG,MAAM,OAAO,CAAC,OAAO,CAAC,CAAA;IAClC,CAAC;IAAC,MAAM,CAAC;QACP,oBAAoB;QACpB,OAAO,EAAE,CAAA;IACX,CAAC;IAED,MAAM,QAAQ,GAAqB,EAAE,CAAA;IAErC,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,6BAA6B;QAC7B,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC;YAAE,SAAQ;QAEpC,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,KAAK,CAAC,CAAA;QAE5C,QAAQ;QACR,IAAI,OAAO,CAAA;QACX,IAAI,CAAC;YACH,OAAO,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,CAAA;QAClC,CAAC;QAAC,MAAM,CAAC;YACP,SAAQ;QACV,CAAC;QACD,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE;YAAE,SAAQ;QAEpC,iCAAiC;QACjC,IAAI,KAAe,CAAA;QACnB,IAAI,CAAC;YACH,KAAK,GAAG,MAAM,OAAO,CAAC,UAAU,CAAC,CAAA;QACnC,CAAC;QAAC,MAAM,CAAC;YACP,SAAQ;QACV,CAAC;QAED,MAAM,QAAQ,GAAqB,EAAE,CAAA;QACrC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC;gBAAE,SAAQ;YAEtC,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,CAAA;YAC5C,IAAI,QAAQ,CAAA;YACZ,IAAI,CAAC;gBACH,QAAQ,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,CAAA;YACjC,CAAC;YAAC,MAAM,CAAC;gBACP,SAAQ;YACV,CAAC;YACD,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE;gBAAE,SAAQ;YAEhC,QAAQ,CAAC,IAAI,CAAC;gBACZ,QAAQ;gBACR,QAAQ,EAAE,QAAQ,CAAC,IAAI;gBACvB,SAAS,EAAE,QAAQ,CAAC,KAAK,CAAC,WAAW,EAAE;gBACvC,SAAS,EAAE,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC;aACxC,CAAC,CAAA;QACJ,CAAC;QAED,QAAQ,CAAC,IAAI,CAAC;YACZ,SAAS,EAAE,KAAK;YAChB,WAAW,EAAE,iBAAiB,CAAC,KAAK,CAAC;YACrC,QAAQ;SACT,CAAC,CAAA;IACJ,CAAC;IAED,OAAO,QAAQ,CAAA;AACjB,CAAC;AAED,2DAA2D;AAC3D,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,UAAkB,EAAE,eAAuB;IAC7E,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,WAAW,CAAC,CAAA;IAEvD,IAAI,OAAiB,CAAA;IACrB,IAAI,CAAC;QACH,OAAO,GAAG,MAAM,OAAO,CAAC,YAAY,CAAC,CAAA;IACvC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAA;IACX,CAAC;IAED,MAAM,OAAO,GAAsB,EAAE,CAAA;IAErC,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,QAAQ,CAAC;YAAE,SAAQ;QAEvC,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,KAAK,CAAC,CAAA;QAC/C,IAAI,QAAQ,CAAA;QACZ,IAAI,CAAC;YACH,QAAQ,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,CAAA;QACjC,CAAC;QAAC,MAAM,CAAC;YACP,SAAQ;QACV,CAAC;QACD,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE;YAAE,SAAQ;QAEhC,MAAM,MAAM,GAAG,KAAK,CAAC,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAAA;QAC5C,MAAM,UAAU,GAAG,GAAG,eAAe,IAAI,MAAM,EAAE,CAAA;QAEjD,mBAAmB;QACnB,IAAI,SAAS,GAAkB,IAAI,CAAA;QACnC,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,GAAG,MAAM,YAAY,CAAC,CAAA;QAC/D,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAA;YACjD,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAA;YAChC,IAAI,OAAO,IAAI,CAAC,SAAS,KAAK,QAAQ,EAAE,CAAC;gBACvC,SAAS,GAAG,IAAI,CAAC,SAAS,CAAA;YAC5B,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,8CAA8C;QAChD,CAAC;QAED,OAAO,CAAC,IAAI,CAAC;YACX,QAAQ;YACR,QAAQ,EAAE,QAAQ,CAAC,IAAI;YACvB,SAAS,EAAE,QAAQ,CAAC,KAAK,CAAC,WAAW,EAAE;YACvC,UAAU;YACV,eAAe;YACf,SAAS;SACV,CAAC,CAAA;IACJ,CAAC;IAED,OAAO,OAAO,CAAA;AAChB,CAAC"}
@@ -0,0 +1,12 @@
1
+ import type { ParsedLine, SessionSummary, SessionFileInput } from './types.js';
2
+ /** 摘要引擎版本(每次規則改動時遞增,讓 backfill 可追蹤) */
3
+ export declare const SUMMARY_VERSION = 1;
4
+ /** 計算 active time:累加相鄰 message 間 ≤ 5 分鐘的間隔秒數 */
5
+ export declare function computeActiveTime(messages: ParsedLine[]): number | null;
6
+ export interface SummarizerResult {
7
+ summary: SessionSummary;
8
+ sessionFiles: SessionFileInput[];
9
+ }
10
+ /** 為一組 ParsedLine 產生結構化摘要 + session_files */
11
+ export declare function summarizeSession(messages: ParsedLine[], startedAt?: string | null, endedAt?: string | null): SummarizerResult;
12
+ //# sourceMappingURL=summarizer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"summarizer.d.ts","sourceRoot":"","sources":["../../src/core/summarizer.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,cAAc,EAAgD,gBAAgB,EAAE,MAAM,YAAY,CAAA;AAE5H,uCAAuC;AACvC,eAAO,MAAM,eAAe,IAAI,CAAA;AAqVhC,gDAAgD;AAChD,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,UAAU,EAAE,GAAG,MAAM,GAAG,IAAI,CAiBvE;AAID,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,cAAc,CAAA;IACvB,YAAY,EAAE,gBAAgB,EAAE,CAAA;CACjC;AAED,6CAA6C;AAC7C,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,UAAU,EAAE,EACtB,SAAS,GAAE,MAAM,GAAG,IAAW,EAC/B,OAAO,GAAE,MAAM,GAAG,IAAW,GAC5B,gBAAgB,CAkGlB"}