@pushary/agent-hooks 0.87.2 → 0.87.3
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/data/cursor-plugin/hooks/hooks.json +7 -0
- package/data/cursor-plugin/scripts/pushary-gate.mjs +85 -28
- package/data/cursor-plugin/scripts/pushary-gate.test.mjs +42 -1
- package/dist/bin/pushary-bell-hook.js +4 -4
- package/dist/bin/pushary-bell.js +7 -6
- package/dist/bin/pushary-claude.js +14 -11
- package/dist/bin/pushary-clean.js +36 -20
- package/dist/bin/pushary-codex-bridge.js +6 -5
- package/dist/bin/pushary-codex-hook.js +129 -52
- package/dist/bin/pushary-codex.js +4 -3
- package/dist/bin/pushary-connect.js +6 -6
- package/dist/bin/pushary-daemon.js +5 -4
- package/dist/bin/pushary-disconnect.js +65 -8
- package/dist/bin/pushary-doctor.js +79 -18
- package/dist/bin/pushary-elicitation-hook.js +1 -1
- package/dist/bin/pushary-gemini-bridge.js +6 -5
- package/dist/bin/pushary-gemini-hook.js +12 -10
- package/dist/bin/pushary-hook.js +6 -5
- package/dist/bin/pushary-login.js +4 -4
- package/dist/bin/pushary-logout.js +5 -4
- package/dist/bin/pushary-mode.js +3 -3
- package/dist/bin/pushary-notification-hook.js +4 -3
- package/dist/bin/pushary-opencode-hook.d.ts +1 -0
- package/dist/bin/pushary-opencode-hook.js +329 -0
- package/dist/bin/pushary-permission-denied-hook.js +6 -5
- package/dist/bin/pushary-permission-hook.js +6 -5
- package/dist/bin/pushary-post-hook.js +4 -3
- package/dist/bin/pushary-prompt-hook.js +4 -3
- package/dist/bin/pushary-session-end-hook.js +4 -3
- package/dist/bin/pushary-session-start-hook.js +4 -3
- package/dist/bin/pushary-setup.js +238 -84
- package/dist/bin/pushary-stats.js +2 -2
- package/dist/bin/pushary-status.js +5 -5
- package/dist/bin/pushary-stop-hook.js +4 -3
- package/dist/bin/pushary-stopfailure-hook.js +4 -3
- package/dist/bin/pushary-upgrade.js +7 -6
- package/dist/bin/pushary-wait.js +3 -3
- package/dist/{chunk-5646VKR4.js → chunk-2JYQAW4B.js} +5 -53
- package/dist/chunk-7J67NYK4.js +287 -0
- package/dist/{chunk-M7RYIZX6.js → chunk-B7ZBHWOW.js} +10 -1
- package/dist/{chunk-7YJS2VTG.js → chunk-DMW54VWK.js} +12 -1
- package/dist/{chunk-LT2VLPUK.js → chunk-DPUOW6NS.js} +18 -2
- package/dist/{chunk-3LKYBFWA.js → chunk-EJL3PJU7.js} +1 -1
- package/dist/chunk-GIRT7677.js +11 -0
- package/dist/{chunk-HAUTLCMA.js → chunk-ICERLAE2.js} +1 -1
- package/dist/{chunk-ZZE6FN7T.js → chunk-K42RXJPG.js} +52 -1
- package/dist/{chunk-Y3UTTFTZ.js → chunk-KBS53WOE.js} +1 -1
- package/dist/{chunk-SJVLFIYP.js → chunk-KCAFCGGY.js} +1 -1
- package/dist/{chunk-A4I5JGCW.js → chunk-KFAH6KRE.js} +1 -1
- package/dist/{chunk-QBWYNVKY.js → chunk-LGVHYFIB.js} +1 -1
- package/dist/{chunk-HJ44HIUW.js → chunk-OMA2OZRE.js} +11 -9
- package/dist/{chunk-ECEUMWBH.js → chunk-QLMX5LLV.js} +1 -1
- package/dist/{chunk-XW5CHAQX.js → chunk-TAYHEJFF.js} +2 -2
- package/dist/{chunk-JAICP7BA.js → chunk-TD3M232T.js} +1 -1
- package/dist/{chunk-WLLBFDVY.js → chunk-TV3UFGT7.js} +1 -1
- package/dist/{chunk-7MBDFNUC.js → chunk-VIHRP25S.js} +1 -1
- package/dist/{chunk-B3V2H6SA.js → chunk-VL5ZNK6V.js} +43 -12
- package/dist/{chunk-V2XPF77V.js → chunk-VOE4SYPR.js} +42 -279
- package/dist/{chunk-OT4YD54Q.js → chunk-YX6ZKCC5.js} +1 -1
- package/dist/{chunk-2T3GX7WG.js → chunk-YYTLTEGU.js} +1 -1
- package/dist/chunk-ZGC3W23N.js +371 -0
- package/dist/src/index.js +6 -5
- package/package.json +2 -1
|
@@ -9,6 +9,19 @@ import {
|
|
|
9
9
|
sendNotification,
|
|
10
10
|
waitForAnswer
|
|
11
11
|
} from "./chunk-J3YDT4HM.js";
|
|
12
|
+
import {
|
|
13
|
+
deriveReceiptMeta,
|
|
14
|
+
deriveToolTarget,
|
|
15
|
+
describeToolCall,
|
|
16
|
+
isToolResultError,
|
|
17
|
+
parseApplyPatchFiles,
|
|
18
|
+
parseApplyPatchOps,
|
|
19
|
+
sessionEndAction,
|
|
20
|
+
sessionStartAction,
|
|
21
|
+
summarizeStop,
|
|
22
|
+
taskTitleFrom,
|
|
23
|
+
toolResultErrorText
|
|
24
|
+
} from "./chunk-7J67NYK4.js";
|
|
12
25
|
import {
|
|
13
26
|
getMachineId
|
|
14
27
|
} from "./chunk-RN3NOEJF.js";
|
|
@@ -17,26 +30,20 @@ import {
|
|
|
17
30
|
} from "./chunk-BSZYIAZL.js";
|
|
18
31
|
import {
|
|
19
32
|
reportedInstallSource
|
|
20
|
-
} from "./chunk-
|
|
33
|
+
} from "./chunk-KBS53WOE.js";
|
|
21
34
|
import {
|
|
22
35
|
getApiKey,
|
|
23
36
|
getBaseUrl
|
|
24
37
|
} from "./chunk-2UMNXADU.js";
|
|
25
38
|
import {
|
|
26
|
-
ACTION_BODY_MAX,
|
|
27
|
-
AGENT_LABELS_BY_TYPE,
|
|
28
|
-
DECISION_LINE_MAX,
|
|
29
|
-
FILE_TARGET_TOOLS,
|
|
30
39
|
gateOutputFor,
|
|
31
40
|
isAutoApprove,
|
|
32
41
|
localRepoKey,
|
|
33
42
|
modeStateFromResponse,
|
|
34
43
|
normalizeRepoRemote,
|
|
35
|
-
redactSecrets,
|
|
36
|
-
redactSecretsDeep,
|
|
37
44
|
resolveAutoResolveOrigin,
|
|
38
45
|
resolvePolicy
|
|
39
|
-
} from "./chunk-
|
|
46
|
+
} from "./chunk-DMW54VWK.js";
|
|
40
47
|
|
|
41
48
|
// src/policy.ts
|
|
42
49
|
import { createHash } from "crypto";
|
|
@@ -45,9 +52,10 @@ import { join } from "path";
|
|
|
45
52
|
import { tmpdir } from "os";
|
|
46
53
|
var CACHE_TTL_MS = 60 * 1e3;
|
|
47
54
|
var STALE_CACHE_MAX_MS = 12 * 60 * 60 * 1e3;
|
|
55
|
+
var REPO_AWARE_AGENTS = ["claude_code", "codex", "gemini_cli", "opencode"];
|
|
48
56
|
var policyRequestFor = (agentType) => ({
|
|
49
57
|
agent: agentType,
|
|
50
|
-
repoAware:
|
|
58
|
+
repoAware: REPO_AWARE_AGENTS.includes(agentType)
|
|
51
59
|
});
|
|
52
60
|
var policyCacheFile = (apiKey, agent, repoAware = false) => {
|
|
53
61
|
const parts = [apiKey, agent, repoAware ? "repoAware" : void 0].filter(Boolean);
|
|
@@ -178,254 +186,13 @@ var fetchModeState = async (apiKey, sessionId, reuseWithinMs = 0) => {
|
|
|
178
186
|
};
|
|
179
187
|
var fetchModeOverride = async (apiKey) => (await fetchModeState(apiKey)).mode;
|
|
180
188
|
|
|
181
|
-
// ../hook-mapping/src/describe.ts
|
|
182
|
-
import { isAbsolute, relative, resolve } from "path";
|
|
183
|
-
var hookPrefixes = {
|
|
184
|
-
Bash: (input) => `bash: ${input.command ?? "(no command)"}`,
|
|
185
|
-
PowerShell: (input) => `powershell: ${input.command ?? "(no command)"}`,
|
|
186
|
-
Monitor: (input) => `monitor: ${input.command ?? "(no command)"}`,
|
|
187
|
-
Write: (input) => `write file: ${input.file_path ?? "(unknown path)"}`,
|
|
188
|
-
Edit: (input) => `edit file: ${input.file_path ?? "(unknown path)"}`,
|
|
189
|
-
MultiEdit: (input) => `edit file: ${input.file_path ?? "(unknown path)"}`,
|
|
190
|
-
Read: (input) => `read file: ${input.file_path ?? "(unknown path)"}`,
|
|
191
|
-
// Without an entry here the fallback stringifies the whole tool input, and for
|
|
192
|
-
// ExitPlanMode that input IS the plan: the action line became a truncated dump of
|
|
193
|
-
// the plan markdown. The plan belongs in the body, not the one-line summary.
|
|
194
|
-
ExitPlanMode: () => "finished planning and wants to start coding"
|
|
195
|
-
};
|
|
196
|
-
var describeTodoProgress = (todos) => {
|
|
197
|
-
if (!Array.isArray(todos)) return "updated the plan";
|
|
198
|
-
const items = todos.filter((t) => !!t && typeof t === "object");
|
|
199
|
-
const total = items.length;
|
|
200
|
-
if (total === 0) return "updated the plan";
|
|
201
|
-
const done = items.filter((t) => t.status === "completed").length;
|
|
202
|
-
const current = items.find((t) => t.status === "in_progress");
|
|
203
|
-
const label = current ? [current.activeForm, current.content].find((v) => typeof v === "string" && v.trim().length > 0) : void 0;
|
|
204
|
-
if (done >= total) return `finished all ${total} tasks`;
|
|
205
|
-
if (label) return `${label.trim()} (${done}/${total} done)`;
|
|
206
|
-
return `${done}/${total} tasks done`;
|
|
207
|
-
};
|
|
208
|
-
var eventPrefixes = {
|
|
209
|
-
Bash: (input) => `ran: ${String(input.command ?? "")}`,
|
|
210
|
-
PowerShell: (input) => `ran: ${String(input.command ?? "")}`,
|
|
211
|
-
Monitor: (input) => `ran: ${String(input.command ?? "")}`,
|
|
212
|
-
Write: (input) => `wrote: ${input.file_path ?? "unknown"}`,
|
|
213
|
-
Edit: (input) => `edited: ${input.file_path ?? "unknown"}`,
|
|
214
|
-
MultiEdit: (input) => `edited: ${input.file_path ?? "unknown"}`,
|
|
215
|
-
Read: (input) => `read: ${input.file_path ?? "unknown"}`,
|
|
216
|
-
TodoWrite: (input) => describeTodoProgress(input.todos)
|
|
217
|
-
};
|
|
218
|
-
var EVENT_ACTION_MAX = 120;
|
|
219
|
-
var HOOK_FALLBACK_MAX = 200;
|
|
220
|
-
var describeToolCall = (toolName, toolInput, format = "hook") => {
|
|
221
|
-
const prefixes = format === "hook" ? hookPrefixes : eventPrefixes;
|
|
222
|
-
const builder = prefixes[toolName];
|
|
223
|
-
const raw = builder ? builder(toolInput) : format === "hook" ? `${toolName}: ${JSON.stringify(toolInput)}` : `${toolName}: done`;
|
|
224
|
-
const redacted = redactSecrets(raw);
|
|
225
|
-
if (format === "event") return redacted.slice(0, EVENT_ACTION_MAX);
|
|
226
|
-
return builder ? redacted : redacted.slice(0, HOOK_FALLBACK_MAX);
|
|
227
|
-
};
|
|
228
|
-
var TOOL_TARGET_MAX_LENGTH = 80;
|
|
229
|
-
var deriveCommandHead = (command) => {
|
|
230
|
-
if (typeof command !== "string") return void 0;
|
|
231
|
-
const head = command.trim().split(/\s+/).slice(0, 2).join(" ");
|
|
232
|
-
return head ? redactSecrets(head).slice(0, TOOL_TARGET_MAX_LENGTH) : void 0;
|
|
233
|
-
};
|
|
234
|
-
var deriveToolTarget = (toolName, toolInput) => {
|
|
235
|
-
if (toolName === "Bash" || toolName === "PowerShell" || toolName === "Monitor") {
|
|
236
|
-
return deriveCommandHead(toolInput.command);
|
|
237
|
-
}
|
|
238
|
-
if (FILE_TARGET_TOOLS.has(toolName)) {
|
|
239
|
-
const filePath = toolInput.file_path;
|
|
240
|
-
if (typeof filePath !== "string") return void 0;
|
|
241
|
-
const separator = Math.max(filePath.lastIndexOf("/"), filePath.lastIndexOf("\\"));
|
|
242
|
-
const base = filePath.slice(separator + 1);
|
|
243
|
-
const dot = base.lastIndexOf(".");
|
|
244
|
-
if (dot <= 0) return void 0;
|
|
245
|
-
return base.slice(dot).slice(0, TOOL_TARGET_MAX_LENGTH);
|
|
246
|
-
}
|
|
247
|
-
return void 0;
|
|
248
|
-
};
|
|
249
|
-
var SCRIPT_RUNNERS = /* @__PURE__ */ new Set(["npm", "pnpm", "yarn", "bun", "npx", "deno", "rake", "make", "just", "task", "turbo"]);
|
|
250
|
-
var RUN_SUBCOMMANDS = /* @__PURE__ */ new Set(["run", "run-script", "exec", "task"]);
|
|
251
|
-
var deriveReceiptCommandHead = (command) => {
|
|
252
|
-
if (typeof command !== "string") return void 0;
|
|
253
|
-
const tokens = command.trim().split(/\s+/);
|
|
254
|
-
const [first, second] = tokens;
|
|
255
|
-
const keep = first && second && SCRIPT_RUNNERS.has(first.toLowerCase()) && RUN_SUBCOMMANDS.has(second.toLowerCase()) ? 3 : 2;
|
|
256
|
-
const head = tokens.slice(0, keep).join(" ");
|
|
257
|
-
return head ? redactSecrets(head).slice(0, TOOL_TARGET_MAX_LENGTH) : void 0;
|
|
258
|
-
};
|
|
259
|
-
var RECEIPT_TARGET_MAX_LENGTH = 256;
|
|
260
|
-
var parseApplyPatchOps = (command) => {
|
|
261
|
-
if (typeof command !== "string") return [];
|
|
262
|
-
const ops = [];
|
|
263
|
-
for (const line of command.split("\n")) {
|
|
264
|
-
const file = line.match(/^\*\*\*\s+(Add|Update|Delete) File:\s+(.+?)\s*$/);
|
|
265
|
-
if (file) {
|
|
266
|
-
ops.push({ op: file[1].toLowerCase(), path: file[2] });
|
|
267
|
-
continue;
|
|
268
|
-
}
|
|
269
|
-
const move = line.match(/^\*\*\*\s+Move to:\s+(.+?)\s*$/);
|
|
270
|
-
if (move) ops.push({ op: "move", path: move[1] });
|
|
271
|
-
}
|
|
272
|
-
return ops;
|
|
273
|
-
};
|
|
274
|
-
var parseApplyPatchFiles = (command) => [...new Set(parseApplyPatchOps(command).map((entry) => entry.path))];
|
|
275
|
-
var EXIT_CODE_FAILURE = /^Error: Exit code \d+/;
|
|
276
|
-
var isToolResultError = (toolResult) => {
|
|
277
|
-
try {
|
|
278
|
-
if (typeof toolResult === "string") return EXIT_CODE_FAILURE.test(toolResult);
|
|
279
|
-
if (!toolResult || typeof toolResult !== "object") return false;
|
|
280
|
-
return "error" in toolResult || "is_error" in toolResult;
|
|
281
|
-
} catch {
|
|
282
|
-
return false;
|
|
283
|
-
}
|
|
284
|
-
};
|
|
285
|
-
var toolResultErrorText = (toolResult) => {
|
|
286
|
-
try {
|
|
287
|
-
const raw = typeof toolResult === "string" ? toolResult : toolResult && typeof toolResult === "object" ? String(
|
|
288
|
-
toolResult.error ?? toolResult.stderr ?? ""
|
|
289
|
-
) : "";
|
|
290
|
-
return redactSecrets(raw);
|
|
291
|
-
} catch {
|
|
292
|
-
return "";
|
|
293
|
-
}
|
|
294
|
-
};
|
|
295
|
-
var relativizeReceiptPath = (filePath, cwd) => {
|
|
296
|
-
if (!cwd || !isAbsolute(filePath)) return filePath;
|
|
297
|
-
return relative(cwd, filePath);
|
|
298
|
-
};
|
|
299
|
-
var deriveReceiptMeta = (toolName, toolInput, toolResult, cwd) => {
|
|
300
|
-
try {
|
|
301
|
-
const ok = !isToolResultError(toolResult);
|
|
302
|
-
if (toolName === "apply_patch") {
|
|
303
|
-
const files = parseApplyPatchFiles(toolInput.command);
|
|
304
|
-
const target = files.length === 1 ? files[0] : toolInput.command;
|
|
305
|
-
if (typeof target !== "string" || !target) return void 0;
|
|
306
|
-
return { kind: "edit", target: redactSecrets(target).slice(0, RECEIPT_TARGET_MAX_LENGTH), ok };
|
|
307
|
-
}
|
|
308
|
-
const canonicalTool = {
|
|
309
|
-
run_shell_command: "Bash",
|
|
310
|
-
write_file: "Write",
|
|
311
|
-
replace: "Edit"
|
|
312
|
-
}[toolName] ?? toolName;
|
|
313
|
-
const canonicalInput = canonicalTool === toolName ? toolInput : {
|
|
314
|
-
...toolInput,
|
|
315
|
-
file_path: toolInput.file_path ?? toolInput.absolute_path ?? toolInput.path
|
|
316
|
-
};
|
|
317
|
-
if (FILE_TARGET_TOOLS.has(canonicalTool)) {
|
|
318
|
-
const filePath = canonicalInput.file_path;
|
|
319
|
-
if (typeof filePath !== "string" || !filePath) return void 0;
|
|
320
|
-
return {
|
|
321
|
-
kind: canonicalTool === "Write" ? "write" : "edit",
|
|
322
|
-
// A path is an unlikely place for a credential but not an impossible one
|
|
323
|
-
// (a token in a temp directory name), and this field is persisted.
|
|
324
|
-
target: redactSecrets(relativizeReceiptPath(filePath, cwd)).slice(0, RECEIPT_TARGET_MAX_LENGTH),
|
|
325
|
-
ok
|
|
326
|
-
};
|
|
327
|
-
}
|
|
328
|
-
if (canonicalTool === "Bash" || canonicalTool === "PowerShell" || canonicalTool === "Monitor") {
|
|
329
|
-
const head = deriveReceiptCommandHead(canonicalInput.command);
|
|
330
|
-
if (!head) return void 0;
|
|
331
|
-
return {
|
|
332
|
-
kind: head === "git commit" ? "commit" : "bash",
|
|
333
|
-
target: head,
|
|
334
|
-
ok
|
|
335
|
-
};
|
|
336
|
-
}
|
|
337
|
-
return void 0;
|
|
338
|
-
} catch {
|
|
339
|
-
return void 0;
|
|
340
|
-
}
|
|
341
|
-
};
|
|
342
|
-
var scopePathFor = (toolName, toolInput, cwd) => {
|
|
343
|
-
const meta = deriveReceiptMeta(toolName, toolInput, void 0, cwd);
|
|
344
|
-
if (!meta) return void 0;
|
|
345
|
-
return meta.kind === "edit" || meta.kind === "write" ? meta.target : void 0;
|
|
346
|
-
};
|
|
347
|
-
var firstString = (...values) => values.find((v) => typeof v === "string" && v.length > 0);
|
|
348
|
-
var ACTION_BODY_TRUNCATION_MARKER = "\n\u2026 [truncated]";
|
|
349
|
-
var capActionBody = (text) => text.length <= ACTION_BODY_MAX ? text : `${text.slice(0, ACTION_BODY_MAX - ACTION_BODY_TRUNCATION_MARKER.length)}${ACTION_BODY_TRUNCATION_MARKER}`;
|
|
350
|
-
var rawActionBody = (toolName, toolInput) => {
|
|
351
|
-
if (toolName === "Edit" || toolName === "replace") {
|
|
352
|
-
const before = firstString(toolInput.old_string);
|
|
353
|
-
const after = firstString(toolInput.new_string);
|
|
354
|
-
if (before === void 0 && after === void 0) return void 0;
|
|
355
|
-
return `- ${before ?? ""}
|
|
356
|
-
+ ${after ?? ""}`;
|
|
357
|
-
}
|
|
358
|
-
if (toolName === "Write" || toolName === "write_file") return firstString(toolInput.content);
|
|
359
|
-
if (toolName === "ExitPlanMode") return firstString(toolInput.plan);
|
|
360
|
-
if (toolName === "Bash" || toolName === "PowerShell" || toolName === "Monitor" || toolName === "run_shell_command" || toolName === "shell" || toolName === "apply_patch") {
|
|
361
|
-
return firstString(toolInput.command);
|
|
362
|
-
}
|
|
363
|
-
return void 0;
|
|
364
|
-
};
|
|
365
|
-
var deriveActionBody = (toolName, toolInput) => {
|
|
366
|
-
try {
|
|
367
|
-
const raw = rawActionBody(toolName, toolInput);
|
|
368
|
-
if (!raw) return void 0;
|
|
369
|
-
return capActionBody(redactSecretsDeep(raw));
|
|
370
|
-
} catch {
|
|
371
|
-
return void 0;
|
|
372
|
-
}
|
|
373
|
-
};
|
|
374
|
-
var deriveAction = (toolName, toolInput) => describeToolCall(toolName, toolInput, "hook").slice(0, DECISION_LINE_MAX);
|
|
375
|
-
var BLOCKER_BY_MODE = {
|
|
376
|
-
push_only: "Approval required before this runs",
|
|
377
|
-
push_first: "Paused for your approval before continuing",
|
|
378
|
-
escalate: "Escalated to you after the approval timeout"
|
|
379
|
-
};
|
|
380
|
-
var deriveBlocker = (mode, reason) => {
|
|
381
|
-
const text = reason?.replace(/\s+/g, " ").trim() || BLOCKER_BY_MODE[mode] || "Waiting for your approval";
|
|
382
|
-
return text.slice(0, DECISION_LINE_MAX);
|
|
383
|
-
};
|
|
384
|
-
|
|
385
|
-
// ../hook-mapping/src/map.ts
|
|
386
|
-
import { basename } from "path";
|
|
387
|
-
var AGENT_IDENTITIES = {
|
|
388
|
-
claude: { type: "claude_code", label: AGENT_LABELS_BY_TYPE.claude_code },
|
|
389
|
-
codex: { type: "codex", label: AGENT_LABELS_BY_TYPE.codex },
|
|
390
|
-
gemini: { type: "gemini_cli", label: AGENT_LABELS_BY_TYPE.gemini_cli },
|
|
391
|
-
cursor: { type: "cursor", label: AGENT_LABELS_BY_TYPE.cursor },
|
|
392
|
-
vscode: { type: "vscode", label: AGENT_LABELS_BY_TYPE.vscode }
|
|
393
|
-
};
|
|
394
|
-
var TASK_TITLE_MAX_LENGTH = 120;
|
|
395
|
-
var STOP_SUMMARY_MAX_LENGTH = 200;
|
|
396
|
-
var SESSION_END_ACTIONS = {
|
|
397
|
-
clear: "Session cleared",
|
|
398
|
-
logout: "Logged out",
|
|
399
|
-
resume: "Session suspended",
|
|
400
|
-
prompt_input_exit: "Session ended",
|
|
401
|
-
bypass_permissions_disabled: "Session ended",
|
|
402
|
-
other: "Session ended"
|
|
403
|
-
};
|
|
404
|
-
var countArray = (value) => Array.isArray(value) ? value.length : 0;
|
|
405
|
-
var summarizeFinalMessage = (message) => {
|
|
406
|
-
if (typeof message !== "string") return "Session ended";
|
|
407
|
-
const collapsed = message.replace(/\s+/g, " ").trim();
|
|
408
|
-
if (!collapsed) return "Session ended";
|
|
409
|
-
return collapsed.slice(0, STOP_SUMMARY_MAX_LENGTH);
|
|
410
|
-
};
|
|
411
|
-
var summarizeStop = (input) => {
|
|
412
|
-
const running = countArray(input.background_tasks);
|
|
413
|
-
if (running > 0) return `Paused with ${running} background task${running === 1 ? "" : "s"} still running`;
|
|
414
|
-
const crons = countArray(input.session_crons);
|
|
415
|
-
if (crons > 0) return `Idle until a scheduled task wakes it (${crons} pending)`;
|
|
416
|
-
return summarizeFinalMessage(input.last_assistant_message);
|
|
417
|
-
};
|
|
418
|
-
var sessionStartAction = (source) => source === "resume" ? "Session resumed" : "Session started";
|
|
419
|
-
var sessionEndAction = (reason) => typeof reason === "string" && SESSION_END_ACTIONS[reason] || "Session ended";
|
|
420
|
-
var taskTitleFrom = (prompt) => typeof prompt === "string" ? prompt.replace(/\s+/g, " ").trim().slice(0, TASK_TITLE_MAX_LENGTH) || void 0 : void 0;
|
|
421
|
-
|
|
422
189
|
// src/repo.ts
|
|
423
190
|
import { existsSync as existsSync2, readFileSync as readFileSync2, statSync } from "fs";
|
|
424
|
-
import { basename
|
|
191
|
+
import { basename, dirname, isAbsolute, join as join2, resolve } from "path";
|
|
425
192
|
var MAX_PARENT_WALK = 64;
|
|
426
193
|
var GIT_FILE_PREFIX = "gitdir:";
|
|
427
194
|
var findGitDir = (startDir) => {
|
|
428
|
-
let current =
|
|
195
|
+
let current = resolve(startDir);
|
|
429
196
|
for (let depth = 0; depth < MAX_PARENT_WALK; depth += 1) {
|
|
430
197
|
const candidate = join2(current, ".git");
|
|
431
198
|
try {
|
|
@@ -434,7 +201,7 @@ var findGitDir = (startDir) => {
|
|
|
434
201
|
const pointer = readFileSync2(candidate, "utf-8").trim();
|
|
435
202
|
if (pointer.startsWith(GIT_FILE_PREFIX)) {
|
|
436
203
|
const target = pointer.slice(GIT_FILE_PREFIX.length).trim();
|
|
437
|
-
return
|
|
204
|
+
return isAbsolute(target) ? target : resolve(current, target);
|
|
438
205
|
}
|
|
439
206
|
}
|
|
440
207
|
} catch {
|
|
@@ -480,9 +247,9 @@ var deriveRepoKey = (cwd) => {
|
|
|
480
247
|
const normalized = remote ? normalizeRepoRemote(remote) : void 0;
|
|
481
248
|
if (normalized) return normalized;
|
|
482
249
|
const root = gitDir.endsWith(".git") ? dirname(gitDir) : dir;
|
|
483
|
-
return localRepoKey(
|
|
250
|
+
return localRepoKey(basename(root));
|
|
484
251
|
}
|
|
485
|
-
return localRepoKey(
|
|
252
|
+
return localRepoKey(basename(resolve(dir)));
|
|
486
253
|
} catch {
|
|
487
254
|
return void 0;
|
|
488
255
|
}
|
|
@@ -675,7 +442,7 @@ var readNewUsage = (transcriptPath, sessionId) => {
|
|
|
675
442
|
};
|
|
676
443
|
|
|
677
444
|
// src/codex-adapter.ts
|
|
678
|
-
import { resolve as
|
|
445
|
+
import { resolve as resolve2 } from "path";
|
|
679
446
|
var CODEX_AGENT = { type: "codex", label: "Codex" };
|
|
680
447
|
var codexAllow = () => ({ kind: "allow" });
|
|
681
448
|
var codexDeny = (reason) => ({ kind: "deny", reason });
|
|
@@ -704,7 +471,7 @@ var toPolicyLookup = (toolName, toolInput, cwd) => {
|
|
|
704
471
|
const command = toolInput.command;
|
|
705
472
|
const files = parseApplyPatchFiles(command);
|
|
706
473
|
if (files.length === 1) {
|
|
707
|
-
return { tool: "Edit", input: { file_path: cwd ?
|
|
474
|
+
return { tool: "Edit", input: { file_path: cwd ? resolve2(cwd, files[0]) : files[0] } };
|
|
708
475
|
}
|
|
709
476
|
return { tool: "Edit", input: typeof command === "string" ? { file_path: command } : {} };
|
|
710
477
|
};
|
|
@@ -720,7 +487,7 @@ var toPolicyLookups = (toolName, toolInput, cwd) => {
|
|
|
720
487
|
}
|
|
721
488
|
return {
|
|
722
489
|
tool: "Edit",
|
|
723
|
-
inputs: files.map((file) => ({ file_path: cwd ?
|
|
490
|
+
inputs: files.map((file) => ({ file_path: cwd ? resolve2(cwd, file) : file }))
|
|
724
491
|
};
|
|
725
492
|
};
|
|
726
493
|
var permissionTimeoutDecision = (timeoutAction) => {
|
|
@@ -750,7 +517,7 @@ var throttlePass = (key, windowMs) => {
|
|
|
750
517
|
};
|
|
751
518
|
|
|
752
519
|
// src/events.ts
|
|
753
|
-
import { basename as
|
|
520
|
+
import { basename as basename2, join as join5 } from "path";
|
|
754
521
|
import { existsSync as existsSync4, mkdirSync as mkdirSync3, readFileSync as readFileSync4, statSync as statSync4, writeFileSync as writeFileSync4 } from "fs";
|
|
755
522
|
import { tmpdir as tmpdir4 } from "os";
|
|
756
523
|
var INTENT_DIR = join5(tmpdir4(), "pushary-intent");
|
|
@@ -939,7 +706,7 @@ var reportEvent = async (event, options = {}) => {
|
|
|
939
706
|
var NON_GATED_MIRROR_TOOLS = /* @__PURE__ */ new Set(["TodoWrite"]);
|
|
940
707
|
var handlePostToolUse = async (input, agent = CLAUDE_CODE_AGENT) => {
|
|
941
708
|
try {
|
|
942
|
-
const projectName =
|
|
709
|
+
const projectName = basename2(input.cwd ?? process.cwd());
|
|
943
710
|
const action = describeToolCall(input.tool_name, input.tool_input, "event");
|
|
944
711
|
const lookup = toPolicyLookup(input.tool_name, input.tool_input);
|
|
945
712
|
const toolResult = input.tool_response ?? input.tool_result;
|
|
@@ -993,7 +760,7 @@ var handlePostToolUse = async (input, agent = CLAUDE_CODE_AGENT) => {
|
|
|
993
760
|
};
|
|
994
761
|
var handleUserPrompt = async (input, agent = CLAUDE_CODE_AGENT) => {
|
|
995
762
|
try {
|
|
996
|
-
const projectName =
|
|
763
|
+
const projectName = basename2(input.cwd ?? process.cwd());
|
|
997
764
|
const sessionKey = input.session_id || DEFAULT_SESSION;
|
|
998
765
|
const titlesEnabled = process.env.PUSHARY_TASK_TITLES !== "off";
|
|
999
766
|
const taskTitle = titlesEnabled ? taskTitleFrom(input.prompt) : void 0;
|
|
@@ -1023,7 +790,7 @@ var handleUserPrompt = async (input, agent = CLAUDE_CODE_AGENT) => {
|
|
|
1023
790
|
};
|
|
1024
791
|
var handleStop = async (input, agent = CLAUDE_CODE_AGENT) => {
|
|
1025
792
|
try {
|
|
1026
|
-
const projectName =
|
|
793
|
+
const projectName = basename2(input.cwd ?? process.cwd());
|
|
1027
794
|
const sessionKey = input.session_id || DEFAULT_SESSION;
|
|
1028
795
|
const late = await reconcilePendingQuestions(sessionKey);
|
|
1029
796
|
const tasks = [
|
|
@@ -1059,7 +826,7 @@ var handleStop = async (input, agent = CLAUDE_CODE_AGENT) => {
|
|
|
1059
826
|
};
|
|
1060
827
|
var handleSessionStart = async (input, agent = CLAUDE_CODE_AGENT) => {
|
|
1061
828
|
try {
|
|
1062
|
-
const projectName =
|
|
829
|
+
const projectName = basename2(input.cwd ?? process.cwd());
|
|
1063
830
|
const action = sessionStartAction(input.source);
|
|
1064
831
|
await reportEvent({
|
|
1065
832
|
event: "session_start",
|
|
@@ -1071,16 +838,18 @@ var handleSessionStart = async (input, agent = CLAUDE_CODE_AGENT) => {
|
|
|
1071
838
|
} catch {
|
|
1072
839
|
}
|
|
1073
840
|
};
|
|
1074
|
-
var handleSessionEnd = async (input, agent = CLAUDE_CODE_AGENT) => {
|
|
841
|
+
var handleSessionEnd = async (input, agent = CLAUDE_CODE_AGENT, options = {}) => {
|
|
1075
842
|
try {
|
|
1076
|
-
const projectName =
|
|
843
|
+
const projectName = basename2(input.cwd ?? process.cwd());
|
|
1077
844
|
const action = sessionEndAction(input.reason);
|
|
1078
845
|
const sessionKey = input.session_id || DEFAULT_SESSION;
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
846
|
+
if (options.reconcile ?? true) {
|
|
847
|
+
const late = await reconcilePendingQuestions(sessionKey);
|
|
848
|
+
if (late.length > 0) {
|
|
849
|
+
await notifyLateAnswers(getApiKey(), late, `${agent.label} - ${projectName}`, input.session_id).catch(() => {
|
|
850
|
+
});
|
|
851
|
+
for (const l of late) removePendingQuestion(sessionKey, l.correlationId);
|
|
852
|
+
}
|
|
1084
853
|
}
|
|
1085
854
|
if (!isDefaultSession(sessionKey)) removePendingSession(sessionKey);
|
|
1086
855
|
await reportEvent({
|
|
@@ -1089,7 +858,7 @@ var handleSessionEnd = async (input, agent = CLAUDE_CODE_AGENT) => {
|
|
|
1089
858
|
agentName: `${agent.label} - ${projectName}`,
|
|
1090
859
|
action,
|
|
1091
860
|
sessionId: input.session_id
|
|
1092
|
-
}, { maxAttempts: 2, timeoutMs: 3e3 });
|
|
861
|
+
}, { maxAttempts: options.reportAttempts ?? 2, timeoutMs: options.reportTimeoutMs ?? 3e3 });
|
|
1093
862
|
} catch {
|
|
1094
863
|
}
|
|
1095
864
|
};
|
|
@@ -1097,7 +866,7 @@ var NOTIFICATION_PUSH_TYPES = /* @__PURE__ */ new Set(["idle_prompt", "agent_nee
|
|
|
1097
866
|
var NOTIFICATION_THROTTLE_MS = 60 * 1e3;
|
|
1098
867
|
var handleNotification = async (input, agent = CLAUDE_CODE_AGENT) => {
|
|
1099
868
|
try {
|
|
1100
|
-
const projectName =
|
|
869
|
+
const projectName = basename2(input.cwd ?? process.cwd());
|
|
1101
870
|
const notifType = input.notification_type ?? input.type ?? "";
|
|
1102
871
|
const sessionKey = input.session_id || DEFAULT_SESSION;
|
|
1103
872
|
if (NOTIFICATION_PUSH_TYPES.has(notifType)) {
|
|
@@ -1170,7 +939,7 @@ var handleStopFailure = async (input, agent = CLAUDE_CODE_AGENT) => {
|
|
|
1170
939
|
} catch {
|
|
1171
940
|
return;
|
|
1172
941
|
}
|
|
1173
|
-
const projectName =
|
|
942
|
+
const projectName = basename2(input.cwd ?? process.cwd());
|
|
1174
943
|
const mode = await fetchModeState(apiKey, input.session_id, MODE_REUSE_MS).catch(() => null);
|
|
1175
944
|
if (mode?.kill || mode?.mode === "terminal_only") return;
|
|
1176
945
|
const reason = describeStopFailure(input.error);
|
|
@@ -1191,12 +960,6 @@ export {
|
|
|
1191
960
|
getPolicy,
|
|
1192
961
|
fetchModeState,
|
|
1193
962
|
fetchModeOverride,
|
|
1194
|
-
describeToolCall,
|
|
1195
|
-
deriveToolTarget,
|
|
1196
|
-
scopePathFor,
|
|
1197
|
-
deriveActionBody,
|
|
1198
|
-
deriveAction,
|
|
1199
|
-
deriveBlocker,
|
|
1200
963
|
repoKeyFor,
|
|
1201
964
|
throttlePass,
|
|
1202
965
|
readLastUserPrompt,
|