@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.
- package/README.md +2 -0
- package/dist/cli.js +66 -4
- 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.
|
|
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:
|
|
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"] },
|