@pushary/agent-hooks 0.89.12 → 0.90.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/CHANGELOG.md +77 -0
- package/README.md +1 -0
- package/data/SKILL.md +1 -1
- package/data/cursor-plugin/skills/pushary/SKILL.md +1 -1
- package/data/vscode-plugin/skills/pushary/SKILL.md +1 -1
- package/dist/bin/pushary-bell-hook.js +4 -4
- package/dist/bin/pushary-bell.js +8 -8
- package/dist/bin/pushary-claude.js +194 -38
- package/dist/bin/pushary-clean.js +15 -32
- package/dist/bin/pushary-codex-bridge.js +37 -12
- package/dist/bin/pushary-codex-hook.js +45 -12
- package/dist/bin/pushary-codex.js +7 -7
- package/dist/bin/pushary-connect.js +11 -10
- package/dist/bin/pushary-daemon.js +186 -62
- package/dist/bin/pushary-disconnect.js +8 -8
- package/dist/bin/pushary-doctor.js +108 -25
- package/dist/bin/pushary-elicitation-hook.js +4 -4
- package/dist/bin/pushary-gemini-bridge.js +33 -11
- package/dist/bin/pushary-gemini-hook.js +21 -10
- package/dist/bin/pushary-hook.js +13 -13
- package/dist/bin/pushary-login.js +18 -7
- package/dist/bin/pushary-logout.js +6 -6
- package/dist/bin/pushary-mode.js +28 -21
- package/dist/bin/pushary-notification-hook.js +7 -7
- package/dist/bin/pushary-opencode-hook.js +8 -8
- package/dist/bin/pushary-permission-denied-hook.js +11 -11
- package/dist/bin/pushary-permission-hook.js +11 -11
- package/dist/bin/pushary-post-hook.js +14 -8
- package/dist/bin/pushary-prompt-hook.js +7 -7
- package/dist/bin/pushary-session-end-hook.js +7 -7
- package/dist/bin/pushary-session-start-hook.js +7 -7
- package/dist/bin/pushary-setup.js +168 -45
- package/dist/bin/pushary-stats.js +4 -4
- package/dist/bin/pushary-status.js +11 -10
- package/dist/bin/pushary-stop-hook.js +14 -8
- package/dist/bin/pushary-stopfailure-hook.js +7 -7
- package/dist/bin/pushary-suggestions.js +2 -2
- package/dist/bin/pushary-transcripts.d.ts +1 -0
- package/dist/bin/pushary-transcripts.js +79 -0
- package/dist/bin/pushary-upgrade.js +15 -15
- package/dist/bin/pushary-wait.js +5 -5
- package/dist/bin/pushary.js +3 -2
- package/dist/{chunk-KVHP5ZME.js → chunk-2LAHXHBR.js} +1 -1
- package/dist/{chunk-RLQWNEPM.js → chunk-43GMYSS4.js} +15 -0
- package/dist/{chunk-5NDB3YOE.js → chunk-54ELC7D7.js} +1 -1
- package/dist/{chunk-VPLQFXCH.js → chunk-5NAZ7SFS.js} +1 -1
- package/dist/chunk-7FE2KABY.js +156 -0
- package/dist/{chunk-DHR4F2CR.js → chunk-7TPQEWUZ.js} +1 -1
- package/dist/{chunk-Y4WVZIEI.js → chunk-AJYV3VGU.js} +1 -1
- package/dist/{chunk-QFJZHVVL.js → chunk-AZPIQG4G.js} +35 -1
- package/dist/{chunk-OCMOTJTW.js → chunk-B7UZHEBL.js} +29 -22
- package/dist/{chunk-7HYJPOGG.js → chunk-BQBEH6TV.js} +5 -5
- package/dist/{chunk-OTPJ4FUR.js → chunk-BVBEURWJ.js} +1 -1
- package/dist/{chunk-7DK3ZH3N.js → chunk-CELX75MW.js} +1 -1
- package/dist/{chunk-6VXNA5JB.js → chunk-CNPAT3HL.js} +3 -2
- package/dist/{chunk-327YMKP5.js → chunk-DYP6SMOR.js} +1 -1
- package/dist/chunk-DZDI62LY.js +145 -0
- package/dist/{chunk-VF3RTVWY.js → chunk-EZIEXHYM.js} +15 -7
- package/dist/{chunk-PS7DQ2SU.js → chunk-F2ICEWZL.js} +101 -19
- package/dist/{chunk-3XSP5SML.js → chunk-FQL5E6NG.js} +2 -2
- package/dist/{chunk-JHJHCMAF.js → chunk-FXEVRLHC.js} +20 -2
- package/dist/{chunk-6V7ZDH3A.js → chunk-GL3FFM7A.js} +7 -4
- package/dist/{chunk-NBRM3FMD.js → chunk-H2QZRQR2.js} +1 -1
- package/dist/{chunk-GKPURU7P.js → chunk-I463AEG3.js} +1 -1
- package/dist/{chunk-XREW7RQ3.js → chunk-JW4KO5AF.js} +1 -1
- package/dist/{chunk-OVEGEQSB.js → chunk-KUZWXPUS.js} +3 -2
- package/dist/{chunk-JVZX5YRJ.js → chunk-L4E2BIJ2.js} +80 -7
- package/dist/{chunk-RNKPLUWC.js → chunk-OSALSIUF.js} +1 -1
- package/dist/{chunk-MFNQ5IMW.js → chunk-PYA4FLKI.js} +32 -21
- package/dist/chunk-QCGNGEGE.js +15 -0
- package/dist/chunk-S6LYP7QA.js +127 -0
- package/dist/{chunk-OADGBOP7.js → chunk-TDZFPMSZ.js} +70 -11
- package/dist/{chunk-JJV5Q4KG.js → chunk-UZNKVRLE.js} +1 -1
- package/dist/{chunk-FCUUVHTS.js → chunk-VHWCVD42.js} +1 -1
- package/dist/{chunk-3MCEES6Z.js → chunk-VNMKIJZB.js} +15 -2
- package/dist/{chunk-6GU55AQQ.js → chunk-Y6BWPERV.js} +90 -7
- package/dist/chunk-YKLCWWEI.js +76 -0
- package/dist/src/index.d.ts +3 -0
- package/dist/src/index.js +11 -11
- package/package.json +3 -2
- package/dist/chunk-NESKLV6R.js +0 -72
- package/dist/chunk-WDVQ6O4C.js +0 -84
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
FILE_TARGET_TOOLS,
|
|
6
6
|
redactSecrets,
|
|
7
7
|
redactSecretsDeep
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-VNMKIJZB.js";
|
|
9
9
|
|
|
10
10
|
// ../hook-mapping/src/describe.ts
|
|
11
11
|
import { isAbsolute, relative, resolve } from "path";
|
|
@@ -44,6 +44,48 @@ var eventPrefixes = {
|
|
|
44
44
|
Read: (input) => `read: ${input.file_path ?? "unknown"}`,
|
|
45
45
|
TodoWrite: (input) => describeTodoProgress(input.todos)
|
|
46
46
|
};
|
|
47
|
+
var MCP_TOOL_PREFIX = "mcp__";
|
|
48
|
+
var parseMcpToolName = (toolName) => {
|
|
49
|
+
if (!toolName.startsWith(MCP_TOOL_PREFIX)) return void 0;
|
|
50
|
+
const rest = toolName.slice(MCP_TOOL_PREFIX.length);
|
|
51
|
+
const split = rest.indexOf("__");
|
|
52
|
+
if (split <= 0 || split + 2 >= rest.length) return void 0;
|
|
53
|
+
return { server: rest.slice(0, split), tool: rest.slice(split + 2) };
|
|
54
|
+
};
|
|
55
|
+
var NETWORK_TARGET_KEYS = ["url", "urls", "href", "host", "hosts", "hostname", "domain", "domains"];
|
|
56
|
+
var ABSOLUTE_HTTP_URL = /^https?:\/\//i;
|
|
57
|
+
var HOSTNAME = /^(?=.{1,253}$)[a-z0-9](?:[a-z0-9-]*[a-z0-9])?(?:\.[a-z0-9](?:[a-z0-9-]*[a-z0-9])?)+(?::\d{1,5})?$/i;
|
|
58
|
+
var hostOfUrl = (value) => {
|
|
59
|
+
try {
|
|
60
|
+
return new URL(value).host || void 0;
|
|
61
|
+
} catch {
|
|
62
|
+
return void 0;
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
var hostOf = (value, bareHostnames) => {
|
|
66
|
+
if (typeof value !== "string") return void 0;
|
|
67
|
+
const trimmed = value.trim();
|
|
68
|
+
if (ABSOLUTE_HTTP_URL.test(trimmed)) return hostOfUrl(trimmed);
|
|
69
|
+
return bareHostnames && HOSTNAME.test(trimmed) ? trimmed : void 0;
|
|
70
|
+
};
|
|
71
|
+
var firstHost = (value, bareHostnames) => Array.isArray(value) ? value.map((entry) => hostOf(entry, bareHostnames)).find((host) => host !== void 0) : hostOf(value, bareHostnames);
|
|
72
|
+
var deriveNetworkTarget = (toolInput) => {
|
|
73
|
+
for (const key of NETWORK_TARGET_KEYS) {
|
|
74
|
+
const host = firstHost(toolInput[key], true);
|
|
75
|
+
if (host) return host;
|
|
76
|
+
}
|
|
77
|
+
return Object.values(toolInput).map((value) => firstHost(value, false)).find((host) => host !== void 0);
|
|
78
|
+
};
|
|
79
|
+
var describeUnbuiltCall = (toolName, toolInput, format) => {
|
|
80
|
+
const mcp = parseMcpToolName(toolName);
|
|
81
|
+
const host = deriveNetworkTarget(toolInput);
|
|
82
|
+
if (mcp) {
|
|
83
|
+
if (format === "event") return `called ${mcp.tool} on ${mcp.server}`;
|
|
84
|
+
return host ? `call ${mcp.tool} on ${mcp.server} to reach ${host}` : `call ${mcp.tool} on ${mcp.server}`;
|
|
85
|
+
}
|
|
86
|
+
if (host) return format === "event" ? `accessed ${host}` : `network access to ${host}`;
|
|
87
|
+
return void 0;
|
|
88
|
+
};
|
|
47
89
|
var EVENT_ACTION_MAX = 120;
|
|
48
90
|
var HOOK_FALLBACK_MAX = 200;
|
|
49
91
|
var UNNAMED_ACTION = "this request";
|
|
@@ -51,11 +93,12 @@ var describeToolCall = (toolName, toolInput, format = "hook") => {
|
|
|
51
93
|
if (!toolName) return "";
|
|
52
94
|
const prefixes = format === "hook" ? hookPrefixes : eventPrefixes;
|
|
53
95
|
const builder = prefixes[toolName];
|
|
96
|
+
const unbuilt = builder ? void 0 : describeUnbuiltCall(toolName, toolInput ?? {}, format);
|
|
54
97
|
const detail = JSON.stringify(toolInput ?? {});
|
|
55
|
-
const raw = builder ? builder(toolInput) : format === "hook" ? detail === "{}" || detail === void 0 ? toolName : `${toolName}: ${detail}` : `${toolName}: done
|
|
98
|
+
const raw = builder ? builder(toolInput) : unbuilt ?? (format === "hook" ? detail === "{}" || detail === void 0 ? toolName : `${toolName}: ${detail}` : `${toolName}: done`);
|
|
56
99
|
const redacted = redactSecrets(raw);
|
|
57
100
|
if (format === "event") return redacted.slice(0, EVENT_ACTION_MAX);
|
|
58
|
-
return builder ? redacted : redacted.slice(0, HOOK_FALLBACK_MAX);
|
|
101
|
+
return builder || unbuilt ? redacted : redacted.slice(0, HOOK_FALLBACK_MAX);
|
|
59
102
|
};
|
|
60
103
|
var TOOL_TARGET_MAX_LENGTH = 80;
|
|
61
104
|
var deriveCommandHead = (command) => {
|
|
@@ -76,7 +119,9 @@ var deriveToolTarget = (toolName, toolInput) => {
|
|
|
76
119
|
if (dot <= 0) return void 0;
|
|
77
120
|
return base.slice(dot).slice(0, TOOL_TARGET_MAX_LENGTH);
|
|
78
121
|
}
|
|
79
|
-
|
|
122
|
+
const mcp = parseMcpToolName(toolName);
|
|
123
|
+
if (mcp) return mcp.server.slice(0, TOOL_TARGET_MAX_LENGTH);
|
|
124
|
+
return deriveNetworkTarget(toolInput)?.slice(0, TOOL_TARGET_MAX_LENGTH);
|
|
80
125
|
};
|
|
81
126
|
var SCRIPT_RUNNERS = /* @__PURE__ */ new Set(["npm", "pnpm", "yarn", "bun", "npx", "deno", "rake", "make", "just", "task", "turbo"]);
|
|
82
127
|
var RUN_SUBCOMMANDS = /* @__PURE__ */ new Set(["run", "run-script", "exec", "task"]);
|
|
@@ -210,7 +255,7 @@ var rawActionBody = (toolName, toolInput) => {
|
|
|
210
255
|
if (toolName === "Bash" || toolName === "PowerShell" || toolName === "Monitor" || toolName === "run_shell_command" || toolName === "shell" || toolName === "apply_patch") {
|
|
211
256
|
return firstString(toolInput.command);
|
|
212
257
|
}
|
|
213
|
-
return
|
|
258
|
+
return firstString(toolInput.url, toolInput.href);
|
|
214
259
|
};
|
|
215
260
|
var deriveActionBody = (toolName, toolInput) => {
|
|
216
261
|
try {
|
|
@@ -264,11 +309,36 @@ var summarizeStop = (input) => {
|
|
|
264
309
|
if (running > 0) return `Paused with ${running} background task${running === 1 ? "" : "s"} still running`;
|
|
265
310
|
const crons = countArray(input.session_crons);
|
|
266
311
|
if (crons > 0) return `Idle until a scheduled task wakes it (${crons} pending)`;
|
|
267
|
-
return summarizeFinalMessage(input.last_assistant_message);
|
|
312
|
+
return summarizeFinalMessage(input.last_assistant_message ?? input.prompt_response);
|
|
313
|
+
};
|
|
314
|
+
var subagentStopAction = (agentType) => {
|
|
315
|
+
const name = typeof agentType === "string" ? agentType.replace(/\s+/g, " ").trim() : "";
|
|
316
|
+
return name ? `${name} subagent finished` : "Subagent finished";
|
|
317
|
+
};
|
|
318
|
+
var subagentStopSummary = (input) => {
|
|
319
|
+
const message = input.last_assistant_message ?? input.prompt_response;
|
|
320
|
+
if (typeof message === "string" && message.trim()) return summarizeStop(input);
|
|
321
|
+
return subagentStopAction(input.agent_type);
|
|
322
|
+
};
|
|
323
|
+
var COMPACTION_TRIGGERS = {
|
|
324
|
+
manual: "on request",
|
|
325
|
+
auto: "automatically"
|
|
326
|
+
};
|
|
327
|
+
var compactionAction = (hookEvent, trigger) => {
|
|
328
|
+
const how = typeof trigger === "string" ? COMPACTION_TRIGGERS[trigger] : void 0;
|
|
329
|
+
const base = hookEvent === "PostCompact" ? "Compacted context" : "Compacting context";
|
|
330
|
+
return how ? `${base} ${how}` : base;
|
|
268
331
|
};
|
|
269
332
|
var sessionStartAction = (source) => source === "resume" ? "Session resumed" : "Session started";
|
|
270
333
|
var sessionEndAction = (reason) => typeof reason === "string" && SESSION_END_ACTIONS[reason] || "Session ended";
|
|
271
334
|
var taskTitleFrom = (prompt) => typeof prompt === "string" ? prompt.replace(/\s+/g, " ").trim().slice(0, TASK_TITLE_MAX_LENGTH) || void 0 : void 0;
|
|
335
|
+
var asString = (value) => typeof value === "string" && value.length > 0 ? value : void 0;
|
|
336
|
+
var sessionIdentityOf = (payload) => {
|
|
337
|
+
const sessionId = asString(payload.session_id);
|
|
338
|
+
const agentId = asString(payload.agent_id);
|
|
339
|
+
if (!agentId) return { sessionId };
|
|
340
|
+
return { sessionId: agentId, parentSessionId: sessionId };
|
|
341
|
+
};
|
|
272
342
|
|
|
273
343
|
export {
|
|
274
344
|
HOOK_FALLBACK_MAX,
|
|
@@ -287,7 +357,10 @@ export {
|
|
|
287
357
|
deriveBlocker,
|
|
288
358
|
AGENT_IDENTITIES,
|
|
289
359
|
summarizeStop,
|
|
360
|
+
subagentStopSummary,
|
|
361
|
+
compactionAction,
|
|
290
362
|
sessionStartAction,
|
|
291
363
|
sessionEndAction,
|
|
292
|
-
taskTitleFrom
|
|
364
|
+
taskTitleFrom,
|
|
365
|
+
sessionIdentityOf
|
|
293
366
|
};
|
|
@@ -3,6 +3,10 @@ import {
|
|
|
3
3
|
openSealedKey,
|
|
4
4
|
publicKeyFingerprint
|
|
5
5
|
} from "./chunk-3EGEA4KH.js";
|
|
6
|
+
import {
|
|
7
|
+
humanIsTty,
|
|
8
|
+
writeHuman
|
|
9
|
+
} from "./chunk-QCGNGEGE.js";
|
|
6
10
|
import {
|
|
7
11
|
useColor
|
|
8
12
|
} from "./chunk-5RUIFDTP.js";
|
|
@@ -11,7 +15,7 @@ import {
|
|
|
11
15
|
} from "./chunk-BSZYIAZL.js";
|
|
12
16
|
import {
|
|
13
17
|
reportedInstallSource
|
|
14
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-JW4KO5AF.js";
|
|
15
19
|
|
|
16
20
|
// src/reach.ts
|
|
17
21
|
var reachVerdict = (channels) => {
|
|
@@ -263,16 +267,6 @@ var describeRoundTrip = (outcome) => {
|
|
|
263
267
|
}
|
|
264
268
|
};
|
|
265
269
|
|
|
266
|
-
// src/cli/human.ts
|
|
267
|
-
var stream = process.stdout;
|
|
268
|
-
var setHumanStream = (target) => {
|
|
269
|
-
stream = target;
|
|
270
|
-
};
|
|
271
|
-
var writeHuman = (text) => {
|
|
272
|
-
stream.write(text);
|
|
273
|
-
};
|
|
274
|
-
var humanIsTty = () => stream === process.stdout && process.stdout.isTTY === true;
|
|
275
|
-
|
|
276
270
|
// src/onboarding.ts
|
|
277
271
|
import qrcodeTerminal from "qrcode-terminal";
|
|
278
272
|
var paint = (open) => (s) => useColor() ? `${open}${s}\x1B[0m` : s;
|
|
@@ -650,6 +644,20 @@ var confirmAppConnection = async (apiKey) => {
|
|
|
650
644
|
}
|
|
651
645
|
return sendAndConfirm(apiKey, channels);
|
|
652
646
|
};
|
|
647
|
+
var planAppConnect = (channels) => channels.precise && ownedApp(channels) === 0 ? { kind: "unpaired", repair: describeAppRepair(reachVerdict(channels)) ?? [] } : { kind: "send" };
|
|
648
|
+
var connectExistingApp = async (apiKey) => {
|
|
649
|
+
const probe = await fetchChannels(apiKey);
|
|
650
|
+
if (probe.kind !== "ok") return describeProbeFailure(probe);
|
|
651
|
+
const plan = planAppConnect(probe.status);
|
|
652
|
+
if (plan.kind === "send") {
|
|
653
|
+
console.log(` ${check} ${describeExistingConnection(probe.status)}`);
|
|
654
|
+
return sendAndConfirm(apiKey, probe.status);
|
|
655
|
+
}
|
|
656
|
+
console.log(` ${yellow("!")} No Pushary app of yours is connected to this site, and nothing was paired just now.`);
|
|
657
|
+
for (const line of plan.repair) console.log(` ${dim(line)}`);
|
|
658
|
+
console.log(` ${dim("No app yet? Get it at")} ${cyan("https://pushary.com/download")}`);
|
|
659
|
+
return phoneFailure("app_not_paired", plan.repair);
|
|
660
|
+
};
|
|
653
661
|
var printConnectInstructions = async (apiKey) => {
|
|
654
662
|
const probe = await fetchChannels(apiKey);
|
|
655
663
|
if (probe.kind !== "ok") return describeProbeFailure(probe);
|
|
@@ -737,6 +745,8 @@ var ackPairing = async (pairId) => {
|
|
|
737
745
|
} catch {
|
|
738
746
|
}
|
|
739
747
|
};
|
|
748
|
+
var pairFailed = (reason) => ({ kind: "failed", reason });
|
|
749
|
+
var pairingEscapeApplies = (outcome) => outcome.reason === "timeout" || outcome.reason === "expired" || outcome.reason === "cancelled";
|
|
740
750
|
var buildPairLinks = (pairId, publicKeyB64, baseUrl = apiBase(), code = null) => {
|
|
741
751
|
const id = encodeURIComponent(pairId);
|
|
742
752
|
const pk = encodeURIComponent(publicKeyB64);
|
|
@@ -760,7 +770,7 @@ var connectViaAppPairing = async (options = {}) => {
|
|
|
760
770
|
const started = await startPairing(keypair.publicKeyB64);
|
|
761
771
|
if (!started) {
|
|
762
772
|
console.log(` ${yellow("!")} Couldn't start pairing. Check your connection and try again.`);
|
|
763
|
-
return
|
|
773
|
+
return pairFailed("unreachable");
|
|
764
774
|
}
|
|
765
775
|
const { pairId, code } = started;
|
|
766
776
|
const { qrLink, universalLink, deepLink } = buildPairLinks(pairId, keypair.publicKeyB64, apiBase(), code);
|
|
@@ -800,14 +810,14 @@ var connectViaAppPairing = async (options = {}) => {
|
|
|
800
810
|
let consecutiveFailures = 0;
|
|
801
811
|
try {
|
|
802
812
|
while (Date.now() < deadline) {
|
|
803
|
-
if (cancelled) return
|
|
813
|
+
if (cancelled) return pairFailed("cancelled");
|
|
804
814
|
const claim = await claimPairing(pairId);
|
|
805
815
|
if (claim === null) {
|
|
806
816
|
consecutiveFailures += 1;
|
|
807
817
|
if (consecutiveFailures >= PAIR_MAX_CONSECUTIVE_FAILURES) {
|
|
808
818
|
stop(yellow("!"), "Can't reach pushary.com to finish pairing. Check your connection, then re-run setup.");
|
|
809
819
|
await cancelPairing(pairId);
|
|
810
|
-
return
|
|
820
|
+
return pairFailed("unreachable");
|
|
811
821
|
}
|
|
812
822
|
await sleep(PAIR_POLL_INTERVAL_MS);
|
|
813
823
|
continue;
|
|
@@ -820,29 +830,29 @@ var connectViaAppPairing = async (options = {}) => {
|
|
|
820
830
|
} catch {
|
|
821
831
|
stop(yellow("!"), "Pairing failed to decrypt \u2014 re-run setup to try again");
|
|
822
832
|
await cancelPairing(pairId);
|
|
823
|
-
return
|
|
833
|
+
return pairFailed("decrypt");
|
|
824
834
|
}
|
|
825
835
|
await ackPairing(pairId);
|
|
826
836
|
stop(check, "App connected");
|
|
827
|
-
return { apiKey, handle: claim.siteSlug };
|
|
837
|
+
return { kind: "paired", apiKey, handle: claim.siteSlug };
|
|
828
838
|
}
|
|
829
839
|
if (claim?.status === "expired") {
|
|
830
840
|
stop(yellow("!"), "Pairing expired \u2014 re-run setup to try again");
|
|
831
|
-
return
|
|
841
|
+
return pairFailed("expired");
|
|
832
842
|
}
|
|
833
843
|
if (claim?.status === "failed") {
|
|
834
844
|
stop(yellow("!"), describePairFailure(claim.reason));
|
|
835
|
-
return
|
|
845
|
+
return pairFailed("rejected");
|
|
836
846
|
}
|
|
837
847
|
await sleep(PAIR_POLL_INTERVAL_MS);
|
|
838
848
|
}
|
|
839
849
|
stop(yellow("!"), "Timed out waiting for the app");
|
|
840
850
|
await cancelPairing(pairId);
|
|
841
|
-
return
|
|
851
|
+
return pairFailed("timeout");
|
|
842
852
|
} catch (err) {
|
|
843
853
|
stop(yellow("!"), `Pairing error ${dim(`(${err instanceof Error ? err.message : "network"})`)}`);
|
|
844
854
|
await cancelPairing(pairId);
|
|
845
|
-
return
|
|
855
|
+
return pairFailed("unreachable");
|
|
846
856
|
} finally {
|
|
847
857
|
process.off("SIGINT", onInterrupt);
|
|
848
858
|
}
|
|
@@ -853,10 +863,11 @@ export {
|
|
|
853
863
|
describeReach,
|
|
854
864
|
verifyRoundTrip,
|
|
855
865
|
describeRoundTrip,
|
|
856
|
-
setHumanStream,
|
|
857
866
|
fetchChannels,
|
|
858
867
|
connectDevice,
|
|
859
868
|
confirmAppConnection,
|
|
869
|
+
connectExistingApp,
|
|
860
870
|
printConnectInstructions,
|
|
871
|
+
pairingEscapeApplies,
|
|
861
872
|
connectViaAppPairing
|
|
862
873
|
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
// src/cli/human.ts
|
|
2
|
+
var stream = process.stdout;
|
|
3
|
+
var setHumanStream = (target) => {
|
|
4
|
+
stream = target;
|
|
5
|
+
};
|
|
6
|
+
var writeHuman = (text) => {
|
|
7
|
+
stream.write(text);
|
|
8
|
+
};
|
|
9
|
+
var humanIsTty = () => stream === process.stdout && process.stdout.isTTY === true;
|
|
10
|
+
|
|
11
|
+
export {
|
|
12
|
+
setHumanStream,
|
|
13
|
+
writeHuman,
|
|
14
|
+
humanIsTty
|
|
15
|
+
};
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import {
|
|
2
|
+
HOOK_LOCATOR_BINARY
|
|
3
|
+
} from "./chunk-VNMKIJZB.js";
|
|
4
|
+
|
|
5
|
+
// src/diagnostics/bridge.ts
|
|
6
|
+
import { execFileSync } from "child_process";
|
|
7
|
+
import { existsSync, readFileSync } from "fs";
|
|
8
|
+
import { homedir } from "os";
|
|
9
|
+
import { dirname, join } from "path";
|
|
10
|
+
var BRIDGE_BUNDLE_IDENTIFIER = "com.pushary.app";
|
|
11
|
+
var BRIDGE_HELPER_SUFFIX = "/Contents/Helpers/pushary-bridge";
|
|
12
|
+
var BRIDGE_BUNDLE_ROOTS = ["/Applications/Pushary.app", "$HOME/Applications/Pushary.app"];
|
|
13
|
+
var expandHome = (path, home) => path.replaceAll("$HOME", home);
|
|
14
|
+
var parseBridgeStub = (contents, stubPath) => {
|
|
15
|
+
const helperSuffix = contents.match(/^H=(\S+)$/m)?.[1] ?? BRIDGE_HELPER_SUFFIX;
|
|
16
|
+
const cachePath = contents.match(/^C="([^"\n]+)"$/m)?.[1] ?? join(dirname(stubPath), ".bridge-cache");
|
|
17
|
+
const rootsLine = contents.match(/^for P in ((?:"[^"\n]*"\s*)+); do$/m)?.[1];
|
|
18
|
+
const bundleRoots = rootsLine ? [...rootsLine.matchAll(/"([^"]*)"/g)].map((match) => match[1]) : BRIDGE_BUNDLE_ROOTS;
|
|
19
|
+
const bundleIdentifier = contents.match(/kMDItemCFBundleIdentifier == "([^"]+)"/)?.[1] ?? BRIDGE_BUNDLE_IDENTIFIER;
|
|
20
|
+
return { helperSuffix, cachePath, bundleRoots, bundleIdentifier };
|
|
21
|
+
};
|
|
22
|
+
var resolveBridgeStub = (stubPath, probe) => {
|
|
23
|
+
const contents = probe.readFile(stubPath);
|
|
24
|
+
if (contents === null) return { kind: "no-stub", stub: stubPath };
|
|
25
|
+
const shape = parseBridgeStub(contents, stubPath);
|
|
26
|
+
const helperIn = (bundle) => `${bundle}${shape.helperSuffix}`;
|
|
27
|
+
const looked = [];
|
|
28
|
+
for (const root of shape.bundleRoots.map((root2) => expandHome(root2, probe.home))) {
|
|
29
|
+
looked.push(root);
|
|
30
|
+
if (probe.exists(helperIn(root))) return { kind: "bundle", helper: helperIn(root), via: "root" };
|
|
31
|
+
}
|
|
32
|
+
const cached = shape.cachePath ? probe.readFile(shape.cachePath)?.split("\n")[0]?.trim() : void 0;
|
|
33
|
+
if (cached) {
|
|
34
|
+
looked.push(cached);
|
|
35
|
+
if (probe.exists(helperIn(cached))) return { kind: "bundle", helper: helperIn(cached), via: "cache" };
|
|
36
|
+
}
|
|
37
|
+
for (const found of probe.mdfind(shape.bundleIdentifier)) {
|
|
38
|
+
looked.push(found);
|
|
39
|
+
if (probe.exists(helperIn(found))) return { kind: "bundle", helper: helperIn(found), via: "spotlight" };
|
|
40
|
+
}
|
|
41
|
+
return { kind: "missing", stub: stubPath, looked };
|
|
42
|
+
};
|
|
43
|
+
var BRIDGE_GONE_MESSAGE = "the Mac app is gone but its hooks remain; run pushary setup or reinstall the app";
|
|
44
|
+
var describeBridgeResolution = (resolution) => {
|
|
45
|
+
switch (resolution.kind) {
|
|
46
|
+
case "bundle":
|
|
47
|
+
return `${resolution.helper} (${resolution.via === "root" ? "installed" : resolution.via === "cache" ? "cached path" : "found by Spotlight"})`;
|
|
48
|
+
case "missing":
|
|
49
|
+
return BRIDGE_GONE_MESSAGE;
|
|
50
|
+
case "no-stub":
|
|
51
|
+
return `${resolution.stub} is not there; ${BRIDGE_GONE_MESSAGE}`;
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
var isBridgeLocator = (executable) => executable !== null && executable.split(/[/\\]/).pop() === HOOK_LOCATOR_BINARY;
|
|
55
|
+
var spotlight = (bundleIdentifier) => {
|
|
56
|
+
if (process.platform !== "darwin") return [];
|
|
57
|
+
try {
|
|
58
|
+
return execFileSync("/usr/bin/mdfind", [`kMDItemCFBundleIdentifier == "${bundleIdentifier}"`], {
|
|
59
|
+
encoding: "utf-8",
|
|
60
|
+
timeout: 5e3,
|
|
61
|
+
stdio: ["ignore", "pipe", "ignore"]
|
|
62
|
+
}).split("\n").map((line) => line.trim()).filter((line) => line !== "");
|
|
63
|
+
} catch {
|
|
64
|
+
return [];
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
var readOrNull = (path) => {
|
|
68
|
+
try {
|
|
69
|
+
return readFileSync(path, "utf-8");
|
|
70
|
+
} catch {
|
|
71
|
+
return null;
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
var liveBridgeProbe = () => ({
|
|
75
|
+
exists: existsSync,
|
|
76
|
+
readFile: readOrNull,
|
|
77
|
+
mdfind: spotlight,
|
|
78
|
+
home: homedir()
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
// src/diagnostics/service-runtime.ts
|
|
82
|
+
var unescapeXml = (value) => value.replaceAll(""", '"').replaceAll("'", "'").replaceAll("<", "<").replaceAll(">", ">").replaceAll("&", "&");
|
|
83
|
+
var unquoteSystemd = (value) => value.replaceAll('\\"', '"').replaceAll("\\\\", "\\").replaceAll("%%", "%");
|
|
84
|
+
var readServiceExecPath = (contents, platform) => {
|
|
85
|
+
if (platform === "darwin") {
|
|
86
|
+
const program = contents.match(/<key>ProgramArguments<\/key>\s*<array>\s*<string>([^<]*)<\/string>/)?.[1];
|
|
87
|
+
return program ? unescapeXml(program) : null;
|
|
88
|
+
}
|
|
89
|
+
if (platform === "linux") {
|
|
90
|
+
const exec = contents.match(/^ExecStart="((?:[^"\\]|\\.)*)"/m)?.[1];
|
|
91
|
+
return exec ? unquoteSystemd(exec) : null;
|
|
92
|
+
}
|
|
93
|
+
if (platform === "win32") {
|
|
94
|
+
const command = contents.match(/<Command>([^<]*)<\/Command>/)?.[1];
|
|
95
|
+
return command ? unescapeXml(command) : null;
|
|
96
|
+
}
|
|
97
|
+
return null;
|
|
98
|
+
};
|
|
99
|
+
var MANAGER_SEGMENTS = [
|
|
100
|
+
[".nvm", "nvm"],
|
|
101
|
+
["nvm", "nvm"],
|
|
102
|
+
["fnm", "fnm"],
|
|
103
|
+
[".fnm", "fnm"],
|
|
104
|
+
[".volta", "volta"],
|
|
105
|
+
["volta", "volta"],
|
|
106
|
+
[".asdf", "asdf"],
|
|
107
|
+
["asdf", "asdf"]
|
|
108
|
+
];
|
|
109
|
+
var versionManagerOf = (execPath) => {
|
|
110
|
+
const segments = execPath.split(/[/\\]/);
|
|
111
|
+
for (const segment of segments) {
|
|
112
|
+
const hit = MANAGER_SEGMENTS.find(([name]) => name === segment);
|
|
113
|
+
if (hit) return hit[1];
|
|
114
|
+
}
|
|
115
|
+
return null;
|
|
116
|
+
};
|
|
117
|
+
var describeVersionManagerPin = (execPath, manager) => `The background service is pinned to ${execPath}, which ${manager} manages. Switching Node versions strands it; run pushary daemon install afterwards.`;
|
|
118
|
+
|
|
119
|
+
export {
|
|
120
|
+
resolveBridgeStub,
|
|
121
|
+
describeBridgeResolution,
|
|
122
|
+
isBridgeLocator,
|
|
123
|
+
liveBridgeProbe,
|
|
124
|
+
readServiceExecPath,
|
|
125
|
+
versionManagerOf,
|
|
126
|
+
describeVersionManagerPin
|
|
127
|
+
};
|
|
@@ -4,6 +4,7 @@ import {
|
|
|
4
4
|
isDefaultSession,
|
|
5
5
|
isPolicyConfig,
|
|
6
6
|
listPendingQuestions,
|
|
7
|
+
listPendingQuestionsForToolUse,
|
|
7
8
|
markPendingCommandDelivered,
|
|
8
9
|
readPendingCommand,
|
|
9
10
|
removePendingCommand,
|
|
@@ -12,9 +13,10 @@ import {
|
|
|
12
13
|
savePendingCommand,
|
|
13
14
|
sendNotification,
|
|
14
15
|
waitForAnswer
|
|
15
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-FXEVRLHC.js";
|
|
16
17
|
import {
|
|
17
18
|
AGENT_IDENTITIES,
|
|
19
|
+
compactionAction,
|
|
18
20
|
deriveReceiptMeta,
|
|
19
21
|
deriveToolTarget,
|
|
20
22
|
describeToolCall,
|
|
@@ -22,20 +24,22 @@ import {
|
|
|
22
24
|
parseApplyPatchFiles,
|
|
23
25
|
parseApplyPatchOps,
|
|
24
26
|
sessionEndAction,
|
|
27
|
+
sessionIdentityOf,
|
|
25
28
|
sessionStartAction,
|
|
29
|
+
subagentStopSummary,
|
|
26
30
|
summarizeStop,
|
|
27
31
|
taskTitleFrom,
|
|
28
32
|
toolResultErrorText
|
|
29
|
-
} from "./chunk-
|
|
33
|
+
} from "./chunk-L4E2BIJ2.js";
|
|
30
34
|
import {
|
|
31
35
|
getMachineId
|
|
32
|
-
} from "./chunk-
|
|
36
|
+
} from "./chunk-54ELC7D7.js";
|
|
33
37
|
import {
|
|
34
38
|
withRetry
|
|
35
39
|
} from "./chunk-BSZYIAZL.js";
|
|
36
40
|
import {
|
|
37
41
|
reportedInstallSource
|
|
38
|
-
} from "./chunk-
|
|
42
|
+
} from "./chunk-JW4KO5AF.js";
|
|
39
43
|
import {
|
|
40
44
|
getApiKey,
|
|
41
45
|
getBaseUrl
|
|
@@ -51,7 +55,7 @@ import {
|
|
|
51
55
|
pendingCommandEvents,
|
|
52
56
|
resolveAutoResolveOrigin,
|
|
53
57
|
resolvePolicy
|
|
54
|
-
} from "./chunk-
|
|
58
|
+
} from "./chunk-VNMKIJZB.js";
|
|
55
59
|
|
|
56
60
|
// src/policy.ts
|
|
57
61
|
import { createHash } from "crypto";
|
|
@@ -505,6 +509,15 @@ var permissionTimeoutDecision = (timeoutAction) => {
|
|
|
505
509
|
};
|
|
506
510
|
var preToolUseTimeoutDecision = (timeoutAction, denyReason = "No response within timeout") => timeoutAction === "deny" ? codexDeny(denyReason) : codexPass();
|
|
507
511
|
|
|
512
|
+
// src/driver.ts
|
|
513
|
+
var DRIVER_ENV = "PUSHARY_DRIVER";
|
|
514
|
+
var PHONE_DRIVER = "phone";
|
|
515
|
+
var driverFromEnv = (env) => env[DRIVER_ENV] === PHONE_DRIVER ? PHONE_DRIVER : void 0;
|
|
516
|
+
var phoneDrivenEnv = (base) => ({
|
|
517
|
+
...base,
|
|
518
|
+
[DRIVER_ENV]: PHONE_DRIVER
|
|
519
|
+
});
|
|
520
|
+
|
|
508
521
|
// src/throttle.ts
|
|
509
522
|
import { join as join4 } from "path";
|
|
510
523
|
import { tmpdir as tmpdir3 } from "os";
|
|
@@ -552,10 +565,13 @@ var readLastPrompt = (sessionId) => {
|
|
|
552
565
|
return void 0;
|
|
553
566
|
}
|
|
554
567
|
};
|
|
555
|
-
var
|
|
568
|
+
var pendingQuestionsToSettle = (sessionId, toolUseId) => {
|
|
569
|
+
const settledElsewhere = toolUseId ? listPendingQuestionsForToolUse(sessionId, toolUseId) : [];
|
|
570
|
+
return [.../* @__PURE__ */ new Set([...settledElsewhere, ...listPendingQuestions(sessionId)])];
|
|
571
|
+
};
|
|
572
|
+
var reconcileQuestions = async (sessionId, files) => {
|
|
556
573
|
const late = [];
|
|
557
574
|
try {
|
|
558
|
-
const files = listPendingQuestions(sessionId);
|
|
559
575
|
if (files.length === 0) return late;
|
|
560
576
|
const apiKey = getApiKey();
|
|
561
577
|
for (const correlationId of files) {
|
|
@@ -576,6 +592,7 @@ var reconcilePendingQuestions = async (sessionId) => {
|
|
|
576
592
|
}
|
|
577
593
|
return late;
|
|
578
594
|
};
|
|
595
|
+
var reconcilePendingQuestions = (sessionId, toolUseId) => reconcileQuestions(sessionId, pendingQuestionsToSettle(sessionId, toolUseId));
|
|
579
596
|
var describeLateAnswer = (value) => {
|
|
580
597
|
const v = (value ?? "").trim();
|
|
581
598
|
if (v === "yes") return "approved it";
|
|
@@ -724,6 +741,7 @@ var reportEvent = async (event, options = {}) => {
|
|
|
724
741
|
// Link-back for a phone-spawned session: forward the spawn id the daemon
|
|
725
742
|
// set in the environment so the server can map spawnId -> sessionId.
|
|
726
743
|
...process.env.PUSHARY_SPAWN_ID ? { spawnId: process.env.PUSHARY_SPAWN_ID } : {},
|
|
744
|
+
...driverFromEnv(process.env) ? { driver: driverFromEnv(process.env) } : {},
|
|
727
745
|
canDrainCommand: clientCanDrain && !storedCommand,
|
|
728
746
|
ackMode: clientCanDrain && !storedCommand,
|
|
729
747
|
skipCommandDrain: storedCommand != null
|
|
@@ -780,6 +798,11 @@ var reportEvent = async (event, options = {}) => {
|
|
|
780
798
|
}, { maxAttempts: options.maxAttempts ?? 2, baseDelayMs: 300 });
|
|
781
799
|
};
|
|
782
800
|
var NON_GATED_MIRROR_TOOLS = /* @__PURE__ */ new Set(["TodoWrite"]);
|
|
801
|
+
var settleQuestionsForToolUse = async (sessionId, toolUseId) => {
|
|
802
|
+
if (!toolUseId) return;
|
|
803
|
+
const late = await reconcileQuestions(sessionId, listPendingQuestionsForToolUse(sessionId, toolUseId));
|
|
804
|
+
for (const answer of late) removePendingQuestion(sessionId, answer.correlationId);
|
|
805
|
+
};
|
|
783
806
|
var handlePostToolUse = async (input, agent = CLAUDE_CODE_AGENT) => {
|
|
784
807
|
try {
|
|
785
808
|
const projectName = basename2(input.cwd ?? process.cwd());
|
|
@@ -790,7 +813,7 @@ var handlePostToolUse = async (input, agent = CLAUDE_CODE_AGENT) => {
|
|
|
790
813
|
const receiptsEnabled = process.env.PUSHARY_RECEIPTS !== "off";
|
|
791
814
|
const sessionKey = input.session_id || DEFAULT_SESSION;
|
|
792
815
|
const liveMode = await fetchModeState(getApiKey(), input.session_id, MODE_REUSE_MS);
|
|
793
|
-
const late = await reconcilePendingQuestions(sessionKey);
|
|
816
|
+
const late = await reconcilePendingQuestions(sessionKey, input.tool_use_id);
|
|
794
817
|
let additionalContext;
|
|
795
818
|
if (late.length > 0 && agent.type === CLAUDE_CODE_AGENT.type) {
|
|
796
819
|
additionalContext = buildLateAnswerContext(late);
|
|
@@ -875,7 +898,7 @@ var handleStop = async (input, agent = CLAUDE_CODE_AGENT) => {
|
|
|
875
898
|
agentType: agent.type,
|
|
876
899
|
agentName: `${agent.label} - ${projectName}`,
|
|
877
900
|
action: summarizeStop(input),
|
|
878
|
-
|
|
901
|
+
...sessionIdentityOf(input),
|
|
879
902
|
usage: deriveUsage(input.transcript_path, input.session_id)
|
|
880
903
|
}, { maxAttempts: 1 })
|
|
881
904
|
];
|
|
@@ -897,16 +920,46 @@ var handleStop = async (input, agent = CLAUDE_CODE_AGENT) => {
|
|
|
897
920
|
return void 0;
|
|
898
921
|
}
|
|
899
922
|
};
|
|
923
|
+
var isSubagentStop = (input) => input.hook_event_name === "SubagentStop" || typeof input.agent_id === "string" && input.agent_id.length > 0;
|
|
924
|
+
var SUBAGENT_STOP_REPORT_TIMEOUT_MS = 4e3;
|
|
925
|
+
var handleSubagentStop = async (input, agent = CLAUDE_CODE_AGENT) => {
|
|
926
|
+
try {
|
|
927
|
+
const projectName = basename2(input.cwd ?? process.cwd());
|
|
928
|
+
await reportEvent({
|
|
929
|
+
event: "session_end",
|
|
930
|
+
agentType: agent.type,
|
|
931
|
+
agentName: `${agent.label} - ${projectName}`,
|
|
932
|
+
action: subagentStopSummary(input),
|
|
933
|
+
...sessionIdentityOf(input)
|
|
934
|
+
}, { maxAttempts: 1, timeoutMs: SUBAGENT_STOP_REPORT_TIMEOUT_MS });
|
|
935
|
+
} catch {
|
|
936
|
+
}
|
|
937
|
+
};
|
|
938
|
+
var isCompactionEvent = (hookEventName) => hookEventName === "PreCompact" || hookEventName === "PostCompact";
|
|
939
|
+
var COMPACTION_REPORT_TIMEOUT_MS = 4e3;
|
|
940
|
+
var handleCompaction = async (input, agent = CLAUDE_CODE_AGENT) => {
|
|
941
|
+
try {
|
|
942
|
+
const projectName = basename2(input.cwd ?? process.cwd());
|
|
943
|
+
await reportEvent({
|
|
944
|
+
event: "compaction",
|
|
945
|
+
agentType: agent.type,
|
|
946
|
+
agentName: `${agent.label} - ${projectName}`,
|
|
947
|
+
action: compactionAction(input.hook_event_name, input.trigger),
|
|
948
|
+
sessionId: input.session_id
|
|
949
|
+
}, { maxAttempts: 1, timeoutMs: COMPACTION_REPORT_TIMEOUT_MS });
|
|
950
|
+
} catch {
|
|
951
|
+
}
|
|
952
|
+
};
|
|
900
953
|
var handleSessionStart = async (input, agent = CLAUDE_CODE_AGENT) => {
|
|
901
954
|
try {
|
|
902
955
|
const projectName = basename2(input.cwd ?? process.cwd());
|
|
903
|
-
const action = sessionStartAction(input.source);
|
|
956
|
+
const action = input.agent_id ? "Subagent started" : sessionStartAction(input.source);
|
|
904
957
|
await reportEvent({
|
|
905
958
|
event: "session_start",
|
|
906
959
|
agentType: agent.type,
|
|
907
960
|
agentName: `${agent.label} - ${projectName}`,
|
|
908
961
|
action,
|
|
909
|
-
|
|
962
|
+
...sessionIdentityOf(input)
|
|
910
963
|
}, { maxAttempts: 2, timeoutMs: 4e3 });
|
|
911
964
|
} catch {
|
|
912
965
|
}
|
|
@@ -1033,6 +1086,7 @@ export {
|
|
|
1033
1086
|
getPolicy,
|
|
1034
1087
|
fetchModeState,
|
|
1035
1088
|
fetchModeOverride,
|
|
1089
|
+
phoneDrivenEnv,
|
|
1036
1090
|
repoKeyFor,
|
|
1037
1091
|
throttlePass,
|
|
1038
1092
|
readLastUserPrompt,
|
|
@@ -1048,9 +1102,14 @@ export {
|
|
|
1048
1102
|
preToolUseTimeoutDecision,
|
|
1049
1103
|
readLastPrompt,
|
|
1050
1104
|
reportEvent,
|
|
1105
|
+
settleQuestionsForToolUse,
|
|
1051
1106
|
handlePostToolUse,
|
|
1052
1107
|
handleUserPrompt,
|
|
1053
1108
|
handleStop,
|
|
1109
|
+
isSubagentStop,
|
|
1110
|
+
handleSubagentStop,
|
|
1111
|
+
isCompactionEvent,
|
|
1112
|
+
handleCompaction,
|
|
1054
1113
|
handleSessionStart,
|
|
1055
1114
|
handleSessionEnd,
|
|
1056
1115
|
handleNotification,
|