@wbern/cc-ping 1.9.0 → 1.10.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.
- package/README.md +4 -0
- package/dist/cli.js +45 -20
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -5,6 +5,10 @@
|
|
|
5
5
|
[](https://github.com/wbern/cc-ping/actions/workflows/ci.yml)
|
|
6
6
|
[](https://opensource.org/licenses/MIT)
|
|
7
7
|
|
|
8
|
+
<p align="center">
|
|
9
|
+
<img src="docs/daemon-status.png" alt="cc-ping daemon status" width="520" />
|
|
10
|
+
</p>
|
|
11
|
+
|
|
8
12
|
**Ping Claude Code sessions to trigger quota windows early across multiple accounts.**
|
|
9
13
|
|
|
10
14
|
Claude Code has a 5-hour quota window that starts on your first message. If you rotate between accounts, your idle accounts sit there with full quota doing nothing. cc-ping pings them so their windows start ticking — when you need them, they've already reset.
|
package/dist/cli.js
CHANGED
|
@@ -1772,12 +1772,31 @@ function colorizeStatus(windowStatus) {
|
|
|
1772
1772
|
return yellow(windowStatus);
|
|
1773
1773
|
}
|
|
1774
1774
|
}
|
|
1775
|
-
function
|
|
1775
|
+
function censorHandle(handle) {
|
|
1776
|
+
const atIdx = handle.indexOf("@");
|
|
1777
|
+
if (atIdx !== -1) {
|
|
1778
|
+
const local = handle.slice(0, atIdx);
|
|
1779
|
+
const domain = handle.slice(atIdx + 1);
|
|
1780
|
+
return censorPart(local) + "@" + censorDomain(domain);
|
|
1781
|
+
}
|
|
1782
|
+
return censorDomain(handle);
|
|
1783
|
+
}
|
|
1784
|
+
function censorPart(part) {
|
|
1785
|
+
if (part.length <= 1) return part;
|
|
1786
|
+
return part[0] + "*".repeat(part.length - 1);
|
|
1787
|
+
}
|
|
1788
|
+
function censorDomain(domain) {
|
|
1789
|
+
const lastDot = domain.lastIndexOf(".");
|
|
1790
|
+
if (lastDot === -1) return censorPart(domain);
|
|
1791
|
+
const name = domain.slice(0, lastDot);
|
|
1792
|
+
const tld = domain.slice(lastDot);
|
|
1793
|
+
return censorPart(name) + tld;
|
|
1794
|
+
}
|
|
1795
|
+
function formatStatusLine(status, options) {
|
|
1776
1796
|
const lines = [];
|
|
1777
|
-
const
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
);
|
|
1797
|
+
const handle = options?.censor ? censorHandle(status.handle) : status.handle;
|
|
1798
|
+
const dup = status.duplicateOf ? ` [duplicate of ${options?.censor ? censorHandle(status.duplicateOf) : status.duplicateOf}]` : "";
|
|
1799
|
+
lines.push(` ${handle}: ${colorizeStatus(status.windowStatus)}${dup}`);
|
|
1781
1800
|
const ping = status.lastPing === null ? "never" : status.lastPing.replace("T", " ").replace(/\.\d+Z$/, "Z");
|
|
1782
1801
|
lines.push(` - last ping: ${ping}`);
|
|
1783
1802
|
if (status.timeUntilReset !== null) {
|
|
@@ -1832,7 +1851,7 @@ function getAccountStatuses(accounts, now = /* @__PURE__ */ new Date(), duplicat
|
|
|
1832
1851
|
};
|
|
1833
1852
|
});
|
|
1834
1853
|
}
|
|
1835
|
-
function printAccountTable(log = console.log, now = /* @__PURE__ */ new Date(), deferredHandles) {
|
|
1854
|
+
function printAccountTable(log = console.log, now = /* @__PURE__ */ new Date(), deferredHandles, options) {
|
|
1836
1855
|
const accounts = listAccounts();
|
|
1837
1856
|
if (accounts.length === 0) {
|
|
1838
1857
|
log("No accounts configured");
|
|
@@ -1841,12 +1860,12 @@ function printAccountTable(log = console.log, now = /* @__PURE__ */ new Date(),
|
|
|
1841
1860
|
const dupes = findDuplicates(accounts);
|
|
1842
1861
|
const statuses = getAccountStatuses(accounts, now, dupes, deferredHandles);
|
|
1843
1862
|
for (const s of statuses) {
|
|
1844
|
-
log(formatStatusLine(s));
|
|
1863
|
+
log(formatStatusLine(s, options));
|
|
1845
1864
|
}
|
|
1846
1865
|
}
|
|
1847
1866
|
|
|
1848
1867
|
// src/default-command.ts
|
|
1849
|
-
function showDefault(log = console.log, now = /* @__PURE__ */ new Date(), deferredHandles) {
|
|
1868
|
+
function showDefault(log = console.log, now = /* @__PURE__ */ new Date(), deferredHandles, options) {
|
|
1850
1869
|
const accounts = listAccounts();
|
|
1851
1870
|
if (accounts.length === 0) {
|
|
1852
1871
|
log("No accounts configured.");
|
|
@@ -1858,7 +1877,7 @@ function showDefault(log = console.log, now = /* @__PURE__ */ new Date(), deferr
|
|
|
1858
1877
|
const dupes = findDuplicates(accounts);
|
|
1859
1878
|
const statuses = getAccountStatuses(accounts, now, dupes, deferredHandles);
|
|
1860
1879
|
for (const s of statuses) {
|
|
1861
|
-
log(formatStatusLine(s));
|
|
1880
|
+
log(formatStatusLine(s, options));
|
|
1862
1881
|
}
|
|
1863
1882
|
const needsPing = statuses.filter((s) => s.windowStatus !== "active");
|
|
1864
1883
|
if (needsPing.length > 0) {
|
|
@@ -2001,7 +2020,7 @@ function getDeferredHandles() {
|
|
|
2001
2020
|
}
|
|
2002
2021
|
return deferred;
|
|
2003
2022
|
}
|
|
2004
|
-
var program = new Command().name("cc-ping").description("Ping Claude Code sessions to trigger quota windows early").version("1.
|
|
2023
|
+
var program = new Command().name("cc-ping").description("Ping Claude Code sessions to trigger quota windows early").version("1.10.1").option(
|
|
2005
2024
|
"--config <path>",
|
|
2006
2025
|
"Path to config directory (default: ~/.config/cc-ping, env: CC_PING_CONFIG)"
|
|
2007
2026
|
).hook("preAction", (thisCommand) => {
|
|
@@ -2123,7 +2142,7 @@ program.command("list").description("List configured accounts").option("--json",
|
|
|
2123
2142
|
console.log(` ${a.handle} -> ${a.configDir}`);
|
|
2124
2143
|
}
|
|
2125
2144
|
});
|
|
2126
|
-
program.command("status").description("Show status of all accounts with window information").option("--json", "Output as JSON", false).action((opts) => {
|
|
2145
|
+
program.command("status").description("Show status of all accounts with window information").option("--json", "Output as JSON", false).option("--censor", "Mask account handles in output (for screenshots)").action((opts) => {
|
|
2127
2146
|
const deferred = getDeferredHandles();
|
|
2128
2147
|
if (opts.json) {
|
|
2129
2148
|
const accounts = listAccounts();
|
|
@@ -2137,7 +2156,9 @@ program.command("status").description("Show status of all accounts with window i
|
|
|
2137
2156
|
console.log(JSON.stringify(statuses, null, 2));
|
|
2138
2157
|
return;
|
|
2139
2158
|
}
|
|
2140
|
-
printAccountTable(console.log, /* @__PURE__ */ new Date(), deferred
|
|
2159
|
+
printAccountTable(console.log, /* @__PURE__ */ new Date(), deferred, {
|
|
2160
|
+
censor: opts.censor
|
|
2161
|
+
});
|
|
2141
2162
|
});
|
|
2142
2163
|
program.command("next-reset").description("Show which account has its quota window resetting soonest").option("--json", "Output as JSON", false).action((opts) => {
|
|
2143
2164
|
const accounts = listAccounts();
|
|
@@ -2217,7 +2238,7 @@ daemon.command("start").description("Start the daemon process").option(
|
|
|
2217
2238
|
).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(
|
|
2218
2239
|
"--smart-schedule <on|off>",
|
|
2219
2240
|
"Time pings based on usage patterns (default: on)"
|
|
2220
|
-
).action(async (opts) => {
|
|
2241
|
+
).option("--censor", "Mask account handles in output (for screenshots)").action(async (opts) => {
|
|
2221
2242
|
let smartSchedule;
|
|
2222
2243
|
if (opts.smartSchedule !== void 0) {
|
|
2223
2244
|
smartSchedule = parseSmartSchedule(opts.smartSchedule);
|
|
@@ -2228,7 +2249,7 @@ daemon.command("start").description("Start the daemon process").option(
|
|
|
2228
2249
|
bell: opts.bell,
|
|
2229
2250
|
notify: opts.notify,
|
|
2230
2251
|
smartSchedule,
|
|
2231
|
-
version: "1.
|
|
2252
|
+
version: "1.10.1"
|
|
2232
2253
|
});
|
|
2233
2254
|
if (!result.success) {
|
|
2234
2255
|
console.error(result.error);
|
|
@@ -2242,7 +2263,9 @@ daemon.command("start").description("Start the daemon process").option(
|
|
|
2242
2263
|
"Hint: won't survive a reboot. Use `cc-ping daemon install` for a persistent service."
|
|
2243
2264
|
);
|
|
2244
2265
|
}
|
|
2245
|
-
printAccountTable(console.log, /* @__PURE__ */ new Date(), getDeferredHandles()
|
|
2266
|
+
printAccountTable(console.log, /* @__PURE__ */ new Date(), getDeferredHandles(), {
|
|
2267
|
+
censor: opts.censor
|
|
2268
|
+
});
|
|
2246
2269
|
});
|
|
2247
2270
|
daemon.command("stop").description("Stop the daemon process").action(async () => {
|
|
2248
2271
|
const result = await stopDaemon();
|
|
@@ -2259,10 +2282,10 @@ daemon.command("stop").description("Stop the daemon process").action(async () =>
|
|
|
2259
2282
|
);
|
|
2260
2283
|
}
|
|
2261
2284
|
});
|
|
2262
|
-
daemon.command("status").description("Show daemon status").option("--json", "Output as JSON", false).action(async (opts) => {
|
|
2285
|
+
daemon.command("status").description("Show daemon status").option("--json", "Output as JSON", false).option("--censor", "Mask account handles in output (for screenshots)").action(async (opts) => {
|
|
2263
2286
|
const { getServiceStatus: getServiceStatus2 } = await Promise.resolve().then(() => (init_service(), service_exports));
|
|
2264
2287
|
const svc = getServiceStatus2();
|
|
2265
|
-
const status = getDaemonStatus({ currentVersion: "1.
|
|
2288
|
+
const status = getDaemonStatus({ currentVersion: "1.10.1" });
|
|
2266
2289
|
if (opts.json) {
|
|
2267
2290
|
const serviceInfo = svc.installed ? {
|
|
2268
2291
|
service: {
|
|
@@ -2323,7 +2346,7 @@ daemon.command("status").description("Show daemon status").option("--json", "Out
|
|
|
2323
2346
|
if (status.versionMismatch) {
|
|
2324
2347
|
console.log(
|
|
2325
2348
|
yellow(
|
|
2326
|
-
` Warning: daemon is running v${status.daemonVersion} but v${"1.
|
|
2349
|
+
` Warning: daemon is running v${status.daemonVersion} but v${"1.10.1"} is installed.`
|
|
2327
2350
|
)
|
|
2328
2351
|
);
|
|
2329
2352
|
console.log(
|
|
@@ -2333,7 +2356,9 @@ daemon.command("status").description("Show daemon status").option("--json", "Out
|
|
|
2333
2356
|
);
|
|
2334
2357
|
}
|
|
2335
2358
|
console.log("");
|
|
2336
|
-
printAccountTable(console.log, /* @__PURE__ */ new Date(), getDeferredHandles()
|
|
2359
|
+
printAccountTable(console.log, /* @__PURE__ */ new Date(), getDeferredHandles(), {
|
|
2360
|
+
censor: opts.censor
|
|
2361
|
+
});
|
|
2337
2362
|
});
|
|
2338
2363
|
daemon.command("install").description("Install daemon as a system service (launchd/systemd)").option(
|
|
2339
2364
|
"--interval <minutes>",
|
|
@@ -2389,7 +2414,7 @@ daemon.command("_run", { hidden: true }).option("--interval-ms <ms>", "Ping inte
|
|
|
2389
2414
|
startedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2390
2415
|
intervalMs,
|
|
2391
2416
|
configDir: resolveConfigDir2(),
|
|
2392
|
-
version: "1.
|
|
2417
|
+
version: "1.10.1"
|
|
2393
2418
|
});
|
|
2394
2419
|
}
|
|
2395
2420
|
await runDaemonWithDefaults(intervalMs, {
|