@kennethsolomon/shipkit 3.0.3 → 3.0.6

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.
@@ -0,0 +1,92 @@
1
+ #!/usr/bin/env python3
2
+ """Manage ShipKit project configuration."""
3
+
4
+ import json
5
+ import os
6
+ import sys
7
+ from pathlib import Path
8
+
9
+ def get_defaults():
10
+ return {
11
+ "profile": "balanced",
12
+ "auto_commit": True,
13
+ "skip_gates": [],
14
+ "coverage_threshold": 100,
15
+ "branch_pattern": "feature/{slug}",
16
+ "model_overrides": {}
17
+ }
18
+
19
+ def get_config():
20
+ """Read current config or return defaults."""
21
+ config_file = Path(".shipkit/config.json")
22
+ if config_file.exists():
23
+ try:
24
+ with open(config_file) as f:
25
+ return json.load(f)
26
+ except json.JSONDecodeError:
27
+ return get_defaults()
28
+ return get_defaults()
29
+
30
+ def get_models_for_profile(profile):
31
+ """Get model assignments for a profile."""
32
+ models = {
33
+ "full-sail": {"planning": "opus", "implementation": "opus", "audits": "opus", "gates": "sonnet"},
34
+ "quality": {"planning": "opus", "implementation": "sonnet", "audits": "sonnet", "gates": "sonnet"},
35
+ "balanced": {"planning": "sonnet", "implementation": "sonnet", "audits": "sonnet", "gates": "haiku"},
36
+ "budget": {"planning": "sonnet", "implementation": "sonnet", "audits": "haiku", "gates": "haiku"}
37
+ }
38
+ return models.get(profile, models["balanced"])
39
+
40
+ def display_config(config):
41
+ """Display current configuration in a table."""
42
+ print("\n## Current Configuration\n")
43
+ print("| Setting | Value | Description |")
44
+ print("|---------|-------|-------------|")
45
+ print(f"| `profile` | `{config['profile']}` | Model routing profile (full-sail / quality / balanced / budget) |")
46
+ print(f"| `auto_commit` | `{str(config['auto_commit']).lower()}` | Auto-run `/sk:smart-commit` after each gate passes |")
47
+ skip_gates_str = ", ".join(config['skip_gates']) if config['skip_gates'] else "(none)"
48
+ print(f"| `skip_gates` | `{skip_gates_str}` | Gates to skip |")
49
+ print(f"| `coverage_threshold` | `{config['coverage_threshold']}%` | Minimum test coverage on new code |")
50
+ print(f"| `branch_pattern` | `{config['branch_pattern']}` | Branch naming pattern |")
51
+ print(f"| `model_overrides` | `{json.dumps(config['model_overrides'])}` | Per-skill model overrides |")
52
+
53
+ profile = config['profile']
54
+ models = get_models_for_profile(profile)
55
+ print(f"\n## Model Assignments — `{profile}` profile\n")
56
+ print("| Skill group | Model |")
57
+ print("|-------------|-------|")
58
+ print(f"| brainstorm, write-plan, debug, execute-plan, review | `{models['planning']}` |")
59
+ print(f"| write-tests, frontend-design, api-design, security-check | `{models['implementation']}` |")
60
+ print(f"| perf, schema-migrate, accessibility | `{models['audits']}` |")
61
+ print(f"| lint, test | `{models['gates']}` |")
62
+ print(f"| smart-commit, branch, update-task | `haiku` |")
63
+
64
+ def save_config(config):
65
+ """Save config to .shipkit/config.json."""
66
+ Path(".shipkit").mkdir(exist_ok=True)
67
+ config_file = Path(".shipkit/config.json")
68
+
69
+ with open(config_file, "w") as f:
70
+ json.dump(config, f, indent=2)
71
+
72
+ # Add to .gitignore
73
+ gitignore = Path(".gitignore")
74
+ if gitignore.exists():
75
+ content = gitignore.read_text()
76
+ if ".shipkit/config.json" not in content:
77
+ with open(gitignore, "a") as f:
78
+ f.write("\n.shipkit/config.json\n")
79
+ else:
80
+ gitignore.write_text(".shipkit/config.json\n")
81
+
82
+ print(f"\n✅ Config saved to `.shipkit/config.json`")
83
+
84
+ def main():
85
+ config = get_config()
86
+ display_config(config)
87
+
88
+ print("\n---\n")
89
+ print("To change a setting, run: `/sk:set-profile <profile>` or edit `.shipkit/config.json` directly")
90
+
91
+ if __name__ == "__main__":
92
+ main()
@@ -1,7 +1,10 @@
1
- <!-- Generated by /sk:setup-claude -->
2
- <!-- Template Hash: 7deba6efd53c -->
1
+ ---
2
+ description: "Finalize a feature/bug-fix: changelog, arch log, verification, and PR creation."
3
+ ---
3
4
 
