esque-bridge 0.2.0 → 0.2.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/index.js +43 -5
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -138,7 +138,20 @@ const ADAPTERS = {
|
|
|
138
138
|
// `--output-format json` returns a single JSON object with
|
|
139
139
|
// {result, session_id, is_error, ...} — easy to parse, exact.
|
|
140
140
|
buildArgs(_prompt, prevSessionId) {
|
|
141
|
-
|
|
141
|
+
// `--dangerously-skip-permissions` lets Claude actually use its
|
|
142
|
+
// Write / Edit / Bash tools without an interactive approval prompt.
|
|
143
|
+
// In headless `--print` mode there's no way to say "yes" to a
|
|
144
|
+
// permission request, so without this every file write is silently
|
|
145
|
+
// blocked — the agent looks busy but can't touch the disk. This is
|
|
146
|
+
// the autonomous-bridge use case the flag exists for; access is
|
|
147
|
+
// already gated by the per-session pairing secret. (Mirrors Aider's
|
|
148
|
+
// `--yes-always` below.)
|
|
149
|
+
const args = [
|
|
150
|
+
'--print',
|
|
151
|
+
'--output-format',
|
|
152
|
+
'json',
|
|
153
|
+
'--dangerously-skip-permissions',
|
|
154
|
+
];
|
|
142
155
|
if (prevSessionId) args.push('--resume', prevSessionId);
|
|
143
156
|
return args;
|
|
144
157
|
},
|
|
@@ -371,17 +384,42 @@ async function executeHandler(req, res) {
|
|
|
371
384
|
`[bridge] POST ${preview}… esque=${esqueSessionId ?? '-'} ${AGENT_TYPE}=${prev ?? 'new'}`,
|
|
372
385
|
);
|
|
373
386
|
|
|
387
|
+
// Stream a keep-alive heartbeat while the agent thinks. `claude --print`
|
|
388
|
+
// emits nothing until it finishes (often 30–120s on a cold start with a big
|
|
389
|
+
// prompt), and localtunnel / intervening proxies close *idle* connections —
|
|
390
|
+
// which surfaced on the phone as "fetch request has been canceled". A space
|
|
391
|
+
// every few seconds keeps the connection active. The phone trims the body
|
|
392
|
+
// before JSON.parse, so leading whitespace is harmless.
|
|
393
|
+
res.status(200);
|
|
394
|
+
res.setHeader('Content-Type', 'application/json; charset=utf-8');
|
|
395
|
+
res.setHeader('Cache-Control', 'no-cache, no-transform');
|
|
396
|
+
const heartbeat = setInterval(() => {
|
|
397
|
+
try {
|
|
398
|
+
res.write(' ');
|
|
399
|
+
} catch {
|
|
400
|
+
/* socket already closed */
|
|
401
|
+
}
|
|
402
|
+
}, 5000);
|
|
403
|
+
const finish = (payload) => {
|
|
404
|
+
clearInterval(heartbeat);
|
|
405
|
+
try {
|
|
406
|
+
res.end(JSON.stringify(payload));
|
|
407
|
+
} catch {
|
|
408
|
+
/* socket already closed */
|
|
409
|
+
}
|
|
410
|
+
};
|
|
411
|
+
|
|
374
412
|
try {
|
|
375
413
|
const result = await runAgent(prompt, esqueSessionId);
|
|
376
|
-
|
|
414
|
+
finish({
|
|
377
415
|
text: result.text,
|
|
378
416
|
status: result.isError ? 'blocked' : 'finished',
|
|
379
417
|
});
|
|
380
418
|
} catch (err) {
|
|
381
419
|
console.error('[bridge] error:', err.message);
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
420
|
+
// Headers are already sent (heartbeat), so the error rides in the body
|
|
421
|
+
// with status 'blocked' rather than an HTTP 500.
|
|
422
|
+
finish({ text: `${adapter.label} failed: ${err.message}`, status: 'blocked' });
|
|
385
423
|
}
|
|
386
424
|
}
|
|
387
425
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "esque-bridge",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"description": "Desktop-side receiver for the Esque Agent mobile app. Pairs your phone with a local coding-agent CLI (Claude Code, Aider, or any custom command) via a tunnel + QR code, so prompts run through your subscription instead of per-token API billing.",
|
|
5
5
|
"bin": {
|
|
6
6
|
"esque-bridge": "index.js"
|