wize-dev-kit 0.11.0 → 0.12.1

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 (92) hide show
  1. package/AGENTS.md +3 -3
  2. package/CHANGELOG.md +37 -0
  3. package/README.es.md +3 -1
  4. package/README.md +3 -1
  5. package/README.pt-BR.md +3 -1
  6. package/package.json +1 -1
  7. package/src/app-overlay/wize-app-release-channels/workflow.md +2 -0
  8. package/src/app-overlay/wize-app-scaffold/workflow.md +2 -0
  9. package/src/app-overlay/wize-app-store-listing/workflow.md +2 -0
  10. package/src/builder-skills/wize-create-agent/workflow.md +2 -0
  11. package/src/builder-skills/wize-create-skill/workflow.md +2 -0
  12. package/src/builder-skills/wize-create-workflow/workflow.md +2 -0
  13. package/src/core-skills/module.yaml +3 -0
  14. package/src/core-skills/wize-advanced-elicitation/skill.md +2 -0
  15. package/src/core-skills/wize-brainstorming/skill.md +2 -0
  16. package/src/core-skills/wize-customize/skill.md +2 -0
  17. package/src/core-skills/wize-editorial-review-prose/skill.md +2 -0
  18. package/src/core-skills/wize-editorial-review-structure/skill.md +2 -0
  19. package/src/core-skills/wize-grill/skill.md +3 -1
  20. package/src/core-skills/wize-index-docs/skill.md +3 -1
  21. package/src/core-skills/wize-pre-pr-check/skill.md +134 -0
  22. package/src/core-skills/wize-review-adversarial/skill.md +2 -0
  23. package/src/core-skills/wize-review-edge-case-hunter/skill.md +2 -0
  24. package/src/core-skills/wize-shard-doc/skill.md +2 -0
  25. package/src/core-skills/wize-spec/skill.md +2 -0
  26. package/src/method-skills/1-analysis/wize-agent-analyst/agent.yaml +3 -0
  27. package/src/method-skills/1-analysis/wize-document-project/workflow.md +2 -0
  28. package/src/method-skills/1-analysis/wize-domain-research/workflow.md +7 -0
  29. package/src/method-skills/1-analysis/wize-market-research/workflow.md +7 -0
  30. package/src/method-skills/1-analysis/wize-prfaq/workflow.md +2 -0
  31. package/src/method-skills/1-analysis/wize-product-brief/workflow.md +2 -0
  32. package/src/method-skills/1-analysis/wize-refresh-knowledge/workflow.md +3 -1
  33. package/src/method-skills/1-analysis/wize-research/workflow.md +24 -89
  34. package/src/method-skills/1-analysis/wize-technical-research/workflow.md +7 -0
  35. package/src/method-skills/1-analysis/wize-trigger-map/workflow.md +2 -0
  36. package/src/method-skills/2-plan-workflows/wize-create-prd/workflow.md +2 -0
  37. package/src/method-skills/2-plan-workflows/wize-edit-prd/workflow.md +3 -1
  38. package/src/method-skills/2-plan-workflows/wize-ux-design/workflow.md +2 -0
  39. package/src/method-skills/2-plan-workflows/wize-ux-scenarios/workflow.md +2 -0
  40. package/src/method-skills/2-plan-workflows/wize-validate-prd/workflow.md +2 -0
  41. package/src/method-skills/3-solutioning/wize-check-implementation-readiness/workflow.md +2 -0
  42. package/src/method-skills/3-solutioning/wize-create-architecture/steps/step-08-complete.md +1 -1
  43. package/src/method-skills/3-solutioning/wize-create-architecture/workflow.md +2 -0
  44. package/src/method-skills/3-solutioning/wize-create-epics-and-stories/workflow.md +2 -0
  45. package/src/method-skills/3-solutioning/wize-design-system/workflow.md +2 -0
  46. package/src/method-skills/3-solutioning/wize-nfr-principles/workflow.md +3 -1
  47. package/src/method-skills/3-solutioning/wize-project-context/workflow.md +3 -1
  48. package/src/method-skills/3-solutioning/wize-tech-vision/workflow.md +3 -1
  49. package/src/method-skills/4-implementation/wize-changelog/workflow.md +184 -0
  50. package/src/method-skills/4-implementation/wize-checkpoint-preview/workflow.md +2 -0
  51. package/src/method-skills/4-implementation/wize-code-review/workflow.md +2 -0
  52. package/src/method-skills/4-implementation/wize-correct-course/workflow.md +2 -0
  53. package/src/method-skills/4-implementation/wize-create-story/workflow.md +2 -0
  54. package/src/method-skills/4-implementation/wize-dev-story/workflow.md +3 -1
  55. package/src/method-skills/4-implementation/wize-investigate/workflow.md +2 -0
  56. package/src/method-skills/4-implementation/wize-quick-dev/workflow.md +2 -0
  57. package/src/method-skills/4-implementation/wize-release/workflow.md +162 -0
  58. package/src/method-skills/4-implementation/wize-retrospective/workflow.md +2 -0
  59. package/src/method-skills/4-implementation/wize-sprint-planning/workflow.md +2 -0
  60. package/src/method-skills/4-implementation/wize-sprint-status/workflow.md +2 -0
  61. package/src/method-skills/module.yaml +12 -3
  62. package/src/orchestrator-skills/module.yaml +4 -1
  63. package/src/orchestrator-skills/wize/skill.md +164 -0
  64. package/src/orchestrator-skills/wize-help/skill.md +126 -5
  65. package/src/orchestrator-skills/wize-onboarding/workflow.md +3 -1
  66. package/src/orchestrator-skills/wize-orchestrator/agent.yaml +1 -0
  67. package/src/orchestrator-skills/wize-orchestrator/persona.md +29 -4
  68. package/src/orchestrator-skills/wize-party-mode/workflow.md +2 -0
  69. package/src/security-overlay/_shared/scope-parser.js +27 -0
  70. package/src/security-overlay/agents/red-teamer/agent.yaml +2 -0
  71. package/src/security-overlay/agents/red-teamer/persona.md +6 -0
  72. package/src/security-overlay/skills/wize-sec-enumerate/skill.md +2 -0
  73. package/src/security-overlay/skills/wize-sec-pentest/scripts/run-pipeline.js +18 -1
  74. package/src/security-overlay/skills/wize-sec-pentest/skill.md +2 -0
  75. package/src/security-overlay/skills/wize-sec-recon/skill.md +2 -0
  76. package/src/security-overlay/skills/wize-sec-scope/scripts/generate-scope.js +106 -0
  77. package/src/security-overlay/skills/wize-sec-scope/skill.md +52 -0
  78. package/src/tea-skills/wize-qa-generate-e2e-tests/workflow.md +2 -0
  79. package/src/tea-skills/wize-tea-design/workflow.md +3 -0
  80. package/src/tea-skills/wize-tea-gate/workflow.md +3 -0
  81. package/src/tea-skills/wize-tea-nfr/workflow.md +3 -0
  82. package/src/tea-skills/wize-tea-review/workflow.md +3 -0
  83. package/src/tea-skills/wize-tea-risk/workflow.md +3 -0
  84. package/src/tea-skills/wize-tea-trace/workflow.md +3 -0
  85. package/src/web-overlay/wize-web-deploy/workflow.md +2 -0
  86. package/src/web-overlay/wize-web-scaffold/workflow.md +2 -0
  87. package/src/web-overlay/wize-web-seo-audit/workflow.md +2 -0
  88. package/tools/installer/commands/doctor.js +2 -2
  89. package/tools/installer/onboarding.js +14 -21
  90. package/tools/installer/render-shared.js +50 -28
  91. package/tools/installer/validators/run-all.js +3 -2
  92. package/tools/installer/wize-cli.js +323 -77
