@maudecode/kanvil 0.3.0 → 0.4.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 (125) hide show
  1. package/apps/server/dist/{auth-JcS53IcO.mjs → auth-Cuo7ECLh.mjs} +119 -4773
  2. package/apps/server/dist/client.mjs +884 -0
  3. package/apps/server/dist/{config-D3cAABi7.mjs → config-DtNfVSnB.mjs} +2 -132
  4. package/apps/server/dist/index.mjs +6 -4
  5. package/apps/server/dist/instance-CCeXRJ6m.mjs +133 -0
  6. package/apps/server/dist/migrate.mjs +1 -1
  7. package/apps/server/dist/recover.mjs +3 -2
  8. package/apps/server/dist/src-tQ82UI8k.mjs +4818 -0
  9. package/apps/server/drizzle/0038_time_entries.sql +19 -0
  10. package/apps/server/drizzle/meta/0038_snapshot.json +6998 -0
  11. package/apps/server/drizzle/meta/_journal.json +7 -0
  12. package/apps/web/dist/assets/{CompositeItem-BbuEp99X.js → CompositeItem-DgnfVvrF.js} +1 -1
  13. package/apps/web/dist/assets/{Trans-DJGH63s1.js → Trans-f2VYVS9z.js} +1 -1
  14. package/apps/web/dist/assets/admin-settings-DBZL4siY.js +1 -0
  15. package/apps/web/dist/assets/{archive-restore-B6_SsOIP.js → archive-restore-CGuLxoHC.js} +1 -1
  16. package/apps/web/dist/assets/az-AZ-DesqXNg5.js +1 -0
  17. package/apps/web/dist/assets/{az-DqY__MpS.js → az-BE5iqNIE.js} +1 -1
  18. package/apps/web/dist/assets/{corner-left-up-DA7MG5uX.js → corner-left-up-BCro--Gl.js} +1 -1
  19. package/apps/web/dist/assets/de-DE-BIGY9SNm.js +1 -0
  20. package/apps/web/dist/assets/{de-UHreLwyV.js → de-DLGjUGf_.js} +1 -1
  21. package/apps/web/dist/assets/{default-D5TdIZQS.js → default-BgvtI7HK.js} +1 -1
  22. package/apps/web/dist/assets/delivery-settings-CZOtb4X8.js +1 -0
  23. package/apps/web/dist/assets/{el-EJnrsyVr.js → el-CG6Xy42v.js} +1 -1
  24. package/apps/web/dist/assets/el-GR-D2TjImt0.js +1 -0
  25. package/apps/web/dist/assets/{ellipsis-D6154JKs.js → ellipsis-ZJM26JNS.js} +1 -1
  26. package/apps/web/dist/assets/{es-D2ScuV-5.js → es-Bbj5WuMM.js} +1 -1
  27. package/apps/web/dist/assets/es-ES-C_fRqLGU.js +1 -0
  28. package/apps/web/dist/assets/{forms-BcD6Wwyv.js → forms-C3pNy-qY.js} +1 -1
  29. package/apps/web/dist/assets/{fr-C_VpS8u6.js → fr-CjuIKc1o.js} +1 -1
  30. package/apps/web/dist/assets/fr-FR-_tnQsn4j.js +1 -0
  31. package/apps/web/dist/assets/{hi-CW4rdp_m.js → hi-BVVrZ-zZ.js} +1 -1
  32. package/apps/web/dist/assets/hi-IN-CcmFsZYy.js +1 -0
  33. package/apps/web/dist/assets/{highlight-CMydIf9M.js → highlight-CKyEM4jx.js} +1 -1
  34. package/apps/web/dist/assets/{id-CvL3yBVr.js → id-BhNWOQnp.js} +1 -1
  35. package/apps/web/dist/assets/id-ID-C59tC61D.js +1 -0
  36. package/apps/web/dist/assets/index-BIuqxnJn.js +17 -0
  37. package/apps/web/dist/assets/{invitations-BmpelTJu.js → invitations-D5unaga2.js} +1 -1
  38. package/apps/web/dist/assets/{it-DOLotXOj.js → it-Cav3_-xd.js} +1 -1
  39. package/apps/web/dist/assets/it-IT-BAP5O3gK.js +1 -0
  40. package/apps/web/dist/assets/{item-Cq_ZbivE.js → item-Cj8xpMLk.js} +1 -1
  41. package/apps/web/dist/assets/{ja-B1iJt9qB.js → ja-DTmZE0Qe.js} +1 -1
  42. package/apps/web/dist/assets/ja-JP-vQa7mEdh.js +1 -0
  43. package/apps/web/dist/assets/{ko-fmUq1-8W.js → ko-BuYCMOUj.js} +1 -1
  44. package/apps/web/dist/assets/ko-KR-CXlpmX0-.js +1 -0
  45. package/apps/web/dist/assets/{label-settings-B3LsJxhk.js → label-settings-B89Ehf78.js} +1 -1
  46. package/apps/web/dist/assets/{markdown-blocks-Bw26pRKB.js → markdown-blocks-DSEA68s5.js} +1 -1
  47. package/apps/web/dist/assets/{member-directory-CHKUw0u4.js → member-directory-48yD01yN.js} +1 -1
  48. package/apps/web/dist/assets/{mk-LWVrR-T-.js → mk-BZ2Rg2sU.js} +1 -1
  49. package/apps/web/dist/assets/mk-MK-BU5BLpXM.js +1 -0
  50. package/apps/web/dist/assets/{nl-ro6hbqo5.js → nl-BtnPzRih.js} +1 -1
  51. package/apps/web/dist/assets/nl-NL-2aSpdZkg.js +1 -0
  52. package/apps/web/dist/assets/{pl-Bx_fYLKY.js → pl-Beg8hEdK.js} +1 -1
  53. package/apps/web/dist/assets/pl-PL-C5Wvnv7f.js +1 -0
  54. package/apps/web/dist/assets/project-lifecycle-CIAMJ-SX.js +1 -0
  55. package/apps/web/dist/assets/project-settings-C7lolDSl.js +1 -0
  56. package/apps/web/dist/assets/{pt-BR-D-a7F5zJ.js → pt-BR-B4VZ35N_.js} +1 -1
  57. package/apps/web/dist/assets/pt-BR-CVvI-ZB7.js +1 -0
  58. package/apps/web/dist/assets/public-project-DvvfaUd2.js +1 -0
  59. package/apps/web/dist/assets/{rotate-ccw-Bm0ESNH_.js → rotate-ccw-GjVJPDML.js} +1 -1
  60. package/apps/web/dist/assets/{ru-D-WIMI5_.js → ru-DjVJVHzv.js} +1 -1
  61. package/apps/web/dist/assets/ru-RU-C7UUdGIh.js +1 -0
  62. package/apps/web/dist/assets/search-ZaQmVnj1.js +85 -0
  63. package/apps/web/dist/assets/{send-D9TETK3s.js → send-Dr9bXHhf.js} +1 -1
  64. package/apps/web/dist/assets/settings-DXvrVvyS.js +1 -0
  65. package/apps/web/dist/assets/{sliders-horizontal-CiZZFL1o.js → sliders-horizontal-C1t_zA7D.js} +1 -1
  66. package/apps/web/dist/assets/{switch-B_u8n1o6.js → switch-D-WTDajm.js} +1 -1
  67. package/apps/web/dist/assets/{table-DcCLC7fi.js → table-BaRMFP84.js} +1 -1
  68. package/apps/web/dist/assets/ticket-detail-CFJI4qoK.js +2 -0
  69. package/apps/web/dist/assets/ticket-editor-DL3nHG_q.js +2 -0
  70. package/apps/web/dist/assets/ticket-list-CDkweYGS.js +5 -0
  71. package/apps/web/dist/assets/ticket-list-controls-CmTgFQQ-.js +1 -0
  72. package/apps/web/dist/assets/{tr-BZEJyY-F.js → tr-Ckc4TA71.js} +1 -1
  73. package/apps/web/dist/assets/tr-TR-VVsL3uMp.js +1 -0
  74. package/apps/web/dist/assets/{uk-f8X5q5C_.js → uk-B4ZvJ8xG.js} +1 -1
  75. package/apps/web/dist/assets/uk-UA-DRpCbOps.js +1 -0
  76. package/apps/web/dist/assets/{upload-CGpna3R2.js → upload-BwGa8shS.js} +1 -1
  77. package/apps/web/dist/assets/{useQueries-BihXYrAP.js → useQueries-sQEHjB0a.js} +1 -1
  78. package/apps/web/dist/assets/{vi-CSGaJFlR.js → vi-Dq2krfY8.js} +1 -1
  79. package/apps/web/dist/assets/vi-VN-C0YFqq9j.js +1 -0
  80. package/apps/web/dist/assets/{visual-editor-B6HiiLMg.js → visual-editor-CBhwqTDu.js} +1 -1
  81. package/apps/web/dist/assets/workspace-settings-DgLyieJN.js +1 -0
  82. package/apps/web/dist/assets/{zh-CN-BdRcimyZ.js → zh-CN-B7Rxc3Mp.js} +1 -1
  83. package/apps/web/dist/assets/zh-CN-pcgTdR8c.js +1 -0
  84. package/apps/web/dist/assets/zh-TW-DymSXkFg.js +1 -0
  85. package/apps/web/dist/assets/{zh-TW-BH1L9tOt.js → zh-TW-awiwHjeM.js} +1 -1
  86. package/apps/web/dist/index.html +7 -7
  87. package/bin/kanvil.mjs +3 -1
  88. package/docs/api.md +27 -1
  89. package/docs/cli.md +74 -0
  90. package/docs/plan.md +6 -1
  91. package/docs/workspaces.md +1 -1
  92. package/package.json +1 -1
  93. package/apps/web/dist/assets/admin-settings-CJG9PMKR.js +0 -1
  94. package/apps/web/dist/assets/az-AZ-BtrlbgjS.js +0 -1
  95. package/apps/web/dist/assets/de-DE-Bu_Ko2QA.js +0 -1
  96. package/apps/web/dist/assets/delivery-settings-BE5MW8U0.js +0 -1
  97. package/apps/web/dist/assets/el-GR-CpKEps47.js +0 -1
  98. package/apps/web/dist/assets/es-ES-DVkfi7H-.js +0 -1
  99. package/apps/web/dist/assets/fr-FR-DkHaEHqi.js +0 -1
  100. package/apps/web/dist/assets/hi-IN-CbUDNSTK.js +0 -1
  101. package/apps/web/dist/assets/id-ID-DLTkxt2j.js +0 -1
  102. package/apps/web/dist/assets/index-DoqlyejP.js +0 -17
  103. package/apps/web/dist/assets/it-IT-CIzq0YwC.js +0 -1
  104. package/apps/web/dist/assets/ja-JP-CIE4-D-v.js +0 -1
  105. package/apps/web/dist/assets/ko-KR-DYP5Zae6.js +0 -1
  106. package/apps/web/dist/assets/mk-MK-CpOo5Bd8.js +0 -1
  107. package/apps/web/dist/assets/nl-NL-Mu8G8RON.js +0 -1
  108. package/apps/web/dist/assets/pl-PL-DGuxe2Aq.js +0 -1
  109. package/apps/web/dist/assets/project-lifecycle-Ba7iRF3u.js +0 -1
  110. package/apps/web/dist/assets/project-settings-CtOWgEam.js +0 -1
  111. package/apps/web/dist/assets/pt-BR-DwkMPgq1.js +0 -1
  112. package/apps/web/dist/assets/public-project-CHRjhFIn.js +0 -1
  113. package/apps/web/dist/assets/ru-RU-DrXnqZbV.js +0 -1
  114. package/apps/web/dist/assets/search-D94SZwrC.js +0 -85
  115. package/apps/web/dist/assets/settings-Dd9EVxua.js +0 -1
  116. package/apps/web/dist/assets/ticket-detail-C9egaVSf.js +0 -2
  117. package/apps/web/dist/assets/ticket-editor-UlSZgpWF.js +0 -2
  118. package/apps/web/dist/assets/ticket-list-controls-BidzkMOD.js +0 -1
  119. package/apps/web/dist/assets/ticket-list-vNBO8mkk.js +0 -5
  120. package/apps/web/dist/assets/tr-TR-B92YeFW5.js +0 -1
  121. package/apps/web/dist/assets/uk-UA-DmcDs-MU.js +0 -1
  122. package/apps/web/dist/assets/vi-VN-DM5JYNuP.js +0 -1
  123. package/apps/web/dist/assets/workspace-settings-CSvVqaL6.js +0 -1
  124. package/apps/web/dist/assets/zh-CN-CiUOkQXe.js +0 -1
  125. package/apps/web/dist/assets/zh-TW-Co4UBSfi.js +0 -1
