opencode-agent-skills-md 1.0.0 → 1.1.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 (129) hide show
  1. package/dist/cli.mjs +770 -0
  2. package/dist/plugin.mjs +1138 -0
  3. package/dist/src/cli/config.d.ts +144 -0
  4. package/dist/src/cli/install.d.ts +33 -0
  5. package/dist/src/cli/main.d.ts +11 -0
  6. package/dist/src/cli/real-fs.d.ts +6 -0
  7. package/dist/src/cli/status.d.ts +34 -0
  8. package/dist/src/cli/uninstall.d.ts +22 -0
  9. package/dist/src/host.d.ts +51 -0
  10. package/dist/src/index.d.ts +17 -0
  11. package/dist/src/plugin.d.ts +35 -0
  12. package/dist/src/sdk.d.ts +51 -0
  13. package/dist/src/tools.d.ts +86 -0
  14. package/package.json +48 -18
  15. package/{packages/opencode-agent-skills-md/src → src}/cli/main.ts +20 -4
  16. package/.beads/.local_version +0 -1
  17. package/.beads/README.md +0 -81
  18. package/.beads/config.yaml +0 -61
  19. package/.beads/deletions.jsonl +0 -1
  20. package/.beads/issues.jsonl +0 -64
  21. package/.beads/metadata.json +0 -4
  22. package/.gitattributes +0 -3
  23. package/.github/CODEOWNERS +0 -1
  24. package/.github/copilot-instructions.md +0 -78
  25. package/.github/dependabot.yml +0 -13
  26. package/.github/workflows/release.yml +0 -51
  27. package/.opencode/command/test-compaction.md +0 -9
  28. package/.opencode/command/test-find-skills.md +0 -7
  29. package/.opencode/command/test-read-skill-file.md +0 -14
  30. package/.opencode/command/test-run-skill-script.md +0 -13
  31. package/.opencode/command/test-skills.md +0 -14
  32. package/.opencode/command/test-use-skill.md +0 -10
  33. package/.opencode/skills/git-helper/SKILL.md +0 -65
  34. package/.opencode/skills/test-skill/SKILL.md +0 -43
  35. package/.opencode/skills/test-skill/example-config.json +0 -16
  36. package/.opencode/skills/test-skill/helper-docs.md +0 -29
  37. package/.opencode/skills/test-skill/scripts/echo-args +0 -14
  38. package/.opencode/skills/test-skill/scripts/greet +0 -6
  39. package/AGENTS.md +0 -43
  40. package/CHANGELOG.md +0 -178
  41. package/Justfile +0 -39
  42. package/README.md +0 -189
  43. package/openspec/changes/archive/2026-06-14-skills-core-decouple/specs/core-decoupling/spec.md +0 -74
  44. package/openspec/changes/archive/2026-06-14-skills-core-decouple/tasks.md +0 -64
  45. package/openspec/changes/archive/2026-06-14-skills-core-decouple/verify-report.md +0 -75
  46. package/openspec/changes/archive/2026-06-17-fix-skill-loading-regression/apply-progress.md +0 -136
  47. package/openspec/changes/archive/2026-06-17-fix-skill-loading-regression/archive-report.md +0 -77
  48. package/openspec/changes/archive/2026-06-17-fix-skill-loading-regression/design.md +0 -89
  49. package/openspec/changes/archive/2026-06-17-fix-skill-loading-regression/proposal.md +0 -65
  50. package/openspec/changes/archive/2026-06-17-fix-skill-loading-regression/specs/core-decoupling/spec.md +0 -77
  51. package/openspec/changes/archive/2026-06-17-fix-skill-loading-regression/tasks.md +0 -65
  52. package/openspec/changes/archive/2026-06-17-fix-skill-loading-regression/verify-report.md +0 -165
  53. package/openspec/specs/core-decoupling/spec.md +0 -110
  54. package/packages/core/package.json +0 -30
  55. package/packages/core/src/content.d.ts +0 -16
  56. package/packages/core/src/content.ts +0 -30
  57. package/packages/core/src/debug.ts +0 -16
  58. package/packages/core/src/discovery.d.ts +0 -86
  59. package/packages/core/src/discovery.ts +0 -257
  60. package/packages/core/src/index.d.ts +0 -20
  61. package/packages/core/src/index.ts +0 -55
  62. package/packages/core/src/match.d.ts +0 -19
  63. package/packages/core/src/match.ts +0 -75
  64. package/packages/core/src/parse.d.ts +0 -26
  65. package/packages/core/src/parse.ts +0 -141
  66. package/packages/core/src/scripts.d.ts +0 -17
  67. package/packages/core/src/scripts.ts +0 -79
  68. package/packages/core/src/search.d.ts +0 -83
  69. package/packages/core/src/search.ts +0 -188
  70. package/packages/core/src/types.d.ts +0 -82
  71. package/packages/core/src/types.ts +0 -131
  72. package/packages/core/src/walk.ts +0 -109
  73. package/packages/core/tests/agnostic.test.ts +0 -346
  74. package/packages/core/tests/content.test.ts +0 -65
  75. package/packages/core/tests/discovery.test.ts +0 -370
  76. package/packages/core/tests/package-boundary.test.ts +0 -310
  77. package/packages/core/tests/parse-trigger.test.ts +0 -282
  78. package/packages/core/tests/search.test.ts +0 -374
  79. package/packages/core/tests/subpath.test.ts +0 -87
  80. package/packages/core/tsconfig.json +0 -10
  81. package/packages/opencode-agent-skills-md/package.json +0 -42
  82. package/packages/opencode-agent-skills-md/rolldown.config.js +0 -48
  83. package/packages/opencode-agent-skills-md/tests/cli-commands.test.ts +0 -1423
  84. package/packages/opencode-agent-skills-md/tests/e2e/startup-smoke.test.ts +0 -66
  85. package/packages/opencode-agent-skills-md/tests/fixtures/skills/home/.claude/skills/claude-user-only-skill/SKILL.md +0 -8
  86. package/packages/opencode-agent-skills-md/tests/fixtures/skills/home/.config/opencode/skills/shared-skill/SKILL.md +0 -8
  87. package/packages/opencode-agent-skills-md/tests/fixtures/skills/home/.config/opencode/skills/user-only-skill/SKILL.md +0 -8
  88. package/packages/opencode-agent-skills-md/tests/fixtures/skills/project/.claude/skills/claude-project-only-skill/SKILL.md +0 -8
  89. package/packages/opencode-agent-skills-md/tests/fixtures/skills/project/.opencode/skills/go-tester/SKILL.md +0 -12
  90. package/packages/opencode-agent-skills-md/tests/fixtures/skills/project/.opencode/skills/nested/team/nested-skill/SKILL.md +0 -8
  91. package/packages/opencode-agent-skills-md/tests/fixtures/skills/project/.opencode/skills/rust-tester/SKILL.md +0 -11
  92. package/packages/opencode-agent-skills-md/tests/fixtures/skills/project/.opencode/skills/scripted-skill/SKILL.md +0 -8
  93. package/packages/opencode-agent-skills-md/tests/fixtures/skills/project/.opencode/skills/scripted-skill/bin/echo.sh +0 -2
  94. package/packages/opencode-agent-skills-md/tests/fixtures/skills/project/.opencode/skills/scripted-skill/docs/reference.md +0 -1
  95. package/packages/opencode-agent-skills-md/tests/fixtures/skills/project/.opencode/skills/shared-skill/SKILL.md +0 -8
  96. package/packages/opencode-agent-skills-md/tests/fixtures/skills/project/.opencode/skills/using-superpowers/SKILL.md +0 -8
  97. package/packages/opencode-agent-skills-md/tests/integration/helpers/mock-opencode.ts +0 -114
  98. package/packages/opencode-agent-skills-md/tests/integration/plugin.test.ts +0 -316
  99. package/packages/opencode-agent-skills-md/tests/integration/skill-discovery.test.ts +0 -315
  100. package/packages/opencode-agent-skills-md/tests/opencode/host.test.ts +0 -179
  101. package/packages/opencode-agent-skills-md/tests/opencode/plugin.test.ts +0 -551
  102. package/packages/opencode-agent-skills-md/tests/opencode/subpath.test.ts +0 -66
  103. package/packages/opencode-agent-skills-md/tests/opencode/tools.test.ts +0 -213
  104. package/packages/opencode-agent-skills-md/tests/package-boundary.test.ts +0 -346
  105. package/packages/opencode-agent-skills-md/tests/tools-security.test.ts +0 -72
  106. package/packages/opencode-agent-skills-md/tsconfig.build.json +0 -11
  107. package/packages/opencode-agent-skills-md/tsconfig.json +0 -10
  108. package/plans/001-ci-gate.md +0 -177
  109. package/plans/002-is-path-safe.md +0 -243
  110. package/plans/003-escape-prompts.md +0 -310
  111. package/plans/004-test-security-paths.md +0 -228
  112. package/plans/005-stop-swallowing-errors.md +0 -246
  113. package/plans/006-preserve-jsonc-commas.md +0 -144
  114. package/plans/007-write-before-purge.md +0 -144
  115. package/plans/008-reuse-walkdir-for-list-skill-files.md +0 -164
  116. package/plans/README.md +0 -43
  117. package/pnpm-workspace.yaml +0 -6
  118. package/tests/workspace.test.ts +0 -367
  119. package/tsconfig.json +0 -15
  120. /package/{packages/opencode-agent-skills-md/src → src}/cli/config.ts +0 -0
  121. /package/{packages/opencode-agent-skills-md/src → src}/cli/install.ts +0 -0
  122. /package/{packages/opencode-agent-skills-md/src → src}/cli/real-fs.ts +0 -0
  123. /package/{packages/opencode-agent-skills-md/src → src}/cli/status.ts +0 -0
  124. /package/{packages/opencode-agent-skills-md/src → src}/cli/uninstall.ts +0 -0
  125. /package/{packages/opencode-agent-skills-md/src → src}/host.ts +0 -0
  126. /package/{packages/opencode-agent-skills-md/src → src}/index.ts +0 -0
  127. /package/{packages/opencode-agent-skills-md/src → src}/plugin.ts +0 -0
  128. /package/{packages/opencode-agent-skills-md/src → src}/sdk.ts +0 -0
  129. /package/{packages/opencode-agent-skills-md/src → src}/tools.ts +0 -0
