opencode-sa-assistant 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-sa-assistant",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "type": "module",
5
5
  "main": "src/index.ts",
6
6
  "description": "OpenCode plugin for AWS Solutions Architect assistant with multi-agent Guru system",
@@ -0,0 +1,166 @@
1
+ /**
2
+ * SA Agent Markdown File Generator
3
+ *
4
+ * Automatically creates agent MD files in ~/.config/opencode/agents/
5
+ * so that SA agents appear in Tab selector and /agent list.
6
+ */
7
+
8
+ import { SA_ORCHESTRATOR_PROMPT } from "../prompts/orchestrator";
9
+ import { GURU_PROMPTS } from "../prompts/gurus";
10
+ import { SPECIALIST_PROMPTS } from "../prompts/specialists";
11
+ import { existsSync, mkdirSync, writeFileSync } from "fs";
12
+ import { join } from "path";
13
+ import { homedir } from "os";
14
+
15
+ /**
16
+ * Agent definition with frontmatter metadata
17
+ */
18
+ interface AgentDefinition {
19
+ name: string;
20
+ description: string;
21
+ mode: "primary" | "subagent";
22
+ prompt: string;
23
+ tools?: Record<string, boolean>;
24
+ }
25
+
26
+ /**
27
+ * SA Agent definitions
28
+ */
29
+ export const SA_AGENTS: AgentDefinition[] = [
30
+ {
31
+ name: "sa-orchestrator",
32
+ description: "AWS Solutions Architect Orchestrator - SA Assistant의 메인 에이전트",
33
+ mode: "primary",
34
+ prompt: SA_ORCHESTRATOR_PROMPT,
35
+ tools: {
36
+ write: true,
37
+ edit: true,
38
+ bash: true,
39
+ webfetch: true,
40
+ },
41
+ },
42
+ {
43
+ name: "sa-bezos",
44
+ description: "Jeff Bezos Thinking Coach - 고객 중심 사고 전문가",
45
+ mode: "subagent",
46
+ prompt: GURU_PROMPTS.bezos,
47
+ },
48
+ {
49
+ name: "sa-vogels",
50
+ description: "Werner Vogels Thinking Coach - 분산 시스템 전문가",
51
+ mode: "subagent",
52
+ prompt: GURU_PROMPTS.vogels,
53
+ },
54
+ {
55
+ name: "sa-naval",
56
+ description: "Naval Ravikant Thinking Coach - 시스템적 사고 전문가",
57
+ mode: "subagent",
58
+ prompt: GURU_PROMPTS.naval,
59
+ },
60
+ {
61
+ name: "sa-feynman",
62
+ description: "Richard Feynman Thinking Coach - 학습 최적화 전문가",
63
+ mode: "subagent",
64
+ prompt: GURU_PROMPTS.feynman,
65
+ },
66
+ {
67
+ name: "sa-explorer",
68
+ description: "Architecture Explorer - 아키텍처 분석 전문가",
69
+ mode: "subagent",
70
+ prompt: SPECIALIST_PROMPTS.explorer,
71
+ },
72
+ {
73
+ name: "sa-researcher",
74
+ description: "AWS Researcher - AWS 정보 수집 전문가 (MCP 도구 활용)",
75
+ mode: "subagent",
76
+ prompt: SPECIALIST_PROMPTS.researcher,
77
+ },
78
+ {
79
+ name: "sa-reviewer",
80
+ description: "Architecture Reviewer - Well-Architected 검토 전문가",
81
+ mode: "subagent",
82
+ prompt: SPECIALIST_PROMPTS.reviewer,
83
+ },
84
+ ];
85
+
86
+ /**
87
+ * Generate markdown content for an agent
88
+ */
89
+ function generateAgentMarkdown(agent: AgentDefinition): string {
90
+ const toolsSection = agent.tools
91
+ ? Object.entries(agent.tools)
92
+ .map(([tool, enabled]) => ` ${tool}: ${enabled}`)
93
+ .join("\n")
94
+ : "";
95
+
96
+ const frontmatter = [
97
+ "---",
98
+ `description: ${agent.description}`,
99
+ `mode: ${agent.mode}`,
100
+ toolsSection ? `tools:\n${toolsSection}` : "",
101
+ "---",
102
+ ]
103
+ .filter(Boolean)
104
+ .join("\n");
105
+
106
+ return `${frontmatter}\n\n${agent.prompt}`;
107
+ }
108
+
109
+ /**
110
+ * Get the agents directory path
111
+ */
112
+ function getAgentsDir(): string {
113
+ return join(homedir(), ".config", "opencode", "agents");
114
+ }
115
+
116
+ /**
117
+ * Install SA agents to ~/.config/opencode/agents/
118
+ * Creates the directory if it doesn't exist.
119
+ * Only writes files if they don't exist or have different content.
120
+ */
121
+ export function installSAAgents(): { installed: string[]; skipped: string[] } {
122
+ const agentsDir = getAgentsDir();
123
+ const installed: string[] = [];
124
+ const skipped: string[] = [];
125
+
126
+ // Create agents directory if it doesn't exist
127
+ if (!existsSync(agentsDir)) {
128
+ mkdirSync(agentsDir, { recursive: true });
129
+ }
130
+
131
+ for (const agent of SA_AGENTS) {
132
+ const filePath = join(agentsDir, `${agent.name}.md`);
133
+ const content = generateAgentMarkdown(agent);
134
+
135
+ // Check if file already exists
136
+ if (existsSync(filePath)) {
137
+ // Skip if file exists (don't overwrite user modifications)
138
+ skipped.push(agent.name);
139
+ } else {
140
+ // Write new file
141
+ writeFileSync(filePath, content, "utf-8");
142
+ installed.push(agent.name);
143
+ }
144
+ }
145
+
146
+ return { installed, skipped };
147
+ }
148
+
149
+ /**
150
+ * Uninstall SA agents (remove MD files)
151
+ */
152
+ export function uninstallSAAgents(): string[] {
153
+ const agentsDir = getAgentsDir();
154
+ const removed: string[] = [];
155
+
156
+ for (const agent of SA_AGENTS) {
157
+ const filePath = join(agentsDir, `${agent.name}.md`);
158
+ if (existsSync(filePath)) {
159
+ const { unlinkSync } = require("fs");
160
+ unlinkSync(filePath);
161
+ removed.push(agent.name);
162
+ }
163
+ }
164
+
165
+ return removed;
166
+ }
package/src/index.ts CHANGED
@@ -1,7 +1,14 @@
1
1
  import type { Plugin } from "@opencode-ai/plugin";
2
2
  import { chatMessageHook, systemTransformHook } from "./hooks/wadd-mode";
3
+ import { installSAAgents } from "./agents";
3
4
 
4
5
  export const SaAssistantPlugin: Plugin = async (ctx) => {
6
+ const { installed, skipped } = installSAAgents();
7
+
8
+ if (installed.length > 0) {
9
+ console.log(`[SA Assistant] Installed agents: ${installed.join(", ")}`);
10
+ }
11
+
5
12
  return {
6
13
  "chat.message": chatMessageHook,
7
14
  "experimental.chat.system.transform": systemTransformHook,