agentic-sdlc-wizard 1.15.0 → 1.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,6 +1,52 @@
1
1
  # Claude Code SDLC Wizard
2
2
 
3
- A **self-evolving SDLC enforcement system for AI coding agents**. Makes Claude plan before coding, test before shipping, and ask when uncertain. Measures itself getting better over time.
3
+ A **self-evolving Software Development Life Cycle (SDLC) enforcement system for AI coding agents**. Makes Claude plan before coding, test before shipping, and ask when uncertain. Measures itself getting better over time.
4
+
5
+ ## Install
6
+
7
+ **Requires [Claude Code](https://docs.anthropic.com/en/docs/claude-code/overview)** (Anthropic's CLI for Claude).
8
+
9
+ Run from your terminal or from inside Claude Code (`!` prefix):
10
+ ```bash
11
+ npx agentic-sdlc-wizard init
12
+ ```
13
+ Then start (or restart) Claude Code — type `/exit` then `claude` to reload hooks. Setup auto-invokes on first prompt — Claude reads the wizard doc, scans your project, and generates bespoke CLAUDE.md, SDLC.md, TESTING.md, and ARCHITECTURE.md. No manual commands needed.
14
+
15
+ <details>
16
+ <summary>Alternative install methods</summary>
17
+
18
+ **From GitHub (no npm needed):**
19
+ ```bash
20
+ npx github:BaseInfinity/agentic-ai-sdlc-wizard init
21
+ ```
22
+
23
+ **Manual:** Download `CLAUDE_CODE_SDLC_WIZARD.md` to your project and tell Claude `Run the SDLC wizard setup`.
24
+ </details>
25
+
26
+ <details>
27
+ <summary>Health check & updates</summary>
28
+
29
+ ```bash
30
+ npx agentic-sdlc-wizard check # Human-readable
31
+ npx agentic-sdlc-wizard check --json # Machine-readable (CI-friendly)
32
+ ```
33
+
34
+ Reports MATCH / CUSTOMIZED / MISSING / DRIFT for every installed file. Exits non-zero on MISSING or DRIFT — use in CI to catch setup regressions.
35
+
36
+ **Check for content updates:** Tell Claude `Check if the SDLC wizard has updates` — it reads [CHANGELOG.md](CHANGELOG.md), shows what's new, and offers to apply changes.
37
+ </details>
38
+
39
+ ## Why Use This
40
+
41
+ You want Claude Code to follow engineering discipline automatically:
42
+ - **Plan before coding** (not guess-and-check)
43
+ - **Write tests first** (TDD enforced via hooks)
44
+ - **State confidence** (LOW = ask user, don't guess)
45
+ - **Track work visibly** (TaskCreate)
46
+ - **Self-review before presenting**
47
+ - **Prove it's better** (use native features unless you prove custom wins)
48
+
49
+ The wizard auto-detects your stack (package.json, test framework, deployment targets) and generates bespoke hooks + skills + docs. CI validates the generated assets; cross-stack setup-path E2E is on the [roadmap](ROADMAP.md).
4
50
 
5
51
  ## What This Actually Is
6
52
 
@@ -21,25 +67,13 @@ Layer 3: SCORING ENGINE
21
67
 
22
68
  Layer 2: ENFORCEMENT
23
69
  Hooks fire every interaction (~100 tokens).
24
- PreToolUse blocks source edits without tests.
70
+ PreToolUse reminds Claude to write tests first.
25
71
 
26
72
  Layer 1: PHILOSOPHY
27
73
  The wizard document. KISS. TDD. Confidence levels.
28
74
  Copy it, run setup, get a bespoke SDLC.
29
75
  ```
30
76
 
31
- ## Why Someone Uses This
32
-
33
- You want Claude Code to follow engineering discipline automatically:
34
- - **Plan before coding** (not guess-and-check)
35
- - **Write tests first** (TDD enforced via hooks)
36
- - **State confidence** (LOW = ask user, don't guess)
37
- - **Track work visibly** (TaskCreate)
38
- - **Self-review before presenting**
39
- - **Prove it's better** (use native features unless you prove custom wins)
40
-
41
- The wizard auto-detects your stack (package.json, test framework, deployment targets) and generates bespoke hooks + skills + docs. CI validates the generated assets; cross-stack setup-path E2E is on the [roadmap](ROADMAP.md).
42
-
43
77
  ## What Makes This Different
44
78
 
45
79
  | Capability | What It Does |
@@ -48,7 +82,7 @@ The wizard auto-detects your stack (package.json, test framework, deployment tar
48
82
  | **Before/after A/B testing** | Compares wizard changes against a baseline with 95% confidence intervals to prove improvements aren't noise |
49
83
  | **SDP normalization** | Separates "the model had a bad day" from "our SDLC broke" by cross-referencing external benchmarks |
50
84
  | **CUSUM drift detection** | Catches gradual quality decay over time — borrowed from manufacturing quality control |
51
- | **Pre-tool TDD hooks** | Claude can't write code without writing tests first enforced at the hook level, not just guidance |
85
+ | **Pre-tool TDD hooks** | Before source edits, a hook reminds Claude to write tests first. CI scoring checks whether it actually followed TDD |
52
86
  | **Self-evolving loop** | Weekly/monthly external research + CI friction signals from self-heal — you approve, the system gets better |
53
87
 
54
88
  ## How It Works
@@ -79,24 +113,6 @@ CI/CD PIPELINE
79
113
  - Model-aware: SDP adjusts for external conditions
80
114
  ```
81
115
 
82
- ## Using It
83
-
84
- **One command (recommended):**
85
- ```bash
86
- npx agentic-sdlc-wizard init
87
- ```
88
-
89
- Installs hooks, skills, settings, and the wizard doc. Then start Claude Code and tell it "Run the SDLC wizard setup" — it'll scan your project and generate bespoke CLAUDE.md, SDLC.md, TESTING.md, and ARCHITECTURE.md.
90
-
91
- **From GitHub (no npm needed):**
92
- ```bash
93
- npx github:BaseInfinity/agentic-ai-sdlc-wizard init
94
- ```
95
-
96
- **Manual:** Download `CLAUDE_CODE_SDLC_WIZARD.md` to your project and follow setup instructions inside.
97
-
98
- **Check for updates:** Ask Claude "Check if the SDLC wizard has updates" — it reads [CHANGELOG.md](CHANGELOG.md), shows what's new, and offers to apply changes (opt-in each).
99
-
100
116
  ## Self-Evolving System
101
117
 
102
118
  | Cadence | Source | Action |
@@ -148,7 +164,7 @@ Tests aren't just validation - they're the foundation everything else builds on.
148
164
  |--------|---------|-------|
149
165
  | `claude-md-management` | **Required** - CLAUDE.md maintenance | CLAUDE.md only |
150
166
  | `claude-code-setup` | Recommends automations | Recommendations |
151
- | `code-review` | PR review (optional) | PRs only |
167
+ | `code-review` | Local self-review and PR review (optional) | Local + PRs |
152
168
 
153
169
  ## Prove It's Better
154
170
 
@@ -170,7 +186,7 @@ This isn't the only Claude Code SDLC tool. Here's an honest comparison:
170
186
  |--------|------------|----------------------|-------------|
171
187
  | **Focus** | SDLC enforcement + measurement | Agent performance optimization | Plugin marketplace |
172
188
  | **Hooks** | 3 (SDLC, TDD, instructions) | 12+ (dev blocker, prettier, etc.) | Webhook watcher |
173
- | **Skills** | 2 (/sdlc, /testing) | 80+ domain-specific | 13 slash commands |
189
+ | **Skills** | 2 (/sdlc, /setup) | 80+ domain-specific | 13 slash commands |
174
190
  | **Evaluation** | 95% CI, CUSUM, SDP, Tier 1/2 | Configuration testing | skilltest framework |
175
191
  | **Self-healing** | CI auto-fix + re-trigger | No | No |
176
192
  | **Auto-updates** | Weekly CC + community scan | No | No |
@@ -2,13 +2,14 @@
2
2
  'use strict';
3
3
 
4
4
  const { version } = require('../../package.json');
5
- const { init } = require('../init');
5
+ const { init, check } = require('../init');
6
6
 
7
7
  const args = process.argv.slice(2);
8
8
 
9
9
  const flags = {
10
10
  force: args.includes('--force'),
11
11
  dryRun: args.includes('--dry-run'),
12
+ json: args.includes('--json'),
12
13
  };
13
14
 
14
15
  const command = args.find((a) => !a.startsWith('--'));
@@ -24,10 +25,12 @@ if (args.includes('--help') || args.includes('-h') || !command) {
24
25
 
25
26
  Usage:
26
27
  sdlc-wizard init [options] Install SDLC wizard into current directory
28
+ sdlc-wizard check [options] Check installation health and updates
27
29
 
28
30
  Options:
29
- --force Overwrite existing files
30
- --dry-run Preview changes without writing
31
+ --force Overwrite existing files (init only)
32
+ --dry-run Preview changes without writing (init only)
33
+ --json Output as JSON (check only)
31
34
  --version Show version
32
35
  --help Show this help
33
36
  `.trim());
@@ -42,6 +45,14 @@ if (command === 'init') {
42
45
  console.error(`Error: ${err.message}`);
43
46
  process.exit(1);
44
47
  }
48
+ } else if (command === 'check') {
49
+ try {
50
+ const { hasDrift } = check(process.cwd(), { json: flags.json });
51
+ process.exit(hasDrift ? 1 : 0);
52
+ } catch (err) {
53
+ console.error(`Error: ${err.message}`);
54
+ process.exit(1);
55
+ }
45
56
  } else {
46
57
  console.error(`Unknown command: ${command}`);
47
58
  console.error('Run "sdlc-wizard --help" for usage.');
package/cli/init.js CHANGED
@@ -1,11 +1,14 @@
1
1
  'use strict';
2
2
 
3
+ const crypto = require('crypto');
3
4
  const fs = require('fs');
4
5
  const path = require('path');
5
6
 
6
7
  const RESET = '\x1b[0m';
8
+ const RED = '\x1b[31m';
7
9
  const GREEN = '\x1b[32m';
8
10
  const YELLOW = '\x1b[33m';
11
+ const MAGENTA = '\x1b[35m';
9
12
  const CYAN = '\x1b[36m';
10
13
 
11
14
  const TEMPLATES_DIR = path.join(__dirname, 'templates');
@@ -17,19 +20,86 @@ const FILES = [
17
20
  { src: 'hooks/tdd-pretool-check.sh', dest: '.claude/hooks/tdd-pretool-check.sh', executable: true },
18
21
  { src: 'hooks/instructions-loaded-check.sh', dest: '.claude/hooks/instructions-loaded-check.sh', executable: true },
19
22
  { src: 'skills/sdlc/SKILL.md', dest: '.claude/skills/sdlc/SKILL.md' },
20
- { src: 'skills/testing/SKILL.md', dest: '.claude/skills/testing/SKILL.md' },
23
+ { src: 'skills/setup/SKILL.md', dest: '.claude/skills/setup/SKILL.md' },
24
+ { src: 'skills/update/SKILL.md', dest: '.claude/skills/update/SKILL.md' },
21
25
  ];
22
26
 
27
+ const WIZARD_HOOK_MARKERS = FILES
28
+ .filter((f) => f.executable && f.dest.startsWith('.claude/hooks/'))
29
+ .map((f) => path.basename(f.src));
30
+
23
31
  const GITIGNORE_ENTRIES = ['.claude/plans/', '.claude/settings.local.json'];
24
32
 
33
+ // Paths from previous versions that should be removed on upgrade
34
+ const OBSOLETE_PATHS = [
35
+ '.claude/skills/testing', // consolidated into /sdlc in v1.17.0
36
+ ];
37
+
38
+ function isWizardHookEntry(hookEntry) {
39
+ if (!hookEntry || !hookEntry.hooks) return false;
40
+ return hookEntry.hooks.some((h) =>
41
+ WIZARD_HOOK_MARKERS.some((marker) => h.command && h.command.includes(marker))
42
+ );
43
+ }
44
+
45
+ function mergeSettings(existingPath, templatePath, force) {
46
+ try {
47
+ const existing = JSON.parse(fs.readFileSync(existingPath, 'utf8'));
48
+ const template = JSON.parse(fs.readFileSync(templatePath, 'utf8'));
49
+
50
+ if (!existing.hooks) existing.hooks = {};
51
+
52
+ for (const [event, templateEntries] of Object.entries(template.hooks || {})) {
53
+ if (!existing.hooks[event]) {
54
+ existing.hooks[event] = templateEntries;
55
+ continue;
56
+ }
57
+
58
+ // Each template event has exactly one hook entry
59
+ const templateEntry = templateEntries[0];
60
+ const existingIdx = existing.hooks[event].findIndex(isWizardHookEntry);
61
+
62
+ if (existingIdx === -1) {
63
+ existing.hooks[event].push(templateEntry);
64
+ } else if (force) {
65
+ existing.hooks[event][existingIdx] = templateEntry;
66
+ }
67
+ }
68
+
69
+ const merged = JSON.stringify(existing, null, 2) + '\n';
70
+ const original = fs.readFileSync(existingPath, 'utf8');
71
+ return merged === original ? null : merged;
72
+ } catch (_) {
73
+ return null;
74
+ }
75
+ }
76
+
25
77
  function planOperations(targetDir, { force }) {
26
78
  const ops = [];
27
79
 
28
80
  for (const file of FILES) {
29
81
  const destPath = path.join(targetDir, file.dest);
82
+ const srcPath = path.join(TEMPLATES_DIR, file.src);
30
83
  const exists = fs.existsSync(destPath);
84
+
85
+ if (exists && file.dest === '.claude/settings.json') {
86
+ const merged = mergeSettings(destPath, srcPath, force);
87
+ if (merged) {
88
+ ops.push({
89
+ src: srcPath,
90
+ dest: destPath,
91
+ relativeDest: file.dest,
92
+ action: 'MERGE',
93
+ mergedContent: merged,
94
+ executable: false,
95
+ });
96
+ continue;
97
+ }
98
+ // Invalid JSON — fall through to normal SKIP/OVERWRITE
99
+ }
100
+
31
101
  ops.push({
32
- src: path.join(TEMPLATES_DIR, file.src),
102
+ src: srcPath,
33
103
  dest: destPath,
34
104
  relativeDest: file.dest,
35
105
  action: exists ? (force ? 'OVERWRITE' : 'SKIP') : 'CREATE',
@@ -59,13 +129,31 @@ function executeOperations(ops) {
59
129
  for (const op of ops) {
60
130
  if (op.action === 'SKIP') continue;
61
131
  ensureDir(op.dest);
62
- fs.copyFileSync(op.src, op.dest);
132
+ if (op.action === 'MERGE') {
133
+ fs.writeFileSync(op.dest, op.mergedContent);
134
+ } else {
135
+ fs.copyFileSync(op.src, op.dest);
136
+ }
63
137
  if (op.executable) {
64
138
  fs.chmodSync(op.dest, 0o755);
65
139
  }
66
140
  }
67
141
  }
68
142
 
143
+ function removeObsoletePaths(targetDir, { dryRun }) {
144
+ const removed = [];
145
+ for (const rel of OBSOLETE_PATHS) {
146
+ const fullPath = path.join(targetDir, rel);
147
+ if (fs.existsSync(fullPath)) {
148
+ if (!dryRun) {
149
+ fs.rmSync(fullPath, { recursive: true, force: true });
150
+ }
151
+ removed.push(rel);
152
+ }
153
+ }
154
+ return removed;
155
+ }
156
+
69
157
  function updateGitignore(targetDir, { dryRun }) {
70
158
  const gitignorePath = path.join(targetDir, '.gitignore');
71
159
  let content = '';
@@ -73,7 +161,8 @@ function updateGitignore(targetDir, { dryRun }) {
73
161
  content = fs.readFileSync(gitignorePath, 'utf8');
74
162
  }
75
163
 
76
- const toAdd = GITIGNORE_ENTRIES.filter((entry) => !content.includes(entry));
164
+ const lines = content.split('\n').map((l) => l.trim()).filter((l) => l && !l.startsWith('#'));
165
+ const toAdd = GITIGNORE_ENTRIES.filter((entry) => !lines.includes(entry));
77
166
  if (toAdd.length === 0) return [];
78
167
 
79
168
  if (!dryRun) {
@@ -86,7 +175,10 @@ function updateGitignore(targetDir, { dryRun }) {
86
175
 
87
176
  function printOps(ops) {
88
177
  for (const op of ops) {
89
- const color = op.action === 'CREATE' ? GREEN : op.action === 'SKIP' ? YELLOW : CYAN;
178
+ const color = op.action === 'CREATE' ? GREEN
179
+ : op.action === 'SKIP' ? YELLOW
180
+ : op.action === 'MERGE' ? MAGENTA
181
+ : CYAN;
90
182
  console.log(` ${color}${op.action}${RESET} ${op.relativeDest}`);
91
183
  }
92
184
  }
@@ -97,6 +189,10 @@ function init(targetDir, { force = false, dryRun = false } = {}) {
97
189
  if (dryRun) {
98
190
  console.log('Dry run — no files will be written:\n');
99
191
  printOps(ops);
192
+ const obsolete = removeObsoletePaths(targetDir, { dryRun: true });
193
+ for (const p of obsolete) {
194
+ console.log(` ${RED}REMOVE${RESET} ${p} (obsolete)`);
195
+ }
100
196
  const gitignoreAdds = updateGitignore(targetDir, { dryRun: true });
101
197
  if (gitignoreAdds.length > 0) {
102
198
  console.log(` ${GREEN}APPEND${RESET} .gitignore (${gitignoreAdds.join(', ')})`);
@@ -107,7 +203,13 @@ function init(targetDir, { force = false, dryRun = false } = {}) {
107
203
  console.log('');
108
204
  printOps(ops);
109
205
 
110
- if (ops.every((o) => o.action === 'SKIP')) {
206
+ // Always clean up obsolete paths, even when all managed files are SKIP
207
+ const obsolete = removeObsoletePaths(targetDir, { dryRun: false });
208
+ for (const p of obsolete) {
209
+ console.log(` ${RED}REMOVE${RESET} ${p} (obsolete)`);
210
+ }
211
+
212
+ if (ops.every((o) => o.action === 'SKIP') && obsolete.length === 0) {
111
213
  console.log('\nAll files already exist. Use --force to overwrite.');
112
214
  return true;
113
215
  }
@@ -122,10 +224,14 @@ function init(targetDir, { force = false, dryRun = false } = {}) {
122
224
  console.log(`
123
225
  ${GREEN}SDLC Wizard installed successfully!${RESET}
124
226
 
227
+ ${YELLOW}Important:${RESET} Hooks and settings load at session start.
228
+ If Claude Code is already running, type ${CYAN}/exit${RESET} then ${CYAN}claude${RESET} to restart.
229
+ (Or ${CYAN}claude --continue${RESET} to keep your conversation history.)
230
+
125
231
  Next steps:
126
- 1. Start Claude Code in this directory
127
- 2. Tell Claude: "Run the SDLC wizard setup"
128
- 3. Claude will scan your project and create CLAUDE.md, SDLC.md, TESTING.md, ARCHITECTURE.md
232
+ 1. Start Claude Code in this directory (or restart if already running)
233
+ 2. Tell Claude anything setup auto-invokes when SDLC files are missing
234
+ 3. Claude reads the wizard doc and creates CLAUDE.md, SDLC.md, TESTING.md, ARCHITECTURE.md
129
235
 
130
236
  The wizard doc is at: CLAUDE_CODE_SDLC_WIZARD.md
131
237
  `);
@@ -133,4 +239,90 @@ The wizard doc is at: CLAUDE_CODE_SDLC_WIZARD.md
133
239
  return true;
134
240
  }
135
241
 
136
- module.exports = { init, planOperations, GITIGNORE_ENTRIES };
242
+ function check(targetDir, { json = false } = {}) {
243
+ const results = [];
244
+
245
+ for (const file of FILES) {
246
+ const destPath = path.join(targetDir, file.dest);
247
+ const srcPath = path.join(TEMPLATES_DIR, file.src);
248
+ results.push(checkFile(srcPath, destPath, file.dest, file.executable || false));
249
+ }
250
+
251
+ const wizardDest = path.join(targetDir, 'CLAUDE_CODE_SDLC_WIZARD.md');
252
+ results.push(checkFile(WIZARD_DOC, wizardDest, 'CLAUDE_CODE_SDLC_WIZARD.md', false));
253
+
254
+ const gitignorePath = path.join(targetDir, '.gitignore');
255
+ results.push(checkGitignore(gitignorePath));
256
+
257
+ let updateInfo = null;
258
+ try {
259
+ const { execSync } = require('child_process');
260
+ const latest = execSync('npm view agentic-sdlc-wizard version 2>/dev/null', {
261
+ encoding: 'utf8',
262
+ timeout: 5000,
263
+ }).trim();
264
+ const current = require('../package.json').version;
265
+ if (latest !== current) {
266
+ updateInfo = { current, latest };
267
+ }
268
+ } catch (_) {
269
+ // Offline or npm unavailable — skip update check
270
+ }
271
+
272
+ const hasDrift = results.some((r) => r.status === 'MISSING' || r.status === 'DRIFT');
273
+
274
+ if (json) {
275
+ console.log(JSON.stringify({ files: results, update: updateInfo }, null, 2));
276
+ } else {
277
+ for (const r of results) {
278
+ const color = r.status === 'MATCH' ? GREEN : r.status === 'MISSING' ? RED : YELLOW;
279
+ console.log(` ${color}${r.status}${RESET} ${r.file}`);
280
+ if (r.details) console.log(` ${r.details}`);
281
+ }
282
+ if (updateInfo) {
283
+ console.log(`\n ${YELLOW}UPDATE${RESET} v${updateInfo.current} -> v${updateInfo.latest}`);
284
+ console.log(' Run: npx agentic-sdlc-wizard init --force');
285
+ }
286
+ }
287
+
288
+ return { results, updateInfo, hasDrift };
289
+ }
290
+
291
+ function checkFile(srcPath, destPath, relativeDest, shouldBeExecutable) {
292
+ if (!fs.existsSync(destPath)) {
293
+ return { file: relativeDest, status: 'MISSING' };
294
+ }
295
+ const srcHash = crypto.createHash('sha256').update(fs.readFileSync(srcPath)).digest('hex');
296
+ const destHash = crypto.createHash('sha256').update(fs.readFileSync(destPath)).digest('hex');
297
+ const result = {
298
+ file: relativeDest,
299
+ status: srcHash === destHash ? 'MATCH' : 'CUSTOMIZED',
300
+ };
301
+
302
+ if (shouldBeExecutable) {
303
+ try {
304
+ fs.accessSync(destPath, fs.constants.X_OK);
305
+ } catch (_) {
306
+ result.status = 'DRIFT';
307
+ result.details = 'Missing executable permission (chmod +x)';
308
+ }
309
+ }
310
+
311
+ return result;
312
+ }
313
+
314
+ function checkGitignore(gitignorePath) {
315
+ if (!fs.existsSync(gitignorePath)) {
316
+ return { file: '.gitignore', status: 'MISSING', details: 'No .gitignore found' };
317
+ }
318
+ const lines = fs.readFileSync(gitignorePath, 'utf8').split('\n')
319
+ .map((l) => l.trim())
320
+ .filter((l) => l && !l.startsWith('#'));
321
+ const missing = GITIGNORE_ENTRIES.filter((e) => !lines.includes(e));
322
+ if (missing.length > 0) {
323
+ return { file: '.gitignore', status: 'DRIFT', details: `Missing entries: ${missing.join(', ')}` };
324
+ }
325
+ return { file: '.gitignore', status: 'MATCH' };
326
+ }
327
+
328
+ module.exports = { init, check, planOperations, GITIGNORE_ENTRIES };
@@ -17,7 +17,7 @@ fi
17
17
 
18
18
  if [ -n "$MISSING" ]; then
19
19
  echo "WARNING: Missing SDLC wizard files: ${MISSING}"
20
- echo "Run the wizard setup to generate them."
20
+ echo "Invoke Skill tool, skill=\"setup-wizard\" to generate them."
21
21
  fi
22
22
 
23
23
  exit 0
@@ -1,6 +1,19 @@
1
1
  #!/bin/bash
2
2
  # Light SDLC hook - baseline reminder every prompt (~100 tokens)
3
- # Full guidance in skills: .claude/skills/sdlc/ and .claude/skills/testing/
3
+ # Full guidance in skill: .claude/skills/sdlc/
4
+
5
+ # Check if setup has been completed
6
+ PROJECT_DIR="${CLAUDE_PROJECT_DIR:-.}"
7
+ if [ ! -s "$PROJECT_DIR/SDLC.md" ] || [ ! -s "$PROJECT_DIR/TESTING.md" ]; then
8
+ cat << 'SETUP'
9
+ SETUP NOT COMPLETE: SDLC.md and/or TESTING.md are missing.
10
+
11
+ MANDATORY FIRST ACTION: Invoke Skill tool, skill="setup-wizard"
12
+ Do NOT proceed with any other task until setup is complete.
13
+ Tell the user: "I need to run the SDLC setup wizard first to configure your project."
14
+ SETUP
15
+ exit 0
16
+ fi
4
17
 
5
18
  cat << 'EOF'
6
19
  SDLC BASELINE:
@@ -10,10 +23,8 @@ SDLC BASELINE:
10
23
  4. FAILED 2x? STOP and ASK USER
11
24
  5. ALL TESTS MUST PASS BEFORE COMMIT - NO EXCEPTIONS
12
25
 
13
- AUTO-INVOKE SKILLS (Claude MUST do this FIRST):
14
- - implement/fix/refactor/feature/bug/build → Invoke: Skill tool, skill="sdlc"
15
- - test/TDD/write test (standalone) → Invoke: Skill tool, skill="testing"
16
- - If BOTH match (e.g., "fix the test") → sdlc takes precedence (includes TDD)
26
+ AUTO-INVOKE SKILL (Claude MUST do this FIRST):
27
+ - implement/fix/refactor/feature/bug/build/test/TDD → Invoke: Skill tool, skill="sdlc"
17
28
  - DON'T invoke for: questions, explanations, reading/exploring code, simple queries
18
29
  - DON'T wait for user to type /sdlc - AUTO-INVOKE based on task type
19
30