oh-my-opencode-slim 0.3.5 → 0.3.7
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/README.md +96 -108
- package/dist/agents/coder.d.ts +2 -0
- package/dist/agents/index.d.ts +0 -40
- package/dist/agents/orchestrator.d.ts +2 -2
- package/dist/agents/scribe.d.ts +2 -0
- package/dist/cli/config-manager.d.ts +4 -0
- package/dist/cli/index.js +29 -63
- package/dist/config/schema.d.ts +2 -0
- package/dist/features/background-manager.d.ts +3 -1
- package/dist/index.js +371 -231
- package/dist/tools/background.d.ts +2 -1
- package/dist/utils/agent-variant.d.ts +6 -0
- package/dist/utils/index.d.ts +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
|
|
13
13
|
> Slimmed-down fork of [oh-my-opencode](https://github.com/code-yeongyu/oh-my-opencode) - focused on core agent orchestration without the extra bells and whistles.
|
|
14
14
|
|
|
15
|
-
> **[Antigravity](https://antigravity.
|
|
15
|
+
> **[Antigravity](https://antigravity.google) subscription recommended.** The pantheon is tuned for Antigravity's model routing. Other providers work, but you'll get the best experience with Antigravity.
|
|
16
16
|
|
|
17
17
|
---
|
|
18
18
|
|
|
@@ -23,24 +23,14 @@
|
|
|
23
23
|
- [For LLM Agents](#for-llm-agents)
|
|
24
24
|
- [🏗️ **Architecture & Flow**](#architecture--flow)
|
|
25
25
|
- [🏛️ **Meet the Pantheon**](#meet-the-pantheon)
|
|
26
|
-
- [Orchestrator](#orchestrator)
|
|
27
|
-
- [Explorer](#explorer)
|
|
28
|
-
- [Oracle](#oracle)
|
|
29
|
-
- [Librarian](#librarian)
|
|
30
|
-
- [Frontend Designer](#frontend-designer)
|
|
31
|
-
- [Document Writer](#document-writer)
|
|
32
|
-
- [Multimodal Viewer](#multimodal-viewer)
|
|
33
|
-
- [Code Simplifier](#code-simplifier)
|
|
34
26
|
- [🛠️ **Tools & Capabilities**](#tools--capabilities)
|
|
35
|
-
- [Tmux Integration](#tmux-integration)
|
|
36
|
-
- [Quota Tool](#quota-tool)
|
|
37
|
-
- [Background Tasks](#background-tasks)
|
|
38
|
-
- [LSP Tools](#lsp-tools)
|
|
39
|
-
- [Code Search Tools](#code-search-tools)
|
|
40
27
|
- [🧩 **Skills**](#-skills)
|
|
41
|
-
|
|
42
|
-
- [
|
|
43
|
-
- [
|
|
28
|
+
- [⚙️ **Configuration Guide**](#configuration-guide)
|
|
29
|
+
- [Locations & Precedence](#locations--precedence)
|
|
30
|
+
- [General Settings](#general-settings)
|
|
31
|
+
- [Agent Configuration](#agent-configuration)
|
|
32
|
+
- [Tmux Setup](#tmux-setup)
|
|
33
|
+
- [MCP Management](#mcp-management)
|
|
44
34
|
- [🗑️ **Uninstallation**](#uninstallation)
|
|
45
35
|
|
|
46
36
|
---
|
|
@@ -350,71 +340,6 @@ Identify unnecessary complexity, challenge premature abstractions, estimate LOC
|
|
|
350
340
|
- **Auto-Cleanup**: Panes close when agents finish, layout rebalances
|
|
351
341
|
- **Zero Overhead**: Works with OpenCode's built-in `task` tool AND our `background_task` tool
|
|
352
342
|
|
|
353
|
-
#### Quick Setup
|
|
354
|
-
|
|
355
|
-
**1. Enable the OpenCode HTTP server** (one-time setup)
|
|
356
|
-
|
|
357
|
-
Add to your `~/.config/opencode/opencode.json`:
|
|
358
|
-
|
|
359
|
-
```json
|
|
360
|
-
{
|
|
361
|
-
"server": {
|
|
362
|
-
"port": 4096
|
|
363
|
-
}
|
|
364
|
-
}
|
|
365
|
-
```
|
|
366
|
-
|
|
367
|
-
**2. Enable tmux integration in the plugin**
|
|
368
|
-
|
|
369
|
-
Add to your `~/.config/opencode/oh-my-opencode-slim.json`:
|
|
370
|
-
|
|
371
|
-
```json
|
|
372
|
-
{
|
|
373
|
-
"tmux": {
|
|
374
|
-
"enabled": true,
|
|
375
|
-
"layout": "main-vertical",
|
|
376
|
-
"main_pane_size": 60
|
|
377
|
-
}
|
|
378
|
-
}
|
|
379
|
-
```
|
|
380
|
-
|
|
381
|
-
**3. Run OpenCode inside tmux**
|
|
382
|
-
|
|
383
|
-
```bash
|
|
384
|
-
tmux
|
|
385
|
-
opencode
|
|
386
|
-
```
|
|
387
|
-
|
|
388
|
-
That's it. When agents spawn, they'll appear in new panes.
|
|
389
|
-
|
|
390
|
-
#### Layout Options
|
|
391
|
-
|
|
392
|
-
| Layout | Description |
|
|
393
|
-
|--------|-------------|
|
|
394
|
-
| `main-vertical` | Your session on the left (60%), agents stacked on the right |
|
|
395
|
-
| `main-horizontal` | Your session on top (60%), agents stacked below |
|
|
396
|
-
| `tiled` | All panes in equal-sized grid |
|
|
397
|
-
| `even-horizontal` | All panes side by side |
|
|
398
|
-
| `even-vertical` | All panes stacked vertically |
|
|
399
|
-
|
|
400
|
-
#### Configuration Reference
|
|
401
|
-
|
|
402
|
-
```json
|
|
403
|
-
{
|
|
404
|
-
"tmux": {
|
|
405
|
-
"enabled": true,
|
|
406
|
-
"layout": "main-vertical",
|
|
407
|
-
"main_pane_size": 60
|
|
408
|
-
}
|
|
409
|
-
}
|
|
410
|
-
```
|
|
411
|
-
|
|
412
|
-
| Option | Type | Default | Description |
|
|
413
|
-
|--------|------|---------|-------------|
|
|
414
|
-
| `enabled` | boolean | `false` | Enable/disable tmux integration |
|
|
415
|
-
| `layout` | string | `"main-vertical"` | Tmux layout preset |
|
|
416
|
-
| `main_pane_size` | number | `60` | Size of main pane as percentage (20-80) |
|
|
417
|
-
|
|
418
343
|
---
|
|
419
344
|
|
|
420
345
|
### Quota Tool
|
|
@@ -431,7 +356,6 @@ For Antigravity users. You can trigger this at any time by asking the agent to *
|
|
|
431
356
|
|
|
432
357
|
### Background Tasks
|
|
433
358
|
|
|
434
|
-
|
|
435
359
|
The plugin provides tools to manage asynchronous work:
|
|
436
360
|
|
|
437
361
|
| Tool | Description |
|
|
@@ -487,60 +411,124 @@ Skills are specialized capabilities that combine MCP servers with specific instr
|
|
|
487
411
|
|
|
488
412
|
---
|
|
489
413
|
|
|
490
|
-
##
|
|
414
|
+
## ⚙️ Configuration Guide
|
|
491
415
|
|
|
492
|
-
|
|
416
|
+
The Pantheon listens to your commands through sacred JSON scriptures. Here is how you shape their behavior.
|
|
493
417
|
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
|
418
|
+
### Locations & Precedence
|
|
419
|
+
|
|
420
|
+
The plugin merges configuration from two locations. Settings in the **Project Local** file override those in the **User Global** file.
|
|
421
|
+
|
|
422
|
+
| Level | Path | Scope |
|
|
423
|
+
| :--- | :--- | :--- |
|
|
424
|
+
| **User Global** | `~/.config/opencode/oh-my-opencode-slim.json` | All projects for this user |
|
|
425
|
+
| **Project Local** | `./.opencode/oh-my-opencode-slim.json` | This specific repository |
|
|
426
|
+
|
|
427
|
+
> **Note for Windows Users:** The global config is located at `%APPDATA%\opencode\oh-my-opencode-slim.json` or `~/.config/opencode/oh-my-opencode-slim.json`.
|
|
499
428
|
|
|
500
|
-
|
|
429
|
+
---
|
|
430
|
+
|
|
431
|
+
### General Settings
|
|
501
432
|
|
|
502
|
-
|
|
433
|
+
#### OpenCode Server
|
|
434
|
+
To enable certain integrations (like Tmux), you must first enable the OpenCode HTTP server in your main `opencode.json` file.
|
|
503
435
|
|
|
436
|
+
**File:** `~/.config/opencode/opencode.json`
|
|
504
437
|
```json
|
|
505
438
|
{
|
|
506
|
-
"
|
|
439
|
+
"server": {
|
|
440
|
+
"port": 4096
|
|
441
|
+
}
|
|
507
442
|
}
|
|
508
443
|
```
|
|
509
444
|
|
|
510
445
|
---
|
|
511
446
|
|
|
512
|
-
|
|
447
|
+
### Agent Configuration
|
|
448
|
+
|
|
449
|
+
You can customize the underlying LLM and reasoning effort for each deity in the Pantheon.
|
|
450
|
+
|
|
451
|
+
**File:** `oh-my-opencode-slim.json`
|
|
452
|
+
```json
|
|
453
|
+
{
|
|
454
|
+
"agents": {
|
|
455
|
+
"orchestrator": {
|
|
456
|
+
"model": "openai/gpt-5.2-codex",
|
|
457
|
+
"variant": "high"
|
|
458
|
+
},
|
|
459
|
+
"explore": {
|
|
460
|
+
"model": "opencode/glm-4.7",
|
|
461
|
+
"variant": "low"
|
|
462
|
+
}
|
|
463
|
+
},
|
|
464
|
+
"disabled_agents": ["multimodal-looker", "code-simplicity-reviewer"]
|
|
465
|
+
}
|
|
466
|
+
```
|
|
467
|
+
|
|
468
|
+
#### Agent Settings Reference
|
|
469
|
+
| Option | Type | Default | Description |
|
|
470
|
+
|--------|------|---------|-------------|
|
|
471
|
+
| `agents.<name>.model` | string | *Varies* | Override the LLM for a specific agent |
|
|
472
|
+
| `agents.<name>.variant` | string | `"medium"` | Reasoning level (`low`, `medium`, `high`) |
|
|
473
|
+
| `disabled_agents` | array | `[]` | List of agents to completely deactivate |
|
|
474
|
+
|
|
475
|
+
---
|
|
476
|
+
|
|
477
|
+
### Tmux Setup
|
|
478
|
+
|
|
479
|
+
Watch your agents work in real-time by enabling the Tmux integration. This requires the [OpenCode Server](#opencode-server) to be active.
|
|
480
|
+
|
|
481
|
+
**File:** `oh-my-opencode-slim.json`
|
|
482
|
+
```json
|
|
483
|
+
{
|
|
484
|
+
"tmux": {
|
|
485
|
+
"enabled": true,
|
|
486
|
+
"layout": "main-vertical",
|
|
487
|
+
"main_pane_size": 60
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
```
|
|
513
491
|
|
|
514
|
-
|
|
492
|
+
#### Tmux Settings Reference
|
|
493
|
+
| Option | Type | Default | Description |
|
|
494
|
+
|--------|------|---------|-------------|
|
|
495
|
+
| `enabled` | boolean | `false` | Enable/disable tmux integration |
|
|
496
|
+
| `layout` | string | `"main-vertical"` | Layout preset (see below) |
|
|
497
|
+
| `main_pane_size` | number | `60` | Size of main session pane as % (20-80) |
|
|
515
498
|
|
|
516
|
-
|
|
499
|
+
**Available Layouts:**
|
|
500
|
+
- `main-vertical`: Main session left, agents stacked right.
|
|
501
|
+
- `main-horizontal`: Main session top, agents stacked below.
|
|
502
|
+
- `tiled`: Equal-sized grid.
|
|
503
|
+
- `even-horizontal` / `even-vertical`: Evenly distributed panes.
|
|
517
504
|
|
|
518
|
-
|
|
505
|
+
---
|
|
519
506
|
|
|
520
|
-
|
|
521
|
-
2. **Project Local**: `./.opencode/oh-my-opencode-slim.json`
|
|
507
|
+
### MCP Management
|
|
522
508
|
|
|
523
|
-
|
|
524
|
-
| :--- | :--- |
|
|
525
|
-
| **Windows** | `~/.config/opencode/oh-my-opencode-slim.json` or `%APPDATA%\opencode\oh-my-opencode-slim.json` |
|
|
526
|
-
| **macOS/Linux** | `~/.config/opencode/oh-my-opencode-slim.json` |
|
|
509
|
+
The Pantheon comes equipped with built-in Model Context Protocol (MCP) servers.
|
|
527
510
|
|
|
528
|
-
|
|
511
|
+
| MCP | Purpose | URL |
|
|
512
|
+
|-----|---------|-----|
|
|
513
|
+
| `websearch` | Real-time web search via Exa AI | `https://mcp.exa.ai/mcp` |
|
|
514
|
+
| `context7` | Official library documentation | `https://mcp.context7.com/mcp` |
|
|
515
|
+
| `grep_app` | GitHub code search via grep.app | `https://mcp.grep.app` |
|
|
529
516
|
|
|
530
|
-
|
|
517
|
+
#### Disabling MCPs
|
|
518
|
+
If you wish to silence an MCP server, add it to the `disabled_mcps` array in your config:
|
|
531
519
|
|
|
520
|
+
**File:** `oh-my-opencode-slim.json`
|
|
532
521
|
```json
|
|
533
522
|
{
|
|
534
|
-
"
|
|
523
|
+
"disabled_mcps": ["websearch", "grep_app"]
|
|
535
524
|
}
|
|
536
525
|
```
|
|
537
526
|
|
|
538
527
|
---
|
|
539
528
|
|
|
540
|
-
## Uninstallation
|
|
529
|
+
## 🗑️ Uninstallation
|
|
541
530
|
|
|
542
531
|
1. **Remove the plugin from your OpenCode config**:
|
|
543
|
-
|
|
544
532
|
Edit `~/.config/opencode/opencode.json` and remove `"oh-my-opencode-slim"` from the `plugin` array.
|
|
545
533
|
|
|
546
534
|
2. **Remove configuration files (optional)**:
|
package/dist/agents/index.d.ts
CHANGED
|
@@ -1,48 +1,8 @@
|
|
|
1
1
|
import type { AgentConfig as SDKAgentConfig } from "@opencode-ai/sdk";
|
|
2
2
|
import { type AgentName, type PluginConfig } from "../config";
|
|
3
3
|
import { type AgentDefinition } from "./orchestrator";
|
|
4
|
-
import { createOracleAgent } from "./oracle";
|
|
5
|
-
import { createLibrarianAgent } from "./librarian";
|
|
6
|
-
import { createExploreAgent } from "./explore";
|
|
7
|
-
import { createFrontendAgent } from "./frontend";
|
|
8
|
-
import { createDocumentWriterAgent } from "./document-writer";
|
|
9
|
-
import { createMultimodalAgent } from "./multimodal";
|
|
10
|
-
import { createSimplicityReviewerAgent } from "./simplicity-reviewer";
|
|
11
4
|
export type { AgentDefinition } from "./orchestrator";
|
|
12
5
|
type SubagentName = Exclude<AgentName, "orchestrator">;
|
|
13
|
-
/** Short descriptions for each subagent (used in tool descriptions) */
|
|
14
|
-
export declare const SUBAGENT_INFO: {
|
|
15
|
-
readonly explore: {
|
|
16
|
-
readonly factory: typeof createExploreAgent;
|
|
17
|
-
readonly shortDesc: "codebase grep";
|
|
18
|
-
};
|
|
19
|
-
readonly librarian: {
|
|
20
|
-
readonly factory: typeof createLibrarianAgent;
|
|
21
|
-
readonly shortDesc: "docs/GitHub";
|
|
22
|
-
};
|
|
23
|
-
readonly oracle: {
|
|
24
|
-
readonly factory: typeof createOracleAgent;
|
|
25
|
-
readonly shortDesc: "strategy";
|
|
26
|
-
};
|
|
27
|
-
readonly "frontend-ui-ux-engineer": {
|
|
28
|
-
readonly factory: typeof createFrontendAgent;
|
|
29
|
-
readonly shortDesc: "UI/UX";
|
|
30
|
-
};
|
|
31
|
-
readonly "document-writer": {
|
|
32
|
-
readonly factory: typeof createDocumentWriterAgent;
|
|
33
|
-
readonly shortDesc: "docs";
|
|
34
|
-
};
|
|
35
|
-
readonly "multimodal-looker": {
|
|
36
|
-
readonly factory: typeof createMultimodalAgent;
|
|
37
|
-
readonly shortDesc: "image/visual analysis";
|
|
38
|
-
};
|
|
39
|
-
readonly "code-simplicity-reviewer": {
|
|
40
|
-
readonly factory: typeof createSimplicityReviewerAgent;
|
|
41
|
-
readonly shortDesc: "code review";
|
|
42
|
-
};
|
|
43
|
-
};
|
|
44
|
-
/** Generate agent list string for tool descriptions */
|
|
45
|
-
export declare function getAgentListDescription(): string;
|
|
46
6
|
/** Get list of agent names */
|
|
47
7
|
export declare function getAgentNames(): SubagentName[];
|
|
48
8
|
export declare function createAgents(config?: PluginConfig): AgentDefinition[];
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { AgentConfig } from "@opencode-ai/sdk";
|
|
2
2
|
export interface AgentDefinition {
|
|
3
3
|
name: string;
|
|
4
|
-
description
|
|
4
|
+
description?: string;
|
|
5
5
|
config: AgentConfig;
|
|
6
6
|
}
|
|
7
|
-
export declare function createOrchestratorAgent(model: string
|
|
7
|
+
export declare function createOrchestratorAgent(model: string): AgentDefinition;
|
|
@@ -12,4 +12,8 @@ export declare function addProviderConfig(installConfig: InstallConfig): ConfigM
|
|
|
12
12
|
export declare function addServerConfig(installConfig: InstallConfig): ConfigMergeResult;
|
|
13
13
|
export declare function generateLiteConfig(installConfig: InstallConfig): Record<string, unknown>;
|
|
14
14
|
export declare function writeLiteConfig(installConfig: InstallConfig): ConfigMergeResult;
|
|
15
|
+
/**
|
|
16
|
+
* Disable OpenCode's default subagents since the plugin provides its own
|
|
17
|
+
*/
|
|
18
|
+
export declare function disableDefaultAgents(): ConfigMergeResult;
|
|
15
19
|
export declare function detectCurrentConfig(): DetectedConfig;
|
package/dist/cli/index.js
CHANGED
|
@@ -51,18 +51,6 @@ async function isOpenCodeInstalled() {
|
|
|
51
51
|
return false;
|
|
52
52
|
}
|
|
53
53
|
}
|
|
54
|
-
async function isTmuxInstalled() {
|
|
55
|
-
try {
|
|
56
|
-
const proc = Bun.spawn(["tmux", "-V"], {
|
|
57
|
-
stdout: "pipe",
|
|
58
|
-
stderr: "pipe"
|
|
59
|
-
});
|
|
60
|
-
await proc.exited;
|
|
61
|
-
return proc.exitCode === 0;
|
|
62
|
-
} catch {
|
|
63
|
-
return false;
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
54
|
async function getOpenCodeVersion() {
|
|
67
55
|
try {
|
|
68
56
|
const proc = Bun.spawn(["opencode", "--version"], {
|
|
@@ -193,29 +181,6 @@ function addProviderConfig(installConfig) {
|
|
|
193
181
|
};
|
|
194
182
|
}
|
|
195
183
|
}
|
|
196
|
-
function addServerConfig(installConfig) {
|
|
197
|
-
const configPath = getConfigJson();
|
|
198
|
-
try {
|
|
199
|
-
ensureConfigDir();
|
|
200
|
-
let config = parseConfig(configPath) ?? {};
|
|
201
|
-
if (installConfig.hasTmux) {
|
|
202
|
-
const server = config.server ?? {};
|
|
203
|
-
if (server.port === undefined) {
|
|
204
|
-
server.port = 4096;
|
|
205
|
-
}
|
|
206
|
-
config.server = server;
|
|
207
|
-
}
|
|
208
|
-
writeFileSync(configPath, JSON.stringify(config, null, 2) + `
|
|
209
|
-
`);
|
|
210
|
-
return { success: true, configPath };
|
|
211
|
-
} catch (err) {
|
|
212
|
-
return {
|
|
213
|
-
success: false,
|
|
214
|
-
configPath,
|
|
215
|
-
error: `Failed to add server config: ${err}`
|
|
216
|
-
};
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
184
|
var MODEL_MAPPINGS = {
|
|
220
185
|
antigravity: {
|
|
221
186
|
orchestrator: "google/claude-opus-4-5-thinking",
|
|
@@ -290,6 +255,26 @@ function writeLiteConfig(installConfig) {
|
|
|
290
255
|
};
|
|
291
256
|
}
|
|
292
257
|
}
|
|
258
|
+
function disableDefaultAgents() {
|
|
259
|
+
const configPath = getConfigJson();
|
|
260
|
+
try {
|
|
261
|
+
ensureConfigDir();
|
|
262
|
+
let config = parseConfig(configPath) ?? {};
|
|
263
|
+
const agent = config.agent ?? {};
|
|
264
|
+
agent.explore = { disable: true };
|
|
265
|
+
agent.general = { disable: true };
|
|
266
|
+
config.agent = agent;
|
|
267
|
+
writeFileSync(configPath, JSON.stringify(config, null, 2) + `
|
|
268
|
+
`);
|
|
269
|
+
return { success: true, configPath };
|
|
270
|
+
} catch (err) {
|
|
271
|
+
return {
|
|
272
|
+
success: false,
|
|
273
|
+
configPath,
|
|
274
|
+
error: `Failed to disable default agents: ${err}`
|
|
275
|
+
};
|
|
276
|
+
}
|
|
277
|
+
}
|
|
293
278
|
function detectCurrentConfig() {
|
|
294
279
|
const result = {
|
|
295
280
|
isInstalled: false,
|
|
@@ -424,8 +409,7 @@ async function askYesNo(rl, prompt, defaultValue = "no") {
|
|
|
424
409
|
}
|
|
425
410
|
async function runInteractiveMode(detected) {
|
|
426
411
|
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
427
|
-
const
|
|
428
|
-
const totalQuestions = tmuxInstalled ? 4 : 3;
|
|
412
|
+
const totalQuestions = 3;
|
|
429
413
|
try {
|
|
430
414
|
console.log(`${BOLD}Question 1/${totalQuestions}:${RESET}`);
|
|
431
415
|
printInfo("The Pantheon is tuned for Antigravity's model routing. Other models work, but results may vary.");
|
|
@@ -437,19 +421,11 @@ async function runInteractiveMode(detected) {
|
|
|
437
421
|
console.log(`${BOLD}Question 3/${totalQuestions}:${RESET}`);
|
|
438
422
|
const cerebras = await askYesNo(rl, "Do you have access to Cerebras API?", detected.hasCerebras ? "yes" : "no");
|
|
439
423
|
console.log();
|
|
440
|
-
let tmux = "no";
|
|
441
|
-
if (tmuxInstalled) {
|
|
442
|
-
console.log(`${BOLD}Question 4/4:${RESET}`);
|
|
443
|
-
printInfo(`${BOLD}Tmux detected!${RESET} We can enable tmux integration for you.`);
|
|
444
|
-
printInfo("This will spawn new panes for sub-agents, letting you watch them work in real-time.");
|
|
445
|
-
tmux = await askYesNo(rl, "Enable tmux integration?", detected.hasTmux ? "yes" : "no");
|
|
446
|
-
console.log();
|
|
447
|
-
}
|
|
448
424
|
return {
|
|
449
425
|
hasAntigravity: antigravity === "yes",
|
|
450
426
|
hasOpenAI: openai === "yes",
|
|
451
427
|
hasCerebras: cerebras === "yes",
|
|
452
|
-
hasTmux:
|
|
428
|
+
hasTmux: false
|
|
453
429
|
};
|
|
454
430
|
} finally {
|
|
455
431
|
rl.close();
|
|
@@ -459,11 +435,9 @@ async function runInstall(config) {
|
|
|
459
435
|
const detected = detectCurrentConfig();
|
|
460
436
|
const isUpdate = detected.isInstalled;
|
|
461
437
|
printHeader(isUpdate);
|
|
462
|
-
let totalSteps =
|
|
438
|
+
let totalSteps = 4;
|
|
463
439
|
if (config.hasAntigravity)
|
|
464
440
|
totalSteps += 2;
|
|
465
|
-
if (config.hasTmux)
|
|
466
|
-
totalSteps += 1;
|
|
467
441
|
let step = 1;
|
|
468
442
|
printStep(step++, totalSteps, "Checking OpenCode installation...");
|
|
469
443
|
const { ok } = await checkOpenCodeInstalled();
|
|
@@ -473,6 +447,10 @@ async function runInstall(config) {
|
|
|
473
447
|
const pluginResult = await addPluginToOpenCodeConfig();
|
|
474
448
|
if (!handleStepResult(pluginResult, "Plugin added"))
|
|
475
449
|
return 1;
|
|
450
|
+
printStep(step++, totalSteps, "Disabling OpenCode default agents...");
|
|
451
|
+
const agentResult = disableDefaultAgents();
|
|
452
|
+
if (!handleStepResult(agentResult, "Default agents disabled"))
|
|
453
|
+
return 1;
|
|
476
454
|
if (config.hasAntigravity) {
|
|
477
455
|
printStep(step++, totalSteps, "Adding auth plugins...");
|
|
478
456
|
const authResult = await addAuthPlugins(config);
|
|
@@ -483,12 +461,6 @@ async function runInstall(config) {
|
|
|
483
461
|
if (!handleStepResult(providerResult, "Providers configured"))
|
|
484
462
|
return 1;
|
|
485
463
|
}
|
|
486
|
-
if (config.hasTmux) {
|
|
487
|
-
printStep(step++, totalSteps, "Configuring OpenCode HTTP server for tmux...");
|
|
488
|
-
const serverResult = addServerConfig(config);
|
|
489
|
-
if (!handleStepResult(serverResult, "Server configured"))
|
|
490
|
-
return 1;
|
|
491
|
-
}
|
|
492
464
|
printStep(step++, totalSteps, "Writing oh-my-opencode-slim configuration...");
|
|
493
465
|
const liteResult = writeLiteConfig(config);
|
|
494
466
|
if (!handleStepResult(liteResult, "Config written"))
|
|
@@ -509,14 +481,8 @@ async function runInstall(config) {
|
|
|
509
481
|
console.log(` ${nextStep++}. Authenticate with your providers:`);
|
|
510
482
|
console.log(` ${BLUE}$ opencode auth login${RESET}`);
|
|
511
483
|
console.log();
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
console.log(` ${BLUE}$ tmux${RESET}`);
|
|
515
|
-
console.log(` ${BLUE}$ opencode${RESET}`);
|
|
516
|
-
} else {
|
|
517
|
-
console.log(` ${nextStep++}. Start OpenCode:`);
|
|
518
|
-
console.log(` ${BLUE}$ opencode${RESET}`);
|
|
519
|
-
}
|
|
484
|
+
console.log(` ${nextStep++}. Start OpenCode:`);
|
|
485
|
+
console.log(` ${BLUE}$ opencode${RESET}`);
|
|
520
486
|
console.log();
|
|
521
487
|
return 0;
|
|
522
488
|
}
|
package/dist/config/schema.d.ts
CHANGED
|
@@ -4,6 +4,7 @@ export declare const AgentOverrideConfigSchema: z.ZodObject<{
|
|
|
4
4
|
temperature: z.ZodOptional<z.ZodNumber>;
|
|
5
5
|
prompt: z.ZodOptional<z.ZodString>;
|
|
6
6
|
prompt_append: z.ZodOptional<z.ZodString>;
|
|
7
|
+
variant: z.ZodCatch<z.ZodOptional<z.ZodString>>;
|
|
7
8
|
disable: z.ZodOptional<z.ZodBoolean>;
|
|
8
9
|
}, z.core.$strip>;
|
|
9
10
|
export declare const TmuxLayoutSchema: z.ZodEnum<{
|
|
@@ -39,6 +40,7 @@ export declare const PluginConfigSchema: z.ZodObject<{
|
|
|
39
40
|
temperature: z.ZodOptional<z.ZodNumber>;
|
|
40
41
|
prompt: z.ZodOptional<z.ZodString>;
|
|
41
42
|
prompt_append: z.ZodOptional<z.ZodString>;
|
|
43
|
+
variant: z.ZodCatch<z.ZodOptional<z.ZodString>>;
|
|
42
44
|
disable: z.ZodOptional<z.ZodBoolean>;
|
|
43
45
|
}, z.core.$strip>>>;
|
|
44
46
|
disabled_agents: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { PluginInput } from "@opencode-ai/plugin";
|
|
2
2
|
import type { TmuxConfig } from "../config/schema";
|
|
3
|
+
import type { PluginConfig } from "../config";
|
|
3
4
|
export interface BackgroundTask {
|
|
4
5
|
id: string;
|
|
5
6
|
sessionId: string;
|
|
@@ -24,7 +25,8 @@ export declare class BackgroundTaskManager {
|
|
|
24
25
|
private directory;
|
|
25
26
|
private pollInterval?;
|
|
26
27
|
private tmuxEnabled;
|
|
27
|
-
|
|
28
|
+
private config?;
|
|
29
|
+
constructor(ctx: PluginInput, tmuxConfig?: TmuxConfig, config?: PluginConfig);
|
|
28
30
|
launch(opts: LaunchOptions): Promise<BackgroundTask>;
|
|
29
31
|
getResult(taskId: string, block?: boolean, timeout?: number): Promise<BackgroundTask | null>;
|
|
30
32
|
cancel(taskId?: string): number;
|
package/dist/index.js
CHANGED
|
@@ -20484,6 +20484,7 @@ var AgentOverrideConfigSchema = exports_external.object({
|
|
|
20484
20484
|
temperature: exports_external.number().min(0).max(2).optional(),
|
|
20485
20485
|
prompt: exports_external.string().optional(),
|
|
20486
20486
|
prompt_append: exports_external.string().optional(),
|
|
20487
|
+
variant: exports_external.string().optional().catch(undefined),
|
|
20487
20488
|
disable: exports_external.boolean().optional()
|
|
20488
20489
|
});
|
|
20489
20490
|
var TmuxLayoutSchema = exports_external.enum([
|
|
@@ -20585,73 +20586,172 @@ function loadPluginConfig(directory) {
|
|
|
20585
20586
|
return config2;
|
|
20586
20587
|
}
|
|
20587
20588
|
// src/agents/orchestrator.ts
|
|
20588
|
-
function createOrchestratorAgent(model
|
|
20589
|
-
const agentTable = subAgents.map((a) => `| @${a.name} | ${a.description} |`).join(`
|
|
20590
|
-
`);
|
|
20591
|
-
const prompt = ORCHESTRATOR_PROMPT_TEMPLATE.replace("{{AGENT_TABLE}}", agentTable);
|
|
20589
|
+
function createOrchestratorAgent(model) {
|
|
20592
20590
|
return {
|
|
20593
20591
|
name: "orchestrator",
|
|
20594
|
-
description: "AI coding orchestrator with access to specialized subagents",
|
|
20595
20592
|
config: {
|
|
20596
20593
|
model,
|
|
20597
20594
|
temperature: 0.1,
|
|
20598
|
-
|
|
20595
|
+
prompt: ORCHESTRATOR_PROMPT
|
|
20599
20596
|
}
|
|
20600
20597
|
};
|
|
20601
20598
|
}
|
|
20602
|
-
var
|
|
20603
|
-
You are an AI coding orchestrator
|
|
20599
|
+
var ORCHESTRATOR_PROMPT = `<Role>
|
|
20600
|
+
You are an AI coding orchestrator. You DO NOT implement - you DELEGATE.
|
|
20601
|
+
|
|
20602
|
+
**Your Identity:**
|
|
20603
|
+
- You are a CONDUCTOR, not a musician
|
|
20604
|
+
- You are a MANAGER, not a worker
|
|
20605
|
+
- You are a ROUTER, not a processor
|
|
20606
|
+
|
|
20607
|
+
**Core Rule:** If a specialist agent can do the work, YOU MUST delegate to them.
|
|
20604
20608
|
|
|
20605
|
-
**
|
|
20606
|
-
-
|
|
20607
|
-
-
|
|
20608
|
-
-
|
|
20609
|
+
**Why Delegation Matters:**
|
|
20610
|
+
- @frontend-ui-ux-engineer \u2192 10x better designs than you \u2192 improves quality
|
|
20611
|
+
- @librarian \u2192 finds docs you'd miss \u2192 improves speed and quality
|
|
20612
|
+
- @explore \u2192 searches faster than you \u2192 improves speed
|
|
20613
|
+
- @oracle \u2192 catches architectural issues you'd overlook \u2192 improves quality
|
|
20614
|
+
- @document-writer \u2192 writes cleaner docs for less cost \u2192 reduceses cost
|
|
20615
|
+
- @code-simplicity-reviewer \u2192 spots complexity you're blind to \u2192 improves quality
|
|
20616
|
+
- @multimodal-looker \u2192 understands images you can't parse \u2192 improves speed and quality
|
|
20609
20617
|
|
|
20618
|
+
**Your value is in orchestration, not implementation.**
|
|
20610
20619
|
</Role>
|
|
20611
20620
|
|
|
20612
|
-
<
|
|
20613
|
-
|
|
20614
|
-
|-------|-----------------------|
|
|
20615
|
-
{{AGENT_TABLE}}
|
|
20616
|
-
</Subagents>
|
|
20621
|
+
<Agents>
|
|
20622
|
+
## Research Agents (Background-friendly)
|
|
20617
20623
|
|
|
20618
|
-
|
|
20619
|
-
|
|
20624
|
+
@explore - Fast codebase search and pattern matching
|
|
20625
|
+
Triggers: "find", "where is", "search for", "which file", "locate"
|
|
20626
|
+
Example: background_task(agent="explore", prompt="Find all authentication implementations")
|
|
20620
20627
|
|
|
20621
|
-
|
|
20622
|
-
|
|
20623
|
-
|
|
20624
|
-
background_task(agent="explore", prompt="Find all auth implementations")
|
|
20625
|
-
background_task(agent="librarian", prompt="How does library X handle Y")
|
|
20626
|
-
\`\`\`
|
|
20628
|
+
@librarian - External documentation and library research
|
|
20629
|
+
Triggers: "how does X library work", "docs for", "API reference", "best practice for"
|
|
20630
|
+
Example: background_task(agent="librarian", prompt="How does React Query handle cache invalidation")
|
|
20627
20631
|
|
|
20628
|
-
##
|
|
20629
|
-
- Use the subagent most relevant to the task description.
|
|
20630
|
-
- Use background tasks for research or search while you continue working.
|
|
20632
|
+
## Advisory Agents (Usually sync)
|
|
20631
20633
|
|
|
20632
|
-
|
|
20633
|
-
|
|
20634
|
-
|
|
20634
|
+
@oracle - Architecture, debugging, and strategic code review
|
|
20635
|
+
Triggers: "should I", "why does", "review", "debug", "what's wrong", "tradeoffs"
|
|
20636
|
+
Use when: Complex decisions, mysterious bugs, architectural uncertainty
|
|
20637
|
+
|
|
20638
|
+
@code-simplicity-reviewer - Complexity analysis and YAGNI enforcement
|
|
20639
|
+
Triggers: "too complex", "simplify", "review for complexity", after major refactors
|
|
20640
|
+
Use when: After writing significant code, before finalizing PRs
|
|
20641
|
+
|
|
20642
|
+
## Implementation Agents (Sync)
|
|
20643
|
+
|
|
20644
|
+
@frontend-ui-ux-engineer - UI/UX design and implementation
|
|
20645
|
+
Triggers: "styling", "responsive", "UI", "UX", "component design", "CSS", "animation"
|
|
20646
|
+
Use when: Any visual/frontend work that needs design sense
|
|
20647
|
+
|
|
20648
|
+
@document-writer - Technical documentation and knowledge capture
|
|
20649
|
+
Triggers: "document", "README", "update docs", "explain in docs"
|
|
20650
|
+
Use when: After features are implemented, before closing tasks
|
|
20651
|
+
|
|
20652
|
+
@multimodal-looker - Image and visual content analysis
|
|
20653
|
+
Triggers: User provides image, screenshot, diagram, mockup
|
|
20654
|
+
Use when: Need to extract info from visual inputs
|
|
20655
|
+
</Agents>
|
|
20635
20656
|
|
|
20636
20657
|
<Workflow>
|
|
20637
|
-
1
|
|
20638
|
-
|
|
20639
|
-
|
|
20640
|
-
|
|
20641
|
-
|
|
20642
|
-
|
|
20658
|
+
## Phase 1: Understand
|
|
20659
|
+
Parse the request. Identify explicit and implicit requirements.
|
|
20660
|
+
|
|
20661
|
+
## Phase 2: Delegation Gate (MANDATORY - DO NOT SKIP)
|
|
20662
|
+
|
|
20663
|
+
STOP. Before ANY implementation, you MUST complete this checklist:
|
|
20664
|
+
|
|
20665
|
+
\`\`\`
|
|
20666
|
+
DELEGATION CHECKLIST (complete before coding):
|
|
20667
|
+
[ ] UI/styling/design/visual/CSS/animation? \u2192 @frontend-ui-ux-engineer MUST handle
|
|
20668
|
+
[ ] Need codebase context? \u2192 @explore first
|
|
20669
|
+
[ ] External library/API docs needed? \u2192 @librarian first
|
|
20670
|
+
[ ] Architecture decision or debugging? \u2192 @oracle first
|
|
20671
|
+
[ ] Image/screenshot/diagram provided? \u2192 @multimodal-looker first
|
|
20672
|
+
[ ] Documentation to write? \u2192 @document-writer handles
|
|
20673
|
+
\`\`\`
|
|
20674
|
+
|
|
20675
|
+
**CRITICAL RULES:**
|
|
20676
|
+
1. If ANY checkbox applies \u2192 delegate BEFORE you write code
|
|
20677
|
+
2. Reading files for context \u2260 completing the task. Context gathering is Phase 1, not Phase 3.
|
|
20678
|
+
3. Your job is to DELEGATE task when specialize provide improved speed, quality or cost, not to DO it yourself this time.
|
|
20679
|
+
|
|
20680
|
+
**Anti-patterns to avoid:**
|
|
20681
|
+
- Reading files \u2192 feeling productive \u2192 implementing yourself (WRONG)
|
|
20682
|
+
- Creating todos \u2192 feeling like you planned \u2192 skipping delegation (WRONG)
|
|
20683
|
+
- "I can handle this" \u2192 doing specialist work yourself (WRONG)
|
|
20684
|
+
|
|
20685
|
+
## Phase 2.1: Task Planning
|
|
20686
|
+
1. If task has 2+ steps \u2192 Create todo list with delegations noted
|
|
20687
|
+
2. Mark current task \`in_progress\` before starting
|
|
20688
|
+
3. Mark \`completed\` immediately when done
|
|
20689
|
+
|
|
20690
|
+
## Phase 3: Execute
|
|
20691
|
+
1. Fire background research (explore, librarian) in parallel
|
|
20692
|
+
2. DELEGATE implementation to specialists based on Phase 2 checklist
|
|
20693
|
+
3. Only do work yourself if NO specialist applies
|
|
20694
|
+
4. Integrate results from specialists
|
|
20695
|
+
|
|
20696
|
+
## Phase 4: Verify
|
|
20697
|
+
- Run lsp_diagnostics to check for errors
|
|
20698
|
+
- @code-simplicity-reviewer for complex changes
|
|
20699
|
+
- Update documentation if behavior changed
|
|
20643
20700
|
</Workflow>
|
|
20701
|
+
|
|
20702
|
+
### Clarification Protocol (when asking):
|
|
20703
|
+
|
|
20704
|
+
\`\`\`
|
|
20705
|
+
I want to make sure I understand correctly.
|
|
20706
|
+
|
|
20707
|
+
**What I understood**: [Your interpretation]
|
|
20708
|
+
**What I'm unsure about**: [Specific ambiguity]
|
|
20709
|
+
**Options I see**:
|
|
20710
|
+
1. [Option A] - [effort/implications]
|
|
20711
|
+
2. [Option B] - [effort/implications]
|
|
20712
|
+
|
|
20713
|
+
**My recommendation**: [suggestion with reasoning]
|
|
20714
|
+
|
|
20715
|
+
Should I proceed with [recommendation], or would you prefer differently?
|
|
20716
|
+
\`\`\`
|
|
20717
|
+
|
|
20718
|
+
## Communication Style
|
|
20719
|
+
|
|
20720
|
+
### Be Concise
|
|
20721
|
+
- Start work immediately. No acknowledgments ("I'm on it", "Let me...", "I'll start...")
|
|
20722
|
+
- Answer directly without preamble
|
|
20723
|
+
- Don't summarize what you did unless asked
|
|
20724
|
+
- Don't explain your code unless asked
|
|
20725
|
+
- One word answers are acceptable when appropriate
|
|
20726
|
+
|
|
20727
|
+
### No Flattery
|
|
20728
|
+
Never start responses with:
|
|
20729
|
+
- "Great question!"
|
|
20730
|
+
- "That's a really good idea!"
|
|
20731
|
+
- "Excellent choice!"
|
|
20732
|
+
- Any praise of the user's input
|
|
20733
|
+
|
|
20734
|
+
### When User is Wrong
|
|
20735
|
+
If the user's approach seems problematic:
|
|
20736
|
+
- Don't blindly implement it
|
|
20737
|
+
- Don't lecture or be preachy
|
|
20738
|
+
- Concisely state your concern and alternative
|
|
20739
|
+
- Ask if they want to proceed anyway
|
|
20740
|
+
|
|
20741
|
+
## Skills
|
|
20742
|
+
For browser tasks (verification, screenshots, scraping), call omo_skill with name "playwright" first.
|
|
20743
|
+
Use omo_skill_mcp to invoke browser actions. Screenshots save to '/tmp/playwright-mcp-output/'.
|
|
20644
20744
|
`;
|
|
20645
20745
|
|
|
20646
20746
|
// src/agents/oracle.ts
|
|
20647
20747
|
function createOracleAgent(model) {
|
|
20648
20748
|
return {
|
|
20649
20749
|
name: "oracle",
|
|
20650
|
-
description: "
|
|
20750
|
+
description: "Strategic technical advisor. Use for architecture decisions, complex debugging, code review, and engineering guidance.",
|
|
20651
20751
|
config: {
|
|
20652
20752
|
model,
|
|
20653
20753
|
temperature: 0.1,
|
|
20654
|
-
|
|
20754
|
+
prompt: ORACLE_PROMPT
|
|
20655
20755
|
}
|
|
20656
20756
|
};
|
|
20657
20757
|
}
|
|
@@ -20680,11 +20780,11 @@ var ORACLE_PROMPT = `You are Oracle - a strategic technical advisor.
|
|
|
20680
20780
|
function createLibrarianAgent(model) {
|
|
20681
20781
|
return {
|
|
20682
20782
|
name: "librarian",
|
|
20683
|
-
description: "External documentation and library research",
|
|
20783
|
+
description: "External documentation and library research. Use for official docs lookup, GitHub examples, and understanding library internals.",
|
|
20684
20784
|
config: {
|
|
20685
20785
|
model,
|
|
20686
20786
|
temperature: 0.1,
|
|
20687
|
-
|
|
20787
|
+
prompt: LIBRARIAN_PROMPT
|
|
20688
20788
|
}
|
|
20689
20789
|
};
|
|
20690
20790
|
}
|
|
@@ -20713,11 +20813,11 @@ var LIBRARIAN_PROMPT = `You are Librarian - a research specialist for codebases
|
|
|
20713
20813
|
function createExploreAgent(model) {
|
|
20714
20814
|
return {
|
|
20715
20815
|
name: "explore",
|
|
20716
|
-
description: "Fast codebase search and pattern matching",
|
|
20816
|
+
description: "Fast codebase search and pattern matching. Use for finding files, locating code patterns, and answering 'where is X?' questions.",
|
|
20717
20817
|
config: {
|
|
20718
20818
|
model,
|
|
20719
20819
|
temperature: 0.1,
|
|
20720
|
-
|
|
20820
|
+
prompt: EXPLORE_PROMPT
|
|
20721
20821
|
}
|
|
20722
20822
|
};
|
|
20723
20823
|
}
|
|
@@ -20764,11 +20864,11 @@ Concise answer to the question
|
|
|
20764
20864
|
function createFrontendAgent(model) {
|
|
20765
20865
|
return {
|
|
20766
20866
|
name: "frontend-ui-ux-engineer",
|
|
20767
|
-
description: "UI/UX implementation and visual
|
|
20867
|
+
description: "UI/UX design and implementation. Use for styling, responsive design, component architecture, CSS/Tailwind, and visual polish.",
|
|
20768
20868
|
config: {
|
|
20769
20869
|
model,
|
|
20770
20870
|
temperature: 0.7,
|
|
20771
|
-
|
|
20871
|
+
prompt: FRONTEND_PROMPT
|
|
20772
20872
|
}
|
|
20773
20873
|
};
|
|
20774
20874
|
}
|
|
@@ -20799,11 +20899,11 @@ var FRONTEND_PROMPT = `You are a Frontend UI/UX Engineer - a designer turned dev
|
|
|
20799
20899
|
function createDocumentWriterAgent(model) {
|
|
20800
20900
|
return {
|
|
20801
20901
|
name: "document-writer",
|
|
20802
|
-
description: "Technical documentation and
|
|
20902
|
+
description: "Technical documentation writer. Use for README files, API docs, architecture docs, and user guides.",
|
|
20803
20903
|
config: {
|
|
20804
20904
|
model,
|
|
20805
20905
|
temperature: 0.3,
|
|
20806
|
-
|
|
20906
|
+
prompt: DOCUMENT_WRITER_PROMPT
|
|
20807
20907
|
}
|
|
20808
20908
|
};
|
|
20809
20909
|
}
|
|
@@ -20832,11 +20932,11 @@ var DOCUMENT_WRITER_PROMPT = `You are a Technical Writer - crafting clear, compr
|
|
|
20832
20932
|
function createMultimodalAgent(model) {
|
|
20833
20933
|
return {
|
|
20834
20934
|
name: "multimodal-looker",
|
|
20835
|
-
description: "Image and
|
|
20935
|
+
description: "Image and visual content analysis. Use for PDFs, screenshots, diagrams, mockups, and extracting info from visuals.",
|
|
20836
20936
|
config: {
|
|
20837
20937
|
model,
|
|
20838
20938
|
temperature: 0.1,
|
|
20839
|
-
|
|
20939
|
+
prompt: MULTIMODAL_PROMPT
|
|
20840
20940
|
}
|
|
20841
20941
|
};
|
|
20842
20942
|
}
|
|
@@ -20865,11 +20965,11 @@ var MULTIMODAL_PROMPT = `You are a Multimodal Analyst - extracting information f
|
|
|
20865
20965
|
function createSimplicityReviewerAgent(model) {
|
|
20866
20966
|
return {
|
|
20867
20967
|
name: "code-simplicity-reviewer",
|
|
20868
|
-
description: "
|
|
20968
|
+
description: "Code complexity analysis and YAGNI enforcement. Use after major refactors or before finalizing PRs to simplify code.",
|
|
20869
20969
|
config: {
|
|
20870
20970
|
model,
|
|
20871
20971
|
temperature: 0.1,
|
|
20872
|
-
|
|
20972
|
+
prompt: SIMPLICITY_REVIEWER_PROMPT
|
|
20873
20973
|
}
|
|
20874
20974
|
};
|
|
20875
20975
|
}
|
|
@@ -20960,32 +21060,33 @@ function applyOverrides(agent, override) {
|
|
|
20960
21060
|
if (override.temperature !== undefined)
|
|
20961
21061
|
agent.config.temperature = override.temperature;
|
|
20962
21062
|
if (override.prompt)
|
|
20963
|
-
agent.config.
|
|
21063
|
+
agent.config.prompt = override.prompt;
|
|
20964
21064
|
if (override.prompt_append) {
|
|
20965
|
-
agent.config.
|
|
21065
|
+
agent.config.prompt = `${agent.config.prompt}
|
|
20966
21066
|
|
|
20967
21067
|
${override.prompt_append}`;
|
|
20968
21068
|
}
|
|
20969
21069
|
}
|
|
20970
|
-
|
|
20971
|
-
|
|
20972
|
-
|
|
20973
|
-
oracle: { factory: createOracleAgent, shortDesc: "strategy" },
|
|
20974
|
-
"frontend-ui-ux-engineer": { factory: createFrontendAgent, shortDesc: "UI/UX" },
|
|
20975
|
-
"document-writer": { factory: createDocumentWriterAgent, shortDesc: "docs" },
|
|
20976
|
-
"multimodal-looker": { factory: createMultimodalAgent, shortDesc: "image/visual analysis" },
|
|
20977
|
-
"code-simplicity-reviewer": { factory: createSimplicityReviewerAgent, shortDesc: "code review" }
|
|
20978
|
-
};
|
|
20979
|
-
function getAgentListDescription() {
|
|
20980
|
-
return Object.entries(SUBAGENT_INFO).map(([name, { shortDesc }]) => `${name} (${shortDesc})`).join(", ");
|
|
21070
|
+
function applyDefaultPermissions(agent) {
|
|
21071
|
+
const existing = agent.config.permission ?? {};
|
|
21072
|
+
agent.config.permission = { ...existing, question: "allow" };
|
|
20981
21073
|
}
|
|
21074
|
+
var SUBAGENT_FACTORIES = {
|
|
21075
|
+
explore: createExploreAgent,
|
|
21076
|
+
librarian: createLibrarianAgent,
|
|
21077
|
+
oracle: createOracleAgent,
|
|
21078
|
+
"frontend-ui-ux-engineer": createFrontendAgent,
|
|
21079
|
+
"document-writer": createDocumentWriterAgent,
|
|
21080
|
+
"multimodal-looker": createMultimodalAgent,
|
|
21081
|
+
"code-simplicity-reviewer": createSimplicityReviewerAgent
|
|
21082
|
+
};
|
|
20982
21083
|
function getAgentNames() {
|
|
20983
|
-
return Object.keys(
|
|
21084
|
+
return Object.keys(SUBAGENT_FACTORIES);
|
|
20984
21085
|
}
|
|
20985
21086
|
function createAgents(config2) {
|
|
20986
21087
|
const disabledAgents = new Set(config2?.disabled_agents ?? []);
|
|
20987
21088
|
const agentOverrides = config2?.agents ?? {};
|
|
20988
|
-
const protoSubAgents = Object.entries(
|
|
21089
|
+
const protoSubAgents = Object.entries(SUBAGENT_FACTORIES).map(([name, factory]) => factory(DEFAULT_MODELS[name]));
|
|
20989
21090
|
const allSubAgents = protoSubAgents.filter((a) => !disabledAgents.has(a.name)).map((agent) => {
|
|
20990
21091
|
const override = agentOverrides[agent.name];
|
|
20991
21092
|
if (override) {
|
|
@@ -20994,7 +21095,8 @@ function createAgents(config2) {
|
|
|
20994
21095
|
return agent;
|
|
20995
21096
|
});
|
|
20996
21097
|
const orchestratorModel = agentOverrides["orchestrator"]?.model ?? DEFAULT_MODELS["orchestrator"];
|
|
20997
|
-
const orchestrator = createOrchestratorAgent(orchestratorModel
|
|
21098
|
+
const orchestrator = createOrchestratorAgent(orchestratorModel);
|
|
21099
|
+
applyDefaultPermissions(orchestrator);
|
|
20998
21100
|
const oOverride = agentOverrides["orchestrator"];
|
|
20999
21101
|
if (oOverride) {
|
|
21000
21102
|
applyOverrides(orchestrator, oOverride);
|
|
@@ -21003,158 +21105,7 @@ function createAgents(config2) {
|
|
|
21003
21105
|
}
|
|
21004
21106
|
function getAgentConfigs(config2) {
|
|
21005
21107
|
const agents = createAgents(config2);
|
|
21006
|
-
return Object.fromEntries(agents.map((a) => [a.name, a.config]));
|
|
21007
|
-
}
|
|
21008
|
-
|
|
21009
|
-
// src/features/background-manager.ts
|
|
21010
|
-
function generateTaskId() {
|
|
21011
|
-
return `bg_${Math.random().toString(36).substring(2, 10)}`;
|
|
21012
|
-
}
|
|
21013
|
-
|
|
21014
|
-
class BackgroundTaskManager {
|
|
21015
|
-
tasks = new Map;
|
|
21016
|
-
client;
|
|
21017
|
-
directory;
|
|
21018
|
-
pollInterval;
|
|
21019
|
-
tmuxEnabled;
|
|
21020
|
-
constructor(ctx, tmuxConfig) {
|
|
21021
|
-
this.client = ctx.client;
|
|
21022
|
-
this.directory = ctx.directory;
|
|
21023
|
-
this.tmuxEnabled = tmuxConfig?.enabled ?? false;
|
|
21024
|
-
}
|
|
21025
|
-
async launch(opts) {
|
|
21026
|
-
const session = await this.client.session.create({
|
|
21027
|
-
body: {
|
|
21028
|
-
parentID: opts.parentSessionId,
|
|
21029
|
-
title: `Background: ${opts.description}`
|
|
21030
|
-
},
|
|
21031
|
-
query: { directory: this.directory }
|
|
21032
|
-
});
|
|
21033
|
-
if (!session.data?.id) {
|
|
21034
|
-
throw new Error("Failed to create background session");
|
|
21035
|
-
}
|
|
21036
|
-
const task = {
|
|
21037
|
-
id: generateTaskId(),
|
|
21038
|
-
sessionId: session.data.id,
|
|
21039
|
-
description: opts.description,
|
|
21040
|
-
agent: opts.agent,
|
|
21041
|
-
status: "running",
|
|
21042
|
-
startedAt: new Date
|
|
21043
|
-
};
|
|
21044
|
-
this.tasks.set(task.id, task);
|
|
21045
|
-
this.startPolling();
|
|
21046
|
-
if (this.tmuxEnabled) {
|
|
21047
|
-
await new Promise((r) => setTimeout(r, 500));
|
|
21048
|
-
}
|
|
21049
|
-
const promptQuery = {
|
|
21050
|
-
directory: this.directory
|
|
21051
|
-
};
|
|
21052
|
-
if (opts.model) {
|
|
21053
|
-
promptQuery.model = opts.model;
|
|
21054
|
-
}
|
|
21055
|
-
await this.client.session.prompt({
|
|
21056
|
-
path: { id: session.data.id },
|
|
21057
|
-
body: {
|
|
21058
|
-
agent: opts.agent,
|
|
21059
|
-
tools: { background_task: false, task: false },
|
|
21060
|
-
parts: [{ type: "text", text: opts.prompt }]
|
|
21061
|
-
},
|
|
21062
|
-
query: promptQuery
|
|
21063
|
-
});
|
|
21064
|
-
return task;
|
|
21065
|
-
}
|
|
21066
|
-
async getResult(taskId, block = false, timeout = 120000) {
|
|
21067
|
-
const task = this.tasks.get(taskId);
|
|
21068
|
-
if (!task)
|
|
21069
|
-
return null;
|
|
21070
|
-
if (!block || task.status === "completed" || task.status === "failed") {
|
|
21071
|
-
return task;
|
|
21072
|
-
}
|
|
21073
|
-
const deadline = Date.now() + timeout;
|
|
21074
|
-
while (Date.now() < deadline) {
|
|
21075
|
-
await this.pollTask(task);
|
|
21076
|
-
const status = task.status;
|
|
21077
|
-
if (status === "completed" || status === "failed") {
|
|
21078
|
-
return task;
|
|
21079
|
-
}
|
|
21080
|
-
await new Promise((r) => setTimeout(r, POLL_INTERVAL_SLOW_MS));
|
|
21081
|
-
}
|
|
21082
|
-
return task;
|
|
21083
|
-
}
|
|
21084
|
-
cancel(taskId) {
|
|
21085
|
-
if (taskId) {
|
|
21086
|
-
const task = this.tasks.get(taskId);
|
|
21087
|
-
if (task && task.status === "running") {
|
|
21088
|
-
task.status = "failed";
|
|
21089
|
-
task.error = "Cancelled by user";
|
|
21090
|
-
task.completedAt = new Date;
|
|
21091
|
-
return 1;
|
|
21092
|
-
}
|
|
21093
|
-
return 0;
|
|
21094
|
-
}
|
|
21095
|
-
let count = 0;
|
|
21096
|
-
for (const task of this.tasks.values()) {
|
|
21097
|
-
if (task.status === "running") {
|
|
21098
|
-
task.status = "failed";
|
|
21099
|
-
task.error = "Cancelled by user";
|
|
21100
|
-
task.completedAt = new Date;
|
|
21101
|
-
count++;
|
|
21102
|
-
}
|
|
21103
|
-
}
|
|
21104
|
-
return count;
|
|
21105
|
-
}
|
|
21106
|
-
startPolling() {
|
|
21107
|
-
if (this.pollInterval)
|
|
21108
|
-
return;
|
|
21109
|
-
this.pollInterval = setInterval(() => this.pollAllTasks(), POLL_INTERVAL_BACKGROUND_MS);
|
|
21110
|
-
}
|
|
21111
|
-
async pollAllTasks() {
|
|
21112
|
-
const runningTasks = [...this.tasks.values()].filter((t) => t.status === "running");
|
|
21113
|
-
if (runningTasks.length === 0 && this.pollInterval) {
|
|
21114
|
-
clearInterval(this.pollInterval);
|
|
21115
|
-
this.pollInterval = undefined;
|
|
21116
|
-
return;
|
|
21117
|
-
}
|
|
21118
|
-
for (const task of runningTasks) {
|
|
21119
|
-
await this.pollTask(task);
|
|
21120
|
-
}
|
|
21121
|
-
}
|
|
21122
|
-
async pollTask(task) {
|
|
21123
|
-
try {
|
|
21124
|
-
const statusResult = await this.client.session.status();
|
|
21125
|
-
const allStatuses = statusResult.data ?? {};
|
|
21126
|
-
const sessionStatus = allStatuses[task.sessionId];
|
|
21127
|
-
if (sessionStatus && sessionStatus.type !== "idle") {
|
|
21128
|
-
return;
|
|
21129
|
-
}
|
|
21130
|
-
const messagesResult = await this.client.session.messages({ path: { id: task.sessionId } });
|
|
21131
|
-
const messages = messagesResult.data ?? messagesResult;
|
|
21132
|
-
const assistantMessages = messages.filter((m) => m.info?.role === "assistant");
|
|
21133
|
-
if (assistantMessages.length === 0) {
|
|
21134
|
-
return;
|
|
21135
|
-
}
|
|
21136
|
-
const extractedContent = [];
|
|
21137
|
-
for (const message of assistantMessages) {
|
|
21138
|
-
for (const part of message.parts ?? []) {
|
|
21139
|
-
if ((part.type === "text" || part.type === "reasoning") && part.text) {
|
|
21140
|
-
extractedContent.push(part.text);
|
|
21141
|
-
}
|
|
21142
|
-
}
|
|
21143
|
-
}
|
|
21144
|
-
const responseText = extractedContent.filter((t) => t.length > 0).join(`
|
|
21145
|
-
|
|
21146
|
-
`);
|
|
21147
|
-
if (responseText) {
|
|
21148
|
-
task.result = responseText;
|
|
21149
|
-
task.status = "completed";
|
|
21150
|
-
task.completedAt = new Date;
|
|
21151
|
-
}
|
|
21152
|
-
} catch (error48) {
|
|
21153
|
-
task.status = "failed";
|
|
21154
|
-
task.error = error48 instanceof Error ? error48.message : String(error48);
|
|
21155
|
-
task.completedAt = new Date;
|
|
21156
|
-
}
|
|
21157
|
-
}
|
|
21108
|
+
return Object.fromEntries(agents.map((a) => [a.name, { ...a.config, description: a.description }]));
|
|
21158
21109
|
}
|
|
21159
21110
|
// src/utils/tmux.ts
|
|
21160
21111
|
var {spawn } = globalThis.Bun;
|
|
@@ -21375,7 +21326,193 @@ function startTmuxCheck() {
|
|
|
21375
21326
|
getTmuxPath().catch(() => {});
|
|
21376
21327
|
}
|
|
21377
21328
|
}
|
|
21329
|
+
// src/utils/agent-variant.ts
|
|
21330
|
+
function normalizeAgentName(agentName) {
|
|
21331
|
+
const trimmed = agentName.trim();
|
|
21332
|
+
return trimmed.startsWith("@") ? trimmed.slice(1) : trimmed;
|
|
21333
|
+
}
|
|
21334
|
+
function resolveAgentVariant(config2, agentName) {
|
|
21335
|
+
const normalized = normalizeAgentName(agentName);
|
|
21336
|
+
const rawVariant = config2?.agents?.[normalized]?.variant;
|
|
21337
|
+
if (typeof rawVariant !== "string") {
|
|
21338
|
+
log(`[variant] no variant configured for agent "${normalized}"`);
|
|
21339
|
+
return;
|
|
21340
|
+
}
|
|
21341
|
+
const trimmed = rawVariant.trim();
|
|
21342
|
+
if (trimmed.length === 0) {
|
|
21343
|
+
log(`[variant] empty variant for agent "${normalized}" (ignored)`);
|
|
21344
|
+
return;
|
|
21345
|
+
}
|
|
21346
|
+
log(`[variant] resolved variant="${trimmed}" for agent "${normalized}"`);
|
|
21347
|
+
return trimmed;
|
|
21348
|
+
}
|
|
21349
|
+
function applyAgentVariant(variant, body) {
|
|
21350
|
+
if (!variant) {
|
|
21351
|
+
log("[variant] no variant to apply (skipped)");
|
|
21352
|
+
return body;
|
|
21353
|
+
}
|
|
21354
|
+
if (body.variant) {
|
|
21355
|
+
log(`[variant] body already has variant="${body.variant}" (not overriding)`);
|
|
21356
|
+
return body;
|
|
21357
|
+
}
|
|
21358
|
+
log(`[variant] applied variant="${variant}" to prompt body`);
|
|
21359
|
+
return { ...body, variant };
|
|
21360
|
+
}
|
|
21361
|
+
// src/features/background-manager.ts
|
|
21362
|
+
function generateTaskId() {
|
|
21363
|
+
return `bg_${Math.random().toString(36).substring(2, 10)}`;
|
|
21364
|
+
}
|
|
21378
21365
|
|
|
21366
|
+
class BackgroundTaskManager {
|
|
21367
|
+
tasks = new Map;
|
|
21368
|
+
client;
|
|
21369
|
+
directory;
|
|
21370
|
+
pollInterval;
|
|
21371
|
+
tmuxEnabled;
|
|
21372
|
+
config;
|
|
21373
|
+
constructor(ctx, tmuxConfig, config2) {
|
|
21374
|
+
this.client = ctx.client;
|
|
21375
|
+
this.directory = ctx.directory;
|
|
21376
|
+
this.tmuxEnabled = tmuxConfig?.enabled ?? false;
|
|
21377
|
+
this.config = config2;
|
|
21378
|
+
}
|
|
21379
|
+
async launch(opts) {
|
|
21380
|
+
const session = await this.client.session.create({
|
|
21381
|
+
body: {
|
|
21382
|
+
parentID: opts.parentSessionId,
|
|
21383
|
+
title: `Background: ${opts.description}`
|
|
21384
|
+
},
|
|
21385
|
+
query: { directory: this.directory }
|
|
21386
|
+
});
|
|
21387
|
+
if (!session.data?.id) {
|
|
21388
|
+
throw new Error("Failed to create background session");
|
|
21389
|
+
}
|
|
21390
|
+
const task = {
|
|
21391
|
+
id: generateTaskId(),
|
|
21392
|
+
sessionId: session.data.id,
|
|
21393
|
+
description: opts.description,
|
|
21394
|
+
agent: opts.agent,
|
|
21395
|
+
status: "running",
|
|
21396
|
+
startedAt: new Date
|
|
21397
|
+
};
|
|
21398
|
+
this.tasks.set(task.id, task);
|
|
21399
|
+
this.startPolling();
|
|
21400
|
+
if (this.tmuxEnabled) {
|
|
21401
|
+
await new Promise((r) => setTimeout(r, 500));
|
|
21402
|
+
}
|
|
21403
|
+
const promptQuery = {
|
|
21404
|
+
directory: this.directory
|
|
21405
|
+
};
|
|
21406
|
+
if (opts.model) {
|
|
21407
|
+
promptQuery.model = opts.model;
|
|
21408
|
+
}
|
|
21409
|
+
log(`[background-manager] launching task for agent="${opts.agent}"`, { description: opts.description });
|
|
21410
|
+
const resolvedVariant = resolveAgentVariant(this.config, opts.agent);
|
|
21411
|
+
const promptBody = applyAgentVariant(resolvedVariant, {
|
|
21412
|
+
agent: opts.agent,
|
|
21413
|
+
tools: { background_task: false, task: false },
|
|
21414
|
+
parts: [{ type: "text", text: opts.prompt }]
|
|
21415
|
+
});
|
|
21416
|
+
await this.client.session.prompt({
|
|
21417
|
+
path: { id: session.data.id },
|
|
21418
|
+
body: promptBody,
|
|
21419
|
+
query: promptQuery
|
|
21420
|
+
});
|
|
21421
|
+
return task;
|
|
21422
|
+
}
|
|
21423
|
+
async getResult(taskId, block = false, timeout = 120000) {
|
|
21424
|
+
const task = this.tasks.get(taskId);
|
|
21425
|
+
if (!task)
|
|
21426
|
+
return null;
|
|
21427
|
+
if (!block || task.status === "completed" || task.status === "failed") {
|
|
21428
|
+
return task;
|
|
21429
|
+
}
|
|
21430
|
+
const deadline = Date.now() + timeout;
|
|
21431
|
+
while (Date.now() < deadline) {
|
|
21432
|
+
await this.pollTask(task);
|
|
21433
|
+
const status = task.status;
|
|
21434
|
+
if (status === "completed" || status === "failed") {
|
|
21435
|
+
return task;
|
|
21436
|
+
}
|
|
21437
|
+
await new Promise((r) => setTimeout(r, POLL_INTERVAL_SLOW_MS));
|
|
21438
|
+
}
|
|
21439
|
+
return task;
|
|
21440
|
+
}
|
|
21441
|
+
cancel(taskId) {
|
|
21442
|
+
if (taskId) {
|
|
21443
|
+
const task = this.tasks.get(taskId);
|
|
21444
|
+
if (task && task.status === "running") {
|
|
21445
|
+
task.status = "failed";
|
|
21446
|
+
task.error = "Cancelled by user";
|
|
21447
|
+
task.completedAt = new Date;
|
|
21448
|
+
return 1;
|
|
21449
|
+
}
|
|
21450
|
+
return 0;
|
|
21451
|
+
}
|
|
21452
|
+
let count = 0;
|
|
21453
|
+
for (const task of this.tasks.values()) {
|
|
21454
|
+
if (task.status === "running") {
|
|
21455
|
+
task.status = "failed";
|
|
21456
|
+
task.error = "Cancelled by user";
|
|
21457
|
+
task.completedAt = new Date;
|
|
21458
|
+
count++;
|
|
21459
|
+
}
|
|
21460
|
+
}
|
|
21461
|
+
return count;
|
|
21462
|
+
}
|
|
21463
|
+
startPolling() {
|
|
21464
|
+
if (this.pollInterval)
|
|
21465
|
+
return;
|
|
21466
|
+
this.pollInterval = setInterval(() => this.pollAllTasks(), POLL_INTERVAL_BACKGROUND_MS);
|
|
21467
|
+
}
|
|
21468
|
+
async pollAllTasks() {
|
|
21469
|
+
const runningTasks = [...this.tasks.values()].filter((t) => t.status === "running");
|
|
21470
|
+
if (runningTasks.length === 0 && this.pollInterval) {
|
|
21471
|
+
clearInterval(this.pollInterval);
|
|
21472
|
+
this.pollInterval = undefined;
|
|
21473
|
+
return;
|
|
21474
|
+
}
|
|
21475
|
+
for (const task of runningTasks) {
|
|
21476
|
+
await this.pollTask(task);
|
|
21477
|
+
}
|
|
21478
|
+
}
|
|
21479
|
+
async pollTask(task) {
|
|
21480
|
+
try {
|
|
21481
|
+
const statusResult = await this.client.session.status();
|
|
21482
|
+
const allStatuses = statusResult.data ?? {};
|
|
21483
|
+
const sessionStatus = allStatuses[task.sessionId];
|
|
21484
|
+
if (sessionStatus && sessionStatus.type !== "idle") {
|
|
21485
|
+
return;
|
|
21486
|
+
}
|
|
21487
|
+
const messagesResult = await this.client.session.messages({ path: { id: task.sessionId } });
|
|
21488
|
+
const messages = messagesResult.data ?? messagesResult;
|
|
21489
|
+
const assistantMessages = messages.filter((m) => m.info?.role === "assistant");
|
|
21490
|
+
if (assistantMessages.length === 0) {
|
|
21491
|
+
return;
|
|
21492
|
+
}
|
|
21493
|
+
const extractedContent = [];
|
|
21494
|
+
for (const message of assistantMessages) {
|
|
21495
|
+
for (const part of message.parts ?? []) {
|
|
21496
|
+
if ((part.type === "text" || part.type === "reasoning") && part.text) {
|
|
21497
|
+
extractedContent.push(part.text);
|
|
21498
|
+
}
|
|
21499
|
+
}
|
|
21500
|
+
}
|
|
21501
|
+
const responseText = extractedContent.filter((t) => t.length > 0).join(`
|
|
21502
|
+
|
|
21503
|
+
`);
|
|
21504
|
+
if (responseText) {
|
|
21505
|
+
task.result = responseText;
|
|
21506
|
+
task.status = "completed";
|
|
21507
|
+
task.completedAt = new Date;
|
|
21508
|
+
}
|
|
21509
|
+
} catch (error48) {
|
|
21510
|
+
task.status = "failed";
|
|
21511
|
+
task.error = error48 instanceof Error ? error48.message : String(error48);
|
|
21512
|
+
task.completedAt = new Date;
|
|
21513
|
+
}
|
|
21514
|
+
}
|
|
21515
|
+
}
|
|
21379
21516
|
// src/features/tmux-session-manager.ts
|
|
21380
21517
|
var POLL_INTERVAL_MS2 = 2000;
|
|
21381
21518
|
var SESSION_TIMEOUT_MS = 10 * 60 * 1000;
|
|
@@ -33826,13 +33963,12 @@ function tool(input) {
|
|
|
33826
33963
|
tool.schema = exports_external2;
|
|
33827
33964
|
// src/tools/background.ts
|
|
33828
33965
|
var z2 = tool.schema;
|
|
33829
|
-
function createBackgroundTools(ctx, manager, tmuxConfig) {
|
|
33830
|
-
const agentList = getAgentListDescription();
|
|
33966
|
+
function createBackgroundTools(ctx, manager, tmuxConfig, pluginConfig) {
|
|
33831
33967
|
const agentNames = getAgentNames().join(", ");
|
|
33832
33968
|
const background_task = tool({
|
|
33833
33969
|
description: `Run agent task. Use sync=true to wait for result, sync=false (default) to run in background.
|
|
33834
33970
|
|
|
33835
|
-
Agents: ${
|
|
33971
|
+
Agents: ${agentNames}.
|
|
33836
33972
|
|
|
33837
33973
|
Async mode returns task_id immediately - use \`background_output\` to get results.
|
|
33838
33974
|
Sync mode blocks until completion and returns the result directly.`,
|
|
@@ -33850,7 +33986,7 @@ Sync mode blocks until completion and returns the result directly.`,
|
|
|
33850
33986
|
const description = String(args.description);
|
|
33851
33987
|
const isSync = args.sync === true;
|
|
33852
33988
|
if (isSync) {
|
|
33853
|
-
return await executeSync(description, prompt, agent, tctx, ctx, tmuxConfig, args.session_id);
|
|
33989
|
+
return await executeSync(description, prompt, agent, tctx, ctx, tmuxConfig, pluginConfig, args.session_id);
|
|
33854
33990
|
}
|
|
33855
33991
|
const task = await manager.launch({
|
|
33856
33992
|
agent,
|
|
@@ -33921,7 +34057,7 @@ Duration: ${duration5}
|
|
|
33921
34057
|
});
|
|
33922
34058
|
return { background_task, background_output, background_cancel };
|
|
33923
34059
|
}
|
|
33924
|
-
async function executeSync(description, prompt, agent, toolContext, ctx, tmuxConfig, existingSessionId) {
|
|
34060
|
+
async function executeSync(description, prompt, agent, toolContext, ctx, tmuxConfig, pluginConfig, existingSessionId) {
|
|
33925
34061
|
let sessionID;
|
|
33926
34062
|
if (existingSessionId) {
|
|
33927
34063
|
const sessionResult = await ctx.client.session.get({ path: { id: existingSessionId } });
|
|
@@ -33947,14 +34083,18 @@ async function executeSync(description, prompt, agent, toolContext, ctx, tmuxCon
|
|
|
33947
34083
|
await new Promise((r) => setTimeout(r, 500));
|
|
33948
34084
|
}
|
|
33949
34085
|
}
|
|
34086
|
+
log(`[background-sync] launching sync task for agent="${agent}"`, { description });
|
|
34087
|
+
const resolvedVariant = resolveAgentVariant(pluginConfig, agent);
|
|
34088
|
+
const baseBody = {
|
|
34089
|
+
agent,
|
|
34090
|
+
tools: { background_task: false, task: false },
|
|
34091
|
+
parts: [{ type: "text", text: prompt }]
|
|
34092
|
+
};
|
|
34093
|
+
const promptBody = applyAgentVariant(resolvedVariant, baseBody);
|
|
33950
34094
|
try {
|
|
33951
34095
|
await ctx.client.session.prompt({
|
|
33952
34096
|
path: { id: sessionID },
|
|
33953
|
-
body:
|
|
33954
|
-
agent,
|
|
33955
|
-
tools: { background_task: false, task: false },
|
|
33956
|
-
parts: [{ type: "text", text: prompt }]
|
|
33957
|
-
}
|
|
34097
|
+
body: promptBody
|
|
33958
34098
|
});
|
|
33959
34099
|
} catch (error92) {
|
|
33960
34100
|
return `Error: Failed to send prompt: ${error92 instanceof Error ? error92.message : String(error92)}
|
|
@@ -40836,8 +40976,8 @@ var OhMyOpenCodeLite = async (ctx) => {
|
|
|
40836
40976
|
if (tmuxConfig.enabled) {
|
|
40837
40977
|
startTmuxCheck();
|
|
40838
40978
|
}
|
|
40839
|
-
const backgroundManager = new BackgroundTaskManager(ctx, tmuxConfig);
|
|
40840
|
-
const backgroundTools = createBackgroundTools(ctx, backgroundManager, tmuxConfig);
|
|
40979
|
+
const backgroundManager = new BackgroundTaskManager(ctx, tmuxConfig, config3);
|
|
40980
|
+
const backgroundTools = createBackgroundTools(ctx, backgroundManager, tmuxConfig, config3);
|
|
40841
40981
|
const mcps = createBuiltinMcps(config3.disabled_mcps);
|
|
40842
40982
|
const skillMcpManager = SkillMcpManager.getInstance();
|
|
40843
40983
|
const skillTools = createSkillTools(skillMcpManager);
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { type PluginInput, type ToolDefinition } from "@opencode-ai/plugin";
|
|
2
2
|
import type { BackgroundTaskManager } from "../features";
|
|
3
3
|
import type { TmuxConfig } from "../config/schema";
|
|
4
|
-
|
|
4
|
+
import type { PluginConfig } from "../config";
|
|
5
|
+
export declare function createBackgroundTools(ctx: PluginInput, manager: BackgroundTaskManager, tmuxConfig?: TmuxConfig, pluginConfig?: PluginConfig): Record<string, ToolDefinition>;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { PluginConfig } from "../config";
|
|
2
|
+
export declare function normalizeAgentName(agentName: string): string;
|
|
3
|
+
export declare function resolveAgentVariant(config: PluginConfig | undefined, agentName: string): string | undefined;
|
|
4
|
+
export declare function applyAgentVariant<T extends {
|
|
5
|
+
variant?: string;
|
|
6
|
+
}>(variant: string | undefined, body: T): T;
|
package/dist/utils/index.d.ts
CHANGED
package/package.json
CHANGED