@bendyline/docblocks 2.6.1 → 2.7.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 (62) hide show
  1. package/THIRD_PARTY_NOTICES.txt +33 -33
  2. package/dist/capabilities-CdQAc745.d.ts +1233 -0
  3. package/dist/catalog-BQK05tne.d.ts +122 -0
  4. package/dist/chunk-245W57QP.js +31 -0
  5. package/dist/{chunk-2WDJ27EH.js → chunk-46AGYHDY.js} +8 -0
  6. package/dist/{chunk-4437YWLE.js → chunk-6UPO2GE6.js} +4 -2
  7. package/dist/{chunk-UMWCTEXW.js → chunk-7SN7YQL4.js} +211 -40
  8. package/dist/{chunk-OQCPBOQA.js → chunk-DAPFSEKY.js} +35 -0
  9. package/dist/{chunk-M62ZGJ5I.js → chunk-HABG2JM3.js} +0 -17
  10. package/dist/{chunk-YM7O3PWO.js → chunk-HKOOHM67.js} +20 -12
  11. package/dist/chunk-IDYE73TU.js +77 -0
  12. package/dist/{chunk-KLQKU74Q.js → chunk-IGB2VSRE.js} +124 -330
  13. package/dist/{chunk-BVY7GGNV.js → chunk-L6PRMR7T.js} +137 -95
  14. package/dist/chunk-LPIJ6HKL.js +19 -0
  15. package/dist/{chunk-SJBB5OD7.js → chunk-QS5WTLUZ.js} +10 -8
  16. package/dist/chunk-R2JX5N3F.js +382 -0
  17. package/dist/{chunk-ZO7G53QP.js → chunk-UDEWLHQI.js} +4 -2
  18. package/dist/chunk-UK7R3RC7.js +514 -0
  19. package/dist/chunk-XTNWCNSK.js +464 -0
  20. package/dist/chunk-YHSFRPBS.js +42 -0
  21. package/dist/chunk-YNUQG4GF.js +1173 -0
  22. package/dist/document/index.d.ts +31 -1
  23. package/dist/document/index.js +7 -6
  24. package/dist/filesystem/electron.d.ts +8 -34
  25. package/dist/filesystem/electron.js +7 -4
  26. package/dist/filesystem/host.d.ts +28 -0
  27. package/dist/filesystem/host.js +103 -0
  28. package/dist/filesystem/index.d.ts +52 -6
  29. package/dist/filesystem/index.js +36 -15
  30. package/dist/filesystem/indexeddb.d.ts +8 -1
  31. package/dist/filesystem/indexeddb.js +7 -6
  32. package/dist/filesystem/memory.d.ts +2 -1
  33. package/dist/filesystem/memory.js +3 -2
  34. package/dist/filesystem/native.d.ts +2 -1
  35. package/dist/filesystem/native.js +3 -2
  36. package/dist/filesystem-v2-C8AdSXUN.d.ts +74 -0
  37. package/dist/host/index.d.ts +127 -5
  38. package/dist/host/index.js +100 -4
  39. package/dist/host/mobile.d.ts +389 -0
  40. package/dist/host/mobile.js +315 -0
  41. package/dist/host-provider-v2-CyLTRKJF.d.ts +51 -0
  42. package/dist/index.d.ts +8 -5
  43. package/dist/index.js +153 -34
  44. package/dist/mcp/index.d.ts +2 -2
  45. package/dist/mcp/zod.d.ts +23 -1
  46. package/dist/mcp/zod.js +1 -0
  47. package/dist/settings-HrrCikVX.d.ts +170 -0
  48. package/dist/types-BvDnr3YU.d.ts +88 -0
  49. package/dist/{types-Oy9U5FST.d.ts → types-d0yvHUJz.d.ts} +6 -0
  50. package/dist/{types-Bb3yccTH.d.ts → v2-BVnZZyd4.d.ts} +1 -86
  51. package/dist/vscode/index.d.ts +43 -1
  52. package/dist/vscode/index.js +67 -1
  53. package/dist/workspace/index.d.ts +10 -6
  54. package/dist/workspace/index.js +4 -2
  55. package/dist/workspace-index/index.d.ts +240 -0
  56. package/dist/workspace-index/index.js +1287 -0
  57. package/dist/workspace-settings/index.d.ts +301 -0
  58. package/dist/workspace-settings/index.js +820 -0
  59. package/package.json +22 -2
  60. package/dist/chunk-6XHOOBYF.js +0 -36
  61. package/dist/chunk-QI6YKTQV.js +0 -110
  62. package/dist/types-DBYraXxE.d.ts +0 -557
