@pushary/agent-hooks 0.89.3 → 0.89.4
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/README.md +40 -0
- package/dist/bin/pushary-bell-hook.js +3 -3
- package/dist/bin/pushary-bell.js +9 -10
- package/dist/bin/pushary-claude.js +62 -26
- package/dist/bin/pushary-clean.js +28 -7
- package/dist/bin/pushary-codex-bridge.js +4 -5
- package/dist/bin/pushary-codex-hook.js +8 -7
- package/dist/bin/pushary-codex.js +6 -4
- package/dist/bin/pushary-connect.js +4 -4
- package/dist/bin/pushary-daemon.js +141 -21
- package/dist/bin/pushary-disconnect.js +3 -4
- package/dist/bin/pushary-doctor.js +31 -20
- package/dist/bin/pushary-elicitation-hook.js +4 -2
- package/dist/bin/pushary-gemini-bridge.js +3 -4
- package/dist/bin/pushary-gemini-hook.js +6 -4
- package/dist/bin/pushary-hook.js +9 -7
- package/dist/bin/pushary-login.js +4 -4
- package/dist/bin/pushary-logout.js +5 -6
- package/dist/bin/pushary-mode.js +2 -2
- package/dist/bin/pushary-notification-hook.js +6 -4
- package/dist/bin/pushary-opencode-hook.js +14 -6
- package/dist/bin/pushary-permission-denied-hook.js +7 -5
- package/dist/bin/pushary-permission-hook.js +7 -5
- package/dist/bin/pushary-post-hook.js +6 -4
- package/dist/bin/pushary-prompt-hook.js +6 -4
- package/dist/bin/pushary-session-end-hook.js +6 -4
- package/dist/bin/pushary-session-start-hook.js +6 -4
- package/dist/bin/pushary-setup.js +49 -28
- package/dist/bin/pushary-stats.js +2 -2
- package/dist/bin/pushary-status.js +7 -6
- package/dist/bin/pushary-stop-hook.js +6 -4
- package/dist/bin/pushary-stopfailure-hook.js +6 -4
- package/dist/bin/pushary-suggestions.js +2 -2
- package/dist/bin/pushary-upgrade.js +63 -28
- package/dist/bin/pushary-wait.js +2 -2
- package/dist/bin/pushary.js +1 -1
- package/dist/chunk-2HYPZLYY.js +45 -0
- package/dist/{chunk-ZYPS2XMT.js → chunk-4ZHQNBDP.js} +1 -1
- package/dist/{chunk-B7JE4XHD.js → chunk-7IJYOBHL.js} +1 -1
- package/dist/{chunk-NRGRUOAR.js → chunk-FWUEYXSD.js} +4 -0
- package/dist/{chunk-HUJAAWNL.js → chunk-GKAKAOKC.js} +10 -3
- package/dist/{chunk-GOEXZ5QJ.js → chunk-GPNOHKFO.js} +9 -2
- package/dist/{chunk-SQOFGPNX.js → chunk-KJ57OPCC.js} +1 -1
- package/dist/{chunk-LGXTBUT4.js → chunk-KOPUTJQC.js} +1 -0
- package/dist/{chunk-JT6TIBYH.js → chunk-MZBT2LXW.js} +4 -4
- package/dist/{chunk-3UBYTSCY.js → chunk-NFI2K2ZQ.js} +15 -7
- package/dist/{chunk-K42SZKYF.js → chunk-NLMSSKES.js} +251 -6
- package/dist/{chunk-3O2XPYLF.js → chunk-OBI4YMCT.js} +1 -1
- package/dist/{chunk-LUCFN47K.js → chunk-QH4AA7QV.js} +1 -1
- package/dist/{chunk-VKVHY5HD.js → chunk-V37ZXMH3.js} +11 -3
- package/dist/{chunk-MHBC2XUP.js → chunk-VP7SDXYG.js} +1 -1
- package/dist/src/index.js +7 -5
- package/package.json +1 -1
- package/dist/chunk-GIRT7677.js +0 -11
- package/dist/chunk-RN3NOEJF.js +0 -9
- package/dist/{chunk-LALHWDWL.js → chunk-W6NPWHBJ.js} +3 -3
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
// src/live-capabilities.ts
|
|
2
|
+
var CLAUDE_BRIDGE_CAPABILITY = "claude-bridge";
|
|
3
|
+
var CLAUDE_RESUME_CAPABILITY = "claude-resume";
|
|
2
4
|
var CODEX_BRIDGE_CAPABILITY = "codex-bridge";
|
|
3
5
|
var CODEX_RESUME_CAPABILITY = "codex-resume";
|
|
4
6
|
var GEMINI_BRIDGE_CAPABILITY = "gemini-bridge";
|
|
@@ -19,6 +21,8 @@ var geminiLiveCapabilities = (rawVersion) => {
|
|
|
19
21
|
};
|
|
20
22
|
|
|
21
23
|
export {
|
|
24
|
+
CLAUDE_BRIDGE_CAPABILITY,
|
|
25
|
+
CLAUDE_RESUME_CAPABILITY,
|
|
22
26
|
CODEX_BRIDGE_CAPABILITY,
|
|
23
27
|
CODEX_RESUME_CAPABILITY,
|
|
24
28
|
geminiLiveCapabilities
|
|
@@ -91,7 +91,11 @@ var readPendingCommand = (sessionId, namespace = "") => {
|
|
|
91
91
|
unlinkSync(commandFile(sessionId, namespace));
|
|
92
92
|
return null;
|
|
93
93
|
}
|
|
94
|
-
return {
|
|
94
|
+
return {
|
|
95
|
+
...value,
|
|
96
|
+
delivered: value.delivered === true,
|
|
97
|
+
...value.failed === true ? { failed: true } : {}
|
|
98
|
+
};
|
|
95
99
|
} catch {
|
|
96
100
|
return null;
|
|
97
101
|
}
|
|
@@ -106,13 +110,13 @@ var savePendingCommand = (sessionId, command, namespace = "") => {
|
|
|
106
110
|
return false;
|
|
107
111
|
}
|
|
108
112
|
};
|
|
109
|
-
var
|
|
113
|
+
var updatePendingCommand = (sessionId, id, update, namespace = "") => {
|
|
110
114
|
const command = readPendingCommand(sessionId, namespace);
|
|
111
115
|
if (!command || command.id !== id) return false;
|
|
112
116
|
const file = commandFile(sessionId, namespace);
|
|
113
117
|
const temporary = `${file}.${process.pid}.tmp`;
|
|
114
118
|
try {
|
|
115
|
-
writeFileSync(temporary, JSON.stringify({ ...command,
|
|
119
|
+
writeFileSync(temporary, JSON.stringify({ ...command, ...update }), { encoding: "utf-8", mode: 384 });
|
|
116
120
|
renameSync(temporary, file);
|
|
117
121
|
return true;
|
|
118
122
|
} catch {
|
|
@@ -123,6 +127,8 @@ var markPendingCommandDelivered = (sessionId, id, namespace = "") => {
|
|
|
123
127
|
return false;
|
|
124
128
|
}
|
|
125
129
|
};
|
|
130
|
+
var markPendingCommandDelivered = (sessionId, id, namespace = "") => updatePendingCommand(sessionId, id, { delivered: true, failed: void 0 }, namespace);
|
|
131
|
+
var markPendingCommandFailed = (sessionId, id, namespace = "") => updatePendingCommand(sessionId, id, { delivered: false, failed: true }, namespace);
|
|
126
132
|
var removePendingCommand = (sessionId, id, namespace = "") => {
|
|
127
133
|
if (readPendingCommand(sessionId, namespace)?.id !== id) return;
|
|
128
134
|
try {
|
|
@@ -178,6 +184,7 @@ export {
|
|
|
178
184
|
readPendingCommand,
|
|
179
185
|
savePendingCommand,
|
|
180
186
|
markPendingCommandDelivered,
|
|
187
|
+
markPendingCommandFailed,
|
|
181
188
|
removePendingCommand,
|
|
182
189
|
isDefaultSession,
|
|
183
190
|
savePendingQuestion,
|
|
@@ -19,8 +19,8 @@ var COMMAND_LIST = [
|
|
|
19
19
|
module: "pushary-daemon",
|
|
20
20
|
summary: "Keep this machine reachable so your phone can START a new session",
|
|
21
21
|
detail: [
|
|
22
|
-
"
|
|
23
|
-
"
|
|
22
|
+
"Install the native per-user service for restart-on-login and restart-on-failure.",
|
|
23
|
+
"A bare `pushary daemon` remains foreground mode for diagnostics."
|
|
24
24
|
]
|
|
25
25
|
},
|
|
26
26
|
{
|
|
@@ -114,6 +114,13 @@ var COMMAND_OPTIONS = {
|
|
|
114
114
|
claude: [
|
|
115
115
|
["--remote", "Start headless and drive it entirely from your phone"],
|
|
116
116
|
["-p <prompt>", "Initial prompt"]
|
|
117
|
+
],
|
|
118
|
+
daemon: [
|
|
119
|
+
["install", "Install and start the native per-user service"],
|
|
120
|
+
["start | stop | restart", "Control the installed service"],
|
|
121
|
+
["status", "Show local daemon health and PID"],
|
|
122
|
+
["uninstall", "Stop and remove the native service"],
|
|
123
|
+
["foreground", "Run attached to this terminal for diagnostics"]
|
|
117
124
|
]
|
|
118
125
|
};
|
|
119
126
|
var SETUP_OPTIONS = [
|
|
@@ -268,6 +268,7 @@ var sessionEndAction = (reason) => typeof reason === "string" && SESSION_END_ACT
|
|
|
268
268
|
var taskTitleFrom = (prompt) => typeof prompt === "string" ? prompt.replace(/\s+/g, " ").trim().slice(0, TASK_TITLE_MAX_LENGTH) || void 0 : void 0;
|
|
269
269
|
|
|
270
270
|
export {
|
|
271
|
+
HOOK_FALLBACK_MAX,
|
|
271
272
|
describeToolCall,
|
|
272
273
|
deriveToolTarget,
|
|
273
274
|
parseApplyPatchOps,
|
|
@@ -17,7 +17,7 @@ import {
|
|
|
17
17
|
readLastUserPrompt,
|
|
18
18
|
repoKeyFor,
|
|
19
19
|
throttlePass
|
|
20
|
-
} from "./chunk-
|
|
20
|
+
} from "./chunk-NFI2K2ZQ.js";
|
|
21
21
|
import {
|
|
22
22
|
DEFAULT_SESSION,
|
|
23
23
|
askUser,
|
|
@@ -25,7 +25,7 @@ import {
|
|
|
25
25
|
pollForAnswer,
|
|
26
26
|
savePendingQuestion,
|
|
27
27
|
sendNotification
|
|
28
|
-
} from "./chunk-
|
|
28
|
+
} from "./chunk-GKAKAOKC.js";
|
|
29
29
|
import {
|
|
30
30
|
deriveAction,
|
|
31
31
|
deriveActionBody,
|
|
@@ -33,10 +33,10 @@ import {
|
|
|
33
33
|
deriveToolTarget,
|
|
34
34
|
describeToolCall,
|
|
35
35
|
scopePathFor
|
|
36
|
-
} from "./chunk-
|
|
36
|
+
} from "./chunk-KOPUTJQC.js";
|
|
37
37
|
import {
|
|
38
38
|
getMachineId
|
|
39
|
-
} from "./chunk-
|
|
39
|
+
} from "./chunk-2HYPZLYY.js";
|
|
40
40
|
import {
|
|
41
41
|
getApiKey,
|
|
42
42
|
getBaseUrl
|
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
savePendingCommand,
|
|
13
13
|
sendNotification,
|
|
14
14
|
waitForAnswer
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-GKAKAOKC.js";
|
|
16
16
|
import {
|
|
17
17
|
AGENT_IDENTITIES,
|
|
18
18
|
deriveReceiptMeta,
|
|
@@ -26,10 +26,10 @@ import {
|
|
|
26
26
|
summarizeStop,
|
|
27
27
|
taskTitleFrom,
|
|
28
28
|
toolResultErrorText
|
|
29
|
-
} from "./chunk-
|
|
29
|
+
} from "./chunk-KOPUTJQC.js";
|
|
30
30
|
import {
|
|
31
31
|
getMachineId
|
|
32
|
-
} from "./chunk-
|
|
32
|
+
} from "./chunk-2HYPZLYY.js";
|
|
33
33
|
import {
|
|
34
34
|
withRetry
|
|
35
35
|
} from "./chunk-BSZYIAZL.js";
|
|
@@ -670,7 +670,7 @@ var consumesActivityContext = (agentType) => {
|
|
|
670
670
|
return pendingCommandEvents(source).some((event) => event !== "Stop");
|
|
671
671
|
};
|
|
672
672
|
var detectInstallMode = () => (process.argv[1] ?? "").includes("_npx") ? "npx" : "cli";
|
|
673
|
-
var acknowledgePendingCommand = async (apiKey, baseUrl, commandId, sessionId, machineId, timeoutMs) => {
|
|
673
|
+
var acknowledgePendingCommand = async (apiKey, baseUrl, commandId, sessionId, machineId, timeoutMs, state = "delivered") => {
|
|
674
674
|
try {
|
|
675
675
|
const response = await fetch(`${baseUrl}/api/agent/command/ack`, {
|
|
676
676
|
method: "POST",
|
|
@@ -678,7 +678,13 @@ var acknowledgePendingCommand = async (apiKey, baseUrl, commandId, sessionId, ma
|
|
|
678
678
|
"Content-Type": "application/json",
|
|
679
679
|
"Authorization": `Bearer ${apiKey}`
|
|
680
680
|
},
|
|
681
|
-
body: JSON.stringify({
|
|
681
|
+
body: JSON.stringify({
|
|
682
|
+
commandId,
|
|
683
|
+
sessionId: sessionId ?? null,
|
|
684
|
+
machineId,
|
|
685
|
+
state,
|
|
686
|
+
...state === "failed" ? { failureCode: "consumer_rejected" } : {}
|
|
687
|
+
}),
|
|
682
688
|
signal: AbortSignal.timeout(timeoutMs)
|
|
683
689
|
});
|
|
684
690
|
return response.ok;
|
|
@@ -729,16 +735,18 @@ var reportEvent = async (event, options = {}) => {
|
|
|
729
735
|
const result = await res.json();
|
|
730
736
|
const withoutPending = () => ({ ...result, pendingCommand: void 0, pendingCommandId: void 0 });
|
|
731
737
|
if (storedCommand) {
|
|
738
|
+
const failed = storedCommand.failed === true;
|
|
732
739
|
const acknowledged = await acknowledgePendingCommand(
|
|
733
740
|
apiKey,
|
|
734
741
|
baseUrl,
|
|
735
742
|
storedCommand.id,
|
|
736
743
|
event.sessionId,
|
|
737
744
|
machineId,
|
|
738
|
-
options.timeoutMs ?? 1e4
|
|
745
|
+
options.timeoutMs ?? 1e4,
|
|
746
|
+
failed ? "failed" : "delivered"
|
|
739
747
|
);
|
|
740
748
|
if (!acknowledged) return withoutPending();
|
|
741
|
-
if (storedCommand.delivered) {
|
|
749
|
+
if (storedCommand.delivered || failed) {
|
|
742
750
|
removePendingCommand(sessionKey, storedCommand.id, receiptNamespace);
|
|
743
751
|
return withoutPending();
|
|
744
752
|
}
|
|
@@ -5,17 +5,18 @@ import {
|
|
|
5
5
|
import {
|
|
6
6
|
resolveGlobalBinary
|
|
7
7
|
} from "./chunk-PZA7G4CN.js";
|
|
8
|
-
import {
|
|
9
|
-
pusharyDir
|
|
10
|
-
} from "./chunk-VKVHY5HD.js";
|
|
11
8
|
import {
|
|
12
9
|
getMachineId
|
|
13
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-2HYPZLYY.js";
|
|
11
|
+
import {
|
|
12
|
+
pusharyDir
|
|
13
|
+
} from "./chunk-V37ZXMH3.js";
|
|
14
14
|
import {
|
|
15
15
|
getPackageVersion
|
|
16
16
|
} from "./chunk-DINDL2CF.js";
|
|
17
17
|
import {
|
|
18
18
|
readJsonSafe,
|
|
19
|
+
writeFileAtomic,
|
|
19
20
|
writeJsonAtomic
|
|
20
21
|
} from "./chunk-6MTNS63X.js";
|
|
21
22
|
import {
|
|
@@ -23,9 +24,11 @@ import {
|
|
|
23
24
|
} from "./chunk-2UMNXADU.js";
|
|
24
25
|
|
|
25
26
|
// src/daemon-lifecycle.ts
|
|
26
|
-
import { dirname, join } from "path";
|
|
27
|
-
import { existsSync, mkdirSync, renameSync, unlinkSync, writeFileSync } from "fs";
|
|
27
|
+
import { dirname, join, win32 as win32Path } from "path";
|
|
28
|
+
import { existsSync, mkdirSync, realpathSync, renameSync, unlinkSync, writeFileSync } from "fs";
|
|
28
29
|
import { createHash, randomUUID } from "crypto";
|
|
30
|
+
import { homedir } from "os";
|
|
31
|
+
import { execFileSync } from "child_process";
|
|
29
32
|
var daemonNeedsHandoff = (status) => status.kind === "version-mismatch" || status.kind === "configuration-mismatch" || status.kind === "unresponsive" && status.processAlive === true;
|
|
30
33
|
var statePath = (dir) => join(dir, "daemon-state.json");
|
|
31
34
|
var lockPath = (dir) => join(dir, "daemon.lock");
|
|
@@ -37,6 +40,219 @@ var buildDaemonLaunch = (input) => input.siblingEntry ? { command: input.execPat
|
|
|
37
40
|
args: [],
|
|
38
41
|
shell: needsShell(input.daemonBinary, input.platform ?? process.platform)
|
|
39
42
|
};
|
|
43
|
+
var xml = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
44
|
+
var systemdQuote = (value) => `"${value.replaceAll("%", "%%").replaceAll("\\", "\\\\").replaceAll('"', '\\"')}"`;
|
|
45
|
+
var buildDaemonService = (input) => {
|
|
46
|
+
if (input.platform === "darwin") {
|
|
47
|
+
if (!Number.isInteger(input.uid) || input.uid < 0) return null;
|
|
48
|
+
const label = "com.pushary.daemon";
|
|
49
|
+
const domain = `gui/${input.uid}`;
|
|
50
|
+
const target = `${domain}/${label}`;
|
|
51
|
+
const definitionPath = join(input.homeDir, "Library", "LaunchAgents", `${label}.plist`);
|
|
52
|
+
const contents = `<?xml version="1.0" encoding="UTF-8"?>
|
|
53
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
54
|
+
<plist version="1.0">
|
|
55
|
+
<dict>
|
|
56
|
+
<key>Label</key><string>${label}</string>
|
|
57
|
+
<key>ProgramArguments</key>
|
|
58
|
+
<array><string>${xml(input.execPath)}</string><string>${xml(input.daemonEntry)}</string></array>
|
|
59
|
+
<key>WorkingDirectory</key><string>${xml(input.homeDir)}</string>
|
|
60
|
+
<key>EnvironmentVariables</key><dict><key>PATH</key><string>${xml(input.pathEnv)}</string></dict>
|
|
61
|
+
<key>RunAtLoad</key><true/>
|
|
62
|
+
<key>KeepAlive</key><dict><key>SuccessfulExit</key><false/></dict>
|
|
63
|
+
<key>ThrottleInterval</key><integer>10</integer>
|
|
64
|
+
<key>StandardOutPath</key><string>${xml(join(input.stateDir, "daemon.log"))}</string>
|
|
65
|
+
<key>StandardErrorPath</key><string>${xml(join(input.stateDir, "daemon-error.log"))}</string>
|
|
66
|
+
</dict>
|
|
67
|
+
</plist>
|
|
68
|
+
`;
|
|
69
|
+
const bootstrap = { command: "launchctl", args: ["bootstrap", domain, definitionPath] };
|
|
70
|
+
return {
|
|
71
|
+
definitionPath,
|
|
72
|
+
contents,
|
|
73
|
+
install: [
|
|
74
|
+
{ command: "launchctl", args: ["bootout", domain, definitionPath], ignoreFailure: true },
|
|
75
|
+
bootstrap,
|
|
76
|
+
{ command: "launchctl", args: ["enable", target] },
|
|
77
|
+
{ command: "launchctl", args: ["kickstart", "-k", target] }
|
|
78
|
+
],
|
|
79
|
+
start: [{ command: "launchctl", args: ["kickstart", "-k", target] }],
|
|
80
|
+
stop: [{ command: "launchctl", args: ["kill", "SIGTERM", target], ignoreFailure: true }],
|
|
81
|
+
uninstall: [{ command: "launchctl", args: ["bootout", domain, definitionPath], ignoreFailure: true }]
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
if (input.platform === "linux") {
|
|
85
|
+
const unit = "pushary-daemon.service";
|
|
86
|
+
const definitionPath = join(input.homeDir, ".config", "systemd", "user", unit);
|
|
87
|
+
const contents = `[Unit]
|
|
88
|
+
Description=Pushary phone-to-agent daemon
|
|
89
|
+
After=network-online.target
|
|
90
|
+
|
|
91
|
+
[Service]
|
|
92
|
+
Type=simple
|
|
93
|
+
ExecStart=${systemdQuote(input.execPath)} ${systemdQuote(input.daemonEntry)}
|
|
94
|
+
WorkingDirectory=${systemdQuote(input.homeDir)}
|
|
95
|
+
Environment=${systemdQuote(`PATH=${input.pathEnv}`)}
|
|
96
|
+
Restart=on-failure
|
|
97
|
+
RestartSec=10
|
|
98
|
+
|
|
99
|
+
[Install]
|
|
100
|
+
WantedBy=default.target
|
|
101
|
+
`;
|
|
102
|
+
return {
|
|
103
|
+
definitionPath,
|
|
104
|
+
contents,
|
|
105
|
+
install: [
|
|
106
|
+
{ command: "systemctl", args: ["--user", "daemon-reload"] },
|
|
107
|
+
{ command: "systemctl", args: ["--user", "enable", "--now", unit] }
|
|
108
|
+
],
|
|
109
|
+
start: [{ command: "systemctl", args: ["--user", "start", unit] }],
|
|
110
|
+
stop: [{ command: "systemctl", args: ["--user", "stop", unit], ignoreFailure: true }],
|
|
111
|
+
uninstall: [
|
|
112
|
+
{ command: "systemctl", args: ["--user", "disable", "--now", unit], ignoreFailure: true }
|
|
113
|
+
],
|
|
114
|
+
reloadAfterUninstall: { command: "systemctl", args: ["--user", "daemon-reload"] }
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
if (input.platform === "win32") {
|
|
118
|
+
const taskName = "Pushary Daemon";
|
|
119
|
+
const definitionPath = win32Path.join(input.stateDir, "pushary-daemon-task.xml");
|
|
120
|
+
const contents = `<?xml version="1.0" encoding="UTF-8"?>
|
|
121
|
+
<Task version="1.4" xmlns="http://schemas.microsoft.com/windows/2004/02/mit/task">
|
|
122
|
+
<RegistrationInfo><Description>Pushary phone-to-agent daemon</Description></RegistrationInfo>
|
|
123
|
+
<Triggers><LogonTrigger><Enabled>true</Enabled></LogonTrigger></Triggers>
|
|
124
|
+
<Principals><Principal id="Author"><LogonType>InteractiveToken</LogonType><RunLevel>LeastPrivilege</RunLevel></Principal></Principals>
|
|
125
|
+
<Settings>
|
|
126
|
+
<MultipleInstancesPolicy>IgnoreNew</MultipleInstancesPolicy>
|
|
127
|
+
<StartWhenAvailable>true</StartWhenAvailable>
|
|
128
|
+
<DisallowStartIfOnBatteries>false</DisallowStartIfOnBatteries>
|
|
129
|
+
<StopIfGoingOnBatteries>false</StopIfGoingOnBatteries>
|
|
130
|
+
<ExecutionTimeLimit>PT0S</ExecutionTimeLimit>
|
|
131
|
+
<RestartOnFailure><Interval>PT1M</Interval><Count>999</Count></RestartOnFailure>
|
|
132
|
+
</Settings>
|
|
133
|
+
<Actions Context="Author">
|
|
134
|
+
<Exec>
|
|
135
|
+
<Command>${xml(input.execPath)}</Command>
|
|
136
|
+
<Arguments>"${xml(input.daemonEntry)}"</Arguments>
|
|
137
|
+
<WorkingDirectory>${xml(input.homeDir)}</WorkingDirectory>
|
|
138
|
+
</Exec>
|
|
139
|
+
</Actions>
|
|
140
|
+
</Task>
|
|
141
|
+
`;
|
|
142
|
+
return {
|
|
143
|
+
definitionPath,
|
|
144
|
+
contents,
|
|
145
|
+
install: [
|
|
146
|
+
{ command: "schtasks.exe", args: ["/Create", "/TN", taskName, "/XML", definitionPath, "/F"] },
|
|
147
|
+
{ command: "schtasks.exe", args: ["/Run", "/TN", taskName] }
|
|
148
|
+
],
|
|
149
|
+
start: [{ command: "schtasks.exe", args: ["/Run", "/TN", taskName] }],
|
|
150
|
+
stop: [{ command: "schtasks.exe", args: ["/End", "/TN", taskName], ignoreFailure: true }],
|
|
151
|
+
uninstall: [{ command: "schtasks.exe", args: ["/Delete", "/TN", taskName, "/F"], ignoreFailure: true }]
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
return null;
|
|
155
|
+
};
|
|
156
|
+
var resolveDaemonServiceDefinition = (options = {}) => {
|
|
157
|
+
const platform = options.platform ?? process.platform;
|
|
158
|
+
const exists = options.entryExists ?? existsSync;
|
|
159
|
+
const globalBinary = options.globalBinary ?? resolveGlobalBinary("pushary-daemon");
|
|
160
|
+
let daemonEntry = options.daemonEntry;
|
|
161
|
+
if (!daemonEntry && globalBinary) {
|
|
162
|
+
if (platform === "win32") {
|
|
163
|
+
const globalRoot = win32Path.dirname(globalBinary);
|
|
164
|
+
const candidate = win32Path.join(
|
|
165
|
+
globalRoot,
|
|
166
|
+
"node_modules",
|
|
167
|
+
"@pushary",
|
|
168
|
+
"agent-hooks",
|
|
169
|
+
"dist",
|
|
170
|
+
"bin",
|
|
171
|
+
"pushary-daemon.js"
|
|
172
|
+
);
|
|
173
|
+
if (exists(candidate)) daemonEntry = candidate;
|
|
174
|
+
} else {
|
|
175
|
+
try {
|
|
176
|
+
const candidate = (options.realpath ?? realpathSync)(globalBinary);
|
|
177
|
+
if (exists(candidate)) daemonEntry = candidate;
|
|
178
|
+
} catch {
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
const argvEntry = options.argvEntry ?? process.argv[1];
|
|
183
|
+
if (!daemonEntry && argvEntry) {
|
|
184
|
+
const path = platform === "win32" ? win32Path : { dirname, join };
|
|
185
|
+
const candidate = path.join(path.dirname(argvEntry), "pushary-daemon.js");
|
|
186
|
+
if (exists(candidate)) daemonEntry = candidate;
|
|
187
|
+
}
|
|
188
|
+
if (!daemonEntry || !exists(daemonEntry)) return null;
|
|
189
|
+
const homeDir = options.homeDir ?? homedir();
|
|
190
|
+
return buildDaemonService({
|
|
191
|
+
platform,
|
|
192
|
+
homeDir,
|
|
193
|
+
stateDir: options.stateDir ?? pusharyDir(),
|
|
194
|
+
execPath: options.execPath ?? process.execPath,
|
|
195
|
+
daemonEntry,
|
|
196
|
+
pathEnv: options.pathEnv ?? process.env.PATH ?? "",
|
|
197
|
+
uid: options.uid ?? process.getuid?.()
|
|
198
|
+
});
|
|
199
|
+
};
|
|
200
|
+
var applyDaemonService = (action, definition, options = {}) => {
|
|
201
|
+
const run = options.run ?? ((command, args) => {
|
|
202
|
+
execFileSync(command, [...args], { stdio: "ignore", windowsHide: true });
|
|
203
|
+
});
|
|
204
|
+
try {
|
|
205
|
+
if (action === "install") writeFileAtomic(definition.definitionPath, definition.contents, 384);
|
|
206
|
+
const steps = action === "uninstall" ? [...definition.stop, ...definition.uninstall] : definition[action];
|
|
207
|
+
for (const step of steps) {
|
|
208
|
+
try {
|
|
209
|
+
run(step.command, step.args);
|
|
210
|
+
} catch (err) {
|
|
211
|
+
if (!step.ignoreFailure) throw err;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
if (action === "uninstall") {
|
|
215
|
+
safeUnlink(definition.definitionPath);
|
|
216
|
+
const reload = definition.reloadAfterUninstall;
|
|
217
|
+
if (reload) run(reload.command, reload.args);
|
|
218
|
+
}
|
|
219
|
+
return { kind: "ok" };
|
|
220
|
+
} catch (err) {
|
|
221
|
+
return { kind: "failed", detail: err instanceof Error ? err.message : String(err) };
|
|
222
|
+
}
|
|
223
|
+
};
|
|
224
|
+
var DAEMON_ACTIONS = /* @__PURE__ */ new Set([
|
|
225
|
+
"install",
|
|
226
|
+
"start",
|
|
227
|
+
"stop",
|
|
228
|
+
"restart",
|
|
229
|
+
"status",
|
|
230
|
+
"uninstall",
|
|
231
|
+
"foreground"
|
|
232
|
+
]);
|
|
233
|
+
var parseDaemonAction = (argv) => {
|
|
234
|
+
const args = argv[0] === "daemon" ? argv.slice(1) : argv;
|
|
235
|
+
const action = args[0] ?? "foreground";
|
|
236
|
+
return DAEMON_ACTIONS.has(action) ? action : null;
|
|
237
|
+
};
|
|
238
|
+
var manageDaemonService = (action, options = {}) => {
|
|
239
|
+
const definition = action === "uninstall" ? buildDaemonService({
|
|
240
|
+
platform: options.platform ?? process.platform,
|
|
241
|
+
homeDir: options.homeDir ?? homedir(),
|
|
242
|
+
stateDir: options.stateDir ?? pusharyDir(),
|
|
243
|
+
execPath: options.execPath ?? process.execPath,
|
|
244
|
+
daemonEntry: options.daemonEntry ?? process.execPath,
|
|
245
|
+
pathEnv: options.pathEnv ?? process.env.PATH ?? "",
|
|
246
|
+
uid: options.uid ?? process.getuid?.()
|
|
247
|
+
}) : resolveDaemonServiceDefinition(options);
|
|
248
|
+
if (!definition) {
|
|
249
|
+
return {
|
|
250
|
+
kind: "unavailable",
|
|
251
|
+
detail: "Could not find the globally installed daemon entry. Run Pushary setup again."
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
return applyDaemonService(action, definition, { run: options.run });
|
|
255
|
+
};
|
|
40
256
|
var spawnDetachedDaemon = (plan, options = {}) => {
|
|
41
257
|
const spawnImpl = options.spawnImpl ?? spawnClaude;
|
|
42
258
|
const child = spawnImpl(plan.command, plan.args, {
|
|
@@ -278,6 +494,31 @@ var requestDaemonHandoff = async (initial, options = {}) => {
|
|
|
278
494
|
}
|
|
279
495
|
return status;
|
|
280
496
|
};
|
|
497
|
+
var stopDaemonRunning = async (options = {}) => {
|
|
498
|
+
const dir = options.dir ?? pusharyDir();
|
|
499
|
+
const initial = readDaemonStatus(options);
|
|
500
|
+
if (initial.pid === null || initial.processAlive !== true) {
|
|
501
|
+
safeUnlink(statePath(dir));
|
|
502
|
+
safeUnlink(lockPath(dir));
|
|
503
|
+
return { kind: "absent" };
|
|
504
|
+
}
|
|
505
|
+
let status;
|
|
506
|
+
try {
|
|
507
|
+
status = await requestDaemonHandoff(initial, options);
|
|
508
|
+
} catch (err) {
|
|
509
|
+
return { kind: "unavailable", detail: err instanceof Error ? err.message : String(err) };
|
|
510
|
+
}
|
|
511
|
+
if (status.pid === initial.pid && status.processAlive === true) {
|
|
512
|
+
return { kind: "unavailable", detail: "daemon did not stop" };
|
|
513
|
+
}
|
|
514
|
+
safeUnlink(statePath(dir));
|
|
515
|
+
safeUnlink(lockPath(dir));
|
|
516
|
+
return { kind: "stopped" };
|
|
517
|
+
};
|
|
518
|
+
var replaceDaemonService = async (options = {}) => {
|
|
519
|
+
const stopped = await stopDaemonRunning(options);
|
|
520
|
+
return stopped.kind === "unavailable" ? stopped : manageDaemonService("install", options);
|
|
521
|
+
};
|
|
281
522
|
var launchInstalledDaemon = (options) => {
|
|
282
523
|
const entryExists = options.entryExists ?? existsSync;
|
|
283
524
|
const argvEntry = process.argv[1];
|
|
@@ -336,8 +577,12 @@ var ensureDaemonRunning = async (options = {}) => {
|
|
|
336
577
|
|
|
337
578
|
export {
|
|
338
579
|
DAEMON_LEASE_RENEW_INTERVAL_MS,
|
|
580
|
+
parseDaemonAction,
|
|
581
|
+
manageDaemonService,
|
|
339
582
|
readDaemonStatus,
|
|
340
583
|
acquireDaemonLease,
|
|
341
584
|
requestDaemonHandoff,
|
|
585
|
+
stopDaemonRunning,
|
|
586
|
+
replaceDaemonService,
|
|
342
587
|
ensureDaemonRunning
|
|
343
588
|
};
|
|
@@ -1,6 +1,3 @@
|
|
|
1
|
-
import {
|
|
2
|
-
canonicalJson
|
|
3
|
-
} from "./chunk-GIRT7677.js";
|
|
4
1
|
import {
|
|
5
2
|
HOOK_BUDGETS,
|
|
6
3
|
HOOK_LOCATOR_BINARY
|
|
@@ -10,6 +7,16 @@ import {
|
|
|
10
7
|
import { createHash } from "crypto";
|
|
11
8
|
import { homedir } from "os";
|
|
12
9
|
import { join } from "path";
|
|
10
|
+
|
|
11
|
+
// src/canonical-json.ts
|
|
12
|
+
var canonicalJson = (value) => {
|
|
13
|
+
if (value === null || typeof value !== "object") return JSON.stringify(value);
|
|
14
|
+
if (Array.isArray(value)) return "[" + value.map(canonicalJson).join(",") + "]";
|
|
15
|
+
const record = value;
|
|
16
|
+
return "{" + Object.keys(record).sort().map((key) => JSON.stringify(key) + ":" + canonicalJson(record[key])).join(",") + "}";
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
// src/codex-config.ts
|
|
13
20
|
var CODEX_HOOK_BINARY = "pushary-codex-hook";
|
|
14
21
|
var codexHome = () => codexHomeFrom(homedir());
|
|
15
22
|
var codexHomeFrom = (home) => process.env.CODEX_HOME?.trim() || join(home, ".codex");
|
|
@@ -263,6 +270,7 @@ var geminiMd = () => join2(homedir2(), ".gemini", "GEMINI.md");
|
|
|
263
270
|
var pusharyConfigFile = () => join2(homedir2(), ".pushary", "config.json");
|
|
264
271
|
|
|
265
272
|
export {
|
|
273
|
+
canonicalJson,
|
|
266
274
|
CODEX_HOOK_BINARY,
|
|
267
275
|
codexHome,
|
|
268
276
|
codexHomeFrom,
|
package/dist/src/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
handlePreToolUse
|
|
3
|
-
} from "../chunk-
|
|
3
|
+
} from "../chunk-MZBT2LXW.js";
|
|
4
4
|
import "../chunk-ATBKJNWS.js";
|
|
5
5
|
import "../chunk-VZKXBFUA.js";
|
|
6
6
|
import "../chunk-YHG74UFF.js";
|
|
@@ -12,19 +12,21 @@ import {
|
|
|
12
12
|
handlePostToolUse,
|
|
13
13
|
handleStop,
|
|
14
14
|
reportEvent
|
|
15
|
-
} from "../chunk-
|
|
15
|
+
} from "../chunk-NFI2K2ZQ.js";
|
|
16
16
|
import {
|
|
17
17
|
askUser,
|
|
18
18
|
cancelQuestion,
|
|
19
19
|
waitForAnswer
|
|
20
|
-
} from "../chunk-
|
|
21
|
-
import "../chunk-
|
|
22
|
-
import "../chunk-
|
|
20
|
+
} from "../chunk-GKAKAOKC.js";
|
|
21
|
+
import "../chunk-KOPUTJQC.js";
|
|
22
|
+
import "../chunk-2HYPZLYY.js";
|
|
23
|
+
import "../chunk-V37ZXMH3.js";
|
|
23
24
|
import "../chunk-BSZYIAZL.js";
|
|
24
25
|
import "../chunk-SAF6HGAA.js";
|
|
25
26
|
import "../chunk-OFRNZWC4.js";
|
|
26
27
|
import "../chunk-7QLSKOSU.js";
|
|
27
28
|
import "../chunk-KZERVKTD.js";
|
|
29
|
+
import "../chunk-6MTNS63X.js";
|
|
28
30
|
import {
|
|
29
31
|
getApiKey,
|
|
30
32
|
getBaseUrl
|
package/package.json
CHANGED
package/dist/chunk-GIRT7677.js
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
// src/canonical-json.ts
|
|
2
|
-
var canonicalJson = (value) => {
|
|
3
|
-
if (value === null || typeof value !== "object") return JSON.stringify(value);
|
|
4
|
-
if (Array.isArray(value)) return "[" + value.map(canonicalJson).join(",") + "]";
|
|
5
|
-
const record = value;
|
|
6
|
-
return "{" + Object.keys(record).sort().map((key) => JSON.stringify(key) + ":" + canonicalJson(record[key])).join(",") + "}";
|
|
7
|
-
};
|
|
8
|
-
|
|
9
|
-
export {
|
|
10
|
-
canonicalJson
|
|
11
|
-
};
|
package/dist/chunk-RN3NOEJF.js
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
// src/identity.ts
|
|
2
|
-
import { createHash } from "crypto";
|
|
3
|
-
import { hostname } from "os";
|
|
4
|
-
var deriveMachineId = (host) => createHash("sha256").update(host).digest("hex").slice(0, 8);
|
|
5
|
-
var getMachineId = () => deriveMachineId(hostname());
|
|
6
|
-
|
|
7
|
-
export {
|
|
8
|
-
getMachineId
|
|
9
|
-
};
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import {
|
|
2
2
|
resolveShellRc
|
|
3
3
|
} from "./chunk-BC3VCZ3E.js";
|
|
4
|
+
import {
|
|
5
|
+
resolveInstallSourceFor
|
|
6
|
+
} from "./chunk-OFRNZWC4.js";
|
|
4
7
|
import {
|
|
5
8
|
backupFile,
|
|
6
9
|
readJsonSafe,
|
|
7
10
|
writeFileAtomic,
|
|
8
11
|
writeJsonAtomic
|
|
9
12
|
} from "./chunk-6MTNS63X.js";
|
|
10
|
-
import {
|
|
11
|
-
resolveInstallSourceFor
|
|
12
|
-
} from "./chunk-OFRNZWC4.js";
|
|
13
13
|
import {
|
|
14
14
|
configFilePath
|
|
15
15
|
} from "./chunk-2UMNXADU.js";
|