@@ -1,65 +0,0 @@
1
- # Tasks: Fix Skill-Loading Regression
2
-
3
- ## Review Workload Forecast
4
-
5
- | Field | Value |
6
- |-------|-------|
7
- | Estimated changed lines | 180-260 |
8
- | 400-line budget risk | Medium |
9
- | Chained PRs recommended | Yes |
10
- | Suggested split | PR 1 → PR 2 → PR 3 (optional) |
11
- | Delivery strategy | force-chained |
12
- | Chain strategy | stacked-to-main |
13
-
14
- Decision needed before apply: No
15
- Chained PRs recommended: Yes
16
- Chain strategy: stacked-to-main
17
- 400-line budget risk: Medium
18
-
19
- ### Suggested Work Units
20
-
21
- | Unit | Goal | Likely PR | Notes |
22
- |------|------|-----------|-------|
23
- | 1 | Restore callback seam + session dedupe | PR 1 | `src/opencode/*`; tests first |
24
- | 2 | Restore baseline discovery sources | PR 2 | `src/core/discovery.ts`; stack after PR 1 |
25
- | 3 | Cleanup only if scope stays tight | PR 3 | Optional polish + final verification |
26
-
27
- ## Phase 1: PR 1 — Callback wiring
28
-
29
- - [x] 1.1 RED — Extend `tests/opencode/plugin.test.ts` and `tests/integration/plugin.test.ts` to fail when `use_skill` loads once but does not update loaded-session state or suppress duplicate re-injection; commit `test: add skill loading callback regression coverage`.
30
- - [x] 1.2 GREEN — Update `src/opencode/tools.ts` and `src/opencode/plugin.ts` to thread optional `onSkillLoaded` through `createSkillTools()` → `UseSkill()` and restore `loadedSkillsPerSession` updates; commit `fix: restore use-skill callback wiring`.
31
- - [x] 1.3 REFACTOR — Keep the callback seam optional, trim duplicated plugin-test setup, and rerun `node --import tsx --test tests/opencode/plugin.test.ts tests/integration/plugin.test.ts`; commit `refactor: preserve optional skill callback seam`.
32
-
33
- ## Phase 2: PR 2 — Discovery breadth
34
-
35
- - [x] 2.1 RED — Extend `tests/integration/skill-discovery.test.ts` with baseline-coverage cases for `.opencode/skills`, `.claude/skills`, `~/.config/opencode/skills`, `~/.claude/skills`, plus the partial-trigger regression from spec R5; commit `test: add discovery breadth regression coverage`.
36
- - [x] 2.2 GREEN — Modify `src/core/discovery.ts` to restore the pre-refactor source set from `c2d8e74` while preserving first-match-wins and duplicate warnings; commit `fix: restore baseline skill discovery sources`.
37
- - [x] 2.3 REFACTOR — Normalize any helper/constants in `src/core/discovery.ts`, keep search/host boundaries unchanged, and rerun `node --import tsx --test tests/integration/skill-discovery.test.ts`; commit `refactor: clean up discovery source helpers`.
38
-
39
- ## Phase 3: PR 3 — Optional cleanup / verification
40
-
41
- - [x] 3.1 RED/GREEN — Coverage gap check: PR 1 + PR 2 cover all spec R3/R5 scenarios. No additional regression needed; skip the commit.
42
- - [x] 3.2 REFACTOR — Code is already minimal (OnSkillLoaded type, inlined 4-line callback, DEFAULT_DISCOVERY_MAX_DEPTH constant). No behavior-neutral cleanup needed; skip the commit.
43
- - [x] 3.3 VERIFY — Run `pnpm run typecheck` (clean) and the full `pnpm test` suite (102 tests, 0 fail); commit `chore: verify skill loading regression fix`.
44
-
45
- ## Final Commit Stack
46
-
47
- ```
48
- d2c3584 test: correct dedupe assertion to allow other matches
49
- c1f5b27 chore: verify skill loading regression fix
50
- 8c7de19 refactor: clean up discovery source helpers
51
- 7e4293e fix: restore baseline skill discovery sources
52
- b764c15 test: add discovery breadth regression coverage
53
- 9e975ab refactor: preserve optional skill callback seam
54
- fd4ab41 fix: restore use-skill callback wiring
55
- c64d4e7 test: add skill loading callback regression coverage
56
- 01c4b46 chore(sdd): add fix-skill-loading-regression change artifacts
57
- ```
58
-
59
- ## Verification
60
-
61
- - `pnpm run typecheck` — clean
62
- - `node --import tsx --test src/utils.test.ts tests/core/*.test.ts tests/opencode/plugin.test.ts tests/integration/plugin.test.ts tests/integration/skill-discovery.test.ts tests/e2e/*.test.ts` — 89 pass / 0 fail
63
- - `pnpm test` (unit + core + opencode + integration + e2e) — 102 pass / 0 fail
64
- - All spec R3 scenarios covered: callback fires, dedupe, missing-callback
65
- - All spec R5 scenarios covered: priority + first-match-wins, baseline match, partial-trigger
@@ -1,165 +0,0 @@
1
- ## Verification Report
2
-
3
- **Change**: fix-skill-loading-regression
4
- **Version**: delta for core-decoupling (R3, R5)
5
- **Mode**: Strict TDD
6
-
7
- ---
8
-
9
- ### Completeness
10
- | Metric | Value |
11
- |--------|-------|
12
- | Tasks total | 9 |
13
- | Tasks complete | 9 |
14
- | Tasks incomplete | 0 |
15
-
16
- ---
17
-
18
- ### Build & Tests Execution
19
- **Build**: ✅ Passed
20
- ```text
21
- $ CI=true pnpm run typecheck
22
- $ tsc --noEmit
23
- (no errors, silent)
24
- ```
25
-
26
- **Tests**: ✅ 102 passed / 0 failed / 0 skipped
27
- ```text
28
- unit: 42 pass (src/*.test.ts)
29
- core: 20 pass (tests/core/*.test.ts)
30
- opencode: 22 pass (tests/opencode/*.test.ts) ← 3 new regression tests
31
- integration: 17 pass (tests/integration/*.test.ts) ← 2 new regression tests
32
- e2e: 1 pass (tests/e2e/*.test.ts)
33
- Total: 102 pass / 0 fail
34
- ```
35
-
36
- **Coverage**: ➖ Not available (no coverage tool in project capabilities)
37
-
38
- ---
39
-
40
- ### Spec Compliance Matrix
41
-
42
- #### R3 — Backward-Compatible Root Export
43
-
44
- | Scenario | Test | Result |
45
- |----------|------|--------|
46
- | Root export still loads the OpenCode plugin with four tool names | `tests/integration/startup-smoke.test.ts` (existing) | ✅ COMPLIANT |
47
- | use_skill fires the onSkillLoaded callback | `tests/opencode/plugin.test.ts` > "createSkillTools forwards onSkillLoaded so UseSkill invokes it (R3)" | ✅ COMPLIANT |
48
- | use_skill does not re-inject the same skill in one session | `tests/opencode/plugin.test.ts` > "plugin updates loadedSkillsPerSession so a repeat chat.message does not re-inject (R3 dedupe)" | ✅ COMPLIANT |
49
- | missing callback does not break the load | `tests/opencode/plugin.test.ts` > "use_skill still loads when no callback is registered (R3 missing-callback)" | ✅ COMPLIANT |
50
-
51
- #### R5 — Discovery Semantics Preservation
52
-
53
- | Scenario | Test | Result |
54
- |----------|------|--------|
55
- | Discovery priority and first-match-wins are preserved | `tests/integration/skill-discovery.test.ts` > "discoverAllSkills surfaces skills from all four priority locations" + "first-match-wins: project skill shadows the same-named user skill" | ✅ COMPLIANT |
56
- | discoverAllSkills matches the pre-refactor skill set | `tests/integration/skill-discovery.test.ts` > "discoverAllSkills surfaces skills from all four priority locations" | ✅ COMPLIANT |
57
- | Literal-token search does not drop the pre-refactor skill set | `tests/integration/skill-discovery.test.ts` > "a skill whose trigger tokens are partial substrings of the query still appears" | ✅ COMPLIANT |
58
-
59
- **Compliance summary**: 7/7 scenarios compliant
60
-
61
- ---
62
-
63
- ### Correctness (Static Evidence)
64
-
65
- | Requirement | Status | Evidence |
66
- |------------|--------|---------|
67
- | R3 — onSkillLoaded threading through createSkillTools | ✅ Implemented | `src/opencode/tools.ts:79` — optional `onSkillLoaded?` 4th param; `src/opencode/tools.ts:316` — `onSkillLoaded?.()` called after injectContent |
68
- | R3 — loadedSkillsPerSession updated by callback | ✅ Implemented | `src/opencode/plugin.ts:120-122` — inline callback adds to session set |
69
- | R3 — dedupe via loadedSkillsPerSession | ✅ Implemented | `src/opencode/plugin.ts:187-188` — filter: `!loadedSkills.has(s.name)` |
70
- | R3 — missing callback is safe (optional) | ✅ Implemented | `onSkillLoaded?.()` uses optional chaining; no-op when undefined |
71
- | R5 — four-location priority restored | ✅ Implemented | `src/core/discovery.ts:125-132` — `getDefaultOpencodeRoots` returns all four roots |
72
- | R5 — first-match-wins preserved | ✅ Implemented | `src/core/discovery.ts:176-179` — duplicate handling calls `onDuplicate` but does not store |
73
- | R5 — DEFAULT_DISCOVERY_MAX_DEPTH = 3 | ✅ Implemented | `src/core/discovery.ts:113` constant; `src/core/discovery.ts:127-130` used in all four roots |
74
- | R5 — partial-trigger regression covered | ✅ Implemented | `tests/integration/skill-discovery.test.ts:277-314` — dynamically creates fixture skill and asserts it is surfaced |
75
-
76
- ---
77
-
78
- ### Coherence (Design)
79
-
80
- | Decision | Followed? | Notes |
81
- |----------|-----------|-------|
82
- | Thread `onSkillLoaded` through `createSkillTools` → `UseSkill` | ✅ Yes | Signature change minimal (optional 4th arg); no behavioral change to other three tools |
83
- | Restore discovery breadth in `core/discovery.ts` | ✅ Yes | `getDefaultOpencodeRoots` widened to four locations; no changes to search/ranking/validation |
84
- | Keep core/host split intact | ✅ Yes | `src/core/` has zero references to `@opencode-ai/plugin`; host adapter only in `src/opencode/` |
85
- | Keep search engine, tag filtering, trigger-aware ranking, Zod parsing, path-safety | ✅ Yes | All preserved; `DEFAULT_DISCOVERY_MAX_DEPTH` constant extracted |
86
- | `getDefaultOpencodeRoots` remains canonical discovery-source definition | ✅ Yes | Returns `DiscoveryPath[]`; no host-specific knowledge moved to core modules |
87
-
88
- ---
89
-
90
- ### TDD Compliance
91
-
92
- | Check | Result | Details |
93
- |-------|--------|---------|
94
- | TDD Evidence reported | ✅ | Found in `apply-progress.md` — "TDD Cycle Evidence" table with all rows |
95
- | All tasks have tests | ✅ | 9/9 tasks have test files or production commits |
96
- | RED confirmed (tests exist) | ✅ | 5 test files written/modified: `tests/opencode/plugin.test.ts`, `tests/integration/plugin.test.ts`, `tests/integration/skill-discovery.test.ts` |
97
- | GREEN confirmed (tests pass) | ✅ | All 102 tests pass on execution |
98
- | Triangulation adequate | ✅ | R3 has 3 test cases; R5 has 3 test cases (per spec scenarios) |
99
- | Safety Net for modified files | ✅ | Pre-existing tests (42 unit + 20 core + 22 opencode + 17 integration + 1 e2e = 102) ran before each PR |
100
- | TDD cycle completeness | ✅ | RED → GREEN → REFACTOR sequence documented per task |
101
-
102
- **TDD Compliance**: 7/7 checks passed
103
-
104
- ---
105
-
106
- ### Test Layer Distribution
107
-
108
- | Layer | Tests | Files | Notes |
109
- |-------|-------|-------|-------|
110
- | Unit | 22 | 1 | `tests/opencode/plugin.test.ts` — matchSkillsByKeyword, formatMatchedSkillsInjection, callback wiring |
111
- | Integration | 17 | 2 | `tests/integration/plugin.test.ts` (plugin integration + keywords), `tests/integration/skill-discovery.test.ts` (discovery breadth + normalization) |
112
- | E2E | 1 | 1 | `tests/e2e/startup-smoke.test.ts` |
113
- | **Total** | **102** | **~12** | Full suite green |
114
-
115
- ---
116
-
117
- ### Changed File Coverage
118
-
119
- | File | Lines (Δ) | Test Count | Coverage |
120
- |------|-----------|------------|----------|
121
- | `src/opencode/tools.ts` | +18/-3 | 3 regression tests | ⚠️ Low (no per-file coverage tool) |
122
- | `src/opencode/plugin.ts` | +7/-6 | 2 regression tests | ⚠️ Low (no per-file coverage tool) |
123
- | `src/core/discovery.ts` | +8/-5 | 4 regression tests | ⚠️ Low (no per-file coverage tool) |
124
-
125
- **Average changed file coverage**: ➖ Not available (no coverage tool detected)
126
-
127
- ---
128
-
129
- ### Assertion Quality
130
-
131
- | File | Line | Assertion | Issue | Severity |
132
- |------|------|-----------|-------|----------|
133
- | — | — | — | — | — |
134
-
135
- **Assertion quality**: ✅ All assertions verify real behavior (no tautologies, no ghost loops, no smoke-only tests)
136
-
137
- ---
138
-
139
- ### Issues Found
140
-
141
- **CRITICAL**: None
142
- **WARNING**: None
143
- **SUGGESTION**: None
144
-
145
- ---
146
-
147
- ### Notable Observations
148
-
149
- 1. **Dedupe assertion nuance**: The dedupe tests correctly assert that the *loaded* skill is *filtered out* of `<skill-evaluation-required>` injections — not that zero injections fire (other skills may match the same query tokens). This is the correct regression target per the apply-progress discovery log.
150
-
151
- 2. **maxDepth deviation from c2d8e74 baseline**: Pre-refactor `c2d8e74` used `maxDepth: 1` for Claude-side roots; commit `12de52a` widened to 3 deliberately. The JSDoc in `discovery.ts` now documents this intentionally and the regression net locks `maxDepth: 3` in place.
152
-
153
- 3. **Plugin/marketplace discovery out of scope**: The `c2d8e74` baseline also surfaced `~/.claude/plugins/cache/` and `~/.claude/plugins/marketplaces/`. The proposal correctly scoped this fix to the four standard locations only.
154
-
155
- 4. **Callback already existed in UseSkill**: `UseSkill` already accepted `onSkillLoaded?` before the fix. `createSkillTools` simply never accepted or forwarded it. The fix is a minimal 2-line production code change.
156
-
157
- ---
158
-
159
- ### Verdict
160
-
161
- **PASS**
162
-
163
- All 9 tasks complete. All 7 spec scenarios have covering tests that pass. All 3 design decisions are implemented correctly and coherently. Typecheck clean; 102/102 tests green. Strict TDD protocol was followed (RED → GREEN → REFACTOR per task). No critical issues, warnings, or suggestions.
164
-
165
- **Next recommended**: sdd-archive
@@ -1,110 +0,0 @@
1
- # Core Decoupling Specification
2
-
3
- ## Purpose
4
-
5
- This spec defines the boundary between the portable core skills engine and the OpenCode-specific adapter in the `opencode-agent-skills-md` package. It guarantees that the core is reusable by any host while OpenCode users see no behavior change. This domain is introduced by the `skills-core-decouple` change; there is no prior baseline to delta against, so this file is the initial full definition.
6
-
7
- ## Requirements
8
-
9
- ### Requirement: Core Module Independence (R1)
10
-
11
- The `src/core/**` module graph SHALL contain zero runtime imports from `@opencode-ai/plugin`. A static import walk (AST or regex over the compiled dependency graph of `src/core/**`) SHALL fail the build if any such import is detected.
12
-
13
- ### Requirement: Boundary Interface Location (R2)
14
-
15
- The interfaces `SkillHostClient` and `SkillHostSession` SHALL be declared in `src/core/types.ts`. The concrete OpenCode implementation of those interfaces SHALL exist only in `src/opencode/host.ts`. No other module SHALL contain a concrete implementation of either interface.
16
-
17
- ### Requirement: Backward-Compatible Root Export (R3)
18
-
19
- Importing `opencode-agent-skills-md` (the package root) SHALL return the OpenCode plugin with the same shape and behavior as before this change. The four tool names (`use_skill`, `read_skill_file`, `run_skill_script`, `get_available_skills`) SHALL resolve. Additionally, `use_skill` SHALL visibly load a skill: the `onSkillLoaded` callback registered with `createSkillTools` SHALL fire exactly once per successful load per session, the loaded skill's `SKILL.md` content SHALL be injected into the agent context exactly once per session per skill, and the host SHALL observe the loaded-skill state update (TUI icon visible). The callback SHALL be threaded from `src/opencode/plugin.ts` → `createSkillTools` → `UseSkill`.
20
-
21
- ### Requirement: Framework-Agnostic Subpath Export (R4)
22
-
23
- Importing `opencode-agent-skills-md/core` SHALL resolve to the core modules only. A smoke import of the subpath SHALL NOT trigger any side effect, top-level await, or transitive import from `@opencode-ai/plugin`.
24
-
25
- ### Requirement: Discovery Semantics Preservation (R5)
26
-
27
- When the OpenCode adapter delegates to the core's `discoverAllSkills()`, the adapter SHALL observe the same four-location priority and first-match-wins semantics defined by the existing skill behavior. The set of skills surfaced for the baseline fixture locations SHALL match the set surfaced by pre-refactor commit `c2d8e74`. An integration test that mirrors `tests/integration/*` SHALL pass against the new boundary.
28
-
29
- ### Requirement: Public Surface Freeze (R6)
30
-
31
- The four tool names, their parameter shapes, and their user-visible error messages SHALL remain unchanged. Existing tests under `tests/integration/*` and `tests/e2e/*` SHALL pass without modification.
32
-
33
- ## Scenarios
34
-
35
- ### Scenario: core is decoupled from the OpenCode SDK
36
-
37
- - GIVEN the `src/core/**` module graph is fully composed
38
- - WHEN a static import walk scans every file in that graph for `from "@opencode-ai/plugin"`
39
- - THEN zero matches are reported
40
- - AND the test `tests/core/agnostic.test.ts` passes
41
-
42
- ### Scenario: opencode host is the only concrete implementation
43
-
44
- - GIVEN the interfaces `SkillHostClient` and `SkillHostSession` exist in `src/core/types.ts`
45
- - WHEN the codebase is searched for classes or factories that implement either interface
46
- - THEN exactly one match exists, located in `src/opencode/host.ts`
47
-
48
- #### Scenario: root export still loads the OpenCode plugin
49
-
50
- - GIVEN a consumer imports the package via its root export
51
- - WHEN the consumer resolves the four tool names from the returned plugin object
52
- - THEN all four tool names (`use_skill`, `read_skill_file`, `run_skill_script`, `get_available_skills`) are present
53
- - AND the test-skill load assertion in `tests/integration/startup-smoke.test.ts` passes
54
-
55
- #### Scenario: use_skill fires the onSkillLoaded callback
56
-
57
- - GIVEN the host registered an `onSkillLoaded` callback via `createSkillTools`
58
- - WHEN the agent calls `use_skill("test-skill")` on an unloaded skill
59
- - THEN the callback is invoked exactly once with the loaded skill identifier
60
- - AND the loaded skill's `SKILL.md` content is present in the agent context
61
- - AND the host's loaded-skill state reflects the new skill
62
-
63
- #### Scenario: use_skill does not re-inject the same skill in one session
64
-
65
- - GIVEN the agent has already loaded a given skill via `use_skill` in the current session
66
- - WHEN the agent calls `use_skill` with the same skill name again in the same session
67
- - THEN `onSkillLoaded` is NOT re-fired for that skill
68
- - AND the `SKILL.md` content is NOT re-injected into the context
69
-
70
- #### Scenario: missing callback does not break the load
71
-
72
- - GIVEN no `onSkillLoaded` is registered with `createSkillTools`
73
- - WHEN the agent calls `use_skill("any-skill")`
74
- - THEN the skill still loads and `SKILL.md` content is injected
75
- - AND no thrown error or unhandled rejection occurs
76
-
77
- ### Scenario: subpath export does not pull in the OpenCode SDK
78
-
79
- - GIVEN a consumer imports `opencode-agent-skills-md/core` in a fresh process
80
- - WHEN the import resolves and the module graph is recorded
81
- - THEN no module under `node_modules/@opencode-ai/plugin` appears in the resolved graph
82
- - AND no side effect from the SDK runs at import time
83
-
84
- #### Scenario: discovery priority and first-match-wins are preserved
85
-
86
- - GIVEN skill fixtures exist under `.opencode/skills/`, `.claude/skills/`, `~/.config/opencode/skills/`, and `~/.claude/skills/`
87
- - WHEN the OpenCode adapter calls `discoverAllSkills()`
88
- - THEN the returned list follows the four-location priority
89
- - AND duplicate skill names resolve to the first matching location
90
- - AND the new integration test in `tests/core/` passes
91
-
92
- #### Scenario: discoverAllSkills matches the pre-refactor skill set
93
-
94
- - GIVEN the same fixture tree used by pre-refactor commit `c2d8e74`
95
- - WHEN the OpenCode adapter calls `discoverAllSkills()`
96
- - THEN every skill the baseline surfaced is also surfaced now
97
- - AND no skill the baseline surfaced is missing from the result
98
-
99
- #### Scenario: literal-token search does not drop the pre-refactor skill set
100
-
101
- - GIVEN a skill whose trigger tokens are partial substrings of the user's query (not exact match)
102
- - WHEN the user searches via the literal-token path in `discoverAllSkills()`
103
- - THEN that skill appears in the result
104
- - AND the four-location priority remains consistent with first-match-wins
105
-
106
- ### Scenario: public tool surface is unchanged
107
-
108
- - GIVEN the refactor is complete and `pnpm run typecheck` is clean
109
- - WHEN `pnpm test` runs the existing `tests/integration/*` and `tests/e2e/*` suites
110
- - THEN all existing assertions on tool names, parameter shapes, and error messages continue to pass without modification
@@ -1,30 +0,0 @@
1
- {
2
- "name": "opencode-agent-skills-md-core",
3
- "version": "0.0.0",
4
- "private": true,
5
- "description": "Portable skills engine for opencode-agent-skills-md. Host-agnostic discovery, parsing, search, and host-boundary contracts.",
6
- "type": "module",
7
- "main": "src/index.ts",
8
- "exports": {
9
- ".": {
10
- "types": "./src/index.ts",
11
- "import": "./src/index.ts",
12
- "default": "./src/index.ts"
13
- }
14
- },
15
- "files": [
16
- "src"
17
- ],
18
- "scripts": {
19
- "test": "node --import tsx --test \"tests/**/*.test.ts\"",
20
- "typecheck": "tsc --noEmit"
21
- },
22
- "dependencies": {
23
- "yaml": "^2.9.0"
24
- },
25
- "devDependencies": {
26
- "@types/node": "^25.9.1",
27
- "tsx": "^4.22.3",
28
- "typescript": "^6.0.3"
29
- }
30
- }
@@ -1,16 +0,0 @@
1
- /**
2
- * Content formatting helpers for skill listings and synthetic injections.
3
- *
4
- * Pure functions: string assembly only, no host dependencies.
5
- */
6
- import type { Skill } from "./types";
7
- /**
8
- * Format a list of skills as the inner bullet block used inside the
9
- * `<available-skills>` synthetic injection.
10
- */
11
- export declare function formatSkillListing(skills: Skill[]): string;
12
- /**
13
- * Render the full `<available-skills>...</available-skills>` block that the
14
- * host injects into a session on startup and after compaction.
15
- */
16
- export declare function renderAvailableSkillsBlock(skills: Skill[]): string;
@@ -1,30 +0,0 @@
1
- /**
2
- * Content formatting helpers for skill listings and synthetic injections.
3
- *
4
- * Pure functions: string assembly only, no host dependencies.
5
- */
6
-
7
- import type { Skill } from "./types";
8
-
9
- /**
10
- * Format a list of skills as the inner bullet block used inside the
11
- * `<available-skills>` synthetic injection.
12
- */
13
- export const formatSkillListing = (skills: Skill[]): string => {
14
- return skills
15
- .map((s) => `- ${s.name}: ${s.description}`)
16
- .join("\n");
17
- };
18
-
19
- /**
20
- * Render the full `<available-skills>...</available-skills>` block that the
21
- * host injects into a session on startup and after compaction.
22
- */
23
- export const renderAvailableSkillsBlock = (skills: Skill[]): string => {
24
- const skillsList = formatSkillListing(skills);
25
- return `<available-skills>
26
- Use the use_skill, read_skill_file, run_skill_script, and get_available_skills tools to work with skills.
27
-
28
- ${skillsList}
29
- </available-skills>`;
30
- };
@@ -1,16 +0,0 @@
1
- /**
2
- * Debug-gated logging for bare `catch {}` blocks.
3
- *
4
- * Bare catches stay silent by default so malformed payloads and parse
5
- * errors never surface as user-visible noise. Setting
6
- * `OPENCODE_AGENT_SKILLS_DEBUG=1` makes the diagnostic context appear on
7
- * stderr so developers can trace why a fallback fired.
8
- *
9
- * The env var is checked on every call (not cached at module load) so
10
- * tests can toggle it without re-importing the module.
11
- */
12
- export const debugLog = (...args: unknown[]): void => {
13
- if (!process.env.OPENCODE_AGENT_SKILLS_DEBUG) return;
14
- // eslint-disable-next-line no-console
15
- console.error("[opencode-agent-skills-md]", ...args);
16
- };
@@ -1,86 +0,0 @@
1
- /**
2
- * Skill discovery across filesystem roots.
3
- *
4
- * The core never hard-codes a host's directory layout. Callers pass the list
5
- * of discovery roots; the default `getDefaultOpencodeRoots` reproduces the
6
- * legacy OpenCode priority order. PR2 will call `discoverAllSkills` from the
7
- * OpenCode host adapter with the same default.
8
- */
9
- import type { DiscoveryPath, FileDiscoveryResult, LabeledDiscoveryResult, Skill, SkillLabel } from "./types";
10
- /**
11
- * Check if a file exists in a directory and return path info.
12
- *
13
- * @param directory - Directory to check
14
- * @param relativePath - Relative path to use in result (caller-specific)
15
- * @param filename - Name of file to look for (e.g., 'SKILL.md')
16
- * @returns Path info if file exists, null otherwise
17
- */
18
- export declare function findFile(directory: string, relativePath: string, filename: string): Promise<FileDiscoveryResult | null>;
19
- /**
20
- * Recursively find SKILL.md files in a directory.
21
- *
22
- * The base directory itself is checked first: a SKILL.md placed at the root
23
- * of a discovery root is returned with `relativePath = ""` and wins the
24
- * shadowing tie-break over same-name skills in subdirectories (first found
25
- * wins in `discoverAllSkills`).
26
- */
27
- export declare function findSkillsRecursive(baseDir: string, label: SkillLabel, maxDepth?: number): Promise<LabeledDiscoveryResult[]>;
28
- /**
29
- * Default discovery roots matching the pre-refactor OpenCode priority order
30
- * (see commit `c2d8e74`, `src/skills.ts#discoverAllSkills`):
31
- * 1. .opencode/skills/ (project - OpenCode)
32
- * 2. .claude/skills/ (project - Claude)
33
- * 3. ~/.config/opencode/skills/ (user - OpenCode)
34
- * 4. ~/.claude/skills/ (user - Claude)
35
- *
36
- * No shadowing - unique names only. First match wins, duplicates are warned.
37
- */
38
- export declare function getDefaultOpencodeRoots(directory: string): DiscoveryPath[];
39
- /**
40
- * Default callback for shadowed skill names. Emits a `console.warn` that
41
- * identifies the surviving (existing) skill and the duplicate that was
42
- * skipped. Hosts can override by passing `onDuplicate` to `discoverAllSkills`.
43
- *
44
- * @internal - exported for testing
45
- */
46
- export declare const defaultOnDuplicate: (existing: Skill, duplicate: Skill) => void;
47
- /**
48
- * Discover all skills from the provided roots.
49
- *
50
- * @param directory - Project directory (used to build the default roots).
51
- * @param roots - Discovery roots. Defaults to the OpenCode priority order
52
- * via `getDefaultOpencodeRoots(directory)`. Hosts pass an explicit list to
53
- * override the layout.
54
- * @param onDuplicate - Optional callback invoked when two roots produce a
55
- * skill with the same `name`. Defaults to `console.warn` via
56
- * `defaultOnDuplicate`. The first-discovered skill wins; the duplicate
57
- * (second one encountered) is passed to the callback but never stored.
58
- */
59
- export declare function discoverAllSkills(directory: string, roots?: DiscoveryPath[], onDuplicate?: (existing: Skill, duplicate: Skill) => void): Promise<Map<string, Skill>>;
60
- /**
61
- * Resolve a skill by name, handling namespace prefixes.
62
- * Supports: "skill-name", "project:skill-name", "user:skill-name", etc.
63
- */
64
- export declare function resolveSkill(skillName: string, skillsByName: Map<string, Skill>): Skill | null;
65
- /**
66
- * Recursively list all files in a directory, returning relative paths.
67
- * Excludes SKILL.md since it's already loaded as the main content.
68
- */
69
- export declare function listSkillFiles(skillPath: string, maxDepth?: number): Promise<string[]>;
70
- /**
71
- * Get summaries of all available skills (name, description, trigger).
72
- * Used by preflight LLM call to evaluate which skills are relevant and
73
- * by the plugin's keyword matcher to rank matched skills.
74
- *
75
- * The `trigger` frontmatter key (PR 2 of `trigger-aware-skill-discovery`)
76
- * is threaded through so the keyword matcher can apply the 1.5x trigger
77
- * tier and the targeted outputs can render trigger text.
78
- *
79
- * @param directory - Project directory to discover skills from
80
- * @returns Array of skill summaries
81
- */
82
- export declare function getSkillSummaries(directory: string): Promise<Array<{
83
- name: string;
84
- description: string;
85
- trigger?: string;
86
- }>>;