botmux 2.40.0 → 2.41.0-canary.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 (177) hide show
  1. package/README.en.md +0 -1
  2. package/README.md +0 -1
  3. package/dist/adapters/hook-installer.d.ts.map +1 -1
  4. package/dist/adapters/hook-installer.js +2 -22
  5. package/dist/adapters/hook-installer.js.map +1 -1
  6. package/dist/cli/bots-list-output.d.ts +8 -0
  7. package/dist/cli/bots-list-output.d.ts.map +1 -1
  8. package/dist/cli/bots-list-output.js +9 -0
  9. package/dist/cli/bots-list-output.js.map +1 -1
  10. package/dist/core/command-handler.d.ts +0 -20
  11. package/dist/core/command-handler.d.ts.map +1 -1
  12. package/dist/core/command-handler.js +106 -105
  13. package/dist/core/command-handler.js.map +1 -1
  14. package/dist/core/dashboard-ipc-server.d.ts +2 -0
  15. package/dist/core/dashboard-ipc-server.d.ts.map +1 -1
  16. package/dist/core/dashboard-ipc-server.js +56 -0
  17. package/dist/core/dashboard-ipc-server.js.map +1 -1
  18. package/dist/core/role-resolver.d.ts +17 -1
  19. package/dist/core/role-resolver.d.ts.map +1 -1
  20. package/dist/core/role-resolver.js +64 -10
  21. package/dist/core/role-resolver.js.map +1 -1
  22. package/dist/core/session-manager.d.ts.map +1 -1
  23. package/dist/core/session-manager.js +14 -9
  24. package/dist/core/session-manager.js.map +1 -1
  25. package/dist/core/trigger-session.d.ts +9 -0
  26. package/dist/core/trigger-session.d.ts.map +1 -0
  27. package/dist/core/trigger-session.js +158 -0
  28. package/dist/core/trigger-session.js.map +1 -0
  29. package/dist/daemon.d.ts.map +1 -1
  30. package/dist/daemon.js +27 -19
  31. package/dist/daemon.js.map +1 -1
  32. package/dist/dashboard/connector-api.d.ts +3 -0
  33. package/dist/dashboard/connector-api.d.ts.map +1 -0
  34. package/dist/dashboard/connector-api.js +362 -0
  35. package/dist/dashboard/connector-api.js.map +1 -0
  36. package/dist/dashboard/federation-api.d.ts +35 -0
  37. package/dist/dashboard/federation-api.d.ts.map +1 -0
  38. package/dist/dashboard/federation-api.js +256 -0
  39. package/dist/dashboard/federation-api.js.map +1 -0
  40. package/dist/dashboard/federation-spoke-api.d.ts +46 -0
  41. package/dist/dashboard/federation-spoke-api.d.ts.map +1 -0
  42. package/dist/dashboard/federation-spoke-api.js +400 -0
  43. package/dist/dashboard/federation-spoke-api.js.map +1 -0
  44. package/dist/dashboard/pairing-api.d.ts +19 -0
  45. package/dist/dashboard/pairing-api.d.ts.map +1 -0
  46. package/dist/dashboard/pairing-api.js +83 -0
  47. package/dist/dashboard/pairing-api.js.map +1 -0
  48. package/dist/dashboard/team-group.d.ts +18 -0
  49. package/dist/dashboard/team-group.d.ts.map +1 -0
  50. package/dist/dashboard/team-group.js +7 -0
  51. package/dist/dashboard/team-group.js.map +1 -0
  52. package/dist/dashboard/team-page.d.ts +8 -0
  53. package/dist/dashboard/team-page.d.ts.map +1 -0
  54. package/dist/dashboard/team-page.js +480 -0
  55. package/dist/dashboard/team-page.js.map +1 -0
  56. package/dist/dashboard/team-routes.d.ts +30 -0
  57. package/dist/dashboard/team-routes.d.ts.map +1 -0
  58. package/dist/dashboard/team-routes.js +458 -0
  59. package/dist/dashboard/team-routes.js.map +1 -0
  60. package/dist/dashboard/trigger-api.d.ts +13 -0
  61. package/dist/dashboard/trigger-api.d.ts.map +1 -0
  62. package/dist/dashboard/trigger-api.js +77 -0
  63. package/dist/dashboard/trigger-api.js.map +1 -0
  64. package/dist/dashboard/web/app.js +3 -0
  65. package/dist/dashboard/web/app.js.map +1 -1
  66. package/dist/dashboard/web/team-federation.d.ts +2 -0
  67. package/dist/dashboard/web/team-federation.d.ts.map +1 -0
  68. package/dist/dashboard/web/team-federation.js +304 -0
  69. package/dist/dashboard/web/team-federation.js.map +1 -0
  70. package/dist/dashboard/webhook-routes.d.ts +19 -0
  71. package/dist/dashboard/webhook-routes.d.ts.map +1 -0
  72. package/dist/dashboard/webhook-routes.js +321 -0
  73. package/dist/dashboard/webhook-routes.js.map +1 -0
  74. package/dist/dashboard-web/app.js +310 -244
  75. package/dist/dashboard-web/index.html +1 -0
  76. package/dist/dashboard.js +155 -1
  77. package/dist/dashboard.js.map +1 -1
  78. package/dist/i18n/en.d.ts.map +1 -1
  79. package/dist/i18n/en.js +22 -7
  80. package/dist/i18n/en.js.map +1 -1
  81. package/dist/i18n/zh.d.ts.map +1 -1
  82. package/dist/i18n/zh.js +22 -7
  83. package/dist/i18n/zh.js.map +1 -1
  84. package/dist/im/lark/client.d.ts +21 -0
  85. package/dist/im/lark/client.d.ts.map +1 -1
  86. package/dist/im/lark/client.js +86 -18
  87. package/dist/im/lark/client.js.map +1 -1
  88. package/dist/services/bot-owner-store.d.ts +28 -0
  89. package/dist/services/bot-owner-store.d.ts.map +1 -0
  90. package/dist/services/bot-owner-store.js +82 -0
  91. package/dist/services/bot-owner-store.js.map +1 -0
  92. package/dist/services/bot-profile-store.d.ts +16 -0
  93. package/dist/services/bot-profile-store.d.ts.map +1 -0
  94. package/dist/services/bot-profile-store.js +98 -0
  95. package/dist/services/bot-profile-store.js.map +1 -0
  96. package/dist/services/connector-store.d.ts +63 -0
  97. package/dist/services/connector-store.d.ts.map +1 -0
  98. package/dist/services/connector-store.js +79 -0
  99. package/dist/services/connector-store.js.map +1 -0
  100. package/dist/services/deployment-identity.d.ts +9 -0
  101. package/dist/services/deployment-identity.d.ts.map +1 -0
  102. package/dist/services/deployment-identity.js +47 -0
  103. package/dist/services/deployment-identity.js.map +1 -0
  104. package/dist/services/federation-membership-store.d.ts +23 -0
  105. package/dist/services/federation-membership-store.d.ts.map +1 -0
  106. package/dist/services/federation-membership-store.js +66 -0
  107. package/dist/services/federation-membership-store.js.map +1 -0
  108. package/dist/services/federation-roster.d.ts +54 -0
  109. package/dist/services/federation-roster.d.ts.map +1 -0
  110. package/dist/services/federation-roster.js +51 -0
  111. package/dist/services/federation-roster.js.map +1 -0
  112. package/dist/services/federation-store.d.ts +65 -0
  113. package/dist/services/federation-store.d.ts.map +1 -0
  114. package/dist/services/federation-store.js +125 -0
  115. package/dist/services/federation-store.js.map +1 -0
  116. package/dist/services/group-creator.d.ts +6 -0
  117. package/dist/services/group-creator.d.ts.map +1 -1
  118. package/dist/services/group-creator.js +10 -1
  119. package/dist/services/group-creator.js.map +1 -1
  120. package/dist/services/groups-store.d.ts +11 -0
  121. package/dist/services/groups-store.d.ts.map +1 -1
  122. package/dist/services/groups-store.js +27 -0
  123. package/dist/services/groups-store.js.map +1 -1
  124. package/dist/services/invite-store.d.ts +28 -0
  125. package/dist/services/invite-store.d.ts.map +1 -0
  126. package/dist/services/invite-store.js +85 -0
  127. package/dist/services/invite-store.js.map +1 -0
  128. package/dist/services/pairing-store.d.ts +47 -0
  129. package/dist/services/pairing-store.d.ts.map +1 -0
  130. package/dist/services/pairing-store.js +132 -0
  131. package/dist/services/pairing-store.js.map +1 -0
  132. package/dist/services/project-scanner.d.ts +0 -10
  133. package/dist/services/project-scanner.d.ts.map +1 -1
  134. package/dist/services/project-scanner.js +0 -11
  135. package/dist/services/project-scanner.js.map +1 -1
  136. package/dist/services/team-roster.d.ts +38 -0
  137. package/dist/services/team-roster.d.ts.map +1 -0
  138. package/dist/services/team-roster.js +82 -0
  139. package/dist/services/team-roster.js.map +1 -0
  140. package/dist/services/team-store.d.ts +54 -0
  141. package/dist/services/team-store.d.ts.map +1 -0
  142. package/dist/services/team-store.js +156 -0
  143. package/dist/services/team-store.js.map +1 -0
  144. package/dist/services/trigger-log-store.d.ts +46 -0
  145. package/dist/services/trigger-log-store.d.ts.map +1 -0
  146. package/dist/services/trigger-log-store.js +132 -0
  147. package/dist/services/trigger-log-store.js.map +1 -0
  148. package/dist/services/trigger-types.d.ts +57 -0
  149. package/dist/services/trigger-types.d.ts.map +1 -0
  150. package/dist/services/trigger-types.js +28 -0
  151. package/dist/services/trigger-types.js.map +1 -0
  152. package/dist/services/web-session-store.d.ts +28 -0
  153. package/dist/services/web-session-store.d.ts.map +1 -0
  154. package/dist/services/web-session-store.js +84 -0
  155. package/dist/services/web-session-store.js.map +1 -0
  156. package/dist/services/webhook-key.d.ts +16 -0
  157. package/dist/services/webhook-key.d.ts.map +1 -0
  158. package/dist/services/webhook-key.js +123 -0
  159. package/dist/services/webhook-key.js.map +1 -0
  160. package/dist/services/webhook-lifecycle-extractors.d.ts +15 -0
  161. package/dist/services/webhook-lifecycle-extractors.d.ts.map +1 -0
  162. package/dist/services/webhook-lifecycle-extractors.js +59 -0
  163. package/dist/services/webhook-lifecycle-extractors.js.map +1 -0
  164. package/dist/services/webhook-lifecycle-store.d.ts +45 -0
  165. package/dist/services/webhook-lifecycle-store.d.ts.map +1 -0
  166. package/dist/services/webhook-lifecycle-store.js +159 -0
  167. package/dist/services/webhook-lifecycle-store.js.map +1 -0
  168. package/dist/skills/definitions.d.ts.map +1 -1
  169. package/dist/skills/definitions.js +64 -10
  170. package/dist/skills/definitions.js.map +1 -1
  171. package/dist/workflows/events/payloads.d.ts +2 -2
  172. package/dist/workflows/events/schema.d.ts +8 -8
  173. package/dist/workflows/trigger-from-envelope.d.ts +13 -0
  174. package/dist/workflows/trigger-from-envelope.d.ts.map +1 -0
  175. package/dist/workflows/trigger-from-envelope.js +67 -0
  176. package/dist/workflows/trigger-from-envelope.js.map +1 -0
  177. package/package.json +1 -1
