wize-dev-kit 0.4.1 → 0.5.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.
@@ -8,103 +8,50 @@ status: ready
8
8
 
9
9
  # Sprint Status
10
10
 
11
- **Goal.** Keep a snapshot of in-flight work that the team and stakeholders can read in 60 seconds. Sprint status is read by everyone, written by Hill (or delegated to Wizer); the source of truth is the file, not Slack.
12
-
13
- Update **daily** during a sprint, or after any state change (story moves, blocker appears, gate fails).
11
+ **Goal.** Read `.wize/implementation/sprint-status.yaml` in 60 seconds and say what to do next.
14
12
 
15
13
  ## Inputs
16
14
 
17
- - `.wize/solutioning/stories/` (current statuses)
18
- - `.wize/implementation/tea/{epic}/{story}/gate.md` (gate outcomes)
19
- - The team (verbal stand-up or async update)
15
+ - `.wize/implementation/sprint-status.yaml`
16
+ - `.wize/implementation/tea/{epic}/{story}/gate.md`
20
17
 
21
18
  ## Output
22
19
 
23
- - Updated entry in `.wize/implementation/sprint-status.md`.
20
+ - Updated sprint-status.yaml (if statuses changed).
21
+ - One recommended next workflow.
24
22
 
25
23
  ## Steps
26
24
 
27
- ### 1. Per story, name a status
28
-
29
- | Status | Meaning |
30
- |---|---|
31
- | `pulled` | Committed for this sprint, not started yet |
32
- | `in-progress` | Engineer actively working it (or paused < 1 day) |
33
- | `paused` | Started, paused > 1 day, reason listed |
34
- | `blocked` | Cannot proceed; depends on a named external resolution |
35
- | `in-review` | PR open; Hawkeye running design trace → review |
36
- | `gate-PASS` / `gate-CONCERNS` / `gate-FAIL` | TEA gate outcome |
37
- | `shipped` | Merged to main + deployed (when applicable) |
38
-
39
- ### 2. Blockers up front
40
-
41
- Blockers always appear in the top section. Each gets:
42
- - Owner (the person who can unblock it).
43
- - Specific ask (the action they should take).
44
- - Deadline.
45
-
46
- If a blocker sits longer than 2 days, Hill escalates. Stalled blockers are how sprints fail silently.
47
-
48
- ### 3. Trend
49
-
50
- Daily, write a one-line trend: *"On track."* / *"At risk for E03-S02 due to vendor outage."* / *"Slipping; will defer E04-S01 to next sprint."*
51
-
52
- ### 4. Capture decisions
53
-
54
- If something material was decided during the sprint that affects the plan (story sliced, scope dropped, ADR opened), append a one-line entry.
55
-
56
- ## File template
25
+ 1. **Load YAML.** Parse `development_status`.
26
+ 2. **Classify** each key: epic, story, retrospective.
27
+ 3. **Count** statuses.
28
+ 4. **Detect risks:**
29
+ - Story `in-progress` older than 2 days with no update.
30
+ - Blocked story without owner/deadline.
31
+ - Epic `in-progress` with no stories.
32
+ 5. **Recommend next step** (in priority order):
33
+ 1. Story `in-progress` → `/wize-dev-story`
34
+ 2. Story `review` `/wize-tea-review`
35
+ 3. Story `ready-for-dev` `/wize-dev-story`
36
+ 4. Story `backlog` → `/wize-create-story`
37
+ 5. Retrospective `optional` → `/wize-retrospective`
38
+ 6. All done → congratulate team.
39
+
40
+ ## Summary output
57
41
 
