uniweb 1.8.1 → 1.9.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.
- package/README.md +1 -1
- package/package.json +8 -8
- package/partials/agents.md +0 -2
- package/src/backend/client.js +1 -1
- package/src/commands/pull.js +13 -3
- package/src/commands/refresh.js +9 -3
- package/src/framework-index.json +10 -10
- package/src/index.js +0 -26
- package/src/utils/install-integrity.js +3 -3
- package/src/utils/sync-point.js +15 -0
- package/src/commands/handoff.js +0 -21
- package/src/commands/invite.js +0 -24
package/README.md
CHANGED
|
@@ -334,7 +334,7 @@ cd src
|
|
|
334
334
|
uniweb register --scope @your-org
|
|
335
335
|
```
|
|
336
336
|
|
|
337
|
-
Real sites built on your foundation are managed in the **Uniweb
|
|
337
|
+
Real sites built on your foundation are managed in the **Uniweb app** — a visual editor designed for non-technical authors. They never see git, markdown, yaml, or React. They see *your* components, with live previews and visual controls for the params you defined. The foundation becomes the editor's native vocabulary for that site: you keep creative control of the design system, they get an editor that feels custom-built for them.
|
|
338
338
|
|
|
339
339
|
This is the best path when site content has a life independent of the foundation's release cycle — agencies, design studios, multi-client teams, or any project where content authors aren't the same people as the developers.
|
|
340
340
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "uniweb",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.9.0",
|
|
4
4
|
"description": "Create structured Vite + React sites with content/code separation",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -41,15 +41,15 @@
|
|
|
41
41
|
"js-yaml": "^4.1.0",
|
|
42
42
|
"prompts": "^2.4.2",
|
|
43
43
|
"tar": "^7.0.0",
|
|
44
|
-
"@uniweb/
|
|
45
|
-
"@uniweb/
|
|
46
|
-
"@uniweb/
|
|
47
|
-
"@uniweb/
|
|
44
|
+
"@uniweb/core": "~1.2.3",
|
|
45
|
+
"@uniweb/semantic-parser": "~1.9.0",
|
|
46
|
+
"@uniweb/schemas": "~1.4.0",
|
|
47
|
+
"@uniweb/content-writer": "~1.2.0"
|
|
48
48
|
},
|
|
49
49
|
"peerDependencies": {
|
|
50
|
-
"@uniweb/build": "~1.3.
|
|
51
|
-
"@uniweb/
|
|
52
|
-
"@uniweb/
|
|
50
|
+
"@uniweb/build": "~1.3.11",
|
|
51
|
+
"@uniweb/semantic-parser": "~1.9.0",
|
|
52
|
+
"@uniweb/content-reader": "~1.4.1"
|
|
53
53
|
},
|
|
54
54
|
"peerDependenciesMeta": {
|
|
55
55
|
"@uniweb/build": {
|
package/partials/agents.md
CHANGED
|
@@ -2796,8 +2796,6 @@ uniweb snapshot --compare # Several looks on one sheet; take one with it
|
|
|
2796
2796
|
uniweb <command> --help # Per-command flags — no side effects. Prefer this over guessing.
|
|
2797
2797
|
```
|
|
2798
2798
|
|
|
2799
|
-
**Three verbs dispatch but are deliberately not listed above.** `invite`, `handoff` and `template` are **reserved names with no implementation** — the flows they named ran against a backend the CLI no longer talks to, and the names are held so a future rebuild doesn't need a breaking change. Running any of them is not useful; their absence from this list is the answer, not an omission to fix.
|
|
2800
|
-
|
|
2801
2799
|
### Where a site can live
|
|
2802
2800
|
|
|
2803
2801
|
**There is no lock-in, and no default you're pushed toward.** Four independent paths, and a project can change its mind:
|
package/src/backend/client.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* BackendClient — the single front door to the Uniweb backend.
|
|
3
3
|
*
|
|
4
4
|
* Every CLI verb that talks to the backend (register, push, pull, clone, org,
|
|
5
|
-
* login — and, as the consolidation proceeds, publish/deploy
|
|
5
|
+
* login — and, as the consolidation proceeds, publish/deploy)
|
|
6
6
|
* goes through one instance of this client instead of hand-rolling
|
|
7
7
|
* `fetch(… Authorization: Bearer …)` against a per-command default origin. It
|
|
8
8
|
* owns the three things that were previously scattered across a dozen files:
|
package/src/commands/pull.js
CHANGED
|
@@ -111,6 +111,7 @@ import {
|
|
|
111
111
|
repoOf,
|
|
112
112
|
mergeInProgress,
|
|
113
113
|
unmergedPaths,
|
|
114
|
+
ignoringRepo,
|
|
114
115
|
isAncestor,
|
|
115
116
|
historySyncPoint,
|
|
116
117
|
madeOnto,
|
|
@@ -485,8 +486,15 @@ async function checkWorkingTree(siteDir, args) {
|
|
|
485
486
|
const roots = siteContentRoots(siteDir)
|
|
486
487
|
const written = readWritten(siteDir)
|
|
487
488
|
if (filesUnder(siteDir, roots).every((f) => isPullOutput(siteDir, f, written))) return null
|
|
489
|
+
// A folder the repository around it ignores is outside git too — said as such, since a
|
|
490
|
+
// repository is right there and "not in a repository" is not what the person sees.
|
|
491
|
+
const ignoredBy = ignoringRepo(siteDir)
|
|
488
492
|
if (isNonInteractive(args)) {
|
|
489
|
-
error(
|
|
493
|
+
error(
|
|
494
|
+
ignoredBy
|
|
495
|
+
? 'Refusing to pull: this site is in a folder the repository around it ignores, so no repository holds it.'
|
|
496
|
+
: 'Refusing to pull: this site is not in a git repository.'
|
|
497
|
+
)
|
|
490
498
|
note(
|
|
491
499
|
'Pull rewrites pages, sections and layout from the backend and deletes what it no longer has.'
|
|
492
500
|
)
|
|
@@ -494,12 +502,14 @@ async function checkWorkingTree(siteDir, args) {
|
|
|
494
502
|
'Without version control there is no way back, and this session cannot ask.'
|
|
495
503
|
)
|
|
496
504
|
note(
|
|
497
|
-
|
|
505
|
+
ignoredBy
|
|
506
|
+
? 'Re-run with --force to accept that, or give the site a repository of its own (`git init`, then commit) — there a pull merges.'
|
|
507
|
+
: 'Re-run with --force to accept that, or put the site under git first — there a pull merges.'
|
|
498
508
|
)
|
|
499
509
|
return { exitCode: 1 }
|
|
500
510
|
}
|
|
501
511
|
const ok = await confirm(
|
|
502
|
-
`Pull will overwrite ${roots.length} content location(s) and
|
|
512
|
+
`Pull will overwrite ${roots.length} content location(s), and no git repository holds this site. Continue?`
|
|
503
513
|
)
|
|
504
514
|
if (!ok) {
|
|
505
515
|
info('Nothing pulled.')
|
package/src/commands/refresh.js
CHANGED
|
@@ -52,6 +52,7 @@ import {
|
|
|
52
52
|
pullRemote,
|
|
53
53
|
headProvenance
|
|
54
54
|
} from '../utils/git.js'
|
|
55
|
+
import { ignoringRepo } from '../utils/sync-point.js'
|
|
55
56
|
import { probeUnpushed } from '../backend/site-sync.js'
|
|
56
57
|
import { resolveBackendOrigin } from '../backend/client.js'
|
|
57
58
|
import { readBackendState } from '@uniweb/build/uwx'
|
|
@@ -124,13 +125,18 @@ export async function refresh(args = [], deps = {}) {
|
|
|
124
125
|
// when they are not.
|
|
125
126
|
const consulted = []
|
|
126
127
|
const skipped = []
|
|
128
|
+
// Said at the end — and before stopping on a failure, which can follow a step skipped.
|
|
129
|
+
const tell = () => {
|
|
130
|
+
if (consulted.length) say.dim(`Checked: ${consulted.join(', ')}`)
|
|
131
|
+
for (const s of skipped) say.dim(`Skipped: ${s}`)
|
|
132
|
+
}
|
|
127
133
|
let conflicts = 0
|
|
128
134
|
|
|
129
135
|
// ── 1. the git remote ─────────────────────────────────────────────────────
|
|
130
136
|
if (skipGit) {
|
|
131
137
|
skipped.push('git (--no-git)')
|
|
132
138
|
} else if (!isGitRepo(siteDir)) {
|
|
133
|
-
skipped.push('git (not a repository)')
|
|
139
|
+
skipped.push(ignoringRepo(siteDir) ? 'git (the repository around this folder ignores it)' : 'git (not a repository)')
|
|
134
140
|
} else if (!hasRemote(siteDir)) {
|
|
135
141
|
skipped.push('git (no remote configured)')
|
|
136
142
|
} else {
|
|
@@ -173,6 +179,7 @@ export async function refresh(args = [], deps = {}) {
|
|
|
173
179
|
// Failed for a reason other than conflicts — say so plainly rather than
|
|
174
180
|
// reporting a clean refresh over a lane that never ran.
|
|
175
181
|
say.err('Could not merge the backend content.')
|
|
182
|
+
tell()
|
|
176
183
|
return { exitCode: res.exitCode }
|
|
177
184
|
}
|
|
178
185
|
consulted.push('backend')
|
|
@@ -180,8 +187,7 @@ export async function refresh(args = [], deps = {}) {
|
|
|
180
187
|
|
|
181
188
|
// ── 3. where that leaves you ──────────────────────────────────────────────
|
|
182
189
|
console.log('')
|
|
183
|
-
|
|
184
|
-
for (const s of skipped) say.dim(`Skipped: ${s}`)
|
|
190
|
+
tell()
|
|
185
191
|
|
|
186
192
|
const git = headProvenance(siteDir)
|
|
187
193
|
if (git)
|
package/src/framework-index.json
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": 1,
|
|
3
|
-
"generatedAt": "2026-10-
|
|
3
|
+
"generatedAt": "2026-10-18T05:12:16.689Z",
|
|
4
4
|
"packages": {
|
|
5
5
|
"@uniweb/api": {
|
|
6
6
|
"version": "1.5.0"
|
|
7
7
|
},
|
|
8
8
|
"@uniweb/build": {
|
|
9
|
-
"version": "1.3.
|
|
9
|
+
"version": "1.3.11"
|
|
10
10
|
},
|
|
11
11
|
"@uniweb/content-reader": {
|
|
12
|
-
"version": "1.4.
|
|
12
|
+
"version": "1.4.1"
|
|
13
13
|
},
|
|
14
14
|
"@uniweb/content-writer": {
|
|
15
|
-
"version": "1.
|
|
15
|
+
"version": "1.2.0"
|
|
16
16
|
},
|
|
17
17
|
"@uniweb/core": {
|
|
18
|
-
"version": "1.2.
|
|
18
|
+
"version": "1.2.3"
|
|
19
19
|
},
|
|
20
20
|
"@uniweb/frame-bridge": {
|
|
21
21
|
"version": "1.0.2"
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
"version": "1.0.3"
|
|
25
25
|
},
|
|
26
26
|
"@uniweb/kit": {
|
|
27
|
-
"version": "1.
|
|
27
|
+
"version": "1.3.0"
|
|
28
28
|
},
|
|
29
29
|
"@uniweb/loom": {
|
|
30
30
|
"version": "1.1.0"
|
|
@@ -33,10 +33,10 @@
|
|
|
33
33
|
"version": "1.1.1"
|
|
34
34
|
},
|
|
35
35
|
"@uniweb/projections": {
|
|
36
|
-
"version": "1.1.
|
|
36
|
+
"version": "1.1.2"
|
|
37
37
|
},
|
|
38
38
|
"@uniweb/runtime": {
|
|
39
|
-
"version": "1.1.
|
|
39
|
+
"version": "1.1.5"
|
|
40
40
|
},
|
|
41
41
|
"@uniweb/scene": {
|
|
42
42
|
"version": "1.0.1"
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
"version": "1.1.0"
|
|
49
49
|
},
|
|
50
50
|
"@uniweb/semantic-parser": {
|
|
51
|
-
"version": "1.
|
|
51
|
+
"version": "1.9.0"
|
|
52
52
|
},
|
|
53
53
|
"@uniweb/snapshot": {
|
|
54
54
|
"version": "1.1.0"
|
|
@@ -60,7 +60,7 @@
|
|
|
60
60
|
"version": "1.2.0"
|
|
61
61
|
},
|
|
62
62
|
"@uniweb/unipress": {
|
|
63
|
-
"version": "1.1.
|
|
63
|
+
"version": "1.1.6"
|
|
64
64
|
}
|
|
65
65
|
},
|
|
66
66
|
"templates": {
|
package/src/index.js
CHANGED
|
@@ -33,8 +33,6 @@ import prompts from 'prompts'
|
|
|
33
33
|
// Same pattern as `build` and `docs`.
|
|
34
34
|
import { i18n } from './commands/i18n.js'
|
|
35
35
|
import { inspect } from './commands/inspect.js'
|
|
36
|
-
import { invite } from './commands/invite.js'
|
|
37
|
-
import { handoff } from './commands/handoff.js'
|
|
38
36
|
import { update } from './commands/update.js'
|
|
39
37
|
import { clone } from './commands/clone.js'
|
|
40
38
|
import { template } from './commands/template.js'
|
|
@@ -1010,18 +1008,6 @@ async function main() {
|
|
|
1010
1008
|
return
|
|
1011
1009
|
}
|
|
1012
1010
|
|
|
1013
|
-
// Handle invite command
|
|
1014
|
-
if (command === 'invite') {
|
|
1015
|
-
await invite(args.slice(1))
|
|
1016
|
-
return
|
|
1017
|
-
}
|
|
1018
|
-
|
|
1019
|
-
// Handle handoff command
|
|
1020
|
-
if (command === 'handoff') {
|
|
1021
|
-
await handoff(args.slice(1))
|
|
1022
|
-
return
|
|
1023
|
-
}
|
|
1024
|
-
|
|
1025
1011
|
// Handle families command — the standard section families this CLI ships with
|
|
1026
1012
|
if (command === 'families') {
|
|
1027
1013
|
const { families } = await import('./commands/families.js')
|
|
@@ -1926,18 +1912,6 @@ Record files keep their \`$uuid\`: it is the record's own id, not a backend's.
|
|
|
1926
1912
|
|
|
1927
1913
|
To duplicate a project:
|
|
1928
1914
|
cp -r my-site my-site-2 && cd my-site-2 && uniweb forget --all
|
|
1929
|
-
`,
|
|
1930
|
-
invite: `
|
|
1931
|
-
${colors.cyan}${colors.bright}uniweb invite${colors.reset} ${colors.dim}— (reserved; not available on the new backend yet)${colors.reset}
|
|
1932
|
-
|
|
1933
|
-
The foundation client-invite flow was retired with the legacy backend.
|
|
1934
|
-
Invite clients to your foundation from the Uniweb app for now.
|
|
1935
|
-
`,
|
|
1936
|
-
handoff: `
|
|
1937
|
-
${colors.cyan}${colors.bright}uniweb handoff${colors.reset} ${colors.dim}— (reserved; not available on the new backend yet)${colors.reset}
|
|
1938
|
-
|
|
1939
|
-
The site-handoff flow was retired with the legacy backend.
|
|
1940
|
-
Manage client sites from the Uniweb app for now.
|
|
1941
1915
|
`,
|
|
1942
1916
|
families: `
|
|
1943
1917
|
${colors.cyan}${colors.bright}uniweb families${colors.reset} ${colors.dim}— The standard section families${colors.reset}
|
|
@@ -14,9 +14,9 @@
|
|
|
14
14
|
* foundation — `uniweb dev` with `foundation:` naming a sibling package. There,
|
|
15
15
|
* the site imports `#foundation`, which `build/src/site/config.js` aliases to
|
|
16
16
|
* the foundation's PACKAGE NAME, so Vite resolves it through node_modules. A
|
|
17
|
-
* linked site (registry ref or URL) never takes that path, and neither does
|
|
18
|
-
*
|
|
19
|
-
*
|
|
17
|
+
* linked site (registry ref or URL) never takes that path, and neither does
|
|
18
|
+
* unipress or the edge — they load a built `dist/entry.js`, or read a content
|
|
19
|
+
* folder directly. The check stays silent for all of them
|
|
20
20
|
* because there is no node_modules entry to look at.
|
|
21
21
|
*
|
|
22
22
|
* What goes wrong in that one modality: a `file:` dependency can be satisfied
|
package/src/utils/sync-point.js
CHANGED
|
@@ -107,6 +107,21 @@ export function repoOf(siteDir) {
|
|
|
107
107
|
return { top, prefix, path: prefix ? prefix.replace(/\/$/, '') : '.', gitDir, head }
|
|
108
108
|
}
|
|
109
109
|
|
|
110
|
+
/**
|
|
111
|
+
* The top of the repository around `dir` when that repository ignores it — and so holds none
|
|
112
|
+
* of it — or null. For what is said to a person: "not in a repository" is not what they see
|
|
113
|
+
* when one is right there.
|
|
114
|
+
*/
|
|
115
|
+
export function ignoringRepo(dir) {
|
|
116
|
+
try {
|
|
117
|
+
const top = gitText(dir, ['rev-parse', '--show-toplevel']).trim()
|
|
118
|
+
const prefix = gitText(dir, ['rev-parse', '--show-prefix']).trim()
|
|
119
|
+
return top && prefix && ignoredHere(dir) ? top : null
|
|
120
|
+
} catch {
|
|
121
|
+
return null
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
110
125
|
/** Does the repository around `dir` ignore it? `git check-ignore` exits 0 for yes, 1 for no. */
|
|
111
126
|
function ignoredHere(dir) {
|
|
112
127
|
try {
|
package/src/commands/handoff.js
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* handoff — RESERVED (not available on the new backend yet).
|
|
3
|
-
*
|
|
4
|
-
* The "create a site and hand it off to a client" flow ran against the legacy
|
|
5
|
-
* platform (the PHP backend + Cloudflare Worker) the CLI no longer talks to. A
|
|
6
|
-
* new-backend CLI equivalent isn't built; the command name is kept reserved so a
|
|
7
|
-
* future rebuild can claim it without a breaking change.
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
export async function handoff() {
|
|
11
|
-
console.error(
|
|
12
|
-
"\x1b[31m✗\x1b[0m `uniweb handoff` isn't available on the new backend yet."
|
|
13
|
-
)
|
|
14
|
-
console.error(
|
|
15
|
-
' The legacy site-handoff flow was retired with the PHP backend.'
|
|
16
|
-
)
|
|
17
|
-
console.error(' Manage client sites from the Uniweb app for now.')
|
|
18
|
-
process.exit(1)
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
export default handoff
|
package/src/commands/invite.js
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* invite — RESERVED (not available on the new backend yet).
|
|
3
|
-
*
|
|
4
|
-
* The foundation client-invite flow ran against the legacy platform (the PHP
|
|
5
|
-
* backend + Cloudflare Worker) the CLI no longer talks to. Client onboarding is
|
|
6
|
-
* handled in the Uniweb app for now; a new-backend CLI equivalent isn't built.
|
|
7
|
-
* The command name is kept reserved so a future rebuild can claim it without a
|
|
8
|
-
* breaking change.
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
export async function invite() {
|
|
12
|
-
console.error(
|
|
13
|
-
"\x1b[31m✗\x1b[0m `uniweb invite` isn't available on the new backend yet."
|
|
14
|
-
)
|
|
15
|
-
console.error(
|
|
16
|
-
' The legacy client-invite flow was retired with the PHP backend.'
|
|
17
|
-
)
|
|
18
|
-
console.error(
|
|
19
|
-
' Invite clients to your foundation from the Uniweb app for now.'
|
|
20
|
-
)
|
|
21
|
-
process.exit(1)
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export default invite
|