@pushary/agent-hooks 0.83.2 → 0.84.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 +75 -0
- package/dist/bin/pushary-bell-hook.js +5 -5
- package/dist/bin/pushary-bell.js +15 -14
- package/dist/bin/pushary-claude.js +72 -131
- package/dist/bin/pushary-clean.js +13 -12
- package/dist/bin/pushary-codex-bridge.d.ts +1 -0
- package/dist/bin/pushary-codex-bridge.js +348 -0
- package/dist/bin/pushary-codex-hook.js +15 -14
- package/dist/bin/pushary-codex.js +7 -7
- package/dist/bin/pushary-connect.js +13 -12
- package/dist/bin/pushary-daemon.js +313 -41
- package/dist/bin/pushary-doctor.js +48 -25
- package/dist/bin/pushary-gemini-bridge.d.ts +1 -0
- package/dist/bin/pushary-gemini-bridge.js +298 -0
- package/dist/bin/pushary-gemini-hook.js +24 -20
- package/dist/bin/pushary-hook.js +14 -13
- package/dist/bin/pushary-login.js +15 -14
- package/dist/bin/pushary-logout.js +12 -11
- package/dist/bin/pushary-mode.js +10 -9
- package/dist/bin/pushary-notification-hook.js +5 -5
- package/dist/bin/pushary-permission-denied-hook.js +9 -9
- package/dist/bin/pushary-permission-hook.js +9 -9
- package/dist/bin/pushary-post-hook.js +5 -5
- package/dist/bin/pushary-prompt-hook.js +5 -5
- package/dist/bin/pushary-session-end-hook.js +5 -5
- package/dist/bin/pushary-session-start-hook.js +5 -5
- package/dist/bin/pushary-setup.js +42 -36
- package/dist/bin/pushary-stats.js +6 -5
- package/dist/bin/pushary-status.js +17 -16
- package/dist/bin/pushary-stop-hook.js +5 -5
- package/dist/bin/pushary-stopfailure-hook.js +5 -5
- package/dist/bin/pushary-suggestions.js +7 -6
- package/dist/bin/pushary-upgrade.js +18 -17
- package/dist/bin/pushary-wait.js +10 -9
- package/dist/bin/pushary.js +8 -6
- package/dist/{chunk-4QQOKEOS.js → chunk-37AD5K7W.js} +6 -6
- package/dist/{chunk-SAA3VBDK.js → chunk-437T77TY.js} +3 -3
- package/dist/{chunk-U27BZWFT.js → chunk-6LC4WSCL.js} +1 -1
- package/dist/{chunk-7WWZPII5.js → chunk-7PZPJSWI.js} +1 -1
- package/dist/chunk-CCH775Y6.js +343 -0
- package/dist/chunk-DINDL2CF.js +45 -0
- package/dist/{chunk-TXF4QZSQ.js → chunk-DOXSWT4Q.js} +1 -1
- package/dist/chunk-EVJ6ULHN.js +153 -0
- package/dist/{chunk-QR6MVVQ7.js → chunk-F52SIIDG.js} +4 -4
- package/dist/{chunk-26D2YMDU.js → chunk-FBGBJXVC.js} +1 -1
- package/dist/{chunk-QF7WTF2C.js → chunk-HZNOAJGB.js} +2 -2
- package/dist/{chunk-RRZZ7TFJ.js → chunk-J4KFVOCQ.js} +4 -2
- package/dist/{chunk-WDRRULBH.js → chunk-K7CSRGKZ.js} +4 -4
- package/dist/{chunk-ZUKH2NPJ.js → chunk-MGJBC6DD.js} +1 -44
- package/dist/{chunk-GQLB2GBJ.js → chunk-MHBC2XUP.js} +1 -1
- package/dist/{chunk-YWRJGYUH.js → chunk-MQMPG5X4.js} +28 -2
- package/dist/{chunk-3AGM3TDM.js → chunk-NJ7JT26G.js} +1 -1
- package/dist/chunk-NRGRUOAR.js +25 -0
- package/dist/chunk-NWYGW7HY.js +117 -0
- package/dist/{chunk-7PO2VEA4.js → chunk-OPMSMF5R.js} +38 -33
- package/dist/{chunk-DHAZ6SOT.js → chunk-QNBA5OXQ.js} +81 -25
- package/dist/{chunk-EHLTWCDZ.js → chunk-SEAHGHCE.js} +1 -1
- package/dist/{chunk-NDC3TBHI.js → chunk-UKSQWTBH.js} +1 -1
- package/dist/{chunk-UVAC2KHH.js → chunk-UXWEE3QI.js} +1 -1
- package/dist/{chunk-MUEW424A.js → chunk-VT4IVERX.js} +50 -3
- package/dist/chunk-YJCMI5GF.js +133 -0
- package/dist/src/index.d.ts +6 -3
- package/dist/src/index.js +9 -9
- package/package.json +3 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// src/npm.ts
|
|
2
|
-
import { execSync } from "child_process";
|
|
3
|
-
import { existsSync } from "fs";
|
|
4
|
-
import { join } from "path";
|
|
2
|
+
import { execFileSync, execSync } from "child_process";
|
|
3
|
+
import { existsSync, readFileSync, realpathSync } from "fs";
|
|
4
|
+
import { dirname, join } from "path";
|
|
5
5
|
var cleanNpmEnv = () => {
|
|
6
6
|
const env = {};
|
|
7
7
|
for (const [key, value] of Object.entries(process.env)) {
|
|
@@ -33,6 +33,50 @@ var resolveGlobalBinary = (name) => {
|
|
|
33
33
|
return void 0;
|
|
34
34
|
}
|
|
35
35
|
};
|
|
36
|
+
var resolvePathBinary = (name, platform = process.platform) => {
|
|
37
|
+
try {
|
|
38
|
+
return execFileSync(platform === "win32" ? "where" : "which", [name], {
|
|
39
|
+
encoding: "utf8",
|
|
40
|
+
stdio: "pipe",
|
|
41
|
+
timeout: 5e3
|
|
42
|
+
}).split(/\r?\n/, 1)[0]?.trim() || void 0;
|
|
43
|
+
} catch {
|
|
44
|
+
return void 0;
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
var resolveBinary = (name) => resolveGlobalBinary(name) ?? resolvePathBinary(name);
|
|
48
|
+
var resolvePackageVersionFromBinary = (binary, packageName) => {
|
|
49
|
+
try {
|
|
50
|
+
let dir = dirname(realpathSync(binary));
|
|
51
|
+
const packagePath = packageName.split("/");
|
|
52
|
+
for (let depth = 0; depth < 8; depth++) {
|
|
53
|
+
for (const manifest of [
|
|
54
|
+
join(dir, "package.json"),
|
|
55
|
+
join(dir, "node_modules", ...packagePath, "package.json")
|
|
56
|
+
]) {
|
|
57
|
+
try {
|
|
58
|
+
const value = JSON.parse(readFileSync(manifest, "utf8"));
|
|
59
|
+
if (value.name === packageName && typeof value.version === "string") return value.version;
|
|
60
|
+
} catch {
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
const parent = dirname(dir);
|
|
64
|
+
if (parent === dir) break;
|
|
65
|
+
dir = parent;
|
|
66
|
+
}
|
|
67
|
+
} catch {
|
|
68
|
+
}
|
|
69
|
+
return void 0;
|
|
70
|
+
};
|
|
71
|
+
var resolveGlobalPackageVersion = (name) => {
|
|
72
|
+
try {
|
|
73
|
+
const result = JSON.parse(execNpm("list -g --depth=0 --json --no-workspaces", { timeout: 5e3 }).toString());
|
|
74
|
+
const value = result.dependencies?.[name]?.version;
|
|
75
|
+
return typeof value === "string" ? value : void 0;
|
|
76
|
+
} catch {
|
|
77
|
+
return void 0;
|
|
78
|
+
}
|
|
79
|
+
};
|
|
36
80
|
var resolveGlobalBinDir = (probe) => {
|
|
37
81
|
if (process.platform === "win32") return void 0;
|
|
38
82
|
const resolved = resolveGlobalBinary(probe);
|
|
@@ -61,6 +105,9 @@ export {
|
|
|
61
105
|
npmErrorMessage,
|
|
62
106
|
execNpm,
|
|
63
107
|
resolveGlobalBinary,
|
|
108
|
+
resolveBinary,
|
|
109
|
+
resolvePackageVersionFromBinary,
|
|
110
|
+
resolveGlobalPackageVersion,
|
|
64
111
|
resolveGlobalBinDir,
|
|
65
112
|
quoteIfNeeded,
|
|
66
113
|
installGlobally
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import {
|
|
2
|
+
buildTranscriptRecords,
|
|
3
|
+
decodePublicKey,
|
|
4
|
+
fetchAccountPublicKey,
|
|
5
|
+
generateSessionKey,
|
|
6
|
+
uploadTranscriptRecords,
|
|
7
|
+
wrapSessionKey
|
|
8
|
+
} from "./chunk-NWYGW7HY.js";
|
|
9
|
+
|
|
10
|
+
// src/live-session.ts
|
|
11
|
+
var MAX_TRANSCRIPT_QUEUE = 100;
|
|
12
|
+
var MAX_TRANSCRIPT_TEXT = 32 * 1024;
|
|
13
|
+
var LIVE_SESSION_HEARTBEAT_MS = 6e4;
|
|
14
|
+
var liveSessionSleep = (ms, signal) => new Promise((resolve) => {
|
|
15
|
+
if (signal.aborted) return resolve();
|
|
16
|
+
const timer = setTimeout(done, ms);
|
|
17
|
+
function done() {
|
|
18
|
+
clearTimeout(timer);
|
|
19
|
+
signal.removeEventListener("abort", done);
|
|
20
|
+
resolve();
|
|
21
|
+
}
|
|
22
|
+
signal.addEventListener("abort", done, { once: true });
|
|
23
|
+
});
|
|
24
|
+
var postLiveSession = (options, path, body) => {
|
|
25
|
+
const controller = new AbortController();
|
|
26
|
+
const abort = () => controller.abort();
|
|
27
|
+
const timeout = setTimeout(abort, options.requestTimeoutMs ?? 1e4);
|
|
28
|
+
if (options.signal.aborted) abort();
|
|
29
|
+
else options.signal.addEventListener("abort", abort, { once: true });
|
|
30
|
+
return fetch(`${options.baseUrl}${path}`, {
|
|
31
|
+
method: "POST",
|
|
32
|
+
headers: { Authorization: `Bearer ${options.apiKey}`, "Content-Type": "application/json" },
|
|
33
|
+
body: JSON.stringify(body),
|
|
34
|
+
signal: controller.signal
|
|
35
|
+
}).finally(() => {
|
|
36
|
+
clearTimeout(timeout);
|
|
37
|
+
options.signal.removeEventListener("abort", abort);
|
|
38
|
+
});
|
|
39
|
+
};
|
|
40
|
+
var postLiveSessionUntilAccepted = async (options, path, body) => {
|
|
41
|
+
while (!options.signal.aborted) {
|
|
42
|
+
try {
|
|
43
|
+
const response = await postLiveSession(options, path, body);
|
|
44
|
+
if (response.ok) return;
|
|
45
|
+
if (response.status < 500 && response.status !== 429) {
|
|
46
|
+
throw new Error(`${path} rejected (${response.status})`);
|
|
47
|
+
}
|
|
48
|
+
} catch (error) {
|
|
49
|
+
if (options.signal.aborted) throw error;
|
|
50
|
+
if (error instanceof Error && error.message.startsWith(`${path} rejected`)) throw error;
|
|
51
|
+
}
|
|
52
|
+
await liveSessionSleep(options.pollIntervalMs ?? 2e3, options.signal);
|
|
53
|
+
}
|
|
54
|
+
throw new Error("Live session stopped before it linked");
|
|
55
|
+
};
|
|
56
|
+
var startLiveSessionHeartbeat = (options, body, intervalMs = LIVE_SESSION_HEARTBEAT_MS) => {
|
|
57
|
+
const timer = setInterval(() => {
|
|
58
|
+
if (!options.signal.aborted) {
|
|
59
|
+
void postLiveSession(options, "/api/agent/event", body).catch(() => {
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
}, intervalMs);
|
|
63
|
+
timer.unref();
|
|
64
|
+
return () => clearInterval(timer);
|
|
65
|
+
};
|
|
66
|
+
var LiveTranscriptRelay = class {
|
|
67
|
+
constructor(options, sessionId) {
|
|
68
|
+
this.options = options;
|
|
69
|
+
this.sessionId = sessionId;
|
|
70
|
+
}
|
|
71
|
+
queue = [];
|
|
72
|
+
sessionKey = null;
|
|
73
|
+
wrappedKey = null;
|
|
74
|
+
keyUploaded = false;
|
|
75
|
+
flushing = null;
|
|
76
|
+
add(value) {
|
|
77
|
+
const raw = JSON.stringify(value);
|
|
78
|
+
if (raw.length > MAX_TRANSCRIPT_TEXT) return;
|
|
79
|
+
if (this.queue.length === MAX_TRANSCRIPT_QUEUE) this.queue.shift();
|
|
80
|
+
this.queue.push(raw);
|
|
81
|
+
void this.flush();
|
|
82
|
+
}
|
|
83
|
+
async flush() {
|
|
84
|
+
if (this.flushing) return this.flushing;
|
|
85
|
+
if (this.queue.length === 0) return;
|
|
86
|
+
this.flushing = this.drainQueue().finally(() => {
|
|
87
|
+
this.flushing = null;
|
|
88
|
+
});
|
|
89
|
+
return this.flushing;
|
|
90
|
+
}
|
|
91
|
+
async drainQueue() {
|
|
92
|
+
while (this.queue.length > 0 && await this.flushBatch()) {
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
async flushBatch() {
|
|
96
|
+
try {
|
|
97
|
+
if (!this.sessionKey) {
|
|
98
|
+
const publicKey = await fetchAccountPublicKey(this.options.apiKey, this.options.baseUrl);
|
|
99
|
+
if (!publicKey) return false;
|
|
100
|
+
this.sessionKey = generateSessionKey();
|
|
101
|
+
this.wrappedKey = wrapSessionKey(this.sessionKey, decodePublicKey(publicKey));
|
|
102
|
+
}
|
|
103
|
+
const count = Math.min(this.queue.length, 50);
|
|
104
|
+
const records = buildTranscriptRecords(this.queue.slice(0, count), this.sessionKey).records;
|
|
105
|
+
if (records.length === 0) {
|
|
106
|
+
this.queue.splice(0, count);
|
|
107
|
+
return true;
|
|
108
|
+
}
|
|
109
|
+
const uploaded = await uploadTranscriptRecords(this.options.apiKey, {
|
|
110
|
+
sessionId: this.sessionId,
|
|
111
|
+
machineId: this.options.machineId,
|
|
112
|
+
dataEncryptionKey: this.keyUploaded ? void 0 : this.wrappedKey ?? void 0,
|
|
113
|
+
records
|
|
114
|
+
}, this.options.baseUrl);
|
|
115
|
+
if (uploaded) {
|
|
116
|
+
this.keyUploaded = true;
|
|
117
|
+
this.queue.splice(0, count);
|
|
118
|
+
return true;
|
|
119
|
+
}
|
|
120
|
+
return false;
|
|
121
|
+
} catch {
|
|
122
|
+
return false;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
export {
|
|
128
|
+
liveSessionSleep,
|
|
129
|
+
postLiveSession,
|
|
130
|
+
postLiveSessionUntilAccepted,
|
|
131
|
+
startLiveSessionHeartbeat,
|
|
132
|
+
LiveTranscriptRelay
|
|
133
|
+
};
|
package/dist/src/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { PolicyConfig, ApprovalMode, ToolPolicy, ScopeContract } from '@pushary/contracts';
|
|
1
|
+
import { PolicyConfig, ApprovalMode, ToolPolicy, ScopeContract, AgentQuestion } from '@pushary/contracts';
|
|
2
2
|
export { ApprovalMode, PolicyConfig, ToolPolicy } from '@pushary/contracts';
|
|
3
3
|
|
|
4
4
|
interface ToolInput {
|
|
@@ -27,9 +27,9 @@ interface ReceiptMeta {
|
|
|
27
27
|
ok: boolean;
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
-
declare const getPolicy: (apiKey: string, expectedVersion?: string | null, agent?: string, repoAware?: boolean) => Promise<PolicyConfig>;
|
|
30
|
+
declare const getPolicy: (apiKey: string, expectedVersion?: string | null, agent?: string, repoAware?: boolean, sessionId?: string) => Promise<PolicyConfig>;
|
|
31
31
|
type AutoResolveOrigin = 'safe_readonly' | 'policy_timeout';
|
|
32
|
-
declare const resolvePolicy: (config: PolicyConfig, toolName: string, modeOverride?: ApprovalMode | null, toolInput?: Record<string, unknown>, cwd?: string, repoKey?: string) => ToolPolicy;
|
|
32
|
+
declare const resolvePolicy: (config: PolicyConfig, toolName: string, modeOverride?: ApprovalMode | null, toolInput?: Record<string, unknown>, cwd?: string, repoKey?: string, sessionId?: string) => ToolPolicy;
|
|
33
33
|
interface ModeState {
|
|
34
34
|
readonly mode: ApprovalMode | null;
|
|
35
35
|
readonly kill: boolean;
|
|
@@ -76,6 +76,7 @@ interface AgentEvent {
|
|
|
76
76
|
interface ReportEventOptions {
|
|
77
77
|
maxAttempts?: number;
|
|
78
78
|
timeoutMs?: number;
|
|
79
|
+
requireOk?: boolean;
|
|
79
80
|
/**
|
|
80
81
|
* Authenticate with this key instead of the ambient one.
|
|
81
82
|
*
|
|
@@ -127,12 +128,14 @@ interface AskUserParams {
|
|
|
127
128
|
question: string;
|
|
128
129
|
type?: 'confirm' | 'select' | 'input';
|
|
129
130
|
options?: string[];
|
|
131
|
+
questions?: AgentQuestion[];
|
|
130
132
|
context?: string;
|
|
131
133
|
agentName?: string;
|
|
132
134
|
sessionId?: string;
|
|
133
135
|
machineId?: string;
|
|
134
136
|
toolName?: string;
|
|
135
137
|
toolTarget?: string;
|
|
138
|
+
repoKey?: string;
|
|
136
139
|
intent?: string;
|
|
137
140
|
action?: string;
|
|
138
141
|
blocker?: string;
|
package/dist/src/index.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
2
|
handlePreToolUse
|
|
3
|
-
} from "../chunk-
|
|
4
|
-
import "../chunk-
|
|
5
|
-
import "../chunk-
|
|
6
|
-
import "../chunk-
|
|
3
|
+
} from "../chunk-QNBA5OXQ.js";
|
|
4
|
+
import "../chunk-UKSQWTBH.js";
|
|
5
|
+
import "../chunk-NJ7JT26G.js";
|
|
6
|
+
import "../chunk-37AD5K7W.js";
|
|
7
7
|
import {
|
|
8
8
|
askUser,
|
|
9
9
|
cancelQuestion,
|
|
@@ -16,18 +16,18 @@ import {
|
|
|
16
16
|
reportEvent,
|
|
17
17
|
resolvePolicy,
|
|
18
18
|
waitForAnswer
|
|
19
|
-
} from "../chunk-
|
|
19
|
+
} from "../chunk-OPMSMF5R.js";
|
|
20
|
+
import "../chunk-RN3NOEJF.js";
|
|
20
21
|
import "../chunk-BSZYIAZL.js";
|
|
21
22
|
import "../chunk-SAF6HGAA.js";
|
|
22
|
-
import "../chunk-
|
|
23
|
+
import "../chunk-437T77TY.js";
|
|
23
24
|
import "../chunk-7QLSKOSU.js";
|
|
24
|
-
import "../chunk-
|
|
25
|
-
import "../chunk-RN3NOEJF.js";
|
|
25
|
+
import "../chunk-KZERVKTD.js";
|
|
26
26
|
import {
|
|
27
27
|
getApiKey,
|
|
28
28
|
getBaseUrl
|
|
29
29
|
} from "../chunk-2UMNXADU.js";
|
|
30
|
-
import "../chunk-
|
|
30
|
+
import "../chunk-MQMPG5X4.js";
|
|
31
31
|
export {
|
|
32
32
|
askUser,
|
|
33
33
|
cancelQuestion,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pushary/agent-hooks",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.84.0",
|
|
4
4
|
"description": "Permission hooks for AI coding agents: route tool approvals through Pushary push notifications",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"pushary",
|
|
@@ -51,8 +51,10 @@
|
|
|
51
51
|
"pushary-claude": "./dist/bin/pushary-claude.js",
|
|
52
52
|
"pushary-daemon": "./dist/bin/pushary-daemon.js",
|
|
53
53
|
"pushary-codex": "./dist/bin/pushary-codex.js",
|
|
54
|
+
"pushary-codex-bridge": "./dist/bin/pushary-codex-bridge.js",
|
|
54
55
|
"pushary-codex-hook": "./dist/bin/pushary-codex-hook.js",
|
|
55
56
|
"pushary-gemini-hook": "./dist/bin/pushary-gemini-hook.js",
|
|
57
|
+
"pushary-gemini-bridge": "./dist/bin/pushary-gemini-bridge.js",
|
|
56
58
|
"pushary-setup": "./dist/bin/pushary-setup.js",
|
|
57
59
|
"pushary-clean": "./dist/bin/pushary-clean.js",
|
|
58
60
|
"pushary-status": "./dist/bin/pushary-status.js",
|