agentgui 1.0.11 → 1.0.13

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.
Files changed (2) hide show
  1. package/acp-launcher.js +58 -61
  2. package/package.json +1 -1
package/acp-launcher.js CHANGED
@@ -3,9 +3,35 @@ import fs from 'fs';
3
3
  import path from 'path';
4
4
  import os from 'os';
5
5
 
6
- const CLAUDE_BIN = '/home/user/.local/bin/claude';
7
- const API_KEY_PATH = path.join(os.homedir(), '.claude', 'oauth-api-key');
8
- const API_URL = 'https://api.anthropic.com/v1/messages';
6
+ // Common paths where claude-code-acp might be installed
7
+ const CLAUDE_CODE_ACP_PATHS = [
8
+ '/config/.gmweb/npm-global/bin/claude-code-acp',
9
+ '/usr/local/bin/claude-code-acp',
10
+ '/usr/bin/claude-code-acp',
11
+ path.join(os.homedir(), '.local/bin/claude-code-acp'),
12
+ path.join(os.homedir(), '.gmweb/npm-global/bin/claude-code-acp'),
13
+ 'claude-code-acp', // fallback to PATH
14
+ ];
15
+
16
+ // Common paths where opencode might be installed
17
+ const OPENCODE_PATHS = [
18
+ '/usr/local/bin/opencode',
19
+ '/usr/bin/opencode',
20
+ path.join(os.homedir(), '.local/bin/opencode'),
21
+ 'opencode', // fallback to PATH
22
+ ];
23
+
24
+ function findBinary(paths) {
25
+ for (const p of paths) {
26
+ try {
27
+ fs.accessSync(p, fs.constants.X_OK);
28
+ return p;
29
+ } catch (_) {
30
+ continue;
31
+ }
32
+ }
33
+ return null;
34
+ }
9
35
 
10
36
  const RIPPLEUI_SYSTEM_PROMPT = `ALWAYS respond with HTML using RippleUI components. The chat renders HTML. Use: cards (class='card'), alerts (class='alert alert-info'), tables (class='table table-zebra'), badges (class='badge badge-primary'), buttons (class='btn btn-primary'). Wrap all responses in styled HTML with Tailwind CSS utility classes for layout.
11
37
 
@@ -75,9 +101,35 @@ export default class ACPConnection {
75
101
  delete env.NODE_INSPECT;
76
102
  delete env.NODE_DEBUG;
77
103
 
104
+ // Ensure npm global bin directories are in PATH
105
+ const npmGlobalBins = [
106
+ '/config/.gmweb/npm-global/bin',
107
+ path.join(os.homedir(), '.gmweb/npm-global/bin'),
108
+ path.join(os.homedir(), '.local/bin'),
109
+ '/usr/local/bin',
110
+ ];
111
+ const currentPath = env.PATH || '';
112
+ const newPathEntries = npmGlobalBins.filter(p => !currentPath.includes(p));
113
+ if (newPathEntries.length > 0) {
114
+ env.PATH = [...newPathEntries, currentPath].join(':');
115
+ }
116
+
78
117
  try {
79
- const cmd = agentType === 'opencode' ? 'opencode' : 'claude-code-acp';
80
- const args = agentType === 'opencode' ? ['acp'] : [];
118
+ let cmd;
119
+ let args;
120
+ if (agentType === 'opencode') {
121
+ cmd = findBinary(OPENCODE_PATHS);
122
+ args = ['acp'];
123
+ } else {
124
+ cmd = findBinary(CLAUDE_CODE_ACP_PATHS);
125
+ args = [];
126
+ }
127
+
128
+ if (!cmd) {
129
+ reject(new Error(`Could not find ${agentType} ACP binary. Please ensure ${agentType === 'opencode' ? 'opencode' : 'claude-code-acp'} is installed and in your PATH.`));
130
+ return;
131
+ }
132
+
81
133
  this.child = spawn(cmd, args, { cwd, stdio: ['pipe', 'pipe', 'pipe'], env, shell: false });
82
134
  } catch (err) {
83
135
  reject(new Error(`Failed to spawn ACP: ${err.message}`));
@@ -219,62 +271,7 @@ export default class ACPConnection {
219
271
  }
220
272
 
221
273
  async _sendPrintPrompt(prompt) {
222
- const text = typeof prompt === 'string' ? prompt : (Array.isArray(prompt) ? prompt.map(p => p.text || '').join('\n') : String(prompt));
223
- let apiKey;
224
- try { apiKey = fs.readFileSync(API_KEY_PATH, 'utf-8').trim(); }
225
- catch (e) { throw new Error('No API key found at ' + API_KEY_PATH); }
226
-
227
- const body = JSON.stringify({
228
- model: 'claude-sonnet-4-20250514',
229
- max_tokens: 4096,
230
- system: RIPPLEUI_SYSTEM_PROMPT,
231
- messages: [{ role: 'user', content: text }],
232
- stream: true,
233
- });
234
-
235
- const res = await fetch(API_URL, {
236
- method: 'POST',
237
- headers: {
238
- 'Content-Type': 'application/json',
239
- 'x-api-key': apiKey,
240
- 'anthropic-version': '2023-06-01',
241
- },
242
- body,
243
- });
244
-
245
- if (!res.ok) {
246
- const errText = await res.text();
247
- throw new Error(`Anthropic API ${res.status}: ${errText.substring(0, 200)}`);
248
- }
249
-
250
- let fullText = '';
251
- const reader = res.body.getReader();
252
- const decoder = new TextDecoder();
253
- let buf = '';
254
-
255
- while (true) {
256
- const { done, value } = await reader.read();
257
- if (done) break;
258
- buf += decoder.decode(value, { stream: true });
259
- const lines = buf.split('\n');
260
- buf = lines.pop() || '';
261
- for (const line of lines) {
262
- if (!line.startsWith('data: ')) continue;
263
- const data = line.slice(6);
264
- if (data === '[DONE]') continue;
265
- try {
266
- const evt = JSON.parse(data);
267
- if (evt.type === 'content_block_delta' && evt.delta?.text) {
268
- fullText += evt.delta.text;
269
- if (this.onUpdate) {
270
- this.onUpdate({ update: { sessionUpdate: 'agent_message_chunk', content: { text: evt.delta.text } } });
271
- }
272
- }
273
- } catch (_) {}
274
- }
275
- }
276
-
277
- return { stopReason: 'end_turn', result: fullText };
274
+ throw new Error('Claude Code uses OAuth and requires the ACP bridge. The fallback to direct API calls is not supported because OAuth tokens cannot be used with the Anthropic API directly. Please ensure claude-code-acp is available in your PATH.');
278
275
  }
279
276
 
280
277
  isRunning() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentgui",
3
- "version": "1.0.11",
3
+ "version": "1.0.13",
4
4
  "description": "Multi-agent ACP client with real-time communication",
5
5
  "type": "module",
6
6
  "main": "server.js",