create-walle 0.4.3 → 0.4.5
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/package.json
CHANGED
|
@@ -123,6 +123,7 @@
|
|
|
123
123
|
<div class="done-section">
|
|
124
124
|
<a href="/index.html" id="done-link">Go to Dashboard →</a>
|
|
125
125
|
<div style="margin-top:8px;font-size:12px;color:var(--dim)">You can return to this page anytime from the settings icon in the nav bar.</div>
|
|
126
|
+
<div id="version-label" style="margin-top:16px;font-size:11px;color:#30363d"></div>
|
|
126
127
|
</div>
|
|
127
128
|
</div>
|
|
128
129
|
|
|
@@ -139,6 +140,9 @@
|
|
|
139
140
|
if (d.slack_connected) {
|
|
140
141
|
document.getElementById('slack-btn').outerHTML = '<span class="badge badge-connected">Connected</span>';
|
|
141
142
|
}
|
|
143
|
+
if (d.version) {
|
|
144
|
+
document.getElementById('version-label').textContent = 'Wall-E v' + d.version;
|
|
145
|
+
}
|
|
142
146
|
} catch {}
|
|
143
147
|
}
|
|
144
148
|
|
|
@@ -202,44 +202,58 @@ function handleApi(req, res, url) {
|
|
|
202
202
|
slackConnected = fs.existsSync(tokPath);
|
|
203
203
|
} catch {}
|
|
204
204
|
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
205
|
-
|
|
205
|
+
let version = '';
|
|
206
|
+
try { version = require('../package.json').version; } catch {}
|
|
207
|
+
res.end(JSON.stringify({ owner_name: ownerName, has_api_key: hasApiKey, slack_connected: slackConnected, needs_setup: setup.needsSetup(), version }));
|
|
206
208
|
return;
|
|
207
209
|
}
|
|
208
210
|
if (url.pathname === '/api/setup/detect-key' && req.method === 'GET') {
|
|
211
|
+
// Detect API credentials from external sources (NOT .env — that's what we're trying to populate).
|
|
212
|
+
// Priority: 1) devbox auth file, 2) shell environment, 3) Claude Code keychain
|
|
213
|
+
const { execFileSync } = require('child_process');
|
|
209
214
|
let key = '';
|
|
210
215
|
let source = '';
|
|
211
|
-
let gateway = null;
|
|
212
|
-
|
|
213
|
-
// 1. Check for corporate gateway setup (Portkey, cybertron, etc.)
|
|
214
|
-
if (process.env.ANTHROPIC_BASE_URL && process.env.ANTHROPIC_CUSTOM_HEADERS_B64) {
|
|
215
|
-
gateway = {
|
|
216
|
-
base_url: process.env.ANTHROPIC_BASE_URL,
|
|
217
|
-
auth_token: process.env.ANTHROPIC_AUTH_TOKEN || 'sk-ant-api03-unused',
|
|
218
|
-
custom_headers_b64: process.env.ANTHROPIC_CUSTOM_HEADERS_B64,
|
|
219
|
-
};
|
|
220
|
-
source = 'Claude Code gateway (' + process.env.ANTHROPIC_BASE_URL.replace(/https?:\/\//, '').split('/')[0] + ')';
|
|
221
|
-
}
|
|
216
|
+
let gateway = null;
|
|
222
217
|
|
|
223
|
-
//
|
|
224
|
-
if (
|
|
225
|
-
|
|
226
|
-
|
|
218
|
+
// 1. Devbox corporate gateway (reads auth headers file directly)
|
|
219
|
+
if (process.platform === 'darwin') {
|
|
220
|
+
try {
|
|
221
|
+
const authFile = path.join(process.env.HOME, '.devbox', 'secrets', 'claude', 'auth_headers');
|
|
222
|
+
const headers = fs.readFileSync(authFile, 'utf8').trim();
|
|
223
|
+
if (headers) {
|
|
224
|
+
let baseUrl = '';
|
|
225
|
+
try {
|
|
226
|
+
const claudeScript = fs.readFileSync(path.join(process.env.HOME, '.devbox', 'ai', 'claude', 'claude'), 'utf8');
|
|
227
|
+
const m = claudeScript.match(/VPN_CHECK_URL="(https?:\/\/[^"]+)"/);
|
|
228
|
+
if (m) baseUrl = m[1] + '/v1';
|
|
229
|
+
} catch {}
|
|
230
|
+
if (baseUrl) {
|
|
231
|
+
gateway = {
|
|
232
|
+
base_url: baseUrl,
|
|
233
|
+
auth_token: 'sk-ant-api03-unused',
|
|
234
|
+
custom_headers_b64: Buffer.from(headers).toString('base64'),
|
|
235
|
+
};
|
|
236
|
+
source = 'Claude Code devbox (' + baseUrl.replace(/https?:\/\//, '').split('/')[0] + ')';
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
} catch {}
|
|
227
240
|
}
|
|
228
241
|
|
|
229
|
-
//
|
|
242
|
+
// 2. Shell environment (fresh from login shell, not inherited .env)
|
|
230
243
|
if (!gateway && !key) {
|
|
231
244
|
try {
|
|
232
|
-
const { execFileSync } = require('child_process');
|
|
233
245
|
const shell = process.env.SHELL || '/bin/zsh';
|
|
234
|
-
const result = execFileSync(shell, ['-ilc', 'echo $ANTHROPIC_API_KEY'], { encoding: 'utf8', timeout:
|
|
235
|
-
if (result && result.
|
|
246
|
+
const result = execFileSync(shell, ['-ilc', 'echo "$ANTHROPIC_API_KEY"'], { encoding: 'utf8', timeout: 5000 }).trim();
|
|
247
|
+
if (result && result.length > 5 && result !== 'sk-ant-api03-unused') {
|
|
248
|
+
key = result;
|
|
249
|
+
source = 'shell environment';
|
|
250
|
+
}
|
|
236
251
|
} catch {}
|
|
237
252
|
}
|
|
238
253
|
|
|
239
|
-
//
|
|
254
|
+
// 3. Claude Code OAuth token from macOS Keychain
|
|
240
255
|
if (!gateway && !key && process.platform === 'darwin') {
|
|
241
256
|
try {
|
|
242
|
-
const { execFileSync } = require('child_process');
|
|
243
257
|
const credJson = execFileSync('security', ['find-generic-password', '-s', 'Claude Code-credentials', '-w'], { encoding: 'utf8', timeout: 3000 }).trim();
|
|
244
258
|
if (credJson) {
|
|
245
259
|
const cred = JSON.parse(credJson);
|
|
@@ -251,11 +265,7 @@ function handleApi(req, res, url) {
|
|
|
251
265
|
source = 'Claude Code (OAuth)';
|
|
252
266
|
} else {
|
|
253
267
|
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
254
|
-
res.end(JSON.stringify({
|
|
255
|
-
found: false,
|
|
256
|
-
claude_code_expired: true,
|
|
257
|
-
hint: 'Found Claude Code, but the OAuth token has expired. Run "claude" in your terminal once to refresh it, then click Detect again.'
|
|
258
|
-
}));
|
|
268
|
+
res.end(JSON.stringify({ found: false, claude_code_expired: true, hint: 'Found Claude Code, but the OAuth token has expired. Run "claude" in your terminal once to refresh it, then click Detect again.' }));
|
|
259
269
|
return;
|
|
260
270
|
}
|
|
261
271
|
}
|
|
@@ -269,7 +279,7 @@ function handleApi(req, res, url) {
|
|
|
269
279
|
} else if (key) {
|
|
270
280
|
res.end(JSON.stringify({ found: true, key, source }));
|
|
271
281
|
} else {
|
|
272
|
-
res.end(JSON.stringify({ found: false, hint: 'No API key found. Checked:
|
|
282
|
+
res.end(JSON.stringify({ found: false, hint: 'No API key found. Checked: devbox auth, shell environment, Claude Code keychain. Enter your key manually or get one at console.anthropic.com' }));
|
|
273
283
|
}
|
|
274
284
|
return;
|
|
275
285
|
}
|
|
@@ -339,6 +349,10 @@ function handleApi(req, res, url) {
|
|
|
339
349
|
}
|
|
340
350
|
fs.writeFileSync(envPath, lines.join('\n') + '\n', { mode: 0o600 });
|
|
341
351
|
setup.clearSetupCache(); // so next / request goes to dashboard
|
|
352
|
+
// Restart Wall-E so it picks up the new env vars from .env
|
|
353
|
+
if (apiKey || gw) {
|
|
354
|
+
_restartWalleQuiet();
|
|
355
|
+
}
|
|
342
356
|
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
343
357
|
res.end(JSON.stringify({ ok: true }));
|
|
344
358
|
} catch (e) {
|
|
@@ -2181,6 +2195,24 @@ function apiStartWalle(req, res) {
|
|
|
2181
2195
|
});
|
|
2182
2196
|
}
|
|
2183
2197
|
|
|
2198
|
+
// Silent Wall-E restart (no HTTP response needed) — used after saving API key
|
|
2199
|
+
function _restartWalleQuiet() {
|
|
2200
|
+
const walleDir = path.join(__dirname, '..', 'wall-e');
|
|
2201
|
+
const agentScript = path.join(walleDir, 'agent.js');
|
|
2202
|
+
execFile('lsof', ['-ti', ':' + WALLE_PORT], (err, stdout) => {
|
|
2203
|
+
const pids = (stdout || '').trim().split('\n').filter(Boolean);
|
|
2204
|
+
for (const pid of pids) { try { process.kill(parseInt(pid), 'SIGTERM'); } catch {} }
|
|
2205
|
+
setTimeout(() => {
|
|
2206
|
+
const child = require('child_process').spawn(
|
|
2207
|
+
process.execPath, [agentScript],
|
|
2208
|
+
{ cwd: walleDir, detached: true, stdio: 'ignore', env: { ...process.env, WALL_E_PORT: String(WALLE_PORT) } }
|
|
2209
|
+
);
|
|
2210
|
+
child.unref();
|
|
2211
|
+
console.log('[setup] Restarted Wall-E (PID ' + child.pid + ') to pick up new API config');
|
|
2212
|
+
}, 1000);
|
|
2213
|
+
});
|
|
2214
|
+
}
|
|
2215
|
+
|
|
2184
2216
|
function apiRestartCtm(req, res) {
|
|
2185
2217
|
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
2186
2218
|
res.end(JSON.stringify({ ok: true, message: 'CTM server restarting...' }));
|