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