opencode-pilot 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/.github/workflows/ci.yml +8 -1
- package/.releaserc.cjs +10 -1
- package/AGENTS.md +6 -12
- package/README.md +31 -25
- package/bin/opencode-pilot +47 -209
- package/examples/config.yaml +2 -9
- package/package.json +6 -6
- package/plugin/index.js +45 -245
- package/service/{io.opencode.ntfy.plist → io.opencode.pilot.plist} +5 -5
- package/service/server.js +44 -1381
- package/test/run_tests.bash +1 -1
- package/test/test_actions.bash +21 -36
- package/test/test_cli.bash +20 -24
- package/test/test_plist.bash +11 -12
- package/test/test_poller.bash +20 -20
- package/test/test_repo_config.bash +19 -233
- package/test/test_service.bash +48 -1095
- package/test/unit/paths.test.js +16 -43
- package/test/unit/plugin.test.js +46 -0
- package/dist/opencode-ntfy.tar.gz +0 -0
- package/plugin/config.js +0 -76
- package/plugin/logger.js +0 -125
- package/plugin/notifier.js +0 -110
- package/test/test_config.bash +0 -438
- package/test/test_logger.bash +0 -401
- package/test/test_notifier.bash +0 -310
- package/test/test_plugin.bash +0 -952
- package/test/unit/config.test.js +0 -86
package/.github/workflows/ci.yml
CHANGED
|
@@ -9,6 +9,7 @@ on:
|
|
|
9
9
|
permissions:
|
|
10
10
|
contents: write
|
|
11
11
|
id-token: write # Enable OIDC for npm trusted publishing
|
|
12
|
+
issues: write # For semantic-release failure reporting
|
|
12
13
|
|
|
13
14
|
jobs:
|
|
14
15
|
test:
|
|
@@ -56,12 +57,18 @@ jobs:
|
|
|
56
57
|
with:
|
|
57
58
|
node-version: '22'
|
|
58
59
|
|
|
60
|
+
- name: Upgrade npm for trusted publishing
|
|
61
|
+
run: npm install -g npm@latest
|
|
62
|
+
|
|
63
|
+
- name: Configure npm registry
|
|
64
|
+
run: npm config set registry https://registry.npmjs.org/
|
|
65
|
+
|
|
59
66
|
- name: Install Node.js dependencies
|
|
60
67
|
run: npm install
|
|
61
68
|
|
|
62
69
|
- name: Run semantic-release
|
|
63
70
|
id: semantic
|
|
64
|
-
|
|
71
|
+
run: npx semantic-release
|
|
65
72
|
env:
|
|
66
73
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
67
74
|
NPM_CONFIG_PROVENANCE: true
|
package/.releaserc.cjs
CHANGED
|
@@ -5,7 +5,16 @@ module.exports = {
|
|
|
5
5
|
|
|
6
6
|
plugins: [
|
|
7
7
|
// Analyze commits to determine release type
|
|
8
|
-
|
|
8
|
+
// While in 0.x, breaking changes bump minor (not major) per semver spec
|
|
9
|
+
['@semantic-release/commit-analyzer', {
|
|
10
|
+
releaseRules: [
|
|
11
|
+
{ breaking: true, release: 'minor' },
|
|
12
|
+
{ type: 'feat', release: 'minor' },
|
|
13
|
+
{ type: 'fix', release: 'patch' },
|
|
14
|
+
{ type: 'perf', release: 'patch' },
|
|
15
|
+
{ type: 'refactor', release: 'patch' },
|
|
16
|
+
]
|
|
17
|
+
}],
|
|
9
18
|
|
|
10
19
|
// Generate release notes
|
|
11
20
|
'@semantic-release/release-notes-generator',
|
package/AGENTS.md
CHANGED
|
@@ -7,7 +7,6 @@ Before committing changes, verify documentation is updated to reflect code chang
|
|
|
7
7
|
1. **README.md** - Update if changes affect:
|
|
8
8
|
- Configuration options (config.yaml keys)
|
|
9
9
|
- CLI commands (`opencode-pilot <command>`)
|
|
10
|
-
- Notification types or behavior
|
|
11
10
|
- Installation or setup steps
|
|
12
11
|
- Service management
|
|
13
12
|
- Sources or polling behavior
|
|
@@ -15,7 +14,6 @@ Before committing changes, verify documentation is updated to reflect code chang
|
|
|
15
14
|
2. **CONTRIBUTING.md** - Update if changes affect:
|
|
16
15
|
- Development setup or workflow
|
|
17
16
|
- Test commands or patterns
|
|
18
|
-
- Plugin architecture
|
|
19
17
|
|
|
20
18
|
## Post-PR: Release and Upgrade Workflow
|
|
21
19
|
|
|
@@ -38,20 +36,16 @@ gh release list -R athal7/opencode-pilot -L 1
|
|
|
38
36
|
npm view opencode-pilot version
|
|
39
37
|
```
|
|
40
38
|
|
|
41
|
-
### 3. Restart
|
|
39
|
+
### 3. Restart Service
|
|
42
40
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
### 4. Restart Service
|
|
46
|
-
|
|
47
|
-
If the callback service is running, restart it:
|
|
41
|
+
If the service is running, restart it:
|
|
48
42
|
|
|
49
43
|
```bash
|
|
50
44
|
# Stop current service (Ctrl+C) and restart
|
|
51
45
|
npx opencode-pilot start
|
|
52
46
|
```
|
|
53
47
|
|
|
54
|
-
###
|
|
48
|
+
### 4. Verify Upgrade
|
|
55
49
|
|
|
56
50
|
```bash
|
|
57
51
|
npx opencode-pilot status
|
|
@@ -61,10 +55,10 @@ npx opencode-pilot status
|
|
|
61
55
|
|
|
62
56
|
Config file: `~/.config/opencode-pilot/config.yaml`
|
|
63
57
|
|
|
64
|
-
Configuration has
|
|
65
|
-
- `
|
|
66
|
-
- `repos` - per-repository settings (use YAML anchors to share config)
|
|
58
|
+
Configuration has these sections:
|
|
59
|
+
- `tools` - field mappings for MCP servers
|
|
67
60
|
- `sources` - polling sources with generic MCP tool references
|
|
61
|
+
- `repos` - per-repository settings (use YAML anchors to share config)
|
|
68
62
|
|
|
69
63
|
Template files: `~/.config/opencode-pilot/templates/*.md`
|
|
70
64
|
|
package/README.md
CHANGED
|
@@ -1,38 +1,42 @@
|
|
|
1
1
|
# opencode-pilot
|
|
2
2
|
|
|
3
|
-
Automation
|
|
3
|
+
Automation daemon for [OpenCode](https://github.com/sst/opencode) - polls for work and spawns sessions.
|
|
4
4
|
|
|
5
5
|
> **Note**: This is a community project and is not built by or affiliated with the OpenCode team.
|
|
6
6
|
|
|
7
7
|
## Features
|
|
8
8
|
|
|
9
|
-
- **Idle notifications** - Get notified when OpenCode has been waiting for input
|
|
10
|
-
- **Error alerts** - Stay informed when something needs attention
|
|
11
9
|
- **Polling automation** - Automatically start sessions from GitHub issues, Linear tickets, etc.
|
|
10
|
+
- **Readiness evaluation** - Check labels, dependencies, and priority before starting work
|
|
11
|
+
- **Template-based prompts** - Customize prompts with placeholders for issue data
|
|
12
12
|
|
|
13
13
|
## Installation
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
```json
|
|
18
|
-
{
|
|
19
|
-
"plugin": ["opencode-pilot"]
|
|
20
|
-
}
|
|
15
|
+
```bash
|
|
16
|
+
npm install -g opencode-pilot
|
|
21
17
|
```
|
|
22
18
|
|
|
23
|
-
OpenCode auto-installs npm plugins on startup.
|
|
24
|
-
|
|
25
19
|
## Quick Start
|
|
26
20
|
|
|
27
21
|
1. **Create config** - Copy [examples/config.yaml](examples/config.yaml) to `~/.config/opencode-pilot/config.yaml` and customize
|
|
28
22
|
|
|
29
|
-
2. **
|
|
23
|
+
2. **Create templates** - Add prompt templates to `~/.config/opencode-pilot/templates/`
|
|
30
24
|
|
|
31
|
-
|
|
32
|
-
|
|
25
|
+
3. **Enable the plugin** - Add to your `opencode.json`:
|
|
26
|
+
|
|
27
|
+
```json
|
|
28
|
+
{
|
|
29
|
+
"plugin": ["opencode-pilot"]
|
|
30
|
+
}
|
|
33
31
|
```
|
|
34
32
|
|
|
35
|
-
|
|
33
|
+
The daemon will auto-start when OpenCode launches.
|
|
34
|
+
|
|
35
|
+
Or start manually:
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
opencode-pilot start
|
|
39
|
+
```
|
|
36
40
|
|
|
37
41
|
## Configuration
|
|
38
42
|
|
|
@@ -40,28 +44,30 @@ See [examples/config.yaml](examples/config.yaml) for a complete example with all
|
|
|
40
44
|
|
|
41
45
|
### Key Sections
|
|
42
46
|
|
|
43
|
-
- **`notifications`** - ntfy settings (topic, server, idle/error settings)
|
|
44
|
-
- **`repos`** - Repository paths and settings (use YAML anchors to share config)
|
|
45
47
|
- **`sources`** - What to poll (GitHub issues, Linear tickets, etc.)
|
|
46
48
|
- **`tools`** - Field mappings to normalize different MCP APIs
|
|
49
|
+
- **`repos`** - Repository paths and settings (use YAML anchors to share config)
|
|
47
50
|
|
|
48
51
|
### Prompt Templates
|
|
49
52
|
|
|
50
53
|
Create prompt templates as markdown files in `~/.config/opencode-pilot/templates/`. Templates support placeholders like `{title}`, `{body}`, `{number}`, `{html_url}`, etc.
|
|
51
54
|
|
|
52
|
-
##
|
|
55
|
+
## CLI Commands
|
|
53
56
|
|
|
54
57
|
```bash
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
+
opencode-pilot start # Start the service (foreground)
|
|
59
|
+
opencode-pilot status # Check status
|
|
60
|
+
opencode-pilot config # Validate and show config
|
|
61
|
+
opencode-pilot test-source NAME # Test a source
|
|
62
|
+
opencode-pilot test-mapping MCP # Test field mappings
|
|
58
63
|
```
|
|
59
64
|
|
|
60
|
-
##
|
|
65
|
+
## How It Works
|
|
61
66
|
|
|
62
|
-
1.
|
|
63
|
-
2.
|
|
64
|
-
3.
|
|
67
|
+
1. **Poll sources** - Periodically fetch items from configured MCP tools (GitHub, Linear, etc.)
|
|
68
|
+
2. **Evaluate readiness** - Check labels, dependencies, and calculate priority
|
|
69
|
+
3. **Spawn sessions** - Start `opencode run` with the appropriate prompt template
|
|
70
|
+
4. **Track state** - Remember which items have been processed
|
|
65
71
|
|
|
66
72
|
## Related
|
|
67
73
|
|
package/bin/opencode-pilot
CHANGED
|
@@ -1,18 +1,22 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
/**
|
|
3
|
-
* opencode-pilot - CLI for opencode-pilot automation
|
|
3
|
+
* opencode-pilot - CLI for opencode-pilot automation daemon
|
|
4
4
|
*
|
|
5
5
|
* Commands:
|
|
6
|
-
*
|
|
7
|
-
* status Show
|
|
6
|
+
* start Start the polling service
|
|
7
|
+
* status Show service status
|
|
8
|
+
* config Validate and show configuration
|
|
9
|
+
* test-source Test a polling source
|
|
10
|
+
* test-mapping Test field mappings
|
|
8
11
|
* help Show help
|
|
9
12
|
*/
|
|
10
13
|
|
|
11
14
|
import { fileURLToPath } from "url";
|
|
12
15
|
import { dirname, join } from "path";
|
|
13
|
-
import { existsSync, readFileSync
|
|
16
|
+
import { existsSync, readFileSync } from "fs";
|
|
14
17
|
import { execSync } from "child_process";
|
|
15
18
|
import os from "os";
|
|
19
|
+
import YAML from "yaml";
|
|
16
20
|
|
|
17
21
|
// Get script directory for relative imports
|
|
18
22
|
const __filename = fileURLToPath(import.meta.url);
|
|
@@ -32,30 +36,34 @@ function findServiceDir() {
|
|
|
32
36
|
return candidates[0];
|
|
33
37
|
}
|
|
34
38
|
|
|
35
|
-
// Find plugin directory
|
|
36
|
-
function findPluginDir() {
|
|
37
|
-
const candidates = [
|
|
38
|
-
join(__dirname, "..", "plugin"), // Development
|
|
39
|
-
join(__dirname, "..", "lib", "opencode-pilot", "plugin"), // Homebrew
|
|
40
|
-
];
|
|
41
|
-
for (const dir of candidates) {
|
|
42
|
-
if (existsSync(join(dir, "index.js"))) {
|
|
43
|
-
return dir;
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
return null;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
39
|
const serviceDir = findServiceDir();
|
|
50
40
|
|
|
51
41
|
// Paths
|
|
52
|
-
const OPENCODE_CONFIG_DIR = join(os.homedir(), ".config/opencode");
|
|
53
|
-
const PLUGIN_NAME = "opencode-pilot";
|
|
54
|
-
const PLUGIN_DEST = join(OPENCODE_CONFIG_DIR, "plugins", PLUGIN_NAME);
|
|
55
|
-
const OPENCODE_CONFIG_FILE = join(OPENCODE_CONFIG_DIR, "opencode.json");
|
|
56
42
|
const PILOT_CONFIG_FILE = join(os.homedir(), ".config/opencode-pilot/config.yaml");
|
|
57
43
|
const PILOT_TEMPLATES_DIR = join(os.homedir(), ".config/opencode-pilot/templates");
|
|
58
44
|
|
|
45
|
+
// Default port
|
|
46
|
+
const DEFAULT_PORT = 4097;
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Load port from config file
|
|
50
|
+
* @returns {number} Port number
|
|
51
|
+
*/
|
|
52
|
+
function getPortFromConfig() {
|
|
53
|
+
try {
|
|
54
|
+
if (existsSync(PILOT_CONFIG_FILE)) {
|
|
55
|
+
const content = readFileSync(PILOT_CONFIG_FILE, "utf8");
|
|
56
|
+
const config = YAML.parse(content);
|
|
57
|
+
if (config?.port && typeof config.port === "number") {
|
|
58
|
+
return config.port;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
} catch {
|
|
62
|
+
// Ignore errors, use default
|
|
63
|
+
}
|
|
64
|
+
return DEFAULT_PORT;
|
|
65
|
+
}
|
|
66
|
+
|
|
59
67
|
// Parse command line arguments
|
|
60
68
|
function parseArgs(args) {
|
|
61
69
|
const result = {
|
|
@@ -99,27 +107,25 @@ function parseArgs(args) {
|
|
|
99
107
|
|
|
100
108
|
// Help text
|
|
101
109
|
function showHelp() {
|
|
102
|
-
console.log(`opencode-pilot - Automation
|
|
110
|
+
console.log(`opencode-pilot - Automation daemon for OpenCode
|
|
103
111
|
|
|
104
112
|
Usage:
|
|
105
113
|
opencode-pilot <command> [options]
|
|
106
114
|
|
|
107
115
|
Commands:
|
|
108
|
-
start Start the
|
|
109
|
-
|
|
110
|
-
status Show installation and service status
|
|
116
|
+
start Start the polling service (foreground)
|
|
117
|
+
status Show service status
|
|
111
118
|
config Validate and show configuration
|
|
112
119
|
test-source NAME Test a source by fetching items and showing mappings
|
|
113
120
|
test-mapping MCP Test field mappings with sample JSON input
|
|
114
121
|
help Show this help message
|
|
115
122
|
|
|
116
123
|
The service handles:
|
|
117
|
-
- Notification callbacks from ntfy
|
|
118
124
|
- Polling for GitHub/Linear issues to work on
|
|
125
|
+
- Spawning OpenCode sessions for ready items
|
|
119
126
|
|
|
120
127
|
Examples:
|
|
121
128
|
opencode-pilot start # Start service (foreground)
|
|
122
|
-
opencode-pilot setup # Initial setup
|
|
123
129
|
opencode-pilot status # Check status
|
|
124
130
|
opencode-pilot config # Validate and show config
|
|
125
131
|
opencode-pilot test-source my-issues # Test a source
|
|
@@ -140,14 +146,13 @@ async function startCommand() {
|
|
|
140
146
|
process.exit(1);
|
|
141
147
|
}
|
|
142
148
|
|
|
143
|
-
console.log("[opencode-pilot] Starting
|
|
149
|
+
console.log("[opencode-pilot] Starting polling service...");
|
|
144
150
|
|
|
145
151
|
// Dynamic import of the service module
|
|
146
152
|
const { startService, stopService } = await import(serverPath);
|
|
147
153
|
|
|
148
154
|
const config = {
|
|
149
|
-
httpPort:
|
|
150
|
-
socketPath: process.env.NTFY_SOCKET_PATH || "/tmp/opencode-pilot.sock",
|
|
155
|
+
httpPort: getPortFromConfig(),
|
|
151
156
|
};
|
|
152
157
|
|
|
153
158
|
const service = await startService(config);
|
|
@@ -169,180 +174,34 @@ async function startCommand() {
|
|
|
169
174
|
await new Promise(() => {});
|
|
170
175
|
}
|
|
171
176
|
|
|
172
|
-
// ============================================================================
|
|
173
|
-
// Setup Command
|
|
174
|
-
// ============================================================================
|
|
175
|
-
|
|
176
|
-
async function setupCommand() {
|
|
177
|
-
console.log("Setting up opencode-pilot...");
|
|
178
|
-
console.log("");
|
|
179
|
-
|
|
180
|
-
const pluginSource = findPluginDir();
|
|
181
|
-
if (!pluginSource) {
|
|
182
|
-
console.error("ERROR: Could not find plugin source files");
|
|
183
|
-
console.error("Install via: brew install athal7/tap/opencode-pilot");
|
|
184
|
-
process.exit(1);
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
console.log(`Source: ${pluginSource}`);
|
|
188
|
-
console.log(`Destination: ${PLUGIN_DEST}`);
|
|
189
|
-
console.log("");
|
|
190
|
-
|
|
191
|
-
// Backup existing config
|
|
192
|
-
if (existsSync(OPENCODE_CONFIG_FILE)) {
|
|
193
|
-
const backupFile = `${OPENCODE_CONFIG_FILE}.backup.${Date.now()}`;
|
|
194
|
-
try {
|
|
195
|
-
cpSync(OPENCODE_CONFIG_FILE, backupFile);
|
|
196
|
-
console.log(`Backup created: ${backupFile}`);
|
|
197
|
-
} catch (err) {
|
|
198
|
-
console.error("ERROR: Failed to create backup of opencode.json");
|
|
199
|
-
process.exit(1);
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
// Copy plugin files
|
|
204
|
-
mkdirSync(join(OPENCODE_CONFIG_DIR, "plugins"), { recursive: true });
|
|
205
|
-
if (existsSync(PLUGIN_DEST)) {
|
|
206
|
-
rmSync(PLUGIN_DEST, { recursive: true });
|
|
207
|
-
}
|
|
208
|
-
cpSync(pluginSource, PLUGIN_DEST, { recursive: true });
|
|
209
|
-
console.log("Plugin files copied.");
|
|
210
|
-
|
|
211
|
-
// Update opencode.json
|
|
212
|
-
let config = {};
|
|
213
|
-
if (existsSync(OPENCODE_CONFIG_FILE)) {
|
|
214
|
-
try {
|
|
215
|
-
config = JSON.parse(readFileSync(OPENCODE_CONFIG_FILE, "utf8"));
|
|
216
|
-
} catch {
|
|
217
|
-
config = {};
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
config.plugin = config.plugin || [];
|
|
222
|
-
const alreadyRegistered = config.plugin.some(p => p.includes(`plugins/${PLUGIN_NAME}`));
|
|
223
|
-
|
|
224
|
-
if (alreadyRegistered) {
|
|
225
|
-
console.log("Plugin already in opencode.json");
|
|
226
|
-
} else {
|
|
227
|
-
config.plugin.push(PLUGIN_DEST);
|
|
228
|
-
const tempFile = `${OPENCODE_CONFIG_FILE}.tmp`;
|
|
229
|
-
writeFileSync(tempFile, JSON.stringify(config, null, 2) + "\n");
|
|
230
|
-
const { renameSync } = await import("fs");
|
|
231
|
-
renameSync(tempFile, OPENCODE_CONFIG_FILE);
|
|
232
|
-
console.log("Added plugin to opencode.json");
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
// Try to restart service
|
|
236
|
-
try {
|
|
237
|
-
execSync("brew services restart opencode-pilot", { stdio: "pipe" });
|
|
238
|
-
console.log("");
|
|
239
|
-
console.log("Service restarted.");
|
|
240
|
-
} catch {
|
|
241
|
-
// Not installed via brew or service not available
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
console.log("");
|
|
245
|
-
console.log("Setup complete!");
|
|
246
|
-
console.log("");
|
|
247
|
-
console.log("Next steps:");
|
|
248
|
-
console.log(" 1. Edit ~/.config/opencode-pilot/config.yaml");
|
|
249
|
-
console.log(" 2. Run: opencode-pilot start");
|
|
250
|
-
}
|
|
251
|
-
|
|
252
177
|
// ============================================================================
|
|
253
178
|
// Status Command
|
|
254
179
|
// ============================================================================
|
|
255
180
|
|
|
256
|
-
function getConfigValue(envVar, configKey, defaultValue = "") {
|
|
257
|
-
// Check env var first
|
|
258
|
-
if (process.env[envVar]) {
|
|
259
|
-
return process.env[envVar];
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
// Check config file
|
|
263
|
-
if (existsSync(PILOT_CONFIG_FILE)) {
|
|
264
|
-
try {
|
|
265
|
-
const config = JSON.parse(readFileSync(PILOT_CONFIG_FILE, "utf8"));
|
|
266
|
-
if (config[configKey] !== undefined && config[configKey] !== "") {
|
|
267
|
-
return config[configKey];
|
|
268
|
-
}
|
|
269
|
-
} catch {
|
|
270
|
-
// Ignore
|
|
271
|
-
}
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
return defaultValue;
|
|
275
|
-
}
|
|
276
|
-
|
|
277
181
|
function statusCommand() {
|
|
278
182
|
console.log("opencode-pilot status");
|
|
279
183
|
console.log("=====================");
|
|
280
184
|
console.log("");
|
|
281
185
|
|
|
282
|
-
//
|
|
283
|
-
|
|
284
|
-
console.log(`Plugin: installed at ${PLUGIN_DEST}`);
|
|
285
|
-
} else {
|
|
286
|
-
console.log("Plugin: NOT INSTALLED (run: opencode-pilot setup)");
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
// Config?
|
|
290
|
-
if (existsSync(OPENCODE_CONFIG_FILE)) {
|
|
291
|
-
try {
|
|
292
|
-
const config = JSON.parse(readFileSync(OPENCODE_CONFIG_FILE, "utf8"));
|
|
293
|
-
const registered = (config.plugin || []).some(p => p.includes(`plugins/${PLUGIN_NAME}`));
|
|
294
|
-
if (registered) {
|
|
295
|
-
console.log("Config: plugin registered in opencode.json");
|
|
296
|
-
} else {
|
|
297
|
-
console.log("Config: plugin NOT in opencode.json");
|
|
298
|
-
}
|
|
299
|
-
} catch {
|
|
300
|
-
console.log("Config: could not parse opencode.json");
|
|
301
|
-
}
|
|
302
|
-
} else {
|
|
303
|
-
console.log("Config: opencode.json not found");
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
// Service running? Check if socket exists and HTTP responds
|
|
307
|
-
const socketPath = "/tmp/opencode-pilot.sock";
|
|
308
|
-
const servicePort = getConfigValue("NTFY_CALLBACK_PORT", "callbackPort", "4097");
|
|
186
|
+
// Service running? Check if HTTP responds
|
|
187
|
+
const servicePort = getPortFromConfig();
|
|
309
188
|
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
} else {
|
|
317
|
-
console.log("Service: socket exists but not responding (run: opencode-pilot start)");
|
|
318
|
-
}
|
|
319
|
-
} catch {
|
|
320
|
-
console.log("Service: socket exists but health check failed");
|
|
189
|
+
try {
|
|
190
|
+
const res = execSync(`curl -s -o /dev/null -w "%{http_code}" http://localhost:${servicePort}/health`, { encoding: "utf8", timeout: 2000 });
|
|
191
|
+
if (res.trim() === "200") {
|
|
192
|
+
console.log("Service: running");
|
|
193
|
+
} else {
|
|
194
|
+
console.log("Service: not responding (run: opencode-pilot start)");
|
|
321
195
|
}
|
|
322
|
-
}
|
|
196
|
+
} catch {
|
|
323
197
|
console.log("Service: not running (run: opencode-pilot start)");
|
|
324
198
|
}
|
|
325
199
|
|
|
326
|
-
// Notification configuration
|
|
327
|
-
console.log("");
|
|
328
|
-
console.log("Notification Configuration:");
|
|
329
|
-
|
|
330
|
-
const topic = getConfigValue("NTFY_TOPIC", "topic", "");
|
|
331
|
-
const server = getConfigValue("NTFY_SERVER", "server", "https://ntfy.sh");
|
|
332
|
-
const callbackHost = getConfigValue("NTFY_CALLBACK_HOST", "callbackHost", "");
|
|
333
|
-
const callbackPort = getConfigValue("NTFY_CALLBACK_PORT", "callbackPort", "4097");
|
|
334
|
-
|
|
335
|
-
console.log(` topic: ${topic || "<not set>"}`);
|
|
336
|
-
console.log(` server: ${server}`);
|
|
337
|
-
console.log(` callbackHost: ${callbackHost || "<not set>"}`);
|
|
338
|
-
console.log(` callbackPort: ${callbackPort}`);
|
|
339
|
-
|
|
340
200
|
// Polling configuration
|
|
341
201
|
console.log("");
|
|
342
|
-
console.log("
|
|
202
|
+
console.log("Configuration:");
|
|
343
203
|
if (existsSync(PILOT_CONFIG_FILE)) {
|
|
344
204
|
console.log(` config.yaml: ${PILOT_CONFIG_FILE}`);
|
|
345
|
-
console.log(" polling: enabled (handled by service)");
|
|
346
205
|
} else {
|
|
347
206
|
console.log(` config.yaml: not found at ${PILOT_CONFIG_FILE}`);
|
|
348
207
|
console.log(" polling: disabled");
|
|
@@ -379,22 +238,6 @@ async function configCommand() {
|
|
|
379
238
|
process.exit(1);
|
|
380
239
|
}
|
|
381
240
|
|
|
382
|
-
// Validate notifications section
|
|
383
|
-
console.log("");
|
|
384
|
-
console.log("Notifications:");
|
|
385
|
-
const notifications = config.notifications || {};
|
|
386
|
-
if (notifications.topic) {
|
|
387
|
-
console.log(` ✓ topic: ${notifications.topic.substring(0, 8)}...`);
|
|
388
|
-
} else {
|
|
389
|
-
console.log(" ✗ topic: not set (required for notifications)");
|
|
390
|
-
}
|
|
391
|
-
console.log(` server: ${notifications.server || "https://ntfy.sh"}`);
|
|
392
|
-
if (notifications.callback_host) {
|
|
393
|
-
console.log(` ✓ callback_host: ${notifications.callback_host}`);
|
|
394
|
-
} else {
|
|
395
|
-
console.log(" ⚠ callback_host: not set (interactive notifications disabled)");
|
|
396
|
-
}
|
|
397
|
-
|
|
398
241
|
// Validate defaults section
|
|
399
242
|
console.log("");
|
|
400
243
|
console.log("Defaults:");
|
|
@@ -599,7 +442,6 @@ async function testSourceCommand(sourceName) {
|
|
|
599
442
|
// Import poller
|
|
600
443
|
const pollerPath = join(serviceDir, "poller.js");
|
|
601
444
|
const { pollGenericSource, applyMappings } = await import(pollerPath);
|
|
602
|
-
const { getToolMappings } = await import(join(serviceDir, "repo-config.js"));
|
|
603
445
|
|
|
604
446
|
// Fetch items with mappings applied
|
|
605
447
|
const items = await pollGenericSource(source, { mappings });
|
|
@@ -763,7 +605,7 @@ async function testMappingCommand(mcpName) {
|
|
|
763
605
|
|
|
764
606
|
async function main() {
|
|
765
607
|
const args = process.argv.slice(2);
|
|
766
|
-
const { command, subcommand
|
|
608
|
+
const { command, subcommand } = parseArgs(args);
|
|
767
609
|
|
|
768
610
|
if (!command || command === "help") {
|
|
769
611
|
showHelp();
|
|
@@ -775,10 +617,6 @@ async function main() {
|
|
|
775
617
|
await startCommand();
|
|
776
618
|
break;
|
|
777
619
|
|
|
778
|
-
case "setup":
|
|
779
|
-
await setupCommand();
|
|
780
|
-
break;
|
|
781
|
-
|
|
782
620
|
case "status":
|
|
783
621
|
statusCommand();
|
|
784
622
|
break;
|
package/examples/config.yaml
CHANGED
|
@@ -4,16 +4,9 @@
|
|
|
4
4
|
# Also create templates/ directory with prompt template files
|
|
5
5
|
|
|
6
6
|
# =============================================================================
|
|
7
|
-
#
|
|
7
|
+
# SERVICE - Daemon configuration
|
|
8
8
|
# =============================================================================
|
|
9
|
-
|
|
10
|
-
topic: your-secret-topic # Required: ntfy topic name
|
|
11
|
-
server: https://ntfy.sh # Optional: ntfy server URL
|
|
12
|
-
idle_delay_ms: 300000 # Optional: idle notification delay (5 min)
|
|
13
|
-
idle_notify: true # Optional: enable idle notifications
|
|
14
|
-
error_notify: true # Optional: enable error notifications
|
|
15
|
-
error_debounce_ms: 60000 # Optional: error debounce window (1 min)
|
|
16
|
-
debug: false # Optional: enable debug logging
|
|
9
|
+
# port: 4097 # HTTP port for health checks (default: 4097)
|
|
17
10
|
|
|
18
11
|
# =============================================================================
|
|
19
12
|
# TOOLS - Field mappings for MCP servers (normalize different APIs)
|
package/package.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "opencode-pilot",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"type": "module",
|
|
5
|
-
"description": "Automation layer for OpenCode - notifications, mobile UI, and workflow orchestration",
|
|
6
5
|
"main": "plugin/index.js",
|
|
6
|
+
"description": "Automation daemon for OpenCode - polls for work and spawns sessions",
|
|
7
7
|
"repository": {
|
|
8
8
|
"type": "git",
|
|
9
9
|
"url": "https://github.com/athal7/opencode-pilot.git"
|
|
@@ -14,10 +14,10 @@
|
|
|
14
14
|
},
|
|
15
15
|
"keywords": [
|
|
16
16
|
"opencode",
|
|
17
|
-
"plugin",
|
|
18
|
-
"notifications",
|
|
19
17
|
"automation",
|
|
20
|
-
"
|
|
18
|
+
"polling",
|
|
19
|
+
"github",
|
|
20
|
+
"linear"
|
|
21
21
|
],
|
|
22
22
|
"author": "Andrew Thal <467872+athal7@users.noreply.github.com>",
|
|
23
23
|
"license": "MIT",
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
"devDependencies": {
|
|
31
31
|
"@semantic-release/git": "^10.0.1",
|
|
32
32
|
"@semantic-release/github": "^9.2.6",
|
|
33
|
-
"@semantic-release/npm": "^
|
|
33
|
+
"@semantic-release/npm": "^13.1.0",
|
|
34
34
|
"semantic-release": "^25.0.2"
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|