orchestrix-yuri 2.0.0 → 2.0.2
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/lib/gateway/config.js
CHANGED
|
@@ -18,10 +18,7 @@ const DEFAULTS = {
|
|
|
18
18
|
storage: path.join(os.homedir(), '.yuri', 'chat-history'),
|
|
19
19
|
},
|
|
20
20
|
engine: {
|
|
21
|
-
cli_command: 'cc',
|
|
22
|
-
fallback_command: 'claude',
|
|
23
21
|
skill: 'yuri',
|
|
24
|
-
allowed_tools: 'Read,Write,Edit,Bash,Glob,Grep',
|
|
25
22
|
},
|
|
26
23
|
};
|
|
27
24
|
|
|
@@ -47,7 +44,7 @@ function loadConfig() {
|
|
|
47
44
|
? parsed.chat_history.storage.replace('~', os.homedir())
|
|
48
45
|
: DEFAULTS.chat_history.storage,
|
|
49
46
|
},
|
|
50
|
-
engine: { ...DEFAULTS.engine, ...parsed.engine },
|
|
47
|
+
engine: { ...DEFAULTS.engine, ...(parsed.engine || {}) },
|
|
51
48
|
};
|
|
52
49
|
}
|
|
53
50
|
|
|
@@ -1,14 +1,11 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const {
|
|
4
|
-
const { promisify } = require('util');
|
|
3
|
+
const { spawn } = require('child_process');
|
|
5
4
|
const fs = require('fs');
|
|
6
5
|
const path = require('path');
|
|
7
6
|
const os = require('os');
|
|
8
7
|
const yaml = require('js-yaml');
|
|
9
8
|
|
|
10
|
-
const execFileAsync = promisify(execFile);
|
|
11
|
-
|
|
12
9
|
const YURI_GLOBAL = path.join(os.homedir(), '.yuri');
|
|
13
10
|
|
|
14
11
|
/**
|
|
@@ -69,31 +66,61 @@ function resolveProjectRoot() {
|
|
|
69
66
|
}
|
|
70
67
|
|
|
71
68
|
/**
|
|
72
|
-
* Find the
|
|
69
|
+
* Find the claude binary path.
|
|
70
|
+
* Shell aliases (like `cc`) are not available in child_process, so we
|
|
71
|
+
* resolve the actual binary via the user's login shell PATH.
|
|
73
72
|
*/
|
|
74
|
-
function
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
// Check if primary command exists via which
|
|
73
|
+
function findClaudeBinary() {
|
|
74
|
+
// Primary: resolve via user's login shell (handles all install methods)
|
|
78
75
|
try {
|
|
79
|
-
require('child_process')
|
|
80
|
-
|
|
76
|
+
const resolved = require('child_process')
|
|
77
|
+
.execSync('zsh -lc "which claude" 2>/dev/null', { encoding: 'utf8' })
|
|
78
|
+
.trim();
|
|
79
|
+
if (resolved && fs.existsSync(resolved)) {
|
|
80
|
+
return resolved;
|
|
81
|
+
}
|
|
81
82
|
} catch {
|
|
82
|
-
//
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
83
|
+
// fall through
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// Fallback: check common install locations
|
|
87
|
+
const candidates = [
|
|
88
|
+
'/usr/local/bin/claude',
|
|
89
|
+
'/opt/homebrew/bin/claude',
|
|
90
|
+
path.join(os.homedir(), '.npm-global', 'bin', 'claude'),
|
|
91
|
+
path.join(os.homedir(), '.local', 'bin', 'claude'),
|
|
92
|
+
path.join(os.homedir(), '.claude', 'bin', 'claude'),
|
|
93
|
+
];
|
|
94
|
+
|
|
95
|
+
for (const candidate of candidates) {
|
|
96
|
+
if (fs.existsSync(candidate)) {
|
|
97
|
+
return candidate;
|
|
88
98
|
}
|
|
89
99
|
}
|
|
100
|
+
|
|
101
|
+
// Last resort: let the shell find it
|
|
102
|
+
return 'claude';
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Cache the binary path
|
|
106
|
+
let _claudeBinary = null;
|
|
107
|
+
function getClaudeBinary() {
|
|
108
|
+
if (!_claudeBinary) {
|
|
109
|
+
_claudeBinary = findClaudeBinary();
|
|
110
|
+
console.log(`[claude-cli] Using binary: ${_claudeBinary}`);
|
|
111
|
+
}
|
|
112
|
+
return _claudeBinary;
|
|
90
113
|
}
|
|
91
114
|
|
|
92
115
|
/**
|
|
93
116
|
* Execute a Claude CLI call with the Yuri skill.
|
|
94
117
|
*
|
|
118
|
+
* Uses `claude --dangerously-skip-permissions -p "prompt"` to match the user's
|
|
119
|
+
* `cc` alias behavior. The prompt is written to a temp file to avoid command-line
|
|
120
|
+
* length limits and shell escaping issues.
|
|
121
|
+
*
|
|
95
122
|
* @param {object} opts
|
|
96
|
-
* @param {string} opts.prompt - The composed prompt
|
|
123
|
+
* @param {string} opts.prompt - The composed prompt
|
|
97
124
|
* @param {string} opts.cwd - Working directory (project root)
|
|
98
125
|
* @param {object} opts.engineConfig - Engine configuration from channels.yaml
|
|
99
126
|
* @param {number} [opts.timeout=300000] - Timeout in ms (default 5 min)
|
|
@@ -102,35 +129,56 @@ function findCliCommand(engineConfig) {
|
|
|
102
129
|
async function callClaude(opts) {
|
|
103
130
|
const { prompt, cwd, engineConfig, timeout = 300000 } = opts;
|
|
104
131
|
|
|
105
|
-
const
|
|
106
|
-
const args = [
|
|
107
|
-
'-p', prompt,
|
|
108
|
-
'--allowedTools', engineConfig.allowed_tools || 'Read,Write,Edit,Bash,Glob,Grep',
|
|
109
|
-
];
|
|
132
|
+
const binary = getClaudeBinary();
|
|
110
133
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
maxBuffer: 10 * 1024 * 1024, // 10MB
|
|
115
|
-
env: { ...process.env },
|
|
116
|
-
};
|
|
134
|
+
// Write prompt to temp file to avoid command-line length limits
|
|
135
|
+
const tmpFile = path.join(os.tmpdir(), `yuri-prompt-${Date.now()}.txt`);
|
|
136
|
+
fs.writeFileSync(tmpFile, prompt);
|
|
117
137
|
|
|
118
|
-
|
|
119
|
-
const
|
|
138
|
+
return new Promise((resolve) => {
|
|
139
|
+
const args = [
|
|
140
|
+
'--dangerously-skip-permissions',
|
|
141
|
+
'-p',
|
|
142
|
+
`$(cat "${tmpFile}")`,
|
|
143
|
+
];
|
|
120
144
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
145
|
+
// Use shell to expand $(cat ...) and get proper PATH
|
|
146
|
+
const child = spawn('zsh', ['-lc', `"${binary}" --dangerously-skip-permissions -p "$(cat "${tmpFile}")"`], {
|
|
147
|
+
cwd: cwd || os.homedir(),
|
|
148
|
+
env: { ...process.env },
|
|
149
|
+
timeout,
|
|
150
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
151
|
+
});
|
|
124
152
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
153
|
+
let stdout = '';
|
|
154
|
+
let stderr = '';
|
|
155
|
+
|
|
156
|
+
child.stdout.on('data', (data) => { stdout += data.toString(); });
|
|
157
|
+
child.stderr.on('data', (data) => { stderr += data.toString(); });
|
|
158
|
+
|
|
159
|
+
child.on('close', (code) => {
|
|
160
|
+
// Clean up temp file
|
|
161
|
+
try { fs.unlinkSync(tmpFile); } catch {}
|
|
162
|
+
|
|
163
|
+
if (stderr.trim()) {
|
|
164
|
+
console.error('[claude-cli] stderr:', stderr.trim().slice(0, 500));
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
if (code !== 0 && !stdout.trim()) {
|
|
168
|
+
console.error(`[claude-cli] Process exited with code ${code}`);
|
|
169
|
+
resolve({ reply: `❌ Claude CLI error (exit ${code}). Check gateway logs.`, raw: '' });
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
resolve({ reply: stdout.trim(), raw: stdout });
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
child.on('error', (err) => {
|
|
177
|
+
try { fs.unlinkSync(tmpFile); } catch {}
|
|
178
|
+
console.error('[claude-cli] spawn error:', err.message);
|
|
179
|
+
resolve({ reply: `❌ Failed to start Claude CLI: ${err.message}`, raw: '' });
|
|
180
|
+
});
|
|
181
|
+
});
|
|
134
182
|
}
|
|
135
183
|
|
|
136
184
|
/**
|
|
@@ -174,4 +222,4 @@ function composePrompt(userMessage, chatHistory) {
|
|
|
174
222
|
return parts.join('\n\n---\n\n');
|
|
175
223
|
}
|
|
176
224
|
|
|
177
|
-
module.exports = { callClaude, composePrompt, loadL1Context, resolveProjectRoot,
|
|
225
|
+
module.exports = { callClaude, composePrompt, loadL1Context, resolveProjectRoot, findClaudeBinary };
|
package/package.json
CHANGED