webtape-receiver 1.0.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.
@@ -0,0 +1,17 @@
1
+ import type { WorkspacePaths } from './workspace.js';
2
+ export type AnalyzerBackend = 'cursor';
3
+ export interface AnalyzeOptions {
4
+ backend: AnalyzerBackend;
5
+ workspace: WorkspacePaths;
6
+ sessionDir: string;
7
+ }
8
+ /**
9
+ * Run AI analysis on a recording session.
10
+ * Returns the path to the generated analysis report.
11
+ */
12
+ export declare function analyzeRecording(opts: AnalyzeOptions): Promise<string>;
13
+ /**
14
+ * Generate a standalone prompt file for manual use (e.g. paste into Cursor chat).
15
+ */
16
+ export declare function generatePromptFile(workspace: WorkspacePaths, sessionDir: string): string;
17
+ //# sourceMappingURL=analyzer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"analyzer.d.ts","sourceRoot":"","sources":["../src/analyzer.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AA4CrD,MAAM,MAAM,eAAe,GAAG,QAAQ,CAAC;AAEvC,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,eAAe,CAAC;IACzB,SAAS,EAAE,cAAc,CAAC;IAC1B,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;;GAGG;AACH,wBAAsB,gBAAgB,CAAC,IAAI,EAAE,cAAc,GAAG,OAAO,CAAC,MAAM,CAAC,CAY5E;AA+CD;;GAEG;AACH,wBAAgB,kBAAkB,CAChC,SAAS,EAAE,cAAc,EACzB,UAAU,EAAE,MAAM,GACjB,MAAM,CAMR"}
@@ -0,0 +1,101 @@
1
+ import { execFile } from 'node:child_process';
2
+ import { readFileSync, writeFileSync, existsSync } from 'node:fs';
3
+ import { join } from 'node:path';
4
+ const ANALYSIS_PROMPT_TEMPLATE = `你是一个专业的 Web 前端业务分析专家。请根据以下 WebTape 录制数据,分析该网页的业务逻辑和完整接口链路。
5
+
6
+ ## 任务
7
+
8
+ 1. **梳理用户操作流程**:根据 index.json 中的 action 序列,还原用户的完整操作路径。
9
+ 2. **分析接口调用链路**:
10
+ - 列出每个用户操作触发的所有 API 请求
11
+ - 标注请求方法、URL、状态码
12
+ - 分析请求之间的依赖关系(例如:登录后拿到 token,后续请求携带 token)
13
+ 3. **识别业务模块**:根据 URL 模式和请求内容,划分业务模块(如:用户认证、数据查询、表单提交等)
14
+ 4. **生成接口文档概要**:对每个接口给出简要说明,包括用途、请求参数、响应结构
15
+ 5. **绘制链路图**:用 Mermaid 序列图描述核心业务流程的接口调用时序
16
+
17
+ ## 录制数据
18
+
19
+ 以下是 WebTape 录制的 index.json 内容:
20
+
21
+ \`\`\`json
22
+ {{INDEX_JSON}}
23
+ \`\`\`
24
+
25
+ ## 请求详情目录
26
+
27
+ 录制的请求详情文件位于:{{SESSION_DIR}}
28
+
29
+ 请详细分析并输出 Markdown 格式的报告。`;
30
+ /**
31
+ * Build the analysis prompt from a recording session.
32
+ */
33
+ function buildPrompt(sessionDir) {
34
+ const indexPath = join(sessionDir, 'index.json');
35
+ if (!existsSync(indexPath)) {
36
+ throw new Error(`index.json not found in ${sessionDir}`);
37
+ }
38
+ const indexContent = readFileSync(indexPath, 'utf-8');
39
+ return ANALYSIS_PROMPT_TEMPLATE
40
+ .replace('{{INDEX_JSON}}', indexContent)
41
+ .replace('{{SESSION_DIR}}', sessionDir);
42
+ }
43
+ /**
44
+ * Run AI analysis on a recording session.
45
+ * Returns the path to the generated analysis report.
46
+ */
47
+ export async function analyzeRecording(opts) {
48
+ const { backend, workspace, sessionDir } = opts;
49
+ const sessionName = sessionDir.split('/').pop() || 'unknown';
50
+ const reportPath = join(workspace.analyses, `${sessionName}.md`);
51
+ const prompt = buildPrompt(sessionDir);
52
+ if (backend === 'cursor') {
53
+ return analyzeByCursor(prompt, sessionDir, reportPath);
54
+ }
55
+ throw new Error(`Unsupported analyzer backend: ${backend}`);
56
+ }
57
+ /**
58
+ * Analyze via `cursor agent` CLI.
59
+ * Writes the prompt to a temp file and invokes cursor in agent mode.
60
+ */
61
+ async function analyzeByCursor(prompt, sessionDir, reportPath) {
62
+ const promptPath = join(sessionDir, '.analysis_prompt.md');
63
+ writeFileSync(promptPath, prompt, 'utf-8');
64
+ return new Promise((resolve, reject) => {
65
+ const args = [
66
+ 'agent',
67
+ '--message', prompt,
68
+ ];
69
+ const child = execFile('cursor', args, {
70
+ cwd: sessionDir,
71
+ maxBuffer: 10 * 1024 * 1024,
72
+ timeout: 5 * 60 * 1000,
73
+ }, (error, stdout, stderr) => {
74
+ if (error) {
75
+ if (stderr) {
76
+ console.error('[analyzer] cursor stderr:', stderr);
77
+ }
78
+ reject(new Error(`cursor agent failed: ${error.message}`));
79
+ return;
80
+ }
81
+ const output = stdout || '';
82
+ writeFileSync(reportPath, output, 'utf-8');
83
+ resolve(reportPath);
84
+ });
85
+ child.on('error', (err) => {
86
+ reject(new Error(`Failed to launch cursor agent: ${err.message}. ` +
87
+ 'Ensure Cursor is installed and the `cursor` CLI is on your PATH.'));
88
+ });
89
+ });
90
+ }
91
+ /**
92
+ * Generate a standalone prompt file for manual use (e.g. paste into Cursor chat).
93
+ */
94
+ export function generatePromptFile(workspace, sessionDir) {
95
+ const sessionName = sessionDir.split('/').pop() || 'unknown';
96
+ const promptPath = join(workspace.analyses, `${sessionName}_prompt.md`);
97
+ const prompt = buildPrompt(sessionDir);
98
+ writeFileSync(promptPath, prompt, 'utf-8');
99
+ return promptPath;
100
+ }
101
+ //# sourceMappingURL=analyzer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"analyzer.js","sourceRoot":"","sources":["../src/analyzer.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,150 @@
1
+ #!/usr/bin/env node
2
+ import { Command } from 'commander';
3
+ import chalk from 'chalk';
4
+ import ora from 'ora';
5
+ import { resolveWorkspaceRoot, ensureWorkspace } from './workspace.js';
6
+ import { createWebhookServer } from './server.js';
7
+ import { listRecordings } from './storage.js';
8
+ import { analyzeRecording, generatePromptFile } from './analyzer.js';
9
+ const VERSION = '1.0.0';
10
+ const program = new Command();
11
+ program
12
+ .name('webtape-receiver')
13
+ .description('接收 WebTape 插件的 webhook 数据,保存录制内容并通过 AI 分析业务接口链路')
14
+ .version(VERSION);
15
+ // ─── serve ───────────────────────────────────────────────────────────────────
16
+ program
17
+ .command('serve')
18
+ .description('启动 webhook 接收服务器')
19
+ .option('-p, --port <number>', '监听端口', '5643')
20
+ .option('-w, --workspace <path>', '工作区路径(默认 ~/Desktop/WebTape)')
21
+ .option('--auto-analyze', '接收数据后自动运行 AI 分析', false)
22
+ .option('--backend <name>', 'AI 分析后端(cursor)', 'cursor')
23
+ .action(async (opts) => {
24
+ const port = parseInt(opts.port, 10);
25
+ const workspaceRoot = resolveWorkspaceRoot(opts.workspace);
26
+ const workspace = ensureWorkspace(workspaceRoot);
27
+ console.log('');
28
+ console.log(chalk.bold.cyan(' 🎬 WebTape Receiver'));
29
+ console.log(chalk.gray(' ─────────────────────────────────'));
30
+ console.log(` ${chalk.green('工作区')} ${workspace.root}`);
31
+ console.log(` ${chalk.green('端口')} ${port}`);
32
+ console.log(` ${chalk.green('自动分析')} ${opts.autoAnalyze ? chalk.yellow('开启') : chalk.gray('关闭')}`);
33
+ console.log(` ${chalk.green('AI 后端')} ${opts.backend}`);
34
+ console.log('');
35
+ const spinner = ora('正在启动服务器…').start();
36
+ const srv = createWebhookServer({
37
+ port,
38
+ workspace,
39
+ autoAnalyze: opts.autoAnalyze,
40
+ analyzerBackend: opts.backend,
41
+ onReceive(sessionDir, payload) {
42
+ const actions = payload.content['index.json'].filter((b) => b.action).length;
43
+ const requests = Object.keys(payload.content.requests).length;
44
+ console.log('');
45
+ console.log(chalk.green(' ✓ 收到录制数据'));
46
+ console.log(` ${chalk.gray('会话')} ${sessionDir}`);
47
+ console.log(` ${chalk.gray('操作数')} ${actions}`);
48
+ console.log(` ${chalk.gray('请求数')} ${requests}`);
49
+ },
50
+ onAnalyzeDone(reportPath) {
51
+ console.log('');
52
+ console.log(chalk.green(' ✓ AI 分析完成'));
53
+ console.log(` ${chalk.gray('报告')} ${reportPath}`);
54
+ },
55
+ onError(err) {
56
+ console.error('');
57
+ console.error(chalk.red(' ✗ 错误:'), err.message);
58
+ },
59
+ });
60
+ try {
61
+ await srv.start();
62
+ spinner.succeed(`服务器已启动,监听端口 ${chalk.bold(String(port))}`);
63
+ console.log('');
64
+ console.log(chalk.gray(' 在 WebTape 插件中将 webhook URL 设置为:'));
65
+ console.log(chalk.cyan(` http://localhost:${port}/webhook`));
66
+ console.log('');
67
+ console.log(chalk.gray(' 按 Ctrl+C 停止服务器'));
68
+ console.log('');
69
+ }
70
+ catch (err) {
71
+ spinner.fail('服务器启动失败');
72
+ console.error(err);
73
+ process.exit(1);
74
+ }
75
+ const shutdown = async () => {
76
+ console.log('');
77
+ const stopSpinner = ora('正在关闭服务器…').start();
78
+ await srv.stop();
79
+ stopSpinner.succeed('服务器已关闭');
80
+ process.exit(0);
81
+ };
82
+ process.on('SIGINT', shutdown);
83
+ process.on('SIGTERM', shutdown);
84
+ });
85
+ // ─── list ────────────────────────────────────────────────────────────────────
86
+ program
87
+ .command('list')
88
+ .description('列出所有录制会话')
89
+ .option('-w, --workspace <path>', '工作区路径')
90
+ .action((opts) => {
91
+ const workspaceRoot = resolveWorkspaceRoot(opts.workspace);
92
+ const workspace = ensureWorkspace(workspaceRoot);
93
+ const sessions = listRecordings(workspace);
94
+ if (sessions.length === 0) {
95
+ console.log(chalk.gray('暂无录制会话。'));
96
+ return;
97
+ }
98
+ console.log('');
99
+ console.log(chalk.bold(`录制会话(共 ${sessions.length} 个):`));
100
+ console.log('');
101
+ for (const s of sessions) {
102
+ console.log(` ${chalk.cyan('●')} ${s}`);
103
+ }
104
+ console.log('');
105
+ });
106
+ // ─── analyze ─────────────────────────────────────────────────────────────────
107
+ program
108
+ .command('analyze <session>')
109
+ .description('对指定的录制会话运行 AI 分析')
110
+ .option('-w, --workspace <path>', '工作区路径')
111
+ .option('--backend <name>', 'AI 分析后端(cursor)', 'cursor')
112
+ .option('--prompt-only', '仅生成提示词文件,不执行分析', false)
113
+ .action(async (session, opts) => {
114
+ const workspaceRoot = resolveWorkspaceRoot(opts.workspace);
115
+ const workspace = ensureWorkspace(workspaceRoot);
116
+ const sessionDir = `${workspace.recordings}/${session}`;
117
+ if (opts.promptOnly) {
118
+ const spinner = ora('正在生成提示词文件…').start();
119
+ try {
120
+ const promptPath = generatePromptFile(workspace, sessionDir);
121
+ spinner.succeed('提示词文件已生成');
122
+ console.log(` ${chalk.gray('路径')} ${promptPath}`);
123
+ console.log('');
124
+ console.log(chalk.gray(' 你可以将此文件内容粘贴到 Cursor Chat 中进行分析。'));
125
+ }
126
+ catch (err) {
127
+ spinner.fail('生成失败');
128
+ console.error(err instanceof Error ? err.message : err);
129
+ process.exit(1);
130
+ }
131
+ return;
132
+ }
133
+ const spinner = ora(`正在通过 ${opts.backend} 分析会话 ${session}…`).start();
134
+ try {
135
+ const reportPath = await analyzeRecording({
136
+ backend: opts.backend,
137
+ workspace,
138
+ sessionDir,
139
+ });
140
+ spinner.succeed('分析完成');
141
+ console.log(` ${chalk.gray('报告')} ${reportPath}`);
142
+ }
143
+ catch (err) {
144
+ spinner.fail('分析失败');
145
+ console.error(err instanceof Error ? err.message : err);
146
+ process.exit(1);
147
+ }
148
+ });
149
+ program.parse();
150
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ import { type IncomingMessage, type ServerResponse } from 'node:http';
2
+ import type { WorkspacePaths } from './workspace.js';
3
+ import type { WebTapePayload } from './types.js';
4
+ import { type AnalyzerBackend } from './analyzer.js';
5
+ export interface ServerOptions {
6
+ port: number;
7
+ workspace: WorkspacePaths;
8
+ autoAnalyze: boolean;
9
+ analyzerBackend: AnalyzerBackend;
10
+ onReceive?: (sessionDir: string, payload: WebTapePayload) => void;
11
+ onAnalyzeDone?: (reportPath: string) => void;
12
+ onError?: (err: Error) => void;
13
+ }
14
+ export declare function createWebhookServer(opts: ServerOptions): {
15
+ start: () => Promise<void>;
16
+ stop: () => Promise<void>;
17
+ server: import("http").Server<typeof IncomingMessage, typeof ServerResponse>;
18
+ };
19
+ //# sourceMappingURL=server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,KAAK,eAAe,EAAE,KAAK,cAAc,EAAE,MAAM,WAAW,CAAC;AACpF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AACrD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAEjD,OAAO,EAAwC,KAAK,eAAe,EAAE,MAAM,eAAe,CAAC;AAE3F,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,cAAc,CAAC;IAC1B,WAAW,EAAE,OAAO,CAAC;IACrB,eAAe,EAAE,eAAe,CAAC;IACjC,SAAS,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,cAAc,KAAK,IAAI,CAAC;IAClE,aAAa,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7C,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,KAAK,KAAK,IAAI,CAAC;CAChC;AAiCD,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,aAAa;;;;EAyFtD"}
package/dist/server.js ADDED
@@ -0,0 +1,118 @@
1
+ import { createServer } from 'node:http';
2
+ import { saveRecording } from './storage.js';
3
+ import { analyzeRecording, generatePromptFile } from './analyzer.js';
4
+ function readBody(req) {
5
+ return new Promise((resolve, reject) => {
6
+ const chunks = [];
7
+ req.on('data', (chunk) => chunks.push(chunk));
8
+ req.on('end', () => resolve(Buffer.concat(chunks).toString('utf-8')));
9
+ req.on('error', reject);
10
+ });
11
+ }
12
+ function json(res, status, body) {
13
+ res.writeHead(status, {
14
+ 'Content-Type': 'application/json',
15
+ 'Access-Control-Allow-Origin': '*',
16
+ });
17
+ res.end(JSON.stringify(body));
18
+ }
19
+ function handleCors(req, res) {
20
+ if (req.method === 'OPTIONS') {
21
+ res.writeHead(204, {
22
+ 'Access-Control-Allow-Origin': '*',
23
+ 'Access-Control-Allow-Methods': 'POST, GET, OPTIONS',
24
+ 'Access-Control-Allow-Headers': 'Content-Type',
25
+ 'Access-Control-Max-Age': '86400',
26
+ });
27
+ res.end();
28
+ return true;
29
+ }
30
+ return false;
31
+ }
32
+ export function createWebhookServer(opts) {
33
+ const { port, workspace, autoAnalyze, analyzerBackend, onReceive, onAnalyzeDone, onError } = opts;
34
+ const server = createServer(async (req, res) => {
35
+ if (handleCors(req, res))
36
+ return;
37
+ // Health check
38
+ if (req.method === 'GET' && (req.url === '/' || req.url === '/health')) {
39
+ json(res, 200, {
40
+ status: 'ok',
41
+ service: 'webtape-receiver',
42
+ workspace: workspace.root,
43
+ });
44
+ return;
45
+ }
46
+ // Webhook endpoint
47
+ if (req.method === 'POST' && (req.url === '/' || req.url === '/webhook')) {
48
+ try {
49
+ const body = await readBody(req);
50
+ const payload = JSON.parse(body);
51
+ if (!payload.meta || !payload.content) {
52
+ json(res, 400, { error: 'Invalid WebTape payload: missing meta or content' });
53
+ return;
54
+ }
55
+ const sessionDir = saveRecording(workspace, payload);
56
+ onReceive?.(sessionDir, payload);
57
+ if (autoAnalyze) {
58
+ runAnalysis(workspace, sessionDir, analyzerBackend, onAnalyzeDone, onError);
59
+ }
60
+ json(res, 200, {
61
+ status: 'received',
62
+ session: sessionDir,
63
+ autoAnalyze,
64
+ });
65
+ }
66
+ catch (err) {
67
+ const message = err instanceof Error ? err.message : String(err);
68
+ onError?.(err instanceof Error ? err : new Error(message));
69
+ json(res, 500, { error: message });
70
+ }
71
+ return;
72
+ }
73
+ // Trigger analysis for a specific session
74
+ if (req.method === 'POST' && req.url?.startsWith('/analyze/')) {
75
+ const sessionName = req.url.slice('/analyze/'.length);
76
+ const sessionDir = `${workspace.recordings}/${sessionName}`;
77
+ try {
78
+ runAnalysis(workspace, sessionDir, analyzerBackend, onAnalyzeDone, onError);
79
+ json(res, 200, { status: 'analysis_started', session: sessionDir });
80
+ }
81
+ catch (err) {
82
+ const message = err instanceof Error ? err.message : String(err);
83
+ json(res, 500, { error: message });
84
+ }
85
+ return;
86
+ }
87
+ // Generate prompt file for manual analysis
88
+ if (req.method === 'POST' && req.url?.startsWith('/prompt/')) {
89
+ const sessionName = req.url.slice('/prompt/'.length);
90
+ const sessionDir = `${workspace.recordings}/${sessionName}`;
91
+ try {
92
+ const promptPath = generatePromptFile(workspace, sessionDir);
93
+ json(res, 200, { status: 'prompt_generated', path: promptPath });
94
+ }
95
+ catch (err) {
96
+ const message = err instanceof Error ? err.message : String(err);
97
+ json(res, 500, { error: message });
98
+ }
99
+ return;
100
+ }
101
+ json(res, 404, { error: 'Not found' });
102
+ });
103
+ return {
104
+ start: () => new Promise((resolve) => {
105
+ server.listen(port, () => resolve());
106
+ }),
107
+ stop: () => new Promise((resolve, reject) => {
108
+ server.close((err) => (err ? reject(err) : resolve()));
109
+ }),
110
+ server,
111
+ };
112
+ }
113
+ function runAnalysis(workspace, sessionDir, backend, onDone, onError) {
114
+ analyzeRecording({ backend, workspace, sessionDir })
115
+ .then((reportPath) => onDone?.(reportPath))
116
+ .catch((err) => onError?.(err instanceof Error ? err : new Error(String(err))));
117
+ }
118
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ import type { WorkspacePaths } from './workspace.js';
2
+ import type { WebTapePayload } from './types.js';
3
+ /**
4
+ * Persist a webhook payload to the workspace as structured files:
5
+ *
6
+ * recordings/<session>/
7
+ * index.json
8
+ * requests/
9
+ * req_0001_body.json
10
+ * responses/
11
+ * req_0001_res.json
12
+ *
13
+ * Returns the absolute path of the session directory.
14
+ */
15
+ export declare function saveRecording(workspace: WorkspacePaths, payload: WebTapePayload): string;
16
+ /**
17
+ * List existing recording sessions (directory names) sorted newest-first.
18
+ */
19
+ export declare function listRecordings(workspace: WorkspacePaths): string[];
20
+ //# sourceMappingURL=storage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../src/storage.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AACrD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAoBjD;;;;;;;;;;;GAWG;AACH,wBAAgB,aAAa,CAC3B,SAAS,EAAE,cAAc,EACzB,OAAO,EAAE,cAAc,GACtB,MAAM,CAsCR;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,SAAS,EAAE,cAAc,GAAG,MAAM,EAAE,CAUlE"}
@@ -0,0 +1,64 @@
1
+ import { mkdirSync, writeFileSync, readdirSync } from 'node:fs';
2
+ import { join } from 'node:path';
3
+ /**
4
+ * Build a human-readable session directory name from the payload metadata.
5
+ * Format: YYYY-MM-DD_HH-mm-ss
6
+ */
7
+ function sessionDirName(payload) {
8
+ const d = new Date(payload.meta.epoch);
9
+ const pad = (n, len = 2) => String(n).padStart(len, '0');
10
+ return [
11
+ d.getFullYear(),
12
+ pad(d.getMonth() + 1),
13
+ pad(d.getDate()),
14
+ ].join('-') + '_' + [
15
+ pad(d.getHours()),
16
+ pad(d.getMinutes()),
17
+ pad(d.getSeconds()),
18
+ ].join('-');
19
+ }
20
+ /**
21
+ * Persist a webhook payload to the workspace as structured files:
22
+ *
23
+ * recordings/<session>/
24
+ * index.json
25
+ * requests/
26
+ * req_0001_body.json
27
+ * responses/
28
+ * req_0001_res.json
29
+ *
30
+ * Returns the absolute path of the session directory.
31
+ */
32
+ export function saveRecording(workspace, payload) {
33
+ const dirName = sessionDirName(payload);
34
+ const sessionDir = join(workspace.recordings, dirName);
35
+ const reqDir = join(sessionDir, 'requests');
36
+ const resDir = join(sessionDir, 'responses');
37
+ mkdirSync(reqDir, { recursive: true });
38
+ mkdirSync(resDir, { recursive: true });
39
+ writeFileSync(join(sessionDir, 'index.json'), JSON.stringify(payload.content['index.json'], null, 2), 'utf-8');
40
+ for (const [filename, data] of Object.entries(payload.content.requests)) {
41
+ writeFileSync(join(reqDir, filename), JSON.stringify(data, null, 2), 'utf-8');
42
+ }
43
+ for (const [filename, data] of Object.entries(payload.content.responses)) {
44
+ writeFileSync(join(resDir, filename), JSON.stringify(data, null, 2), 'utf-8');
45
+ }
46
+ writeFileSync(join(sessionDir, 'meta.json'), JSON.stringify(payload.meta, null, 2), 'utf-8');
47
+ return sessionDir;
48
+ }
49
+ /**
50
+ * List existing recording sessions (directory names) sorted newest-first.
51
+ */
52
+ export function listRecordings(workspace) {
53
+ try {
54
+ return readdirSync(workspace.recordings, { withFileTypes: true })
55
+ .filter((d) => d.isDirectory())
56
+ .map((d) => d.name)
57
+ .sort()
58
+ .reverse();
59
+ }
60
+ catch {
61
+ return [];
62
+ }
63
+ }
64
+ //# sourceMappingURL=storage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"storage.js","sourceRoot":"","sources":["../src/storage.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,64 @@
1
+ /**
2
+ * Webhook payload sent by the WebTape Chrome extension (background.js).
3
+ */
4
+ export interface WebTapePayload {
5
+ meta: {
6
+ timestamp: string;
7
+ epoch: number;
8
+ version: string;
9
+ source: string;
10
+ };
11
+ content: {
12
+ 'index.json': ContextBlock[];
13
+ requests: Record<string, RequestEntry>;
14
+ responses: Record<string, ResponseEntry>;
15
+ };
16
+ }
17
+ export interface ContextBlock {
18
+ context_id: string;
19
+ timestamp: number;
20
+ state?: {
21
+ type: string;
22
+ url: string;
23
+ title: string;
24
+ fav_icon_url: string;
25
+ a11y_tree_summary: string;
26
+ };
27
+ action?: {
28
+ type: string;
29
+ target_element: string;
30
+ tag: string;
31
+ id: string;
32
+ aria_label: string;
33
+ };
34
+ triggered_network?: NetworkSummary[] | null;
35
+ post_action_a11y_tree_summary?: string | null;
36
+ }
37
+ export interface NetworkSummary {
38
+ req_id: string;
39
+ method: string;
40
+ url: string;
41
+ status: number | null;
42
+ type: 'http' | 'sse' | 'websocket';
43
+ detail_path: {
44
+ request: string;
45
+ response: string;
46
+ };
47
+ }
48
+ export interface RequestEntry {
49
+ req_id: string;
50
+ type: 'http' | 'sse' | 'websocket';
51
+ method: string;
52
+ url: string;
53
+ headers: Record<string, string>;
54
+ body: string | null;
55
+ }
56
+ export interface ResponseEntry {
57
+ req_id: string;
58
+ type: 'http' | 'sse' | 'websocket';
59
+ status: number | null;
60
+ headers: Record<string, string> | null;
61
+ mime_type?: string;
62
+ body: string | object | null;
63
+ }
64
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE;QACJ,SAAS,EAAE,MAAM,CAAC;QAClB,KAAK,EAAE,MAAM,CAAC;QACd,OAAO,EAAE,MAAM,CAAC;QAChB,MAAM,EAAE,MAAM,CAAC;KAChB,CAAC;IACF,OAAO,EAAE;QACP,YAAY,EAAE,YAAY,EAAE,CAAC;QAC7B,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;QACvC,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;KAC1C,CAAC;CACH;AAED,MAAM,WAAW,YAAY;IAC3B,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE;QACN,IAAI,EAAE,MAAM,CAAC;QACb,GAAG,EAAE,MAAM,CAAC;QACZ,KAAK,EAAE,MAAM,CAAC;QACd,YAAY,EAAE,MAAM,CAAC;QACrB,iBAAiB,EAAE,MAAM,CAAC;KAC3B,CAAC;IACF,MAAM,CAAC,EAAE;QACP,IAAI,EAAE,MAAM,CAAC;QACb,cAAc,EAAE,MAAM,CAAC;QACvB,GAAG,EAAE,MAAM,CAAC;QACZ,EAAE,EAAE,MAAM,CAAC;QACX,UAAU,EAAE,MAAM,CAAC;KACpB,CAAC;IACF,iBAAiB,CAAC,EAAE,cAAc,EAAE,GAAG,IAAI,CAAC;IAC5C,6BAA6B,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC/C;AAED,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,IAAI,EAAE,MAAM,GAAG,KAAK,GAAG,WAAW,CAAC;IACnC,WAAW,EAAE;QACX,OAAO,EAAE,MAAM,CAAC;QAChB,QAAQ,EAAE,MAAM,CAAC;KAClB,CAAC;CACH;AAED,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,GAAG,KAAK,GAAG,WAAW,CAAC;IACnC,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;CACrB;AAED,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,GAAG,KAAK,GAAG,WAAW,CAAC;IACnC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,CAAC;IACvC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;CAC9B"}
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,16 @@
1
+ export interface WorkspacePaths {
2
+ root: string;
3
+ recordings: string;
4
+ analyses: string;
5
+ }
6
+ /**
7
+ * Resolve the WebTape workspace root. Priority:
8
+ * 1. Explicit --workspace CLI flag
9
+ * 2. ~/Desktop/WebTape (macOS default)
10
+ */
11
+ export declare function resolveWorkspaceRoot(explicit?: string): string;
12
+ /**
13
+ * Ensure the workspace directory tree exists and return the resolved paths.
14
+ */
15
+ export declare function ensureWorkspace(root: string): WorkspacePaths;
16
+ //# sourceMappingURL=workspace.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workspace.d.ts","sourceRoot":"","sources":["../src/workspace.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAG9D;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,cAAc,CAW5D"}
@@ -0,0 +1,27 @@
1
+ import { mkdirSync, existsSync } from 'node:fs';
2
+ import { join } from 'node:path';
3
+ import { homedir } from 'node:os';
4
+ /**
5
+ * Resolve the WebTape workspace root. Priority:
6
+ * 1. Explicit --workspace CLI flag
7
+ * 2. ~/Desktop/WebTape (macOS default)
8
+ */
9
+ export function resolveWorkspaceRoot(explicit) {
10
+ if (explicit)
11
+ return explicit;
12
+ return join(homedir(), 'Desktop', 'WebTape');
13
+ }
14
+ /**
15
+ * Ensure the workspace directory tree exists and return the resolved paths.
16
+ */
17
+ export function ensureWorkspace(root) {
18
+ const recordings = join(root, 'recordings');
19
+ const analyses = join(root, 'analyses');
20
+ for (const dir of [root, recordings, analyses]) {
21
+ if (!existsSync(dir)) {
22
+ mkdirSync(dir, { recursive: true });
23
+ }
24
+ }
25
+ return { root, recordings, analyses };
26
+ }
27
+ //# sourceMappingURL=workspace.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workspace.js","sourceRoot":"","sources":["../src/workspace.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAChD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAQlC;;;;GAIG;AACH,MAAM,UAAU,oBAAoB,CAAC,QAAiB;IACpD,IAAI,QAAQ;QAAE,OAAO,QAAQ,CAAC;IAC9B,OAAO,IAAI,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,SAAS,CAAC,CAAC;AAC/C,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,eAAe,CAAC,IAAY;IAC1C,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,EAAE,YAAY,CAAC,CAAC;IAC5C,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;IAExC,KAAK,MAAM,GAAG,IAAI,CAAC,IAAI,EAAE,UAAU,EAAE,QAAQ,CAAC,EAAE,CAAC;QAC/C,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;YACrB,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACtC,CAAC;IACH,CAAC;IAED,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,QAAQ,EAAE,CAAC;AACxC,CAAC"}
package/package.json ADDED
@@ -0,0 +1,45 @@
1
+ {
2
+ "name": "webtape-receiver",
3
+ "version": "1.0.0",
4
+ "description": "CLI tool that receives WebTape webhook data, saves recordings, and analyzes web business logic API chains via AI.",
5
+ "type": "module",
6
+ "bin": {
7
+ "webtape-receiver": "./dist/index.js"
8
+ },
9
+ "files": [
10
+ "dist"
11
+ ],
12
+ "scripts": {
13
+ "build": "tsc",
14
+ "dev": "tsx src/index.ts",
15
+ "start": "node dist/index.js",
16
+ "prepublishOnly": "npm run build"
17
+ },
18
+ "repository": {
19
+ "type": "git",
20
+ "url": "git+https://github.com/FurtherBank/WebTape.git",
21
+ "directory": "packages/webtape-receiver"
22
+ },
23
+ "homepage": "https://github.com/FurtherBank/WebTape/tree/main/packages/webtape-receiver",
24
+ "bugs": {
25
+ "url": "https://github.com/FurtherBank/WebTape/issues"
26
+ },
27
+ "keywords": [
28
+ "webtape",
29
+ "webhook",
30
+ "api-analysis",
31
+ "chrome-extension",
32
+ "llm"
33
+ ],
34
+ "license": "ISC",
35
+ "dependencies": {
36
+ "chalk": "^5.3.0",
37
+ "commander": "^12.1.0",
38
+ "ora": "^8.1.0"
39
+ },
40
+ "devDependencies": {
41
+ "@types/node": "^22.10.0",
42
+ "tsx": "^4.19.0",
43
+ "typescript": "^5.7.0"
44
+ }
45
+ }