pikiclaw 0.2.48 → 0.2.50
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 +49 -51
- package/dist/bot-commands.js +3 -4
- package/dist/bot-feishu-render.js +72 -2
- package/dist/bot-feishu.js +265 -65
- package/dist/bot-menu.js +1 -1
- package/dist/bot-orchestration.js +66 -0
- package/dist/bot-telegram-live-preview.js +3 -1
- package/dist/bot-telegram-render.js +39 -0
- package/dist/bot-telegram.js +247 -74
- package/dist/bot.js +265 -5
- package/dist/channel-feishu.js +47 -10
- package/dist/cli.js +1 -1
- package/dist/code-agent.js +18 -3
- package/dist/driver-claude.js +14 -0
- package/dist/driver-codex.js +157 -8
- package/dist/driver-gemini.js +10 -0
- package/dist/human-loop-codex.js +23 -0
- package/dist/human-loop.js +120 -0
- package/dist/mcp-bridge.js +114 -28
- package/dist/mcp-session-server.js +12 -2
- package/dist/tools/desktop.js +445 -0
- package/dist/user-config.js +6 -1
- package/package.json +2 -2
- package/dist/tools/gui.js +0 -14
package/README.md
CHANGED
|
@@ -92,48 +92,48 @@ npx pikiclaw@latest --doctor
|
|
|
92
92
|
|
|
93
93
|
---
|
|
94
94
|
|
|
95
|
-
##
|
|
95
|
+
## Current Capabilities
|
|
96
96
|
|
|
97
|
-
### Channels
|
|
97
|
+
### Channels And Agents
|
|
98
98
|
|
|
99
|
-
- Telegram
|
|
100
|
-
-
|
|
101
|
-
-
|
|
102
|
-
|
|
103
|
-
### Agents
|
|
104
|
-
|
|
105
|
-
- Claude Code
|
|
106
|
-
- Codex CLI
|
|
107
|
-
- Gemini CLI
|
|
108
|
-
|
|
109
|
-
Agent 通过 driver registry 接入,模型列表、会话列表、usage 展示都走统一接口。
|
|
99
|
+
- Telegram、飞书都可用,也可以同时启动
|
|
100
|
+
- Claude Code、Codex CLI、Gemini CLI 都已接入
|
|
101
|
+
- agent 通过统一 driver registry 管理,模型列表、session 列表、usage 展示走同一套接口
|
|
110
102
|
|
|
111
103
|
### Runtime
|
|
112
104
|
|
|
113
105
|
- 流式预览和持续消息更新
|
|
114
106
|
- 会话切换、恢复和多轮续聊
|
|
115
107
|
- 工作目录浏览与切换
|
|
116
|
-
-
|
|
117
|
-
- watchdog 守护和自动重启
|
|
118
|
-
-
|
|
108
|
+
- 文件附件自动进入 session workspace
|
|
109
|
+
- 长任务防休眠、watchdog 守护和自动重启
|
|
110
|
+
- 长文本自动拆分,图片和文件可直接回传到 IM
|
|
111
|
+
- Dashboard 可查看运行状态、sessions、usage、主机状态和 macOS 权限状态
|
|
119
112
|
|
|
120
113
|
### Skills
|
|
121
114
|
|
|
122
|
-
-
|
|
115
|
+
- 项目级 skills 以 `.pikiclaw/skills/*/SKILL.md` 为 canonical 入口
|
|
123
116
|
- 兼容 `.claude/commands/*.md`
|
|
117
|
+
- 兼容 legacy `.claude/skills` / `.agents/skills`,并可合并回 `.pikiclaw/skills`
|
|
124
118
|
- IM 内可通过 `/skills` 和 `/sk_<name>` 触发
|
|
125
119
|
|
|
126
|
-
###
|
|
120
|
+
### Codex Human Loop
|
|
121
|
+
|
|
122
|
+
当 Codex 在运行过程中请求额外用户输入时,pikiclaw 会把问题转成 Telegram / 飞书里的交互提示,用户回复后再继续当前任务。
|
|
127
123
|
|
|
128
|
-
|
|
124
|
+
### MCP And GUI Automation
|
|
129
125
|
|
|
130
|
-
|
|
126
|
+
每次 Agent stream 都会启动一个会话级 MCP bridge,把本地工具按本次任务注入给 Agent。
|
|
127
|
+
|
|
128
|
+
当前内置工具:
|
|
131
129
|
|
|
132
130
|
- `im_list_files`:列出 session workspace 文件
|
|
133
131
|
- `im_send_file`:把文件实时发回 IM
|
|
134
|
-
- `take_screenshot`:跨平台截图并返回路径
|
|
135
132
|
|
|
136
|
-
|
|
133
|
+
可选 GUI 能力:
|
|
134
|
+
|
|
135
|
+
- 浏览器自动化:通过 `@playwright/mcp` 补充接入,默认支持 Chrome extension mode,也可切到 headless / isolated 模式
|
|
136
|
+
- macOS 桌面自动化:通过 Appium Mac2 提供 `desktop_open_app`、`desktop_snapshot`、`desktop_click`、`desktop_type`、`desktop_screenshot` 等工具
|
|
137
137
|
|
|
138
138
|
---
|
|
139
139
|
|
|
@@ -156,42 +156,37 @@ Agent 通过 driver registry 接入,模型列表、会话列表、usage 展示
|
|
|
156
156
|
|
|
157
157
|
---
|
|
158
158
|
|
|
159
|
-
##
|
|
159
|
+
## Config And Setup Notes
|
|
160
160
|
|
|
161
|
-
|
|
161
|
+
- 持久化配置在 `~/.pikiclaw/setting.json`
|
|
162
|
+
- Dashboard 是主配置入口,环境变量仍然可用
|
|
163
|
+
- 浏览器 GUI 相关常用变量:
|
|
164
|
+
- `PIKICLAW_BROWSER_GUI`
|
|
165
|
+
- `PIKICLAW_BROWSER_USE_EXTENSION`
|
|
166
|
+
- `PIKICLAW_BROWSER_HEADLESS`
|
|
167
|
+
- `PIKICLAW_BROWSER_ISOLATED`
|
|
168
|
+
- `PLAYWRIGHT_MCP_EXTENSION_TOKEN`
|
|
169
|
+
- 桌面 GUI 相关常用变量:
|
|
170
|
+
- `PIKICLAW_DESKTOP_GUI`
|
|
171
|
+
- `PIKICLAW_DESKTOP_APPIUM_URL`
|
|
162
172
|
|
|
163
|
-
|
|
164
|
-
- MCP tools:偏“可执行工具能力”,目前是会话级 bridge,由 pikiclaw 在每次 stream 时注入
|
|
173
|
+
如果要启用 macOS 桌面自动化,需要先准备 Appium Mac2:
|
|
165
174
|
|
|
166
|
-
|
|
175
|
+
```bash
|
|
176
|
+
npm install -g appium
|
|
177
|
+
appium driver install mac2
|
|
178
|
+
appium
|
|
179
|
+
```
|
|
167
180
|
|
|
168
|
-
|
|
181
|
+
然后给运行 `pikiclaw` 的终端应用授予 macOS 的辅助功能权限。
|
|
169
182
|
|
|
170
|
-
|
|
183
|
+
---
|
|
171
184
|
|
|
172
|
-
|
|
185
|
+
## Roadmap
|
|
173
186
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
| 飞书渠道 | ✅ |
|
|
178
|
-
| Claude Code driver | ✅ |
|
|
179
|
-
| Codex CLI driver | ✅ |
|
|
180
|
-
| Gemini CLI driver | ✅ |
|
|
181
|
-
| Web Dashboard | ✅ |
|
|
182
|
-
| 项目级 Skills | ✅ |
|
|
183
|
-
| 会话级 MCP bridge | ✅ |
|
|
184
|
-
| 文件回传 / 截图回传 | ✅ |
|
|
185
|
-
| 守护重启 / 防休眠 | ✅ |
|
|
186
|
-
|
|
187
|
-
### 待办
|
|
188
|
-
|
|
189
|
-
| 项目 | 说明 |
|
|
190
|
-
|---|---|
|
|
191
|
-
| 顶级 Skills 接入 | 把 skills 从当前项目级入口提升为更统一的顶级接入能力 |
|
|
192
|
-
| 顶级 MCP 工具接入 | 把当前会话级 MCP bridge 扩展成更完整的顶级工具接入层 |
|
|
193
|
-
| GUI 自动化工具补全 | 在 `src/tools/gui.ts` 上接入点击、输入、聚焦、窗口控制等工具 |
|
|
194
|
-
| 更多渠道 | WhatsApp 仍在规划中 |
|
|
187
|
+
- 把当前会话级 MCP bridge 继续扩展成更完整的顶级工具接入层
|
|
188
|
+
- 继续完善 GUI 自动化能力,尤其是浏览器与桌面工具的协同链路
|
|
189
|
+
- 增加更多 IM 渠道,WhatsApp 仍在规划中
|
|
195
190
|
|
|
196
191
|
---
|
|
197
192
|
|
|
@@ -216,6 +211,9 @@ npx vitest run test/channel-feishu.unit.test.ts
|
|
|
216
211
|
npx pikiclaw@latest --doctor
|
|
217
212
|
```
|
|
218
213
|
|
|
214
|
+
`npm run dev` 只跑本地源码链路,会固定使用 `--no-daemon`,避免跳转到生产/自举用的 `npx pikiclaw@latest`。
|
|
215
|
+
同时会把本次启动的全部日志写到 `~/.pikiclaw/dev/dev.log`,并在每次启动时先清空旧日志。
|
|
216
|
+
|
|
219
217
|
更多实现细节见:
|
|
220
218
|
|
|
221
219
|
- [ARCHITECTURE.md](ARCHITECTURE.md)
|
package/dist/bot-commands.js
CHANGED
|
@@ -12,17 +12,16 @@ import path from 'node:path';
|
|
|
12
12
|
import { fmtTokens, fmtUptime, fmtBytes } from './bot.js';
|
|
13
13
|
import { getProjectSkillPaths } from './code-agent.js';
|
|
14
14
|
import { getDriver } from './agent-driver.js';
|
|
15
|
-
import { buildWelcomeIntro,
|
|
15
|
+
import { buildWelcomeIntro, buildSkillCommandName, indexSkillsByCommand, SKILL_CMD_PREFIX } from './bot-menu.js';
|
|
16
|
+
import { buildBotMenuState } from './bot-orchestration.js';
|
|
16
17
|
import { summarizePromptForStatus } from './bot-streaming.js';
|
|
17
18
|
import { getSessionStatusForChat } from './session-status.js';
|
|
18
19
|
import { VERSION } from './version.js';
|
|
19
20
|
export function getStartData(bot, chatId) {
|
|
20
21
|
const cs = bot.chat(chatId);
|
|
21
22
|
const intro = buildWelcomeIntro(VERSION);
|
|
23
|
+
const commands = buildBotMenuState(bot).commands;
|
|
22
24
|
const res = bot.fetchAgents();
|
|
23
|
-
const installedCount = res.agents.filter(a => a.installed).length;
|
|
24
|
-
const skillRes = bot.fetchSkills();
|
|
25
|
-
const commands = buildDefaultMenuCommands(installedCount, skillRes.skills);
|
|
26
25
|
const agentDetails = res.agents
|
|
27
26
|
.filter(a => a.installed)
|
|
28
27
|
.map(a => ({
|
|
@@ -9,6 +9,7 @@ import { fmtUptime, fmtTokens, fmtBytes, formatThinkingForDisplay, thinkLabel }
|
|
|
9
9
|
import { summarizePromptForStatus } from './bot-commands.js';
|
|
10
10
|
import { formatProviderUsageLines } from './bot-telegram-render.js';
|
|
11
11
|
import { formatActivityCommandSummary, parseActivitySummary, renderPlanForPreview, summarizeActivityForPreview } from './bot-streaming.js';
|
|
12
|
+
import { currentHumanLoopQuestion, humanLoopAnsweredCount, isHumanLoopAwaitingText, isHumanLoopQuestionAnswered, summarizeHumanLoopAnswer, } from './human-loop.js';
|
|
12
13
|
import path from 'node:path';
|
|
13
14
|
import { listSubdirs } from './bot.js';
|
|
14
15
|
// ---------------------------------------------------------------------------
|
|
@@ -163,6 +164,38 @@ export function renderSessionTurnMarkdown(userText, assistantText) {
|
|
|
163
164
|
parts.push('**Assistant**', assistant);
|
|
164
165
|
return parts.join('\n\n');
|
|
165
166
|
}
|
|
167
|
+
export function buildHumanLoopPromptMarkdown(prompt) {
|
|
168
|
+
const question = currentHumanLoopQuestion(prompt);
|
|
169
|
+
const lines = [`**${prompt.title}**`];
|
|
170
|
+
if (prompt.detail)
|
|
171
|
+
lines.push(`\`${prompt.detail}\``);
|
|
172
|
+
lines.push(`*${humanLoopAnsweredCount(prompt)}/${prompt.questions.length} answered*`);
|
|
173
|
+
if (!question)
|
|
174
|
+
return lines.join('\n\n');
|
|
175
|
+
if (question.header.trim())
|
|
176
|
+
lines.push(`**${question.header}**`);
|
|
177
|
+
lines.push(question.prompt);
|
|
178
|
+
const options = question.options || [];
|
|
179
|
+
if (options.length) {
|
|
180
|
+
lines.push(options.map((option, index) => {
|
|
181
|
+
const detail = option.description ? `\n ${option.description}` : '';
|
|
182
|
+
return `${index + 1}. ${option.label}${detail}`;
|
|
183
|
+
}).join('\n'));
|
|
184
|
+
}
|
|
185
|
+
if (isHumanLoopAwaitingText(prompt)) {
|
|
186
|
+
lines.push(`*${question.secret ? 'Reply in chat with the secret value.' : 'Reply in chat with text to answer.'}*`);
|
|
187
|
+
}
|
|
188
|
+
if (prompt.hint)
|
|
189
|
+
lines.push(`*${prompt.hint}*`);
|
|
190
|
+
if (prompt.questions.length > 1) {
|
|
191
|
+
lines.push(prompt.questions.map((item, index) => {
|
|
192
|
+
const summary = summarizeHumanLoopAnswer(prompt, item);
|
|
193
|
+
const answered = isHumanLoopQuestionAnswered(prompt, index);
|
|
194
|
+
return `${answered ? '●' : '○'} ${item.header || item.prompt}: ${summary.display}`;
|
|
195
|
+
}).join('\n'));
|
|
196
|
+
}
|
|
197
|
+
return lines.join('\n\n');
|
|
198
|
+
}
|
|
166
199
|
// ---------------------------------------------------------------------------
|
|
167
200
|
// LivePreview renderer — produces Markdown for Feishu card elements
|
|
168
201
|
// ---------------------------------------------------------------------------
|
|
@@ -584,7 +617,44 @@ function stripBoldMarkers(text) {
|
|
|
584
617
|
}
|
|
585
618
|
/** Strip anchor links [text](#id) → text (anchors don't work in Feishu cards). */
|
|
586
619
|
function adaptLine(line) {
|
|
587
|
-
|
|
620
|
+
const withoutAnchors = line.replace(/\[([^\]]+)\]\(#[^)]*\)/g, '$1');
|
|
621
|
+
const heading = withoutAnchors.match(/^(\s*)#{1,6}\s+(.+?)\s*#*\s*$/);
|
|
622
|
+
if (!heading)
|
|
623
|
+
return withoutAnchors;
|
|
624
|
+
const indent = heading[1] || '';
|
|
625
|
+
const content = heading[2].trim();
|
|
626
|
+
return content ? `${indent}**${content}**` : '';
|
|
627
|
+
}
|
|
628
|
+
function normalizeFeishuMarkdown(lines) {
|
|
629
|
+
const out = [];
|
|
630
|
+
let inCodeBlock = false;
|
|
631
|
+
let pendingBlankLine = false;
|
|
632
|
+
for (const rawLine of lines) {
|
|
633
|
+
const line = rawLine.replace(/\s+$/g, '');
|
|
634
|
+
const trimmed = line.trimStart();
|
|
635
|
+
if (trimmed.startsWith('```') || trimmed.startsWith('~~~')) {
|
|
636
|
+
if (pendingBlankLine && out.length && !inCodeBlock)
|
|
637
|
+
out.push('');
|
|
638
|
+
pendingBlankLine = false;
|
|
639
|
+
out.push(line);
|
|
640
|
+
inCodeBlock = !inCodeBlock;
|
|
641
|
+
continue;
|
|
642
|
+
}
|
|
643
|
+
if (inCodeBlock) {
|
|
644
|
+
out.push(rawLine);
|
|
645
|
+
continue;
|
|
646
|
+
}
|
|
647
|
+
if (!line.trim()) {
|
|
648
|
+
if (out.length)
|
|
649
|
+
pendingBlankLine = true;
|
|
650
|
+
continue;
|
|
651
|
+
}
|
|
652
|
+
if (pendingBlankLine && out.length)
|
|
653
|
+
out.push('');
|
|
654
|
+
pendingBlankLine = false;
|
|
655
|
+
out.push(line);
|
|
656
|
+
}
|
|
657
|
+
return out.join('\n');
|
|
588
658
|
}
|
|
589
659
|
export function adaptMarkdownForFeishu(markdown) {
|
|
590
660
|
const lines = markdown.split('\n');
|
|
@@ -643,5 +713,5 @@ export function adaptMarkdownForFeishu(markdown) {
|
|
|
643
713
|
i++;
|
|
644
714
|
}
|
|
645
715
|
}
|
|
646
|
-
return out
|
|
716
|
+
return normalizeFeishuMarkdown(out);
|
|
647
717
|
}
|