pushary 1.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (186) hide show
  1. package/CHANGELOG.md +1943 -0
  2. package/LICENSE +21 -0
  3. package/README.md +330 -0
  4. package/data/SKILL.md +591 -0
  5. package/data/cowork/SKILL.md +77 -0
  6. package/data/cursor-plugin/.cursor-plugin/plugin.json +25 -0
  7. package/data/cursor-plugin/CHANGELOG.md +70 -0
  8. package/data/cursor-plugin/CONTRIBUTING.md +40 -0
  9. package/data/cursor-plugin/LICENSE +21 -0
  10. package/data/cursor-plugin/README.md +113 -0
  11. package/data/cursor-plugin/SECURITY.md +33 -0
  12. package/data/cursor-plugin/assets/logo.png +0 -0
  13. package/data/cursor-plugin/commands/notify-when-done.md +14 -0
  14. package/data/cursor-plugin/commands/pushary-test.md +13 -0
  15. package/data/cursor-plugin/hooks/hooks.json +75 -0
  16. package/data/cursor-plugin/mcp.json +11 -0
  17. package/data/cursor-plugin/rules/pushary.mdc +40 -0
  18. package/data/cursor-plugin/scripts/pushary-gate.mjs +724 -0
  19. package/data/cursor-plugin/scripts/pushary-gate.test.mjs +137 -0
  20. package/data/cursor-plugin/scripts/redaction.mjs +51 -0
  21. package/data/cursor-plugin/skills/pushary/SKILL.md +584 -0
  22. package/data/vscode-plugin/.claude-plugin/plugin.json +28 -0
  23. package/data/vscode-plugin/.mcp.json +11 -0
  24. package/data/vscode-plugin/CHANGELOG.md +49 -0
  25. package/data/vscode-plugin/CONTRIBUTING.md +40 -0
  26. package/data/vscode-plugin/LICENSE +21 -0
  27. package/data/vscode-plugin/README.md +128 -0
  28. package/data/vscode-plugin/SECURITY.md +56 -0
  29. package/data/vscode-plugin/assets/logo.png +0 -0
  30. package/data/vscode-plugin/commands/notify-when-done.md +14 -0
  31. package/data/vscode-plugin/commands/pushary-test.md +13 -0
  32. package/data/vscode-plugin/hooks/hooks.json +60 -0
  33. package/data/vscode-plugin/scripts/pushary-gate.mjs +762 -0
  34. package/data/vscode-plugin/scripts/redaction.mjs +51 -0
  35. package/data/vscode-plugin/skills/pushary/SKILL.md +584 -0
  36. package/dist/bin/pushary-bell-hook.d.ts +1 -0
  37. package/dist/bin/pushary-bell-hook.js +46 -0
  38. package/dist/bin/pushary-bell.d.ts +1 -0
  39. package/dist/bin/pushary-bell.js +146 -0
  40. package/dist/bin/pushary-claude.d.ts +1 -0
  41. package/dist/bin/pushary-claude.js +1916 -0
  42. package/dist/bin/pushary-clean.d.ts +1 -0
  43. package/dist/bin/pushary-clean.js +1300 -0
  44. package/dist/bin/pushary-codex-bridge.d.ts +1 -0
  45. package/dist/bin/pushary-codex-bridge.js +599 -0
  46. package/dist/bin/pushary-codex-hook.d.ts +1 -0
  47. package/dist/bin/pushary-codex-hook.js +886 -0
  48. package/dist/bin/pushary-codex.d.ts +1 -0
  49. package/dist/bin/pushary-codex.js +125 -0
  50. package/dist/bin/pushary-connect.d.ts +1 -0
  51. package/dist/bin/pushary-connect.js +100 -0
  52. package/dist/bin/pushary-cowork.d.ts +1 -0
  53. package/dist/bin/pushary-cowork.js +36 -0
  54. package/dist/bin/pushary-daemon-supervisor.d.ts +1 -0
  55. package/dist/bin/pushary-daemon-supervisor.js +27 -0
  56. package/dist/bin/pushary-daemon.d.ts +1 -0
  57. package/dist/bin/pushary-daemon.js +878 -0
  58. package/dist/bin/pushary-disconnect.d.ts +1 -0
  59. package/dist/bin/pushary-disconnect.js +264 -0
  60. package/dist/bin/pushary-doctor.d.ts +1 -0
  61. package/dist/bin/pushary-doctor.js +1433 -0
  62. package/dist/bin/pushary-elicitation-hook.d.ts +1 -0
  63. package/dist/bin/pushary-elicitation-hook.js +149 -0
  64. package/dist/bin/pushary-gemini-bridge.d.ts +1 -0
  65. package/dist/bin/pushary-gemini-bridge.js +339 -0
  66. package/dist/bin/pushary-gemini-hook.d.ts +1 -0
  67. package/dist/bin/pushary-gemini-hook.js +381 -0
  68. package/dist/bin/pushary-hook.d.ts +1 -0
  69. package/dist/bin/pushary-hook.js +95 -0
  70. package/dist/bin/pushary-login.d.ts +1 -0
  71. package/dist/bin/pushary-login.js +198 -0
  72. package/dist/bin/pushary-logout.d.ts +1 -0
  73. package/dist/bin/pushary-logout.js +147 -0
  74. package/dist/bin/pushary-mcp.d.ts +1 -0
  75. package/dist/bin/pushary-mcp.js +114 -0
  76. package/dist/bin/pushary-mode.d.ts +1 -0
  77. package/dist/bin/pushary-mode.js +130 -0
  78. package/dist/bin/pushary-notification-hook.d.ts +1 -0
  79. package/dist/bin/pushary-notification-hook.js +56 -0
  80. package/dist/bin/pushary-opencode-hook.d.ts +1 -0
  81. package/dist/bin/pushary-opencode-hook.js +338 -0
  82. package/dist/bin/pushary-permission-denied-hook.d.ts +1 -0
  83. package/dist/bin/pushary-permission-denied-hook.js +60 -0
  84. package/dist/bin/pushary-permission-hook.d.ts +1 -0
  85. package/dist/bin/pushary-permission-hook.js +65 -0
  86. package/dist/bin/pushary-post-hook.d.ts +1 -0
  87. package/dist/bin/pushary-post-hook.js +70 -0
  88. package/dist/bin/pushary-prompt-hook.d.ts +1 -0
  89. package/dist/bin/pushary-prompt-hook.js +61 -0
  90. package/dist/bin/pushary-session-end-hook.d.ts +1 -0
  91. package/dist/bin/pushary-session-end-hook.js +59 -0
  92. package/dist/bin/pushary-session-start-hook.d.ts +1 -0
  93. package/dist/bin/pushary-session-start-hook.js +72 -0
  94. package/dist/bin/pushary-setup.d.ts +1 -0
  95. package/dist/bin/pushary-setup.js +2660 -0
  96. package/dist/bin/pushary-stats.d.ts +1 -0
  97. package/dist/bin/pushary-stats.js +44 -0
  98. package/dist/bin/pushary-status.d.ts +1 -0
  99. package/dist/bin/pushary-status.js +262 -0
  100. package/dist/bin/pushary-stop-hook.d.ts +1 -0
  101. package/dist/bin/pushary-stop-hook.js +63 -0
  102. package/dist/bin/pushary-stopfailure-hook.d.ts +1 -0
  103. package/dist/bin/pushary-stopfailure-hook.js +56 -0
  104. package/dist/bin/pushary-suggestions.d.ts +1 -0
  105. package/dist/bin/pushary-suggestions.js +100 -0
  106. package/dist/bin/pushary-transcript-register.d.ts +1 -0
  107. package/dist/bin/pushary-transcript-register.js +40 -0
  108. package/dist/bin/pushary-transcripts.d.ts +1 -0
  109. package/dist/bin/pushary-transcripts.js +77 -0
  110. package/dist/bin/pushary-upgrade.d.ts +1 -0
  111. package/dist/bin/pushary-upgrade.js +599 -0
  112. package/dist/bin/pushary-wait.d.ts +1 -0
  113. package/dist/bin/pushary-wait.js +122 -0
  114. package/dist/bin/pushary.d.ts +1 -0
  115. package/dist/bin/pushary.js +74 -0
  116. package/dist/chunk-2ABTSGFT.js +173 -0
  117. package/dist/chunk-2OY3ZZ5N.js +124 -0
  118. package/dist/chunk-3EGEA4KH.js +44 -0
  119. package/dist/chunk-3EVPNIBE.js +185 -0
  120. package/dist/chunk-5OP5MQI7.js +45 -0
  121. package/dist/chunk-6J2JC2RT.js +149 -0
  122. package/dist/chunk-7QLSKOSU.js +19 -0
  123. package/dist/chunk-7Z7Q4GGS.js +88 -0
  124. package/dist/chunk-A2A2YTMG.js +835 -0
  125. package/dist/chunk-AHV4LNB5.js +377 -0
  126. package/dist/chunk-AXPCESYO.js +197 -0
  127. package/dist/chunk-C2WCPBF7.js +86 -0
  128. package/dist/chunk-CJVVKOSR.js +73 -0
  129. package/dist/chunk-CULUZTWQ.js +2117 -0
  130. package/dist/chunk-CVQYGMSR.js +142 -0
  131. package/dist/chunk-CVWG2N3Y.js +16 -0
  132. package/dist/chunk-D2FX3EPW.js +15 -0
  133. package/dist/chunk-DB3ONZB4.js +44 -0
  134. package/dist/chunk-DE4Y6TCC.js +160 -0
  135. package/dist/chunk-E4FJTUH4.js +249 -0
  136. package/dist/chunk-EPCXUP3P.js +41 -0
  137. package/dist/chunk-EX3GAPA4.js +44 -0
  138. package/dist/chunk-EYK3GSRH.js +143 -0
  139. package/dist/chunk-GMXKITVA.js +70 -0
  140. package/dist/chunk-GPEGOGRJ.js +49 -0
  141. package/dist/chunk-GU3EJCVV.js +43 -0
  142. package/dist/chunk-HQ6G3B5R.js +59 -0
  143. package/dist/chunk-HZVVNGEW.js +22 -0
  144. package/dist/chunk-IPVKH2ST.js +231 -0
  145. package/dist/chunk-J5TIV3J6.js +238 -0
  146. package/dist/chunk-JU6W3XAU.js +64 -0
  147. package/dist/chunk-JYG4B33G.js +227 -0
  148. package/dist/chunk-JZTHGAPA.js +503 -0
  149. package/dist/chunk-KGDWDSNL.js +102 -0
  150. package/dist/chunk-KVQBWI5T.js +99 -0
  151. package/dist/chunk-KZERVKTD.js +16 -0
  152. package/dist/chunk-LXQ5FBBD.js +47 -0
  153. package/dist/chunk-M5ICYGHT.js +138 -0
  154. package/dist/chunk-M5JDZ45W.js +943 -0
  155. package/dist/chunk-MDEPU45E.js +1226 -0
  156. package/dist/chunk-MPWXGONV.js +157 -0
  157. package/dist/chunk-N6IOSZOE.js +185 -0
  158. package/dist/chunk-NGDD6TXY.js +192 -0
  159. package/dist/chunk-NQTHFF4W.js +2830 -0
  160. package/dist/chunk-OKXS7WDZ.js +68 -0
  161. package/dist/chunk-OLQRRFBX.js +21 -0
  162. package/dist/chunk-P7WQEVWA.js +307 -0
  163. package/dist/chunk-POFBE6ZY.js +12 -0
  164. package/dist/chunk-PQ4K74WL.js +30 -0
  165. package/dist/chunk-PUZZELE6.js +37 -0
  166. package/dist/chunk-Q7E4I6UA.js +767 -0
  167. package/dist/chunk-QCGNGEGE.js +15 -0
  168. package/dist/chunk-R7437YI3.js +151 -0
  169. package/dist/chunk-RHR6NARM.js +305 -0
  170. package/dist/chunk-SAXBC4AZ.js +60 -0
  171. package/dist/chunk-SGZJ5LYH.js +76 -0
  172. package/dist/chunk-SIFVFP6T.js +70 -0
  173. package/dist/chunk-SLFABHW3.js +150 -0
  174. package/dist/chunk-T7E75EKA.js +67 -0
  175. package/dist/chunk-TY4JT7W3.js +38 -0
  176. package/dist/chunk-U4TMAANR.js +111 -0
  177. package/dist/chunk-UI36QSBI.js +177 -0
  178. package/dist/chunk-VQKRG3AC.js +339 -0
  179. package/dist/chunk-WE2J62NC.js +1131 -0
  180. package/dist/chunk-XHKBHWLX.js +14 -0
  181. package/dist/chunk-ZSZSSJCV.js +275 -0
  182. package/dist/chunk-ZVSKMPBZ.js +135 -0
  183. package/dist/reapply-CW3MA66V.js +34 -0
  184. package/dist/src/index.d.ts +204 -0
  185. package/dist/src/index.js +64 -0
  186. package/package.json +108 -0
