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.
Files changed (156) hide show
  1. package/dashboard/dist/assets/{AgentTab-BNJ73P0m.js → AgentTab-DtjuI8NU.js} +1 -1
  2. package/dashboard/dist/assets/ConnectionModal-BIx6a5o1.js +1 -0
  3. package/dashboard/dist/assets/{DirBrowser-D-GT-G-w.js → DirBrowser-BINh_7NB.js} +1 -1
  4. package/dashboard/dist/assets/{ExtensionsTab-BrJMulJR.js → ExtensionsTab-CHpd147b.js} +1 -1
  5. package/dashboard/dist/assets/{IMAccessTab-auPnx468.js → IMAccessTab-C4DbGxbG.js} +1 -1
  6. package/dashboard/dist/assets/{Modal-lYfO9m-I.js → Modal-D_PUi-5O.js} +1 -1
  7. package/dashboard/dist/assets/{Modals-PRdWOIY9.js → Modals-BahDEMqf.js} +1 -1
  8. package/dashboard/dist/assets/{Select-BhbU-rll.js → Select-Cp5VXb_2.js} +1 -1
  9. package/dashboard/dist/assets/SessionPanel-DZVNXptx.js +1 -0
  10. package/dashboard/dist/assets/SystemTab-CLznS31f.js +1 -0
  11. package/dashboard/dist/assets/index-CLGovkkw.js +3 -0
  12. package/dashboard/dist/assets/index-CXIN3nTr.css +1 -0
  13. package/dashboard/dist/assets/index-DcYOI6rL.js +23 -0
  14. package/dashboard/dist/assets/{shared-C5uXvhZJ.js → shared-C8DCTJ44.js} +1 -1
  15. package/dashboard/dist/index.html +2 -2
  16. package/dist/agent/acp-client.js +0 -59
  17. package/dist/agent/artifacts.js +1 -38
  18. package/dist/agent/auto-update.js +2 -78
  19. package/dist/agent/await-resume.js +0 -20
  20. package/dist/agent/cli/auth.js +3 -51
  21. package/dist/agent/cli/catalog.js +0 -3
  22. package/dist/agent/cli/detector.js +1 -19
  23. package/dist/agent/cli/index.js +0 -3
  24. package/dist/agent/cli/registry.js +0 -25
  25. package/dist/agent/driver.js +0 -14
  26. package/dist/agent/drivers/claude-tui.js +2 -769
  27. package/dist/agent/drivers/claude.js +12 -631
  28. package/dist/agent/drivers/codex.js +11 -162
  29. package/dist/agent/drivers/gemini.js +6 -114
  30. package/dist/agent/drivers/hermes.js +0 -128
  31. package/dist/agent/goal.js +0 -45
  32. package/dist/agent/handover.js +1 -46
  33. package/dist/agent/images.js +7 -133
  34. package/dist/agent/index.js +1 -29
  35. package/dist/agent/mcp/bridge.js +1 -197
  36. package/dist/agent/mcp/extensions.js +5 -84
  37. package/dist/agent/mcp/oauth.js +2 -69
  38. package/dist/agent/mcp/registry.js +2 -33
  39. package/dist/agent/mcp/session-server.js +2 -45
  40. package/dist/agent/mcp/tools/ask-user.js +0 -6
  41. package/dist/agent/mcp/tools/await-resume.js +0 -15
  42. package/dist/agent/mcp/tools/goal.js +0 -25
  43. package/dist/agent/mcp/tools/types.js +0 -5
  44. package/dist/agent/mcp/tools/workspace.js +0 -23
  45. package/dist/agent/npm.js +0 -14
  46. package/dist/agent/session.js +86 -196
  47. package/dist/agent/skill-installer.js +3 -70
  48. package/dist/agent/skills.js +0 -43
  49. package/dist/agent/stream.js +5 -148
  50. package/dist/agent/types.js +0 -12
  51. package/dist/agent/utils.js +2 -120
  52. package/dist/bot/bot.js +3 -468
  53. package/dist/bot/command-ui.js +0 -45
  54. package/dist/bot/commands.js +0 -51
  55. package/dist/bot/headless-bot.js +0 -21
  56. package/dist/bot/host.js +1 -5
  57. package/dist/bot/human-loop.js +0 -8
  58. package/dist/bot/menu.js +0 -3
  59. package/dist/bot/orchestration.js +0 -3
  60. package/dist/bot/render-shared.js +0 -63
  61. package/dist/bot/session-hub.js +14 -92
  62. package/dist/bot/session-status.js +1 -5
  63. package/dist/bot/streaming.js +0 -53
  64. package/dist/browser-profile.js +0 -51
  65. package/dist/browser-supervisor.js +0 -75
  66. package/dist/catalog/cli-tools.js +0 -53
  67. package/dist/catalog/index.js +0 -18
  68. package/dist/catalog/local-models.js +0 -18
  69. package/dist/catalog/mcp-servers.js +0 -35
  70. package/dist/catalog/skill-repos.js +0 -32
  71. package/dist/channels/base.js +0 -19
  72. package/dist/channels/dingtalk/bot.js +0 -3
  73. package/dist/channels/dingtalk/channel.js +0 -33
  74. package/dist/channels/discord/bot.js +0 -7
  75. package/dist/channels/discord/channel.js +0 -22
  76. package/dist/channels/feishu/bot.js +0 -71
  77. package/dist/channels/feishu/channel.js +0 -78
  78. package/dist/channels/feishu/markdown.js +0 -5
  79. package/dist/channels/feishu/render.js +0 -45
  80. package/dist/channels/health.js +0 -46
  81. package/dist/channels/slack/bot.js +0 -7
  82. package/dist/channels/slack/channel.js +1 -27
  83. package/dist/channels/states.js +0 -3
  84. package/dist/channels/telegram/bot.js +0 -60
  85. package/dist/channels/telegram/channel.js +2 -99
  86. package/dist/channels/telegram/directory.js +0 -3
  87. package/dist/channels/telegram/live-preview.js +0 -8
  88. package/dist/channels/telegram/render.js +0 -30
  89. package/dist/channels/wecom/bot.js +0 -3
  90. package/dist/channels/wecom/channel.js +0 -58
  91. package/dist/channels/weixin/api.js +0 -9
  92. package/dist/channels/weixin/bot.js +0 -88
  93. package/dist/channels/weixin/channel.js +0 -6
  94. package/dist/cli/autostart.js +1 -44
  95. package/dist/cli/channel-supervisor.js +1 -59
  96. package/dist/cli/channels.js +0 -6
  97. package/dist/cli/main.js +1 -145
  98. package/dist/cli/onboarding.js +0 -6
  99. package/dist/cli/run.js +0 -11
  100. package/dist/cli/setup-wizard.js +0 -3
  101. package/dist/core/config/runtime-config.js +0 -38
  102. package/dist/core/config/user-config.js +0 -63
  103. package/dist/core/config/validation.js +0 -9
  104. package/dist/core/constants.js +0 -268
  105. package/dist/core/git.js +0 -31
  106. package/dist/core/legacy-compat.js +1 -28
  107. package/dist/core/logging.js +0 -3
  108. package/dist/core/platform.js +0 -28
  109. package/dist/core/process-control.js +0 -8
  110. package/dist/core/secrets/index.js +0 -17
  111. package/dist/core/secrets/inline-seal.js +0 -7
  112. package/dist/core/secrets/ref.js +0 -19
  113. package/dist/core/secrets/resolver.js +0 -8
  114. package/dist/core/secrets/store.js +1 -12
  115. package/dist/core/utils.js +1 -37
  116. package/dist/core/version.js +0 -3
  117. package/dist/dashboard/platform.js +1 -35
  118. package/dist/dashboard/routes/agents.js +2 -71
  119. package/dist/dashboard/routes/cli.js +0 -27
  120. package/dist/dashboard/routes/config.js +0 -54
  121. package/dist/dashboard/routes/extensions.js +0 -132
  122. package/dist/dashboard/routes/local-models.js +0 -68
  123. package/dist/dashboard/routes/models.js +0 -46
  124. package/dist/dashboard/routes/sessions.js +0 -100
  125. package/dist/dashboard/runtime.js +1 -58
  126. package/dist/dashboard/server.js +0 -49
  127. package/dist/dashboard/session-control.js +2 -69
  128. package/dist/model/catalog.js +1 -17
  129. package/dist/model/index.js +0 -15
  130. package/dist/model/injector.js +1 -181
  131. package/dist/model/provider-models.js +1 -48
  132. package/dist/model/responses-bridge.js +3 -45
  133. package/dist/model/store.js +0 -17
  134. package/dist/model/types.js +0 -12
  135. package/dist/model/validation.js +1 -18
  136. package/dist/pikichannel/adapter-pikiloom.js +0 -31
  137. package/dist/pikichannel/code.js +0 -12
  138. package/dist/pikichannel/codec.js +0 -14
  139. package/dist/pikichannel/host.js +4 -33
  140. package/dist/pikichannel/protocol.js +0 -52
  141. package/dist/pikichannel/rendezvous-broker.js +5 -26
  142. package/dist/pikichannel/rendezvous-host.js +3 -16
  143. package/dist/pikichannel/server.js +6 -55
  144. package/dist/pikichannel/transport.js +0 -25
  145. package/dist/pikichannel/transports/webrtc-host.js +0 -18
  146. package/dist/pikichannel/transports/webrtc-shared.js +4 -34
  147. package/dist/pikichannel/transports/websocket-host.js +1 -14
  148. package/dist/pikichannel/turn.js +2 -69
  149. package/dist/pikichannel/web/sdk.js +14 -71
  150. package/package.json +1 -1
  151. package/dashboard/dist/assets/ConnectionModal-Dt05H2f9.js +0 -1
  152. package/dashboard/dist/assets/SessionPanel-_0dLWvEb.js +0 -1
  153. package/dashboard/dist/assets/SystemTab-CN_QrRKt.js +0 -1
  154. package/dashboard/dist/assets/index-CP3LYJR2.js +0 -23
  155. package/dashboard/dist/assets/index-C_neLnaO.js +0 -3
  156. package/dashboard/dist/assets/index-CyCspgtc.css +0 -1
