@wbern/cc-ping 1.5.0 → 1.5.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.
Files changed (2) hide show
  1. package/dist/cli.js +39 -16
  2. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -701,6 +701,7 @@ __export(daemon_exports, {
701
701
  daemonStopPath: () => daemonStopPath,
702
702
  getDaemonStatus: () => getDaemonStatus,
703
703
  isProcessRunning: () => isProcessRunning,
704
+ msUntilUtcHour: () => msUntilUtcHour,
704
705
  parseInterval: () => parseInterval,
705
706
  readDaemonState: () => readDaemonState,
706
707
  removeDaemonState: () => removeDaemonState,
@@ -824,6 +825,12 @@ function formatUptime(ms) {
824
825
  if (minutes > 0) return `${minutes}m ${seconds}s`;
825
826
  return `${seconds}s`;
826
827
  }
828
+ function msUntilUtcHour(targetHour, now) {
829
+ const currentMs = now.getUTCHours() * 36e5 + now.getUTCMinutes() * 6e4 + now.getUTCSeconds() * 1e3 + now.getUTCMilliseconds();
830
+ const targetMs = targetHour * 36e5;
831
+ const diff = targetMs - currentMs;
832
+ return diff > 0 ? diff : diff + 24 * 36e5;
833
+ }
827
834
  async function daemonLoop(intervalMs, options, deps) {
828
835
  let wakeDelayMs;
829
836
  while (!deps.shouldStop()) {
@@ -837,23 +844,28 @@ async function daemonLoop(intervalMs, options, deps) {
837
844
  if (skipped > 0) {
838
845
  deps.log(`Skipping ${skipped} account(s) with active window`);
839
846
  }
847
+ let soonestDeferHour;
840
848
  if (deps.shouldDeferPing) {
841
849
  const deferResults = /* @__PURE__ */ new Map();
842
850
  for (const a of accounts) {
843
- deferResults.set(
844
- a.handle,
845
- deps.shouldDeferPing(a.handle, a.configDir).defer
846
- );
851
+ deferResults.set(a.handle, deps.shouldDeferPing(a.handle, a.configDir));
847
852
  }
848
- const deferredCount = [...deferResults.values()].filter(Boolean).length;
849
- if (deferredCount > 0) {
850
- accounts = accounts.filter((a) => !deferResults.get(a.handle));
851
- deps.log(`Deferring ${deferredCount} account(s) (smart scheduling)`);
853
+ const deferred = [...deferResults.entries()].filter(([, r]) => r.defer);
854
+ if (deferred.length > 0) {
855
+ accounts = accounts.filter((a) => !deferResults.get(a.handle)?.defer);
856
+ deps.log(`Deferring ${deferred.length} account(s) (smart scheduling)`);
857
+ for (const [, r] of deferred) {
858
+ if (r.deferUntilUtcHour !== void 0 && (soonestDeferHour === void 0 || /* c8 ignore next -- production default */
859
+ msUntilUtcHour(r.deferUntilUtcHour, deps.now?.() ?? /* @__PURE__ */ new Date()) < /* c8 ignore next -- production default */
860
+ msUntilUtcHour(soonestDeferHour, deps.now?.() ?? /* @__PURE__ */ new Date()))) {
861
+ soonestDeferHour = r.deferUntilUtcHour;
862
+ }
863
+ }
852
864
  }
853
865
  }
854
866
  if (accounts.length === 0) {
855
867
  deps.log(
856
- allAccounts.length === 0 ? "No accounts configured, waiting..." : "All accounts have active windows, waiting..."
868
+ allAccounts.length === 0 ? "No accounts configured, waiting..." : soonestDeferHour !== void 0 ? "All accounts deferred (smart scheduling), waiting..." : "All accounts have active windows, waiting..."
857
869
  );
858
870
  } else {
859
871
  deps.log(
@@ -882,9 +894,20 @@ async function daemonLoop(intervalMs, options, deps) {
882
894
  deps.updateState?.({ lastPingAt: (/* @__PURE__ */ new Date()).toISOString() });
883
895
  }
884
896
  if (deps.shouldStop()) break;
885
- deps.log(`Sleeping ${Math.round(intervalMs / 6e4)}m until next ping...`);
897
+ let sleepMs = intervalMs;
898
+ if (soonestDeferHour !== void 0) {
899
+ const msUntilDefer = msUntilUtcHour(
900
+ soonestDeferHour,
901
+ /* c8 ignore next -- production default */
902
+ deps.now?.() ?? /* @__PURE__ */ new Date()
903
+ );
904
+ if (msUntilDefer > 0 && msUntilDefer < intervalMs) {
905
+ sleepMs = msUntilDefer;
906
+ }
907
+ }
908
+ deps.log(`Sleeping ${Math.round(sleepMs / 6e4)}m until next ping...`);
886
909
  const sleepStart = Date.now();
887
- await deps.sleep(intervalMs);
910
+ await deps.sleep(sleepMs);
888
911
  const overshootMs = Date.now() - sleepStart - intervalMs;
889
912
  if (overshootMs > 6e4) {
890
913
  wakeDelayMs = overshootMs;
@@ -1893,7 +1916,7 @@ function suggestAccount(accounts, now = /* @__PURE__ */ new Date()) {
1893
1916
  }
1894
1917
 
1895
1918
  // src/cli.ts
1896
- var program = new Command().name("cc-ping").description("Ping Claude Code sessions to trigger quota windows early").version("1.5.0").option(
1919
+ var program = new Command().name("cc-ping").description("Ping Claude Code sessions to trigger quota windows early").version("1.5.1").option(
1897
1920
  "--config <path>",
1898
1921
  "Path to config directory (default: ~/.config/cc-ping, env: CC_PING_CONFIG)"
1899
1922
  ).hook("preAction", (thisCommand) => {
@@ -2114,7 +2137,7 @@ daemon.command("start").description("Start the daemon process").option(
2114
2137
  bell: opts.bell,
2115
2138
  notify: opts.notify,
2116
2139
  smartSchedule,
2117
- version: "1.5.0"
2140
+ version: "1.5.1"
2118
2141
  });
2119
2142
  if (!result.success) {
2120
2143
  console.error(result.error);
@@ -2148,7 +2171,7 @@ daemon.command("stop").description("Stop the daemon process").action(async () =>
2148
2171
  daemon.command("status").description("Show daemon status").option("--json", "Output as JSON", false).action(async (opts) => {
2149
2172
  const { getServiceStatus: getServiceStatus2 } = await Promise.resolve().then(() => (init_service(), service_exports));
2150
2173
  const svc = getServiceStatus2();
2151
- const status = getDaemonStatus({ currentVersion: "1.5.0" });
2174
+ const status = getDaemonStatus({ currentVersion: "1.5.1" });
2152
2175
  if (opts.json) {
2153
2176
  const serviceInfo = svc.installed ? {
2154
2177
  service: {
@@ -2202,7 +2225,7 @@ daemon.command("status").description("Show daemon status").option("--json", "Out
2202
2225
  }
2203
2226
  if (status.versionMismatch) {
2204
2227
  console.log(
2205
- ` Warning: daemon is running v${status.daemonVersion} but v${"1.5.0"} is installed.`
2228
+ ` Warning: daemon is running v${status.daemonVersion} but v${"1.5.1"} is installed.`
2206
2229
  );
2207
2230
  console.log(
2208
2231
  " Restart to pick up the new version: cc-ping daemon stop && cc-ping daemon start"
@@ -2265,7 +2288,7 @@ daemon.command("_run", { hidden: true }).option("--interval-ms <ms>", "Ping inte
2265
2288
  startedAt: (/* @__PURE__ */ new Date()).toISOString(),
2266
2289
  intervalMs,
2267
2290
  configDir: resolveConfigDir2(),
2268
- version: "1.5.0"
2291
+ version: "1.5.1"
2269
2292
  });
2270
2293
  }
2271
2294
  await runDaemonWithDefaults(intervalMs, {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wbern/cc-ping",
3
- "version": "1.5.0",
3
+ "version": "1.5.1",
4
4
  "description": "Ping Claude Code sessions to trigger quota windows early across multiple accounts",
5
5
  "type": "module",
6
6
  "bin": {