-
Notifications
You must be signed in to change notification settings - Fork 7
Expand file tree
/
Copy pathtmux-agent-status.ts
More file actions
121 lines (104 loc) · 3 KB
/
Copy pathtmux-agent-status.ts
File metadata and controls
121 lines (104 loc) · 3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
import { execFileSync } from 'node:child_process'
import { existsSync, readFileSync, rmSync, writeFileSync } from 'node:fs'
import { tmpdir } from 'node:os'
import { basename, join } from 'node:path'
import type { ExtensionAPI } from '@earendil-works/pi-coding-agent'
const TMUX = process.env.TMUX
const TMUX_PANE = process.env.TMUX_PANE
const STATE_FILE = join(tmpdir(), `tmux-pi-window-${TMUX_PANE ?? process.pid}`)
function inTmux(): boolean {
return Boolean(TMUX)
}
function exec(command: string, args: string[], cwd?: string): string | undefined {
try {
return execFileSync(command, args, {
cwd,
encoding: 'utf8',
stdio: ['ignore', 'pipe', 'ignore'],
env: { ...process.env, GIT_OPTIONAL_LOCKS: '0' },
}).trim()
} catch {
return undefined
}
}
function git(cwd: string, args: string[]): string | undefined {
return exec('git', args, cwd)
}
function computeBaseName(cwd: string): string {
let baseName = ''
const gitDir = git(cwd, ['rev-parse', '--git-dir'])
if (gitDir?.includes('.git/worktrees/')) {
baseName = git(cwd, ['rev-parse', '--abbrev-ref', 'HEAD']) ?? ''
}
if (!baseName || baseName === 'HEAD') baseName = basename(cwd)
return baseName
}
function setBaseName(cwd: string): string {
const baseName = computeBaseName(cwd)
writeFileSync(STATE_FILE, baseName)
return baseName
}
function getBaseName(cwd: string): string {
if (existsSync(STATE_FILE)) return readFileSync(STATE_FILE, 'utf8').trim()
return setBaseName(cwd)
}
function renameWindow(name: string): void {
if (!inTmux()) return
const args = TMUX_PANE ? ['rename-window', '-t', TMUX_PANE, name] : ['rename-window', name]
try {
execFileSync('tmux', args, { stdio: 'ignore' })
} catch {
// Ignore failures outside attached tmux clients or with unsupported targets.
}
}
function toolIcon(toolName: string): string {
switch (toolName.toLowerCase()) {
case 'bash':
return '🖥️'
case 'read':
return '📖'
case 'edit':
return '✏️'
case 'write':
return '💾'
case 'grep':
return '🔍'
case 'glob':
case 'find':
case 'ls':
return '📂'
case 'task':
case 'agent':
return '🤖'
case 'webfetch':
case 'web_fetch':
return '🌐'
case 'websearch':
case 'web_search':
return '🔎'
case 'askuserquestion':
case 'ask_user_question':
return '❓'
default:
return '🔄'
}
}
export default function (pi: ExtensionAPI) {
if (!inTmux()) return
pi.on('session_start', (_event, ctx) => {
renameWindow(setBaseName(ctx.cwd))
})
pi.on('input', (_event, ctx) => {
renameWindow(`🔄 ${getBaseName(ctx.cwd)}`)
})
pi.on('tool_call', (event, ctx) => {
renameWindow(`${toolIcon(event.toolName)} ${getBaseName(ctx.cwd)}`)
})
pi.on('agent_end', (_event, ctx) => {
renameWindow(`🟢 ${getBaseName(ctx.cwd)}`)
})
pi.on('session_shutdown', (_event, ctx) => {
renameWindow(getBaseName(ctx.cwd))
rmSync(STATE_FILE, { force: true })
})
}