uniweb 0.13.17 → 0.14.0

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.
Files changed (65) hide show
  1. package/README.md +1 -1
  2. package/package.json +7 -7
  3. package/partials/agents.md +51 -0
  4. package/src/backend/client.js +173 -40
  5. package/src/backend/data-bundle.js +15 -3
  6. package/src/backend/foundation-bring-along.js +76 -21
  7. package/src/backend/payment-handoff.js +28 -9
  8. package/src/backend/site-media.js +147 -19
  9. package/src/backend/site-sync.js +362 -40
  10. package/src/commands/add.js +575 -273
  11. package/src/commands/build.js +160 -57
  12. package/src/commands/clone.js +79 -26
  13. package/src/commands/content.js +11 -7
  14. package/src/commands/deploy.js +80 -32
  15. package/src/commands/dev.js +39 -17
  16. package/src/commands/docs.js +44 -16
  17. package/src/commands/doctor.js +338 -82
  18. package/src/commands/export.js +15 -7
  19. package/src/commands/handoff.js +6 -2
  20. package/src/commands/i18n.js +248 -99
  21. package/src/commands/inspect.js +48 -19
  22. package/src/commands/invite.js +9 -3
  23. package/src/commands/org.js +19 -5
  24. package/src/commands/publish.js +229 -60
  25. package/src/commands/pull.js +157 -48
  26. package/src/commands/push.js +144 -42
  27. package/src/commands/refresh.js +37 -10
  28. package/src/commands/register.js +235 -64
  29. package/src/commands/rename.js +126 -46
  30. package/src/commands/runtime.js +74 -24
  31. package/src/commands/status.js +48 -15
  32. package/src/commands/sync.js +7 -2
  33. package/src/commands/template.js +12 -4
  34. package/src/commands/update.js +263 -87
  35. package/src/commands/validate.js +115 -32
  36. package/src/framework-index.json +15 -13
  37. package/src/index.js +298 -145
  38. package/src/templates/fetchers/github.js +7 -7
  39. package/src/templates/fetchers/npm.js +3 -3
  40. package/src/templates/fetchers/release.js +21 -18
  41. package/src/templates/index.js +34 -12
  42. package/src/templates/processor.js +44 -12
  43. package/src/templates/resolver.js +42 -15
  44. package/src/templates/validator.js +14 -7
  45. package/src/utils/asset-upload.js +90 -22
  46. package/src/utils/code-upload.js +62 -37
  47. package/src/utils/config.js +31 -10
  48. package/src/utils/dep-survey.js +33 -7
  49. package/src/utils/destination-prompt.js +27 -17
  50. package/src/utils/git.js +66 -22
  51. package/src/utils/host-prompt.js +4 -3
  52. package/src/utils/install-integrity.js +8 -4
  53. package/src/utils/interactive.js +3 -3
  54. package/src/utils/json-file.js +6 -2
  55. package/src/utils/names.js +15 -6
  56. package/src/utils/placement.js +16 -8
  57. package/src/utils/registry-auth.js +185 -57
  58. package/src/utils/registry-orgs.js +142 -53
  59. package/src/utils/runtime-upload.js +52 -14
  60. package/src/utils/scaffold.js +55 -14
  61. package/src/utils/site-content-refs.js +3 -1
  62. package/src/utils/update-check.js +43 -17
  63. package/src/utils/workspace.js +13 -7
  64. package/src/versions.js +18 -7
  65. package/templates/site/_gitignore +5 -0
@@ -28,7 +28,7 @@ const colors = {
28
28
  red: '\x1b[31m',
29
29
  green: '\x1b[32m',
30
30
  yellow: '\x1b[33m',
31
- blue: '\x1b[36m',
31
+ blue: '\x1b[36m'
32
32
  }
33
33
 
34
34
  const log = console.log
@@ -44,7 +44,8 @@ function flagValue(args, name) {
44
44
  const eq = args.find((a) => a.startsWith(`${name}=`))
45
45
  if (eq) return eq.slice(name.length + 1)
46
46
  const idx = args.indexOf(name)
47
- if (idx !== -1 && args[idx + 1] && !args[idx + 1].startsWith('--')) return args[idx + 1]
47
+ if (idx !== -1 && args[idx + 1] && !args[idx + 1].startsWith('--'))
48
+ return args[idx + 1]
48
49
  return null
49
50
  }
