@puyinkai/xiaobao-cli 0.5.0 → 0.6.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 (80) hide show
  1. package/README.md +6 -0
  2. package/dist/add-CCuWFy1O.mjs +21 -0
  3. package/dist/{admin-BOL_otwc.mjs → admin-CpPlecd5.mjs} +2 -2
  4. package/dist/analyze-DsiZ9O18.mjs +72 -0
  5. package/dist/{api-client-D3sCv6L3.mjs → api-client-JrgUZpe8.mjs} +19 -1
  6. package/dist/{api-BaX_r5S5.mjs → api-nDku2tzx.mjs} +1 -1
  7. package/dist/{audio-DzcmDYVu.mjs → audio-D-XxOe-n.mjs} +3 -2
  8. package/dist/{auth-DvvYyJBK.mjs → auth-sQwZSTNA.mjs} +4 -4
  9. package/dist/beautx-CK9SR4Tg.mjs +16 -0
  10. package/dist/cli.mjs +20 -13
  11. package/dist/config-WGgTcEU1.mjs +11 -0
  12. package/dist/{consultant-Ccnjnhzz.mjs → consultant-aWz8jHvH.mjs} +1 -1
  13. package/dist/{customer-D_LctjqX.mjs → customer-B410Tvlz.mjs} +1 -1
  14. package/dist/date-BcQMKhIT.mjs +21 -0
  15. package/dist/deal-analysis-C3yn-bFg.mjs +10 -0
  16. package/dist/diff-8I1_L-nU.mjs +21 -0
  17. package/dist/{doc-CC08fj8m.mjs → doc-CrY6qNkG.mjs} +1 -1
  18. package/dist/{doc-content-DktnDECM.mjs → doc-content-YKxaMDEp.mjs} +1 -1
  19. package/dist/{docs-DtQy3Zoc.mjs → docs-BpowF7jz.mjs} +1 -1
  20. package/dist/fields-iyCGxxkh.mjs +54 -0
  21. package/dist/{focus-BPPyRCBb.mjs → focus-DFxVA1UZ.mjs} +1 -1
  22. package/dist/follow-BLq9XK6s.mjs +14 -0
  23. package/dist/get-Cvl1PgHr.mjs +66 -0
  24. package/dist/{kb-DpBUFdFV.mjs → kb-B1sxz-PW.mjs} +4 -4
  25. package/dist/last-7-days-VKMMIzDz.mjs +5 -0
  26. package/dist/list-B8QkIq76.mjs +76 -0
  27. package/dist/{list-Ca5Fvq_e.mjs → list-BZVeH1P0.mjs} +2 -2
  28. package/dist/{list-DPyzRkq4.mjs → list-Bu9oehY8.mjs} +1 -1
  29. package/dist/{list-DciEIXpx.mjs → list-BvZ0SnDf.mjs} +2 -2
  30. package/dist/{list-xbJZbyGQ.mjs → list-C3bNdA1t.mjs} +2 -2
  31. package/dist/{list-CTSX1XuK.mjs → list-CjLiGMIC.mjs} +2 -2
  32. package/dist/{list-D_8QLOZ1.mjs → list-CtICqXPF.mjs} +2 -2
  33. package/dist/list-D3P2E5vT.mjs +43 -0
  34. package/dist/{list-Ikc5mo6a.mjs → list-DqLKhW5s.mjs} +1 -1
  35. package/dist/now-Ce3ViNOw.mjs +9 -0
  36. package/dist/plan-DC7ZFHWK.mjs +10 -0
  37. package/dist/portrait-D6oQPQfC.mjs +14 -0
  38. package/dist/portrait-tags-DGjYKGDf.mjs +10 -0
  39. package/dist/{project-CYA9qd8k.mjs → project-UkyNWPm6.mjs} +3 -3
  40. package/dist/{qa-CDYWW-19.mjs → qa-Dm1X6IoO.mjs} +1 -1
  41. package/dist/{quantum-Dyhp2Clf.mjs → quantum-DIuY6j7I.mjs} +3 -3
  42. package/dist/range-CSJiXTp3.mjs +18 -0
  43. package/dist/{resistance-BhlYgeUx.mjs → resistance-B-v-lfkT.mjs} +1 -1
  44. package/dist/{sales-report-BIfyfucO.mjs → sales-report-Daps9Vr5.mjs} +1 -1
  45. package/dist/{search-ChFFOKV4.mjs → search-VsAp96Co.mjs} +2 -2
  46. package/dist/shared-BEkL4JRB.mjs +11 -0
  47. package/dist/shared-CYALikq5.mjs +277 -0
  48. package/dist/shared-DtIllnrz.mjs +92 -0
  49. package/dist/subtract-B4XTXD_X.mjs +21 -0
  50. package/dist/{summary-C3poiB2C.mjs → summary-CF2uhuE3.mjs} +2 -2
  51. package/dist/summary-CgBgJOw2.mjs +65 -0
  52. package/dist/{text-K7uP8bat.mjs → text-8R0TuzgK.mjs} +1 -1
  53. package/dist/this-month-BRdfmc1s.mjs +5 -0
  54. package/dist/this-week-2GoqEaXU.mjs +5 -0
  55. package/dist/today-BhQnSMJH.mjs +5 -0
  56. package/dist/today-CdlU96lq.mjs +9 -0
  57. package/dist/today-so-far-D2g98rKv.mjs +5 -0
  58. package/dist/{token-usage-y46b3_7C.mjs → token-usage-BvWb3N3J.mjs} +1 -1
  59. package/dist/tomorrow-BgSEBV69.mjs +9 -0
  60. package/dist/{visit-qf8Lwf_s.mjs → visit-4xsa_DFD.mjs} +2 -2
  61. package/dist/visit-evaluate-BvmghATK.mjs +9 -0
  62. package/dist/weekday-CgEg7n7U.mjs +14 -0
  63. package/dist/yesterday-CHAh1DlJ.mjs +5 -0
  64. package/dist/yesterday-DW-YiRTt.mjs +9 -0
  65. package/package.json +1 -1
  66. package/skills/wangxiaobao-audio-analyze/SKILL.md +42 -0
  67. package/skills/wangxiaobao-beautx/SKILL.md +42 -0
  68. package/skills/wangxiaobao-customer-portrait/SKILL.md +45 -0
  69. package/skills/wangxiaobao-customer-query/SKILL.md +1 -1
  70. package/skills/wangxiaobao-follow-query/SKILL.md +45 -0
  71. package/skills/wangxiaobao-quantum-stats/SKILL.md +3 -1
  72. package/skills/wangxiaobao-quantum-stats/references/quantum-metrics.md +3 -2
  73. package/skills/wangxiaobao-shared/SKILL.md +5 -1
  74. /package/dist/{current-CaUOiS5G.mjs → current-ABh6R3vp.mjs} +0 -0
  75. /package/dist/{login-COK74GKN.mjs → login-Bp2W2Hnj.mjs} +0 -0
  76. /package/dist/{logout-BQnDwD5-.mjs → logout-BnoEQxKZ.mjs} +0 -0
  77. /package/dist/{status-DR0tFzju.mjs → status-CrpCtf5U.mjs} +0 -0
  78. /package/dist/{use-DwoZynR9.mjs → use-rAR4OVC7.mjs} +0 -0
  79. /package/dist/{util-pyTg7qwY.mjs → util-BuoFIeLS.mjs} +0 -0
  80. /package/dist/{whoami-CtuWBu20.mjs → whoami-oRc8gILN.mjs} +0 -0
