opencode-agent-kit 1.0.2 → 1.0.3
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/bin/commands/init.mjs +71 -60
- package/package.json +1 -1
- package/template/opencode.json +0 -13
- package/template/AGENTS.md +0 -32
package/bin/commands/init.mjs
CHANGED
|
@@ -1,19 +1,26 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
import {
|
|
2
|
+
readFileSync,
|
|
3
|
+
existsSync,
|
|
4
|
+
copyFileSync,
|
|
5
|
+
mkdirSync,
|
|
6
|
+
writeFileSync,
|
|
7
|
+
readdirSync,
|
|
8
|
+
} from "fs";
|
|
9
|
+
import { join, dirname } from "path";
|
|
10
|
+
import { fileURLToPath } from "url";
|
|
11
|
+
import { execSync } from "child_process";
|
|
5
12
|
|
|
6
13
|
const __filename = fileURLToPath(import.meta.url);
|
|
7
14
|
const __dirname = dirname(__filename);
|
|
8
|
-
const PKG_ROOT = join(__dirname,
|
|
9
|
-
const TEMPLATE_DIR = join(PKG_ROOT,
|
|
15
|
+
const PKG_ROOT = join(__dirname, "..", "..");
|
|
16
|
+
const TEMPLATE_DIR = join(PKG_ROOT, "template");
|
|
10
17
|
|
|
11
18
|
function copyRecursive(src, dest) {
|
|
12
19
|
if (!existsSync(src)) return;
|
|
13
20
|
const entries = readdirSync(src, { withFileTypes: true });
|
|
14
21
|
mkdirSync(dest, { recursive: true });
|
|
15
22
|
for (const entry of entries) {
|
|
16
|
-
if (entry.name ===
|
|
23
|
+
if (entry.name === ".DS_Store") continue;
|
|
17
24
|
const srcPath = join(src, entry.name);
|
|
18
25
|
const destPath = join(dest, entry.name);
|
|
19
26
|
if (entry.isDirectory()) {
|
|
@@ -25,10 +32,10 @@ function copyRecursive(src, dest) {
|
|
|
25
32
|
}
|
|
26
33
|
|
|
27
34
|
function detectPackageManager(cwd) {
|
|
28
|
-
if (existsSync(join(cwd,
|
|
29
|
-
if (existsSync(join(cwd,
|
|
30
|
-
if (existsSync(join(cwd,
|
|
31
|
-
return
|
|
35
|
+
if (existsSync(join(cwd, "bun.lock"))) return "bun";
|
|
36
|
+
if (existsSync(join(cwd, "pnpm-lock.yaml"))) return "pnpm";
|
|
37
|
+
if (existsSync(join(cwd, "yarn.lock"))) return "yarn";
|
|
38
|
+
return "npm";
|
|
32
39
|
}
|
|
33
40
|
|
|
34
41
|
function mergeJson(target, source, strategy = {}) {
|
|
@@ -40,19 +47,19 @@ function mergeJson(target, source, strategy = {}) {
|
|
|
40
47
|
continue;
|
|
41
48
|
}
|
|
42
49
|
|
|
43
|
-
const rule = strategy[key] ||
|
|
50
|
+
const rule = strategy[key] || "default";
|
|
44
51
|
|
|
45
|
-
if (rule ===
|
|
52
|
+
if (rule === "keep-target") {
|
|
46
53
|
// Keep user's existing value
|
|
47
54
|
continue;
|
|
48
55
|
}
|
|
49
56
|
|
|
50
|
-
if (rule ===
|
|
57
|
+
if (rule === "source-wins") {
|
|
51
58
|
merged[key] = JSON.parse(JSON.stringify(value));
|
|
52
59
|
continue;
|
|
53
60
|
}
|
|
54
61
|
|
|
55
|
-
if (rule ===
|
|
62
|
+
if (rule === "merge-agents") {
|
|
56
63
|
merged[key] = merged[key] || {};
|
|
57
64
|
for (const [agentKey, agentVal] of Object.entries(value)) {
|
|
58
65
|
if (!(agentKey in merged[key])) {
|
|
@@ -63,7 +70,7 @@ function mergeJson(target, source, strategy = {}) {
|
|
|
63
70
|
continue;
|
|
64
71
|
}
|
|
65
72
|
|
|
66
|
-
if (rule ===
|
|
73
|
+
if (rule === "merge-mcp") {
|
|
67
74
|
merged[key] = merged[key] || {};
|
|
68
75
|
for (const [mcpKey, mcpVal] of Object.entries(value)) {
|
|
69
76
|
if (!(mcpKey in merged[key])) {
|
|
@@ -73,7 +80,7 @@ function mergeJson(target, source, strategy = {}) {
|
|
|
73
80
|
continue;
|
|
74
81
|
}
|
|
75
82
|
|
|
76
|
-
if (rule ===
|
|
83
|
+
if (rule === "merge-instructions") {
|
|
77
84
|
const existing = merged[key] || [];
|
|
78
85
|
const srcArr = Array.isArray(value) ? value : [value];
|
|
79
86
|
for (const item of srcArr) {
|
|
@@ -85,7 +92,7 @@ function mergeJson(target, source, strategy = {}) {
|
|
|
85
92
|
continue;
|
|
86
93
|
}
|
|
87
94
|
|
|
88
|
-
if (rule ===
|
|
95
|
+
if (rule === "merge-permissions") {
|
|
89
96
|
merged[key] = merged[key] || {};
|
|
90
97
|
for (const [permKey, permVal] of Object.entries(value)) {
|
|
91
98
|
if (!(permKey in merged[key])) {
|
|
@@ -96,8 +103,14 @@ function mergeJson(target, source, strategy = {}) {
|
|
|
96
103
|
}
|
|
97
104
|
|
|
98
105
|
// default: source wins for top-level, but merge nested objects
|
|
99
|
-
if (
|
|
100
|
-
|
|
106
|
+
if (
|
|
107
|
+
typeof value === "object" &&
|
|
108
|
+
value !== null &&
|
|
109
|
+
!Array.isArray(value) &&
|
|
110
|
+
typeof merged[key] === "object" &&
|
|
111
|
+
merged[key] !== null &&
|
|
112
|
+
!Array.isArray(merged[key])
|
|
113
|
+
) {
|
|
101
114
|
merged[key] = { ...merged[key], ...value };
|
|
102
115
|
} else {
|
|
103
116
|
merged[key] = value;
|
|
@@ -108,19 +121,19 @@ function mergeJson(target, source, strategy = {}) {
|
|
|
108
121
|
}
|
|
109
122
|
|
|
110
123
|
function mergeOencodeConfig(templateConfigPath, userConfigPath, force) {
|
|
111
|
-
const templateConfig = JSON.parse(readFileSync(templateConfigPath,
|
|
124
|
+
const templateConfig = JSON.parse(readFileSync(templateConfigPath, "utf-8"));
|
|
112
125
|
const userConfig = existsSync(userConfigPath)
|
|
113
|
-
? JSON.parse(readFileSync(userConfigPath,
|
|
126
|
+
? JSON.parse(readFileSync(userConfigPath, "utf-8"))
|
|
114
127
|
: {};
|
|
115
128
|
|
|
116
129
|
const strategy = {
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
130
|
+
$schema: "source-wins",
|
|
131
|
+
formatter: "keep-target",
|
|
132
|
+
permission: "keep-target",
|
|
133
|
+
instructions: "merge-instructions",
|
|
134
|
+
mcp: "merge-mcp",
|
|
135
|
+
agent: force ? "source-wins" : "merge-agents",
|
|
136
|
+
plugin: "merge-instructions",
|
|
124
137
|
};
|
|
125
138
|
|
|
126
139
|
const merged = mergeJson(userConfig, templateConfig, strategy);
|
|
@@ -141,16 +154,21 @@ export async function init(options) {
|
|
|
141
154
|
}
|
|
142
155
|
|
|
143
156
|
// 2. Check if .opencode already exists
|
|
144
|
-
const opencodeDir = join(targetDir,
|
|
145
|
-
const userConfigPath = join(targetDir,
|
|
157
|
+
const opencodeDir = join(targetDir, ".opencode");
|
|
158
|
+
const userConfigPath = join(targetDir, "opencode.json");
|
|
146
159
|
|
|
147
160
|
if (existsSync(opencodeDir) && !force) {
|
|
148
161
|
console.log(` \n ⚠ .opencode/ already exists in ${targetDir}`);
|
|
149
|
-
const rl = await import(
|
|
150
|
-
const readline = rl.createInterface({
|
|
151
|
-
|
|
162
|
+
const rl = await import("readline/promises");
|
|
163
|
+
const readline = rl.createInterface({
|
|
164
|
+
input: process.stdin,
|
|
165
|
+
output: process.stdout,
|
|
166
|
+
});
|
|
167
|
+
const answer = await readline.question(
|
|
168
|
+
` ? Overwrite existing files? [y/N] `,
|
|
169
|
+
);
|
|
152
170
|
readline.close();
|
|
153
|
-
if (answer.toLowerCase() !==
|
|
171
|
+
if (answer.toLowerCase() !== "y") {
|
|
154
172
|
console.log(` ✗ Aborted.`);
|
|
155
173
|
process.exit(0);
|
|
156
174
|
}
|
|
@@ -165,50 +183,43 @@ export async function init(options) {
|
|
|
165
183
|
|
|
166
184
|
// 4. Copy .opencode/ from template
|
|
167
185
|
console.log(` \n 📁 Copying .opencode/ configuration...`);
|
|
168
|
-
copyRecursive(join(TEMPLATE_DIR,
|
|
186
|
+
copyRecursive(join(TEMPLATE_DIR, ".opencode"), opencodeDir);
|
|
169
187
|
|
|
170
188
|
// 5. Merge opencode.json
|
|
171
|
-
const templateConfigPath = join(TEMPLATE_DIR,
|
|
189
|
+
const templateConfigPath = join(TEMPLATE_DIR, "opencode.json");
|
|
172
190
|
if (existsSync(templateConfigPath)) {
|
|
173
191
|
console.log(` 📝 Merging opencode.json...`);
|
|
174
|
-
const merged = mergeOencodeConfig(
|
|
175
|
-
|
|
192
|
+
const merged = mergeOencodeConfig(
|
|
193
|
+
templateConfigPath,
|
|
194
|
+
userConfigPath,
|
|
195
|
+
force,
|
|
196
|
+
);
|
|
197
|
+
writeFileSync(
|
|
198
|
+
userConfigPath,
|
|
199
|
+
JSON.stringify(merged, null, 2) + "\n",
|
|
200
|
+
"utf-8",
|
|
201
|
+
);
|
|
176
202
|
}
|
|
177
203
|
|
|
178
|
-
// 6.
|
|
179
|
-
const templateAgentsPath = join(TEMPLATE_DIR, 'AGENTS.md');
|
|
180
|
-
const userAgentsPath = join(targetDir, 'AGENTS.md');
|
|
181
|
-
if (existsSync(templateAgentsPath)) {
|
|
182
|
-
const templateContent = readFileSync(templateAgentsPath, 'utf-8');
|
|
183
|
-
if (existsSync(userAgentsPath) && !force) {
|
|
184
|
-
const existingContent = readFileSync(userAgentsPath, 'utf-8');
|
|
185
|
-
if (!existingContent.includes('# opencode-agent-kit')) {
|
|
186
|
-
console.log(` 📄 Appending to existing AGENTS.md...`);
|
|
187
|
-
writeFileSync(userAgentsPath, existingContent.trimEnd() + '\n\n' + templateContent, 'utf-8');
|
|
188
|
-
}
|
|
189
|
-
} else {
|
|
190
|
-
console.log(` 📄 Writing AGENTS.md...`);
|
|
191
|
-
writeFileSync(userAgentsPath, templateContent, 'utf-8');
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
// 7. Install dependencies
|
|
204
|
+
// 6. Install dependencies
|
|
196
205
|
if (!skipInstall) {
|
|
197
206
|
const pm = detectPackageManager(opencodeDir);
|
|
198
207
|
console.log(` 📦 Installing .opencode/ dependencies with ${pm}...`);
|
|
199
208
|
try {
|
|
200
|
-
execSync(`${pm} install`, { cwd: opencodeDir, stdio:
|
|
209
|
+
execSync(`${pm} install`, { cwd: opencodeDir, stdio: "pipe" });
|
|
201
210
|
} catch (err) {
|
|
202
211
|
console.error(` ⚠ Dependency install failed: ${err.message}`);
|
|
203
212
|
console.error(` You can run "${pm} install" manually in .opencode/`);
|
|
204
213
|
}
|
|
205
214
|
}
|
|
206
215
|
|
|
207
|
-
//
|
|
216
|
+
// 7. Done
|
|
208
217
|
console.log(`\n ✅ opencode-agent-kit installed!\n`);
|
|
209
218
|
console.log(` Location: ${targetDir}`);
|
|
210
219
|
console.log(` What you got:`);
|
|
211
|
-
console.log(
|
|
220
|
+
console.log(
|
|
221
|
+
` • opencode.json — 13 agents config with MCP servers`,
|
|
222
|
+
);
|
|
212
223
|
console.log(` • .opencode/agents/ — 14 agent prompt files`);
|
|
213
224
|
console.log(` • .opencode/skills/ — 60+ skill playbooks`);
|
|
214
225
|
console.log(` • .opencode/commands/ — 35+ slash commands`);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "opencode-agent-kit",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.3",
|
|
4
4
|
"description": "Multi-stack OpenCode agent toolkit — 13 specialized AI agents (Nuxt, React, Node.js, Laravel, CI3, Android, Flutter, DevOps, SEO) with 62 skills, 36 commands, and 6 MCP servers",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
package/template/opencode.json
CHANGED
|
@@ -34,7 +34,6 @@
|
|
|
34
34
|
"leader": {
|
|
35
35
|
"description": "IT Leader & Technical Project Manager — analyzes requirements, designs architecture, decomposes tasks, delegates to subagents, and unifies outputs",
|
|
36
36
|
"mode": "primary",
|
|
37
|
-
"model": "opencode/claude-opus-4.5",
|
|
38
37
|
"prompt": "{file:.opencode/agents/it-leader.md}",
|
|
39
38
|
"temperature": 0.4,
|
|
40
39
|
"color": "#8b5cf6",
|
|
@@ -61,7 +60,6 @@
|
|
|
61
60
|
"frontend-nuxt": {
|
|
62
61
|
"description": "Expert Vue/Nuxt frontend developer for Nuxt.js, Vue 3, Nuxt UI, and modern web technologies with MCP integration (subagent of IT Leader)",
|
|
63
62
|
"mode": "subagent",
|
|
64
|
-
"model": "opencode/claude-sonnet-4.5",
|
|
65
63
|
"prompt": "{file:.opencode/agents/nuxt-frontend-developer.md}",
|
|
66
64
|
"color": "#3b82f6",
|
|
67
65
|
"permission": {
|
|
@@ -85,7 +83,6 @@
|
|
|
85
83
|
"frontend-react": {
|
|
86
84
|
"description": "Expert React/Next.js frontend developer for React 19, Next.js 15, Vite, shadcn/ui, and modern web technologies (subagent of IT Leader)",
|
|
87
85
|
"mode": "subagent",
|
|
88
|
-
"model": "opencode/claude-sonnet-4.5",
|
|
89
86
|
"prompt": "{file:.opencode/agents/react-frontend-developer.md}",
|
|
90
87
|
"color": "#06b6d4",
|
|
91
88
|
"permission": {
|
|
@@ -107,7 +104,6 @@
|
|
|
107
104
|
"backend": {
|
|
108
105
|
"description": "Expert backend developer for Node.js, Express, Prisma, and PostgreSQL (subagent of IT Leader)",
|
|
109
106
|
"mode": "subagent",
|
|
110
|
-
"model": "opencode/claude-sonnet-4.5",
|
|
111
107
|
"prompt": "{file:.opencode/agents/node-backend-developer.md}",
|
|
112
108
|
"color": "#10b981",
|
|
113
109
|
"permission": {
|
|
@@ -127,7 +123,6 @@
|
|
|
127
123
|
"ci3": {
|
|
128
124
|
"description": "CodeIgniter 3 MVC fullstack developer for REST API, JWT, MySQL/PostgreSQL (subagent of IT Leader)",
|
|
129
125
|
"mode": "subagent",
|
|
130
|
-
"model": "opencode/claude-sonnet-4.5",
|
|
131
126
|
"prompt": "{file:.opencode/agents/code-igniter-3-fullstack.md}",
|
|
132
127
|
"color": "#84cc16",
|
|
133
128
|
"permission": {
|
|
@@ -146,7 +141,6 @@
|
|
|
146
141
|
"laravel": {
|
|
147
142
|
"description": "Laravel backend engineer for REST API, Service/Repository, JWT, MySQL/PostgreSQL (subagent of IT Leader)",
|
|
148
143
|
"mode": "subagent",
|
|
149
|
-
"model": "opencode/claude-sonnet-4.5",
|
|
150
144
|
"prompt": "{file:.opencode/agents/laravel-advanced.md}",
|
|
151
145
|
"color": "#f97316",
|
|
152
146
|
"permission": {
|
|
@@ -165,7 +159,6 @@
|
|
|
165
159
|
"designer": {
|
|
166
160
|
"description": "UI/UX Designer specializing in design systems, Google Stitch, Figma, accessibility, and design-to-code handoff (subagent of IT Leader)",
|
|
167
161
|
"mode": "subagent",
|
|
168
|
-
"model": "opencode/claude-sonnet-4",
|
|
169
162
|
"prompt": "{file:.opencode/agents/ui-ux-designer.md}",
|
|
170
163
|
"color": "#f59e0b",
|
|
171
164
|
"permission": {
|
|
@@ -186,7 +179,6 @@
|
|
|
186
179
|
"reviewer": {
|
|
187
180
|
"description": "Code Reviewer & QA Engineer specializing in code quality, security audit, testing strategy, and verification (subagent of IT Leader)",
|
|
188
181
|
"mode": "subagent",
|
|
189
|
-
"model": "opencode/claude-opus-4.5",
|
|
190
182
|
"prompt": "{file:.opencode/agents/code-reviewer.md}",
|
|
191
183
|
"color": "#ef4444",
|
|
192
184
|
"permission": {
|
|
@@ -207,7 +199,6 @@
|
|
|
207
199
|
"database": {
|
|
208
200
|
"description": "Database Specialist specializing in PostgreSQL schema design, query optimization, Prisma ORM, and migrations (subagent of IT Leader)",
|
|
209
201
|
"mode": "subagent",
|
|
210
|
-
"model": "opencode/claude-sonnet-4.5",
|
|
211
202
|
"prompt": "{file:.opencode/agents/database-specialist.md}",
|
|
212
203
|
"color": "#06b6d4",
|
|
213
204
|
"permission": {
|
|
@@ -226,7 +217,6 @@
|
|
|
226
217
|
"devops": {
|
|
227
218
|
"description": "DevOps Engineer specializing in CI/CD, deployment, Docker, monitoring, and infrastructure (subagent of IT Leader)",
|
|
228
219
|
"mode": "subagent",
|
|
229
|
-
"model": "opencode/claude-haiku-4.5",
|
|
230
220
|
"prompt": "{file:.opencode/agents/devops-specialist.md}",
|
|
231
221
|
"color": "#6366f1",
|
|
232
222
|
"permission": {
|
|
@@ -246,7 +236,6 @@
|
|
|
246
236
|
"seo": {
|
|
247
237
|
"description": "SEO Specialist specializing in meta tags, structured data, Core Web Vitals, and content optimization (subagent of IT Leader)",
|
|
248
238
|
"mode": "subagent",
|
|
249
|
-
"model": "opencode/gpt-5.1-codex-mini",
|
|
250
239
|
"prompt": "{file:.opencode/agents/seo-specialist.md}",
|
|
251
240
|
"color": "#84cc16",
|
|
252
241
|
"permission": {
|
|
@@ -265,7 +254,6 @@
|
|
|
265
254
|
"android": {
|
|
266
255
|
"description": "Expert Android developer for Kotlin, Jetpack Compose, XML, Material Design 3, and Google Play (subagent of IT Leader)",
|
|
267
256
|
"mode": "subagent",
|
|
268
|
-
"model": "opencode/claude-sonnet-4.5",
|
|
269
257
|
"prompt": "{file:.opencode/agents/android-developer.md}",
|
|
270
258
|
"color": "#22c55e",
|
|
271
259
|
"permission": {
|
|
@@ -284,7 +272,6 @@
|
|
|
284
272
|
"flutter": {
|
|
285
273
|
"description": "Expert Flutter developer for Dart, Flutter SDK, Material Design 3, Firebase, and cross-platform mobile apps (subagent of IT Leader)",
|
|
286
274
|
"mode": "subagent",
|
|
287
|
-
"model": "opencode/claude-sonnet-4.5",
|
|
288
275
|
"prompt": "{file:.opencode/agents/flutter-developer.md}",
|
|
289
276
|
"color": "#0284c7",
|
|
290
277
|
"permission": {
|
package/template/AGENTS.md
DELETED
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
# opencode-agent-kit
|
|
2
|
-
|
|
3
|
-
Multi-stack agent toolkit installed by `opencode-agent-kit`.
|
|
4
|
-
|
|
5
|
-
## Agents
|
|
6
|
-
|
|
7
|
-
| Agent | Type | Description |
|
|
8
|
-
|-------|------|-------------|
|
|
9
|
-
| `leader` | primary | IT Leader — orchestrates subagents via task tool |
|
|
10
|
-
| `@frontend-nuxt` | subagent | Nuxt 4 + Vue 3 + TypeScript |
|
|
11
|
-
| `@frontend-react` | subagent | React 19 + Next.js 15 + shadcn/ui |
|
|
12
|
-
| `@backend` | subagent | Node.js + Express + Prisma + PostgreSQL |
|
|
13
|
-
| `@ci3` | subagent | CodeIgniter 3 MVC monolith |
|
|
14
|
-
| `@laravel` | subagent | Laravel 10+ REST API + Service Layer |
|
|
15
|
-
| `@designer` | subagent | UI/UX — design system, Figma, Stitch |
|
|
16
|
-
| `@reviewer` | subagent | Code quality, security audit, testing |
|
|
17
|
-
| `@database` | subagent | PostgreSQL, Prisma, migrations |
|
|
18
|
-
| `@devops` | subagent | CI/CD, Docker, monitoring |
|
|
19
|
-
| `@seo` | subagent | Meta tags, Core Web Vitals, structured data |
|
|
20
|
-
| `@android` | subagent | Kotlin, Jetpack Compose, Google Play |
|
|
21
|
-
| `@flutter` | subagent | Dart, Flutter SDK, Firebase |
|
|
22
|
-
|
|
23
|
-
## Slash Commands
|
|
24
|
-
|
|
25
|
-
`/plan`, `/tdd`, `/code-review`, `/security`, `/build-fix`, `/e2e`, `/refactor-clean`
|
|
26
|
-
`/orchestrate`, `/update-docs`, `/test-coverage`
|
|
27
|
-
`/android-build`, `/android-test`, `/gpc-release`
|
|
28
|
-
`/flutter-build`, `/flutter-test`
|
|
29
|
-
|
|
30
|
-
## MCP Servers
|
|
31
|
-
|
|
32
|
-
Nuxt docs, Nuxt UI, Playwright, Postman (enabled). Figma, Stitch (disabled, set env vars to enable).
|