botmux 2.69.0 → 2.71.0

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 (80) hide show
  1. package/dist/adapters/backend/sandbox.d.ts +7 -0
  2. package/dist/adapters/backend/sandbox.d.ts.map +1 -1
  3. package/dist/adapters/backend/sandbox.js +85 -9
  4. package/dist/adapters/backend/sandbox.js.map +1 -1
  5. package/dist/adapters/cli/antigravity.d.ts.map +1 -1
  6. package/dist/adapters/cli/antigravity.js +1 -0
  7. package/dist/adapters/cli/antigravity.js.map +1 -1
  8. package/dist/adapters/cli/claude-code.d.ts +2 -0
  9. package/dist/adapters/cli/claude-code.d.ts.map +1 -1
  10. package/dist/adapters/cli/claude-code.js +3 -0
  11. package/dist/adapters/cli/claude-code.js.map +1 -1
  12. package/dist/adapters/cli/coco.d.ts.map +1 -1
  13. package/dist/adapters/cli/coco.js +1 -0
  14. package/dist/adapters/cli/coco.js.map +1 -1
  15. package/dist/adapters/cli/codex-app.d.ts.map +1 -1
  16. package/dist/adapters/cli/codex-app.js +1 -0
  17. package/dist/adapters/cli/codex-app.js.map +1 -1
  18. package/dist/adapters/cli/codex.d.ts.map +1 -1
  19. package/dist/adapters/cli/codex.js +2 -0
  20. package/dist/adapters/cli/codex.js.map +1 -1
  21. package/dist/adapters/cli/gemini.d.ts.map +1 -1
  22. package/dist/adapters/cli/gemini.js +1 -0
  23. package/dist/adapters/cli/gemini.js.map +1 -1
  24. package/dist/adapters/cli/mtr.d.ts.map +1 -1
  25. package/dist/adapters/cli/mtr.js +1 -0
  26. package/dist/adapters/cli/mtr.js.map +1 -1
  27. package/dist/adapters/cli/oh-my-pi.d.ts.map +1 -1
  28. package/dist/adapters/cli/oh-my-pi.js +1 -0
  29. package/dist/adapters/cli/oh-my-pi.js.map +1 -1
  30. package/dist/adapters/cli/opencode.d.ts.map +1 -1
  31. package/dist/adapters/cli/opencode.js +1 -0
  32. package/dist/adapters/cli/opencode.js.map +1 -1
  33. package/dist/adapters/cli/pi.d.ts.map +1 -1
  34. package/dist/adapters/cli/pi.js +1 -0
  35. package/dist/adapters/cli/pi.js.map +1 -1
  36. package/dist/adapters/cli/seed.d.ts.map +1 -1
  37. package/dist/adapters/cli/seed.js +1 -0
  38. package/dist/adapters/cli/seed.js.map +1 -1
  39. package/dist/adapters/cli/traex.d.ts.map +1 -1
  40. package/dist/adapters/cli/traex.js +1 -0
  41. package/dist/adapters/cli/traex.js.map +1 -1
  42. package/dist/adapters/cli/types.d.ts +14 -0
  43. package/dist/adapters/cli/types.d.ts.map +1 -1
  44. package/dist/core/command-handler.d.ts +6 -4
  45. package/dist/core/command-handler.d.ts.map +1 -1
  46. package/dist/core/command-handler.js +59 -12
  47. package/dist/core/command-handler.js.map +1 -1
  48. package/dist/core/session-discovery.d.ts.map +1 -1
  49. package/dist/core/session-discovery.js +13 -1
  50. package/dist/core/session-discovery.js.map +1 -1
  51. package/dist/core/types.d.ts +16 -0
  52. package/dist/core/types.d.ts.map +1 -1
  53. package/dist/core/types.js.map +1 -1
  54. package/dist/core/worker-pool.d.ts.map +1 -1
  55. package/dist/core/worker-pool.js +23 -2
  56. package/dist/core/worker-pool.js.map +1 -1
  57. package/dist/core/zellij-adopt-discovery.d.ts.map +1 -1
  58. package/dist/core/zellij-adopt-discovery.js +5 -0
  59. package/dist/core/zellij-adopt-discovery.js.map +1 -1
  60. package/dist/daemon.d.ts.map +1 -1
  61. package/dist/daemon.js +125 -1
  62. package/dist/daemon.js.map +1 -1
  63. package/dist/i18n/en.d.ts.map +1 -1
  64. package/dist/i18n/en.js +4 -3
  65. package/dist/i18n/en.js.map +1 -1
  66. package/dist/i18n/zh.d.ts.map +1 -1
  67. package/dist/i18n/zh.js +4 -3
  68. package/dist/i18n/zh.js.map +1 -1
  69. package/dist/im/lark/card-builder.d.ts +6 -4
  70. package/dist/im/lark/card-builder.d.ts.map +1 -1
  71. package/dist/im/lark/card-builder.js +14 -7
  72. package/dist/im/lark/card-builder.js.map +1 -1
  73. package/dist/im/lark/card-handler.d.ts.map +1 -1
  74. package/dist/im/lark/card-handler.js +35 -4
  75. package/dist/im/lark/card-handler.js.map +1 -1
  76. package/dist/types.d.ts +8 -1
  77. package/dist/types.d.ts.map +1 -1
  78. package/dist/worker.js +34 -4
  79. package/dist/worker.js.map +1 -1
  80. package/package.json +1 -1
