pikiclaw 0.3.50 → 0.3.51

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 CHANGED
@@ -24,7 +24,7 @@ npx pikiclaw@latest
24
24
  <b>English</b> | <a href="README.zh-CN.md">简体中文</a>
25
25
  </p>
26
26
 
27
- <img src="docs/workspace.png" alt="Workspace" width="780">
27
+ <img src="docs/promo-dashboard-workspace.png" alt="Workspace" width="780">
28
28
 
29
29
  </div>
30
30
 
@@ -313,8 +313,6 @@ The shape that truly matters: **You never have to leave your preferred environme
313
313
  - **Richer Tool Ecosystem** — Releasing official MCP packs, skill templates, and a community marketplace.
314
314
  - **Cross-Platform Computer-Use** — Extending desktop control drivers beyond macOS to support Windows and Linux.
315
315
 
316
- For protocol-level insights, see our [ACP Migration Plan](docs/acp-migration.md).
317
-
318
316
  ---
319
317
 
320
318
  ## Development
package/README.zh-CN.md CHANGED
@@ -24,7 +24,7 @@ npx pikiclaw@latest
24
24
  <a href="README.md">English</a> | <b>简体中文</b>
25
25
  </p>
26
26
 
27
- <img src="docs/workspace.png" alt="工作区" width="780">
27
+ <img src="docs/promo-dashboard-workspace.png" alt="工作区" width="780">
28
28
 
29
29
  </div>
30
30
 
@@ -312,8 +312,6 @@ docker run -d --name pikiclaw -p 3939:3939 \
312
312
  - **完善工具生态** —— 推出官方推荐的 MCP 插件合集、Skill 模版库及社区应用市场。
313
313
  - **全平台的 Computer-use** —— 在已有的 macOS Peekaboo 驱动之外,加入适配 Windows / Linux 操作系统的桌面控制支持。
314
314
 
315
- 想了解协议层的下一步动作,请参阅 [ACP 迁移计划](docs/acp-migration.md)。
316
-
317
315
  ---
318
316
 
319
317
  ## 本地开发
@@ -8,16 +8,19 @@
8
8
  * the dashboard ultimately shows, do it in the dashboard layer instead.
9
9
  */
10
10
  /**
11
- * Shrink absolute paths that bloat IM cards on small screens. Anything past
12
- * 48 chars collapses to `…/<last-two-segments>` so directory context is kept
13
- * while the leading `/Users/…/long/project/root/` noise is dropped. Relative
14
- * paths and short absolute paths are passed through unchanged.
11
+ * Shrink absolute paths that bloat IM cards on small screens. Any absolute
12
+ * path with 4+ segments collapses to `…/<last-two-segments>` so directory
13
+ * context is kept while the leading `/Users/…/long/project/root/` noise is
14
+ * dropped. Length-based gating made the output inconsistent borderline
15
+ * paths (47 chars) sat next to compacted ones (52 chars), making the activity
16
+ * list look broken. Relative paths and short paths (<4 segments, e.g.
17
+ * `~/foo`, `/tmp/x.log`) are passed through unchanged.
15
18
  */
16
19
  function compactActivityPath(token) {
17
- if (token.length <= 48 || !token.includes('/'))
20
+ if (!token.includes('/'))
18
21
  return token;
19
22
  const segments = token.split('/').filter(Boolean);
20
- if (segments.length < 2)
23
+ if (segments.length < 4)
21
24
  return token;
22
25
  const tail = segments.slice(-2).join('/');
23
26
  return `…/${tail}`;
@@ -33,6 +36,12 @@ function compactPathsInActivityLine(line) {
33
36
  });
34
37
  }
35
38
  const TOOL_DONE_RE = /^(.+?)\s+(done|failed)$/;
39
+ /** "X -> Y" pattern produced by `summarizeClaudeToolResult` for tools whose
40
+ * result has body text (im_ask_user, ToolSearch, MCP tools, …). The Y half
41
+ * is the tool's response — capturing it lets us collapse the pre-event
42
+ * (`Ask user: q`) and the post-event (`Ask user: q -> A: …`) into a single
43
+ * line in the narrative instead of leaving both sitting around. */
44
+ const TOOL_ARROW_RE = /^(.+?)\s*->\s*(.+)$/;
36
45
  const INJECTED_PROMPT_MARKERS = [
37
46
  '\n[Session Workspace]',
38
47
  '\n[Telegram Artifact Return]',
@@ -172,13 +181,58 @@ export function parseActivitySummary(activity) {
172
181
  narrative.push(status === 'failed' ? `${baseKey} failed` : baseKey);
173
182
  continue;
174
183
  }
184
+ // Pair "X" → "X -> Y" (im_ask_user, ToolSearch, MCP tools, … — any tool
185
+ // whose summarizeClaudeToolResult fell into the arrow branch). Without
186
+ // this, the IM card shows the question and the answered form side by
187
+ // side. We replace the pending entry with the full arrow form so the
188
+ // narrative carries the answer in a single line.
189
+ const arrowMatch = line.match(TOOL_ARROW_RE);
190
+ if (arrowMatch) {
191
+ const baseKey = arrowMatch[1].trim();
192
+ const idx = popPending(baseKey);
193
+ if (idx != null) {
194
+ narrative[idx] = line;
195
+ continue;
196
+ }
197
+ }
175
198
  pushPending(line, narrative.length);
176
199
  narrative.push(line);
177
200
  }
178
201
  for (const pending of activeClaudeShells.values()) {
179
202
  activeCommands += pending;
180
203
  }
181
- return { narrative, failedCommands, completedCommands, activeCommands };
204
+ return { narrative: collapseConsecutiveDuplicates(narrative), failedCommands, completedCommands, activeCommands };
205
+ }
206
+ /**
207
+ * Walk the narrative and collapse runs of identical lines into `X ×N`. The
208
+ * input narrative often contains repeats when the model calls the same tool
209
+ * multiple times in a row (two consecutive `Edit README.md`, three `Read X`,
210
+ * …) — listing them N times wastes IM card real estate without adding
211
+ * information. Non-adjacent duplicates are preserved to keep the temporal
212
+ * order intact.
213
+ */
214
+ function collapseConsecutiveDuplicates(narrative) {
215
+ const out = [];
216
+ let runStart = -1;
217
+ let runCount = 0;
218
+ const flush = () => {
219
+ if (runStart < 0)
220
+ return;
221
+ out.push(runCount > 1 ? `${narrative[runStart]} ×${runCount}` : narrative[runStart]);
222
+ runStart = -1;
223
+ runCount = 0;
224
+ };
225
+ for (let i = 0; i < narrative.length; i++) {
226
+ if (runStart >= 0 && narrative[i] === narrative[runStart]) {
227
+ runCount++;
228
+ continue;
229
+ }
230
+ flush();
231
+ runStart = i;
232
+ runCount = 1;
233
+ }
234
+ flush();
235
+ return out;
182
236
  }
183
237
  export function formatActivityCommandSummary(completedCommands, activeCommands, failedCommands = 0) {
184
238
  const parts = [];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pikiclaw",
3
- "version": "0.3.50",
3
+ "version": "0.3.51",
4
4
  "description": "Put the world's smartest AI agents in your pocket. Command local Claude & Gemini via IM. | 让最好用的 IM 变成你电脑上的顶级 Agent 控制台",
5
5
  "type": "module",
6
6
  "bin": {