opencodekit 0.6.0 → 0.6.1

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 (77) hide show
  1. package/dist/index.js +1 -1
  2. package/dist/template/.opencode/AGENTS.md +4 -1
  3. package/dist/template/.opencode/command/skill-create.md +3 -3
  4. package/dist/template/.opencode/command/skill-optimize.md +1 -1
  5. package/dist/template/.opencode/opencode.json +493 -535
  6. package/dist/template/.opencode/pickle-thinker.jsonc +11 -0
  7. package/dist/template/.opencode/plugin/skill.ts +275 -0
  8. package/dist/template/.opencode/{skills → skill}/accessibility-audit/SKILL.md +5 -0
  9. package/dist/template/.opencode/{skills → skill}/brainstorming/SKILL.md +2 -2
  10. package/dist/template/.opencode/{skills → skill}/design-system-audit/SKILL.md +5 -0
  11. package/dist/template/.opencode/{skills → skill}/executing-plans/SKILL.md +13 -2
  12. package/dist/template/.opencode/{skills → skill}/frontend-aesthetics/SKILL.md +5 -0
  13. package/dist/template/.opencode/{skills → skill}/mockup-to-code/SKILL.md +5 -0
  14. package/dist/template/.opencode/{skills → skill}/requesting-code-review/SKILL.md +16 -6
  15. package/dist/template/.opencode/{skills → skill}/subagent-driven-development/SKILL.md +38 -17
  16. package/dist/template/.opencode/{skills → skill}/systematic-debugging/SKILL.md +28 -18
  17. package/dist/template/.opencode/{skills → skill}/testing-skills-with-subagents/SKILL.md +1 -1
  18. package/dist/template/.opencode/{skills → skill}/ui-ux-research/SKILL.md +5 -0
  19. package/dist/template/.opencode/{skills → skill}/visual-analysis/SKILL.md +5 -0
  20. package/dist/template/.opencode/{skills → skill}/writing-plans/SKILL.md +3 -3
  21. package/dist/template/.opencode/{skills → skill}/writing-skills/SKILL.md +101 -41
  22. package/package.json +1 -1
  23. package/dist/template/.opencode/plugin/superpowers.ts +0 -271
  24. package/dist/template/.opencode/superpowers/.claude/settings.local.json +0 -141
  25. package/dist/template/.opencode/superpowers/.claude-plugin/marketplace.json +0 -20
  26. package/dist/template/.opencode/superpowers/.claude-plugin/plugin.json +0 -13
  27. package/dist/template/.opencode/superpowers/.codex/INSTALL.md +0 -35
  28. package/dist/template/.opencode/superpowers/.codex/superpowers-bootstrap.md +0 -33
  29. package/dist/template/.opencode/superpowers/.codex/superpowers-codex +0 -267
  30. package/dist/template/.opencode/superpowers/.github/FUNDING.yml +0 -3
  31. package/dist/template/.opencode/superpowers/.opencode/INSTALL.md +0 -135
  32. package/dist/template/.opencode/superpowers/.opencode/plugin/superpowers.js +0 -215
  33. package/dist/template/.opencode/superpowers/LICENSE +0 -21
  34. package/dist/template/.opencode/superpowers/README.md +0 -165
  35. package/dist/template/.opencode/superpowers/RELEASE-NOTES.md +0 -493
  36. package/dist/template/.opencode/superpowers/agents/code-reviewer.md +0 -48
  37. package/dist/template/.opencode/superpowers/commands/brainstorm.md +0 -5
  38. package/dist/template/.opencode/superpowers/commands/execute-plan.md +0 -5
  39. package/dist/template/.opencode/superpowers/commands/write-plan.md +0 -5
  40. package/dist/template/.opencode/superpowers/docs/README.codex.md +0 -153
  41. package/dist/template/.opencode/superpowers/docs/README.opencode.md +0 -234
  42. package/dist/template/.opencode/superpowers/docs/plans/2025-11-22-opencode-support-design.md +0 -294
  43. package/dist/template/.opencode/superpowers/docs/plans/2025-11-22-opencode-support-implementation.md +0 -1095
  44. package/dist/template/.opencode/superpowers/hooks/hooks.json +0 -15
  45. package/dist/template/.opencode/superpowers/hooks/session-start.sh +0 -34
  46. package/dist/template/.opencode/superpowers/lib/skills-core.js +0 -208
  47. package/dist/template/.opencode/superpowers/tests/opencode/run-tests.sh +0 -165
  48. package/dist/template/.opencode/superpowers/tests/opencode/setup.sh +0 -73
  49. package/dist/template/.opencode/superpowers/tests/opencode/test-plugin-loading.sh +0 -81
  50. package/dist/template/.opencode/superpowers/tests/opencode/test-priority.sh +0 -198
  51. package/dist/template/.opencode/superpowers/tests/opencode/test-skills-core.sh +0 -440
  52. package/dist/template/.opencode/superpowers/tests/opencode/test-tools.sh +0 -104
  53. /package/dist/template/.opencode/{skills → skill}/condition-based-waiting/SKILL.md +0 -0
  54. /package/dist/template/.opencode/{skills → skill}/condition-based-waiting/example.ts +0 -0
  55. /package/dist/template/.opencode/{skills → skill}/defense-in-depth/SKILL.md +0 -0
  56. /package/dist/template/.opencode/{skills → skill}/dispatching-parallel-agents/SKILL.md +0 -0
  57. /package/dist/template/.opencode/{skills → skill}/finishing-a-development-branch/SKILL.md +0 -0
  58. /package/dist/template/.opencode/{skills → skill}/gemini-large-context/SKILL.md +0 -0
  59. /package/dist/template/.opencode/{skills → skill}/receiving-code-review/SKILL.md +0 -0
  60. /package/dist/template/.opencode/{skills/requesting-code-review/code-reviewer.md → skill/requesting-code-review/review.md} +0 -0
  61. /package/dist/template/.opencode/{skills → skill}/root-cause-tracing/SKILL.md +0 -0
  62. /package/dist/template/.opencode/{skills → skill}/root-cause-tracing/find-polluter.sh +0 -0
  63. /package/dist/template/.opencode/{skills → skill}/sharing-skills/SKILL.md +0 -0
  64. /package/dist/template/.opencode/{skills → skill}/systematic-debugging/CREATION-LOG.md +0 -0
  65. /package/dist/template/.opencode/{skills → skill}/systematic-debugging/test-academic.md +0 -0
  66. /package/dist/template/.opencode/{skills → skill}/systematic-debugging/test-pressure-1.md +0 -0
  67. /package/dist/template/.opencode/{skills → skill}/systematic-debugging/test-pressure-2.md +0 -0
  68. /package/dist/template/.opencode/{skills → skill}/systematic-debugging/test-pressure-3.md +0 -0
  69. /package/dist/template/.opencode/{skills → skill}/test-driven-development/SKILL.md +0 -0
  70. /package/dist/template/.opencode/{skills → skill}/testing-anti-patterns/SKILL.md +0 -0
  71. /package/dist/template/.opencode/{skills → skill}/testing-skills-with-subagents/examples/CLAUDE_MD_TESTING.md +0 -0
  72. /package/dist/template/.opencode/{skills → skill}/using-git-worktrees/SKILL.md +0 -0
  73. /package/dist/template/.opencode/{skills → skill}/using-superpowers/SKILL.md +0 -0
  74. /package/dist/template/.opencode/{skills → skill}/verification-before-completion/SKILL.md +0 -0
  75. /package/dist/template/.opencode/{skills → skill}/writing-skills/anthropic-best-practices.md +0 -0
  76. /package/dist/template/.opencode/{skills → skill}/writing-skills/graphviz-conventions.dot +0 -0
  77. /package/dist/template/.opencode/{skills → skill}/writing-skills/persuasion-principles.md +0 -0