@@ -7,10 +7,12 @@ I am **Wizer**. I am the host of this development kit. I know who you are, what
7
7
  ## Operating principles
8
8
 
9
9
  1. **Listen first.** Before routing, I make sure I understand the demand. One clarifying question is cheaper than three wrong hand-offs.
10
- 2. **Route, don't perform.** I rarely do the specialist's job. When the question is a brief, I call Pepper. When it is a PRD, Maria Hill. When it is architecture, Tony.
11
- 3. **Keep the thread.** I keep the knowledge of the project consistent across conversations. If something changed, I update `.wize/config/project.toml` before moving on.
12
- 4. **Pair when needed.** When a decision crosses concerns (UX touching architecture, PM touching TEA), I open a **party-mode** with the relevant agents.
13
- 5. **Treat the kit as the contract.** `.wize/`, `AGENTS.md`, and the installed `wize-*` skills are the operating instructions and persistent memory of whoever executes — not background reading. I make sure a demand is classified (Quick Dev vs Full Lifecycle, via `/wize-help`) and framed as a mission — objective, sources of truth, scope, acceptance criteria, validation — before any code is touched.
10
+ 2. **Route by intent, not just phase.** When the user's message contains a clear intent phrase ("quero pesquisar concorrência", "cria um PRD", "roda um pentest"), I route directly to the matching skill using the intent routing table. I use the phase heuristic only when intent is ambiguous or no intent phrase matches.
11
+ 3. **Route, don't perform.** I rarely do the specialist's job. When the question is a brief, I call Pepper. When it is a PRD, Maria Hill. When it is architecture, Tony.
12
+ 4. **Keep the thread.** I keep the knowledge of the project consistent across conversations. If something changed, I update `.wize/config/project.toml` before moving on.
13
+ 5. **Pair when needed.** When a decision crosses concerns (UX touching architecture, PM touching TEA), I open a **party-mode** with the relevant agents.
14
+ 6. **Treat the kit as the contract.** `.wize/`, `AGENTS.md`, and the installed `wize-*` skills are the operating instructions and persistent memory of whoever executes — not background reading. I make sure a demand is classified (Quick Dev vs Full Lifecycle, via `/wize` or `/wize-help`) and framed as a mission — objective, sources of truth, scope, acceptance criteria, validation — before any code is touched.
15
+ 7. **Harness-aware interaction.** In text-only harnesses, I ask one clarifying question when intent is ambiguous. In rich-UI harnesses, I offer a menu of matching options.
14
16
 
15
17
  ## Fan-out to subagents
16
18
 
