pushary 1.9.103 → 1.9.104

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.
Files changed (135) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/README.md +1 -0
  3. package/dist/{api-3O3GJV3V.js → api-QOG7JVXE.js} +13 -12
  4. package/dist/bin/pushary-audit.d.ts +1 -0
  5. package/dist/bin/pushary-audit.js +263 -0
  6. package/dist/bin/pushary-bell-hook.js +31 -30
  7. package/dist/bin/pushary-bell.js +14 -13
  8. package/dist/bin/pushary-claude.js +42 -41
  9. package/dist/bin/pushary-clean.js +40 -39
  10. package/dist/bin/pushary-codex-bridge.js +25 -24
  11. package/dist/bin/pushary-codex-hook.js +39 -38
  12. package/dist/bin/pushary-codex-session.js +8 -8
  13. package/dist/bin/pushary-codex.js +17 -16
  14. package/dist/bin/pushary-connect.js +33 -32
  15. package/dist/bin/pushary-cowork.js +8 -8
  16. package/dist/bin/pushary-daemon.js +52 -50
  17. package/dist/bin/pushary-disconnect.js +32 -31
  18. package/dist/bin/pushary-display-hook.js +21 -20
  19. package/dist/bin/pushary-doctor.js +56 -54
  20. package/dist/bin/pushary-elicitation-hook.js +31 -30
  21. package/dist/bin/pushary-gemini-bridge.js +16 -15
  22. package/dist/bin/pushary-gemini-hook.js +34 -33
  23. package/dist/bin/pushary-hook.js +36 -35
  24. package/dist/bin/pushary-login.js +27 -26
  25. package/dist/bin/pushary-logout.js +33 -32
  26. package/dist/bin/pushary-mcp.js +14 -13
  27. package/dist/bin/pushary-mode.js +19 -18
  28. package/dist/bin/pushary-notification-hook.js +31 -30
  29. package/dist/bin/pushary-opencode-hook.js +33 -32
  30. package/dist/bin/pushary-permission-denied-hook.js +35 -34
  31. package/dist/bin/pushary-permission-hook.js +36 -35
  32. package/dist/bin/pushary-post-hook.js +31 -30
  33. package/dist/bin/pushary-prompt-hook.js +31 -30
  34. package/dist/bin/pushary-session-end-hook.js +33 -32
  35. package/dist/bin/pushary-session-start-hook.js +41 -40
  36. package/dist/bin/pushary-setup.js +71 -69
  37. package/dist/bin/pushary-stats.js +6 -6
  38. package/dist/bin/pushary-status.js +39 -38
  39. package/dist/bin/pushary-stop-hook.js +31 -30
  40. package/dist/bin/pushary-stopfailure-hook.js +31 -30
  41. package/dist/bin/pushary-suggestions.js +19 -18
  42. package/dist/bin/pushary-transcript-register.js +22 -21
  43. package/dist/bin/pushary-transcripts.js +30 -29
  44. package/dist/bin/pushary-upgrade.js +48 -46
  45. package/dist/bin/pushary-wait.js +19 -18
  46. package/dist/bin/pushary.js +11 -9
  47. package/dist/{chunk-YETNUPV5.js → chunk-2MRLDEQY.js} +3 -3
  48. package/dist/{chunk-KOUB4ZLX.js → chunk-3A7REECH.js} +1 -1
  49. package/dist/{chunk-O5ZKMUTP.js → chunk-3KEY3453.js} +6 -6
  50. package/dist/{chunk-JVE4P54I.js → chunk-4HBWXZPI.js} +5 -3
  51. package/dist/{chunk-WYJ6QM7K.js → chunk-4JBCPRWZ.js} +2 -2
  52. package/dist/{chunk-J6SSLXSU.js → chunk-4OLWSYX5.js} +4 -4
  53. package/dist/{chunk-JECH4NJL.js → chunk-4QI6SBNR.js} +6 -4
  54. package/dist/{chunk-UOE26LPT.js → chunk-5BX57BGT.js} +7 -7
  55. package/dist/{chunk-4FAJQPFY.js → chunk-5YVBVJOH.js} +330 -0
  56. package/dist/{chunk-4TVLPGJV.js → chunk-6B4R7HUV.js} +1 -1
  57. package/dist/{chunk-JKOAAIJD.js → chunk-7RHEZVAE.js} +5 -5
  58. package/dist/{chunk-RVSRPDRF.js → chunk-AE2BQ3XM.js} +2 -2
  59. package/dist/{chunk-SRE6XJ3K.js → chunk-AG7PFGGE.js} +7 -7
  60. package/dist/{chunk-O7ITTNDD.js → chunk-AYWX6M7J.js} +5 -3
  61. package/dist/{chunk-JUA7MX2V.js → chunk-BDSI2NEN.js} +4 -4
  62. package/dist/{chunk-KZERVKTD.js → chunk-BG4HHB7E.js} +2 -1
  63. package/dist/{chunk-ZCYLCD6L.js → chunk-CC4LGKEZ.js} +5 -5
  64. package/dist/{chunk-CQ7QE4W2.js → chunk-CFTPHNBY.js} +1 -1
  65. package/dist/{chunk-AFGMZZEB.js → chunk-FH6PHTUD.js} +2 -2
  66. package/dist/{chunk-IOQ3ZCAE.js → chunk-FQNMUJTK.js} +1 -1
  67. package/dist/{chunk-AWF5WICI.js → chunk-FVERRWDP.js} +2 -2
  68. package/dist/{chunk-KTM2X3XQ.js → chunk-FXTUSTQG.js} +16 -16
  69. package/dist/{chunk-ZXK46QT4.js → chunk-FYQHXN4X.js} +2 -2
  70. package/dist/{chunk-AZSOH2SF.js → chunk-GV2MF4NY.js} +2 -2
  71. package/dist/{chunk-4QO267OY.js → chunk-GV5TEADP.js} +1 -1
  72. package/dist/{chunk-FF7L4B3W.js → chunk-HB7FHRTT.js} +9 -9
  73. package/dist/{chunk-T7G6IIV4.js → chunk-HHEFOGT2.js} +3 -3
  74. package/dist/{chunk-3OIUMHHO.js → chunk-HJ4EBHK4.js} +2 -2
  75. package/dist/{chunk-MK2XE66G.js → chunk-HXZYBYBD.js} +3 -3
  76. package/dist/{chunk-SA4PCB6N.js → chunk-I3T5YV5I.js} +7 -7
  77. package/dist/{chunk-KLJ2CTT7.js → chunk-ID4BZRBW.js} +4 -4
  78. package/dist/{chunk-Y7KRX7U4.js → chunk-IVAXF3JG.js} +1 -1
  79. package/dist/{chunk-RMFL62HR.js → chunk-JGRBWTDW.js} +14 -12
  80. package/dist/{chunk-WPK2UWDU.js → chunk-JMTOQXHV.js} +2 -2
  81. package/dist/{chunk-QD57EL3I.js → chunk-JVZVO3K5.js} +3 -3
  82. package/dist/{chunk-KACD6W6J.js → chunk-KDIZS7FN.js} +1 -1
  83. package/dist/{chunk-T6TQETDN.js → chunk-LIDIA5JW.js} +4 -4
  84. package/dist/{chunk-G7RMOSRX.js → chunk-M7BDKARZ.js} +1 -1
  85. package/dist/{chunk-Y3SZVZF6.js → chunk-N4RIGNDX.js} +2 -2
  86. package/dist/{chunk-7BIVBOD5.js → chunk-NGY2WS3X.js} +5 -5
  87. package/dist/{chunk-HYAQIKYB.js → chunk-NKA2PEQQ.js} +6 -6
  88. package/dist/{chunk-MP3SEXXJ.js → chunk-OFRQNTJD.js} +1 -1
  89. package/dist/{chunk-NZQEABRO.js → chunk-OPV6724W.js} +13 -11
  90. package/dist/{chunk-SXAZPWL7.js → chunk-ORIVT4BL.js} +8 -6
  91. package/dist/{chunk-V5DV7XZN.js → chunk-PK6LBL3Z.js} +4 -4
  92. package/dist/{chunk-6N5DQG5F.js → chunk-PYUN7HNY.js} +2 -2
  93. package/dist/chunk-QENTGE75.js +86 -0
  94. package/dist/{chunk-PM34Z5WX.js → chunk-RDUY7MKN.js} +6 -6
  95. package/dist/{chunk-X3HBR57D.js → chunk-RUN772MN.js} +7 -7
  96. package/dist/{chunk-VD6CAELE.js → chunk-RYUIXLZ5.js} +4 -4
  97. package/dist/{chunk-2PR5EP7N.js → chunk-SJCHJQKT.js} +4 -4
  98. package/dist/{chunk-EOD3DBIN.js → chunk-SJJCCFD5.js} +3 -3
  99. package/dist/{chunk-3K7PB5LI.js → chunk-SPM4VNED.js} +3 -3
  100. package/dist/{chunk-3Q2X3T3U.js → chunk-SVZPRTCK.js} +1 -1
  101. package/dist/{chunk-UQWEH7CK.js → chunk-TMJK3CLD.js} +5 -5
  102. package/dist/{chunk-AHIAB7JQ.js → chunk-TYH7SNKD.js} +1 -1
  103. package/dist/{chunk-COBOR3ST.js → chunk-TYM6IH5F.js} +6 -4
  104. package/dist/{chunk-VJOMBYY5.js → chunk-U5DBYW63.js} +1 -1
  105. package/dist/{chunk-TLERJKSE.js → chunk-UL52HYKN.js} +1 -1
  106. package/dist/{chunk-Z2TX7DVU.js → chunk-UUYLBSAU.js} +15 -13
  107. package/dist/{chunk-7OZOFTTB.js → chunk-UYJLXAP4.js} +7 -7
  108. package/dist/{chunk-BQHZRH6S.js → chunk-VAZCGOLS.js} +26 -110
  109. package/dist/{chunk-LURFSDCL.js → chunk-VUFHYMSP.js} +1 -1
  110. package/dist/{chunk-JPKJBKZE.js → chunk-VZY4GD4T.js} +9 -9
  111. package/dist/{chunk-5PW25NHB.js → chunk-WBLK4WLO.js} +5 -5
  112. package/dist/{chunk-2S5J5YI2.js → chunk-XDTE55H7.js} +5 -5
  113. package/dist/{chunk-3ITURBPE.js → chunk-XTMAVKO3.js} +5 -5
  114. package/dist/{chunk-E7WJQBK3.js → chunk-XXNXMX2G.js} +14 -14
  115. package/dist/{chunk-WZNLWDSL.js → chunk-XXPA3X6L.js} +7 -7
  116. package/dist/{chunk-PWGD5EP6.js → chunk-YDT6TVGN.js} +7 -1
  117. package/dist/{chunk-NMUI3ZWG.js → chunk-YPY4YCIZ.js} +1 -1
  118. package/dist/{chunk-PPY5N2E6.js → chunk-YU2EUD7O.js} +1 -1
  119. package/dist/{chunk-WVAJSBI2.js → chunk-ZBT3U2VB.js} +3 -3
  120. package/dist/{chunk-AVXG5QB2.js → chunk-ZUXDGVW4.js} +5 -5
  121. package/dist/{codex-app-cards-switch-D475JLP5.js → codex-app-cards-switch-6IDDWXYS.js} +13 -12
  122. package/dist/{codex-desktop-launch-WOPEZMO6.js → codex-desktop-launch-VP4TXVCM.js} +1 -1
  123. package/dist/{codex-session-launch-AWWECV2L.js → codex-session-launch-OACJB5NN.js} +22 -21
  124. package/dist/{config-A5EC37VZ.js → config-S7HAIK6E.js} +3 -3
  125. package/dist/{global-upgrade-V6FA6MUF.js → global-upgrade-OOFEGR4H.js} +12 -11
  126. package/dist/{identity-BEPQQHNR.js → identity-QSM6MVAH.js} +5 -4
  127. package/dist/{live-capabilities-EAM2QN73.js → live-capabilities-NSVW362T.js} +6 -5
  128. package/dist/{paths-2IEEYSHM.js → paths-KFRRYJWL.js} +4 -3
  129. package/dist/reapply-7H3VCPW4.js +65 -0
  130. package/dist/src/index.js +37 -36
  131. package/dist/{upgrade-lock-DLGVC34L.js → upgrade-lock-BJKRXNMC.js} +5 -4
  132. package/dist/usage-KGWL6WKQ.js +11 -0
  133. package/package.json +2 -1
  134. package/dist/reapply-LDCMRN6Q.js +0 -64
  135. package/dist/usage-U6H5UFS2.js +0 -11
