You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit 96e54da
Browse filesBrowse the repository at this point in the historyBrowse files
* stdin and write stderr, so a piped stdout must not disable them: stdin TTY
1416
1424
* alone means an operator can answer. Fully headless (stdin not a TTY) fails
1417
1425
* closed — denials name the action and the remedy on stderr instead of
1418
-
* prompting. stdoutTTY rides along so the call site stays explicit that a
1426
+
* prompting (gate onHeadlessDeny wiring above, not the prompt seam: the gate
1427
+
* denies headless asks before requestApproval is ever reached). stdoutTTY
1428
+
* rides along so the call site stays explicit that a
1419
1429
* piped stdout is a supported prompting configuration, not an oversight.
1420
1430
*/
1421
1431
exportfunctionresolveExecInteractive(stdio: {
@@ -1450,22 +1460,9 @@ async function promptOperator(
1450
1460
}
1451
1461
}
1452
1462
1453
-
exportasyncfunctionpromptPermission(
1463
+
asyncfunctionpromptPermission(
1454
1464
request: PermissionRequest,
1455
-
interactive: boolean,
1456
1465
): Promise<ApprovalOutcome>{
1457
-
if(!interactive){
1458
-
// Fail closed and say so on stderr (never stdout: piped stdout may feed
1459
-
// JSON consumers — see printResumeHint). A headless ask has no operator
1460
-
// to answer, so the denial names the action and the bypass instead of
1461
-
// vanishing into a generic block. Same sentence as the gate's
1462
-
// non-interactive deny reasons (src/permission/gate.ts) by intent; the
1463
-
// gate stays canonical for model-facing text, this seam for the operator.
1464
-
stderr.write(
1465
-
`Permission denied: ${request.action} requires operator approval, which is unavailable in a non-interactive run. Re-run with --dangerously-skip-permissions to bypass, or narrow the action.\n`,
1466
-
);
1467
-
return{allow: false};
1468
-
}
1469
1466
// Same freeze-while-deciding contract as the TUI gate: the tool wall-clock
1470
1467
// budget must not run down while the operator reads the prompt.
// The --dangerously-skip-permissions escape hatch: auto-allow anything the
399
406
// authorization layer did not already deny.
400
407
skipPermissions: boolean;
@@ -1023,6 +1030,7 @@ export function createPermissionGate(
1023
1030
? `${request.action} references a sensitive path and requires operator approval, which is unavailable in a non-interactive run.`
1024
1031
: `${request.action} requires operator approval, which is unavailable in a non-interactive run. Re-run with --dangerously-skip-permissions to bypass, or narrow the action.`;
1025
1032
denialMemory.record(stableId,reason);
1033
+
options.onHeadlessDeny?.(reason);
1026
1034
return{kind: "deny", reason };
1027
1035
}
1028
1036
@@ -1067,6 +1075,7 @@ export function createPermissionGate(
constreason=`${request.action} requires operator approval, which is unavailable in a non-interactive run. Re-run with --dangerously-skip-permissions to bypass, or narrow the action.`;
0 commit comments