@@ -39,6 +41,29 @@ Before greeting, read `.wize/config/user.toml` if it exists. If it has `[user] n
39
41
 
40
42
  If `user.toml` is missing or has no `name`, fall back to a neutral greeting.
41
43
 
44
+ ## First-run detection
45
+
46
+ Before greeting, check whether this is a first run:
47
+
48
+ 1. Read `.wize/planning/brief.md` — if it exists, this is NOT a first run.
49
+ 2. Read `.wize/knowledge/document-project/` — if it has content (any `.md` files), this is NOT a first run.
50
+ 3. If neither exists: **first run**.
51
+
52
+ ## First-run flow
53
+
54
+ When first run is detected, do NOT show a menu. Ask one question:
55
+
56
+ > "O que você está construindo?"
57
+
58
+ Wait for the answer. Then classify:
59
+
60
+ - **Greenfield** (new project, idea, feature, product): route to **Pepper / `wize-product-brief`**.
61
+ - **Brownfield** (existing codebase, legacy system, "we already have X"): route to **Pepper / `wize-document-project`**.
62
+
63
+ If the answer is ambiguous, ask one clarifying question: "Is this a new project or an existing codebase?" Then route.
64
+
65
+ Never show a menu on first run. One question → classify → route.
66
+
42
67
  ## Greet
43
68
 
44
69
  > "Welcome back{{`, ` + user.name when present, else ''}}. What are we working on?"
@@ -1,5 +1,7 @@
1
1
  ---
2
+
2
3
  code: wize-party-mode
4
+ description: "Use quando uma decisão cruzar preocupações de múltiplos agentes e precisar de discussão multi-agente facilitada."
3
5
  name: Party Mode (multi-agent)
4
6
  owner: wize-orchestrator # Wizer facilitates
5
7
  status: stub
@@ -111,10 +111,37 @@ function loadScope(scopePath) {
111
111
  return scope;
112
112
  }
113
113
 
114
+ // signScope(scopePath) — read, parse, recompute SHA-256 of the body, and
115
+ // rewrite the scope_sha256 field in the frontmatter. Returns metadata about
116
+ // the signed scope. Throws ScopeError on missing file or invalid format.
117
+ // Idempotent: running twice on the same body produces the same hash.
118
+ function signScope(scopePath) {
119
+ if (!fs.existsSync(scopePath)) {
120
+ throw new ScopeError('MISSING_FILE', null,
121
+ `scope.md ausente em ${scopePath} — crie com wize-sec-scope antes de assinar`);
122
+ }
123
+ const text = fs.readFileSync(scopePath, 'utf8');
124
+ const scope = parseScope(text);
125
+
126
+ const newHash = computeScopeSha256(scope.body);
127
+
128
+ // Replace scope_sha256 within the frontmatter block only (avoid
129
+ // accidental matches in the body).
130
+ const fmMatch = text.match(/^---\n([\s\S]*?)\n---\n/);
131
+ const fmBlock = fmMatch[0];
132
+ const newFmBlock = fmBlock.replace(/^(scope_sha256:\s*).*$/m, `$1${newHash}`);
133
+ const newText = text.replace(fmBlock, newFmBlock);
134
+
135
+ fs.writeFileSync(scopePath, newText, 'utf8');
136
+
137
+ return { path: scopePath, sha256: newHash, accepted_by: scope.frontmatter.accepted_by };
138
+ }
139
+
114
140
  module.exports = {
115
141
  parseScope,
116
142
  validateScope,
117
143
  computeScopeSha256,
118
144
  loadScope,
145
+ signScope,
119
146
  ScopeError
120
147
  };
@@ -22,9 +22,11 @@ overlay: security
22
22
 
23
23
  skills:
24
24
  - wize-sec-pentest
25
+ - wize-sec-scope
25
26
 
26
27
  commands:
27
28
  - /wize-sec-pentest
29
+ - /wize-sec-scope
28
30
 
29
31
  inputs:
30
32
  - ".wize/security/scope.md (gate of authorization)"
@@ -25,6 +25,12 @@ Each phase is a standalone skill; the orchestrator `wize-sec-pentest` chains the
25
25
  - **Missing tools degrade, they don't abort.** If a tool is not on `$PATH`, the corresponding check is recorded as `degraded_checks` in the partial. The pipeline continues.
26
26
  - **Flags via allowlist.** Every argument to every external tool is filtered through `data/tool-allowlist.json`. I never pass user-supplied flags directly to `execFile`.
27
27
 
28
+ ## Scope management
29
+
30
+ - **Create scope:** `/wize-sec-scope` — guided flow that asks for target URL, hosts, paths, and acceptance name. Generates `.wize/security/scope.md` with a valid `scope_sha256`.
31
+ - **Re-sign scope:** `/wize-sec-pentest --sign-scope` — recomputes the SHA-256 of the body and rewrites `scope_sha256` in the frontmatter. Use after editing the allowlist manually.
32
+ - **Validate scope:** `loadScope()` is called before any offensive action. An invalid scope (missing file, missing fields, hash mismatch) aborts the pipeline.
33
+
28
34
  ## Limits
29
35
 
30
36
  - I do NOT attack hosts, URLs, or paths outside the `scope.md` allowlist. Even with `--active`.
@@ -1,5 +1,7 @@
1
1
  ---
2
+
2
3
  code: wize-sec-enumerate
4
+ description: "Use quando o recon estiver concluído e precisar enumerar a superfície de ataque (portas, serviços, tecnologias) a partir dos alvos autorizados."
3
5
  name: wize-sec-enumerate
4
6
  overlay: security
5
7
  module: security-overlay
@@ -26,10 +26,11 @@ const PHASE_SCRIPTS = {
26
26
  };
27
27
 
28
28
  function parseArgv(argv) {
29
- const out = { active: false, scopePath: null, kitRoot: DEFAULT_KIT_ROOT };
29
+ const out = { active: false, scopePath: null, kitRoot: DEFAULT_KIT_ROOT, signScope: false };
30
30
  for (let i = 0; i < (argv || []).length; i++) {
31
31
  const a = argv[i];
32
32
  if (a === '--active') out.active = true;
33
+ else if (a === '--sign-scope') out.signScope = true;
33
34
  else if (a === '--scope' && argv[i + 1]) { out.scopePath = argv[i + 1]; i++; }
34
35
  else if (a.startsWith('--scope=')) out.scopePath = a.slice('--scope='.length);
35
36
  }
@@ -120,6 +121,22 @@ async function runPipeline(opts = {}) {
120
121
  // user invokes `/wize-sec-pentest`.
121
122
  async function main() {
122
123
  const args = parseArgv(process.argv.slice(2));
124
+
125
+ // --sign-scope: recompute SHA-256 and exit (no pipeline run).
126
+ if (args.signScope) {
127
+ try {
128
+ const { signScope } = require('../../../_shared/scope-parser.js');
129
+ const result = signScope(args.scopePath);
130
+ console.log(`✓ Scope re-assinado. SHA-256: ${result.sha256}`);
131
+ console.log(` aceite por: ${result.accepted_by}`);
132
+ console.log(` arquivo: ${result.path}`);
133
+ process.exit(0);
134
+ } catch (err) {
135
+ console.error('✖ sign-scope falhou:', err && err.message ? err.message : err);
136
+ process.exit(2);
137
+ }
138
+ }
139
+
123
140
  let result;
124
141
  try {
125
142
  // Derive the securityDir from the scopePath's parent (the .wize/security
@@ -1,5 +1,7 @@
1
1
  ---
2
+
2
3
  code: wize-sec-pentest
4
+ description: "Use quando o scope de segurança estiver definido e precisar executar o pipeline completo de pentest (recon → enumerate → exploit → report)."
3
5
  name: wize-sec-pentest
4
6
  overlay: security
5
7
  module: security-overlay
@@ -1,5 +1,7 @@
1
1
  ---
2
+
2
3
  code: wize-sec-recon
4
+ description: "Use quando o scope de segurança estiver autorizado e precisar executar reconhecimento passivo (nmap) nos alvos."
3
5
  name: wize-sec-recon
4
6
  overlay: security
5
7
  module: security-overlay
@@ -0,0 +1,106 @@
1
+ 'use strict';
2
+
3
+ // generate-scope.js — creates a valid .wize/security/scope.md from CLI args.
4
+ // Zero-dep. Computes scope_sha256 from the body (including the leading newline
5
+ // separator, matching parseScope's convention).
6
+
7
+ const fs = require('node:fs');
8
+ const path = require('node:path');
9
+ const crypto = require('node:crypto');
10
+
11
+ function parseArgv(argv) {
12
+ const out = { url: null, hosts: [], paths: [], acceptedBy: null, outPath: null };
13
+ for (let i = 0; i < (argv || []).length; i++) {
14
+ const a = argv[i];
15
+ if (a === '--url' && argv[i + 1]) { out.url = argv[i + 1]; i++; }
16
+ else if (a.startsWith('--url=')) out.url = a.slice('--url='.length);
17
+ else if (a === '--hosts' && argv[i + 1]) { out.hosts = argv[i + 1].split(',').map(s => s.trim()).filter(Boolean); i++; }
18
+ else if (a.startsWith('--hosts=')) out.hosts = a.slice('--hosts='.length).split(',').map(s => s.trim()).filter(Boolean);
19
+ else if (a === '--paths' && argv[i + 1]) { out.paths = argv[i + 1].split(',').map(s => s.trim()).filter(Boolean); i++; }
20
+ else if (a.startsWith('--paths=')) out.paths = a.slice('--paths='.length).split(',').map(s => s.trim()).filter(Boolean);
21
+ else if (a === '--accepted-by' && argv[i + 1]) { out.acceptedBy = argv[i + 1]; i++; }
22
+ else if (a.startsWith('--accepted-by=')) out.acceptedBy = a.slice('--accepted-by='.length);
23
+ else if (a === '--out' && argv[i + 1]) { out.outPath = argv[i + 1]; i++; }
24
+ else if (a.startsWith('--out=')) out.outPath = a.slice('--out='.length);
25
+ }
26
+ if (!out.outPath) out.outPath = path.join(process.cwd(), '.wize', 'security', 'scope.md');
27
+ return out;
28
+ }
29
+
30
+ function buildBody({ url, hosts, paths }) {
31
+ const lines = [];
32
+
33
+ lines.push('## allowlist');
34
+
35
+ lines.push('hosts:');
36
+ for (const h of hosts) lines.push(` - ${h}`);
37
+
38
+ lines.push('urls:');
39
+ if (url) lines.push(` - ${url.replace(/\/+$/, '')}/`);
40
+
41
+ lines.push('paths:');
42
+ if (paths.length > 0) {
43
+ for (const p of paths) lines.push(` - ${p}`);
44
+ } else {
45
+ lines.push(' - /');
46
+ }
47
+
48
+ lines.push('');
49
+ lines.push('## dast_target');
50
+ if (url) lines.push(`url: ${url}`);
51
+ lines.push('');
52
+ lines.push('## notes');
53
+ lines.push(`Scope gerado por wize-sec-scope em ${new Date().toISOString()}.`);
54
+ lines.push('');
55
+
56
+ return lines.join('\n');
57
+ }
58
+
59
+ function generateScope({ url, hosts, paths, acceptedBy, outPath }) {
60
+ const body = buildBody({ url, hosts, paths });
61
+
62
+ // The hash is computed on the body as parseScope returns it: with the
63
+ // leading newline separator between the closing --- and the body.
64
+ const signedBody = '\n' + body;
65
+ const scopeSha256 = crypto.createHash('sha256').update(signedBody, 'utf8').digest('hex');
66
+ const acceptedAt = new Date().toISOString();
67
+
68
+ const fm = [
69
+ `accepted_by: ${acceptedBy || 'unknown'}`,
70
+ `accepted_at: ${acceptedAt}`,
71
+ `scope_sha256: ${scopeSha256}`
72
+ ].join('\n');
73
+
74
+ const content = `---\n${fm}\n---\n${signedBody}`;
75
+
76
+ const dir = path.dirname(outPath);
77
+ fs.mkdirSync(dir, { recursive: true });
78
+ fs.writeFileSync(outPath, content, 'utf8');
79
+
80
+ return { path: outPath, sha256: scopeSha256, acceptedBy, acceptedAt };
81
+ }
82
+
83
+ function main() {
84
+ const args = parseArgv(process.argv.slice(2));
85
+
86
+ if (!args.url) {
87
+ console.error('✖ --url é obrigatório (ex: --url=http://localhost:8080)');
88
+ process.exit(2);
89
+ }
90
+ if (!args.acceptedBy) {
91
+ console.error('✖ --accepted-by é obrigatório (ex: --accepted-by="Seu Nome")');
92
+ process.exit(2);
93
+ }
94
+
95
+ const result = generateScope(args);
96
+ console.log(`✓ scope.md gerado em ${result.path}`);
97
+ console.log(` SHA-256: ${result.sha256}`);
98
+ console.log(` aceite por: ${result.acceptedBy}`);
99
+ console.log(` aceite em: ${result.acceptedAt}`);
100
+ }
101
+
102
+ if (require.main === module) {
103
+ main();
104
+ }
105
+
106
+ module.exports = { generateScope, buildBody, parseArgv };
@@ -0,0 +1,52 @@
1
+ ---
2
+
3
+ code: wize-sec-scope
4
+ description: "Use para criar ou re-assinar o scope.md de segurança. Guia o usuário com perguntas e gera o arquivo com hash SHA-256."
5
+ name: wize-sec-scope
6
+ overlay: security
7
+ module: security-overlay
8
+ owner: wize-sec-red-teamer # Natasha Romanoff
9
+ status: ready
10
+ ---
11
+
12
+ # wize-sec-scope — Criação guiada de scope.md
13
+
14
+ Cria o arquivo `.wize/security/scope.md` a partir de perguntas interativas. Gera o frontmatter com `accepted_by`, `accepted_at`, e `scope_sha256` (SHA-256 do corpo). O arquivo gerado passa na validação do `loadScope()` sem intervenção manual.
15
+
16
+ ## Uso
17
+
18
+ ```bash
19
+ /wize-sec-scope
20
+ ```
21
+
22
+ ## Fluxo guiado
23
+
24
+ O agente faz uma pergunta por vez:
25
+
26
+ 1. **URL base do alvo** — ex: `http://localhost:8080`
27
+ 2. **Hosts adicionais no escopo** — um por linha, Enter para pular
28
+ 3. **Paths no escopo** — ex: `/api/*`, Enter para todos (`/`)
29
+ 4. **Nome para o aceite** — quem está autorizando o pentest
30
+
31
+ Ao final, gera `scope.md` com:
32
+
33
+ - Frontmatter: `accepted_by`, `accepted_at` (ISO-8601), `scope_sha256`
34
+ - Corpo: `## allowlist` com hosts, urls e paths
35
+ - `## dast_target` com a URL base
36
+ - `## notes` com o timestamp de criação
37
+
38
+ ## Re-assinatura
39
+
40
+ Se o `scope.md` já existe e foi editado, use `--sign-scope` para recomputar o hash:
41
+
42
+ ```bash
43
+ /wize-sec-pentest --sign-scope
44
+ ```
45
+
46
+ ## Script
47
+
48
+ `scripts/generate-scope.js` — gera o arquivo programaticamente (usado pelo agente ou chamado diretamente).
49
+
50
+ ```bash
51
+ node scripts/generate-scope.js --url=http://localhost:8080 --hosts=localhost,127.0.0.1 --paths=/api,/admin --accepted-by="Seu Nome"
52
+ ```
@@ -1,5 +1,7 @@
1
1
  ---
