@unoverse-platform/studio 0.1.104 → 0.1.106
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 +30 -10
- package/bin/studio.mjs +21 -13
- package/local/authoring.ts +2 -2
- package/local/catalog.ts +10 -2
- package/local/design-home.d.mts +7 -0
- package/local/design-home.mjs +24 -1
- package/local/plugin.ts +34 -23
- package/local/sample-app/chat/components/chat-region.yaml +2 -3
- package/local/sample-app/chat/manifest.yaml +2 -2
- package/local/sample-component/text-chat/components/suggestions.yaml +1 -1
- package/local/sample-component/text-chat/layouts/chat-welcome.yaml +1 -1
- package/local/sample-component/text-chat/text-chat.yaml +3 -0
- package/local/scaffold.d.mts +11 -2
- package/local/scaffold.mjs +136 -7
- package/local/source.ts +2 -2
- package/package.json +1 -1
- package/screens/EmptyLibrary.tsx +2 -2
- package/screens/IdentityView.tsx +1 -1
- package/screens/TemplatesView.tsx +1 -1
- package/src/App.tsx +10 -5
- package/vendor/base/src/definitions/registry/homes.ts +7 -1
- package/vendor/base/src/definitions/registry/orgDocuments.ts +5 -2
- package/vendor/base/src/items/collect.ts +85 -4
- package/vendor/base/src/items/publish.ts +23 -2
- package/vendor/base/src/lint/design/index.d.mts +8 -1
- package/vendor/base/src/lint/design/index.mjs +39 -7
- package/vendor/base/src/lint/objects/index.d.mts +2 -0
- package/vendor/base/src/lint/objects/index.mjs +12 -6
- package/vendor/base/src/lint/prompts/index.d.mts +2 -0
- package/vendor/base/src/lint/prompts/index.mjs +8 -3
- package/vendor/base/src/paths.ts +5 -0
|
@@ -75,7 +75,17 @@ export function lintDefinitions(designRoot, options = {}) {
|
|
|
75
75
|
});
|
|
76
76
|
};
|
|
77
77
|
|
|
78
|
-
|
|
78
|
+
/**
|
|
79
|
+
* AN ORG'S OWN REPO (RELEASE_LIFECYCLE.md §3, UNO-88). The repo IS the org: its folders sit
|
|
80
|
+
* at the root and its name is declared (`unoverse.yaml` org:), never read off a folder.
|
|
81
|
+
* The caller says so with `options.org = { name, dir }`, and then nothing here guesses:
|
|
82
|
+
* the org list is that one folder, and its name is the one given. Without it a flat repo
|
|
83
|
+
* would read as the legacy design-system layout (components/ at the root) and lint as
|
|
84
|
+
* nothing at all.
|
|
85
|
+
*/
|
|
86
|
+
const ORG_REPO = options.org?.dir ? resolve(options.org.dir) : null;
|
|
87
|
+
const ORG_NAME = options.org?.name ?? null;
|
|
88
|
+
const DESIGN_ROOT = ORG_REPO ? dirname(ORG_REPO) : candidates.find((p) => holdsDesignSystem(p) || holdsOrgs(p));
|
|
79
89
|
if (!DESIGN_ROOT)
|
|
80
90
|
return {
|
|
81
91
|
problems: [{ level: "error", file: candidates[0], msg: `no design/ folder here (looked in: ${candidates.join(", ")})` }],
|
|
@@ -94,6 +104,12 @@ export function lintDefinitions(designRoot, options = {}) {
|
|
|
94
104
|
// styles/base/spacing, so a fallback finding only components would build a PARTIAL scale
|
|
95
105
|
// and reject valid steps, reporting false errors on correct work. Mirrors definitions.ts.
|
|
96
106
|
const DS = (() => {
|
|
107
|
+
// In an org repo the design system is only ever the installed bundle inside that repo:
|
|
108
|
+
// never a sibling folder, which would be another org's repo.
|
|
109
|
+
if (ORG_REPO) {
|
|
110
|
+
const bundled = join(ORG_REPO, "plugins", "node_modules", "@unoverse-platform", "marketplace", "definitions");
|
|
111
|
+
return existsSync(bundled) ? bundled : join(ORG_REPO, ".unoverse", "no-design-system");
|
|
112
|
+
}
|
|
97
113
|
const onDisk = join(DESIGN_ROOT, "marketplace");
|
|
98
114
|
if (existsSync(onDisk)) return onDisk;
|
|
99
115
|
for (const c of [
|
|
@@ -102,8 +118,15 @@ export function lintDefinitions(designRoot, options = {}) {
|
|
|
102
118
|
if (existsSync(c)) return c;
|
|
103
119
|
return DESIGN_ROOT; // none anywhere: shared refs will not resolve, and the findings will say so
|
|
104
120
|
})();
|
|
121
|
+
/** Is a design system on disk at all? When not, checks that need it are skipped, not failed. */
|
|
122
|
+
const HAS_DS = DS !== DESIGN_ROOT && existsSync(DS);
|
|
123
|
+
/** The org a home folder belongs to: the declared name in an org repo, else the folder's name. */
|
|
124
|
+
const orgName = (dir) => (ORG_REPO && dir === ORG_REPO ? ORG_NAME : basename(dir));
|
|
125
|
+
/** Every home that can hold node packages, credentials or places: the design system and the orgs. */
|
|
126
|
+
const tierHomes = () => (ORG_REPO ? [DS, ...orgDirs] : readdirSync(DESIGN_ROOT).map((t) => join(DESIGN_ROOT, t)));
|
|
105
127
|
const legacyOrgsDir = join(DESIGN_ROOT, "orgs");
|
|
106
128
|
const orgDirs = (() => {
|
|
129
|
+
if (ORG_REPO) return [ORG_REPO];
|
|
107
130
|
if (existsSync(legacyOrgsDir))
|
|
108
131
|
return readdirSync(legacyOrgsDir)
|
|
109
132
|
.filter((e) => !e.startsWith("."))
|
|
@@ -448,7 +471,7 @@ for (const orgDir of orgDirs) {
|
|
|
448
471
|
const name = statSync(join(home, e)).isDirectory() ? e : isDefFile(e) ? defName(e) : null;
|
|
449
472
|
if (name) set.add(name.toLowerCase());
|
|
450
473
|
}
|
|
451
|
-
orgComponentNames.set(
|
|
474
|
+
orgComponentNames.set(orgName(orgDir), set);
|
|
452
475
|
}
|
|
453
476
|
// TEMPLATE-LOCAL PARTS are addressed `<template>/<part>` (§9b rule 7) — the same
|
|
454
477
|
// qualified shape as `<org>/<name>`, resolved against the template homes. The runtime
|
|
@@ -461,7 +484,7 @@ const orgTemplateNames = new Map(); // org (or DS basename) -> Set(lower block n
|
|
|
461
484
|
for (const root of [DS, ...orgDirs]) {
|
|
462
485
|
const home = join(root, "templates");
|
|
463
486
|
if (!existsSync(home)) continue;
|
|
464
|
-
const blocks = orgTemplateNames.get(
|
|
487
|
+
const blocks = orgTemplateNames.get(orgName(root)) ?? new Set();
|
|
465
488
|
for (const t of readdirSync(home)) {
|
|
466
489
|
if (isDefFile(t)) {
|
|
467
490
|
blocks.add(defName(t).toLowerCase());
|
|
@@ -479,11 +502,11 @@ for (const root of [DS, ...orgDirs]) {
|
|
|
479
502
|
}
|
|
480
503
|
templatePartNames.set(t.toLowerCase(), set);
|
|
481
504
|
}
|
|
482
|
-
orgTemplateNames.set(
|
|
505
|
+
orgTemplateNames.set(orgName(root), blocks);
|
|
483
506
|
}
|
|
484
507
|
const orgOfFile = (file) => {
|
|
485
508
|
const home = orgDirs.find((d) => file.startsWith(d + sep));
|
|
486
|
-
return home ?
|
|
509
|
+
return home ? orgName(home) : null;
|
|
487
510
|
};
|
|
488
511
|
// A valid Ref target if there's ANY resolvable home the FILE may reach: atoms, DS
|
|
489
512
|
// components, or (from inside an org tree) that org's own components — bare or
|
|
@@ -747,7 +770,7 @@ const credentialDefs = new Set();
|
|
|
747
770
|
// Every tier's node packages: the marketplace's and each org's, all at <tier>/nodes/.
|
|
748
771
|
const nodesHomes = [];
|
|
749
772
|
try {
|
|
750
|
-
for (const
|
|
773
|
+
for (const home of tierHomes()) nodesHomes.push(join(home, "nodes"));
|
|
751
774
|
} catch {
|
|
752
775
|
/* no design root: nothing declares a credential */
|
|
753
776
|
}
|
|
@@ -924,6 +947,15 @@ function componentNamesForFile(file) {
|
|
|
924
947
|
const org = projectSegs.join("/");
|
|
925
948
|
const cached = componentNamesCache.get(org);
|
|
926
949
|
if (cached !== undefined) return cached;
|
|
950
|
+
// A PARTIAL SET IS WORSE THAN NO SET (the app-sizes trap below, same cause). A developer's
|
|
951
|
+
// project has no design system on disk, so DS falls back to DESIGN_ROOT and only the org's
|
|
952
|
+
// own names would be left: every marketplace name a preview uses (`card`) then reads as
|
|
953
|
+
// unknown, and a fresh Studio workspace failed lint on its own sample. Unverifiable here,
|
|
954
|
+
// so not asserted.
|
|
955
|
+
if (!HAS_DS) {
|
|
956
|
+
componentNamesCache.set(org, null);
|
|
957
|
+
return null;
|
|
958
|
+
}
|
|
927
959
|
const dirs = [
|
|
928
960
|
join(DS, "components"),
|
|
929
961
|
join(DESIGN_ROOT, ...projectSegs, "components"),
|
|
@@ -955,7 +987,7 @@ function placeNames() {
|
|
|
955
987
|
if (n.type === "Place" && typeof n.name === "string") names.add(n.name);
|
|
956
988
|
for (const v of Object.values(n)) walk(v);
|
|
957
989
|
};
|
|
958
|
-
const roots = [DS, ...
|
|
990
|
+
const roots = [DS, ...tierHomes().filter((d) => !basename(d).startsWith("."))];
|
|
959
991
|
for (const root of new Set(roots))
|
|
960
992
|
for (const f of jsonFiles(join(root, "apps"))) {
|
|
961
993
|
try {
|
|
@@ -23,6 +23,8 @@ export interface ObjectsResult {
|
|
|
23
23
|
export interface LintObjectsOptions {
|
|
24
24
|
/** Absolute path -> text that stands in for what is on disk (Studio's unsaved editor). */
|
|
25
25
|
overlay?: Record<string, string>;
|
|
26
|
+
/** An org's own repo (UNO-88): its folder and its DECLARED name. The org list is then this one. */
|
|
27
|
+
org?: { name: string; dir: string };
|
|
26
28
|
}
|
|
27
29
|
|
|
28
30
|
/** Lint every object and pipeline folder under `designRoot`, every tier. Prints nothing, throws nothing for a lint failure. */
|
|
@@ -117,13 +117,19 @@ export function lintObjects(designRoot, options = {}) {
|
|
|
117
117
|
loadAllSchemas();
|
|
118
118
|
|
|
119
119
|
// ── the tiers: the marketplace, then every org folder ──
|
|
120
|
+
// An org's own repo is ONE tier with a DECLARED name (`options.org`, UNO-88): its folder may
|
|
121
|
+
// be called anything, and the org name is also the dataset table's (`dataset_<org>_<name>`).
|
|
120
122
|
const marketplace = join(ROOT, "marketplace");
|
|
121
123
|
const tiers = [];
|
|
122
|
-
if (
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
124
|
+
if (options.org?.dir) {
|
|
125
|
+
tiers.push({ org: options.org.name, dir: resolve(options.org.dir) });
|
|
126
|
+
} else {
|
|
127
|
+
if (isDir(marketplace)) tiers.push({ org: undefined, dir: marketplace });
|
|
128
|
+
for (const e of readdirSync(ROOT)) {
|
|
129
|
+
if (e.startsWith(".") || e === "marketplace" || e === "_schema") continue;
|
|
130
|
+
const d = join(ROOT, e);
|
|
131
|
+
if (isDir(d)) tiers.push({ org: e, dir: d });
|
|
132
|
+
}
|
|
127
133
|
}
|
|
128
134
|
|
|
129
135
|
/**
|
|
@@ -233,7 +239,7 @@ export function lintObjects(designRoot, options = {}) {
|
|
|
233
239
|
let objectCount = 0;
|
|
234
240
|
for (const [, f] of objectIndex) {
|
|
235
241
|
objectCount++;
|
|
236
|
-
const tier = { org: f.org, dir:
|
|
242
|
+
const tier = { org: f.org, dir: tiers.find((t) => t.org === f.org)?.dir ?? marketplace };
|
|
237
243
|
const at = (file) => rel(join(f.dir, file));
|
|
238
244
|
if (f.envelope === null) continue;
|
|
239
245
|
validateAgainst(SCHEMA_ID.object, f.envelope, rel(f.envFile), `object ${f.name}: the envelope`);
|
|
@@ -22,6 +22,8 @@ export interface PromptsResult {
|
|
|
22
22
|
export interface LintPromptsOptions {
|
|
23
23
|
/** Absolute path -> text that stands in for what is on disk (an unsaved editor). */
|
|
24
24
|
overlay?: Record<string, string>;
|
|
25
|
+
/** An org's own repo (UNO-88): its folder and its DECLARED name. The org list is then this one. */
|
|
26
|
+
org?: { name: string; dir: string };
|
|
25
27
|
}
|
|
26
28
|
|
|
27
29
|
/** Lint every skill and prompt block under `designRoot`, every tier. Prints nothing, throws nothing for a lint failure. */
|
|
@@ -143,10 +143,15 @@ export function lintPrompts(designRoot, options = {}) {
|
|
|
143
143
|
// ── the tiers: the marketplace, every flat org folder, and the legacy orgs/ container ──
|
|
144
144
|
const tiers = [];
|
|
145
145
|
const marketplace = join(ROOT, "marketplace");
|
|
146
|
-
if (isDir(marketplace)) tiers.push({ org: undefined, dir: marketplace });
|
|
147
146
|
const orgDirs = (base) => readdirSync(base).filter((e) => !e.startsWith(".") && !e.startsWith("_") && e !== "marketplace" && e !== "orgs" && isDir(join(base, e)));
|
|
148
|
-
|
|
149
|
-
|
|
147
|
+
if (options.org?.dir) {
|
|
148
|
+
// An org's own repo: one tier, its name declared, never read off the folder (UNO-88).
|
|
149
|
+
tiers.push({ org: options.org.name, dir: resolve(options.org.dir) });
|
|
150
|
+
} else {
|
|
151
|
+
if (isDir(marketplace)) tiers.push({ org: undefined, dir: marketplace });
|
|
152
|
+
for (const e of orgDirs(ROOT)) tiers.push({ org: e, dir: join(ROOT, e) });
|
|
153
|
+
if (isDir(join(ROOT, "orgs"))) for (const e of orgDirs(join(ROOT, "orgs"))) tiers.push({ org: e, dir: join(ROOT, "orgs", e) });
|
|
154
|
+
}
|
|
150
155
|
|
|
151
156
|
let skillCount = 0;
|
|
152
157
|
let blockCount = 0;
|
package/vendor/base/src/paths.ts
CHANGED
|
@@ -65,6 +65,11 @@ export interface Paths {
|
|
|
65
65
|
packages: string;
|
|
66
66
|
/** LEGACY: the pre-migration marketplace folder. Usually absent. */
|
|
67
67
|
marketplace: string;
|
|
68
|
+
/**
|
|
69
|
+
* AN ORG'S OWN REPO (UNO-88). When set, the home IS this one org: its folders at the root,
|
|
70
|
+
* its name declared in unoverse.yaml. projectDir(org) is `dir` and listOrgs() is `[org]`.
|
|
71
|
+
*/
|
|
72
|
+
orgRepo?: { org: string; dir: string };
|
|
68
73
|
}
|
|
69
74
|
|
|
70
75
|
/**
|