wize-dev-kit 0.4.1 → 0.6.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.
Files changed (49) hide show
  1. package/CHANGELOG.md +49 -0
  2. package/package.json +1 -1
  3. package/src/core-skills/wize-customize/skill.md +114 -0
  4. package/src/core-skills/wize-editorial-review-prose/skill.md +92 -0
  5. package/src/core-skills/wize-editorial-review-structure/skill.md +97 -0
  6. package/src/core-skills/wize-index-docs/skill.md +117 -0
  7. package/src/core-skills/wize-review-edge-case-hunter/skill.md +112 -0
  8. package/src/method-skills/2-plan-workflows/wize-edit-prd/workflow.md +108 -0
  9. package/src/method-skills/3-solutioning/wize-project-context/workflow.md +118 -0
  10. package/src/method-skills/4-implementation/wize-checkpoint-preview/workflow.md +115 -0
  11. package/src/method-skills/4-implementation/wize-correct-course/workflow.md +89 -0
  12. package/src/method-skills/4-implementation/wize-investigate/workflow.md +121 -0
  13. package/src/method-skills/4-implementation/wize-sprint-planning/workflow.md +58 -71
  14. package/src/method-skills/4-implementation/wize-sprint-status/workflow.md +29 -82
  15. package/src/orchestrator-skills/wize-onboarding/workflow.md +76 -14
  16. package/src/security-overlay/_shared/allowlist.js +154 -0
  17. package/src/security-overlay/_shared/cli-runner.js +87 -0
  18. package/src/security-overlay/_shared/cvss.js +108 -0
  19. package/src/security-overlay/_shared/detect.js +125 -0
  20. package/src/security-overlay/_shared/install-script.js +205 -0
  21. package/src/security-overlay/_shared/invoke-phase.js +86 -0
  22. package/src/security-overlay/_shared/owasp.js +56 -0
  23. package/src/security-overlay/_shared/partial.js +225 -0
  24. package/src/security-overlay/_shared/preflight.js +175 -0
  25. package/src/security-overlay/_shared/scope-gate.js +172 -0
  26. package/src/security-overlay/_shared/scope-parser.js +120 -0
  27. package/src/security-overlay/agents/red-teamer/agent.yaml +51 -0
  28. package/src/security-overlay/agents/red-teamer/persona.md +43 -0
  29. package/src/security-overlay/data/common.txt +115 -0
  30. package/src/security-overlay/data/owasp-top10.json +15 -0
  31. package/src/security-overlay/data/tool-allowlist.json +31 -0
  32. package/src/security-overlay/skills/wize-sec-enumerate/scripts/run-enumerate.js +180 -0
  33. package/src/security-overlay/skills/wize-sec-enumerate/skill.md +32 -0
  34. package/src/security-overlay/skills/wize-sec-exploit/data/common.txt +117 -0
  35. package/src/security-overlay/skills/wize-sec-exploit/scripts/run-ffuf.js +147 -0
  36. package/src/security-overlay/skills/wize-sec-exploit/scripts/run-nikto.js +145 -0
  37. package/src/security-overlay/skills/wize-sec-exploit/scripts/run-nuclei.js +176 -0
  38. package/src/security-overlay/skills/wize-sec-exploit/scripts/run-sqlmap.js +139 -0
  39. package/src/security-overlay/skills/wize-sec-pentest/scripts/run-pipeline.js +157 -0
  40. package/src/security-overlay/skills/wize-sec-pentest/skill.md +52 -0
  41. package/src/security-overlay/skills/wize-sec-recon/scripts/run-gitleaks.js +139 -0
  42. package/src/security-overlay/skills/wize-sec-recon/scripts/run-osv.js +227 -0
  43. package/src/security-overlay/skills/wize-sec-recon/scripts/run-recon.js +162 -0
  44. package/src/security-overlay/skills/wize-sec-recon/skill.md +35 -0
  45. package/src/security-overlay/skills/wize-sec-report/scripts/render-report.js +999 -0
  46. package/src/tea-skills/wize-qa-generate-e2e-tests/workflow.md +119 -0
  47. package/tools/installer/onboarding.js +1 -0
  48. package/tools/installer/render-shared.js +50 -3
  49. package/tools/installer/wize-cli.js +72 -5
