create-semaphor-app 0.1.6 → 0.1.8
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/README.md +27 -45
- package/bin/create-semaphor-app.mjs +9 -138
- package/package.json +1 -1
- package/scripts/smoke-test.mjs +6 -131
package/README.md
CHANGED
|
@@ -7,9 +7,10 @@ npx create-semaphor-app@latest
|
|
|
7
7
|
```
|
|
8
8
|
|
|
9
9
|
The CLI scaffolds the public Semaphor Data App Starter, installs local
|
|
10
|
-
dependencies by default,
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
dependencies by default, and can optionally install the Semaphor Agent Plugin
|
|
11
|
+
for detected Codex and Claude Code installations. The starter already includes
|
|
12
|
+
the Semaphor-specific Data App components and local samples used by agents for
|
|
13
|
+
first-run dashboard quality.
|
|
13
14
|
|
|
14
15
|
It does not authenticate to Semaphor, write tokens, or choose a project/domain.
|
|
15
16
|
The Semaphor Agent Plugin handles OAuth, project selection, runtime token
|
|
@@ -26,22 +27,20 @@ When `app-name` is omitted, the CLI creates `./semaphor-data-app`.
|
|
|
26
27
|
Options:
|
|
27
28
|
|
|
28
29
|
```text
|
|
29
|
-
--no-install Skip dependency installation.
|
|
30
|
+
--no-install Skip dependency installation.
|
|
30
31
|
--package-manager <name> Use npm, pnpm, yarn, or bun. Defaults to detected npm.
|
|
31
32
|
--skip-plugin Skip Codex/Claude plugin install prompts.
|
|
32
33
|
--install-codex-plugin Install the Codex plugin without prompting.
|
|
33
34
|
--install-claude-plugin Install the Claude Code plugin without prompting.
|
|
34
35
|
--template <source> Starter source. Defaults to the public starter repo.
|
|
35
36
|
--template-ref <ref> Git branch/tag for the default starter repo. Defaults to main.
|
|
36
|
-
--shadcn-preset <preset> Apply a shadcn preset
|
|
37
|
+
--shadcn-preset <preset> Apply a shadcn preset after scaffolding.
|
|
37
38
|
--shadcn-base <base> Pass base or radix to shadcn init when using a preset.
|
|
38
|
-
--components <list> Add Semaphor registry components. Defaults to all. Use none, kit, query,
|
|
39
|
-
metrics, filters, card, table, matrix, recommended, all, or a comma-separated list.
|
|
40
39
|
--yes Use noninteractive defaults; skip optional plugin installs unless explicit.
|
|
41
40
|
--help Show help.
|
|
42
41
|
```
|
|
43
42
|
|
|
44
|
-
## shadcn Presets
|
|
43
|
+
## shadcn Presets
|
|
45
44
|
|
|
46
45
|
The starter ships with a working shadcn setup. For teams that bring their own
|
|
47
46
|
style, pass a shadcn preset during creation:
|
|
@@ -50,45 +49,28 @@ style, pass a shadcn preset during creation:
|
|
|
50
49
|
npx create-semaphor-app@latest my-app --shadcn-preset <preset-id>
|
|
51
50
|
```
|
|
52
51
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
registry components:
|
|
52
|
+
`--shadcn-preset` runs the shadcn CLI. To skip installs entirely, pass
|
|
53
|
+
`--no-install`, then run dependency and shadcn commands manually later if
|
|
54
|
+
needed.
|
|
57
55
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
56
|
+
## Included Semaphor Components
|
|
57
|
+
|
|
58
|
+
The generated starter includes Semaphor-specific source components under
|
|
59
|
+
`src/components/semaphor/*` and browsable local samples at `/samples`. The
|
|
60
|
+
components are normal app source files, not a separate runtime package:
|
|
61
|
+
|
|
62
|
+
- query loading/error/empty/success states;
|
|
63
|
+
- SDK-shaped query state boundaries;
|
|
64
|
+
- view cards with scoped filter affordances;
|
|
65
|
+
- metric KPI and multi-measure KPI helpers;
|
|
66
|
+
- filter controls;
|
|
67
|
+
- server-backed tables;
|
|
68
|
+
- matrix/pivot tables.
|
|
64
69
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
| `none` | No Semaphor registry components. |
|
|
70
|
-
| `kit` | `data-app-kit`, the one-command registry bundle. |
|
|
71
|
-
| `query` | `query-state` |
|
|
72
|
-
| `metrics` | `query-state-boundary`, `metric-kpis` |
|
|
73
|
-
| `filters` | `filter-controls` |
|
|
74
|
-
| `card` | `view-card` |
|
|
75
|
-
| `table` | `query-state`, `server-data-table` |
|
|
76
|
-
| `matrix` | `query-state`, `matrix-table` |
|
|
77
|
-
| `recommended` | `query-state`, `query-state-boundary`, `view-card`, `metric-kpis`, `filter-controls`, `server-data-table` |
|
|
78
|
-
| `all` | Full component set, installed through `data-app-kit`. This is the default. |
|
|
79
|
-
|
|
80
|
-
Registry components install as source into the generated app. They are optional
|
|
81
|
-
UI accelerators and do not replace `react-semaphor/data-app-sdk`.
|
|
82
|
-
The default starter keeps its shadcn primitives aligned with the public
|
|
83
|
-
registry, so default component installs should not ask overwrite questions.
|
|
84
|
-
`create-semaphor-app` does not pass `--overwrite`; customer-owned base
|
|
85
|
-
components stay intact. During the `data-app-kit` rollout, the CLI falls back
|
|
86
|
-
to one multi-component install if an older registry deployment does not have
|
|
87
|
-
the kit item yet.
|
|
88
|
-
|
|
89
|
-
`--shadcn-preset` and installed registry components run the shadcn CLI. To skip
|
|
90
|
-
installs, pass `--no-install --components none`, then run the shadcn commands
|
|
91
|
-
manually later if needed.
|
|
70
|
+
This keeps the default scaffold fast and avoids shadcn overwrite prompts for
|
|
71
|
+
Semaphor components. Customers can still customize shadcn primitives or apply a
|
|
72
|
+
preset, but the default path does not require installing a second component
|
|
73
|
+
registry.
|
|
92
74
|
|
|
93
75
|
## Local Validation
|
|
94
76
|
|
|
@@ -13,50 +13,6 @@ const DEFAULT_TEMPLATE_REF = 'main';
|
|
|
13
13
|
const DEFAULT_APP_NAME = 'semaphor-data-app';
|
|
14
14
|
const MARKETPLACE = 'semaphor-analytics/agent-plugin';
|
|
15
15
|
const PLUGIN_ID = 'semaphor@semaphor-analytics';
|
|
16
|
-
const SEMAPHOR_COMPONENT_REGISTRY = 'semaphor-analytics/semaphor-data-app-components';
|
|
17
|
-
const SEMAPHOR_COMPONENT_KIT = 'data-app-kit';
|
|
18
|
-
const SEMAPHOR_COMPONENT_PRESETS = Object.freeze({
|
|
19
|
-
none: [],
|
|
20
|
-
query: ['query-state'],
|
|
21
|
-
table: ['query-state', 'server-data-table'],
|
|
22
|
-
metrics: ['query-state-boundary', 'metric-kpis'],
|
|
23
|
-
filters: ['filter-controls'],
|
|
24
|
-
card: ['view-card'],
|
|
25
|
-
matrix: ['query-state', 'matrix-table'],
|
|
26
|
-
recommended: [
|
|
27
|
-
'query-state',
|
|
28
|
-
'query-state-boundary',
|
|
29
|
-
'view-card',
|
|
30
|
-
'metric-kpis',
|
|
31
|
-
'filter-controls',
|
|
32
|
-
'server-data-table',
|
|
33
|
-
],
|
|
34
|
-
all: [
|
|
35
|
-
'query-state',
|
|
36
|
-
'query-state-boundary',
|
|
37
|
-
'view-card',
|
|
38
|
-
'metric-kpis',
|
|
39
|
-
'filter-controls',
|
|
40
|
-
'server-data-table',
|
|
41
|
-
'matrix-table',
|
|
42
|
-
],
|
|
43
|
-
});
|
|
44
|
-
const SEMAPHOR_COMPONENT_ALIASES = Object.freeze({
|
|
45
|
-
kit: SEMAPHOR_COMPONENT_KIT,
|
|
46
|
-
'data-app-kit': SEMAPHOR_COMPONENT_KIT,
|
|
47
|
-
'query-state': 'query-state',
|
|
48
|
-
'query-state-boundary': 'query-state-boundary',
|
|
49
|
-
'view-card': 'view-card',
|
|
50
|
-
card: 'view-card',
|
|
51
|
-
'server-data-table': 'server-data-table',
|
|
52
|
-
table: 'server-data-table',
|
|
53
|
-
'metric-kpis': 'metric-kpis',
|
|
54
|
-
kpis: 'metric-kpis',
|
|
55
|
-
'filter-controls': 'filter-controls',
|
|
56
|
-
filters: 'filter-controls',
|
|
57
|
-
'matrix-table': 'matrix-table',
|
|
58
|
-
matrix: 'matrix-table',
|
|
59
|
-
});
|
|
60
16
|
const canPrompt = Boolean(process.stdin.isTTY && process.stdout.isTTY);
|
|
61
17
|
|
|
62
18
|
const cwd = process.cwd();
|
|
@@ -68,17 +24,15 @@ Usage:
|
|
|
68
24
|
npx create-semaphor-app@latest [app-name] [options]
|
|
69
25
|
|
|
70
26
|
Options:
|
|
71
|
-
--no-install Skip dependency installation.
|
|
27
|
+
--no-install Skip dependency installation.
|
|
72
28
|
--package-manager <name> Use npm, pnpm, yarn, or bun.
|
|
73
29
|
--skip-plugin Skip Codex/Claude plugin install prompts.
|
|
74
30
|
--install-codex-plugin Install the Codex plugin without prompting.
|
|
75
31
|
--install-claude-plugin Install the Claude Code plugin without prompting.
|
|
76
32
|
--template <source> Starter source. Can be a local directory or git URL.
|
|
77
33
|
--template-ref <ref> Git branch/tag for the default starter repo.
|
|
78
|
-
--shadcn-preset <preset> Apply a shadcn preset
|
|
34
|
+
--shadcn-preset <preset> Apply a shadcn preset after scaffolding.
|
|
79
35
|
--shadcn-base <base> Pass base or radix to shadcn init when using a preset.
|
|
80
|
-
--components <list> Add Semaphor registry components. Defaults to all. Use none, kit, query,
|
|
81
|
-
metrics, filters, card, table, matrix, recommended, all, or a comma-separated list.
|
|
82
36
|
--yes, -y Use noninteractive defaults; skip optional plugin installs unless explicit.
|
|
83
37
|
--help, -h Show this help.
|
|
84
38
|
`;
|
|
@@ -96,7 +50,6 @@ function parseArgs(argv) {
|
|
|
96
50
|
templateRef: DEFAULT_TEMPLATE_REF,
|
|
97
51
|
shadcnPreset: null,
|
|
98
52
|
shadcnBase: null,
|
|
99
|
-
components: 'all',
|
|
100
53
|
yes: false,
|
|
101
54
|
help: false,
|
|
102
55
|
};
|
|
@@ -133,10 +86,6 @@ function parseArgs(argv) {
|
|
|
133
86
|
parsed.shadcnBase = readRequiredValue(argv, ++i, arg);
|
|
134
87
|
} else if (arg.startsWith('--shadcn-base=')) {
|
|
135
88
|
parsed.shadcnBase = arg.slice('--shadcn-base='.length);
|
|
136
|
-
} else if (arg === '--components') {
|
|
137
|
-
parsed.components = readRequiredValue(argv, ++i, arg);
|
|
138
|
-
} else if (arg.startsWith('--components=')) {
|
|
139
|
-
parsed.components = arg.slice('--components='.length);
|
|
140
89
|
} else if (arg === '--yes' || arg === '-y') {
|
|
141
90
|
parsed.yes = true;
|
|
142
91
|
} else if (arg.startsWith('-')) {
|
|
@@ -288,10 +237,6 @@ function resolvePackageManager(requested) {
|
|
|
288
237
|
return 'npm';
|
|
289
238
|
}
|
|
290
239
|
|
|
291
|
-
function hasOwn(object, key) {
|
|
292
|
-
return Object.prototype.hasOwnProperty.call(object, key);
|
|
293
|
-
}
|
|
294
|
-
|
|
295
240
|
function resolveShadcnRunner(packageManager) {
|
|
296
241
|
if (packageManager === 'pnpm') {
|
|
297
242
|
return { command: 'pnpm', args: ['dlx', 'shadcn@latest'] };
|
|
@@ -395,30 +340,6 @@ function loadTemplate(template, templateRef) {
|
|
|
395
340
|
return { tempRoot, templateDir };
|
|
396
341
|
}
|
|
397
342
|
|
|
398
|
-
function normalizeSemaphorComponents(value) {
|
|
399
|
-
const raw = String(value || 'none')
|
|
400
|
-
.split(',')
|
|
401
|
-
.map((entry) => entry.trim().toLowerCase())
|
|
402
|
-
.filter(Boolean);
|
|
403
|
-
if (raw.length === 0) return [];
|
|
404
|
-
|
|
405
|
-
const components = [];
|
|
406
|
-
for (const entry of raw) {
|
|
407
|
-
if (hasOwn(SEMAPHOR_COMPONENT_PRESETS, entry)) {
|
|
408
|
-
components.push(...SEMAPHOR_COMPONENT_PRESETS[entry]);
|
|
409
|
-
continue;
|
|
410
|
-
}
|
|
411
|
-
if (!hasOwn(SEMAPHOR_COMPONENT_ALIASES, entry)) {
|
|
412
|
-
throw new Error(
|
|
413
|
-
`Unsupported Semaphor component "${entry}". Use none, kit, query, metrics, filters, card, table, matrix, recommended, all, or one of ${Object.keys(SEMAPHOR_COMPONENT_ALIASES).join(', ')}.`,
|
|
414
|
-
);
|
|
415
|
-
}
|
|
416
|
-
components.push(SEMAPHOR_COMPONENT_ALIASES[entry]);
|
|
417
|
-
}
|
|
418
|
-
|
|
419
|
-
return Array.from(new Set(components));
|
|
420
|
-
}
|
|
421
|
-
|
|
422
343
|
function normalizeShadcnBase(value) {
|
|
423
344
|
if (!value) return null;
|
|
424
345
|
const normalized = String(value).trim().toLowerCase();
|
|
@@ -429,7 +350,6 @@ function normalizeShadcnBase(value) {
|
|
|
429
350
|
}
|
|
430
351
|
|
|
431
352
|
function validateScaffoldOptions(args) {
|
|
432
|
-
const components = normalizeSemaphorComponents(args.components);
|
|
433
353
|
normalizeShadcnBase(args.shadcnBase);
|
|
434
354
|
|
|
435
355
|
if (args.shadcnBase && !args.shadcnPreset) {
|
|
@@ -440,9 +360,9 @@ function validateScaffoldOptions(args) {
|
|
|
440
360
|
throw new Error('--shadcn-preset requires a non-empty preset id.');
|
|
441
361
|
}
|
|
442
362
|
|
|
443
|
-
if (!args.install &&
|
|
363
|
+
if (!args.install && args.shadcnPreset) {
|
|
444
364
|
throw new Error(
|
|
445
|
-
'--no-install cannot be combined with --shadcn-preset
|
|
365
|
+
'--no-install cannot be combined with --shadcn-preset. Run create-semaphor-app with installs enabled, or apply the shadcn preset manually after scaffolding.',
|
|
446
366
|
);
|
|
447
367
|
}
|
|
448
368
|
}
|
|
@@ -456,50 +376,11 @@ function runShadcn(packageManager, targetDir, args) {
|
|
|
456
376
|
});
|
|
457
377
|
}
|
|
458
378
|
|
|
459
|
-
function selectedComponentsUseFullKit(components) {
|
|
460
|
-
const selected = new Set(components);
|
|
461
|
-
const full = SEMAPHOR_COMPONENT_PRESETS.all;
|
|
462
|
-
return selected.size === full.length && full.every((component) => selected.has(component));
|
|
463
|
-
}
|
|
464
|
-
|
|
465
|
-
function componentRegistryAddress(component) {
|
|
466
|
-
return `${SEMAPHOR_COMPONENT_REGISTRY}/${component}`;
|
|
467
|
-
}
|
|
468
|
-
|
|
469
|
-
function installSemaphorRegistryComponents(packageManager, targetDir, components) {
|
|
470
|
-
if (components.length === 0) return [];
|
|
471
|
-
|
|
472
|
-
if (selectedComponentsUseFullKit(components)) {
|
|
473
|
-
try {
|
|
474
|
-
runShadcn(packageManager, targetDir, [
|
|
475
|
-
'add',
|
|
476
|
-
componentRegistryAddress(SEMAPHOR_COMPONENT_KIT),
|
|
477
|
-
]);
|
|
478
|
-
console.log(`✓ Added ${SEMAPHOR_COMPONENT_KIT}`);
|
|
479
|
-
return [SEMAPHOR_COMPONENT_KIT];
|
|
480
|
-
} catch {
|
|
481
|
-
console.log(
|
|
482
|
-
'data-app-kit was not available from the registry yet; falling back to individual Semaphor components.',
|
|
483
|
-
);
|
|
484
|
-
}
|
|
485
|
-
}
|
|
486
|
-
|
|
487
|
-
runShadcn(packageManager, targetDir, [
|
|
488
|
-
'add',
|
|
489
|
-
...components.map(componentRegistryAddress),
|
|
490
|
-
]);
|
|
491
|
-
for (const component of components) {
|
|
492
|
-
console.log(`✓ Added ${component}`);
|
|
493
|
-
}
|
|
494
|
-
return components;
|
|
495
|
-
}
|
|
496
|
-
|
|
497
379
|
function customizeShadcn(args, packageManager, targetDir) {
|
|
498
|
-
const components = normalizeSemaphorComponents(args.components);
|
|
499
380
|
const shadcnBase = normalizeShadcnBase(args.shadcnBase);
|
|
500
381
|
|
|
501
|
-
if (!args.shadcnPreset
|
|
502
|
-
return { presetApplied: false
|
|
382
|
+
if (!args.shadcnPreset) {
|
|
383
|
+
return { presetApplied: false };
|
|
503
384
|
}
|
|
504
385
|
|
|
505
386
|
if (args.shadcnPreset) {
|
|
@@ -520,12 +401,7 @@ function customizeShadcn(args, packageManager, targetDir) {
|
|
|
520
401
|
console.log('✓ Applied shadcn preset');
|
|
521
402
|
}
|
|
522
403
|
|
|
523
|
-
|
|
524
|
-
console.log('\nAdding Semaphor registry components...');
|
|
525
|
-
installSemaphorRegistryComponents(packageManager, targetDir, components);
|
|
526
|
-
}
|
|
527
|
-
|
|
528
|
-
return { presetApplied: Boolean(args.shadcnPreset), components };
|
|
404
|
+
return { presetApplied: true };
|
|
529
405
|
}
|
|
530
406
|
|
|
531
407
|
function detectAgents() {
|
|
@@ -630,14 +506,9 @@ function printNextSteps({ targetDir, packageManager, pluginSummary, shadcnSummar
|
|
|
630
506
|
console.log(` cd ${relativeTarget}`);
|
|
631
507
|
console.log(` ${packageManager} run dev`);
|
|
632
508
|
|
|
633
|
-
if (shadcnSummary?.presetApplied
|
|
509
|
+
if (shadcnSummary?.presetApplied) {
|
|
634
510
|
console.log('\nConfigured shadcn:');
|
|
635
|
-
|
|
636
|
-
console.log(' - Applied custom preset');
|
|
637
|
-
}
|
|
638
|
-
for (const component of shadcnSummary.components ?? []) {
|
|
639
|
-
console.log(` - Added Semaphor ${component}`);
|
|
640
|
-
}
|
|
511
|
+
console.log(' - Applied custom preset');
|
|
641
512
|
}
|
|
642
513
|
|
|
643
514
|
if (pluginSummary?.skipped) {
|
package/package.json
CHANGED
package/scripts/smoke-test.mjs
CHANGED
|
@@ -98,8 +98,6 @@ async function main() {
|
|
|
98
98
|
'--template',
|
|
99
99
|
defaultLocalStarterPath,
|
|
100
100
|
'--no-install',
|
|
101
|
-
'--components',
|
|
102
|
-
'none',
|
|
103
101
|
'--skip-plugin',
|
|
104
102
|
'--yes',
|
|
105
103
|
], { cwd: root });
|
|
@@ -115,8 +113,6 @@ async function main() {
|
|
|
115
113
|
'--template',
|
|
116
114
|
defaultLocalStarterPath,
|
|
117
115
|
'--no-install',
|
|
118
|
-
'--components',
|
|
119
|
-
'none',
|
|
120
116
|
'--skip-plugin',
|
|
121
117
|
'--yes',
|
|
122
118
|
], { cwd: root });
|
|
@@ -130,8 +126,6 @@ async function main() {
|
|
|
130
126
|
const result = runCli([
|
|
131
127
|
'github-template-app',
|
|
132
128
|
'--no-install',
|
|
133
|
-
'--components',
|
|
134
|
-
'none',
|
|
135
129
|
'--skip-plugin',
|
|
136
130
|
'--yes',
|
|
137
131
|
], { cwd: root });
|
|
@@ -152,8 +146,6 @@ async function main() {
|
|
|
152
146
|
'--template',
|
|
153
147
|
defaultLocalStarterPath,
|
|
154
148
|
'--no-install',
|
|
155
|
-
'--components',
|
|
156
|
-
'none',
|
|
157
149
|
'--install-codex-plugin',
|
|
158
150
|
], {
|
|
159
151
|
cwd: root,
|
|
@@ -176,42 +168,6 @@ async function main() {
|
|
|
176
168
|
console.log('✓ fake Codex plugin install path');
|
|
177
169
|
}
|
|
178
170
|
|
|
179
|
-
{
|
|
180
|
-
const root = createTempRoot('default-components-');
|
|
181
|
-
const binDir = path.join(root, 'bin');
|
|
182
|
-
fs.mkdirSync(binDir, { recursive: true });
|
|
183
|
-
const shadcnLog = path.join(root, 'shadcn.log');
|
|
184
|
-
const npmLog = path.join(root, 'npm.log');
|
|
185
|
-
createFakeCommand(binDir, 'npx', shadcnLog);
|
|
186
|
-
createFakeCommand(binDir, 'npm', npmLog);
|
|
187
|
-
|
|
188
|
-
const result = runCli([
|
|
189
|
-
'default-components-app',
|
|
190
|
-
'--template',
|
|
191
|
-
defaultLocalStarterPath,
|
|
192
|
-
'--skip-plugin',
|
|
193
|
-
'--yes',
|
|
194
|
-
'--package-manager',
|
|
195
|
-
'npm',
|
|
196
|
-
], {
|
|
197
|
-
cwd: root,
|
|
198
|
-
env: {
|
|
199
|
-
...process.env,
|
|
200
|
-
PATH: `${binDir}${path.delimiter}${process.env.PATH || ''}`,
|
|
201
|
-
},
|
|
202
|
-
});
|
|
203
|
-
assertSuccess(result, 'default component install');
|
|
204
|
-
assertScaffold(root, 'default-components-app');
|
|
205
|
-
const npmInstallLog = fs.readFileSync(npmLog, 'utf8');
|
|
206
|
-
assert(npmInstallLog.includes('npm install'), 'expected npm install command');
|
|
207
|
-
const log = fs.readFileSync(shadcnLog, 'utf8');
|
|
208
|
-
assert(
|
|
209
|
-
log.includes('npx shadcn@latest add semaphor-analytics/semaphor-data-app-components/data-app-kit'),
|
|
210
|
-
'expected default data-app-kit registry add command',
|
|
211
|
-
);
|
|
212
|
-
console.log('✓ default Semaphor registry component install');
|
|
213
|
-
}
|
|
214
|
-
|
|
215
171
|
{
|
|
216
172
|
const root = createTempRoot('shadcn-');
|
|
217
173
|
const binDir = path.join(root, 'bin');
|
|
@@ -233,8 +189,6 @@ async function main() {
|
|
|
233
189
|
'test-preset',
|
|
234
190
|
'--shadcn-base',
|
|
235
191
|
'base',
|
|
236
|
-
'--components',
|
|
237
|
-
'recommended,matrix-table',
|
|
238
192
|
], {
|
|
239
193
|
cwd: root,
|
|
240
194
|
env: {
|
|
@@ -242,7 +196,7 @@ async function main() {
|
|
|
242
196
|
PATH: `${binDir}${path.delimiter}${process.env.PATH || ''}`,
|
|
243
197
|
},
|
|
244
198
|
});
|
|
245
|
-
assertSuccess(result, 'shadcn preset
|
|
199
|
+
assertSuccess(result, 'shadcn preset install');
|
|
246
200
|
assertScaffold(root, 'styled-app');
|
|
247
201
|
const npmInstallLog = fs.readFileSync(npmLog, 'utf8');
|
|
248
202
|
assert(npmInstallLog.includes('npm install'), 'expected npm install command');
|
|
@@ -252,89 +206,10 @@ async function main() {
|
|
|
252
206
|
'expected shadcn preset init command',
|
|
253
207
|
);
|
|
254
208
|
assert(
|
|
255
|
-
log.includes('npx shadcn@latest add
|
|
256
|
-
'
|
|
209
|
+
!log.includes('npx shadcn@latest add'),
|
|
210
|
+
'create-semaphor-app should not run shadcn add during scaffold',
|
|
257
211
|
);
|
|
258
|
-
console.log('✓ shadcn preset
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
{
|
|
262
|
-
const root = createTempRoot('component-kit-alias-');
|
|
263
|
-
const binDir = path.join(root, 'bin');
|
|
264
|
-
fs.mkdirSync(binDir, { recursive: true });
|
|
265
|
-
const shadcnLog = path.join(root, 'shadcn.log');
|
|
266
|
-
const npmLog = path.join(root, 'npm.log');
|
|
267
|
-
createFakeCommand(binDir, 'npx', shadcnLog);
|
|
268
|
-
createFakeCommand(binDir, 'npm', npmLog);
|
|
269
|
-
|
|
270
|
-
const result = runCli([
|
|
271
|
-
'kit-alias-app',
|
|
272
|
-
'--template',
|
|
273
|
-
defaultLocalStarterPath,
|
|
274
|
-
'--skip-plugin',
|
|
275
|
-
'--yes',
|
|
276
|
-
'--package-manager',
|
|
277
|
-
'npm',
|
|
278
|
-
'--components',
|
|
279
|
-
'kit',
|
|
280
|
-
], {
|
|
281
|
-
cwd: root,
|
|
282
|
-
env: {
|
|
283
|
-
...process.env,
|
|
284
|
-
PATH: `${binDir}${path.delimiter}${process.env.PATH || ''}`,
|
|
285
|
-
},
|
|
286
|
-
});
|
|
287
|
-
assertSuccess(result, 'component kit alias install');
|
|
288
|
-
assertScaffold(root, 'kit-alias-app');
|
|
289
|
-
const log = fs.readFileSync(shadcnLog, 'utf8');
|
|
290
|
-
assert(
|
|
291
|
-
log.includes('npx shadcn@latest add semaphor-analytics/semaphor-data-app-components/data-app-kit'),
|
|
292
|
-
'expected kit alias to use data-app-kit registry add command',
|
|
293
|
-
);
|
|
294
|
-
console.log('✓ Semaphor data-app-kit component alias');
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
{
|
|
298
|
-
const root = createTempRoot('component-subset-');
|
|
299
|
-
const binDir = path.join(root, 'bin');
|
|
300
|
-
fs.mkdirSync(binDir, { recursive: true });
|
|
301
|
-
const shadcnLog = path.join(root, 'shadcn.log');
|
|
302
|
-
const npmLog = path.join(root, 'npm.log');
|
|
303
|
-
createFakeCommand(binDir, 'npx', shadcnLog);
|
|
304
|
-
createFakeCommand(binDir, 'npm', npmLog);
|
|
305
|
-
|
|
306
|
-
const result = runCli([
|
|
307
|
-
'subset-app',
|
|
308
|
-
'--template',
|
|
309
|
-
defaultLocalStarterPath,
|
|
310
|
-
'--skip-plugin',
|
|
311
|
-
'--yes',
|
|
312
|
-
'--package-manager',
|
|
313
|
-
'npm',
|
|
314
|
-
'--components',
|
|
315
|
-
'table,filters',
|
|
316
|
-
], {
|
|
317
|
-
cwd: root,
|
|
318
|
-
env: {
|
|
319
|
-
...process.env,
|
|
320
|
-
PATH: `${binDir}${path.delimiter}${process.env.PATH || ''}`,
|
|
321
|
-
},
|
|
322
|
-
});
|
|
323
|
-
assertSuccess(result, 'component subset install');
|
|
324
|
-
assertScaffold(root, 'subset-app');
|
|
325
|
-
const log = fs.readFileSync(shadcnLog, 'utf8');
|
|
326
|
-
assert(
|
|
327
|
-
log.includes(
|
|
328
|
-
[
|
|
329
|
-
'npx shadcn@latest add',
|
|
330
|
-
'semaphor-analytics/semaphor-data-app-components/query-state',
|
|
331
|
-
'semaphor-analytics/semaphor-data-app-components/server-data-table',
|
|
332
|
-
'semaphor-analytics/semaphor-data-app-components/filter-controls',
|
|
333
|
-
].join(' '),
|
|
334
|
-
),
|
|
335
|
-
'expected subset components to install in one registry add command',
|
|
336
|
-
);
|
|
337
|
-
console.log('✓ Semaphor component subset installs in one command');
|
|
212
|
+
console.log('✓ shadcn preset path');
|
|
338
213
|
}
|
|
339
214
|
|
|
340
215
|
{
|
|
@@ -346,8 +221,8 @@ async function main() {
|
|
|
346
221
|
'--no-install',
|
|
347
222
|
'--skip-plugin',
|
|
348
223
|
'--yes',
|
|
349
|
-
'--
|
|
350
|
-
'
|
|
224
|
+
'--shadcn-preset',
|
|
225
|
+
'test-preset',
|
|
351
226
|
], { cwd: root });
|
|
352
227
|
assert(result.status !== 0, 'expected shadcn options with --no-install to fail');
|
|
353
228
|
assert(
|