@yijiancaotang/cli 1.0.0 → 1.2.0

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 (50) hide show
  1. package/README.md +70 -26
  2. package/dist/auth.js +7 -4
  3. package/dist/calendar-contract.js +358 -0
  4. package/dist/calendar-help.js +12 -0
  5. package/dist/calendar.js +64 -0
  6. package/dist/capability-result.js +5 -0
  7. package/dist/cli.js +58 -10
  8. package/dist/command-help.js +18 -8
  9. package/dist/commands.js +11 -0
  10. package/dist/doctor.js +13 -5
  11. package/dist/generated/agent-operations.js +12 -0
  12. package/dist/habit-read.js +3 -1
  13. package/dist/habit-wire.js +36 -5
  14. package/dist/handoff-read.js +29 -0
  15. package/dist/handoff-wire.js +42 -0
  16. package/dist/http.js +11 -1
  17. package/dist/input-validation.js +14 -0
  18. package/dist/installation.js +334 -45
  19. package/dist/local-commands.js +133 -16
  20. package/dist/local-records.js +150 -0
  21. package/dist/local-types.js +1 -0
  22. package/dist/managed-skill-baseline.js +35 -0
  23. package/dist/missing-sections.js +1 -0
  24. package/dist/onboarding.js +4 -20
  25. package/dist/output.js +7 -1
  26. package/dist/platforms.js +69 -12
  27. package/dist/project-binding-cli.js +110 -0
  28. package/dist/project-binding.js +370 -0
  29. package/dist/query-search.js +3 -2
  30. package/dist/reviewed-managed-bundle-baseline.js +356 -0
  31. package/dist/schedule-contract.js +289 -0
  32. package/dist/schedule-help.js +35 -0
  33. package/dist/schedule-start-wire.js +80 -0
  34. package/dist/schedule.js +70 -0
  35. package/dist/setup-guidance.js +40 -0
  36. package/dist/skill-assets.js +1 -1
  37. package/dist/skills-export.js +206 -0
  38. package/dist/web-citations.js +1 -1
  39. package/dist/work-context-human.js +67 -0
  40. package/dist/work-context-wire.js +391 -0
  41. package/dist/write-routing.js +26 -0
  42. package/package.json +2 -2
  43. package/skills/caotang-context/SKILL.md +20 -7
  44. package/skills/caotang-first-connect/SKILL.md +48 -34
  45. package/skills/caotang-project-progress/SKILL.md +6 -2
  46. package/skills/caotang-save-knowledge/SKILL.md +6 -4
  47. package/skills/caotang-schedule/SKILL.md +54 -0
  48. package/skills/caotang-search/SKILL.md +11 -0
  49. package/skills/caotang-workday/SKILL.md +56 -9
  50. package/skills/manifest.json +28 -6