@@ -1,9 +1,9 @@
1
1
  import { o as resolveConfig } from "./device-flow-j10PFOQL.mjs";
2
- import { t as xbApiFetch } from "./api-client-D3sCv6L3.mjs";
2
+ import { t as xbApiFetch } from "./api-client-JrgUZpe8.mjs";
3
3
  import { n as requireActiveProject } from "./project-store-CudTRvbA.mjs";
4
4
  import { t as tenantProjectHeaders } from "./headers-Dy5gROBB.mjs";
5
5
  import { n as writeResult, t as writeError } from "./format-DfVypHID.mjs";
6
- import { r as toLocalDateTime, t as csvToArray } from "./util-pyTg7qwY.mjs";
6
+ import { r as toLocalDateTime, t as csvToArray } from "./util-BuoFIeLS.mjs";
7
7
  import { defineCommand } from "citty";
8
8
  //#region src/commands/resistance/list.ts
9
9
  /**
@@ -1,9 +1,9 @@
1
1
  import { o as resolveConfig } from "./device-flow-j10PFOQL.mjs";
2
- import { t as xbApiFetch } from "./api-client-D3sCv6L3.mjs";
2
+ import { t as xbApiFetch } from "./api-client-JrgUZpe8.mjs";
3
3
  import { n as requireActiveProject } from "./project-store-CudTRvbA.mjs";
4
4
  import { t as tenantProjectHeaders } from "./headers-Dy5gROBB.mjs";
5
5
  import { n as writeResult, t as writeError } from "./format-DfVypHID.mjs";
6
- import { r as toLocalDateTime } from "./util-pyTg7qwY.mjs";
6
+ import { r as toLocalDateTime } from "./util-BuoFIeLS.mjs";
7
7
  import { defineCommand } from "citty";
8
8
  //#region src/commands/customer/list.ts
9
9
  /**
@@ -1,9 +1,9 @@
1
1
  import { o as resolveConfig } from "./device-flow-j10PFOQL.mjs";
2
- import { t as xbApiFetch } from "./api-client-D3sCv6L3.mjs";
2
+ import { t as xbApiFetch } from "./api-client-JrgUZpe8.mjs";
3
3
  import { n as requireActiveProject } from "./project-store-CudTRvbA.mjs";
4
4
  import { t as tenantProjectHeaders } from "./headers-Dy5gROBB.mjs";
5
5
  import { n as writeResult, t as writeError } from "./format-DfVypHID.mjs";
6
- import { n as mergeUserIds, r as toLocalDateTime, t as csvToArray } from "./util-pyTg7qwY.mjs";
6
+ import { n as mergeUserIds, r as toLocalDateTime, t as csvToArray } from "./util-BuoFIeLS.mjs";
7
7
  import { defineCommand } from "citty";
8
8
  //#region src/commands/audio/list.ts
9
9
  /**
@@ -1,9 +1,9 @@
1
1
  import { o as resolveConfig } from "./device-flow-j10PFOQL.mjs";
2
- import { t as xbApiFetch } from "./api-client-D3sCv6L3.mjs";
2
+ import { t as xbApiFetch } from "./api-client-JrgUZpe8.mjs";
3
3
  import { n as requireActiveProject } from "./project-store-CudTRvbA.mjs";
4
4
  import { t as tenantProjectHeaders } from "./headers-Dy5gROBB.mjs";
5
5
  import { n as writeResult, t as writeError } from "./format-DfVypHID.mjs";
6
- import { r as toLocalDateTime, t as csvToArray } from "./util-pyTg7qwY.mjs";
6
+ import { r as toLocalDateTime, t as csvToArray } from "./util-BuoFIeLS.mjs";
7
7
  import { defineCommand } from "citty";
8
8
  //#region src/commands/focus/list.ts
9
9
  /**
@@ -0,0 +1,43 @@
1
+ import { o as resolveConfig } from "./device-flow-j10PFOQL.mjs";
2
+ import { t as xbApiFetch } from "./api-client-JrgUZpe8.mjs";
3
+ import { n as requireActiveProject } from "./project-store-CudTRvbA.mjs";
4
+ import { t as tenantProjectHeaders } from "./headers-Dy5gROBB.mjs";
5
+ import { n as writeResult, t as writeError } from "./format-DfVypHID.mjs";
6
+ import { defineCommand } from "citty";
7
+ //#region src/commands/portrait/list.ts
8
+ /**
9
+ * `xiaobao-cli portrait list` — 画像字段清单(中文名 + 分档枚举)。
10
+ *
11
+ * 返回本项目可用的画像字段(fieldNames + fields[].values 分档),
12
+ * 供 `portrait get <field>` 使用。调 POST /ai-open/portraits/fields。
13
+ */
14
+ var list_default = defineCommand({
15
+ meta: {
16
+ name: "list",
17
+ description: "画像字段清单(中文名,供 portrait get 使用)"
18
+ },
19
+ args: {
20
+ "api-base": { type: "string" },
21
+ "auth-base": { type: "string" },
22
+ format: {
23
+ type: "string",
24
+ default: "toon"
25
+ }
26
+ },
27
+ async run({ args }) {
28
+ try {
29
+ writeResult(await xbApiFetch(resolveConfig({
30
+ apiBase: args["api-base"],
31
+ authBase: args["auth-base"]
32
+ }), "POST", "/ai-open/portraits/fields", {
33
+ headers: tenantProjectHeaders(await requireActiveProject()),
34
+ body: {}
35
+ }), args.format);
36
+ } catch (err) {
37
+ writeError(err, args.format);
38
+ process.exit(1);
39
+ }
40
+ }
41
+ });
42
+ //#endregion
43
+ export { list_default as default };
@@ -1,5 +1,5 @@
1
1
  import { o as resolveConfig } from "./device-flow-j10PFOQL.mjs";
