ghostykit 0.2.0 → 0.3.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.
- package/README.md +9 -4
- package/dist/chunks/{chunk-KZOMMG2D.js → chunk-D6JXJWYM.js} +12 -4
- package/dist/chunks/{chunk-XWOGK2HN.js → chunk-O6FCE4CS.js} +8 -0
- package/dist/core/index.d.ts +1 -1
- package/dist/core/index.js +3 -1
- package/dist/core/reducer.d.ts +5 -0
- package/dist/fonts.css +3 -3
- package/dist/react/Bubble.d.ts +4 -2
- package/dist/react/Chips.d.ts +7 -3
- package/dist/react/Composer.d.ts +4 -1
- package/dist/react/InlineMarkdown.d.ts +5 -0
- package/dist/react/Piloto.d.ts +8 -0
- package/dist/react/Status.d.ts +1 -1
- package/dist/react/Steps.d.ts +11 -6
- package/dist/react/index.d.ts +2 -1
- package/dist/react/index.js +636 -411
- package/dist/styles.css +651 -502
- package/dist/transport/index.js +1 -1
- package/dist/transport/postStream.d.ts +3 -3
- package/dist/transport/types.d.ts +7 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
# Piloto UI · `ghostykit`
|
|
2
2
|
|
|
3
3
|
**An in-app copilot for React.** Piloto UI is the agent chat from
|
|
4
|
-
[Ghosty Studio](https://www.ghosty.studio), packaged as a library
|
|
4
|
+
[Ghosty Studio](https://www.ghosty.studio) (`/c`), packaged as a library: same components, same
|
|
5
|
+
markup, same look ([side by side](https://raw.githubusercontent.com/blissito/ghostykit/main/docs/screenshots/parity/desktop-done-gs-vs-ghostykit.png)). You drop it into an app you already
|
|
5
6
|
have. It sees what the user has on screen, streams what the agent says and does, and **stops to ask
|
|
6
7
|
before anything risky** (human in the loop).
|
|
7
8
|
|
|
@@ -107,6 +108,7 @@ const ref = useRef<PilotoHandle>(null);
|
|
|
107
108
|
agentName="Admin assistant"
|
|
108
109
|
welcome="How can I help with your crons?"
|
|
109
110
|
suggestions={["Why did the monitor fail?"]}
|
|
111
|
+
draft={{ text: "Why did the monitor fail?", key: row.id }} // prefilled + focused, not sent
|
|
110
112
|
context={() => ({ screen: "crons", selected })} // sent with EVERY turn
|
|
111
113
|
toolVerbs={{ run_cron: { one: "Ran a cron", many: "Ran %n crons", running: "Running the cron…" } }}
|
|
112
114
|
upload={async (file) => ({ url: await myUpload(file) })}
|
|
@@ -130,9 +132,11 @@ your own layout.
|
|
|
130
132
|
### Skins and theming
|
|
131
133
|
|
|
132
134
|
`ghostykit/styles.css` is self-contained and scoped under `.piloto`. It works the same with
|
|
133
|
-
**Tailwind 3, Tailwind 4 or no Tailwind
|
|
134
|
-
|
|
135
|
-
|
|
135
|
+
**Tailwind 3, Tailwind 4 or no Tailwind**, and it shields its fields from the host's CSS (verified
|
|
136
|
+
in a Tailwind 3 app **with `@tailwindcss/forms`**: Piloto's textarea gets no border or focus ring, and
|
|
137
|
+
the app's own utilities compute identically with and without Piloto's CSS). Sizes don't depend on
|
|
138
|
+
the host's `html` font size either: `1rem` inside Piloto is `--piloto-rem` (18 px in the Ghosty skin,
|
|
139
|
+
like ghosty.studio; 16 px in the others). Every color, radius, border width and shadow is a variable:
|
|
136
140
|
|
|
137
141
|
```css
|
|
138
142
|
.my-app .piloto {
|
|
@@ -141,6 +145,7 @@ variable:
|
|
|
141
145
|
--piloto-radius-card: 6px;
|
|
142
146
|
--piloto-border-width: 3px;
|
|
143
147
|
--piloto-shadow-hero: 6px 6px 0 #0f766e;
|
|
148
|
+
--piloto-rem: 16px;
|
|
144
149
|
--piloto-font: "Your Sans", sans-serif;
|
|
145
150
|
}
|
|
146
151
|
```
|
|
@@ -52,8 +52,16 @@ function parse(raw) {
|
|
|
52
52
|
}
|
|
53
53
|
}
|
|
54
54
|
function defaultHistory(json) {
|
|
55
|
-
const
|
|
56
|
-
|
|
55
|
+
const j = json;
|
|
56
|
+
const turns = (j?.messages ?? []).filter((m) => typeof m.text === "string").map((m) => ({ role: m.role === "user" ? "user" : "assistant", text: m.text }));
|
|
57
|
+
const permissions = (j?.pending ?? []).filter((p) => typeof p === "object" && p !== null && typeof p.id === "string").map((p) => ({
|
|
58
|
+
id: p.id,
|
|
59
|
+
title: String(p.title ?? ""),
|
|
60
|
+
...typeof p.tool === "string" ? { tool: p.tool } : {},
|
|
61
|
+
options: Array.isArray(p.options) ? p.options : [],
|
|
62
|
+
...p.expiresAt != null ? { expiresAt: p.expiresAt } : {}
|
|
63
|
+
}));
|
|
64
|
+
return { turns, permissions };
|
|
57
65
|
}
|
|
58
66
|
function uuid() {
|
|
59
67
|
const c = globalThis.crypto;
|
|
@@ -146,9 +154,9 @@ function createPostStreamTransport(target, options = {}) {
|
|
|
146
154
|
};
|
|
147
155
|
},
|
|
148
156
|
async history() {
|
|
149
|
-
if (!historyUrl) return [];
|
|
157
|
+
if (!historyUrl) return { turns: [] };
|
|
150
158
|
const res = await doFetch(historyUrl, { credentials, headers: { accept: "application/json" } });
|
|
151
|
-
if (!res.ok) return [];
|
|
159
|
+
if (!res.ok) return { turns: [] };
|
|
152
160
|
return (opts.parseHistory ?? defaultHistory)(await res.json().catch(() => null));
|
|
153
161
|
},
|
|
154
162
|
async send(input) {
|
|
@@ -411,6 +411,13 @@ function resolvePermission(prev, id, optionId, resolved, detail, asked) {
|
|
|
411
411
|
s = { ...s, turns };
|
|
412
412
|
return s;
|
|
413
413
|
}
|
|
414
|
+
function applyHistory(prev, turns, permissions = []) {
|
|
415
|
+
let s = { ...prev, effects: [] };
|
|
416
|
+
if (turns.length && !prev.turns.length) s.turns = turns;
|
|
417
|
+
const fresh = permissions.filter((p) => !prev.permissions.some((q) => q.id === p.id));
|
|
418
|
+
if (fresh.length) s.permissions = [...prev.permissions, ...fresh];
|
|
419
|
+
return s.turns === prev.turns && !fresh.length ? prev : s;
|
|
420
|
+
}
|
|
414
421
|
function appendAgentMessages(prev, texts) {
|
|
415
422
|
if (!texts.length) return prev;
|
|
416
423
|
return { ...prev, effects: [], turns: [...prev.turns, ...texts.map((text) => ({ role: "assistant", text, arrived: true }))] };
|
|
@@ -643,6 +650,7 @@ export {
|
|
|
643
650
|
stopTurn,
|
|
644
651
|
dropLastExchange,
|
|
645
652
|
resolvePermission,
|
|
653
|
+
applyHistory,
|
|
646
654
|
appendAgentMessages,
|
|
647
655
|
reconcileWith,
|
|
648
656
|
lastUserTurn,
|
package/dist/core/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export * from "./types";
|
|
2
|
-
export { RESTART_NOTICE, RESUME_TEXT, appendAgentMessages, beginSend, createPilotState, dropLastExchange, expiryMs, lastUserTurn, reconcileWith, reducePilotEvent, resolvePermission, resumeMode, sendAccepted, sendFailed, sendRejectedBusy, stopTurn, } from "./reducer";
|
|
2
|
+
export { RESTART_NOTICE, RESUME_TEXT, appendAgentMessages, applyHistory, beginSend, createPilotState, dropLastExchange, expiryMs, lastUserTurn, reconcileWith, reducePilotEvent, resolvePermission, resumeMode, sendAccepted, sendFailed, sendRejectedBusy, stopTurn, } from "./reducer";
|
|
3
3
|
export { reconcileTurns } from "./reconcile";
|
|
4
4
|
export { isNarration, narrationToMarkdown, splitNarration } from "./narration";
|
|
5
5
|
export { cleanReplyOption, extractReplyOptions, type ReplyOptions } from "./options";
|
package/dist/core/index.js
CHANGED
|
@@ -4,6 +4,7 @@ import {
|
|
|
4
4
|
TOOL_VERBS_EN,
|
|
5
5
|
TOOL_VERBS_ES,
|
|
6
6
|
appendAgentMessages,
|
|
7
|
+
applyHistory,
|
|
7
8
|
beginSend,
|
|
8
9
|
cleanReplyOption,
|
|
9
10
|
createPilotState,
|
|
@@ -28,7 +29,7 @@ import {
|
|
|
28
29
|
stopTurn,
|
|
29
30
|
summarizeTools,
|
|
30
31
|
toolName
|
|
31
|
-
} from "../chunks/chunk-
|
|
32
|
+
} from "../chunks/chunk-O6FCE4CS.js";
|
|
32
33
|
import {
|
|
33
34
|
applyReferences,
|
|
34
35
|
cleanUserText,
|
|
@@ -41,6 +42,7 @@ export {
|
|
|
41
42
|
TOOL_VERBS_EN,
|
|
42
43
|
TOOL_VERBS_ES,
|
|
43
44
|
appendAgentMessages,
|
|
45
|
+
applyHistory,
|
|
44
46
|
applyReferences,
|
|
45
47
|
beginSend,
|
|
46
48
|
cleanReplyOption,
|
package/dist/core/reducer.d.ts
CHANGED
|
@@ -36,6 +36,11 @@ export declare function dropLastExchange(prev: PilotState): PilotState;
|
|
|
36
36
|
export declare function resolvePermission(prev: PilotState, id: string, optionId: string, resolved: boolean, detail?: string,
|
|
37
37
|
/** La tarjeta como estaba al contestarla (el stream pudo retirarla mientras tanto). */
|
|
38
38
|
asked?: PermissionRequest): PilotState;
|
|
39
|
+
/**
|
|
40
|
+
* El historial guardado (al montar): el hilo, si la pantalla sigue vacía, y las tarjetas de permiso
|
|
41
|
+
* que siguen abiertas (sin duplicar las que el stream ya trajo).
|
|
42
|
+
*/
|
|
43
|
+
export declare function applyHistory(prev: PilotState, turns: Turn[], permissions?: PermissionRequest[]): PilotState;
|
|
39
44
|
/** Un mensaje del agente que entró fuera de un turno (el remate de los subagentes). */
|
|
40
45
|
export declare function appendAgentMessages(prev: PilotState, texts: string[]): PilotState;
|
|
41
46
|
/** La copia del hilo cambió: trae los mensajes que el usuario mandó desde OTRO cliente. Sólo en reposo. */
|
package/dist/fonts.css
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
/* Opcional: las fuentes de las pieles de casa (
|
|
2
|
-
|
|
3
|
-
@import url("https://fonts.googleapis.com/css2?family=Big+Shoulders+Stencil+Display:wght@
|
|
1
|
+
/* Opcional: las fuentes de las pieles de casa — Inter (la de Ghosty) y Big Shoulders Stencil (el
|
|
2
|
+
reloj y el sello del pase de permiso). Sin esto, Piloto cae a las fuentes del sistema. */
|
|
3
|
+
@import url("https://fonts.googleapis.com/css2?family=Big+Shoulders+Stencil+Display:wght@800;900&family=Inter:opsz,wght@14..32,400..800&display=swap");
|
package/dist/react/Bubble.d.ts
CHANGED
|
@@ -16,11 +16,12 @@ export declare function ReplyOptionButtons({ options, onPick }: {
|
|
|
16
16
|
/** Tokens del turno, qué tanto del contexto se llevó y cuánto costó. */
|
|
17
17
|
export declare function UsageStats({ used, size, cost }: Usage): import("react").JSX.Element | null;
|
|
18
18
|
/** El pie de una respuesta terminada: cuánto tardó, copiar y reintentar. */
|
|
19
|
-
export declare function TurnFooter({ text, seconds, onRetry, showCopy }: {
|
|
19
|
+
export declare function TurnFooter({ text, seconds, onRetry, showCopy, showDuration }: {
|
|
20
20
|
text: string;
|
|
21
21
|
seconds?: number;
|
|
22
22
|
onRetry?: () => void;
|
|
23
23
|
showCopy?: boolean;
|
|
24
|
+
showDuration?: boolean;
|
|
24
25
|
}): import("react").JSX.Element;
|
|
25
26
|
/** Las entregas por defecto: una ficha por archivo (las apps pintan las suyas con `renderDeliveries`). */
|
|
26
27
|
export declare function DeliveryChips({ deliveries }: {
|
|
@@ -35,7 +36,8 @@ export interface AgentBubbleProps {
|
|
|
35
36
|
onOption?: (text: string) => void;
|
|
36
37
|
showUsage?: boolean;
|
|
37
38
|
showCopy?: boolean;
|
|
39
|
+
showDuration?: boolean;
|
|
38
40
|
/** Las entregas (y lo que la app quiera bajo la respuesta). Sin esto, fichas simples. */
|
|
39
41
|
renderDeliveries?: (turn: Turn, live: boolean) => ReactNode;
|
|
40
42
|
}
|
|
41
|
-
export declare function AgentBubble({ turn, live, onRetry, onOption, showUsage, showCopy, renderDeliveries }: AgentBubbleProps): import("react").JSX.Element;
|
|
43
|
+
export declare function AgentBubble({ turn, live, onRetry, onOption, showUsage, showCopy, showDuration, renderDeliveries }: AgentBubbleProps): import("react").JSX.Element;
|
package/dist/react/Chips.d.ts
CHANGED
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
import type { Reference } from "../core/types";
|
|
2
|
-
/**
|
|
3
|
-
|
|
2
|
+
/**
|
|
3
|
+
* Las referencias del mensaje: chips atómicos con ×. Una con `prompt` (un elemento señalado) se pinta
|
|
4
|
+
* con la mira, como en Ghosty; las demás (tarjetas del tablero), con su etiqueta. Clic = `onActivate`.
|
|
5
|
+
*/
|
|
6
|
+
export declare function ReferenceChips({ references, onRemove, onActivate }: {
|
|
4
7
|
references: Reference[];
|
|
5
8
|
onRemove: (id: string) => void;
|
|
6
9
|
onActivate?: (ref: Reference) => void;
|
|
7
10
|
}): import("react").JSX.Element | null;
|
|
8
11
|
/** Sugerencias para arrancar. Una que termina en «: » se escribe en la caja en vez de mandarse. */
|
|
9
|
-
export declare function Suggestions({ items, onPick, onPrefill }: {
|
|
12
|
+
export declare function Suggestions({ items, onPick, onPrefill, disabled }: {
|
|
10
13
|
items: string[];
|
|
11
14
|
onPick: (text: string) => void;
|
|
12
15
|
onPrefill?: (text: string) => void;
|
|
16
|
+
disabled?: boolean;
|
|
13
17
|
}): import("react").JSX.Element | null;
|
package/dist/react/Composer.d.ts
CHANGED
|
@@ -37,7 +37,10 @@ export interface ComposerProps {
|
|
|
37
37
|
maxFileMb?: number;
|
|
38
38
|
}
|
|
39
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
|
-
/**
|
|
40
|
+
/**
|
|
41
|
+
* El selector de modelo. PORTADO de Ghosty (`ModelPicker.tsx`): dropdown discreto hacia arriba, sin
|
|
42
|
+
* Radix; cierra con clic fuera y con Escape.
|
|
43
|
+
*/
|
|
41
44
|
export declare function ModelPicker({ models, current, onChange }: {
|
|
42
45
|
models: ModelOption[];
|
|
43
46
|
current: string | null;
|
package/dist/react/Piloto.d.ts
CHANGED
|
@@ -65,6 +65,14 @@ export interface PilotoProps extends UsePilotOptions {
|
|
|
65
65
|
* `transport.respondPermission`. Devuelve `{resolved:false}` si ya no estaba abierto.
|
|
66
66
|
*/
|
|
67
67
|
onPermission?: PermissionHandler;
|
|
68
|
+
/**
|
|
69
|
+
* Una pregunta lista en la caja (sin mandarla) y el foco en ella: al abrir el copiloto desde una
|
|
70
|
+
* fila («Pídeselo»). Cambiar el texto —o `key`, para repetir el mismo— la vuelve a poner.
|
|
71
|
+
*/
|
|
72
|
+
draft?: string | {
|
|
73
|
+
text: string;
|
|
74
|
+
key?: string | number;
|
|
75
|
+
} | null;
|
|
68
76
|
/** Referencias controladas (si no, Piloto las guarda; agrégalas con `ref.addReference`). */
|
|
69
77
|
references?: Reference[];
|
|
70
78
|
onReferencesChange?: (refs: Reference[]) => void;
|
package/dist/react/Status.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { type ReactNode } from "react";
|
|
2
2
|
import type { ConnectPhase } from "../core/types";
|
|
3
|
-
/** Los tres
|
|
3
|
+
/** Los tres puntitos de «escribiendo» (color y animación en CSS: `gc-typing`). */
|
|
4
4
|
export declare function TypingDots(): import("react").JSX.Element;
|
|
5
5
|
export declare function WaitLabel({ phase, since, elsewhere, onLost, showDuration, }: {
|
|
6
6
|
phase: ConnectPhase;
|
package/dist/react/Steps.d.ts
CHANGED
|
@@ -1,22 +1,27 @@
|
|
|
1
|
-
import { type ReactNode } from "react";
|
|
2
1
|
import type { ToolEntry } from "../core/types";
|
|
3
2
|
import { type PilotIcon } from "./context";
|
|
4
|
-
/** La garra de máquina de peluches: el ícono de «usó una herramienta»
|
|
3
|
+
/** La garra de máquina de peluches: el ícono de «usó una herramienta» (baja, cierra y sube en bucle). */
|
|
5
4
|
export declare function ClawIcon({ className }: {
|
|
6
5
|
className?: string;
|
|
7
6
|
}): import("react").JSX.Element;
|
|
8
|
-
/**
|
|
7
|
+
/** Brazo robot agarrando — «Robot grab» de Delapouite (game-icons.net, CC BY 3.0): los pasos técnicos. */
|
|
8
|
+
export declare function RobotArmIcon({ className }: {
|
|
9
|
+
className?: string;
|
|
10
|
+
}): import("react").JSX.Element;
|
|
11
|
+
/** Máquina arcade (Iconoir «arcade», MIT): las herramientas de un MCP conectado. */
|
|
12
|
+
export declare function ArcadeIcon({ className }: {
|
|
13
|
+
className?: string;
|
|
14
|
+
}): import("react").JSX.Element;
|
|
15
|
+
/** Un ícono por tipo de herramienta (los de Ghosty); lo desconocido cae en la garra. */
|
|
9
16
|
export declare const DEFAULT_TOOL_ICONS: Record<string, PilotIcon>;
|
|
10
17
|
export declare function AgentSteps({ tools, live }: {
|
|
11
18
|
tools: ToolEntry[];
|
|
12
19
|
live: boolean;
|
|
13
20
|
}): import("react").JSX.Element;
|
|
14
|
-
/** El detalle de un paso (lista desplegada): rótulo, detalle y ruta. */
|
|
15
21
|
export declare function ToolRow({ tool }: {
|
|
16
22
|
tool: ToolEntry;
|
|
17
23
|
}): import("react").JSX.Element;
|
|
18
24
|
/** La narración del agente como avance: una palomita por lo que ya dijo que hacía. */
|
|
19
|
-
export declare function Narration({ steps
|
|
25
|
+
export declare function Narration({ steps }: {
|
|
20
26
|
steps: string[];
|
|
21
|
-
children?: ReactNode;
|
|
22
27
|
}): import("react").JSX.Element;
|
package/dist/react/index.d.ts
CHANGED
|
@@ -3,6 +3,7 @@ export { usePilot, useSseTransport, type PermissionAnswer, type PermissionHandle
|
|
|
3
3
|
export { AgentBubble, CopyUserMessage, DeliveryChips, ReplyOptionButtons, TurnFooter, UsageStats, UserBubble, type AgentBubbleProps } from "./Bubble";
|
|
4
4
|
export { AgentSteps, ClawIcon, DEFAULT_TOOL_ICONS, Narration, ToolRow } from "./Steps";
|
|
5
5
|
export { LinkSafetyModal, Markdown } from "./Markdown";
|
|
6
|
+
export { InlineMarkdown, renderInline } from "./InlineMarkdown";
|
|
6
7
|
export { useTextAtPace } from "./TextAtPace";
|
|
7
8
|
export { Composer, ModelPicker, mimeOf, type ComposerProps, type UploadResult } from "./Composer";
|
|
8
9
|
export { ConfirmCard, DecisionLines } from "./ConfirmCard";
|
|
@@ -11,4 +12,4 @@ export { ConnectingState, TypingDots, WaitLabel } from "./Status";
|
|
|
11
12
|
export { PilotoContext, usePiloto, type MarkdownOptions, type PilotIcon, type PilotoConfig, type PilotTheme } from "./context";
|
|
12
13
|
export { STRINGS_EN, STRINGS_ES, type PilotStrings } from "./strings";
|
|
13
14
|
export * from "../core";
|
|
14
|
-
export { PilotHttpError, createPostStreamTransport, createSseTransport, readSse, type PilotListener, type PilotTransport, type PostStreamTransportOptions, type SseTransportOptions, type SubscribeOptions, } from "../transport";
|
|
15
|
+
export { PilotHttpError, createPostStreamTransport, createSseTransport, readSse, type PilotHistory, type PilotListener, type PilotTransport, type PostStreamTransportOptions, type SseTransportOptions, type SubscribeOptions, } from "../transport";
|