@celestia-island/hikari 0.55.149 → 0.55.150

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/package.json +1 -1
  2. package/src/animation/registerAnimations.ts +0 -1
  3. package/src/components/HkConnectionStatus.shell.test.tsx +34 -0
  4. package/src/components/HkConnectionStatus.tsx +31 -10
  5. package/src/components/HkThemeDecor.test.tsx +11 -22
  6. package/src/components/HkThemeDecor.tsx +1 -1
  7. package/src/components/StatusTrayDecor.mount.test.ts +35 -0
  8. package/src/components/{HkStatusTray.size.test.ts → StatusTrayDecor.size.test.ts} +7 -3
  9. package/src/components/{HkStatusTray.test.tsx → StatusTrayDecor.test.tsx} +3 -2
  10. package/src/components/themeDecorLayout.contract.test.ts +6 -6
  11. package/src/composables/engineHealthTypes.ts +50 -0
  12. package/src/i18n/usageSurface.test.ts +0 -1
  13. package/src/index.ts +2 -102
  14. package/src/theme/standardDecor.test.ts +14 -13
  15. package/src/theme/standardDecor.ts +7 -3
  16. package/src/theme/themeDecorSurface.test.ts +5 -3
  17. package/src/utils/format.ts +0 -11
  18. package/src/components/HkAttachmentModal.scss +0 -49
  19. package/src/components/HkAttachmentModal.tsx +0 -318
  20. package/src/components/HkChatTypes.ts +0 -65
  21. package/src/components/HkContextRing.scss +0 -136
  22. package/src/components/HkContextRing.test.tsx +0 -309
  23. package/src/components/HkContextRing.tsx +0 -276
  24. package/src/components/HkModelCatalog.test.ts +0 -81
  25. package/src/components/HkModelCatalog.ts +0 -330
  26. package/src/components/HkModelTag.scss +0 -171
  27. package/src/components/HkModelTag.test.tsx +0 -155
  28. package/src/components/HkModelTag.tsx +0 -219
  29. package/src/components/HkRichInput.scss +0 -178
  30. package/src/components/HkRichInput.tsx +0 -335
  31. package/src/components/HkStatusTray.scss +0 -36
  32. package/src/components/HkStatusTray.tsx +0 -187
  33. package/src/components/HkTokenUsageBadge.scss +0 -50
  34. package/src/components/HkTokenUsageBadge.test.tsx +0 -59
  35. package/src/components/HkTokenUsageBadge.tsx +0 -54
  36. package/src/components/HkTokenUsagePanel.scss +0 -100
  37. package/src/components/HkTokenUsagePanel.tsx +0 -140
  38. package/src/components/HkToolBlock.scss +0 -327
  39. package/src/components/HkToolBlock.tsx +0 -394
  40. package/src/components/HkToolBlock.windowScroll.contract.test.ts +0 -93
  41. package/src/components/HkVoiceInputPopup.scss +0 -82
  42. package/src/components/HkVoiceInputPopup.tsx +0 -97
  43. package/src/composables/useAttachments.ts +0 -154
  44. package/src/composables/useConnectionProbe.test.ts +0 -179
  45. package/src/composables/useConnectionProbe.ts +0 -201
  46. package/src/composables/useEngineHealth.test.ts +0 -128
  47. package/src/composables/useEngineHealth.ts +0 -93
  48. package/src/composables/useSendShortcut.ts +0 -35
  49. package/src/i18n/contextKeys.test.ts +0 -52
  50. package/src/i18n/locales/ar/chat.json +0 -49
  51. package/src/i18n/locales/de/chat.json +0 -49
  52. package/src/i18n/locales/en/chat.json +0 -49
  53. package/src/i18n/locales/es/chat.json +0 -49
  54. package/src/i18n/locales/fr/chat.json +0 -49
  55. package/src/i18n/locales/ja/chat.json +0 -49
  56. package/src/i18n/locales/ko/chat.json +0 -49
  57. package/src/i18n/locales/pt/chat.json +0 -49
  58. package/src/i18n/locales/ru/chat.json +0 -49
  59. package/src/i18n/locales/zh-Hans/chat.json +0 -49
  60. package/src/i18n/locales/zh-Hant/chat.json +0 -49
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@celestia-island/hikari",
3
- "version": "0.55.149",
3
+ "version": "0.55.150",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "description": "Hikari Vue 3 component library — production-grade UI components based on shittim-chest design system",
@@ -110,7 +110,6 @@ registerCssAnimation("hk-flip-out");
110
110
  registerCssAnimation("hk-flip-in");
111
111
  // components/HkVoiceInputPopup.scss — voice waveform bounce (loops
112
112
  // forever while listening; upstreamed from chest's plana-legacy).
113
- registerCssAnimation("s-voice-wave-bounce", { infinite: true });
114
113
  // components/HkPlaceholderMarquee.scss — overflowing placeholder sweep
115
114
  // (loops forever; pure CSS, loop geometry on inline custom properties).
116
115
  registerCssAnimation("hk-placeholder-marquee-scroll", { infinite: true });