58
42
  ```markdown
59
- # Sprint status
43
+ ## Sprint Status
60
44
 
61
- ## Sprint 7 — 2026-06-12 → 2026-06-25
45
+ - Project: {project} ({project_key})
46
+ - Tracking: {tracking_system}
47
+ - Status file: .wize/implementation/sprint-status.yaml
62
48
 
63
- ### Day 4 (2026-06-15)
64
- **Trend:** On track.
49
+ **Stories:** backlog {n} | ready-for-dev {n} | in-progress {n} | review {n} | done {n}
50
+ **Epics:** backlog {n} | in-progress {n} | done {n}
65
51
 
66
- **Blockers:**
67
- - (none)
68
-
69
- **Stories:**
70
- - E01-S05 — gate-PASS — shipped (carry-over from S6).
71
- - E01-S06 — in-progress — Shuri.
72
- - E02-S02 — in-review — PR #418; Hawkeye doing trace.
73
- - E03-S02 — in-progress — Aaliyah.
74
- - E04-S01 — pulled — Shuri starts after E01-S06.
75
- - E02-S03 (stretch) — pulled — Aaliyah picks up if capacity allows.
76
-
77
- **Decisions:**
78
- - E03-S03 sliced into two stories (E03-S03a, E03-S03b) — ADR-009 incoming.
79
-
80
- ### Day 5 (2026-06-16)
81
- **Trend:** At risk on E02-S02 (vendor sandbox down; Hawkeye unblocked at 14:00).
82
- **Blockers:** Resolved.
83
- **Stories:** (changes from Day 4)
84
- - E02-S02 — gate-PASS at 16:30; merged.
85
- - E01-S06 — in-review — PR #419.
86
-
87
- ## Sprint 6 — 2026-05-29 → 2026-06-11
88
- {{archived}}
52
+ **Next:** /{next_workflow} ({next_story_id})
89
53
  ```
90
54
 
91
- ## Daily cadence (lean)
92
-
93
- A daily standup, when present, is 5 minutes max:
94
-
95
- - "What did I ship since last time?"
96
- - "What am I shipping next?"
97
- - "Anything blocking me?"
98
-
99
- Hill updates `sprint-status.md` immediately after; Wizer reads it before any other agent's session that day.
100
-
101
- ## Anti-patterns Hill rejects
102
-
103
- - "Status: in progress" for 4 days with no further detail. Either it really is, in which case slice progress, or it's stuck.
104
- - Blockers without an owner or a deadline.
105
- - Sprint goals that drift silently (added stories without removing others).
106
- - Stale entries in the file. Update daily or delegate the update.
107
-
108
55
  ## Hand-off
109
56
 
110
- > `sprint-status.md` updated. Day 5 trend: at-risk-mitigated. Wizer, if asked about state, the file is the answer. Pepper, brief stays valid; no scope move triggered.
57
+ > Status updated. Run the recommended workflow or call `/wize-sprint-planning` to reprioritize.
@@ -2,27 +2,89 @@
2
2
  code: wize-onboarding
3
3
  name: Onboarding
4
4
  owner: wize-orchestrator # Wizer
5
- status: stub
5
+ status: ready
6
6
  ---
7
7
 
8
8
  # Onboarding
9
9
 
10
- **Goal.** Post-install triage. Decide greenfield vs brownfield, profile(s), objective, then delegate.
10
+ **Goal.** First-contact triage after `npx wize-dev-kit install`. Decide greenfield vs brownfield, profile, objective, and route to the right persona. Always ask who the user is so the rest of the session feels personal.
11
+
12
+ Wizer drives. Each branch ends by handing off to a specific workflow with explicit handoff copy.
11
13
 
12
14
  ## Inputs
13
- - `.wize/config/project.toml` (just-created)
14
- - Repo state (git log, presence of `src/`, `package.json` etc.)
15
+
16
+ - `.wize/config/project.toml` (always present after install)
17
+ - `.wize/config/user.toml` (per-developer)
18
+ - `.wize/implementation/sprint-status.yaml` (when an active sprint exists)
19
+ - `.wize/planning/brief.md` (when Phase 1 started)
20
+ - `.wize/planning/prd.md` (when Phase 2 finished)
21
+ - Optional: chat message describing the user’s goal.
15
22
 
