deepspider 0.2.11 → 0.3.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.
- package/README.md +71 -24
- package/bin/cli.js +45 -0
- package/package.json +10 -4
- package/src/agent/core/PanelBridge.js +133 -0
- package/src/agent/core/RetryManager.js +51 -0
- package/src/agent/core/StreamHandler.js +263 -0
- package/src/agent/core/index.js +7 -0
- package/src/agent/errors/ErrorClassifier.js +43 -0
- package/src/agent/errors/SpiderError.js +68 -0
- package/src/agent/errors/index.js +19 -0
- package/src/agent/run.js +67 -460
- package/src/agent/setup.js +14 -14
- package/src/agent/subagents/factory.js +60 -0
- package/src/agent/subagents/index.js +3 -0
- package/src/agent/tools/report.js +36 -4
- package/src/browser/client.js +47 -10
- package/src/cli/commands/config.js +94 -0
- package/src/cli/commands/help.js +34 -0
- package/src/cli/commands/update.js +78 -0
- package/src/cli/commands/version.js +9 -0
- package/src/cli/config.js +15 -0
- package/src/config/settings.js +102 -0
- package/.claude/agents/check.md +0 -122
- package/.claude/agents/debug.md +0 -106
- package/.claude/agents/dispatch.md +0 -214
- package/.claude/agents/implement.md +0 -96
- package/.claude/agents/plan.md +0 -396
- package/.claude/agents/research.md +0 -120
- package/.claude/commands/evolve/merge.md +0 -80
- package/.claude/commands/trellis/before-backend-dev.md +0 -13
- package/.claude/commands/trellis/before-frontend-dev.md +0 -13
- package/.claude/commands/trellis/break-loop.md +0 -107
- package/.claude/commands/trellis/check-backend.md +0 -13
- package/.claude/commands/trellis/check-cross-layer.md +0 -153
- package/.claude/commands/trellis/check-frontend.md +0 -13
- package/.claude/commands/trellis/create-command.md +0 -154
- package/.claude/commands/trellis/finish-work.md +0 -129
- package/.claude/commands/trellis/integrate-skill.md +0 -219
- package/.claude/commands/trellis/onboard.md +0 -358
- package/.claude/commands/trellis/parallel.md +0 -193
- package/.claude/commands/trellis/record-session.md +0 -62
- package/.claude/commands/trellis/start.md +0 -280
- package/.claude/commands/trellis/update-spec.md +0 -213
- package/.claude/hooks/inject-subagent-context.py +0 -758
- package/.claude/hooks/ralph-loop.py +0 -374
- package/.claude/hooks/session-start.py +0 -126
- package/.claude/settings.json +0 -41
- package/.claude/skills/deepagents-guide/SKILL.md +0 -428
- package/.cursor/commands/trellis-before-backend-dev.md +0 -13
- package/.cursor/commands/trellis-before-frontend-dev.md +0 -13
- package/.cursor/commands/trellis-break-loop.md +0 -107
- package/.cursor/commands/trellis-check-backend.md +0 -13
- package/.cursor/commands/trellis-check-cross-layer.md +0 -153
- package/.cursor/commands/trellis-check-frontend.md +0 -13
- package/.cursor/commands/trellis-create-command.md +0 -154
- package/.cursor/commands/trellis-finish-work.md +0 -129
- package/.cursor/commands/trellis-integrate-skill.md +0 -219
- package/.cursor/commands/trellis-onboard.md +0 -358
- package/.cursor/commands/trellis-record-session.md +0 -62
- package/.cursor/commands/trellis-start.md +0 -156
- package/.cursor/commands/trellis-update-spec.md +0 -213
- package/.github/workflows/publish.yml +0 -63
- package/.husky/pre-commit +0 -1
- package/.mcp.json +0 -8
- package/.trellis/.template-hashes.json +0 -65
- package/.trellis/.version +0 -1
- package/.trellis/scripts/add-session.sh +0 -384
- package/.trellis/scripts/common/developer.sh +0 -129
- package/.trellis/scripts/common/git-context.sh +0 -263
- package/.trellis/scripts/common/paths.sh +0 -208
- package/.trellis/scripts/common/phase.sh +0 -150
- package/.trellis/scripts/common/registry.sh +0 -247
- package/.trellis/scripts/common/task-queue.sh +0 -142
- package/.trellis/scripts/common/task-utils.sh +0 -151
- package/.trellis/scripts/common/worktree.sh +0 -128
- package/.trellis/scripts/create-bootstrap.sh +0 -299
- package/.trellis/scripts/get-context.sh +0 -7
- package/.trellis/scripts/get-developer.sh +0 -15
- package/.trellis/scripts/init-developer.sh +0 -34
- package/.trellis/scripts/multi-agent/cleanup.sh +0 -396
- package/.trellis/scripts/multi-agent/create-pr.sh +0 -241
- package/.trellis/scripts/multi-agent/plan.sh +0 -207
- package/.trellis/scripts/multi-agent/start.sh +0 -310
- package/.trellis/scripts/multi-agent/status.sh +0 -828
- package/.trellis/scripts/task.sh +0 -1118
- package/.trellis/spec/backend/ci-cd-guidelines.md +0 -73
- package/.trellis/spec/backend/deepagents-guide.md +0 -380
- package/.trellis/spec/backend/directory-structure.md +0 -126
- package/.trellis/spec/backend/examples/skills/deepagents-guide/README.md +0 -11
- package/.trellis/spec/backend/examples/skills/deepagents-guide/agent.js.template +0 -20
- package/.trellis/spec/backend/examples/skills/deepagents-guide/skills-config.js.template +0 -13
- package/.trellis/spec/backend/examples/skills/deepagents-guide/subagent.js.template +0 -19
- package/.trellis/spec/backend/hook-guidelines.md +0 -218
- package/.trellis/spec/backend/index.md +0 -37
- package/.trellis/spec/backend/quality-guidelines.md +0 -302
- package/.trellis/spec/backend/state-management.md +0 -76
- package/.trellis/spec/backend/tool-guidelines.md +0 -144
- package/.trellis/spec/backend/type-safety.md +0 -71
- package/.trellis/spec/guides/code-reuse-thinking-guide.md +0 -92
- package/.trellis/spec/guides/cross-layer-thinking-guide.md +0 -94
- package/.trellis/spec/guides/index.md +0 -79
- package/.trellis/tasks/archive/02-02-evolving-skills/prd.md +0 -61
- package/.trellis/tasks/archive/02-02-evolving-skills/task.json +0 -29
- package/.trellis/tasks/archive/2026-02/00-bootstrap-guidelines/prd.md +0 -86
- package/.trellis/tasks/archive/2026-02/00-bootstrap-guidelines/task.json +0 -27
- package/.trellis/tasks/archive/2026-02/02-02-skills-system/check.jsonl +0 -3
- package/.trellis/tasks/archive/2026-02/02-02-skills-system/debug.jsonl +0 -2
- package/.trellis/tasks/archive/2026-02/02-02-skills-system/implement.jsonl +0 -5
- package/.trellis/tasks/archive/2026-02/02-02-skills-system/prd.md +0 -33
- package/.trellis/tasks/archive/2026-02/02-02-skills-system/task.json +0 -41
- package/.trellis/workflow.md +0 -407
- package/.trellis/workspace/index.md +0 -123
- package/.trellis/workspace/pony/index.md +0 -42
- package/.trellis/workspace/pony/journal-1.md +0 -125
- package/.trellis/worktree.yaml +0 -47
- package/AGENTS.md +0 -18
- package/CLAUDE.md +0 -315
- package/agents/deepspider.md +0 -142
- package/docs/DEBUG.md +0 -42
- package/docs/GUIDE.md +0 -334
- package/docs/PROMPT.md +0 -60
- package/docs/USAGE.md +0 -226
- package/eslint.config.js +0 -51
- package/test/analyze.test.js +0 -90
- package/test/envdump.test.js +0 -74
- package/test/flow.test.js +0 -90
- package/test/hooks.test.js +0 -138
- package/test/plugin.test.js +0 -35
- package/test/refactor-full.test.js +0 -30
- package/test/refactor.test.js +0 -21
- package/test/samples/obfuscated.js +0 -61
- package/test/samples/original.js +0 -66
- package/test/samples/v10_eval_chain.js +0 -52
- package/test/samples/v11_bytecode_vm.js +0 -81
- package/test/samples/v12_polymorphic.js +0 -69
- package/test/samples/v1_ob_basic.js +0 -98
- package/test/samples/v2_ob_advanced.js +0 -99
- package/test/samples/v3_jjencode.js +0 -77
- package/test/samples/v4_aaencode.js +0 -73
- package/test/samples/v5_control_flow.js +0 -86
- package/test/samples/v6_string_encryption.js +0 -71
- package/test/samples/v7_jsvmp.js +0 -83
- package/test/samples/v8_anti_debug.js +0 -79
- package/test/samples/v9_proxy_trap.js +0 -49
- package/test/samples.test.js +0 -96
- package/test/webcrack.test.js +0 -55
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DeepSpider - 子代理工厂函数
|
|
3
|
+
* 统一子代理创建,自动注入公共配置
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { createSkillsMiddleware } from 'deepagents';
|
|
7
|
+
import { SKILLS, skillsBackend } from '../skills/config.js';
|
|
8
|
+
import { createFilterToolsMiddleware } from '../middleware/filterTools.js';
|
|
9
|
+
import { evolveTools } from '../tools/evolve.js';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* 创建子代理配置
|
|
13
|
+
* @param {Object} config - 子代理配置
|
|
14
|
+
* @param {string} config.name - 子代理名称
|
|
15
|
+
* @param {string} config.description - 子代理描述
|
|
16
|
+
* @param {string} config.systemPrompt - 系统提示
|
|
17
|
+
* @param {Array} config.tools - 工具列表
|
|
18
|
+
* @param {Array} [config.skills] - 技能源列表(SKILLS 枚举值)
|
|
19
|
+
* @param {Array} [config.middleware] - 额外的中间件
|
|
20
|
+
* @param {boolean} [config.includeEvolve=true] - 是否包含 evolve 工具
|
|
21
|
+
*/
|
|
22
|
+
export function createSubagent(config) {
|
|
23
|
+
const {
|
|
24
|
+
name,
|
|
25
|
+
description,
|
|
26
|
+
systemPrompt,
|
|
27
|
+
tools,
|
|
28
|
+
skills = [],
|
|
29
|
+
middleware = [],
|
|
30
|
+
includeEvolve = true,
|
|
31
|
+
} = config;
|
|
32
|
+
|
|
33
|
+
// 合并工具列表
|
|
34
|
+
const finalTools = includeEvolve
|
|
35
|
+
? [...tools, ...evolveTools]
|
|
36
|
+
: tools;
|
|
37
|
+
|
|
38
|
+
// 构建中间件列表
|
|
39
|
+
const finalMiddleware = [
|
|
40
|
+
createFilterToolsMiddleware(),
|
|
41
|
+
createSkillsMiddleware({
|
|
42
|
+
backend: skillsBackend,
|
|
43
|
+
sources: skills,
|
|
44
|
+
}),
|
|
45
|
+
...middleware,
|
|
46
|
+
];
|
|
47
|
+
|
|
48
|
+
return {
|
|
49
|
+
name,
|
|
50
|
+
description,
|
|
51
|
+
systemPrompt,
|
|
52
|
+
tools: finalTools,
|
|
53
|
+
middleware: finalMiddleware,
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* 预定义的技能映射
|
|
59
|
+
*/
|
|
60
|
+
export { SKILLS };
|
|
@@ -102,8 +102,24 @@ function generateHtmlPage(title, markdown, pythonCode, jsCode) {
|
|
|
102
102
|
* 2. 传入代码内容(兼容)- pythonCode/jsCode
|
|
103
103
|
*/
|
|
104
104
|
export const saveAnalysisReport = tool(
|
|
105
|
-
async ({ domain, title, markdown, pythonCode, pythonCodeFile, jsCode, jsCodeFile }) => {
|
|
105
|
+
async ({ domain, title, markdown, pythonCode, pythonCodeFile, jsCode, jsCodeFile, validationResult }) => {
|
|
106
106
|
try {
|
|
107
|
+
// 验证状态检查
|
|
108
|
+
let validationWarning = '';
|
|
109
|
+
let validationStatus = 'unknown';
|
|
110
|
+
|
|
111
|
+
if (!validationResult) {
|
|
112
|
+
validationWarning = '⚠️ 警告:未提供端到端验证结果,建议先使用 verify_encryption 或 run_python 验证代码正确性';
|
|
113
|
+
validationStatus = 'not_verified';
|
|
114
|
+
console.warn('[report]', validationWarning);
|
|
115
|
+
} else if (validationResult.success === false) {
|
|
116
|
+
validationWarning = `⚠️ 警告:验证失败 - ${validationResult.error || '未知错误'}`;
|
|
117
|
+
validationStatus = 'failed';
|
|
118
|
+
console.warn('[report]', validationWarning);
|
|
119
|
+
} else {
|
|
120
|
+
validationStatus = 'passed';
|
|
121
|
+
}
|
|
122
|
+
|
|
107
123
|
const domainDir = join(OUTPUT_DIR, extractDomain(domain));
|
|
108
124
|
ensureDir(domainDir);
|
|
109
125
|
|
|
@@ -153,18 +169,30 @@ export const saveAnalysisReport = tool(
|
|
|
153
169
|
const fileList = Object.entries(paths)
|
|
154
170
|
.map(([type, p]) => `- ${type}: \`${p}\``)
|
|
155
171
|
.join('\n');
|
|
156
|
-
|
|
172
|
+
|
|
173
|
+
// 添加验证状态标记
|
|
174
|
+
const validationSection = validationWarning
|
|
175
|
+
? `\n\n## 验证状态\n\n${validationWarning}\n`
|
|
176
|
+
: '\n\n## 验证状态\n\n✅ 端到端验证通过\n';
|
|
177
|
+
|
|
178
|
+
const finalMarkdown = markdown + validationSection + '\n## 生成文件\n\n' + fileList;
|
|
157
179
|
writeFileSync(paths.markdown, finalMarkdown, 'utf-8');
|
|
158
180
|
|
|
159
181
|
console.log('[report] 已保存:', domainDir);
|
|
160
|
-
return JSON.stringify({
|
|
182
|
+
return JSON.stringify({
|
|
183
|
+
success: true,
|
|
184
|
+
paths,
|
|
185
|
+
dir: domainDir,
|
|
186
|
+
validationStatus,
|
|
187
|
+
validationWarning: validationWarning || null,
|
|
188
|
+
});
|
|
161
189
|
} catch (e) {
|
|
162
190
|
return JSON.stringify({ success: false, error: e.message });
|
|
163
191
|
}
|
|
164
192
|
},
|
|
165
193
|
{
|
|
166
194
|
name: 'save_analysis_report',
|
|
167
|
-
description: `保存分析报告。推荐先用 artifact_save
|
|
195
|
+
description: `保存分析报告。推荐先用 artifact_save 保存代码文件,再传入文件路径。建议先验证代码正确性再保存报告。`,
|
|
168
196
|
schema: z.object({
|
|
169
197
|
domain: z.string().describe('网站域名'),
|
|
170
198
|
title: z.string().optional().describe('报告标题'),
|
|
@@ -173,6 +201,10 @@ export const saveAnalysisReport = tool(
|
|
|
173
201
|
pythonCode: z.string().optional().describe('Python 代码内容(不推荐)'),
|
|
174
202
|
jsCodeFile: z.string().optional().describe('JS 代码文件路径'),
|
|
175
203
|
jsCode: z.string().optional().describe('JS 代码内容'),
|
|
204
|
+
validationResult: z.object({
|
|
205
|
+
success: z.boolean().describe('验证是否成功'),
|
|
206
|
+
error: z.string().optional().describe('错误信息'),
|
|
207
|
+
}).optional().describe('端到端验证结果(推荐提供)'),
|
|
176
208
|
}),
|
|
177
209
|
}
|
|
178
210
|
);
|
package/src/browser/client.js
CHANGED
|
@@ -4,13 +4,15 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import { chromium } from 'patchright';
|
|
7
|
+
import { EventEmitter } from 'events';
|
|
7
8
|
import { getDefaultHookScript } from './defaultHooks.js';
|
|
8
9
|
import { NetworkInterceptor } from './interceptors/NetworkInterceptor.js';
|
|
9
10
|
import { ScriptInterceptor } from './interceptors/ScriptInterceptor.js';
|
|
10
11
|
import { getDataStore } from '../store/DataStore.js';
|
|
11
12
|
|
|
12
|
-
export class BrowserClient {
|
|
13
|
+
export class BrowserClient extends EventEmitter {
|
|
13
14
|
constructor() {
|
|
15
|
+
super();
|
|
14
16
|
this.browser = null;
|
|
15
17
|
this.context = null;
|
|
16
18
|
this.page = null;
|
|
@@ -20,6 +22,7 @@ export class BrowserClient {
|
|
|
20
22
|
this.scriptInterceptor = null;
|
|
21
23
|
this.hookScript = null;
|
|
22
24
|
this.onMessage = null;
|
|
25
|
+
this._isCleaningUp = false;
|
|
23
26
|
}
|
|
24
27
|
|
|
25
28
|
/**
|
|
@@ -51,6 +54,8 @@ export class BrowserClient {
|
|
|
51
54
|
}
|
|
52
55
|
|
|
53
56
|
this.browser = await chromium.launch(launchOptions);
|
|
57
|
+
this.emit('launched', { headless });
|
|
58
|
+
|
|
54
59
|
this.context = await this.browser.newContext({
|
|
55
60
|
ignoreHTTPSErrors: true,
|
|
56
61
|
});
|
|
@@ -183,15 +188,47 @@ export class BrowserClient {
|
|
|
183
188
|
* 关闭浏览器
|
|
184
189
|
*/
|
|
185
190
|
async close() {
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
191
|
+
await this.cleanup();
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* 清理所有资源
|
|
196
|
+
*/
|
|
197
|
+
async cleanup() {
|
|
198
|
+
if (this._isCleaningUp) return;
|
|
199
|
+
this._isCleaningUp = true;
|
|
200
|
+
|
|
201
|
+
try {
|
|
202
|
+
// 停止拦截器
|
|
203
|
+
if (this.networkInterceptor) {
|
|
204
|
+
await this.networkInterceptor.stop?.().catch(() => {});
|
|
205
|
+
this.networkInterceptor = null;
|
|
206
|
+
}
|
|
207
|
+
if (this.scriptInterceptor) {
|
|
208
|
+
await this.scriptInterceptor.stop?.().catch(() => {});
|
|
209
|
+
this.scriptInterceptor = null;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
// 分离 CDP session
|
|
213
|
+
if (this.cdpSession) {
|
|
214
|
+
await this.cdpSession.detach().catch(() => {});
|
|
215
|
+
this.cdpSession = null;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// 关闭浏览器
|
|
219
|
+
if (this.browser) {
|
|
220
|
+
await this.browser.close();
|
|
221
|
+
this.browser = null;
|
|
222
|
+
this.context = null;
|
|
223
|
+
this.page = null;
|
|
224
|
+
this.pages = [];
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
this.emit('closed');
|
|
228
|
+
} catch (e) {
|
|
229
|
+
this.emit('error', e);
|
|
230
|
+
} finally {
|
|
231
|
+
this._isCleaningUp = false;
|
|
195
232
|
}
|
|
196
233
|
}
|
|
197
234
|
}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* deepspider config 子命令
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import {
|
|
6
|
+
loadConfig,
|
|
7
|
+
saveConfig,
|
|
8
|
+
getEffectiveConfig,
|
|
9
|
+
resetConfig,
|
|
10
|
+
CONFIG_FILE,
|
|
11
|
+
ENV_MAP,
|
|
12
|
+
DEFAULTS,
|
|
13
|
+
} from '../config.js';
|
|
14
|
+
|
|
15
|
+
export function run(args) {
|
|
16
|
+
const sub = args[0] || 'list';
|
|
17
|
+
|
|
18
|
+
switch (sub) {
|
|
19
|
+
case 'list':
|
|
20
|
+
return list();
|
|
21
|
+
case 'get':
|
|
22
|
+
return get(args[1]);
|
|
23
|
+
case 'set':
|
|
24
|
+
return set(args[1], args[2]);
|
|
25
|
+
case 'reset':
|
|
26
|
+
return reset();
|
|
27
|
+
case 'path':
|
|
28
|
+
return path();
|
|
29
|
+
default:
|
|
30
|
+
console.error(`未知子命令: ${sub}\n可用: list, get, set, reset, path`);
|
|
31
|
+
process.exit(1);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function list() {
|
|
36
|
+
const effective = getEffectiveConfig();
|
|
37
|
+
console.log('配置项:');
|
|
38
|
+
for (const [key, { value, source }] of Object.entries(effective)) {
|
|
39
|
+
const display = key === 'apiKey' && value ? maskKey(value) : value || '(未设置)';
|
|
40
|
+
console.log(` ${key} = ${display} [${source}]`);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function get(key) {
|
|
45
|
+
if (!key) {
|
|
46
|
+
console.error('用法: deepspider config get <key>');
|
|
47
|
+
process.exit(1);
|
|
48
|
+
}
|
|
49
|
+
if (!Object.hasOwn(DEFAULTS, key)) {
|
|
50
|
+
console.error(`未知配置项: ${key}\n可用: ${Object.keys(DEFAULTS).join(', ')}`);
|
|
51
|
+
process.exit(1);
|
|
52
|
+
}
|
|
53
|
+
const effective = getEffectiveConfig();
|
|
54
|
+
const { value, source } = effective[key];
|
|
55
|
+
const display = key === 'apiKey' && value ? maskKey(value) : value || '(未设置)';
|
|
56
|
+
console.log(`${key} = ${display} [${source}]`);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function set(key, value) {
|
|
60
|
+
if (!key || value === undefined) {
|
|
61
|
+
console.error('用法: deepspider config set <key> <value>');
|
|
62
|
+
process.exit(1);
|
|
63
|
+
}
|
|
64
|
+
if (!Object.hasOwn(DEFAULTS, key)) {
|
|
65
|
+
console.error(`未知配置项: ${key}\n可用: ${Object.keys(DEFAULTS).join(', ')}`);
|
|
66
|
+
process.exit(1);
|
|
67
|
+
}
|
|
68
|
+
const config = loadConfig();
|
|
69
|
+
config[key] = value;
|
|
70
|
+
saveConfig(config);
|
|
71
|
+
|
|
72
|
+
const envVar = ENV_MAP[key];
|
|
73
|
+
console.log(`已设置 ${key} = ${key === 'apiKey' ? maskKey(value) : value}`);
|
|
74
|
+
if (process.env[envVar]) {
|
|
75
|
+
console.log(`注意: 环境变量 ${envVar} 已设置,将优先使用环境变量的值`);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function reset() {
|
|
80
|
+
if (resetConfig()) {
|
|
81
|
+
console.log('配置已重置');
|
|
82
|
+
} else {
|
|
83
|
+
console.log('配置文件不存在,无需重置');
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function path() {
|
|
88
|
+
console.log(CONFIG_FILE);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function maskKey(key) {
|
|
92
|
+
if (key.length <= 8) return '****';
|
|
93
|
+
return key.slice(0, 4) + '****' + key.slice(-4);
|
|
94
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* deepspider --help
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { getVersion } from '../../config/settings.js';
|
|
6
|
+
|
|
7
|
+
export function run() {
|
|
8
|
+
console.log(`
|
|
9
|
+
deepspider v${getVersion()} - 智能爬虫工程平台
|
|
10
|
+
|
|
11
|
+
用法:
|
|
12
|
+
deepspider 启动交互式 Agent
|
|
13
|
+
deepspider <url> 打开目标网站并启动 Agent
|
|
14
|
+
deepspider config 管理配置
|
|
15
|
+
deepspider update 检查更新
|
|
16
|
+
|
|
17
|
+
选项:
|
|
18
|
+
-v, --version 显示版本号
|
|
19
|
+
-h, --help 显示帮助信息
|
|
20
|
+
--debug 启用调试模式
|
|
21
|
+
|
|
22
|
+
配置命令:
|
|
23
|
+
deepspider config list 列出所有配置
|
|
24
|
+
deepspider config get <key> 获取配置项
|
|
25
|
+
deepspider config set <key> <val> 设置配置项
|
|
26
|
+
deepspider config reset 重置配置
|
|
27
|
+
deepspider config path 显示配置文件路径
|
|
28
|
+
|
|
29
|
+
示例:
|
|
30
|
+
deepspider https://example.com 分析目标网站
|
|
31
|
+
deepspider config set apiKey sk-xxx
|
|
32
|
+
deepspider config set model gpt-4o
|
|
33
|
+
`.trim());
|
|
34
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* deepspider update
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import readline from 'readline';
|
|
6
|
+
import { existsSync } from 'fs';
|
|
7
|
+
import { execSync } from 'child_process';
|
|
8
|
+
import { join } from 'path';
|
|
9
|
+
import { getVersion } from '../../config/settings.js';
|
|
10
|
+
|
|
11
|
+
export async function run() {
|
|
12
|
+
const current = getVersion();
|
|
13
|
+
|
|
14
|
+
console.log(`当前版本: v${current}`);
|
|
15
|
+
console.log('检查更新...');
|
|
16
|
+
|
|
17
|
+
let latest;
|
|
18
|
+
try {
|
|
19
|
+
const resp = await fetch('https://registry.npmjs.org/deepspider/latest');
|
|
20
|
+
if (!resp.ok) throw new Error(`HTTP ${resp.status}`);
|
|
21
|
+
const data = await resp.json();
|
|
22
|
+
latest = data.version;
|
|
23
|
+
} catch (e) {
|
|
24
|
+
console.error(`检查更新失败: ${e.message}`);
|
|
25
|
+
process.exit(1);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
if (current === latest) {
|
|
29
|
+
console.log(`已是最新版本 v${current}`);
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
console.log(`发现新版本: v${latest}`);
|
|
34
|
+
|
|
35
|
+
const isGlobal = detectGlobalInstall();
|
|
36
|
+
|
|
37
|
+
if (isGlobal) {
|
|
38
|
+
const confirmed = await confirm(`是否更新到 v${latest}?(y/N) `);
|
|
39
|
+
if (!confirmed) {
|
|
40
|
+
console.log('已取消');
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
console.log('正在更新...');
|
|
44
|
+
try {
|
|
45
|
+
execSync('npm install -g deepspider@latest', { stdio: 'inherit' });
|
|
46
|
+
console.log(`已更新到 v${latest}`);
|
|
47
|
+
} catch {
|
|
48
|
+
console.error('更新失败,请手动执行: npm install -g deepspider@latest');
|
|
49
|
+
process.exit(1);
|
|
50
|
+
}
|
|
51
|
+
} else {
|
|
52
|
+
console.log('当前为本地安装,请手动更新:');
|
|
53
|
+
console.log(' git pull && pnpm install');
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function confirm(question) {
|
|
58
|
+
return new Promise((resolve) => {
|
|
59
|
+
const rl = readline.createInterface({
|
|
60
|
+
input: process.stdin,
|
|
61
|
+
output: process.stdout,
|
|
62
|
+
});
|
|
63
|
+
rl.question(question, (answer) => {
|
|
64
|
+
rl.close();
|
|
65
|
+
resolve(answer.toLowerCase() === 'y');
|
|
66
|
+
});
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function detectGlobalInstall() {
|
|
71
|
+
try {
|
|
72
|
+
const globalDir = execSync('npm root -g', { encoding: 'utf-8' }).trim();
|
|
73
|
+
const globalPkg = join(globalDir, 'deepspider');
|
|
74
|
+
return existsSync(globalPkg);
|
|
75
|
+
} catch {
|
|
76
|
+
return false;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DeepSpider 配置管理(核心层)
|
|
3
|
+
* 配置文件:~/.deepspider/config/settings.json
|
|
4
|
+
* 优先级:环境变量 > 配置文件 > 默认值
|
|
5
|
+
*
|
|
6
|
+
* 此模块位于 config/ 层,供 cli/ 和 agent/ 共同依赖
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { join } from 'path';
|
|
10
|
+
import { readFileSync, writeFileSync, existsSync, unlinkSync } from 'fs';
|
|
11
|
+
import { PATHS, ensureDir } from './paths.js';
|
|
12
|
+
|
|
13
|
+
export const CONFIG_FILE = join(PATHS.CONFIG_DIR, 'settings.json');
|
|
14
|
+
|
|
15
|
+
export const DEFAULTS = {
|
|
16
|
+
apiKey: '',
|
|
17
|
+
baseUrl: 'https://api.openai.com/v1',
|
|
18
|
+
model: 'gpt-4o',
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export const ENV_MAP = {
|
|
22
|
+
apiKey: 'DEEPSPIDER_API_KEY',
|
|
23
|
+
baseUrl: 'DEEPSPIDER_BASE_URL',
|
|
24
|
+
model: 'DEEPSPIDER_MODEL',
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* 从配置文件加载
|
|
29
|
+
*/
|
|
30
|
+
export function loadConfig() {
|
|
31
|
+
if (!existsSync(CONFIG_FILE)) return {};
|
|
32
|
+
try {
|
|
33
|
+
return JSON.parse(readFileSync(CONFIG_FILE, 'utf-8'));
|
|
34
|
+
} catch {
|
|
35
|
+
return {};
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* 保存到配置文件
|
|
41
|
+
*/
|
|
42
|
+
export function saveConfig(config) {
|
|
43
|
+
ensureDir(PATHS.CONFIG_DIR);
|
|
44
|
+
writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2) + '\n');
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* 获取有效配置(合并环境变量、配置文件、默认值)
|
|
49
|
+
* 返回 { key: { value, source } }
|
|
50
|
+
*/
|
|
51
|
+
export function getEffectiveConfig() {
|
|
52
|
+
const fileConfig = loadConfig();
|
|
53
|
+
const result = {};
|
|
54
|
+
|
|
55
|
+
for (const key of Object.keys(DEFAULTS)) {
|
|
56
|
+
const envVar = ENV_MAP[key];
|
|
57
|
+
const envVal = process.env[envVar];
|
|
58
|
+
|
|
59
|
+
if (envVal !== undefined && envVal !== '') {
|
|
60
|
+
result[key] = { value: envVal, source: 'env' };
|
|
61
|
+
} else if (fileConfig[key] !== undefined && fileConfig[key] !== '') {
|
|
62
|
+
result[key] = { value: fileConfig[key], source: 'file' };
|
|
63
|
+
} else {
|
|
64
|
+
result[key] = { value: DEFAULTS[key], source: 'default' };
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return result;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* 获取配置值(纯值,用于运行时)
|
|
73
|
+
*/
|
|
74
|
+
export function getConfigValues() {
|
|
75
|
+
const effective = getEffectiveConfig();
|
|
76
|
+
const values = {};
|
|
77
|
+
for (const [key, { value }] of Object.entries(effective)) {
|
|
78
|
+
values[key] = value;
|
|
79
|
+
}
|
|
80
|
+
return values;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* 重置配置文件
|
|
85
|
+
*/
|
|
86
|
+
export function resetConfig() {
|
|
87
|
+
if (existsSync(CONFIG_FILE)) {
|
|
88
|
+
unlinkSync(CONFIG_FILE);
|
|
89
|
+
return true;
|
|
90
|
+
}
|
|
91
|
+
return false;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* 读取 package.json 版本号
|
|
96
|
+
* 基于 import.meta.url 定位,不依赖文件调用位置
|
|
97
|
+
*/
|
|
98
|
+
export function getVersion() {
|
|
99
|
+
const __dirname = new URL('.', import.meta.url).pathname;
|
|
100
|
+
const pkg = JSON.parse(readFileSync(join(__dirname, '../../package.json'), 'utf-8'));
|
|
101
|
+
return pkg.version;
|
|
102
|
+
}
|
package/.claude/agents/check.md
DELETED
|
@@ -1,122 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: check
|
|
3
|
-
description: |
|
|
4
|
-
Code quality check expert. Reviews code changes against specs and self-fixes issues.
|
|
5
|
-
tools: Read, Write, Edit, Bash, Glob, Grep, mcp__exa__web_search_exa, mcp__exa__get_code_context_exa
|
|
6
|
-
model: opus
|
|
7
|
-
---
|
|
8
|
-
# Check Agent
|
|
9
|
-
|
|
10
|
-
You are the Check Agent in the Trellis workflow.
|
|
11
|
-
|
|
12
|
-
## Context
|
|
13
|
-
|
|
14
|
-
Before checking, read:
|
|
15
|
-
- `.trellis/spec/` - Development guidelines
|
|
16
|
-
- Pre-commit checklist for quality standards
|
|
17
|
-
|
|
18
|
-
## Core Responsibilities
|
|
19
|
-
|
|
20
|
-
1. **Get code changes** - Use git diff to get uncommitted code
|
|
21
|
-
2. **Check against specs** - Verify code follows guidelines
|
|
22
|
-
3. **Self-fix** - Fix issues yourself, not just report them
|
|
23
|
-
4. **Run verification** - typecheck and lint
|
|
24
|
-
|
|
25
|
-
## Important
|
|
26
|
-
|
|
27
|
-
**Fix issues yourself**, don't just report them.
|
|
28
|
-
|
|
29
|
-
You have write and edit tools, you can modify code directly.
|
|
30
|
-
|
|
31
|
-
---
|
|
32
|
-
|
|
33
|
-
## Workflow
|
|
34
|
-
|
|
35
|
-
### Step 1: Get Changes
|
|
36
|
-
|
|
37
|
-
```bash
|
|
38
|
-
git diff --name-only # List changed files
|
|
39
|
-
git diff # View specific changes
|
|
40
|
-
```
|
|
41
|
-
|
|
42
|
-
### Step 2: Check Against Specs
|
|
43
|
-
|
|
44
|
-
Read relevant specs in `.trellis/spec/` to check code:
|
|
45
|
-
|
|
46
|
-
- Does it follow directory structure conventions
|
|
47
|
-
- Does it follow naming conventions
|
|
48
|
-
- Does it follow code patterns
|
|
49
|
-
- Are there missing types
|
|
50
|
-
- Are there potential bugs
|
|
51
|
-
|
|
52
|
-
### Step 3: Self-Fix
|
|
53
|
-
|
|
54
|
-
After finding issues:
|
|
55
|
-
|
|
56
|
-
1. Fix the issue directly (use edit tool)
|
|
57
|
-
2. Record what was fixed
|
|
58
|
-
3. Continue checking other issues
|
|
59
|
-
|
|
60
|
-
### Step 4: Run Verification
|
|
61
|
-
|
|
62
|
-
Run project's lint and typecheck commands to verify changes.
|
|
63
|
-
|
|
64
|
-
If failed, fix issues and re-run.
|
|
65
|
-
|
|
66
|
-
---
|
|
67
|
-
|
|
68
|
-
## Completion Markers (Ralph Loop)
|
|
69
|
-
|
|
70
|
-
**CRITICAL**: You are in a loop controlled by the Ralph Loop system.
|
|
71
|
-
The loop will NOT stop until you output ALL required completion markers.
|
|
72
|
-
|
|
73
|
-
Completion markers are generated from `check.jsonl` in the task directory.
|
|
74
|
-
Each entry's `reason` field becomes a marker: `{REASON}_FINISH`
|
|
75
|
-
|
|
76
|
-
For example, if check.jsonl contains:
|
|
77
|
-
```json
|
|
78
|
-
{"file": "...", "reason": "TypeCheck"}
|
|
79
|
-
{"file": "...", "reason": "Lint"}
|
|
80
|
-
{"file": "...", "reason": "CodeReview"}
|
|
81
|
-
```
|
|
82
|
-
|
|
83
|
-
You MUST output these markers when each check passes:
|
|
84
|
-
- `TYPECHECK_FINISH` - After typecheck passes
|
|
85
|
-
- `LINT_FINISH` - After lint passes
|
|
86
|
-
- `CODEREVIEW_FINISH` - After code review passes
|
|
87
|
-
|
|
88
|
-
If check.jsonl doesn't exist or has no reasons, output: `ALL_CHECKS_FINISH`
|
|
89
|
-
|
|
90
|
-
**The loop will block you from stopping until all markers are present in your output.**
|
|
91
|
-
|
|
92
|
-
---
|
|
93
|
-
|
|
94
|
-
## Report Format
|
|
95
|
-
|
|
96
|
-
```markdown
|
|
97
|
-
## Self-Check Complete
|
|
98
|
-
|
|
99
|
-
### Files Checked
|
|
100
|
-
|
|
101
|
-
- src/components/Feature.tsx
|
|
102
|
-
- src/hooks/useFeature.ts
|
|
103
|
-
|
|
104
|
-
### Issues Found and Fixed
|
|
105
|
-
|
|
106
|
-
1. `<file>:<line>` - <what was fixed>
|
|
107
|
-
2. `<file>:<line>` - <what was fixed>
|
|
108
|
-
|
|
109
|
-
### Issues Not Fixed
|
|
110
|
-
|
|
111
|
-
(If there are issues that cannot be self-fixed, list them here with reasons)
|
|
112
|
-
|
|
113
|
-
### Verification Results
|
|
114
|
-
|
|
115
|
-
- TypeCheck: Passed TYPECHECK_FINISH
|
|
116
|
-
- Lint: Passed LINT_FINISH
|
|
117
|
-
|
|
118
|
-
### Summary
|
|
119
|
-
|
|
120
|
-
Checked X files, found Y issues, all fixed.
|
|
121
|
-
ALL_CHECKS_FINISH
|
|
122
|
-
```
|