@k1e1n04/mav 0.1.31 → 0.1.32
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/README.md +3 -1
- package/dist/package.json +1 -1
- package/dist/src/process-cwd.js +85 -27
- package/dist/src/process-cwd.js.map +1 -1
- package/package.json +1 -1
- package/src/process-cwd.ts +90 -26
package/README.md
CHANGED
|
@@ -120,13 +120,15 @@ mav tracks each agent's working directory. When an agent changes directory (e.g.
|
|
|
120
120
|
|
|
121
121
|
| Agent | CWD Tracking | Hook Auto-injection |
|
|
122
122
|
|---|---|---|
|
|
123
|
-
| `claude-code` |
|
|
123
|
+
| `claude-code` | child PID polling + OSC 7 | ❌ No injection needed |
|
|
124
124
|
| `gemini-cli` | IPC + AfterTool hook | ✅ Auto-injected via `.gemini/settings.local.json` |
|
|
125
125
|
| `codex` | IPC + PostToolUse hook | ✅ Auto-injected via `--profile-v2` |
|
|
126
126
|
| `copilot` | IPC + PostToolUse hook | ✅ Auto-injected via `.github/hooks/*.json` |
|
|
127
127
|
| `cursor` | lsof polling only | ❌ Not supported |
|
|
128
128
|
| Other | lsof polling only | ❌ Not supported |
|
|
129
129
|
|
|
130
|
+
`claude-code` CWD tracking works by finding the Claude Code process (direct child of the shell PTY) and polling its own working directory. This correctly captures `process.chdir()` calls made by Claude Code when switching git worktrees, without any hook injection.
|
|
131
|
+
|
|
130
132
|
> **Cursor** and unlisted agents use process polling to track the working directory.
|
|
131
133
|
> Directory changes made in child processes (e.g., git worktrees) may not be detected.
|
|
132
134
|
>
|
package/dist/package.json
CHANGED
package/dist/src/process-cwd.js
CHANGED
|
@@ -21,50 +21,108 @@ export function getProcessCwd(pid, platform = process.platform) {
|
|
|
21
21
|
}
|
|
22
22
|
return null;
|
|
23
23
|
}
|
|
24
|
+
const CLAUDE_CHILD_MAX_DEPTH = 5;
|
|
24
25
|
export function getClaudeChildPid(shellPid, platform = process.platform) {
|
|
25
26
|
if (!Number.isInteger(shellPid) || shellPid <= 0) {
|
|
26
27
|
return null;
|
|
27
28
|
}
|
|
29
|
+
if (platform === 'darwin') {
|
|
30
|
+
return findClaudeChildDarwin(shellPid);
|
|
31
|
+
}
|
|
32
|
+
if (platform === 'linux') {
|
|
33
|
+
return findClaudeChildLinux(shellPid);
|
|
34
|
+
}
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
function findClaudeChildDarwin(shellPid) {
|
|
38
|
+
let initialChildren;
|
|
28
39
|
try {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
40
|
+
initialChildren = execFileSync('pgrep', ['-P', String(shellPid)], { encoding: 'utf8' })
|
|
41
|
+
.split('\n')
|
|
42
|
+
.map((s) => s.trim())
|
|
43
|
+
.filter(Boolean);
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
48
|
+
const queue = initialChildren.map((p) => ({ pidStr: p, depth: 0 }));
|
|
49
|
+
while (queue.length > 0) {
|
|
50
|
+
const item = queue.shift();
|
|
51
|
+
if (item.depth >= CLAUDE_CHILD_MAX_DEPTH)
|
|
52
|
+
continue;
|
|
53
|
+
try {
|
|
54
|
+
const line = execFileSync('ps', ['-o', 'pid=,args=', '-p', item.pidStr], { encoding: 'utf8' }).trim();
|
|
55
|
+
if (line) {
|
|
38
56
|
const spaceIdx = line.search(/\s/);
|
|
39
|
-
if (spaceIdx
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
57
|
+
if (spaceIdx !== -1) {
|
|
58
|
+
const args = line.slice(spaceIdx).trim();
|
|
59
|
+
const binary = args.split(' ')[0] ?? '';
|
|
60
|
+
if ((binary === 'node' || binary.endsWith('/node')) && args.includes('claude')) {
|
|
61
|
+
return parseInt(item.pidStr, 10);
|
|
62
|
+
}
|
|
45
63
|
}
|
|
46
64
|
}
|
|
47
|
-
return null;
|
|
48
65
|
}
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
66
|
+
catch {
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
69
|
+
// Not claude — enqueue children for next level
|
|
70
|
+
try {
|
|
71
|
+
const children = execFileSync('pgrep', ['-P', item.pidStr], { encoding: 'utf8' })
|
|
72
|
+
.split('\n')
|
|
52
73
|
.map((s) => s.trim())
|
|
53
74
|
.filter(Boolean);
|
|
54
|
-
for (const
|
|
55
|
-
|
|
56
|
-
const parts = cmdline.split('\0').filter(Boolean);
|
|
57
|
-
const binary = parts[0] ?? '';
|
|
58
|
-
if ((binary === 'node' || binary.endsWith('/node')) && cmdline.includes('claude')) {
|
|
59
|
-
return parseInt(pidStr, 10);
|
|
60
|
-
}
|
|
75
|
+
for (const child of children) {
|
|
76
|
+
queue.push({ pidStr: child, depth: item.depth + 1 });
|
|
61
77
|
}
|
|
62
|
-
return null;
|
|
63
78
|
}
|
|
79
|
+
catch {
|
|
80
|
+
// No children — continue
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
return null;
|
|
84
|
+
}
|
|
85
|
+
function findClaudeChildLinux(shellPid) {
|
|
86
|
+
let initialChildren;
|
|
87
|
+
try {
|
|
88
|
+
initialChildren = readFileSync(`/proc/${shellPid}/task/${shellPid}/children`, 'utf8')
|
|
89
|
+
.split(' ')
|
|
90
|
+
.map((s) => s.trim())
|
|
91
|
+
.filter(Boolean);
|
|
64
92
|
}
|
|
65
93
|
catch {
|
|
66
94
|
return null;
|
|
67
95
|
}
|
|
96
|
+
const queue = initialChildren.map((p) => ({ pidStr: p, depth: 0 }));
|
|
97
|
+
while (queue.length > 0) {
|
|
98
|
+
const item = queue.shift();
|
|
99
|
+
if (item.depth >= CLAUDE_CHILD_MAX_DEPTH)
|
|
100
|
+
continue;
|
|
101
|
+
try {
|
|
102
|
+
const cmdline = readFileSync(`/proc/${item.pidStr}/cmdline`, 'utf8');
|
|
103
|
+
const parts = cmdline.split('\0').filter(Boolean);
|
|
104
|
+
const binary = parts[0] ?? '';
|
|
105
|
+
if ((binary === 'node' || binary.endsWith('/node')) && cmdline.includes('claude')) {
|
|
106
|
+
return parseInt(item.pidStr, 10);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
catch {
|
|
110
|
+
continue;
|
|
111
|
+
}
|
|
112
|
+
// Not claude — enqueue children for next level
|
|
113
|
+
try {
|
|
114
|
+
const children = readFileSync(`/proc/${item.pidStr}/task/${item.pidStr}/children`, 'utf8')
|
|
115
|
+
.split(' ')
|
|
116
|
+
.map((s) => s.trim())
|
|
117
|
+
.filter(Boolean);
|
|
118
|
+
for (const child of children) {
|
|
119
|
+
queue.push({ pidStr: child, depth: item.depth + 1 });
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
catch {
|
|
123
|
+
// No children — continue
|
|
124
|
+
}
|
|
125
|
+
}
|
|
68
126
|
return null;
|
|
69
127
|
}
|
|
70
128
|
//# sourceMappingURL=process-cwd.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"process-cwd.js","sourceRoot":"","sources":["../../src/process-cwd.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AACjD,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AAEpD,MAAM,UAAU,aAAa,CAAC,GAAW,EAAE,WAA4B,OAAO,CAAC,QAAQ;IACrF,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,EAAE,CAAC;QACvC,OAAO,IAAI,CAAA;IACb,CAAC;IAED,IAAI,CAAC;QACH,IAAI,QAAQ,KAAK,OAAO,EAAE,CAAC;YACzB,OAAO,YAAY,CAAC,SAAS,GAAG,MAAM,CAAC,CAAA;QACzC,CAAC;QAED,IAAI,QAAQ,KAAK,QAAQ,EAAE,CAAC;YAC1B,MAAM,MAAM,GAAG,YAAY,CACzB,MAAM,EACN,CAAC,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC,EAC7C,EAAE,QAAQ,EAAE,MAAM,EAAE,CACrB,CAAA;YACD,MAAM,OAAO,GAAG,MAAM;iBACnB,KAAK,CAAC,IAAI,CAAC;iBACX,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,IAAI,KAAK,IAAI,CAAC,CAAA;YAEzD,OAAO,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAA;QAC1C,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAA;IACb,CAAC;IAED,OAAO,IAAI,CAAA;AACb,CAAC;AAED,MAAM,UAAU,iBAAiB,CAC/B,QAAgB,EAChB,WAA4B,OAAO,CAAC,QAAQ;IAE5C,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,QAAQ,IAAI,CAAC,EAAE,CAAC;QACjD,OAAO,IAAI,CAAA;IACb,CAAC;IAED,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"process-cwd.js","sourceRoot":"","sources":["../../src/process-cwd.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
package/src/process-cwd.ts
CHANGED
|
@@ -30,6 +30,8 @@ export function getProcessCwd(pid: number, platform: NodeJS.Platform = process.p
|
|
|
30
30
|
return null
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
+
const CLAUDE_CHILD_MAX_DEPTH = 5
|
|
34
|
+
|
|
33
35
|
export function getClaudeChildPid(
|
|
34
36
|
shellPid: number,
|
|
35
37
|
platform: NodeJS.Platform = process.platform,
|
|
@@ -38,46 +40,108 @@ export function getClaudeChildPid(
|
|
|
38
40
|
return null
|
|
39
41
|
}
|
|
40
42
|
|
|
43
|
+
if (platform === 'darwin') {
|
|
44
|
+
return findClaudeChildDarwin(shellPid)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (platform === 'linux') {
|
|
48
|
+
return findClaudeChildLinux(shellPid)
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return null
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function findClaudeChildDarwin(shellPid: number): number | null {
|
|
55
|
+
let initialChildren: string[]
|
|
41
56
|
try {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
57
|
+
initialChildren = execFileSync('pgrep', ['-P', String(shellPid)], { encoding: 'utf8' })
|
|
58
|
+
.split('\n')
|
|
59
|
+
.map((s) => s.trim())
|
|
60
|
+
.filter(Boolean)
|
|
61
|
+
} catch {
|
|
62
|
+
return null
|
|
63
|
+
}
|
|
47
64
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
65
|
+
const queue: Array<{ pidStr: string; depth: number }> = initialChildren.map((p) => ({ pidStr: p, depth: 0 }))
|
|
66
|
+
|
|
67
|
+
while (queue.length > 0) {
|
|
68
|
+
const item = queue.shift()!
|
|
69
|
+
if (item.depth >= CLAUDE_CHILD_MAX_DEPTH) continue
|
|
70
|
+
|
|
71
|
+
try {
|
|
72
|
+
const line = execFileSync('ps', ['-o', 'pid=,args=', '-p', item.pidStr], { encoding: 'utf8' }).trim()
|
|
73
|
+
if (line) {
|
|
51
74
|
const spaceIdx = line.search(/\s/)
|
|
52
|
-
if (spaceIdx
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
75
|
+
if (spaceIdx !== -1) {
|
|
76
|
+
const args = line.slice(spaceIdx).trim()
|
|
77
|
+
const binary = args.split(' ')[0] ?? ''
|
|
78
|
+
if ((binary === 'node' || binary.endsWith('/node')) && args.includes('claude')) {
|
|
79
|
+
return parseInt(item.pidStr, 10)
|
|
80
|
+
}
|
|
57
81
|
}
|
|
58
82
|
}
|
|
59
|
-
|
|
83
|
+
} catch {
|
|
84
|
+
continue
|
|
60
85
|
}
|
|
61
86
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
87
|
+
// Not claude — enqueue children for next level
|
|
88
|
+
try {
|
|
89
|
+
const children = execFileSync('pgrep', ['-P', item.pidStr], { encoding: 'utf8' })
|
|
90
|
+
.split('\n')
|
|
65
91
|
.map((s) => s.trim())
|
|
66
92
|
.filter(Boolean)
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
const cmdline = readFileSync(`/proc/${pidStr}/cmdline`, 'utf8')
|
|
70
|
-
const parts = cmdline.split('\0').filter(Boolean)
|
|
71
|
-
const binary = parts[0] ?? ''
|
|
72
|
-
if ((binary === 'node' || binary.endsWith('/node')) && cmdline.includes('claude')) {
|
|
73
|
-
return parseInt(pidStr, 10)
|
|
74
|
-
}
|
|
93
|
+
for (const child of children) {
|
|
94
|
+
queue.push({ pidStr: child, depth: item.depth + 1 })
|
|
75
95
|
}
|
|
76
|
-
|
|
96
|
+
} catch {
|
|
97
|
+
// No children — continue
|
|
77
98
|
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
return null
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function findClaudeChildLinux(shellPid: number): number | null {
|
|
105
|
+
let initialChildren: string[]
|
|
106
|
+
try {
|
|
107
|
+
initialChildren = readFileSync(`/proc/${shellPid}/task/${shellPid}/children`, 'utf8')
|
|
108
|
+
.split(' ')
|
|
109
|
+
.map((s) => s.trim())
|
|
110
|
+
.filter(Boolean)
|
|
78
111
|
} catch {
|
|
79
112
|
return null
|
|
80
113
|
}
|
|
81
114
|
|
|
115
|
+
const queue: Array<{ pidStr: string; depth: number }> = initialChildren.map((p) => ({ pidStr: p, depth: 0 }))
|
|
116
|
+
|
|
117
|
+
while (queue.length > 0) {
|
|
118
|
+
const item = queue.shift()!
|
|
119
|
+
if (item.depth >= CLAUDE_CHILD_MAX_DEPTH) continue
|
|
120
|
+
|
|
121
|
+
try {
|
|
122
|
+
const cmdline = readFileSync(`/proc/${item.pidStr}/cmdline`, 'utf8')
|
|
123
|
+
const parts = cmdline.split('\0').filter(Boolean)
|
|
124
|
+
const binary = parts[0] ?? ''
|
|
125
|
+
if ((binary === 'node' || binary.endsWith('/node')) && cmdline.includes('claude')) {
|
|
126
|
+
return parseInt(item.pidStr, 10)
|
|
127
|
+
}
|
|
128
|
+
} catch {
|
|
129
|
+
continue
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// Not claude — enqueue children for next level
|
|
133
|
+
try {
|
|
134
|
+
const children = readFileSync(`/proc/${item.pidStr}/task/${item.pidStr}/children`, 'utf8')
|
|
135
|
+
.split(' ')
|
|
136
|
+
.map((s) => s.trim())
|
|
137
|
+
.filter(Boolean)
|
|
138
|
+
for (const child of children) {
|
|
139
|
+
queue.push({ pidStr: child, depth: item.depth + 1 })
|
|
140
|
+
}
|
|
141
|
+
} catch {
|
|
142
|
+
// No children — continue
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
82
146
|
return null
|
|
83
147
|
}
|