package/README.en.md CHANGED
@@ -308,7 +308,6 @@ Send these straight into a topic — the daemon intercepts them (no clash with t
308
308
  |---------|-------------|
309
309
  | `/repo` | Show project selector card (interactive dropdown + text list) |
310
310
  | `/repo <N>` | Switch to Nth project from last scan |
311
- | `/repo <path\|name>` | Skip the selector card; pass a path (relative/absolute) or a first-level project name under workingDir |
312
311
  | `/skip` | Skip the repo selector card, start the session in the default dir |
313
312
  | `/cd <path>` | Change working directory and restart the CLI process |
314
313
  | `/status` | Show session info (uptime, terminal URL, etc.) |
package/README.md CHANGED
@@ -302,7 +302,6 @@ botmux autostart enable
302
302
  |------|------|
303
303
  | `/repo` | 显示项目选择卡片(交互式下拉 + 文本列表) |
304
304
  | `/repo <N>` | 切换到上次扫描的第 N 个项目 |
305
- | `/repo <路径\|项目名>` | 跳过选择卡片,直接指定路径(相对/绝对)或 workingDir 下的一级项目名 |
306
305
  | `/skip` | 跳过仓库选择卡片,直接用默认目录开启会话 |
307
306
  | `/cd <路径>` | 切换工作目录并重启 CLI 进程 |
308
307
  | `/status` | 查看会话信息(运行时间、终端地址等) |
@@ -1 +1 @@
1
- {"version":3,"file":"hook-installer.d.ts","sourceRoot":"","sources":["../../src/adapters/hook-installer.ts"],"names":[],"mappings":"AAcA,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,MAAM,EAAE,iBAAiB,GAAG,iBAAiB,CAAC;CACxD;AA0LD;;;;;;;GAOG;AACH,wBAAgB,WAAW,CACzB,KAAK,EAAE,MAAM,EACb,WAAW,EAAE,iBAAiB,EAC9B,WAAW,EAAE,MAAM,GAClB,IAAI,CAoBN"}
1
+ {"version":3,"file":"hook-installer.d.ts","sourceRoot":"","sources":["../../src/adapters/hook-installer.ts"],"names":[],"mappings":"AAcA,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,MAAM,EAAE,iBAAiB,GAAG,iBAAiB,CAAC;CACxD;AAoKD;;;;;;;GAOG;AACH,wBAAgB,WAAW,CACzB,KAAK,EAAE,MAAM,EACb,WAAW,EAAE,iBAAiB,EAC9B,WAAW,EAAE,MAAM,GAClB,IAAI,CAoBN"}
@@ -40,29 +40,9 @@ function writeIfChanged(filePath, content) {
40
40
  throw new Error(`写入 ${filePath} 失败:${err.message}`);
41
41
  }
42
42
  }
