@yxzpro/agent-acta 2.14.4

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/LOGFORMATS.md +960 -0
  3. package/README.md +238 -0
  4. package/REFERENCE.md +1428 -0
  5. package/agent-acta-page.html +1998 -0
  6. package/agent-acta-server.mjs +1066 -0
  7. package/agent-acta-widget.html +724 -0
  8. package/archive.mjs +335 -0
  9. package/core/log.mjs +20 -0
  10. package/core/service.mjs +4285 -0
  11. package/hooks/cursor-usage-hook.mjs +89 -0
  12. package/mcp-server.mjs +372 -0
  13. package/package.json +68 -0
  14. package/page/dialog-add-agent.js +65 -0
  15. package/page/dialog-alert.js +159 -0
  16. package/page/dialog-archive.js +342 -0
  17. package/page/dialog-compare.js +238 -0
  18. package/page/dialog-ctxw.js +101 -0
  19. package/page/dialog-diag.js +72 -0
  20. package/page/dialog-heatmap.js +215 -0
  21. package/page/dialog-selftest.js +202 -0
  22. package/page/dialog-sess-timeline.js +108 -0
  23. package/page/dialog-stats.js +694 -0
  24. package/page/dialog-usage.js +158 -0
  25. package/page/log-card.js +277 -0
  26. package/page/log-view.js +273 -0
  27. package/page/sess-view.js +382 -0
  28. package/page/shared.js +408 -0
  29. package/page/sidebar.js +129 -0
  30. package/page/style.css +973 -0
  31. package/page/topbar.js +61 -0
  32. package/parsers/atomcode.mjs +321 -0
  33. package/parsers/buddy.mjs +272 -0
  34. package/parsers/buddyext.mjs +582 -0
  35. package/parsers/claude.mjs +496 -0
  36. package/parsers/cline.mjs +468 -0
  37. package/parsers/codearts.mjs +96 -0
  38. package/parsers/codex.mjs +188 -0
  39. package/parsers/comate.mjs +195 -0
  40. package/parsers/copilot.mjs +308 -0
  41. package/parsers/cursor.mjs +493 -0
  42. package/parsers/devindb.mjs +358 -0
  43. package/parsers/discovery.mjs +1230 -0
  44. package/parsers/doubao.mjs +406 -0
  45. package/parsers/dsh.mjs +377 -0
  46. package/parsers/gemini.mjs +267 -0
  47. package/parsers/generic.mjs +494 -0
  48. package/parsers/hermes.mjs +398 -0
  49. package/parsers/kilo.mjs +42 -0
  50. package/parsers/kimi.mjs +249 -0
  51. package/parsers/mimocode.mjs +531 -0
  52. package/parsers/minimax.mjs +503 -0
  53. package/parsers/openclaw.mjs +490 -0
  54. package/parsers/opencode.mjs +465 -0
  55. package/parsers/shared.mjs +418 -0
  56. package/parsers/trace.mjs +66 -0
  57. package/parsers/tracecode.mjs +348 -0
  58. package/parsers/traedb.mjs +528 -0
  59. package/parsers/zcode.mjs +356 -0
  60. package/plugin/client.js +51 -0
  61. package/plugin/cordis.patch.yml +5 -0
  62. package/plugin/plugin.mjs +220 -0
  63. package/search.mjs +554 -0
  64. package/tools/grab-trae-key.ps1 +265 -0
  65. package/vendor/element-plus-icons.js +3 -0
  66. package/vendor/element-plus.css +1 -0
  67. package/vendor/element-plus.dark.css +1 -0
  68. package/vendor/element-plus.full.min.js +65 -0
  69. package/vendor/element-plus.zh-cn.js +2 -0
  70. package/vendor/svg/antgroup-color.svg +1 -0
  71. package/vendor/svg/bytedance-color.svg +1 -0
  72. package/vendor/svg/chatglm-color.svg +1 -0
  73. package/vendor/svg/claude-color.svg +1 -0
  74. package/vendor/svg/claudecode-color.svg +1 -0
  75. package/vendor/svg/cline.svg +1 -0
  76. package/vendor/svg/codebuddy-color.svg +1 -0
  77. package/vendor/svg/codebuddy.svg +1 -0
  78. package/vendor/svg/codex-color.svg +1 -0
  79. package/vendor/svg/copilot.svg +1 -0
  80. package/vendor/svg/cursor.svg +1 -0
  81. package/vendor/svg/deepseek-color.svg +1 -0
  82. package/vendor/svg/deepseek-harness-whale.svg +8 -0
  83. package/vendor/svg/doubao-color.svg +1 -0
  84. package/vendor/svg/gemini-color.svg +1 -0
  85. package/vendor/svg/glmv-color.svg +1 -0
  86. package/vendor/svg/grok.svg +1 -0
  87. package/vendor/svg/hermesagent.svg +1 -0
  88. package/vendor/svg/huawei-color.svg +1 -0
  89. package/vendor/svg/hunyuan-color.svg +1 -0
  90. package/vendor/svg/kilocode-avatar.svg +1 -0
  91. package/vendor/svg/kilocode.svg +1 -0
  92. package/vendor/svg/kimi-color.svg +1 -0
  93. package/vendor/svg/kimi.svg +1 -0
  94. package/vendor/svg/logo-AtomGit-G-red.svg +3 -0
  95. package/vendor/svg/logo-AtomGit-dark.svg +4 -0
  96. package/vendor/svg/logo-AtomGit-light.svg +4 -0
  97. package/vendor/svg/meta-color.svg +1 -0
  98. package/vendor/svg/mimo.svg +66 -0
  99. package/vendor/svg/minimax-code-logo.svg +8 -0
  100. package/vendor/svg/minimax-color.svg +1 -0
  101. package/vendor/svg/moonshot.svg +1 -0
  102. package/vendor/svg/nex-color.svg +1 -0
  103. package/vendor/svg/nex.svg +1 -0
  104. package/vendor/svg/nvidia-color.svg +1 -0
  105. package/vendor/svg/openai.svg +1 -0
  106. package/vendor/svg/openclaw-color.svg +1 -0
  107. package/vendor/svg/openclaw.svg +1 -0
  108. package/vendor/svg/opencode.svg +1 -0
  109. package/vendor/svg/openrouter-color.svg +1 -0
  110. package/vendor/svg/qoder-color.svg +1 -0
  111. package/vendor/svg/qwen-color.svg +1 -0
  112. package/vendor/svg/sensenova-color.svg +1 -0
  113. package/vendor/svg/stepfun.svg +1 -0
  114. package/vendor/svg/trae-color.svg +1 -0
  115. package/vendor/svg/traework-v2.svg +1 -0
  116. package/vendor/svg/wenxin-color.svg +1 -0
  117. package/vendor/svg/windsurf.svg +1 -0
  118. package/vendor/svg/workbuddy-color.svg +29 -0
  119. package/vendor/svg/xiaomimimo.svg +1 -0
  120. package/vendor/svg/yuanbao-color.svg +1 -0
  121. package/vendor/svg/yuanbao.svg +1 -0
  122. package/vendor/svg/zai.svg +1 -0
  123. package/vendor/svg/zhipu-color.svg +1 -0
  124. package/vendor/vue.global.prod.js +9 -0
  125. package/widget/main.js +202 -0
  126. package/widget/package.json +7 -0
  127. package/widget/preload.js +11 -0