50
51
 
@@ -76,19 +77,28 @@ async function validateSite(site, foundations, workspaceDir) {
76
77
  // No local foundation to check against → out of static scope (the schemas
77
78
  // live in the foundation; a registry-ref / URL foundation isn't on disk).
78
79
  if (!foundationName) {
79
- return { site: site.name, status: 'skipped', reason: 'no foundation declared in site.yml (runtime-loaded?)' }
80
+ return {
81
+ site: site.name,
82
+ status: 'skipped',
83
+ reason: 'no foundation declared in site.yml (runtime-loaded?)'
84
+ }
80
85
  }
81
- const match = foundations.find((f) => f.name === foundationName || basename(f.path) === foundationName)
86
+ const match = foundations.find(
87
+ (f) => f.name === foundationName || basename(f.path) === foundationName
88
+ )
82
89
  if (!match) {
83
90
  return {
84
91
  site: site.name,
85
92
  status: 'skipped',
86
- reason: `foundation "${foundationName}" is not a local workspace foundation — its schemas aren't on disk to check against`,
93
+ reason: `foundation "${foundationName}" is not a local workspace foundation — its schemas aren't on disk to check against`
87
94
  }
88
95
  }
89
96
 
90
97
  const foundationPath = join(workspaceDir, match.path)
91
- const report = await validateDataInputs({ siteRoot: sitePath, foundationPath })
98
+ const report = await validateDataInputs({
99
+ siteRoot: sitePath,
100
+ foundationPath
101
+ })
92
102
  return { site: site.name, foundation: match.name, status: 'checked', report }
93
103
  }
94
104
 