@@ -0,0 +1,34 @@
1
+ import { afterEach, describe, expect, it, vi } from "vitest";
2
+ import { createApp, h } from "vue";
3
+
4
+ import { HkConnectionStatus } from "./HkConnectionStatus";
5
+
6
+ /** The shell contract: WITHOUT injections the component never touches
7
+ * the network — the fetch-poll was demoted with the chat kit (the M1
8
+ * mutation guard: a fetch in the fallback path must go red here). */
9
+ const mounts: Array<{ app: ReturnType<typeof createApp>; container: HTMLElement }> = [];
10
+ afterEach(() => {
11
+ for (const { app, container } of mounts.splice(0)) {
12
+ app.unmount();
13
+ container.remove();
14
+ }
15
+ });
16
+
17
+ describe("HkConnectionStatus (shell)", () => {
18
+ it("renders an inert unknown state with zero network calls", () => {
19
+ const fetchSpy = vi.fn();
20
+ const holder = globalThis.fetch;
21
+ globalThis.fetch = fetchSpy as unknown as typeof fetch;
22
+ try {
23
+ const container = document.createElement("div");
24
+ document.body.appendChild(container);
25
+ const app = createApp({ render: () => h(HkConnectionStatus, { standalone: true }) });
26
+ app.mount(container);
27
+ mounts.push({ app, container });
28
+ expect(fetchSpy).not.toHaveBeenCalled();
29
+ expect(container.textContent ?? "").not.toBeNull();
30
+ } finally {
31
+ globalThis.fetch = holder;
32
+ }
33
+ });
34
+ });
@@ -1,8 +1,7 @@
1
- import { computed, defineComponent, inject, type InjectionKey, type PropType, type Ref } from "vue";
1
+ import { computed, defineComponent, inject, ref, type InjectionKey, type PropType, type Ref } from "vue";
2
2
 
3
3
  import { useI18n } from "../i18n/context";
4
- import { useConnectionProbe, type ProbeResult } from "../composables/useConnectionProbe";
5
- import { useEngineHealth } from "../composables/useEngineHealth";
4
+ import type { EngineHealth, EngineNetworkInfo, ProbeResult } from "../composables/engineHealthTypes";
6
5
 
7
6
  import { HkStatusBar } from "./HkStatusBar";
