wize-dev-kit 0.16.0 → 0.17.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 (235) hide show
  1. package/AGENTS.md +37 -0
  2. package/ARCH.md +77 -24
  3. package/CHANGELOG.md +14 -0
  4. package/DECISIONS.md +27 -1
  5. package/README.es.md +296 -0
  6. package/README.md +3 -2
  7. package/README.pt-BR.md +294 -0
  8. package/ROSTER.md +11 -3
  9. package/adapters/README.md +9 -7
  10. package/adapters/antigravity/README.md +5 -5
  11. package/adapters/claude-code/README.md +1 -1
  12. package/adapters/codex/README.md +5 -5
  13. package/adapters/codex/adapter.yaml +1 -1
  14. package/adapters/codex/render.js +1 -1
  15. package/adapters/continue/README.md +5 -5
  16. package/adapters/cursor/README.md +2 -2
  17. package/adapters/generic/README.md +1 -1
  18. package/adapters/hermes/README.md +23 -0
  19. package/adapters/hermes/adapter.yaml +8 -0
  20. package/adapters/hermes/render.js +17 -0
  21. package/adapters/kimi-code/README.md +5 -5
  22. package/adapters/kimi-code/render.js +2 -2
  23. package/adapters/kiro/README.md +30 -0
  24. package/adapters/kiro/adapter.yaml +8 -0
  25. package/adapters/kiro/render.js +21 -0
  26. package/adapters/opencode/README.md +3 -3
  27. package/adapters/opencode/render.js +27 -1
  28. package/adapters/windsurf/README.md +3 -3
  29. package/docs/harnesses/antigravity.md +20 -0
  30. package/docs/harnesses/antigravity.pt-BR.md +20 -0
  31. package/docs/harnesses/claude-code.md +23 -0
  32. package/docs/harnesses/claude-code.pt-BR.md +23 -0
  33. package/docs/harnesses/codex.md +21 -0
  34. package/docs/harnesses/codex.pt-BR.md +21 -0
  35. package/docs/harnesses/continue.md +21 -0
  36. package/docs/harnesses/continue.pt-BR.md +21 -0
  37. package/docs/harnesses/cursor.md +22 -0
  38. package/docs/harnesses/cursor.pt-BR.md +22 -0
  39. package/docs/harnesses/generic.md +20 -0
  40. package/docs/harnesses/generic.pt-BR.md +20 -0
  41. package/docs/harnesses/hermes.md +26 -0
  42. package/docs/harnesses/hermes.pt-BR.md +26 -0
  43. package/docs/harnesses/kimi-code.md +19 -0
  44. package/docs/harnesses/kimi-code.pt-BR.md +19 -0
  45. package/docs/harnesses/kiro.md +26 -0
  46. package/docs/harnesses/kiro.pt-BR.md +26 -0
  47. package/docs/harnesses/opencode.md +31 -0
  48. package/docs/harnesses/opencode.pt-BR.md +31 -0
  49. package/docs/harnesses/windsurf.md +22 -0
  50. package/docs/harnesses/windsurf.pt-BR.md +22 -0
  51. package/package.json +1 -1
  52. package/schemas/agent.schema.json +2 -2
  53. package/schemas/workflow.schema.json +1 -1
  54. package/src/app-overlay/wize-app-release-channels/workflow.md +2 -0
  55. package/src/app-overlay/wize-app-scaffold/workflow.md +2 -0
  56. package/src/app-overlay/wize-app-store-listing/workflow.md +2 -0
  57. package/src/builder-skills/wize-create-agent/workflow.md +2 -0
  58. package/src/builder-skills/wize-create-skill/workflow.md +2 -0
  59. package/src/builder-skills/wize-create-workflow/workflow.md +2 -0
  60. package/src/core-skills/wize-advanced-elicitation/skill.md +2 -0
  61. package/src/core-skills/wize-brainstorming/skill.md +2 -0
  62. package/src/core-skills/wize-customize/skill.md +116 -0
  63. package/src/core-skills/wize-editorial-review-prose/skill.md +94 -0
  64. package/src/core-skills/wize-editorial-review-structure/skill.md +99 -0
  65. package/src/core-skills/wize-grill/skill.md +77 -0
  66. package/src/core-skills/wize-index-docs/skill.md +119 -0
  67. package/src/core-skills/wize-pre-pr-check/skill.md +134 -0
  68. package/src/core-skills/wize-review-adversarial/skill.md +3 -0
  69. package/src/core-skills/wize-review-edge-case-hunter/skill.md +115 -0
  70. package/src/core-skills/wize-shard-doc/skill.md +2 -0
  71. package/src/core-skills/wize-spec/assets/headless-schemas.md +39 -0
  72. package/src/core-skills/wize-spec/assets/spec-template.md +40 -0
  73. package/src/core-skills/wize-spec/customize.toml +20 -0
  74. package/src/core-skills/wize-spec/skill.md +112 -0
  75. package/src/method-skills/1-analysis/wize-agent-analyst/agent.yaml +3 -0
  76. package/src/method-skills/1-analysis/wize-document-project/documentation-requirements.csv +12 -0
  77. package/src/method-skills/1-analysis/wize-document-project/templates/api-contracts-template.md +38 -0
  78. package/src/method-skills/1-analysis/wize-document-project/templates/architecture-template.md +54 -0
  79. package/src/method-skills/1-analysis/wize-document-project/templates/component-inventory-template.md +40 -0
  80. package/src/method-skills/1-analysis/wize-document-project/templates/contribution-guide-template.md +34 -0
  81. package/src/method-skills/1-analysis/wize-document-project/templates/data-models-template.md +36 -0
  82. package/src/method-skills/1-analysis/wize-document-project/templates/deep-dive-template.md +312 -0
  83. package/src/method-skills/1-analysis/wize-document-project/templates/deployment-guide-template.md +42 -0
  84. package/src/method-skills/1-analysis/wize-document-project/templates/development-guide-template.md +61 -0
  85. package/src/method-skills/1-analysis/wize-document-project/templates/index-template.md +185 -0
  86. package/src/method-skills/1-analysis/wize-document-project/templates/project-overview-template.md +110 -0
  87. package/src/method-skills/1-analysis/wize-document-project/templates/project-scan-report-schema.json +159 -0
  88. package/src/method-skills/1-analysis/wize-document-project/templates/source-tree-template.md +142 -0
  89. package/src/method-skills/1-analysis/wize-document-project/workflow.md +213 -20
  90. package/src/method-skills/1-analysis/wize-domain-research/customize.toml +14 -0
  91. package/src/method-skills/1-analysis/wize-domain-research/domain-steps/step-01-init.md +49 -0
  92. package/src/method-skills/1-analysis/wize-domain-research/domain-steps/step-02-domain-analysis.md +39 -0
  93. package/src/method-skills/1-analysis/wize-domain-research/domain-steps/step-03-competitive-landscape.md +39 -0
  94. package/src/method-skills/1-analysis/wize-domain-research/domain-steps/step-04-regulatory-focus.md +39 -0
  95. package/src/method-skills/1-analysis/wize-domain-research/domain-steps/step-05-technical-trends.md +39 -0
  96. package/src/method-skills/1-analysis/wize-domain-research/domain-steps/step-06-research-synthesis.md +43 -0
  97. package/src/method-skills/1-analysis/wize-domain-research/research.template.md +31 -0
  98. package/src/method-skills/1-analysis/wize-domain-research/workflow.md +58 -0
  99. package/src/method-skills/1-analysis/wize-market-research/customize.toml +14 -0
  100. package/src/method-skills/1-analysis/wize-market-research/research.template.md +31 -0
  101. package/src/method-skills/1-analysis/wize-market-research/steps/step-01-init.md +57 -0
  102. package/src/method-skills/1-analysis/wize-market-research/steps/step-02-customer-behavior.md +39 -0
  103. package/src/method-skills/1-analysis/wize-market-research/steps/step-03-customer-pain-points.md +37 -0
  104. package/src/method-skills/1-analysis/wize-market-research/steps/step-04-customer-decisions.md +39 -0
  105. package/src/method-skills/1-analysis/wize-market-research/steps/step-05-competitive-analysis.md +37 -0
  106. package/src/method-skills/1-analysis/wize-market-research/steps/step-06-research-completion.md +47 -0
  107. package/src/method-skills/1-analysis/wize-market-research/workflow.md +66 -0
  108. package/src/method-skills/1-analysis/wize-prfaq/workflow.md +152 -11
  109. package/src/method-skills/1-analysis/wize-product-brief/workflow.md +92 -19
  110. package/src/method-skills/1-analysis/wize-refresh-knowledge/workflow.md +129 -0
  111. package/src/method-skills/1-analysis/wize-research/workflow.md +39 -12
  112. package/src/method-skills/1-analysis/wize-technical-research/customize.toml +14 -0
  113. package/src/method-skills/1-analysis/wize-technical-research/research.template.md +31 -0
  114. package/src/method-skills/1-analysis/wize-technical-research/technical-steps/step-01-init.md +49 -0
  115. package/src/method-skills/1-analysis/wize-technical-research/technical-steps/step-02-technical-overview.md +45 -0
  116. package/src/method-skills/1-analysis/wize-technical-research/technical-steps/step-03-integration-patterns.md +39 -0
  117. package/src/method-skills/1-analysis/wize-technical-research/technical-steps/step-04-architectural-patterns.md +39 -0
  118. package/src/method-skills/1-analysis/wize-technical-research/technical-steps/step-05-implementation-research.md +42 -0
  119. package/src/method-skills/1-analysis/wize-technical-research/technical-steps/step-06-research-synthesis.md +46 -0
  120. package/src/method-skills/1-analysis/wize-technical-research/workflow.md +60 -0
  121. package/src/method-skills/1-analysis/wize-trigger-map/workflow.md +82 -16
  122. package/src/method-skills/2-plan-workflows/wize-create-prd/workflow.md +135 -23
  123. package/src/method-skills/2-plan-workflows/wize-edit-prd/workflow.md +110 -0
  124. package/src/method-skills/2-plan-workflows/wize-ux-design/workflow.md +134 -28
  125. package/src/method-skills/2-plan-workflows/wize-ux-scenarios/workflow.md +93 -15
  126. package/src/method-skills/2-plan-workflows/wize-validate-prd/workflow.md +108 -12
  127. package/src/method-skills/3-solutioning/wize-check-implementation-readiness/workflow.md +103 -11
  128. package/src/method-skills/3-solutioning/wize-create-architecture/architecture-decision-template.md +41 -0
  129. package/src/method-skills/3-solutioning/wize-create-architecture/customize.toml +20 -0
  130. package/src/method-skills/3-solutioning/wize-create-architecture/steps/step-01-init.md +95 -0
  131. package/src/method-skills/3-solutioning/wize-create-architecture/steps/step-01b-continue.md +32 -0
  132. package/src/method-skills/3-solutioning/wize-create-architecture/steps/step-02-context.md +126 -0
  133. package/src/method-skills/3-solutioning/wize-create-architecture/steps/step-03-starter.md +110 -0
  134. package/src/method-skills/3-solutioning/wize-create-architecture/steps/step-04-decisions.md +129 -0
  135. package/src/method-skills/3-solutioning/wize-create-architecture/steps/step-05-patterns.md +109 -0
  136. package/src/method-skills/3-solutioning/wize-create-architecture/steps/step-06-structure.md +97 -0
  137. package/src/method-skills/3-solutioning/wize-create-architecture/steps/step-07-validation.md +124 -0
  138. package/src/method-skills/3-solutioning/wize-create-architecture/steps/step-08-complete.md +59 -0
  139. package/src/method-skills/3-solutioning/wize-create-architecture/workflow.md +55 -48
  140. package/src/method-skills/3-solutioning/wize-create-epics-and-stories/workflow.md +154 -15
  141. package/src/method-skills/3-solutioning/wize-design-system/workflow.md +184 -22
  142. package/src/method-skills/3-solutioning/wize-nfr-principles/workflow.md +145 -17
  143. package/src/method-skills/3-solutioning/wize-project-context/workflow.md +120 -0
  144. package/src/method-skills/3-solutioning/wize-tech-vision/workflow.md +130 -22
  145. package/src/method-skills/4-implementation/wize-agent-dev/persona.md +12 -0
  146. package/src/method-skills/4-implementation/wize-changelog/workflow.md +184 -0
  147. package/src/method-skills/4-implementation/wize-checkpoint-preview/workflow.md +117 -0
  148. package/src/method-skills/4-implementation/wize-code-review/customize.toml +21 -0
  149. package/src/method-skills/4-implementation/wize-code-review/steps/step-01-gather-context.md +64 -0
  150. package/src/method-skills/4-implementation/wize-code-review/steps/step-02-review.md +40 -0
  151. package/src/method-skills/4-implementation/wize-code-review/steps/step-03-triage.md +43 -0
  152. package/src/method-skills/4-implementation/wize-code-review/steps/step-04-present.md +100 -0
  153. package/src/method-skills/4-implementation/wize-code-review/workflow.md +54 -12
  154. package/src/method-skills/4-implementation/wize-correct-course/workflow.md +93 -0
  155. package/src/method-skills/4-implementation/wize-create-story/workflow.md +154 -10
  156. package/src/method-skills/4-implementation/wize-dev-story/workflow.md +185 -17
  157. package/src/method-skills/4-implementation/wize-investigate/workflow.md +123 -0
  158. package/src/method-skills/4-implementation/wize-quick-dev/workflow.md +136 -18
  159. package/src/method-skills/4-implementation/wize-release/workflow.md +162 -0
  160. package/src/method-skills/4-implementation/wize-retrospective/workflow.md +114 -10
  161. package/src/method-skills/4-implementation/wize-sprint-planning/workflow.md +78 -11
  162. package/src/method-skills/4-implementation/wize-sprint-status/workflow.md +45 -11
  163. package/src/method-skills/module.yaml +28 -0
  164. package/src/orchestrator-skills/module.yaml +7 -1
  165. package/src/orchestrator-skills/wize/skill.md +164 -0
  166. package/src/orchestrator-skills/wize-check/skill.md +98 -0
  167. package/src/orchestrator-skills/wize-help/skill.md +227 -67
  168. package/src/orchestrator-skills/wize-onboarding/workflow.md +78 -14
  169. package/src/orchestrator-skills/wize-orchestrator/agent.yaml +2 -0
  170. package/src/orchestrator-skills/wize-orchestrator/persona.md +44 -3
  171. package/src/orchestrator-skills/wize-party-mode/workflow.md +2 -0
  172. package/src/security-overlay/_shared/allowlist.js +154 -0
  173. package/src/security-overlay/_shared/backlog.js +169 -0
  174. package/src/security-overlay/_shared/cli-runner.js +87 -0
  175. package/src/security-overlay/_shared/cvss.js +108 -0
  176. package/src/security-overlay/_shared/detect.js +125 -0
  177. package/src/security-overlay/_shared/install-script.js +205 -0
  178. package/src/security-overlay/_shared/invoke-phase.js +86 -0
  179. package/src/security-overlay/_shared/owasp.js +56 -0
  180. package/src/security-overlay/_shared/partial.js +225 -0
  181. package/src/security-overlay/_shared/preflight.js +175 -0
  182. package/src/security-overlay/_shared/scope-gate.js +172 -0
  183. package/src/security-overlay/_shared/scope-parser.js +147 -0
  184. package/src/security-overlay/agents/red-teamer/agent.yaml +54 -0
  185. package/src/security-overlay/agents/red-teamer/persona.md +49 -0
  186. package/src/security-overlay/data/common.txt +115 -0
  187. package/src/security-overlay/data/owasp-top10.json +15 -0
  188. package/src/security-overlay/data/tool-allowlist.json +31 -0
  189. package/src/security-overlay/skills/wize-sec-enumerate/scripts/run-enumerate.js +180 -0
  190. package/src/security-overlay/skills/wize-sec-enumerate/skill.md +34 -0
  191. package/src/security-overlay/skills/wize-sec-exploit/data/common.txt +117 -0
  192. package/src/security-overlay/skills/wize-sec-exploit/scripts/run-ffuf.js +147 -0
  193. package/src/security-overlay/skills/wize-sec-exploit/scripts/run-nikto.js +145 -0
  194. package/src/security-overlay/skills/wize-sec-exploit/scripts/run-nuclei.js +176 -0
  195. package/src/security-overlay/skills/wize-sec-exploit/scripts/run-sqlmap.js +139 -0
  196. package/src/security-overlay/skills/wize-sec-pentest/scripts/run-pipeline.js +184 -0
  197. package/src/security-overlay/skills/wize-sec-pentest/skill.md +54 -0
  198. package/src/security-overlay/skills/wize-sec-recon/scripts/run-gitleaks.js +139 -0
  199. package/src/security-overlay/skills/wize-sec-recon/scripts/run-osv.js +227 -0
  200. package/src/security-overlay/skills/wize-sec-recon/scripts/run-recon.js +162 -0
  201. package/src/security-overlay/skills/wize-sec-recon/skill.md +37 -0
  202. package/src/security-overlay/skills/wize-sec-report/scripts/render-report.js +1033 -0
  203. package/src/security-overlay/skills/wize-sec-scope/scripts/generate-scope.js +106 -0
  204. package/src/security-overlay/skills/wize-sec-scope/skill.md +52 -0
  205. package/src/tea-skills/wize-qa-generate-e2e-tests/workflow.md +121 -0
  206. package/src/tea-skills/wize-tea-design/workflow.md +107 -13
  207. package/src/tea-skills/wize-tea-gate/workflow.md +118 -25
  208. package/src/tea-skills/wize-tea-nfr/workflow.md +107 -14
  209. package/src/tea-skills/wize-tea-review/workflow.md +123 -13
  210. package/src/tea-skills/wize-tea-risk/workflow.md +113 -10
  211. package/src/tea-skills/wize-tea-trace/workflow.md +86 -12
  212. package/src/web-overlay/wize-web-deploy/workflow.md +2 -0
  213. package/src/web-overlay/wize-web-scaffold/workflow.md +2 -0
  214. package/src/web-overlay/wize-web-seo-audit/workflow.md +2 -0
  215. package/tools/check-eli5-all-adapters.js +3 -2
  216. package/tools/installer/baseline.js +138 -0
  217. package/tools/installer/commands/agent.js +197 -0
  218. package/tools/installer/commands/doctor.js +321 -0
  219. package/tools/installer/commands/document-project.js +93 -0
  220. package/tools/installer/commands/sync.js +45 -0
  221. package/tools/installer/commands/update.js +172 -0
  222. package/tools/installer/document-project/batch-scanner.js +93 -0
  223. package/tools/installer/document-project/classify.js +170 -0
  224. package/tools/installer/document-project/modes/deep-dive.js +196 -0
  225. package/tools/installer/document-project/modes/full-rescan.js +15 -0
  226. package/tools/installer/document-project/modes/initial-scan.js +100 -0
  227. package/tools/installer/document-project/modes/quick.js +211 -0
  228. package/tools/installer/document-project/render-index.js +101 -0
  229. package/tools/installer/document-project/state.js +110 -0
  230. package/tools/installer/onboarding.js +14 -20
  231. package/tools/installer/render-shared.js +159 -15
  232. package/tools/installer/setup-helpers.js +2 -0
  233. package/tools/installer/validators/run-all.js +3 -2
  234. package/tools/installer/version-check.js +117 -0
  235. package/tools/installer/wize-cli.js +501 -70
