opencodekit 0.5.0 → 0.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +1 -1
- package/dist/template/.opencode/AGENTS.md +12 -1
- package/dist/template/.opencode/command/skill-create.md +3 -3
- package/dist/template/.opencode/command/skill-optimize.md +1 -1
- package/dist/template/.opencode/command/summarize.md +71 -0
- package/dist/template/.opencode/opencode.json +23 -5
- package/dist/template/.opencode/package.json +1 -1
- package/dist/template/.opencode/plugin/sessions.ts +26 -1
- package/dist/template/.opencode/plugin/skill.ts +275 -0
- package/dist/template/.opencode/{skills → skill}/accessibility-audit/SKILL.md +5 -0
- package/dist/template/.opencode/{skills → skill}/brainstorming/SKILL.md +2 -2
- package/dist/template/.opencode/{skills → skill}/design-system-audit/SKILL.md +5 -0
- package/dist/template/.opencode/{skills → skill}/executing-plans/SKILL.md +13 -2
- package/dist/template/.opencode/{skills → skill}/frontend-aesthetics/SKILL.md +5 -0
- package/dist/template/.opencode/{skills → skill}/mockup-to-code/SKILL.md +5 -0
- package/dist/template/.opencode/{skills → skill}/requesting-code-review/SKILL.md +16 -6
- package/dist/template/.opencode/{skills → skill}/subagent-driven-development/SKILL.md +38 -17
- package/dist/template/.opencode/{skills → skill}/systematic-debugging/SKILL.md +28 -18
- package/dist/template/.opencode/{skills → skill}/testing-skills-with-subagents/SKILL.md +1 -1
- package/dist/template/.opencode/{skills → skill}/ui-ux-research/SKILL.md +5 -0
- package/dist/template/.opencode/{skills → skill}/visual-analysis/SKILL.md +5 -0
- package/dist/template/.opencode/{skills → skill}/writing-plans/SKILL.md +3 -3
- package/dist/template/.opencode/{skills → skill}/writing-skills/SKILL.md +101 -41
- package/package.json +1 -1
- package/dist/template/.opencode/plugin/superpowers.ts +0 -271
- package/dist/template/.opencode/superpowers/.claude/settings.local.json +0 -141
- package/dist/template/.opencode/superpowers/.claude-plugin/marketplace.json +0 -20
- package/dist/template/.opencode/superpowers/.claude-plugin/plugin.json +0 -13
- package/dist/template/.opencode/superpowers/.codex/INSTALL.md +0 -35
- package/dist/template/.opencode/superpowers/.codex/superpowers-bootstrap.md +0 -33
- package/dist/template/.opencode/superpowers/.codex/superpowers-codex +0 -267
- package/dist/template/.opencode/superpowers/.github/FUNDING.yml +0 -3
- package/dist/template/.opencode/superpowers/.opencode/INSTALL.md +0 -135
- package/dist/template/.opencode/superpowers/.opencode/plugin/superpowers.js +0 -215
- package/dist/template/.opencode/superpowers/LICENSE +0 -21
- package/dist/template/.opencode/superpowers/README.md +0 -165
- package/dist/template/.opencode/superpowers/RELEASE-NOTES.md +0 -493
- package/dist/template/.opencode/superpowers/agents/code-reviewer.md +0 -48
- package/dist/template/.opencode/superpowers/commands/brainstorm.md +0 -5
- package/dist/template/.opencode/superpowers/commands/execute-plan.md +0 -5
- package/dist/template/.opencode/superpowers/commands/write-plan.md +0 -5
- package/dist/template/.opencode/superpowers/docs/README.codex.md +0 -153
- package/dist/template/.opencode/superpowers/docs/README.opencode.md +0 -234
- package/dist/template/.opencode/superpowers/docs/plans/2025-11-22-opencode-support-design.md +0 -294
- package/dist/template/.opencode/superpowers/docs/plans/2025-11-22-opencode-support-implementation.md +0 -1095
- package/dist/template/.opencode/superpowers/hooks/hooks.json +0 -15
- package/dist/template/.opencode/superpowers/hooks/session-start.sh +0 -34
- package/dist/template/.opencode/superpowers/lib/skills-core.js +0 -208
- package/dist/template/.opencode/superpowers/tests/opencode/run-tests.sh +0 -165
- package/dist/template/.opencode/superpowers/tests/opencode/setup.sh +0 -73
- package/dist/template/.opencode/superpowers/tests/opencode/test-plugin-loading.sh +0 -81
- package/dist/template/.opencode/superpowers/tests/opencode/test-priority.sh +0 -198
- package/dist/template/.opencode/superpowers/tests/opencode/test-skills-core.sh +0 -440
- package/dist/template/.opencode/superpowers/tests/opencode/test-tools.sh +0 -104
- /package/dist/template/.opencode/{skills → skill}/condition-based-waiting/SKILL.md +0 -0
- /package/dist/template/.opencode/{skills → skill}/condition-based-waiting/example.ts +0 -0
- /package/dist/template/.opencode/{skills → skill}/defense-in-depth/SKILL.md +0 -0
- /package/dist/template/.opencode/{skills → skill}/dispatching-parallel-agents/SKILL.md +0 -0
- /package/dist/template/.opencode/{skills → skill}/finishing-a-development-branch/SKILL.md +0 -0
- /package/dist/template/.opencode/{skills → skill}/gemini-large-context/SKILL.md +0 -0
- /package/dist/template/.opencode/{skills → skill}/receiving-code-review/SKILL.md +0 -0
- /package/dist/template/.opencode/{skills/requesting-code-review/code-reviewer.md → skill/requesting-code-review/review.md} +0 -0
- /package/dist/template/.opencode/{skills → skill}/root-cause-tracing/SKILL.md +0 -0
- /package/dist/template/.opencode/{skills → skill}/root-cause-tracing/find-polluter.sh +0 -0
- /package/dist/template/.opencode/{skills → skill}/sharing-skills/SKILL.md +0 -0
- /package/dist/template/.opencode/{skills → skill}/systematic-debugging/CREATION-LOG.md +0 -0
- /package/dist/template/.opencode/{skills → skill}/systematic-debugging/test-academic.md +0 -0
- /package/dist/template/.opencode/{skills → skill}/systematic-debugging/test-pressure-1.md +0 -0
- /package/dist/template/.opencode/{skills → skill}/systematic-debugging/test-pressure-2.md +0 -0
- /package/dist/template/.opencode/{skills → skill}/systematic-debugging/test-pressure-3.md +0 -0
- /package/dist/template/.opencode/{skills → skill}/test-driven-development/SKILL.md +0 -0
- /package/dist/template/.opencode/{skills → skill}/testing-anti-patterns/SKILL.md +0 -0
- /package/dist/template/.opencode/{skills → skill}/testing-skills-with-subagents/examples/CLAUDE_MD_TESTING.md +0 -0
- /package/dist/template/.opencode/{skills → skill}/using-git-worktrees/SKILL.md +0 -0
- /package/dist/template/.opencode/{skills → skill}/using-superpowers/SKILL.md +0 -0
- /package/dist/template/.opencode/{skills → skill}/verification-before-completion/SKILL.md +0 -0
- /package/dist/template/.opencode/{skills → skill}/writing-skills/anthropic-best-practices.md +0 -0
- /package/dist/template/.opencode/{skills → skill}/writing-skills/graphviz-conventions.dot +0 -0
- /package/dist/template/.opencode/{skills → skill}/writing-skills/persuasion-principles.md +0 -0
package/dist/index.js
CHANGED
|
@@ -750,7 +750,7 @@ var cac = (name = "") => new CAC(name);
|
|
|
750
750
|
// package.json
|
|
751
751
|
var package_default = {
|
|
752
752
|
name: "opencodekit",
|
|
753
|
-
version: "0.
|
|
753
|
+
version: "0.6.1",
|
|
754
754
|
description: "CLI tool for bootstrapping and managing OpenCodeKit projects",
|
|
755
755
|
type: "module",
|
|
756
756
|
repository: {
|
|
@@ -230,6 +230,14 @@ read_session("today") # Today's first session
|
|
|
230
230
|
read_session("ses_abc123", focus="file changes") # Specific aspect
|
|
231
231
|
```
|
|
232
232
|
|
|
233
|
+
**`summarize_session`** - Generate AI summary of a session
|
|
234
|
+
|
|
235
|
+
```
|
|
236
|
+
summarize_session("ses_abc123") # Trigger AI summarization
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
Use before `read_session` to get a quick overview of what happened in a past session without loading full context.
|
|
240
|
+
|
|
233
241
|
### When to Start New Session
|
|
234
242
|
|
|
235
243
|
- Completing distinct task from `bd ready`
|
|
@@ -281,7 +289,10 @@ Use `find_skills` → `use_skill` when:
|
|
|
281
289
|
- Complex multi-step work → `writing-plans` → `executing-plans`
|
|
282
290
|
- Finished implementation → `requesting-code-review`
|
|
283
291
|
- Building UI → `frontend-aesthetics`
|
|
284
|
-
- UI/UX with images → `ui-ux-research`
|
|
292
|
+
- UI/UX with images → `ui-ux-research` or `visual-analysis`
|
|
293
|
+
- Accessibility audit → `accessibility-audit`
|
|
294
|
+
- Design system audit → `design-system-audit`
|
|
295
|
+
- Mockups to code → `mockup-to-code`
|
|
285
296
|
- Large codebase research → `gemini-large-context`
|
|
286
297
|
|
|
287
298
|
Skip for simple questions, quick edits, or conversations.
|
|
@@ -11,13 +11,13 @@ Use `use_skill("writing-skills")` to create a new skill.
|
|
|
11
11
|
## Workflow
|
|
12
12
|
|
|
13
13
|
1. **Load skill** - `use_skill("writing-skills")`
|
|
14
|
-
2. **Follow
|
|
15
|
-
3. **Save to** `.opencode/
|
|
14
|
+
2. **Follow by TDD process** - Test with subagents before writing
|
|
15
|
+
3. **Save to** `.opencode/skill/$ARGUMENTS/`
|
|
16
16
|
|
|
17
17
|
## Skill Structure
|
|
18
18
|
|
|
19
19
|
```
|
|
20
|
-
.opencode/
|
|
20
|
+
.opencode/skill/$ARGUMENTS/
|
|
21
21
|
├── SKILL.md (Main skill definition)
|
|
22
22
|
├── instructions.md (Detailed instructions)
|
|
23
23
|
└── tests/ (Test scenarios)
|
|
@@ -10,7 +10,7 @@ Use `use_skill("writing-skills")` to optimize an existing skill.
|
|
|
10
10
|
|
|
11
11
|
## Workflow
|
|
12
12
|
|
|
13
|
-
1. **Read current skill** from `.opencode/
|
|
13
|
+
1. **Read current skill** from `.opencode/skill/$ARGUMENTS/` or `.opencode/superpowers/skills/$ARGUMENTS/`
|
|
14
14
|
2. **Load skill** - `use_skill("writing-skills")`
|
|
15
15
|
3. **Apply TDD process** - Test, refine, verify
|
|
16
16
|
4. **Test changes** with `use_skill("testing-skills-with-subagents")`
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Generate AI summary of a previous session for quick context
|
|
3
|
+
argument-hint: "[session_reference]"
|
|
4
|
+
agent: build
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Summarize
|
|
8
|
+
|
|
9
|
+
Generate an AI summary of a previous session to quickly understand what happened without loading full context.
|
|
10
|
+
|
|
11
|
+
## Phase 1: Resolve Session
|
|
12
|
+
|
|
13
|
+
If no argument provided, list recent sessions:
|
|
14
|
+
|
|
15
|
+
```
|
|
16
|
+
list_sessions(limit=5, project="current")
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Parse the session reference:
|
|
20
|
+
|
|
21
|
+
- Empty or "last" resolves to most recent session
|
|
22
|
+
- "2 ago" or "3 ago" resolves to nth most recent
|
|
23
|
+
- "today" resolves to first session today
|
|
24
|
+
- "ses\_..." uses the session ID directly
|
|
25
|
+
|
|
26
|
+
## Phase 2: Generate Summary
|
|
27
|
+
|
|
28
|
+
Trigger AI summarization using the configured compaction model:
|
|
29
|
+
|
|
30
|
+
```
|
|
31
|
+
summarize_session(session_id)
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
The summary is generated asynchronously and stored with the session.
|
|
35
|
+
|
|
36
|
+
## Phase 3: Display Result
|
|
37
|
+
|
|
38
|
+
Read the session with focus on the generated summary:
|
|
39
|
+
|
|
40
|
+
```
|
|
41
|
+
read_session(session_id, focus="summary")
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Present the summary in a clear, scannable format showing what was accomplished, key decisions made, and any blockers encountered.
|
|
45
|
+
|
|
46
|
+
## Output
|
|
47
|
+
|
|
48
|
+
Report the session metadata (ID, timestamp, message count, token usage) followed by the AI-generated summary. Highlight key actions taken during the session.
|
|
49
|
+
|
|
50
|
+
End with actionable next steps:
|
|
51
|
+
|
|
52
|
+
- How to load full context if needed
|
|
53
|
+
- How to resume associated work
|
|
54
|
+
|
|
55
|
+
## Examples
|
|
56
|
+
|
|
57
|
+
```
|
|
58
|
+
/summarize # Summarize most recent session
|
|
59
|
+
/summarize last # Same as above
|
|
60
|
+
/summarize ses_abc123 # Summarize specific session
|
|
61
|
+
/summarize 2 ago # Summarize 2nd most recent
|
|
62
|
+
/summarize today # First session today
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## When to Use
|
|
66
|
+
|
|
67
|
+
Use this command before resuming work to get a quick overview without loading full context. Helpful during handoffs to understand previous session state, for context triage to decide if a session is worth loading, or when researching across multiple past sessions to find relevant work.
|
|
68
|
+
|
|
69
|
+
## Integration
|
|
70
|
+
|
|
71
|
+
This command works alongside other session tools. Start with `list_sessions` to discover available sessions, use `/summarize` to quickly understand promising candidates, then load full context with `read_session` only for the most relevant session. This workflow saves context space by avoiding unnecessary full session loads.
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
},
|
|
12
12
|
"explore": {
|
|
13
13
|
"description": "Fast codebase search specialist",
|
|
14
|
-
"model": "
|
|
14
|
+
"model": "opencode/grok-code"
|
|
15
15
|
},
|
|
16
16
|
"general": {
|
|
17
17
|
"disable": true
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
},
|
|
22
22
|
"planner": {
|
|
23
23
|
"description": "Strategic planning agent for architecture and design",
|
|
24
|
-
"model": "proxypal/gpt-5.
|
|
24
|
+
"model": "proxypal/gpt-5.1"
|
|
25
25
|
},
|
|
26
26
|
"review": {
|
|
27
27
|
"description": "Code review, debugging, and security audit specialist",
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
},
|
|
30
30
|
"rush": {
|
|
31
31
|
"description": "Fast primary agent for small, well-defined tasks",
|
|
32
|
-
"model": "
|
|
32
|
+
"model": "zai-coding-plan/glm-4.7"
|
|
33
33
|
},
|
|
34
34
|
"scout": {
|
|
35
35
|
"description": "External research specialist for library docs and patterns",
|
|
@@ -42,6 +42,7 @@
|
|
|
42
42
|
},
|
|
43
43
|
"autoupdate": false,
|
|
44
44
|
"experimental": {
|
|
45
|
+
"lsp": true,
|
|
45
46
|
"batch_tool": true,
|
|
46
47
|
"chatMaxRetries": 2,
|
|
47
48
|
"primary_tools": ["edit", "write", "bash", "prune"]
|
|
@@ -124,8 +125,8 @@
|
|
|
124
125
|
"plugin": [
|
|
125
126
|
"opencode-gemini-auth",
|
|
126
127
|
"@tarquinen/opencode-dcp@latest",
|
|
127
|
-
"@
|
|
128
|
-
"
|
|
128
|
+
"@franlol/opencode-md-table-formatter@0.0.3",
|
|
129
|
+
"./plugin/skill.ts"
|
|
129
130
|
],
|
|
130
131
|
"provider": {
|
|
131
132
|
"github-copilot": {
|
|
@@ -431,6 +432,23 @@
|
|
|
431
432
|
},
|
|
432
433
|
"zai-coding-plan": {
|
|
433
434
|
"models": {
|
|
435
|
+
"glm-4.7": {
|
|
436
|
+
"id": "glm-4.7",
|
|
437
|
+
"name": "GLM-4.7",
|
|
438
|
+
"reasoning": true,
|
|
439
|
+
"interleaved": true,
|
|
440
|
+
"options": {
|
|
441
|
+
"reasoningEffort": "high",
|
|
442
|
+
"reasoningSummary": "true",
|
|
443
|
+
"temperature": 1,
|
|
444
|
+
"top_k": 40,
|
|
445
|
+
"top_p": 0.95,
|
|
446
|
+
"maxOutputTokens": 131072,
|
|
447
|
+
"thinking": {
|
|
448
|
+
"type": "enabled"
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
},
|
|
434
452
|
"glm-4.6": {
|
|
435
453
|
"attachment": true,
|
|
436
454
|
"options": {
|
|
@@ -61,7 +61,7 @@ function parseDate(dateStr: string): Date | null {
|
|
|
61
61
|
return null;
|
|
62
62
|
}
|
|
63
63
|
|
|
64
|
-
export const SessionsPlugin: Plugin = async ({ directory }) => {
|
|
64
|
+
export const SessionsPlugin: Plugin = async ({ client, directory }) => {
|
|
65
65
|
const storageDir = join(
|
|
66
66
|
process.env.HOME || "",
|
|
67
67
|
".local/share/opencode/storage",
|
|
@@ -158,6 +158,31 @@ export const SessionsPlugin: Plugin = async ({ directory }) => {
|
|
|
158
158
|
|
|
159
159
|
return {
|
|
160
160
|
tool: {
|
|
161
|
+
summarize_session: tool({
|
|
162
|
+
description:
|
|
163
|
+
"Generate an AI summary of a session using the new auto parameter. Useful for quickly understanding what happened in a previous session.",
|
|
164
|
+
args: {
|
|
165
|
+
session_id: tool.schema
|
|
166
|
+
.string()
|
|
167
|
+
.describe("Session ID to summarize (e.g. 'ses_abc123')"),
|
|
168
|
+
},
|
|
169
|
+
async execute(args) {
|
|
170
|
+
try {
|
|
171
|
+
// Use compaction model from config: proxypal/gemini-3-flash-preview
|
|
172
|
+
const result = await client.session.summarize({
|
|
173
|
+
path: { id: args.session_id },
|
|
174
|
+
body: {
|
|
175
|
+
providerID: "proxypal",
|
|
176
|
+
modelID: "gemini-3-flash-preview",
|
|
177
|
+
},
|
|
178
|
+
});
|
|
179
|
+
return `Session summarized successfully.\n\n${JSON.stringify(result, null, 2)}`;
|
|
180
|
+
} catch (error) {
|
|
181
|
+
return `Error summarizing session: ${error instanceof Error ? error.message : String(error)}`;
|
|
182
|
+
}
|
|
183
|
+
},
|
|
184
|
+
}),
|
|
185
|
+
|
|
161
186
|
list_sessions: tool({
|
|
162
187
|
description:
|
|
163
188
|
"List OpenCode sessions with metadata. Filter by project and date. Use this before read_session to discover available sessions.",
|
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Skills plugin for OpenCode.ai
|
|
3
|
+
*
|
|
4
|
+
* Provides custom tools for loading and discovering skills.
|
|
5
|
+
* Skills are loaded on-demand via use_skill tool, not auto-injected.
|
|
6
|
+
*
|
|
7
|
+
* OpenCode Official Skill Locations:
|
|
8
|
+
* - Project skills: .opencode/skill/
|
|
9
|
+
* - Personal skills: ~/.opencode/skill/
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import fs from "fs";
|
|
13
|
+
import os from "os";
|
|
14
|
+
import path from "path";
|
|
15
|
+
import { type Plugin, tool } from "@opencode-ai/plugin";
|
|
16
|
+
|
|
17
|
+
interface SkillResolution {
|
|
18
|
+
skillFile: string;
|
|
19
|
+
sourceType: "project" | "personal";
|
|
20
|
+
skillPath: string;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
interface SkillInfo {
|
|
24
|
+
path: string;
|
|
25
|
+
skillFile: string;
|
|
26
|
+
name: string;
|
|
27
|
+
description: string;
|
|
28
|
+
sourceType: "project" | "personal";
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
interface Frontmatter {
|
|
32
|
+
name: string;
|
|
33
|
+
description: string;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// ============================================
|
|
37
|
+
// Skills Core Functions
|
|
38
|
+
// ============================================
|
|
39
|
+
|
|
40
|
+
function extractFrontmatter(filePath: string): Frontmatter {
|
|
41
|
+
try {
|
|
42
|
+
const content = fs.readFileSync(filePath, "utf8");
|
|
43
|
+
const lines = content.split("\n");
|
|
44
|
+
|
|
45
|
+
let inFrontmatter = false;
|
|
46
|
+
let name = "";
|
|
47
|
+
let description = "";
|
|
48
|
+
|
|
49
|
+
for (const line of lines) {
|
|
50
|
+
if (line.trim() === "---") {
|
|
51
|
+
if (inFrontmatter) break;
|
|
52
|
+
inFrontmatter = true;
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if (inFrontmatter) {
|
|
57
|
+
const match = line.match(/^(\w+):\s*(.*)$/);
|
|
58
|
+
if (match) {
|
|
59
|
+
const [, key, value] = match;
|
|
60
|
+
if (key === "name") name = value.trim();
|
|
61
|
+
if (key === "description") description = value.trim();
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return { name, description };
|
|
67
|
+
} catch {
|
|
68
|
+
return { name: "", description: "" };
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function findSkillsInDir(
|
|
73
|
+
dir: string,
|
|
74
|
+
sourceType: "project" | "personal",
|
|
75
|
+
maxDepth = 3,
|
|
76
|
+
): SkillInfo[] {
|
|
77
|
+
const skills: SkillInfo[] = [];
|
|
78
|
+
|
|
79
|
+
if (!fs.existsSync(dir)) return skills;
|
|
80
|
+
|
|
81
|
+
function recurse(currentDir: string, depth: number) {
|
|
82
|
+
if (depth > maxDepth) return;
|
|
83
|
+
|
|
84
|
+
const entries = fs.readdirSync(currentDir, { withFileTypes: true });
|
|
85
|
+
|
|
86
|
+
for (const entry of entries) {
|
|
87
|
+
const fullPath = path.join(currentDir, entry.name);
|
|
88
|
+
|
|
89
|
+
if (entry.isDirectory()) {
|
|
90
|
+
const skillFile = path.join(fullPath, "SKILL.md");
|
|
91
|
+
if (fs.existsSync(skillFile)) {
|
|
92
|
+
const { name, description } = extractFrontmatter(skillFile);
|
|
93
|
+
skills.push({
|
|
94
|
+
path: fullPath,
|
|
95
|
+
skillFile,
|
|
96
|
+
name: name || entry.name,
|
|
97
|
+
description: description || "",
|
|
98
|
+
sourceType,
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
recurse(fullPath, depth + 1);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
recurse(dir, 0);
|
|
107
|
+
return skills;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function stripFrontmatter(content: string): string {
|
|
111
|
+
const lines = content.split("\n");
|
|
112
|
+
let inFrontmatter = false;
|
|
113
|
+
let frontmatterEnded = false;
|
|
114
|
+
const contentLines: string[] = [];
|
|
115
|
+
|
|
116
|
+
for (const line of lines) {
|
|
117
|
+
if (line.trim() === "---") {
|
|
118
|
+
if (inFrontmatter) {
|
|
119
|
+
frontmatterEnded = true;
|
|
120
|
+
continue;
|
|
121
|
+
}
|
|
122
|
+
inFrontmatter = true;
|
|
123
|
+
continue;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
if (frontmatterEnded || !inFrontmatter) {
|
|
127
|
+
contentLines.push(line);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
return contentLines.join("\n").trim();
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// ============================================
|
|
135
|
+
// Plugin Export
|
|
136
|
+
// ============================================
|
|
137
|
+
|
|
138
|
+
export const SkillsPlugin: Plugin = async ({ client, directory }) => {
|
|
139
|
+
const homeDir = os.homedir();
|
|
140
|
+
const projectSkillsDir = path.join(directory, ".opencode/skill");
|
|
141
|
+
const personalSkillsDir = path.join(homeDir, ".opencode/skill");
|
|
142
|
+
|
|
143
|
+
return {
|
|
144
|
+
tool: {
|
|
145
|
+
use_skill: tool({
|
|
146
|
+
description:
|
|
147
|
+
"Load and read a specific skill to guide your work. Skills contain proven workflows, mandatory processes, and expert techniques.",
|
|
148
|
+
args: {
|
|
149
|
+
skill_name: tool.schema
|
|
150
|
+
.string()
|
|
151
|
+
.describe(
|
|
152
|
+
'Name of skill to load (e.g., "brainstorming", "my-custom-skill", or "project:my-skill")',
|
|
153
|
+
),
|
|
154
|
+
},
|
|
155
|
+
execute: async (
|
|
156
|
+
args: { skill_name: string },
|
|
157
|
+
context: { sessionID: string },
|
|
158
|
+
) => {
|
|
159
|
+
const { skill_name } = args;
|
|
160
|
+
|
|
161
|
+
// Resolve with priority: project > personal
|
|
162
|
+
const forceProject = skill_name.startsWith("project:");
|
|
163
|
+
const actualSkillName = forceProject
|
|
164
|
+
? skill_name.replace(/^project:/, "")
|
|
165
|
+
: skill_name;
|
|
166
|
+
|
|
167
|
+
let resolved: SkillResolution | null = null;
|
|
168
|
+
|
|
169
|
+
// Try project skills first
|
|
170
|
+
if (forceProject) {
|
|
171
|
+
const projectSkillFile = path.join(
|
|
172
|
+
projectSkillsDir,
|
|
173
|
+
actualSkillName,
|
|
174
|
+
"SKILL.md",
|
|
175
|
+
);
|
|
176
|
+
if (fs.existsSync(projectSkillFile)) {
|
|
177
|
+
resolved = {
|
|
178
|
+
skillFile: projectSkillFile,
|
|
179
|
+
sourceType: "project",
|
|
180
|
+
skillPath: actualSkillName,
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// Fall back to personal resolution
|
|
186
|
+
if (!resolved && !forceProject) {
|
|
187
|
+
const personalSkillFile = path.join(
|
|
188
|
+
personalSkillsDir,
|
|
189
|
+
skill_name,
|
|
190
|
+
"SKILL.md",
|
|
191
|
+
);
|
|
192
|
+
if (fs.existsSync(personalSkillFile)) {
|
|
193
|
+
resolved = {
|
|
194
|
+
skillFile: personalSkillFile,
|
|
195
|
+
sourceType: "personal",
|
|
196
|
+
skillPath: skill_name,
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
if (!resolved) {
|
|
202
|
+
return `Error: Skill "${skill_name}" not found.\n\nRun find_skills to see available skills.`;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
const fullContent = fs.readFileSync(resolved.skillFile, "utf8");
|
|
206
|
+
const { name, description } = extractFrontmatter(resolved.skillFile);
|
|
207
|
+
const content = stripFrontmatter(fullContent);
|
|
208
|
+
const skillDirectory = path.dirname(resolved.skillFile);
|
|
209
|
+
|
|
210
|
+
const skillHeader = `# ${name || skill_name}
|
|
211
|
+
# ${description || ""}
|
|
212
|
+
# Supporting tools and docs are in ${skillDirectory}
|
|
213
|
+
# ============================================`;
|
|
214
|
+
|
|
215
|
+
// Insert as user message with noReply for persistence across compaction
|
|
216
|
+
try {
|
|
217
|
+
await client.session.prompt({
|
|
218
|
+
path: { id: context.sessionID },
|
|
219
|
+
body: {
|
|
220
|
+
noReply: true,
|
|
221
|
+
parts: [
|
|
222
|
+
{
|
|
223
|
+
type: "text",
|
|
224
|
+
text: `Loading skill: ${name || skill_name}`,
|
|
225
|
+
},
|
|
226
|
+
{ type: "text", text: `${skillHeader}\n\n${content}` },
|
|
227
|
+
],
|
|
228
|
+
},
|
|
229
|
+
});
|
|
230
|
+
} catch {
|
|
231
|
+
// Fallback: return content directly if message insertion fails
|
|
232
|
+
return `${skillHeader}\n\n${content}`;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
return `Launching skill: ${name || skill_name}`;
|
|
236
|
+
},
|
|
237
|
+
}),
|
|
238
|
+
|
|
239
|
+
find_skills: tool({
|
|
240
|
+
description:
|
|
241
|
+
"List all available skills in project and personal skill libraries.",
|
|
242
|
+
args: {},
|
|
243
|
+
execute: async () => {
|
|
244
|
+
const projectSkills = findSkillsInDir(projectSkillsDir, "project", 3);
|
|
245
|
+
const personalSkills = findSkillsInDir(
|
|
246
|
+
personalSkillsDir,
|
|
247
|
+
"personal",
|
|
248
|
+
3,
|
|
249
|
+
);
|
|
250
|
+
|
|
251
|
+
const allSkills = [...projectSkills, ...personalSkills];
|
|
252
|
+
|
|
253
|
+
if (allSkills.length === 0) {
|
|
254
|
+
return `No skills found. Add project skills to .opencode/skill/ or personal skills to ~/.opencode/skill/`;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
let output = "Available skills:\n\n";
|
|
258
|
+
|
|
259
|
+
for (const skill of allSkills) {
|
|
260
|
+
const namespace = skill.sourceType === "project" ? "project:" : "";
|
|
261
|
+
const skillName = skill.name || path.basename(skill.path);
|
|
262
|
+
|
|
263
|
+
output += `${namespace}${skillName}\n`;
|
|
264
|
+
if (skill.description) {
|
|
265
|
+
output += ` ${skill.description}\n`;
|
|
266
|
+
}
|
|
267
|
+
output += ` Directory: ${skill.path}\n\n`;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
return output;
|
|
271
|
+
},
|
|
272
|
+
}),
|
|
273
|
+
},
|
|
274
|
+
};
|
|
275
|
+
};
|
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: accessibility-audit
|
|
3
|
+
description: Use when auditing UI components or pages for accessibility compliance, checking WCAG conformance, identifying keyboard navigation issues, color contrast problems, and pre-launch accessibility verification
|
|
4
|
+
---
|
|
5
|
+
|
|
1
6
|
# Accessibility Audit Skill
|
|
2
7
|
|
|
3
8
|
Audit UI accessibility against WCAG 2.1/2.2 guidelines.
|
|
@@ -46,8 +46,8 @@ Start by understanding the current project context, then ask questions one at a
|
|
|
46
46
|
**Implementation (if continuing):**
|
|
47
47
|
|
|
48
48
|
- Ask: "Ready to set up for implementation?"
|
|
49
|
-
- Use
|
|
50
|
-
- Use
|
|
49
|
+
- Use use_skill("using-git-worktrees") to create isolated workspace
|
|
50
|
+
- Use use_skill("writing-plans") to create detailed implementation plan
|
|
51
51
|
|
|
52
52
|
## Key Principles
|
|
53
53
|
|
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: design-system-audit
|
|
3
|
+
description: Use when auditing existing design systems for consistency, documenting undocumented design tokens, identifying design debt, preparing for design system refactoring, or comparing implementation vs design specs
|
|
4
|
+
---
|
|
5
|
+
|
|
1
6
|
# Design System Audit Skill
|
|
2
7
|
|
|
3
8
|
Audit, document, and improve design systems.
|
|
@@ -16,28 +16,35 @@ Load plan, review critically, execute tasks in batches, report for review betwee
|
|
|
16
16
|
## The Process
|
|
17
17
|
|
|
18
18
|
### Step 1: Load and Review Plan
|
|
19
|
+
|
|
19
20
|
1. Read plan file
|
|
20
21
|
2. Review critically - identify any questions or concerns about the plan
|
|
21
22
|
3. If concerns: Raise them with your human partner before starting
|
|
22
23
|
4. If no concerns: Create TodoWrite and proceed
|
|
23
24
|
|
|
24
25
|
### Step 2: Execute Batch
|
|
26
|
+
|
|
25
27
|
**Default: First 3 tasks**
|
|
26
28
|
|
|
27
29
|
For each task:
|
|
30
|
+
|
|
28
31
|
1. Mark as in_progress
|
|
29
32
|
2. Follow each step exactly (plan has bite-sized steps)
|
|
30
33
|
3. Run verifications as specified
|
|
31
34
|
4. Mark as completed
|
|
32
35
|
|
|
33
36
|
### Step 3: Report
|
|
37
|
+
|
|
34
38
|
When batch complete:
|
|
39
|
+
|
|
35
40
|
- Show what was implemented
|
|
36
41
|
- Show verification output
|
|
37
42
|
- Say: "Ready for feedback."
|
|
38
43
|
|
|
39
44
|
### Step 4: Continue
|
|
45
|
+
|
|
40
46
|
Based on feedback:
|
|
47
|
+
|
|
41
48
|
- Apply changes if needed
|
|
42
49
|
- Execute next batch
|
|
43
50
|
- Repeat until complete
|
|
@@ -45,13 +52,15 @@ Based on feedback:
|
|
|
45
52
|
### Step 5: Complete Development
|
|
46
53
|
|
|
47
54
|
After all tasks complete and verified:
|
|
48
|
-
|
|
49
|
-
-
|
|
55
|
+
|
|
56
|
+
- Announce: "I'm using finishing-a-development-branch skill to complete this work."
|
|
57
|
+
- **REQUIRED SUB-SKILL:** Use use_skill("finishing-a-development-branch")
|
|
50
58
|
- Follow that skill to verify tests, present options, execute choice
|
|
51
59
|
|
|
52
60
|
## When to Stop and Ask for Help
|
|
53
61
|
|
|
54
62
|
**STOP executing immediately when:**
|
|
63
|
+
|
|
55
64
|
- Hit a blocker mid-batch (missing dependency, test fails, instruction unclear)
|
|
56
65
|
- Plan has critical gaps preventing starting
|
|
57
66
|
- You don't understand an instruction
|
|
@@ -62,12 +71,14 @@ After all tasks complete and verified:
|
|
|
62
71
|
## When to Revisit Earlier Steps
|
|
63
72
|
|
|
64
73
|
**Return to Review (Step 1) when:**
|
|
74
|
+
|
|
65
75
|
- Partner updates the plan based on your feedback
|
|
66
76
|
- Fundamental approach needs rethinking
|
|
67
77
|
|
|
68
78
|
**Don't force through blockers** - stop and ask.
|
|
69
79
|
|
|
70
80
|
## Remember
|
|
81
|
+
|
|
71
82
|
- Review plan critically first
|
|
72
83
|
- Follow plan steps exactly
|
|
73
84
|
- Don't skip verifications
|
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: frontend-aesthetics
|
|
3
|
+
description: Use when building landing pages, dashboards, forms, or any frontend generation task where you need to prevent generic "AI slop" and create distinctive, intentional designs
|
|
4
|
+
---
|
|
5
|
+
|
|
1
6
|
# Frontend Aesthetics Skill
|
|
2
7
|
|
|
3
8
|
Prevent generic "AI slop" frontends. Create distinctive, intentional designs.
|
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: mockup-to-code
|
|
3
|
+
description: Use when converting UI mockups, screenshots, Figma/Sketch designs, wireframes, or building component libraries from design systems into production-ready code
|
|
4
|
+
---
|
|
5
|
+
|
|
1
6
|
# Mockup to Code Skill
|
|
2
7
|
|
|
3
8
|
Convert UI mockups, screenshots, and designs into production-ready code.
|