botmux 2.40.0-canary.0 → 2.40.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 +1 -0
  2. package/README.md +1 -0
  3. package/dist/adapters/hook-installer.d.ts.map +1 -1
  4. package/dist/adapters/hook-installer.js +22 -2
  5. package/dist/adapters/hook-installer.js.map +1 -1
  6. package/dist/cli/bots-list-output.d.ts +0 -8
  7. package/dist/cli/bots-list-output.d.ts.map +1 -1
  8. package/dist/cli/bots-list-output.js +0 -9
  9. package/dist/cli/bots-list-output.js.map +1 -1
  10. package/dist/core/command-handler.d.ts +20 -0
  11. package/dist/core/command-handler.d.ts.map +1 -1
  12. package/dist/core/command-handler.js +105 -106
  13. package/dist/core/command-handler.js.map +1 -1
  14. package/dist/core/dashboard-ipc-server.d.ts +0 -2
  15. package/dist/core/dashboard-ipc-server.d.ts.map +1 -1
  16. package/dist/core/dashboard-ipc-server.js +0 -56
  17. package/dist/core/dashboard-ipc-server.js.map +1 -1
  18. package/dist/core/role-resolver.d.ts +1 -17
  19. package/dist/core/role-resolver.d.ts.map +1 -1
  20. package/dist/core/role-resolver.js +10 -64
  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 +9 -14
  24. package/dist/core/session-manager.js.map +1 -1
  25. package/dist/daemon.d.ts.map +1 -1
  26. package/dist/daemon.js +19 -27
  27. package/dist/daemon.js.map +1 -1
  28. package/dist/dashboard/web/app.js +0 -3
  29. package/dist/dashboard/web/app.js.map +1 -1
  30. package/dist/dashboard-web/app.js +244 -310
  31. package/dist/dashboard-web/index.html +0 -1
  32. package/dist/dashboard.js +1 -149
  33. package/dist/dashboard.js.map +1 -1
  34. package/dist/i18n/en.d.ts.map +1 -1
  35. package/dist/i18n/en.js +7 -22
  36. package/dist/i18n/en.js.map +1 -1
  37. package/dist/i18n/zh.d.ts.map +1 -1
  38. package/dist/i18n/zh.js +7 -22
  39. package/dist/i18n/zh.js.map +1 -1
  40. package/dist/im/lark/client.d.ts +0 -21
  41. package/dist/im/lark/client.d.ts.map +1 -1
  42. package/dist/im/lark/client.js +18 -86
  43. package/dist/im/lark/client.js.map +1 -1
  44. package/dist/services/group-creator.d.ts +0 -6
  45. package/dist/services/group-creator.d.ts.map +1 -1
  46. package/dist/services/group-creator.js +1 -10
  47. package/dist/services/group-creator.js.map +1 -1
  48. package/dist/services/groups-store.d.ts +0 -11
  49. package/dist/services/groups-store.d.ts.map +1 -1
  50. package/dist/services/groups-store.js +0 -27
  51. package/dist/services/groups-store.js.map +1 -1
  52. package/dist/services/project-scanner.d.ts +10 -0
  53. package/dist/services/project-scanner.d.ts.map +1 -1
  54. package/dist/services/project-scanner.js +11 -0
  55. package/dist/services/project-scanner.js.map +1 -1
  56. package/dist/skills/definitions.d.ts.map +1 -1
  57. package/dist/skills/definitions.js +10 -64
  58. package/dist/skills/definitions.js.map +1 -1
  59. package/dist/workflows/events/payloads.d.ts +2 -2
  60. package/dist/workflows/events/schema.d.ts +8 -8
  61. package/package.json +1 -1
  62. package/dist/core/trigger-session.d.ts +0 -9
  63. package/dist/core/trigger-session.d.ts.map +0 -1
  64. package/dist/core/trigger-session.js +0 -158
  65. package/dist/core/trigger-session.js.map +0 -1
  66. package/dist/dashboard/connector-api.d.ts +0 -3
  67. package/dist/dashboard/connector-api.d.ts.map +0 -1
  68. package/dist/dashboard/connector-api.js +0 -362
  69. package/dist/dashboard/connector-api.js.map +0 -1
  70. package/dist/dashboard/federation-api.d.ts +0 -31
  71. package/dist/dashboard/federation-api.d.ts.map +0 -1
  72. package/dist/dashboard/federation-api.js +0 -256
  73. package/dist/dashboard/federation-api.js.map +0 -1
  74. package/dist/dashboard/federation-spoke-api.d.ts +0 -41
  75. package/dist/dashboard/federation-spoke-api.d.ts.map +0 -1
  76. package/dist/dashboard/federation-spoke-api.js +0 -398
  77. package/dist/dashboard/federation-spoke-api.js.map +0 -1
  78. package/dist/dashboard/pairing-api.d.ts +0 -19
  79. package/dist/dashboard/pairing-api.d.ts.map +0 -1
  80. package/dist/dashboard/pairing-api.js +0 -83
  81. package/dist/dashboard/pairing-api.js.map +0 -1
  82. package/dist/dashboard/team-group.d.ts +0 -18
  83. package/dist/dashboard/team-group.d.ts.map +0 -1
  84. package/dist/dashboard/team-group.js +0 -7
  85. package/dist/dashboard/team-group.js.map +0 -1
  86. package/dist/dashboard/team-page.d.ts +0 -8
  87. package/dist/dashboard/team-page.d.ts.map +0 -1
  88. package/dist/dashboard/team-page.js +0 -480
  89. package/dist/dashboard/team-page.js.map +0 -1
  90. package/dist/dashboard/team-routes.d.ts +0 -30
  91. package/dist/dashboard/team-routes.d.ts.map +0 -1
  92. package/dist/dashboard/team-routes.js +0 -458
  93. package/dist/dashboard/team-routes.js.map +0 -1
  94. package/dist/dashboard/trigger-api.d.ts +0 -13
  95. package/dist/dashboard/trigger-api.d.ts.map +0 -1
  96. package/dist/dashboard/trigger-api.js +0 -77
  97. package/dist/dashboard/trigger-api.js.map +0 -1
  98. package/dist/dashboard/web/team-federation.d.ts +0 -2
  99. package/dist/dashboard/web/team-federation.d.ts.map +0 -1
  100. package/dist/dashboard/web/team-federation.js +0 -304
  101. package/dist/dashboard/web/team-federation.js.map +0 -1
  102. package/dist/dashboard/webhook-routes.d.ts +0 -19
  103. package/dist/dashboard/webhook-routes.d.ts.map +0 -1
  104. package/dist/dashboard/webhook-routes.js +0 -321
  105. package/dist/dashboard/webhook-routes.js.map +0 -1
  106. package/dist/services/bot-owner-store.d.ts +0 -28
  107. package/dist/services/bot-owner-store.d.ts.map +0 -1
  108. package/dist/services/bot-owner-store.js +0 -82
  109. package/dist/services/bot-owner-store.js.map +0 -1
  110. package/dist/services/bot-profile-store.d.ts +0 -16
  111. package/dist/services/bot-profile-store.d.ts.map +0 -1
  112. package/dist/services/bot-profile-store.js +0 -98
  113. package/dist/services/bot-profile-store.js.map +0 -1
  114. package/dist/services/connector-store.d.ts +0 -63
  115. package/dist/services/connector-store.d.ts.map +0 -1
  116. package/dist/services/connector-store.js +0 -79
  117. package/dist/services/connector-store.js.map +0 -1
  118. package/dist/services/deployment-identity.d.ts +0 -9
  119. package/dist/services/deployment-identity.d.ts.map +0 -1
  120. package/dist/services/deployment-identity.js +0 -47
  121. package/dist/services/deployment-identity.js.map +0 -1
  122. package/dist/services/federation-membership-store.d.ts +0 -23
  123. package/dist/services/federation-membership-store.d.ts.map +0 -1
  124. package/dist/services/federation-membership-store.js +0 -66
  125. package/dist/services/federation-membership-store.js.map +0 -1
  126. package/dist/services/federation-roster.d.ts +0 -45
  127. package/dist/services/federation-roster.d.ts.map +0 -1
  128. package/dist/services/federation-roster.js +0 -51
  129. package/dist/services/federation-roster.js.map +0 -1
  130. package/dist/services/federation-store.d.ts +0 -65
  131. package/dist/services/federation-store.d.ts.map +0 -1
  132. package/dist/services/federation-store.js +0 -125
  133. package/dist/services/federation-store.js.map +0 -1
  134. package/dist/services/invite-store.d.ts +0 -28
  135. package/dist/services/invite-store.d.ts.map +0 -1
  136. package/dist/services/invite-store.js +0 -85
  137. package/dist/services/invite-store.js.map +0 -1
  138. package/dist/services/pairing-store.d.ts +0 -47
  139. package/dist/services/pairing-store.d.ts.map +0 -1
  140. package/dist/services/pairing-store.js +0 -132
  141. package/dist/services/pairing-store.js.map +0 -1
  142. package/dist/services/team-roster.d.ts +0 -28
  143. package/dist/services/team-roster.d.ts.map +0 -1
  144. package/dist/services/team-roster.js +0 -58
  145. package/dist/services/team-roster.js.map +0 -1
  146. package/dist/services/team-store.d.ts +0 -54
  147. package/dist/services/team-store.d.ts.map +0 -1
  148. package/dist/services/team-store.js +0 -156
  149. package/dist/services/team-store.js.map +0 -1
  150. package/dist/services/trigger-log-store.d.ts +0 -46
  151. package/dist/services/trigger-log-store.d.ts.map +0 -1
  152. package/dist/services/trigger-log-store.js +0 -132
  153. package/dist/services/trigger-log-store.js.map +0 -1
  154. package/dist/services/trigger-types.d.ts +0 -57
  155. package/dist/services/trigger-types.d.ts.map +0 -1
  156. package/dist/services/trigger-types.js +0 -28
  157. package/dist/services/trigger-types.js.map +0 -1
  158. package/dist/services/web-session-store.d.ts +0 -28
  159. package/dist/services/web-session-store.d.ts.map +0 -1
  160. package/dist/services/web-session-store.js +0 -84
  161. package/dist/services/web-session-store.js.map +0 -1
  162. package/dist/services/webhook-key.d.ts +0 -16
  163. package/dist/services/webhook-key.d.ts.map +0 -1
  164. package/dist/services/webhook-key.js +0 -123
  165. package/dist/services/webhook-key.js.map +0 -1
  166. package/dist/services/webhook-lifecycle-extractors.d.ts +0 -15
  167. package/dist/services/webhook-lifecycle-extractors.d.ts.map +0 -1
  168. package/dist/services/webhook-lifecycle-extractors.js +0 -59
  169. package/dist/services/webhook-lifecycle-extractors.js.map +0 -1
  170. package/dist/services/webhook-lifecycle-store.d.ts +0 -45
  171. package/dist/services/webhook-lifecycle-store.d.ts.map +0 -1
  172. package/dist/services/webhook-lifecycle-store.js +0 -159
  173. package/dist/services/webhook-lifecycle-store.js.map +0 -1
  174. package/dist/workflows/trigger-from-envelope.d.ts +0 -13
  175. package/dist/workflows/trigger-from-envelope.d.ts.map +0 -1
  176. package/dist/workflows/trigger-from-envelope.js +0 -67
  177. package/dist/workflows/trigger-from-envelope.js.map +0 -1
