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.
- package/AGENTS.md +1 -0
- package/CHANGELOG.md +25 -0
- package/README.md +64 -34
- package/agent/rules/basalt-agent.md +49 -6
- package/agent/rules/basalt-charts.md +74 -5
- package/configs/oxlint-plugin.js +279 -0
- package/configs/oxlint-plugin.test.ts +216 -1
- package/configs/oxlint.json +5 -2
- package/dist/agent/use-agent-thread-runs.d.ts.map +1 -1
- package/dist/agent/use-agent-thread-runs.js +1 -0
- package/dist/agent-chat/index.d.ts +4 -3
- package/dist/agent-chat/index.d.ts.map +1 -1
- package/dist/charts/hooks/useHoverSync.d.ts +18 -2
- package/dist/charts/hooks/useHoverSync.d.ts.map +1 -1
- package/dist/charts/hooks/useHoverSync.js +12 -7
- package/dist/charts/index.d.ts +1 -0
- package/dist/charts/index.d.ts.map +1 -1
- package/dist/charts/index.js +6 -0
- package/dist/charts/kinds/Bars.d.ts +2 -0
- package/dist/charts/kinds/Bars.d.ts.map +1 -1
- package/dist/charts/kinds/Bars.js +3 -1
- package/dist/charts/kinds/Donut.d.ts +2 -0
- package/dist/charts/kinds/Donut.d.ts.map +1 -1
- package/dist/charts/kinds/Donut.js +8 -4
- package/dist/charts/kinds/DualPanel.d.ts +2 -0
- package/dist/charts/kinds/DualPanel.d.ts.map +1 -1
- package/dist/charts/kinds/DualPanel.js +2 -1
- package/dist/charts/kinds/Heatmap.d.ts +8 -0
- package/dist/charts/kinds/Heatmap.d.ts.map +1 -1
- package/dist/charts/kinds/Heatmap.js +7 -3
- package/dist/charts/kinds/MultiLine.d.ts +2 -0
- package/dist/charts/kinds/MultiLine.d.ts.map +1 -1
- package/dist/charts/kinds/MultiLine.js +2 -1
- package/dist/charts/kinds/StackedArea.d.ts +2 -0
- package/dist/charts/kinds/StackedArea.d.ts.map +1 -1
- package/dist/charts/kinds/StackedArea.js +2 -1
- package/dist/charts/kinds/ZonedLine.d.ts +2 -0
- package/dist/charts/kinds/ZonedLine.d.ts.map +1 -1
- package/dist/charts/kinds/ZonedLine.js +2 -1
- package/dist/charts/primitives/Axes.d.ts +6 -1
- package/dist/charts/primitives/Axes.d.ts.map +1 -1
- package/dist/charts/primitives/Axes.js +3 -2
- package/dist/charts/primitives/ChartFrame.d.ts +8 -1
- package/dist/charts/primitives/ChartFrame.d.ts.map +1 -1
- package/dist/charts/primitives/ChartFrame.js +8 -4
- package/dist/charts/primitives/ChartPending.d.ts +34 -0
- package/dist/charts/primitives/ChartPending.d.ts.map +1 -0
- package/dist/charts/primitives/ChartPending.js +23 -0
- package/dist/charts/primitives/ChartTooltip.d.ts +5 -2
- package/dist/charts/primitives/ChartTooltip.d.ts.map +1 -1
- package/dist/charts/primitives/ChartTooltip.js +6 -1
- package/dist/charts/primitives/HoverOverlay.d.ts +5 -4
- package/dist/charts/primitives/HoverOverlay.d.ts.map +1 -1
- package/dist/charts/primitives/HoverOverlay.js +4 -2
- package/dist/cli/index.d.ts +55 -1
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +217 -5
- package/dist/dashboard/stat-card.d.ts.map +1 -1
- package/dist/guard/index.d.ts.map +1 -1
- package/dist/guard/index.js +13 -5
- package/dist/surfaces.d.ts +10 -0
- package/dist/surfaces.d.ts.map +1 -1
- package/dist/surfaces.js +21 -0
- package/llms.txt +9 -2
- package/package.json +8 -5
- package/src/agent/ai-sdk-transport.test.ts +269 -0
- package/src/agent/parts.test.ts +261 -0
- package/src/agent/thread.test.ts +147 -0
- package/src/agent/use-agent-stream.test.tsx +231 -0
- package/src/agent/use-agent-thread-runs.resume.test.tsx +261 -0
- package/src/agent/use-agent-thread-runs.test.tsx +398 -0
- package/src/agent/use-agent-thread-runs.ts +7 -1
- package/src/agent/use-agent-thread-runs.wedge.test.tsx +299 -0
- package/src/agent-chat/index.ts +4 -3
- package/src/charts/hooks/useHoverSync.ts +43 -7
- package/src/charts/index.ts +6 -0
- package/src/charts/kinds/Bars.tsx +4 -0
- package/src/charts/kinds/Donut.tsx +10 -4
- package/src/charts/kinds/DualPanel.tsx +5 -1
- package/src/charts/kinds/Heatmap.tsx +19 -2
- package/src/charts/kinds/MultiLine.tsx +4 -1
- package/src/charts/kinds/StackedArea.tsx +4 -1
- package/src/charts/kinds/ZonedLine.tsx +4 -1
- package/src/charts/primitives/Axes.tsx +7 -1
- package/src/charts/primitives/ChartFrame.test.tsx +67 -0
- package/src/charts/primitives/ChartFrame.tsx +17 -4
- package/src/charts/primitives/ChartPending.tsx +59 -0
- package/src/charts/primitives/ChartTooltip.tsx +15 -3
- package/src/charts/primitives/HoverOverlay.tsx +12 -6
- package/src/cli/index.ts +439 -5
- package/src/cli/placement-engine.test.ts +104 -0
- package/src/dashboard/stat-card.test.tsx +5 -3
- package/src/dashboard/stat-card.tsx +12 -0
- package/src/guard/check-source.test.ts +20 -0
- package/src/guard/index.ts +20 -9
- package/src/provider/index.test.tsx +6 -5
- package/src/surfaces.ts +22 -0
- package/src/theme/use-basalt-spacing.test.tsx +7 -4
- 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
|
-
/**
|
|
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").
|
|
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;
|
|
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
|
-
|
|
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 {
|
|
2
|
-
/** Transparent <rect> that captures
|
|
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:
|
|
7
|
-
onLeave:
|
|
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,
|
|
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
|
-
|
|
15
|
-
|
|
14
|
+
style: { touchAction: "pan-y" },
|
|
15
|
+
onPointerMove: onMove,
|
|
16
|
+
onPointerLeave: onLeave,
|
|
17
|
+
onPointerCancel: onLeave
|
|
16
18
|
}
|
|
17
19
|
);
|
|
18
20
|
}
|
package/dist/cli/index.d.ts
CHANGED
|
@@ -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
|
*/
|
package/dist/cli/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":"AAmCA,OAAO,KAAK,EAAwB,SAAS,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AAE9E,OAAO,EAAE,UAAU,EAAE,WAAW,EAA2C,MAAM,aAAa,CAAA;AAI9F,yEAAyE;AACzE,MAAM,MAAM,YAAY,GAAG;IACzB,sFAAsF;IACtF,KAAK,CAAC,EAAE,MAAM,EAAE,CAAA;IAChB,4FAA4F;IAC5F,MAAM,CAAC,EAAE,MAAM,EAAE,CAAA;IACjB,uGAAuG;IACvG,YAAY,CAAC,EAAE,MAAM,EAAE,CAAA;IACvB;wFACoF;IACpF,QAAQ,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,SAAS,EAAE,aAAa,CAAC,CAAC,CAAA;IACpD,6FAA6F;IAC7F,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAA;IAC3B,iFAAiF;IACjF,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB;;;;OAIG;IACH,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB;;;;OAIG;IACH,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB;;;;;;OAMG;IACH,cAAc,CAAC,EAAE,OAAO,CAAA;IACxB;;;;OAIG;IACH,mBAAmB,CAAC,EAAE,OAAO,CAAA;IAC7B;;;;;;;OAOG;IACH,iBAAiB,CAAC,EAAE,OAAO,CAAA;IAC3B;;;;;OAKG;IACH,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB;;;;OAIG;IACH,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB;;;;OAIG;IACH,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB;;;;;;OAMG;IACH,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB;;;;OAIG;IACH,cAAc,CAAC,EAAE,OAAO,CAAA;IACxB;;;;OAIG;IACH,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB;;;;OAIG;IACH,qBAAqB,CAAC,EAAE,OAAO,CAAA;IAC/B;;;;;OAKG;IACH,cAAc,CAAC,EAAE,OAAO,CAAA;IACxB;;;;;OAKG;IACH,cAAc,CAAC,EAAE,OAAO,CAAA;IACxB;;;OAGG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB;;;;;;;;;;OAUG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,SAAS,EAAE,MAAM,EAAE,CAAC,CAAC,CAAA;
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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":"
|
|
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;
|
|
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"}
|
package/dist/guard/index.js
CHANGED
|
@@ -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.
|
|
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
|
-
|
|
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
|
-
|
|
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": {
|
package/dist/surfaces.d.ts
CHANGED
|
@@ -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";
|
package/dist/surfaces.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"surfaces.d.ts","sourceRoot":"","sources":["../src/surfaces.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,eAAe,CAAA;AAI9C;;;;;GAKG;AACH,MAAM,MAAM,QAAQ,GAChB,QAAQ,GACR,QAAQ,GACR,SAAS,GACT,QAAQ,GACR,OAAO,GACP,OAAO,GACP,OAAO,GACP,eAAe,GACf,UAAU,GACV,MAAM,GACN,OAAO,GACP,SAAS,GACT,KAAK,CAAA;AAET;;;;;GAKG;AACH,MAAM,MAAM,SAAS,GAAG,YAAY,GAAG,eAAe,GAAG,eAAe,CAAA;AAExE;;;;GAIG;AACH,MAAM,MAAM,KAAK,GAAG,iBAAiB,GAAG,UAAU,GAAG,YAAY,GAAG,cAAc,CAAA;AAElF;;;;;;GAMG;AACH,MAAM,MAAM,eAAe,GAAG;IAC5B,mEAAmE;IACnE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,wFAAwF;IACxF,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAA;IAChC,oFAAoF;IACpF,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,oFAAoF;IACpF,QAAQ,CAAC,WAAW,CAAC,EAAE,IAAI,CAAA;IAC3B,2FAA2F;IAC3F,QAAQ,CAAC,QAAQ,CAAC,EAAE,IAAI,CAAA;CACzB,CAAA;AAED;;;;;GAKG;AACH,MAAM,MAAM,YAAY,GAAG;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,KAAK,EAAE,KAAK,GAAG,MAAM,GAAG,OAAO,CAAA;IACxC,QAAQ,CAAC,MAAM,CAAC,EAAE,SAAS,GAAG,MAAM,CAAA;CACrC,CAAA;AAID,KAAK,WAAW,GAAG;IACjB,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAA;IACrB,QAAQ,CAAC,gBAAgB,EAAE,SAAS,eAAe,EAAE,CAAA;IACrD,QAAQ,CAAC,aAAa,CAAC,EAAE,SAAS,YAAY,EAAE,CAAA;IAChD;;;OAGG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAA;IAC7B;;;OAGG;IACH,QAAQ,CAAC,KAAK,CAAC,EAAE;QACf,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAA;QACnC,QAAQ,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,CAAA;KACjC,CAAA;IACD;;;;;;OAMG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;CAC3C,CAAA;AAED;;;;;;;GAOG;AACH,MAAM,MAAM,YAAY,GAAG,WAAW,GAAG;IACvC,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAA;IACzB,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAA;IACvB,iGAAiG;IACjG,QAAQ,CAAC,KAAK,EAAE,SAAS,SAAS,EAAE,CAAA;IACpC,2FAA2F;IAC3F,QAAQ,CAAC,UAAU,EAAE,SAAS,SAAS,EAAE,CAAA;CAC1C,CAAA;AAED;;;;;;;GAOG;AACH,MAAM,MAAM,WAAW,GAAG,WAAW,GAAG;IACtC,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAA;IACxB,QAAQ,CAAC,IAAI,CAAC,EAAE,KAAK,CAAA;IACrB,QAAQ,CAAC,KAAK,CAAC,EAAE,KAAK,CAAA;IACtB,QAAQ,CAAC,UAAU,CAAC,EAAE,KAAK,CAAA;CAC5B,CAAA;AAED,kEAAkE;AAClE,MAAM,MAAM,WAAW,GAAG,YAAY,GAAG,WAAW,CAAA;AA8BpD;;;;;;;;;GASG;AACH,eAAO,MAAM,QAAQ
|
|
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.
|
|
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.
|
|
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
|