uniweb 0.8.15 → 0.8.16

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
@@ -200,7 +200,7 @@ After creating your project:
200
200
 
201
201
  1. **Explore the structure** — Browse `site/pages/` to see how content is organized. Each page folder contains `page.yml` (metadata) and `.md` files (sections).
202
202
 
203
- 2. **Generate component docs** — Run `npx uniweb docs` to create `COMPONENTS.md` with all available components, their parameters, and presets.
203
+ 2. **Generate component docs** — Run `uniweb docs` to create `COMPONENTS.md` with all available components, their parameters, and presets.
204
204
 
205
205
  3. **Learn the configuration** — Run `uniweb docs site` or `uniweb docs page` for quick reference on configuration options.
206
206
 
@@ -267,31 +267,31 @@ Start simple. Add what you need, when you need it:
267
267
  cd my-site
268
268
 
269
269
  # Add a co-located foundation + site pair
270
- npx uniweb add project blog
270
+ uniweb add project blog
271
271
 
272
272
  # Add a second foundation at root
273
- npx uniweb add foundation ui
273
+ uniweb add foundation ui
274
274
 
275
275
  # Add a site wired to a specific foundation
276
- npx uniweb add site docs --foundation ui
276
+ uniweb add site docs --foundation ui
277
277
 
278
278
  # Add an extension (auto-wired to the only site)
279
- npx uniweb add extension effects
279
+ uniweb add extension effects
280
280
 
281
281
  # Scaffold + apply content from an official template
282
- npx uniweb add project marketing --from marketing
282
+ uniweb add project marketing --from marketing
283
283
  ```
284
284
 
285
285
  The workspace grows organically. `add` handles placement, wires dependencies, updates workspace globs, and generates root scripts. The name you provide becomes both the directory name and the package name. Use `--path` to override default placement, or `--project` for explicit co-located layouts.
286
286
 
287
- > `npx uniweb` works before and after install. Once dependencies are installed, you can also use `pnpm uniweb` directly since `uniweb` is a project dependency.
287
+ > **Install the CLI globally** with `npm i -g uniweb` for the best experience. You can also use `npx uniweb` or `pnpm uniweb` without a global install.
288
288
 
289
289
  **Or start blank and build up:**
290
290
 
291
291
  ```bash
292
292
  pnpm create uniweb acme --blank
293
293
  cd acme
294
- npx uniweb add project main
294
+ uniweb add project main
295
295
  pnpm install
296
296
  pnpm dev
297
297
  ```
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "uniweb",
3
- "version": "0.8.15",
3
+ "version": "0.8.16",
4
4
  "description": "Create structured Vite + React sites with content/code separation",
5
5
  "type": "module",
6
6
  "bin": {
@@ -41,11 +41,24 @@
41
41
  "js-yaml": "^4.1.0",
42
42
  "prompts": "^2.4.2",
43
43
  "tar": "^7.0.0",
44
- "@uniweb/build": "0.8.14",
45
- "@uniweb/content-reader": "1.1.4",
46
- "@uniweb/core": "0.5.10",
47
44
  "@uniweb/runtime": "0.6.11",
48
- "@uniweb/kit": "0.7.10",
49
- "@uniweb/semantic-parser": "1.1.6"
45
+ "@uniweb/core": "0.5.10",
46
+ "@uniweb/kit": "0.7.11"
47
+ },
48
+ "peerDependencies": {
49
+ "@uniweb/build": "0.8.15",
50
+ "@uniweb/semantic-parser": "1.1.6",
51
+ "@uniweb/content-reader": "1.1.4"
52
+ },
53
+ "peerDependenciesMeta": {
54
+ "@uniweb/build": {
55
+ "optional": true
56
+ },
57
+ "@uniweb/content-reader": {
58
+ "optional": true
59
+ },
60
+ "@uniweb/semantic-parser": {
61
+ "optional": true
62
+ }
50
63
  }
51
64
  }
@@ -83,7 +83,7 @@ Use `--template <n>` for an official template (`none`, `starter`, `marketing`, `
83
83
  ### Adding a co-located project
