@datarails-ai/dr-appspace-cli 0.10.4 → 0.10.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.
Files changed (3) hide show
  1. package/README.md +2 -0
  2. package/dist/cli.js +66 -4
  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.5",
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-30T14:45:52.678Z";
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
@@ -7853,6 +7857,7 @@ var contract_schema_default = {
7853
7857
  properties: {
7854
7858
  id: { type: ["string", "null"] },
7855
7859
  name: { type: ["string", "null"] },
7860
+ 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
7861
  kind: { type: ["string", "null"], description: "dashboard, app, or absent" },
7857
7862
  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
7863
  version: { type: ["string", "null"] },
@@ -11663,6 +11668,8 @@ function manifestFile(contract, handlerName) {
11663
11668
  apiVersion: app.api_version ?? "appspace/v1",
11664
11669
  id: app.id ?? null,
11665
11670
  name: app.name ?? null,
11671
+ // The line under the name on the dashboard's card, as `compileApp` writes an app's.
11672
+ ...typeof app.description === "string" ? { description: app.description } : {},
11666
11673
  version: app.version ?? "0.1.0",
11667
11674
  kind: "dashboard",
11668
11675
  ...app.nav_label ? { nav: { label: app.nav_label } } : {},
@@ -15734,6 +15741,10 @@ function manifestOf(contract, app, handlers, names, model, served = []) {
15734
15741
  apiVersion: app.api_version ?? DEFAULT_API_VERSION,
15735
15742
  id: app.id ?? null,
15736
15743
  name: app.name ?? app.id ?? null,
15744
+ // The line under the name on the app's card. Any string is written, an
15745
+ // empty one too, so the verifier says "blank" and the round trip holds;
15746
+ // a contract that states none writes the manifest it always did.
15747
+ ...typeof app.description === "string" ? { description: app.description } : {},
15737
15748
  version: app.version ?? DEFAULT_VERSION
15738
15749
  };
15739
15750
  if (named4(app.nav_label)) manifest.nav = { label: app.nav_label };
@@ -17405,6 +17416,27 @@ function isReferenced2(name, frontendText) {
17405
17416
  return new RegExp(`(['"\`])${escaped}\\1|/${escaped}\\b`).test(frontendText);
17406
17417
  }
17407
17418
 
17419
+ // ../flows/insights-builder/kit/checks/lib/description.mjs
17420
+ var DESCRIPTION_MAX = 120;
17421
+ var SAYS_NOTHING = "so the app's card in Studio says nothing under its name";
17422
+ 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`;
17423
+ var LINE_BREAK = /[\n\r\u2028\u2029]/;
17424
+ function descriptionProblems(description) {
17425
+ if (description === void 0 || description === null) return [`manifest.description is missing, ${SAYS_NOTHING}. ${WRITE}`];
17426
+ if (typeof description !== "string") return [`manifest.description is ${JSON.stringify(description)}, not text, ${SAYS_NOTHING}. ${WRITE}`];
17427
+ const shown2 = description.trim().split(/\s+/).join(" ");
17428
+ if (shown2 === "") return [`manifest.description is blank, ${SAYS_NOTHING}. ${WRITE}`];
17429
+ const problems = [];
17430
+ if (LINE_BREAK.test(description)) {
17431
+ problems.push(`manifest.description breaks onto a second line, and the card in Studio shows one paragraph. ${WRITE}`);
17432
+ }
17433
+ const characters = [...shown2].length;
17434
+ if (characters > DESCRIPTION_MAX) {
17435
+ problems.push(`manifest.description is ${characters} characters, and the card in Studio has room for ${DESCRIPTION_MAX} (three lines). ${WRITE}`);
17436
+ }
17437
+ return problems;
17438
+ }
17439
+
17408
17440
  // ../flows/insights-builder/kit/checks/rules/manifest.mjs
17409
17441
  var DASHBOARD_CAPABILITIES = /* @__PURE__ */ new Set(["financeos", "state"]);
17410
17442
  var FINANCEOS_READ_SCOPE = /^(metrics|semantic|tables|status|filebox|raw):read$/;
@@ -17418,6 +17450,7 @@ function checkManifest(app) {
17418
17450
  if (dataModel !== null || manifest.dataModel !== void 0 || manifest.data_model !== void 0) {
17419
17451
  violations.push({ rule: "R1.1", where: where2, message: "a dashboard declares no data_model: every number is read live from FinanceOS" });
17420
17452
  }
17453
+ for (const message of descriptionProblems(manifest.description)) violations.push({ rule: "R1.5", where: where2, message });
17421
17454
  const capabilities = manifest.capabilities ?? {};
17422
17455
  if (typeof capabilities !== "object" || Array.isArray(capabilities)) {
17423
17456
  violations.push({ rule: "R1.1", where: where2, message: "capabilities must be an object" });
@@ -18883,6 +18916,9 @@ function appSection2(app, manifest) {
18883
18916
  return {
18884
18917
  id: manifest.id ?? null,
18885
18918
  name: manifest.name ?? null,
18919
+ // What the app does, in the line under its name on the card Studio lists
18920
+ // it on. Read as written: the verifier, not the reader, judges the words.
18921
+ description: typeof manifest.description === "string" ? manifest.description : null,
18886
18922
  kind: manifest.kind ?? null,
18887
18923
  // What the app is called in the nav, which is not always what it is
18888
18924
  // called: `name` is the title of the page and `nav.label` is the word
@@ -21595,6 +21631,27 @@ function checkLook(app, contract, contractError) {
21595
21631
  return { violations, skipped: [] };
21596
21632
  }
21597
21633
 
21634
+ // ../flows/appspace-builder/kit/checks/lib/description.mjs
21635
+ var DESCRIPTION_MAX2 = 120;
21636
+ var SAYS_NOTHING2 = "so the app's card in Studio says nothing under its name";
21637
+ 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`;
21638
+ var LINE_BREAK2 = /[\n\r\u2028\u2029]/;
21639
+ function descriptionProblems2(description) {
21640
+ if (description === void 0 || description === null) return [`manifest.description is missing, ${SAYS_NOTHING2}. ${WRITE2}`];
21641
+ if (typeof description !== "string") return [`manifest.description is ${JSON.stringify(description)}, not text, ${SAYS_NOTHING2}. ${WRITE2}`];
21642
+ const shown2 = description.trim().split(/\s+/).join(" ");
21643
+ if (shown2 === "") return [`manifest.description is blank, ${SAYS_NOTHING2}. ${WRITE2}`];
21644
+ const problems = [];
21645
+ if (LINE_BREAK2.test(description)) {
21646
+ problems.push(`manifest.description breaks onto a second line, and the card in Studio shows one paragraph. ${WRITE2}`);
21647
+ }
21648
+ const characters = [...shown2].length;
21649
+ if (characters > DESCRIPTION_MAX2) {
21650
+ problems.push(`manifest.description is ${characters} characters, and the card in Studio has room for ${DESCRIPTION_MAX2} (three lines). ${WRITE2}`);
21651
+ }
21652
+ return problems;
21653
+ }
21654
+
21598
21655
  // ../flows/appspace-builder/kit/checks/rules/manifest.mjs
21599
21656
  function checkManifest2(app) {
21600
21657
  const violations = [];
@@ -21603,6 +21660,7 @@ function checkManifest2(app) {
21603
21660
  if (typeof manifest.name !== "string" || !manifest.name.trim()) {
21604
21661
  violations.push({ rule: "A1.1", where: where2, message: "manifest.name is empty; the app is listed under its id" });
21605
21662
  }
21663
+ for (const message of descriptionProblems2(manifest.description)) violations.push({ rule: "A1.7", where: where2, message });
21606
21664
  if (manifest.kind === "dashboard") {
21607
21665
  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
21666
  }
@@ -22537,7 +22595,7 @@ var kit_default = {
22537
22595
  // ../flows/appspace-builder/kit/kit.json
22538
22596
  var kit_default2 = {
22539
22597
  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.",
22598
+ 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
22599
  checks: "checks/run.mjs",
22542
22600
  contract: "contract/extract.mjs",
22543
22601
  charts: "echarts@5.6.0",
@@ -29511,6 +29569,8 @@ function dashboardStarter(values) {
29511
29569
  app: {
29512
29570
  id: values.id,
29513
29571
  name: values.name,
29572
+ // What the card Studio lists the dashboard on says under its name.
29573
+ description: "What this dashboard answers, in one sentence its reader would use.",
29514
29574
  kind: "dashboard",
29515
29575
  nav_label: values.name,
29516
29576
  routes: ["/"],
@@ -29597,6 +29657,8 @@ function appStarter(values) {
29597
29657
  app: {
29598
29658
  id: values.id,
29599
29659
  name: values.name,
29660
+ // What the card Studio lists the app on says under its name.
29661
+ description: `Raise a ${record2} and follow it until it is done.`,
29600
29662
  nav_label: values.name,
29601
29663
  routes: ["/"],
29602
29664
  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.5",
4
4
  "description": "Datarails App Space CLI — build, try, push and publish App Space apps",
5
5
  "type": "module",
6
6
  "engines": {