botmux 2.24.4 → 2.25.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 (61) hide show
  1. package/README.en.md +4 -2
  2. package/README.md +4 -2
  3. package/dist/adapters/cli/claude-code.js +1 -1
  4. package/dist/adapters/cli/claude-code.js.map +1 -1
  5. package/dist/adapters/cli/shared-hints.js +2 -2
  6. package/dist/adapters/cli/shared-hints.js.map +1 -1
  7. package/dist/cli/arg-utils.d.ts +11 -0
  8. package/dist/cli/arg-utils.d.ts.map +1 -0
  9. package/dist/cli/arg-utils.js +25 -0
  10. package/dist/cli/arg-utils.js.map +1 -0
  11. package/dist/cli/quoted-render.d.ts +30 -0
  12. package/dist/cli/quoted-render.d.ts.map +1 -0
  13. package/dist/cli/quoted-render.js +29 -0
  14. package/dist/cli/quoted-render.js.map +1 -0
  15. package/dist/cli.js +63 -14
  16. package/dist/cli.js.map +1 -1
  17. package/dist/core/worker-pool.d.ts.map +1 -1
  18. package/dist/core/worker-pool.js +34 -19
  19. package/dist/core/worker-pool.js.map +1 -1
  20. package/dist/daemon.d.ts.map +1 -1
  21. package/dist/daemon.js +13 -4
  22. package/dist/daemon.js.map +1 -1
  23. package/dist/im/lark/client.d.ts +1 -1
  24. package/dist/im/lark/client.d.ts.map +1 -1
  25. package/dist/im/lark/client.js +8 -5
  26. package/dist/im/lark/client.js.map +1 -1
  27. package/dist/im/lark/md-card.d.ts +21 -0
  28. package/dist/im/lark/md-card.d.ts.map +1 -1
  29. package/dist/im/lark/md-card.js +63 -0
  30. package/dist/im/lark/md-card.js.map +1 -1
  31. package/dist/im/lark/message-parser.d.ts +9 -3
  32. package/dist/im/lark/message-parser.d.ts.map +1 -1
  33. package/dist/im/lark/message-parser.js +13 -5
  34. package/dist/im/lark/message-parser.js.map +1 -1
  35. package/dist/im/lark/quote-hint.d.ts +18 -0
  36. package/dist/im/lark/quote-hint.d.ts.map +1 -0
  37. package/dist/im/lark/quote-hint.js +23 -0
  38. package/dist/im/lark/quote-hint.js.map +1 -0
  39. package/dist/services/coco-transcript.d.ts +11 -8
  40. package/dist/services/coco-transcript.d.ts.map +1 -1
  41. package/dist/services/coco-transcript.js +77 -40
  42. package/dist/services/coco-transcript.js.map +1 -1
  43. package/dist/services/codex-transcript.d.ts +26 -10
  44. package/dist/services/codex-transcript.d.ts.map +1 -1
  45. package/dist/services/codex-transcript.js +95 -30
  46. package/dist/services/codex-transcript.js.map +1 -1
  47. package/dist/skills/definitions.d.ts +4 -0
  48. package/dist/skills/definitions.d.ts.map +1 -1
  49. package/dist/skills/definitions.js +69 -12
  50. package/dist/skills/definitions.js.map +1 -1
  51. package/dist/skills/installer.d.ts +3 -1
  52. package/dist/skills/installer.d.ts.map +1 -1
  53. package/dist/skills/installer.js +18 -3
  54. package/dist/skills/installer.js.map +1 -1
  55. package/dist/types.d.ts +5 -0
  56. package/dist/types.d.ts.map +1 -1
  57. package/dist/utils/logger.d.ts +1 -1
  58. package/dist/utils/logger.js +1 -1
  59. package/dist/worker.js +78 -40
  60. package/dist/worker.js.map +1 -1
  61. package/package.json +1 -1
@@ -1,8 +1,10 @@
1
1
  /**
2
2
  * Reader for CoCo's per-session events JSONL.
3
3
  *
4
- * CoCo stores each session under:
5
- * ~/.cache/coco/sessions/<sessionId>/events.jsonl
4
+ * CoCo (Rust, `dirs` crate 选 cache dir) 的会话路径按平台分叉:
5
+ * Linux: ~/.cache/coco/sessions/<sessionId>/events.jsonl
6
+ * macOS: ~/Library/Caches/coco/sessions/<sessionId>/events.jsonl
7
+ * Windows 这里不考虑(botmux 跟 tmux 强绑,跑不了 Windows)。
6
8
  *
7
9
  * The bridge fallback only needs the original user prompt and the final
8
10
  * assistant message. Those appear as event objects containing
@@ -12,62 +14,97 @@
12
14
  * turn fingerprints against the user's prompt, not injected context.
13
15
  */
14
16
  import { existsSync, statSync, openSync, readSync, closeSync, readdirSync, readlinkSync } from 'node:fs';
15
- import { homedir } from 'node:os';
17
+ import { execSync } from 'node:child_process';
18
+ import { homedir, platform } from 'node:os';
16
19
  import { join } from 'node:path';