84
84
 
85
85
  ```bash
86
- pnpm uniweb add project docs
86
+ uniweb add project docs
87
87
  pnpm install
88
88
  ```
89
89
 
@@ -92,10 +92,10 @@ This creates `docs/foundation/` + `docs/site/` with package names `docs-foundati
92
92
  ### Adding individual packages
93
93
 
94
94
  ```bash
95
- pnpm uniweb add foundation # First foundation → ./foundation/
96
- pnpm uniweb add foundation ui # Named → ./ui/
97
- pnpm uniweb add site # First site → ./site/
98
- pnpm uniweb add site blog # Named → ./blog/
95
+ uniweb add foundation # First foundation → ./foundation/
96
+ uniweb add foundation ui # Named → ./ui/
97
+ uniweb add site # First site → ./site/
98
+ uniweb add site blog # Named → ./blog/
99
99
  ```
100
100
 
101
101
  The name is both the directory name and the package name. Use `--project <n>` to co-locate under a project directory (e.g., `--project docs` → `docs/foundation/`).
@@ -103,8 +103,8 @@ The name is both the directory name and the package name. Use `--project <n>` to
103
103
  ### Adding section types
104
104
 
105
105
  ```bash
106
- pnpm uniweb add section Hero
107
- pnpm uniweb add section Hero --foundation ui # When multiple foundations exist
106
+ uniweb add section Hero
107
+ uniweb add section Hero --foundation ui # When multiple foundations exist
108
108
  ```
109
109
 
110
110
  Creates `src/sections/Hero/index.jsx` and `meta.js` with a minimal CCA-proper starter. The dev server picks it up automatically — no build or install needed.
@@ -340,9 +340,9 @@ Check out [this](/a) link. ← inline → stays in paragraphs as <a> tag
340
340
  This is [less important]{muted} context.
341
341
  ```
342
342
 
343
- `accent` (colored + bold) and `muted` (subtle) adapt to context automatically. Components receive HTML strings with spans applied: `<span accent="true">faster</span>`.
343
+ `accent` (link-colored + bold), `callout` (accent-colored + bold), and `muted` (subtle) are built-in defaults that adapt to context automatically. Components receive HTML strings with spans applied: `<span accent="true">faster</span>`.
344
344
 
345
- Sites can define additional named styles in `theme.yml`'s `inline:` section.
345
+ Sites can override these or define additional named styles in `theme.yml`'s `inline:` section.
346
346
 
347
347
  ### Fenced Code in Content
348
348
 
@@ -676,6 +676,9 @@ inline:
676
676
  accent:
677
677
  color: var(--link)
678
678
  font-weight: '600'
679
+ callout:
680
+ color: var(--accent)
681
+ font-weight: '600'
679
682
 
680
683
  vars:
681
684
  header-height: 5rem
@@ -1282,9 +1285,9 @@ Semantic tokens come from `theme-tokens.css` (populated from `theme.yml`). Use `
1282
1285
 
1283
1286
  **Content not appearing as expected?**
1284
1287
  ```bash
1285
- pnpm uniweb inspect pages/home/hero.md # Single section
1286
- pnpm uniweb inspect pages/home/ # Whole page
1287
- pnpm uniweb inspect pages/home/hero.md --raw # ProseMirror AST
1288
+ uniweb inspect pages/home/hero.md # Single section
1289
+ uniweb inspect pages/home/ # Whole page
1290
+ uniweb inspect pages/home/hero.md --raw # ProseMirror AST
1288
1291
  ```
1289
1292
 
1290
1293
  ## Learning from Official Templates
@@ -1292,7 +1295,7 @@ pnpm uniweb inspect pages/home/hero.md --raw # ProseMirror AST
1292
1295
  When you're unsure how to implement a pattern — data fetching, i18n, layouts, insets, theming — install an official template as a reference project in your workspace:
1293
1296
 
1294
1297
  ```bash
