@guuey/chat 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +137 -0
- package/dist/history-inputs.d.ts +24 -0
- package/dist/history-inputs.d.ts.map +1 -0
- package/dist/history-inputs.js +34 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +17 -0
- package/dist/plan.d.ts +5 -0
- package/dist/plan.d.ts.map +1 -0
- package/dist/plan.js +629 -0
- package/dist/policy.d.ts +110 -0
- package/dist/policy.d.ts.map +1 -0
- package/dist/policy.js +75 -0
- package/dist/react/components.d.ts +87 -0
- package/dist/react/components.d.ts.map +1 -0
- package/dist/react/components.js +270 -0
- package/dist/react/guuey-chat.d.ts +84 -0
- package/dist/react/guuey-chat.d.ts.map +1 -0
- package/dist/react/guuey-chat.js +103 -0
- package/dist/react/markdown.d.ts +32 -0
- package/dist/react/markdown.d.ts.map +1 -0
- package/dist/react/markdown.js +40 -0
- package/dist/react/theme-css.d.ts +16 -0
- package/dist/react/theme-css.d.ts.map +1 -0
- package/dist/react/theme-css.js +37 -0
- package/dist/react/transcript.d.ts +42 -0
- package/dist/react/transcript.d.ts.map +1 -0
- package/dist/react/transcript.js +88 -0
- package/dist/react/use-transcript.d.ts +39 -0
- package/dist/react/use-transcript.d.ts.map +1 -0
- package/dist/react/use-transcript.js +201 -0
- package/dist/react.d.ts +21 -0
- package/dist/react.d.ts.map +1 -0
- package/dist/react.js +20 -0
- package/dist/strings.d.ts +74 -0
- package/dist/strings.d.ts.map +1 -0
- package/dist/strings.js +45 -0
- package/dist/theme.d.ts +99 -0
- package/dist/theme.d.ts.map +1 -0
- package/dist/theme.js +182 -0
- package/dist/types.d.ts +283 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +1 -0
- package/package.json +87 -0
- package/src/corpus/README.md +40 -0
- package/src/corpus/__snapshots__/corpus.test.ts.snap +1590 -0
- package/src/corpus/capture.ts +67 -0
- package/src/corpus/captures/issue2627-render-capture.coalesced.sse.txt +173 -0
- package/src/corpus/drive.ts +184 -0
- package/src/corpus/fixtures.ts +338 -0
- package/src/history-inputs.ts +48 -0
- package/src/index.ts +58 -0
- package/src/plan.ts +740 -0
- package/src/policy.ts +146 -0
- package/src/react/components.tsx +655 -0
- package/src/react/guuey-chat.tsx +227 -0
- package/src/react/markdown.tsx +114 -0
- package/src/react/theme-css.ts +50 -0
- package/src/react/transcript.tsx +187 -0
- package/src/react/use-transcript.ts +274 -0
- package/src/react.tsx +51 -0
- package/src/strings.ts +144 -0
- package/src/theme.ts +195 -0
- package/src/types.ts +320 -0
- package/styles.css +514 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"react.d.ts","sourceRoot":"","sources":["../src/react.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,OAAO,EACL,UAAU,EACV,KAAK,eAAe,EACpB,KAAK,mBAAmB,GACzB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,2BAA2B,EAC3B,UAAU,EACV,kBAAkB,EAClB,WAAW,EACX,gBAAgB,EAChB,WAAW,EACX,gBAAgB,EAChB,iBAAiB,EACjB,WAAW,EACX,YAAY,EACZ,WAAW,EACX,gBAAgB,EAChB,aAAa,EACb,YAAY,EACZ,sBAAsB,EACtB,iBAAiB,EACjB,cAAc,EACd,aAAa,EACb,KAAK,oBAAoB,EACzB,KAAK,qBAAqB,GAC3B,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,aAAa,EACb,mBAAmB,EACnB,KAAK,iBAAiB,EACtB,KAAK,mBAAmB,EACxB,KAAK,yBAAyB,GAC/B,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAE,SAAS,EAAE,KAAK,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvE,OAAO,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAC/C,OAAO,EAAE,YAAY,EAAE,KAAK,SAAS,EAAE,MAAM,sBAAsB,CAAC"}
|
package/dist/react.js
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* React entry point (`@guuey/chat/react`) — the component kit over the
|
|
3
|
+
* root subpath's headless view-model (wave 3b, guuey#135).
|
|
4
|
+
*
|
|
5
|
+
* The root subpath stays React-free forever; everything React-coupled —
|
|
6
|
+
* the per-category components, `<Transcript>`, the renderer-state owner
|
|
7
|
+
* (`useTranscript`), and the live input assembler (`useTranscriptInputs`)
|
|
8
|
+
* — lives behind this arm, with `react` as an optional peer (the
|
|
9
|
+
* mcp-apps-host precedent).
|
|
10
|
+
*
|
|
11
|
+
* Composition ladder (spec §1 "configurable"): use `<Transcript>` with the
|
|
12
|
+
* default kit as-is → override per-category components → tune policy knobs
|
|
13
|
+
* → drop to `planTranscript` + `attachViewHost` and render it all yourself.
|
|
14
|
+
*/
|
|
15
|
+
export { Transcript, } from "./react/transcript.js";
|
|
16
|
+
export { defaultTranscriptComponents, renderItem, DefaultUserMessage, DefaultText, DefaultReasoning, DefaultTool, DefaultToolGroup, DefaultDataResult, DefaultView, DefaultMedia, DefaultCode, DefaultCitations, DefaultPrompt, DefaultError, DefaultHistoryBoundary, DefaultCompaction, DefaultUnknown, DefaultStatus, } from "./react/components.js";
|
|
17
|
+
export { useTranscript, useTranscriptInputs, } from "./react/use-transcript.js";
|
|
18
|
+
export { GuueyChat } from "./react/guuey-chat.js";
|
|
19
|
+
export { Markdown } from "./react/markdown.js";
|
|
20
|
+
export { themeCssVars } from "./react/theme-css.js";
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The ONE place every user-facing string lives — the i18n seam (spec §4.2).
|
|
3
|
+
*
|
|
4
|
+
* Builders override any string (or all of them, for a locale) through
|
|
5
|
+
* `TranscriptPolicy.strings` without forking components; nothing else in the
|
|
6
|
+
* package carries literal copy. Parameterized strings are functions so word
|
|
7
|
+
* order stays translatable ("Ran 4 tools" vs "4 Werkzeuge ausgeführt").
|
|
8
|
+
*
|
|
9
|
+
* The en defaults below are the founder-review copy from the wave-3a design
|
|
10
|
+
* (§4.2 + per-row labels; guuey#135 — F7 keeps them wordsmith-able until 3b
|
|
11
|
+
* freezes the voice).
|
|
12
|
+
*/
|
|
13
|
+
export interface ChatStrings {
|
|
14
|
+
/** R12 escalation ladder (spec §4.2). */
|
|
15
|
+
connecting: string;
|
|
16
|
+
starting: string;
|
|
17
|
+
longStart: string;
|
|
18
|
+
thinking: string;
|
|
19
|
+
usingTool: (toolTitle: string) => string;
|
|
20
|
+
/** R1 aborted-partial marker + §4.2 aborted line. */
|
|
21
|
+
stopped: string;
|
|
22
|
+
/** R11 family copy — each is a PREFIX slot for the builder's own wording. */
|
|
23
|
+
errorAuth: string;
|
|
24
|
+
errorQuota: string;
|
|
25
|
+
errorTransient: string;
|
|
26
|
+
errorInvalid: string;
|
|
27
|
+
/** R3/R4. */
|
|
28
|
+
toolGroup: (count: number) => string;
|
|
29
|
+
toolGroupFailures: (count: number) => string;
|
|
30
|
+
toolDidntFinish: string;
|
|
31
|
+
/** R4 calm attribution chrome on a display-bearing call ("via {tool}"). */
|
|
32
|
+
viaTool: (toolTitle: string) => string;
|
|
33
|
+
/** R2. */
|
|
34
|
+
reasoningLabel: string;
|
|
35
|
+
/** R9. */
|
|
36
|
+
citations: (count: number) => string;
|
|
37
|
+
/** R15 — the trust invariant's label. */
|
|
38
|
+
unknownLabel: string;
|
|
39
|
+
/** R14. */
|
|
40
|
+
compaction: string;
|
|
41
|
+
/** R0. */
|
|
42
|
+
userCouldntSend: string;
|
|
43
|
+
userRetry: string;
|
|
44
|
+
/** R6 states. */
|
|
45
|
+
viewNegotiating: string;
|
|
46
|
+
viewBootFailure: string;
|
|
47
|
+
viewInlineFallback: string;
|
|
48
|
+
viewExpired: string;
|
|
49
|
+
viewSandboxUnavailable: string;
|
|
50
|
+
/** #192 debug-preset marker (calm never shows it — spec §3, F10). */
|
|
51
|
+
recoveredFromHistory: string;
|
|
52
|
+
/** R5 empty result. */
|
|
53
|
+
noOutput: string;
|
|
54
|
+
/** R5/R15 byte-count note. */
|
|
55
|
+
bytes: (byteCount: number) => string;
|
|
56
|
+
/** R13 states. */
|
|
57
|
+
historyLoading: string;
|
|
58
|
+
threadGone: string;
|
|
59
|
+
/** Renderer chrome (spec §3.2 — the 3b kit's own affordances). */
|
|
60
|
+
jumpToLatest: string;
|
|
61
|
+
showEarlier: (count: number) => string;
|
|
62
|
+
copy: string;
|
|
63
|
+
copied: string;
|
|
64
|
+
/** The 3c composer (`<GuueyChat>`). */
|
|
65
|
+
composerPlaceholder: string;
|
|
66
|
+
composerUnavailable: string;
|
|
67
|
+
composerLabel: string;
|
|
68
|
+
send: string;
|
|
69
|
+
stop: string;
|
|
70
|
+
}
|
|
71
|
+
/** Humanize a wire tool name: `render_weather-card` → `render weather card`. */
|
|
72
|
+
export declare function humanizeToolName(wireName: string): string;
|
|
73
|
+
export declare const defaultChatStrings: ChatStrings;
|
|
74
|
+
//# sourceMappingURL=strings.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"strings.d.ts","sourceRoot":"","sources":["../src/strings.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,WAAW;IAC1B,yCAAyC;IACzC,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,MAAM,CAAC;IACzC,qDAAqD;IACrD,OAAO,EAAE,MAAM,CAAC;IAEhB,6EAA6E;IAC7E,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,EAAE,MAAM,CAAC;IAErB,aAAa;IACb,SAAS,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC;IACrC,iBAAiB,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC;IAC7C,eAAe,EAAE,MAAM,CAAC;IACxB,2EAA2E;IAC3E,OAAO,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,MAAM,CAAC;IAEvC,UAAU;IACV,cAAc,EAAE,MAAM,CAAC;IAEvB,UAAU;IACV,SAAS,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC;IAErC,yCAAyC;IACzC,YAAY,EAAE,MAAM,CAAC;IAErB,WAAW;IACX,UAAU,EAAE,MAAM,CAAC;IAEnB,UAAU;IACV,eAAe,EAAE,MAAM,CAAC;IACxB,SAAS,EAAE,MAAM,CAAC;IAElB,iBAAiB;IACjB,eAAe,EAAE,MAAM,CAAC;IACxB,eAAe,EAAE,MAAM,CAAC;IACxB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,WAAW,EAAE,MAAM,CAAC;IACpB,sBAAsB,EAAE,MAAM,CAAC;IAE/B,qEAAqE;IACrE,oBAAoB,EAAE,MAAM,CAAC;IAE7B,uBAAuB;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,8BAA8B;IAC9B,KAAK,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,MAAM,CAAC;IAErC,kBAAkB;IAClB,cAAc,EAAE,MAAM,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC;IAEnB,kEAAkE;IAClE,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC;IACvC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IAEf,uCAAuC;IACvC,mBAAmB,EAAE,MAAM,CAAC;IAC5B,mBAAmB,EAAE,MAAM,CAAC;IAC5B,aAAa,EAAE,MAAM,CAAC;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd;AAED,gFAAgF;AAChF,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAEzD;AAED,eAAO,MAAM,kBAAkB,EAAE,WAsDhC,CAAC"}
|
package/dist/strings.js
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/** Humanize a wire tool name: `render_weather-card` → `render weather card`. */
|
|
2
|
+
export function humanizeToolName(wireName) {
|
|
3
|
+
return wireName.replace(/[_-]+/g, " ").trim();
|
|
4
|
+
}
|
|
5
|
+
export const defaultChatStrings = {
|
|
6
|
+
connecting: "Connecting…",
|
|
7
|
+
starting: "Starting your agent…",
|
|
8
|
+
longStart: "Starting your agent… first load can take a minute",
|
|
9
|
+
thinking: "Thinking…",
|
|
10
|
+
usingTool: (toolTitle) => `Using ${toolTitle}…`,
|
|
11
|
+
stopped: "Stopped.",
|
|
12
|
+
errorAuth: "Sign in to continue.",
|
|
13
|
+
errorQuota: "This agent is over its usage limit.",
|
|
14
|
+
errorTransient: "Something went wrong on our side — try again.",
|
|
15
|
+
errorInvalid: "The app sent a request the agent couldn't read.",
|
|
16
|
+
toolGroup: (count) => `Ran ${count} tools`,
|
|
17
|
+
toolGroupFailures: (count) => (count === 1 ? "1 failed" : `${count} failed`),
|
|
18
|
+
toolDidntFinish: "didn't finish",
|
|
19
|
+
viaTool: (toolTitle) => `via ${toolTitle}`,
|
|
20
|
+
reasoningLabel: "Thought for a moment",
|
|
21
|
+
citations: (count) => (count === 1 ? "1 source" : `${count} sources`),
|
|
22
|
+
unknownLabel: "Unrecognized content",
|
|
23
|
+
compaction: "Earlier conversation summarized",
|
|
24
|
+
userCouldntSend: "Couldn't send",
|
|
25
|
+
userRetry: "Retry",
|
|
26
|
+
viewNegotiating: "Loading view…",
|
|
27
|
+
viewBootFailure: "This view couldn't start",
|
|
28
|
+
viewInlineFallback: "Showing plain content",
|
|
29
|
+
viewExpired: "This view expired",
|
|
30
|
+
viewSandboxUnavailable: "Interactive view unavailable",
|
|
31
|
+
recoveredFromHistory: "recovered from history",
|
|
32
|
+
noOutput: "no output",
|
|
33
|
+
bytes: (byteCount) => byteCount >= 1024 ? `${Math.round(byteCount / 1024)} KB` : `${byteCount} B`,
|
|
34
|
+
historyLoading: "Loading conversation…",
|
|
35
|
+
threadGone: "This conversation is no longer available.",
|
|
36
|
+
jumpToLatest: "Jump to latest",
|
|
37
|
+
showEarlier: (count) => `Show ${count} earlier`,
|
|
38
|
+
copy: "Copy",
|
|
39
|
+
copied: "Copied",
|
|
40
|
+
composerPlaceholder: "Message the agent…",
|
|
41
|
+
composerUnavailable: "Chat is unavailable.",
|
|
42
|
+
composerLabel: "Message",
|
|
43
|
+
send: "Send",
|
|
44
|
+
stop: "Stop",
|
|
45
|
+
};
|
package/dist/theme.d.ts
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Theme = platform data (wave-3a design §6, founder-ratified).
|
|
3
|
+
*
|
|
4
|
+
* ONE serializable token schema, four consumers: this package's default
|
|
5
|
+
* theme, the per-app theme configured on platform.guuey.com (console editor
|
|
6
|
+
* + app-record field + runtime delivery — a platform-lane slice sharing this
|
|
7
|
+
* schema), the widget (defaults to the app's configured theme), and portal
|
|
8
|
+
* (defaults to the GUUEY theme, per-app override).
|
|
9
|
+
*
|
|
10
|
+
* EVOLUTION RULE (spec §6): this schema becomes PERSISTED platform data —
|
|
11
|
+
* changes are additive-only, parsing is LENIENT (unknown keys pass through,
|
|
12
|
+
* never rejected), and every new token ships with a default-theme fallback.
|
|
13
|
+
* A stored theme from any earlier schema version must always parse:
|
|
14
|
+
* `resolveTheme` merges per-token over the default, so a half-configured (or
|
|
15
|
+
* old-schema) app theme can never produce an unreadable surface.
|
|
16
|
+
*
|
|
17
|
+
* The React kit (3b) projects these as `--guuey-chat-*` CSS custom
|
|
18
|
+
* properties; RN (3c) maps the same object to style values — the schema is
|
|
19
|
+
* the cross-platform contract, CSS is one projection.
|
|
20
|
+
*/
|
|
21
|
+
import { z } from "zod";
|
|
22
|
+
/**
|
|
23
|
+
* One mode's palette — grounded in the widget's shipped `--guuey-*`
|
|
24
|
+
* custom-property precedent (`apps/widget/src/app/globals.css`).
|
|
25
|
+
*/
|
|
26
|
+
export declare const GuueyChatPalette: z.ZodObject<{
|
|
27
|
+
accent: z.ZodString;
|
|
28
|
+
onAccent: z.ZodString;
|
|
29
|
+
ink: z.ZodString;
|
|
30
|
+
inkMuted: z.ZodString;
|
|
31
|
+
surface: z.ZodString;
|
|
32
|
+
canvas: z.ZodString;
|
|
33
|
+
canvasMuted: z.ZodString;
|
|
34
|
+
error: z.ZodString;
|
|
35
|
+
}, z.core.$loose>;
|
|
36
|
+
export type GuueyChatPalette = z.infer<typeof GuueyChatPalette>;
|
|
37
|
+
export declare const GuueyChatTheme: z.ZodObject<{
|
|
38
|
+
name: z.ZodString;
|
|
39
|
+
colors: z.ZodObject<{
|
|
40
|
+
light: z.ZodObject<{
|
|
41
|
+
accent: z.ZodString;
|
|
42
|
+
onAccent: z.ZodString;
|
|
43
|
+
ink: z.ZodString;
|
|
44
|
+
inkMuted: z.ZodString;
|
|
45
|
+
surface: z.ZodString;
|
|
46
|
+
canvas: z.ZodString;
|
|
47
|
+
canvasMuted: z.ZodString;
|
|
48
|
+
error: z.ZodString;
|
|
49
|
+
}, z.core.$loose>;
|
|
50
|
+
dark: z.ZodObject<{
|
|
51
|
+
accent: z.ZodString;
|
|
52
|
+
onAccent: z.ZodString;
|
|
53
|
+
ink: z.ZodString;
|
|
54
|
+
inkMuted: z.ZodString;
|
|
55
|
+
surface: z.ZodString;
|
|
56
|
+
canvas: z.ZodString;
|
|
57
|
+
canvasMuted: z.ZodString;
|
|
58
|
+
error: z.ZodString;
|
|
59
|
+
}, z.core.$loose>;
|
|
60
|
+
}, z.core.$loose>;
|
|
61
|
+
typography: z.ZodObject<{
|
|
62
|
+
fontFamily: z.ZodOptional<z.ZodString>;
|
|
63
|
+
monoFontFamily: z.ZodOptional<z.ZodString>;
|
|
64
|
+
scale: z.ZodOptional<z.ZodNumber>;
|
|
65
|
+
}, z.core.$loose>;
|
|
66
|
+
shape: z.ZodObject<{
|
|
67
|
+
radius: z.ZodEnum<{
|
|
68
|
+
none: "none";
|
|
69
|
+
soft: "soft";
|
|
70
|
+
round: "round";
|
|
71
|
+
}>;
|
|
72
|
+
density: z.ZodEnum<{
|
|
73
|
+
compact: "compact";
|
|
74
|
+
comfortable: "comfortable";
|
|
75
|
+
}>;
|
|
76
|
+
}, z.core.$loose>;
|
|
77
|
+
}, z.core.$loose>;
|
|
78
|
+
export type GuueyChatTheme = z.infer<typeof GuueyChatTheme>;
|
|
79
|
+
/**
|
|
80
|
+
* The brand-neutral-but-polished package default — the theme a builder gets
|
|
81
|
+
* before configuring anything, and the per-token fallback floor every other
|
|
82
|
+
* theme resolves against.
|
|
83
|
+
*/
|
|
84
|
+
export declare const DEFAULT_CHAT_THEME: GuueyChatTheme;
|
|
85
|
+
/**
|
|
86
|
+
* The guuey visual identity — portal's default, and the look an app
|
|
87
|
+
* "unleashes" its own theme against. Values are the widget's shipped
|
|
88
|
+
* slime/ink/fog tokens verbatim; the saturated accents deliberately do not
|
|
89
|
+
* change between modes (they read the same on any canvas — the widget's own
|
|
90
|
+
* documented posture).
|
|
91
|
+
*/
|
|
92
|
+
export declare const GUUEY_CHAT_THEME: GuueyChatTheme;
|
|
93
|
+
/**
|
|
94
|
+
* Resolve a stored (possibly partial, possibly old-schema, possibly not even
|
|
95
|
+
* object-shaped) theme against a base — per-token fallback, lenient parse.
|
|
96
|
+
* NEVER throws: unparseable input resolves to the base theme untouched.
|
|
97
|
+
*/
|
|
98
|
+
export declare function resolveTheme(candidate: unknown, base?: GuueyChatTheme): GuueyChatTheme;
|
|
99
|
+
//# sourceMappingURL=theme.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"theme.d.ts","sourceRoot":"","sources":["../src/theme.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;;GAGG;AACH,eAAO,MAAM,gBAAgB;;;;;;;;;iBAWnB,CAAC;AACX,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAEhE,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAmBjB,CAAC;AACX,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAC;AAE5D;;;;GAIG;AACH,eAAO,MAAM,kBAAkB,EAAE,cA0BhC,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,gBAAgB,EAAE,cA0B9B,CAAC;AA0CF;;;;GAIG;AACH,wBAAgB,YAAY,CAC1B,SAAS,EAAE,OAAO,EAClB,IAAI,GAAE,cAAmC,GACxC,cAAc,CAgBhB"}
|
package/dist/theme.js
ADDED
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Theme = platform data (wave-3a design §6, founder-ratified).
|
|
3
|
+
*
|
|
4
|
+
* ONE serializable token schema, four consumers: this package's default
|
|
5
|
+
* theme, the per-app theme configured on platform.guuey.com (console editor
|
|
6
|
+
* + app-record field + runtime delivery — a platform-lane slice sharing this
|
|
7
|
+
* schema), the widget (defaults to the app's configured theme), and portal
|
|
8
|
+
* (defaults to the GUUEY theme, per-app override).
|
|
9
|
+
*
|
|
10
|
+
* EVOLUTION RULE (spec §6): this schema becomes PERSISTED platform data —
|
|
11
|
+
* changes are additive-only, parsing is LENIENT (unknown keys pass through,
|
|
12
|
+
* never rejected), and every new token ships with a default-theme fallback.
|
|
13
|
+
* A stored theme from any earlier schema version must always parse:
|
|
14
|
+
* `resolveTheme` merges per-token over the default, so a half-configured (or
|
|
15
|
+
* old-schema) app theme can never produce an unreadable surface.
|
|
16
|
+
*
|
|
17
|
+
* The React kit (3b) projects these as `--guuey-chat-*` CSS custom
|
|
18
|
+
* properties; RN (3c) maps the same object to style values — the schema is
|
|
19
|
+
* the cross-platform contract, CSS is one projection.
|
|
20
|
+
*/
|
|
21
|
+
import { z } from "zod";
|
|
22
|
+
/**
|
|
23
|
+
* One mode's palette — grounded in the widget's shipped `--guuey-*`
|
|
24
|
+
* custom-property precedent (`apps/widget/src/app/globals.css`).
|
|
25
|
+
*/
|
|
26
|
+
export const GuueyChatPalette = z
|
|
27
|
+
.object({
|
|
28
|
+
accent: z.string(),
|
|
29
|
+
onAccent: z.string(),
|
|
30
|
+
ink: z.string(),
|
|
31
|
+
inkMuted: z.string(),
|
|
32
|
+
surface: z.string(),
|
|
33
|
+
canvas: z.string(),
|
|
34
|
+
canvasMuted: z.string(),
|
|
35
|
+
error: z.string(),
|
|
36
|
+
})
|
|
37
|
+
.loose();
|
|
38
|
+
export const GuueyChatTheme = z
|
|
39
|
+
.object({
|
|
40
|
+
name: z.string(),
|
|
41
|
+
/** BOTH palettes always present — mode is the consumer's runtime choice. */
|
|
42
|
+
colors: z.object({ light: GuueyChatPalette, dark: GuueyChatPalette }).loose(),
|
|
43
|
+
typography: z
|
|
44
|
+
.object({
|
|
45
|
+
fontFamily: z.string().optional(),
|
|
46
|
+
monoFontFamily: z.string().optional(),
|
|
47
|
+
scale: z.number().optional(),
|
|
48
|
+
})
|
|
49
|
+
.loose(),
|
|
50
|
+
shape: z
|
|
51
|
+
.object({
|
|
52
|
+
radius: z.enum(["none", "soft", "round"]),
|
|
53
|
+
density: z.enum(["compact", "comfortable"]),
|
|
54
|
+
})
|
|
55
|
+
.loose(),
|
|
56
|
+
})
|
|
57
|
+
.loose();
|
|
58
|
+
/**
|
|
59
|
+
* The brand-neutral-but-polished package default — the theme a builder gets
|
|
60
|
+
* before configuring anything, and the per-token fallback floor every other
|
|
61
|
+
* theme resolves against.
|
|
62
|
+
*/
|
|
63
|
+
export const DEFAULT_CHAT_THEME = {
|
|
64
|
+
name: "default",
|
|
65
|
+
colors: {
|
|
66
|
+
light: {
|
|
67
|
+
accent: "#2f6bff",
|
|
68
|
+
onAccent: "#ffffff",
|
|
69
|
+
ink: "#111318",
|
|
70
|
+
inkMuted: "#5b6270",
|
|
71
|
+
surface: "#ffffff",
|
|
72
|
+
canvas: "#f7f7f5",
|
|
73
|
+
canvasMuted: "#eceded",
|
|
74
|
+
error: "#d64545",
|
|
75
|
+
},
|
|
76
|
+
dark: {
|
|
77
|
+
accent: "#5c8dff",
|
|
78
|
+
onAccent: "#0b0d12",
|
|
79
|
+
ink: "#e8e9ee",
|
|
80
|
+
inkMuted: "#9aa0ac",
|
|
81
|
+
surface: "#1b1e26",
|
|
82
|
+
canvas: "#0f1116",
|
|
83
|
+
canvasMuted: "#1b1e26",
|
|
84
|
+
error: "#ff6b6b",
|
|
85
|
+
},
|
|
86
|
+
},
|
|
87
|
+
typography: {},
|
|
88
|
+
shape: { radius: "soft", density: "comfortable" },
|
|
89
|
+
};
|
|
90
|
+
/**
|
|
91
|
+
* The guuey visual identity — portal's default, and the look an app
|
|
92
|
+
* "unleashes" its own theme against. Values are the widget's shipped
|
|
93
|
+
* slime/ink/fog tokens verbatim; the saturated accents deliberately do not
|
|
94
|
+
* change between modes (they read the same on any canvas — the widget's own
|
|
95
|
+
* documented posture).
|
|
96
|
+
*/
|
|
97
|
+
export const GUUEY_CHAT_THEME = {
|
|
98
|
+
name: "guuey",
|
|
99
|
+
colors: {
|
|
100
|
+
light: {
|
|
101
|
+
accent: "#b8ff3a",
|
|
102
|
+
onAccent: "#0e1014",
|
|
103
|
+
ink: "#0e1014",
|
|
104
|
+
inkMuted: "#1a1d24",
|
|
105
|
+
surface: "#ffffff",
|
|
106
|
+
canvas: "#f6f5ee",
|
|
107
|
+
canvasMuted: "#ecebe0",
|
|
108
|
+
error: "#ff5b5b",
|
|
109
|
+
},
|
|
110
|
+
dark: {
|
|
111
|
+
accent: "#b8ff3a",
|
|
112
|
+
onAccent: "#0e1014",
|
|
113
|
+
ink: "#e7e8ec",
|
|
114
|
+
inkMuted: "#9aa0ac",
|
|
115
|
+
surface: "#1a1d24",
|
|
116
|
+
canvas: "#0e1014",
|
|
117
|
+
canvasMuted: "#1a1d24",
|
|
118
|
+
error: "#ff5b5b",
|
|
119
|
+
},
|
|
120
|
+
},
|
|
121
|
+
typography: {},
|
|
122
|
+
shape: { radius: "soft", density: "comfortable" },
|
|
123
|
+
};
|
|
124
|
+
/** The candidate shape `resolveTheme` accepts: anything partial, unknown, or stale. */
|
|
125
|
+
const PartialPalette = GuueyChatPalette.partial();
|
|
126
|
+
const PartialTheme = z
|
|
127
|
+
.object({
|
|
128
|
+
name: z.string().optional(),
|
|
129
|
+
colors: z
|
|
130
|
+
.object({ light: PartialPalette.optional(), dark: PartialPalette.optional() })
|
|
131
|
+
.loose()
|
|
132
|
+
.optional(),
|
|
133
|
+
typography: GuueyChatTheme.shape.typography.optional(),
|
|
134
|
+
shape: GuueyChatTheme.shape.shape.partial().loose().optional(),
|
|
135
|
+
})
|
|
136
|
+
.loose();
|
|
137
|
+
/** The known token set — the per-token fallback iterates THIS, so unknown
|
|
138
|
+
* (future-schema) keys are preserved by the parse but never projected. */
|
|
139
|
+
const PALETTE_TOKENS = [
|
|
140
|
+
"accent",
|
|
141
|
+
"onAccent",
|
|
142
|
+
"ink",
|
|
143
|
+
"inkMuted",
|
|
144
|
+
"surface",
|
|
145
|
+
"canvas",
|
|
146
|
+
"canvasMuted",
|
|
147
|
+
"error",
|
|
148
|
+
];
|
|
149
|
+
function mergePalette(base, over) {
|
|
150
|
+
if (!over)
|
|
151
|
+
return { ...base };
|
|
152
|
+
const merged = { ...base };
|
|
153
|
+
for (const token of PALETTE_TOKENS) {
|
|
154
|
+
const value = over[token];
|
|
155
|
+
if (typeof value === "string")
|
|
156
|
+
merged[token] = value;
|
|
157
|
+
}
|
|
158
|
+
return merged;
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Resolve a stored (possibly partial, possibly old-schema, possibly not even
|
|
162
|
+
* object-shaped) theme against a base — per-token fallback, lenient parse.
|
|
163
|
+
* NEVER throws: unparseable input resolves to the base theme untouched.
|
|
164
|
+
*/
|
|
165
|
+
export function resolveTheme(candidate, base = DEFAULT_CHAT_THEME) {
|
|
166
|
+
const parsed = PartialTheme.safeParse(candidate);
|
|
167
|
+
if (!parsed.success)
|
|
168
|
+
return { ...base, colors: { light: { ...base.colors.light }, dark: { ...base.colors.dark } } };
|
|
169
|
+
const p = parsed.data;
|
|
170
|
+
return {
|
|
171
|
+
name: p.name ?? base.name,
|
|
172
|
+
colors: {
|
|
173
|
+
light: mergePalette(base.colors.light, p.colors?.light),
|
|
174
|
+
dark: mergePalette(base.colors.dark, p.colors?.dark),
|
|
175
|
+
},
|
|
176
|
+
typography: { ...base.typography, ...(p.typography ?? {}) },
|
|
177
|
+
shape: {
|
|
178
|
+
radius: p.shape?.radius ?? base.shape.radius,
|
|
179
|
+
density: p.shape?.density ?? base.shape.density,
|
|
180
|
+
},
|
|
181
|
+
};
|
|
182
|
+
}
|