43
- /**
44
- * 从完整 hookCommand 中提取 `hook <cliId>` 尾签名。
45
- * hookCommand 形如:`"<node>" "<...dist/cli.js>" hook claude-code`,
46
- * 尾部 `hook <cliId>` 不随 node / cli.js 安装路径变化。
47
- */
48
- function botmuxHookSuffix(hookCommand) {
49
- const idx = hookCommand.lastIndexOf(' hook ');
50
- return idx === -1 ? hookCommand : hookCommand.slice(idx + 1); // "hook <cliId>"
51
- }
52
- /**
53
- * 判断某个 hook group 是否是 botmux ask hook(用于幂等替换)。
54
- *
55
- * 不能只按命令字符串完全相等比对:同一台机器上 dev 源码 checkout 与 npm global
56
- * 安装的 cli.js 绝对路径不同,命令字符串就不同,会导致两条 botmux hook 同时残留、
57
- * 同一次 AskUserQuestion 触发两次 → 飞书发出两张卡。
58
- * 因此结构化识别:命令引用了 botmux 的 `cli.js` 且尾部是相同的 `hook <cliId>` 签名,
59
- * 即视为 botmux hook,无论它指向哪个安装路径。
60
- */
43
+ /** 判断某个 hook group 是否是 botmux ask hook(用于幂等替换)。 */
61
44
  function isBotmuxAskHookGroup(group, hookCommand) {
62
- const suffix = botmuxHookSuffix(hookCommand); // e.g. "hook claude-code"
63
- return group.hooks.some((e) => e.type === 'command' &&
64
- (e.command === hookCommand ||
65
- (e.command.includes('cli.js') && e.command.trimEnd().endsWith(suffix))));
45
+ return group.hooks.some((e) => e.type === 'command' && e.command === hookCommand);
66
46
  }