@@ -0,0 +1,884 @@
1
+ import { B as notificationIdsInput, G as okSchema, H as notificationPreferencesSchema, U as notificationReadInput, V as notificationPreferencesInput, W as notificationsSchema, X as parsePublicOutput, Y as parseOutput, _t as snapshotSchema, a as checkpointSchema, q as operations, rt as publicOperations, t as ApiError, w as eventSchema, x as errorSchema, xt as streamErrorSchema } from "./src-tQ82UI8k.mjs";
2
+ import { z } from "zod";
3
+ import { parseArgs } from "node:util";
4
+ import { constants } from "node:fs";
5
+ import { mkdir, open, rename, rm } from "node:fs/promises";
6
+ import { homedir } from "node:os";
7
+ import { dirname, join } from "node:path";
8
+ //#region ../../node_modules/.pnpm/eventsource-parser@4.1.2/node_modules/eventsource-parser/dist/errors.js
9
+ /**
10
+ * Error thrown when encountering an issue during parsing.
11
+ *
12
+ * @public
13
+ */
14
+ var ParseError = class extends Error {
15
+ constructor(message, options) {
16
+ super(message);
17
+ this.name = "ParseError";
18
+ this.type = options.type;
19
+ this.field = options.field;
20
+ this.value = options.value;
21
+ this.line = options.line;
22
+ }
23
+ };
24
+ //#endregion
25
+ //#region ../../node_modules/.pnpm/eventsource-parser@4.1.2/node_modules/eventsource-parser/dist/parse.js
26
+ /**
27
+ * EventSource/Server-Sent Events parser
28
+ * @see https://html.spec.whatwg.org/multipage/server-sent-events.html
29
+ */
30
+ const LF = 10;
31
+ const CR = 13;
32
+ const SPACE = 32;
33
+ const MAX_FIELD_PREFIX_LENGTH = 6;
34
+ /**
35
+ * Creates a new EventSource parser.
36
+ *
37
+ * @param config - Parser configuration. Accepts callbacks (see {@link ParserCallbacks})
38
+ * and options like `maxBufferSize` (see {@link ParserConfig}).
39
+ *
40
+ * @returns A new EventSource parser, with `feed` and `reset` methods.
41
+ * @public
42
+ */
43
+ function createParser(config) {
44
+ if (typeof config === "function") throw new TypeError("`config` must be an object, got a function instead. Did you mean `createParser({onEvent: fn})`?");
45
+ const { maxBufferSize, onComment, onError, onEvent, onId, onRetry } = config;
46
+ const pendingFragments = [];
47
+ let pendingFragmentsLength = 0;
48
+ let bomPrefix = "";
49
+ let id;
50
+ let data = "";
51
+ let dataLines = 0;
52
+ let eventType;
53
+ let terminated = false;
54
+ let skippingLine = false;
55
+ let skipNextLineFeed = false;
56
+ /**
57
+ * Feeds a chunk of the SSE stream to the parser. Any trailing bytes that do
58
+ * not yet form a complete line are held back and prepended to the next chunk,
59
+ * so callers can pass arbitrary slices of the stream without worrying about
60
+ * line boundaries.
61
+ *
62
+ * Per the SSE spec, one leading UTF-8 BOM is stripped before parsing,
63
+ * even when split across chunks. This handles both the raw 3-byte form (0xEF 0xBB
64
+ * 0xBF) and a single decoded U+FEFF, so a leading BOM is ignored regardless of
65
+ * how the caller decoded the bytes.
66
+ *
67
+ * @see https://html.spec.whatwg.org/multipage/server-sent-events.html#parsing-an-event-stream
68
+ */
69
+ function feed(chunk) {
70
+ if (terminated) throw new Error("Cannot feed parser: it was terminated after exceeding the configured max buffer size. Call `reset()` to resume parsing.");
71
+ if (bomPrefix !== void 0) {
72
+ chunk = bomPrefix + chunk;
73
+ if (chunk === "" || chunk === "ï" || chunk === "ï»") {
74
+ bomPrefix = chunk;
75
+ return;
76
+ }
77
+ bomPrefix = void 0;
78
+ chunk = chunk.replace(/^(?:\uFEFF|\xEF\xBB\xBF)/, "");
79
+ }
80
+ if (skippingLine || skipNextLineFeed) {
81
+ chunk = resumeAfterSkip(chunk);
82
+ if (!chunk) return;
83
+ }
84
+ if (!pendingFragments.length) {
85
+ const trailing = processLines(chunk);
86
+ if (trailing !== "") storeTrailing(trailing);
87
+ checkForBufferOverflow();
88
+ return;
89
+ }
90
+ if (chunk.indexOf("\n") === -1 && chunk.indexOf("\r") === -1) {
91
+ if (pendingFragmentsLength < MAX_FIELD_PREFIX_LENGTH) {
92
+ if (!shouldBufferTrailing(pendingFragments.join("") + chunk.slice(0, MAX_FIELD_PREFIX_LENGTH - pendingFragmentsLength))) {
93
+ pendingFragments.length = 0;
94
+ pendingFragmentsLength = 0;
95
+ skippingLine = true;
96
+ return;
97
+ }
98
+ }
99
+ pendingFragments.push(chunk);
100
+ pendingFragmentsLength += chunk.length;
101
+ checkForBufferOverflow();
102
+ return;
103
+ }
104
+ pendingFragments.push(chunk);
105
+ const input = pendingFragments.join("");
106
+ pendingFragments.length = 0;
107
+ pendingFragmentsLength = 0;
108
+ storeTrailing(processLines(input));
109
+ checkForBufferOverflow();
110
+ }
111
+ function resumeAfterSkip(chunk) {
112
+ if (chunk.length === 0) return chunk;
113
+ if (skipNextLineFeed) {
114
+ skipNextLineFeed = false;
115
+ return chunk.charCodeAt(0) === LF ? chunk.slice(1) : chunk;
116
+ }
117
+ const crIndex = chunk.indexOf("\r");
118
+ const lfIndex = chunk.indexOf("\n");
119
+ const lineEnd = crIndex === -1 ? lfIndex : lfIndex === -1 ? crIndex : crIndex < lfIndex ? crIndex : lfIndex;
120
+ if (lineEnd === -1) return "";
121
+ if (lineEnd === chunk.length - 1 && chunk.charCodeAt(lineEnd) === CR) {
122
+ skippingLine = false;
123
+ skipNextLineFeed = true;
124
+ return "";
125
+ }
126
+ skippingLine = false;
127
+ return chunk.slice(lineEnd + (chunk.charCodeAt(lineEnd) === CR && chunk.charCodeAt(lineEnd + 1) === LF ? 2 : 1));
128
+ }
129
+ function storeTrailing(trailing) {
130
+ if (!trailing) return;
131
+ if (trailing.charCodeAt(trailing.length - 1) === CR) {
132
+ parseLine(trailing, 0, trailing.length - 1);
133
+ if (checkForBufferOverflow()) return;
134
+ skipNextLineFeed = true;
135
+ return;
136
+ }
137
+ if (shouldBufferTrailing(trailing)) {
138
+ pendingFragments.push(trailing);
139
+ pendingFragmentsLength = trailing.length;
140
+ return;
141
+ }
142
+ skippingLine = true;
143
+ }
144
+ function shouldBufferTrailing(trailing) {
145
+ const firstCharCode = trailing.charCodeAt(0);
146
+ return firstCharCode === 58 && !!onComment || firstCharCode === 100 && isPotentialField(trailing, "data") || firstCharCode === 101 && isPotentialField(trailing, "event") || firstCharCode === 105 && isPotentialField(trailing, "id") || firstCharCode === 114 && isPotentialField(trailing, "retry");
147
+ }
148
+ function checkForBufferOverflow() {
149
+ if (terminated) return true;
150
+ if (maxBufferSize === void 0) return false;
151
+ if (pendingFragmentsLength + data.length <= maxBufferSize) return false;
152
+ terminated = true;
153
+ pendingFragments.length = 0;
154
+ pendingFragmentsLength = 0;
155
+ id = void 0;
156
+ data = "";
157
+ dataLines = 0;
158
+ eventType = void 0;
159
+ skippingLine = false;
160
+ skipNextLineFeed = false;
161
+ onError === null || onError === void 0 || onError(new ParseError(`Buffered data exceeded max buffer size of ${maxBufferSize} characters`, { type: "max-buffer-size-exceeded" }));
162
+ return true;
163
+ }
164
+ /**
165
+ * Splits `chunk` into SSE lines and dispatches each to the appropriate handler.
166
+ * Returns any trailing bytes that did not terminate with a line break, so the
167
+ * caller can prepend them to the next chunk.
168
+ *
169
+ * The SSE spec permits three line terminators: `\n`, `\r`, and `\r\n`. Real-world
170
+ * streams almost always use plain `\n`, so we take a fast path when no `\r` is
171
+ * present in the chunk. The slow path is spec-correct but does more work per line.
172
+ */
173
+ function processLines(chunk) {
174
+ let searchIndex = 0;
175
+ if (chunk.indexOf("\r") === -1) {
176
+ let lfIndex = chunk.indexOf("\n", searchIndex);
177
+ while (lfIndex !== -1) {
178
+ if (searchIndex === lfIndex) {
179
+ if (id !== void 0) onId === null || onId === void 0 || onId(id);
180
+ if (dataLines > 0) onEvent === null || onEvent === void 0 || onEvent({
181
+ id,
182
+ event: eventType,
183
+ data
184
+ });
185
+ id = void 0;
186
+ data = "";
187
+ dataLines = 0;
188
+ eventType = void 0;
189
+ searchIndex = lfIndex + 1;
190
+ lfIndex = chunk.indexOf("\n", searchIndex);
191
+ continue;
192
+ }
193
+ const firstCharCode = chunk.charCodeAt(searchIndex);
194
+ if (isDataPrefix(chunk, searchIndex, firstCharCode)) {
195
+ const valueStart = chunk.charCodeAt(searchIndex + 5) === SPACE ? searchIndex + 6 : searchIndex + 5;
196
+ const value = chunk.slice(valueStart, lfIndex);
197
+ if (dataLines === 0 && chunk.charCodeAt(lfIndex + 1) === LF) {
198
+ if (id !== void 0) onId === null || onId === void 0 || onId(id);
199
+ onEvent === null || onEvent === void 0 || onEvent({
200
+ id,
201
+ event: eventType,
202
+ data: value
203
+ });
204
+ id = void 0;
205
+ data = "";
206
+ eventType = void 0;
207
+ searchIndex = lfIndex + 2;
208
+ lfIndex = chunk.indexOf("\n", searchIndex);
209
+ continue;
210
+ }
211
+ data = dataLines === 0 ? value : `${data}\n${value}`;
212
+ dataLines++;
213
+ } else if (isEventPrefix(chunk, searchIndex, firstCharCode)) eventType = chunk.slice(chunk.charCodeAt(searchIndex + 6) === SPACE ? searchIndex + 7 : searchIndex + 6, lfIndex) || void 0;
214
+ else parseLine(chunk, searchIndex, lfIndex);
215
+ if (checkForBufferOverflow()) return "";
216
+ searchIndex = lfIndex + 1;
217
+ lfIndex = chunk.indexOf("\n", searchIndex);
218
+ }
219
+ return chunk.slice(searchIndex);
220
+ }
221
+ while (searchIndex < chunk.length) {
222
+ const crIndex = chunk.indexOf("\r", searchIndex);
223
+ const lfIndex = chunk.indexOf("\n", searchIndex);
224
+ let lineEnd = -1;
225
+ if (crIndex !== -1 && lfIndex !== -1) lineEnd = crIndex < lfIndex ? crIndex : lfIndex;
226
+ else if (crIndex !== -1) {
227
+ if (crIndex === chunk.length - 1) lineEnd = -1;
228
+ else lineEnd = crIndex;
229
+ } else if (lfIndex !== -1) lineEnd = lfIndex;
230
+ if (lineEnd === -1) break;
231
+ parseLine(chunk, searchIndex, lineEnd);
232
+ if (checkForBufferOverflow()) return "";
233
+ searchIndex = lineEnd + 1;
234
+ if (chunk.charCodeAt(searchIndex - 1) === CR && chunk.charCodeAt(searchIndex) === LF) searchIndex++;
235
+ }
236
+ return chunk.slice(searchIndex);
237
+ }
238
+ function parseLine(chunk, start, end) {
239
+ if (start === end) {
240
+ dispatchEvent();
241
+ return;
242
+ }
243
+ const firstCharCode = chunk.charCodeAt(start);
244
+ if (isDataPrefix(chunk, start, firstCharCode)) {
245
+ const valueStart = chunk.charCodeAt(start + 5) === SPACE ? start + 6 : start + 5;
246
+ const value = chunk.slice(valueStart, end);
247
+ data = dataLines === 0 ? value : `${data}\n${value}`;
248
+ dataLines++;
249
+ return;
250
+ }
251
+ if (isEventPrefix(chunk, start, firstCharCode)) {
252
+ eventType = chunk.slice(chunk.charCodeAt(start + 6) === SPACE ? start + 7 : start + 6, end) || void 0;
253
+ return;
254
+ }
255
+ if (firstCharCode === 105 && chunk.charCodeAt(start + 1) === 100 && chunk.charCodeAt(start + 2) === 58) {
256
+ const value = chunk.slice(chunk.charCodeAt(start + 3) === SPACE ? start + 4 : start + 3, end);
257
+ if (!value.includes("\0")) id = value;
258
+ return;
259
+ }
260
+ if (firstCharCode === 58) {
261
+ if (onComment) {
262
+ const line = chunk.slice(start, end);
263
+ onComment(line.slice(chunk.charCodeAt(start + 1) === SPACE ? 2 : 1));
264
+ }
265
+ return;
266
+ }
267
+ const line = chunk.slice(start, end);
268
+ const fieldSeparatorIndex = line.indexOf(":");
269
+ if (fieldSeparatorIndex === -1) {
270
+ processField(line, "", line);
271
+ return;
272
+ }
273
+ const field = line.slice(0, fieldSeparatorIndex);
274
+ const offset = line.charCodeAt(fieldSeparatorIndex + 1) === SPACE ? 2 : 1;
275
+ processField(field, line.slice(fieldSeparatorIndex + offset), line);
276
+ }
277
+ function processField(field, value, line) {
278
+ switch (field) {
279
+ case "event":
280
+ eventType = value || void 0;
281
+ break;
282
+ case "data":
283
+ data = dataLines === 0 ? value : `${data}\n${value}`;
284
+ dataLines++;
285
+ break;
286
+ case "id":
287
+ if (!value.includes("\0")) id = value;
288
+ break;
289
+ case "retry":
290
+ if (/^\d+$/.test(value)) onRetry === null || onRetry === void 0 || onRetry(parseInt(value, 10));
291
+ else onError === null || onError === void 0 || onError(new ParseError(`Invalid \`retry\` value: "${value}"`, {
292
+ type: "invalid-retry",
293
+ value,
294
+ line
295
+ }));
296
+ break;
297
+ default: onError === null || onError === void 0 || onError(new ParseError(`Unknown field "${field.length > 20 ? `${field.slice(0, 20)}…` : field}"`, {
298
+ type: "unknown-field",
299
+ field,
300
+ value,
301
+ line
302
+ }));
303
+ }
304
+ }
305
+ function dispatchEvent() {
306
+ if (id !== void 0) onId === null || onId === void 0 || onId(id);
307
+ if (dataLines > 0) onEvent === null || onEvent === void 0 || onEvent({
308
+ id,
309
+ event: eventType,
310
+ data
311
+ });
312
+ id = void 0;
313
+ data = "";
314
+ dataLines = 0;
315
+ eventType = void 0;
316
+ }
317
+ function reset(options = {}) {
318
+ if (options.consume && pendingFragments.length > 0) {
319
+ const incompleteLine = pendingFragments.join("");
320
+ parseLine(incompleteLine, 0, incompleteLine.length);
321
+ }
322
+ bomPrefix = "";
323
+ id = void 0;
324
+ data = "";
325
+ dataLines = 0;
326
+ eventType = void 0;
327
+ pendingFragments.length = 0;
328
+ pendingFragmentsLength = 0;
329
+ terminated = false;
330
+ skippingLine = false;
331
+ skipNextLineFeed = false;
332
+ }
333
+ return {
334
+ feed,
335
+ reset
336
+ };
337
+ }
338
+ /**
339
+ * Checks if `chunk` starts with the literal `data:` at index `i`.
340
+ *
341
+ * Equivalent to `chunk.startsWith('data:', i)`, but benchmarks show this
342
+ * hand-unrolled char-code comparison is ~20% faster on common event types.
343
+ * The caller passes `firstCharCode` (the code at `i`) so it can be reused
344
+ * across prefix checks.
345
+ *
346
+ * ASCII: 'd' = 100, 'a' = 97, 't' = 116, 'a' = 97, ':' = 58
347
+ */
348
+ function isDataPrefix(chunk, i, firstCharCode) {
349
+ return firstCharCode === 100 && chunk.charCodeAt(i + 1) === 97 && chunk.charCodeAt(i + 2) === 116 && chunk.charCodeAt(i + 3) === 97 && chunk.charCodeAt(i + 4) === 58;
350
+ }
351
+ /**
352
+ * Checks if `chunk` starts with the literal `event:` at index `i`.
353
+ *
354
+ * See {@link isDataPrefix} for why this is hand-unrolled rather than using
355
+ * `String.prototype.startsWith`.
356
+ *
357
+ * ASCII: 'e' = 101, 'v' = 118, 'e' = 101, 'n' = 110, 't' = 116, ':' = 58
358
+ */
359
+ function isEventPrefix(chunk, i, firstCharCode) {
360
+ return firstCharCode === 101 && chunk.charCodeAt(i + 1) === 118 && chunk.charCodeAt(i + 2) === 101 && chunk.charCodeAt(i + 3) === 110 && chunk.charCodeAt(i + 4) === 116 && chunk.charCodeAt(i + 5) === 58;
361
+ }
362
+ function isPotentialField(line, field) {
363
+ let i = 1;
364
+ while (i < line.length && i < field.length) {
365
+ if (line.charCodeAt(i) !== field.charCodeAt(i)) return false;
366
+ i++;
367
+ }
368
+ return line.length <= field.length || line.charCodeAt(field.length) === 58;
369
+ }
370
+ //#endregion
371
+ //#region ../../packages/client/src/index.ts
372
+ function randomRequestId() {
373
+ if (typeof crypto.randomUUID === "function") return crypto.randomUUID();
374
+ const bytes = crypto.getRandomValues(/* @__PURE__ */ new Uint8Array(16));
375
+ bytes[6] = (bytes[6] ?? 0) & 15 | 64;
376
+ bytes[8] = (bytes[8] ?? 0) & 63 | 128;
377
+ const hex = Array.from(bytes, (value) => value.toString(16).padStart(2, "0")).join("");
378
+ return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
379
+ }
380
+ async function decode(response) {
381
+ const data = await response.json().catch(() => {
382
+ throw new ApiError(response.status, "invalid_response", "Kanvil returned an invalid response");
383
+ });
384
+ if (!response.ok) {
385
+ const error = errorSchema.safeParse(data);
386
+ throw new ApiError(response.status, error.success ? error.data.error.code : "request_failed", error.success ? error.data.error.message : `Request failed (${response.status})`, error.success ? error.data.error.details : void 0);
387
+ }
388
+ return data;
389
+ }
390
+ function createClient(options) {
391
+ const request = options.fetch ?? fetch;
392
+ const endpoint = (path) => {
393
+ if (!path.startsWith("/") || path.startsWith("//")) throw new ApiError(400, "invalid_path", "Use a relative Kanvil endpoint");
394
+ const url = new URL(`${options.baseUrl.replace(/\/$/, "")}${path}`);
395
+ if (url.origin !== new URL(options.baseUrl).origin) throw new ApiError(400, "invalid_path", "Credentials cannot be sent to another origin");
396
+ return url;
397
+ };
398
+ const retry = async (url, init) => {
399
+ try {
400
+ return await request(url, init);
401
+ } catch (error) {
402
+ if (init.signal?.aborted) throw error;
403
+ return request(url, init);
404
+ }
405
+ };
406
+ const send = async (spec, input, base) => {
407
+ const values = { ...spec.input.parse(input) };
408
+ const path = spec.path.replace(/\{(\w+)\}/g, (_, key) => {
409
+ const value = values[key];
410
+ delete values[key];
411
+ if (typeof value !== "string") throw new ApiError(400, "invalid_path", `Missing path parameter ${key}`);
412
+ return encodeURIComponent(value);
413
+ });
414
+ const url = new URL(`${options.baseUrl.replace(/\/$/, "")}${base}${path}`);
415
+ const headers = new Headers(await options.headers?.());
416
+ const init = {
417
+ method: spec.method,
418
+ credentials: options.credentials ?? "include",
419
+ headers
420
+ };
421
+ if (spec.method === "GET") {
422
+ for (const [key, value] of Object.entries(values)) for (const item of Array.isArray(value) ? value : [value]) if (typeof item === "string" || typeof item === "number" || typeof item === "boolean") url.searchParams.append(key, String(item));
423
+ } else {
424
+ headers.set("Content-Type", "application/json");
425
+ if ("requestId" in spec.input.shape) values.requestId ??= (options.requestId ?? randomRequestId)();
426
+ init.body = JSON.stringify(values);
427
+ }
428
+ return decode(await (spec.method === "GET" || "requestId" in values ? retry(url, init) : request(url, init)));
429
+ };
430
+ const api = {
431
+ async request(path, schema, init = {}) {
432
+ const headers = new Headers(await options.headers?.());
433
+ new Headers(init.headers).forEach((value, key) => headers.set(key, value));
434
+ return schema.parse(await decode(await request(endpoint(path), {
435
+ ...init,
436
+ headers,
437
+ credentials: options.credentials ?? "include"
438
+ })));
439
+ },
440
+ async call(name, input) {
441
+ return parseOutput(name, await send(operations[name], input, "/api/v1"));
442
+ },
443
+ async callPublic(name, input) {
444
+ return parsePublicOutput(name, await send(publicOperations[name], input, "/api/public"));
445
+ },
446
+ async subscribe(subscription) {
447
+ let cursor = subscription.cursor, backoff = 1e3;
448
+ try {
449
+ while (!subscription.signal.aborted) {
450
+ subscription.onState?.("connecting");
451
+ const url = endpoint("/api/v1/events");
452
+ if (cursor) url.searchParams.set("cursor", cursor);
453
+ if (subscription.projectId) url.searchParams.set("projectId", subscription.projectId);
454
+ let reader;
455
+ const cancel = () => {
456
+ reader?.cancel().catch(() => {});
457
+ };
458
+ subscription.signal.addEventListener("abort", cancel, { once: true });
459
+ try {
460
+ const response = await request(url, {
461
+ headers: new Headers(await options.headers?.()),
462
+ credentials: options.credentials ?? "include",
463
+ signal: subscription.signal
464
+ });
465
+ if (response.status === 410 && subscription.onReset) {
466
+ cursor = await subscription.onReset();
467
+ continue;
468
+ }
469
+ if (!response.ok) await decode(response);
470
+ if (!response.body) throw new ApiError(502, "invalid_stream", "The event stream has no body");
471
+ reader = response.body.getReader();
472
+ const messages = [];
473
+ const parser = createParser({
474
+ maxBufferSize: 1e6,
475
+ onEvent: (event) => messages.push(event),
476
+ onError: (error) => {
477
+ throw new ApiError(502, "invalid_stream", error.message);
478
+ }
479
+ });
480
+ const decoder = new TextDecoder();
481
+ while (!subscription.signal.aborted) {
482
+ const chunk = await reader.read();
483
+ if (chunk.done) break;
484
+ parser.feed(decoder.decode(chunk.value, { stream: true }));
485
+ for (const message of messages.splice(0)) {
486
+ if (message.event === "error") {
487
+ const error = streamErrorSchema.parse(JSON.parse(message.data));
488
+ throw new ApiError(error.status, error.code, error.message);
489
+ }
490
+ if (message.event === "change") await subscription.onEvent(eventSchema.parse(JSON.parse(message.data)));
491
+ if (message.event === "checkpoint" || message.event === "change") {
492
+ subscription.onState?.("connected");
493
+ backoff = 1e3;
494
+ if (message.id) {
495
+ await subscription.onCursor?.(message.id);
496
+ cursor = message.id;
497
+ }
498
+ }
499
+ }
500
+ }
501
+ } catch (error) {
502
+ if (subscription.signal.aborted) return;
503
+ if (error instanceof ApiError && error.status === 410 && subscription.onReset) {
504
+ cursor = await subscription.onReset();
505
+ continue;
506
+ }
507
+ if (error instanceof ApiError && error.status < 500) throw error;
508
+ } finally {
509
+ subscription.signal.removeEventListener("abort", cancel);
510
+ await reader?.cancel().catch(() => {});
511
+ }
512
+ if (subscription.signal.aborted) return;
513
+ subscription.onState?.("offline");
514
+ await new Promise((resolve) => {
515
+ const finish = () => {
516
+ clearTimeout(timer);
517
+ subscription.signal.removeEventListener("abort", finish);
518
+ resolve();
519
+ };
520
+ const timer = setTimeout(finish, backoff);
521
+ subscription.signal.addEventListener("abort", finish, { once: true });
522
+ if (subscription.signal.aborted) finish();
523
+ });
524
+ backoff = Math.min(backoff * 2, 3e4);
525
+ }
526
+ } finally {
527
+ subscription.onState?.("closed");
528
+ }
529
+ }
530
+ };
531
+ return {
532
+ ...api,
533
+ notifications() {
534
+ return {
535
+ queryKey: [
536
+ "kanvil",
537
+ options.baseUrl,
538
+ "notifications"
539
+ ],
540
+ queryFn: () => api.request("/api/v1/notifications", notificationsSchema)
541
+ };
542
+ },
543
+ markNotifications(input) {
544
+ return api.request("/api/v1/notifications/read", okSchema, {
545
+ method: "POST",
546
+ headers: { "Content-Type": "application/json" },
547
+ body: JSON.stringify(notificationReadInput.parse(input))
548
+ });
549
+ },
550
+ dismissNotifications(input) {
551
+ return api.request("/api/v1/notifications/dismiss", okSchema, {
552
+ method: "POST",
553
+ headers: { "Content-Type": "application/json" },
554
+ body: JSON.stringify(notificationIdsInput.parse(input))
555
+ });
556
+ },
557
+ notificationPreferences() {
558
+ return {
559
+ queryKey: [
560
+ "kanvil",
561
+ options.baseUrl,
562
+ "notification-preferences"
563
+ ],
564
+ queryFn: () => api.request("/api/v1/notifications/preferences", notificationPreferencesSchema)
565
+ };
566
+ },
567
+ setNotificationPreferences(input) {
568
+ return api.request("/api/v1/notifications/preferences", notificationPreferencesSchema, {
569
+ method: "PUT",
570
+ headers: { "Content-Type": "application/json" },
571
+ body: JSON.stringify(notificationPreferencesInput.parse(input))
572
+ });
573
+ },
574
+ watch(observer) {
575
+ let initial = true;
576
+ return api.subscribe({
577
+ ...observer.projectId ? { projectId: observer.projectId } : {},
578
+ signal: observer.signal,
579
+ ...observer.onState ? { onState: observer.onState } : {},
580
+ onEvent: (event) => observer.invalidate(event),
581
+ onCursor: async () => {
582
+ if (initial) {
583
+ initial = false;
584
+ await observer.invalidate();
585
+ }
586
+ },
587
+ onReset: async () => {
588
+ const snapshot = observer.projectId ? await api.request(`/api/v1/snapshot?projectId=${encodeURIComponent(observer.projectId)}`, snapshotSchema) : await api.request("/api/v1/checkpoint", checkpointSchema);
589
+ await observer.invalidate();
590
+ return snapshot.cursor;
591
+ }
592
+ });
593
+ },
594
+ query(name, input) {
595
+ return {
596
+ queryKey: [
597
+ "kanvil",
598
+ options.baseUrl,
599
+ name,
600
+ input
601
+ ],
602
+ queryFn: () => api.call(name, input)
603
+ };
604
+ },
605
+ publicQuery(name, input) {
606
+ return {
607
+ queryKey: [
608
+ "kanvil-public",
609
+ options.baseUrl,
610
+ name,
611
+ input
612
+ ],
613
+ queryFn: () => api.callPublic(name, input)
614
+ };
615
+ },
616
+ action(name) {
617
+ return {
618
+ mutationFn: (input) => api.call(name, input),
619
+ networkMode: "always",
620
+ retry: false
621
+ };
622
+ }
623
+ };
624
+ }
625
+ //#endregion
626
+ //#region src/cli/client.ts
627
+ const commands = {
628
+ "workspace list": "list_workspaces",
629
+ "project list": "list_projects",
630
+ "project get": "get_project",
631
+ "project create": "create_project",
632
+ "task list": "list_tickets",
633
+ "task get": "get_ticket",
634
+ "task create": "create_ticket",
635
+ "task update": "update_ticket",
636
+ "task delete": "delete_ticket",
637
+ "task ready": "list_eligible_tickets",
638
+ "comment list": "list_comments",
639
+ "comment add": "add_comment",
640
+ "claim acquire": "claim_ticket",
641
+ "claim renew": "renew_claim",
642
+ "claim release": "release_claim"
643
+ };
644
+ const clientHelp = `Usage: kanvil <namespace> <action> [ticket-key] [options]
645
+ ${Object.keys(commands).join("\n")}
646
+ profile set <name> --server <url> [--project <id>] --token-stdin
647
+ profile list | profile remove <name> --yes
648
+
649
+ --profile <name> Named server/project credential (default: default)
650
+ --config <path> Private configuration (default: ~/.config/kanvil/client.json)
651
+ --input <json|-> Operation input as a JSON object; - reads stdin
652
+ --title <text> Ticket title
653
+ --body <markdown> Comment body
654
+ --expected-version <n> Required version for update, delete and acquire
655
+ --changes <json> Ticket update changes as a JSON object
656
+ --request-id <uuid> Reuse for a deliberate retry across invocations
657
+ --json Compact JSON output (default: indented JSON)
658
+ --yes Confirm task deletion or profile removal
659
+ --help Show commands and input conventions
660
+
661
+ All operation fields also accept --input. A profile's project cannot be overridden.
662
+ Writes never refresh versions or retry conflicts. Credentials are never command arguments.
663
+ `;
664
+ const profileSchema = z.object({
665
+ server: z.string().transform((value, context) => {
666
+ try {
667
+ const url = new URL(value);
668
+ if (url.username || url.password || url.search || url.hash || url.pathname !== "/" || url.protocol !== "https:" && !(url.protocol === "http:" && [
669
+ "localhost",
670
+ "127.0.0.1",
671
+ "[::1]"
672
+ ].includes(url.hostname))) throw new Error();
673
+ return url.origin;
674
+ } catch {
675
+ context.addIssue({
676
+ code: "custom",
677
+ message: "Use an HTTPS server origin (HTTP only on loopback)."
678
+ });
679
+ return z.NEVER;
680
+ }
681
+ }),
682
+ projectId: z.string().min(1).optional(),
683
+ token: z.string().trim().min(1).max(8192).regex(/^[^\s]+$/)
684
+ });
685
+ const configSchema = z.object({
686
+ version: z.literal(1),
687
+ profiles: z.record(z.string(), profileSchema)
688
+ }).strict();
689
+ const objectSchema = z.record(z.string(), z.unknown());
690
+ var UsageError = class extends ApiError {
691
+ constructor(message) {
692
+ super(400, "invalid_arguments", message);
693
+ }
694
+ };
695
+ function usage(message) {
696
+ throw new UsageError(message);
697
+ }
698
+ function jsonObject(value) {
699
+ try {
700
+ return objectSchema.parse(JSON.parse(value));
701
+ } catch {
702
+ return usage("Input must be a JSON object.");
703
+ }
704
+ }
705
+ async function readConfig(path) {
706
+ let file;
707
+ try {
708
+ file = await open(path, constants.O_RDONLY | constants.O_NOFOLLOW);
709
+ } catch (error) {
710
+ if (error instanceof Error && "code" in error && error.code === "ENOENT") return {
711
+ version: 1,
712
+ profiles: {}
713
+ };
714
+ throw new ApiError(400, "invalid_config", "Cannot open private CLI configuration.");
715
+ }
716
+ try {
717
+ const info = await file.stat();
718
+ if (!info.isFile() || (info.mode & 63) !== 0) usage("CLI configuration must be a private file (chmod 600).");
719
+ return configSchema.parse(JSON.parse(await file.readFile("utf8")));
720
+ } catch {
721
+ throw new ApiError(400, "invalid_config", "Invalid CLI configuration; require a private file (chmod 600).");
722
+ } finally {
723
+ await file.close();
724
+ }
725
+ }
726
+ async function saveConfig(path, config) {
727
+ await mkdir(dirname(path), {
728
+ recursive: true,
729
+ mode: 448
730
+ });
731
+ const temporary = `${path}.${crypto.randomUUID()}.tmp`;
732
+ try {
733
+ const file = await open(temporary, "wx", 384);
734
+ try {
735
+ await file.writeFile(JSON.stringify(config) + "\n");
736
+ } finally {
737
+ await file.close();
738
+ }
739
+ await rename(temporary, path);
740
+ } finally {
741
+ await rm(temporary, { force: true });
742
+ }
743
+ }
744
+ async function runClient(args, io) {
745
+ let secret = "";
746
+ let compact = args.includes("--json");
747
+ const serialize = (value, pretty = false) => JSON.stringify(value, (_key, item) => typeof item === "string" && secret ? item.replaceAll(secret, "[redacted]") : item, pretty ? 2 : void 0);
748
+ const output = (value) => io.stdout(serialize(value, !compact) + "\n");
749
+ try {
750
+ const { values, positionals } = parseArgs({
751
+ args,
752
+ allowPositionals: true,
753
+ options: {
754
+ help: { type: "boolean" },
755
+ json: { type: "boolean" },
756
+ yes: { type: "boolean" },
757
+ profile: {
758
+ type: "string",
759
+ default: "default"
760
+ },
761
+ config: { type: "string" },
762
+ input: { type: "string" },
763
+ server: { type: "string" },
764
+ project: { type: "string" },
765
+ "token-stdin": { type: "boolean" },
766
+ title: { type: "string" },
767
+ body: { type: "string" },
768
+ "expected-version": { type: "string" },
769
+ changes: { type: "string" },
770
+ "request-id": { type: "string" }
771
+ }
772
+ });
773
+ compact = values.json ?? false;
774
+ if (values.help) {
775
+ io.stdout(clientHelp);
776
+ return 0;
777
+ }
778
+ const [namespace, action, identifier, ...extra] = positionals;
779
+ if (extra.length) usage("Too many command arguments.");
780
+ const path = values.config ?? io.configPath ?? join(homedir(), ".config", "kanvil", "client.json");
781
+ const config = await readConfig(path);
782
+ if (namespace === "profile") {
783
+ if (action === "list" && !identifier) output(Object.entries(config.profiles).map(([name, { server, projectId }]) => ({
784
+ name,
785
+ server,
786
+ projectId
787
+ })));
788
+ else if (action === "set" && identifier) {
789
+ if (!/^[a-zA-Z0-9][a-zA-Z0-9_-]{0,79}$/.test(identifier)) usage("Use a profile name containing letters, digits, hyphens or underscores.");
790
+ if (!values["token-stdin"] || values.input) usage("Pass the credential privately with --token-stdin; do not use --input.");
791
+ secret = (await io.stdin()).trim();
792
+ const profile = profileSchema.parse({
793
+ server: values.server,
794
+ projectId: values.project,
795
+ token: secret
796
+ });
797
+ if (Object.hasOwn(config.profiles, identifier) && !values.yes) usage("Replacing a profile requires --yes.");
798
+ Object.defineProperty(config.profiles, identifier, {
799
+ value: profile,
800
+ enumerable: true,
801
+ configurable: true,
802
+ writable: true
803
+ });
804
+ await saveConfig(path, config);
805
+ output({
806
+ name: identifier,
807
+ server: profile.server,
808
+ projectId: profile.projectId
809
+ });
810
+ } else if (action === "remove" && identifier) {
811
+ if (!values.yes) usage("Removing a profile requires --yes.");
812
+ if (!Object.hasOwn(config.profiles, identifier)) usage("Unknown profile.");
813
+ delete config.profiles[identifier];
814
+ await saveConfig(path, config);
815
+ output({ ok: true });
816
+ } else usage("Unknown profile command. Use --help.");
817
+ return 0;
818
+ }
819
+ if (values.server || values.project || values["token-stdin"]) usage("Server, project and token options belong to profile set.");
820
+ const command = Object.entries(commands).find(([name]) => name === `${namespace} ${action}`)?.[1];
821
+ if (!command) usage("Unknown client command. Use --help.");
822
+ const profile = Object.hasOwn(config.profiles, values.profile) ? config.profiles[values.profile] : void 0;
823
+ if (!profile) usage("Unknown profile. Use profile set first.");
824
+ secret = profile.token;
825
+ const input = values.input ? jsonObject(values.input === "-" ? await io.stdin() : values.input) : {};
826
+ if (profile.projectId) {
827
+ if (input.projectId !== void 0 && input.projectId !== profile.projectId) usage("Input project differs from the selected profile.");
828
+ if ("projectId" in operations[command].input.shape) input.projectId = profile.projectId;
829
+ }
830
+ if (identifier) {
831
+ if (!("ticketId" in operations[command].input.shape)) usage("This command takes no ticket argument.");
832
+ if (input.ticketId !== void 0 && input.ticketId !== identifier) usage("Conflicting ticket identifiers.");
833
+ input.ticketId = identifier;
834
+ }
835
+ for (const key of ["title", "body"]) if (values[key] !== void 0) input[key] = values[key];
836
+ if (values["expected-version"] !== void 0) input.expectedVersion = Number(values["expected-version"]);
837
+ if (values["request-id"] !== void 0) input.requestId = values["request-id"];
838
+ if (values.changes !== void 0) input.changes = jsonObject(values.changes);
839
+ if (command === "delete_ticket" && !values.yes) usage("Deleting a task requires --yes and --expected-version.");
840
+ const spec = operations[command];
841
+ if (Object.keys(input).some((key) => !Object.hasOwn(spec.input.shape, key))) usage("Unknown operation input field. See the API operation schema.");
842
+ const parsed = spec.input.parse(input);
843
+ output(await createClient({
844
+ baseUrl: profile.server,
845
+ headers: () => ({ Authorization: `Bearer ${profile.token}` }),
846
+ credentials: "omit",
847
+ fetch: (url, init) => (io.fetch ?? fetch)(url, {
848
+ ...init,
849
+ redirect: "error",
850
+ signal: AbortSignal.timeout(3e4)
851
+ })
852
+ }).call(command, parsed).catch((error) => {
853
+ if (error instanceof z.ZodError) throw new ApiError(502, "invalid_response", "Invalid server response.");
854
+ throw error;
855
+ }));
856
+ return 0;
857
+ } catch (error) {
858
+ const status = error instanceof ApiError ? error.status : 0;
859
+ const code = error instanceof ApiError ? error.code : error instanceof z.ZodError ? "invalid_arguments" : "client_error";
860
+ const message = error instanceof UsageError ? error.message : error instanceof z.ZodError ? "Invalid input. Check the operation schema and required fields." : "Command failed. Check the error code, profile, permissions and server connection.";
861
+ io.stderr(serialize({ error: {
862
+ code,
863
+ message
864
+ } }) + "\n");
865
+ return status === 401 || status === 403 ? 3 : status === 404 ? 4 : status === 409 ? 5 : status === 400 || error instanceof z.ZodError || error instanceof SyntaxError || error instanceof TypeError && "code" in error ? 2 : error instanceof TypeError || error instanceof Error && error.name === "TimeoutError" ? 6 : 1;
866
+ }
867
+ }
868
+ //#endregion
869
+ //#region src/cli/client-main.ts
870
+ process.exitCode = await runClient(process.argv.slice(2), {
871
+ stdin: async () => {
872
+ process.stdin.setEncoding("utf8");
873
+ let text = "";
874
+ for await (const chunk of process.stdin) {
875
+ text += String(chunk);
876
+ if (Buffer.byteLength(text) > 1e6) throw new Error("Input exceeds the CLI limit.");
877
+ }
878
+ return text;
879
+ },
880
+ stdout: (text) => process.stdout.write(text),
881
+ stderr: (text) => process.stderr.write(text)
882
+ });
883
+ //#endregion
884
+ export {};