package/README.en.md CHANGED
@@ -308,6 +308,7 @@ 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 |
311
312
  | `/skip` | Skip the repo selector card, start the session in the default dir |
312
313
  | `/cd <path>` | Change working directory and restart the CLI process |
313
314
  | `/status` | Show session info (uptime, terminal URL, etc.) |
package/README.md CHANGED
@@ -302,6 +302,7 @@ botmux autostart enable
302
302
  |------|------|
303
303
  | `/repo` | 显示项目选择卡片(交互式下拉 + 文本列表) |
304
304
  | `/repo <N>` | 切换到上次扫描的第 N 个项目 |
305
+ | `/repo <路径\|项目名>` | 跳过选择卡片,直接指定路径(相对/绝对)或 workingDir 下的一级项目名 |
305
306
  | `/skip` | 跳过仓库选择卡片,直接用默认目录开启会话 |
306
307
  | `/cd <路径>` | 切换工作目录并重启 CLI 进程 |
307
308
  | `/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;AAoKD;;;;;;;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;AA0LD;;;;;;;GAOG;AACH,wBAAgB,WAAW,CACzB,KAAK,EAAE,MAAM,EACb,WAAW,EAAE,iBAAiB,EAC9B,WAAW,EAAE,MAAM,GAClB,IAAI,CAoBN"}
@@ -40,9 +40,29 @@ function writeIfChanged(filePath, content) {
40
40
  throw new Error(`写入 ${filePath} 失败:${err.message}`);
41
41
  }
42
42
  }
43
- /** 判断某个 hook group 是否是 botmux ask hook(用于幂等替换)。 */
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
+ */
44
61
  function isBotmuxAskHookGroup(group, hookCommand) {
45
- return group.hooks.some((e) => e.type === 'command' && e.command === 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))));
46
66
  }
47
67
  function removeBotmuxAskHookGroups(hooks, eventName, hookCommand) {
48
68
  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,14 +15,6 @@ 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';
26
18
  };
27
19
  export declare function formatChatBotsForCli(chatBots: ChatBotMember[], currentLarkAppId: string): BotListOutputEntry[];
28
20
  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;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"}
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"}
@@ -6,10 +6,6 @@ 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,
13
9
  }));
14
10
  }
15
11
  export function formatBotInfoEntriesForCli(botEntries, currentLarkAppId) {
@@ -22,11 +18,6 @@ export function formatBotInfoEntriesForCli(botEntries, currentLarkAppId) {
22
18
  source: 'configured',
23
19
  larkAppId: b.larkAppId,
24
20
  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'),
30
21
  }));
31
22
  }
32
23
  //# 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":"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"}
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"}
@@ -16,6 +16,26 @@ 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;
19
39
  /**
20
40
  * Parse a force-topic invocation: `/t [prompt]` or `/topic [prompt]`.
21
41
  *
@@ -1 +1 @@
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"}
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"}
@@ -2,18 +2,17 @@
2
2
  * Command handler — processes /slash commands from users.
3
3
  * Extracted from daemon.ts for modularity.
4
4
  */
5
- import { existsSync, readFileSync } from 'node:fs';
6
- import { join } from 'node:path';
5
+ import { existsSync, readFileSync, statSync } from 'node:fs';
6
+ import { join, resolve, basename } 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 } from '../services/project-scanner.js';
12
+ import { scanMultipleProjects, describeProjectDir } 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, resolveUserUnionId } from '../im/lark/client.js';
16
- import { claimPairing } from '../services/pairing-store.js';
15
+ import { deleteMessage, listChatBotMembers } from '../im/lark/client.js';
17
16
  import { logger } from '../utils/logger.js';
18
17
  import { killWorker, forkWorker, forkAdoptWorker, getCurrentCliVersion } from './worker-pool.js';
19
18
  import { expandHome, getSessionWorkingDir, getProjectScanDirs, rememberLastCliInput } from './session-manager.js';
@@ -22,12 +21,11 @@ import { discoverAdoptableSessions, validateAdoptTarget } from './session-discov
22
21
  import { generateAuthUrl, getTokenStatus } from '../utils/user-token.js';
23
22
  import { bindOncall, unbindOncall, getOncallStatus } from '../services/oncall-store.js';
24
23
  import { invalidWorkingDirs } from '../utils/working-dir.js';
25
- import { writeRoleFile, deleteRoleFile, resolveRole, resolveTeamRoleFile, writeTeamRoleFile, deleteTeamRoleFile } from './role-resolver.js';
26
- import { getBotCapability, setBotCapability, clearBotCapability } from '../services/bot-profile-store.js';
24
+ import { resolveRoleFile, writeRoleFile, deleteRoleFile } from './role-resolver.js';
27
25
  import { sessionKey, sessionAnchorId } from './types.js';
28
26
  import { t, localeForBot } from '../i18n/index.js';
29
27
  // ─── Exported constants ──────────────────────────────────────────────────────
30
- export const DAEMON_COMMANDS = new Set(['/close', '/restart', '/status', '/help', '/cd', '/repo', '/skip', '/schedule', '/role', '/pair', '/login', '/adopt', '/oncall', '/group', '/g']);
28
+ export const DAEMON_COMMANDS = new Set(['/close', '/restart', '/status', '/help', '/cd', '/repo', '/skip', '/schedule', '/role', '/login', '/adopt', '/oncall', '/group', '/g']);
31
29
  /**
32
30
  * Slash commands that are forwarded verbatim to the underlying CLI (e.g.
33
31
  * Claude Code's `/compact`, `/model`, `/usage`). The daemon does NOT handle
@@ -47,6 +45,67 @@ const MULTILINE_COMMANDS = new Set(['/schedule', '/role']);
47
45
  // `validateWorkingDir` now lives in ./working-dir.js (leaf module the CLI can
48
46
  // import without the daemon graph); re-exported here for existing callers.
49
47
  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
+ }
50
109
  /**
51
110
  * Parse a force-topic invocation: `/t [prompt]` or `/topic [prompt]`.
52
111
  *
@@ -159,69 +218,16 @@ function invalidConfiguredWorkingDirs(ds, larkAppId) {
159
218
  });
160
219
  }
161
220
  // ─── Schedule command ────────────────────────────────────────────────────────
162
- async function handleRoleCommand(args, rootId, chatId, larkAppId, senderId, deps) {
221
+ async function handleRoleCommand(args, rootId, chatId, larkAppId, deps) {
163
222
  const sessionReply = (rid, content, msgType) => deps.sessionReply(rid, content, msgType, larkAppId);
164
223
  const trimmed = args.trim();
165
224
  const loc = localeForBot(larkAppId);
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)
225
+ // /role show current role
219
226
  if (!trimmed) {
220
- const { content, source } = resolveRole(larkAppId, chatId);
227
+ const content = resolveRoleFile(larkAppId, chatId);
221
228
  if (content) {
222
229
  const len = Buffer.byteLength(content, 'utf-8');
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)}`);
230
+ await sessionReply(rootId, `${t('role.current', undefined, loc)}\n\`\`\`markdown\n${content}\n\`\`\`\n${t('role.byte_count', { bytes: len, max: 4096 }, loc)}`);
225
231
  }
