botmux 2.12.0 → 2.12.2

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 (38) hide show
  1. package/dist/adapters/cli/claude-code.d.ts +9 -3
  2. package/dist/adapters/cli/claude-code.d.ts.map +1 -1
  3. package/dist/adapters/cli/claude-code.js +20 -12
  4. package/dist/adapters/cli/claude-code.js.map +1 -1
  5. package/dist/core/session-discovery.d.ts.map +1 -1
  6. package/dist/core/session-discovery.js +11 -1
  7. package/dist/core/session-discovery.js.map +1 -1
  8. package/dist/core/worker-pool.d.ts.map +1 -1
  9. package/dist/core/worker-pool.js +13 -9
  10. package/dist/core/worker-pool.js.map +1 -1
  11. package/dist/daemon.js +10 -9
  12. package/dist/daemon.js.map +1 -1
  13. package/dist/services/bridge-rotation-policy.d.ts +139 -0
  14. package/dist/services/bridge-rotation-policy.d.ts.map +1 -0
  15. package/dist/services/bridge-rotation-policy.js +125 -0
  16. package/dist/services/bridge-rotation-policy.js.map +1 -0
  17. package/dist/services/bridge-turn-queue.d.ts +9 -1
  18. package/dist/services/bridge-turn-queue.d.ts.map +1 -1
  19. package/dist/services/bridge-turn-queue.js +9 -2
  20. package/dist/services/bridge-turn-queue.js.map +1 -1
  21. package/dist/services/claude-transcript.d.ts +67 -0
  22. package/dist/services/claude-transcript.d.ts.map +1 -1
  23. package/dist/services/claude-transcript.js +228 -1
  24. package/dist/services/claude-transcript.js.map +1 -1
  25. package/dist/services/codex-bridge-queue.d.ts +56 -0
  26. package/dist/services/codex-bridge-queue.d.ts.map +1 -0
  27. package/dist/services/codex-bridge-queue.js +150 -0
  28. package/dist/services/codex-bridge-queue.js.map +1 -0
  29. package/dist/services/codex-transcript.d.ts +68 -0
  30. package/dist/services/codex-transcript.d.ts.map +1 -0
  31. package/dist/services/codex-transcript.js +233 -0
  32. package/dist/services/codex-transcript.js.map +1 -0
  33. package/dist/utils/idle-detector.d.ts.map +1 -1
  34. package/dist/utils/idle-detector.js +15 -4
  35. package/dist/utils/idle-detector.js.map +1 -1
  36. package/dist/worker.js +743 -114
  37. package/dist/worker.js.map +1 -1
  38. package/package.json +2 -2