4
- # Finish Feature Command
5
+ # /sk:finish-feature
6
+
7
+ Finalize a feature/bug-fix branch and create a pull request.
5
8
 
6
9
  Finalize a feature/bug-fix branch: changelog, arch log, security gate, verification, and PR creation.
7
10
 
@@ -80,22 +83,24 @@ If unresolved Critical/High findings remain, warn the user before proceeding.
80
83
 
81
84
  Tests should have been created during `/sk:execute-plan`. Verify:
82
85
 
86
+ Detect the project stack from `CLAUDE.md`, `package.json`, `composer.json`, etc. before running checks.
87
+
83
88
  a) **Automated Tests**
84
- - Execute: `npm test`
89
+ - Execute the detected test runner (e.g. `npm test`, `./vendor/bin/pest`, `python -m pytest`)
85
90
  - Verify all tests pass with no failures
86
- - Check test coverage (target: >80% for new code in `Unknown` projects)
91
+ - Check test coverage (target: >80% for new code)
87
92
  - No skipped tests (`test.skip`, `it.skip`, `@skip`, etc.)
88
- - Run other CI checks: lint (`npm run lint` or equivalent), build (`npm run build` or equivalent)
93
+ - Run other CI checks: lint and build using project-detected commands
89
94
 
90
- b) **Manual Testing - Unknown / Unknown**
91
- - For frontend (Unknown): Render the component/page in browser, verify state updates work correctly, test all user interactions (clicks, form inputs, navigation), verify conditional rendering, check edge cases and error states
92
- - For backend/API (Unknown): Test HTTP status codes and responses, verify request/response bodies match spec, test error cases and input validation, check database transactions/state, verify authentication/authorization if applicable
93
- - For CLI/desktop (Unknown): Test command-line arguments and flags, verify output format and readability, test error messages and help text, check file I/O operations
94
- - Using Unknown framework: Verify test structure matches project conventions, assertions are clear and specific, setup/teardown is properly handled
95
+ b) **Manual Testing**
96
+ - For frontend (if detected): Render the component/page in browser, verify state updates work correctly, test all user interactions (clicks, form inputs, navigation), verify conditional rendering, check edge cases and error states
97
+ - For backend/API (if detected): Test HTTP status codes and responses, verify request/response bodies match spec, test error cases and input validation, check database transactions/state, verify authentication/authorization if applicable
98
+ - For CLI/desktop (if detected): Test command-line arguments and flags, verify output format and readability, test error messages and help text, check file I/O operations
99
+ - Verify test structure matches project conventions, assertions are clear and specific, setup/teardown is properly handled
95
100
 
96
101
  c) **Regression Testing**
97
102
  - Test related existing functionality to ensure no breakage
98
- - For Unknown projects: check related components/endpoints/commands work correctly
103
+ - Check related components/endpoints/commands work correctly
99
104
  - Verify no new console errors, warnings, or debug statements