1295
- pnpm uniweb add project marketing --from marketing
1298
+ uniweb add project marketing --from marketing
1296
1299
  pnpm install
1297
1300
  ```
1298
1301
 
@@ -4,10 +4,10 @@ Generate up-to-date documentation for all foundation components:
4
4
 
5
5
  ```bash
6
6
  # From foundation directory
7
- pnpm uniweb docs
7
+ uniweb docs
8
8
 
9
9
  # Or from site directory (auto-detects linked foundation)
10
- cd site && pnpm uniweb docs
10
+ cd site && uniweb docs
11
11
  ```
12
12
 
13
13
  This creates `COMPONENTS.md` with details on each component's parameters, presets, and content elements. The documentation is generated from component `meta.js` files, so it's always current.
@@ -64,4 +64,4 @@ seo:
64
64
  priority: 0.8
65
65
  ```
66
66
 
67
- Run `pnpm uniweb docs site` or `pnpm uniweb docs page` for complete reference.
67
+ Run `uniweb docs site` or `uniweb docs page` for complete reference.
@@ -352,7 +352,7 @@ async function addSite(rootDir, projectName, opts, pm = 'pnpm') {
352
352
  }, {
353
353
  onProgress: (msg) => info(` ${msg}`),
354
354
  })
355
- log(` ${colors.yellow}⚠ No foundation wired. Add one later with: npx uniweb add foundation${colors.reset}`)
355
+ log(` ${colors.yellow}⚠ No foundation wired. Add one later with: uniweb add foundation${colors.reset}`)
356
356
  }
357
357
 
358
358
  // Apply template content if --from specified
@@ -379,7 +379,7 @@ export async function doctor(args = []) {
379
379
  message: `Foundation not built: ${matchingFoundation.name}`
380
380
  })
381
381
  warn(`Foundation not built yet`)
382
- log(` ${colors.dim}Run: npx uniweb build${colors.reset}`)
382
+ log(` ${colors.dim}Run: uniweb build${colors.reset}`)
383
383
  } else {
384
384
  success(`Foundation built: dist/foundation.js exists`)
385
385
  }
@@ -431,7 +431,7 @@ export async function doctor(args = []) {
431
431
  message: `Extension not built: ${ext.name}`
432
432
  })
433
433
  warn(`Extension not built yet`)
434
- log(` ${colors.dim}Run: npx uniweb build${colors.reset}`)
434
+ log(` ${colors.dim}Run: uniweb build${colors.reset}`)
435
435
  } else {
436
436
  success(`Extension built: dist/foundation.js exists`)
437
437
  }
package/src/index.js CHANGED
@@ -5,20 +5,27 @@
5
5
  *
6
6
  * Scaffolds new Uniweb sites and foundations, builds projects, and generates docs.
7
7
  *
8
+ * Install globally:
9
+ * npm i -g uniweb
10
+ *
8
11
  * Usage:
9
- * npx uniweb create [project-name]
10
- * npx uniweb create --template marketing
11
- * npx uniweb add foundation [name]
12
- * npx uniweb build
13
- * npx uniweb docs # Generate COMPONENTS.md from schema
12
+ * uniweb create [project-name]
13
+ * uniweb create --template marketing
14
+ * uniweb add foundation [name]
15
+ * uniweb build
16
+ * uniweb docs
17
+ *
18
+ * Global install delegation:
19
+ * When installed globally, project-bound commands (build, docs, etc.) are
20
+ * delegated to the project-local CLI if one exists in node_modules. This
21
+ * ensures version alignment between the CLI and @uniweb/build.
14
22
  */
15
23
 