16
23
  ## Outputs
17
- - Updates to `.wize/config/project.toml`
18
- - A first task handed off to the right agent
24
+
25
+ - A **single handoff message** naming the next workflow to run, with the user’s name.
26
+ - Optional: `.wize/knowledge/onboarding-summary.md` written when state is ambiguous.
19
27
 
20
28
  ## Steps
21
- 1. **Greet.** "What are we working on?"
22
- 2. **Detect.** Brownfield? Offer `wize-document-project`.
23
- 3. **Profile check.** Confirm Core/+Web/+App and ask if changes needed.
24
- 4. **Objective.** One sentence: what does success look like in 30 days?
25
- 5. **Route.**
26
- - No brief? call Pepper (`wize-product-brief`).
27
- - Has brief? → call Maria Hill (`wize-create-prd`).
28
- - Mid-flight? resume where we left off (`sprint-status.md`).
29
+
30
+ ### 1. Greet the user
31
+
32
+ Read `name` from `.wize/config/user.toml`. Greet by name. Speak in `communication_language` from `project.toml`. If `name` is blank, ask once and persist it back to `user.toml` before continuing.
33
+
34
+ > "Welcome, {name}. You are at Wize onboarding for *{project_name}*."
35
+
36
+ ### 2. Detect project state
37
+
38
+ Inspect, in order:
39
+
40
+ | Path | Meaning |
41
+ |---|---|
42
+ | `.wize/implementation/sprint-status.yaml` | Active sprint exists. |
43
+ | `.wize/planning/prd.md` | Phase 2 (PRD) is done. |
44
+ | `.wize/planning/brief.md` | Phase 1 (Brief) is done. |
45
+ | `.wize/knowledge/document-project/*.md` | Brownfield baseline exists. |
46
+ | `package.json`, `src/`, etc. | Brownfield signals (vs. greenfield). |
47
+
48
+ If multiple artifacts exist, treat the **latest** (PRD > brief > baseline) as the current phase.
49
+
50
+ ### 3. State machine
51
+
52
+ - **S0 — No artifacts** → greenfield or no planning yet.
53
+ - **S1 — Baseline only** → brownfield, no brief.
54
+ - **S2 — Brief exists** → ready for PRD.
55
+ - **S3 — PRD exists** → ready for sprint planning.
56
+ - **S4 — Active sprint** → resume in-flight.
57
+
58
+ ### 4. Branch by state
59
+
60
+ | State | Action | Hand-off |
61
+ |---|---|---|
62
+ | S0 | Ask: "What are we building?" Confirm: brownfield or greenfield. Offer `/wize-document-project` (brownfield) or `/wize-product-brief` (greenfield). | "Run `/wize-document-project` (Tony + Peggy) to baseline the repo, or `/wize-product-brief` (Pepper) to write a brief." |
63
+ | S1 | Read `document-project/overview.md`; summarize the project in 3 bullets. Offer brief. | "Repo baselined. Run `/wize-product-brief` (Pepper)." |
64
+ | S2 | Read `brief.md` (3 bullets). Offer PRD. | "Brief ready. Run `/wize-create-prd` (Maria Hill)." |
65
+ | S3 | Read `prd.md` summary + `architecture.md` (if present). Offer sprint planning. | "PRD ready. Run `/wize-sprint-planning` (Maria Hill)." |
66
+ | S4 | Read `sprint-status.yaml` and surface: which stories are in progress, last gate. | "Sprint active. Run `/wize-sprint-status` (Maria Hill) for the full picture." |
67
+
68
+ ### 5. Confirm and exit
69
+
70
+ End every onboarding session with:
71
+
72
+ > "Onboarding complete. Next: `/wize-<next-workflow>` ({persona})."
73
+
74
+ Never auto-launch the next workflow. The user must confirm.
75
+
76
+ ## When to skip
77
+
78
+ - When the user already knows what they want and explicitly invokes another workflow, route directly. Do not force onboarding.
79
+ - When `WIZE_SKIP_ONBOARDING=1` is set, print a 1-line state summary and exit.
80
+
81
+ ## Anti-patterns Wizer rejects
82
+
83
+ - Launching the next workflow without confirmation.
84
+ - Re-asking the user’s name when it’s already in `user.toml`.
85
+ - Dumping the full project state to the user. Summarize in ≤ 5 bullets.
86
+ - Suggesting `wize-onboarding` from `/wize-help` once onboarding is complete. (Help should bypass onboarding for return users.)
87
+
88
+ ## Hand-off
89
+
90
+ > "Onboarding done. You are at **{state}**. Next: `/wize-<next-workflow>` ({persona})."
@@ -0,0 +1,119 @@
1
+ ---
2
+ code: wize-qa-generate-e2e-tests
3
+ name: Generate E2E Tests
4
+ owner: wize-agent-test-architect # Hawkeye
5
+ status: ready
6
+ ---
7
+
8
+ # Generate E2E Tests
9
+
10
+ **Goal.** Translate UX screens + PRD ACs into concrete E2E test cases. Hawkeye produces the cases (names, steps, selectors, expected outcome); the user (or Shuri) writes the actual test bodies in the chosen framework.
11
+
12
+ Hawkeye drives. Mantis confirms UX fidelity. Shuri confirms selectors match the design system.
13
+
14
+ ## When to run
15
+
16
+ - After `wize-ux-design` and `wize-create-prd` are validated.
17
+ - Before a story enters `in-progress` if the ACs are E2E-heavy.
18
+ - When the team adopts a new E2E framework and needs a baseline.
19
+
20
+ ## When NOT to run
21
+
22
+ - Before UX design is ready (no screens = no cases).
23
+ - For unit tests (covered by `wize-tea-design`).
24
+ - For visual / a11y (separate audit, out of scope here).
25
+
26
+ ## Inputs
27
+
28
+ - `.wize/planning/ux/ux-design/{screen}.md` — page specs.
29
+ - `.wize/planning/prd.md` — ACs.
30
+ - `.wize/solutioning/design-system/` — component + testid names.
31
+ - The active profile (web-overlay → Playwright; app-overlay → Detox; core-only → propose and let user pick).
32
+
33
+ ## Output
34
+
35
+ - `.wize/implementation/tea/e2e-cases/{screen}.md` — one file per screen with the test cases.
36
+
37
+ ## Steps
38
+
39
+ ### 1. Map (UX screen → ACs)
40
+
41
+ For each screen, list the ACs that touch it. Cross-reference the PRD. If a screen has no ACs, flag it (gap).
42
+
43
+ ### 2. Cases (3-10 per screen)
44
+
45
+ For each screen, generate 3-10 cases. For each case:
46
+ - **Name:** verb-led, in 1 line.
47
+ - **Pre-conditions:** setup (logged in, on screen X, etc.).
48
+ - **Steps:** numbered, observable actions.
49
+ - **Selectors:** `data-testid` values from the design system. If none exist, propose new ones.
50
+ - **Expected outcome:** what the test asserts.
51
+ - **Priority:** P0 (must pass before release) / P1 (should pass) / P2 (nice to have).
52
+
53
+ ### 3. Selectors
54
+
55
+ Derive selectors from `design-system/` tokens + story notes. If a story has a `data-testid` map, prefer that. New selectors go into a "proposed testids" section; Mantis signs off in the next design-system sync.
56
+
57
+ ### 4. Triage
58
+
59
+ Mark each case P0/P1/P2. P0 is the minimum viable E2E coverage. P1 expands happy paths. P2 covers edge cases.
60
+
61
+ ### 5. Hand off
62
+
63
+ Notify the next workflow:
64
+ - Shuri → implement the P0 cases first.
65
+ - Mantis → sign off on the new testids.
66
+ - The user → confirm the framework choice if it is ambiguous.
67
+
68
+ ## Output template
69
+
70
+ ```markdown
71
+ ---
72
+ screen: sign-in
73
+ generated: 2026-06-16
74
+ linked_acs: [AC-01-1, AC-01-2]
75
+ framework: playwright
76
+ ---
77
+
78
+ # E2E cases — sign-in
79
+
80
+ ## Map
81
+ - AC-01-1: user enters valid email + password
82
+ - AC-01-2: user enters invalid email → error message
83
+
84
+ ## Cases
85
+
86
+ ### P0 — happy path
87
+ - **Name:** Sign in with valid credentials
88
+ - **Pre-conditions:** not signed in; on /signin
89
+ - **Steps:** enter email; enter password; click "Sign in"
90
+ - **Selectors:** data-testid="email-input", data-testid="password-input", data-testid="signin-cta"
91
+ - **Expected outcome:** redirect to /dashboard; token in localStorage
92
+
93
+ ### P0 — invalid email
94
+ - **Name:** Sign in with invalid email
95
+ - **Pre-conditions:** not signed in; on /signin
96
+ - **Steps:** enter "not-an-email"; enter password; click "Sign in"
97
+ - **Selectors:** data-testid="email-input", data-testid="email-error"
98
+ - **Expected outcome:** error text appears within 200ms; no redirect
99
+
100
+ ## Proposed testids
101
+ - (none — using existing design system)
102
+
103
+ ## Triage summary
104
+ - P0: 2
105
+ - P1: 0
106
+ - P2: 0
107
+ ```
108
+
109
+ ## Anti-patterns Hawkeye rejects
110
+
111
+ - Generating 50 cases per screen. (Cap at 10; surface the rest as out-of-scope.)
112
+ - Skipping the priority. (P0 is the contract; the rest is optional.)
113
+ - Inventing selectors not present in the design system. (Propose them, but flag for Mantis.)
114
+ - Auto-writing Playwright code. (Hawkeye proposes cases; the human writes the bodies.)
115
+ - Skipping the screen-to-AC mapping. (Coverage gap = bug.)
116
+
117
+ ## Hand-off
118
+
119
+ > "E2E cases generated for {N} screens. {N0} P0, {N1} P1, {N2} P2. Files at `.wize/implementation/tea/e2e-cases/`. Next: implement P0 (Shuri), sign off new testids (Mantis)."
@@ -53,6 +53,42 @@ function ensureDir(dir) {
53
53
  fs.mkdirSync(dir, { recursive: true });
54
54
  }
