thoth-agents 0.1.19 → 0.2.1
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 +41 -9
- package/dist/agents/prompt-dialects.d.ts +9 -0
- package/dist/{chunk-2SGSRR6L.js → chunk-3NOVCFN7.js} +61 -3
- package/dist/chunk-4WYCZ5Z7.js +698 -0
- package/dist/{chunk-7CTSLCEU.js → chunk-FRZZ25ND.js} +1450 -310
- package/dist/cli/claude-code-install.d.ts +53 -0
- package/dist/cli/claude-code-paths.d.ts +31 -0
- package/dist/cli/codex-install.d.ts +1 -5
- package/dist/cli/commands.d.ts +1 -1
- package/dist/cli/index.js +85 -27
- package/dist/cli/managed-state-io.d.ts +16 -0
- package/dist/cli/operations/claude-code.d.ts +21 -0
- package/dist/cli/tui/index.js +87 -9
- package/dist/cli/tui/operations.d.ts +2 -0
- package/dist/cli/types.d.ts +3 -3
- package/dist/config/index.d.ts +1 -1
- package/dist/config/schema.d.ts +11 -0
- package/dist/config/utils.d.ts +5 -0
- package/dist/harness/adapters/claude-code.d.ts +24 -0
- package/dist/harness/core/package-version.d.ts +7 -0
- package/dist/harness/types.d.ts +1 -1
- package/dist/harness/writers/claude-code-plugin-package.d.ts +32 -0
- package/dist/harness/writers/claude-code-skill-layout.d.ts +16 -0
- package/dist/harness/writers/claude-code-subagent.d.ts +26 -0
- package/dist/harness/writers/fs-skill-collect.d.ts +7 -0
- package/dist/index.js +4 -476
- package/package.json +1 -1
- package/thoth-agents.schema.json +16 -0
- package/dist/chunk-DYGVRAMS.js +0 -182
|
@@ -0,0 +1,698 @@
|
|
|
1
|
+
import {
|
|
2
|
+
DEFAULT_MODELS,
|
|
3
|
+
OPENCODE_PROMPT_DIALECT,
|
|
4
|
+
SUBAGENT_NAMES,
|
|
5
|
+
appendPromptSections,
|
|
6
|
+
composeAgentPrompt,
|
|
7
|
+
createOrchestratorPromptSections,
|
|
8
|
+
createReadOnlySpecialistPromptSections,
|
|
9
|
+
createWriteCapableSpecialistPromptSections,
|
|
10
|
+
detectModelFamily,
|
|
11
|
+
getAgentOverride,
|
|
12
|
+
getModelFamilyPromptSection,
|
|
13
|
+
getStepBudgetPromptSection,
|
|
14
|
+
loadAgentPrompt,
|
|
15
|
+
renderRolePrompt
|
|
16
|
+
} from "./chunk-3NOVCFN7.js";
|
|
17
|
+
|
|
18
|
+
// src/agents/deep.ts
|
|
19
|
+
var DEEP_PROMPT = renderRolePrompt(
|
|
20
|
+
createWriteCapableSpecialistPromptSections("deep"),
|
|
21
|
+
OPENCODE_PROMPT_DIALECT
|
|
22
|
+
);
|
|
23
|
+
function createDeepAgent(model, customPrompt, customAppendPrompt) {
|
|
24
|
+
const prompt = composeAgentPrompt({
|
|
25
|
+
basePrompt: DEEP_PROMPT,
|
|
26
|
+
customPrompt,
|
|
27
|
+
customAppendPrompt: appendPromptSections(
|
|
28
|
+
getModelFamilyPromptSection("deep", model),
|
|
29
|
+
customAppendPrompt
|
|
30
|
+
)
|
|
31
|
+
});
|
|
32
|
+
return {
|
|
33
|
+
name: "deep",
|
|
34
|
+
description: "Synchronous write-capable implementation agent optimized for thorough context analysis, edge cases, and correctness \u2014 not for bulk mechanical changes.",
|
|
35
|
+
config: {
|
|
36
|
+
model,
|
|
37
|
+
temperature: 0.1,
|
|
38
|
+
prompt,
|
|
39
|
+
color: "secondary"
|
|
40
|
+
// steps: 80,
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// src/agents/designer.ts
|
|
46
|
+
var DESIGNER_PROMPT = renderRolePrompt(
|
|
47
|
+
createWriteCapableSpecialistPromptSections("designer"),
|
|
48
|
+
OPENCODE_PROMPT_DIALECT
|
|
49
|
+
);
|
|
50
|
+
function createDesignerAgent(model, customPrompt, customAppendPrompt) {
|
|
51
|
+
const prompt = composeAgentPrompt({
|
|
52
|
+
basePrompt: DESIGNER_PROMPT,
|
|
53
|
+
customPrompt,
|
|
54
|
+
customAppendPrompt: appendPromptSections(
|
|
55
|
+
getModelFamilyPromptSection("designer", model),
|
|
56
|
+
customAppendPrompt
|
|
57
|
+
)
|
|
58
|
+
});
|
|
59
|
+
return {
|
|
60
|
+
name: "designer",
|
|
61
|
+
description: "Synchronous write-capable UI/UX implementation agent with ownership of approach, execution, and visual verification.",
|
|
62
|
+
config: {
|
|
63
|
+
model,
|
|
64
|
+
temperature: 0.4,
|
|
65
|
+
prompt,
|
|
66
|
+
color: "accent"
|
|
67
|
+
// steps: 50,
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// src/agents/explorer.ts
|
|
73
|
+
var EXPLORER_PROMPT = renderRolePrompt(
|
|
74
|
+
createReadOnlySpecialistPromptSections("explorer"),
|
|
75
|
+
OPENCODE_PROMPT_DIALECT
|
|
76
|
+
);
|
|
77
|
+
function createExplorerAgent(model, customPrompt, customAppendPrompt) {
|
|
78
|
+
const prompt = composeAgentPrompt({
|
|
79
|
+
basePrompt: EXPLORER_PROMPT,
|
|
80
|
+
customPrompt,
|
|
81
|
+
customAppendPrompt: appendPromptSections(
|
|
82
|
+
getModelFamilyPromptSection("explorer", model),
|
|
83
|
+
customAppendPrompt
|
|
84
|
+
)
|
|
85
|
+
});
|
|
86
|
+
return {
|
|
87
|
+
name: "explorer",
|
|
88
|
+
description: "Read-only local discovery agent for fast codebase search, references, and repository mapping.",
|
|
89
|
+
config: {
|
|
90
|
+
model,
|
|
91
|
+
temperature: 0.1,
|
|
92
|
+
prompt,
|
|
93
|
+
color: "info"
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// src/agents/librarian.ts
|
|
99
|
+
var LIBRARIAN_PROMPT = renderRolePrompt(
|
|
100
|
+
createReadOnlySpecialistPromptSections("librarian"),
|
|
101
|
+
OPENCODE_PROMPT_DIALECT
|
|
102
|
+
);
|
|
103
|
+
function createLibrarianAgent(model, customPrompt, customAppendPrompt) {
|
|
104
|
+
const prompt = composeAgentPrompt({
|
|
105
|
+
basePrompt: LIBRARIAN_PROMPT,
|
|
106
|
+
customPrompt,
|
|
107
|
+
customAppendPrompt: appendPromptSections(
|
|
108
|
+
getModelFamilyPromptSection("librarian", model),
|
|
109
|
+
customAppendPrompt
|
|
110
|
+
)
|
|
111
|
+
});
|
|
112
|
+
return {
|
|
113
|
+
name: "librarian",
|
|
114
|
+
description: "Read-only research agent for official docs, public examples, and externally sourced implementation guidance.",
|
|
115
|
+
config: {
|
|
116
|
+
model,
|
|
117
|
+
temperature: 0.1,
|
|
118
|
+
prompt,
|
|
119
|
+
color: "info"
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// src/agents/oracle.ts
|
|
125
|
+
var ORACLE_PROMPT = renderRolePrompt(
|
|
126
|
+
createReadOnlySpecialistPromptSections("oracle"),
|
|
127
|
+
OPENCODE_PROMPT_DIALECT
|
|
128
|
+
);
|
|
129
|
+
function createOracleAgent(model, customPrompt, customAppendPrompt) {
|
|
130
|
+
const prompt = composeAgentPrompt({
|
|
131
|
+
basePrompt: ORACLE_PROMPT,
|
|
132
|
+
customPrompt,
|
|
133
|
+
customAppendPrompt: appendPromptSections(
|
|
134
|
+
getModelFamilyPromptSection("oracle", model),
|
|
135
|
+
customAppendPrompt
|
|
136
|
+
)
|
|
137
|
+
});
|
|
138
|
+
return {
|
|
139
|
+
name: "oracle",
|
|
140
|
+
description: "Synchronous read-only strategic advisor for debugging, architecture, code review, and SDD plan review.",
|
|
141
|
+
config: {
|
|
142
|
+
model,
|
|
143
|
+
temperature: 0.1,
|
|
144
|
+
prompt,
|
|
145
|
+
color: "warning"
|
|
146
|
+
}
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// src/agents/orchestrator.ts
|
|
151
|
+
var OPENCODE_RUNTIME_SECTION = `<opencode-runtime>
|
|
152
|
+
In the OpenCode harness, an automatic \`<reminder>...</reminder>\` workflow block followed by a \`\\n\\n---\\n\\n\` separator is prepended to your user messages as harness scaffolding, not user input.
|
|
153
|
+
When saving the user prompt via mem_save(kind="prompt"), you MUST exclude that injected \`<reminder>\` block and the \`---\` separator, and persist only the real user request text that follows.
|
|
154
|
+
</opencode-runtime>`;
|
|
155
|
+
var ORCHESTRATOR_PROMPT = appendPromptSections(
|
|
156
|
+
renderRolePrompt(createOrchestratorPromptSections(), OPENCODE_PROMPT_DIALECT),
|
|
157
|
+
OPENCODE_RUNTIME_SECTION
|
|
158
|
+
);
|
|
159
|
+
function createOrchestratorAgent(model, customPrompt, customAppendPrompt) {
|
|
160
|
+
const prompt = composeAgentPrompt({
|
|
161
|
+
basePrompt: ORCHESTRATOR_PROMPT,
|
|
162
|
+
customPrompt,
|
|
163
|
+
customAppendPrompt: appendPromptSections(
|
|
164
|
+
getModelFamilyPromptSection("orchestrator", model),
|
|
165
|
+
customAppendPrompt
|
|
166
|
+
)
|
|
167
|
+
});
|
|
168
|
+
const definition = {
|
|
169
|
+
name: "orchestrator",
|
|
170
|
+
description: "Delegate-first coordinator for SDD workflow, specialist dispatch, and root-session memory ownership.",
|
|
171
|
+
config: {
|
|
172
|
+
temperature: 0.1,
|
|
173
|
+
prompt,
|
|
174
|
+
color: "primary"
|
|
175
|
+
// steps: 100,
|
|
176
|
+
}
|
|
177
|
+
};
|
|
178
|
+
if (Array.isArray(model)) {
|
|
179
|
+
definition._modelArray = model.map(
|
|
180
|
+
(entry) => typeof entry === "string" ? { id: entry } : entry
|
|
181
|
+
);
|
|
182
|
+
} else if (typeof model === "string" && model) {
|
|
183
|
+
definition.config.model = model;
|
|
184
|
+
}
|
|
185
|
+
return definition;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// src/agents/quick.ts
|
|
189
|
+
var QUICK_PROMPT = renderRolePrompt(
|
|
190
|
+
createWriteCapableSpecialistPromptSections("quick"),
|
|
191
|
+
OPENCODE_PROMPT_DIALECT
|
|
192
|
+
);
|
|
193
|
+
function createQuickAgent(model, customPrompt, customAppendPrompt) {
|
|
194
|
+
const prompt = composeAgentPrompt({
|
|
195
|
+
basePrompt: QUICK_PROMPT,
|
|
196
|
+
customPrompt,
|
|
197
|
+
customAppendPrompt: appendPromptSections(
|
|
198
|
+
getModelFamilyPromptSection("quick", model),
|
|
199
|
+
customAppendPrompt
|
|
200
|
+
)
|
|
201
|
+
});
|
|
202
|
+
return {
|
|
203
|
+
name: "quick",
|
|
204
|
+
description: "Synchronous write-capable implementation agent optimized for fast, mechanical, well-bounded changes \u2014 including uniform patterns across multiple files.",
|
|
205
|
+
config: {
|
|
206
|
+
model,
|
|
207
|
+
temperature: 0.2,
|
|
208
|
+
prompt,
|
|
209
|
+
color: "success"
|
|
210
|
+
// steps: 30,
|
|
211
|
+
}
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
// src/agents/index.ts
|
|
216
|
+
var GEMINI_DEFAULT_STEPS = {
|
|
217
|
+
explorer: 120,
|
|
218
|
+
librarian: 80,
|
|
219
|
+
oracle: 80,
|
|
220
|
+
designer: 80,
|
|
221
|
+
quick: 40,
|
|
222
|
+
deep: 120
|
|
223
|
+
};
|
|
224
|
+
var BUILTIN_PERMISSION_PRESETS = {
|
|
225
|
+
orchestrator: {
|
|
226
|
+
read: "allow",
|
|
227
|
+
edit: "allow",
|
|
228
|
+
write: "allow",
|
|
229
|
+
glob: "allow",
|
|
230
|
+
grep: "allow",
|
|
231
|
+
list: "allow",
|
|
232
|
+
bash: "allow",
|
|
233
|
+
codesearch: "allow",
|
|
234
|
+
lsp: "allow",
|
|
235
|
+
skill: "allow",
|
|
236
|
+
question: "allow",
|
|
237
|
+
webfetch: "allow",
|
|
238
|
+
exa: "allow",
|
|
239
|
+
todowrite: "allow",
|
|
240
|
+
task: "allow",
|
|
241
|
+
external_directory: "allow"
|
|
242
|
+
},
|
|
243
|
+
explorer: {
|
|
244
|
+
read: "allow",
|
|
245
|
+
glob: "allow",
|
|
246
|
+
grep: "allow",
|
|
247
|
+
list: "allow",
|
|
248
|
+
codesearch: "allow",
|
|
249
|
+
lsp: "allow",
|
|
250
|
+
external_directory: "allow",
|
|
251
|
+
bash: "allow",
|
|
252
|
+
question: "allow",
|
|
253
|
+
skill: "allow",
|
|
254
|
+
edit: "deny",
|
|
255
|
+
todowrite: "deny",
|
|
256
|
+
task: "deny"
|
|
257
|
+
},
|
|
258
|
+
librarian: {
|
|
259
|
+
read: "allow",
|
|
260
|
+
glob: "allow",
|
|
261
|
+
grep: "allow",
|
|
262
|
+
external_directory: "allow",
|
|
263
|
+
bash: "allow",
|
|
264
|
+
webfetch: "allow",
|
|
265
|
+
exa: "allow",
|
|
266
|
+
codesearch: "allow",
|
|
267
|
+
question: "allow",
|
|
268
|
+
skill: "allow",
|
|
269
|
+
edit: "deny",
|
|
270
|
+
todowrite: "deny",
|
|
271
|
+
task: "deny"
|
|
272
|
+
},
|
|
273
|
+
oracle: {
|
|
274
|
+
read: "allow",
|
|
275
|
+
glob: "allow",
|
|
276
|
+
grep: "allow",
|
|
277
|
+
list: "allow",
|
|
278
|
+
lsp: "allow",
|
|
279
|
+
codesearch: "allow",
|
|
280
|
+
webfetch: "allow",
|
|
281
|
+
exa: "allow",
|
|
282
|
+
external_directory: "allow",
|
|
283
|
+
bash: "allow",
|
|
284
|
+
question: "allow",
|
|
285
|
+
skill: "allow",
|
|
286
|
+
edit: "deny",
|
|
287
|
+
todowrite: "deny",
|
|
288
|
+
task: "deny"
|
|
289
|
+
},
|
|
290
|
+
designer: {
|
|
291
|
+
read: "allow",
|
|
292
|
+
edit: "allow",
|
|
293
|
+
glob: "allow",
|
|
294
|
+
grep: "allow",
|
|
295
|
+
list: "allow",
|
|
296
|
+
bash: "allow",
|
|
297
|
+
codesearch: "allow",
|
|
298
|
+
lsp: "allow",
|
|
299
|
+
skill: "allow",
|
|
300
|
+
question: "allow",
|
|
301
|
+
todowrite: "deny",
|
|
302
|
+
task: "deny",
|
|
303
|
+
external_directory: {
|
|
304
|
+
"~/.config/opencode/skills/**": "allow"
|
|
305
|
+
}
|
|
306
|
+
},
|
|
307
|
+
quick: {
|
|
308
|
+
read: "allow",
|
|
309
|
+
edit: "allow",
|
|
310
|
+
glob: "allow",
|
|
311
|
+
grep: "allow",
|
|
312
|
+
list: "allow",
|
|
313
|
+
bash: "allow",
|
|
314
|
+
question: "allow",
|
|
315
|
+
codesearch: "allow",
|
|
316
|
+
lsp: "allow",
|
|
317
|
+
skill: "allow",
|
|
318
|
+
todowrite: "deny",
|
|
319
|
+
task: "deny",
|
|
320
|
+
external_directory: {
|
|
321
|
+
"~/.config/opencode/skills/**": "allow"
|
|
322
|
+
}
|
|
323
|
+
},
|
|
324
|
+
deep: {
|
|
325
|
+
read: "allow",
|
|
326
|
+
edit: "allow",
|
|
327
|
+
glob: "allow",
|
|
328
|
+
grep: "allow",
|
|
329
|
+
list: "allow",
|
|
330
|
+
bash: "allow",
|
|
331
|
+
codesearch: "allow",
|
|
332
|
+
lsp: "allow",
|
|
333
|
+
skill: "allow",
|
|
334
|
+
question: "allow",
|
|
335
|
+
webfetch: "allow",
|
|
336
|
+
exa: "allow",
|
|
337
|
+
todowrite: "deny",
|
|
338
|
+
task: "deny",
|
|
339
|
+
external_directory: {
|
|
340
|
+
"~/.config/opencode/skills/**": "allow"
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
};
|
|
344
|
+
function normalizeModelArray(model) {
|
|
345
|
+
return model.map(
|
|
346
|
+
(entry) => typeof entry === "string" ? { id: entry } : entry
|
|
347
|
+
);
|
|
348
|
+
}
|
|
349
|
+
function applyOverrides(agent, override) {
|
|
350
|
+
if (override.model) {
|
|
351
|
+
if (Array.isArray(override.model)) {
|
|
352
|
+
agent._modelArray = normalizeModelArray(override.model);
|
|
353
|
+
agent.config.model = void 0;
|
|
354
|
+
} else {
|
|
355
|
+
agent.config.model = override.model;
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
if (override.variant) {
|
|
359
|
+
agent.config.variant = override.variant;
|
|
360
|
+
}
|
|
361
|
+
if (override.temperature !== void 0) {
|
|
362
|
+
agent.config.temperature = override.temperature;
|
|
363
|
+
}
|
|
364
|
+
if (override.steps !== void 0) {
|
|
365
|
+
agent.config.steps = override.steps;
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
function applyStepBudgetPrompt(agent) {
|
|
369
|
+
const stepBudgetPrompt = getStepBudgetPromptSection(agent.config.steps);
|
|
370
|
+
if (!stepBudgetPrompt) {
|
|
371
|
+
return;
|
|
372
|
+
}
|
|
373
|
+
agent.config.prompt = appendPromptSections(
|
|
374
|
+
agent.config.prompt,
|
|
375
|
+
stepBudgetPrompt
|
|
376
|
+
);
|
|
377
|
+
}
|
|
378
|
+
function applyGeminiDefaultSteps(agent) {
|
|
379
|
+
if (!isSubagent(agent.name) || agent.config.steps !== void 0) {
|
|
380
|
+
return;
|
|
381
|
+
}
|
|
382
|
+
if (detectModelFamily(agent._modelArray ?? agent.config.model) !== "gemini") {
|
|
383
|
+
return;
|
|
384
|
+
}
|
|
385
|
+
agent.config.steps = GEMINI_DEFAULT_STEPS[agent.name];
|
|
386
|
+
}
|
|
387
|
+
function clonePermissionConfig(permission) {
|
|
388
|
+
if (typeof permission === "string") {
|
|
389
|
+
return permission;
|
|
390
|
+
}
|
|
391
|
+
return Object.fromEntries(
|
|
392
|
+
Object.entries(permission).map(([key, value]) => [
|
|
393
|
+
key,
|
|
394
|
+
value && typeof value === "object" && !Array.isArray(value) ? { ...value } : value
|
|
395
|
+
])
|
|
396
|
+
);
|
|
397
|
+
}
|
|
398
|
+
function getBuiltinPermissionPreset(name) {
|
|
399
|
+
return clonePermissionConfig(BUILTIN_PERMISSION_PRESETS[name]);
|
|
400
|
+
}
|
|
401
|
+
function getExplicitPermissionOverride(override) {
|
|
402
|
+
return override?.permission;
|
|
403
|
+
}
|
|
404
|
+
function getPrimaryModelForPrompt(model) {
|
|
405
|
+
if (Array.isArray(model)) {
|
|
406
|
+
const first = model[0];
|
|
407
|
+
return typeof first === "string" ? first : first?.id;
|
|
408
|
+
}
|
|
409
|
+
return model;
|
|
410
|
+
}
|
|
411
|
+
function isSubagent(name) {
|
|
412
|
+
return SUBAGENT_NAMES.includes(name);
|
|
413
|
+
}
|
|
414
|
+
var SUBAGENT_FACTORIES = {
|
|
415
|
+
explorer: createExplorerAgent,
|
|
416
|
+
librarian: createLibrarianAgent,
|
|
417
|
+
oracle: createOracleAgent,
|
|
418
|
+
designer: createDesignerAgent,
|
|
419
|
+
quick: createQuickAgent,
|
|
420
|
+
deep: createDeepAgent
|
|
421
|
+
};
|
|
422
|
+
function createAgents(config) {
|
|
423
|
+
const protoSubAgents = Object.entries(SUBAGENT_FACTORIES).map(([name, factory]) => {
|
|
424
|
+
const override = getAgentOverride(config, name);
|
|
425
|
+
const prompts = loadAgentPrompt(name, config?.preset);
|
|
426
|
+
const model = getPrimaryModelForPrompt(override?.model) ?? DEFAULT_MODELS[name];
|
|
427
|
+
return factory(model, prompts.prompt, prompts.appendPrompt);
|
|
428
|
+
});
|
|
429
|
+
const allSubAgents = protoSubAgents.map((agent) => {
|
|
430
|
+
const override = getAgentOverride(config, agent.name);
|
|
431
|
+
if (override) {
|
|
432
|
+
applyOverrides(agent, override);
|
|
433
|
+
}
|
|
434
|
+
applyGeminiDefaultSteps(agent);
|
|
435
|
+
applyStepBudgetPrompt(agent);
|
|
436
|
+
return agent;
|
|
437
|
+
});
|
|
438
|
+
const orchestratorOverride = getAgentOverride(config, "orchestrator");
|
|
439
|
+
const orchestratorPrompts = loadAgentPrompt("orchestrator", config?.preset);
|
|
440
|
+
const orchestrator = createOrchestratorAgent(
|
|
441
|
+
orchestratorOverride?.model ?? DEFAULT_MODELS.orchestrator,
|
|
442
|
+
orchestratorPrompts.prompt,
|
|
443
|
+
orchestratorPrompts.appendPrompt
|
|
444
|
+
);
|
|
445
|
+
if (orchestratorOverride) {
|
|
446
|
+
applyOverrides(orchestrator, orchestratorOverride);
|
|
447
|
+
}
|
|
448
|
+
applyStepBudgetPrompt(orchestrator);
|
|
449
|
+
return [orchestrator, ...allSubAgents];
|
|
450
|
+
}
|
|
451
|
+
function getAgentConfigs(config) {
|
|
452
|
+
const agents = createAgents(config);
|
|
453
|
+
return Object.fromEntries(
|
|
454
|
+
agents.map((agent) => {
|
|
455
|
+
const override = getAgentOverride(config, agent.name);
|
|
456
|
+
const sdkConfig = {
|
|
457
|
+
...agent.config,
|
|
458
|
+
description: agent.description
|
|
459
|
+
};
|
|
460
|
+
const builtinPermission = isSubagent(agent.name) ? getBuiltinPermissionPreset(agent.name) : agent.name === "orchestrator" ? getBuiltinPermissionPreset("orchestrator") : void 0;
|
|
461
|
+
const explicitPermissionOverride = getExplicitPermissionOverride(override);
|
|
462
|
+
sdkConfig.permission = explicitPermissionOverride ?? agent.config.permission ?? builtinPermission;
|
|
463
|
+
if (isSubagent(agent.name)) {
|
|
464
|
+
sdkConfig.mode = "subagent";
|
|
465
|
+
} else if (agent.name === "orchestrator") {
|
|
466
|
+
sdkConfig.mode = "primary";
|
|
467
|
+
}
|
|
468
|
+
return [agent.name, sdkConfig];
|
|
469
|
+
})
|
|
470
|
+
);
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
// src/harness/adapters/opencode.ts
|
|
474
|
+
var OPENCODE_CAPABILITIES = {
|
|
475
|
+
agentDefinitions: "supported",
|
|
476
|
+
delegatedExecution: "supported",
|
|
477
|
+
parallelDelegation: "supported",
|
|
478
|
+
runtimeHooks: "supported",
|
|
479
|
+
mcpConfiguration: "supported",
|
|
480
|
+
skillPackaging: "supported",
|
|
481
|
+
rolePermissions: "supported",
|
|
482
|
+
parentContextInjection: "supported",
|
|
483
|
+
memoryGovernanceEnforcement: "supported"
|
|
484
|
+
};
|
|
485
|
+
function renderOpenCodeAgentConfigs(config) {
|
|
486
|
+
return getAgentConfigs(config);
|
|
487
|
+
}
|
|
488
|
+
function hasOpenCodeConfig(context) {
|
|
489
|
+
return "config" in context;
|
|
490
|
+
}
|
|
491
|
+
var opencodeAdapter = {
|
|
492
|
+
id: "opencode",
|
|
493
|
+
displayName: "OpenCode",
|
|
494
|
+
capabilities: OPENCODE_CAPABILITIES,
|
|
495
|
+
render(context) {
|
|
496
|
+
const config = hasOpenCodeConfig(context) ? context.config : void 0;
|
|
497
|
+
const agents = renderOpenCodeAgentConfigs(config);
|
|
498
|
+
return {
|
|
499
|
+
harness: "opencode",
|
|
500
|
+
artifacts: [
|
|
501
|
+
{
|
|
502
|
+
harness: "opencode",
|
|
503
|
+
kind: "agent-config",
|
|
504
|
+
path: "opencode.agent.config.json",
|
|
505
|
+
description: "Current OpenCode AgentConfig output rendered through the harness adapter boundary.",
|
|
506
|
+
content: JSON.stringify(agents, null, 2)
|
|
507
|
+
}
|
|
508
|
+
],
|
|
509
|
+
diagnostics: []
|
|
510
|
+
};
|
|
511
|
+
}
|
|
512
|
+
};
|
|
513
|
+
|
|
514
|
+
// src/utils/subprocess.ts
|
|
515
|
+
import {
|
|
516
|
+
spawn as nodeSpawn,
|
|
517
|
+
spawnSync as nodeSpawnSync
|
|
518
|
+
} from "child_process";
|
|
519
|
+
import { Readable } from "stream";
|
|
520
|
+
function emptyReadableStream() {
|
|
521
|
+
return new ReadableStream({
|
|
522
|
+
start(controller) {
|
|
523
|
+
controller.close();
|
|
524
|
+
}
|
|
525
|
+
});
|
|
526
|
+
}
|
|
527
|
+
function toWebReadable(stream) {
|
|
528
|
+
if (!stream) {
|
|
529
|
+
return emptyReadableStream();
|
|
530
|
+
}
|
|
531
|
+
return Readable.toWeb(
|
|
532
|
+
stream
|
|
533
|
+
);
|
|
534
|
+
}
|
|
535
|
+
function fallbackStdin() {
|
|
536
|
+
return {
|
|
537
|
+
write: () => void 0,
|
|
538
|
+
end: () => void 0
|
|
539
|
+
};
|
|
540
|
+
}
|
|
541
|
+
function spawn(command, options = {}) {
|
|
542
|
+
const child = nodeSpawn(command[0], command.slice(1), {
|
|
543
|
+
cwd: options.cwd,
|
|
544
|
+
env: options.env,
|
|
545
|
+
stdio: [
|
|
546
|
+
options.stdin ?? "pipe",
|
|
547
|
+
options.stdout ?? "pipe",
|
|
548
|
+
options.stderr ?? "pipe"
|
|
549
|
+
]
|
|
550
|
+
});
|
|
551
|
+
const managed = {
|
|
552
|
+
stdin: child.stdin ?? fallbackStdin(),
|
|
553
|
+
stdout: toWebReadable(child.stdout),
|
|
554
|
+
stderr: toWebReadable(child.stderr),
|
|
555
|
+
exited: new Promise((resolve) => {
|
|
556
|
+
child.on("exit", (code) => {
|
|
557
|
+
managed.exitCode = code;
|
|
558
|
+
resolve(code ?? 1);
|
|
559
|
+
});
|
|
560
|
+
child.on("error", () => {
|
|
561
|
+
managed.exitCode = 1;
|
|
562
|
+
resolve(1);
|
|
563
|
+
});
|
|
564
|
+
}),
|
|
565
|
+
exitCode: child.exitCode,
|
|
566
|
+
kill: () => {
|
|
567
|
+
child.kill();
|
|
568
|
+
}
|
|
569
|
+
};
|
|
570
|
+
return managed;
|
|
571
|
+
}
|
|
572
|
+
function spawnSync(command, options = {}) {
|
|
573
|
+
const result = nodeSpawnSync(command[0], command.slice(1), {
|
|
574
|
+
cwd: options.cwd,
|
|
575
|
+
env: options.env,
|
|
576
|
+
stdio: [
|
|
577
|
+
options.stdin ?? "ignore",
|
|
578
|
+
options.stdout ?? "pipe",
|
|
579
|
+
options.stderr ?? "pipe"
|
|
580
|
+
]
|
|
581
|
+
});
|
|
582
|
+
return { exitCode: result.status };
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
// src/cli/system.ts
|
|
586
|
+
import { statSync } from "fs";
|
|
587
|
+
var cachedOpenCodePath = null;
|
|
588
|
+
function getOpenCodePaths() {
|
|
589
|
+
const home = process.env.HOME || process.env.USERPROFILE || "";
|
|
590
|
+
return [
|
|
591
|
+
// PATH (try this first)
|
|
592
|
+
"opencode",
|
|
593
|
+
// User local installations (Linux & macOS)
|
|
594
|
+
`${home}/.local/bin/opencode`,
|
|
595
|
+
`${home}/.opencode/bin/opencode`,
|
|
596
|
+
`${home}/bin/opencode`,
|
|
597
|
+
// System-wide installations
|
|
598
|
+
"/usr/local/bin/opencode",
|
|
599
|
+
"/opt/opencode/bin/opencode",
|
|
600
|
+
"/usr/bin/opencode",
|
|
601
|
+
"/bin/opencode",
|
|
602
|
+
// macOS specific
|
|
603
|
+
"/Applications/OpenCode.app/Contents/MacOS/opencode",
|
|
604
|
+
`${home}/Applications/OpenCode.app/Contents/MacOS/opencode`,
|
|
605
|
+
// Homebrew (macOS & Linux)
|
|
606
|
+
"/opt/homebrew/bin/opencode",
|
|
607
|
+
"/home/linuxbrew/.linuxbrew/bin/opencode",
|
|
608
|
+
`${home}/homebrew/bin/opencode`,
|
|
609
|
+
// macOS user Library
|
|
610
|
+
`${home}/Library/Application Support/opencode/bin/opencode`,
|
|
611
|
+
// Snap (Linux)
|
|
612
|
+
"/snap/bin/opencode",
|
|
613
|
+
"/var/snap/opencode/current/bin/opencode",
|
|
614
|
+
// Flatpak (Linux)
|
|
615
|
+
"/var/lib/flatpak/exports/bin/ai.opencode.OpenCode",
|
|
616
|
+
`${home}/.local/share/flatpak/exports/bin/ai.opencode.OpenCode`,
|
|
617
|
+
// Nix (Linux/macOS)
|
|
618
|
+
"/nix/store/opencode/bin/opencode",
|
|
619
|
+
`${home}/.nix-profile/bin/opencode`,
|
|
620
|
+
"/run/current-system/sw/bin/opencode",
|
|
621
|
+
// Cargo (Rust toolchain)
|
|
622
|
+
`${home}/.cargo/bin/opencode`,
|
|
623
|
+
// npm/npx global
|
|
624
|
+
`${home}/.npm-global/bin/opencode`,
|
|
625
|
+
"/usr/local/lib/node_modules/opencode/bin/opencode",
|
|
626
|
+
// Yarn global
|
|
627
|
+
`${home}/.yarn/bin/opencode`,
|
|
628
|
+
// PNPM
|
|
629
|
+
`${home}/.pnpm-global/bin/opencode`
|
|
630
|
+
];
|
|
631
|
+
}
|
|
632
|
+
function resolveOpenCodePath() {
|
|
633
|
+
if (cachedOpenCodePath) {
|
|
634
|
+
return cachedOpenCodePath;
|
|
635
|
+
}
|
|
636
|
+
const paths = getOpenCodePaths();
|
|
637
|
+
for (const opencodePath of paths) {
|
|
638
|
+
if (opencodePath === "opencode") continue;
|
|
639
|
+
try {
|
|
640
|
+
const stat = statSync(opencodePath);
|
|
641
|
+
if (stat.isFile()) {
|
|
642
|
+
cachedOpenCodePath = opencodePath;
|
|
643
|
+
return opencodePath;
|
|
644
|
+
}
|
|
645
|
+
} catch {
|
|
646
|
+
}
|
|
647
|
+
}
|
|
648
|
+
return "opencode";
|
|
649
|
+
}
|
|
650
|
+
async function isOpenCodeInstalled() {
|
|
651
|
+
const paths = getOpenCodePaths();
|
|
652
|
+
for (const opencodePath of paths) {
|
|
653
|
+
try {
|
|
654
|
+
const proc = spawn([opencodePath, "--version"], {
|
|
655
|
+
stdout: "pipe",
|
|
656
|
+
stderr: "pipe"
|
|
657
|
+
});
|
|
658
|
+
await proc.exited;
|
|
659
|
+
if (proc.exitCode === 0) {
|
|
660
|
+
cachedOpenCodePath = opencodePath;
|
|
661
|
+
return true;
|
|
662
|
+
}
|
|
663
|
+
} catch {
|
|
664
|
+
}
|
|
665
|
+
}
|
|
666
|
+
return false;
|
|
667
|
+
}
|
|
668
|
+
async function getOpenCodeVersion() {
|
|
669
|
+
const opencodePath = resolveOpenCodePath();
|
|
670
|
+
try {
|
|
671
|
+
const proc = spawn([opencodePath, "--version"], {
|
|
672
|
+
stdout: "pipe",
|
|
673
|
+
stderr: "pipe"
|
|
674
|
+
});
|
|
675
|
+
const output = await new Response(proc.stdout).text();
|
|
676
|
+
await proc.exited;
|
|
677
|
+
if (proc.exitCode === 0) {
|
|
678
|
+
return output.trim();
|
|
679
|
+
}
|
|
680
|
+
} catch {
|
|
681
|
+
}
|
|
682
|
+
return null;
|
|
683
|
+
}
|
|
684
|
+
function getOpenCodePath() {
|
|
685
|
+
const path = resolveOpenCodePath();
|
|
686
|
+
return path === "opencode" ? null : path;
|
|
687
|
+
}
|
|
688
|
+
|
|
689
|
+
export {
|
|
690
|
+
createAgents,
|
|
691
|
+
renderOpenCodeAgentConfigs,
|
|
692
|
+
opencodeAdapter,
|
|
693
|
+
spawn,
|
|
694
|
+
spawnSync,
|
|
695
|
+
isOpenCodeInstalled,
|
|
696
|
+
getOpenCodeVersion,
|
|
697
|
+
getOpenCodePath
|
|
698
|
+
};
|