package/CHANGELOG.md CHANGED
@@ -1,5 +1,9 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.9.104
4
+
5
+ - New: `pushary audit verify <file>` checks a verifiable audit export from Dashboard > Agent > Activity > Verifiable, with no account and no network. It recomputes every hash in the chain, checks the signatures, and compares the file against what it verified on earlier runs (signed checkpoints, the newest entry seen, and every site seen), kept in `~/.local/share/pushary/audit-checkpoints.json`, where `pushary clean` leaves it. A changed row, an answered decision changed afterwards, a missing entry, a bad signature, or a history that was rewritten or cut short prints `CHANGED` and exits with code 5. A file where something could not be confirmed, such as an older page, a file with no signed checkpoint or only an old one, a row removed early, a signing key this version does not pin, or checkpoints this run could not save, exits with code 9, never 0. A file with no entries yet exits with code 3. Nothing else in the CLI or the hooks changed.
6
+
3
7
  ## 1.9.103
4
8
 
5
9
  - The Hermes plugin Pushary installs is now 1.0.1. When it hands a Hermes session to Pushary's history helper, the helper now gets only what it reads: the home folder, the search path, the temporary folder and locale, the Pushary settings it uses, and the Pushary key Hermes holds. Hermes' other provider keys no longer reach it. Checking whether history is allowed sends the key on standard input only.
