@pushary/agent-hooks 0.89.13 → 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 +60 -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 +72 -21
- package/dist/bin/pushary-clean.js +16 -42
- 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.js +6 -6
- package/dist/bin/pushary-upgrade.js +15 -15
- package/dist/bin/pushary-wait.js +5 -5
- package/dist/bin/pushary.js +1 -1
- package/dist/{chunk-B2HND22S.js → chunk-2LAHXHBR.js} +1 -1
- package/dist/{chunk-GMJDQDXU.js → chunk-43GMYSS4.js} +1 -0
- package/dist/{chunk-JTBDBKHU.js → chunk-54ELC7D7.js} +1 -1
- package/dist/{chunk-C56VHSXU.js → chunk-5NAZ7SFS.js} +1 -1
- package/dist/{chunk-4IPSMEGT.js → chunk-7FE2KABY.js} +12 -2
- package/dist/{chunk-RAEPAUNJ.js → chunk-7TPQEWUZ.js} +1 -1
- package/dist/{chunk-ZO43JTT3.js → chunk-AJYV3VGU.js} +1 -1
- package/dist/{chunk-QFJZHVVL.js → chunk-AZPIQG4G.js} +35 -1
- package/dist/{chunk-5MNTWAAJ.js → chunk-B7UZHEBL.js} +29 -22
- package/dist/{chunk-MNTZKFZI.js → chunk-BQBEH6TV.js} +5 -5
- package/dist/{chunk-WHDSJ6PD.js → chunk-BVBEURWJ.js} +1 -1
- package/dist/{chunk-ZWEKONU6.js → chunk-CELX75MW.js} +1 -1
- package/dist/{chunk-ZP3SNUP7.js → chunk-CNPAT3HL.js} +3 -2
- package/dist/{chunk-YXT55PYF.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-7JZCADBR.js → chunk-F2ICEWZL.js} +101 -19
- package/dist/{chunk-VASZ6TWW.js → chunk-FQL5E6NG.js} +2 -2
- package/dist/{chunk-JHJHCMAF.js → chunk-FXEVRLHC.js} +20 -2
- package/dist/{chunk-JVLB5CAJ.js → chunk-GL3FFM7A.js} +7 -4
- package/dist/{chunk-5YEF55AX.js → chunk-H2QZRQR2.js} +1 -1
- package/dist/{chunk-S4BLNILH.js → chunk-I463AEG3.js} +1 -1
- package/dist/{chunk-ANMHIZZY.js → chunk-JW4KO5AF.js} +1 -1
- package/dist/{chunk-3YGGEDJK.js → chunk-KUZWXPUS.js} +3 -2
- package/dist/{chunk-N4QJ3CLX.js → chunk-L4E2BIJ2.js} +80 -7
- package/dist/{chunk-NBDU3R3G.js → chunk-OSALSIUF.js} +1 -1
- package/dist/{chunk-KNLKHJZR.js → chunk-PYA4FLKI.js} +32 -21
- package/dist/chunk-QCGNGEGE.js +15 -0
- package/dist/chunk-S6LYP7QA.js +127 -0
- package/dist/{chunk-OX35BSPV.js → chunk-TDZFPMSZ.js} +70 -11
- package/dist/{chunk-M3UABYRT.js → chunk-UZNKVRLE.js} +1 -1
- package/dist/{chunk-FOGW6O2Y.js → chunk-VHWCVD42.js} +1 -1
- package/dist/{chunk-QINYXLA5.js → chunk-VNMKIJZB.js} +15 -2
- package/dist/{chunk-CBGGUEKE.js → chunk-Y6BWPERV.js} +90 -7
- package/dist/src/index.d.ts +3 -0
- package/dist/src/index.js +11 -11
- package/package.json +1 -1
- package/dist/chunk-MSTHT2M7.js +0 -72
|
@@ -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,
|
|
@@ -91,7 +91,7 @@ var INSTALL_SOURCES = [
|
|
|
91
91
|
var isInstallSource = (value) => typeof value === "string" && INSTALL_SOURCES.includes(value);
|
|
92
92
|
var normalizeInstallSource = (value) => isInstallSource(value) ? value : "unknown";
|
|
93
93
|
var HOOK_BUDGETS = {
|
|
94
|
-
claude: { budgetSeconds:
|
|
94
|
+
claude: { budgetSeconds: 600, guardSeconds: 10 },
|
|
95
95
|
codex: { budgetSeconds: 180, guardSeconds: 10 },
|
|
96
96
|
gemini: { budgetSeconds: 180, guardSeconds: 10 },
|
|
97
97
|
// The Cursor gate is a dependency-free .mjs that cannot import this module; it
|
|
@@ -1054,6 +1054,8 @@ var resolvePolicyAcross = (config, toolName, modeOverride, toolInputs, cwd, repo
|
|
|
1054
1054
|
};
|
|
1055
1055
|
var isModeStateDegraded = (state) => state?.degraded === true;
|
|
1056
1056
|
var KILL_REASON = "Stopped by user, this agent was halted from Pushary";
|
|
1057
|
+
var PUSHARY_TOOL_PREFIX = "mcp__pushary__";
|
|
1058
|
+
var isPusharyOwnTool = (toolName) => toolName.startsWith(PUSHARY_TOOL_PREFIX);
|
|
1057
1059
|
var strictestScopeVerdict = (scope, paths) => {
|
|
1058
1060
|
if (paths.length === 0) return evaluateScope(scope, void 0);
|
|
1059
1061
|
let worst = { outcome: "in_scope" };
|
|
@@ -1085,6 +1087,13 @@ var ASKED_IN_EVERY_MODE = new Set(ASKED_IN_EVERY_MODE_TOOLS);
|
|
|
1085
1087
|
var isAskedInEveryMode = (toolName) => ASKED_IN_EVERY_MODE.has(toolName);
|
|
1086
1088
|
var resolveGate = (input) => {
|
|
1087
1089
|
const { modeState, config, toolName, toolInputs, cwd, repoKey, sessionId } = input;
|
|
1090
|
+
if (isPusharyOwnTool(toolName)) {
|
|
1091
|
+
return {
|
|
1092
|
+
kind: "defer",
|
|
1093
|
+
policy: resolvePolicyAcross(config, toolName, modeState.mode, toolInputs, cwd, repoKey, sessionId),
|
|
1094
|
+
reason: "own_tool"
|
|
1095
|
+
};
|
|
1096
|
+
}
|
|
1088
1097
|
if (modeState.kill) return { kind: "kill", reason: KILL_REASON };
|
|
1089
1098
|
const policy = resolvePolicyAcross(config, toolName, modeState.mode, toolInputs, cwd, repoKey, sessionId);
|
|
1090
1099
|
const verdict = verdictForPolicy(policy);
|
|
@@ -1128,9 +1137,11 @@ var modeStateFromResponse = (data) => {
|
|
|
1128
1137
|
// Validated rather than cast: a malformed contract must read as no contract,
|
|
1129
1138
|
// never as one that silently matches nothing.
|
|
1130
1139
|
scope: isScopeContract(data.scope) ? data.scope : null,
|
|
1131
|
-
degraded: false
|
|
1140
|
+
degraded: false,
|
|
1141
|
+
askHandoff: data.askHandoff === true
|
|
1132
1142
|
};
|
|
1133
1143
|
};
|
|
1144
|
+
var stoppedOutput = (output, stopReason) => ({ ...output, continue: false, stopReason });
|
|
1134
1145
|
var claudePreToolUseOutput = (decision, reason, updatedInput) => ({
|
|
1135
1146
|
hookSpecificOutput: {
|
|
1136
1147
|
hookEventName: "PreToolUse",
|
|
@@ -1362,10 +1373,12 @@ export {
|
|
|
1362
1373
|
resolveAutoResolveOrigin,
|
|
1363
1374
|
resolvePolicy,
|
|
1364
1375
|
KILL_REASON,
|
|
1376
|
+
isPusharyOwnTool,
|
|
1365
1377
|
shouldDeferToNativeMode,
|
|
1366
1378
|
ASKED_IN_EVERY_MODE_TOOLS,
|
|
1367
1379
|
resolveGate,
|
|
1368
1380
|
modeStateFromResponse,
|
|
1381
|
+
stoppedOutput,
|
|
1369
1382
|
claudePreToolUseOutput,
|
|
1370
1383
|
PENDING_COMMAND_PREFIX,
|
|
1371
1384
|
pendingCommandEvents,
|