67
47
  function removeBotmuxAskHookGroups(hooks, eventName, hookCommand) {
68
48
  const existing = hooks[eventName] ?? [];
@@ -1 +1 @@
1
- {"version":3,"file":"hook-installer.js","sourceRoot":"","sources":["../../src/adapters/hook-installer.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"hook-installer.js","sourceRoot":"","sources":["../../src/adapters/hook-installer.ts"],"names":[],"mappings":"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"}
@@ -15,6 +15,14 @@ export type BotListOutputEntry = {
15
15
  larkAppId: string;
16
16
  /** Alias for workflow authors. Equal to larkAppId when locally configured. */
17
17
  workflowBot: string | null;
18
+ /** Short capability label (team-level), for picking who to hand off to. */
19
+ capability: string | null;
20
+ /** Whether this bot has a team-level role registered. */
21
+ hasTeamRole: boolean;
22
+ /** Whether YOU (the listing bot) can reliably @-mention it from here. */
23
+ mentionable: boolean;
24
+ /** How the @-mention handle was resolved. */
25
+ mentionSource: 'cross-ref' | 'self' | 'observed' | 'fallback';
18
26
  };
19
27
  export declare function formatChatBotsForCli(chatBots: ChatBotMember[], currentLarkAppId: string): BotListOutputEntry[];
20
28
  export declare function formatBotInfoEntriesForCli(botEntries: BotInfoEntryForList[], currentLarkAppId: string): BotListOutputEntry[];
@@ -1 +1 @@
1
- {"version":3,"file":"bots-list-output.d.ts","sourceRoot":"","sources":["../../src/cli/bots-list-output.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAE1D,MAAM,MAAM,mBAAmB,GAAG;IAChC,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,wFAAwF;IACxF,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,OAAO,CAAC;IAChB,MAAM,EAAE,YAAY,GAAG,WAAW,CAAC;IACnC,gGAAgG;IAChG,SAAS,EAAE,MAAM,CAAC;IAClB,8EAA8E;IAC9E,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B,CAAC;AAEF,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,aAAa,EAAE,EACzB,gBAAgB,EAAE,MAAM,GACvB,kBAAkB,EAAE,CAStB;AAED,wBAAgB,0BAA0B,CACxC,UAAU,EAAE,mBAAmB,EAAE,EACjC,gBAAgB,EAAE,MAAM,GACvB,kBAAkB,EAAE,CAWtB"}
1
+ {"version":3,"file":"bots-list-output.d.ts","sourceRoot":"","sources":["../../src/cli/bots-list-output.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAE1D,MAAM,MAAM,mBAAmB,GAAG;IAChC,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,wFAAwF;IACxF,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,OAAO,CAAC;IAChB,MAAM,EAAE,YAAY,GAAG,WAAW,CAAC;IACnC,gGAAgG;IAChG,SAAS,EAAE,MAAM,CAAC;IAClB,8EAA8E;IAC9E,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,2EAA2E;IAC3E,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,yDAAyD;IACzD,WAAW,EAAE,OAAO,CAAC;IACrB,yEAAyE;IACzE,WAAW,EAAE,OAAO,CAAC;IACrB,6CAA6C;IAC7C,aAAa,EAAE,WAAW,GAAG,MAAM,GAAG,UAAU,GAAG,UAAU,CAAC;CAC/D,CAAC;AAEF,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,aAAa,EAAE,EACzB,gBAAgB,EAAE,MAAM,GACvB,kBAAkB,EAAE,CAatB;AAED,wBAAgB,0BAA0B,CACxC,UAAU,EAAE,mBAAmB,EAAE,EACjC,gBAAgB,EAAE,MAAM,GACvB,kBAAkB,EAAE,CAgBtB"}
@@ -6,6 +6,10 @@ export function formatChatBotsForCli(chatBots, currentLarkAppId) {
6
6
  source: cb.source,
7
7
  larkAppId: cb.larkAppId,
8
8
  workflowBot: cb.larkAppId || null,
9
+ capability: cb.capability ?? null,
10
+ hasTeamRole: cb.hasTeamRole,
11
+ mentionable: cb.mentionable,
12
+ mentionSource: cb.mentionSource,
9
13
  }));
10
14
  }
11
15
  export function formatBotInfoEntriesForCli(botEntries, currentLarkAppId) {
@@ -18,6 +22,11 @@ export function formatBotInfoEntriesForCli(botEntries, currentLarkAppId) {
18
22
  source: 'configured',
19
23
  larkAppId: b.larkAppId,
20
24
  workflowBot: b.larkAppId,
25
+ // Local fallback path (no live chat query): we only know self reliably.
26
+ capability: null,
27
+ hasTeamRole: false,
28
+ mentionable: b.larkAppId === currentLarkAppId,
29
+ mentionSource: (b.larkAppId === currentLarkAppId ? 'self' : 'fallback'),
21
30
  }));
22
31
  }
23
32
  //# sourceMappingURL=bots-list-output.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"bots-list-output.js","sourceRoot":"","sources":["../../src/cli/bots-list-output.ts"],"names":[],"mappings":"AAqBA,MAAM,UAAU,oBAAoB,CAClC,QAAyB,EACzB,gBAAwB;IAExB,OAAO,QAAQ,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;QAC3B,IAAI,EAAE,EAAE,CAAC,WAAW;QACpB,MAAM,EAAE,EAAE,CAAC,MAAM;QACjB,MAAM,EAAE,EAAE,CAAC,SAAS,KAAK,gBAAgB;QACzC,MAAM,EAAE,EAAE,CAAC,MAAM;QACjB,SAAS,EAAE,EAAE,CAAC,SAAS;QACvB,WAAW,EAAE,EAAE,CAAC,SAAS,IAAI,IAAI;KAClC,CAAC,CAAC,CAAC;AACN,CAAC;AAED,MAAM,UAAU,0BAA0B,CACxC,UAAiC,EACjC,gBAAwB;IAExB,OAAO,UAAU;SACd,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;SAC1B,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QACX,IAAI,EAAE,CAAC,CAAC,OAAO,IAAI,CAAC,CAAC,KAAK;QAC1B,MAAM,EAAE,CAAC,CAAC,SAAU;QACpB,MAAM,EAAE,CAAC,CAAC,SAAS,KAAK,gBAAgB;QACxC,MAAM,EAAE,YAAqB;QAC7B,SAAS,EAAE,CAAC,CAAC,SAAS;QACtB,WAAW,EAAE,CAAC,CAAC,SAAS;KACzB,CAAC,CAAC,CAAC;AACR,CAAC"}
