basalt-ui 1.8.0 → 1.10.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.
Files changed (99) hide show
  1. package/AGENTS.md +1 -0
  2. package/CHANGELOG.md +25 -0
  3. package/README.md +64 -34
  4. package/agent/rules/basalt-agent.md +49 -6
  5. package/agent/rules/basalt-charts.md +74 -5
  6. package/configs/oxlint-plugin.js +279 -0
  7. package/configs/oxlint-plugin.test.ts +216 -1
  8. package/configs/oxlint.json +5 -2
  9. package/dist/agent/use-agent-thread-runs.d.ts.map +1 -1
  10. package/dist/agent/use-agent-thread-runs.js +1 -0
  11. package/dist/agent-chat/index.d.ts +4 -3
  12. package/dist/agent-chat/index.d.ts.map +1 -1
  13. package/dist/charts/hooks/useHoverSync.d.ts +18 -2
  14. package/dist/charts/hooks/useHoverSync.d.ts.map +1 -1
  15. package/dist/charts/hooks/useHoverSync.js +12 -7
  16. package/dist/charts/index.d.ts +1 -0
  17. package/dist/charts/index.d.ts.map +1 -1
  18. package/dist/charts/index.js +6 -0
  19. package/dist/charts/kinds/Bars.d.ts +2 -0
  20. package/dist/charts/kinds/Bars.d.ts.map +1 -1
  21. package/dist/charts/kinds/Bars.js +3 -1
  22. package/dist/charts/kinds/Donut.d.ts +2 -0
  23. package/dist/charts/kinds/Donut.d.ts.map +1 -1
  24. package/dist/charts/kinds/Donut.js +8 -4
  25. package/dist/charts/kinds/DualPanel.d.ts +2 -0
  26. package/dist/charts/kinds/DualPanel.d.ts.map +1 -1
  27. package/dist/charts/kinds/DualPanel.js +2 -1
  28. package/dist/charts/kinds/Heatmap.d.ts +8 -0
  29. package/dist/charts/kinds/Heatmap.d.ts.map +1 -1
  30. package/dist/charts/kinds/Heatmap.js +7 -3
  31. package/dist/charts/kinds/MultiLine.d.ts +2 -0
  32. package/dist/charts/kinds/MultiLine.d.ts.map +1 -1
  33. package/dist/charts/kinds/MultiLine.js +2 -1
  34. package/dist/charts/kinds/StackedArea.d.ts +2 -0
  35. package/dist/charts/kinds/StackedArea.d.ts.map +1 -1
  36. package/dist/charts/kinds/StackedArea.js +2 -1
  37. package/dist/charts/kinds/ZonedLine.d.ts +2 -0
  38. package/dist/charts/kinds/ZonedLine.d.ts.map +1 -1
  39. package/dist/charts/kinds/ZonedLine.js +2 -1
  40. package/dist/charts/primitives/Axes.d.ts +6 -1
  41. package/dist/charts/primitives/Axes.d.ts.map +1 -1
  42. package/dist/charts/primitives/Axes.js +3 -2
  43. package/dist/charts/primitives/ChartFrame.d.ts +8 -1
  44. package/dist/charts/primitives/ChartFrame.d.ts.map +1 -1
  45. package/dist/charts/primitives/ChartFrame.js +8 -4
  46. package/dist/charts/primitives/ChartPending.d.ts +34 -0
  47. package/dist/charts/primitives/ChartPending.d.ts.map +1 -0
  48. package/dist/charts/primitives/ChartPending.js +23 -0
  49. package/dist/charts/primitives/ChartTooltip.d.ts +5 -2
  50. package/dist/charts/primitives/ChartTooltip.d.ts.map +1 -1
  51. package/dist/charts/primitives/ChartTooltip.js +6 -1
  52. package/dist/charts/primitives/HoverOverlay.d.ts +5 -4
  53. package/dist/charts/primitives/HoverOverlay.d.ts.map +1 -1
  54. package/dist/charts/primitives/HoverOverlay.js +4 -2
  55. package/dist/cli/index.d.ts +55 -1
  56. package/dist/cli/index.d.ts.map +1 -1
  57. package/dist/cli/index.js +217 -5
  58. package/dist/dashboard/stat-card.d.ts.map +1 -1
  59. package/dist/guard/index.d.ts.map +1 -1
  60. package/dist/guard/index.js +13 -5
  61. package/dist/surfaces.d.ts +10 -0
  62. package/dist/surfaces.d.ts.map +1 -1
  63. package/dist/surfaces.js +21 -0
  64. package/llms.txt +9 -2
  65. package/package.json +8 -5
  66. package/src/agent/ai-sdk-transport.test.ts +269 -0
  67. package/src/agent/parts.test.ts +261 -0
  68. package/src/agent/thread.test.ts +147 -0
  69. package/src/agent/use-agent-stream.test.tsx +231 -0
  70. package/src/agent/use-agent-thread-runs.resume.test.tsx +261 -0
  71. package/src/agent/use-agent-thread-runs.test.tsx +398 -0
  72. package/src/agent/use-agent-thread-runs.ts +7 -1
  73. package/src/agent/use-agent-thread-runs.wedge.test.tsx +299 -0
  74. package/src/agent-chat/index.ts +4 -3
  75. package/src/charts/hooks/useHoverSync.ts +43 -7
  76. package/src/charts/index.ts +6 -0
  77. package/src/charts/kinds/Bars.tsx +4 -0
  78. package/src/charts/kinds/Donut.tsx +10 -4
  79. package/src/charts/kinds/DualPanel.tsx +5 -1
  80. package/src/charts/kinds/Heatmap.tsx +19 -2
  81. package/src/charts/kinds/MultiLine.tsx +4 -1
  82. package/src/charts/kinds/StackedArea.tsx +4 -1
  83. package/src/charts/kinds/ZonedLine.tsx +4 -1
  84. package/src/charts/primitives/Axes.tsx +7 -1
  85. package/src/charts/primitives/ChartFrame.test.tsx +67 -0
  86. package/src/charts/primitives/ChartFrame.tsx +17 -4
  87. package/src/charts/primitives/ChartPending.tsx +59 -0
  88. package/src/charts/primitives/ChartTooltip.tsx +15 -3
  89. package/src/charts/primitives/HoverOverlay.tsx +12 -6
  90. package/src/cli/index.ts +439 -5
  91. package/src/cli/placement-engine.test.ts +104 -0
  92. package/src/dashboard/stat-card.test.tsx +5 -3
  93. package/src/dashboard/stat-card.tsx +12 -0
  94. package/src/guard/check-source.test.ts +20 -0
  95. package/src/guard/index.ts +20 -9
  96. package/src/provider/index.test.tsx +6 -5
  97. package/src/surfaces.ts +22 -0
  98. package/src/theme/use-basalt-spacing.test.tsx +7 -4
  99. package/src/tokens/build-fonts-css.test.ts +3 -2