@@ -0,0 +1,139 @@
1
+ /**
2
+ * Pure rotation-policy gate for the Claude bridge watcher.
3
+ *
4
+ * Lives outside `worker.ts` so tests can import without dragging worker-level
5
+ * fs / IPC side-effects.
6
+ */
7
+ export type PidFollowResult = 'unavailable' | 'same' | 'switched';
8
+ /**
9
+ * Decide whether `bridgeIngest` should fall through to the directory-mtime
10
+ * `maybeFollowQuietRotation` heuristic this tick.
11
+ *
12
+ * Inputs:
13
+ * - `pidFollow`: result of the authoritative pid-state probe
14
+ * (`maybeFollowSessionRotationViaPid`). `'switched'` means it already
15
+ * moved us; `'same'` means the pid file's `sessionId` matches our
16
+ * current path; `'unavailable'` means the pid file was unreadable
17
+ * (non-Linux, no `~/.claude/sessions/<pid>.json`, validation failure).
18
+ * - `switched`: whether ANY earlier rotation step (pid resolver OR
19
+ * fingerprint fallback) already moved the watcher this tick.
20
+ *
21
+ * Returns true only when there was no earlier switch AND the pid resolver
22
+ * gave no opinion.
23
+ *
24
+ * Trade-off: pid resolver `'same'` is NOT proof that no rotation happened
25
+ * — Claude Code 2.1.123 writes `sessionId` ONCE at process start and the
26
+ * in-pane `/clear` path does not refresh it. We still skip the mtime
27
+ * heuristic on `'same'` because the alternative is sibling-pane hijack:
28
+ * any other Claude pane in the same cwd gets a busier jsonl and the
29
+ * heuristic picks it. The cost is that a pure-local `/clear` with no
30
+ * pending Lark turn won't auto-follow until the user sends a Lark
31
+ * message (which arms fingerprint fallback). The Lark-message path is
32
+ * the dominant /clear recovery flow in practice; sibling-pane
33
+ * corruption would silently break every multi-pane adopt setup.
34
+ *
35
+ * `--resume` is a fresh spawn and rewrites the pid file's sessionId, so
36
+ * it surfaces here as `'switched'`, not `'same'` — it's not affected by
37
+ * this gate.
38
+ */
39
+ export declare function shouldRunQuietRotation(pidFollow: PidFollowResult, switched: boolean): boolean;
40
+ export interface PidResolverPullbackInput {
41
+ /** sessionId reported by the pid file this tick. */
42
+ resolvedCliSessionId: string;
43
+ /** The pid file's full jsonl path (derived from sessionId + cwd). */
44
+ resolvedPath: string;
45
+ /** Current bridge jsonl path. */
46
+ currentBridgeJsonlPath: string | undefined;
47
+ /** Sid recorded as "stale" by the fingerprint fallback the last time it
48
+ * accepted a candidate the pid file disagreed about. Undefined when no
49
+ * fingerprint accept has overridden the pid file. */
50
+ stalePidStateSessionId: string | undefined;
51
+ }
52
+ export interface PidResolverPullbackDecision {
53
+ /** True ⇒ pid resolver should report 'same' rather than rotate the
54
+ * watcher back to `resolvedPath`. */
55
+ suppress: boolean;
56
+ /** True ⇒ caller should clear `stalePidStateSessionId`: a fresh sid
57
+ * (different from the stale one) appeared in the pid file, meaning a
58
+ * real rotation has happened (`--resume` / fresh spawn) and the prior
59
+ * fingerprint accept is no longer relevant. */
60
+ clearStale: boolean;
61
+ }
62
+ /**
63
+ * Decide whether the pid resolver should pull the watcher back to a path
64
+ * that disagrees with the current bridgeJsonlPath, given the worker's
65
+ * staleness bookkeeping.
66
+ *
67
+ * Rules:
68
+ * - No `stalePidStateSessionId` recorded ⇒ honour pid resolver as before.
69
+ * - Recorded sid matches pid file's current sid ⇒ suppress: this is the
70
+ * spawn-time sid that fingerprint fallback already overrode for an
71
+ * in-pane /clear that pid file can't see.
72
+ * - Recorded sid differs from pid file's current sid ⇒ a NEW rotation has
73
+ * happened (`--resume` / fresh spawn / Claude restart with new pid file
74
+ * contents). Clear the stale flag and let pid resolver switch normally.
75
+ */
76
+ export declare function evaluatePidResolverPullback(input: PidResolverPullbackInput): PidResolverPullbackDecision;
77
+ /** UUID-shaped Claude jsonl filename (sessionId.jsonl). Duplicated from
78
+ * `src/adapters/cli/claude-code.ts:SESSION_UUID_RE` to keep this module
79
+ * free of adapter imports. Keep the two patterns in sync; both gate
80
+ * trust-set membership and fingerprint-fallback candidate eligibility. */
81
+ export declare const SESSION_ID_FILENAME_RE: RegExp;
82
+ /** Extract the sessionId portion of a `<sid>.jsonl` path (basename minus
83
+ * the `.jsonl` extension). Returns the empty string when the path lacks
84
+ * the expected suffix; callers should treat that as "untrusted". */
85
+ export declare function sessionIdFromJsonlPath(path: string): string;
86
+ export interface FingerprintSwitchInput {
87
+ /** Substring fingerprint to feed Phase 1's scanner. Required. */
88
+ contentFingerprint: string;
89
+ /** Full normalised content of the Lark turn. Phase 2 (unknown-sid
90
+ * exact-content recovery) is skipped when this is missing or empty —
91
+ * short content can't anchor a recovery without ambiguity. */
92
+ contentNormalized?: string;
93
+ /** Trust set populated from initial attach, pid resolver hits, fd probes. */
94
+ knownSessionIds: ReadonlySet<string>;
95
+ /** Phase 1 scanner: substring fingerprint search. Caller wires it to
96
+ * `findJsonlContainingFingerprint`; this helper only sees the result. */
97
+ findSubstring: (acceptCandidate: (path: string) => boolean) => string | null;
98
+ /** Phase 2 scanner: exact-content search returning ALL matches in
99
+ * mtime-descending order. Caller wires it to
100
+ * `findJsonlsContainingExactContent`. */
101
+ findExact: (acceptCandidate: (path: string) => boolean) => string[];
102
+ }
103
+ export type FingerprintSwitchDecision = {
104
+ action: 'switch';
105
+ path: string;
106
+ reason: 'known-sid-substring' | 'unknown-sid-exact';
107
+ } | {
108
+ action: 'abstain';
109
+ reason: 'multiple-unknown-exact';
110
+ candidates: string[];
111
+ } | {
112
+ action: 'no-match';
113
+ };
114
+ /**
115
+ * Two-phase candidate selection for the bridge fingerprint fallback.
116
+ *
117
+ * Phase 1 (known-sid substring): the cheap path. Run the substring
118
+ * fingerprint scanner with an acceptCandidate predicate that requires
119
+ * `(UUID-shaped sid) AND (sid in knownSessionIds)`. Sibling panes are
120
+ * UUID-shaped but not in our trust set — their fingerprint hits are
121
+ * rejected. UUID gate also blocks accidental non-Claude jsonls.
122
+ *
123
+ * Phase 2 (unknown-sid exact-content recovery): only runs when
124
+ * `contentNormalized` is non-empty. Fires when Phase 1 found no match,
125
+ * which is the worst-case in-pane `/clear` scenario where the new sid
126
+ * never reaches our trust set (pid file lags, fd probe missed the open
127
+ * window). Run the exact-content scanner with predicate
128
+ * `(UUID-shaped sid) AND (sid NOT in knownSessionIds)`. Decision:
129
+ * - 0 matches → no-match
130
+ * - 1 match → switch (the post-/clear file we couldn't otherwise see)
131
+ * - ≥2 matches → abstain; multiple untrusted files normalise to the
132
+ * same Lark content, so we cannot pick one without further evidence.
133
+ * Caller is expected to log and surface a diagnostic.
134
+ *
135
+ * Pure: never touches fs / IPC / module state. Tests inject fakes for
136
+ * `findSubstring` and `findExact` to exercise every branch.
137
+ */
138
+ export declare function decideFingerprintSwitch(input: FingerprintSwitchInput): FingerprintSwitchDecision;
139
+ //# sourceMappingURL=bridge-rotation-policy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bridge-rotation-policy.d.ts","sourceRoot":"","sources":["../../src/services/bridge-rotation-policy.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,MAAM,eAAe,GAAG,aAAa,GAAG,MAAM,GAAG,UAAU,CAAC;AAElE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,wBAAgB,sBAAsB,CACpC,SAAS,EAAE,eAAe,EAC1B,QAAQ,EAAE,OAAO,GAChB,OAAO,CAGT;AAID,MAAM,WAAW,wBAAwB;IACvC,oDAAoD;IACpD,oBAAoB,EAAE,MAAM,CAAC;IAC7B,qEAAqE;IACrE,YAAY,EAAE,MAAM,CAAC;IACrB,iCAAiC;IACjC,sBAAsB,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3C;;0DAEsD;IACtD,sBAAsB,EAAE,MAAM,GAAG,SAAS,CAAC;CAC5C;AAED,MAAM,WAAW,2BAA2B;IAC1C;0CACsC;IACtC,QAAQ,EAAE,OAAO,CAAC;IAClB;;;oDAGgD;IAChD,UAAU,EAAE,OAAO,CAAC;CACrB;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,2BAA2B,CACzC,KAAK,EAAE,wBAAwB,GAC9B,2BAA2B,CAQ7B;AAID;;;2EAG2E;AAC3E,eAAO,MAAM,sBAAsB,QAAoE,CAAC;AAExG;;qEAEqE;AACrE,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAG3D;AAED,MAAM,WAAW,sBAAsB;IACrC,iEAAiE;IACjE,kBAAkB,EAAE,MAAM,CAAC;IAC3B;;mEAE+D;IAC/D,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,6EAA6E;IAC7E,eAAe,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IACrC;8EAC0E;IAC1E,aAAa,EAAE,CAAC,eAAe,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,KAAK,MAAM,GAAG,IAAI,CAAC;IAC7E;;8CAE0C;IAC1C,SAAS,EAAE,CAAC,eAAe,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,KAAK,MAAM,EAAE,CAAC;CACrE;AAED,MAAM,MAAM,yBAAyB,GACjC;IAAE,MAAM,EAAE,QAAQ,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,qBAAqB,GAAG,mBAAmB,CAAA;CAAE,GACvF;IAAE,MAAM,EAAE,SAAS,CAAC;IAAC,MAAM,EAAE,wBAAwB,CAAC;IAAC,UAAU,EAAE,MAAM,EAAE,CAAA;CAAE,GAC7E;IAAE,MAAM,EAAE,UAAU,CAAA;CAAE,CAAC;AAE3B;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,uBAAuB,CACrC,KAAK,EAAE,sBAAsB,GAC5B,yBAAyB,CAoB3B"}
@@ -0,0 +1,125 @@
1
+ /**
2
+ * Pure rotation-policy gate for the Claude bridge watcher.
3
+ *
4
+ * Lives outside `worker.ts` so tests can import without dragging worker-level
5
+ * fs / IPC side-effects.
6
+ */
7
+ /**
8
+ * Decide whether `bridgeIngest` should fall through to the directory-mtime
9
+ * `maybeFollowQuietRotation` heuristic this tick.
10
+ *
11
+ * Inputs:
12
+ * - `pidFollow`: result of the authoritative pid-state probe
13
+ * (`maybeFollowSessionRotationViaPid`). `'switched'` means it already
14
+ * moved us; `'same'` means the pid file's `sessionId` matches our
15
+ * current path; `'unavailable'` means the pid file was unreadable
16
+ * (non-Linux, no `~/.claude/sessions/<pid>.json`, validation failure).
17
+ * - `switched`: whether ANY earlier rotation step (pid resolver OR
18
+ * fingerprint fallback) already moved the watcher this tick.
19
+ *
20
+ * Returns true only when there was no earlier switch AND the pid resolver
21
+ * gave no opinion.
22
+ *
23
+ * Trade-off: pid resolver `'same'` is NOT proof that no rotation happened
24
+ * — Claude Code 2.1.123 writes `sessionId` ONCE at process start and the
25
+ * in-pane `/clear` path does not refresh it. We still skip the mtime
26
+ * heuristic on `'same'` because the alternative is sibling-pane hijack:
27
+ * any other Claude pane in the same cwd gets a busier jsonl and the
28
+ * heuristic picks it. The cost is that a pure-local `/clear` with no
29
+ * pending Lark turn won't auto-follow until the user sends a Lark
30
+ * message (which arms fingerprint fallback). The Lark-message path is
31
+ * the dominant /clear recovery flow in practice; sibling-pane
32
+ * corruption would silently break every multi-pane adopt setup.
33
+ *
34
+ * `--resume` is a fresh spawn and rewrites the pid file's sessionId, so
35
+ * it surfaces here as `'switched'`, not `'same'` — it's not affected by
36
+ * this gate.
37
+ */
38
+ export function shouldRunQuietRotation(pidFollow, switched) {
39
+ if (switched)
40
+ return false;
41
+ return pidFollow === 'unavailable';
42
+ }
43
+ /**
44
+ * Decide whether the pid resolver should pull the watcher back to a path
45
+ * that disagrees with the current bridgeJsonlPath, given the worker's
46
+ * staleness bookkeeping.
47
+ *
48
+ * Rules:
49
+ * - No `stalePidStateSessionId` recorded ⇒ honour pid resolver as before.
50
+ * - Recorded sid matches pid file's current sid ⇒ suppress: this is the
51
+ * spawn-time sid that fingerprint fallback already overrode for an
52
+ * in-pane /clear that pid file can't see.
53
+ * - Recorded sid differs from pid file's current sid ⇒ a NEW rotation has
54
+ * happened (`--resume` / fresh spawn / Claude restart with new pid file
55
+ * contents). Clear the stale flag and let pid resolver switch normally.
56
+ */
57
+ export function evaluatePidResolverPullback(input) {
58
+ if (input.stalePidStateSessionId === undefined) {
59
+ return { suppress: false, clearStale: false };
60
+ }
61
+ if (input.resolvedCliSessionId === input.stalePidStateSessionId) {
62
+ return { suppress: true, clearStale: false };
63
+ }
64
+ return { suppress: false, clearStale: true };
65
+ }
66
+ // ─── Two-phase fingerprint-fallback decision ───────────────────────────────
67
+ /** UUID-shaped Claude jsonl filename (sessionId.jsonl). Duplicated from
68
+ * `src/adapters/cli/claude-code.ts:SESSION_UUID_RE` to keep this module
69
+ * free of adapter imports. Keep the two patterns in sync; both gate
70
+ * trust-set membership and fingerprint-fallback candidate eligibility. */
71
+ export const SESSION_ID_FILENAME_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
72
+ /** Extract the sessionId portion of a `<sid>.jsonl` path (basename minus
73
+ * the `.jsonl` extension). Returns the empty string when the path lacks
74
+ * the expected suffix; callers should treat that as "untrusted". */
75
+ export function sessionIdFromJsonlPath(path) {
76
+ const base = path.split('/').pop() ?? '';
77
+ return base.endsWith('.jsonl') ? base.slice(0, -'.jsonl'.length) : '';
78
+ }
79
+ /**
80
+ * Two-phase candidate selection for the bridge fingerprint fallback.
81
+ *
82
+ * Phase 1 (known-sid substring): the cheap path. Run the substring
83
+ * fingerprint scanner with an acceptCandidate predicate that requires
84
+ * `(UUID-shaped sid) AND (sid in knownSessionIds)`. Sibling panes are
85
+ * UUID-shaped but not in our trust set — their fingerprint hits are
86
+ * rejected. UUID gate also blocks accidental non-Claude jsonls.
87
+ *
88
+ * Phase 2 (unknown-sid exact-content recovery): only runs when
89
+ * `contentNormalized` is non-empty. Fires when Phase 1 found no match,
90
+ * which is the worst-case in-pane `/clear` scenario where the new sid
91
+ * never reaches our trust set (pid file lags, fd probe missed the open
92
+ * window). Run the exact-content scanner with predicate
93
+ * `(UUID-shaped sid) AND (sid NOT in knownSessionIds)`. Decision:
94
+ * - 0 matches → no-match
95
+ * - 1 match → switch (the post-/clear file we couldn't otherwise see)
96
+ * - ≥2 matches → abstain; multiple untrusted files normalise to the
97
+ * same Lark content, so we cannot pick one without further evidence.
98
+ * Caller is expected to log and surface a diagnostic.
99
+ *
100
+ * Pure: never touches fs / IPC / module state. Tests inject fakes for
101
+ * `findSubstring` and `findExact` to exercise every branch.
102
+ */
103
+ export function decideFingerprintSwitch(input) {
104
+ const matchedKnown = input.findSubstring((path) => {
105
+ const sid = sessionIdFromJsonlPath(path);
106
+ return SESSION_ID_FILENAME_RE.test(sid) && input.knownSessionIds.has(sid);
107
+ });
108
+ if (matchedKnown) {
109
+ return { action: 'switch', path: matchedKnown, reason: 'known-sid-substring' };
110
+ }
111
+ if (!input.contentNormalized || input.contentNormalized.length === 0) {
112
+ return { action: 'no-match' };
113
+ }
114
+ const exact = input.findExact((path) => {
115
+ const sid = sessionIdFromJsonlPath(path);
116
+ return SESSION_ID_FILENAME_RE.test(sid) && !input.knownSessionIds.has(sid);
117
+ });
118
+ if (exact.length === 0)
119
+ return { action: 'no-match' };
120
+ if (exact.length > 1) {
121
+ return { action: 'abstain', reason: 'multiple-unknown-exact', candidates: exact };
122
+ }
123
+ return { action: 'switch', path: exact[0], reason: 'unknown-sid-exact' };
124
+ }
125
+ //# sourceMappingURL=bridge-rotation-policy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bridge-rotation-policy.js","sourceRoot":"","sources":["../../src/services/bridge-rotation-policy.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,MAAM,UAAU,sBAAsB,CACpC,SAA0B,EAC1B,QAAiB;IAEjB,IAAI,QAAQ;QAAE,OAAO,KAAK,CAAC;IAC3B,OAAO,SAAS,KAAK,aAAa,CAAC;AACrC,CAAC;AA4BD;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,2BAA2B,CACzC,KAA+B;IAE/B,IAAI,KAAK,CAAC,sBAAsB,KAAK,SAAS,EAAE,CAAC;QAC/C,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,CAAC;IAChD,CAAC;IACD,IAAI,KAAK,CAAC,oBAAoB,KAAK,KAAK,CAAC,sBAAsB,EAAE,CAAC;QAChE,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,CAAC;IAC/C,CAAC;IACD,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC;AAC/C,CAAC;AAED,8EAA8E;AAE9E;;;2EAG2E;AAC3E,MAAM,CAAC,MAAM,sBAAsB,GAAG,iEAAiE,CAAC;AAExG;;qEAEqE;AACrE,MAAM,UAAU,sBAAsB,CAAC,IAAY;IACjD,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,IAAI,EAAE,CAAC;IACzC,OAAO,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;AACxE,CAAC;AAyBD;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,MAAM,UAAU,uBAAuB,CACrC,KAA6B;IAE7B,MAAM,YAAY,GAAG,KAAK,CAAC,aAAa,CAAC,CAAC,IAAI,EAAE,EAAE;QAChD,MAAM,GAAG,GAAG,sBAAsB,CAAC,IAAI,CAAC,CAAC;QACzC,OAAO,sBAAsB,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,KAAK,CAAC,eAAe,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAC5E,CAAC,CAAC,CAAC;IACH,IAAI,YAAY,EAAE,CAAC;QACjB,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,YAAY,EAAE,MAAM,EAAE,qBAAqB,EAAE,CAAC;IACjF,CAAC;IACD,IAAI,CAAC,KAAK,CAAC,iBAAiB,IAAI,KAAK,CAAC,iBAAiB,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACrE,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC;IAChC,CAAC;IACD,MAAM,KAAK,GAAG,KAAK,CAAC,SAAS,CAAC,CAAC,IAAI,EAAE,EAAE;QACrC,MAAM,GAAG,GAAG,sBAAsB,CAAC,IAAI,CAAC,CAAC;QACzC,OAAO,sBAAsB,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,eAAe,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAC7E,CAAC,CAAC,CAAC;IACH,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC;IACtD,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACrB,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,wBAAwB,EAAE,UAAU,EAAE,KAAK,EAAE,CAAC;IACpF,CAAC;IACD,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,mBAAmB,EAAE,CAAC;AAC3E,CAAC"}
@@ -51,6 +51,14 @@ export interface BridgePendingTurn {
51
51
  * start the turn. Local-terminal input (whose content won't contain
52
52
  * the Lark fingerprint) leaves the turn unstarted. */
53
53
  contentFingerprint?: string;
54
+ /** Full normalised content of the Lark message. Used by the rotation
55
+ * fallback's recovery path to gate a switch into an UNKNOWN sessionId
56
+ * on exact equality with a user/queue event in that file — much
57
+ * stronger than the substring fingerprint check, which can't tell
58
+ * "test" from "run tests" across sibling panes. Stored in addition to
59
+ * `contentFingerprint` (not instead of) because in-pane known-sid
60
+ * candidates still benefit from the cheaper substring path. */
61
+ contentNormalized?: string;
54
62
  /** JSONL file the turn's user event was first seen in. Stamped by ingest()
55
63
  * when the turn transitions to started. Lets the emit step re-read text
56
64
  * from the original transcript even after a sessionId rotation has
@@ -84,7 +92,7 @@ export declare class BridgeTurnQueue {
84
92
  * `markTimeMs` is captured here so the rotation fallback can bound its
85
93
  * fingerprint scan to events written after this point — protects short
86
94
  * fingerprints from matching old history in unrelated sibling jsonls. */
87
- mark(turnId: string, contentFingerprint?: string, markTimeMs?: number): void;
95
+ mark(turnId: string, contentFingerprint?: string, markTimeMs?: number, contentNormalized?: string): void;
88
96
  /** Drop all pending turns. Used when the worker discovers it can't
89
97
  * reliably attribute future events (e.g. baseline raced with a turn
90
98
  * already in flight) and wants to clear the slate. */
@@ -1 +1 @@
1
- {"version":3,"file":"bridge-turn-queue.d.ts","sourceRoot":"","sources":["../../src/services/bridge-turn-queue.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,OAAO,EAAwB,uBAAuB,EAAyB,KAAK,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAIpI,OAAO,EAAE,uBAAuB,EAAE,CAAC;AAEnC,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,OAAO,CAAC;IACjB,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB;;;;+EAI2E;IAC3E,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;;gEAG4D;IAC5D,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;;2DAIuD;IACvD,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B;;;;;mBAKe;IACf,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB;;;wEAGoE;IACpE,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAQD;;;6CAG6C;AAC7C,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,SAAK,GAAG,MAAM,GAAG,SAAS,CAK7E;AAED,qBAAa,eAAe;IAC1B,OAAO,CAAC,IAAI,CAAqB;IACjC,OAAO,CAAC,KAAK,CAA2B;IACxC,OAAO,CAAC,UAAU,CAAkC;IAEpD;uEACmE;IACnE,MAAM,CAAC,MAAM,EAAE,eAAe,EAAE,GAAG,IAAI;IAMvC;;;;;;;8EAO0E;IAC1E,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,kBAAkB,CAAC,EAAE,MAAM,EAAE,UAAU,GAAE,MAAmB,GAAG,IAAI;IAIxF;;2DAEuD;IACvD,YAAY,IAAI,iBAAiB,EAAE;IAMnC;;;;;;;;yEAQqE;IACrE,MAAM,CAAC,MAAM,EAAE,eAAe,EAAE,EAAE,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI;IAoFjE;;gEAE4D;IAC5D,cAAc,IAAI,iBAAiB,EAAE;IAYrC,qDAAqD;IACrD,IAAI,IAAI,MAAM;IAId,qDAAqD;IACrD,IAAI,IAAI,SAAS,iBAAiB,EAAE;CAGrC"}
1
+ {"version":3,"file":"bridge-turn-queue.d.ts","sourceRoot":"","sources":["../../src/services/bridge-turn-queue.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,OAAO,EAAwB,uBAAuB,EAAyB,KAAK,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAIpI,OAAO,EAAE,uBAAuB,EAAE,CAAC;AAEnC,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,OAAO,CAAC;IACjB,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB;;;;+EAI2E;IAC3E,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;;gEAG4D;IAC5D,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;;2DAIuD;IACvD,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B;;;;;;oEAMgE;IAChE,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B;;;;;mBAKe;IACf,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB;;;wEAGoE;IACpE,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAQD;;;6CAG6C;AAC7C,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,SAAK,GAAG,MAAM,GAAG,SAAS,CAK7E;AAED,qBAAa,eAAe;IAC1B,OAAO,CAAC,IAAI,CAAqB;IACjC,OAAO,CAAC,KAAK,CAA2B;IACxC,OAAO,CAAC,UAAU,CAAkC;IAEpD;uEACmE;IACnE,MAAM,CAAC,MAAM,EAAE,eAAe,EAAE,GAAG,IAAI;IAMvC;;;;;;;8EAO0E;IAC1E,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,kBAAkB,CAAC,EAAE,MAAM,EAAE,UAAU,GAAE,MAAmB,EAAE,iBAAiB,CAAC,EAAE,MAAM,GAAG,IAAI;IAWpH;;2DAEuD;IACvD,YAAY,IAAI,iBAAiB,EAAE;IAMnC;;;;;;;;yEAQqE;IACrE,MAAM,CAAC,MAAM,EAAE,eAAe,EAAE,EAAE,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI;IAoFjE;;gEAE4D;IAC5D,cAAc,IAAI,iBAAiB,EAAE;IAYrC,qDAAqD;IACrD,IAAI,IAAI,MAAM;IAId,qDAAqD;IACrD,IAAI,IAAI,SAAS,iBAAiB,EAAE;CAGrC"}
@@ -71,8 +71,15 @@ export class BridgeTurnQueue {
71
71
  * `markTimeMs` is captured here so the rotation fallback can bound its
72
72
  * fingerprint scan to events written after this point — protects short
73
73
  * fingerprints from matching old history in unrelated sibling jsonls. */
74
- mark(turnId, contentFingerprint, markTimeMs = Date.now()) {
75
- this.queue.push({ turnId, started: false, assistantUuids: [], contentFingerprint, markTimeMs });
74
+ mark(turnId, contentFingerprint, markTimeMs = Date.now(), contentNormalized) {
75
+ this.queue.push({
76
+ turnId,
77
+ started: false,
78
+ assistantUuids: [],
79
+ contentFingerprint,
80
+ contentNormalized,
81
+ markTimeMs,
82
+ });
76
83
  }
77
84
  /** Drop all pending turns. Used when the worker discovers it can't
78
85
  * reliably attribute future events (e.g. baseline raced with a turn
@@ -1 +1 @@
1
- {"version":3,"file":"bridge-turn-queue.js","sourceRoot":"","sources":["../../src/services/bridge-turn-queue.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"bridge-turn-queue.js","sourceRoot":"","sources":["../../src/services/bridge-turn-queue.ts"],"names":[],"mappings":"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"}
@@ -153,6 +153,14 @@ export interface JsonlFingerprintSearchOptions {
153
153
  minEventTimestampMs?: number;
154
154
  /** Also match Claude Code type-ahead enqueue events, whose content is not role:user. */
155
155
  includeQueueOperations?: boolean;
156
+ /** Called on each candidate that already passed the fingerprint match.
157
+ * Returning `false` skips the candidate and continues searching older
158
+ * files in the directory (mtime-descending walk). Used by the bridge
159
+ * watcher to reject sibling-pane jsonls whose sessionId we don't trust,
160
+ * without losing the chance to find a legitimate /clear rotation buried
161
+ * under a busier sibling. Default (no callback): accept the first
162
+ * fingerprint match like the original behaviour. */
163
+ acceptCandidate?: (path: string) => boolean;
156
164
  }
157
165
  /** Scan a single jsonl file's tail for a Lark message fingerprint. Same
158
166
  * parsing rules as `findJsonlContainingFingerprint` (decode role:user content,
@@ -165,4 +173,63 @@ export declare function jsonlContainsFingerprint(path: string, fingerprint: stri
165
173
  minEventTimestampMs?: number;
166
174
  }): boolean;
167
175
  export declare function findJsonlContainingFingerprint(dir: string, fingerprint: string, excludePathOrOptions?: string | JsonlFingerprintSearchOptions): string | null;
176
+ /**
177
+ * Stronger sibling-pane recovery anchor than the substring fingerprint
178
+ * search. Walks every `.jsonl` in `dir` and returns the paths whose
179
+ * trailing 1MB contains a user/queue event whose normalised text is
180
+ * EXACTLY equal to `normalisedContent` (not a substring), respecting
181
+ * `excludePath`, `minMtimeMs`, `minEventTimestampMs`,
182
+ * `includeQueueOperations`, and `acceptCandidate` the same way as
183
+ * `findJsonlContainingFingerprint`.
184
+ *
185
+ * Returns *all* matches in mtime-descending order — callers must
186
+ * abstain when the result has length > 1, since multiple files containing
187
+ * the same exact normalised content cannot be disambiguated without
188
+ * stronger evidence (and forcing a switch would risk picking the wrong
189
+ * pane). The caller's typical pattern is:
190
+ *
191
+ * - 1 match → switch to it (legitimate post-/clear recovery)
192
+ * - 0 matches → no recovery this tick; wait for stronger signal
193
+ * - >1 match → log and abstain; surface a diagnostic to the user
194
+ *
195
+ * Used by the bridge fingerprint fallback's recovery path for in-pane
196
+ * `/clear`: substring matches risk hijacking on short fingerprints (the
197
+ * literal text "test" matches "run tests" / "test bridge"), but full
198
+ * equality on a Lark message we just wrote is a much stronger anchor.
199
+ */
200
+ export declare function findJsonlsContainingExactContent(dir: string, normalisedContent: string, options?: JsonlFingerprintSearchOptions): string[];
201
+ /**
202
+ * Partition transcript events into history (timestamp ≤ cutoff) and live
203
+ * (timestamp > cutoff, or no parseable timestamp). Used by the bridge
204
+ * watcher when it switches to a new jsonl that may contain pre-existing
205
+ * conversation: anything older than the cutoff (e.g. iTerm-typed turns
206
+ * the user produced before the Lark mark fired) belongs in the seen-set
207
+ * via `BridgeTurnQueue.absorb` so the worker doesn't replay them as
208
+ * "🖥️ 终端本地对话" cards. Anything newer is fed through `ingest()` so
209
+ * the freshly-written Lark user event can match its pending fingerprint.
210
+ *
211
+ * Events with malformed / missing timestamps fall into `live`: better
212
+ * to forward an unattributable event once than to silently drop a real
213
+ * reply because Claude omitted a timestamp.
214
+ */
215
+ export declare function splitTranscriptEventsByCutoff(events: TranscriptEvent[], cutoffMs: number): {
216
+ history: TranscriptEvent[];
217
+ live: TranscriptEvent[];
218
+ };
219
+ /**
220
+ * Read the first event timestamp out of a jsonl. Reads only the leading
221
+ * 4 KB — Claude's `file-history-snapshot` and `SessionStart` events both
222
+ * land in the first few hundred bytes. Returns the parsed millis, or
223
+ * undefined when no parseable timestamp is found in the leading chunk
224
+ * (corrupted file, partial first line, format change).
225
+ *
226
+ * NOTE: not currently wired into the bridge rotation flow. The bridge
227
+ * fingerprint fallback (`decideFingerprintSwitch` in
228
+ * `bridge-rotation-policy.ts`) deliberately rejects candidates outside
229
+ * the pid-derived trust set rather than relying on freshness heuristics
230
+ * — file-creation timestamps cannot prove ownership across panes in
231
+ * the same project dir. Kept here as a reusable primitive for
232
+ * diagnostics and future /clear-recovery work.
233
+ */
234
+ export declare function readFirstEventTimestamp(path: string): number | undefined;
168
235
  //# sourceMappingURL=claude-transcript.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"claude-transcript.d.ts","sourceRoot":"","sources":["../../src/services/claude-transcript.ts"],"names":[],"mappings":"AAgBA,+DAA+D;AAC/D,MAAM,WAAW,eAAe;IAC9B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE;QACR,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,OAAO,CAAC,EAAE,OAAO,CAAC;KACnB,CAAC;CACH;AAED,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,eAAe,EAAE,CAAC;IAC1B,kDAAkD;IAClD,SAAS,EAAE,MAAM,CAAC;IAClB;;wCAEoC;IACpC,WAAW,EAAE,MAAM,CAAC;CACrB;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,eAAe,CAC7B,IAAI,EAAE,MAAM,EACZ,UAAU,EAAE,MAAM,GACjB,WAAW,CA8Db;AAED;;;;;;;;GAQG;AACH,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,eAAe,EAAE,GAAG,eAAe,EAAE,CAapF;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,eAAe,GAAG,MAAM,CAYnE;AAED,sFAAsF;AACtF,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,eAAe,EAAE,GAAG,MAAM,CAKnE;AAeD;;;;;mCAKmC;AACnC,wBAAgB,qBAAqB,CAAC,EAAE,EAAE,eAAe,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO,CAcrF;AAED,MAAM,WAAW,aAAa;IAC5B;2EACuE;IACvE,QAAQ,EAAE,MAAM,CAAC;IACjB;;6DAEyD;IACzD,aAAa,EAAE,MAAM,CAAC;CACvB;AAED;;;;;;;;;;+DAU+D;AAC/D,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,eAAe,EAAE,GAAG,aAAa,GAAG,IAAI,CAyBxF;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAGnE;AAED;;;;;;;;GAQG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,CAS7D;AAED;;;;;GAKG;AACH,wBAAgB,uBAAuB,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAEzD;AAED;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAyB1D;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,WAAW,6BAA6B;IAC5C,6DAA6D;IAC7D,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,+EAA+E;IAC/E,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;wEAGoE;IACpE,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,wFAAwF;IACxF,sBAAsB,CAAC,EAAE,OAAO,CAAC;CAClC;AAED;;;;;6CAK6C;AAC7C,wBAAgB,wBAAwB,CACtC,IAAI,EAAE,MAAM,EACZ,WAAW,EAAE,MAAM,EACnB,IAAI,CAAC,EAAE;IAAE,sBAAsB,CAAC,EAAE,OAAO,CAAC;IAAC,mBAAmB,CAAC,EAAE,MAAM,CAAA;CAAE,GACxE,OAAO,CA6DT;AAED,wBAAgB,8BAA8B,CAC5C,GAAG,EAAE,MAAM,EACX,WAAW,EAAE,MAAM,EACnB,oBAAoB,CAAC,EAAE,MAAM,GAAG,6BAA6B,GAC5D,MAAM,GAAG,IAAI,CA2Ff"}
1
+ {"version":3,"file":"claude-transcript.d.ts","sourceRoot":"","sources":["../../src/services/claude-transcript.ts"],"names":[],"mappings":"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"}