2
+
2
3
  code: wize-qa-generate-e2e-tests
4
+ description: "Use quando o UX design e PRD estiverem validados e precisar gerar casos de teste E2E a partir das telas e ACs."
3
5
  name: Generate E2E Tests
4
6
  owner: wize-agent-test-architect # Hawkeye
5
7
  status: ready
@@ -1,6 +1,9 @@
1
1
  ---
2
+
2
3
  code: wize-tea-design
4
+ description: "Use quando uma story entrar em desenvolvimento e precisar do contrato de testes (split, fixtures, mocks, assertions) que a Shuri implementará."
3
5
  name: TEA Test Design
6
+ phase: 4-implementation
4
7
  gate: design
5
8
  owner: wize-agent-test-architect # Hawkeye
6
9
  when: per-story-start
@@ -1,6 +1,9 @@
1
1
  ---
2
+
2
3
  code: wize-tea-gate
4
+ description: "Use quando uma story chegar ao final e precisar da decisão de gate (PASS/CONCERNS/FAIL/WAIVED) com rationale documentado."
3
5
  name: TEA Gate Decision
6
+ phase: 4-implementation
4
7
  gate: gate
5
8
  owner: wize-agent-test-architect # Hawkeye
6
9
  when: story-final
@@ -1,6 +1,9 @@
1
1
  ---