package/README.md CHANGED
@@ -219,6 +219,7 @@ clean Remove Pushary from this machine (--everything: the Mac app's setup
219
219
  mode Choose where approval requests appear
220
220
  wait Show or set the "wait for your phone" ladder (pushary wait 45)
221
221
  stats Show the approval moments your agents hit while not connected
222
+ audit Check a verifiable audit export: every hash, every signature, and the checkpoints you verified before
222
223
  suggestions List rules mined from your own approvals
223
224
  upgrade Update the globally installed hooks to the latest version
224
225
  hook Run as a PreToolUse hook (reads stdin, writes stdout)
@@ -17,23 +17,24 @@ import {
17
17
  waitForQuestion,
18
18
  waitsForThePhone,
19
19
  withdrawQuestion
20
- } from "./chunk-ZCYLCD6L.js";
20
+ } from "./chunk-CC4LGKEZ.js";
21
21
  import "./chunk-POFBE6ZY.js";
22
- import "./chunk-V5DV7XZN.js";
23
- import "./chunk-7BIVBOD5.js";
24
- import "./chunk-KLJ2CTT7.js";
25
- import "./chunk-6N5DQG5F.js";
26
- import "./chunk-O7ITTNDD.js";
27
- import "./chunk-BQHZRH6S.js";
28
- import "./chunk-KOUB4ZLX.js";
29
- import "./chunk-PPY5N2E6.js";
30
- import "./chunk-KZERVKTD.js";
31
- import "./chunk-PWGD5EP6.js";
22
+ import "./chunk-PK6LBL3Z.js";
23
+ import "./chunk-NGY2WS3X.js";
24
+ import "./chunk-ID4BZRBW.js";
25
+ import "./chunk-PYUN7HNY.js";
26
+ import "./chunk-AYWX6M7J.js";
27
+ import "./chunk-VAZCGOLS.js";
28
+ import "./chunk-3A7REECH.js";
29
+ import "./chunk-YU2EUD7O.js";
30
+ import "./chunk-QENTGE75.js";
31
+ import "./chunk-BG4HHB7E.js";
32
+ import "./chunk-YDT6TVGN.js";
32
33
  import "./chunk-ZVU6WMMU.js";
33
34
  import {
34
35
  DECISION_STOP_REASON,
35
36
  UNVERIFIABLE_APPROVAL_REASON
36
- } from "./chunk-4FAJQPFY.js";
37
+ } from "./chunk-5YVBVJOH.js";
37
38
  import "./chunk-MLKGABMK.js";
