pikiloom 0.4.26 → 0.4.27

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 (155) hide show
  1. package/dashboard/dist/assets/{AgentTab-BNJ73P0m.js → AgentTab-DIP-y4dl.js} +1 -1
  2. package/dashboard/dist/assets/ConnectionModal-BCfvhkiI.js +1 -0
  3. package/dashboard/dist/assets/{DirBrowser-D-GT-G-w.js → DirBrowser-Dot7ua9-.js} +1 -1
  4. package/dashboard/dist/assets/{ExtensionsTab-BrJMulJR.js → ExtensionsTab-GioMx4S6.js} +1 -1
  5. package/dashboard/dist/assets/{IMAccessTab-auPnx468.js → IMAccessTab-C9_r8jJP.js} +1 -1
  6. package/dashboard/dist/assets/{Modal-lYfO9m-I.js → Modal-M1AP1sgR.js} +1 -1
  7. package/dashboard/dist/assets/{Modals-PRdWOIY9.js → Modals-CCm3UUfJ.js} +1 -1
  8. package/dashboard/dist/assets/{Select-BhbU-rll.js → Select-YubDM16P.js} +1 -1
  9. package/dashboard/dist/assets/{SessionPanel-_0dLWvEb.js → SessionPanel-Cnv9o96n.js} +1 -1
  10. package/dashboard/dist/assets/SystemTab-VgNivIe3.js +1 -0
  11. package/dashboard/dist/assets/index-BY7l20bi.js +23 -0
  12. package/dashboard/dist/assets/index-BlqvzDUL.js +3 -0
  13. package/dashboard/dist/assets/index-CXIN3nTr.css +1 -0
  14. package/dashboard/dist/assets/{shared-C5uXvhZJ.js → shared-C0SAInnT.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/SystemTab-CN_QrRKt.js +0 -1
  153. package/dashboard/dist/assets/index-CP3LYJR2.js +0 -23
  154. package/dashboard/dist/assets/index-C_neLnaO.js +0 -3
  155. package/dashboard/dist/assets/index-CyCspgtc.css +0 -1
@@ -1,6 +1,3 @@
1
- /**
2
- * Persistent user configuration (~/.pikiloom/setting.json) load/save/sync.
3
- */
4
1
  import fs from 'node:fs';
5
2
  import os from 'node:os';
6
3
  import path from 'node:path';
@@ -26,23 +23,10 @@ const MANAGED_ENV_KEYS = [
26
23
  'WECOM_BOT_SECRET',
27
24
  'WECOM_ENDPOINT',
28
25
  ];
29
- // Snapshot env vars present at module load — these were set externally by the
30
- // process launcher (docker `-e`, shell `export`, systemd unit, ...) and reflect
31
- // the operator's intent. `applyUserConfig` with `clearMissing` must never
32
- // delete them, even if setting.json is silent on the same key. Without this,
33
- // `docker run -e TELEGRAM_BOT_TOKEN=...` would survive only until the first
34
- // config sync tick, at which point the token gets wiped from the environment.
35
26
  const EXTERNAL_ENV_PRESET = new Set(MANAGED_ENV_KEYS.filter(key => {
36
27
  const value = process.env[key];
37
28
  return typeof value === 'string' && value.trim() !== '';
38
29
  }));
39
- /**
40
- * Channel-credential env vars that should hydrate a missing setting.json value
41
- * back into the in-memory config. Display surfaces (dashboard channel cards,
42
- * setup wizard) and channel resolution all read `config.telegramBotToken`-style
43
- * fields, so if the operator only provided env vars (the docker default) the
44
- * UI would otherwise show "not configured" even though the bot works fine.
45
- */
46
30
  const ENV_TO_CONFIG_KEY = [
47
31
  ['telegramBotToken', 'TELEGRAM_BOT_TOKEN'],
48
32
  ['telegramAllowedChatIds', 'TELEGRAM_ALLOWED_CHAT_IDS'],
@@ -60,14 +44,6 @@ const ENV_TO_CONFIG_KEY = [
60
44
  ['wecomBotSecret', 'WECOM_BOT_SECRET'],
61
45
  ['wecomEndpoint', 'WECOM_ENDPOINT'],
62
46
  ];
63
- /**
64
- * Return a copy of `config` with channel credential fields hydrated from
65
- * matching env vars when the setting.json value is empty. The returned object
66
- * must NOT be used as input to `saveUserConfig` — that would persist env-only
67
- * values into setting.json, which would defeat the purpose of running with
68
- * `-e TELEGRAM_BOT_TOKEN=...` (the operator wants the env var to remain the
69
- * source of truth across container restarts).
70
- */
71
47
  export function applyChannelEnvFallback(config) {
72
48
  let next = null;
73
49
  for (const [key, envName] of ENV_TO_CONFIG_KEY) {
@@ -86,13 +62,6 @@ export function applyChannelEnvFallback(config) {
86
62
  const USER_CONFIG_DIRNAME = STATE_DIR_NAME;
87
63
  const USER_CONFIG_FILENAME = 'setting.json';
88
64
  let activeUserConfig = {};
89
- // Parsed-config cache keyed by setting.json identity (path + mtime + size).
90
- // loadUserConfig() is hit from ~60 call sites — several times per HTTP request and
91
- // per agent stream (the MCP bridge resolves GUI config + per-extension OAuth) — so
92
- // re-reading + JSON.parse + normalize on every call is pure waste. A cache hit costs
93
- // one statSync (~100x cheaper). saveUserConfig refreshes this entry so writes are
94
- // visible immediately regardless of mtime granularity. Callers treat the result as
95
- // read-only and spread to mutate (the same contract getActiveUserConfig already uses).
96
65
  let userConfigCache = null;
97
66
  const userConfigListeners = new Set();
98
67
  let userConfigSyncTimer = null;
@@ -100,7 +69,6 @@ let userConfigSyncRefCount = 0;
100
69
  let userConfigSyncRaw = '';
101
70
  let userConfigSyncOverrides = {};
102
71
  const expandHomeDir = expandTilde;
103
- /** Normalize workspace entries — resolve paths, deduplicate, sort by order. */
104
72
  function normalizeWorkspaces(raw) {
105
73
  if (!Array.isArray(raw))
106
74
  return [];
@@ -133,10 +101,6 @@ function normalizeWorkspaces(raw) {
133
101
  entries.sort((a, b) => (a.order ?? 999) - (b.order ?? 999));
134
102
  return entries;
135
103
  }
136
- /**
137
- * Single canonical config path: ~/.pikiloom/setting.json
138
- * Both CLI and dashboard read/write this file exclusively.
139
- */
140
104
  export function getDevUserConfigPath() {
141
105
  return path.join(os.homedir(), USER_CONFIG_DIRNAME, 'dev', USER_CONFIG_FILENAME);
142
106
  }
@@ -306,10 +270,6 @@ export function applyUserConfig(config, _channel, options = {}) {
306
270
  const next = managed[key];
307
271
  const prev = process.env[key] ?? '';
308
272
  if (!next) {
309
- // Never clobber an env var the launcher set externally — that's the
310
- // `docker run -e ...` / `export FOO=...` contract. We only clear keys we
311
- // know were written by a previous `applyUserConfig` (i.e. *not* in the
312
- // boot-time snapshot).
313
273
  if (clearMissing && key in process.env && !EXTERNAL_ENV_PRESET.has(key)) {
314
274
  delete process.env[key];
315
275
  changedKeys.push(key);
@@ -334,9 +294,6 @@ export function setUserWorkdir(workdir, options = {}) {
334
294
  const resolvedWorkdir = resolveUserWorkdir({ workdir });
335
295
  const config = normalizeUserConfig({ ...loadUserConfig(), workdir: resolvedWorkdir });
336
296
  const configPath = saveUserConfig(config);
337
- // Don't pin workdir into userConfigSyncOverrides: the periodic sync reads
338
- // setting.json fresh each tick, so an external `npx pikiloom@latest` that
339
- // updates the file should be honored, not clobbered by an in-memory lock.
340
297
  applyUserConfig(config, undefined, { overwrite: true, clearMissing: true, notify: options.notify ?? true });
341
298
  return { configPath, workdir: resolvedWorkdir, config };
342
299
  }
@@ -370,18 +327,10 @@ export function startUserConfigSync(options = {}) {
370
327
  userConfigSyncOverrides = {};
371
328
  };
372
329
  }
373
- // ---------------------------------------------------------------------------
374
- // Known chat persistence
375
- // ---------------------------------------------------------------------------
376
330
  const KNOWN_CHAT_CONFIG_KEY = {
377
331
  feishu: 'feishuKnownChatIds',
378
332
  telegram: 'telegramKnownChatIds',
379
333
  };
380
- /**
381
- * Append `chatId` to the persisted known-chat list for `channelType` if it
382
- * isn't already there. The list survives crashes (env-based hand-off does
383
- * not) so `sendStartupNotice` can greet known chats after any restart path.
384
- */
385
334
  export function recordKnownChatId(channelType, chatId) {
386
335
  const id = String(chatId ?? '').trim();
387
336
  if (!id)
@@ -397,7 +346,6 @@ export function recordKnownChatId(channelType, chatId) {
397
346
  }
398
347
  catch { }
399
348
  }
400
- /** Load the persisted known-chat list for a channel. */
401
349
  export function loadKnownChatIds(channelType) {
402
350
  const key = KNOWN_CHAT_CONFIG_KEY[channelType];
403
351
  const config = loadUserConfig();
@@ -406,15 +354,10 @@ export function loadKnownChatIds(channelType) {
406
354
  ? list.map(v => String(v ?? '').trim()).filter(Boolean)
407
355
  : [];
408
356
  }
409
- // ---------------------------------------------------------------------------
410
- // Workspace registry
411
- // ---------------------------------------------------------------------------
412
- /** Load registered workspaces from config. Returns empty array if none. */
413
357
  export function loadWorkspaces() {
414
358
  const config = loadUserConfig();
415
359
  return normalizeWorkspaces(config.workspaces);
416
360
  }
417
- /** Add a workspace. Returns the new entry. Deduplicates by resolved path. */
418
361
  export function addWorkspace(workspacePath, name) {
419
362
  const resolved = path.resolve(expandHomeDir(workspacePath));
420
363
  const config = loadUserConfig();
@@ -436,7 +379,6 @@ export function addWorkspace(workspacePath, name) {
436
379
  saveUserConfig({ ...config, workspaces });
437
380
  return entry;
438
381
  }
439
- /** Remove a workspace by path. Returns true if removed. */
440
382
  export function removeWorkspace(workspacePath) {
441
383
  const resolved = path.resolve(expandHomeDir(workspacePath));
442
384
  const config = loadUserConfig();
@@ -448,7 +390,6 @@ export function removeWorkspace(workspacePath) {
448
390
  saveUserConfig({ ...config, workspaces: filtered });
449
391
  return true;
450
392
  }
451
- /** Rename a workspace. Returns the updated entry or null if not found. */
452
393
  export function renameWorkspace(workspacePath, newName) {
453
394
  const resolved = path.resolve(expandHomeDir(workspacePath));
454
395
  const config = loadUserConfig();
@@ -460,7 +401,6 @@ export function renameWorkspace(workspacePath, newName) {
460
401
  saveUserConfig({ ...config, workspaces });
461
402
  return entry;
462
403
  }
463
- /** Reorder workspaces by providing paths in desired order. */
464
404
  export function reorderWorkspaces(orderedPaths) {
465
405
  const config = loadUserConfig();
466
406
  const workspaces = normalizeWorkspaces(config.workspaces);
@@ -476,7 +416,6 @@ export function reorderWorkspaces(orderedPaths) {
476
416
  seen.add(resolved);
477
417
  }
478
418
  }
479
- // Append any workspaces not in the ordered list
480
419
  for (const entry of workspaces) {
481
420
  if (!seen.has(entry.path)) {
482
421
  entry.order = reordered.length;
@@ -486,7 +425,6 @@ export function reorderWorkspaces(orderedPaths) {
486
425
  saveUserConfig({ ...config, workspaces: reordered });
487
426
  return reordered;
488
427
  }
489
- /** Update workspace preferences (preferredAgent, etc.) */
490
428
  export function updateWorkspace(workspacePath, patch) {
491
429
  const resolved = path.resolve(expandHomeDir(workspacePath));
492
430
  const config = loadUserConfig();
@@ -503,7 +441,6 @@ export function updateWorkspace(workspacePath, patch) {
503
441
  saveUserConfig({ ...config, workspaces });
504
442
  return entry;
505
443
  }
506
- /** Find a workspace entry by path. */
507
444
  export function findWorkspace(workspacePath) {
508
445
  const resolved = path.resolve(expandHomeDir(workspacePath));
509
446
  return loadWorkspaces().find(w => w.path === resolved) || null;
@@ -1,6 +1,3 @@
1
- /**
2
- * Channel credential validation for Telegram, Feishu, and WeChat.
3
- */
4
1
  import * as lark from '@larksuiteoapi/node-sdk';
5
2
  import { validateTelegramToken } from '../../cli/setup-wizard.js';
6
3
  import { VALIDATION_TIMEOUTS } from '../constants.js';
@@ -220,7 +217,6 @@ export async function validateFeishuConfig(appId, appSecret, options = {}) {
220
217
  app: null,
221
218
  };
222
219
  }
223
- // Try to fetch bot display name using the tenant access token
224
220
  let botDisplayName = null;
225
221
  try {
226
222
  const botResp = await withTimeout(fetch(`${apiDomain}/open-apis/bot/v3/info`, {
@@ -232,7 +228,6 @@ export async function validateFeishuConfig(appId, appSecret, options = {}) {
232
228
  }
233
229
  }
234
230
  catch {
235
- // Non-critical — proceed without bot name
236
231
  }
237
232
  const app = { appId: trimmedAppId, displayName: botDisplayName };
238
233
  const identity = botDisplayName
@@ -490,10 +485,6 @@ export async function validateWecomConfig(botId, botSecret, _options = {}) {
490
485
  bot: null,
491
486
  };
492
487
  }
493
- // The Smart Bot WS endpoint cannot be probed via a simple HTTP request;
494
- // we accept the configured credentials and let the websocket subscribe ack
495
- // surface real auth errors at runtime. A non-empty pair already covers the
496
- // most common configuration mistake.
497
488
  return {
498
489
  state: readyChannelState('wecom', `WeChat Work bot ${trimmedId} configured.`),
499
490
  bot: { botId: trimmedId },
@@ -1,408 +1,140 @@
1
- /**
2
- * constants.ts — Centralized timeout, retry, and numeric constants.
3
- *
4
- * Grouped by domain / module so each subsystem can import only the
5
- * bucket it needs.
6
- */
7
1
  import path from 'node:path';
8
- // ---------------------------------------------------------------------------
9
- // MCP bridge
10
- // ---------------------------------------------------------------------------
11
- /** Timeouts for the per-stream MCP callback server and tool operations. */
12
2
  export const MCP_TIMEOUTS = {
13
- /** Max time to wait for the sendFile callback to complete. */
14
3
  sendFile: 60_000,
15
- /** Max time to receive the HTTP request body on the callback server. */
16
4
  requestBody: 10_000,
17
- /** Server-level: max time for an entire request lifecycle. */
18
5
  serverRequest: 90_000,
19
- /** Server-level: max time to receive request headers. */
20
6
  serverHeaders: 10_000,
21
- /** Timeout for `codex mcp add` registration commands. */
22
7
  codexMcpAdd: 10_000,
23
- /** Timeout for `codex mcp remove` cleanup commands. */
24
8
  codexMcpRemove: 5_000,
25
9
  };
26
- /** Maximum artifact file size the MCP bridge will accept (20 MB). */
27
10
  export const MCP_ARTIFACT_MAX_BYTES = 20 * 1024 * 1024;
28
- // ---------------------------------------------------------------------------
29
- // Dashboard
30
- // ---------------------------------------------------------------------------
31
- /** Timeouts used by the dashboard HTTP server and its status endpoints. */
32
11
  export const DASHBOARD_TIMEOUTS = {
33
- /** Timeout for agent model discovery (Codex cold-start can be slow). */
34
12
  agentStatusModels: 4_000,
35
- /** Timeout for agent usage data fetch. */
36
13
  agentStatusUsage: 1_500,
37
- /** Timeout for channel credential validation requests. */
38
14
  channelStatusValidation: 3_000,
39
- /** How long validated channel states are cached before re-checking. */
40
15
  channelStatusCacheTtl: 20_000,
41
- /** How long the full agent-status response is cached (SWR). */
42
16
  agentStatusCacheTtl: 30_000,
43
- /** Timeout for agent npm install via the dashboard. */
44
17
  agentInstall: 10 * 60_000,
45
- /** Default timeout for dashboard-spawned shell commands. */
46
18
  runCommand: 30_000,
47
19
  };
48
- // ---------------------------------------------------------------------------
49
- // Browser automation
50
- // ---------------------------------------------------------------------------
51
- // ---------------------------------------------------------------------------
52
- // Brand / state-dir / env identifiers — single source of truth
53
- // ---------------------------------------------------------------------------
54
- /** Home state directory name: `~/.pikiloom`. */
55
20
  export const STATE_DIR_NAME = '.pikiloom';
56
- /** Env var prefix for all pikiloom-specific variables. */
57
21
  export const ENV_PREFIX = 'PIKILOOM_';
58
- /**
59
- * Pre-rename identifier (`pikiclaw`). Kept ONLY for the one-time state-dir
60
- * migration, the env-var fallback (see core/legacy-compat.ts) and project-skill
61
- * discovery, so the real pikiclaw install base is never orphaned. Kept as lists
62
- * so a future rename only appends one entry. Drop a couple releases later.
63
- */
64
22
  export const LEGACY_STATE_DIR_NAMES = ['.pikiclaw'];
65
23
  export const LEGACY_ENV_PREFIXES = ['PIKICLAW_'];
66
- /**
67
- * Stable relative path for the managed Chrome profile under the home directory.
68
- * Keep this outside config-specific directories so `npm run dev` and the main
69
- * runtime share the same browser login state.
70
- */
71
24
  export const MANAGED_BROWSER_PROFILE_SUBPATH = path.join(STATE_DIR_NAME, 'browser', 'chrome-profile');
72
- /** Base Playwright MCP args for the managed browser integration. */
73
25
  export const PLAYWRIGHT_MCP_PACKAGE_NAME = '@playwright/mcp';
74
26
  export const PLAYWRIGHT_MCP_PACKAGE_VERSION = '0.0.75';
75
27
  export const PLAYWRIGHT_MCP_PACKAGE_SPEC = `${PLAYWRIGHT_MCP_PACKAGE_NAME}@${PLAYWRIGHT_MCP_PACKAGE_VERSION}`;
76
28
  export const PLAYWRIGHT_MCP_BROWSER_ARGS = ['--browser', 'chrome', '--viewport-size', '1920x1080'];
77
- /**
78
- * Env var name for pointing pikiloom at an external Chrome DevTools Protocol
79
- * endpoint (e.g. `http://chromium:9222`) instead of launching a local Chrome.
80
- * Primary use cases: Docker deployments that run a sidecar like
81
- * `lscr.io/linuxserver/chromium`, or attaching to a remote browser the user
82
- * already manages. When set, browser-supervisor skips every local-launch
83
- * codepath (no Chrome detection, no pid SIGKILL on restart) and pipes the URL
84
- * through to Playwright MCP's `--cdp-endpoint`.
85
- */
86
29
  export const PIKILOOM_BROWSER_CDP_URL_ENV = 'PIKILOOM_BROWSER_CDP_URL';
87
- /** Dashboard session pagination limits. */
88
30
  export const DASHBOARD_PAGINATION = {
89
31
  defaultPageSize: 6,
90
32
  maxPageSize: 30,
91
33
  };
92
- /** Timeouts for macOS permission checks and JXA scripts (dashboard). */
93
34
  export const DASHBOARD_PERMISSION_TIMEOUTS = {
94
- /** Default timeout for osascript / JXA calls. */
95
35
  jxaDefault: 5_000,
96
- /** Timeout for screencapture permission probe. */
97
36
  screenRecordingProbe: 5_000,
98
- /** Timeout for CGPreflight screen capture check. */
99
37
  screenRecordingPreflight: 4_000,
100
- /** Timeout for CGRequest screen capture request. */
101
38
  screenRecordingRequest: 6_000,
102
- /** Timeout for `open` command to launch System Preferences. */
103
39
  openSystemPreferences: 3_000,
104
- /** Timeout for parent process tree detection. */
105
40
  detectTerminal: 3_000,
106
41
  };
107
- /**
108
- * TTL for cached dashboard permission / host-terminal probes. `/api/state` is
109
- * polled (~1.5s while a channel validates) and each probe spawns subprocesses
110
- * (screencapture, an `ls` shell, a `ps` process-tree walk), so the raw checks
111
- * must not run per request. The host terminal is immutable per process;
112
- * permission grants change rarely and `requestPermission` invalidates the cache
113
- * on user action, so a short TTL surfaces grants without per-request spawns.
114
- */
115
42
  export const DASHBOARD_PERMISSION_CACHE_TTL_MS = 30_000;
116
- // ---------------------------------------------------------------------------
117
- // CLI / Daemon
118
- // ---------------------------------------------------------------------------
119
- /** Daemon (watchdog) restart timing constants. */
120
43
  export const DAEMON_TIMEOUTS = {
121
- /** Initial delay before restarting a crashed child. */
122
44
  restartDelay: 3_000,
123
- /** Maximum back-off delay for repeated rapid crashes. */
124
45
  maxRestartDelay: 60_000,
125
- /** If the child runs shorter than this, treat it as a rapid crash. */
126
46
  rapidCrashWindow: 10_000,
127
- /** Polling interval while waiting for dashboard config to become ready. */
128
47
  configPollInterval: 1_000,
129
48
  };
130
- // ---------------------------------------------------------------------------
131
- // Bot orchestration / shutdown
132
- // ---------------------------------------------------------------------------
133
- /** Time to wait before force-exiting during bot shutdown. */
134
49
  export const BOT_SHUTDOWN_FORCE_EXIT_MS = 3_000;
135
- // ---------------------------------------------------------------------------
136
- // Bot runtime
137
- // ---------------------------------------------------------------------------
138
- /** Bot-level timing constants. */
139
50
  export const BOT_TIMEOUTS = {
140
- /** Default run timeout for agent streams (seconds). */
141
51
  defaultRunTimeoutS: 7200,
142
- /** Interval for macOS user-activity caffeinate pulses. */
143
52
  macosUserActivityPulseInterval: 20_000,
144
- /** Timeout (seconds) for the caffeinate assertion per pulse. */
145
53
  macosUserActivityPulseTimeoutS: 30,
146
54
  };
147
- // ---------------------------------------------------------------------------
148
- // Live preview (stream feedback)
149
- // ---------------------------------------------------------------------------
150
- /** Timing constants for the channel-agnostic live preview controller. */
151
55
  export const STREAM_PREVIEW_TIMEOUTS = {
152
- /** Interval between heartbeat edits that refresh the elapsed timer. */
153
56
  heartbeat: 5_000,
154
- /** Interval between typing indicator pulses. */
155
57
  typing: 4_000,
156
- /** After this idle time, a "stalled" notice is shown. */
157
58
  stalledNotice: 15_000,
158
59
  };
159
- // ---------------------------------------------------------------------------
160
- // Channels — Telegram
161
- // ---------------------------------------------------------------------------
162
- /** Telegram channel transport constants. */
163
60
  export const TELEGRAM_LIMITS = {
164
- /** Maximum text length per Telegram message. */
165
61
  maxMessageLength: 4096,
166
- /** Maximum file size for send/receive (20 MB). */
167
62
  fileMaxBytes: 20 * 1024 * 1024,
168
- /** Maximum back-off delay for polling/connect retries. */
169
63
  maxRetryDelay: 60_000,
170
64
  };
171
- // ---------------------------------------------------------------------------
172
- // Channels — Feishu
173
- // ---------------------------------------------------------------------------
174
- /** Feishu channel transport constants. */
175
65
  export const FEISHU_LIMITS = {
176
- /** Card markdown budget (card JSON limit ~30 KB). */
177
66
  cardMax: 28_000,
178
- /** Maximum file size for send/receive (20 MB). */
179
67
  fileMaxBytes: 20 * 1024 * 1024,
180
- /** Maximum back-off delay for WebSocket reconnection retries. */
181
68
  wsStartRetryMaxDelay: 60_000,
182
- /** Initial retry delay for Feishu WebSocket connection. */
183
69
  wsStartRetryInitialDelay: 3_000,
184
70
  };
185
- /** Feishu bot rendering limit for card payloads. */
186
71
  export const FEISHU_BOT_CARD_MAX = 25_000;
187
- // ---------------------------------------------------------------------------
188
- // Channels — Weixin
189
- // ---------------------------------------------------------------------------
190
- /** Weixin channel transport constants. */
191
72
  export const WEIXIN_LIMITS = {
192
- /** Conservative text split budget for plain-text replies. */
193
73
  maxMessageLength: 1200,
194
- /** Long-poll timeout for getupdates. */
195
74
  longPollTimeout: 35_000,
196
- /** Maximum back-off delay for polling retries. */
197
75
  maxRetryDelay: 60_000,
198
76
  };
199
- // ---------------------------------------------------------------------------
200
- // Channels — Slack
201
- // ---------------------------------------------------------------------------
202
- /** Slack channel transport constants. */
203
77
  export const SLACK_LIMITS = {
204
- /** Slack chat.postMessage hard limit is 40000; cap at 35k for safety. */
205
78
  maxMessageLength: 35_000,
206
- /** Slack file upload size cap (1 GB); we keep parity with other channels at 20 MB. */
207
79
  fileMaxBytes: 20 * 1024 * 1024,
208
- /** Maximum back-off delay for socket-mode reconnect retries. */
209
80
  maxRetryDelay: 60_000,
210
- /** Initial back-off delay for socket-mode reconnect. */
211
81
  initialRetryDelay: 3_000,
212
82
  };
213
- // ---------------------------------------------------------------------------
214
- // Channels — Discord
215
- // ---------------------------------------------------------------------------
216
- /** Discord channel transport constants. */
217
83
  export const DISCORD_LIMITS = {
218
- /** Hard message cap is 2000 chars; leave a small buffer. */
219
84
  maxMessageLength: 1900,
220
- /** File size cap for non-Nitro guilds is 25 MB; we keep parity at 20 MB. */
221
85
  fileMaxBytes: 20 * 1024 * 1024,
222
- /** Maximum back-off delay for gateway reconnect retries. */
223
86
  maxRetryDelay: 60_000,
224
- /** Initial back-off delay for gateway reconnect. */
225
87
  initialRetryDelay: 3_000,
226
88
  };
227
- // ---------------------------------------------------------------------------
228
- // Channels — DingTalk
229
- // ---------------------------------------------------------------------------
230
- /** DingTalk channel transport constants. */
231
89
  export const DINGTALK_LIMITS = {
232
- /** Conservative text limit per message (markdown segments split here). */
233
90
  maxMessageLength: 5_000,
234
- /** Maximum back-off delay for stream reconnect retries. */
235
91
  maxRetryDelay: 60_000,
236
- /** Initial back-off delay for stream reconnect. */
237
92
  initialRetryDelay: 3_000,
238
93
  };
239
- // ---------------------------------------------------------------------------
240
- // Channels — WeChat Work (企业微信 智能机器人)
241
- // ---------------------------------------------------------------------------
242
- /** WeChat Work Smart Bot WebSocket transport constants. */
243
94
  export const WECOM_LIMITS = {
244
- /** Smart Bot text message hard cap is roughly 5KB chars. */
245
95
  maxMessageLength: 4_000,
246
- /** Heartbeat interval to keep the websocket alive. */
247
96
  heartbeatInterval: 30_000,
248
- /** Maximum back-off delay for websocket reconnect retries. */
249
97
  maxRetryDelay: 60_000,
250
- /** Initial back-off delay for websocket reconnect. */
251
98
  initialRetryDelay: 1_000,
252
- /** Default smart bot websocket endpoint. */
253
99
  defaultEndpoint: 'wss://openws.work.weixin.qq.com/wssvr/',
254
100
  };
255
- // ---------------------------------------------------------------------------
256
- // Config validation
257
- // ---------------------------------------------------------------------------
258
- /** Timeouts for channel credential validation flows. */
259
101
  export const VALIDATION_TIMEOUTS = {
260
- /** Default timeout for Feishu credential validation. */
261
102
  feishuDefault: 15_000,
262
- /** Timeout for fetching Feishu bot info after credential validation. */
263
103
  feishuBotInfo: 5_000,
264
- /** Timeout for Telegram token validation (setup wizard). */
265
104
  telegramToken: 8_000,
266
- /** Default timeout for Weixin credential validation. */
267
105
  weixinDefault: 8_000,
268
- /** Long-poll timeout for dashboard QR login wait calls. */
269
106
  weixinQrPoll: 35_000,
270
- /** Default timeout for Slack credential validation. */
271
107
  slackDefault: 8_000,
272
- /** Default timeout for Discord credential validation. */
273
108
  discordDefault: 8_000,
274
- /** Default timeout for DingTalk credential validation (gettoken endpoint). */
275
109
  dingtalkDefault: 8_000,
276
- /** Default timeout for WeChat Work bot validation handshake. */
277
110
  wecomDefault: 8_000,
278
111
  };
279
- // ---------------------------------------------------------------------------
280
- // Agent auto-update
281
- // ---------------------------------------------------------------------------
282
- /** Timeouts for the background agent auto-update system. */
283
112
  export const AGENT_UPDATE_TIMEOUTS = {
284
- /** After this duration a stale lock file is removed. */
285
113
  lockStale: 60 * 60_000,
286
- /** Maximum time for an agent update command to run. */
287
114
  commandTimeout: 15 * 60_000,
288
- /** Timeout for `npm prefix -g`. */
289
115
  npmPrefix: 10_000,
290
- /** Timeout for `npm view <pkg> version`. */
291
116
  npmView: 20_000,
292
- /** Max time an agent spawn waits for an in-flight reinstall of that agent's
293
- * own CLI to finish before exec'ing. A concurrent `npm install -g` / `brew
294
- * upgrade` (this process OR the prod self-bootstrap) briefly removes the bin
295
- * symlink, so racing it yields exit 127 "command not found"; the wait
296
- * resolves early the instant the install ends. */
297
117
  spawnWait: 2 * 60_000,
298
- /** Poll interval while a spawn waits out an in-flight reinstall. */
299
118
  spawnWaitPoll: 200,
300
119
  };
301
- // ---------------------------------------------------------------------------
302
- // Code agent (shared layer)
303
- // ---------------------------------------------------------------------------
304
- /** Caching TTLs for agent detection and version lookups. */
305
120
  export const AGENT_DETECT_TIMEOUTS = {
306
- /** How long a binary-detection result is cached. */
307
121
  detectTtl: 1_000,
308
- /** How long a version string is cached. */
309
122
  versionTtl: 5 * 60_000,
310
- /** Timeout for the `--version` command itself. */
311
123
  versionCommand: 3_000,
312
124
  };
313
- /** Grace period added to the user-configured timeout before hard-killing the agent. */
314
125
  export const AGENT_STREAM_HARD_KILL_GRACE_MS = 10_000;
315
- /**
316
- * On user abort, wait this long for the agent CLI to flush its session JSONL
317
- * (including any `[Request interrupted]` marker) before falling back to
318
- * SIGTERM. Keeps the partial assistant response persisted so the next task,
319
- * resumed via --resume, can see it in the transcript.
320
- */
321
126
  export const AGENT_GRACEFUL_ABORT_GRACE_MS = 2_000;
322
- /**
323
- * claude-tui stall watchdog — claude CLI is known to freeze mid-turn (observed
324
- * 2026-06-02 on 2.1.160: after a tool_result lands, the next assistant segment
325
- * never starts; the process stays alive, the JSONL goes permanently quiet, no
326
- * Stop hook ever fires). When every live signal (main JSONL, hook tool events,
327
- * sub-agent sidecars, hook lifecycle state) is silent past the threshold the
328
- * driver SIGTERMs the PTY and the dispatch wrapper auto-resumes the session
329
- * once. Quiet threshold must sit safely above the longest healthy gap between
330
- * JSONL events — a single max-effort inference can take a few minutes before
331
- * its first content block lands.
332
- */
333
127
  export const CLAUDE_TUI_STALL_QUIET_MS = 10 * 60_000;
334
- /**
335
- * Stall threshold while a hook-reported tool is still executing (PreToolUse
336
- * seen, no matching PostToolUse). Claude's own Bash timeout caps foreground
337
- * commands at ~10 minutes and fires PostToolUse either way, so a pending tool
338
- * silent for this long means the freeze hit mid-execution.
339
- */
340
128
  export const CLAUDE_TUI_STALL_PENDING_TOOL_MS = 30 * 60_000;
341
- /**
342
- * Fast-path stall: a healthy claude TUI repaints continuously while a turn is
343
- * in flight (spinner frames, stream ticks, status line) — the PTY never goes
344
- * byte-silent for minutes. If NO PTY output arrives for this long AND every
345
- * structured signal is equally quiet, the process event loop itself is gone
346
- * (the 2.1.160 mid-turn freeze: attachment lands → next API call never
347
- * assembles). Declare the stall now instead of waiting out the 10/30-minute
348
- * quiet thresholds — turns a 10-30 分钟「卡死」into a ~3 分钟自愈。
349
- * False-positive safe: long thinking / long Bash keep painting frames, which
350
- * refreshes the PTY signal and defers this path to the slow thresholds.
351
- */
352
129
  export const CLAUDE_TUI_STALL_PTY_DEAD_MS = 3 * 60_000;
353
- /**
354
- * Settle window after the TUI paints the "selected model is unavailable" banner
355
- * (a 404 model_not_found). The notice is terminal — claude paints it then idles
356
- * at the REPL forever: no JSONL is written, no Stop hook fires. We wait this
357
- * brief window to cross-validate that nothing substantive followed (the banner
358
- * alone is evidence, not a verdict — same discipline as resolveClaudeTuiLimitOutcome)
359
- * before ending the turn, instead of waiting out the 3–10 minute stall watchdog.
360
- */
361
130
  export const CLAUDE_TUI_MODEL_ERROR_SETTLE_MS = 2_500;
362
- /**
363
- * TTL for the post-Stop `hold-background` path. The hold protects
364
- * run_in_background agents living inside the claude process — but a live
365
- * agent keeps emitting hook/sidecar/JSONL traffic. If the hold sees no
366
- * activity on ANY channel for this long, the pending count is phantom (lost
367
- * <task-notification>, agents already finished): release as a NORMAL Stop.
368
- * Without this TTL the stall watchdog eventually fires instead, mislabels the
369
- * cleanly-finished turn 'stalled', and injects a confusing auto-resume prompt
370
- * (the「回合明明答完了还被注入 Continue」symptom).
371
- */
372
131
  export const CLAUDE_TUI_STOP_HOLD_QUIET_TTL_MS = 10 * 60_000;
373
- /** Codex-specific grace period added to the user-configured timeout. */
374
132
  export const CODEX_STREAM_HARD_KILL_GRACE_MS = 5_000;
375
- /**
376
- * If a session file was modified more recently than this threshold,
377
- * consider the session "running". Shared across Claude, Codex, and Gemini drivers.
378
- */
379
133
  export const SESSION_RUNNING_THRESHOLD_MS = 10_000;
380
- // ---------------------------------------------------------------------------
381
- // Driver — Codex
382
- // ---------------------------------------------------------------------------
383
- /** Timeout for the Codex app-server to become ready after spawn. */
384
134
  export const CODEX_APPSERVER_SPAWN_TIMEOUT_MS = 15_000;
385
- // ---------------------------------------------------------------------------
386
- // Driver — Gemini
387
- // ---------------------------------------------------------------------------
388
- /** Timeouts for Gemini usage / quota queries. */
389
135
  export const GEMINI_USAGE_TIMEOUTS = {
390
- /** Max time for the curl quota request. */
391
136
  request: 5_000,
392
- /** Extra buffer added to the curl timeout for the execSync wrapper. */
393
137
  execSyncBuffer: 3_000,
394
138
  };
395
- // ---------------------------------------------------------------------------
396
- // User config sync
397
- // ---------------------------------------------------------------------------
398
- /** Default interval for the user config file sync poll. */
399
139
  export const USER_CONFIG_SYNC_DEFAULT_INTERVAL_MS = 1_000;
400
- // ---------------------------------------------------------------------------
401
- // Git status
402
- // ---------------------------------------------------------------------------
403
- /**
404
- * Upper bound for a single `git status` invocation. Bounded so a huge repo or a
405
- * stuck `.git/index.lock` can never block `/status` or a workspace poll. Matches
406
- * the timeout used by the existing `/api/git-changes` endpoint.
407
- */
408
140
  export const GIT_STATUS_TIMEOUT_MS = 5_000;