opencode-arise 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/LICENSE +21 -0
- package/README.md +271 -0
- package/assets/arise-banner.txt +13 -0
- package/dist/agents/index.d.ts +1 -0
- package/dist/agents/shadows.d.ts +28 -0
- package/dist/cli/index.d.ts +2 -0
- package/dist/cli/index.js +183 -0
- package/dist/config/schema.d.ts +90 -0
- package/dist/hooks/arise-banner.d.ts +6 -0
- package/dist/hooks/compaction-preserver.d.ts +3 -0
- package/dist/hooks/index.d.ts +4 -0
- package/dist/hooks/output-shaper.d.ts +4 -0
- package/dist/hooks/todo-enforcer.d.ts +9 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +17114 -0
- package/dist/tools/background-manager.d.ts +35 -0
- package/dist/tools/background-tools.d.ts +6 -0
- package/dist/tools/call-arise-agent.d.ts +3 -0
- package/dist/tools/index.d.ts +3 -0
- package/package.json +59 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 opencode-arise contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
# opencode-arise
|
|
2
|
+
|
|
3
|
+
> ⚔️ **ARISE!** A Solo Leveling themed orchestrator harness for OpenCode
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/opencode-arise)
|
|
6
|
+
[](https://opensource.org/licenses/MIT)
|
|
7
|
+
|
|
8
|
+
A lightweight, token-efficient orchestrator layer that extends [OpenCode](https://opencode.ai) with a shadow army of specialized AI agents. Inspired by Solo Leveling's Shadow Monarch, Sung Jinwoo.
|
|
9
|
+
|
|
10
|
+
## Features
|
|
11
|
+
|
|
12
|
+
- **Shadow Army** - 7 specialized agents for different tasks
|
|
13
|
+
- **Smart Delegation** - Monarch orchestrates with minimal token usage
|
|
14
|
+
- **Parallel Execution** - Background tasks for concurrent exploration
|
|
15
|
+
- **Quality-Safe Output** - Never truncates errors or stack traces
|
|
16
|
+
- **Configurable** - Customize models, disable shadows, tweak behavior
|
|
17
|
+
|
|
18
|
+
## Installation
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
bunx opencode-arise install
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
This registers the plugin with OpenCode and creates a default config.
|
|
25
|
+
|
|
26
|
+
**Verify installation:**
|
|
27
|
+
```bash
|
|
28
|
+
bunx opencode-arise doctor
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Quick Start
|
|
32
|
+
|
|
33
|
+
After installation, just run OpenCode as usual:
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
opencode
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
You'll see the "ARISE!" banner, and the **Monarch** becomes your default agent. Talk naturally - the Monarch decides when to delegate to shadows.
|
|
40
|
+
|
|
41
|
+
```
|
|
42
|
+
You: "Find all React components using useState and add error boundaries"
|
|
43
|
+
|
|
44
|
+
Monarch: "I'll have Beru scout the codebase, then Igris implement the changes."
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Shadow Army
|
|
48
|
+
|
|
49
|
+
| Shadow | Role | Best For |
|
|
50
|
+
|--------|------|----------|
|
|
51
|
+
| 👑 **monarch** | Shadow Monarch | Orchestration, delegation decisions |
|
|
52
|
+
| 🐜 **beru** | Ant King Scout | Fast codebase exploration, grep, file discovery |
|
|
53
|
+
| ⚔️ **igris** | Loyal Knight | Precise implementation, code changes |
|
|
54
|
+
| 🎖️ **bellion** | Grand Marshal | Strategic planning, architecture analysis |
|
|
55
|
+
| 🎨 **tusk** | Creative Shadow | UI/UX, frontend, styling |
|
|
56
|
+
| 🛡️ **tank** | Research Shadow | External docs, web search, examples |
|
|
57
|
+
| 👁️ **shadow-sovereign** | Full Power | Deep reasoning, complex debugging |
|
|
58
|
+
|
|
59
|
+
### Direct Summoning
|
|
60
|
+
|
|
61
|
+
You can bypass the Monarch and summon shadows directly:
|
|
62
|
+
|
|
63
|
+
```
|
|
64
|
+
@beru find all TODO comments in src/
|
|
65
|
+
|
|
66
|
+
@bellion plan a migration from REST to GraphQL
|
|
67
|
+
|
|
68
|
+
@shadow-sovereign why is this recursive function causing a stack overflow?
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## How It Works
|
|
72
|
+
|
|
73
|
+
```
|
|
74
|
+
┌─────────────────────────────────────────────────────────┐
|
|
75
|
+
│ USER │
|
|
76
|
+
│ │ │
|
|
77
|
+
│ ▼ │
|
|
78
|
+
│ ┌─────────────────────────────────────────────────┐ │
|
|
79
|
+
│ │ 👑 MONARCH │ │
|
|
80
|
+
│ │ (Primary Orchestrator) │ │
|
|
81
|
+
│ │ │ │
|
|
82
|
+
│ │ Assesses task → Delegates or handles │ │
|
|
83
|
+
│ └──────────────────────┬──────────────────────────┘ │
|
|
84
|
+
│ │ │
|
|
85
|
+
│ ┌───────┬───────────┼───────────┬───────┐ │
|
|
86
|
+
│ ▼ ▼ ▼ ▼ ▼ │
|
|
87
|
+
│ 🐜 ⚔️ 🎖️ 🛡️ 👁️ │
|
|
88
|
+
│ BERU IGRIS BELLION TANK SOVEREIGN │
|
|
89
|
+
│ scout implement plan research reason │
|
|
90
|
+
└─────────────────────────────────────────────────────────┘
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
**Monarch's Principles:**
|
|
94
|
+
1. Assess intent before acting - don't over-delegate
|
|
95
|
+
2. Handle trivial tasks directly
|
|
96
|
+
3. Use parallel background tasks for exploration
|
|
97
|
+
4. Only summon shadow-sovereign for complex problems
|
|
98
|
+
5. Verify changes work before declaring done
|
|
99
|
+
|
|
100
|
+
## Custom Tools
|
|
101
|
+
|
|
102
|
+
The plugin provides these tools to the Monarch:
|
|
103
|
+
|
|
104
|
+
| Tool | Description |
|
|
105
|
+
|------|-------------|
|
|
106
|
+
| `arise_summon` | Invoke a shadow (sync or background) |
|
|
107
|
+
| `arise_background` | Launch parallel background task |
|
|
108
|
+
| `arise_background_output` | Get result from background task |
|
|
109
|
+
| `arise_background_status` | List all background tasks |
|
|
110
|
+
| `arise_background_cancel` | Cancel a running task |
|
|
111
|
+
|
|
112
|
+
## Hooks
|
|
113
|
+
|
|
114
|
+
| Hook | Description |
|
|
115
|
+
|------|-------------|
|
|
116
|
+
| `arise-banner` | Shows "ARISE!" toast on session start |
|
|
117
|
+
| `output-shaper` | Quality-safe output truncation (preserves errors) |
|
|
118
|
+
| `compaction-preserver` | Preserves critical context during session compaction |
|
|
119
|
+
| `todo-enforcer` | Reminds about incomplete TODOs on session idle |
|
|
120
|
+
|
|
121
|
+
## Configuration
|
|
122
|
+
|
|
123
|
+
Create `~/.config/opencode/opencode-arise.json`:
|
|
124
|
+
|
|
125
|
+
```json
|
|
126
|
+
{
|
|
127
|
+
"show_banner": true,
|
|
128
|
+
"disabled_shadows": [],
|
|
129
|
+
"disabled_hooks": [],
|
|
130
|
+
"agents": {
|
|
131
|
+
"monarch": {
|
|
132
|
+
"model": "anthropic/claude-sonnet-4"
|
|
133
|
+
},
|
|
134
|
+
"beru": {
|
|
135
|
+
"model": "openai/gpt-4.1-mini"
|
|
136
|
+
}
|
|
137
|
+
},
|
|
138
|
+
"output_shaping": {
|
|
139
|
+
"max_chars": 12000,
|
|
140
|
+
"preserve_errors": true
|
|
141
|
+
},
|
|
142
|
+
"compaction": {
|
|
143
|
+
"threshold_percent": 80,
|
|
144
|
+
"preserve_todos": true
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
### Configuration Options
|
|
150
|
+
|
|
151
|
+
| Option | Type | Default | Description |
|
|
152
|
+
|--------|------|---------|-------------|
|
|
153
|
+
| `show_banner` | boolean | `true` | Show "ARISE!" toast on session start |
|
|
154
|
+
| `banner_every_session` | boolean | `false` | Show banner for every session (not just first) |
|
|
155
|
+
| `disabled_shadows` | string[] | `[]` | Shadows to disable (e.g., `["tusk", "tank"]`) |
|
|
156
|
+
| `disabled_hooks` | string[] | `[]` | Hooks to disable |
|
|
157
|
+
| `agents.<name>.model` | string | varies | Override model for a shadow |
|
|
158
|
+
| `agents.<name>.disabled` | boolean | `false` | Disable specific shadow |
|
|
159
|
+
| `output_shaping.max_chars` | number | `12000` | Max output length before truncation |
|
|
160
|
+
| `output_shaping.preserve_errors` | boolean | `true` | Never truncate error outputs |
|
|
161
|
+
| `compaction.threshold_percent` | number | `80` | Context threshold for compaction |
|
|
162
|
+
| `compaction.preserve_todos` | boolean | `true` | Keep TODOs during compaction |
|
|
163
|
+
|
|
164
|
+
### Project-Level Config
|
|
165
|
+
|
|
166
|
+
You can also create `.opencode/opencode-arise.json` in your project root. Project config merges with (and overrides) global config.
|
|
167
|
+
|
|
168
|
+
## Default Models
|
|
169
|
+
|
|
170
|
+
| Shadow | Default Model |
|
|
171
|
+
|--------|---------------|
|
|
172
|
+
| monarch | `opencode/opus-4.5` |
|
|
173
|
+
| beru | `opencode/glm-4.7` |
|
|
174
|
+
| igris | `opencode/glm-4.7` |
|
|
175
|
+
| bellion | `opencode/opus-4.5` |
|
|
176
|
+
| tusk | `opencode/opus-4.5` |
|
|
177
|
+
| tank | `opencode/glm-4.7` |
|
|
178
|
+
| shadow-sovereign | `openai/gpt-5.2` (high reasoning) |
|
|
179
|
+
|
|
180
|
+
## Examples
|
|
181
|
+
|
|
182
|
+
### Parallel Codebase Exploration
|
|
183
|
+
|
|
184
|
+
```
|
|
185
|
+
You: "I need to understand how authentication works and find security best practices"
|
|
186
|
+
|
|
187
|
+
Monarch: *launches beru (codebase) and tank (research) in background*
|
|
188
|
+
"Beru is exploring the auth implementation while Tank researches
|
|
189
|
+
security best practices. I'll compile their findings."
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
### Complex Refactoring
|
|
193
|
+
|
|
194
|
+
```
|
|
195
|
+
You: "Refactor the payment module to use the new Stripe API"
|
|
196
|
+
|
|
197
|
+
Monarch: "This requires planning. Let me consult Bellion first."
|
|
198
|
+
|
|
199
|
+
Bellion: *analyzes codebase, creates migration plan*
|
|
200
|
+
|
|
201
|
+
Monarch: "Bellion's plan looks good. Igris will implement it step by step."
|
|
202
|
+
|
|
203
|
+
Igris: *implements changes, runs tests after each step*
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
### Deep Debugging
|
|
207
|
+
|
|
208
|
+
```
|
|
209
|
+
You: "This async function is causing race conditions but I can't figure out why"
|
|
210
|
+
|
|
211
|
+
Monarch: "This needs deep analysis. Summoning the Shadow Sovereign."
|
|
212
|
+
|
|
213
|
+
Shadow-Sovereign: *deep reasoning analysis*
|
|
214
|
+
"The issue is a closure capturing a stale reference..."
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
## Uninstall
|
|
218
|
+
|
|
219
|
+
Remove from OpenCode config:
|
|
220
|
+
|
|
221
|
+
```bash
|
|
222
|
+
# Edit ~/.config/opencode/opencode.json
|
|
223
|
+
# Remove "opencode-arise" from the "plugin" array
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
Or manually:
|
|
227
|
+
```bash
|
|
228
|
+
# Remove config
|
|
229
|
+
rm ~/.config/opencode/opencode-arise.json
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
## Requirements
|
|
233
|
+
|
|
234
|
+
- [OpenCode](https://opencode.ai) CLI installed
|
|
235
|
+
- [Bun](https://bun.sh) runtime (v1.0.0+)
|
|
236
|
+
|
|
237
|
+
## Philosophy
|
|
238
|
+
|
|
239
|
+
- **Minimal sufficient delegation** - Don't over-delegate simple tasks
|
|
240
|
+
- **Parallel exploration** - Use background tasks for concurrent scouting
|
|
241
|
+
- **Quality-safe truncation** - Never lose errors, tracebacks, or critical output
|
|
242
|
+
- **Token efficiency** - Lean prompts, smart delegation patterns
|
|
243
|
+
|
|
244
|
+
## Contributing
|
|
245
|
+
|
|
246
|
+
Contributions are welcome! Please read the contributing guidelines first.
|
|
247
|
+
|
|
248
|
+
```bash
|
|
249
|
+
# Clone the repo
|
|
250
|
+
git clone https://github.com/moinulmoin/opencode-arise.git
|
|
251
|
+
cd opencode-arise
|
|
252
|
+
|
|
253
|
+
# Install dependencies
|
|
254
|
+
bun install
|
|
255
|
+
|
|
256
|
+
# Run tests
|
|
257
|
+
bun test
|
|
258
|
+
|
|
259
|
+
# Build
|
|
260
|
+
bun run build
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
## License
|
|
264
|
+
|
|
265
|
+
[MIT](LICENSE) © moinulmoin
|
|
266
|
+
|
|
267
|
+
---
|
|
268
|
+
|
|
269
|
+
<p align="center">
|
|
270
|
+
<i>"I alone level up."</i> - Sung Jinwoo
|
|
271
|
+
</p>
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
|
|
2
|
+
╔═══════════════════════════════════════════════════════╗
|
|
3
|
+
║ ║
|
|
4
|
+
║ ⚔️ A R I S E ! ⚔️ ║
|
|
5
|
+
║ ║
|
|
6
|
+
║ ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ ║
|
|
7
|
+
║ ░░ Shadow Army Assembled ░░░ ║
|
|
8
|
+
║ ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ ║
|
|
9
|
+
║ ║
|
|
10
|
+
║ Monarch ready. Shadows await your command. ║
|
|
11
|
+
║ ║
|
|
12
|
+
╚═══════════════════════════════════════════════════════╝
|
|
13
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { SHADOW_AGENTS, OPENCODE_OVERRIDES, type ShadowAgent } from "./shadows";
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export interface ShadowAgent {
|
|
2
|
+
name: string;
|
|
3
|
+
description: string;
|
|
4
|
+
mode: "primary" | "subagent" | "all";
|
|
5
|
+
model: string;
|
|
6
|
+
steps: number;
|
|
7
|
+
prompt?: string;
|
|
8
|
+
permission?: Record<string, "allow" | "deny" | "ask">;
|
|
9
|
+
options?: Record<string, unknown>;
|
|
10
|
+
}
|
|
11
|
+
export declare const SHADOW_AGENTS: Record<string, ShadowAgent>;
|
|
12
|
+
export declare const OPENCODE_OVERRIDES: {
|
|
13
|
+
build: {
|
|
14
|
+
mode: "all";
|
|
15
|
+
model: string;
|
|
16
|
+
};
|
|
17
|
+
plan: {
|
|
18
|
+
mode: "all";
|
|
19
|
+
model: string;
|
|
20
|
+
};
|
|
21
|
+
explore: {
|
|
22
|
+
description: string;
|
|
23
|
+
hidden: boolean;
|
|
24
|
+
};
|
|
25
|
+
general: {
|
|
26
|
+
hidden: boolean;
|
|
27
|
+
};
|
|
28
|
+
};
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
// @bun
|
|
3
|
+
|
|
4
|
+
// src/cli/index.ts
|
|
5
|
+
import { existsSync, readFileSync, writeFileSync, mkdirSync } from "fs";
|
|
6
|
+
import { join } from "path";
|
|
7
|
+
|
|
8
|
+
// src/hooks/arise-banner.ts
|
|
9
|
+
var BANNER_ASCII = `
|
|
10
|
+
\u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557
|
|
11
|
+
\u2551 \u2551
|
|
12
|
+
\u2551 \u2694\uFE0F A R I S E ! \u2694\uFE0F \u2551
|
|
13
|
+
\u2551 \u2551
|
|
14
|
+
\u2551 \u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591 \u2551
|
|
15
|
+
\u2551 \u2591\u2591 Shadow Army Assembled \u2591\u2591\u2591 \u2551
|
|
16
|
+
\u2551 \u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591 \u2551
|
|
17
|
+
\u2551 \u2551
|
|
18
|
+
\u2551 Monarch ready. Shadows await your command. \u2551
|
|
19
|
+
\u2551 \u2551
|
|
20
|
+
\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D
|
|
21
|
+
`;
|
|
22
|
+
function getBanner() {
|
|
23
|
+
return BANNER_ASCII;
|
|
24
|
+
}
|
|
25
|
+
// src/cli/index.ts
|
|
26
|
+
var PLUGIN_NAME = "opencode-arise";
|
|
27
|
+
var OPENCODE_CONFIG_PATHS = [
|
|
28
|
+
join(process.env.HOME ?? "", ".config/opencode/opencode.json"),
|
|
29
|
+
join(process.env.HOME ?? "", ".config/opencode/opencode.jsonc")
|
|
30
|
+
];
|
|
31
|
+
function findOpencodeConfig() {
|
|
32
|
+
for (const path of OPENCODE_CONFIG_PATHS) {
|
|
33
|
+
if (existsSync(path))
|
|
34
|
+
return path;
|
|
35
|
+
}
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
function parseJsonc(content) {
|
|
39
|
+
let cleaned = content.replace(/\/\/.*$/gm, "").replace(/\/\*[\s\S]*?\*\//g, "").replace(/,(\s*[}\]])/g, "$1");
|
|
40
|
+
return JSON.parse(cleaned);
|
|
41
|
+
}
|
|
42
|
+
function addPluginToConfig(configPath) {
|
|
43
|
+
try {
|
|
44
|
+
const content = readFileSync(configPath, "utf-8");
|
|
45
|
+
const config = parseJsonc(content);
|
|
46
|
+
if (!config.plugin) {
|
|
47
|
+
config.plugin = [];
|
|
48
|
+
}
|
|
49
|
+
const plugins = config.plugin;
|
|
50
|
+
if (plugins.includes(PLUGIN_NAME)) {
|
|
51
|
+
console.log(`\u2713 ${PLUGIN_NAME} already registered in OpenCode config`);
|
|
52
|
+
return true;
|
|
53
|
+
}
|
|
54
|
+
plugins.push(PLUGIN_NAME);
|
|
55
|
+
const newContent = JSON.stringify(config, null, 2);
|
|
56
|
+
writeFileSync(configPath, newContent, "utf-8");
|
|
57
|
+
console.log(`\u2713 Added ${PLUGIN_NAME} to ${configPath}`);
|
|
58
|
+
return true;
|
|
59
|
+
} catch (err) {
|
|
60
|
+
console.error(`\u2717 Failed to update config:`, err);
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
function createDefaultAriseConfig() {
|
|
65
|
+
const configDir = join(process.env.HOME ?? "", ".config/opencode");
|
|
66
|
+
const configPath = join(configDir, "opencode-arise.json");
|
|
67
|
+
if (existsSync(configPath)) {
|
|
68
|
+
console.log(`\u2713 opencode-arise.json already exists`);
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
const defaultConfig = {
|
|
72
|
+
$schema: "https://raw.githubusercontent.com/your-repo/opencode-arise/main/assets/opencode-arise.schema.json",
|
|
73
|
+
show_banner: true,
|
|
74
|
+
disabled_shadows: [],
|
|
75
|
+
disabled_hooks: []
|
|
76
|
+
};
|
|
77
|
+
try {
|
|
78
|
+
if (!existsSync(configDir)) {
|
|
79
|
+
mkdirSync(configDir, { recursive: true });
|
|
80
|
+
}
|
|
81
|
+
writeFileSync(configPath, JSON.stringify(defaultConfig, null, 2), "utf-8");
|
|
82
|
+
console.log(`\u2713 Created default config at ${configPath}`);
|
|
83
|
+
} catch (err) {
|
|
84
|
+
console.error(`\u2717 Failed to create config:`, err);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
function install() {
|
|
88
|
+
console.log(getBanner());
|
|
89
|
+
console.log(`
|
|
90
|
+
\uD83C\uDF11 Installing opencode-arise...
|
|
91
|
+
`);
|
|
92
|
+
const configPath = findOpencodeConfig();
|
|
93
|
+
if (!configPath) {
|
|
94
|
+
console.error("\u2717 OpenCode config not found. Is OpenCode installed?");
|
|
95
|
+
console.error(" Expected: ~/.config/opencode/opencode.json");
|
|
96
|
+
process.exit(1);
|
|
97
|
+
}
|
|
98
|
+
const success = addPluginToConfig(configPath);
|
|
99
|
+
if (!success) {
|
|
100
|
+
process.exit(1);
|
|
101
|
+
}
|
|
102
|
+
createDefaultAriseConfig();
|
|
103
|
+
console.log(`
|
|
104
|
+
\u2694\uFE0F Installation complete!`);
|
|
105
|
+
console.log(`
|
|
106
|
+
The Shadow Army awaits. Run 'opencode' to begin.
|
|
107
|
+
`);
|
|
108
|
+
console.log(" Shadows available:");
|
|
109
|
+
console.log(" @beru - Fast codebase scout (Ant King)");
|
|
110
|
+
console.log(" @igris - Precise implementation (Loyal Knight)");
|
|
111
|
+
console.log(" @bellion - Strategic planning (Grand Marshal)");
|
|
112
|
+
console.log(" @tusk - UI/UX specialist");
|
|
113
|
+
console.log(" @tank - External research");
|
|
114
|
+
console.log(" @shadow-sovereign - Deep reasoning (Full Power)");
|
|
115
|
+
console.log("");
|
|
116
|
+
}
|
|
117
|
+
function doctor() {
|
|
118
|
+
console.log(`\uD83D\uDD0D Checking opencode-arise installation...
|
|
119
|
+
`);
|
|
120
|
+
const configPath = findOpencodeConfig();
|
|
121
|
+
if (!configPath) {
|
|
122
|
+
console.log("\u2717 OpenCode config not found");
|
|
123
|
+
process.exit(1);
|
|
124
|
+
}
|
|
125
|
+
console.log(`\u2713 OpenCode config: ${configPath}`);
|
|
126
|
+
try {
|
|
127
|
+
const content = readFileSync(configPath, "utf-8");
|
|
128
|
+
const config = parseJsonc(content);
|
|
129
|
+
const plugins = config.plugin ?? [];
|
|
130
|
+
if (plugins.includes(PLUGIN_NAME)) {
|
|
131
|
+
console.log(`\u2713 ${PLUGIN_NAME} is registered`);
|
|
132
|
+
} else {
|
|
133
|
+
console.log(`\u2717 ${PLUGIN_NAME} is NOT registered`);
|
|
134
|
+
console.log(` Run: bunx ${PLUGIN_NAME} install`);
|
|
135
|
+
}
|
|
136
|
+
} catch (err) {
|
|
137
|
+
console.log(`\u2717 Failed to read config:`, err);
|
|
138
|
+
}
|
|
139
|
+
const ariseConfigPath = join(process.env.HOME ?? "", ".config/opencode/opencode-arise.json");
|
|
140
|
+
if (existsSync(ariseConfigPath)) {
|
|
141
|
+
console.log(`\u2713 opencode-arise.json exists`);
|
|
142
|
+
} else {
|
|
143
|
+
console.log(`\u25CB opencode-arise.json not found (optional)`);
|
|
144
|
+
}
|
|
145
|
+
console.log(`
|
|
146
|
+
\u2705 Doctor check complete`);
|
|
147
|
+
}
|
|
148
|
+
function showHelp() {
|
|
149
|
+
console.log(`
|
|
150
|
+
${getBanner()}
|
|
151
|
+
Usage: opencode-arise <command>
|
|
152
|
+
|
|
153
|
+
Commands:
|
|
154
|
+
install Register plugin with OpenCode and create default config
|
|
155
|
+
doctor Check installation status
|
|
156
|
+
help Show this help message
|
|
157
|
+
|
|
158
|
+
Examples:
|
|
159
|
+
bunx opencode-arise install
|
|
160
|
+
npx opencode-arise install
|
|
161
|
+
`);
|
|
162
|
+
}
|
|
163
|
+
var args = process.argv.slice(2);
|
|
164
|
+
var command = args[0];
|
|
165
|
+
switch (command) {
|
|
166
|
+
case "install":
|
|
167
|
+
install();
|
|
168
|
+
break;
|
|
169
|
+
case "doctor":
|
|
170
|
+
doctor();
|
|
171
|
+
break;
|
|
172
|
+
case "help":
|
|
173
|
+
case "--help":
|
|
174
|
+
case "-h":
|
|
175
|
+
showHelp();
|
|
176
|
+
break;
|
|
177
|
+
default:
|
|
178
|
+
if (command) {
|
|
179
|
+
console.error(`Unknown command: ${command}`);
|
|
180
|
+
}
|
|
181
|
+
showHelp();
|
|
182
|
+
process.exit(command ? 1 : 0);
|
|
183
|
+
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export declare const ShadowName: z.ZodEnum<["monarch", "beru", "igris", "bellion", "tusk", "tank", "shadow-sovereign"]>;
|
|
3
|
+
export type ShadowName = z.infer<typeof ShadowName>;
|
|
4
|
+
export declare const HookName: z.ZodEnum<["arise-banner", "output-shaper", "compaction-preserver", "todo-enforcer"]>;
|
|
5
|
+
export type HookName = z.infer<typeof HookName>;
|
|
6
|
+
export declare const AgentOverride: z.ZodObject<{
|
|
7
|
+
model: z.ZodOptional<z.ZodString>;
|
|
8
|
+
disabled: z.ZodOptional<z.ZodBoolean>;
|
|
9
|
+
}, "strip", z.ZodTypeAny, {
|
|
10
|
+
model?: string | undefined;
|
|
11
|
+
disabled?: boolean | undefined;
|
|
12
|
+
}, {
|
|
13
|
+
model?: string | undefined;
|
|
14
|
+
disabled?: boolean | undefined;
|
|
15
|
+
}>;
|
|
16
|
+
export declare const AriseConfigSchema: z.ZodObject<{
|
|
17
|
+
$schema: z.ZodOptional<z.ZodString>;
|
|
18
|
+
disabled_shadows: z.ZodOptional<z.ZodArray<z.ZodEnum<["monarch", "beru", "igris", "bellion", "tusk", "tank", "shadow-sovereign"]>, "many">>;
|
|
19
|
+
disabled_hooks: z.ZodOptional<z.ZodArray<z.ZodEnum<["arise-banner", "output-shaper", "compaction-preserver", "todo-enforcer"]>, "many">>;
|
|
20
|
+
show_banner: z.ZodDefault<z.ZodBoolean>;
|
|
21
|
+
banner_every_session: z.ZodDefault<z.ZodBoolean>;
|
|
22
|
+
agents: z.ZodOptional<z.ZodRecord<z.ZodEnum<["monarch", "beru", "igris", "bellion", "tusk", "tank", "shadow-sovereign"]>, z.ZodObject<{
|
|
23
|
+
model: z.ZodOptional<z.ZodString>;
|
|
24
|
+
disabled: z.ZodOptional<z.ZodBoolean>;
|
|
25
|
+
}, "strip", z.ZodTypeAny, {
|
|
26
|
+
model?: string | undefined;
|
|
27
|
+
disabled?: boolean | undefined;
|
|
28
|
+
}, {
|
|
29
|
+
model?: string | undefined;
|
|
30
|
+
disabled?: boolean | undefined;
|
|
31
|
+
}>>>;
|
|
32
|
+
output_shaping: z.ZodOptional<z.ZodObject<{
|
|
33
|
+
max_chars: z.ZodDefault<z.ZodNumber>;
|
|
34
|
+
preserve_errors: z.ZodDefault<z.ZodBoolean>;
|
|
35
|
+
}, "strip", z.ZodTypeAny, {
|
|
36
|
+
max_chars: number;
|
|
37
|
+
preserve_errors: boolean;
|
|
38
|
+
}, {
|
|
39
|
+
max_chars?: number | undefined;
|
|
40
|
+
preserve_errors?: boolean | undefined;
|
|
41
|
+
}>>;
|
|
42
|
+
compaction: z.ZodOptional<z.ZodObject<{
|
|
43
|
+
threshold_percent: z.ZodDefault<z.ZodNumber>;
|
|
44
|
+
preserve_todos: z.ZodDefault<z.ZodBoolean>;
|
|
45
|
+
}, "strip", z.ZodTypeAny, {
|
|
46
|
+
threshold_percent: number;
|
|
47
|
+
preserve_todos: boolean;
|
|
48
|
+
}, {
|
|
49
|
+
threshold_percent?: number | undefined;
|
|
50
|
+
preserve_todos?: boolean | undefined;
|
|
51
|
+
}>>;
|
|
52
|
+
}, "strip", z.ZodTypeAny, {
|
|
53
|
+
show_banner: boolean;
|
|
54
|
+
banner_every_session: boolean;
|
|
55
|
+
$schema?: string | undefined;
|
|
56
|
+
disabled_shadows?: ("monarch" | "beru" | "igris" | "bellion" | "tusk" | "tank" | "shadow-sovereign")[] | undefined;
|
|
57
|
+
disabled_hooks?: ("arise-banner" | "output-shaper" | "compaction-preserver" | "todo-enforcer")[] | undefined;
|
|
58
|
+
agents?: Partial<Record<"monarch" | "beru" | "igris" | "bellion" | "tusk" | "tank" | "shadow-sovereign", {
|
|
59
|
+
model?: string | undefined;
|
|
60
|
+
disabled?: boolean | undefined;
|
|
61
|
+
}>> | undefined;
|
|
62
|
+
output_shaping?: {
|
|
63
|
+
max_chars: number;
|
|
64
|
+
preserve_errors: boolean;
|
|
65
|
+
} | undefined;
|
|
66
|
+
compaction?: {
|
|
67
|
+
threshold_percent: number;
|
|
68
|
+
preserve_todos: boolean;
|
|
69
|
+
} | undefined;
|
|
70
|
+
}, {
|
|
71
|
+
$schema?: string | undefined;
|
|
72
|
+
disabled_shadows?: ("monarch" | "beru" | "igris" | "bellion" | "tusk" | "tank" | "shadow-sovereign")[] | undefined;
|
|
73
|
+
disabled_hooks?: ("arise-banner" | "output-shaper" | "compaction-preserver" | "todo-enforcer")[] | undefined;
|
|
74
|
+
show_banner?: boolean | undefined;
|
|
75
|
+
banner_every_session?: boolean | undefined;
|
|
76
|
+
agents?: Partial<Record<"monarch" | "beru" | "igris" | "bellion" | "tusk" | "tank" | "shadow-sovereign", {
|
|
77
|
+
model?: string | undefined;
|
|
78
|
+
disabled?: boolean | undefined;
|
|
79
|
+
}>> | undefined;
|
|
80
|
+
output_shaping?: {
|
|
81
|
+
max_chars?: number | undefined;
|
|
82
|
+
preserve_errors?: boolean | undefined;
|
|
83
|
+
} | undefined;
|
|
84
|
+
compaction?: {
|
|
85
|
+
threshold_percent?: number | undefined;
|
|
86
|
+
preserve_todos?: boolean | undefined;
|
|
87
|
+
} | undefined;
|
|
88
|
+
}>;
|
|
89
|
+
export type AriseConfig = z.infer<typeof AriseConfigSchema>;
|
|
90
|
+
export declare const DEFAULT_CONFIG: AriseConfig;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { createAriseBannerHook, getBanner, printBannerToConsole } from "./arise-banner";
|
|
2
|
+
export { createOutputShaperHook } from "./output-shaper";
|
|
3
|
+
export { createTodoEnforcerHook } from "./todo-enforcer";
|
|
4
|
+
export { createCompactionPreserverHook } from "./compaction-preserver";
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { PluginInput } from "@opencode-ai/plugin";
|
|
2
|
+
export declare function createTodoEnforcerHook(_ctx: PluginInput): {
|
|
3
|
+
checkCompletion(messages: Array<{
|
|
4
|
+
content: string;
|
|
5
|
+
}>): Promise<{
|
|
6
|
+
hasIncompleteTodos: boolean;
|
|
7
|
+
reminderMessage?: string;
|
|
8
|
+
}>;
|
|
9
|
+
};
|