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.
- package/CHANGELOG.md +33 -0
- package/package.json +1 -1
- package/src/core-skills/wize-customize/skill.md +114 -0
- package/src/core-skills/wize-editorial-review-prose/skill.md +92 -0
- package/src/core-skills/wize-editorial-review-structure/skill.md +97 -0
- package/src/core-skills/wize-index-docs/skill.md +117 -0
- package/src/core-skills/wize-review-edge-case-hunter/skill.md +112 -0
- package/src/method-skills/2-plan-workflows/wize-edit-prd/workflow.md +108 -0
- package/src/method-skills/3-solutioning/wize-project-context/workflow.md +118 -0
- package/src/method-skills/4-implementation/wize-checkpoint-preview/workflow.md +115 -0
- package/src/method-skills/4-implementation/wize-correct-course/workflow.md +89 -0
- package/src/method-skills/4-implementation/wize-investigate/workflow.md +121 -0
- package/src/method-skills/4-implementation/wize-sprint-planning/workflow.md +58 -71
- package/src/method-skills/4-implementation/wize-sprint-status/workflow.md +29 -82
- package/src/orchestrator-skills/wize-onboarding/workflow.md +76 -14
- package/src/tea-skills/wize-qa-generate-e2e-tests/workflow.md +119 -0
- package/tools/installer/render-shared.js +46 -3
- package/tools/installer/wize-cli.js +64 -4
|
@@ -8,103 +8,50 @@ status: ready
|
|
|
8
8
|
|
|
9
9
|
# Sprint Status
|
|
10
10
|
|
|
11
|
-
**Goal.**
|
|
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/
|
|
18
|
-
- `.wize/implementation/tea/{epic}/{story}/gate.md`
|
|
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
|
|
20
|
+
- Updated sprint-status.yaml (if statuses changed).
|
|
21
|
+
- One recommended next workflow.
|
|
24
22
|
|
|
25
23
|
## Steps
|
|
26
24
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
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
|
-
|
|
43
|
+
## Sprint Status
|
|
60
44
|
|
|
61
|
-
|
|
45
|
+
- Project: {project} ({project_key})
|
|
46
|
+
- Tracking: {tracking_system}
|
|
47
|
+
- Status file: .wize/implementation/sprint-status.yaml
|
|
62
48
|
|
|
63
|
-
|
|
64
|
-
**
|
|
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
|
-
**
|
|
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
|
-
>
|
|
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:
|
|
5
|
+
status: ready
|
|
6
6
|
---
|
|
7
7
|
|
|
8
8
|
# Onboarding
|
|
9
9
|
|
|
10
|
-
**Goal.**
|
|
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
|
-
|
|
14
|
-
-
|
|
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
|
-
|
|
18
|
-
- A
|
|
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
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
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
|
|
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 =
|
|
403
|
-
|
|
404
|
-
|
|
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(
|