1
+ {"version":3,"file":"bots-list-output.js","sourceRoot":"","sources":["../../src/cli/bots-list-output.ts"],"names":[],"mappings":"AA6BA,MAAM,UAAU,oBAAoB,CAClC,QAAyB,EACzB,gBAAwB;IAExB,OAAO,QAAQ,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;QAC3B,IAAI,EAAE,EAAE,CAAC,WAAW;QACpB,MAAM,EAAE,EAAE,CAAC,MAAM;QACjB,MAAM,EAAE,EAAE,CAAC,SAAS,KAAK,gBAAgB;QACzC,MAAM,EAAE,EAAE,CAAC,MAAM;QACjB,SAAS,EAAE,EAAE,CAAC,SAAS;QACvB,WAAW,EAAE,EAAE,CAAC,SAAS,IAAI,IAAI;QACjC,UAAU,EAAE,EAAE,CAAC,UAAU,IAAI,IAAI;QACjC,WAAW,EAAE,EAAE,CAAC,WAAW;QAC3B,WAAW,EAAE,EAAE,CAAC,WAAW;QAC3B,aAAa,EAAE,EAAE,CAAC,aAAa;KAChC,CAAC,CAAC,CAAC;AACN,CAAC;AAED,MAAM,UAAU,0BAA0B,CACxC,UAAiC,EACjC,gBAAwB;IAExB,OAAO,UAAU;SACd,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;SAC1B,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QACX,IAAI,EAAE,CAAC,CAAC,OAAO,IAAI,CAAC,CAAC,KAAK;QAC1B,MAAM,EAAE,CAAC,CAAC,SAAU;QACpB,MAAM,EAAE,CAAC,CAAC,SAAS,KAAK,gBAAgB;QACxC,MAAM,EAAE,YAAqB;QAC7B,SAAS,EAAE,CAAC,CAAC,SAAS;QACtB,WAAW,EAAE,CAAC,CAAC,SAAS;QACxB,wEAAwE;QACxE,UAAU,EAAE,IAAI;QAChB,WAAW,EAAE,KAAK;QAClB,WAAW,EAAE,CAAC,CAAC,SAAS,KAAK,gBAAgB;QAC7C,aAAa,EAAE,CAAC,CAAC,CAAC,SAAS,KAAK,gBAAgB,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,UAAU,CAAwB;KAC/F,CAAC,CAAC,CAAC;AACR,CAAC"}
@@ -16,26 +16,6 @@ export interface SlashCommandInvocation {
16
16
  content: string;
17
17
  }
18
18
  export { validateWorkingDir };
19
- /**
20
- * Resolve a non-numeric `/repo <arg>` into a concrete repo path + display name.
21
- * `arg` is either a path (absolute or relative) or a first-level project name
22
- * under one of the bot's scan dirs — letting the user skip the selection card.
23
- *
24
- * Resolution:
25
- * 1. Build candidate absolute paths — absolute / `~` taken as-is; relative or
26
- * bare names resolved against each scan dir, then the daemon cwd (mirrors
27
- * how the card's project list is rooted).
28
- * 2. Prefer a candidate matching a scanned git project (carries a branch label).
29
- * 3. For a bare name, also match a scanned project by basename (covers projects
30
- * nested deeper than the scan-dir top level).
31
- * 4. Fall back to any existing directory — lenient like `/cd`, whose trust model
32
- * is "owner explicitly chose a dir"; the CLI already runs with full FS access.
33
- * Returns null when nothing resolves to an existing directory.
34
- */
35
- export declare function resolveRepoSelection(repoArg: string, scanDirs: string[]): {
36
- path: string;
37
- displayName: string;
38
- } | null;
39
19
  /**
40
20
  * Parse a force-topic invocation: `/t [prompt]` or `/topic [prompt]`.
41
21
  *
@@ -1 +1 @@
1
- {"version":3,"file":"command-handler.d.ts","sourceRoot":"","sources":["../../src/core/command-handler.ts"],"names":[],"mappings":"AAkBA,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EAAkD,KAAK,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAK/G,OAAO,KAAK,EAAE,WAAW,EAAkB,MAAM,aAAa,CAAC;AAE/D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAKhD,eAAO,MAAM,eAAe,aAAoJ,CAAC;AAEjL;;;;;;GAMG;AACH,eAAO,MAAM,oBAAoB,aAO/B,CAAC;AAIH,MAAM,WAAW,sBAAsB;IACrC,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;CACjB;AAMD,OAAO,EAAE,kBAAkB,EAAE,CAAC;AAE9B;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,EAAE,GACjB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CA0C9C;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,MAAM,GAAG;IAAE,MAAM,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAKpF;AAED;;;;mCAImC;AACnC,wBAAgB,2BAA2B,CAAC,OAAO,EAAE,MAAM,GAAG,sBAAsB,GAAG,IAAI,CAqB1F;AA8DD,MAAM,WAAW,kBAAkB;IACjC,cAAc,EAAE,GAAG,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;IAC3C,YAAY,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IACzG,cAAc,EAAE,MAAM,MAAM,CAAC;IAC7B,YAAY,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,gCAAgC,EAAE,WAAW,EAAE,CAAC,CAAC;CACnF;AAmLD,wBAAsB,aAAa,CACjC,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,WAAW,EACpB,IAAI,EAAE,kBAAkB,EACxB,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC,IAAI,CAAC,CA6pBf;AAID,wBAAsB,iBAAiB,CACrC,MAAM,EAAE,gBAAgB,EACxB,EAAE,EAAE,aAAa,EACjB,IAAI,EAAE,kBAAkB,EACxB,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC,IAAI,CAAC,CA+Bf"}
1
+ {"version":3,"file":"command-handler.d.ts","sourceRoot":"","sources":["../../src/core/command-handler.ts"],"names":[],"mappings":"AAmBA,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EAAkD,KAAK,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAM/G,OAAO,KAAK,EAAE,WAAW,EAAkB,MAAM,aAAa,CAAC;AAE/D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAKhD,eAAO,MAAM,eAAe,aAA6J,CAAC;AAE1L;;;;;;GAMG;AACH,eAAO,MAAM,oBAAoB,aAO/B,CAAC;AAIH,MAAM,WAAW,sBAAsB;IACrC,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;CACjB;AAMD,OAAO,EAAE,kBAAkB,EAAE,CAAC;AAE9B;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,MAAM,GAAG;IAAE,MAAM,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAKpF;AAED;;;;mCAImC;AACnC,wBAAgB,2BAA2B,CAAC,OAAO,EAAE,MAAM,GAAG,sBAAsB,GAAG,IAAI,CAqB1F;AA8DD,MAAM,WAAW,kBAAkB;IACjC,cAAc,EAAE,GAAG,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;IAC3C,YAAY,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IACzG,cAAc,EAAE,MAAM,MAAM,CAAC;IAC7B,YAAY,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,gCAAgC,EAAE,WAAW,EAAE,CAAC,CAAC;CACnF;AAoOD,wBAAsB,aAAa,CACjC,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,WAAW,EACpB,IAAI,EAAE,kBAAkB,EACxB,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC,IAAI,CAAC,CAypBf;AAID,wBAAsB,iBAAiB,CACrC,MAAM,EAAE,gBAAgB,EACxB,EAAE,EAAE,aAAa,EACjB,IAAI,EAAE,kBAAkB,EACxB,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC,IAAI,CAAC,CA+Bf"}
@@ -2,17 +2,18 @@
2
2
  * Command handler — processes /slash commands from users.
3
3
  * Extracted from daemon.ts for modularity.
4
4
  */
