@pushary/agent-hooks 0.84.0 → 0.84.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +19 -0
- package/dist/bin/pushary-claude.js +27 -18
- package/dist/bin/pushary-codex-bridge.js +7 -6
- package/dist/bin/pushary-codex-hook.js +6 -3
- package/dist/bin/pushary-codex.js +1 -1
- package/dist/bin/pushary-daemon.js +32 -14
- package/dist/bin/pushary-gemini-bridge.js +7 -6
- package/dist/bin/pushary-gemini-hook.js +7 -4
- package/dist/bin/pushary-hook.js +3 -3
- package/dist/bin/pushary-notification-hook.js +1 -1
- package/dist/bin/pushary-permission-denied-hook.js +3 -3
- package/dist/bin/pushary-permission-hook.js +3 -3
- package/dist/bin/pushary-post-hook.js +1 -1
- package/dist/bin/pushary-prompt-hook.js +1 -1
- package/dist/bin/pushary-session-end-hook.js +1 -1
- package/dist/bin/pushary-session-start-hook.js +1 -1
- package/dist/bin/pushary-setup.js +1 -1
- package/dist/bin/pushary-stop-hook.js +1 -1
- package/dist/bin/pushary-stopfailure-hook.js +1 -1
- package/dist/{chunk-37AD5K7W.js → chunk-BLDDXHHA.js} +1 -1
- package/dist/{chunk-OPMSMF5R.js → chunk-CCCJ6BPW.js} +2 -1
- package/dist/{chunk-YJCMI5GF.js → chunk-ERYKGH4J.js} +11 -4
- package/dist/{chunk-NWYGW7HY.js → chunk-GCKAWHFP.js} +9 -2
- package/dist/{chunk-EVJ6ULHN.js → chunk-ILB6UOAF.js} +67 -28
- package/dist/{chunk-QNBA5OXQ.js → chunk-YR5TSPXB.js} +2 -2
- package/dist/src/index.js +3 -3
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,24 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.84.1
|
|
4
|
+
|
|
5
|
+
### Remote starts survive lost acknowledgements without double-launching
|
|
6
|
+
|
|
7
|
+
A phone-started agent now claims exclusive process ownership before the provider
|
|
8
|
+
starts. If the daemon restarts or the launch acknowledgement is lost, retrying the
|
|
9
|
+
same request reconnects to the existing process instead of starting a second one.
|
|
10
|
+
|
|
11
|
+
### Repository approval scopes reach Codex and Gemini
|
|
12
|
+
|
|
13
|
+
Codex and Gemini sessions now carry their repository identity through approval
|
|
14
|
+
requests, so repository-scoped rules stay inside the repository that created them.
|
|
15
|
+
|
|
16
|
+
### Encrypted transcripts retry safely
|
|
17
|
+
|
|
18
|
+
Transcript writers now retry while a session key is temporarily unavailable and
|
|
19
|
+
stop on a real key conflict, preventing undecryptable transcript entries from being
|
|
20
|
+
accepted or silently dropped.
|
|
21
|
+
|
|
3
22
|
## 0.84.0
|
|
4
23
|
|
|
5
24
|
### The phone can start an agent on a machine that is not running one
|
|
@@ -9,10 +9,11 @@ import {
|
|
|
9
9
|
generateSessionKey,
|
|
10
10
|
uploadTranscriptRecords,
|
|
11
11
|
wrapSessionKey
|
|
12
|
-
} from "../chunk-
|
|
12
|
+
} from "../chunk-GCKAWHFP.js";
|
|
13
13
|
import {
|
|
14
|
-
startProcessOwnership
|
|
15
|
-
|
|
14
|
+
startProcessOwnership,
|
|
15
|
+
withSpawnProcessOwnership
|
|
16
|
+
} from "../chunk-ILB6UOAF.js";
|
|
16
17
|
import {
|
|
17
18
|
needsShell,
|
|
18
19
|
spawnClaude
|
|
@@ -23,7 +24,7 @@ import {
|
|
|
23
24
|
KILL_REASON,
|
|
24
25
|
isDeferAnswer,
|
|
25
26
|
resolveGate
|
|
26
|
-
} from "../chunk-
|
|
27
|
+
} from "../chunk-BLDDXHHA.js";
|
|
27
28
|
import {
|
|
28
29
|
askUser,
|
|
29
30
|
cancelQuestion,
|
|
@@ -35,7 +36,7 @@ import {
|
|
|
35
36
|
reportEvent,
|
|
36
37
|
scopePathFor,
|
|
37
38
|
waitForAnswer
|
|
38
|
-
} from "../chunk-
|
|
39
|
+
} from "../chunk-CCCJ6BPW.js";
|
|
39
40
|
import {
|
|
40
41
|
getMachineId
|
|
41
42
|
} from "../chunk-RN3NOEJF.js";
|
|
@@ -113,9 +114,9 @@ var runLocalPassthrough = (binary, args2) => {
|
|
|
113
114
|
cleanup();
|
|
114
115
|
resolve2(127);
|
|
115
116
|
});
|
|
116
|
-
child.on("exit", (
|
|
117
|
+
child.on("exit", (code2, signal) => {
|
|
117
118
|
cleanup();
|
|
118
|
-
if (typeof
|
|
119
|
+
if (typeof code2 === "number") resolve2(code2);
|
|
119
120
|
else if (signal) resolve2(128 + (SIGNAL_NUMBERS[signal] ?? 0));
|
|
120
121
|
else resolve2(0);
|
|
121
122
|
});
|
|
@@ -139,9 +140,11 @@ var createSyncState = () => ({
|
|
|
139
140
|
sessionKey: null,
|
|
140
141
|
wrappedKey: null,
|
|
141
142
|
seen: /* @__PURE__ */ new Set(),
|
|
142
|
-
keyUploaded: false
|
|
143
|
+
keyUploaded: false,
|
|
144
|
+
keyRejected: false
|
|
143
145
|
});
|
|
144
146
|
var syncTick = async (lines, state, uploader, sessionId, machineId) => {
|
|
147
|
+
if (state.keyRejected) return state;
|
|
145
148
|
let sessionKey = state.sessionKey;
|
|
146
149
|
let wrappedKey = state.wrappedKey;
|
|
147
150
|
if (!sessionKey) {
|
|
@@ -152,9 +155,9 @@ var syncTick = async (lines, state, uploader, sessionId, machineId) => {
|
|
|
152
155
|
}
|
|
153
156
|
const built = buildTranscriptRecords(lines, sessionKey, state.seen);
|
|
154
157
|
if (built.records.length === 0) {
|
|
155
|
-
return { sessionKey, wrappedKey, seen: built.seen
|
|
158
|
+
return { ...state, sessionKey, wrappedKey, seen: built.seen };
|
|
156
159
|
}
|
|
157
|
-
const
|
|
160
|
+
const result = await uploader.uploadRecords({
|
|
158
161
|
sessionId,
|
|
159
162
|
machineId,
|
|
160
163
|
dataEncryptionKey: state.keyUploaded ? void 0 : wrappedKey ?? void 0,
|
|
@@ -163,8 +166,9 @@ var syncTick = async (lines, state, uploader, sessionId, machineId) => {
|
|
|
163
166
|
return {
|
|
164
167
|
sessionKey,
|
|
165
168
|
wrappedKey,
|
|
166
|
-
seen: ok ? built.seen : state.seen,
|
|
167
|
-
keyUploaded: state.keyUploaded ||
|
|
169
|
+
seen: result.ok ? built.seen : state.seen,
|
|
170
|
+
keyUploaded: state.keyUploaded || result.keyRegistered,
|
|
171
|
+
keyRejected: result.keyConflict
|
|
168
172
|
};
|
|
169
173
|
};
|
|
170
174
|
var readLines = (path) => {
|
|
@@ -258,7 +262,7 @@ var ensureClaudeSdk = async (log) => {
|
|
|
258
262
|
{ cwd: dir, stdio: "ignore", shell: process.platform === "win32" }
|
|
259
263
|
);
|
|
260
264
|
child.on("error", () => resolve2(false));
|
|
261
|
-
child.on("close", (
|
|
265
|
+
child.on("close", (code2) => resolve2(code2 === 0));
|
|
262
266
|
});
|
|
263
267
|
if (!installed) {
|
|
264
268
|
log?.(`[pushary] could not auto-install the SDK. Install it manually: npm i -g ${SDK_SPEC}`);
|
|
@@ -1039,13 +1043,13 @@ var runLocalLeg = (session, deps = {}) => {
|
|
|
1039
1043
|
}
|
|
1040
1044
|
finish();
|
|
1041
1045
|
});
|
|
1042
|
-
child.on("exit", (
|
|
1046
|
+
child.on("exit", (code2, signal) => {
|
|
1043
1047
|
if (signal === "SIGTERM" && legAbort.signal.aborted) {
|
|
1044
1048
|
} else if (!exitReason) {
|
|
1045
1049
|
if (session.input.bufferedCount > 0) {
|
|
1046
1050
|
exitReason = "switch";
|
|
1047
|
-
} else if (typeof
|
|
1048
|
-
exitReason = { type: "exit", code };
|
|
1051
|
+
} else if (typeof code2 === "number") {
|
|
1052
|
+
exitReason = { type: "exit", code: code2 };
|
|
1049
1053
|
} else if (signal) {
|
|
1050
1054
|
exitReason = { type: "exit", code: SIGNAL_EXIT_BASE + (SIGNAL_NUMBERS2[signal] ?? 0) };
|
|
1051
1055
|
} else {
|
|
@@ -1492,10 +1496,15 @@ var runClaudeWrapper = async (args2) => {
|
|
|
1492
1496
|
|
|
1493
1497
|
// bin/pushary-claude.ts
|
|
1494
1498
|
var args = resolveClaudeArgs(process.argv);
|
|
1495
|
-
|
|
1499
|
+
var spawnId = process.env.PUSHARY_SPAWN_ID?.trim() || void 0;
|
|
1500
|
+
var code = await withSpawnProcessOwnership(spawnId, async () => {
|
|
1501
|
+
await ensureDaemonRunning();
|
|
1502
|
+
return runClaudeWrapper(args);
|
|
1503
|
+
}).catch((err) => {
|
|
1496
1504
|
process.stderr.write(
|
|
1497
1505
|
`[pushary] wrapper error: ${err instanceof Error ? err.message : String(err)}
|
|
1498
1506
|
`
|
|
1499
1507
|
);
|
|
1500
|
-
|
|
1508
|
+
return 1;
|
|
1501
1509
|
});
|
|
1510
|
+
process.exit(code);
|
|
@@ -6,11 +6,12 @@ import {
|
|
|
6
6
|
postLiveSession,
|
|
7
7
|
postLiveSessionUntilAccepted,
|
|
8
8
|
startLiveSessionHeartbeat
|
|
9
|
-
} from "../chunk-
|
|
10
|
-
import "../chunk-
|
|
9
|
+
} from "../chunk-ERYKGH4J.js";
|
|
10
|
+
import "../chunk-GCKAWHFP.js";
|
|
11
11
|
import {
|
|
12
|
-
startProcessOwnership
|
|
13
|
-
|
|
12
|
+
startProcessOwnership,
|
|
13
|
+
withSpawnProcessOwnership
|
|
14
|
+
} from "../chunk-ILB6UOAF.js";
|
|
14
15
|
import {
|
|
15
16
|
spawnClaude
|
|
16
17
|
} from "../chunk-XHKBHWLX.js";
|
|
@@ -327,7 +328,7 @@ var abort = new AbortController();
|
|
|
327
328
|
var signals = process.platform === "win32" ? ["SIGINT", "SIGTERM"] : ["SIGINT", "SIGTERM", "SIGHUP"];
|
|
328
329
|
var stop = () => abort.abort();
|
|
329
330
|
for (const signal of signals) process.on(signal, stop);
|
|
330
|
-
var outcome = await runCodexBridge({
|
|
331
|
+
var outcome = await withSpawnProcessOwnership(spawnId, () => runCodexBridge({
|
|
331
332
|
apiKey: getApiKey(),
|
|
332
333
|
baseUrl: getBaseUrl(),
|
|
333
334
|
machineId: getMachineId(),
|
|
@@ -343,6 +344,6 @@ var outcome = await runCodexBridge({
|
|
|
343
344
|
},
|
|
344
345
|
signal: abort.signal,
|
|
345
346
|
transcripts: process.env.PUSHARY_TRANSCRIPTS === "1"
|
|
346
|
-
});
|
|
347
|
+
}));
|
|
347
348
|
for (const signal of signals) process.off(signal, stop);
|
|
348
349
|
process.exit(outcome === "stopped" ? 0 : 1);
|
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
denyReasonFrom,
|
|
9
9
|
isDeferAnswer,
|
|
10
10
|
resolveGate
|
|
11
|
-
} from "../chunk-
|
|
11
|
+
} from "../chunk-BLDDXHHA.js";
|
|
12
12
|
import {
|
|
13
13
|
CODEX_AGENT,
|
|
14
14
|
DEFAULT_SESSION,
|
|
@@ -28,6 +28,7 @@ import {
|
|
|
28
28
|
handleStop,
|
|
29
29
|
handleUserPrompt,
|
|
30
30
|
permissionTimeoutDecision,
|
|
31
|
+
policyRequestFor,
|
|
31
32
|
preToolUseTimeoutDecision,
|
|
32
33
|
readLastPrompt,
|
|
33
34
|
repoKeyFor,
|
|
@@ -39,7 +40,7 @@ import {
|
|
|
39
40
|
toPolicyLookup,
|
|
40
41
|
toPolicyLookups,
|
|
41
42
|
waitForAnswer
|
|
42
|
-
} from "../chunk-
|
|
43
|
+
} from "../chunk-CCCJ6BPW.js";
|
|
43
44
|
import {
|
|
44
45
|
getMachineId
|
|
45
46
|
} from "../chunk-RN3NOEJF.js";
|
|
@@ -143,6 +144,7 @@ var pushQuestion = async (apiKey, input, lookup, waitSeconds, mode) => {
|
|
|
143
144
|
action: description.slice(0, DECISION_LINE_MAX),
|
|
144
145
|
blocker: deriveBlocker(mode),
|
|
145
146
|
actionBody: deriveActionBody(input.tool_name ?? "", input.tool_input ?? {}),
|
|
147
|
+
repoKey: repoKeyFor(input.cwd),
|
|
146
148
|
// Codex has always sent this; it is what claimNotify and markApproved already
|
|
147
149
|
// key on locally. Passing it through lets the server collapse a retried create
|
|
148
150
|
// the same way, instead of putting the same approval on the phone twice.
|
|
@@ -177,9 +179,10 @@ var notifyApprovalNeeded = async (apiKey, input, lookup) => {
|
|
|
177
179
|
};
|
|
178
180
|
var codexGate = async (apiKey, input) => {
|
|
179
181
|
const modeState = await fetchModeState(apiKey, input.session_id);
|
|
182
|
+
const policyRequest = policyRequestFor("codex");
|
|
180
183
|
const lookup = toPolicyLookup(input.tool_name ?? "", input.tool_input ?? {}, input.cwd);
|
|
181
184
|
const lookups = toPolicyLookups(input.tool_name ?? "", input.tool_input ?? {}, input.cwd);
|
|
182
|
-
const config = await getPolicy(apiKey, modeState.policyVersion,
|
|
185
|
+
const config = await getPolicy(apiKey, modeState.policyVersion, policyRequest.agent, policyRequest.repoAware, input.session_id);
|
|
183
186
|
const verdict = resolveGate({
|
|
184
187
|
modeState,
|
|
185
188
|
config,
|
|
@@ -15,8 +15,9 @@ import {
|
|
|
15
15
|
geminiLiveCapabilities
|
|
16
16
|
} from "../chunk-NRGRUOAR.js";
|
|
17
17
|
import {
|
|
18
|
+
findLiveProcessBySpawnId,
|
|
18
19
|
ownsLiveProcess
|
|
19
|
-
} from "../chunk-
|
|
20
|
+
} from "../chunk-ILB6UOAF.js";
|
|
20
21
|
import {
|
|
21
22
|
spawnClaude
|
|
22
23
|
} from "../chunk-XHKBHWLX.js";
|
|
@@ -135,6 +136,23 @@ var spawnAcknowledgement = (request, machineId, outcome) => {
|
|
|
135
136
|
}
|
|
136
137
|
};
|
|
137
138
|
};
|
|
139
|
+
var launchSpawnClaim = async (request, runtime) => {
|
|
140
|
+
const existingPid = await runtime.findExistingPid(request.id);
|
|
141
|
+
if (existingPid !== null) {
|
|
142
|
+
await runtime.acknowledge(spawnAcknowledgement(request, runtime.machineId, { state: "started", pid: existingPid }));
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
let pid;
|
|
146
|
+
try {
|
|
147
|
+
pid = await runtime.launch(request);
|
|
148
|
+
} catch (err) {
|
|
149
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
150
|
+
runtime.reportLaunchError(message);
|
|
151
|
+
await runtime.acknowledge(spawnAcknowledgement(request, runtime.machineId, { state: "failed", message }));
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
await runtime.acknowledge(spawnAcknowledgement(request, runtime.machineId, { state: "started", pid }));
|
|
155
|
+
};
|
|
138
156
|
var DrainError = class extends Error {
|
|
139
157
|
constructor(status) {
|
|
140
158
|
super(`drain ${status}`);
|
|
@@ -397,19 +415,19 @@ var runSpawnDaemon = async () => {
|
|
|
397
415
|
}
|
|
398
416
|
throw lastError ?? new Error("spawn acknowledgement stopped");
|
|
399
417
|
};
|
|
400
|
-
const launchClaim =
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
pid
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
}
|
|
411
|
-
|
|
412
|
-
};
|
|
418
|
+
const launchClaim = (request) => launchSpawnClaim(request, {
|
|
419
|
+
machineId,
|
|
420
|
+
findExistingPid: async (spawnId) => {
|
|
421
|
+
for (const [pid, launchedSpawnId] of launchedProcesses) {
|
|
422
|
+
if (launchedSpawnId === spawnId) return pid;
|
|
423
|
+
}
|
|
424
|
+
return findLiveProcessBySpawnId(spawnId);
|
|
425
|
+
},
|
|
426
|
+
launch,
|
|
427
|
+
acknowledge,
|
|
428
|
+
reportLaunchError: (message) => stderr(`[pushary] could not launch session: ${message}
|
|
429
|
+
`)
|
|
430
|
+
});
|
|
413
431
|
const nextDelay = () => {
|
|
414
432
|
if (errorStreak > 0) return Math.min(SLOW_POLL_MS * 2 ** (errorStreak - 1), MAX_ERROR_BACKOFF_MS);
|
|
415
433
|
return idleTicks >= FAST_DECAY_TICKS ? SLOW_POLL_MS : FAST_POLL_MS;
|
|
@@ -5,11 +5,12 @@ import {
|
|
|
5
5
|
postLiveSession,
|
|
6
6
|
postLiveSessionUntilAccepted,
|
|
7
7
|
startLiveSessionHeartbeat
|
|
8
|
-
} from "../chunk-
|
|
9
|
-
import "../chunk-
|
|
8
|
+
} from "../chunk-ERYKGH4J.js";
|
|
9
|
+
import "../chunk-GCKAWHFP.js";
|
|
10
10
|
import {
|
|
11
|
-
startProcessOwnership
|
|
12
|
-
|
|
11
|
+
startProcessOwnership,
|
|
12
|
+
withSpawnProcessOwnership
|
|
13
|
+
} from "../chunk-ILB6UOAF.js";
|
|
13
14
|
import {
|
|
14
15
|
spawnClaude
|
|
15
16
|
} from "../chunk-XHKBHWLX.js";
|
|
@@ -280,7 +281,7 @@ var abort = new AbortController();
|
|
|
280
281
|
var signals = process.platform === "win32" ? ["SIGINT", "SIGTERM"] : ["SIGINT", "SIGTERM", "SIGHUP"];
|
|
281
282
|
var stop = () => abort.abort();
|
|
282
283
|
for (const signal of signals) process.on(signal, stop);
|
|
283
|
-
var outcome = await runGeminiBridge({
|
|
284
|
+
var outcome = await withSpawnProcessOwnership(spawnId, () => runGeminiBridge({
|
|
284
285
|
apiKey: getApiKey(),
|
|
285
286
|
baseUrl: getBaseUrl(),
|
|
286
287
|
machineId: getMachineId(),
|
|
@@ -293,6 +294,6 @@ var outcome = await runGeminiBridge({
|
|
|
293
294
|
command: { command: process.env.PUSHARY_GEMINI_COMMAND?.trim() || resolveBinary("gemini") || "gemini" },
|
|
294
295
|
signal: abort.signal,
|
|
295
296
|
transcripts: process.env.PUSHARY_TRANSCRIPTS === "1"
|
|
296
|
-
});
|
|
297
|
+
}));
|
|
297
298
|
for (const signal of signals) process.off(signal, stop);
|
|
298
299
|
process.exit(outcome === "stopped" ? 0 : 1);
|
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
denyReasonFrom,
|
|
9
9
|
isDeferAnswer,
|
|
10
10
|
resolveGate
|
|
11
|
-
} from "../chunk-
|
|
11
|
+
} from "../chunk-BLDDXHHA.js";
|
|
12
12
|
import {
|
|
13
13
|
DEFAULT_SESSION,
|
|
14
14
|
askUser,
|
|
@@ -22,6 +22,7 @@ import {
|
|
|
22
22
|
handlePostToolUse,
|
|
23
23
|
handleStop,
|
|
24
24
|
handleUserPrompt,
|
|
25
|
+
policyRequestFor,
|
|
25
26
|
readLastPrompt,
|
|
26
27
|
readLastUserPrompt,
|
|
27
28
|
repoKeyFor,
|
|
@@ -30,7 +31,7 @@ import {
|
|
|
30
31
|
scopePathFor,
|
|
31
32
|
sendNotification,
|
|
32
33
|
waitForAnswer
|
|
33
|
-
} from "../chunk-
|
|
34
|
+
} from "../chunk-CCCJ6BPW.js";
|
|
34
35
|
import {
|
|
35
36
|
getMachineId
|
|
36
37
|
} from "../chunk-RN3NOEJF.js";
|
|
@@ -127,7 +128,8 @@ var pushQuestion = async (apiKey, input, lookup, waitSeconds, mode, pollInterval
|
|
|
127
128
|
intent: readLastPrompt(input.session_id || DEFAULT_SESSION) ?? (input.transcript_path ? readLastUserPrompt(input.transcript_path) : void 0),
|
|
128
129
|
action: description.slice(0, DECISION_LINE_MAX),
|
|
129
130
|
blocker: deriveBlocker(mode),
|
|
130
|
-
actionBody: deriveActionBody(input.tool_name ?? "", input.tool_input ?? {})
|
|
131
|
+
actionBody: deriveActionBody(input.tool_name ?? "", input.tool_input ?? {}),
|
|
132
|
+
repoKey: repoKeyFor(input.cwd)
|
|
131
133
|
});
|
|
132
134
|
if (result.suppressed || result.noDevices) {
|
|
133
135
|
return {
|
|
@@ -219,8 +221,9 @@ var decideBeforeTool = async (input) => {
|
|
|
219
221
|
}
|
|
220
222
|
try {
|
|
221
223
|
const modeState = await fetchModeState(apiKey, input.session_id);
|
|
224
|
+
const policyRequest = policyRequestFor("gemini_cli");
|
|
222
225
|
const lookup = toGeminiPolicyLookup(input.tool_name ?? "", input.tool_input ?? {}, input.cwd);
|
|
223
|
-
const config = await getPolicy(apiKey, modeState.policyVersion,
|
|
226
|
+
const config = await getPolicy(apiKey, modeState.policyVersion, policyRequest.agent, policyRequest.repoAware, input.session_id);
|
|
224
227
|
const scopePath = modeState.scope ? scopePathFor(lookup.tool, lookup.input, input.cwd) : void 0;
|
|
225
228
|
const verdict = resolveGate({
|
|
226
229
|
modeState,
|
package/dist/bin/pushary-hook.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
handlePreToolUse
|
|
4
|
-
} from "../chunk-
|
|
4
|
+
} from "../chunk-YR5TSPXB.js";
|
|
5
5
|
import "../chunk-UKSQWTBH.js";
|
|
6
6
|
import "../chunk-NJ7JT26G.js";
|
|
7
|
-
import "../chunk-
|
|
8
|
-
import "../chunk-
|
|
7
|
+
import "../chunk-BLDDXHHA.js";
|
|
8
|
+
import "../chunk-CCCJ6BPW.js";
|
|
9
9
|
import "../chunk-RN3NOEJF.js";
|
|
10
10
|
import {
|
|
11
11
|
exitOnHelpFlag
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
handlePermissionDenied
|
|
4
|
-
} from "../chunk-
|
|
4
|
+
} from "../chunk-YR5TSPXB.js";
|
|
5
5
|
import "../chunk-UKSQWTBH.js";
|
|
6
6
|
import "../chunk-NJ7JT26G.js";
|
|
7
|
-
import "../chunk-
|
|
8
|
-
import "../chunk-
|
|
7
|
+
import "../chunk-BLDDXHHA.js";
|
|
8
|
+
import "../chunk-CCCJ6BPW.js";
|
|
9
9
|
import "../chunk-RN3NOEJF.js";
|
|
10
10
|
import "../chunk-BSZYIAZL.js";
|
|
11
11
|
import "../chunk-SAF6HGAA.js";
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
handlePermissionRequest
|
|
4
|
-
} from "../chunk-
|
|
4
|
+
} from "../chunk-YR5TSPXB.js";
|
|
5
5
|
import "../chunk-UKSQWTBH.js";
|
|
6
6
|
import "../chunk-NJ7JT26G.js";
|
|
7
|
-
import "../chunk-
|
|
8
|
-
import "../chunk-
|
|
7
|
+
import "../chunk-BLDDXHHA.js";
|
|
8
|
+
import "../chunk-CCCJ6BPW.js";
|
|
9
9
|
import "../chunk-RN3NOEJF.js";
|
|
10
10
|
import "../chunk-BSZYIAZL.js";
|
|
11
11
|
import "../chunk-SAF6HGAA.js";
|
|
@@ -60,7 +60,7 @@ var CACHE_TTL_MS = 60 * 1e3;
|
|
|
60
60
|
var STALE_CACHE_MAX_MS = 12 * 60 * 60 * 1e3;
|
|
61
61
|
var policyRequestFor = (agentType) => ({
|
|
62
62
|
agent: agentType,
|
|
63
|
-
repoAware:
|
|
63
|
+
repoAware: ["claude_code", "codex", "gemini_cli"].includes(agentType)
|
|
64
64
|
});
|
|
65
65
|
var policyCacheFile = (apiKey, agent, repoAware = false) => {
|
|
66
66
|
const parts = [apiKey, agent, repoAware ? "repoAware" : void 0].filter(Boolean);
|
|
@@ -1318,6 +1318,7 @@ var handleStopFailure = async (input, agent = CLAUDE_CODE_AGENT) => {
|
|
|
1318
1318
|
};
|
|
1319
1319
|
|
|
1320
1320
|
export {
|
|
1321
|
+
policyRequestFor,
|
|
1321
1322
|
getPolicy,
|
|
1322
1323
|
resolveAutoResolveOrigin,
|
|
1323
1324
|
resolvePolicy,
|
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
generateSessionKey,
|
|
6
6
|
uploadTranscriptRecords,
|
|
7
7
|
wrapSessionKey
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-GCKAWHFP.js";
|
|
9
9
|
|
|
10
10
|
// src/live-session.ts
|
|
11
11
|
var MAX_TRANSCRIPT_QUEUE = 100;
|
|
@@ -72,8 +72,10 @@ var LiveTranscriptRelay = class {
|
|
|
72
72
|
sessionKey = null;
|
|
73
73
|
wrappedKey = null;
|
|
74
74
|
keyUploaded = false;
|
|
75
|
+
keyRejected = false;
|
|
75
76
|
flushing = null;
|
|
76
77
|
add(value) {
|
|
78
|
+
if (this.keyRejected) return;
|
|
77
79
|
const raw = JSON.stringify(value);
|
|
78
80
|
if (raw.length > MAX_TRANSCRIPT_TEXT) return;
|
|
79
81
|
if (this.queue.length === MAX_TRANSCRIPT_QUEUE) this.queue.shift();
|
|
@@ -106,14 +108,19 @@ var LiveTranscriptRelay = class {
|
|
|
106
108
|
this.queue.splice(0, count);
|
|
107
109
|
return true;
|
|
108
110
|
}
|
|
109
|
-
const
|
|
111
|
+
const result = await uploadTranscriptRecords(this.options.apiKey, {
|
|
110
112
|
sessionId: this.sessionId,
|
|
111
113
|
machineId: this.options.machineId,
|
|
112
114
|
dataEncryptionKey: this.keyUploaded ? void 0 : this.wrappedKey ?? void 0,
|
|
113
115
|
records
|
|
114
116
|
}, this.options.baseUrl);
|
|
115
|
-
if (
|
|
116
|
-
this.
|
|
117
|
+
if (result.keyConflict) {
|
|
118
|
+
this.keyRejected = true;
|
|
119
|
+
this.queue.length = 0;
|
|
120
|
+
return false;
|
|
121
|
+
}
|
|
122
|
+
if (result.ok) {
|
|
123
|
+
this.keyUploaded ||= result.keyRegistered;
|
|
117
124
|
this.queue.splice(0, count);
|
|
118
125
|
return true;
|
|
119
126
|
}
|
|
@@ -101,9 +101,16 @@ var uploadTranscriptRecords = async (apiKey, params, baseUrl = getBaseUrl()) =>
|
|
|
101
101
|
body: JSON.stringify(params),
|
|
102
102
|
signal: AbortSignal.timeout(15e3)
|
|
103
103
|
});
|
|
104
|
-
|
|
104
|
+
const body = await res.json().catch(() => null);
|
|
105
|
+
const keyRegistered = body?.keyRegistered === true;
|
|
106
|
+
const keyConflict = body?.keyConflict === true;
|
|
107
|
+
return {
|
|
108
|
+
ok: res.ok && !keyConflict && (params.dataEncryptionKey === void 0 || keyRegistered),
|
|
109
|
+
keyRegistered,
|
|
110
|
+
keyConflict
|
|
111
|
+
};
|
|
105
112
|
} catch {
|
|
106
|
-
return false;
|
|
113
|
+
return { ok: false, keyRegistered: false, keyConflict: false };
|
|
107
114
|
}
|
|
108
115
|
};
|
|
109
116
|
|
|
@@ -91,7 +91,11 @@ var startProcessOwnership = (identity, options = {}) => {
|
|
|
91
91
|
proof = { ...identity, port: address.port, token };
|
|
92
92
|
mkdirSync(dir, { recursive: true, mode: 448 });
|
|
93
93
|
pruneProofs(dir);
|
|
94
|
-
writeFileSync(path, JSON.stringify(proof), {
|
|
94
|
+
writeFileSync(path, JSON.stringify(proof), {
|
|
95
|
+
encoding: "utf8",
|
|
96
|
+
mode: 384,
|
|
97
|
+
flag: options.exclusive ? "wx" : "w"
|
|
98
|
+
});
|
|
95
99
|
resolve();
|
|
96
100
|
} catch {
|
|
97
101
|
server.close();
|
|
@@ -113,41 +117,76 @@ var startProcessOwnership = (identity, options = {}) => {
|
|
|
113
117
|
}
|
|
114
118
|
};
|
|
115
119
|
};
|
|
120
|
+
var withSpawnProcessOwnership = async (spawnId, run, options = {}) => {
|
|
121
|
+
if (!spawnId) return run();
|
|
122
|
+
const sessionId = `spawn:${spawnId}`;
|
|
123
|
+
const ownership = startProcessOwnership({
|
|
124
|
+
sessionId,
|
|
125
|
+
pid: process.pid,
|
|
126
|
+
spawnId
|
|
127
|
+
}, { ...options, exclusive: true });
|
|
128
|
+
await ownership.ready;
|
|
129
|
+
if (!await ownsLiveProcess({ sessionId, pid: process.pid, spawnId }, options)) {
|
|
130
|
+
ownership.stop();
|
|
131
|
+
throw new Error("Could not establish spawned process ownership");
|
|
132
|
+
}
|
|
133
|
+
try {
|
|
134
|
+
return await run();
|
|
135
|
+
} finally {
|
|
136
|
+
ownership.stop();
|
|
137
|
+
}
|
|
138
|
+
};
|
|
116
139
|
var ownsLiveProcess = async (request, options = {}) => {
|
|
117
140
|
const stored = readJsonSafe(proofPath(ownershipDir(options), request.sessionId));
|
|
118
141
|
if (stored.kind !== "ok" || !isProof(stored.value)) return false;
|
|
119
142
|
const proof = stored.value;
|
|
120
143
|
if (proof.sessionId !== request.sessionId || proof.pid !== request.pid) return false;
|
|
121
144
|
if (request.spawnId && proof.spawnId !== request.spawnId) return false;
|
|
122
|
-
return
|
|
123
|
-
let settled = false;
|
|
124
|
-
let raw = "";
|
|
125
|
-
const socket = createConnection({ host: "127.0.0.1", port: proof.port });
|
|
126
|
-
const finish = (owned) => {
|
|
127
|
-
if (settled) return;
|
|
128
|
-
settled = true;
|
|
129
|
-
socket.destroy();
|
|
130
|
-
resolve(owned);
|
|
131
|
-
};
|
|
132
|
-
socket.setTimeout(options.connectTimeoutMs ?? 500, () => finish(false));
|
|
133
|
-
socket.on("error", () => finish(false));
|
|
134
|
-
socket.on("connect", () => socket.write(proof.token));
|
|
135
|
-
socket.on("data", (chunk) => {
|
|
136
|
-
raw += String(chunk);
|
|
137
|
-
if (raw.length > MAX_PROOF_BYTES) finish(false);
|
|
138
|
-
});
|
|
139
|
-
socket.on("end", () => {
|
|
140
|
-
try {
|
|
141
|
-
const live = JSON.parse(raw);
|
|
142
|
-
finish(isProof(live) && live.token === proof.token && live.sessionId === proof.sessionId && live.pid === proof.pid && live.spawnId === proof.spawnId);
|
|
143
|
-
} catch {
|
|
144
|
-
finish(false);
|
|
145
|
-
}
|
|
146
|
-
});
|
|
147
|
-
});
|
|
145
|
+
return verifyProof(proof, options);
|
|
148
146
|
};
|
|
147
|
+
var findLiveProcessBySpawnId = async (spawnId, options = {}) => {
|
|
148
|
+
try {
|
|
149
|
+
const dir = ownershipDir(options);
|
|
150
|
+
for (const entry of readdirSync(dir, { withFileTypes: true })) {
|
|
151
|
+
if (!entry.isFile() || !entry.name.endsWith(".json")) continue;
|
|
152
|
+
const stored = readJsonSafe(join(dir, entry.name));
|
|
153
|
+
if (stored.kind !== "ok" || !isProof(stored.value) || stored.value.spawnId !== spawnId) continue;
|
|
154
|
+
if (await verifyProof(stored.value, options)) return stored.value.pid;
|
|
155
|
+
}
|
|
156
|
+
} catch {
|
|
157
|
+
}
|
|
158
|
+
return null;
|
|
159
|
+
};
|
|
160
|
+
var verifyProof = (proof, options) => new Promise((resolve) => {
|
|
161
|
+
let settled = false;
|
|
162
|
+
let raw = "";
|
|
163
|
+
const socket = createConnection({ host: "127.0.0.1", port: proof.port });
|
|
164
|
+
const finish = (owned) => {
|
|
165
|
+
if (settled) return;
|
|
166
|
+
settled = true;
|
|
167
|
+
socket.destroy();
|
|
168
|
+
resolve(owned);
|
|
169
|
+
};
|
|
170
|
+
socket.setTimeout(options.connectTimeoutMs ?? 500, () => finish(false));
|
|
171
|
+
socket.on("error", () => finish(false));
|
|
172
|
+
socket.on("connect", () => socket.write(proof.token));
|
|
173
|
+
socket.on("data", (chunk) => {
|
|
174
|
+
raw += String(chunk);
|
|
175
|
+
if (raw.length > MAX_PROOF_BYTES) finish(false);
|
|
176
|
+
});
|
|
177
|
+
socket.on("end", () => {
|
|
178
|
+
try {
|
|
179
|
+
const live = JSON.parse(raw);
|
|
180
|
+
finish(isProof(live) && live.token === proof.token && live.sessionId === proof.sessionId && live.pid === proof.pid && live.spawnId === proof.spawnId);
|
|
181
|
+
} catch {
|
|
182
|
+
finish(false);
|
|
183
|
+
}
|
|
184
|
+
});
|
|
185
|
+
});
|
|
149
186
|
|
|
150
187
|
export {
|
|
151
188
|
startProcessOwnership,
|
|
152
|
-
|
|
189
|
+
withSpawnProcessOwnership,
|
|
190
|
+
ownsLiveProcess,
|
|
191
|
+
findLiveProcessBySpawnId
|
|
153
192
|
};
|
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
denyReasonFrom,
|
|
10
10
|
isDeferAnswer,
|
|
11
11
|
resolveGate
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-BLDDXHHA.js";
|
|
13
13
|
import {
|
|
14
14
|
DEFAULT_SESSION,
|
|
15
15
|
askUser,
|
|
@@ -29,7 +29,7 @@ import {
|
|
|
29
29
|
sendNotification,
|
|
30
30
|
throttlePass,
|
|
31
31
|
waitForAnswer
|
|
32
|
-
} from "./chunk-
|
|
32
|
+
} from "./chunk-CCCJ6BPW.js";
|
|
33
33
|
import {
|
|
34
34
|
getMachineId
|
|
35
35
|
} from "./chunk-RN3NOEJF.js";
|
package/dist/src/index.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
2
|
handlePreToolUse
|
|
3
|
-
} from "../chunk-
|
|
3
|
+
} from "../chunk-YR5TSPXB.js";
|
|
4
4
|
import "../chunk-UKSQWTBH.js";
|
|
5
5
|
import "../chunk-NJ7JT26G.js";
|
|
6
|
-
import "../chunk-
|
|
6
|
+
import "../chunk-BLDDXHHA.js";
|
|
7
7
|
import {
|
|
8
8
|
askUser,
|
|
9
9
|
cancelQuestion,
|
|
@@ -16,7 +16,7 @@ import {
|
|
|
16
16
|
reportEvent,
|
|
17
17
|
resolvePolicy,
|
|
18
18
|
waitForAnswer
|
|
19
|
-
} from "../chunk-
|
|
19
|
+
} from "../chunk-CCCJ6BPW.js";
|
|
20
20
|
import "../chunk-RN3NOEJF.js";
|
|
21
21
|
import "../chunk-BSZYIAZL.js";
|
|
22
22
|
import "../chunk-SAF6HGAA.js";
|