2
- import { t as xbApiFetch } from "./api-client-D3sCv6L3.mjs";
2
+ import { t as xbApiFetch } from "./api-client-JrgUZpe8.mjs";
3
3
  import { n as requireActiveProject } from "./project-store-CudTRvbA.mjs";
4
4
  import { t as tenantProjectHeaders } from "./headers-Dy5gROBB.mjs";
5
5
  import { n as writeResult, t as writeError } from "./format-DfVypHID.mjs";
@@ -0,0 +1,9 @@
1
+ import { o as getNow, t as defineDateCommand } from "./shared-CYALikq5.mjs";
2
+ //#region src/commands/date/now.ts
3
+ var now_default = defineDateCommand({
4
+ name: "now",
5
+ description: "当前日期时间(含星期)",
6
+ run: ({ args }) => getNow(args.timezone)
7
+ });
8
+ //#endregion
9
+ export { now_default as default };
@@ -0,0 +1,10 @@
1
+ import { t as defineBeautxCommand } from "./shared-DtIllnrz.mjs";
2
+ //#region src/commands/beautx/plan.ts
3
+ var plan_default = defineBeautxCommand({
4
+ name: "plan",
5
+ description: "医美变美计划分页(报告分组 sections + 面诊医生/复诊时间等)",
6
+ path: "/ai-open/beautx/plans",
7
+ supportsLatestOnly: true
8
+ });
9
+ //#endregion
10
+ export { plan_default as default };
@@ -0,0 +1,14 @@
1
+ import { defineCommand } from "citty";
2
+ //#region src/commands/portrait/index.ts
3
+ var portrait_default = defineCommand({
4
+ meta: {
5
+ name: "portrait",
6
+ description: "客户画像分布:字段清单(list) / 单字段饼图(get)(按画像筛客户用 customer list --portrait)"
7
+ },
8
+ subCommands: {
9
+ list: () => import("./list-D3P2E5vT.mjs").then((m) => m.default),
10
+ get: () => import("./get-Cvl1PgHr.mjs").then((m) => m.default)
11
+ }
12
+ });
13
+ //#endregion
14
+ export { portrait_default as default };
@@ -0,0 +1,10 @@
1
+ import { t as defineBeautxCommand } from "./shared-DtIllnrz.mjs";
2
+ //#region src/commands/beautx/portrait-tags.ts
3
+ var portrait_tags_default = defineBeautxCommand({
4
+ name: "portrait-tags",
5
+ description: "医美来访画像标签分页(维度 → 命中标签值;--dimension 过滤维度名)",
6
+ path: "/ai-open/beautx/portrait-tags",
7
+ supportsDimension: true
8
+ });
9
+ //#endregion
10
+ export { portrait_tags_default as default };
@@ -6,9 +6,9 @@ var project_default = defineCommand({
6
6
  description: "查询 / 切换激活项目"
7
7
  },
8
8
  subCommands: {
9
- list: () => import("./list-DPyzRkq4.mjs").then((m) => m.default),
10
- use: () => import("./use-DwoZynR9.mjs").then((m) => m.default),
11
- current: () => import("./current-CaUOiS5G.mjs").then((m) => m.default)
9
+ list: () => import("./list-Bu9oehY8.mjs").then((m) => m.default),
10
+ use: () => import("./use-rAR4OVC7.mjs").then((m) => m.default),
11
+ current: () => import("./current-ABh6R3vp.mjs").then((m) => m.default)
12
12
  }
13
13
  });
