@pushary/agent-hooks 0.87.4 → 0.88.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/CHANGELOG.md +20 -0
- package/data/cursor-plugin/scripts/pushary-gate.mjs +63 -7
- package/data/vscode-plugin/scripts/pushary-gate.mjs +56 -18
- package/dist/bin/pushary-bell-hook.js +4 -4
- package/dist/bin/pushary-bell.js +7 -7
- package/dist/bin/pushary-claude.js +9 -9
- package/dist/bin/pushary-clean.js +13 -14
- package/dist/bin/pushary-codex-bridge.js +6 -6
- package/dist/bin/pushary-codex-hook.js +15 -9
- package/dist/bin/pushary-codex.js +4 -4
- package/dist/bin/pushary-connect.js +6 -6
- package/dist/bin/pushary-daemon.js +5 -5
- package/dist/bin/pushary-disconnect.js +9 -11
- package/dist/bin/pushary-doctor.js +17 -16
- package/dist/bin/pushary-elicitation-hook.js +7 -120
- package/dist/bin/pushary-gemini-bridge.js +6 -6
- package/dist/bin/pushary-gemini-hook.js +15 -9
- package/dist/bin/pushary-hook.js +6 -6
- package/dist/bin/pushary-login.js +4 -4
- package/dist/bin/pushary-logout.js +4 -4
- package/dist/bin/pushary-mode.js +3 -3
- package/dist/bin/pushary-notification-hook.js +4 -4
- package/dist/bin/pushary-opencode-hook.js +5 -5
- package/dist/bin/pushary-permission-denied-hook.js +6 -6
- package/dist/bin/pushary-permission-hook.js +6 -6
- package/dist/bin/pushary-post-hook.js +4 -4
- package/dist/bin/pushary-prompt-hook.js +4 -4
- package/dist/bin/pushary-session-end-hook.js +4 -4
- package/dist/bin/pushary-session-start-hook.js +4 -4
- package/dist/bin/pushary-setup.js +26 -25
- package/dist/bin/pushary-stats.js +2 -2
- package/dist/bin/pushary-status.js +5 -5
- package/dist/bin/pushary-stop-hook.js +4 -4
- package/dist/bin/pushary-stopfailure-hook.js +4 -4
- package/dist/bin/pushary-upgrade.js +9 -11
- package/dist/bin/pushary-wait.js +3 -3
- package/dist/{chunk-H5PIPIKQ.js → chunk-4FANZF2L.js} +2 -2
- package/dist/{chunk-ZGC3W23N.js → chunk-4KMWTOBK.js} +4 -1
- package/dist/{chunk-QLMX5LLV.js → chunk-6GBQDZ7K.js} +1 -1
- package/dist/{chunk-B7ZBHWOW.js → chunk-AIGDBRIJ.js} +1 -1
- package/dist/{chunk-KBS53WOE.js → chunk-AJ4EMW5D.js} +1 -1
- package/dist/{chunk-ICERLAE2.js → chunk-DLI5IXSD.js} +1 -1
- package/dist/{chunk-YX6ZKCC5.js → chunk-EKNFTIKO.js} +1 -1
- package/dist/{chunk-K42RXJPG.js → chunk-F3ZDPL6O.js} +187 -60
- package/dist/{chunk-NAPRGHZ3.js → chunk-FRH2QIMY.js} +1 -1
- package/dist/{chunk-TV3UFGT7.js → chunk-LNAQWWBP.js} +1 -1
- package/dist/{chunk-7J67NYK4.js → chunk-LXTX5CT7.js} +2 -1
- package/dist/{chunk-KULUNLRO.js → chunk-O7P7O4VY.js} +3 -7
- package/dist/{chunk-VOE4SYPR.js → chunk-OSE7X44J.js} +23 -7
- package/dist/{chunk-VIHRP25S.js → chunk-PXEFENML.js} +1 -1
- package/dist/{chunk-DMW54VWK.js → chunk-Q6MK2YKV.js} +213 -4
- package/dist/{chunk-EJL3PJU7.js → chunk-SHVW5KFR.js} +1 -1
- package/dist/{chunk-QXZ2CKRK.js → chunk-SUZF64M4.js} +2 -2
- package/dist/{chunk-BFBAHOGR.js → chunk-U44C3ULB.js} +1 -1
- package/dist/{chunk-OMA2OZRE.js → chunk-U65EIMUJ.js} +27 -62
- package/dist/{chunk-KFAH6KRE.js → chunk-WFFPWJN6.js} +1 -1
- package/dist/{chunk-YYTLTEGU.js → chunk-WPDMGNQR.js} +1 -1
- package/dist/{chunk-TD3M232T.js → chunk-ZPRF4YLA.js} +1 -1
- package/dist/src/index.js +6 -6
- package/package.json +1 -1
- package/dist/chunk-2JYQAW4B.js +0 -137
- /package/dist/{chunk-VT4IVERX.js → chunk-PZA7G4CN.js} +0 -0
|
@@ -1,6 +1,39 @@
|
|
|
1
1
|
// ../contracts/src/index.ts
|
|
2
2
|
var APPROVAL_MODES = ["push_only", "terminal_only", "push_first", "notify_only"];
|
|
3
3
|
var isApprovalMode = (value) => typeof value === "string" && APPROVAL_MODES.includes(value);
|
|
4
|
+
var MAX_AGENT_QUESTIONS = 4;
|
|
5
|
+
var parseAgentQuestion = (raw) => {
|
|
6
|
+
const q = raw;
|
|
7
|
+
if (!q || typeof q.question !== "string") return void 0;
|
|
8
|
+
const options = Array.isArray(q.options) ? q.options.flatMap((option) => {
|
|
9
|
+
if (!option || typeof option !== "object") return [];
|
|
10
|
+
const value = option;
|
|
11
|
+
if (typeof value.label !== "string" || value.label.length === 0) return [];
|
|
12
|
+
return [{
|
|
13
|
+
label: value.label,
|
|
14
|
+
...typeof value.description === "string" ? { description: value.description } : {}
|
|
15
|
+
}];
|
|
16
|
+
}) : [];
|
|
17
|
+
if (options.length < 2) return void 0;
|
|
18
|
+
return {
|
|
19
|
+
question: q.question,
|
|
20
|
+
...typeof q.header === "string" ? { header: q.header } : {},
|
|
21
|
+
multiSelect: q.multiSelect === true,
|
|
22
|
+
options
|
|
23
|
+
};
|
|
24
|
+
};
|
|
25
|
+
var parseAgentQuestions = (toolInput) => {
|
|
26
|
+
const questions = toolInput.questions;
|
|
27
|
+
if (!Array.isArray(questions) || questions.length === 0) return void 0;
|
|
28
|
+
if (questions.length > MAX_AGENT_QUESTIONS) return void 0;
|
|
29
|
+
const parsed = [];
|
|
30
|
+
for (const raw of questions) {
|
|
31
|
+
const one = parseAgentQuestion(raw);
|
|
32
|
+
if (!one || parsed.some((question) => question.question === one.question)) return void 0;
|
|
33
|
+
parsed.push(one);
|
|
34
|
+
}
|
|
35
|
+
return parsed;
|
|
36
|
+
};
|
|
4
37
|
var parseAgentQuestionAnswers = (questions, value) => {
|
|
5
38
|
let parsed;
|
|
6
39
|
try {
|
|
@@ -43,6 +76,8 @@ var INSTALL_SOURCES = [
|
|
|
43
76
|
/** The browser onboarding wizard. */
|
|
44
77
|
"dashboard",
|
|
45
78
|
/** Reported nothing, or reported something we do not recognise. */
|
|
79
|
+
/** The macOS app pairing a phone from its own onboarding. */
|
|
80
|
+
"mac_app",
|
|
46
81
|
"unknown"
|
|
47
82
|
];
|
|
48
83
|
var isInstallSource = (value) => typeof value === "string" && INSTALL_SOURCES.includes(value);
|
|
@@ -72,6 +107,7 @@ var hookWaitDeadline = (startMs, policyWaitSeconds, agent, nowMs) => {
|
|
|
72
107
|
};
|
|
73
108
|
var hookWaitClamped = (startMs, policyWaitSeconds, agent, nowMs) => startMs + hookMaxWaitSeconds(agent) * 1e3 < nowMs + Math.max(policyWaitSeconds, 0) * 1e3;
|
|
74
109
|
var effectiveWaitSeconds = (timeoutAction, policySeconds, agent) => timeoutAction === "wait" ? hookMaxWaitSeconds(agent) : policySeconds;
|
|
110
|
+
var HOOK_SOURCES = ["claude", "codex", "gemini", "cursor", "vscode", "opencode"];
|
|
75
111
|
var AGENT_LABELS_BY_TYPE = {
|
|
76
112
|
claude_code: "Claude Code",
|
|
77
113
|
claude_cowork: "Claude Cowork",
|
|
@@ -86,6 +122,7 @@ var AGENT_LABELS_BY_TYPE = {
|
|
|
86
122
|
unknown: "Agent"
|
|
87
123
|
};
|
|
88
124
|
var OPENCODE_APPROVAL_EVENT = "permission.ask";
|
|
125
|
+
var CURSOR_GATE_EVENTS = ["beforeShellExecution", "beforeMCPExecution"];
|
|
89
126
|
var HOOK_LOCATOR_BINARY = "pushary-bridge";
|
|
90
127
|
var HOOK_BATCH_MAX_BYTES = 4 * 1024 * 1024;
|
|
91
128
|
var REPO_KEY_MAX_LENGTH = 200;
|
|
@@ -960,8 +997,15 @@ var resolveAutoResolveOrigin = (config, toolName, toolInput, cwd, repoKey, sessi
|
|
|
960
997
|
var resolvePolicy = (config, toolName, modeOverride, toolInput, cwd, repoKey, sessionId) => {
|
|
961
998
|
const args = toolInput ? policyArgForms(toolName, toolInput, cwd) : [];
|
|
962
999
|
const arg = args[0];
|
|
963
|
-
const
|
|
964
|
-
|
|
1000
|
+
const governing = (pool) => {
|
|
1001
|
+
if (pool.length === 0) return void 0;
|
|
1002
|
+
const rule = selectGoverningRule(pool, toolName, args, repoKey, sessionId);
|
|
1003
|
+
if (rule) return rule;
|
|
1004
|
+
const wildcard = pool.find((p) => p.tool === "*");
|
|
1005
|
+
return wildcard ? { policy: wildcard, rank: "wildcard" } : void 0;
|
|
1006
|
+
};
|
|
1007
|
+
const match = governing(config.policies.filter((p) => !p.origin)) ?? governing(config.policies.filter((p) => p.origin === "preset")) ?? governing(config.policies.filter((p) => p.origin === "builtin"));
|
|
1008
|
+
let base = match?.policy ?? {
|
|
965
1009
|
tool: toolName,
|
|
966
1010
|
timeoutSeconds: config.defaultTimeoutSeconds,
|
|
967
1011
|
timeoutAction: config.defaultTimeoutAction,
|
|
@@ -1013,6 +1057,21 @@ var strictestScopeVerdict = (scope, paths) => {
|
|
|
1013
1057
|
return worst;
|
|
1014
1058
|
};
|
|
1015
1059
|
var survivesDegraded = (config, toolName, toolInputs, cwd, repoKey, sessionId) => toolInputs.length === 1 && resolveAutoResolveOrigin(config, toolName, toolInputs[0], cwd, repoKey, sessionId) === "safe_readonly";
|
|
1060
|
+
var FULL_DEFER_MODES = /* @__PURE__ */ new Set(["plan", "auto", "dontAsk"]);
|
|
1061
|
+
var ACCEPT_EDITS_DEFER_TOOLS = /* @__PURE__ */ new Set([
|
|
1062
|
+
"Write",
|
|
1063
|
+
"Edit",
|
|
1064
|
+
"MultiEdit",
|
|
1065
|
+
"NotebookEdit"
|
|
1066
|
+
]);
|
|
1067
|
+
var shouldDeferToNativeMode = (permissionMode, toolName, options = {}) => {
|
|
1068
|
+
if (options.respectPermissionMode === false) return false;
|
|
1069
|
+
if (typeof permissionMode !== "string") return false;
|
|
1070
|
+
if (FULL_DEFER_MODES.has(permissionMode)) return true;
|
|
1071
|
+
if (permissionMode === "acceptEdits" && ACCEPT_EDITS_DEFER_TOOLS.has(toolName)) return true;
|
|
1072
|
+
if (permissionMode === "bypassPermissions") return options.deferBypass === true;
|
|
1073
|
+
return false;
|
|
1074
|
+
};
|
|
1016
1075
|
var resolveGate = (input) => {
|
|
1017
1076
|
const { modeState, config, toolName, toolInputs, cwd, repoKey, sessionId } = input;
|
|
1018
1077
|
if (modeState.kill) return { kind: "kill", reason: KILL_REASON };
|
|
@@ -1068,6 +1127,33 @@ var claudePreToolUseOutput = (decision, reason, updatedInput) => ({
|
|
|
1068
1127
|
...updatedInput ? { updatedInput } : {}
|
|
1069
1128
|
}
|
|
1070
1129
|
});
|
|
1130
|
+
var PENDING_COMMAND_PREFIX = "The user sent a new instruction from their phone via Pushary:";
|
|
1131
|
+
var pendingCommandEvents = (source) => {
|
|
1132
|
+
switch (source) {
|
|
1133
|
+
case "claude":
|
|
1134
|
+
return ["PostToolUse", "UserPromptSubmit", "Stop"];
|
|
1135
|
+
// Codex carries context on its activity events and NOT on Stop, whose output
|
|
1136
|
+
// schema has no context field at all. Draining for it at the turn boundary
|
|
1137
|
+
// was therefore right to render nothing, and wrong to conclude that Codex
|
|
1138
|
+
// could not be sent a message.
|
|
1139
|
+
case "codex":
|
|
1140
|
+
return ["PostToolUse", "PreToolUse", "UserPromptSubmit"];
|
|
1141
|
+
case "gemini":
|
|
1142
|
+
return ["AfterTool", "BeforeTool", "BeforeAgent"];
|
|
1143
|
+
// Registered events only. Cursor's carriers are `postToolUse` and `stop`,
|
|
1144
|
+
// which this build does not write into the config; the ones it does write
|
|
1145
|
+
// (`afterShellExecution`, `afterFileEdit`, `afterAgentResponse`) are
|
|
1146
|
+
// observational and discard whatever they print.
|
|
1147
|
+
case "cursor":
|
|
1148
|
+
return [];
|
|
1149
|
+
case "vscode":
|
|
1150
|
+
return [];
|
|
1151
|
+
// The prompt is appended through the TUI rather than through a hook return,
|
|
1152
|
+
// so there is nothing for this to print.
|
|
1153
|
+
case "opencode":
|
|
1154
|
+
return [];
|
|
1155
|
+
}
|
|
1156
|
+
};
|
|
1071
1157
|
var claudePermissionRequestOutput = (decision, reason, updatedInput) => ({
|
|
1072
1158
|
hookSpecificOutput: {
|
|
1073
1159
|
hookEventName: "PermissionRequest",
|
|
@@ -1103,7 +1189,7 @@ var gateOutputFor = (source, event, decision, reason) => {
|
|
|
1103
1189
|
output = decision === "allow" ? { decision: "allow" } : { decision: "deny", reason: reason ?? "Denied from Pushary" };
|
|
1104
1190
|
} else if (source === "opencode" && event === OPENCODE_APPROVAL_EVENT) {
|
|
1105
1191
|
output = decision === "deny" ? { status: "deny", reason: reason ?? "Denied from Pushary" } : { status: decision };
|
|
1106
|
-
} else if (source === "cursor" && event
|
|
1192
|
+
} else if (source === "cursor" && CURSOR_GATE_EVENTS.includes(event)) {
|
|
1107
1193
|
output = decision === "allow" ? { permission: "allow" } : decision === "ask" ? { permission: "ask" } : {
|
|
1108
1194
|
permission: "deny",
|
|
1109
1195
|
user_message: "Command denied via Pushary.",
|
|
@@ -1123,16 +1209,131 @@ var claudeElicitationOutput = (event, action, content) => ({
|
|
|
1123
1209
|
}
|
|
1124
1210
|
});
|
|
1125
1211
|
var renderElicitationOutput = (event, action, content) => ELICITATION_EVENTS.includes(event) ? JSON.stringify(claudeElicitationOutput(event, action, content)) : void 0;
|
|
1212
|
+
var ELICITATION_ANSWERABLE_MODE = "form";
|
|
1213
|
+
var ELICITATION_MIN_OPTIONS = 2;
|
|
1214
|
+
var ELICITATION_MAX_MULTI_QUESTIONS = 4;
|
|
1215
|
+
var ELICITATION_MAX_MULTI_OPTIONS = 4;
|
|
1216
|
+
var elicitationRecord = (value) => value !== null && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
1217
|
+
var elicitationLabel = (name, property) => typeof property.title === "string" && property.title.trim() ? property.title.trim() : name;
|
|
1218
|
+
var elicitationEnum = (property) => {
|
|
1219
|
+
if (!Array.isArray(property.enum)) return null;
|
|
1220
|
+
const members = property.enum.filter((member) => typeof member === "string");
|
|
1221
|
+
return members.length === property.enum.length && members.length >= ELICITATION_MIN_OPTIONS ? members : null;
|
|
1222
|
+
};
|
|
1223
|
+
var readElicitationFields = (schema) => {
|
|
1224
|
+
const record = elicitationRecord(schema);
|
|
1225
|
+
const properties = elicitationRecord(record?.properties);
|
|
1226
|
+
if (!properties) return null;
|
|
1227
|
+
const entries = Object.entries(properties);
|
|
1228
|
+
if (entries.length === 0) return null;
|
|
1229
|
+
const fields = [];
|
|
1230
|
+
for (const [name, raw] of entries) {
|
|
1231
|
+
const property = elicitationRecord(raw);
|
|
1232
|
+
if (!property) return null;
|
|
1233
|
+
const label = elicitationLabel(name, property);
|
|
1234
|
+
if ("enum" in property) {
|
|
1235
|
+
const options = elicitationEnum(property);
|
|
1236
|
+
if (!options) return null;
|
|
1237
|
+
fields.push({ kind: "choice", name, label, options });
|
|
1238
|
+
continue;
|
|
1239
|
+
}
|
|
1240
|
+
switch (property.type) {
|
|
1241
|
+
case "string":
|
|
1242
|
+
fields.push({ kind: "text", name, label });
|
|
1243
|
+
break;
|
|
1244
|
+
case "number":
|
|
1245
|
+
fields.push({ kind: "number", name, label, integer: false });
|
|
1246
|
+
break;
|
|
1247
|
+
case "integer":
|
|
1248
|
+
fields.push({ kind: "number", name, label, integer: true });
|
|
1249
|
+
break;
|
|
1250
|
+
case "boolean":
|
|
1251
|
+
fields.push({ kind: "boolean", name, label });
|
|
1252
|
+
break;
|
|
1253
|
+
default:
|
|
1254
|
+
return null;
|
|
1255
|
+
}
|
|
1256
|
+
}
|
|
1257
|
+
return fields;
|
|
1258
|
+
};
|
|
1259
|
+
var elicitationQuestionText = (message, field, alone) => alone ? message : `${message} \u2014 ${field.label}`;
|
|
1260
|
+
var planElicitationAsk = (message, fields) => {
|
|
1261
|
+
if (fields.length === 1) {
|
|
1262
|
+
const field = fields[0];
|
|
1263
|
+
const question = elicitationQuestionText(message, field, true);
|
|
1264
|
+
switch (field.kind) {
|
|
1265
|
+
case "choice":
|
|
1266
|
+
return { kind: "select", field, question, options: field.options };
|
|
1267
|
+
case "boolean":
|
|
1268
|
+
return { kind: "confirm", field, question };
|
|
1269
|
+
case "text":
|
|
1270
|
+
case "number":
|
|
1271
|
+
return { kind: "input", field, question };
|
|
1272
|
+
}
|
|
1273
|
+
}
|
|
1274
|
+
if (fields.length > ELICITATION_MAX_MULTI_QUESTIONS) return null;
|
|
1275
|
+
if (!fields.every((field) => field.kind === "choice" && field.options.length <= ELICITATION_MAX_MULTI_OPTIONS)) return null;
|
|
1276
|
+
const questions = fields.map((field) => ({
|
|
1277
|
+
question: elicitationQuestionText(message, field, false),
|
|
1278
|
+
header: field.label.slice(0, 12),
|
|
1279
|
+
multiSelect: false,
|
|
1280
|
+
options: field.options.map((label) => ({ label }))
|
|
1281
|
+
}));
|
|
1282
|
+
return new Set(questions.map((question) => question.question)).size === questions.length ? { kind: "questions", fields, questions } : null;
|
|
1283
|
+
};
|
|
1284
|
+
var ELICITATION_CONFIRMED = /* @__PURE__ */ new Set(["yes", "true", "approve", "approved", "allow"]);
|
|
1285
|
+
var ELICITATION_REFUSED = /* @__PURE__ */ new Set(["no", "false", "deny", "denied", "reject"]);
|
|
1286
|
+
var elicitationNumber = (raw, integer) => {
|
|
1287
|
+
const trimmed = raw.trim();
|
|
1288
|
+
if (!/^-?\d+(\.\d+)?$/.test(trimmed)) return null;
|
|
1289
|
+
const value = Number(trimmed);
|
|
1290
|
+
if (!Number.isFinite(value)) return null;
|
|
1291
|
+
return integer && !Number.isInteger(value) ? null : value;
|
|
1292
|
+
};
|
|
1293
|
+
var elicitationContent = (ask, answer) => {
|
|
1294
|
+
const value = answer.trim();
|
|
1295
|
+
if (!value) return null;
|
|
1296
|
+
if (ask.kind === "input") {
|
|
1297
|
+
if (ask.field.kind === "number") {
|
|
1298
|
+
const parsed = elicitationNumber(value, ask.field.integer);
|
|
1299
|
+
return parsed === null ? null : { [ask.field.name]: parsed };
|
|
1300
|
+
}
|
|
1301
|
+
return { [ask.field.name]: value };
|
|
1302
|
+
}
|
|
1303
|
+
if (ask.kind === "confirm") {
|
|
1304
|
+
const lowered = value.toLowerCase();
|
|
1305
|
+
if (ELICITATION_CONFIRMED.has(lowered)) return { [ask.field.name]: true };
|
|
1306
|
+
if (ELICITATION_REFUSED.has(lowered)) return { [ask.field.name]: false };
|
|
1307
|
+
return null;
|
|
1308
|
+
}
|
|
1309
|
+
if (ask.kind === "select") {
|
|
1310
|
+
return ask.options.includes(value) ? { [ask.field.name]: value } : null;
|
|
1311
|
+
}
|
|
1312
|
+
return null;
|
|
1313
|
+
};
|
|
1314
|
+
var elicitationContentFromAnswers = (ask, answers) => {
|
|
1315
|
+
const content = {};
|
|
1316
|
+
for (const [index, field] of ask.fields.entries()) {
|
|
1317
|
+
if (field.kind !== "choice") return null;
|
|
1318
|
+
const chosen = answers[ask.questions[index].question];
|
|
1319
|
+
if (typeof chosen !== "string" || !field.options.includes(chosen)) return null;
|
|
1320
|
+
content[field.name] = chosen;
|
|
1321
|
+
}
|
|
1322
|
+
return content;
|
|
1323
|
+
};
|
|
1126
1324
|
|
|
1127
1325
|
export {
|
|
1326
|
+
parseAgentQuestions,
|
|
1128
1327
|
parseAgentQuestionAnswers,
|
|
1129
1328
|
normalizeInstallSource,
|
|
1130
1329
|
HOOK_BUDGETS,
|
|
1131
1330
|
hookWaitDeadline,
|
|
1132
1331
|
hookWaitClamped,
|
|
1133
1332
|
effectiveWaitSeconds,
|
|
1333
|
+
HOOK_SOURCES,
|
|
1134
1334
|
AGENT_LABELS_BY_TYPE,
|
|
1135
1335
|
OPENCODE_APPROVAL_EVENT,
|
|
1336
|
+
CURSOR_GATE_EVENTS,
|
|
1136
1337
|
HOOK_LOCATOR_BINARY,
|
|
1137
1338
|
normalizeRepoRemote,
|
|
1138
1339
|
localRepoKey,
|
|
@@ -1148,10 +1349,18 @@ export {
|
|
|
1148
1349
|
resolveAutoResolveOrigin,
|
|
1149
1350
|
resolvePolicy,
|
|
1150
1351
|
KILL_REASON,
|
|
1352
|
+
shouldDeferToNativeMode,
|
|
1151
1353
|
resolveGate,
|
|
1152
1354
|
modeStateFromResponse,
|
|
1153
1355
|
claudePreToolUseOutput,
|
|
1356
|
+
PENDING_COMMAND_PREFIX,
|
|
1357
|
+
pendingCommandEvents,
|
|
1154
1358
|
claudePermissionRequestOutput,
|
|
1155
1359
|
gateOutputFor,
|
|
1156
|
-
renderElicitationOutput
|
|
1360
|
+
renderElicitationOutput,
|
|
1361
|
+
ELICITATION_ANSWERABLE_MODE,
|
|
1362
|
+
readElicitationFields,
|
|
1363
|
+
planElicitationAsk,
|
|
1364
|
+
elicitationContent,
|
|
1365
|
+
elicitationContentFromAnswers
|
|
1157
1366
|
};
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
2
|
hasGeminiHooks
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-F3ZDPL6O.js";
|
|
4
4
|
import {
|
|
5
5
|
hasCodexHooks
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-FRH2QIMY.js";
|
|
7
7
|
|
|
8
8
|
// src/diagnostics/wiring.ts
|
|
9
9
|
var record = (value) => value && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
import {
|
|
6
6
|
isGatingMoment,
|
|
7
7
|
recordKeylessMoment
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-PXEFENML.js";
|
|
9
9
|
import {
|
|
10
10
|
denyReasonFrom,
|
|
11
11
|
isDeferAnswer
|
|
@@ -17,7 +17,7 @@ import {
|
|
|
17
17
|
readLastUserPrompt,
|
|
18
18
|
repoKeyFor,
|
|
19
19
|
throttlePass
|
|
20
|
-
} from "./chunk-
|
|
20
|
+
} from "./chunk-OSE7X44J.js";
|
|
21
21
|
import {
|
|
22
22
|
DEFAULT_SESSION,
|
|
23
23
|
askUser,
|
|
@@ -33,7 +33,7 @@ import {
|
|
|
33
33
|
deriveToolTarget,
|
|
34
34
|
describeToolCall,
|
|
35
35
|
scopePathFor
|
|
36
|
-
} from "./chunk-
|
|
36
|
+
} from "./chunk-LXTX5CT7.js";
|
|
37
37
|
import {
|
|
38
38
|
getMachineId
|
|
39
39
|
} from "./chunk-RN3NOEJF.js";
|
|
@@ -49,8 +49,10 @@ import {
|
|
|
49
49
|
hookWaitClamped,
|
|
50
50
|
hookWaitDeadline,
|
|
51
51
|
parseAgentQuestionAnswers,
|
|
52
|
-
|
|
53
|
-
|
|
52
|
+
parseAgentQuestions,
|
|
53
|
+
resolveGate,
|
|
54
|
+
shouldDeferToNativeMode
|
|
55
|
+
} from "./chunk-Q6MK2YKV.js";
|
|
54
56
|
|
|
55
57
|
// src/decision-episode.ts
|
|
56
58
|
var EPISODE_PATH = "/api/agent/decision-episode";
|
|
@@ -107,10 +109,10 @@ var handlePushOnly = async (apiKey, description, projectName, timeoutSeconds, ti
|
|
|
107
109
|
return void 0;
|
|
108
110
|
}
|
|
109
111
|
}
|
|
110
|
-
if (result.suppressed) {
|
|
112
|
+
if (result.suppressed || result.status === "terminal") {
|
|
111
113
|
await cancelQuestion(apiKey, result.correlationId).catch(() => {
|
|
112
114
|
});
|
|
113
|
-
return ask("You are at the keyboard, approve here.");
|
|
115
|
+
return ask(result.suppressed ? "You are at the keyboard, approve here." : "Delivery mode is Terminal, approve here.");
|
|
114
116
|
}
|
|
115
117
|
if (result.noDevices) {
|
|
116
118
|
switch (timeoutAction) {
|
|
@@ -300,58 +302,21 @@ var keylessNoticeOnce = (sessionId) => {
|
|
|
300
302
|
} catch {
|
|
301
303
|
}
|
|
302
304
|
};
|
|
303
|
-
var
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
const flag = process.env.PUSHARY_RESPECT_PERMISSION_MODE;
|
|
307
|
-
return flag === "0" || flag === "false";
|
|
308
|
-
};
|
|
309
|
-
var shouldDeferToNativeMode = (permissionMode, toolName) => {
|
|
310
|
-
if (nativeModeGatingDisabled()) return false;
|
|
311
|
-
if (typeof permissionMode !== "string") return false;
|
|
312
|
-
if (FULL_DEFER_MODES.has(permissionMode)) return true;
|
|
313
|
-
if (permissionMode === "acceptEdits" && ACCEPT_EDITS_DEFER_TOOLS.has(toolName)) return true;
|
|
314
|
-
if (permissionMode === "bypassPermissions") {
|
|
315
|
-
const flag = process.env.PUSHARY_DEFER_BYPASS;
|
|
316
|
-
return flag === "1" || flag === "true";
|
|
317
|
-
}
|
|
318
|
-
return false;
|
|
319
|
-
};
|
|
320
|
-
var MAX_PHONE_QUESTIONS = 4;
|
|
321
|
-
var parseQuestion = (raw) => {
|
|
322
|
-
const q = raw;
|
|
323
|
-
if (!q || typeof q.question !== "string") return void 0;
|
|
324
|
-
const options = Array.isArray(q.options) ? q.options.flatMap((option) => {
|
|
325
|
-
if (!option || typeof option !== "object") return [];
|
|
326
|
-
const value = option;
|
|
327
|
-
if (typeof value.label !== "string" || value.label.length === 0) return [];
|
|
328
|
-
return [{
|
|
329
|
-
label: value.label,
|
|
330
|
-
...typeof value.description === "string" ? { description: value.description } : {}
|
|
331
|
-
}];
|
|
332
|
-
}) : [];
|
|
333
|
-
const labels = options.map((option) => option.label);
|
|
334
|
-
if (labels.length < 2) return void 0;
|
|
305
|
+
var nativeDeferOptions = () => {
|
|
306
|
+
const respect = process.env.PUSHARY_RESPECT_PERMISSION_MODE;
|
|
307
|
+
const bypass = process.env.PUSHARY_DEFER_BYPASS;
|
|
335
308
|
return {
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
multiSelect: q.multiSelect === true,
|
|
339
|
-
options,
|
|
340
|
-
labels
|
|
309
|
+
respectPermissionMode: !(respect === "0" || respect === "false"),
|
|
310
|
+
deferBypass: bypass === "1" || bypass === "true"
|
|
341
311
|
};
|
|
342
312
|
};
|
|
343
|
-
var
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
if (!one || parsed.some((question) => question.question === one.question)) return void 0;
|
|
351
|
-
parsed.push(one);
|
|
352
|
-
}
|
|
353
|
-
return parsed;
|
|
354
|
-
};
|
|
313
|
+
var shouldDeferToNativeMode2 = (permissionMode, toolName) => shouldDeferToNativeMode(permissionMode, toolName, nativeDeferOptions());
|
|
314
|
+
var handedToTerminal = (result) => result.suppressed === true || result.noDevices === true || result.status === "terminal";
|
|
315
|
+
var withLabels = (question) => ({
|
|
316
|
+
...question,
|
|
317
|
+
labels: question.options.map((option) => option.label)
|
|
318
|
+
});
|
|
319
|
+
var parseQuestions = (toolInput) => parseAgentQuestions(toolInput)?.map(withLabels);
|
|
355
320
|
var questionContext = (question, index, total, project) => {
|
|
356
321
|
const subject = question.header ? `${question.header}: your agent is asking in ${project}` : `Your agent is asking in ${project}`;
|
|
357
322
|
return total > 1 ? `${subject} (${index + 1} of ${total})` : subject;
|
|
@@ -376,7 +341,7 @@ var askAsOneCard = async (apiKey, input, parsed, projectName, deadline) => {
|
|
|
376
341
|
} catch {
|
|
377
342
|
return void 0;
|
|
378
343
|
}
|
|
379
|
-
if (result
|
|
344
|
+
if (handedToTerminal(result)) {
|
|
380
345
|
await cancelQuestion(apiKey, result.correlationId).catch(() => {
|
|
381
346
|
});
|
|
382
347
|
return void 0;
|
|
@@ -411,7 +376,7 @@ var askQuestionByQuestion = async (apiKey, input, parsed, projectName, deadline)
|
|
|
411
376
|
} catch {
|
|
412
377
|
return void 0;
|
|
413
378
|
}
|
|
414
|
-
if (result
|
|
379
|
+
if (handedToTerminal(result)) {
|
|
415
380
|
await cancelQuestion(apiKey, result.correlationId).catch(() => {
|
|
416
381
|
});
|
|
417
382
|
return void 0;
|
|
@@ -461,7 +426,7 @@ var handleExitPlanMode = async (apiKey, input) => {
|
|
|
461
426
|
} catch {
|
|
462
427
|
return void 0;
|
|
463
428
|
}
|
|
464
|
-
if (result
|
|
429
|
+
if (handedToTerminal(result)) {
|
|
465
430
|
await cancelQuestion(apiKey, result.correlationId).catch(() => {
|
|
466
431
|
});
|
|
467
432
|
return void 0;
|
|
@@ -524,7 +489,7 @@ var handlePreToolUse = async (input) => {
|
|
|
524
489
|
if (input.tool_name === "ExitPlanMode") {
|
|
525
490
|
return handleExitPlanMode(apiKey, input);
|
|
526
491
|
}
|
|
527
|
-
if (
|
|
492
|
+
if (shouldDeferToNativeMode2(input.permission_mode, input.tool_name)) {
|
|
528
493
|
return void 0;
|
|
529
494
|
}
|
|
530
495
|
switch (verdict.kind) {
|
|
@@ -555,7 +520,7 @@ var toPermissionRequestOutput = (hookOutput) => {
|
|
|
555
520
|
};
|
|
556
521
|
var handlePermissionRequest = async (input) => {
|
|
557
522
|
if (PRETOOLUSE_HANDLED_TOOLS.has(input.tool_name)) {
|
|
558
|
-
const reclaimDeferredExec = !PRETOOLUSE_PHONE_ANSWERED_TOOLS.includes(input.tool_name) &&
|
|
523
|
+
const reclaimDeferredExec = !PRETOOLUSE_PHONE_ANSWERED_TOOLS.includes(input.tool_name) && shouldDeferToNativeMode2(input.permission_mode, input.tool_name);
|
|
559
524
|
if (!reclaimDeferredExec) return void 0;
|
|
560
525
|
}
|
|
561
526
|
if (input.tool_name.startsWith("mcp__pushary__")) return void 0;
|
|
@@ -636,7 +601,7 @@ var handlePermissionDenied = async (input) => {
|
|
|
636
601
|
} catch {
|
|
637
602
|
return void 0;
|
|
638
603
|
}
|
|
639
|
-
if (result
|
|
604
|
+
if (handedToTerminal(result)) {
|
|
640
605
|
await cancelQuestion(apiKey, result.correlationId).catch(() => {
|
|
641
606
|
});
|
|
642
607
|
return void 0;
|
package/dist/src/index.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import {
|
|
2
2
|
handlePreToolUse
|
|
3
|
-
} from "../chunk-
|
|
3
|
+
} from "../chunk-U65EIMUJ.js";
|
|
4
4
|
import "../chunk-ATBKJNWS.js";
|
|
5
|
-
import "../chunk-
|
|
5
|
+
import "../chunk-PXEFENML.js";
|
|
6
6
|
import "../chunk-YHG74UFF.js";
|
|
7
7
|
import {
|
|
8
8
|
fetchModeOverride,
|
|
@@ -12,17 +12,17 @@ import {
|
|
|
12
12
|
handlePostToolUse,
|
|
13
13
|
handleStop,
|
|
14
14
|
reportEvent
|
|
15
|
-
} from "../chunk-
|
|
15
|
+
} from "../chunk-OSE7X44J.js";
|
|
16
16
|
import {
|
|
17
17
|
askUser,
|
|
18
18
|
cancelQuestion,
|
|
19
19
|
waitForAnswer
|
|
20
20
|
} from "../chunk-J3YDT4HM.js";
|
|
21
|
-
import "../chunk-
|
|
21
|
+
import "../chunk-LXTX5CT7.js";
|
|
22
22
|
import "../chunk-RN3NOEJF.js";
|
|
23
23
|
import "../chunk-BSZYIAZL.js";
|
|
24
24
|
import "../chunk-SAF6HGAA.js";
|
|
25
|
-
import "../chunk-
|
|
25
|
+
import "../chunk-AJ4EMW5D.js";
|
|
26
26
|
import "../chunk-7QLSKOSU.js";
|
|
27
27
|
import "../chunk-KZERVKTD.js";
|
|
28
28
|
import {
|
|
@@ -31,7 +31,7 @@ import {
|
|
|
31
31
|
} from "../chunk-2UMNXADU.js";
|
|
32
32
|
import {
|
|
33
33
|
resolvePolicy
|
|
34
|
-
} from "../chunk-
|
|
34
|
+
} from "../chunk-Q6MK2YKV.js";
|
|
35
35
|
export {
|
|
36
36
|
askUser,
|
|
37
37
|
cancelQuestion,
|