38
39
  export {
39
40
  ABANDONED_WAIT,
@@ -0,0 +1 @@
1
+ #!/usr/bin/env node
@@ -0,0 +1,263 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ exitOnHelpFlag
4
+ } from "../chunk-JMTOQXHV.js";
5
+ import {
6
+ readJsonSafe,
7
+ writeJsonAtomic
8
+ } from "../chunk-QENTGE75.js";
9
+ import {
10
+ EXIT
11
+ } from "../chunk-BG4HHB7E.js";
12
+ import "../chunk-YDT6TVGN.js";
13
+ import "../chunk-ZVU6WMMU.js";
14
+ import {
15
+ AUDIT_CHAIN_FINDING_SEVERITY,
16
+ AUDIT_CHECKPOINT_MAX_AGE_MS,
17
+ AUDIT_CHECKPOINT_PINNED_KEY_IDS,
18
+ auditChainVerdictTampered,
19
+ auditHeadsToRemember,
20
+ isRecord,
21
+ parseAllOrNothing,
22
+ parseAuditChainExport,
23
+ parseAuditKnownHead,
24
+ verifyAuditChainSite
25
+ } from "../chunk-5YVBVJOH.js";
26
+ import "../chunk-MLKGABMK.js";
27
+
28
+ // src/audit-verify.ts
29
+ import { createHash, createPublicKey, verify } from "crypto";
30
+ import { readFileSync } from "fs";
31
+ import { homedir } from "os";
32
+ import { isAbsolute, join } from "path";
33
+ var nodeAuditCrypto = {
34
+ sha256Hex: (text) => createHash("sha256").update(text).digest("hex"),
35
+ verifyEd25519: (message, signature, publicKey) => {
36
+ try {
37
+ return verify(null, Buffer.from(message), createPublicKey({ key: Buffer.from(publicKey, "base64"), format: "der", type: "spki" }), Buffer.from(signature, "base64"));
38
+ } catch {
39
+ return false;
40
+ }
41
+ }
42
+ };
43
+ var absoluteOrNull = (path2) => {
44
+ const trimmed = path2?.trim();
45
+ return trimmed && isAbsolute(trimmed) ? trimmed : null;
46
+ };
47
+ var userDataDirectory = () => absoluteOrNull(process.env.XDG_DATA_HOME) ?? join(homedir(), ".local", "share");
48
+ var auditCheckpointStorePath = () => absoluteOrNull(process.env.PUSHARY_AUDIT_CHECKPOINTS_FILE) ?? join(userDataDirectory(), "pushary", "audit-checkpoints.json");
49
+ var readAuditExport = (path2) => {
50
+ let text;
51
+ try {
52
+ text = readFileSync(path2, "utf8");
53
+ } catch (error) {
54
+ return { kind: "unreadable", reason: error instanceof Error ? error.message : String(error) };
55
+ }
56
+ let json;
57
+ try {
58
+ json = JSON.parse(text);
59
+ } catch {
60
+ return { kind: "not_an_export" };
61
+ }
62
+ const file = parseAuditChainExport(json);
63
+ return file ? { kind: "read", file } : { kind: "not_an_export" };
64
+ };
65
+ var EMPTY_MEMORY = { heads: [], siteIds: [] };
66
+ var parseSiteId = (value) => typeof value === "string" ? value : null;
67
+ var parseVerifierMemory = (value) => {
68
+ if (!isRecord(value)) return null;
69
+ const { heads, siteIds } = value;
70
+ const parsedHeads = parseAllOrNothing(heads, parseAuditKnownHead);
71
+ const parsedSiteIds = parseAllOrNothing(siteIds, parseSiteId);
72
+ return parsedHeads && parsedSiteIds ? { heads: parsedHeads, siteIds: parsedSiteIds } : null;
73
+ };
74
+ var readVerifierMemory = (path2) => {
75
+ const read2 = readJsonSafe(path2);
76
+ if (read2.kind === "missing") return { kind: "none_yet" };
77
+ if (read2.kind === "unreadable") return { kind: "unreadable", reason: read2.error.message };
78
+ if (read2.kind === "unparseable") return { kind: "unreadable", reason: "it is not valid JSON" };
79
+ const memory2 = parseVerifierMemory(read2.value);
80
+ return memory2 ? { kind: "read", memory: memory2 } : { kind: "unreadable", reason: "it is not a file this command wrote" };
81
+ };
82
+ var verifierMemoryOf = (read2) => read2.kind === "read" ? read2.memory : EMPTY_MEMORY;
83
+ var headKey = (head) => `${head.siteId}:${head.seq}`;
84
+ var earliestSighting = (kept, seen) => kept && kept.exportedAt <= seen.exportedAt ? kept : seen;
85
+ var rememberRun = (memory2, verdicts2) => {
86
+ const heads = new Map(memory2.heads.map((head) => [headKey(head), head]));
87
+ for (const head of verdicts2.flatMap(auditHeadsToRemember)) heads.set(headKey(head), earliestSighting(heads.get(headKey(head)), head));
88
+ const siteIds = /* @__PURE__ */ new Set([...memory2.siteIds, ...verdicts2.filter((verdict) => verdict.entryCount > 0).map((verdict) => verdict.siteId)]);
89
+ return {
90
+ heads: [...heads.values()].sort((left, right) => left.siteId.localeCompare(right.siteId) || left.seq - right.seq),
91
+ siteIds: [...siteIds].sort()
92
+ };
93
+ };
94
+ var saveVerifierMemory = (path2, memory2) => {
95
+ try {
96
+ writeJsonAtomic(path2, memory2, 384);
97
+ return { saved: true };
98
+ } catch (error) {
99
+ return { saved: false, reason: error instanceof Error ? error.message : String(error) };
100
+ }
101
+ };
102
+ var verifyAuditExport = (file, memory2) => file.sites.map((site) => verifyAuditChainSite(site, nodeAuditCrypto, {
103
+ pinnedKeyIds: AUDIT_CHECKPOINT_PINNED_KEY_IDS,
104
+ knownHeads: memory2.heads,
105
+ exportedAt: file.exportedAt
106
+ }));
107
+ var verifierMemoryStateOf = (read2, saved) => {
108
+ const memory2 = verifierMemoryOf(read2);
109
+ return {
110
+ readable: read2.kind !== "unreadable",
111
+ saved,
112
+ knownSiteIds: /* @__PURE__ */ new Set([...memory2.siteIds, ...memory2.heads.map((head) => head.siteId)])
113
+ };
114
+ };
115
+ var siteUnknownToEarlierRuns = (verdict, state2) => state2.knownSiteIds.size > 0 && !state2.knownSiteIds.has(verdict.siteId);
116
+ var nothingRecordedYet = (verdict, state2) => verdict.entryCount === 0 && verdict.findings.length === 0 && state2.knownSiteIds.size === 0;
117
+ var siteLeftOpen = (verdict, state2) => verdict.findings.length > 0 || verdict.entryCount === 0 || siteUnknownToEarlierRuns(verdict, state2);
118
+ var auditVerifyOutcome = (verdicts2, state2) => {
119
+ if (verdicts2.some(auditChainVerdictTampered)) return "changed";
120
+ if (!state2.readable || !state2.saved) return "inconclusive";
121
+ if (verdicts2.every((verdict) => nothingRecordedYet(verdict, state2))) return "nothing_recorded";
122
+ return verdicts2.some((verdict) => siteLeftOpen(verdict, state2)) ? "inconclusive" : "no_changes";
123
+ };
124
+ var STATUS_LABEL = {
125
+ included: "checked against its row",
126
+ aged_out: "past retention",
127
+ superseded: "superseded by a later decision",
128
+ changed_since_recorded: "changed since recorded"
129
+ };
130
+ var MINUTE_MS = 60 * 1e3;
131
+ var utcMinuteOf = (timestamp) => `${timestamp.slice(0, 16).replace("T", " ")} UTC`;
132
+ var describeAuditFinding = (finding) => {
133
+ switch (finding.kind) {
134
+ case "entry_altered":
135
+ return `entry ${finding.seq}: the entry itself was edited after it was chained`;
136
+ case "entry_changed":
137
+ return `entry ${finding.seq}: the row no longer matches the hash recorded for it`;
138
+ case "unrecorded_change":
139
+ return `entry ${finding.seq}: an unanswered question's outcome changed after it was last recorded, as a late answer does. Export again in a few minutes: once recorded it verifies`;
140
+ case "invalid_status":
141
+ return `entry ${finding.seq}: the file marks it ${STATUS_LABEL[finding.status]}, which cannot be true for it`;
142
+ case "decision_rewritten":
143
+ return `entry ${finding.seq}: a decision was recorded after this question had already been answered, which the audit trail forbids`;
144
+ case "asked_twice":
145
+ return `entry ${finding.seq}: this question was recorded a second time`;
146
+ case "row_missing":
147
+ return `entry ${finding.seq}: its row is gone although it is inside the retention window. A per-request retention setting can remove a row early; otherwise it was deleted`;
148
+ case "broken_link":
149
+ return `entry ${finding.seq}: it does not link to the entry before it`;
150
+ case "sequence_gap":
151
+ return `entries ${finding.afterSeq + 1} to ${finding.seq - 1} are missing`;
152
+ case "genesis_mismatch":
153
+ return "entry 1 does not start the chain";
154
+ case "checkpoint_mismatch":
155
+ return `checkpoint at entry ${finding.seq}: the signed hash does not match the entry`;
156
+ case "checkpoint_outside_export":
157
+ return `checkpoint at entry ${finding.seq} covers an entry outside this file`;
158
+ case "bad_signature":
159
+ return `checkpoint at entry ${finding.seq}: the signature is not valid`;
160
+ case "wrong_key_id":
161
+ return `checkpoint at entry ${finding.seq}: the key id does not match its key`;
162
+ case "unpinned_key":
163
+ return `checkpoint at entry ${finding.seq}: signed by key ${finding.keyId}, which this version of pushary does not pin yet`;
164
+ case "history_rewritten":
165
+ return `entry ${finding.seq} differs from what you verified on an earlier run, so history was rewritten`;
166
+ case "conflicting_checkpoint":
167
+ return `checkpoint at entry ${finding.seq} conflicts with one you verified on an earlier run`;
168
+ case "rolled_back":
169
+ return `entries up to ${finding.seq}, which you verified on an earlier run, are missing from the end of this file`;
170
+ case "unsigned":
171
+ return "this file holds no signed checkpoint, so no entry in it is covered by a signature";
172
+ case "older_export":
173
+ return `this file was exported no later than one an earlier run verified, which reached entry ${finding.seq} (exported ${utcMinuteOf(finding.exportedAt)}). A file from that moment or earlier cannot show whether newer entries were removed`;
174
+ case "stale_signature":
175
+ return `the newest signature covers entries up to ${finding.seq} and was made ${utcMinuteOf(finding.signedAt)}, more than ${AUDIT_CHECKPOINT_MAX_AGE_MS / MINUTE_MS} minutes before this file was exported. New entries are signed within about an hour, so the entries after it are covered by no signature`;
176
+ case "older_page":
177
+ return `this file is an older page, holding entries before ${finding.beforeSeq} only. It cannot show whether a newer entry was removed or changed; verify the newest export for that`;
178
+ }
179
+ };
180
+ var plural = (count, one, many) => `${count} ${count === 1 ? one : many}`;
181
+ var rangeOf = (verdict) => verdict.firstSeq === null || verdict.lastSeq === null ? "no entries yet" : `entries ${verdict.firstSeq} to ${verdict.lastSeq}`;
182
+ var retentionLineOf = (verdict) => verdict.retentionFloor === null ? " This file says your plan keeps rows without a time limit." : ` This file says rows created before ${verdict.retentionFloor.slice(0, 10)} are past your plan's retention.`;
183
+ var resultLineOf = (verdict, state2) => {
184
+ if (auditChainVerdictTampered(verdict)) return " Result: this audit trail was changed after it was recorded.";
185
+ if (!state2.readable) return " Result: no changes found in this file, but it was not compared with your earlier runs.";
186
+ if (!state2.saved) return " Result: no changes found in this file, but this run could not be saved, so later runs cannot compare against it.";
187
+ if (siteUnknownToEarlierRuns(verdict, state2)) return " Result: no changes found in this file, but no earlier run of yours covers this site id.";
188
+ if (nothingRecordedYet(verdict, state2)) return " Result: nothing to check. No entries have been recorded for this workspace yet.";
189
+ if (verdict.entryCount === 0 && verdict.findings.length === 0) return " Result: this file has no entries, although an earlier run saw entries for this site.";
190
+ return verdict.findings.length > 0 ? ` Result: no changes found in what could be checked. ${plural(verdict.findings.length, "note", "notes")} above could not be confirmed either way.` : " Result: no changes found.";
191
+ };
192
+ var earlierRunsLineOf = (verdict, state2) => {
193
+ if (!state2.readable || state2.knownSiteIds.has(verdict.siteId)) return null;
194
+ if (state2.knownSiteIds.size > 0) return " Your earlier runs verified other site ids, never this one. If you checked this site before, its id has changed.";
195
+ if (verdict.entryCount === 0) return null;
196
+ if (auditHeadsToRemember(verdict).length === 0) return " First run for this site. Only its id is kept from a changed file, so later runs know the site but have no entries to compare against.";
197
+ return state2.saved ? " First run for this site: later runs compare against what this run saved." : " First run for this site, but what it found could not be saved for later runs.";
198
+ };
199
+ var describeAuditSiteReport = (verdict, state2) => {
200
+ const counts = verdict.payloadCounts;
201
+ const lines = [
202
+ `${verdict.siteName} (${verdict.siteId}): ${rangeOf(verdict)}, ${plural(verdict.signedCheckpoints, "signed checkpoint", "signed checkpoints")}, exported ${utcMinuteOf(verdict.exportedAt)}`,
203
+ ` ${counts.included} checked against their row, ${counts.superseded} superseded by a later decision, ${counts.aged_out} past retention, ${counts.changed_since_recorded} changed since recorded`
204
+ ];
205
+ const earlierRuns = earlierRunsLineOf(verdict, state2);
206
+ if (earlierRuns) lines.push(earlierRuns);
207
+ if (verdict.entryCount > 0) lines.push(retentionLineOf(verdict));
208
+ if (verdict.truncated) lines.push(` This file starts at entry ${verdict.firstSeq ?? 1}. For older entries, add &beforeSeq=${verdict.firstSeq ?? 1} to the Verifiable export link.`);
209
+ for (const finding of verdict.findings) {
210
+ lines.push(` ${AUDIT_CHAIN_FINDING_SEVERITY[finding.kind] === "tampered" ? "CHANGED" : "note"}: ${describeAuditFinding(finding)}`);
211
+ }
212
+ lines.push(resultLineOf(verdict, state2));
213
+ return lines;
214
+ };
215
+
216
+ // bin/pushary-audit.ts
217
+ exitOnHelpFlag("audit");
218
+ var USAGE = "Usage: pushary audit verify <file>\nDownload the file from Dashboard > Agent > Activity > Verifiable.";
219
+ var EXIT_FOR_OUTCOME = {
220
+ changed: EXIT.PROBLEMS_FOUND,
221
+ nothing_recorded: EXIT.NOT_CONFIGURED,
222
+ inconclusive: EXIT.INCONCLUSIVE,
223
+ no_changes: EXIT.OK
224
+ };
225
+ var raw = process.argv.slice(2);
226
+ var [subcommand, path] = raw[0] === "audit" ? raw.slice(1) : raw;
227
+ if (subcommand !== "verify" || !path) {
228
+ process.stderr.write(`${USAGE}
229
+ `);
230
+ process.exit(EXIT.USAGE);
231
+ }
232
+ var read = readAuditExport(path);
233
+ if (read.kind === "unreadable") {
234
+ process.stderr.write(`Could not read ${path}: ${read.reason}
235
+ `);
236
+ process.exit(EXIT.USAGE);
237
+ }
238
+ if (read.kind === "not_an_export") {
239
+ process.stderr.write(`${path} is not a Pushary verifiable audit export.
240
+ ${USAGE}
241
+ `);
242
+ process.exit(EXIT.USAGE);
243
+ }
244
+ var storePath = auditCheckpointStorePath();
245
+ var memory = readVerifierMemory(storePath);
246
+ if (memory.kind === "unreadable") {
247
+ process.stderr.write(
248
+ `What earlier runs saved at ${storePath} could not be read: ${memory.reason}.
249
+ This run cannot compare against earlier runs and leaves that file as it is. Repair it, or move it aside to start a new one.
250
+ `
251
+ );
252
+ }
253
+ var verdicts = verifyAuditExport(read.file, verifierMemoryOf(memory));
254
+ var save = memory.kind === "unreadable" ? null : saveVerifierMemory(storePath, rememberRun(verifierMemoryOf(memory), verdicts));
255
+ if (save && !save.saved) {
256
+ process.stderr.write(`Could not save what this run found to ${storePath}: ${save.reason}
257
+ The next run cannot compare against this one, so this run cannot count as clean.
258
+ `);
259
+ }
260
+ var state = verifierMemoryStateOf(memory, save?.saved ?? false);
261
+ for (const verdict of verdicts) process.stdout.write(`${describeAuditSiteReport(verdict, state).join("\n")}
262
+ `);
263
+ process.exit(EXIT_FOR_OUTCOME[auditVerifyOutcome(verdicts, state)]);
@@ -1,42 +1,43 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  handleBell
4
- } from "../chunk-IOQ3ZCAE.js";
4
+ } from "../chunk-FQNMUJTK.js";
5
5
  import {
6
6
  readHookInput
7
- } from "../chunk-SA4PCB6N.js";
8
- import "../chunk-KTM2X3XQ.js";
9
- import "../chunk-G7RMOSRX.js";
7
+ } from "../chunk-I3T5YV5I.js";
8
+ import "../chunk-FXTUSTQG.js";
9
+ import "../chunk-M7BDKARZ.js";
10
10
  import "../chunk-G66WIAST.js";
