docs(mission): author MVP rollup manifest, archive install-ux-v2
Replace the install-ux-v2 manifest at docs/MISSION-MANIFEST.md with a top-level MVP rollup that tracks workstream-level missions instead of sub-mission scope. install-ux-v2 substantively shipped (IUV-M03 via PR #446 + releases 0.0.27 → 0.0.29) and is archived under docs/archive/missions/install-ux-v2-20260405/ with status corrected to complete. The new MVP manifest: - Names federation v1 as workstream W1 (planning-complete, 7 milestones, manifest at docs/federation/MISSION-MANIFEST.md, issues #460-#466) - Encodes three-surface parity (webUI/TUI/CLI) as cross-cutting requirement MVP-X1 so it cannot be silently dropped - Pre-stages additional workstreams (PRD-derived candidates) without committing execution capacity to them — scope creep is named and accommodated, not denied - Preserves Phase 0–8 history from sessions 1-14 in the scratchpad as prior execution context, not as the active control plane docs/TASKS.md becomes a rollup pointing at workstream task files; workers operating inside W1 read docs/federation/TASKS.md as their primary task source. Session 15 entry appended to docs/scratchpads/mvp-20260312.md (the existing scratchpad, active since 2026-03-13). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,74 @@
|
||||
# Mission Manifest — Install UX v2
|
||||
|
||||
> Persistent document tracking full mission scope, status, and session history.
|
||||
> Updated by the orchestrator at each phase transition and milestone completion.
|
||||
|
||||
## Mission
|
||||
|
||||
**ID:** install-ux-v2-20260405
|
||||
**Statement:** The install-ux-hardening mission shipped the plumbing (uninstall, masked password, hooks consent, unified flow, headless path), but the first real end-to-end run surfaced a critical regression and a collection of UX failings that make the wizard feel neither quick nor intelligent. This mission closes the bootstrap regression as a hotfix, then rethinks the first-run experience around a provider-first, intent-driven flow with a drill-down main menu and a genuinely fast quick-start.
|
||||
**Phase:** Closed
|
||||
**Current Milestone:** —
|
||||
**Progress:** 3 / 3 milestones
|
||||
**Status:** complete
|
||||
**Last Updated:** 2026-04-19 (archived during MVP manifest authoring; IUV-M03 substantively shipped via PR #446 — drill-down menu + provider-first flow + quick start; releases 0.0.27 → 0.0.29)
|
||||
**Archived to:** `docs/archive/missions/install-ux-v2-20260405/`
|
||||
**Parent Mission:** [install-ux-hardening-20260405](./archive/missions/install-ux-hardening-20260405/MISSION-MANIFEST.md) (complete — `mosaic-v0.0.25`)
|
||||
|
||||
## Context
|
||||
|
||||
Real-run testing of `@mosaicstack/mosaic@0.0.25` uncovered:
|
||||
|
||||
1. **Critical:** admin bootstrap fails with HTTP 400 `property email should not exist` — `bootstrap.controller.ts` uses `import type { BootstrapSetupDto }`, erasing the class at runtime. Nest's `@Body()` falls back to plain `Object` metatype, and ValidationPipe with `forbidNonWhitelisted` rejects every property. One-character fix (drop the `type` keyword), but it blocks the happy path of the release that just shipped.
|
||||
2. The wizard reports `✔ Wizard complete` and `✔ Done` _after_ the bootstrap 400 — failure only propagates in headless mode (`wizard.ts:147`).
|
||||
3. The gateway port prompt does not prefill `14242` in the input buffer.
|
||||
4. `"What is Mosaic?"` intro copy does not mention Pi SDK (the actual agent runtime behind Claude/Codex/OpenCode).
|
||||
5. CORS origin prompt is confusing — the user should be able to supply an FQDN/hostname and have the system derive the CORS value.
|
||||
6. Skill / additional feature install section is unusable in practice.
|
||||
7. Quick-start asks far too many questions to be meaningfully "quick".
|
||||
8. No drill-down main menu — everything is a linear interrogation.
|
||||
9. Provider setup happens late and without intelligence. An OpenClaw-style provider-first flow would let the user describe what they want in natural language, have the agent expound on it, and have the agent choose its own name based on that intent.
|
||||
|
||||
## Success Criteria
|
||||
|
||||
- [x] AC-1: Admin bootstrap completes successfully end-to-end on a fresh install (DTO value import, no forbidNonWhitelisted regression); covered by an integration or e2e test that exercises the real DTO binding. _(PR #440)_
|
||||
- [x] AC-2: Wizard fails loudly (non-zero exit, clear error) when the bootstrap stage returns `completed: false`, in both interactive and headless modes. No more silent `✔ Wizard complete` after a 400. _(PR #440)_
|
||||
- [x] AC-3: Gateway port prompt prefills `14242` in the input field (user can press Enter to accept). _(PR #440)_
|
||||
- [x] AC-4: `"What is Mosaic?"` intro copy mentions Pi SDK as the underlying agent runtime. _(PR #440)_
|
||||
- [x] AC-5: Release `mosaic-v0.0.26` tagged and published to the Gitea npm registry, unblocking the 0.0.25 happy path. _(tag: mosaic-v0.0.26, registry: 0.0.26 live)_
|
||||
- [ ] AC-6: CORS origin prompt replaced with FQDN/hostname input; CORS string is derived from that.
|
||||
- [ ] AC-7: Skill / additional feature install section is reworked until it is actually usable end-to-end (worker defines the concrete failure modes during diagnosis).
|
||||
- [ ] AC-8: First-run flow has a drill-down main menu with at least `Plugins` (Recommended / Custom), `Providers`, and the other top-level configuration groups. Linear interrogation is gone.
|
||||
- [ ] AC-9: `Quick Start` path completes with a minimal, curated set of questions (target: under 90 seconds for a returning user; define the exact baseline during design).
|
||||
- [ ] AC-10: Provider setup happens first, driven by a natural-language intake prompt. The agent expounds on the user's intent and chooses its own name based on that intent (OpenClaw-style). Naming is confirmable / overridable.
|
||||
- [ ] AC-11: All milestones ship as merged PRs with green CI and closed issues.
|
||||
|
||||
## Milestones
|
||||
|
||||
| # | ID | Name | Status | Branch | Issue | Started | Completed |
|
||||
| --- | ------- | ------------------------------------------------------------ | -------- | ---------------------- | ----- | ---------- | ---------- |
|
||||
| 1 | IUV-M01 | Hotfix: bootstrap DTO + wizard failure + port prefill + copy | complete | fix/bootstrap-hotfix | #436 | 2026-04-05 | 2026-04-05 |
|
||||
| 2 | IUV-M02 | UX polish: CORS/FQDN, skill installer rework | complete | feat/install-ux-polish | #437 | 2026-04-05 | 2026-04-05 |
|
||||
| 3 | IUV-M03 | Provider-first intelligent flow + drill-down main menu | complete | feat/install-ux-intent | #438 | 2026-04-05 | 2026-04-19 |
|
||||
|
||||
## Subagent Delegation Plan
|
||||
|
||||
| Milestone | Recommended Tier | Rationale |
|
||||
| --------- | ---------------- | --------------------------------------------------------------------- |
|
||||
| IUV-M01 | sonnet | Tight bug cluster with known fix sites + small release cycle |
|
||||
| IUV-M02 | sonnet | UX rework, moderate surface, diagnostic-heavy for the skill installer |
|
||||
| IUV-M03 | opus | Architectural redesign of first-run flow, state machine + LLM intake |
|
||||
|
||||
## Risks
|
||||
|
||||
- **Hotfix regression surface** — the `import type` → `import` fix on the DTO class is one character but needs an integration test that binds the real DTO, not just a controller unit test, to prevent the same class-erasure regression from sneaking back in.
|
||||
- **LLM-driven intake latency / offline** — M03's provider-first intent flow assumes an available LLM call to expound on user input and choose a name. Offline installs need a deterministic fallback.
|
||||
- **Menu vs. linear back-compat** — M03 changes the top-level flow shape; existing `tools/install.sh --yes` + env-var headless path must continue to work.
|
||||
- **Scope creep in M03** — "redesign the wizard" can absorb arbitrary work. Keep it bounded with explicit non-goals.
|
||||
|
||||
## Out of Scope
|
||||
|
||||
- Migrating the wizard to a GUI / web UI (still terminal-first)
|
||||
- Replacing the Gitea registry or the Woodpecker publish pipeline
|
||||
- Multi-tenant / multi-user onboarding (still single-admin bootstrap)
|
||||
- Reworking `mosaic uninstall` (M01 of the parent mission — stable)
|
||||
39
docs/archive/missions/install-ux-v2-20260405/TASKS.md
Normal file
39
docs/archive/missions/install-ux-v2-20260405/TASKS.md
Normal file
@@ -0,0 +1,39 @@
|
||||
# Tasks — Install UX v2
|
||||
|
||||
> Single-writer: orchestrator only. Workers read but never modify.
|
||||
>
|
||||
> **Mission:** install-ux-v2-20260405
|
||||
> **Schema:** `| id | status | description | issue | agent | branch | depends_on | estimate | notes |`
|
||||
> **Status values:** `not-started` | `in-progress` | `done` | `blocked` | `failed` | `needs-qa`
|
||||
> **Agent values:** `codex` | `sonnet` | `haiku` | `opus` | `—` (auto)
|
||||
|
||||
## Milestone 1 — Hotfix: bootstrap DTO + wizard failure + port prefill + copy (IUV-M01)
|
||||
|
||||
| id | status | description | issue | agent | branch | depends_on | estimate | notes |
|
||||
| --------- | ------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----- | ------ | -------------------- | ---------- | -------- | --------------------------------------------------------------------------------------- |
|
||||
| IUV-01-01 | done | Fix `apps/gateway/src/admin/bootstrap.controller.ts:16` — switch `import type { BootstrapSetupDto }` to a value import so Nest's `@Body()` binds the real class | #436 | sonnet | fix/bootstrap-hotfix | — | 3K | PR #440 merged `0ae932ab` |
|
||||
| IUV-01-02 | done | Add integration / e2e test that POSTs `/api/bootstrap/setup` with `{name,email,password}` against a real Nest app instance and asserts 201 — NOT a mocked controller unit test | #436 | sonnet | fix/bootstrap-hotfix | IUV-01-01 | 10K | `apps/gateway/src/admin/bootstrap.e2e.spec.ts` — 4 tests; unplugin-swc added for vitest |
|
||||
| IUV-01-03 | done | `packages/mosaic/src/wizard.ts:147` — propagate `!bootstrapResult.completed` as a wizard failure in **interactive** mode too (not only headless); non-zero exit + no `✔ Wizard complete` line | #436 | sonnet | fix/bootstrap-hotfix | IUV-01-02 | 5K | removed `&& headlessRun` guard |
|
||||
| IUV-01-04 | done | Gateway port prompt prefills `14242` in the input buffer — investigate why `promptPort`'s `defaultValue` isn't reaching the user-visible input | #436 | sonnet | fix/bootstrap-hotfix | IUV-01-03 | 5K | added `initialValue` through prompter interface → clack |
|
||||
| IUV-01-05 | done | `"What is Mosaic?"` intro copy updated to mention Pi SDK as the underlying agent runtime (alongside Claude Code / Codex / OpenCode) | #436 | sonnet | fix/bootstrap-hotfix | IUV-01-04 | 2K | `packages/mosaic/src/stages/welcome.ts` |
|
||||
| IUV-01-06 | done | Tests + code review + PR merge + tag `mosaic-v0.0.26` + Gitea release + npm registry republish | #436 | sonnet | fix/bootstrap-hotfix | IUV-01-05 | 10K | PRs #440/#441/#442 merged; tag `mosaic-v0.0.26`; registry latest=0.0.26 ✓ |
|
||||
|
||||
## Milestone 2 — UX polish: CORS/FQDN, skill installer rework (IUV-M02)
|
||||
|
||||
| id | status | description | issue | agent | branch | depends_on | estimate | notes |
|
||||
| --------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------ | ----- | ------ | ---------------------- | ---------- | -------- | ---------------------------------------------------------------------- |
|
||||
| IUV-02-01 | done | Replace CORS origin prompt with FQDN / hostname input; derive the CORS value internally; default to `localhost` with clear help text | #437 | sonnet | feat/install-ux-polish | — | 10K | `deriveCorsOrigin()` pure fn; MOSAIC_HOSTNAME headless var; PR #444 |
|
||||
| IUV-02-02 | done | Diagnose and document the concrete failure modes of the current skill / additional feature install section end-to-end | #437 | sonnet | feat/install-ux-polish | IUV-02-01 | 8K | selection→install gap, silent catch{}, no whitelist concept |
|
||||
| IUV-02-03 | done | Rework the skill installer so it is usable end-to-end (selection, install, verify, failure reporting) | #437 | sonnet | feat/install-ux-polish | IUV-02-02 | 20K | MOSAIC_INSTALL_SKILLS env var whitelist; SyncSkillsResult typed return |
|
||||
| IUV-02-04 | done | Tests + code review + PR merge | #437 | sonnet | feat/install-ux-polish | IUV-02-03 | 10K | 18 new tests (13 CORS + 5 skills); PR #444 merged `172bacb3` |
|
||||
|
||||
## Milestone 3 — Provider-first intelligent flow + drill-down main menu (IUV-M03)
|
||||
|
||||
| id | status | description | issue | agent | branch | depends_on | estimate | notes |
|
||||
| --------- | ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ | ----- | ----- | ---------------------- | ---------- | -------- | ------------------------------------------------------------- |
|
||||
| IUV-03-01 | not-started | Design doc: new first-run state machine — main menu (Plugins / Providers / …), Quick Start vs Custom paths, provider-first flow, intent intake + naming loop | #438 | opus | feat/install-ux-intent | — | 15K | scratchpad + explicit non-goals |
|
||||
| IUV-03-02 | not-started | Implement drill-down main menu (Plugins: Recommended / Custom, Providers, …) as the top-level entry point of `mosaic wizard` | #438 | opus | feat/install-ux-intent | IUV-03-01 | 25K | |
|
||||
| IUV-03-03 | not-started | Quick Start path: curated minimum question set — define the exact baseline, delete everything else from the fast path | #438 | opus | feat/install-ux-intent | IUV-03-02 | 15K | |
|
||||
| IUV-03-04 | not-started | Provider-first natural-language intake: user describes intent → agent expounds → agent proposes a name (confirmable / overridable) — OpenClaw-style | #438 | opus | feat/install-ux-intent | IUV-03-03 | 25K | offline fallback required (deterministic default name + path) |
|
||||
| IUV-03-05 | not-started | Preserve backward-compat: headless path (`MOSAIC_ASSUME_YES=1` + env vars) still works end-to-end; `tools/install.sh --yes` unchanged | #438 | opus | feat/install-ux-intent | IUV-03-04 | 10K | |
|
||||
| IUV-03-06 | not-started | Tests + code review + PR merge + `mosaic-v0.0.27` release | #438 | opus | feat/install-ux-intent | IUV-03-05 | 15K | |
|
||||
227
docs/archive/missions/install-ux-v2-20260405/iuv-m03-design.md
Normal file
227
docs/archive/missions/install-ux-v2-20260405/iuv-m03-design.md
Normal file
@@ -0,0 +1,227 @@
|
||||
# IUV-M03 Design: Provider-first intelligent flow + drill-down main menu
|
||||
|
||||
**Issue:** #438
|
||||
**Branch:** `feat/install-ux-intent`
|
||||
**Date:** 2026-04-05
|
||||
|
||||
## 1. New first-run state machine
|
||||
|
||||
The linear 12-stage interrogation is replaced with a menu-driven architecture.
|
||||
|
||||
### Flow overview
|
||||
|
||||
```
|
||||
Welcome banner
|
||||
|
|
||||
v
|
||||
Detect existing install (auto)
|
||||
|
|
||||
v
|
||||
Main Menu (loop)
|
||||
|-- Quick Start -> provider key + admin creds -> finalize
|
||||
|-- Providers -> LLM API key config
|
||||
|-- Agent Identity -> intent intake + naming (deterministic)
|
||||
|-- Skills -> recommended / custom selection
|
||||
|-- Gateway -> port, storage tier, hostname, CORS
|
||||
|-- Advanced -> SOUL.md, USER.md, TOOLS.md, runtimes, hooks
|
||||
|-- Finish & Apply -> finalize + gateway bootstrap
|
||||
v
|
||||
Done
|
||||
```
|
||||
|
||||
### Menu navigation
|
||||
|
||||
- Main menu is a `select` prompt. Each option drills into a sub-flow.
|
||||
- Completing a section returns to the main menu.
|
||||
- Menu items show completion state: `[done]` hint after configuration.
|
||||
- `Finish & Apply` is always last and requires at minimum a provider key (or explicit skip).
|
||||
- The menu tracks configured sections in `WizardState.completedSections`.
|
||||
|
||||
### Headless bypass
|
||||
|
||||
When `MOSAIC_ASSUME_YES=1` or `!process.stdin.isTTY`, the entire menu is skipped.
|
||||
The wizard runs: defaults + env var overrides -> finalize -> gateway config -> bootstrap.
|
||||
This preserves full backward compatibility with `tools/install.sh --yes`.
|
||||
|
||||
## 2. Quick Start path
|
||||
|
||||
Target: 3-5 questions max. Under 90 seconds for a returning user.
|
||||
|
||||
### Questions asked
|
||||
|
||||
1. **Provider API key** (Anthropic/OpenAI) - `text` prompt with paste support
|
||||
2. **Admin email** - `text` prompt
|
||||
3. **Admin password** - masked + confirmed
|
||||
|
||||
### Questions skipped (with defaults)
|
||||
|
||||
| Setting | Default | Rationale |
|
||||
| ---------------------------- | ------------------------------- | ---------------------- |
|
||||
| Agent name | "Mosaic" | Generic but branded |
|
||||
| Port | 14242 | Standard default |
|
||||
| Storage tier | local | No external deps |
|
||||
| Hostname | localhost | Dev-first |
|
||||
| CORS origin | http://localhost:3000 | Standard web UI port |
|
||||
| Skills | recommended set | Curated by maintainers |
|
||||
| Runtimes | auto-detected | No user input needed |
|
||||
| Communication style | direct | Most popular choice |
|
||||
| SOUL.md / USER.md / TOOLS.md | template defaults | Can customize later |
|
||||
| Hooks | auto-install if Claude detected | Safe default |
|
||||
|
||||
### Flow
|
||||
|
||||
```
|
||||
Quick Start selected
|
||||
-> "Paste your LLM API key (Anthropic recommended):"
|
||||
-> [auto-detect provider from key prefix: sk-ant-* = Anthropic, sk-* = OpenAI]
|
||||
-> Apply all defaults
|
||||
-> Run finalize (sync framework, write configs, link assets, sync skills)
|
||||
-> Run gateway config (headless-style with defaults + provided key)
|
||||
-> "Admin email:"
|
||||
-> "Admin password:" (masked + confirm)
|
||||
-> Run gateway bootstrap
|
||||
-> Done
|
||||
```
|
||||
|
||||
## 3. Provider-first flow
|
||||
|
||||
Provider configuration (currently buried in gateway-config stage as "ANTHROPIC_API_KEY")
|
||||
moves to a dedicated top-level menu item and is the first question in Quick Start.
|
||||
|
||||
### Provider detection
|
||||
|
||||
The API key prefix determines the provider:
|
||||
|
||||
- `sk-ant-api03-*` -> Anthropic (Claude)
|
||||
- `sk-*` -> OpenAI
|
||||
- Empty/skipped -> no provider (gateway starts without LLM access)
|
||||
|
||||
### Storage
|
||||
|
||||
The provider key is stored in the gateway `.env` as `ANTHROPIC_API_KEY` or `OPENAI_API_KEY`.
|
||||
For Quick Start, this replaces the old interactive prompt in `collectAndWriteConfig`.
|
||||
|
||||
### Menu section: "Providers"
|
||||
|
||||
In the drill-down menu, "Providers" lets users:
|
||||
|
||||
1. Enter/change their API key
|
||||
2. See which provider was detected
|
||||
3. Optionally configure a second provider
|
||||
|
||||
For v0.0.27, we support Anthropic and OpenAI keys only. The key is stored
|
||||
in `WizardState` and written during finalize.
|
||||
|
||||
## 4. Intent intake + naming (deterministic fallback - Option B)
|
||||
|
||||
### Rationale
|
||||
|
||||
At install time, the LLM provider may not be configured yet (chicken-and-egg).
|
||||
We use **Option B: deterministic advisor** for the install wizard.
|
||||
|
||||
### Flow (Agent Identity menu section)
|
||||
|
||||
```
|
||||
1. "What will this agent primarily help you with?"
|
||||
-> Select from presets:
|
||||
- General purpose assistant
|
||||
- Software development
|
||||
- DevOps & infrastructure
|
||||
- Research & analysis
|
||||
- Content & writing
|
||||
- Custom (free text description)
|
||||
|
||||
2. System proposes a thematic name based on selection:
|
||||
- General purpose -> "Mosaic"
|
||||
- Software development -> "Forge"
|
||||
- DevOps & infrastructure -> "Sentinel"
|
||||
- Research & analysis -> "Atlas"
|
||||
- Content & writing -> "Muse"
|
||||
- Custom -> "Mosaic" (default)
|
||||
|
||||
3. "Your agent will be named 'Forge'. Press Enter to accept or type a new name:"
|
||||
-> User confirms or overrides
|
||||
```
|
||||
|
||||
### Storage
|
||||
|
||||
- Agent name -> `WizardState.soul.agentName` -> written to SOUL.md
|
||||
- Intent category -> `WizardState.agentIntent` (new field) -> written to `~/.config/mosaic/agent.json`
|
||||
|
||||
### Post-install LLM-powered intake (future)
|
||||
|
||||
A future `mosaic configure identity` command can use the configured LLM to:
|
||||
|
||||
- Accept free-text intent description
|
||||
- Generate an expounded persona
|
||||
- Propose a contextual name
|
||||
|
||||
This is explicitly out of scope for the install wizard.
|
||||
|
||||
## 5. Headless backward-compat
|
||||
|
||||
### Supported env vars (unchanged)
|
||||
|
||||
| Variable | Used by |
|
||||
| -------------------------- | ---------------------------------------------- |
|
||||
| `MOSAIC_ASSUME_YES=1` | Skip all prompts, use defaults + env overrides |
|
||||
| `MOSAIC_ADMIN_NAME` | Gateway bootstrap |
|
||||
| `MOSAIC_ADMIN_EMAIL` | Gateway bootstrap |
|
||||
| `MOSAIC_ADMIN_PASSWORD` | Gateway bootstrap |
|
||||
| `MOSAIC_GATEWAY_PORT` | Gateway config |
|
||||
| `MOSAIC_HOSTNAME` | Gateway config (CORS derivation) |
|
||||
| `MOSAIC_CORS_ORIGIN` | Gateway config (full override) |
|
||||
| `MOSAIC_STORAGE_TIER` | Gateway config (local/team) |
|
||||
| `MOSAIC_DATABASE_URL` | Gateway config (team tier) |
|
||||
| `MOSAIC_VALKEY_URL` | Gateway config (team tier) |
|
||||
| `MOSAIC_ANTHROPIC_API_KEY` | Provider config |
|
||||
|
||||
### New env vars
|
||||
|
||||
| Variable | Purpose |
|
||||
| --------------------- | ----------------------------------------- |
|
||||
| `MOSAIC_AGENT_NAME` | Override agent name in headless mode |
|
||||
| `MOSAIC_AGENT_INTENT` | Override intent category in headless mode |
|
||||
|
||||
### `tools/install.sh --yes`
|
||||
|
||||
The install script sets `MOSAIC_ASSUME_YES=1` and passes through env vars.
|
||||
No changes needed to the script itself. The new wizard detects headless mode
|
||||
at the top of `runWizard` and runs a linear path identical to the old flow.
|
||||
|
||||
## 6. Explicit non-goals
|
||||
|
||||
- **No GUI** — this is a terminal wizard only
|
||||
- **No multi-user install** — single-user, single-machine
|
||||
- **No registry changes** — npm publish flow is unchanged
|
||||
- **No LLM calls during install** — deterministic fallback only
|
||||
- **No new dependencies** — uses existing @clack/prompts and picocolors
|
||||
- **No changes to gateway API** — only the wizard orchestration changes
|
||||
- **No changes to tools/install.sh** — headless compat maintained via env vars
|
||||
|
||||
## 7. Implementation plan
|
||||
|
||||
### Files to modify
|
||||
|
||||
1. `packages/mosaic/src/types.ts` — add `MenuSection`, `AgentIntent`, `completedSections`, `agentIntent`, `providerKey`, `providerType` to WizardState
|
||||
2. `packages/mosaic/src/wizard.ts` — replace linear flow with menu loop
|
||||
3. `packages/mosaic/src/stages/mode-select.ts` — becomes the main menu
|
||||
4. `packages/mosaic/src/stages/provider-setup.ts` — new: provider key collection
|
||||
5. `packages/mosaic/src/stages/agent-intent.ts` — new: intent intake + naming
|
||||
6. `packages/mosaic/src/stages/menu-gateway.ts` — new: gateway sub-menu wrapper
|
||||
7. `packages/mosaic/src/stages/quick-start.ts` — new: quick start linear path
|
||||
8. `packages/mosaic/src/constants.ts` — add intent presets and name mappings
|
||||
9. `packages/mosaic/package.json` — version bump 0.0.26 -> 0.0.27
|
||||
|
||||
### Files to add (tests)
|
||||
|
||||
1. `packages/mosaic/src/stages/wizard-menu.spec.ts` — menu navigation tests
|
||||
2. `packages/mosaic/src/stages/quick-start.spec.ts` — quick start path tests
|
||||
3. `packages/mosaic/src/stages/agent-intent.spec.ts` — intent + naming tests
|
||||
4. `packages/mosaic/src/stages/provider-setup.spec.ts` — provider detection tests
|
||||
|
||||
### Migration strategy
|
||||
|
||||
The existing stage functions remain intact. The menu system wraps them —
|
||||
each menu item calls the appropriate stage function(s). The linear headless
|
||||
path calls them in the same order as before.
|
||||
173
docs/archive/missions/install-ux-v2-20260405/scratchpad.md
Normal file
173
docs/archive/missions/install-ux-v2-20260405/scratchpad.md
Normal file
@@ -0,0 +1,173 @@
|
||||
# Install UX v2 — Orchestrator Scratchpad
|
||||
|
||||
## Session 1 — 2026-04-05 (orchestrator scaffold)
|
||||
|
||||
### Trigger
|
||||
|
||||
Real-run testing of `@mosaicstack/mosaic@0.0.25` (fresh install of the release we just shipped from the parent mission `install-ux-hardening-20260405`) surfaced a critical regression and a cluster of UX failings. User feedback verbatim:
|
||||
|
||||
> The skill/additional feature installation section of install.sh is unsable
|
||||
> The "quick-start" is asking way too many questions. This process should be much faster to get a quick start.
|
||||
> The installater should have a main menu that allows for a drill-down install approach.
|
||||
> "Plugins" — Install Recommended Plugins / Custom
|
||||
> "Providers" — …
|
||||
> The gateway port is not prefilling with 14242 for default
|
||||
> What is the CORS origin for? Is that the webUI that isn't working yet? Maybe we should ask for the fqdn/hostname instead? There must be a better way to handle this.
|
||||
|
||||
Plus the critical bug, reproduced verbatim:
|
||||
|
||||
```
|
||||
◇ Admin email
|
||||
│ jason@woltje.com
|
||||
Admin password (min 8 chars): ****************
|
||||
Confirm password: ****************
|
||||
│
|
||||
▲ Bootstrap failed (400): {"message":["property email should not exist","property password should not exist"],"error":"Bad Request","statusCode":400}
|
||||
✔ Wizard complete.
|
||||
✔ Install manifest written: /home/jarvis/.config/mosaic/.install-manifest.json
|
||||
|
||||
✔ Done.
|
||||
```
|
||||
|
||||
Note the `✔ Wizard complete` and `✔ Done` lines **after** the 400. That's a second bug — failure didn't propagate in interactive mode.
|
||||
|
||||
### Diagnosis — orchestrator pre-scope
|
||||
|
||||
To avoid handing workers a vague prompt, pre-identified the concrete fix sites:
|
||||
|
||||
**Bug 1 (critical) — DTO class erasure.** `apps/gateway/src/admin/bootstrap.controller.ts:16`:
|
||||
|
||||
```ts
|
||||
import type { BootstrapSetupDto, BootstrapStatusDto, BootstrapResultDto } from './bootstrap.dto.js';
|
||||
```
|
||||
|
||||
`import type` erases the class at runtime. `@Body() dto: BootstrapSetupDto` then has no runtime metatype — `design:paramtypes` reflects `Object`. Nest's `ValidationPipe` with `whitelist: true` + `forbidNonWhitelisted: true` receives a plain Object metatype, treats every incoming property as non-whitelisted, and 400s with `"property email should not exist", "property password should not exist"`.
|
||||
|
||||
**One-character fix:** drop the `type` keyword on the `BootstrapSetupDto` import. `BootstrapStatusDto` and `BootstrapResultDto` are fine as type-only imports because they're used only in return type positions, not as `@Body()` metatypes.
|
||||
|
||||
Must be covered by an **integration test that binds through Nest**, not a controller unit test that imports the DTO directly — the unit test path would pass even with `import type` because it constructs the pipe manually. An e2e test with `@nestjs/testing` + `supertest` against the real `/api/bootstrap/setup` endpoint is the right guard.
|
||||
|
||||
**Bug 2 — interactive silent failure.** `packages/mosaic/src/wizard.ts:147-150`:
|
||||
|
||||
```ts
|
||||
if (!bootstrapResult.completed && headlessRun) {
|
||||
prompter.warn('Admin bootstrap failed in headless mode — aborting wizard.');
|
||||
process.exit(1);
|
||||
}
|
||||
```
|
||||
|
||||
The guard is `&& headlessRun`. In interactive mode, `completed: false` is silently swallowed and the wizard continues to the success lines. Fix: propagate failure in both modes. Decision for the worker — either `throw` or `process.exit(1)` with a clear error.
|
||||
|
||||
**Bug 3 — port prefill.** `packages/mosaic/src/stages/gateway-config.ts:77-88`:
|
||||
|
||||
```ts
|
||||
const raw = await p.text({
|
||||
message: 'Gateway port',
|
||||
defaultValue: defaultPort.toString(),
|
||||
...
|
||||
});
|
||||
```
|
||||
|
||||
The stage is passing `defaultValue`. Either the `WizardPrompter.text` adapter is dropping it, or the underlying `@clack/prompts` call expects `initialValue` (which actually prefills the buffer) vs `defaultValue` (which is used only if the user submits an empty string). Worker should verify the adapter and likely switch to `initialValue` semantics so the user sees `14242` in the field.
|
||||
|
||||
**Bug 4 — Pi SDK copy gap.** The `"What is Mosaic?"` intro text enumerates Claude Code, Codex, and OpenCode but never mentions Pi SDK, which is the actual agent runtime behind those frontends. Purely a copy edit — find the string, add Pi SDK.
|
||||
|
||||
### Mission shape
|
||||
|
||||
Three milestones, three tracks, different tiers:
|
||||
|
||||
1. **IUV-M01 Hotfix** (sonnet) — the four bugs above + release `mosaic-v0.0.26`. Small, fast, unblocks the 0.0.25 happy path.
|
||||
2. **IUV-M02 UX polish** (sonnet) — CORS origin → FQDN/hostname abstraction; diagnose and rework the skill installer section. Diagnostic-heavy.
|
||||
3. **IUV-M03 Provider-first intelligent flow** (opus) — the big one: drill-down main menu, Quick Start path that's actually quick, provider-first natural-language intake with agent self-naming (OpenClaw-style). Architectural.
|
||||
|
||||
Sequencing: strict. M01 ships first as a hotfix release (mosaic-v0.0.26). M02 is diagnostic-heavy and can share groundwork with M03 but ships separately for clean release notes. M03 is the architectural anchor and lands last as `mosaic-v0.0.27`.
|
||||
|
||||
### Open design questions (to be resolved by workers, not pre-decided)
|
||||
|
||||
- M01: does `process.exit(1)` vs `throw` matter for how `tools/install.sh` surfaces the error? Worker should check the install.sh call site and pick the behavior that surfaces cleanly.
|
||||
- M03: what LLM call powers the intent intake, and what's the offline fallback? Options: (a) reuse the provider the user is configuring (chicken-and-egg — provider setup hasn't happened yet), (b) a bundled deterministic "advisor" that hard-codes common intents, (c) require a provider key up-front before intake. Design doc (IUV-03-01) must resolve.
|
||||
- M03: is the "agent self-naming" persistent across all future `mosaic` invocations, or a per-session nickname? Probably persistent — lives in `~/.config/mosaic/agent.json` or similar. Worker to decide + document.
|
||||
|
||||
### Non-goals for this mission
|
||||
|
||||
- No GUI / web UI
|
||||
- No registry / pipeline migration
|
||||
- No multi-user / multi-tenant onboarding
|
||||
- No rework of `mosaic uninstall` (stable from parent mission)
|
||||
|
||||
### Known tooling caveats (carry forward from parent mission)
|
||||
|
||||
- `issue-create.sh` / `pr-create.sh` wrappers have an `eval` bug with multiline bodies — use Gitea REST API fallback with `load_credentials gitea-mosaicstack`
|
||||
- `pr-ci-wait.sh` reports `state=unknown` against Woodpecker (combined-status endpoint gap) — use `tea pr` glyphs or poll the commit status endpoint directly
|
||||
- Protected `main`, squash-merge only, PR-required
|
||||
- CI queue guard before push/merge: `~/.config/mosaic/tools/git/ci-queue-wait.sh --purpose push|merge`
|
||||
|
||||
### Next action
|
||||
|
||||
1. Create Gitea issues for M01, M02, M03
|
||||
2. Open the mission-scaffold docs PR (same pattern as parent mission's PR #430)
|
||||
3. After merge, delegate IUV-M01 to a sonnet subagent in an isolated worktree with the concrete fix-site pointers above
|
||||
|
||||
## Session 2 — 2026-04-05 (IUV-M01 delivery + close-out)
|
||||
|
||||
### Outcome
|
||||
|
||||
IUV-M01 shipped. `mosaic-v0.0.26` released and registry latest confirmed `0.0.26`.
|
||||
|
||||
### PRs merged
|
||||
|
||||
| PR | Title | Merge |
|
||||
| ---- | ------------------------------------------------------------------------ | -------- |
|
||||
| #440 | fix: bootstrap hotfix — DTO erasure, wizard failure, port prefill, copy | 0ae932ab |
|
||||
| #441 | fix: add vitest.config.ts to eslint allowDefaultProject (#440 build fix) | c08aa6fa |
|
||||
| #442 | docs: mark IUV-M01 complete — mosaic-v0.0.26 released | 78388437 |
|
||||
|
||||
### Bugs fixed (all 4 in worker's PR #440)
|
||||
|
||||
1. **DTO class erasure** — `apps/gateway/src/admin/bootstrap.controller.ts:16` — dropped `type` from `import { BootstrapSetupDto }`. Guarded by new e2e test `bootstrap.e2e.spec.ts` (4 cases) that binds through a real Nest app with `ValidationPipe { whitelist, forbidNonWhitelisted }`. Test suite needed `unplugin-swc` in `apps/gateway/vitest.config.ts` to emit `decoratorMetadata` (tsx/esbuild can't).
|
||||
2. **Wizard silent failure** — `packages/mosaic/src/wizard.ts` — removed the `&& headlessRun` guard so `!bootstrapResult.completed` now aborts in both modes.
|
||||
3. **Port prefill** — root cause was clack's `defaultValue` vs `initialValue` semantics (`defaultValue` only fills on empty submit, `initialValue` prefills the buffer). Added an `initialValue` field to `WizardPrompter.text()` interface, threaded through clack and headless prompters, switched `gateway-config.ts` port/url prompts to use it.
|
||||
4. **Pi SDK copy** — `packages/mosaic/src/stages/welcome.ts` — intro copy now lists Pi SDK.
|
||||
|
||||
### Mid-delivery hiccup — tsconfig/eslint cross-contamination
|
||||
|
||||
Worker's initial approach added `vitest.config.ts` to `apps/gateway/tsconfig.json`'s `include` to appease the eslint parser. That broke `pnpm --filter @mosaicstack/gateway build` with TS6059 (`vitest.config.ts` outside `rootDir: "src"`). The publish pipeline on the `#440` merge commit failed.
|
||||
|
||||
**Correct fix** (worker's PR #441): leave `tsconfig.json` clean (`include: ["src/**/*"]`) and instead add the file to `allowDefaultProject` in the root `eslint.config.mjs`. This keeps the tsc program strict while letting eslint resolve a parser project for the standalone config file.
|
||||
|
||||
**Pattern to remember**: when adding root-level `.ts` config files (vitest, build scripts) to a package with `rootDir: "src"`, the eslint parser project conflict is solved with `allowDefaultProject`, NEVER by widening tsconfig include. I had independently arrived at the same fix on a branch before the worker shipped #441 — deleted the duplicate.
|
||||
|
||||
### Residual follow-ups carried forward
|
||||
|
||||
1. Headless prompter fallback order: worker set `initialValue > defaultValue` in the headless path. Correct semantic, but any future headless test that explicitly depends on `defaultValue` precedence will need review.
|
||||
2. Vitest + SWC decorator metadata pattern is now the blessed approach for NestJS e2e tests in this monorepo. Any other package that adds NestJS e2e tests should mirror `apps/gateway/vitest.config.ts`.
|
||||
|
||||
### Next action
|
||||
|
||||
- Close out orchestrator doc sync (this commit): mark M01 subtasks done in `TASKS.md`, update manifest phase to Execution, commit scratchpad session 2, PR to main.
|
||||
- After merge, delegate IUV-M02 (sonnet, isolated worktree). Dependencies: IUV-02-01 (CORS→FQDN) starts unblocked since M01 is released; first real task for the M02 worker is diagnosing the skill installer failure modes (IUV-02-02) against the fresh 0.0.26 install.
|
||||
|
||||
## Session 3 — 2026-04-05 (IUV-M02 delivery + close-out)
|
||||
|
||||
### Outcome
|
||||
|
||||
IUV-M02 shipped. PR #444 merged (`172bacb3`), issue #437 closed. 18 new tests (13 CORS derivation, 5 skill sync).
|
||||
|
||||
### Changes
|
||||
|
||||
**CORS → FQDN (IUV-02-01):**
|
||||
|
||||
- `packages/mosaic/src/stages/gateway-config.ts` — replaced raw "CORS origin" text prompt with "Web UI hostname" (default: `localhost`). Added HTTPS follow-up for remote hosts. Pure `deriveCorsOrigin(hostname, port, useHttps?)` function exported for testability.
|
||||
- Headless: `MOSAIC_HOSTNAME` env var as friendly alternative; `MOSAIC_CORS_ORIGIN` still works as full override.
|
||||
- `packages/mosaic/src/types.ts` — added `hostname?: string` to `GatewayState`.
|
||||
|
||||
**Skill installer rework (IUV-02-02 + IUV-02-03):**
|
||||
|
||||
- Root cause confirmed: `syncSkills()` in `finalize.ts` ignored `state.selectedSkills` entirely. The multiselect UI was a no-op.
|
||||
- `packages/mosaic/src/stages/finalize.ts` — `syncSkills()` rewritten to accept `selectedSkills[]`, returns typed `SyncSkillsResult`, passes `MOSAIC_INSTALL_SKILLS` (colon-separated) as env var to the bash script.
|
||||
- `packages/mosaic/framework/tools/_scripts/mosaic-sync-skills` — added bash associative array whitelist filter keyed on `MOSAIC_INSTALL_SKILLS`. When set, only whitelisted skills are linked. Empty/unset = all skills (legacy behavior preserved for `mosaic sync` outside wizard).
|
||||
- Failure surfaces: silent `catch {}` replaced with typed error reporting through `p.warn()`.
|
||||
|
||||
### Next action
|
||||
|
||||
- Delegate IUV-M03 (opus, isolated worktree) — the architectural milestone: provider-first intelligent flow, drill-down main menu, Quick Start fast path, agent self-naming. This is the biggest piece of the mission.
|
||||
Reference in New Issue
Block a user