5
- import { existsSync, readFileSync, statSync } from 'node:fs';
6
- import { join, resolve, basename } from 'node:path';
5
+ import { existsSync, readFileSync } from 'node:fs';
6
+ import { join } from 'node:path';
7
7
  import { config } from '../config.js';
8
8
  import { getBot, getAllBots, getBotOpenId } from '../bot-registry.js';
9
9
  import * as sessionStore from '../services/session-store.js';
10
10
  import * as scheduleStore from '../services/schedule-store.js';
11
11
  import * as scheduler from './scheduler.js';
12
- import { scanMultipleProjects, describeProjectDir } from '../services/project-scanner.js';
12
+ import { scanMultipleProjects } from '../services/project-scanner.js';
13
13
  import { buildRepoSelectCard, buildAdoptSelectCard, buildSessionClosedCard, getCliDisplayName } from '../im/lark/card-builder.js';
14
14
  import { createCliAdapterSync } from '../adapters/cli/registry.js';
15
- import { deleteMessage, listChatBotMembers } from '../im/lark/client.js';
15
+ import { deleteMessage, listChatBotMembers, resolveUserUnionId } from '../im/lark/client.js';
16
+ import { claimPairing } from '../services/pairing-store.js';
16
17
  import { logger } from '../utils/logger.js';
17
18
  import { killWorker, forkWorker, forkAdoptWorker, getCurrentCliVersion } from './worker-pool.js';
18
19
  import { expandHome, getSessionWorkingDir, getProjectScanDirs, rememberLastCliInput } from './session-manager.js';
@@ -21,11 +22,12 @@ import { discoverAdoptableSessions, validateAdoptTarget } from './session-discov
21
22
  import { generateAuthUrl, getTokenStatus } from '../utils/user-token.js';
22
23
  import { bindOncall, unbindOncall, getOncallStatus } from '../services/oncall-store.js';
23
24
  import { invalidWorkingDirs } from '../utils/working-dir.js';
24
- import { resolveRoleFile, writeRoleFile, deleteRoleFile } from './role-resolver.js';
25
+ import { writeRoleFile, deleteRoleFile, resolveRole, resolveTeamRoleFile, writeTeamRoleFile, deleteTeamRoleFile } from './role-resolver.js';
26
+ import { getBotCapability, setBotCapability, clearBotCapability } from '../services/bot-profile-store.js';
25
27
  import { sessionKey, sessionAnchorId } from './types.js';
26
28
  import { t, localeForBot } from '../i18n/index.js';
27
29
  // ─── Exported constants ──────────────────────────────────────────────────────