16
- import { existsSync } from 'node:fs'
17
- import { execSync } from 'node:child_process'
18
- import { resolve, join, relative } from 'node:path'
24
+ import { existsSync, readFileSync } from 'node:fs'
25
+ import { execSync, spawn as spawnChild } from 'node:child_process'
26
+ import { resolve, join, relative, dirname } from 'node:path'
27
+ import { fileURLToPath } from 'node:url'
19
28
  import prompts from 'prompts'
20
- import { build } from './commands/build.js'
21
- import { docs } from './commands/docs.js'
22
29
  import { doctor } from './commands/doctor.js'
23
30
  import { i18n } from './commands/i18n.js'
24
31
  import { inspect } from './commands/inspect.js'
@@ -80,6 +87,108 @@ function title(message) {
80
87
  console.log(`\n${colors.cyan}${colors.bright}${message}${colors.reset}\n`)
81
88
  }
82
89
 
90
+ // CLI version (read once, lazily)
91
+ const __dirname = dirname(fileURLToPath(import.meta.url))
92
+ let _cliVersion = null
93
+ function getCliVersion() {
94
+ if (!_cliVersion) {
95
+ const pkg = JSON.parse(readFileSync(join(__dirname, '..', 'package.json'), 'utf8'))
96
+ _cliVersion = pkg.version
97
+ }
98
+ return _cliVersion
99
+ }
100
+
101
+ /**
102
+ * Commands that always run from the global CLI (no project context needed)
103
+ */
104
+ const STANDALONE_COMMANDS = new Set([
105
+ 'create', '--help', '-h', '--version', '-v', 'login',
106
+ ])
107
+
108
+ /**
109
+ * Check if this CLI is running from a global install.
110
+ * When installed globally, process.argv[1] points outside any node_modules.
111
+ * When run via npx or as a local dependency, it's inside node_modules.
112
+ */
113
+ function isGlobalInstall() {
114
+ const scriptPath = process.argv[1]
115
+ if (!scriptPath) return false
116
+ // Normalize path separators for Windows compatibility
117
+ return !scriptPath.split('/').includes('node_modules') &&
118
+ !scriptPath.split('\\').includes('node_modules')
119
+ }
120
+
121
+ /**
122
+ * Find the project-local CLI entry point, if one exists.
123
+ * Walks up from cwd looking for node_modules/uniweb/src/index.js.
124
+ */
125
+ function findLocalCli() {
126
+ let dir = process.cwd()
127
+ while (true) {
128
+ const localCli = join(dir, 'node_modules', 'uniweb', 'src', 'index.js')
129
+ if (existsSync(localCli)) return localCli
130
+ const parent = dirname(dir)
131
+ if (parent === dir) break
132
+ dir = parent
133
+ }
134
+ return null
135
+ }
136
+
137
+ /**
138
+ * Delegate execution to the project-local CLI.
139
+ * Spawns the local CLI with the same arguments and inherits stdio.
140
+ * Warns if the local version differs from the global version.
141
+ */
142
+ function delegateToLocal(localCliPath) {
143
+ // Check for version mismatch between global and local CLI
144
+ try {
145
+ const localPkgPath = join(dirname(localCliPath), '..', 'package.json')
146
+ const localPkg = JSON.parse(readFileSync(localPkgPath, 'utf8'))
147
+ const globalVersion = getCliVersion()
148
+ if (localPkg.version && localPkg.version !== globalVersion) {
149
+ const yellow = '\x1b[33m'
150
+ const dim = '\x1b[2m'
151
+ const reset = '\x1b[0m'
152
+ console.error(`${yellow}Note:${reset} Global CLI is ${dim}${globalVersion}${reset}, project has ${dim}${localPkg.version}${reset} ${dim}(using project version)${reset}`)
153
+ }
154
+ } catch { /* ignore — version check is best-effort */ }
155
+
156
+ return new Promise((resolve, reject) => {
157
+ const child = spawnChild(
158
+ process.execPath,
159
+ [localCliPath, ...process.argv.slice(2)],
160
+ { stdio: 'inherit' }
161
+ )
162
+ child.on('close', (code) => process.exit(code ?? 0))
163
+ child.on('error', reject)
164
+ })
165
+ }
166
+
167
+ /**
168
+ * Import a command module that may depend on @uniweb/build.
169
+ * Provides a helpful error when the dependency can't be resolved
170
+ * (e.g., running a project-bound command from a global install
171
+ * outside a project directory).
172
+ */
173
+ async function importProjectCommand(modulePath) {
174
+ try {
175
+ return await import(modulePath)
176
+ } catch (err) {
177
+ if (err.code === 'ERR_MODULE_NOT_FOUND' && err.message?.includes('@uniweb/')) {
178
+ error('This command must be run from inside a Uniweb project.')
179
+ log('')
180
+ log(`Make sure you're in a project directory with dependencies installed:`)
181
+ log(` ${colors.cyan}cd your-project${colors.reset}`)
182
+ log(` ${colors.cyan}npm install${colors.reset}`)
183
+ log('')
184
+ log(`Or create a new project:`)
185
+ log(` ${colors.cyan}uniweb create my-project${colors.reset}`)
186
+ process.exit(1)
187
+ }
188
+ throw err
189
+ }
190
+ }
191
+
83
192
  /**
84
193
  * Create a project using the new package template flow (default)
85
194
  */
