@pushary/agent-hooks 1.9.30 → 1.9.31
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 +11 -0
- package/data/SKILL.md +46 -12
- package/data/cursor-plugin/skills/pushary/SKILL.md +46 -12
- package/data/vscode-plugin/skills/pushary/SKILL.md +46 -12
- package/dist/bin/pushary-bell-hook.js +26 -26
- package/dist/bin/pushary-bell.js +9 -9
- package/dist/bin/pushary-claude.js +25 -25
- package/dist/bin/pushary-clean.js +29 -29
- package/dist/bin/pushary-codex-bridge.js +17 -17
- package/dist/bin/pushary-codex-hook.js +31 -31
- package/dist/bin/pushary-codex.js +12 -12
- package/dist/bin/pushary-connect.js +24 -24
- package/dist/bin/pushary-cowork.js +5 -5
- package/dist/bin/pushary-daemon.js +33 -33
- package/dist/bin/pushary-disconnect.js +24 -24
- package/dist/bin/pushary-doctor.js +33 -33
- package/dist/bin/pushary-elicitation-hook.js +26 -26
- package/dist/bin/pushary-gemini-bridge.js +13 -13
- package/dist/bin/pushary-gemini-hook.js +28 -28
- package/dist/bin/pushary-hook.js +30 -30
- package/dist/bin/pushary-login.js +12 -12
- package/dist/bin/pushary-logout.js +24 -24
- package/dist/bin/pushary-mcp.js +9 -9
- package/dist/bin/pushary-mode.js +12 -12
- package/dist/bin/pushary-notification-hook.js +25 -25
- package/dist/bin/pushary-opencode-hook.js +27 -27
- package/dist/bin/pushary-permission-denied-hook.js +30 -30
- package/dist/bin/pushary-permission-hook.js +29 -29
- package/dist/bin/pushary-post-hook.js +25 -25
- package/dist/bin/pushary-prompt-hook.js +25 -25
- package/dist/bin/pushary-session-end-hook.js +25 -25
- package/dist/bin/pushary-session-start-hook.js +29 -29
- package/dist/bin/pushary-setup.js +35 -35
- package/dist/bin/pushary-stats.js +5 -5
- package/dist/bin/pushary-status.js +26 -26
- package/dist/bin/pushary-stop-hook.js +25 -25
- package/dist/bin/pushary-stopfailure-hook.js +25 -25
- package/dist/bin/pushary-suggestions.js +12 -12
- package/dist/bin/pushary-transcript-register.js +18 -18
- package/dist/bin/pushary-transcripts.js +8 -8
- package/dist/bin/pushary-upgrade.js +30 -30
- package/dist/bin/pushary-wait.js +12 -12
- package/dist/bin/pushary.js +6 -6
- package/dist/{chunk-SMA7LUCS.js → chunk-2ROXUEZV.js} +1 -1
- package/dist/{chunk-DP6FJABB.js → chunk-35RJKPIC.js} +1 -1
- package/dist/{chunk-PWQN4D6R.js → chunk-3EIJDBVB.js} +5 -5
- package/dist/{chunk-OQ5K6QHU.js → chunk-464FX6W5.js} +5 -5
- package/dist/{chunk-Q6HJD6SH.js → chunk-4JOWKPUF.js} +1 -1
- package/dist/{chunk-3QKX22ZA.js → chunk-4WGKAGIU.js} +3 -3
- package/dist/{chunk-XNKFK27C.js → chunk-5EX2SD5N.js} +1 -1
- package/dist/{chunk-VTTHXOCR.js → chunk-5F32ZTWD.js} +2 -2
- package/dist/{chunk-DU6UZXGV.js → chunk-5FNE6ZVV.js} +2 -2
- package/dist/{chunk-RZTWWE26.js → chunk-5GDNIEL5.js} +1 -1
- package/dist/{chunk-E2WJLU5U.js → chunk-7447DYNW.js} +1 -1
- package/dist/{chunk-SAGO6JNL.js → chunk-75UCMLT5.js} +1 -1
- package/dist/{chunk-NKDK3H3I.js → chunk-77J4RVB2.js} +4 -4
- package/dist/{chunk-AO75FKBR.js → chunk-7S4Z36H7.js} +3 -3
- package/dist/{chunk-HMA7QQ3P.js → chunk-ALSIMOFS.js} +4 -4
- package/dist/{chunk-CI2H3U7O.js → chunk-AXANUGOV.js} +2 -2
- package/dist/{chunk-3FIKV3PW.js → chunk-BMUTA66M.js} +11 -11
- package/dist/{chunk-6R22H57A.js → chunk-CJCVPCOB.js} +2 -2
- package/dist/{chunk-CS5JKDWW.js → chunk-D3TVRNZC.js} +2 -2
- package/dist/{chunk-3HTCA4SQ.js → chunk-DP2FAIW6.js} +1 -1
- package/dist/{chunk-VTR4VRL2.js → chunk-DWQYCOPI.js} +2 -4
- package/dist/{chunk-IMUCTAM2.js → chunk-EPVY3JU3.js} +1 -1
- package/dist/{chunk-7JO33ODX.js → chunk-FEICGRNI.js} +3 -3
- package/dist/{chunk-OARF7TWF.js → chunk-FGFFUCEL.js} +6 -6
- package/dist/{chunk-GFY6XONT.js → chunk-FXJ5SEQT.js} +5 -5
- package/dist/{chunk-XZRRYMY2.js → chunk-GROYT52D.js} +4 -4
- package/dist/{chunk-JHVSVVHB.js → chunk-GSBOLJZ4.js} +177 -56
- package/dist/{chunk-2VQULZ4L.js → chunk-H2PQXK26.js} +2 -2
- package/dist/{chunk-S6J3A4DF.js → chunk-IDGESFKZ.js} +1 -1
- package/dist/{chunk-GSMB7FWI.js → chunk-IIP4LEO3.js} +7 -7
- package/dist/{chunk-LD3A63IE.js → chunk-IKJJB4QG.js} +3 -3
- package/dist/{chunk-KRZECDHA.js → chunk-KBRKQMCI.js} +2 -2
- package/dist/{chunk-J3HI2SRD.js → chunk-MG523AVN.js} +1 -1
- package/dist/{chunk-434NFCK2.js → chunk-MRR4NQ3H.js} +1 -1
- package/dist/{chunk-V2FRBKMP.js → chunk-N4LLBUU2.js} +2 -2
- package/dist/{chunk-6DJBVMTR.js → chunk-NTWTU6FA.js} +1 -1
- package/dist/{chunk-2OIGS4P2.js → chunk-OS6AE2MR.js} +3 -3
- package/dist/{chunk-MTPE6BW7.js → chunk-OSUAY4SA.js} +1 -1
- package/dist/{chunk-SM4P6VIY.js → chunk-OTDRNEED.js} +1 -1
- package/dist/{chunk-EDEEITT3.js → chunk-OULHOX5C.js} +5 -5
- package/dist/{chunk-PGFLQXW5.js → chunk-Q2GSTQ3R.js} +2 -2
- package/dist/{chunk-SMAY3CGD.js → chunk-Q7H2IMJQ.js} +2 -2
- package/dist/{chunk-ZLKJHXSC.js → chunk-QCOE42GO.js} +4 -4
- package/dist/{chunk-H7HRHS3M.js → chunk-QGCEQGH6.js} +4 -4
- package/dist/{chunk-KHYUAZPL.js → chunk-RN3KZDWP.js} +2 -2
- package/dist/{chunk-KT4SP73I.js → chunk-SAHD5DYW.js} +4 -4
- package/dist/{chunk-4GIGQIRN.js → chunk-SJJA2GPD.js} +2 -2
- package/dist/{chunk-T4KXYKDL.js → chunk-SQIZGUAN.js} +5 -5
- package/dist/{chunk-2QEW5FJK.js → chunk-SRRJLA24.js} +4 -4
- package/dist/{chunk-XKSAXKRY.js → chunk-SYUHM6V3.js} +3 -3
- package/dist/{chunk-JBVKA3UR.js → chunk-TDLEFGAM.js} +707 -101
- package/dist/{chunk-QYD5TN2J.js → chunk-VFNYTVTJ.js} +5 -5
- package/dist/{chunk-XLNSQLTV.js → chunk-X427XA76.js} +8 -8
- package/dist/{chunk-YZPCDR32.js → chunk-X5HK4XUN.js} +4 -4
- package/dist/{chunk-MYTWZ33A.js → chunk-ZYDSHR5P.js} +3 -3
- package/dist/{global-upgrade-JDZPAQ6B.js → global-upgrade-YMBTZHDP.js} +6 -6
- package/dist/{paths-4QBYMQHK.js → paths-BPFRUWMB.js} +2 -2
- package/dist/{reapply-26GMHUWI.js → reapply-ZC2LSUVZ.js} +20 -20
- package/dist/src/index.js +19 -19
- package/dist/{upgrade-lock-DIRCINDI.js → upgrade-lock-TTZMLZPB.js} +3 -3
- package/package.json +1 -1
|
@@ -3,46 +3,46 @@ import {
|
|
|
3
3
|
loadPin,
|
|
4
4
|
savePin,
|
|
5
5
|
verifyRecipients
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-DWQYCOPI.js";
|
|
7
7
|
import {
|
|
8
8
|
ensureDaemonRunning
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-VFNYTVTJ.js";
|
|
10
10
|
import {
|
|
11
11
|
buildTranscriptRecords,
|
|
12
12
|
decodePublicKey,
|
|
13
13
|
generateSessionKey,
|
|
14
14
|
wrapSessionKey
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-7447DYNW.js";
|
|
16
16
|
import {
|
|
17
17
|
fetchTranscriptRecipients,
|
|
18
18
|
uploadTranscriptRecords
|
|
19
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-EPVY3JU3.js";
|
|
20
20
|
import {
|
|
21
21
|
transcriptEnvironmentPreference,
|
|
22
22
|
transcriptsEnabled
|
|
23
|
-
} from "./chunk-
|
|
23
|
+
} from "./chunk-MRR4NQ3H.js";
|
|
24
24
|
import {
|
|
25
25
|
hookOwnerOf
|
|
26
|
-
} from "./chunk-
|
|
26
|
+
} from "./chunk-FXJ5SEQT.js";
|
|
27
27
|
import {
|
|
28
28
|
readTranscriptPreference
|
|
29
|
-
} from "./chunk-
|
|
29
|
+
} from "./chunk-IKJJB4QG.js";
|
|
30
30
|
import {
|
|
31
31
|
codexHome,
|
|
32
32
|
pusharyDir
|
|
33
|
-
} from "./chunk-
|
|
33
|
+
} from "./chunk-SRRJLA24.js";
|
|
34
34
|
import {
|
|
35
35
|
writeJsonAtomic
|
|
36
36
|
} from "./chunk-AQFEP65J.js";
|
|
37
37
|
import {
|
|
38
38
|
getApiKey,
|
|
39
39
|
getBaseUrl
|
|
40
|
-
} from "./chunk-
|
|
40
|
+
} from "./chunk-5EX2SD5N.js";
|
|
41
41
|
|
|
42
42
|
// src/transcript-registration.ts
|
|
43
43
|
import { createHash } from "crypto";
|
|
44
44
|
import { readFileSync as readFileSync3, readdirSync as readdirSync2, statSync as statSync3, unlinkSync } from "fs";
|
|
45
|
-
import { isAbsolute, join as join3, resolve as resolve2, sep } from "path";
|
|
45
|
+
import { basename, isAbsolute, join as join3, resolve as resolve2, sep } from "path";
|
|
46
46
|
|
|
47
47
|
// src/transcript-source.ts
|
|
48
48
|
var normalizeTranscriptLines = (lines, source) => {
|
|
@@ -59,11 +59,42 @@ var normalizeTranscriptLines = (lines, source) => {
|
|
|
59
59
|
}
|
|
60
60
|
});
|
|
61
61
|
};
|
|
62
|
+
var createdDuringEpoch = (sighting, epochStartedAtMs) => sighting.birthtimeMs !== null && sighting.birthtimeMs >= epochStartedAtMs && sighting.birthtimeMs <= sighting.seenAtMs;
|
|
63
|
+
var everythingAlreadyWritten = (sighting) => ({ identity: sighting.identity, offset: sighting.sizeBytes, startedBeforeEpoch: true });
|
|
64
|
+
var cutoffAtFirstSight = (sighting, epochStartedAtMs) => sighting.identity === null || createdDuringEpoch(sighting, epochStartedAtMs) ? { identity: sighting.identity, offset: 0, startedBeforeEpoch: false } : everythingAlreadyWritten(sighting);
|
|
65
|
+
var replacedOrShrunk = (previous, sighting) => previous.identity !== sighting.identity || sighting.sizeBytes < previous.offset;
|
|
66
|
+
var nextTranscriptCutoff = (previous, sighting, epochStartedAtMs) => {
|
|
67
|
+
if (!previous) return cutoffAtFirstSight(sighting, epochStartedAtMs);
|
|
68
|
+
if (sighting.identity === null) return previous;
|
|
69
|
+
if (previous.identity === null) return { ...previous, identity: sighting.identity };
|
|
70
|
+
return replacedOrShrunk(previous, sighting) ? everythingAlreadyWritten(sighting) : previous;
|
|
71
|
+
};
|
|
72
|
+
var advancedTranscriptCutoff = (current, readFrom, settledThroughOffset) => current !== void 0 && current.identity === readFrom.identity && settledThroughOffset > current.offset ? { ...current, offset: settledThroughOffset } : current;
|
|
73
|
+
var isTranscriptObject = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
|
|
74
|
+
var parsedTranscriptRecord = (line) => {
|
|
75
|
+
try {
|
|
76
|
+
const value = JSON.parse(line);
|
|
77
|
+
return isTranscriptObject(value) ? value : null;
|
|
78
|
+
} catch {
|
|
79
|
+
return null;
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
var stampedBefore = (record, momentMs) => {
|
|
83
|
+
if (typeof record.timestamp !== "string") return false;
|
|
84
|
+
const stamped = Date.parse(record.timestamp);
|
|
85
|
+
return Number.isFinite(stamped) && stamped < momentMs;
|
|
86
|
+
};
|
|
87
|
+
var isCompactionSummary = (record) => record.isCompactSummary === true;
|
|
88
|
+
var transcriptLinesSeenLive = (lines, epochStartedAtMs, startedBeforeEpoch) => lines.filter((line) => {
|
|
89
|
+
const record = parsedTranscriptRecord(line);
|
|
90
|
+
if (record === null) return true;
|
|
91
|
+
return !stampedBefore(record, epochStartedAtMs) && !(startedBeforeEpoch && isCompactionSummary(record));
|
|
92
|
+
});
|
|
62
93
|
|
|
63
94
|
// src/transcript-sync.ts
|
|
64
95
|
import { homedir as homedir2 } from "os";
|
|
65
96
|
import { join as join2, resolve } from "path";
|
|
66
|
-
import { existsSync as existsSync2, readFileSync as readFileSync2, statSync as statSync2 } from "fs";
|
|
97
|
+
import { closeSync, existsSync as existsSync2, fstatSync, openSync, readFileSync as readFileSync2, readSync, statSync as statSync2 } from "fs";
|
|
67
98
|
|
|
68
99
|
// src/transcript-session-key.ts
|
|
69
100
|
import { existsSync, mkdirSync, readFileSync, readdirSync, rmSync, statSync, writeFileSync } from "fs";
|
|
@@ -72,9 +103,9 @@ import { join } from "path";
|
|
|
72
103
|
var sessionDir = () => process.env.PUSHARY_SESSION_KEY_DIR?.trim() || join(homedir(), ".pushary", "sessions");
|
|
73
104
|
var SESSION_KEY_TTL_MS = 48 * 60 * 60 * 1e3;
|
|
74
105
|
var SAFE_SESSION_ID = /^[A-Za-z0-9._-]{1,128}$/;
|
|
75
|
-
var fileFor = (sessionId) => SAFE_SESSION_ID.test(sessionId) ? join(
|
|
76
|
-
var loadSessionKey = (sessionId) => {
|
|
77
|
-
const path = fileFor(sessionId);
|
|
106
|
+
var fileFor = (sessionId, directory) => SAFE_SESSION_ID.test(sessionId) ? join(directory, `${sessionId}.json`) : null;
|
|
107
|
+
var loadSessionKey = (sessionId, directory = sessionDir()) => {
|
|
108
|
+
const path = fileFor(sessionId, directory);
|
|
78
109
|
if (!path || !existsSync(path)) return null;
|
|
79
110
|
try {
|
|
80
111
|
if (Date.now() - statSync(path).mtimeMs > SESSION_KEY_TTL_MS) return null;
|
|
@@ -92,11 +123,11 @@ var loadSessionKey = (sessionId) => {
|
|
|
92
123
|
return null;
|
|
93
124
|
}
|
|
94
125
|
};
|
|
95
|
-
var saveSessionKey = (sessionId, value) => {
|
|
96
|
-
const path = fileFor(sessionId);
|
|
126
|
+
var saveSessionKey = (sessionId, value, directory = sessionDir()) => {
|
|
127
|
+
const path = fileFor(sessionId, directory);
|
|
97
128
|
if (!path) return;
|
|
98
129
|
try {
|
|
99
|
-
mkdirSync(
|
|
130
|
+
mkdirSync(directory, { recursive: true, mode: 448 });
|
|
100
131
|
writeFileSync(
|
|
101
132
|
path,
|
|
102
133
|
JSON.stringify({
|
|
@@ -111,8 +142,7 @@ var saveSessionKey = (sessionId, value) => {
|
|
|
111
142
|
} catch {
|
|
112
143
|
}
|
|
113
144
|
};
|
|
114
|
-
var sweepStaleSessionKeys = (now = Date.now()) => {
|
|
115
|
-
const dir = sessionDir();
|
|
145
|
+
var sweepStaleSessionKeys = (now = Date.now(), dir = sessionDir()) => {
|
|
116
146
|
if (!existsSync(dir)) return 0;
|
|
117
147
|
let removed = 0;
|
|
118
148
|
try {
|
|
@@ -237,14 +267,75 @@ var readLines = (path) => {
|
|
|
237
267
|
}
|
|
238
268
|
};
|
|
239
269
|
var IDLE_CEILING_MS = 6e4;
|
|
270
|
+
var recordedBirthtime = (info) => process.platform === "darwin" && info.birthtimeMs > 0 ? info.birthtimeMs : null;
|
|
271
|
+
var sightingOf = (info, seenAtMs) => info ? { identity: `${info.dev}:${info.ino}`, sizeBytes: info.size, birthtimeMs: recordedBirthtime(info), seenAtMs } : { identity: null, sizeBytes: 0, birthtimeMs: null, seenAtMs };
|
|
272
|
+
var storeCutoff = (epoch, path, cutoff) => {
|
|
273
|
+
epoch.cutoffs.set(path, cutoff);
|
|
274
|
+
epoch.positions.save(epoch.cutoffs);
|
|
275
|
+
};
|
|
276
|
+
var recordSighting = (epoch, path, sighting) => {
|
|
277
|
+
const previous = epoch.cutoffs.get(path);
|
|
278
|
+
const cutoff = nextTranscriptCutoff(previous, sighting, epoch.startedAtMs);
|
|
279
|
+
if (cutoff !== previous) storeCutoff(epoch, path, cutoff);
|
|
280
|
+
return cutoff;
|
|
281
|
+
};
|
|
282
|
+
var recordSettledPosition = (epoch, path, readFrom, settledThroughOffset) => {
|
|
283
|
+
const current = epoch.cutoffs.get(path);
|
|
284
|
+
const advanced = advancedTranscriptCutoff(current, readFrom, settledThroughOffset);
|
|
285
|
+
if (advanced !== void 0 && advanced !== current) storeCutoff(epoch, path, advanced);
|
|
286
|
+
};
|
|
287
|
+
var forgetUnregisteredTranscripts = (epoch, registeredPaths) => {
|
|
288
|
+
const unregistered = [...epoch.cutoffs.keys()].filter((path) => !registeredPaths.has(path));
|
|
289
|
+
if (unregistered.length === 0) return;
|
|
290
|
+
for (const path of unregistered) epoch.cutoffs.delete(path);
|
|
291
|
+
epoch.positions.save(epoch.cutoffs);
|
|
292
|
+
};
|
|
293
|
+
var statOrNull = (path) => {
|
|
294
|
+
try {
|
|
295
|
+
return statSync2(path);
|
|
296
|
+
} catch {
|
|
297
|
+
return null;
|
|
298
|
+
}
|
|
299
|
+
};
|
|
300
|
+
var sightTranscript = (epoch, path, seenAtMs) => recordSighting(epoch, path, sightingOf(statOrNull(path), seenAtMs));
|
|
301
|
+
var LINE_FEED = 10;
|
|
302
|
+
var nothingUnread = (cutoff) => ({ lines: [], cutoff, completeThroughOffset: cutoff.offset });
|
|
303
|
+
var readLinesSinceCutoff = (epoch, path, seenAtMs) => {
|
|
304
|
+
let descriptor;
|
|
305
|
+
try {
|
|
306
|
+
descriptor = openSync(path, "r");
|
|
307
|
+
} catch {
|
|
308
|
+
return nothingUnread(sightTranscript(epoch, path, seenAtMs));
|
|
309
|
+
}
|
|
310
|
+
try {
|
|
311
|
+
const info = fstatSync(descriptor);
|
|
312
|
+
const cutoff = recordSighting(epoch, path, sightingOf(info, seenAtMs));
|
|
313
|
+
const unread = info.size - cutoff.offset;
|
|
314
|
+
if (unread <= 0) return nothingUnread(cutoff);
|
|
315
|
+
const buffer = Buffer.alloc(unread);
|
|
316
|
+
const received = buffer.subarray(0, readSync(descriptor, buffer, 0, unread, cutoff.offset));
|
|
317
|
+
return {
|
|
318
|
+
lines: received.toString("utf8").split("\n"),
|
|
319
|
+
cutoff,
|
|
320
|
+
completeThroughOffset: cutoff.offset + received.lastIndexOf(LINE_FEED) + 1
|
|
321
|
+
};
|
|
322
|
+
} finally {
|
|
323
|
+
closeSync(descriptor);
|
|
324
|
+
}
|
|
325
|
+
};
|
|
326
|
+
var linesSeenDuringEpoch = (epoch, path, source, seenAtMs) => {
|
|
327
|
+
const read2 = readLinesSinceCutoff(epoch, path, seenAtMs);
|
|
328
|
+
return { ...read2, lines: transcriptLinesSeenLive(normalizeTranscriptLines(read2.lines, source), epoch.startedAtMs, read2.cutoff.startedBeforeEpoch) };
|
|
329
|
+
};
|
|
330
|
+
var nothingLeftToUpload = (state, lines) => state.sessionKey !== null && !state.keyRejected && buildTranscriptRecords(lines, state.sessionKey, state.seen).records.length === 0;
|
|
240
331
|
var nextInterval = (previousMs, idle, baseMs, maxMs) => idle ? Math.min(previousMs * 2, maxMs) : baseMs;
|
|
241
332
|
var startTranscriptSync = (opts) => {
|
|
242
333
|
let warnedAboutRecipients = false;
|
|
243
334
|
const fetchPinnedRecipients = async () => {
|
|
244
|
-
const offer = await fetchTranscriptRecipients(opts.apiKey);
|
|
335
|
+
const offer = await fetchTranscriptRecipients(opts.apiKey, opts.baseUrl);
|
|
245
336
|
if (!offer) return null;
|
|
246
|
-
const verdict = verifyRecipients(offer, loadPin());
|
|
247
|
-
if (verdict.kind === "first-use" && !savePin(verdict.pin)) return null;
|
|
337
|
+
const verdict = verifyRecipients(offer, loadPin(opts.storage?.recipientPinFile));
|
|
338
|
+
if (verdict.kind === "first-use" && !savePin(verdict.pin, opts.storage?.recipientPinFile)) return null;
|
|
248
339
|
if (verdict.kind === "changed") {
|
|
249
340
|
if (!warnedAboutRecipients) {
|
|
250
341
|
warnedAboutRecipients = true;
|
|
@@ -257,12 +348,12 @@ var startTranscriptSync = (opts) => {
|
|
|
257
348
|
};
|
|
258
349
|
const uploader = {
|
|
259
350
|
fetchTranscriptRecipients: fetchPinnedRecipients,
|
|
260
|
-
uploadRecords: (params) => (opts.enabled ? opts.enabled() : transcriptsEnabled()) ? uploadTranscriptRecords(opts.apiKey, params) : Promise.resolve({ ok: false, keyRegistered: false, keyConflict: false, keyUnavailable: false, settledIds: null, rejectedIds: [] })
|
|
351
|
+
uploadRecords: (params) => (opts.enabled ? opts.enabled() : transcriptsEnabled()) ? uploadTranscriptRecords(opts.apiKey, params, opts.baseUrl) : Promise.resolve({ ok: false, keyRegistered: false, keyConflict: false, keyUnavailable: false, settledIds: null, rejectedIds: [] })
|
|
261
352
|
};
|
|
262
353
|
const path = opts.path ?? claudeTranscriptPath(opts.cwd, opts.sessionId);
|
|
263
|
-
const persisted = loadSessionKey(opts.sessionId);
|
|
354
|
+
const persisted = loadSessionKey(opts.sessionId, opts.storage?.sessionKeyDirectory);
|
|
264
355
|
let state = persisted ? { ...createSyncState(), ...persisted } : createSyncState();
|
|
265
|
-
sweepStaleSessionKeys();
|
|
356
|
+
sweepStaleSessionKeys(Date.now(), opts.storage?.sessionKeyDirectory);
|
|
266
357
|
let persistedUploaded = persisted?.keyUploaded ?? false;
|
|
267
358
|
let running = true;
|
|
268
359
|
let inFlight = false;
|
|
@@ -273,7 +364,9 @@ var startTranscriptSync = (opts) => {
|
|
|
273
364
|
const before = state.sessionKey;
|
|
274
365
|
const ending = opts.ending?.() === true;
|
|
275
366
|
const modified = existsSync2(path) ? statSync2(path).mtimeMs : null;
|
|
276
|
-
const
|
|
367
|
+
const source = opts.source ?? "claude";
|
|
368
|
+
const read2 = opts.epoch ? linesSeenDuringEpoch(opts.epoch, path, source, Date.now()) : null;
|
|
369
|
+
const lines = read2?.lines ?? normalizeTranscriptLines(readLines(path), source);
|
|
277
370
|
state = await syncTick(lines, state, uploader, opts.sessionId, opts.machineId);
|
|
278
371
|
if (state.sessionKey && (before !== state.sessionKey || state.keyUploaded !== persistedUploaded)) {
|
|
279
372
|
persistedUploaded = state.keyUploaded;
|
|
@@ -283,9 +376,10 @@ var startTranscriptSync = (opts) => {
|
|
|
283
376
|
providerWrappedKey: state.providerWrappedKey,
|
|
284
377
|
providerKeyId: state.providerKeyId,
|
|
285
378
|
keyUploaded: state.keyUploaded
|
|
286
|
-
});
|
|
379
|
+
}, opts.storage?.sessionKeyDirectory);
|
|
287
380
|
}
|
|
288
|
-
if (
|
|
381
|
+
if (opts.epoch && read2 && nothingLeftToUpload(state, lines)) recordSettledPosition(opts.epoch, path, read2.cutoff, read2.completeThroughOffset);
|
|
382
|
+
if (ending && opts.ending?.() && existsSync2(path) && statSync2(path).mtimeMs === modified && state.keyUploaded && nothingLeftToUpload(state, lines)) opts.onDrained?.();
|
|
289
383
|
} catch {
|
|
290
384
|
} finally {
|
|
291
385
|
inFlight = false;
|
|
@@ -316,17 +410,20 @@ var startTranscriptSync = (opts) => {
|
|
|
316
410
|
|
|
317
411
|
// src/transcript-registration.ts
|
|
318
412
|
import { homedir as homedir3 } from "os";
|
|
319
|
-
var
|
|
320
|
-
var
|
|
413
|
+
var defaultRegistryDirectory = () => process.env.PUSHARY_TRANSCRIPT_REGISTRY_DIR || join3(pusharyDir(), "transcript-capture");
|
|
414
|
+
var cliRegistry = (apiKey = getApiKey()) => ({ apiKey, baseUrl: getBaseUrl(), directory: defaultRegistryDirectory() });
|
|
415
|
+
var accountFor = (registry) => createHash("sha256").update(`${registry.baseUrl}\0${registry.apiKey}`).digest("hex");
|
|
321
416
|
var TTL = 48 * 60 * 60 * 1e3;
|
|
322
417
|
var read = (path) => JSON.parse(readFileSync3(path, "utf8"));
|
|
323
418
|
var consent = (record) => record.consentOverride ?? readTranscriptPreference() ?? false;
|
|
324
|
-
var
|
|
325
|
-
var
|
|
326
|
-
var
|
|
419
|
+
var withoutTrailingSlash = (url) => url.replace(/\/+$/, "");
|
|
420
|
+
var sameServer = (url, registry) => withoutTrailingSlash(url) === withoutTrailingSlash(registry.baseUrl);
|
|
421
|
+
var fileFor2 = (registry, sessionId) => join3(registry.directory, `${createHash("sha256").update(accountFor(registry) + sessionId).digest("hex")}.json`);
|
|
422
|
+
var permitted = (registry, raw) => raw.account === accountFor(registry) && consent(raw) && !raw.drained && (raw.source !== "claude" || !!raw.expectedSiteId || !macOwnsClaudeHooks(raw.cwd)) && (!raw.expectedSiteId || raw.expectedSiteId === raw.verifiedSiteId && !!raw.expectedBaseUrl && sameServer(raw.expectedBaseUrl, registry));
|
|
327
423
|
var registeredTranscriptEnabled = (apiKey, sessionId) => {
|
|
424
|
+
const registry = cliRegistry(apiKey);
|
|
328
425
|
try {
|
|
329
|
-
return permitted(
|
|
426
|
+
return permitted(registry, read(fileFor2(registry, sessionId)));
|
|
330
427
|
} catch {
|
|
331
428
|
return false;
|
|
332
429
|
}
|
|
@@ -342,25 +439,29 @@ var macOwnsClaudeHooks = (cwd) => [
|
|
|
342
439
|
return false;
|
|
343
440
|
}
|
|
344
441
|
});
|
|
442
|
+
var TRANSCRIPT_ROOT_NAME = { claude: "projects", codex: "sessions" };
|
|
345
443
|
var transcriptRoots = (source) => {
|
|
346
444
|
const home = homedir3();
|
|
347
|
-
if (source === "codex") return [join3(codexHome(),
|
|
445
|
+
if (source === "codex") return [join3(codexHome(), TRANSCRIPT_ROOT_NAME.codex)];
|
|
348
446
|
const configured = process.env.CLAUDE_CONFIG_DIR;
|
|
349
|
-
return [join3(configured || join3(home, ".claude"),
|
|
447
|
+
return [join3(configured || join3(home, ".claude"), TRANSCRIPT_ROOT_NAME.claude), join3(home, ".claude", TRANSCRIPT_ROOT_NAME.claude)];
|
|
350
448
|
};
|
|
351
|
-
var
|
|
449
|
+
var isAgentTranscriptRoot = (root, source) => isAbsolute(root) && resolve2(root) === root && basename(root) === TRANSCRIPT_ROOT_NAME[source];
|
|
450
|
+
var acceptedTranscriptRoots = (source, registeredRoot) => typeof registeredRoot === "string" && isAgentTranscriptRoot(registeredRoot, source) ? [...transcriptRoots(source), registeredRoot] : transcriptRoots(source);
|
|
451
|
+
var transcriptRootContaining = (candidate, roots) => {
|
|
352
452
|
const target = resolve2(candidate);
|
|
353
|
-
return
|
|
453
|
+
return roots.map((root) => resolve2(root)).find((root) => target.startsWith(root + sep)) ?? null;
|
|
354
454
|
};
|
|
355
|
-
var captureRegistration = (source, value) => {
|
|
455
|
+
var captureRegistration = (source, value, registeredRoot) => {
|
|
356
456
|
const input = value;
|
|
357
457
|
if (source !== "claude" && source !== "codex") return null;
|
|
358
458
|
if (input.agent_id || typeof input.session_id !== "string" || !/^[\w-]{1,128}$/.test(input.session_id)) return null;
|
|
359
459
|
if (typeof input.cwd !== "string" || !isAbsolute(input.cwd)) return null;
|
|
360
460
|
const path = input.transcript_path ?? input.agent_transcript_path ?? (source === "claude" ? claudeTranscriptPath(input.cwd, input.session_id) : null);
|
|
361
461
|
if (typeof path !== "string" || !isAbsolute(path) || !path.endsWith(".jsonl")) return null;
|
|
362
|
-
|
|
363
|
-
|
|
462
|
+
const root = transcriptRootContaining(path, acceptedTranscriptRoots(source, registeredRoot));
|
|
463
|
+
if (root === null) return null;
|
|
464
|
+
return { sessionId: input.session_id, cwd: input.cwd, path, source, root };
|
|
364
465
|
};
|
|
365
466
|
var registerTranscript = (source, input, startDaemon = () => {
|
|
366
467
|
void ensureDaemonRunning({ waitTimeoutMs: 0 }).catch(() => {
|
|
@@ -369,8 +470,9 @@ var registerTranscript = (source, input, startDaemon = () => {
|
|
|
369
470
|
const registration = captureRegistration(source, input);
|
|
370
471
|
if (!registration) return;
|
|
371
472
|
try {
|
|
372
|
-
const
|
|
373
|
-
const
|
|
473
|
+
const registry = options.registry ?? cliRegistry();
|
|
474
|
+
const account = accountFor(registry);
|
|
475
|
+
const path = fileFor2(registry, registration.sessionId);
|
|
374
476
|
let previous;
|
|
375
477
|
try {
|
|
376
478
|
previous = read(path);
|
|
@@ -381,7 +483,7 @@ var registerTranscript = (source, input, startDaemon = () => {
|
|
|
381
483
|
const stored = {
|
|
382
484
|
...registration,
|
|
383
485
|
account,
|
|
384
|
-
consentOverride: transcriptEnvironmentPreference(),
|
|
486
|
+
consentOverride: options.consentOverride ?? transcriptEnvironmentPreference(),
|
|
385
487
|
// A wrapper refresh must not erase the Mac's account binding.
|
|
386
488
|
expectedSiteId: options.siteId ?? previous?.expectedSiteId,
|
|
387
489
|
expectedBaseUrl: options.baseUrl ?? previous?.expectedBaseUrl,
|
|
@@ -394,19 +496,33 @@ var registerTranscript = (source, input, startDaemon = () => {
|
|
|
394
496
|
} catch {
|
|
395
497
|
}
|
|
396
498
|
};
|
|
397
|
-
var
|
|
499
|
+
var sightRegisteredTranscripts = (epoch, registry, listing) => {
|
|
500
|
+
const seenAtMs = Date.now();
|
|
501
|
+
const registeredPaths = /* @__PURE__ */ new Set();
|
|
502
|
+
for (const raw of listing.records) {
|
|
503
|
+
const registration = captureRegistration(raw.source, { session_id: raw.sessionId, cwd: raw.cwd, transcript_path: raw.path }, raw.root);
|
|
504
|
+
if (!registration) continue;
|
|
505
|
+
registeredPaths.add(registration.path);
|
|
506
|
+
if (raw.account === accountFor(registry) && !raw.drained) sightTranscript(epoch, registration.path, seenAtMs);
|
|
507
|
+
}
|
|
508
|
+
if (listing.complete) forgetUnregisteredTranscripts(epoch, registeredPaths);
|
|
509
|
+
};
|
|
510
|
+
var startRegisteredTranscripts = (apiKey, machineId, options = {}) => {
|
|
511
|
+
const { intervalMs = 3e3, enabled = () => true, storage, epoch } = options;
|
|
512
|
+
const registry = { apiKey, baseUrl: options.baseUrl ?? getBaseUrl(), directory: options.registryDirectory ?? defaultRegistryDirectory() };
|
|
398
513
|
const active = /* @__PURE__ */ new Map();
|
|
399
514
|
let stopped = false;
|
|
400
515
|
let scanning = false;
|
|
401
516
|
let verifiedSiteId;
|
|
402
517
|
let nextVerification = 0;
|
|
403
518
|
const tick = async () => {
|
|
404
|
-
if (stopped || scanning) return;
|
|
519
|
+
if (stopped || scanning || !enabled()) return;
|
|
405
520
|
scanning = true;
|
|
406
521
|
const wanted = /* @__PURE__ */ new Map();
|
|
407
522
|
try {
|
|
408
|
-
|
|
409
|
-
|
|
523
|
+
let unreadable = 0;
|
|
524
|
+
const files = readdirSync2(registry.directory).filter((name) => name.endsWith(".json")).flatMap((name) => {
|
|
525
|
+
const path = join3(registry.directory, name);
|
|
410
526
|
try {
|
|
411
527
|
const time = statSync3(path).mtimeMs;
|
|
412
528
|
if (Date.now() - time > TTL) {
|
|
@@ -415,16 +531,18 @@ var startRegisteredTranscripts = (apiKey, machineId, intervalMs = 3e3) => {
|
|
|
415
531
|
}
|
|
416
532
|
return [{ path, time, raw: read(path) }];
|
|
417
533
|
} catch {
|
|
534
|
+
unreadable += 1;
|
|
418
535
|
return [];
|
|
419
536
|
}
|
|
420
537
|
}).sort((a, b) => Number(!!a.raw.endedAt) - Number(!!b.raw.endedAt) || b.time - a.time);
|
|
538
|
+
if (epoch) sightRegisteredTranscripts(epoch, registry, { records: files.map((file) => file.raw), complete: unreadable === 0 });
|
|
421
539
|
for (const file of files) {
|
|
422
540
|
const raw = file.raw;
|
|
423
|
-
if (raw.account !== accountFor(
|
|
424
|
-
if (raw.expectedSiteId && !verifiedSiteId && Date.now() >= nextVerification && raw.expectedBaseUrl && sameServer(raw.expectedBaseUrl)) {
|
|
541
|
+
if (raw.account !== accountFor(registry) || !consent(raw) || raw.drained) continue;
|
|
542
|
+
if (raw.expectedSiteId && !verifiedSiteId && Date.now() >= nextVerification && raw.expectedBaseUrl && sameServer(raw.expectedBaseUrl, registry)) {
|
|
425
543
|
nextVerification = Date.now() + 3e4;
|
|
426
544
|
try {
|
|
427
|
-
const response = await fetch(`${
|
|
545
|
+
const response = await fetch(`${registry.baseUrl}/api/agent/encryption-account`, {
|
|
428
546
|
headers: { Authorization: `Bearer ${apiKey}` },
|
|
429
547
|
signal: AbortSignal.timeout(5e3)
|
|
430
548
|
});
|
|
@@ -433,18 +551,18 @@ var startRegisteredTranscripts = (apiKey, machineId, intervalMs = 3e3) => {
|
|
|
433
551
|
} catch {
|
|
434
552
|
}
|
|
435
553
|
}
|
|
436
|
-
if (raw.expectedSiteId && raw.expectedSiteId === verifiedSiteId && raw.expectedBaseUrl && sameServer(raw.expectedBaseUrl) && raw.verifiedSiteId !== verifiedSiteId) {
|
|
554
|
+
if (raw.expectedSiteId && raw.expectedSiteId === verifiedSiteId && raw.expectedBaseUrl && sameServer(raw.expectedBaseUrl, registry) && raw.verifiedSiteId !== verifiedSiteId) {
|
|
437
555
|
const latest = read(file.path);
|
|
438
556
|
if (JSON.stringify(latest) !== JSON.stringify(raw)) continue;
|
|
439
557
|
raw.verifiedSiteId = verifiedSiteId;
|
|
440
558
|
writeJsonAtomic(file.path, raw, 384);
|
|
441
559
|
}
|
|
442
|
-
if (!permitted(
|
|
560
|
+
if (!permitted(registry, raw)) continue;
|
|
443
561
|
if (wanted.size >= (raw.endedAt ? 33 : 32)) continue;
|
|
444
|
-
const registration = captureRegistration(raw.source, { session_id: raw.sessionId, cwd: raw.cwd, transcript_path: raw.path });
|
|
562
|
+
const registration = captureRegistration(raw.source, { session_id: raw.sessionId, cwd: raw.cwd, transcript_path: raw.path }, raw.root);
|
|
445
563
|
if (registration) wanted.set(registration.sessionId, { ...registration, registrationPath: file.path });
|
|
446
564
|
}
|
|
447
|
-
if (stopped) return;
|
|
565
|
+
if (stopped || !enabled()) return;
|
|
448
566
|
for (const [id, reader] of active) {
|
|
449
567
|
if (wanted.get(id)?.path === reader.path) continue;
|
|
450
568
|
reader.stop();
|
|
@@ -458,9 +576,12 @@ var startRegisteredTranscripts = (apiKey, machineId, intervalMs = 3e3) => {
|
|
|
458
576
|
machineId,
|
|
459
577
|
...registration,
|
|
460
578
|
intervalMs,
|
|
579
|
+
baseUrl: registry.baseUrl,
|
|
580
|
+
storage,
|
|
581
|
+
epoch,
|
|
461
582
|
enabled: () => {
|
|
462
583
|
try {
|
|
463
|
-
return permitted(
|
|
584
|
+
return !stopped && enabled() && permitted(registry, current());
|
|
464
585
|
} catch {
|
|
465
586
|
return false;
|
|
466
587
|
}
|
|
@@ -3,11 +3,11 @@ import {
|
|
|
3
3
|
decodePublicKey,
|
|
4
4
|
generateSessionKey,
|
|
5
5
|
wrapSessionKey
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-7447DYNW.js";
|
|
7
7
|
import {
|
|
8
8
|
fetchTranscriptRecipients,
|
|
9
9
|
uploadTranscriptRecords
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-EPVY3JU3.js";
|
|
11
11
|
|
|
12
12
|
// src/live-session.ts
|
|
13
13
|
var MAX_TRANSCRIPT_QUEUE = 100;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
ensureCodexTrustsPusharyHooks
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-Q2GSTQ3R.js";
|
|
4
4
|
import {
|
|
5
5
|
detectClaudeVersion
|
|
6
6
|
} from "./chunk-RIVNNBEK.js";
|
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
openCodeHookArgv,
|
|
13
13
|
openCodePluginDir,
|
|
14
14
|
openCodeWired
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-OULHOX5C.js";
|
|
16
16
|
import {
|
|
17
17
|
addClaudeMcpServer,
|
|
18
18
|
addCompatibleHooks,
|
|
@@ -20,7 +20,7 @@ import {
|
|
|
20
20
|
addPusharyToolPermissions,
|
|
21
21
|
compatibleConfigFile,
|
|
22
22
|
hasCompatibleHooks
|
|
23
|
-
} from "./chunk-
|
|
23
|
+
} from "./chunk-SAHD5DYW.js";
|
|
24
24
|
import {
|
|
25
25
|
claudeUnprovenHolds,
|
|
26
26
|
claudeWired,
|
|
@@ -28,7 +28,7 @@ import {
|
|
|
28
28
|
codexWired,
|
|
29
29
|
geminiWired,
|
|
30
30
|
planHooks
|
|
31
|
-
} from "./chunk-
|
|
31
|
+
} from "./chunk-FXJ5SEQT.js";
|
|
32
32
|
import {
|
|
33
33
|
CLAUDE_HOOK_BINARY,
|
|
34
34
|
CLAUDE_HOOK_EVENTS,
|
|
@@ -39,7 +39,7 @@ import {
|
|
|
39
39
|
needsReregistration,
|
|
40
40
|
registrationSignatures,
|
|
41
41
|
supportedClaudeEvents
|
|
42
|
-
} from "./chunk-
|
|
42
|
+
} from "./chunk-OS6AE2MR.js";
|
|
43
43
|
import {
|
|
44
44
|
formatVersion
|
|
45
45
|
} from "./chunk-6ICPEJY5.js";
|
|
@@ -63,7 +63,7 @@ import {
|
|
|
63
63
|
resolveGlobalBinDir,
|
|
64
64
|
resolveGlobalBinary,
|
|
65
65
|
vscodePluginMcp
|
|
66
|
-
} from "./chunk-
|
|
66
|
+
} from "./chunk-SRRJLA24.js";
|
|
67
67
|
import {
|
|
68
68
|
readJsonSafe,
|
|
69
69
|
writeFileAtomic,
|
|
@@ -73,7 +73,7 @@ import {
|
|
|
73
73
|
HOOK_COMPATIBLE_PROFILES,
|
|
74
74
|
isCompatibleAgentType,
|
|
75
75
|
isRecord
|
|
76
|
-
} from "./chunk-
|
|
76
|
+
} from "./chunk-TDLEFGAM.js";
|
|
77
77
|
|
|
78
78
|
// src/reapply.ts
|
|
79
79
|
import { dirname, join } from "path";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
resolveInstallSourceFor
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-KBRKQMCI.js";
|
|
4
4
|
import {
|
|
5
5
|
backupFile,
|
|
6
6
|
readJsonSafe,
|
|
@@ -9,11 +9,11 @@ import {
|
|
|
9
9
|
} from "./chunk-AQFEP65J.js";
|
|
10
10
|
import {
|
|
11
11
|
configFilePath
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-5EX2SD5N.js";
|
|
13
13
|
import {
|
|
14
14
|
API_KEY_PREFIX_PATTERN,
|
|
15
15
|
isRecord
|
|
16
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-TDLEFGAM.js";
|
|
17
17
|
|
|
18
18
|
// src/shell-alias.ts
|
|
19
19
|
import { homedir } from "os";
|
|
@@ -4,10 +4,10 @@ import {
|
|
|
4
4
|
keyPrefix,
|
|
5
5
|
readConfigFileKey,
|
|
6
6
|
readMacAppKeyPrefix
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-IKJJB4QG.js";
|
|
8
8
|
import {
|
|
9
9
|
NPX_LATEST_COMMAND
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-2ROXUEZV.js";
|
|
11
11
|
|
|
12
12
|
// src/key-signed-out.ts
|
|
13
13
|
var VERDICT_BY_CHECK = {
|
|
@@ -5,16 +5,16 @@ import {
|
|
|
5
5
|
import {
|
|
6
6
|
NOTIFICATION_MATCHED_TYPES,
|
|
7
7
|
POSTTOOLUSE_MIRRORED_TOOLS
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-4JOWKPUF.js";
|
|
9
9
|
import {
|
|
10
10
|
isProtectedByScope,
|
|
11
11
|
registerHookEntry
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-SRRJLA24.js";
|
|
13
13
|
import {
|
|
14
14
|
CLAUDE_PRETOOLUSE_MATCHER,
|
|
15
15
|
HOOK_BUDGETS,
|
|
16
16
|
HOOK_LOCATOR_BINARY
|
|
17
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-TDLEFGAM.js";
|
|
18
18
|
|
|
19
19
|
// src/gemini-config.ts
|
|
20
20
|
var GEMINI_HOOK_BINARY = "pushary-gemini-hook";
|