pushary 1.9.88 → 1.9.90
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 +9 -0
- package/dist/{api-BE4B7HBE.js → api-ORGHXO4N.js} +10 -10
- package/dist/bin/pushary-bell-hook.js +26 -26
- package/dist/bin/pushary-bell.js +10 -10
- package/dist/bin/pushary-claude.js +27 -27
- package/dist/bin/pushary-clean.js +34 -34
- package/dist/bin/pushary-codex-bridge.js +21 -21
- package/dist/bin/pushary-codex-hook.js +31 -31
- package/dist/bin/pushary-codex-session.js +8 -8
- package/dist/bin/pushary-codex.js +14 -14
- package/dist/bin/pushary-connect.js +27 -27
- package/dist/bin/pushary-cowork.js +5 -5
- package/dist/bin/pushary-daemon.js +39 -39
- package/dist/bin/pushary-disconnect.js +26 -26
- package/dist/bin/pushary-display-hook.js +17 -17
- package/dist/bin/pushary-doctor.js +42 -42
- package/dist/bin/pushary-elicitation-hook.js +26 -26
- package/dist/bin/pushary-gemini-bridge.js +15 -15
- package/dist/bin/pushary-gemini-hook.js +28 -28
- package/dist/bin/pushary-hook.js +30 -30
- package/dist/bin/pushary-login.js +20 -20
- package/dist/bin/pushary-logout.js +25 -25
- package/dist/bin/pushary-mcp.js +11 -11
- package/dist/bin/pushary-mode.js +15 -15
- 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 +30 -30
- 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 +27 -27
- package/dist/bin/pushary-session-start-hook.js +35 -35
- package/dist/bin/pushary-setup.js +48 -48
- package/dist/bin/pushary-stats.js +5 -5
- package/dist/bin/pushary-status.js +32 -32
- package/dist/bin/pushary-stop-hook.js +25 -25
- package/dist/bin/pushary-stopfailure-hook.js +25 -25
- package/dist/bin/pushary-suggestions.js +15 -15
- package/dist/bin/pushary-transcript-register.js +18 -18
- package/dist/bin/pushary-transcripts.js +59 -30
- package/dist/bin/pushary-upgrade.js +40 -40
- package/dist/bin/pushary-wait.js +15 -15
- package/dist/bin/pushary.js +7 -7
- package/dist/{chunk-N7OMDSXK.js → chunk-2EOTXWFK.js} +3 -3
- package/dist/{chunk-3BG5S7MB.js → chunk-2RUJIPNN.js} +2 -2
- package/dist/{chunk-Z2LYELNQ.js → chunk-2U6FPMXG.js} +3 -3
- package/dist/{chunk-NP65LEAY.js → chunk-32F3BWRY.js} +1 -1
- package/dist/{chunk-2NJNC26C.js → chunk-3EVOYLXQ.js} +5 -5
- package/dist/{chunk-QQCGYHYG.js → chunk-3N4GETIW.js} +2 -2
- package/dist/{chunk-FRUKY6KV.js → chunk-4V25M4X5.js} +2 -2
- package/dist/{chunk-JQMOQLM2.js → chunk-53YQO4HL.js} +151 -93
- package/dist/{chunk-6RFDH4JU.js → chunk-5DTOMJVD.js} +2 -2
- package/dist/{chunk-3ZE7VQOU.js → chunk-6B4O7XNC.js} +6 -6
- package/dist/{chunk-P4W5TP2X.js → chunk-6LJOCQBB.js} +1 -1
- package/dist/{chunk-CAXE3TYX.js → chunk-6P4II3ZL.js} +5 -5
- package/dist/{chunk-JOULYVW6.js → chunk-72UCLJJW.js} +1 -1
- package/dist/{chunk-LHXJYSNX.js → chunk-7BEQB3X4.js} +1 -1
- package/dist/{chunk-NOGDU4XS.js → chunk-7EGNVZLK.js} +2 -2
- package/dist/{chunk-I6MNMAS7.js → chunk-7MN3KPHM.js} +38 -38
- package/dist/{chunk-RKX2ZOIG.js → chunk-AF3OHGKE.js} +1 -1
- package/dist/{chunk-O53SJBBB.js → chunk-ALT4KW5M.js} +5 -5
- package/dist/{chunk-D7ZJ3AUK.js → chunk-ALTGRWSO.js} +1 -1
- package/dist/{chunk-6GDZ4RYR.js → chunk-APT7KJ5I.js} +6 -6
- package/dist/{chunk-33RQ7I3K.js → chunk-ASTOMXHJ.js} +1 -1
- package/dist/{chunk-BSTZ66FA.js → chunk-CDBGZWPY.js} +3 -3
- package/dist/{chunk-M4UXDYNJ.js → chunk-CE2ISNPN.js} +5 -5
- package/dist/{chunk-BC2HT6JP.js → chunk-CNFM6JEV.js} +2 -2
- package/dist/{chunk-4C7OJLSL.js → chunk-DADN6GJO.js} +4 -4
- package/dist/{chunk-RPXPRBBA.js → chunk-E3EJARHF.js} +1 -1
- package/dist/{chunk-KWWHFTNJ.js → chunk-E4XGV5UG.js} +3 -2
- package/dist/{chunk-JQPY2B2H.js → chunk-EFQQLEWW.js} +4 -4
- package/dist/{chunk-TXJ65MIV.js → chunk-FAM2TLFC.js} +1 -1
- package/dist/{chunk-3XJL2M7H.js → chunk-FSJYYZ3G.js} +5 -5
- package/dist/{chunk-4Z7MR5FE.js → chunk-G7GVI5RL.js} +3 -3
- package/dist/{chunk-DWUD47H5.js → chunk-G7MVZHMM.js} +2 -2
- package/dist/{chunk-FK2EK27I.js → chunk-GKDVI6WX.js} +3 -3
- package/dist/{chunk-LXFBSMAE.js → chunk-HKGGENVU.js} +6 -6
- package/dist/{chunk-FUVVGIXZ.js → chunk-HT5WOP2M.js} +6 -6
- package/dist/{chunk-LH3SNS6H.js → chunk-I567L2KG.js} +10 -10
- package/dist/{chunk-QOMIFKQL.js → chunk-I7UZODYO.js} +3 -3
- package/dist/{chunk-DHVVEH2K.js → chunk-INNH7EUK.js} +10 -10
- package/dist/{chunk-4TT2ZFWZ.js → chunk-JJNO3ACZ.js} +3 -3
- package/dist/{chunk-GJXRYXMC.js → chunk-JQUMX7YZ.js} +2 -2
- package/dist/{chunk-B4NVYPX5.js → chunk-K2NIENKY.js} +1 -1
- package/dist/{chunk-OUIUIJV4.js → chunk-K6QLKUCT.js} +1 -1
- package/dist/{chunk-ZXDHPPGI.js → chunk-KT25MC57.js} +4 -4
- package/dist/{chunk-2HTE4ECJ.js → chunk-LGQQUQDZ.js} +4 -4
- package/dist/{chunk-DM5LNEGJ.js → chunk-LJFITB6T.js} +4 -4
- package/dist/{chunk-KXGKUV2F.js → chunk-MWXX34K4.js} +1 -1
- package/dist/{chunk-2JTWOTOC.js → chunk-NIZ6ITRH.js} +1 -1
- package/dist/{chunk-OBS7O22Q.js → chunk-NMDWW3EY.js} +3 -3
- package/dist/{chunk-ZEPS4KIK.js → chunk-NWSGMYX7.js} +4 -4
- package/dist/{chunk-TBPMI4LY.js → chunk-OEPP5VUW.js} +6 -6
- package/dist/{chunk-RX5FSSQK.js → chunk-OGR5WSHI.js} +7 -7
- package/dist/{chunk-FFIDXKQ7.js → chunk-OH67LB2U.js} +14 -14
- package/dist/{chunk-ZP5AB6R5.js → chunk-OODEIR3Z.js} +6 -6
- package/dist/{chunk-3C4UGMIV.js → chunk-P4OZVK2B.js} +4 -4
- package/dist/{chunk-A2F7T3IR.js → chunk-QCSPLJL6.js} +3 -3
- package/dist/{chunk-NWLGRSGE.js → chunk-QUKDNQ4L.js} +3 -3
- package/dist/{chunk-ZUIAABLS.js → chunk-SJCPI4WT.js} +1 -1
- package/dist/{chunk-IXOCJHJW.js → chunk-TOPXBWUN.js} +2 -2
- package/dist/{chunk-YN4IXOFK.js → chunk-TTXUWHBL.js} +1 -1
- package/dist/{chunk-MQKXQWXA.js → chunk-URJHH72Z.js} +1 -1
- package/dist/{chunk-STQEIEYJ.js → chunk-V4ZLZYQ4.js} +3 -3
- package/dist/{chunk-BOWXZWHG.js → chunk-VMUBIBHQ.js} +7 -7
- package/dist/{chunk-VIDB26GQ.js → chunk-VTF6EYVB.js} +5 -5
- package/dist/{chunk-PYI2EFRH.js → chunk-WGBW66IO.js} +5 -5
- package/dist/{chunk-PG5WFIHE.js → chunk-XBXBX7YF.js} +2 -2
- package/dist/{chunk-LAYKEYZE.js → chunk-XIPP777K.js} +3 -3
- package/dist/{chunk-4PS27SCG.js → chunk-XO3UJDJE.js} +26 -8
- package/dist/{chunk-WBZA72O5.js → chunk-XRSE2PAM.js} +3 -3
- package/dist/{chunk-OMLR56J5.js → chunk-Y5BPNOJI.js} +1 -1
- package/dist/{codex-app-cards-switch-XLSLVXDP.js → codex-app-cards-switch-UQ7TGFYV.js} +11 -11
- package/dist/{codex-desktop-launch-HRE6YP56.js → codex-desktop-launch-O5FWONZ7.js} +1 -1
- package/dist/{codex-session-launch-7RGYGW32.js → codex-session-launch-MTKJC2RH.js} +18 -18
- package/dist/{config-ZDOHQUNU.js → config-EGBMIS5K.js} +3 -3
- package/dist/{global-upgrade-VR76ZRWG.js → global-upgrade-QOAUUHZ6.js} +10 -10
- package/dist/{identity-NJAXA45Q.js → identity-Z5TRRQL5.js} +4 -4
- package/dist/{live-capabilities-5UTM55OC.js → live-capabilities-M4HOY7EM.js} +5 -5
- package/dist/{paths-BX4DXC3B.js → paths-ZOS6Y3PS.js} +3 -3
- package/dist/{reapply-PMCMNTED.js → reapply-PYDRWYKU.js} +28 -28
- package/dist/src/index.js +29 -29
- package/dist/{upgrade-lock-2G2S3FH7.js → upgrade-lock-QZOSOFK5.js} +4 -4
- package/dist/{usage-3EPWR2WQ.js → usage-4FVOG3QN.js} +3 -3
- package/package.json +2 -2
- /package/dist/{chunk-5TLDFPW6.js → chunk-VE333PL5.js} +0 -0
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import {
|
|
2
2
|
SESSION_HISTORY_RETENTION_DAYS,
|
|
3
|
+
readOwnerOnlyJson,
|
|
3
4
|
savedTranscriptReadPositions
|
|
4
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-7MN3KPHM.js";
|
|
5
6
|
import {
|
|
6
7
|
ensureDaemonRunning
|
|
7
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-HT5WOP2M.js";
|
|
8
9
|
import {
|
|
9
10
|
hookOwnerOf
|
|
10
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-LJFITB6T.js";
|
|
11
12
|
import {
|
|
12
13
|
buildTranscriptRecords,
|
|
13
14
|
decodePublicKey,
|
|
@@ -18,33 +19,33 @@ import {
|
|
|
18
19
|
recordSealerFor,
|
|
19
20
|
uploadTranscriptRecords,
|
|
20
21
|
wrapSessionKey
|
|
21
|
-
} from "./chunk-
|
|
22
|
+
} from "./chunk-XO3UJDJE.js";
|
|
22
23
|
import {
|
|
23
24
|
external_exports
|
|
24
25
|
} from "./chunk-XMSDA5WA.js";
|
|
25
26
|
import {
|
|
26
27
|
transcriptEnvironmentPreference,
|
|
27
28
|
transcriptsEnabled
|
|
28
|
-
} from "./chunk-
|
|
29
|
+
} from "./chunk-72UCLJJW.js";
|
|
29
30
|
import {
|
|
30
31
|
readTranscriptPreference
|
|
31
|
-
} from "./chunk-
|
|
32
|
+
} from "./chunk-LGQQUQDZ.js";
|
|
32
33
|
import {
|
|
33
34
|
hookMeaning
|
|
34
|
-
} from "./chunk-
|
|
35
|
+
} from "./chunk-FAM2TLFC.js";
|
|
35
36
|
import {
|
|
36
37
|
claudeConfigDir,
|
|
37
38
|
codexHome,
|
|
38
39
|
pusharyDir
|
|
39
|
-
} from "./chunk-
|
|
40
|
+
} from "./chunk-7EGNVZLK.js";
|
|
40
41
|
import {
|
|
41
42
|
writeJsonAtomic,
|
|
42
43
|
writeJsonAtomicDurable
|
|
43
|
-
} from "./chunk-
|
|
44
|
+
} from "./chunk-I7UZODYO.js";
|
|
44
45
|
import {
|
|
45
46
|
getApiKey,
|
|
46
47
|
getBaseUrl
|
|
47
|
-
} from "./chunk-
|
|
48
|
+
} from "./chunk-32F3BWRY.js";
|
|
48
49
|
import {
|
|
49
50
|
PENDING_COMMAND_PREFIX,
|
|
50
51
|
SESSION_HISTORY_BACKFILL_LIMIT_BYTES,
|
|
@@ -52,33 +53,33 @@ import {
|
|
|
52
53
|
isHookSource,
|
|
53
54
|
isRecord,
|
|
54
55
|
redactSecretsFromContent
|
|
55
|
-
} from "./chunk-
|
|
56
|
+
} from "./chunk-VE333PL5.js";
|
|
56
57
|
|
|
57
58
|
// src/transcript-recipient-pin.ts
|
|
58
|
-
import {
|
|
59
|
+
import { createHash } from "crypto";
|
|
60
|
+
import { mkdirSync, rmSync } from "fs";
|
|
59
61
|
import { homedir } from "os";
|
|
60
62
|
import { dirname, join } from "path";
|
|
61
|
-
var
|
|
63
|
+
var recipientPinFile = () => process.env.PUSHARY_RECIPIENT_PIN_FILE?.trim() || join(homedir(), ".pushary", "recipients.json");
|
|
62
64
|
var asPin = (offer) => ({
|
|
63
65
|
phonePublicKey: offer.phonePublicKey,
|
|
64
66
|
providerKeyId: offer.provider?.keyId ?? null,
|
|
65
67
|
providerPublicKey: offer.provider?.publicKey ?? null
|
|
66
68
|
});
|
|
67
|
-
var
|
|
68
|
-
|
|
69
|
+
var pinnedRecipientsSchema = external_exports.object({
|
|
70
|
+
phonePublicKey: external_exports.string().min(1).max(256),
|
|
71
|
+
providerKeyId: external_exports.string().min(1).max(256).nullable().default(null),
|
|
72
|
+
providerPublicKey: external_exports.string().min(1).max(256).nullable().default(null)
|
|
73
|
+
});
|
|
74
|
+
var loadPin = (path = recipientPinFile()) => {
|
|
69
75
|
try {
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
return
|
|
73
|
-
|
|
74
|
-
providerKeyId: typeof raw.providerKeyId === "string" ? raw.providerKeyId : null,
|
|
75
|
-
providerPublicKey: typeof raw.providerPublicKey === "string" ? raw.providerPublicKey : null
|
|
76
|
-
};
|
|
77
|
-
} catch {
|
|
78
|
-
return null;
|
|
76
|
+
return pinnedRecipientsSchema.parse(readOwnerOnlyJson(path, 16384));
|
|
77
|
+
} catch (error) {
|
|
78
|
+
if (error instanceof Error && "code" in error && error.code === "ENOENT") return null;
|
|
79
|
+
throw new Error("Existing history trust could not be read. Nothing was replaced.");
|
|
79
80
|
}
|
|
80
81
|
};
|
|
81
|
-
var savePin = (pin, path =
|
|
82
|
+
var savePin = (pin, path = recipientPinFile()) => {
|
|
82
83
|
try {
|
|
83
84
|
mkdirSync(dirname(path), { recursive: true, mode: 448 });
|
|
84
85
|
writeJsonAtomicDurable(path, pin, 384);
|
|
@@ -89,7 +90,7 @@ var savePin = (pin, path = pinFile()) => {
|
|
|
89
90
|
};
|
|
90
91
|
var clearPin = () => {
|
|
91
92
|
try {
|
|
92
|
-
rmSync(
|
|
93
|
+
rmSync(recipientPinFile(), { force: true });
|
|
93
94
|
} catch {
|
|
94
95
|
}
|
|
95
96
|
};
|
|
@@ -102,28 +103,78 @@ var verifyRecipients = (offer, pinned) => {
|
|
|
102
103
|
if (next.providerPublicKey !== pinned.providerPublicKey) changed.push("the compliance recovery key");
|
|
103
104
|
return changed.length === 0 ? { kind: "match" } : { kind: "changed", changed };
|
|
104
105
|
};
|
|
105
|
-
var fingerprint = (publicKey) =>
|
|
106
|
-
const hex = Buffer.from(publicKey, "base64").toString("hex").toUpperCase();
|
|
107
|
-
return (hex.slice(0, 8).match(/.{2}/g) ?? []).join(" ");
|
|
108
|
-
};
|
|
106
|
+
var fingerprint = (publicKey) => createHash("sha256").update(publicKey).digest("hex");
|
|
109
107
|
var changedRecipientsMessage = (verdict, offer) => [
|
|
110
108
|
"[pushary] Transcript sync stopped: the keys this machine seals transcripts to have changed.",
|
|
111
109
|
...verdict.changed.map((what) => `[pushary] changed: ${what}`),
|
|
112
110
|
`[pushary] now offered: phone ${fingerprint(offer.phonePublicKey)}${offer.provider ? `, recovery ${offer.provider.keyId.slice(0, 8)}` : ", no recovery key"}`,
|
|
113
111
|
"[pushary] If you reinstalled the app or rotated a key, this is expected. Compare the",
|
|
114
112
|
"[pushary] fingerprint above with the one in the app under Settings, then run:",
|
|
115
|
-
"[pushary] pushary transcripts trust --
|
|
113
|
+
"[pushary] pushary transcripts trust --fingerprint <fingerprint-from-phone-settings>",
|
|
116
114
|
"[pushary] Until then nothing is uploaded, so no turn is sealed to a key you have not seen."
|
|
117
115
|
].join("\n");
|
|
118
116
|
|
|
117
|
+
// src/transcript-phone-trust.ts
|
|
118
|
+
import { createHash as createHash2 } from "crypto";
|
|
119
|
+
import { mkdirSync as mkdirSync2 } from "fs";
|
|
120
|
+
import { dirname as dirname2, join as join2 } from "path";
|
|
121
|
+
var approvedPhoneSchema = external_exports.object({ version: external_exports.literal(1), sourcePinHash: external_exports.string().regex(/^[a-f0-9]{64}$/), phonePublicKey: external_exports.string().min(1).max(256) });
|
|
122
|
+
var pinHash = (pin) => createHash2("sha256").update(JSON.stringify(pin)).digest("hex");
|
|
123
|
+
var approvalFile = (path, pin, publicKey) => join2(`${path}.trusted-phones`, `${pinHash(pin)}-${fingerprint(publicKey)}.json`);
|
|
124
|
+
var sameRecoveryRecipient = (offer, pin) => (offer.provider?.keyId ?? null) === pin.providerKeyId && (offer.provider?.publicKey ?? null) === pin.providerPublicKey;
|
|
125
|
+
var canonicalPublicKey = (key) => {
|
|
126
|
+
const bytes = Buffer.from(key, "base64");
|
|
127
|
+
return bytes.length === 32 && bytes.toString("base64") === key;
|
|
128
|
+
};
|
|
129
|
+
var phoneWasApproved = (offer, pin, path) => {
|
|
130
|
+
try {
|
|
131
|
+
const approval = approvedPhoneSchema.parse(readOwnerOnlyJson(approvalFile(path, pin, offer.phonePublicKey), 16384));
|
|
132
|
+
if (approval.sourcePinHash !== pinHash(pin) || approval.phonePublicKey !== offer.phonePublicKey) throw new Error("Mismatched approval");
|
|
133
|
+
return true;
|
|
134
|
+
} catch (error) {
|
|
135
|
+
if (error instanceof Error && "code" in error && error.code === "ENOENT") return false;
|
|
136
|
+
throw new Error("Saved phone verification could not be read. Nothing was replaced.");
|
|
137
|
+
}
|
|
138
|
+
};
|
|
139
|
+
var verifyTrustedRecipients = (offer, path = recipientPinFile()) => {
|
|
140
|
+
const pin = loadPin(path);
|
|
141
|
+
const verdict = verifyRecipients(offer, pin);
|
|
142
|
+
if (verdict.kind !== "changed" || !pin || !sameRecoveryRecipient(offer, pin)) return verdict;
|
|
143
|
+
return phoneWasApproved(offer, pin, path) ? { kind: "match" } : verdict;
|
|
144
|
+
};
|
|
145
|
+
var verifyAnchoredRecipients = (offer, path = recipientPinFile(), anchorPath) => {
|
|
146
|
+
const verdict = verifyTrustedRecipients(offer, path);
|
|
147
|
+
if (verdict.kind !== "first-use" || anchorPath === void 0 || loadPin(anchorPath) === null) return verdict;
|
|
148
|
+
const anchored = verifyTrustedRecipients(offer, anchorPath);
|
|
149
|
+
return anchored.kind === "match" ? verdict : anchored;
|
|
150
|
+
};
|
|
151
|
+
var assertVerifiedPhone = (offer, pin, expectedFingerprint) => {
|
|
152
|
+
if (!canonicalPublicKey(offer.phonePublicKey) || fingerprint(offer.phonePublicKey) !== expectedFingerprint.trim().toLowerCase()) {
|
|
153
|
+
throw new Error("The fingerprint does not match this phone. Nothing was changed.");
|
|
154
|
+
}
|
|
155
|
+
if (!pin) throw new Error("No existing history trust was found. Nothing was changed.");
|
|
156
|
+
if (!sameRecoveryRecipient(offer, pin)) throw new Error("The recovery recipient also changed. Phone verification cannot approve that change.");
|
|
157
|
+
};
|
|
158
|
+
var trustPhoneRecipient = (request) => {
|
|
159
|
+
const { offer, pinFile } = request;
|
|
160
|
+
const pin = loadPin(pinFile);
|
|
161
|
+
assertVerifiedPhone(offer, pin, request.expectedFingerprint);
|
|
162
|
+
if (!pin) throw new Error("No existing history trust was found.");
|
|
163
|
+
if (verifyTrustedRecipients(offer, pinFile).kind === "match") return "already_trusted";
|
|
164
|
+
const path = approvalFile(pinFile, pin, offer.phonePublicKey);
|
|
165
|
+
mkdirSync2(dirname2(path), { recursive: true, mode: 448 });
|
|
166
|
+
writeJsonAtomicDurable(path, { version: 1, sourcePinHash: pinHash(pin), phonePublicKey: offer.phonePublicKey }, 384);
|
|
167
|
+
return "trusted";
|
|
168
|
+
};
|
|
169
|
+
|
|
119
170
|
// src/transcript-registration.ts
|
|
120
|
-
import { createHash as
|
|
121
|
-
import { lstatSync as lstatSync3, readFileSync as
|
|
122
|
-
import { basename, dirname as
|
|
171
|
+
import { createHash as createHash6 } from "crypto";
|
|
172
|
+
import { lstatSync as lstatSync3, readFileSync as readFileSync6, readdirSync as readdirSync2, realpathSync, statSync as statSync3, unlinkSync as unlinkSync2 } from "fs";
|
|
173
|
+
import { basename, dirname as dirname4, isAbsolute, join as join7, relative, resolve as resolve2, sep } from "path";
|
|
123
174
|
|
|
124
175
|
// src/claude-display-draft.ts
|
|
125
|
-
import { closeSync, fstatSync, lstatSync, openSync, readFileSync
|
|
126
|
-
import { join as
|
|
176
|
+
import { closeSync, fstatSync, lstatSync, openSync, readFileSync, readSync, unlinkSync } from "fs";
|
|
177
|
+
import { join as join3 } from "path";
|
|
127
178
|
|
|
128
179
|
// src/transcript-redaction.ts
|
|
129
180
|
var redactDraft = (text, complete = false) => {
|
|
@@ -176,14 +227,14 @@ var stateSchema = external_exports.object({
|
|
|
176
227
|
startedAt: external_exports.number().int().positive(),
|
|
177
228
|
updatedAt: external_exports.number().int().positive()
|
|
178
229
|
});
|
|
179
|
-
var fileFor = (id, directory) =>
|
|
230
|
+
var fileFor = (id, directory) => join3(directory, `${id}.display`);
|
|
180
231
|
var readState = (sessionId, runtime) => {
|
|
181
232
|
if (!identifier.safeParse(sessionId).success) return null;
|
|
182
233
|
try {
|
|
183
234
|
const path = fileFor(sessionId, runtime.directory);
|
|
184
235
|
const info = lstatSync(path);
|
|
185
236
|
if (!info.isFile() || info.nlink !== 1 || info.size > MAX_TAIL || (info.mode & 511) !== 384) return null;
|
|
186
|
-
const envelope = external_exports.object({ content: external_exports.string() }).parse(JSON.parse(
|
|
237
|
+
const envelope = external_exports.object({ content: external_exports.string() }).parse(JSON.parse(readFileSync(path, "utf8")));
|
|
187
238
|
const plain = decryptRecord(envelope.content, runtime.sessionKey);
|
|
188
239
|
if (!plain) return null;
|
|
189
240
|
const state = stateSchema.parse(JSON.parse(plain));
|
|
@@ -266,18 +317,18 @@ var readDisplayDraft = (sessionId, runtime) => {
|
|
|
266
317
|
};
|
|
267
318
|
|
|
268
319
|
// src/transcript-session-key.ts
|
|
269
|
-
import { existsSync
|
|
320
|
+
import { existsSync, mkdirSync as mkdirSync3, readFileSync as readFileSync2, readdirSync, rmSync as rmSync2, statSync } from "fs";
|
|
270
321
|
import { homedir as homedir2 } from "os";
|
|
271
|
-
import { join as
|
|
272
|
-
var sessionKeyDirectory = () => process.env.PUSHARY_SESSION_KEY_DIR?.trim() ||
|
|
322
|
+
import { join as join4 } from "path";
|
|
323
|
+
var sessionKeyDirectory = () => process.env.PUSHARY_SESSION_KEY_DIR?.trim() || join4(homedir2(), ".pushary", "sessions");
|
|
273
324
|
var SESSION_DISPLAY_TTL_MS = 48 * 60 * 60 * 1e3;
|
|
274
325
|
var SAFE_SESSION_ID = /^[A-Za-z0-9._-]{1,128}$/;
|
|
275
|
-
var fileFor2 = (sessionId, directory) => SAFE_SESSION_ID.test(sessionId) ?
|
|
326
|
+
var fileFor2 = (sessionId, directory) => SAFE_SESSION_ID.test(sessionId) ? join4(directory, `${sessionId}.json`) : null;
|
|
276
327
|
var loadSessionKey = (sessionId, directory = sessionKeyDirectory()) => {
|
|
277
328
|
const path = fileFor2(sessionId, directory);
|
|
278
|
-
if (!path || !
|
|
329
|
+
if (!path || !existsSync(path)) return null;
|
|
279
330
|
try {
|
|
280
|
-
const raw = JSON.parse(
|
|
331
|
+
const raw = JSON.parse(readFileSync2(path, "utf-8"));
|
|
281
332
|
const key = typeof raw.sessionKey === "string" ? Buffer.from(raw.sessionKey, "base64") : null;
|
|
282
333
|
if (!key || key.length !== 32) return null;
|
|
283
334
|
return {
|
|
@@ -296,7 +347,7 @@ var saveSessionKey = (sessionId, value, directory = sessionKeyDirectory()) => {
|
|
|
296
347
|
const path = fileFor2(sessionId, directory);
|
|
297
348
|
if (!path) return false;
|
|
298
349
|
try {
|
|
299
|
-
|
|
350
|
+
mkdirSync3(directory, { recursive: true, mode: 448 });
|
|
300
351
|
writeJsonAtomicDurable(path, {
|
|
301
352
|
sessionKey: Buffer.from(value.sessionKey).toString("base64"),
|
|
302
353
|
wrappedKey: value.wrappedKey,
|
|
@@ -311,12 +362,12 @@ var saveSessionKey = (sessionId, value, directory = sessionKeyDirectory()) => {
|
|
|
311
362
|
}
|
|
312
363
|
};
|
|
313
364
|
var sweepStaleSessionDisplays = (now = Date.now(), dir = sessionKeyDirectory()) => {
|
|
314
|
-
if (!
|
|
365
|
+
if (!existsSync(dir)) return 0;
|
|
315
366
|
let removed = 0;
|
|
316
367
|
try {
|
|
317
368
|
for (const name of readdirSync(dir)) {
|
|
318
369
|
if (!name.endsWith(".display")) continue;
|
|
319
|
-
const path =
|
|
370
|
+
const path = join4(dir, name);
|
|
320
371
|
try {
|
|
321
372
|
if (now - statSync(path).mtimeMs <= SESSION_DISPLAY_TTL_MS) continue;
|
|
322
373
|
rmSync2(path, { force: true });
|
|
@@ -426,9 +477,9 @@ var startDisplayPublisher = (options) => {
|
|
|
426
477
|
};
|
|
427
478
|
|
|
428
479
|
// src/transcript-reader.ts
|
|
429
|
-
import { createHash as
|
|
430
|
-
import { join as
|
|
431
|
-
import { closeSync as closeSync3, fstatSync as fstatSync3, openSync as openSync3, readFileSync as
|
|
480
|
+
import { createHash as createHash5 } from "crypto";
|
|
481
|
+
import { join as join5 } from "path";
|
|
482
|
+
import { closeSync as closeSync3, fstatSync as fstatSync3, openSync as openSync3, readFileSync as readFileSync5, readSync as readSync2, statSync as statSync2 } from "fs";
|
|
432
483
|
|
|
433
484
|
// src/transcript-source.ts
|
|
434
485
|
var normalizeTranscriptLines = (lines, source) => {
|
|
@@ -483,10 +534,10 @@ var transcriptLinesSince = (lines, oldestLineMs, dropCompactionSummaries) => lin
|
|
|
483
534
|
});
|
|
484
535
|
|
|
485
536
|
// src/transcript-snapshot-file.ts
|
|
486
|
-
import { closeSync as closeSync2, fstatSync as fstatSync2, openSync as openSync2, readFileSync as
|
|
537
|
+
import { closeSync as closeSync2, fstatSync as fstatSync2, openSync as openSync2, readFileSync as readFileSync3 } from "fs";
|
|
487
538
|
|
|
488
539
|
// src/transcript-snapshot-source.ts
|
|
489
|
-
import { createHash } from "crypto";
|
|
540
|
+
import { createHash as createHash3 } from "crypto";
|
|
490
541
|
var identity = external_exports.string().min(1).max(256);
|
|
491
542
|
var timestamp = external_exports.string().refine((value) => Number.isFinite(Date.parse(value)));
|
|
492
543
|
var geminiTool = external_exports.object({ id: identity, name: external_exports.string(), args: external_exports.record(external_exports.string(), external_exports.unknown()), result: external_exports.unknown().optional(), status: external_exports.string() });
|
|
@@ -612,7 +663,7 @@ var parseCursorSnapshot = (text) => {
|
|
|
612
663
|
const record = JSON.parse(line);
|
|
613
664
|
if (isRecord(record) && (record.type === "metadata" || record.type === "turn_ended")) continue;
|
|
614
665
|
const message = cursorMessage.parse(record);
|
|
615
|
-
const fingerprint2 =
|
|
666
|
+
const fingerprint2 = createHash3("sha256").update(canonicalJsonText(message)).digest("hex");
|
|
616
667
|
const occurrence = occurrences.get(fingerprint2) ?? 0;
|
|
617
668
|
occurrences.set(fingerprint2, occurrence + 1);
|
|
618
669
|
messages.push({ id: `cursor:${fingerprint2}:${occurrence}`, role: message.role, content: message.message.content });
|
|
@@ -648,7 +699,7 @@ var readTranscriptSnapshot = (path, source, sessionId) => {
|
|
|
648
699
|
try {
|
|
649
700
|
const before = fstatSync2(descriptor);
|
|
650
701
|
if (!before.isFile() || before.size === 0 || before.size > MAXIMUM_SNAPSHOT_FILE_BYTES) throw new Error("History snapshot is empty or exceeds its size limit");
|
|
651
|
-
const text =
|
|
702
|
+
const text = readFileSync3(descriptor, "utf8");
|
|
652
703
|
const after = fstatSync2(descriptor);
|
|
653
704
|
if (before.size !== after.size || before.mtimeMs !== after.mtimeMs) throw new Error("History snapshot changed while reading");
|
|
654
705
|
let messages;
|
|
@@ -670,11 +721,11 @@ var readTranscriptSnapshot = (path, source, sessionId) => {
|
|
|
670
721
|
};
|
|
671
722
|
|
|
672
723
|
// src/transcript-snapshot-journal.ts
|
|
673
|
-
import { lstatSync as lstatSync2, mkdirSync as
|
|
674
|
-
import { dirname as
|
|
724
|
+
import { lstatSync as lstatSync2, mkdirSync as mkdirSync4, readFileSync as readFileSync4 } from "fs";
|
|
725
|
+
import { dirname as dirname3 } from "path";
|
|
675
726
|
|
|
676
727
|
// src/transcript-projection.ts
|
|
677
|
-
import { createHash as
|
|
728
|
+
import { createHash as createHash4 } from "crypto";
|
|
678
729
|
var newestWithinUploadLimits = (messages, limits) => {
|
|
679
730
|
let start = messages.length;
|
|
680
731
|
let contentBytes = 0;
|
|
@@ -703,7 +754,7 @@ var projectTranscriptSnapshot = (previous, messages, older) => {
|
|
|
703
754
|
const order = message.sourcePosition;
|
|
704
755
|
if (!message.id || message.id.length > 256 || Object.hasOwn(entries, message.id)) throw new Error("Invalid or duplicate history message identity");
|
|
705
756
|
const record = { timestamp: message.timestamp, observedAtMs: message.observedAtMs, historyMessage: { role: message.role, content: message.content } };
|
|
706
|
-
const digest =
|
|
757
|
+
const digest = createHash4("sha256").update(JSON.stringify(record)).digest("hex");
|
|
707
758
|
entries[message.id] = { digest, order };
|
|
708
759
|
const earlier = previous?.entries[message.id];
|
|
709
760
|
if (earlier?.digest === digest && earlier.order === order) continue;
|
|
@@ -748,7 +799,7 @@ var TranscriptSnapshotJournal = class {
|
|
|
748
799
|
return;
|
|
749
800
|
}
|
|
750
801
|
if (!info.isFile() || info.nlink !== 1 || info.size > MAXIMUM_JOURNAL_BYTES || process.getuid && (info.uid !== process.getuid() || (info.mode & 511) !== 384)) throw new Error("Unsafe history checkpoint");
|
|
751
|
-
const saved = journalSchema.parse(JSON.parse(
|
|
802
|
+
const saved = journalSchema.parse(JSON.parse(readFileSync4(path, "utf8")));
|
|
752
803
|
if (saved.binding !== binding) throw new Error("History checkpoint belongs to another source");
|
|
753
804
|
this.current = saved.epochStartedAtMs === epochStartedAtMs ? saved : { ...saved, epochStartedAtMs, initialized: false, observedAtMs: {}, pending: null, excludedIds: [], projection: { revision: Math.max(saved.projection?.revision ?? 0, saved.pending?.next.revision ?? 0), entries: {} } };
|
|
754
805
|
}
|
|
@@ -799,7 +850,7 @@ var TranscriptSnapshotJournal = class {
|
|
|
799
850
|
}
|
|
800
851
|
store(next) {
|
|
801
852
|
if (Buffer.byteLength(JSON.stringify(next)) > MAXIMUM_JOURNAL_BYTES) throw new Error("History checkpoint exceeds its size limit");
|
|
802
|
-
|
|
853
|
+
mkdirSync4(dirname3(this.path), { recursive: true, mode: 448 });
|
|
803
854
|
writeJsonAtomicDurable(this.path, next, 384);
|
|
804
855
|
this.current = journalSchema.parse(next);
|
|
805
856
|
}
|
|
@@ -895,7 +946,7 @@ var appendOnlyReader = (path, source, epoch) => ({
|
|
|
895
946
|
read(retentionDays, nowMs) {
|
|
896
947
|
const version = sourceVersion(path);
|
|
897
948
|
const read2 = epoch ? linesSeenDuringEpoch(epoch, path, source, nowMs, retentionDays) : null;
|
|
898
|
-
const lines = read2?.lines ?? normalizeTranscriptLines(
|
|
949
|
+
const lines = read2?.lines ?? normalizeTranscriptLines(readFileSync5(path, "utf8").split("\n"), source);
|
|
899
950
|
return {
|
|
900
951
|
lines,
|
|
901
952
|
acknowledge() {
|
|
@@ -911,8 +962,8 @@ var caughtUpReadStillCurrent = (caughtUp, version, nowMs) => caughtUp !== null &
|
|
|
911
962
|
var UNCHANGED_SNAPSHOT_READ = { lines: [], acknowledge: () => "unchanged" };
|
|
912
963
|
var snapshotReader = (options, source) => {
|
|
913
964
|
const { path, epoch } = options;
|
|
914
|
-
const binding =
|
|
915
|
-
const journalPath =
|
|
965
|
+
const binding = createHash5("sha256").update(JSON.stringify([options.baseUrl, options.apiKey, options.machineId, options.sessionId, source, path])).digest("hex");
|
|
966
|
+
const journalPath = join5(options.keyDirectory, "snapshots", binding + ".json");
|
|
916
967
|
const epochStart = epoch?.startedAtMs ?? 0;
|
|
917
968
|
const backfill = epoch ? epoch.backfill : SESSION_HISTORY_BACKFILL;
|
|
918
969
|
let journal;
|
|
@@ -967,11 +1018,11 @@ var transcriptHealthReporter = (target) => {
|
|
|
967
1018
|
};
|
|
968
1019
|
|
|
969
1020
|
// src/transcript-sync.ts
|
|
970
|
-
import { join as
|
|
1021
|
+
import { join as join6, resolve } from "path";
|
|
971
1022
|
var claudeTranscriptPath = (cwd, sessionId) => {
|
|
972
1023
|
const projectId = resolve(cwd).replace(/[^a-zA-Z0-9-]/g, "-");
|
|
973
1024
|
const configDir = claudeConfigDir();
|
|
974
|
-
return
|
|
1025
|
+
return join6(configDir, "projects", projectId, `${sessionId}.jsonl`);
|
|
975
1026
|
};
|
|
976
1027
|
var createSyncState = () => ({
|
|
977
1028
|
sessionKey: null,
|
|
@@ -1102,7 +1153,7 @@ var startTranscriptSync = (opts) => {
|
|
|
1102
1153
|
recipientFailure = reason;
|
|
1103
1154
|
});
|
|
1104
1155
|
if (!offer) return null;
|
|
1105
|
-
const verdict =
|
|
1156
|
+
const verdict = verifyAnchoredRecipients(offer, opts.storage?.recipientPinFile, opts.storage?.firstUseAnchorPinFile);
|
|
1106
1157
|
if (verdict.kind === "first-use" && !savePin(verdict.pin, opts.storage?.recipientPinFile)) return null;
|
|
1107
1158
|
if (verdict.kind === "changed") {
|
|
1108
1159
|
recipientFailure = "phone_key_changed";
|
|
@@ -1168,13 +1219,14 @@ var startTranscriptSync = (opts) => {
|
|
|
1168
1219
|
if (ending) opts.onDrained?.();
|
|
1169
1220
|
return;
|
|
1170
1221
|
}
|
|
1222
|
+
waitingForRecipients = true;
|
|
1171
1223
|
const recipients = await fetchPinnedRecipients();
|
|
1172
1224
|
if (!recipients) {
|
|
1173
|
-
waitingForRecipients = true;
|
|
1174
1225
|
if (recipientFailure === "off_for_workspace") passOverConversationWhileHistoryIsOff();
|
|
1175
1226
|
await reportHealth(recipientFailure);
|
|
1176
1227
|
return;
|
|
1177
1228
|
}
|
|
1229
|
+
waitingForRecipients = false;
|
|
1178
1230
|
if (reader.requiresRevisions && recipients.phoneReadsTranscriptRevisions !== true) {
|
|
1179
1231
|
await reportHealth("phone_upgrade_required");
|
|
1180
1232
|
return;
|
|
@@ -1253,15 +1305,15 @@ var storedRegistrationSchema = external_exports.object({
|
|
|
1253
1305
|
endedAt: external_exports.number().positive().optional(),
|
|
1254
1306
|
drained: external_exports.boolean().optional()
|
|
1255
1307
|
});
|
|
1256
|
-
var defaultRegistryDirectory = () => process.env.PUSHARY_TRANSCRIPT_REGISTRY_DIR ||
|
|
1308
|
+
var defaultRegistryDirectory = () => process.env.PUSHARY_TRANSCRIPT_REGISTRY_DIR || join7(pusharyDir(), "transcript-capture");
|
|
1257
1309
|
var cliRegistry = (apiKey = getApiKey()) => ({ apiKey, baseUrl: getBaseUrl(), directory: defaultRegistryDirectory() });
|
|
1258
|
-
var accountFor = (registry) =>
|
|
1310
|
+
var accountFor = (registry) => createHash6("sha256").update(`${registry.baseUrl}\0${registry.apiKey}`).digest("hex");
|
|
1259
1311
|
var TTL = 48 * 60 * 60 * 1e3;
|
|
1260
|
-
var registeredReadPositionsFile = (registry) =>
|
|
1312
|
+
var registeredReadPositionsFile = (registry) => join7(registry.directory, "read-positions", `${accountFor(registry)}.json`);
|
|
1261
1313
|
var SNAPSHOT_KEYS_DIRECTORY_NAME = "snapshot-keys";
|
|
1262
1314
|
var SNAPSHOT_RECIPIENT_PIN_FILE_NAME = "recipients.json";
|
|
1263
|
-
var snapshotKeyDirectory = (registry) =>
|
|
1264
|
-
var snapshotRecipientPinFile = (registry) =>
|
|
1315
|
+
var snapshotKeyDirectory = (registry) => join7(registry.directory, SNAPSHOT_KEYS_DIRECTORY_NAME, accountFor(registry));
|
|
1316
|
+
var snapshotRecipientPinFile = (registry = cliRegistry()) => join7(snapshotKeyDirectory(registry), SNAPSHOT_RECIPIENT_PIN_FILE_NAME);
|
|
1265
1317
|
var entryAt = (path) => {
|
|
1266
1318
|
try {
|
|
1267
1319
|
return lstatSync3(path);
|
|
@@ -1276,18 +1328,18 @@ var removedPinFile = (path) => {
|
|
|
1276
1328
|
return true;
|
|
1277
1329
|
};
|
|
1278
1330
|
var clearSnapshotRecipientPins = (registryDirectory = defaultRegistryDirectory()) => {
|
|
1279
|
-
const accounts =
|
|
1331
|
+
const accounts = join7(registryDirectory, SNAPSHOT_KEYS_DIRECTORY_NAME);
|
|
1280
1332
|
if (!entryAt(accounts)?.isDirectory()) return false;
|
|
1281
|
-
return readdirSync2(accounts, { withFileTypes: true }).filter((account) => account.isDirectory()).map((account) => removedPinFile(
|
|
1333
|
+
return readdirSync2(accounts, { withFileTypes: true }).filter((account) => account.isDirectory()).map((account) => removedPinFile(join7(accounts, account.name, SNAPSHOT_RECIPIENT_PIN_FILE_NAME))).includes(true);
|
|
1282
1334
|
};
|
|
1283
1335
|
var read = (path) => {
|
|
1284
1336
|
if (statSync3(path).size > 16384) throw new Error("History registration exceeds its size limit");
|
|
1285
|
-
return storedRegistrationSchema.parse(JSON.parse(
|
|
1337
|
+
return storedRegistrationSchema.parse(JSON.parse(readFileSync6(path, "utf8")));
|
|
1286
1338
|
};
|
|
1287
1339
|
var consent = (record) => record.consentOverride ?? readTranscriptPreference() ?? true;
|
|
1288
1340
|
var withoutTrailingSlash = (url) => url.replace(/\/+$/, "");
|
|
1289
1341
|
var sameServer = (url, registry) => withoutTrailingSlash(url) === withoutTrailingSlash(registry.baseUrl);
|
|
1290
|
-
var fileFor3 = (registry, sessionId) =>
|
|
1342
|
+
var fileFor3 = (registry, sessionId) => join7(registry.directory, `${createHash6("sha256").update(accountFor(registry) + sessionId).digest("hex")}.json`);
|
|
1291
1343
|
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));
|
|
1292
1344
|
var registeredTranscriptEnabled = (apiKey, sessionId, registry = cliRegistry(apiKey)) => {
|
|
1293
1345
|
try {
|
|
@@ -1297,12 +1349,12 @@ var registeredTranscriptEnabled = (apiKey, sessionId, registry = cliRegistry(api
|
|
|
1297
1349
|
}
|
|
1298
1350
|
};
|
|
1299
1351
|
var macOwnsClaudeHooks = (cwd) => [
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1352
|
+
join7(claudeConfigDir(), "settings.json"),
|
|
1353
|
+
join7(cwd, ".claude", "settings.json"),
|
|
1354
|
+
join7(cwd, ".claude", "settings.local.json")
|
|
1303
1355
|
].some((path) => {
|
|
1304
1356
|
try {
|
|
1305
|
-
return hookOwnerOf(JSON.parse(
|
|
1357
|
+
return hookOwnerOf(JSON.parse(readFileSync6(path, "utf8"))) === "app";
|
|
1306
1358
|
} catch {
|
|
1307
1359
|
return false;
|
|
1308
1360
|
}
|
|
@@ -1310,12 +1362,12 @@ var macOwnsClaudeHooks = (cwd) => [
|
|
|
1310
1362
|
var TRANSCRIPT_ROOT_NAME = { claude: "projects", codex: "sessions", gemini: "tmp", cursor: "projects", hermes: "hermes-history" };
|
|
1311
1363
|
var transcriptRoots = (source) => {
|
|
1312
1364
|
const home = homedir3();
|
|
1313
|
-
if (source === "codex") return [
|
|
1314
|
-
if (source === "cursor") return [
|
|
1315
|
-
if (source === "hermes") return [
|
|
1316
|
-
if (source === "gemini") return [
|
|
1365
|
+
if (source === "codex") return [join7(codexHome(), TRANSCRIPT_ROOT_NAME.codex)];
|
|
1366
|
+
if (source === "cursor") return [join7(home, ".cursor", TRANSCRIPT_ROOT_NAME.cursor)];
|
|
1367
|
+
if (source === "hermes") return [join7(home, ".pushary", TRANSCRIPT_ROOT_NAME.hermes)];
|
|
1368
|
+
if (source === "gemini") return [join7(process.env.GEMINI_CLI_HOME || home, ".gemini", "tmp"), join7(home, ".cache", ".gemini", "tmp")];
|
|
1317
1369
|
const configured = process.env.CLAUDE_CONFIG_DIR;
|
|
1318
|
-
return [
|
|
1370
|
+
return [join7(configured || join7(home, ".claude"), TRANSCRIPT_ROOT_NAME.claude), join7(home, ".claude", TRANSCRIPT_ROOT_NAME.claude)];
|
|
1319
1371
|
};
|
|
1320
1372
|
var isAgentTranscriptRoot = (root, source) => isAbsolute(root) && resolve2(root) === root && basename(root) === TRANSCRIPT_ROOT_NAME[source];
|
|
1321
1373
|
var acceptedTranscriptRoots = (source, registeredRoot) => typeof registeredRoot === "string" && isAgentTranscriptRoot(registeredRoot, source) ? [...transcriptRoots(source), registeredRoot] : transcriptRoots(source);
|
|
@@ -1324,8 +1376,8 @@ var resolvedSourcePath = (path) => {
|
|
|
1324
1376
|
try {
|
|
1325
1377
|
return realpathSync(absolute);
|
|
1326
1378
|
} catch {
|
|
1327
|
-
const parent =
|
|
1328
|
-
return parent === absolute ? absolute :
|
|
1379
|
+
const parent = dirname4(absolute);
|
|
1380
|
+
return parent === absolute ? absolute : join7(resolvedSourcePath(parent), basename(absolute));
|
|
1329
1381
|
}
|
|
1330
1382
|
};
|
|
1331
1383
|
var transcriptRootContaining = (candidate, roots) => {
|
|
@@ -1345,7 +1397,7 @@ var captureRegistration = (source, value, registeredRoot) => {
|
|
|
1345
1397
|
const segments = relative(root, path).split(sep);
|
|
1346
1398
|
if (source === "hermes" && (segments.length !== 2 || !/^[a-f0-9]{64}$/.test(segments[0] ?? "") || basename(path) !== `${sessionId}.json`)) return null;
|
|
1347
1399
|
if (source === "gemini" && (segments.length !== 3 || segments[1] !== "chats" || !basename(path).startsWith("session-"))) return null;
|
|
1348
|
-
if (source === "cursor" && (segments[1] !== "agent-transcripts" || basename(path) !== `${sessionId}.jsonl` || !(segments.length === 3 || segments.length === 4 && basename(
|
|
1400
|
+
if (source === "cursor" && (segments[1] !== "agent-transcripts" || basename(path) !== `${sessionId}.jsonl` || !(segments.length === 3 || segments.length === 4 && basename(dirname4(path)) === sessionId))) return null;
|
|
1349
1401
|
return { sessionId, cwd: input.cwd, path, source, root };
|
|
1350
1402
|
};
|
|
1351
1403
|
var SESSION_END_EVENT = "SessionEnd";
|
|
@@ -1419,7 +1471,7 @@ var startRegisteredTranscripts = (apiKey, machineId, options = {}) => {
|
|
|
1419
1471
|
try {
|
|
1420
1472
|
let unreadable = 0;
|
|
1421
1473
|
const files = readdirSync2(registry.directory).filter((name) => name.endsWith(".json")).flatMap((name) => {
|
|
1422
|
-
const path =
|
|
1474
|
+
const path = join7(registry.directory, name);
|
|
1423
1475
|
try {
|
|
1424
1476
|
const time = statSync3(path).mtimeMs;
|
|
1425
1477
|
if (Date.now() - time > TTL) {
|
|
@@ -1470,7 +1522,8 @@ var startRegisteredTranscripts = (apiKey, machineId, options = {}) => {
|
|
|
1470
1522
|
const current = () => read(registration.registrationPath);
|
|
1471
1523
|
const keyStorage = storage ?? (registration.source === "claude" || registration.source === "codex" ? void 0 : {
|
|
1472
1524
|
sessionKeyDirectory: snapshotKeyDirectory(registry),
|
|
1473
|
-
recipientPinFile: snapshotRecipientPinFile(registry)
|
|
1525
|
+
recipientPinFile: snapshotRecipientPinFile(registry),
|
|
1526
|
+
firstUseAnchorPinFile: recipientPinFile()
|
|
1474
1527
|
});
|
|
1475
1528
|
active.set(id, { path: registration.path, stop: startTranscriptSync({
|
|
1476
1529
|
apiKey,
|
|
@@ -1517,15 +1570,20 @@ var startRegisteredTranscripts = (apiKey, machineId, options = {}) => {
|
|
|
1517
1570
|
};
|
|
1518
1571
|
|
|
1519
1572
|
export {
|
|
1573
|
+
recipientPinFile,
|
|
1574
|
+
loadPin,
|
|
1575
|
+
clearPin,
|
|
1576
|
+
fingerprint,
|
|
1577
|
+
verifyTrustedRecipients,
|
|
1578
|
+
assertVerifiedPhone,
|
|
1579
|
+
trustPhoneRecipient,
|
|
1520
1580
|
redactDraft,
|
|
1521
1581
|
captureDisplayDraft,
|
|
1522
1582
|
sessionKeyDirectory,
|
|
1523
1583
|
loadSessionKey,
|
|
1524
1584
|
startDraftPublisher,
|
|
1525
|
-
loadPin,
|
|
1526
|
-
clearPin,
|
|
1527
|
-
fingerprint,
|
|
1528
1585
|
claudeTranscriptPath,
|
|
1586
|
+
snapshotRecipientPinFile,
|
|
1529
1587
|
clearSnapshotRecipientPins,
|
|
1530
1588
|
registeredTranscriptEnabled,
|
|
1531
1589
|
captureRegistration,
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
2
|
absoluteUrl
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-JJNO3ACZ.js";
|
|
4
4
|
import {
|
|
5
5
|
KEY_SCOPE
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-VE333PL5.js";
|
|
7
7
|
|
|
8
8
|
// src/cli/approval-settings-pages.ts
|
|
9
9
|
var API_KEYS_PATH = "/dashboard/agent/settings";
|
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
postLiveSession,
|
|
5
5
|
postLiveSessionUntilAccepted,
|
|
6
6
|
startLiveSessionHeartbeat
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-6LJOCQBB.js";
|
|
8
8
|
import {
|
|
9
9
|
CommandReceipts,
|
|
10
10
|
controllerCommandSchema
|
|
@@ -14,24 +14,24 @@ import {
|
|
|
14
14
|
describeIdleWindow,
|
|
15
15
|
idleDeadlinePassed,
|
|
16
16
|
startProcessOwnership
|
|
17
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-NMDWW3EY.js";
|
|
18
18
|
import {
|
|
19
19
|
spawnClaude
|
|
20
20
|
} from "./chunk-XHKBHWLX.js";
|
|
21
21
|
import {
|
|
22
22
|
repoKeyFor
|
|
23
|
-
} from "./chunk-
|
|
23
|
+
} from "./chunk-K6QLKUCT.js";
|
|
24
24
|
import {
|
|
25
25
|
isAskUserResponse,
|
|
26
26
|
isDecisionStopped,
|
|
27
27
|
isWaitForAnswerResponse,
|
|
28
28
|
withdrawQuestion,
|
|
29
29
|
writeDegraded
|
|
30
|
-
} from "./chunk-
|
|
30
|
+
} from "./chunk-FSJYYZ3G.js";
|
|
31
31
|
import {
|
|
32
32
|
callMcpTool,
|
|
33
33
|
isRetryable
|
|
34
|
-
} from "./chunk-
|
|
34
|
+
} from "./chunk-NWSGMYX7.js";
|
|
35
35
|
import {
|
|
36
36
|
AGENT_QUESTION_DESCRIPTION_MAX,
|
|
37
37
|
AGENT_QUESTION_HEADER_MAX,
|
|
@@ -52,7 +52,7 @@ import {
|
|
|
52
52
|
parseCodexQuestions,
|
|
53
53
|
planElicitationAsk,
|
|
54
54
|
readElicitationFields
|
|
55
|
-
} from "./chunk-
|
|
55
|
+
} from "./chunk-VE333PL5.js";
|
|
56
56
|
|
|
57
57
|
// src/codex-question-owner.ts
|
|
58
58
|
import { createHash } from "crypto";
|
|
@@ -4,13 +4,13 @@ import {
|
|
|
4
4
|
configFailureKind,
|
|
5
5
|
retryAgentCommand,
|
|
6
6
|
writeSetupConfigFile
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-2EOTXWFK.js";
|
|
8
8
|
import {
|
|
9
9
|
MCP_BRIDGE_BINARY
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-3N4GETIW.js";
|
|
11
11
|
import {
|
|
12
12
|
KEY_FILE_MODE
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-LGQQUQDZ.js";
|
|
14
14
|
import {
|
|
15
15
|
CLINE_SERVER_NAME_TAKEN,
|
|
16
16
|
CLINE_SETTINGS_REFUSALS,
|
|
@@ -32,13 +32,13 @@ import {
|
|
|
32
32
|
withClinePusharyServer,
|
|
33
33
|
withRefreshedClineKey,
|
|
34
34
|
withoutClinePusharyServer
|
|
35
|
-
} from "./chunk-
|
|
35
|
+
} from "./chunk-7EGNVZLK.js";
|
|
36
36
|
import {
|
|
37
37
|
readJsonSafe,
|
|
38
38
|
resolveGlobalBinary,
|
|
39
39
|
writeFileAtomic,
|
|
40
40
|
writeJsonAtomic
|
|
41
|
-
} from "./chunk-
|
|
41
|
+
} from "./chunk-I7UZODYO.js";
|
|
42
42
|
|
|
43
43
|
// src/fx-config.ts
|
|
44
44
|
var FX_SERVER_NAME = "pushary";
|