@agentuity/opencode 0.1.39 → 0.1.41
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 +321 -9
- package/dist/agents/architect.d.ts +4 -0
- package/dist/agents/architect.d.ts.map +1 -0
- package/dist/agents/architect.js +259 -0
- package/dist/agents/architect.js.map +1 -0
- package/dist/agents/builder.d.ts +1 -1
- package/dist/agents/builder.d.ts.map +1 -1
- package/dist/agents/builder.js +44 -1
- package/dist/agents/builder.js.map +1 -1
- package/dist/agents/index.d.ts.map +1 -1
- package/dist/agents/index.js +6 -0
- package/dist/agents/index.js.map +1 -1
- package/dist/agents/lead.d.ts +1 -1
- package/dist/agents/lead.d.ts.map +1 -1
- package/dist/agents/lead.js +183 -19
- package/dist/agents/lead.js.map +1 -1
- package/dist/agents/planner.d.ts +4 -0
- package/dist/agents/planner.d.ts.map +1 -0
- package/dist/agents/planner.js +158 -0
- package/dist/agents/planner.js.map +1 -0
- package/dist/agents/runner.d.ts +4 -0
- package/dist/agents/runner.d.ts.map +1 -0
- package/dist/agents/runner.js +364 -0
- package/dist/agents/runner.js.map +1 -0
- package/dist/agents/types.d.ts +5 -1
- package/dist/agents/types.d.ts.map +1 -1
- package/dist/background/concurrency.d.ts +36 -0
- package/dist/background/concurrency.d.ts.map +1 -0
- package/dist/background/concurrency.js +92 -0
- package/dist/background/concurrency.js.map +1 -0
- package/dist/background/index.d.ts +5 -0
- package/dist/background/index.d.ts.map +1 -0
- package/dist/background/index.js +4 -0
- package/dist/background/index.js.map +1 -0
- package/dist/background/manager.d.ts +54 -0
- package/dist/background/manager.d.ts.map +1 -0
- package/dist/background/manager.js +409 -0
- package/dist/background/manager.js.map +1 -0
- package/dist/background/types.d.ts +47 -0
- package/dist/background/types.d.ts.map +1 -0
- package/dist/background/types.js +2 -0
- package/dist/background/types.js.map +1 -0
- package/dist/config/index.d.ts +2 -0
- package/dist/config/index.d.ts.map +1 -1
- package/dist/config/index.js +2 -0
- package/dist/config/index.js.map +1 -1
- package/dist/config/loader.d.ts +24 -0
- package/dist/config/loader.d.ts.map +1 -1
- package/dist/config/loader.js +102 -23
- package/dist/config/loader.js.map +1 -1
- package/dist/config/presets.d.ts +16 -0
- package/dist/config/presets.d.ts.map +1 -0
- package/dist/config/presets.js +20 -0
- package/dist/config/presets.js.map +1 -0
- package/dist/config/validation.d.ts +26 -0
- package/dist/config/validation.d.ts.map +1 -0
- package/dist/config/validation.js +48 -0
- package/dist/config/validation.js.map +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/plugin/hooks/keyword.d.ts.map +1 -1
- package/dist/plugin/hooks/keyword.js +3 -0
- package/dist/plugin/hooks/keyword.js.map +1 -1
- package/dist/plugin/plugin.d.ts.map +1 -1
- package/dist/plugin/plugin.js +297 -36
- package/dist/plugin/plugin.js.map +1 -1
- package/dist/skills/frontmatter.d.ts +7 -0
- package/dist/skills/frontmatter.d.ts.map +1 -0
- package/dist/skills/frontmatter.js +17 -0
- package/dist/skills/frontmatter.js.map +1 -0
- package/dist/skills/index.d.ts +4 -0
- package/dist/skills/index.d.ts.map +1 -0
- package/dist/skills/index.js +4 -0
- package/dist/skills/index.js.map +1 -0
- package/dist/skills/loader.d.ts +20 -0
- package/dist/skills/loader.d.ts.map +1 -0
- package/dist/skills/loader.js +152 -0
- package/dist/skills/loader.js.map +1 -0
- package/dist/skills/types.d.ts +41 -0
- package/dist/skills/types.d.ts.map +1 -0
- package/dist/skills/types.js +2 -0
- package/dist/skills/types.js.map +1 -0
- package/dist/tmux/decision-engine.d.ts +24 -0
- package/dist/tmux/decision-engine.d.ts.map +1 -0
- package/dist/tmux/decision-engine.js +193 -0
- package/dist/tmux/decision-engine.js.map +1 -0
- package/dist/tmux/executor.d.ts +56 -0
- package/dist/tmux/executor.d.ts.map +1 -0
- package/dist/tmux/executor.js +231 -0
- package/dist/tmux/executor.js.map +1 -0
- package/dist/tmux/index.d.ts +7 -0
- package/dist/tmux/index.d.ts.map +1 -0
- package/dist/tmux/index.js +7 -0
- package/dist/tmux/index.js.map +1 -0
- package/dist/tmux/manager.d.ts +80 -0
- package/dist/tmux/manager.d.ts.map +1 -0
- package/dist/tmux/manager.js +276 -0
- package/dist/tmux/manager.js.map +1 -0
- package/dist/tmux/state-query.d.ts +7 -0
- package/dist/tmux/state-query.d.ts.map +1 -0
- package/dist/tmux/state-query.js +67 -0
- package/dist/tmux/state-query.js.map +1 -0
- package/dist/tmux/types.d.ts +96 -0
- package/dist/tmux/types.d.ts.map +1 -0
- package/dist/tmux/types.js +8 -0
- package/dist/tmux/types.js.map +1 -0
- package/dist/tmux/utils.d.ts +32 -0
- package/dist/tmux/utils.d.ts.map +1 -0
- package/dist/tmux/utils.js +80 -0
- package/dist/tmux/utils.js.map +1 -0
- package/dist/tools/background.d.ts +61 -0
- package/dist/tools/background.d.ts.map +1 -0
- package/dist/tools/background.js +78 -0
- package/dist/tools/background.js.map +1 -0
- package/dist/tools/delegate.d.ts +6 -0
- package/dist/tools/delegate.d.ts.map +1 -1
- package/dist/tools/delegate.js +8 -2
- package/dist/tools/delegate.js.map +1 -1
- package/dist/tools/index.d.ts +1 -0
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +1 -0
- package/dist/tools/index.js.map +1 -1
- package/dist/types.d.ts +118 -18
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +49 -7
- package/dist/types.js.map +1 -1
- package/package.json +4 -3
- package/src/agents/architect.ts +262 -0
- package/src/agents/builder.ts +44 -1
- package/src/agents/index.ts +6 -0
- package/src/agents/lead.ts +183 -19
- package/src/agents/planner.ts +161 -0
- package/src/agents/runner.ts +367 -0
- package/src/agents/types.ts +5 -1
- package/src/background/concurrency.ts +116 -0
- package/src/background/index.ts +4 -0
- package/src/background/manager.ts +478 -0
- package/src/background/types.ts +52 -0
- package/src/config/index.ts +2 -0
- package/src/config/loader.ts +128 -31
- package/src/config/presets.ts +21 -0
- package/src/config/validation.ts +70 -0
- package/src/index.ts +1 -0
- package/src/plugin/hooks/keyword.ts +3 -0
- package/src/plugin/plugin.ts +323 -42
- package/src/skills/frontmatter.ts +25 -0
- package/src/skills/index.ts +3 -0
- package/src/skills/loader.ts +185 -0
- package/src/skills/types.ts +43 -0
- package/src/tmux/decision-engine.ts +246 -0
- package/src/tmux/executor.ts +286 -0
- package/src/tmux/index.ts +11 -0
- package/src/tmux/manager.ts +331 -0
- package/src/tmux/state-query.ts +74 -0
- package/src/tmux/types.ts +106 -0
- package/src/tmux/utils.ts +85 -0
- package/src/tools/background.ts +145 -0
- package/src/tools/delegate.ts +8 -2
- package/src/tools/index.ts +9 -0
- package/src/types.ts +88 -15
package/src/plugin/plugin.ts
CHANGED
|
@@ -1,24 +1,58 @@
|
|
|
1
1
|
import type { PluginInput, Hooks } from '@opencode-ai/plugin';
|
|
2
|
+
import { tool } from '@opencode-ai/plugin';
|
|
2
3
|
import type { AgentConfig, CommandDefinition } from '../types';
|
|
4
|
+
import { loadAllSkills, type LoadedSkill } from '../skills';
|
|
3
5
|
import { agents } from '../agents';
|
|
4
|
-
import { loadCoderConfig, getDefaultConfig, mergeConfig } from '../config';
|
|
6
|
+
import { loadCoderConfig, getDefaultConfig, mergeConfig, validateAndWarnConfigs } from '../config';
|
|
5
7
|
import { createSessionHooks } from './hooks/session';
|
|
6
8
|
import { createToolHooks } from './hooks/tools';
|
|
7
9
|
import { createKeywordHooks } from './hooks/keyword';
|
|
8
10
|
import { createParamsHooks } from './hooks/params';
|
|
9
11
|
import { createCadenceHooks } from './hooks/cadence';
|
|
10
12
|
import { createSessionMemoryHooks } from './hooks/session-memory';
|
|
11
|
-
import { z } from 'zod';
|
|
12
13
|
import type { AgentRole } from '../types';
|
|
14
|
+
import { BackgroundManager } from '../background';
|
|
15
|
+
import { TmuxSessionManager } from '../tmux';
|
|
16
|
+
|
|
17
|
+
// Sandbox environment detection
|
|
18
|
+
const SANDBOX_ID = process.env.AGENTUITY_SANDBOX_ID;
|
|
19
|
+
const IN_SANDBOX = !!SANDBOX_ID;
|
|
20
|
+
|
|
21
|
+
// Sandbox context injected into Lead, Builder, and Architect prompts
|
|
22
|
+
const SANDBOX_CONTEXT = IN_SANDBOX
|
|
23
|
+
? `
|
|
24
|
+
## Sandbox Environment
|
|
25
|
+
|
|
26
|
+
You are running inside an Agentuity Sandbox (ID: ${SANDBOX_ID}).
|
|
27
|
+
|
|
28
|
+
**Permissions:** All file operations are allowed without prompts.
|
|
29
|
+
|
|
30
|
+
**File Locations:**
|
|
31
|
+
- Working directory: \`/home/agentuity\`
|
|
32
|
+
- Temp files: \`/home/agentuity/tmp/\` (preferred over \`/tmp/\`)
|
|
33
|
+
- Artifacts: \`/home/agentuity/.agentuity/\`
|
|
34
|
+
|
|
35
|
+
**Tips:**
|
|
36
|
+
- No permission prompts - you can read/write freely
|
|
37
|
+
- Sandbox is isolated - safe to experiment
|
|
38
|
+
- Use \`/home/agentuity/\` paths for all file operations
|
|
39
|
+
`
|
|
40
|
+
: '';
|
|
41
|
+
|
|
42
|
+
// Agents that should receive sandbox context in their prompts
|
|
43
|
+
const SANDBOX_AWARE_AGENTS: AgentRole[] = ['lead', 'builder', 'architect'];
|
|
13
44
|
|
|
14
45
|
// Agent display names for @mentions
|
|
15
46
|
const AGENT_MENTIONS: Record<AgentRole, string> = {
|
|
16
47
|
lead: '@Agentuity Coder Lead',
|
|
17
48
|
scout: '@Agentuity Coder Scout',
|
|
18
49
|
builder: '@Agentuity Coder Builder',
|
|
50
|
+
architect: '@Agentuity Coder Architect',
|
|
19
51
|
reviewer: '@Agentuity Coder Reviewer',
|
|
20
52
|
memory: '@Agentuity Coder Memory',
|
|
21
53
|
expert: '@Agentuity Coder Expert',
|
|
54
|
+
planner: '@Agentuity Coder Planner',
|
|
55
|
+
runner: '@Agentuity Coder Runner',
|
|
22
56
|
};
|
|
23
57
|
|
|
24
58
|
export async function createCoderPlugin(ctx: PluginInput): Promise<Hooks> {
|
|
@@ -38,6 +72,30 @@ export async function createCoderPlugin(ctx: PluginInput): Promise<Hooks> {
|
|
|
38
72
|
const keywordHooks = createKeywordHooks(ctx, coderConfig);
|
|
39
73
|
const paramsHooks = createParamsHooks(ctx, coderConfig);
|
|
40
74
|
const cadenceHooks = createCadenceHooks(ctx, coderConfig);
|
|
75
|
+
const tmuxManager = coderConfig.tmux?.enabled
|
|
76
|
+
? new TmuxSessionManager(ctx, coderConfig.tmux, {
|
|
77
|
+
onLog: (message) =>
|
|
78
|
+
ctx.client.app.log({
|
|
79
|
+
body: {
|
|
80
|
+
service: 'agentuity-coder',
|
|
81
|
+
level: 'info',
|
|
82
|
+
message,
|
|
83
|
+
},
|
|
84
|
+
}),
|
|
85
|
+
})
|
|
86
|
+
: undefined;
|
|
87
|
+
const backgroundManager = new BackgroundManager(ctx, coderConfig.background, {
|
|
88
|
+
onSubagentSessionCreated: tmuxManager
|
|
89
|
+
? (event) => {
|
|
90
|
+
void tmuxManager.onSessionCreated(event);
|
|
91
|
+
}
|
|
92
|
+
: undefined,
|
|
93
|
+
onSubagentSessionDeleted: tmuxManager
|
|
94
|
+
? (event) => {
|
|
95
|
+
void tmuxManager.onSessionDeleted(event);
|
|
96
|
+
}
|
|
97
|
+
: undefined,
|
|
98
|
+
});
|
|
41
99
|
|
|
42
100
|
// Session memory hooks handle checkpointing and compaction for non-Cadence sessions
|
|
43
101
|
// Orchestration (deciding which module handles which session) happens below in the hooks
|
|
@@ -45,12 +103,10 @@ export async function createCoderPlugin(ctx: PluginInput): Promise<Hooks> {
|
|
|
45
103
|
|
|
46
104
|
const configHandler = createConfigHandler(coderConfig);
|
|
47
105
|
|
|
48
|
-
//
|
|
49
|
-
const
|
|
50
|
-
| ((schema: (s: typeof z) => unknown) => unknown)
|
|
51
|
-
| undefined;
|
|
106
|
+
// Create plugin tools using the @opencode-ai/plugin tool helper
|
|
107
|
+
const tools = createTools(backgroundManager);
|
|
52
108
|
|
|
53
|
-
|
|
109
|
+
registerShutdownHandler(backgroundManager, tmuxManager);
|
|
54
110
|
|
|
55
111
|
// Show startup toast (fire and forget, don't block)
|
|
56
112
|
try {
|
|
@@ -73,6 +129,10 @@ export async function createCoderPlugin(ctx: PluginInput): Promise<Hooks> {
|
|
|
73
129
|
'tool.execute.before': toolHooks.before,
|
|
74
130
|
'tool.execute.after': toolHooks.after,
|
|
75
131
|
event: async (input) => {
|
|
132
|
+
const event = extractEventFromInput(input);
|
|
133
|
+
if (event) {
|
|
134
|
+
backgroundManager.handleEvent(event);
|
|
135
|
+
}
|
|
76
136
|
// Orchestrate: route to appropriate module based on session type
|
|
77
137
|
const sessionId = extractSessionIdFromEvent(input);
|
|
78
138
|
if (sessionId && cadenceHooks.isActiveCadenceSession(sessionId)) {
|
|
@@ -101,27 +161,60 @@ function createConfigHandler(
|
|
|
101
161
|
return async (config: Record<string, unknown>) => {
|
|
102
162
|
const agentConfigs = createAgentConfigs(coderConfig);
|
|
103
163
|
const commands = createCommands();
|
|
164
|
+
const loadedSkills = await loadAllSkills(coderConfig.skills);
|
|
165
|
+
const skillCommands = createSkillCommands(loadedSkills);
|
|
166
|
+
|
|
167
|
+
// Merge agent configs: our defaults first, then user's opencode.json overrides on top
|
|
168
|
+
// This allows users to customize any agent via their opencode.json
|
|
169
|
+
const userAgentConfigs = config.agent as Record<string, AgentConfig> | undefined;
|
|
170
|
+
const mergedAgents: Record<string, AgentConfig> = { ...agentConfigs };
|
|
171
|
+
|
|
172
|
+
// Shallow merge user overrides on top of our defaults (nested objects like tools are replaced, not merged)
|
|
173
|
+
if (userAgentConfigs) {
|
|
174
|
+
for (const [name, userConfig] of Object.entries(userAgentConfigs)) {
|
|
175
|
+
if (mergedAgents[name]) {
|
|
176
|
+
// Merge user config on top of our default
|
|
177
|
+
mergedAgents[name] = {
|
|
178
|
+
...mergedAgents[name],
|
|
179
|
+
...userConfig,
|
|
180
|
+
};
|
|
181
|
+
} else {
|
|
182
|
+
// User defined a new agent not in our defaults
|
|
183
|
+
mergedAgents[name] = userConfig;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
}
|
|
104
187
|
|
|
105
|
-
config.agent =
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
188
|
+
config.agent = mergedAgents;
|
|
189
|
+
|
|
190
|
+
// Validate merged configs and warn about mismatches
|
|
191
|
+
validateAndWarnConfigs(mergedAgents);
|
|
192
|
+
|
|
193
|
+
// In sandbox, allow all permissions without prompts
|
|
194
|
+
if (IN_SANDBOX) {
|
|
195
|
+
config.permission = {
|
|
196
|
+
'*': 'allow',
|
|
197
|
+
external_directory: {
|
|
198
|
+
'/home/agentuity/**': 'allow',
|
|
199
|
+
'*': 'allow',
|
|
200
|
+
},
|
|
201
|
+
};
|
|
202
|
+
}
|
|
109
203
|
|
|
110
204
|
config.command = {
|
|
111
205
|
...(config.command as Record<string, CommandDefinition> | undefined),
|
|
112
206
|
...commands,
|
|
207
|
+
...skillCommands,
|
|
113
208
|
};
|
|
114
209
|
};
|
|
115
210
|
}
|
|
116
211
|
|
|
117
212
|
function createAgentConfigs(
|
|
118
|
-
|
|
213
|
+
_config: ReturnType<typeof getDefaultConfig>
|
|
119
214
|
): Record<string, AgentConfig> {
|
|
120
215
|
const result: Record<string, AgentConfig> = {};
|
|
121
216
|
|
|
122
217
|
for (const agent of Object.values(agents)) {
|
|
123
|
-
const modelConfig = config.agents?.[agent.role];
|
|
124
|
-
|
|
125
218
|
// Convert tools.exclude to Open Code format (tool: false)
|
|
126
219
|
const tools: Record<string, boolean> = {};
|
|
127
220
|
if (agent.tools?.exclude) {
|
|
@@ -130,16 +223,25 @@ function createAgentConfigs(
|
|
|
130
223
|
}
|
|
131
224
|
}
|
|
132
225
|
|
|
226
|
+
// Inject sandbox context into specific agents when running in sandbox
|
|
227
|
+
const shouldInjectSandbox =
|
|
228
|
+
IN_SANDBOX && SANDBOX_AWARE_AGENTS.includes(agent.role as AgentRole);
|
|
229
|
+
const prompt = shouldInjectSandbox
|
|
230
|
+
? `${agent.systemPrompt}\n${SANDBOX_CONTEXT}`
|
|
231
|
+
: agent.systemPrompt;
|
|
232
|
+
|
|
233
|
+
// Use agent defaults directly - user overrides happen in createConfigHandler
|
|
133
234
|
result[agent.displayName] = {
|
|
134
235
|
description: agent.description,
|
|
135
|
-
model:
|
|
136
|
-
prompt
|
|
236
|
+
model: agent.defaultModel,
|
|
237
|
+
prompt,
|
|
137
238
|
mode: agent.mode ?? 'subagent',
|
|
138
239
|
...(Object.keys(tools).length > 0 ? { tools } : {}),
|
|
139
|
-
// Pass through thinking/reasoning settings
|
|
140
240
|
...(agent.variant ? { variant: agent.variant } : {}),
|
|
141
241
|
...(agent.temperature !== undefined ? { temperature: agent.temperature } : {}),
|
|
142
242
|
...(agent.maxSteps !== undefined ? { maxSteps: agent.maxSteps } : {}),
|
|
243
|
+
...(agent.reasoningEffort ? { reasoningEffort: agent.reasoningEffort } : {}),
|
|
244
|
+
...(agent.thinking ? { thinking: agent.thinking } : {}),
|
|
143
245
|
};
|
|
144
246
|
}
|
|
145
247
|
|
|
@@ -158,20 +260,24 @@ You are the Agentuity Coder Lead agent orchestrating the Agentuity Coder team.
|
|
|
158
260
|
## Your Team (use @mentions to invoke)
|
|
159
261
|
- **@Agentuity Coder Scout**: Explore codebase, find patterns, research docs (read-only)
|
|
160
262
|
- **@Agentuity Coder Builder**: Implement features, write code, run tests
|
|
263
|
+
- **@Agentuity Coder Architect**: Complex autonomous tasks, Cadence mode (GPT Codex)
|
|
161
264
|
- **@Agentuity Coder Reviewer**: Review changes, catch issues, apply fixes
|
|
162
265
|
- **@Agentuity Coder Memory**: Store context, remember decisions
|
|
163
266
|
- **@Agentuity Coder Expert**: Agentuity CLI and cloud services specialist
|
|
267
|
+
- **@Agentuity Coder Planner**: Deep planning for complex architecture decisions
|
|
268
|
+
- **@Agentuity Coder Runner**: Run lint/build/test commands, returns structured results
|
|
164
269
|
|
|
165
270
|
## Task
|
|
166
271
|
$ARGUMENTS
|
|
167
272
|
|
|
168
273
|
## Guidelines
|
|
169
274
|
1. Use @Agentuity Coder Scout first to understand context
|
|
170
|
-
2. Delegate implementation to @Agentuity Coder Builder
|
|
171
|
-
3.
|
|
172
|
-
4.
|
|
173
|
-
5.
|
|
174
|
-
6.
|
|
275
|
+
2. Delegate implementation to @Agentuity Coder Builder (or Architect for complex work)
|
|
276
|
+
3. Delegate lint/build/test commands to @Agentuity Coder Runner for structured results
|
|
277
|
+
4. Have @Agentuity Coder Reviewer check the work
|
|
278
|
+
5. Use @Agentuity Coder Expert for Agentuity CLI questions
|
|
279
|
+
6. Only use cloud services when genuinely helpful
|
|
280
|
+
7. **When done, tell @Agentuity Coder Memory to memorialize the session**
|
|
175
281
|
</coder-mode>`,
|
|
176
282
|
agent: 'Agentuity Coder Lead',
|
|
177
283
|
argumentHint: '"task description"',
|
|
@@ -289,10 +395,13 @@ You are the Agentuity Coder Lead in **Cadence mode** — a long-running autonomo
|
|
|
289
395
|
|
|
290
396
|
## Your Team (use @mentions to invoke)
|
|
291
397
|
- **@Agentuity Coder Scout**: Explore codebase, find patterns, research docs (read-only)
|
|
292
|
-
- **@Agentuity Coder
|
|
398
|
+
- **@Agentuity Coder Architect**: Complex autonomous implementation (GPT Codex with high reasoning) — **USE THIS FOR CADENCE**
|
|
399
|
+
- **@Agentuity Coder Builder**: Quick fixes, simple changes (for minor iterations only)
|
|
293
400
|
- **@Agentuity Coder Reviewer**: Review changes, catch issues, apply fixes
|
|
294
401
|
- **@Agentuity Coder Memory**: Store context, remember decisions, checkpoints
|
|
295
402
|
- **@Agentuity Coder Expert**: Agentuity CLI and cloud services specialist
|
|
403
|
+
- **@Agentuity Coder Planner**: Deep planning for complex architecture decisions
|
|
404
|
+
- **@Agentuity Coder Runner**: Run lint/build/test commands, returns structured results
|
|
296
405
|
|
|
297
406
|
## Task
|
|
298
407
|
$ARGUMENTS
|
|
@@ -306,7 +415,8 @@ $ARGUMENTS
|
|
|
306
415
|
2. **Each iteration**:
|
|
307
416
|
- Ask @Agentuity Coder Memory for relevant context
|
|
308
417
|
- Use @Agentuity Coder Scout to understand what's needed
|
|
309
|
-
-
|
|
418
|
+
- For complex planning, consult @Agentuity Coder Planner
|
|
419
|
+
- Delegate implementation to **@Agentuity Coder Architect** (preferred for Cadence)
|
|
310
420
|
- Have @Agentuity Coder Reviewer verify the work
|
|
311
421
|
- Tell @Agentuity Coder Memory to store checkpoint
|
|
312
422
|
|
|
@@ -318,10 +428,11 @@ $ARGUMENTS
|
|
|
318
428
|
4. **Tell @Agentuity Coder Memory to memorialize** the completed session
|
|
319
429
|
|
|
320
430
|
## Guidelines
|
|
321
|
-
- **
|
|
431
|
+
- **Use Architect for implementation** — Architect has GPT Codex with maximum reasoning, ideal for autonomous work
|
|
432
|
+
- Use regular Builder only for trivial fixes within an iteration
|
|
322
433
|
- Ask Memory for context at each iteration start
|
|
323
434
|
- Store checkpoints at each iteration end
|
|
324
|
-
- If stuck
|
|
435
|
+
- If stuck on architecture, consult Planner before trying more approaches
|
|
325
436
|
- Use @Agentuity Coder Expert for sandbox/cloud operations
|
|
326
437
|
- Respect max iterations (50 default)`,
|
|
327
438
|
agent: 'Agentuity Coder Lead',
|
|
@@ -330,40 +441,178 @@ $ARGUMENTS
|
|
|
330
441
|
};
|
|
331
442
|
}
|
|
332
443
|
|
|
333
|
-
function
|
|
334
|
-
const
|
|
444
|
+
function createSkillCommands(skills: LoadedSkill[]): Record<string, CommandDefinition> {
|
|
445
|
+
const commands: Record<string, CommandDefinition> = {};
|
|
446
|
+
|
|
447
|
+
for (const skill of skills) {
|
|
448
|
+
const baseDir = normalizeBaseDir(skill.resolvedPath);
|
|
449
|
+
commands[skill.name] = {
|
|
450
|
+
name: skill.name,
|
|
451
|
+
description: skill.metadata.description,
|
|
452
|
+
template: `<skill-instruction>
|
|
453
|
+
Base directory for this skill: ${baseDir}/
|
|
454
|
+
File references (@path) in this skill are relative to this directory.
|
|
455
|
+
|
|
456
|
+
${skill.content}
|
|
457
|
+
</skill-instruction>
|
|
458
|
+
|
|
459
|
+
<user-request>
|
|
460
|
+
$ARGUMENTS
|
|
461
|
+
</user-request>`,
|
|
462
|
+
...(skill.metadata.agent ? { agent: skill.metadata.agent } : {}),
|
|
463
|
+
...(skill.metadata.model ? { model: skill.metadata.model } : {}),
|
|
464
|
+
...(skill.metadata['argument-hint']
|
|
465
|
+
? { argumentHint: skill.metadata['argument-hint'] }
|
|
466
|
+
: {}),
|
|
467
|
+
...(skill.metadata.subtask ? { subtask: true } : {}),
|
|
468
|
+
};
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
return commands;
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
function normalizeBaseDir(path: string): string {
|
|
475
|
+
return path.replace(/[\\/]+$/, '');
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
function createTools(backgroundManager: BackgroundManager): Hooks['tool'] {
|
|
479
|
+
// Use the schema from @opencode-ai/plugin's tool helper to avoid Zod version mismatches
|
|
480
|
+
const s = tool.schema;
|
|
481
|
+
|
|
482
|
+
const coderDelegate = tool({
|
|
335
483
|
description: `Delegate a task to a specialized Agentuity Coder agent.
|
|
336
484
|
|
|
337
485
|
Use this to:
|
|
338
486
|
- Scout: Explore codebase, find patterns, research documentation
|
|
339
|
-
- Builder: Implement features, write code, run tests
|
|
487
|
+
- Builder: Implement features, write code, run tests (interactive work)
|
|
488
|
+
- Architect: Complex autonomous tasks, Cadence mode, deep reasoning (GPT Codex)
|
|
340
489
|
- Reviewer: Review changes, catch issues, apply fixes
|
|
341
490
|
- Memory: Store context, remember decisions across sessions
|
|
342
|
-
- Expert: Get help with Agentuity CLI and cloud services
|
|
343
|
-
|
|
491
|
+
- Expert: Get help with Agentuity CLI and cloud services
|
|
492
|
+
- Planner: Strategic advisor for complex architecture and deep planning (read-only)`,
|
|
493
|
+
args: {
|
|
344
494
|
agent: s
|
|
345
|
-
.enum([
|
|
495
|
+
.enum([
|
|
496
|
+
'scout',
|
|
497
|
+
'builder',
|
|
498
|
+
'architect',
|
|
499
|
+
'reviewer',
|
|
500
|
+
'memory',
|
|
501
|
+
'expert',
|
|
502
|
+
'planner',
|
|
503
|
+
'runner',
|
|
504
|
+
])
|
|
346
505
|
.describe('Which agent to delegate to'),
|
|
347
506
|
task: s.string().describe('Clear description of the task'),
|
|
348
507
|
context: s.string().optional().describe('Additional context from previous tasks'),
|
|
349
|
-
}
|
|
350
|
-
|
|
351
|
-
const mention = AGENT_MENTIONS[args.agent];
|
|
508
|
+
},
|
|
509
|
+
async execute(args) {
|
|
510
|
+
const mention = AGENT_MENTIONS[args.agent as AgentRole];
|
|
352
511
|
let prompt = `${mention}\n\n## Task\n${args.task}`;
|
|
353
512
|
if (args.context) {
|
|
354
513
|
prompt = `${mention}\n\n## Context\n${args.context}\n\n## Task\n${args.task}`;
|
|
355
514
|
}
|
|
356
|
-
return {
|
|
357
|
-
|
|
358
|
-
|
|
515
|
+
return `To delegate this task, use the Task tool with this prompt:\n\n${prompt}\n\nThe ${args.agent} agent will handle this task.`;
|
|
516
|
+
},
|
|
517
|
+
});
|
|
518
|
+
|
|
519
|
+
const backgroundTask = tool({
|
|
520
|
+
description: `Launch a task to run in the background. Use this for parallel execution of multiple independent tasks.
|
|
521
|
+
|
|
522
|
+
IMPORTANT: Use this tool instead of the 'task' tool when:
|
|
523
|
+
- You need to run multiple agents in parallel
|
|
524
|
+
- Tasks are independent and don't need sequential execution
|
|
525
|
+
- The user asks for "parallel", "background", or "concurrent" work`,
|
|
526
|
+
args: {
|
|
527
|
+
agent: s
|
|
528
|
+
.enum([
|
|
529
|
+
'lead',
|
|
530
|
+
'scout',
|
|
531
|
+
'builder',
|
|
532
|
+
'architect',
|
|
533
|
+
'reviewer',
|
|
534
|
+
'memory',
|
|
535
|
+
'expert',
|
|
536
|
+
'planner',
|
|
537
|
+
'runner',
|
|
538
|
+
])
|
|
539
|
+
.describe('Agent role to run the task'),
|
|
540
|
+
task: s.string().describe('Task prompt to run in the background'),
|
|
541
|
+
description: s.string().optional().describe('Short description of the task'),
|
|
542
|
+
},
|
|
543
|
+
async execute(args, context) {
|
|
544
|
+
const parentSessionId = context.sessionID;
|
|
545
|
+
if (!parentSessionId) {
|
|
546
|
+
return JSON.stringify({
|
|
547
|
+
taskId: 'unknown',
|
|
548
|
+
status: 'error',
|
|
549
|
+
message: 'Missing session context for background task.',
|
|
550
|
+
});
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
const agentName = resolveAgentName(args.agent as AgentRole);
|
|
554
|
+
const bgTask = await backgroundManager.launch({
|
|
555
|
+
description: args.description ?? args.task,
|
|
556
|
+
prompt: args.task,
|
|
557
|
+
agent: agentName,
|
|
558
|
+
parentSessionId,
|
|
559
|
+
parentMessageId: context.messageID,
|
|
560
|
+
});
|
|
561
|
+
return JSON.stringify({
|
|
562
|
+
taskId: bgTask.id,
|
|
563
|
+
status: bgTask.status,
|
|
564
|
+
message:
|
|
565
|
+
bgTask.status === 'error'
|
|
566
|
+
? (bgTask.error ?? 'Failed to launch background task.')
|
|
567
|
+
: 'Background task launched.',
|
|
568
|
+
});
|
|
569
|
+
},
|
|
570
|
+
});
|
|
571
|
+
|
|
572
|
+
const backgroundOutput = tool({
|
|
573
|
+
description: 'Retrieve output for a background task.',
|
|
574
|
+
args: {
|
|
575
|
+
task_id: s.string().describe('Background task ID'),
|
|
576
|
+
},
|
|
577
|
+
async execute(args) {
|
|
578
|
+
const bgTask = backgroundManager.getTask(args.task_id);
|
|
579
|
+
if (!bgTask) {
|
|
580
|
+
return JSON.stringify({
|
|
581
|
+
taskId: args.task_id,
|
|
582
|
+
status: 'error',
|
|
583
|
+
error: 'Task not found.',
|
|
584
|
+
});
|
|
585
|
+
}
|
|
586
|
+
return JSON.stringify({
|
|
587
|
+
taskId: bgTask.id,
|
|
588
|
+
status: bgTask.status,
|
|
589
|
+
result: bgTask.result,
|
|
590
|
+
error: bgTask.error,
|
|
591
|
+
});
|
|
359
592
|
},
|
|
360
|
-
})
|
|
593
|
+
});
|
|
594
|
+
|
|
595
|
+
const backgroundCancel = tool({
|
|
596
|
+
description: 'Cancel a running background task.',
|
|
597
|
+
args: {
|
|
598
|
+
task_id: s.string().describe('Background task ID'),
|
|
599
|
+
},
|
|
600
|
+
async execute(args) {
|
|
601
|
+
const success = backgroundManager.cancel(args.task_id);
|
|
602
|
+
return JSON.stringify({
|
|
603
|
+
taskId: args.task_id,
|
|
604
|
+
success,
|
|
605
|
+
message: success ? 'Background task cancelled.' : 'Unable to cancel task.',
|
|
606
|
+
});
|
|
607
|
+
},
|
|
608
|
+
});
|
|
361
609
|
|
|
362
|
-
// Type assertion needed because the tool() helper returns unknown
|
|
363
|
-
// but the runtime type is correct (it's created by OpenCode's tool helper)
|
|
364
610
|
return {
|
|
365
611
|
coder_delegate: coderDelegate,
|
|
366
|
-
|
|
612
|
+
background_task: backgroundTask,
|
|
613
|
+
background_output: backgroundOutput,
|
|
614
|
+
background_cancel: backgroundCancel,
|
|
615
|
+
};
|
|
367
616
|
}
|
|
368
617
|
|
|
369
618
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
@@ -381,3 +630,35 @@ function extractSessionIdFromEvent(input: unknown): string | undefined {
|
|
|
381
630
|
(inp.event.properties.sessionID as string | undefined)
|
|
382
631
|
);
|
|
383
632
|
}
|
|
633
|
+
|
|
634
|
+
function resolveAgentName(role: AgentRole): string {
|
|
635
|
+
const agent = agents[role];
|
|
636
|
+
return agent?.displayName ?? role;
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
function extractEventFromInput(
|
|
640
|
+
input: unknown
|
|
641
|
+
): { type: string; properties?: Record<string, unknown> } | undefined {
|
|
642
|
+
if (typeof input !== 'object' || input === null) return undefined;
|
|
643
|
+
const inp = input as { event?: { type?: string; properties?: Record<string, unknown> } };
|
|
644
|
+
if (!inp.event || typeof inp.event.type !== 'string') return undefined;
|
|
645
|
+
return { type: inp.event.type, properties: inp.event.properties };
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
function registerShutdownHandler(
|
|
649
|
+
manager: BackgroundManager,
|
|
650
|
+
tmuxManager?: TmuxSessionManager
|
|
651
|
+
): void {
|
|
652
|
+
if (typeof process === 'undefined') return;
|
|
653
|
+
const shutdown = () => {
|
|
654
|
+
manager.shutdown();
|
|
655
|
+
if (tmuxManager) {
|
|
656
|
+
// Use sync version to ensure cleanup completes before process exits
|
|
657
|
+
tmuxManager.cleanupSync();
|
|
658
|
+
}
|
|
659
|
+
};
|
|
660
|
+
process.once('beforeExit', shutdown);
|
|
661
|
+
process.once('SIGINT', shutdown);
|
|
662
|
+
process.once('SIGTERM', shutdown);
|
|
663
|
+
process.once('exit', shutdown); // Also handle exit event for extra safety
|
|
664
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import yaml from 'yaml';
|
|
2
|
+
|
|
3
|
+
interface ParsedFrontmatter<T = Record<string, unknown>> {
|
|
4
|
+
data: T;
|
|
5
|
+
body: string;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export function parseFrontmatter<T = Record<string, unknown>>(
|
|
9
|
+
content: string
|
|
10
|
+
): ParsedFrontmatter<T> {
|
|
11
|
+
const match = content.match(/^---\r?\n([\s\S]*?)\r?\n---/);
|
|
12
|
+
if (!match) {
|
|
13
|
+
return { data: {} as T, body: content.trim() };
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const frontmatter = match[1];
|
|
17
|
+
const body = content.slice(match[0].length).trim();
|
|
18
|
+
|
|
19
|
+
try {
|
|
20
|
+
const data = yaml.parse(frontmatter) as T;
|
|
21
|
+
return { data: (data ?? {}) as T, body };
|
|
22
|
+
} catch {
|
|
23
|
+
return { data: {} as T, body: content.trim() };
|
|
24
|
+
}
|
|
25
|
+
}
|