@k1e1n04/mav 0.1.30 → 0.1.31
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/package.json +1 -1
- package/dist/src/agent.d.ts +1 -0
- package/dist/src/agent.js +23 -2
- package/dist/src/agent.js.map +1 -1
- package/dist/src/hook-injector.js +2 -83
- package/dist/src/hook-injector.js.map +1 -1
- package/dist/src/process-cwd.d.ts +1 -0
- package/dist/src/process-cwd.js +47 -1
- package/dist/src/process-cwd.js.map +1 -1
- package/package.json +1 -1
- package/src/agent.ts +20 -2
- package/src/hook-injector.ts +2 -101
- package/src/process-cwd.ts +53 -1
package/dist/package.json
CHANGED
package/dist/src/agent.d.ts
CHANGED
package/dist/src/agent.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { EventEmitter } from 'node:events';
|
|
2
2
|
import * as pty from 'node-pty';
|
|
3
|
-
import { getProcessCwd } from './process-cwd.js';
|
|
3
|
+
import { getProcessCwd, getClaudeChildPid } from './process-cwd.js';
|
|
4
4
|
import { cleanupHookFiles } from './hook-injector.js';
|
|
5
5
|
const counters = {};
|
|
6
6
|
export class AgentSession extends EventEmitter {
|
|
@@ -22,6 +22,7 @@ export class AgentSession extends EventEmitter {
|
|
|
22
22
|
exited = false;
|
|
23
23
|
idleTimer = null;
|
|
24
24
|
cwdPollTimer = null;
|
|
25
|
+
claudeChildPid = null;
|
|
25
26
|
displayNameLocked = false;
|
|
26
27
|
initialInputBuffer = '';
|
|
27
28
|
hookFiles = [];
|
|
@@ -41,6 +42,11 @@ export class AgentSession extends EventEmitter {
|
|
|
41
42
|
env.MAV_SESSION_ID = this.id;
|
|
42
43
|
this.hookFiles = ipcContext.hookFiles;
|
|
43
44
|
}
|
|
45
|
+
else {
|
|
46
|
+
// Prevent child processes from inheriting the parent mav session's socket
|
|
47
|
+
delete env.MAV_SOCKET;
|
|
48
|
+
delete env.MAV_SESSION_ID;
|
|
49
|
+
}
|
|
44
50
|
proc = pty.spawn(config.cmd, config.args, {
|
|
45
51
|
name: 'xterm-256color',
|
|
46
52
|
cols,
|
|
@@ -153,7 +159,22 @@ export class AgentSession extends EventEmitter {
|
|
|
153
159
|
if (this.exited || !this.ptyProcess) {
|
|
154
160
|
return;
|
|
155
161
|
}
|
|
156
|
-
|
|
162
|
+
if (this.type === 'claude-code') {
|
|
163
|
+
if (this.claudeChildPid === null) {
|
|
164
|
+
this.claudeChildPid = getClaudeChildPid(this.ptyProcess.pid);
|
|
165
|
+
}
|
|
166
|
+
const targetPid = this.claudeChildPid ?? this.ptyProcess.pid;
|
|
167
|
+
const cwd = getProcessCwd(targetPid);
|
|
168
|
+
if (cwd === null && this.claudeChildPid !== null) {
|
|
169
|
+
this.claudeChildPid = null;
|
|
170
|
+
}
|
|
171
|
+
else {
|
|
172
|
+
this.updateCwd(cwd);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
else {
|
|
176
|
+
this.updateCwd(getProcessCwd(this.ptyProcess.pid));
|
|
177
|
+
}
|
|
157
178
|
}, AgentSession.CWD_POLL_INTERVAL_MS);
|
|
158
179
|
}
|
|
159
180
|
clearCwdPollTimer() {
|
package/dist/src/agent.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent.js","sourceRoot":"","sources":["../../src/agent.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAC1C,OAAO,KAAK,GAAG,MAAM,UAAU,CAAA;AAE/B,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAA;
|
|
1
|
+
{"version":3,"file":"agent.js","sourceRoot":"","sources":["../../src/agent.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { writeFileSync, readFileSync, existsSync, unlinkSync, mkdirSync } from 'node:fs';
|
|
2
2
|
import { join } from 'node:path';
|
|
3
|
-
import { homedir
|
|
4
|
-
import { randomUUID
|
|
3
|
+
import { homedir } from 'node:os';
|
|
4
|
+
import { randomUUID } from 'node:crypto';
|
|
5
5
|
/**
|
|
6
6
|
* Injects a hook into the startup args for the given agent type and returns the result.
|
|
7
7
|
* Generated temp files are listed in hookFiles.
|
|
@@ -9,8 +9,6 @@ import { randomUUID, createHash } from 'node:crypto';
|
|
|
9
9
|
*/
|
|
10
10
|
export function buildHookArgs(agentType, baseArgs, hookCommand, options = {}) {
|
|
11
11
|
switch (agentType) {
|
|
12
|
-
case 'claude-code':
|
|
13
|
-
return buildClaudeCodeHook(baseArgs, hookCommand, options.cmd, options.settingsFile);
|
|
14
12
|
case 'gemini-cli':
|
|
15
13
|
return buildGeminiHook(baseArgs, hookCommand, options.cwd);
|
|
16
14
|
case 'copilot':
|
|
@@ -21,85 +19,6 @@ export function buildHookArgs(agentType, baseArgs, hookCommand, options = {}) {
|
|
|
21
19
|
return { args: baseArgs, hookFiles: [] };
|
|
22
20
|
}
|
|
23
21
|
}
|
|
24
|
-
function buildClaudeCodeHook(baseArgs, hookCommand, cmd, settingsFile) {
|
|
25
|
-
// If a custom wrapper is used (e.g. claude-launcher), skip --settings <json> injection.
|
|
26
|
-
// Wrappers detect --settings in their args and skip their own overlay (including
|
|
27
|
-
// apiKeyHelper), which breaks authentication.
|
|
28
|
-
if (cmd != null && cmd !== 'claude') {
|
|
29
|
-
if (settingsFile) {
|
|
30
|
-
return buildClaudeCodeHookViaFile(baseArgs, hookCommand, settingsFile);
|
|
31
|
-
}
|
|
32
|
-
return { args: baseArgs, hookFiles: [] };
|
|
33
|
-
}
|
|
34
|
-
const claudeSettingsPath = join(homedir(), '.claude', 'settings.json');
|
|
35
|
-
let existing = {};
|
|
36
|
-
if (existsSync(claudeSettingsPath)) {
|
|
37
|
-
try {
|
|
38
|
-
existing = JSON.parse(readFileSync(claudeSettingsPath, 'utf-8'));
|
|
39
|
-
}
|
|
40
|
-
catch {
|
|
41
|
-
// Unreadable/invalid JSON — start from empty
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
const existingHooks = (existing.hooks ?? {});
|
|
45
|
-
const existingPostToolUse = (existingHooks.PostToolUse ?? []);
|
|
46
|
-
const merged = {
|
|
47
|
-
...existing,
|
|
48
|
-
hooks: {
|
|
49
|
-
...existingHooks,
|
|
50
|
-
PostToolUse: [
|
|
51
|
-
...existingPostToolUse,
|
|
52
|
-
{
|
|
53
|
-
matcher: '',
|
|
54
|
-
hooks: [{ type: 'command', command: hookCommand }],
|
|
55
|
-
},
|
|
56
|
-
],
|
|
57
|
-
},
|
|
58
|
-
};
|
|
59
|
-
return {
|
|
60
|
-
args: [...baseArgs, '--settings', JSON.stringify(merged)],
|
|
61
|
-
hookFiles: [],
|
|
62
|
-
};
|
|
63
|
-
}
|
|
64
|
-
function buildClaudeCodeHookViaFile(baseArgs, hookCommand, settingsFile) {
|
|
65
|
-
const expandedPath = settingsFile.replace(/^~/, homedir());
|
|
66
|
-
// Read the overlay file BEFORE the wrapper starts (and potentially overwrites it).
|
|
67
|
-
// The wrapper's overlay content (apiKeyHelper etc.) is preserved in the temp file,
|
|
68
|
-
// so even though the wrapper skips its own overlay injection, auth still works.
|
|
69
|
-
let existing = {};
|
|
70
|
-
if (existsSync(expandedPath)) {
|
|
71
|
-
try {
|
|
72
|
-
existing = JSON.parse(readFileSync(expandedPath, 'utf-8'));
|
|
73
|
-
}
|
|
74
|
-
catch {
|
|
75
|
-
// Treat as empty
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
const existingHooks = (existing.hooks ?? {});
|
|
79
|
-
const existingPostToolUse = (existingHooks.PostToolUse ?? []);
|
|
80
|
-
const merged = {
|
|
81
|
-
...existing,
|
|
82
|
-
hooks: {
|
|
83
|
-
...existingHooks,
|
|
84
|
-
PostToolUse: [
|
|
85
|
-
...existingPostToolUse,
|
|
86
|
-
{
|
|
87
|
-
matcher: '',
|
|
88
|
-
hooks: [{ type: 'command', command: hookCommand }],
|
|
89
|
-
},
|
|
90
|
-
],
|
|
91
|
-
},
|
|
92
|
-
};
|
|
93
|
-
// Use a deterministic name based on the settingsFile path so that at most one
|
|
94
|
-
// temp file exists per overlay path — crash leftovers get overwritten next run.
|
|
95
|
-
const pathHash = createHash('sha256').update(expandedPath).digest('hex').slice(0, 8);
|
|
96
|
-
const tempPath = join(tmpdir(), `mav-settings-${pathHash}.json`);
|
|
97
|
-
writeFileSync(tempPath, JSON.stringify(merged, null, 2));
|
|
98
|
-
return {
|
|
99
|
-
args: [...baseArgs, '--settings', tempPath],
|
|
100
|
-
hookFiles: [tempPath],
|
|
101
|
-
};
|
|
102
|
-
}
|
|
103
22
|
const MAV_MARKER = '_mavGenerated';
|
|
104
23
|
function buildGeminiHook(baseArgs, hookCommand, cwd) {
|
|
105
24
|
const projectDir = cwd ?? process.cwd();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hook-injector.js","sourceRoot":"","sources":["../../src/hook-injector.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,UAAU,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,SAAS,CAAA;AACxF,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAChC,OAAO,EAAE,OAAO,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"hook-injector.js","sourceRoot":"","sources":["../../src/hook-injector.ts"],"names":[],"mappings":"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"}
|
package/dist/src/process-cwd.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { execFileSync } from 'node:child_process';
|
|
2
|
-
import { readlinkSync } from 'node:fs';
|
|
2
|
+
import { readlinkSync, readFileSync } from 'node:fs';
|
|
3
3
|
export function getProcessCwd(pid, platform = process.platform) {
|
|
4
4
|
if (!Number.isInteger(pid) || pid <= 0) {
|
|
5
5
|
return null;
|
|
@@ -21,4 +21,50 @@ export function getProcessCwd(pid, platform = process.platform) {
|
|
|
21
21
|
}
|
|
22
22
|
return null;
|
|
23
23
|
}
|
|
24
|
+
export function getClaudeChildPid(shellPid, platform = process.platform) {
|
|
25
|
+
if (!Number.isInteger(shellPid) || shellPid <= 0) {
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
try {
|
|
29
|
+
if (platform === 'darwin') {
|
|
30
|
+
const childPids = execFileSync('pgrep', ['-P', String(shellPid)], { encoding: 'utf8' })
|
|
31
|
+
.split('\n')
|
|
32
|
+
.map((s) => s.trim())
|
|
33
|
+
.filter(Boolean);
|
|
34
|
+
for (const pidStr of childPids) {
|
|
35
|
+
const line = execFileSync('ps', ['-o', 'pid=,args=', '-p', pidStr], { encoding: 'utf8' }).trim();
|
|
36
|
+
if (!line)
|
|
37
|
+
continue;
|
|
38
|
+
const spaceIdx = line.search(/\s/);
|
|
39
|
+
if (spaceIdx === -1)
|
|
40
|
+
continue;
|
|
41
|
+
const args = line.slice(spaceIdx).trim();
|
|
42
|
+
const binary = args.split(' ')[0] ?? '';
|
|
43
|
+
if ((binary === 'node' || binary.endsWith('/node')) && args.includes('claude')) {
|
|
44
|
+
return parseInt(pidStr, 10);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
if (platform === 'linux') {
|
|
50
|
+
const childPids = readFileSync(`/proc/${shellPid}/task/${shellPid}/children`, 'utf8')
|
|
51
|
+
.split(' ')
|
|
52
|
+
.map((s) => s.trim())
|
|
53
|
+
.filter(Boolean);
|
|
54
|
+
for (const pidStr of childPids) {
|
|
55
|
+
const cmdline = readFileSync(`/proc/${pidStr}/cmdline`, 'utf8');
|
|
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
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
catch {
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
24
70
|
//# 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,MAAM,SAAS,CAAA;
|
|
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;QACH,IAAI,QAAQ,KAAK,QAAQ,EAAE,CAAC;YAC1B,MAAM,SAAS,GAAG,YAAY,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC;iBACpF,KAAK,CAAC,IAAI,CAAC;iBACX,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;iBACpB,MAAM,CAAC,OAAO,CAAC,CAAA;YAElB,KAAK,MAAM,MAAM,IAAI,SAAS,EAAE,CAAC;gBAC/B,MAAM,IAAI,GAAG,YAAY,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,CAAC,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAC,IAAI,EAAE,CAAA;gBAChG,IAAI,CAAC,IAAI;oBAAE,SAAQ;gBACnB,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAA;gBAClC,IAAI,QAAQ,KAAK,CAAC,CAAC;oBAAE,SAAQ;gBAC7B,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,IAAI,EAAE,CAAA;gBACxC,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAA;gBACvC,IAAI,CAAC,MAAM,KAAK,MAAM,IAAI,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;oBAC/E,OAAO,QAAQ,CAAC,MAAM,EAAE,EAAE,CAAC,CAAA;gBAC7B,CAAC;YACH,CAAC;YACD,OAAO,IAAI,CAAA;QACb,CAAC;QAED,IAAI,QAAQ,KAAK,OAAO,EAAE,CAAC;YACzB,MAAM,SAAS,GAAG,YAAY,CAAC,SAAS,QAAQ,SAAS,QAAQ,WAAW,EAAE,MAAM,CAAC;iBAClF,KAAK,CAAC,GAAG,CAAC;iBACV,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;iBACpB,MAAM,CAAC,OAAO,CAAC,CAAA;YAElB,KAAK,MAAM,MAAM,IAAI,SAAS,EAAE,CAAC;gBAC/B,MAAM,OAAO,GAAG,YAAY,CAAC,SAAS,MAAM,UAAU,EAAE,MAAM,CAAC,CAAA;gBAC/D,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAA;gBACjD,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,CAAA;gBAC7B,IAAI,CAAC,MAAM,KAAK,MAAM,IAAI,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,IAAI,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;oBAClF,OAAO,QAAQ,CAAC,MAAM,EAAE,EAAE,CAAC,CAAA;gBAC7B,CAAC;YACH,CAAC;YACD,OAAO,IAAI,CAAA;QACb,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAA;IACb,CAAC;IAED,OAAO,IAAI,CAAA;AACb,CAAC"}
|
package/package.json
CHANGED
package/src/agent.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { EventEmitter } from 'node:events'
|
|
2
2
|
import * as pty from 'node-pty'
|
|
3
3
|
import type { AgentConfig } from './config.js'
|
|
4
|
-
import { getProcessCwd } from './process-cwd.js'
|
|
4
|
+
import { getProcessCwd, getClaudeChildPid } from './process-cwd.js'
|
|
5
5
|
import { cleanupHookFiles } from './hook-injector.js'
|
|
6
6
|
|
|
7
7
|
export type SessionStatus = 'running' | 'idle' | 'done' | 'error'
|
|
@@ -34,6 +34,7 @@ export class AgentSession extends EventEmitter {
|
|
|
34
34
|
private exited = false
|
|
35
35
|
private idleTimer: ReturnType<typeof setTimeout> | null = null
|
|
36
36
|
private cwdPollTimer: ReturnType<typeof setInterval> | null = null
|
|
37
|
+
private claudeChildPid: number | null = null
|
|
37
38
|
private displayNameLocked = false
|
|
38
39
|
private initialInputBuffer = ''
|
|
39
40
|
private hookFiles: string[] = []
|
|
@@ -54,6 +55,10 @@ export class AgentSession extends EventEmitter {
|
|
|
54
55
|
env.MAV_SOCKET = ipcContext.socketPath
|
|
55
56
|
env.MAV_SESSION_ID = this.id
|
|
56
57
|
this.hookFiles = ipcContext.hookFiles
|
|
58
|
+
} else {
|
|
59
|
+
// Prevent child processes from inheriting the parent mav session's socket
|
|
60
|
+
delete env.MAV_SOCKET
|
|
61
|
+
delete env.MAV_SESSION_ID
|
|
57
62
|
}
|
|
58
63
|
proc = pty.spawn(config.cmd, config.args, {
|
|
59
64
|
name: 'xterm-256color',
|
|
@@ -179,7 +184,20 @@ export class AgentSession extends EventEmitter {
|
|
|
179
184
|
return
|
|
180
185
|
}
|
|
181
186
|
|
|
182
|
-
|
|
187
|
+
if (this.type === 'claude-code') {
|
|
188
|
+
if (this.claudeChildPid === null) {
|
|
189
|
+
this.claudeChildPid = getClaudeChildPid(this.ptyProcess.pid)
|
|
190
|
+
}
|
|
191
|
+
const targetPid = this.claudeChildPid ?? this.ptyProcess.pid
|
|
192
|
+
const cwd = getProcessCwd(targetPid)
|
|
193
|
+
if (cwd === null && this.claudeChildPid !== null) {
|
|
194
|
+
this.claudeChildPid = null
|
|
195
|
+
} else {
|
|
196
|
+
this.updateCwd(cwd)
|
|
197
|
+
}
|
|
198
|
+
} else {
|
|
199
|
+
this.updateCwd(getProcessCwd(this.ptyProcess.pid))
|
|
200
|
+
}
|
|
183
201
|
}, AgentSession.CWD_POLL_INTERVAL_MS)
|
|
184
202
|
}
|
|
185
203
|
|
package/src/hook-injector.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { writeFileSync, readFileSync, existsSync, unlinkSync, mkdirSync } from 'node:fs'
|
|
2
2
|
import { join } from 'node:path'
|
|
3
|
-
import { homedir
|
|
4
|
-
import { randomUUID
|
|
3
|
+
import { homedir } from 'node:os'
|
|
4
|
+
import { randomUUID } from 'node:crypto'
|
|
5
5
|
|
|
6
6
|
export interface HookInjectionResult {
|
|
7
7
|
/** Injected startup args */
|
|
@@ -37,8 +37,6 @@ export function buildHookArgs(
|
|
|
37
37
|
options: BuildHookArgsOptions = {},
|
|
38
38
|
): HookInjectionResult {
|
|
39
39
|
switch (agentType) {
|
|
40
|
-
case 'claude-code':
|
|
41
|
-
return buildClaudeCodeHook(baseArgs, hookCommand, options.cmd, options.settingsFile)
|
|
42
40
|
case 'gemini-cli':
|
|
43
41
|
return buildGeminiHook(baseArgs, hookCommand, options.cwd)
|
|
44
42
|
case 'copilot':
|
|
@@ -50,103 +48,6 @@ export function buildHookArgs(
|
|
|
50
48
|
}
|
|
51
49
|
}
|
|
52
50
|
|
|
53
|
-
function buildClaudeCodeHook(
|
|
54
|
-
baseArgs: string[],
|
|
55
|
-
hookCommand: string,
|
|
56
|
-
cmd?: string,
|
|
57
|
-
settingsFile?: string,
|
|
58
|
-
): HookInjectionResult {
|
|
59
|
-
// If a custom wrapper is used (e.g. claude-launcher), skip --settings <json> injection.
|
|
60
|
-
// Wrappers detect --settings in their args and skip their own overlay (including
|
|
61
|
-
// apiKeyHelper), which breaks authentication.
|
|
62
|
-
if (cmd != null && cmd !== 'claude') {
|
|
63
|
-
if (settingsFile) {
|
|
64
|
-
return buildClaudeCodeHookViaFile(baseArgs, hookCommand, settingsFile)
|
|
65
|
-
}
|
|
66
|
-
return { args: baseArgs, hookFiles: [] }
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
const claudeSettingsPath = join(homedir(), '.claude', 'settings.json')
|
|
70
|
-
let existing: Record<string, unknown> = {}
|
|
71
|
-
if (existsSync(claudeSettingsPath)) {
|
|
72
|
-
try {
|
|
73
|
-
existing = JSON.parse(readFileSync(claudeSettingsPath, 'utf-8')) as Record<string, unknown>
|
|
74
|
-
} catch {
|
|
75
|
-
// Unreadable/invalid JSON — start from empty
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
const existingHooks = (existing.hooks ?? {}) as Record<string, unknown[]>
|
|
80
|
-
const existingPostToolUse = (existingHooks.PostToolUse ?? []) as unknown[]
|
|
81
|
-
|
|
82
|
-
const merged = {
|
|
83
|
-
...existing,
|
|
84
|
-
hooks: {
|
|
85
|
-
...existingHooks,
|
|
86
|
-
PostToolUse: [
|
|
87
|
-
...existingPostToolUse,
|
|
88
|
-
{
|
|
89
|
-
matcher: '',
|
|
90
|
-
hooks: [{ type: 'command', command: hookCommand }],
|
|
91
|
-
},
|
|
92
|
-
],
|
|
93
|
-
},
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
return {
|
|
97
|
-
args: [...baseArgs, '--settings', JSON.stringify(merged)],
|
|
98
|
-
hookFiles: [],
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
function buildClaudeCodeHookViaFile(
|
|
103
|
-
baseArgs: string[],
|
|
104
|
-
hookCommand: string,
|
|
105
|
-
settingsFile: string,
|
|
106
|
-
): HookInjectionResult {
|
|
107
|
-
const expandedPath = settingsFile.replace(/^~/, homedir())
|
|
108
|
-
|
|
109
|
-
// Read the overlay file BEFORE the wrapper starts (and potentially overwrites it).
|
|
110
|
-
// The wrapper's overlay content (apiKeyHelper etc.) is preserved in the temp file,
|
|
111
|
-
// so even though the wrapper skips its own overlay injection, auth still works.
|
|
112
|
-
let existing: Record<string, unknown> = {}
|
|
113
|
-
if (existsSync(expandedPath)) {
|
|
114
|
-
try {
|
|
115
|
-
existing = JSON.parse(readFileSync(expandedPath, 'utf-8')) as Record<string, unknown>
|
|
116
|
-
} catch {
|
|
117
|
-
// Treat as empty
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
const existingHooks = (existing.hooks ?? {}) as Record<string, unknown[]>
|
|
122
|
-
const existingPostToolUse = (existingHooks.PostToolUse ?? []) as unknown[]
|
|
123
|
-
|
|
124
|
-
const merged = {
|
|
125
|
-
...existing,
|
|
126
|
-
hooks: {
|
|
127
|
-
...existingHooks,
|
|
128
|
-
PostToolUse: [
|
|
129
|
-
...existingPostToolUse,
|
|
130
|
-
{
|
|
131
|
-
matcher: '',
|
|
132
|
-
hooks: [{ type: 'command', command: hookCommand }],
|
|
133
|
-
},
|
|
134
|
-
],
|
|
135
|
-
},
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
// Use a deterministic name based on the settingsFile path so that at most one
|
|
139
|
-
// temp file exists per overlay path — crash leftovers get overwritten next run.
|
|
140
|
-
const pathHash = createHash('sha256').update(expandedPath).digest('hex').slice(0, 8)
|
|
141
|
-
const tempPath = join(tmpdir(), `mav-settings-${pathHash}.json`)
|
|
142
|
-
writeFileSync(tempPath, JSON.stringify(merged, null, 2))
|
|
143
|
-
|
|
144
|
-
return {
|
|
145
|
-
args: [...baseArgs, '--settings', tempPath],
|
|
146
|
-
hookFiles: [tempPath],
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
|
|
150
51
|
const MAV_MARKER = '_mavGenerated'
|
|
151
52
|
|
|
152
53
|
function buildGeminiHook(
|
package/src/process-cwd.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { execFileSync } from 'node:child_process'
|
|
2
|
-
import { readlinkSync } from 'node:fs'
|
|
2
|
+
import { readlinkSync, readFileSync } from 'node:fs'
|
|
3
3
|
|
|
4
4
|
export function getProcessCwd(pid: number, platform: NodeJS.Platform = process.platform): string | null {
|
|
5
5
|
if (!Number.isInteger(pid) || pid <= 0) {
|
|
@@ -29,3 +29,55 @@ export function getProcessCwd(pid: number, platform: NodeJS.Platform = process.p
|
|
|
29
29
|
|
|
30
30
|
return null
|
|
31
31
|
}
|
|
32
|
+
|
|
33
|
+
export function getClaudeChildPid(
|
|
34
|
+
shellPid: number,
|
|
35
|
+
platform: NodeJS.Platform = process.platform,
|
|
36
|
+
): number | null {
|
|
37
|
+
if (!Number.isInteger(shellPid) || shellPid <= 0) {
|
|
38
|
+
return null
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
try {
|
|
42
|
+
if (platform === 'darwin') {
|
|
43
|
+
const childPids = execFileSync('pgrep', ['-P', String(shellPid)], { encoding: 'utf8' })
|
|
44
|
+
.split('\n')
|
|
45
|
+
.map((s) => s.trim())
|
|
46
|
+
.filter(Boolean)
|
|
47
|
+
|
|
48
|
+
for (const pidStr of childPids) {
|
|
49
|
+
const line = execFileSync('ps', ['-o', 'pid=,args=', '-p', pidStr], { encoding: 'utf8' }).trim()
|
|
50
|
+
if (!line) continue
|
|
51
|
+
const spaceIdx = line.search(/\s/)
|
|
52
|
+
if (spaceIdx === -1) continue
|
|
53
|
+
const args = line.slice(spaceIdx).trim()
|
|
54
|
+
const binary = args.split(' ')[0] ?? ''
|
|
55
|
+
if ((binary === 'node' || binary.endsWith('/node')) && args.includes('claude')) {
|
|
56
|
+
return parseInt(pidStr, 10)
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return null
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if (platform === 'linux') {
|
|
63
|
+
const childPids = readFileSync(`/proc/${shellPid}/task/${shellPid}/children`, 'utf8')
|
|
64
|
+
.split(' ')
|
|
65
|
+
.map((s) => s.trim())
|
|
66
|
+
.filter(Boolean)
|
|
67
|
+
|
|
68
|
+
for (const pidStr of childPids) {
|
|
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
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return null
|
|
77
|
+
}
|
|
78
|
+
} catch {
|
|
79
|
+
return null
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
return null
|
|
83
|
+
}
|