226
232
  else {
227
233
  await sessionReply(rootId, t('role.empty', undefined, loc));
@@ -452,20 +458,11 @@ export async function handleCommand(cmd, rootId, message, deps, larkAppId) {
452
458
  }
453
459
  case '/repo': {
454
460
  const repoArg = message.content.replace(/^\/repo\s*/, '').trim();
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})`;
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) => {
469
466
  ds.workingDir = selectedPath;
470
467
  ds.session.workingDir = selectedPath;
471
468
  sessionStore.updateSession(ds.session);
@@ -503,7 +500,33 @@ export async function handleCommand(cmd, rootId, message, deps, larkAppId) {
503
500
  deleteMessage(ds.larkAppId, ds.repoCardMessageId);
504
501
  ds.repoCardMessageId = undefined;
505
502
  }
506
- logger.info(`[${logTag}] Repo selected via /repo ${repoIndex}: ${selectedPath}`);
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}`);
507
530
  break;
508
531
  }
509
532
  if (ds?.worker && !ds.worker.killed) {
@@ -604,35 +627,10 @@ export async function handleCommand(cmd, rootId, message, deps, larkAppId) {
604
627
  break;
605
628
  }
606
629
  const roleArgs = message.content.replace(/^\/role\s*/, '');
607
- await handleRoleCommand(roleArgs, rootId, chatId, larkAppId, message.senderId, deps);
630
+ await handleRoleCommand(roleArgs, rootId, chatId, larkAppId, deps);
608
631
  logger.info(`[${logTag}] Role command handled`);
609
632
  break;
610
633
  }
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
- }
636
634
  case '/login': {
637
635
  const subCmd = message.content.replace(/^\/login\s*/, '').trim();
638
636
  if (subCmd === 'status' || subCmd === '状态') {
@@ -952,6 +950,7 @@ export async function handleCommand(cmd, rootId, message, deps, larkAppId) {
952
950
  t('help.cd', { cliName }, loc),
953
951
  t('help.repo_list', undefined, loc),
954
952
  t('help.repo_n', undefined, loc),
953
+ t('help.repo_path', undefined, loc),
955
954
  t('help.status', undefined, loc),
956
955
  '',
957
956
  t('help.heading_passthrough', { cliName }, loc),