webtape 1.7.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 (48) hide show
  1. package/README.md +99 -0
  2. package/dist/analyzer.d.ts +27 -0
  3. package/dist/analyzer.d.ts.map +1 -0
  4. package/dist/analyzer.js +128 -0
  5. package/dist/analyzer.js.map +1 -0
  6. package/dist/config.d.ts +36 -0
  7. package/dist/config.d.ts.map +1 -0
  8. package/dist/config.js +158 -0
  9. package/dist/config.js.map +1 -0
  10. package/dist/context.d.ts +4 -0
  11. package/dist/context.d.ts.map +1 -0
  12. package/dist/context.js +276 -0
  13. package/dist/context.js.map +1 -0
  14. package/dist/index.d.ts +3 -0
  15. package/dist/index.d.ts.map +1 -0
  16. package/dist/index.js +326 -0
  17. package/dist/index.js.map +1 -0
  18. package/dist/install.d.ts +17 -0
  19. package/dist/install.d.ts.map +1 -0
  20. package/dist/install.js +235 -0
  21. package/dist/install.js.map +1 -0
  22. package/dist/native-host.d.ts +15 -0
  23. package/dist/native-host.d.ts.map +1 -0
  24. package/dist/native-host.js +129 -0
  25. package/dist/native-host.js.map +1 -0
  26. package/dist/rules.d.ts +59 -0
  27. package/dist/rules.d.ts.map +1 -0
  28. package/dist/rules.js +115 -0
  29. package/dist/rules.js.map +1 -0
  30. package/dist/server.d.ts +32 -0
  31. package/dist/server.d.ts.map +1 -0
  32. package/dist/server.js +122 -0
  33. package/dist/server.js.map +1 -0
  34. package/dist/storage.d.ts +48 -0
  35. package/dist/storage.d.ts.map +1 -0
  36. package/dist/storage.js +271 -0
  37. package/dist/storage.js.map +1 -0
  38. package/dist/templates/context.md.ejs +79 -0
  39. package/dist/types.d.ts +103 -0
  40. package/dist/types.d.ts.map +1 -0
  41. package/dist/types.js +2 -0
  42. package/dist/types.js.map +1 -0
  43. package/dist/workspace.d.ts +15 -0
  44. package/dist/workspace.d.ts.map +1 -0
  45. package/dist/workspace.js +128 -0
  46. package/dist/workspace.js.map +1 -0
  47. package/dist/workspace.zip +0 -0
  48. package/package.json +52 -0