14
14
  //#endregion
@@ -1,5 +1,5 @@
1
1
  import { o as resolveConfig } from "./device-flow-j10PFOQL.mjs";
2
- import { t as xbApiFetch } from "./api-client-D3sCv6L3.mjs";
2
+ import { t as xbApiFetch } from "./api-client-JrgUZpe8.mjs";
3
3
  import { n as requireActiveProject } from "./project-store-CudTRvbA.mjs";
4
4
  import { t as tenantProjectHeaders } from "./headers-Dy5gROBB.mjs";
5
5
  import { n as writeResult, t as writeError } from "./format-DfVypHID.mjs";
@@ -1,9 +1,9 @@
1
1
  import { o as resolveConfig } from "./device-flow-j10PFOQL.mjs";
2
- import { t as xbApiFetch } from "./api-client-D3sCv6L3.mjs";
2
+ import { t as xbApiFetch } from "./api-client-JrgUZpe8.mjs";
3
3
  import { n as requireActiveProject } from "./project-store-CudTRvbA.mjs";
4
4
  import { t as tenantProjectHeaders } from "./headers-Dy5gROBB.mjs";
5
5
  import { n as writeResult, t as writeError } from "./format-DfVypHID.mjs";
6
- import { r as toLocalDateTime, t as csvToArray } from "./util-pyTg7qwY.mjs";
6
+ import { r as toLocalDateTime, t as csvToArray } from "./util-BuoFIeLS.mjs";
7
7
  import { defineCommand } from "citty";
8
8
  //#region src/commands/quantum.ts
