@optima-chat/optima-agent 0.8.44 → 0.8.47

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 (80) hide show
  1. package/.claude/skills/xhs/SKILL.md +178 -0
  2. package/dist/bin/bi-cli.js +0 -0
  3. package/dist/bin/commerce.js +0 -0
  4. package/dist/bin/google-ads.js +0 -0
  5. package/dist/bin/optima.js +0 -0
  6. package/dist/bin/scout.js +0 -0
  7. package/dist/src/agent.d.ts +1 -1
  8. package/dist/src/system-prompt.d.ts.map +1 -1
  9. package/dist/src/system-prompt.js +13 -21
  10. package/dist/src/system-prompt.js.map +1 -1
  11. package/package.json +1 -1
  12. package/.claude/settings.local.json +0 -154
  13. package/dist/bin/comfy.d.ts +0 -3
  14. package/dist/bin/comfy.d.ts.map +0 -1
  15. package/dist/bin/comfy.js +0 -3
  16. package/dist/bin/comfy.js.map +0 -1
  17. package/dist/src/hooks-loader.d.ts +0 -6
  18. package/dist/src/hooks-loader.d.ts.map +0 -1
  19. package/dist/src/hooks-loader.js +0 -215
  20. package/dist/src/hooks-loader.js.map +0 -1
  21. package/dist/src/ui/App.d.ts +0 -6
  22. package/dist/src/ui/App.d.ts.map +0 -1
  23. package/dist/src/ui/App.js +0 -164
  24. package/dist/src/ui/App.js.map +0 -1
  25. package/dist/src/ui/components/Composer.d.ts +0 -10
  26. package/dist/src/ui/components/Composer.d.ts.map +0 -1
  27. package/dist/src/ui/components/Composer.js +0 -13
  28. package/dist/src/ui/components/Composer.js.map +0 -1
  29. package/dist/src/ui/components/Header.d.ts +0 -7
  30. package/dist/src/ui/components/Header.d.ts.map +0 -1
  31. package/dist/src/ui/components/Header.js +0 -7
  32. package/dist/src/ui/components/Header.js.map +0 -1
  33. package/dist/src/ui/components/Message.d.ts +0 -12
  34. package/dist/src/ui/components/Message.d.ts.map +0 -1
  35. package/dist/src/ui/components/Message.js +0 -21
  36. package/dist/src/ui/components/Message.js.map +0 -1
  37. package/dist/src/ui/components/MessageList.d.ts +0 -9
  38. package/dist/src/ui/components/MessageList.d.ts.map +0 -1
  39. package/dist/src/ui/components/MessageList.js +0 -18
  40. package/dist/src/ui/components/MessageList.js.map +0 -1
  41. package/dist/src/ui/components/Spinner.d.ts +0 -6
  42. package/dist/src/ui/components/Spinner.d.ts.map +0 -1
  43. package/dist/src/ui/components/Spinner.js +0 -7
  44. package/dist/src/ui/components/Spinner.js.map +0 -1
  45. package/dist/src/ui/components/StatusBar.d.ts +0 -11
  46. package/dist/src/ui/components/StatusBar.d.ts.map +0 -1
  47. package/dist/src/ui/components/StatusBar.js +0 -7
  48. package/dist/src/ui/components/StatusBar.js.map +0 -1
  49. package/dist/src/ui/components/index.d.ts +0 -7
  50. package/dist/src/ui/components/index.d.ts.map +0 -1
  51. package/dist/src/ui/components/index.js +0 -7
  52. package/dist/src/ui/components/index.js.map +0 -1
  53. package/dist/src/validation/error-formatter.d.ts +0 -21
  54. package/dist/src/validation/error-formatter.d.ts.map +0 -1
  55. package/dist/src/validation/error-formatter.js +0 -98
  56. package/dist/src/validation/error-formatter.js.map +0 -1
  57. package/dist/src/validation/index.d.ts +0 -10
  58. package/dist/src/validation/index.d.ts.map +0 -1
  59. package/dist/src/validation/index.js +0 -10
  60. package/dist/src/validation/index.js.map +0 -1
  61. package/dist/src/validation/json-validator.d.ts +0 -25
  62. package/dist/src/validation/json-validator.d.ts.map +0 -1
  63. package/dist/src/validation/json-validator.js +0 -173
  64. package/dist/src/validation/json-validator.js.map +0 -1
  65. package/dist/src/validation/schema.d.ts +0 -353
  66. package/dist/src/validation/schema.d.ts.map +0 -1
  67. package/dist/src/validation/schema.js +0 -57
  68. package/dist/src/validation/schema.js.map +0 -1
  69. package/dist/src/validation/suggestions.d.ts +0 -25
  70. package/dist/src/validation/suggestions.d.ts.map +0 -1
  71. package/dist/src/validation/suggestions.js +0 -144
  72. package/dist/src/validation/suggestions.js.map +0 -1
  73. package/dist/src/validation/types.d.ts +0 -40
  74. package/dist/src/validation/types.d.ts.map +0 -1
  75. package/dist/src/validation/types.js +0 -5
  76. package/dist/src/validation/types.js.map +0 -1
  77. package/dist/src/validation/yaml-validator.d.ts +0 -25
  78. package/dist/src/validation/yaml-validator.d.ts.map +0 -1
  79. package/dist/src/validation/yaml-validator.js +0 -177
  80. package/dist/src/validation/yaml-validator.js.map +0 -1
