@wbern/cc-ping 1.12.0 → 1.13.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/dist/cli.js +47 -15
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -618,14 +618,30 @@ var init_run_ping = __esm({
|
|
|
618
618
|
var schedule_exports = {};
|
|
619
619
|
__export(schedule_exports, {
|
|
620
620
|
buildHourHistogram: () => buildHourHistogram,
|
|
621
|
+
checkRecentActivity: () => checkRecentActivity,
|
|
621
622
|
findOptimalPingHour: () => findOptimalPingHour,
|
|
622
623
|
getAccountSchedule: () => getAccountSchedule,
|
|
624
|
+
isRecentlyActive: () => isRecentlyActive,
|
|
623
625
|
parseSmartSchedule: () => parseSmartSchedule,
|
|
624
626
|
readAccountSchedule: () => readAccountSchedule,
|
|
625
627
|
shouldDefer: () => shouldDefer
|
|
626
628
|
});
|
|
627
629
|
import { existsSync as existsSync5, readFileSync as readFileSync5 } from "fs";
|
|
628
630
|
import { join as join6 } from "path";
|
|
631
|
+
function isRecentlyActive(historyLines, now) {
|
|
632
|
+
let latest = 0;
|
|
633
|
+
for (const line of historyLines) {
|
|
634
|
+
try {
|
|
635
|
+
const entry = JSON.parse(line);
|
|
636
|
+
if (typeof entry.timestamp === "number" && entry.timestamp > latest) {
|
|
637
|
+
latest = entry.timestamp;
|
|
638
|
+
}
|
|
639
|
+
} catch {
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
if (latest === 0) return false;
|
|
643
|
+
return now.getTime() - latest < QUOTA_WINDOW_MS2;
|
|
644
|
+
}
|
|
629
645
|
function buildHourHistogram(timestamps) {
|
|
630
646
|
const bins = new Array(24).fill(0);
|
|
631
647
|
for (const ts of timestamps) {
|
|
@@ -697,6 +713,13 @@ function readAccountSchedule(configDir, now = /* @__PURE__ */ new Date(), resetA
|
|
|
697
713
|
const lines = content.split("\n").filter((l) => l.trim());
|
|
698
714
|
return getAccountSchedule(lines, now, resetAt);
|
|
699
715
|
}
|
|
716
|
+
function checkRecentActivity(configDir, now = /* @__PURE__ */ new Date()) {
|
|
717
|
+
const historyPath = join6(configDir, "history.jsonl");
|
|
718
|
+
if (!existsSync5(historyPath)) return false;
|
|
719
|
+
const content = readFileSync5(historyPath, "utf-8");
|
|
720
|
+
const lines = content.split("\n").filter((l) => l.trim());
|
|
721
|
+
return isRecentlyActive(lines, now);
|
|
722
|
+
}
|
|
700
723
|
function parseSmartSchedule(value) {
|
|
701
724
|
const lower = value.toLowerCase();
|
|
702
725
|
if (TRUTHY.has(lower)) return true;
|
|
@@ -705,11 +728,12 @@ function parseSmartSchedule(value) {
|
|
|
705
728
|
`Invalid smart-schedule value: "${value}". Use true/false, on/off, or 1/0`
|
|
706
729
|
);
|
|
707
730
|
}
|
|
708
|
-
var QUOTA_WINDOW_HOURS, MIN_DAYS, HISTORY_WINDOW_MS, TRUTHY, FALSY;
|
|
731
|
+
var QUOTA_WINDOW_HOURS, QUOTA_WINDOW_MS2, MIN_DAYS, HISTORY_WINDOW_MS, TRUTHY, FALSY;
|
|
709
732
|
var init_schedule = __esm({
|
|
710
733
|
"src/schedule.ts"() {
|
|
711
734
|
"use strict";
|
|
712
735
|
QUOTA_WINDOW_HOURS = 5;
|
|
736
|
+
QUOTA_WINDOW_MS2 = QUOTA_WINDOW_HOURS * 60 * 60 * 1e3;
|
|
713
737
|
MIN_DAYS = 7;
|
|
714
738
|
HISTORY_WINDOW_MS = 14 * 24 * 60 * 60 * 1e3;
|
|
715
739
|
TRUTHY = /* @__PURE__ */ new Set(["true", "on", "1"]);
|
|
@@ -1109,6 +1133,7 @@ async function runDaemonWithDefaults(intervalMs, options) {
|
|
|
1109
1133
|
const { runPing: runPing2 } = await Promise.resolve().then(() => (init_run_ping(), run_ping_exports));
|
|
1110
1134
|
const { listAccounts: listAccounts2 } = await Promise.resolve().then(() => (init_config(), config_exports));
|
|
1111
1135
|
const { getWindowReset: getWindowReset2 } = await Promise.resolve().then(() => (init_state(), state_exports));
|
|
1136
|
+
const { checkRecentActivity: checkRecentActivity2 } = await Promise.resolve().then(() => (init_schedule(), schedule_exports));
|
|
1112
1137
|
const smartScheduleEnabled = options.smartSchedule !== false;
|
|
1113
1138
|
let shouldDeferPing;
|
|
1114
1139
|
if (smartScheduleEnabled) {
|
|
@@ -1167,7 +1192,11 @@ async function runDaemonWithDefaults(intervalMs, options) {
|
|
|
1167
1192
|
sleep: (ms) => new Promise((resolve2) => setTimeout(resolve2, ms)),
|
|
1168
1193
|
shouldStop: () => existsSync6(stopPath),
|
|
1169
1194
|
log: (msg) => console.log(msg),
|
|
1170
|
-
isWindowActive: (handle) =>
|
|
1195
|
+
isWindowActive: (handle) => {
|
|
1196
|
+
if (getWindowReset2(handle) !== null) return true;
|
|
1197
|
+
const account = listAccounts2().find((a) => a.handle === handle);
|
|
1198
|
+
return account ? checkRecentActivity2(account.configDir) : false;
|
|
1199
|
+
},
|
|
1171
1200
|
shouldDeferPing,
|
|
1172
1201
|
hasUpgraded,
|
|
1173
1202
|
updateState: (patch) => {
|
|
@@ -1227,7 +1256,7 @@ function resolveExecutable(deps) {
|
|
|
1227
1256
|
args: [process.argv[1]]
|
|
1228
1257
|
};
|
|
1229
1258
|
}
|
|
1230
|
-
function generateLaunchdPlist(options, execInfo, configDir) {
|
|
1259
|
+
function generateLaunchdPlist(options, execInfo, configDir, path) {
|
|
1231
1260
|
const intervalMs = parseIntervalForService(options.interval);
|
|
1232
1261
|
const programArgs = [
|
|
1233
1262
|
...execInfo.args,
|
|
@@ -1251,6 +1280,7 @@ function generateLaunchdPlist(options, execInfo, configDir) {
|
|
|
1251
1280
|
const envVars = {};
|
|
1252
1281
|
if (configDir) envVars.CC_PING_CONFIG = configDir;
|
|
1253
1282
|
if (execInfo.args.length === 0) envVars.CC_PING_BIN = execInfo.executable;
|
|
1283
|
+
if (path) envVars.PATH = path;
|
|
1254
1284
|
let envSection = "";
|
|
1255
1285
|
if (Object.keys(envVars).length > 0) {
|
|
1256
1286
|
const entries = Object.entries(envVars).map(
|
|
@@ -1288,7 +1318,7 @@ ${argsXml}
|
|
|
1288
1318
|
</plist>
|
|
1289
1319
|
`;
|
|
1290
1320
|
}
|
|
1291
|
-
function generateSystemdUnit(options, execInfo, configDir) {
|
|
1321
|
+
function generateSystemdUnit(options, execInfo, configDir, path) {
|
|
1292
1322
|
const intervalMs = parseIntervalForService(options.interval);
|
|
1293
1323
|
const programArgs = [
|
|
1294
1324
|
...execInfo.args,
|
|
@@ -1308,6 +1338,7 @@ function generateSystemdUnit(options, execInfo, configDir) {
|
|
|
1308
1338
|
if (configDir) envPairs.push(`CC_PING_CONFIG=${configDir}`);
|
|
1309
1339
|
if (execInfo.args.length === 0)
|
|
1310
1340
|
envPairs.push(`CC_PING_BIN=${execInfo.executable}`);
|
|
1341
|
+
if (path) envPairs.push(`PATH=${path}`);
|
|
1311
1342
|
const envLine = envPairs.map((p) => `
|
|
1312
1343
|
Environment=${p}`).join("");
|
|
1313
1344
|
return `[Unit]
|
|
@@ -1379,11 +1410,12 @@ async function installService(options, deps) {
|
|
|
1379
1410
|
execSync: _execSync
|
|
1380
1411
|
});
|
|
1381
1412
|
const configDir = _configDir || void 0;
|
|
1413
|
+
const envPath = process.env.PATH;
|
|
1382
1414
|
let content;
|
|
1383
1415
|
if (_platform === "darwin") {
|
|
1384
|
-
content = generateLaunchdPlist(options, execInfo, configDir);
|
|
1416
|
+
content = generateLaunchdPlist(options, execInfo, configDir, envPath);
|
|
1385
1417
|
} else {
|
|
1386
|
-
content = generateSystemdUnit(options, execInfo, configDir);
|
|
1418
|
+
content = generateSystemdUnit(options, execInfo, configDir, envPath);
|
|
1387
1419
|
}
|
|
1388
1420
|
_mkdirSync(dirname(path), { recursive: true });
|
|
1389
1421
|
_writeFileSync(path, content);
|
|
@@ -1458,18 +1490,18 @@ function escapeXml(str) {
|
|
|
1458
1490
|
return str.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
1459
1491
|
}
|
|
1460
1492
|
function parseIntervalForService(value) {
|
|
1461
|
-
if (!value) return
|
|
1493
|
+
if (!value) return QUOTA_WINDOW_MS3;
|
|
1462
1494
|
const minutes = Number(value);
|
|
1463
|
-
if (Number.isNaN(minutes) || minutes <= 0) return
|
|
1495
|
+
if (Number.isNaN(minutes) || minutes <= 0) return QUOTA_WINDOW_MS3;
|
|
1464
1496
|
return minutes * 60 * 1e3;
|
|
1465
1497
|
}
|
|
1466
|
-
var PLIST_LABEL, SYSTEMD_SERVICE,
|
|
1498
|
+
var PLIST_LABEL, SYSTEMD_SERVICE, QUOTA_WINDOW_MS3;
|
|
1467
1499
|
var init_service = __esm({
|
|
1468
1500
|
"src/service.ts"() {
|
|
1469
1501
|
"use strict";
|
|
1470
1502
|
PLIST_LABEL = "com.cc-ping.daemon";
|
|
1471
1503
|
SYSTEMD_SERVICE = "cc-ping-daemon";
|
|
1472
|
-
|
|
1504
|
+
QUOTA_WINDOW_MS3 = 5 * 60 * 60 * 1e3;
|
|
1473
1505
|
}
|
|
1474
1506
|
});
|
|
1475
1507
|
|
|
@@ -2063,7 +2095,7 @@ function getDeferredHandles() {
|
|
|
2063
2095
|
}
|
|
2064
2096
|
return deferred;
|
|
2065
2097
|
}
|
|
2066
|
-
var program = new Command().name("cc-ping").description("Ping Claude Code sessions to trigger quota windows early").version("1.
|
|
2098
|
+
var program = new Command().name("cc-ping").description("Ping Claude Code sessions to trigger quota windows early").version("1.13.1").option(
|
|
2067
2099
|
"--config <path>",
|
|
2068
2100
|
"Path to config directory (default: ~/.config/cc-ping, env: CC_PING_CONFIG)"
|
|
2069
2101
|
).hook("preAction", (thisCommand) => {
|
|
@@ -2292,7 +2324,7 @@ daemon.command("start").description("Start the daemon process").option(
|
|
|
2292
2324
|
bell: opts.bell,
|
|
2293
2325
|
notify: opts.notify,
|
|
2294
2326
|
smartSchedule,
|
|
2295
|
-
version: "1.
|
|
2327
|
+
version: "1.13.1"
|
|
2296
2328
|
});
|
|
2297
2329
|
if (!result.success) {
|
|
2298
2330
|
console.error(result.error);
|
|
@@ -2328,7 +2360,7 @@ daemon.command("stop").description("Stop the daemon process").action(async () =>
|
|
|
2328
2360
|
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) => {
|
|
2329
2361
|
const { getServiceStatus: getServiceStatus2 } = await Promise.resolve().then(() => (init_service(), service_exports));
|
|
2330
2362
|
const svc = getServiceStatus2();
|
|
2331
|
-
const status = getDaemonStatus({ currentVersion: "1.
|
|
2363
|
+
const status = getDaemonStatus({ currentVersion: "1.13.1" });
|
|
2332
2364
|
if (opts.json) {
|
|
2333
2365
|
const serviceInfo = svc.installed ? {
|
|
2334
2366
|
service: {
|
|
@@ -2389,7 +2421,7 @@ daemon.command("status").description("Show daemon status").option("--json", "Out
|
|
|
2389
2421
|
if (status.versionMismatch) {
|
|
2390
2422
|
console.log(
|
|
2391
2423
|
yellow(
|
|
2392
|
-
` Warning: daemon is running v${status.daemonVersion} but v${"1.
|
|
2424
|
+
` Warning: daemon is running v${status.daemonVersion} but v${"1.13.1"} is installed.`
|
|
2393
2425
|
)
|
|
2394
2426
|
);
|
|
2395
2427
|
console.log(
|
|
@@ -2457,7 +2489,7 @@ daemon.command("_run", { hidden: true }).option("--interval-ms <ms>", "Ping inte
|
|
|
2457
2489
|
startedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2458
2490
|
intervalMs,
|
|
2459
2491
|
configDir: resolveConfigDir2(),
|
|
2460
|
-
version: "1.
|
|
2492
|
+
version: "1.13.1"
|
|
2461
2493
|
});
|
|
2462
2494
|
}
|
|
2463
2495
|
await runDaemonWithDefaults(intervalMs, {
|