@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/dist/index.cjs CHANGED
@@ -3756,9 +3756,10 @@ var COMMAND_TREE = [
3756
3756
  name: "stats",
3757
3757
  summary: "按维度聚合统计",
3758
3758
  options: [
3759
- { flags: "--from <date>", summary: "YYYY-MM-DD,默认 7 天前" },
3760
- { flags: "--to <date>", summary: "YYYY-MM-DD,默认今天" },
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.4".trim();
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 from = opts.from ?? daysAgo(7);
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: null,
13242
- toTs: null,
13243
- fromDateKey: from,
13244
- toDateKey: to
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=389ACD187A2A9B6164756E2164756E21
14783
+ //# debugId=0CD266CF72FF908264756E2164756E21
14707
14784
  //# sourceMappingURL=index.cjs.map