package/dist/daemon.js CHANGED
@@ -41,7 +41,7 @@ import { createCliAdapterSync } from './adapters/cli/registry.js';
41
41
  import { initWorkerPool, setActiveSessionsRegistry, forkWorker, killWorker, scheduleCardPatch, setCurrentCliVersion, CARD_POSTING_SENTINEL, parkStreamCard, closeSession as closeSessionHelper, ensureCliEnv, writableTerminalLinkFor, } from './core/worker-pool.js';
42
42
  import { ipcRoute, jsonRes, readJsonBody, setBotName, setLarkAppId, startIpcServer, setWorkflowRunner } from './core/dashboard-ipc-server.js';
43
43
  import { saveFrozenCards } from './services/frozen-card-store.js';
44
- import { DAEMON_COMMANDS, SESSIONLESS_DAEMON_COMMANDS, resolvePassthroughCommands, handleCommand, handleCardCommand, handleTermLinkCommand, parseSlashCommandInvocation, parseForceTopicInvocation } from './core/command-handler.js';
44
+ import { DAEMON_COMMANDS, SESSIONLESS_DAEMON_COMMANDS, resolvePassthroughCommands, resolveAdapterDefaultPassthroughCommands, handleCommand, handleCardCommand, handleTermLinkCommand, parseSlashCommandInvocation, parseForceTopicInvocation } from './core/command-handler.js';
45
45
  import { findInheritablePeer } from './core/inherit-peer.js';
46
46
  import { isCallbackUrl, handleCallbackUrl } from './utils/user-token.js';
47
47
  import { consumeQuota, removeChatGrant, removeGlobalGrant } from './services/grant-store.js';
@@ -1693,6 +1693,90 @@ async function replyInvalidWorkingDirs(anchor, larkAppId, ds) {
1693
1693
  logger.warn(`[${tag(ds)}] configured workingDir missing: ${invalid.join(', ')}`);
1694
1694
  return true;
1695
1695
  }
