bmad-plus 0.12.0 → 0.12.2
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 +612 -554
- package/README.md +557 -577
- package/osint-agent-package/agents/osint-investigator.md +12 -0
- package/osint-agent-package/skills/bmad-osint-investigate/osint/SKILL.md +491 -482
- package/osint-agent-package/skills/bmad-osint-investigate/osint/assets/dossier-template.md +126 -126
- package/osint-agent-package/skills/bmad-osint-investigate/osint/assets/lawful-basis-record.md +48 -48
- package/osint-agent-package/skills/bmad-osint-investigate/osint/references/content-extraction.md +100 -100
- package/osint-agent-package/skills/bmad-osint-investigate/osint/references/gdpr-osint.md +48 -48
- package/osint-agent-package/skills/bmad-osint-investigate/osint/references/platforms.md +130 -130
- package/osint-agent-package/skills/bmad-osint-investigate/osint/references/psychoprofile.md +69 -69
- package/osint-agent-package/skills/bmad-osint-investigate/osint/references/tools.md +281 -281
- package/osint-agent-package/skills/bmad-osint-investigate/osint/scripts/mcp-client.py +136 -136
- package/package.json +104 -91
- package/readme-international/README.de.md +596 -589
- package/readme-international/README.es.md +613 -606
- package/readme-international/README.fr.md +611 -604
- package/src/bmad-plus/agents/agent-shadow/SKILL.md +18 -0
- package/src/bmad-plus/data/role-triggers.yaml +52 -0
- package/src/bmad-plus/module.yaml +283 -283
- package/src/bmad-plus/packs/pack-animated/animated-website-agent.md +325 -325
- package/src/bmad-plus/packs/pack-animated/templates/animated-website-workflow.md +55 -55
- package/src/bmad-plus/packs/pack-backup/backup-agent.md +71 -71
- package/src/bmad-plus/packs/pack-backup/templates/backup-workflow.md +51 -51
- package/src/bmad-plus/packs/pack-dev-studio/README.md +162 -162
- package/src/bmad-plus/packs/pack-dev-studio/categories/analysis/analyst-agent.md +73 -73
- package/src/bmad-plus/packs/pack-dev-studio/categories/analysis/document-project.md +61 -61
- package/src/bmad-plus/packs/pack-dev-studio/categories/analysis/domain-research.md +95 -95
- package/src/bmad-plus/packs/pack-dev-studio/categories/analysis/market-research.md +95 -95
- package/src/bmad-plus/packs/pack-dev-studio/categories/analysis/prfaq.md +134 -134
- package/src/bmad-plus/packs/pack-dev-studio/categories/analysis/product-brief.md +80 -80
- package/src/bmad-plus/packs/pack-dev-studio/categories/analysis/tech-writer-agent.md +73 -73
- package/src/bmad-plus/packs/pack-dev-studio/categories/analysis/technical-research.md +95 -95
- package/src/bmad-plus/packs/pack-dev-studio/categories/architecture/architect-agent.md +73 -73
- package/src/bmad-plus/packs/pack-dev-studio/categories/architecture/create-architecture.md +73 -73
- package/src/bmad-plus/packs/pack-dev-studio/categories/architecture/create-epics-stories.md +92 -92
- package/src/bmad-plus/packs/pack-dev-studio/categories/architecture/generate-project-context.md +80 -80
- package/src/bmad-plus/packs/pack-dev-studio/categories/architecture/implementation-readiness.md +90 -90
- package/src/bmad-plus/packs/pack-dev-studio/categories/architecture/steps/step-01-init.md +153 -153
- package/src/bmad-plus/packs/pack-dev-studio/categories/architecture/steps/step-01b-continue.md +173 -173
- package/src/bmad-plus/packs/pack-dev-studio/categories/architecture/steps/step-02-context.md +224 -224
- package/src/bmad-plus/packs/pack-dev-studio/categories/architecture/steps/step-03-starter.md +329 -329
- package/src/bmad-plus/packs/pack-dev-studio/categories/architecture/steps/step-04-decisions.md +318 -318
- package/src/bmad-plus/packs/pack-dev-studio/categories/architecture/steps/step-05-patterns.md +359 -359
- package/src/bmad-plus/packs/pack-dev-studio/categories/architecture/steps/step-06-structure.md +379 -379
- package/src/bmad-plus/packs/pack-dev-studio/categories/architecture/steps/step-07-validation.md +361 -361
- package/src/bmad-plus/packs/pack-dev-studio/categories/architecture/steps/step-08-complete.md +81 -81
- package/src/bmad-plus/packs/pack-dev-studio/categories/implementation/checkpoint-preview.md +67 -67
- package/src/bmad-plus/packs/pack-dev-studio/categories/implementation/code-review-steps/step-01-gather-context.md +85 -85
- package/src/bmad-plus/packs/pack-dev-studio/categories/implementation/code-review-steps/step-02-review.md +35 -35
- package/src/bmad-plus/packs/pack-dev-studio/categories/implementation/code-review-steps/step-03-triage.md +49 -49
- package/src/bmad-plus/packs/pack-dev-studio/categories/implementation/code-review-steps/step-04-present.md +131 -131
- package/src/bmad-plus/packs/pack-dev-studio/categories/implementation/code-review.md +89 -89
- package/src/bmad-plus/packs/pack-dev-studio/categories/implementation/correct-course.md +300 -300
- package/src/bmad-plus/packs/pack-dev-studio/categories/implementation/create-story.md +428 -428
- package/src/bmad-plus/packs/pack-dev-studio/categories/implementation/dev-agent.md +73 -73
- package/src/bmad-plus/packs/pack-dev-studio/categories/implementation/dev-story-checklist.md +80 -80
- package/src/bmad-plus/packs/pack-dev-studio/categories/implementation/dev-story.md +484 -484
- package/src/bmad-plus/packs/pack-dev-studio/categories/implementation/investigate.md +193 -193
- package/src/bmad-plus/packs/pack-dev-studio/categories/implementation/qa-e2e-tests.md +175 -175
- package/src/bmad-plus/packs/pack-dev-studio/categories/implementation/quick-dev.md +110 -110
- package/src/bmad-plus/packs/pack-dev-studio/categories/implementation/retrospective.md +1511 -1511
- package/src/bmad-plus/packs/pack-dev-studio/categories/implementation/sprint-planning.md +298 -298
- package/src/bmad-plus/packs/pack-dev-studio/categories/implementation/sprint-status.md +296 -296
- package/src/bmad-plus/packs/pack-dev-studio/categories/planning/create-prd.md +29 -29
- package/src/bmad-plus/packs/pack-dev-studio/categories/planning/create-ux-design.md +74 -74
- package/src/bmad-plus/packs/pack-dev-studio/categories/planning/edit-prd.md +29 -29
- package/src/bmad-plus/packs/pack-dev-studio/categories/planning/pm-agent.md +73 -73
- package/src/bmad-plus/packs/pack-dev-studio/categories/planning/prd.md +89 -89
- package/src/bmad-plus/packs/pack-dev-studio/categories/planning/ux-designer-agent.md +73 -73
- package/src/bmad-plus/packs/pack-dev-studio/categories/planning/validate-prd.md +29 -29
- package/src/bmad-plus/packs/pack-dev-studio/categories/utilities/advanced-elicitation.md +141 -141
- package/src/bmad-plus/packs/pack-dev-studio/categories/utilities/adversarial-review.md +37 -37
- package/src/bmad-plus/packs/pack-dev-studio/categories/utilities/bmad-help.md +75 -75
- package/src/bmad-plus/packs/pack-dev-studio/categories/utilities/brainstorming.md +6 -6
- package/src/bmad-plus/packs/pack-dev-studio/categories/utilities/customize.md +110 -110
- package/src/bmad-plus/packs/pack-dev-studio/categories/utilities/distillator.md +176 -176
- package/src/bmad-plus/packs/pack-dev-studio/categories/utilities/edge-case-hunter.md +67 -67
- package/src/bmad-plus/packs/pack-dev-studio/categories/utilities/editorial-review-prose.md +86 -86
- package/src/bmad-plus/packs/pack-dev-studio/categories/utilities/editorial-review-structure.md +179 -179
- package/src/bmad-plus/packs/pack-dev-studio/categories/utilities/index-docs.md +66 -66
- package/src/bmad-plus/packs/pack-dev-studio/categories/utilities/party-mode.md +127 -127
- package/src/bmad-plus/packs/pack-dev-studio/categories/utilities/shard-doc.md +105 -105
- package/src/bmad-plus/packs/pack-dev-studio/dev-studio-orchestrator.md +120 -120
- package/src/bmad-plus/packs/pack-dev-studio/shared/architecture-decision-template.md +12 -12
- package/src/bmad-plus/packs/pack-dev-studio/shared/bwml-spec.md +328 -328
- package/src/bmad-plus/packs/pack-dev-studio/shared/module-help.csv +32 -32
- package/src/bmad-plus/packs/pack-dev-studio/upstream-sync.yaml +81 -81
- package/src/bmad-plus/packs/pack-memory/shared/memory-protocol.md +14 -0
- package/src/bmad-plus/packs/pack-seo/SKILL.md +171 -171
- package/src/bmad-plus/packs/pack-seo/checklist.md +140 -140
- package/src/bmad-plus/packs/pack-seo/pagespeed-playbook.md +320 -320
- package/src/bmad-plus/packs/pack-seo/ref/audit-schema.json +187 -187
- package/src/bmad-plus/packs/pack-seo/ref/cwv-thresholds.md +87 -87
- package/src/bmad-plus/packs/pack-seo/ref/eeat-criteria.md +123 -123
- package/src/bmad-plus/packs/pack-seo/ref/geo-signals.md +167 -167
- package/src/bmad-plus/packs/pack-seo/ref/hreflang-rules.md +153 -153
- package/src/bmad-plus/packs/pack-seo/ref/quality-gates.md +133 -133
- package/src/bmad-plus/packs/pack-seo/ref/schema-catalog.md +91 -91
- package/src/bmad-plus/packs/pack-seo/ref/schema-templates.json +356 -356
- package/src/bmad-plus/packs/pack-seo/requirements.txt +17 -0
- package/src/bmad-plus/packs/pack-seo/scripts/seo_apis.py +456 -0
- package/src/bmad-plus/packs/pack-seo/scripts/seo_crawl.py +359 -0
- package/src/bmad-plus/packs/pack-seo/scripts/seo_fetch.py +304 -0
- package/src/bmad-plus/packs/pack-seo/scripts/seo_parse.py +255 -0
- package/src/bmad-plus/packs/pack-seo/scripts/seo_report.py +410 -0
- package/src/bmad-plus/packs/pack-seo/scripts/seo_screenshot.py +202 -0
- package/src/bmad-plus/packs/pack-seo/seo-chief.md +294 -294
- package/src/bmad-plus/packs/pack-seo/seo-judge.md +241 -241
- package/src/bmad-plus/packs/pack-seo/seo-scout.md +171 -171
- package/src/bmad-plus/packs/pack-seo/templates/seo-audit-workflow.md +241 -241
- package/src/bmad-plus/packs/pack-shield/README.md +6 -6
- package/src/bmad-plus/packs/pack-shield/SKILL.md +2 -2
- package/src/bmad-plus/packs/pack-shield/categories/accessibility-esg/csrd-agent.md +11 -11
- package/src/bmad-plus/packs/pack-shield/categories/accessibility-esg/section508-agent.md +11 -11
- package/src/bmad-plus/packs/pack-shield/categories/accessibility-esg/wcag-agent.md +11 -11
- package/src/bmad-plus/packs/pack-shield/categories/ai-governance/eu-ai-act-agent.md +11 -11
- package/src/bmad-plus/packs/pack-shield/categories/ai-governance/iso42001-agent.md +11 -11
- package/src/bmad-plus/packs/pack-shield/categories/ai-governance/nist-ai-rmf-agent.md +11 -11
- package/src/bmad-plus/packs/pack-shield/categories/cybersecurity/cis-controls-agent.md +11 -11
- package/src/bmad-plus/packs/pack-shield/categories/cybersecurity/ism-agent.md +11 -11
- package/src/bmad-plus/packs/pack-shield/categories/cybersecurity/iso27001-agent.md +11 -11
- package/src/bmad-plus/packs/pack-shield/categories/cybersecurity/nis2-agent.md +11 -11
- package/src/bmad-plus/packs/pack-shield/categories/cybersecurity/nist-800-53-agent.md +11 -11
- package/src/bmad-plus/packs/pack-shield/categories/cybersecurity/nist-csf-agent.md +11 -11
- package/src/bmad-plus/packs/pack-shield/categories/defense-export/cmmc-agent.md +11 -11
- package/src/bmad-plus/packs/pack-shield/categories/defense-export/ear-agent.md +11 -11
- package/src/bmad-plus/packs/pack-shield/categories/defense-export/itar-agent.md +11 -11
- package/src/bmad-plus/packs/pack-shield/categories/defense-export/tsa-agent.md +11 -11
- package/src/bmad-plus/packs/pack-shield/categories/industry-compliance/dora-agent.md +11 -11
- package/src/bmad-plus/packs/pack-shield/categories/industry-compliance/fedramp-agent.md +11 -11
- package/src/bmad-plus/packs/pack-shield/categories/industry-compliance/hipaa-agent.md +11 -11
- package/src/bmad-plus/packs/pack-shield/categories/industry-compliance/pci-dss-agent.md +11 -11
- package/src/bmad-plus/packs/pack-shield/categories/industry-compliance/soc2-agent.md +11 -11
- package/src/bmad-plus/packs/pack-shield/categories/industry-compliance/swift-csp-agent.md +11 -11
- package/src/bmad-plus/packs/pack-shield/shield-orchestrator.md +1 -1
- package/tools/build/check-counts.js +628 -0
- package/tools/build/generated-adapters/.codex/AGENTS.md +1 -1
- package/tools/build/generated-adapters/.cursor/rules/bmad-plus.mdc +1 -1
- package/tools/build/generated-adapters/.opencode/AGENTS.md +1 -1
- package/tools/build/generated-adapters/AGENTS.md +1 -1
- package/tools/build/generated-adapters/CLAUDE.md +1 -1
- package/tools/build/generated-adapters/CONVENTIONS.md +1 -1
- package/tools/build/generated-adapters/GEMINI.md +1 -1
- package/tools/cli/commands/autoconfig.js +470 -472
- package/tools/cli/commands/doctor.js +233 -233
- package/tools/cli/commands/install.js +598 -495
- package/tools/cli/commands/memory-journal-cmd.js +311 -311
- package/tools/cli/commands/memory.js +195 -195
- package/tools/cli/commands/scan.js +348 -364
- package/tools/cli/commands/uninstall.js +101 -101
- package/tools/cli/commands/update.js +134 -134
- package/tools/cli/i18n.js +845 -845
- package/tools/cli/lib/README-memory-journal.md +125 -125
- package/tools/cli/lib/ide-config.js +267 -259
- package/tools/cli/lib/memory-init.js +204 -113
- package/tools/cli/lib/packs.js +209 -209
- package/tools/cli/lib/path-hash.js +39 -0
- package/tools/cli/lib/python-provision.js +508 -508
- package/tools/cli/lib/stack-detect.js +102 -102
- package/tools/cli/lib/validate.js +50 -50
|
@@ -1,102 +1,102 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* BMAD+ Stack Detection — Shared Module
|
|
3
|
-
* Unified project stack detection for autoconfig and scan commands.
|
|
4
|
-
* Merges patterns from both original implementations.
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
const path = require('node:path');
|
|
8
|
-
const fs = require('node:fs');
|
|
9
|
-
|
|
10
|
-
// ── Project Detection Markers (for scan.js) ──
|
|
11
|
-
|
|
12
|
-
const PROJECT_MARKERS = [
|
|
13
|
-
{ file: 'package.json', stack: 'Node.js', detect: (dir) => {
|
|
14
|
-
try {
|
|
15
|
-
const pkg = JSON.parse(fs.readFileSync(path.join(dir, 'package.json'), 'utf8'));
|
|
16
|
-
const deps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
17
|
-
if (deps['next']) return 'Next.js';
|
|
18
|
-
if (deps['nuxt']) return 'Nuxt';
|
|
19
|
-
if (deps['react']) return 'React';
|
|
20
|
-
if (deps['vue']) return 'Vue.js';
|
|
21
|
-
if (deps['svelte']) return 'Svelte';
|
|
22
|
-
if (deps['express']) return 'Express';
|
|
23
|
-
if (deps['fastify']) return 'Fastify';
|
|
24
|
-
if (deps['electron']) return 'Electron';
|
|
25
|
-
if (deps['tauri']) return 'Tauri';
|
|
26
|
-
return 'Node.js';
|
|
27
|
-
} catch {
|
|
28
|
-
return 'Node.js';
|
|
29
|
-
}
|
|
30
|
-
}},
|
|
31
|
-
{ file: 'Cargo.toml', stack: 'Rust' },
|
|
32
|
-
{ file: 'pyproject.toml', stack: 'Python' },
|
|
33
|
-
{ file: 'requirements.txt', stack: 'Python' },
|
|
34
|
-
{ file: 'go.mod', stack: 'Go' },
|
|
35
|
-
{ file: 'composer.json', stack: 'PHP' },
|
|
36
|
-
{ file: 'Gemfile', stack: 'Ruby' },
|
|
37
|
-
{ file: 'pom.xml', stack: 'Java' },
|
|
38
|
-
{ file: 'build.gradle', stack: 'Java/Kotlin' },
|
|
39
|
-
];
|
|
40
|
-
|
|
41
|
-
// ── Full Stack Detection (for autoconfig.js) ──
|
|
42
|
-
|
|
43
|
-
function detectStack(dir) {
|
|
44
|
-
const result = {
|
|
45
|
-
language: null,
|
|
46
|
-
framework: null,
|
|
47
|
-
runtime: null,
|
|
48
|
-
packageManager: null,
|
|
49
|
-
hasTypeScript: false,
|
|
50
|
-
};
|
|
51
|
-
|
|
52
|
-
// Package.json analysis
|
|
53
|
-
const pkgPath = path.join(dir, 'package.json');
|
|
54
|
-
if (fs.existsSync(pkgPath)) {
|
|
55
|
-
try {
|
|
56
|
-
const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
|
|
57
|
-
const deps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
58
|
-
result.runtime = 'Node.js';
|
|
59
|
-
result.language = deps['typescript'] || fs.existsSync(path.join(dir, 'tsconfig.json')) ? 'TypeScript' : 'JavaScript';
|
|
60
|
-
result.hasTypeScript = result.language === 'TypeScript';
|
|
61
|
-
|
|
62
|
-
// Framework detection
|
|
63
|
-
if (deps['next']) result.framework = 'Next.js';
|
|
64
|
-
else if (deps['nuxt']) result.framework = 'Nuxt';
|
|
65
|
-
else if (deps['@angular/core']) result.framework = 'Angular';
|
|
66
|
-
else if (deps['react']) result.framework = 'React';
|
|
67
|
-
else if (deps['vue']) result.framework = 'Vue.js';
|
|
68
|
-
else if (deps['svelte']) result.framework = 'Svelte';
|
|
69
|
-
else if (deps['express']) result.framework = 'Express';
|
|
70
|
-
else if (deps['fastify']) result.framework = 'Fastify';
|
|
71
|
-
else if (deps['hono']) result.framework = 'Hono';
|
|
72
|
-
else if (deps['electron']) result.framework = 'Electron';
|
|
73
|
-
else if (deps['tauri']) result.framework = 'Tauri';
|
|
74
|
-
else if (deps['react-native']) result.framework = 'React Native';
|
|
75
|
-
|
|
76
|
-
// Package manager
|
|
77
|
-
if (fs.existsSync(path.join(dir, 'pnpm-lock.yaml'))) result.packageManager = 'pnpm';
|
|
78
|
-
else if (fs.existsSync(path.join(dir, 'yarn.lock'))) result.packageManager = 'yarn';
|
|
79
|
-
else if (fs.existsSync(path.join(dir, 'bun.lockb'))) result.packageManager = 'bun';
|
|
80
|
-
else result.packageManager = 'npm';
|
|
81
|
-
} catch (e) {
|
|
82
|
-
console.warn('stack-detect: Failed to parse package.json in detectStack', e.message);
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
// Other languages
|
|
87
|
-
if (!result.runtime) {
|
|
88
|
-
if (fs.existsSync(path.join(dir, 'Cargo.toml'))) { result.language = 'Rust'; result.runtime = 'Rust'; }
|
|
89
|
-
else if (fs.existsSync(path.join(dir, 'pyproject.toml')) || fs.existsSync(path.join(dir, 'requirements.txt'))) { result.language = 'Python'; result.runtime = 'Python'; }
|
|
90
|
-
else if (fs.existsSync(path.join(dir, 'go.mod'))) { result.language = 'Go'; result.runtime = 'Go'; }
|
|
91
|
-
else if (fs.existsSync(path.join(dir, 'composer.json'))) { result.language = 'PHP'; result.runtime = 'PHP'; }
|
|
92
|
-
else if (fs.existsSync(path.join(dir, 'Gemfile'))) { result.language = 'Ruby'; result.runtime = 'Ruby'; }
|
|
93
|
-
else if (fs.existsSync(path.join(dir, 'pom.xml')) || fs.existsSync(path.join(dir, 'build.gradle'))) { result.language = 'Java'; result.runtime = 'JVM'; }
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
return result;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
module.exports = {
|
|
100
|
-
detectStack,
|
|
101
|
-
PROJECT_MARKERS,
|
|
102
|
-
};
|
|
1
|
+
/**
|
|
2
|
+
* BMAD+ Stack Detection — Shared Module
|
|
3
|
+
* Unified project stack detection for autoconfig and scan commands.
|
|
4
|
+
* Merges patterns from both original implementations.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const path = require('node:path');
|
|
8
|
+
const fs = require('node:fs');
|
|
9
|
+
|
|
10
|
+
// ── Project Detection Markers (for scan.js) ──
|
|
11
|
+
|
|
12
|
+
const PROJECT_MARKERS = [
|
|
13
|
+
{ file: 'package.json', stack: 'Node.js', detect: (dir) => {
|
|
14
|
+
try {
|
|
15
|
+
const pkg = JSON.parse(fs.readFileSync(path.join(dir, 'package.json'), 'utf8'));
|
|
16
|
+
const deps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
17
|
+
if (deps['next']) return 'Next.js';
|
|
18
|
+
if (deps['nuxt']) return 'Nuxt';
|
|
19
|
+
if (deps['react']) return 'React';
|
|
20
|
+
if (deps['vue']) return 'Vue.js';
|
|
21
|
+
if (deps['svelte']) return 'Svelte';
|
|
22
|
+
if (deps['express']) return 'Express';
|
|
23
|
+
if (deps['fastify']) return 'Fastify';
|
|
24
|
+
if (deps['electron']) return 'Electron';
|
|
25
|
+
if (deps['tauri']) return 'Tauri';
|
|
26
|
+
return 'Node.js';
|
|
27
|
+
} catch {
|
|
28
|
+
return 'Node.js';
|
|
29
|
+
}
|
|
30
|
+
}},
|
|
31
|
+
{ file: 'Cargo.toml', stack: 'Rust' },
|
|
32
|
+
{ file: 'pyproject.toml', stack: 'Python' },
|
|
33
|
+
{ file: 'requirements.txt', stack: 'Python' },
|
|
34
|
+
{ file: 'go.mod', stack: 'Go' },
|
|
35
|
+
{ file: 'composer.json', stack: 'PHP' },
|
|
36
|
+
{ file: 'Gemfile', stack: 'Ruby' },
|
|
37
|
+
{ file: 'pom.xml', stack: 'Java' },
|
|
38
|
+
{ file: 'build.gradle', stack: 'Java/Kotlin' },
|
|
39
|
+
];
|
|
40
|
+
|
|
41
|
+
// ── Full Stack Detection (for autoconfig.js) ──
|
|
42
|
+
|
|
43
|
+
function detectStack(dir) {
|
|
44
|
+
const result = {
|
|
45
|
+
language: null,
|
|
46
|
+
framework: null,
|
|
47
|
+
runtime: null,
|
|
48
|
+
packageManager: null,
|
|
49
|
+
hasTypeScript: false,
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
// Package.json analysis
|
|
53
|
+
const pkgPath = path.join(dir, 'package.json');
|
|
54
|
+
if (fs.existsSync(pkgPath)) {
|
|
55
|
+
try {
|
|
56
|
+
const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
|
|
57
|
+
const deps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
58
|
+
result.runtime = 'Node.js';
|
|
59
|
+
result.language = deps['typescript'] || fs.existsSync(path.join(dir, 'tsconfig.json')) ? 'TypeScript' : 'JavaScript';
|
|
60
|
+
result.hasTypeScript = result.language === 'TypeScript';
|
|
61
|
+
|
|
62
|
+
// Framework detection
|
|
63
|
+
if (deps['next']) result.framework = 'Next.js';
|
|
64
|
+
else if (deps['nuxt']) result.framework = 'Nuxt';
|
|
65
|
+
else if (deps['@angular/core']) result.framework = 'Angular';
|
|
66
|
+
else if (deps['react']) result.framework = 'React';
|
|
67
|
+
else if (deps['vue']) result.framework = 'Vue.js';
|
|
68
|
+
else if (deps['svelte']) result.framework = 'Svelte';
|
|
69
|
+
else if (deps['express']) result.framework = 'Express';
|
|
70
|
+
else if (deps['fastify']) result.framework = 'Fastify';
|
|
71
|
+
else if (deps['hono']) result.framework = 'Hono';
|
|
72
|
+
else if (deps['electron']) result.framework = 'Electron';
|
|
73
|
+
else if (deps['tauri']) result.framework = 'Tauri';
|
|
74
|
+
else if (deps['react-native']) result.framework = 'React Native';
|
|
75
|
+
|
|
76
|
+
// Package manager
|
|
77
|
+
if (fs.existsSync(path.join(dir, 'pnpm-lock.yaml'))) result.packageManager = 'pnpm';
|
|
78
|
+
else if (fs.existsSync(path.join(dir, 'yarn.lock'))) result.packageManager = 'yarn';
|
|
79
|
+
else if (fs.existsSync(path.join(dir, 'bun.lockb'))) result.packageManager = 'bun';
|
|
80
|
+
else result.packageManager = 'npm';
|
|
81
|
+
} catch (e) {
|
|
82
|
+
console.warn('stack-detect: Failed to parse package.json in detectStack', e.message);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// Other languages
|
|
87
|
+
if (!result.runtime) {
|
|
88
|
+
if (fs.existsSync(path.join(dir, 'Cargo.toml'))) { result.language = 'Rust'; result.runtime = 'Rust'; }
|
|
89
|
+
else if (fs.existsSync(path.join(dir, 'pyproject.toml')) || fs.existsSync(path.join(dir, 'requirements.txt'))) { result.language = 'Python'; result.runtime = 'Python'; }
|
|
90
|
+
else if (fs.existsSync(path.join(dir, 'go.mod'))) { result.language = 'Go'; result.runtime = 'Go'; }
|
|
91
|
+
else if (fs.existsSync(path.join(dir, 'composer.json'))) { result.language = 'PHP'; result.runtime = 'PHP'; }
|
|
92
|
+
else if (fs.existsSync(path.join(dir, 'Gemfile'))) { result.language = 'Ruby'; result.runtime = 'Ruby'; }
|
|
93
|
+
else if (fs.existsSync(path.join(dir, 'pom.xml')) || fs.existsSync(path.join(dir, 'build.gradle'))) { result.language = 'Java'; result.runtime = 'JVM'; }
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return result;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
module.exports = {
|
|
100
|
+
detectStack,
|
|
101
|
+
PROJECT_MARKERS,
|
|
102
|
+
};
|
|
@@ -1,50 +1,50 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* BMAD+ User Input Validation Utilities
|
|
3
|
-
* Extracted from install.js for modularity and reuse.
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
// Shell/quote metacharacters that are dangerous in user-provided names.
|
|
7
|
-
// Includes single/double quotes so a name cannot break out of a quoted context.
|
|
8
|
-
const SHELL_META = /[;&|`$(){}[\]!#~<>*?\\'"\n\r]/;
|
|
9
|
-
// Global variant used to strip EVERY occurrence during sanitization.
|
|
10
|
-
// (A non-global regex in String.replace only removes the first match.)
|
|
11
|
-
const SHELL_META_GLOBAL = /[;&|`$(){}[\]!#~<>*?\\'"\n\r]/g;
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* Validate and sanitize a user name.
|
|
15
|
-
* Rules:
|
|
16
|
-
* - Must not be empty
|
|
17
|
-
* - Must not exceed 100 characters
|
|
18
|
-
* - Must not contain shell metacharacters
|
|
19
|
-
*
|
|
20
|
-
* @param {string} rawName - Raw user-provided name
|
|
21
|
-
* @param {string} fallback - Fallback name if validation fails
|
|
22
|
-
* @returns {{ name: string, warnings: string[] }} Sanitized name and any warnings
|
|
23
|
-
*/
|
|
24
|
-
function validateUserName(rawName, fallback) {
|
|
25
|
-
const warnings = [];
|
|
26
|
-
|
|
27
|
-
if (!rawName || rawName.trim().length === 0) {
|
|
28
|
-
warnings.push('Name cannot be empty. Using default.');
|
|
29
|
-
return { name: fallback, warnings };
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
if (rawName.length > 100) {
|
|
33
|
-
warnings.push('Name too long (>100 chars). Truncating.');
|
|
34
|
-
return { name: rawName.slice(0, 100), warnings };
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
if (SHELL_META.test(rawName)) {
|
|
38
|
-
const sanitized = rawName.replace(SHELL_META_GLOBAL, '').trim() || 'Developer';
|
|
39
|
-
warnings.push('Name contains shell metacharacters. Using sanitized version.');
|
|
40
|
-
return { name: sanitized, warnings };
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
return { name: rawName, warnings };
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
module.exports = {
|
|
47
|
-
validateUserName,
|
|
48
|
-
SHELL_META,
|
|
49
|
-
SHELL_META_GLOBAL,
|
|
50
|
-
};
|
|
1
|
+
/**
|
|
2
|
+
* BMAD+ User Input Validation Utilities
|
|
3
|
+
* Extracted from install.js for modularity and reuse.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
// Shell/quote metacharacters that are dangerous in user-provided names.
|
|
7
|
+
// Includes single/double quotes so a name cannot break out of a quoted context.
|
|
8
|
+
const SHELL_META = /[;&|`$(){}[\]!#~<>*?\\'"\n\r]/;
|
|
9
|
+
// Global variant used to strip EVERY occurrence during sanitization.
|
|
10
|
+
// (A non-global regex in String.replace only removes the first match.)
|
|
11
|
+
const SHELL_META_GLOBAL = /[;&|`$(){}[\]!#~<>*?\\'"\n\r]/g;
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Validate and sanitize a user name.
|
|
15
|
+
* Rules:
|
|
16
|
+
* - Must not be empty
|
|
17
|
+
* - Must not exceed 100 characters
|
|
18
|
+
* - Must not contain shell metacharacters
|
|
19
|
+
*
|
|
20
|
+
* @param {string} rawName - Raw user-provided name
|
|
21
|
+
* @param {string} fallback - Fallback name if validation fails
|
|
22
|
+
* @returns {{ name: string, warnings: string[] }} Sanitized name and any warnings
|
|
23
|
+
*/
|
|
24
|
+
function validateUserName(rawName, fallback) {
|
|
25
|
+
const warnings = [];
|
|
26
|
+
|
|
27
|
+
if (!rawName || rawName.trim().length === 0) {
|
|
28
|
+
warnings.push('Name cannot be empty. Using default.');
|
|
29
|
+
return { name: fallback, warnings };
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
if (rawName.length > 100) {
|
|
33
|
+
warnings.push('Name too long (>100 chars). Truncating.');
|
|
34
|
+
return { name: rawName.slice(0, 100), warnings };
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
if (SHELL_META.test(rawName)) {
|
|
38
|
+
const sanitized = rawName.replace(SHELL_META_GLOBAL, '').trim() || 'Developer';
|
|
39
|
+
warnings.push('Name contains shell metacharacters. Using sanitized version.');
|
|
40
|
+
return { name: sanitized, warnings };
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return { name: rawName, warnings };
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
module.exports = {
|
|
47
|
+
validateUserName,
|
|
48
|
+
SHELL_META,
|
|
49
|
+
SHELL_META_GLOBAL,
|
|
50
|
+
};
|