@@ -101,7 +111,9 @@ async function validateSite(site, foundations, workspaceDir) {
101
111
  function printSiteHuman(result) {
102
112
  log('')
103
113
  if (result.status === 'skipped') {
104
- warn(`${colors.bright}${result.site}${colors.reset} — skipped: ${result.reason}`)
114
+ warn(
115
+ `${colors.bright}${result.site}${colors.reset} — skipped: ${result.reason}`
116
+ )
105
117
  return
106
118
  }
107
119
 
@@ -110,7 +122,9 @@ function printSiteHuman(result) {
110
122
  const header = `${colors.bright}${result.site}${colors.reset} ${colors.dim}(foundation: ${foundation})${colors.reset}`
111
123
 
112
124
  if (violations.length === 0 && setupErrors.length === 0) {
113
- success(`${header} — ${summary.records} record(s) / ${summary.schemas} schema(s) conform`)
125
+ success(
126
+ `${header} — ${summary.records} record(s) / ${summary.schemas} schema(s) conform`
127
+ )
114
128
  } else {
115
129
  info(header)
116
130
  }
@@ -119,31 +133,51 @@ function printSiteHuman(result) {
119
133
  const groups = new Map()
120
134
  for (const v of violations) {
121
135
  const key = `${v.file} ${v.schema}`
122
- if (!groups.has(key)) groups.set(key, { file: v.file, schema: v.schema, users: v.users, findings: [] })
136
+ if (!groups.has(key))
137
+ groups.set(key, {
138
+ file: v.file,
139
+ schema: v.schema,
140
+ users: v.users,
141
+ findings: []
142
+ })
123
143
  groups.get(key).findings.push(v)
124
144
  }
125
145
  for (const g of groups.values()) {
126
- log(` ${colors.red}✗${colors.reset} ${g.file} ${colors.dim}· schema ${g.schema}${colors.reset}`)
146
+ log(
147
+ ` ${colors.red}✗${colors.reset} ${g.file} ${colors.dim}· schema ${g.schema}${colors.reset}`
148
+ )
127
149
  for (const u of dedupeUsers(g.users)) {
128
- log(` ${colors.dim}used by${colors.reset} ${u.route} › ${u.section} › data.${u.key}`)
150
+ log(
151
+ ` ${colors.dim}used by${colors.reset} ${u.route} › ${u.section} › data.${u.key}`
152
+ )
129
153
  }
130
154
  for (const f of g.findings) {
131
- log(` ${colors.yellow}•${colors.reset} item ${colors.bright}"${f.item}"${colors.reset} › ${f.field} — ${f.message}`)
155
+ log(
156
+ ` ${colors.yellow}•${colors.reset} item ${colors.bright}"${f.item}"${colors.reset} › ${f.field} — ${f.message}`
157
+ )
132
158
  }
133
159
  }
134
160
 
135
161
  for (const e of setupErrors) {
136
162
  log(` ${colors.red}✗${colors.reset} ${e.file} — ${e.message}`)
137
163
  for (const u of dedupeUsers(e.users)) {
138
- log(` ${colors.dim}used by${colors.reset} ${u.route} › ${u.section} › data.${u.key}`)
164
+ log(
165
+ ` ${colors.dim}used by${colors.reset} ${u.route} › ${u.section} › data.${u.key}`
166
+ )
139
167
  }
140
168
  }
141
169
 
142
170
  if (deferred.length > 0) {
143
171
  log(` ${colors.dim}↪ deferred (not statically checkable):${colors.reset}`)
144
172
  for (const d of deferred) {
145
- const extra = d.url ? ` ${colors.dim}(${d.url})${colors.reset}` : d.ref ? ` ${colors.dim}(${d.ref})${colors.reset}` : ''
146
- log(` ${colors.dim}•${colors.reset} ${d.route}${d.section} › data.${d.key} — ${d.reason}${extra}`)
173
+ const extra = d.url
174
+ ? ` ${colors.dim}(${d.url})${colors.reset}`
175
+ : d.ref
176
+ ? ` ${colors.dim}(${d.ref})${colors.reset}`
177
+ : ''
178
+ log(
179
+ ` ${colors.dim}•${colors.reset} ${d.route} › ${d.section} › data.${d.key} — ${d.reason}${extra}`
180
+ )
147
181
  }
148
182
  }
149
183
 
@@ -169,27 +203,55 @@ export async function validate(args = []) {
169
203
  const asJson = args.includes('--json')
170
204
  const strict = args.includes('--strict')
171
205
  const siteFilter = flagValue(args, '--site')
172
- const positional = args.find((a, i) => !a.startsWith('--') && args[i - 1] !== '--site')
206
+ const positional = args.find(
207
+ (a, i) => !a.startsWith('--') && args[i - 1] !== '--site'
208
+ )
173
209
 
174
210
  const target = positional ? resolve(process.cwd(), positional) : process.cwd()
175
211
  const workspaceDir = findWorkspaceRoot(target)
176
212
 
177
213
  if (!workspaceDir) {
178
- if (asJson) log(JSON.stringify({ ok: false, error: 'not in a Uniweb workspace' }, null, 2))
179
- else error('Not in a Uniweb workspace. Run this from a project root or a site directory.')
214
+ if (asJson)
215
+ log(
216
+ JSON.stringify(
217
+ { ok: false, error: 'not in a Uniweb workspace' },
218
+ null,
219
+ 2
220
+ )
221
+ )
222
+ else
223
+ error(
224
+ 'Not in a Uniweb workspace. Run this from a project root or a site directory.'
225
+ )
180
226
  return { exitCode: 2 }
181
227
  }
182
228
 
183
- const [sites, foundations] = await Promise.all([discoverSites(workspaceDir), discoverFoundations(workspaceDir)])
229
+ const [sites, foundations] = await Promise.all([
230
+ discoverSites(workspaceDir),
231
+ discoverFoundations(workspaceDir)
232
+ ])
184
233
 
185
234
  // Select which sites to check: --site filter, an explicitly targeted site
186
235
  // directory, or all sites in the workspace.
187
236
  let selected = sites
188
237
  if (siteFilter) {
189
- selected = sites.filter((s) => s.name === siteFilter || basename(s.path) === siteFilter)
238
+ selected = sites.filter(
239
+ (s) => s.name === siteFilter || basename(s.path) === siteFilter
240
+ )
190
241
  if (selected.length === 0) {
191
242
  const names = sites.map((s) => s.name).join(', ') || '(none)'
192
- if (asJson) log(JSON.stringify({ ok: false, error: `site "${siteFilter}" not found`, sites: sites.map((s) => s.name) }, null, 2))
243
+ if (asJson)
244
+ log(
245
+ JSON.stringify(
246
+ {
247
+ ok: false,
248
+ error: `site "${siteFilter}" not found`,
249
+ sites: sites.map((s) => s.name)
250
+ },
251
+ null,
252
+ 2
253
+ )
254
+ )
193
255
  else error(`Site "${siteFilter}" not found. Available: ${names}`)
194
256
  return { exitCode: 2 }
195
257
  }
@@ -199,7 +261,10 @@ export async function validate(args = []) {
199
261
  }
200
262
 
201
263
  if (selected.length === 0) {
202
- if (asJson) log(JSON.stringify({ ok: true, sites: [], note: 'no sites found' }, null, 2))
264
+ if (asJson)
265
+ log(
266
+ JSON.stringify({ ok: true, sites: [], note: 'no sites found' }, null, 2)
267
+ )
203
268
  else warn('No sites found in this workspace.')
204
269
  return { exitCode: 0 }
205
270
  }
@@ -223,8 +288,14 @@ export async function validate(args = []) {
223
288
  console.log = origConsoleLog
224
289
  }
225
290
 
226
- const totalViolations = results.reduce((n, r) => n + (r.report?.violations.length || 0), 0)
227
- const totalSetupErrors = results.reduce((n, r) => n + (r.report?.setupErrors.length || 0), 0)
291
+ const totalViolations = results.reduce(
292
+ (n, r) => n + (r.report?.violations.length || 0),
293
+ 0
294
+ )
295
+ const totalSetupErrors = results.reduce(
296
+ (n, r) => n + (r.report?.setupErrors.length || 0),
297
+ 0
298
+ )
228
299
  const hadError = results.some((r) => r.status === 'error')
229
300
 
230
301
  if (asJson) {
@@ -236,24 +307,31 @@ export async function validate(args = []) {
236
307
  foundation: r.foundation || null,
237
308
  status: r.status,
238
309
  reason: r.reason || null,
239
- ...(r.report || {}),
310
+ ...(r.report || {})
240
311
  })),
241
312
  summary: {
242
313
  sites: results.length,
243
314
  violations: totalViolations,
244
315
  setupErrors: totalSetupErrors,
245
- deferred: results.reduce((n, r) => n + (r.report?.deferred.length || 0), 0),
246
- },
316
+ deferred: results.reduce(
317
+ (n, r) => n + (r.report?.deferred.length || 0),
318
+ 0
319
+ )
320
+ }
247
321
  }
248
322
  log(JSON.stringify(payload, null, 2))
249
323
  } else {
250
324
  log('')
251
325
  log(`${colors.blue}${colors.bright}Uniweb Validate${colors.reset}`)
252
- log(`${colors.dim}Checking content against the data schemas your foundation declares…${colors.reset}`)
326
+ log(
327
+ `${colors.dim}Checking content against the data schemas your foundation declares…${colors.reset}`
328
+ )
253
329
  for (const r of results) {
254
330
  if (r.status === 'error') {
255
331
  log('')
256
- error(`${colors.bright}${r.site}${colors.reset} — could not check: ${r.reason}`)
332
+ error(
333
+ `${colors.bright}${r.site}${colors.reset} — could not check: ${r.reason}`
334
+ )
257
335
  } else {
258
336
  printSiteHuman(r)
259
337
  }
@@ -271,10 +349,15 @@ export async function validate(args = []) {
271
349
  } else {
272
350
  log('')
273
351
  if (totalViolations > 0) {
274
- const mode = strict ? `${colors.red}error${colors.reset}` : `${colors.yellow}warning${colors.reset}`
275
- log(`${totalViolations} violation(s) — reported as ${mode}${strict ? '' : ` ${colors.dim}(pass --strict to fail CI)${colors.reset}`}`)
352
+ const mode = strict
353
+ ? `${colors.red}error${colors.reset}`
354
+ : `${colors.yellow}warning${colors.reset}`
355
+ log(
356
+ `${totalViolations} violation(s) — reported as ${mode}${strict ? '' : ` ${colors.dim}(pass --strict to fail CI)${colors.reset}`}`
357
+ )
276
358
  }
277
- if (hadError) log(`${colors.red}Some sites could not be checked.${colors.reset}`)
359
+ if (hadError)
360
+ log(`${colors.red}Some sites could not be checked.${colors.reset}`)
278
361
  log('')
279
362
  }
280
363
  }
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
- "generatedAt": "2026-07-28T17:39:41.218Z",
3
+ "generatedAt": "2026-07-30T18:57:10.510Z",
4
4
  "packages": {
5
5
  "@uniweb/build": {
6
- "version": "0.15.14",
6
+ "version": "0.16.0",
7
7
  "path": "framework/build",
8
8
  "deps": [
9
9
  "@uniweb/content-reader",
@@ -12,21 +12,22 @@
12
12
  "@uniweb/projections",
13
13
  "@uniweb/runtime",
14
14
  "@uniweb/schemas",
15
+ "@uniweb/semantic-parser",
15
16
  "@uniweb/theming"
16
17
  ]
17
18
  },
18
19
  "@uniweb/content-reader": {
19
- "version": "1.1.19",
20
+ "version": "1.2.0",
20
21
  "path": "framework/content-reader",
21
22
  "deps": []
22
23
  },
23
24
  "@uniweb/content-writer": {
24
- "version": "0.2.9",
25
+ "version": "0.3.0",
25
26
  "path": "framework/content-writer",
26
27
  "deps": []
27
28
  },
28
29
  "@uniweb/core": {
29
- "version": "0.7.34",
30
+ "version": "0.8.0",
30
31
  "path": "framework/core",
31
32
  "deps": [
32
33
  "@uniweb/semantic-parser",
@@ -39,16 +40,17 @@
39
40
  "deps": []
40
41
  },
41
42
  "@uniweb/icons": {
42
- "version": "0.1.0",
43
+ "version": "0.4.0",
43
44
  "path": "framework/icons",
44
45
  "deps": []
45
46
  },
46
47
  "@uniweb/kit": {
47
- "version": "0.9.46",
48
+ "version": "0.10.0",
48
49
  "path": "framework/kit",
49
50
  "deps": [
50
51
  "@uniweb/core",
51
- "@uniweb/scene"
52
+ "@uniweb/scene",
53
+ "@uniweb/semantic-parser"
52
54
  ]
53
55
  },
54
56
  "@uniweb/loom": {
@@ -62,7 +64,7 @@
62
64
  "deps": []
63
65
  },
64
66
  "@uniweb/projections": {
65
- "version": "0.1.6",
67
+ "version": "0.2.0",
66
68
  "path": "framework/projections",
67
69
  "deps": [
68
70
  "@uniweb/content-writer",
@@ -70,7 +72,7 @@
70
72
  ]
71
73
  },
72
74
  "@uniweb/runtime": {
73
- "version": "0.8.42",
75
+ "version": "0.9.0",
74
76
  "path": "framework/runtime",
75
77
  "deps": [
76
78
  "@uniweb/core",
@@ -93,12 +95,12 @@
93
95
  "deps": []
94
96
  },
95
97
  "@uniweb/semantic-parser": {
96
- "version": "1.1.21",
98
+ "version": "1.2.0",
97
99
  "path": "framework/semantic-parser",
98
100
  "deps": []
99
101
  },
100
102
  "@uniweb/templates": {
101
- "version": "0.7.45",
103
+ "version": "0.7.46",
102
104
  "path": "framework/templates",
103
105
  "deps": []
104
106
  },
@@ -108,7 +110,7 @@
108
110
  "deps": []
109
111
  },
110
112
  "@uniweb/unipress": {
111
- "version": "0.5.13",
113
+ "version": "0.5.14",
112
114
  "path": "framework/unipress",
113
115
  "deps": [
114
116
  "@uniweb/build",