@@ -306,21 +415,55 @@ async function main() {
306
415
  const command = args[0]
307
416
  const pm = detectPackageManager()
308
417
 
418
+ // Handle --version / -v
419
+ if (command === '--version' || command === '-v') {
420
+ console.log(`uniweb ${getCliVersion()}`)
421
+ return
422
+ }
423
+
424
+ // Global install launcher: delegate project-bound commands to local CLI
425
+ const global = isGlobalInstall()
426
+ if (global && command && !STANDALONE_COMMANDS.has(command)) {
427
+ const localCli = findLocalCli()
428
+ if (localCli) {
429
+ await delegateToLocal(localCli)
430
+ return
431
+ }
432
+ // No local CLI found — fall through and try to run the command directly.
433
+ // Commands that need @uniweb/build will get a helpful error via importProjectCommand().
434
+ }
435
+
436
+ // Start non-blocking update check for global installs
437
+ let showUpdateNotification = () => {}
438
+ if (global) {
439
+ try {
440
+ const { startUpdateCheck } = await import('./utils/update-check.js')
441
+ showUpdateNotification = startUpdateCheck(getCliVersion())
442
+ } catch {
443
+ // Update check is optional — don't fail if the module is missing
444
+ }
445
+ }
446
+
309
447
  // Show help
310
448
  if (!command || command === '--help' || command === '-h') {
311
449
  showHelp()
450
+ await showUpdateNotification()
312
451
  return
313
452
  }
314
453
 
315
- // Handle build command
454
+ // Handle build command (dynamic import — depends on @uniweb/build)
316
455
  if (command === 'build') {
456
+ const { build } = await importProjectCommand('./commands/build.js')
317
457
  await build(args.slice(1))
458
+ await showUpdateNotification()
318
459
  return
319
460
  }
320
461
 
321
- // Handle docs command
462
+ // Handle docs command (dynamic import — depends on @uniweb/build)
322
463
  if (command === 'docs') {
464
+ const { docs } = await importProjectCommand('./commands/docs.js')
323
465
  await docs(args.slice(1))
466
+ await showUpdateNotification()
324
467
  return
325
468
  }
326
469
 
@@ -616,14 +759,16 @@ async function main() {
616
759
  log(` ${colors.cyan}${runCmd(pm, 'dev')}${colors.reset}`)
617
760
  }
618
761
  log('')
762
+
763
+ await showUpdateNotification()
619
764
  }
620
765
 
