Part of the CLI-features-coverage epic #701.
Context
The UI command group is ui:init and ui:add only (public-command-tree.ts) — both copy pre-authored registry items. The web layer's create path is entirely hand-authored:
- No page/route generator.
docs/site/how-to/customize-fresh-ui.md:137 hand-writes a full definePage() route file; docs/site/tutorials/live-dashboard/04-definePage-QueryIsland.md:66-124 hand-creates index.route.ts, (_shared)/query-loaders.ts, and index.tsx. Grep of features/generate and features/ui finds no route/page emitter.
- No island generator.
customize-fresh-ui.md:162 and 04-definePage-QueryIsland.md:199 hand-write islands; ui:add only copies fixed registry islands under islands/ui/, never a user-named island.
- No registry list/inspect. The ~60-item machine-readable manifest (
packages/fresh-ui/registry.manifest.ts, 7 named collections) is unexposed; the docs maintain a hand-written prose table of available components (customize-fresh-ui.md:258).
- No update/remove for installed items.
installUiRegistryItems (packages/cli/src/kernel/application/ui/registry.ts) only copies or --force-clobbers app-owned source (silently destroying local edits); nothing diffs against a newer registry version, removes files, or prunes merged deno.json imports — the classic shadcn update problem.
- (p3) Theme tokens are hand-edited:
customize-fresh-ui.md:198-214 edits assets/tokens.css (mirrored in tokens.json) and per-component CSS by hand; no token/theme mutation verb.
Dashboard consumer
The merged dashboard design (PR #685, .llm/runs/dashboard-design--orchestrator/) makes scaffold-from-UI the management keystone: coverage-matrix row #432 requires the full "template-gallery -> file-diff preview -> confirm-CLI -> success" loop, explicitly "one generator, two callers" (CLI and dashboard call the same codegen), with "every console gets 'New X from template'" (.llm/runs/dashboard-design--orchestrator/coverage-matrix.md row #432 and Direction-A gap table). The extension platform adds a first-class create-from-template flow with a generated-file-tree preview + config diff before the confirm (.llm/runs/dashboard-design--orchestrator/design-prompts/06-extension-platform.md); console empty states must show the scaffold command (.llm/runs/dashboard-design--orchestrator/design-prompts/03-capability-consoles.md, States).
Dashboard capability unlock
unblocks-dashboard: true — for the web layer, the "one generator, two callers" contract has no first caller: there is no page/route/island generator for the dashboard's "Add page" action to share, and no ui:list --json for a template/component gallery to enumerate (today's source is a hand-maintained prose table). Once this lands: dashboard-side "New page/island from template" actions reuse the CLI generator with a real file-diff preview; the registry browser panel enumerates items/collections/installed-state from ui:list; and update/remove actions become non-destructive verbs instead of --force clobbering app-owned source.
Scope
netscript ui:add page <path> [--route <id>] [--island] scaffolding routes/<path>/index.tsx via definePage() + optional (_islands)/ + (_shared)/query-loaders.ts (typed route picked up by the vite plugin).
netscript ui:add island <Name> [--query] generating islands/<Name>.tsx (signals template, or QueryIsland wired to the query package).
netscript ui:list [--json] [--collections] emitting the registry manifest with per-project installed-state.
netscript ui:update [<name>] (diff copied source vs registry, report/3-way on drift) and netscript ui:remove <name> (delete files + prune deno.json imports).
- (p3)
netscript ui token set <name> <value> updating tokens.css + tokens.json together.
Acceptance
Part of the CLI-features-coverage epic #701.
Context
The UI command group is
ui:initandui:addonly (public-command-tree.ts) — both copy pre-authored registry items. The web layer's create path is entirely hand-authored:docs/site/how-to/customize-fresh-ui.md:137hand-writes a fulldefinePage()route file;docs/site/tutorials/live-dashboard/04-definePage-QueryIsland.md:66-124hand-createsindex.route.ts,(_shared)/query-loaders.ts, andindex.tsx. Grep offeatures/generateandfeatures/uifinds no route/page emitter.customize-fresh-ui.md:162and04-definePage-QueryIsland.md:199hand-write islands;ui:addonly copies fixed registry islands underislands/ui/, never a user-named island.packages/fresh-ui/registry.manifest.ts, 7 named collections) is unexposed; the docs maintain a hand-written prose table of available components (customize-fresh-ui.md:258).installUiRegistryItems(packages/cli/src/kernel/application/ui/registry.ts) only copies or--force-clobbers app-owned source (silently destroying local edits); nothing diffs against a newer registry version, removes files, or prunes merged deno.json imports — the classic shadcn update problem.customize-fresh-ui.md:198-214editsassets/tokens.css(mirrored in tokens.json) and per-component CSS by hand; no token/theme mutation verb.Dashboard consumer
The merged dashboard design (PR #685,
.llm/runs/dashboard-design--orchestrator/) makes scaffold-from-UI the management keystone: coverage-matrix row #432 requires the full "template-gallery -> file-diff preview -> confirm-CLI -> success" loop, explicitly "one generator, two callers" (CLI and dashboard call the same codegen), with "every console gets 'New X from template'" (.llm/runs/dashboard-design--orchestrator/coverage-matrix.mdrow #432 and Direction-A gap table). The extension platform adds a first-class create-from-template flow with a generated-file-tree preview + config diff before the confirm (.llm/runs/dashboard-design--orchestrator/design-prompts/06-extension-platform.md); console empty states must show the scaffold command (.llm/runs/dashboard-design--orchestrator/design-prompts/03-capability-consoles.md, States).Dashboard capability unlock
unblocks-dashboard: true— for the web layer, the "one generator, two callers" contract has no first caller: there is no page/route/island generator for the dashboard's "Add page" action to share, and noui:list --jsonfor a template/component gallery to enumerate (today's source is a hand-maintained prose table). Once this lands: dashboard-side "New page/island from template" actions reuse the CLI generator with a real file-diff preview; the registry browser panel enumerates items/collections/installed-state fromui:list; and update/remove actions become non-destructive verbs instead of--forceclobbering app-owned source.Scope
netscript ui:add page <path> [--route <id>] [--island]scaffoldingroutes/<path>/index.tsxviadefinePage()+ optional(_islands)/+(_shared)/query-loaders.ts(typed route picked up by the vite plugin).netscript ui:add island <Name> [--query]generatingislands/<Name>.tsx(signals template, or QueryIsland wired to the query package).netscript ui:list [--json] [--collections]emitting the registry manifest with per-project installed-state.netscript ui:update [<name>](diff copied source vs registry, report/3-way on drift) andnetscript ui:remove <name>(delete files + prune deno.json imports).netscript ui token set <name> <value>updating tokens.css + tokens.json together.Acceptance
ui:add pageemits a compiling definePage route that the typed route manifest picks up on next build — PR feat(cli): Fresh web-layer scaffolding + UI registry management (ui:add page/island, ui:list/update/remove) #717: shared web generator emits adefinePage()route; semantically tested against the real definePage/typed-route builder shape (manifest pickup proven by the orchestrator scaffold-runtime gate pre-cut).ui:add islandemits a hydrating island wired into a route — PR feat(cli): Fresh web-layer scaffolding + UI registry management (ui:add page/island, ui:list/update/remove) #717: signals/QueryIsland templates, covered by generator tests.ui:list --jsonoutput matches the registry manifest and flags installed items — PR feat(cli): Fresh web-layer scaffolding + UI registry management (ui:add page/island, ui:list/update/remove) #717:listUiRegistryItemsreads the registry manifest with per-project installed state; stable JSON output.ui:updatenever silently clobbers locally-edited files (reports drift instead);ui:removeleaves no orphaned files or imports — PR feat(cli): Fresh web-layer scaffolding + UI registry management (ui:add page/island, ui:list/update/remove) #717: update reports drift on locally-edited files (registry-lifecycle tests); remove deletes files + prunes imports.