@pushary/agent-hooks 0.64.1 → 0.64.3
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 +61 -0
- package/dist/bin/pushary-claude.js +1 -1
- package/dist/bin/pushary-codex-hook.js +1 -1
- package/dist/bin/pushary-codex.js +1 -1
- package/dist/bin/pushary-connect.js +1 -1
- package/dist/bin/pushary-doctor.js +1 -1
- package/dist/bin/pushary-gemini-hook.js +1 -1
- package/dist/bin/pushary-hook.js +2 -2
- package/dist/bin/pushary-notification-hook.js +1 -1
- package/dist/bin/pushary-permission-denied-hook.js +2 -2
- package/dist/bin/pushary-permission-hook.js +2 -2
- package/dist/bin/pushary-post-hook.js +1 -1
- package/dist/bin/pushary-prompt-hook.js +1 -1
- package/dist/bin/pushary-session-end-hook.js +1 -1
- package/dist/bin/pushary-session-start-hook.js +1 -1
- package/dist/bin/pushary-setup.js +104 -37
- package/dist/bin/pushary-status.js +1 -1
- package/dist/bin/pushary-stop-hook.js +1 -1
- package/dist/bin/pushary-stopfailure-hook.js +1 -1
- package/dist/{chunk-RASBS2CC.js → chunk-GFHQ26ST.js} +2 -2
- package/dist/{chunk-SDXF5I46.js → chunk-SONXGCZY.js} +1 -1
- package/dist/{chunk-5ZDYDU2Q.js → chunk-XOUYM27W.js} +1 -1
- package/dist/src/index.d.ts +10 -0
- package/dist/src/index.js +2 -2
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,66 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.64.3
|
|
4
|
+
|
|
5
|
+
### A stale shell export hid the working key on disk
|
|
6
|
+
|
|
7
|
+
`PUSHARY_API_KEY` wins over `~/.pushary/config.json`, which is right and
|
|
8
|
+
unchanged. But the environment used to win on the key's *shape* alone, so a
|
|
9
|
+
well-formed key the server had since revoked shadowed a working one in the config
|
|
10
|
+
file and setup exited "This key was rejected by pushary.com" with a perfectly
|
|
11
|
+
good key sitting on the machine.
|
|
12
|
+
|
|
13
|
+
That is the state any shell left open across a key rotation is in: the export is
|
|
14
|
+
the old key, the file is the new one, and the terminal you happen to be typing in
|
|
15
|
+
decides whether setup works.
|
|
16
|
+
|
|
17
|
+
The environment key is checked with the server before it is chosen now, and a
|
|
18
|
+
rejected one falls through to the stored key rather than ending the run. It costs
|
|
19
|
+
no extra call: the verdict is handed to the verification step that was already
|
|
20
|
+
making it.
|
|
21
|
+
|
|
22
|
+
### `--connect app` on a machine with no terminal named the wrong problem
|
|
23
|
+
|
|
24
|
+
A headless run that asked to pair said "No API key, and no terminal to sign in
|
|
25
|
+
from" even with a key in the config file, because asking to pair deliberately
|
|
26
|
+
takes the stored key off the table. It now says the flag needs a terminal for the
|
|
27
|
+
QR, and that dropping it uses the key already there.
|
|
28
|
+
|
|
29
|
+
## 0.64.2
|
|
30
|
+
|
|
31
|
+
### A run that gave up reported nothing, and said it stopped at the start
|
|
32
|
+
|
|
33
|
+
`agent_setup_completed` was wired to one of setup's fifteen exits: the last line
|
|
34
|
+
of a run that finished. Every other way out returned before it. A key the server
|
|
35
|
+
refused, a cancelled pairing, no terminal to sign in from, an installer that
|
|
36
|
+
threw, a Ctrl-C at the agent checkbox: all silent. The beacon was added so failed
|
|
37
|
+
and abandoned runs would stop being invisible, and the runs it could see were
|
|
38
|
+
still only the ones that already worked.
|
|
39
|
+
|
|
40
|
+
Every early exit reports now, and each says why it stopped: `key-refused`,
|
|
41
|
+
`pairing-cancelled`, `no-key`, `login-rejected`, `no-agents-detected`,
|
|
42
|
+
`invalid-key`, `interrupted`, `crashed`.
|
|
43
|
+
|
|
44
|
+
Argv-time exits stay silent, along with `--help` and `--dry-run`. A flag typo is
|
|
45
|
+
not an abandoned run: nothing was attempted and nothing was written. It is also
|
|
46
|
+
the fastest-failing path there is, and waiting on a beacon took `setup --bogus`
|
|
47
|
+
from 60ms to two seconds against an unreachable server. A dry run stays silent
|
|
48
|
+
for the other reason: counting it as a completed setup would be its own lie.
|
|
49
|
+
|
|
50
|
+
`abandonedAt` said where. It was always `start`, because `markStep` had no call
|
|
51
|
+
site outside its own test, so the field that was supposed to locate a failure was
|
|
52
|
+
a constant. It now moves through the run, per agent inside the configure loop, so
|
|
53
|
+
an installer that hangs is named rather than grouped.
|
|
54
|
+
|
|
55
|
+
Ctrl-C at the pairing QR reports before the process leaves. The cancel and the
|
|
56
|
+
beacon run concurrently and the exit waits for both, so this adds nothing to the
|
|
57
|
+
worst case a cancel already had.
|
|
58
|
+
|
|
59
|
+
The beacon authenticates with the key the run resolved rather than the one
|
|
60
|
+
already installed. Most of these exits happen before the key is written to disk,
|
|
61
|
+
so without that they posted as nobody, which meant the window holding the
|
|
62
|
+
interesting failures was exactly the window that could not report.
|
|
63
|
+
|
|
3
64
|
## 0.64.1
|
|
4
65
|
|
|
5
66
|
### Ctrl-C at the pairing QR printed nothing
|
package/dist/bin/pushary-hook.js
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
handlePreToolUse
|
|
4
|
-
} from "../chunk-
|
|
4
|
+
} from "../chunk-SONXGCZY.js";
|
|
5
5
|
import "../chunk-CAJZAFVS.js";
|
|
6
6
|
import {
|
|
7
7
|
exitOnHelpFlag
|
|
8
8
|
} from "../chunk-ATP6UQPH.js";
|
|
9
9
|
import "../chunk-JGH37QRB.js";
|
|
10
10
|
import "../chunk-YHG74UFF.js";
|
|
11
|
-
import "../chunk-
|
|
11
|
+
import "../chunk-XOUYM27W.js";
|
|
12
12
|
import "../chunk-WLGEY4UX.js";
|
|
13
13
|
import "../chunk-BSZYIAZL.js";
|
|
14
14
|
import "../chunk-SAF6HGAA.js";
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
handlePermissionDenied
|
|
4
|
-
} from "../chunk-
|
|
4
|
+
} from "../chunk-SONXGCZY.js";
|
|
5
5
|
import "../chunk-CAJZAFVS.js";
|
|
6
6
|
import "../chunk-YHG74UFF.js";
|
|
7
|
-
import "../chunk-
|
|
7
|
+
import "../chunk-XOUYM27W.js";
|
|
8
8
|
import "../chunk-WLGEY4UX.js";
|
|
9
9
|
import "../chunk-BSZYIAZL.js";
|
|
10
10
|
import "../chunk-SAF6HGAA.js";
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
handlePermissionRequest
|
|
4
|
-
} from "../chunk-
|
|
4
|
+
} from "../chunk-SONXGCZY.js";
|
|
5
5
|
import "../chunk-CAJZAFVS.js";
|
|
6
6
|
import "../chunk-YHG74UFF.js";
|
|
7
|
-
import "../chunk-
|
|
7
|
+
import "../chunk-XOUYM27W.js";
|
|
8
8
|
import "../chunk-WLGEY4UX.js";
|
|
9
9
|
import "../chunk-BSZYIAZL.js";
|
|
10
10
|
import "../chunk-SAF6HGAA.js";
|
|
@@ -45,7 +45,7 @@ import {
|
|
|
45
45
|
connectViaAppPairing,
|
|
46
46
|
printConnectInstructions,
|
|
47
47
|
setHumanStream
|
|
48
|
-
} from "../chunk-
|
|
48
|
+
} from "../chunk-GFHQ26ST.js";
|
|
49
49
|
import "../chunk-3EGEA4KH.js";
|
|
50
50
|
import {
|
|
51
51
|
KEY_FILE_MODE,
|
|
@@ -86,7 +86,7 @@ import {
|
|
|
86
86
|
} from "../chunk-JGH37QRB.js";
|
|
87
87
|
import {
|
|
88
88
|
reportEvent
|
|
89
|
-
} from "../chunk-
|
|
89
|
+
} from "../chunk-XOUYM27W.js";
|
|
90
90
|
import "../chunk-BSZYIAZL.js";
|
|
91
91
|
import "../chunk-SAF6HGAA.js";
|
|
92
92
|
import {
|
|
@@ -206,32 +206,60 @@ var installSkillViaSkillsCli = (agent) => {
|
|
|
206
206
|
|
|
207
207
|
// src/setup/telemetry.ts
|
|
208
208
|
var currentStep = "start";
|
|
209
|
+
var markStep = (step) => {
|
|
210
|
+
currentStep = step;
|
|
211
|
+
};
|
|
212
|
+
var recordedOptions = null;
|
|
213
|
+
var recordSetupOptions = (options) => {
|
|
214
|
+
recordedOptions = options;
|
|
215
|
+
};
|
|
216
|
+
var recordedKey = null;
|
|
217
|
+
var recordSetupKey = (apiKey) => {
|
|
218
|
+
recordedKey = apiKey;
|
|
219
|
+
};
|
|
209
220
|
var emitted = false;
|
|
210
|
-
var
|
|
221
|
+
var defaultDeps = { report: reportEvent };
|
|
222
|
+
var emit = async (deps, props) => {
|
|
211
223
|
if (emitted) return;
|
|
212
224
|
emitted = true;
|
|
213
225
|
try {
|
|
214
|
-
await
|
|
215
|
-
{
|
|
216
|
-
|
|
217
|
-
agentType: "setup",
|
|
218
|
-
agents: outcome.completed,
|
|
219
|
-
connectMode: outcome.options.connectMode,
|
|
220
|
-
connectOutcome: outcome.connectOutcome,
|
|
221
|
-
failedAgents: outcome.failed.length,
|
|
222
|
-
skippedAgents: outcome.skipped,
|
|
223
|
-
nonInteractive: outcome.options.nonInteractive,
|
|
224
|
-
keyCheck: outcome.keyCheck,
|
|
225
|
-
exitCode: outcome.exitCode,
|
|
226
|
-
// Where the run stopped. On a completed run this is the closing step, so
|
|
227
|
-
// the interesting values are the ones that are not.
|
|
228
|
-
abandonedAt: outcome.exitCode === 0 ? null : currentStep
|
|
229
|
-
},
|
|
230
|
-
{ maxAttempts: 1, timeoutMs: 2e3 }
|
|
226
|
+
await deps.report(
|
|
227
|
+
{ event: "agent_setup_completed", agentType: "setup", ...props },
|
|
228
|
+
{ maxAttempts: 1, timeoutMs: 2e3, ...recordedKey ? { apiKey: recordedKey } : {} }
|
|
231
229
|
);
|
|
232
230
|
} catch {
|
|
233
231
|
}
|
|
234
232
|
};
|
|
233
|
+
var reportSetupOutcomeWith = async (deps, outcome) => emit(deps, {
|
|
234
|
+
agents: outcome.completed,
|
|
235
|
+
connectMode: outcome.options.connectMode,
|
|
236
|
+
connectOutcome: outcome.connectOutcome,
|
|
237
|
+
failedAgents: outcome.failed.length,
|
|
238
|
+
skippedAgents: outcome.skipped,
|
|
239
|
+
nonInteractive: outcome.options.nonInteractive,
|
|
240
|
+
keyCheck: outcome.keyCheck,
|
|
241
|
+
exitCode: outcome.exitCode,
|
|
242
|
+
// Where the run stopped. On a completed run this is the closing step, so the
|
|
243
|
+
// interesting values are the ones that are not.
|
|
244
|
+
abandonedAt: outcome.exitCode === 0 ? null : currentStep,
|
|
245
|
+
// Always present, so a query can separate "ended" from "gave up" on the
|
|
246
|
+
// property rather than on the absence of one.
|
|
247
|
+
abortReason: null
|
|
248
|
+
});
|
|
249
|
+
var reportSetupOutcome = (outcome) => reportSetupOutcomeWith(defaultDeps, outcome);
|
|
250
|
+
var reportSetupAbortWith = async (deps, reason, exitCode, keyCheck = "unknown") => emit(deps, {
|
|
251
|
+
agents: [],
|
|
252
|
+
connectMode: recordedOptions?.connectMode ?? null,
|
|
253
|
+
connectOutcome: "skipped",
|
|
254
|
+
failedAgents: 0,
|
|
255
|
+
skippedAgents: [],
|
|
256
|
+
nonInteractive: recordedOptions?.nonInteractive ?? null,
|
|
257
|
+
keyCheck,
|
|
258
|
+
exitCode,
|
|
259
|
+
abandonedAt: currentStep,
|
|
260
|
+
abortReason: reason
|
|
261
|
+
});
|
|
262
|
+
var reportSetupAbort = (reason, exitCode, keyCheck) => reportSetupAbortWith(defaultDeps, reason, exitCode, keyCheck);
|
|
235
263
|
|
|
236
264
|
// src/setup/options.ts
|
|
237
265
|
var AGENT_CHOICES = ["claude_code", "codex", "gemini_cli", "hermes", "cursor", "custom"];
|
|
@@ -333,6 +361,10 @@ var green = (s) => `\x1B[32m${s}\x1B[0m`;
|
|
|
333
361
|
var cyan = (s) => `\x1B[36m${s}\x1B[0m`;
|
|
334
362
|
var yellow = (s) => `\x1B[33m${s}\x1B[0m`;
|
|
335
363
|
var check = green("\u2713");
|
|
364
|
+
var abortWith = async (reason, code, keyCheck) => {
|
|
365
|
+
await reportSetupAbort(reason, code, keyCheck);
|
|
366
|
+
return code;
|
|
367
|
+
};
|
|
336
368
|
var readKeyFromStdin = async (options) => {
|
|
337
369
|
if (!options.keyStdin) return void 0;
|
|
338
370
|
const chunks = [];
|
|
@@ -341,14 +373,14 @@ var readKeyFromStdin = async (options) => {
|
|
|
341
373
|
if (!first) {
|
|
342
374
|
console.log(`
|
|
343
375
|
${yellow("!")} --key-stdin was passed but stdin was empty.`);
|
|
344
|
-
process.exit(
|
|
376
|
+
process.exit(EXIT.USAGE);
|
|
345
377
|
}
|
|
346
378
|
if (!isValidApiKey(first)) {
|
|
347
379
|
console.log(`
|
|
348
380
|
${yellow("!")} The key on stdin is not a valid Pushary key. Expected: ${dim("pk_xxx.xxx")}`);
|
|
349
381
|
console.log(` ${dim("Copy your key from")} ${cyan("https://pushary.com/dashboard/agent/settings")}
|
|
350
382
|
`);
|
|
351
|
-
process.exit(
|
|
383
|
+
process.exit(EXIT.USAGE);
|
|
352
384
|
}
|
|
353
385
|
return first;
|
|
354
386
|
};
|
|
@@ -971,7 +1003,7 @@ var verifyKeyOrExit = async (apiKey, options, precomputed) => {
|
|
|
971
1003
|
console.log(` ${yellow("!")} ${report.message}`);
|
|
972
1004
|
for (const line of report.next) console.log(` ${dim(line)}`);
|
|
973
1005
|
console.log();
|
|
974
|
-
process.exit(report.exitCode);
|
|
1006
|
+
process.exit(await abortWith("key-refused", report.exitCode, result.kind));
|
|
975
1007
|
}
|
|
976
1008
|
if (result.kind === "ok") {
|
|
977
1009
|
const { siteSlug, siteName, plan } = result.identity;
|
|
@@ -1054,7 +1086,7 @@ var resolveAgents = async (options) => {
|
|
|
1054
1086
|
console.log(` ${yellow("!")} No agents detected, so nothing was configured. Your key is saved.`);
|
|
1055
1087
|
console.log(` ${dim("Install an agent and re-run, name one with --agents <id>, or pass --agents none to accept this.")}`);
|
|
1056
1088
|
console.log();
|
|
1057
|
-
process.exit(EXIT.PROBLEMS_FOUND);
|
|
1089
|
+
process.exit(await abortWith("no-agents-detected", EXIT.PROBLEMS_FOUND));
|
|
1058
1090
|
}
|
|
1059
1091
|
console.log(` ${check} Selected automatically: ${picked.map((a) => AGENT_NAMES[a]).join(", ")} ${dim("(--agents to choose)")}`);
|
|
1060
1092
|
return picked;
|
|
@@ -1125,6 +1157,7 @@ var main = async () => {
|
|
|
1125
1157
|
`);
|
|
1126
1158
|
process.exit(EXIT.OK);
|
|
1127
1159
|
}
|
|
1160
|
+
recordSetupOptions(options);
|
|
1128
1161
|
if (options.json) {
|
|
1129
1162
|
humanStream = process.stderr;
|
|
1130
1163
|
setHumanStream(process.stderr);
|
|
@@ -1139,6 +1172,7 @@ var main = async () => {
|
|
|
1139
1172
|
console.log(` ${dim("Push notifications for AI agents")}`);
|
|
1140
1173
|
console.log();
|
|
1141
1174
|
await checkForUpdates(version);
|
|
1175
|
+
markStep("resolve-key");
|
|
1142
1176
|
const connectMode = options.connectMode;
|
|
1143
1177
|
const flagKey = await readKeyFromStdin(options) ?? options.key ?? void 0;
|
|
1144
1178
|
const envKey = process.env.PUSHARY_API_KEY?.trim();
|
|
@@ -1146,7 +1180,10 @@ var main = async () => {
|
|
|
1146
1180
|
let keyFromPairing = false;
|
|
1147
1181
|
const storedKey = readConfigFileKey();
|
|
1148
1182
|
const pairingRequested = connectMode === "app" && options.connectExplicit && !options.skipPhone;
|
|
1149
|
-
const
|
|
1183
|
+
const ambientEligible = !(flagKey && isValidApiKey(flagKey)) && !pairingRequested;
|
|
1184
|
+
const envCheck = ambientEligible && envKey && isValidApiKey(envKey) ? await usableStoredKey(envKey) : null;
|
|
1185
|
+
const storedCheck = ambientEligible && envCheck === null && storedKey !== null && isValidApiKey(storedKey) && // login writes both, so without this the same key is probed twice.
|
|
1186
|
+
storedKey !== envKey ? await usableStoredKey(storedKey) : null;
|
|
1150
1187
|
let storedKeyCheck = null;
|
|
1151
1188
|
if (flagKey && isValidApiKey(flagKey)) {
|
|
1152
1189
|
const masked = `${flagKey.slice(0, 8)}...${flagKey.slice(-4)}`;
|
|
@@ -1160,13 +1197,14 @@ var main = async () => {
|
|
|
1160
1197
|
console.log();
|
|
1161
1198
|
trimmedKey = storedKey;
|
|
1162
1199
|
storedKeyCheck = storedCheck;
|
|
1163
|
-
} else if (
|
|
1200
|
+
} else if (envKey && envCheck !== null) {
|
|
1164
1201
|
const masked = `${envKey.slice(0, 8)}...${envKey.slice(-4)}`;
|
|
1165
1202
|
console.log(` ${check} Found API key in environment: ${dim(masked)}`);
|
|
1166
1203
|
console.log();
|
|
1167
1204
|
const useExisting = options.nonInteractive ? true : await confirm({ message: "Use this key?", default: true });
|
|
1168
1205
|
if (useExisting) {
|
|
1169
1206
|
trimmedKey = envKey;
|
|
1207
|
+
storedKeyCheck = envCheck;
|
|
1170
1208
|
} else {
|
|
1171
1209
|
const apiKey = await input({ message: "API key:" });
|
|
1172
1210
|
trimmedKey = apiKey.trim();
|
|
@@ -1174,11 +1212,17 @@ var main = async () => {
|
|
|
1174
1212
|
} else if (connectMode === "app" && canRunBrowserLogin() && !options.skipPhone) {
|
|
1175
1213
|
console.log(` ${dim("Pairing with your Pushary app.")}`);
|
|
1176
1214
|
console.log(` ${dim("No app? Ctrl-C, then:")} ${cyan("npx @pushary/agent-hooks setup --connect browser")}`);
|
|
1215
|
+
markStep("pair");
|
|
1177
1216
|
const previous = readKeySource();
|
|
1178
|
-
const paired = await connectViaAppPairing({
|
|
1217
|
+
const paired = await connectViaAppPairing({
|
|
1218
|
+
onCancelled: async () => {
|
|
1219
|
+
printPairingEscape();
|
|
1220
|
+
await reportSetupAbort("pairing-cancelled", 130);
|
|
1221
|
+
}
|
|
1222
|
+
});
|
|
1179
1223
|
if (!paired) {
|
|
1180
1224
|
printPairingEscape();
|
|
1181
|
-
process.exit(EXIT.NOT_CONFIGURED);
|
|
1225
|
+
process.exit(await abortWith("pairing-cancelled", EXIT.NOT_CONFIGURED));
|
|
1182
1226
|
}
|
|
1183
1227
|
trimmedKey = paired.apiKey;
|
|
1184
1228
|
keyFromPairing = true;
|
|
@@ -1191,12 +1235,18 @@ var main = async () => {
|
|
|
1191
1235
|
}
|
|
1192
1236
|
console.log();
|
|
1193
1237
|
} else if (!canRunBrowserLogin()) {
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1238
|
+
if (pairingRequested) {
|
|
1239
|
+
console.log(` ${yellow("!")} ${cyan("--connect app")} needs a terminal to show the pairing QR in.`);
|
|
1240
|
+
console.log(` ${dim("Drop the flag to use the key this machine already has, or pass --key <pk_xxx.xxx>.")}`);
|
|
1241
|
+
} else {
|
|
1242
|
+
console.log(` ${yellow("!")} No API key, and no terminal to sign in from.`);
|
|
1243
|
+
console.log(` ${dim("Pass --key <pk_xxx.xxx>, or --key-stdin, or export PUSHARY_API_KEY.")}`);
|
|
1244
|
+
console.log(` ${dim("On a machine with a terminal, run")} ${cyan("pushary login")} ${dim("once and re-run this.")}`);
|
|
1245
|
+
}
|
|
1197
1246
|
console.log();
|
|
1198
|
-
process.exit(EXIT.NOT_CONFIGURED);
|
|
1247
|
+
process.exit(await abortWith("no-key", EXIT.NOT_CONFIGURED));
|
|
1199
1248
|
} else {
|
|
1249
|
+
markStep("browser-login");
|
|
1200
1250
|
const outcome = await runBrowserLogin(
|
|
1201
1251
|
{ say: (line) => console.log(line), bold, dim, cyan, yellow },
|
|
1202
1252
|
{ cliVersion: version }
|
|
@@ -1210,7 +1260,7 @@ var main = async () => {
|
|
|
1210
1260
|
console.log();
|
|
1211
1261
|
console.log(` ${yellow("!")} That request was rejected in the browser. Nothing was written.`);
|
|
1212
1262
|
console.log();
|
|
1213
|
-
process.exit(EXIT.NOT_CONFIGURED);
|
|
1263
|
+
process.exit(await abortWith("login-rejected", EXIT.NOT_CONFIGURED));
|
|
1214
1264
|
} else {
|
|
1215
1265
|
console.log();
|
|
1216
1266
|
if (outcome.kind === "unavailable") {
|
|
@@ -1231,15 +1281,19 @@ var main = async () => {
|
|
|
1231
1281
|
console.log(` ${dim("Copy your key from")} ${cyan("https://pushary.com/dashboard/agent/settings")}`);
|
|
1232
1282
|
console.log(` ${dim("Or sign up at")} ${cyan("https://pushary.com/sign-up?from=ai-coding")}
|
|
1233
1283
|
`);
|
|
1234
|
-
process.exit(EXIT.USAGE);
|
|
1284
|
+
process.exit(await abortWith("invalid-key", EXIT.USAGE));
|
|
1235
1285
|
}
|
|
1286
|
+
recordSetupKey(trimmedKey);
|
|
1287
|
+
markStep("verify-key");
|
|
1236
1288
|
const keyCheck = keyFromPairing ? null : await verifyKeyOrExit(trimmedKey, options, storedKeyCheck ?? void 0);
|
|
1289
|
+
markStep("resolve-agents");
|
|
1237
1290
|
const agents = await resolveAgents(options);
|
|
1238
1291
|
if (options.dryRun) {
|
|
1239
1292
|
reportDryRun(trimmedKey, agents, keyCheck);
|
|
1240
1293
|
emitJson(options, { ok: true, dryRun: true, agents, keyCheck: keyCheck?.kind ?? "skipped" });
|
|
1241
1294
|
process.exit(EXIT.OK);
|
|
1242
1295
|
}
|
|
1296
|
+
markStep("save-key");
|
|
1243
1297
|
const rc = await saveApiKey(trimmedKey);
|
|
1244
1298
|
const context = { rc };
|
|
1245
1299
|
const failed = [];
|
|
@@ -1251,6 +1305,7 @@ var main = async () => {
|
|
|
1251
1305
|
console.log(` ${dim("Run setup again with --agents <id> when you want one wired up.")}`);
|
|
1252
1306
|
} else {
|
|
1253
1307
|
for (const agent of agents) {
|
|
1308
|
+
markStep(`configure:${agent}`);
|
|
1254
1309
|
try {
|
|
1255
1310
|
const outcome = await AGENT_SETUP[agent](trimmedKey, context);
|
|
1256
1311
|
if (outcome === "skipped") skipped.push(agent);
|
|
@@ -1269,11 +1324,13 @@ var main = async () => {
|
|
|
1269
1324
|
console.log();
|
|
1270
1325
|
console.log(` ${yellow("!")} Failed: ${failed.join(", ")} ${dim("(others completed successfully)")}`);
|
|
1271
1326
|
}
|
|
1327
|
+
markStep("project-instructions");
|
|
1272
1328
|
await offerProjectInstructions(agents, options);
|
|
1273
1329
|
if (completed.includes("claude_code")) {
|
|
1274
1330
|
await offerClaudeAlias(options);
|
|
1275
1331
|
}
|
|
1276
1332
|
}
|
|
1333
|
+
markStep("connect-phone");
|
|
1277
1334
|
const skipPhone = options.skipPhone;
|
|
1278
1335
|
let phone = null;
|
|
1279
1336
|
if (keyCheck?.kind === "locked") {
|
|
@@ -1311,6 +1368,15 @@ var main = async () => {
|
|
|
1311
1368
|
rc: rc.kind,
|
|
1312
1369
|
exitCode: report.exitCode
|
|
1313
1370
|
});
|
|
1371
|
+
await reportSetupOutcome({
|
|
1372
|
+
options,
|
|
1373
|
+
completed,
|
|
1374
|
+
skipped,
|
|
1375
|
+
failed,
|
|
1376
|
+
connectOutcome: "skipped",
|
|
1377
|
+
keyCheck: "locked",
|
|
1378
|
+
exitCode: report.exitCode
|
|
1379
|
+
});
|
|
1314
1380
|
process.exit(report.exitCode);
|
|
1315
1381
|
}
|
|
1316
1382
|
printManualSteps();
|
|
@@ -1318,6 +1384,7 @@ var main = async () => {
|
|
|
1318
1384
|
const agentsOk = failed.length === 0 && !configuredNothing;
|
|
1319
1385
|
const reachChecked = phone !== null;
|
|
1320
1386
|
const reachesYou = phone?.reachesYou ?? true;
|
|
1387
|
+
markStep("closing");
|
|
1321
1388
|
const closing = describeClosing({
|
|
1322
1389
|
agentsOk,
|
|
1323
1390
|
configuredNothing,
|
|
@@ -1372,7 +1439,7 @@ var main = async () => {
|
|
|
1372
1439
|
process.exit(exitCode);
|
|
1373
1440
|
}
|
|
1374
1441
|
};
|
|
1375
|
-
main().catch((err) => {
|
|
1442
|
+
main().catch(async (err) => {
|
|
1376
1443
|
if (err instanceof UsageError) {
|
|
1377
1444
|
console.log();
|
|
1378
1445
|
console.log(` ${yellow("!")} ${err.message}`);
|
|
@@ -1384,11 +1451,11 @@ main().catch((err) => {
|
|
|
1384
1451
|
console.log();
|
|
1385
1452
|
console.log(` ${dim("Cancelled. Nothing further was changed.")}`);
|
|
1386
1453
|
console.log();
|
|
1387
|
-
process.exit(130);
|
|
1454
|
+
process.exit(await abortWith("interrupted", 130));
|
|
1388
1455
|
}
|
|
1389
1456
|
console.log();
|
|
1390
1457
|
console.log(` ${yellow("!")} Setup failed: ${formatError(err)}`);
|
|
1391
1458
|
console.log(` ${dim("Run")} ${cyan("npx @pushary/agent-hooks doctor")} ${dim("after fixing the issue, then rerun setup.")}`);
|
|
1392
1459
|
console.log();
|
|
1393
|
-
process.exit(
|
|
1460
|
+
process.exit(await abortWith("crashed", EXIT.FAILED));
|
|
1394
1461
|
});
|
|
@@ -520,8 +520,8 @@ var connectViaAppPairing = async (options = {}) => {
|
|
|
520
520
|
const onInterrupt = () => {
|
|
521
521
|
cancelled = true;
|
|
522
522
|
stop(yellow("!"), "Cancelled");
|
|
523
|
-
options.onCancelled?.();
|
|
524
|
-
void cancelPairing(pairId).finally(() => process.exit(EXIT_ABORTED));
|
|
523
|
+
const flushed = options.onCancelled?.();
|
|
524
|
+
void Promise.allSettled([Promise.resolve(flushed), cancelPairing(pairId)]).finally(() => process.exit(EXIT_ABORTED));
|
|
525
525
|
};
|
|
526
526
|
process.once("SIGINT", onInterrupt);
|
|
527
527
|
try {
|
|
@@ -928,7 +928,7 @@ ${injected}` : injected;
|
|
|
928
928
|
};
|
|
929
929
|
var detectInstallMode = () => (process.argv[1] ?? "").includes("_npx") ? "npx" : "cli";
|
|
930
930
|
var reportEvent = async (event, options = {}) => {
|
|
931
|
-
const apiKey = getApiKey();
|
|
931
|
+
const apiKey = options.apiKey ?? getApiKey();
|
|
932
932
|
const baseUrl = getBaseUrl();
|
|
933
933
|
return withRetry(async () => {
|
|
934
934
|
const res = await fetch(`${baseUrl}/api/agent/event`, {
|
package/dist/src/index.d.ts
CHANGED
|
@@ -73,6 +73,16 @@ interface AgentEvent {
|
|
|
73
73
|
interface ReportEventOptions {
|
|
74
74
|
maxAttempts?: number;
|
|
75
75
|
timeoutMs?: number;
|
|
76
|
+
/**
|
|
77
|
+
* Authenticate with this key instead of the ambient one.
|
|
78
|
+
*
|
|
79
|
+
* getApiKey() reads the environment and ~/.pushary/config.json, so it can only
|
|
80
|
+
* ever speak for a key that is already installed. setup resolves a key minutes
|
|
81
|
+
* before it writes one, and its abort beacons run inside that window: without
|
|
82
|
+
* an override they post as nobody, so the runs that fail before saveApiKey are
|
|
83
|
+
* exactly the runs that cannot report failing.
|
|
84
|
+
*/
|
|
85
|
+
apiKey?: string;
|
|
76
86
|
}
|
|
77
87
|
interface EventResponse {
|
|
78
88
|
readonly ok?: boolean;
|
package/dist/src/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
handlePreToolUse
|
|
3
|
-
} from "../chunk-
|
|
3
|
+
} from "../chunk-SONXGCZY.js";
|
|
4
4
|
import "../chunk-CAJZAFVS.js";
|
|
5
5
|
import "../chunk-YHG74UFF.js";
|
|
6
6
|
import {
|
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
reportEvent,
|
|
16
16
|
resolvePolicy,
|
|
17
17
|
waitForAnswer
|
|
18
|
-
} from "../chunk-
|
|
18
|
+
} from "../chunk-XOUYM27W.js";
|
|
19
19
|
import "../chunk-WLGEY4UX.js";
|
|
20
20
|
import "../chunk-BSZYIAZL.js";
|
|
21
21
|
import "../chunk-SAF6HGAA.js";
|