@@ -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)."
@@ -26,6 +26,7 @@ function compose(detection, profiles) {
26
26
  lines.push(' → /wize-quick-dev (Shuri, for small fixes)');
27
27
  if (profiles.find(p => p.code === 'web-overlay')) lines.push(' → /wize-web-scaffold (overlay)');
28
28
  if (profiles.find(p => p.code === 'app-overlay')) lines.push(' → /wize-app-scaffold (overlay)');
29
+ if (profiles.find(p => p.code === 'security-overlay')) lines.push(' → /wize-sec-pentest (overlay)');
29
30
  return lines.join('\n');
30
31
  }
31
32
 
@@ -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)) {
@@ -78,6 +114,7 @@ function collectAssets(kitRoot, { profiles = ['core'] } = {}) {
78
114
  if (!fm.code) continue;
79
115
  if (fm.overlay === 'web' && !profSet.has('web-overlay')) continue;
80
116
  if (fm.overlay === 'app' && !profSet.has('app-overlay')) continue;
117
+ if (fm.overlay === 'security' && !profSet.has('security-overlay')) continue;
81
118
  out.push({
82
119
  kind: 'workflow',
83
120
  code: fm.code,
@@ -85,7 +122,8 @@ function collectAssets(kitRoot, { profiles = ['core'] } = {}) {
85
122
  title: fm.phase || fm.gate || '',
86
123
  description: `${fm.phase || fm.gate || 'workflow'}: ${fm.name || fm.code}`,
87
124
  body: bodyAfterFrontmatter(content),
88
- overlay: fm.overlay || null
125
+ overlay: fm.overlay || null,
126
+ srcDir: path.dirname(wfPath)
89
127
  });
90
128
  }
91
129
 
@@ -93,6 +131,9 @@ function collectAssets(kitRoot, { profiles = ['core'] } = {}) {
93
131
  const content = fs.readFileSync(skPath, 'utf-8');
94
132
  const fm = readFrontmatter(content);
95
133
  if (!fm.code) continue;
134
+ if (fm.overlay === 'web' && !profSet.has('web-overlay')) continue;
135
+ if (fm.overlay === 'app' && !profSet.has('app-overlay')) continue;
136
+ if (fm.overlay === 'security' && !profSet.has('security-overlay')) continue;
96
137
  out.push({
97
138
  kind: 'skill',
98
139
  code: fm.code,
@@ -100,7 +141,8 @@ function collectAssets(kitRoot, { profiles = ['core'] } = {}) {
100
141
  title: fm.module || '',
101
142
  description: fm.module ? `${fm.module} skill: ${fm.name || fm.code}` : (fm.name || fm.code),
102
143
  body: bodyAfterFrontmatter(content),
103
- overlay: null
144
+ overlay: fm.overlay || null,
145
+ srcDir: path.dirname(skPath)
104
146
  });
105
147
  }
106
148
 
@@ -140,6 +182,10 @@ function renderAnthropicSkills(kitRoot, targetDir, opts = {}) {
140
182
  ensureDir(skillDir);
141
183
  fs.writeFileSync(path.join(skillDir, 'SKILL.md'), content, 'utf-8');
142
184
  written.push(`${a.code}/SKILL.md`);
185
+ // Copy companion files (steps/, templates/, data/, *.csv, customize.toml,
186
+ // *-template.md, research.template.md, etc.) so micro-file workflows can
187
+ // resolve relative paths from inside the SKILL body.
188
+ copyCompanionFiles(a.srcDir, skillDir, written, a.code);
143
189
  }
144
190
  }
145
191
  return { written, skipped: [] };
@@ -178,6 +224,7 @@ module.exports = {
178
224
  collectAssets,
179
225
  renderAnthropicSkills,
180
226
  renderAgentsMd,
227
+ copyCompanionFiles,
181
228
  // Re-exports for adapter authors who need to roll their own format:
182
229
  readFrontmatter,
183
230
  bodyAfterFrontmatter,
@@ -43,7 +43,8 @@ const TARGETS = [
43
43
  const PROFILES = [
44
44
  { code: 'core', label: 'Wize Dev Core', required: true },
45
45
  { code: 'web-overlay', label: 'Wize Web Dev (overlay)', required: false },
46
- { code: 'app-overlay', label: 'Wize App Development (overlay)', required: false }
46
+ { code: 'app-overlay', label: 'Wize App Development (overlay)', required: false },
47
+ { code: 'security-overlay', label: 'Wize Security (AI Pentester overlay)', required: false }
47
48
  ];
48
49
 
49
50
  // Common BCP-47 short codes. Users can type any other value freely.
@@ -140,12 +141,69 @@ function prompt(question) {
140
141
  }
141
142
 
142
143
  async function confirm(question, defaultYes = true) {
144
+ if (INTERACTIVE) {
145
+ const { value } = await prompts({
146
+ type: 'confirm',
147
+ name: 'value',
148
+ message: question,
149
+ initial: defaultYes
150
+ });
151
+ if (value === undefined) process.exit(130);
152
+ return value;
153
+ }
143
154
  const hint = defaultYes ? '[Y/n]' : '[y/N]';
144
155
  const ans = (await prompt(`${question} ${hint} `)).toLowerCase();
145
156
  if (!ans) return defaultYes;
146
157
  return ans.startsWith('y');
147
158
  }
148
159
 
160
+ async function promptText(question, defaultValue = '') {
161
+ if (INTERACTIVE) {
162
+ const { value } = await prompts({
163
+ type: 'text',
164
+ name: 'value',
165
+ message: question,
166
+ initial: defaultValue
167
+ });
168
+ if (value === undefined) process.exit(130);
169
+ return value.trim();
170
+ }
171
+ const ans = (await prompt(`${question} [${defaultValue}]: `)).trim();
172
+ return ans || defaultValue;
173
+ }
174
+
175
+ async function promptTextMandatory(question, defaultValue = '') {
176
+ if (INTERACTIVE) {
177
+ if (defaultValue) {
178
+ const { keep } = await prompts({
179
+ type: 'confirm',
180
+ name: 'keep',
181
+ message: `${question} (use "${defaultValue}"?)`,
182
+ initial: true
183
+ });
184
+ if (keep === undefined) process.exit(130);
185
+ if (keep) return defaultValue;
186
+ }
187
+ const { value } = await prompts({
188
+ type: 'text',
189
+ name: 'value',
190
+ message: question
191
+ });
192
+ if (value === undefined) process.exit(130);
193
+ const trimmed = value.trim();
194
+ if (trimmed) return trimmed;
195
+ if (defaultValue) return defaultValue;
196
+ return promptTextMandatory(question, defaultValue);
197
+ }
198
+ // Non-TTY: keep asking until non-empty.
199
+ for (;;) {
200
+ const ans = (await prompt(`${question}: `)).trim();
201
+ if (ans) return ans;
202
+ if (defaultValue) return defaultValue;
203
+ console.log('Please provide a value.');
204
+ }
205
+ }
206
+
149
207
  async function select(label, choices, defaultValue) {
150
208
  if (INTERACTIVE) {
151
209
  const initial = choices.findIndex(c => c.value === defaultValue);
@@ -384,7 +442,7 @@ async function cmdInstall(args) {
384
442
  console.log('\nGreenfield repo detected.');
385
443
  }
386
444
 
387
- const project_name = (await prompt(`Project name [${path.basename(cwd)}]: `)) || path.basename(cwd);
445
+ const project_name = (await promptText(`Project name`, path.basename(cwd))) || path.basename(cwd);
388
446
  const profiles = await multiSelect('Select profile(s) to install', PROFILES);
389
447
  const targets = await multiSelect('Select IDE target(s)', TARGETS);
390
448
 
@@ -398,10 +456,13 @@ async function cmdInstall(args) {
398
456
  );
399
457
 
400
458
  // Personal touch — the user_name lands in .wize/config/user.toml (per-developer).
459
+ // Always ask; do not silently accept the OS username, because the install must
460
+ // feel personal and avoid misnaming the user in agent conversations.
401
461
  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;
462
+ const user_name = await promptTextMandatory(
463
+ 'How should the agents call you?',
464
+ defaultName
465
+ );
405
466
 
406
467
  // Gitignore — opt-in, idempotent.
407
468
  const wantsGitignore = await confirm(
@@ -423,6 +484,12 @@ async function cmdInstall(args) {
423
484
  console.log(`✓ ide targets: ${targets.map(t => t.code).join(', ')}`);
424
485
  if (user_name) console.log(`✓ user.toml: agents will call you "${user_name}"`);
425
486
 
487
+ if (profiles.some(p => p.code === 'security-overlay')) {
488
+ console.log('\n⚠ security-overlay selected — authorized use only.');
489
+ console.log(' Uso autorizado. Você é responsável por obter permissão antes de testar alvos que não são seus.');
490
+ console.log(' O kit detecta alvos fora do scope.md e recusa automaticamente; ainda assim, use com responsabilidade.');
491
+ }
492
+
426
493
  if (wantsGitignore) {
427
494
  const r = applyGitignore(cwd);
428
495
  if (r.changed) console.log(`✓ .gitignore ${r.mode} with the wize-dev-kit block`);