1696
+ function isInitialSessionPassthrough(larkAppId, cmd) {
1697
+ return resolveAdapterDefaultPassthroughCommands(larkAppId).includes(cmd);
1698
+ }
1699
+ async function startInitialPassthroughSession(args) {
1700
+ const { larkAppId, chatId, chatType, scope, anchor, messageId, replyRootId, parsed, commandContent, senderOpenId, ownerOpenId, ownerUnionId, creatorOpenId, } = args;
1701
+ if (!await enforceMessageQuotaForCliInput(larkAppId, chatId, senderOpenId, messageId, anchor)) {
1702
+ return;
1703
+ }
1704
+ const botCfg = getBot(larkAppId).config;
1705
+ refreshCliVersion(botCfg.cliId, botCfg.cliPathOverride);
1706
+ const rootIdForStore = scope === 'thread' ? anchor : messageId;
1707
+ const session = sessionStore.createSession(chatId, rootIdForStore, commandContent.substring(0, 50), chatType);
1708
+ const now = Date.now();
1709
+ session.larkAppId = larkAppId;
1710
+ session.ownerOpenId = ownerOpenId;
1711
+ session.creatorOpenId = creatorOpenId;
1712
+ session.ownerUnionId = ownerUnionId;
1713
+ session.lastCallerOpenId = senderOpenId;
1714
+ session.quoteTargetId = parsed.messageId;
1715
+ session.quoteTargetSenderOpenId = senderOpenId;
1716
+ session.quoteTargetSenderIsBot = parsed.senderType === 'app' || parsed.senderType === 'bot';
1717
+ session.lastMessageAt = new Date(now).toISOString();
1718
+ session.scope = scope;
1719
+ sessionStore.updateSession(session);
1720
+ messageQueue.ensureQueue(anchor);
1721
+ messageQueue.appendMessage(anchor, { ...parsed, content: commandContent });
1722
+ const { pinnedWorkingDir, oncallEntry, inheritedFrom } = await resolvePinnedWorkingDir({ scope, anchor, chatId, chatType, larkAppId });
1723
+ const ds = {
1724
+ session,
1725
+ worker: null,
1726
+ workerPort: null,
1727
+ workerToken: null,
1728
+ larkAppId,
1729
+ chatId,
1730
+ chatType,
1731
+ scope,
1732
+ spawnedAt: Date.parse(session.createdAt) || now,
1733
+ cliVersion: cliVersionCache.get(botCfg.cliId)?.version ?? 'unknown',
1734
+ lastMessageAt: now,
1735
+ hasHistory: false,
1736
+ pendingRepo: !pinnedWorkingDir,
1737
+ pendingPrompt: '',
1738
+ pendingRawInput: commandContent,
1739
+ ownerOpenId,
1740
+ currentTurnTitle: commandContent.substring(0, 50),
1741
+ workingDir: pinnedWorkingDir,
1742
+ };
1743
+ if (pinnedWorkingDir) {
1744
+ ds.session.workingDir = pinnedWorkingDir;
1745
+ sessionStore.updateSession(ds.session);
1746
+ }
1747
+ beginReplyTargetTurn(ds, replyRootId, messageId);
1748
+ sessionStore.updateSession(ds.session);
1749
+ activeSessions.set(sessionKey(anchor, larkAppId), ds);
1750
+ if (pinnedWorkingDir) {
1751
+ if (await replyInvalidWorkingDirs(anchor, larkAppId, ds))
1752
+ return;
1753
+ rememberLastCliInput(ds, commandContent, commandContent);
1754
+ forkWorker(ds, '', false);
1755
+ const reason = oncallEntry
1756
+ ? `oncall-bound chat ${chatId}`
1757
+ : inheritedFrom
1758
+ ? `inherited from sibling session ${inheritedFrom.sessionId.substring(0, 8)} (app=${inheritedFrom.larkAppId ?? 'unknown'})`
1759
+ : `bot defaultWorkingDir`;
1760
+ logger.info(`[${tag(ds)}] ${reason} → workingDir=${pinnedWorkingDir}, queued initial raw passthrough ${commandContent.substring(0, 40)}`);
1761
+ return;
1762
+ }
1763
+ if (await replyInvalidWorkingDirs(anchor, larkAppId, ds))
1764
+ return;
1765
+ const scanDirs = getProjectScanDirs(ds).filter(d => existsSync(d));
1766
+ const projects = scanDirs.length > 0 ? scanMultipleProjects(scanDirs) : [];
1767
+ if (projects.length > 0) {
1768
+ lastRepoScan.set(chatId, projects);
1769
+ const cardJson = buildRepoSelectCard(projects, getSessionWorkingDir(ds), anchor, localeForBot(larkAppId));
1770
+ ds.repoCardMessageId = await sessionReply(anchor, cardJson, 'interactive', larkAppId);
1771
+ announcePendingRepoSession(ds);
1772
+ logger.info(`[${tag(ds)}] Waiting for repo selection before initial raw passthrough (${projects.length} projects)`);
1773
+ return;
1774
+ }
1775
+ ds.pendingRepo = false;
1776
+ rememberLastCliInput(ds, commandContent, commandContent);
1777
+ forkWorker(ds, '', false);
1778
+ logger.info(`[${tag(ds)}] No projects to select, queued initial raw passthrough ${commandContent.substring(0, 40)}`);
1779
+ }
1696
1780
  async function handleNewTopic(data, ctx) {
1697
1781
  const { chatId, messageId, chatType, larkAppId, replyRootId } = ctx;
1698
1782
  // scope/anchor are mutable here: `/t` / `/topic` may flip a 普通群 chat-scope
@@ -1783,6 +1867,26 @@ async function handleNewTopic(data, ctx) {
1783
1867
  return;
1784
1868
  }
1785
1869
  if (resolvePassthroughCommands(larkAppId).has(cmd)) {
1870
+ if (isInitialSessionPassthrough(larkAppId, cmd)) {
1871
+ await startInitialPassthroughSession({
1872
+ larkAppId,
1873
+ chatId,
1874
+ chatType,
1875
+ scope,
1876
+ anchor,
1877
+ messageId,
1878
+ replyRootId,
1879
+ parsed,
1880
+ commandContent,
1881
+ senderOpenId,
1882
+ // New-topic senders are humans here (mirrors the normal new-topic
1883
+ // spawn path, which assigns ownership unconditionally too).
1884
+ ownerOpenId: senderOpenId,
1885
+ ownerUnionId: senderUnionId,
1886
+ creatorOpenId: senderOpenId,
1887
+ });
1888
+ return;
1889
+ }
1786
1890
  await sessionReply(anchor, tr('daemon.cmd_requires_session', { cmd }, localeForBot(larkAppId)), 'text', larkAppId);
1787
1891
  return;
1788
1892
  }
@@ -2337,6 +2441,26 @@ async function handleThreadReply(data, ctx) {
2337
2441
  return;
2338
2442
  }
2339
2443
  if (resolvePassthroughCommands(larkAppId).has(cmd)) {
2444
+ if (!existingDs && threadChatId && isInitialSessionPassthrough(larkAppId, cmd)) {
2445
+ await startInitialPassthroughSession({
2446
+ larkAppId,
2447
+ chatId: threadChatId,
2448
+ chatType: ctxChatType,
2449
+ scope,
2450
+ anchor,
2451
+ messageId: parsed.messageId,
2452
+ replyRootId,
2453
+ parsed,
2454
+ commandContent,
2455
+ senderOpenId: threadSenderOpenId,
2456
+ // Bot-started cold starts get no human owner (mirrors the auto-create
2457
+ // path) — see the ownership note on startInitialPassthroughSession.
2458
+ ownerOpenId: isForeignBot ? undefined : threadSenderOpenId,
2459
+ ownerUnionId: isForeignBot ? undefined : data?.sender?.sender_id?.union_id,
2460
+ creatorOpenId: threadSenderOpenId,
2461
+ });
2462
+ return;
2463
+ }
2340
2464
  // 语义边界(刻意保留,非疏漏):passthrough(/model /clear /compact 等)按
2341
2465
  // “发给 CLI 的对话输入”处理,因此不过下面 DAEMON_COMMANDS 的 oncall
2342
2466
  // canOperate 闸 —— oncall 放行的就是对话输入,canOperate 只管 botmux