opencode-dev-runner 0.1.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/bin/setup.js ADDED
@@ -0,0 +1,138 @@
1
+ #!/usr/bin/env node
2
+ const { execSync } = require('child_process');
3
+ const { existsSync, mkdirSync, copyFileSync, writeFileSync } = require('fs');
4
+ const { join } = require('path');
5
+ const os = require('os');
6
+
7
+ const PLATFORM = os.platform(); // 'win32' | 'darwin' | 'linux'
8
+ const HOME = os.homedir();
9
+ const AGENTS_DIR = join(process.cwd(), '.opencode', 'agents');
10
+ const TEMPLATE = join(__dirname, '..', 'templates', 'dev-runner.md');
11
+ const MAP_FILE = join(AGENTS_DIR, 'tool-map.json');
12
+
13
+ // ── tools to discover ─────────────────────────────────────────────────
14
+ const TOOLS = [
15
+ 'adb', 'flutter', 'dart', 'git', 'node', 'npm', 'npx',
16
+ 'gh', 'code', 'supabase', 'sqlite3', 'java', 'javac', 'gradle',
17
+ 'python', 'python3', 'pip', 'pip3', 'docker', 'make',
18
+ ];
19
+
20
+ const CATEGORIES = {
21
+ adb: 'android', emulator: 'android', sdkmanager: 'android',
22
+ flutter: 'flutter', dart: 'flutter',
23
+ git: 'vcs', gh: 'vcs',
24
+ node: 'node', npm: 'node', npx: 'node', yarn: 'node', pnpm: 'node',
25
+ supabase: 'database', psql: 'database', sqlite3: 'database',
26
+ code: 'editor', nvim: 'editor', vim: 'editor',
27
+ java: 'java', javac: 'java', gradle: 'java', mvn: 'java',
28
+ python: 'python', python3: 'python', pip: 'python', pip3: 'python',
29
+ docker: 'container', make: 'build',
30
+ };
31
+
32
+ // ── cross-platform helpers ────────────────────────────────────────────
33
+
34
+ function sh(cmd) {
35
+ try { return execSync(cmd, { encoding: 'utf8', stdio: ['ignore', 'pipe', 'pipe'] }).trim().split(/[\r\n]+/)[0]; }
36
+ catch { return null; }
37
+ }
38
+
39
+ function which(tool) {
40
+ if (PLATFORM === 'win32') return sh(`where.exe ${tool}`);
41
+ return sh(`which ${tool}`) || sh(`command -v ${tool}`);
42
+ }
43
+
44
+ function classify(path) {
45
+ if (!path) return '';
46
+ if (path.includes('scoop')) return 'scoop';
47
+ if (path.includes('Android') || path.includes('android')) return 'android-sdk';
48
+ if (path.includes('homebrew') || path.includes('/opt/homebrew')) return 'brew';
49
+ if (path.includes('/usr/bin') || path.includes('System32')) return 'system';
50
+ if (path.includes('/usr/local')) return 'local';
51
+ return 'path';
52
+ }
53
+
54
+ // ── platform-specific discovery ───────────────────────────────────────
55
+
56
+ function discoverWin(tool) {
57
+ // 1. PATH
58
+ let p = which(tool);
59
+ if (p) return { path: p, source: classify(p) };
60
+
61
+ // 2. Scoop shims
62
+ p = sh(`powershell -NoProfile -Command "Get-ChildItem -LiteralPath '${join(HOME, 'scoop', 'shims')}' -Filter '${tool}*' -ErrorAction SilentlyContinue | Select-Object -ExpandProperty FullName -First 1"`);
63
+ if (p) return { path: p, source: 'scoop' };
64
+
65
+ // 3. Scoop apps deep
66
+ p = sh(`powershell -NoProfile -Command "Get-ChildItem -LiteralPath '${join(HOME, 'scoop', 'apps')}' -Filter '${tool}.exe' -Recurse -Depth 3 -ErrorAction SilentlyContinue | Select-Object -ExpandProperty FullName -First 1"`);
67
+ if (p) return { path: p, source: 'scoop' };
68
+
69
+ // 4. Android SDK
70
+ for (const base of [join(HOME, 'Android', 'Sdk'), join(HOME, 'AppData', 'Local', 'Android', 'Sdk')]) {
71
+ p = sh(`powershell -NoProfile -Command "Get-ChildItem -LiteralPath '${base}' -Filter '${tool}.exe' -Recurse -Depth 4 -ErrorAction SilentlyContinue | Select-Object -ExpandProperty FullName -First 1"`);
72
+ if (p) return { path: p, source: 'android-sdk' };
73
+ }
74
+
75
+ return null;
76
+ }
77
+
78
+ function discoverUnix(tool) {
79
+ // 1. PATH
80
+ let p = which(tool);
81
+ if (p) return { path: p, source: classify(p) };
82
+
83
+ // 2. Brew (macOS)
84
+ if (PLATFORM === 'darwin') {
85
+ for (const prefix of ['/opt/homebrew/bin', '/usr/local/bin']) {
86
+ const candidate = join(prefix, tool);
87
+ if (existsSync(candidate)) return { path: candidate, source: 'brew' };
88
+ }
89
+ }
90
+
91
+ // 3. Common unix paths
92
+ for (const prefix of ['/usr/bin', '/usr/local/bin', join(HOME, '.local', 'bin')]) {
93
+ const candidate = join(prefix, tool);
94
+ if (existsSync(candidate)) return { path: candidate, source: classify(candidate) };
95
+ }
96
+
97
+ // 4. Android SDK (Linux/Mac)
98
+ for (const base of [join(HOME, 'Android', 'Sdk'), join(HOME, 'Library', 'Android', 'sdk')]) {
99
+ p = sh(`find "${base}" -name "${tool}" -type f 2>/dev/null | head -1`);
100
+ if (p) return { path: p, source: 'android-sdk' };
101
+ }
102
+
103
+ return null;
104
+ }
105
+
106
+ function discover(tool) {
107
+ if (PLATFORM === 'win32') return discoverWin(tool);
108
+ return discoverUnix(tool);
109
+ }
110
+
111
+ // ── main ──────────────────────────────────────────────────────────────
112
+ console.log(`🔍 dev-runner-setup (${PLATFORM}) — discovering tools...\n`);
113
+
114
+ if (!existsSync(AGENTS_DIR)) mkdirSync(AGENTS_DIR, { recursive: true });
115
+
116
+ copyFileSync(TEMPLATE, join(AGENTS_DIR, 'dev-runner.md'));
117
+ console.log(' ✓ Agent installed');
118
+
119
+ const map = {};
120
+ let found = 0;
121
+ for (const tool of TOOLS) {
122
+ const r = discover(tool);
123
+ if (r && r.path) {
124
+ map[tool] = {
125
+ path: r.path.replace(/\\/g, '/'),
126
+ source: r.source,
127
+ category: CATEGORIES[tool] || 'other',
128
+ };
129
+ found++;
130
+ console.log(` ✓ ${tool}`);
131
+ } else {
132
+ console.log(` ✗ ${tool}`);
133
+ }
134
+ }
135
+
136
+ writeFileSync(MAP_FILE, JSON.stringify(map, null, 2));
137
+ console.log(`\n📦 ${found}/${TOOLS.length} tools found → ${MAP_FILE}`);
138
+ console.log(' Restart opencode to load the agent.\n');
package/package.json ADDED
@@ -0,0 +1,21 @@
1
+ {
2
+ "name": "opencode-dev-runner",
3
+ "version": "0.1.0",
4
+ "description": "Auto-discovers dev tools on your machine and installs a dev-runner subagent for opencode",
5
+ "bin": {
6
+ "dev-runner-setup": "bin/setup.js"
7
+ },
8
+ "files": [
9
+ "bin/",
10
+ "templates/"
11
+ ],
12
+ "keywords": [
13
+ "opencode",
14
+ "agent",
15
+ "dev-tools",
16
+ "flutter",
17
+ "adb",
18
+ "tool-discovery"
19
+ ],
20
+ "license": "MIT"
21
+ }
@@ -0,0 +1,105 @@
1
+ ---
2
+ description: Knows how to find and run any dev tool. Learns new tools by searching the system and saving them to tool-map.json. Use when you need a tool path, or to run flutter/dart/adb/git/npm/node/python/docker commands. Use before guessing any path or command.
3
+ mode: subagent
4
+ ---
5
+
6
+ You are the dev-runner agent. Your job: find and run any development tool on this machine. You maintain a tool registry in `tool-map.json` and learn new tools by searching the system.
7
+
8
+ ## Architecture
9
+
10
+ ```
11
+ .opencode/agents/
12
+ dev-runner.md ← you (this file)
13
+ tool-map.json ← { "toolname": { "path", "source", "category" } }
14
+ ```
15
+
16
+ **Rule**: tool-map.json is the source of truth. Read it first. Never guess paths.
17
+
18
+ ## How to resolve a tool
19
+
20
+ ### 1. Check the map
21
+
22
+ Read `.opencode/agents/tool-map.json`. Return `path` if found.
23
+
24
+ ### 2. Search the system
25
+
26
+ Stop on first hit. Platform-specific:
27
+
28
+ **Linux / macOS (bash/zsh):**
29
+ ```bash
30
+ # PATH
31
+ which <tool> 2>/dev/null || command -v <tool>
32
+
33
+ # Brew (macOS)
34
+ ls /opt/homebrew/bin/<tool> /usr/local/bin/<tool> 2>/dev/null
35
+
36
+ # Common locations
37
+ ls /usr/bin/<tool> /usr/local/bin/<tool> ~/.local/bin/<tool> 2>/dev/null
38
+
39
+ # Android SDK
40
+ find ~/Android/Sdk -name "<tool>" -type f 2>/dev/null | head -1
41
+ find ~/Library/Android/sdk -name "<tool>" -type f 2>/dev/null | head -1
42
+
43
+ # Deep search (slow, last resort)
44
+ find /usr -name "<tool>" -type f 2>/dev/null | head -3
45
+ ```
46
+
47
+ **Windows (PowerShell):**
48
+ ```powershell
49
+ # PATH
50
+ where.exe <tool> 2>$null | Select-Object -First 1
51
+
52
+ # Scoop shims
53
+ Get-ChildItem "$env:USERPROFILE\scoop\shims" -Filter "<tool>*" -ErrorAction SilentlyContinue | % FullName
54
+
55
+ # Scoop apps (deep)
56
+ Get-ChildItem "$env:USERPROFILE\scoop\apps" -Filter "<tool>.exe" -Recurse -Depth 3 -ErrorAction SilentlyContinue | % FullName
57
+
58
+ # Android SDK
59
+ Get-ChildItem "$env:LOCALAPPDATA\Android\Sdk" -Filter "<tool>.exe" -Recurse -Depth 4 -ErrorAction SilentlyContinue | % FullName
60
+ Get-ChildItem "$env:USERPROFILE\Android\Sdk" -Filter "<tool>.exe" -Recurse -Depth 4 -ErrorAction SilentlyContinue | % FullName
61
+ ```
62
+
63
+ ### 3. Save learned tool
64
+
65
+ When discovered, add to `tool-map.json` using the Edit tool. Format:
66
+
67
+ ```json
68
+ "toolname": {
69
+ "path": "/absolute/path/to/tool",
70
+ "source": "scoop|brew|android-sdk|system|path|discovered",
71
+ "category": "one-of-below"
72
+ }
73
+ ```
74
+
75
+ ### 4. Report not found
76
+
77
+ "Tool `<tool>` not found. Searched: PATH, system bins, package manager dirs, Android SDK."
78
+
79
+ ## Categories
80
+
81
+ | Category | Tools |
82
+ |----------|-------|
83
+ | `android` | adb, emulator, sdkmanager |
84
+ | `flutter` | flutter, dart |
85
+ | `vcs` | git, gh |
86
+ | `node` | node, npm, npx, yarn, pnpm |
87
+ | `python` | python, python3, pip, pip3 |
88
+ | `java` | java, javac, gradle, mvn |
89
+ | `database` | supabase, psql, sqlite3 |
90
+ | `container` | docker, podman |
91
+ | `editor` | code, nvim, vim |
92
+ | `package-manager` | scoop, choco, brew, apt, winget |
93
+ | `build` | make, cmake |
94
+ | `other` | anything else |
95
+
96
+ ## Response format
97
+
98
+ ```
99
+ tool: <name>
100
+ path: <resolved>
101
+ command: <exact command>
102
+ workdir: <dir or none>
103
+ ```
104
+
105
+ If just learned: append "→ saved to tool-map.json".