@@ -0,0 +1,1173 @@
1
+ import {
2
+ HOST_WIRE_LIMITS,
3
+ isBoundedString
4
+ } from "./chunk-46AGYHDY.js";
5
+
6
+ // src/host/capabilities.ts
7
+ var HOST_SURFACE_KINDS = Object.freeze([
8
+ "electron",
9
+ "capacitor"
10
+ ]);
11
+ var HOST_PLATFORMS = Object.freeze([
12
+ "darwin",
13
+ "win32",
14
+ "linux",
15
+ "ios",
16
+ "android"
17
+ ]);
18
+ var NO_CAPABILITIES = Object.freeze({
19
+ nativeWorkspaces: false,
20
+ workspaceAuthority: false,
21
+ workspaceFolderPicker: false,
22
+ defaultWorkspace: false,
23
+ filesystemV2: false,
24
+ revealInFileManager: false,
25
+ openWorkspaceFolder: false,
26
+ externalNavigation: false,
27
+ clipboard: false,
28
+ exportDestinations: false,
29
+ exportRememberedTargets: false,
30
+ externalResources: false,
31
+ openRequests: false,
32
+ menuCommands: false,
33
+ pinnedDocumentMirror: false,
34
+ guardedClose: false,
35
+ git: false,
36
+ updater: false,
37
+ systemFfmpeg: false,
38
+ aiAssist: false,
39
+ aiModelManagement: false,
40
+ aiKnowledgeManagement: false,
41
+ aiWorkspaceIndex: false,
42
+ aiSearch: false,
43
+ aiImages: false,
44
+ aiTranscription: false,
45
+ aiSpeechSynthesis: false,
46
+ speechInput: false,
47
+ speechOutput: false,
48
+ speechModelManagement: false,
49
+ // A browser with no host keeps its documents in the origin.
50
+ browserOriginStorage: true,
51
+ ownsWindowChrome: false
52
+ });
53
+ var NO_HOST_CAPABILITIES = NO_CAPABILITIES;
54
+ function isRecord(value) {
55
+ return typeof value === "object" && value !== null && !Array.isArray(value);
56
+ }
57
+ function hasMethod(container, name) {
58
+ return isRecord(container) && typeof container[name] === "function";
59
+ }
60
+ function hasObject(container, name) {
61
+ return isRecord(container) && isRecord(container[name]);
62
+ }
63
+ function parseHostEnvironment(value) {
64
+ if (!isRecord(value)) return null;
65
+ const allowed = /* @__PURE__ */ new Set(["surface", "surfaceLabel", "platform", "appVersion", "isDev"]);
66
+ for (const key of Object.keys(value)) {
67
+ if (!allowed.has(key)) return null;
68
+ }
69
+ const { surface, surfaceLabel, platform, appVersion, isDev } = value;
70
+ if (typeof surface !== "string" || !HOST_SURFACE_KINDS.includes(surface)) {
71
+ return null;
72
+ }
73
+ if (typeof platform !== "string" || !HOST_PLATFORMS.includes(platform)) {
74
+ return null;
75
+ }
76
+ if (!isBoundedString(surfaceLabel, HOST_WIRE_LIMITS.labelCharacters)) return null;
77
+ if (!isBoundedString(appVersion, HOST_WIRE_LIMITS.labelCharacters)) return null;
78
+ if (typeof isDev !== "boolean") return null;
79
+ return Object.freeze({
80
+ surface,
81
+ surfaceLabel,
82
+ platform,
83
+ appVersion,
84
+ isDev
85
+ });
86
+ }
87
+ function deriveHostCapabilities(host) {
88
+ if (!isRecord(host)) return NO_CAPABILITIES;
89
+ const environment = parseHostEnvironment(host.env);
90
+ if (!environment) return NO_CAPABILITIES;
91
+ const workspaces = host.workspaces;
92
+ const shell = host.shell;
93
+ const exports = host.exports;
94
+ return Object.freeze({
95
+ nativeWorkspaces: hasMethod(workspaces, "register"),
96
+ workspaceAuthority: hasMethod(workspaces, "list"),
97
+ workspaceFolderPicker: hasMethod(workspaces, "pickFolder"),
98
+ defaultWorkspace: hasMethod(workspaces, "getDefault"),
99
+ filesystemV2: hasObject(host, "fsV2"),
100
+ revealInFileManager: hasMethod(shell, "revealInFolder"),
101
+ openWorkspaceFolder: hasMethod(shell, "openWorkspaceFolder"),
102
+ externalNavigation: hasMethod(shell, "openExternal"),
103
+ clipboard: hasMethod(host.clipboard, "writeText"),
104
+ exportDestinations: hasMethod(exports, "save"),
105
+ exportRememberedTargets: hasMethod(exports, "resolveTarget") && hasMethod(exports, "pickTarget"),
106
+ externalResources: hasMethod(host.external, "readText"),
107
+ openRequests: hasMethod(host, "onOpenRequest"),
108
+ menuCommands: hasMethod(host, "onMenuCommand"),
109
+ pinnedDocumentMirror: hasMethod(host.menu, "setPinnedDocuments"),
110
+ guardedClose: hasMethod(host.lifecycle, "onPrepareClose"),
111
+ git: hasMethod(host.git, "status"),
112
+ updater: hasMethod(host.updater, "checkForUpdates"),
113
+ systemFfmpeg: hasMethod(host.ffmpeg, "available"),
114
+ // All three members are required: the UI needs provider presence to decide
115
+ // whether connection controls are relevant, and a stream without status
116
+ // leaves it unable to say why nothing is happening.
117
+ aiAssist: hasMethod(host.ai, "providerInstalled") && hasMethod(host.ai, "chat") && hasMethod(host.ai, "onStatus"),
118
+ aiModelManagement: hasMethod(host.ai, "availableModels") && hasMethod(host.ai, "installModel"),
119
+ aiKnowledgeManagement: isRecord(host.ai) && hasMethod(host.ai.knowledge, "state") && hasMethod(host.ai.knowledge, "update"),
120
+ aiWorkspaceIndex: hasMethod(host.ai, "ensureWorkspace"),
121
+ aiSearch: hasMethod(host.ai, "search"),
122
+ aiImages: hasMethod(host.ai, "generateImage"),
123
+ aiTranscription: hasMethod(host.ai, "transcribe"),
124
+ aiSpeechSynthesis: hasMethod(host.ai, "synthesize"),
125
+ speechInput: hasMethod(host.speech, "transcribe"),
126
+ speechOutput: hasMethod(host.speech, "synthesize"),
127
+ speechModelManagement: hasMethod(host.speech, "catalog") && hasMethod(host.speech, "installModel"),
128
+ // A host that owns workspace roots keeps documents outside the web origin.
129
+ browserOriginStorage: !hasMethod(workspaces, "register"),
130
+ ownsWindowChrome: environment.surface === "electron"
131
+ });
132
+ }
133
+
134
+ // src/host/ai-wire-policy.ts
135
+ var AI_WIRE_LIMITS = Object.freeze({
136
+ messageEntries: 64,
137
+ /** Sum of every message's content in one request. */
138
+ promptCharacters: 256 * 1024,
139
+ deltaCharacters: 16 * 1024,
140
+ /** Generated documents have the same transport capacity as other documents. */
141
+ completionCharacters: HOST_WIRE_LIMITS.documentCharacters,
142
+ maxTokensCeiling: 32768,
143
+ temperatureCeiling: 2,
144
+ verificationCodeCharacters: 16,
145
+ progressPhaseCharacters: 64,
146
+ modelEntries: 200,
147
+ contextWindowCeiling: 8e6,
148
+ downloadBytesCeiling: Number.MAX_SAFE_INTEGER
149
+ });
150
+ var CHAT_ROLES = /* @__PURE__ */ new Set(["system", "user", "assistant"]);
151
+ var CHAT_PURPOSES = /* @__PURE__ */ new Set(["write", "review", "illustrate", "chat"]);
152
+ var REVIEW_MODES = /* @__PURE__ */ new Set(["off", "explicit", "implicit"]);
153
+ var FINISH_REASONS = /* @__PURE__ */ new Set(["stop", "length", "cancelled"]);
154
+ var UNAVAILABLE_REASONS = /* @__PURE__ */ new Set([
155
+ "opt-out",
156
+ "platform-unsupported",
157
+ "not-installed",
158
+ "not-running",
159
+ "disconnected"
160
+ ]);
161
+ var CONNECTION_STEPS = /* @__PURE__ */ new Set([
162
+ "detecting",
163
+ "awaiting-approval",
164
+ "preparing-model",
165
+ "preparing-workspace"
166
+ ]);
167
+ var PROVIDER_MODES = /* @__PURE__ */ new Set(["installed", "hosted", "remote"]);
168
+ var ERROR_CODES = /* @__PURE__ */ new Set([
169
+ "provider-unavailable",
170
+ "approval-denied",
171
+ "approval-timeout",
172
+ "approval-expired",
173
+ "approval-required",
174
+ "inference-disabled",
175
+ "already-connected",
176
+ "model-unavailable",
177
+ "model-download-failed",
178
+ "runtime-missing",
179
+ "workspace-not-registered",
180
+ "unsupported",
181
+ "budget-exceeded",
182
+ "rate-limited",
183
+ "timeout",
184
+ "cancelled",
185
+ "unknown"
186
+ ]);
187
+ var MODEL_DOWNLOAD_STATES = /* @__PURE__ */ new Set(["download-required", "downloading"]);
188
+ function isRecord2(value) {
189
+ return typeof value === "object" && value !== null && !Array.isArray(value);
190
+ }
191
+ function hasExactKeys(value, keys) {
192
+ const actual = Object.keys(value);
193
+ return actual.length === keys.length && keys.every((key) => Object.prototype.hasOwnProperty.call(value, key));
194
+ }
195
+ function hasKeysWithin(value, required, optional = []) {
196
+ const allowed = /* @__PURE__ */ new Set([...required, ...optional]);
197
+ for (const key of Object.keys(value)) {
198
+ if (!allowed.has(key)) return false;
199
+ }
200
+ return required.every((key) => Object.prototype.hasOwnProperty.call(value, key));
201
+ }
202
+ function isFiniteInRange(value, minimum, maximum) {
203
+ return typeof value === "number" && Number.isFinite(value) && value >= minimum && value <= maximum;
204
+ }
205
+ function isNonNegativeInteger(value, maximum) {
206
+ return typeof value === "number" && Number.isInteger(value) && value >= 0 && value <= maximum;
207
+ }
208
+ function parseAiError(value) {
209
+ if (!isRecord2(value)) return null;
210
+ if (!hasKeysWithin(value, ["code", "message"], ["detail"])) return null;
211
+ if (typeof value.code !== "string" || !ERROR_CODES.has(value.code)) return null;
212
+ if (!isBoundedString(value.message, HOST_WIRE_LIMITS.messageCharacters)) return null;
213
+ if (value.detail !== void 0 && !isBoundedString(value.detail, HOST_WIRE_LIMITS.messageCharacters)) {
214
+ return null;
215
+ }
216
+ const error = {
217
+ code: value.code,
218
+ message: value.message,
219
+ ...value.detail === void 0 ? {} : { detail: value.detail }
220
+ };
221
+ return error;
222
+ }
223
+ function parseAiProgress(value) {
224
+ if (!isRecord2(value)) return null;
225
+ if (!hasExactKeys(value, ["phase", "message", "percent"])) return null;
226
+ if (!isBoundedString(value.phase, AI_WIRE_LIMITS.progressPhaseCharacters, 1)) return null;
227
+ if (!isBoundedString(value.message, HOST_WIRE_LIMITS.messageCharacters)) return null;
228
+ if (value.percent !== null && !isFiniteInRange(value.percent, 0, 100)) return null;
229
+ return { phase: value.phase, message: value.message, percent: value.percent };
230
+ }
231
+ function parseAiModelInfo(value) {
232
+ if (!isRecord2(value)) return null;
233
+ if (!hasKeysWithin(
234
+ value,
235
+ ["id", "label", "local", "contextWindow", "isDefault"],
236
+ ["availability", "unavailableReason"]
237
+ ))
238
+ return null;
239
+ if (!isBoundedString(value.id, HOST_WIRE_LIMITS.identifierCharacters, 1)) return null;
240
+ if (!isBoundedString(value.label, HOST_WIRE_LIMITS.labelCharacters, 1)) return null;
241
+ if (typeof value.local !== "boolean") return null;
242
+ if (typeof value.isDefault !== "boolean") return null;
243
+ if (value.availability !== void 0 && !["available", "unavailable", "download-required", "downloading"].includes(
244
+ value.availability
245
+ ))
246
+ return null;
247
+ if (value.unavailableReason !== void 0 && (!isBoundedString(value.unavailableReason, HOST_WIRE_LIMITS.messageCharacters, 1) || value.availability === void 0 || value.availability === "available"))
248
+ return null;
249
+ if (value.isDefault && value.availability !== void 0 && value.availability !== "available")
250
+ return null;
251
+ if (value.contextWindow !== null && !isNonNegativeInteger(value.contextWindow, AI_WIRE_LIMITS.contextWindowCeiling)) {
252
+ return null;
253
+ }
254
+ return {
255
+ id: value.id,
256
+ label: value.label,
257
+ local: value.local,
258
+ contextWindow: value.contextWindow,
259
+ isDefault: value.isDefault,
260
+ ...value.availability === void 0 ? {} : {
261
+ availability: value.availability
262
+ },
263
+ ...value.unavailableReason === void 0 ? {} : {
264
+ unavailableReason: value.unavailableReason
265
+ }
266
+ };
267
+ }
268
+ function parseAiModelInfoList(value) {
269
+ if (!Array.isArray(value) || value.length > AI_WIRE_LIMITS.modelEntries) return null;
270
+ const models = [];
271
+ for (const entry of value) {
272
+ const model = parseAiModelInfo(entry);
273
+ if (!model) return null;
274
+ models.push(model);
275
+ }
276
+ return models;
277
+ }
278
+ function parseAiModelDownloadInfo(value) {
279
+ if (!isRecord2(value)) return null;
280
+ if (!hasExactKeys(value, ["id", "label", "contextWindow", "downloadBytes", "state"])) {
281
+ return null;
282
+ }
283
+ if (!isBoundedString(value.id, HOST_WIRE_LIMITS.identifierCharacters, 1)) return null;
284
+ if (!isBoundedString(value.label, HOST_WIRE_LIMITS.labelCharacters, 1)) return null;
285
+ if (value.contextWindow !== null && !isNonNegativeInteger(value.contextWindow, AI_WIRE_LIMITS.contextWindowCeiling)) {
286
+ return null;
287
+ }
288
+ if (value.downloadBytes !== null && (!isNonNegativeInteger(value.downloadBytes, AI_WIRE_LIMITS.downloadBytesCeiling) || value.downloadBytes === 0)) {
289
+ return null;
290
+ }
291
+ if (typeof value.state !== "string" || !MODEL_DOWNLOAD_STATES.has(value.state)) return null;
292
+ return {
293
+ id: value.id,
294
+ label: value.label,
295
+ contextWindow: value.contextWindow,
296
+ downloadBytes: value.downloadBytes,
297
+ state: value.state
298
+ };
299
+ }
300
+ function parseAiModelDownloadInfoList(value) {
301
+ if (!Array.isArray(value) || value.length > AI_WIRE_LIMITS.modelEntries) return null;
302
+ const models = [];
303
+ for (const entry of value) {
304
+ const model = parseAiModelDownloadInfo(entry);
305
+ if (!model) return null;
306
+ models.push(model);
307
+ }
308
+ return models;
309
+ }
310
+ function parseAiModelInstallEvent(value) {
311
+ if (!isRecord2(value)) return null;
312
+ if (value.kind === "progress") {
313
+ if (!hasExactKeys(value, ["kind", "progress"])) return null;
314
+ const progress = parseAiProgress(value.progress);
315
+ return progress ? { kind: "progress", progress } : null;
316
+ }
317
+ if (value.kind === "done") {
318
+ if (!hasExactKeys(value, ["kind", "model"])) return null;
319
+ const model = parseAiModelInfo(value.model);
320
+ return model ? { kind: "done", model } : null;
321
+ }
322
+ if (value.kind === "error") {
323
+ if (!hasExactKeys(value, ["kind", "error"])) return null;
324
+ const error = parseAiError(value.error);
325
+ return error ? { kind: "error", error } : null;
326
+ }
327
+ return null;
328
+ }
329
+ function parseAiChatMessage(value) {
330
+ if (!isRecord2(value)) return null;
331
+ if (!hasExactKeys(value, ["role", "content"])) return null;
332
+ if (typeof value.role !== "string" || !CHAT_ROLES.has(value.role)) return null;
333
+ if (!isBoundedString(value.content, AI_WIRE_LIMITS.promptCharacters)) return null;
334
+ return { role: value.role, content: value.content };
335
+ }
336
+ function parseAiChatRequest(value) {
337
+ if (!isRecord2(value)) return null;
338
+ if (!hasKeysWithin(value, ["messages", "purpose"], ["model", "temperature", "maxTokens"])) {
339
+ return null;
340
+ }
341
+ if (typeof value.purpose !== "string" || !CHAT_PURPOSES.has(value.purpose)) return null;
342
+ if (!Array.isArray(value.messages)) return null;
343
+ if (value.messages.length < 1 || value.messages.length > AI_WIRE_LIMITS.messageEntries)
344
+ return null;
345
+ const messages = [];
346
+ let totalCharacters = 0;
347
+ for (const entry of value.messages) {
348
+ const message2 = parseAiChatMessage(entry);
349
+ if (!message2) return null;
350
+ totalCharacters += message2.content.length;
351
+ if (totalCharacters > AI_WIRE_LIMITS.promptCharacters) return null;
352
+ messages.push(message2);
353
+ }
354
+ if (value.model !== void 0 && !isBoundedString(value.model, HOST_WIRE_LIMITS.identifierCharacters, 1)) {
355
+ return null;
356
+ }
357
+ if (value.temperature !== void 0 && !isFiniteInRange(value.temperature, 0, AI_WIRE_LIMITS.temperatureCeiling)) {
358
+ return null;
359
+ }
360
+ if (value.maxTokens !== void 0 && !isNonNegativeInteger(value.maxTokens, AI_WIRE_LIMITS.maxTokensCeiling)) {
361
+ return null;
362
+ }
363
+ return {
364
+ messages,
365
+ purpose: value.purpose,
366
+ ...value.model === void 0 ? {} : { model: value.model },
367
+ ...value.temperature === void 0 ? {} : { temperature: value.temperature },
368
+ ...value.maxTokens === void 0 ? {} : { maxTokens: value.maxTokens }
369
+ };
370
+ }
371
+ function parseAiChatProgress(value) {
372
+ if (!isRecord2(value)) return null;
373
+ if (!hasExactKeys(value, ["phase", "percent", "outputTokens", "tokensPerSecond"])) return null;
374
+ if (value.phase !== "starting" && value.phase !== "queued" && value.phase !== "loading_model" && value.phase !== "prefill" && value.phase !== "reasoning" && value.phase !== "generating")
375
+ return null;
376
+ if (value.percent !== null && (value.phase !== "loading_model" && value.phase !== "prefill" || !isFiniteInRange(value.percent, 0, 100)))
377
+ return null;
378
+ if (value.outputTokens !== null && !isNonNegativeInteger(value.outputTokens, Number.MAX_SAFE_INTEGER))
379
+ return null;
380
+ if (value.tokensPerSecond !== null && !isFiniteInRange(value.tokensPerSecond, 0, 1e7))
381
+ return null;
382
+ return {
383
+ phase: value.phase,
384
+ percent: value.percent,
385
+ outputTokens: value.outputTokens,
386
+ tokensPerSecond: value.tokensPerSecond
387
+ };
388
+ }
389
+ function parseAiChatEvent(value) {
390
+ if (!isRecord2(value)) return null;
391
+ if (value.kind === "progress") {
392
+ if (!hasExactKeys(value, ["kind", "progress"])) return null;
393
+ const progress = parseAiChatProgress(value.progress);
394
+ return progress ? { kind: "progress", progress } : null;
395
+ }
396
+ if (value.kind === "delta") {
397
+ if (!hasExactKeys(value, ["kind", "text"])) return null;
398
+ if (!isBoundedString(value.text, AI_WIRE_LIMITS.deltaCharacters)) return null;
399
+ return { kind: "delta", text: value.text };
400
+ }
401
+ if (value.kind === "done") {
402
+ if (!hasExactKeys(value, ["kind", "completion"])) return null;
403
+ const completion = value.completion;
404
+ if (!isRecord2(completion)) return null;
405
+ if (!hasExactKeys(completion, ["text", "model", "finishReason", "usage"])) return null;
406
+ if (!isBoundedString(completion.text, AI_WIRE_LIMITS.completionCharacters)) return null;
407
+ if (!isBoundedString(completion.model, HOST_WIRE_LIMITS.identifierCharacters, 1)) return null;
408
+ if (typeof completion.finishReason !== "string" || !FINISH_REASONS.has(completion.finishReason)) {
409
+ return null;
410
+ }
411
+ let usage = null;
412
+ if (completion.usage !== null) {
413
+ if (!isRecord2(completion.usage)) return null;
414
+ if (!hasExactKeys(completion.usage, ["promptTokens", "completionTokens"])) return null;
415
+ if (!isNonNegativeInteger(completion.usage.promptTokens, Number.MAX_SAFE_INTEGER))
416
+ return null;
417
+ if (!isNonNegativeInteger(completion.usage.completionTokens, Number.MAX_SAFE_INTEGER)) {
418
+ return null;
419
+ }
420
+ usage = {
421
+ promptTokens: completion.usage.promptTokens,
422
+ completionTokens: completion.usage.completionTokens
423
+ };
424
+ }
425
+ return {
426
+ kind: "done",
427
+ completion: {
428
+ text: completion.text,
429
+ model: completion.model,
430
+ finishReason: completion.finishReason,
431
+ usage
432
+ }
433
+ };
434
+ }
435
+ if (value.kind === "error") {
436
+ if (!hasExactKeys(value, ["kind", "error"])) return null;
437
+ const error = parseAiError(value.error);
438
+ return error ? { kind: "error", error } : null;
439
+ }
440
+ return null;
441
+ }
442
+ function parseAiStatus(value) {
443
+ if (!isRecord2(value)) return null;
444
+ if (value.kind === "unavailable") {
445
+ if (!hasExactKeys(value, ["kind", "reason"])) return null;
446
+ if (typeof value.reason !== "string" || !UNAVAILABLE_REASONS.has(value.reason)) return null;
447
+ return { kind: "unavailable", reason: value.reason };
448
+ }
449
+ if (value.kind === "connecting") {
450
+ if (!hasExactKeys(value, ["kind", "step", "verificationCode", "progress"])) return null;
451
+ if (typeof value.step !== "string" || !CONNECTION_STEPS.has(value.step)) return null;
452
+ if (value.verificationCode !== null && !isBoundedString(value.verificationCode, AI_WIRE_LIMITS.verificationCodeCharacters, 1)) {
453
+ return null;
454
+ }
455
+ let progress = null;
456
+ if (value.progress !== null) {
457
+ progress = parseAiProgress(value.progress);
458
+ if (!progress) return null;
459
+ }
460
+ return {
461
+ kind: "connecting",
462
+ step: value.step,
463
+ verificationCode: value.verificationCode,
464
+ progress
465
+ };
466
+ }
467
+ if (value.kind === "ready") {
468
+ if (!hasExactKeys(value, ["kind", "provider", "model", "activeRequests"])) return null;
469
+ const provider = value.provider;
470
+ if (!isRecord2(provider)) return null;
471
+ if (!hasExactKeys(provider, ["name", "version", "mode"])) return null;
472
+ if (!isBoundedString(provider.name, HOST_WIRE_LIMITS.labelCharacters, 1)) return null;
473
+ if (provider.version !== null && !isBoundedString(provider.version, HOST_WIRE_LIMITS.labelCharacters)) {
474
+ return null;
475
+ }
476
+ if (typeof provider.mode !== "string" || !PROVIDER_MODES.has(provider.mode)) return null;
477
+ if (!isNonNegativeInteger(value.activeRequests, AI_WIRE_LIMITS.messageEntries)) return null;
478
+ let model = null;
479
+ if (value.model !== null) {
480
+ model = parseAiModelInfo(value.model);
481
+ if (!model) return null;
482
+ }
483
+ return {
484
+ kind: "ready",
485
+ provider: {
486
+ name: provider.name,
487
+ version: provider.version,
488
+ mode: provider.mode
489
+ },
490
+ model,
491
+ activeRequests: value.activeRequests
492
+ };
493
+ }
494
+ if (value.kind === "error") {
495
+ if (!hasExactKeys(value, ["kind", "error", "retryable"])) return null;
496
+ if (typeof value.retryable !== "boolean") return null;
497
+ const error = parseAiError(value.error);
498
+ return error ? { kind: "error", error, retryable: value.retryable } : null;
499
+ }
500
+ return null;
501
+ }
502
+ function parseAiPreferences(value) {
503
+ if (!isRecord2(value)) return null;
504
+ if (!hasExactKeys(value, ["enabled", "model", "reviewMode"])) return null;
505
+ if (typeof value.enabled !== "boolean") return null;
506
+ if (value.model !== null && !isBoundedString(value.model, HOST_WIRE_LIMITS.identifierCharacters, 1)) {
507
+ return null;
508
+ }
509
+ if (typeof value.reviewMode !== "string" || !REVIEW_MODES.has(value.reviewMode)) return null;
510
+ return {
511
+ enabled: value.enabled,
512
+ model: value.model,
513
+ reviewMode: value.reviewMode
514
+ };
515
+ }
516
+ function parseAiPreferencesPatch(value) {
517
+ if (!isRecord2(value)) return null;
518
+ if (!hasKeysWithin(value, [], ["enabled", "model", "reviewMode"])) return null;
519
+ const patch = {};
520
+ if (Object.prototype.hasOwnProperty.call(value, "enabled")) {
521
+ if (typeof value.enabled !== "boolean") return null;
522
+ patch.enabled = value.enabled;
523
+ }
524
+ if (Object.prototype.hasOwnProperty.call(value, "model")) {
525
+ if (value.model !== null && !isBoundedString(value.model, HOST_WIRE_LIMITS.identifierCharacters, 1)) {
526
+ return null;
527
+ }
528
+ patch.model = value.model;
529
+ }
530
+ if (Object.prototype.hasOwnProperty.call(value, "reviewMode")) {
531
+ if (typeof value.reviewMode !== "string" || !REVIEW_MODES.has(value.reviewMode)) return null;
532
+ patch.reviewMode = value.reviewMode;
533
+ }
534
+ return patch;
535
+ }
536
+
537
+ // src/host/speech-wire-policy.ts
538
+ var SPEECH_WIRE_LIMITS = Object.freeze({
539
+ transcribeAudioBytes: 16 * 1024 * 1024,
540
+ promptCharacters: 2e3,
541
+ languageCharacters: 16,
542
+ transcriptCharacters: 64 * 1024,
543
+ segmentEntries: 4096,
544
+ synthesizeTextCharacters: 2e4,
545
+ chunkPcmBytes: 16 * 1024 * 1024,
546
+ chunkWordEntries: 1024,
547
+ minSampleRate: 8e3,
548
+ maxSampleRate: 96e3,
549
+ minSpeed: 0.5,
550
+ maxSpeed: 2,
551
+ modelEntries: 64,
552
+ voiceEntries: 256,
553
+ /** Seconds; a take or a chunk is never an hour long. */
554
+ durationCeiling: 3600,
555
+ downloadBytesCeiling: 8 * 1024 ** 3
556
+ });
557
+ var MODEL_ID = /^[a-z0-9][a-z0-9._-]{0,127}$/u;
558
+ var LANGUAGE_TAG = /^[A-Za-z]{2,3}(?:-[A-Za-z0-9]{2,8})*$/u;
559
+ var ERROR_CODES2 = /* @__PURE__ */ new Set([
560
+ "model-missing",
561
+ "model-download-failed",
562
+ "engine-unavailable",
563
+ "engine-failed",
564
+ "invalid-request",
565
+ "busy",
566
+ "timeout",
567
+ "cancelled",
568
+ "unknown"
569
+ ]);
570
+ var READINESS_STATES = /* @__PURE__ */ new Set([
571
+ "ready",
572
+ "download-required",
573
+ "unavailable",
574
+ "permission-required"
575
+ ]);
576
+ function isRecord3(value) {
577
+ return typeof value === "object" && value !== null && !Array.isArray(value);
578
+ }
579
+ function hasExactKeys2(value, keys) {
580
+ const actual = Object.keys(value);
581
+ return actual.length === keys.length && keys.every((key) => Object.prototype.hasOwnProperty.call(value, key));
582
+ }
583
+ function hasKeysWithin2(value, required, optional = []) {
584
+ const allowed = /* @__PURE__ */ new Set([...required, ...optional]);
585
+ for (const key of Object.keys(value)) {
586
+ if (!allowed.has(key)) return false;
587
+ }
588
+ return required.every((key) => Object.prototype.hasOwnProperty.call(value, key));
589
+ }
590
+ function isFiniteInRange2(value, minimum, maximum) {
591
+ return typeof value === "number" && Number.isFinite(value) && value >= minimum && value <= maximum;
592
+ }
593
+ function isNonNegativeInteger2(value, maximum) {
594
+ return typeof value === "number" && Number.isInteger(value) && value >= 0 && value <= maximum;
595
+ }
596
+ function isLabel(value) {
597
+ return isBoundedString(value, HOST_WIRE_LIMITS.labelCharacters);
598
+ }
599
+ function ownedBuffer(value, maximumBytes) {
600
+ if (value instanceof ArrayBuffer) {
601
+ return value.byteLength <= maximumBytes ? value.slice(0) : null;
602
+ }
603
+ if (ArrayBuffer.isView(value) && !(value instanceof DataView)) {
604
+ if (value.byteLength > maximumBytes) return null;
605
+ const copy = new Uint8Array(value.byteLength);
606
+ copy.set(new Uint8Array(value.buffer, value.byteOffset, value.byteLength));
607
+ return copy.buffer;
608
+ }
609
+ return null;
610
+ }
611
+ function hasRiffWaveHeader(buffer) {
612
+ if (buffer.byteLength < 44) return false;
613
+ const bytes = new Uint8Array(buffer, 0, 12);
614
+ const tag = (offset) => String.fromCharCode(...bytes.subarray(offset, offset + 4));
615
+ return tag(0) === "RIFF" && tag(8) === "WAVE";
616
+ }
617
+ function isSpeechModelId(value) {
618
+ return typeof value === "string" && MODEL_ID.test(value);
619
+ }
620
+ function parseSpeechModelKind(value) {
621
+ return value === "stt" || value === "tts" ? value : null;
622
+ }
623
+ function parseSpeechTranscribeRequest(value) {
624
+ if (!isRecord3(value)) return null;
625
+ if (!hasKeysWithin2(value, ["audio", "mimeType"], ["prompt", "language"])) return null;
626
+ if (value.mimeType !== "audio/wav") return null;
627
+ const audio = ownedBuffer(value.audio, SPEECH_WIRE_LIMITS.transcribeAudioBytes);
628
+ if (!audio || !hasRiffWaveHeader(audio)) return null;
629
+ if (value.prompt !== void 0 && !isBoundedString(value.prompt, SPEECH_WIRE_LIMITS.promptCharacters)) {
630
+ return null;
631
+ }
632
+ if (value.language !== void 0 && (!isBoundedString(value.language, SPEECH_WIRE_LIMITS.languageCharacters, 2) || !LANGUAGE_TAG.test(value.language))) {
633
+ return null;
634
+ }
635
+ return {
636
+ audio,
637
+ mimeType: "audio/wav",
638
+ ...value.prompt === void 0 ? {} : { prompt: value.prompt },
639
+ ...value.language === void 0 ? {} : { language: value.language }
640
+ };
641
+ }
642
+ function parseSpeechSynthesizeRequest(value) {
643
+ if (!isRecord3(value)) return null;
644
+ if (!hasKeysWithin2(value, ["text"], ["voice", "speed"])) return null;
645
+ if (!isBoundedString(value.text, SPEECH_WIRE_LIMITS.synthesizeTextCharacters, 1)) return null;
646
+ if (value.voice !== void 0 && !isSpeechModelId(value.voice)) return null;
647
+ if (value.speed !== void 0 && !isFiniteInRange2(value.speed, SPEECH_WIRE_LIMITS.minSpeed, SPEECH_WIRE_LIMITS.maxSpeed)) {
648
+ return null;
649
+ }
650
+ return {
651
+ text: value.text,
652
+ ...value.voice === void 0 ? {} : { voice: value.voice },
653
+ ...value.speed === void 0 ? {} : { speed: value.speed }
654
+ };
655
+ }
656
+ function parseSpeechPreferencesPatch(value) {
657
+ if (!isRecord3(value)) return null;
658
+ if (!hasKeysWithin2(value, [], ["sttModel", "voice", "speed"])) return null;
659
+ if (value.sttModel !== void 0 && value.sttModel !== null && !isSpeechModelId(value.sttModel))
660
+ return null;
661
+ if (value.voice !== void 0 && value.voice !== null && !isSpeechModelId(value.voice))
662
+ return null;
663
+ if (value.speed !== void 0 && !isFiniteInRange2(value.speed, SPEECH_WIRE_LIMITS.minSpeed, SPEECH_WIRE_LIMITS.maxSpeed)) {
664
+ return null;
665
+ }
666
+ return {
667
+ ...value.sttModel === void 0 ? {} : { sttModel: value.sttModel },
668
+ ...value.voice === void 0 ? {} : { voice: value.voice },
669
+ ...value.speed === void 0 ? {} : { speed: value.speed }
670
+ };
671
+ }
672
+ function parseSpeechError(value) {
673
+ if (!isRecord3(value)) return null;
674
+ if (!hasKeysWithin2(value, ["code", "message"], ["detail"])) return null;
675
+ if (typeof value.code !== "string" || !ERROR_CODES2.has(value.code)) return null;
676
+ if (!isBoundedString(value.message, HOST_WIRE_LIMITS.messageCharacters)) return null;
677
+ if (value.detail !== void 0 && !isBoundedString(value.detail, HOST_WIRE_LIMITS.messageCharacters)) {
678
+ return null;
679
+ }
680
+ return {
681
+ code: value.code,
682
+ message: value.message,
683
+ ...value.detail === void 0 ? {} : { detail: value.detail }
684
+ };
685
+ }
686
+ function parseSpeechResult(value, parseValue) {
687
+ if (!isRecord3(value)) return null;
688
+ if (value.ok === true && hasExactKeys2(value, ["ok", "value"])) {
689
+ const parsed = parseValue(value.value);
690
+ return parsed === null ? null : { ok: true, value: parsed };
691
+ }
692
+ if (value.ok === false && hasExactKeys2(value, ["ok", "error"])) {
693
+ const error = parseSpeechError(value.error);
694
+ return error ? { ok: false, error } : null;
695
+ }
696
+ return null;
697
+ }
698
+ function parseSpeechNullResult(value) {
699
+ if (isRecord3(value) && value.ok === true && hasExactKeys2(value, ["ok", "value"])) {
700
+ return value.value === null ? { ok: true, value: null } : null;
701
+ }
702
+ return parseSpeechResult(value, () => null);
703
+ }
704
+ function parseSpeechReadiness(value) {
705
+ if (!isRecord3(value)) return null;
706
+ if (!hasKeysWithin2(value, ["state"], ["reason", "model"])) return null;
707
+ if (typeof value.state !== "string" || !READINESS_STATES.has(value.state)) return null;
708
+ if (value.reason !== void 0 && !isBoundedString(value.reason, HOST_WIRE_LIMITS.messageCharacters)) {
709
+ return null;
710
+ }
711
+ if (value.model !== void 0 && !isSpeechModelId(value.model)) return null;
712
+ return {
713
+ state: value.state,
714
+ ...value.reason === void 0 ? {} : { reason: value.reason },
715
+ ...value.model === void 0 ? {} : { model: value.model }
716
+ };
717
+ }
718
+ function parseSpeechStatus(value) {
719
+ if (!isRecord3(value) || !hasExactKeys2(value, ["stt", "tts"])) return null;
720
+ const stt = parseSpeechReadiness(value.stt);
721
+ const tts = parseSpeechReadiness(value.tts);
722
+ return stt && tts ? { stt, tts } : null;
723
+ }
724
+ function parseHttpsUrl(value) {
725
+ if (!isBoundedString(value, HOST_WIRE_LIMITS.urlCharacters, 1)) return false;
726
+ try {
727
+ return new URL(value).protocol === "https:";
728
+ } catch {
729
+ return false;
730
+ }
731
+ }
732
+ function parseSpeechModelInfo(value) {
733
+ if (!isRecord3(value)) return null;
734
+ if (!hasKeysWithin2(
735
+ value,
736
+ [
737
+ "id",
738
+ "kind",
739
+ "label",
740
+ "description",
741
+ "downloadBytes",
742
+ "installed",
743
+ "source",
744
+ "recommended",
745
+ "license",
746
+ "licenseUrl"
747
+ ],
748
+ ["updateRequired", "sharedStorage"]
749
+ )) {
750
+ return null;
751
+ }
752
+ const kind = parseSpeechModelKind(value.kind);
753
+ if (!isSpeechModelId(value.id) || !kind) return null;
754
+ if (!isLabel(value.label) || !isLabel(value.description) || !isLabel(value.license)) return null;
755
+ if (!isNonNegativeInteger2(value.downloadBytes, SPEECH_WIRE_LIMITS.downloadBytesCeiling))
756
+ return null;
757
+ if (typeof value.installed !== "boolean" || typeof value.recommended !== "boolean") return null;
758
+ if (value.sharedStorage !== void 0 && typeof value.sharedStorage !== "boolean") return null;
759
+ if (value.source !== "app" && value.source !== "shared" && value.source !== null) return null;
760
+ if (value.installed !== (value.source !== null)) return null;
761
+ if (value.sharedStorage === true && value.source !== "app") return null;
762
+ if ("updateRequired" in value && typeof value.updateRequired !== "boolean") return null;
763
+ if (value.updateRequired === true && value.installed) return null;
764
+ if (!parseHttpsUrl(value.licenseUrl)) return null;
765
+ return {
766
+ id: value.id,
767
+ kind,
768
+ label: value.label,
769
+ description: value.description,
770
+ downloadBytes: value.downloadBytes,
771
+ installed: value.installed,
772
+ ...typeof value.updateRequired === "boolean" ? { updateRequired: value.updateRequired } : {},
773
+ source: value.source,
774
+ ...value.sharedStorage !== void 0 ? { sharedStorage: value.sharedStorage } : {},
775
+ recommended: value.recommended,
776
+ license: value.license,
777
+ licenseUrl: value.licenseUrl
778
+ };
779
+ }
780
+ function parseSpeechVoiceInfo(value) {
781
+ if (!isRecord3(value)) return null;
782
+ if (!hasExactKeys2(value, ["id", "label", "language", "gender", "modelId"])) return null;
783
+ if (!isSpeechModelId(value.id) || !isSpeechModelId(value.modelId)) return null;
784
+ if (!isLabel(value.label)) return null;
785
+ if (typeof value.language !== "string" || !LANGUAGE_TAG.test(value.language)) return null;
786
+ if (value.gender !== "female" && value.gender !== "male" && value.gender !== null) return null;
787
+ return {
788
+ id: value.id,
789
+ label: value.label,
790
+ language: value.language,
791
+ gender: value.gender,
792
+ modelId: value.modelId
793
+ };
794
+ }
795
+ function parseSpeechCatalog(value) {
796
+ if (!isRecord3(value) || !hasExactKeys2(value, ["models", "voices"])) return null;
797
+ if (!Array.isArray(value.models) || value.models.length > SPEECH_WIRE_LIMITS.modelEntries)
798
+ return null;
799
+ if (!Array.isArray(value.voices) || value.voices.length > SPEECH_WIRE_LIMITS.voiceEntries)
800
+ return null;
801
+ const models = [];
802
+ for (const entry of value.models) {
803
+ const model = parseSpeechModelInfo(entry);
804
+ if (!model) return null;
805
+ models.push(model);
806
+ }
807
+ const voices = [];
808
+ for (const entry of value.voices) {
809
+ const voice = parseSpeechVoiceInfo(entry);
810
+ if (!voice) return null;
811
+ voices.push(voice);
812
+ }
813
+ return { models, voices };
814
+ }
815
+ function parseSpeechProgress(value) {
816
+ if (!isRecord3(value) || !hasExactKeys2(value, ["phase", "receivedBytes", "totalBytes"]))
817
+ return null;
818
+ if (value.phase !== "downloading" && value.phase !== "verifying") return null;
819
+ if (!isNonNegativeInteger2(value.receivedBytes, SPEECH_WIRE_LIMITS.downloadBytesCeiling))
820
+ return null;
821
+ if (value.totalBytes !== null && !isNonNegativeInteger2(value.totalBytes, SPEECH_WIRE_LIMITS.downloadBytesCeiling)) {
822
+ return null;
823
+ }
824
+ return {
825
+ phase: value.phase,
826
+ receivedBytes: value.receivedBytes,
827
+ totalBytes: value.totalBytes
828
+ };
829
+ }
830
+ function parseSpeechInstallEvent(value) {
831
+ if (!isRecord3(value)) return null;
832
+ if (value.kind === "progress" && hasExactKeys2(value, ["kind", "progress"])) {
833
+ const progress = parseSpeechProgress(value.progress);
834
+ return progress ? { kind: "progress", progress } : null;
835
+ }
836
+ if (value.kind === "done" && hasExactKeys2(value, ["kind", "model"])) {
837
+ const model = parseSpeechModelInfo(value.model);
838
+ return model ? { kind: "done", model } : null;
839
+ }
840
+ if (value.kind === "error" && hasExactKeys2(value, ["kind", "error"])) {
841
+ const error = parseSpeechError(value.error);
842
+ return error ? { kind: "error", error } : null;
843
+ }
844
+ return null;
845
+ }
846
+ function parseSpeechPreferences(value) {
847
+ if (!isRecord3(value) || !hasExactKeys2(value, ["sttModel", "voice", "speed"])) return null;
848
+ const patch = parseSpeechPreferencesPatch(value);
849
+ if (!patch || patch.speed === void 0) return null;
850
+ return {
851
+ sttModel: patch.sttModel ?? null,
852
+ voice: patch.voice ?? null,
853
+ speed: patch.speed
854
+ };
855
+ }
856
+ function parseSpeechSegment(value) {
857
+ if (!isRecord3(value) || !hasExactKeys2(value, ["start", "end", "text"])) return null;
858
+ if (!isFiniteInRange2(value.start, 0, SPEECH_WIRE_LIMITS.durationCeiling)) return null;
859
+ if (!isFiniteInRange2(value.end, value.start, SPEECH_WIRE_LIMITS.durationCeiling)) return null;
860
+ if (!isBoundedString(value.text, SPEECH_WIRE_LIMITS.transcriptCharacters)) return null;
861
+ return { start: value.start, end: value.end, text: value.text };
862
+ }
863
+ function parseSpeechTranscript(value) {
864
+ if (!isRecord3(value)) return null;
865
+ if (!hasExactKeys2(value, ["text", "language", "segments", "durationMs"])) return null;
866
+ if (!isBoundedString(value.text, SPEECH_WIRE_LIMITS.transcriptCharacters)) return null;
867
+ if (value.language !== null && (typeof value.language !== "string" || !LANGUAGE_TAG.test(value.language))) {
868
+ return null;
869
+ }
870
+ if (!Array.isArray(value.segments) || value.segments.length > SPEECH_WIRE_LIMITS.segmentEntries)
871
+ return null;
872
+ if (!isFiniteInRange2(value.durationMs, 0, SPEECH_WIRE_LIMITS.durationCeiling * 1e3)) return null;
873
+ const segments = [];
874
+ for (const entry of value.segments) {
875
+ const segment = parseSpeechSegment(entry);
876
+ if (!segment) return null;
877
+ segments.push(segment);
878
+ }
879
+ return {
880
+ text: value.text,
881
+ language: value.language,
882
+ segments,
883
+ durationMs: value.durationMs
884
+ };
885
+ }
886
+ function parseSpeechAudioChunk(value) {
887
+ if (!isRecord3(value)) return null;
888
+ if (!hasKeysWithin2(
889
+ value,
890
+ ["index", "pcm", "sampleRate", "durationSec", "textStart", "textEnd"],
891
+ ["wordTimings"]
892
+ )) {
893
+ return null;
894
+ }
895
+ if (!isNonNegativeInteger2(value.index, Number.MAX_SAFE_INTEGER)) return null;
896
+ const pcm = ownedBuffer(value.pcm, SPEECH_WIRE_LIMITS.chunkPcmBytes);
897
+ if (!pcm || pcm.byteLength % Float32Array.BYTES_PER_ELEMENT !== 0) return null;
898
+ if (!isNonNegativeInteger2(value.sampleRate, SPEECH_WIRE_LIMITS.maxSampleRate) || value.sampleRate < SPEECH_WIRE_LIMITS.minSampleRate) {
899
+ return null;
900
+ }
901
+ if (!isFiniteInRange2(value.durationSec, 0, SPEECH_WIRE_LIMITS.durationCeiling)) return null;
902
+ const textCeiling = SPEECH_WIRE_LIMITS.synthesizeTextCharacters;
903
+ if (!isNonNegativeInteger2(value.textStart, textCeiling)) return null;
904
+ if (!isNonNegativeInteger2(value.textEnd, textCeiling) || value.textEnd < value.textStart)
905
+ return null;
906
+ const wordTimings = [];
907
+ if ("wordTimings" in value) {
908
+ if (!Array.isArray(value.wordTimings) || value.wordTimings.length > SPEECH_WIRE_LIMITS.chunkWordEntries)
909
+ return null;
910
+ let previousEnd = 0;
911
+ let previousTextStart = value.textStart;
912
+ let previousTextEnd = value.textStart;
913
+ for (const word of value.wordTimings) {
914
+ if (!isRecord3(word) || !hasExactKeys2(word, ["textStart", "textEnd", "startSec", "endSec"]))
915
+ return null;
916
+ if (!isNonNegativeInteger2(word.textStart, value.textEnd) || word.textStart < previousTextStart)
917
+ return null;
918
+ if (!isNonNegativeInteger2(word.textEnd, value.textEnd) || word.textEnd <= word.textStart || word.textEnd < previousTextEnd)
919
+ return null;
920
+ if (!isFiniteInRange2(word.startSec, previousEnd, value.durationSec) || !isFiniteInRange2(word.endSec, word.startSec, value.durationSec) || word.endSec === word.startSec)
921
+ return null;
922
+ wordTimings.push({
923
+ textStart: word.textStart,
924
+ textEnd: word.textEnd,
925
+ startSec: word.startSec,
926
+ endSec: word.endSec
927
+ });
928
+ previousEnd = word.endSec;
929
+ previousTextStart = word.textStart;
930
+ previousTextEnd = word.textEnd;
931
+ }
932
+ }
933
+ return {
934
+ index: value.index,
935
+ pcm,
936
+ sampleRate: value.sampleRate,
937
+ durationSec: value.durationSec,
938
+ textStart: value.textStart,
939
+ textEnd: value.textEnd,
940
+ ..."wordTimings" in value ? { wordTimings } : {}
941
+ };
942
+ }
943
+ function parseSpeechSynthesisSummary(value) {
944
+ if (!isRecord3(value)) return null;
945
+ if (!hasExactKeys2(value, ["voice", "model", "sampleRate", "durationSec", "chunks"])) return null;
946
+ if (!isSpeechModelId(value.voice) || !isSpeechModelId(value.model)) return null;
947
+ if (!isNonNegativeInteger2(value.sampleRate, SPEECH_WIRE_LIMITS.maxSampleRate) || value.sampleRate < SPEECH_WIRE_LIMITS.minSampleRate) {
948
+ return null;
949
+ }
950
+ if (!isFiniteInRange2(value.durationSec, 0, SPEECH_WIRE_LIMITS.durationCeiling * 24)) return null;
951
+ if (!isNonNegativeInteger2(value.chunks, Number.MAX_SAFE_INTEGER)) return null;
952
+ return {
953
+ voice: value.voice,
954
+ model: value.model,
955
+ sampleRate: value.sampleRate,
956
+ durationSec: value.durationSec,
957
+ chunks: value.chunks
958
+ };
959
+ }
960
+ function parseSpeechSynthesizeEvent(value) {
961
+ if (!isRecord3(value)) return null;
962
+ if (value.kind === "progress" && hasExactKeys2(value, ["kind", "phase", "completedCharacters", "totalCharacters"])) {
963
+ if (value.phase !== "loading" && value.phase !== "synthesizing") return null;
964
+ const ceiling = SPEECH_WIRE_LIMITS.synthesizeTextCharacters;
965
+ if (!isNonNegativeInteger2(value.totalCharacters, ceiling)) return null;
966
+ if (!isNonNegativeInteger2(value.completedCharacters, value.totalCharacters)) return null;
967
+ return {
968
+ kind: "progress",
969
+ phase: value.phase,
970
+ completedCharacters: value.completedCharacters,
971
+ totalCharacters: value.totalCharacters
972
+ };
973
+ }
974
+ if (value.kind === "chunk" && hasExactKeys2(value, ["kind", "chunk"])) {
975
+ const chunk = parseSpeechAudioChunk(value.chunk);
976
+ return chunk ? { kind: "chunk", chunk } : null;
977
+ }
978
+ if (value.kind === "done" && hasExactKeys2(value, ["kind", "summary"])) {
979
+ const summary = parseSpeechSynthesisSummary(value.summary);
980
+ return summary ? { kind: "done", summary } : null;
981
+ }
982
+ if (value.kind === "error" && hasExactKeys2(value, ["kind", "error"])) {
983
+ const error = parseSpeechError(value.error);
984
+ return error ? { kind: "error", error } : null;
985
+ }
986
+ return null;
987
+ }
988
+
989
+ // src/host/filesystem-v2.ts
990
+ var FILE_SYSTEM_TRANSFER_LIMITS = Object.freeze({
991
+ fileBytes: 1024 * 1024 * 1024,
992
+ chunkBytes: 4 * 1024 * 1024,
993
+ totalBytes: 2 * 1024 * 1024 * 1024,
994
+ transfers: 4,
995
+ idleMs: 12e4,
996
+ lifetimeMs: 15 * 6e4
997
+ });
998
+ var ELECTRON_FILE_SYSTEM_V2_CAPABILITIES = Object.freeze({
999
+ writeAtomicity: "process",
1000
+ moveAtomicity: "process",
1001
+ snapshotAtomicity: "process",
1002
+ conditionalWrite: "process",
1003
+ recursiveRemove: true,
1004
+ watch: true,
1005
+ caseSensitivity: "platform",
1006
+ symlinkPolicy: "follow-contained",
1007
+ durability: "best-effort"
1008
+ });
1009
+
1010
+ // src/host/ai-knowledge.ts
1011
+ function record(value) {
1012
+ return typeof value === "object" && value !== null && !Array.isArray(value);
1013
+ }
1014
+ function exact(value, keys) {
1015
+ return Object.keys(value).length === keys.length && keys.every((key) => Object.prototype.hasOwnProperty.call(value, key));
1016
+ }
1017
+ var label = (value) => isBoundedString(value, HOST_WIRE_LIMITS.labelCharacters, 1);
1018
+ var message = (value) => value === null || isBoundedString(value, HOST_WIRE_LIMITS.messageCharacters);
1019
+ var count = (value) => value === null || typeof value === "number" && Number.isSafeInteger(value) && value >= 0;
1020
+ function parseAiKnowledgeAction(value) {
1021
+ if (!record(value)) return null;
1022
+ if (value.action === "improve" && exact(value, ["action"])) return { action: value.action };
1023
+ if (!exact(value, ["action", "catalogId"]) || !label(value.catalogId)) return null;
1024
+ switch (value.action) {
1025
+ case "install":
1026
+ case "remove":
1027
+ case "enable":
1028
+ case "disable":
1029
+ case "cancel":
1030
+ return { action: value.action, catalogId: value.catalogId };
1031
+ default:
1032
+ return null;
1033
+ }
1034
+ }
1035
+ function parseAiKnowledgeState(value) {
1036
+ if (!record(value) || !exact(value, ["catalogs", "improvement"]) || !Array.isArray(value.catalogs) || value.catalogs.length > 512)
1037
+ return null;
1038
+ let improvement = null;
1039
+ if (value.improvement !== null) {
1040
+ const raw = value.improvement;
1041
+ if (!record(raw) || !exact(raw, ["downloadBytes", "downloading"]) || typeof raw.downloadBytes !== "number" || !count(raw.downloadBytes) || typeof raw.downloading !== "boolean")
1042
+ return null;
1043
+ improvement = { downloadBytes: raw.downloadBytes, downloading: raw.downloading };
1044
+ }
1045
+ const catalogs = [];
1046
+ const ids = /* @__PURE__ */ new Set();
1047
+ for (const raw of value.catalogs) {
1048
+ if (!record(raw) || !exact(raw, [
1049
+ "id",
1050
+ "name",
1051
+ "description",
1052
+ "version",
1053
+ "installedVersion",
1054
+ "enabled",
1055
+ "updateAvailable",
1056
+ "downloadBytes",
1057
+ "documents",
1058
+ "state",
1059
+ "percent",
1060
+ "message"
1061
+ ]))
1062
+ return null;
1063
+ if (!label(raw.id) || ids.has(raw.id) || !label(raw.name) || !isBoundedString(raw.description, HOST_WIRE_LIMITS.messageCharacters) || !label(raw.version) || !(raw.installedVersion === null || label(raw.installedVersion)) || typeof raw.enabled !== "boolean" || typeof raw.updateAvailable !== "boolean" || !count(raw.downloadBytes) || !count(raw.documents) || !message(raw.message))
1064
+ return null;
1065
+ if (raw.state !== "available" && raw.state !== "installed" && raw.state !== "downloading" && raw.state !== "error")
1066
+ return null;
1067
+ if (raw.percent !== null && !(typeof raw.percent === "number" && Number.isFinite(raw.percent) && raw.percent >= 0 && raw.percent <= 100))
1068
+ return null;
1069
+ ids.add(raw.id);
1070
+ catalogs.push({
1071
+ id: raw.id,
1072
+ name: raw.name,
1073
+ description: raw.description,
1074
+ version: raw.version,
1075
+ installedVersion: raw.installedVersion,
1076
+ enabled: raw.enabled,
1077
+ updateAvailable: raw.updateAvailable,
1078
+ downloadBytes: raw.downloadBytes,
1079
+ documents: raw.documents,
1080
+ state: raw.state,
1081
+ percent: raw.percent,
1082
+ message: raw.message
1083
+ });
1084
+ }
1085
+ return { catalogs, improvement };
1086
+ }
1087
+
1088
+ // src/host/index.ts
1089
+ function rawHost() {
1090
+ if (typeof globalThis === "undefined") return null;
1091
+ return globalThis.docBlocksHost ?? null;
1092
+ }
1093
+ function hasDocBlocksHost() {
1094
+ return deriveHostCapabilities(rawHost()) !== NO_HOST_CAPABILITIES;
1095
+ }
1096
+ function getHostCapabilities() {
1097
+ return deriveHostCapabilities(rawHost());
1098
+ }
1099
+ function hostSupports(capability) {
1100
+ return getHostCapabilities()[capability];
1101
+ }
1102
+ function getHostEnvironment() {
1103
+ const host = rawHost();
1104
+ if (typeof host !== "object" || host === null) return null;
1105
+ return parseHostEnvironment(host.env);
1106
+ }
1107
+ function isElectronHost() {
1108
+ return getHostEnvironment()?.surface === "electron";
1109
+ }
1110
+ function getDocBlocksHost() {
1111
+ const host = globalThis.docBlocksHost;
1112
+ if (!host) {
1113
+ throw new Error("docBlocksHost is not available \u2014 not running under Electron?");
1114
+ }
1115
+ return host;
1116
+ }
1117
+ function maybeGetDocBlocksHost() {
1118
+ return globalThis.docBlocksHost ?? null;
1119
+ }
1120
+
1121
+ export {
1122
+ HOST_SURFACE_KINDS,
1123
+ HOST_PLATFORMS,
1124
+ NO_HOST_CAPABILITIES,
1125
+ parseHostEnvironment,
1126
+ deriveHostCapabilities,
1127
+ AI_WIRE_LIMITS,
1128
+ parseAiError,
1129
+ parseAiProgress,
1130
+ parseAiModelInfo,
1131
+ parseAiModelInfoList,
1132
+ parseAiModelDownloadInfo,
1133
+ parseAiModelDownloadInfoList,
1134
+ parseAiModelInstallEvent,
1135
+ parseAiChatRequest,
1136
+ parseAiChatProgress,
1137
+ parseAiChatEvent,
1138
+ parseAiStatus,
1139
+ parseAiPreferences,
1140
+ parseAiPreferencesPatch,
1141
+ SPEECH_WIRE_LIMITS,
1142
+ isSpeechModelId,
1143
+ parseSpeechModelKind,
1144
+ parseSpeechTranscribeRequest,
1145
+ parseSpeechSynthesizeRequest,
1146
+ parseSpeechPreferencesPatch,
1147
+ parseSpeechError,
1148
+ parseSpeechResult,
1149
+ parseSpeechNullResult,
1150
+ parseSpeechReadiness,
1151
+ parseSpeechStatus,
1152
+ parseSpeechModelInfo,
1153
+ parseSpeechVoiceInfo,
1154
+ parseSpeechCatalog,
1155
+ parseSpeechProgress,
1156
+ parseSpeechInstallEvent,
1157
+ parseSpeechPreferences,
1158
+ parseSpeechTranscript,
1159
+ parseSpeechAudioChunk,
1160
+ parseSpeechSynthesisSummary,
1161
+ parseSpeechSynthesizeEvent,
1162
+ FILE_SYSTEM_TRANSFER_LIMITS,
1163
+ ELECTRON_FILE_SYSTEM_V2_CAPABILITIES,
1164
+ parseAiKnowledgeAction,
1165
+ parseAiKnowledgeState,
1166
+ hasDocBlocksHost,
1167
+ getHostCapabilities,
1168
+ hostSupports,
1169
+ getHostEnvironment,
1170
+ isElectronHost,
1171
+ getDocBlocksHost,
1172
+ maybeGetDocBlocksHost
1173
+ };