621
766
  function showHelp() {
622
767
  log(`
623
- ${colors.cyan}${colors.bright}Uniweb CLI${colors.reset}
768
+ ${colors.cyan}${colors.bright}Uniweb CLI${colors.reset} ${colors.dim}v${getCliVersion()}${colors.reset}
624
769
 
625
770
  ${colors.bright}Usage:${colors.reset}
626
- npx uniweb <command> [options]
771
+ uniweb <command> [options]
627
772
 
628
773
  ${colors.bright}Commands:${colors.reset}
629
774
  create [name] Create a new project
@@ -654,6 +799,7 @@ ${colors.bright}Add Subcommands:${colors.reset}
654
799
  add section <name> Add a section type to a foundation (--foundation)
655
800
 
656
801
  ${colors.bright}Global Options:${colors.reset}
802
+ --version, -v Show version
657
803
  --non-interactive Fail with usage info instead of prompting
658
804
  Auto-detected when CI=true or no TTY (pipes, agents)
659
805
 
@@ -720,22 +866,26 @@ ${colors.bright}Template Types:${colors.reset}
720
866
  https://github.com/user/repo GitHub URL
721
867
 
722
868
  ${colors.bright}Examples:${colors.reset}
723
- npx uniweb create my-project # Foundation + site + starter content
724
- npx uniweb create my-project --template none # Foundation + site, no content
725
- npx uniweb create my-project --blank # Empty workspace
726
- npx uniweb create my-project --template marketing # Official template
727
- npx uniweb create my-project --template ./my-template # Local template
869
+ uniweb create my-project # Foundation + site + starter content
870
+ uniweb create my-project --template none # Foundation + site, no content
871
+ uniweb create my-project --blank # Empty workspace
872
+ uniweb create my-project --template marketing # Official template
873
+ uniweb create my-project --template ./my-template # Local template
728
874
 
729
875
  cd my-project
730
- npx uniweb add project docs # Add docs/foundation/ + docs/site/
731
- npx uniweb add project docs --from academic # Co-located pair + academic content
732
- npx uniweb add foundation # Add foundation at root
733
- npx uniweb add site blog --foundation marketing # Add site wired to marketing
734
- npx uniweb add extension effects --site site # Add extensions/effects/
735
-
736
- npx uniweb build
737
- npx uniweb build --target foundation
738
- cd foundation && npx uniweb docs # Generate COMPONENTS.md
876
+ uniweb add project docs # Add docs/foundation/ + docs/site/
877
+ uniweb add project docs --from academic # Co-located pair + academic content
878
+ uniweb add foundation # Add foundation at root
879
+ uniweb add site blog --foundation marketing # Add site wired to marketing
880
+ uniweb add extension effects --site site # Add extensions/effects/
881
+
882
+ uniweb build
883
+ uniweb build --target foundation
884
+ cd foundation && uniweb docs # Generate COMPONENTS.md
885
+
886
+ ${colors.bright}Install:${colors.reset}
887
+ npm i -g uniweb Global install (recommended)
888
+ npx uniweb <command> Run without installing
739
889
  `)
740
890
  }
741
891
 