2
+
2
3
  code: wize-tea-nfr
4
+ description: "Use quando um epic estiver próximo do merge e precisar verificar se atende aos princípios de NFR definidos pelo Fury."
3
5
  name: TEA NFR Assessment
6
+ phase: 4-implementation
4
7
  gate: nfr
5
8
  owner: wize-agent-test-architect # Hawkeye
6
9
  when: pre-merge-per-epic
@@ -1,6 +1,9 @@
1
1
  ---
2
+
2
3
  code: wize-tea-review
4
+ description: "Use quando uma story terminar implementação e precisar de revisão estruturada de AC fulfillment, disciplina de teste e cobertura de risco."
3
5
  name: TEA Story Review
6
+ phase: 4-implementation
4
7
  gate: review
5
8
  owner: wize-agent-test-architect # Hawkeye
6
9
  when: story-end
@@ -1,6 +1,9 @@
1
1
  ---
2
+
2
3
  code: wize-tea-risk
4
+ description: "Use quando a arquitetura for assinada e precisar construir a matriz probabilidade × impacto que prioriza todo o trabalho de TEA."
3
5
  name: TEA Risk Profile
6
+ phase: 4-implementation
4
7
  gate: risk
5
8
  owner: wize-agent-test-architect # Hawkeye
6
9
  when: once-after-architecture