100
105
  - Confirm existing tests still pass
101
106
 
@@ -104,7 +109,7 @@ If unresolved Critical/High findings remain, warn the user before proceeding.
104
109
  - Proper error handling and validation
105
110
  - No debugging code (`console.log`, `debugger`, `pdb`, `print` statements, etc.)
106
111
  - Comments explain *why*, not *what*
107
- - Follows Unknown conventions and style guide (see `CLAUDE.md`)
112
+ - Follows project conventions and style guide (see `CLAUDE.md`)
108
113
 
109
114
  6. **Security Gate**
110
115
  - If `/sk:security-check` has not been run on this branch, recommend: "Run `/sk:security-check` before creating a PR."
@@ -2,6 +2,16 @@
2
2
  description: "Show all ShipKit commands and workflow overview."
3
3
  ---
4
4
 
5
+ # Meta
6
+
7
+ | Command | Description |
8
+ |---------|-------------|
9
+ | `/sk:help` | Show all commands and workflow overview |
10
+ | `/sk:status` | Show workflow and task status at a glance |
11
+ | `/sk:skill-creator` | Create or improve ShipKit skills |
12
+
13
+ ---
14
+
5
15
  # /sk:help — ShipKit
6
16
 
7
17
  A structured workflow toolkit for Claude Code.
@@ -19,7 +29,6 @@ Run these commands in order for a complete, quality-gated feature build.
19
29
  | `/sk:schema-migrate` | Analyze schema changes *(skip if no DB changes)* |
20
30
  | `/sk:write-tests` | TDD red: write failing tests first |
21
31
  | `/sk:execute-plan` | TDD green: implement until tests pass |
22
- | `/sk:change` | Requirements changed? Re-enter at the right step |
23
32
  | `/sk:smart-commit` | Conventional commit with approval |
24
33
  | `/sk:lint` | **GATE** — all linters must pass |
25
34
  | `/sk:test` | **GATE** — 100% coverage on new code |
@@ -70,7 +79,7 @@ Requirements change mid-workflow? Run `/sk:change` — it classifies the scope a
70
79
  | `/sk:lint` | Auto-detect and run all linters |
71
80
  | `/sk:perf` | Performance audit |
72
81
  | `/sk:plan` | Create/refresh task planning files |
73
- | `/sk:release` | Version bump + changelog + tag |
82
+ | `/sk:release` | Automate releases: bump version, update CHANGELOG, create tag, push to GitHub. Use --android and/or --ios flags for App Store / Play Store readiness audit |
74
83
  | `/sk:review` | Self-review of branch changes |
75
84
  | `/sk:schema-migrate` | Multi-ORM schema change analysis |
76
85
  | `/sk:security-check` | OWASP security audit |
@@ -113,4 +122,4 @@ Config lives in `.shipkit/config.json` — per project, gitignored by default.
113
122
 
114
123
  ---
115
124
 
116
- **ShipKit** by Kenneth Solomon · `npm install -g @kennethsolomon/shipkit` to install/update
125
+ **ShipKit** by Kenneth Solomon · `npx @kennethsolomon/shipkit` to install/update
@@ -53,36 +53,38 @@ Read each file in scope before auditing.
53
53
  - **A09 Logging Failures** — Missing audit logs, PII in logs, no alerting on security events
54
54
  - **A10 SSRF** — Unvalidated URLs, internal network access, DNS rebinding
55
55
 
56
- ### 2. Stack-Specific Checks (Unknown / Unknown)
56
+ ### 2. Stack-Specific Checks
57
57
 
58
- **If Unknown includes React/Next.js:**
58
+ Detect the project stack from `CLAUDE.md`, `package.json`, `composer.json`, `pyproject.toml`, `go.mod`, `Cargo.toml`, etc. Apply the relevant checks below for every detected framework/language.
59
+
60
+ **If the project uses React/Next.js:**
59
61
  - `dangerouslySetInnerHTML` usage without sanitization
