@kennethsolomon/shipkit 3.19.0 → 3.21.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 +36 -4
- package/package.json +1 -1
- package/skills/sk:brainstorming/SKILL.md +19 -128
- package/skills/sk:debug/SKILL.md +44 -111
- package/skills/sk:e2e/SKILL.md +45 -97
- package/skills/sk:features/SKILL.md +44 -99
- package/skills/sk:frontend-design/SKILL.md +16 -32
- package/skills/sk:laravel-init/SKILL.md +8 -7
- package/skills/sk:laravel-new/SKILL.md +1 -0
- package/skills/sk:lint/SKILL.md +42 -62
- package/skills/sk:mvp/SKILL.md +81 -134
- package/skills/sk:perf/SKILL.md +24 -43
- package/skills/sk:review/SKILL.md +57 -93
- package/skills/sk:security-check/SKILL.md +37 -43
- package/skills/sk:seo-audit/SKILL.md +75 -96
- package/skills/sk:setup-claude/SKILL.md +154 -0
- package/skills/sk:setup-claude/references/skill-profiles.md +223 -0
- package/skills/sk:setup-claude/scripts/__pycache__/apply_setup_claude.cpython-314.pyc +0 -0
- package/skills/sk:setup-claude/scripts/apply_setup_claude.py +110 -10
- package/skills/sk:setup-claude/templates/.claude/rules/laravel.md.template +14 -0
- package/skills/sk:setup-claude/templates/CLAUDE.md.template +102 -247
- package/skills/sk:setup-claude/templates/commands/brainstorm.md.template +1 -1
- package/skills/sk:setup-claude/templates/commands/execute-plan.md.template +1 -1
- package/skills/sk:setup-claude/templates/commands/finish-feature.md.template +1 -1
- package/skills/sk:setup-claude/templates/commands/security-check.md.template +1 -1
- package/skills/sk:setup-claude/templates/commands/write-plan.md.template +1 -1
- package/skills/sk:setup-claude/tests/__pycache__/test_apply_setup_claude.cpython-314.pyc +0 -0
- package/skills/sk:setup-claude/tests/test_apply_setup_claude.py +267 -0
- package/skills/sk:setup-optimizer/SKILL.md +101 -17
- package/skills/sk:skill-creator/SKILL.md +115 -226
- package/skills/sk:website/SKILL.md +81 -149
- package/skills/sk:write-tests/SKILL.md +44 -110
|
@@ -158,5 +158,272 @@ class TestApplySetupClaude(unittest.TestCase):
|
|
|
158
158
|
self.assertIn("Notes:", buf.getvalue())
|
|
159
159
|
|
|
160
160
|
|
|
161
|
+
def test_laravel_detection_inertia_react(self):
|
|
162
|
+
mod = _load_apply_module()
|
|
163
|
+
|
|
164
|
+
with tempfile.TemporaryDirectory() as td:
|
|
165
|
+
repo_root = Path(td)
|
|
166
|
+
(repo_root / "composer.json").write_text(
|
|
167
|
+
json.dumps({
|
|
168
|
+
"require": {"laravel/framework": "^12.0"},
|
|
169
|
+
"require-dev": {
|
|
170
|
+
"pestphp/pest": "^3.0",
|
|
171
|
+
"inertiajs/inertia-laravel": "^2.0",
|
|
172
|
+
},
|
|
173
|
+
}),
|
|
174
|
+
encoding="utf-8",
|
|
175
|
+
)
|
|
176
|
+
(repo_root / "package.json").write_text(
|
|
177
|
+
json.dumps({"dependencies": {"react": "^19.0"}}),
|
|
178
|
+
encoding="utf-8",
|
|
179
|
+
)
|
|
180
|
+
(repo_root / "database" / "migrations").mkdir(parents=True)
|
|
181
|
+
|
|
182
|
+
detection = mod.detect(repo_root)
|
|
183
|
+
self.assertEqual(detection.framework, "Laravel (Inertia + React)")
|
|
184
|
+
self.assertEqual(detection.language, "PHP")
|
|
185
|
+
self.assertEqual(detection.database, "Eloquent ORM")
|
|
186
|
+
self.assertEqual(detection.testing, "Pest")
|
|
187
|
+
self.assertEqual(detection.dev_cmd, "php artisan serve")
|
|
188
|
+
self.assertEqual(detection.lint_cmd, "vendor/bin/pint")
|
|
189
|
+
self.assertEqual(detection.test_cmd, "vendor/bin/pest")
|
|
190
|
+
|
|
191
|
+
def test_laravel_detection_livewire(self):
|
|
192
|
+
mod = _load_apply_module()
|
|
193
|
+
|
|
194
|
+
with tempfile.TemporaryDirectory() as td:
|
|
195
|
+
repo_root = Path(td)
|
|
196
|
+
(repo_root / "composer.json").write_text(
|
|
197
|
+
json.dumps({
|
|
198
|
+
"require": {
|
|
199
|
+
"laravel/framework": "^12.0",
|
|
200
|
+
"livewire/livewire": "^3.0",
|
|
201
|
+
},
|
|
202
|
+
}),
|
|
203
|
+
encoding="utf-8",
|
|
204
|
+
)
|
|
205
|
+
|
|
206
|
+
detection = mod.detect(repo_root)
|
|
207
|
+
self.assertEqual(detection.framework, "Laravel (Livewire)")
|
|
208
|
+
|
|
209
|
+
def test_laravel_detection_api_only(self):
|
|
210
|
+
mod = _load_apply_module()
|
|
211
|
+
|
|
212
|
+
with tempfile.TemporaryDirectory() as td:
|
|
213
|
+
repo_root = Path(td)
|
|
214
|
+
(repo_root / "composer.json").write_text(
|
|
215
|
+
json.dumps({"require": {"laravel/framework": "^12.0"}}),
|
|
216
|
+
encoding="utf-8",
|
|
217
|
+
)
|
|
218
|
+
|
|
219
|
+
detection = mod.detect(repo_root)
|
|
220
|
+
self.assertEqual(detection.framework, "Laravel (API)")
|
|
221
|
+
|
|
222
|
+
def test_mcp_json_created_for_laravel(self):
|
|
223
|
+
mod = _load_apply_module()
|
|
224
|
+
skill_root = Path(__file__).resolve().parents[1]
|
|
225
|
+
|
|
226
|
+
with tempfile.TemporaryDirectory() as td:
|
|
227
|
+
repo_root = Path(td)
|
|
228
|
+
(repo_root / "composer.json").write_text(
|
|
229
|
+
json.dumps({"require": {"laravel/framework": "^12.0"}}),
|
|
230
|
+
encoding="utf-8",
|
|
231
|
+
)
|
|
232
|
+
|
|
233
|
+
buf = io.StringIO()
|
|
234
|
+
with contextlib.redirect_stdout(buf):
|
|
235
|
+
mod.apply(
|
|
236
|
+
repo_root,
|
|
237
|
+
skill_root,
|
|
238
|
+
update_generated=False,
|
|
239
|
+
dry_run=False,
|
|
240
|
+
detection=mod.detect(repo_root),
|
|
241
|
+
)
|
|
242
|
+
|
|
243
|
+
mcp_path = repo_root / ".mcp.json"
|
|
244
|
+
self.assertTrue(mcp_path.exists())
|
|
245
|
+
mcp_data = json.loads(mcp_path.read_text(encoding="utf-8"))
|
|
246
|
+
self.assertIn("laravel-boost", mcp_data["mcpServers"])
|
|
247
|
+
self.assertEqual(mcp_data["mcpServers"]["laravel-boost"]["command"], "php")
|
|
248
|
+
|
|
249
|
+
def test_mcp_json_not_created_for_nextjs(self):
|
|
250
|
+
mod = _load_apply_module()
|
|
251
|
+
skill_root = Path(__file__).resolve().parents[1]
|
|
252
|
+
|
|
253
|
+
with tempfile.TemporaryDirectory() as td:
|
|
254
|
+
repo_root = Path(td)
|
|
255
|
+
(repo_root / "package.json").write_text(
|
|
256
|
+
json.dumps({
|
|
257
|
+
"name": "demo",
|
|
258
|
+
"dependencies": {"next": "15.0.0", "react": "19.0.0"},
|
|
259
|
+
}),
|
|
260
|
+
encoding="utf-8",
|
|
261
|
+
)
|
|
262
|
+
|
|
263
|
+
buf = io.StringIO()
|
|
264
|
+
with contextlib.redirect_stdout(buf):
|
|
265
|
+
mod.apply(
|
|
266
|
+
repo_root,
|
|
267
|
+
skill_root,
|
|
268
|
+
update_generated=False,
|
|
269
|
+
dry_run=False,
|
|
270
|
+
detection=mod.detect(repo_root),
|
|
271
|
+
)
|
|
272
|
+
|
|
273
|
+
mcp_path = repo_root / ".mcp.json"
|
|
274
|
+
if mcp_path.exists():
|
|
275
|
+
mcp_data = json.loads(mcp_path.read_text(encoding="utf-8"))
|
|
276
|
+
self.assertNotIn("laravel-boost", mcp_data.get("mcpServers", {}))
|
|
277
|
+
|
|
278
|
+
def test_mcp_json_removed_when_stack_changes(self):
|
|
279
|
+
mod = _load_apply_module()
|
|
280
|
+
skill_root = Path(__file__).resolve().parents[1]
|
|
281
|
+
|
|
282
|
+
with tempfile.TemporaryDirectory() as td:
|
|
283
|
+
repo_root = Path(td)
|
|
284
|
+
|
|
285
|
+
# Start with Laravel — creates .mcp.json with laravel-boost
|
|
286
|
+
(repo_root / "composer.json").write_text(
|
|
287
|
+
json.dumps({"require": {"laravel/framework": "^12.0"}}),
|
|
288
|
+
encoding="utf-8",
|
|
289
|
+
)
|
|
290
|
+
laravel_detection = mod.detect(repo_root)
|
|
291
|
+
|
|
292
|
+
buf = io.StringIO()
|
|
293
|
+
with contextlib.redirect_stdout(buf):
|
|
294
|
+
mod.apply(
|
|
295
|
+
repo_root,
|
|
296
|
+
skill_root,
|
|
297
|
+
update_generated=False,
|
|
298
|
+
dry_run=False,
|
|
299
|
+
detection=laravel_detection,
|
|
300
|
+
)
|
|
301
|
+
|
|
302
|
+
mcp_path = repo_root / ".mcp.json"
|
|
303
|
+
self.assertTrue(mcp_path.exists())
|
|
304
|
+
mcp_data = json.loads(mcp_path.read_text(encoding="utf-8"))
|
|
305
|
+
self.assertIn("laravel-boost", mcp_data["mcpServers"])
|
|
306
|
+
|
|
307
|
+
# Switch to Next.js — laravel-boost should be removed
|
|
308
|
+
(repo_root / "composer.json").unlink()
|
|
309
|
+
(repo_root / "package.json").write_text(
|
|
310
|
+
json.dumps({
|
|
311
|
+
"name": "demo",
|
|
312
|
+
"dependencies": {"next": "15.0.0", "react": "19.0.0"},
|
|
313
|
+
}),
|
|
314
|
+
encoding="utf-8",
|
|
315
|
+
)
|
|
316
|
+
nextjs_detection = mod.detect(repo_root)
|
|
317
|
+
|
|
318
|
+
buf = io.StringIO()
|
|
319
|
+
with contextlib.redirect_stdout(buf):
|
|
320
|
+
mod.apply(
|
|
321
|
+
repo_root,
|
|
322
|
+
skill_root,
|
|
323
|
+
update_generated=False,
|
|
324
|
+
dry_run=False,
|
|
325
|
+
detection=nextjs_detection,
|
|
326
|
+
)
|
|
327
|
+
|
|
328
|
+
mcp_data = json.loads(mcp_path.read_text(encoding="utf-8"))
|
|
329
|
+
self.assertNotIn("laravel-boost", mcp_data.get("mcpServers", {}))
|
|
330
|
+
|
|
331
|
+
def test_mcp_json_sail_detection(self):
|
|
332
|
+
mod = _load_apply_module()
|
|
333
|
+
skill_root = Path(__file__).resolve().parents[1]
|
|
334
|
+
|
|
335
|
+
with tempfile.TemporaryDirectory() as td:
|
|
336
|
+
repo_root = Path(td)
|
|
337
|
+
(repo_root / "composer.json").write_text(
|
|
338
|
+
json.dumps({"require": {"laravel/framework": "^12.0"}}),
|
|
339
|
+
encoding="utf-8",
|
|
340
|
+
)
|
|
341
|
+
# Simulate Sail being present
|
|
342
|
+
(repo_root / "vendor" / "bin").mkdir(parents=True)
|
|
343
|
+
(repo_root / "vendor" / "bin" / "sail").write_text("#!/bin/sh\n", encoding="utf-8")
|
|
344
|
+
|
|
345
|
+
buf = io.StringIO()
|
|
346
|
+
with contextlib.redirect_stdout(buf):
|
|
347
|
+
mod.apply(
|
|
348
|
+
repo_root,
|
|
349
|
+
skill_root,
|
|
350
|
+
update_generated=False,
|
|
351
|
+
dry_run=False,
|
|
352
|
+
detection=mod.detect(repo_root),
|
|
353
|
+
)
|
|
354
|
+
|
|
355
|
+
mcp_path = repo_root / ".mcp.json"
|
|
356
|
+
mcp_data = json.loads(mcp_path.read_text(encoding="utf-8"))
|
|
357
|
+
self.assertEqual(
|
|
358
|
+
mcp_data["mcpServers"]["laravel-boost"]["command"],
|
|
359
|
+
"vendor/bin/sail",
|
|
360
|
+
)
|
|
361
|
+
|
|
362
|
+
def test_mcp_json_preserves_user_entries(self):
|
|
363
|
+
mod = _load_apply_module()
|
|
364
|
+
skill_root = Path(__file__).resolve().parents[1]
|
|
365
|
+
|
|
366
|
+
with tempfile.TemporaryDirectory() as td:
|
|
367
|
+
repo_root = Path(td)
|
|
368
|
+
(repo_root / "composer.json").write_text(
|
|
369
|
+
json.dumps({"require": {"laravel/framework": "^12.0"}}),
|
|
370
|
+
encoding="utf-8",
|
|
371
|
+
)
|
|
372
|
+
|
|
373
|
+
# Pre-existing user MCP entry
|
|
374
|
+
(repo_root / ".mcp.json").write_text(
|
|
375
|
+
json.dumps({
|
|
376
|
+
"mcpServers": {
|
|
377
|
+
"my-custom-server": {"command": "node", "args": ["server.js"]},
|
|
378
|
+
},
|
|
379
|
+
}),
|
|
380
|
+
encoding="utf-8",
|
|
381
|
+
)
|
|
382
|
+
|
|
383
|
+
buf = io.StringIO()
|
|
384
|
+
with contextlib.redirect_stdout(buf):
|
|
385
|
+
mod.apply(
|
|
386
|
+
repo_root,
|
|
387
|
+
skill_root,
|
|
388
|
+
update_generated=False,
|
|
389
|
+
dry_run=False,
|
|
390
|
+
detection=mod.detect(repo_root),
|
|
391
|
+
)
|
|
392
|
+
|
|
393
|
+
mcp_data = json.loads((repo_root / ".mcp.json").read_text(encoding="utf-8"))
|
|
394
|
+
self.assertIn("my-custom-server", mcp_data["mcpServers"])
|
|
395
|
+
self.assertIn("laravel-boost", mcp_data["mcpServers"])
|
|
396
|
+
|
|
397
|
+
def test_laravel_rules_filter(self):
|
|
398
|
+
mod = _load_apply_module()
|
|
399
|
+
|
|
400
|
+
with tempfile.TemporaryDirectory() as td:
|
|
401
|
+
repo_root = Path(td)
|
|
402
|
+
(repo_root / "composer.json").write_text(
|
|
403
|
+
json.dumps({"require": {"laravel/framework": "^12.0"}}),
|
|
404
|
+
encoding="utf-8",
|
|
405
|
+
)
|
|
406
|
+
detection = mod.detect(repo_root)
|
|
407
|
+
rule_filter = mod._rules_filter(detection)
|
|
408
|
+
self.assertTrue(rule_filter("laravel.md.template"))
|
|
409
|
+
self.assertTrue(rule_filter("tests.md.template"))
|
|
410
|
+
|
|
411
|
+
def test_nextjs_rules_filter_excludes_laravel(self):
|
|
412
|
+
mod = _load_apply_module()
|
|
413
|
+
|
|
414
|
+
with tempfile.TemporaryDirectory() as td:
|
|
415
|
+
repo_root = Path(td)
|
|
416
|
+
(repo_root / "package.json").write_text(
|
|
417
|
+
json.dumps({
|
|
418
|
+
"dependencies": {"next": "15.0.0", "react": "19.0.0"},
|
|
419
|
+
}),
|
|
420
|
+
encoding="utf-8",
|
|
421
|
+
)
|
|
422
|
+
detection = mod.detect(repo_root)
|
|
423
|
+
rule_filter = mod._rules_filter(detection)
|
|
424
|
+
self.assertFalse(rule_filter("laravel.md.template"))
|
|
425
|
+
self.assertTrue(rule_filter("react.md.template"))
|
|
426
|
+
|
|
427
|
+
|
|
161
428
|
if __name__ == "__main__":
|
|
162
429
|
unittest.main()
|
|
@@ -55,6 +55,89 @@ Before making any changes, runs a diagnostic pass on the existing CLAUDE.md:
|
|
|
55
55
|
|
|
56
56
|
Reports findings before proceeding. If issues are found, they inform subsequent steps.
|
|
57
57
|
|
|
58
|
+
### Step 0.5: Re-detect Stack + Sync Skills/Agents/Rules
|
|
59
|
+
|
|
60
|
+
After diagnosis, re-detect the project stack and sync installed skills, agents, and rules.
|
|
61
|
+
|
|
62
|
+
**Reference:** Read `~/.claude/skills/sk:setup-claude/references/skill-profiles.md` for the categorization matrix.
|
|
63
|
+
|
|
64
|
+
#### 1. Re-detect stack
|
|
65
|
+
|
|
66
|
+
Run the same detection logic as `sk:setup-claude` Phase 0.5:
|
|
67
|
+
- Scan for stack indicators (composer.json, package.json, go.mod, etc.)
|
|
68
|
+
- Sub-detect database capability (Prisma, Drizzle, Laravel migrations, etc.)
|
|
69
|
+
- Compare new detection against `.shipkit/config.json` current values
|
|
70
|
+
|
|
71
|
+
#### 2. Diff and display changes
|
|
72
|
+
|
|
73
|
+
If the detected stack or capabilities changed, display a diff:
|
|
74
|
+
|
|
75
|
+
```
|
|
76
|
+
Stack re-detection:
|
|
77
|
+
Stack: nextjs (unchanged)
|
|
78
|
+
Capabilities: web → web, database (prisma/schema.prisma detected)
|
|
79
|
+
|
|
80
|
+
Skill changes:
|
|
81
|
+
+ sk:schema-migrate (database capability detected)
|
|
82
|
+
No removals.
|
|
83
|
+
|
|
84
|
+
Agent changes:
|
|
85
|
+
+ database-architect (database capability detected)
|
|
86
|
+
No removals.
|
|
87
|
+
|
|
88
|
+
Rule changes:
|
|
89
|
+
+ migrations.md (database paths)
|
|
90
|
+
No removals.
|
|
91
|
+
|
|
92
|
+
Project MCP changes:
|
|
93
|
+
- laravel-boost (stack is no longer laravel)
|
|
94
|
+
No additions.
|
|
95
|
+
|
|
96
|
+
Apply changes? (y/n)
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
If no changes detected, report `Stack: [stack] — no changes detected` and skip to Step 1.
|
|
100
|
+
|
|
101
|
+
#### 3. Sync on confirmation
|
|
102
|
+
|
|
103
|
+
If the user confirms:
|
|
104
|
+
|
|
105
|
+
**Skills sync:**
|
|
106
|
+
- Add newly relevant skills: copy from `~/.claude/skills/` to `.claude/skills/` in the project
|
|
107
|
+
- Remove stale skills: delete from `.claude/skills/` in the project if they no longer match the detected stack
|
|
108
|
+
- Never touch skills in `config.skills.extra` (user manually added)
|
|
109
|
+
- Never touch skills in `config.skills.disabled` (user manually excluded)
|
|
110
|
+
|
|
111
|
+
**Agent sync:**
|
|
112
|
+
- Add newly relevant agents: copy from `~/.claude/agents/` to `.claude/agents/` in the project
|
|
113
|
+
- Remove stale agents: delete from `.claude/agents/` in the project if they no longer match
|
|
114
|
+
- Never remove user-customized agents (detect via content that differs from the template — check if file hash differs from template hash, or if file contains `<!-- EDITED -->` marker)
|
|
115
|
+
|
|
116
|
+
**Rule sync:**
|
|
117
|
+
- Add newly relevant rules: copy from `~/.claude/rules/` to `.claude/rules/` in the project
|
|
118
|
+
- Remove stale rules: delete from `.claude/rules/` in the project if they no longer match
|
|
119
|
+
- Never remove user-customized rules (same detection as agents)
|
|
120
|
+
|
|
121
|
+
**Project-level MCP sync** (sole owner of `.mcp.json` managed entries — Step 1.7 only handles global MCP):
|
|
122
|
+
- Read the MCP Server → Stack Mapping from `skill-profiles.md`
|
|
123
|
+
- **Add:** MCP entries to `.mcp.json` when stack matches and entry is missing
|
|
124
|
+
- **Remove:** MCP entries from `.mcp.json` when stack no longer matches (e.g., `laravel-boost` removed if stack changed from Laravel to Next.js). Only remove entries whose key matches the mapping table — never touch other entries.
|
|
125
|
+
- **Update:** If entry exists but command is stale (e.g., Sail added/removed since last setup — `vendor/bin/sail` exists but entry uses `php`, or vice versa), update the command to match current state
|
|
126
|
+
- For Laravel Boost Sail detection: use `vendor/bin/sail` command variant if `vendor/bin/sail` exists in the project
|
|
127
|
+
|
|
128
|
+
**Config update:**
|
|
129
|
+
- Update `.shipkit/config.json` with new `stack.detected`, `stack.detected_at`, `stack.capabilities`
|
|
130
|
+
|
|
131
|
+
**CLAUDE.md commands table:**
|
|
132
|
+
- Regenerate the Commands table to list only currently installed skills
|
|
133
|
+
|
|
134
|
+
#### 4. Upgrade path handling
|
|
135
|
+
|
|
136
|
+
- If project has no `stack` field in config → treat as auto-detect (backwards compatible)
|
|
137
|
+
- If capabilities expanded (e.g., added database) → suggest new skills
|
|
138
|
+
- If capabilities reduced (e.g., removed a dependency) → suggest removing irrelevant skills
|
|
139
|
+
- Display: `Capabilities changed: [old] → [new]. [N] skills affected. Apply? (y/n)`
|
|
140
|
+
|
|
58
141
|
### Step 1: Update Workflow
|
|
59
142
|
|
|
60
143
|
If the workflow section is outdated or missing, replace it with the latest version:
|
|
@@ -173,9 +256,11 @@ After hooks deployment, check and configure LSP tooling:
|
|
|
173
256
|
|
|
174
257
|
**Idempotency:** Never overwrite existing hook files — the user may have customized them. Only deploy hooks that don't exist yet. For settings.json, merge additively.
|
|
175
258
|
|
|
176
|
-
### Step 1.7: MCP Servers & Plugin Check
|
|
259
|
+
### Step 1.7: Global MCP Servers & Plugin Check
|
|
260
|
+
|
|
261
|
+
After LSP check, verify the three recommended **global** tools are configured.
|
|
177
262
|
|
|
178
|
-
|
|
263
|
+
> **Note:** Project-level MCP (`.mcp.json`) is managed exclusively by Step 0.5 during stack sync. This step only handles global MCP/plugins.
|
|
179
264
|
|
|
180
265
|
1. **Sequential Thinking MCP** — grep `~/.mcp.json` for `sequential-thinking`
|
|
181
266
|
2. **Context7 plugin** — grep `~/.claude/settings.json` for `context7@claude-plugins-official` in `enabledPlugins`
|
|
@@ -183,7 +268,7 @@ After LSP check, verify the three recommended tools are configured:
|
|
|
183
268
|
|
|
184
269
|
**Report status and prompt:**
|
|
185
270
|
|
|
186
|
-
> "MCP/Plugins: [X/3] configured
|
|
271
|
+
> "Global MCP/Plugins: [X/3] configured
|
|
187
272
|
> sequential-thinking: [✓ configured / ✗ missing]
|
|
188
273
|
> context7: [✓ configured / ✗ missing]
|
|
189
274
|
> ccstatusline: [✓ configured / ✗ missing]
|
|
@@ -200,28 +285,27 @@ After LSP check, verify the three recommended tools are configured:
|
|
|
200
285
|
|
|
201
286
|
### Step 1.8: Agents & Rules Check
|
|
202
287
|
|
|
203
|
-
After MCP check, verify the project has
|
|
288
|
+
After MCP check, verify the project has the correct agents and rules for its detected stack.
|
|
289
|
+
|
|
290
|
+
**Reference:** Read `~/.claude/skills/sk:setup-claude/references/skill-profiles.md` for agent→stack and rule→stack mappings.
|
|
204
291
|
|
|
205
292
|
**Agents check:**
|
|
206
293
|
|
|
207
294
|
1. Check if `.claude/agents/` directory exists
|
|
208
|
-
2.
|
|
209
|
-
|
|
210
|
-
-
|
|
211
|
-
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
3. For each existing agent, check if it has `memory:` and `model:` in frontmatter (older agents may be missing these)
|
|
295
|
+
2. Read detected stack from `.shipkit/config.json` (or re-detect if not present)
|
|
296
|
+
3. Using the agent→stack mapping from `skill-profiles.md`, determine which agents this project should have:
|
|
297
|
+
- Universal agents (all projects): architect, qa-engineer, debugger, code-reviewer, security-reviewer, performance-optimizer, refactor-specialist, tech-writer, devops-engineer
|
|
298
|
+
- Stack-specific: backend-dev (backend stacks), frontend-dev (web stacks), mobile-dev (mobile stacks), database-architect (database capability)
|
|
299
|
+
4. For each expected agent, check if it exists in `.claude/agents/`
|
|
300
|
+
5. For each existing agent, check if it has `memory:` and `model:` in frontmatter (older agents may be missing these)
|
|
215
301
|
|
|
216
302
|
**Rules check:**
|
|
217
303
|
|
|
218
304
|
1. Check if `.claude/rules/` directory exists
|
|
219
|
-
2.
|
|
220
|
-
|
|
221
|
-
-
|
|
222
|
-
|
|
223
|
-
- Vue/Nuxt detected → check for `vue.md`, `tests.md`, `api.md`
|
|
224
|
-
- Any stack → check for `tests.md`
|
|
305
|
+
2. Using the rule→stack mapping from `skill-profiles.md`, determine which rules this project should have:
|
|
306
|
+
- Universal rules (all projects): tests.md, api.md
|
|
307
|
+
- Stack-specific: laravel.md (Laravel), react.md (React/Next.js), vue.md (Vue/Nuxt), migrations.md (database capability)
|
|
308
|
+
3. Check for each expected rule file
|
|
225
309
|
|
|
226
310
|
**Report status and prompt:**
|
|
227
311
|
|