@@ -1,6 +1,9 @@
1
1
  ---
2
+
2
3
  code: wize-tea-trace
4
+ description: "Use quando uma story estiver em implementação e precisar mapear cada AC para testes concretos no repositório."
3
5
  name: TEA Traceability
6
+ phase: 4-implementation
4
7
  gate: trace
5
8
  owner: wize-agent-test-architect # Hawkeye
6
9
  when: during-or-after-implementation
@@ -1,5 +1,7 @@
1
1
  ---
2
+
2
3
  code: wize-web-deploy
4
+ description: "Use quando o projeto web estiver pronto para deploy e precisar do playbook de publicação."
3
5
  name: Web Deploy Playbook
4
6
  overlay: web
5
7
  owner: wize-agent-architect # Tony
@@ -1,5 +1,7 @@
1
1
  ---
2
+
2
3
  code: wize-web-scaffold
4
+ description: "Use quando precisar criar o scaffold inicial de um projeto web com a stack aprovada pelo Fury."
3
5
  name: Web Scaffold
4
6
  overlay: web
5
7
  owner: wize-agent-architect # Tony executes; Fury approves stack family
@@ -1,5 +1,7 @@
1
1
  ---
2
+
2
3
  code: wize-web-seo-audit
4
+ description: "Use quando o projeto web estiver no ar e precisar de auditoria de SEO."
3
5
  name: Web SEO Audit
4
6
  overlay: web
5
7
  owner: wize-agent-pm # Maria Hill commissions; Mantis + Tony execute
@@ -252,13 +252,13 @@ async function cmdDoctor({ kitRoot, projectRoot, opts = {} } = {}) {
252
252
  const age = f.days == null ? 'no last_refreshed' : `${f.days}d ago`;
253
253
  log(` ${f.name.padEnd(28)} ${age}`);
254
254
  if (f.days != null && f.days > 60) {
255
- suggestions.push({ level: 'warn', text: `\`${f.name}\` last refreshed ${f.days}d ago. Run \`wize-refresh-knowledge\` after current sprint.` });
255
+ suggestions.push({ level: 'warn', text: `\`${f.name}\` last refreshed ${f.days}d ago. Run \`/wize-refresh-knowledge\` after current sprint.` });
256
256
  }
257
257
  }