60
62
  - Client-side secrets (API keys in browser bundles)
61
63
  - Missing CSP headers
62
64
  - Server component data leaking to client
63
65
  - `getServerSideProps`/Server Actions exposing internal data
64
66
 
65
- **If Unknown includes Express/Node.js:**
67
+ **If the project uses Express/Node.js:**
66
68
  - Missing helmet/security headers
67
69
  - Unsanitized user input in `req.params`, `req.query`, `req.body`
68
70
  - Path traversal via `req.params` in file operations
69
71
  - Missing rate limiting on auth endpoints
70
72
  - Prototype pollution
71
73
 
72
- **If Unknown is Python:**
74
+ **If the project uses Python:**
73
75
  - `eval()`, `exec()`, `pickle.loads()` with untrusted input
74
76
  - SQL string formatting instead of parameterized queries
75
77
  - `subprocess.shell=True` with user input
76
78
  - Missing input validation on FastAPI/Django endpoints
77
79
  - Jinja2 `| safe` filter misuse
78
80
 
79
- **If Unknown is Go:**
81
+ **If the project uses Go:**
80
82
  - Unchecked error returns on security-critical operations
81
83
  - `html/template` vs `text/template` confusion
82
84
  - Missing context cancellation/timeouts
83
85
  - Race conditions on shared state
84
86
 
85
- **If Unknown is PHP:**
87
+ **If the project uses PHP/Laravel:**
86
88
  - `include`/`require` with user-controlled paths
87
89
  - `mysqli_query` without prepared statements
88
90
  - Missing CSRF tokens
@@ -112,7 +114,7 @@ Write findings to `tasks/security-findings.md` using this format:
112
114
  # Security Audit — YYYY-MM-DD
113
115
 
114
116
  **Scope:** Changed files on branch `<branch-name>` | Full project scan
115
- **Stack:** Unknown / Unknown
117
+ **Stack:** `<detected stack — e.g. Laravel / React>`
116
118
  **Files audited:** N
117
119
 
118
120
  ## Critical (must fix before deploy)
