pikiloom 0.4.26 → 0.4.28
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/dashboard/dist/assets/{AgentTab-BNJ73P0m.js → AgentTab-DtjuI8NU.js} +1 -1
- package/dashboard/dist/assets/ConnectionModal-BIx6a5o1.js +1 -0
- package/dashboard/dist/assets/{DirBrowser-D-GT-G-w.js → DirBrowser-BINh_7NB.js} +1 -1
- package/dashboard/dist/assets/{ExtensionsTab-BrJMulJR.js → ExtensionsTab-CHpd147b.js} +1 -1
- package/dashboard/dist/assets/{IMAccessTab-auPnx468.js → IMAccessTab-C4DbGxbG.js} +1 -1
- package/dashboard/dist/assets/{Modal-lYfO9m-I.js → Modal-D_PUi-5O.js} +1 -1
- package/dashboard/dist/assets/{Modals-PRdWOIY9.js → Modals-BahDEMqf.js} +1 -1
- package/dashboard/dist/assets/{Select-BhbU-rll.js → Select-Cp5VXb_2.js} +1 -1
- package/dashboard/dist/assets/SessionPanel-DZVNXptx.js +1 -0
- package/dashboard/dist/assets/SystemTab-CLznS31f.js +1 -0
- package/dashboard/dist/assets/index-CLGovkkw.js +3 -0
- package/dashboard/dist/assets/index-CXIN3nTr.css +1 -0
- package/dashboard/dist/assets/index-DcYOI6rL.js +23 -0
- package/dashboard/dist/assets/{shared-C5uXvhZJ.js → shared-C8DCTJ44.js} +1 -1
- package/dashboard/dist/index.html +2 -2
- package/dist/agent/acp-client.js +0 -59
- package/dist/agent/artifacts.js +1 -38
- package/dist/agent/auto-update.js +2 -78
- package/dist/agent/await-resume.js +0 -20
- package/dist/agent/cli/auth.js +3 -51
- package/dist/agent/cli/catalog.js +0 -3
- package/dist/agent/cli/detector.js +1 -19
- package/dist/agent/cli/index.js +0 -3
- package/dist/agent/cli/registry.js +0 -25
- package/dist/agent/driver.js +0 -14
- package/dist/agent/drivers/claude-tui.js +2 -769
- package/dist/agent/drivers/claude.js +12 -631
- package/dist/agent/drivers/codex.js +11 -162
- package/dist/agent/drivers/gemini.js +6 -114
- package/dist/agent/drivers/hermes.js +0 -128
- package/dist/agent/goal.js +0 -45
- package/dist/agent/handover.js +1 -46
- package/dist/agent/images.js +7 -133
- package/dist/agent/index.js +1 -29
- package/dist/agent/mcp/bridge.js +1 -197
- package/dist/agent/mcp/extensions.js +5 -84
- package/dist/agent/mcp/oauth.js +2 -69
- package/dist/agent/mcp/registry.js +2 -33
- package/dist/agent/mcp/session-server.js +2 -45
- package/dist/agent/mcp/tools/ask-user.js +0 -6
- package/dist/agent/mcp/tools/await-resume.js +0 -15
- package/dist/agent/mcp/tools/goal.js +0 -25
- package/dist/agent/mcp/tools/types.js +0 -5
- package/dist/agent/mcp/tools/workspace.js +0 -23
- package/dist/agent/npm.js +0 -14
- package/dist/agent/session.js +86 -196
- package/dist/agent/skill-installer.js +3 -70
- package/dist/agent/skills.js +0 -43
- package/dist/agent/stream.js +5 -148
- package/dist/agent/types.js +0 -12
- package/dist/agent/utils.js +2 -120
- package/dist/bot/bot.js +3 -468
- package/dist/bot/command-ui.js +0 -45
- package/dist/bot/commands.js +0 -51
- package/dist/bot/headless-bot.js +0 -21
- package/dist/bot/host.js +1 -5
- package/dist/bot/human-loop.js +0 -8
- package/dist/bot/menu.js +0 -3
- package/dist/bot/orchestration.js +0 -3
- package/dist/bot/render-shared.js +0 -63
- package/dist/bot/session-hub.js +14 -92
- package/dist/bot/session-status.js +1 -5
- package/dist/bot/streaming.js +0 -53
- package/dist/browser-profile.js +0 -51
- package/dist/browser-supervisor.js +0 -75
- package/dist/catalog/cli-tools.js +0 -53
- package/dist/catalog/index.js +0 -18
- package/dist/catalog/local-models.js +0 -18
- package/dist/catalog/mcp-servers.js +0 -35
- package/dist/catalog/skill-repos.js +0 -32
- package/dist/channels/base.js +0 -19
- package/dist/channels/dingtalk/bot.js +0 -3
- package/dist/channels/dingtalk/channel.js +0 -33
- package/dist/channels/discord/bot.js +0 -7
- package/dist/channels/discord/channel.js +0 -22
- package/dist/channels/feishu/bot.js +0 -71
- package/dist/channels/feishu/channel.js +0 -78
- package/dist/channels/feishu/markdown.js +0 -5
- package/dist/channels/feishu/render.js +0 -45
- package/dist/channels/health.js +0 -46
- package/dist/channels/slack/bot.js +0 -7
- package/dist/channels/slack/channel.js +1 -27
- package/dist/channels/states.js +0 -3
- package/dist/channels/telegram/bot.js +0 -60
- package/dist/channels/telegram/channel.js +2 -99
- package/dist/channels/telegram/directory.js +0 -3
- package/dist/channels/telegram/live-preview.js +0 -8
- package/dist/channels/telegram/render.js +0 -30
- package/dist/channels/wecom/bot.js +0 -3
- package/dist/channels/wecom/channel.js +0 -58
- package/dist/channels/weixin/api.js +0 -9
- package/dist/channels/weixin/bot.js +0 -88
- package/dist/channels/weixin/channel.js +0 -6
- package/dist/cli/autostart.js +1 -44
- package/dist/cli/channel-supervisor.js +1 -59
- package/dist/cli/channels.js +0 -6
- package/dist/cli/main.js +1 -145
- package/dist/cli/onboarding.js +0 -6
- package/dist/cli/run.js +0 -11
- package/dist/cli/setup-wizard.js +0 -3
- package/dist/core/config/runtime-config.js +0 -38
- package/dist/core/config/user-config.js +0 -63
- package/dist/core/config/validation.js +0 -9
- package/dist/core/constants.js +0 -268
- package/dist/core/git.js +0 -31
- package/dist/core/legacy-compat.js +1 -28
- package/dist/core/logging.js +0 -3
- package/dist/core/platform.js +0 -28
- package/dist/core/process-control.js +0 -8
- package/dist/core/secrets/index.js +0 -17
- package/dist/core/secrets/inline-seal.js +0 -7
- package/dist/core/secrets/ref.js +0 -19
- package/dist/core/secrets/resolver.js +0 -8
- package/dist/core/secrets/store.js +1 -12
- package/dist/core/utils.js +1 -37
- package/dist/core/version.js +0 -3
- package/dist/dashboard/platform.js +1 -35
- package/dist/dashboard/routes/agents.js +2 -71
- package/dist/dashboard/routes/cli.js +0 -27
- package/dist/dashboard/routes/config.js +0 -54
- package/dist/dashboard/routes/extensions.js +0 -132
- package/dist/dashboard/routes/local-models.js +0 -68
- package/dist/dashboard/routes/models.js +0 -46
- package/dist/dashboard/routes/sessions.js +0 -100
- package/dist/dashboard/runtime.js +1 -58
- package/dist/dashboard/server.js +0 -49
- package/dist/dashboard/session-control.js +2 -69
- package/dist/model/catalog.js +1 -17
- package/dist/model/index.js +0 -15
- package/dist/model/injector.js +1 -181
- package/dist/model/provider-models.js +1 -48
- package/dist/model/responses-bridge.js +3 -45
- package/dist/model/store.js +0 -17
- package/dist/model/types.js +0 -12
- package/dist/model/validation.js +1 -18
- package/dist/pikichannel/adapter-pikiloom.js +0 -31
- package/dist/pikichannel/code.js +0 -12
- package/dist/pikichannel/codec.js +0 -14
- package/dist/pikichannel/host.js +4 -33
- package/dist/pikichannel/protocol.js +0 -52
- package/dist/pikichannel/rendezvous-broker.js +5 -26
- package/dist/pikichannel/rendezvous-host.js +3 -16
- package/dist/pikichannel/server.js +6 -55
- package/dist/pikichannel/transport.js +0 -25
- package/dist/pikichannel/transports/webrtc-host.js +0 -18
- package/dist/pikichannel/transports/webrtc-shared.js +4 -34
- package/dist/pikichannel/transports/websocket-host.js +1 -14
- package/dist/pikichannel/turn.js +2 -69
- package/dist/pikichannel/web/sdk.js +14 -71
- package/package.json +1 -1
- package/dashboard/dist/assets/ConnectionModal-Dt05H2f9.js +0 -1
- package/dashboard/dist/assets/SessionPanel-_0dLWvEb.js +0 -1
- package/dashboard/dist/assets/SystemTab-CN_QrRKt.js +0 -1
- package/dashboard/dist/assets/index-CP3LYJR2.js +0 -23
- package/dashboard/dist/assets/index-C_neLnaO.js +0 -3
- package/dashboard/dist/assets/index-CyCspgtc.css +0 -1
package/dist/agent/utils.js
CHANGED
|
@@ -1,7 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Pure utility functions shared across the agent layer.
|
|
3
|
-
* No filesystem or session state side effects.
|
|
4
|
-
*/
|
|
5
1
|
import fs from 'node:fs';
|
|
6
2
|
import { writeScopedLog } from '../core/logging.js';
|
|
7
3
|
export const Q = (a) => {
|
|
@@ -70,7 +66,6 @@ export function normalizeStreamPreviewPlan(value) {
|
|
|
70
66
|
steps,
|
|
71
67
|
};
|
|
72
68
|
}
|
|
73
|
-
/** Parse a TodoWrite tool input into a StreamPreviewPlan. */
|
|
74
69
|
export function parseTodoWriteAsPlan(input) {
|
|
75
70
|
if (!input || typeof input !== 'object')
|
|
76
71
|
return null;
|
|
@@ -95,11 +90,6 @@ export function parseTodoWriteAsPlan(input) {
|
|
|
95
90
|
return { explanation: null, steps };
|
|
96
91
|
}
|
|
97
92
|
export function normalizeActivityLine(text) { return text.replace(/\s+/g, ' ').trim(); }
|
|
98
|
-
// The activity feed is only ever rendered as a tail — downstream previews trim
|
|
99
|
-
// it to ~900 chars (trimActivityForPreview) and the final reply to ~1600 — yet
|
|
100
|
-
// every tool event rebuilds `s.activity = recentActivity.join('\n')`. A 500-line
|
|
101
|
-
// cap made that rejoin effectively O(n²) over a tool-heavy turn for history no
|
|
102
|
-
// view ever shows; 80 lines comfortably covers the largest consumer.
|
|
103
93
|
export function pushRecentActivity(lines, line, maxLines = 80) {
|
|
104
94
|
const cleaned = normalizeActivityLine(line);
|
|
105
95
|
if (!cleaned)
|
|
@@ -118,10 +108,6 @@ export function firstNonEmptyLine(text) {
|
|
|
118
108
|
}
|
|
119
109
|
return '';
|
|
120
110
|
}
|
|
121
|
-
// MCP tool results carry structured content blocks (e.g. screenshot returns
|
|
122
|
-
// `[{type:'image',...}, {type:'text', text:'Saved as ...'}]`). Coerce that to
|
|
123
|
-
// plain text by keeping only the `type:'text'` blocks; otherwise `String([{…}])`
|
|
124
|
-
// silently becomes the literal "[object Object]" in activity summaries.
|
|
125
111
|
export function coerceToolResultText(value) {
|
|
126
112
|
if (typeof value === 'string')
|
|
127
113
|
return value;
|
|
@@ -171,24 +157,6 @@ export function joinErrorMessages(errors) {
|
|
|
171
157
|
return '';
|
|
172
158
|
return errors.map(error => normalizeErrorMessage(error)).filter(Boolean).join('; ').trim();
|
|
173
159
|
}
|
|
174
|
-
/**
|
|
175
|
-
* Detect Claude Code's synthetic "API Error: …" assistant message. When the
|
|
176
|
-
* upstream Anthropic API returns a transient error (529 Overloaded, 5xx, gateway
|
|
177
|
-
* timeouts, …), the Claude CLI swallows it and replaces the assistant turn with
|
|
178
|
-
* a single `text` block whose body is literally `API Error: <reason>`. The
|
|
179
|
-
* turn's stop_reason still claims `end_turn`, so the driver can't distinguish
|
|
180
|
-
* it from a normal short reply without inspecting the text.
|
|
181
|
-
*
|
|
182
|
-
* Heuristics — keep them tight so real prose mentioning "API Error" doesn't
|
|
183
|
-
* trip the detector:
|
|
184
|
-
* - exact prefix "API Error: "
|
|
185
|
-
* - total length ≤ 200 chars (the synthetic line is always short)
|
|
186
|
-
* - no newlines (legit prose containing "API Error" virtually always wraps)
|
|
187
|
-
*
|
|
188
|
-
* Returns the trimmed reason (e.g. "Overloaded", "Internal server error") when
|
|
189
|
-
* matched, otherwise null. Callers decide whether the reason is retryable —
|
|
190
|
-
* `looksRetryable` answers that.
|
|
191
|
-
*/
|
|
192
160
|
export function detectClaudeApiError(text) {
|
|
193
161
|
if (!text)
|
|
194
162
|
return null;
|
|
@@ -198,36 +166,12 @@ export function detectClaudeApiError(text) {
|
|
|
198
166
|
const m = trimmed.match(/^API Error:\s*(.+)$/i);
|
|
199
167
|
return m ? m[1].trim() : null;
|
|
200
168
|
}
|
|
201
|
-
/**
|
|
202
|
-
* Retryable Claude Code API errors — transient upstream conditions that
|
|
203
|
-
* usually clear within seconds. Non-retryable conditions (auth, quota,
|
|
204
|
-
* context length) fall through and surface to the user immediately.
|
|
205
|
-
*/
|
|
206
169
|
export function isRetryableClaudeApiError(reason) {
|
|
207
170
|
const r = reason.toLowerCase();
|
|
208
171
|
if (/rate limit|rate limited|quota|usage limit|session limit/i.test(r))
|
|
209
172
|
return false;
|
|
210
173
|
return /overloaded|overload|timeout|timed out|500|502|503|504|529|temporar|gateway|connection|network|internal (server )?error/i.test(r);
|
|
211
174
|
}
|
|
212
|
-
/**
|
|
213
|
-
* Detect Claude Code's "selected model is unavailable" notice — emitted when
|
|
214
|
-
* the requested `--model` id is disabled / not provisioned for the account (a
|
|
215
|
-
* 404 model_not_found). Its delivery differs by mode:
|
|
216
|
-
* - `-p`/stream-json: a `<synthetic>` assistant event carrying
|
|
217
|
-
* `error:"model_not_found"` plus the banner text, and a `result` event with
|
|
218
|
-
* `is_error` — both reach the parser.
|
|
219
|
-
* - TUI: the banner is *only* painted to the PTY screen. It is never written
|
|
220
|
-
* to the transcript JSONL and fires no Stop hook (verified 2026-06-13), so
|
|
221
|
-
* the screen scrape is the sole signal and the turn would otherwise hang
|
|
222
|
-
* until the stall watchdog (3–10 min).
|
|
223
|
-
*
|
|
224
|
-
* Matching is whitespace-insensitive on purpose: the TUI renders the banner
|
|
225
|
-
* character-by-character with cursor positioning, so after ANSI stripping the
|
|
226
|
-
* words lose their spaces and wrap arbitrarily ("issuewiththeselectedmodel").
|
|
227
|
-
* Collapsing whitespace on both sides makes the match survive that rendering.
|
|
228
|
-
* Callers compose the user-facing message via `claudeModelErrorMessage` with
|
|
229
|
-
* the concrete model id they hold.
|
|
230
|
-
*/
|
|
231
175
|
export function detectClaudeModelError(text) {
|
|
232
176
|
if (!text)
|
|
233
177
|
return false;
|
|
@@ -235,7 +179,6 @@ export function detectClaudeModelError(text) {
|
|
|
235
179
|
return collapsed.includes('issuewiththeselectedmodel')
|
|
236
180
|
|| collapsed.includes('maynotexistoryoumaynothaveaccess');
|
|
237
181
|
}
|
|
238
|
-
/** User-facing message for an unavailable / no-access model (see {@link detectClaudeModelError}). */
|
|
239
182
|
export function claudeModelErrorMessage(model) {
|
|
240
183
|
const id = (model || '').trim();
|
|
241
184
|
return `The selected model${id ? ` (${id})` : ''} is unavailable — it may not exist, or this account doesn't have access to it. Switch to a different model in pikiloom settings.`;
|
|
@@ -267,7 +210,6 @@ export function computeContext(s) {
|
|
|
267
210
|
: null;
|
|
268
211
|
return { contextUsedTokens: used, contextPercent: pct };
|
|
269
212
|
}
|
|
270
|
-
/** Max structured tool calls carried per preview emit (most recent win). */
|
|
271
213
|
const PREVIEW_TOOL_CALLS_MAX = 40;
|
|
272
214
|
export function buildStreamPreviewMeta(s) {
|
|
273
215
|
const ctx = computeContext(s);
|
|
@@ -276,7 +218,6 @@ export function buildStreamPreviewMeta(s) {
|
|
|
276
218
|
cachedInputTokens: s.cachedInputTokens,
|
|
277
219
|
contextUsedTokens: ctx.contextUsedTokens, contextPercent: ctx.contextPercent,
|
|
278
220
|
};
|
|
279
|
-
// Turn-cumulative output: finished calls' total + the in-flight call.
|
|
280
221
|
const turnOutput = (s.turnOutputTokensBase ?? 0) + (s.outputTokens ?? 0);
|
|
281
222
|
if (turnOutput > 0)
|
|
282
223
|
meta.turnOutputTokens = turnOutput;
|
|
@@ -306,12 +247,6 @@ export function buildStreamPreviewMeta(s) {
|
|
|
306
247
|
}
|
|
307
248
|
return meta;
|
|
308
249
|
}
|
|
309
|
-
/**
|
|
310
|
-
* Bounded, human-readable input detail for a live tool-call row. Bash shows
|
|
311
|
-
* the raw command (the summary already carries the description); everything
|
|
312
|
-
* else gets compact JSON. Returns null when there's nothing beyond the
|
|
313
|
-
* summary worth expanding.
|
|
314
|
-
*/
|
|
315
250
|
export function previewToolCallInput(name, input, max = 500) {
|
|
316
251
|
if (input == null)
|
|
317
252
|
return null;
|
|
@@ -329,11 +264,6 @@ export function previewToolCallInput(name, input, max = 500) {
|
|
|
329
264
|
return null;
|
|
330
265
|
}
|
|
331
266
|
}
|
|
332
|
-
/**
|
|
333
|
-
* Bounded text preview of a tool result. Accepts the JSONL tool_result
|
|
334
|
-
* `content` (string | block array) or a hook `tool_response` (string |
|
|
335
|
-
* object). Extracts text blocks where present, falls back to compact JSON.
|
|
336
|
-
*/
|
|
337
267
|
export function previewToolCallResult(content, max = 500) {
|
|
338
268
|
if (content == null)
|
|
339
269
|
return null;
|
|
@@ -348,7 +278,6 @@ export function previewToolCallResult(content, max = 500) {
|
|
|
348
278
|
return text ? clipText(text, max) : null;
|
|
349
279
|
}
|
|
350
280
|
if (typeof content === 'object') {
|
|
351
|
-
// Hook tool_response commonly nests the payload under `content` / `result`.
|
|
352
281
|
if (content.content != null && content.content !== content) {
|
|
353
282
|
const nested = previewToolCallResult(content.content, max);
|
|
354
283
|
if (nested)
|
|
@@ -373,7 +302,6 @@ function clipText(text, max) {
|
|
|
373
302
|
return text;
|
|
374
303
|
return `${text.slice(0, Math.max(0, max - 1)).trimEnd()}…`;
|
|
375
304
|
}
|
|
376
|
-
// Claude tool use helpers (used by driver-claude.ts)
|
|
377
305
|
export function summarizeClaudeToolUse(name, input) {
|
|
378
306
|
const tool = String(name || '').trim() || 'Tool';
|
|
379
307
|
const description = shortValue(input?.description, 120);
|
|
@@ -408,10 +336,6 @@ export function summarizeClaudeToolUse(name, input) {
|
|
|
408
336
|
}
|
|
409
337
|
case 'TodoWrite': return 'Update plan';
|
|
410
338
|
case 'AskUserQuestion': {
|
|
411
|
-
// Claude's built-in clarify tool. The CLI in `-p` mode self-resolves it
|
|
412
|
-
// with an error and degrades to a plain-text question in the same turn —
|
|
413
|
-
// we just surface the question text in the activity panel so users see
|
|
414
|
-
// what was asked.
|
|
415
339
|
const qs = Array.isArray(input?.questions) ? input.questions : [];
|
|
416
340
|
const first = qs[0];
|
|
417
341
|
const q = shortValue(first?.question || input?.question, 120);
|
|
@@ -428,7 +352,6 @@ export function summarizeClaudeToolUse(name, input) {
|
|
|
428
352
|
return c ? `Run shell: ${c}` : 'Run shell command';
|
|
429
353
|
}
|
|
430
354
|
default: {
|
|
431
|
-
// MCP tools come through as `mcp__<server>__<tool>` — unwrap common pikiloom tools
|
|
432
355
|
const mcpMatch = tool.match(/^mcp__[^_]+__(.+)$/);
|
|
433
356
|
const bare = mcpMatch ? mcpMatch[1] : tool;
|
|
434
357
|
if (bare === 'im_send_file') {
|
|
@@ -464,7 +387,6 @@ export function summarizeClaudeToolResult(tool, block, toolUseResult) {
|
|
|
464
387
|
return `${summary} done`;
|
|
465
388
|
return `${summary} -> ${shortValue(detail, 120)}`;
|
|
466
389
|
}
|
|
467
|
-
// Usage helpers (used by drivers)
|
|
468
390
|
export function roundPercent(value) {
|
|
469
391
|
const n = Number(value);
|
|
470
392
|
if (!Number.isFinite(n))
|
|
@@ -580,7 +502,6 @@ export function stripInjectedPrompts(text) {
|
|
|
580
502
|
if (idx >= 0)
|
|
581
503
|
text = text.slice(0, idx).trim();
|
|
582
504
|
}
|
|
583
|
-
// Strip Codex IDE context prefix ("# Context from my IDE setup: ...")
|
|
584
505
|
if (text.startsWith('# Context from')) {
|
|
585
506
|
const tag = '## My request for Codex:\n';
|
|
586
507
|
const idx = text.indexOf(tag);
|
|
@@ -595,18 +516,7 @@ export const SESSION_PREVIEW_IGNORED_USER_PATTERNS = [
|
|
|
595
516
|
];
|
|
596
517
|
export const SESSION_PREVIEW_IMAGE_PLACEHOLDER_RE = /\[Image:[^\]]+\]/gi;
|
|
597
518
|
export const SESSION_PREVIEW_FILE_PLACEHOLDER_RE = /\[Attached file:[^\]]+\]/gi;
|
|
598
|
-
/**
|
|
599
|
-
* Claude TUI mode prepends `@/abs/path/file.ext` mentions to the prompt as
|
|
600
|
-
* positional argv (see `src/agent/drivers/claude-tui.ts`) — that's how the TUI
|
|
601
|
-
* ingests local image files. The mentions end up baked into the JSONL user
|
|
602
|
-
* `content` string verbatim. This regex captures them so:
|
|
603
|
-
* - the dashboard's user bubble (via `getClaudeSessionMessages`) can lift
|
|
604
|
-
* them into structured `image` blocks for thumbnail rendering;
|
|
605
|
-
* - session-list previews don't surface a long absolute path.
|
|
606
|
-
* Whitespace-free paths only — matches what `claude-tui.ts` emits.
|
|
607
|
-
*/
|
|
608
519
|
export const CLAUDE_AT_MENTION_IMAGE_RE = /(^|\s)@(\/[^\s@\n]+\.(?:png|jpe?g|gif|webp|svg))(?=\s|$)/gi;
|
|
609
|
-
/** Pull the absolute paths out of every image-mention in `text`. */
|
|
610
520
|
export function extractClaudeAtMentionImagePaths(text) {
|
|
611
521
|
if (!text)
|
|
612
522
|
return [];
|
|
@@ -615,8 +525,6 @@ export function extractClaudeAtMentionImagePaths(text) {
|
|
|
615
525
|
out.push(m[2]);
|
|
616
526
|
return out;
|
|
617
527
|
}
|
|
618
|
-
/** Remove image @-mentions from `text` while preserving the leading boundary
|
|
619
|
-
* character (start-of-string or whitespace) so adjacent content stays joinable. */
|
|
620
528
|
export function stripClaudeAtMentionImages(text) {
|
|
621
529
|
if (!text)
|
|
622
530
|
return text;
|
|
@@ -638,18 +546,6 @@ export function sanitizeSessionUserPreviewText(text) {
|
|
|
638
546
|
export function isPendingSessionId(sessionId) {
|
|
639
547
|
return typeof sessionId === 'string' && sessionId.startsWith('pending_');
|
|
640
548
|
}
|
|
641
|
-
/**
|
|
642
|
-
* Update a stream-state's session id and notify the caller in one step.
|
|
643
|
-
*
|
|
644
|
-
* Drivers used to assign `s.sessionId = ev.session_id ?? s.sessionId` at every
|
|
645
|
-
* place the CLI surfaced an id, then leave promotion until `finalizeStreamResult`
|
|
646
|
-
* at end-of-stream. That meant an early abort (before the result line) or a
|
|
647
|
-
* mid-stream rotation (Claude `--resume` rewriting the session id) was invisible
|
|
648
|
-
* to the bot runtime — leaving the runtime stuck on a pending id, or letting a
|
|
649
|
-
* later insertion land on a phantom session. Routing through this helper makes
|
|
650
|
-
* every observed id change propagate immediately to `opts.onSessionId`, which
|
|
651
|
-
* in bot.ts wires straight into `promoteSessionRuntime`.
|
|
652
|
-
*/
|
|
653
549
|
export function emitSessionIdUpdate(s, rawId) {
|
|
654
550
|
if (typeof rawId !== 'string')
|
|
655
551
|
return;
|
|
@@ -660,22 +556,8 @@ export function emitSessionIdUpdate(s, rawId) {
|
|
|
660
556
|
try {
|
|
661
557
|
s._emitSessionId?.(trimmed);
|
|
662
558
|
}
|
|
663
|
-
catch {
|
|
664
|
-
}
|
|
665
|
-
/**
|
|
666
|
-
* Canonical session-list display title used by *every* surface (IM channels
|
|
667
|
-
* + dashboard). The order is intentional:
|
|
668
|
-
*
|
|
669
|
-
* 1. `title` — set ONCE from the original user prompt that started the
|
|
670
|
-
* session. Stable; never overwritten by sub-agent or tool prompts.
|
|
671
|
-
* 2. `lastQuestion` — most recent user message. Fallback only, because for
|
|
672
|
-
* Claude this can be a Task-tool sub-agent prompt and we don't want
|
|
673
|
-
* sub-agent text leaking into the title.
|
|
674
|
-
* 3. `sessionId` — last-resort identifier.
|
|
675
|
-
*
|
|
676
|
-
* The dashboard frontend (`dashboard/src/utils.ts`) mirrors this order — keep
|
|
677
|
-
* the two in sync.
|
|
678
|
-
*/
|
|
559
|
+
catch { }
|
|
560
|
+
}
|
|
679
561
|
export function sessionListDisplayTitle(session) {
|
|
680
562
|
const title = sanitizeSessionUserPreviewText(String(session.title || ''));
|
|
681
563
|
if (title)
|