@unoverse-platform/studio 0.1.104 → 0.1.105

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.
@@ -23,8 +23,8 @@ inputSchema:
23
23
  # components/chat-region. The component defaults to welcome on an empty conversation
24
24
  # and hands over to the timeline the moment messages exist.
25
25
  states:
26
- standard: {}
27
- focused: {}
26
+ standard: { layout: layouts/standard }
27
+ focused: { layout: layouts/focused }
28
28
 
29
29
  preview:
30
30
  focused: [ card ]
@@ -65,7 +65,7 @@ children:
65
65
  align: start
66
66
  gap: "2"
67
67
  width: full
68
- template:
68
+ item:
69
69
  type: Button
70
70
  action:
71
71
  type: sendMessage
@@ -36,7 +36,7 @@ children:
36
36
  gap: "4"
37
37
  width: full
38
38
  padding: [ "2", "0", "2", "0" ]
39
- template:
39
+ item:
40
40
  type: Button
41
41
  action: sendMessage
42
42
  style:
@@ -19,6 +19,7 @@ props:
19
19
  # pin the mood forever.
20
20
  chatState:
21
21
  type: string
22
+ description: "Which face the chat is showing. Empty means its default."
22
23
  input: false
23
24
  default: ""
24
25
  enum: ["", welcome, active]
@@ -26,10 +27,12 @@ props:
26
27
  # platform projects for real).
27
28
  isEmpty:
28
29
  type: boolean
30
+ description: "True before any message exists, so the empty state is drawn."
29
31
  input: false
30
32
  default: true
31
33
  hasMessages:
32
34
  type: boolean
35
+ description: "True once the conversation has started."
33
36
  input: false
34
37
  default: false
35
38
  # THE STATE TREE (State Model v2): ONE public state — the single-state permanent
@@ -6,8 +6,11 @@
6
6
  /** Null when the name is usable, otherwise the reason to show beside the field. */
7
7
  export function checkProjectName(name: string): string | null;
8
8
 
9
- /** Create rx/<name>/ under `home`. Returns the created path. Throws if unusable. */
9
+ /** Create design/<name>/ under `home`. Returns the created path. Throws if unusable. */
10
10
  export function createProject(home: string, name: string): string;
11
11
 
12
- /** The first project, plus prompts/ and nodes/ beside rx/. Returns the project path. */
12
+ /** The first project, plus the editor settings and the CI template. Returns the project path. */
13
13
  export function createFirstProject(home: string, name: string): string;
14
+
15
+ /** Write .github/workflows/unoverse.yml for `project`, once. Never replaces an existing file. */
16
+ export function writeCiWorkflow(home: string, project: string): void;
@@ -245,12 +245,79 @@ export function writeEditorSettings(home) {
245
245
  if (!existsSync(ext)) writeFileSync(ext, JSON.stringify({ recommendations: ["redhat.vscode-yaml"] }, null, 2) + "\n");
246
246
  }
247
247
 
248
+ /**
249
+ * THE CI TEMPLATE (RELEASE_LIFECYCLE.md §3). The workspace is the client's Git repo, and
250
+ * their pipeline deploys it: pull requests lint, main goes to UAT, a `v*` tag goes to
251
+ * production. Each GitHub environment (`uat`, `production`) holds its own UNOVERSE_TOKEN,
252
+ * so a UAT key can never write to production, and production's environment is where the
253
+ * client adds a required approver. Addresses come from unoverse.yaml `environments:`.
254
+ * Written once; a later run never replaces the team's own edits.
255
+ */
256
+ const CI_WORKFLOW = `# Deploys this workspace. Pull requests lint; main goes to UAT; a v* tag goes to production.
257
+ # Setup: https://docs.unoverse.ai/runbooks/publish-from-github
258
+ name: unoverse
259
+
260
+ on:
261
+ pull_request:
262
+ push:
263
+ branches: [main]
264
+ tags: ["v*"]
265
+
266
+ jobs:
267
+ lint:
268
+ runs-on: ubuntu-latest
269
+ steps:
270
+ - uses: actions/checkout@v4
271
+ - uses: actions/setup-node@v4
272
+ with:
273
+ node-version: 20
274
+ - run: npx --yes unoverse@latest lint PROJECT
275
+
276
+ uat:
277
+ if: github.event_name == 'push' && github.ref == 'refs/heads/main'
278
+ needs: lint
279
+ runs-on: ubuntu-latest
280
+ environment: uat
281
+ steps:
282
+ - uses: actions/checkout@v4
283
+ - uses: actions/setup-node@v4
284
+ with:
285
+ node-version: 20
286
+ - run: npx --yes unoverse@latest deploy studio PROJECT --env uat --yes
287
+ env:
288
+ UNOVERSE_TOKEN: \${{ secrets.UNOVERSE_TOKEN }}
289
+
290
+ production:
291
+ if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v')
292
+ needs: lint
293
+ runs-on: ubuntu-latest
294
+ environment: production
295
+ steps:
296
+ - uses: actions/checkout@v4
297
+ - uses: actions/setup-node@v4
298
+ with:
299
+ node-version: 20
300
+ - run: npx --yes unoverse@latest deploy studio PROJECT --env production --yes
301
+ env:
302
+ UNOVERSE_TOKEN: \${{ secrets.UNOVERSE_TOKEN }}
303
+ `;
304
+
305
+ export function writeCiWorkflow(home, project) {
306
+ const dir = join(home, ".github", "workflows");
307
+ const file = join(dir, "unoverse.yml");
308
+ if (existsSync(file)) return;
309
+ mkdirSync(dir, { recursive: true });
310
+ writeFileSync(file, CI_WORKFLOW.replaceAll("PROJECT", project));
311
+ }
312
+
248
313
  export function createFirstProject(home, name) {
249
314
  const root = createProject(home, name);
250
315
  // NOTHING beside the design tree. skills/ and blocks/ moved INTO the org on 2026-08-24
251
316
  // and nodes/ followed on 2026-09-08 (the sample package lands at design/<org>/nodes/),
252
- // so every authored kind sits in one place.
317
+ // so every authored kind sits in one place. The two exceptions are the editor's
318
+ // settings and the CI template, which belong to the repo, not to a project.
253
319
  writeEditorSettings(home);
320
+ writeCiWorkflow(home, name);
254
321
 
255
322
  topUpSamples(home, name);
256
323
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@unoverse-platform/studio",
3
- "version": "0.1.104",
3
+ "version": "0.1.105",
4
4
  "type": "module",
5
5
  "description": "Unoverse Studio: the local authoring app. Reads your own rx/ folder, no backend.",
6
6
  "scripts": {
@@ -924,6 +924,15 @@ function componentNamesForFile(file) {
924
924
  const org = projectSegs.join("/");
925
925
  const cached = componentNamesCache.get(org);
926
926
  if (cached !== undefined) return cached;
927
+ // A PARTIAL SET IS WORSE THAN NO SET (the app-sizes trap below, same cause). A developer's
928
+ // project has no design system on disk, so DS falls back to DESIGN_ROOT and only the org's
929
+ // own names would be left: every marketplace name a preview uses (`card`) then reads as
930
+ // unknown, and a fresh Studio workspace failed lint on its own sample. Unverifiable here,
931
+ // so not asserted.
932
+ if (DS === DESIGN_ROOT) {
933
+ componentNamesCache.set(org, null);
934
+ return null;
935
+ }
927
936
  const dirs = [
928
937
  join(DS, "components"),
929
938
  join(DESIGN_ROOT, ...projectSegs, "components"),