opencode-agent-skills-md 1.0.1 → 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/.beads/.local_version +0 -1
  16. package/.beads/README.md +0 -81
  17. package/.beads/config.yaml +0 -61
  18. package/.beads/deletions.jsonl +0 -1
  19. package/.beads/issues.jsonl +0 -64
  20. package/.beads/metadata.json +0 -4
  21. package/.gitattributes +0 -3
  22. package/.github/CODEOWNERS +0 -1
  23. package/.github/copilot-instructions.md +0 -78
  24. package/.github/dependabot.yml +0 -13
  25. package/.github/workflows/release.yml +0 -51
  26. package/.opencode/command/test-compaction.md +0 -9
  27. package/.opencode/command/test-find-skills.md +0 -7
  28. package/.opencode/command/test-read-skill-file.md +0 -14
  29. package/.opencode/command/test-run-skill-script.md +0 -13
  30. package/.opencode/command/test-skills.md +0 -14
  31. package/.opencode/command/test-use-skill.md +0 -10
  32. package/.opencode/skills/git-helper/SKILL.md +0 -65
  33. package/.opencode/skills/test-skill/SKILL.md +0 -43
  34. package/.opencode/skills/test-skill/example-config.json +0 -16
  35. package/.opencode/skills/test-skill/helper-docs.md +0 -29
  36. package/.opencode/skills/test-skill/scripts/echo-args +0 -14
  37. package/.opencode/skills/test-skill/scripts/greet +0 -6
  38. package/AGENTS.md +0 -43
  39. package/CHANGELOG.md +0 -178
  40. package/Justfile +0 -39
  41. package/README.md +0 -220
  42. package/openspec/changes/archive/2026-06-14-skills-core-decouple/specs/core-decoupling/spec.md +0 -74
  43. package/openspec/changes/archive/2026-06-14-skills-core-decouple/tasks.md +0 -64
  44. package/openspec/changes/archive/2026-06-14-skills-core-decouple/verify-report.md +0 -75
  45. package/openspec/changes/archive/2026-06-17-fix-skill-loading-regression/apply-progress.md +0 -136
  46. package/openspec/changes/archive/2026-06-17-fix-skill-loading-regression/archive-report.md +0 -77
  47. package/openspec/changes/archive/2026-06-17-fix-skill-loading-regression/design.md +0 -89
  48. package/openspec/changes/archive/2026-06-17-fix-skill-loading-regression/proposal.md +0 -65
  49. package/openspec/changes/archive/2026-06-17-fix-skill-loading-regression/specs/core-decoupling/spec.md +0 -77
  50. package/openspec/changes/archive/2026-06-17-fix-skill-loading-regression/tasks.md +0 -65
  51. package/openspec/changes/archive/2026-06-17-fix-skill-loading-regression/verify-report.md +0 -165
  52. package/openspec/specs/core-decoupling/spec.md +0 -110
  53. package/packages/core/package.json +0 -30
  54. package/packages/core/src/content.d.ts +0 -16
  55. package/packages/core/src/content.ts +0 -30
  56. package/packages/core/src/debug.ts +0 -16
  57. package/packages/core/src/discovery.d.ts +0 -86
  58. package/packages/core/src/discovery.ts +0 -257
  59. package/packages/core/src/index.d.ts +0 -20
  60. package/packages/core/src/index.ts +0 -55
  61. package/packages/core/src/match.d.ts +0 -19
  62. package/packages/core/src/match.ts +0 -75
  63. package/packages/core/src/parse.d.ts +0 -26
  64. package/packages/core/src/parse.ts +0 -141
  65. package/packages/core/src/scripts.d.ts +0 -17
  66. package/packages/core/src/scripts.ts +0 -79
  67. package/packages/core/src/search.d.ts +0 -83
  68. package/packages/core/src/search.ts +0 -188
  69. package/packages/core/src/types.d.ts +0 -82
  70. package/packages/core/src/types.ts +0 -131
  71. package/packages/core/src/walk.ts +0 -109
  72. package/packages/core/tests/agnostic.test.ts +0 -346
  73. package/packages/core/tests/content.test.ts +0 -65
  74. package/packages/core/tests/discovery.test.ts +0 -370
  75. package/packages/core/tests/package-boundary.test.ts +0 -310
  76. package/packages/core/tests/parse-trigger.test.ts +0 -282
  77. package/packages/core/tests/search.test.ts +0 -374
  78. package/packages/core/tests/subpath.test.ts +0 -87
  79. package/packages/core/tsconfig.json +0 -10
  80. package/packages/opencode-agent-skills-md/package.json +0 -66
  81. package/packages/opencode-agent-skills-md/rolldown.config.js +0 -47
  82. package/packages/opencode-agent-skills-md/tests/cli-commands.test.ts +0 -1423
  83. package/packages/opencode-agent-skills-md/tests/e2e/startup-smoke.test.ts +0 -66
  84. package/packages/opencode-agent-skills-md/tests/fixtures/skills/home/.claude/skills/claude-user-only-skill/SKILL.md +0 -8
  85. package/packages/opencode-agent-skills-md/tests/fixtures/skills/home/.config/opencode/skills/shared-skill/SKILL.md +0 -8
  86. package/packages/opencode-agent-skills-md/tests/fixtures/skills/home/.config/opencode/skills/user-only-skill/SKILL.md +0 -8
  87. package/packages/opencode-agent-skills-md/tests/fixtures/skills/project/.claude/skills/claude-project-only-skill/SKILL.md +0 -8
  88. package/packages/opencode-agent-skills-md/tests/fixtures/skills/project/.opencode/skills/go-tester/SKILL.md +0 -12
  89. package/packages/opencode-agent-skills-md/tests/fixtures/skills/project/.opencode/skills/nested/team/nested-skill/SKILL.md +0 -8
  90. package/packages/opencode-agent-skills-md/tests/fixtures/skills/project/.opencode/skills/rust-tester/SKILL.md +0 -11
  91. package/packages/opencode-agent-skills-md/tests/fixtures/skills/project/.opencode/skills/scripted-skill/SKILL.md +0 -8
  92. package/packages/opencode-agent-skills-md/tests/fixtures/skills/project/.opencode/skills/scripted-skill/bin/echo.sh +0 -2
  93. package/packages/opencode-agent-skills-md/tests/fixtures/skills/project/.opencode/skills/scripted-skill/docs/reference.md +0 -1
  94. package/packages/opencode-agent-skills-md/tests/fixtures/skills/project/.opencode/skills/shared-skill/SKILL.md +0 -8
  95. package/packages/opencode-agent-skills-md/tests/fixtures/skills/project/.opencode/skills/using-superpowers/SKILL.md +0 -8
  96. package/packages/opencode-agent-skills-md/tests/integration/helpers/mock-opencode.ts +0 -114
  97. package/packages/opencode-agent-skills-md/tests/integration/plugin.test.ts +0 -316
  98. package/packages/opencode-agent-skills-md/tests/integration/skill-discovery.test.ts +0 -315
  99. package/packages/opencode-agent-skills-md/tests/opencode/host.test.ts +0 -179
  100. package/packages/opencode-agent-skills-md/tests/opencode/plugin.test.ts +0 -551
  101. package/packages/opencode-agent-skills-md/tests/opencode/subpath.test.ts +0 -66
  102. package/packages/opencode-agent-skills-md/tests/opencode/tools.test.ts +0 -213
  103. package/packages/opencode-agent-skills-md/tests/package-boundary.test.ts +0 -345
  104. package/packages/opencode-agent-skills-md/tests/tools-security.test.ts +0 -72
  105. package/packages/opencode-agent-skills-md/tsconfig.build.json +0 -11
  106. package/packages/opencode-agent-skills-md/tsconfig.json +0 -10
  107. package/plans/001-ci-gate.md +0 -177
  108. package/plans/002-is-path-safe.md +0 -243
  109. package/plans/003-escape-prompts.md +0 -310
  110. package/plans/004-test-security-paths.md +0 -228
  111. package/plans/005-stop-swallowing-errors.md +0 -246
  112. package/plans/006-preserve-jsonc-commas.md +0 -144
  113. package/plans/007-write-before-purge.md +0 -144
  114. package/plans/008-reuse-walkdir-for-list-skill-files.md +0 -164
  115. package/plans/README.md +0 -43
  116. package/pnpm-workspace.yaml +0 -6
  117. package/tests/workspace.test.ts +0 -367
  118. package/tsconfig.json +0 -15
  119. /package/{packages/opencode-agent-skills-md/src → src}/cli/config.ts +0 -0
  120. /package/{packages/opencode-agent-skills-md/src → src}/cli/install.ts +0 -0
  121. /package/{packages/opencode-agent-skills-md/src → src}/cli/main.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,246 +0,0 @@
