@pushary/agent-hooks 0.49.0 → 0.49.1
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.
|
@@ -509,7 +509,7 @@ var startCommandPoller = (opts) => {
|
|
|
509
509
|
schedule(nextDelay());
|
|
510
510
|
};
|
|
511
511
|
schedule(fast);
|
|
512
|
-
opts.log?.("[pushary]
|
|
512
|
+
opts.log?.("[pushary] command poller active");
|
|
513
513
|
return {
|
|
514
514
|
stop() {
|
|
515
515
|
stopped = true;
|
|
@@ -1130,6 +1130,11 @@ var runDualMode = async (binary, args2, startingMode) => {
|
|
|
1130
1130
|
const agentName = `Claude Code - ${projectName}`;
|
|
1131
1131
|
const machineId = getMachineId();
|
|
1132
1132
|
const stdin = createStdinHandoff();
|
|
1133
|
+
const verbose = process.env.PUSHARY_VERBOSE === "1";
|
|
1134
|
+
const verboseLog = (message) => {
|
|
1135
|
+
if (verbose) process.stderr.write(`${message}
|
|
1136
|
+
`);
|
|
1137
|
+
};
|
|
1133
1138
|
const { initialPrompt, resume, permissionMode } = parseRemoteArgs(args2);
|
|
1134
1139
|
const userManagesSession = args2.some((a) => SESSION_FLAG_RE.test(a));
|
|
1135
1140
|
let sessionId = resume;
|
|
@@ -1164,10 +1169,8 @@ var runDualMode = async (binary, args2, startingMode) => {
|
|
|
1164
1169
|
agentType: "claude_code",
|
|
1165
1170
|
getSessionId: () => sessionId,
|
|
1166
1171
|
onCommand: (command) => onPhoneCommand(command),
|
|
1167
|
-
onFatal: (message) =>
|
|
1168
|
-
|
|
1169
|
-
log: (message) => process.stderr.write(`${message}
|
|
1170
|
-
`)
|
|
1172
|
+
onFatal: (message) => verboseLog(`[pushary] relay unavailable (${message}); using polling`),
|
|
1173
|
+
log: verboseLog
|
|
1171
1174
|
});
|
|
1172
1175
|
relay.start();
|
|
1173
1176
|
}
|
|
@@ -1228,8 +1231,7 @@ var runDualMode = async (binary, args2, startingMode) => {
|
|
|
1228
1231
|
activeLeg?.stop("kill");
|
|
1229
1232
|
}
|
|
1230
1233
|
},
|
|
1231
|
-
log:
|
|
1232
|
-
`)
|
|
1234
|
+
log: verboseLog
|
|
1233
1235
|
});
|
|
1234
1236
|
const signals = ["SIGINT", "SIGTERM", "SIGHUP"];
|
|
1235
1237
|
const onSignal = () => {
|
|
@@ -1265,6 +1267,9 @@ var runDualMode = async (binary, args2, startingMode) => {
|
|
|
1265
1267
|
};
|
|
1266
1268
|
try {
|
|
1267
1269
|
if (sessionId && startingMode === "local") {
|
|
1270
|
+
process.stderr.write(
|
|
1271
|
+
"[pushary] reachable from your phone \u2014 send an instruction from the app when this goes idle (Ctrl-] keeps the terminal).\n"
|
|
1272
|
+
);
|
|
1268
1273
|
void announcePresence("session_start", "Session ready \u2014 reachable from your phone");
|
|
1269
1274
|
}
|
|
1270
1275
|
if (startingMode === "remote" && initialPrompt) input.push(userMessage(initialPrompt));
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
removeClaudeAlias
|
|
4
|
-
} from "../chunk-
|
|
4
|
+
} from "../chunk-BC3VCZ3E.js";
|
|
5
5
|
import {
|
|
6
6
|
removeCodexHooks,
|
|
7
7
|
removeGeminiSettings,
|
|
@@ -277,6 +277,13 @@ var main = async () => {
|
|
|
277
277
|
console.log();
|
|
278
278
|
console.log(` ${green(bold("Clean complete."))}`);
|
|
279
279
|
console.log(` ${dim("Run")} npx @pushary/agent-hooks@latest setup ${dim("to reinstall.")}`);
|
|
280
|
+
if (aliasRemovedFrom.length > 0) {
|
|
281
|
+
console.log();
|
|
282
|
+
console.log(` ${yellow("!")} ${bold("One thing left in your current terminal.")}`);
|
|
283
|
+
console.log(` ${dim("It still has the")} ${bold("claude")} ${dim("alias loaded from before. Run")} ${bold("unalias claude")}`);
|
|
284
|
+
console.log(` ${dim("(or open a new terminal) so")} ${bold("claude")} ${dim("runs Claude Code again.")}`);
|
|
285
|
+
}
|
|
286
|
+
console.log(` ${dim("If a")} ${bold("pushary claude")} ${dim("or")} ${bold("pushary daemon")} ${dim("is still running anywhere, stop it (Ctrl-C).")}`);
|
|
280
287
|
console.log();
|
|
281
288
|
};
|
|
282
289
|
main();
|
|
@@ -14,8 +14,9 @@ import {
|
|
|
14
14
|
} from "../chunk-NKXSILEW.js";
|
|
15
15
|
|
|
16
16
|
// src/spawn-daemon.ts
|
|
17
|
+
import { spawn } from "child_process";
|
|
17
18
|
import { existsSync } from "fs";
|
|
18
|
-
import { basename } from "path";
|
|
19
|
+
import { basename, dirname, join } from "path";
|
|
19
20
|
var DRAIN_PATH = "/api/agent/spawn/drain";
|
|
20
21
|
var FAST_POLL_MS = 3e3;
|
|
21
22
|
var SLOW_POLL_MS = 3e4;
|
|
@@ -43,6 +44,8 @@ var runSpawnDaemon = async () => {
|
|
|
43
44
|
const machineId = getMachineId();
|
|
44
45
|
const baseUrl = getBaseUrl();
|
|
45
46
|
const pusharyBin = resolveGlobalBinary("pushary") ?? "pushary";
|
|
47
|
+
const siblingEntry = process.argv[1] ? join(dirname(process.argv[1]), "pushary.js") : "";
|
|
48
|
+
const spawnDirect = siblingEntry.length > 0 && existsSync(siblingEntry);
|
|
46
49
|
let stopped = false;
|
|
47
50
|
let idleTicks = 0;
|
|
48
51
|
let errorStreak = 0;
|
|
@@ -50,20 +53,11 @@ var runSpawnDaemon = async () => {
|
|
|
50
53
|
let timer;
|
|
51
54
|
let inflight;
|
|
52
55
|
const launch = (req) => {
|
|
53
|
-
if (!spawnRateAllows(spawnTimestamps, Date.now())) {
|
|
54
|
-
stderr(`[pushary] spawn rate limit reached; skipping a queued session
|
|
55
|
-
`);
|
|
56
|
-
return;
|
|
57
|
-
}
|
|
58
56
|
spawnTimestamps.push(Date.now());
|
|
59
57
|
const cwd = req.cwd && existsSync(req.cwd) ? req.cwd : process.cwd();
|
|
58
|
+
const args = ["claude", "--remote", "-p", req.prompt];
|
|
60
59
|
try {
|
|
61
|
-
const child =
|
|
62
|
-
cwd,
|
|
63
|
-
detached: true,
|
|
64
|
-
stdio: "ignore",
|
|
65
|
-
env: process.env
|
|
66
|
-
});
|
|
60
|
+
const child = spawnDirect ? spawn(process.execPath, [siblingEntry, ...args], { cwd, detached: true, stdio: "ignore", env: process.env }) : spawnClaude(pusharyBin, args, { cwd, detached: true, stdio: "ignore", env: process.env });
|
|
67
61
|
child.on("error", (err) => stderr(`[pushary] could not launch session: ${err.message}
|
|
68
62
|
`));
|
|
69
63
|
child.unref();
|
|
@@ -83,8 +77,8 @@ var runSpawnDaemon = async () => {
|
|
|
83
77
|
});
|
|
84
78
|
if (!res.ok) throw new Error(`drain ${res.status}`);
|
|
85
79
|
const data = await res.json();
|
|
86
|
-
const
|
|
87
|
-
return
|
|
80
|
+
const spawn2 = data.spawn;
|
|
81
|
+
return spawn2 && typeof spawn2.prompt === "string" && typeof spawn2.id === "string" ? spawn2 : null;
|
|
88
82
|
};
|
|
89
83
|
const nextDelay = () => {
|
|
90
84
|
if (errorStreak > 0) return Math.min(SLOW_POLL_MS * 2 ** (errorStreak - 1), MAX_ERROR_BACKOFF_MS);
|
|
@@ -93,6 +87,10 @@ var runSpawnDaemon = async () => {
|
|
|
93
87
|
const jitter = (ms) => Math.max(1, Math.round(ms * (0.85 + Math.random() * 0.3)));
|
|
94
88
|
const tick = async () => {
|
|
95
89
|
if (stopped) return;
|
|
90
|
+
if (!spawnRateAllows(spawnTimestamps, Date.now())) {
|
|
91
|
+
timer = setTimeout(tick, jitter(nextDelay()));
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
96
94
|
const controller = new AbortController();
|
|
97
95
|
inflight = controller;
|
|
98
96
|
const timeout = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS);
|
|
@@ -119,18 +117,18 @@ var runSpawnDaemon = async () => {
|
|
|
119
117
|
if (timer) clearTimeout(timer);
|
|
120
118
|
inflight?.abort();
|
|
121
119
|
};
|
|
122
|
-
const signals = ["SIGINT", "SIGTERM", "SIGHUP"];
|
|
123
|
-
const onSignal = () => {
|
|
124
|
-
teardown();
|
|
125
|
-
process.exit(0);
|
|
126
|
-
};
|
|
127
|
-
for (const signal of signals) process.on(signal, onSignal);
|
|
128
120
|
stderr(
|
|
129
121
|
`[pushary] daemon online \u2014 this machine (${machineId}) can now be sent a new session from your phone. Ctrl-C to stop.
|
|
130
122
|
`
|
|
131
123
|
);
|
|
132
124
|
timer = setTimeout(tick, FAST_POLL_MS);
|
|
133
|
-
|
|
125
|
+
const signals = ["SIGINT", "SIGTERM", "SIGHUP"];
|
|
126
|
+
await new Promise((resolve) => {
|
|
127
|
+
const onSignal = () => {
|
|
128
|
+
teardown();
|
|
129
|
+
resolve();
|
|
130
|
+
};
|
|
131
|
+
for (const signal of signals) process.on(signal, onSignal);
|
|
134
132
|
});
|
|
135
133
|
return 0;
|
|
136
134
|
};
|
|
@@ -342,6 +342,45 @@ var main = async () => {
|
|
|
342
342
|
}
|
|
343
343
|
}
|
|
344
344
|
console.log();
|
|
345
|
+
console.log(` ${dim("Remote control")}`);
|
|
346
|
+
const aliasRc = SHELL_FILES.find((f) => {
|
|
347
|
+
try {
|
|
348
|
+
return /alias\s+claude=['"]?pushary claude/.test(readFileSync(f, "utf-8"));
|
|
349
|
+
} catch {
|
|
350
|
+
return false;
|
|
351
|
+
}
|
|
352
|
+
});
|
|
353
|
+
if (aliasRc) {
|
|
354
|
+
if (globalVersion) {
|
|
355
|
+
check(true, "claude alias \u2192 pushary claude", `set in ${aliasRc.split("/").pop()}`);
|
|
356
|
+
} else {
|
|
357
|
+
check(false, "claude alias \u2192 pushary claude", "alias is set but pushary is not installed \u2014 run `unalias claude` (this shell) or reinstall");
|
|
358
|
+
}
|
|
359
|
+
} else {
|
|
360
|
+
console.log(` ${dim("\u2013")} claude alias not set ${dim("(optional \u2014 run `pushary claude` directly, or re-run setup to add it)")}`);
|
|
361
|
+
}
|
|
362
|
+
if (apiKey) {
|
|
363
|
+
try {
|
|
364
|
+
const modeRes = await fetch(`${getBaseUrl()}/api/mcp/mode`, {
|
|
365
|
+
headers: { Authorization: `Bearer ${apiKey}` },
|
|
366
|
+
signal: AbortSignal.timeout(8e3)
|
|
367
|
+
});
|
|
368
|
+
const relayUrl = modeRes.ok ? (await modeRes.json()).relayUrl : void 0;
|
|
369
|
+
if (typeof relayUrl === "string" && relayUrl.length > 0) {
|
|
370
|
+
const healthUrl = relayUrl.replace(/^wss:/, "https:").replace(/\/relay$/, "/health/ready");
|
|
371
|
+
try {
|
|
372
|
+
const h = await fetch(healthUrl, { signal: AbortSignal.timeout(6e3) });
|
|
373
|
+
console.log(h.ok ? ` ${pass} Relay reachable ${dim("(sub-second phone commands)")}` : ` ${dim("\u2013")} Relay advertised but returned ${h.status} ${dim("(commands still delivered via polling)")}`);
|
|
374
|
+
} catch {
|
|
375
|
+
console.log(` ${dim("\u2013")} Relay advertised but unreachable ${dim("(commands still delivered via polling)")}`);
|
|
376
|
+
}
|
|
377
|
+
} else {
|
|
378
|
+
console.log(` ${dim("\u2013")} Relay not enabled ${dim("(phone commands delivered via polling)")}`);
|
|
379
|
+
}
|
|
380
|
+
} catch {
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
console.log();
|
|
345
384
|
console.log(` ${dim("Connectivity")}`);
|
|
346
385
|
if (!apiKey) {
|
|
347
386
|
check(false, "MCP server reachable", "skipped \u2014 no API key");
|
|
@@ -37,7 +37,9 @@ var resolveShellRc = () => {
|
|
|
37
37
|
if (shell === "zsh") return { path: join(home, ".zshrc"), shell };
|
|
38
38
|
if (shell === "bash") {
|
|
39
39
|
const bashrc = join(home, ".bashrc");
|
|
40
|
-
|
|
40
|
+
const profile = join(home, ".bash_profile");
|
|
41
|
+
if (process.platform === "darwin") return { path: profile, shell };
|
|
42
|
+
return { path: existsSync(bashrc) ? bashrc : profile, shell };
|
|
41
43
|
}
|
|
42
44
|
return null;
|
|
43
45
|
};
|