@datarails-ai/dr-appspace-cli 0.10.4 → 0.10.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.
Files changed (3) hide show
  1. package/README.md +2 -0
  2. package/dist/cli.js +72 -6
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -85,6 +85,8 @@ A dashboard can be **assembled** rather than typed. `compile --draft
85
85
  (`--skeleton <file>`, or the draft's own `skeleton` key) and one SPEC draft
86
86
  per page — each card's `props` and SPEC `row`, plus its `page`, `reads`,
87
87
  `datasets` and `capabilities` — and then compiles it like any other. The
88
+ app's `name` and `description` (the line under the name on its card, which
89
+ kit rule R1.5 requires) are the skeleton's `app`, as written. The rest of the
88
90
  frame is the CLI's: the first page is `ui/index.html` at `/`, every other
89
91
  `ui/<name>.html` at `/<name>.html`, the skeleton's sections and card order,
90
92
  a page not built yet carries one card saying it comes next, and — only
package/dist/cli.js CHANGED
@@ -13,7 +13,7 @@ import { fileURLToPath as fileURLToPath6 } from "url";
13
13
  // package.json
14
14
  var package_default = {
15
15
  name: "@datarails-ai/dr-appspace-cli",
16
- version: "0.10.4",
16
+ version: "0.10.6",
17
17
  description: "Datarails App Space CLI \u2014 build, try, push and publish App Space apps",
18
18
  type: "module",
19
19
  engines: {
@@ -57,7 +57,7 @@ var package_default = {
57
57
  };
58
58
 
59
59
  // src/buildInfo.ts
60
- var BUILD_TIME = "2026-09-30T14:25:42.306Z";
60
+ var BUILD_TIME = "2026-09-30T16:43:46.444Z";
61
61
  function formatBuildTime(iso) {
62
62
  if (iso === "") return "";
63
63
  const d = new Date(iso);
@@ -3531,9 +3531,10 @@ function canonical(value) {
3531
3531
  return JSON.stringify(value) ?? "null";
3532
3532
  }
3533
3533
  function frame(skeleton, pages, appId) {
3534
+ const described = skeleton.app.description === void 0 ? {} : { description: skeleton.app.description };
3534
3535
  return {
3535
3536
  v: 1,
3536
- app: { id: appId, name: skeleton.app.name, kind: "dashboard", routes: pages.map((plan) => plan.address) },
3537
+ app: { id: appId, name: skeleton.app.name, ...described, kind: "dashboard", routes: pages.map((plan) => plan.address) },
3537
3538
  pages: pages.map(pageFrom),
3538
3539
  elements: {},
3539
3540
  data: { source: "static", widgets: {} }
@@ -4936,6 +4937,9 @@ function appSection(app, manifest) {
4936
4937
  return {
4937
4938
  id: manifest.id ?? null,
4938
4939
  name: manifest.name ?? null,
4940
+ // What the app does, in the line under its name on the card Studio lists
4941
+ // it on. Read as written: the verifier, not the reader, judges the words.
4942
+ description: typeof manifest.description === "string" ? manifest.description : null,
4939
4943
  kind: manifest.kind ?? null,
4940
4944
  // What the app is called in the nav, which is not always what it is
4941
4945
  // called: `name` is the title of the page and `nav.label` is the word
@@ -6186,9 +6190,13 @@ var EXPECT_EMPTY = "empty";
6186
6190
  var EXPECTATIONS = /* @__PURE__ */ new Set([EXPECT_FIGURE, EXPECT_EMPTY]);
6187
6191
  var FIGURE = {
6188
6192
  series: (body) => Array.isArray(body.series) && body.series.some((entry) => Array.isArray(entry?.values) && entry.values.some(isNumber)),
6189
- breakdown: (body) => Array.isArray(body.items) && body.items.length > 0,
6193
+ // A container of labels with nothing beside them draws no figure either:
6194
+ // seven departments down a variance table with every cell null is the same
6195
+ // blank card as no rows at all (dev-1, 2026-09-30, `actual - budget` where
6196
+ // neither was a measure of the dataset), and it passed here as "rows > 0".
6197
+ breakdown: (body) => Array.isArray(body.items) && body.items.some((item) => isNumber(item?.value)),
6190
6198
  kpi: (body) => isNumber(body.value),
6191
- table: (body) => Array.isArray(body.rows) && body.rows.length > 0,
6199
+ table: (body) => Array.isArray(body.rows) && body.rows.some((row) => isPlainObject2(row) && Object.values(row).some(isNumber)),
6192
6200
  ohlc: (body) => Array.isArray(body.candles) && body.candles.length > 0,
6193
6201
  scatter: (body) => Array.isArray(body.points) && body.points.length > 0,
6194
6202
  // A narrative in AGENT mode has no prose to carry: the words arrive from the
@@ -7853,6 +7861,7 @@ var contract_schema_default = {
7853
7861
  properties: {
7854
7862
  id: { type: ["string", "null"] },
7855
7863
  name: { type: ["string", "null"] },
7864
+ description: { type: ["string", "null"], description: "manifest.description - what the app does, in one sentence: the line under its name on the card Studio lists it on. OPTIONAL: a contract written before this key existed omits it." },
7856
7865
  kind: { type: ["string", "null"], description: "dashboard, app, or absent" },
7857
7866
  nav_label: { type: ["string", "null"], description: "manifest.nav.label - what the app is called in the nav, which is not always manifest.name. OPTIONAL: a contract written before this key existed omits it." },
7858
7867
  version: { type: ["string", "null"] },
@@ -11663,6 +11672,8 @@ function manifestFile(contract, handlerName) {
11663
11672
  apiVersion: app.api_version ?? "appspace/v1",
11664
11673
  id: app.id ?? null,
11665
11674
  name: app.name ?? null,
11675
+ // The line under the name on the dashboard's card, as `compileApp` writes an app's.
11676
+ ...typeof app.description === "string" ? { description: app.description } : {},
11666
11677
  version: app.version ?? "0.1.0",
11667
11678
  kind: "dashboard",
11668
11679
  ...app.nav_label ? { nav: { label: app.nav_label } } : {},
@@ -15734,6 +15745,10 @@ function manifestOf(contract, app, handlers, names, model, served = []) {
15734
15745
  apiVersion: app.api_version ?? DEFAULT_API_VERSION,
15735
15746
  id: app.id ?? null,
15736
15747
  name: app.name ?? app.id ?? null,
15748
+ // The line under the name on the app's card. Any string is written, an
15749
+ // empty one too, so the verifier says "blank" and the round trip holds;
15750
+ // a contract that states none writes the manifest it always did.
15751
+ ...typeof app.description === "string" ? { description: app.description } : {},
15737
15752
  version: app.version ?? DEFAULT_VERSION
15738
15753
  };
15739
15754
  if (named4(app.nav_label)) manifest.nav = { label: app.nav_label };
@@ -17405,6 +17420,27 @@ function isReferenced2(name, frontendText) {
17405
17420
  return new RegExp(`(['"\`])${escaped}\\1|/${escaped}\\b`).test(frontendText);
17406
17421
  }
17407
17422
 
17423
+ // ../flows/insights-builder/kit/checks/lib/description.mjs
17424
+ var DESCRIPTION_MAX = 120;
17425
+ var SAYS_NOTHING = "so the app's card in Studio says nothing under its name";
17426
+ var WRITE = `Write app.description in the contract: one sentence on what the app does, for the card; no newline, and at most ${DESCRIPTION_MAX} characters`;
17427
+ var LINE_BREAK = /[\n\r\u2028\u2029]/;
17428
+ function descriptionProblems(description) {
17429
+ if (description === void 0 || description === null) return [`manifest.description is missing, ${SAYS_NOTHING}. ${WRITE}`];
17430
+ if (typeof description !== "string") return [`manifest.description is ${JSON.stringify(description)}, not text, ${SAYS_NOTHING}. ${WRITE}`];
17431
+ const shown2 = description.trim().split(/\s+/).join(" ");
17432
+ if (shown2 === "") return [`manifest.description is blank, ${SAYS_NOTHING}. ${WRITE}`];
17433
+ const problems = [];
17434
+ if (LINE_BREAK.test(description)) {
17435
+ problems.push(`manifest.description breaks onto a second line, and the card in Studio shows one paragraph. ${WRITE}`);
17436
+ }
17437
+ const characters = [...shown2].length;
17438
+ if (characters > DESCRIPTION_MAX) {
17439
+ problems.push(`manifest.description is ${characters} characters, and the card in Studio has room for ${DESCRIPTION_MAX} (three lines). ${WRITE}`);
17440
+ }
17441
+ return problems;
17442
+ }
17443
+
17408
17444
  // ../flows/insights-builder/kit/checks/rules/manifest.mjs
17409
17445
  var DASHBOARD_CAPABILITIES = /* @__PURE__ */ new Set(["financeos", "state"]);
17410
17446
  var FINANCEOS_READ_SCOPE = /^(metrics|semantic|tables|status|filebox|raw):read$/;
@@ -17418,6 +17454,7 @@ function checkManifest(app) {
17418
17454
  if (dataModel !== null || manifest.dataModel !== void 0 || manifest.data_model !== void 0) {
17419
17455
  violations.push({ rule: "R1.1", where: where2, message: "a dashboard declares no data_model: every number is read live from FinanceOS" });
17420
17456
  }
17457
+ for (const message of descriptionProblems(manifest.description)) violations.push({ rule: "R1.5", where: where2, message });
17421
17458
  const capabilities = manifest.capabilities ?? {};
17422
17459
  if (typeof capabilities !== "object" || Array.isArray(capabilities)) {
17423
17460
  violations.push({ rule: "R1.1", where: where2, message: "capabilities must be an object" });
@@ -18883,6 +18920,9 @@ function appSection2(app, manifest) {
18883
18920
  return {
18884
18921
  id: manifest.id ?? null,
18885
18922
  name: manifest.name ?? null,
18923
+ // What the app does, in the line under its name on the card Studio lists
18924
+ // it on. Read as written: the verifier, not the reader, judges the words.
18925
+ description: typeof manifest.description === "string" ? manifest.description : null,
18886
18926
  kind: manifest.kind ?? null,
18887
18927
  // What the app is called in the nav, which is not always what it is
18888
18928
  // called: `name` is the title of the page and `nav.label` is the word
@@ -21595,6 +21635,27 @@ function checkLook(app, contract, contractError) {
21595
21635
  return { violations, skipped: [] };
21596
21636
  }
21597
21637
 
21638
+ // ../flows/appspace-builder/kit/checks/lib/description.mjs
21639
+ var DESCRIPTION_MAX2 = 120;
21640
+ var SAYS_NOTHING2 = "so the app's card in Studio says nothing under its name";
21641
+ var WRITE2 = `Write app.description in the contract: one sentence on what the app does, for the card; no newline, and at most ${DESCRIPTION_MAX2} characters`;
21642
+ var LINE_BREAK2 = /[\n\r\u2028\u2029]/;
21643
+ function descriptionProblems2(description) {
21644
+ if (description === void 0 || description === null) return [`manifest.description is missing, ${SAYS_NOTHING2}. ${WRITE2}`];
21645
+ if (typeof description !== "string") return [`manifest.description is ${JSON.stringify(description)}, not text, ${SAYS_NOTHING2}. ${WRITE2}`];
21646
+ const shown2 = description.trim().split(/\s+/).join(" ");
21647
+ if (shown2 === "") return [`manifest.description is blank, ${SAYS_NOTHING2}. ${WRITE2}`];
21648
+ const problems = [];
21649
+ if (LINE_BREAK2.test(description)) {
21650
+ problems.push(`manifest.description breaks onto a second line, and the card in Studio shows one paragraph. ${WRITE2}`);
21651
+ }
21652
+ const characters = [...shown2].length;
21653
+ if (characters > DESCRIPTION_MAX2) {
21654
+ problems.push(`manifest.description is ${characters} characters, and the card in Studio has room for ${DESCRIPTION_MAX2} (three lines). ${WRITE2}`);
21655
+ }
21656
+ return problems;
21657
+ }
21658
+
21598
21659
  // ../flows/appspace-builder/kit/checks/rules/manifest.mjs
21599
21660
  function checkManifest2(app) {
21600
21661
  const violations = [];
@@ -21603,6 +21664,7 @@ function checkManifest2(app) {
21603
21664
  if (typeof manifest.name !== "string" || !manifest.name.trim()) {
21604
21665
  violations.push({ rule: "A1.1", where: where2, message: "manifest.name is empty; the app is listed under its id" });
21605
21666
  }
21667
+ for (const message of descriptionProblems2(manifest.description)) violations.push({ rule: "A1.7", where: where2, message });
21606
21668
  if (manifest.kind === "dashboard") {
21607
21669
  violations.push({ rule: "A1.2", where: where2, message: 'manifest.kind is "dashboard"; dashboards are built by the Insights Builder and its kit, not here' });
21608
21670
  }
@@ -22537,7 +22599,7 @@ var kit_default = {
22537
22599
  // ../flows/appspace-builder/kit/kit.json
22538
22600
  var kit_default2 = {
22539
22601
  name: "appspace-app-kit",
22540
- description: "The checks the App Builder runs on every pushed version of a regular App Space app: a manifest that names the app, handlers that exist and take (ctx, payload), a page that calls only handlers that exist, no handler nothing reaches, roles declared wherever a handler reads ctx.role, and the component vocabulary held to the data model \u2014 every data-dr-action a declared handler, every data-dr-entity a table, every data-dr-field one of its columns.",
22602
+ description: "The checks the App Builder runs on every pushed version of a regular App Space app: a manifest that names the app and says in a line what it does, handlers that exist and take (ctx, payload), a page that calls only handlers that exist, no handler nothing reaches, roles declared wherever a handler reads ctx.role, and the component vocabulary held to the data model \u2014 every data-dr-action a declared handler, every data-dr-entity a table, every data-dr-field one of its columns.",
22541
22603
  checks: "checks/run.mjs",
22542
22604
  contract: "contract/extract.mjs",
22543
22605
  charts: "echarts@5.6.0",
@@ -29511,6 +29573,8 @@ function dashboardStarter(values) {
29511
29573
  app: {
29512
29574
  id: values.id,
29513
29575
  name: values.name,
29576
+ // What the card Studio lists the dashboard on says under its name.
29577
+ description: "What this dashboard answers, in one sentence its reader would use.",
29514
29578
  kind: "dashboard",
29515
29579
  nav_label: values.name,
29516
29580
  routes: ["/"],
@@ -29597,6 +29661,8 @@ function appStarter(values) {
29597
29661
  app: {
29598
29662
  id: values.id,
29599
29663
  name: values.name,
29664
+ // What the card Studio lists the app on says under its name.
29665
+ description: `Raise a ${record2} and follow it until it is done.`,
29600
29666
  nav_label: values.name,
29601
29667
  routes: ["/"],
29602
29668
  capabilities: { data: ["rw"] },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@datarails-ai/dr-appspace-cli",
3
- "version": "0.10.4",
3
+ "version": "0.10.6",
4
4
  "description": "Datarails App Space CLI — build, try, push and publish App Space apps",
5
5
  "type": "module",
6
6
  "engines": {