28
- export const DAEMON_COMMANDS = new Set(['/close', '/restart', '/status', '/help', '/cd', '/repo', '/skip', '/schedule', '/role', '/login', '/adopt', '/oncall', '/group', '/g']);
30
+ export const DAEMON_COMMANDS = new Set(['/close', '/restart', '/status', '/help', '/cd', '/repo', '/skip', '/schedule', '/role', '/pair', '/login', '/adopt', '/oncall', '/group', '/g']);
29
31
  /**
30
32
  * Slash commands that are forwarded verbatim to the underlying CLI (e.g.
31
33
  * Claude Code's `/compact`, `/model`, `/usage`). The daemon does NOT handle
@@ -45,67 +47,6 @@ const MULTILINE_COMMANDS = new Set(['/schedule', '/role']);
45
47
  // `validateWorkingDir` now lives in ./working-dir.js (leaf module the CLI can
46
48
  // import without the daemon graph); re-exported here for existing callers.
47
49
  export { validateWorkingDir };
48
- /**
49
- * Resolve a non-numeric `/repo <arg>` into a concrete repo path + display name.
50
- * `arg` is either a path (absolute or relative) or a first-level project name
51
- * under one of the bot's scan dirs — letting the user skip the selection card.
52
- *
53
- * Resolution:
54
- * 1. Build candidate absolute paths — absolute / `~` taken as-is; relative or
55
- * bare names resolved against each scan dir, then the daemon cwd (mirrors
56
- * how the card's project list is rooted).
57
- * 2. Prefer a candidate matching a scanned git project (carries a branch label).
58
- * 3. For a bare name, also match a scanned project by basename (covers projects
59
- * nested deeper than the scan-dir top level).
60
- * 4. Fall back to any existing directory — lenient like `/cd`, whose trust model
61
- * is "owner explicitly chose a dir"; the CLI already runs with full FS access.
62
- * Returns null when nothing resolves to an existing directory.
63
- */
64
- export function resolveRepoSelection(repoArg, scanDirs) {
65
- const existingScanDirs = scanDirs.filter((d) => existsSync(d));
66
- const projects = existingScanDirs.length > 0 ? scanMultipleProjects(existingScanDirs) : [];
67
- const isExplicitPath = repoArg.startsWith('/') ||
68
- repoArg.startsWith('~') ||
69
- repoArg.startsWith('.') ||
70
- repoArg.includes('/');
71
- const candidates = [];
72
- if (repoArg.startsWith('/') || repoArg.startsWith('~')) {
73
- candidates.push(resolve(expandHome(repoArg)));
74
- }
75
- else {
76
- for (const d of scanDirs)
77
- candidates.push(resolve(d, repoArg));
78
- candidates.push(resolve(expandHome(repoArg))); // daemon-cwd fallback (matches /cd)
79
- }
80
- // 1) Exact scanned-project match — preferred, gives the "name (branch)" label.
81
- for (const cand of candidates) {
82
- const proj = projects.find((p) => resolve(p.path) === cand);
83
- if (proj)
84
- return { path: proj.path, displayName: `${proj.name} (${proj.branch})` };
85
- }
86
- // 2) Bare name → match a scanned project by basename.
87
- if (!isExplicitPath) {
88
- const byName = projects.find((p) => p.name === repoArg);
89
- if (byName)
90
- return { path: byName.path, displayName: `${byName.name} (${byName.branch})` };
91
- }
92
- // 3) Lenient fallback: any existing directory. Label it with a git ref when
93
- // it's a repo (covers explicit paths outside the scan roots), else basename.
94
- for (const cand of candidates) {
95
- try {
96
- if (!statSync(cand).isDirectory())
97
- continue;
98
- }
99
- catch {
100
- continue; // missing / not a dir — try next candidate
101
- }
102
- const desc = describeProjectDir(cand);
103
- return desc
104
- ? { path: cand, displayName: `${desc.name} (${desc.branch})` }
105
- : { path: cand, displayName: basename(cand) };
106
- }
107
- return null;
108
- }
109
50
  /**
110
51
  * Parse a force-topic invocation: `/t [prompt]` or `/topic [prompt]`.
111
52
  *
@@ -218,16 +159,69 @@ function invalidConfiguredWorkingDirs(ds, larkAppId) {
218
159
  });
219
160
  }
220
161
  // ─── Schedule command ────────────────────────────────────────────────────────
221
- async function handleRoleCommand(args, rootId, chatId, larkAppId, deps) {
162
+ async function handleRoleCommand(args, rootId, chatId, larkAppId, senderId, deps) {
222
163
  const sessionReply = (rid, content, msgType) => deps.sessionReply(rid, content, msgType, larkAppId);
223
164
  const trimmed = args.trim();
224
165
  const loc = localeForBot(larkAppId);
225
- // /role show current role
166
+ const dataDir = config.session.dataDir;
167
+ // /role team [...] — manage the team-level (per-bot, cross-chat) role
168
+ const teamMatch = trimmed.match(/^team\b([\s\S]*)$/);
169
+ if (teamMatch) {
170
+ const teamArgs = teamMatch[1].trim();
171
+ const teamSet = teamArgs.match(/^set\s+([\s\S]+)/);
172
+ if (teamSet) {
173
+ const content = teamSet[1].trim();
174
+ if (!content) {
175
+ await sessionReply(rootId, t('role.set_empty', undefined, loc));
176
+ return;
177
+ }
178
+ writeTeamRoleFile(larkAppId, content);
179
+ await sessionReply(rootId, t('role.team_saved', { bytes: Buffer.byteLength(content, 'utf-8'), max: 4096 }, loc));
180
+ return;
181
+ }
182
+ if (teamArgs === 'delete' || teamArgs === '删除') {
183
+ await sessionReply(rootId, deleteTeamRoleFile(larkAppId) ? t('role.team_deleted', undefined, loc) : t('role.team_nothing', undefined, loc));
184
+ return;
185
+ }
186
+ const content = resolveTeamRoleFile(larkAppId);
187
+ if (content) {
188
+ await sessionReply(rootId, `${t('role.team_current', undefined, loc)}\n\`\`\`markdown\n${content}\n\`\`\`\n${t('role.byte_count', { bytes: Buffer.byteLength(content, 'utf-8'), max: 4096 }, loc)}`);
189
+ }
190
+ else {
191
+ await sessionReply(rootId, t('role.team_empty', undefined, loc));
192
+ }
193
+ return;
194
+ }
195
+ // /role cap [...] — manage the short capability label shown in the roster
196
+ const capMatch = trimmed.match(/^cap\b([\s\S]*)$/);
197
+ if (capMatch) {
198
+ const capArgs = capMatch[1].trim();
199
+ const capSet = capArgs.match(/^set\s+([\s\S]+)/);
200
+ if (capSet) {
201
+ const label = capSet[1].trim();
202
+ if (!label) {
203
+ await sessionReply(rootId, t('role.cap_set_empty', undefined, loc));
204
+ return;
205
+ }
206
+ setBotCapability(dataDir, larkAppId, label, senderId);
207
+ await sessionReply(rootId, t('role.cap_saved', { cap: getBotCapability(dataDir, larkAppId) ?? label }, loc));
208
+ return;
209
+ }
210
+ if (capArgs === 'clear' || capArgs === '清除') {
211
+ await sessionReply(rootId, clearBotCapability(dataDir, larkAppId) ? t('role.cap_cleared', undefined, loc) : t('role.cap_empty', undefined, loc));
212
+ return;
213
+ }
214
+ const cap = getBotCapability(dataDir, larkAppId);
215
+ await sessionReply(rootId, cap ? t('role.cap_current', { cap }, loc) : t('role.cap_empty', undefined, loc));
216
+ return;
217
+ }
218
+ // /role → show the EFFECTIVE role + where it comes from (chat override > team > none)
226
219
  if (!trimmed) {
227
- const content = resolveRoleFile(larkAppId, chatId);
220
+ const { content, source } = resolveRole(larkAppId, chatId);
228
221
  if (content) {
229
222
  const len = Buffer.byteLength(content, 'utf-8');
230
- await sessionReply(rootId, `${t('role.current', undefined, loc)}\n\`\`\`markdown\n${content}\n\`\`\`\n${t('role.byte_count', { bytes: len, max: 4096 }, loc)}`);
223
+ const srcLabel = source === 'chat' ? t('role.src_chat', undefined, loc) : t('role.src_team', undefined, loc);
224
+ await sessionReply(rootId, `${t('role.current', undefined, loc)} ${srcLabel}\n\`\`\`markdown\n${content}\n\`\`\`\n${t('role.byte_count', { bytes: len, max: 4096 }, loc)}`);
231
225
  }
232
226
  else {
233
227
  await sessionReply(rootId, t('role.empty', undefined, loc));
@@ -458,11 +452,20 @@ export async function handleCommand(cmd, rootId, message, deps, larkAppId) {
458
452
  }
459
453
  case '/repo': {
460
454
  const repoArg = message.content.replace(/^\/repo\s*/, '').trim();