@@ -1,7 +1,10 @@
1
1
  import type { CSSProperties, ReactNode, RefObject } from 'react';
2
2
  /** Theme-aware tooltip container styles — use with useChartTooltip(). */
3
3
  export declare function useTooltipStyles(): CSSProperties;
4
- /** Outer tooltip shell. Renders nothing when tip is null. */
4
+ /**
5
+ * Outer tooltip shell. Renders nothing when tip is null. Renders to `document.body` via a
6
+ * portal, so it may be authored anywhere in the tree, including inside `<svg>`.
7
+ */
5
8
  export declare function ChartTooltip({ tip, tooltipRef, styles, children, }: {
6
9
  tip: {
7
10
  x: number;
@@ -10,7 +13,7 @@ export declare function ChartTooltip({ tip, tooltipRef, styles, children, }: {
10
13
  tooltipRef?: RefObject<HTMLDivElement | null>;
11
14
  styles: CSSProperties;
12
15
  children: ReactNode;
13
- }): import("react").JSX.Element | null;
16
+ }): import("react").ReactPortal | null;
14
17
  /** Tooltip header — shows formatted date + optional right-aligned label with color. */
15
18
  export declare function TooltipHeader({ date, label, labelColor, }: {
16
19
  date: string;
@@ -1 +1 @@
1
- {"version":3,"file":"ChartTooltip.d.ts","sourceRoot":"","sources":["../../../src/charts/primitives/ChartTooltip.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAqBhE,yEAAyE;AACzE,wBAAgB,gBAAgB,IAAI,aAAa,CAEhD;AAED,6DAA6D;AAC7D,wBAAgB,YAAY,CAAC,EAC3B,GAAG,EACH,UAAU,EACV,MAAM,EACN,QAAQ,GACT,EAAE;IACD,GAAG,EAAE;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAA;IACpC,UAAU,CAAC,EAAE,SAAS,CAAC,cAAc,GAAG,IAAI,CAAC,CAAA;IAC7C,MAAM,EAAE,aAAa,CAAA;IACrB,QAAQ,EAAE,SAAS,CAAA;CACpB,sCAOA;AAED,uFAAuF;AACvF,wBAAgB,aAAa,CAAC,EAC5B,IAAI,EACJ,KAAK,EACL,UAAU,GACX,EAAE;IACD,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB,+BAoCA;AAED,4CAA4C;AAC5C,wBAAgB,UAAU,CAAC,EACzB,KAAK,EACL,KAAK,EACL,KAAK,EACL,UAAU,EACV,KAAK,EACL,WAAW,EACX,MAAM,GACP,EAAE;IACD,KAAK,EAAE,MAAM,CAAA;IACb,KAAK,EAAE,MAAM,CAAA;IACb,KAAK,EAAE,MAAM,CAAA;IACb,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,KAAK,CAAC,EAAE,KAAK,GAAG,MAAM,GAAG,KAAK,CAAA;IAC9B,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,uEAAuE;IACvE,MAAM,CAAC,EAAE,OAAO,CAAA;CACjB,+BA0CA;AAED,wBAAgB,WAAW,CAAC,EAAE,QAAQ,EAAE,EAAE;IAAE,QAAQ,EAAE,SAAS,CAAA;CAAE,+BAEhE"}
1
+ {"version":3,"file":"ChartTooltip.d.ts","sourceRoot":"","sources":["../../../src/charts/primitives/ChartTooltip.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAsBhE,yEAAyE;AACzE,wBAAgB,gBAAgB,IAAI,aAAa,CAEhD;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,EAC3B,GAAG,EACH,UAAU,EACV,MAAM,EACN,QAAQ,GACT,EAAE;IACD,GAAG,EAAE;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAA;IACpC,UAAU,CAAC,EAAE,SAAS,CAAC,cAAc,GAAG,IAAI,CAAC,CAAA;IAC7C,MAAM,EAAE,aAAa,CAAA;IACrB,QAAQ,EAAE,SAAS,CAAA;CACpB,sCAeA;AAED,uFAAuF;AACvF,wBAAgB,aAAa,CAAC,EAC5B,IAAI,EACJ,KAAK,EACL,UAAU,GACX,EAAE;IACD,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB,+BAoCA;AAED,4CAA4C;AAC5C,wBAAgB,UAAU,CAAC,EACzB,KAAK,EACL,KAAK,EACL,KAAK,EACL,UAAU,EACV,KAAK,EACL,WAAW,EACX,MAAM,GACP,EAAE;IACD,KAAK,EAAE,MAAM,CAAA;IACb,KAAK,EAAE,MAAM,CAAA;IACb,KAAK,EAAE,MAAM,CAAA;IACb,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,KAAK,CAAC,EAAE,KAAK,GAAG,MAAM,GAAG,KAAK,CAAA;IAC9B,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,uEAAuE;IACvE,MAAM,CAAC,EAAE,OAAO,CAAA;CACjB,+BA0CA;AAED,wBAAgB,WAAW,CAAC,EAAE,QAAQ,EAAE,EAAE;IAAE,QAAQ,EAAE,SAAS,CAAA;CAAE,+BAEhE"}
@@ -1,4 +1,5 @@
1
1
  import { jsx, jsxs } from "react/jsx-runtime";
2
+ import { createPortal } from "react-dom";
2
3
  import { VX } from "../../tokens/index.js";
3
4
  import { fmtTooltipDate } from "../utils/format.js";
4
5
  const TOOLTIP_STYLES = {
@@ -24,7 +25,11 @@ function ChartTooltip({
24
25
  children
25
26
  }) {
26
27
  if (!tip) return null;
27
- return /* @__PURE__ */ jsx("div", { ref: tooltipRef, style: { ...styles, left: tip.x, top: tip.y }, children });
28
+ if (typeof document === "undefined") return null;
29
+ return createPortal(
30
+ /* @__PURE__ */ jsx("div", { ref: tooltipRef, style: { ...styles, left: tip.x, top: tip.y }, children }),
31
+ document.body
32
+ );
28
33
  }
29
34
  function TooltipHeader({
30
35
  date,
@@ -1,9 +1,10 @@
1
- import type { MouseEventHandler } from 'react';
2
- /** Transparent <rect> that captures mouse events for tooltip + crosshair sync. */
1
+ import type { PointerEventHandler } from 'react';
2
+ /** Transparent <rect> that captures pointer events (mouse + touch + pen) for tooltip + crosshair
3
+ * sync. */
3
4
  export declare function HoverOverlay({ width, height, onMove, onLeave, }: {
4
5
  width: number;
5
6
  height: number;
6
- onMove: MouseEventHandler<SVGRectElement>;
7
- onLeave: MouseEventHandler<SVGRectElement>;
7
+ onMove: PointerEventHandler<SVGRectElement>;
8
+ onLeave: PointerEventHandler<SVGRectElement>;
8
9
  }): import("react").JSX.Element;
9
10
  //# sourceMappingURL=HoverOverlay.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"HoverOverlay.d.ts","sourceRoot":"","sources":["../../../src/charts/primitives/HoverOverlay.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,OAAO,CAAA;AAE9C,kFAAkF;AAClF,wBAAgB,YAAY,CAAC,EAC3B,KAAK,EACL,MAAM,EACN,MAAM,EACN,OAAO,GACR,EAAE;IACD,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,iBAAiB,CAAC,cAAc,CAAC,CAAA;IACzC,OAAO,EAAE,iBAAiB,CAAC,cAAc,CAAC,CAAA;CAC3C,+BAUA"}
1
+ {"version":3,"file":"HoverOverlay.d.ts","sourceRoot":"","sources":["../../../src/charts/primitives/HoverOverlay.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,OAAO,CAAA;AAEhD;WACW;AACX,wBAAgB,YAAY,CAAC,EAC3B,KAAK,EACL,MAAM,EACN,MAAM,EACN,OAAO,GACR,EAAE;IACD,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,mBAAmB,CAAC,cAAc,CAAC,CAAA;IAC3C,OAAO,EAAE,mBAAmB,CAAC,cAAc,CAAC,CAAA;CAC7C,+BAeA"}
@@ -11,8 +11,10 @@ function HoverOverlay({
11
11
  width,
12
12
  height,
13
13
  fill: "transparent",
14
- onMouseMove: onMove,
15
- onMouseLeave: onLeave
14
+ style: { touchAction: "pan-y" },
15
+ onPointerMove: onMove,
16
+ onPointerLeave: onLeave,
17
+ onPointerCancel: onLeave
16
18
  }
17
19
  );
18
20
  }
@@ -126,6 +126,25 @@ export type BasaltConfig = {
126
126
  * { exemptRules: { 'inline-display': ['agent'] } } // inline-display never fires under src/agent/**
127
127
  */
128
128
  exemptRules?: Partial<Record<GuardKind, string[]>>;
129
+ /**
130
+ * Declares an intentional `ai` package major-version skew across workspace packages, exempting
131
+ * `doctor`'s `ai-major-parity` hard check. The value IS the reason — a bare `true` is rejected,
132
+ * because the whole point of this key is that the pairing is written down, not just switched off.
133
+ * A written declaration is the pin `basalt/ai-sdk-major`'s own comment notes is otherwise missing.
134
+ *
135
+ * Semantics: absent (or present but not a non-empty string) → the skew still hard-fails exactly as
136
+ * without this key. A non-empty string with a skew present → `doctor` passes, echoing both the
137
+ * skew and this reason. A non-empty string with NO skew present → `doctor` warns that the
138
+ * exemption is stale and can be deleted (an exemption nobody re-checks is how a real, later skew
139
+ * slips through unnoticed).
140
+ *
141
+ * @example
142
+ * // apps/api streams on ai@5; apps/dashboard parses on ai@7; a producer-side TransformStream
143
+ * // neutralizes the one enum value that differs between the two majors.
144
+ * { aiMajorSkewReason: 'apps/api pinned to ai@5, apps/dashboard on ai@7 — the skew is neutralized '
145
+ * + 'by a producer-side TransformStream in apps/api/src/stream-transform.ts' }
146
+ */
147
+ aiMajorSkewReason?: string;
129
148
  };
130
149
  /**
131
150
  * Theme guard — thin FS walker over the headless `../guard` core. Reads BasaltConfig, builds a
@@ -205,8 +224,29 @@ type PeerFlags = {
205
224
  hasRouter: boolean;
206
225
  hasQuery: boolean;
207
226
  };
227
+ /**
228
+ * Where the seed engine is running relative to the consumer's git repo — decides which
229
+ * repo-root-shaped seeds are safe to write. `init`/`sync` compute it once per run via
230
+ * `resolvePlacement` and print the matching skip notices themselves; `managedFiles` only reads it.
231
+ */
232
+ type PlacementFlags = {
233
+ /** True when the package directory IS the detected repo root, or no `.git` exists anywhere above
234
+ * it (a consumer not using git keeps today's behaviour exactly). False means the package lives
235
+ * in a subdirectory of the repo (a monorepo's `web/`, say) — lefthook and GitHub Actions both
236
+ * only read config at the repo root, so seeding either one there is worse than not seeding at
237
+ * all. */
238
+ isPackageRepoRoot: boolean;
239
+ /** Absolute path of the detected repo root. Meaningful only when `isPackageRepoRoot` is false —
240
+ * otherwise it equals the package dir and is never read. */
241
+ repoRoot: string;
242
+ /** Absolute path of a `query-client.ts` already present elsewhere under the package's `src/` (the
243
+ * consumer relocated it — e.g. to `src/lib/query-client.ts`), or null. The seed's OWN
244
+ * destination is deliberately excluded here — that exact-path case is handled by the ordinary
245
+ * skip-if-exists logic every seed file already goes through, unchanged. */
246
+ relocatedQueryClient: string | null;
247
+ };
208
248
  /** The full managed-file manifest. Stable, declarative — the single source of truth for init/sync. */
209
- declare function managedFiles(peers: PeerFlags): ManagedFile[];
249
+ declare function managedFiles(peers: PeerFlags, placement?: PlacementFlags): ManagedFile[];
210
250
  type Manifest = {
211
251
  version: 1;
212
252
  /** The basalt-ui version that last wrote this manifest — `doctor`'s one reconciliation axis. */
@@ -303,6 +343,17 @@ type DoctorResult = {
303
343
  *
304
344
  * Hard failures (exit non-zero):
305
345
  * 1. .basalt/manifest.json exists (init was run).
346
+ * 6. `ai-major-parity`: every workspace package that declares the `ai` package agrees on its
347
+ * major version. `basalt/ai-sdk-major` (the oxlint plugin rule) cannot catch this — it checks
348
+ * a linted file's NEAREST package.json, so a lint run scoped to one workspace package only
349
+ * ever sees that package's own `ai` major and is perfectly happy; the cross-package skew (one
350
+ * package streaming on `ai@5`, another parsing it on `ai@7`) only a repo-wide manifest walk
351
+ * can see. Skipped entirely when `cwd` has no `workspaces` field or none of its packages
352
+ * declare `ai`. A detected skew is exempt-able via `basalt.aiMajorSkewReason` (a non-empty
353
+ * reason string, not a bare `true`) in the consumer's package.json — an intentional
354
+ * producer/consumer split neutralized by a transform is a locked decision, not a defect, and
355
+ * the written reason IS the pin that a permanently-failing guard would otherwise lack. Missing
356
+ * or invalid (empty/non-string) still hard-fails exactly as if the key were absent.
306
357
  *
307
358
  * Warnings (non-fatal):
308
359
  * 2. The installed node_modules/basalt-ui version matches the manifest's basaltVersion
@@ -314,6 +365,9 @@ type DoctorResult = {
314
365
  * `bunx basalt-ui` npm fetch; best-effort, skipped if node_modules is absent).
315
366
  * 5. `basaltAppPlugin`'s (basalt-ui/vite) default icon filenames exist under public/ (only when
316
367
  * a public/ dir exists at all — skipped otherwise).
368
+ * 7. A declared `basalt.aiMajorSkewReason` when the ai majors currently AGREE — the exemption is
369
+ * stale and can be deleted; an exemption nobody revisits is how a real, later skew slips
370
+ * through unnoticed.
317
371
  *
318
372
  * Returns the exit code: 0 = all good, 1 = one or more hard failures.
319
373
  */
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":"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"}
package/dist/cli/index.js CHANGED
@@ -285,7 +285,59 @@ function resolvePeerFlags(cwd, flags) {
285
285
  hasQuery: flags.withQuery === true || hasDependency(cwd, "@tanstack/react-query")
286
286
  };
287
287
  }
288
- function managedFiles(peers) {
288
+ const ROOT_PLACEMENT = {
289
+ isPackageRepoRoot: true,
290
+ repoRoot: "",
291
+ relocatedQueryClient: null
292
+ };
293
+ function findRepoRoot(dir) {
294
+ let current = dir;
295
+ for (; ; ) {
296
+ if (existsSync(resolve(current, ".git"))) return current;
297
+ const parent = dirname(current);
298
+ if (parent === current) return dir;
299
+ current = parent;
300
+ }
301
+ }
302
+ function findFileNamed(dir, filename) {
303
+ let entries;
304
+ try {
305
+ entries = readdirSync(dir);
306
+ } catch {
307
+ return null;
308
+ }
309
+ for (const name of entries) {
310
+ if (name === "node_modules" || name === ".git" || name === "dist") continue;
311
+ const abs = resolve(dir, name);
312
+ let isDir;
313
+ try {
314
+ isDir = statSync(abs).isDirectory();
315
+ } catch {
316
+ continue;
317
+ }
318
+ if (isDir) {
319
+ const found = findFileNamed(abs, filename);
320
+ if (found !== null) return found;
321
+ } else if (name === filename) {
322
+ return abs;
323
+ }
324
+ }
325
+ return null;
326
+ }
327
+ function findRelocatedQueryClient(cwd) {
328
+ const seedAbs = resolve(cwd, "src/query-client.ts");
329
+ const found = findFileNamed(resolve(cwd, "src"), "query-client.ts");
330
+ return found !== null && found !== seedAbs ? found : null;
331
+ }
332
+ function resolvePlacement(cwd) {
333
+ const repoRoot = findRepoRoot(cwd);
334
+ return {
335
+ isPackageRepoRoot: repoRoot === cwd,
336
+ repoRoot,
337
+ relocatedQueryClient: findRelocatedQueryClient(cwd)
338
+ };
339
+ }
340
+ function managedFiles(peers, placement = ROOT_PLACEMENT) {
289
341
  const rules = RULE_NAMES.map((name) => ({
290
342
  dest: `.claude/rules/basalt-${name}.md`,
291
343
  mode: "managed",
@@ -370,9 +422,10 @@ function managedFiles(peers) {
370
422
  }
371
423
  };
372
424
  const scaffolds = [];
373
- if (peers.hasQuery) scaffolds.push(queryClient);
425
+ if (peers.hasQuery && placement.relocatedQueryClient === null) scaffolds.push(queryClient);
374
426
  if (peers.hasRouter && peers.hasQuery) scaffolds.push(rootRoute);
375
- return [...rules, ...skills, claudeBlock, design, oxfmt, lefthook, ci, oxlintrc, ...scaffolds];
427
+ const rootTooling = placement.isPackageRepoRoot ? [lefthook, ci] : [];
428
+ return [...rules, ...skills, claudeBlock, design, oxfmt, ...rootTooling, oxlintrc, ...scaffolds];
376
429
  }
377
430
  function readManifest(cwd) {
378
431
  const raw = readIfExists(resolve(cwd, MANIFEST_PATH));
@@ -462,7 +515,8 @@ function init(cwd = process.cwd(), scaffoldFlags = {}) {
462
515
  const manifest = readManifest(cwd);
463
516
  migrateLegacyOxfmt(cwd, ctx.pkgRoot, manifest);
464
517
  const peers = resolvePeerFlags(cwd, scaffoldFlags);
465
- const files = managedFiles(peers);
518
+ const placement = resolvePlacement(cwd);
519
+ const files = managedFiles(peers, placement);
466
520
  let written = 0;
467
521
  let skipped = 0;
468
522
  const missingSources = [];
@@ -492,6 +546,19 @@ function init(cwd = process.cwd(), scaffoldFlags = {}) {
492
546
  `basalt-ui init: ${missingSources.length} shipped asset(s) not present, skipped: ${missingSources.join(", ")}`
493
547
  );
494
548
  }
549
+ if (!placement.isPackageRepoRoot) {
550
+ console.log(
551
+ `basalt-ui init: skipped lefthook.yml (this package is not the repo root \u2014 repo root detected at ${placement.repoRoot}) \u2014 lefthook only reads config at the repo root; extend node_modules/basalt-ui/configs/lefthook.yml from your root lefthook.yml instead.`
552
+ );
553
+ console.log(
554
+ `basalt-ui init: skipped .github/workflows/check.yml (this package is not the repo root \u2014 repo root detected at ${placement.repoRoot}) \u2014 GitHub Actions only reads .github/ at the repo root; extend node_modules/basalt-ui/configs/check.yml from your root CI workflow instead.`
555
+ );
556
+ }
557
+ if (placement.relocatedQueryClient !== null) {
558
+ console.log(
559
+ `basalt-ui init: skipped src/query-client.ts (found an existing query client at ${relative(cwd, placement.relocatedQueryClient)}) \u2014 import it from there instead of re-seeding at the original path.`
560
+ );
561
+ }
495
562
  if (!peers.hasQuery) {
496
563
  console.log(
497
564
  "basalt-ui init: skipped src/query-client.ts (no @tanstack/react-query dependency detected) \u2014 install it, or re-run with --with-query, to scaffold it."
@@ -524,7 +591,8 @@ function sync(opts = {}, cwd = process.cwd()) {
524
591
  const manifest = readManifest(cwd);
525
592
  if (!opts.check) migrateLegacyOxfmt(cwd, ctx.pkgRoot, manifest);
526
593
  const peers = resolvePeerFlags(cwd, {});
527
- const files = managedFiles(peers);
594
+ const placement = resolvePlacement(cwd);
595
+ const files = managedFiles(peers, placement);
528
596
  let updated = 0;
529
597
  let recreated = 0;
530
598
  let skippedDrift = 0;
@@ -561,6 +629,19 @@ function sync(opts = {}, cwd = process.cwd()) {
561
629
  if (kind === "missing") recreated++;
562
630
  else updated++;
563
631
  }
632
+ if (!placement.isPackageRepoRoot) {
633
+ console.log(
634
+ `basalt-ui sync: skipped lefthook.yml (this package is not the repo root \u2014 repo root detected at ${placement.repoRoot}) \u2014 lefthook only reads config at the repo root; extend node_modules/basalt-ui/configs/lefthook.yml from your root lefthook.yml instead.`
635
+ );
636
+ console.log(
637
+ `basalt-ui sync: skipped .github/workflows/check.yml (this package is not the repo root \u2014 repo root detected at ${placement.repoRoot}) \u2014 GitHub Actions only reads .github/ at the repo root; extend node_modules/basalt-ui/configs/check.yml from your root CI workflow instead.`
638
+ );
639
+ }
640
+ if (placement.relocatedQueryClient !== null) {
641
+ console.log(
642
+ `basalt-ui sync: skipped src/query-client.ts (found an existing query client at ${relative(cwd, placement.relocatedQueryClient)}) \u2014 import it from there instead of re-seeding at the original path.`
643
+ );
644
+ }
564
645
  if (opts.check) {
565
646
  if (driftLines.length > 0) {
566
647
  console.error("basalt-ui sync --check: locally-drifted managed files:");
@@ -702,7 +783,105 @@ function checkCoverage() {
702
783
  }
703
784
  return 1;
704
785
  }
786
+ function subdirNames(base, options = {}) {
787
+ let entries;
788
+ try {
789
+ entries = readdirSync(base);
790
+ } catch {
791
+ return [];
792
+ }
793
+ return entries.filter((name) => {
794
+ if (name === "node_modules") return false;
795
+ if (options.skipDotDirs && name.startsWith(".")) return false;
796
+ try {
797
+ return statSync(resolve(base, name)).isDirectory();
798
+ } catch {
799
+ return false;
800
+ }
801
+ });
802
+ }
803
+ function expandPatternSegments(baseDir, segments) {
804
+ if (segments.length === 0) return [baseDir];
805
+ const [head, ...rest] = segments;
806
+ if (head === "**") {
807
+ const matches = expandPatternSegments(baseDir, rest);
808
+ for (const name of subdirNames(baseDir, { skipDotDirs: true })) {
809
+ matches.push(...expandPatternSegments(resolve(baseDir, name), segments));
810
+ }
811
+ return matches;
812
+ }
813
+ const names = head === "*" ? subdirNames(baseDir, { skipDotDirs: true }) : subdirNames(baseDir).filter((n) => n === head);
814
+ return names.flatMap((name) => expandPatternSegments(resolve(baseDir, name), rest));
815
+ }
816
+ function expandWorkspaceGlobs(cwd, patterns) {
817
+ const expand = (pattern) => expandPatternSegments(
818
+ cwd,
819
+ pattern.split("/").filter((s) => s.length > 0)
820
+ );
821
+ const excluded = new Set(
822
+ patterns.filter((pattern) => pattern.startsWith("!")).flatMap((pattern) => expand(pattern.replace(/^!+/, "")))
823
+ );
824
+ const dirs = [];
825
+ for (const pattern of patterns) {
826
+ if (pattern.startsWith("!")) continue;
827
+ for (const abs of expand(pattern)) {
828
+ if (excluded.has(abs)) continue;
829
+ if (existsSync(resolve(abs, "package.json"))) dirs.push(abs);
830
+ }
831
+ }
832
+ return dirs;
833
+ }
834
+ function collectWorkspacePackages(cwd) {
835
+ const raw = readIfExists(resolve(cwd, "package.json"));
836
+ if (raw === null) return { packages: [], hasWorkspacesField: false };
837
+ let parsed;
838
+ try {
839
+ parsed = JSON.parse(raw);
840
+ } catch {
841
+ return { packages: [], hasWorkspacesField: false };
842
+ }
843
+ const patterns = isStringArray(parsed.workspaces) ? parsed.workspaces : parsed.workspaces !== null && typeof parsed.workspaces === "object" && isStringArray(parsed.workspaces.packages) ? parsed.workspaces.packages : null;
844
+ if (patterns === null) return { packages: [], hasWorkspacesField: false };
845
+ const rootName = parsed.name && parsed.name.length > 0 ? `${parsed.name} (root)` : "(root)";
846
+ const workspacePackages = expandWorkspaceGlobs(cwd, patterns).map((dir) => ({
847
+ name: readPackageName(dir),
848
+ dir
849
+ }));
850
+ return {
851
+ packages: [{ name: rootName, dir: cwd }, ...workspacePackages],
852
+ hasWorkspacesField: true
853
+ };
854
+ }
855
+ function isStringArray(value) {
856
+ return Array.isArray(value) && value.every((entry) => typeof entry === "string");
857
+ }
858
+ function majorOf(range) {
859
+ if (typeof range !== "string") return null;
860
+ const match = range.match(/\d+/);
861
+ return match === null ? null : Number(match[0]);
862
+ }
863
+ function aiMajorAt(dir) {
864
+ const raw = readIfExists(resolve(dir, "package.json"));
865
+ if (raw === null) return null;
866
+ try {
867
+ const pkg = JSON.parse(raw);
868
+ return majorOf(
869
+ pkg.dependencies?.["ai"] ?? pkg.devDependencies?.["ai"] ?? pkg.peerDependencies?.["ai"]
870
+ );
871
+ } catch {
872
+ return null;
873
+ }
874
+ }
875
+ function resolveAiMajorSkewReason(cfg) {
876
+ const raw = cfg.aiMajorSkewReason;
877
+ if (raw === void 0) return { reason: null, presentButInvalid: false };
878
+ if (typeof raw === "string" && raw.trim().length > 0) {
879
+ return { reason: raw, presentButInvalid: false };
880
+ }
881
+ return { reason: null, presentButInvalid: true };
882
+ }
705
883
  function doctor(cwd = process.cwd()) {
884
+ const cfg = readBasaltConfig(cwd);
706
885
  const result = { hardFailures: 0, warnings: 0 };
707
886
  const lines = [`
708
887
  basalt-ui doctor \u2014 ${cwd}
@@ -800,6 +979,39 @@ basalt-ui doctor \u2014 ${cwd}
800
979
  pass("public/ has all of basaltAppPlugin's default icon files");
801
980
  }
802
981
  }
982
+ const workspaceWalk = collectWorkspacePackages(cwd);
983
+ const aiMajors = workspaceWalk.packages.map((pkg) => ({ name: pkg.name, major: aiMajorAt(pkg.dir) })).filter((entry) => entry.major !== null);
984
+ const { reason: aiMajorSkewReason, presentButInvalid: aiMajorSkewReasonInvalid } = resolveAiMajorSkewReason(cfg);
985
+ if (aiMajors.length > 0) {
986
+ const distinctMajors = new Set(aiMajors.map((entry) => entry.major));
987
+ if (distinctMajors.size > 1) {
988
+ const summary = aiMajors.map((entry) => `${entry.name}@ai${entry.major}`).join(", ");
989
+ if (aiMajorSkewReason !== null) {
990
+ pass(
991
+ `ai package major version mismatch across workspace packages: ${summary} \u2014 exempted via basalt.aiMajorSkewReason: "${aiMajorSkewReason}"`
992
+ );
993
+ } else if (aiMajorSkewReasonInvalid) {
994
+ fail(
995
+ `ai package major version mismatch across workspace packages: ${summary} \u2014 basalt.aiMajorSkewReason is present but is not a non-empty string (a bare \`true\` is not accepted); the exemption must carry a written reason, e.g. \`aiMajorSkewReason: "apps/api on ai@5, apps/dashboard on ai@7, neutralized by a producer-side TransformStream"\`.`
996
+ );
997
+ } else {
998
+ fail(`ai package major version mismatch across workspace packages: ${summary}`);
999
+ }
1000
+ } else {
1001
+ const [major] = distinctMajors;
1002
+ if (aiMajorSkewReason !== null) {
1003
+ warn(
1004
+ `basalt.aiMajorSkewReason ("${aiMajorSkewReason}") is declared but the ai package major already matches across all ${aiMajors.length} workspace package(s) declaring it (ai@${major}) \u2014 the exemption is no longer needed and can be deleted.`
1005
+ );
1006
+ } else {
1007
+ pass(
1008
+ `ai package major matches across ${aiMajors.length} workspace package(s) declaring it (ai@${major})`
1009
+ );
1010
+ }
1011
+ }
1012
+ } else if (workspaceWalk.hasWorkspacesField) {
1013
+ pass("ai-major-parity: no workspace package declares the ai dependency \u2014 nothing to compare");
1014
+ }
803
1015
  lines.push("");
804
1016
  if (result.hardFailures === 0 && result.warnings === 0) {
805
1017
  lines.push("All checks passed.");
@@ -1 +1 @@
1
- {"version":3,"file":"stat-card.d.ts","sourceRoot":"","sources":["../../src/dashboard/stat-card.tsx"],"names":[],"mappings":"AA0CA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAItC,sGAAsG;AACtG,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,MAAM,GAAG,KAAK,CAAA;AAYlD,MAAM,MAAM,aAAa,GAAG;IAC1B,2FAA2F;IAC3F,KAAK,EAAE,MAAM,CAAA;IACb,oEAAoE;IACpE,KAAK,EAAE,MAAM,CAAA;IACb,oFAAoF;IACpF,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,oGAAoG;IACpG,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB;kGAC8F;IAC9F,SAAS,CAAC,EAAE,SAAS,CAAA;IACrB,qFAAqF;IACrF,IAAI,CAAC,EAAE,SAAS,CAAA;IAChB;;;+EAG2E;IAC3E,IAAI,CAAC,EAAE,YAAY,CAAA;CACpB,CAAA;AAED,wBAAgB,QAAQ,CAAC,EACvB,KAAK,EACL,KAAK,EACL,KAAK,EACL,WAAW,EACX,SAAS,EACT,IAAI,EACJ,IAAI,GACL,EAAE,aAAa,+BAyFf"}
1
+ {"version":3,"file":"stat-card.d.ts","sourceRoot":"","sources":["../../src/dashboard/stat-card.tsx"],"names":[],"mappings":"AAsDA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAItC,sGAAsG;AACtG,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,MAAM,GAAG,KAAK,CAAA;AAYlD,MAAM,MAAM,aAAa,GAAG;IAC1B,2FAA2F;IAC3F,KAAK,EAAE,MAAM,CAAA;IACb,oEAAoE;IACpE,KAAK,EAAE,MAAM,CAAA;IACb,oFAAoF;IACpF,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,oGAAoG;IACpG,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB;kGAC8F;IAC9F,SAAS,CAAC,EAAE,SAAS,CAAA;IACrB,qFAAqF;IACrF,IAAI,CAAC,EAAE,SAAS,CAAA;IAChB;;;+EAG2E;IAC3E,IAAI,CAAC,EAAE,YAAY,CAAA;CACpB,CAAA;AAED,wBAAgB,QAAQ,CAAC,EACvB,KAAK,EACL,KAAK,EACL,KAAK,EACL,WAAW,EACX,SAAS,EACT,IAAI,EACJ,IAAI,GACL,EAAE,aAAa,+BAyFf"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/guard/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,KAAK,EAAE,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,SAAS,CAAA;AAE7E,YAAY,EAAE,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,aAAa,EAAE,CAAA;AAoP9D,8EAA8E;AAC9E,eAAO,MAAM,oBAAoB,EAAE,WAoBlC,CAAA;AAuTD;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;gCA0BL,WAAW;;;;;;;gCAcX,WAAW;;;;;gCAMX,WAAW;;;;;;;gCAaX,WAAW;;;;;;;gCAQX,WAAW;;;;;;gCAOX,WAAW;;;;;;;gCASX,WAAW;;;;;;gCAOX,WAAW;;;;;;;gCASX,WAAW;;;;;;gCAMX,WAAW;;;;;;;gCASX,WAAW;;;;;;;gCAUX,WAAW;;;;;;;gCAUX,WAAW;;;;;;;gCASX,WAAW;;;;;;;gCASX,WAAW;;;;;;;gCAUX,WAAW;;;;CAOmB,CAAA;AAUjD;;;;;;;;;GASG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,WAAW,GAAG,OAAO,EAAE,CA2PtF"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/guard/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,KAAK,EAAE,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,SAAS,CAAA;AAE7E,YAAY,EAAE,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,aAAa,EAAE,CAAA;AAoP9D,8EAA8E;AAC9E,eAAO,MAAM,oBAAoB,EAAE,WAoBlC,CAAA;AA0TD;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;gCA0BL,WAAW;;;;;;;gCAcX,WAAW;;;;;gCAMX,WAAW;;;;;;;gCAaX,WAAW;;;;;;;gCAQX,WAAW;;;;;;gCAOX,WAAW;;;;;;;gCASX,WAAW;;;;;;gCAOX,WAAW;;;;;;;gCAaX,WAAW;;;;;;gCAMX,WAAW;;;;;;;gCAaX,WAAW;;;;;;;gCAUX,WAAW;;;;;;;gCAUX,WAAW;;;;;;;gCASX,WAAW;;;;;;;gCASX,WAAW;;;;;;;gCAUX,WAAW;;;;CAOmB,CAAA;AAUjD;;;;;;;;;GASG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,WAAW,GAAG,OAAO,EAAE,CA2PtF"}
@@ -78,7 +78,7 @@ const DEFAULT_GUARD_CONFIG = {
78
78
  severity: {}
79
79
  };
80
80
  const GRACE_PERIOD_KINDS = {
81
- "mantine-shade-index": "introduced 1.7.0 \u2014 promote to error in 1.9.0"
81
+ "mantine-shade-index": "introduced 1.7.0 \u2014 promote to error in 1.10.0"
82
82
  };
83
83
  function severityOf(kind, cfg) {
84
84
  return cfg.severity?.[kind] ?? (kind in GRACE_PERIOD_KINDS ? "warn" : "error");
@@ -339,8 +339,12 @@ const GUARD_RULES = {
339
339
  pattern: RAW_HTML_TAG,
340
340
  // handled inline (3-condition conjunction); entry keeps registry complete
341
341
  enabled: (cfg) => cfg.rawHtmlLayout,
342
- // JSX-tag-shaped (`<div style={{...}}>`) — never appears in CSS text.
343
- appliesTo: (relPath) => !relPath.endsWith(".css"),
342
+ // JSX-tag-shaped (`<div style={{...}}>`) — never appears in CSS text. Also excluded from
343
+ // chart files: the remedy (Box/Flex/Grid/Stack/Group) is `@mantine/*`, and src/charts/** is a
344
+ // lint-enforced Mantine-free layer (basalt/token-layer-boundary) — so inside a chart file the
345
+ // finding is unactionable, not merely inconvenient, and the only "fix" would be a theme-allow
346
+ // comment written inside the very directory this rule protects.
347
+ appliesTo: (relPath) => !isChartFile(relPath) && !relPath.endsWith(".css"),
344
348
  message: "Raw HTML element with inline layout/surface styling \u2014 use a Mantine layout primitive (Box/Flex/Grid/Stack/Group)."
345
349
  },
346
350
  "inline-spacing": {
@@ -354,8 +358,12 @@ const GUARD_RULES = {
354
358
  pattern: INLINE_DISPLAY,
355
359
  enabled: (cfg) => cfg.inlineDisplay,
356
360
  // JSX-object-shaped (`display: 'flex'`, quoted value) — CSS never quotes a keyword value
357
- // (`display: flex;` is bare), so the pattern's quote anchor can never match real CSS.
358
- appliesTo: (relPath) => !relPath.endsWith(".css"),
361
+ // (`display: flex;` is bare), so the pattern's quote anchor can never match real CSS. Also
362
+ // excluded from chart files: the remedy (Flex/Grid/Group) is `@mantine/*`, and src/charts/**
363
+ // is a lint-enforced Mantine-free layer (basalt/token-layer-boundary) — so inside a chart file
364
+ // the finding is unactionable, not merely inconvenient, and the only "fix" would be a
365
+ // theme-allow comment written inside the very directory this rule protects.
366
+ appliesTo: (relPath) => !isChartFile(relPath) && !relPath.endsWith(".css"),
359
367
  message: "Use <Flex>/<Grid>/<Group> instead of an inline display:flex/grid."
360
368
  },
361
369
  "raw-visx-axis": {
@@ -291,6 +291,16 @@ export declare const SURFACES: {
291
291
  };
292
292
  readonly forbiddenImports: readonly [ForbiddenImport, ForbiddenImport, ForbiddenImport];
293
293
  };
294
+ readonly './agent-chat': {
295
+ readonly kind: "doctrine";
296
+ readonly layer: "mantine-coupled";
297
+ readonly rule: "agent";
298
+ readonly skill: readonly ["basalt-app"];
299
+ readonly guardKinds: readonly [];
300
+ readonly description: "Mantine-styled thread-chat components over basalt-ui/agent: ThreadWorkspace, ThreadFeed, ThreadOutcomeCard, ThreadDetailPanel, Composer, ThreadTranscript, threadPartRenderers (Mantine-coupled). remend and motion are required, not optional — ThreadTranscript imports content/markdown.tsx (remend eagerly), and ThreadFeed/ThreadDetailPanel import motion/react eagerly, so this subpath fails to resolve without both installed even though peerDependenciesMeta marks them optional (npm has no per-subpath optionality).";
301
+ readonly optionalPeers: readonly ["ai", "motion", "remend", "use-stick-to-bottom", "react-markdown", "remark-gfm", "shiki", "@shikijs/langs", "@shikijs/themes", "beautiful-mermaid"];
302
+ readonly forbiddenImports: readonly [];
303
+ };
294
304
  readonly './content': {
295
305
  readonly kind: "doctrine";
296
306
  readonly layer: "mantine-coupled";
@@ -1 +1 @@
1
- {"version":3,"file":"surfaces.d.ts","sourceRoot":"","sources":["../src/surfaces.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"surfaces.d.ts","sourceRoot":"","sources":["../src/surfaces.ts"],"names":[],"mappings":"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"}
package/dist/surfaces.js CHANGED
@@ -197,6 +197,27 @@ const SURFACES = {
197
197
  // @visx/* ban dropped — `basalt/visx-boundary` now bans it universally outside charts.
198
198
  forbiddenImports: [...MANTINE_BANS]
199
199
  },
200
+ "./agent-chat": {
201
+ kind: "doctrine",
202
+ layer: "mantine-coupled",
203
+ rule: "agent",
204
+ skill: ["basalt-app"],
205
+ guardKinds: [],
206
+ description: "Mantine-styled thread-chat components over basalt-ui/agent: ThreadWorkspace, ThreadFeed, ThreadOutcomeCard, ThreadDetailPanel, Composer, ThreadTranscript, threadPartRenderers (Mantine-coupled). remend and motion are required, not optional \u2014 ThreadTranscript imports content/markdown.tsx (remend eagerly), and ThreadFeed/ThreadDetailPanel import motion/react eagerly, so this subpath fails to resolve without both installed even though peerDependenciesMeta marks them optional (npm has no per-subpath optionality).",
207
+ optionalPeers: [
208
+ "ai",
209
+ "motion",
210
+ "remend",
211
+ "use-stick-to-bottom",
212
+ "react-markdown",
213
+ "remark-gfm",
214
+ "shiki",
215
+ "@shikijs/langs",
216
+ "@shikijs/themes",
217
+ "beautiful-mermaid"
218
+ ],
219
+ forbiddenImports: []
220
+ },
200
221
  "./content": {
201
222
  kind: "doctrine",
202
223
  layer: "mantine-coupled",
package/llms.txt CHANGED
@@ -1,4 +1,4 @@
1
- # basalt-ui v1.8.0
1
+ # basalt-ui v1.10.0
2
2
  # Opinionated framework for Mantine-based React apps — theme, app shell, visx charts, toolchain presets
3
3
  #
4
4
  # basalt-ui is an opinionated framework for Mantine-based React apps.
@@ -19,7 +19,7 @@
19
19
  # ./tokens.css subpath. Guide: docs/FRAMEWORK-FREE.md in the repo.
20
20
 
21
21
  Package: basalt-ui
22
- Version: 1.8.0
22
+ Version: 1.10.0
23
23
 
24
24
  ## basalt-ui
25
25
  Import: import { ... } from 'basalt-ui'
@@ -119,6 +119,13 @@ Layer: headless
119
119
  Rule: basalt-agent
120
120
  OptionalPeers: ai@^7.0.15, use-stick-to-bottom@^1.1.6
121
121
 
122
+ ## basalt-ui/agent-chat
123
+ Import: import { ... } from 'basalt-ui/agent-chat'
124
+ Description: Mantine-styled thread-chat components over basalt-ui/agent: ThreadWorkspace, ThreadFeed, ThreadOutcomeCard, ThreadDetailPanel, Composer, ThreadTranscript, threadPartRenderers (Mantine-coupled). remend and motion are required, not optional — ThreadTranscript imports content/markdown.tsx (remend eagerly), and ThreadFeed/ThreadDetailPanel import motion/react eagerly, so this subpath fails to resolve without both installed even though peerDependenciesMeta marks them optional (npm has no per-subpath optionality).
125
+ Layer: mantine-coupled
126
+ Rule: basalt-agent
127
+ OptionalPeers: ai@^7.0.15, motion@12.42.0, remend@1.3.0, use-stick-to-bottom@^1.1.6, react-markdown@^10.1.0, remark-gfm@^4.0.1, shiki@^4.3.0, @shikijs/langs@^4.3.1, @shikijs/themes@^4.3.1, beautiful-mermaid@^1.1.0
128
+
122
129
  ## basalt-ui/content
123
130
  Import: import { ... } from 'basalt-ui/content'
124
131
  Description: Prose (article/chat typography), CodeBlock (shiki, optional peer), Callout, TableOfContents, ReadingProgress, Markdown (react-markdown + remark-gfm, optional peers, streaming-aware), MermaidDiagram (beautiful-mermaid, optional peer), mdxComponents/createMdxComponents, ArticleLayout (docs-page frame), ArticleCard/ArticleGrid (overview cards), Article model (sortArticles/filterArticles/formatArticleDate), ArticleFilterBar (category/tags filter UI), toArticleActions (Spotlight projector, @mantine/spotlight type-only), GuideLink/GuideDrawer (contextual-help drawer) — the content/prose surface