@kleber.mottajr/juninho 1.1.0 → 1.2.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.
Files changed (49) hide show
  1. package/README.md +112 -13
  2. package/dist/cli.js +40 -23
  3. package/dist/cli.js.map +1 -1
  4. package/dist/config.d.ts +5 -0
  5. package/dist/config.d.ts.map +1 -1
  6. package/dist/config.js +7 -1
  7. package/dist/config.js.map +1 -1
  8. package/dist/installer.d.ts +2 -0
  9. package/dist/installer.d.ts.map +1 -1
  10. package/dist/installer.js +178 -54
  11. package/dist/installer.js.map +1 -1
  12. package/dist/lint-detection.d.ts +26 -0
  13. package/dist/lint-detection.d.ts.map +1 -0
  14. package/dist/lint-detection.js +200 -0
  15. package/dist/lint-detection.js.map +1 -0
  16. package/dist/models.js +4 -4
  17. package/dist/models.js.map +1 -1
  18. package/dist/project-types.d.ts +47 -0
  19. package/dist/project-types.d.ts.map +1 -0
  20. package/dist/project-types.js +251 -0
  21. package/dist/project-types.js.map +1 -0
  22. package/dist/templates/agents.d.ts +2 -1
  23. package/dist/templates/agents.d.ts.map +1 -1
  24. package/dist/templates/agents.js +7 -5
  25. package/dist/templates/agents.js.map +1 -1
  26. package/dist/templates/commands.d.ts.map +1 -1
  27. package/dist/templates/commands.js +225 -150
  28. package/dist/templates/commands.js.map +1 -1
  29. package/dist/templates/docs.d.ts +2 -1
  30. package/dist/templates/docs.d.ts.map +1 -1
  31. package/dist/templates/docs.js +61 -14
  32. package/dist/templates/docs.js.map +1 -1
  33. package/dist/templates/plugins.d.ts +2 -1
  34. package/dist/templates/plugins.d.ts.map +1 -1
  35. package/dist/templates/plugins.js +167 -102
  36. package/dist/templates/plugins.js.map +1 -1
  37. package/dist/templates/skills.d.ts +2 -1
  38. package/dist/templates/skills.d.ts.map +1 -1
  39. package/dist/templates/skills.js +708 -195
  40. package/dist/templates/skills.js.map +1 -1
  41. package/dist/templates/support-scripts.d.ts +2 -1
  42. package/dist/templates/support-scripts.d.ts.map +1 -1
  43. package/dist/templates/support-scripts.js +468 -21
  44. package/dist/templates/support-scripts.js.map +1 -1
  45. package/dist/templates/tools.d.ts +2 -1
  46. package/dist/templates/tools.d.ts.map +1 -1
  47. package/dist/templates/tools.js +315 -74
  48. package/dist/templates/tools.js.map +1 -1
  49. package/package.json +1 -1
@@ -6,22 +6,52 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.writeSkills = writeSkills;
7
7
  const fs_1 = require("fs");
8
8
  const path_1 = __importDefault(require("path"));
