@esotech/contextuate 2.0.0 → 2.1.0
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 +169 -1
- package/dist/commands/claude.d.ts +21 -0
- package/dist/commands/claude.js +213 -0
- package/dist/commands/context.d.ts +1 -0
- package/dist/commands/create.d.ts +3 -0
- package/dist/commands/index.d.ts +4 -0
- package/dist/commands/init.d.ts +7 -0
- package/dist/commands/init.js +67 -6
- package/dist/commands/install.d.ts +28 -0
- package/dist/commands/install.js +116 -11
- package/dist/commands/monitor.d.ts +55 -0
- package/dist/commands/monitor.js +1007 -0
- package/dist/commands/remove.d.ts +3 -0
- package/dist/commands/run.d.ts +6 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +113 -1
- package/dist/monitor/daemon/circuit-breaker.d.ts +121 -0
- package/dist/monitor/daemon/circuit-breaker.js +552 -0
- package/dist/monitor/daemon/cli.d.ts +8 -0
- package/dist/monitor/daemon/cli.js +82 -0
- package/dist/monitor/daemon/index.d.ts +137 -0
- package/dist/monitor/daemon/index.js +695 -0
- package/dist/monitor/daemon/notifier.d.ts +25 -0
- package/dist/monitor/daemon/notifier.js +98 -0
- package/dist/monitor/daemon/processor.d.ts +89 -0
- package/dist/monitor/daemon/processor.js +455 -0
- package/dist/monitor/daemon/state.d.ts +80 -0
- package/dist/monitor/daemon/state.js +162 -0
- package/dist/monitor/daemon/watcher.d.ts +47 -0
- package/dist/monitor/daemon/watcher.js +171 -0
- package/dist/monitor/daemon/wrapper-manager.d.ts +106 -0
- package/dist/monitor/daemon/wrapper-manager.js +374 -0
- package/dist/monitor/hooks/emit-event.js +652 -0
- package/dist/monitor/persistence/file-store.d.ts +88 -0
- package/dist/monitor/persistence/file-store.js +335 -0
- package/dist/monitor/persistence/index.d.ts +7 -0
- package/dist/monitor/persistence/index.js +10 -0
- package/dist/monitor/server/adapters/redis.d.ts +38 -0
- package/dist/monitor/server/adapters/redis.js +213 -0
- package/dist/monitor/server/adapters/unix-socket.d.ts +33 -0
- package/dist/monitor/server/adapters/unix-socket.js +182 -0
- package/dist/monitor/server/broker.d.ts +135 -0
- package/dist/monitor/server/broker.js +475 -0
- package/dist/monitor/server/cli.d.ts +8 -0
- package/dist/monitor/server/cli.js +98 -0
- package/dist/monitor/server/fastify.d.ts +16 -0
- package/dist/monitor/server/fastify.js +184 -0
- package/dist/monitor/server/index.d.ts +36 -0
- package/dist/monitor/server/index.js +153 -0
- package/dist/monitor/server/websocket.d.ts +80 -0
- package/dist/monitor/server/websocket.js +453 -0
- package/dist/monitor/ui/assets/index-4IssW9On.js +59 -0
- package/dist/monitor/ui/assets/index-vo9hLe5R.css +32 -0
- package/dist/monitor/ui/favicon.png +0 -0
- package/dist/monitor/ui/index.html +14 -0
- package/dist/monitor/ui/logo.png +0 -0
- package/dist/monitor/ui/logo.svg +1 -0
- package/dist/runtime/driver.d.ts +16 -0
- package/dist/runtime/tools.d.ts +10 -0
- package/dist/templates/README.md +33 -7
- package/dist/templates/agents/aegis.md +4 -0
- package/dist/templates/agents/archon.md +13 -22
- package/dist/templates/agents/atlas.md +4 -0
- package/dist/templates/agents/canvas.md +4 -0
- package/dist/templates/agents/chronicle.md +4 -0
- package/dist/templates/agents/chronos.md +4 -0
- package/dist/templates/agents/cipher.md +4 -0
- package/dist/templates/agents/crucible.md +4 -0
- package/dist/templates/agents/echo.md +4 -0
- package/dist/templates/agents/forge.md +4 -0
- package/dist/templates/agents/ledger.md +4 -0
- package/dist/templates/agents/meridian.md +4 -0
- package/dist/templates/agents/nexus.md +4 -0
- package/dist/templates/agents/pythia.md +217 -0
- package/dist/templates/agents/scribe.md +4 -0
- package/dist/templates/agents/sentinel.md +4 -0
- package/dist/templates/agents/{oracle.md → thoth.md} +11 -7
- package/dist/templates/agents/unity.md +4 -0
- package/dist/templates/agents/vox.md +4 -0
- package/dist/templates/agents/weaver.md +4 -0
- package/dist/templates/framework-agents/documentation-expert.md +3 -3
- package/dist/templates/framework-agents/tools-expert.md +8 -8
- package/dist/templates/skills/consult.md +138 -0
- package/dist/templates/skills/orchestrate.md +173 -0
- package/dist/templates/skills/pythia.md +37 -0
- package/dist/templates/standards/agent-roles.md +68 -21
- package/dist/templates/standards/coding-standards.md +9 -26
- package/dist/templates/templates/context.md +17 -2
- package/dist/templates/templates/contextuate.md +21 -28
- package/dist/templates/templates/standards/go.md +167 -0
- package/dist/templates/templates/standards/java.md +167 -0
- package/dist/templates/templates/standards/javascript.md +292 -0
- package/dist/templates/templates/standards/php.md +181 -0
- package/dist/templates/templates/standards/python.md +175 -0
- package/dist/templates/tools/agent-creator.md +252 -0
- package/dist/templates/tools/agent-creator.tool.md +2 -2
- package/dist/templates/tools/quickref.md +216 -0
- package/dist/templates/tools/spawn.md +31 -0
- package/dist/templates/tools/standards-detector.md +301 -0
- package/dist/templates/version.json +1 -1
- package/dist/types/monitor.d.ts +660 -0
- package/dist/types/monitor.js +75 -0
- package/dist/utils/git.d.ts +9 -0
- package/dist/utils/tokens.d.ts +10 -0
- package/package.json +18 -5
|
@@ -0,0 +1,374 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Wrapper Manager
|
|
4
|
+
*
|
|
5
|
+
* Manages Claude wrapper sessions with PTY.
|
|
6
|
+
* Spawns and manages Claude processes, handles input/output streaming,
|
|
7
|
+
* persists session state, and cleans up on exit.
|
|
8
|
+
*/
|
|
9
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
12
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
13
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
14
|
+
}
|
|
15
|
+
Object.defineProperty(o, k2, desc);
|
|
16
|
+
}) : (function(o, m, k, k2) {
|
|
17
|
+
if (k2 === undefined) k2 = k;
|
|
18
|
+
o[k2] = m[k];
|
|
19
|
+
}));
|
|
20
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
21
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
22
|
+
}) : function(o, v) {
|
|
23
|
+
o["default"] = v;
|
|
24
|
+
});
|
|
25
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
26
|
+
var ownKeys = function(o) {
|
|
27
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
28
|
+
var ar = [];
|
|
29
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
30
|
+
return ar;
|
|
31
|
+
};
|
|
32
|
+
return ownKeys(o);
|
|
33
|
+
};
|
|
34
|
+
return function (mod) {
|
|
35
|
+
if (mod && mod.__esModule) return mod;
|
|
36
|
+
var result = {};
|
|
37
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
38
|
+
__setModuleDefault(result, mod);
|
|
39
|
+
return result;
|
|
40
|
+
};
|
|
41
|
+
})();
|
|
42
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
43
|
+
exports.WrapperManager = void 0;
|
|
44
|
+
const pty = __importStar(require("node-pty"));
|
|
45
|
+
const fs = __importStar(require("fs-extra"));
|
|
46
|
+
const path = __importStar(require("path"));
|
|
47
|
+
const os = __importStar(require("os"));
|
|
48
|
+
const uuid_1 = require("uuid");
|
|
49
|
+
const child_process_1 = require("child_process");
|
|
50
|
+
class WrapperManager {
|
|
51
|
+
constructor(persistPath, onEvent) {
|
|
52
|
+
this.wrappers = new Map();
|
|
53
|
+
this.persistPath = persistPath;
|
|
54
|
+
this.onEvent = onEvent;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Initialize - load persisted wrappers and clean up dead ones
|
|
58
|
+
*/
|
|
59
|
+
async initialize() {
|
|
60
|
+
await fs.ensureDir(path.dirname(this.persistPath));
|
|
61
|
+
await this.loadAndCleanup();
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Load persisted wrappers and clean up any that are no longer running
|
|
65
|
+
*/
|
|
66
|
+
async loadAndCleanup() {
|
|
67
|
+
try {
|
|
68
|
+
if (await fs.pathExists(this.persistPath)) {
|
|
69
|
+
const data = await fs.readJson(this.persistPath);
|
|
70
|
+
const persistedWrappers = data.wrappers || [];
|
|
71
|
+
// Check each persisted wrapper to see if it's still running
|
|
72
|
+
const stillRunning = [];
|
|
73
|
+
for (const wrapper of persistedWrappers) {
|
|
74
|
+
if (this.isProcessRunning(wrapper.pid)) {
|
|
75
|
+
console.log(`[WrapperManager] Found running wrapper ${wrapper.wrapperId} (PID ${wrapper.pid})`);
|
|
76
|
+
stillRunning.push(wrapper);
|
|
77
|
+
// Note: We can't reconnect to existing PTYs, so these are "orphaned"
|
|
78
|
+
// We'll mark them as ended and clean up
|
|
79
|
+
}
|
|
80
|
+
else {
|
|
81
|
+
console.log(`[WrapperManager] Cleaning up dead wrapper ${wrapper.wrapperId} (PID ${wrapper.pid})`);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
// For now, we just clean up all persisted wrappers since we can't reconnect to PTYs
|
|
85
|
+
// In a more advanced implementation, we could use screen/tmux to maintain sessions
|
|
86
|
+
await this.persist();
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
catch (err) {
|
|
90
|
+
console.error('[WrapperManager] Error loading persisted wrappers:', err);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Check if a process is still running
|
|
95
|
+
*/
|
|
96
|
+
isProcessRunning(pid) {
|
|
97
|
+
try {
|
|
98
|
+
process.kill(pid, 0);
|
|
99
|
+
return true;
|
|
100
|
+
}
|
|
101
|
+
catch {
|
|
102
|
+
return false;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Spawn a new Claude wrapper session
|
|
107
|
+
*/
|
|
108
|
+
async spawn(options = {}) {
|
|
109
|
+
const wrapperId = (0, uuid_1.v4)().slice(0, 8);
|
|
110
|
+
const cwd = options.cwd || process.cwd();
|
|
111
|
+
const args = options.args || [];
|
|
112
|
+
const cols = options.cols || 120;
|
|
113
|
+
const rows = options.rows || 40;
|
|
114
|
+
// Find Claude executable
|
|
115
|
+
const claudePath = this.findClaudeExecutable();
|
|
116
|
+
if (!claudePath) {
|
|
117
|
+
throw new Error('Claude CLI not found. Please install Claude Code.');
|
|
118
|
+
}
|
|
119
|
+
console.log(`[WrapperManager] Spawning Claude wrapper ${wrapperId} at ${cwd}`);
|
|
120
|
+
// Spawn Claude with PTY
|
|
121
|
+
const ptyProcess = pty.spawn(claudePath, args, {
|
|
122
|
+
name: 'xterm-256color',
|
|
123
|
+
cols,
|
|
124
|
+
rows,
|
|
125
|
+
cwd,
|
|
126
|
+
env: {
|
|
127
|
+
...process.env,
|
|
128
|
+
CONTEXTUATE_WRAPPER_ID: wrapperId,
|
|
129
|
+
},
|
|
130
|
+
});
|
|
131
|
+
const session = {
|
|
132
|
+
wrapperId,
|
|
133
|
+
ptyProcess,
|
|
134
|
+
pid: ptyProcess.pid,
|
|
135
|
+
claudeSessionId: null,
|
|
136
|
+
state: 'starting',
|
|
137
|
+
cwd,
|
|
138
|
+
args,
|
|
139
|
+
startTime: Date.now(),
|
|
140
|
+
cols,
|
|
141
|
+
rows,
|
|
142
|
+
};
|
|
143
|
+
this.wrappers.set(wrapperId, session);
|
|
144
|
+
// Handle PTY output
|
|
145
|
+
let outputBuffer = '';
|
|
146
|
+
ptyProcess.onData((data) => {
|
|
147
|
+
// Stream to UI
|
|
148
|
+
this.onEvent({
|
|
149
|
+
type: 'output',
|
|
150
|
+
wrapperId,
|
|
151
|
+
data,
|
|
152
|
+
});
|
|
153
|
+
// Buffer for pattern detection
|
|
154
|
+
outputBuffer += data;
|
|
155
|
+
if (outputBuffer.length > 1000) {
|
|
156
|
+
outputBuffer = outputBuffer.slice(-500);
|
|
157
|
+
}
|
|
158
|
+
// Heuristic: detect if waiting for input
|
|
159
|
+
if (session.state === 'processing' || session.state === 'starting') {
|
|
160
|
+
if (this.detectInputPrompt(outputBuffer)) {
|
|
161
|
+
session.state = 'waiting_input';
|
|
162
|
+
this.onEvent({
|
|
163
|
+
type: 'state_changed',
|
|
164
|
+
wrapperId,
|
|
165
|
+
state: 'waiting_input',
|
|
166
|
+
});
|
|
167
|
+
outputBuffer = '';
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
});
|
|
171
|
+
// Handle PTY exit
|
|
172
|
+
ptyProcess.onExit(({ exitCode }) => {
|
|
173
|
+
console.log(`[WrapperManager] Wrapper ${wrapperId} exited with code ${exitCode}`);
|
|
174
|
+
session.state = 'ended';
|
|
175
|
+
this.onEvent({
|
|
176
|
+
type: 'ended',
|
|
177
|
+
wrapperId,
|
|
178
|
+
exitCode,
|
|
179
|
+
});
|
|
180
|
+
this.wrappers.delete(wrapperId);
|
|
181
|
+
this.persist();
|
|
182
|
+
});
|
|
183
|
+
// Persist and notify
|
|
184
|
+
await this.persist();
|
|
185
|
+
this.onEvent({
|
|
186
|
+
type: 'started',
|
|
187
|
+
wrapperId,
|
|
188
|
+
state: 'starting',
|
|
189
|
+
});
|
|
190
|
+
// Mark as processing after a short delay (Claude is starting up)
|
|
191
|
+
setTimeout(() => {
|
|
192
|
+
if (session.state === 'starting') {
|
|
193
|
+
session.state = 'processing';
|
|
194
|
+
this.onEvent({
|
|
195
|
+
type: 'state_changed',
|
|
196
|
+
wrapperId,
|
|
197
|
+
state: 'processing',
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
}, 1000);
|
|
201
|
+
return wrapperId;
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Write input to a wrapper's PTY
|
|
205
|
+
*/
|
|
206
|
+
writeInput(wrapperId, input) {
|
|
207
|
+
const session = this.wrappers.get(wrapperId);
|
|
208
|
+
if (!session) {
|
|
209
|
+
return false;
|
|
210
|
+
}
|
|
211
|
+
session.ptyProcess.write(input);
|
|
212
|
+
return true;
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* Resize a wrapper's PTY
|
|
216
|
+
*/
|
|
217
|
+
resize(wrapperId, cols, rows) {
|
|
218
|
+
const session = this.wrappers.get(wrapperId);
|
|
219
|
+
if (!session) {
|
|
220
|
+
return false;
|
|
221
|
+
}
|
|
222
|
+
session.ptyProcess.resize(cols, rows);
|
|
223
|
+
session.cols = cols;
|
|
224
|
+
session.rows = rows;
|
|
225
|
+
return true;
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* Kill a wrapper session
|
|
229
|
+
*/
|
|
230
|
+
kill(wrapperId) {
|
|
231
|
+
const session = this.wrappers.get(wrapperId);
|
|
232
|
+
if (!session) {
|
|
233
|
+
return false;
|
|
234
|
+
}
|
|
235
|
+
console.log(`[WrapperManager] Killing wrapper ${wrapperId}`);
|
|
236
|
+
session.ptyProcess.kill();
|
|
237
|
+
return true;
|
|
238
|
+
}
|
|
239
|
+
/**
|
|
240
|
+
* Get all active wrappers
|
|
241
|
+
*/
|
|
242
|
+
getAll() {
|
|
243
|
+
return Array.from(this.wrappers.values());
|
|
244
|
+
}
|
|
245
|
+
/**
|
|
246
|
+
* Get a specific wrapper
|
|
247
|
+
*/
|
|
248
|
+
get(wrapperId) {
|
|
249
|
+
return this.wrappers.get(wrapperId);
|
|
250
|
+
}
|
|
251
|
+
/**
|
|
252
|
+
* Update wrapper state (e.g., from hook events)
|
|
253
|
+
*/
|
|
254
|
+
updateState(wrapperId, state, claudeSessionId) {
|
|
255
|
+
const session = this.wrappers.get(wrapperId);
|
|
256
|
+
if (session) {
|
|
257
|
+
session.state = state;
|
|
258
|
+
if (claudeSessionId) {
|
|
259
|
+
session.claudeSessionId = claudeSessionId;
|
|
260
|
+
}
|
|
261
|
+
this.onEvent({
|
|
262
|
+
type: 'state_changed',
|
|
263
|
+
wrapperId,
|
|
264
|
+
state,
|
|
265
|
+
claudeSessionId,
|
|
266
|
+
});
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
/**
|
|
270
|
+
* Shutdown all wrappers
|
|
271
|
+
*/
|
|
272
|
+
async shutdown() {
|
|
273
|
+
console.log(`[WrapperManager] Shutting down ${this.wrappers.size} wrappers`);
|
|
274
|
+
for (const [wrapperId, session] of this.wrappers) {
|
|
275
|
+
try {
|
|
276
|
+
session.ptyProcess.kill();
|
|
277
|
+
}
|
|
278
|
+
catch (err) {
|
|
279
|
+
console.error(`[WrapperManager] Error killing wrapper ${wrapperId}:`, err);
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
this.wrappers.clear();
|
|
283
|
+
await this.persist();
|
|
284
|
+
}
|
|
285
|
+
/**
|
|
286
|
+
* Persist wrapper state to disk
|
|
287
|
+
*/
|
|
288
|
+
async persist() {
|
|
289
|
+
const data = Array.from(this.wrappers.values()).map(w => ({
|
|
290
|
+
wrapperId: w.wrapperId,
|
|
291
|
+
pid: w.pid,
|
|
292
|
+
claudeSessionId: w.claudeSessionId,
|
|
293
|
+
state: w.state,
|
|
294
|
+
cwd: w.cwd,
|
|
295
|
+
args: w.args,
|
|
296
|
+
startTime: w.startTime,
|
|
297
|
+
cols: w.cols,
|
|
298
|
+
rows: w.rows,
|
|
299
|
+
}));
|
|
300
|
+
try {
|
|
301
|
+
await fs.writeJson(this.persistPath, { wrappers: data }, { spaces: 2 });
|
|
302
|
+
}
|
|
303
|
+
catch (err) {
|
|
304
|
+
console.error('[WrapperManager] Error persisting wrappers:', err);
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
/**
|
|
308
|
+
* Detect if output indicates Claude is waiting for input
|
|
309
|
+
*/
|
|
310
|
+
detectInputPrompt(buffer) {
|
|
311
|
+
// Look for common patterns that indicate Claude is waiting
|
|
312
|
+
const patterns = [
|
|
313
|
+
/>\s*$/, // Simple prompt
|
|
314
|
+
/\?\s*$/, // Question prompt
|
|
315
|
+
/:\s*$/, // Colon prompt
|
|
316
|
+
/waiting for.*input/i, // Explicit waiting message
|
|
317
|
+
/enter.*to continue/i, // Continue prompt
|
|
318
|
+
/press.*to/i, // Press key prompt
|
|
319
|
+
];
|
|
320
|
+
return patterns.some(p => p.test(buffer));
|
|
321
|
+
}
|
|
322
|
+
/**
|
|
323
|
+
* Find the Claude executable
|
|
324
|
+
*/
|
|
325
|
+
findClaudeExecutable() {
|
|
326
|
+
const commonPaths = [
|
|
327
|
+
// New Claude Code installation location (Bun-based)
|
|
328
|
+
path.join(os.homedir(), '.local', 'bin', 'claude'),
|
|
329
|
+
// Legacy npm-based installations
|
|
330
|
+
path.join(os.homedir(), '.npm-global', 'bin', 'claude'),
|
|
331
|
+
path.join(os.homedir(), '.nvm', 'versions', 'node', process.version, 'bin', 'claude'),
|
|
332
|
+
'/opt/homebrew/bin/claude',
|
|
333
|
+
'/usr/local/bin/claude',
|
|
334
|
+
'/usr/bin/claude',
|
|
335
|
+
];
|
|
336
|
+
for (const p of commonPaths) {
|
|
337
|
+
if (fs.existsSync(p)) {
|
|
338
|
+
// Resolve symlinks to get the actual executable path
|
|
339
|
+
try {
|
|
340
|
+
const resolved = fs.realpathSync(p);
|
|
341
|
+
console.log(`[WrapperManager] Found Claude at ${p} -> ${resolved}`);
|
|
342
|
+
return resolved;
|
|
343
|
+
}
|
|
344
|
+
catch {
|
|
345
|
+
return p;
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
// Try to find via PATH
|
|
350
|
+
try {
|
|
351
|
+
const result = (0, child_process_1.execSync)('which claude 2>/dev/null || where claude 2>/dev/null', {
|
|
352
|
+
encoding: 'utf-8',
|
|
353
|
+
timeout: 5000,
|
|
354
|
+
}).trim();
|
|
355
|
+
if (result) {
|
|
356
|
+
const foundPath = result.split('\n')[0];
|
|
357
|
+
// Resolve symlinks to get the actual executable path
|
|
358
|
+
try {
|
|
359
|
+
const resolved = fs.realpathSync(foundPath);
|
|
360
|
+
console.log(`[WrapperManager] Found Claude via PATH at ${foundPath} -> ${resolved}`);
|
|
361
|
+
return resolved;
|
|
362
|
+
}
|
|
363
|
+
catch {
|
|
364
|
+
return foundPath;
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
catch {
|
|
369
|
+
// Not found via PATH
|
|
370
|
+
}
|
|
371
|
+
return null;
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
exports.WrapperManager = WrapperManager;
|