create-semaphor-app 0.1.4 → 0.1.6
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 +25 -13
- package/bin/create-semaphor-app.mjs +47 -12
- package/package.json +1 -1
- package/scripts/smoke-test.mjs +122 -23
package/README.md
CHANGED
|
@@ -7,8 +7,9 @@ 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
|
-
|
|
10
|
+
dependencies by default, installs the production Semaphor shadcn registry
|
|
11
|
+
components, and can optionally install the Semaphor Agent Plugin for detected
|
|
12
|
+
Codex and Claude Code installations.
|
|
12
13
|
|
|
13
14
|
It does not authenticate to Semaphor, write tokens, or choose a project/domain.
|
|
14
15
|
The Semaphor Agent Plugin handles OAuth, project selection, runtime token
|
|
@@ -25,7 +26,7 @@ When `app-name` is omitted, the CLI creates `./semaphor-data-app`.
|
|
|
25
26
|
Options:
|
|
26
27
|
|
|
27
28
|
```text
|
|
28
|
-
--no-install Skip dependency installation.
|
|
29
|
+
--no-install Skip dependency installation. Requires --components none.
|
|
29
30
|
--package-manager <name> Use npm, pnpm, yarn, or bun. Defaults to detected npm.
|
|
30
31
|
--skip-plugin Skip Codex/Claude plugin install prompts.
|
|
31
32
|
--install-codex-plugin Install the Codex plugin without prompting.
|
|
@@ -34,8 +35,8 @@ Options:
|
|
|
34
35
|
--template-ref <ref> Git branch/tag for the default starter repo. Defaults to main.
|
|
35
36
|
--shadcn-preset <preset> Apply a shadcn preset before adding Semaphor components.
|
|
36
37
|
--shadcn-base <base> Pass base or radix to shadcn init when using a preset.
|
|
37
|
-
--components <list> Add Semaphor registry components. Use none,
|
|
38
|
-
filters, card, table, matrix, recommended, all, or a comma-separated list.
|
|
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.
|
|
39
40
|
--yes Use noninteractive defaults; skip optional plugin installs unless explicit.
|
|
40
41
|
--help Show help.
|
|
41
42
|
```
|
|
@@ -49,10 +50,14 @@ style, pass a shadcn preset during creation:
|
|
|
49
50
|
npx create-semaphor-app@latest my-app --shadcn-preset <preset-id>
|
|
50
51
|
```
|
|
51
52
|
|
|
52
|
-
Semaphor UI helpers
|
|
53
|
-
|
|
53
|
+
Semaphor UI helpers are added from the public shadcn registry at scaffold time.
|
|
54
|
+
By default, `create-semaphor-app` installs all production app-building
|
|
55
|
+
components. Use `--components none` when you want the starter without Semaphor
|
|
56
|
+
registry components:
|
|
54
57
|
|
|
55
58
|
```bash
|
|
59
|
+
npx create-semaphor-app@latest my-app
|
|
60
|
+
npx create-semaphor-app@latest my-app --components none
|
|
56
61
|
npx create-semaphor-app@latest my-app --components table
|
|
57
62
|
npx create-semaphor-app@latest my-app --components query-state,view-card,metric-kpis,filter-controls,server-data-table,matrix-table
|
|
58
63
|
```
|
|
@@ -61,7 +66,8 @@ Component presets:
|
|
|
61
66
|
|
|
62
67
|
| Value | Installs |
|
|
63
68
|
| --- | --- |
|
|
64
|
-
| `none` | No Semaphor registry components.
|
|
69
|
+
| `none` | No Semaphor registry components. |
|
|
70
|
+
| `kit` | `data-app-kit`, the one-command registry bundle. |
|
|
65
71
|
| `query` | `query-state` |
|
|
66
72
|
| `metrics` | `query-state-boundary`, `metric-kpis` |
|
|
67
73
|
| `filters` | `filter-controls` |
|
|
@@ -69,14 +75,20 @@ Component presets:
|
|
|
69
75
|
| `table` | `query-state`, `server-data-table` |
|
|
70
76
|
| `matrix` | `query-state`, `matrix-table` |
|
|
71
77
|
| `recommended` | `query-state`, `query-state-boundary`, `view-card`, `metric-kpis`, `filter-controls`, `server-data-table` |
|
|
72
|
-
| `all` |
|
|
78
|
+
| `all` | Full component set, installed through `data-app-kit`. This is the default. |
|
|
73
79
|
|
|
74
80
|
Registry components install as source into the generated app. They are optional
|
|
75
81
|
UI accelerators and do not replace `react-semaphor/data-app-sdk`.
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
the
|
|
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.
|
|
80
92
|
|
|
81
93
|
## Local Validation
|
|
82
94
|
|
|
@@ -14,6 +14,7 @@ const DEFAULT_APP_NAME = 'semaphor-data-app';
|
|
|
14
14
|
const MARKETPLACE = 'semaphor-analytics/agent-plugin';
|
|
15
15
|
const PLUGIN_ID = 'semaphor@semaphor-analytics';
|
|
16
16
|
const SEMAPHOR_COMPONENT_REGISTRY = 'semaphor-analytics/semaphor-data-app-components';
|
|
17
|
+
const SEMAPHOR_COMPONENT_KIT = 'data-app-kit';
|
|
17
18
|
const SEMAPHOR_COMPONENT_PRESETS = Object.freeze({
|
|
18
19
|
none: [],
|
|
19
20
|
query: ['query-state'],
|
|
@@ -41,6 +42,8 @@ const SEMAPHOR_COMPONENT_PRESETS = Object.freeze({
|
|
|
41
42
|
],
|
|
42
43
|
});
|
|
43
44
|
const SEMAPHOR_COMPONENT_ALIASES = Object.freeze({
|
|
45
|
+
kit: SEMAPHOR_COMPONENT_KIT,
|
|
46
|
+
'data-app-kit': SEMAPHOR_COMPONENT_KIT,
|
|
44
47
|
'query-state': 'query-state',
|
|
45
48
|
'query-state-boundary': 'query-state-boundary',
|
|
46
49
|
'view-card': 'view-card',
|
|
@@ -65,7 +68,7 @@ Usage:
|
|
|
65
68
|
npx create-semaphor-app@latest [app-name] [options]
|
|
66
69
|
|
|
67
70
|
Options:
|
|
68
|
-
--no-install Skip dependency installation.
|
|
71
|
+
--no-install Skip dependency installation. Requires --components none.
|
|
69
72
|
--package-manager <name> Use npm, pnpm, yarn, or bun.
|
|
70
73
|
--skip-plugin Skip Codex/Claude plugin install prompts.
|
|
71
74
|
--install-codex-plugin Install the Codex plugin without prompting.
|
|
@@ -74,8 +77,8 @@ Options:
|
|
|
74
77
|
--template-ref <ref> Git branch/tag for the default starter repo.
|
|
75
78
|
--shadcn-preset <preset> Apply a shadcn preset before adding Semaphor components.
|
|
76
79
|
--shadcn-base <base> Pass base or radix to shadcn init when using a preset.
|
|
77
|
-
--components <list> Add Semaphor registry components. Use none,
|
|
78
|
-
filters, card, table, matrix, recommended, all, or a comma-separated list.
|
|
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.
|
|
79
82
|
--yes, -y Use noninteractive defaults; skip optional plugin installs unless explicit.
|
|
80
83
|
--help, -h Show this help.
|
|
81
84
|
`;
|
|
@@ -93,7 +96,7 @@ function parseArgs(argv) {
|
|
|
93
96
|
templateRef: DEFAULT_TEMPLATE_REF,
|
|
94
97
|
shadcnPreset: null,
|
|
95
98
|
shadcnBase: null,
|
|
96
|
-
components: '
|
|
99
|
+
components: 'all',
|
|
97
100
|
yes: false,
|
|
98
101
|
help: false,
|
|
99
102
|
};
|
|
@@ -407,7 +410,7 @@ function normalizeSemaphorComponents(value) {
|
|
|
407
410
|
}
|
|
408
411
|
if (!hasOwn(SEMAPHOR_COMPONENT_ALIASES, entry)) {
|
|
409
412
|
throw new Error(
|
|
410
|
-
`Unsupported Semaphor component "${entry}". Use none, query, metrics, filters, card, table, matrix, recommended, all, or one of ${Object.keys(SEMAPHOR_COMPONENT_ALIASES).join(', ')}.`,
|
|
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(', ')}.`,
|
|
411
414
|
);
|
|
412
415
|
}
|
|
413
416
|
components.push(SEMAPHOR_COMPONENT_ALIASES[entry]);
|
|
@@ -453,6 +456,44 @@ function runShadcn(packageManager, targetDir, args) {
|
|
|
453
456
|
});
|
|
454
457
|
}
|
|
455
458
|
|
|
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
|
+
|
|
456
497
|
function customizeShadcn(args, packageManager, targetDir) {
|
|
457
498
|
const components = normalizeSemaphorComponents(args.components);
|
|
458
499
|
const shadcnBase = normalizeShadcnBase(args.shadcnBase);
|
|
@@ -481,13 +522,7 @@ function customizeShadcn(args, packageManager, targetDir) {
|
|
|
481
522
|
|
|
482
523
|
if (components.length > 0) {
|
|
483
524
|
console.log('\nAdding Semaphor registry components...');
|
|
484
|
-
|
|
485
|
-
runShadcn(packageManager, targetDir, [
|
|
486
|
-
'add',
|
|
487
|
-
`${SEMAPHOR_COMPONENT_REGISTRY}/${component}`,
|
|
488
|
-
]);
|
|
489
|
-
console.log(`✓ Added ${component}`);
|
|
490
|
-
}
|
|
525
|
+
installSemaphorRegistryComponents(packageManager, targetDir, components);
|
|
491
526
|
}
|
|
492
527
|
|
|
493
528
|
return { presetApplied: Boolean(args.shadcnPreset), components };
|
package/package.json
CHANGED
package/scripts/smoke-test.mjs
CHANGED
|
@@ -98,6 +98,8 @@ async function main() {
|
|
|
98
98
|
'--template',
|
|
99
99
|
defaultLocalStarterPath,
|
|
100
100
|
'--no-install',
|
|
101
|
+
'--components',
|
|
102
|
+
'none',
|
|
101
103
|
'--skip-plugin',
|
|
102
104
|
'--yes',
|
|
103
105
|
], { cwd: root });
|
|
@@ -113,6 +115,8 @@ async function main() {
|
|
|
113
115
|
'--template',
|
|
114
116
|
defaultLocalStarterPath,
|
|
115
117
|
'--no-install',
|
|
118
|
+
'--components',
|
|
119
|
+
'none',
|
|
116
120
|
'--skip-plugin',
|
|
117
121
|
'--yes',
|
|
118
122
|
], { cwd: root });
|
|
@@ -126,6 +130,8 @@ async function main() {
|
|
|
126
130
|
const result = runCli([
|
|
127
131
|
'github-template-app',
|
|
128
132
|
'--no-install',
|
|
133
|
+
'--components',
|
|
134
|
+
'none',
|
|
129
135
|
'--skip-plugin',
|
|
130
136
|
'--yes',
|
|
131
137
|
], { cwd: root });
|
|
@@ -146,6 +152,8 @@ async function main() {
|
|
|
146
152
|
'--template',
|
|
147
153
|
defaultLocalStarterPath,
|
|
148
154
|
'--no-install',
|
|
155
|
+
'--components',
|
|
156
|
+
'none',
|
|
149
157
|
'--install-codex-plugin',
|
|
150
158
|
], {
|
|
151
159
|
cwd: root,
|
|
@@ -168,6 +176,42 @@ async function main() {
|
|
|
168
176
|
console.log('✓ fake Codex plugin install path');
|
|
169
177
|
}
|
|
170
178
|
|
|
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
|
+
|
|
171
215
|
{
|
|
172
216
|
const root = createTempRoot('shadcn-');
|
|
173
217
|
const binDir = path.join(root, 'bin');
|
|
@@ -208,34 +252,89 @@ async function main() {
|
|
|
208
252
|
'expected shadcn preset init command',
|
|
209
253
|
);
|
|
210
254
|
assert(
|
|
211
|
-
log.includes('npx shadcn@latest add semaphor-analytics/semaphor-data-app-components/
|
|
212
|
-
'expected
|
|
213
|
-
);
|
|
214
|
-
assert(
|
|
215
|
-
log.includes('npx shadcn@latest add semaphor-analytics/semaphor-data-app-components/query-state-boundary'),
|
|
216
|
-
'expected query-state-boundary registry add command',
|
|
217
|
-
);
|
|
218
|
-
assert(
|
|
219
|
-
log.includes('npx shadcn@latest add semaphor-analytics/semaphor-data-app-components/view-card'),
|
|
220
|
-
'expected view-card registry add command',
|
|
221
|
-
);
|
|
222
|
-
assert(
|
|
223
|
-
log.includes('npx shadcn@latest add semaphor-analytics/semaphor-data-app-components/metric-kpis'),
|
|
224
|
-
'expected metric-kpis registry add command',
|
|
225
|
-
);
|
|
226
|
-
assert(
|
|
227
|
-
log.includes('npx shadcn@latest add semaphor-analytics/semaphor-data-app-components/filter-controls'),
|
|
228
|
-
'expected filter-controls registry add command',
|
|
255
|
+
log.includes('npx shadcn@latest add semaphor-analytics/semaphor-data-app-components/data-app-kit'),
|
|
256
|
+
'expected full component selection to use data-app-kit registry add command',
|
|
229
257
|
);
|
|
258
|
+
console.log('✓ shadcn preset and registry component path');
|
|
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');
|
|
230
290
|
assert(
|
|
231
|
-
log.includes('npx shadcn@latest add semaphor-analytics/semaphor-data-app-components/
|
|
232
|
-
'expected
|
|
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',
|
|
233
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');
|
|
234
326
|
assert(
|
|
235
|
-
log.includes(
|
|
236
|
-
|
|
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',
|
|
237
336
|
);
|
|
238
|
-
console.log('✓
|
|
337
|
+
console.log('✓ Semaphor component subset installs in one command');
|
|
239
338
|
}
|
|
240
339
|
|
|
241
340
|
{
|