botmux 2.67.1 → 2.68.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 (55) hide show
  1. package/dist/adapters/cli/pi.d.ts.map +1 -1
  2. package/dist/adapters/cli/pi.js +0 -1
  3. package/dist/adapters/cli/pi.js.map +1 -1
  4. package/dist/cli.d.ts.map +1 -1
  5. package/dist/cli.js +79 -17
  6. package/dist/cli.js.map +1 -1
  7. package/dist/core/auto-start.d.ts +23 -0
  8. package/dist/core/auto-start.d.ts.map +1 -1
  9. package/dist/core/auto-start.js +30 -0
  10. package/dist/core/auto-start.js.map +1 -1
  11. package/dist/core/command-handler.d.ts +9 -9
  12. package/dist/core/command-handler.d.ts.map +1 -1
  13. package/dist/core/command-handler.js +23 -16
  14. package/dist/core/command-handler.js.map +1 -1
  15. package/dist/core/cost-calculator.d.ts +27 -0
  16. package/dist/core/cost-calculator.d.ts.map +1 -1
  17. package/dist/core/cost-calculator.js +483 -27
  18. package/dist/core/cost-calculator.js.map +1 -1
  19. package/dist/core/dashboard-rows.d.ts +3 -0
  20. package/dist/core/dashboard-rows.d.ts.map +1 -1
  21. package/dist/core/dashboard-rows.js +11 -0
  22. package/dist/core/dashboard-rows.js.map +1 -1
  23. package/dist/core/worker-pool.d.ts.map +1 -1
  24. package/dist/core/worker-pool.js +22 -1
  25. package/dist/core/worker-pool.js.map +1 -1
  26. package/dist/daemon.d.ts.map +1 -1
  27. package/dist/daemon.js +15 -6
  28. package/dist/daemon.js.map +1 -1
  29. package/dist/dashboard/web/i18n.d.ts.map +1 -1
  30. package/dist/dashboard/web/i18n.js +4 -0
  31. package/dist/dashboard/web/i18n.js.map +1 -1
  32. package/dist/dashboard/web/sessions.d.ts.map +1 -1
  33. package/dist/dashboard/web/sessions.js +16 -1
  34. package/dist/dashboard/web/sessions.js.map +1 -1
  35. package/dist/dashboard-web/app.js +120 -116
  36. package/dist/dashboard-web/style.css +4 -0
  37. package/dist/dashboard.js +41 -13
  38. package/dist/dashboard.js.map +1 -1
  39. package/dist/i18n/en.js +2 -2
  40. package/dist/i18n/en.js.map +1 -1
  41. package/dist/i18n/zh.js +2 -2
  42. package/dist/i18n/zh.js.map +1 -1
  43. package/dist/services/aiden-checkpoints.d.ts +5 -0
  44. package/dist/services/aiden-checkpoints.d.ts.map +1 -0
  45. package/dist/services/aiden-checkpoints.js +91 -0
  46. package/dist/services/aiden-checkpoints.js.map +1 -0
  47. package/dist/services/codex-transcript.d.ts +7 -0
  48. package/dist/services/codex-transcript.d.ts.map +1 -1
  49. package/dist/services/codex-transcript.js +60 -1
  50. package/dist/services/codex-transcript.js.map +1 -1
  51. package/dist/services/usage-ledger.d.ts +81 -0
  52. package/dist/services/usage-ledger.d.ts.map +1 -0
  53. package/dist/services/usage-ledger.js +353 -0
  54. package/dist/services/usage-ledger.js.map +1 -0
  55. package/package.json +1 -1