8
7
  import {
@@ -28,6 +27,25 @@ export interface HkConnectionProbeSource {
28
27
  }
29
28
 
30
29
  /** Injection key for the connection-probe overload (see above). */
30
+ /** Engine-health source a host provides (the demoted fetch's
31
+ * replacement): a ref of the /api/health envelope, or null. */
32
+ export const HK_ENGINE_HEALTH: InjectionKey<Ref<EngineHealth | null>> = Symbol(
33
+ "HK_ENGINE_HEALTH",
34
+ );
35
+
36
+ /** The shell's inert probe — no network, no timers: "unknown". */
37
+ const INERT_PROBE: ProbeResult = {
38
+ connected: false,
39
+ state: "disconnected",
40
+ transportTier: "unknown",
41
+ tier: "unknown",
42
+ latencyMs: null,
43
+ attemptNumber: 0,
44
+ retryCount: 0,
45
+ retryTotal: 0,
46
+ countdown: 0,
47
+ };
48
+
31
49
  export const HK_CONNECTION_PROBE: InjectionKey<HkConnectionProbeSource> =
32
50
  Symbol("HkConnectionProbe");
33
51
 
@@ -45,7 +63,8 @@ const backendStateColor: Record<HkBackendStatus["state"], string> = {
45
63
  * Composes useConnectionProbe + useEngineHealth + useConnectionInfo +
46
64
  * HkStatusBar. The probe source is injectable: when a parent provides
47
65
  * HK_CONNECTION_PROBE, that probe (and its retryNow) is used verbatim;
48
- * otherwise hikari's own fetch-poll useConnectionProbe() runs. Slots:
66
+ * without an injection the shell renders an inert unknown state and
67
+ * NEVER touches the network (pinned). Slots:
49
68
  * - `left` — extras after the status tags (e.g. a mock badge)
50
69
  * - `right` — extras on the far right (e.g. an engine version tag)
51
70
  */
@@ -54,19 +73,21 @@ export const HkConnectionStatus = defineComponent({
54
73
  props: {
55
74
  version: { type: String, default: "0.1.0" },
56
75
  panelBuildHash: { type: String as PropType<string | undefined>, default: undefined },
57
- /** API origin for the /api/health probe (defaults to same-origin ""). */
58
- baseUrl: { type: String as PropType<string | undefined>, default: undefined },
59
76
  backendStatus: { type: Object as PropType<HkBackendStatus | undefined>, default: undefined },
60
77
  standalone: { type: Boolean, default: true },
61
78
  /** Forwarded to HkStatusBar — collapse to the traffic-light dot. */
62
79
  compact: { type: Boolean, default: false },
63
80
  },
64
81
  setup(props, { slots }) {
65
- // Probe-source overload: a host app (chest) provides its own
66
- // RpcClient-driven probe; everyone else gets hikari's fetch-poll.
82
+ // SHELL-ONLY: the network side (WHO polls /api/health and HOW)
83
+ // lives in the host — injected via HK_CONNECTION_PROBE /
84
+ // HK_ENGINE_HEALTH. Without an injection the shell renders an
85
+ // inert unknown state and never touches the network (the
86
+ // fetch-poll defaults were demoted with the chat kit wave).
67
87
  const injectedProbe = inject(HK_CONNECTION_PROBE, null);
68
- const { result: probe, retryNow } = injectedProbe ?? useConnectionProbe();
69
- const { health } = useEngineHealth(props.baseUrl);
88
+ const probe = injectedProbe?.result ?? ref(INERT_PROBE);
89
+ const retryNow = injectedProbe?.retryNow ?? (() => {});
90
+ const health = inject(HK_ENGINE_HEALTH, ref<EngineHealth | null>(null));
70
91
 
71
92
  const connectionState = computed<ConnectionStateInput>(() => probe.value.state);
72
93
  const transportTier = computed(() => probe.value.transportTier);
@@ -175,29 +175,18 @@ describe("HkThemeDecor", () => {
175
175
  expect(seen.at(-1)).toMatchObject({ variant: "host", kept: 1 });
176
176
  });
177
177
 
178
- it("lets a theme replace the built-in tray end to end (the TRAY_DECORS replacement path)", async () => {
179
- // The per-theme decoration table chest kept inside its tray component is
180
- // gone: a theme ships its own tray by registering a component for this
181
- // slot under its own id, and hikari's built-in tray answers for every
182
- // other theme.
183
- registerStandardThemeDecor();
184
- const { setTheme } = useTheme();
185
- const themedTray = defineComponent({
186
- name: "ThemedTray",
187
- setup: () => () => h("i", { "data-decor": "themed-tray" }),
178
+ it("renders a theme tray over the now-empty builtin floor", async () => {
179
+ // The builtin status.tray floor is EMPTY since the demotion wave —
180
+ // the default theme package fills it via the "*" wildcard, and any
181
+ // exact-theme registration wins over that. Here: only the themed
182
+ // tray renders.
183
+ const ThemedTray = defineComponent({
184
+ setup: () => () => h("div", { "data-decor": "themed-tray" }),
188
185
  });
189
- registerThemeDecor({ themeId: "endfield", slot: "status.tray", component: themedTray });
190
-
191
- const container = mount(h(HkThemeDecor, { slot: "status.tray" }));
192
-
193
- setTheme("endfield");
194
- await nextTick();
195
- expect(container.querySelector('[data-decor="themed-tray"]')).not.toBeNull();
196
- expect(container.querySelector(".s-status-bar-system-tray")).toBeNull();
197
-
198
- setTheme("default");
186
+ registerThemeDecor({ themeId: "t", slot: "status.tray", component: ThemedTray });
187
+ useTheme().setTheme("t");
188
+ const host = mount(h(HkThemeDecor, { slot: "status.tray" }));
199
189
  await nextTick();
200
- expect(container.querySelector('[data-decor="themed-tray"]')).toBeNull();
201
- expect(container.querySelector(".s-status-bar-system-tray")).not.toBeNull();
190
+ expect(host.querySelector('[data-decor="themed-tray"]')).not.toBeNull();
202
191
  });
203
192
  });
@@ -50,7 +50,7 @@ import { useTheme } from "../theme/useTheme";
50
50
  * that wants numeric sizing declares its own prop and receives it through
51
51
  * `decorProps`.
52
52
  *
53
- * The ladder is the CONTRACT's, not any one decor's: `HkStatusTray`
53
+ * The ladder is the CONTRACT's, not any one decor's: the default theme's tray
54
54
  * implements `sm | md | lg` only, so asking it for `xs` publishes no
55
55
  * `--hk-tray-*` var at all and the sheet's `var(--hk-tray-glyph, 9px)`
56
56
  * fallbacks render the shipped (md) geometry. That degradation is pinned by
@@ -0,0 +1,35 @@
1
+ import { describe, expect, it } from "vitest";
2
+
3
+ import StatusTrayDecor from "../../../default_theme/src/StatusTrayDecor";
4
+ // The one-import contract under test: importing the package index IS the
5
+ // mount (README: `import "@celestia-island/default-theme"` — CSS + decor).
6
+ import "../../../default_theme/src/index";
7
+ import { getThemeDecor } from "../theme/themeDecor";
8
+
9
+ /**
10
+ * @celestia-island/default-theme's delivery mechanism: a bare import of the
11
+ * package mounts the tray decor on the "*" wildcard via registerThemeDecor,
12
+ * so every theme (and themeless hosts) resolve it without any host glue.
13
+ *
14
+ * This pin lives in the vue suite because default_theme ships no runner of
15
+ * its own — the vue suite is the only vitest root (CI: ci-hosted.yml) — and
16
+ * the registry it asserts against is hikari's own. It goes red if the
17
+ * side-effect call disappears from the package index (the "explicit
18
+ * mountDefaultTheme()" escape hatch is a replacement, not a supplement).
19
+ */
20
+ describe("@celestia-island/default-theme side-effect mount", () => {
21
+ it("a bare import of the package mounts the tray on the '*' wildcard", () => {
22
+ const resolved = getThemeDecor("status.tray", "any-theme-id");
23
+ expect(resolved, "status.tray resolves after the bare import").toBeDefined();
24
+ // And it is THE decor component — not merely some entry — so the
25
+ // wildcard registration cannot silently drift to another component.
26
+ expect(resolved?.component).toBe(StatusTrayDecor);
27
+ });
28
+
29
+ it("outranks the builtin floor without touching it (the override path)", () => {
30
+ // The builtin floor for status.tray is deliberately empty (pinned in
31
+ // standardDecor.test.ts); the wildcard entry is the ONLY reason the
32
+ // slot resolves. Same lookup through the star id lands on it too.
33
+ expect(getThemeDecor("status.tray", "*")?.component).toBe(StatusTrayDecor);
34
+ });
35
+ });
@@ -6,7 +6,7 @@ import { compile } from "sass";
6
6
  import { describe, expect, it } from "vitest";
7
7
  import { createApp, h } from "vue";
8
8
 
9
- import HkStatusTray, { HK_TRAY_SIZE_VARS, type HkStatusTraySize } from "./HkStatusTray";
9
+ import HkStatusTray, { HK_TRAY_SIZE_VARS, type HkStatusTraySize } from "../../../default_theme/src/StatusTrayDecor";
10
10
 
11
11
  /**
12
12
  * The "md is pixel-identical to what already ships" contract.
@@ -18,7 +18,7 @@ import HkStatusTray, { HK_TRAY_SIZE_VARS, type HkStatusTraySize } from "./HkStat
18
18
  *
19
19
  * 1. the shipped admin-tokens rules (the source of truth),
20
20
  * 2. the component's `md` row in HK_TRAY_SIZE_VARS,
21
- * 3. the fallbacks in HkStatusTray.scss.
21
+ * 3. the fallbacks in StatusTrayDecor.scss (packages/default_theme).
22
22
  *
23
23
  * This guard reads (1) out of the COMPILED sheet — not a hand-copied list —
24
24
  * and holds (2) and (3) to it, so moving any one of them alone fails here
@@ -67,7 +67,11 @@ function specificity(selector: string): number {
67
67
  }
68
68
 
69
69
  const adminCss = compileSheet(resolve(stylesDir, "admin-tokens.scss"));
70
- const trayCss = compileSheet(resolve(componentDir, "HkStatusTray.scss"));
70
+ // The tray decor itself lives in packages/default_theme now; the shared
71
+ // sheets it is held against (admin-tokens.scss, scale.scss) stayed here.
72
+ const trayCss = compileSheet(
73
+ resolve(componentDir, "../../../default_theme/src/StatusTrayDecor.scss"),
74
+ );
71
75
  const scaleVars: Record<string, string> = {};
72
76
  for (const m of readFileSync(resolve(srcDir, "scale.scss"), "utf8")
73
77
  .replace(/\/\*[\s\S]*?\*\//g, "")
@@ -2,7 +2,7 @@ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
2
2
  import { createApp, h, nextTick } from "vue";
3
3
 
4
4
  import { readHkRuntime } from "../runtime/registry";
5
- import HkStatusTray from "./HkStatusTray";
5
+ import HkStatusTray from "../../../default_theme/src/StatusTrayDecor";
6
6
 
7
7
  /**
8
8
  * HkStatusTray behaviour: the gamepad cluster + clock surface, its size and
@@ -10,7 +10,8 @@ import HkStatusTray from "./HkStatusTray";
10
10
  * teardown of both intervals.
11
11
  *
12
12
  * The "md equals the shipped CSS" contract lives next door in
13
- * `HkStatusTray.size.test.ts` (it reads the sheets, not the DOM).
13
+ * `StatusTrayDecor.size.test.ts` (it reads the sheets, not the DOM —
14
+ * the decor itself lives in packages/default_theme).
14
15
  */
15
16
 
16
17
  const mounts: Array<{ app: ReturnType<typeof createApp>; container: HTMLElement }> = [];
@@ -50,7 +50,6 @@ interface Target {
50
50
 
51
51
  const TARGETS: Target[] = [
52
52
  { file: "HkThemeDecor.tsx", anchor: "HkThemeDecor" },
53
- { file: "HkStatusTray.tsx", anchor: "s-status-bar-system-tray" },
54
53
  { file: "HkStatusTray.scss", anchor: "s-status-bar-system-tray" },
55
54
  ];
56
55
 
@@ -102,10 +101,11 @@ describe("theme decor layout contract", () => {
102
101
  });
103
102
 
104
103
  it("scans existing files that carry the expected content (no empty scan)", () => {
105
- expect(TARGETS.length).toBeGreaterThan(0);
106
- for (const { file, anchor } of TARGETS) {
107
- const path = resolve(componentDir, file);
108
- expect(existsSync(path), `${file} exists`).toBe(true);
104
+ // The tray decor moved to packages/default_theme (the demotion
105
+ // wave); only the files still living here are scanned.
106
+ const present = TARGETS.filter(({ file }) => existsSync(resolve(componentDir, file)));
107
+ expect(present.length, "at least one target still in-tree").toBeGreaterThan(0);
108
+ for (const { file, anchor } of present) {
109
109
  const source = read(file);
110
110
  expect(source.length, `${file} is not empty`).toBeGreaterThan(50);
111
111
  expect(source, `${file} carries ${anchor}`).toContain(anchor);
@@ -113,7 +113,7 @@ describe("theme decor layout contract", () => {
113
113
  });
114
114
 
115
115
  it("keeps positioning out of the decor components and their sheets", () => {
116
- for (const { file } of TARGETS) {
116
+ for (const { file } of TARGETS.filter(({ file }) => existsSync(resolve(componentDir, file)))) {
117
117
  const hits = positionHits(file, read(file));
118
118
  expect(hits, `${file} must not position itself: ${JSON.stringify(hits)}`).toEqual([]);
119
119
  }
@@ -0,0 +1,50 @@
1
+ /** Engine-health DTOs — the SHELL side of the split (the fetch hook
2
+ * that fills them was demoted to the consuming app with the chat-kit
3
+ * wave; the shapes stay so HkConnectionStatus's injection contract is
4
+ * typed here). */
5
+
6
+ /** Connectivity probe result — the shape a host's injected probe
7
+ * (HK_CONNECTION_PROBE) exposes. The fetch implementation that
8
+ * produced it was demoted to the app; the shape stays as the shell's
9
+ * contract. */
10
+ export interface ProbeResult {
11
+ connected: boolean;
12
+ state: "connected" | "disconnected" | "connecting" | "reconnecting" | "failed";
13
+ /** Canonical transport tier ("local" | "ws" | "sse" | "poll"). */
14
+ transportTier: string;
15
+ /** @deprecated Use `transportTier`. Alias kept for compatibility. */
16
+ tier: string;
17
+ latencyMs: number | null;
18
+ /** Canonical 1-based connect-attempt counter. */
19
+ attemptNumber: number;
20
+ /** @deprecated Use `attemptNumber`. Alias kept for compatibility. */
21
+ retryCount: number;
22
+ retryTotal: number;
23
+ /** Seconds until the next automatic probe attempt. */
24
+ countdown: number;
25
+ }
26
+
27
+
28
+ /** Inlined subset of the `/api/health` network payload — kept local so
29
+ * hikari stays dependency-free of protocol packages. */
30
+ export interface NetworkInfo {
31
+ transport?: string;
32
+ region?: string;
33
+ asn?: number | null;
34
+ }
35
+
36
+ /** Inlined subset of the `/api/health` response envelope. */
37
+ export interface HealthResponse {
38
+ engine_version?: string;
39
+ build_hash?: string;
40
+ network?: NetworkInfo;
41
+ }
42
+
43
+ export type { NetworkInfo as EngineNetworkInfo };
44
+
45
+ /** Subset of `/api/health` relevant to status-bar style consumers. */
46
+ export interface EngineHealth {
47
+ engineVersion: string | null;
48
+ engineBuildHash: string | null;
49
+ network: NetworkInfo | null;
50
+ }
@@ -122,7 +122,6 @@ function scanSources(): { statics: Site[]; constructed: Site[] } {
122
122
  * every listed family must still exist in source, so this whitelist
123
123
  * cannot rot into silence. */
124
124
  const DYNAMIC_KEY_FAMILIES: Record<string, string> = {
125
- "hikari::context.": "HkContextRing section keys — closed enum, pinned by name in contextKeys.test.ts.",
126
125
  "hikari::statusBar.backend.": "HkConnectionStatus — enumerated connection-state suffixes.",
127
126
  "hikari::statusBar.region.": "HkStatusBar region names — OPTIONAL per-locale overrides over Intl.DisplayNames (see LOCALE_SPECIFIC_NESTED in flatKeyParity.test.ts).",
128
127
  "hikari::statusBar.tier.": "HkStatusBar transport tiers — constructed into a variable at a distance from its t() call (F1); the four concrete ids are pinned by name in CONSTRUCTED_FAMILY_KEYS below.",
package/src/index.ts CHANGED
@@ -124,30 +124,7 @@ export { default as HWaterfall } from "./components/HkWaterfall";
124
124
  export { default as HBlankCanvas } from "./components/HkBlankCanvas";
125
125
  export type { BlankCanvasSize } from "./components/HkBlankCanvas";
126
126
  export { default as HKanban } from "./components/HkKanban";
127
- export type {
128
- KanbanAxis,
129
- KanbanCardSlotProps,
130
- KanbanHeaderSlotProps,
131
- KanbanMove,
132
- } from "./components/HkKanban";
133
127
  export { default as HNodeCanvas, NODE_CANVAS_DEFAULTS } from "./components/HkNodeCanvas";
134
- export type {
135
- NodeCanvasCamera,
136
- NodeCanvasBounds,
137
- NodeCanvasSlotProps,
138
- MinimapPlacement,
139
- NodeCanvasEdge,
140
- EdgeRouting,
141
- EdgeSide,
142
- EdgeSubpath,
143
- EdgePointerEvent,
144
- } from "./components/HkNodeCanvas";
145
- export type {
146
- WaterfallBucket,
147
- WaterfallCardSlotProps,
148
- WaterfallHeaderSlotProps,
149
- WaterfallRailSlotProps,
150
- } from "./components/HkWaterfall";
151
128
  export { default as HDateTimePicker } from "./components/HkDateTimePicker";
152
129
  export { default as HDatePicker } from "./components/HkDatePicker";
153
130
  export { default as HTimeline } from "./components/HkTimeline";
@@ -251,7 +228,6 @@ export { type TrendPen, type TrendPoint, type AlarmThresholds } from "./componen
251
228
 
252
229
  // ── Theme decor (theme-provided decorative widgets, host-placed) ──────────
253
230
  export { default as HkThemeDecor, type HkThemeDecorSize } from "./components/HkThemeDecor";
254
- export { default as HkStatusTray, type HkStatusTraySize } from "./components/HkStatusTray";
255
231
 
256
232
  // Theme system
257
233
  export {
@@ -446,10 +422,6 @@ export { useApproachEnd } from "./composables/useApproachEnd";
446
422
  export type { ApproachEndOptions, ApproachEndHandle } from "./composables/useApproachEnd";
447
423
  export { useDeferredTransition } from "./composables/useDeferredTransition";
448
424
  export { useSurfaceTransition } from "./composables/useSurfaceTransition";
449
- export type {
450
- SurfaceTransition,
451
- SurfaceTransitionHooks,
452
- } from "./composables/useSurfaceTransition";
453
425
  export { useSizeMorph } from "./composables/useSizeMorph";
454
426
  export type { SizeMorph } from "./composables/useSizeMorph";
455
427
  export { useImage } from "./composables/useImage";
@@ -471,11 +443,6 @@ export {
471
443
  nearestLaidAncestor,
472
444
  placePoint,
473
445
  } from "./composables/layoutGeometry";
474
- export type {
475
- FrameMetrics,
476
- LayoutOffset,
477
- LayoutRect,
478
- } from "./composables/layoutGeometry";
479
446
  export { useMeasuredHighlight } from "./composables/useMeasuredHighlight";
480
447
  export type { UseMeasuredHighlightOptions, MeasuredHighlight } from "./composables/useMeasuredHighlight";
481
448
  export {
@@ -532,10 +499,6 @@ export {
532
499
  export { usePageTitle, useRouteTitle } from "./composables/usePageTitle";
533
500
  export { provideActionBar, useActionBar } from "./composables/useActionBar";
534
501
  export type { ActionBarRenderer } from "./composables/useActionBar";
535
- export { setProbeEndpoint, useConnectionProbe } from "./composables/useConnectionProbe";
536
- export type { ProbeResult } from "./composables/useConnectionProbe";
537
- export { useEngineHealth } from "./composables/useEngineHealth";
538
- export type { EngineHealth, EngineNetworkInfo } from "./composables/useEngineHealth";
539
502
  export { leadingZeroBits, sha256, solvePow, solvePowSync, verifyPow } from "./utils/pow";
540
503
  export type { PowChallenge, PowSolution } from "./utils/pow";
541
504
  export { HkLocalePicker as HLocalePicker } from "./components/HkLocalePicker";
@@ -570,13 +533,6 @@ export {
570
533
  } from "./components/HkSettingsDialog";
571
534
 
572
535
  export { HkCookieConsent as HCookieConsent } from "./components/HkCookieConsent";
573
- export {
574
- HkAttachmentModal as HAttachmentModal,
575
- previewKindFor,
576
- type HAttachmentDetail,
577
- type HAttachmentItem,
578
- type HAttachmentPreviewType,
579
- } from "./components/HkAttachmentModal";
580
536
  export { HkStatusBar as HStatusBar } from "./components/HkStatusBar";
581
537
  export { useConnectionInfo } from "./components/HkConnectionInfo";
582
538
  export type { ConnectionStateInput, HkConnectionInfo } from "./components/HkConnectionInfo";
@@ -587,67 +543,22 @@ export {
587
543
  type HkBackendStatus,
588
544
  type HkConnectionProbeSource,
589
545
  } from "./components/HkConnectionStatus";
546
+ export { HK_ENGINE_HEALTH } from "./components/HkConnectionStatus";
547
+ export type { ProbeResult, EngineHealth, EngineNetworkInfo } from "./composables/engineHealthTypes";
590
548
 
591
549
  // ── Chat kit (upstreamed from shittim-chest's plana-legacy layer) ──────────
592
- export { HkRichInput as HRichInput } from "./components/HkRichInput";
593
- export { HkVoiceInputPopup as HVoiceInputPopup } from "./components/HkVoiceInputPopup";
594
- export {
595
- HkToolBlock as HToolBlock,
596
- parseToolCallText,
597
- extractExecCode,
598
- buildHighlightedLines,
599
- type HParsedToolCall,
600
- type HToolBlockVariant,
601
- type HHighlightedLine,
602
- } from "./components/HkToolBlock";
603
550
  export {
604
551
  HkJsonTree as HJsonTree,
605
552
  buildJsonTree,
606
553
  type HJsonNode,
607
554
  } from "./components/HkJsonTree";
608
- export { HkTokenUsageBadge as HTokenUsageBadge } from "./components/HkTokenUsageBadge";
609
- export { HkTokenUsagePanel as HTokenUsagePanel } from "./components/HkTokenUsagePanel";
610
- export { HkModelTag as HModelTag } from "./components/HkModelTag";
611
- export { HkContextRing as HContextRing, HkContextRing, type HkContextSegment } from "./components/HkContextRing";
612
- export {
613
- getModelMeta,
614
- registerModelCatalog,
615
- splitModelId,
616
- type HModelPricing,
617
- type HModelMeta,
618
- type HModelCatalog,
619
- } from "./components/HkModelCatalog";
620
- export type {
621
- HChatRole,
622
- HToolCall,
623
- HToolCallStatus,
624
- HVoicePopupMode,
625
- HVoiceState,
626
- HModelUsageEntry,
627
- HModelCosts,
628
- } from "./components/HkChatTypes";
629
555
  // Canonical Hk* names for the directly-exported types above (2026-09-24
630
556
  // unification follow-up, second batch — caught by the third-scan reverse
631
557
  // validation). These types are defined with their H* names at the source.
632
- export type {
633
- HChatRole as HkChatRole,
634
- HToolCall as HkToolCall,
635
- HToolCallStatus as HkToolCallStatus,
636
- HVoicePopupMode as HkVoicePopupMode,
637
- HVoiceState as HkVoiceState,
638
- HModelUsageEntry as HkModelUsageEntry,
639
- HModelCosts as HkModelCosts,
640
- } from "./components/HkChatTypes";
641
- export { useSendShortcut } from "./composables/useSendShortcut";
642
- export type { SendShortcutMode } from "./composables/useSendShortcut";
643
- export { useAttachments } from "./composables/useAttachments";
644
- export type { HkUploadedFile } from "./composables/useAttachments";
645
558
 
646
559
  export {
647
- formatTokenCount,
648
560
  formatNumber,
649
561
  formatBytes,
650
- formatPriceUsd,
651
562
  formatRelativeTime,
652
563
  formatDateTime,
653
564
  formatDate,
@@ -861,27 +772,16 @@ export { HkSettingsGroup as HkSettingsGroup } from "./components/HkSettingsDialo
861
772
  export { HkSettingsSub as HkSettingsSub } from "./components/HkSettingsDialog";
862
773
  export { HkSettingsHint as HkSettingsHint } from "./components/HkSettingsDialog";
863
774
  export { HkCookieConsent as HkCookieConsent } from "./components/HkCookieConsent";
864
- export { HkAttachmentModal as HkAttachmentModal } from "./components/HkAttachmentModal";
865
775
  export { HkStatusBar as HkStatusBar, hkMergeVersionDisplay, hkParseIdentity } from "./components/HkStatusBar";
866
776
  export type { HkVersionIdentity } from "./components/HkStatusBar";
867
777
  export { HkCountdownDigit as HkCountdownDigit } from "./components/HkCountdownDigit";
868
778
  export { HkConnectionStatus as HkConnectionStatus } from "./components/HkConnectionStatus";
869
- export { HkRichInput as HkRichInput } from "./components/HkRichInput";
870
- export { HkVoiceInputPopup as HkVoiceInputPopup } from "./components/HkVoiceInputPopup";
871
- export { HkToolBlock as HkToolBlock } from "./components/HkToolBlock";
872
779
  export { HkJsonTree as HkJsonTree } from "./components/HkJsonTree";
873
- export { HkTokenUsageBadge as HkTokenUsageBadge } from "./components/HkTokenUsageBadge";
874
- export { HkTokenUsagePanel as HkTokenUsagePanel } from "./components/HkTokenUsagePanel";
875
- export { HkModelTag as HkModelTag } from "./components/HkModelTag";
876
780
 
877
781
  // Canonical Hk* names for directly-exported types (2026-09-24
878
782
  // unification follow-up). These types were defined with their H*
879
783
  // names at the source and exported directly — not aliased from an Hk*
880
784
  // identifier — so the canonical Hk* form is an alias export here.
881
- export { type HAttachmentItem as HkAttachmentItem } from "./components/HkAttachmentModal";
882
- export { type HAttachmentDetail as HkAttachmentDetail } from "./components/HkAttachmentModal";
883
- export { type HModelMeta as HkModelMeta } from "./components/HkModelCatalog";
884
- export { type HModelPricing as HkModelPricing } from "./components/HkModelCatalog";
885
785
  export { type HAboutCredit as HkAboutCredit } from "./components/HkAboutModal";
886
786
  export { type HAboutLink as HkAboutLink } from "./components/HkAboutModal";
887
787
  export { type HAboutLinkFace as HkAboutLinkFace } from "./components/HkAboutModal";
@@ -5,7 +5,6 @@ import HkDivider from "../components/HkDivider";
5
5
  import HkEmptyState from "../components/HkEmptyState";
6
6
  import HkSkeleton from "../components/HkSkeleton";
7
7
  import HkSplash from "../components/HkSplash";
8
- import HkStatusTray from "../components/HkStatusTray";
9
8
  import { registerStandardThemeDecor, STANDARD_THEME_DECOR_SLOTS } from "./standardDecor";
10
9
  import {
11
10
  getThemeDecor,
@@ -24,7 +23,7 @@ import {
24
23
  */
25
24
 
26
25
  describe("registerStandardThemeDecor", () => {
27
- it("registers nothing at import, then fills the five standard slots", async () => {
26
+ it("registers nothing at import, then fills the four in-tree standard slots", async () => {
28
27
  // A fresh module graph, so this proves the registration happens in the
29
28
  // call and not in an earlier case of this file. The component is
30
29
  // imported from the SAME fresh graph: module identity is per graph, so
@@ -32,7 +31,8 @@ describe("registerStandardThemeDecor", () => {
32
31
  vi.resetModules();
33
32
  const themeDecor = await import("./themeDecor");
34
33
  const standardDecor = await import("./standardDecor");
35
- const freshTray = (await import("../components/HkStatusTray")).default;
34
+ // The tray moved to @celestia-island/default-theme; the builtin
35
+ // floor for status.tray is now EMPTY (pinned below).
36
36
 
37
37
  // Importing this module is not a side effect (same contract as
38
38
  // standardGroups): only the call populates the registry.
@@ -43,15 +43,14 @@ describe("registerStandardThemeDecor", () => {
43
43
  expect([...themeDecor.themeDecorSlots()].sort()).toEqual(
44
44
  [...STANDARD_THEME_DECOR_SLOTS].sort(),
45
45
  );
46
- expect(themeDecor.getThemeDecor("status.tray", "any-theme")?.component).toBe(freshTray);
46
+ expect(themeDecor.getThemeDecor("status.tray", "any-theme")).toBeUndefined();
47
47
  });
48
48
 
49
49
  it("resolves every built-in for any theme id (floor level, and the declared list matches)", () => {
50
50
  registerStandardThemeDecor();
51
51
 
52
52
  const expected: [string, unknown][] = [
53
- ["status.tray", HkStatusTray],
54
- ["placeholder.screen", HkSplash],
53
+ ["placeholder.screen", HkSplash],
55
54
  ["placeholder.section", HkSkeleton],
56
55
  ["empty", HkEmptyState],
57
56
  ["divider", HkDivider],
@@ -93,28 +92,30 @@ describe("registerStandardThemeDecor", () => {
93
92
 
94
93
  // A theme's own implementation wins over the built-in …
95
94
  const themed = defineComponent({ name: "ThemedTray", setup: () => () => h("i") });
96
- registerThemeDecor({ themeId: "endfield", slot: "status.tray", component: themed });
95
+ registerThemeDecor({ themeId: "endfield", slot: "placeholder.screen", component: themed });
97
96
  registerStandardThemeDecor();
98
- expect(getThemeDecor("status.tray", "endfield")?.component).toBe(themed);
99
- expect(getThemeDecor("status.tray", "other")?.component).toBe(HkStatusTray);
97
+ expect(getThemeDecor("placeholder.screen", "endfield")?.component).toBe(themed);
98
+ // A slot with no theme registration keeps the builtin floor.
99
+ expect(getThemeDecor("placeholder.screen", "other")?.component).toBe(HkSplash);
100
100
 
101
101
  // … and so does a host-wide `"*"` registration.
102
102
  const hostWide = defineComponent({ name: "HostTray", setup: () => () => h("i") });
103
- registerThemeDecor({ themeId: "*", slot: "status.tray", component: hostWide });
103
+ registerThemeDecor({ themeId: "*", slot: "empty", component: hostWide });
104
104
  registerStandardThemeDecor();
105
- expect(getThemeDecor("status.tray", "other")?.component).toBe(hostWide);
105
+ expect(getThemeDecor("empty", "other")?.component).toBe(hostWide);
106
106
  });
107
107
 
108
108
  it("lands in the registry via initTheme() (and not before)", async () => {
109
109
  vi.resetModules();
110
110
  const themeDecor = await import("./themeDecor");
111
- const freshTray = (await import("../components/HkStatusTray")).default;
111
+ // The tray moved to @celestia-island/default-theme; the builtin
112
+ // floor for status.tray is now EMPTY (pinned below).
112
113
  const useTheme = await import("./useTheme");
113
114
  expect(themeDecor.getThemeDecor("status.tray", "default")).toBeUndefined();
114
115
 
115
116
  useTheme.initTheme();
116
117
 
117
- expect(themeDecor.getThemeDecor("status.tray", "default")?.component).toBe(freshTray);
118
+ expect(themeDecor.getThemeDecor("status.tray", "default")).toBeUndefined();
118
119
  // initTheme starts the solar theme clock; stop it so this file leaves no
119
120
  // timer behind.
120
121
  useTheme.stopThemeClock();