opencode-agent-kit 1.0.1 → 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.
@@ -1,19 +1,26 @@
1
- import { readFileSync, existsSync, copyFileSync, mkdirSync, writeFileSync, readdirSync, statSync } from 'fs';
2
- import { join, dirname } from 'path';
3
- import { fileURLToPath } from 'url';
4
- import { execSync } from 'child_process';
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, 'template');
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 === '.DS_Store') continue;
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, 'bun.lock'))) return 'bun';
29
- if (existsSync(join(cwd, 'pnpm-lock.yaml'))) return 'pnpm';
30
- if (existsSync(join(cwd, 'yarn.lock'))) return 'yarn';
31
- return 'npm';
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] || 'default';
50
+ const rule = strategy[key] || "default";
44
51
 
45
- if (rule === 'keep-target') {
52
+ if (rule === "keep-target") {
46
53
  // Keep user's existing value
47
54
  continue;
48
55
  }
49
56
 
50
- if (rule === 'source-wins') {
57
+ if (rule === "source-wins") {
51
58
  merged[key] = JSON.parse(JSON.stringify(value));
52
59
  continue;
53
60
  }
54
61
 
55
- if (rule === 'merge-agents') {
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 === 'merge-mcp') {
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 === 'merge-instructions') {
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 === 'merge-permissions') {
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 (typeof value === 'object' && value !== null && !Array.isArray(value) &&
100
- typeof merged[key] === 'object' && merged[key] !== null && !Array.isArray(merged[key])) {
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, 'utf-8'));
124
+ const templateConfig = JSON.parse(readFileSync(templateConfigPath, "utf-8"));
112
125
  const userConfig = existsSync(userConfigPath)
113
- ? JSON.parse(readFileSync(userConfigPath, 'utf-8'))
126
+ ? JSON.parse(readFileSync(userConfigPath, "utf-8"))
114
127
  : {};
115
128
 
116
129
  const strategy = {
117
- '$schema': 'source-wins',
118
- 'formatter': 'keep-target',
119
- 'permission': 'keep-target',
120
- 'instructions': 'merge-instructions',
121
- 'mcp': 'merge-mcp',
122
- 'agent': force ? 'source-wins' : 'merge-agents',
123
- 'plugin': 'merge-instructions',
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, '.opencode');
145
- const userConfigPath = join(targetDir, 'opencode.json');
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('readline/promises');
150
- const readline = rl.createInterface({ input: process.stdin, output: process.stdout });
151
- const answer = await readline.question(` ? Overwrite existing files? [y/N] `);
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() !== 'y') {
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, '.opencode'), opencodeDir);
186
+ copyRecursive(join(TEMPLATE_DIR, ".opencode"), opencodeDir);
169
187
 
170
188
  // 5. Merge opencode.json
