bobo-ai-cli 1.6.0 → 2.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,345 @@
1
+ /**
2
+ * Skill Router — intelligent content-based skill triggering.
3
+ *
4
+ * Architecture:
5
+ * 1. Each skill declares triggers (keywords, patterns, intents)
6
+ * 2. On every user message, the router scores all skills
7
+ * 3. Top-scoring skills get their prompts injected into context
8
+ * 4. Skills can be: always-on (kernel), triggered, or manual
9
+ *
10
+ * Trigger types:
11
+ * - keywords: exact word matches (fast)
12
+ * - patterns: regex patterns (flexible)
13
+ * - intents: semantic categories (broad)
14
+ * - fileTypes: triggered by file extensions in CWD or message
15
+ *
16
+ * Skill tiers:
17
+ * - kernel: always active (memory, verification, compression)
18
+ * - auto: triggered by content match
19
+ * - manual: only enabled explicitly by user
20
+ */
21
+ import { readFileSync, existsSync, readdirSync, statSync } from 'node:fs';
22
+ import { join, extname } from 'node:path';
23
+ import { getConfigDir } from './config.js';
24
+ // ─── Intent Detection ────────────────────────────────────────
25
+ const INTENT_PATTERNS = {
26
+ 'code-write': [/写代码|write code|implement|实现|create.*function|创建.*模块|新增.*功能/i],
27
+ 'code-review': [/review|审查|code review|check.*code|看.*代码/i],
28
+ 'code-debug': [/debug|调试|bug|error|报错|fix|修复|为什么.*不|doesn't work/i],
29
+ 'code-refactor': [/refactor|重构|优化.*代码|clean.*up|整理/i],
30
+ 'search': [/搜索|search|找|look.*for|查找|grep/i],
31
+ 'research': [/调研|research|了解|分析|investigate|study/i],
32
+ 'analysis': [/分析|analyze|statistics|统计|数据/i],
33
+ 'image-gen': [/生图|画|image|图片|generate.*image|生成.*图|draw|设计.*图/i],
34
+ 'video-gen': [/视频|video|动画|animation|clip|短片/i],
35
+ 'audio-gen': [/音频|audio|音乐|music|声音|tts|语音/i],
36
+ 'web-scrape': [/爬虫|scrape|crawl|抓取|爬取|抓.*页面/i],
37
+ 'web-browse': [/打开.*网页|browse|浏览|open.*url|访问.*网站/i],
38
+ 'git-pr': [/pr|pull request|merge request|提PR|合并请求/i],
39
+ 'git-workflow': [/branch|分支|commit|push|rebase|cherry.*pick|stash/i],
40
+ 'deploy': [/部署|deploy|发布|release|上线/i],
41
+ 'ci-cd': [/ci|cd|pipeline|github actions|workflow/i],
42
+ 'seo': [/seo|关键词|keyword|排名|ranking|竞品.*词/i],
43
+ 'marketing': [/营销|marketing|推广|广告|campaign|选品/i],
44
+ 'design': [/设计|design|ui|ux|界面|layout|原型/i],
45
+ 'ui-ux': [/组件|component|样式|style|css|tailwind|前端/i],
46
+ 'data-query': [/sql|query|数据库|database|查询|mysql|postgres/i],
47
+ 'data-viz': [/图表|chart|visualization|可视化|dashboard/i],
48
+ 'writing': [/写|write|文章|article|文案|copy|内容/i],
49
+ 'translation': [/翻译|translate|中英|英中/i],
50
+ 'security': [/安全|security|漏洞|vulnerability|审计|audit/i],
51
+ 'audit': [/检查|check|验证|verify|audit|review/i],
52
+ 'planning': [/计划|plan|规划|方案|strategy|架构/i],
53
+ 'architecture': [/架构|architecture|系统设计|设计模式|pattern/i],
54
+ 'memory': [/记住|remember|记忆|memory|recall/i],
55
+ 'learning': [/学习|learn|教程|tutorial|解释|explain/i],
56
+ 'api-call': [/api|接口|endpoint|request|调用/i],
57
+ 'integration': [/集成|integrate|对接|connect|接入/i],
58
+ };
59
+ function detectIntents(message) {
60
+ const detected = [];
61
+ for (const [intent, patterns] of Object.entries(INTENT_PATTERNS)) {
62
+ if (patterns.some(p => p.test(message))) {
63
+ detected.push(intent);
64
+ }
65
+ }
66
+ return detected;
67
+ }
68
+ // ─── Router Registry ─────────────────────────────────────────
69
+ let routeRegistry = [];
70
+ let routeIndexBuilt = false;
71
+ /**
72
+ * Build the route index from skills directory.
73
+ * Parses SKILL.md files for trigger metadata.
74
+ */
75
+ export function buildRouteIndex() {
76
+ routeRegistry = [];
77
+ const skillsDir = join(getConfigDir(), 'skills');
78
+ if (!existsSync(skillsDir)) {
79
+ routeIndexBuilt = true;
80
+ return;
81
+ }
82
+ for (const entry of readdirSync(skillsDir)) {
83
+ const fullPath = join(skillsDir, entry);
84
+ try {
85
+ if (!statSync(fullPath).isDirectory())
86
+ continue;
87
+ }
88
+ catch {
89
+ continue;
90
+ }
91
+ const skillFile = join(fullPath, 'SKILL.md');
92
+ if (!existsSync(skillFile))
93
+ continue;
94
+ const content = readFileSync(skillFile, 'utf-8');
95
+ const route = parseSkillRoute(entry, content, skillFile);
96
+ if (route)
97
+ routeRegistry.push(route);
98
+ }
99
+ // Sort by priority (higher first)
100
+ routeRegistry.sort((a, b) => (b.priority || 0) - (a.priority || 0));
101
+ routeIndexBuilt = true;
102
+ }
103
+ /**
104
+ * Parse a SKILL.md into a SkillRoute.
105
+ * Extracts triggers from frontmatter-style comments or content analysis.
106
+ */
107
+ function parseSkillRoute(name, content, filePath) {
108
+ // Extract description
109
+ let description = '';
110
+ const descMatch = content.match(/^description:\s*(.+)/m)
111
+ || content.match(/^#\s+.+\n+([^#\n][^\n]{10,})/m);
112
+ if (descMatch)
113
+ description = descMatch[1].trim().slice(0, 150);
114
+ // Extract tier from content
115
+ let tier = 'auto';
116
+ if (/tier:\s*kernel/i.test(content) || /常驻|always.?on|always.?active/i.test(content)) {
117
+ tier = 'kernel';
118
+ }
119
+ else if (/tier:\s*manual/i.test(content)) {
120
+ tier = 'manual';
121
+ }
122
+ // Extract keywords from content
123
+ const keywords = [];
124
+ const keywordMatch = content.match(/(?:keywords?|triggers?|触发词|关键词):\s*(.+)/i);
125
+ if (keywordMatch) {
126
+ keywords.push(...keywordMatch[1].split(/[,,、|]/).map(k => k.trim().toLowerCase()).filter(Boolean));
127
+ }
128
+ // Auto-extract keywords from skill name
129
+ const nameWords = name.replace(/[-_]/g, ' ').split(' ').filter(w => w.length > 2);
130
+ keywords.push(...nameWords.map(w => w.toLowerCase()));
131
+ // Extract patterns
132
+ const patterns = [];
133
+ const patternMatch = content.match(/(?:patterns?|正则):\s*(.+)/i);
134
+ if (patternMatch) {
135
+ patterns.push(...patternMatch[1].split(/[,,]/).map(p => p.trim()).filter(Boolean));
136
+ }
137
+ // Auto-detect intents from description + content
138
+ const intents = [];
139
+ const combinedText = `${name} ${description} ${content.slice(0, 500)}`;
140
+ for (const [intent, pats] of Object.entries(INTENT_PATTERNS)) {
141
+ if (pats.some(p => p.test(combinedText))) {
142
+ intents.push(intent);
143
+ }
144
+ }
145
+ // Extract file types
146
+ const fileTypes = [];
147
+ const fileTypeMatch = content.match(/(?:file.?types?|文件类型):\s*(.+)/i);
148
+ if (fileTypeMatch) {
149
+ fileTypes.push(...fileTypeMatch[1].split(/[,,]/).map(t => t.trim()).filter(Boolean));
150
+ }
151
+ // Priority
152
+ let priority = 50; // default
153
+ if (tier === 'kernel')
154
+ priority = 100;
155
+ const priorityMatch = content.match(/priority:\s*(\d+)/i);
156
+ if (priorityMatch)
157
+ priority = parseInt(priorityMatch[1], 10);
158
+ return {
159
+ name,
160
+ description,
161
+ tier,
162
+ trigger: {
163
+ keywords: keywords.length > 0 ? keywords : undefined,
164
+ patterns: patterns.length > 0 ? patterns : undefined,
165
+ intents: intents.length > 0 ? intents : undefined,
166
+ fileTypes: fileTypes.length > 0 ? fileTypes : undefined,
167
+ },
168
+ promptSource: 'file',
169
+ promptFile: filePath,
170
+ priority,
171
+ };
172
+ }
173
+ // ─── Routing Engine ──────────────────────────────────────────
174
+ /**
175
+ * Route a user message to matching skills.
176
+ * Returns scored matches, sorted by relevance.
177
+ */
178
+ export function routeMessage(message, options) {
179
+ if (!routeIndexBuilt)
180
+ buildRouteIndex();
181
+ const maxSkills = options?.maxSkills || 5;
182
+ const messageLower = message.toLowerCase();
183
+ const messageIntents = detectIntents(message);
184
+ // Detect file types in CWD
185
+ const cwdExtensions = new Set((options?.cwdFiles || []).map(f => extname(f).toLowerCase()));
186
+ const matches = [];
187
+ for (const route of routeRegistry) {
188
+ // Kernel skills always match
189
+ if (route.tier === 'kernel') {
190
+ matches.push({ route, score: 100, matchedBy: ['kernel (always-on)'] });
191
+ continue;
192
+ }
193
+ // Manual skills skip auto-routing
194
+ if (route.tier === 'manual')
195
+ continue;
196
+ let score = 0;
197
+ const matchedBy = [];
198
+ // Keyword matching (highest signal)
199
+ if (route.trigger.keywords) {
200
+ for (const kw of route.trigger.keywords) {
201
+ if (messageLower.includes(kw)) {
202
+ score += 30;
203
+ matchedBy.push(`keyword: "${kw}"`);
204
+ }
205
+ }
206
+ }
207
+ // Exclude keywords
208
+ if (route.trigger.excludeKeywords) {
209
+ for (const kw of route.trigger.excludeKeywords) {
210
+ if (messageLower.includes(kw)) {
211
+ score = -100;
212
+ break;
213
+ }
214
+ }
215
+ }
216
+ // Pattern matching
217
+ if (route.trigger.patterns && score >= 0) {
218
+ for (const pat of route.trigger.patterns) {
219
+ try {
220
+ if (new RegExp(pat, 'i').test(message)) {
221
+ score += 25;
222
+ matchedBy.push(`pattern: ${pat}`);
223
+ }
224
+ }
225
+ catch { /* invalid regex, skip */ }
226
+ }
227
+ }
228
+ // Intent matching
229
+ if (route.trigger.intents && score >= 0) {
230
+ for (const intent of route.trigger.intents) {
231
+ if (messageIntents.includes(intent)) {
232
+ score += 20;
233
+ matchedBy.push(`intent: ${intent}`);
234
+ }
235
+ }
236
+ }
237
+ // File type matching
238
+ if (route.trigger.fileTypes && score >= 0) {
239
+ for (const ft of route.trigger.fileTypes) {
240
+ if (cwdExtensions.has(ft)) {
241
+ score += 10;
242
+ matchedBy.push(`fileType: ${ft}`);
243
+ }
244
+ }
245
+ }
246
+ if (score > 0) {
247
+ // Apply priority as a tiebreaker
248
+ score += (route.priority || 0) / 100;
249
+ matches.push({ route, score, matchedBy });
250
+ }
251
+ }
252
+ // Sort by score descending
253
+ matches.sort((a, b) => b.score - a.score);
254
+ return matches.slice(0, maxSkills);
255
+ }
256
+ /**
257
+ * Load matched skill prompts within a token budget.
258
+ * Returns the combined prompt string.
259
+ */
260
+ export function loadMatchedSkillPrompts(matches, tokenBudget = 8000) {
261
+ const loaded = [];
262
+ const skipped = [];
263
+ const parts = [];
264
+ let usedTokens = 0;
265
+ for (const match of matches) {
266
+ const { route } = match;
267
+ let content = '';
268
+ if (route.promptSource === 'inline' && route.prompt) {
269
+ content = route.prompt;
270
+ }
271
+ else if (route.promptSource === 'file' && route.promptFile && existsSync(route.promptFile)) {
272
+ content = readFileSync(route.promptFile, 'utf-8');
273
+ }
274
+ if (!content) {
275
+ skipped.push(route.name);
276
+ continue;
277
+ }
278
+ // Estimate tokens (~4 chars/token English, ~2 chars/token Chinese)
279
+ const estimatedTokens = Math.ceil(content.length / 3);
280
+ if (usedTokens + estimatedTokens > tokenBudget && loaded.length > 0) {
281
+ // Budget exceeded — truncate or skip
282
+ if (route.tier === 'kernel') {
283
+ // Kernel skills always loaded, even over budget
284
+ const truncated = content.slice(0, tokenBudget * 2);
285
+ parts.push(`## Skill: ${route.name}\n\n${truncated}`);
286
+ loaded.push(route.name);
287
+ usedTokens += Math.ceil(truncated.length / 3);
288
+ }
289
+ else {
290
+ skipped.push(route.name);
291
+ }
292
+ continue;
293
+ }
294
+ parts.push(`## Skill: ${route.name}\n\n${content}`);
295
+ loaded.push(route.name);
296
+ usedTokens += estimatedTokens;
297
+ }
298
+ const prompt = parts.length > 0
299
+ ? `\n\n---\n\n# Active Skills (${loaded.length} loaded)\n\n${parts.join('\n\n---\n\n')}`
300
+ : '';
301
+ return { prompt, loaded, skipped };
302
+ }
303
+ /**
304
+ * Get router stats for debugging.
305
+ */
306
+ export function getRouterStats() {
307
+ if (!routeIndexBuilt)
308
+ buildRouteIndex();
309
+ return {
310
+ totalSkills: routeRegistry.length,
311
+ kernel: routeRegistry.filter(r => r.tier === 'kernel').length,
312
+ auto: routeRegistry.filter(r => r.tier === 'auto').length,
313
+ manual: routeRegistry.filter(r => r.tier === 'manual').length,
314
+ intents: Object.keys(INTENT_PATTERNS).length,
315
+ };
316
+ }
317
+ /**
318
+ * Export the full registry for debugging.
319
+ */
320
+ export function getRouteRegistry() {
321
+ if (!routeIndexBuilt)
322
+ buildRouteIndex();
323
+ return [...routeRegistry];
324
+ }
325
+ /**
326
+ * Generate a routing report for a message (for debugging).
327
+ */
328
+ export function debugRoute(message) {
329
+ const matches = routeMessage(message);
330
+ const intents = detectIntents(message);
331
+ const lines = [
332
+ `Message: "${message.slice(0, 100)}"`,
333
+ `Detected intents: ${intents.join(', ') || '(none)'}`,
334
+ `Matches (${matches.length}):`,
335
+ ];
336
+ for (const m of matches) {
337
+ lines.push(` ${m.route.name} (score: ${m.score.toFixed(1)}, tier: ${m.route.tier})`);
338
+ lines.push(` matched by: ${m.matchedBy.join(', ')}`);
339
+ }
340
+ if (matches.length === 0) {
341
+ lines.push(' (no skills matched)');
342
+ }
343
+ return lines.join('\n');
344
+ }
345
+ //# sourceMappingURL=skill-router.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"skill-router.js","sourceRoot":"","sources":["../src/skill-router.ts"],"names":[],"mappings":"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"}
@@ -10,16 +10,16 @@ export declare const RuleSchema: z.ZodObject<{
10
10
  }, "strip", z.ZodTypeAny, {
11
11
  title: string;
12
12
  content: string;
13
- category: "project" | "root" | "core" | "domain" | "evomap";
14
13
  id: string;
14
+ category: "project" | "root" | "core" | "domain" | "evomap";
15
15
  tags: string[];
16
16
  source?: string | undefined;
17
17
  version?: string | undefined;
18
18
  }, {
19
19
  title: string;
20
20
  content: string;
21
- category: "project" | "root" | "core" | "domain" | "evomap";
22
21
  id: string;
22
+ category: "project" | "root" | "core" | "domain" | "evomap";
23
23
  tags: string[];
24
24
  source?: string | undefined;
25
25
  version?: string | undefined;
@@ -37,8 +37,8 @@ export declare const SkillSchema: z.ZodObject<{
37
37
  }, "strip", z.ZodTypeAny, {
38
38
  title: string;
39
39
  content: string;
40
- category: "knowledge" | "research" | "agent-engineering" | "marketing" | "dev-tools" | "design" | "media" | "infrastructure" | "other";
41
40
  id: string;
41
+ category: "knowledge" | "research" | "marketing" | "design" | "agent-engineering" | "dev-tools" | "media" | "infrastructure" | "other";
42
42
  tags: string[];
43
43
  triggers: string[];
44
44
  dependencies: string[];
@@ -46,8 +46,8 @@ export declare const SkillSchema: z.ZodObject<{
46
46
  }, {
47
47
  title: string;
48
48
  content: string;
49
- category: "knowledge" | "research" | "agent-engineering" | "marketing" | "dev-tools" | "design" | "media" | "infrastructure" | "other";
50
49
  id: string;
50
+ category: "knowledge" | "research" | "marketing" | "design" | "agent-engineering" | "dev-tools" | "media" | "infrastructure" | "other";
51
51
  tags: string[];
52
52
  source?: string | undefined;
53
53
  triggers?: string[] | undefined;
@@ -127,14 +127,14 @@ export declare const MemorySchema: z.ZodObject<{
127
127
  content: z.ZodString;
128
128
  template: z.ZodDefault<z.ZodBoolean>;
129
129
  }, "strip", z.ZodTypeAny, {
130
- type: "custom" | "account" | "patterns" | "projects" | "services";
130
+ type: "custom" | "patterns" | "account" | "projects" | "services";
131
131
  title: string;
132
132
  content: string;
133
133
  id: string;
134
134
  tags: string[];
135
135
  template: boolean;
136
136
  }, {
137
- type: "custom" | "account" | "patterns" | "projects" | "services";
137
+ type: "custom" | "patterns" | "account" | "projects" | "services";
138
138
  title: string;
139
139
  content: string;
140
140
  id: string;
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Browser automation — headless browser for visual verification.
3
+ * Solves: "没有浏览器/Playwright"
4
+ *
5
+ * Uses Node.js built-in fetch + system browser for:
6
+ * - URL screenshots (via Puppeteer if available, fallback to text)
7
+ * - HTTP endpoint testing
8
+ * - HTML rendering preview
9
+ */
10
+ import type { ChatCompletionTool } from 'openai/resources/index.js';
11
+ export declare const browserToolDefinitions: ChatCompletionTool[];
12
+ export declare function isBrowserTool(name: string): boolean;
13
+ export declare function executeBrowserTool(name: string, args: Record<string, unknown>): Promise<string>;
@@ -0,0 +1,193 @@
1
+ /**
2
+ * Browser automation — headless browser for visual verification.
3
+ * Solves: "没有浏览器/Playwright"
4
+ *
5
+ * Uses Node.js built-in fetch + system browser for:
6
+ * - URL screenshots (via Puppeteer if available, fallback to text)
7
+ * - HTTP endpoint testing
8
+ * - HTML rendering preview
9
+ */
10
+ import { execSync } from 'node:child_process';
11
+ import { writeFileSync } from 'node:fs';
12
+ import { join } from 'node:path';
13
+ export const browserToolDefinitions = [
14
+ {
15
+ type: 'function',
16
+ function: {
17
+ name: 'browser_screenshot',
18
+ description: 'Take a screenshot of a URL. Requires Puppeteer/Playwright installed. Saves to a file.',
19
+ parameters: {
20
+ type: 'object',
21
+ properties: {
22
+ url: { type: 'string', description: 'URL to screenshot' },
23
+ output: { type: 'string', description: 'Output file path (default: screenshot.png)' },
24
+ width: { type: 'number', description: 'Viewport width (default: 1280)' },
25
+ height: { type: 'number', description: 'Viewport height (default: 720)' },
26
+ fullPage: { type: 'boolean', description: 'Capture full page (default: false)' },
27
+ },
28
+ required: ['url'],
29
+ },
30
+ },
31
+ },
32
+ {
33
+ type: 'function',
34
+ function: {
35
+ name: 'browser_fetch',
36
+ description: 'Fetch a URL and return the HTML/text content. Like curl but with better output formatting.',
37
+ parameters: {
38
+ type: 'object',
39
+ properties: {
40
+ url: { type: 'string', description: 'URL to fetch' },
41
+ selector: { type: 'string', description: 'CSS selector to extract (requires cheerio)' },
42
+ headers: { type: 'object', description: 'Custom headers' },
43
+ },
44
+ required: ['url'],
45
+ },
46
+ },
47
+ },
48
+ {
49
+ type: 'function',
50
+ function: {
51
+ name: 'browser_preview',
52
+ description: 'Render HTML content to a file and optionally take a screenshot of it.',
53
+ parameters: {
54
+ type: 'object',
55
+ properties: {
56
+ html: { type: 'string', description: 'HTML content to render' },
57
+ output: { type: 'string', description: 'Output HTML file path' },
58
+ screenshot: { type: 'boolean', description: 'Also take a screenshot (default: false)' },
59
+ },
60
+ required: ['html'],
61
+ },
62
+ },
63
+ },
64
+ ];
65
+ // ─── Implementations ─────────────────────────────────────────
66
+ function hasPuppeteer() {
67
+ try {
68
+ execSync('node -e "require(\'puppeteer\')"', { encoding: 'utf-8', timeout: 5000 });
69
+ return true;
70
+ }
71
+ catch {
72
+ return false;
73
+ }
74
+ }
75
+ function hasPlaywright() {
76
+ try {
77
+ execSync('node -e "require(\'playwright\')"', { encoding: 'utf-8', timeout: 5000 });
78
+ return true;
79
+ }
80
+ catch {
81
+ return false;
82
+ }
83
+ }
84
+ function screenshotWithPuppeteer(url, output, width, height, fullPage) {
85
+ const script = `
86
+ const puppeteer = require('puppeteer');
87
+ (async () => {
88
+ const browser = await puppeteer.launch({ headless: 'new', args: ['--no-sandbox'] });
89
+ const page = await browser.newPage();
90
+ await page.setViewport({ width: ${width}, height: ${height} });
91
+ await page.goto('${url.replace(/'/g, "\\'")}', { waitUntil: 'networkidle2', timeout: 30000 });
92
+ await page.screenshot({ path: '${output.replace(/'/g, "\\'")}', fullPage: ${fullPage} });
93
+ await browser.close();
94
+ console.log('OK');
95
+ })().catch(e => { console.error(e.message); process.exit(1); });
96
+ `;
97
+ try {
98
+ execSync(`node -e "${script.replace(/"/g, '\\"').replace(/\n/g, ' ')}"`, {
99
+ encoding: 'utf-8',
100
+ timeout: 45000,
101
+ });
102
+ return `Screenshot saved to ${output}`;
103
+ }
104
+ catch (e) {
105
+ return `Screenshot failed: ${e.message}`;
106
+ }
107
+ }
108
+ function screenshotWithPlaywright(url, output, width, height, fullPage) {
109
+ const script = `
110
+ const { chromium } = require('playwright');
111
+ (async () => {
112
+ const browser = await chromium.launch();
113
+ const page = await browser.newPage({ viewport: { width: ${width}, height: ${height} } });
114
+ await page.goto('${url.replace(/'/g, "\\'")}', { waitUntil: 'networkidle', timeout: 30000 });
115
+ await page.screenshot({ path: '${output.replace(/'/g, "\\'")}', fullPage: ${fullPage} });
116
+ await browser.close();
117
+ console.log('OK');
118
+ })().catch(e => { console.error(e.message); process.exit(1); });
119
+ `;
120
+ try {
121
+ execSync(`node -e "${script.replace(/"/g, '\\"').replace(/\n/g, ' ')}"`, {
122
+ encoding: 'utf-8',
123
+ timeout: 45000,
124
+ });
125
+ return `Screenshot saved to ${output}`;
126
+ }
127
+ catch (e) {
128
+ return `Screenshot failed: ${e.message}`;
129
+ }
130
+ }
131
+ function browserScreenshot(args) {
132
+ const url = args.url;
133
+ const output = args.output || 'screenshot.png';
134
+ const width = args.width || 1280;
135
+ const height = args.height || 720;
136
+ const fullPage = args.fullPage || false;
137
+ if (hasPuppeteer()) {
138
+ return screenshotWithPuppeteer(url, output, width, height, fullPage);
139
+ }
140
+ if (hasPlaywright()) {
141
+ return screenshotWithPlaywright(url, output, width, height, fullPage);
142
+ }
143
+ return 'No browser automation library found. Install puppeteer or playwright:\n npm install -g puppeteer\n # or\n npm install -g playwright';
144
+ }
145
+ async function browserFetch(args) {
146
+ const url = args.url;
147
+ const headers = (args.headers || {});
148
+ try {
149
+ const response = await fetch(url, {
150
+ headers: { 'User-Agent': 'Bobo-CLI/1.6.0', ...headers },
151
+ });
152
+ const status = response.status;
153
+ const contentType = response.headers.get('content-type') || '';
154
+ let body = await response.text();
155
+ // Truncate large responses
156
+ if (body.length > 8000) {
157
+ body = body.slice(0, 8000) + '\n\n... (truncated at 8000 chars)';
158
+ }
159
+ return `HTTP ${status} (${contentType})\n\n${body}`;
160
+ }
161
+ catch (e) {
162
+ return `Fetch error: ${e.message}`;
163
+ }
164
+ }
165
+ function browserPreview(args) {
166
+ const html = args.html;
167
+ const output = args.output || 'preview.html';
168
+ const screenshot = args.screenshot || false;
169
+ writeFileSync(output, html);
170
+ let result = `HTML written to ${output} (${html.length} bytes)`;
171
+ if (screenshot) {
172
+ const screenshotPath = output.replace(/\.html?$/, '.png');
173
+ const screenshotResult = browserScreenshot({
174
+ url: `file://${join(process.cwd(), output)}`,
175
+ output: screenshotPath,
176
+ });
177
+ result += '\n' + screenshotResult;
178
+ }
179
+ return result;
180
+ }
181
+ // ─── Executor ────────────────────────────────────────────────
182
+ export function isBrowserTool(name) {
183
+ return ['browser_screenshot', 'browser_fetch', 'browser_preview'].includes(name);
184
+ }
185
+ export async function executeBrowserTool(name, args) {
186
+ switch (name) {
187
+ case 'browser_screenshot': return browserScreenshot(args);
188
+ case 'browser_fetch': return await browserFetch(args);
189
+ case 'browser_preview': return browserPreview(args);
190
+ default: return `Unknown browser tool: ${name}`;
191
+ }
192
+ }
193
+ //# sourceMappingURL=browser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"browser.js","sourceRoot":"","sources":["../../src/tools/browser.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Enhanced Git tools — PR workflow, branch management, stash.
3
+ * Solves: "Git 操作较基础"
4
+ */
5
+ import type { ChatCompletionTool } from 'openai/resources/index.js';
6
+ export declare const gitAdvancedToolDefinitions: ChatCompletionTool[];
7
+ export declare function isGitAdvancedTool(name: string): boolean;
8
+ export declare function executeGitAdvancedTool(name: string, args: Record<string, unknown>): string;