unoverse 0.1.148 → 0.1.150

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
@@ -27,9 +27,11 @@ unoverse stop
27
27
 
28
28
  ## Build with Claude
29
29
 
30
- Creating a universe also installs a Claude Code skill (`.claude/skills/unoverse-create`)
30
+ Creating a universe also installs the Claude Code authoring skills (`.claude/skills/`)
31
31
  and registers the `canvas` MCP (`.mcp.json`). Open the folder in Claude Code and ask for
32
32
  what you want: components, templates, custom nodes, agent skills, or whole workflows
33
- built live on your Canvas. `unoverse update` keeps the CLI and the skill current.
33
+ built live on your Canvas. `unoverse update` keeps the CLI and the skills current, and
34
+ any agent can install the same skills straight from the docs site:
35
+ `npx skills add docs.unoverse.ai`.
34
36
 
35
- Documentation: https://github.com/unoverse-platform/docs
37
+ Documentation: https://docs.unoverse.ai
package/bin/unoverse.mjs CHANGED
@@ -145,7 +145,50 @@ switch (cmd) {
145
145
 
146
146
  case "studio": {
147
147
  // Studio is its own npm app; this is a launcher, not a wrapper.
148
- const r = spawnSync("npx", ["-y", "@unoverse-platform/studio@latest", ...args], {
148
+ //
149
+ // Launched by EXACT version, resolved fresh, never `@latest`: npx keys its cache
150
+ // by the spec, and a cached `@latest` entry updates the top package IN PLACE while
151
+ // reusing whatever dependencies already satisfy their ranges — observed live as
152
+ // studio 0.1.43 running against a base two releases stale, which is how a
153
+ // developer gets last week's lint under this week's screens. An exact spec is a
154
+ // new cache key, so every studio release installs clean and fully resolved, and
155
+ // relaunching the same version stays instant from cache. Offline (npm view
156
+ // fails), fall back to the cached latest — stale beats broken with no network.
157
+ // RECLAIM THE PORT FROM A STALE STUDIO. A studio left over from an earlier session
158
+ // keeps :4108, so the new launch either fails to bind or — worse — the browser
159
+ // quietly keeps talking to last week's build. If the listener IS a studio, it is
160
+ // ours to replace: kill it and wait for the port. Anything else on the port is
161
+ // NOT ours: name it and stop, never kill a stranger's process.
162
+ const STUDIO_PORT = 4108;
163
+ const lsof = spawnSync("lsof", ["-nP", `-iTCP:${STUDIO_PORT}`, "-sTCP:LISTEN", "-Fpc"], { encoding: "utf8" });
164
+ const holder = lsof.status === 0 ? (lsof.stdout.match(/^p(\d+)$/m) || [])[1] : undefined;
165
+ if (holder) {
166
+ const cmd = spawnSync("ps", ["-p", holder, "-o", "command="], { encoding: "utf8" }).stdout?.trim() ?? "";
167
+ if (/unoverse-studio|@unoverse-platform\/studio/.test(cmd)) {
168
+ try {
169
+ process.kill(Number(holder));
170
+ } catch {
171
+ /* already gone */
172
+ }
173
+ // Wait (up to ~5s) for the socket to actually free — kill returns before close.
174
+ for (let i = 0; i < 25; i++) {
175
+ const still = spawnSync("lsof", ["-nP", `-iTCP:${STUDIO_PORT}`, "-sTCP:LISTEN"], { encoding: "utf8" });
176
+ if (!still.stdout?.trim()) break;
177
+ spawnSync("sleep", ["0.2"]);
178
+ }
179
+ console.log(` Reclaimed :${STUDIO_PORT} from a previous studio (pid ${holder})`);
180
+ } else {
181
+ console.error(
182
+ ` :${STUDIO_PORT} is held by something that is not a studio (pid ${holder}: ${cmd || "unknown"}).\n` +
183
+ ` Stop that process first — unoverse won't kill what it didn't start.`,
184
+ );
185
+ process.exit(1);
186
+ }
187
+ }
188
+ const view = spawnSync("npm", ["view", "@unoverse-platform/studio", "version"], { encoding: "utf8" });
189
+ const exact = view.status === 0 ? view.stdout.trim() : "";
190
+ const spec = exact ? `@unoverse-platform/studio@${exact}` : "@unoverse-platform/studio@latest";
191
+ const r = spawnSync("npx", ["-y", spec, ...args], {
149
192
  stdio: "inherit",
150
193
  });
151
194
  process.exit(r.status ?? 0);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "unoverse",
3
- "version": "0.1.148",
3
+ "version": "0.1.150",
4
4
  "description": "The Unoverse front door — create a Studio project, a universe, or a client app, and launch Studio.",
5
5
  "license": "SEE LICENSE IN README.md",
6
6
  "type": "module",