@@ -0,0 +1,122 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ describeWaitLadder
4
+ } from "../chunk-CVWG2N3Y.js";
5
+ import {
6
+ exitOnFailedResponse
7
+ } from "../chunk-EX3GAPA4.js";
8
+ import {
9
+ createIo
10
+ } from "../chunk-U4TMAANR.js";
11
+ import {
12
+ exitOnHelpFlag
13
+ } from "../chunk-HZVVNGEW.js";
14
+ import {
15
+ rejectUnknownFlags
16
+ } from "../chunk-GMXKITVA.js";
17
+ import "../chunk-2ABTSGFT.js";
18
+ import "../chunk-2OY3ZZ5N.js";
19
+ import "../chunk-LXQ5FBBD.js";
20
+ import {
21
+ UsageError
22
+ } from "../chunk-7QLSKOSU.js";
23
+ import {
24
+ EXIT
25
+ } from "../chunk-KZERVKTD.js";
26
+ import "../chunk-A2A2YTMG.js";
27
+ import "../chunk-T7E75EKA.js";
28
+ import {
29
+ getApiKey,
30
+ getBaseUrl
31
+ } from "../chunk-GPEGOGRJ.js";
32
+ import "../chunk-E4FJTUH4.js";
33
+ import "../chunk-NQTHFF4W.js";
34
+
35
+ // bin/pushary-wait.ts
36
+ exitOnHelpFlag("wait");
37
+ var { dim, bold, green, cyan, yellow } = createIo();
38
+ var MAX_WINDOW = 300;
39
+ var printLadder = (data) => {
40
+ console.log();
41
+ console.log(` ${bold("Wait ladder")} ${dim("(what happens when you don't answer)")}`);
42
+ console.log();
43
+ console.log(` Default push window: ${cyan(`${data.defaultPushFirstSeconds}s`)} ${dim("(catch-all tools)")}`);
44
+ if (data.modeOverride) {
45
+ console.log(` ${yellow("!")} Active mode override: ${cyan(data.modeOverride)} ${dim("(pushary mode status)")}`);
46
+ }
47
+ console.log();
48
+ const rows = [...data.policies].sort((a, b) => a.tool === "*" ? -1 : b.tool === "*" ? 1 : a.tool.localeCompare(b.tool));
49
+ const width = Math.max(...rows.map((p) => p.tool.length), 4);
50
+ for (const p of rows) {
51
+ const label = p.tool === "*" ? "default (*)" : p.tool;
52
+ console.log(` ${label.padEnd(width + 2)} ${dim("\xB7")} ${describeWaitLadder(p)}`);
53
+ }
54
+ console.log();
55
+ console.log(` ${dim("Set the default window:")} ${cyan("pushary wait <seconds>")}`);
56
+ console.log(` ${dim("Reset it:")} ${cyan("pushary wait clear")}`);
57
+ console.log(` ${dim("Per-tool rules live in the dashboard under Agent \u2192 Policies.")}`);
58
+ };
59
+ var fetchPolicy = async (baseUrl, headers) => {
60
+ const res = await fetch(`${baseUrl}/api/mcp/policy`, { headers });
61
+ if (!res.ok) await exitOnFailedResponse(res, baseUrl);
62
+ return res.json();
63
+ };
64
+ var setWindow = async (baseUrl, headers, seconds) => {
65
+ const res = await fetch(`${baseUrl}/api/mcp/policy`, {
66
+ method: "PATCH",
67
+ headers,
68
+ body: JSON.stringify({ defaultPushFirstSeconds: seconds })
69
+ });
70
+ if (!res.ok) await exitOnFailedResponse(res, baseUrl);
71
+ const data = await res.json();
72
+ return data.defaultPushFirstSeconds;
73
+ };
74
+ {
75
+ const raw = process.argv.slice(2);
76
+ const positional = raw[0] === "wait" ? raw.slice(1) : raw;
77
+ try {
78
+ rejectUnknownFlags(positional, []);
79
+ } catch (err) {
80
+ process.stderr.write(` ! ${err instanceof Error ? err.message : String(err)}
81
+ `);
82
+ process.exit(EXIT.USAGE);
83
+ }
84
+ }
85
+ var main = async () => {
86
+ const apiKey = getApiKey();
87
+ const baseUrl = getBaseUrl();
88
+ const headers = {
89
+ "Authorization": `Bearer ${apiKey}`,
90
+ "Content-Type": "application/json"
91
+ };
92
+ const rest = process.argv.slice(2);
93
+ const args = rest[0] === "wait" ? rest.slice(1) : rest;
94
+ const arg = args[0];
95
+ if (!arg || arg === "status") {
96
+ printLadder(await fetchPolicy(baseUrl, headers));
97
+ return;
98
+ }
99
+ if (arg === "clear" || arg === "reset") {
100
+ const value2 = await setWindow(baseUrl, headers, 20);
101
+ console.log(` ${green("\u2713")} Default push window reset to ${cyan(`${value2}s`)}`);
102
+ return;
103
+ }
104
+ const seconds = Number(arg);
105
+ if (!Number.isFinite(seconds) || seconds < 0 || seconds > MAX_WINDOW) {
106
+ console.log(` ${yellow("!")} Invalid window: ${arg} ${dim(`(use 0-${MAX_WINDOW} seconds, or "status" / "clear")`)}`);
107
+ console.log(` ${dim("Usage: pushary wait <seconds> | status | clear")}`);
108
+ process.exit(EXIT.USAGE);
109
+ }
110
+ const value = await setWindow(baseUrl, headers, Math.trunc(seconds));
111
+ const ladder = describeWaitLadder({ tool: "*", mode: "push_first", pushFirstSeconds: value, timeoutSeconds: 0, timeoutAction: "escalate" });
112
+ console.log(` ${green("\u2713")} Default push window set to ${cyan(`${value}s`)} ${dim(`(${ladder})`)}`);
113
+ };
114
+ main().catch((err) => {
115
+ if (err instanceof UsageError) {
116
+ process.stderr.write(` ! ${err.message}
117
+ `);
118
+ process.exit(EXIT.USAGE);
119
+ }
120
+ console.error(` ${yellow("!")} ${err instanceof Error ? err.message : err}`);
121
+ process.exit(1);
122
+ });
@@ -0,0 +1 @@
1
+ #!/usr/bin/env node
@@ -0,0 +1,74 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ installNetworkDefaults
4
+ } from "../chunk-2OY3ZZ5N.js";
5
+ import "../chunk-LXQ5FBBD.js";
6
+ import "../chunk-7QLSKOSU.js";
7
+ import {
8
+ EXIT
9
+ } from "../chunk-KZERVKTD.js";
10
+ import "../chunk-A2A2YTMG.js";
11
+ import "../chunk-T7E75EKA.js";
12
+ import "../chunk-GPEGOGRJ.js";
13
+ import {
14
+ COMMANDS,
15
+ isCommandName,
16
+ renderHelp
17
+ } from "../chunk-E4FJTUH4.js";
18
+ import {
19
+ getPackageVersion
20
+ } from "../chunk-NQTHFF4W.js";
21
+
22
+ // src/cli/runtime.ts
23
+ var supportsRuntime = (version) => {
24
+ const [major, minor] = version.split(".").map(Number);
25
+ return major >= 24 || major === 23 && minor >= 5 || major === 22 && minor >= 13 || major === 20 && minor >= 17;
26
+ };
27
+
28
+ // bin/pushary.ts
29
+ var LOADERS = {
30
+ setup: () => import("./pushary-setup.js"),
31
+ cowork: () => import("./pushary-cowork.js"),
32
+ claude: () => import("./pushary-claude.js"),
33
+ daemon: () => import("./pushary-daemon.js"),
34
+ status: () => import("./pushary-status.js"),
35
+ login: () => import("./pushary-login.js"),
36
+ logout: () => import("./pushary-logout.js"),
37
+ connect: () => import("./pushary-connect.js"),
38
+ bell: () => import("./pushary-bell.js"),
39
+ doctor: () => import("./pushary-doctor.js"),
40
+ disconnect: () => import("./pushary-disconnect.js"),
41
+ clean: () => import("./pushary-clean.js"),
42
+ mode: () => import("./pushary-mode.js"),
43
+ wait: () => import("./pushary-wait.js"),
44
+ stats: () => import("./pushary-stats.js"),
45
+ suggestions: () => import("./pushary-suggestions.js"),
46
+ upgrade: () => import("./pushary-upgrade.js"),
47
+ hook: () => import("./pushary-hook.js"),
48
+ transcripts: () => import("./pushary-transcripts.js")
49
+ };
50
+ if (!supportsRuntime(process.versions.node)) {
51
+ process.stderr.write("Pushary requires Node 20.17+, 22.13+, or 23.5+. Upgrade to a current Node LTS and retry.\n");
52
+ process.exit(EXIT.USAGE);
53
+ }
54
+ installNetworkDefaults();
55
+ var argv = process.argv.slice(2);
56
+ var command = argv[0] ?? "";
57
+ var wants = (...names) => argv.some((arg) => names.includes(arg));
58
+ if (!command || wants("--help", "-h") && !isCommandName(command)) {
59
+ process.stdout.write(renderHelp(getPackageVersion()));
60
+ process.exit(EXIT.OK);
61
+ }
62
+ if (wants("--version", "-v") && !isCommandName(command)) {
63
+ process.stdout.write(`${getPackageVersion()}
64
+ `);
65
+ process.exit(EXIT.OK);
66
+ }
67
+ if (!isCommandName(command)) {
68
+ process.stderr.write(`Unknown command: ${command}
69
+ `);
70
+ process.stderr.write(`Run \`pushary --help\`. Available: ${COMMANDS.map((c) => c.name).join(", ")}
71
+ `);
72
+ process.exit(EXIT.USAGE);
73
+ }
74
+ await LOADERS[command]();
@@ -0,0 +1,173 @@
1
+ import {
2
+ pusharyFetch
3
+ } from "./chunk-2OY3ZZ5N.js";
4
+ import {
5
+ NetworkError
6
+ } from "./chunk-7QLSKOSU.js";
7
+ import {
8
+ EXIT
9
+ } from "./chunk-KZERVKTD.js";
10
+ import {
11
+ getBaseUrl
12
+ } from "./chunk-GPEGOGRJ.js";
13
+ import {
14
+ isValidApiKey,
15
+ normalizeKeyScope
16
+ } from "./chunk-NQTHFF4W.js";
17
+
18
+ // src/session.ts
19
+ var samePusharyAccount = (left, right) => left.kind === "ok" && right.kind === "ok" && left.identity.workspaceId !== "" && left.identity.workspaceId === right.identity.workspaceId && left.identity.siteId === right.identity.siteId;
20
+ var IDENTITY_PATH = "/api/v1/server/identity";
21
+ var DEFAULT_TIMEOUT_MS = 1e4;
22
+ var SUBSCRIPTION_REQUIRED_CODE = "subscription_required";
23
+ var DEFAULT_UPGRADE_PATH = "/dashboard/settings?tab=billing";
24
+ var SUBSCRIPTION_STATUSES = [
25
+ "active",
26
+ "past_due",
27
+ "canceled",
28
+ "incomplete",
29
+ "trialing",
30
+ "expired",
31
+ "none"
32
+ ];
33
+ var asString = (value) => typeof value === "string" && value ? value : null;
34
+ var asStatus = (value) => SUBSCRIPTION_STATUSES.includes(value) ? value : "none";
35
+ var asCount = (value) => typeof value === "number" && Number.isFinite(value) ? Math.max(0, Math.trunc(value)) : 0;
36
+ var absoluteUrl = (baseUrl, pathOrUrl) => {
37
+ if (/^https?:\/\//i.test(pathOrUrl)) return pathOrUrl;
38
+ return `${baseUrl.replace(/\/+$/, "")}${pathOrUrl.startsWith("/") ? "" : "/"}${pathOrUrl}`;
39
+ };
40
+ var toIdentity = (body) => {
41
+ if (typeof body !== "object" || body === null) return null;
42
+ const raw = body;
43
+ const keyId = asString(raw.keyId);
44
+ const siteId = asString(raw.siteId);
45
+ const keyScope = normalizeKeyScope(raw.keyScope);
46
+ if (!keyId || !siteId || !keyScope) return null;
47
+ return {
48
+ keyId,
49
+ keyPrefix: asString(raw.keyPrefix) ?? "",
50
+ keyName: asString(raw.keyName) ?? "",
51
+ keyScope,
52
+ siteId,
53
+ siteSlug: asString(raw.siteSlug) ?? "",
54
+ siteName: asString(raw.siteName) ?? "",
55
+ workspaceId: asString(raw.workspaceId) ?? "",
56
+ plan: asString(raw.plan) ?? "unknown",
57
+ surfacePlan: asString(raw.surfacePlan) ?? "unknown",
58
+ subscriptionStatus: asStatus(raw.subscriptionStatus),
59
+ locked: raw.locked === true,
60
+ machineId: asString(raw.machineId),
61
+ authorizedUserId: asString(raw.authorizedUserId),
62
+ workspaceMembers: asCount(raw.workspaceMembers),
63
+ createdAt: asString(raw.createdAt),
64
+ lastUsedAt: asString(raw.lastUsedAt)
65
+ };
66
+ };
67
+ var readJsonBody = async (response) => {
68
+ try {
69
+ return await response.json();
70
+ } catch {
71
+ return null;
72
+ }
73
+ };
74
+ var checkApiKey = async (apiKey, options = {}) => {
75
+ if (!isValidApiKey(apiKey)) return { kind: "malformed" };
76
+ const baseUrl = options.baseUrl ?? getBaseUrl();
77
+ const fetchImpl = options.fetchImpl ?? pusharyFetch;
78
+ const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
79
+ let response;
80
+ try {
81
+ response = await fetchImpl(`${baseUrl.replace(/\/+$/, "")}${IDENTITY_PATH}`, {
82
+ headers: { Authorization: `Bearer ${apiKey}`, Accept: "application/json" },
83
+ timeoutMs
84
+ });
85
+ } catch (err) {
86
+ const detail = err instanceof NetworkError || err instanceof Error ? err.message : String(err);
87
+ return { kind: "unreachable", detail };
88
+ }
89
+ if (response.status === 401) return { kind: "rejected" };
90
+ if (response.status === 403) {
91
+ const body = await readJsonBody(response);
92
+ const raw = typeof body === "object" && body !== null ? body : {};
93
+ if (raw.code !== SUBSCRIPTION_REQUIRED_CODE) {
94
+ return { kind: "unreachable", detail: asString(raw.message) ?? `HTTP ${response.status}` };
95
+ }
96
+ return {
97
+ kind: "locked",
98
+ plan: asString(raw.plan),
99
+ upgradeUrl: absoluteUrl(baseUrl, asString(raw.upgradeUrl) ?? DEFAULT_UPGRADE_PATH)
100
+ };
101
+ }
102
+ if (!response.ok) {
103
+ return { kind: "unreachable", detail: `HTTP ${response.status}` };
104
+ }
105
+ const identity = toIdentity(await readJsonBody(response));
106
+ if (!identity) {
107
+ return { kind: "unreachable", detail: "the server answered with an unexpected body" };
108
+ }
109
+ return { kind: "ok", identity };
110
+ };
111
+ var keyCheckFromResponse = async (response, baseUrl = getBaseUrl()) => {
112
+ if (response.status === 401) return { kind: "rejected" };
113
+ if (response.status !== 403) return null;
114
+ const body = await readJsonBody(response.clone());
115
+ const raw = typeof body === "object" && body !== null ? body : {};
116
+ if (raw.code !== SUBSCRIPTION_REQUIRED_CODE) return null;
117
+ return {
118
+ kind: "locked",
119
+ plan: asString(raw.plan),
120
+ upgradeUrl: absoluteUrl(baseUrl, asString(raw.upgradeUrl) ?? DEFAULT_UPGRADE_PATH)
121
+ };
122
+ };
123
+ var describeKeyCheck = (check, baseUrl = getBaseUrl()) => {
124
+ const settingsUrl = absoluteUrl(baseUrl, "/dashboard/agent/settings");
125
+ switch (check.kind) {
126
+ case "ok":
127
+ return {
128
+ message: `Key verified for ${check.identity.siteSlug || check.identity.siteName || "your site"}.`,
129
+ next: [],
130
+ exitCode: EXIT.OK,
131
+ fatal: false
132
+ };
133
+ case "malformed":
134
+ return {
135
+ message: "That does not look like a Pushary API key.",
136
+ next: [`Expected the pk_xxx.xxx form. Copy yours from ${settingsUrl}`],
137
+ exitCode: EXIT.USAGE,
138
+ fatal: true
139
+ };
140
+ case "rejected":
141
+ return {
142
+ message: "This key was rejected by pushary.com.",
143
+ next: [`Get a working key: ${settingsUrl}`, "Then re-run: pushary setup"],
144
+ exitCode: EXIT.UNAUTHENTICATED,
145
+ fatal: true
146
+ };
147
+ case "locked":
148
+ return {
149
+ message: "Your Pushary plan is not active, so approvals will not deliver yet.",
150
+ next: [
151
+ "Your key is valid; activating the plan does not require replacing it.",
152
+ `Activate the plan: ${check.upgradeUrl}`,
153
+ "Then run: pushary doctor"
154
+ ],
155
+ exitCode: EXIT.PROBLEMS_FOUND,
156
+ fatal: false
157
+ };
158
+ case "unreachable":
159
+ return {
160
+ message: `Could not reach pushary.com to verify the key (${check.detail}).`,
161
+ next: ["Account readiness is unverified. Re-run `pushary setup` once you are online."],
162
+ exitCode: EXIT.UNREACHABLE,
163
+ fatal: false
164
+ };
165
+ }
166
+ };
167
+
168
+ export {
169
+ samePusharyAccount,
170
+ checkApiKey,
171
+ keyCheckFromResponse,
172
+ describeKeyCheck
173
+ };
@@ -0,0 +1,124 @@
1
+ import {
2
+ readExistingMachineId
3
+ } from "./chunk-LXQ5FBBD.js";
4
+ import {
5
+ NetworkError
6
+ } from "./chunk-7QLSKOSU.js";
7
+ import {
8
+ getBaseUrl
9
+ } from "./chunk-GPEGOGRJ.js";
10
+ import {
11
+ clientContextHeaders,
12
+ getPackageVersion
13
+ } from "./chunk-NQTHFF4W.js";
14
+
15
+ // src/cli/net.ts
16
+ import { createRequire } from "module";
17
+
18
+ // src/cli/client-context.ts
19
+ import { randomUUID } from "crypto";
20
+ var CLI_RUN_ID = randomUUID();
21
+ var cliPlatform = () => `${process.platform}-${process.arch}`;
22
+ var memoizedContext = null;
23
+ var safeMachineId = () => {
24
+ try {
25
+ return readExistingMachineId();
26
+ } catch {
27
+ return null;
28
+ }
29
+ };
30
+ var readCliClientContext = () => ({
31
+ surface: "cli",
32
+ clientVersion: getPackageVersion(),
33
+ machineId: safeMachineId(),
34
+ runId: CLI_RUN_ID,
35
+ platform: cliPlatform()
36
+ });
37
+ var cliClientContext = () => {
38
+ if (memoizedContext) return memoizedContext;
39
+ const context = readCliClientContext();
40
+ if (context.machineId !== null) memoizedContext = context;
41
+ return context;
42
+ };
43
+ var originOf = (url) => {
44
+ try {
45
+ return new URL(url).origin;
46
+ } catch {
47
+ return null;
48
+ }
49
+ };
50
+ var requestUrlOf = (input) => typeof input === "string" ? input : input instanceof URL ? input.href : input.url;
51
+ var isPusharyRequest = (input, baseUrl) => {
52
+ const target = originOf(requestUrlOf(input));
53
+ return target !== null && target === originOf(baseUrl);
54
+ };
55
+ var mergeClientContextHeaders = (input, init, context) => {
56
+ const headers = new Headers(input instanceof Request ? input.headers : void 0);
57
+ new Headers(init?.headers).forEach((value, name) => headers.set(name, value));
58
+ for (const [name, value] of Object.entries(clientContextHeaders(context))) {
59
+ if (!headers.has(name)) headers.set(name, value);
60
+ }
61
+ return headers;
62
+ };
63
+ var withClientContext = (fetchImpl, options) => (input, init) => isPusharyRequest(input, options.baseUrl()) ? fetchImpl(input, { ...init, headers: mergeClientContextHeaders(input, init, options.context()) }) : fetchImpl(input, init);
64
+ var installed = false;
65
+ var installClientContextHeaders = () => {
66
+ if (installed) return;
67
+ installed = true;
68
+ globalThis.fetch = withClientContext(globalThis.fetch.bind(globalThis), { baseUrl: getBaseUrl, context: cliClientContext });
69
+ };
70
+
71
+ // src/cli/net.ts
72
+ var requireCjs = createRequire(import.meta.url);
73
+ var PROXY_VARS = ["HTTPS_PROXY", "https_proxy", "HTTP_PROXY", "http_proxy"];
74
+ var proxyFromEnv = () => {
75
+ for (const name of PROXY_VARS) {
76
+ const value = process.env[name]?.trim();
77
+ if (value) return value;
78
+ }
79
+ return void 0;
80
+ };
81
+ var installed2 = false;
82
+ var installNetworkDefaults = () => {
83
+ if (installed2) return;
84
+ installed2 = true;
85
+ installClientContextHeaders();
86
+ if (!proxyFromEnv()) return;
87
+ try {
88
+ const { EnvHttpProxyAgent, setGlobalDispatcher } = requireCjs("undici");
89
+ setGlobalDispatcher(new EnvHttpProxyAgent());
90
+ } catch {
91
+ }
92
+ };
93
+ var isNetworkFailure = (err) => {
94
+ if (!(err instanceof Error)) return false;
95
+ const code = err.code;
96
+ if (code && ["ENOTFOUND", "ECONNREFUSED", "ECONNRESET", "ETIMEDOUT", "EAI_AGAIN", "EPROTO", "CERT_HAS_EXPIRED", "UNABLE_TO_VERIFY_LEAF_SIGNATURE"].includes(code)) {
97
+ return true;
98
+ }
99
+ return err.name === "AbortError" || err.name === "TimeoutError" || /fetch failed/i.test(err.message);
100
+ };
101
+ var DEFAULT_TIMEOUT_MS = 15e3;
102
+ var pusharyFetch = async (url, init = {}) => {
103
+ installNetworkDefaults();
104
+ const { timeoutMs = DEFAULT_TIMEOUT_MS, signal, ...rest } = init;
105
+ try {
106
+ return await fetch(url, {
107
+ ...rest,
108
+ signal: signal ?? AbortSignal.timeout(timeoutMs)
109
+ });
110
+ } catch (err) {
111
+ if (isNetworkFailure(err)) {
112
+ const proxy = proxyFromEnv();
113
+ const via = proxy ? ` (via proxy ${proxy})` : "";
114
+ throw new NetworkError(`Could not reach ${new URL(url).host}${via}: ${err instanceof Error ? err.message : String(err)}`);
115
+ }
116
+ throw err;
117
+ }
118
+ };
119
+
120
+ export {
121
+ installNetworkDefaults,
122
+ isNetworkFailure,
123
+ pusharyFetch
124
+ };
@@ -0,0 +1,44 @@
1
+ // src/pairing.ts
2
+ import crypto from "crypto";
3
+ var X25519_SPKI_PREFIX = Buffer.from("302a300506032b656e032100", "hex");
4
+ var HKDF_INFO = Buffer.from("pushary-pair-v1");
5
+ var HEADER_BYTES = 32 + 12 + 16;
6
+ var rawToPublicKey = (raw) => crypto.createPublicKey({
7
+ key: Buffer.concat([X25519_SPKI_PREFIX, raw]),
8
+ format: "der",
9
+ type: "spki"
10
+ });
11
+ var publicKeyToRaw = (key) => key.export({ format: "der", type: "spki" }).subarray(-32);
12
+ var generateKeypair = () => {
13
+ const { publicKey, privateKey } = crypto.generateKeyPairSync("x25519");
14
+ const publicKeyRaw = publicKeyToRaw(publicKey);
15
+ return { publicKeyB64: publicKeyRaw.toString("base64"), publicKeyRaw, privateKey };
16
+ };
17
+ var publicKeyFingerprint = (b64) => {
18
+ const raw = Buffer.from(b64, "base64");
19
+ const digest = crypto.createHash("sha256").update(raw).digest("hex");
20
+ return (digest.slice(0, 8).match(/.{2}/g) ?? []).join(" ").toUpperCase();
21
+ };
22
+ var openSealedKey = (blobB64, keypair) => {
23
+ const blob = Buffer.from(blobB64, "base64");
24
+ if (blob.length <= HEADER_BYTES) throw new Error("sealed payload too short");
25
+ const ephemeralRaw = blob.subarray(0, 32);
26
+ const nonce = blob.subarray(32, 44);
27
+ const tag = blob.subarray(44, 60);
28
+ const ciphertext = blob.subarray(60);
29
+ const shared = crypto.diffieHellman({
30
+ privateKey: keypair.privateKey,
31
+ publicKey: rawToPublicKey(ephemeralRaw)
32
+ });
33
+ const salt = Buffer.concat([ephemeralRaw, keypair.publicKeyRaw]);
34
+ const key = Buffer.from(crypto.hkdfSync("sha256", shared, salt, HKDF_INFO, 32));
35
+ const decipher = crypto.createDecipheriv("aes-256-gcm", key, nonce);
36
+ decipher.setAuthTag(tag);
37
+ return Buffer.concat([decipher.update(ciphertext), decipher.final()]).toString("utf8");
38
+ };
39
+
40
+ export {
41
+ generateKeypair,
42
+ publicKeyFingerprint,
43
+ openSealedKey
44
+ };