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.
- package/CHANGELOG.md +49 -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/security-overlay/_shared/allowlist.js +154 -0
- package/src/security-overlay/_shared/cli-runner.js +87 -0
- package/src/security-overlay/_shared/cvss.js +108 -0
- package/src/security-overlay/_shared/detect.js +125 -0
- package/src/security-overlay/_shared/install-script.js +205 -0
- package/src/security-overlay/_shared/invoke-phase.js +86 -0
- package/src/security-overlay/_shared/owasp.js +56 -0
- package/src/security-overlay/_shared/partial.js +225 -0
- package/src/security-overlay/_shared/preflight.js +175 -0
- package/src/security-overlay/_shared/scope-gate.js +172 -0
- package/src/security-overlay/_shared/scope-parser.js +120 -0
- package/src/security-overlay/agents/red-teamer/agent.yaml +51 -0
- package/src/security-overlay/agents/red-teamer/persona.md +43 -0
- package/src/security-overlay/data/common.txt +115 -0
- package/src/security-overlay/data/owasp-top10.json +15 -0
- package/src/security-overlay/data/tool-allowlist.json +31 -0
- package/src/security-overlay/skills/wize-sec-enumerate/scripts/run-enumerate.js +180 -0
- package/src/security-overlay/skills/wize-sec-enumerate/skill.md +32 -0
- package/src/security-overlay/skills/wize-sec-exploit/data/common.txt +117 -0
- package/src/security-overlay/skills/wize-sec-exploit/scripts/run-ffuf.js +147 -0
- package/src/security-overlay/skills/wize-sec-exploit/scripts/run-nikto.js +145 -0
- package/src/security-overlay/skills/wize-sec-exploit/scripts/run-nuclei.js +176 -0
- package/src/security-overlay/skills/wize-sec-exploit/scripts/run-sqlmap.js +139 -0
- package/src/security-overlay/skills/wize-sec-pentest/scripts/run-pipeline.js +157 -0
- package/src/security-overlay/skills/wize-sec-pentest/skill.md +52 -0
- package/src/security-overlay/skills/wize-sec-recon/scripts/run-gitleaks.js +139 -0
- package/src/security-overlay/skills/wize-sec-recon/scripts/run-osv.js +227 -0
- package/src/security-overlay/skills/wize-sec-recon/scripts/run-recon.js +162 -0
- package/src/security-overlay/skills/wize-sec-recon/skill.md +35 -0
- package/src/security-overlay/skills/wize-sec-report/scripts/render-report.js +999 -0
- package/src/tea-skills/wize-qa-generate-e2e-tests/workflow.md +119 -0
- package/tools/installer/onboarding.js +1 -0
- package/tools/installer/render-shared.js +50 -3
- 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
|
|
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 =
|
|
403
|
-
|
|
404
|
-
|
|
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`);
|