@@ -1,198 +0,0 @@
1
- #!/usr/bin/env bash
2
- # Test: Skill Priority Resolution
3
- # Verifies that skills are resolved with correct priority: project > personal > superpowers
4
- # NOTE: These tests require OpenCode to be installed and configured
5
- set -euo pipefail
6
-
7
- SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
8
-
9
- echo "=== Test: Skill Priority Resolution ==="
10
-
11
- # Source setup to create isolated environment
12
- source "$SCRIPT_DIR/setup.sh"
13
-
14
- # Trap to cleanup on exit
15
- trap cleanup_test_env EXIT
16
-
17
- # Create same skill "priority-test" in all three locations with different markers
18
- echo "Setting up priority test fixtures..."
19
-
20
- # 1. Create in superpowers location (lowest priority)
21
- mkdir -p "$HOME/.config/opencode/superpowers/skills/priority-test"
22
- cat > "$HOME/.config/opencode/superpowers/skills/priority-test/SKILL.md" <<'EOF'
23
- ---
24
- name: priority-test
25
- description: Superpowers version of priority test skill
26
- ---
27
- # Priority Test Skill (Superpowers Version)
28
-
29
- This is the SUPERPOWERS version of the priority test skill.
30
-
31
- PRIORITY_MARKER_SUPERPOWERS_VERSION
32
- EOF
33
-
34
- # 2. Create in personal location (medium priority)
35
- mkdir -p "$HOME/.config/opencode/skills/priority-test"
36
- cat > "$HOME/.config/opencode/skills/priority-test/SKILL.md" <<'EOF'
37
- ---
38
- name: priority-test
39
- description: Personal version of priority test skill
40
- ---
41
- # Priority Test Skill (Personal Version)
42
-
43
- This is the PERSONAL version of the priority test skill.
44
-
45
- PRIORITY_MARKER_PERSONAL_VERSION
46
- EOF
47
-
48
- # 3. Create in project location (highest priority)
49
- mkdir -p "$TEST_HOME/test-project/.opencode/skills/priority-test"
50
- cat > "$TEST_HOME/test-project/.opencode/skills/priority-test/SKILL.md" <<'EOF'
51
- ---
52
- name: priority-test
53
- description: Project version of priority test skill
54
- ---
55
- # Priority Test Skill (Project Version)
56
-
57
- This is the PROJECT version of the priority test skill.
58
-
59
- PRIORITY_MARKER_PROJECT_VERSION
60
- EOF
61
-
62
- echo " Created priority-test skill in all three locations"
63
-
64
- # Test 1: Verify fixture setup
65
- echo ""
66
- echo "Test 1: Verifying test fixtures..."
67
-
68
- if [ -f "$HOME/.config/opencode/superpowers/skills/priority-test/SKILL.md" ]; then
69
- echo " [PASS] Superpowers version exists"
70
- else
71
- echo " [FAIL] Superpowers version missing"
72
- exit 1
73
- fi
74
-
75
- if [ -f "$HOME/.config/opencode/skills/priority-test/SKILL.md" ]; then
76
- echo " [PASS] Personal version exists"
77
- else
78
- echo " [FAIL] Personal version missing"
79
- exit 1
80
- fi
81
-
82
- if [ -f "$TEST_HOME/test-project/.opencode/skills/priority-test/SKILL.md" ]; then
83
- echo " [PASS] Project version exists"
84
- else
85
- echo " [FAIL] Project version missing"
86
- exit 1
87
- fi
88
-
89
- # Check if opencode is available for integration tests
90
- if ! command -v opencode &> /dev/null; then
91
- echo ""
92
- echo " [SKIP] OpenCode not installed - skipping integration tests"
93
- echo " To run these tests, install OpenCode: https://opencode.ai"
94
- echo ""
95
- echo "=== Priority fixture tests passed (integration tests skipped) ==="
96
- exit 0
97
- fi
98
-
99
- # Test 2: Test that personal overrides superpowers
100
- echo ""
101
- echo "Test 2: Testing personal > superpowers priority..."
102
- echo " Running from outside project directory..."
103
-
104
- # Run from HOME (not in project) - should get personal version
105
- cd "$HOME"
106
- output=$(timeout 60s opencode run --print-logs "Use the use_skill tool to load the priority-test skill. Show me the exact content including any PRIORITY_MARKER text." 2>&1) || {
107
- exit_code=$?
108
- if [ $exit_code -eq 124 ]; then
109
- echo " [FAIL] OpenCode timed out after 60s"
110
- exit 1
111
- fi
112
- }
113
-
114
- if echo "$output" | grep -qi "PRIORITY_MARKER_PERSONAL_VERSION"; then
115
- echo " [PASS] Personal version loaded (overrides superpowers)"
116
- elif echo "$output" | grep -qi "PRIORITY_MARKER_SUPERPOWERS_VERSION"; then
117
- echo " [FAIL] Superpowers version loaded instead of personal"
118
- exit 1
119
- else
120
- echo " [WARN] Could not verify priority marker in output"
121
- echo " Output snippet:"
122
- echo "$output" | grep -i "priority\|personal\|superpowers" | head -10
123
- fi
124
-
125
- # Test 3: Test that project overrides both personal and superpowers
126
- echo ""
127
- echo "Test 3: Testing project > personal > superpowers priority..."
128
- echo " Running from project directory..."
129
-
130
- # Run from project directory - should get project version
131
- cd "$TEST_HOME/test-project"
132
- output=$(timeout 60s opencode run --print-logs "Use the use_skill tool to load the priority-test skill. Show me the exact content including any PRIORITY_MARKER text." 2>&1) || {
133
- exit_code=$?
134
- if [ $exit_code -eq 124 ]; then
135
- echo " [FAIL] OpenCode timed out after 60s"
136
- exit 1
137
- fi
138
- }
139
-
140
- if echo "$output" | grep -qi "PRIORITY_MARKER_PROJECT_VERSION"; then
141
- echo " [PASS] Project version loaded (highest priority)"
142
- elif echo "$output" | grep -qi "PRIORITY_MARKER_PERSONAL_VERSION"; then
143
- echo " [FAIL] Personal version loaded instead of project"
144
- exit 1
145
- elif echo "$output" | grep -qi "PRIORITY_MARKER_SUPERPOWERS_VERSION"; then
146
- echo " [FAIL] Superpowers version loaded instead of project"
147
- exit 1
148
- else
149
- echo " [WARN] Could not verify priority marker in output"
150
- echo " Output snippet:"
151
- echo "$output" | grep -i "priority\|project\|personal" | head -10
152
- fi
153
-
154
- # Test 4: Test explicit superpowers: prefix bypasses priority
155
- echo ""
156
- echo "Test 4: Testing superpowers: prefix forces superpowers version..."
157
-
158
- cd "$TEST_HOME/test-project"
159
- output=$(timeout 60s opencode run --print-logs "Use the use_skill tool to load superpowers:priority-test specifically. Show me the exact content including any PRIORITY_MARKER text." 2>&1) || {
160
- exit_code=$?
161
- if [ $exit_code -eq 124 ]; then
162
- echo " [FAIL] OpenCode timed out after 60s"
163
- exit 1
164
- fi
165
- }
166
-
167
- if echo "$output" | grep -qi "PRIORITY_MARKER_SUPERPOWERS_VERSION"; then
168
- echo " [PASS] superpowers: prefix correctly forces superpowers version"
169
- elif echo "$output" | grep -qi "PRIORITY_MARKER_PROJECT_VERSION\|PRIORITY_MARKER_PERSONAL_VERSION"; then
170
- echo " [FAIL] superpowers: prefix did not force superpowers version"
171
- exit 1
172
- else
173
- echo " [WARN] Could not verify priority marker in output"
174
- fi
175
-
176
- # Test 5: Test explicit project: prefix
177
- echo ""
178
- echo "Test 5: Testing project: prefix forces project version..."
179
-
180
- cd "$HOME" # Run from outside project but with project: prefix
181
- output=$(timeout 60s opencode run --print-logs "Use the use_skill tool to load project:priority-test specifically. Show me the exact content." 2>&1) || {
182
- exit_code=$?
183
- if [ $exit_code -eq 124 ]; then
184
- echo " [FAIL] OpenCode timed out after 60s"
185
- exit 1
186
- fi
187
- }
188
-
189
- # Note: This may fail since we're not in the project directory
190
- # The project: prefix only works when in a project context
191
- if echo "$output" | grep -qi "not found\|error"; then
192
- echo " [PASS] project: prefix correctly fails when not in project context"
193
- else
194
- echo " [INFO] project: prefix behavior outside project context may vary"
195
- fi
196
-
197
- echo ""
198
- echo "=== All priority tests passed ==="
@@ -1,440 +0,0 @@
1
- #!/usr/bin/env bash
2
- # Test: Skills Core Library
3
- # Tests the skills-core.js library functions directly via Node.js
4
- # Does not require OpenCode - tests pure library functionality
5
- set -euo pipefail
6
-
7
- SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
8
-
9
- echo "=== Test: Skills Core Library ==="
10
-
11
- # Source setup to create isolated environment
12
- source "$SCRIPT_DIR/setup.sh"
13
-
14
- # Trap to cleanup on exit
15
- trap cleanup_test_env EXIT
16
-
17
- # Test 1: Test extractFrontmatter function
18
- echo "Test 1: Testing extractFrontmatter..."
19
-
20
- # Create test file with frontmatter
21
- test_skill_dir="$TEST_HOME/test-skill"
22
- mkdir -p "$test_skill_dir"
23
- cat > "$test_skill_dir/SKILL.md" <<'EOF'
24
- ---
25
- name: test-skill
26
- description: A test skill for unit testing
27
- ---
28
- # Test Skill Content
29
-
30
- This is the content.
31
- EOF
32
-
33
- # Run Node.js test using inline function (avoids ESM path resolution issues in test env)
34
- result=$(node -e "
35
- const path = require('path');
36
- const fs = require('fs');
37
-
38
- // Inline the extractFrontmatter function for testing
39
- function extractFrontmatter(filePath) {
40
- try {
41
- const content = fs.readFileSync(filePath, 'utf8');
42
- const lines = content.split('\n');
43
- let inFrontmatter = false;
44
- let name = '';
45
- let description = '';
46
- for (const line of lines) {
47
- if (line.trim() === '---') {
48
- if (inFrontmatter) break;
49
- inFrontmatter = true;
50
- continue;
51
- }
52
- if (inFrontmatter) {
53
- const match = line.match(/^(\w+):\s*(.*)$/);
54
- if (match) {
55
- const [, key, value] = match;
56
- if (key === 'name') name = value.trim();
57
- if (key === 'description') description = value.trim();
58
- }
59
- }
60
- }
61
- return { name, description };
62
- } catch (error) {
63
- return { name: '', description: '' };
64
- }
65
- }
66
-
67
- const result = extractFrontmatter('$TEST_HOME/test-skill/SKILL.md');
68
- console.log(JSON.stringify(result));
69
- " 2>&1)
70
-
71
- if echo "$result" | grep -q '"name":"test-skill"'; then
72
- echo " [PASS] extractFrontmatter parses name correctly"
73
- else
74
- echo " [FAIL] extractFrontmatter did not parse name"
75
- echo " Result: $result"
76
- exit 1
77
- fi
78
-
79
- if echo "$result" | grep -q '"description":"A test skill for unit testing"'; then
80
- echo " [PASS] extractFrontmatter parses description correctly"
81
- else
82
- echo " [FAIL] extractFrontmatter did not parse description"
83
- exit 1
84
- fi
85
-
86
- # Test 2: Test stripFrontmatter function
87
- echo ""
88
- echo "Test 2: Testing stripFrontmatter..."
89
-
90
- result=$(node -e "
91
- const fs = require('fs');
92
-
93
- function stripFrontmatter(content) {
94
- const lines = content.split('\n');
95
- let inFrontmatter = false;
96
- let frontmatterEnded = false;
97
- const contentLines = [];
98
- for (const line of lines) {
99
- if (line.trim() === '---') {
100
- if (inFrontmatter) {
101
- frontmatterEnded = true;
102
- continue;
103
- }
104
- inFrontmatter = true;
105
- continue;
106
- }
107
- if (frontmatterEnded || !inFrontmatter) {
108
- contentLines.push(line);
109
- }
110
- }
111
- return contentLines.join('\n').trim();
112
- }
113
-
114
- const content = fs.readFileSync('$TEST_HOME/test-skill/SKILL.md', 'utf8');
115
- const stripped = stripFrontmatter(content);
116
- console.log(stripped);
117
- " 2>&1)
118
-
119
- if echo "$result" | grep -q "# Test Skill Content"; then
120
- echo " [PASS] stripFrontmatter preserves content"
121
- else
122
- echo " [FAIL] stripFrontmatter did not preserve content"
123
- echo " Result: $result"
124
- exit 1
125
- fi
126
-
127
- if ! echo "$result" | grep -q "name: test-skill"; then
128
- echo " [PASS] stripFrontmatter removes frontmatter"
129
- else
130
- echo " [FAIL] stripFrontmatter did not remove frontmatter"
131
- exit 1
132
- fi
133
-
134
- # Test 3: Test findSkillsInDir function
135
- echo ""
136
- echo "Test 3: Testing findSkillsInDir..."
137
-
138
- # Create multiple test skills
139
- mkdir -p "$TEST_HOME/skills-dir/skill-a"
140
- mkdir -p "$TEST_HOME/skills-dir/skill-b"
141
- mkdir -p "$TEST_HOME/skills-dir/nested/skill-c"
142
-
143
- cat > "$TEST_HOME/skills-dir/skill-a/SKILL.md" <<'EOF'
144
- ---
145
- name: skill-a
146
- description: First skill
147
- ---
148
- # Skill A
149
- EOF
150
-
151
- cat > "$TEST_HOME/skills-dir/skill-b/SKILL.md" <<'EOF'
152
- ---
153
- name: skill-b
154
- description: Second skill
155
- ---
156
- # Skill B
157
- EOF
158
-
159
- cat > "$TEST_HOME/skills-dir/nested/skill-c/SKILL.md" <<'EOF'
160
- ---
161
- name: skill-c
162
- description: Nested skill
163
- ---
164
- # Skill C
165
- EOF
166
-
167
- result=$(node -e "
168
- const fs = require('fs');
169
- const path = require('path');
170
-
171
- function extractFrontmatter(filePath) {
172
- try {
173
- const content = fs.readFileSync(filePath, 'utf8');
174
- const lines = content.split('\n');
175
- let inFrontmatter = false;
176
- let name = '';
177
- let description = '';
178
- for (const line of lines) {
179
- if (line.trim() === '---') {
180
- if (inFrontmatter) break;
181
- inFrontmatter = true;
182
- continue;
183
- }
184
- if (inFrontmatter) {
185
- const match = line.match(/^(\w+):\s*(.*)$/);
186
- if (match) {
187
- const [, key, value] = match;
188
- if (key === 'name') name = value.trim();
189
- if (key === 'description') description = value.trim();
190
- }
191
- }
192
- }
193
- return { name, description };
194
- } catch (error) {
195
- return { name: '', description: '' };
196
- }
197
- }
198
-
199
- function findSkillsInDir(dir, sourceType, maxDepth = 3) {
200
- const skills = [];
201
- if (!fs.existsSync(dir)) return skills;
202
- function recurse(currentDir, depth) {
203
- if (depth > maxDepth) return;
204
- const entries = fs.readdirSync(currentDir, { withFileTypes: true });
205
- for (const entry of entries) {
206
- const fullPath = path.join(currentDir, entry.name);
207
- if (entry.isDirectory()) {
208
- const skillFile = path.join(fullPath, 'SKILL.md');
209
- if (fs.existsSync(skillFile)) {
210
- const { name, description } = extractFrontmatter(skillFile);
211
- skills.push({
212
- path: fullPath,
213
- skillFile: skillFile,
214
- name: name || entry.name,
215
- description: description || '',
216
- sourceType: sourceType
217
- });
218
- }
219
- recurse(fullPath, depth + 1);
220
- }
221
- }
222
- }
223
- recurse(dir, 0);
224
- return skills;
225
- }
226
-
227
- const skills = findSkillsInDir('$TEST_HOME/skills-dir', 'test', 3);
228
- console.log(JSON.stringify(skills, null, 2));
229
- " 2>&1)
230
-
231
- skill_count=$(echo "$result" | grep -c '"name":' || echo "0")
232
-
233
- if [ "$skill_count" -ge 3 ]; then
234
- echo " [PASS] findSkillsInDir found all skills (found $skill_count)"
235
- else
236
- echo " [FAIL] findSkillsInDir did not find all skills (expected 3, found $skill_count)"
237
- echo " Result: $result"
238
- exit 1
239
- fi
240
-
241
- if echo "$result" | grep -q '"name": "skill-c"'; then
242
- echo " [PASS] findSkillsInDir found nested skills"
243
- else
244
- echo " [FAIL] findSkillsInDir did not find nested skill"
245
- exit 1
246
- fi
247
-
248
- # Test 4: Test resolveSkillPath function
249
- echo ""
250
- echo "Test 4: Testing resolveSkillPath..."
251
-
252
- # Create skills in personal and superpowers locations for testing
253
- mkdir -p "$TEST_HOME/personal-skills/shared-skill"
254
- mkdir -p "$TEST_HOME/superpowers-skills/shared-skill"
255
- mkdir -p "$TEST_HOME/superpowers-skills/unique-skill"
256
-
257
- cat > "$TEST_HOME/personal-skills/shared-skill/SKILL.md" <<'EOF'
258
- ---
259
- name: shared-skill
260
- description: Personal version
261
- ---
262
- # Personal Shared
263
- EOF
264
-
265
- cat > "$TEST_HOME/superpowers-skills/shared-skill/SKILL.md" <<'EOF'
266
- ---
267
- name: shared-skill
268
- description: Superpowers version
269
- ---
270
- # Superpowers Shared
271
- EOF
272
-
273
- cat > "$TEST_HOME/superpowers-skills/unique-skill/SKILL.md" <<'EOF'
274
- ---
275
- name: unique-skill
276
- description: Only in superpowers
277
- ---
278
- # Unique
279
- EOF
280
-
281
- result=$(node -e "
282
- const fs = require('fs');
283
- const path = require('path');
284
-
285
- function resolveSkillPath(skillName, superpowersDir, personalDir) {
286
- const forceSuperpowers = skillName.startsWith('superpowers:');
287
- const actualSkillName = forceSuperpowers ? skillName.replace(/^superpowers:/, '') : skillName;
288
-
289
- if (!forceSuperpowers && personalDir) {
290
- const personalPath = path.join(personalDir, actualSkillName);
291
- const personalSkillFile = path.join(personalPath, 'SKILL.md');
292
- if (fs.existsSync(personalSkillFile)) {
293
- return {
294
- skillFile: personalSkillFile,
295
- sourceType: 'personal',
296
- skillPath: actualSkillName
297
- };
298
- }
299
- }
300
-
301
- if (superpowersDir) {
302
- const superpowersPath = path.join(superpowersDir, actualSkillName);
303
- const superpowersSkillFile = path.join(superpowersPath, 'SKILL.md');
304
- if (fs.existsSync(superpowersSkillFile)) {
305
- return {
306
- skillFile: superpowersSkillFile,
307
- sourceType: 'superpowers',
308
- skillPath: actualSkillName
309
- };
310
- }
311
- }
312
-
313
- return null;
314
- }
315
-
316
- const superpowersDir = '$TEST_HOME/superpowers-skills';
317
- const personalDir = '$TEST_HOME/personal-skills';
318
-
319
- // Test 1: Shared skill should resolve to personal
320
- const shared = resolveSkillPath('shared-skill', superpowersDir, personalDir);
321
- console.log('SHARED:', JSON.stringify(shared));
322
-
323
- // Test 2: superpowers: prefix should force superpowers
324
- const forced = resolveSkillPath('superpowers:shared-skill', superpowersDir, personalDir);
325
- console.log('FORCED:', JSON.stringify(forced));
326
-
327
- // Test 3: Unique skill should resolve to superpowers
328
- const unique = resolveSkillPath('unique-skill', superpowersDir, personalDir);
329
- console.log('UNIQUE:', JSON.stringify(unique));
330
-
331
- // Test 4: Non-existent skill
332
- const notfound = resolveSkillPath('not-a-skill', superpowersDir, personalDir);
333
- console.log('NOTFOUND:', JSON.stringify(notfound));
334
- " 2>&1)
335
-
336
- if echo "$result" | grep -q 'SHARED:.*"sourceType":"personal"'; then
337
- echo " [PASS] Personal skills shadow superpowers skills"
338
- else
339
- echo " [FAIL] Personal skills not shadowing correctly"
340
- echo " Result: $result"
341
- exit 1
342
- fi
343
-
344
- if echo "$result" | grep -q 'FORCED:.*"sourceType":"superpowers"'; then
345
- echo " [PASS] superpowers: prefix forces superpowers resolution"
346
- else
347
- echo " [FAIL] superpowers: prefix not working"
348
- exit 1
349
- fi
350
-
351
- if echo "$result" | grep -q 'UNIQUE:.*"sourceType":"superpowers"'; then
352
- echo " [PASS] Unique superpowers skills are found"
353
- else
354
- echo " [FAIL] Unique superpowers skills not found"
355
- exit 1
356
- fi
357
-
358
- if echo "$result" | grep -q 'NOTFOUND: null'; then
359
- echo " [PASS] Non-existent skills return null"
360
- else
361
- echo " [FAIL] Non-existent skills should return null"
362
- exit 1
363
- fi
364
-
365
- # Test 5: Test checkForUpdates function
366
- echo ""
367
- echo "Test 5: Testing checkForUpdates..."
368
-
369
- # Create a test git repo
370
- mkdir -p "$TEST_HOME/test-repo"
371
- cd "$TEST_HOME/test-repo"
372
- git init --quiet
373
- git config user.email "test@test.com"
374
- git config user.name "Test"
375
- echo "test" > file.txt
376
- git add file.txt
377
- git commit -m "initial" --quiet
378
- cd "$SCRIPT_DIR"
379
-
380
- # Test checkForUpdates on repo without remote (should return false, not error)
381
- result=$(node -e "
382
- const { execSync } = require('child_process');
383
-
384
- function checkForUpdates(repoDir) {
385
- try {
386
- const output = execSync('git fetch origin && git status --porcelain=v1 --branch', {
387
- cwd: repoDir,
388
- timeout: 3000,
389
- encoding: 'utf8',
390
- stdio: 'pipe'
391
- });
392
- const statusLines = output.split('\n');
393
- for (const line of statusLines) {
394
- if (line.startsWith('## ') && line.includes('[behind ')) {
395
- return true;
396
- }
397
- }
398
- return false;
399
- } catch (error) {
400
- return false;
401
- }
402
- }
403
-
404
- // Test 1: Repo without remote should return false (graceful error handling)
405
- const result1 = checkForUpdates('$TEST_HOME/test-repo');
406
- console.log('NO_REMOTE:', result1);
407
-
408
- // Test 2: Non-existent directory should return false
409
- const result2 = checkForUpdates('$TEST_HOME/nonexistent');
410
- console.log('NONEXISTENT:', result2);
411
-
412
- // Test 3: Non-git directory should return false
413
- const result3 = checkForUpdates('$TEST_HOME');
414
- console.log('NOT_GIT:', result3);
415
- " 2>&1)
416
-
417
- if echo "$result" | grep -q 'NO_REMOTE: false'; then
418
- echo " [PASS] checkForUpdates handles repo without remote gracefully"
419
- else
420
- echo " [FAIL] checkForUpdates should return false for repo without remote"
421
- echo " Result: $result"
422
- exit 1
423
- fi
424
-
425
- if echo "$result" | grep -q 'NONEXISTENT: false'; then
426
- echo " [PASS] checkForUpdates handles non-existent directory"
427
- else
428
- echo " [FAIL] checkForUpdates should return false for non-existent directory"
429
- exit 1
430
- fi
431
-
432
- if echo "$result" | grep -q 'NOT_GIT: false'; then
433
- echo " [PASS] checkForUpdates handles non-git directory"
434
- else
435
- echo " [FAIL] checkForUpdates should return false for non-git directory"
436
- exit 1
437
- fi
438
-
439
- echo ""
440
- echo "=== All skills-core library tests passed ==="