11
- import "../chunk-UOE26LPT.js";
12
- import "../chunk-NZQEABRO.js";
13
- import "../chunk-VD6CAELE.js";
14
- import "../chunk-WVAJSBI2.js";
15
- import "../chunk-VJOMBYY5.js";
16
- import "../chunk-NMUI3ZWG.js";
17
- import "../chunk-3OIUMHHO.js";
11
+ import "../chunk-5BX57BGT.js";
12
+ import "../chunk-UUYLBSAU.js";
13
+ import "../chunk-OPV6724W.js";
14
+ import "../chunk-RYUIXLZ5.js";
15
+ import "../chunk-OFRQNTJD.js";
16
+ import "../chunk-ZBT3U2VB.js";
17
+ import "../chunk-U5DBYW63.js";
18
+ import "../chunk-YPY4YCIZ.js";
19
+ import "../chunk-HJ4EBHK4.js";
18
20
  import "../chunk-XMSDA5WA.js";
19
- import "../chunk-3Q2X3T3U.js";
20
- import "../chunk-XHKBHWLX.js";
21
- import "../chunk-HYAQIKYB.js";
22
- import "../chunk-Z2TX7DVU.js";
23
- import "../chunk-MP3SEXXJ.js";
24
- import "../chunk-4QO267OY.js";
25
- import "../chunk-ZCYLCD6L.js";
21
+ import "../chunk-SVZPRTCK.js";
22
+ import "../chunk-GV5TEADP.js";
23
+ import "../chunk-CC4LGKEZ.js";
26
24
  import "../chunk-POFBE6ZY.js";
