@aistrike-dev/ui-shell-dev 1.0.4 → 1.0.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.
package/README.md CHANGED
@@ -54,8 +54,11 @@ Read from the Vite root when present (or from the plugin's `devFile` option).
54
54
  `profile` defaults to `local`, `overrides` point other domains at their own dev servers (bare origins, no path; your
55
55
  own domain is overridden automatically), `idleTimeoutMs` defaults to `0` (idle timeout off), and `claims` is merged
56
56
  over the default dev claims. The plugin's `claims`, `ttlMs` and `noToken` options win over the file. `"lab": true`
57
- shows the shell's Design Lab (its live controls for the open design questions) over your pages, so you can judge them
58
- on your own screens; its **Lock in** needs the lab MFE's dev server and says so otherwise.
57
+ shows Octopus UI's Design Lab (its live controls for the open design questions, in a Picture-in-Picture window) over
58
+ your pages, so you can judge them on your own screens. `"lab": { "designSystem": "../octopus-ui" }` also names an
59
+ Octopus checkout (relative to the Vite root): **Lock in** then writes a work-loop item into its `.backlog/`, through
60
+ Octopus's Lock-in plugin (`@aistrike-dev/ui/lab/vite`, loaded from the installed `@aistrike-dev/ui`). Without one, or
61
+ when the path is not an Octopus checkout, Lock in downloads the same item instead.
59
62
 
60
63
  ## Commands
61
64
 
package/dist/devfile.d.ts CHANGED
@@ -2,6 +2,9 @@ import type { DevConfig, DevDomain } from '@aistrike-dev/ui-shell-sdk/shell';
2
2
  import type { Session } from '@aistrike-dev/ui-shell-sdk';
3
3
  import type { DevClaimsInput } from './token.js';
4
4
  export declare const DEV_FILE = "shell.dev.json";
5
+ export interface DevLab {
6
+ designSystem?: string;
7
+ }
5
8
  export interface DevFile {
6
9
  profile?: string;
7
10
  overrides?: {
@@ -10,8 +13,11 @@ export interface DevFile {
10
13
  domains?: DevDomain[];
11
14
  idleTimeoutMs?: number;
12
15
  landing?: string;
13
- /** Shows the shell's Design Lab over this MFE's pages, to judge open design questions on them. */
14
- lab?: boolean;
16
+ /**
17
+ * Shows Octopus UI's Design Lab over this MFE's pages, to judge open design questions on them. As an object, it is on,
18
+ * and `designSystem` is the path (from the Vite root) of the Octopus checkout its locks are written to.
19
+ */
20
+ lab?: boolean | DevLab;
15
21
  claims?: DevClaimsInput;
16
22
  }
17
23
  /** Dev claims must be a plain object of known keys; `iss`/`exp`/`iat` and friends cannot be smuggled into the token. */
package/dist/devfile.js CHANGED
@@ -111,6 +111,24 @@ function validateLanding(value) {
111
111
  }
112
112
  return value;
113
113
  }
114
+ const LAB_KEYS = ['designSystem'];
115
+ function validateLab(lab) {
116
+ if (typeof lab === 'boolean') {
117
+ return lab;
118
+ }
119
+ if (!isPlainObject(lab)) {
120
+ throw new Error('lab must be true, false or an object');
121
+ }
122
+ rejectUnknownKeys(lab, LAB_KEYS, 'lab');
123
+ const { designSystem } = lab;
124
+ if (designSystem === undefined) {
125
+ return {};
126
+ }
127
+ if (typeof designSystem !== 'string' || designSystem === '') {
128
+ throw new Error('lab.designSystem must be a non-empty string');
129
+ }
130
+ return { designSystem };
131
+ }
114
132
  function readExtras(parsed, result) {
115
133
  if (parsed.idleTimeoutMs !== undefined) {
116
134
  result.idleTimeoutMs = validateIdle(parsed.idleTimeoutMs);
@@ -119,10 +137,7 @@ function readExtras(parsed, result) {
119
137
  result.landing = validateLanding(parsed.landing);
120
138
  }
121
139
  if (parsed.lab !== undefined) {
122
- if (typeof parsed.lab !== 'boolean') {
123
- throw new Error('lab must be true or false');
124
- }
125
- result.lab = parsed.lab;
140
+ result.lab = validateLab(parsed.lab);
126
141
  }
127
142
  if (parsed.claims !== undefined) {
128
143
  result.claims = assertClaimsInput(parsed.claims, 'claims');
@@ -177,7 +192,7 @@ function landingOf(file, args) {
177
192
  }
178
193
  /** The lab flag, only when the file sets it: a config without one is the same config it always was. */
179
194
  function labOf(file) {
180
- return file?.lab === undefined ? {} : { lab: file.lab };
195
+ return file?.lab === undefined ? {} : { lab: file.lab !== false };
181
196
  }
182
197
  /** Explicit overrides win over the file; the profile defaults to `local`; the idle timeout defaults to off for local work. */
183
198
  export function buildDevConfig(file, args, session) {
@@ -31,6 +31,30 @@ const SHELL_ASSET_TAG = /<(script|link)\b([^>]*?\s(?:src|href)=["']\/assets\/)/g
31
31
  export function markShellAssets(html) {
32
32
  return html.replace(SHELL_ASSET_TAG, '<$1 vite-ignore$2');
33
33
  }
34
+ /**
35
+ * Mounts Octopus UI's Lock-in endpoint when the dev file names a design-system checkout (`lab.designSystem`), so the
36
+ * Design Lab's "Lock in" writes a work-loop item into that checkout's backlog. The plugin is Octopus's, loaded from the
37
+ * copy installed beside this package. Without a checkout, nothing is mounted and the lab downloads the lock instead.
38
+ */
39
+ async function mountLabLock(context, server, file, root) {
40
+ const lab = file?.lab;
41
+ if (typeof lab !== 'object' || lab.designSystem === undefined) {
42
+ return;
43
+ }
44
+ let plugin;
45
+ try {
46
+ const { labLockPlugin } = await import('@aistrike-dev/ui/lab/vite');
47
+ plugin = labLockPlugin({ designSystem: lab.designSystem, root });
48
+ }
49
+ catch {
50
+ console.warn('[octopus-lab] lock-in is disabled: @aistrike-dev/ui/lab/vite could not be loaded');
51
+ return;
52
+ }
53
+ const { configureServer } = plugin;
54
+ if (typeof configureServer === 'function') {
55
+ await configureServer.call(context, server);
56
+ }
57
+ }
34
58
  function sendHtml(res, html) {
35
59
  res.statusCode = 200;
36
60
  res.setHeader('Content-Type', CONTENT_TYPES['.html'] ?? 'text/html');
@@ -104,13 +128,14 @@ export function shellDevHost(options = {}) {
104
128
  config = resolved;
105
129
  id = mfeId(resolved);
106
130
  },
107
- configureServer(server) {
131
+ async configureServer(server) {
108
132
  if (!config) {
109
133
  throw new Error('aistrike:shell-dev-host: configureServer ran before configResolved');
110
134
  }
111
135
  const base = config.base;
112
136
  const scheme = server.config.server.https ? 'https' : 'http';
113
137
  const file = loadDevFile(options.devFile, config.root);
138
+ await mountLabLock(this, server, file, config.root);
114
139
  let session;
115
140
  if (options.noToken !== true) {
116
141
  const claims = { ...(file?.claims ?? {}), ...(options.claims ?? {}) };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aistrike-dev/ui-shell-dev",
3
- "version": "1.0.4",
3
+ "version": "1.0.6",
4
4
  "description": "A Vite plugin that serves the AiStrike UI shell from your micro front-end's dev server, plus a dev-token CLI.",
5
5
  "license": "SEE LICENSE IN LICENSE",
6
6
  "repository": {
@@ -46,14 +46,19 @@
46
46
  "e2e": "node scripts/check-pack.mjs && playwright test"
47
47
  },
48
48
  "peerDependencies": {
49
+ "@aistrike-dev/ui": ">=6.0.0-alpha.10",
49
50
  "vite": "^8.0.0"
50
51
  },
51
52
  "peerDependenciesMeta": {
53
+ "@aistrike-dev/ui": {
54
+ "optional": true
55
+ },
52
56
  "vite": {
53
57
  "optional": true
54
58
  }
55
59
  },
56
60
  "devDependencies": {
61
+ "@aistrike-dev/ui": "6.0.0-alpha.10",
57
62
  "@aistrike-dev/ui-shell-sdk": "workspace:*",
58
63
  "@playwright/test": "^1.63.0",
59
64
  "@types/node": "^24.0.0",