9
- function writeSkills(projectDir) {
9
+ const project_types_js_1 = require("../project-types.js");
10
+ function writeSkills(projectDir, projectType = "node-nextjs", isKotlin = false) {
10
11
  const skillsDir = path_1.default.join(projectDir, ".opencode", "skills");
11
- (0, fs_1.writeFileSync)(path_1.default.join(skillsDir, "j.test-writing", "SKILL.md"), TEST_WRITING);
12
- (0, fs_1.writeFileSync)(path_1.default.join(skillsDir, "j.page-creation", "SKILL.md"), PAGE_CREATION);
13
- (0, fs_1.writeFileSync)(path_1.default.join(skillsDir, "j.api-route-creation", "SKILL.md"), API_ROUTE_CREATION);
14
- (0, fs_1.writeFileSync)(path_1.default.join(skillsDir, "j.server-action-creation", "SKILL.md"), SERVER_ACTION_CREATION);
15
- (0, fs_1.writeFileSync)(path_1.default.join(skillsDir, "j.schema-migration", "SKILL.md"), SCHEMA_MIGRATION);
16
- (0, fs_1.writeFileSync)(path_1.default.join(skillsDir, "j.agents-md-writing", "SKILL.md"), AGENTS_MD_WRITING);
17
- (0, fs_1.writeFileSync)(path_1.default.join(skillsDir, "j.domain-doc-writing", "SKILL.md"), DOMAIN_DOC_WRITING);
18
- (0, fs_1.writeFileSync)(path_1.default.join(skillsDir, "j.principle-doc-writing", "SKILL.md"), PRINCIPLE_DOC_WRITING);
19
- (0, fs_1.writeFileSync)(path_1.default.join(skillsDir, "j.shell-script-writing", "SKILL.md"), SHELL_SCRIPT_WRITING);
12
+ const config = project_types_js_1.PROJECT_TYPE_REGISTRY[projectType];
13
+ // Create skill directories and write only the skills for this project type
14
+ const skillWriters = {
15
+ "j.test-writing": () => testWriting(projectType, isKotlin),
16
+ "j.page-creation": () => PAGE_CREATION,
17
+ "j.api-route-creation": () => API_ROUTE_CREATION,
18
+ "j.server-action-creation": () => SERVER_ACTION_CREATION,
19
+ "j.schema-migration": () => SCHEMA_MIGRATION,
20
+ "j.agents-md-writing": () => AGENTS_MD_WRITING,
21
+ "j.domain-doc-writing": () => DOMAIN_DOC_WRITING,
22
+ "j.principle-doc-writing": () => PRINCIPLE_DOC_WRITING,
23
+ "j.shell-script-writing": () => SHELL_SCRIPT_WRITING,
24
+ };
25
+ for (const skill of config.skills) {
26
+ const writer = skillWriters[skill];
27
+ if (!writer)
28
+ continue;
29
+ const skillDir = path_1.default.join(skillsDir, skill);
30
+ if (!(0, fs_1.existsSync)(skillDir)) {
31
+ (0, fs_1.mkdirSync)(skillDir, { recursive: true });
32
+ }
33
+ (0, fs_1.writeFileSync)(path_1.default.join(skillDir, "SKILL.md"), writer());
34
+ }
20
35
  }
21
- // ─── Test Writing ────────────────────────────────────────────────────────────
22
- const TEST_WRITING = `---
23
- name: j.test-writing
24
- description: Write focused unit and integration tests following project conventions
36
+ // ─── Test Writing (parameterized by type) ──────────────────────────────────
37
+ function testWriting(projectType, isKotlin) {
38
+ switch (projectType) {
39
+ case "node-nextjs":
40
+ case "node-generic":
41
+ return TEST_WRITING_NODE;
42
+ case "python":
43
+ return TEST_WRITING_PYTHON;
44
+ case "go":
45
+ return TEST_WRITING_GO;
46
+ case "java":
47
+ return isKotlin ? TEST_WRITING_KOTLIN : TEST_WRITING_JAVA;
48
+ case "generic":
49
+ return TEST_WRITING_GENERIC;
50
+ }
51
+ }
52
+ const TEST_WRITING_NODE = `---
53
+ name: j.test-writing
54
+ description: Write focused unit and integration tests following project conventions
25
55
  # Optional: uncomment to enable Playwright MCP for E2E tests
26
56
  # mcp:
27
57
  # playwright:
@@ -61,12 +91,12 @@ describe("ComponentName / functionName", () => {
61
91
  })
62
92
  \`\`\`
63
93
 
64
- ### 3. Coverage requirements
65
- - Happy path: at least 1 test
66
- - Error cases: test each distinct error path
67
- - Edge cases: empty inputs, boundary values, null/undefined
68
- - Prefer tests related to the changed files before running the full suite
69
- - Do NOT test implementation details — test behavior
94
+ ### 3. Coverage requirements
95
+ - Happy path: at least 1 test
96
+ - Error cases: test each distinct error path
97
+ - Edge cases: empty inputs, boundary values, null/undefined
98
+ - Prefer tests related to the changed files before running the full suite
99
+ - Do NOT test implementation details — test behavior
70
100
 
71
101
  ### 4. Mock strategy
72
102
  - Mock external dependencies (APIs, DB, file system)
@@ -96,15 +126,501 @@ it("should handle async operation", async () => {
96
126
  - \`expect.assertions(0)\` — always assert something
97
127
  - Tests that depend on order of execution
98
128
  `;
99
- // ─── Page Creation ────────────────────────────────────────────────────────────
100
- const PAGE_CREATION = `---
101
- name: j.page-creation
102
- description: Create Next.js App Router pages with correct patterns
103
- ---
104
-
105
- # Skill: Page Creation
106
-
107
- This is a stack-specific skill. Only apply it when the project actually uses Next.js App Router patterns.
129
+ const TEST_WRITING_PYTHON = `---
130
+ name: j.test-writing
131
+ description: Write focused unit and integration tests using pytest
132
+ ---
133
+
134
+ # Skill: Test Writing (Python)
135
+
136
+ ## When this skill activates
137
+ Writing or editing \`test_*.py\` or \`*_test.py\` files.
138
+
139
+ ## Required Steps
140
+
141
+ ### 1. Read the implementation first
142
+ Before writing any test, read the file being tested. Understand:
143
+ - What it does (not what you think it does)
144
+ - Its dependencies and side effects
145
+ - Error cases and edge conditions
146
+
147
+ ### 2. Test structure
148
+ Follow the AAA pattern with pytest:
149
+ \`\`\`python
150
+ class TestFunctionName:
151
+ """Tests for function_name."""
152
+
153
+ def test_happy_path(self):
154
+ # Arrange
155
+ input_data = ...
156
+
157
+ # Act
158
+ result = function_name(input_data)
159
+
160
+ # Assert
161
+ assert result == expected
162
+
163
+ def test_when_invalid_input(self):
164
+ with pytest.raises(ValueError, match="specific message"):
165
+ function_name(invalid_input)
166
+ \`\`\`
167
+
168
+ Or functional style:
169
+ \`\`\`python
170
+ def test_function_does_expected_thing():
171
+ # Arrange
172
+ input_data = ...
173
+
174
+ # Act
175
+ result = function_name(input_data)
176
+
177
+ # Assert
178
+ assert result == expected
179
+ \`\`\`
180
+
181
+ ### 3. Coverage requirements
182
+ - Happy path: at least 1 test
183
+ - Error cases: test each distinct error path with \`pytest.raises\`
184
+ - Edge cases: empty inputs, boundary values, None
185
+ - Prefer tests related to the changed files before running the full suite
186
+
187
+ ### 4. Mock strategy
188
+ - Use \`unittest.mock.patch\` or \`pytest-mock\` fixtures
189
+ - Mock external dependencies (APIs, DB, file system)
190
+ - Do NOT mock the module under test
191
+ \`\`\`python
192
+ from unittest.mock import patch, MagicMock
193
+
194
+ def test_with_mock(mocker):
195
+ mock_service = mocker.patch("module.ExternalService")
196
+ mock_service.return_value.fetch.return_value = {"data": "value"}
197
+
198
+ result = my_function()
199
+ assert result == expected
200
+ \`\`\`
201
+
202
+ ### 5. Fixtures
203
+ Use pytest fixtures for reusable setup:
204
+ \`\`\`python
205
+ @pytest.fixture
206
+ def sample_user():
207
+ return User(name="Test", email="test@example.com")
208
+
209
+ def test_user_display(sample_user):
210
+ assert sample_user.display_name == "Test"
211
+ \`\`\`
212
+
213
+ ### 6. Naming conventions
214
+ - File: \`test_{module}.py\` or \`{module}_test.py\`
215
+ - Class: \`TestClassName\`
216
+ - Function: \`test_{what_it_does}\` or \`test_when_{condition}_then_{outcome}\`
217
+
218
+ ## Anti-patterns to avoid
219
+ - \`assert True\` — meaningless assertion
220
+ - Testing private methods (\`_method\`) directly
221
+ - Tests that depend on execution order
222
+ - Mocking the module under test
223
+ - Using \`time.sleep\` in tests
224
+ `;
225
+ const TEST_WRITING_GO = `---
226
+ name: j.test-writing
227
+ description: Write focused unit and integration tests using Go testing
228
+ ---
229
+
230
+ # Skill: Test Writing (Go)
231
+
232
+ ## When this skill activates
233
+ Writing or editing \`*_test.go\` files.
234
+
235
+ ## Required Steps
236
+
237
+ ### 1. Read the implementation first
238
+ Before writing any test, read the file being tested. Understand:
239
+ - What it does (not what you think it does)
240
+ - Its dependencies and side effects
241
+ - Error cases and edge conditions
242
+
243
+ ### 2. Test structure
244
+ Use table-driven tests with \`t.Run\`:
245
+ \`\`\`go
246
+ func TestFunctionName(t *testing.T) {
247
+ tests := []struct {
248
+ name string
249
+ input InputType
250
+ expected OutputType
251
+ wantErr bool
252
+ }{
253
+ {
254
+ name: "happy path",
255
+ input: validInput,
256
+ expected: expectedOutput,
257
+ },
258
+ {
259
+ name: "invalid input returns error",
260
+ input: invalidInput,
261
+ wantErr: true,
262
+ },
263
+ }
264
+
265
+ for _, tt := range tests {
266
+ t.Run(tt.name, func(t *testing.T) {
267
+ result, err := FunctionName(tt.input)
268
+
269
+ if tt.wantErr {
270
+ if err == nil {
271
+ t.Fatal("expected error, got nil")
272
+ }
273
+ return
274
+ }
275
+ if err != nil {
276
+ t.Fatalf("unexpected error: %v", err)
277
+ }
278
+ if result != tt.expected {
279
+ t.Errorf("got %v, want %v", result, tt.expected)
280
+ }
281
+ })
282
+ }
283
+ }
284
+ \`\`\`
285
+
286
+ ### 3. Coverage requirements
287
+ - Happy path: at least 1 test case
288
+ - Error cases: test each distinct error path
289
+ - Edge cases: nil inputs, zero values, empty slices
290
+ - Use \`t.Parallel()\` for independent subtests
291
+
292
+ ### 4. Mock strategy
293
+ - Use interfaces for dependency injection
294
+ - Create mock implementations in test files
295
+ - For HTTP, use \`httptest.NewServer\`
296
+ - For DB, use test containers or in-memory implementations
297
+
298
+ ### 5. Test helpers
299
+ \`\`\`go
300
+ func setupTestDB(t *testing.T) *DB {
301
+ t.Helper()
302
+ db := NewTestDB()
303
+ t.Cleanup(func() { db.Close() })
304
+ return db
305
+ }
306
+ \`\`\`
307
+
308
+ ### 6. Naming conventions
309
+ - File: \`{package}_test.go\` in the same package
310
+ - Function: \`TestFunctionName\`, \`TestType_Method\`
311
+ - Subtests: descriptive names in \`t.Run("when condition", ...)\`
312
+
313
+ ## Anti-patterns to avoid
314
+ - Using \`t.Log\` instead of assertions
315
+ - Testing unexported functions from external packages
316
+ - Using global state between tests
317
+ - Not using \`t.Helper()\` in helper functions
318
+ `;
319
+ const TEST_WRITING_JAVA = `---
320
+ name: j.test-writing
321
+ description: Write focused unit and integration tests using JUnit 5
322
+ ---
323
+
324
+ # Skill: Test Writing (Java/JUnit 5)
325
+
326
+ ## When this skill activates
327
+ Writing or editing \`*Test.java\`, \`*Tests.java\`, or \`*IT.java\` files.
328
+
329
+ ## Required Steps
330
+
331
+ ### 1. Read the implementation first
332
+ Before writing any test, read the file being tested. Understand:
333
+ - What it does (not what you think it does)
334
+ - Its dependencies and side effects
335
+ - Error cases and edge conditions
336
+
337
+ ### 2. Test structure
338
+ Follow the AAA pattern with JUnit 5:
339
+ \`\`\`java
340
+ @DisplayName("FunctionName")
341
+ class FunctionNameTest {
342
+
343
+ @Nested
344
+ @DisplayName("when valid input")
345
+ class WhenValidInput {
346
+
347
+ @Test
348
+ @DisplayName("should return expected result")
349
+ void shouldReturnExpectedResult() {
350
+ // Arrange
351
+ var input = createValidInput();
352
+
353
+ // Act
354
+ var result = functionName(input);
355
+
356
+ // Assert
357
+ assertThat(result).isEqualTo(expected);
358
+ }
359
+ }
360
+
361
+ @Nested
362
+ @DisplayName("when invalid input")
363
+ class WhenInvalidInput {
364
+
365
+ @Test
366
+ @DisplayName("should throw IllegalArgumentException")
367
+ void shouldThrowException() {
368
+ assertThatThrownBy(() -> functionName(invalidInput))
369
+ .isInstanceOf(IllegalArgumentException.class)
370
+ .hasMessageContaining("specific message");
371
+ }
372
+ }
373
+ }
374
+ \`\`\`
375
+
376
+ ### 3. Coverage requirements
377
+ - Happy path: at least 1 test
378
+ - Error cases: test each distinct error path
379
+ - Edge cases: null inputs, empty collections, boundary values
380
+ - Use \`@ParameterizedTest\` for multiple inputs
381
+
382
+ ### 4. Mock strategy (Mockito)
383
+ - Mock external dependencies
384
+ - Do NOT mock the class under test
385
+ \`\`\`java
386
+ @ExtendWith(MockitoExtension.class)
387
+ class ServiceTest {
388
+
389
+ @Mock
390
+ private Repository repository;
391
+
392
+ @InjectMocks
393
+ private Service service;
394
+
395
+ @Test
396
+ void shouldReturnData() {
397
+ when(repository.findById(1L)).thenReturn(Optional.of(entity));
398
+
399
+ var result = service.getData(1L);
400
+
401
+ assertThat(result).isNotNull();
402
+ verify(repository).findById(1L);
403
+ }
404
+ }
405
+ \`\`\`
406
+
407
+ ### 5. Naming conventions
408
+ - File: \`{ClassName}Test.java\` in \`src/test/java/\`
409
+ - Class: \`{ClassName}Test\`
410
+ - Method: \`should{ExpectedBehavior}\` or \`should{Action}When{Condition}\`
411
+ - Use \`@DisplayName\` for readable test names
412
+
413
+ ## Anti-patterns to avoid
414
+ - \`assertTrue(true)\` — meaningless assertion
415
+ - Testing private methods via reflection
416
+ - \`@SuppressWarnings\` in tests
417
+ - Tests that depend on execution order
418
+ - Not using \`@ExtendWith(MockitoExtension.class)\`
419
+ `;
420
+ const TEST_WRITING_KOTLIN = `---
421
+ name: j.test-writing
422
+ description: Write focused unit and integration tests using JUnit 5 with Kotlin idioms
423
+ ---
424
+
425
+ # Skill: Test Writing (Kotlin/JUnit 5)
426
+
427
+ ## When this skill activates
428
+ Writing or editing \`*Test.kt\`, \`*Tests.kt\`, or \`*IT.kt\` files.
429
+
430
+ ## Required Steps
431
+
432
+ ### 1. Read the implementation first
433
+ Before writing any test, read the file being tested. Understand:
434
+ - What it does (not what you think it does)
435
+ - Its dependencies and side effects
436
+ - Error cases and edge conditions
437
+
438
+ ### 2. Test structure
439
+ Follow the AAA pattern with JUnit 5 and Kotlin idioms:
440
+ \`\`\`kotlin
441
+ @DisplayName("FunctionName")
442
+ class FunctionNameTest {
443
+
444
+ @Nested
445
+ @DisplayName("when valid input")
446
+ inner class WhenValidInput {
447
+
448
+ @Test
449
+ @DisplayName("should return expected result")
450
+ fun \`should return expected result\`() {
451
+ // Arrange
452
+ val input = createValidInput()
453
+
454
+ // Act
455
+ val result = functionName(input)
456
+
457
+ // Assert
458
+ assertThat(result).isEqualTo(expected)
459
+ }
460
+ }
461
+
462
+ @Nested
463
+ @DisplayName("when invalid input")
464
+ inner class WhenInvalidInput {
465
+
466
+ @Test
467
+ fun \`should throw IllegalArgumentException\`() {
468
+ assertThatThrownBy { functionName(invalidInput) }
469
+ .isInstanceOf(IllegalArgumentException::class.java)
470
+ .hasMessageContaining("specific message")
471
+ }
472
+ }
473
+ }
474
+ \`\`\`
475
+
476
+ ### 3. Kotlin-specific patterns
477
+ - Use backtick method names for readable test names: \`fun \\\`should do something\\\`()\`
478
+ - Use \`assertThrows<ExceptionType>\` from JUnit 5 Kotlin extensions
479
+ - Prefer \`shouldBe\`, \`shouldThrow\` if using Kotest assertions
480
+ - Use data classes for test fixtures
481
+ - Use \`@ParameterizedTest\` with \`@MethodSource\` for multiple inputs
482
+
483
+ \`\`\`kotlin
484
+ @ParameterizedTest
485
+ @MethodSource("invalidInputs")
486
+ fun \`should reject invalid input\`(input: String) {
487
+ assertThrows<ValidationException> {
488
+ validate(input)
489
+ }
490
+ }
491
+
492
+ companion object {
493
+ @JvmStatic
494
+ fun invalidInputs() = listOf("", " ", "invalid@chars")
495
+ }
496
+ \`\`\`
497
+
498
+ ### 4. Mock strategy (Mockito-Kotlin or MockK)
499
+ \`\`\`kotlin
500
+ // Using MockK (preferred for Kotlin)
501
+ class ServiceTest {
502
+
503
+ private val repository = mockk<Repository>()
504
+ private val service = Service(repository)
505
+
506
+ @Test
507
+ fun \`should return data\`() {
508
+ every { repository.findById(1L) } returns Optional.of(entity)
509
+
510
+ val result = service.getData(1L)
511
+
512
+ assertThat(result).isNotNull
513
+ verify { repository.findById(1L) }
514
+ }
515
+ }
516
+ \`\`\`
517
+
518
+ Or with Mockito-Kotlin:
519
+ \`\`\`kotlin
520
+ @ExtendWith(MockitoExtension::class)
521
+ class ServiceTest {
522
+
523
+ @Mock
524
+ lateinit var repository: Repository
525
+
526
+ @InjectMocks
527
+ lateinit var service: Service
528
+
529
+ @Test
530
+ fun \`should return data\`() {
531
+ whenever(repository.findById(1L)).thenReturn(Optional.of(entity))
532
+
533
+ val result = service.getData(1L)
534
+
535
+ assertThat(result).isNotNull
536
+ verify(repository).findById(1L)
537
+ }
538
+ }
539
+ \`\`\`
540
+
541
+ ### 5. Spring Boot test patterns
542
+ \`\`\`kotlin
543
+ @SpringBootTest
544
+ @ActiveProfiles("test")
545
+ class IntegrationTest {
546
+
547
+ @Autowired
548
+ lateinit var service: MyService
549
+
550
+ @MockkBean // or @MockBean for Mockito
551
+ lateinit var externalClient: ExternalClient
552
+
553
+ @Test
554
+ fun \`should integrate correctly\`() {
555
+ every { externalClient.fetch() } returns listOf(data)
556
+ val result = service.process()
557
+ assertThat(result).hasSize(1)
558
+ }
559
+ }
560
+ \`\`\`
561
+
562
+ ### 6. Naming conventions
563
+ - File: \`{ClassName}Test.kt\` in \`src/test/kotlin/\`
564
+ - Class: \`{ClassName}Test\`
565
+ - Method: backtick names for readability
566
+ - Use \`@DisplayName\` or \`@Nested\` for grouping
567
+
568
+ ## Anti-patterns to avoid
569
+ - \`assertTrue(true)\` — meaningless assertion
570
+ - Testing private methods via reflection
571
+ - Not using \`inner class\` with \`@Nested\` (required in Kotlin)
572
+ - Using Java-style mock setup instead of Kotlin DSL
573
+ - Not cleaning up coroutine test scopes in coroutine tests
574
+ - Ignoring \`runTest {}\` for suspend function tests
575
+ `;
576
+ const TEST_WRITING_GENERIC = `---
577
+ name: j.test-writing
578
+ description: Write focused unit and integration tests following AAA pattern
579
+ ---
580
+
581
+ # Skill: Test Writing (Generic)
582
+
583
+ ## When this skill activates
584
+ Writing or editing test files in any language.
585
+
586
+ ## Required Steps
587
+
588
+ ### 1. Read the implementation first
589
+ Before writing any test, read the file being tested.
590
+
591
+ ### 2. Test structure
592
+ Follow the AAA (Arrange-Act-Assert) pattern:
593
+ - **Arrange**: set up test data and dependencies
594
+ - **Act**: call the function/method under test
595
+ - **Assert**: verify the result matches expectations
596
+
597
+ ### 3. Coverage requirements
598
+ - Happy path: at least 1 test
599
+ - Error cases: test each distinct error path
600
+ - Edge cases: empty inputs, boundary values, null/nil/None
601
+
602
+ ### 4. Mock strategy
603
+ - Mock external dependencies (APIs, DB, file system)
604
+ - Do NOT mock the module under test
605
+
606
+ ### 5. Naming conventions
607
+ - Test names should describe the expected behavior
608
+ - Group related tests logically
609
+
610
+ ## Anti-patterns to avoid
611
+ - Meaningless assertions
612
+ - Testing implementation details instead of behavior
613
+ - Tests that depend on execution order
614
+ `;
615
+ // ─── Non-test skills (unchanged) ─────────────────────────────────────────────
616
+ const PAGE_CREATION = `---
617
+ name: j.page-creation
618
+ description: Create Next.js App Router pages with correct patterns
619
+ ---
620
+
621
+ # Skill: Page Creation
622
+
623
+ This is a stack-specific skill. Only apply it when the project actually uses Next.js App Router patterns.
108
624
 
109
625
  ## When this skill activates
110
626
  Creating or editing \`app/**/page.tsx\` or \`app/**/layout.tsx\` files.
@@ -176,15 +692,14 @@ Always create companion files:
176
692
  - Missing loading states
177
693
  - Not handling error boundaries
178
694
  `;
179
- // ─── API Route Creation ───────────────────────────────────────────────────────
180
- const API_ROUTE_CREATION = `---
181
- name: j.api-route-creation
182
- description: Create Next.js App Router API routes with correct patterns
183
- ---
184
-
185
- # Skill: API Route Creation
186
-
187
- This is a stack-specific skill. Only apply it when the project actually uses Next.js App Router routes.
695
+ const API_ROUTE_CREATION = `---
696
+ name: j.api-route-creation
697
+ description: Create Next.js App Router API routes with correct patterns
698
+ ---
699
+
700
+ # Skill: API Route Creation
701
+
702
+ This is a stack-specific skill. Only apply it when the project actually uses Next.js App Router routes.
188
703
 
189
704
  ## When this skill activates
190
705
  Creating or editing \`app/api/**/*.ts\` route files.
@@ -272,15 +787,14 @@ const CreateSchema = z.object({
272
787
  - Missing input validation
273
788
  - Returning 200 for errors
274
789
  `;
275
- // ─── Server Action Creation ───────────────────────────────────────────────────
276
- const SERVER_ACTION_CREATION = `---
277
- name: j.server-action-creation
278
- description: Create Next.js Server Actions with correct patterns
279
- ---
280
-
281
- # Skill: Server Action Creation
282
-
283
- This is a stack-specific skill. Only apply it when the project actually uses Next.js Server Actions.
790
+ const SERVER_ACTION_CREATION = `---
791
+ name: j.server-action-creation
792
+ description: Create Next.js Server Actions with correct patterns
793
+ ---
794
+
795
+ # Skill: Server Action Creation
796
+
797
+ This is a stack-specific skill. Only apply it when the project actually uses Next.js Server Actions.
284
798
 
285
799
  ## When this skill activates
286
800
  Creating or editing files with \`"use server"\` directive, typically \`actions.ts\` or \`**/actions/*.ts\`.
@@ -361,11 +875,10 @@ export function ExampleForm() {
361
875
  - Catching errors silently without logging
362
876
  - Forgetting to revalidate affected paths
363
877
  `;
364
- // ─── Schema Migration ─────────────────────────────────────────────────────────
365
- const SCHEMA_MIGRATION = `---
366
- name: j.schema-migration
367
- description: Modify Prisma schema and create migrations safely
368
- ---
878
+ const SCHEMA_MIGRATION = `---
879
+ name: j.schema-migration
880
+ description: Modify Prisma schema and create migrations safely
881
+ ---
369
882
 
370
883
  # Skill: Schema Migration
371
884
 
@@ -432,152 +945,152 @@ npx tsc --noEmit # type check
432
945
  npm test # run tests
433
946
  \`\`\`
434
947
 
435
- ## Anti-patterns
436
- - Renaming columns without a migration step (data loss)
437
- - Adding required columns without defaults to non-empty tables
438
- - Forgetting to run \`prisma generate\` after schema changes
439
- - Not updating TypeScript types after schema changes
948
+ ## Anti-patterns
949
+ - Renaming columns without a migration step (data loss)
950
+ - Adding required columns without defaults to non-empty tables
951
+ - Forgetting to run \`prisma generate\` after schema changes
952
+ - Not updating TypeScript types after schema changes
440
953
  `;
441
- const AGENTS_MD_WRITING = `---
442
- name: j.agents-md-writing
443
- description: Write strong AGENTS.md files with local rules, commands, and boundaries
444
- ---
445
-
446
- # Skill: AGENTS.md Writing
447
-
448
- ## When this skill activates
449
- Creating or editing any \`AGENTS.md\` file.
450
-
451
- ## Goal
452
- Write an agent-facing operating manual for the current directory only.
453
-
454
- ## Required Sections
455
- - Project or directory purpose
456
- - Build, lint, and test commands that actually work here
457
- - File layout and ownership boundaries
458
- - Local coding conventions and pitfalls
459
- - Review and verification expectations
460
-
461
- ## Rules
462
- - Keep the root \`AGENTS.md\` concise and high-signal
463
- - Make nested \`AGENTS.md\` files additive, not repetitive
464
- - Prefer concrete commands over vague guidance
465
- - Separate business rules from technical principles:
466
- - \`AGENTS.md\` = how to work in this area
467
- - \`docs/domain/*\` = business behavior
468
- - \`docs/principles/*\` = cross-cutting technical patterns
469
-
470
- ## Good patterns
471
- - Include exact commands such as \`npm test -- foo\` or \`./gradlew test --tests \"...\"\`
472
- - Call out invariants, ownership boundaries, and high-blast-radius files
473
- - Mention generated files, migrations, or release steps when relevant
474
-
475
- ## Anti-patterns
476
- - Dumping generic style advice with no repository specifics
477
- - Repeating the same commands in every nested file
478
- - Mixing business flows into technical instructions
479
- - Writing aspirational rules that are not enforced anywhere
954
+ const AGENTS_MD_WRITING = `---
955
+ name: j.agents-md-writing
956
+ description: Write strong AGENTS.md files with local rules, commands, and boundaries
957
+ ---
958
+
959
+ # Skill: AGENTS.md Writing
960
+
961
+ ## When this skill activates
962
+ Creating or editing any \`AGENTS.md\` file.
963
+
964
+ ## Goal
965
+ Write an agent-facing operating manual for the current directory only.
966
+
967
+ ## Required Sections
968
+ - Project or directory purpose
969
+ - Build, lint, and test commands that actually work here
970
+ - File layout and ownership boundaries
971
+ - Local coding conventions and pitfalls
972
+ - Review and verification expectations
973
+
974
+ ## Rules
975
+ - Keep the root \`AGENTS.md\` concise and high-signal
976
+ - Make nested \`AGENTS.md\` files additive, not repetitive
977
+ - Prefer concrete commands over vague guidance
978
+ - Separate business rules from technical principles:
979
+ - \`AGENTS.md\` = how to work in this area
980
+ - \`docs/domain/*\` = business behavior
981
+ - \`docs/principles/*\` = cross-cutting technical patterns
982
+
983
+ ## Good patterns
984
+ - Include exact commands such as \`npm test -- foo\` or \`./gradlew test --tests "..."\`
985
+ - Call out invariants, ownership boundaries, and high-blast-radius files
986
+ - Mention generated files, migrations, or release steps when relevant
987
+
988
+ ## Anti-patterns
989
+ - Dumping generic style advice with no repository specifics
990
+ - Repeating the same commands in every nested file
991
+ - Mixing business flows into technical instructions
992
+ - Writing aspirational rules that are not enforced anywhere
480
993
  `;
481
- const DOMAIN_DOC_WRITING = `---
482
- name: j.domain-doc-writing
483
- description: Write business-domain documentation that stays aligned with code
484
- ---
485
-
486
- # Skill: Domain Doc Writing
487
-
488
- ## When this skill activates
489
- Creating or editing files under \`docs/domain/\`.
490
-
491
- ## Goal
492
- Document how the business domain works now, not how the code is implemented internally.
493
-
494
- ## Required Structure
495
- - Domain summary
496
- - Rules and invariants
497
- - Inputs, outputs, and state transitions when relevant
498
- - Edge cases and operational limits
499
- - Source of truth references to the key code files
500
-
501
- ## Sync marker pattern
502
- At the top of a generated or refreshed section, prefer a marker like:
503
-
504
- \`<!-- juninho:sync source=src/payments/service.ts hash=abc123 -->\`
505
-
506
- Use the marker to indicate which code file justified the current documentation.
507
-
508
- ## Rules
509
- - Write in present tense
510
- - Prefer user-visible behavior and business meaning
511
- - Cite key files that justify each rule
512
- - Update \`docs/domain/INDEX.md\` when adding or renaming a domain doc
513
-
514
- ## Anti-patterns
515
- - Explaining framework internals instead of business behavior
516
- - Copying raw code into the document
517
- - Leaving undocumented edge cases discovered during implementation
994
+ const DOMAIN_DOC_WRITING = `---
995
+ name: j.domain-doc-writing
996
+ description: Write business-domain documentation that stays aligned with code
997
+ ---
998
+
999
+ # Skill: Domain Doc Writing
1000
+
1001
+ ## When this skill activates
1002
+ Creating or editing files under \`docs/domain/\`.
1003
+
1004
+ ## Goal
1005
+ Document how the business domain works now, not how the code is implemented internally.
1006
+
1007
+ ## Required Structure
1008
+ - Domain summary
1009
+ - Rules and invariants
1010
+ - Inputs, outputs, and state transitions when relevant
1011
+ - Edge cases and operational limits
1012
+ - Source of truth references to the key code files
1013
+
1014
+ ## Sync marker pattern
1015
+ At the top of a generated or refreshed section, prefer a marker like:
1016
+
1017
+ \`<!-- juninho:sync source=src/payments/service.ts hash=abc123 -->\`
1018
+
1019
+ Use the marker to indicate which code file justified the current documentation.
1020
+
1021
+ ## Rules
1022
+ - Write in present tense
1023
+ - Prefer user-visible behavior and business meaning
1024
+ - Cite key files that justify each rule
1025
+ - Update \`docs/domain/INDEX.md\` when adding or renaming a domain doc
1026
+
1027
+ ## Anti-patterns
1028
+ - Explaining framework internals instead of business behavior
1029
+ - Copying raw code into the document
1030
+ - Leaving undocumented edge cases discovered during implementation
518
1031
  `;
519
- const PRINCIPLE_DOC_WRITING = `---
520
- name: j.principle-doc-writing
521
- description: Write technical principle docs with rationale, rules, and examples
522
- ---
523
-
524
- # Skill: Principle Doc Writing
525
-
526
- ## When this skill activates
527
- Creating or editing files under \`docs/principles/\`.
528
-
529
- ## Goal
530
- Capture cross-cutting engineering guidance that multiple modules should follow.
531
-
532
- ## Required Structure
533
- - Problem this principle solves
534
- - Rule set (do / avoid)
535
- - Rationale and trade-offs
536
- - Canonical examples in this repository
537
- - Related files or tooling that enforce the rule
538
-
539
- ## Sync marker pattern
540
- For generated sections, prefer a marker like:
541
-
542
- \`<!-- juninho:sync source=src/api/client.ts hash=def456 -->\`
543
-
544
- ## Rules
545
- - Keep principles technical, reusable, and stack-aware
546
- - Reference concrete files or commands when possible
547
- - Register or update the keyword mapping in \`docs/principles/manifest\`
548
- - Distinguish principle docs from domain docs and \`AGENTS.md\`
549
-
550
- ## Anti-patterns
551
- - Repeating business requirements here
552
- - Writing slogans with no enforcement or examples
553
- - Documenting obsolete patterns without marking them deprecated
1032
+ const PRINCIPLE_DOC_WRITING = `---
1033
+ name: j.principle-doc-writing
1034
+ description: Write technical principle docs with rationale, rules, and examples
1035
+ ---
1036
+
1037
+ # Skill: Principle Doc Writing
1038
+
1039
+ ## When this skill activates
1040
+ Creating or editing files under \`docs/principles/\`.
1041
+
1042
+ ## Goal
1043
+ Capture cross-cutting engineering guidance that multiple modules should follow.
1044
+
1045
+ ## Required Structure
1046
+ - Problem this principle solves
1047
+ - Rule set (do / avoid)
1048
+ - Rationale and trade-offs
1049
+ - Canonical examples in this repository
1050
+ - Related files or tooling that enforce the rule
1051
+
1052
+ ## Sync marker pattern
1053
+ For generated sections, prefer a marker like:
1054
+
1055
+ \`<!-- juninho:sync source=src/api/client.ts hash=def456 -->\`
1056
+
1057
+ ## Rules
1058
+ - Keep principles technical, reusable, and stack-aware
1059
+ - Reference concrete files or commands when possible
1060
+ - Register or update the keyword mapping in \`docs/principles/manifest\`
1061
+ - Distinguish principle docs from domain docs and \`AGENTS.md\`
1062
+
1063
+ ## Anti-patterns
1064
+ - Repeating business requirements here
1065
+ - Writing slogans with no enforcement or examples
1066
+ - Documenting obsolete patterns without marking them deprecated
554
1067
  `;
555
- const SHELL_SCRIPT_WRITING = `---
556
- name: j.shell-script-writing
557
- description: Write robust shell automation for project workflows and hooks
558
- ---
559
-
560
- # Skill: Shell Script Writing
561
-
562
- ## When this skill activates
563
- Creating or editing shell scripts, especially in \`.opencode/scripts/\`, \`scripts/\`, or git hooks.
564
-
565
- ## Required Steps
566
- 1. Start with \`#!/bin/sh\` unless bash-only features are required
567
- 2. Use \`set -e\` and quote every variable expansion that can contain spaces
568
- 3. Resolve and \`cd\` to the project root before running project commands
569
- 4. Prefer delegating to project scripts (\`npm run ...\`, \`make ...\`, \`./gradlew ...\`) over embedding large command logic
570
- 5. Print short, actionable failure messages
571
-
572
- ## Preferred patterns
573
- - Detect staged files once and reuse them
574
- - Support project-specific overrides before framework defaults
575
- - Keep hook scripts fast; full-suite checks belong outside the pre-commit path
576
-
577
- ## Anti-patterns
578
- - Hardcoding one stack when multiple fallback commands are possible
579
- - Running the full test suite inside pre-commit by default
580
- - Using unquoted file lists or unsafe globbing
581
- - Mixing environment bootstrapping with small hook utilities
1068
+ const SHELL_SCRIPT_WRITING = `---
1069
+ name: j.shell-script-writing
1070
+ description: Write robust shell automation for project workflows and hooks
1071
+ ---
1072
+
1073
+ # Skill: Shell Script Writing
1074
+
1075
+ ## When this skill activates
1076
+ Creating or editing shell scripts, especially in \`.opencode/scripts/\`, \`scripts/\`, or git hooks.
1077
+
1078
+ ## Required Steps
1079
+ 1. Start with \`#!/bin/sh\` unless bash-only features are required
1080
+ 2. Use \`set -e\` and quote every variable expansion that can contain spaces
1081
+ 3. Resolve and \`cd\` to the project root before running project commands
1082
+ 4. Prefer delegating to project scripts (\`npm run ...\`, \`make ...\`, \`./gradlew ...\`) over embedding large command logic
1083
+ 5. Print short, actionable failure messages
1084
+
1085
+ ## Preferred patterns
1086
+ - Detect staged files once and reuse them
1087
+ - Support project-specific overrides before framework defaults
1088
+ - Keep hook scripts fast; full-suite checks belong outside the pre-commit path
1089
+
1090
+ ## Anti-patterns
1091
+ - Hardcoding one stack when multiple fallback commands are possible
1092
+ - Running the full test suite inside pre-commit by default
1093
+ - Using unquoted file lists or unsafe globbing
1094
+ - Mixing environment bootstrapping with small hook utilities
582
1095
  `;
583
1096
  //# sourceMappingURL=skills.js.map