@pushary/agent-hooks 0.89.4 → 0.89.6
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/dist/bin/pushary-bell-hook.js +2 -2
- package/dist/bin/pushary-bell.js +4 -4
- package/dist/bin/pushary-claude.js +1 -1
- package/dist/bin/pushary-clean.js +5 -8
- package/dist/bin/pushary-codex-bridge.js +1 -1
- package/dist/bin/pushary-connect.js +3 -3
- package/dist/bin/pushary-daemon.js +64 -31
- package/dist/bin/pushary-disconnect.js +2 -2
- package/dist/bin/pushary-doctor.js +51 -24
- package/dist/bin/pushary-hook.js +2 -2
- package/dist/bin/pushary-login.js +3 -3
- package/dist/bin/pushary-logout.js +3 -3
- package/dist/bin/pushary-mode.js +2 -2
- package/dist/bin/pushary-setup.js +116 -21
- package/dist/bin/pushary-stats.js +2 -2
- package/dist/bin/pushary-status.js +3 -3
- package/dist/bin/pushary-suggestions.js +2 -2
- package/dist/bin/pushary-upgrade.js +68 -199
- package/dist/bin/pushary-wait.js +2 -2
- package/dist/bin/pushary.js +1 -1
- package/dist/{chunk-GPNOHKFO.js → chunk-3XTFX4CL.js} +1 -0
- package/dist/chunk-5TASNKRX.js +210 -0
- package/dist/{chunk-W6NPWHBJ.js → chunk-L3YUHEB6.js} +13 -1
- package/dist/{chunk-KJ57OPCC.js → chunk-LURY4WNF.js} +1 -1
- package/dist/chunk-NKHEHEUM.js +56 -0
- package/dist/{chunk-NLMSSKES.js → chunk-NQNCSPEH.js} +72 -9
- package/dist/{chunk-7IJYOBHL.js → chunk-WQGMUIDW.js} +1 -1
- package/package.json +1 -1
- package/dist/chunk-FWUEYXSD.js +0 -29
|
@@ -50,9 +50,19 @@ import {
|
|
|
50
50
|
guardedArgv
|
|
51
51
|
} from "../chunk-AIGDBRIJ.js";
|
|
52
52
|
import {
|
|
53
|
+
daemonServiceManagerAvailable,
|
|
54
|
+
disableDaemonService,
|
|
53
55
|
ensureDaemonRunning,
|
|
54
|
-
|
|
55
|
-
|
|
56
|
+
hasDaemonServiceDefinition,
|
|
57
|
+
readDaemonStatus,
|
|
58
|
+
replaceDaemonService,
|
|
59
|
+
stopDaemonService
|
|
60
|
+
} from "../chunk-NQNCSPEH.js";
|
|
61
|
+
import {
|
|
62
|
+
detectProviderLiveCapabilities,
|
|
63
|
+
hasSpawnProvider,
|
|
64
|
+
resolveControlPolicy
|
|
65
|
+
} from "../chunk-NKHEHEUM.js";
|
|
56
66
|
import "../chunk-XHKBHWLX.js";
|
|
57
67
|
import {
|
|
58
68
|
installGlobally,
|
|
@@ -108,15 +118,16 @@ import {
|
|
|
108
118
|
exportLine,
|
|
109
119
|
keyPrefix,
|
|
110
120
|
readConfigFileKey,
|
|
121
|
+
readControlMode,
|
|
111
122
|
readKeySource,
|
|
112
123
|
writeKey
|
|
113
|
-
} from "../chunk-
|
|
124
|
+
} from "../chunk-L3YUHEB6.js";
|
|
114
125
|
import {
|
|
115
126
|
parseFlags
|
|
116
127
|
} from "../chunk-GMXKITVA.js";
|
|
117
128
|
import {
|
|
118
129
|
renderCommandHelp
|
|
119
|
-
} from "../chunk-
|
|
130
|
+
} from "../chunk-3XTFX4CL.js";
|
|
120
131
|
import {
|
|
121
132
|
installClaudeAlias,
|
|
122
133
|
resolveShellRc
|
|
@@ -487,6 +498,12 @@ var parseVerifyMode = (raw) => {
|
|
|
487
498
|
if (VERIFY_MODES.includes(value)) return value;
|
|
488
499
|
throw new UsageError(`--verify must be one of: ${VERIFY_MODES.join(", ")} (got ${raw})`);
|
|
489
500
|
};
|
|
501
|
+
var CONTROL_MODES = ["auto", "on", "off"];
|
|
502
|
+
var parseControlMode = (raw) => {
|
|
503
|
+
const value = raw.trim().toLowerCase();
|
|
504
|
+
if (CONTROL_MODES.includes(value)) return value;
|
|
505
|
+
throw new UsageError(`--control must be one of: ${CONTROL_MODES.join(", ")} (got ${raw})`);
|
|
506
|
+
};
|
|
490
507
|
var effectiveVerify = (options, context) => {
|
|
491
508
|
if (options.verifyExplicit) return options.verify;
|
|
492
509
|
if (options.verify === "roundtrip") return "roundtrip";
|
|
@@ -494,8 +511,9 @@ var effectiveVerify = (options, context) => {
|
|
|
494
511
|
};
|
|
495
512
|
var SETUP_FLAGS = {
|
|
496
513
|
bools: ["key-stdin", "skip-phone", "yes", "y", "json", "dry-run", "help", "h"],
|
|
497
|
-
values: ["key", "connect", "agents", "verify"]
|
|
514
|
+
values: ["key", "connect", "agents", "verify", "control"]
|
|
498
515
|
};
|
|
516
|
+
var effectiveControlMode = (options, stored, configPresent) => options.controlExplicit ? options.control : stored ?? (configPresent ? null : options.control);
|
|
499
517
|
var isAgentChoice = (value) => AGENT_CHOICES.includes(value);
|
|
500
518
|
var parseAgentSelection = (raw, yes) => {
|
|
501
519
|
if (raw === void 0) {
|
|
@@ -532,6 +550,7 @@ var parseSetupOptions = (input2) => {
|
|
|
532
550
|
const connectRaw = flags.values.get("connect");
|
|
533
551
|
const connectMode = connectRaw === void 0 ? "app" : parseConnectMode(connectRaw);
|
|
534
552
|
const verifyRaw = flags.values.get("verify");
|
|
553
|
+
const controlRaw = flags.values.get("control");
|
|
535
554
|
const nonInteractive = yes || agentsFlag !== void 0 || flags.bools.has("json") || !input2.stdinIsTty;
|
|
536
555
|
const verify = verifyRaw !== void 0 ? parseVerifyMode(verifyRaw) : nonInteractive ? "push" : "roundtrip";
|
|
537
556
|
const key = flags.values.get("key")?.trim() || null;
|
|
@@ -567,7 +586,9 @@ var parseSetupOptions = (input2) => {
|
|
|
567
586
|
key,
|
|
568
587
|
keyStdin,
|
|
569
588
|
verify,
|
|
570
|
-
verifyExplicit: verifyRaw !== void 0
|
|
589
|
+
verifyExplicit: verifyRaw !== void 0,
|
|
590
|
+
control: controlRaw === void 0 ? "auto" : parseControlMode(controlRaw),
|
|
591
|
+
controlExplicit: controlRaw !== void 0
|
|
571
592
|
};
|
|
572
593
|
};
|
|
573
594
|
|
|
@@ -719,7 +740,9 @@ var checkForUpdates = async (current) => {
|
|
|
719
740
|
} catch {
|
|
720
741
|
}
|
|
721
742
|
};
|
|
743
|
+
var globalInstallReady = false;
|
|
722
744
|
var installGlobally2 = async () => {
|
|
745
|
+
if (globalInstallReady) return;
|
|
723
746
|
const version = getPackageVersion();
|
|
724
747
|
await spinner(`Installing pushary-hook globally (${version})`, async () => {
|
|
725
748
|
try {
|
|
@@ -728,6 +751,7 @@ var installGlobally2 = async () => {
|
|
|
728
751
|
throw new Error(npmErrorMessage(err));
|
|
729
752
|
}
|
|
730
753
|
});
|
|
754
|
+
globalInstallReady = true;
|
|
731
755
|
};
|
|
732
756
|
var _cachedSkillContent = null;
|
|
733
757
|
var fetchSkillContent = async () => {
|
|
@@ -1346,10 +1370,10 @@ ${pluginLocationSnippet(VSCODE_PLUGIN_DIR)}`
|
|
|
1346
1370
|
console.log(` ${dim("\u2022")} Fully quit and reopen VS Code to load the plugin`);
|
|
1347
1371
|
noteManual("Fully quit and reopen VS Code. A Reload Window may not pick up a new plugin location.");
|
|
1348
1372
|
};
|
|
1349
|
-
var saveApiKey = async (apiKey) => {
|
|
1373
|
+
var saveApiKey = async (apiKey, controlMode) => {
|
|
1350
1374
|
let result;
|
|
1351
1375
|
await spinner("Saving your API key", async () => {
|
|
1352
|
-
result = writeKey(apiKey);
|
|
1376
|
+
result = writeKey(apiKey, controlMode === null ? {} : { controlMode });
|
|
1353
1377
|
});
|
|
1354
1378
|
if (!result) throw new Error("Could not save the API key");
|
|
1355
1379
|
if (result.configBackupPath) {
|
|
@@ -1702,7 +1726,7 @@ var AGENT_TARGETS = {
|
|
|
1702
1726
|
],
|
|
1703
1727
|
custom: ["nothing (prints connection details only)"]
|
|
1704
1728
|
};
|
|
1705
|
-
var reportDryRun = (apiKey, agents, keyCheck) => {
|
|
1729
|
+
var reportDryRun = (apiKey, agents, keyCheck, controlMode) => {
|
|
1706
1730
|
console.log();
|
|
1707
1731
|
console.log(` ${bold("Dry run")} ${dim("\u2014 nothing below has been written")}`);
|
|
1708
1732
|
console.log();
|
|
@@ -1710,6 +1734,7 @@ var reportDryRun = (apiKey, agents, keyCheck) => {
|
|
|
1710
1734
|
apiKey ? ` ${dim("Key:")} ${dim(`${apiKey.slice(0, 8)}...${apiKey.slice(-4)}`)} ${dim(`(${keyCheck?.kind ?? "not verified"})`)}` : ` ${dim("Key:")} ${dim("none on this machine \u2014 a real run would acquire one")}`
|
|
1711
1735
|
);
|
|
1712
1736
|
console.log(` ${dim("Key store:")} ${PUSHARY_CONFIG_FILE}`);
|
|
1737
|
+
console.log(` ${dim("Control:")} ${controlMode ?? "unchanged (legacy install)"}`);
|
|
1713
1738
|
const rc = resolveShellRc();
|
|
1714
1739
|
console.log(` ${dim("Shell rc:")} ${rc ? rc.path : dim("none for this shell; the export line would be printed instead")}`);
|
|
1715
1740
|
console.log();
|
|
@@ -1748,6 +1773,7 @@ var main = async () => {
|
|
|
1748
1773
|
`);
|
|
1749
1774
|
process.exit(EXIT.OK);
|
|
1750
1775
|
}
|
|
1776
|
+
const controlMode = effectiveControlMode(options, readControlMode(), existsSync(PUSHARY_CONFIG_FILE));
|
|
1751
1777
|
recordSetupOptions(options);
|
|
1752
1778
|
if (options.json) {
|
|
1753
1779
|
jsonMode = true;
|
|
@@ -1806,8 +1832,8 @@ var main = async () => {
|
|
|
1806
1832
|
console.log();
|
|
1807
1833
|
markStep("resolve-agents");
|
|
1808
1834
|
const plannedAgents = await resolveAgents(options);
|
|
1809
|
-
reportDryRun(null, plannedAgents, null);
|
|
1810
|
-
emitJson(options, { ok: true, dryRun: true, agents: plannedAgents, keyCheck: "skipped", key: "none" });
|
|
1835
|
+
reportDryRun(null, plannedAgents, null, controlMode);
|
|
1836
|
+
emitJson(options, { ok: true, dryRun: true, agents: plannedAgents, control: controlMode, keyCheck: "skipped", key: "none" });
|
|
1811
1837
|
process.exit(EXIT.OK);
|
|
1812
1838
|
} else if (connectMode === "app" && canShowPairingQr() && !options.skipPhone) {
|
|
1813
1839
|
console.log(` ${dim("Pairing with your Pushary app.")}`);
|
|
@@ -1894,12 +1920,12 @@ var main = async () => {
|
|
|
1894
1920
|
markStep("resolve-agents");
|
|
1895
1921
|
const agents = await resolveAgents(options);
|
|
1896
1922
|
if (options.dryRun) {
|
|
1897
|
-
reportDryRun(trimmedKey, agents, keyCheck);
|
|
1898
|
-
emitJson(options, { ok: true, dryRun: true, agents, keyCheck: keyCheck?.kind ?? "skipped" });
|
|
1923
|
+
reportDryRun(trimmedKey, agents, keyCheck, controlMode);
|
|
1924
|
+
emitJson(options, { ok: true, dryRun: true, agents, control: controlMode, keyCheck: keyCheck?.kind ?? "skipped" });
|
|
1899
1925
|
process.exit(EXIT.OK);
|
|
1900
1926
|
}
|
|
1901
1927
|
markStep("save-key");
|
|
1902
|
-
const rc = await saveApiKey(trimmedKey);
|
|
1928
|
+
const rc = await saveApiKey(trimmedKey, controlMode);
|
|
1903
1929
|
const context = { rc };
|
|
1904
1930
|
if (envKey && envKey !== trimmedKey) {
|
|
1905
1931
|
noteManual(
|
|
@@ -1909,6 +1935,7 @@ var main = async () => {
|
|
|
1909
1935
|
const failed = [];
|
|
1910
1936
|
const completed = [];
|
|
1911
1937
|
const skipped = [];
|
|
1938
|
+
let controlLifecycleFailure = null;
|
|
1912
1939
|
if (agents.length === 0) {
|
|
1913
1940
|
console.log(`
|
|
1914
1941
|
${check} API key saved. No agents configured.`);
|
|
@@ -1947,6 +1974,16 @@ var main = async () => {
|
|
|
1947
1974
|
await offerClaudeAlias(options);
|
|
1948
1975
|
}
|
|
1949
1976
|
}
|
|
1977
|
+
if (controlMode === "off") {
|
|
1978
|
+
markStep("control:disable");
|
|
1979
|
+
const disabled = await disableDaemonService();
|
|
1980
|
+
if (disabled.kind !== "ok") {
|
|
1981
|
+
controlLifecycleFailure = disabled.detail;
|
|
1982
|
+
console.log(` ${yellow("!")} Could not fully disable phone-start: ${controlLifecycleFailure}`);
|
|
1983
|
+
} else {
|
|
1984
|
+
console.log(` ${check} Phone-start background service disabled.`);
|
|
1985
|
+
}
|
|
1986
|
+
}
|
|
1950
1987
|
markStep("connect-phone");
|
|
1951
1988
|
const skipPhone = options.skipPhone;
|
|
1952
1989
|
let phone = null;
|
|
@@ -2008,6 +2045,8 @@ var main = async () => {
|
|
|
2008
2045
|
failed,
|
|
2009
2046
|
keyCheck: "locked",
|
|
2010
2047
|
rc: rc.kind,
|
|
2048
|
+
control: controlMode,
|
|
2049
|
+
daemon: controlLifecycleFailure ? "unavailable" : "skipped",
|
|
2011
2050
|
exitCode: report.exitCode
|
|
2012
2051
|
});
|
|
2013
2052
|
await reportSetupOutcome({
|
|
@@ -2028,11 +2067,64 @@ var main = async () => {
|
|
|
2028
2067
|
const reachesYou = phone?.reachesYou ?? true;
|
|
2029
2068
|
markStep("closing");
|
|
2030
2069
|
const keyIsTrusted = keyFromPairing || keyCheck?.kind === "ok";
|
|
2031
|
-
const
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
|
|
2035
|
-
|
|
2070
|
+
const managedControlAgents = ["claude_code", "codex", "gemini_cli"];
|
|
2071
|
+
const configuredControlAgents = managedControlAgents.filter((agent) => agentIsWired(agent));
|
|
2072
|
+
const controlCapabilities = detectProviderLiveCapabilities(configuredControlAgents.map(
|
|
2073
|
+
(agent) => agent === "claude_code" ? "claude" : agent === "gemini_cli" ? "gemini" : agent
|
|
2074
|
+
));
|
|
2075
|
+
const providerAvailable = hasSpawnProvider(controlCapabilities);
|
|
2076
|
+
const managerAvailable = daemonServiceManagerAvailable();
|
|
2077
|
+
const servicePresent = readDaemonStatus().kind !== "absent" || hasDaemonServiceDefinition();
|
|
2078
|
+
let controlPolicy = resolveControlPolicy({
|
|
2079
|
+
mode: controlMode,
|
|
2080
|
+
providerAvailable,
|
|
2081
|
+
managerAvailable,
|
|
2082
|
+
servicePresent
|
|
2083
|
+
});
|
|
2084
|
+
if (controlPolicy === "legacy") {
|
|
2085
|
+
let legacyRuntimeFailure = null;
|
|
2086
|
+
try {
|
|
2087
|
+
await installGlobally2();
|
|
2088
|
+
const replaced = await replaceDaemonService();
|
|
2089
|
+
if (replaced.kind !== "ok") throw new Error(replaced.detail);
|
|
2090
|
+
} catch (err) {
|
|
2091
|
+
legacyRuntimeFailure = formatError(err);
|
|
2092
|
+
}
|
|
2093
|
+
let retired = legacyRuntimeFailure !== null;
|
|
2094
|
+
let stopped = retired ? await disableDaemonService() : await stopDaemonService();
|
|
2095
|
+
if (!retired && stopped.kind !== "ok") {
|
|
2096
|
+
legacyRuntimeFailure = stopped.detail;
|
|
2097
|
+
retired = true;
|
|
2098
|
+
stopped = await disableDaemonService();
|
|
2099
|
+
}
|
|
2100
|
+
if (stopped.kind !== "ok") {
|
|
2101
|
+
controlLifecycleFailure = [legacyRuntimeFailure, stopped.detail].filter(Boolean).join("; ");
|
|
2102
|
+
console.log(` ${yellow("!")} Could not make the legacy phone-start service safe: ${controlLifecycleFailure}`);
|
|
2103
|
+
} else if (retired) {
|
|
2104
|
+
controlPolicy = resolveControlPolicy({
|
|
2105
|
+
mode: controlMode,
|
|
2106
|
+
providerAvailable,
|
|
2107
|
+
managerAvailable,
|
|
2108
|
+
servicePresent: false
|
|
2109
|
+
});
|
|
2110
|
+
console.log(` ${yellow("!")} Retired the legacy phone-start service because it could not be safely repinned: ${legacyRuntimeFailure}`);
|
|
2111
|
+
}
|
|
2112
|
+
}
|
|
2113
|
+
if (controlMode === "on" && controlPolicy !== "enabled") {
|
|
2114
|
+
console.log(` ${yellow("!")} Phone-start was required, but this machine has no supported provider or native background-service manager.`);
|
|
2115
|
+
} else if (controlPolicy === "legacy") {
|
|
2116
|
+
console.log(` ${yellow("!")} A legacy phone-start service cannot be safely adopted in this session. Disable it with --control off or restore its provider and native service manager.`);
|
|
2117
|
+
}
|
|
2118
|
+
const daemon = keyIsTrusted && controlPolicy === "enabled" ? await (async () => {
|
|
2119
|
+
try {
|
|
2120
|
+
await installGlobally2();
|
|
2121
|
+
const service = await replaceDaemonService();
|
|
2122
|
+
return service.kind === "ok" ? ensureDaemonRunning({ spawnDaemon: () => {
|
|
2123
|
+
} }) : { kind: "unavailable", detail: service.detail };
|
|
2124
|
+
} catch (err) {
|
|
2125
|
+
return { kind: "unavailable", detail: formatError(err) };
|
|
2126
|
+
}
|
|
2127
|
+
})() : controlMode === "on" || controlPolicy === "legacy" ? { kind: "unavailable", detail: "Managed control is required but no usable provider/service-manager pair is available" } : null;
|
|
2036
2128
|
const closing = describeClosing({
|
|
2037
2129
|
agentsOk,
|
|
2038
2130
|
configuredNothing,
|
|
@@ -2040,7 +2132,7 @@ var main = async () => {
|
|
|
2040
2132
|
failed,
|
|
2041
2133
|
reachChecked,
|
|
2042
2134
|
reachesYou,
|
|
2043
|
-
daemonReady: daemon === null ? null : daemon.kind === "running" || daemon.kind === "started",
|
|
2135
|
+
daemonReady: controlLifecycleFailure ? false : daemon === null ? null : daemon.kind === "running" || daemon.kind === "started",
|
|
2044
2136
|
// null when the check did not run, so it changes nothing. Only an outright
|
|
2045
2137
|
// `false` is allowed to hold back "Setup complete.".
|
|
2046
2138
|
roundTripAnswered: roundTrip === null ? null : roundTrip.kind === "answered" ? true : roundTrip.kind === "unanswered" ? false : null
|
|
@@ -2085,7 +2177,10 @@ var main = async () => {
|
|
|
2085
2177
|
roundTrip: roundTrip === null ? "skipped" : roundTrip.kind,
|
|
2086
2178
|
rc: rc.kind,
|
|
2087
2179
|
rcPath: rc.path,
|
|
2088
|
-
daemon: daemon?.kind ?? "skipped",
|
|
2180
|
+
daemon: controlLifecycleFailure ? "unavailable" : daemon?.kind ?? "skipped",
|
|
2181
|
+
control: controlMode,
|
|
2182
|
+
controlPolicy,
|
|
2183
|
+
controlCapabilities,
|
|
2089
2184
|
exitCode
|
|
2090
2185
|
});
|
|
2091
2186
|
if (exitCode !== EXIT.OK) {
|
|
@@ -4,8 +4,8 @@ import {
|
|
|
4
4
|
} from "../chunk-VZKXBFUA.js";
|
|
5
5
|
import {
|
|
6
6
|
exitOnHelpFlag
|
|
7
|
-
} from "../chunk-
|
|
8
|
-
import "../chunk-
|
|
7
|
+
} from "../chunk-LURY4WNF.js";
|
|
8
|
+
import "../chunk-3XTFX4CL.js";
|
|
9
9
|
import "../chunk-DINDL2CF.js";
|
|
10
10
|
import "../chunk-KZERVKTD.js";
|
|
11
11
|
import {
|
|
@@ -20,14 +20,14 @@ import {
|
|
|
20
20
|
} from "../chunk-5RUIFDTP.js";
|
|
21
21
|
import {
|
|
22
22
|
readKeySource
|
|
23
|
-
} from "../chunk-
|
|
23
|
+
} from "../chunk-L3YUHEB6.js";
|
|
24
24
|
import {
|
|
25
25
|
rejectUnknownFlags
|
|
26
26
|
} from "../chunk-GMXKITVA.js";
|
|
27
27
|
import {
|
|
28
28
|
exitOnHelpFlag
|
|
29
|
-
} from "../chunk-
|
|
30
|
-
import "../chunk-
|
|
29
|
+
} from "../chunk-LURY4WNF.js";
|
|
30
|
+
import "../chunk-3XTFX4CL.js";
|
|
31
31
|
import "../chunk-BC3VCZ3E.js";
|
|
32
32
|
import "../chunk-DINDL2CF.js";
|
|
33
33
|
import "../chunk-BSZYIAZL.js";
|
|
@@ -7,8 +7,8 @@ import {
|
|
|
7
7
|
} from "../chunk-GMXKITVA.js";
|
|
8
8
|
import {
|
|
9
9
|
exitOnHelpFlag
|
|
10
|
-
} from "../chunk-
|
|
11
|
-
import "../chunk-
|
|
10
|
+
} from "../chunk-LURY4WNF.js";
|
|
11
|
+
import "../chunk-3XTFX4CL.js";
|
|
12
12
|
import "../chunk-DINDL2CF.js";
|
|
13
13
|
import {
|
|
14
14
|
UsageError
|
|
@@ -1,253 +1,98 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
|
-
|
|
4
|
-
} from "../chunk-
|
|
5
|
-
import
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
addGeminiHooks,
|
|
9
|
-
addGeminiMcpServer,
|
|
10
|
-
addPusharyHooks,
|
|
11
|
-
addPusharyToolPermissions,
|
|
12
|
-
hasGeminiHooks
|
|
13
|
-
} from "../chunk-7TS2G4QG.js";
|
|
3
|
+
reapplyAllAgents
|
|
4
|
+
} from "../chunk-5TASNKRX.js";
|
|
5
|
+
import "../chunk-475T3XIO.js";
|
|
6
|
+
import "../chunk-OBI4YMCT.js";
|
|
7
|
+
import "../chunk-7TS2G4QG.js";
|
|
14
8
|
import "../chunk-ATBKJNWS.js";
|
|
9
|
+
import "../chunk-AIGDBRIJ.js";
|
|
15
10
|
import {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
import {
|
|
11
|
+
daemonServiceManagerAvailable,
|
|
12
|
+
disableDaemonService,
|
|
19
13
|
ensureDaemonRunning,
|
|
20
|
-
|
|
21
|
-
|
|
14
|
+
hasDaemonServiceDefinition,
|
|
15
|
+
readDaemonStatus,
|
|
16
|
+
replaceDaemonService,
|
|
17
|
+
stopDaemonService
|
|
18
|
+
} from "../chunk-NQNCSPEH.js";
|
|
19
|
+
import {
|
|
20
|
+
detectProviderLiveCapabilities,
|
|
21
|
+
hasSpawnProvider,
|
|
22
|
+
resolveControlPolicy
|
|
23
|
+
} from "../chunk-NKHEHEUM.js";
|
|
22
24
|
import {
|
|
23
25
|
needsShell
|
|
24
26
|
} from "../chunk-XHKBHWLX.js";
|
|
25
27
|
import {
|
|
26
28
|
execNpm,
|
|
27
29
|
npmErrorMessage,
|
|
28
|
-
resolveGlobalBinDir,
|
|
29
30
|
resolveGlobalBinary
|
|
30
31
|
} from "../chunk-PZA7G4CN.js";
|
|
31
32
|
import "../chunk-2HYPZLYY.js";
|
|
32
33
|
import {
|
|
33
|
-
CODEX_HOOK_BINARY,
|
|
34
|
-
addCodexHookTrust,
|
|
35
|
-
addCodexHooks,
|
|
36
|
-
addCodexMcpServer,
|
|
37
34
|
claudeJson,
|
|
38
35
|
codexConfigToml,
|
|
39
|
-
codexHookPositions,
|
|
40
|
-
codexHooksJson,
|
|
41
36
|
cursorPluginDir,
|
|
42
37
|
geminiSettings,
|
|
43
|
-
|
|
44
|
-
vscodePluginDir,
|
|
45
|
-
vscodePluginMcp
|
|
38
|
+
vscodePluginDir
|
|
46
39
|
} from "../chunk-V37ZXMH3.js";
|
|
40
|
+
import {
|
|
41
|
+
readControlMode
|
|
42
|
+
} from "../chunk-L3YUHEB6.js";
|
|
47
43
|
import {
|
|
48
44
|
exitOnHelpFlag
|
|
49
|
-
} from "../chunk-
|
|
50
|
-
import "../chunk-
|
|
45
|
+
} from "../chunk-LURY4WNF.js";
|
|
46
|
+
import "../chunk-3XTFX4CL.js";
|
|
47
|
+
import "../chunk-BC3VCZ3E.js";
|
|
51
48
|
import {
|
|
52
49
|
isNewerVersion
|
|
53
50
|
} from "../chunk-DINDL2CF.js";
|
|
51
|
+
import "../chunk-OFRNZWC4.js";
|
|
54
52
|
import "../chunk-KZERVKTD.js";
|
|
55
|
-
import
|
|
56
|
-
readJsonSafe
|
|
57
|
-
} from "../chunk-6MTNS63X.js";
|
|
53
|
+
import "../chunk-6MTNS63X.js";
|
|
58
54
|
import {
|
|
59
55
|
getApiKey
|
|
60
56
|
} from "../chunk-2UMNXADU.js";
|
|
61
57
|
import "../chunk-L4C2JXJS.js";
|
|
62
58
|
|
|
63
59
|
// bin/pushary-upgrade.ts
|
|
64
|
-
import { existsSync
|
|
65
|
-
import { homedir as homedir2 } from "os";
|
|
66
|
-
import { join as join2 } from "path";
|
|
67
|
-
import { execFileSync } from "child_process";
|
|
68
|
-
|
|
69
|
-
// src/reapply.ts
|
|
70
|
-
import { join, dirname } from "path";
|
|
60
|
+
import { existsSync } from "fs";
|
|
71
61
|
import { homedir } from "os";
|
|
72
|
-
import {
|
|
73
|
-
import {
|
|
74
|
-
var CLAUDE_SETTINGS = join(homedir(), ".claude", "settings.json");
|
|
75
|
-
var CLAUDE_JSON = join(homedir(), ".claude.json");
|
|
76
|
-
var readJson = (filePath) => {
|
|
77
|
-
const result = readJsonSafe(filePath);
|
|
78
|
-
if (result.kind === "ok") return result.value;
|
|
79
|
-
if (result.kind === "missing") return {};
|
|
80
|
-
return null;
|
|
81
|
-
};
|
|
82
|
-
var writeJson = (filePath, data) => {
|
|
83
|
-
const dir = dirname(filePath);
|
|
84
|
-
if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
|
|
85
|
-
writeFileSync(filePath, JSON.stringify(data, null, 2) + "\n", "utf-8");
|
|
86
|
-
};
|
|
87
|
-
var hasPusharyClaudeHooks = (settings) => JSON.stringify(settings.hooks ?? {}).includes("pushary-hook");
|
|
88
|
-
var hasPusharyMcp = (claudeJson2) => !!claudeJson2.mcpServers?.pushary;
|
|
89
|
-
var reapplyClaudeSettings = (apiKey, paths = {}) => {
|
|
90
|
-
const settingsPath = paths.settingsPath ?? CLAUDE_SETTINGS;
|
|
91
|
-
const claudeJsonPath = paths.claudeJsonPath ?? CLAUDE_JSON;
|
|
92
|
-
const settings = readJson(settingsPath);
|
|
93
|
-
const claudeJson2 = readJson(claudeJsonPath);
|
|
94
|
-
const configured = settings != null && hasPusharyClaudeHooks(settings) || claudeJson2 != null && hasPusharyMcp(claudeJson2);
|
|
95
|
-
if (!configured) return { reapplied: false, hooks: false, mcp: false };
|
|
96
|
-
const settingsWritable = settings != null;
|
|
97
|
-
const claudeJsonWritable = claudeJson2 != null;
|
|
98
|
-
let hooks = false;
|
|
99
|
-
let mcp = false;
|
|
100
|
-
try {
|
|
101
|
-
if (!settingsWritable) throw new Error("settings.json could not be parsed");
|
|
102
|
-
const s = settings;
|
|
103
|
-
addPusharyToolPermissions(s);
|
|
104
|
-
addPusharyHooks(s, resolveGlobalBinDir("pushary-hook"), detectClaudeVersion());
|
|
105
|
-
writeJson(settingsPath, s);
|
|
106
|
-
hooks = true;
|
|
107
|
-
} catch {
|
|
108
|
-
}
|
|
109
|
-
if (apiKey) {
|
|
110
|
-
try {
|
|
111
|
-
if (!claudeJsonWritable) throw new Error(".claude.json could not be parsed");
|
|
112
|
-
const cj = claudeJson2;
|
|
113
|
-
addClaudeMcpServer(cj, apiKey);
|
|
114
|
-
writeJson(claudeJsonPath, cj);
|
|
115
|
-
mcp = true;
|
|
116
|
-
} catch {
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
return { reapplied: hooks || mcp, hooks, mcp };
|
|
120
|
-
};
|
|
121
|
-
var readToml = (filePath) => {
|
|
122
|
-
try {
|
|
123
|
-
const raw = readFileSync(filePath, "utf-8");
|
|
124
|
-
return raw.trim() === "" ? {} : parseTOML(raw);
|
|
125
|
-
} catch {
|
|
126
|
-
return null;
|
|
127
|
-
}
|
|
128
|
-
};
|
|
129
|
-
var reapplyCodexSettings = (apiKey, paths = {}) => {
|
|
130
|
-
const configPath = paths.configPath ?? codexConfigToml();
|
|
131
|
-
const hooksPath = paths.hooksPath ?? codexHooksJson();
|
|
132
|
-
const config = readToml(configPath);
|
|
133
|
-
const hooksConfig = readJson(hooksPath);
|
|
134
|
-
const configured = config != null && !!config.mcp_servers?.pushary || hooksConfig != null && hasCodexHooks(hooksConfig);
|
|
135
|
-
if (!configured) return { reapplied: false, hooks: false, mcp: false };
|
|
136
|
-
const command = guardBinary(resolveGlobalBinary(CODEX_HOOK_BINARY) ?? CODEX_HOOK_BINARY);
|
|
137
|
-
let hooks = false;
|
|
138
|
-
let mcp = false;
|
|
139
|
-
if (hooksConfig != null) {
|
|
140
|
-
try {
|
|
141
|
-
addCodexHooks(hooksConfig, command);
|
|
142
|
-
writeJson(hooksPath, hooksConfig);
|
|
143
|
-
hooks = true;
|
|
144
|
-
} catch {
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
if (config != null) {
|
|
148
|
-
try {
|
|
149
|
-
if (hooks) addCodexHookTrust(config, hooksPath, command, codexHookPositions(hooksConfig ?? void 0));
|
|
150
|
-
if (apiKey) {
|
|
151
|
-
addCodexMcpServer(config, apiKey);
|
|
152
|
-
mcp = true;
|
|
153
|
-
}
|
|
154
|
-
if (hooks || apiKey) writeFileSync(configPath, stringifyTOML(config), "utf-8");
|
|
155
|
-
} catch {
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
return { reapplied: hooks || mcp, hooks, mcp };
|
|
159
|
-
};
|
|
160
|
-
var reapplyGeminiSettings = (apiKey, paths = {}) => {
|
|
161
|
-
const settingsPath = paths.settingsPath ?? join(homedir(), ".gemini", "settings.json");
|
|
162
|
-
const settings = readJson(settingsPath);
|
|
163
|
-
if (settings == null) return { reapplied: false, hooks: false, mcp: false };
|
|
164
|
-
const configured = hasGeminiHooks(settings) || !!settings.mcpServers?.pushary;
|
|
165
|
-
if (!configured) return { reapplied: false, hooks: false, mcp: false };
|
|
166
|
-
let hooks = false;
|
|
167
|
-
let mcp = false;
|
|
168
|
-
try {
|
|
169
|
-
addGeminiHooks(settings, guardBinary(resolveGlobalBinary(GEMINI_HOOK_BINARY) ?? GEMINI_HOOK_BINARY));
|
|
170
|
-
hooks = true;
|
|
171
|
-
if (apiKey) {
|
|
172
|
-
addGeminiMcpServer(settings, apiKey);
|
|
173
|
-
mcp = true;
|
|
174
|
-
}
|
|
175
|
-
writeJson(settingsPath, settings);
|
|
176
|
-
} catch {
|
|
177
|
-
}
|
|
178
|
-
return { reapplied: hooks || mcp, hooks, mcp };
|
|
179
|
-
};
|
|
180
|
-
var reapplyPluginMcp = (mcpPath, apiKey) => {
|
|
181
|
-
if (!apiKey) return { reapplied: false, hooks: false, mcp: false };
|
|
182
|
-
const mcpConfig = readJson(mcpPath);
|
|
183
|
-
if (mcpConfig == null) return { reapplied: false, hooks: false, mcp: false };
|
|
184
|
-
const servers = mcpConfig.mcpServers;
|
|
185
|
-
if (!servers?.pushary) return { reapplied: false, hooks: false, mcp: false };
|
|
186
|
-
try {
|
|
187
|
-
addClaudeMcpServer(mcpConfig, apiKey);
|
|
188
|
-
writeJson(mcpPath, mcpConfig);
|
|
189
|
-
return { reapplied: true, hooks: false, mcp: true };
|
|
190
|
-
} catch {
|
|
191
|
-
return { reapplied: false, hooks: false, mcp: false };
|
|
192
|
-
}
|
|
193
|
-
};
|
|
194
|
-
var reapplyCursorPlugin = (apiKey, paths = {}) => reapplyPluginMcp(
|
|
195
|
-
paths.pluginMcpPath ?? join(homedir(), ".cursor", "plugins", "local", "pushary", "mcp.json"),
|
|
196
|
-
apiKey
|
|
197
|
-
);
|
|
198
|
-
var reapplyVsCodePlugin = (apiKey, paths = {}) => reapplyPluginMcp(paths.pluginMcpPath ?? vscodePluginMcp(), apiKey);
|
|
199
|
-
var reapplyAllAgents = (apiKey) => {
|
|
200
|
-
const runners = [
|
|
201
|
-
{ label: "Claude Code", run: () => reapplyClaudeSettings(apiKey) },
|
|
202
|
-
{ label: "Codex", run: () => reapplyCodexSettings(apiKey) },
|
|
203
|
-
{ label: "Gemini CLI", run: () => reapplyGeminiSettings(apiKey) },
|
|
204
|
-
{ label: "Cursor", run: () => reapplyCursorPlugin(apiKey) },
|
|
205
|
-
{ label: "VS Code", run: () => reapplyVsCodePlugin(apiKey) }
|
|
206
|
-
];
|
|
207
|
-
const done = [];
|
|
208
|
-
for (const runner of runners) {
|
|
209
|
-
try {
|
|
210
|
-
const result = runner.run();
|
|
211
|
-
if (result.reapplied) done.push({ label: runner.label, result });
|
|
212
|
-
} catch {
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
return done;
|
|
216
|
-
};
|
|
217
|
-
|
|
218
|
-
// bin/pushary-upgrade.ts
|
|
62
|
+
import { join } from "path";
|
|
63
|
+
import { execFileSync } from "child_process";
|
|
219
64
|
exitOnHelpFlag("upgrade");
|
|
220
65
|
var detectInstallModes = () => {
|
|
221
66
|
const candidates = [
|
|
222
67
|
{
|
|
223
68
|
label: "Cursor plugin",
|
|
224
69
|
upgrade: "updates itself through Cursor",
|
|
225
|
-
present:
|
|
70
|
+
present: existsSync(cursorPluginDir())
|
|
226
71
|
},
|
|
227
72
|
{
|
|
228
73
|
label: "VS Code plugin",
|
|
229
74
|
upgrade: "npx @pushary/agent-hooks@latest setup --agents vscode",
|
|
230
|
-
present:
|
|
75
|
+
present: existsSync(vscodePluginDir())
|
|
231
76
|
},
|
|
232
77
|
{
|
|
233
78
|
label: "Codex config",
|
|
234
79
|
upgrade: "npx @pushary/agent-hooks@latest setup --agents codex",
|
|
235
|
-
present:
|
|
80
|
+
present: existsSync(codexConfigToml())
|
|
236
81
|
},
|
|
237
82
|
{
|
|
238
83
|
label: "Claude Code config",
|
|
239
84
|
upgrade: "npx @pushary/agent-hooks@latest setup --agents claude_code",
|
|
240
|
-
present:
|
|
85
|
+
present: existsSync(claudeJson())
|
|
241
86
|
},
|
|
242
87
|
{
|
|
243
88
|
label: "Gemini config",
|
|
244
89
|
upgrade: "npx @pushary/agent-hooks@latest setup --agents gemini_cli",
|
|
245
|
-
present:
|
|
90
|
+
present: existsSync(geminiSettings())
|
|
246
91
|
},
|
|
247
92
|
{
|
|
248
93
|
label: "Hermes plugin (pip)",
|
|
249
94
|
upgrade: "npx @pushary/agent-hooks@latest setup --agents hermes",
|
|
250
|
-
present:
|
|
95
|
+
present: existsSync(join(homedir(), ".hermes"))
|
|
251
96
|
}
|
|
252
97
|
];
|
|
253
98
|
return candidates.filter((candidate) => candidate.present).map(({ label, upgrade }) => ({ label, upgrade }));
|
|
@@ -278,13 +123,37 @@ var finishUpgrade = async () => {
|
|
|
278
123
|
} catch {
|
|
279
124
|
apiKey = void 0;
|
|
280
125
|
}
|
|
281
|
-
const
|
|
126
|
+
const inspectedAgents = reapplyAllAgents(apiKey);
|
|
127
|
+
const refreshed = inspectedAgents.filter((agent) => agent.result.reapplied);
|
|
128
|
+
const configuredControlProviders = inspectedAgents.filter((agent) => agent.result.configured && (agent.id === "claude" || agent.id === "codex" || agent.id === "gemini")).map((agent) => agent.id);
|
|
129
|
+
const controlMode = readControlMode();
|
|
130
|
+
const daemonStatus = readDaemonStatus();
|
|
131
|
+
const serviceWasPresent = daemonStatus.kind !== "absent" || hasDaemonServiceDefinition();
|
|
132
|
+
const controlPolicy = resolveControlPolicy({
|
|
133
|
+
mode: controlMode,
|
|
134
|
+
providerAvailable: hasSpawnProvider(detectProviderLiveCapabilities(configuredControlProviders)),
|
|
135
|
+
managerAvailable: daemonServiceManagerAvailable(),
|
|
136
|
+
servicePresent: serviceWasPresent
|
|
137
|
+
});
|
|
282
138
|
let daemonReady = true;
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
139
|
+
let legacyStopFailure = null;
|
|
140
|
+
if (controlPolicy === "disabled" && serviceWasPresent) {
|
|
141
|
+
daemonReady = (await disableDaemonService()).kind === "ok";
|
|
142
|
+
} else if (controlPolicy === "legacy") {
|
|
143
|
+
const stopped = await stopDaemonService();
|
|
144
|
+
legacyStopFailure = stopped.kind === "ok" ? null : stopped.detail;
|
|
145
|
+
daemonReady = false;
|
|
146
|
+
} else if (controlPolicy === "enabled") {
|
|
147
|
+
if (!apiKey) {
|
|
148
|
+
daemonReady = false;
|
|
149
|
+
} else {
|
|
150
|
+
const service = await replaceDaemonService();
|
|
151
|
+
const daemon = service.kind === "ok" ? await ensureDaemonRunning({ spawnDaemon: () => {
|
|
152
|
+
} }) : null;
|
|
153
|
+
daemonReady = service.kind === "ok" && (daemon?.kind === "running" || daemon?.kind === "started");
|
|
154
|
+
}
|
|
155
|
+
} else if (controlMode === "on" && controlPolicy === "unsupported") {
|
|
156
|
+
daemonReady = false;
|
|
288
157
|
}
|
|
289
158
|
console.log();
|
|
290
159
|
if (refreshed.length > 0) {
|
|
@@ -302,11 +171,11 @@ var finishUpgrade = async () => {
|
|
|
302
171
|
}
|
|
303
172
|
console.log();
|
|
304
173
|
if (!daemonReady) {
|
|
305
|
-
console.error("Upgrade installed, but the background service did not start. Run: pushary daemon install");
|
|
174
|
+
console.error(controlPolicy === "disabled" ? "Upgrade installed, but the disabled background service could not be fully removed. Re-run setup with --control off." : controlPolicy === "legacy" ? legacyStopFailure ? `Upgrade installed, but the legacy background service could not be stopped: ${legacyStopFailure}. Run setup with --control off.` : "Upgrade installed and the legacy background service was stopped, but it cannot be safely adopted. Run setup with --control off, or restore its provider and native service manager." : controlPolicy === "enabled" && !apiKey ? "Upgrade installed, but phone-start could not be reconciled because no API key was readable. Re-run setup." : "Upgrade installed, but the background service did not start. Run: pushary daemon install");
|
|
306
175
|
process.exitCode = 1;
|
|
307
176
|
return;
|
|
308
177
|
}
|
|
309
|
-
console.log("Done. Your hooks and background service use the new global install.");
|
|
178
|
+
console.log(controlPolicy === "disabled" ? "Done. Your hooks use the new global install; phone-start remains disabled." : controlPolicy === "unsupported" || controlPolicy === "preserve-absent" ? "Done. Your hooks use the new global install; no background service was added." : "Done. Your hooks and background service use the new global install.");
|
|
310
179
|
console.log("Verify with: pushary doctor");
|
|
311
180
|
};
|
|
312
181
|
var main = async () => {
|