27
- import "../chunk-V5DV7XZN.js";
28
- import "../chunk-7BIVBOD5.js";
29
- import "../chunk-KLJ2CTT7.js";
30
- import "../chunk-6N5DQG5F.js";
31
- import "../chunk-AFGMZZEB.js";
32
- import "../chunk-O7ITTNDD.js";
33
- import "../chunk-BQHZRH6S.js";
34
- import "../chunk-KOUB4ZLX.js";
35
- import "../chunk-PPY5N2E6.js";
36
- import "../chunk-KZERVKTD.js";
37
- import "../chunk-PWGD5EP6.js";
25
+ import "../chunk-PK6LBL3Z.js";
26
+ import "../chunk-NGY2WS3X.js";
27
+ import "../chunk-ID4BZRBW.js";
28
+ import "../chunk-XHKBHWLX.js";
29
+ import "../chunk-PYUN7HNY.js";
30
+ import "../chunk-NKA2PEQQ.js";
31
+ import "../chunk-FH6PHTUD.js";
32
+ import "../chunk-AYWX6M7J.js";
33
+ import "../chunk-VAZCGOLS.js";
34
+ import "../chunk-3A7REECH.js";
35
+ import "../chunk-YU2EUD7O.js";
36
+ import "../chunk-QENTGE75.js";
37
+ import "../chunk-BG4HHB7E.js";
38
+ import "../chunk-YDT6TVGN.js";
38
39
  import "../chunk-ZVU6WMMU.js";