1
- # Plan 005: Surface swallowed discovery and parse errors
2
-
3
- > **Executor instructions**: Follow this plan step by step. Run every
4
- > verification command and confirm the expected result before moving to the
5
- > next step. If anything in the "STOP conditions" section occurs, stop and
6
- > report — do not improvise. When done, update the status row for this plan
7
- > in `plans/README.md`.
8
- >
9
- > **Drift check (run first)**: `git diff --stat fb45791..HEAD -- packages/core/src/discovery.ts packages/core/src/parse.ts packages/opencode-agent-skills-md/src/host.ts`
10
- > If any in-scope file changed since this plan was written, compare the
11
- > "Current state" excerpts against the live code before proceeding; on a
12
- > mismatch, treat it as a STOP condition.
13
-
14
- ## Status
15
-
16
- - **Priority**: P2
17
- - **Effort**: S
18
- - **Risk**: LOW
19
- - **Depends on**: none
20
- - **Category**: correctness
21
- - **Planned at**: commit `fb45791`, 2026-06-29
22
-
23
- ## Why this matters
24
-
25
- Four locations in the core and host packages silently swallow filesystem and
26
- parse errors with bare `catch {}` blocks. When a discovery root is
27
- inaccessible (permission denied), a SKILL.md file is corrupted, or a session
28
- context lookup fails, the failure produces no diagnostic output. Users see
29
- "no skills found" with no path to debug. Adding `debugLog` calls in these
30
- catch blocks makes failures discoverable when
31
- `OPENCODE_AGENT_SKILLS_DEBUG=1` is set, without changing the current
32
- graceful-degradation behavior.
33
-
34
- ## Current state
35
-
36
- ### 1. `packages/core/src/discovery.ts:87` — outer catch in `findSkillsRecursive`
37
-
38
- ```ts
39
- } catch { }
40
- ```
41
-
42
- This wraps the entire `fs.access` + `walkDir` call. If `baseDir` exists but
43
- is unreadable, the error is invisible.
44
-
45
- ### 2. `packages/core/src/discovery.ts:219` — inner catch in `listSkillFiles`
46
-
47
- ```ts
48
- } catch { }
49
- ```
50
-
51
- This wraps `fs.stat` per entry. If a file in the skill directory can't be
52
- stat'd, the entry is silently skipped.
53
-
54
- ### 3. `packages/core/src/parse.ts:91` — catch on `fs.readFile`
55
-
56
- ```ts
57
- const content = await fs.readFile(skillPath, 'utf-8').catch(() => null);
58
- ```
59
-
60
- If a SKILL.md can't be read, returns `null` with no diagnostic.
61
-
62
- Note: `parse.ts:107` (`try { parseYamlFrontmatter(...) } catch { return null; }`)
63
- is excluded — `parseYamlFrontmatter` already logs errors via `debugLog` at
64
- `parse.ts:38`.
65
-
66
- ### 4. `packages/opencode-agent-skills-md/src/host.ts:97` — catch in `getSessionContext`
67
-
68
- ```ts
69
- } catch {
70
- // Fall through to undefined - mirrors the legacy behaviour
71
- }
72
- ```
73
-
74
- If the session lookup fails, the error is swallowed. This is important for
75
- privacy (session data should not leak in error messages), but a debug log
76
- is safe.
77
-
78
- Excluded by design:
79
- - `walk.ts:100-103` per-entry isolation is documented as intentional.
80
- - `parse.ts:25-26` YAML fallback to `{}` is documented as intentional.
81
- - `discovery.ts:165-168` duplicate skill handling is documented as intentional.
82
-
83
- Conventions:
84
- - `debugLog` is imported in `discovery.ts` (not yet, but `parse.ts` imports it)
85
- - The import is `import { debugLog } from "./debug"` from `packages/core/src/`
86
-
87
- ## Commands you will need
88
-
89
- | Purpose | Command | Expected on success |
90
- |-----------|--------------------------|---------------------|
91
- | Typecheck | `pnpm run typecheck` | exit 0, no errors |
92
- | Tests | `pnpm test` | all pass |
93
-
94
- ## Scope
95
-
96
- **In scope** (the only files you should modify):
97
- - `packages/core/src/discovery.ts` — add `debugLog` import and calls in catch blocks
98
- - `packages/core/src/parse.ts` — add `debugLog` to the `readFile` catch at line 91
99
- - `packages/opencode-agent-skills-md/src/host.ts` — add `debugLog` to the `getSessionContext` catch at line 97
100
-
101
- **Out of scope** (do NOT touch):
102
- - `walk.ts` — per-entry isolation is by-design
103
- - `parse.ts` YAML error handling — already logs via `debugLog`
104
- - `packages/core/src/scripts.ts` — catches there are intentional
105
- - Any test files — the existing tests must pass unchanged
106
-
107
- ## Git workflow
108
-
109
- - Branch: `advisor/005-stop-swallowing-errors`
110
- - Commit per file (or single commit for all three)
111
- - Do NOT push or open a PR unless instructed.
112
-
113
- ## Steps
114
-
115
- ### Step 1: Add `debugLog` imports where missing
116
-
117
- Check which files already import `debugLog`:
118
-
119
- - `packages/core/src/discovery.ts` — does NOT import `debugLog`. Add:
120
- ```ts
121
- import { debugLog } from "./debug";
122
- ```
123
-
124
- - `packages/core/src/parse.ts` — ALREADY imports `debugLog` at line 12. No change needed.
125
-
126
- - `packages/opencode-agent-skills-md/src/host.ts` — does NOT import `debugLog`. Add:
127
- ```ts
128
- import { debugLog } from "opencode-agent-skills-md-core";
129
- ```
130
-
131
- ### Step 2: Add `debugLog` to `findSkillsRecursive` catch in `discovery.ts:87`
132
-
133
- Old:
134
- ```ts
135
- } catch { }
136
- ```
137
-
138
- New:
139
- ```ts
140
- } catch (error) {
141
- debugLog("findSkillsRecursive: cannot access baseDir", baseDir, error);
142
- }
143
- ```
144
-
145
- **Verify**: `grep -A2 'debugLog.*findSkillsRecursive' packages/core/src/discovery.ts` → matches
146
-
147
- ### Step 3: Add `debugLog` to `listSkillFiles` stat error in `discovery.ts:219`
148
-
149
- Old:
150
- ```ts
151
- } catch { }
152
- ```
153
-
154
- New:
155
- ```ts
156
- } catch (error) {
157
- debugLog("listSkillFiles: cannot stat", fullPath, error);
158
- }
159
- ```
160
-
161
- **Verify**: `grep -A2 'debugLog.*listSkillFiles' packages/core/src/discovery.ts` → matches
162
-
163
- ### Step 4: Add `debugLog` to `parseSkillFile` file read in `parse.ts:91`
164
-
165
- Old:
166
- ```ts
167
- const content = await fs.readFile(skillPath, 'utf-8').catch(() => null);
168
- ```
169
-
170
- New:
171
- ```ts
172
- const content = await fs.readFile(skillPath, 'utf-8').catch((error) => {
173
- debugLog("parseSkillFile: cannot read", skillPath, error);
174
- return null;
175
- });
176
- ```
177
-
178
- **Verify**: `grep -A3 'parseSkillFile.*cannot read' packages/core/src/parse.ts` → matches
179
-
180
- ### Step 5: Add `debugLog` to `getSessionContext` catch in `host.ts:97`
181
-
182
- Old:
183
- ```ts
184
- } catch {
185
- // Fall through to undefined - mirrors the legacy behaviour
186
- }
187
- ```
188
-
189
- New:
190
- ```ts
191
- } catch (error) {
192
- debugLog("getSessionContext: session lookup failed", sessionID, error);
193
- // Fall through to undefined - mirrors the legacy behaviour
194
- }
195
- ```
196
-
197
- **Verify**: `grep 'debugLog.*getSessionContext' packages/opencode-agent-skills-md/src/host.ts` → matches
198
-
199
- ### Step 6: Typecheck
200
-
201
- **Verify**: `pnpm run typecheck` → exit 0, no errors
202
-
203
- ### Step 7: Run tests
204
-
205
- **Verify**: `pnpm test` → exit 0, all tests pass
206
-
207
- ## Test plan
208
-
209
- No new tests needed — the `debugLog` function is gated behind
210
- `OPENCODE_AGENT_SKILLS_DEBUG` and has no side effects when not set.
211
- Existing tests that exercise the error paths will continue to pass
212
- (same behavior) but will now log when the env var is set.
213
-
214
- To manually verify, run with debug logging:
215
- ```bash
216
- OPENCODE_AGENT_SKILLS_DEBUG=true pnpm test 2>&1 | grep '\[opencode-agent-skills-md\]'
217
- ```
218
-
219
- ## Done criteria
220
-
221
- Machine-checkable. ALL must hold:
222
-
223
- - [ ] `packages/core/src/discovery.ts` imports `debugLog` and calls it in both catch blocks with context
224
- - [ ] `packages/core/src/parse.ts` logs via `debugLog` when `readFile` fails for a SKILL.md
225
- - [ ] `packages/opencode-agent-skills-md/src/host.ts` imports `debugLog` and calls it in the `getSessionContext` catch
226
- - [ ] `pnpm run typecheck` exits 0
227
- - [ ] `pnpm test` exits 0
228
- - [ ] No files outside the in-scope list are modified (`git status`)
229
- - [ ] `plans/README.md` status row updated
230
-
231
- ## STOP conditions
232
-
233
- Stop and report back (do not improvise) if:
234
-
235
- - The import path for `debugLog` differs between the core and plugin packages (it does: core uses `"./debug"`, plugin uses `"opencode-agent-skills-md-core"`).
236
- - A step's verification fails twice after a reasonable fix attempt.
237
- - The fix appears to require touching an out-of-scope file.
238
- - Adding `error` to the log output leaks any sensitive information (in `host.ts`, the `error` may contain session data — log only the error type, not the full error object).
239
-
240
- ## Maintenance notes
241
-
242
- - If a more structured logging system replaces `debugLog` in the future,
243
- these catch blocks will emit through the new system automatically.
244
- - The `host.ts` catch in `getSessionContext` should avoid logging the full
245
- error object if it might contain session payload data. If unsure, log
246
- only `(error as Error).name` and `(error as Error).message`.
@@ -1,144 +0,0 @@
1
- # Plan 006: Preserve commas inside JSONC string values
2
-
3
- > **Executor instructions**: Follow this plan step by step. Run every
4
- > verification command before moving on. If a STOP condition occurs, stop
5
- > and report instead of improvising. When done, update the status row for
6
- > this plan in `plans/README.md`.
7
- >
8
- > **Drift check (run first)**:
9
- > `git diff --stat 9c57cb0..HEAD -- packages/opencode-agent-skills-md/src/cli/config.ts packages/opencode-agent-skills-md/tests/cli-commands.test.ts`
10
- > If any in-scope file changed since this plan was written, compare the
11
- > Current state excerpts below against live code first. Any mismatch is a
12
- > STOP condition.
13
-
14
- ## Status
15
-
16
- - **Priority**: P1
17
- - **Effort**: S
18
- - **Risk**: LOW
19
- - **Depends on**: none
20
- - **Category**: bug
21
- - **Planned at**: commit `9c57cb0`, 2026-07-03
22
-
23
- ## Why this matters
24
-
25
- `parseJsonc()` currently strips trailing commas with a regex applied to the
26
- entire post-comment text. That regex does not respect string boundaries, so a
27
- valid string value containing `,}` or `,]` is silently mutated before
28
- `JSON.parse()` runs. This is a real data-corruption bug in the CLI config
29
- loader, and the fix is narrow.
30
-
31
- ## Current state
32
-
33
- - `packages/opencode-agent-skills-md/src/cli/config.ts` — CLI config parsing helpers used by install, uninstall, status, and doctor.
34
- - `packages/opencode-agent-skills-md/tests/cli-commands.test.ts` — existing characterization tests for `parseJsonc()` and other CLI helpers.
35
-
36
- Relevant excerpts:
37
-
38
- - `packages/opencode-agent-skills-md/src/cli/config.ts:204-255`
39
- - `stripJsoncComments()` already tracks `inString` and `escaped` while removing comments.
40
- - It ends with: `return out.replace(/,(\s*[}\]])/g, "$1");`
41
- - `packages/opencode-agent-skills-md/tests/cli-commands.test.ts:272-319`
42
- - Existing tests cover empty input, comments, escaped quotes, and ordinary trailing commas.
43
- - There is no test proving commas inside string literals survive unchanged.
44
-
45
- Conventions to match:
46
-
47
- - CLI helper tests live in `packages/opencode-agent-skills-md/tests/cli-commands.test.ts`.
48
- - Keep the implementation minimal and local; do not introduce a new parser dependency.
49
- - Preserve the current graceful behavior: comments are stripped, trailing commas still work, malformed JSON still throws.
50
-
51
- ## Commands you will need
52
-
53
- | Purpose | Command | Expected on success |
54
- |---|---|---|
55
- | Typecheck | `pnpm run typecheck` | exit 0 |
56
- | Targeted tests | `pnpm -F opencode-agent-skills-md exec node --import tsx --test tests/cli-commands.test.ts` | all pass |
57
- | Full tests | `pnpm test` | all pass |
58
-
59
- ## Scope
60
-
61
- **In scope** (the only files you should modify):
62
- - `packages/opencode-agent-skills-md/src/cli/config.ts`
63
- - `packages/opencode-agent-skills-md/tests/cli-commands.test.ts`
64
-
65
- **Out of scope**:
66
- - Any CLI command behavior beyond config parsing correctness
67
- - Any release workflow or docs change
68
- - Any new dependency
69
-
70
- ## Git workflow
71
-
72
- - Branch: `advisor/006-preserve-jsonc-commas`
73
- - Commit style: conventional commits, for example `fix(cli): preserve commas inside JSONC strings`
74
- - Do NOT push or open a PR unless instructed
75
-
76
- ## Steps
77
-
78
- ### Step 1: Add a failing regression test for string-preservation
79
-
80
- Extend `describe("parseJsonc", ...)` in `packages/opencode-agent-skills-md/tests/cli-commands.test.ts`.
81
-
82
- Add at least these cases:
83
-
84
- - A string containing `,}` such as `{"doc":"keep ,} inside string","plugin":["a",],}`
85
- - A string containing `,]` such as `{"doc":"keep ,] inside string","list":[1,2,],}`
86
- - A nested mixed case with both string patterns and structural trailing commas
87
-
88
- The assertions must prove both:
89
- - trailing commas are still removed structurally
90
- - string content is unchanged byte-for-byte
91
-
92
- **Verify**: `pnpm -F opencode-agent-skills-md exec node --import tsx --test tests/cli-commands.test.ts` → the new test fails before the fix
93
-
94
- ### Step 2: Replace regex-based trailing-comma stripping with a string-aware pass
95
-
96
- Modify `stripJsoncComments()` in `packages/opencode-agent-skills-md/src/cli/config.ts`.
97
-
98
- Target shape:
99
-
100
- - Keep the existing comment-stripping loop
101
- - Replace the final regex with a second character-by-character pass (or fold it inline)
102
- - Track `inString` and `escaped` state
103
- - Remove commas only when the next non-whitespace token is `}` or `]` and the parser is not inside a string literal
104
-
105
- Do not change `parseJsonc()` public behavior.
106
-
107
- **Verify**: `pnpm -F opencode-agent-skills-md exec node --import tsx --test tests/cli-commands.test.ts` → all tests pass
108
-
109
- ### Step 3: Run repo verification
110
-
111
- **Verify**:
112
- - `pnpm run typecheck` → exit 0
113
- - `pnpm test` → exit 0
114
- - `git status --short` → only the two in-scope files plus `plans/README.md`
115
-
116
- ## Test plan
117
-
118
- Extend `packages/opencode-agent-skills-md/tests/cli-commands.test.ts` inside the existing `describe("parseJsonc", ...)`. Model new cases after the existing block at lines 272-319. Cover:
119
- - happy path trailing comma removal still works
120
- - regression: `,}` inside a string is preserved
121
- - regression: `,]` inside a string is preserved
122
- - nested mixed case with both strings and structural trailing commas
123
-
124
- ## Done criteria
125
-
126
- - [ ] `parseJsonc()` preserves commas inside string literals
127
- - [ ] Existing trailing-comma behavior still works
128
- - [ ] `pnpm run typecheck` exits 0
129
- - [ ] `pnpm test` exits 0
130
- - [ ] No files outside scope are modified
131
- - [ ] `plans/README.md` status row updated
132
-
133
- ## STOP conditions
134
-
135
- Stop and report back (do not improvise) if:
136
- - The `parseJsonc` implementation no longer ends in a regex-based trailing comma removal step.
137
- - Fixing the bug appears to require a new parser dependency.
138
- - The regression test cannot be made to fail before the implementation change.
139
- - Verification fails twice after a reasonable fix attempt.
140
-
141
- ## Maintenance notes
142
-
143
- - Keep this logic near `stripJsoncComments()`; splitting into many helpers is unnecessary unless the function becomes unreadable.
144
- - Future changes to config parsing should always add regression tests for string-boundary handling.
@@ -1,144 +0,0 @@
1
- # Plan 007: Write config before purging plugin-owned directories
2
-
3
- > **Executor instructions**: Follow this plan step by step. Run every
4
- > verification command before moving on. If a STOP condition occurs, stop
5
- > and report instead of improvising. When done, update the status row for
6
- > this plan in `plans/README.md`.
7
- >
8
- > **Drift check (run first)**:
9
- > `git diff --stat 9c57cb0..HEAD -- packages/opencode-agent-skills-md/src/cli/uninstall.ts packages/opencode-agent-skills-md/tests/cli-commands.test.ts`
10
- > If any in-scope file changed since this plan was written, compare the
11
- > Current state excerpts below against live code first. Any mismatch is a
12
- > STOP condition.
13
-
14
- ## Status
15
-
16
- - **Priority**: P1
17
- - **Effort**: S
18
- - **Risk**: LOW
19
- - **Depends on**: none
20
- - **Category**: bug
21
- - **Planned at**: commit `9c57cb0`, 2026-07-03
22
-
23
- ## Why this matters
24
-
25
- `runUninstall({ purge: true })` currently deletes the plugin cache/config
26
- directories before it attempts the config write. If the later write fails, the
27
- global OpenCode config can still claim the plugin is installed while the
28
- plugin-owned directories are already gone. The bug is about operation ordering.
29
-
30
- ## Current state
31
-
32
- - `packages/opencode-agent-skills-md/src/cli/uninstall.ts` — uninstall command implementation
33
- - `packages/opencode-agent-skills-md/tests/cli-commands.test.ts` — existing uninstall coverage with in-memory `CliFs`
34
-
35
- Relevant excerpts:
36
-
37
- - `packages/opencode-agent-skills-md/src/cli/uninstall.ts:98-110`
38
- - purge candidates are computed and, for real `--purge`, deleted before the no-op/write path
39
- - `packages/opencode-agent-skills-md/src/cli/uninstall.ts:145-149`
40
- - config backup and `writeAtomically()` happen later
41
- - `packages/opencode-agent-skills-md/tests/cli-commands.test.ts:1048-1065`
42
- - existing `--purge (real)` test only asserts the command returns `wrote`; there is no regression test for a config-write failure after purge begins
43
- - `packages/opencode-agent-skills-md/tests/cli-commands.test.ts:70-156`
44
- - `createMemoryFs()` supports failure injection for `write` and `rename`
45
-
46
- Conventions to match:
47
-
48
- - Keep `purgeDir()` best-effort
49
- - Preserve `--dry-run` output and current return shapes
50
- - Reorder operations instead of adding rollback machinery
51
-
52
- ## Commands you will need
53
-
54
- | Purpose | Command | Expected on success |
55
- |---|---|---|
56
- | Typecheck | `pnpm run typecheck` | exit 0 |
57
- | Targeted tests | `pnpm -F opencode-agent-skills-md exec node --import tsx --test tests/cli-commands.test.ts` | all pass |
58
- | Full tests | `pnpm test` | all pass |
59
-
60
- ## Scope
61
-
62
- **In scope** (the only files you should modify):
63
- - `packages/opencode-agent-skills-md/src/cli/uninstall.ts`
64
- - `packages/opencode-agent-skills-md/tests/cli-commands.test.ts`
65
-
66
- **Out of scope**:
67
- - Install command behavior
68
- - Purge path redesign or rollback framework
69
- - Any changes to `CliFs` shape
70
-
71
- ## Git workflow
72
-
73
- - Branch: `advisor/007-write-before-purge`
74
- - Commit style: conventional commits, for example `fix(cli): write uninstall config before purge`
75
- - Do NOT push or open a PR unless instructed
76
-
77
- ## Steps
78
-
79
- ### Step 1: Add a regression test for write-failure ordering
80
-
81
- Extend `describe("runUninstall", ...)` in `packages/opencode-agent-skills-md/tests/cli-commands.test.ts`.
82
-
83
- Add a test that:
84
-
85
- - starts with a config containing the plugin entry
86
- - injects a write or rename failure via `setFailNext()`
87
- - calls `runUninstall({ purge: true }, ...)`
88
- - asserts the thrown error propagates
89
- - asserts the original config file content is unchanged
90
-
91
- Because the purge path uses `node:fs.rmSync` directly, do not assert real directory deletion in the in-memory FS. The point is to pin that the config write must be attempted before purge side effects happen.
92
-
93
- **Verify**: `pnpm -F opencode-agent-skills-md exec node --import tsx --test tests/cli-commands.test.ts` → the new test fails before the reorder
94
-
95
- ### Step 2: Reorder `runUninstall()` side effects
96
-
97
- Modify `packages/opencode-agent-skills-md/src/cli/uninstall.ts`.
98
-
99
- Target shape:
100
-
101
- - Keep dry-run planning unchanged
102
- - Keep no-op handling unchanged
103
- - Build the post-uninstall config object as today
104
- - If config removal is needed, do backup + atomic write first
105
- - Only after a successful write, perform best-effort purge of plugin-owned dirs
106
-
107
- Do not add fallback writes, retries, or rollback code.
108
-
109
- **Verify**: `pnpm -F opencode-agent-skills-md exec node --import tsx --test tests/cli-commands.test.ts` → all tests pass
110
-
111
- ### Step 3: Run repo verification
112
-
113
- **Verify**:
114
- - `pnpm run typecheck` → exit 0
115
- - `pnpm test` → exit 0
116
- - `git status --short` → only the two in-scope files plus `plans/README.md`
117
-
118
- ## Test plan
119
-
120
- Extend `packages/opencode-agent-skills-md/tests/cli-commands.test.ts`. Model after existing uninstall tests and the existing write-failure helpers. Cover:
121
- - regression: `purge: true` plus write failure leaves config unchanged
122
- - existing `--dry-run` and success paths remain green
123
-
124
- ## Done criteria
125
-
126
- - [ ] `runUninstall()` writes config before purging
127
- - [ ] Write failure leaves the config intact
128
- - [ ] `pnpm run typecheck` exits 0
129
- - [ ] `pnpm test` exits 0
130
- - [ ] No files outside scope are modified
131
- - [ ] `plans/README.md` status row updated
132
-
133
- ## STOP conditions
134
-
135
- Stop and report back (do not improvise) if:
136
- - `runUninstall()` no longer has a distinct write phase and purge phase.
137
- - The regression requires changing `CliFs` or adding a purge abstraction.
138
- - The fix appears to require changing public return types or console output format.
139
- - Verification fails twice after a reasonable fix attempt.
140
-
141
- ## Maintenance notes
142
-
143
- - Purge remains best-effort by design; the important invariant is that config state is committed first.
144
- - If uninstall ever gains transactional semantics later, revisit install/uninstall symmetry together rather than expanding this fix.
@@ -1,164 +0,0 @@
1
- # Plan 008: Reuse the shared walker in `listSkillFiles`
2
-
3
- > **Executor instructions**: Follow this plan step by step. Run every
4
- > verification command before moving on. If a STOP condition occurs, stop
5
- > and report instead of improvising. When done, update the status row for
6
- > this plan in `plans/README.md`.
7
- >
8
- > **Drift check (run first)**:
9
- > `git diff --stat 9c57cb0..HEAD -- packages/core/src/discovery.ts packages/core/src/walk.ts packages/core/tests/discovery.test.ts`
10
- > If any in-scope file changed since this plan was written, compare the
11
- > Current state excerpts below against live code first. Any mismatch is a
12
- > STOP condition.
13
-
14
- ## Status
15
-
16
- - **Priority**: P2
17
- - **Effort**: S
18
- - **Risk**: LOW
19
- - **Depends on**: none
20
- - **Category**: tech-debt
21
- - **Planned at**: commit `9c57cb0`, 2026-07-03
22
-
23
- ## Why this matters
24
-
25
- `listSkillFiles()` reimplements recursive traversal instead of using the shared
26
- `walkDir()` utility that already defines the repo's skip rules and
27
- error-isolation behavior. That duplication means `listSkillFiles()` can descend
28
- into hidden directories, `.git`, and `node_modules`, and it pays an extra
29
- `stat()` per entry. The fix is a small consolidation onto the existing
30
- abstraction.
31
-
32
- ## Current state
33
-
34
- - `packages/core/src/discovery.ts` — skill discovery helpers, including `listSkillFiles()`
35
- - `packages/core/src/walk.ts` — shared recursive walker already used by `findSkillsRecursive()` and `findScripts()`
36
- - `packages/core/tests/discovery.test.ts` — existing walker/discovery tests; no direct `listSkillFiles()` coverage
37
-
38
- Relevant excerpts:
39
-
40
- - `packages/core/src/discovery.ts:202-233`
41
- - `listSkillFiles()` uses a private `recurse()` function
42
- - calls `fs.readdir(..., { withFileTypes: true })`
43
- - then immediately calls `fs.stat(fullPath)` for every entry
44
- - does not apply `walkDir()` skip rules
45
- - `packages/core/src/walk.ts:4-16`
46
- - `walkDir()` owns shared traversal rules: hidden dirs, `node_modules`, `.git` are skipped
47
- - per-entry failures are isolated
48
- - `packages/core/tests/discovery.test.ts:82-161`
49
- - direct tests already pin `walkDir()` skip behavior
50
- - `packages/core/tests/discovery.test.ts:163-252`
51
- - `findSkillsRecursive()` already proves the walker-based pattern
52
-
53
- Conventions to match:
54
-
55
- - Keep the core package host-agnostic and dependency-free
56
- - Prefer the smallest correct refactor
57
- - Preserve sorted output and graceful handling of missing directories
58
-
59
- ## Commands you will need
60
-
61
- | Purpose | Command | Expected on success |
62
- |---|---|---|
63
- | Typecheck | `pnpm run typecheck` | exit 0 |
64
- | Targeted tests | `pnpm -F opencode-agent-skills-md-core exec node --import tsx --test tests/discovery.test.ts` | all pass |
65
- | Full tests | `pnpm test` | all pass |
66
-
67
- ## Scope
68
-
69
- **In scope** (the only files you should modify):
70
- - `packages/core/src/discovery.ts`
71
- - `packages/core/tests/discovery.test.ts`
72
-
73
- **Out of scope**:
74
- - `packages/core/src/walk.ts` behavior changes
75
- - `findScripts()` performance cleanup
76
- - Plugin package source changes
77
-
78
- ## Git workflow
79
-
80
- - Branch: `advisor/008-reuse-walkdir-for-list-skill-files`
81
- - Commit style: conventional commits, for example `refactor(core): reuse walkDir in listSkillFiles`
82
- - Do NOT push or open a PR unless instructed
83
-
84
- ## Steps
85
-
86
- ### Step 1: Add direct characterization tests for `listSkillFiles()`
87
-
88
- Extend `packages/core/tests/discovery.test.ts` with a dedicated `describe("listSkillFiles", ...)`.
89
-
90
- Build a temp skill tree that includes:
91
- - `SKILL.md`
92
- - visible nested files that should be returned
93
- - `.hidden/`
94
- - `node_modules/`
95
- - `.git/`
96
- - a nested depth boundary case
97
-
98
- Assert:
99
- - `SKILL.md` is excluded
100
- - visible files are returned as sorted relative paths
101
- - hidden, `.git`, and `node_modules` contents are not returned
102
- - missing base directory returns `[]`
103
-
104
- Model setup style after the existing `walkDir` and `findSkillsRecursive` tests.
105
-
106
- **Verify**: `pnpm -F opencode-agent-skills-md-core exec node --import tsx --test tests/discovery.test.ts` → the new tests fail before the refactor
107
-
108
- ### Step 2: Rewrite `listSkillFiles()` onto `walkDir()`
109
-
110
- Modify `packages/core/src/discovery.ts`.
111
-
112
- Target shape:
113
-
114
- - import and reuse `walkDir()` instead of the bespoke `recurse()` implementation
115
- - in the visitor:
116
- - ignore directories
117
- - ignore `SKILL.md`
118
- - compute relative paths from `skillPath`
119
- - push file paths only for visible files the walker surfaces
120
- - keep sorted return order
121
- - preserve graceful behavior when `skillPath` does not exist
122
-
123
- Do not change other discovery helpers in this plan.
124
-
125
- **Verify**: `pnpm -F opencode-agent-skills-md-core exec node --import tsx --test tests/discovery.test.ts` → all tests pass
126
-
127
- ### Step 3: Run repo verification
128
-
129
- **Verify**:
130
- - `pnpm run typecheck` → exit 0
131
- - `pnpm test` → exit 0
132
- - `git status --short` → only the two in-scope files plus `plans/README.md`
133
-
134
- ## Test plan
135
-
136
- Extend `packages/core/tests/discovery.test.ts`. Reuse the same temp-directory style already used by `walkDir` / `findSkillsRecursive`. Cover:
137
- - sorted visible file listing
138
- - exclusion of `SKILL.md`
139
- - exclusion of hidden, `.git`, and `node_modules`
140
- - missing directory returns `[]`
141
- - maxDepth still limits traversal
142
-
143
- ## Done criteria
144
-
145
- - [ ] `listSkillFiles()` reuses `walkDir()`
146
- - [ ] `listSkillFiles()` no longer has custom recursive traversal
147
- - [ ] Direct tests cover skip rules and `SKILL.md` exclusion
148
- - [ ] `pnpm run typecheck` exits 0
149
- - [ ] `pnpm test` exits 0
150
- - [ ] No files outside scope are modified
151
- - [ ] `plans/README.md` status row updated
152
-
153
- ## STOP conditions
154
-
155
- Stop and report back (do not improvise) if:
156
- - `listSkillFiles()` has already been moved out of `discovery.ts`
157
- - Reusing `walkDir()` would require changing `walkDir()` semantics
158
- - The characterization tests cannot be made to fail before the refactor
159
- - Verification fails twice after a reasonable fix attempt.
160
-
161
- ## Maintenance notes
162
-
163
- - If `findScripts()` later gets the same consolidation or perf cleanup, do that as a separate plan.
164
- - Keep `walkDir()` as the single source of truth for shared traversal rules; avoid reintroducing bespoke recursion.