55
55
 
56
+ // Companion files (steps/, templates/, data/, *.csv, *-template.md,
57
+ // customize.toml, research.template.md, etc.) that micro-file workflows
58
+ // reference from their body. We must copy these alongside the SKILL.md so
59
+ // the IDE can resolve paths like "./steps/step-01-init.md" at runtime.
60
+ const SKIP_NAMES = new Set(['.DS_Store', 'Thumbs.db', 'node_modules', '.git']);
61
+ const SKIP_FILES = new Set([
62
+ 'skill.md', 'workflow.md', 'agent.yaml', 'persona.md',
63
+ 'package.json', 'package-lock.json'
64
+ ]);
65
+
66
+ function isCompanion(entry) {
67
+ if (entry.name.startsWith('.')) return false;
68
+ if (SKIP_NAMES.has(entry.name)) return false;
69
+ if (SKIP_FILES.has(entry.name)) return false;
70
+ if (entry.name.endsWith('.test.js')) return false;
71
+ return true;
72
+ }
73
+
74
+ function copyCompanionFiles(srcDir, destDir, written, relPrefix = '') {
75
+ if (!srcDir || !fs.existsSync(srcDir)) return;
76
+ for (const entry of fs.readdirSync(srcDir, { withFileTypes: true })) {
77
+ if (!isCompanion(entry)) continue;
78
+ const s = path.join(srcDir, entry.name);
79
+ const d = path.join(destDir, entry.name);
80
+ const rel = relPrefix ? `${relPrefix}/${entry.name}` : entry.name;
81
+ if (entry.isDirectory()) {
82
+ ensureDir(d);
83
+ copyCompanionFiles(s, d, written, rel);
84
+ } else if (entry.isFile()) {
85
+ ensureDir(path.dirname(d));
86
+ fs.copyFileSync(s, d);
87
+ written.push(rel);
88
+ }
89
+ }
90
+ }
91
+
56
92
  // Walks the kit and returns a flat array of "assets" the adapters can render.
