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.
- package/dist/adapters/cli/claude-code.d.ts +9 -3
- package/dist/adapters/cli/claude-code.d.ts.map +1 -1
- package/dist/adapters/cli/claude-code.js +20 -12
- package/dist/adapters/cli/claude-code.js.map +1 -1
- package/dist/core/session-discovery.d.ts.map +1 -1
- package/dist/core/session-discovery.js +11 -1
- package/dist/core/session-discovery.js.map +1 -1
- package/dist/core/worker-pool.d.ts.map +1 -1
- package/dist/core/worker-pool.js +13 -9
- package/dist/core/worker-pool.js.map +1 -1
- package/dist/daemon.js +10 -9
- package/dist/daemon.js.map +1 -1
- package/dist/services/bridge-rotation-policy.d.ts +139 -0
- package/dist/services/bridge-rotation-policy.d.ts.map +1 -0
- package/dist/services/bridge-rotation-policy.js +125 -0
- package/dist/services/bridge-rotation-policy.js.map +1 -0
- package/dist/services/bridge-turn-queue.d.ts +9 -1
- package/dist/services/bridge-turn-queue.d.ts.map +1 -1
- package/dist/services/bridge-turn-queue.js +9 -2
- package/dist/services/bridge-turn-queue.js.map +1 -1
- package/dist/services/claude-transcript.d.ts +67 -0
- package/dist/services/claude-transcript.d.ts.map +1 -1
- package/dist/services/claude-transcript.js +228 -1
- package/dist/services/claude-transcript.js.map +1 -1
- package/dist/services/codex-bridge-queue.d.ts +56 -0
- package/dist/services/codex-bridge-queue.d.ts.map +1 -0
- package/dist/services/codex-bridge-queue.js +150 -0
- package/dist/services/codex-bridge-queue.js.map +1 -0
- package/dist/services/codex-transcript.d.ts +68 -0
- package/dist/services/codex-transcript.d.ts.map +1 -0
- package/dist/services/codex-transcript.js +233 -0
- package/dist/services/codex-transcript.js.map +1 -0
- package/dist/utils/idle-detector.d.ts.map +1 -1
- package/dist/utils/idle-detector.js +15 -4
- package/dist/utils/idle-detector.js.map +1 -1
- package/dist/worker.js +743 -114
- package/dist/worker.js.map +1 -1
- 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;
|
|
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({
|
|
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":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,OAAO,EAAE,oBAAoB,EAAE,uBAAuB,EAAE,qBAAqB,EAAwB,MAAM,wBAAwB,CAAC;AAEpI,wEAAwE;AACxE,yEAAyE;AACzE,OAAO,EAAE,uBAAuB,EAAE,CAAC;
|
|
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;
|
|
1
|
+
{"version":3,"file":"claude-transcript.d.ts","sourceRoot":"","sources":["../../src/services/claude-transcript.ts"],"names":[],"mappings":"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"}
|