@@ -0,0 +1,308 @@
1
+ // ---------------- GitHub Copilot CLI 解析器(~/.copilot/session-state/*/events.jsonl) ----------------
2
+ // 正文/事件来自每个 session 的 events.jsonl;逐次用量来自同根 session-store.db 的
3
+ // assistant_usage_events(SQLite WAL 也由 node:sqlite 自动读到)。
4
+ import fs from 'node:fs';
5
+ import path from 'node:path';
6
+ import {
7
+ files, entries, srcs, removedIds, sorted, addEntry, markKind,
8
+ toolNameCounts, modelName, toText, sqliteMod,
9
+ } from './shared.mjs';
10
+ import { copilotSessionFiles } from './discovery.mjs';
11
+
12
+ export const copilotScanErr = new Map();
13
+
14
+ // I8 复现包原始片段提取复用:copilot 的 `user.message` 行即开轮(扫描侧不跳过空/命令,这里同口径)。
15
+ export function copilotTurnStart(j) { return j.type === 'user.message'; }
16
+
17
+ function ts(v) {
18
+ if (typeof v === 'number' && Number.isFinite(v)) return v;
19
+ if (typeof v === 'string') {
20
+ const raw = v.trim();
21
+ const normalized = /^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}(?:\.\d+)?$/.test(raw)
22
+ ? raw.replace(' ', 'T') + 'Z' : raw;
23
+ const n = Date.parse(normalized);
24
+ return Number.isFinite(n) ? n : 0;
25
+ }
26
+ return 0;
27
+ }
28
+
29
+ function safeJson(s) {
30
+ try { return JSON.parse(s); } catch { return null; }
31
+ }
32
+
33
+ function sessionIdOf(fp) {
34
+ return path.basename(path.dirname(fp));
35
+ }
36
+
37
+ function sourceKey(fp) { return fp; }
38
+ function idBase(fp) { return 'p#' + fp.replace(/[\\/:]/g, '~') + '#'; }
39
+
40
+ function readWorkspace(sessionDir) {
41
+ const out = {};
42
+ try {
43
+ const text = fs.readFileSync(path.join(sessionDir, 'workspace.yaml'), 'utf8');
44
+ for (const line of text.split(/\r?\n/)) {
45
+ const m = /^(cwd|name):\s*(.*?)\s*$/.exec(line);
46
+ if (m) out[m[1]] = m[2].replace(/^['"]|['"]$/g, '');
47
+ }
48
+ } catch {}
49
+ return out;
50
+ }
51
+
52
+ function turnOf(turns, byKey, key, t) {
53
+ const k = key == null || key === '' ? '0' : String(key);
54
+ let turn = byKey.get(k);
55
+ if (!turn) {
56
+ turn = {
57
+ key: k, time: t || 0, lastTs: t || 0, endTs: 0,
58
+ user: '', texts: [], tools: [], callList: [], models: [],
59
+ events: [], others: [], err: false, errMsg: '', finished: false, aborted: false,
60
+ };
61
+ byKey.set(k, turn);
62
+ turns.push(turn);
63
+ }
64
+ if (t) {
65
+ turn.time = turn.time ? Math.min(turn.time, t) : t;
66
+ turn.lastTs = Math.max(turn.lastTs, t);
67
+ }
68
+ return turn;
69
+ }
70
+
71
+ function toolName(req) {
72
+ return String(req?.name || req?.toolName || req?.tool || req?.function?.name || '?');
73
+ }
74
+
75
+ function toolInput(req) {
76
+ return req?.arguments ?? req?.input ?? req?.parameters ?? req?.function?.arguments ?? '';
77
+ }
78
+
79
+ function addTool(turn, req, t, output = '', error = null) {
80
+ const tid = req?.id || req?.callId || req?.call_id || req?.toolCallId || req?.tool_call_id || null;
81
+ let tool = tid ? turn.tools.find(x => x.tid === tid) : null;
82
+ if (!tool) {
83
+ tool = { name: toolName(req), tid, ct: t || turn.time, input: toolInput(req), output, error, dur: 0 };
84
+ turn.tools.push(tool);
85
+ } else {
86
+ if (output !== '') tool.output = output;
87
+ if (error) tool.error = error;
88
+ }
89
+ return tool;
90
+ }
91
+
92
+ function readUsage(root) {
93
+ const dbPath = path.join(path.basename(root).toLowerCase() === 'session-state' ? path.dirname(root) : root, 'session-store.db');
94
+ let dbSt = null, walSt = null;
95
+ try { dbSt = fs.statSync(dbPath); } catch {}
96
+ try { walSt = fs.statSync(dbPath + '-wal'); } catch {}
97
+ const sig = dbSt
98
+ ? dbSt.mtimeMs + '|' + dbSt.size + '|' + (walSt ? walSt.mtimeMs + '|' + walSt.size : '-')
99
+ : '-';
100
+ if (!dbSt) return { byKey: new Map(), path: dbPath, sig, error: null };
101
+ const mod = sqliteMod();
102
+ if (!mod) return { byKey: new Map(), path: dbPath, sig, error: '当前 Node 没有 node:sqlite(需要 22.5+)' };
103
+ let db = null;
104
+ try {
105
+ db = new mod.DatabaseSync(dbPath, { readOnly: true });
106
+ const rows = db.prepare(`SELECT session_id, turn_index, agent_id, model, input_tokens, output_tokens,
107
+ cache_read_tokens, cache_write_tokens, reasoning_tokens, duration_ms,
108
+ time_to_first_token_ms, finish_reason, created_at
109
+ FROM assistant_usage_events ORDER BY session_id, id`).all();
110
+ const byKey = new Map();
111
+ for (const r of rows) {
112
+ const key = String(r.session_id || '') + '|' + String(r.turn_index == null ? '' : r.turn_index);
113
+ if (!byKey.has(key)) byKey.set(key, []);
114
+ byKey.get(key).push(r);
115
+ }
116
+ return { byKey, path: dbPath, error: null, sig };
117
+ } catch (e) {
118
+ return { byKey: new Map(), path: dbPath, error: e.message, sig };
119
+ } finally {
120
+ try { db && db.close(); } catch {}
121
+ }
122
+ }
123
+
124
+ function parseEvents(fp, usageByKey) {
125
+ const raw = fs.readFileSync(fp, 'utf8');
126
+ const complete = raw.endsWith('\n') ? raw : raw.slice(0, raw.lastIndexOf('\n') + 1);
127
+ const sessionId = sessionIdOf(fp);
128
+ const sessionDir = path.dirname(fp);
129
+ const ws = readWorkspace(sessionDir);
130
+ const turns = [], byKey = new Map();
131
+ let cwd = ws.cwd || '';
132
+ let sessionName = ws.name || null;
133
+ let sessionStart = 0;
134
+ for (const line of complete.split(/\r?\n/)) {
135
+ if (!line.trim()) continue;
136
+ const j = safeJson(line);
137
+ if (!j) continue;
138
+ const d = j.data || {};
139
+ const t = ts(j.timestamp || d.timestamp || d.startTime || d.completedAt);
140
+ if (j.type === 'session.start') {
141
+ sessionStart = t || sessionStart;
142
+ cwd = d.context?.cwd || cwd;
143
+ continue;
144
+ }
145
+ if (j.type === 'user.message') {
146
+ const turn = turnOf(turns, byKey, d.turnId, t);
147
+ const text = toText(d.content);
148
+ if (text && !turn.user) turn.user = text;
149
+ if (t) turn.events.push({ k: 'user', t });
150
+ continue;
151
+ }
152
+ if (j.type === 'assistant.message') {
153
+ const turn = turnOf(turns, byKey, d.turnId, t);
154
+ const text = toText(d.content);
155
+ if (text) turn.texts.push(text);
156
+ const mdl = modelName(d.model);
157
+ if (mdl && !turn.models.includes(mdl)) turn.models.push(mdl);
158
+ for (const req of Array.isArray(d.toolRequests) ? d.toolRequests : []) addTool(turn, req, t);
159
+ if (d.phase === 'error' || d.error) {
160
+ turn.err = true;
161
+ turn.errMsg = turn.errMsg || toText(d.error || d.content);
162
+ }
163
+ if (t) turn.events.push({ k: 'llm', t, model: mdl || '', blocks: text ? ['text'] : [] });
164
+ continue;
165
+ }
166
+ if (j.type === 'assistant.turn_end') {
167
+ const turn = turnOf(turns, byKey, d.turnId, t);
168
+ turn.finished = true;
169
+ turn.endTs = Math.max(turn.endTs, t || 0);
170
+ if (t) turn.lastTs = Math.max(turn.lastTs, t);
171
+ continue;
172
+ }
173
+ if (j.type === 'hook.start' && d.hookType === 'agentStop') {
174
+ const turn = turnOf(turns, byKey, d.input?.turnId, t);
175
+ if (d.input?.stopReason && d.input.stopReason !== 'end_turn') {
176
+ turn.aborted = true;
177
+ turn.err = true;
178
+ turn.errMsg = turn.errMsg || String(d.input.stopReason);
179
+ }
180
+ continue;
181
+ }
182
+ const type = String(j.type || '').toLowerCase();
183
+ if (type.includes('tool')) {
184
+ const payload = d.tool || d;
185
+ const turn = turnOf(turns, byKey, d.turnId ?? payload.turnId, t);
186
+ const isResult = type.includes('result') || type.includes('end') || type.includes('complete');
187
+ const tool = addTool(turn, payload, t, isResult ? (payload.output ?? payload.result ?? '') : '', payload.error || (payload.isError ? 'error' : null));
188
+ if (isResult && tool.ct && t) tool.dur = Math.max(0, t - tool.ct);
189
+ continue;
190
+ }
191
+ if (j.type === 'session.end' || j.type === 'session.stop') {
192
+ for (const turn of turns) {
193
+ if (!turn.finished) { turn.finished = true; turn.endTs = Math.max(turn.endTs, t || 0); }
194
+ }
195
+ }
196
+ }
197
+
198
+ for (let i = 0; i < turns.length; i++) {
199
+ const turn = turns[i];
200
+ const rows = usageByKey.get(sessionId + '|' + turn.key) || [];
201
+ for (const r of rows) {
202
+ const mdl = modelName(r.model);
203
+ const cache = (r.cache_read_tokens || 0) + (r.cache_write_tokens || 0);
204
+ const call = {
205
+ model: mdl || '(未知模型)',
206
+ tin: r.input_tokens || 0,
207
+ tout: (r.output_tokens || 0) + (r.reasoning_tokens || 0),
208
+ tcache: cache,
209
+ dur: r.duration_ms || 0,
210
+ ttft: r.time_to_first_token_ms || 0,
211
+ };
212
+ if (r.finish_reason && r.finish_reason !== 'stop') call.finishReason = r.finish_reason;
213
+ turn.callList.push(call);
214
+ if (mdl && !turn.models.includes(mdl)) turn.models.push(mdl);
215
+ turn.tin = (turn.tin || 0) + call.tin;
216
+ turn.tout = (turn.tout || 0) + call.tout;
217
+ turn.tcache = (turn.tcache || 0) + call.tcache;
218
+ if (r.created_at) {
219
+ const ct = ts(r.created_at);
220
+ if (ct) turn.time = turn.time ? Math.min(turn.time, ct) : ct;
221
+ }
222
+ if (call.dur && turn.time) turn.lastTs = Math.max(turn.lastTs, turn.time + call.dur);
223
+ if (r.finish_reason && r.finish_reason !== 'stop') turn.err = true;
224
+ }
225
+ if (!turn.callList.length && turn.models.length) {
226
+ turn.callList.push({ model: turn.models[0], tin: 0, tout: 0, tcache: 0, dur: 0 });
227
+ }
228
+ turn.endTs = Math.max(turn.endTs, turn.lastTs, turn.time);
229
+ turn.preview = (turn.user || turn.texts.join('\n\n---\n\n') || turn.errMsg || '').replace(/\s+/g, ' ').slice(0, 300);
230
+ turn.events.push({ k: 'end', t: turn.endTs, reason: turn.err ? 'error' : 'completed' });
231
+ turn.events.sort((a, b) => (a.t || 0) - (b.t || 0));
232
+ }
233
+ return { sessionId, cwd, sessionName, sessionStart, turns, consumed: Buffer.byteLength(complete) };
234
+ }
235
+
236
+ function emit(agent, fp, data, prevData) {
237
+ const base = idBase(fp);
238
+ const ids = new Set();
239
+ data.turns.forEach((t, i) => {
240
+ const id = base + data.sessionId + '#' + t.key;
241
+ ids.add(id);
242
+ addEntry(id, {
243
+ agent, project: data.cwd || '(未知项目)', session: data.sessionId,
244
+ time: t.time || data.sessionStart || 0,
245
+ dur: Math.max(0, (t.endTs || t.lastTs || t.time) - (t.time || data.sessionStart || 0)),
246
+ status: t.err ? 'error' : 'ok',
247
+ tin: t.tin || 0, tout: t.tout || 0, tcache: t.tcache || 0,
248
+ total: (t.tin || 0) + (t.tout || 0) + (t.tcache || 0),
249
+ ctx: 0, ctxUsed: (t.tin || 0) + (t.tcache || 0),
250
+ rounds: t.callList.length, calls: t.callList.length, tools: t.tools.length,
251
+ models: t.models, preview: t.preview, name: data.sessionName || null,
252
+ finished: !!t.finished || i < data.turns.length - 1, aborted: !!t.aborted,
253
+ toolNames: toolNameCounts(t.tools),
254
+ }, { file: fp, turn: i, kind: 'copilot' });
255
+ });
256
+ for (const old of prevData?.ids || []) {
257
+ if (ids.has(old)) continue;
258
+ entries.delete(old); srcs.delete(old); removedIds.push(old);
259
+ }
260
+ data.ids = [...ids];
261
+ sorted.cache = null;
262
+ }
263
+
264
+ export function scanCopilotFile(agent, fp, root, usageByKey, usageSig = '-') {
265
+ let st;
266
+ try { st = fs.statSync(fp); } catch { return; }
267
+ const sig = st.mtimeMs + '|' + st.size + '|u:' + usageSig;
268
+ const prev = files.get(sourceKey(fp));
269
+ if (prev && prev.data?.sig === sig) {
270
+ const last = prev.data.turns?.[prev.data.turns.length - 1];
271
+ if (last && !entries.has(idBase(fp) + prev.data.sessionId + '#' + last.key)) emit(agent, fp, prev.data, null);
272
+ return;
273
+ }
274
+ try {
275
+ const data = parseEvents(fp, usageByKey);
276
+ data.sig = sig;
277
+ data.rev = (prev?.data?.rev || 0) + 1;
278
+ files.set(sourceKey(fp), { agent, kind: 'copilot', m: st.mtimeMs, s: st.size, off: data.consumed, data });
279
+ copilotScanErr.delete(agent);
280
+ markKind('copilot');
281
+ emit(agent, fp, data, prev?.data);
282
+ } catch (e) {
283
+ console.error('[copilot]', e.message);
284
+ copilotScanErr.set(agent, e.message);
285
+ }
286
+ }
287
+
288
+ export function scanCopilot(agent, root) {
289
+ const usage = readUsage(root);
290
+ if (usage.error) copilotScanErr.set(agent, '用量库读取失败:' + usage.error);
291
+ const list = copilotSessionFiles(root);
292
+ const seen = new Set(list.map(x => x.fp));
293
+ for (const x of list) {
294
+ try { scanCopilotFile(agent, x.fp, root, usage.byKey, usage.sig); }
295
+ catch (e) { copilotScanErr.set(agent, e.message); }
296
+ }
297
+ if (usage.error) copilotScanErr.set(agent, '用量库读取失败:' + usage.error);
298
+ for (const [fp, f] of [...files]) {
299
+ if (f.agent !== agent || f.kind !== 'copilot' || seen.has(fp)) continue;
300
+ for (const [id, e] of [...entries]) {
301
+ if (e.agent === agent && srcs.get(id)?.file === fp) { entries.delete(id); srcs.delete(id); removedIds.push(id); }
302
+ }
303
+ files.delete(fp);
304
+ }
305
+ sorted.cache = null;
306
+ }
307
+
308
+ export function copilotIdBase(fp) { return idBase(fp); }