57
93
  // Each asset has: { kind: 'agent'|'workflow'|'skill', code, name, title, description, body, overlay }
58
94
  function collectAssets(kitRoot, { profiles = ['core'] } = {}) {
@@ -69,7 +105,7 @@ function collectAssets(kitRoot, { profiles = ['core'] } = {}) {
69
105
  if (!code || !name) continue;
70
106
  const personaPath = path.join(dir, 'persona.md');
71
107
  const persona = fs.existsSync(personaPath) ? fs.readFileSync(personaPath, 'utf-8') : '';
72
- out.push({ kind: 'agent', code, name, title, description, body: persona || description, overlay: null });
108
+ out.push({ kind: 'agent', code, name, title, description, body: persona || description, overlay: null, srcDir: dir });
73
109
  }
74
110
 
75
111
  for (const wfPath of walkWorkflows(kitRoot)) {
@@ -85,7 +121,8 @@ function collectAssets(kitRoot, { profiles = ['core'] } = {}) {
85
121
  title: fm.phase || fm.gate || '',
86
122
  description: `${fm.phase || fm.gate || 'workflow'}: ${fm.name || fm.code}`,
87
123
  body: bodyAfterFrontmatter(content),
88
- overlay: fm.overlay || null
124
+ overlay: fm.overlay || null,
125
+ srcDir: path.dirname(wfPath)
89
126
  });
90
127
  }
