@yoooclaw/cli 0.1.4 → 0.1.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/README.md +242 -65
- package/dist/bin.cjs +90 -13
- package/dist/bin.cjs.map +4 -4
- package/dist/index.cjs +90 -13
- package/dist/index.cjs.map +4 -4
- package/package.json +1 -1
- package/skills/yoooclaw-notification-query/SKILL.md +3 -2
package/dist/index.cjs
CHANGED
|
@@ -3756,9 +3756,10 @@ var COMMAND_TREE = [
|
|
|
3756
3756
|
name: "stats",
|
|
3757
3757
|
summary: "按维度聚合统计",
|
|
3758
3758
|
options: [
|
|
3759
|
-
{ flags: "--from <
|
|
3760
|
-
{ flags: "--to <
|
|
3759
|
+
{ flags: "--from <time>", summary: "YYYY-MM-DD 或 ISO 8601,默认 7 天前" },
|
|
3760
|
+
{ flags: "--to <time>", summary: "YYYY-MM-DD 或 ISO 8601,默认今天" },
|
|
3761
3761
|
{ flags: "--app <name>", summary: "仅统计指定应用" },
|
|
3762
|
+
{ flags: "--sender <name>", summary: "仅统计指定发送人/标题" },
|
|
3762
3763
|
{ flags: "--client <label>", summary: "按 clientLabel 过滤;all 为全部" },
|
|
3763
3764
|
{ flags: "--dim <dim>", summary: "date|app|sender|hour|client|all", default: "all" }
|
|
3764
3765
|
]
|
|
@@ -4272,7 +4273,7 @@ function buildContext(flags) {
|
|
|
4272
4273
|
var import_node_fs3 = require("node:fs");
|
|
4273
4274
|
function readBuildInjectedVersion() {
|
|
4274
4275
|
if (false) {}
|
|
4275
|
-
const version = "0.1.
|
|
4276
|
+
const version = "0.1.6".trim();
|
|
4276
4277
|
return version || undefined;
|
|
4277
4278
|
}
|
|
4278
4279
|
function readVersionFromPackageJson() {
|
|
@@ -9546,8 +9547,8 @@ function quantizeWindow(value) {
|
|
|
9546
9547
|
// src/vendor/light/sender.ts
|
|
9547
9548
|
async function sendLightEffect(apiKey, segments, logger, repeatInput, reason, title) {
|
|
9548
9549
|
const apiUrl = getEnvUrls().lightApiUrl;
|
|
9549
|
-
const appKey = "";
|
|
9550
|
-
const templateId = "";
|
|
9550
|
+
const appKey = "7Q617S1G5WD274JI";
|
|
9551
|
+
const templateId = "1990771146010017800";
|
|
9551
9552
|
const resolvedTitle = resolveLightTitle(title, reason, segments);
|
|
9552
9553
|
logger?.info(`Light sender: apiUrl=${apiUrl ?? "UNSET"}, appKey=${appKey ? appKey.substring(0, 8) + "…" : "UNSET"}, templateId=${templateId ?? "UNSET"}, apiKey=${apiKey ? apiKey.substring(0, 20) + "…" : "EMPTY"}, title=${resolvedTitle}, reason=${reason ?? ""}, segments=${JSON.stringify(segments)}`);
|
|
9553
9554
|
if (!apiUrl || !appKey || !templateId) {
|
|
@@ -13226,22 +13227,98 @@ async function notificationSummary(ctx, _args, opts) {
|
|
|
13226
13227
|
};
|
|
13227
13228
|
}
|
|
13228
13229
|
var HOUR_KEY = (n) => String(new Date(n.timestamp).getHours()).padStart(2, "0");
|
|
13230
|
+
var DATE_ONLY_RE = /^\d{4}-\d{2}-\d{2}$/;
|
|
13231
|
+
var ISO_TIME_RE = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}(?::\d{2}(?:\.\d{1,3})?)?(Z|[+-]\d{2}:\d{2})$/;
|
|
13232
|
+
function parseDateParts(value) {
|
|
13233
|
+
const m = /^(\d{4})-(\d{2})-(\d{2})$/.exec(value);
|
|
13234
|
+
if (!m)
|
|
13235
|
+
return null;
|
|
13236
|
+
const year = Number(m[1]);
|
|
13237
|
+
const month = Number(m[2]);
|
|
13238
|
+
const day = Number(m[3]);
|
|
13239
|
+
const d = new Date(year, month - 1, day);
|
|
13240
|
+
if (d.getFullYear() !== year || d.getMonth() !== month - 1 || d.getDate() !== day) {
|
|
13241
|
+
return null;
|
|
13242
|
+
}
|
|
13243
|
+
return { year, month, day };
|
|
13244
|
+
}
|
|
13245
|
+
function localDateTimestamp(parts, endOfDay) {
|
|
13246
|
+
return new Date(parts.year, parts.month - 1, parts.day, endOfDay ? 23 : 0, endOfDay ? 59 : 0, endOfDay ? 59 : 0, endOfDay ? 999 : 0).getTime();
|
|
13247
|
+
}
|
|
13248
|
+
function minDateKey(...keys) {
|
|
13249
|
+
return keys.sort()[0];
|
|
13250
|
+
}
|
|
13251
|
+
function maxDateKey(...keys) {
|
|
13252
|
+
return keys.sort().at(-1);
|
|
13253
|
+
}
|
|
13254
|
+
function parseStatsBoundary(value, optionName) {
|
|
13255
|
+
if (DATE_ONLY_RE.test(value)) {
|
|
13256
|
+
const parts = parseDateParts(value);
|
|
13257
|
+
if (!parts) {
|
|
13258
|
+
throw new YoooclawError("YOOOCLAW_INVALID_ARGUMENT", `${optionName} 必须是合法日期 YYYY-MM-DD`);
|
|
13259
|
+
}
|
|
13260
|
+
const startTs = localDateTimestamp(parts, false);
|
|
13261
|
+
const endTs = localDateTimestamp(parts, true);
|
|
13262
|
+
return {
|
|
13263
|
+
raw: value,
|
|
13264
|
+
exactTs: null,
|
|
13265
|
+
startTs,
|
|
13266
|
+
endTs,
|
|
13267
|
+
minDateKey: value,
|
|
13268
|
+
maxDateKey: value
|
|
13269
|
+
};
|
|
13270
|
+
}
|
|
13271
|
+
if (!ISO_TIME_RE.test(value)) {
|
|
13272
|
+
throw new YoooclawError("YOOOCLAW_INVALID_ARGUMENT", `${optionName} 必须是 YYYY-MM-DD 或 ISO 8601 时间,例如 2026-06-02 或 2026-06-02T09:00:00+08:00`);
|
|
13273
|
+
}
|
|
13274
|
+
const exactTs = Date.parse(value);
|
|
13275
|
+
if (Number.isNaN(exactTs)) {
|
|
13276
|
+
throw new YoooclawError("YOOOCLAW_INVALID_ARGUMENT", `${optionName} 不是合法时间`);
|
|
13277
|
+
}
|
|
13278
|
+
const declaredDateKey = value.slice(0, 10);
|
|
13279
|
+
const localDateKey = formatDate(new Date(exactTs));
|
|
13280
|
+
return {
|
|
13281
|
+
raw: value,
|
|
13282
|
+
exactTs,
|
|
13283
|
+
startTs: exactTs,
|
|
13284
|
+
endTs: exactTs,
|
|
13285
|
+
minDateKey: minDateKey(declaredDateKey, localDateKey),
|
|
13286
|
+
maxDateKey: maxDateKey(declaredDateKey, localDateKey)
|
|
13287
|
+
};
|
|
13288
|
+
}
|
|
13289
|
+
function buildStatsRange(fromRaw, toRaw) {
|
|
13290
|
+
const from = parseStatsBoundary(fromRaw ?? daysAgo(7), "--from");
|
|
13291
|
+
const to = parseStatsBoundary(toRaw ?? today(), "--to");
|
|
13292
|
+
if (from.startTs > to.endTs) {
|
|
13293
|
+
throw new YoooclawError("YOOOCLAW_INVALID_ARGUMENT", "--from 不能晚于 --to");
|
|
13294
|
+
}
|
|
13295
|
+
return {
|
|
13296
|
+
from: from.raw,
|
|
13297
|
+
to: to.raw,
|
|
13298
|
+
fromTs: from.exactTs,
|
|
13299
|
+
toTs: to.exactTs,
|
|
13300
|
+
fromDateKey: from.minDateKey,
|
|
13301
|
+
toDateKey: to.maxDateKey
|
|
13302
|
+
};
|
|
13303
|
+
}
|
|
13229
13304
|
async function notificationStats(ctx, _args, opts) {
|
|
13230
|
-
const
|
|
13231
|
-
const to = opts.to ?? today();
|
|
13305
|
+
const range = buildStatsRange(opts.from, opts.to);
|
|
13232
13306
|
const dim = opts.dim ?? "all";
|
|
13233
13307
|
const allowed = ["date", "app", "sender", "hour", "client", "all"];
|
|
13234
13308
|
if (!allowed.includes(dim)) {
|
|
13235
13309
|
throw new YoooclawError("YOOOCLAW_INVALID_ARGUMENT", `--dim 只能是 ${allowed.join("|")}`);
|
|
13236
13310
|
}
|
|
13237
13311
|
const options = {
|
|
13312
|
+
from: range.from,
|
|
13313
|
+
to: range.to,
|
|
13238
13314
|
app: opts.app,
|
|
13315
|
+
sender: opts.sender,
|
|
13239
13316
|
client: opts.client,
|
|
13240
13317
|
limit: MAX_LIMIT,
|
|
13241
|
-
fromTs:
|
|
13242
|
-
toTs:
|
|
13243
|
-
fromDateKey:
|
|
13244
|
-
toDateKey:
|
|
13318
|
+
fromTs: range.fromTs,
|
|
13319
|
+
toTs: range.toTs,
|
|
13320
|
+
fromDateKey: range.fromDateKey,
|
|
13321
|
+
toDateKey: range.toDateKey
|
|
13245
13322
|
};
|
|
13246
13323
|
const items = await queryNotifications(ctx.paths, options);
|
|
13247
13324
|
const byDate = topCounts(items, (n) => formatDate(new Date(n.timestamp)), MAX_LIMIT);
|
|
@@ -13253,7 +13330,7 @@ async function notificationStats(ctx, _args, opts) {
|
|
|
13253
13330
|
return {
|
|
13254
13331
|
ok: true,
|
|
13255
13332
|
total: items.length,
|
|
13256
|
-
range: { from, to },
|
|
13333
|
+
range: { from: range.from, to: range.to },
|
|
13257
13334
|
dim,
|
|
13258
13335
|
...dim === "all" ? dims : { [dim]: dims[dim] }
|
|
13259
13336
|
};
|
|
@@ -14703,5 +14780,5 @@ async function run(argv = process.argv) {
|
|
|
14703
14780
|
await program.parseAsync(argv);
|
|
14704
14781
|
}
|
|
14705
14782
|
|
|
14706
|
-
//# debugId=
|
|
14783
|
+
//# debugId=0CD266CF72FF908264756E2164756E21
|
|
14707
14784
|
//# sourceMappingURL=index.cjs.map
|