uniweb 0.48.0 → 0.48.1
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/package.json +5 -5
- package/src/commands/add.js +10 -2
- package/src/commands/template.js +90 -2
- package/src/framework-index.json +3 -3
- package/src/index.js +100 -18
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "uniweb",
|
|
3
|
-
"version": "0.48.
|
|
3
|
+
"version": "0.48.1",
|
|
4
4
|
"description": "Create structured Vite + React sites with content/code separation",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -42,14 +42,14 @@
|
|
|
42
42
|
"prompts": "^2.4.2",
|
|
43
43
|
"tar": "^7.0.0",
|
|
44
44
|
"@uniweb/core": "^0.24.2",
|
|
45
|
-
"@uniweb/semantic-parser": "^1.4.0",
|
|
46
45
|
"@uniweb/kit": "^0.18.0",
|
|
46
|
+
"@uniweb/semantic-parser": "^1.4.0",
|
|
47
47
|
"@uniweb/runtime": "^0.19.3"
|
|
48
48
|
},
|
|
49
49
|
"peerDependencies": {
|
|
50
|
-
"@uniweb/build": "^0.44.
|
|
51
|
-
"@uniweb/
|
|
52
|
-
"@uniweb/
|
|
50
|
+
"@uniweb/build": "^0.44.1",
|
|
51
|
+
"@uniweb/content-reader": "^1.2.4",
|
|
52
|
+
"@uniweb/semantic-parser": "^1.4.0"
|
|
53
53
|
},
|
|
54
54
|
"peerDependenciesMeta": {
|
|
55
55
|
"@uniweb/build": {
|
package/src/commands/add.js
CHANGED
|
@@ -1249,8 +1249,16 @@ async function addCi(rootDir, opts, pm = 'pnpm') {
|
|
|
1249
1249
|
let getAdapter, listAdapters
|
|
1250
1250
|
try {
|
|
1251
1251
|
;({ getAdapter, listAdapters } = await import('@uniweb/build/hosts'))
|
|
1252
|
-
} catch {
|
|
1253
|
-
|
|
1252
|
+
} catch (err) {
|
|
1253
|
+
// ⛔ Keep the reason. A bare `catch {}` here printed one line for three
|
|
1254
|
+
// different failures — the package is absent, the `./hosts` subpath is
|
|
1255
|
+
// not exported by the installed version, or the module threw while
|
|
1256
|
+
// evaluating — and they have different remedies.
|
|
1257
|
+
error(`Failed to load the host adapter registry from @uniweb/build/hosts.`)
|
|
1258
|
+
error(` ${err.message}`)
|
|
1259
|
+
if (err.code === 'ERR_MODULE_NOT_FOUND') {
|
|
1260
|
+
error(` Install the workspace's dependencies, or upgrade @uniweb/build.`)
|
|
1261
|
+
}
|
|
1254
1262
|
process.exit(1)
|
|
1255
1263
|
}
|
|
1256
1264
|
|
package/src/commands/template.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* template — RESERVED (not
|
|
2
|
+
* template — `list` is live; `register` is RESERVED (not on the new backend yet).
|
|
3
3
|
*
|
|
4
4
|
* `uniweb template publish` submitted a site as a cloud template to the legacy
|
|
5
5
|
* registry (the PHP backend + Cloudflare Worker) the CLI no longer talks to. A
|
|
@@ -9,9 +9,35 @@
|
|
|
9
9
|
*
|
|
10
10
|
* (Unrelated: scaffolding FROM a template — `uniweb create --template <name>` —
|
|
11
11
|
* is a separate path and is unaffected.)
|
|
12
|
+
*
|
|
13
|
+
* ⭐ `list` exists so a SCRIPT can enumerate the official templates. The
|
|
14
|
+
* interactive picker in `create` has always shown this list; `--json` is the
|
|
15
|
+
* same data, second rendering, for tooling that scaffolds several templates in
|
|
16
|
+
* a row and needs their names first.
|
|
17
|
+
*
|
|
18
|
+
* ⚠️ IT REPORTS A BUNDLED SNAPSHOT, NOT A LIVE FETCH — the roster is baked into
|
|
19
|
+
* the CLI at publish time (`src/framework-index.json`, rewritten from
|
|
20
|
+
* `templates/manifest.json` by the pre-publish hook). So it answers "which
|
|
21
|
+
* official templates does THIS CLI know", which is the right question when the
|
|
22
|
+
* next step is resolving one of those names with the same CLI. `cliVersion` is
|
|
23
|
+
* in the JSON for exactly that reason. A newer template than your CLI will not
|
|
24
|
+
* appear — and an unknown name is not fatal either way, since `create` falls
|
|
25
|
+
* through to npm `@uniweb/template-<name>`, so this is the OFFICIAL roster
|
|
26
|
+
* rather than the set of resolvable names.
|
|
12
27
|
*/
|
|
13
28
|
|
|
14
|
-
|
|
29
|
+
import { OFFICIAL_TEMPLATE_MAP } from '../templates/resolver.js'
|
|
30
|
+
import { getCliVersion } from '../versions.js'
|
|
31
|
+
|
|
32
|
+
const colors = {
|
|
33
|
+
reset: '\x1b[0m',
|
|
34
|
+
bright: '\x1b[1m',
|
|
35
|
+
dim: '\x1b[2m',
|
|
36
|
+
cyan: '\x1b[36m',
|
|
37
|
+
red: '\x1b[31m'
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function reserved() {
|
|
15
41
|
console.error(
|
|
16
42
|
"\x1b[31m✗\x1b[0m `uniweb template register` isn't available on the new backend yet."
|
|
17
43
|
)
|
|
@@ -24,7 +50,69 @@ export async function template() {
|
|
|
24
50
|
console.error(
|
|
25
51
|
' (Scaffolding FROM a template still works: `uniweb create --template <name>`.)'
|
|
26
52
|
)
|
|
53
|
+
console.error('')
|
|
54
|
+
console.error(' To list the official templates: `uniweb template list`.')
|
|
27
55
|
process.exit(1)
|
|
28
56
|
}
|
|
29
57
|
|
|
58
|
+
function listTemplates(args) {
|
|
59
|
+
const entries = Object.entries(OFFICIAL_TEMPLATE_MAP).map(([id, info]) => ({
|
|
60
|
+
id,
|
|
61
|
+
name: info?.name || id,
|
|
62
|
+
description: info?.description || '',
|
|
63
|
+
tags: info?.tags || []
|
|
64
|
+
}))
|
|
65
|
+
|
|
66
|
+
if (args.includes('--json')) {
|
|
67
|
+
// ⛔ stdout carries JSON and nothing else, so it pipes. Every human-facing
|
|
68
|
+
// line in this command goes to stderr for the same reason.
|
|
69
|
+
process.stdout.write(
|
|
70
|
+
JSON.stringify(
|
|
71
|
+
{ cliVersion: getCliVersion(), count: entries.length, templates: entries },
|
|
72
|
+
null,
|
|
73
|
+
2
|
|
74
|
+
) + '\n'
|
|
75
|
+
)
|
|
76
|
+
return
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
if (entries.length === 0) {
|
|
80
|
+
// Not a crash: a CLI whose snapshot failed to load falls back to an empty
|
|
81
|
+
// map, and `create` then routes every name to npm. Say which happened.
|
|
82
|
+
console.error(
|
|
83
|
+
`${colors.red}✗${colors.reset} No official templates found in this CLI's bundled index.`
|
|
84
|
+
)
|
|
85
|
+
console.error(
|
|
86
|
+
` ${colors.dim}A template name will still resolve through npm as @uniweb/template-<name>.${colors.reset}`
|
|
87
|
+
)
|
|
88
|
+
process.exit(1)
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const width = Math.max(...entries.map((e) => e.id.length))
|
|
92
|
+
console.log('')
|
|
93
|
+
console.log(
|
|
94
|
+
`${colors.bright}Official templates${colors.reset} ${colors.dim}(uniweb ${getCliVersion()})${colors.reset}`
|
|
95
|
+
)
|
|
96
|
+
console.log('')
|
|
97
|
+
for (const e of entries) {
|
|
98
|
+
console.log(
|
|
99
|
+
` ${colors.cyan}${e.id.padEnd(width)}${colors.reset} ${e.description || e.name}`
|
|
100
|
+
)
|
|
101
|
+
}
|
|
102
|
+
console.log('')
|
|
103
|
+
console.log(
|
|
104
|
+
` ${colors.dim}uniweb create <project> --template <name>${colors.reset}`
|
|
105
|
+
)
|
|
106
|
+
console.log(
|
|
107
|
+
` ${colors.dim}--json for scripts. This is the roster THIS CLI ships with, not a live fetch.${colors.reset}`
|
|
108
|
+
)
|
|
109
|
+
console.log('')
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export async function template(args = []) {
|
|
113
|
+
const sub = args.find((a) => !a.startsWith('-'))
|
|
114
|
+
if (sub === 'list') return listTemplates(args)
|
|
115
|
+
return reserved()
|
|
116
|
+
}
|
|
117
|
+
|
|
30
118
|
export default template
|
package/src/framework-index.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": 1,
|
|
3
|
-
"generatedAt": "2026-09-
|
|
3
|
+
"generatedAt": "2026-09-09T22:45:28.403Z",
|
|
4
4
|
"packages": {
|
|
5
5
|
"@uniweb/api": {
|
|
6
6
|
"version": "0.2.13",
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
]
|
|
11
11
|
},
|
|
12
12
|
"@uniweb/build": {
|
|
13
|
-
"version": "0.44.
|
|
13
|
+
"version": "0.44.1",
|
|
14
14
|
"path": "framework/build",
|
|
15
15
|
"deps": [
|
|
16
16
|
"@uniweb/content-reader",
|
|
@@ -120,7 +120,7 @@
|
|
|
120
120
|
"deps": []
|
|
121
121
|
},
|
|
122
122
|
"@uniweb/unipress": {
|
|
123
|
-
"version": "0.9.
|
|
123
|
+
"version": "0.9.12",
|
|
124
124
|
"path": "framework/unipress",
|
|
125
125
|
"deps": [
|
|
126
126
|
"@uniweb/build",
|
package/src/index.js
CHANGED
|
@@ -55,6 +55,7 @@ import {
|
|
|
55
55
|
} from './utils/scaffold.js'
|
|
56
56
|
import {
|
|
57
57
|
detectPackageManager,
|
|
58
|
+
detectWorkspacePm,
|
|
58
59
|
filterCmd,
|
|
59
60
|
installCmd,
|
|
60
61
|
runCmd,
|
|
@@ -224,32 +225,98 @@ function delegateToLocal(localCliPath) {
|
|
|
224
225
|
}
|
|
225
226
|
|
|
226
227
|
/**
|
|
227
|
-
* Import a command module that may depend on @uniweb
|
|
228
|
-
*
|
|
229
|
-
*
|
|
230
|
-
*
|
|
228
|
+
* Import a command module that may depend on an optional @uniweb/* peer
|
|
229
|
+
* (`@uniweb/build` above all). Sixteen commands load through here, so this
|
|
230
|
+
* is the error most users meet when something is not installed.
|
|
231
|
+
*
|
|
232
|
+
* ⛔ IT MUST NOT NAME A CAUSE IT HAS NOT CHECKED. This said "This command
|
|
233
|
+
* must be run from inside a Uniweb project" for every `ERR_MODULE_NOT_FOUND`
|
|
234
|
+
* on a `@uniweb/*` specifier — a guess, and wrong in the two cases that do
|
|
235
|
+
* not involve your location at all: a workspace whose dependencies are simply
|
|
236
|
+
* not installed, and a CLI installed on its own (the optional peers are not
|
|
237
|
+
* installed with it, so `npm install uniweb --prefix X` yields exactly this).
|
|
238
|
+
* Project resolution is cwd-based (`findWorkspaceRoot`) and always was, so
|
|
239
|
+
* the check the message needed was one call away and already imported here.
|
|
240
|
+
*
|
|
241
|
+
* ⚠️ A wrong cause is worse than a vague one: it does not merely fail to
|
|
242
|
+
* explain, it DIRECTS the investigation. Reported 2026-09-09 by a consumer
|
|
243
|
+
* who lost an hour testing the cause this text named, having already done
|
|
244
|
+
* the `cd` and the install it advised.
|
|
231
245
|
*/
|
|
232
246
|
async function importProjectCommand(modulePath) {
|
|
233
247
|
try {
|
|
234
248
|
return await import(modulePath)
|
|
235
249
|
} catch (err) {
|
|
236
250
|
if (
|
|
237
|
-
err.code
|
|
238
|
-
err.message?.includes('@uniweb/')
|
|
251
|
+
err.code !== 'ERR_MODULE_NOT_FOUND' ||
|
|
252
|
+
!err.message?.includes('@uniweb/')
|
|
239
253
|
) {
|
|
240
|
-
|
|
254
|
+
throw err
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
// Name the package that actually failed to resolve, rather than making
|
|
258
|
+
// the reader guess which of the optional peers this command needed.
|
|
259
|
+
const missing =
|
|
260
|
+
err.message.match(/'(@uniweb\/[^']+)'/)?.[1] ?? 'a @uniweb/* package'
|
|
261
|
+
const root = findWorkspaceRoot(process.cwd())
|
|
262
|
+
|
|
263
|
+
// ⛔ THREE STATES, and the second and third look identical from here — the
|
|
264
|
+
// import failed either way. Discriminate on what is ON DISK, because
|
|
265
|
+
// "declared but not installed" and "installed but not reachable from where
|
|
266
|
+
// THIS CLI lives" have opposite remedies, and telling a fully-installed
|
|
267
|
+
// workspace to run its installer is the same wrong-cause defect again.
|
|
268
|
+
const workspaceModules = root ? join(root, 'node_modules') : null
|
|
269
|
+
const workspaceInstalled = !!workspaceModules && existsSync(workspaceModules)
|
|
270
|
+
const localCli = root ? join(workspaceModules, '.bin', 'uniweb') : null
|
|
271
|
+
|
|
272
|
+
error(`Cannot load ${missing}, which this command needs.`)
|
|
273
|
+
log('')
|
|
274
|
+
|
|
275
|
+
if (!root) {
|
|
276
|
+
log(
|
|
277
|
+
`No Uniweb workspace found above ${colors.dim}${process.cwd()}${colors.reset}.`
|
|
278
|
+
)
|
|
279
|
+
log(` ${colors.cyan}cd${colors.reset} into a project, or create one:`)
|
|
280
|
+
log(` ${colors.cyan}uniweb create my-project${colors.reset}`)
|
|
241
281
|
log('')
|
|
242
282
|
log(
|
|
243
|
-
|
|
283
|
+
`${colors.dim}Driving projects from a standalone CLI? ${missing} is an optional${colors.reset}`
|
|
284
|
+
)
|
|
285
|
+
log(
|
|
286
|
+
`${colors.dim}peer, so a bare \`npm i uniweb\` does not bring it:${colors.reset}`
|
|
244
287
|
)
|
|
245
|
-
log(` ${colors.cyan}
|
|
246
|
-
|
|
288
|
+
log(` ${colors.cyan}npm install uniweb ${missing}${colors.reset}`)
|
|
289
|
+
} else if (!workspaceInstalled) {
|
|
290
|
+
// Declared, not on disk. Prefer the workspace's own package manager,
|
|
291
|
+
// read off its lockfile — but a workspace that has NEVER been installed
|
|
292
|
+
// has no lockfile to read, so fall back the same way `create` does
|
|
293
|
+
// rather than to whichever PM happens to be running this process.
|
|
294
|
+
const pm =
|
|
295
|
+
detectWorkspacePm(root) ||
|
|
296
|
+
(isPnpmAvailable() ? 'pnpm' : detectPackageManager())
|
|
297
|
+
log(`Uniweb workspace: ${colors.dim}${root}${colors.reset}`)
|
|
298
|
+
log(`Its dependencies are not installed:`)
|
|
299
|
+
log(` ${colors.cyan}${installCmd(pm)}${colors.reset}`)
|
|
300
|
+
} else {
|
|
301
|
+
// Installed, and still unreachable: Node resolves a command's imports
|
|
302
|
+
// from the CLI's own location, so a CLI installed elsewhere cannot see
|
|
303
|
+
// this workspace's copy. Both remedies are real; the local bin is the
|
|
304
|
+
// one that guarantees the project's own pinned toolchain does the work.
|
|
305
|
+
log(
|
|
306
|
+
`Uniweb workspace: ${colors.dim}${root}${colors.reset} ${colors.dim}(dependencies are installed)${colors.reset}`
|
|
307
|
+
)
|
|
308
|
+
log(
|
|
309
|
+
`This CLI resolves its imports from its own install location, not from`
|
|
310
|
+
)
|
|
311
|
+
log(`the workspace, so it cannot see the workspace's ${missing}.`)
|
|
247
312
|
log('')
|
|
248
|
-
log(`
|
|
249
|
-
log(` ${colors.cyan}
|
|
250
|
-
|
|
313
|
+
log(`Use the project's own CLI:`)
|
|
314
|
+
log(` ${colors.cyan}${localCli}${colors.reset}`)
|
|
315
|
+
log(`or install the peer next to this one:`)
|
|
316
|
+
log(` ${colors.cyan}npm install uniweb ${missing}${colors.reset}`)
|
|
251
317
|
}
|
|
252
|
-
|
|
318
|
+
|
|
319
|
+
process.exit(1)
|
|
253
320
|
}
|
|
254
321
|
}
|
|
255
322
|
|
|
@@ -1640,11 +1707,26 @@ The site-handoff flow was retired with the legacy backend.
|
|
|
1640
1707
|
Manage client sites from the Uniweb app for now.
|
|
1641
1708
|
`,
|
|
1642
1709
|
template: `
|
|
1643
|
-
${colors.cyan}${colors.bright}uniweb template${colors.reset} ${colors.dim}—
|
|
1710
|
+
${colors.cyan}${colors.bright}uniweb template${colors.reset} ${colors.dim}— Official templates${colors.reset}
|
|
1644
1711
|
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1712
|
+
${colors.bright}Usage:${colors.reset}
|
|
1713
|
+
uniweb template list List the official templates
|
|
1714
|
+
uniweb template list --json Same, machine-readable (for scripts)
|
|
1715
|
+
|
|
1716
|
+
${colors.bright}What \`list\` reports:${colors.reset}
|
|
1717
|
+
The roster ${colors.bright}this CLI ships with${colors.reset} — a snapshot baked in at publish time,
|
|
1718
|
+
not a live fetch. That is the right question when the next step is resolving
|
|
1719
|
+
one of those names with the same CLI, which is why \`--json\` stamps
|
|
1720
|
+
\`cliVersion\`. A template newer than your CLI will not be listed.
|
|
1721
|
+
|
|
1722
|
+
It is the ${colors.bright}official${colors.reset} roster, not the set of resolvable names: an unknown
|
|
1723
|
+
name is not fatal, since \`create\` falls through to npm \`@uniweb/template-<name>\`.
|
|
1724
|
+
|
|
1725
|
+
${colors.bright}Reserved:${colors.reset}
|
|
1726
|
+
\`uniweb template register\` is not available on the new backend yet. Submitting
|
|
1727
|
+
a site as a cloud template was retired with the legacy backend; when rebuilt, a
|
|
1728
|
+
template is REGISTERED (like a foundation) — \`publish\` is for sites only.
|
|
1729
|
+
Scaffolding FROM a template is unaffected: \`uniweb create --template <name>\`.
|
|
1648
1730
|
`,
|
|
1649
1731
|
docs: `
|
|
1650
1732
|
${colors.cyan}${colors.bright}uniweb docs${colors.reset} ${colors.dim}— Generate component documentation${colors.reset}
|