@@ -0,0 +1,175 @@
1
+ 'use strict';
2
+
3
+ // preflight.js — detects the host environment (OS/arch/package manager)
4
+ // and which tools from data/tool-allowlist.json are installed.
5
+ //
6
+ // Test hook: when WIZE_SEC_PREFLIGHT_OS, WIZE_SEC_PREFLIGHT_PM, and
7
+ // WIZE_SEC_PREFLIGHT_TOOLS (JSON) env vars are set, the real probes
8
+ // are skipped and the values are returned directly. This lets tests
9
+ // simulate Mac/Linux/Windows-WSL without actually running `which` etc.
10
+
11
+ const fs = require('node:fs');
12
+ const path = require('node:path');
13
+ const os = require('node:os');
14
+ const { execFileSync, spawnSync } = require('node:child_process');
15
+
16
+ const ALLOWLIST_PATH = path.join(__dirname, '..', 'data', 'tool-allowlist.json');
17
+
18
+ function readToolNames() {
19
+ try {
20
+ const data = JSON.parse(fs.readFileSync(ALLOWLIST_PATH, 'utf8'));
21
+ // Skip _schema and any non-array fields.
22
+ return Object.keys(data).filter(k => k !== '_schema' && Array.isArray(data[k]));
23
+ } catch (_) {
24
+ return [];
25
+ }
26
+ }
27
+
28
+ function detectOS() {
29
+ if (process.env.WIZE_SEC_PREFLIGHT_OS) return process.env.WIZE_SEC_PREFLIGHT_OS;
30
+ const platform = os.platform();
31
+ if (platform === 'linux') {
32
+ // Detect WSL by reading /proc/version for "Microsoft" or "WSL".
33
+ try {
34
+ const v = fs.readFileSync('/proc/version', 'utf8');
35
+ if (/microsoft|wsl/i.test(v)) return 'wsl';
36
+ } catch (_) { /* not linux */ }
37
+ return 'linux';
38
+ }
39
+ if (platform === 'darwin') return 'darwin';
40
+ if (platform === 'win32') return 'win32';
41
+ return 'linux';
42
+ }
43
+
44
+ function detectArch() {
45
+ if (process.env.WIZE_SEC_PREFLIGHT_ARCH) return process.env.WIZE_SEC_PREFLIGHT_ARCH;
46
+ return process.arch; // 'x64' | 'arm64' | 'ia32' etc.
47
+ }
48
+
49
+ function detectPackageManager(os) {
50
+ if (process.env.WIZE_SEC_PREFLIGHT_PM) return process.env.WIZE_SEC_PREFLIGHT_PM;
51
+ // Check for the most common PMs in order.
52
+ const candidates = {
53
+ linux: ['apt', 'dnf', 'pacman', 'zypper', 'apk'],
54
+ wsl: ['apt', 'dnf', 'pacman'],
55
+ darwin: ['brew'],
56
+ win32: ['scoop', 'chocolatey']
57
+ };
58
+ const list = candidates[os] || [];
59
+ for (const pm of list) {
60
+ const cmds = { apt: 'apt', dnf: 'dnf', pacman: 'pacman', zypper: 'zypper', apk: 'apk', brew: 'brew', scoop: 'scoop', chocolatey: 'choco' }[pm];
61
+ try {
62
+ execFileSync(cmds, ['--version'], { stdio: 'ignore' });
63
+ return pm;
64
+ } catch (_) { /* not present */ }
65
+ }
66
+ return 'none';
67
+ }
68
+
69
+ function whichCommand(os) {
70
+ // 'command -v' on POSIX, 'where' on Windows.
71
+ if (os === 'win32') return 'where';
72
+ return 'command';
73
+ }
74
+
75
+ function whichArg(os) {
76
+ if (os === 'win32') return [];
77
+ return ['-v'];
78
+ }
79
+
80
+ function probeWhich(name, os) {
81
+ try {
82
+ const r = spawnSync(whichCommand(os), [...whichArg(os), name], { encoding: 'utf8', timeout: 2000 });
83
+ if (r.status === 0 && r.stdout) {
84
+ return r.stdout.split('\n')[0].trim();
85
+ }
86
+ } catch (_) { /* not present */ }
87
+ return null;
88
+ }
89
+
90
+ function probeVersion(binPath, os) {
91
+ // Try common version flags. Each is a separate probe; failure is non-fatal.
92
+ const flags = ['--version', '-version', '-V', 'version'];
93
+ for (const f of flags) {
94
+ try {
95
+ const out = execFileSync(binPath, [f], { encoding: 'utf8', timeout: 2000, stdio: ['ignore', 'pipe', 'ignore'] });
96
+ const first = (out || '').split('\n')[0].trim();
97
+ if (first) return first.slice(0, 120);
98
+ } catch (_) { /* try next */ }
99
+ }
100
+ return null;
101
+ }
102
+
103
+ function detectTools(os) {
104
+ const names = readToolNames();
105
+ const tools = {};
106
+ // Initialize all tools as missing.
107
+ for (const n of names) tools[n] = { present: false };
108
+ // Test hook: parse the JSON env var. The hook marks the listed tools as
109
+ // present; everything else stays missing.
110
+ if (process.env.WIZE_SEC_PREFLIGHT_TOOLS) {
111
+ try {
112
+ const m = JSON.parse(process.env.WIZE_SEC_PREFLIGHT_TOOLS);
113
+ for (const [name, path] of Object.entries(m)) {
114
+ if (!(name in tools)) tools[name] = { present: !!path, path: path || undefined, version: null };
115
+ else {
116
+ tools[name] = { present: !!path, path: path || undefined, version: null };
117
+ }
118
+ }
119
+ } catch (_) { /* fall through to real detection */ }
120
+ return tools;
121
+ }
122
+ // Real detection.
123
+ for (const name of names) {
124
+ const p = probeWhich(name, os);
125
+ if (!p) {
126
+ tools[name] = { present: false };
127
+ } else {
128
+ tools[name] = { present: true, path: p, version: probeVersion(p, os) };
129
+ }
130
+ }
131
+ return tools;
132
+ }
133
+
134
+ function runPreflight(opts = {}) {
135
+ const os_ = detectOS();
136
+ const arch = detectArch();
137
+ const pm = detectPackageManager(os_);
138
+ const tools = detectTools(os_);
139
+ const missing = Object.entries(tools).filter(([, v]) => !v.present).map(([k]) => k);
140
+ return {
141
+ os: os_,
142
+ arch,
143
+ packageManager: pm,
144
+ tools,
145
+ missing,
146
+ node: process.version,
147
+ nodePath: process.execPath
148
+ };
149
+ }
150
+
151
+ function formatReport(p) {
152
+ const present = Object.entries(p.tools).filter(([, v]) => v.present);
153
+ const lines = [];
154
+ lines.push(`OS: ${p.os} (${p.arch})`);
155
+ lines.push(`Package manager: ${p.packageManager || 'none'}`);
156
+ lines.push(`Node: ${p.node}`);
157
+ lines.push('');
158
+ lines.push(`Tools: ${present.length} present, ${p.missing.length} missing`);
159
+ if (present.length) {
160
+ lines.push(' present:');
161
+ for (const [name, info] of present) {
162
+ const v = info.version ? ` — ${info.version}` : '';
163
+ lines.push(` ✓ ${name}${v}`);
164
+ }
165
+ }
166
+ if (p.missing.length) {
167
+ lines.push(' missing:');
168
+ for (const name of p.missing) lines.push(` ✗ ${name}`);
169
+ lines.push('');
170
+ lines.push('Run the install script (see .wize/security/install-pentest-tools.sh) to add the missing tools.');
171
+ }
172
+ return lines.join('\n');
173
+ }
174
+
175
+ module.exports = { runPreflight, formatReport, readToolNames };
@@ -0,0 +1,172 @@
1
+ 'use strict';
2
+
3
+ // scope-gate.js — single point that decides whether an offensive tool may run
4
+ // against a given target. ADR-001: this module is THE gate; skills must call
5
+ // assertTargetInScope before any execFile.
6
+ //
7
+ // Refusals (returns false) are logged to .wize/security/.refusals.log with
8
+ // ISO-8601 timestamp + target + reason. Scope validation errors (ScopeError)
9
+ // propagate — they signal an invalid scope, not a refused action.
10
+
11
+ const fs = require('node:fs');
12
+ const path = require('node:path');
13
+
14
+ const {
15
+ parseScope,
16
+ validateScope,
17
+ ScopeError
18
+ } = require('./scope-parser.js');
19
+
20
+ const REFSUAL_LOG_FILENAME = '.refusals.log';
21
+
22
+ // --- body parsing --------------------------------------------------------
23
+
24
+ // Parse the body of a scope.md into a structured allowlist. We accept the
25
+ // shape defined in ADR-002:
26
+ //
27
+ // ## allowlist
28
+ // hosts:
29
+ // - localhost
30
+ // - 127.0.0.1
31
+ // urls:
32
+ // - https://staging.example.internal/api/
33
+ // paths:
34
+ // - /api
35
+ //
36
+ // Zero-dep: each list block is matched line-by-line under its `## allowlist`
37
+ // heading until the next `##` heading or EOF. Empty / missing blocks yield
38
+ // empty arrays (which makes EVERY target fail the allowlist — fail-closed).
39
+ function parseAllowlist(body) {
40
+ const out = { hosts: [], urls: [], paths: [] };
41
+ const lines = String(body || '').split('\n');
42
+ let section = null;
43
+ let key = null;
44
+ for (const line of lines) {
45
+ const h = line.match(/^##\s+([a-zA-Z_][a-zA-Z0-9_-]*)/);
46
+ if (h) {
47
+ section = h[1] === 'allowlist' ? 'allowlist' : null;
48
+ key = null;
49
+ continue;
50
+ }
51
+ if (section !== 'allowlist') continue;
52
+ const km = line.match(/^([a-zA-Z_][a-zA-Z0-9_-]*):\s*$/);
53
+ if (km) {
54
+ const k = km[1];
55
+ if (k === 'hosts' || k === 'urls' || k === 'paths') key = k;
56
+ else key = null;
57
+ continue;
58
+ }
59
+ const lm = line.match(/^\s+-\s+(.+?)\s*$/);
60
+ if (lm && key) {
61
+ out[key].push(lm[1]);
62
+ }
63
+ }
64
+ return out;
65
+ }
66
+
67
+ // --- matching ------------------------------------------------------------
68
+
69
+ function matchHost(allowlist, host) {
70
+ return allowlist.hosts.some(h => h === host);
71
+ }
72
+
73
+ function matchUrl(allowlist, url) {
74
+ // Normalize by stripping trailing slashes so 'http://x/' and 'http://x'
75
+ // match the same prefix.
76
+ const norm = s => String(s || '').replace(/\/+$/, '');
77
+ const target = norm(url);
78
+ return allowlist.urls.some(prefix => target.startsWith(norm(prefix)));
79
+ }
80
+
81
+ function matchPath(allowlist, p) {
82
+ // The path must equal or start with one of the allowlisted paths.
83
+ return allowlist.paths.some(ap => p === ap || p.startsWith(ap.endsWith('/') ? ap : ap + '/'));
84
+ }
85
+
86
+ // --- public api ----------------------------------------------------------
87
+
88
+ // loadScope(scopePath) — load + parse + validate. On error: log refusal
89
+ // (best-effort) and rethrow. The caller (a skill) aborts on throw.
90
+ function loadScope(scopePath) {
91
+ if (!fs.existsSync(scopePath)) {
92
+ // Cannot log refusal without a known scope directory; rely on caller.
93
+ throw new ScopeError('MISSING_FILE', null,
94
+ `scope.md ausente em ${scopePath} — crie e assine em .wize/security/scope.md antes de rodar o pipeline`);
95
+ }
96
+ const text = fs.readFileSync(scopePath, 'utf8');
97
+ const scope = parseScope(text);
98
+ validateScope(scope);
99
+ return scope;
100
+ }
101
+
102
+ // assertTargetInScope(scope, target, { refusalsDir }) -> boolean.
103
+ // On refusal, writes a line to <refusalsDir>/.refusals.log and returns false.
104
+ // Throws ScopeError if `scope` itself is invalid (HASH_MISMATCH, etc.) —
105
+ // callers should treat that as abort-the-pipeline.
106
+ function assertTargetInScope(scope, target, opts = {}) {
107
+ const refusalsDir = opts.refusalsDir || path.join(process.cwd(), '.wize', 'security');
108
+
109
+ // Validate the scope up front so any tampering is surfaced loudly. We
110
+ // also log the attempt before re-throwing — an invalid scope is itself
111
+ // a refusal event that must appear in the audit trail.
112
+ try {
113
+ validateScope(scope);
114
+ } catch (err) {
115
+ if (err && err.code) {
116
+ logRefusal(refusalsDir, target || {}, `${err.code}: ${String(err.message || '').slice(0, 200)}`);
117
+ }
118
+ throw err;
119
+ }
120
+
121
+ const allowlist = parseAllowlist(scope.body);
122
+
123
+ // Evaluate each provided dimension of the target. A dimension is "in scope"
124
+ // iff it matches an allowlist entry. If the caller provides multiple
125
+ // dimensions (e.g. {host, url}), all of them must match.
126
+ const checks = [];
127
+ if (target.host) checks.push({ ok: matchHost(allowlist, target.host), why: 'host not in allowlist' });
128
+ if (target.url) checks.push({ ok: matchUrl(allowlist, target.url), why: 'url not in allowlist' });
129
+ if (target.path) checks.push({ ok: matchPath(allowlist, target.path), why: 'path not in allowlist' });
130
+
131
+ if (checks.length === 0) {
132
+ // Defensive: refusing a target we can't classify is the safe default.
133
+ logRefusal(refusalsDir, target, 'no target dimension provided');
134
+ return false;
135
+ }
136
+
137
+ const allIn = checks.every(c => c.ok);
138
+ if (!allIn) {
139
+ const reason = checks.filter(c => !c.ok).map(c => c.why).join('; ');
140
+ logRefusal(refusalsDir, target, reason);
141
+ return false;
142
+ }
143
+ return true;
144
+ }
145
+
146
+ // logRefusal(refusalsDir, target, reason) — append a YAML line to
147
+ // .wize/security/.refusals.log. Best-effort: never throws (a logging failure
148
+ // must not mask the refusal that caused it).
149
+ function logRefusal(refusalsDir, target, reason) {
150
+ try {
151
+ fs.mkdirSync(refusalsDir, { recursive: true });
152
+ const file = path.join(refusalsDir, REFSUAL_LOG_FILENAME);
153
+ const entry = [
154
+ '-',
155
+ ` timestamp: ${new Date().toISOString()}`,
156
+ ...Object.entries(target || {}).map(([k, v]) => ` ${k}: ${String(v).replace(/\n/g, ' ')}`),
157
+ ` reason: ${String(reason || 'unspecified').replace(/\n/g, ' ')}`
158
+ ].join('\n') + '\n';
159
+ fs.appendFileSync(file, entry, 'utf8');
160
+ } catch (_) {
161
+ // Intentionally swallow — refusing to crash the caller is more important
162
+ // than refusing to log. The gate decision (return false) is what matters.
163
+ }
164
+ }
165
+
166
+ module.exports = {
167
+ loadScope,
168
+ assertTargetInScope,
169
+ logRefusal,
170
+ parseAllowlist,
171
+ ScopeError
172
+ };
@@ -0,0 +1,147 @@
1
+ 'use strict';
2
+
3
+ // scope-parser.js — file-first parser/validator for `.wize/security/scope.md`.
4
+ //
5
+ // Format (ADR-002):
6
+ // ---
7
+ // accepted_by: <string>
8
+ // accepted_at: <ISO-8601>
9
+ // scope_sha256: <hex SHA-256 of the body below>
10
+ // ---
11
+ //
12
+ // ## allowlist
13
+ // ...
14
+ //
15
+ // This module is the single source of truth for parsing + validating the
16
+ // scope. Skills that touch offensive tools must call loadScope() and abort
17
+ // on any ScopeError.
18
+
19
+ const fs = require('node:fs');
20
+ const crypto = require('node:crypto');
21
+
22
+ class ScopeError extends Error {
23
+ constructor(code, field, message) {
24
+ super(message || `${code}${field ? ` (${field})` : ''}`);
25
+ this.name = 'ScopeError';
26
+ this.code = code;
27
+ this.field = field || null;
28
+ }
29
+ }
30
+
31
+ const REQUIRED_FIELDS = ['accepted_by', 'accepted_at', 'scope_sha256'];
32
+
33
+ // Split a `scope.md` text into { frontmatter, body }.
34
+ // The frontmatter is the YAML block delimited by `---` lines at the very top.
35
+ // We do NOT use a YAML library (zero-dep); we accept a flat `key: value` shape
36
+ // only, which is the entire scope of this overlay's frontmatter (ADR-002).
37
+ function parseScope(mdText) {
38
+ if (typeof mdText !== 'string' || !mdText.startsWith('---\n') && mdText !== '---') {
39
+ throw new ScopeError('INVALID_FORMAT', null,
40
+ 'scope.md must start with a YAML frontmatter block (--- on line 1)');
41
+ }
42
+ // Normalize: accept either "---\n...\n---\n\nbody" or "---\n...\n---\nbody".
43
+ // The trailing \n after the closing --- is part of the separator, NOT the body.
44
+ // This is what the user signs when they run --sign-scope (and what they
45
+ // expect when the hash is computed on the body they wrote).
46
+ const fmMatch = mdText.match(/^---\n([\s\S]*?)\n---\n/);
47
+ if (!fmMatch) {
48
+ throw new ScopeError('INVALID_FORMAT', null,
49
+ 'scope.md frontmatter is missing or not terminated by a second --- line');
50
+ }
51
+ const fmText = fmMatch[1];
52
+ const body = mdText.slice(fmMatch[0].length);
53
+
54
+ const frontmatter = {};
55
+ for (const line of fmText.split('\n')) {
56
+ const m = line.match(/^([a-zA-Z_][a-zA-Z0-9_-]*):\s*(.*?)\s*$/);
57
+ if (!m) continue;
58
+ frontmatter[m[1]] = m[2].replace(/^['"]|['"]$/g, ''); // strip wrapping quotes
59
+ }
60
+
61
+ return { frontmatter, body };
62
+ }
63
+
64
+ // Validate a parsed scope. Returns true on success; throws ScopeError otherwise.
65
+ // opts: { now?: Date } — for future `accepted_at` warning. Currently unused but
66
+ // reserved so we can add a warn() channel without breaking callers.
67
+ function validateScope(scope, opts = {}) {
68
+ if (!scope || typeof scope !== 'object') {
69
+ throw new ScopeError('INVALID_FORMAT', null, 'scope is not an object');
70
+ }
71
+ const fm = scope.frontmatter || {};
72
+ for (const field of REQUIRED_FIELDS) {
73
+ if (!fm[field] || typeof fm[field] !== 'string' || fm[field].trim() === '') {
74
+ throw new ScopeError('MISSING_FIELDS', field,
75
+ `scope.md frontmatter is missing required field "${field}" — ` +
76
+ `crie e assine com "wize-sec-pentest --sign-scope" ou preencha manualmente`);
77
+ }
78
+ }
79
+
80
+ // Hash integrity. Compute SHA-256 of the body and compare to scope_sha256.
81
+ // We re-parse the body as-is (already stripped of frontmatter) — the original
82
+ // signing was done on the raw body bytes, so byte-equality matters.
83
+ const expected = computeScopeSha256(scope.body || '');
84
+ if (expected !== fm.scope_sha256) {
85
+ throw new ScopeError('HASH_MISMATCH', 'scope_sha256',
86
+ `scope.md body was modified after acceptance (expected ${expected.slice(0, 12)}…, ` +
87
+ `got ${String(fm.scope_sha256).slice(0, 12)}…) — re-assine com "wize-sec-pentest --sign-scope"`);
88
+ }
89
+
90
+ // Soft check: accepted_at in the future is a warning, not an error.
91
+ // We don't surface the warning through this function (no logger plumbed
92
+ // here); consumers can inspect frontmatter.accepted_at themselves.
93
+
94
+ return true;
95
+ }
96
+
97
+ function computeScopeSha256(bodyText) {
98
+ return crypto.createHash('sha256').update(String(bodyText || ''), 'utf8').digest('hex');
99
+ }
100
+
101
+ // Read + parse + validate a scope.md file. The single entry point used by
102
+ // every offensive skill (AC-E02-1, AC-E02-3).
103
+ function loadScope(scopePath) {
104
+ if (!fs.existsSync(scopePath)) {
105
+ throw new ScopeError('MISSING_FILE', null,
106
+ `scope.md ausente em ${scopePath} — crie e assine em .wize/security/scope.md antes de rodar o pipeline`);
107
+ }
108
+ const text = fs.readFileSync(scopePath, 'utf8');
109
+ const scope = parseScope(text);
110
+ validateScope(scope);
111
+ return scope;
112
+ }
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
+
140
+ module.exports = {
141
+ parseScope,
142
+ validateScope,
143
+ computeScopeSha256,
144
+ loadScope,
145
+ signScope,
146
+ ScopeError
147
+ };
@@ -0,0 +1,54 @@
1
+ code: wize-sec-red-teamer
2
+ name: Natasha Romanoff
3
+ title: Security Overlay — Red-Teamer
4
+ icon: "🕷️"
5
+ team: software-development
6
+ module: security-overlay
7
+ phase: "4-implementation (per-project, gated)"
8
+
9
+ description: |
10
+ Natasha Romanoff is the red-teamer — the offensive pentester for the
11
+ security-overlay. Drives the recon -> enumerate -> exploit -> report
12
+ pipeline against targets the user has explicitly authorized in
13
+ .wize/security/scope.md. Runs inside the user's AI harness — never as a
14
+ remote service.
15
+
16
+ style:
17
+ voice: "pragmatic, direct, no-flourish pentester"
18
+ brevity: "high — finding + impact + PoC"
19
+ approach: "always asks: is this in scope, and do I have --active?"
20
+
21
+ overlay: security
22
+
23
+ skills:
24
+ - wize-sec-pentest
25
+ - wize-sec-scope
26
+
27
+ commands:
28
+ - /wize-sec-pentest
29
+ - /wize-sec-scope
30
+
31
+ inputs:
32
+ - ".wize/security/scope.md (gate of authorization)"
33
+ - ".wize/security/.tools.json (detection cache)"
34
+ - ".wize/security/.refusals.log (audit trail of refusals)"
35
+
36
+ outputs:
37
+ - ".wize/security/recon.md"
38
+ - ".wize/security/enumerate.md"
39
+ - ".wize/security/sast.md"
40
+ - ".wize/security/dast.md"
41
+ - ".wize/security/report.md"
42
+ - ".wize/security/report.html"
43
+
44
+ hand_off:
45
+ to_tea: |
46
+ Findings of severity High or Critical should be reviewable by
47
+ Hawkeye/TEA in the implementation gate of the security-overlay
48
+ itself. Natasha's results (the red-teamer's findings) are inputs to
49
+ the user's security review, NOT a substitute for it.
50
+
51
+ non_negotiables:
52
+ - "Default passive — never run an offensive tool without scope + --active."
53
+ - "Findings of secrets list file+line; the secret VALUE never appears in report.html."
54
+ - "Refusals are audited to .wize/security/.refusals.log (no silent failure)."
@@ -0,0 +1,49 @@
1
+ # Natasha Romanoff — Red-Teamer (Security Overlay)
2
+
3
+ ## Identity
4
+
5
+ I am **Natasha Romanoff**, the red-teamer. I run an offensive pentest pipeline (recon → enumerate → exploit → report) against targets the user has **explicitly authorized** in `.wize/security/scope.md`. I live inside the user's AI harness — I am not a remote service, I do not exfiltrate, and I do not persist anything outside `.wize/security/`.
6
+
7
+ I am a pentester who respects the scope. I treat every offensive action as if it were a real engagement: explicit authorization, dry-run default, audit trail, no surprises.
8
+
9
+ ## What I do
10
+
11
+ | Phase | Tooling | Output |
12
+ |---|---|---|
13
+ | **recon** | nmap | `recon.md` (ports, services) |
14
+ | **enumerate** | nuclei (passive), curl probing | `enumerate.md` (endpoints, tech) |
15
+ | **sast** | gitleaks (secrets), osv-scanner / grype (deps) | `sast.md` (findings) |
16
+ | **exploit (DAST)** | nuclei, nikto, sqlmap, ffuf | `dast.md` (findings + PoC) |
17
+ | **report** | local render (MD + HTML self-contained) | `report.md`, `report.html` |
18
+
19
+ Each phase is a standalone skill; the orchestrator `wize-sec-pentest` chains them.
20
+
21
+ ## How I work
22
+
23
+ - **Default passive.** Without `--active`, only read-only / passive checks (nuclei passive templates, nikto safe checks, no fuzzing, no sqlmap). Active exploitation requires the explicit flag.
24
+ - **Scope is the gate.** Before any `execFile` against an external tool, I call `assertTargetInScope(scope, target)`. If the target is not in the allowlist, the action is refused and logged to `.wize/security/.refusals.log`. No exceptions.
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
+ - **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
+
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
+
34
+ ## Limits
35
+
36
+ - I do NOT attack hosts, URLs, or paths outside the `scope.md` allowlist. Even with `--active`.
37
+ - I do NOT log or persist secrets (their values are redacted to `***REDACTED***` in the HTML report; the partial keeps file+line only).
38
+ - I do NOT call services outside the local machine (no telemetry, no remote reporting).
39
+ - I do NOT auto-install missing tools — I report the absence and let the user decide.
40
+
41
+ ## Hand-off to TEA
42
+
43
+ Hawkeye / TEA may review the security-overlay's own implementation (this code) in the kit's normal gates (risk / design / trace / review / gate). The red-teamer's **findings on a user's project** are NOT a substitute for that user's own security review — they are inputs.
44
+
45
+ When a finding is severity High or Critical, the orchestrator surfaces it with PoC + scope_sha256 + scope mode, so the user can act on it inside their normal review process.
46
+
47
+ ## Tone
48
+
49
+ Pragmatic. Direct. No flourish. A real pentester who respects the scope.