@@ -0,0 +1,356 @@
1
+ // Exact runtime bytes from reviewed CLI tgz 8ce64d4ae13656763b913da10637cd20da85b6763fb7a5c02757a1417b7f8d9b.
2
+ // One full-content baseline only; version/receipt/directory self-reports are not evidence.
3
+ export const REVIEWED_MANAGED_BUNDLE_1_1_0 = {
4
+ "version": "1.1.0",
5
+ "sha": "ed87c23c98d57cd990a5212a05788cc95136b6bc810e61f30c1fbac7026c212a",
6
+ "files": [
7
+ {
8
+ "path": "bin/caotang.cjs",
9
+ "mode": 448,
10
+ "bytes": 861,
11
+ "sha256": "b1047ea22a774718e377edcb4a18e3c16ce2b101ad40c5d39721894d652f37c5"
12
+ },
13
+ {
14
+ "path": "dist/agent-identity.js",
15
+ "mode": 384,
16
+ "bytes": 1417,
17
+ "sha256": "e217376060e8c5a46c6c58f596f198750c3154eca561be757fee7151e3e1c86c"
18
+ },
19
+ {
20
+ "path": "dist/auth.js",
21
+ "mode": 384,
22
+ "bytes": 20770,
23
+ "sha256": "5c0917ae4b212b47091ca205d40427f8dd580bd494ccc6b5c586177bbfded0e0"
24
+ },
25
+ {
26
+ "path": "dist/calendar-contract.js",
27
+ "mode": 384,
28
+ "bytes": 24328,
29
+ "sha256": "3124493cea046a0f0dc6841f52610cb4e1aae78f3375de7090e378010f953807"
30
+ },
31
+ {
32
+ "path": "dist/calendar-help.js",
33
+ "mode": 384,
34
+ "bytes": 4578,
35
+ "sha256": "224c5eeb5376358593e04501c4d92d39174a6ca23e1d4bc46729e8f84058c37a"
36
+ },
37
+ {
38
+ "path": "dist/calendar.js",
39
+ "mode": 384,
40
+ "bytes": 3748,
41
+ "sha256": "b10c9135617e9c9fe6530fef32c6679ff9e6c497967308a33ddd2013469e7a6f"
42
+ },
43
+ {
44
+ "path": "dist/capability-result.js",
45
+ "mode": 384,
46
+ "bytes": 3829,
47
+ "sha256": "09d398275dfeb82c18bcfa0b9abe6341607678e3248eb543d944fed390a0466d"
48
+ },
49
+ {
50
+ "path": "dist/cli.js",
51
+ "mode": 384,
52
+ "bytes": 22177,
53
+ "sha256": "71eff64b32306430fd9c35a2ecc633dda195eec7064c3b700822de3b76940af8"
54
+ },
55
+ {
56
+ "path": "dist/command-help.js",
57
+ "mode": 384,
58
+ "bytes": 14071,
59
+ "sha256": "556be79209c89eef690f18866cd27803aef671279b411f73383c115a82a41cc6"
60
+ },
61
+ {
62
+ "path": "dist/commands.js",
63
+ "mode": 384,
64
+ "bytes": 23262,
65
+ "sha256": "cfc95b14372a105c917b588e4574458196b58bf30967591361f8bdec0493b989"
66
+ },
67
+ {
68
+ "path": "dist/config.js",
69
+ "mode": 384,
70
+ "bytes": 1289,
71
+ "sha256": "7a99ac4696d06db5bcecef3a9c9e406ef079ace724101bf720bf916e319bef0a"
72
+ },
73
+ {
74
+ "path": "dist/connection-copy.js",
75
+ "mode": 384,
76
+ "bytes": 2284,
77
+ "sha256": "5617453b07fe39ebf1fa20a4a4f64729adbfb2f93a51f9754330b2be60bb6078"
78
+ },
79
+ {
80
+ "path": "dist/context.js",
81
+ "mode": 384,
82
+ "bytes": 1885,
83
+ "sha256": "6c92b7c7f7d11674bebb0f6f9981794ac64a8c94f45393a9a4e5b6e92bd87616"
84
+ },
85
+ {
86
+ "path": "dist/contracts.js",
87
+ "mode": 384,
88
+ "bytes": 11,
89
+ "sha256": "8e609bb71c20b858c77f0e9f90bb1319db8477b13f9f965f1a1e18524bf50881"
90
+ },
91
+ {
92
+ "path": "dist/create-bundle.js",
93
+ "mode": 384,
94
+ "bytes": 9646,
95
+ "sha256": "043713b3e9d435268634aab72dc6f8a15017b5be1ecf4760bde2d788f31e95f5"
96
+ },
97
+ {
98
+ "path": "dist/create-file-failure.js",
99
+ "mode": 384,
100
+ "bytes": 1555,
101
+ "sha256": "690a59a4fc47b624260d753bbf79b88ecb8a83d6ee846341e3c9133779dff045"
102
+ },
103
+ {
104
+ "path": "dist/credential-store.js",
105
+ "mode": 384,
106
+ "bytes": 27762,
107
+ "sha256": "2bf9b031eec6cf984af30822e5fa7b5e8f8888f58d09084e723feeaf49c291a2"
108
+ },
109
+ {
110
+ "path": "dist/doctor.js",
111
+ "mode": 384,
112
+ "bytes": 17642,
113
+ "sha256": "c0438daeab4483a483051f9bd94beb40d5cedd11f20155506f09bbb3d5ec00c2"
114
+ },
115
+ {
116
+ "path": "dist/errors.js",
117
+ "mode": 384,
118
+ "bytes": 17485,
119
+ "sha256": "0634831524769f8c348aea43f8b2b90f1e5eab74f66bdf3c0ef77057c8a3e9d7"
120
+ },
121
+ {
122
+ "path": "dist/generated/knowledge-growth.js",
123
+ "mode": 384,
124
+ "bytes": 1324,
125
+ "sha256": "3fefbb5bd04dfef4548b21bb91b739bbdcc4f565cfd34d8cf08bdcb598d069b9"
126
+ },
127
+ {
128
+ "path": "dist/habit-day.js",
129
+ "mode": 384,
130
+ "bytes": 2697,
131
+ "sha256": "23bbcd87ae6af1d874c57e5601b2ac6a6d27982f94a84490fdce0a5fb565b237"
132
+ },
133
+ {
134
+ "path": "dist/habit-read.js",
135
+ "mode": 384,
136
+ "bytes": 2134,
137
+ "sha256": "db69e3a7ba00887367d86e101dd451efe4b993138cee6704fb96031dcbcf965f"
138
+ },
139
+ {
140
+ "path": "dist/habit-wire.js",
141
+ "mode": 384,
142
+ "bytes": 7188,
143
+ "sha256": "ce414a79b8e444f97a641eb048e52397bf2d5b3e162121f2f349ebfeb0d0b8f7"
144
+ },
145
+ {
146
+ "path": "dist/http.js",
147
+ "mode": 384,
148
+ "bytes": 10029,
149
+ "sha256": "8bdb9bede2b928037e882a9b375d0a1959d53f599b969d83fa2081248e051f67"
150
+ },
151
+ {
152
+ "path": "dist/input-validation.js",
153
+ "mode": 384,
154
+ "bytes": 4135,
155
+ "sha256": "c5382d9287b1f330a5468d2c3abad33903bc560182f45d69f121a132ac15e28b"
156
+ },
157
+ {
158
+ "path": "dist/installation.js",
159
+ "mode": 384,
160
+ "bytes": 39276,
161
+ "sha256": "4e371462d83abc0e440906cdc802a3a3713e6f62cf59c3e2e0519492a5cd08db"
162
+ },
163
+ {
164
+ "path": "dist/knowledge-growth.js",
165
+ "mode": 384,
166
+ "bytes": 4257,
167
+ "sha256": "18187fb1100faf0d79e32fc1bf0455ad35d59ffe94d35040b9a765d89674c12b"
168
+ },
169
+ {
170
+ "path": "dist/local-commands.js",
171
+ "mode": 384,
172
+ "bytes": 17710,
173
+ "sha256": "0ddde63bb06d84acce0072be202384e550c070cfddb7befb7477eb3fd6ad1e36"
174
+ },
175
+ {
176
+ "path": "dist/local-lock.js",
177
+ "mode": 384,
178
+ "bytes": 9362,
179
+ "sha256": "3ee54676ebb20a177bb22726ff6d08d329a511b25500e59cd969e5a27c5e417a"
180
+ },
181
+ {
182
+ "path": "dist/local-records.js",
183
+ "mode": 384,
184
+ "bytes": 8122,
185
+ "sha256": "a2304b1ad0ddc3107265a61faf3935b3a3f14436be275906dd9a306338fa6b77"
186
+ },
187
+ {
188
+ "path": "dist/local-types.js",
189
+ "mode": 384,
190
+ "bytes": 358,
191
+ "sha256": "d43abb2a72ecb33f501e5c16bf624fd971f33f3541153937060f4320d54d956f"
192
+ },
193
+ {
194
+ "path": "dist/managed-skill-baseline.js",
195
+ "mode": 384,
196
+ "bytes": 2142,
197
+ "sha256": "63f869e057d2bc41405facc9a4883c136955255bef2abc2c443c85e204ed8d97"
198
+ },
199
+ {
200
+ "path": "dist/missing-sections.js",
201
+ "mode": 384,
202
+ "bytes": 4216,
203
+ "sha256": "9ce6d37478ebc813ce9d2ee1a8372bdc8170a7867274a7bf5f817052972b88b7"
204
+ },
205
+ {
206
+ "path": "dist/onboarding.js",
207
+ "mode": 384,
208
+ "bytes": 2768,
209
+ "sha256": "f48693b69edadba01dc34fd4949bcd617bc3130451c4ea6c158860bc85e2aaaf"
210
+ },
211
+ {
212
+ "path": "dist/output.js",
213
+ "mode": 384,
214
+ "bytes": 3970,
215
+ "sha256": "0f8cdd45522f2990d77d5078820d7a6897a4e4e1c969fc729480ce14017276fc"
216
+ },
217
+ {
218
+ "path": "dist/pending-requests.js",
219
+ "mode": 384,
220
+ "bytes": 3697,
221
+ "sha256": "29ba9aa0af625fde56dd7d3da708d2a283d2a0aef40118f1ce16304e9ee01195"
222
+ },
223
+ {
224
+ "path": "dist/platforms.js",
225
+ "mode": 384,
226
+ "bytes": 10224,
227
+ "sha256": "5660acdd8f1471c7ff2df19e02ce23ebfbb5124846b2e04882a1670158ad7392"
228
+ },
229
+ {
230
+ "path": "dist/query-daily.js",
231
+ "mode": 384,
232
+ "bytes": 6188,
233
+ "sha256": "5648b0322f72c8296df9d3beac7a788cd94f7af9c902c46539a9ae4f36834b67"
234
+ },
235
+ {
236
+ "path": "dist/query-search.js",
237
+ "mode": 384,
238
+ "bytes": 4015,
239
+ "sha256": "eeb4b76665489edd57e2ab757ce585cdf91941c08cbc088758ed88b35f130332"
240
+ },
241
+ {
242
+ "path": "dist/query-validation.js",
243
+ "mode": 384,
244
+ "bytes": 3439,
245
+ "sha256": "0aa2123725ca27720eb86cfbe59cb1f6771ee2db2991150eae783db9c4c9cd79"
246
+ },
247
+ {
248
+ "path": "dist/schedule-contract.js",
249
+ "mode": 384,
250
+ "bytes": 16879,
251
+ "sha256": "d5f5a43e4ac33274ddf275d00dd5b3696fe125c773e117979643830b5294da6e"
252
+ },
253
+ {
254
+ "path": "dist/schedule-help.js",
255
+ "mode": 384,
256
+ "bytes": 4821,
257
+ "sha256": "cc86c38e16e8660fca343dc95d2dfc9af525b41296c67db2ccd1b969f7da82f4"
258
+ },
259
+ {
260
+ "path": "dist/schedule-start-wire.js",
261
+ "mode": 384,
262
+ "bytes": 3634,
263
+ "sha256": "6b6b6843dd41053c3b334c0785100de90ef3f4e5af130fb839911897100161ce"
264
+ },
265
+ {
266
+ "path": "dist/schedule.js",
267
+ "mode": 384,
268
+ "bytes": 4030,
269
+ "sha256": "ee234a5744aa0cef9afcbd0b2ac9cb4336e7226069a148c39858fa439a25202e"
270
+ },
271
+ {
272
+ "path": "dist/skill-assets.js",
273
+ "mode": 384,
274
+ "bytes": 6960,
275
+ "sha256": "962171172db20f2ecc1cc0eaa9863e2f27e414b7cf1399fb224cade57b09613d"
276
+ },
277
+ {
278
+ "path": "dist/upload.js",
279
+ "mode": 384,
280
+ "bytes": 7625,
281
+ "sha256": "59c862ea1d31f90e48a746f8d26fb0903c8bedd3af0f0b4624c744280359afff"
282
+ },
283
+ {
284
+ "path": "dist/web-citations.js",
285
+ "mode": 384,
286
+ "bytes": 4509,
287
+ "sha256": "58cd8275f992f88a030f30239bb78eb301948e40e24d9c2c0e9b4fe27aa3d00a"
288
+ },
289
+ {
290
+ "path": "dist/write-permissions.js",
291
+ "mode": 384,
292
+ "bytes": 2497,
293
+ "sha256": "ecaf3009ee061d246d85aef69036815c5ae778617578be7e4f3513426045cc1b"
294
+ },
295
+ {
296
+ "path": "dist/write-routing.js",
297
+ "mode": 384,
298
+ "bytes": 2629,
299
+ "sha256": "4acff0b485ee0c8a394adf5142122f82ca14c6d03fdaf81fd7c46aa80fe8f39c"
300
+ },
301
+ {
302
+ "path": "package.json",
303
+ "mode": 384,
304
+ "bytes": 140,
305
+ "sha256": "ecddc8f82d17dec46897ed0d324b24f5465451dc413a90b1e0ba7a8b0e259889"
306
+ },
307
+ {
308
+ "path": "skills/caotang-context/SKILL.md",
309
+ "mode": 384,
310
+ "bytes": 7260,
311
+ "sha256": "0580c8513de3f91c9a12cf94290200e90d1a0ee5dc2610e0654ccc3146832732"
312
+ },
313
+ {
314
+ "path": "skills/caotang-first-connect/SKILL.md",
315
+ "mode": 384,
316
+ "bytes": 11277,
317
+ "sha256": "cbbe660f4a058214ff6fbc320f999f7342457384ba9a38ce493f1dbc8eda7692"
318
+ },
319
+ {
320
+ "path": "skills/caotang-project-progress/SKILL.md",
321
+ "mode": 384,
322
+ "bytes": 9829,
323
+ "sha256": "1a5a2c4849aca52237a1e18f6c70bbddd2a9815260c87ce6fb26872736120c94"
324
+ },
325
+ {
326
+ "path": "skills/caotang-save-knowledge/SKILL.md",
327
+ "mode": 384,
328
+ "bytes": 6779,
329
+ "sha256": "002dd420b32851b1b0a97175baaf270c44c327900c1f9ae40197673d415e10fa"
330
+ },
331
+ {
332
+ "path": "skills/caotang-schedule/SKILL.md",
333
+ "mode": 384,
334
+ "bytes": 5365,
335
+ "sha256": "e2f3689412b39cc1475ba56d6e6082380ed9bbc195f6fb44ed9b5e9992a787a4"
336
+ },
337
+ {
338
+ "path": "skills/caotang-search/SKILL.md",
339
+ "mode": 384,
340
+ "bytes": 9895,
341
+ "sha256": "d69f9e6dae707c163139ddb64eef787bd9ae1d3ca0328079353f206085edf0a2"
342
+ },
343
+ {
344
+ "path": "skills/caotang-workday/SKILL.md",
345
+ "mode": 384,
346
+ "bytes": 7233,
347
+ "sha256": "b20b3592e2d9d61d1d42638b51fdcd34bbe113b6655ec353e342e45aa7dd65cb"
348
+ },
349
+ {
350
+ "path": "skills/manifest.json",
351
+ "mode": 384,
352
+ "bytes": 1438,
353
+ "sha256": "9bdbf8e82510fd51036704e8de6830a4d53bc8a6d97aad3c3a20c883c50c9939"
354
+ }
355
+ ]
356
+ };
@@ -0,0 +1,289 @@
1
+ export const scheduleRoot = "/api/v1/agent";
2
+ export const scheduleKeyPattern = /^[A-Za-z0-9._:-]{16,128}(?![\s\S])/;
3
+ export const scheduleUUID = (value) => typeof value === "string" && /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}(?![\s\S])/i.test(value);
4
+ const record = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
5
+ const scalarText = (value) => ![...value].some(char => { const n = char.codePointAt(0); return n >= 0xd800 && n <= 0xdfff; });
6
+ const trim = (value) => value.replace(/^\p{White_Space}+|\p{White_Space}+$/gu, "");
7
+ export const validScheduleRevision = (value) => typeof value === "number" && Number.isSafeInteger(value) && value > 0;
8
+ export function validScheduleDate(value) {
9
+ if (typeof value !== "string" || !/^(?!0000)\d{4}-\d{2}-\d{2}(?![\s\S])/.test(value))
10
+ return false;
11
+ const date = new Date(value + "T00:00:00Z");
12
+ return Number.isFinite(date.getTime()) && date.toISOString().slice(0, 10) === value;
13
+ }
14
+ export function validScheduleTime(value) {
15
+ if (typeof value !== "string" || !/^(?!0000)\d{4}-\d{2}-\d{2}T([01]\d|2[0-3]):[0-5]\d:[0-5]\d(\.\d{1,9})?(Z|[+-]([01]\d|2[0-3]):[0-5]\d)(?![\s\S])/.test(value))
16
+ return false;
17
+ return validScheduleDate(value.slice(0, 10)) && Number.isFinite(Date.parse(value));
18
+ }
19
+ export class ScheduleProblem extends Error {
20
+ code;
21
+ humanMessage;
22
+ nextAction;
23
+ exitCode;
24
+ details;
25
+ constructor(code, humanMessage, nextAction, exitCode = 2, details = {}) {
26
+ super(JSON.stringify({ code, message: humanMessage, next_action: nextAction, ...details }));
27
+ this.code = code;
28
+ this.humanMessage = humanMessage;
29
+ this.nextAction = nextAction;
30
+ this.exitCode = exitCode;
31
+ this.details = details;
32
+ }
33
+ }
34
+ export function scheduleInvalid() {
35
+ throw new ScheduleProblem("invalid_arguments", "日程命令或参数无效。", "请查看本命令帮助,只提交本人确认的字段;日期用 YYYY-MM-DD,精确时间用带时区偏移的 RFC3339。");
36
+ }
37
+ export function scheduleKey(value) {
38
+ if (typeof value !== "string" || !scheduleKeyPattern.test(value))
39
+ return scheduleInvalid();
40
+ return value;
41
+ }
42
+ export function scheduleID(value) {
43
+ return scheduleUUID(value) ? value : scheduleInvalid();
44
+ }
45
+ export function scheduleQuery(input) {
46
+ const allowed = ["view", "status", "group_by", "project_id", "q", "start_date", "end_date", "limit", "offset"];
47
+ const out = {};
48
+ for (const [name, value] of Object.entries(input)) {
49
+ if (!allowed.includes(name))
50
+ scheduleInvalid();
51
+ if (value === undefined)
52
+ continue;
53
+ if (name === "limit" || name === "offset") {
54
+ if (typeof value !== "number" || !Number.isSafeInteger(value) || value < (name === "limit" ? 1 : 0) || (name === "limit" && value > 100))
55
+ scheduleInvalid();
56
+ }
57
+ else {
58
+ if (typeof value !== "string" || value === "" || !scalarText(value) || value.includes("\0"))
59
+ scheduleInvalid();
60
+ if (name === "view" && !["pending", "workbench", "recent_completed", "history"].includes(value))
61
+ scheduleInvalid();
62
+ if (name === "status" && (!["all", "completed", "cancelled"].includes(value) || input.view !== "history"))
63
+ scheduleInvalid();
64
+ if (name === "group_by" && !["date", "project"].includes(value))
65
+ scheduleInvalid();
66
+ if (name === "project_id" && value !== "none" && !scheduleUUID(value))
67
+ scheduleInvalid();
68
+ if ((name === "start_date" || name === "end_date") && !validScheduleDate(value))
69
+ scheduleInvalid();
70
+ if (name === "q" && [...trim(value)].length > 200)
71
+ scheduleInvalid();
72
+ }
73
+ out[name] = value;
74
+ }
75
+ if (typeof input.start_date === "string" && typeof input.end_date === "string" && input.start_date > input.end_date)
76
+ scheduleInvalid();
77
+ return out;
78
+ }
79
+ export function scheduleBody(operation, value) {
80
+ if (!record(value))
81
+ return scheduleInvalid();
82
+ const fields = operation === "create" || operation === "update" ? ["title", "due_date", "due_at", "project_id", "confirmed"] : ["confirmed"];
83
+ if (Object.keys(value).some(name => !fields.includes(name)) || value.confirmed !== true)
84
+ return scheduleInvalid();
85
+ if (operation === "create" && !Object.hasOwn(value, "title"))
86
+ scheduleInvalid();
87
+ if (operation === "update" && !["title", "due_date", "due_at", "project_id"].some(name => Object.hasOwn(value, name)))
88
+ scheduleInvalid();
89
+ const out = { ...value };
90
+ if (Object.hasOwn(value, "title")) {
91
+ if (typeof value.title !== "string" || !scalarText(value.title))
92
+ scheduleInvalid();
93
+ const title = trim(value.title);
94
+ if (!title || [...title].length > 200 || /[\p{Cc}\u2028\u2029]/u.test(title))
95
+ scheduleInvalid();
96
+ out.title = title;
97
+ }
98
+ for (const name of ["due_date", "due_at", "project_id"]) {
99
+ if (!Object.hasOwn(value, name))
100
+ continue;
101
+ const item = value[name];
102
+ if (item === null || item === "")
103
+ continue;
104
+ if (name === "due_date" ? !validScheduleDate(item) : name === "due_at" ? !validScheduleTime(item) : !scheduleUUID(item))
105
+ scheduleInvalid();
106
+ }
107
+ if (value.due_date && value.due_at)
108
+ scheduleInvalid();
109
+ return out;
110
+ }
111
+ export function scheduleUnknown(key, status) {
112
+ return new ScheduleProblem("write_outcome_unknown", "日程写入结果未确认,不能视为成功。", "保留原幂等键,用 schedule status 或 get_schedule_write_status 核对同一连接的回执;不要换键、自动重试或执行依赖写入。", 6, { write_status: "unknown", idempotency_key: key, ...(status === undefined ? {} : { http_status: status }) });
113
+ }
114
+ export function scheduleFailure(status, body, capabilities, key) {
115
+ if (key && (status === 202 || status >= 500))
116
+ return scheduleUnknown(key, status);
117
+ const raw = record(body) ? body.code ?? body.error : undefined;
118
+ const consistent = record(body) && (body.code === undefined || body.code === raw) && (body.error === undefined || body.error === raw);
119
+ const codes = {
120
+ 400: ["invalid_schedule_query", "invalid_schedule_id", "invalid_idempotency_key", "invalid_schedule_revision", "invalid_schedule_input", "schedule_confirmation_required"],
121
+ 401: ["not_authenticated"], 403: ["token_scope_insufficient", "capability_disabled", "second_confirmation_required", "legal_consent_required", "account_unavailable"],
122
+ 404: ["schedule_not_found"], 409: ["schedule_revision_conflict", "idempotency_conflict", "schedule_closed", "schedule_undo_expired"],
123
+ 415: ["invalid_content_type"], 429: ["rate_limited"], 503: ["schedule_unavailable"]
124
+ };
125
+ const code = consistent && typeof raw === "string" && codes[status]?.includes(raw) ? raw : "request_rejected";
126
+ const details = { http_status: status, ...(key ? { idempotency_key: key } : {}) };
127
+ if (code === "capability_disabled" && record(body) && typeof body.required_capability === "string" && capabilities.includes(body.required_capability)
128
+ && (!Object.hasOwn(body, "missing_sections") || Array.isArray(body.missing_sections) && body.missing_sections.length === 0))
129
+ details.required_capability = body.required_capability;
130
+ const next = status === 403 ? "请本人在网页核对账号能力、设备只读/读写范围或协议确认;不要重新授权或换入口绕过限制。"
131
+ : status === 409 ? "请先读取当前版本或到网页核对;撤销只在完成后的约 5 秒内有效,不自动重试或换键。"
132
+ : "请核对命令输入、服务版本和实际状态,不把失败或权限缺口解释为没有日程,不自动重试写入。";
133
+ return new ScheduleProblem(code, status === 403 ? "日程操作权限不足。" : status === 409 ? "日程状态或版本冲突,本次未确认写入。" : "日程请求未完成。", next, status === 401 ? 3 : status === 403 ? 4 : status >= 500 ? 7 : 2, details);
134
+ }
135
+ const buckets = ["overdue", "today", "tomorrow", "this_week", "later", "undated"];
136
+ const countNames = [...buckets, "completed", "cancelled"];
137
+ const natural = (value) => typeof value === "number" && Number.isSafeInteger(value) && value >= 0;
138
+ const safeText = (value) => typeof value === "string" && scalarText(value) && !/[\p{Cc}\u2028\u2029]/u.test(value);
139
+ const projectText = (value) => typeof value === "string" && scalarText(value) && [...value].length >= 1 && [...value].length <= 80;
140
+ function readInvalid() {
141
+ throw new ScheduleProblem("invalid_response", "日程读取回执无法核实。", "请核对服务版本和访问范围,不把异常响应解释为没有日程。", 7);
142
+ }
143
+ function projectItem(value) {
144
+ if (!record(value) || !scheduleUUID(value.id) || !validScheduleRevision(value.revision)
145
+ || !safeText(value.title) || !trim(value.title) || [...value.title].length > 200
146
+ || typeof value.status !== "string" || !["pending", "completed", "cancelled"].includes(value.status)
147
+ || !validScheduleTime(value.created_at) || !validScheduleTime(value.updated_at))
148
+ return readInvalid();
149
+ const out = { id: value.id, title: value.title, status: value.status, revision: value.revision, created_at: value.created_at, updated_at: value.updated_at };
150
+ for (const name of ["due_date", "due_at", "project_id", "project_title", "project_unavailable_reason", "completed_at", "cancelled_at", "undo_until", "bucket", "closed_actor_kind", "closed_actor_name"]) {
151
+ if (!Object.hasOwn(value, name))
152
+ continue;
153
+ const field = value[name];
154
+ if (name === "project_title" ? !projectText(field) : !safeText(field) || !field)
155
+ readInvalid();
156
+ if (name === "due_date" && !validScheduleDate(field) || name === "project_id" && !scheduleUUID(field)
157
+ || ["due_at", "completed_at", "cancelled_at", "undo_until"].includes(name) && !validScheduleTime(field)
158
+ || name === "bucket" && !buckets.includes(field)
159
+ || name === "project_unavailable_reason" && field !== "project_unavailable")
160
+ readInvalid();
161
+ out[name] = field;
162
+ }
163
+ if (out.due_date && out.due_at)
164
+ readInvalid();
165
+ if (out.project_unavailable_reason) {
166
+ delete out.project_id;
167
+ delete out.project_title;
168
+ }
169
+ else if (out.project_title && !out.project_id)
170
+ readInvalid();
171
+ return out;
172
+ }
173
+ export function scheduleReadResult(status, value, detail) {
174
+ if (status !== 200 || !record(value) || value.timezone !== "Asia/Shanghai")
175
+ return readInvalid();
176
+ if (detail)
177
+ return { schedule_item: projectItem(value.schedule_item), timezone: "Asia/Shanghai" };
178
+ if (!Array.isArray(value.items) || !Array.isArray(value.groups) || !record(value.counts)
179
+ || !natural(value.total) || !natural(value.offset) || !natural(value.limit) || value.limit < 1 || value.limit > 100
180
+ || typeof value.has_more !== "boolean")
181
+ return readInvalid();
182
+ const total = value.total, offset = value.offset, limit = value.limit;
183
+ const items = value.items.map(projectItem);
184
+ if (items.length !== Math.min(limit, Math.max(0, total - offset)) || value.has_more !== (offset < total && items.length < total - offset))
185
+ readInvalid();
186
+ const counts = {};
187
+ for (const name of countNames) {
188
+ if (!natural(value.counts[name]))
189
+ readInvalid();
190
+ counts[name] = value.counts[name];
191
+ }
192
+ if (Object.values(counts).reduce((sum, count) => sum + count, 0) !== total)
193
+ readInvalid();
194
+ const itemMap = new Map(), shownCounts = {};
195
+ for (const item of items) {
196
+ if (itemMap.has(item.id) || typeof item.bucket !== "string")
197
+ readInvalid();
198
+ itemMap.set(item.id, item);
199
+ const name = item.status === "pending" ? item.bucket : item.status;
200
+ shownCounts[name] = (shownCounts[name] ?? 0) + 1;
201
+ if (shownCounts[name] > counts[name])
202
+ readInvalid();
203
+ }
204
+ const groupKeys = new Set(), groupedIDs = new Set();
205
+ let groupTotal = 0;
206
+ const groups = value.groups.map(raw => {
207
+ if (!record(raw) || !safeText(raw.key) || !raw.key || groupKeys.has(raw.key)
208
+ || !natural(raw.total) || !natural(raw.shown) || raw.shown < 1 || raw.total < raw.shown || raw.total > total
209
+ || typeof raw.has_more !== "boolean" || raw.has_more !== (raw.shown < raw.total)
210
+ || !Array.isArray(raw.items) || raw.items.length !== raw.shown)
211
+ return readInvalid();
212
+ groupKeys.add(raw.key);
213
+ groupTotal += raw.total;
214
+ const groupItems = raw.items.map(projectItem);
215
+ for (const item of groupItems) {
216
+ const id = item.id;
217
+ if (groupedIDs.has(id) || !itemMap.has(id) || JSON.stringify(itemMap.get(id)) !== JSON.stringify(item))
218
+ readInvalid();
219
+ groupedIDs.add(id);
220
+ }
221
+ const group = { key: raw.key, total: raw.total, shown: raw.shown, has_more: raw.has_more, items: groupItems };
222
+ if (Object.hasOwn(raw, "title")) {
223
+ if (!projectText(raw.title))
224
+ readInvalid();
225
+ group.title = raw.title;
226
+ }
227
+ if (Object.hasOwn(raw, "project_id")) {
228
+ if (!scheduleUUID(raw.project_id) || raw.key !== raw.project_id)
229
+ readInvalid();
230
+ group.project_id = raw.project_id;
231
+ }
232
+ return group;
233
+ });
234
+ if (groupedIDs.size !== items.length || groupTotal > total)
235
+ readInvalid();
236
+ return { items, groups, counts, total, limit, offset, has_more: value.has_more, timezone: "Asia/Shanghai" };
237
+ }
238
+ export function scheduleReceipt(status, value, key) {
239
+ if (![200, 201].includes(status) || !record(value) || !scheduleUUID(value.id) || value.write_status !== "confirmed" || typeof value.replayed !== "boolean"
240
+ || value.code !== undefined || value.error !== undefined
241
+ || value.read_permission_missing !== undefined && typeof value.read_permission_missing !== "boolean"
242
+ || value.read_unavailable !== undefined && typeof value.read_unavailable !== "boolean")
243
+ throw scheduleUnknown(key, status);
244
+ const out = { id: value.id, write_status: "confirmed", replayed: value.replayed };
245
+ const missing = value.missing_sections;
246
+ if (value.read_permission_missing === true || value.read_unavailable === true || Array.isArray(missing) && missing.length > 0) {
247
+ const unavailable = value.read_unavailable === true;
248
+ const reason = unavailable ? "read_failed" : "capability_disabled";
249
+ if (!Array.isArray(missing) || missing.length !== 1 || !record(missing[0]) || missing[0].section !== "schedule_items"
250
+ || missing[0].required_capability !== "read_workbench" || missing[0].reason !== reason
251
+ || unavailable && value.read_permission_missing === true)
252
+ throw scheduleUnknown(key, status);
253
+ out[unavailable ? "read_unavailable" : "read_permission_missing"] = true;
254
+ out.missing_sections = [{ section: "schedule_items", required_capability: "read_workbench", reason }];
255
+ }
256
+ else {
257
+ if (missing !== undefined && (!Array.isArray(missing) || missing.length !== 0))
258
+ throw scheduleUnknown(key, status);
259
+ try {
260
+ out.schedule_item = projectItem(value.schedule_item);
261
+ }
262
+ catch {
263
+ throw scheduleUnknown(key, status);
264
+ }
265
+ if (out.schedule_item.id !== value.id)
266
+ throw scheduleUnknown(key, status);
267
+ }
268
+ return out;
269
+ }
270
+ export function isScheduleHeaderPath(path, method) {
271
+ return method === "GET" && path === scheduleRoot + "/m1/schedule-write-status"
272
+ || method === "POST" && (path === scheduleRoot + "/m2/schedule-items" || /^\/api\/v1\/agent\/m2\/schedule-items\/[^/]+\/(complete|cancel|undo)$/.test(path))
273
+ || method === "PATCH" && /^\/api\/v1\/agent\/m2\/schedule-items\/[^/]+$/.test(path);
274
+ }
275
+ export function scheduleHeaders(path, method, value) {
276
+ if (!record(value) || Object.keys(value).some(name => !["Idempotency-Key", "If-Match"].includes(name)))
277
+ return scheduleInvalid();
278
+ const headers = { "Idempotency-Key": scheduleKey(value["Idempotency-Key"]) };
279
+ const revisionRequired = method !== "GET" && path !== scheduleRoot + "/m2/schedule-items";
280
+ if (revisionRequired) {
281
+ const revision = value["If-Match"];
282
+ if (typeof revision !== "string" || !/^"[1-9]\d*"(?![\s\S])/.test(revision) || !validScheduleRevision(Number(revision.slice(1, -1))))
283
+ return scheduleInvalid();
284
+ headers["If-Match"] = revision;
285
+ }
286
+ else if (value["If-Match"] !== undefined)
287
+ scheduleInvalid();
288
+ return headers;
289
+ }