@@ -0,0 +1,276 @@
1
+ import { readFileSync } from 'node:fs';
2
+ import { join, dirname } from 'node:path';
3
+ import { fileURLToPath } from 'node:url';
4
+ import ejs from 'ejs';
5
+ import { isNoiseHeader, SENSITIVE_HEADER_RULES, HEADER_VALUE_MAX_LENGTH, BODY_FULL_LIMIT, BODY_OVERSIZE_HINT_LT_LARGE, BODY_OVERSIZE_HINT_LT_HUGE, isAllowedProtocol, STRIP_FIRST_CLICK, } from './rules.js';
6
+ const __dirname = dirname(fileURLToPath(import.meta.url));
7
+ const TEMPLATE_PATH = join(__dirname, 'templates', 'context.md.ejs');
8
+ let cachedTemplate = null;
9
+ function loadTemplate() {
10
+ if (!cachedTemplate) {
11
+ cachedTemplate = readFileSync(TEMPLATE_PATH, 'utf-8');
12
+ }
13
+ return cachedTemplate;
14
+ }
15
+ function renderHeaders(headers, role) {
16
+ if (!headers)
17
+ return null;
18
+ const lines = [];
19
+ for (const [key, value] of Object.entries(headers)) {
20
+ if (isNoiseHeader(key, role))
21
+ continue;
22
+ const lower = key.toLowerCase();
23
+ const sensitiveRule = SENSITIVE_HEADER_RULES[lower];
24
+ if (sensitiveRule === 'cookie_names') {
25
+ const names = value.split(';').map((p) => p.trim().split('=')[0]).filter(Boolean);
26
+ lines.push(`${key}: [${names.length} cookies: ${names.join(', ')}]`);
27
+ }
28
+ else if (sensitiveRule === 'presence_only') {
29
+ lines.push(`${key}: [${lower} present]`);
30
+ }
31
+ else {
32
+ lines.push(`${key}: ${value.length > HEADER_VALUE_MAX_LENGTH ? value.slice(0, HEADER_VALUE_MAX_LENGTH) + '…' : value}`);
33
+ }
34
+ }
35
+ return lines.length > 0 ? lines.join('\n') : null;
36
+ }
37
+ function bodyOversizeHint(byteSize, role) {
38
+ const noun = role === 'request' ? '请求' : '响应';
39
+ if (byteSize < BODY_OVERSIZE_HINT_LT_LARGE) {
40
+ return `请查看原始${noun}记录`;
41
+ }
42
+ if (byteSize < BODY_OVERSIZE_HINT_LT_HUGE) {
43
+ return `${noun}体较大,请小心查看原始记录分析`;
44
+ }
45
+ return `${noun}体过大,疑似包含大文件 base64 等情况,请审慎阅读`;
46
+ }
47
+ function renderBody(body) {
48
+ if (body == null)
49
+ return null;
50
+ let text;
51
+ let lang = '';
52
+ if (typeof body === 'string') {
53
+ text = body;
54
+ if (text.trimStart().startsWith('{') || text.trimStart().startsWith('[')) {
55
+ try {
56
+ text = JSON.stringify(JSON.parse(text), null, 2);
57
+ lang = 'json';
58
+ }
59
+ catch { /* not JSON */ }
60
+ }
61
+ }
62
+ else {
63
+ text = JSON.stringify(body, null, 2);
64
+ lang = 'json';
65
+ }
66
+ const byteSize = Buffer.byteLength(text, 'utf-8');
67
+ if (text.length <= BODY_FULL_LIMIT) {
68
+ return { mode: 'full', text, lang, byteSize };
69
+ }
70
+ return { mode: 'oversize', byteSize, hint: bodyOversizeHint(byteSize, 'response') };
71
+ }
72
+ function fmtBytes(bytes) {
73
+ if (bytes < 1024)
74
+ return `${bytes}B`;
75
+ if (bytes < 1024 * 1024)
76
+ return `${(bytes / 1024).toFixed(1)}KB`;
77
+ return `${(bytes / (1024 * 1024)).toFixed(1)}MB`;
78
+ }
79
+ function getContentType(headers) {
80
+ if (!headers)
81
+ return null;
82
+ for (const [key, value] of Object.entries(headers)) {
83
+ if (key.toLowerCase() === 'content-type')
84
+ return value.split(';')[0].trim();
85
+ }
86
+ return null;
87
+ }
88
+ /**
89
+ * Render request body info for the network entry summary.
90
+ * - 不超过 BODY_FULL_LIMIT:完整展示(JSON 或纯文本)
91
+ * - 超过阈值:仅类型与大小 + 按体积分级的提示(不写入正文)
92
+ */
93
+ function renderRequestBody(body, headers) {
94
+ if (body == null)
95
+ return null;
96
+ if (typeof body === 'string' && body.length === 0)
97
+ return null;
98
+ const lines = [];
99
+ const contentType = getContentType(headers);
100
+ let raw;
101
+ let isJson = false;
102
+ if (typeof body === 'string') {
103
+ raw = body;
104
+ if (raw.trimStart().startsWith('{') || raw.trimStart().startsWith('[')) {
105
+ try {
106
+ raw = JSON.stringify(JSON.parse(raw), null, 2);
107
+ isJson = true;
108
+ }
109
+ catch { /* not JSON */ }
110
+ }
111
+ }
112
+ else {
113
+ raw = JSON.stringify(body, null, 2);
114
+ isJson = true;
115
+ }
116
+ const byteSize = Buffer.byteLength(raw, 'utf-8');
117
+ const typePart = contentType ?? (isJson ? 'application/json' : 'text/plain');
118
+ const meta = `${typePart}, ${fmtBytes(byteSize)}`;
119
+ if (raw.length <= BODY_FULL_LIMIT) {
120
+ lines.push(`入参 (${meta}):`);
121
+ lines.push('```' + (isJson ? 'json' : ''));
122
+ lines.push(raw);
123
+ lines.push('```');
124
+ }
125
+ else {
126
+ lines.push(`入参: ${meta}`);
127
+ lines.push(bodyOversizeHint(byteSize, 'request'));
128
+ }
129
+ return lines;
130
+ }
131
+ // ---------------------------------------------------------------------------
132
+ // Template helpers (passed to EJS as locals)
133
+ // ---------------------------------------------------------------------------
134
+ function describeBlock(block) {
135
+ if (block.state) {
136
+ const label = block.state.title || block.state.url;
137
+ if (block.state.type === 'URL_CHANGE') {
138
+ return `URL 变更: ${label}`;
139
+ }
140
+ return `初始页面: ${label}`;
141
+ }
142
+ if (block.action) {
143
+ const tag = block.action.tag || '';
144
+ const label = block.action.aria_label || block.action.id || block.action.target_element || '';
145
+ return `用户操作: ${block.action.type} ${tag}${label ? ' "' + label + '"' : ''}`;
146
+ }
147
+ return `上下文 ${block.context_id}`;
148
+ }
149
+ /**
150
+ * Filter and sort timeline blocks.
151
+ * 1. (STRIP_FIRST_CLICK) Remove the first block if it's a CLICK action (often a mis-capture during recording start).
152
+ * 2. Ensure blocks are sorted by timestamp.
153
+ * 3. Filter out network requests with disallowed protocols (http, ws).
154
+ */
155
+ function processTimeline(timeline) {
156
+ if (timeline.length === 0)
157
+ return [];
158
+ const sorted = [...timeline].sort((a, b) => a.timestamp - b.timestamp);
159
+ let result = sorted;
160
+ if (STRIP_FIRST_CLICK && sorted[0].action?.type === 'CLICK') {
161
+ result = sorted.slice(1);
162
+ }
163
+ return result.map((block) => ({
164
+ ...block,
165
+ triggered_network: block.triggered_network
166
+ ? block.triggered_network.filter((net) => isAllowedProtocol(net.url))
167
+ : block.triggered_network,
168
+ }));
169
+ }
170
+ /**
171
+ * Render a single network request entry as a markdown block.
172
+ * Kept as a helper so the EJS template stays focused on document structure.
173
+ */
174
+ function makeNetworkEntryRenderer(requests, responses) {
175
+ return (net) => {
176
+ const lines = [];
177
+ const reqKey = net.detail_path.request.replace(/^requests\//, '');
178
+ const resKey = net.detail_path.response.replace(/^responses\//, '');
179
+ const reqData = requests[reqKey] ??
180
+ requests[`${net.req_id}.json`] ??
181
+ requests[`${net.req_id}_body.json`];
182
+ const resData = responses[resKey] ??
183
+ responses[`${net.req_id.replace(/^req_/, 'res_')}.json`] ??
184
+ responses[`${net.req_id}_res.json`];
185
+ const sizeHint = net.response_body_bytes != null ? ` (${fmtBytes(net.response_body_bytes)})` : '';
186
+ lines.push(`#### [${net.req_id}] ${net.method} ${net.url} → ${net.status ?? '?'}${sizeHint}`);
187
+ lines.push('');
188
+ if (reqData) {
189
+ const hdr = renderHeaders(reqData.headers, 'request');
190
+ if (hdr) {
191
+ lines.push('请求头:');
192
+ lines.push('```');
193
+ lines.push(hdr);
194
+ lines.push('```');
195
+ }
196
+ const reqBody = renderRequestBody(reqData.body, reqData.headers);
197
+ if (reqBody)
198
+ lines.push(...reqBody);
199
+ }
200
+ if (resData) {
201
+ const body = renderBody(resData.body);
202
+ if (body) {
203
+ if (body.mode === 'full') {
204
+ lines.push('响应体:');
205
+ lines.push('```' + body.lang);
206
+ lines.push(body.text);
207
+ lines.push('```');
208
+ }
209
+ else {
210
+ // 与标题行一致:扩展在 timeline 里用紧凑 JSON 统计 response_body_bytes;
211
+ // renderBody 用 pretty JSON 估体积会偏大,优先展示录制时的字节数。
212
+ const displayBytes = net.response_body_bytes ?? body.byteSize;
213
+ lines.push(`响应体 (${fmtBytes(displayBytes)}):`);
214
+ lines.push('');
215
+ lines.push(body.hint);
216
+ }
217
+ }
218
+ }
219
+ return lines.join('\n');
220
+ };
221
+ }
222
+ function collectOrphanRequests(payload, processedTimeline) {
223
+ const referenced = new Set();
224
+ for (const block of processedTimeline) {
225
+ if (block.triggered_network) {
226
+ for (const net of block.triggered_network)
227
+ referenced.add(net.req_id);
228
+ }
229
+ }
230
+ const orphans = [];
231
+ for (const key of Object.keys(payload.content.requests)) {
232
+ const reqId = key.endsWith('_body.json')
233
+ ? key.slice(0, -'_body.json'.length)
234
+ : key.slice(0, -'.json'.length);
235
+ if (referenced.has(reqId))
236
+ continue;
237
+ const reqData = payload.content.requests[key];
238
+ const resStem = reqId.replace(/^req_/, 'res_');
239
+ const resData = payload.content.responses[`${resStem}.json`] ??
240
+ payload.content.responses[`${reqId}_res.json`];
241
+ if (!reqData || !isAllowedProtocol(reqData.url))
242
+ continue;
243
+ let sizeHint = '';
244
+ if (resData?.body != null) {
245
+ const raw = typeof resData.body === 'string' ? resData.body : JSON.stringify(resData.body);
246
+ sizeHint = ` (${fmtBytes(Buffer.byteLength(raw, 'utf-8'))})`;
247
+ }
248
+ orphans.push({ id: reqId, method: reqData.method, url: reqData.url, status: resData?.status ?? '?', sizeHint });
249
+ }
250
+ return orphans;
251
+ }
252
+ // ---------------------------------------------------------------------------
253
+ // Public API
254
+ // ---------------------------------------------------------------------------
255
+ export function extractSiteUrl(payload) {
256
+ for (const block of payload.content['index.json']) {
257
+ if (block.state?.url)
258
+ return block.state.url;
259
+ }
260
+ return '';
261
+ }
262
+ export function renderAnalysisContext(payload, siteUrl) {
263
+ const { requests, responses, snapshots = {} } = payload.content;
264
+ const timeline = processTimeline(payload.content['index.json']);
265
+ return ejs.render(loadTemplate(), {
266
+ meta: payload.meta,
267
+ siteUrl,
268
+ timeline,
269
+ snapshots,
270
+ requestCount: Object.keys(requests).length,
271
+ orphanRequests: collectOrphanRequests(payload, timeline),
272
+ describeBlock,
273
+ renderNetworkEntry: makeNetworkEntryRenderer(requests, responses),
274
+ });
275
+ }
276
+ //# sourceMappingURL=context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context.js","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"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"}
@@ -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,326 @@
1
+ #!/usr/bin/env node
2
+ import { join } from 'node:path';
3
+ import { Command } from 'commander';
4
+ import chalk from 'chalk';
5
+ import ora from 'ora';
6
+ import { resolveWorkspaceRoot, ensureWorkspace } from './workspace.js';
7
+ import { createWebhookServer } from './server.js';
8
+ import { listRecordings, listUnanalyzedRecordings, parseSessionName, formatTime } from './storage.js';
9
+ import { analyzeRecording } from './analyzer.js';
10
+ import { loadConfig, promptAiBackend, runConfigWizard } from './config.js';
11
+ import { runInstall } from './install.js';
12
+ import { runNativeHost, runDetachedAnalysis } from './native-host.js';
13
+ const VERSION = '1.7.0';
14
+ // ─── Native Messaging host mode ──────────────────────────────────────────────
15
+ // When Chrome spawns us as a Native Messaging host, stdin is not a TTY and
16
+ // the first argument is not a sub-command name. Detect this early and run the
17
+ // host protocol handler.
18
+ // Handle detached analysis subprocess: webtape --analyze <dir> --backend <b>
19
+ if (process.argv.includes('--analyze')) {
20
+ const sessionIdx = process.argv.indexOf('--analyze') + 1;
21
+ const backendIdx = process.argv.indexOf('--backend') + 1;
22
+ const modelIdx = process.argv.indexOf('--model') + 1;
23
+ const sessionDir = process.argv[sessionIdx];
24
+ const backend = backendIdx > 0 ? process.argv[backendIdx] : 'cursor';
25
+ const model = modelIdx > 0 ? process.argv[modelIdx] : undefined;
26
+ runDetachedAnalysis(sessionDir, backend, model).catch(() => process.exit(1));
27
+ }
28
+ else if (!process.stdin.isTTY && process.argv.length <= 2) {
29
+ // No sub-command and stdin is not a TTY → Native Messaging host mode
30
+ runNativeHost().catch(() => process.exit(1));
31
+ }
32
+ else {
33
+ const program = new Command();
34
+ program
35
+ .name('webtape')
36
+ .description('WebTape CLI — 运行 webtape install 完成一次性初始化,之后插件可自动调用')
37
+ .version(VERSION);
38
+ /**
39
+ * Log analysis result — success or failure hint.
40
+ */
41
+ function logAnalyzeResult(result) {
42
+ if (result.success) {
43
+ const { domain, time } = parseSessionName(result.sessionName);
44
+ const formattedTime = formatTime(time);
45
+ const durationText = result.duration ? chalk.gray(` (耗时 ${(result.duration / 1000).toFixed(1)}s)`) : '';
46
+ console.log(chalk.green(` ✅ 已将 ${formattedTime} 录制的 ${domain} 站点 api 分析记录保存到了 ${result.reportPath}${durationText}`));
47
+ }
48
+ else {
49
+ console.log(chalk.yellow(` ⚠️ 未检测到分析报告: ${result.reportPath}`));
50
+ console.log(chalk.gray(' 你可以稍后使用 webtape-receiver retry 命令重新分析所有未完成的记录。'));
51
+ }
52
+ }
53
+ // ─── serve ───────────────────────────────────────────────────────────────────
54
+ program
55
+ .command('serve')
56
+ .description('启动 webhook 接收服务器')
57
+ .option('-p, --port <number>', '监听端口', '5643')
58
+ .option('-w, --workspace <path>', '工作区路径(默认 ~/Desktop/WebTape)')
59
+ .option('--backend <name>', 'AI 分析后端(cursor / claude / none),覆盖配置文件', '')
60
+ .option('--model <name>', 'AI 模型名称(例如 kimi-k2.5)')
61
+ .action(async (opts) => {
62
+ const port = parseInt(opts.port, 10);
63
+ const workspaceRoot = resolveWorkspaceRoot(opts.workspace);
64
+ const workspace = ensureWorkspace(workspaceRoot, VERSION);
65
+ // Resolve AI backend: CLI flag > saved config > interactive prompt
66
+ let backend;
67
+ const config = loadConfig();
68
+ if (opts.backend) {
69
+ backend = opts.backend;
70
+ }
71
+ else if (config.aiBackend) {
72
+ backend = config.aiBackend;
73
+ }
74
+ else {
75
+ backend = await promptAiBackend();
76
+ }
77
+ // 'none' means the user explicitly disabled auto-analysis via config
78
+ const autoAnalyze = backend !== 'none';
79
+ console.log('');
80
+ console.log(chalk.bold.cyan(' 🎬 WebTape Receiver') + chalk.gray(` v${VERSION}`));
81
+ console.log(chalk.gray(' ─────────────────────────────────'));
82
+ console.log(` ${chalk.green('工作区')} ${workspace.root}`);
83
+ console.log(` ${chalk.green('端口')} ${port}`);
84
+ if (autoAnalyze) {
85
+ console.log(` ${chalk.green('自动分析')} ${chalk.yellow('开启')}`);
86
+ console.log(` ${chalk.green('AI 后端')} ${backend}`);
87
+ if (opts.model) {
88
+ console.log(` ${chalk.green('AI 模型')} ${opts.model}`);
89
+ }
90
+ }
91
+ else {
92
+ console.log(` ${chalk.green('自动分析')} ${chalk.gray('关闭')}`);
93
+ }
94
+ console.log('');
95
+ const spinner = ora('正在启动服务器…').start();
96
+ const srv = createWebhookServer({
97
+ port,
98
+ workspace,
99
+ autoAnalyze,
100
+ analyzerBackend: backend,
101
+ analyzerModel: opts.model,
102
+ onReceive(sessionDir, payload, metrics) {
103
+ const actions = payload.content['index.json'].filter((b) => b.action).length;
104
+ const requests = Object.keys(payload.content.requests).length;
105
+ const nonAiMs = Math.round(metrics.totalNonAiMs);
106
+ console.log('');
107
+ console.log(chalk.green(' ✓ 收到录制数据') + chalk.gray(` (${nonAiMs}ms)`));
108
+ console.log(` ${chalk.gray('会话')} ${sessionDir}`);
109
+ console.log(` ${chalk.gray('操作数')} ${actions}`);
110
+ console.log(` ${chalk.gray('请求数')} ${requests}`);
111
+ if (autoAnalyze) {
112
+ console.log('');
113
+ console.log(chalk.cyan(' ⏳ 正在启动 AI 分析…') + chalk.gray(' (预估 1-2min,请稍候)'));
114
+ }
115
+ },
116
+ onAnalyzeLog(line) {
117
+ if (autoAnalyze) {
118
+ process.stdout.write(chalk.gray(` ${line.length > 80 ? line.slice(0, 77) + '...' : line}\r`));
119
+ }
120
+ },
121
+ onAnalyzeDone(result) {
122
+ if (autoAnalyze) {
123
+ process.stdout.write(' '.repeat(process.stdout.columns || 80) + '\r');
124
+ }
125
+ console.log('');
126
+ logAnalyzeResult(result);
127
+ },
128
+ onError(err) {
129
+ console.error('');
130
+ console.error(chalk.red(' ✗ 错误:'), err.message);
131
+ },
132
+ });
133
+ try {
134
+ await srv.start();
135
+ spinner.succeed(`服务器已启动,监听端口 ${chalk.bold(String(port))}`);
136
+ console.log('');
137
+ console.log(chalk.gray(' 在 WebTape 插件中将 webhook URL 设置为:'));
138
+ console.log(chalk.cyan(` http://localhost:${port}/webhook`));
139
+ console.log('');
140
+ console.log(chalk.gray(' 按 Ctrl+C 停止服务器'));
141
+ console.log('');
142
+ }
143
+ catch (err) {
144
+ spinner.fail('服务器启动失败');
145
+ console.error(err);
146
+ process.exit(1);
147
+ }
148
+ const shutdown = async () => {
149
+ console.log('');
150
+ const stopSpinner = ora('正在关闭服务器…').start();
151
+ await srv.stop();
152
+ stopSpinner.succeed('服务器已关闭');
153
+ process.exit(0);
154
+ };
155
+ process.on('SIGINT', shutdown);
156
+ process.on('SIGTERM', shutdown);
157
+ });
158
+ // ─── list ────────────────────────────────────────────────────────────────────
159
+ program
160
+ .command('list')
161
+ .description('列出所有录制会话')
162
+ .option('-w, --workspace <path>', '工作区路径')
163
+ .action((opts) => {
164
+ const workspaceRoot = resolveWorkspaceRoot(opts.workspace);
165
+ const workspace = ensureWorkspace(workspaceRoot, VERSION);
166
+ const sessions = listRecordings(workspace);
167
+ if (sessions.length === 0) {
168
+ console.log(chalk.gray('暂无录制会话。'));
169
+ return;
170
+ }
171
+ console.log('');
172
+ console.log(chalk.bold(`录制会话(共 ${sessions.length} 个):`));
173
+ console.log('');
174
+ for (const s of sessions) {
175
+ console.log(` ${chalk.cyan('●')} ${s}`);
176
+ }
177
+ console.log('');
178
+ });
179
+ // ─── analyze ─────────────────────────────────────────────────────────────────
180
+ program
181
+ .command('analyze <session>')
182
+ .description('对指定的录制会话运行 AI 分析')
183
+ .option('-w, --workspace <path>', '工作区路径')
184
+ .option('--backend <name>', 'AI 分析后端(cursor / claude)', '')
185
+ .option('--model <name>', 'AI 模型名称(例如 kimi-k2.5)')
186
+ .action(async (session, opts) => {
187
+ const workspaceRoot = resolveWorkspaceRoot(opts.workspace);
188
+ const workspace = ensureWorkspace(workspaceRoot, VERSION);
189
+ const sessionDir = join(workspace.recordings, session);
190
+ // Resolve AI backend: CLI flag > saved config > default cursor
191
+ let backend;
192
+ const config = loadConfig();
193
+ if (opts.backend) {
194
+ backend = opts.backend;
195
+ }
196
+ else if (config.aiBackend && config.aiBackend !== 'none') {
197
+ backend = config.aiBackend;
198
+ }
199
+ else {
200
+ if (config.aiBackend === 'none') {
201
+ console.log(chalk.yellow(' ⚠️ 当前配置为"不分析",请先运行 webtape-receiver config 选择 AI 后端。'));
202
+ process.exit(1);
203
+ }
204
+ backend = 'cursor';
205
+ }
206
+ const spinner = ora(`正在通过 ${backend} 分析会话 ${session}…`).start();
207
+ spinner.text = `正在通过 ${backend} 分析会话 ${session}… ${chalk.gray('(预估 1-2min,请稍候)')}`;
208
+ try {
209
+ const result = await analyzeRecording({
210
+ backend,
211
+ workspace,
212
+ sessionDir,
213
+ model: opts.model,
214
+ onLog: (line) => {
215
+ spinner.text = `正在通过 ${backend} 分析会话 ${session}… ${chalk.gray('(预估 1-2min,请稍候)')}\n ${chalk.gray(line.length > 80 ? line.slice(0, 77) + '...' : line)}`;
216
+ },
217
+ });
218
+ spinner.stop();
219
+ logAnalyzeResult(result);
220
+ }
221
+ catch (err) {
222
+ spinner.fail('分析失败');
223
+ console.error(err instanceof Error ? err.message : err);
224
+ process.exit(1);
225
+ }
226
+ });
227
+ // ─── retry ───────────────────────────────────────────────────────────────────
228
+ program
229
+ .command('retry')
230
+ .description('重新分析所有未生成报告的录制会话')
231
+ .option('-w, --workspace <path>', '工作区路径')
232
+ .option('--backend <name>', 'AI 分析后端(cursor / claude)', '')
233
+ .option('--model <name>', 'AI 模型名称(例如 kimi-k2.5)')
234
+ .action(async (opts) => {
235
+ const workspaceRoot = resolveWorkspaceRoot(opts.workspace);
236
+ const workspace = ensureWorkspace(workspaceRoot, VERSION);
237
+ const unanalyzed = listUnanalyzedRecordings(workspace);
238
+ if (unanalyzed.length === 0) {
239
+ console.log(chalk.green(' ✅ 所有录制会话均已完成分析。'));
240
+ return;
241
+ }
242
+ // Resolve AI backend: CLI flag > saved config > default cursor
243
+ let backend;
244
+ const config = loadConfig();
245
+ if (opts.backend) {
246
+ backend = opts.backend;
247
+ }
248
+ else if (config.aiBackend && config.aiBackend !== 'none') {
249
+ backend = config.aiBackend;
250
+ }
251
+ else {
252
+ if (config.aiBackend === 'none') {
253
+ console.log(chalk.yellow(' ⚠️ 当前配置为"不分析",请先运行 webtape-receiver config 选择 AI 后端。'));
254
+ process.exit(1);
255
+ }
256
+ backend = 'cursor';
257
+ }
258
+ console.log('');
259
+ console.log(chalk.bold(`待分析会话(共 ${unanalyzed.length} 个):`));
260
+ for (const s of unanalyzed) {
261
+ console.log(` ${chalk.cyan('●')} ${s}`);
262
+ }
263
+ console.log('');
264
+ for (const session of unanalyzed) {
265
+ const sessionDir = join(workspace.recordings, session);
266
+ const spinner = ora(`正在通过 ${backend} 分析会话 ${session}…`).start();
267
+ spinner.text = `正在通过 ${backend} 分析会话 ${session}… ${chalk.gray('(预估 1-2min,请稍候)')}`;
268
+ try {
269
+ const result = await analyzeRecording({
270
+ backend,
271
+ workspace,
272
+ sessionDir,
273
+ model: opts.model,
274
+ onLog: (line) => {
275
+ spinner.text = `正在通过 ${backend} 分析会话 ${session}… ${chalk.gray('(预估 1-2min,请稍候)')}\n ${chalk.gray(line.length > 80 ? line.slice(0, 77) + '...' : line)}`;
276
+ },
277
+ });
278
+ spinner.stop();
279
+ logAnalyzeResult(result);
280
+ }
281
+ catch (err) {
282
+ spinner.fail(`分析 ${session} 失败`);
283
+ console.error(err instanceof Error ? err.message : err);
284
+ }
285
+ }
286
+ });
287
+ // ─── config ──────────────────────────────────────────────────────────────────
288
+ const configCmd = program
289
+ .command('config')
290
+ .description('交互式配置向导')
291
+ .action(async () => {
292
+ await runConfigWizard();
293
+ });
294
+ configCmd
295
+ .command('show')
296
+ .description('显示当前配置')
297
+ .action(() => {
298
+ const config = loadConfig();
299
+ console.log('');
300
+ console.log(chalk.bold('当前配置:'));
301
+ console.log('');
302
+ if (Object.keys(config).length === 0) {
303
+ console.log(chalk.gray(' (尚无配置,运行 webtape-receiver config 进行设置)'));
304
+ }
305
+ else {
306
+ if (config.aiBackend) {
307
+ console.log(` ${chalk.green('AI 后端')} ${config.aiBackend}`);
308
+ }
309
+ }
310
+ console.log('');
311
+ });
312
+ // ─── install ─────────────────────────────────────────────────────────────────
313
+ program
314
+ .command('install')
315
+ .description('注册 Native Messaging Host 并打开插件安装页')
316
+ .option('--extension-id <id>', '手动指定插件 ID(默认自动检测)')
317
+ .option('--no-open', '不自动打开浏览器')
318
+ .action(async (opts) => {
319
+ await runInstall({
320
+ extensionId: opts.extensionId,
321
+ openStore: opts.open !== false,
322
+ });
323
+ });
324
+ program.parse();
325
+ } // end of else block for non-native-messaging mode
326
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}