@@ -0,0 +1,113 @@
1
+ #!/usr/bin/env python3
2
+ """Switch ShipKit model routing profile."""
3
+
4
+ import json
5
+ import sys
6
+ from pathlib import Path
7
+
8
+ VALID_PROFILES = ["full-sail", "quality", "balanced", "budget"]
9
+
10
+ def get_defaults():
11
+ return {
12
+ "profile": "balanced",
13
+ "auto_commit": True,
14
+ "skip_gates": [],
15
+ "coverage_threshold": 100,
16
+ "branch_pattern": "feature/{slug}",
17
+ "model_overrides": {}
18
+ }
19
+
20
+ def get_config():
21
+ """Read current config or return defaults."""
22
+ config_file = Path(".shipkit/config.json")
23
+ if config_file.exists():
24
+ try:
25
+ with open(config_file) as f:
26
+ return json.load(f)
27
+ except json.JSONDecodeError:
28
+ return get_defaults()
29
+ return get_defaults()
30
+
31
+ def get_models_for_profile(profile):
32
+ """Get model assignments for a profile."""
33
+ models = {
34
+ "full-sail": {"planning": "opus", "implementation": "opus", "audits": "opus", "gates": "sonnet"},
35
+ "quality": {"planning": "opus", "implementation": "sonnet", "audits": "sonnet", "gates": "sonnet"},
36
+ "balanced": {"planning": "sonnet", "implementation": "sonnet", "audits": "sonnet", "gates": "haiku"},
37
+ "budget": {"planning": "sonnet", "implementation": "sonnet", "audits": "haiku", "gates": "haiku"}
38
+ }
39
+ return models.get(profile, models["balanced"])
40
+
41
+ def get_profile_description(profile):
42
+ """Get profile philosophy and use case."""
43
+ descriptions = {
44
+ "full-sail": ("Opus on everything that matters", "High-stakes work, client projects, production features"),
45
+ "quality": ("Opus for planning + review, Sonnet for implementation", "Most professional projects"),
46
+ "balanced": ("Sonnet across the board", "Day-to-day development (default)"),
47
+ "budget": ("Haiku where possible, Sonnet for gates", "Side projects, exploration, prototyping")
48
+ }
49
+ return descriptions.get(profile, ("", ""))
50
+
51
+ def save_config(config):
52
+ """Save config to .shipkit/config.json."""
53
+ Path(".shipkit").mkdir(exist_ok=True)
54
+ config_file = Path(".shipkit/config.json")
55
+
56
+ with open(config_file, "w") as f:
57
+ json.dump(config, f, indent=2)
58
+
59
+ # Add to .gitignore
60
+ gitignore = Path(".gitignore")
61
+ if gitignore.exists():
62
+ content = gitignore.read_text()
63
+ if ".shipkit/config.json" not in content:
64
+ with open(gitignore, "a") as f:
65
+ f.write("\n.shipkit/config.json\n")
66
+ else:
67
+ gitignore.write_text(".shipkit/config.json\n")
68
+
69
+ def main():
70
+ # Get profile argument
71
+ profile = None
72
+ if len(sys.argv) > 1:
73
+ profile = sys.argv[1].lower()
74
+
75
+ # Validate profile
76
+ if profile and profile not in VALID_PROFILES:
77
+ print(f"❌ Invalid profile: `{profile}`")
78
+ print(f"\nValid profiles: {' · '.join(VALID_PROFILES)}")
79
+ sys.exit(1)
80
+
81
+ # If no profile provided, show options
82
+ if not profile:
83
+ print("## Available Profiles\n")
84
+ print("| Profile | Philosophy | Best for |")
85
+ print("|---------|-----------|---------|")
86
+ for p in VALID_PROFILES:
87
+ philosophy, use_case = get_profile_description(p)
88
+ default = " *(default)*" if p == "balanced" else ""
89
+ print(f"| `{p}` | {philosophy}{default} | {use_case} |")
90
+ print("\nUsage: `/sk:set-profile <profile>`")
91
+ sys.exit(0)
92
+
93
+ # Read current config
94
+ config = get_config()
95
+ old_profile = config['profile']
96
+
97
+ # Update profile
98
+ config['profile'] = profile
99
+ save_config(config)
100
+
101
+ # Confirm and display new assignments
102
+ models = get_models_for_profile(profile)
103
+ print(f"\n✅ Profile set to: `{profile}` (was `{old_profile}`)\n")
104
+ print("## Model assignments for this project:\n")
105
+ print(f" brainstorm, write-plan, debug, execute-plan, review → `{models['planning']}`")
106
+ print(f" write-tests, frontend-design, api-design, security-check → `{models['implementation']}`")
107
+ print(f" perf, schema-migrate, accessibility → `{models['audits']}`")
108
+ print(f" lint, test → `{models['gates']}`")
109
+ print(f" smart-commit, branch, update-task → `haiku`\n")
110
+ print("Run `/sk:config` to see all settings or make further changes.")
111
+
112
+ if __name__ == "__main__":
113
+ main()
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kennethsolomon/shipkit",
3
- "version": "3.0.3",
3
+ "version": "3.0.6",
4
4
  "description": "A structured workflow toolkit for Claude Code.",
5
5
  "keywords": [
6
6
  "claude",
@@ -72,7 +72,7 @@ npm install -D vitest @testing-library/react @testing-library/jest-dom @testing-
72
72
 
73
73
  Create `vitest.config.ts`:
74
74
  ```ts
75
- import { defineConfig } from 'vitest/sk:config';
75
+ import { defineConfig } from 'vitest/config';
76
76
  import react from '@vitejs/plugin-react';
77
77
 
78
78
  export default defineConfig({