@@ -0,0 +1,178 @@
1
+ ---
2
+ name: xhs
3
+ description: "小红书笔记搜索、创作者分析和内容趋势研究。当用户需要搜索小红书笔记(小红书/红书/XHS/种草/笔记)、查看小红书博主(博主/达人/KOL/创作者)、分析小红书内容(内容分析/爆款笔记)、或研究小红书市场趋势(小红书选品/什么好卖/种草趋势)时使用此技能。"
4
+ ---
5
+
6
+ # 小红书 (XHS) - 笔记搜索与创作者分析
7
+
8
+ 所有命令使用 `scout xhs` 前缀。
9
+
10
+ ---
11
+
12
+ ## 快速选择:我该用哪个命令?
13
+
14
+ | 你的目标 | 命令 | 说明 |
15
+ |---------|------|------|
16
+ | **搜产品/找灵感** | `search-notes "关键词"` | 搜索笔记,支持中英文关键词 |
17
+ | **分析某篇笔记** | `note-detail <noteId>` | 获取笔记详情(互动数据、标签等) |
18
+ | **看博主主页** | `user-profile <userId>` | 粉丝数、笔记数、获赞数 |
19
+ | **看博主作品** | `user-notes <userId>` | 博主发布的笔记列表 |
20
+ | **看博主收藏** | `user-collected <userId>` | 博主收藏了什么(选品灵感) |
21
+
22
+ ---
23
+
24
+ ## 典型场景
25
+
26
+ 当用户说:
27
+ - "小红书上搜一下XX" / "小红书什么火" → `scout xhs search-notes "XX"`
28
+ - "看看这个笔记" + noteId → `scout xhs note-detail <noteId>`
29
+ - "看看这个博主" + userId → `scout xhs user-profile <userId>`
30
+ - "这个博主发了什么" → `scout xhs user-notes <userId>`
31
+ - "这个博主收藏了什么" → `scout xhs user-collected <userId>`
32
+ - "小红书上XX好不好卖" → `scout xhs search-notes "XX"` 分析互动数据
33
+ - "找小红书达人" → `scout xhs search-notes "品类关键词"` 从高赞笔记找创作者
34
+
35
+ ---
36
+
37
+ ## URL 解析 - 小红书链接处理
38
+
39
+ 用户可能贴小红书链接。**不要用 WebFetch**(会被登录墙拦截),按以下规则提取 ID:
40
+
41
+ | URL 特征 | 提取内容 | 调用命令 |
42
+ |----------|---------|---------|
43
+ | `xiaohongshu.com/explore/笔记ID` | note_id(末尾的十六进制字符串) | `scout xhs note-detail <noteId>` |
44
+ | `xiaohongshu.com/user/profile/用户ID` | user_id | `scout xhs user-profile <userId>` |
45
+ | `xhslink.com/短链接` | 无法直接提取,告知用户提供 note_id | — |
46
+
47
+ ---
48
+
49
+ ## 命令详情
50
+
51
+ ### 搜索笔记 — `scout xhs search-notes`
52
+
53
+ ```bash
54
+ scout xhs search-notes "瑜伽裤" --page 1 --page-size 20
55
+ ```
56
+
57
+ **参数**:
58
+ - `关键词`(必填):支持中英文
59
+ - `--page`:页码(默认 1)
60
+ - `--page-size`:每页数量(默认 20)
61
+ - `-f, --format`:`json`(默认)| `text`
62
+
63
+ **返回数据**:
64
+ - `id` — 笔记 ID
65
+ - `title` — 标题
66
+ - `description` — 正文
67
+ - `type` — `image` 或 `video`
68
+ - `creator` — 作者(uid, username)
69
+ - `likes`, `comments`, `collects`, `shares` — 互动数据
70
+ - `url` — 笔记链接
71
+ - `hashtags` — 标签列表
72
+
73
+ ### 笔记详情 — `scout xhs note-detail`
74
+
75
+ ```bash
76
+ scout xhs note-detail 6489a2b0000000001e012345
77
+ ```
78
+
79
+ ### 用户主页 — `scout xhs user-profile`
80
+
81
+ ```bash
82
+ scout xhs user-profile 5a1234567890abcdef012345
83
+ ```
84
+
85
+ **返回数据**:
86
+ - `uid`, `username` — 用户基本信息
87
+ - `followers`, `following`, `totalNotes`, `totalLikes` — 数据概览
88
+ - `bio` — 简介
89
+ - `verified`, `verifyContent` — 认证状态
90
+ - `ipLocation` — IP 属地
91
+
92
+ ### 用户笔记 — `scout xhs user-notes`
93
+
94
+ ```bash
95
+ scout xhs user-notes 5a1234567890abcdef012345 --num 30
96
+ ```
97
+
98
+ **参数**:
99
+ - `--num`:数量(默认 30)
100
+ - `--cursor`:分页游标(翻页用)
101
+
102
+ ### 用户收藏 — `scout xhs user-collected`
103
+
104
+ ```bash
105
+ scout xhs user-collected 5a1234567890abcdef012345
106
+ ```
107
+
108
+ ---
109
+
110
+ ## 数据解读
111
+
112
+ ### 互动数据指标
113
+
114
+ | 指标 | 爆款 | 优质 | 普通 | 低迷 |
115
+ |------|------|------|------|------|
116
+ | likes | >1万 | 1000-1万 | 100-1000 | <100 |
117
+ | collects | >5000 | 500-5000 | 50-500 | <50 |
118
+ | comments | >500 | 100-500 | 10-100 | <10 |
119
+
120
+ - **高赞 + 高收藏** = 内容有价值,用户想留存
121
+ - **高赞 + 低收藏** = 娱乐性内容,不够实用
122
+ - **低赞 + 高收藏** = 实用干货,用户默默收藏
123
+ - **收藏/点赞比 > 0.5** = 强购买意向信号(选品关键指标)
124
+
125
+ ### 创作者评估
126
+
127
+ | 指标 | 头部达人 | 腰部达人 | 尾部达人 |
128
+ |------|---------|---------|---------|
129
+ | followers | >50万 | 1万-50万 | <1万 |
130
+ | totalNotes | >200 | 50-200 | <50 |
131
+
132
+ ---
133
+
134
+ ## 使用场景
135
+
136
+ ### 场景 1:选品调研
137
+
138
+ ```bash
139
+ # 搜索品类,分析爆款笔记的互动数据
140
+ scout xhs search-notes "瑜伽裤测评" --page-size 20
141
+
142
+ # 分析:
143
+ # - 高收藏/点赞比的笔记 = 有购买意向的品类
144
+ # - 多篇爆款笔记提到的品牌/功能 = 市场验证的卖点
145
+ ```
146
+
147
+ ### 场景 2:达人分析
148
+
149
+ ```bash
150
+ # 从热门笔记找到达人 → 看主页 → 看作品
151
+ scout xhs search-notes "护肤推荐"
152
+ scout xhs user-profile <从笔记中获取的userId>
153
+ scout xhs user-notes <userId>
154
+ ```
155
+
156
+ ### 场景 3:跨平台验证
157
+
158
+ ```bash
159
+ # 1. 小红书发现趋势
160
+ scout xhs search-notes "防晒霜推荐"
161
+
162
+ # 2. Amazon 验证海外市场需求
163
+ scout search "sunscreen"
164
+
165
+ # 3. 1688 找供应商
166
+ scout supplier-search "防晒霜"
167
+ ```
168
+
169
+ ---
170
+
171
+ ## 重要提醒
172
+
173
+ 1. **中文关键词效果更好**:小红书是中文平台,用中文搜索更精准
174
+ 2. **收藏数是核心选品指标**:收藏 = 购买意向,比点赞更有参考价值
175
+ 3. **笔记 ID 是十六进制字符串**:类似 `6489a2b0000000001e012345`
176
+ 4. **用户 ID 也是十六进制字符串**:类似 `5a1234567890abcdef012345`
177
+ 5. **不要用 WebFetch 访问小红书**:会被登录墙拦截,只能通过 API
178
+ 6. **跨平台联动**:小红书发现趋势 → Amazon/TikTok 验证需求 → 1688 找供应商
File without changes
File without changes
File without changes
File without changes
package/dist/bin/scout.js CHANGED
File without changes
@@ -11,7 +11,7 @@ export declare class OptimaAgent {
11
11
  * @param prompt 用户输入
12
12
  * @param chatOptions 选项,包括 streamFormat: 'delta' | 'content'
13
13
  */
14
- chat(prompt: string, chatOptions?: ChatOptions): AsyncGenerator<import("@anthropic-ai/claude-agent-sdk").SDKUserMessage | import("@anthropic-ai/claude-agent-sdk").SDKAssistantMessage | import("@anthropic-ai/claude-agent-sdk").SDKResultSuccess | import("@anthropic-ai/claude-agent-sdk").SDKResultError | import("@anthropic-ai/claude-agent-sdk").SDKSystemMessage | import("@anthropic-ai/claude-agent-sdk").SDKPartialAssistantMessage | import("@anthropic-ai/claude-agent-sdk").SDKCompactBoundaryMessage | import("@anthropic-ai/claude-agent-sdk").SDKStatusMessage | import("@anthropic-ai/claude-agent-sdk").SDKAPIRetryMessage | import("@anthropic-ai/claude-agent-sdk").SDKLocalCommandOutputMessage | import("@anthropic-ai/claude-agent-sdk").SDKHookStartedMessage | import("@anthropic-ai/claude-agent-sdk").SDKHookProgressMessage | import("@anthropic-ai/claude-agent-sdk").SDKHookResponseMessage | import("@anthropic-ai/claude-agent-sdk").SDKToolProgressMessage | import("@anthropic-ai/claude-agent-sdk").SDKAuthStatusMessage | import("@anthropic-ai/claude-agent-sdk").SDKTaskNotificationMessage | import("@anthropic-ai/claude-agent-sdk").SDKTaskStartedMessage | import("@anthropic-ai/claude-agent-sdk").SDKTaskProgressMessage | import("@anthropic-ai/claude-agent-sdk").SDKFilesPersistedEvent | import("@anthropic-ai/claude-agent-sdk").SDKToolUseSummaryMessage | import("@anthropic-ai/claude-agent-sdk").SDKRateLimitEvent | import("@anthropic-ai/claude-agent-sdk").SDKElicitationCompleteMessage | import("@anthropic-ai/claude-agent-sdk").SDKPromptSuggestionMessage | {
14
+ chat(prompt: string, chatOptions?: ChatOptions): AsyncGenerator<import("@anthropic-ai/claude-agent-sdk").SDKUserMessage | import("@anthropic-ai/claude-agent-sdk").SDKAssistantMessage | import("@anthropic-ai/claude-agent-sdk").SDKResultSuccess | import("@anthropic-ai/claude-agent-sdk").SDKResultError | import("@anthropic-ai/claude-agent-sdk").SDKSystemMessage | import("@anthropic-ai/claude-agent-sdk").SDKPartialAssistantMessage | import("@anthropic-ai/claude-agent-sdk").SDKCompactBoundaryMessage | import("@anthropic-ai/claude-agent-sdk").SDKStatusMessage | import("@anthropic-ai/claude-agent-sdk").SDKLocalCommandOutputMessage | import("@anthropic-ai/claude-agent-sdk").SDKHookStartedMessage | import("@anthropic-ai/claude-agent-sdk").SDKHookProgressMessage | import("@anthropic-ai/claude-agent-sdk").SDKHookResponseMessage | import("@anthropic-ai/claude-agent-sdk").SDKToolProgressMessage | import("@anthropic-ai/claude-agent-sdk").SDKAuthStatusMessage | import("@anthropic-ai/claude-agent-sdk").SDKTaskNotificationMessage | import("@anthropic-ai/claude-agent-sdk").SDKTaskStartedMessage | import("@anthropic-ai/claude-agent-sdk").SDKTaskProgressMessage | import("@anthropic-ai/claude-agent-sdk").SDKFilesPersistedEvent | import("@anthropic-ai/claude-agent-sdk").SDKToolUseSummaryMessage | import("@anthropic-ai/claude-agent-sdk").SDKRateLimitEvent | import("@anthropic-ai/claude-agent-sdk").SDKElicitationCompleteMessage | import("@anthropic-ai/claude-agent-sdk").SDKPromptSuggestionMessage | {
15
15
  type: "text_delta";
16
16
  delta: {
17
17
  text: string;
@@ -1 +1 @@
1
- {"version":3,"file":"system-prompt.d.ts","sourceRoot":"","sources":["../../src/system-prompt.ts"],"names":[],"mappings":"AAAA,wBAAgB,eAAe,IAAI,MAAM,CA6KxC"}
1
+ {"version":3,"file":"system-prompt.d.ts","sourceRoot":"","sources":["../../src/system-prompt.ts"],"names":[],"mappings":"AAAA,wBAAgB,eAAe,IAAI,MAAM,CAqKxC"}
@@ -126,29 +126,21 @@ export function getSystemPrompt() {
126
126
  - 简要说明创建商铺的价值(管理商品、查看数据等)
127
127
  - 必须使用准确的 action link 格式:\`action://create-merchant\`
128
128
 
129
- ## 文件下载链接
130
-
131
- 当你生成报告、文档、图片等文件后,需要给用户提供**可直接在浏览器打开的下载链接**。
132
-
133
- **步骤**:
134
- 1. 用 Write 工具将文件保存到用户工作目录(如 \`/home/aiuser/docs/报告.pdf\`)
135
- 2. 用 Bash 调用签名链接 API 生成下载 URL
136
- \`\`\`bash
137
- TOKEN=$(jq -r .access_token ~/.optima/token.json)
138
- curl -s -X POST "$SESSION_GATEWAY_URL/api/user/files/share?path=/home/aiuser/docs/报告.pdf" \\
139
- -H "Authorization: Bearer $TOKEN"
140
- \`\`\`
141
- 3. 从返回的 JSON 中提取 \`url\` 字段,展示给用户
142
-
143
- **返回示例**:
144
- \`\`\`json
145
- {"data":{"url":"https://shell.optima.shop/api/files/d/xxxxx","expiresAt":"...","fileName":"报告.pdf","fileSize":12345}}
129
+ ## 文件与工作空间
130
+
131
+ 用户的工作目录(\`/home/aiuser/\`)就是 workspace,用户可以在 Web UI 的文件管理器中直接查看和下载里面的文件。
132
+
133
+ **默认行为**:生成或下载文件后,保存到工作目录并告诉用户文件位置即可。用户能在文件管理器中直接看到。
134
+
135
+ **生成分享链接**:仅当用户明确要求"给我链接"、"发给别人"、"分享链接"时,才调用签名链接 API:
136
+ \`\`\`bash
137
+ TOKEN=$(jq -r .access_token ~/.optima/token.json)
138
+ curl -s -X POST "$SESSION_GATEWAY_URL/api/user/files/share?path=/home/aiuser/docs/报告.pdf" \\
139
+ -H "Authorization: Bearer $TOKEN"
146
140
  \`\`\`
141
+ 返回 JSON 中的 \`url\` 字段即为下载链接(有效期 30 分钟)。展示时用 Markdown:\`[下载报告](url)\`
147
142
 
148
- **注意事项**:
149
- - 链接有效期 30 分钟,过期后需重新生成
150
- - **不要**自己拼接下载 URL,必须通过 API 生成
151
- - 展示链接时用 Markdown 格式:\`[下载报告](url)\`
143
+ **注意**:不要自己拼接下载 URL,必须通过 API 生成。
152
144
 
153
145
  ## 用户记忆
154
146
 
@@ -1 +1 @@
1
- {"version":3,"file":"system-prompt.js","sourceRoot":"","sources":["../../src/system-prompt.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,eAAe;IAC7B,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC;IACvB,MAAM,OAAO,GAAG,GAAG,CAAC,kBAAkB,CAAC,OAAO,EAAE;QAC9C,IAAI,EAAE,SAAS;QACf,KAAK,EAAE,MAAM;QACb,GAAG,EAAE,SAAS;QACd,OAAO,EAAE,MAAM;KAChB,CAAC,CAAC;IACH,MAAM,OAAO,GAAG,GAAG,CAAC,kBAAkB,CAAC,OAAO,EAAE;QAC9C,IAAI,EAAE,SAAS;QACf,MAAM,EAAE,SAAS;KAClB,CAAC,CAAC;IAEH,OAAO;;;;;;;;;aASI,OAAO,IAAI,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAsJ9B,CAAC;AACF,CAAC"}
1
+ {"version":3,"file":"system-prompt.js","sourceRoot":"","sources":["../../src/system-prompt.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,eAAe;IAC7B,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC;IACvB,MAAM,OAAO,GAAG,GAAG,CAAC,kBAAkB,CAAC,OAAO,EAAE;QAC9C,IAAI,EAAE,SAAS;QACf,KAAK,EAAE,MAAM;QACb,GAAG,EAAE,SAAS;QACd,OAAO,EAAE,MAAM;KAChB,CAAC,CAAC;IACH,MAAM,OAAO,GAAG,GAAG,CAAC,kBAAkB,CAAC,OAAO,EAAE;QAC9C,IAAI,EAAE,SAAS;QACf,MAAM,EAAE,SAAS;KAClB,CAAC,CAAC;IAEH,OAAO;;;;;;;;;aASI,OAAO,IAAI,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA8I9B,CAAC;AACF,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@optima-chat/optima-agent",
3
- "version": "0.8.44",
3
+ "version": "0.8.47",
4
4
  "description": "基于 Claude Agent SDK 的电商运营 AI 助手",
5
5
  "type": "module",
6
6
  "main": "dist/src/index.js",
@@ -1,154 +0,0 @@
1
- {
2
- "permissions": {
3
- "allow": [
4
- "Bash(gh api:*)",
5
- "WebFetch(domain:platform.claude.com)",
6
- "Bash(git init:*)",
7
- "Bash(mkdir:*)",
8
- "Bash(npm run typecheck:*)",
9
- "Bash(npm view:*)",
10
- "WebSearch",
11
- "Bash(commerce --help)",
12
- "Bash(done)",
13
- "Bash(commerce product:*)",
14
- "Bash(commerce order:*)",
15
- "Bash(commerce i18n:*)",
16
- "Bash(google-ads:*)",
17
- "Bash(scout --help:*)",
18
- "Bash(tree:*)",
19
- "Bash(cloc:*)",
20
- "Bash(npm run build:*)",
21
- "Bash(git restore:*)",
22
- "Bash(gh repo view:*)",
23
- "Bash(mv:*)",
24
- "Bash(rmdir:*)",
25
- "Bash(git add:*)",
26
- "Bash(git commit:*)",
27
- "Bash(git push)",
28
- "Bash(timeout 5 npm run optima:*)",
29
- "Bash(npm install:*)",
30
- "Bash(cat:*)",
31
- "Bash(gh issue create:*)",
32
- "Bash(npx tsx:*)",
33
- "Bash(timeout 30 npx tsx:*)",
34
- "Bash(git push origin feature/ask-user-question)",
35
- "Bash(node:*)",
36
- "Bash(npm version:*)",
37
- "Bash(git push:*)",
38
- "Bash(npm publish:*)",
39
- "Bash(pkill:*)",
40
- "Bash(git -C /Users/verypro/optima-agent log --oneline --all -- \".claude/\")",
41
- "Bash(wc:*)",
42
- "Bash(grep:*)",
43
- "Bash(find:*)",
44
- "Bash(commerce collection --help:*)",
45
- "Bash(commerce collection update --help:*)",
46
- "Bash(commerce collection set-cover:*)",
47
- "Bash(commerce collection get --help:*)",
48
- "Bash(commerce collection list --help:*)",
49
- "Bash(commerce collection create --help:*)",
50
- "Bash(commerce collection remove-products:*)",
51
- "Bash(commerce collection list-products:*)",
52
- "Bash(commerce --version:*)",
53
- "Bash(bi-cli --version:*)",
54
- "Bash(commerce homepage create --help:*)",
55
- "Bash(commerce homepage reorder --help:*)",
56
- "Bash(commerce homepage delete --help:*)",
57
- "Bash(commerce homepage update-images:*)",
58
- "Bash(commerce homepage update-collections:*)",
59
- "Bash(commerce homepage update-target:*)",
60
- "Bash(commerce homepage switch-template:*)",
61
- "Bash(commerce inventory:*)",
62
- "Bash(commerce merchant:*)",
63
- "Bash(commerce review:*)",
64
- "Bash(commerce product-page:*)",
65
- "Bash(bi-cli:*)",
66
- "Bash(comfy:*)",
67
- "Bash(scout search:*)",
68
- "Bash(scout product:*)",
69
- "Bash(commerce homepage create-collections:*)",
70
- "Bash(commerce homepage create-featured:*)",
71
- "Bash(commerce homepage create-collection-products:*)",
72
- "Bash(commerce homepage create-banner:*)",
73
- "Bash(xargs -I {} sh -c 'echo \"\"\"\"=== {} ===\"\"\"\"; head -3 /Users/verypro/optima-agent/.claude/skills/{}/SKILL.md | grep \"\"\"\"name:\"\"\"\"')",
74
- "Bash(ls:*)",
75
- "Bash(gh issue view:*)",
76
- "Bash(npx markdownlint-cli:*)",
77
- "Bash(chmod:*)",
78
- "Bash(npm whoami:*)",
79
- "Bash(tsx test-scripts/test-headless-progress.ts:*)",
80
- "Bash(DEBUG_STREAM=1 node dist/bin/optima.js:*)",
81
- "Bash(git describe:*)",
82
- "WebFetch(domain:github.com)",
83
- "Bash(./scripts/test-headless.sh:*)",
84
- "Bash(./scripts/test-headless-simple.sh:*)",
85
- "Bash(env)",
86
- "Bash(gh pr list:*)",
87
- "Bash(gh pr view:*)",
88
- "Bash(gh pr diff:*)",
89
- "Bash(optima --version:*)",
90
- "Bash(optima agent headless:*)",
91
- "Bash(optima headless:*)",
92
- "Bash(/Users/verypro/optima-agent/scripts/test-headless.sh:*)",
93
- "Bash(/Users/verypro/optima-agent/scripts/test-headless-simple.sh:*)",
94
- "Bash(tee:*)",
95
- "Bash(CONV_ID=\"conv-1\":*)",
96
- "Bash(echo:*)",
97
- "Bash(scout tiktok trending --help:*)",
98
- "Bash(scout tiktok trending:*)",
99
- "Bash(git checkout:*)",
100
- "Bash(npm test:*)",
101
- "Bash(git tag:*)",
102
- "Bash(/private/tmp/claude/-Users-verypro-optima-agent/68a9ac2c-def2-44e1-b42b-e53bd9022ab6/scratchpad/test-canUseTool.sh)",
103
- "Bash(optima --help:*)",
104
- "Bash(npx @optima-chat/ads-cli:*)",
105
- "Bash(head:*)",
106
- "Bash(git pull:*)",
107
- "Bash(pnpm build:*)",
108
- "Skill(read-code)",
109
- "Bash(npm run cli:*)",
110
- "Bash(scout:*)",
111
- "WebFetch(domain:docs.scrapecreators.com)",
112
- "WebFetch(domain:scrapecreators.com)",
113
- "Bash(gh auth status:*)",
114
- "Bash(optima-agent:*)",
115
- "Bash(python3:*)",
116
- "Bash(python3 -c \" import sys content = sys.stdin.read\\(\\) # Find flushMessageQueueSync idx = content.find\\(''flushMessageQueueSync''\\) # Get context around it lines = content.split\\(''\\\\n''\\) for i, line in enumerate\\(lines\\): if ''flushMessageQueueSync'' in line and ''private'' in line: for j in range\\(i, min\\(i+20, len\\(lines\\)\\)\\): print\\(f''{j+1}: {lines[j]}''\\) break \")",
117
- "Bash(optima:*)",
118
- "WebFetch(domain:www.npmjs.com)",
119
- "WebFetch(domain:registry.npmjs.org)",
120
- "WebFetch(domain:zod.dev)",
121
- "Bash(npm ls:*)",
122
- "Bash(NODE_DEBUG=child_process npx tsx:*)",
123
- "Bash(DEBUG_CLAUDE_AGENT_SDK=1 npx tsx:*)",
124
- "Bash(CLAUDECODE= npx tsx:*)",
125
- "Bash(env:*)",
126
- "Bash(gh release:*)",
127
- "Bash(npm info:*)",
128
- "Bash(gh run:*)",
129
- "Bash(gtimeout 90:*)",
130
- "Bash(sentinel:*)",
131
- "Bash(gh pr:*)",
132
- "Bash(git fetch:*)",
133
- "Bash(git log:*)",
134
- "Bash(npm bin:*)",
135
- "Bash(git status:*)",
136
- "Bash(browser-cli --version && browser-cli --help)",
137
- "Bash(browser-cli status:*)",
138
- "Bash(browser-cli launch:*)",
139
- "Bash(browser-cli screenshot:*)",
140
- "Bash(browser-cli --version)",
141
- "Bash(browser-cli close:*)",
142
- "Bash(npm update:*)",
143
- "Bash(node -e \"console.log\\(require\\('./node_modules/@optima-chat/browser-cli/package.json'\\).version\\)\")",
144
- "WebFetch(domain:raw.githubusercontent.com)",
145
- "Bash(aws ecs:*)",
146
- "Bash(aws ecr:*)",
147
- "Bash(gh search:*)",
148
- "Bash(npx tsc:*)",
149
- "Bash(find /Users/verypro/optima-agent -path */node_modules -prune -o -type f \\\\\\(-name *comfy* -o -name *gen* \\\\\\) -print)"
150
- ],
151
- "deny": [],
152
- "ask": []
153
- }
154
- }
@@ -1,3 +0,0 @@
1
- #!/usr/bin/env node
2
- import "@optima-chat/comfy-cli";
3
- //# sourceMappingURL=comfy.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"comfy.d.ts","sourceRoot":"","sources":["../../bin/comfy.ts"],"names":[],"mappings":";AACA,OAAO,wBAAwB,CAAC"}
package/dist/bin/comfy.js DELETED
@@ -1,3 +0,0 @@
1
- #!/usr/bin/env node
2
- import "@optima-chat/comfy-cli";
3
- //# sourceMappingURL=comfy.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"comfy.js","sourceRoot":"","sources":["../../bin/comfy.ts"],"names":[],"mappings":";AACA,OAAO,wBAAwB,CAAC"}
@@ -1,6 +0,0 @@
1
- import type { HooksConfig } from "./types.js";
2
- /**
3
- * 从 skills 目录加载所有 skill 的 hooks
4
- */
5
- export declare function loadSkillHooks(skillsDir: string, cwd: string, getSessionId: () => string | undefined): HooksConfig;
6
- //# sourceMappingURL=hooks-loader.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"hooks-loader.d.ts","sourceRoot":"","sources":["../../src/hooks-loader.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAgB,MAAM,YAAY,CAAC;AAwL5D;;GAEG;AACH,wBAAgB,cAAc,CAC5B,SAAS,EAAE,MAAM,EACjB,GAAG,EAAE,MAAM,EACX,YAAY,EAAE,MAAM,MAAM,GAAG,SAAS,GACrC,WAAW,CAiFb"}
@@ -1,215 +0,0 @@
1
- import { readFileSync, readdirSync, existsSync, writeFileSync, mkdirSync } from "fs";
2
- import { join, dirname } from "path";
3
- import yaml from "js-yaml";
4
- import { execSync } from "child_process";
5
- import { YamlValidator, formatValidationErrors, formatValidationWarning } from "./validation/index.js";
6
- /**
7
- * 从 SKILL.md 提取 YAML frontmatter
8
- */
9
- function extractYamlFrontmatter(content) {
10
- const match = content.match(/^---\n([\s\S]*?)\n---/);
11
- if (!match)
12
- return null;
13
- try {
14
- return yaml.load(match[1]);
15
- }
16
- catch (error) {
17
- console.error("Failed to parse YAML frontmatter:", error);
18
- return null;
19
- }
20
- }
21
- /**
22
- * 执行 shell 命令并返回结果
23
- */
24
- function executeCommand(command, cwd, skillDir, sessionId) {
25
- try {
26
- // 替换环境变量
27
- const expandedCommand = command
28
- .replace(/\$\{CLAUDE_PLUGIN_ROOT\}/g, skillDir)
29
- .replace(/\$\{SESSION_ID\}/g, sessionId || 'default');
30
- const result = execSync(expandedCommand, {
31
- cwd,
32
- encoding: "utf-8",
33
- stdio: ["pipe", "pipe", "pipe"],
34
- });
35
- return result.trim();
36
- }
37
- catch (error) {
38
- // 命令失败不阻塞,返回错误信息
39
- return error.stdout || error.message || "";
40
- }
41
- }
42
- /**
43
- * 转换 skill hooks 为 SDK hooks 格式
44
- */
45
- function convertSkillHooksToSdkHooks(skillHooks, skillDir, cwd, getSessionId, hookType) {
46
- return skillHooks.map((hookConfig) => ({
47
- matcher: hookConfig.matcher,
48
- hooks: hookConfig.hooks.map((hook) => {
49
- // SDK HookCallback 签名: (input, toolUseID, options) => Promise<HookJSONOutput>
50
- return async (input, toolUseID, options) => {
51
- // PreToolUse: 拦截并重定向 planning 文件操作
52
- if (hookType === "PreToolUse" && input.tool_name && input.tool_input) {
53
- const toolName = input.tool_name;
54
- const toolInput = input.tool_input;
55
- // 处理文件操作工具的路径重定向
56
- if ((toolName === "Write" || toolName === "Read" || toolName === "Edit") && toolInput.file_path) {
57
- const filePath = toolInput.file_path;
58
- if (filePath.includes(".planning/default/")) {
59
- const sessionId = getSessionId() || "default";
60
- const updatedPath = filePath.replace(".planning/default/", `.planning/${sessionId}/`);
61
- console.log(`[hooks-loader] Intercepting and redirecting: ${filePath} -> ${updatedPath}`);
62
- // 手动执行文件操作并 return,不要继续到 command 部分
63
- try {
64
- console.log(`[hooks-loader] Inside try block, toolName=${toolName}`);
65
- if (toolName === "Write") {
66
- console.log(`[hooks-loader] Handling Write operation`);
67
- // 创建目录
68
- const dir = dirname(updatedPath);
69
- if (!existsSync(dir)) {
70
- mkdirSync(dir, { recursive: true });
71
- }
72
- // 写入文件
73
- writeFileSync(updatedPath, toolInput.content || "", "utf-8");
74
- console.log(`[hooks-loader] File written to ${updatedPath}`);
75
- // Block 原始工具执行
76
- return {
77
- decision: "block",
78
- systemMessage: `File written to session-specific directory`,
79
- };
80
- }
81
- else if (toolName === "Read") {
82
- // 读取文件
83
- if (existsSync(updatedPath)) {
84
- const content = readFileSync(updatedPath, "utf-8");
85
- console.log(`[hooks-loader] File read from ${updatedPath}`);
86
- // Block 原始工具,返回文件内容
87
- return {
88
- decision: "block",
89
- systemMessage: `File content:\n\n${content}`,
90
- };
91
- }
92
- else {
93
- return {
94
- decision: "block",
95
- systemMessage: `File not found: ${updatedPath}`,
96
- };
97
- }
98
- }
99
- else if (toolName === "Edit") {
100
- // Edit 需要读取、修改、写入
101
- if (existsSync(updatedPath)) {
102
- let content = readFileSync(updatedPath, "utf-8");
103
- // 执行替换
104
- if (toolInput.old_string && toolInput.new_string) {
105
- if (toolInput.replace_all) {
106
- content = content.split(toolInput.old_string).join(toolInput.new_string);
107
- }
108
- else {
109
- content = content.replace(toolInput.old_string, toolInput.new_string);
110
- }
111
- writeFileSync(updatedPath, content, "utf-8");
112
- console.log(`[hooks-loader] File edited at ${updatedPath}`);
113
- }
114
- return {
115
- decision: "block",
116
- systemMessage: `File edited successfully`,
117
- };
118
- }
119
- else {
120
- return {
121
- decision: "block",
122
- systemMessage: `File not found: ${updatedPath}`,
123
- };
124
- }
125
- }
126
- }
127
- catch (error) {
128
- console.error(`[hooks-loader] Error:`, error);
129
- return {
130
- decision: "block",
131
- systemMessage: `Error: ${error.message}`,
132
- };
133
- }
134
- }
135
- }
136
- }
137
- if (hook.type === "command") {
138
- const sessionId = getSessionId();
139
- const result = executeCommand(hook.command, cwd, skillDir, sessionId);
140
- // 如果有输出,作为系统消息返回
141
- if (result) {
142
- return {
143
- continue: true,
144
- systemMessage: result,
145
- };
146
- }
147
- }
148
- return { continue: true };
149
- };
150
- }),
151
- }));
152
- }
153
- /**
154
- * 从 skills 目录加载所有 skill 的 hooks
155
- */
156
- export function loadSkillHooks(skillsDir, cwd, getSessionId) {
157
- const hooks = {};
158
- if (!existsSync(skillsDir)) {
159
- return hooks;
160
- }
161
- const skillDirs = readdirSync(skillsDir, { withFileTypes: true })
162
- .filter((dirent) => dirent.isDirectory())
163
- .map((dirent) => dirent.name);
164
- for (const skillName of skillDirs) {
165
- const skillDir = join(skillsDir, skillName);
166
- const skillMdPath = join(skillDir, "SKILL.md");
167
- if (!existsSync(skillMdPath)) {
168
- continue;
169
- }
170
- try {
171
- const content = readFileSync(skillMdPath, "utf-8");
172
- // 验证配置文件
173
- const validator = new YamlValidator();
174
- const validationResult = validator.validate(content, skillMdPath);
175
- // 显示错误
176
- if (!validationResult.valid) {
177
- console.error(formatValidationErrors(validationResult.errors));
178
- continue;
179
- }
180
- // 显示警告
181
- if (validationResult.warnings && validationResult.warnings.length > 0) {
182
- for (const warning of validationResult.warnings) {
183
- console.warn(formatValidationWarning(warning));
184
- }
185
- }
186
- const frontmatter = extractYamlFrontmatter(content);
187
- if (!frontmatter?.hooks) {
188
- continue;
189
- }
190
- // 转换各个 hook 事件
191
- if (frontmatter.hooks.SessionStart) {
192
- hooks.SessionStart = hooks.SessionStart || [];
193
- hooks.SessionStart.push(...convertSkillHooksToSdkHooks(frontmatter.hooks.SessionStart, skillDir, cwd, getSessionId, "SessionStart"));
194
- }
195
- if (frontmatter.hooks.PreToolUse) {
196
- hooks.PreToolUse = hooks.PreToolUse || [];
197
- hooks.PreToolUse.push(...convertSkillHooksToSdkHooks(frontmatter.hooks.PreToolUse, skillDir, cwd, getSessionId, "PreToolUse"));
198
- }
199
- if (frontmatter.hooks.PostToolUse) {
200
- hooks.PostToolUse = hooks.PostToolUse || [];
201
- hooks.PostToolUse.push(...convertSkillHooksToSdkHooks(frontmatter.hooks.PostToolUse, skillDir, cwd, getSessionId, "PostToolUse"));
202
- }
203
- if (frontmatter.hooks.Stop) {
204
- hooks.Stop = hooks.Stop || [];
205
- hooks.Stop.push(...convertSkillHooksToSdkHooks(frontmatter.hooks.Stop, skillDir, cwd, getSessionId, "Stop"));
206
- }
207
- console.log(`[hooks-loader] Loaded hooks from skill: ${skillName}`);
208
- }
209
- catch (error) {
210
- console.error(`[hooks-loader] Failed to load hooks from ${skillName}:`, error);
211
- }
212
- }
213
- return hooks;
214
- }
215
- //# sourceMappingURL=hooks-loader.js.map