461
- // Shared commit path for an already-resolved repo: update the session's
462
- // working dir, then either fork into the pending CLI (first spawn) or
463
- // close + recreate the session (mid-session switch). Used by both the
464
- // numeric `/repo <N>` form and the `/repo <path|name>` form.
465
- const commitRepoSelection = async (selectedPath, displayName, how) => {
455
+ const repoIndex = repoArg ? parseInt(repoArg, 10) : NaN;
456
+ if (!isNaN(repoIndex) && ds) {
457
+ const cached = lastRepoScan.get(ds.chatId);
458
+ if (!cached || cached.length === 0) {
459
+ await sessionReply(rootId, t('cmd.repo.no_prior_scan', undefined, loc));
460
+ break;
461
+ }
462
+ if (repoIndex < 1 || repoIndex > cached.length) {
463
+ await sessionReply(rootId, t('cmd.repo.index_out_of_range', { max: cached.length }, loc));
464
+ break;
465
+ }
466
+ const project = cached[repoIndex - 1];
467
+ const selectedPath = project.path;
468
+ const displayName = `${project.name} (${project.branch})`;
466
469
  ds.workingDir = selectedPath;
467
470
  ds.session.workingDir = selectedPath;
468
471
  sessionStore.updateSession(ds.session);
@@ -500,33 +503,7 @@ export async function handleCommand(cmd, rootId, message, deps, larkAppId) {
500
503
  deleteMessage(ds.larkAppId, ds.repoCardMessageId);
501
504
  ds.repoCardMessageId = undefined;
502
505
  }
503
- logger.info(`[${logTag}] Repo selected via ${how}: ${selectedPath}`);
504
- };
505
- // Numeric arg → pick by 1-based index from the last scan.
506
- if (repoArg && ds && /^\d+$/.test(repoArg)) {
507
- const repoIndex = parseInt(repoArg, 10);
508
- const cached = lastRepoScan.get(ds.chatId);
509
- if (!cached || cached.length === 0) {
510
- await sessionReply(rootId, t('cmd.repo.no_prior_scan', undefined, loc));
511
- break;
512
- }
513
- if (repoIndex < 1 || repoIndex > cached.length) {
514
- await sessionReply(rootId, t('cmd.repo.index_out_of_range', { max: cached.length }, loc));
515
- break;
516
- }
517
- const project = cached[repoIndex - 1];
518
- await commitRepoSelection(project.path, `${project.name} (${project.branch})`, `/repo ${repoIndex}`);
519
- break;
520
- }
521
- // Non-numeric arg → a path (relative/absolute) or first-level project
522
- // name under workingDir; resolve it directly and skip the card.
523
- if (repoArg && ds) {
524
- const resolved = resolveRepoSelection(repoArg, getProjectScanDirs(ds));
525
- if (!resolved) {
526
- await sessionReply(rootId, t('cmd.repo.path_not_found', { arg: repoArg }, loc));
527
- break;
528
- }
529
- await commitRepoSelection(resolved.path, resolved.displayName, `/repo ${repoArg}`);
506
+ logger.info(`[${logTag}] Repo selected via /repo ${repoIndex}: ${selectedPath}`);
530
507
  break;
531
508
  }
532
509
  if (ds?.worker && !ds.worker.killed) {
@@ -627,10 +604,35 @@ export async function handleCommand(cmd, rootId, message, deps, larkAppId) {
627
604
  break;
628
605
  }
629
606
  const roleArgs = message.content.replace(/^\/role\s*/, '');
630
- await handleRoleCommand(roleArgs, rootId, chatId, larkAppId, deps);
607
+ await handleRoleCommand(roleArgs, rootId, chatId, larkAppId, message.senderId, deps);
631
608
  logger.info(`[${logTag}] Role command handled`);
632
609
  break;
633
610
  }
611
+ case '/pair': {
612
+ const code = message.content.replace(/^\/pair\s*/, '').trim();
613
+ if (!larkAppId) {
614
+ await sessionReply(rootId, t('role.no_chat', undefined, loc));
615
+ break;
616
+ }
617
+ if (!code) {
618
+ await sessionReply(rootId, t('pair.usage', undefined, loc));
619
+ break;
620
+ }
621
+ // Resolve the sender's canonical union_id (best-effort) so the web
622
+ // session is keyed stably across apps; degrade to open_id-only.
623
+ const who = await resolveUserUnionId(larkAppId, message.senderId);
624
+ const result = claimPairing(config.session.dataDir, code, { openId: message.senderId, unionId: who.unionId, name: who.name, larkAppId });
625
+ if (result.ok)
626
+ await sessionReply(rootId, t('pair.ok', undefined, loc));
627
+ else if (result.reason === 'expired')
628
+ await sessionReply(rootId, t('pair.expired', undefined, loc));
629
+ else if (result.reason === 'already_claimed')
630
+ await sessionReply(rootId, t('pair.already', undefined, loc));
631
+ else
632
+ await sessionReply(rootId, t('pair.not_found', undefined, loc));
633
+ logger.info(`[${logTag}] Pair command handled: ${result.ok ? 'ok' : result.reason}`);
634
+ break;
635
+ }
634
636
  case '/login': {
635
637
  const subCmd = message.content.replace(/^\/login\s*/, '').trim();
636
638
  if (subCmd === 'status' || subCmd === '状态') {
@@ -950,7 +952,6 @@ export async function handleCommand(cmd, rootId, message, deps, larkAppId) {
950
952
  t('help.cd', { cliName }, loc),
951
953
  t('help.repo_list', undefined, loc),
952
954
  t('help.repo_n', undefined, loc),
953
- t('help.repo_path', undefined, loc),
954
955
  t('help.status', undefined, loc),
955
956
  '',
956
957
  t('help.heading_passthrough', { cliName }, loc),