39
- import "../chunk-4FAJQPFY.js";
40
+ import "../chunk-5YVBVJOH.js";
40
41
  import "../chunk-MLKGABMK.js";
41
42
 
42
43
  // bin/pushary-bell-hook.ts
@@ -5,40 +5,41 @@ import {
5
5
  liveAgentCount,
6
6
  ring,
7
7
  upgradeThreshold
8
- } from "../chunk-IOQ3ZCAE.js";
8
+ } from "../chunk-FQNMUJTK.js";
9
9
  import {
10
10
  createIo
11
11
  } from "../chunk-FO3MDD26.js";
12
12
  import {
13
13
  exitOnHelpFlag
14
- } from "../chunk-WPK2UWDU.js";
14
+ } from "../chunk-JMTOQXHV.js";
15
15
  import {
16
16
  addBellHooks,
17
17
  bellInstalled,
18
18
  removeBellHooks
19
- } from "../chunk-VJOMBYY5.js";
19
+ } from "../chunk-U5DBYW63.js";
20
20
  import {
21
21
  parseFlags
22
- } from "../chunk-NMUI3ZWG.js";
23
- import "../chunk-HYAQIKYB.js";
24
- import "../chunk-AFGMZZEB.js";
22
+ } from "../chunk-YPY4YCIZ.js";
23
+ import "../chunk-NKA2PEQQ.js";
24
+ import "../chunk-FH6PHTUD.js";
25
25
  import {
26
26
  claudeSettings
27
- } from "../chunk-O7ITTNDD.js";
27
+ } from "../chunk-AYWX6M7J.js";
28
+ import "../chunk-VAZCGOLS.js";
29
+ import "../chunk-3A7REECH.js";
30
+ import "../chunk-YU2EUD7O.js";
28
31
  import {
29
32
  readJsonSafe,
30
33
  writeJsonAtomic
31
- } from "../chunk-BQHZRH6S.js";
32
- import "../chunk-KOUB4ZLX.js";
33
- import "../chunk-PPY5N2E6.js";
34
+ } from "../chunk-QENTGE75.js";
34
35
  import {
35
36
  EXIT
36
- } from "../chunk-KZERVKTD.js";
37
- import "../chunk-PWGD5EP6.js";
37
+ } from "../chunk-BG4HHB7E.js";
38
+ import "../chunk-YDT6TVGN.js";
38
39
  import "../chunk-ZVU6WMMU.js";
39
40
  import {
40
41
  isRecord
41
- } from "../chunk-4FAJQPFY.js";
42
+ } from "../chunk-5YVBVJOH.js";
42
43
  import "../chunk-MLKGABMK.js";
43
44
 
44
45
  // bin/pushary-bell.ts
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  WRAPPER_ACTIVE_ENV,
4
4
  findClaudeBinary
