orchestrating 0.1.6 → 0.1.9
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/bin/orch +54 -29
- package/package.json +1 -1
package/bin/orch
CHANGED
|
@@ -342,7 +342,6 @@ if (adapter) {
|
|
|
342
342
|
|
|
343
343
|
// Spawn a claude process and wire up output handling
|
|
344
344
|
function spawnClaude(claudeArgs) {
|
|
345
|
-
process.stderr.write(`${DIM}[orch] Spawning: ${command} ${claudeArgs.join(" ")}${RESET}\n`);
|
|
346
345
|
const proc = spawn(command, claudeArgs, {
|
|
347
346
|
stdio: ["ignore", "pipe", "pipe"],
|
|
348
347
|
cwd: process.cwd(),
|
|
@@ -350,16 +349,12 @@ if (adapter) {
|
|
|
350
349
|
});
|
|
351
350
|
childRunning = true;
|
|
352
351
|
child = proc;
|
|
353
|
-
process.stderr.write(`${DIM}[orch] Child PID: ${proc.pid}${RESET}\n`);
|
|
354
352
|
|
|
355
353
|
// Parse NDJSON from stdout line-by-line
|
|
356
354
|
const rl = readline.createInterface({ input: proc.stdout });
|
|
357
355
|
let permissionsSent = false;
|
|
358
|
-
let lineCount = 0;
|
|
359
356
|
|
|
360
357
|
rl.on("line", (line) => {
|
|
361
|
-
lineCount++;
|
|
362
|
-
process.stderr.write(`${DIM}[orch] stdout line #${lineCount}: ${line.slice(0, 120)}${RESET}\n`);
|
|
363
358
|
if (!permissionsSent) {
|
|
364
359
|
permissionsSent = true;
|
|
365
360
|
broadcastPermissions();
|
|
@@ -369,41 +364,41 @@ if (adapter) {
|
|
|
369
364
|
try {
|
|
370
365
|
raw = JSON.parse(line);
|
|
371
366
|
} catch {
|
|
372
|
-
process.stderr.write(`${DIM}[orch] JSON parse failed for line${RESET}\n`);
|
|
373
367
|
return;
|
|
374
368
|
}
|
|
375
369
|
|
|
376
370
|
// Normalize and relay each event
|
|
377
371
|
const events = normalizeClaudeEvent(raw);
|
|
378
|
-
process.stderr.write(`${DIM}[orch] Normalized ${events.length} events (type=${raw.type})${RESET}\n`);
|
|
379
372
|
for (const event of events) {
|
|
380
373
|
printLocalEvent(event);
|
|
381
374
|
sendToServer({ type: "agent_event", sessionId, event });
|
|
382
375
|
|
|
383
|
-
// Yolo mode: auto-approve permission denials
|
|
376
|
+
// Yolo mode: auto-approve permission denials — save to settings,
|
|
377
|
+
// claude will pick it up on respawn via pendingPermissionGrant
|
|
384
378
|
if (yoloMode && event.kind === "permission_denied") {
|
|
385
379
|
process.stderr.write(`${GREEN}[yolo] Auto-approving: ${event.toolName}${RESET}\n`);
|
|
386
380
|
approvePermission(event.toolName, "session");
|
|
381
|
+
pendingPermissionGrant = event.toolName;
|
|
387
382
|
}
|
|
388
383
|
}
|
|
389
384
|
});
|
|
390
385
|
|
|
391
|
-
proc.stdout.on("end", () => {
|
|
392
|
-
process.stderr.write(`${DIM}[orch] stdout stream ended (${lineCount} lines total)${RESET}\n`);
|
|
393
|
-
});
|
|
394
|
-
|
|
395
386
|
proc.stderr.on("data", (buf) => {
|
|
396
|
-
process.stderr.write(`${DIM}[orch] child stderr: ${RESET}`);
|
|
397
387
|
process.stderr.write(buf);
|
|
398
388
|
});
|
|
399
389
|
|
|
400
|
-
proc.on("exit", (code
|
|
390
|
+
proc.on("exit", (code) => {
|
|
401
391
|
childRunning = false;
|
|
402
|
-
process.stderr.write(`${DIM}[orch] Child exited: code=${code} signal=${signal}${RESET}\n`);
|
|
403
392
|
const exitCode = code ?? 0;
|
|
404
393
|
if (exitCode !== 0 || exitRequested) {
|
|
405
394
|
sendToServer({ type: "exit", sessionId, exitCode });
|
|
406
395
|
setTimeout(() => process.exit(exitCode), 200);
|
|
396
|
+
} else if (pendingPermissionGrant) {
|
|
397
|
+
// Permission was granted while claude was running — respawn to retry
|
|
398
|
+
const tool = pendingPermissionGrant;
|
|
399
|
+
pendingPermissionGrant = null;
|
|
400
|
+
process.stderr.write(`${GREEN}Retrying with new permission: ${tool}${RESET}\n`);
|
|
401
|
+
respawnWithContinue(`Permission for ${tool} was granted. Please retry your last action.`);
|
|
407
402
|
} else {
|
|
408
403
|
sendToServer({
|
|
409
404
|
type: "agent_event", sessionId,
|
|
@@ -414,7 +409,7 @@ if (adapter) {
|
|
|
414
409
|
|
|
415
410
|
proc.on("error", (err) => {
|
|
416
411
|
childRunning = false;
|
|
417
|
-
|
|
412
|
+
console.error("Failed to start:", err.message);
|
|
418
413
|
process.exit(1);
|
|
419
414
|
});
|
|
420
415
|
|
|
@@ -468,23 +463,45 @@ if (adapter) {
|
|
|
468
463
|
}
|
|
469
464
|
spawnClaude(initialArgs);
|
|
470
465
|
|
|
466
|
+
// Emit the initial prompt as a user message so the dashboard shows it
|
|
467
|
+
if (prompt) {
|
|
468
|
+
sendToServer({
|
|
469
|
+
type: "agent_event", sessionId,
|
|
470
|
+
event: { kind: "user_message", text: prompt },
|
|
471
|
+
});
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
// Respawn claude with -c to continue after permission grants or follow-up
|
|
475
|
+
function respawnWithContinue(prompt) {
|
|
476
|
+
const args = ["--output-format", "stream-json", "--verbose", "-c"];
|
|
477
|
+
if (prompt) args.push("-p", prompt);
|
|
478
|
+
if (yoloMode) args.push("--dangerously-skip-permissions");
|
|
479
|
+
spawnClaude(args);
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
// Queue of permission grants received while claude is still running
|
|
483
|
+
let pendingPermissionGrant = null;
|
|
484
|
+
|
|
471
485
|
handleServerMessage = (msg) => {
|
|
472
486
|
if (msg.type === "agent_input" && (msg.text || msg.images)) {
|
|
473
487
|
// Follow-up from dashboard — spawn new claude with -c (continue)
|
|
474
488
|
if (childRunning) {
|
|
475
|
-
// Child still running, queue or ignore
|
|
476
489
|
process.stderr.write(`${DIM}[orch] Ignoring input — claude is still running${RESET}\n`);
|
|
477
490
|
return;
|
|
478
491
|
}
|
|
479
|
-
|
|
480
|
-
if (yoloMode) {
|
|
481
|
-
followUpArgs.push("--dangerously-skip-permissions");
|
|
482
|
-
}
|
|
483
|
-
spawnClaude(followUpArgs);
|
|
492
|
+
respawnWithContinue(msg.text || "continue");
|
|
484
493
|
} else if (msg.type === "agent_permission" && msg.tool && msg.action === "allow") {
|
|
485
494
|
const scope = msg.scope || "session";
|
|
486
495
|
approvePermission(msg.tool, scope);
|
|
487
496
|
process.stderr.write(`${GREEN}Permission granted (${scope}): ${msg.tool}${RESET}\n`);
|
|
497
|
+
|
|
498
|
+
if (childRunning) {
|
|
499
|
+
// Claude is still running — remember the grant and respawn when it exits
|
|
500
|
+
pendingPermissionGrant = msg.tool;
|
|
501
|
+
} else {
|
|
502
|
+
// Claude already finished — respawn with -c to retry with new permission
|
|
503
|
+
respawnWithContinue(`Permission for ${msg.tool} was granted. Please retry your last action.`);
|
|
504
|
+
}
|
|
488
505
|
} else if (msg.type === "agent_permission" && msg.tool && msg.action === "revoke") {
|
|
489
506
|
removePermission(msg.tool);
|
|
490
507
|
broadcastPermissions();
|
|
@@ -535,7 +552,18 @@ if (adapter) {
|
|
|
535
552
|
if (process.stdin.isTTY) {
|
|
536
553
|
process.stdin.setRawMode(false);
|
|
537
554
|
}
|
|
538
|
-
|
|
555
|
+
// Wait for WS to connect and flush buffer before exiting
|
|
556
|
+
// (fast commands like `ls` may finish before the WS handshake)
|
|
557
|
+
function tryExit() {
|
|
558
|
+
if (wsReady && sendBuffer.length === 0) {
|
|
559
|
+
setTimeout(() => process.exit(exitCode), 100);
|
|
560
|
+
} else {
|
|
561
|
+
setTimeout(tryExit, 50);
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
// Give up after 3 seconds regardless
|
|
565
|
+
setTimeout(() => process.exit(exitCode), 3000);
|
|
566
|
+
tryExit();
|
|
539
567
|
});
|
|
540
568
|
|
|
541
569
|
child.on("error", (err) => {
|
|
@@ -770,8 +798,6 @@ function connectWs() {
|
|
|
770
798
|
ws = new WebSocket(serverUrl);
|
|
771
799
|
|
|
772
800
|
ws.on("open", () => {
|
|
773
|
-
process.stderr.write(`${DIM}[orch] WS connected to ${serverUrl}${RESET}\n`);
|
|
774
|
-
process.stderr.write(`${DIM}[orch] Token: ${authToken ? authToken.slice(0, 20) + "..." : "(none)"}${RESET}\n`);
|
|
775
801
|
ws.send(JSON.stringify({
|
|
776
802
|
type: "register",
|
|
777
803
|
token: authToken,
|
|
@@ -816,8 +842,7 @@ function connectWs() {
|
|
|
816
842
|
} catch {}
|
|
817
843
|
});
|
|
818
844
|
|
|
819
|
-
ws.on("close", (
|
|
820
|
-
process.stderr.write(`${DIM}[orch] WS closed: code=${code} reason=${reason}${RESET}\n`);
|
|
845
|
+
ws.on("close", () => {
|
|
821
846
|
wsReady = false;
|
|
822
847
|
ws = null;
|
|
823
848
|
if (!authFailed) {
|
|
@@ -825,8 +850,8 @@ function connectWs() {
|
|
|
825
850
|
}
|
|
826
851
|
});
|
|
827
852
|
|
|
828
|
-
ws.on("error", (
|
|
829
|
-
|
|
853
|
+
ws.on("error", () => {
|
|
854
|
+
// Will trigger close
|
|
830
855
|
});
|
|
831
856
|
}
|
|
832
857
|
|