91
128
 
@@ -100,7 +137,8 @@ function collectAssets(kitRoot, { profiles = ['core'] } = {}) {
100
137
  title: fm.module || '',
101
138
  description: fm.module ? `${fm.module} skill: ${fm.name || fm.code}` : (fm.name || fm.code),
102
139
  body: bodyAfterFrontmatter(content),
103
- overlay: null
140
+ overlay: null,
141
+ srcDir: path.dirname(skPath)
104
142
  });
105
143
  }
106
144
 
@@ -140,6 +178,10 @@ function renderAnthropicSkills(kitRoot, targetDir, opts = {}) {
140
178
  ensureDir(skillDir);
141
179
  fs.writeFileSync(path.join(skillDir, 'SKILL.md'), content, 'utf-8');
142
180
  written.push(`${a.code}/SKILL.md`);
181
+ // Copy companion files (steps/, templates/, data/, *.csv, customize.toml,
182
+ // *-template.md, research.template.md, etc.) so micro-file workflows can
183
+ // resolve relative paths from inside the SKILL body.
184
+ copyCompanionFiles(a.srcDir, skillDir, written, a.code);
143
185
  }
144
186
  }
145
187
  return { written, skipped: [] };
@@ -178,6 +220,7 @@ module.exports = {
178
220
  collectAssets,
179
221
  renderAnthropicSkills,
180
222
  renderAgentsMd,
223
+ copyCompanionFiles,
181
224
  // Re-exports for adapter authors who need to roll their own format:
182
225
  readFrontmatter,
183
226
  bodyAfterFrontmatter,
@@ -140,12 +140,69 @@ function prompt(question) {
140
140
  }
141
141
 
142
142
  async function confirm(question, defaultYes = true) {
143
+ if (INTERACTIVE) {
144
+ const { value } = await prompts({
145
+ type: 'confirm',
146
+ name: 'value',
147
+ message: question,
148
+ initial: defaultYes
149
+ });
150
+ if (value === undefined) process.exit(130);
151
+ return value;
152
+ }
143
153
  const hint = defaultYes ? '[Y/n]' : '[y/N]';
144
154
  const ans = (await prompt(`${question} ${hint} `)).toLowerCase();
145
155
  if (!ans) return defaultYes;
146
156
  return ans.startsWith('y');
147
157
  }
148
158
 
159
+ async function promptText(question, defaultValue = '') {
160
+ if (INTERACTIVE) {
161
+ const { value } = await prompts({
162
+ type: 'text',
163
+ name: 'value',
164
+ message: question,
165
+ initial: defaultValue
166
+ });
167
+ if (value === undefined) process.exit(130);
168
+ return value.trim();
169
+ }
170
+ const ans = (await prompt(`${question} [${defaultValue}]: `)).trim();
171
+ return ans || defaultValue;
172
+ }
173
+
174
+ async function promptTextMandatory(question, defaultValue = '') {
175
+ if (INTERACTIVE) {
176
+ if (defaultValue) {
177
+ const { keep } = await prompts({
178
+ type: 'confirm',
179
+ name: 'keep',
180
+ message: `${question} (use "${defaultValue}"?)`,
181
+ initial: true
182
+ });
183
+ if (keep === undefined) process.exit(130);
184
+ if (keep) return defaultValue;
185
+ }
186
+ const { value } = await prompts({
187
+ type: 'text',
188
+ name: 'value',
189
+ message: question
190
+ });
191
+ if (value === undefined) process.exit(130);
192
+ const trimmed = value.trim();
193
+ if (trimmed) return trimmed;
194
+ if (defaultValue) return defaultValue;
195
+ return promptTextMandatory(question, defaultValue);
196
+ }
197
+ // Non-TTY: keep asking until non-empty.
198
+ for (;;) {
199
+ const ans = (await prompt(`${question}: `)).trim();
200
+ if (ans) return ans;
201
+ if (defaultValue) return defaultValue;
202
+ console.log('Please provide a value.');
203
+ }
204
+ }
205
+
149
206
  async function select(label, choices, defaultValue) {
150
207
  if (INTERACTIVE) {
151
208
  const initial = choices.findIndex(c => c.value === defaultValue);
@@ -384,7 +441,7 @@ async function cmdInstall(args) {
384
441
  console.log('\nGreenfield repo detected.');
385
442
  }
386
443
 
387
- const project_name = (await prompt(`Project name [${path.basename(cwd)}]: `)) || path.basename(cwd);
444
+ const project_name = (await promptText(`Project name`, path.basename(cwd))) || path.basename(cwd);
388
445
  const profiles = await multiSelect('Select profile(s) to install', PROFILES);
389
446
  const targets = await multiSelect('Select IDE target(s)', TARGETS);
390
447
 
@@ -398,10 +455,13 @@ async function cmdInstall(args) {
398
455
  );
399
456
 
400
457
  // Personal touch — the user_name lands in .wize/config/user.toml (per-developer).
458
+ // Always ask; do not silently accept the OS username, because the install must
459
+ // feel personal and avoid misnaming the user in agent conversations.
401
460
  const defaultName = (os.userInfo().username || '').trim();
402
- const user_name = (await prompt(
403
- `How should the agents call you? [${defaultName || 'leave blank'}]: `
404
- )).trim() || defaultName;
461
+ const user_name = await promptTextMandatory(
462
+ 'How should the agents call you?',
463
+ defaultName
464
+ );
405
465
 
406
466
  // Gitignore — opt-in, idempotent.
407
467
  const wantsGitignore = await confirm(