weaver-work-cli 0.1.29 → 0.1.32

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 (185) hide show
  1. package/dist/chunks/archive-UMGX72K6.js +2537 -0
  2. package/dist/chunks/archive-oa-N2IYBLF3.js +1317 -0
  3. package/dist/chunks/asset-GLEGKFG5.js +2109 -0
  4. package/dist/chunks/attachment-content-AQNX5N3S.js +23 -0
  5. package/dist/chunks/blog-E44OTVDA.js +2157 -0
  6. package/dist/chunks/caizhilian-DQUFZXZL.js +10087 -0
  7. package/dist/chunks/calendar-JKPIRKFD.js +1195 -0
  8. package/dist/chunks/chunk-2GA5ZIQL.js +1615 -0
  9. package/dist/chunks/chunk-4YC43QQ4.js +403 -0
  10. package/dist/chunks/chunk-6EFWDL7Y.js +161 -0
  11. package/dist/chunks/chunk-6RKD4DRZ.js +5556 -0
  12. package/dist/chunks/chunk-AJ62BGAW.js +29 -0
  13. package/dist/chunks/chunk-BUSC6UAE.js +43 -0
  14. package/dist/chunks/chunk-C6R3B2ML.js +358 -0
  15. package/dist/chunks/chunk-CVZ2JOSW.js +62 -0
  16. package/dist/chunks/chunk-DW6AUUKS.js +508 -0
  17. package/dist/chunks/chunk-E4Z23GHM.js +6962 -0
  18. package/dist/chunks/chunk-EG6ZU444.js +654 -0
  19. package/dist/chunks/chunk-EZALDOQH.js +383 -0
  20. package/dist/chunks/chunk-FMPJJYYI.js +106 -0
  21. package/dist/chunks/chunk-G2JSIUWF.js +769 -0
  22. package/dist/chunks/chunk-G3QJULO2.js +387 -0
  23. package/dist/chunks/chunk-GCG2NMWR.js +703 -0
  24. package/dist/chunks/chunk-GPMFD4RD.js +75 -0
  25. package/dist/chunks/chunk-H6XSTSLM.js +2357 -0
  26. package/dist/chunks/chunk-H7J4DC5R.js +464 -0
  27. package/dist/chunks/chunk-IURUFGZK.js +477 -0
  28. package/dist/chunks/chunk-LUSPKZKY.js +53 -0
  29. package/dist/chunks/chunk-NIAJ5ZCG.js +73 -0
  30. package/dist/chunks/chunk-NOODWMCL.js +584 -0
  31. package/dist/chunks/chunk-OOUTBLZ4.js +51 -0
  32. package/dist/chunks/chunk-P26ZWSKU.js +73 -0
  33. package/dist/chunks/chunk-QWY6PGL6.js +3472 -0
  34. package/dist/chunks/chunk-WKI2FBIQ.js +15606 -0
  35. package/dist/chunks/chunk-WSKBSQ2U.js +231 -0
  36. package/dist/chunks/chunk-YLCYX7LE.js +371 -0
  37. package/dist/chunks/chunk-YRVDW4WN.js +205 -0
  38. package/dist/chunks/chunk-ZEDWSH32.js +68 -0
  39. package/dist/chunks/continuation-2CKSBLA6.js +11 -0
  40. package/dist/chunks/continuation-HZIZRZBX.js +13 -0
  41. package/dist/chunks/continuation-NLECEJPX.js +11 -0
  42. package/dist/chunks/ebuilder-form-V5FG2EHC.js +2276 -0
  43. package/dist/chunks/ehr-HMFY6VIL.js +5241 -0
  44. package/dist/chunks/employee-SAK2QYXX.js +11 -0
  45. package/dist/chunks/esb-ZYSVB7SG.js +141 -0
  46. package/dist/chunks/fna-B7RKPAZD.js +1444 -0
  47. package/dist/chunks/host-45WED2KK.js +21 -0
  48. package/dist/chunks/host-I4Z6BFYX.js +23 -0
  49. package/dist/chunks/host-KNZ52LJZ.js +17 -0
  50. package/dist/chunks/host-OCH2BCCV.js +19 -0
  51. package/dist/chunks/hrm-2KAZGUHI.js +244 -0
  52. package/dist/chunks/im-ACJJWH4U.js +252 -0
  53. package/dist/chunks/invoice-ZK3WCX2U.js +5179 -0
  54. package/dist/chunks/jiuchuanhui-5PQD3IL2.js +1940 -0
  55. package/dist/chunks/lazy-dispatch-JQXBW3GM.js +28 -0
  56. package/dist/chunks/mail-S2HDDXO2.js +2695 -0
  57. package/dist/chunks/meeting-QVN3I37L.js +504 -0
  58. package/dist/chunks/msg-parse-4GSQ2WTO.js +41 -0
  59. package/dist/chunks/okr-QNG4VC2Q.js +2482 -0
  60. package/dist/chunks/plan-A25EMW6U.js +2025 -0
  61. package/dist/chunks/project-G6XV66DZ.js +1361 -0
  62. package/dist/chunks/registry-2VLUAESA.js +14 -0
  63. package/dist/chunks/registry-7C5UMIPL.js +19 -0
  64. package/dist/chunks/registry-DC6KR3NH.js +18 -0
  65. package/dist/chunks/registry-NYPYMZXG.js +16 -0
  66. package/dist/chunks/registry-TI3CIUXF.js +19 -0
  67. package/dist/chunks/room-recommend-WRTHO6Y2.js +20 -0
  68. package/dist/chunks/schedule-KFIITGSK.js +24 -0
  69. package/dist/chunks/state-Y2XBP6YE.js +15 -0
  70. package/dist/chunks/workflow-DJ7SYWAF.js +245 -0
  71. package/dist/cmd/argv.js +45 -0
  72. package/dist/cmd/docs/index.js +3 -3
  73. package/dist/cmd/lazy-dispatch.js +20 -0
  74. package/dist/cmd/root.js +2 -4
  75. package/dist/cmd/setup/index.js +2 -2
  76. package/dist/cmd/skills/index.js +2 -2
  77. package/dist/core/package-paths.js +61 -0
  78. package/dist/index.js +163 -7
  79. package/dist/internal/e10/auth/xiaoe.js +3 -3
  80. package/dist/internal/e10/request-runtime.js +18 -62
  81. package/dist/internal/skills/detector.js +2 -2
  82. package/dist/shortcuts/contract/data/performance-catalog.js +1306 -0
  83. package/dist/shortcuts/contract/host.js +91 -35
  84. package/dist/shortcuts/contract/index.js +213 -0
  85. package/dist/shortcuts/contract/manifest.js +928 -0
  86. package/dist/shortcuts/contract/ooxml/docx.js +295 -0
  87. package/dist/shortcuts/contract/ooxml/xlsx.js +221 -0
  88. package/dist/shortcuts/contract/ooxml/zip.js +158 -0
  89. package/dist/shortcuts/contract/operations/assistant.js +1156 -0
  90. package/dist/shortcuts/contract/operations/clause-library.js +522 -0
  91. package/dist/shortcuts/contract/operations/compare.js +193 -0
  92. package/dist/shortcuts/contract/operations/credit-page.js +34 -0
  93. package/dist/shortcuts/contract/operations/flow.js +98 -0
  94. package/dist/shortcuts/contract/operations/page.js +66 -0
  95. package/dist/shortcuts/contract/operations/performance.js +733 -0
  96. package/dist/shortcuts/contract/operations/quote.js +557 -0
  97. package/dist/shortcuts/contract/operations/recommend.js +78 -0
  98. package/dist/shortcuts/contract/operations/registry.js +18 -0
  99. package/dist/shortcuts/contract/operations/review.js +83 -0
  100. package/dist/shortcuts/contract/operations/shared.js +37 -0
  101. package/dist/shortcuts/contract/operations/upload.js +108 -0
  102. package/dist/shortcuts/contract/operations/write.js +3 -2
  103. package/dist/shortcuts/index.js +140 -40
  104. package/dist/shortcuts/invoice/manifest.js +34 -11
  105. package/dist/shortcuts/invoice/operations/reim-auto.js +9 -0
  106. package/dist/shortcuts/invoice/operations/reim.js +81 -5
  107. package/dist/shortcuts/invoice/operations/shared.js +12 -5
  108. package/dist/shortcuts/meeting/host.js +45 -3
  109. package/dist/shortcuts/meeting/invitation/docx.js +442 -0
  110. package/dist/shortcuts/meeting/operations/attachment-content.js +418 -0
  111. package/dist/shortcuts/meeting/operations/attachment.js +442 -0
  112. package/dist/shortcuts/meeting/operations/eb/cache.js +57 -0
  113. package/dist/shortcuts/meeting/operations/eb/catalog.js +343 -28
  114. package/dist/shortcuts/meeting/operations/eb/conflict.js +372 -11
  115. package/dist/shortcuts/meeting/operations/eb/create-flow.js +710 -0
  116. package/dist/shortcuts/meeting/operations/eb/decision.js +47 -1
  117. package/dist/shortcuts/meeting/operations/eb/factory.js +129 -11
  118. package/dist/shortcuts/meeting/operations/eb/index.js +122 -2
  119. package/dist/shortcuts/meeting/operations/eb/room-recommend.js +378 -0
  120. package/dist/shortcuts/meeting/operations/eb/room-summary.js +84 -0
  121. package/dist/shortcuts/meeting/operations/eb/schedule.js +450 -0
  122. package/dist/shortcuts/meeting/operations/from-group-chat.js +576 -0
  123. package/dist/shortcuts/meeting/operations/invitation.js +458 -0
  124. package/dist/shortcuts/meeting/operations/minute-content.js +266 -0
  125. package/dist/shortcuts/meeting/operations/pipeline.js +489 -0
  126. package/dist/shortcuts/meeting/operations/qrcode.js +131 -0
  127. package/dist/shortcuts/meeting/operations/receipts.js +1 -1
  128. package/dist/shortcuts/meeting/operations/registry.js +18 -0
  129. package/dist/shortcuts/meeting/operations/summary.js +276 -0
  130. package/dist/shortcuts/meeting/operations/task-notify.js +325 -0
  131. package/dist/shortcuts/meeting/operations.js +42 -1
  132. package/dist/shortcuts/meeting/qr/encoder.js +427 -0
  133. package/dist/shortcuts/meeting/qr/render.js +103 -0
  134. package/dist/shortcuts/workflow/operations/form.js +17 -5
  135. package/docs/contract.md +39 -4
  136. package/docs/invoice.md +5 -5
  137. package/package.json +3 -2
  138. package/scripts/bundle.mjs +63 -0
  139. package/skill-template/business-info.json +25 -4
  140. package/skill-template/domains/jinchengda.md +16 -3
  141. package/skill-template/domains/yepiaotong.md +1 -1
  142. package/skills/weaver-e10-jinchengda/SKILL.md +111 -31
  143. package/skills/weaver-e10-jinchengda/references/contract-agent-entry.md +7 -13
  144. package/skills/weaver-e10-jinchengda/references/contract-ai-assistant.md +150 -0
  145. package/skills/weaver-e10-jinchengda/references/contract-ai-review.md +87 -0
  146. package/skills/weaver-e10-jinchengda/references/contract-clause-library-crud.md +111 -0
  147. package/skills/weaver-e10-jinchengda/references/contract-clause-recommender.md +0 -15
  148. package/skills/weaver-e10-jinchengda/references/contract-clause-reference-save.md +0 -13
  149. package/skills/weaver-e10-jinchengda/references/contract-credit-page.md +50 -0
  150. package/skills/weaver-e10-jinchengda/references/contract-disabled-capabilities.md +4 -2
  151. package/skills/weaver-e10-jinchengda/references/contract-doc-compare.md +74 -0
  152. package/skills/weaver-e10-jinchengda/references/contract-flow-launch.md +84 -0
  153. package/skills/weaver-e10-jinchengda/references/contract-performance-query.md +29 -0
  154. package/skills/weaver-e10-jinchengda/references/contract-quote-to-contract.md +28 -0
  155. package/skills/weaver-e10-jinchengda/references/contract-request-status.md +2 -21
  156. package/skills/weaver-e10-jinchengda/references/contract-request-write.md +0 -24
  157. package/skills/weaver-e10-jinchengda/references/contract-signing-subjects.md +0 -15
  158. package/skills/weaver-e10-jinchengda/references/contract-subject-create.md +0 -17
  159. package/skills/weaver-e10-jinchengda/references/contract-template-recommend.md +70 -0
  160. package/skills/weaver-e10-jinchengda/references/contract-template-selector.md +0 -15
  161. package/skills/weaver-e10-jinchengda/references/contract-workflow-discovery.md +0 -15
  162. package/skills/weaver-e10-jinchengda/references/source-manifest.json +1168 -152
  163. package/skills/weaver-e10-meeting/SKILL.md +493 -17
  164. package/skills/weaver-e10-meeting/references/meeting-change.md +4 -4
  165. package/skills/weaver-e10-meeting/references/meeting-create.md +6 -6
  166. package/skills/weaver-e10-meeting/references/meeting-eb.md +503 -27
  167. package/skills/weaver-e10-meeting/references/meeting-invitation.md +113 -0
  168. package/skills/weaver-e10-meeting/references/meeting-lifecycle.md +6 -6
  169. package/skills/weaver-e10-meeting/references/meeting-minute-file.md +425 -0
  170. package/skills/weaver-e10-meeting/references/meeting-queries.md +4 -4
  171. package/skills/weaver-e10-meeting/references/meeting-receipts-signs.md +15 -15
  172. package/skills/weaver-e10-meeting/references/meeting-verification.md +19 -11
  173. package/skills/weaver-e10-meeting.zip +0 -0
  174. package/skills/weaver-e10-yepiaotong/SKILL.md +9 -5
  175. package/skills/weaver-e10-yepiaotong/references/invoice-enterprise-list.md +1 -1
  176. package/skills/weaver-e10-yepiaotong/references/invoice-personal-list.md +6 -5
  177. package/skills/weaver-e10-yepiaotong/references/invoice-reim.md +14 -11
  178. package/skills/weaver-e10-yepiaotong/references/reim-api-reference.md +97 -56
  179. package/skills/weaver-e10-yepiaotong/references/reim-examples.md +84 -60
  180. package/skills/weaver-e10-yepiaotong/references/reim-form-fill-rules.md +142 -105
  181. package/skills/weaver-e10-yepiaotong/references/reim-matching-rules.md +53 -194
  182. package/skills/weaver-e10-yepiaotong/references/reim-phone-subsidy-rules.md +7 -7
  183. package/skills/weaver-e10-yepiaotong/references/reim-workflow.md +164 -72
  184. package/skills/weaver-e10-yepiaotong/references/source-manifest.json +6 -0
  185. package/templates/meeting/invitation.docx +0 -0
