foliko 1.1.2 → 1.1.4
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/.agent/agents/code-assistant.json +14 -0
- package/.agent/agents/email-assistant.json +14 -0
- package/.agent/agents/file-assistant.json +15 -0
- package/.agent/agents/system-assistant.json +15 -0
- package/.agent/agents/web-assistant.json +12 -0
- package/.agent/data/ambient/goals.json +50 -0
- package/.agent/data/ambient/memories.json +7 -0
- package/.agent/data/default.json +3 -412
- package/.agent/data/plugins-state.json +174 -173
- package/.agent/data/scheduler/tasks.json +1 -0
- package/.agent/memory/core.md +1 -0
- package/.agent/memory/project/mnn93ogy-ypjn27.md +9 -0
- package/.agent/memory/project/mnn98fqy-5nhc1u.md +25 -0
- package/.agent/memory/reference/mnq3oenw-46haj6.md +63 -0
- package/.agent/memory/reference/mnq5qxm2-mjoooh.md +116 -0
- package/.agent/memory/user/mnm67t9m-x8rekk.md +9 -0
- package/.agent/memory/user/mnn5mmqh-w6aktx.md +11 -0
- package/.agent/memory/user/mnnbfhhn-dk1bd1.md +22 -0
- package/.agent/package.json +8 -0
- package/.agent/plugins/__pycache__/file_writer.cpython-312.pyc +0 -0
- package/.agent/plugins/daytona/README.md +89 -0
- package/.agent/plugins/daytona/index.js +377 -0
- package/.agent/plugins/daytona/package.json +12 -0
- package/.agent/plugins/marknative/README.md +134 -0
- package/.agent/plugins/marknative/fonts/SegoeUI Emoji.ttf +0 -0
- package/.agent/plugins/marknative/index.js +256 -0
- package/.agent/plugins/marknative/package.json +12 -0
- package/.agent/plugins/marknative/update-readme.js +134 -0
- package/.agent/plugins/poster-plugin/emojis/rocket.png +1 -0
- package/.agent/plugins/poster-plugin/fonts/SegoeUI Emoji.ttf +0 -0
- package/.agent/plugins/poster-plugin/src/elements/text.js +3 -1
- package/.agent/plugins/poster-plugin/src/fonts.js +10 -0
- package/.agent/plugins/poster-plugin/yarn.lock +1007 -0
- package/.agent/plugins/system-info/index.js +387 -0
- package/.agent/plugins/system-info/package.json +4 -0
- package/.agent/plugins/system-info/test.js +40 -0
- package/.agent/plugins.json +11 -5
- package/.agent/python-scripts/test_sample.py +24 -0
- package/.agent/sessions/cli_default.json +1869 -691
- package/.agent/skills/agent-browser/SKILL.md +311 -0
- package/.agent/skills/agent-browser/TEST_PLAN.md +200 -0
- package/.agent/skills/sysinfo/SKILL.md +38 -0
- package/.agent/skills/sysinfo/system-info.sh +130 -0
- package/.agent/skills/workflow/SKILL.md +324 -0
- package/.agent/weixin.json +6 -0
- package/.agent/workflows/email-digest.json +50 -0
- package/.agent/workflows/file-backup.json +21 -0
- package/.agent/workflows/get-ip-notify.json +32 -0
- package/.agent/workflows/news-aggregator.json +93 -0
- package/.agent/workflows/news-dashboard-v2.json +94 -0
- package/.agent/workflows/notification-batch.json +32 -0
- package/.claude/settings.local.json +1 -20
- package/.env.example +56 -56
- package/README.md +441 -441
- package/cli/src/commands/chat.js +22 -13
- package/cli/src/ui/chat-ui.js +50 -37
- package/output/emoji-segoe-test-v2.png +0 -0
- package/output/emoji-segoe-test.png +0 -0
- package/output/emoji-test.png +0 -0
- package/output/emoji-windows-test.png +0 -0
- package/output/foliko-emoji-poster.png +0 -0
- package/output/foliko-muji-poster-final.png +0 -0
- package/output/foliko-muji-poster-v2.png +0 -0
- package/output/foliko-muji-poster.png +0 -0
- package/output/foliko-share.png +0 -0
- package/output/progress-circle-test.png +0 -0
- package/output/vb-agent-poster.png +0 -0
- package/package.json +1 -2
- package/plugins/default-plugins.js +4 -3
- package/plugins/extension-executor-plugin.js +12 -91
- package/plugins/file-system-plugin.js +19 -4
- package/plugins/memory-plugin.js +33 -4
- package/plugins/subagent-plugin.js +14 -37
- package/plugins/weixin-plugin.js +40 -168
- package/skills/find-skills/AGENTS.md +162 -162
- package/skills/find-skills/SKILL.md +133 -133
- package/skills/poster-guide/SKILL.md +669 -1426
- package/src/core/agent-chat.js +439 -269
- package/src/core/agent.js +3 -6
- package/.agent/.shared/ui-ux-pro-max/data/charts.csv +0 -26
- package/.agent/.shared/ui-ux-pro-max/data/colors.csv +0 -97
- package/.agent/.shared/ui-ux-pro-max/data/icons.csv +0 -101
- package/.agent/.shared/ui-ux-pro-max/data/landing.csv +0 -31
- package/.agent/.shared/ui-ux-pro-max/data/products.csv +0 -97
- package/.agent/.shared/ui-ux-pro-max/data/prompts.csv +0 -24
- package/.agent/.shared/ui-ux-pro-max/data/react-performance.csv +0 -45
- package/.agent/.shared/ui-ux-pro-max/data/stacks/flutter.csv +0 -53
- package/.agent/.shared/ui-ux-pro-max/data/stacks/html-tailwind.csv +0 -56
- package/.agent/.shared/ui-ux-pro-max/data/stacks/jetpack-compose.csv +0 -53
- package/.agent/.shared/ui-ux-pro-max/data/stacks/nextjs.csv +0 -53
- package/.agent/.shared/ui-ux-pro-max/data/stacks/nuxt-ui.csv +0 -51
- package/.agent/.shared/ui-ux-pro-max/data/stacks/nuxtjs.csv +0 -59
- package/.agent/.shared/ui-ux-pro-max/data/stacks/react-native.csv +0 -52
- package/.agent/.shared/ui-ux-pro-max/data/stacks/react.csv +0 -54
- package/.agent/.shared/ui-ux-pro-max/data/stacks/shadcn.csv +0 -61
- package/.agent/.shared/ui-ux-pro-max/data/stacks/svelte.csv +0 -54
- package/.agent/.shared/ui-ux-pro-max/data/stacks/swiftui.csv +0 -51
- package/.agent/.shared/ui-ux-pro-max/data/stacks/vue.csv +0 -50
- package/.agent/.shared/ui-ux-pro-max/data/styles.csv +0 -59
- package/.agent/.shared/ui-ux-pro-max/data/typography.csv +0 -58
- package/.agent/.shared/ui-ux-pro-max/data/ui-reasoning.csv +0 -101
- package/.agent/.shared/ui-ux-pro-max/data/ux-guidelines.csv +0 -100
- package/.agent/.shared/ui-ux-pro-max/data/web-interface.csv +0 -31
- package/.agent/.shared/ui-ux-pro-max/scripts/__pycache__/core.cpython-313.pyc +0 -0
- package/.agent/.shared/ui-ux-pro-max/scripts/__pycache__/design_system.cpython-313.pyc +0 -0
- package/.agent/.shared/ui-ux-pro-max/scripts/core.py +0 -258
- package/.agent/.shared/ui-ux-pro-max/scripts/design_system.py +0 -1067
- package/.agent/.shared/ui-ux-pro-max/scripts/search.py +0 -106
- package/.agent/ARCHITECTURE.md +0 -288
- package/.agent/agents/ambient-agent.md +0 -57
- package/.agent/agents/debugger.md +0 -55
- package/.agent/agents/email-assistant.md +0 -49
- package/.agent/agents/file-manager.md +0 -42
- package/.agent/agents/python-developer.md +0 -60
- package/.agent/agents/scheduler.md +0 -59
- package/.agent/agents/web-developer.md +0 -45
- package/.agent/data/puppeteer-sessions/undefined.json +0 -6
- package/.agent/data/weixin-media/2026-04-08/img_1775618677512.jpg +0 -0
- package/.agent/data/weixin-media/2026-04-08/img_1775619073340.jpg +0 -0
- package/.agent/data/weixin-media/2026-04-08/img_1775619097536.jpg +0 -0
- package/.agent/data/weixin-media/2026-04-08/img_1775619209388.jpg +0 -0
- package/.agent/mcp_config_updated.json +0 -12
- package/.agent/plugins/poster-plugin/fonts/NotoColorEmoji-Regular.ttf +0 -0
- package/.agent/plugins/puppeteer-plugin/README.md +0 -147
- package/.agent/plugins/puppeteer-plugin/index.js +0 -1418
- package/.agent/plugins/puppeteer-plugin/package.json +0 -9
- package/.agent/rules/GEMINI.md +0 -273
- package/.agent/rules/allow-rule.md +0 -77
- package/.agent/rules/log-rule.md +0 -83
- package/.agent/rules/security-rule.md +0 -93
- package/.agent/scripts/auto_preview.py +0 -148
- package/.agent/scripts/checklist.py +0 -217
- package/.agent/scripts/session_manager.py +0 -120
- package/.agent/scripts/verify_all.py +0 -327
- package/.agent/sessions/weixin_o9cq80zgZqKPA2-s59PN43GdDy1w@im.wechat.json +0 -11097
- package/.agent/skills/api-patterns/SKILL.md +0 -81
- package/.agent/skills/api-patterns/api-style.md +0 -42
- package/.agent/skills/api-patterns/auth.md +0 -24
- package/.agent/skills/api-patterns/documentation.md +0 -26
- package/.agent/skills/api-patterns/graphql.md +0 -41
- package/.agent/skills/api-patterns/rate-limiting.md +0 -31
- package/.agent/skills/api-patterns/response.md +0 -37
- package/.agent/skills/api-patterns/rest.md +0 -40
- package/.agent/skills/api-patterns/scripts/api_validator.py +0 -211
- package/.agent/skills/api-patterns/security-testing.md +0 -122
- package/.agent/skills/api-patterns/trpc.md +0 -41
- package/.agent/skills/api-patterns/versioning.md +0 -22
- package/.agent/skills/app-builder/SKILL.md +0 -75
- package/.agent/skills/app-builder/agent-coordination.md +0 -71
- package/.agent/skills/app-builder/feature-building.md +0 -53
- package/.agent/skills/app-builder/project-detection.md +0 -34
- package/.agent/skills/app-builder/scaffolding.md +0 -118
- package/.agent/skills/app-builder/tech-stack.md +0 -40
- package/.agent/skills/app-builder/templates/SKILL.md +0 -39
- package/.agent/skills/app-builder/templates/astro-static/TEMPLATE.md +0 -76
- package/.agent/skills/app-builder/templates/chrome-extension/TEMPLATE.md +0 -92
- package/.agent/skills/app-builder/templates/cli-tool/TEMPLATE.md +0 -88
- package/.agent/skills/app-builder/templates/electron-desktop/TEMPLATE.md +0 -88
- package/.agent/skills/app-builder/templates/express-api/TEMPLATE.md +0 -83
- package/.agent/skills/app-builder/templates/flutter-app/TEMPLATE.md +0 -90
- package/.agent/skills/app-builder/templates/monorepo-turborepo/TEMPLATE.md +0 -90
- package/.agent/skills/app-builder/templates/nextjs-fullstack/TEMPLATE.md +0 -122
- package/.agent/skills/app-builder/templates/nextjs-saas/TEMPLATE.md +0 -122
- package/.agent/skills/app-builder/templates/nextjs-static/TEMPLATE.md +0 -169
- package/.agent/skills/app-builder/templates/nuxt-app/TEMPLATE.md +0 -134
- package/.agent/skills/app-builder/templates/python-fastapi/TEMPLATE.md +0 -83
- package/.agent/skills/app-builder/templates/react-native-app/TEMPLATE.md +0 -119
- package/.agent/skills/architecture/SKILL.md +0 -55
- package/.agent/skills/architecture/context-discovery.md +0 -43
- package/.agent/skills/architecture/examples.md +0 -94
- package/.agent/skills/architecture/pattern-selection.md +0 -68
- package/.agent/skills/architecture/patterns-reference.md +0 -50
- package/.agent/skills/architecture/trade-off-analysis.md +0 -77
- package/.agent/skills/clean-code/SKILL.md +0 -201
- package/.agent/skills/doc.md +0 -177
- package/.agent/skills/frontend-design/SKILL.md +0 -418
- package/.agent/skills/frontend-design/animation-guide.md +0 -331
- package/.agent/skills/frontend-design/color-system.md +0 -311
- package/.agent/skills/frontend-design/decision-trees.md +0 -418
- package/.agent/skills/frontend-design/motion-graphics.md +0 -306
- package/.agent/skills/frontend-design/scripts/accessibility_checker.py +0 -183
- package/.agent/skills/frontend-design/scripts/ux_audit.py +0 -722
- package/.agent/skills/frontend-design/typography-system.md +0 -345
- package/.agent/skills/frontend-design/ux-psychology.md +0 -1116
- package/.agent/skills/frontend-design/visual-effects.md +0 -383
- package/.agent/skills/i18n-localization/SKILL.md +0 -154
- package/.agent/skills/i18n-localization/scripts/i18n_checker.py +0 -241
- package/.agent/skills/mcp-builder/SKILL.md +0 -176
- package/.agent/skills/web-design-guidelines/SKILL.md +0 -57
- package/.agent/workflows/brainstorm.md +0 -113
- package/.agent/workflows/create.md +0 -59
- package/.agent/workflows/debug.md +0 -103
- package/.agent/workflows/deploy.md +0 -176
- package/.agent/workflows/enhance.md +0 -63
- package/.agent/workflows/orchestrate.md +0 -237
- package/.agent/workflows/plan.md +0 -89
- package/.agent/workflows/preview.md +0 -81
- package/.agent/workflows/simple-test.md +0 -42
- package/.agent/workflows/status.md +0 -86
- package/.agent/workflows/structured-orchestrate.md +0 -180
- package/.agent/workflows/test.md +0 -144
- package/.agent/workflows/ui-ux-pro-max.md +0 -296
- package/output/beef-love-poster.png +0 -0
- package/output/international-news-daily.png +0 -0
- package/poster-test-2.png +0 -0
package/plugins/weixin-plugin.js
CHANGED
|
@@ -6,18 +6,16 @@
|
|
|
6
6
|
* - forceLogin: 是否强制重新扫码登录
|
|
7
7
|
* - qrcodeTerminal: 是否在终端渲染二维码 (默认 true)
|
|
8
8
|
*/
|
|
9
|
-
|
|
9
|
+
|
|
10
10
|
const { Plugin } = require('../src/core/plugin-base')
|
|
11
11
|
const { logger } = require('../src/utils/logger')
|
|
12
12
|
const log = logger.child('WeChat')
|
|
13
|
-
const {
|
|
14
|
-
const { renderLine } = require('../cli/src/utils/markdown');
|
|
13
|
+
const {cleanResponse} =require('../src/utils')
|
|
15
14
|
const removeMarkdown = require('remove-markdown');
|
|
16
15
|
const { z } = require('zod')
|
|
17
16
|
const { WeixinBot } = require('@chnak/weixin-bot')
|
|
18
17
|
const fs = require('fs')
|
|
19
18
|
const path = require('path')
|
|
20
|
-
const dayjs = require('dayjs')
|
|
21
19
|
|
|
22
20
|
class WeixinPlugin extends Plugin {
|
|
23
21
|
constructor(config = {}) {
|
|
@@ -28,7 +26,7 @@ class WeixinPlugin extends Plugin {
|
|
|
28
26
|
this.priority = 80
|
|
29
27
|
// 默认不启用,需要在 plugins.json 中设置 enabled: true
|
|
30
28
|
this.enabled = false
|
|
31
|
-
this.path
|
|
29
|
+
this.path=`.agent/data`
|
|
32
30
|
this.systemPrompt=`你是一个微信助手。
|
|
33
31
|
|
|
34
32
|
**重要:** 子Agent 匹配规则必须遵守:
|
|
@@ -58,80 +56,6 @@ class WeixinPlugin extends Plugin {
|
|
|
58
56
|
this._initialized = false
|
|
59
57
|
}
|
|
60
58
|
|
|
61
|
-
/**
|
|
62
|
-
* 保存媒体文件到本地
|
|
63
|
-
* @param {Object} msg - 消息对象,包含 raw.item_list
|
|
64
|
-
* @param {string} type - 媒体类型: image/video/file/voice
|
|
65
|
-
* @returns {Promise<string|null>} 保存后的文件路径,失败返回 null
|
|
66
|
-
*/
|
|
67
|
-
async _saveMediaFile(msg, type) {
|
|
68
|
-
try {
|
|
69
|
-
const itemList = msg.raw?.item_list;
|
|
70
|
-
if (!itemList || !itemList[0]) {
|
|
71
|
-
return null;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
const item = itemList[0];
|
|
75
|
-
const baseDir = path.join(this.path, 'weixin-media', dayjs().format('YYYY-MM-DD'));
|
|
76
|
-
|
|
77
|
-
// 确保目录存在
|
|
78
|
-
if (!fs.existsSync(baseDir)) {
|
|
79
|
-
fs.mkdirSync(baseDir, { recursive: true });
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
const fileTimestamp = Date.now();
|
|
83
|
-
let fileName = '';
|
|
84
|
-
let downloadUrl = '';
|
|
85
|
-
|
|
86
|
-
switch (type) {
|
|
87
|
-
case 'image': {
|
|
88
|
-
fileName = `img_${fileTimestamp}.jpg`;
|
|
89
|
-
downloadUrl = item.image_item?.media?.full_url;
|
|
90
|
-
break;
|
|
91
|
-
}
|
|
92
|
-
case 'video': {
|
|
93
|
-
fileName = `video_${fileTimestamp}.mp4`;
|
|
94
|
-
downloadUrl = item.video_item?.media?.full_url || item.video_item?.aeskey;
|
|
95
|
-
break;
|
|
96
|
-
}
|
|
97
|
-
case 'file': {
|
|
98
|
-
fileName = item.file_item?.file_name || `file_${fileTimestamp}`;
|
|
99
|
-
downloadUrl = item.file_item?.media?.full_url;
|
|
100
|
-
break;
|
|
101
|
-
}
|
|
102
|
-
case 'voice': {
|
|
103
|
-
fileName = `voice_${fileTimestamp}.silk`;
|
|
104
|
-
downloadUrl = item.voice_item?.media?.full_url;
|
|
105
|
-
break;
|
|
106
|
-
}
|
|
107
|
-
default:
|
|
108
|
-
return null;
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
if (!downloadUrl) {
|
|
112
|
-
log.warn(`No download URL for ${type}`);
|
|
113
|
-
return null;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
const filePath = path.join(baseDir, fileName);
|
|
117
|
-
|
|
118
|
-
// 使用 fetch 下载文件
|
|
119
|
-
const response = await fetch(downloadUrl);
|
|
120
|
-
if (!response.ok) {
|
|
121
|
-
throw new Error(`Download failed: ${response.status}`);
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
const buffer = Buffer.from(await response.arrayBuffer());
|
|
125
|
-
fs.writeFileSync(filePath, buffer);
|
|
126
|
-
|
|
127
|
-
log.info(`Media saved: ${filePath}`);
|
|
128
|
-
return filePath;
|
|
129
|
-
} catch (err) {
|
|
130
|
-
log.error(`Failed to save ${type}:`, err.message);
|
|
131
|
-
return null;
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
|
|
135
59
|
install(framework) {
|
|
136
60
|
this._framework = framework
|
|
137
61
|
// 注册微信发送工具
|
|
@@ -387,7 +311,6 @@ class WeixinPlugin extends Plugin {
|
|
|
387
311
|
// log.info('', this.config.forceLogin ? '强制重新扫码登录...' : '正在登录(已有凭证则自动跳过扫码)...')
|
|
388
312
|
|
|
389
313
|
const creds = await this._bot.login(loginOptions)
|
|
390
|
-
console.log(creds)
|
|
391
314
|
// log.info(' 登录成功 — Bot ID:', creds.accountId)
|
|
392
315
|
// log.info(' 关联用户:', creds.userId)
|
|
393
316
|
// log.info(' API 地址:', creds.baseUrl)
|
|
@@ -496,34 +419,25 @@ class WeixinPlugin extends Plugin {
|
|
|
496
419
|
}
|
|
497
420
|
break
|
|
498
421
|
|
|
499
|
-
case 'image':
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
break;
|
|
504
|
-
}
|
|
422
|
+
case 'image':
|
|
423
|
+
// log.info(` 收到图片消息`)
|
|
424
|
+
await this._processMediaChat(userId, '[用户发送了图片]', msg)
|
|
425
|
+
break
|
|
505
426
|
|
|
506
|
-
case 'file':
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
await this._processMediaChat(userId, fileText, msg);
|
|
511
|
-
break;
|
|
512
|
-
}
|
|
427
|
+
case 'file':
|
|
428
|
+
// log.info(` 收到文件消息: ${msg.fileName || 'unknown'}`)
|
|
429
|
+
await this._processMediaChat(userId, `[用户发送了文件: ${msg.fileName || 'unknown'}]`, msg)
|
|
430
|
+
break
|
|
513
431
|
|
|
514
|
-
case 'video':
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
break;
|
|
519
|
-
}
|
|
432
|
+
case 'video':
|
|
433
|
+
// log.info(` 收到视频消息`)
|
|
434
|
+
await this._processMediaChat(userId, '[用户发送了视频]', msg)
|
|
435
|
+
break
|
|
520
436
|
|
|
521
|
-
case 'voice':
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
break;
|
|
526
|
-
}
|
|
437
|
+
case 'voice':
|
|
438
|
+
// log.info(` 收到语音消息`)
|
|
439
|
+
await this._processMediaChat(userId, '[用户发送了语音消息]', msg)
|
|
440
|
+
break
|
|
527
441
|
|
|
528
442
|
default:
|
|
529
443
|
// log.info(` 不支持的消息类型: ${msg.type}`)
|
|
@@ -533,58 +447,6 @@ class WeixinPlugin extends Plugin {
|
|
|
533
447
|
}
|
|
534
448
|
}
|
|
535
449
|
|
|
536
|
-
/**
|
|
537
|
-
* 流式处理聊天,返回完整响应
|
|
538
|
-
* @param {Object} agent - Agent 实例
|
|
539
|
-
* @param {string} text - 用户消息
|
|
540
|
-
* @param {string} sessionId - 会话 ID
|
|
541
|
-
* @returns {Promise<string>} 完整响应文本
|
|
542
|
-
*/
|
|
543
|
-
async _streamChat(agent, text, sessionId) {
|
|
544
|
-
const runWithContext = agent.framework?.runWithContext.bind(agent.framework);
|
|
545
|
-
let fullResponse = '';
|
|
546
|
-
let lineBuffer = '';
|
|
547
|
-
const renderState = { inThink: false, inCodeBlock: false };
|
|
548
|
-
|
|
549
|
-
const processChunk = (chunk) => {
|
|
550
|
-
if (chunk.type === 'text') {
|
|
551
|
-
fullResponse += chunk.text;
|
|
552
|
-
lineBuffer += chunk.text;
|
|
553
|
-
|
|
554
|
-
while (lineBuffer.includes('\n')) {
|
|
555
|
-
const nlIndex = lineBuffer.indexOf('\n');
|
|
556
|
-
const line = lineBuffer.substring(0, nlIndex);
|
|
557
|
-
lineBuffer = lineBuffer.substring(nlIndex + 1);
|
|
558
|
-
if (line.trim()) {
|
|
559
|
-
log.info(renderLine(line, renderState));
|
|
560
|
-
}
|
|
561
|
-
}
|
|
562
|
-
} else if (chunk.type === 'tool-call') {
|
|
563
|
-
log.info(`[工具调用] ${chunk.toolName}`);
|
|
564
|
-
} else if (chunk.type === 'error') {
|
|
565
|
-
log.warn(' Chat stream error:', chunk.error);
|
|
566
|
-
}
|
|
567
|
-
};
|
|
568
|
-
|
|
569
|
-
if (runWithContext) {
|
|
570
|
-
await runWithContext({ sessionId }, async () => {
|
|
571
|
-
for await (const chunk of agent.chatStream(text, { sessionId })) {
|
|
572
|
-
processChunk(chunk);
|
|
573
|
-
}
|
|
574
|
-
});
|
|
575
|
-
} else {
|
|
576
|
-
for await (const chunk of agent.chatStream(text, { sessionId })) {
|
|
577
|
-
processChunk(chunk);
|
|
578
|
-
}
|
|
579
|
-
}
|
|
580
|
-
|
|
581
|
-
if (lineBuffer.trim()) {
|
|
582
|
-
log.info(renderLine(lineBuffer, renderState));
|
|
583
|
-
}
|
|
584
|
-
|
|
585
|
-
return cleanResponse(fullResponse);
|
|
586
|
-
}
|
|
587
|
-
|
|
588
450
|
/**
|
|
589
451
|
* 处理媒体消息(图片/文件/视频/语音)
|
|
590
452
|
*/
|
|
@@ -594,7 +456,7 @@ class WeixinPlugin extends Plugin {
|
|
|
594
456
|
log.error(' No session agent available')
|
|
595
457
|
return
|
|
596
458
|
}
|
|
597
|
-
|
|
459
|
+
|
|
598
460
|
const { agent, sessionId } = sessionInfo
|
|
599
461
|
|
|
600
462
|
// 发送正在输入状态
|
|
@@ -605,7 +467,16 @@ class WeixinPlugin extends Plugin {
|
|
|
605
467
|
await new Promise((resolve) => setTimeout(resolve, 1000))
|
|
606
468
|
|
|
607
469
|
try {
|
|
608
|
-
|
|
470
|
+
// 使用 chatStream 保持和 CLI 一致的行为
|
|
471
|
+
|
|
472
|
+
let fullResponse = '';
|
|
473
|
+
for await (const chunk of agent.chatStream(text, { sessionId })) {
|
|
474
|
+
if (chunk.type === 'text') {
|
|
475
|
+
fullResponse += chunk.text;
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
const response = cleanResponse(fullResponse);
|
|
479
|
+
|
|
609
480
|
if (response) {
|
|
610
481
|
await this._sendMessageBatch(originalMsg, userId, response, true)
|
|
611
482
|
}
|
|
@@ -640,7 +511,14 @@ class WeixinPlugin extends Plugin {
|
|
|
640
511
|
await new Promise((resolve) => setTimeout(resolve, 1000))
|
|
641
512
|
|
|
642
513
|
try {
|
|
643
|
-
|
|
514
|
+
// 使用 chatStream 保持和 CLI 一致的行为
|
|
515
|
+
let fullResponse = '';
|
|
516
|
+
for await (const chunk of agent.chatStream(text, { sessionId })) {
|
|
517
|
+
if (chunk.type === 'text') {
|
|
518
|
+
fullResponse += chunk.text;
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
const response = cleanResponse(fullResponse);
|
|
644
522
|
|
|
645
523
|
// 发送回复(超过500字自动分批)
|
|
646
524
|
if (response) {
|
|
@@ -674,14 +552,8 @@ class WeixinPlugin extends Plugin {
|
|
|
674
552
|
*/
|
|
675
553
|
async _sendMessageBatch(originalMsg, userId, text, useReply = true) {
|
|
676
554
|
const MAX_LEN = 500
|
|
677
|
-
text
|
|
678
|
-
|
|
679
|
-
// 检查是否为空
|
|
680
|
-
if (!text || text.trim().length === 0) {
|
|
681
|
-
text = '[消息内容为空]'
|
|
682
|
-
}
|
|
683
|
-
|
|
684
|
-
if (text.length <= MAX_LEN) {
|
|
555
|
+
text=removeMarkdown(text)
|
|
556
|
+
if (!text || text.length <= MAX_LEN) {
|
|
685
557
|
if (useReply && originalMsg) {
|
|
686
558
|
await this._bot.reply(originalMsg, text)
|
|
687
559
|
} else {
|
|
@@ -1,162 +1,162 @@
|
|
|
1
|
-
# AGENTS.md
|
|
2
|
-
|
|
3
|
-
This file provides guidance to AI coding agents working on the `skills` CLI codebase.
|
|
4
|
-
|
|
5
|
-
## Project Overview
|
|
6
|
-
|
|
7
|
-
`skills` is the CLI for the open agent skills ecosystem.
|
|
8
|
-
|
|
9
|
-
## Commands
|
|
10
|
-
|
|
11
|
-
| Command | Description |
|
|
12
|
-
| ----------------------------- | --------------------------------------------------- |
|
|
13
|
-
| `skills` | Show banner with available commands |
|
|
14
|
-
| `skills add <pkg>` | Install skills from git repos, URLs, or local paths |
|
|
15
|
-
| `skills experimental_install` | Restore skills from skills-lock.json |
|
|
16
|
-
| `skills experimental_sync` | Sync skills from node_modules into agent dirs |
|
|
17
|
-
| `skills list` | List installed skills (alias: `ls`) |
|
|
18
|
-
| `skills check` | Check for available skill updates |
|
|
19
|
-
| `skills update` | Update all skills to latest versions |
|
|
20
|
-
| `skills init [name]` | Create a new SKILL.md template |
|
|
21
|
-
|
|
22
|
-
Aliases: `skills a` works for `add`. `skills i`, `skills install` (no args) restore from `skills-lock.json`. `skills ls` works for `list`. `skills experimental_install` restores from `skills-lock.json`. `skills experimental_sync` crawls `node_modules` for skills.
|
|
23
|
-
|
|
24
|
-
## Architecture
|
|
25
|
-
|
|
26
|
-
```
|
|
27
|
-
src/
|
|
28
|
-
├── cli.ts # Main entry point, command routing, init/check/update
|
|
29
|
-
├── cli.test.ts # CLI tests
|
|
30
|
-
├── add.ts # Core add command logic
|
|
31
|
-
├── add.test.ts # Add command tests
|
|
32
|
-
├── list.ts # List installed skills command
|
|
33
|
-
├── list.test.ts # List command tests
|
|
34
|
-
├── agents.ts # Agent definitions and detection
|
|
35
|
-
├── installer.ts # Skill installation logic (symlink/copy) + listInstalledSkills
|
|
36
|
-
├── skills.ts # Skill discovery and parsing
|
|
37
|
-
├── skill-lock.ts # Global lock file management (~/.agents/.skill-lock.json)
|
|
38
|
-
├── local-lock.ts # Local lock file management (skills-lock.json, checked in)
|
|
39
|
-
├── sync.ts # Sync command - crawl node_modules for skills
|
|
40
|
-
├── source-parser.ts # Parse git URLs, GitHub shorthand, local paths
|
|
41
|
-
├── git.ts # Git clone operations
|
|
42
|
-
├── telemetry.ts # Anonymous usage tracking
|
|
43
|
-
├── types.ts # TypeScript types
|
|
44
|
-
├── mintlify.ts # Mintlify skill fetching (legacy)
|
|
45
|
-
├── providers/ # Remote skill providers (GitHub, HuggingFace, Mintlify)
|
|
46
|
-
│ ├── index.ts
|
|
47
|
-
│ ├── registry.ts
|
|
48
|
-
│ ├── types.ts
|
|
49
|
-
│ ├── huggingface.ts
|
|
50
|
-
│ └── mintlify.ts
|
|
51
|
-
├── init.test.ts # Init command tests
|
|
52
|
-
└── test-utils.ts # Test utilities
|
|
53
|
-
|
|
54
|
-
tests/
|
|
55
|
-
├── sanitize-name.test.ts # Tests for sanitizeName (path traversal prevention)
|
|
56
|
-
├── skill-matching.test.ts # Tests for filterSkills (multi-word skill name matching)
|
|
57
|
-
├── source-parser.test.ts # Tests for URL/path parsing
|
|
58
|
-
├── installer-symlink.test.ts # Tests for symlink installation
|
|
59
|
-
├── list-installed.test.ts # Tests for listing installed skills
|
|
60
|
-
├── skill-path.test.ts # Tests for skill path handling
|
|
61
|
-
├── wellknown-provider.test.ts # Tests for well-known provider
|
|
62
|
-
└── dist.test.ts # Tests for built distribution
|
|
63
|
-
```
|
|
64
|
-
|
|
65
|
-
## Update Checking System
|
|
66
|
-
|
|
67
|
-
### How `skills check` and `skills update` Work
|
|
68
|
-
|
|
69
|
-
1. Read `~/.agents/.skill-lock.json` for installed skills
|
|
70
|
-
2. For each skill, get `skillFolderHash` from lock file
|
|
71
|
-
3. POST to `https://add-skill.vercel.sh/check-updates` with:
|
|
72
|
-
```json
|
|
73
|
-
{
|
|
74
|
-
"skills": [{ "name": "...", "source": "...", "skillFolderHash": "..." }],
|
|
75
|
-
"forceRefresh": true
|
|
76
|
-
}
|
|
77
|
-
```
|
|
78
|
-
4. API fetches fresh content from GitHub, computes hash, compares
|
|
79
|
-
5. Returns list of skills with different hashes (updates available)
|
|
80
|
-
|
|
81
|
-
### Why `forceRefresh: true`?
|
|
82
|
-
|
|
83
|
-
Both `check` and `update` always send `forceRefresh: true`. This ensures the API fetches fresh content from GitHub rather than using its Redis cache.
|
|
84
|
-
|
|
85
|
-
**Without forceRefresh:** Users saw phantom "updates available" due to stale cached hashes. The fix was to always fetch fresh.
|
|
86
|
-
|
|
87
|
-
**Tradeoff:** Slightly slower (GitHub API call per skill), but always accurate.
|
|
88
|
-
|
|
89
|
-
### Lock File Compatibility
|
|
90
|
-
|
|
91
|
-
The lock file format is v3. Key field: `skillFolderHash` (GitHub tree SHA for the skill folder).
|
|
92
|
-
|
|
93
|
-
If reading an older lock file version, it's wiped. Users must reinstall skills to populate the new format.
|
|
94
|
-
|
|
95
|
-
## Key Integration Points
|
|
96
|
-
|
|
97
|
-
| Feature | Implementation |
|
|
98
|
-
| -------------------------- | ------------------------------------------- |
|
|
99
|
-
| `skills add` | `src/add.ts` - full implementation |
|
|
100
|
-
| `skills experimental_sync` | `src/sync.ts` - crawl node_modules |
|
|
101
|
-
| `skills check` | `POST /check-updates` API |
|
|
102
|
-
| `skills update` | `POST /check-updates` + reinstall per skill |
|
|
103
|
-
|
|
104
|
-
## Development
|
|
105
|
-
|
|
106
|
-
```bash
|
|
107
|
-
# Install dependencies
|
|
108
|
-
pnpm install
|
|
109
|
-
|
|
110
|
-
# Build
|
|
111
|
-
pnpm build
|
|
112
|
-
|
|
113
|
-
# Test locally
|
|
114
|
-
pnpm dev add vercel-labs/agent-skills --list
|
|
115
|
-
pnpm dev experimental_sync
|
|
116
|
-
pnpm dev check
|
|
117
|
-
pnpm dev update
|
|
118
|
-
pnpm dev init my-skill
|
|
119
|
-
|
|
120
|
-
# Run all tests
|
|
121
|
-
pnpm test
|
|
122
|
-
|
|
123
|
-
# Run specific test file(s)
|
|
124
|
-
pnpm test tests/sanitize-name.test.ts
|
|
125
|
-
pnpm test tests/skill-matching.test.ts tests/source-parser.test.ts
|
|
126
|
-
|
|
127
|
-
# Type check
|
|
128
|
-
pnpm type-check
|
|
129
|
-
|
|
130
|
-
# Format code
|
|
131
|
-
pnpm format
|
|
132
|
-
```
|
|
133
|
-
|
|
134
|
-
## Code Style
|
|
135
|
-
|
|
136
|
-
This project uses Prettier for code formatting. **Always run `pnpm format` before committing changes** to ensure consistent formatting.
|
|
137
|
-
|
|
138
|
-
```bash
|
|
139
|
-
# Format all files
|
|
140
|
-
pnpm format
|
|
141
|
-
|
|
142
|
-
# Check formatting without fixing
|
|
143
|
-
pnpm prettier --check .
|
|
144
|
-
```
|
|
145
|
-
|
|
146
|
-
CI will fail if code is not properly formatted.
|
|
147
|
-
|
|
148
|
-
## Publishing
|
|
149
|
-
|
|
150
|
-
```bash
|
|
151
|
-
# 1. Bump version in package.json
|
|
152
|
-
# 2. Build
|
|
153
|
-
pnpm build
|
|
154
|
-
# 3. Publish
|
|
155
|
-
npm publish
|
|
156
|
-
```
|
|
157
|
-
|
|
158
|
-
## Adding a New Agent
|
|
159
|
-
|
|
160
|
-
1. Add the agent definition to `src/agents.ts`
|
|
161
|
-
2. Run `pnpm run -C scripts validate-agents.ts` to validate
|
|
162
|
-
3. Run `pnpm run -C scripts sync-agents.ts` to update README.md
|
|
1
|
+
# AGENTS.md
|
|
2
|
+
|
|
3
|
+
This file provides guidance to AI coding agents working on the `skills` CLI codebase.
|
|
4
|
+
|
|
5
|
+
## Project Overview
|
|
6
|
+
|
|
7
|
+
`skills` is the CLI for the open agent skills ecosystem.
|
|
8
|
+
|
|
9
|
+
## Commands
|
|
10
|
+
|
|
11
|
+
| Command | Description |
|
|
12
|
+
| ----------------------------- | --------------------------------------------------- |
|
|
13
|
+
| `skills` | Show banner with available commands |
|
|
14
|
+
| `skills add <pkg>` | Install skills from git repos, URLs, or local paths |
|
|
15
|
+
| `skills experimental_install` | Restore skills from skills-lock.json |
|
|
16
|
+
| `skills experimental_sync` | Sync skills from node_modules into agent dirs |
|
|
17
|
+
| `skills list` | List installed skills (alias: `ls`) |
|
|
18
|
+
| `skills check` | Check for available skill updates |
|
|
19
|
+
| `skills update` | Update all skills to latest versions |
|
|
20
|
+
| `skills init [name]` | Create a new SKILL.md template |
|
|
21
|
+
|
|
22
|
+
Aliases: `skills a` works for `add`. `skills i`, `skills install` (no args) restore from `skills-lock.json`. `skills ls` works for `list`. `skills experimental_install` restores from `skills-lock.json`. `skills experimental_sync` crawls `node_modules` for skills.
|
|
23
|
+
|
|
24
|
+
## Architecture
|
|
25
|
+
|
|
26
|
+
```
|
|
27
|
+
src/
|
|
28
|
+
├── cli.ts # Main entry point, command routing, init/check/update
|
|
29
|
+
├── cli.test.ts # CLI tests
|
|
30
|
+
├── add.ts # Core add command logic
|
|
31
|
+
├── add.test.ts # Add command tests
|
|
32
|
+
├── list.ts # List installed skills command
|
|
33
|
+
├── list.test.ts # List command tests
|
|
34
|
+
├── agents.ts # Agent definitions and detection
|
|
35
|
+
├── installer.ts # Skill installation logic (symlink/copy) + listInstalledSkills
|
|
36
|
+
├── skills.ts # Skill discovery and parsing
|
|
37
|
+
├── skill-lock.ts # Global lock file management (~/.agents/.skill-lock.json)
|
|
38
|
+
├── local-lock.ts # Local lock file management (skills-lock.json, checked in)
|
|
39
|
+
├── sync.ts # Sync command - crawl node_modules for skills
|
|
40
|
+
├── source-parser.ts # Parse git URLs, GitHub shorthand, local paths
|
|
41
|
+
├── git.ts # Git clone operations
|
|
42
|
+
├── telemetry.ts # Anonymous usage tracking
|
|
43
|
+
├── types.ts # TypeScript types
|
|
44
|
+
├── mintlify.ts # Mintlify skill fetching (legacy)
|
|
45
|
+
├── providers/ # Remote skill providers (GitHub, HuggingFace, Mintlify)
|
|
46
|
+
│ ├── index.ts
|
|
47
|
+
│ ├── registry.ts
|
|
48
|
+
│ ├── types.ts
|
|
49
|
+
│ ├── huggingface.ts
|
|
50
|
+
│ └── mintlify.ts
|
|
51
|
+
├── init.test.ts # Init command tests
|
|
52
|
+
└── test-utils.ts # Test utilities
|
|
53
|
+
|
|
54
|
+
tests/
|
|
55
|
+
├── sanitize-name.test.ts # Tests for sanitizeName (path traversal prevention)
|
|
56
|
+
├── skill-matching.test.ts # Tests for filterSkills (multi-word skill name matching)
|
|
57
|
+
├── source-parser.test.ts # Tests for URL/path parsing
|
|
58
|
+
├── installer-symlink.test.ts # Tests for symlink installation
|
|
59
|
+
├── list-installed.test.ts # Tests for listing installed skills
|
|
60
|
+
├── skill-path.test.ts # Tests for skill path handling
|
|
61
|
+
├── wellknown-provider.test.ts # Tests for well-known provider
|
|
62
|
+
└── dist.test.ts # Tests for built distribution
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## Update Checking System
|
|
66
|
+
|
|
67
|
+
### How `skills check` and `skills update` Work
|
|
68
|
+
|
|
69
|
+
1. Read `~/.agents/.skill-lock.json` for installed skills
|
|
70
|
+
2. For each skill, get `skillFolderHash` from lock file
|
|
71
|
+
3. POST to `https://add-skill.vercel.sh/check-updates` with:
|
|
72
|
+
```json
|
|
73
|
+
{
|
|
74
|
+
"skills": [{ "name": "...", "source": "...", "skillFolderHash": "..." }],
|
|
75
|
+
"forceRefresh": true
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
4. API fetches fresh content from GitHub, computes hash, compares
|
|
79
|
+
5. Returns list of skills with different hashes (updates available)
|
|
80
|
+
|
|
81
|
+
### Why `forceRefresh: true`?
|
|
82
|
+
|
|
83
|
+
Both `check` and `update` always send `forceRefresh: true`. This ensures the API fetches fresh content from GitHub rather than using its Redis cache.
|
|
84
|
+
|
|
85
|
+
**Without forceRefresh:** Users saw phantom "updates available" due to stale cached hashes. The fix was to always fetch fresh.
|
|
86
|
+
|
|
87
|
+
**Tradeoff:** Slightly slower (GitHub API call per skill), but always accurate.
|
|
88
|
+
|
|
89
|
+
### Lock File Compatibility
|
|
90
|
+
|
|
91
|
+
The lock file format is v3. Key field: `skillFolderHash` (GitHub tree SHA for the skill folder).
|
|
92
|
+
|
|
93
|
+
If reading an older lock file version, it's wiped. Users must reinstall skills to populate the new format.
|
|
94
|
+
|
|
95
|
+
## Key Integration Points
|
|
96
|
+
|
|
97
|
+
| Feature | Implementation |
|
|
98
|
+
| -------------------------- | ------------------------------------------- |
|
|
99
|
+
| `skills add` | `src/add.ts` - full implementation |
|
|
100
|
+
| `skills experimental_sync` | `src/sync.ts` - crawl node_modules |
|
|
101
|
+
| `skills check` | `POST /check-updates` API |
|
|
102
|
+
| `skills update` | `POST /check-updates` + reinstall per skill |
|
|
103
|
+
|
|
104
|
+
## Development
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
# Install dependencies
|
|
108
|
+
pnpm install
|
|
109
|
+
|
|
110
|
+
# Build
|
|
111
|
+
pnpm build
|
|
112
|
+
|
|
113
|
+
# Test locally
|
|
114
|
+
pnpm dev add vercel-labs/agent-skills --list
|
|
115
|
+
pnpm dev experimental_sync
|
|
116
|
+
pnpm dev check
|
|
117
|
+
pnpm dev update
|
|
118
|
+
pnpm dev init my-skill
|
|
119
|
+
|
|
120
|
+
# Run all tests
|
|
121
|
+
pnpm test
|
|
122
|
+
|
|
123
|
+
# Run specific test file(s)
|
|
124
|
+
pnpm test tests/sanitize-name.test.ts
|
|
125
|
+
pnpm test tests/skill-matching.test.ts tests/source-parser.test.ts
|
|
126
|
+
|
|
127
|
+
# Type check
|
|
128
|
+
pnpm type-check
|
|
129
|
+
|
|
130
|
+
# Format code
|
|
131
|
+
pnpm format
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
## Code Style
|
|
135
|
+
|
|
136
|
+
This project uses Prettier for code formatting. **Always run `pnpm format` before committing changes** to ensure consistent formatting.
|
|
137
|
+
|
|
138
|
+
```bash
|
|
139
|
+
# Format all files
|
|
140
|
+
pnpm format
|
|
141
|
+
|
|
142
|
+
# Check formatting without fixing
|
|
143
|
+
pnpm prettier --check .
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
CI will fail if code is not properly formatted.
|
|
147
|
+
|
|
148
|
+
## Publishing
|
|
149
|
+
|
|
150
|
+
```bash
|
|
151
|
+
# 1. Bump version in package.json
|
|
152
|
+
# 2. Build
|
|
153
|
+
pnpm build
|
|
154
|
+
# 3. Publish
|
|
155
|
+
npm publish
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
## Adding a New Agent
|
|
159
|
+
|
|
160
|
+
1. Add the agent definition to `src/agents.ts`
|
|
161
|
+
2. Run `pnpm run -C scripts validate-agents.ts` to validate
|
|
162
|
+
3. Run `pnpm run -C scripts sync-agents.ts` to update README.md
|