mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-11-15 10:59:32 +01:00
fix: the live transcript lookup targets the exact tmux session (release review)
list-panes -t '=name' with no colon is a window target to tmux, so a remote session that is gone resolved to a window of that name or to a session the name is a prefix of, and the Edit history panel moved to that session's conversation and stored its diffs. `=name:` is an exact session match, as src/remote-pane-history.ts already uses. Measured on tmux 3.4. The fake tmux in the test matched the name as a substring, so it passed with or without the colon. It now needs the exact token and answers a bare prefix the way real tmux does. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
08d99da5ae
commit
81f8c8e894
2 files changed
+23
-2
No files matched your search
+5
-1
@@ -522,12 +522,16 @@ function claudeConfigDirLines(): string[] {
|
||||
* non-interactive shell may not list the directory it lives in, and a silent miss here leaves
|
||||
* the panel on the launch conversation after a `/clear`. The `export` stays inside the `$(…)`,
|
||||
* and inside this script, which runs under `sh` whatever the remote user's login shell is.
|
||||
*
|
||||
* ⚠️ `=name:` is an EXACT session match. Without the colon tmux reads a window target, so a
|
||||
* session that is gone resolves to a window of that name or a session the name is a prefix of,
|
||||
* and that session's conversation would land in this one's edit history.
|
||||
*/
|
||||
function liveClaudeIdLines(pane: RemoteClaudePane | undefined): string[] {
|
||||
if (!pane || !TMUX_NAME_PATTERN.test(pane.socket) || !TMUX_NAME_PATTERN.test(pane.sessionName)) return [];
|
||||
return [
|
||||
'live=',
|
||||
`pp=$(${withRemoteTmuxPath(`tmux -L ${shellescape(pane.socket)} list-panes -t ${shellescape(`=${pane.sessionName}`)} -F '#{pane_pid}' 2>/dev/null | head -n 1`)})`,
|
||||
`pp=$(${withRemoteTmuxPath(`tmux -L ${shellescape(pane.socket)} list-panes -t ${shellescape(`=${pane.sessionName}:`)} -F '#{pane_pid}' 2>/dev/null | head -n 1`)})`,
|
||||
"case $pp in ''|*[!0-9]*) pp= ;; esac",
|
||||
'if [ -n "$pp" ]; then',
|
||||
' tree=$(ps -A -o pid= -o ppid= 2>/dev/null)',
|
||||
|
||||
@@ -173,9 +173,20 @@ describe('the transcript lookup on a real shell', () => {
|
||||
bin = mkdtempSync(join(tmpdir(), 'codeman-fake-tmux-'));
|
||||
const localBin = join(home, '.local', 'bin');
|
||||
mkdirSync(localBin, { recursive: true });
|
||||
// Only the exact `=name:` target reaches the pane. Real tmux (3.4, measured) reads `=name`
|
||||
// without the colon as a window target too, so it also answers for a window of that name
|
||||
// or a session the name is a prefix of: the second pattern is that second case.
|
||||
writeFileSync(
|
||||
join(localBin, 'tmux'),
|
||||
'#!/bin/sh\ncase "$*" in *"=codeman-ssh-conv1abc"*) echo 100 ;; *) echo "no such session" >&2; exit 1 ;; esac\n'
|
||||
[
|
||||
'#!/bin/sh',
|
||||
'for a; do',
|
||||
' case "$a" in =codeman-ssh-conv1abc:|=codeman-ssh-conv1) echo 100; exit 0 ;; esac',
|
||||
'done',
|
||||
'echo "no such session" >&2',
|
||||
'exit 1',
|
||||
'',
|
||||
].join('\n')
|
||||
);
|
||||
writeFileSync(join(bin, 'ps'), '#!/bin/sh\nprintf " 1 0\\n100 1\\n200 100\\n300 200\\n"\n');
|
||||
chmodSync(join(localBin, 'tmux'), 0o755);
|
||||
@@ -210,6 +221,12 @@ describe('the transcript lookup on a real shell', () => {
|
||||
expect(locateIn(pane)).toBe(join(projects(), 'new', 'conv-1.jsonl'));
|
||||
});
|
||||
|
||||
it('never takes the pane of another tmux session whose name starts with this one', () => {
|
||||
// codeman-ssh-conv1 is gone, codeman-ssh-conv1abc is alive: its conversation is not ours.
|
||||
session('{"pid":300,"sessionId":"solo"}');
|
||||
expect(locateIn({ ...pane, sessionName: 'codeman-ssh-conv1' })).toBe(join(projects(), 'new', 'conv-1.jsonl'));
|
||||
});
|
||||
|
||||
it('reads the live id from the sessions dir under CLAUDE_CONFIG_DIR', () => {
|
||||
const cfg = join(home, 'alt-config');
|
||||
mkdirSync(join(cfg, 'sessions'), { recursive: true });
|
||||
|
||||
Reference in new issue
Block a user