@@ -58,4 +58,27 @@ export declare function chatHasAllowedUser(memberOpenIds: Iterable<string>, allo
58
58
  * produces a non-empty CLI turn (FR-11).
59
59
  */
60
60
  export declare function resolveGroupJoinPrompt(configured: string | undefined): string;
61
+ /**
62
+ * 场景①: D7 gate with retry — wait for an allowedUser to appear in the chat.
63
+ *
64
+ * Alarm/oncall platforms that auto-create incident chats (e.g. ByteDance
65
+ * Nexus) add the bot FIRST and the human members moments later. A one-shot
66
+ * membership snapshot taken at bot.added time races against that and loses:
67
+ * the chat looks like it has no allowedUser and auto-start is silently
68
+ * skipped even though the owner lands in the chat a second later. Re-check
69
+ * membership a few times with backoff before giving up.
70
+ *
71
+ * Attempts = retryDelaysMs.length + 1 (default 4 attempts over ~25s). Errors
72
+ * from `listMembers` propagate to the caller on ANY attempt — same handling
73
+ * as the previous one-shot check (warn + scope hint). Empty allowedUsers
74
+ * short-circuits to false without calling `listMembers` (FR-2).
75
+ */
76
+ export declare function waitForAllowedUserInChat(opts: {
77
+ listMembers: () => Promise<string[]>;
78
+ allowedUsers: Iterable<string>;
79
+ /** Waits BETWEEN attempts (ms). Default [3000, 7000, 15000]. */
80
+ retryDelaysMs?: number[];
81
+ sleep?: (ms: number) => Promise<void>;
82
+ onRetry?: (attempt: number, delayMs: number) => void;
83
+ }): Promise<boolean>;
61
84
  //# sourceMappingURL=auto-start.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"auto-start.d.ts","sourceRoot":"","sources":["../../src/core/auto-start.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,+DAA+D;AAC/D,MAAM,WAAW,cAAc;IAC7B,2DAA2D;IAC3D,oBAAoB,EAAE,OAAO,CAAC;IAC9B,+EAA+E;IAC/E,0BAA0B,EAAE,MAAM,CAAC;IACnC,2EAA2E;IAC3E,mBAAmB,EAAE,OAAO,CAAC;CAC9B;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,yBAAyB,CAAC,IAAI,EAAE;IAC9C,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,QAAQ,GAAG,MAAM,CAAC;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,OAAO,GAAG,KAAK,CAAC;IAC1B,WAAW,EAAE,OAAO,CAAC;CACtB,GAAG,OAAO,CAQV;AAED;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAChC,aAAa,EAAE,QAAQ,CAAC,MAAM,CAAC,EAC/B,kBAAkB,EAAE,QAAQ,CAAC,MAAM,CAAC,GACnC,OAAO,CAOT;AAED;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CAAC,UAAU,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAE7E"}
1
+ {"version":3,"file":"auto-start.d.ts","sourceRoot":"","sources":["../../src/core/auto-start.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,+DAA+D;AAC/D,MAAM,WAAW,cAAc;IAC7B,2DAA2D;IAC3D,oBAAoB,EAAE,OAAO,CAAC;IAC9B,+EAA+E;IAC/E,0BAA0B,EAAE,MAAM,CAAC;IACnC,2EAA2E;IAC3E,mBAAmB,EAAE,OAAO,CAAC;CAC9B;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,yBAAyB,CAAC,IAAI,EAAE;IAC9C,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,QAAQ,GAAG,MAAM,CAAC;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,OAAO,GAAG,KAAK,CAAC;IAC1B,WAAW,EAAE,OAAO,CAAC;CACtB,GAAG,OAAO,CAQV;AAED;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAChC,aAAa,EAAE,QAAQ,CAAC,MAAM,CAAC,EAC/B,kBAAkB,EAAE,QAAQ,CAAC,MAAM,CAAC,GACnC,OAAO,CAOT;AAED;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CAAC,UAAU,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAE7E;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,wBAAwB,CAAC,IAAI,EAAE;IACnD,WAAW,EAAE,MAAM,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IACrC,YAAY,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;IAC/B,gEAAgE;IAChE,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IACzB,KAAK,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACtC,OAAO,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;CACtD,GAAG,OAAO,CAAC,OAAO,CAAC,CAWnB"}
@@ -59,4 +59,34 @@ export function chatHasAllowedUser(memberOpenIds, allowedUserOpenIds) {
59
59
  export function resolveGroupJoinPrompt(configured) {
60
60
  return (configured ?? '').trim();
61
61
  }
62
+ /**
63
+ * 场景①: D7 gate with retry — wait for an allowedUser to appear in the chat.
64
+ *
65
+ * Alarm/oncall platforms that auto-create incident chats (e.g. ByteDance
66
+ * Nexus) add the bot FIRST and the human members moments later. A one-shot
67
+ * membership snapshot taken at bot.added time races against that and loses:
68
+ * the chat looks like it has no allowedUser and auto-start is silently
69
+ * skipped even though the owner lands in the chat a second later. Re-check
70
+ * membership a few times with backoff before giving up.
71
+ *
72
+ * Attempts = retryDelaysMs.length + 1 (default 4 attempts over ~25s). Errors
73
+ * from `listMembers` propagate to the caller on ANY attempt — same handling
74
+ * as the previous one-shot check (warn + scope hint). Empty allowedUsers
75
+ * short-circuits to false without calling `listMembers` (FR-2).
76
+ */
77
+ export async function waitForAllowedUserInChat(opts) {
78
+ const allowed = [...opts.allowedUsers];
79
+ if (allowed.length === 0)
80
+ return false;
81
+ const delays = opts.retryDelaysMs ?? [3000, 7000, 15000];
82
+ const sleep = opts.sleep ?? ((ms) => new Promise(r => setTimeout(r, ms)));
83
+ for (let attempt = 0;; attempt++) {
84
+ if (chatHasAllowedUser(await opts.listMembers(), allowed))
85
+ return true;
86
+ if (attempt >= delays.length)
87
+ return false;
88
+ opts.onRetry?.(attempt + 1, delays[attempt]);
89
+ await sleep(delays[attempt]);
90
+ }
91
+ }
62
92
  //# sourceMappingURL=auto-start.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"auto-start.js","sourceRoot":"","sources":["../../src/core/auto-start.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAYH;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,yBAAyB,CAAC,IAOzC;IACC,OAAO,CACL,IAAI,CAAC,OAAO;QACZ,IAAI,CAAC,QAAQ,KAAK,OAAO;QACzB,IAAI,CAAC,KAAK,KAAK,QAAQ;QACvB,IAAI,CAAC,MAAM,KAAK,IAAI,CAAC,SAAS;QAC9B,CAAC,IAAI,CAAC,WAAW,CAClB,CAAC;AACJ,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,kBAAkB,CAChC,aAA+B,EAC/B,kBAAoC;IAEpC,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,kBAAkB,CAAC,CAAC;IAC5C,IAAI,OAAO,CAAC,IAAI,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IACrC,KAAK,MAAM,CAAC,IAAI,aAAa,EAAE,CAAC;QAC9B,IAAI,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC;YAAE,OAAO,IAAI,CAAC;IAClC,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,sBAAsB,CAAC,UAA8B;IACnE,OAAO,CAAC,UAAU,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;AACnC,CAAC"}
1
+ {"version":3,"file":"auto-start.js","sourceRoot":"","sources":["../../src/core/auto-start.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAYH;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,yBAAyB,CAAC,IAOzC;IACC,OAAO,CACL,IAAI,CAAC,OAAO;QACZ,IAAI,CAAC,QAAQ,KAAK,OAAO;QACzB,IAAI,CAAC,KAAK,KAAK,QAAQ;QACvB,IAAI,CAAC,MAAM,KAAK,IAAI,CAAC,SAAS;QAC9B,CAAC,IAAI,CAAC,WAAW,CAClB,CAAC;AACJ,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,kBAAkB,CAChC,aAA+B,EAC/B,kBAAoC;IAEpC,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,kBAAkB,CAAC,CAAC;IAC5C,IAAI,OAAO,CAAC,IAAI,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IACrC,KAAK,MAAM,CAAC,IAAI,aAAa,EAAE,CAAC;QAC9B,IAAI,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC;YAAE,OAAO,IAAI,CAAC;IAClC,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,sBAAsB,CAAC,UAA8B;IACnE,OAAO,CAAC,UAAU,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;AACnC,CAAC;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAM,CAAC,KAAK,UAAU,wBAAwB,CAAC,IAO9C;IACC,MAAM,OAAO,GAAG,CAAC,GAAG,IAAI,CAAC,YAAY,CAAC,CAAC;IACvC,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IACvC,MAAM,MAAM,GAAG,IAAI,CAAC,aAAa,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC;IACzD,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,IAAI,CAAC,CAAC,EAAU,EAAE,EAAE,CAAC,IAAI,OAAO,CAAO,CAAC,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC;IACxF,KAAK,IAAI,OAAO,GAAG,CAAC,GAAI,OAAO,EAAE,EAAE,CAAC;QAClC,IAAI,kBAAkB,CAAC,MAAM,IAAI,CAAC,WAAW,EAAE,EAAE,OAAO,CAAC;YAAE,OAAO,IAAI,CAAC;QACvE,IAAI,OAAO,IAAI,MAAM,CAAC,MAAM;YAAE,OAAO,KAAK,CAAC;QAC3C,IAAI,CAAC,OAAO,EAAE,CAAC,OAAO,GAAG,CAAC,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC;QAC7C,MAAM,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC;IAC/B,CAAC;AACH,CAAC"}
@@ -89,7 +89,7 @@ export interface CommandHandlerDeps {
89
89
  lastRepoScan: Map<string, import('../services/project-scanner.js').ProjectInfo[]>;
90
90
  }
91
91
  /**
92
- * Handle `/card` (owner-only). Resolves the active session itself, so off/on
92
+ * Handle `/card` (operator-only). Resolves the active session itself, so off/on
93
93
  * work WITHOUT one -- they only toggle the per-chat `noCardChats` config. A
94
94
  * summon (show/bare) needs a live session.
95
95
  *
@@ -103,15 +103,15 @@ export interface CommandHandlerDeps {
103
103
  */
104
104
  export declare function handleCardCommand(rootId: string, larkAppId: string, chatId: string, senderOpenId: string | undefined, content: string, deps: CommandHandlerDeps): Promise<void>;
105
105
  /**
106
- * Handle `/term` (owner-only) — the slash-command twin of the "🔑 获取操作链接"
107
- * card button. Privately hands the owner a writable (token-bearing) terminal card:
108
- * an in-chat visible-to-you ephemeral card in plain groups, auto-falling back to a
109
- * DM in topic / p2p chats. The link rides only that private channel — never the
110
- * group. Gated identically to /card (`senderOpenId === owner`), and strictly
111
- * needs a live session whose terminal is up. Routed for both the new-topic path
112
- * (daemon.ts) and the existing-session switch below.
106
+ * Handle `/term` (operator-only) — the slash-command twin of the "🔑 获取操作链接"
107
+ * card button. Privately hands the operator a writable (token-bearing) terminal
108
+ * card: an in-chat visible-to-you ephemeral card in plain groups, auto-falling back
109
+ * to a DM in topic / p2p chats. The link rides only that private channel — never the
110
+ * group. Gated identically to /card (`canOperate`), and strictly needs a live
111
+ * session whose terminal is up. Routed for both the new-topic path (daemon.ts) and
112
+ * the existing-session switch below.
113
113
  */
114
- export declare function handleTermLinkCommand(rootId: string, larkAppId: string, _chatId: string, senderOpenId: string | undefined, _content: string, deps: CommandHandlerDeps): Promise<void>;
114
+ export declare function handleTermLinkCommand(rootId: string, larkAppId: string, chatId: string, senderOpenId: string | undefined, _content: string, deps: CommandHandlerDeps): Promise<void>;
115
115
  export declare function handleCommand(cmd: string, rootId: string, message: LarkMessage, deps: CommandHandlerDeps, larkAppId?: string): Promise<void>;
116
116
  export declare function startCodexAppThreadSession(thread: CodexAppThreadSummary, ds: DaemonSession, deps: CommandHandlerDeps, larkAppId?: string): Promise<void>;
117
117
  export declare function startAdoptSession(target: AdoptableSession | ZellijAdoptableSession, ds: DaemonSession, deps: CommandHandlerDeps, larkAppId?: string): Promise<void>;
@@ -1 +1 @@
1
- {"version":3,"file":"command-handler.d.ts","sourceRoot":"","sources":["../../src/core/command-handler.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"command-handler.d.ts","sourceRoot":"","sources":["../../src/core/command-handler.ts"],"names":[],"mappings":"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"}
@@ -6,7 +6,7 @@ import { existsSync, readFileSync, statSync, writeFileSync } from 'node:fs';
6
6
  import { join, resolve, basename } from 'node:path';
7
7
  import { config } from '../config.js';
8
8
  import { buildTerminalUrl } from './terminal-url.js';
9
- import { getBot, getAllBots, getBotOpenId, getOwnerOpenId } from '../bot-registry.js';
9
+ import { getBot, getAllBots, getBotOpenId } from '../bot-registry.js';
10
10
  import * as sessionStore from '../services/session-store.js';
11
11
  import * as scheduleStore from '../services/schedule-store.js';
12
12
  import * as scheduler from './scheduler.js';
@@ -31,6 +31,7 @@ import { CONFIG_FIELDS, findConfigField, settableFieldKeys, parseBooleanValue, a
31
31
  import { resolveCliId, findInvalidAllowedUserEntries } from '../setup/bot-config-editor.js';
32
32
  import { publishAttentionPatch, announcePendingRepoSession } from './session-activity.js';
33
33
  import { setCardMode } from '../services/card-mode-store.js';
34
+ import { canOperate } from '../im/lark/event-dispatcher.js';
34
35
  import { invalidWorkingDirs } from '../utils/working-dir.js';
35
36
  import { writeRoleFile, deleteRoleFile, resolveRole, resolveTeamRoleFile, writeTeamRoleFile, deleteTeamRoleFile } from './role-resolver.js';
36
37
  import { getBotCapability, setBotCapability, clearBotCapability } from '../services/bot-profile-store.js';
@@ -709,7 +710,7 @@ async function handleConfigCommand(message, rootId, larkAppId, deps) {
709
710
  }
710
711
  // ─── Main command handler ────────────────────────────────────────────────────
711
712
  /**
712
- * Handle `/card` (owner-only). Resolves the active session itself, so off/on
713
+ * Handle `/card` (operator-only). Resolves the active session itself, so off/on
713
714
  * work WITHOUT one -- they only toggle the per-chat `noCardChats` config. A
714
715
  * summon (show/bare) needs a live session.
715
716
  *
@@ -724,9 +725,12 @@ async function handleConfigCommand(message, rootId, larkAppId, deps) {
724
725
  export async function handleCardCommand(rootId, larkAppId, chatId, senderOpenId, content, deps) {
725
726
  const loc = localeForBot(larkAppId);
726
727
  const reply = (c) => deps.sessionReply(rootId, c, undefined, larkAppId);
727
- const ownerOpenId = getOwnerOpenId(larkAppId);
728
- if (!ownerOpenId || !senderOpenId || senderOpenId !== ownerOpenId) {
729
- await reply(t('cmd.card.owner_only', undefined, loc));
728
+ // /card is an operator command — gate on canOperate, the same model every other
729
+ // daemon command uses. Open mode (no owner/allowlist) → canOperate passes for
730
+ // everyone; configured → any allowedUser (owner or co-owner); talk-only grantees
731
+ // (chatGrant/globalGrant/oncall members) are never operators.
732
+ if (!canOperate(larkAppId, chatId, senderOpenId)) {
733
+ await reply(t('cmd.card.operator_only', undefined, loc));
730
734
  return;
731
735
  }
732
736
  const ds = deps.activeSessions.get(sessionKey(rootId, larkAppId));
@@ -782,20 +786,23 @@ export async function handleCardCommand(rootId, larkAppId, chatId, senderOpenId,
782
786
  await reply(t('cmd.card.usage', undefined, loc));
783
787
  }
784
788
  /**
785
- * Handle `/term` (owner-only) — the slash-command twin of the "🔑 获取操作链接"
786
- * card button. Privately hands the owner a writable (token-bearing) terminal card:
787
- * an in-chat visible-to-you ephemeral card in plain groups, auto-falling back to a
788
- * DM in topic / p2p chats. The link rides only that private channel — never the
789
- * group. Gated identically to /card (`senderOpenId === owner`), and strictly
790
- * needs a live session whose terminal is up. Routed for both the new-topic path
791
- * (daemon.ts) and the existing-session switch below.
789
+ * Handle `/term` (operator-only) — the slash-command twin of the "🔑 获取操作链接"
790
+ * card button. Privately hands the operator a writable (token-bearing) terminal
791
+ * card: an in-chat visible-to-you ephemeral card in plain groups, auto-falling back
792
+ * to a DM in topic / p2p chats. The link rides only that private channel — never the
793
+ * group. Gated identically to /card (`canOperate`), and strictly needs a live
794
+ * session whose terminal is up. Routed for both the new-topic path (daemon.ts) and
795
+ * the existing-session switch below.
792
796
  */
793
- export async function handleTermLinkCommand(rootId, larkAppId, _chatId, senderOpenId, _content, deps) {
797
+ export async function handleTermLinkCommand(rootId, larkAppId, chatId, senderOpenId, _content, deps) {
794
798
  const loc = localeForBot(larkAppId);
795
799
  const reply = (c) => deps.sessionReply(rootId, c, undefined, larkAppId);
796
- const ownerOpenId = getOwnerOpenId(larkAppId);
797
- if (!ownerOpenId || !senderOpenId || senderOpenId !== ownerOpenId) {
798
- await reply(t('cmd.term.owner_only', undefined, loc));
800
+ // /term is an operator command that hands out a *writable* terminal link — gate
801
+ // on canOperate (same model as other daemon commands). senderOpenId must be
802
+ // present: open-mode canOperate passes even an undefined sender, but the writable
803
+ // card is delivered privately to that exact open_id.
804
+ if (!senderOpenId || !canOperate(larkAppId, chatId, senderOpenId)) {
805
+ await reply(t('cmd.term.operator_only', undefined, loc));
799
806
  return;
800
807
  }
801
808
  const ds = deps.activeSessions.get(sessionKey(rootId, larkAppId));