9
9
  /**
@@ -96,7 +96,7 @@ var quantum_default = defineCommand({
96
96
  },
97
97
  "intent-dimension": {
98
98
  type: "string",
99
- description: "review|ai(intent)"
99
+ description: "intent 数据口径:review=复核后数据(默认,日常汇报用)|ai=AI 智能评级;用户明确说「AI 评级」才传 ai"
100
100
  },
101
101
  "risk-dimension": {
102
102
  type: "string",
@@ -0,0 +1,18 @@
1
+ import { defineCommand } from "citty";
2
+ //#region src/commands/date/range/index.ts
3
+ var range_default = defineCommand({
4
+ meta: {
5
+ name: "range",
6
+ description: "算出业务查询用的 from/to(含时分秒);不查数据,只生成时间参数给 quantum / list"
7
+ },
8
+ subCommands: {
9
+ today: () => import("./today-BhQnSMJH.mjs").then((m) => m.default),
10
+ yesterday: () => import("./yesterday-CHAh1DlJ.mjs").then((m) => m.default),
11
+ "this-week": () => import("./this-week-2GoqEaXU.mjs").then((m) => m.default),
12
+ "this-month": () => import("./this-month-BRdfmc1s.mjs").then((m) => m.default),
13
+ "last-7-days": () => import("./last-7-days-VKMMIzDz.mjs").then((m) => m.default),
14
+ "today-so-far": () => import("./today-so-far-D2g98rKv.mjs").then((m) => m.default)
15
+ }
16
+ });
17
+ //#endregion
18
+ export { range_default as default };
@@ -5,7 +5,7 @@ var resistance_default = defineCommand({
5
5
  name: "resistance",
6
6
  description: "客户抗性点标签分页查询"
7
7
  },
8
- subCommands: { list: () => import("./list-DciEIXpx.mjs").then((m) => m.default) }
8
+ subCommands: { list: () => import("./list-BvZ0SnDf.mjs").then((m) => m.default) }
9
9
  });
10
10
  //#endregion
11
11
  export { resistance_default as default };
@@ -1,5 +1,5 @@
1
1
  import { o as resolveConfig } from "./device-flow-j10PFOQL.mjs";
2
- import { t as xbApiFetch } from "./api-client-D3sCv6L3.mjs";
2
+ import { t as xbApiFetch } from "./api-client-JrgUZpe8.mjs";
3
3
  import { t as loadActiveProject } from "./project-store-CudTRvbA.mjs";
4
4
  import { t as tenantProjectHeaders } from "./headers-Dy5gROBB.mjs";
5
5
  import { n as writeResult, t as writeError } from "./format-DfVypHID.mjs";
@@ -1,9 +1,9 @@
1
1
  import { o as resolveConfig } from "./device-flow-j10PFOQL.mjs";
2
- import { t as xbApiFetch } from "./api-client-D3sCv6L3.mjs";
2
+ import { t as xbApiFetch } from "./api-client-JrgUZpe8.mjs";
3
3
  import { n as requireActiveProject } from "./project-store-CudTRvbA.mjs";
4
4
  import { t as tenantProjectHeaders } from "./headers-Dy5gROBB.mjs";
5
5
  import { n as writeResult, t as writeError } from "./format-DfVypHID.mjs";
6
- import { t as csvToArray } from "./util-pyTg7qwY.mjs";
6
+ import { t as csvToArray } from "./util-BuoFIeLS.mjs";
7
7
  import { defineCommand } from "citty";
8
8
  //#region src/commands/kb/search.ts
9
9
  /**
@@ -0,0 +1,11 @@
1
+ import { s as getRange, t as defineDateCommand } from "./shared-CYALikq5.mjs";
2
+ //#region src/commands/date/range/shared.ts
3
+ function defineRangePresetCommand(preset, description) {
4
+ return defineDateCommand({
5
+ name: preset,
6
+ description,
7
+ run: ({ args }) => getRange(preset, args.timezone)
8
+ });
9
+ }
10
+ //#endregion
11
+ export { defineRangePresetCommand as t };
@@ -0,0 +1,277 @@
1
+ import { n as writeResult, t as writeError } from "./format-DfVypHID.mjs";
2
+ import { defineCommand } from "citty";
3
+ //#region src/core/date-util.ts
4
+ /**
5
+ * Local date/time helpers for `xiaobao-cli date *` (no network).
6
+ *
7
+ * Default timezone: Asia/Shanghai (or TZ env). Weekday numbering: 1=Monday … 7=Sunday.
8
+ */
9
+ const DEFAULT_TIMEZONE = "Asia/Shanghai";
10
+ const DATE_RE = /^(\d{4})-(\d{2})-(\d{2})$/;
11
+ const WEEKDAY_SHORT_TO_NUM = {
12
+ Mon: 1,
13
+ Tue: 2,
14
+ Wed: 3,
15
+ Thu: 4,
16
+ Fri: 5,
17
+ Sat: 6,
18
+ Sun: 7
19
+ };
20
+ var DateInputError = class extends Error {
21
+ code = "INVALID_DATE";
22
+ hint = "日期须为 YYYY-MM-DD;days 须为非负整数";
23
+ constructor(message) {
24
+ super(message);
25
+ this.name = "DateInputError";
26
+ }
27
+ };
28
+ function resolveTimezone(input) {
29
+ const tz = (input ?? process.env.TZ ?? "Asia/Shanghai").trim();
30
+ if (!tz) return DEFAULT_TIMEZONE;
31
+ try {
32
+ Intl.DateTimeFormat(void 0, { timeZone: tz });
33
+ return tz;
34
+ } catch {
35
+ throw new DateInputError(`无效时区: ${tz}`);
36
+ }
37
+ }
38
+ function parseYmd(date) {
39
+ const m = DATE_RE.exec(date.trim());
40
+ if (!m) throw new DateInputError(`无效日期: ${date}`);
41
+ const year = Number(m[1]);
42
+ const month = Number(m[2]);
43
+ const day = Number(m[3]);
44
+ const probe = new Date(Date.UTC(year, month - 1, day));
45
+ if (probe.getUTCFullYear() !== year || probe.getUTCMonth() + 1 !== month || probe.getUTCDate() !== day) throw new DateInputError(`无效日期: ${date}`);
46
+ return {
47
+ year,
48
+ month,
49
+ day
50
+ };
51
+ }
52
+ function pad2(n) {
53
+ return String(n).padStart(2, "0");
54
+ }
55
+ function formatYmd(ymd) {
56
+ return `${ymd.year}-${pad2(ymd.month)}-${pad2(ymd.day)}`;
57
+ }
58
+ function formatDateTime(parts) {
59
+ return `${formatYmd(parts)} ${pad2(parts.hour)}:${pad2(parts.minute)}:${pad2(parts.second)}`;
60
+ }
61
+ function getZonedParts(instant, timeZone) {
62
+ const parts = new Intl.DateTimeFormat("en-US", {
63
+ timeZone,
64
+ year: "numeric",
65
+ month: "2-digit",
66
+ day: "2-digit",
67
+ hour: "2-digit",
68
+ minute: "2-digit",
69
+ second: "2-digit",
70
+ weekday: "short",
71
+ hour12: false,
72
+ hourCycle: "h23"
73
+ }).formatToParts(instant);
74
+ const pick = (type) => parts.find((p) => p.type === type)?.value ?? "";
75
+ const hourRaw = Number(pick("hour"));
76
+ const hour = hourRaw === 24 ? 0 : hourRaw;
77
+ return {
78
+ year: Number(pick("year")),
79
+ month: Number(pick("month")),
80
+ day: Number(pick("day")),
81
+ hour,
82
+ minute: Number(pick("minute")),
83
+ second: Number(pick("second")),
84
+ weekdayShort: pick("weekday")
85
+ };
86
+ }
87
+ function weekdayNumFromShort(short) {
88
+ const num = WEEKDAY_SHORT_TO_NUM[short];
89
+ if (!num) throw new DateInputError(`无法解析星期: ${short}`);
90
+ return num;
91
+ }
92
+ function weekdayZh(instant, timeZone) {
93
+ return new Intl.DateTimeFormat("zh-CN", {
94
+ timeZone,
95
+ weekday: "long"
96
+ }).format(instant);
97
+ }
98
+ function zonedInstant(ymd, hms, timeZone) {
99
+ const [hh, mm, ss] = hms.split(":").map(Number);
100
+ const utcGuess = Date.UTC(ymd.year, ymd.month - 1, ymd.day, hh, mm, ss);
101
+ const offset = getTimezoneOffsetMs(timeZone, new Date(utcGuess));
102
+ return new Date(utcGuess - offset);
103
+ }
104
+ function getTimezoneOffsetMs(timeZone, date) {
105
+ const parts = getZonedParts(date, timeZone);
106
+ return Date.UTC(parts.year, parts.month - 1, parts.day, parts.hour, parts.minute, parts.second) - date.getTime();
107
+ }
108
+ function addCalendarDays(ymd, offset) {
109
+ const dt = new Date(Date.UTC(ymd.year, ymd.month - 1, ymd.day + offset));
110
+ return {
111
+ year: dt.getUTCFullYear(),
112
+ month: dt.getUTCMonth() + 1,
113
+ day: dt.getUTCDate()
114
+ };
115
+ }
116
+ function buildDateInfo(parts, timeZone, instant) {
117
+ const weekdayNum = weekdayNumFromShort(parts.weekdayShort);
118
+ return {
119
+ date: formatYmd(parts),
120
+ datetime: formatDateTime(parts),
121
+ timezone: timeZone,
122
+ weekday: weekdayZh(instant, timeZone),
123
+ weekdayNum
124
+ };
125
+ }
126
+ function getNow(timeZoneInput) {
127
+ const timeZone = resolveTimezone(timeZoneInput);
128
+ const instant = /* @__PURE__ */ new Date();
129
+ return buildDateInfo(getZonedParts(instant, timeZone), timeZone, instant);
130
+ }
131
+ function getDateInfo(date, timeZoneInput) {
132
+ const timeZone = resolveTimezone(timeZoneInput);
133
+ const instant = zonedInstant(parseYmd(date), "00:00:00", timeZone);
134
+ const parts = getZonedParts(instant, timeZone);
135
+ return {
136
+ date: formatYmd(parts),
137
+ timezone: timeZone,
138
+ weekday: weekdayZh(instant, timeZone),
139
+ weekdayNum: weekdayNumFromShort(parts.weekdayShort)
140
+ };
141
+ }
142
+ function getRelativeDay(offsetDays, timeZoneInput) {
143
+ const timeZone = resolveTimezone(timeZoneInput);
144
+ return getDateInfo(formatYmd(addCalendarDays(getZonedParts(/* @__PURE__ */ new Date(), timeZone), offsetDays)), timeZone);
145
+ }
146
+ function addDays(date, offset, timeZoneInput) {
147
+ const timeZone = resolveTimezone(timeZoneInput);
148
+ return getDateInfo(formatYmd(addCalendarDays(parseYmd(date), offset)), timeZone);
149
+ }
150
+ function dateDiff(startDate, endDate) {
151
+ const start = parseYmd(startDate);
152
+ const end = parseYmd(endDate);
153
+ const startMs = Date.UTC(start.year, start.month - 1, start.day);
154
+ const endMs = Date.UTC(end.year, end.month - 1, end.day);
155
+ return {
156
+ startDate: formatYmd(start),
157
+ endDate: formatYmd(end),
158
+ days: Math.round((endMs - startMs) / 864e5)
159
+ };
160
+ }
161
+ function startOfWeekMonday(ymd, timeZone) {
162
+ return addCalendarDays(ymd, -(weekdayNumFromShort(getZonedParts(zonedInstant(ymd, "12:00:00", timeZone), timeZone).weekdayShort) - 1));
163
+ }
164
+ function startOfMonth(ymd) {
165
+ return {
166
+ year: ymd.year,
167
+ month: ymd.month,
168
+ day: 1
169
+ };
170
+ }
171
+ function nextMonthStart(ymd) {
172
+ if (ymd.month === 12) return {
173
+ year: ymd.year + 1,
174
+ month: 1,
175
+ day: 1
176
+ };
177
+ return {
178
+ year: ymd.year,
179
+ month: ymd.month + 1,
180
+ day: 1
181
+ };
182
+ }
183
+ function getRange(preset, timeZoneInput) {
184
+ const timeZone = resolveTimezone(timeZoneInput);
185
+ const todayParts = getZonedParts(/* @__PURE__ */ new Date(), timeZone);
186
+ const today = formatYmd(todayParts);
187
+ const tomorrow = formatYmd(addCalendarDays(todayParts, 1));
188
+ const yesterday = formatYmd(addCalendarDays(todayParts, -1));
189
+ let from;
190
+ let to;
191
+ switch (preset) {
192
+ case "today":
193
+ from = `${today} 00:00:00`;
194
+ to = `${tomorrow} 00:00:00`;
195
+ break;
196
+ case "yesterday":
197
+ from = `${yesterday} 00:00:00`;
198
+ to = `${today} 00:00:00`;
199
+ break;
200
+ case "today-so-far":
201
+ from = `${today} 00:00:00`;
202
+ to = formatDateTime(todayParts);
203
+ break;
204
+ case "this-week": {
205
+ const monday = formatYmd(startOfWeekMonday(todayParts, timeZone));
206
+ const nextMonday = formatYmd(addCalendarDays(parseYmd(monday), 7));
207
+ from = `${monday} 00:00:00`;
208
+ to = `${nextMonday} 00:00:00`;
209
+ break;
210
+ }
211
+ case "this-month": {
212
+ const monthStart = formatYmd(startOfMonth(todayParts));
213
+ const nextMonth = formatYmd(nextMonthStart(todayParts));
214
+ from = `${monthStart} 00:00:00`;
215
+ to = `${nextMonth} 00:00:00`;
216
+ break;
217
+ }
218
+ case "last-7-days":
219
+ from = `${formatYmd(addCalendarDays(todayParts, -6))} 00:00:00`;
220
+ to = `${tomorrow} 00:00:00`;
221
+ break;
222
+ default: throw new DateInputError(`未知 preset: ${preset}`);
223
+ }
224
+ const anchor = getDateInfo(today, timeZone);
225
+ return {
226
+ range: preset,
227
+ timezone: timeZone,
228
+ from,
229
+ to,
230
+ date: anchor.date,
231
+ weekday: anchor.weekday,
232
+ weekdayNum: anchor.weekdayNum
233
+ };
234
+ }
235
+ //#endregion
236
+ //#region src/commands/date/shared.ts
237
+ /**
238
+ * Shared helpers for `xiaobao-cli date *`.
239
+ */
240
+ const timezoneArg = { timezone: {
241
+ type: "string",
242
+ description: "IANA 时区,默认 Asia/Shanghai(或 TZ 环境变量)"
243
+ } };
244
+ function parsePositiveDays(raw, label = "days") {
245
+ if (raw === void 0 || raw === "") throw new DateInputError(`缺少 ${label}`);
246
+ const days = Number(raw);
247
+ if (!Number.isInteger(days) || days < 0) throw new DateInputError(`${label} 须为非负整数: ${raw}`);
248
+ return days;
249
+ }
250
+ function defineDateCommand(def) {
251
+ return defineCommand({
252
+ meta: {
253
+ name: def.name,
254
+ description: def.description
255
+ },
256
+ args: {
257
+ format: {
258
+ type: "string",
259
+ default: "toon",
260
+ description: "Stdout format: toon (default) / json / table"
261
+ },
262
+ ...timezoneArg,
263
+ ...def.args
264
+ },
265
+ async run({ args }) {
266
+ const format = typeof args.format === "string" ? args.format : void 0;
267
+ try {
268
+ writeResult(def.run({ args }), format);
269
+ } catch (err) {
270
+ writeError(err, format);
271
+ process.exit(1);
272
+ }
273
+ }
274
+ });
275
+ }
276
+ //#endregion
277
+ export { getDateInfo as a, getRelativeDay as c, dateDiff as i, parsePositiveDays as n, getNow as o, addDays as r, getRange as s, defineDateCommand as t };
@@ -0,0 +1,92 @@
1
+ import { o as resolveConfig } from "./device-flow-j10PFOQL.mjs";
2
+ import { t as xbApiFetch } from "./api-client-JrgUZpe8.mjs";
3
+ import { n as requireActiveProject } from "./project-store-CudTRvbA.mjs";
4
+ import { t as tenantProjectHeaders } from "./headers-Dy5gROBB.mjs";
5
+ import { n as writeResult, t as writeError } from "./format-DfVypHID.mjs";
6
+ import { r as toLocalDateTime, t as csvToArray } from "./util-BuoFIeLS.mjs";
7
+ import { defineCommand } from "citty";
8
+ //#region src/commands/beautx/shared.ts
9
+ /**
10
+ * Shared args/body builder for `xiaobao-cli beautx *` — the four beautx (医美)
11
+ * queries share one request shape (visitIds/wangIds/beautxCustomerIds/时间窗/分页).
12
+ */
13
+ function defineBeautxCommand(def) {
14
+ return defineCommand({
15
+ meta: {
16
+ name: def.name,
17
+ description: def.description
18
+ },
19
+ args: {
20
+ "visit-ids": {
21
+ type: "string",
22
+ description: "CSV: 来访 ID 过滤"
23
+ },
24
+ "customer-ids": {
25
+ type: "string",
26
+ description: "CSV: 客户 wang_id 过滤"
27
+ },
28
+ "beautx-customer-ids": {
29
+ type: "string",
30
+ description: "CSV: 医美业务客户 ID 过滤"
31
+ },
32
+ ...def.supportsLatestOnly ? { "latest-only": {
33
+ type: "boolean",
34
+ description: "每客户只取最新一条"
35
+ } } : {},
36
+ ...def.supportsDimension ? { dimension: {
37
+ type: "string",
38
+ description: "画像标签维度名过滤"
39
+ } } : {},
40
+ from: {
41
+ type: "string",
42
+ description: "开始时间(含)"
43
+ },
44
+ to: {
45
+ type: "string",
46
+ description: "结束时间(不含)"
47
+ },
48
+ page: {
49
+ type: "string",
50
+ default: "1"
51
+ },
52
+ size: {
53
+ type: "string",
54
+ default: "10"
55
+ },
56
+ "api-base": { type: "string" },
57
+ "auth-base": { type: "string" },
58
+ format: {
59
+ type: "string",
60
+ default: "toon"
61
+ }
62
+ },
63
+ async run({ args }) {
64
+ try {
65
+ const config = resolveConfig({
66
+ apiBase: args["api-base"],
67
+ authBase: args["auth-base"]
68
+ });
69
+ const active = await requireActiveProject();
70
+ writeResult(await xbApiFetch(config, "POST", def.path, {
71
+ headers: tenantProjectHeaders(active),
72
+ body: {
73
+ visitIds: csvToArray(args["visit-ids"]),
74
+ customerIds: csvToArray(args["customer-ids"]),
75
+ beautxCustomerIds: csvToArray(args["beautx-customer-ids"])?.map(Number),
76
+ latestOnly: def.supportsLatestOnly ? args["latest-only"] : void 0,
77
+ dimensionName: def.supportsDimension ? args.dimension : void 0,
78
+ fromDate: toLocalDateTime(args.from),
79
+ toDate: toLocalDateTime(args.to),
80
+ page: Number(args.page),
81
+ size: Number(args.size)
82
+ }
83
+ }), args.format);
84
+ } catch (err) {
85
+ writeError(err, args.format);
86
+ process.exit(1);
87
+ }
88
+ }
89
+ });
90
+ }
91
+ //#endregion
92
+ export { defineBeautxCommand as t };
@@ -0,0 +1,21 @@
1
+ import { n as parsePositiveDays, r as addDays, t as defineDateCommand } from "./shared-CYALikq5.mjs";
2
+ //#region src/commands/date/subtract.ts
3
+ var subtract_default = defineDateCommand({
4
+ name: "subtract",
5
+ description: "日期往前推 N 天",
6
+ args: {
7
+ date: {
8
+ type: "positional",
9
+ required: true,
10
+ description: "基准日期 YYYY-MM-DD"
11
+ },
12
+ days: {
13
+ type: "positional",
14
+ required: true,
15
+ description: "往前推的天数(非负整数)"
16
+ }
17
+ },
18
+ run: ({ args }) => addDays(args.date, -parsePositiveDays(args.days, "days"), args.timezone)
19
+ });
20
+ //#endregion
21
+ export { subtract_default as default };
@@ -1,9 +1,9 @@
1
1
  import { o as resolveConfig } from "./device-flow-j10PFOQL.mjs";
2
- import { t as xbApiFetch } from "./api-client-D3sCv6L3.mjs";
2
+ import { t as xbApiFetch } from "./api-client-JrgUZpe8.mjs";
3
3
  import { n as requireActiveProject } from "./project-store-CudTRvbA.mjs";
4
4
  import { t as tenantProjectHeaders } from "./headers-Dy5gROBB.mjs";
5
5
  import { n as writeResult, t as writeError } from "./format-DfVypHID.mjs";
6
- import { r as toLocalDateTime } from "./util-pyTg7qwY.mjs";
6
+ import { r as toLocalDateTime } from "./util-BuoFIeLS.mjs";
7
7
  import { defineCommand } from "citty";
8
8
  //#region src/commands/visit/summary.ts
9
9
  /**