@@ -0,0 +1,2157 @@
1
+ import { createRequire as __esbuildCreateRequire } from 'node:module';
2
+ const require = __esbuildCreateRequire(import.meta.url);
3
+ import {
4
+ createE10RequestRuntime,
5
+ requireE10Session
6
+ } from "./chunk-DW6AUUKS.js";
7
+ import {
8
+ E10_SESSION_EXPIRED_MESSAGE,
9
+ getActiveProfile
10
+ } from "./chunk-2GA5ZIQL.js";
11
+ import {
12
+ CliError,
13
+ isCliError,
14
+ toErrorEnvelope
15
+ } from "./chunk-LUSPKZKY.js";
16
+ import "./chunk-BUSC6UAE.js";
17
+
18
+ // src/shortcuts/blog/index.ts
19
+ import { readFile as readFile2 } from "node:fs/promises";
20
+
21
+ // src/shortcuts/blog/continuation.ts
22
+ import { createHmac, randomBytes, timingSafeEqual } from "node:crypto";
23
+ import { existsSync } from "node:fs";
24
+ import { chmod, mkdir, readFile, writeFile } from "node:fs/promises";
25
+ import { homedir } from "node:os";
26
+ import { resolve } from "node:path";
27
+
28
+ // src/shortcuts/blog/errors.ts
29
+ var BlogCliError = class extends CliError {
30
+ type;
31
+ subtype;
32
+ code;
33
+ retryable;
34
+ stage;
35
+ details;
36
+ partialData;
37
+ constructor(type, subtype, message, options = {}) {
38
+ super(message, options.exitCode ?? 5 /* InternalError */);
39
+ this.name = "BlogCliError";
40
+ this.type = type;
41
+ this.subtype = subtype;
42
+ this.code = options.code;
43
+ this.retryable = options.retryable ?? false;
44
+ this.stage = options.stage;
45
+ this.details = options.details;
46
+ this.partialData = options.partialData;
47
+ }
48
+ };
49
+ function blogValidationError(subtype, message, details) {
50
+ return new BlogCliError("validation", subtype, message, {
51
+ details,
52
+ exitCode: 2 /* UsageError */
53
+ });
54
+ }
55
+ function blogAuthError(subtype, message, details) {
56
+ return new BlogCliError("authentication", subtype, message, {
57
+ details,
58
+ exitCode: 3 /* AuthError */
59
+ });
60
+ }
61
+ function blogNetworkError(subtype, message, options = {}) {
62
+ return new BlogCliError("network", subtype, message, {
63
+ ...options,
64
+ retryable: options.retryable ?? true,
65
+ exitCode: 4 /* NetworkError */
66
+ });
67
+ }
68
+ function blogConfirmationError(action, details) {
69
+ return new BlogCliError("confirmation", "required", "\u8BE5\u64CD\u4F5C\u9700\u8981\u660E\u786E\u786E\u8BA4", {
70
+ details: { action, ...details },
71
+ exitCode: 10 /* ConfirmationRequired */
72
+ });
73
+ }
74
+ function blogPartialError(message, partialData, details) {
75
+ return new BlogCliError("partial", "write_uncertain", message, {
76
+ details,
77
+ partialData,
78
+ exitCode: 11 /* Partial */
79
+ });
80
+ }
81
+ function isBlogNetworkError(error) {
82
+ return Boolean(
83
+ error && typeof error === "object" && "type" in error && error.type === "network"
84
+ );
85
+ }
86
+
87
+ // src/shortcuts/blog/continuation.ts
88
+ function stateRoot(ctx) {
89
+ const configured = ctx?.config?.path();
90
+ if (configured) return resolve(configured, "..");
91
+ return process.env.WEAVER_WORK_CLI_HOME || process.env.WORK_CLI_HOME || resolve(homedir(), ".weaver-work-cli");
92
+ }
93
+ async function loadKey(ctx) {
94
+ const keysDir = resolve(stateRoot(ctx), "keys");
95
+ const filename = resolve(keysDir, "blog-continuation.key");
96
+ await mkdir(keysDir, { recursive: true, mode: 448 });
97
+ if (existsSync(filename)) return readFile(filename);
98
+ const key = randomBytes(32);
99
+ try {
100
+ await writeFile(filename, key, { flag: "wx", mode: 384 });
101
+ if (process.platform !== "win32") await chmod(filename, 384).catch(() => void 0);
102
+ return key;
103
+ } catch {
104
+ return readFile(filename);
105
+ }
106
+ }
107
+ function encode(value) {
108
+ return Buffer.from(JSON.stringify(value)).toString("base64url");
109
+ }
110
+ function signature(payload, key) {
111
+ return createHmac("sha256", key).update(payload).digest("base64url");
112
+ }
113
+ function createBlogContinuationSigner(ctx) {
114
+ return {
115
+ async issue(payload, ttlMs = 10 * 6e4) {
116
+ const issuedAt = Date.now();
117
+ const body = encode({ ...payload, issuedAt, expiresAt: issuedAt + ttlMs });
118
+ const sig = signature(body, await loadKey(ctx));
119
+ return `${body}.${sig}`;
120
+ },
121
+ async verify(token, expectedOperation) {
122
+ if (typeof token !== "string" || !token.includes(".")) {
123
+ throw blogValidationError("continuation_invalid", "continuation \u65E0\u6548");
124
+ }
125
+ const [body, provided] = token.split(".");
126
+ const expected = signature(body, await loadKey(ctx));
127
+ const valid = provided.length === expected.length && timingSafeEqual(Buffer.from(provided), Buffer.from(expected));
128
+ if (!valid) throw blogValidationError("continuation_invalid", "continuation \u7B7E\u540D\u6821\u9A8C\u5931\u8D25");
129
+ let value;
130
+ try {
131
+ value = JSON.parse(Buffer.from(body, "base64url").toString("utf8"));
132
+ } catch {
133
+ throw blogValidationError("continuation_invalid", "continuation \u5185\u5BB9\u65E0\u6CD5\u89E3\u6790");
134
+ }
135
+ if (value.operation !== expectedOperation) {
136
+ throw blogValidationError("continuation_mismatch", "continuation \u4E0D\u5C5E\u4E8E\u5F53\u524D\u64CD\u4F5C");
137
+ }
138
+ if (!Number.isSafeInteger(value.expiresAt) || value.expiresAt < Date.now()) {
139
+ throw blogValidationError("continuation_expired", "continuation \u5DF2\u8FC7\u671F");
140
+ }
141
+ return value;
142
+ }
143
+ };
144
+ }
145
+
146
+ // src/shortcuts/blog/host.ts
147
+ var MAX_EXPORT_BYTES = 50 * 1024 * 1024;
148
+ var SESSION_EXPIRED_CODES = /* @__PURE__ */ new Set(["-2", -2]);
149
+ function assertPath(requestPath) {
150
+ if (typeof requestPath !== "string" || !requestPath.startsWith("/") || requestPath.startsWith("//")) {
151
+ throw blogValidationError("path_invalid", "\u8BF7\u6C42\u8DEF\u5F84\u5FC5\u987B\u662F\u76F8\u5BF9\u7EDD\u5BF9\u8DEF\u5F84");
152
+ }
153
+ if (/^https?:/i.test(requestPath) || /[\r\n]/.test(requestPath) || requestPath.includes("/../")) {
154
+ throw blogValidationError("path_invalid", "\u8BF7\u6C42\u8DEF\u5F84\u4E0D\u5141\u8BB8\u8DE8\u57DF\u6216\u8DEF\u5F84\u9003\u9038");
155
+ }
156
+ if (!requestPath.startsWith("/api/")) {
157
+ throw blogValidationError("path_not_allowed", "\u65E5\u62A5\u6A21\u5757\u53EA\u80FD\u8C03\u7528 /api/ \u8DEF\u5F84");
158
+ }
159
+ }
160
+ function responseCode(value) {
161
+ return value?.code ?? value?.res_base?.ret ?? value?.data?.res_base?.ret;
162
+ }
163
+ function responseMessage(value) {
164
+ if (typeof value?.msg === "string") return value.msg;
165
+ if (typeof value?.message === "string") return value.message;
166
+ if (typeof value?.error === "string") return value.error;
167
+ return "\u6CDB\u5FAE\u63A5\u53E3\u8FD4\u56DE\u4E1A\u52A1\u5931\u8D25";
168
+ }
169
+ function isSessionExpired(value) {
170
+ const code = responseCode(value);
171
+ return code !== void 0 && SESSION_EXPIRED_CODES.has(code);
172
+ }
173
+ function isBusinessFailure(value) {
174
+ if (value?.fail === true) return true;
175
+ const code = responseCode(value);
176
+ if (code === void 0 || code === null) return false;
177
+ return !SESSION_EXPIRED_CODES.has(code) && code !== 0 && code !== "0" && code !== 200 && code !== "200";
178
+ }
179
+ function inferProfile(ctx) {
180
+ const options = ctx.getGlobalOptions();
181
+ return options.profile || getActiveProfile();
182
+ }
183
+ function createBlogHost(ctx, dependencies = {}) {
184
+ let e10Session = null;
185
+ let sessionContext = null;
186
+ const requireSession = dependencies.requireSession || requireE10Session;
187
+ async function ensureSession() {
188
+ if (!e10Session) {
189
+ e10Session = await requireSession(ctx);
190
+ sessionContext = {
191
+ baseUrl: e10Session.getBaseUrl(),
192
+ profile: inferProfile(ctx),
193
+ userId: e10Session.userId
194
+ };
195
+ }
196
+ return e10Session;
197
+ }
198
+ async function getSession() {
199
+ await ensureSession();
200
+ return sessionContext;
201
+ }
202
+ async function runtime() {
203
+ return createE10RequestRuntime(ctx, await ensureSession(), {
204
+ interceptors: dependencies.interceptors,
205
+ fetch: dependencies.fetch
206
+ });
207
+ }
208
+ function assertSession(value) {
209
+ if (isSessionExpired(value)) {
210
+ throw blogAuthError("session_expired", E10_SESSION_EXPIRED_MESSAGE);
211
+ }
212
+ }
213
+ async function blogRequest(request) {
214
+ const { method = "POST", path, query, body, operation, timeoutMs = 3e4 } = request;
215
+ assertPath(path);
216
+ const response = await (await runtime()).requestJson({
217
+ module: "blog",
218
+ operation,
219
+ method,
220
+ path,
221
+ query,
222
+ body,
223
+ timeoutMs
224
+ });
225
+ if (response.status === 401 || response.status === 302) {
226
+ throw blogAuthError("session_expired", E10_SESSION_EXPIRED_MESSAGE, { httpStatus: response.status });
227
+ }
228
+ if (response.parseError) {
229
+ if (response.status < 200 || response.status >= 300) {
230
+ throw new BlogCliError("api", "http_error", `\u6CDB\u5FAE\u63A5\u53E3 HTTP ${response.status}`, {
231
+ code: response.status,
232
+ details: { status: response.status },
233
+ exitCode: 1 /* GeneralError */
234
+ });
235
+ }
236
+ throw blogNetworkError("protocol", `\u63A5\u53E3\u8FD4\u56DE\u4E0D\u662F\u5408\u6CD5 JSON\uFF08HTTP ${response.status}\uFF09`, { retryable: false });
237
+ }
238
+ if (response.status < 200 || response.status >= 300) {
239
+ throw new BlogCliError("api", "http_error", `\u6CDB\u5FAE\u63A5\u53E3 HTTP ${response.status}`, {
240
+ code: response.status,
241
+ details: { status: response.status, message: responseMessage(response.value) },
242
+ exitCode: 1 /* GeneralError */
243
+ });
244
+ }
245
+ assertSession(response.value);
246
+ if (isBusinessFailure(response.value)) {
247
+ throw new BlogCliError("api", "business_error", responseMessage(response.value), {
248
+ code: String(responseCode(response.value)),
249
+ details: { response: response.value },
250
+ exitCode: 1 /* GeneralError */
251
+ });
252
+ }
253
+ return response.value;
254
+ }
255
+ async function blogBinaryRequest(request) {
256
+ const { method = "POST", path, query, body, operation, timeoutMs = 6e4 } = request;
257
+ assertPath(path);
258
+ const response = await (await runtime()).requestBinary({
259
+ module: "blog",
260
+ operation,
261
+ method,
262
+ path,
263
+ query,
264
+ body,
265
+ timeoutMs,
266
+ headers: { Accept: "application/octet-stream, */*" }
267
+ });
268
+ if (response.status === 401 || response.status === 302) {
269
+ throw blogAuthError("session_expired", E10_SESSION_EXPIRED_MESSAGE, { httpStatus: response.status });
270
+ }
271
+ const contentType = response.contentType;
272
+ const declaredLength = Number(response.headers.get("content-length"));
273
+ if (Number.isFinite(declaredLength) && declaredLength > MAX_EXPORT_BYTES) {
274
+ throw blogNetworkError("response_too_large", `\u5BFC\u51FA\u6587\u4EF6\u8D85\u8FC7 ${MAX_EXPORT_BYTES} \u5B57\u8282\u9650\u5236`, { retryable: false });
275
+ }
276
+ const content = response.content;
277
+ const looksLikeJson = /^[\s\r\n]*[[{]/.test(content.subarray(0, 64).toString("utf8"));
278
+ if (response.status < 200 || response.status >= 300 || contentType.includes("json") || looksLikeJson) {
279
+ let value = {};
280
+ try {
281
+ value = JSON.parse(content.toString("utf8"));
282
+ } catch {
283
+ value = {};
284
+ }
285
+ assertSession(value);
286
+ throw new BlogCliError("api", "export_failed", responseMessage(value) || `\u5BFC\u51FA\u5931\u8D25\uFF08HTTP ${response.status}\uFF09`, {
287
+ code: response.status,
288
+ details: { status: response.status, preview: content.subarray(0, 500).toString("utf8") },
289
+ exitCode: 1 /* GeneralError */
290
+ });
291
+ }
292
+ if (!content.length) {
293
+ throw blogNetworkError("protocol", "\u5BFC\u51FA\u63A5\u53E3\u8FD4\u56DE\u7A7A\u6587\u4EF6", { retryable: false });
294
+ }
295
+ if (content.length > MAX_EXPORT_BYTES) {
296
+ throw blogNetworkError("response_too_large", `\u5BFC\u51FA\u6587\u4EF6\u8D85\u8FC7 ${MAX_EXPORT_BYTES} \u5B57\u8282\u9650\u5236`, { retryable: false });
297
+ }
298
+ return { content, contentType };
299
+ }
300
+ return {
301
+ blogRequest,
302
+ blogBinaryRequest,
303
+ getSession
304
+ };
305
+ }
306
+
307
+ // src/shortcuts/blog/manifest.ts
308
+ var DATE = "^\\d{4}-\\d{2}-\\d{2}$";
309
+ var POSITIVE_ID = { type: "string", pattern: "^[1-9]\\d*$" };
310
+ var CONFIRM_SCHEMA = {
311
+ type: "object",
312
+ additionalProperties: false,
313
+ properties: {
314
+ continuation: { type: "string", minLength: 1, description: "prepare \u8FD4\u56DE\u7684\u786E\u8BA4\u4EE4\u724C\uFF08HMAC \u7B7E\u53D1\uFF0C10 \u5206\u949F\u6709\u6548\uFF09" },
315
+ confirm: { const: true, description: "\u5FC5\u987B\u663E\u5F0F\u4E3A true\uFF0C\u5426\u5219 CLI \u62D2\u7EDD\u5199\u5165" }
316
+ },
317
+ required: ["continuation", "confirm"]
318
+ };
319
+ var blogOperations = [
320
+ {
321
+ name: "blog.query",
322
+ risk: "read",
323
+ summary: "\u7FA4\u4F53\u65E5\u62A5\u67E5\u8BE2\uFF08\u76F4\u63A5/\u95F4\u63A5/\u5168\u90E8\u4E0B\u5C5E\u3001\u6211\u5173\u6CE8\u7684\u4EBA\uFF09\uFF0C\u7A97\u53E3\u88C1\u526A\u5728\u5BA2\u6237\u7AEF\u5B8C\u6210",
324
+ fixed: { blogType: "order", timezoneOffset: -8 },
325
+ inputSchema: {
326
+ type: "object",
327
+ additionalProperties: false,
328
+ properties: {
329
+ user_type: {
330
+ type: "string",
331
+ enum: ["directSubordinate", "indirectSubordinate", "allSubordinate", "myFollow"],
332
+ description: "\u4EBA\u5458\u8303\u56F4\uFF1AdirectSubordinate=\u76F4\u63A5\u4E0B\u5C5E\uFF0CindirectSubordinate=\u95F4\u63A5\u4E0B\u5C5E\uFF0CallSubordinate=\u5168\u90E8\u4E0B\u5C5E\uFF0CmyFollow=\u6211\u5173\u6CE8\u7684\u4EBA\u3002\u67E5\u6307\u5B9A\u4E2A\u4EBA\u8BF7\u6539\u7528 blog.query_user\u3002"
333
+ },
334
+ start_date: { type: "string", pattern: DATE, description: "\u7A97\u53E3\u8D77\u59CB\u65E5\u671F\uFF08\u5BA2\u6237\u7AEF\u88C1\u526A\u7528\uFF09" },
335
+ end_date: { type: "string", pattern: DATE, description: "\u7A97\u53E3\u7ED3\u675F\u65E5\u671F\uFF08\u542B\uFF09\uFF1B\u533A\u95F4\u6309\u5929\u8BA1\u6570\uFF0C\u4E0A\u9650 62 \u5929" },
336
+ keywords: { type: "string", description: "\u6309\u5185\u5BB9\u5173\u952E\u5B57\u670D\u52A1\u7AEF\u6A21\u7CCA\u8FC7\u6EE4\uFF0C\u53EF\u4F20\u7A7A\u4E32" },
337
+ page_size: { type: "integer", minimum: 1, maximum: 300, default: 300, description: "\u670D\u52A1\u7AEF\u5355\u9875\u8FD4\u56DE\u884C\u6570\uFF08\u4E0A\u9650 300\uFF09\u3002\u884C\u6570 \u2248 \u4EBA\u6570 \xD7 \u5929\u6570\uFF0C\u7A97\u53E3\u5927\u65F6\u4FDD\u6301\u9ED8\u8BA4 300 \u4EE5\u5C3D\u91CF\u8986\u76D6" },
338
+ page_no: { type: "integer", minimum: 1, default: 1, description: "\u900F\u4F20\u9875\u7801\uFF1B\u670D\u52A1\u7AEF\u5B9E\u6D4B\u5FFD\u7565 pageNo\uFF08\u8FD4\u56DE\u540C\u4E00\u6279\u6570\u636E\uFF09\uFF0C\u8C03\u5927\u4E0D\u4F1A\u62FF\u5230\u66F4\u591A\u6570\u636E" }
339
+ },
340
+ required: ["user_type", "start_date", "end_date"]
341
+ },
342
+ inputExamples: [
343
+ {
344
+ name: "\u67E5\u6211\u5173\u6CE8\u7684\u4EBA\u672C\u5468\u65E5\u62A5",
345
+ input: { user_type: "myFollow", start_date: "2026-09-14", end_date: "2026-09-18" },
346
+ source: "scripts/query-weaver-e10-blog.mjs\uFF08--userType myfollow \u7528\u6CD5\uFF09",
347
+ sourceType: "source-provided"
348
+ },
349
+ {
350
+ name: "\u67E5\u76F4\u63A5\u4E0B\u5C5E\u65E5\u62A5",
351
+ input: { user_type: "directSubordinate", start_date: "2026-09-01", end_date: "2026-09-30" },
352
+ source: "SKILL.md \u80FD\u529B\u8868\uFF08\u4E0B\u5C5E\u65E5\u62A5\u67E5\u8BE2\u573A\u666F\uFF09",
353
+ sourceType: "source-provided"
354
+ }
355
+ ]
356
+ },
357
+ {
358
+ name: "blog.query_user",
359
+ risk: "read",
360
+ summary: "\u5355\u4EBA\u65E5\u62A5\u9010\u65E5\u626B\u63CF\uFF08detailsByDate\uFF09\uFF0C\u533A\u95F4\u4E0A\u9650 62 \u5929\uFF1B\u67E5\u6307\u5B9A\u4E2A\u4EBA\u7684\u552F\u4E00\u53EF\u9760\u8DEF\u5F84",
361
+ inputSchema: {
362
+ type: "object",
363
+ additionalProperties: false,
364
+ properties: {
365
+ user_id: { ...POSITIVE_ID, description: "\u76EE\u6807\u4EBA\u5458 userId\uFF1B\u4E0E name \u4E8C\u9009\u4E00\uFF0C\u90FD\u7F3A\u7701\u65F6\u67E5\u5F53\u524D\u767B\u5F55\u4EBA\u7684\u65E5\u62A5" },
366
+ name: { type: "string", minLength: 1, description: "\u76EE\u6807\u4EBA\u5458\u59D3\u540D\uFF0C\u7ECF HRM \u7CBE\u786E\u89E3\u6790\uFF1B\u4E0E user_id \u4E8C\u9009\u4E00\uFF0C\u540C\u540D\u591A\u547D\u4E2D\u65F6\u62A5\u9519\u5E76\u5217\u51FA\u5019\u9009" },
367
+ date: { type: "string", pattern: DATE, description: "\u8D77\u59CB\u65E5\u671F YYYY-MM-DD" },
368
+ end_date: { type: "string", pattern: DATE, description: "\u7ED3\u675F\u65E5\u671F\uFF08\u542B\uFF09\uFF0C\u7F3A\u7701\u65F6\u53EA\u67E5 date \u5F53\u5929\uFF1B\u533A\u95F4\u6309\u5929\u626B\u63CF\uFF0C\u4E0A\u9650 62 \u5929" }
369
+ },
370
+ required: ["date"]
371
+ },
372
+ inputExamples: [
373
+ {
374
+ name: "\u6309\u59D3\u540D\u67E5\u67D0\u5929\u65E5\u62A5",
375
+ input: { name: "\u7AE0\u667A\u6DB5", date: "2026-08-18" },
376
+ source: "scripts/query-day.mjs \u7528\u6CD5\u793A\u4F8B\uFF08node query-day.mjs 2026-08-18 --name \u7AE0\u667A\u6DB5\uFF09",
377
+ sourceType: "source-provided"
378
+ },
379
+ {
380
+ name: "\u6309 userId \u67E5\u4E00\u6BB5\u65E5\u62A5",
381
+ input: { user_id: "1077039731822690306", date: "2026-08-17", end_date: "2026-08-20" },
382
+ source: "scripts/query-day.mjs \u7528\u6CD5\u793A\u4F8B\uFF08--userId 1077039731822690306\uFF09",
383
+ sourceType: "source-provided"
384
+ }
385
+ ]
386
+ },
387
+ {
388
+ name: "blog.resolve_users",
389
+ risk: "read",
390
+ summary: "HRM \u6309\u59D3\u540D\u7CBE\u786E\u89E3\u6790 userId\uFF08\u53D6 id \u5B57\u6BB5\uFF0C\u4E0D\u662F userid\uFF09",
391
+ inputSchema: {
392
+ type: "object",
393
+ additionalProperties: false,
394
+ properties: {
395
+ name: { type: "string", minLength: 1, description: "\u5458\u5DE5\u59D3\u540D\uFF08\u7CBE\u786E\u5339\u914D\uFF09" }
396
+ },
397
+ required: ["name"]
398
+ },
399
+ inputExamples: [
400
+ {
401
+ name: "\u6309\u59D3\u540D\u89E3\u6790",
402
+ input: { name: "\u7AE0\u667A\u6DB5" },
403
+ source: "scripts/query-weaver-e10-blog.mjs\uFF08HRM \u89E3\u6790\u59D3\u540D\u6BB5\uFF09",
404
+ sourceType: "source-provided"
405
+ }
406
+ ]
407
+ },
408
+ {
409
+ name: "blog.comments",
410
+ risk: "read",
411
+ summary: "\u67E5\u67D0\u6761\u65E5\u62A5\u7684\u8BC4\u8BBA\u5217\u8868\uFF08commentPage\uFF09",
412
+ fixed: { module: "blog", foldCommentList: false },
413
+ inputSchema: {
414
+ type: "object",
415
+ additionalProperties: false,
416
+ properties: {
417
+ blog_id: { ...POSITIVE_ID, description: "\u65E5\u62A5\u8BB0\u5F55 id\uFF08detailsByDate \u7684 blog.id\uFF09" },
418
+ page_no: { type: "integer", minimum: 1, maximum: 1e4, default: 1 },
419
+ page_size: { type: "integer", minimum: 1, maximum: 100, default: 20 }
420
+ },
421
+ required: ["blog_id"]
422
+ },
423
+ inputExamples: [
424
+ {
425
+ name: "\u67E5\u67D0\u65E5\u62A5\u8BC4\u8BBA",
426
+ input: { blog_id: "1310837921662951425" },
427
+ source: "scripts/query-comments.mjs\uFF08--blogId \u5165\u53C2\uFF09",
428
+ sourceType: "source-provided"
429
+ }
430
+ ]
431
+ },
432
+ {
433
+ name: "blog.default_permission",
434
+ risk: "read",
435
+ summary: "\u67E5\u67D0\u65E5\u671F\u7684\u9ED8\u8BA4\u5171\u4EAB\u5BF9\u8C61\uFF0C\u4F9B\u53D1\u5E03\u65F6\u56DE\u586B permissionList",
436
+ inputSchema: {
437
+ type: "object",
438
+ additionalProperties: false,
439
+ properties: {
440
+ date: { type: "string", pattern: DATE, description: "\u65E5\u62A5\u5F52\u5C5E\u65E5\u671F\uFF0C\u8FD4\u56DE\u7684 data.list \u53EF\u76F4\u63A5\u4F5C\u4E3A\u53D1\u5E03\u65F6\u7684\u5171\u4EAB\u5BF9\u8C61" }
441
+ },
442
+ required: ["date"]
443
+ },
444
+ inputExamples: [
445
+ {
446
+ name: "\u67E5\u9ED8\u8BA4\u5171\u4EAB\uFF08\u6309\u65E5\u671F\uFF09",
447
+ input: { date: "2026-08-19" },
448
+ source: "references/daily-report-blog-get-default-permission.md\uFF08blogTime \u5165\u53C2\uFF09",
449
+ sourceType: "source-provided"
450
+ }
451
+ ]
452
+ },
453
+ {
454
+ name: "blog.export",
455
+ risk: "local-file-write",
456
+ summary: "\u5BFC\u51FA\u65E5\u62A5\u62A5\u8868\u4E3A xlsx\uFF08\u62D2\u7EDD\u8986\u76D6\u5DF2\u6709\u6587\u4EF6\uFF09",
457
+ fixed: { blogType: "all", searchType: "all", disableType: "all", isNeedConvert: false },
458
+ inputSchema: {
459
+ type: "object",
460
+ additionalProperties: false,
461
+ properties: {
462
+ start_date: { type: "string", pattern: DATE },
463
+ end_date: { type: "string", pattern: DATE },
464
+ output: { type: "string", minLength: 1, description: "\u672C\u5730\u8F93\u51FA .xlsx \u8DEF\u5F84\uFF1B\u6587\u4EF6\u5DF2\u5B58\u5728\u65F6\u62D2\u7EDD\u8986\u76D6" },
465
+ page_size: { type: "integer", minimum: 1, maximum: 500, default: 200 }
466
+ },
467
+ required: ["start_date", "end_date", "output"]
468
+ },
469
+ inputExamples: [
470
+ {
471
+ name: "\u5BFC\u51FA\u67D0\u6708\u65E5\u62A5",
472
+ input: { start_date: "2026-08-01", end_date: "2026-08-31", output: "C:/path/to/aug.xlsx" },
473
+ source: "scripts/export-blog.mjs \u7528\u6CD5\u793A\u4F8B\uFF08node export-blog.mjs 2026-08-01 2026-08-31 --out ...\uFF09",
474
+ sourceType: "source-provided"
475
+ }
476
+ ]
477
+ },
478
+ {
479
+ name: "blog.publish.prepare",
480
+ risk: "read-before-write",
481
+ summary: "\u53D1\u5E03\u51C6\u5907\uFF1A\u67E5\u5F53\u65E5\u662F\u5426\u5DF2\u6709\u65E5\u62A5 + \u56DE\u586B\u9ED8\u8BA4\u5171\u4EAB + \u7B7E\u53D1 continuation\uFF08\u4E0D\u5199\u6570\u636E\uFF09",
482
+ inputSchema: {
483
+ type: "object",
484
+ additionalProperties: false,
485
+ properties: {
486
+ date: { type: "string", pattern: DATE, description: "\u65E5\u62A5\u5F52\u5C5E\u65E5\u671F\uFF08\u53EA\u80FD\u53D1\u5E03\u5F53\u524D\u767B\u5F55\u4EBA\u81EA\u5DF1\u7684\u65E5\u62A5\uFF09" },
487
+ content: { type: "string", minLength: 1, description: "\u65E5\u62A5\u6B63\u6587\uFF1B\u7EAF\u6587\u672C\u81EA\u52A8\u5305\u88F9 <p>\uFF0CHTML \u539F\u6837\u4FDD\u7559" },
488
+ share_default: { type: "boolean", default: true, description: "\u662F\u5426\u56DE\u586B\u8BE5\u65E5\u671F\u7684\u9ED8\u8BA4\u5171\u4EAB\u5BF9\u8C61\uFF1Bfalse \u8868\u793A\u4EC5\u81EA\u5DF1\u53EF\u89C1" }
489
+ },
490
+ required: ["date", "content"]
491
+ },
492
+ inputExamples: [
493
+ {
494
+ name: "\u51C6\u5907\u53D1\u5E03\u67D0\u65E5\u65E5\u62A5",
495
+ input: { date: "2026-08-19", content: "<p>\u4ECA\u65E5\u5DE5\u4F5C\u603B\u7ED3</p>", share_default: true },
496
+ source: 'scripts/publish-blog.mjs \u7528\u6CD5\u793A\u4F8B\uFF08node publish-blog.mjs 2026-08-14 "<p>\u8865\u4EA4\u5185\u5BB9</p>" --share\uFF09',
497
+ sourceType: "source-provided"
498
+ }
499
+ ]
500
+ },
501
+ {
502
+ name: "blog.publish.apply",
503
+ risk: "high-risk-write",
504
+ summary: "\u53D1\u5E03\u843D\u5E93\uFF1A\u6821\u9A8C continuation \u4E0E\u5199\u524D\u72B6\u6001\u540E\u8C03\u7528 addBlog\uFF0C\u5E76\u56DE\u67E5\u9A8C\u8BC1",
505
+ inputSchema: CONFIRM_SCHEMA,
506
+ missingExamples: [
507
+ {
508
+ reason: "apply \u7684\u552F\u4E00\u5165\u53C2\u662F prepare \u5F53\u573A\u7B7E\u53D1\u7684 continuation\uFF0C\u6E90\u8D44\u6599\u4E0D\u63D0\u4F9B\u56FA\u5B9A\u6837\u4F8B",
509
+ missingFacts: ["continuation"],
510
+ source: "scripts/publish-blog.mjs\uFF08\u65E0 continuation \u6982\u5FF5\uFF09"
511
+ }
512
+ ]
513
+ },
514
+ {
515
+ name: "blog.edit.prepare",
516
+ risk: "read-before-write",
517
+ summary: "\u7F16\u8F91\u51C6\u5907\uFF1A\u56DE\u67E5\u539F\u5185\u5BB9\u4E0E\u5DEE\u5F02 + \u76EE\u6807\u6307\u7EB9 + \u7B7E\u53D1 continuation\uFF08\u4E0D\u5199\u6570\u636E\uFF09",
518
+ inputSchema: {
519
+ type: "object",
520
+ additionalProperties: false,
521
+ properties: {
522
+ user_id: { ...POSITIVE_ID, description: "\u76EE\u6807\u4EBA\u5458 userId\uFF1B\u4E0E name \u4E8C\u9009\u4E00\uFF1B\u90FD\u4E0D\u4F20\u65F6\u7F16\u8F91\u5F53\u524D\u767B\u5F55\u4EBA\u7684\u65E5\u62A5" },
523
+ name: { type: "string", minLength: 1, description: "\u76EE\u6807\u4EBA\u5458\u59D3\u540D\uFF1B\u4E0E user_id \u4E8C\u9009\u4E00" },
524
+ date: { type: "string", pattern: DATE },
525
+ content: { type: "string", minLength: 1, description: "\u65B0\u65E5\u62A5\u6B63\u6587\uFF1B\u7EAF\u6587\u672C\u81EA\u52A8\u5305\u88F9 <p>" }
526
+ },
527
+ required: ["date", "content"]
528
+ },
529
+ inputExamples: [
530
+ {
531
+ name: "\u51C6\u5907\u7F16\u8F91\u81EA\u5DF1\u7684\u65E5\u62A5",
532
+ input: { date: "2026-08-19", content: "<p>\u4FEE\u6B63\u540E\u7684\u5185\u5BB9</p>" },
533
+ source: "scripts/edit-blog.mjs\uFF08blogTime + content \u5165\u53C2\uFF09",
534
+ sourceType: "source-provided"
535
+ }
536
+ ]
537
+ },
538
+ {
539
+ name: "blog.edit.apply",
540
+ risk: "high-risk-write",
541
+ summary: "\u7F16\u8F91\u843D\u5E93\uFF1A\u76EE\u6807\u6307\u7EB9\u6821\u9A8C\u540E\u8C03\u7528 updateBlog\uFF0C\u5E76\u56DE\u67E5\u5185\u5BB9\u4E00\u81F4\u6027",
542
+ inputSchema: CONFIRM_SCHEMA,
543
+ missingExamples: [
544
+ {
545
+ reason: "apply \u7684\u552F\u4E00\u5165\u53C2\u662F prepare \u5F53\u573A\u7B7E\u53D1\u7684 continuation\uFF0C\u6E90\u8D44\u6599\u4E0D\u63D0\u4F9B\u56FA\u5B9A\u6837\u4F8B",
546
+ missingFacts: ["continuation"],
547
+ source: "scripts/edit-blog.mjs\uFF08\u65E0 continuation \u6982\u5FF5\uFF09"
548
+ }
549
+ ]
550
+ },
551
+ {
552
+ name: "blog.comment.prepare",
553
+ risk: "read-before-write",
554
+ summary: "\u8BC4\u8BBA\u51C6\u5907\uFF1A\u5B9A\u4F4D\u76EE\u6807\u65E5\u62A5\uFF08blog_id \u6216 date+user\uFF09\u540E\u7B7E\u53D1 continuation",
555
+ inputSchema: {
556
+ type: "object",
557
+ additionalProperties: false,
558
+ properties: {
559
+ blog_id: { ...POSITIVE_ID, description: "\u65E5\u62A5\u8BB0\u5F55 id\uFF1B\u4E0E date\uFF08+ user_id/name\uFF09\u4E8C\u9009\u4E00" },
560
+ user_id: POSITIVE_ID,
561
+ name: { type: "string", minLength: 1 },
562
+ date: { type: "string", pattern: DATE },
563
+ content: { type: "string", minLength: 1, description: "\u8BC4\u8BBA\u5185\u5BB9" }
564
+ },
565
+ required: ["content"],
566
+ anyOf: [{ required: ["blog_id"] }, { required: ["date"] }]
567
+ },
568
+ inputExamples: [
569
+ {
570
+ name: "\u6309\u65E5\u671F\u5B9A\u4F4D\u5E76\u8BC4\u8BBA",
571
+ input: { date: "2026-08-19", content: "\u6536\u5230\uFF0C\u8BF7\u8865\u9F50\u660E\u7EC6" },
572
+ source: "scripts/comment-blog.mjs\uFF08blogId \u6216 date+name \u5B9A\u4F4D\uFF09",
573
+ sourceType: "source-provided"
574
+ }
575
+ ]
576
+ },
577
+ {
578
+ name: "blog.comment.apply",
579
+ risk: "high-risk-write",
580
+ summary: "\u8BC4\u8BBA\u843D\u5E93\uFF1AcreateComment \u540E\u4ECE\u8BC4\u8BBA\u5217\u8868\u56DE\u67E5\u8BE5\u8BC4\u8BBA",
581
+ inputSchema: CONFIRM_SCHEMA,
582
+ missingExamples: [
583
+ {
584
+ reason: "apply \u7684\u552F\u4E00\u5165\u53C2\u662F prepare \u5F53\u573A\u7B7E\u53D1\u7684 continuation\uFF0C\u6E90\u8D44\u6599\u4E0D\u63D0\u4F9B\u56FA\u5B9A\u6837\u4F8B",
585
+ missingFacts: ["continuation"],
586
+ source: "scripts/comment-blog.mjs\uFF08\u65E0 continuation \u6982\u5FF5\uFF09"
587
+ }
588
+ ]
589
+ },
590
+ {
591
+ name: "blog.like.prepare",
592
+ risk: "read-before-write",
593
+ summary: "\u70B9\u8D5E/\u53D6\u6D88\u70B9\u8D5E\u51C6\u5907\uFF1A\u5B9A\u4F4D\u76EE\u6807\u65E5\u62A5\u540E\u7B7E\u53D1 continuation",
594
+ inputSchema: {
595
+ type: "object",
596
+ additionalProperties: false,
597
+ properties: {
598
+ blog_id: { ...POSITIVE_ID, description: "\u65E5\u62A5\u8BB0\u5F55 id\uFF1B\u4E0E date\uFF08+ user_id/name\uFF09\u4E8C\u9009\u4E00" },
599
+ user_id: POSITIVE_ID,
600
+ name: { type: "string", minLength: 1 },
601
+ date: { type: "string", pattern: DATE },
602
+ cancel: { type: "boolean", default: false, description: "false=\u70B9\u8D5E\uFF08vote\uFF09\uFF0Ctrue=\u53D6\u6D88\u70B9\u8D5E\uFF08cancelVote\uFF09" }
603
+ },
604
+ anyOf: [{ required: ["blog_id"] }, { required: ["date"] }]
605
+ },
606
+ inputExamples: [
607
+ {
608
+ name: "\u6309\u65E5\u671F\u70B9\u8D5E",
609
+ input: { date: "2026-08-19" },
610
+ source: "scripts/like-blog.mjs\uFF08vote / cancelVote \u4E24\u79CD\u8DEF\u5F84\uFF09",
611
+ sourceType: "source-provided"
612
+ }
613
+ ]
614
+ },
615
+ {
616
+ name: "blog.like.apply",
617
+ risk: "high-risk-write",
618
+ summary: "\u70B9\u8D5E\u843D\u5E93\uFF1Avote / cancelVote\uFF0C\u4EE5\u4E1A\u52A1\u7801\u4E3A\u751F\u6548\u4F9D\u636E\uFF08\u65E0\u53EA\u8BFB\u56DE\u67E5\u63A5\u53E3\uFF09",
619
+ inputSchema: CONFIRM_SCHEMA,
620
+ missingExamples: [
621
+ {
622
+ reason: "apply \u7684\u552F\u4E00\u5165\u53C2\u662F prepare \u5F53\u573A\u7B7E\u53D1\u7684 continuation\uFF0C\u6E90\u8D44\u6599\u4E0D\u63D0\u4F9B\u56FA\u5B9A\u6837\u4F8B",
623
+ missingFacts: ["continuation"],
624
+ source: "scripts/like-blog.mjs\uFF08\u65E0 continuation \u6982\u5FF5\uFF09"
625
+ }
626
+ ]
627
+ },
628
+ {
629
+ name: "blog.remind.prepare",
630
+ risk: "read-before-write",
631
+ summary: "\u63D0\u9192\u51C6\u5907\uFF1A\u89E3\u6790\u88AB\u63D0\u9192\u4EBA + \u751F\u6210\u9ED8\u8BA4\u6587\u6848 + \u7B7E\u53D1 continuation\uFF08\u4E0D\u53D1\u9001\uFF09",
632
+ inputSchema: {
633
+ type: "object",
634
+ additionalProperties: false,
635
+ properties: {
636
+ user_ids: {
637
+ type: "array",
638
+ minItems: 1,
639
+ maxItems: 50,
640
+ items: POSITIVE_ID,
641
+ description: "\u88AB\u63D0\u9192\u4EBA userId \u5217\u8868\uFF08\u6216\u9017\u53F7\u5206\u9694\u5B57\u7B26\u4E32\uFF09\uFF1B\u4E0E names \u4E8C\u9009\u4E00"
642
+ },
643
+ names: {
644
+ type: "array",
645
+ minItems: 1,
646
+ maxItems: 50,
647
+ items: { type: "string", minLength: 1 },
648
+ description: "\u88AB\u63D0\u9192\u4EBA\u59D3\u540D\u5217\u8868\uFF0C\u7ECF HRM \u89E3\u6790\uFF1B\u4E0E user_ids \u4E8C\u9009\u4E00"
649
+ },
650
+ date: { type: "string", pattern: DATE, description: "\u65E5\u62A5\u5F52\u5C5E\u65E5\u671F\uFF0C\u7528\u4E8E\u9ED8\u8BA4\u6587\u6848\u4E0E\u5E74\u4EFD" },
651
+ content: { type: "string", minLength: 1, description: "\u63D0\u9192\u6587\u6848\uFF1B\u7F3A\u7701\u65F6\u751F\u6210\u300C\u8BF7\u586B\u5199 YYYY\u5E74 M\u6708 D\u65E5 \u7684\u65E5\u62A5\uFF01\u300D\uFF0C\u81EA\u5B9A\u4E49\u6587\u6848\u5FC5\u987B\u5305\u542B\u65E5\u671F" },
652
+ year: { type: "integer", minimum: 2e3, maximum: 2100, description: "\u65E5\u62A5\u6240\u5C5E\u5E74\u4EFD\uFF1B\u7F3A\u7701\u65F6\u4ECE date \u63A8\u65AD" }
653
+ },
654
+ required: ["date"],
655
+ oneOf: [{ required: ["user_ids"] }, { required: ["names"] }]
656
+ },
657
+ inputExamples: [
658
+ {
659
+ name: "\u6309 userId \u63D0\u9192\uFF08\u9ED8\u8BA4\u6587\u6848\uFF09",
660
+ input: { user_ids: ["1077039731822690306"], date: "2026-08-19" },
661
+ source: "scripts/remind-blog.mjs \u7528\u6CD5\u793A\u4F8B\uFF08--userId 1077039731822690306 --date 2026-08-19\uFF09",
662
+ sourceType: "source-provided"
663
+ },
664
+ {
665
+ name: "\u6309\u59D3\u540D\u63D0\u9192\uFF08\u81EA\u5B9A\u4E49\u6587\u6848\uFF09",
666
+ input: { names: ["\u7AE0\u667A\u6DB5"], content: "\u8BF7\u5C3D\u5FEB\u63D0\u4EA4 8 \u6708 19 \u65E5\u65E5\u62A5", year: 2026 },
667
+ source: "scripts/remind-blog.mjs \u7528\u6CD5\u793A\u4F8B\uFF08--name \u7AE0\u667A\u6DB5 --content ... --year 2026\uFF09",
668
+ sourceType: "source-provided"
669
+ }
670
+ ]
671
+ },
672
+ {
673
+ name: "blog.remind.apply",
674
+ risk: "high-risk-write",
675
+ summary: "\u63D0\u9192\u843D\u5E93\uFF1A\u9010\u4EBA POST sendUrge\uFF1B\u90E8\u5206\u5931\u8D25\u8FD4\u56DE PARTIAL\uFF0C\u4E2D\u65AD\u8FD4\u56DE write_uncertain",
676
+ inputSchema: CONFIRM_SCHEMA,
677
+ missingExamples: [
678
+ {
679
+ reason: "apply \u7684\u552F\u4E00\u5165\u53C2\u662F prepare \u5F53\u573A\u7B7E\u53D1\u7684 continuation\uFF0C\u6E90\u8D44\u6599\u4E0D\u63D0\u4F9B\u56FA\u5B9A\u6837\u4F8B",
680
+ missingFacts: ["continuation"],
681
+ source: "scripts/remind-blog.mjs\uFF08\u65E0 continuation \u6982\u5FF5\uFF09"
682
+ }
683
+ ]
684
+ }
685
+ ];
686
+ var blogManifest = {
687
+ schemaVersion: 1,
688
+ name: "blog",
689
+ title: "\u6CDB\u5FAEE10\u5DE5\u4F5C\u65E5\u62A5",
690
+ version: "0.1.0",
691
+ host: "e10-blog",
692
+ status: "builtin",
693
+ sourceSkill: "weaver-e10-blog",
694
+ capabilities: ["query", "query-user", "comments", "export", "publish", "edit", "comment", "like", "remind"],
695
+ operations: blogOperations,
696
+ withheldOperations: [
697
+ {
698
+ name: "blog.query_by_ids",
699
+ reason: "blogs \u63A5\u53E3\u7684 filter.userIds/empIds/userId/creator \u88AB\u670D\u52A1\u7AEF\u5FFD\u7565\uFF08\u5185\u7F51\u79DF\u6237\u5B9E\u6D4B\uFF0C\u6052\u5B9A\u8FD4\u56DE\u5F53\u524D\u767B\u5F55\u4EBA\u4E14 HTTP 200\uFF09\uFF0C\u6309 userId \u5217\u8868\u67E5\u4E2A\u4EBA\u4F1A\u9759\u9ED8\u53D8\u6210\u67E5\u81EA\u5DF1\uFF1B\u67E5\u6307\u5B9A\u4E2A\u4EBA\u7EDF\u4E00\u8D70 blog.query_user\uFF08detailsByDate\uFF09\u3002"
700
+ },
701
+ {
702
+ name: "blog.unread",
703
+ reason: "POST /api/blog/query/unRead \u5728\u5F53\u524D\u79DF\u6237\u591A\u79CD body \u5F62\u6001\u5B9E\u6D4B\u6052\u8FD4\u56DE\u7A7A blogList\uFF0C\u4E0D\u53EF\u4F5C\u4E3A\u6570\u636E\u6E90\u3002"
704
+ },
705
+ {
706
+ name: "blog.eb.*",
707
+ reason: "EB \u65E5\u62A5\u5E94\u7528\u63A5\u53E3\u65CF\uFF08ebuilder getFormDataList + secondev addBlog/editBlog\uFF09\u4F9D\u8D56\u79DF\u6237\u662F\u5426\u542F\u7528 EB \u65E5\u62A5\u5E94\u7528\uFF0C\u5F53\u524D\u79DF\u6237\u672A\u542F\u7528\uFF1B\u542F\u7528\u540E\u9700\u53E6\u884C\u8F6C\u6362\u5E76\u6309\u79DF\u6237\u63A2\u6D4B\u3002"
708
+ },
709
+ {
710
+ name: "blog.delete",
711
+ reason: "\u670D\u52A1\u7AEF\u672A\u63D0\u4F9B\u65E5\u62A5\u5220\u9664\u63A5\u53E3\uFF0C\u6E90\u8D44\u6599\u4EA6\u65E0\u5220\u9664\u811A\u672C\uFF1B\u4E0D\u505A\u63A8\u6D4B\u5B9E\u73B0\u3002"
712
+ },
713
+ {
714
+ name: "blog.remind.cancel",
715
+ reason: "\u5DF2\u53D1\u9001\u63D0\u9192\u65E0\u6CD5\u64A4\u56DE\uFF08\u6E90\u8D44\u6599\u65E0\u5BF9\u5E94\u63A5\u53E3\uFF09\u3002"
716
+ }
717
+ ]
718
+ };
719
+
720
+ // src/shortcuts/blog/operations/shared.ts
721
+ import { createHash } from "node:crypto";
722
+ import { existsSync as existsSync2 } from "node:fs";
723
+ import { stat, writeFile as writeFile2 } from "node:fs/promises";
724
+ import { dirname, resolve as resolve2 } from "node:path";
725
+ var DATE_PATTERN = /^\d{4}-\d{2}-\d{2}$/u;
726
+ var MAX_RANGE_DAYS = 62;
727
+ var FORBIDDEN_INPUT_KEYS = /* @__PURE__ */ new Set([
728
+ "access_token",
729
+ "app_key",
730
+ "app_secret",
731
+ "cookie",
732
+ "eteamsid",
733
+ "token",
734
+ "authorization"
735
+ ]);
736
+ var FORBIDDEN_NORMALIZED_KEYS = new Set([...FORBIDDEN_INPUT_KEYS].map((key) => key.toLowerCase()));
737
+ var USER_TYPES = ["directSubordinate", "indirectSubordinate", "allSubordinate", "myFollow"];
738
+ function asObject(value, name = "\u4E1A\u52A1\u8F93\u5165") {
739
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
740
+ throw blogValidationError("input_invalid", `${name}\u5FC5\u987B\u662F JSON \u5BF9\u8C61`);
741
+ }
742
+ return value;
743
+ }
744
+ function asNonEmptyString(value, name) {
745
+ if (typeof value !== "string" || !value.trim()) {
746
+ throw blogValidationError("input_invalid", `${name} \u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32`);
747
+ }
748
+ return value.trim();
749
+ }
750
+ function asPositiveString(value, name) {
751
+ if (typeof value !== "string" || !/^\d+$/u.test(value) || value === "0") {
752
+ throw blogValidationError("input_invalid", `${name} \u5FC5\u987B\u662F\u6B63\u6574\u6570\u6587\u672C`);
753
+ }
754
+ return value;
755
+ }
756
+ function asInteger(value, name, options) {
757
+ const { min, max, dflt } = options;
758
+ if (value === void 0 || value === null || value === "") {
759
+ if (dflt !== void 0) return dflt;
760
+ throw blogValidationError("input_invalid", `${name} \u5FC5\u987B\u662F\u6574\u6570`);
761
+ }
762
+ const parsed = typeof value === "number" ? value : Number(value);
763
+ if (!Number.isInteger(parsed) || parsed < min || parsed > max) {
764
+ throw blogValidationError("input_invalid", `${name} \u5FC5\u987B\u662F ${min}~${max} \u7684\u6574\u6570`);
765
+ }
766
+ return parsed;
767
+ }
768
+ function asDate(value, name) {
769
+ const text = typeof value === "string" ? value.trim() : "";
770
+ if (!DATE_PATTERN.test(text) || Number.isNaN(Date.parse(`${text}T00:00:00+08:00`))) {
771
+ throw blogValidationError("input_invalid", `${name} \u5FC5\u987B\u662F YYYY-MM-DD \u683C\u5F0F\u65E5\u671F`);
772
+ }
773
+ return text;
774
+ }
775
+ function normalizeUserType(value) {
776
+ if (typeof value !== "string" || !USER_TYPES.includes(value.trim())) {
777
+ throw blogValidationError("input_invalid", `user_type \u5FC5\u987B\u662F ${USER_TYPES.join(" | ")} \u4E4B\u4E00`);
778
+ }
779
+ return value.trim();
780
+ }
781
+ function assertNoForbiddenKeys(value, location = "input") {
782
+ if (!value || typeof value !== "object") return;
783
+ if (Array.isArray(value)) {
784
+ value.forEach((item, index) => assertNoForbiddenKeys(item, `${location}[${index}]`));
785
+ return;
786
+ }
787
+ for (const [key, child] of Object.entries(value)) {
788
+ if (FORBIDDEN_INPUT_KEYS.has(key) || FORBIDDEN_NORMALIZED_KEYS.has(key.toLowerCase())) {
789
+ throw blogValidationError("field_forbidden", `\u7981\u6B62\u4E1A\u52A1\u8F93\u5165\u5B57\u6BB5\uFF1A${location}.${key}`);
790
+ }
791
+ assertNoForbiddenKeys(child, `${location}.${key}`);
792
+ }
793
+ }
794
+ function pad(n) {
795
+ return String(n).padStart(2, "0");
796
+ }
797
+ function localDateStr(ms) {
798
+ const d = new Date(ms);
799
+ return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}`;
800
+ }
801
+ function localDateTimeStr(ms) {
802
+ const d = new Date(ms);
803
+ return `${localDateStr(ms)} ${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}`;
804
+ }
805
+ function dateRange(startInput, endInput, startName = "start_date", endName = "end_date") {
806
+ const start = asDate(startInput, startName);
807
+ const end = asDate(endInput, endName);
808
+ const days = [];
809
+ for (let d = /* @__PURE__ */ new Date(`${start}T00:00:00`); d <= /* @__PURE__ */ new Date(`${end}T00:00:00`); d.setDate(d.getDate() + 1)) {
810
+ days.push(`${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}`);
811
+ }
812
+ if (days.length === 0) throw blogValidationError("input_invalid", `${startName} \u4E0D\u80FD\u665A\u4E8E ${endName}`);
813
+ if (days.length > MAX_RANGE_DAYS) {
814
+ throw blogValidationError("range_too_large", `\u65E5\u671F\u533A\u95F4\u5171 ${days.length} \u5929\uFF0C\u8D85\u8FC7 ${MAX_RANGE_DAYS} \u5929\u4E0A\u9650\uFF1B\u8BF7\u7F29\u5C0F\u8303\u56F4\u540E\u91CD\u8BD5`);
815
+ }
816
+ return days;
817
+ }
818
+ function remindContent(date) {
819
+ const d = /* @__PURE__ */ new Date(`${date}T00:00:00`);
820
+ return `\u8BF7\u586B\u5199 ${d.getFullYear()}\u5E74 ${d.getMonth() + 1}\u6708 ${d.getDate()}\u65E5 \u7684\u65E5\u62A5\uFF01`;
821
+ }
822
+ function remindYear(date) {
823
+ return (/* @__PURE__ */ new Date(`${date}T00:00:00`)).getFullYear();
824
+ }
825
+ function htmlToText(html) {
826
+ return html.replace(/<[^>]+>/g, "").trim();
827
+ }
828
+ function ensureHtml(content) {
829
+ return /^\s*</u.test(content) ? content : `<p>${content}</p>`;
830
+ }
831
+ function canonicalJson(value) {
832
+ if (Array.isArray(value)) return `[${value.map(canonicalJson).join(",")}]`;
833
+ if (value && typeof value === "object") {
834
+ return `{${Object.keys(value).sort().map((key) => `${JSON.stringify(key)}:${canonicalJson(value[key])}`).join(",")}}`;
835
+ }
836
+ return JSON.stringify(value);
837
+ }
838
+ function objectFingerprint(value) {
839
+ return createHash("sha256").update(canonicalJson(value)).digest("hex");
840
+ }
841
+ function sessionMatches(lease, session) {
842
+ return lease.baseUrl === session.baseUrl && (lease.profile ?? "") === (session.profile ?? "") && lease.userId === session.userId;
843
+ }
844
+ function detailsFound(value) {
845
+ return Boolean(value?.blog && typeof value.blog === "object" && value.blog.id);
846
+ }
847
+ function submitStatus(blog) {
848
+ if (blog.create_time === null || blog.blog_time === null) return "\u8865\u4EA4";
849
+ return localDateStr(blog.create_time) === localDateStr(blog.blog_time) ? "\u6B63\u5E38" : "\u8865\u4EA4";
850
+ }
851
+ function normalizeBlog(raw) {
852
+ if (!raw || typeof raw !== "object" || !raw.id) return null;
853
+ const createTime = typeof raw.createTime === "number" ? raw.createTime : null;
854
+ const blogTime = typeof raw.blogTime === "number" ? raw.blogTime : null;
855
+ const content = typeof raw.content === "string" ? raw.content : "";
856
+ return {
857
+ id: String(raw.id),
858
+ create_time: createTime,
859
+ create_time_str: createTime === null ? null : localDateTimeStr(createTime),
860
+ blog_time: blogTime,
861
+ blog_time_str: blogTime === null ? null : localDateStr(blogTime),
862
+ content,
863
+ content_text: htmlToText(content),
864
+ comment_count: typeof raw.commentCount === "number" ? raw.commentCount : null,
865
+ praise_count: typeof raw.praiseCount === "number" ? raw.praiseCount : null,
866
+ later: typeof raw.later === "number" ? raw.later : null
867
+ };
868
+ }
869
+ function normalizeBlogListItem(item) {
870
+ if (!item || typeof item !== "object") return null;
871
+ const date = typeof item.date === "number" ? item.date : Number(item.date);
872
+ if (!Number.isFinite(date)) return null;
873
+ const userId = String(item.user?.id ?? "");
874
+ const username = String(item.user?.username ?? item.user?.name ?? "");
875
+ const blog = normalizeBlog(item.blog);
876
+ return {
877
+ date,
878
+ date_str: localDateStr(date),
879
+ user_id: userId,
880
+ username,
881
+ blog,
882
+ submitted: Boolean(blog),
883
+ submit_status: blog ? submitStatus(blog) : "\u672A\u63D0\u4EA4"
884
+ };
885
+ }
886
+ async function searchUsersByName(host, name) {
887
+ const body = {
888
+ browserMultiple: true,
889
+ authWecahtBook: false,
890
+ wxDepNeedConvertCount: 0,
891
+ wxEmpNeedConvertCount: 0,
892
+ wxTotalNeedConvertCount: 0,
893
+ cmd: "all",
894
+ current: 1,
895
+ pageSize: 30,
896
+ formDatas: {
897
+ username: [{ usernameOpt: "eq", usernameInput: name }],
898
+ status: [{ statusSelect: ["normal"] }],
899
+ subcompany: [{ subcompanyOpt: "in" }],
900
+ department: [{ departmentOpt: "in" }],
901
+ role: [{ roleOpt: "in" }],
902
+ position: [{ positionOpt: "in" }],
903
+ superior: [{ superiorOpt: "in" }]
904
+ },
905
+ quickSearchDatas: {},
906
+ type: "and",
907
+ containsNoneAccount: false,
908
+ containsPartTimeEmployee: false
909
+ };
910
+ const countResp = await host.blogRequest({ path: "/api/hrm/common/browser/count/resource", body, operation: "blog.resolve_users" });
911
+ const total = countResp?.data?.total ?? 0;
912
+ if (!total) return [];
913
+ const dataResp = await host.blogRequest({ path: "/api/hrm/common/browser/data/resource", body, operation: "blog.resolve_users" });
914
+ const rows = Array.isArray(dataResp?.data?.data) ? dataResp.data.data : [];
915
+ return rows.map((row) => ({
916
+ id: String(row.id ?? ""),
917
+ name: String(row.name ?? row.username ?? ""),
918
+ department: String(row.department ?? "")
919
+ })).filter((user) => user.id);
920
+ }
921
+ async function resolveUserId(input, host) {
922
+ if (input.user_id !== void 0 && input.name !== void 0) {
923
+ throw blogValidationError("input_ambiguous", "user_id \u4E0E name \u53EA\u80FD\u63D0\u4F9B\u4E00\u4E2A");
924
+ }
925
+ if (input.user_id !== void 0) {
926
+ return { userId: asPositiveString(input.user_id, "user_id"), userName: null };
927
+ }
928
+ if (input.name !== void 0) {
929
+ const name = asNonEmptyString(input.name, "name");
930
+ const users = await searchUsersByName(host, name);
931
+ if (users.length === 0) {
932
+ throw blogValidationError("name_not_found", `\u672A\u627E\u5230\u540D\u4E3A\u300C${name}\u300D\u7684\u5458\u5DE5`);
933
+ }
934
+ if (users.length > 1) {
935
+ throw blogValidationError("name_ambiguous", `\u300C${name}\u300D\u547D\u4E2D ${users.length} \u540D\u5458\u5DE5\uFF0C\u8BF7\u6539\u7528 user_id \u6307\u5B9A`, { candidates: users });
936
+ }
937
+ return { userId: users[0].id, userName: users[0].name };
938
+ }
939
+ throw blogValidationError("input_invalid", "user_id \u4E0E name \u5FC5\u987B\u63D0\u4F9B\u4E00\u4E2A");
940
+ }
941
+ async function resolveTargetUser(input, host) {
942
+ if (input.user_id === void 0 && input.name === void 0) {
943
+ const session = await host.getSession();
944
+ return { userId: session.userId, userName: null };
945
+ }
946
+ return resolveUserId(input, host);
947
+ }
948
+ async function fetchDetailsByDate(host, date, userId) {
949
+ const value = await host.blogRequest({
950
+ method: "GET",
951
+ path: "/api/blog/prior/detailsByDate",
952
+ query: { date, userId },
953
+ operation: "blog.query_user"
954
+ });
955
+ const found = detailsFound(value);
956
+ return { found, raw: value, blog: found ? normalizeBlog(value.blog) : null };
957
+ }
958
+ async function resolveTargetBlog(input, host, action) {
959
+ if (input.blog_id !== void 0 && (input.date !== void 0 || input.user_id !== void 0 || input.name !== void 0)) {
960
+ throw blogValidationError("input_ambiguous", "blog_id \u4E0E date/user_id/name \u53EA\u80FD\u63D0\u4F9B\u4E00\u4E2A");
961
+ }
962
+ if (input.blog_id !== void 0) {
963
+ return { blogId: asPositiveString(input.blog_id, "blog_id"), blog: null, date: null, userId: null };
964
+ }
965
+ const date = asDate(input.date, "date");
966
+ const { userId, userName } = await resolveTargetUser(input, host);
967
+ const detail = await fetchDetailsByDate(host, date, userId);
968
+ if (!detail.found || !detail.blog) {
969
+ throw blogValidationError("target_missing", `\u5BF9\u5E94\u65E5\u671F ${date} \u4EBA\u5458 ${userName ?? userId} \u65E0\u65E5\u62A5\uFF0C\u65E0\u6CD5${action}`);
970
+ }
971
+ return { blogId: detail.blog.id, blog: detail.blog, date, userId };
972
+ }
973
+ async function resolveExportOutput(output) {
974
+ if (typeof output !== "string" || !output.trim()) {
975
+ throw blogValidationError("output_required", "output \u5FC5\u987B\u662F\u660E\u786E\u7684\u672C\u5730\u6587\u4EF6\u8DEF\u5F84");
976
+ }
977
+ const resolved = resolve2(output);
978
+ let parent;
979
+ try {
980
+ parent = await stat(dirname(resolved));
981
+ } catch {
982
+ throw blogValidationError("output_parent_missing", `\u8F93\u51FA\u76EE\u5F55\u4E0D\u5B58\u5728\uFF1A${dirname(resolved)}`);
983
+ }
984
+ if (!parent.isDirectory()) {
985
+ throw blogValidationError("output_parent_invalid", "\u8F93\u51FA\u6587\u4EF6\u7684\u7236\u8DEF\u5F84\u4E0D\u662F\u76EE\u5F55");
986
+ }
987
+ if (existsSync2(resolved)) {
988
+ throw blogValidationError("output_exists", `\u8F93\u51FA\u6587\u4EF6\u5DF2\u5B58\u5728\uFF0C\u62D2\u7EDD\u8986\u76D6\uFF1A${resolved}`);
989
+ }
990
+ return resolved;
991
+ }
992
+ async function writeExportFile(resolved, content) {
993
+ try {
994
+ await writeFile2(resolved, content, { flag: "wx", mode: 384 });
995
+ } catch (error) {
996
+ if (error && typeof error === "object" && "code" in error && error.code === "EEXIST") {
997
+ throw blogValidationError("output_exists", `\u8F93\u51FA\u6587\u4EF6\u5DF2\u5B58\u5728\uFF0C\u62D2\u7EDD\u8986\u76D6\uFF1A${resolved}`);
998
+ }
999
+ throw error;
1000
+ }
1001
+ }
1002
+
1003
+ // src/shortcuts/blog/operations/comments.ts
1004
+ var BlogCommentsOperation = class {
1005
+ name = "blog.comments";
1006
+ async execute(input, { host }) {
1007
+ const blogId = asPositiveString(input.blog_id, "blog_id");
1008
+ const pageNo = asInteger(input.page_no, "page_no", { min: 1, max: 1e4, dflt: 1 });
1009
+ const pageSize = asInteger(input.page_size, "page_size", { min: 1, max: 100, dflt: 20 });
1010
+ const value = await host.blogRequest({
1011
+ path: "/api/blog/common/comment/commentPage",
1012
+ body: {
1013
+ pageNo,
1014
+ pageSize,
1015
+ targetId: blogId,
1016
+ module: "blog",
1017
+ foldCommentList: false
1018
+ },
1019
+ operation: "blog.comments"
1020
+ });
1021
+ const page = value?.data?.page ?? {};
1022
+ return {
1023
+ status: "COMPLETE",
1024
+ data: {
1025
+ blog_id: blogId,
1026
+ total_count: page.totalCount ?? null,
1027
+ page_no: page.pageNo ?? pageNo,
1028
+ page_size: page.pageSize ?? pageSize,
1029
+ comments: Array.isArray(page.result) ? page.result : []
1030
+ }
1031
+ };
1032
+ }
1033
+ };
1034
+
1035
+ // src/shortcuts/blog/operations/types.ts
1036
+ function workflow(name, state) {
1037
+ return { name, state };
1038
+ }
1039
+
1040
+ // src/shortcuts/blog/operations/comment.ts
1041
+ var BlogCommentPrepareOperation = class {
1042
+ name = "blog.comment.prepare";
1043
+ async execute(input, { host, continuation }) {
1044
+ const content = typeof input.content === "string" ? input.content.trim() : "";
1045
+ if (!content) throw blogValidationError("input_invalid", "content \u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32");
1046
+ const target = await resolveTargetBlog(input, host, "\u8BC4\u8BBA");
1047
+ const session = await host.getSession();
1048
+ const continuationToken = await continuation.issue({
1049
+ operation: "blog.comment.apply",
1050
+ workflow: workflow("blog.comment", "AWAITING_CONFIRMATION"),
1051
+ baseUrl: session.baseUrl,
1052
+ profile: session.profile,
1053
+ userId: session.userId,
1054
+ blogId: target.blogId,
1055
+ content,
1056
+ fingerprint: objectFingerprint(target.blog ? { id: target.blog.id, content: target.blog.content } : { id: target.blogId })
1057
+ });
1058
+ return {
1059
+ status: "AWAITING_CONFIRMATION",
1060
+ data: {
1061
+ blog_id: target.blogId,
1062
+ target: target.date ? { date: target.date, user_id: target.userId } : void 0,
1063
+ target_content_text: target.blog?.content_text,
1064
+ comment: content,
1065
+ continuation: continuationToken,
1066
+ expires_in_seconds: 600,
1067
+ workflow: workflow("blog.comment", "AWAITING_CONFIRMATION"),
1068
+ next: "\u5411\u7528\u6237\u590D\u8FF0\u76EE\u6807\u65E5\u62A5\u4E0E\u8BC4\u8BBA\u5185\u5BB9\uFF0C\u7528\u6237\u786E\u8BA4\u540E\u8C03\u7528 blog.comment.apply \u5E76\u4F20 confirm=true"
1069
+ }
1070
+ };
1071
+ }
1072
+ };
1073
+ var BlogCommentApplyOperation = class {
1074
+ name = "blog.comment.apply";
1075
+ async execute(input, { host, continuation }) {
1076
+ if (input.confirm !== true) {
1077
+ throw blogConfirmationError("blog.comment.apply", { hint: "\u91CD\u65B0\u8C03\u7528\u65F6\u4F20\u5165 confirm=true" });
1078
+ }
1079
+ const lease = await continuation.verify(input.continuation, "blog.comment.apply");
1080
+ if (typeof lease.blogId !== "string" || typeof lease.content !== "string") {
1081
+ throw blogValidationError("continuation_invalid", "\u8BC4\u8BBA continuation \u7F3A\u5C11\u6709\u6548\u76EE\u6807\u6216\u5185\u5BB9");
1082
+ }
1083
+ const session = await host.getSession();
1084
+ if (!sessionMatches(lease, session)) {
1085
+ throw blogValidationError("context_mismatch", "\u786E\u8BA4\u4E0A\u4E0B\u6587\u5DF2\u53D8\u5316\uFF0C\u8BF7\u91CD\u65B0\u51C6\u5907\u8BC4\u8BBA");
1086
+ }
1087
+ let result;
1088
+ try {
1089
+ result = await host.blogRequest({
1090
+ path: "/api/blog/common/comment/createComment",
1091
+ body: {
1092
+ comment: {
1093
+ targetId: lease.blogId,
1094
+ disableMessage: false,
1095
+ relevanceList: [],
1096
+ imAtContent: lease.content,
1097
+ atLinkList: [],
1098
+ content: lease.content,
1099
+ originContent: lease.content,
1100
+ module: "blog"
1101
+ },
1102
+ attachments: "",
1103
+ attachmentsList: [],
1104
+ client: "pc"
1105
+ },
1106
+ operation: "blog.comment.apply"
1107
+ });
1108
+ } catch (error) {
1109
+ if (isBlogNetworkError(error)) {
1110
+ throw blogPartialError("\u8BC4\u8BBA\u8BF7\u6C42\u53D1\u9001\u540E\u8FDE\u63A5\u4E2D\u65AD\uFF0C\u7ED3\u679C\u4E0D\u786E\u5B9A\uFF0C\u7981\u6B62\u81EA\u52A8\u91CD\u8BD5", {
1111
+ blog_id: lease.blogId,
1112
+ workflow: workflow("blog.comment", "EXECUTING")
1113
+ }, { stage: "comment" });
1114
+ }
1115
+ throw error;
1116
+ }
1117
+ let verified = false;
1118
+ let commentId = null;
1119
+ try {
1120
+ const page = await host.blogRequest({
1121
+ path: "/api/blog/common/comment/commentPage",
1122
+ body: { pageNo: 1, pageSize: 50, targetId: lease.blogId, module: "blog", foldCommentList: false },
1123
+ operation: "blog.comment.apply"
1124
+ });
1125
+ const comments = Array.isArray(page?.data?.page?.result) ? page.data.page.result : [];
1126
+ const matched = comments.find((item) => item?.content === lease.content);
1127
+ if (matched?.id) {
1128
+ verified = true;
1129
+ commentId = String(matched.id);
1130
+ }
1131
+ } catch {
1132
+ throw blogPartialError("\u8BC4\u8BBA\u63A5\u53E3\u5DF2\u8FD4\u56DE\u6210\u529F\uFF0C\u4F46\u8BC4\u8BBA\u5217\u8868\u56DE\u67E5\u5931\u8D25\uFF0C\u7ED3\u679C\u4E0D\u786E\u5B9A", {
1133
+ blog_id: lease.blogId,
1134
+ result,
1135
+ workflow: workflow("blog.comment", "VERIFYING")
1136
+ }, { stage: "readback" });
1137
+ }
1138
+ if (!verified) {
1139
+ throw blogPartialError("\u8BC4\u8BBA\u63A5\u53E3\u5DF2\u8FD4\u56DE\u6210\u529F\uFF0C\u4F46\u8BC4\u8BBA\u5217\u8868\u4E2D\u672A\u627E\u5230\u8BE5\u8BC4\u8BBA", {
1140
+ blog_id: lease.blogId,
1141
+ result,
1142
+ workflow: workflow("blog.comment", "VERIFYING")
1143
+ }, { stage: "readback" });
1144
+ }
1145
+ return {
1146
+ status: "COMPLETE",
1147
+ data: {
1148
+ blog_id: lease.blogId,
1149
+ comment_id: commentId,
1150
+ verified: true,
1151
+ result,
1152
+ workflow: workflow("blog.comment", "COMPLETE")
1153
+ }
1154
+ };
1155
+ }
1156
+ };
1157
+
1158
+ // src/shortcuts/blog/operations/edit.ts
1159
+ var BlogEditPrepareOperation = class {
1160
+ name = "blog.edit.prepare";
1161
+ async execute(input, { host, continuation }) {
1162
+ const date = asDate(input.date, "date");
1163
+ const rawContent = typeof input.content === "string" ? input.content.trim() : "";
1164
+ if (!rawContent) throw blogValidationError("input_invalid", "content \u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32");
1165
+ const content = ensureHtml(rawContent);
1166
+ const { userId, userName } = await resolveTargetUser(input, host);
1167
+ const detail = await fetchDetailsByDate(host, date, userId);
1168
+ if (!detail.found || !detail.blog) {
1169
+ throw blogValidationError("edit_target_missing", `\u5BF9\u5E94\u65E5\u671F ${date} \u4EBA\u5458 ${userName ?? userId} \u65E0\u65E5\u62A5\uFF0C\u4E0D\u53EF\u7F16\u8F91\uFF1B\u5982\u9700\u65B0\u5EFA\u8BF7\u4F7F\u7528 blog.publish.prepare`);
1170
+ }
1171
+ const original = detail.blog;
1172
+ const originalText = htmlToText(original.content);
1173
+ const newText = htmlToText(content);
1174
+ if (originalText === newText) {
1175
+ throw blogValidationError("changes_noop", "\u65B0\u5185\u5BB9\u4E0E\u5F53\u524D\u65E5\u62A5\u5185\u5BB9\u76F8\u540C");
1176
+ }
1177
+ const session = await host.getSession();
1178
+ const continuationToken = await continuation.issue({
1179
+ operation: "blog.edit.apply",
1180
+ workflow: workflow("blog.edit", "AWAITING_CONFIRMATION"),
1181
+ baseUrl: session.baseUrl,
1182
+ profile: session.profile,
1183
+ userId: session.userId,
1184
+ date,
1185
+ targetUserId: userId,
1186
+ blogId: original.id,
1187
+ content,
1188
+ fingerprint: objectFingerprint(original)
1189
+ });
1190
+ return {
1191
+ status: "AWAITING_CONFIRMATION",
1192
+ data: {
1193
+ date,
1194
+ target: { user_id: userId, name: userName },
1195
+ blog_id: original.id,
1196
+ original: { content: original.content, content_text: originalText, submit_time: original.create_time_str },
1197
+ new: { content, content_text: newText },
1198
+ continuation: continuationToken,
1199
+ expires_in_seconds: 600,
1200
+ workflow: workflow("blog.edit", "AWAITING_CONFIRMATION"),
1201
+ next: "\u5411\u7528\u6237\u590D\u8FF0\u539F\u5185\u5BB9\u4E0E\u65B0\u5185\u5BB9\uFF0C\u7528\u6237\u786E\u8BA4\u540E\u8C03\u7528 blog.edit.apply \u5E76\u4F20 confirm=true"
1202
+ }
1203
+ };
1204
+ }
1205
+ };
1206
+ var BlogEditApplyOperation = class {
1207
+ name = "blog.edit.apply";
1208
+ async execute(input, { host, continuation }) {
1209
+ if (input.confirm !== true) {
1210
+ throw blogConfirmationError("blog.edit.apply", { hint: "\u91CD\u65B0\u8C03\u7528\u65F6\u4F20\u5165 confirm=true" });
1211
+ }
1212
+ const lease = await continuation.verify(input.continuation, "blog.edit.apply");
1213
+ if (typeof lease.blogId !== "string" || typeof lease.content !== "string" || typeof lease.fingerprint !== "string") {
1214
+ throw blogValidationError("continuation_invalid", "\u7F16\u8F91 continuation \u7F3A\u5C11\u6709\u6548\u76EE\u6807\u3001\u5185\u5BB9\u6216\u6307\u7EB9");
1215
+ }
1216
+ const session = await host.getSession();
1217
+ if (!sessionMatches(lease, session)) {
1218
+ throw blogValidationError("context_mismatch", "\u786E\u8BA4\u4E0A\u4E0B\u6587\u5DF2\u53D8\u5316\uFF0C\u8BF7\u91CD\u65B0\u51C6\u5907\u7F16\u8F91");
1219
+ }
1220
+ const current = await fetchDetailsByDate(host, lease.date, lease.targetUserId);
1221
+ if (!current.found || !current.blog || objectFingerprint(current.blog) !== lease.fingerprint) {
1222
+ throw blogValidationError("target_changed", "\u65E5\u62A5\u5728\u786E\u8BA4\u540E\u53D1\u751F\u53D8\u5316\uFF0C\u8BF7\u91CD\u65B0\u51C6\u5907\u7F16\u8F91");
1223
+ }
1224
+ let result;
1225
+ try {
1226
+ result = await host.blogRequest({
1227
+ path: "/api/blog/prior/updateBlog",
1228
+ body: {
1229
+ timezoneOffset: -8,
1230
+ blog: {
1231
+ id: lease.blogId,
1232
+ content: lease.content,
1233
+ client: "pc",
1234
+ attachmentIds: "",
1235
+ atLinkList: [],
1236
+ isTm: 0,
1237
+ isDbCheck: 0
1238
+ }
1239
+ },
1240
+ operation: "blog.edit.apply"
1241
+ });
1242
+ } catch (error) {
1243
+ if (isBlogNetworkError(error)) {
1244
+ throw blogPartialError("\u7F16\u8F91\u8BF7\u6C42\u53D1\u9001\u540E\u8FDE\u63A5\u4E2D\u65AD\uFF0C\u7ED3\u679C\u4E0D\u786E\u5B9A\uFF0C\u7981\u6B62\u81EA\u52A8\u91CD\u8BD5\uFF1B\u8BF7\u5148\u7528 blog.query_user \u56DE\u67E5", {
1245
+ blog_id: lease.blogId,
1246
+ workflow: workflow("blog.edit", "EXECUTING")
1247
+ }, { stage: "update" });
1248
+ }
1249
+ throw error;
1250
+ }
1251
+ const after = await fetchDetailsByDate(host, lease.date, lease.targetUserId);
1252
+ if (!after.found || !after.blog) {
1253
+ throw blogPartialError("\u7F16\u8F91\u63A5\u53E3\u5DF2\u8FD4\u56DE\u6210\u529F\uFF0C\u4F46\u8BE6\u60C5\u56DE\u67E5\u5931\u8D25\uFF0C\u7ED3\u679C\u4E0D\u786E\u5B9A", {
1254
+ blog_id: lease.blogId,
1255
+ result,
1256
+ workflow: workflow("blog.edit", "VERIFYING")
1257
+ }, { stage: "readback" });
1258
+ }
1259
+ if (htmlToText(after.blog.content) !== htmlToText(lease.content)) {
1260
+ throw blogPartialError("\u7F16\u8F91\u63A5\u53E3\u5DF2\u8FD4\u56DE\u6210\u529F\uFF0C\u4F46\u56DE\u67E5\u5185\u5BB9\u4E0E\u65B0\u5185\u5BB9\u4E0D\u4E00\u81F4", {
1261
+ blog_id: lease.blogId,
1262
+ expected: htmlToText(lease.content),
1263
+ actual: after.blog.content_text,
1264
+ result,
1265
+ workflow: workflow("blog.edit", "VERIFYING")
1266
+ }, { stage: "readback" });
1267
+ }
1268
+ return {
1269
+ status: "COMPLETE",
1270
+ data: {
1271
+ blog_id: lease.blogId,
1272
+ date: lease.date,
1273
+ updated: true,
1274
+ verified: true,
1275
+ content_text: after.blog.content_text,
1276
+ result,
1277
+ workflow: workflow("blog.edit", "COMPLETE")
1278
+ }
1279
+ };
1280
+ }
1281
+ };
1282
+
1283
+ // src/shortcuts/blog/operations/export.ts
1284
+ var BlogExportOperation = class {
1285
+ name = "blog.export";
1286
+ async execute(input, { host }) {
1287
+ const startDate = asDate(input.start_date, "start_date");
1288
+ const endDate = asDate(input.end_date, "end_date");
1289
+ const output = asNonEmptyString(input.output, "output");
1290
+ const pageSize = asInteger(input.page_size, "page_size", { min: 1, max: 500, dflt: 200 });
1291
+ const resolved = await resolveExportOutput(output);
1292
+ const result = await host.blogBinaryRequest({
1293
+ path: "/api/blog/report/exportAllBlog",
1294
+ body: {
1295
+ startDate,
1296
+ endDate,
1297
+ blogType: "all",
1298
+ searchType: "all",
1299
+ disableType: "all",
1300
+ pageNo: 1,
1301
+ pageSize,
1302
+ isNeedConvert: false
1303
+ },
1304
+ operation: "blog.export"
1305
+ });
1306
+ const magicOk = result.content.subarray(0, 2).toString("latin1") === "PK";
1307
+ if (!magicOk) {
1308
+ throw new BlogCliError("api", "export_failed", "\u5BFC\u51FA\u54CD\u5E94\u4E0D\u662F\u5408\u6CD5\u7684 xlsx \u6587\u4EF6\u6D41\uFF08\u7F3A\u5C11 PK \u9B54\u6570\uFF09", {
1309
+ details: { contentType: result.contentType, preview: result.content.subarray(0, 200).toString("utf8") },
1310
+ exitCode: 1 /* GeneralError */
1311
+ });
1312
+ }
1313
+ await writeExportFile(resolved, result.content);
1314
+ return {
1315
+ status: "COMPLETE",
1316
+ data: {
1317
+ output: resolved,
1318
+ bytes: result.content.length,
1319
+ content_type: result.contentType,
1320
+ range: { start_date: startDate, end_date: endDate },
1321
+ note: "\u5BFC\u51FA\u8303\u56F4\u4E3A\u5F53\u524D\u8D26\u53F7\u6709\u6743\u9650\u67E5\u770B\u7684\u5168\u90E8\u65E5\u62A5\uFF08\u4E0D\u9650\u4E8E\u672C\u4EBA\uFF09"
1322
+ }
1323
+ };
1324
+ }
1325
+ };
1326
+
1327
+ // src/shortcuts/blog/operations/like.ts
1328
+ var BlogLikePrepareOperation = class {
1329
+ name = "blog.like.prepare";
1330
+ async execute(input, { host, continuation }) {
1331
+ const cancel = input.cancel === true;
1332
+ const target = await resolveTargetBlog(input, host, cancel ? "\u53D6\u6D88\u70B9\u8D5E" : "\u70B9\u8D5E");
1333
+ const session = await host.getSession();
1334
+ const continuationToken = await continuation.issue({
1335
+ operation: "blog.like.apply",
1336
+ workflow: workflow("blog.like", "AWAITING_CONFIRMATION"),
1337
+ baseUrl: session.baseUrl,
1338
+ profile: session.profile,
1339
+ userId: session.userId,
1340
+ blogId: target.blogId,
1341
+ cancel,
1342
+ fingerprint: objectFingerprint(target.blog ? { id: target.blog.id } : { id: target.blogId })
1343
+ });
1344
+ return {
1345
+ status: "AWAITING_CONFIRMATION",
1346
+ data: {
1347
+ blog_id: target.blogId,
1348
+ action: cancel ? "cancelVote" : "vote",
1349
+ target: target.date ? { date: target.date, user_id: target.userId } : void 0,
1350
+ continuation: continuationToken,
1351
+ expires_in_seconds: 600,
1352
+ workflow: workflow("blog.like", "AWAITING_CONFIRMATION"),
1353
+ next: "\u7528\u6237\u786E\u8BA4\u540E\u8C03\u7528 blog.like.apply \u5E76\u4F20 confirm=true"
1354
+ }
1355
+ };
1356
+ }
1357
+ };
1358
+ var BlogLikeApplyOperation = class {
1359
+ name = "blog.like.apply";
1360
+ async execute(input, { host, continuation }) {
1361
+ if (input.confirm !== true) {
1362
+ throw blogConfirmationError("blog.like.apply", { hint: "\u91CD\u65B0\u8C03\u7528\u65F6\u4F20\u5165 confirm=true" });
1363
+ }
1364
+ const lease = await continuation.verify(input.continuation, "blog.like.apply");
1365
+ if (typeof lease.blogId !== "string" || typeof lease.cancel !== "boolean") {
1366
+ throw blogValidationError("continuation_invalid", "\u70B9\u8D5E continuation \u7F3A\u5C11\u6709\u6548\u76EE\u6807\u6216\u52A8\u4F5C");
1367
+ }
1368
+ const session = await host.getSession();
1369
+ if (!sessionMatches(lease, session)) {
1370
+ throw blogValidationError("context_mismatch", "\u786E\u8BA4\u4E0A\u4E0B\u6587\u5DF2\u53D8\u5316\uFF0C\u8BF7\u91CD\u65B0\u51C6\u5907");
1371
+ }
1372
+ let result;
1373
+ try {
1374
+ result = await host.blogRequest({
1375
+ path: lease.cancel ? "/api/blog/common/upvoteComponent/cancelVote" : "/api/blog/common/upvoteComponent/vote",
1376
+ body: { componentId: lease.blogId, upvote: true },
1377
+ operation: "blog.like.apply"
1378
+ });
1379
+ } catch (error) {
1380
+ if (isBlogNetworkError(error)) {
1381
+ throw blogPartialError("\u70B9\u8D5E\u8BF7\u6C42\u53D1\u9001\u540E\u8FDE\u63A5\u4E2D\u65AD\uFF0C\u7ED3\u679C\u4E0D\u786E\u5B9A\uFF0C\u7981\u6B62\u81EA\u52A8\u91CD\u8BD5", {
1382
+ blog_id: lease.blogId,
1383
+ workflow: workflow("blog.like", "EXECUTING")
1384
+ }, { stage: "vote" });
1385
+ }
1386
+ throw error;
1387
+ }
1388
+ return {
1389
+ status: "COMPLETE",
1390
+ data: {
1391
+ blog_id: lease.blogId,
1392
+ action: lease.cancel ? "cancelVote" : "vote",
1393
+ // detailsByDate 不返回点赞数,动作是否生效以业务码(code=200, fail=false)为准
1394
+ receipt: typeof result?.data === "string" ? result.data : null,
1395
+ verified: false,
1396
+ note: "\u70B9\u8D5E\u72B6\u6001\u65E0\u53EA\u8BFB\u56DE\u67E5\u63A5\u53E3\uFF0C\u52A8\u4F5C\u751F\u6548\u4EE5\u63A5\u53E3\u4E1A\u52A1\u7801\u4E3A\u51C6",
1397
+ workflow: workflow("blog.like", "COMPLETE")
1398
+ }
1399
+ };
1400
+ }
1401
+ };
1402
+
1403
+ // src/shortcuts/blog/operations/publish.ts
1404
+ var BlogDefaultPermissionOperation = class {
1405
+ name = "blog.default_permission";
1406
+ async execute(input, { host }) {
1407
+ const date = asDate(input.date, "date");
1408
+ const value = await host.blogRequest({
1409
+ method: "GET",
1410
+ path: "/api/blog/share/getDefaultPermission",
1411
+ query: { blogTime: date },
1412
+ operation: "blog.default_permission"
1413
+ });
1414
+ return {
1415
+ status: "COMPLETE",
1416
+ data: {
1417
+ date,
1418
+ add: value?.data?.add ?? null,
1419
+ list: Array.isArray(value?.data?.list) ? value.data.list : []
1420
+ }
1421
+ };
1422
+ }
1423
+ };
1424
+ var BlogPublishPrepareOperation = class {
1425
+ name = "blog.publish.prepare";
1426
+ async execute(input, { host, continuation }) {
1427
+ const date = asDate(input.date, "date");
1428
+ const rawContent = typeof input.content === "string" ? input.content.trim() : "";
1429
+ if (!rawContent) throw blogValidationError("input_invalid", "content \u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32");
1430
+ const content = ensureHtml(rawContent);
1431
+ const shareDefault = input.share_default === void 0 ? true : input.share_default === true;
1432
+ const session = await host.getSession();
1433
+ const existing = await fetchDetailsByDate(host, date, session.userId);
1434
+ if (existing.found && existing.blog) {
1435
+ throw blogValidationError("publish_already_exists", `${date} \u5DF2\u6709\u65E5\u62A5\uFF08id=${existing.blog.id}\uFF09\uFF0C\u4E0D\u53EF\u91CD\u590D\u53D1\u5E03\uFF1B\u5982\u9700\u4FEE\u6539\u8BF7\u4F7F\u7528 blog.edit.prepare`, {
1436
+ date,
1437
+ blog_id: existing.blog.id
1438
+ });
1439
+ }
1440
+ let permissionList = [];
1441
+ if (shareDefault) {
1442
+ const perm = await host.blogRequest({
1443
+ method: "GET",
1444
+ path: "/api/blog/share/getDefaultPermission",
1445
+ query: { blogTime: date },
1446
+ operation: "blog.publish.prepare"
1447
+ });
1448
+ permissionList = Array.isArray(perm?.data?.list) ? perm.data.list : [];
1449
+ }
1450
+ const continuationToken = await continuation.issue({
1451
+ operation: "blog.publish.apply",
1452
+ workflow: workflow("blog.publish", "AWAITING_CONFIRMATION"),
1453
+ baseUrl: session.baseUrl,
1454
+ profile: session.profile,
1455
+ userId: session.userId,
1456
+ date,
1457
+ content,
1458
+ permissionList,
1459
+ fingerprint: objectFingerprint({ date, content, permissionList })
1460
+ });
1461
+ return {
1462
+ status: "AWAITING_CONFIRMATION",
1463
+ data: {
1464
+ date,
1465
+ content,
1466
+ content_text: htmlToText(content),
1467
+ share: { default: shareDefault, permission_count: permissionList.length },
1468
+ continuation: continuationToken,
1469
+ expires_in_seconds: 600,
1470
+ workflow: workflow("blog.publish", "AWAITING_CONFIRMATION"),
1471
+ next: "\u5411\u7528\u6237\u590D\u8FF0\u65E5\u671F\u4E0E\u5185\u5BB9\uFF0C\u7528\u6237\u786E\u8BA4\u540E\u8C03\u7528 blog.publish.apply \u5E76\u4F20 confirm=true"
1472
+ }
1473
+ };
1474
+ }
1475
+ };
1476
+ var BlogPublishApplyOperation = class {
1477
+ name = "blog.publish.apply";
1478
+ async execute(input, { host, continuation }) {
1479
+ if (input.confirm !== true) {
1480
+ throw blogConfirmationError("blog.publish.apply", { hint: "\u91CD\u65B0\u8C03\u7528\u65F6\u4F20\u5165 confirm=true" });
1481
+ }
1482
+ const lease = await continuation.verify(input.continuation, "blog.publish.apply");
1483
+ if (typeof lease.date !== "string" || typeof lease.content !== "string" || typeof lease.fingerprint !== "string") {
1484
+ throw blogValidationError("continuation_invalid", "\u53D1\u5E03 continuation \u7F3A\u5C11\u6709\u6548\u65E5\u671F\u3001\u5185\u5BB9\u6216\u6307\u7EB9");
1485
+ }
1486
+ const session = await host.getSession();
1487
+ if (!sessionMatches(lease, session)) {
1488
+ throw blogValidationError("context_mismatch", "\u786E\u8BA4\u4E0A\u4E0B\u6587\u5DF2\u53D8\u5316\uFF0C\u8BF7\u91CD\u65B0\u51C6\u5907\u53D1\u5E03");
1489
+ }
1490
+ const existing = await fetchDetailsByDate(host, lease.date, session.userId);
1491
+ if (existing.found && existing.blog) {
1492
+ throw blogValidationError("target_changed", `${lease.date} \u5728\u786E\u8BA4\u540E\u51FA\u73B0\u4E86\u65E5\u62A5\uFF08id=${existing.blog.id}\uFF09\uFF0C\u8BF7\u91CD\u65B0\u51C6\u5907\u53D1\u5E03`);
1493
+ }
1494
+ if (objectFingerprint({ date: lease.date, content: lease.content, permissionList: lease.permissionList }) !== lease.fingerprint) {
1495
+ throw blogValidationError("continuation_invalid", "\u53D1\u5E03 continuation \u6307\u7EB9\u6821\u9A8C\u5931\u8D25");
1496
+ }
1497
+ let result;
1498
+ try {
1499
+ result = await host.blogRequest({
1500
+ path: "/api/blog/prior/addBlog",
1501
+ body: {
1502
+ blog: {
1503
+ blogTime: lease.date,
1504
+ content: lease.content,
1505
+ permissionList: Array.isArray(lease.permissionList) ? lease.permissionList : [],
1506
+ isTm: 0,
1507
+ isDbCheck: 0,
1508
+ formData: "0",
1509
+ attachmentIds: "",
1510
+ atLinkList: [],
1511
+ deleteTargetType: [],
1512
+ client: "pc"
1513
+ },
1514
+ timezoneOffset: -8
1515
+ },
1516
+ operation: "blog.publish.apply"
1517
+ });
1518
+ } catch (error) {
1519
+ if (isBlogNetworkError(error)) {
1520
+ throw blogPartialError("\u53D1\u5E03\u8BF7\u6C42\u53D1\u9001\u540E\u8FDE\u63A5\u4E2D\u65AD\uFF0C\u7ED3\u679C\u4E0D\u786E\u5B9A\uFF0C\u7981\u6B62\u81EA\u52A8\u91CD\u8BD5\uFF1B\u8BF7\u5148\u7528 blog.query_user \u56DE\u67E5", {
1521
+ date: lease.date,
1522
+ workflow: workflow("blog.publish", "EXECUTING")
1523
+ }, { stage: "publish" });
1524
+ }
1525
+ throw error;
1526
+ }
1527
+ const after = await fetchDetailsByDate(host, lease.date, session.userId);
1528
+ if (!after.found || !after.blog) {
1529
+ throw blogPartialError("\u53D1\u5E03\u63A5\u53E3\u5DF2\u8FD4\u56DE\uFF0C\u4F46\u56DE\u67E5\u672A\u53D1\u73B0\u65B0\u65E5\u62A5\uFF0C\u7ED3\u679C\u4E0D\u786E\u5B9A", {
1530
+ date: lease.date,
1531
+ result,
1532
+ workflow: workflow("blog.publish", "VERIFYING")
1533
+ }, { stage: "readback" });
1534
+ }
1535
+ const submitStatus2 = after.blog.create_time !== null && after.blog.blog_time !== null && localDateStr(after.blog.create_time) === localDateStr(after.blog.blog_time) ? "\u6B63\u5E38" : "\u8865\u4EA4";
1536
+ return {
1537
+ status: "COMPLETE",
1538
+ data: {
1539
+ date: lease.date,
1540
+ blog_id: after.blog.id,
1541
+ submit_status: submitStatus2,
1542
+ verified: true,
1543
+ result,
1544
+ workflow: workflow("blog.publish", "COMPLETE")
1545
+ }
1546
+ };
1547
+ }
1548
+ };
1549
+
1550
+ // src/shortcuts/blog/operations/query.ts
1551
+ var MAX_PAGE_SIZE = 300;
1552
+ async function runGroupQuery(input, host) {
1553
+ const userType = normalizeUserType(input.user_type);
1554
+ const days = dateRange(input.start_date, input.end_date, "start_date", "end_date");
1555
+ const startDate = days[0];
1556
+ const endDate = days[days.length - 1];
1557
+ const keywords = typeof input.keywords === "string" ? input.keywords : "";
1558
+ const pageSize = asInteger(input.page_size, "page_size", { min: 1, max: MAX_PAGE_SIZE, dflt: MAX_PAGE_SIZE });
1559
+ const pageNo = asInteger(input.page_no, "page_no", { min: 1, max: 1e4, dflt: 1 });
1560
+ const startMs = (/* @__PURE__ */ new Date(`${startDate}T00:00:00`)).getTime();
1561
+ const endMs = (/* @__PURE__ */ new Date(`${endDate}T23:59:59.999`)).getTime();
1562
+ const value = await host.blogRequest({
1563
+ method: "POST",
1564
+ path: "/api/blog/query/blogs",
1565
+ body: {
1566
+ blogType: "order",
1567
+ keywords,
1568
+ pageNo,
1569
+ pageSize,
1570
+ filter: {
1571
+ userType,
1572
+ startDate,
1573
+ endDate,
1574
+ timezoneOffset: -8
1575
+ }
1576
+ },
1577
+ operation: "blog.query"
1578
+ });
1579
+ const raw = Array.isArray(value?.blogList) ? value.blogList : [];
1580
+ const items = raw.map((item) => normalizeBlogListItem(item)).filter((item) => Boolean(item)).filter((item) => item.date >= startMs && item.date <= endMs);
1581
+ const oldestRaw = raw.length ? Math.min(...raw.map((item) => Number(item?.date)).filter(Number.isFinite)) : null;
1582
+ const truncated = raw.length >= pageSize && oldestRaw !== null && localDateStr(oldestRaw) > startDate;
1583
+ const view = items.map((item) => ({
1584
+ date: item.date_str,
1585
+ date_ms: item.date,
1586
+ user_id: item.user_id,
1587
+ username: item.username,
1588
+ submit_status: item.submit_status,
1589
+ blog: item.blog
1590
+ }));
1591
+ const submitted = items.filter((item) => item.submitted);
1592
+ const people = [...new Map(items.map((item) => [item.user_id, item.username])).entries()].map(([userId, username]) => ({ user_id: userId, username }));
1593
+ const missing = items.filter((item) => !item.submitted).map((item) => ({ date: item.date_str, user_id: item.user_id, username: item.username }));
1594
+ const missingPeople = people.filter((person) => !items.some((item) => item.user_id === person.user_id && item.submitted)).map((person) => person.username);
1595
+ return {
1596
+ status: "COMPLETE",
1597
+ data: {
1598
+ user_type: userType,
1599
+ range: { start_date: startDate, end_date: endDate },
1600
+ total_rows_in_window: items.length,
1601
+ submitted_count: submitted.length,
1602
+ missing_count: missing.length,
1603
+ not_submitted: missing,
1604
+ not_submitted_people: missingPeople,
1605
+ people,
1606
+ items: view,
1607
+ page: { page_size: pageSize, page_no: pageNo, rows_returned: raw.length },
1608
+ _note: truncated ? `\u670D\u52A1\u7AEF\u5355\u6B21\u6700\u591A\u8FD4\u56DE ${pageSize} \u884C\uFF08pageNo \u88AB\u670D\u52A1\u7AEF\u5FFD\u7565\uFF0C\u65E0\u6CD5\u7FFB\u9875\uFF09\uFF0C\u672C\u6B21\u6700\u65E7\u4EC5\u5230 ${localDateStr(oldestRaw)}\uFF0C\u65E9\u4E8E ${startDate} \u7684\u90E8\u5206\u672A\u8986\u76D6\uFF1B\u8BF7\u7F29\u5C0F\u65E5\u671F\u8303\u56F4\uFF08\u6216\u51CF\u5C11\u4EBA\u6570\u8303\u56F4\uFF09\u540E\u91CD\u67E5` : void 0
1609
+ }
1610
+ };
1611
+ }
1612
+ var BlogQueryOperation = class {
1613
+ name = "blog.query";
1614
+ execute(input, { host }) {
1615
+ return runGroupQuery(input, host);
1616
+ }
1617
+ };
1618
+
1619
+ // src/shortcuts/blog/operations/query-user.ts
1620
+ async function runQueryUser(input, host) {
1621
+ const startDate = asDate(input.date, "date");
1622
+ const days = input.end_date === void 0 ? [startDate] : dateRange(startDate, input.end_date, "date", "end_date");
1623
+ const { userId, userName } = await resolveTargetUser(input, host);
1624
+ const items = [];
1625
+ for (const date of days) {
1626
+ const detail = await fetchDetailsByDate(host, date, userId);
1627
+ const status = detail.blog ? submitStatus(detail.blog) : "\u672A\u63D0\u4EA4";
1628
+ items.push({
1629
+ date,
1630
+ found: detail.found,
1631
+ submitted: detail.found,
1632
+ submit_status: status,
1633
+ blog: detail.blog
1634
+ });
1635
+ }
1636
+ return {
1637
+ status: "COMPLETE",
1638
+ data: {
1639
+ user: { user_id: userId, name: userName },
1640
+ range: { start_date: startDate, end_date: days[days.length - 1] },
1641
+ total_days: days.length,
1642
+ submitted_days: items.filter((item) => item.submitted).length,
1643
+ normal_days: items.filter((item) => item.submit_status === "\u6B63\u5E38").length,
1644
+ later_days: items.filter((item) => item.submit_status === "\u8865\u4EA4").length,
1645
+ missing_days: items.filter((item) => item.submit_status === "\u672A\u63D0\u4EA4").length,
1646
+ items
1647
+ }
1648
+ };
1649
+ }
1650
+ var BlogQueryUserOperation = class {
1651
+ name = "blog.query_user";
1652
+ execute(input, { host }) {
1653
+ return runQueryUser(input, host);
1654
+ }
1655
+ };
1656
+ var BlogResolveUsersOperation = class {
1657
+ name = "blog.resolve_users";
1658
+ async execute(input, { host }) {
1659
+ const name = typeof input.name === "string" ? input.name.trim() : "";
1660
+ if (!name) throw blogValidationError("input_invalid", "name \u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32");
1661
+ const users = await searchUsersByName(host, name);
1662
+ return {
1663
+ status: "COMPLETE",
1664
+ data: {
1665
+ name,
1666
+ matched: users.length,
1667
+ users: users.map((user) => ({ user_id: user.id, name: user.name, department: user.department }))
1668
+ }
1669
+ };
1670
+ }
1671
+ };
1672
+
1673
+ // src/shortcuts/blog/operations/remind.ts
1674
+ var MAX_TARGETS = 50;
1675
+ async function resolveRemindTargets(input, host) {
1676
+ if (input.user_ids !== void 0 && input.names !== void 0) {
1677
+ throw blogValidationError("input_ambiguous", "user_ids \u4E0E names \u53EA\u80FD\u63D0\u4F9B\u4E00\u4E2A");
1678
+ }
1679
+ if (input.user_ids !== void 0) {
1680
+ const raw = typeof input.user_ids === "string" ? input.user_ids.split(",").map((item) => item.trim()).filter(Boolean) : input.user_ids;
1681
+ if (!Array.isArray(raw) || raw.length === 0) {
1682
+ throw blogValidationError("input_invalid", "user_ids \u5FC5\u987B\u662F\u975E\u7A7A\u6570\u7EC4\u6216\u9017\u53F7\u5206\u9694\u5B57\u7B26\u4E32");
1683
+ }
1684
+ if (raw.length > MAX_TARGETS) throw blogValidationError("input_invalid", `user_ids \u5355\u6B21\u6700\u591A ${MAX_TARGETS} \u4EBA`);
1685
+ return raw.map((item, index) => {
1686
+ const id = String(item);
1687
+ if (!/^[1-9]\d*$/u.test(id)) {
1688
+ throw blogValidationError("input_invalid", `user_ids[${index}] \u5FC5\u987B\u662F\u6B63\u6574\u6570\u6587\u672C`);
1689
+ }
1690
+ return { user_id: id, name: null };
1691
+ });
1692
+ }
1693
+ if (input.names !== void 0) {
1694
+ const raw = input.names;
1695
+ if (!Array.isArray(raw) || raw.length === 0) {
1696
+ throw blogValidationError("input_invalid", "names \u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32\u6570\u7EC4");
1697
+ }
1698
+ if (raw.length > MAX_TARGETS) throw blogValidationError("input_invalid", `names \u5355\u6B21\u6700\u591A ${MAX_TARGETS} \u4EBA`);
1699
+ const targets = [];
1700
+ for (const item of raw) {
1701
+ const name = typeof item === "string" ? item.trim() : "";
1702
+ if (!name) throw blogValidationError("input_invalid", "names \u4E0D\u80FD\u5305\u542B\u7A7A\u503C");
1703
+ const users = await searchUsersByName(host, name);
1704
+ if (users.length === 0) throw blogValidationError("name_not_found", `\u672A\u627E\u5230\u540D\u4E3A\u300C${name}\u300D\u7684\u5458\u5DE5`);
1705
+ if (users.length > 1) {
1706
+ throw blogValidationError("name_ambiguous", `\u300C${name}\u300D\u547D\u4E2D ${users.length} \u540D\u5458\u5DE5\uFF0C\u8BF7\u6539\u7528 user_ids \u6307\u5B9A`, { candidates: users });
1707
+ }
1708
+ targets.push({ user_id: users[0].id, name: users[0].name });
1709
+ }
1710
+ return targets;
1711
+ }
1712
+ throw blogValidationError("input_invalid", "user_ids \u4E0E names \u5FC5\u987B\u63D0\u4F9B\u4E00\u4E2A");
1713
+ }
1714
+ function normalizeCustomContent(content, date) {
1715
+ if (content === void 0 || content === null) return void 0;
1716
+ const text = typeof content === "string" ? content.trim() : "";
1717
+ if (!text) return void 0;
1718
+ if (!/日/u.test(text)) {
1719
+ throw blogValidationError("input_invalid", `\u81EA\u5B9A\u4E49\u63D0\u9192\u6587\u6848\u5E94\u5305\u542B\u5177\u4F53\u65E5\u671F\uFF0C\u4F8B\u5982\u300C${remindContent(date)}\u300D\uFF1B\u6216\u7701\u7565 content \u4F7F\u7528\u9ED8\u8BA4\u6587\u6848`);
1720
+ }
1721
+ return text;
1722
+ }
1723
+ var BlogRemindPrepareOperation = class {
1724
+ name = "blog.remind.prepare";
1725
+ async execute(input, { host, continuation }) {
1726
+ const date = asDate(input.date, "date");
1727
+ const targets = await resolveRemindTargets(input, host);
1728
+ const custom = normalizeCustomContent(input.content, date);
1729
+ const content = custom ?? remindContent(date);
1730
+ const year = asInteger(input.year, "year", { min: 2e3, max: 2100, dflt: remindYear(date) });
1731
+ const session = await host.getSession();
1732
+ const continuationToken = await continuation.issue({
1733
+ operation: "blog.remind.apply",
1734
+ workflow: workflow("blog.remind", "AWAITING_CONFIRMATION"),
1735
+ baseUrl: session.baseUrl,
1736
+ profile: session.profile,
1737
+ userId: session.userId,
1738
+ date,
1739
+ content,
1740
+ year,
1741
+ targets,
1742
+ fingerprint: objectFingerprint({ date, content, year, targets })
1743
+ });
1744
+ return {
1745
+ status: "AWAITING_CONFIRMATION",
1746
+ data: {
1747
+ targets: targets.map((target) => ({ user_id: target.user_id, name: target.name })),
1748
+ date,
1749
+ content,
1750
+ year,
1751
+ continuation: continuationToken,
1752
+ expires_in_seconds: 600,
1753
+ workflow: workflow("blog.remind", "AWAITING_CONFIRMATION"),
1754
+ next: "\u5411\u7528\u6237\u590D\u8FF0\u88AB\u63D0\u9192\u4EBA\u4E0E\u6587\u6848\uFF0C\u7528\u6237\u786E\u8BA4\u540E\u8C03\u7528 blog.remind.apply \u5E76\u4F20 confirm=true"
1755
+ }
1756
+ };
1757
+ }
1758
+ };
1759
+ var BlogRemindApplyOperation = class {
1760
+ name = "blog.remind.apply";
1761
+ async execute(input, { host, continuation }) {
1762
+ if (input.confirm !== true) {
1763
+ throw blogConfirmationError("blog.remind.apply", { hint: "\u91CD\u65B0\u8C03\u7528\u65F6\u4F20\u5165 confirm=true" });
1764
+ }
1765
+ const lease = await continuation.verify(input.continuation, "blog.remind.apply");
1766
+ if (!Array.isArray(lease.targets) || lease.targets.length === 0 || typeof lease.content !== "string") {
1767
+ throw blogValidationError("continuation_invalid", "\u63D0\u9192 continuation \u7F3A\u5C11\u6709\u6548\u76EE\u6807\u6216\u6587\u6848");
1768
+ }
1769
+ const session = await host.getSession();
1770
+ if (!sessionMatches(lease, session)) {
1771
+ throw blogValidationError("context_mismatch", "\u786E\u8BA4\u4E0A\u4E0B\u6587\u5DF2\u53D8\u5316\uFF0C\u8BF7\u91CD\u65B0\u51C6\u5907\u63D0\u9192");
1772
+ }
1773
+ if (objectFingerprint({ date: lease.date, content: lease.content, year: lease.year, targets: lease.targets }) !== lease.fingerprint) {
1774
+ throw blogValidationError("continuation_invalid", "\u63D0\u9192 continuation \u6307\u7EB9\u6821\u9A8C\u5931\u8D25");
1775
+ }
1776
+ const succeeded = [];
1777
+ const failed = [];
1778
+ for (const target of lease.targets) {
1779
+ try {
1780
+ await host.blogRequest({
1781
+ path: "/api/blog/message/sendUrge",
1782
+ body: {
1783
+ checkStr: "",
1784
+ content: lease.content,
1785
+ definiteType: "blog",
1786
+ ids: target.user_id,
1787
+ targetId: null,
1788
+ type: "blog",
1789
+ year: lease.year
1790
+ },
1791
+ operation: "blog.remind.apply"
1792
+ });
1793
+ succeeded.push({ user_id: target.user_id, name: target.name });
1794
+ } catch (error) {
1795
+ failed.push({
1796
+ user_id: target.user_id,
1797
+ name: target.name,
1798
+ message: error instanceof Error ? error.message : String(error)
1799
+ });
1800
+ if (isBlogNetworkError(error)) {
1801
+ throw blogPartialError("\u63D0\u9192\u53D1\u9001\u8FC7\u7A0B\u4E2D\u8FDE\u63A5\u4E2D\u65AD\uFF0C\u7ED3\u679C\u4E0D\u786E\u5B9A\uFF0C\u7981\u6B62\u81EA\u52A8\u91CD\u8BD5", {
1802
+ succeeded,
1803
+ failed,
1804
+ workflow: workflow("blog.remind", "EXECUTING")
1805
+ }, { stage: "urge" });
1806
+ }
1807
+ }
1808
+ }
1809
+ if (failed.length > 0) {
1810
+ return {
1811
+ status: "PARTIAL",
1812
+ data: {
1813
+ content: lease.content,
1814
+ date: lease.date,
1815
+ succeeded,
1816
+ failed,
1817
+ workflow: workflow("blog.remind", failed.length === lease.targets.length ? "FAILED" : "PARTIAL_COMPLETE")
1818
+ }
1819
+ };
1820
+ }
1821
+ return {
1822
+ status: "COMPLETE",
1823
+ data: {
1824
+ content: lease.content,
1825
+ date: lease.date,
1826
+ succeeded,
1827
+ failed,
1828
+ workflow: workflow("blog.remind", "COMPLETE")
1829
+ }
1830
+ };
1831
+ }
1832
+ };
1833
+
1834
+ // src/shortcuts/blog/operations/registry.ts
1835
+ function buildRegistry() {
1836
+ const registry = /* @__PURE__ */ new Map();
1837
+ const handlers = [
1838
+ new BlogQueryOperation(),
1839
+ new BlogQueryUserOperation(),
1840
+ new BlogResolveUsersOperation(),
1841
+ new BlogCommentsOperation(),
1842
+ new BlogDefaultPermissionOperation(),
1843
+ new BlogExportOperation(),
1844
+ new BlogPublishPrepareOperation(),
1845
+ new BlogPublishApplyOperation(),
1846
+ new BlogEditPrepareOperation(),
1847
+ new BlogEditApplyOperation(),
1848
+ new BlogCommentPrepareOperation(),
1849
+ new BlogCommentApplyOperation(),
1850
+ new BlogLikePrepareOperation(),
1851
+ new BlogLikeApplyOperation(),
1852
+ new BlogRemindPrepareOperation(),
1853
+ new BlogRemindApplyOperation()
1854
+ ];
1855
+ for (const handler of handlers) {
1856
+ if (registry.has(handler.name)) throw new Error(`duplicate blog operation handler: ${handler.name}`);
1857
+ registry.set(handler.name, handler);
1858
+ }
1859
+ for (const contract of blogOperations) {
1860
+ if (!registry.has(contract.name)) throw new Error(`missing blog operation handler: ${contract.name}`);
1861
+ }
1862
+ return registry;
1863
+ }
1864
+ var blogOperationRegistry = buildRegistry();
1865
+ function getBlogOperation(operation) {
1866
+ const handler = blogOperationRegistry.get(operation);
1867
+ if (!handler) {
1868
+ throw blogValidationError("operation_unknown", `\u65E5\u62A5\u6A21\u5757\u4E0D\u652F\u6301\u64CD\u4F5C\uFF1A${operation}`);
1869
+ }
1870
+ return handler;
1871
+ }
1872
+
1873
+ // src/shortcuts/blog/operations.ts
1874
+ async function executeBlogOperation(operation, rawInput, context) {
1875
+ const handler = getBlogOperation(operation);
1876
+ const input = asObject(rawInput);
1877
+ assertNoForbiddenKeys(input);
1878
+ return handler.execute(input, context);
1879
+ }
1880
+
1881
+ // src/shortcuts/blog/index.ts
1882
+ function asOptions(value) {
1883
+ return value && typeof value === "object" && !Array.isArray(value) ? value : {};
1884
+ }
1885
+ async function readStdin() {
1886
+ const chunks = [];
1887
+ for await (const chunk of process.stdin) {
1888
+ chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
1889
+ }
1890
+ return Buffer.concat(chunks).toString("utf8");
1891
+ }
1892
+ function stripBom(value) {
1893
+ return value.replace(/^\uFEFF+/u, "");
1894
+ }
1895
+ async function inputFrom(options, extra = {}) {
1896
+ const opts = asOptions(options);
1897
+ let input = {};
1898
+ if (opts.input && opts.inputJson) {
1899
+ throw blogValidationError("input_conflict", "\u4E0D\u80FD\u540C\u65F6\u4F20 --input \u548C --input-json");
1900
+ }
1901
+ if (opts.inputJson) {
1902
+ input = parseJsonInput(String(opts.inputJson), "--input-json");
1903
+ }
1904
+ if (opts.input) {
1905
+ let raw;
1906
+ try {
1907
+ raw = opts.input === "-" ? await readStdin() : await readFile2(String(opts.input), "utf8");
1908
+ } catch {
1909
+ throw blogValidationError("input_unreadable", `\u65E0\u6CD5\u8BFB\u53D6 --input\uFF1A${String(opts.input)}`);
1910
+ }
1911
+ input = parseJsonInput(raw, "--input");
1912
+ }
1913
+ return {
1914
+ ...input,
1915
+ ...Object.fromEntries(Object.entries(extra).filter(([, value]) => value !== void 0 && value !== ""))
1916
+ };
1917
+ }
1918
+ function parseJsonInput(raw, label) {
1919
+ try {
1920
+ const parsed = JSON.parse(stripBom(raw));
1921
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
1922
+ throw new Error("input must be an object");
1923
+ }
1924
+ return parsed;
1925
+ } catch {
1926
+ throw blogValidationError("input_invalid", `${label} \u4E0D\u662F\u5408\u6CD5 JSON \u5BF9\u8C61`);
1927
+ }
1928
+ }
1929
+ function withJsonInputOptions(command) {
1930
+ command.option("--input <path>", "JSON input file, or - for stdin").option("--input-json <json>", "inline JSON input object");
1931
+ return command;
1932
+ }
1933
+ function intOption(value) {
1934
+ if (value === void 0 || value === null || value === "") return void 0;
1935
+ const parsed = Number(value);
1936
+ return Number.isInteger(parsed) ? parsed : void 0;
1937
+ }
1938
+ function namesOption(value) {
1939
+ if (typeof value !== "string") return void 0;
1940
+ const items = value.split(",").map((item) => item.trim()).filter(Boolean);
1941
+ return items.length ? items : void 0;
1942
+ }
1943
+ function successEnvelope(operation, result) {
1944
+ return {
1945
+ schemaVersion: 1,
1946
+ ok: true,
1947
+ operation,
1948
+ data: result.data,
1949
+ meta: { status: result.status },
1950
+ warnings: []
1951
+ };
1952
+ }
1953
+ function failureEnvelope(error) {
1954
+ const structured = error;
1955
+ return {
1956
+ schemaVersion: 1,
1957
+ ok: false,
1958
+ ...structured?.partialData === void 0 ? {} : { data: structured.partialData },
1959
+ error: toErrorEnvelope(error)
1960
+ };
1961
+ }
1962
+ async function executeAndPrint(ctx, operation, input) {
1963
+ try {
1964
+ const result = await executeBlogOperation(operation, input, {
1965
+ host: createBlogHost(ctx),
1966
+ continuation: createBlogContinuationSigner(ctx)
1967
+ });
1968
+ ctx.output.write(successEnvelope(operation, result), { json: true });
1969
+ } catch (error) {
1970
+ console.error(JSON.stringify(failureEnvelope(error), null, 2));
1971
+ process.exitCode = isCliError(error) ? error.exitCode : 1 /* GeneralError */;
1972
+ }
1973
+ }
1974
+ var blogShortcut = {
1975
+ name: "blog",
1976
+ description: "\u6CDB\u5FAEE10\u5DE5\u4F5C\u65E5\u62A5 CLI\uFF08\u67E5\u8BE2/\u53D1\u5E03/\u7F16\u8F91/\u8BC4\u8BBA/\u70B9\u8D5E/\u63D0\u9192/\u5BFC\u51FA\uFF09",
1977
+ category: "shortcut",
1978
+ register({ program, action }) {
1979
+ const blog = program.command("blog").description("E10 \u5DE5\u4F5C\u65E5\u62A5\uFF08\u67E5\u8BE2/\u53D1\u5E03/\u7F16\u8F91/\u8BC4\u8BBA/\u70B9\u8D5E/\u63D0\u9192/\u5BFC\u51FA\uFF09");
1980
+ blog.command("schema").description("Print blog operation manifest for agents").action(action((ctx) => {
1981
+ ctx.output.write(blogManifest, { json: true });
1982
+ }));
1983
+ withJsonInputOptions(
1984
+ blog.command("run").description("Run a blog operation with JSON input").argument("<operation>", "operation name, e.g. blog.query")
1985
+ ).action(action(async (ctx, operation, options) => {
1986
+ await executeAndPrint(ctx, String(operation), await inputFrom(options));
1987
+ }));
1988
+ withJsonInputOptions(
1989
+ blog.command("query").description("\u6279\u91CF\u67E5\u7FA4\u4F53\u65E5\u62A5\uFF08\u4E0B\u5C5E/\u5173\u6CE8\uFF09\uFF0C\u6309\u5929\u6C47\u603B\u63D0\u4EA4\u60C5\u51B5").option("--user-type <type>", "directSubordinate|indirectSubordinate|allSubordinate|myFollow").option("--start <date>", "start date YYYY-MM-DD").option("--end <date>", "end date YYYY-MM-DD").option("--keywords <text>", "keyword filter").option("--page-size <n>", "page size (max 300)").option("--page-no <n>", "page number")
1990
+ ).action(action(async (ctx, options) => {
1991
+ const opts = asOptions(options);
1992
+ await executeAndPrint(ctx, "blog.query", await inputFrom(options, {
1993
+ user_type: opts.userType,
1994
+ start_date: opts.start,
1995
+ end_date: opts.end,
1996
+ keywords: opts.keywords,
1997
+ page_size: intOption(opts.pageSize),
1998
+ page_no: intOption(opts.pageNo)
1999
+ }));
2000
+ }));
2001
+ withJsonInputOptions(
2002
+ blog.command("query-user").description("\u67E5\u5355\u4EBA\u65E5\u62A5\uFF08detailsByDate \u9010\u65E5\u626B\u63CF\uFF0C\u533A\u95F4\u4E0A\u9650 62 \u5929\uFF09").option("--user-id <id>", "target user id").option("--name <name>", "target user name (HRM exact match)").option("--date <date>", "start date YYYY-MM-DD").option("--end <date>", "end date (inclusive)")
2003
+ ).action(action(async (ctx, options) => {
2004
+ const opts = asOptions(options);
2005
+ await executeAndPrint(ctx, "blog.query_user", await inputFrom(options, {
2006
+ user_id: opts.userId,
2007
+ name: opts.name,
2008
+ date: opts.date,
2009
+ end_date: opts.end
2010
+ }));
2011
+ }));
2012
+ withJsonInputOptions(
2013
+ blog.command("resolve-users").description("HRM \u6309\u59D3\u540D\u89E3\u6790 userId").option("--name <name>", "employee name")
2014
+ ).action(action(async (ctx, options) => {
2015
+ const opts = asOptions(options);
2016
+ await executeAndPrint(ctx, "blog.resolve_users", await inputFrom(options, { name: opts.name }));
2017
+ }));
2018
+ withJsonInputOptions(
2019
+ blog.command("comments").description("\u67E5\u67D0\u6761\u65E5\u62A5\u7684\u8BC4\u8BBA\u5217\u8868").option("--blog-id <id>", "blog id").option("--page-size <n>", "page size (max 100)").option("--page-no <n>", "page number")
2020
+ ).action(action(async (ctx, options) => {
2021
+ const opts = asOptions(options);
2022
+ await executeAndPrint(ctx, "blog.comments", await inputFrom(options, {
2023
+ blog_id: opts.blogId,
2024
+ page_size: intOption(opts.pageSize),
2025
+ page_no: intOption(opts.pageNo)
2026
+ }));
2027
+ }));
2028
+ withJsonInputOptions(
2029
+ blog.command("default-permission").description("\u67E5\u67D0\u65E5\u671F\u7684\u9ED8\u8BA4\u5171\u4EAB\u5BF9\u8C61").option("--date <date>", "blog date YYYY-MM-DD")
2030
+ ).action(action(async (ctx, options) => {
2031
+ const opts = asOptions(options);
2032
+ await executeAndPrint(ctx, "blog.default_permission", await inputFrom(options, { date: opts.date }));
2033
+ }));
2034
+ withJsonInputOptions(
2035
+ blog.command("export").description("\u5BFC\u51FA\u65E5\u62A5\u4E3A xlsx \u6587\u4EF6\uFF08\u62D2\u7EDD\u8986\u76D6\u5DF2\u5B58\u5728\u6587\u4EF6\uFF09").option("--start <date>", "start date YYYY-MM-DD").option("--end <date>", "end date YYYY-MM-DD").option("--output <path>", "output .xlsx path").option("--page-size <n>", "page size")
2036
+ ).action(action(async (ctx, options) => {
2037
+ const opts = asOptions(options);
2038
+ await executeAndPrint(ctx, "blog.export", await inputFrom(options, {
2039
+ start_date: opts.start,
2040
+ end_date: opts.end,
2041
+ output: opts.output,
2042
+ page_size: intOption(opts.pageSize)
2043
+ }));
2044
+ }));
2045
+ const publish = blog.command("publish").description("\u53D1\u5E03\u65E5\u62A5\u547D\u4EE4\u7EC4\uFF08prepare -> apply\uFF09");
2046
+ withJsonInputOptions(
2047
+ publish.command("prepare").description("Prepare blog.publish\uFF08\u67E5\u91CD + \u56DE\u586B\u9ED8\u8BA4\u5171\u4EAB + \u7B7E\u53D1 continuation\uFF09").option("--date <date>", "blog date YYYY-MM-DD").option("--content <text>", "blog content").option("--no-share-default", "skip default share objects")
2048
+ ).action(action(async (ctx, options) => {
2049
+ const opts = asOptions(options);
2050
+ await executeAndPrint(ctx, "blog.publish.prepare", await inputFrom(options, {
2051
+ date: opts.date,
2052
+ content: opts.content,
2053
+ share_default: opts.shareDefault === false ? false : void 0
2054
+ }));
2055
+ }));
2056
+ withJsonInputOptions(
2057
+ publish.command("apply").description("Apply blog.publish\uFF08\u9700 confirm \u4E0E continuation\uFF09").option("--continuation <token>", "continuation token from prepare").option("--yes", "confirm the write operation")
2058
+ ).action(action(async (ctx, options) => {
2059
+ const opts = asOptions(options);
2060
+ await executeAndPrint(ctx, "blog.publish.apply", await inputFrom(options, {
2061
+ continuation: opts.continuation,
2062
+ confirm: opts.yes === true ? true : void 0
2063
+ }));
2064
+ }));
2065
+ const edit = blog.command("edit").description("\u7F16\u8F91\u65E5\u62A5\u547D\u4EE4\u7EC4\uFF08prepare -> apply\uFF09");
2066
+ withJsonInputOptions(
2067
+ edit.command("prepare").description("Prepare blog.edit\uFF08\u56DE\u67E5\u539F\u5185\u5BB9\u4E0E\u5DEE\u5F02 + \u7B7E\u53D1 continuation\uFF09").option("--user-id <id>", "target user id").option("--name <name>", "target user name").option("--date <date>", "blog date YYYY-MM-DD").option("--content <text>", "new blog content")
2068
+ ).action(action(async (ctx, options) => {
2069
+ const opts = asOptions(options);
2070
+ await executeAndPrint(ctx, "blog.edit.prepare", await inputFrom(options, {
2071
+ user_id: opts.userId,
2072
+ name: opts.name,
2073
+ date: opts.date,
2074
+ content: opts.content
2075
+ }));
2076
+ }));
2077
+ withJsonInputOptions(
2078
+ edit.command("apply").description("Apply blog.edit\uFF08\u9700 confirm \u4E0E continuation\uFF09").option("--continuation <token>", "continuation token from prepare").option("--yes", "confirm the write operation")
2079
+ ).action(action(async (ctx, options) => {
2080
+ const opts = asOptions(options);
2081
+ await executeAndPrint(ctx, "blog.edit.apply", await inputFrom(options, {
2082
+ continuation: opts.continuation,
2083
+ confirm: opts.yes === true ? true : void 0
2084
+ }));
2085
+ }));
2086
+ const comment = blog.command("comment").description("\u8BC4\u8BBA\u65E5\u62A5\u547D\u4EE4\u7EC4\uFF08prepare -> apply\uFF09");
2087
+ withJsonInputOptions(
2088
+ comment.command("prepare").description("Prepare blog.comment\uFF08\u5B9A\u4F4D\u76EE\u6807\u65E5\u62A5 + \u7B7E\u53D1 continuation\uFF09").option("--blog-id <id>", "blog id (or date + user)").option("--user-id <id>", "target user id").option("--name <name>", "target user name").option("--date <date>", "blog date YYYY-MM-DD").option("--content <text>", "comment content")
2089
+ ).action(action(async (ctx, options) => {
2090
+ const opts = asOptions(options);
2091
+ await executeAndPrint(ctx, "blog.comment.prepare", await inputFrom(options, {
2092
+ blog_id: opts.blogId,
2093
+ user_id: opts.userId,
2094
+ name: opts.name,
2095
+ date: opts.date,
2096
+ content: opts.content
2097
+ }));
2098
+ }));
2099
+ withJsonInputOptions(
2100
+ comment.command("apply").description("Apply blog.comment\uFF08\u9700 confirm \u4E0E continuation\uFF09").option("--continuation <token>", "continuation token from prepare").option("--yes", "confirm the write operation")
2101
+ ).action(action(async (ctx, options) => {
2102
+ const opts = asOptions(options);
2103
+ await executeAndPrint(ctx, "blog.comment.apply", await inputFrom(options, {
2104
+ continuation: opts.continuation,
2105
+ confirm: opts.yes === true ? true : void 0
2106
+ }));
2107
+ }));
2108
+ const like = blog.command("like").description("\u70B9\u8D5E/\u53D6\u6D88\u70B9\u8D5E\u547D\u4EE4\u7EC4\uFF08prepare -> apply\uFF09");
2109
+ withJsonInputOptions(
2110
+ like.command("prepare").description("Prepare blog.like\uFF08\u5B9A\u4F4D\u76EE\u6807\u65E5\u62A5 + \u7B7E\u53D1 continuation\uFF09").option("--blog-id <id>", "blog id (or date + user)").option("--user-id <id>", "target user id").option("--name <name>", "target user name").option("--date <date>", "blog date YYYY-MM-DD").option("--cancel", "cancel the like (cancelVote)")
2111
+ ).action(action(async (ctx, options) => {
2112
+ const opts = asOptions(options);
2113
+ await executeAndPrint(ctx, "blog.like.prepare", await inputFrom(options, {
2114
+ blog_id: opts.blogId,
2115
+ user_id: opts.userId,
2116
+ name: opts.name,
2117
+ date: opts.date,
2118
+ cancel: opts.cancel === true ? true : void 0
2119
+ }));
2120
+ }));
2121
+ withJsonInputOptions(
2122
+ like.command("apply").description("Apply blog.like\uFF08\u9700 confirm \u4E0E continuation\uFF09").option("--continuation <token>", "continuation token from prepare").option("--yes", "confirm the write operation")
2123
+ ).action(action(async (ctx, options) => {
2124
+ const opts = asOptions(options);
2125
+ await executeAndPrint(ctx, "blog.like.apply", await inputFrom(options, {
2126
+ continuation: opts.continuation,
2127
+ confirm: opts.yes === true ? true : void 0
2128
+ }));
2129
+ }));
2130
+ const remind = blog.command("remind").description("\u63D0\u9192\u63D0\u4EA4\u65E5\u62A5\u547D\u4EE4\u7EC4\uFF08prepare -> apply\uFF09");
2131
+ withJsonInputOptions(
2132
+ remind.command("prepare").description("Prepare blog.remind\uFF08\u89E3\u6790\u88AB\u63D0\u9192\u4EBA + \u9ED8\u8BA4\u6587\u6848 + \u7B7E\u53D1 continuation\uFF09").option("--user-ids <id,id,...>", "remind target user ids").option("--names <name,name,...>", "remind target names (HRM resolved)").option("--date <date>", "blog date YYYY-MM-DD").option("--content <text>", "custom remind content").option("--year <n>", "blog year")
2133
+ ).action(action(async (ctx, options) => {
2134
+ const opts = asOptions(options);
2135
+ await executeAndPrint(ctx, "blog.remind.prepare", await inputFrom(options, {
2136
+ user_ids: opts.userIds,
2137
+ names: namesOption(opts.names),
2138
+ date: opts.date,
2139
+ content: opts.content,
2140
+ year: intOption(opts.year)
2141
+ }));
2142
+ }));
2143
+ withJsonInputOptions(
2144
+ remind.command("apply").description("Apply blog.remind\uFF08\u9700 confirm \u4E0E continuation\uFF09").option("--continuation <token>", "continuation token from prepare").option("--yes", "confirm the write operation")
2145
+ ).action(action(async (ctx, options) => {
2146
+ const opts = asOptions(options);
2147
+ await executeAndPrint(ctx, "blog.remind.apply", await inputFrom(options, {
2148
+ continuation: opts.continuation,
2149
+ confirm: opts.yes === true ? true : void 0
2150
+ }));
2151
+ }));
2152
+ }
2153
+ };
2154
+ export {
2155
+ blogShortcut,
2156
+ inputFrom
2157
+ };