ghostykit 0.0.0-stage → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,72 @@
1
+ import {
2
+ RESTART_NOTICE,
3
+ RESUME_TEXT,
4
+ TOOL_VERBS_EN,
5
+ TOOL_VERBS_ES,
6
+ appendAgentMessages,
7
+ beginSend,
8
+ cleanReplyOption,
9
+ createPilotState,
10
+ dropLastExchange,
11
+ expiryMs,
12
+ extractReplyOptions,
13
+ groupSteps,
14
+ isNarration,
15
+ isRunning,
16
+ lastUserTurn,
17
+ narrationToMarkdown,
18
+ reconcileTurns,
19
+ reconcileWith,
20
+ reducePilotEvent,
21
+ resolvePermission,
22
+ resumeMode,
23
+ sendAccepted,
24
+ sendFailed,
25
+ sendRejectedBusy,
26
+ splitNarration,
27
+ stepLabel,
28
+ stopTurn,
29
+ summarizeTools,
30
+ toolName
31
+ } from "../chunks/chunk-XWOGK2HN.js";
32
+ import {
33
+ applyReferences,
34
+ cleanUserText,
35
+ formatDuration,
36
+ systemNoteOf
37
+ } from "../chunks/chunk-6U545WJG.js";
38
+ export {
39
+ RESTART_NOTICE,
40
+ RESUME_TEXT,
41
+ TOOL_VERBS_EN,
42
+ TOOL_VERBS_ES,
43
+ appendAgentMessages,
44
+ applyReferences,
45
+ beginSend,
46
+ cleanReplyOption,
47
+ cleanUserText,
48
+ createPilotState,
49
+ dropLastExchange,
50
+ expiryMs,
51
+ extractReplyOptions,
52
+ formatDuration,
53
+ groupSteps,
54
+ isNarration,
55
+ isRunning,
56
+ lastUserTurn,
57
+ narrationToMarkdown,
58
+ reconcileTurns,
59
+ reconcileWith,
60
+ reducePilotEvent,
61
+ resolvePermission,
62
+ resumeMode,
63
+ sendAccepted,
64
+ sendFailed,
65
+ sendRejectedBusy,
66
+ splitNarration,
67
+ stepLabel,
68
+ stopTurn,
69
+ summarizeTools,
70
+ systemNoteOf,
71
+ toolName
72
+ };
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Narración intercalada: lo que el agente dice ANTES de cada herramienta («Reviso tus archivos.»,
3
+ * «Armo el calendario.») es avance, no respuesta. Se pinta como lista con palomitas encima de la
4
+ * respuesta final, como los pasos de claude.ai.
5
+ *
6
+ * Dos fuentes, mismo resultado:
7
+ * - En vivo: el reductor anota en qué largo del texto arrancó cada herramienta (`cuts`).
8
+ * - En la copia guardada: el servidor la escribe como `- ✓ …` al inicio, así la recarga la ve igual.
9
+ */
10
+ /** Un tramo es «narración» si es corto y de un solo párrafo; si no, es texto normal. */
11
+ export declare function isNarration(chunk: string): boolean;
12
+ export declare function splitNarration(text: string, cuts?: number[]): {
13
+ steps: string[];
14
+ rest: string;
15
+ };
16
+ /** La copia que se guarda: narración como `- ✓ …` y luego la respuesta. */
17
+ export declare function narrationToMarkdown(chunks: string[], answer: string): string;
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Cuando la ÚLTIMA respuesta, ya terminada, cierra con una oferta («Si quieres, puedo:»,
3
+ * «¿Quieres que…?», «Dos caminos, tú eliges:») seguida de una lista corta, esa lista se pinta como
4
+ * BOTONES: un clic manda la opción como mensaje del usuario, por el camino normal.
5
+ */
6
+ export type ReplyOptions = {
7
+ before: string;
8
+ items: string[];
9
+ numbered: boolean;
10
+ };
11
+ /** ¿El texto termina en una oferta con 2–5 opciones cortas? Si sí, la separa. */
12
+ export declare function extractReplyOptions(text: string): ReplyOptions | null;
13
+ /** La opción como la mandaría una persona: sin «o »/«y », sin negritas ni puntuación final. */
14
+ export declare function cleanReplyOption(t: string): string;
@@ -0,0 +1,7 @@
1
+ import type { Turn } from "./types";
2
+ /**
3
+ * Si la copia trae MÁS mensajes del usuario que la pantalla, faltan los de otro cliente: se repinta
4
+ * con la copia, conservando el turno vivo (pasos, segundos, uso) de cada mensaje que coincide. Con
5
+ * los mismos mensajes del usuario no se toca nada (las burbujas en vivo son más ricas que la copia).
6
+ */
7
+ export declare function reconcileTurns(current: Turn[], fresh: Turn[]): Turn[];
@@ -0,0 +1,49 @@
1
+ import type { Attachment, PermissionRequest, PilotState, SendResult, Turn } from "./types";
2
+ /** El aviso de reinicio del servidor. Se retira solo si el agente sigue mandando algo. */
3
+ export declare const RESTART_NOTICE = "El servidor se reinici\u00F3 a media respuesta. Vuelve a enviar el mensaje.";
4
+ /** Lo que se ve en el hilo al retomar (el servidor manda al agente la continuación entera). */
5
+ export declare const RESUME_TEXT = "Contin\u00FAa donde te quedaste.";
6
+ export declare function createPilotState(turns?: Turn[]): PilotState;
7
+ /**
8
+ * Un evento del stream → estado nuevo. `data` ya viene parseado (JSON); `null` si no traía.
9
+ * `now` se inyecta para que el reductor sea puro (tiempos de turno y de página).
10
+ */
11
+ export declare function reducePilotEvent(prev: PilotState, name: string, data: unknown, now?: number): PilotState;
12
+ /** `expiresAt` (ISO o epoch ms) → epoch ms. */
13
+ export declare function expiryMs(v: string | number): number;
14
+ /**
15
+ * El usuario manda un mensaje. Con turno en vuelo es una CORRECCIÓN: el servidor intenta meterlo
16
+ * al turno (steer) y, hasta saber si entró, la burbuja viva se conserva.
17
+ */
18
+ export declare function beginSend(prev: PilotState, text: string, attachments: Attachment[], now?: number): PilotState;
19
+ /** El servidor aceptó el encargo. `inFlight` = había turno en vuelo al mandar. */
20
+ export declare function sendAccepted(prev: PilotState, r: SendResult, inFlight: boolean, now?: number): PilotState;
21
+ /**
22
+ * El servidor ya tiene un turno corriendo (409 `turn_busy`): el mensaje de este cliente NO entró.
23
+ * Se quita de la pantalla y se avisa; el transporte se re-engancha al turno que sí corre.
24
+ */
25
+ export declare function sendRejectedBusy(prev: PilotState, message: string): PilotState;
26
+ /** El encargo fue rechazado (sin saldo, sin cuenta…): se DICE, para que no se quede pensando. */
27
+ export declare function sendFailed(prev: PilotState, message: string, needsLogin?: boolean): PilotState;
28
+ /** Detener el turno en curso (el POST de cancelar lo hace el transporte). */
29
+ export declare function stopTurn(prev: PilotState): PilotState;
30
+ /** Quita el último intercambio (las respuestas del final y el último mensaje del usuario). */
31
+ export declare function dropLastExchange(prev: PilotState): PilotState;
32
+ /**
33
+ * El usuario contestó una tarjeta: sale de las abiertas y queda anotada en la última respuesta
34
+ * («Aprobaste: correr la purga»). `resolved: false` = ya no estaba abierta (venció o la contestó otro).
35
+ */
36
+ export declare function resolvePermission(prev: PilotState, id: string, optionId: string, resolved: boolean, detail?: string,
37
+ /** La tarjeta como estaba al contestarla (el stream pudo retirarla mientras tanto). */
38
+ asked?: PermissionRequest): PilotState;
39
+ /** Un mensaje del agente que entró fuera de un turno (el remate de los subagentes). */
40
+ export declare function appendAgentMessages(prev: PilotState, texts: string[]): PilotState;
41
+ /** La copia del hilo cambió: trae los mensajes que el usuario mandó desde OTRO cliente. Sólo en reposo. */
42
+ export declare function reconcileWith(prev: PilotState, fresh: Turn[]): PilotState;
43
+ /** El último mensaje del usuario (para reintentar o retomar). */
44
+ export declare function lastUserTurn(turns: Turn[]): Turn | null;
45
+ /**
46
+ * «Retomar»: si el agente alcanzó a trabajar (texto o pasos tras el último mensaje), se le pide
47
+ * CONTINUAR; si no, es reenviar el mensaje tal cual.
48
+ */
49
+ export declare function resumeMode(turns: Turn[]): "continue" | "resend";
@@ -0,0 +1,30 @@
1
+ import type { ToolEntry } from "./types";
2
+ /** El verbo con el que una persona nombraría un paso. `%n` = cuántas veces. */
3
+ export interface ToolVerb {
4
+ one: string;
5
+ many: string;
6
+ /** Rótulo mientras corre (p. ej. «Compactando la memoria…»); si falta, `one`. */
7
+ running?: string;
8
+ }
9
+ /** Por `kind` de ACP (`read`, `execute`…) o por NOMBRE de herramienta (`crm_card_update`). */
10
+ export type ToolVerbs = Record<string, ToolVerb>;
11
+ /** ¿Sigue corriendo? `pending` también: es el instante entre pedirla y arrancarla. */
12
+ export declare const isRunning: (t: ToolEntry) => boolean;
13
+ /** `mcp__servidor__nombre` → `nombre`; cualquier otro título, tal cual. */
14
+ export declare function toolName(t: ToolEntry): string | null;
15
+ /** El rótulo de un paso: el verbo de su nombre, o el título que manda el servidor, o su clase. */
16
+ export declare function stepLabel(t: ToolEntry, verbs: ToolVerbs, fallback?: string): string;
17
+ /** El resumen de una línea: los pasos agrupados por nombre o clase, con su verbo. */
18
+ export declare function summarizeTools(tools: ToolEntry[], verbs: ToolVerbs): string;
19
+ /**
20
+ * Pasos iguales (mismo rótulo y detalle) en UN renglón con «×3», en el orden en que aparecieron.
21
+ * El representante es el ÚLTIMO (su estado es el vigente), salvo que otro siga corriendo o haya
22
+ * fallado: eso manda.
23
+ */
24
+ export declare function groupSteps(tools: ToolEntry[], label: (t: ToolEntry) => string): {
25
+ tool: ToolEntry;
26
+ times: number;
27
+ }[];
28
+ /** Los verbos de casa, en español. Las apps agregan los suyos (por nombre) con `toolVerbs`. */
29
+ export declare const TOOL_VERBS_ES: ToolVerbs;
30
+ export declare const TOOL_VERBS_EN: ToolVerbs;
@@ -0,0 +1,15 @@
1
+ import type { Reference } from "./types";
2
+ /** El texto del usuario como se pinta en su burbuja. Las apps afinan con `formatUserText`. */
3
+ export declare function cleanUserText(raw: string): string;
4
+ /**
5
+ * Un turno que abrió la PLATAFORMA y no la persona (una tarea programada, una entrega): empieza
6
+ * con «⏰ ». Se pinta como línea de sistema con sólo la causa, sin las instrucciones al modelo.
7
+ */
8
+ export declare function systemNoteOf(text: string): string | null;
9
+ /**
10
+ * Las referencias se mandan DENTRO del texto (es lo que el agente lee): primero los renglones con
11
+ * `prompt` (p. ej. un elemento señalado), luego las etiquetas juntas `[#12 Rosa, #7 Javier] `.
12
+ */
13
+ export declare function applyReferences(text: string, refs: Reference[]): string;
14
+ /** «45 s», «3 min», «1 h 05 min». */
15
+ export declare function formatDuration(s: number): string;
@@ -0,0 +1,236 @@
1
+ /** Por dónde va la conexión con el agente antes de que conteste. */
2
+ export type ConnectPhase = "waking" | "connecting" | "session";
3
+ /** Un modelo que el agente ofrece para la sesión (selector ACP). */
4
+ export interface ModelOption {
5
+ value: string;
6
+ name: string;
7
+ }
8
+ /**
9
+ * Un adjunto listo para el agente: base64 sin prefijo + su MIME, o una URL ya subida.
10
+ * Viaja en el cuerpo del POST como `images` (nombre histórico del contrato).
11
+ */
12
+ export interface Attachment {
13
+ name?: string;
14
+ mimeType: string;
15
+ /** Base64 sin el prefijo `data:`. Vacío cuando el archivo viaja por `uri`. */
16
+ data: string;
17
+ /** URL del archivo ya subido (lo que el agente descarga cuando no es imagen ni texto). */
18
+ uri?: string;
19
+ /** Id del archivo en la app, si la app lo guarda. */
20
+ fileId?: string;
21
+ }
22
+ /** Un paso del agente (una herramienta), según ACP: pending → in_progress → completed | failed. */
23
+ export interface ToolEntry {
24
+ id: string;
25
+ title?: string;
26
+ kind?: string;
27
+ status?: string;
28
+ path?: string;
29
+ /** Qué hace, en palabras de persona (el comando, el archivo, el prompt de la imagen). */
30
+ detail?: string;
31
+ }
32
+ /** Lo que el agente ENTREGÓ en el turno (evento `artifact`). `raw` es el payload tal cual. */
33
+ export interface Delivery {
34
+ kind: "file" | "artifact";
35
+ name: string;
36
+ fileId?: string;
37
+ /** Documento editable de la app (Ghosty: `@ghostystudio/docs`). */
38
+ docId?: string;
39
+ mime?: string;
40
+ size?: number;
41
+ /** Captura de pantalla del navegador: se pinta en su tira, no como entrega suelta. */
42
+ capture?: boolean;
43
+ raw?: Record<string, unknown>;
44
+ }
45
+ /** Una sección de la página que el turno arma (constructor por secciones). */
46
+ export interface PageBuildSection {
47
+ id: string;
48
+ label: string;
49
+ kind: string;
50
+ status: "pending" | "building" | "done" | "failed";
51
+ html?: string;
52
+ }
53
+ /** La revisión de la página armada: corriendo, o terminada con sus arreglos. */
54
+ export interface PageReview {
55
+ status: "running" | "done";
56
+ fixes: {
57
+ name: string;
58
+ sectionId: string;
59
+ }[];
60
+ skipped: string[];
61
+ thumb?: string | null;
62
+ seconds?: number;
63
+ }
64
+ /** Una página que el turno está armando, por `pageId` (eventos `page-plan` … `page-ready`). */
65
+ export interface PageBuild {
66
+ pageId: string;
67
+ title: string;
68
+ /** Opaco para Piloto: lo interpreta quien pinta la página (slot `renderDeliveries`). */
69
+ theme: unknown;
70
+ sections: PageBuildSection[];
71
+ startedAt: number;
72
+ readyAt?: number;
73
+ url?: string | null;
74
+ n?: number;
75
+ error?: string;
76
+ mode?: "build" | "edit";
77
+ focus?: {
78
+ sectionId: string;
79
+ nodeId: string;
80
+ };
81
+ editLabel?: string;
82
+ editSummary?: string;
83
+ review?: PageReview;
84
+ }
85
+ export interface Usage {
86
+ used: number;
87
+ size: number;
88
+ cost: number;
89
+ input?: number;
90
+ output?: number;
91
+ }
92
+ export interface Turn {
93
+ role: "user" | "assistant";
94
+ text: string;
95
+ /** Llegó entero fuera de un turno (el remate de los subagentes): se escribe al ritmo. */
96
+ arrived?: boolean;
97
+ deliveries?: Delivery[];
98
+ /** Cuánto tardó, en segundos. Se rellena al cerrar el turno. */
99
+ seconds?: number;
100
+ thought?: string;
101
+ tools?: ToolEntry[];
102
+ /** Largo del texto cuando arrancó cada herramienta: lo de antes es narración (`splitNarration`). */
103
+ cuts?: number[];
104
+ attachments?: Attachment[];
105
+ usage?: Usage;
106
+ /** Lo que el usuario decidió en las tarjetas de permiso de este turno (sólo en vivo). */
107
+ decisions?: Decision[];
108
+ /** Mensaje del usuario que ENTRÓ al turno en vuelo (steer): la respuesta sigue arriba. */
109
+ steer?: boolean;
110
+ pages?: PageBuild[];
111
+ /** El servidor ya está planeando una página (antes de que llegue su plan). */
112
+ planning?: boolean;
113
+ planningAt?: number;
114
+ }
115
+ /** Un turno que se cortó por falla del servidor (deploy, caja caída). Lo dice el servidor. */
116
+ export interface Interrupted {
117
+ reason: string;
118
+ turnId?: string;
119
+ /** El servidor puede CONTINUAR ese turno (EasyBits: `continueTurnId`). */
120
+ canContinue?: boolean;
121
+ }
122
+ /** Una tarjeta de permiso ya contestada. */
123
+ export interface Decision {
124
+ id: string;
125
+ title: string;
126
+ status: "approved" | "rejected" | "expired";
127
+ /** Lo que devolvió la app al resolverla (p. ej. «ejecutada»). */
128
+ detail?: string;
129
+ }
130
+ /** Una opción de un pedido de permiso, tal cual la manda el agente (ACP). */
131
+ export interface PermissionOption {
132
+ optionId: string;
133
+ name: string;
134
+ /** `allow_once` | `allow_always` | `reject_once` | `reject_always` | otra. */
135
+ kind?: string;
136
+ }
137
+ /** El agente pide permiso antes de algo riesgoso: el turno está DETENIDO hasta que alguien conteste. */
138
+ export interface PermissionRequest {
139
+ id: string;
140
+ title: string;
141
+ tool?: string;
142
+ options: PermissionOption[];
143
+ /**
144
+ * Hasta cuándo se puede contestar (ISO o epoch ms). Una tarjeta CON vencimiento no depende del
145
+ * turno (EasyBits: la propuesta vive 15 min aunque el turno ya cerró) y sobrevive al `done`.
146
+ */
147
+ expiresAt?: string | number;
148
+ }
149
+ /** Lo que una transición pide hacer FUERA del estado (avisos a la app). */
150
+ export type PilotEffect = {
151
+ type: "turn-start";
152
+ } | {
153
+ type: "turn-done";
154
+ text: string;
155
+ turnId?: string;
156
+ seconds?: number;
157
+ } | {
158
+ type: "turn-interrupted";
159
+ reason: string;
160
+ turnId?: string;
161
+ } | {
162
+ type: "needs-login";
163
+ } | {
164
+ type: "title";
165
+ title?: string;
166
+ } | {
167
+ type: "disconnected";
168
+ };
169
+ export interface PilotState {
170
+ turns: Turn[];
171
+ busy: boolean;
172
+ connected: boolean;
173
+ phase: ConnectPhase;
174
+ error: string | null;
175
+ notice: string | null;
176
+ usage: Usage | null;
177
+ models: ModelOption[];
178
+ currentModel: string | null;
179
+ /** Qué puede el agente. Empieza en `true` para no bloquear mientras se conecta. */
180
+ canSeeImages: boolean;
181
+ /** El último turno se cortó por falla del servidor: el chat ofrece Retomar. */
182
+ interrupted: Interrupted | null;
183
+ /** El turno sigue en OTRA instancia del servidor (deploy azul/verde): «sigo trabajando». */
184
+ elsewhere: boolean;
185
+ /** Permisos abiertos, en el orden en que llegaron. */
186
+ permissions: PermissionRequest[];
187
+ /** Cuándo empezó el turno que ESTE cliente encargó (0 = ninguno). */
188
+ turnStartedAt: number;
189
+ /** Hay una burbuja del asistente recibiendo eventos del turno en curso. */
190
+ streaming: boolean;
191
+ /** El `turnId` del turno que este cliente encargó (lo devuelve el POST). */
192
+ currentTurnId: string | null;
193
+ /** Cuántas veces se abrió el stream: >1 = reconexión. */
194
+ connections: number;
195
+ /** El servidor avisó (`caps.needAccount`) que hace falta cuenta: se avisa al cerrar el turno. */
196
+ needAccount: boolean;
197
+ /** Cada cuánto promete el servidor su latido (`started.latidoMs`). */
198
+ heartbeatMs: number | null;
199
+ /** Efectos de la ÚLTIMA transición. El hook los ejecuta y los descarta. */
200
+ effects: PilotEffect[];
201
+ }
202
+ /** Lo que se le pide al transporte al mandar un mensaje. */
203
+ export interface SendInput {
204
+ text: string;
205
+ attachments: Attachment[];
206
+ /** Es el primer mensaje del hilo (el servidor lo bautiza al cerrar el turno). */
207
+ firstTurn: boolean;
208
+ /** «Retomar» un turno cortado: el servidor arma la continuación. */
209
+ resume?: boolean;
210
+ /** Con `resume`: el turno a continuar, si el servidor lo dijo (`interrupted.turnId`). */
211
+ resumeTurnId?: string;
212
+ /** Lo que el usuario ve en pantalla, para este turno. */
213
+ context?: unknown;
214
+ /** Las referencias que viajaron en el texto, también estructuradas. */
215
+ references?: Reference[];
216
+ }
217
+ /** Lo que contesta el servidor al encargo. */
218
+ export interface SendResult {
219
+ /** El mensaje entró al turno en vuelo (steer). */
220
+ injected?: boolean;
221
+ /** `queued` = la caja está despertando. */
222
+ state?: string;
223
+ turnId?: string;
224
+ }
225
+ /**
226
+ * Una referencia que acompaña al mensaje (una tarjeta del tablero, un elemento señalado).
227
+ * Con `prompt`, ese renglón va ANTES del mensaje; sin él, las etiquetas van juntas como
228
+ * `[#12 Rosa, #7 Javier] ` (el formato del tablero de Ghosty).
229
+ */
230
+ export interface Reference {
231
+ id: string;
232
+ label: string;
233
+ prompt?: string;
234
+ /** Texto secundario del chip («el texto señalado»). */
235
+ hint?: string;
236
+ }
package/dist/fonts.css ADDED
@@ -0,0 +1,3 @@
1
+ /* Opcional: las fuentes de las pieles de casa (Schibsted Grotesk para leer, Big Shoulders Stencil
2
+ para el reloj y el sello del pase). Sin esto, Piloto cae a las fuentes del sistema. */
3
+ @import url("https://fonts.googleapis.com/css2?family=Big+Shoulders+Stencil+Display:wght@700;800;900&family=Schibsted+Grotesk:ital,wght@0,400..900;1,400..900&display=swap");
@@ -0,0 +1,9 @@
1
+ import { type PickedElement } from "@ghostystudio/pointer/picked";
2
+ import type { Reference } from "../core/types";
3
+ /** Un elemento señalado → referencia: chip «Título «…»» y el renglón `[Elemento señalado …]` antes del mensaje. */
4
+ export declare function elementReference(picked: PickedElement, fileName: string): Reference;
5
+ /** Qué pedirle a lo señalado («¿Qué le cambio a este título? Ej.: …»), para el placeholder. */
6
+ export declare function pickedPlaceholder(picked: PickedElement): string;
7
+ /** `formatUserText` que además pinta el renglón señalado como etiqueta corta (`↳ Título «…»`). */
8
+ export declare function formatWithPicked(text: string): string;
9
+ export type { PickedElement };
@@ -0,0 +1,27 @@
1
+ import {
2
+ cleanUserText
3
+ } from "../chunks/chunk-6U545WJG.js";
4
+
5
+ // src/pointer/index.ts
6
+ import { pickedKind, pickedLineLabel, pickedSnippet } from "@ghostystudio/pointer/kind";
7
+ import { pickedElementLine } from "@ghostystudio/pointer/picked";
8
+ function elementReference(picked, fileName) {
9
+ return {
10
+ id: `pick:${fileName}:${picked.id ?? picked.selector}`,
11
+ label: pickedKind(picked.tag).label,
12
+ hint: picked.text ? pickedSnippet(picked.text) : void 0,
13
+ prompt: pickedElementLine(picked, fileName)
14
+ };
15
+ }
16
+ function pickedPlaceholder(picked) {
17
+ const k = pickedKind(picked.tag);
18
+ return `\xBFQu\xE9 le cambio a ${k.this}? Ej.: ${k.example}`;
19
+ }
20
+ function formatWithPicked(text) {
21
+ return cleanUserText(pickedLineLabel(text));
22
+ }
23
+ export {
24
+ elementReference,
25
+ formatWithPicked,
26
+ pickedPlaceholder
27
+ };
@@ -0,0 +1,41 @@
1
+ import { type ReactNode } from "react";
2
+ import { type ReplyOptions } from "../core/options";
3
+ import type { Delivery, Turn, Usage } from "../core/types";
4
+ export declare function UserBubble({ turn }: {
5
+ turn: Turn;
6
+ }): import("react").JSX.Element;
7
+ /** Copiar lo que TÚ escribiste: un ícono bajo tu burbuja, al pasar el mouse (fijo en táctil). */
8
+ export declare function CopyUserMessage({ text }: {
9
+ text: string;
10
+ }): import("react").JSX.Element;
11
+ /** Las opciones finales de la última respuesta como botones: un clic las manda como tu mensaje. */
12
+ export declare function ReplyOptionButtons({ options, onPick }: {
13
+ options: ReplyOptions;
14
+ onPick: (text: string) => void;
15
+ }): import("react").JSX.Element;
16
+ /** Tokens del turno, qué tanto del contexto se llevó y cuánto costó. */
17
+ export declare function UsageStats({ used, size, cost }: Usage): import("react").JSX.Element | null;
18
+ /** El pie de una respuesta terminada: cuánto tardó, copiar y reintentar. */
19
+ export declare function TurnFooter({ text, seconds, onRetry, showCopy }: {
20
+ text: string;
21
+ seconds?: number;
22
+ onRetry?: () => void;
23
+ showCopy?: boolean;
24
+ }): import("react").JSX.Element;
25
+ /** Las entregas por defecto: una ficha por archivo (las apps pintan las suyas con `renderDeliveries`). */
26
+ export declare function DeliveryChips({ deliveries }: {
27
+ deliveries: Delivery[];
28
+ }): import("react").JSX.Element | null;
29
+ export interface AgentBubbleProps {
30
+ turn: Turn;
31
+ /** El turno sigue escribiéndose. */
32
+ live: boolean;
33
+ onRetry?: () => void;
34
+ /** Sólo la ÚLTIMA respuesta, ya terminada: sus opciones finales salen como botones. */
35
+ onOption?: (text: string) => void;
36
+ showUsage?: boolean;
37
+ showCopy?: boolean;
38
+ /** Las entregas (y lo que la app quiera bajo la respuesta). Sin esto, fichas simples. */
39
+ renderDeliveries?: (turn: Turn, live: boolean) => ReactNode;
40
+ }
41
+ export declare function AgentBubble({ turn, live, onRetry, onOption, showUsage, showCopy, renderDeliveries }: AgentBubbleProps): import("react").JSX.Element;
@@ -0,0 +1,13 @@
1
+ import type { Reference } from "../core/types";
2
+ /** Las referencias del mensaje: chips atómicos con ×. Clic en el chip = `onActivate` (resaltar en la app). */
3
+ export declare function ReferenceChips({ references, onRemove, onActivate, }: {
4
+ references: Reference[];
5
+ onRemove: (id: string) => void;
6
+ onActivate?: (ref: Reference) => void;
7
+ }): import("react").JSX.Element | null;
8
+ /** Sugerencias para arrancar. Una que termina en «: » se escribe en la caja en vez de mandarse. */
9
+ export declare function Suggestions({ items, onPick, onPrefill }: {
10
+ items: string[];
11
+ onPick: (text: string) => void;
12
+ onPrefill?: (text: string) => void;
13
+ }): import("react").JSX.Element | null;
@@ -0,0 +1,45 @@
1
+ import { type ReactNode } from "react";
2
+ import type { Attachment, ModelOption, Reference } from "../core/types";
3
+ /** Lo que devuelve la app al subir un archivo: su URL (y su id, si lo guarda). */
4
+ export interface UploadResult {
5
+ url: string;
6
+ id?: string;
7
+ }
8
+ /** El tipo del archivo, deducido del nombre cuando el navegador no lo dice (pasa más de lo que parece). */
9
+ export declare function mimeOf(file: File): string;
10
+ export interface ComposerProps {
11
+ onSubmit: (text: string, attachments: Attachment[]) => void;
12
+ onStop?: () => void;
13
+ busy?: boolean;
14
+ /** ¿Se puede mandar texto con el turno en vuelo? (el servidor lo mete al turno). Default sí. */
15
+ canSteer?: boolean;
16
+ placeholder?: string;
17
+ initialValue?: string;
18
+ autoFocus?: boolean;
19
+ /** ¿El agente ve imágenes? Si no, el botón de imagen se apaga en vez de fingir. */
20
+ canSeeImages?: boolean;
21
+ /** Adjuntos: imágenes y texto viajan dentro del turno; lo demás se sube con `upload`. */
22
+ attachments?: boolean;
23
+ upload?: (file: File) => Promise<UploadResult>;
24
+ /** Nota de voz: con esto aparece el micrófono. */
25
+ transcribe?: (audio: Blob) => Promise<string>;
26
+ /** Cómo viaja lo dicho (p. ej. con un envoltorio para el agente). Default: tal cual. */
27
+ voiceNoteText?: (transcript: string) => string;
28
+ models?: ModelOption[];
29
+ currentModel?: string | null;
30
+ onModelChange?: (value: string) => void;
31
+ references?: Reference[];
32
+ onRemoveReference?: (id: string) => void;
33
+ onActivateReference?: (ref: Reference) => void;
34
+ /** Botones propios junto a adjuntar (slot `composerExtras`). */
35
+ extras?: ReactNode;
36
+ maxFiles?: number;
37
+ maxFileMb?: number;
38
+ }
39
+ export declare function Composer({ onSubmit, onStop, busy, canSteer, placeholder, initialValue, autoFocus, canSeeImages, attachments: withFiles, upload, transcribe, voiceNoteText, models, currentModel, onModelChange, references, onRemoveReference, onActivateReference, extras, maxFiles, maxFileMb, }: ComposerProps): import("react").JSX.Element;
40
+ /** El selector de modelo: un menú corto hacia arriba, sin Radix. Cierra con clic fuera y Escape. */
41
+ export declare function ModelPicker({ models, current, onChange }: {
42
+ models: ModelOption[];
43
+ current: string | null;
44
+ onChange: (value: string) => void;
45
+ }): import("react").JSX.Element | null;
@@ -0,0 +1,17 @@
1
+ import type { Decision, PermissionOption, PermissionRequest } from "../core/types";
2
+ import type { PermissionAnswer } from "./usePilot";
3
+ /** Las opciones de rechazo van primero y discretas; las de aprobar, al final y en color. */
4
+ export declare const isRejectOption: (o: PermissionOption) => boolean;
5
+ export declare function ConfirmCard({ request, onRespond, onSettled, onExpire, }: {
6
+ request: PermissionRequest;
7
+ /** Contesta (el transporte o la ruta de la app). `{resolved:false}` = ya no estaba abierta. */
8
+ onRespond: (id: string, optionId: string) => Promise<PermissionAnswer> | PermissionAnswer;
9
+ /** El sello ya se vio: anotar la decisión y retirar la tarjeta. */
10
+ onSettled?: (id: string, optionId: string, answer: PermissionAnswer) => void;
11
+ /** Venció sin contestarse. */
12
+ onExpire?: (id: string) => void;
13
+ }): import("react").JSX.Element;
14
+ /** Lo que el usuario decidió en las tarjetas de este turno: «Aprobaste: correr la purga». */
15
+ export declare function DecisionLines({ decisions }: {
16
+ decisions: Decision[];
17
+ }): import("react").JSX.Element | null;
@@ -0,0 +1,12 @@
1
+ import { type LinkSafetyModalProps } from "streamdown";
2
+ /** El aviso de enlace externo, en la lengua y el tema de Piloto (el de Streamdown llega en inglés). */
3
+ export declare function LinkSafetyModal({ isOpen, onClose, onConfirm, url }: LinkSafetyModalProps): import("react").JSX.Element | null;
4
+ /**
5
+ * `animate`: la respuesta se está escribiendo y entra por tramos con fade. Una vez que animó, se
6
+ * queda con el mismo bloque aunque el turno cierre: cambiarlo re-montaría todo y cortaría el fade.
7
+ */
8
+ export declare function Markdown({ children, animate, className }: {
9
+ children: string;
10
+ animate?: boolean;
11
+ className?: string;
12
+ }): import("react").JSX.Element;