17
- const COCO_SESSIONS_ROOT = join(homedir(), '.cache', 'coco', 'sessions');
20
+ // macOS Rust `dirs` crate 把 cache 放在 ~/Library/Caches/,跟 Linux 的
21
+ // ~/.cache 不同。这里硬编码两条平台路径,对不上的话 adopt 完全读不到
22
+ // events.jsonl(user-visible: Lark 收不到模型回复)。
23
+ const COCO_SESSIONS_ROOT = platform() === 'darwin'
24
+ ? join(homedir(), 'Library', 'Caches', 'coco', 'sessions')
25
+ : join(homedir(), '.cache', 'coco', 'sessions');
18
26
  const SESSION_UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
27
+ const IS_LINUX = platform() === 'linux';
28
+ // substring anchor —— 同时匹配 Linux 的 `/.cache/coco/sessions/` 和 macOS 的
29
+ // `/Library/Caches/coco/sessions/` 两种路径形态。anchor 后紧跟一段 UUID 才认
30
+ // 账(matchCocoSessionPath 里 SESSION_UUID_RE 校验),避免误命中。
31
+ const COCO_SESSIONS_ANCHOR = '/coco/sessions/';
19
32
  export function cocoEventsPathForSession(sessionId) {
20
33
  return join(COCO_SESSIONS_ROOT, sessionId, 'events.jsonl');
21
34
  }
