orchestrating 0.3.3 → 0.4.0
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 +42 -11
- package/package.json +1 -1
package/bin/orch
CHANGED
|
@@ -1057,6 +1057,7 @@ if (adapter) {
|
|
|
1057
1057
|
// Spawn claude with bidirectional stdin/stdout (stream-json mode)
|
|
1058
1058
|
// Follow-ups are sent via stdin — no more kill/respawn.
|
|
1059
1059
|
let claudeSessionId = null; // Claude's internal session ID (from init event)
|
|
1060
|
+
let pendingRespawn = null; // { prompt } — set when permission grant needs respawn
|
|
1060
1061
|
|
|
1061
1062
|
function spawnClaude(claudeArgs) {
|
|
1062
1063
|
const proc = spawn(command, claudeArgs, {
|
|
@@ -1104,8 +1105,8 @@ if (adapter) {
|
|
|
1104
1105
|
if (yoloMode && event.kind === "permission_denied") {
|
|
1105
1106
|
process.stderr.write(`${GREEN}[yolo] Auto-approving: ${event.toolName}${RESET}\n`);
|
|
1106
1107
|
approvePermission(event.toolName, "session");
|
|
1107
|
-
//
|
|
1108
|
-
|
|
1108
|
+
// Queue respawn — Claude will exit after this turn, then we respawn with -c
|
|
1109
|
+
pendingRespawn = { prompt: `Permission for ${event.toolName} was granted. Please retry your last action.` };
|
|
1109
1110
|
}
|
|
1110
1111
|
}
|
|
1111
1112
|
});
|
|
@@ -1117,8 +1118,23 @@ if (adapter) {
|
|
|
1117
1118
|
proc.on("exit", (code) => {
|
|
1118
1119
|
childRunning = false;
|
|
1119
1120
|
const exitCode = code ?? 0;
|
|
1120
|
-
|
|
1121
|
-
|
|
1121
|
+
|
|
1122
|
+
if (exitCode !== 0 || exitRequested) {
|
|
1123
|
+
// Non-zero exit or user requested stop — terminate
|
|
1124
|
+
sendToServer({ type: "exit", sessionId, exitCode });
|
|
1125
|
+
setTimeout(() => process.exit(exitCode), 200);
|
|
1126
|
+
} else if (pendingRespawn) {
|
|
1127
|
+
// Permission grant/deny triggered a respawn — do it now
|
|
1128
|
+
const { prompt: respawnPrompt } = pendingRespawn;
|
|
1129
|
+
pendingRespawn = null;
|
|
1130
|
+
respawnWithContinue(respawnPrompt);
|
|
1131
|
+
} else {
|
|
1132
|
+
// Normal exit (turn complete) — stay alive, emit idle, wait for follow-ups
|
|
1133
|
+
sendToServer({
|
|
1134
|
+
type: "agent_event", sessionId,
|
|
1135
|
+
event: { kind: "status", status: "idle" },
|
|
1136
|
+
});
|
|
1137
|
+
}
|
|
1122
1138
|
});
|
|
1123
1139
|
|
|
1124
1140
|
proc.on("error", (err) => {
|
|
@@ -1283,10 +1299,9 @@ if (adapter) {
|
|
|
1283
1299
|
|
|
1284
1300
|
handleServerMessage = (msg) => {
|
|
1285
1301
|
if (msg.type === "agent_input" && (msg.text || msg.images)) {
|
|
1286
|
-
// Follow-up from dashboard
|
|
1302
|
+
// Follow-up from dashboard
|
|
1287
1303
|
if (childRunning) {
|
|
1288
1304
|
process.stderr.write(`${DIM}[orch] Queuing input — claude is still processing${RESET}\n`);
|
|
1289
|
-
// TODO: queue and send after current turn completes
|
|
1290
1305
|
return;
|
|
1291
1306
|
}
|
|
1292
1307
|
let promptText = msg.text || "continue";
|
|
@@ -1303,17 +1318,33 @@ if (adapter) {
|
|
|
1303
1318
|
const fileList = imagePaths.map((p) => `[Attached image: ${p} — use Read tool to view]`).join("\n");
|
|
1304
1319
|
promptText = `${fileList}\n\n${promptText}`;
|
|
1305
1320
|
}
|
|
1306
|
-
|
|
1321
|
+
// If process is still alive, send via stdin; otherwise respawn
|
|
1322
|
+
if (child && child.exitCode === null) {
|
|
1323
|
+
sendFollowUp(promptText);
|
|
1324
|
+
} else {
|
|
1325
|
+
respawnWithContinue(promptText);
|
|
1326
|
+
}
|
|
1307
1327
|
} else if (msg.type === "agent_permission" && msg.tool && msg.action === "allow") {
|
|
1308
1328
|
const scope = msg.scope || "session";
|
|
1309
1329
|
approvePermission(msg.tool, scope);
|
|
1310
1330
|
process.stderr.write(`${GREEN}Permission granted (${scope}): ${msg.tool}${RESET}\n`);
|
|
1311
|
-
// Permissions are file-based
|
|
1312
|
-
|
|
1313
|
-
|
|
1331
|
+
// Permissions are file-based — Claude needs restart to pick up settings.local.json
|
|
1332
|
+
const respawnPrompt = `Permission for ${msg.tool} was granted. Please retry your last action.`;
|
|
1333
|
+
if (child && child.exitCode === null) {
|
|
1334
|
+
// Process still running — queue respawn for when it exits
|
|
1335
|
+
pendingRespawn = { prompt: respawnPrompt };
|
|
1336
|
+
} else {
|
|
1337
|
+
// Process already exited — respawn now
|
|
1338
|
+
respawnWithContinue(respawnPrompt);
|
|
1339
|
+
}
|
|
1314
1340
|
} else if (msg.type === "agent_permission" && msg.tool && msg.action === "deny") {
|
|
1315
1341
|
process.stderr.write(`${RED}Permission denied: ${msg.tool}${RESET}\n`);
|
|
1316
|
-
|
|
1342
|
+
const denyPrompt = `Permission for ${msg.tool} was denied by the user. Do not retry this tool — find an alternative approach or skip this step.`;
|
|
1343
|
+
if (child && child.exitCode === null) {
|
|
1344
|
+
pendingRespawn = { prompt: denyPrompt };
|
|
1345
|
+
} else {
|
|
1346
|
+
respawnWithContinue(denyPrompt);
|
|
1347
|
+
}
|
|
1317
1348
|
} else if (msg.type === "agent_permission" && msg.tool && msg.action === "revoke") {
|
|
1318
1349
|
removePermission(msg.tool);
|
|
1319
1350
|
broadcastPermissions();
|