171
- const templateConfigPath = join(TEMPLATE_DIR, 'opencode.json');
189
+ const templateConfigPath = join(TEMPLATE_DIR, "opencode.json");
172
190
  if (existsSync(templateConfigPath)) {
173
191
  console.log(` 📝 Merging opencode.json...`);
174
- const merged = mergeOencodeConfig(templateConfigPath, userConfigPath, force);
175
- writeFileSync(userConfigPath, JSON.stringify(merged, null, 2) + '\n', 'utf-8');
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. Handle AGENTS.md (append)
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: 'pipe' });
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
- // 8. Done
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(` • opencode.json — 13 agents config with MCP servers`);
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.1",
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": {
@@ -1,6 +1,5 @@
1
1
  {
2
2
  "$schema": "https://opencode.ai/config.json",
3
- "formatter": true,
4
3
  "permission": {
5
4
  "read": {
6
5
  "*": "allow",
@@ -31,60 +30,10 @@
31
30
  ".opencode/skills/security-review/SKILL.md",
32
31
  ".opencode/skills/frontend-design/SKILL.md"
33
32
  ],
34
- "mcp": {
35
- "nuxt": {
36
- "type": "remote",
37
- "url": "https://nuxt.com/mcp",
38
- "enabled": true,
39
- "description": "Nuxt documentation, blog posts, and deployment guides"
40
- },
41
- "nuxt-ui": {
42
- "type": "remote",
43
- "url": "https://ui.nuxt.com/mcp",
44
- "enabled": true,
45
- "description": "Nuxt UI component documentation and examples"
46
- },
47
- "figma": {
48
- "type": "stdio",
49
- "command": "npx",
50
- "args": ["-y", "@modelcontextprotocol/server-figma"],
51
- "env": {
52
- "FIGMA_ACCESS_TOKEN": "${FIGMA_ACCESS_TOKEN}"
53
- },
54
- "enabled": false,
55
- "description": "Figma design file access (requires FIGMA_ACCESS_TOKEN)"
56
- },
57
- "playwright": {
58
- "type": "stdio",
59
- "command": "npx",
60
- "args": ["-y", "@modelcontextprotocol/server-playwright"],
61
- "enabled": true,
62
- "description": "Browser automation and E2E testing with Playwright"
63
- },
64
- "stitch": {
65
- "type": "remote",
66
- "url": "https://stitch.googleapis.com/mcp",
67
- "headers": {
68
- "X-Goog-Api-Key": "${STITCH_API_KEY}"
69
- },
70
- "enabled": false,
71
- "description": "Google Stitch AI design generation (requires STITCH_API_KEY)"
72
- },
73
- "postman": {
74
- "type": "remote",
75
- "url": "https://mcp.postman.com/mcp",
76
- "headers": {
77
- "Authorization": "Bearer ${POSTMAN_API_KEY}"
78
- },
79
- "enabled": true,
80
- "description": "Postman API management for collections, requests, and documentation"
81
- }
82
- },
83
33
  "agent": {
84
34
  "leader": {
85
35
  "description": "IT Leader & Technical Project Manager — analyzes requirements, designs architecture, decomposes tasks, delegates to subagents, and unifies outputs",
86
36
  "mode": "primary",
87
- "model": "opencode/claude-opus-4.5",
88
37
  "prompt": "{file:.opencode/agents/it-leader.md}",
89
38
  "temperature": 0.4,
90
39
  "color": "#8b5cf6",
@@ -111,7 +60,6 @@
111
60
  "frontend-nuxt": {
112
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)",
113
62
  "mode": "subagent",
114
- "model": "opencode/claude-sonnet-4.5",
115
63
  "prompt": "{file:.opencode/agents/nuxt-frontend-developer.md}",
116
64
  "color": "#3b82f6",
117
65
  "permission": {
@@ -135,7 +83,6 @@
135
83
  "frontend-react": {
136
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)",
137
85
  "mode": "subagent",
138
- "model": "opencode/claude-sonnet-4.5",
139
86
  "prompt": "{file:.opencode/agents/react-frontend-developer.md}",
140
87
  "color": "#06b6d4",
141
88
  "permission": {
@@ -157,7 +104,6 @@
157
104
  "backend": {
158
105
  "description": "Expert backend developer for Node.js, Express, Prisma, and PostgreSQL (subagent of IT Leader)",
159
106
  "mode": "subagent",
160
- "model": "opencode/claude-sonnet-4.5",
161
107
  "prompt": "{file:.opencode/agents/node-backend-developer.md}",
162
108
  "color": "#10b981",
163
109
  "permission": {
@@ -177,7 +123,6 @@
177
123
  "ci3": {
178
124
  "description": "CodeIgniter 3 MVC fullstack developer for REST API, JWT, MySQL/PostgreSQL (subagent of IT Leader)",
179
125
  "mode": "subagent",
180
- "model": "opencode/claude-sonnet-4.5",
181
126
  "prompt": "{file:.opencode/agents/code-igniter-3-fullstack.md}",
182
127
  "color": "#84cc16",
183
128
  "permission": {
@@ -196,7 +141,6 @@
196
141
  "laravel": {
197
142
  "description": "Laravel backend engineer for REST API, Service/Repository, JWT, MySQL/PostgreSQL (subagent of IT Leader)",
198
143
  "mode": "subagent",
199
- "model": "opencode/claude-sonnet-4.5",
200
144
  "prompt": "{file:.opencode/agents/laravel-advanced.md}",
201
145
  "color": "#f97316",
202
146
  "permission": {
@@ -215,7 +159,6 @@
215
159
  "designer": {
216
160
  "description": "UI/UX Designer specializing in design systems, Google Stitch, Figma, accessibility, and design-to-code handoff (subagent of IT Leader)",
217
161
  "mode": "subagent",
218
- "model": "opencode/claude-sonnet-4",
219
162
  "prompt": "{file:.opencode/agents/ui-ux-designer.md}",
220
163
  "color": "#f59e0b",
221
164
  "permission": {
@@ -236,7 +179,6 @@
236
179
  "reviewer": {
237
180
  "description": "Code Reviewer & QA Engineer specializing in code quality, security audit, testing strategy, and verification (subagent of IT Leader)",
238
181
  "mode": "subagent",
239
- "model": "opencode/claude-opus-4.5",
240
182
  "prompt": "{file:.opencode/agents/code-reviewer.md}",
241
183
  "color": "#ef4444",
242
184
  "permission": {
@@ -257,7 +199,6 @@
257
199
  "database": {
258
200
  "description": "Database Specialist specializing in PostgreSQL schema design, query optimization, Prisma ORM, and migrations (subagent of IT Leader)",
259
201
  "mode": "subagent",
260
- "model": "opencode/claude-sonnet-4.5",
261
202
  "prompt": "{file:.opencode/agents/database-specialist.md}",
262
203
  "color": "#06b6d4",
263
204
  "permission": {
@@ -276,7 +217,6 @@
276
217
  "devops": {
277
218
  "description": "DevOps Engineer specializing in CI/CD, deployment, Docker, monitoring, and infrastructure (subagent of IT Leader)",
278
219
  "mode": "subagent",
279
- "model": "opencode/claude-haiku-4.5",
280
220
  "prompt": "{file:.opencode/agents/devops-specialist.md}",
281
221
  "color": "#6366f1",
282
222
  "permission": {
@@ -296,7 +236,6 @@
296
236
  "seo": {
297
237
  "description": "SEO Specialist specializing in meta tags, structured data, Core Web Vitals, and content optimization (subagent of IT Leader)",
298
238
  "mode": "subagent",
299
- "model": "opencode/gpt-5.1-codex-mini",
300
239
  "prompt": "{file:.opencode/agents/seo-specialist.md}",
301
240
  "color": "#84cc16",
302
241
  "permission": {
@@ -315,7 +254,6 @@
315
254
  "android": {
316
255
  "description": "Expert Android developer for Kotlin, Jetpack Compose, XML, Material Design 3, and Google Play (subagent of IT Leader)",
317
256
  "mode": "subagent",
318
- "model": "opencode/claude-sonnet-4.5",
319
257
  "prompt": "{file:.opencode/agents/android-developer.md}",
320
258
  "color": "#22c55e",
321
259
  "permission": {
@@ -334,7 +272,6 @@
334
272
  "flutter": {
335
273
  "description": "Expert Flutter developer for Dart, Flutter SDK, Material Design 3, Firebase, and cross-platform mobile apps (subagent of IT Leader)",
336
274
  "mode": "subagent",
337
- "model": "opencode/claude-sonnet-4.5",
338
275
  "prompt": "{file:.opencode/agents/flutter-developer.md}",
339
276
  "color": "#0284c7",
340
277
  "permission": {
@@ -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).