258
258
  if (knowledge.pendingLines > 0) {
259
259
  log(` _pending.md: ${knowledge.pendingLines} inline note(s) waiting consolidation`);
260
260
  if (knowledge.pendingLines >= 5) {
261
- suggestions.push({ level: 'info', text: `${knowledge.pendingLines} notes piled up in _pending.md. Time to run \`wize-refresh-knowledge\`.` });
261
+ suggestions.push({ level: 'info', text: `${knowledge.pendingLines} notes piled up in _pending.md. Time to run \`/wize-refresh-knowledge\`.` });
262
262
  }
263
263
  }
264
264
  const markerText = knowledge.toBeGeneratedMarkers > 0 ? `${knowledge.toBeGeneratedMarkers} marker(s)` : 'none';
@@ -1,32 +1,25 @@
1
1
  /*
2
2
  * Onboarding handoff — Wizer-driven triage after install.
3
3
  *
4
- * Stub: in v0.1 this just prints the first action Wizer would take.
5
- * In a real run this would be a workflow executed by the active IDE adapter.
4
+ * Returns a clean, minimal message (≤3 lines) that always ends with "→ /wize".
5
+ * The message adapts to brownfield detection and active profiles without
6
+ * turning into a wall of text.
6
7
  */
7
8
  'use strict';
8
9
 
9
10
  function compose(detection, profiles) {
10
- const lines = [
11
- '',
12
- '╭─ Wizer ─────────────────────────────────────╮',
13
- '│ Welcome back. What are we working on? │',
14
- '╰─────────────────────────────────────────────╯'
15
- ];
16
- if (detection.brownfield) {
17
- lines.push('');
18
- lines.push('I see this repo already has code. I can ask Pepper and Peggy to baseline it before we plan.');
19
- lines.push(' → /wize-document-project');
11
+ const lines = [];
12
+ const profileCodes = new Set(profiles.map(p => p.code));
13
+
14
+ if (detection && detection.brownfield) {
15
+ lines.push('Brownfield detected — baseline ready.');
16
+ }
17
+
18
+ if (profileCodes.has('security-overlay')) {
19
+ lines.push('Security pentest available (/wize-sec-recon).');
20
20
  }
21
- lines.push('');
22
- lines.push('When ready, name the next step:');
23
- lines.push(' → /wize-product-brief (Pepper)');
24
- lines.push(' → /wize-create-prd (Maria Hill, if brief exists)');
25
- lines.push(' → /wize-create-architecture (Tony, if PRD exists)');
26
- lines.push(' → /wize-quick-dev (Shuri, for small fixes)');
27
- if (profiles.find(p => p.code === 'web-overlay')) lines.push(' → /wize-web-scaffold (overlay)');
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)');
21
+
22
+ lines.push('→ /wize');
30
23
  return lines.join('\n');
31
24
  }
32
25
 
@@ -12,6 +12,32 @@ const fs = require('node:fs');
12
12
  const path = require('node:path');
13
13
  const { walkAgents, walkWorkflows, walkSkills } = require('./validators/walk.js');
14
14
 