@@ -1,6 +1,3 @@
1
- /**
2
- * Shared selection UI models and action executor for interactive commands.
3
- */
4
1
  import { normalizeAgent } from './bot.js';
5
2
  import { getDriverCapabilities } from '../agent/driver.js';
6
3
  import { getSessionStatusForChat } from './session-status.js';
@@ -36,8 +33,6 @@ export function encodeCommandAction(action) {
36
33
  case 'effort.set':
37
34
  return `eff:${action.effort}`;
38
35
  case 'models.select.model':
39
- // Encode native vs profile selection on the wire so decode is unambiguous.
40
- // `md:n:<modelId>` = native; `md:p:<profileId>:<modelId>` = BYOK profile.
41
36
  return action.profileId
42
37
  ? `md:p:${action.profileId}:${action.modelId}`
43
38
  : `md:n:${action.modelId}`;
@@ -97,8 +92,6 @@ export function decodeCommandAction(data) {
97
92
  return { kind: 'models.select.model', modelId, profileId: null };
98
93
  }
99
94
  if (rest.startsWith('p:')) {
100
- // p:<profileId>:<modelId> — profileId is a uuid (no colons), so split on
101
- // the first remaining colon yields a clean (profileId, modelId) pair.
102
95
  const sep = rest.indexOf(':', 2);
103
96
  if (sep < 0)
104
97
  return null;
@@ -108,8 +101,6 @@ export function decodeCommandAction(data) {
108
101
  return null;
109
102
  return { kind: 'models.select.model', modelId, profileId };
110
103
  }
111
- // Legacy callback payloads (pre-union) carried `md:<modelId>` directly.
112
- // Treat them as native selections so old buttons in the wild still work.
113
104
  if (!rest)
114
105
  return null;
115
106
  return { kind: 'models.select.model', modelId: rest, profileId: null };
@@ -144,9 +135,6 @@ export function decodeCommandAction(data) {
144
135
  }
145
136
  export async function buildSessionsCommandView(bot, chatId, page, pageSize = 5) {
146
137
  const data = await getSessionsPageData(bot, chatId, page, pageSize);
147
- // Multi-row: one button per session on its own line, prefixed with the
148
- // agent badge so a mixed workspace list reads cleanly. Avoid cramming
149
- // multiple buttons onto one row (some IM clients truncate).
150
138
  const sessionButtons = data.sessions.map(session => [{
151
139
  label: `[${session.agent}] ${session.title} · ${session.time}`,
152
140
  action: { kind: 'session.switch', sessionId: session.key },
@@ -186,16 +174,12 @@ export async function buildSessionsCommandView(bot, chatId, page, pageSize = 5)
186
174
  export function buildAgentsCommandView(bot, chatId) {
187
175
  const data = getAgentsListData(bot, chatId);
188
176
  const installed = data.agents.filter(a => a.installed);
189
- // Buttons stay short — friendly label + optional ✓ marker — so they don't
190
- // truncate on narrow IM clients.
191
177
  const actions = installed.map(agent => ({
192
178
  label: agent.label,
193
179
  action: { kind: 'agent.switch', agent: agent.agent },
194
180
  state: buttonStateFromFlags({ isCurrent: agent.isCurrent }),
195
181
  primary: agent.isCurrent,
196
182
  }));
197
- // Details (version + bound provider) live in the items list above the
198
- // buttons, where the renderer can show them in full without truncation.
199
183
  const items = installed.map(agent => {
200
184
  const main = agent.versionShort
201
185
  ? `${agent.label} · v${agent.versionShort}`
@@ -234,17 +218,11 @@ async function initModelsDraft(bot, chatId) {
234
218
  modelsDrafts.set(String(chatId), draft);
235
219
  return draft;
236
220
  }
237
- /**
238
- * Section headings for the unified picker. The trailing em-dash padding gives
239
- * the row a "label" look in Telegram/Feishu — clicking it falls through to a
240
- * harmless confirm which is a no-op when nothing has changed.
241
- */
242
221
  const MODEL_GROUP_LABELS = {
243
222
  native: '— Native —',
244
223
  cloud: '— Cloud Profiles —',
245
224
  local: '— Local Profiles —',
246
225
  };
247
- /** Match a picker row against the live draft so the "current" pip is unambiguous. */
248
226
  function modelRowMatchesDraft(agent, row, draft) {
249
227
  if (draft.profileId)
250
228
  return !!row.profileId && row.profileId === draft.profileId;
@@ -259,8 +237,6 @@ export async function buildModelsCommandView(bot, chatId, draft) {
259
237
  effort: data.effort?.current ?? null,
260
238
  };
261
239
  modelsDrafts.set(String(chatId), d);
262
- // Bucket rows by group while preserving the order resolveAgentModels gave us
263
- // (native → cloud → local). We render each non-empty group with a header.
264
240
  const groups = {
265
241
  native: [],
266
242
  cloud: [],
@@ -275,9 +251,6 @@ export async function buildModelsCommandView(bot, chatId, draft) {
275
251
  const rawItems = groups[group];
276
252
  if (!rawItems.length)
277
253
  continue;
278
- // Promote the currently-selected row to the top of its group so the user
279
- // sees their active pick first without having to scroll. This matches the
280
- // pre-union picker's behaviour, just scoped per-group instead of globally.
281
254
  const items = [...rawItems].sort((a, b) => Number(modelRowMatchesDraft(data.agent, b, d)) - Number(modelRowMatchesDraft(data.agent, a, d)));
282
255
  rows.push([{
283
256
  label: MODEL_GROUP_LABELS[group],
@@ -288,9 +261,6 @@ export async function buildModelsCommandView(bot, chatId, draft) {
288
261
  for (const model of items) {
289
262
  const selected = modelRowMatchesDraft(data.agent, model, d);
290
263
  const labelBase = model.alias || model.id;
291
- // For BYOK rows the alias is the Profile name — include provider tag so
292
- // two Profiles sharing a model id (e.g. "Sonnet 4.6 · OpenRouter" vs
293
- // "Sonnet 4.6 · Anthropic Direct") stay distinguishable in 1-column mode.
294
264
  const label = group === 'native' || !model.providerName
295
265
  ? labelBase
296
266
  : `${labelBase} · ${model.providerName}`;
@@ -389,10 +359,6 @@ export function buildModeCommandView(bot, chatId) {
389
359
  const metaLines = [];
390
360
  if (!isClaude)
391
361
  metaLines.push('Permission mode is only available for Claude.');
392
- // Workflow orchestration is no longer a standalone toggle here — it folded
393
- // into the effort picker as the top "Ultra" rung (max depth + multi-agent
394
- // fan-out). Surface its state and point users to /models so the capability
395
- // stays discoverable.
396
362
  if (supportsWorkflow) {
397
363
  metaLines.push(`Workflow orchestration: ${workflowOn ? 'On (Ultra effort)' : 'Off'} — pick the Ultra rung in /models to toggle.`);
398
364
  }
@@ -425,8 +391,6 @@ export async function executeCommandAction(bot, chatId, action, opts = {}) {
425
391
  }
426
392
  case 'session.switch': {
427
393
  const chat = bot.chat(chatId);
428
- // Workspace-wide lookup (no agent filter) so a row from any agent can be
429
- // resumed directly from a single mixed list.
430
394
  const result = await bot.fetchSessions(undefined, bot.chatWorkdir(chatId));
431
395
  if (!result.ok)
432
396
  return { kind: 'noop', message: 'Failed to load sessions' };
@@ -435,14 +399,10 @@ export async function executeCommandAction(bot, chatId, action, opts = {}) {
435
399
  return { kind: 'noop', message: 'Session not found' };
436
400
  const prevAgent = chat.agent;
437
401
  const runtime = bot.adoptExistingSessionForChat(chatId, session);
438
- // Restore the agent's persistent model / effort / Profile binding so the
439
- // next stream — and the IM picker chips — match the resumed session.
440
402
  if (session.model) {
441
403
  bot.switchModelForChat(chatId, session.model, session.profileId ?? null);
442
404
  }
443
405
  else if (session.profileId !== undefined) {
444
- // Session was native (profileId === null) — explicitly clear any
445
- // active Profile so we don't run with a stale BYOK binding.
446
406
  bot.switchModelForChat(chatId, bot.modelForAgent(session.agent), null);
447
407
  }
448
408
  if (session.thinkingEffort) {
@@ -532,8 +492,6 @@ export async function executeCommandAction(bot, chatId, action, opts = {}) {
532
492
  case 'models.select.model': {
533
493
  const draft = modelsDrafts.get(String(chatId)) ?? await initModelsDraft(bot, chatId);
534
494
  draft.modelId = action.modelId;
535
- // profileId can be null (native pick) or a uuid (BYOK pick). Treating
536
- // `undefined` as "leave alone" preserves the action shape's old contract.
537
495
  if (action.profileId !== undefined)
538
496
  draft.profileId = action.profileId;
539
497
  return { kind: 'view', view: await buildModelsCommandView(bot, chatId, draft), callbackText: '' };
@@ -561,9 +519,6 @@ export async function executeCommandAction(bot, chatId, action, opts = {}) {
561
519
  }
562
520
  const parts = [];
563
521
  if (modelChanged) {
564
- // Pass profileId explicitly: a null clears any active Profile binding,
565
- // a uuid binds the picked Profile. switchModelForChat handles both
566
- // sides of the dual path so call sites stay agnostic.
567
522
  bot.switchModelForChat(chatId, draft.modelId, draft.profileId ?? null);
568
523
  parts.push(draft.profileId ? `Profile: ${draft.modelId}` : `Model: ${draft.modelId}`);
569
524
  }
@@ -1,13 +1,3 @@
1
- /**
2
- * bot-commands.ts — channel-agnostic command data layer.
3
- *
4
- * Each function returns structured data objects that any IM renderer can consume.
5
- * No rendering, no HTML, no platform-specific formatting.
6
- *
7
- * Usage from a channel-specific bot (e.g. bot-telegram.ts, bot-feishu.ts):
8
- * const data = await getSessionsPageData(bot, chatId, 0);
9
- * const rendered = renderSessionsPage(data); // channel-specific renderer
10
- */
11
1
  import path from 'node:path';
12
2
  import fs from 'node:fs';
13
3
  import { fmtTokens, fmtUptime, fmtBytes } from './bot.js';
@@ -65,20 +55,6 @@ export function getWorkspacesData(bot, chatId) {
65
55
  });
66
56
  return { currentWorkdir, workspaces };
67
57
  }
68
- // ---------------------------------------------------------------------------
69
- // Goal — channel-agnostic /goal command dispatch
70
- // ---------------------------------------------------------------------------
71
- /**
72
- * Handle /goal <args> for a chat. Returns a human-readable status line for
73
- * the IM renderer to send back. Returns null when there is no active session
74
- * for the chat (caller renders its own "pick a session first" message).
75
- *
76
- * Per-agent routing:
77
- * - codex → native `thread/goal/*` RPC (state machine + budget + pause/resume)
78
- * - claude → native `/goal <condition>` slash command (Stop hook continuation,
79
- * auto-clear on completion, no budget / no pause/resume)
80
- * - others → pikiloom's portable goal.json with continuation injection
81
- */
82
58
  export async function handleGoalCommand(bot, chatId, rawArgs) {
83
59
  const session = bot.selectedSession(chatId);
84
60
  if (!session || !session.sessionId)
@@ -199,9 +175,6 @@ export function summarizeSessionRun(session) {
199
175
  }
200
176
  export async function getSessionsPageData(bot, chatId, page, pageSize = 5) {
201
177
  const cs = bot.chat(chatId);
202
- // Workspace-wide: drop the cs.agent filter so the list matches what the
203
- // dashboard shows for this workspace (all installed agents, sorted by
204
- // most-recent activity).
205
178
  const res = await bot.fetchSessions(undefined, bot.chatWorkdir(chatId));
206
179
  const sessions = res.ok ? res.sessions : [];
207
180
  const total = sessions.length;
@@ -332,14 +305,6 @@ function agentDisplayLabel(agentId) {
332
305
  return AGENT_LABEL_OVERRIDES[agentId]
333
306
  || agentId.charAt(0).toUpperCase() + agentId.slice(1);
334
307
  }
335
- /**
336
- * Pull the first semver-ish token out of a CLI `--version` string. Falls back
337
- * to the original string when no semver is present.
338
- *
339
- * "2.1.132 (Claude Code v2.1.132)" → "2.1.132"
340
- * "Hermes Agent v0.12.0 (2026.4.30)" → "0.12.0"
341
- * "codex-cli 0.128.0" → "0.128.0"
342
- */
343
308
  function shortVersion(raw) {
344
309
  if (!raw)
345
310
  return null;
@@ -422,9 +387,6 @@ const EFFORT_LEVELS = {
422
387
  { id: 'high', label: 'High' },
423
388
  { id: 'xhigh', label: 'Very High' },
424
389
  { id: 'max', label: 'Max' },
425
- // Synthetic top rung: "max depth + multi-agent Workflow orchestration", the
426
- // same bundle as Claude's `ultracode` mode. Not a real --effort value — the
427
- // bot decomposes it into (effort=max, workflow=on) at apply time.
428
390
  { id: 'ultra', label: 'Ultra' },
429
391
  ],
430
392
  codex: [
@@ -442,8 +404,6 @@ const EFFORT_LEVELS = {
442
404
  ],
443
405
  };
444
406
  function buildEffortData(bot, agent) {
445
- // Display value folds workflow into the synthetic `ultra` rung — see
446
- // Bot.effortSelectionForAgent.
447
407
  const currentEffort = bot.effortSelectionForAgent(agent);
448
408
  if (!currentEffort)
449
409
  return null;
@@ -460,11 +420,6 @@ export async function getModelsListData(bot, chatId) {
460
420
  const currentModel = bot.modelForAgent(cs.agent);
461
421
  const activeProfileId = bot.activeProfileIdForAgent(cs.agent);
462
422
  const res = await bot.fetchModels(cs.agent, bot.chatWorkdir(chatId));
463
- // Match priority:
464
- // - if a Profile is bound, only the row carrying that profileId is current
465
- // (two Profiles can share a modelId, so id-equality alone is ambiguous);
466
- // - otherwise only `'native'` rows are eligible to match against the
467
- // user-config model id.
468
423
  return {
469
424
  agent: cs.agent,
470
425
  currentModel,
@@ -504,9 +459,6 @@ export async function getStatusDataAsync(bot, chatId) {
504
459
  export function getHostDataSync(bot) {
505
460
  return bot.getHostData();
506
461
  }
507
- // ---------------------------------------------------------------------------
508
- // Skill routing
509
- // ---------------------------------------------------------------------------
510
462
  export { SKILL_CMD_PREFIX, indexSkillsByCommand };
511
463
  function relSkillPath(workdir, filePath) {
512
464
  const relative = path.relative(workdir, filePath).replace(/\\/g, '/');
@@ -553,7 +505,4 @@ export function getExtensionSummaryData(bot, chatId) {
553
505
  })),
554
506
  };
555
507
  }
556
- // ---------------------------------------------------------------------------
557
- // Re-export commonly used helpers for convenience
558
- // ---------------------------------------------------------------------------
559
508
  export { summarizePromptForStatus, fmtTokens, fmtUptime, fmtBytes, VERSION };
@@ -1,27 +1,6 @@
1
- /**
2
- * HeadlessBot — the Web Dashboard acting as a first-class terminal.
3
- *
4
- * pikiloom's terminals (IM channels and the Dashboard) are equal, pluggable
5
- * entry points. The IM channels each have a Bot subclass that connects a chat
6
- * transport; the Dashboard needs no transport — it drives the bot directly via
7
- * `runtime.getBotRef()`. HeadlessBot fills that gap: it satisfies the Bot
8
- * contract (`run()` / `requestStop()`) so `ChannelSupervisor` can manage its
9
- * lifecycle exactly like a channel bot and the dashboard can attach to it for
10
- * live stream snapshots — but it connects to nothing.
11
- *
12
- * It exists so the bot is usable with zero IM channels configured: install an
13
- * agent, open the dashboard, and you have a working terminal. When an IM
14
- * channel is later added, the supervisor tears this down and the channel's bot
15
- * takes over the dashboard attachment.
16
- */
17
1
  import { Bot } from './bot.js';
18
2
  export class HeadlessBot extends Bot {
19
3
  resolveRun = null;
20
- /**
21
- * No transport to connect — just mark the terminal live and block until
22
- * `requestStop()` so the supervisor's lifecycle (await runPromise on stop)
23
- * matches the channel bots'.
24
- */
25
4
  run() {
26
5
  this.connected = true;
27
6
  this.log('dashboard terminal ready (no IM channel configured)');
package/dist/bot/host.js CHANGED
@@ -1,7 +1,3 @@
1
- /**
2
- * Host system data collection: battery, CPU, memory, display name.
3
- * Platform-adaptive with macOS, Linux, and Windows support.
4
- */
5
1
  import os from 'node:os';
6
2
  import fs from 'node:fs';
7
3
  import path from 'node:path';
@@ -175,7 +171,7 @@ export function getHostDisplayName() {
175
171
  if (name)
176
172
  return name;
177
173
  }
178
- catch { /* fall through */ }
174
+ catch { }
179
175
  }
180
176
  return os.hostname();
181
177
  }
@@ -1,6 +1,3 @@
1
- /**
2
- * Human-in-the-loop prompt state machine and answer helpers.
3
- */
4
1
  export function createEmptyHumanLoopAnswer() {
5
2
  return {
6
3
  selectedValue: null,
@@ -125,11 +122,6 @@ function displayValueForOption(question, value) {
125
122
  const match = question.options?.find(opt => opt.value === value);
126
123
  return match?.label || value;
127
124
  }
128
- /**
129
- * Build a channel-agnostic summary of a prompt's resolved answers. Used by the
130
- * base bot's `onInteractionAnswered` hook so each channel renders the same
131
- * closed-state view + echo message without diverging.
132
- */
133
125
  export function summarizeResolvedHumanLoopAnswers(prompt, status = 'answered') {
134
126
  const rows = [];
135
127
  const compactParts = [];
package/dist/bot/menu.js CHANGED
@@ -1,6 +1,3 @@
1
- /**
2
- * Menu command definitions and skill-to-command mapping.
3
- */
4
1
  export const SKILL_CMD_PREFIX = 'sk_';
5
2
  export function buildWelcomeIntro(version) {
6
3
  return {
@@ -1,6 +1,3 @@
1
- /**
2
- * Session and message orchestration helpers shared across channels.
3
- */
4
1
  import { buildDefaultMenuCommands } from './menu.js';
5
2
  import { BOT_SHUTDOWN_FORCE_EXIT_MS as _BOT_SHUTDOWN_FORCE_EXIT_MS } from '../core/constants.js';
6
3
  export const BOT_SHUTDOWN_FORCE_EXIT_MS = _BOT_SHUTDOWN_FORCE_EXIT_MS;
@@ -1,18 +1,8 @@
1
- /**
2
- * Shared rendering utilities used by channel-specific renderers.
3
- *
4
- * Contains types, pure-data helpers, and functions that are identical across platforms.
5
- * Platform-specific formatting (HTML vs Markdown) stays in the respective render files.
6
- */
7
1
  import { materializeImage } from '../agent/index.js';
8
2
  import { fmtUptime, formatThinkingForDisplay, thinkLabel } from './bot.js';
9
3
  import { formatActivityCommandSummary, parseActivitySummary, renderPlanForPreview, summarizeActivityForPreview } from './streaming.js';
10
4
  import { supportsChannelCapability } from '../channels/base.js';
11
5
  import { agentLog, agentWarn } from '../agent/index.js';
12
- // ---------------------------------------------------------------------------
13
- // GFM table parsing
14
- // ---------------------------------------------------------------------------
15
- /** Parse GFM table lines into structured headers + rows. */
16
6
  export function parseGfmTable(tableLines) {
17
7
  if (tableLines.length < 3)
18
8
  return null;
@@ -39,9 +29,6 @@ export function parseGfmTable(tableLines) {
39
29
  }
40
30
  return rows.length ? { headers, rows } : null;
41
31
  }
42
- // ---------------------------------------------------------------------------
43
- // Footer helpers
44
- // ---------------------------------------------------------------------------
45
32
  export function fmtCompactUptime(ms) {
46
33
  return fmtUptime(ms).replace(/\s+/g, '');
47
34
  }
@@ -52,12 +39,6 @@ export function footerStatusSymbol(status) {
52
39
  case 'failed': return '✗';
53
40
  }
54
41
  }
55
- /**
56
- * Drop a leading `provider/` segment from long model ids so the footer stays
57
- * readable on narrow IM clients. `anthropic/claude-sonnet-4` → `claude-sonnet-4`,
58
- * `deepseek/deepseek-v4-flash` → `deepseek-v4-flash`. Already-short ids are
59
- * returned unchanged.
60
- */
61
42
  function compactModelLabel(model) {
62
43
  const trimmed = model.trim();
63
44
  if (trimmed.length <= 24)
@@ -65,12 +46,6 @@ function compactModelLabel(model) {
65
46
  const slashIdx = trimmed.indexOf('/');
66
47
  return slashIdx > 0 ? trimmed.slice(slashIdx + 1) : trimmed;
67
48
  }
68
- /**
69
- * Split footer fields into a primary identity line (agent + model) and a
70
- * secondary runtime line (effort, context%, elapsed). Channel renderers
71
- * compose the two lines with their own visual styling so narrow IM clients
72
- * never have to soft-wrap a single dense line.
73
- */
74
49
  export function formatFooterParts(agent, elapsedMs, meta, contextPercent, decorations) {
75
50
  const identityParts = [agent];
76
51
  if (decorations?.model)
@@ -82,10 +57,6 @@ export function formatFooterParts(agent, elapsedMs, meta, contextPercent, decora
82
57
  if (ctx != null)
83
58
  runtimeParts.push(`${ctx}%`);
84
59
  runtimeParts.push(fmtCompactUptime(Math.max(0, Math.round(elapsedMs))));
85
- // BYOK attribution — tells the user the turn is being routed through a
86
- // third-party provider rather than the agent CLI's native auth path.
87
- // Tucked at the end of the runtime line so it doesn't crowd the (often
88
- // long) identity line on narrow IM clients.
89
60
  const providerName = meta?.providerName ?? decorations?.provider ?? null;
90
61
  if (providerName)
91
62
  runtimeParts.push(`via ${providerName}`);
@@ -94,23 +65,11 @@ export function formatFooterParts(agent, elapsedMs, meta, contextPercent, decora
94
65
  runtime: runtimeParts.join(' · '),
95
66
  };
96
67
  }
97
- // ---------------------------------------------------------------------------
98
- // Activity trimming
99
- // ---------------------------------------------------------------------------
100
- /**
101
- * Trim the activity narrative for a streaming preview. Keeps the **most
102
- * recent** lines that fit the budget — the user is watching the turn live,
103
- * what just happened matters far more than what happened 30 tool-calls ago.
104
- * A leading `...` marker signals "earlier activity dropped" when truncation
105
- * happens; the tail order is preserved.
106
- */
107
68
  export function trimActivityForPreview(text, maxChars = 900) {
108
69
  if (text.length <= maxChars)
109
70
  return text;
110
71
  const lines = text.split('\n').filter(line => line.trim());
111
72
  if (lines.length <= 1) {
112
- // Single very-long line — keep the trailing characters with a leading
113
- // ellipsis so the freshest content is visible.
114
73
  return '...' + text.slice(text.length - Math.max(0, maxChars - 3));
115
74
  }
116
75
  const ellipsis = '...';
@@ -132,9 +91,6 @@ export function trimActivityForPreview(text, maxChars = 900) {
132
91
  return tail.join('\n');
133
92
  return [ellipsis, ...tail].join('\n');
134
93
  }
135
- // ---------------------------------------------------------------------------
136
- // Provider usage (plain-text builder — caller wraps as needed)
137
- // ---------------------------------------------------------------------------
138
94
  function rawUsageLine(parts) {
139
95
  return parts.filter(part => !!part && String(part).trim()).join(' ');
140
96
  }
@@ -167,15 +123,6 @@ export function buildProviderUsageLines(usage) {
167
123
  }
168
124
  return lines;
169
125
  }
170
- /**
171
- * Iterate an assistant turn's image MessageBlocks and dispatch each through
172
- * the channel's `sendImage` capability. No-op when the channel doesn't claim
173
- * `sendImage`. Errors per image are logged but don't block the rest of the
174
- * dispatch — the text reply path is responsible for the user-visible summary.
175
- *
176
- * Returns the list of `{messageId, caption}` entries so the caller can register
177
- * them with the session for "reply to continue" linkage.
178
- */
179
126
  export async function dispatchImageBlocks(channel, blocks, opts) {
180
127
  if (!blocks?.length)
181
128
  return [];
@@ -253,13 +200,6 @@ export function extractFinalReplyData(agent, result) {
253
200
  elapsedMs,
254
201
  };
255
202
  }
256
- /**
257
- * Build the sub-agent block for the streaming preview. Sub-agents are
258
- * deliberately isolated from parent activity (their tool list lives on each
259
- * StreamSubAgent record), so we render a separate compact section showing each
260
- * sub-agent's purpose + latest tool. Completed sub-agents are hidden — the
261
- * parent's activity already reflects the Task `done` line.
262
- */
263
203
  function renderSubAgentsForPreview(meta) {
264
204
  const subs = meta?.subAgents;
265
205
  if (!subs?.length)
@@ -288,9 +228,6 @@ export function extractStreamPreviewData(input) {
288
228
  const label = thinkLabel(input.agent);
289
229
  const thinkSnippet = rawThinking ? formatThinkingForDisplay(input.thinking, 600) : '';
290
230
  const preview = display.length > maxBody ? '(...truncated)\n' + display.slice(-maxBody) : display;
291
- // Elapsed time is the only monotonic progress signal available during the
292
- // thinking phase (see thinkingProgressText). Hidden in the first second so a
293
- // freshly-opened card doesn't flash "0s".
294
231
  const elapsedMs = Math.max(0, input.elapsedMs);
295
232
  const thinkingProgressText = elapsedMs >= 1000 ? fmtCompactUptime(elapsedMs) : null;
296
233
  return {