ghostykit 0.6.4 → 0.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,1798 @@
1
+ import {
2
+ TOOL_VERBS_ES
3
+ } from "./chunk-UUH37KXA.js";
4
+ import {
5
+ cleanUserText
6
+ } from "./chunk-6U545WJG.js";
7
+
8
+ // src/react/strings.ts
9
+ var STRINGS_ES = {
10
+ numberLocale: "es-MX",
11
+ placeholder: (agent) => `Escr\xEDbele a ${agent}`,
12
+ placeholderDefault: "Escr\xEDbele al agente",
13
+ send: "Enviar",
14
+ stop: "Detener",
15
+ uploading: "Subiendo tu archivo\u2026",
16
+ uploadingN: (n) => `Subiendo tus ${n} archivos\u2026`,
17
+ attachImage: "Adjuntar imagen",
18
+ attachFile: "Adjuntar archivo",
19
+ noImages: "Este agente no ve im\xE1genes",
20
+ removeAttachment: "Quitar adjunto",
21
+ removeReference: "Quitar referencia",
22
+ dropFiles: "Suelta tus archivos",
23
+ dropHint: "Excel, Word, PDF o im\xE1genes",
24
+ tooBig: (name, mb) => `${name} pesa m\xE1s de ${mb} MB`,
25
+ tooMany: (max) => `no caben m\xE1s de ${max} archivos por mensaje`,
26
+ cantSeeImage: (name) => `${name}: este agente no ve im\xE1genes`,
27
+ cantUpload: (name) => `${name}: aqu\xED s\xF3lo se pueden mandar im\xE1genes y texto`,
28
+ uploadFailed: "no se pudo subir el archivo",
29
+ recordVoice: "Grabar nota de voz",
30
+ voiceNote: "Nota de voz",
31
+ cancelVoice: "Cancelar la nota de voz",
32
+ stopAndSendVoice: "Parar y mandar la nota de voz",
33
+ micDenied: "No tengo permiso para usar el micr\xF3fono.",
34
+ voiceEmpty: "no se entendi\xF3 nada en la nota de voz",
35
+ voiceFailed: "no se pudo mandar la nota de voz",
36
+ model: "Modelo",
37
+ thinking: "Pensando\u2026",
38
+ howItGoes: (s) => s < 6 ? "Pensando\u2026" : s < 15 ? "Trabajando\u2026" : s < 60 ? "Estoy en ello\u2026" : s < 120 ? "Esto me lleva un poco\u2026" : s < 300 ? "Llevo un buen rato\u2026" : "Me est\xE1 tomando mucho \u2014 puedes detenerme",
39
+ stillWorking: "Estoy en ello\u2026",
40
+ retry: "Reintentar",
41
+ copy: "Copiar",
42
+ copied: "Copiado",
43
+ copyMessage: "Copiar mensaje",
44
+ worked: (s) => `Trabaj\xF3 ${s} s`,
45
+ stepsExpand: "Ver el detalle de los pasos",
46
+ stepsCollapse: "Plegar los pasos",
47
+ earlierSteps: (n) => n === 1 ? "1 paso antes" : `${n} pasos antes`,
48
+ withProblems: (n) => n === 1 ? "1 con problemas" : `${n} con problemas`,
49
+ running: "Ejecutando",
50
+ done: "Lista",
51
+ failed: "Fall\xF3",
52
+ step: "Paso",
53
+ replyOptions: "Opciones para responder",
54
+ linkTitle: "Vas a salir de aqu\xED",
55
+ linkCopy: "Copiar",
56
+ linkCopied: "Copiado",
57
+ linkOpen: "Abrir",
58
+ close: "Cerrar",
59
+ goToLatest: "Ir al \xFAltimo mensaje",
60
+ steps: { waking: "Despertando al agente\u2026", session: "Preparando la sesi\xF3n\u2026", compacting: "Resumiendo la conversaci\xF3n\u2026" },
61
+ loadOlder: "Cargar mensajes anteriores",
62
+ loadingOlder: "Cargando\u2026",
63
+ continueRun: "Continuar",
64
+ runCut: "La respuesta se cort\xF3 antes de terminar.",
65
+ stalled: "Se ator\xF3, sigo intentando\u2026",
66
+ truncated: "La respuesta qued\xF3 incompleta.",
67
+ attachmentFailed: (name, reason) => reason ? `No pude leer ${name}: ${reason}` : `No pude leer ${name}`,
68
+ queued: "Se manda cuando termine",
69
+ subagentsWorking: (n) => n === 1 ? "1 agente trabajando" : `${n} agentes trabajando`,
70
+ subagentsDone: (n) => n === 1 ? "1 agente termin\xF3" : `${n} agentes terminaron`,
71
+ subagentStop: "Detener",
72
+ subagentStatus: { running: "Trabajando", completed: "Termin\xF3", failed: "Fall\xF3", stopped: "Detenido" },
73
+ confirmTitle: "Necesito tu permiso para",
74
+ approve: "Aprobar",
75
+ reject: "Rechazar",
76
+ expiresIn: (t) => `Vence en ${t}`,
77
+ expiredNow: "Venci\xF3 sin respuesta",
78
+ decisionApproved: "Aprobaste",
79
+ decisionRejected: "Rechazaste",
80
+ decisionExpired: "Venci\xF3",
81
+ decisionCancelled: "Descartaste",
82
+ stampCancelled: "Descartado",
83
+ stampApproved: "Aprobado",
84
+ stampRejected: "Rechazado",
85
+ stampExpired: "Vencido"
86
+ };
87
+ var STRINGS_EN = {
88
+ numberLocale: "en-US",
89
+ placeholder: (agent) => `Message ${agent}`,
90
+ placeholderDefault: "Message the agent",
91
+ send: "Send",
92
+ stop: "Stop",
93
+ uploading: "Uploading your file\u2026",
94
+ uploadingN: (n) => `Uploading your ${n} files\u2026`,
95
+ attachImage: "Attach image",
96
+ attachFile: "Attach file",
97
+ noImages: "This agent can't see images",
98
+ removeAttachment: "Remove attachment",
99
+ removeReference: "Remove reference",
100
+ dropFiles: "Drop your files",
101
+ dropHint: "Excel, Word, PDF or images",
102
+ tooBig: (name, mb) => `${name} is larger than ${mb} MB`,
103
+ tooMany: (max) => `no more than ${max} files per message`,
104
+ cantSeeImage: (name) => `${name}: this agent can't see images`,
105
+ cantUpload: (name) => `${name}: only images and text can be sent here`,
106
+ uploadFailed: "couldn't upload the file",
107
+ recordVoice: "Record voice note",
108
+ voiceNote: "Voice note",
109
+ cancelVoice: "Cancel voice note",
110
+ stopAndSendVoice: "Stop and send voice note",
111
+ micDenied: "I don't have permission to use the microphone.",
112
+ voiceEmpty: "nothing was understood in the voice note",
113
+ voiceFailed: "couldn't send the voice note",
114
+ model: "Model",
115
+ thinking: "Thinking\u2026",
116
+ howItGoes: (s) => s < 6 ? "Thinking\u2026" : s < 15 ? "Working\u2026" : s < 60 ? "On it\u2026" : s < 120 ? "This is taking a bit\u2026" : s < 300 ? "Been at it a while\u2026" : "This is taking long \u2014 you can stop me",
117
+ stillWorking: "On it\u2026",
118
+ retry: "Retry",
119
+ copy: "Copy",
120
+ copied: "Copied",
121
+ copyMessage: "Copy message",
122
+ worked: (s) => `Worked ${s} s`,
123
+ stepsExpand: "See step details",
124
+ stepsCollapse: "Collapse the steps",
125
+ earlierSteps: (n) => n === 1 ? "1 earlier step" : `${n} earlier steps`,
126
+ withProblems: (n) => `${n} with problems`,
127
+ running: "Running",
128
+ done: "Done",
129
+ failed: "Failed",
130
+ step: "Step",
131
+ replyOptions: "Reply options",
132
+ linkTitle: "You're about to leave",
133
+ linkCopy: "Copy",
134
+ linkCopied: "Copied",
135
+ linkOpen: "Open",
136
+ close: "Close",
137
+ goToLatest: "Go to latest message",
138
+ steps: { waking: "Waking the agent\u2026", session: "Starting the session\u2026", compacting: "Compacting the conversation\u2026" },
139
+ loadOlder: "Load earlier messages",
140
+ loadingOlder: "Loading\u2026",
141
+ continueRun: "Continue",
142
+ runCut: "The answer was cut off before it finished.",
143
+ stalled: "Got stuck, still trying\u2026",
144
+ truncated: "The answer is incomplete.",
145
+ attachmentFailed: (name, reason) => reason ? `Couldn't read ${name}: ${reason}` : `Couldn't read ${name}`,
146
+ queued: "Sends when this finishes",
147
+ subagentsWorking: (n) => n === 1 ? "1 agent working" : `${n} agents working`,
148
+ subagentsDone: (n) => n === 1 ? "1 agent finished" : `${n} agents finished`,
149
+ subagentStop: "Stop",
150
+ subagentStatus: { running: "Working", completed: "Done", failed: "Failed", stopped: "Stopped" },
151
+ confirmTitle: "I need your permission to",
152
+ approve: "Approve",
153
+ reject: "Reject",
154
+ expiresIn: (t) => `Expires in ${t}`,
155
+ expiredNow: "Expired without an answer",
156
+ decisionApproved: "You approved",
157
+ decisionRejected: "You rejected",
158
+ decisionExpired: "Expired",
159
+ decisionCancelled: "You dismissed",
160
+ stampCancelled: "Dismissed",
161
+ stampApproved: "Approved",
162
+ stampRejected: "Rejected",
163
+ stampExpired: "Expired"
164
+ };
165
+
166
+ // src/react/context.tsx
167
+ import { createContext, useContext } from "react";
168
+ var PilotoContext = createContext({
169
+ strings: STRINGS_ES,
170
+ toolVerbs: TOOL_VERBS_ES,
171
+ toolIcons: {},
172
+ formatUserText: cleanUserText,
173
+ theme: "light",
174
+ skin: "ghosty",
175
+ markdown: {}
176
+ });
177
+ var usePiloto = () => useContext(PilotoContext);
178
+ var TurnContext = createContext(void 0);
179
+ function rootProps(theme, skin = "ghosty") {
180
+ return { className: "piloto", "data-theme": theme, "data-skin": skin };
181
+ }
182
+
183
+ // ../../node_modules/lucide-react/dist/esm/createLucideIcon.mjs
184
+ import { forwardRef as forwardRef2, createElement as createElement3 } from "react";
185
+
186
+ // ../../node_modules/lucide-react/dist/esm/shared/src/utils/toKebabCase.mjs
187
+ var toKebabCase = (string) => string?.replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase();
188
+
189
+ // ../../node_modules/lucide-react/dist/esm/shared/src/utils/toLucideIconData.mjs
190
+ function toLucideIconData(iconName, iconNode, aliases = []) {
191
+ if (iconNode == null) {
192
+ throw new Error("[lucide]: iconNode is required when icon name is used");
193
+ }
194
+ return {
195
+ name: toKebabCase(iconName),
196
+ size: 24,
197
+ node: iconNode,
198
+ ...aliases.length > 0 ? { aliases } : {}
199
+ };
200
+ }
201
+
202
+ // ../../node_modules/lucide-react/dist/esm/shared/src/utils/toCamelCase.mjs
203
+ var toCamelCase = (string) => {
204
+ let out = "";
205
+ let upperNext = false;
206
+ for (const ch of string) {
207
+ if (ch === "-" || ch === "_" || ch <= " ") {
208
+ upperNext = out.length > 0;
209
+ continue;
210
+ }
211
+ if (out.length === 0) {
212
+ out += ch.toLowerCase();
213
+ } else {
214
+ out += upperNext ? ch.toUpperCase() : ch;
215
+ }
216
+ upperNext = false;
217
+ }
218
+ return out;
219
+ };
220
+
221
+ // ../../node_modules/lucide-react/dist/esm/shared/src/utils/toPascalCase.mjs
222
+ var toPascalCase = (string) => {
223
+ const camelCase = toCamelCase(string);
224
+ return camelCase.charAt(0).toUpperCase() + camelCase.slice(1);
225
+ };
226
+
227
+ // ../../node_modules/lucide-react/dist/esm/Icon.mjs
228
+ import { forwardRef, createElement as createElement2 } from "react";
229
+
230
+ // ../../node_modules/lucide-react/dist/esm/shared/src/utils/mergeClasses.mjs
231
+ var mergeClasses = (...classes) => classes.filter((className, index, array) => {
232
+ return Boolean(className) && className.trim() !== "" && array.indexOf(className) === index;
233
+ }).join(" ").trim();
234
+
235
+ // ../../node_modules/lucide-react/dist/esm/shared/src/build/defaultAttributes.mjs
236
+ var defaultAttributes = {
237
+ xmlns: "http://www.w3.org/2000/svg",
238
+ width: 24,
239
+ height: 24,
240
+ viewBox: "0 0 24 24",
241
+ fill: "none",
242
+ stroke: "currentColor",
243
+ "stroke-width": 2,
244
+ "stroke-linecap": "round",
245
+ "stroke-linejoin": "round"
246
+ };
247
+
248
+ // ../../node_modules/lucide-react/dist/esm/shared/src/build/buildLucideIconNode.mjs
249
+ function isDefined(value) {
250
+ return value !== null && value !== void 0;
251
+ }
252
+ function buildLucideIconNode(icon, params = {}) {
253
+ const attributeNames = params.attributeNames ?? {};
254
+ const getAttributeName = (attributeName) => attributeNames[attributeName] ?? attributeName;
255
+ const viewBoxWidth = icon.size ?? icon.width ?? defaultAttributes["width"];
256
+ const viewBoxHeight = icon.size ?? icon.height ?? defaultAttributes["height"];
257
+ const aliasClassNames = icon.aliases?.filter((alias) => typeof alias === "string" && alias.trim() !== "").map((alias) => `lucide-${alias}`) ?? [];
258
+ const iconClassNames = [...icon.name ? [`lucide-${icon.name}`] : [], ...aliasClassNames];
259
+ const classNamesFromClassName = params.className?.split(" ").filter(Boolean) ?? [];
260
+ const className = params.includeDefaultClasses === false ? mergeClasses(...classNamesFromClassName) : mergeClasses("lucide", ...iconClassNames, ...classNamesFromClassName);
261
+ const calculatedStrokeWidth = params.absoluteStrokeWidth ? Number(params.strokeWidth ?? defaultAttributes["stroke-width"]) * Number(icon.size ?? icon.width ?? defaultAttributes["width"]) / Number(params.size ?? params.width ?? defaultAttributes["width"]) : params.strokeWidth ?? defaultAttributes["stroke-width"];
262
+ const attributes = {
263
+ ...Object.entries(defaultAttributes).reduce((attrs, [attrName, value]) => {
264
+ attrs[getAttributeName(attrName)] = value;
265
+ return attrs;
266
+ }, {}),
267
+ ..."color" in params && params.color && {
268
+ [getAttributeName("stroke")]: params.color
269
+ },
270
+ ..."size" in params && isDefined(params.size) && {
271
+ [getAttributeName("width")]: params.size,
272
+ [getAttributeName("height")]: params.size
273
+ },
274
+ ..."width" in params && isDefined(params.width) && {
275
+ [getAttributeName("width")]: params.width
276
+ },
277
+ ..."height" in params && isDefined(params.height) && {
278
+ [getAttributeName("height")]: params.height
279
+ },
280
+ [getAttributeName("stroke-width")]: calculatedStrokeWidth,
281
+ ...className && {
282
+ [getAttributeName("class")]: className
283
+ },
284
+ [getAttributeName("viewBox")]: `0 0 ${viewBoxWidth} ${viewBoxHeight}`,
285
+ ...params.hasA11yProp === false ? {
286
+ [getAttributeName("aria-hidden")]: "true"
287
+ } : {},
288
+ ..."attributes" in params && params.attributes
289
+ };
290
+ return [
291
+ "svg",
292
+ attributes,
293
+ icon.node.map((child) => {
294
+ const [name, attrs, children] = child;
295
+ const nextAttrs = params.nonScalingStroke ? { [getAttributeName("vector-effect")]: "non-scaling-stroke", ...attrs } : attrs;
296
+ return children ? [name, nextAttrs, children] : [name, nextAttrs];
297
+ })
298
+ ];
299
+ }
300
+
301
+ // ../../node_modules/lucide-react/dist/esm/shared/src/build/buildLucideIconForReact.mjs
302
+ function buildLucideIconForReact(icon, params = {}) {
303
+ return buildLucideIconNode(icon, {
304
+ ...params,
305
+ attributeNames: {
306
+ ...params.attributeNames,
307
+ class: "className",
308
+ "stroke-width": "strokeWidth",
309
+ "stroke-linecap": "strokeLinecap",
310
+ "stroke-linejoin": "strokeLinejoin",
311
+ "vector-effect": "vectorEffect"
312
+ }
313
+ });
314
+ }
315
+
316
+ // ../../node_modules/lucide-react/dist/esm/shared/src/utils/hasA11yProp.mjs
317
+ var hasA11yProp = (props) => {
318
+ for (const prop in props) {
319
+ if (prop.startsWith("aria-") || prop === "role" || prop === "title") {
320
+ return true;
321
+ }
322
+ }
323
+ return false;
324
+ };
325
+
326
+ // ../../node_modules/lucide-react/dist/esm/context.mjs
327
+ import { createContext as createContext2, useContext as useContext2, useMemo, createElement } from "react";
328
+ var LucideContext = createContext2({});
329
+ var useLucideContext = () => useContext2(LucideContext);
330
+
331
+ // ../../node_modules/lucide-react/dist/esm/Icon.mjs
332
+ var Icon = forwardRef(
333
+ ({
334
+ color,
335
+ size,
336
+ width,
337
+ height,
338
+ strokeWidth,
339
+ absoluteStrokeWidth,
340
+ nonScalingStroke,
341
+ className = "",
342
+ children,
343
+ iconNode = [],
344
+ icon = {
345
+ node: iconNode,
346
+ aliases: [],
347
+ size: 24
348
+ },
349
+ ...rest
350
+ }, ref) => {
351
+ const {
352
+ size: contextSize = 24,
353
+ strokeWidth: contextStrokeWidth = 2,
354
+ absoluteStrokeWidth: contextAbsoluteStrokeWidth = false,
355
+ nonScalingStroke: contextNonScalingStroke = false,
356
+ color: contextColor = "currentColor",
357
+ className: contextClass = ""
358
+ } = useLucideContext() ?? {};
359
+ const hasAccessibleProp = Boolean(children) || hasA11yProp(rest);
360
+ const [name, svgAttributes, builtIconNode = []] = buildLucideIconForReact(icon, {
361
+ color: color ?? contextColor,
362
+ width: width ?? size ?? contextSize,
363
+ height: height ?? size ?? contextSize,
364
+ strokeWidth: strokeWidth ?? contextStrokeWidth,
365
+ absoluteStrokeWidth: absoluteStrokeWidth ?? contextAbsoluteStrokeWidth,
366
+ nonScalingStroke: nonScalingStroke ?? contextNonScalingStroke,
367
+ className: mergeClasses(contextClass, className),
368
+ hasA11yProp: hasAccessibleProp,
369
+ attributes: rest
370
+ });
371
+ return createElement2(
372
+ name,
373
+ {
374
+ ref,
375
+ ...svgAttributes
376
+ },
377
+ [
378
+ ...builtIconNode.map(([tag, attrs]) => createElement2(tag, attrs)),
379
+ ...Array.isArray(children) ? children : [children]
380
+ ]
381
+ );
382
+ }
383
+ );
384
+
385
+ // ../../node_modules/lucide-react/dist/esm/createLucideIcon.mjs
386
+ function createLucideIcon(iconDataOrName, iconNode = [], aliases = []) {
387
+ const iconData = typeof iconDataOrName === "string" ? toLucideIconData(iconDataOrName, iconNode, aliases) : iconDataOrName;
388
+ const Component = forwardRef2(
389
+ ({ className, ...props }, ref) => createElement3(Icon, {
390
+ ref,
391
+ icon: iconData,
392
+ className,
393
+ ...props
394
+ })
395
+ );
396
+ if (iconData.name) {
397
+ Component.displayName = toPascalCase(iconData.name);
398
+ }
399
+ return Component;
400
+ }
401
+
402
+ // ../../node_modules/lucide-react/dist/esm/icons/activity.mjs
403
+ var __iconData = {
404
+ name: "activity",
405
+ size: 24,
406
+ node: [
407
+ [
408
+ "path",
409
+ {
410
+ d: "M22 12h-2.48a2 2 0 0 0-1.93 1.46l-2.35 8.36a.25.25 0 0 1-.48 0L9.24 2.18a.25.25 0 0 0-.48 0l-2.35 8.36A2 2 0 0 1 4.49 12H2",
411
+ key: "169zse"
412
+ }
413
+ ]
414
+ ]
415
+ };
416
+ __iconData.node;
417
+ var Activity = createLucideIcon(__iconData);
418
+
419
+ // ../../node_modules/lucide-react/dist/esm/icons/app-window.mjs
420
+ var __iconData2 = {
421
+ name: "app-window",
422
+ size: 24,
423
+ node: [
424
+ ["rect", { x: "2", y: "4", width: "20", height: "16", rx: "2", key: "izxlao" }],
425
+ ["path", { d: "M10 4v4", key: "pp8u80" }],
426
+ ["path", { d: "M2 8h20", key: "d11cs7" }],
427
+ ["path", { d: "M6 4v4", key: "1svtjw" }]
428
+ ]
429
+ };
430
+ __iconData2.node;
431
+ var AppWindow = createLucideIcon(__iconData2);
432
+
433
+ // ../../node_modules/lucide-react/dist/esm/icons/arrow-down.mjs
434
+ var __iconData3 = {
435
+ name: "arrow-down",
436
+ size: 24,
437
+ node: [
438
+ ["path", { d: "M12 5v14", key: "s699le" }],
439
+ ["path", { d: "m19 12-7 7-7-7", key: "1idqje" }]
440
+ ]
441
+ };
442
+ __iconData3.node;
443
+ var ArrowDown = createLucideIcon(__iconData3);
444
+
445
+ // ../../node_modules/lucide-react/dist/esm/icons/arrow-up-right.mjs
446
+ var __iconData4 = {
447
+ name: "arrow-up-right",
448
+ size: 24,
449
+ node: [
450
+ ["path", { d: "M7 7h10v10", key: "1tivn9" }],
451
+ ["path", { d: "M7 17 17 7", key: "1vkiza" }]
452
+ ]
453
+ };
454
+ __iconData4.node;
455
+ var ArrowUpRight = createLucideIcon(__iconData4);
456
+
457
+ // ../../node_modules/lucide-react/dist/esm/icons/arrow-up.mjs
458
+ var __iconData5 = {
459
+ name: "arrow-up",
460
+ size: 24,
461
+ node: [
462
+ ["path", { d: "m5 12 7-7 7 7", key: "hav0vg" }],
463
+ ["path", { d: "M12 19V5", key: "x0mq9r" }]
464
+ ]
465
+ };
466
+ __iconData5.node;
467
+ var ArrowUp = createLucideIcon(__iconData5);
468
+
469
+ // ../../node_modules/lucide-react/dist/esm/icons/book-open.mjs
470
+ var __iconData6 = {
471
+ name: "book-open",
472
+ size: 24,
473
+ node: [
474
+ ["path", { d: "M12 5v16", key: "1f6ucr" }],
475
+ [
476
+ "path",
477
+ {
478
+ d: "M20.001 19A2 2 0 0022 17V5a2 2 0 00-1.999-2L16 3.002A5 5 0 0012 5a5 5 0 00-4-2H4a2 2 0 00-2 2v12a2 2 0 001.999 2H8a5 5 0 014 2 5 5 0 014-2z",
479
+ key: "1fyvmf"
480
+ }
481
+ ]
482
+ ]
483
+ };
484
+ __iconData6.node;
485
+ var BookOpen = createLucideIcon(__iconData6);
486
+
487
+ // ../../node_modules/lucide-react/dist/esm/icons/check.mjs
488
+ var __iconData7 = {
489
+ name: "check",
490
+ size: 24,
491
+ node: [["path", { d: "M20 6 9 17l-5-5", key: "1gmf2c" }]]
492
+ };
493
+ __iconData7.node;
494
+ var Check = createLucideIcon(__iconData7);
495
+
496
+ // ../../node_modules/lucide-react/dist/esm/icons/chevron-down.mjs
497
+ var __iconData8 = {
498
+ name: "chevron-down",
499
+ size: 24,
500
+ node: [["path", { d: "m6 9 6 6 6-6", key: "qrunsl" }]]
501
+ };
502
+ __iconData8.node;
503
+ var ChevronDown = createLucideIcon(__iconData8);
504
+
505
+ // ../../node_modules/lucide-react/dist/esm/icons/chevron-right.mjs
506
+ var __iconData9 = {
507
+ name: "chevron-right",
508
+ size: 24,
509
+ node: [["path", { d: "m9 18 6-6-6-6", key: "mthhwq" }]]
510
+ };
511
+ __iconData9.node;
512
+ var ChevronRight = createLucideIcon(__iconData9);
513
+
514
+ // ../../node_modules/lucide-react/dist/esm/icons/circle-check.mjs
515
+ var __iconData10 = {
516
+ name: "circle-check",
517
+ size: 24,
518
+ node: [
519
+ ["circle", { cx: "12", cy: "12", r: "10", key: "1mglay" }],
520
+ ["path", { d: "m16 9-5.5 5.5L8 12", key: "xofnsj" }]
521
+ ],
522
+ aliases: ["check-circle-2"]
523
+ };
524
+ __iconData10.node;
525
+ var CircleCheck = createLucideIcon(__iconData10);
526
+
527
+ // ../../node_modules/lucide-react/dist/esm/icons/circle-slash.mjs
528
+ var __iconData11 = {
529
+ name: "circle-slash",
530
+ size: 24,
531
+ node: [
532
+ ["circle", { cx: "12", cy: "12", r: "10", key: "1mglay" }],
533
+ ["line", { x1: "9", x2: "15", y1: "15", y2: "9", key: "1dfufj" }]
534
+ ]
535
+ };
536
+ __iconData11.node;
537
+ var CircleSlash = createLucideIcon(__iconData11);
538
+
539
+ // ../../node_modules/lucide-react/dist/esm/icons/circle-x.mjs
540
+ var __iconData12 = {
541
+ name: "circle-x",
542
+ size: 24,
543
+ node: [
544
+ ["circle", { cx: "12", cy: "12", r: "10", key: "1mglay" }],
545
+ ["path", { d: "m15 9-6 6", key: "1uzhvr" }],
546
+ ["path", { d: "m9 9 6 6", key: "z0biqf" }]
547
+ ],
548
+ aliases: ["x-circle"]
549
+ };
550
+ __iconData12.node;
551
+ var CircleX = createLucideIcon(__iconData12);
552
+
553
+ // ../../node_modules/lucide-react/dist/esm/icons/clock.mjs
554
+ var __iconData13 = {
555
+ name: "clock",
556
+ size: 24,
557
+ node: [
558
+ ["circle", { cx: "12", cy: "12", r: "10", key: "1mglay" }],
559
+ ["path", { d: "M12 6v6l4 2", key: "mmk7yg" }]
560
+ ]
561
+ };
562
+ __iconData13.node;
563
+ var Clock = createLucideIcon(__iconData13);
564
+
565
+ // ../../node_modules/lucide-react/dist/esm/icons/coins.mjs
566
+ var __iconData14 = {
567
+ name: "coins",
568
+ size: 24,
569
+ node: [
570
+ ["path", { d: "M13.744 17.736a6 6 0 1 1-7.48-7.48", key: "bq4yh3" }],
571
+ ["path", { d: "M15 6h1v4", key: "11y1tn" }],
572
+ ["path", { d: "m6.134 14.768.866-.5 2 3.464", key: "17snzx" }],
573
+ ["circle", { cx: "16", cy: "8", r: "6", key: "14bfc9" }]
574
+ ]
575
+ };
576
+ __iconData14.node;
577
+ var Coins = createLucideIcon(__iconData14);
578
+
579
+ // ../../node_modules/lucide-react/dist/esm/icons/copy.mjs
580
+ var __iconData15 = {
581
+ name: "copy",
582
+ size: 24,
583
+ node: [
584
+ ["rect", { width: "14", height: "14", x: "8", y: "8", rx: "2", ry: "2", key: "17jyea" }],
585
+ ["path", { d: "M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2", key: "zix9uf" }]
586
+ ]
587
+ };
588
+ __iconData15.node;
589
+ var Copy = createLucideIcon(__iconData15);
590
+
591
+ // ../../node_modules/lucide-react/dist/esm/icons/cpu.mjs
592
+ var __iconData16 = {
593
+ name: "cpu",
594
+ size: 24,
595
+ node: [
596
+ ["path", { d: "M12 20v2", key: "1lh1kg" }],
597
+ ["path", { d: "M12 2v2", key: "tus03m" }],
598
+ ["path", { d: "M17 20v2", key: "1rnc9c" }],
599
+ ["path", { d: "M17 2v2", key: "11trls" }],
600
+ ["path", { d: "M2 12h2", key: "1t8f8n" }],
601
+ ["path", { d: "M2 17h2", key: "7oei6x" }],
602
+ ["path", { d: "M2 7h2", key: "asdhe0" }],
603
+ ["path", { d: "M20 12h2", key: "1q8mjw" }],
604
+ ["path", { d: "M20 17h2", key: "1fpfkl" }],
605
+ ["path", { d: "M20 7h2", key: "1o8tra" }],
606
+ ["path", { d: "M7 20v2", key: "4gnj0m" }],
607
+ ["path", { d: "M7 2v2", key: "1i4yhu" }],
608
+ ["rect", { x: "4", y: "4", width: "16", height: "16", rx: "2", key: "1vbyd7" }],
609
+ ["rect", { x: "8", y: "8", width: "8", height: "8", rx: "1", key: "z9xiuo" }]
610
+ ]
611
+ };
612
+ __iconData16.node;
613
+ var Cpu = createLucideIcon(__iconData16);
614
+
615
+ // ../../node_modules/lucide-react/dist/esm/icons/crosshair.mjs
616
+ var __iconData17 = {
617
+ name: "crosshair",
618
+ size: 24,
619
+ node: [
620
+ ["circle", { cx: "12", cy: "12", r: "10", key: "1mglay" }],
621
+ ["line", { x1: "22", x2: "18", y1: "12", y2: "12", key: "l9bcsi" }],
622
+ ["line", { x1: "6", x2: "2", y1: "12", y2: "12", key: "13hhkx" }],
623
+ ["line", { x1: "12", x2: "12", y1: "6", y2: "2", key: "10w3f3" }],
624
+ ["line", { x1: "12", x2: "12", y1: "22", y2: "18", key: "15g9kq" }]
625
+ ]
626
+ };
627
+ __iconData17.node;
628
+ var Crosshair = createLucideIcon(__iconData17);
629
+
630
+ // ../../node_modules/lucide-react/dist/esm/icons/external-link.mjs
631
+ var __iconData18 = {
632
+ name: "external-link",
633
+ size: 24,
634
+ node: [
635
+ ["path", { d: "M15 3h6v6", key: "1q9fwt" }],
636
+ ["path", { d: "M10 14 21 3", key: "gplh6r" }],
637
+ ["path", { d: "M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6", key: "a6xqqp" }]
638
+ ]
639
+ };
640
+ __iconData18.node;
641
+ var ExternalLink = createLucideIcon(__iconData18);
642
+
643
+ // ../../node_modules/lucide-react/dist/esm/icons/file-pen-line.mjs
644
+ var __iconData19 = {
645
+ name: "file-pen-line",
646
+ size: 24,
647
+ node: [
648
+ [
649
+ "path",
650
+ {
651
+ d: "M14.364 13.634a2 2 0 0 0-.506.854l-.837 2.87a.5.5 0 0 0 .62.62l2.87-.837a2 2 0 0 0 .854-.506l4.013-4.009a1 1 0 0 0-3.004-3.004z",
652
+ key: "ukzhwg"
653
+ }
654
+ ],
655
+ ["path", { d: "M14.487 7.858A1 1 0 0 1 14 7V2", key: "1klhew" }],
656
+ [
657
+ "path",
658
+ {
659
+ d: "M20 19.645V20a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.704.706l2.516 2.516",
660
+ key: "rxaxab"
661
+ }
662
+ ],
663
+ ["path", { d: "M8 18h1", key: "13wk12" }]
664
+ ],
665
+ aliases: ["file-signature"]
666
+ };
667
+ __iconData19.node;
668
+ var FilePenLine = createLucideIcon(__iconData19);
669
+
670
+ // ../../node_modules/lucide-react/dist/esm/icons/file-spreadsheet.mjs
671
+ var __iconData20 = {
672
+ name: "file-spreadsheet",
673
+ size: 24,
674
+ node: [
675
+ [
676
+ "path",
677
+ {
678
+ d: "M6 22a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.704.706l3.588 3.588A2.4 2.4 0 0 1 20 8v12a2 2 0 0 1-2 2z",
679
+ key: "1oefj6"
680
+ }
681
+ ],
682
+ ["path", { d: "M14 2v5a1 1 0 0 0 1 1h5", key: "wfsgrz" }],
683
+ ["path", { d: "M8 13h2", key: "yr2amv" }],
684
+ ["path", { d: "M14 13h2", key: "un5t4a" }],
685
+ ["path", { d: "M8 17h2", key: "2yhykz" }],
686
+ ["path", { d: "M14 17h2", key: "10kma7" }]
687
+ ]
688
+ };
689
+ __iconData20.node;
690
+ var FileSpreadsheet = createLucideIcon(__iconData20);
691
+
692
+ // ../../node_modules/lucide-react/dist/esm/icons/file-text.mjs
693
+ var __iconData21 = {
694
+ name: "file-text",
695
+ size: 24,
696
+ node: [
697
+ [
698
+ "path",
699
+ {
700
+ d: "M6 22a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.704.706l3.588 3.588A2.4 2.4 0 0 1 20 8v12a2 2 0 0 1-2 2z",
701
+ key: "1oefj6"
702
+ }
703
+ ],
704
+ ["path", { d: "M14 2v5a1 1 0 0 0 1 1h5", key: "wfsgrz" }],
705
+ ["path", { d: "M10 9H8", key: "b1mrlr" }],
706
+ ["path", { d: "M16 13H8", key: "t4e002" }],
707
+ ["path", { d: "M16 17H8", key: "z1uh3a" }]
708
+ ]
709
+ };
710
+ __iconData21.node;
711
+ var FileText = createLucideIcon(__iconData21);
712
+
713
+ // ../../node_modules/lucide-react/dist/esm/icons/folder.mjs
714
+ var __iconData22 = {
715
+ name: "folder",
716
+ size: 24,
717
+ node: [
718
+ [
719
+ "path",
720
+ {
721
+ d: "M20 20a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2h-7.9a2 2 0 0 1-1.69-.9L9.6 3.9A2 2 0 0 0 7.93 3H4a2 2 0 0 0-2 2v13a2 2 0 0 0 2 2Z",
722
+ key: "1kt360"
723
+ }
724
+ ]
725
+ ]
726
+ };
727
+ __iconData22.node;
728
+ var Folder = createLucideIcon(__iconData22);
729
+
730
+ // ../../node_modules/lucide-react/dist/esm/icons/gauge.mjs
731
+ var __iconData23 = {
732
+ name: "gauge",
733
+ size: 24,
734
+ node: [
735
+ ["path", { d: "m12 14 4-4", key: "9kzdfg" }],
736
+ ["path", { d: "M3.34 19a10 10 0 1 1 17.32 0", key: "19p75a" }]
737
+ ]
738
+ };
739
+ __iconData23.node;
740
+ var Gauge = createLucideIcon(__iconData23);
741
+
742
+ // ../../node_modules/lucide-react/dist/esm/icons/globe.mjs
743
+ var __iconData24 = {
744
+ name: "globe",
745
+ size: 24,
746
+ node: [
747
+ ["circle", { cx: "12", cy: "12", r: "10", key: "1mglay" }],
748
+ ["path", { d: "M12 2a14.5 14.5 0 0 0 0 20 14.5 14.5 0 0 0 0-20", key: "13o1zl" }],
749
+ ["path", { d: "M2 12h20", key: "9i4pu4" }]
750
+ ]
751
+ };
752
+ __iconData24.node;
753
+ var Globe = createLucideIcon(__iconData24);
754
+
755
+ // ../../node_modules/lucide-react/dist/esm/icons/image.mjs
756
+ var __iconData25 = {
757
+ name: "image",
758
+ size: 24,
759
+ node: [
760
+ ["rect", { width: "18", height: "18", x: "3", y: "3", rx: "2", ry: "2", key: "1m3agn" }],
761
+ ["circle", { cx: "9", cy: "9", r: "2", key: "af1f0g" }],
762
+ ["path", { d: "m21 15-3.086-3.086a2 2 0 0 0-2.828 0L6 21", key: "1xmnt7" }]
763
+ ]
764
+ };
765
+ __iconData25.node;
766
+ var Image = createLucideIcon(__iconData25);
767
+
768
+ // ../../node_modules/lucide-react/dist/esm/icons/inbox.mjs
769
+ var __iconData26 = {
770
+ name: "inbox",
771
+ size: 24,
772
+ node: [
773
+ ["polyline", { points: "22 12 16 12 14 15 10 15 8 12 2 12", key: "o97t9d" }],
774
+ [
775
+ "path",
776
+ {
777
+ d: "M5.45 5.11 2 12v6a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2v-6l-3.45-6.89A2 2 0 0 0 16.76 4H7.24a2 2 0 0 0-1.79 1.11z",
778
+ key: "oot6mr"
779
+ }
780
+ ]
781
+ ]
782
+ };
783
+ __iconData26.node;
784
+ var Inbox = createLucideIcon(__iconData26);
785
+
786
+ // ../../node_modules/lucide-react/dist/esm/icons/list-checks.mjs
787
+ var __iconData27 = {
788
+ name: "list-checks",
789
+ size: 24,
790
+ node: [
791
+ ["path", { d: "M13 5h8", key: "a7qcls" }],
792
+ ["path", { d: "M13 12h8", key: "h98zly" }],
793
+ ["path", { d: "M13 19h8", key: "c3s6r1" }],
794
+ ["path", { d: "m3 17 2 2 4-4", key: "1jhpwq" }],
795
+ ["path", { d: "m3 7 2 2 4-4", key: "1obspn" }]
796
+ ]
797
+ };
798
+ __iconData27.node;
799
+ var ListChecks = createLucideIcon(__iconData27);
800
+
801
+ // ../../node_modules/lucide-react/dist/esm/icons/loader-circle.mjs
802
+ var __iconData28 = {
803
+ name: "loader-circle",
804
+ size: 24,
805
+ node: [["path", { d: "M21 12a9 9 0 1 1-6.219-8.56", key: "13zald" }]],
806
+ aliases: ["loader-2"]
807
+ };
808
+ __iconData28.node;
809
+ var LoaderCircle = createLucideIcon(__iconData28);
810
+
811
+ // ../../node_modules/lucide-react/dist/esm/icons/mic.mjs
812
+ var __iconData29 = {
813
+ name: "mic",
814
+ size: 24,
815
+ node: [
816
+ ["path", { d: "M12 19v3", key: "npa21l" }],
817
+ ["path", { d: "M19 10v2a7 7 0 0 1-14 0v-2", key: "1vc78b" }],
818
+ ["rect", { x: "9", y: "2", width: "6", height: "13", rx: "3", key: "s6n7sd" }]
819
+ ]
820
+ };
821
+ __iconData29.node;
822
+ var Mic = createLucideIcon(__iconData29);
823
+
824
+ // ../../node_modules/lucide-react/dist/esm/icons/octagon-x.mjs
825
+ var __iconData30 = {
826
+ name: "octagon-x",
827
+ size: 24,
828
+ node: [
829
+ ["path", { d: "m15 9-6 6", key: "1uzhvr" }],
830
+ [
831
+ "path",
832
+ {
833
+ d: "M2.586 16.726A2 2 0 0 1 2 15.312V8.688a2 2 0 0 1 .586-1.414l4.688-4.688A2 2 0 0 1 8.688 2h6.624a2 2 0 0 1 1.414.586l4.688 4.688A2 2 0 0 1 22 8.688v6.624a2 2 0 0 1-.586 1.414l-4.688 4.688a2 2 0 0 1-1.414.586H8.688a2 2 0 0 1-1.414-.586z",
834
+ key: "2d38gg"
835
+ }
836
+ ],
837
+ ["path", { d: "m9 9 6 6", key: "z0biqf" }]
838
+ ],
839
+ aliases: ["x-octagon"]
840
+ };
841
+ __iconData30.node;
842
+ var OctagonX = createLucideIcon(__iconData30);
843
+
844
+ // ../../node_modules/lucide-react/dist/esm/icons/paperclip.mjs
845
+ var __iconData31 = {
846
+ name: "paperclip",
847
+ size: 24,
848
+ node: [
849
+ [
850
+ "path",
851
+ {
852
+ d: "m16 6-8.414 8.586a2 2 0 0 0 2.829 2.829l8.414-8.586a4 4 0 1 0-5.657-5.657l-8.379 8.551a6 6 0 1 0 8.485 8.485l8.379-8.551",
853
+ key: "1miecu"
854
+ }
855
+ ]
856
+ ]
857
+ };
858
+ __iconData31.node;
859
+ var Paperclip = createLucideIcon(__iconData31);
860
+
861
+ // ../../node_modules/lucide-react/dist/esm/icons/rotate-ccw.mjs
862
+ var __iconData32 = {
863
+ name: "rotate-ccw",
864
+ size: 24,
865
+ node: [
866
+ ["path", { d: "M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8", key: "1357e3" }],
867
+ ["path", { d: "M3 3v5h5", key: "1xhq8a" }]
868
+ ]
869
+ };
870
+ __iconData32.node;
871
+ var RotateCcw = createLucideIcon(__iconData32);
872
+
873
+ // ../../node_modules/lucide-react/dist/esm/icons/search.mjs
874
+ var __iconData33 = {
875
+ name: "search",
876
+ size: 24,
877
+ node: [
878
+ ["path", { d: "m21 21-4.34-4.34", key: "14j7rj" }],
879
+ ["circle", { cx: "11", cy: "11", r: "8", key: "4ej97u" }]
880
+ ]
881
+ };
882
+ __iconData33.node;
883
+ var Search = createLucideIcon(__iconData33);
884
+
885
+ // ../../node_modules/lucide-react/dist/esm/icons/send.mjs
886
+ var __iconData34 = {
887
+ name: "send",
888
+ size: 24,
889
+ node: [
890
+ [
891
+ "path",
892
+ {
893
+ d: "M14.536 21.686a.5.5 0 0 0 .937-.024l6.5-19a.496.496 0 0 0-.635-.635l-19 6.5a.5.5 0 0 0-.024.937l7.93 3.18a2 2 0 0 1 1.112 1.11z",
894
+ key: "1ffxy3"
895
+ }
896
+ ],
897
+ ["path", { d: "m21.854 2.147-10.94 10.939", key: "12cjpa" }]
898
+ ]
899
+ };
900
+ __iconData34.node;
901
+ var Send = createLucideIcon(__iconData34);
902
+
903
+ // ../../node_modules/lucide-react/dist/esm/icons/shield-alert.mjs
904
+ var __iconData35 = {
905
+ name: "shield-alert",
906
+ size: 24,
907
+ node: [
908
+ [
909
+ "path",
910
+ {
911
+ d: "M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z",
912
+ key: "oel41y"
913
+ }
914
+ ],
915
+ ["path", { d: "M12 8v4", key: "1got3b" }],
916
+ ["path", { d: "M12 16h.01", key: "1drbdi" }]
917
+ ]
918
+ };
919
+ __iconData35.node;
920
+ var ShieldAlert = createLucideIcon(__iconData35);
921
+
922
+ // ../../node_modules/lucide-react/dist/esm/icons/square.mjs
923
+ var __iconData36 = {
924
+ name: "square",
925
+ size: 24,
926
+ node: [["rect", { width: "18", height: "18", x: "3", y: "3", rx: "2", key: "afitv7" }]]
927
+ };
928
+ __iconData36.node;
929
+ var Square = createLucideIcon(__iconData36);
930
+
931
+ // ../../node_modules/lucide-react/dist/esm/icons/users-round.mjs
932
+ var __iconData37 = {
933
+ name: "users-round",
934
+ size: 24,
935
+ node: [
936
+ ["path", { d: "M18 21a8 8 0 0 0-16 0", key: "3ypg7q" }],
937
+ ["circle", { cx: "10", cy: "8", r: "5", key: "o932ke" }],
938
+ ["path", { d: "M22 20c0-3.37-2-6.5-4-8a5 5 0 0 0-.45-8.3", key: "10s06x" }]
939
+ ],
940
+ aliases: ["users-2"]
941
+ };
942
+ __iconData37.node;
943
+ var UsersRound = createLucideIcon(__iconData37);
944
+
945
+ // ../../node_modules/lucide-react/dist/esm/icons/wrench.mjs
946
+ var __iconData38 = {
947
+ name: "wrench",
948
+ size: 24,
949
+ node: [
950
+ [
951
+ "path",
952
+ {
953
+ d: "M14.7 6.3a1 1 0 0 0 0 1.4l1.6 1.6a1 1 0 0 0 1.4 0l3.106-3.105c.32-.322.863-.22.983.218a6 6 0 0 1-8.259 7.057l-7.91 7.91a1 1 0 0 1-2.999-3l7.91-7.91a6 6 0 0 1 7.057-8.259c.438.12.54.662.219.984z",
954
+ key: "1ngwbx"
955
+ }
956
+ ]
957
+ ]
958
+ };
959
+ __iconData38.node;
960
+ var Wrench = createLucideIcon(__iconData38);
961
+
962
+ // ../../node_modules/lucide-react/dist/esm/icons/x.mjs
963
+ var __iconData39 = {
964
+ name: "x",
965
+ size: 24,
966
+ node: [
967
+ ["path", { d: "M18 6 6 18", key: "1bl5f8" }],
968
+ ["path", { d: "m6 6 12 12", key: "d8bk6v" }]
969
+ ]
970
+ };
971
+ __iconData39.node;
972
+ var X = createLucideIcon(__iconData39);
973
+
974
+ // src/react/Chips.tsx
975
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
976
+ function ReferenceChips({ references, onRemove, onActivate }) {
977
+ const { strings: t } = usePiloto();
978
+ if (!references.length) return null;
979
+ const pointed = references.filter((r) => r.prompt);
980
+ const plain = references.filter((r) => !r.prompt);
981
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
982
+ pointed.map((r) => /* @__PURE__ */ jsx("div", { className: "mb-2 flex", children: /* @__PURE__ */ jsxs("span", { className: "inline-flex max-w-full items-center gap-1.5 rounded-full border border-brand-500/40 bg-brand-500/10 py-1 pl-2.5 pr-1 text-xs text-text-primary", children: [
983
+ /* @__PURE__ */ jsx(Crosshair, { size: 13, className: "shrink-0 text-brand-500" }),
984
+ /* @__PURE__ */ jsx("span", { className: "shrink-0 font-semibold", children: r.label }),
985
+ r.hint && /* @__PURE__ */ jsxs("span", { className: "truncate text-text-secondary", children: [
986
+ "\xAB",
987
+ r.hint,
988
+ "\xBB"
989
+ ] }),
990
+ /* @__PURE__ */ jsx(
991
+ "button",
992
+ {
993
+ type: "button",
994
+ onClick: () => onRemove(r.id),
995
+ "aria-label": t.removeReference,
996
+ className: "grid size-5 shrink-0 cursor-pointer place-items-center rounded-full text-text-tertiary hover:bg-background-secondary hover:text-text-primary",
997
+ children: /* @__PURE__ */ jsx(X, { size: 12 })
998
+ }
999
+ )
1000
+ ] }) }, r.id)),
1001
+ plain.length > 0 && /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-1.5", children: plain.map((r) => /* @__PURE__ */ jsxs("span", { className: "inline-flex items-center gap-1 rounded-full border border-border-primary bg-background-secondary py-0.5 pl-2 pr-1 text-xs text-text-primary", children: [
1002
+ /* @__PURE__ */ jsx("button", { type: "button", onClick: () => onActivate?.(r), className: "underline-offset-2 hover:underline", children: r.label }),
1003
+ /* @__PURE__ */ jsx(
1004
+ "button",
1005
+ {
1006
+ type: "button",
1007
+ onClick: () => onRemove(r.id),
1008
+ "aria-label": t.removeReference,
1009
+ className: "flex h-4 w-4 items-center justify-center rounded-full text-text-tertiary hover:bg-background-tertiary hover:text-text-primary",
1010
+ children: /* @__PURE__ */ jsx(X, { className: "h-3 w-3" })
1011
+ }
1012
+ )
1013
+ ] }, r.id)) })
1014
+ ] });
1015
+ }
1016
+ function Suggestions({ items, onPick, onPrefill, disabled }) {
1017
+ if (!items.length) return null;
1018
+ return /* @__PURE__ */ jsx("div", { className: "mt-4 flex flex-wrap justify-center gap-2", children: items.map((c) => /* @__PURE__ */ jsx(
1019
+ "button",
1020
+ {
1021
+ type: "button",
1022
+ onClick: () => onPrefill && /:\s*$/.test(c) ? onPrefill(c) : onPick(c),
1023
+ disabled,
1024
+ className: "gc-chip rounded-full bg-irongray/10 px-3.5 py-1.5 text-xs font-medium text-metal transition-colors hover:bg-irongray/20 hover:text-dark disabled:opacity-40",
1025
+ children: c
1026
+ },
1027
+ c
1028
+ )) });
1029
+ }
1030
+
1031
+ // src/react/Composer.tsx
1032
+ import { useCallback, useEffect, useImperativeHandle, useRef, useState } from "react";
1033
+ import { Fragment as Fragment2, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
1034
+ var MAX_HEIGHT = 240;
1035
+ var BY_EXTENSION = {
1036
+ png: "image/png",
1037
+ jpg: "image/jpeg",
1038
+ jpeg: "image/jpeg",
1039
+ gif: "image/gif",
1040
+ webp: "image/webp",
1041
+ heic: "image/heic",
1042
+ pdf: "application/pdf",
1043
+ csv: "text/csv",
1044
+ txt: "text/plain",
1045
+ md: "text/markdown",
1046
+ json: "application/json"
1047
+ };
1048
+ function mimeOf(file) {
1049
+ if (file.type) return file.type;
1050
+ const ext = (file.name.match(/\.([A-Za-z0-9]+)$/)?.[1] || "").toLowerCase();
1051
+ return BY_EXTENSION[ext] ?? "application/octet-stream";
1052
+ }
1053
+ function accepts(accept, name, mime) {
1054
+ return accept.split(",").map((x) => x.trim().toLowerCase()).filter(Boolean).some((rule) => rule.startsWith(".") ? name.toLowerCase().endsWith(rule) : rule.endsWith("/*") ? mime.startsWith(rule.slice(0, -1)) : mime === rule);
1055
+ }
1056
+ var isText = (mime) => mime.startsWith("text/") || mime === "application/json" || mime.endsWith("+json") || mime.endsWith("+xml");
1057
+ function shortSize(bytes) {
1058
+ if (bytes < 1024) return `${bytes} B`;
1059
+ if (bytes < 1024 * 1024) return `${Math.round(bytes / 1024)} KB`;
1060
+ return `${(bytes / 1024 / 1024).toFixed(1)} MB`;
1061
+ }
1062
+ function readInline(file) {
1063
+ return new Promise((resolve, reject) => {
1064
+ const fr = new FileReader();
1065
+ fr.onload = () => {
1066
+ const result = String(fr.result);
1067
+ const comma = result.indexOf(",");
1068
+ resolve({ name: file.name, mimeType: mimeOf(file), data: comma === -1 ? result : result.slice(comma + 1) });
1069
+ };
1070
+ fr.onerror = () => reject(fr.error);
1071
+ fr.readAsDataURL(file);
1072
+ });
1073
+ }
1074
+ function Composer({
1075
+ onSubmit,
1076
+ onStop,
1077
+ busy = false,
1078
+ canSteer = true,
1079
+ placeholder,
1080
+ initialValue = "",
1081
+ autoFocus = true,
1082
+ canSeeImages = true,
1083
+ attachments: withFiles = false,
1084
+ upload,
1085
+ transcribe,
1086
+ voiceNoteText,
1087
+ models = [],
1088
+ currentModel = null,
1089
+ onModelChange,
1090
+ references = [],
1091
+ onRemoveReference,
1092
+ onActivateReference,
1093
+ extras,
1094
+ extrasEnd,
1095
+ handleRef,
1096
+ accept,
1097
+ maxFiles = 8,
1098
+ maxFileMb = 25
1099
+ }) {
1100
+ const { strings: t } = usePiloto();
1101
+ const [value, setValue] = useState(initialValue);
1102
+ const [files, setFiles] = useState([]);
1103
+ const [dragging, setDragging] = useState(false);
1104
+ const [notice, setNotice] = useState(null);
1105
+ const [uploading, setUploading] = useState(false);
1106
+ const ref = useRef(null);
1107
+ const fileRef = useRef(null);
1108
+ const nextId = useRef(0);
1109
+ const urls = useRef(/* @__PURE__ */ new Set());
1110
+ const releaseUrl = (url) => {
1111
+ urls.current.delete(url);
1112
+ URL.revokeObjectURL(url);
1113
+ };
1114
+ useEffect(() => {
1115
+ if (!autoFocus) return;
1116
+ const id = requestAnimationFrame(() => {
1117
+ const el = ref.current;
1118
+ if (!el) return;
1119
+ el.focus({ preventScroll: true });
1120
+ el.setSelectionRange(el.value.length, el.value.length);
1121
+ });
1122
+ return () => cancelAnimationFrame(id);
1123
+ }, [autoFocus]);
1124
+ useEffect(
1125
+ () => () => {
1126
+ for (const url of urls.current) URL.revokeObjectURL(url);
1127
+ urls.current.clear();
1128
+ },
1129
+ []
1130
+ );
1131
+ useEffect(() => {
1132
+ const el = ref.current;
1133
+ if (!el) return;
1134
+ if (!value) {
1135
+ el.style.height = "";
1136
+ return;
1137
+ }
1138
+ el.style.height = "0px";
1139
+ el.style.height = `${Math.min(el.scrollHeight, MAX_HEIGHT)}px`;
1140
+ }, [value]);
1141
+ const addFiles = useCallback(
1142
+ (list) => {
1143
+ if (busy) return;
1144
+ const rejected = [];
1145
+ setFiles((prev) => {
1146
+ const next = [...prev];
1147
+ for (const file of Array.from(list)) {
1148
+ const mime = mimeOf(file);
1149
+ if (file.size > maxFileMb * 1024 * 1024) {
1150
+ rejected.push(t.tooBig(file.name, maxFileMb));
1151
+ continue;
1152
+ }
1153
+ if (accept && !accepts(accept, file.name, mime)) {
1154
+ rejected.push(t.cantUpload(file.name));
1155
+ continue;
1156
+ }
1157
+ if (next.length >= maxFiles) {
1158
+ rejected.push(t.tooMany(maxFiles));
1159
+ break;
1160
+ }
1161
+ if (mime.startsWith("image/") && !canSeeImages) {
1162
+ rejected.push(t.cantSeeImage(file.name));
1163
+ continue;
1164
+ }
1165
+ if (!mime.startsWith("image/") && !isText(mime) && !upload) {
1166
+ rejected.push(t.cantUpload(file.name));
1167
+ continue;
1168
+ }
1169
+ const url = URL.createObjectURL(file);
1170
+ urls.current.add(url);
1171
+ next.push({ id: ++nextId.current, name: file.name, mime, size: file.size, url, file });
1172
+ }
1173
+ return next;
1174
+ });
1175
+ setNotice(rejected.length ? rejected.join(" \xB7 ") : null);
1176
+ ref.current?.focus({ preventScroll: true });
1177
+ },
1178
+ [busy, canSeeImages, upload, maxFiles, maxFileMb, accept, t]
1179
+ );
1180
+ useEffect(() => {
1181
+ if (!withFiles) return;
1182
+ let inside = 0;
1183
+ const hasFiles = (e) => Array.from(e.dataTransfer?.types ?? []).includes("Files");
1184
+ const enter = (e) => {
1185
+ if (!hasFiles(e)) return;
1186
+ e.preventDefault();
1187
+ inside++;
1188
+ if (!busy) setDragging(true);
1189
+ };
1190
+ const over = (e) => {
1191
+ if (hasFiles(e)) e.preventDefault();
1192
+ };
1193
+ const leave = (e) => {
1194
+ if (!hasFiles(e)) return;
1195
+ inside = Math.max(0, inside - 1);
1196
+ if (inside === 0) setDragging(false);
1197
+ };
1198
+ const drop = (e) => {
1199
+ if (!hasFiles(e)) return;
1200
+ e.preventDefault();
1201
+ inside = 0;
1202
+ setDragging(false);
1203
+ if (e.dataTransfer?.files.length) addFiles(e.dataTransfer.files);
1204
+ };
1205
+ window.addEventListener("dragenter", enter);
1206
+ window.addEventListener("dragover", over);
1207
+ window.addEventListener("dragleave", leave);
1208
+ window.addEventListener("drop", drop);
1209
+ return () => {
1210
+ window.removeEventListener("dragenter", enter);
1211
+ window.removeEventListener("dragover", over);
1212
+ window.removeEventListener("dragleave", leave);
1213
+ window.removeEventListener("drop", drop);
1214
+ };
1215
+ }, [withFiles, busy, addFiles]);
1216
+ useImperativeHandle(
1217
+ handleRef,
1218
+ () => ({
1219
+ addAttachments: (items) => {
1220
+ const files2 = items.filter((x) => typeof File !== "undefined" && x instanceof File);
1221
+ const ready = items.filter((x) => !(typeof File !== "undefined" && x instanceof File));
1222
+ if (files2.length) addFiles(files2);
1223
+ if (ready.length)
1224
+ setFiles((prev) => [
1225
+ ...prev,
1226
+ ...ready.slice(0, Math.max(0, maxFiles - prev.length)).map((att) => ({
1227
+ id: ++nextId.current,
1228
+ name: att.name ?? "archivo",
1229
+ mime: att.mimeType,
1230
+ url: att.url ?? (att.data ? `data:${att.mimeType};base64,${att.data}` : ""),
1231
+ att
1232
+ }))
1233
+ ]);
1234
+ ref.current?.focus({ preventScroll: true });
1235
+ }
1236
+ }),
1237
+ [addFiles, maxFiles]
1238
+ );
1239
+ const removeFile = (id) => setFiles((prev) => {
1240
+ const out = prev.find((a) => a.id === id);
1241
+ if (out?.file) releaseUrl(out.url);
1242
+ return prev.filter((a) => a.id !== id);
1243
+ });
1244
+ const submit = async () => {
1245
+ const body = value.trim();
1246
+ if (!body && files.length === 0 && references.length === 0) return;
1247
+ if (busy && (files.length > 0 || !canSteer)) return;
1248
+ if (uploading) return;
1249
+ let atts = [];
1250
+ if (files.length) setUploading(true);
1251
+ try {
1252
+ atts = await Promise.all(
1253
+ files.map(async (a) => {
1254
+ if (a.att || !a.file) return a.att;
1255
+ const mime = a.mime;
1256
+ if (mime.startsWith("image/") || isText(mime)) return readInline(a.file);
1257
+ const up = await upload(a.file);
1258
+ return { name: a.file.name, mimeType: mime, url: up.url };
1259
+ })
1260
+ );
1261
+ } catch (e) {
1262
+ setNotice(e instanceof Error ? e.message : t.uploadFailed);
1263
+ return;
1264
+ } finally {
1265
+ setUploading(false);
1266
+ }
1267
+ onSubmit(body, atts);
1268
+ setValue("");
1269
+ setNotice(null);
1270
+ for (const a of files) if (a.file) releaseUrl(a.url);
1271
+ setFiles([]);
1272
+ };
1273
+ const [recording, setRecording] = useState(false);
1274
+ const [transcribing, setTranscribing] = useState(false);
1275
+ const [wave, setWave] = useState([]);
1276
+ const [seconds, setSeconds] = useState(0);
1277
+ const recRef = useRef(null);
1278
+ const pieces = useRef([]);
1279
+ const cancelRef = useRef(false);
1280
+ const meter = useRef(null);
1281
+ const [hasMic, setHasMic] = useState(false);
1282
+ useEffect(() => setHasMic(typeof window !== "undefined" && "MediaRecorder" in window && Boolean(navigator.mediaDevices?.getUserMedia)), []);
1283
+ const canRecord = Boolean(transcribe) && hasMic;
1284
+ const toggleRecording = async () => {
1285
+ if (recording) {
1286
+ cancelRef.current = false;
1287
+ recRef.current?.stop();
1288
+ return;
1289
+ }
1290
+ try {
1291
+ const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
1292
+ const mime = ["audio/webm;codecs=opus", "audio/webm", "audio/mp4"].find((m) => MediaRecorder.isTypeSupported(m)) ?? "";
1293
+ const rec = new MediaRecorder(stream, mime ? { mimeType: mime } : void 0);
1294
+ pieces.current = [];
1295
+ rec.ondataavailable = (e) => {
1296
+ if (e.data.size > 0) pieces.current.push(e.data);
1297
+ };
1298
+ const ctx = new AudioContext();
1299
+ const an = ctx.createAnalyser();
1300
+ an.fftSize = 512;
1301
+ ctx.createMediaStreamSource(stream).connect(an);
1302
+ const buf = new Uint8Array(an.fftSize);
1303
+ let lastTick = 0;
1304
+ const tick = (time) => {
1305
+ if (time - lastTick > 80) {
1306
+ lastTick = time;
1307
+ an.getByteTimeDomainData(buf);
1308
+ let acc = 0;
1309
+ for (let i = 0; i < buf.length; i++) {
1310
+ const v = (buf[i] - 128) / 128;
1311
+ acc += v * v;
1312
+ }
1313
+ setWave((w) => [...w.slice(-59), Math.min(1, Math.sqrt(acc / buf.length) * 4)]);
1314
+ }
1315
+ if (meter.current) meter.current.raf = requestAnimationFrame(tick);
1316
+ };
1317
+ const start = Date.now();
1318
+ meter.current = { ctx, raf: requestAnimationFrame(tick), timer: window.setInterval(() => setSeconds(Math.floor((Date.now() - start) / 1e3)), 250) };
1319
+ rec.onstop = async () => {
1320
+ stream.getTracks().forEach((tr) => tr.stop());
1321
+ if (meter.current) {
1322
+ cancelAnimationFrame(meter.current.raf);
1323
+ clearInterval(meter.current.timer);
1324
+ void meter.current.ctx.close();
1325
+ meter.current = null;
1326
+ }
1327
+ setRecording(false);
1328
+ setWave([]);
1329
+ setSeconds(0);
1330
+ if (cancelRef.current) return;
1331
+ const type = rec.mimeType || mime || "audio/webm";
1332
+ const blob = new Blob(pieces.current, { type });
1333
+ if (blob.size < 1e3) return;
1334
+ setTranscribing(true);
1335
+ try {
1336
+ const ext = type.includes("mp4") ? "m4a" : "webm";
1337
+ const name = `nota-de-voz-${(/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-")}.${ext}`;
1338
+ const [said, up] = await Promise.all([transcribe(blob), upload ? upload(new File([blob], name, { type })) : Promise.resolve(null)]);
1339
+ const text = said.trim();
1340
+ if (!text) throw new Error(t.voiceEmpty);
1341
+ const atts = up ? [{ name, mimeType: type, url: up.url }] : [];
1342
+ onSubmit(voiceNoteText ? voiceNoteText(text) : text, atts);
1343
+ setNotice(null);
1344
+ } catch (e) {
1345
+ setNotice(e instanceof Error ? e.message : t.voiceFailed);
1346
+ } finally {
1347
+ setTranscribing(false);
1348
+ }
1349
+ };
1350
+ recRef.current = rec;
1351
+ rec.start();
1352
+ setRecording(true);
1353
+ } catch {
1354
+ setNotice(t.micDenied);
1355
+ }
1356
+ };
1357
+ const canSend = Boolean(value.trim() || files.length > 0 || references.length > 0);
1358
+ return /* @__PURE__ */ jsx2("div", { className: "gc-input rounded-(--piloto-radius-input) border-(length:--piloto-border-width) border-outlines bg-(--piloto-composer-bg) shadow-(--piloto-shadow-input) transition-colors focus-within:border-brand-300", children: /* @__PURE__ */ jsxs2("div", { className: `flex flex-col gap-2 p-3 transition-shadow ${withFiles && dragging ? "rounded-2xl bg-background-secondary/40 ring-2 ring-inset ring-ring-info" : ""}`, children: [
1359
+ withFiles && dragging && /* @__PURE__ */ jsx2("div", { className: "pointer-events-none fixed inset-0 z-50 flex items-center justify-center bg-background-primary/80 p-6 backdrop-blur-sm", children: /* @__PURE__ */ jsxs2("div", { className: "flex flex-col items-center gap-2 rounded-3xl border-2 border-dashed border-brand-500 bg-background-primary px-10 py-8 text-center shadow-lg", children: [
1360
+ /* @__PURE__ */ jsx2(Paperclip, { className: "size-7 text-brand-500" }),
1361
+ /* @__PURE__ */ jsx2("p", { className: "text-base font-semibold text-text-primary", children: t.dropFiles }),
1362
+ /* @__PURE__ */ jsx2("p", { className: "text-xs text-text-secondary", children: t.dropHint })
1363
+ ] }) }),
1364
+ /* @__PURE__ */ jsx2(
1365
+ "input",
1366
+ {
1367
+ ref: fileRef,
1368
+ type: "file",
1369
+ multiple: true,
1370
+ hidden: true,
1371
+ onChange: (e) => {
1372
+ if (e.target.files) addFiles(e.target.files);
1373
+ e.target.value = "";
1374
+ }
1375
+ }
1376
+ ),
1377
+ notice && /* @__PURE__ */ jsx2("p", { className: "text-xs text-text-danger", children: notice }),
1378
+ uploading && /* @__PURE__ */ jsxs2("p", { className: "flex items-center gap-1.5 text-xs text-text-secondary", children: [
1379
+ /* @__PURE__ */ jsx2(LoaderCircle, { className: "h-3.5 w-3.5 animate-spin" }),
1380
+ files.length > 1 ? t.uploadingN(files.length) : t.uploading
1381
+ ] }),
1382
+ files.length > 0 && /* @__PURE__ */ jsx2("div", { className: "flex flex-wrap gap-2", children: files.map((a) => /* @__PURE__ */ jsxs2("div", { className: "relative h-16 w-16 overflow-hidden rounded-lg border border-border-primary bg-background-secondary", children: [
1383
+ a.mime.startsWith("image/") && a.url ? /* @__PURE__ */ jsx2("img", { src: a.url, alt: a.name, className: "h-full w-full object-cover" }) : (
1384
+ // Un PDF pintado con <img> es un recuadro roto: nombre, extensión y peso.
1385
+ /* @__PURE__ */ jsxs2("span", { className: "flex h-full w-full flex-col items-center justify-center gap-1 px-1 text-center", title: a.name, children: [
1386
+ /* @__PURE__ */ jsx2(FileText, { className: "h-4 w-4 shrink-0 text-text-tertiary" }),
1387
+ /* @__PURE__ */ jsx2("span", { className: "w-full truncate text-[9px] font-medium uppercase leading-none text-text-secondary", children: a.name.match(/\.([A-Za-z0-9]+)$/)?.[1] ?? "file" }),
1388
+ a.size !== void 0 && /* @__PURE__ */ jsx2("span", { className: "w-full truncate text-[9px] leading-none text-text-tertiary", children: shortSize(a.size) })
1389
+ ] })
1390
+ ),
1391
+ /* @__PURE__ */ jsx2(
1392
+ "button",
1393
+ {
1394
+ type: "button",
1395
+ onClick: () => removeFile(a.id),
1396
+ "aria-label": t.removeAttachment,
1397
+ className: "absolute top-0.5 right-0.5 flex h-5 w-5 items-center justify-center rounded-full bg-background-inverse/80 text-text-inverse shadow-sm transition-colors hover:bg-background-inverse",
1398
+ children: /* @__PURE__ */ jsx2(X, { className: "h-3 w-3" })
1399
+ }
1400
+ )
1401
+ ] }, a.id)) }),
1402
+ /* @__PURE__ */ jsx2(ReferenceChips, { references, onRemove: (id) => onRemoveReference?.(id), onActivate: onActivateReference }),
1403
+ recording ? (
1404
+ // Grabando: la barra sustituye al campo de texto — punto rojo, reloj, la onda y las dos salidas.
1405
+ /* @__PURE__ */ jsxs2("div", { className: "flex min-h-[24px] items-center gap-3 px-1", children: [
1406
+ /* @__PURE__ */ jsx2(
1407
+ "button",
1408
+ {
1409
+ type: "button",
1410
+ onClick: () => {
1411
+ cancelRef.current = true;
1412
+ recRef.current?.stop();
1413
+ },
1414
+ "aria-label": t.cancelVoice,
1415
+ title: t.cancelVoice,
1416
+ className: "flex h-7 w-7 shrink-0 items-center justify-center rounded-full text-text-secondary hover:bg-background-secondary hover:text-text-primary",
1417
+ children: /* @__PURE__ */ jsx2(X, { className: "h-4 w-4" })
1418
+ }
1419
+ ),
1420
+ /* @__PURE__ */ jsx2("span", { className: "h-2 w-2 shrink-0 animate-pulse rounded-full bg-red-500" }),
1421
+ /* @__PURE__ */ jsxs2("span", { className: "w-10 shrink-0 font-mono text-xs tabular-nums text-text-secondary", children: [
1422
+ Math.floor(seconds / 60),
1423
+ ":",
1424
+ String(seconds % 60).padStart(2, "0")
1425
+ ] }),
1426
+ /* @__PURE__ */ jsx2("div", { className: "flex h-6 min-w-0 flex-1 items-center gap-[2px] overflow-hidden", children: Array.from({ length: 60 }, (_, i) => wave[wave.length - 60 + i] ?? 0).map((v, i) => /* @__PURE__ */ jsx2("span", { className: "w-[3px] shrink-0 rounded-full bg-text-secondary/70", style: { height: `${Math.max(3, Math.round(v * 22))}px` } }, i)) }),
1427
+ /* @__PURE__ */ jsx2(
1428
+ "button",
1429
+ {
1430
+ type: "button",
1431
+ onClick: toggleRecording,
1432
+ "aria-label": t.stopAndSendVoice,
1433
+ title: t.send,
1434
+ className: "flex h-8 w-8 shrink-0 items-center justify-center rounded-full bg-brand-500 text-white hover:bg-brand-600",
1435
+ children: /* @__PURE__ */ jsx2(ArrowUp, { className: "h-4 w-4" })
1436
+ }
1437
+ )
1438
+ ] })
1439
+ ) : /* @__PURE__ */ jsx2(
1440
+ "textarea",
1441
+ {
1442
+ ref,
1443
+ rows: 1,
1444
+ value,
1445
+ placeholder,
1446
+ onChange: (e) => setValue(e.target.value),
1447
+ onKeyDown: (e) => {
1448
+ if (e.key === "Enter" && !e.shiftKey && !e.nativeEvent.isComposing) {
1449
+ e.preventDefault();
1450
+ void submit();
1451
+ } else if (e.key === "Backspace" && !value && references.length) {
1452
+ e.preventDefault();
1453
+ onRemoveReference?.(references[references.length - 1].id);
1454
+ }
1455
+ },
1456
+ className: "max-h-60 min-h-[24px] w-full flex-none resize-none overflow-y-auto bg-transparent px-1 text-sm leading-6 text-text-primary outline-none placeholder:text-text-tertiary"
1457
+ }
1458
+ ),
1459
+ /* @__PURE__ */ jsxs2("div", { className: "flex items-center justify-between gap-2", children: [
1460
+ /* @__PURE__ */ jsxs2("div", { className: "@container flex min-w-0 flex-1 items-center gap-1.5 overflow-hidden", children: [
1461
+ withFiles && /* @__PURE__ */ jsxs2(Fragment2, { children: [
1462
+ (!accept || accepts(accept, "x.png", "image/png")) && /* @__PURE__ */ jsx2(
1463
+ "button",
1464
+ {
1465
+ type: "button",
1466
+ onClick: () => {
1467
+ if (!fileRef.current) return;
1468
+ fileRef.current.accept = "image/*";
1469
+ fileRef.current.click();
1470
+ },
1471
+ disabled: busy || !canSeeImages || files.length >= maxFiles,
1472
+ "aria-label": canSeeImages ? t.attachImage : t.noImages,
1473
+ title: canSeeImages ? t.attachImage : t.noImages,
1474
+ className: "flex h-7 w-7 shrink-0 items-center justify-center rounded-full text-text-secondary transition-colors hover:bg-background-secondary hover:text-text-primary disabled:opacity-30",
1475
+ children: /* @__PURE__ */ jsx2(Image, { className: "h-4 w-4" })
1476
+ }
1477
+ ),
1478
+ extras,
1479
+ (!accept || !/^\s*image\/\*\s*$/.test(accept)) && /* @__PURE__ */ jsx2(
1480
+ "button",
1481
+ {
1482
+ type: "button",
1483
+ onClick: () => {
1484
+ if (!fileRef.current) return;
1485
+ fileRef.current.accept = accept ?? "";
1486
+ fileRef.current.click();
1487
+ },
1488
+ disabled: busy || files.length >= maxFiles,
1489
+ "aria-label": t.attachFile,
1490
+ title: t.attachFile,
1491
+ className: "flex h-7 w-7 shrink-0 items-center justify-center rounded-full text-text-secondary transition-colors hover:bg-background-secondary hover:text-text-primary disabled:opacity-40",
1492
+ children: /* @__PURE__ */ jsx2(Paperclip, { className: "h-4 w-4" })
1493
+ }
1494
+ )
1495
+ ] }),
1496
+ !withFiles && extras,
1497
+ extrasEnd,
1498
+ models.length > 0 && onModelChange && /* @__PURE__ */ jsx2(ModelPicker, { models, current: currentModel, onChange: onModelChange })
1499
+ ] }),
1500
+ /* @__PURE__ */ jsxs2("div", { className: "flex shrink-0 items-center gap-1.5", children: [
1501
+ canRecord && !recording && /* @__PURE__ */ jsx2(
1502
+ "button",
1503
+ {
1504
+ type: "button",
1505
+ onClick: toggleRecording,
1506
+ disabled: busy || transcribing,
1507
+ "aria-label": t.recordVoice,
1508
+ title: t.voiceNote,
1509
+ className: "flex h-8 w-8 shrink-0 items-center justify-center rounded-full text-text-secondary transition-colors hover:bg-background-secondary hover:text-text-primary disabled:opacity-40",
1510
+ children: transcribing ? /* @__PURE__ */ jsx2("span", { className: "h-3.5 w-3.5 animate-spin rounded-full border-2 border-current border-t-transparent" }) : /* @__PURE__ */ jsx2(Mic, { className: "h-4 w-4" })
1511
+ }
1512
+ ),
1513
+ /* @__PURE__ */ jsx2(
1514
+ "button",
1515
+ {
1516
+ type: "button",
1517
+ onClick: busy ? onStop : () => void submit(),
1518
+ disabled: !busy && !canSend || uploading,
1519
+ "aria-label": busy ? t.stop : uploading ? t.uploading : t.send,
1520
+ className: `gc-send flex h-8 w-8 items-center justify-center rounded-full transition-colors ${busy || canSend || uploading ? "bg-brand-500 text-white hover:bg-brand-600" : "bg-background-disabled text-text-disabled"}`,
1521
+ children: busy ? /* @__PURE__ */ jsx2(Square, { className: "h-3 w-3 fill-current" }) : uploading ? /* @__PURE__ */ jsx2(LoaderCircle, { className: "h-4 w-4 animate-spin" }) : /* @__PURE__ */ jsx2(ArrowUp, { className: "h-4 w-4" })
1522
+ }
1523
+ )
1524
+ ] })
1525
+ ] })
1526
+ ] }) });
1527
+ }
1528
+ function ModelPicker({ models, current, onChange }) {
1529
+ const { strings: t } = usePiloto();
1530
+ const [open, setOpen] = useState(false);
1531
+ const box = useRef(null);
1532
+ useEffect(() => {
1533
+ if (!open) return;
1534
+ const outside = (e) => {
1535
+ if (!box.current?.contains(e.target)) setOpen(false);
1536
+ };
1537
+ const escape = (e) => e.key === "Escape" && setOpen(false);
1538
+ document.addEventListener("mousedown", outside);
1539
+ document.addEventListener("keydown", escape);
1540
+ return () => {
1541
+ document.removeEventListener("mousedown", outside);
1542
+ document.removeEventListener("keydown", escape);
1543
+ };
1544
+ }, [open]);
1545
+ if (models.length === 0) return null;
1546
+ const active = models.find((m) => m.value === current) ?? null;
1547
+ return /* @__PURE__ */ jsxs2("div", { ref: box, className: "relative", children: [
1548
+ /* @__PURE__ */ jsxs2(
1549
+ "button",
1550
+ {
1551
+ type: "button",
1552
+ "aria-expanded": open,
1553
+ onClick: () => setOpen((v) => !v),
1554
+ className: "flex max-w-56 items-center gap-1.5 rounded-full border border-border-primary px-2.5 py-1 text-xs text-text-secondary transition-colors outline-none hover:bg-background-secondary hover:text-text-primary",
1555
+ children: [
1556
+ /* @__PURE__ */ jsx2(Cpu, { className: "h-3.5 w-3.5 shrink-0" }),
1557
+ /* @__PURE__ */ jsx2("span", { className: "truncate", children: active?.name ?? t.model }),
1558
+ /* @__PURE__ */ jsx2(ChevronDown, { className: "h-3.5 w-3.5 shrink-0 opacity-70" })
1559
+ ]
1560
+ }
1561
+ ),
1562
+ open && // Hacia ARRIBA: el selector vive pegado al borde inferior del input.
1563
+ /* @__PURE__ */ jsx2("div", { className: "absolute bottom-full left-0 z-20 mb-1 max-h-80 min-w-52 overflow-y-auto rounded-xl border border-border-primary bg-background-primary py-1 shadow-lg", children: models.map((m) => /* @__PURE__ */ jsxs2(
1564
+ "button",
1565
+ {
1566
+ type: "button",
1567
+ onClick: () => {
1568
+ onChange(m.value);
1569
+ setOpen(false);
1570
+ },
1571
+ className: "flex w-full items-center justify-between gap-3 px-3 py-1.5 text-left text-xs text-text-secondary transition-colors hover:bg-background-secondary hover:text-text-primary",
1572
+ children: [
1573
+ /* @__PURE__ */ jsx2("span", { className: "truncate", children: m.name }),
1574
+ m.value === current && /* @__PURE__ */ jsx2(Check, { className: "h-3.5 w-3.5 shrink-0 text-text-success" })
1575
+ ]
1576
+ },
1577
+ m.value
1578
+ )) })
1579
+ ] });
1580
+ }
1581
+
1582
+ // src/react/plugins.ts
1583
+ function definePlugin(plugin) {
1584
+ return plugin;
1585
+ }
1586
+ function pluginRequires(p) {
1587
+ const derived = {
1588
+ events: [...Object.keys(p.events ?? {}).filter((k) => k !== "*"), ...Object.keys(p.message?.custom ?? {})],
1589
+ state: Object.keys(p.state ?? {})
1590
+ };
1591
+ if (!p.requires) return derived;
1592
+ return { events: p.requires.events ?? [], state: p.requires.state ?? [] };
1593
+ }
1594
+ function pluginPoints(p) {
1595
+ const out = [];
1596
+ const add = (cond, name) => cond && out.push(name);
1597
+ add(p.strings, "strings");
1598
+ add(p.markdown?.transform || p.markdown?.onLinkClick, "markdown");
1599
+ add(p.vars || p.className, "branding");
1600
+ add(p.tools?.verbs, "tools.verbs");
1601
+ add(p.tools?.icons, "tools.icons");
1602
+ for (const k of Object.keys(p.tools?.render ?? {})) out.push(`tools.render[${k}]`);
1603
+ for (const k of Object.keys(p.events ?? {})) out.push(`events[${k}]`);
1604
+ for (const k of Object.keys(p.state ?? {})) out.push(`state[${k}]`);
1605
+ for (const k of Object.keys(p.markdown?.blocks ?? {})) out.push(`markdown.blocks[${k}]`);
1606
+ add(p.message?.assistantBefore, "message.assistantBefore");
1607
+ add(p.message?.user, "message.user");
1608
+ add(p.message?.assistant, "message.assistant");
1609
+ for (const k of Object.keys(p.message?.custom ?? {})) out.push(`message.custom[${k}]`);
1610
+ add(p.message?.formatUserText, "message.formatUserText");
1611
+ add(p.message?.beforeSend, "message.beforeSend");
1612
+ add(p.message?.avatar, "message.avatar");
1613
+ for (const k of Object.keys(p.markdown?.components ?? {})) out.push(`markdown.components[${k}]`);
1614
+ add(p.composer?.replace, "composer.replace");
1615
+ add(p.onHttpError, "onHttpError");
1616
+ add(p.composer?.actions, "composer.actions");
1617
+ add(p.composer?.actionsEnd, "composer.actionsEnd");
1618
+ add(p.composer?.above, "composer.above");
1619
+ add(p.composer?.below, "composer.below");
1620
+ add(p.composer?.attachments, "composer.attachments");
1621
+ add(p.header, "header");
1622
+ add(p.sidePanel, "sidePanel");
1623
+ add(p.aboveThread, "aboveThread");
1624
+ add(p.empty, "empty");
1625
+ add(p.waiting, "waiting");
1626
+ add(p.wrap, "wrap");
1627
+ add(p.onTurnStart, "onTurnStart");
1628
+ add(p.onTurnDone, "onTurnDone");
1629
+ return out;
1630
+ }
1631
+ function resolvePlugins(list = []) {
1632
+ var _a, _b;
1633
+ const r = {
1634
+ list,
1635
+ strings: {},
1636
+ verbs: {},
1637
+ icons: {},
1638
+ markdown: {},
1639
+ vars: {},
1640
+ className: "",
1641
+ toolRenders: {},
1642
+ customRenders: {},
1643
+ blockRenders: {},
1644
+ components: {},
1645
+ replacers: [],
1646
+ httpError: [],
1647
+ attachments: {},
1648
+ header: [],
1649
+ sidePanel: [],
1650
+ aboveThread: [],
1651
+ composerActions: [],
1652
+ composerAbove: [],
1653
+ composerActionsEnd: [],
1654
+ composerBelow: [],
1655
+ messageBefore: [],
1656
+ wraps: [],
1657
+ turnStart: [],
1658
+ turnDone: [],
1659
+ ghostykitStyled: /* @__PURE__ */ new Set(),
1660
+ messageUser: [],
1661
+ messageAssistant: [],
1662
+ events: {},
1663
+ state: {},
1664
+ warnings: []
1665
+ };
1666
+ const transforms = [];
1667
+ const linkHandlers = [];
1668
+ const formatters = [];
1669
+ const beforeSends = [];
1670
+ const names = /* @__PURE__ */ new Set();
1671
+ const first = (slot, key, plugin, value, point) => {
1672
+ if (slot[key]) r.warnings.push(`\xAB${plugin}\xBB y \xAB${slot[key].plugin}\xBB dibujan ${point}[${key}]: gana \xAB${slot[key].plugin}\xBB (va antes).`);
1673
+ else slot[key] = { plugin, value };
1674
+ };
1675
+ for (const p of list) {
1676
+ if (names.has(p.name)) r.warnings.push(`Hay dos plugins \xAB${p.name}\xBB: el nombre debe ser \xFAnico.`);
1677
+ names.add(p.name);
1678
+ const own = (value) => ({ plugin: p.name, value });
1679
+ Object.assign(r.strings, p.strings);
1680
+ Object.assign(r.verbs, p.tools?.verbs);
1681
+ Object.assign(r.icons, p.tools?.icons);
1682
+ Object.assign(r.vars, p.vars);
1683
+ if (p.className) r.className = `${r.className} ${p.className}`.trim();
1684
+ if (p.markdown?.transform) transforms.push(p.markdown.transform);
1685
+ if (p.markdown?.onLinkClick) linkHandlers.push(p.markdown.onLinkClick);
1686
+ if (p.message?.formatUserText) formatters.push(p.message.formatUserText);
1687
+ for (const [k, v] of Object.entries(p.tools?.render ?? {})) first(r.toolRenders, k, p.name, v, "tools.render");
1688
+ for (const [k, v] of Object.entries(p.message?.custom ?? {})) first(r.customRenders, k, p.name, v, "message.custom");
1689
+ for (const [k, v] of Object.entries(p.markdown?.blocks ?? {})) first(r.blockRenders, k, p.name, v, "markdown.blocks");
1690
+ if (p.styles === "ghostykit") r.ghostykitStyled.add(p.name);
1691
+ for (const [k, v] of Object.entries(p.markdown?.components ?? {})) first(r.components, k, p.name, v, "markdown.components");
1692
+ if (p.message?.avatar) r.avatar ? r.warnings.push(`\xAB${p.name}\xBB tambi\xE9n da message.avatar: gana \xAB${r.avatar.plugin}\xBB.`) : r.avatar = own(p.message.avatar);
1693
+ if (p.message?.beforeSend) beforeSends.push(p.message.beforeSend);
1694
+ if (p.composer?.replace) r.replacers.push(own(p.composer.replace));
1695
+ if (p.onHttpError) r.httpError.push(own(p.onHttpError));
1696
+ if (p.composer?.actionsEnd) r.composerActionsEnd.push(own(p.composer.actionsEnd));
1697
+ if (p.composer?.below) r.composerBelow.push(own(p.composer.below));
1698
+ if (p.message?.assistantBefore) r.messageBefore.push(own(p.message.assistantBefore));
1699
+ if (p.wrap) r.wraps.push(own(p.wrap));
1700
+ if (p.onTurnStart) r.turnStart.push(own(p.onTurnStart));
1701
+ if (p.onTurnDone) r.turnDone.push(own(p.onTurnDone));
1702
+ for (const key of ["upload", "transcribe", "voiceNoteText", "accept", "maxFiles", "maxBytes"]) {
1703
+ const v = p.composer?.attachments?.[key];
1704
+ if (!v) continue;
1705
+ if (r.attachments[key]) r.warnings.push(`\xAB${p.name}\xBB tambi\xE9n da composer.attachments.${key}: gana el primero.`);
1706
+ else r.attachments[key] = v;
1707
+ }
1708
+ if (p.empty) r.empty ? r.warnings.push(`\xAB${p.name}\xBB tambi\xE9n dibuja empty: gana \xAB${r.empty.plugin}\xBB.`) : r.empty = own(p.empty);
1709
+ if (p.waiting) r.waiting ? r.warnings.push(`\xAB${p.name}\xBB tambi\xE9n dibuja waiting: gana \xAB${r.waiting.plugin}\xBB.`) : r.waiting = own(p.waiting);
1710
+ if (p.header) r.header.push(own(p.header));
1711
+ if (p.sidePanel) r.sidePanel.push(own(p.sidePanel));
1712
+ if (p.aboveThread) r.aboveThread.push(own(p.aboveThread));
1713
+ if (p.composer?.actions) r.composerActions.push(own(p.composer.actions));
1714
+ if (p.composer?.above) r.composerAbove.push(own(p.composer.above));
1715
+ if (p.message?.user) r.messageUser.push(own(p.message.user));
1716
+ if (p.message?.assistant) r.messageAssistant.push(own(p.message.assistant));
1717
+ for (const [k, fn] of Object.entries(p.events ?? {})) ((_a = r.events)[k] ?? (_a[k] = [])).push(own(fn));
1718
+ for (const [k, fn] of Object.entries(p.state ?? {})) ((_b = r.state)[k] ?? (_b[k] = [])).push(own(fn));
1719
+ if (p.requires) {
1720
+ const declared = /* @__PURE__ */ new Set([...p.requires.events ?? [], ...p.requires.state ?? []]);
1721
+ const real = [...Object.keys(p.events ?? {}).filter((k) => k !== "*"), ...Object.keys(p.message?.custom ?? {}), ...Object.keys(p.state ?? {})];
1722
+ for (const k of real) if (!declared.has(k)) r.warnings.push(`\xAB${p.name}\xBB atiende \xAB${k}\xBB sin declararlo en requires.`);
1723
+ }
1724
+ }
1725
+ if (transforms.length) r.markdown.transform = (md, turn) => transforms.reduce((acc, f) => f(acc, turn), md);
1726
+ if (linkHandlers.length) r.markdown.onLinkClick = (href, ev) => linkHandlers.some((f) => f(href, ev));
1727
+ if (beforeSends.length) r.beforeSend = (t, ctx) => beforeSends.reduce((acc, f) => f(acc, ctx), t);
1728
+ if (formatters.length) r.formatUserText = (t) => formatters.reduce((acc, f) => f(acc), t);
1729
+ return r;
1730
+ }
1731
+ var BUILTIN_CUSTOM = /* @__PURE__ */ new Set([
1732
+ "ghosty.title",
1733
+ "ghosty.history",
1734
+ "ghosty.injected",
1735
+ "ghosty.tool",
1736
+ "ghosty.replace",
1737
+ "ghosty.stalled",
1738
+ "ghosty.attachments_failed"
1739
+ ]);
1740
+ function isDev() {
1741
+ try {
1742
+ return process.env.NODE_ENV !== "production";
1743
+ } catch {
1744
+ return false;
1745
+ }
1746
+ }
1747
+
1748
+ export {
1749
+ Activity,
1750
+ AppWindow,
1751
+ ArrowDown,
1752
+ ArrowUpRight,
1753
+ BookOpen,
1754
+ Check,
1755
+ ChevronRight,
1756
+ CircleCheck,
1757
+ CircleSlash,
1758
+ CircleX,
1759
+ Clock,
1760
+ Coins,
1761
+ Copy,
1762
+ ExternalLink,
1763
+ FilePenLine,
1764
+ FileSpreadsheet,
1765
+ FileText,
1766
+ Folder,
1767
+ Gauge,
1768
+ Globe,
1769
+ Image,
1770
+ Inbox,
1771
+ ListChecks,
1772
+ LoaderCircle,
1773
+ OctagonX,
1774
+ RotateCcw,
1775
+ Search,
1776
+ Send,
1777
+ ShieldAlert,
1778
+ UsersRound,
1779
+ Wrench,
1780
+ X,
1781
+ STRINGS_ES,
1782
+ STRINGS_EN,
1783
+ PilotoContext,
1784
+ usePiloto,
1785
+ TurnContext,
1786
+ rootProps,
1787
+ ReferenceChips,
1788
+ Suggestions,
1789
+ mimeOf,
1790
+ Composer,
1791
+ ModelPicker,
1792
+ definePlugin,
1793
+ pluginRequires,
1794
+ pluginPoints,
1795
+ resolvePlugins,
1796
+ BUILTIN_CUSTOM,
1797
+ isDev
1798
+ };