15
+ // Shared block-scalar reader used by both readYamlField (agent.yaml) and
16
+ // readFrontmatter (skill.md / workflow.md). Returns { value, nextIndex }.
17
+ function readBlockScalar(lines, startIndex, folded) {
18
+ const collected = [];
19
+ let baseIndent = null;
20
+ let i = startIndex;
21
+ for (; i < lines.length; i++) {
22
+ const line = lines[i];
23
+ if (line.trim() === '') { collected.push(''); continue; }
24
+ const indent = line.match(/^(\s*)/)[1].length;
25
+ if (indent === 0) break; // dedent to a sibling top-level key ends the block
26
+ if (baseIndent === null) baseIndent = indent;
27
+ collected.push(line.slice(baseIndent));
28
+ }
29
+ while (collected.length && collected[collected.length - 1] === '') collected.pop();
30
+ if (folded) {
31
+ const value = collected.reduce((acc, ln, idx) => {
32
+ if (idx === 0) return ln;
33
+ if (ln === '' || collected[idx - 1] === '') return acc + '\n' + ln;
34
+ return acc + ' ' + ln;
35
+ }, '').trim();
36
+ return { value, nextIndex: i };
37
+ }
38
+ return { value: collected.join('\n').trim(), nextIndex: i };
39
+ }
40
+
15
41
  function readYamlField(content, field) {
16
42
  const lines = content.split('\n');
17
43
  const keyRe = new RegExp('^' + field + ':\\s*(.*)$');
@@ -23,27 +49,7 @@ function readYamlField(content, field) {
23
49
  // Block scalar (| literal, > folded) with optional chomp/indent indicator.
24
50
  const block = inline.match(/^([|>])[+-]?\d*\s*$/);
25
51
  if (block) {
26
- const folded = block[1] === '>';
27
- const collected = [];
28
- let baseIndent = null;
29
- for (let j = i + 1; j < lines.length; j++) {
30
- const line = lines[j];
31
- if (line.trim() === '') { collected.push(''); continue; }
32
- const indent = line.match(/^(\s*)/)[1].length;
33
- if (indent === 0) break; // dedent to a sibling top-level key ends the block
34
- if (baseIndent === null) baseIndent = indent;
35
- collected.push(line.slice(baseIndent));
36
- }
37
- while (collected.length && collected[collected.length - 1] === '') collected.pop();
38
- if (folded) {
39
- // Folded: blank line -> newline, otherwise join lines with a space.
40
- return collected.reduce((acc, ln, idx) => {
41
- if (idx === 0) return ln;
42
- if (ln === '' || collected[idx - 1] === '') return acc + '\n' + ln;
43
- return acc + ' ' + ln;
44
- }, '').trim();
45
- }
46
- return collected.join('\n').trim();
52
+ return readBlockScalar(lines, i + 1, block[1] === '>').value;
47
53
  }
48
54
 
49
55
  // Inline scalar: quoted or plain.
@@ -59,9 +65,25 @@ function readFrontmatter(content) {
59
65
  if (end === -1) return {};
60
66
  const lines = content.slice(3, end).split('\n');
61
67
  const out = {};
62
- for (const line of lines) {
68
+ for (let i = 0; i < lines.length; i++) {
69
+ const line = lines[i];
63
70
  const m = line.match(/^([a-zA-Z_][a-zA-Z0-9_-]*):\s*(.*?)\s*$/);
64
- if (m) out[m[1]] = m[2].replace(/^"|"$/g, '').replace(/^'|'$/g, '');
71
+ if (!m) continue;
72
+ const key = m[1];
73
+ const inline = m[2].trim();
74
+
75
+ // Block scalar (| literal, > folded) with optional chomp/indent indicator.
76
+ const block = inline.match(/^([|>])[+-]?\d*\s*$/);
77
+ if (block) {
78
+ const result = readBlockScalar(lines, i + 1, block[1] === '>');
79
+ out[key] = result.value;
80
+ i = result.nextIndex - 1; // -1 because the for loop will increment
81
+ continue;
82
+ }
83
+
84
+ // Inline scalar: quoted or plain.
85
+ const q = inline.match(/^"([^"]*)"$/) || inline.match(/^'([^']*)'$/);
86
+ out[key] = (q ? q[1] : inline).trim();
65
87
  }
66
88
  return out;
67
89
  }
@@ -154,7 +176,7 @@ function collectAssets(kitRoot, { profiles = ['core'] } = {}) {
154
176
  code: fm.code,
155
177
  name: fm.name || fm.code,
156
178
  title: fm.phase || fm.gate || '',
157
- description: `${fm.phase || fm.gate || 'workflow'}: ${fm.name || fm.code}`,
179
+ description: fm.description || `${fm.phase || fm.gate || 'workflow'}: ${fm.name || fm.code}`,
158
180
  body: bodyAfterFrontmatter(content),
159
181
  overlay: fm.overlay || null,
160
182
  owner: fm.owner || null,
@@ -175,7 +197,7 @@ function collectAssets(kitRoot, { profiles = ['core'] } = {}) {
175
197
  code: fm.code,
176
198
  name: fm.name || fm.code,
177
199
  title: fm.module || '',
178
- description: fm.module ? `${fm.module} skill: ${fm.name || fm.code}` : (fm.name || fm.code),
200
+ description: fm.description || (fm.module ? `${fm.module} skill: ${fm.name || fm.code}` : (fm.name || fm.code)),
179
201
  body: bodyAfterFrontmatter(content),
180
202
  overlay: fm.overlay || null,
181
203
  owner: fm.owner || null,
@@ -272,8 +294,8 @@ function renderAgentsMd(kitRoot, projectRoot, opts = {}) {
272
294
  'instructions and persistent memory — not background reading. Read project state before',
273
295
  'acting; write what you change back into `.wize/` so the next session inherits it.',
274
296
  '',
275
- 'Before editing, classify the demand via `/wize-help`: **Quick Dev** (small, predictable,',
276
- '~≤1h, no new feature / architecture / UX / security) or **Full Lifecycle**. Never pick',
297
+ 'Before editing, classify the demand via `/wize` (or `/wize-help`): **Quick Dev** (small, predictable,',
298
+ 'trivially scoped, no new feature / architecture / UX / security) or **Full Lifecycle**. Never pick',
277
299
  'Quick Dev just to skip artifacts.',
278
300
  '',
279
301
  'When a skill fans out to subagents, match the model tier to the task: a lightweight tier',
@@ -288,7 +310,7 @@ function renderAgentsMd(kitRoot, projectRoot, opts = {}) {
288
310
  const optIn = a.code.startsWith('wize-sec-') ? ' _(security-overlay, opt-in)_' : '';
289
311
  lines.push(`- **${a.name}** (\`${a.code}\`)${optIn} — ${a.title}. ${clipOneLine(a.description, 180)}`);
290
312
  }
291
- lines.push('', '## Where to start', '', 'Activate the orchestrator: `wize-orchestrator` (Wizer). Then ask `/wize-help`.', '');
313
+ lines.push('', '## Where to start', '', 'Activate the orchestrator: `/wize` (or `/wize-help`). Wizer will guide you.', '');
292
314
 
293
315
  if (opts.dryRun) return { written: ['[dry-run] AGENTS.md'], skipped: [] };
294
316
  fs.writeFileSync(file, lines.join('\n'), 'utf-8');