@@ -0,0 +1,105 @@
1
+ /**
2
+ * Lightweight Update Notification
3
+ *
4
+ * Checks the npm registry for newer versions of the CLI.
5
+ * Runs at most once per day, caches results in ~/.uniweb/update-check.json.
6
+ * Uses Node 20+ built-in fetch — no external dependencies.
7
+ */
8
+
9
+ import { homedir } from 'node:os'
10
+ import { existsSync, readFileSync, mkdirSync, writeFileSync } from 'node:fs'
11
+ import { join } from 'node:path'
12
+
13
+ const CHECK_INTERVAL = 24 * 60 * 60 * 1000 // 1 day
14
+ const STATE_DIR = join(homedir(), '.uniweb')
15
+ const STATE_FILE = join(STATE_DIR, 'update-check.json')
16
+
17
+ /**
18
+ * Compare two semver strings.
19
+ * Returns 1 if a > b, -1 if a < b, 0 if equal.
20
+ */
21
+ function compareSemver(a, b) {
22
+ const pa = a.split('.').map(Number)
23
+ const pb = b.split('.').map(Number)
24
+ for (let i = 0; i < 3; i++) {
25
+ if ((pa[i] || 0) > (pb[i] || 0)) return 1
26
+ if ((pa[i] || 0) < (pb[i] || 0)) return -1
27
+ }
28
+ return 0
29
+ }
30
+
31
+ /**
32
+ * Read cached update check state.
33
+ */
34
+ function readState() {
35
+ try {
36
+ if (existsSync(STATE_FILE)) {
37
+ return JSON.parse(readFileSync(STATE_FILE, 'utf8'))
38
+ }
39
+ } catch { /* ignore corrupt cache */ }
40
+ return {}
41
+ }
42
+
43
+ /**
44
+ * Write update check state to disk.
45
+ */
46
+ function writeState(state) {
47
+ try {
48
+ if (!existsSync(STATE_DIR)) mkdirSync(STATE_DIR, { recursive: true })
49
+ writeFileSync(STATE_FILE, JSON.stringify(state))
50
+ } catch { /* ignore write errors */ }
51
+ }
52
+
53
+ /**
54
+ * Print update notification to stderr (doesn't interfere with piped output).
55
+ */
56
+ function printNotification(current, latest) {
57
+ const yellow = '\x1b[33m'
58
+ const cyan = '\x1b[36m'
59
+ const dim = '\x1b[2m'
60
+ const reset = '\x1b[0m'
61
+ console.error('')
62
+ console.error(`${yellow}Update available:${reset} ${dim}${current}${reset} → ${cyan}${latest}${reset}`)
63
+ console.error(`${dim}Run${reset} npm i -g uniweb ${dim}to update${reset}`)
64
+ }
65
+
66
+ /**
67
+ * Start a non-blocking update check.
68
+ *
69
+ * Returns a function that, when called (optionally awaited), prints
70
+ * the notification if a newer version was found.
71
+ *
72
+ * @param {string} currentVersion - The currently running CLI version
73
+ * @returns {Function} Call at the end of command execution to show notification
74
+ */
75
+ export function startUpdateCheck(currentVersion) {
76
+ let notification = null
77
+ const state = readState()
78
+
79
+ // Use cached result if checked recently
80
+ if (state.lastCheck && (Date.now() - state.lastCheck) < CHECK_INTERVAL) {
81
+ if (state.latestVersion && compareSemver(state.latestVersion, currentVersion) > 0) {
82
+ notification = state.latestVersion
83
+ }
84
+ return () => {
85
+ if (notification) printNotification(currentVersion, notification)
86
+ }
87
+ }
88
+
89
+ // Background fetch (non-blocking)
90
+ const fetchPromise = fetch('https://registry.npmjs.org/uniweb/latest')
91
+ .then(r => r.json())
92
+ .then(data => {
93
+ const latest = data.version
94
+ writeState({ lastCheck: Date.now(), latestVersion: latest })
95
+ if (compareSemver(latest, currentVersion) > 0) {
96
+ notification = latest
97
+ }
98
+ })
99
+ .catch(() => { /* network error — ignore silently */ })
100
+
101
+ return async () => {
102
+ await fetchPromise
103
+ if (notification) printNotification(currentVersion, notification)
104
+ }
105
+ }
package/src/versions.js CHANGED
@@ -61,7 +61,7 @@ export function getResolvedVersions() {
61
61
  if (resolvedVersions) return resolvedVersions
62
62
 
63
63
  const pkg = getCliPackageJson()
64
- const deps = { ...pkg.dependencies, ...pkg.devDependencies }
64
+ const deps = { ...pkg.dependencies, ...pkg.devDependencies, ...pkg.peerDependencies }
65
65
 
66
66
  // All @uniweb/* packages are now direct dependencies of the CLI.
67
67
  // When publishing with pnpm, workspace:* gets resolved to actual versions.