@datashow/super-visual-cli 0.1.0-rc.4 → 0.1.0-rc.5

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@datashow/super-visual-cli",
3
- "version": "0.1.0-rc.4",
3
+ "version": "0.1.0-rc.5",
4
4
  "description": "CLI for validating, compiling, packaging, verifying, and deploying Super Visual projects.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -25,10 +25,10 @@
25
25
  "access": "public"
26
26
  },
27
27
  "dependencies": {
28
- "@datashow/super-visual-adapter-claude-dashboard": "0.1.0-rc.4",
29
- "@datashow/super-visual-compiler": "0.1.0-rc.4",
30
- "@datashow/super-visual-contracts": "0.1.0-rc.4",
31
- "@datashow/super-visual-fabric": "0.1.0-rc.4",
28
+ "@datashow/super-visual-adapter-claude-dashboard": "0.1.0-rc.5",
29
+ "@datashow/super-visual-compiler": "0.1.0-rc.5",
30
+ "@datashow/super-visual-contracts": "0.1.0-rc.5",
31
+ "@datashow/super-visual-fabric": "0.1.0-rc.5",
32
32
  "@fontsource/source-serif-4": "5.3.1",
33
33
  "@nivo/bar": "0.99.0",
34
34
  "@nivo/line": "0.99.0",
package/src/main.mjs CHANGED
@@ -16,7 +16,7 @@ import { resolveProjectTarget, targetUpdate, writeProjectTarget } from "./projec
16
16
  import { runSemanticPreviewTest, startSemanticPreview } from "./semantic-preview.mjs";
17
17
 
18
18
  const run = promisify(execFile);
19
- const VERSION = "0.1.0-rc.4";
19
+ const VERSION = "0.1.0-rc.5";
20
20
  const FABRIC_ID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
21
21
  const SPINNER_FRAMES = ["|", "/", "-", "\\"];
22
22
  const progressStream = process.stderr;
@@ -65,7 +65,7 @@ export function stopActiveProgress() {
65
65
  activeProgress = null;
66
66
  }
67
67
 
68
- export function writeInitProgress(event) {
68
+ export function writeCommandProgress(event) {
69
69
  if (event.status === "running") {
70
70
  stopActiveProgress();
71
71
  writeProgress(`> ${event.message}\n`);
@@ -87,6 +87,14 @@ export function writeInitProgress(event) {
87
87
  writeProgress(`${marker} ${event.message}\n`);
88
88
  }
89
89
 
90
+ function printPreviewResult(result) {
91
+ process.stdout.write(`\nLocal preview is ready.\n`);
92
+ process.stdout.write(`URL: ${result.url}\n`);
93
+ process.stdout.write(`Workspace: ${result.workspace.displayName} (${result.workspace.id})\n`);
94
+ process.stdout.write(`Semantic model: ${result.semanticModel.displayName} (${result.semanticModel.id})\n`);
95
+ process.stdout.write("The preview is using live semantic-model data. Press Ctrl+C to stop it.\n");
96
+ }
97
+
90
98
  function semanticInventory(model) {
91
99
  const tables = model.tables ?? [];
92
100
  return {
@@ -345,7 +353,7 @@ function createProgram() {
345
353
  workspaceId: options.workspaceId,
346
354
  workspaceName: options.workspaceName,
347
355
  semanticModelId: options.semanticModelId,
348
- onProgress: json ? null : writeInitProgress,
356
+ onProgress: json ? null : writeCommandProgress,
349
357
  });
350
358
  } catch (error) {
351
359
  throw new CliUserError(error instanceof Error ? error.message : String(error), {
@@ -361,7 +369,7 @@ function createProgram() {
361
369
  semanticModel: { id: inspected.semanticModel.id, displayName: inspected.semanticModel.displayName, format: inspected.semanticModel.format },
362
370
  inventory: semanticInventory(inspected.semanticModel),
363
371
  };
364
- if (!json) writeInitProgress({ status: "passed", message: `Verified workspace ${inspected.workspace.displayName} and semantic model ${inspected.semanticModel.displayName}` });
372
+ if (!json) writeCommandProgress({ status: "passed", message: `Verified workspace ${inspected.workspace.displayName} and semantic model ${inspected.semanticModel.displayName}` });
365
373
  } else if (!json && options.skipLiveValidation) {
366
374
  writeProgress("! Live Fabric validation skipped by request\n");
367
375
  } else if (!json) {
@@ -374,10 +382,10 @@ function createProgram() {
374
382
  title: options.title,
375
383
  app: options.app,
376
384
  force: options.force,
377
- onProgress: json ? null : writeInitProgress,
385
+ onProgress: json ? null : writeCommandProgress,
378
386
  });
379
387
  if (options.workspaceId) {
380
- if (!json) writeInitProgress({ status: "running", message: "Saving the reusable Fabric project binding" });
388
+ if (!json) writeCommandProgress({ status: "running", message: "Saving the reusable Fabric project binding" });
381
389
  const saved = await writeProjectTarget(result.directory, targetUpdate({
382
390
  ...options,
383
391
  workspaceName: options.workspaceName ?? liveValidation?.workspace.displayName,
@@ -385,7 +393,7 @@ function createProgram() {
385
393
  reportName: options.reportName ?? result.application.title,
386
394
  }));
387
395
  result.binding = { file: saved.file, ...saved.value };
388
- if (!json) writeInitProgress({ status: "passed", message: `Saved Fabric binding to ${saved.file}` });
396
+ if (!json) writeCommandProgress({ status: "passed", message: `Saved Fabric binding to ${saved.file}` });
389
397
  }
390
398
  result.validation = { local: result.validation, live: liveValidation ?? { ok: true, status: "not-run", scope: "fabric-read-only" } };
391
399
  if (json) output(result, true);
@@ -434,23 +442,38 @@ function createProgram() {
434
442
  .option("--open", "open the preview in the default browser")
435
443
  .option("--timeout <seconds>", "Fabric operation timeout", "900")
436
444
  .action(async (project = ".", options, command) => {
437
- await syncProjectSource(projectFile(project));
438
- const loaded = await loadProject(projectFile(project));
439
- const target = await resolveProjectTarget(loaded.root, options, { requireSemanticModel: true });
440
- const client = new FabricHttpClient({ timeoutSeconds: Number(options.timeout) });
441
- const preview = await startSemanticPreview({
442
- client,
443
- projectFile: projectFile(project),
444
- workspaceId: target.workspaceId,
445
- workspaceName: target.workspaceName,
446
- semanticModelId: target.semanticModelId ?? target.managedSemanticModelId,
447
- host: options.host,
448
- port: Number(options.port),
449
- open: Boolean(options.open),
450
- });
451
- const { close, ...result } = preview;
452
- output(result, jsonEnabled(command));
453
- await waitForPreviewShutdown({ close });
445
+ const json = jsonEnabled(command);
446
+ if (!json) writeProgress(`\nSuper Visual dev\n\n`);
447
+ try {
448
+ if (!json) writeCommandProgress({ status: "running", message: "Synchronizing the React source and report contract" });
449
+ await syncProjectSource(projectFile(project));
450
+ if (!json) writeCommandProgress({ status: "passed", message: "Synchronized the React source and report contract" });
451
+ if (!json) writeCommandProgress({ status: "running", message: "Loading the saved Fabric project binding" });
452
+ const loaded = await loadProject(projectFile(project));
453
+ const target = await resolveProjectTarget(loaded.root, options, { requireSemanticModel: true });
454
+ if (!json) writeCommandProgress({ status: "passed", message: "Loaded the Fabric workspace and semantic-model binding" });
455
+ const client = new FabricHttpClient({ timeoutSeconds: Number(options.timeout) });
456
+ const preview = await startSemanticPreview({
457
+ client,
458
+ projectFile: projectFile(project),
459
+ workspaceId: target.workspaceId,
460
+ workspaceName: target.workspaceName,
461
+ semanticModelId: target.semanticModelId ?? target.managedSemanticModelId,
462
+ host: options.host,
463
+ port: Number(options.port),
464
+ open: Boolean(options.open),
465
+ onProgress: json ? null : writeCommandProgress,
466
+ });
467
+ const { close, ...result } = preview;
468
+ if (json) output(result, true);
469
+ else printPreviewResult(result);
470
+ await waitForPreviewShutdown({ close });
471
+ } catch (error) {
472
+ throw new CliUserError(error instanceof Error ? error.message : String(error), {
473
+ summary: "Super Visual could not start the local semantic preview.",
474
+ guidance: "Check the project binding and your Fabric access, then run supervisual dev --open again.",
475
+ });
476
+ }
454
477
  });
455
478
 
456
479
  const preview = program.command("preview").description("exercise the local React host against a live semantic model");
@@ -396,15 +396,18 @@ async function writePreviewHost(root, token) {
396
396
  await writeFile(path.join(root, "src", "config.ts"), `export const PREVIEW_TOKEN = ${JSON.stringify(token)};\n`);
397
397
  }
398
398
 
399
- export async function startSemanticPreview({ client, projectFile, workspaceId, workspaceName, semanticModelId, host = "127.0.0.1", port = 5173, open = false }) {
399
+ export async function startSemanticPreview({ client, projectFile, workspaceId, workspaceName, semanticModelId, host = "127.0.0.1", port = 5173, open = false, onProgress = null }) {
400
400
  if (!["127.0.0.1", "localhost", "::1"].includes(host)) throw new Error("Semantic preview may bind only to a loopback host");
401
+ onProgress?.({ status: "running", step: "project", message: "Loading and validating the Super Visual project" });
401
402
  const loaded = await loadProject(projectFile);
402
403
  const diagnostics = validateCompilation(loaded);
403
404
  if (diagnostics.length) throw new Error(`Preview validation failed:\n- ${diagnostics.join("\n- ")}`);
404
- const inspected = await inspectSemanticModel({ client, workspaceId, workspaceName, semanticModelId });
405
+ onProgress?.({ status: "passed", step: "project", message: "Validated the project contracts and semantic bindings" });
406
+ const inspected = await inspectSemanticModel({ client, workspaceId, workspaceName, semanticModelId, onProgress });
405
407
  const catalogMode = usesSemanticCatalog(loaded.broker);
406
408
  const brokerDiagnostics = previewBrokerSurfaceDiagnostics(inspected.semanticModel);
407
409
  const previewMode = catalogMode ? "catalog" : brokerDiagnostics.length ? "direct" : "managed";
410
+ onProgress?.({ status: "running", step: "compatibility", message: "Checking application queries against the selected semantic model" });
408
411
  const compatibility = catalogMode
409
412
  ? { ok: true, summary: { required: 1, matched: 1, missing: 0, ambiguous: 0 }, checks: [], diagnostics: [] }
410
413
  : checkSemanticCompatibility(inspected.semanticModel, loaded.semanticModel, loaded.broker);
@@ -412,19 +415,26 @@ export async function startSemanticPreview({ client, projectFile, workspaceId, w
412
415
  const messages = compatibility.diagnostics.map((item) => item.message);
413
416
  throw new Error(`Semantic preview compatibility failed:\n- ${messages.join("\n- ")}`);
414
417
  }
418
+ onProgress?.({ status: "passed", step: "compatibility", message: `Confirmed ${compatibility.summary.matched || compatibility.summary.required} semantic binding${compatibility.summary.required === 1 ? "" : "s"}` });
415
419
  loaded.previewMode = previewMode;
416
420
  if (catalogMode) loaded.catalogRows = semanticCatalogRows(inspected.semanticModel);
417
421
 
418
422
  const previewRoot = path.join(loaded.root, ".supervisual", "semantic-preview");
419
423
  const solutionRoot = path.join(previewRoot, "solution");
420
424
  const hostRoot = path.join(previewRoot, "host");
425
+ onProgress?.({ status: "running", step: "build", message: "Building the local preview runtime" });
421
426
  await buildSolution(projectFile, { outputDirectory: solutionRoot });
427
+ onProgress?.({ status: "passed", step: "build", message: "Built the local preview runtime" });
428
+ onProgress?.({ status: "running", step: "host", message: "Preparing the secure loopback preview host" });
422
429
  const token = randomBytes(24).toString("base64url");
423
430
  await writePreviewHost(hostRoot, token);
431
+ const aliases = dependencyAliases();
432
+ onProgress?.({ status: "passed", step: "host", message: "Prepared the secure loopback preview host" });
433
+ onProgress?.({ status: "running", step: "server", message: `Starting the preview server on ${host}:${port}` });
424
434
  const server = await createServer({
425
435
  root: hostRoot,
426
436
  logLevel: "silent",
427
- resolve: { alias: dependencyAliases(), dedupe: ["react", "react-dom"] },
437
+ resolve: { alias: aliases, dedupe: ["react", "react-dom"] },
428
438
  server: {
429
439
  host,
430
440
  port: Number(port),
@@ -441,11 +451,13 @@ export async function startSemanticPreview({ client, projectFile, workspaceId, w
441
451
  const address = server.httpServer?.address();
442
452
  const actualPort = typeof address === "object" && address ? address.port : Number(port);
443
453
  const urlHost = host === "::1" ? "[::1]" : host;
454
+ const url = `http://${urlHost}:${actualPort}/`;
455
+ onProgress?.({ status: "passed", step: "server", message: `Preview server is ready at ${url}` });
444
456
  return {
445
457
  ok: true,
446
458
  status: "ready",
447
459
  mode: "live-semantic-model",
448
- url: `http://${urlHost}:${actualPort}/`,
460
+ url,
449
461
  workspace: inspected.workspace,
450
462
  semanticModel: { id: inspected.semanticModel.id, displayName: inspected.semanticModel.displayName },
451
463
  compatibility: compatibility.summary,
@@ -10,6 +10,6 @@
10
10
  "verify": "supervisual verify ."
11
11
  },
12
12
  "devDependencies": {
13
- "@datashow/super-visual-cli": "0.1.0-rc.4"
13
+ "@datashow/super-visual-cli": "0.1.0-rc.5"
14
14
  }
15
15
  }
@@ -10,6 +10,6 @@
10
10
  "verify": "supervisual verify ."
11
11
  },
12
12
  "devDependencies": {
13
- "@datashow/super-visual-cli": "0.1.0-rc.4"
13
+ "@datashow/super-visual-cli": "0.1.0-rc.5"
14
14
  }
15
15
  }