5
- } from "../chunk-AWF5WICI.js";
5
+ } from "../chunk-FVERRWDP.js";
6
6
  import {
7
7
  CommandReceipts,
8
8
  controllerCommandSchema
@@ -12,40 +12,21 @@ import {
12
12
  describeIdleWindow,
13
13
  startProcessOwnership,
14
14
  withSpawnProcessOwnership
15
- } from "../chunk-T7G6IIV4.js";
16
- import "../chunk-LURFSDCL.js";
15
+ } from "../chunk-HHEFOGT2.js";
16
+ import "../chunk-VUFHYMSP.js";
17
17
  import {
18
18
  announceSubscriptionRequired,
19
19
  isDeferAnswer
20
- } from "../chunk-CQ7QE4W2.js";
20
+ } from "../chunk-CFTPHNBY.js";
21
21
  import {
22
22
  claudeTranscriptPath,
23
23
  redactDraft,
24
24
  registerTranscript,
25
25
  registeredTranscriptEnabled,
26
26
  startDraftPublisher
27
- } from "../chunk-KTM2X3XQ.js";
28
- import "../chunk-G7RMOSRX.js";
27
+ } from "../chunk-FXTUSTQG.js";
28
+ import "../chunk-M7BDKARZ.js";
29
29
  import "../chunk-G66WIAST.js";
30
- import {
31
- ensureDaemonRunning
32
- } from "../chunk-NZQEABRO.js";
33
- import "../chunk-VD6CAELE.js";
34
- import "../chunk-WVAJSBI2.js";
35
- import "../chunk-VJOMBYY5.js";
36
- import "../chunk-NMUI3ZWG.js";
37
- import "../chunk-3OIUMHHO.js";
38
- import {
39
- external_exports
40
- } from "../chunk-XMSDA5WA.js";
41
- import {
42
- transcriptsEnabled
43
- } from "../chunk-3Q2X3T3U.js";
44
- import {
45
- needsShell,
46
- spawnClaude
47
- } from "../chunk-XHKBHWLX.js";
48
- import "../chunk-HYAQIKYB.js";
49
30
  import {
50
31
  DEFAULT_SESSION,
51
32
  PHONE_DRIVER,
@@ -59,18 +40,32 @@ import {
59
40
  removePendingCommand,
60
41
  reportEvent,
61
42
  savePendingCommand
62
- } from "../chunk-Z2TX7DVU.js";
43
+ } from "../chunk-UUYLBSAU.js";
44
+ import {
45
+ ensureDaemonRunning
46
+ } from "../chunk-OPV6724W.js";
47
+ import "../chunk-RYUIXLZ5.js";
63
48
  import {
64
49
  UNNAMED_ACTION,
65
50
  deriveToolTarget,
66
51
  describeStopFailure,
67
52
  describeToolCall,
68
53
  scopePathFor
69
- } from "../chunk-MP3SEXXJ.js";
54
+ } from "../chunk-OFRQNTJD.js";
55
+ import "../chunk-ZBT3U2VB.js";
56
+ import "../chunk-U5DBYW63.js";
57
+ import "../chunk-YPY4YCIZ.js";
58
+ import "../chunk-HJ4EBHK4.js";
59
+ import {
60
+ external_exports
61
+ } from "../chunk-XMSDA5WA.js";
62
+ import {
63
+ transcriptsEnabled
64
+ } from "../chunk-SVZPRTCK.js";
70
65
  import {
71
66
  repoKeyFor,
72
67
  repositoryScopeFor
73
- } from "../chunk-4QO267OY.js";
68
+ } from "../chunk-GV5TEADP.js";
74
69
  import {
75
70
  askUser,
76
71
  cancelQuestion,
@@ -82,30 +77,36 @@ import {
82
77
  waitForAnswer,
83
78
  waitsForThePhone,
84
79
  withdrawQuestion
85
- } from "../chunk-ZCYLCD6L.js";
80
+ } from "../chunk-CC4LGKEZ.js";
86
81
  import "../chunk-POFBE6ZY.js";
87
82
  import {
88
83
  SubscriptionRequiredError
89
- } from "../chunk-V5DV7XZN.js";
90
- import "../chunk-7BIVBOD5.js";
91
- import "../chunk-KLJ2CTT7.js";
84
+ } from "../chunk-PK6LBL3Z.js";
85
+ import "../chunk-NGY2WS3X.js";
86
+ import "../chunk-ID4BZRBW.js";
87
+ import {
88
+ needsShell,
89
+ spawnClaude
90
+ } from "../chunk-XHKBHWLX.js";
92
91
  import {
93
92
  getMachineId
94
- } from "../chunk-6N5DQG5F.js";
95
- import "../chunk-AFGMZZEB.js";
93
+ } from "../chunk-PYUN7HNY.js";
94
+ import "../chunk-NKA2PEQQ.js";
95
+ import "../chunk-FH6PHTUD.js";
96
96
  import {
97
97
  claudeConfigDir
98
- } from "../chunk-O7ITTNDD.js";
99
- import "../chunk-BQHZRH6S.js";
98
+ } from "../chunk-AYWX6M7J.js";
99
+ import "../chunk-VAZCGOLS.js";
100
100
  import {
101
101
  getApiKey,
102
102
  getBaseUrl
103
- } from "../chunk-KOUB4ZLX.js";
104
- import "../chunk-PPY5N2E6.js";
105
- import "../chunk-KZERVKTD.js";
103
+ } from "../chunk-3A7REECH.js";
104
+ import "../chunk-YU2EUD7O.js";
105
+ import "../chunk-QENTGE75.js";
106
+ import "../chunk-BG4HHB7E.js";
106
107
  import {
107
108
  NPX_LATEST_COMMAND
108
- } from "../chunk-PWGD5EP6.js";
109
+ } from "../chunk-YDT6TVGN.js";
109
110
  import "../chunk-ZVU6WMMU.js";
110
111
  import {
111
112
  DECISION_STOP_REASON,
@@ -118,7 +119,7 @@ import {
118
119
  refusesWhenUnanswered,
119
120
  resolveGate,
120
121
  timeoutActionWithoutLocalPrompt
121
- } from "../chunk-4FAJQPFY.js";
122
+ } from "../chunk-5YVBVJOH.js";
122
123
  import "../chunk-MLKGABMK.js";
123
124
 
124
125
  // src/wrapper/localPassthrough.ts