@wbern/cc-ping 1.7.0 → 1.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/cli.js +60 -29
  2. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -701,6 +701,7 @@ __export(daemon_exports, {
701
701
  daemonPidPath: () => daemonPidPath,
702
702
  daemonStopPath: () => daemonStopPath,
703
703
  getDaemonStatus: () => getDaemonStatus,
704
+ hasVersionChanged: () => hasVersionChanged,
704
705
  isProcessRunning: () => isProcessRunning,
705
706
  msUntilUtcHour: () => msUntilUtcHour,
706
707
  parseInterval: () => parseInterval,
@@ -712,15 +713,13 @@ __export(daemon_exports, {
712
713
  stopDaemon: () => stopDaemon,
713
714
  writeDaemonState: () => writeDaemonState
714
715
  });
715
- import { execSync, spawn } from "child_process";
716
+ import { execFileSync, execSync, spawn } from "child_process";
716
717
  import {
717
718
  existsSync as existsSync6,
718
719
  closeSync as fsCloseSync,
719
720
  openSync as fsOpenSync,
720
721
  mkdirSync as mkdirSync4,
721
722
  readFileSync as readFileSync6,
722
- realpathSync,
723
- statSync as statSync2,
724
723
  unlinkSync,
725
724
  writeFileSync as writeFileSync3
726
725
  } from "fs";
@@ -832,6 +831,14 @@ function msUntilUtcHour(targetHour, now) {
832
831
  const diff = targetMs - currentMs;
833
832
  return diff > 0 ? diff : diff + 24 * 36e5;
834
833
  }
834
+ function hasVersionChanged(runningVersion, getInstalledVersion) {
835
+ if (!runningVersion) return false;
836
+ try {
837
+ return getInstalledVersion() !== runningVersion;
838
+ } catch {
839
+ return false;
840
+ }
841
+ }
835
842
  async function daemonLoop(intervalMs, options, deps) {
836
843
  let wakeDelayMs;
837
844
  while (!deps.shouldStop()) {
@@ -1100,8 +1107,28 @@ async function runDaemonWithDefaults(intervalMs, options) {
1100
1107
  return shouldDefer2(/* @__PURE__ */ new Date(), schedule.optimalPingHour);
1101
1108
  };
1102
1109
  }
1103
- const binaryPath = realpathSync(process.argv[1]);
1104
- const startMtimeMs = statSync2(binaryPath).mtimeMs;
1110
+ let hasUpgraded;
1111
+ if (options.autoUpdate) {
1112
+ let ccPingBin = process.env.CC_PING_BIN;
1113
+ if (!ccPingBin) {
1114
+ try {
1115
+ ccPingBin = execSync("which cc-ping", {
1116
+ encoding: "utf-8",
1117
+ timeout: 5e3
1118
+ }).trim();
1119
+ } catch {
1120
+ console.log(
1121
+ "Auto-update: cc-ping not found in PATH, version checks disabled"
1122
+ );
1123
+ }
1124
+ }
1125
+ if (ccPingBin) {
1126
+ hasUpgraded = () => hasVersionChanged(
1127
+ readDaemonState()?.version,
1128
+ () => execFileSync(ccPingBin, ["--version"], { timeout: 5e3 }).toString().trim()
1129
+ );
1130
+ }
1131
+ }
1105
1132
  await runDaemon(intervalMs, options, {
1106
1133
  runPing: runPing2,
1107
1134
  listAccounts: listAccounts2,
@@ -1110,13 +1137,7 @@ async function runDaemonWithDefaults(intervalMs, options) {
1110
1137
  log: (msg) => console.log(msg),
1111
1138
  isWindowActive: (handle) => getWindowReset2(handle) !== null,
1112
1139
  shouldDeferPing,
1113
- hasUpgraded: () => {
1114
- try {
1115
- return statSync2(binaryPath).mtimeMs !== startMtimeMs;
1116
- } catch {
1117
- return false;
1118
- }
1119
- },
1140
+ hasUpgraded,
1120
1141
  updateState: (patch) => {
1121
1142
  const current = readDaemonState();
1122
1143
  if (current) writeDaemonState({ ...current, ...patch });
@@ -1188,19 +1209,26 @@ function generateLaunchdPlist(options, execInfo, configDir) {
1188
1209
  if (options.notify) programArgs.push("--notify");
1189
1210
  if (options.smartSchedule === false)
1190
1211
  programArgs.push("--smart-schedule", "off");
1212
+ programArgs.push("--auto-update");
1191
1213
  const allArgs = [execInfo.executable, ...programArgs];
1192
1214
  const argsXml = allArgs.map((a) => ` <string>${escapeXml(a)}</string>`).join("\n");
1193
1215
  const logPath = join10(
1194
1216
  configDir || join10(nodeHomedir(), ".config", "cc-ping"),
1195
1217
  "daemon.log"
1196
1218
  );
1219
+ const envVars = {};
1220
+ if (configDir) envVars.CC_PING_CONFIG = configDir;
1221
+ if (execInfo.args.length === 0) envVars.CC_PING_BIN = execInfo.executable;
1197
1222
  let envSection = "";
1198
- if (configDir) {
1223
+ if (Object.keys(envVars).length > 0) {
1224
+ const entries = Object.entries(envVars).map(
1225
+ ([k, v]) => ` <key>${escapeXml(k)}</key>
1226
+ <string>${escapeXml(v)}</string>`
1227
+ ).join("\n");
1199
1228
  envSection = `
1200
1229
  <key>EnvironmentVariables</key>
1201
1230
  <dict>
1202
- <key>CC_PING_CONFIG</key>
1203
- <string>${escapeXml(configDir)}</string>
1231
+ ${entries}
1204
1232
  </dict>`;
1205
1233
  }
1206
1234
  return `<?xml version="1.0" encoding="UTF-8"?>
@@ -1242,12 +1270,14 @@ function generateSystemdUnit(options, execInfo, configDir) {
1242
1270
  if (options.notify) programArgs.push("--notify");
1243
1271
  if (options.smartSchedule === false)
1244
1272
  programArgs.push("--smart-schedule", "off");
1273
+ programArgs.push("--auto-update");
1245
1274
  const execStart = [execInfo.executable, ...programArgs].map((a) => a.includes(" ") ? `"${a}"` : a).join(" ");
1246
- let envLine = "";
1247
- if (configDir) {
1248
- envLine = `
1249
- Environment=CC_PING_CONFIG=${configDir}`;
1250
- }
1275
+ const envPairs = [];
1276
+ if (configDir) envPairs.push(`CC_PING_CONFIG=${configDir}`);
1277
+ if (execInfo.args.length === 0)
1278
+ envPairs.push(`CC_PING_BIN=${execInfo.executable}`);
1279
+ const envLine = envPairs.map((p) => `
1280
+ Environment=${p}`).join("");
1251
1281
  return `[Unit]
1252
1282
  Description=cc-ping daemon - auto-ping Claude Code sessions
1253
1283
 
@@ -1891,7 +1921,7 @@ init_paths();
1891
1921
  init_run_ping();
1892
1922
 
1893
1923
  // src/scan.ts
1894
- import { existsSync as existsSync7, readdirSync, statSync as statSync3 } from "fs";
1924
+ import { existsSync as existsSync7, readdirSync, statSync as statSync2 } from "fs";
1895
1925
  import { homedir as homedir2 } from "os";
1896
1926
  import { join as join9 } from "path";
1897
1927
  function scanAccounts(dir) {
@@ -1899,7 +1929,7 @@ function scanAccounts(dir) {
1899
1929
  if (!existsSync7(accountsDir)) return [];
1900
1930
  return readdirSync(accountsDir).filter((name) => {
1901
1931
  const full = join9(accountsDir, name);
1902
- return statSync3(full).isDirectory() && !name.startsWith(".") && existsSync7(join9(full, ".claude.json"));
1932
+ return statSync2(full).isDirectory() && !name.startsWith(".") && existsSync7(join9(full, ".claude.json"));
1903
1933
  }).map((name) => ({
1904
1934
  handle: name,
1905
1935
  configDir: join9(accountsDir, name)
@@ -1971,7 +2001,7 @@ function getDeferredHandles() {
1971
2001
  }
1972
2002
  return deferred;
1973
2003
  }
1974
- var program = new Command().name("cc-ping").description("Ping Claude Code sessions to trigger quota windows early").version("1.7.0").option(
2004
+ var program = new Command().name("cc-ping").description("Ping Claude Code sessions to trigger quota windows early").version("1.9.0").option(
1975
2005
  "--config <path>",
1976
2006
  "Path to config directory (default: ~/.config/cc-ping, env: CC_PING_CONFIG)"
1977
2007
  ).hook("preAction", (thisCommand) => {
@@ -2198,7 +2228,7 @@ daemon.command("start").description("Start the daemon process").option(
2198
2228
  bell: opts.bell,
2199
2229
  notify: opts.notify,
2200
2230
  smartSchedule,
2201
- version: "1.7.0"
2231
+ version: "1.9.0"
2202
2232
  });
2203
2233
  if (!result.success) {
2204
2234
  console.error(result.error);
@@ -2232,7 +2262,7 @@ daemon.command("stop").description("Stop the daemon process").action(async () =>
2232
2262
  daemon.command("status").description("Show daemon status").option("--json", "Output as JSON", false).action(async (opts) => {
2233
2263
  const { getServiceStatus: getServiceStatus2 } = await Promise.resolve().then(() => (init_service(), service_exports));
2234
2264
  const svc = getServiceStatus2();
2235
- const status = getDaemonStatus({ currentVersion: "1.7.0" });
2265
+ const status = getDaemonStatus({ currentVersion: "1.9.0" });
2236
2266
  if (opts.json) {
2237
2267
  const serviceInfo = svc.installed ? {
2238
2268
  service: {
@@ -2293,7 +2323,7 @@ daemon.command("status").description("Show daemon status").option("--json", "Out
2293
2323
  if (status.versionMismatch) {
2294
2324
  console.log(
2295
2325
  yellow(
2296
- ` Warning: daemon is running v${status.daemonVersion} but v${"1.7.0"} is installed.`
2326
+ ` Warning: daemon is running v${status.daemonVersion} but v${"1.9.0"} is installed.`
2297
2327
  )
2298
2328
  );
2299
2329
  console.log(
@@ -2342,7 +2372,7 @@ daemon.command("uninstall").description("Remove daemon system service").action(a
2342
2372
  }
2343
2373
  console.log(`Service removed: ${result.servicePath}`);
2344
2374
  });
2345
- daemon.command("_run", { hidden: true }).option("--interval-ms <ms>", "Ping interval in milliseconds").option("-q, --quiet", "Suppress ping output", false).option("--bell", "Ring terminal bell on ping failure", false).option("--notify", "Send desktop notification on ping failure", false).option("--smart-schedule <on|off>", "Smart scheduling (default: on)").action(async (opts) => {
2375
+ daemon.command("_run", { hidden: true }).option("--interval-ms <ms>", "Ping interval in milliseconds").option("-q, --quiet", "Suppress ping output", false).option("--bell", "Ring terminal bell on ping failure", false).option("--notify", "Send desktop notification on ping failure", false).option("--smart-schedule <on|off>", "Smart scheduling (default: on)").option("--auto-update", "Auto-restart on upgrade (for service installs)").action(async (opts) => {
2346
2376
  const intervalMs = Number(opts.intervalMs);
2347
2377
  if (!intervalMs || intervalMs <= 0) {
2348
2378
  console.error("Invalid --interval-ms");
@@ -2359,14 +2389,15 @@ daemon.command("_run", { hidden: true }).option("--interval-ms <ms>", "Ping inte
2359
2389
  startedAt: (/* @__PURE__ */ new Date()).toISOString(),
2360
2390
  intervalMs,
2361
2391
  configDir: resolveConfigDir2(),
2362
- version: "1.7.0"
2392
+ version: "1.9.0"
2363
2393
  });
2364
2394
  }
2365
2395
  await runDaemonWithDefaults(intervalMs, {
2366
2396
  quiet: opts.quiet,
2367
2397
  bell: opts.bell,
2368
2398
  notify: opts.notify,
2369
- smartSchedule
2399
+ smartSchedule,
2400
+ autoUpdate: opts.autoUpdate
2370
2401
  });
2371
2402
  });
2372
2403
  program.parse();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wbern/cc-ping",
3
- "version": "1.7.0",
3
+ "version": "1.9.0",
4
4
  "description": "Ping Claude Code sessions to trigger quota windows early across multiple accounts",
5
5
  "type": "module",
6
6
  "bin": {