@databricks/design-system 2.0.8 → 2.0.9
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/CHANGELOG.md +4 -0
- package/package.json +2 -1
- package/scaffold-agents.md +3 -0
- package/setup.mjs +80 -27
package/CHANGELOG.md
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@databricks/design-system",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.9",
|
|
4
4
|
"description": "DuBois Design System",
|
|
5
5
|
"keywords": [],
|
|
6
6
|
"license": "ISC",
|
|
@@ -56,6 +56,7 @@
|
|
|
56
56
|
"/AGENTS.md",
|
|
57
57
|
"/CHANGELOG.md",
|
|
58
58
|
"/setup.mjs",
|
|
59
|
+
"/scaffold-agents.md",
|
|
59
60
|
"dist",
|
|
60
61
|
"dist-types",
|
|
61
62
|
"test-utils",
|
package/setup.mjs
CHANGED
|
@@ -92,7 +92,11 @@ function ask(rl, question) {
|
|
|
92
92
|
// Runs a command with inherited stdio so the canonical scaffolder's own prompts/output reach the
|
|
93
93
|
// user directly. Exits the process on failure rather than half-finishing a setup.
|
|
94
94
|
function run(command, commandArgs, cwd) {
|
|
95
|
-
|
|
95
|
+
// Quiet npm to errors only, inherited by every npm/npx child (our installs and the
|
|
96
|
+
// sub-scaffolders' internal ones): the deprecation and ERESOLVE peer warnings they print are
|
|
97
|
+
// noise here. Non-npm tools ignore this var.
|
|
98
|
+
const env = { ...process.env, npm_config_loglevel: 'error' };
|
|
99
|
+
const result = spawnSync(command, commandArgs, { cwd, stdio: 'inherit', shell: false, env });
|
|
96
100
|
if (result.status !== 0) {
|
|
97
101
|
fail(`\`${command} ${commandArgs.join(' ')}\` failed (exit ${result.status}).`);
|
|
98
102
|
}
|
|
@@ -224,7 +228,11 @@ function scaffoldVite(name) {
|
|
|
224
228
|
console.log(`\n> Scaffolding a Vite + React + TypeScript project via ${VITE_SCAFFOLDER}…\n`);
|
|
225
229
|
// npx runs the already-`create-`-prefixed package directly (unlike `npm create`, which would
|
|
226
230
|
// prepend a second `create-`), matching how the Next path invokes create-next-app.
|
|
227
|
-
run
|
|
231
|
+
// Force create-vite fully non-interactive — this CLI is run by non-engineers, so its own mode
|
|
232
|
+
// prompt should be the only question. --template picks React+TS and --eslint answers the
|
|
233
|
+
// linter question; --no-interactive suppresses any remaining prompt and --no-immediate keeps
|
|
234
|
+
// create-vite from installing/starting a dev server ahead of our own install steps.
|
|
235
|
+
run('npx', [VITE_SCAFFOLDER, name, '--template', 'react-ts', '--eslint', '--no-interactive', '--no-immediate']);
|
|
228
236
|
|
|
229
237
|
const dir = path.resolve(process.cwd(), name);
|
|
230
238
|
const pm = detectPackageManager(dir);
|
|
@@ -261,10 +269,55 @@ function scaffoldVite(name) {
|
|
|
261
269
|
ensureCssDeclaration(dir, 'vite');
|
|
262
270
|
configureViteEmotion(dir);
|
|
263
271
|
addTsconfigJsxImportSource(path.join(dir, 'tsconfig.app.json'));
|
|
272
|
+
removeViteDemoFiles(dir);
|
|
273
|
+
writeAgentInstructions(dir);
|
|
264
274
|
|
|
265
275
|
printDone(name, pm, 'vite');
|
|
266
276
|
}
|
|
267
277
|
|
|
278
|
+
// create-vite ships a demo splash page (App.css, a styled default index.css, and the Vite/React
|
|
279
|
+
// logo + hero assets). We render our own empty App and rely on dbui's global styles, so delete
|
|
280
|
+
// the demo files to leave a genuinely blank project. Our main.tsx imports none of them.
|
|
281
|
+
function removeViteDemoFiles(dir) {
|
|
282
|
+
for (const rel of ['src/App.css', 'src/index.css', 'src/assets']) {
|
|
283
|
+
fs.rmSync(path.join(dir, rel), { recursive: true, force: true });
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
// Writes agent instructions into the generated project so AI coding agents build UI from dbui
|
|
288
|
+
// components. AGENTS.md holds the guidance (its body ships beside this script); CLAUDE.md just
|
|
289
|
+
// imports it, because Claude Code only auto-loads CLAUDE.md, not AGENTS.md. Neither overwrites an
|
|
290
|
+
// existing file — an existing project may already carry its own. Returns whether it wrote AGENTS.md.
|
|
291
|
+
function writeAgentInstructions(dir) {
|
|
292
|
+
let wroteAgents = false;
|
|
293
|
+
const agentsPath = path.join(dir, 'AGENTS.md');
|
|
294
|
+
if (!fs.existsSync(agentsPath)) {
|
|
295
|
+
const body = readScaffoldAgents();
|
|
296
|
+
if (body === undefined) return false;
|
|
297
|
+
writeFileEnsuringDir(agentsPath, body);
|
|
298
|
+
wroteAgents = true;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
// One source of truth: Claude Code follows this import, other agents read AGENTS.md directly.
|
|
302
|
+
const claudePath = path.join(dir, 'CLAUDE.md');
|
|
303
|
+
if (!fs.existsSync(claudePath)) writeFileEnsuringDir(claudePath, '@AGENTS.md\n');
|
|
304
|
+
|
|
305
|
+
return wroteAgents;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
// The AGENTS.md body ships beside this script (copied from npm_publishing/ at publish time) so it
|
|
309
|
+
// can be edited without touching the CLI. A missing file means a packaging problem — skip the agent
|
|
310
|
+
// docs rather than abort a scaffold that has already installed successfully.
|
|
311
|
+
function readScaffoldAgents() {
|
|
312
|
+
try {
|
|
313
|
+
const templatePath = path.join(path.dirname(fileURLToPath(import.meta.url)), 'scaffold-agents.md');
|
|
314
|
+
return fs.readFileSync(templatePath, 'utf8');
|
|
315
|
+
} catch {
|
|
316
|
+
console.warn('> Skipping AGENTS.md/CLAUDE.md (bundled scaffold-agents.md not found).');
|
|
317
|
+
return undefined;
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
|
|
268
321
|
// create-vite's react plugin drives the JSX transform, so the Emotion `css` prop needs its
|
|
269
322
|
// jsxImportSource option — the runtime half of the Emotion setup (the tsconfig half is separate).
|
|
270
323
|
function configureViteEmotion(dir) {
|
|
@@ -344,6 +397,7 @@ function scaffoldNext(name) {
|
|
|
344
397
|
configureNextEmotion(dir);
|
|
345
398
|
addTsconfigJsxImportSource(path.join(dir, 'tsconfig.json'));
|
|
346
399
|
writeVercelReadme(dir, name);
|
|
400
|
+
writeAgentInstructions(dir);
|
|
347
401
|
|
|
348
402
|
printDone(name, pm, 'next');
|
|
349
403
|
}
|
|
@@ -419,6 +473,9 @@ function addToExisting(dir) {
|
|
|
419
473
|
if (entry && addImports(entry, CSS_IMPORTS)) {
|
|
420
474
|
console.log(`> Added the dbui CSS imports to ${path.relative(dir, entry)}`);
|
|
421
475
|
}
|
|
476
|
+
if (writeAgentInstructions(dir)) {
|
|
477
|
+
console.log('> Added AGENTS.md instructing agents to use @databricks/design-system for UI');
|
|
478
|
+
}
|
|
422
479
|
printManualInstructions(detected.type);
|
|
423
480
|
}
|
|
424
481
|
|
|
@@ -478,17 +535,7 @@ function sampleBody() {
|
|
|
478
535
|
}
|
|
479
536
|
|
|
480
537
|
function viteAppFile() {
|
|
481
|
-
return [
|
|
482
|
-
"import { Button, Typography, useDesignSystemTheme } from '@databricks/design-system';",
|
|
483
|
-
'',
|
|
484
|
-
'export function App() {',
|
|
485
|
-
' const { theme } = useDesignSystemTheme();',
|
|
486
|
-
' return (',
|
|
487
|
-
sampleBody(),
|
|
488
|
-
' );',
|
|
489
|
-
'}',
|
|
490
|
-
'',
|
|
491
|
-
].join('\n');
|
|
538
|
+
return ['// Build your app here.', 'export function App() {', ' return null;', '}', ''].join('\n');
|
|
492
539
|
}
|
|
493
540
|
|
|
494
541
|
// The client-only module Next loads with ssr:false: it owns the DesignSystemProvider and the
|
|
@@ -544,27 +591,33 @@ async function promptMode(rl) {
|
|
|
544
591
|
async function main() {
|
|
545
592
|
const args = parseArgs(process.argv.slice(2));
|
|
546
593
|
|
|
594
|
+
// Collect every interactive answer first, then close readline before shelling out. While the
|
|
595
|
+
// interface is open it holds the TTY in raw mode, which passes through to the scaffolders (and
|
|
596
|
+
// to any dev server they'd start), so Ctrl+C would never reach them. Closing it restores the
|
|
597
|
+
// normal terminal so child processes handle their own signals.
|
|
547
598
|
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
599
|
+
let mode;
|
|
600
|
+
let name;
|
|
548
601
|
try {
|
|
549
|
-
|
|
602
|
+
mode = args.mode ?? (await promptMode(rl));
|
|
550
603
|
if (!mode || !['vite', 'next', 'existing'].includes(mode)) fail('Please choose 1, 2, or 3.');
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
return;
|
|
555
|
-
}
|
|
556
|
-
|
|
557
|
-
const name = args.name || (await ask(rl, `\nProject name (new directory): `));
|
|
558
|
-
if (!name) fail('A project name is required.');
|
|
559
|
-
if (fs.existsSync(path.resolve(process.cwd(), name))) {
|
|
560
|
-
fail(`\`${name}\` already exists here. Choose a name that isn't taken.`);
|
|
604
|
+
if (mode !== 'existing') {
|
|
605
|
+
name = args.name || (await ask(rl, `\nProject name (new directory): `));
|
|
606
|
+
if (!name) fail('A project name is required.');
|
|
561
607
|
}
|
|
562
|
-
|
|
563
|
-
if (mode === 'vite') scaffoldVite(name);
|
|
564
|
-
else scaffoldNext(name);
|
|
565
608
|
} finally {
|
|
566
609
|
rl.close();
|
|
567
610
|
}
|
|
611
|
+
|
|
612
|
+
if (mode === 'existing') {
|
|
613
|
+
addToExisting(process.cwd());
|
|
614
|
+
return;
|
|
615
|
+
}
|
|
616
|
+
if (fs.existsSync(path.resolve(process.cwd(), name))) {
|
|
617
|
+
fail(`\`${name}\` already exists here. Choose a name that isn't taken.`);
|
|
618
|
+
}
|
|
619
|
+
if (mode === 'vite') scaffoldVite(name);
|
|
620
|
+
else scaffoldNext(name);
|
|
568
621
|
}
|
|
569
622
|
|
|
570
623
|
// A bin is symlinked into node_modules/.bin, so compare realpaths (not the raw argv path) to tell
|