opencode-sa-assistant 0.2.3 → 0.2.5
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/README.md +28 -8
- package/package.json +1 -1
- package/src/agents/index.ts +109 -2
- package/src/index.ts +13 -4
package/README.md
CHANGED
|
@@ -28,10 +28,14 @@ This plugin activates when you use the `wadd` keyword in your messages, transfor
|
|
|
28
28
|
|
|
29
29
|
## Installation
|
|
30
30
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
31
|
+
Add the plugin to your `opencode.json`:
|
|
32
|
+
|
|
33
|
+
```json
|
|
34
|
+
{
|
|
35
|
+
"plugin": [
|
|
36
|
+
"opencode-sa-assistant"
|
|
37
|
+
]
|
|
38
|
+
}
|
|
35
39
|
```
|
|
36
40
|
|
|
37
41
|
## Usage
|
|
@@ -73,14 +77,14 @@ wadd bezos에게 고객 경험 관점에서 이 기능을 평가해달라고 해
|
|
|
73
77
|
|
|
74
78
|
## Skills
|
|
75
79
|
|
|
76
|
-
The plugin includes 4 skill modules
|
|
80
|
+
The plugin includes 4 skill modules that are automatically installed to `~/.config/opencode/skills/`:
|
|
77
81
|
|
|
78
82
|
- **guru**: Guru consultation patterns and philosophies
|
|
79
83
|
- **mcp**: AWS MCP tools reference (search_documentation, read_documentation)
|
|
80
84
|
- **docx**: AWS Blog-style document generation guidelines
|
|
81
85
|
- **pptx**: SA presentation templates
|
|
82
86
|
|
|
83
|
-
Skills are
|
|
87
|
+
Skills are installed globally to ensure they are available before any plugin caching occurs. Use `/skill guru` or `/skill mcp` to load them.
|
|
84
88
|
|
|
85
89
|
## Testing
|
|
86
90
|
|
|
@@ -92,7 +96,7 @@ bun test
|
|
|
92
96
|
bun test src/__tests__/integration.test.ts
|
|
93
97
|
```
|
|
94
98
|
|
|
95
|
-
**Test Coverage**:
|
|
99
|
+
**Test Coverage**: 80 tests, 234 assertions, 100% pass rate
|
|
96
100
|
|
|
97
101
|
## Development
|
|
98
102
|
|
|
@@ -163,6 +167,23 @@ Contributions are welcome! Please ensure:
|
|
|
163
167
|
|
|
164
168
|
## Changelog
|
|
165
169
|
|
|
170
|
+
### v0.2.5 (2026-02-05)
|
|
171
|
+
|
|
172
|
+
- Fix: Skills now installed to global location (`~/.config/opencode/skills/`)
|
|
173
|
+
- Resolves oh-my-opencode cache timing issue
|
|
174
|
+
- Skills are now available via `/skill` command immediately
|
|
175
|
+
- Test coverage: 80 tests, 234 assertions
|
|
176
|
+
|
|
177
|
+
### v0.2.4 (2026-02-05)
|
|
178
|
+
|
|
179
|
+
- Added skill installation to `.opencode/skills/`
|
|
180
|
+
- Skills: guru, mcp, docx, pptx
|
|
181
|
+
|
|
182
|
+
### v0.2.3 (2026-02-05)
|
|
183
|
+
|
|
184
|
+
- Aligned wadd hook with oh-my-opencode pattern
|
|
185
|
+
- Added `removeCodeBlocks()` for keyword detection
|
|
186
|
+
|
|
166
187
|
### v0.1.0 (2026-02-05)
|
|
167
188
|
|
|
168
189
|
- Initial release
|
|
@@ -171,4 +192,3 @@ Contributions are welcome! Please ensure:
|
|
|
171
192
|
- Guru_Mandate consultation system
|
|
172
193
|
- Well-Architected Framework integration
|
|
173
194
|
- AWS MCP tools support
|
|
174
|
-
- 65 tests, 100% pass rate
|
package/package.json
CHANGED
package/src/agents/index.ts
CHANGED
|
@@ -8,9 +8,10 @@
|
|
|
8
8
|
import { SA_ORCHESTRATOR_PROMPT } from "../prompts/orchestrator";
|
|
9
9
|
import { GURU_PROMPTS } from "../prompts/gurus";
|
|
10
10
|
import { SPECIALIST_PROMPTS } from "../prompts/specialists";
|
|
11
|
-
import { existsSync, mkdirSync, writeFileSync } from "fs";
|
|
12
|
-
import { join } from "path";
|
|
11
|
+
import { existsSync, mkdirSync, writeFileSync, readFileSync } from "fs";
|
|
12
|
+
import { join, dirname } from "path";
|
|
13
13
|
import { homedir } from "os";
|
|
14
|
+
import { fileURLToPath } from "url";
|
|
14
15
|
|
|
15
16
|
/**
|
|
16
17
|
* Agent definition with frontmatter metadata
|
|
@@ -164,3 +165,109 @@ export function uninstallSAAgents(): string[] {
|
|
|
164
165
|
|
|
165
166
|
return removed;
|
|
166
167
|
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* SA Skill names that will be installed
|
|
171
|
+
*/
|
|
172
|
+
export const SA_SKILL_NAMES = ["docx", "pptx", "mcp", "guru"] as const;
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Get the skills directory path for global installation
|
|
176
|
+
* Uses ~/.config/opencode/skills/ to ensure skills are available
|
|
177
|
+
* before any plugin loads (solving the oh-my-opencode cache timing issue)
|
|
178
|
+
*/
|
|
179
|
+
function getSkillsDir(): string {
|
|
180
|
+
return join(homedir(), ".config", "opencode", "skills");
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Get the source skills directory (where SKILL.md files are bundled)
|
|
185
|
+
*/
|
|
186
|
+
function getSourceSkillsDir(): string {
|
|
187
|
+
// In ESM, use import.meta.url to find the module location
|
|
188
|
+
// Fallback to __dirname for CommonJS compatibility
|
|
189
|
+
try {
|
|
190
|
+
const currentFile = fileURLToPath(import.meta.url);
|
|
191
|
+
return join(dirname(currentFile), "..", "skills");
|
|
192
|
+
} catch {
|
|
193
|
+
// Fallback for environments where import.meta.url is not available
|
|
194
|
+
return join(__dirname, "..", "skills");
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* Install SA skills to ~/.config/opencode/skills/ (global location)
|
|
200
|
+
*/
|
|
201
|
+
export function installSASkills(): { installed: string[]; skipped: string[]; errors: string[] } {
|
|
202
|
+
const skillsDir = getSkillsDir();
|
|
203
|
+
const sourceDir = getSourceSkillsDir();
|
|
204
|
+
const installed: string[] = [];
|
|
205
|
+
const skipped: string[] = [];
|
|
206
|
+
const errors: string[] = [];
|
|
207
|
+
|
|
208
|
+
for (const skillName of SA_SKILL_NAMES) {
|
|
209
|
+
const targetDir = join(skillsDir, skillName);
|
|
210
|
+
const targetPath = join(targetDir, "SKILL.md");
|
|
211
|
+
const sourcePath = join(sourceDir, skillName, "SKILL.md");
|
|
212
|
+
|
|
213
|
+
try {
|
|
214
|
+
// Check if target already exists
|
|
215
|
+
if (existsSync(targetPath)) {
|
|
216
|
+
skipped.push(skillName);
|
|
217
|
+
continue;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
// Read source file
|
|
221
|
+
if (!existsSync(sourcePath)) {
|
|
222
|
+
errors.push(`${skillName}: source file not found at ${sourcePath}`);
|
|
223
|
+
continue;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
const content = readFileSync(sourcePath, "utf-8");
|
|
227
|
+
|
|
228
|
+
// Create target directory
|
|
229
|
+
if (!existsSync(targetDir)) {
|
|
230
|
+
mkdirSync(targetDir, { recursive: true });
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
// Write skill file
|
|
234
|
+
writeFileSync(targetPath, content, "utf-8");
|
|
235
|
+
installed.push(skillName);
|
|
236
|
+
} catch (err) {
|
|
237
|
+
errors.push(`${skillName}: ${err instanceof Error ? err.message : String(err)}`);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
return { installed, skipped, errors };
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* Uninstall SA skills from ~/.config/opencode/skills/
|
|
246
|
+
*/
|
|
247
|
+
export function uninstallSASkills(): string[] {
|
|
248
|
+
const skillsDir = getSkillsDir();
|
|
249
|
+
const removed: string[] = [];
|
|
250
|
+
|
|
251
|
+
for (const skillName of SA_SKILL_NAMES) {
|
|
252
|
+
const skillDir = join(skillsDir, skillName);
|
|
253
|
+
const skillPath = join(skillDir, "SKILL.md");
|
|
254
|
+
|
|
255
|
+
if (existsSync(skillPath)) {
|
|
256
|
+
try {
|
|
257
|
+
const { unlinkSync, rmdirSync } = require("fs");
|
|
258
|
+
unlinkSync(skillPath);
|
|
259
|
+
// Try to remove the directory if empty
|
|
260
|
+
try {
|
|
261
|
+
rmdirSync(skillDir);
|
|
262
|
+
} catch {
|
|
263
|
+
// Directory not empty, leave it
|
|
264
|
+
}
|
|
265
|
+
removed.push(skillName);
|
|
266
|
+
} catch {
|
|
267
|
+
// Ignore errors during uninstall
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
return removed;
|
|
273
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -1,12 +1,21 @@
|
|
|
1
1
|
import type { Plugin } from "@opencode-ai/plugin";
|
|
2
2
|
import { chatMessageHook, systemTransformHook } from "./hooks/wadd-mode";
|
|
3
|
-
import { installSAAgents } from "./agents";
|
|
3
|
+
import { installSAAgents, installSASkills } from "./agents";
|
|
4
4
|
|
|
5
5
|
export const SaAssistantPlugin: Plugin = async (ctx) => {
|
|
6
|
-
const
|
|
6
|
+
const agentResult = installSAAgents();
|
|
7
|
+
const skillResult = installSASkills();
|
|
7
8
|
|
|
8
|
-
if (installed.length > 0) {
|
|
9
|
-
console.log(`[SA Assistant] Installed agents: ${installed.join(", ")}`);
|
|
9
|
+
if (agentResult.installed.length > 0) {
|
|
10
|
+
console.log(`[SA Assistant] Installed agents: ${agentResult.installed.join(", ")}`);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
if (skillResult.installed.length > 0) {
|
|
14
|
+
console.log(`[SA Assistant] Installed skills: ${skillResult.installed.join(", ")}`);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
if (skillResult.errors.length > 0) {
|
|
18
|
+
console.warn(`[SA Assistant] Skill installation errors: ${skillResult.errors.join(", ")}`);
|
|
10
19
|
}
|
|
11
20
|
|
|
12
21
|
return {
|