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
package/README.md ADDED
@@ -0,0 +1,99 @@
1
+ # 🚀 WebTape Receiver:让网页自动化像录屏一样简单
2
+
3
+ **WebTape Receiver** 是 [WebTape](https://github.com/FurtherBank/WebTape) 生态中的核心动力引擎。
4
+
5
+ 它能将你在浏览器中的操作,瞬间转化为可直接运行且**不依赖网站 Open API 和浏览器手动操作**的自动化脚本。
6
+
7
+ 不再需要抓包、不再需要分析复杂的 API 文档、不再需要手动处理 Cookie。你只需在浏览器里点一点,剩下的交给 WebTape。
8
+
9
+ ---
10
+
11
+ ## ✨ 核心价值:录制即自动化集成
12
+
13
+ 通过 WebTape 插件录制你的业务操作,Receiver 会自动接收并保存所有网络请求。
14
+
15
+ 配合 AI 分析,它能直接理解你在网站上的操作,并将这些操作流程编写成**可以自动化运行的**`request.js`脚本,用于快速将网页操作以命令行、Agent 等形式自动化。
16
+
17
+ 其中:
18
+ - 可自动复用你电脑 Chrome 浏览器的登录状态(Cookie),个人场景下运行无需额外网站登录过程。
19
+ - 对于上层业务流程,AI 会深度梳理接口间的调用链路,及其中输入和流转过程中的参数字段关系,帮你从繁琐的逆向工程和拼代码中解脱出来。
20
+
21
+ 这使得你可以将生成的函数快速集成到自己的工具、爬虫或 Agent 中:
22
+
23
+ 让需要打开浏览器的操作可以**完全自动化**,
24
+ 让自动化 API 调用可以**不限于网站 Open API**,**只要日常浏览器使用能通的 API,自动化都可以通**
25
+
26
+ 无论是获取私有接口数据,还是执行复杂的业务流程,都能像调用本地函数一样简单。
27
+
28
+ ---
29
+
30
+ ## 🛠️ 快速上手
31
+
32
+ ### 第一步:安装
33
+ > 如果你还没有安装 Node.js,请先参考 [Node.js 安装指南](https://nodejs.org/zh-cn/download/package-manager) 安装 Node 和 npm。
34
+
35
+ 只需一行命令,开启你的自动化之旅:
36
+
37
+ ```bash
38
+ npm install -g webtape-receiver
39
+ ```
40
+
41
+ ### 第二步:启动服务
42
+ 启动你的专属 Webhook 接收服务器:
43
+ ```bash
44
+ webtape-receiver serve
45
+ ```
46
+ *首次启动,将自动创建默认工作区在你的**桌面 `WebTape` 文件夹**下。*
47
+
48
+ ### 第三步:配置插件
49
+ 在 WebTape Chrome 插件中,将 Webhook 地址设置为:
50
+ `http://localhost:5643/webhook`
51
+
52
+ ---
53
+
54
+ ## WIP 视频演示
55
+
56
+ ### 场景:从网页操作到自动化脚本生成
57
+
58
+ | 阶段 | 操作 | 核心产出 |
59
+ | :--- | :--- | :--- |
60
+ | **1. 接收** | 终端运行 `webtape-receiver serve`,插件端点击导出。 | 录制数据自动进入 `recordings/` 目录。 |
61
+ | **2. 分析** | 运行 `webtape-receiver analyze <session>`。 | AI 自动生成 `analysis_report.md` 业务文档。 |
62
+ | **3. 生成** | AI 根据 `AGENTS.md` 规则编写代码。 | 自动生成 `request.js`,包含封装好的业务函数。 |
63
+ | **4. 集成** | 在你的项目中 `import { xxx } from './request.js'`。 | **无需逆向工程**,直接实现网页功能自动化。 |
64
+
65
+ ## 📂 你的自动化工作区 (Workspace)
66
+
67
+ 当你运行 `serve` 命令时,系统会自动为你准备好一切:
68
+ - **recordings/**:安全存储你所有的录制会话。
69
+ - **AGENTS.md**:内置 AI 分析规则,确保你的 AI 助手(如 Cursor)能精准理解业务逻辑。
70
+ - **自动环境配置**:自动初始化 Node.js 环境并安装必要依赖,确保生成的脚本开箱即用。
71
+
72
+ ---
73
+
74
+ ## 💡 使用场景
75
+
76
+ - **数据采集**:无需研究复杂的反爬和登录校验,直接复用浏览器的登录态获取数据。
77
+ - **业务自动化**:将重复的网页操作转化为脚本,定时运行或集成到你的工作流中。
78
+ - **AI Agent 增强**:为你的 AI 助手提供直接操作真实业务接口的能力。
79
+
80
+ ---
81
+
82
+ ## ⚠️ 温馨提示 (macOS 用户)
83
+ 生成的 request 代码最终基于`chrome-cookies-secure`库获取本机 Chrome 浏览器的 Cookie 信息,
84
+ macOS 在第一次运行时会弹出安全提示。
85
+
86
+
87
+
88
+ - **操作**:请输入你的 **Mac 开机密码**。
89
+ - **建议**:请务必点击 **“始终允许” (Always Allow)**,以获得最流畅的自动化体验。
90
+
91
+ ---
92
+
93
+ ## 📄 开源协议
94
+ 基于 **MIT** 协议开源。
95
+
96
+ ---
97
+
98
+ **准备好释放网页自动化的潜力了吗?**
99
+ [立即开始使用 WebTape](https://github.com/FurtherBank/WebTape)
@@ -0,0 +1,27 @@
1
+ import type { WorkspacePaths } from "./workspace.js";
2
+ export type AnalyzerBackend = "cursor" | "claude" | "none";
3
+ export declare const VALID_BACKENDS: readonly AnalyzerBackend[];
4
+ export interface AnalyzeOptions {
5
+ backend: AnalyzerBackend;
6
+ workspace: WorkspacePaths;
7
+ sessionDir: string;
8
+ model?: string;
9
+ /** Callback for real-time log output */
10
+ onLog?: (line: string) => void;
11
+ }
12
+ export interface AnalyzeResult {
13
+ /** Whether the analysis report was successfully created */
14
+ success: boolean;
15
+ /** Expected report path */
16
+ reportPath: string;
17
+ /** Session name */
18
+ sessionName: string;
19
+ /** Analysis duration in milliseconds */
20
+ duration?: number;
21
+ }
22
+ /**
23
+ * Run AI analysis on a recording session.
24
+ * Returns an AnalyzeResult indicating whether the report was created.
25
+ */
26
+ export declare function analyzeRecording(opts: AnalyzeOptions): Promise<AnalyzeResult>;
27
+ //# 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;AAErD,MAAM,MAAM,eAAe,GAAG,QAAQ,GAAG,QAAQ,GAAG,MAAM,CAAC;AAE3D,eAAO,MAAM,cAAc,EAAE,SAAS,eAAe,EAI3C,CAAC;AASX,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,eAAe,CAAC;IACzB,SAAS,EAAE,cAAc,CAAC;IAC1B,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,wCAAwC;IACxC,KAAK,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CAChC;AAED,MAAM,WAAW,aAAa;IAC5B,2DAA2D;IAC3D,OAAO,EAAE,OAAO,CAAC;IACjB,2BAA2B;IAC3B,UAAU,EAAE,MAAM,CAAC;IACnB,mBAAmB;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,wCAAwC;IACxC,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;;GAGG;AACH,wBAAsB,gBAAgB,CACpC,IAAI,EAAE,cAAc,GACnB,OAAO,CAAC,aAAa,CAAC,CAsBxB"}
@@ -0,0 +1,128 @@
1
+ import { execFile } from "node:child_process";
2
+ import { existsSync } from "node:fs";
3
+ import { join, relative } from "node:path";
4
+ export const VALID_BACKENDS = [
5
+ "cursor",
6
+ "claude",
7
+ "none",
8
+ ];
9
+ /**
10
+ * Build the analysis instruction for a specific recording session.
11
+ */
12
+ function buildInstruction(sessionName) {
13
+ return `"请先阅读 recordings/${sessionName}/_context.md 了解录制数据全貌,然后按照 AGENTS.md 中的指示完成分析,并将报告文件保存到对应位置。如需查看被截断的完整请求/响应体,请查阅 requests/ 和 responses/ 目录下的原始文件。"`;
14
+ }
15
+ /**
16
+ * Run AI analysis on a recording session.
17
+ * Returns an AnalyzeResult indicating whether the report was created.
18
+ */
19
+ export async function analyzeRecording(opts) {
20
+ const { backend, workspace, sessionDir, model } = opts;
21
+ const sessionName = relative(workspace.recordings, sessionDir);
22
+ const reportPath = join(workspace.recordings, sessionName, "analysis_report.md");
23
+ const startTime = Date.now();
24
+ if (backend === "cursor") {
25
+ await runCursor(workspace.root, sessionName, model, opts.onLog);
26
+ }
27
+ else if (backend === "claude") {
28
+ await runClaude(workspace.root, sessionName, opts.onLog);
29
+ }
30
+ else {
31
+ throw new Error(`Unsupported analyzer backend: ${backend}`);
32
+ }
33
+ const duration = Date.now() - startTime;
34
+ const success = existsSync(reportPath);
35
+ return { success, reportPath, sessionName, duration };
36
+ }
37
+ /**
38
+ * Run analysis via `agent` CLI (Cursor).
39
+ * cwd is the workspace root so the agent reads AGENTS.md.
40
+ */
41
+ async function runCursor(workspaceRoot, sessionName, model, onLog) {
42
+ return new Promise((resolve, reject) => {
43
+ const instruction = buildInstruction(sessionName);
44
+ const args = [instruction, "--print", "--trust", "--yolo"];
45
+ if (model) {
46
+ args.push("--model", model);
47
+ }
48
+ const child = execFile("agent", args, {
49
+ cwd: workspaceRoot,
50
+ maxBuffer: 10 * 1024 * 1024,
51
+ timeout: 5 * 60 * 1000,
52
+ }, (error, _stdout, stderr) => {
53
+ if (error) {
54
+ if (stderr) {
55
+ console.error("[analyzer] agent stderr:", stderr);
56
+ }
57
+ reject(new Error(`agent failed: ${error.message}`));
58
+ return;
59
+ }
60
+ resolve();
61
+ });
62
+ if (onLog) {
63
+ child.stdout?.on("data", (data) => {
64
+ const lines = data.toString().split("\n");
65
+ for (const line of lines) {
66
+ if (line.trim())
67
+ onLog(line.trim());
68
+ }
69
+ });
70
+ child.stderr?.on("data", (data) => {
71
+ const lines = data.toString().split("\n");
72
+ for (const line of lines) {
73
+ if (line.trim())
74
+ onLog(line.trim());
75
+ }
76
+ });
77
+ }
78
+ child.on("error", (err) => {
79
+ reject(new Error(`Failed to launch agent: ${err.message}. ` +
80
+ "Ensure the Cursor `agent` CLI is on your PATH."));
81
+ });
82
+ });
83
+ }
84
+ /**
85
+ * Run analysis via `claude` CLI (Claude Code).
86
+ * cwd is the workspace root so claude reads AGENTS.md.
87
+ */
88
+ async function runClaude(workspaceRoot, sessionName, onLog) {
89
+ return new Promise((resolve, reject) => {
90
+ const instruction = buildInstruction(sessionName);
91
+ const args = ["-p", instruction];
92
+ const child = execFile("claude", args, {
93
+ cwd: workspaceRoot,
94
+ maxBuffer: 10 * 1024 * 1024,
95
+ timeout: 5 * 60 * 1000,
96
+ }, (error, _stdout, stderr) => {
97
+ if (error) {
98
+ if (stderr) {
99
+ console.error("[analyzer] claude stderr:", stderr);
100
+ }
101
+ reject(new Error(`claude failed: ${error.message}`));
102
+ return;
103
+ }
104
+ resolve();
105
+ });
106
+ if (onLog) {
107
+ child.stdout?.on("data", (data) => {
108
+ const lines = data.toString().split("\n");
109
+ for (const line of lines) {
110
+ if (line.trim())
111
+ onLog(line.trim());
112
+ }
113
+ });
114
+ child.stderr?.on("data", (data) => {
115
+ const lines = data.toString().split("\n");
116
+ for (const line of lines) {
117
+ if (line.trim())
118
+ onLog(line.trim());
119
+ }
120
+ });
121
+ }
122
+ child.on("error", (err) => {
123
+ reject(new Error(`Failed to launch claude: ${err.message}. ` +
124
+ "Ensure Claude Code is installed and the `claude` CLI is on your PATH."));
125
+ });
126
+ });
127
+ }
128
+ //# 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,36 @@
1
+ import type { AnalyzerBackend } from './analyzer.js';
2
+ export interface WebtapeConfig {
3
+ aiBackend?: AnalyzerBackend;
4
+ aiModel?: string;
5
+ }
6
+ /**
7
+ * Load the persisted configuration, returning an empty object if none exists.
8
+ */
9
+ export declare function loadConfig(): WebtapeConfig;
10
+ /**
11
+ * Save the configuration to disk (merges with existing).
12
+ */
13
+ export declare function saveConfig(partial: Partial<WebtapeConfig>): WebtapeConfig;
14
+ interface SelectOption<T> {
15
+ label: string;
16
+ value: T;
17
+ hint?: string;
18
+ }
19
+ /**
20
+ * Show an interactive list that the user navigates with arrow keys.
21
+ * Returns the selected value, or null if the user pressed ESC.
22
+ */
23
+ export declare function selectItem<T>(title: string, options: SelectOption<T>[], initialIndex?: number): Promise<T | null>;
24
+ /**
25
+ * Run the interactive configuration wizard.
26
+ * Steps through each config item in sequence; ESC exits without saving.
27
+ * Returns the saved config, or null if aborted.
28
+ */
29
+ export declare function runConfigWizard(): Promise<WebtapeConfig | null>;
30
+ /**
31
+ * Prompt for AI backend interactively.
32
+ * Used by the serve command when no backend is configured yet.
33
+ */
34
+ export declare function promptAiBackend(): Promise<AnalyzerBackend>;
35
+ export {};
36
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAKrD,MAAM,WAAW,aAAa;IAC5B,SAAS,CAAC,EAAE,eAAe,CAAC;IAC5B,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;GAEG;AACH,wBAAgB,UAAU,IAAI,aAAa,CAQ1C;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,OAAO,EAAE,OAAO,CAAC,aAAa,CAAC,GAAG,aAAa,CAQzE;AAMD,UAAU,YAAY,CAAC,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,CAAC,CAAC;IACT,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AA0BD;;;GAGG;AACH,wBAAsB,UAAU,CAAC,CAAC,EAChC,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,YAAY,CAAC,CAAC,CAAC,EAAE,EAC1B,YAAY,SAAI,GACf,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC,CAkDnB;AAwBD;;;;GAIG;AACH,wBAAsB,eAAe,IAAI,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC,CAuCrE;AAED;;;GAGG;AACH,wBAAsB,eAAe,IAAI,OAAO,CAAC,eAAe,CAAC,CAGhE"}
package/dist/config.js ADDED
@@ -0,0 +1,158 @@
1
+ import { readFileSync, writeFileSync, existsSync, mkdirSync } from 'node:fs';
2
+ import { join } from 'node:path';
3
+ import { homedir } from 'node:os';
4
+ import chalk from 'chalk';
5
+ const CONFIG_DIR = join(homedir(), '.webtape-receiver');
6
+ const CONFIG_PATH = join(CONFIG_DIR, 'config.json');
7
+ /**
8
+ * Load the persisted configuration, returning an empty object if none exists.
9
+ */
10
+ export function loadConfig() {
11
+ if (!existsSync(CONFIG_PATH))
12
+ return {};
13
+ try {
14
+ return JSON.parse(readFileSync(CONFIG_PATH, 'utf-8'));
15
+ }
16
+ catch (err) {
17
+ console.warn('Failed to parse config file, using defaults:', err.message);
18
+ return {};
19
+ }
20
+ }
21
+ /**
22
+ * Save the configuration to disk (merges with existing).
23
+ */
24
+ export function saveConfig(partial) {
25
+ const current = loadConfig();
26
+ const merged = { ...current, ...partial };
27
+ if (!existsSync(CONFIG_DIR)) {
28
+ mkdirSync(CONFIG_DIR, { recursive: true });
29
+ }
30
+ writeFileSync(CONFIG_PATH, JSON.stringify(merged, null, 2), 'utf-8');
31
+ return merged;
32
+ }
33
+ /** Re-render the selector list in-place by moving the cursor up and overwriting. */
34
+ function renderSelector(title, options, cursor, isFirst) {
35
+ const lineCount = options.length + 2; // blank line + title + options
36
+ if (!isFirst) {
37
+ process.stdout.write(`\x1b[${lineCount}A`); // move up
38
+ process.stdout.write('\x1b[0J'); // clear to end of screen
39
+ }
40
+ process.stdout.write(`\n ${chalk.bold(title)}\n`);
41
+ for (let i = 0; i < options.length; i++) {
42
+ const opt = options[i];
43
+ const hint = opt.hint ? chalk.gray(` ${opt.hint}`) : '';
44
+ if (i === cursor) {
45
+ process.stdout.write(` ${chalk.cyan('❯')} ${chalk.cyan(opt.label)}${hint}\n`);
46
+ }
47
+ else {
48
+ process.stdout.write(` ${chalk.dim(opt.label)}${hint}\n`);
49
+ }
50
+ }
51
+ }
52
+ /**
53
+ * Show an interactive list that the user navigates with arrow keys.
54
+ * Returns the selected value, or null if the user pressed ESC.
55
+ */
56
+ export async function selectItem(title, options, initialIndex = 0) {
57
+ if (!process.stdin.isTTY) {
58
+ // Non-interactive fallback: return first/current option silently
59
+ return options[Math.max(0, Math.min(initialIndex, options.length - 1))].value;
60
+ }
61
+ let cursor = Math.max(0, Math.min(initialIndex, options.length - 1));
62
+ renderSelector(title, options, cursor, true);
63
+ return new Promise((resolve) => {
64
+ const { stdin } = process;
65
+ stdin.setRawMode(true);
66
+ stdin.resume();
67
+ stdin.setEncoding('utf-8');
68
+ const cleanup = () => {
69
+ stdin.removeListener('data', onData);
70
+ stdin.setRawMode(false);
71
+ stdin.pause();
72
+ };
73
+ const onData = (key) => {
74
+ if (key === '\x1b[A') {
75
+ // Up arrow — previous option
76
+ cursor = (cursor - 1 + options.length) % options.length;
77
+ renderSelector(title, options, cursor, false);
78
+ }
79
+ else if (key === '\x1b[B') {
80
+ // Down arrow — next option
81
+ cursor = (cursor + 1) % options.length;
82
+ renderSelector(title, options, cursor, false);
83
+ }
84
+ else if (key === '\r' || key === '\n') {
85
+ // Enter — confirm selection
86
+ cleanup();
87
+ process.stdout.write('\n');
88
+ resolve(options[cursor].value);
89
+ }
90
+ else if (key === '\x1b') {
91
+ // ESC — abort
92
+ cleanup();
93
+ process.stdout.write('\n');
94
+ resolve(null);
95
+ }
96
+ else if (key === '\x03') {
97
+ // Ctrl+C
98
+ cleanup();
99
+ process.stdout.write('\n');
100
+ process.exit(0);
101
+ }
102
+ };
103
+ stdin.on('data', onData);
104
+ });
105
+ }
106
+ const CONFIG_STEPS = [
107
+ {
108
+ key: 'aiBackend',
109
+ title: '请选择 AI 分析后端 / Select AI analysis backend',
110
+ options: [
111
+ { label: 'cursor', value: 'cursor', hint: 'Cursor Agent (agent …)' },
112
+ { label: 'claude', value: 'claude', hint: 'Claude Code (claude -p …)' },
113
+ { label: '不分析', value: 'none', hint: '仅接收并保存录制数据,不自动运行 AI 分析' },
114
+ ],
115
+ },
116
+ ];
117
+ /**
118
+ * Run the interactive configuration wizard.
119
+ * Steps through each config item in sequence; ESC exits without saving.
120
+ * Returns the saved config, or null if aborted.
121
+ */
122
+ export async function runConfigWizard() {
123
+ const current = loadConfig();
124
+ const result = { ...current };
125
+ console.log('');
126
+ console.log(chalk.bold.cyan(' ⚙️ WebTape 配置向导'));
127
+ console.log(chalk.gray(' ↑↓ 选择 Enter 确认 Esc 退出'));
128
+ console.log(chalk.gray(' ─────────────────────────────────'));
129
+ for (const step of CONFIG_STEPS) {
130
+ const currentVal = result[step.key];
131
+ const initialIdx = step.options.findIndex((o) => o.value === currentVal);
132
+ const selected = await selectItem(step.title, step.options, initialIdx >= 0 ? initialIdx : 0);
133
+ if (selected === null) {
134
+ console.log(chalk.gray(' 已取消,配置未更改。\n'));
135
+ return null;
136
+ }
137
+ result[step.key] = selected;
138
+ }
139
+ const saved = saveConfig(result);
140
+ console.log(chalk.green(' ✅ 配置已保存:'));
141
+ for (const step of CONFIG_STEPS) {
142
+ const val = saved[step.key];
143
+ if (val !== undefined) {
144
+ console.log(` ${chalk.green(step.key)} ${val}`);
145
+ }
146
+ }
147
+ console.log('');
148
+ return saved;
149
+ }
150
+ /**
151
+ * Prompt for AI backend interactively.
152
+ * Used by the serve command when no backend is configured yet.
153
+ */
154
+ export async function promptAiBackend() {
155
+ const result = await runConfigWizard();
156
+ return (result?.aiBackend ?? 'cursor');
157
+ }
158
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import type { WebTapePayload } from './types.js';
2
+ export declare function extractSiteUrl(payload: WebTapePayload): string;
3
+ export declare function renderAnalysisContext(payload: WebTapePayload, siteUrl: string): string;
4
+ //# sourceMappingURL=context.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EACV,cAAc,EAKf,MAAM,YAAY,CAAC;AAoSpB,wBAAgB,cAAc,CAAC,OAAO,EAAE,cAAc,GAAG,MAAM,CAK9D;AAED,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,cAAc,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CActF"}