22
- /** Walk `/proc/<pid>/fd` to find which CoCo session a running CoCo process is
23
- * bound to. Unlike Codex (which keeps its rollout fd open continuously),
24
- * CoCo opens-writes-closes `events.jsonl` per event, so we look for ANY open
25
- * file under the session dir — `session.log` and `traces.jsonl` are held
26
- * open for the session's lifetime and reveal the same `<sid>` segment.
35
+ /** Find which CoCo session a running CoCo process is bound to by scanning
36
+ * its open file handles. Unlike Codex (which keeps its rollout fd open
37
+ * continuously), CoCo opens-writes-closes `events.jsonl` per event, so we
38
+ * look for ANY open file under the session dir — `session.log` and
39
+ * `traces.jsonl` are held open for the session's lifetime and reveal the
40
+ * same `<sid>` segment.
27
41
  *
28
- * procfs may report `<path> (deleted)` for a previously-unlinked file kept
29
- * alive by the open fd; strip that suffix before matching. Linux-only —
30
- * returns undefined elsewhere or when /proc lookup fails. */
42
+ * Linux: `/proc/<pid>/fd` 快路径,procfs 会把 unlinked-but-open fd 标
43
+ * ` (deleted)`,跳过它们以免读到失效 inode(曾被 e2e 清理触发)。
44
+ * macOS / BSD: `lsof -p <pid> -Fn` 兜底。macOS 上 lsof 不给 deleted 标记,
45
+ * 但 worker 端在 `codexBridgeAttach` 之前还有 `existsSync(sessionDir)` 的
46
+ * 二次校验,所以这里不会让一个失效 sid 跑死循环。 */
31
47
  export function findCocoSessionByPid(pid) {
32
48
  if (!Number.isInteger(pid) || pid <= 0)
33
49
  return undefined;
34
- if (process.platform !== 'linux')
35
- return undefined;
36
- const fdDir = `/proc/${pid}/fd`;
37
- if (!existsSync(fdDir))
38
- return undefined;
39
- let entries;
50
+ if (IS_LINUX) {
51
+ const fdDir = `/proc/${pid}/fd`;
52
+ if (existsSync(fdDir)) {
53
+ let entries;
54
+ try {
55
+ entries = readdirSync(fdDir);
56
+ }
57
+ catch {
58
+ return undefined;
59
+ }
60
+ for (const fd of entries) {
61
+ let target;
62
+ try {
63
+ target = readlinkSync(join(fdDir, fd));
64
+ }
65
+ catch {
66
+ continue;
67
+ }
68
+ // procfs 标 deleted 的 fd 跳过 —— 后面 lsof 路径上没这个保护,因
69
+ // 为 macOS lsof 不给标记;worker 端 sessionDir existsSync 兜底。
70
+ if (target.endsWith(' (deleted)'))
71
+ continue;
72
+ const hit = matchCocoSessionPath(target);
73
+ if (hit)
74
+ return hit;
75
+ }
76
+ return undefined;
77
+ }
78
+ }
79
+ let out;
40
80
  try {
41
- entries = readdirSync(fdDir);
81
+ out = execSync(`lsof -p ${pid} -Fn`, {
82
+ encoding: 'utf-8',
83
+ stdio: ['pipe', 'pipe', 'pipe'],
84
+ });
42
85
  }
43
86
  catch {
44
87
  return undefined;
45
88
  }
46
- const prefix = COCO_SESSIONS_ROOT + '/';
47
- for (const fd of entries) {
48
- let target;
49
- try {
50
- target = readlinkSync(join(fdDir, fd));
51
- }
52
- catch {
89
+ for (const line of out.split('\n')) {
90
+ if (!line.startsWith('n/'))
53
91
  continue;
54
- }
55
- // Skip handles whose backing file has been unlinked. procfs marks these
56
- // with a literal " (deleted)" suffix. Returning a sid from a deleted
57
- // session dir lets adopt run forever waiting on an events.jsonl that
58
- // CoCo writes to a dangling inode — empirically observed when an e2e
59
- // test wiped the session dir without restarting CoCo.
60
- if (target.endsWith(' (deleted)'))
61
- continue;
62
- if (!target.startsWith(prefix))
63
- continue;
64
- const sid = target.slice(prefix.length).split('/')[0];
65
- if (sid && SESSION_UUID_RE.test(sid)) {
66
- return { sessionId: sid, eventsPath: cocoEventsPathForSession(sid) };
67
- }
92
+ const target = line.slice(1);
93
+ const hit = matchCocoSessionPath(target);
94
+ if (hit)
95
+ return hit;
68
96
  }
69
97
  return undefined;
70
98
  }
99
+ function matchCocoSessionPath(target) {
100
+ const idx = target.indexOf(COCO_SESSIONS_ANCHOR);
101
+ if (idx < 0)
102
+ return undefined;
103
+ const sid = target.slice(idx + COCO_SESSIONS_ANCHOR.length).split('/')[0];
104
+ if (!sid || !SESSION_UUID_RE.test(sid))
105
+ return undefined;
106
+ return { sessionId: sid, eventsPath: cocoEventsPathForSession(sid) };
107
+ }
71
108
  function messageText(content) {
72
109
  return typeof content === 'string' ? content : '';
73
110
  }
@@ -1 +1 @@
1
- {"version":3,"file":"coco-transcript.js","sourceRoot":"","sources":["../../src/services/coco-transcript.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"coco-transcript.js","sourceRoot":"","sources":["../../src/services/coco-transcript.ts"],"names":[],"mappings":"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"}
@@ -4,17 +4,16 @@
4
4
  * contains its own dashes that would otherwise let a greedy match swallow
5
5
  * parts of the sid. Returns undefined for paths that don't match. */
6
6
  export declare function codexSessionIdFromRolloutPath(path: string): string | undefined;
7
- /** Find the rollout file an externally-running Codex process has open by
8
- * walking `/proc/<pid>/fd/*`. The Codex process keeps fd open on its
9
- * current rollout for the entire lifetime of the session, so this is the
10
- * authoritative way to bind a Codex pid to its sessionId — far more
11
- * reliable than scanning `~/.codex/sessions` by mtime (which would race
12
- * with sibling Codex panes in the same project).
7
+ /** Find the rollout file an externally-running Codex process has open. The
8
+ * Codex process keeps fd open on its current rollout for the entire
9
+ * lifetime of the session, so this is the authoritative way to bind a
10
+ * Codex pid to its sessionId — far more reliable than scanning
11
+ * `~/.codex/sessions` by mtime (which would race with sibling Codex panes
12
+ * in the same project).
13
13
  *
14
- * Linux-only: relies on `/proc`. macOS/BSD callers should fall back to
15
- * the cliSessionId path (read from `~/.codex/history.jsonl`'s last
16
- * matching cwd entry) but the use case for /proc-based discovery is
17
- * /adopt, which already runs on Linux servers in practice. */
14
+ * Linux: `/proc/<pid>/fd/*` fast path.
15
+ * macOS / BSD: `lsof -p <pid> -Fn` 兜底(同 session-discovery 里的 readCwd)。
16
+ * 两种平台都用 `codexSessionIdFromRolloutPath` 提取 sid。 */
18
17
  export declare function findCodexRolloutByPid(pid: number): {
19
18
  path: string;
20
19
  cliSessionId: string;
@@ -35,6 +34,23 @@ export interface CodexBridgeEvent {
35
34
  * user, output_text for assistant). */
36
35
  text: string;
37
36
  }
37
+ /** Extract the last completed user/assistant turn from a Codex / CoCo bridge
38
+ * event sequence. Used by /adopt to surface the previous turn as a
39
+ * preamble card in the Lark thread — gives the user context to continue
40
+ * from. CoCo events share the same shape (uuid/timestampMs/kind/text),
41
+ * so this works for both bridges.
42
+ *
43
+ * Algorithm: scan tail-first for the most recent `assistant_final`, then
44
+ * pair it with the most recent `user` event that precedes it. Returns
45
+ * undefined when either side is missing — typically a fresh session whose
46
+ * user typed something but the model hasn't replied yet. */
47
+ export declare function extractLastCodexTurn(events: readonly {
48
+ kind: 'user' | 'assistant_final';
49
+ text: string;
50
+ }[]): {
51
+ userText: string;
52
+ assistantText: string;
53
+ } | undefined;
38
54
  /** Split a drained event list into "history" (older than the live cutoff)
39
55
  * and "live" (cutoff or newer). The Codex adopt bridge uses this when
40
56
  * it discovers the rollout file LATE (after the user already typed in
@@ -1 +1 @@
1
- {"version":3,"file":"codex-transcript.d.ts","sourceRoot":"","sources":["../../src/services/codex-transcript.ts"],"names":[],"mappings":"AAgCA;;;;sEAIsE;AACtE,wBAAgB,6BAA6B,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAG9E;AAED;;;;;;;;;;+DAU+D;AAC/D,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,MAAM,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,CAerG;AAED,MAAM,WAAW,gBAAgB;IAC/B;yEACqE;IACrE,IAAI,EAAE,MAAM,CAAC;IACb;;4CAEwC;IACxC,WAAW,EAAE,MAAM,CAAC;IACpB;;oEAEgE;IAChE,IAAI,EAAE,MAAM,GAAG,iBAAiB,CAAC;IACjC;4CACwC;IACxC,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;;;;;;gEAOgE;AAChE,wBAAgB,wBAAwB,CACtC,MAAM,EAAE,SAAS,gBAAgB,EAAE,EACnC,WAAW,EAAE,MAAM,GAClB;IAAE,OAAO,EAAE,gBAAgB,EAAE,CAAC;IAAC,IAAI,EAAE,gBAAgB,EAAE,CAAA;CAAE,CAQ3D;AAED,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,gBAAgB,EAAE,CAAC;IAC3B;qDACiD;IACjD,SAAS,EAAE,MAAM,CAAC;IAClB;8DAC0D;IAC1D,WAAW,EAAE,MAAM,CAAC;CACrB;AAED;;;oDAGoD;AACpD,wBAAgB,2BAA2B,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAoBpF;AAkBD;;mEAEmE;AACnE,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,gBAAgB,CAqDpF"}
1
+ {"version":3,"file":"codex-transcript.d.ts","sourceRoot":"","sources":["../../src/services/codex-transcript.ts"],"names":[],"mappings":"AAkCA;;;;sEAIsE;AACtE,wBAAgB,6BAA6B,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAG9E;AAED;;;;;;;;;qDASqD;AACrD,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,MAAM,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,CAmCrG;AAUD,MAAM,WAAW,gBAAgB;IAC/B;yEACqE;IACrE,IAAI,EAAE,MAAM,CAAC;IACb;;4CAEwC;IACxC,WAAW,EAAE,MAAM,CAAC;IACpB;;oEAEgE;IAChE,IAAI,EAAE,MAAM,GAAG,iBAAiB,CAAC;IACjC;4CACwC;IACxC,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;;;;;;;;6DAS6D;AAC7D,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,SAAS;IAAE,IAAI,EAAE,MAAM,GAAG,iBAAiB,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,EAAE,GACpE;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,aAAa,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,CAezD;AAED;;;;;;;gEAOgE;AAChE,wBAAgB,wBAAwB,CACtC,MAAM,EAAE,SAAS,gBAAgB,EAAE,EACnC,WAAW,EAAE,MAAM,GAClB;IAAE,OAAO,EAAE,gBAAgB,EAAE,CAAC;IAAC,IAAI,EAAE,gBAAgB,EAAE,CAAA;CAAE,CAQ3D;AAED,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,gBAAgB,EAAE,CAAC;IAC3B;qDACiD;IACjD,SAAS,EAAE,MAAM,CAAC;IAClB;8DAC0D;IAC1D,WAAW,EAAE,MAAM,CAAC;CACrB;AAED;;;oDAGoD;AACpD,wBAAgB,2BAA2B,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAoBpF;AAkBD;;mEAEmE;AACnE,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,gBAAgB,CAqDpF"}
@@ -25,9 +25,11 @@
25
25
  * Pure I/O. Attribution belongs in CodexBridgeQueue.
26
26
  */
27
27
  import { existsSync, statSync, openSync, readSync, closeSync, readdirSync, readlinkSync } from 'node:fs';
28
- import { homedir } from 'node:os';
28
+ import { execSync } from 'node:child_process';
29
+ import { homedir, platform } from 'node:os';
29
30
  import { join } from 'node:path';
30
31
  const CODEX_SESSIONS_ROOT = join(homedir(), '.codex', 'sessions');
32
+ const IS_LINUX = platform() === 'linux';
31
33
  /** Extract the cliSessionId encoded in a rollout filename. Codex's session
32
34
  * id is UUID-shaped (8-4-4-4-12 hex), which lets us anchor the regex on
33
35
  * the UUID alone — the `<ts>` segment between "rollout-" and the sid
@@ -37,48 +39,111 @@ export function codexSessionIdFromRolloutPath(path) {
37
39
  const m = /rollout-.*-([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})\.jsonl$/i.exec(path);
38
40
  return m ? m[1] : undefined;
39
41
  }
40
- /** Find the rollout file an externally-running Codex process has open by
41
- * walking `/proc/<pid>/fd/*`. The Codex process keeps fd open on its
42
- * current rollout for the entire lifetime of the session, so this is the
43
- * authoritative way to bind a Codex pid to its sessionId — far more
44
- * reliable than scanning `~/.codex/sessions` by mtime (which would race
45
- * with sibling Codex panes in the same project).
42
+ /** Find the rollout file an externally-running Codex process has open. The
43
+ * Codex process keeps fd open on its current rollout for the entire
44
+ * lifetime of the session, so this is the authoritative way to bind a
45
+ * Codex pid to its sessionId — far more reliable than scanning
46
+ * `~/.codex/sessions` by mtime (which would race with sibling Codex panes
47
+ * in the same project).
46
48
  *
47
- * Linux-only: relies on `/proc`. macOS/BSD callers should fall back to
48
- * the cliSessionId path (read from `~/.codex/history.jsonl`'s last
49
- * matching cwd entry) but the use case for /proc-based discovery is
50
- * /adopt, which already runs on Linux servers in practice. */
49
+ * Linux: `/proc/<pid>/fd/*` fast path.
50
+ * macOS / BSD: `lsof -p <pid> -Fn` 兜底(同 session-discovery 里的 readCwd)。
51
+ * 两种平台都用 `codexSessionIdFromRolloutPath` 提取 sid。 */
51
52
  export function findCodexRolloutByPid(pid) {
52
53
  if (!Number.isInteger(pid) || pid <= 0)
53
54
  return undefined;
54
- const fdDir = `/proc/${pid}/fd`;
55
- if (!existsSync(fdDir))
56
- return undefined;
57
- let entries;
55
+ if (IS_LINUX) {
56
+ const fdDir = `/proc/${pid}/fd`;
57
+ if (existsSync(fdDir)) {
58
+ let entries;
59
+ try {
60
+ entries = readdirSync(fdDir);
61
+ }
62
+ catch {
63
+ return undefined;
64
+ }
65
+ for (const fd of entries) {
66
+ let target;
67
+ try {
68
+ target = readlinkSync(join(fdDir, fd));
69
+ }
70
+ catch {
71
+ continue;
72
+ }
73
+ const hit = matchCodexRolloutPath(target);
74
+ if (hit)
75
+ return hit;
76
+ }
77
+ return undefined;
78
+ }
79
+ // /proc 不可读时落到下面的 lsof 兜底(极少见,但兜一下)
80
+ }
81
+ // BSD ps 的 lsof:每个 fd 输出一行 `f<n>` 加一行 `n<path>`,socket / pipe
82
+ // 之类的内部条目以 `n->0x...` 或 `n<garbage>` 开头,所以只接受 `n/` 开头。
83
+ let out;
58
84
  try {
59
- entries = readdirSync(fdDir);
85
+ out = execSync(`lsof -p ${pid} -Fn`, {
86
+ encoding: 'utf-8',
87
+ stdio: ['pipe', 'pipe', 'pipe'],
88
+ });
60
89
  }
61
90
  catch {
62
91
  return undefined;
63
92
  }
64
- for (const fd of entries) {
65
- let target;
66
- try {
67
- target = readlinkSync(join(fdDir, fd));
68
- }
69
- catch {
70
- continue;
71
- }
72
- if (!target.endsWith('.jsonl'))
93
+ for (const line of out.split('\n')) {
94
+ if (!line.startsWith('n/'))
73
95
  continue;
74
- if (!target.includes('/.codex/sessions/'))
75
- continue;
76
- const sid = codexSessionIdFromRolloutPath(target);
77
- if (sid)
78
- return { path: target, cliSessionId: sid };
96
+ const target = line.slice(1);
97
+ const hit = matchCodexRolloutPath(target);
98
+ if (hit)
99
+ return hit;
79
100
  }
80
101
  return undefined;
81
102
  }
103
+ function matchCodexRolloutPath(target) {
104
+ if (!target.endsWith('.jsonl'))
105
+ return undefined;
106
+ if (!target.includes('/.codex/sessions/'))
107
+ return undefined;
108
+ const sid = codexSessionIdFromRolloutPath(target);
109
+ if (!sid)
110
+ return undefined;
111
+ return { path: target, cliSessionId: sid };
112
+ }
113
+ /** Extract the last completed user/assistant turn from a Codex / CoCo bridge
114
+ * event sequence. Used by /adopt to surface the previous turn as a
115
+ * preamble card in the Lark thread — gives the user context to continue
116
+ * from. CoCo events share the same shape (uuid/timestampMs/kind/text),
117
+ * so this works for both bridges.
118
+ *
119
+ * Algorithm: scan tail-first for the most recent `assistant_final`, then
120
+ * pair it with the most recent `user` event that precedes it. Returns
121
+ * undefined when either side is missing — typically a fresh session whose
122
+ * user typed something but the model hasn't replied yet. */
123
+ export function extractLastCodexTurn(events) {
124
+ let assistantIdx = -1;
125
+ for (let i = events.length - 1; i >= 0; i--) {
126
+ if (events[i].kind === 'assistant_final') {
127
+ assistantIdx = i;
128
+ break;
129
+ }
130
+ }
131
+ if (assistantIdx < 0)
132
+ return undefined;
133
+ let userIdx = -1;
134
+ for (let i = assistantIdx - 1; i >= 0; i--) {
135
+ if (events[i].kind === 'user') {
136
+ userIdx = i;
137
+ break;
138
+ }
139
+ }
140
+ if (userIdx < 0)
141
+ return undefined;
142
+ return {
143
+ userText: events[userIdx].text,
144
+ assistantText: events[assistantIdx].text,
145
+ };
146
+ }
82
147
  /** Split a drained event list into "history" (older than the live cutoff)
83
148
  * and "live" (cutoff or newer). The Codex adopt bridge uses this when
84
149
  * it discovers the rollout file LATE (after the user already typed in
@@ -1 +1 @@
1
- {"version":3,"file":"codex-transcript.js","sourceRoot":"","sources":["../../src/services/codex-transcript.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"codex-transcript.js","sourceRoot":"","sources":["../../src/services/codex-transcript.ts"],"names":[],"mappings":"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"}
@@ -14,4 +14,8 @@ export interface SkillDef {
14
14
  content: string;
15
15
  }
16
16
  export declare const BUILTIN_SKILLS: SkillDef[];
17
+ /** Skills that earlier botmux versions installed but no longer ship. The
18
+ * installer cleans these up so renamed skills don't linger as duplicates
19
+ * in the CLI's skills directory. */
20
+ export declare const RETIRED_SKILL_NAMES: string[];
17
21
  //# sourceMappingURL=definitions.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"definitions.d.ts","sourceRoot":"","sources":["../../src/skills/definitions.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,MAAM,WAAW,QAAQ;IACvB,2EAA2E;IAC3E,IAAI,EAAE,MAAM,CAAC;IACb,kDAAkD;IAClD,OAAO,EAAE,MAAM,CAAC;CACjB;AAoUD,eAAO,MAAM,cAAc,EAAE,QAAQ,EAKpC,CAAC"}
1
+ {"version":3,"file":"definitions.d.ts","sourceRoot":"","sources":["../../src/skills/definitions.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,MAAM,WAAW,QAAQ;IACvB,2EAA2E;IAC3E,IAAI,EAAE,MAAM,CAAC;IACb,kDAAkD;IAClD,OAAO,EAAE,MAAM,CAAC;CACjB;AAuXD,eAAO,MAAM,cAAc,EAAE,QAAQ,EAMpC,CAAC;AAEF;;qCAEqC;AACrC,eAAO,MAAM,mBAAmB,EAAE,MAAM,EAEvC,CAAC"}
@@ -99,26 +99,26 @@ botmux schedule add "每日11:00" "
99
99
 
100
100
  详见 \`botmux-send\` 技能的"顶层广播 / 跨群发布"章节。
101
101
  `;
102
- const THREAD_MESSAGES_SKILL = `---
103
- name: botmux-thread-messages
104
- description: 需要查看当前 Lark 话题的历史消息时触发。适合"看看这个话题之前聊了什么"、"最近的消息"、"上下文"类请求。在 CLI 会话内自动推断 session-id。
102
+ const HISTORY_SKILL = `---
103
+ name: botmux-history
104
+ description: 需要查看当前飞书会话历史消息时触发。话题群拉话题内消息,普通群拉整群消息(从 session 创建起的最近 N 条)。适合"看看之前聊了什么"、"最近的消息"、"上下文"类请求。在 CLI 会话内自动推断 session-id。
105
105
  ---
106
106
 
107
- # botmux-thread-messages读取话题消息历史
107
+ # botmux-history读取会话消息历史
108
108
 
109
- 想回顾当前 Lark 话题里用户之前发过什么、别的机器人说了什么时使用。
109
+ 想回顾当前飞书会话里用户之前发过什么、别的机器人说了什么时使用。**话题群和普通群都支持**:话题群里只返回当前话题内的消息,普通群里返回整群从 session 创建起的最近 N 条。
110
110
 
111
111
  ## 用法
112
112
 
113
113
  \`\`\`bash
114
114
  # 拉取最近 50 条(默认)
115
- botmux thread messages
115
+ botmux history
116
116
 
117
117
  # 拉取最近 100 条
118
- botmux thread messages --limit 100
118
+ botmux history --limit 100
119
119
 
120
120
  # 指定 session-id(不在 CLI 会话内时用)
121
- botmux thread messages --session-id <uuid>
121
+ botmux history --session-id <uuid>
122
122
  \`\`\`
123
123
 
124
124
  ## 输出
@@ -128,7 +128,9 @@ JSON 格式,字段:
128
128
  \`\`\`json
129
129
  {
130
130
  "sessionId": "...",
131
- "threadId": "...",
131
+ "chatId": "...",
132
+ "scope": "thread" | "chat",
133
+ "rootMessageId": "...", // 仅 scope=thread 时存在
132
134
  "messages": [
133
135
  { "messageId": "...", "senderId": "...", "senderType": "user|app", "msgType": "text|post|interactive", "content": "...", "createTime": "..." }
134
136
  ],
@@ -138,11 +140,59 @@ JSON 格式,字段:
138
140
 
139
141
  ## 注意
140
142
 
141
- - 只返回属于当前话题的消息(按 rootMessageId 过滤)
142
- - senderType="app" 表示机器人发的消息(包括 Claude Code / Codex / 其它 bot),"user" 表示用户
143
+ - \`scope=thread\`:只返回属于当前话题的消息(按 rootMessageId 过滤)
144
+ - \`scope=chat\`:返回当前群从 session 创建起的最近 N 条整群消息
145
+ - \`senderType="app"\` 表示机器人发的消息(包括 Claude Code / Codex / 其它 bot),\`"user"\` 表示用户
143
146
  - **合并转发**消息会自动展开:\`msgType\` 变为 \`merge_forward_expanded\`,\`content\` 是 \`<forwarded_messages>...</forwarded_messages>\` XML(含 \`<participants>\` 别名表 + 嵌套 \`<msg from="A">\` 节点),与 daemon 实时事件路径一致
144
147
  - 需要先把 JSON 读进来再做总结,不要直接把 JSON 扔给用户
145
148
  `;
149
+ const QUOTED_SKILL = `---
150
+ name: botmux-quoted
151
+ description: 当 prompt 顶部出现 \`[用户引用了消息 用 botmux quoted om_xxx 查看]\` 提示时,用本技能按需读取被引用的那条消息内容。看到这种提示就该判断引用内容是否对当前任务必要,必要就调用,不必要就跳过。
152
+ ---
153
+
154
+ # botmux-quoted — 读取被引用的消息
155
+
156
+ 用户在飞书里使用"引用回复" UI @ 机器人时,daemon 会在喂给你的 prompt 头部加一行:
157
+
158
+ \`\`\`
159
+ [用户引用了消息 用 botmux quoted om_xxx 查看]
160
+ <用户的实际文字>
161
+ \`\`\`
162
+
163
+ 看到这种提示,先判断引用内容是否对当前任务必要:必要就调用 \`botmux quoted om_xxx\` 拉取,不必要就忽略(不要无脑调用、污染上下文)。
164
+
165
+ ## 用法
166
+
167
+ \`\`\`bash
168
+ botmux quoted <message_id>
169
+ \`\`\`
170
+
171
+ \`message_id\` 直接从提示行里复制即可。
172
+
173
+ ## 输出
174
+
175
+ JSON 格式,与 \`botmux history\` 的单条消息字段一致,并附带 \`resources\` 列表:
176
+
177
+ \`\`\`json
178
+ {
179
+ "messageId": "om_xxx",
180
+ "senderId": "ou_xxx",
181
+ "senderType": "user|app",
182
+ "msgType": "text|post|interactive|image|file|merge_forward_expanded",
183
+ "content": "...",
184
+ "createTime": "1234567890000",
185
+ "resources": [{"type":"image","key":"img_v3_xxx","name":"img_v3_xxx.jpg"}]
186
+ }
187
+ \`\`\`
188
+
189
+ ## 注意
190
+
191
+ - 图片/文件渲染成 \`[图片 N]\` / \`[文件 N: name.pdf]\` 占位符(与 \`botmux history\` 一致),实际附件 key 在 \`resources\` 列表里
192
+ - 卡片消息会被解析成可读文本
193
+ - 合并转发消息会自动展开
194
+ - 当前不支持自动下载附件本地化;要看图片实际内容,目前只能让用户单独转发或 \`botmux send\` 询问
195
+ `;
146
196
  const SEND_SKILL = `---
147
197
  name: botmux-send
148
198
  description: 向飞书话题发送消息。用户在飞书上阅读看不到终端输出,需要用户看到的内容(关键结论、方案、最终结果、进度更新)必须通过 botmux send 发送。支持图文混排(图片穿插在 markdown 正文中)、文本、图片/文件附件、@mention。
@@ -327,8 +377,15 @@ botmux send --mention "ou_yyy:Aiden" "请 @Aiden 帮忙处理"
327
377
  `;
328
378
  export const BUILTIN_SKILLS = [
329
379
  { name: 'botmux-schedule', content: SCHEDULE_SKILL },
330
- { name: 'botmux-thread-messages', content: THREAD_MESSAGES_SKILL },
380
+ { name: 'botmux-history', content: HISTORY_SKILL },
381
+ { name: 'botmux-quoted', content: QUOTED_SKILL },
331
382
  { name: 'botmux-send', content: SEND_SKILL },
332
383
  { name: 'botmux-bots', content: BOTS_SKILL },
333
384
  ];
385
+ /** Skills that earlier botmux versions installed but no longer ship. The
386
+ * installer cleans these up so renamed skills don't linger as duplicates
387
+ * in the CLI's skills directory. */
388
+ export const RETIRED_SKILL_NAMES = [
389
+ 'botmux-thread-messages',
390
+ ];
334
391
  //# sourceMappingURL=definitions.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"definitions.js","sourceRoot":"","sources":["../../src/skills/definitions.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AASH,MAAM,cAAc,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2FtB,CAAC;AAEF,MAAM,qBAAqB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2C7B,CAAC;AAEF,MAAM,UAAU,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAkJlB,CAAC;AAEF,MAAM,UAAU,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAkClB,CAAC;AAEF,MAAM,CAAC,MAAM,cAAc,GAAe;IACxC,EAAE,IAAI,EAAE,iBAAiB,EAAE,OAAO,EAAE,cAAc,EAAE;IACpD,EAAE,IAAI,EAAE,wBAAwB,EAAE,OAAO,EAAE,qBAAqB,EAAE;IAClE,EAAE,IAAI,EAAE,aAAa,EAAE,OAAO,EAAE,UAAU,EAAE;IAC5C,EAAE,IAAI,EAAE,aAAa,EAAE,OAAO,EAAE,UAAU,EAAE;CAC7C,CAAC"}
1
+ {"version":3,"file":"definitions.js","sourceRoot":"","sources":["../../src/skills/definitions.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AASH,MAAM,cAAc,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2FtB,CAAC;AAEF,MAAM,aAAa,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA8CrB,CAAC;AAEF,MAAM,YAAY,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA8CpB,CAAC;AAEF,MAAM,UAAU,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAkJlB,CAAC;AAEF,MAAM,UAAU,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAkClB,CAAC;AAEF,MAAM,CAAC,MAAM,cAAc,GAAe;IACxC,EAAE,IAAI,EAAE,iBAAiB,EAAE,OAAO,EAAE,cAAc,EAAE;IACpD,EAAE,IAAI,EAAE,gBAAgB,EAAE,OAAO,EAAE,aAAa,EAAE;IAClD,EAAE,IAAI,EAAE,eAAe,EAAE,OAAO,EAAE,YAAY,EAAE;IAChD,EAAE,IAAI,EAAE,aAAa,EAAE,OAAO,EAAE,UAAU,EAAE;IAC5C,EAAE,IAAI,EAAE,aAAa,EAAE,OAAO,EAAE,UAAU,EAAE;CAC7C,CAAC;AAEF;;qCAEqC;AACrC,MAAM,CAAC,MAAM,mBAAmB,GAAa;IAC3C,wBAAwB;CACzB,CAAC"}
@@ -3,7 +3,9 @@
3
3
  * directory. Idempotent — only writes when content differs.
4
4
  *
5
5
  * Each skill becomes {skillsDir}/<name>/SKILL.md. Sub-directory layout
6
- * matches Claude Code / Gemini / OpenCode convention.
6
+ * matches Claude Code / Gemini / OpenCode convention. Retired skills (renamed
7
+ * or removed in a later version) are deleted from the directory so the CLI
8
+ * doesn't keep surfacing stale entries alongside their replacements.
7
9
  */
8
10
  export declare function ensureSkills(cliId: string, skillsDir: string | undefined): void;
9
11
  //# sourceMappingURL=installer.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"installer.d.ts","sourceRoot":"","sources":["../../src/skills/installer.ts"],"names":[],"mappings":"AAUA;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CAoB/E"}
1
+ {"version":3,"file":"installer.d.ts","sourceRoot":"","sources":["../../src/skills/installer.ts"],"names":[],"mappings":"AAUA;;;;;;;;GAQG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CAgC/E"}
@@ -1,8 +1,8 @@
1
- import { writeFileSync, mkdirSync, existsSync, readFileSync } from 'node:fs';
1
+ import { writeFileSync, mkdirSync, existsSync, readFileSync, rmSync } from 'node:fs';
2
2
  import { join } from 'node:path';
3
3
  import { homedir } from 'node:os';
4
4
  import { logger } from '../utils/logger.js';
5
- import { BUILTIN_SKILLS } from './definitions.js';
5
+ import { BUILTIN_SKILLS, RETIRED_SKILL_NAMES } from './definitions.js';
6
6
  function expandHome(p) {
7
7
  return p.startsWith('~') ? join(homedir(), p.slice(1)) : p;
8
8
  }
@@ -11,7 +11,9 @@ function expandHome(p) {
11
11
  * directory. Idempotent — only writes when content differs.
12
12
  *
13
13
  * Each skill becomes {skillsDir}/<name>/SKILL.md. Sub-directory layout
14
- * matches Claude Code / Gemini / OpenCode convention.
14
+ * matches Claude Code / Gemini / OpenCode convention. Retired skills (renamed
15
+ * or removed in a later version) are deleted from the directory so the CLI
16
+ * doesn't keep surfacing stale entries alongside their replacements.
15
17
  */
16
18
  export function ensureSkills(cliId, skillsDir) {
17
19
  if (!skillsDir)
@@ -38,5 +40,18 @@ export function ensureSkills(cliId, skillsDir) {
38
40
  logger.warn(`[skills] Failed to install ${skill.name} for ${cliId}: ${err.message}`);
39
41
  }
40
42
  }
43
+ // Clean up retired skill directories (e.g. botmux-thread-messages → botmux-history).
44
+ for (const retired of RETIRED_SKILL_NAMES) {
45
+ const retiredDir = join(dir, retired);
46
+ if (!existsSync(retiredDir))
47
+ continue;
48
+ try {
49
+ rmSync(retiredDir, { recursive: true, force: true });
50
+ logger.info(`[skills] Removed retired skill ${retired} for ${cliId}`);
51
+ }
52
+ catch (err) {
53
+ logger.warn(`[skills] Failed to remove retired skill ${retired} for ${cliId}: ${err.message}`);
54
+ }
55
+ }
41
56
  }
42
57
  //# sourceMappingURL=installer.js.map