thoth-agents 0.11.0 → 0.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -3
- package/dist/agents/agent-config.d.ts +13 -0
- package/dist/agents/index.d.ts +1 -1
- package/dist/agents/orchestrator.d.ts +1 -1
- package/dist/{chunk-5WPP6IY7.js → chunk-7F33WUSD.js} +1 -1
- package/dist/{chunk-RWQPMWEM.js → chunk-JLU3FSBT.js} +17 -2
- package/dist/chunk-MIDGZE34.js +107 -0
- package/dist/{chunk-DNPKVFOB.js → chunk-NY2IPJ7V.js} +78 -87
- package/dist/{chunk-HACUJFKI.js → chunk-QOA2AETX.js} +2 -228
- package/dist/{chunk-I5TXGNSG.js → chunk-SEF6PFM6.js} +504 -211
- package/dist/cli/config-io.d.ts +2 -2
- package/dist/cli/index.js +92 -39
- package/dist/cli/install.d.ts +1 -0
- package/dist/cli/opencode-skill-consent.d.ts +5 -0
- package/dist/cli/operations/opencode.d.ts +2 -1
- package/dist/cli/operations/types.d.ts +1 -0
- package/dist/cli/owned-skills.d.ts +16 -0
- package/dist/cli/paths.d.ts +1 -1
- package/dist/cli/providers.d.ts +1 -1
- package/dist/cli/system.d.ts +3 -1
- package/dist/cli/thoth-mem-install.d.ts +10 -10
- package/dist/cli/tui/index.js +53 -5
- package/dist/cli/tui/operations.d.ts +2 -0
- package/dist/cli/types.d.ts +2 -4
- package/dist/config/loader.d.ts +1 -1
- package/dist/config/schema.d.ts +0 -31
- package/dist/harness/adapters/opencode.d.ts +1 -1
- package/dist/hooks/delegate-task-retry/hook.d.ts +8 -8
- package/dist/hooks/foreground-fallback/index.d.ts +14 -69
- package/dist/hooks/index.d.ts +0 -2
- package/dist/hooks/json-error-recovery/hook.d.ts +2 -15
- package/dist/hooks/oracle-gate-verdict/hook.d.ts +4 -11
- package/dist/index.d.ts +7 -4
- package/dist/index.js +822 -1421
- package/dist/opencode/agents.d.ts +3 -0
- package/dist/opencode/command.d.ts +3 -0
- package/dist/opencode/context.d.ts +20 -0
- package/dist/opencode/delegation-hooks.d.ts +3 -0
- package/dist/opencode/mcp.d.ts +3 -0
- package/dist/opencode/permission-rules.d.ts +9 -0
- package/dist/opencode/permissions.d.ts +3 -0
- package/dist/opencode/session-hooks.d.ts +3 -0
- package/dist/opencode/session-state.d.ts +39 -0
- package/dist/opencode/skills.d.ts +3 -0
- package/dist/opencode/tools.d.ts +3 -0
- package/dist/pi.js +3 -3
- package/dist/tools/ast-grep/cli.d.ts +1 -0
- package/dist/tools/ast-grep/index.d.ts +108 -2
- package/dist/tools/ast-grep/tools.d.ts +107 -3
- package/dist/tools/define-tool.d.ts +23 -0
- package/dist/tools/lsp/tools.d.ts +97 -5
- package/dist/utils/index.d.ts +0 -1
- package/package.json +14 -3
- package/plugin/.claude-plugin/plugin.json +1 -1
- package/plugin/.codex-plugin/plugin.json +1 -1
- package/plugin/skills/thoth-sdd/SKILL.md +8 -2
- package/plugin/skills/thoth-sdd/scripts/validate-result.mjs +28 -2
- package/skills/thoth-sdd/SKILL.md +8 -2
- package/skills/thoth-sdd/scripts/validate-result.mjs +28 -2
- package/thoth-agents.schema.json +0 -26
- package/dist/chunk-62L3ORXN.js +0 -30
- package/dist/delegation/project-id.d.ts +0 -10
- package/dist/hooks/auto-update-checker/checker.d.ts +0 -23
- package/dist/hooks/auto-update-checker/constants.d.ts +0 -11
- package/dist/hooks/auto-update-checker/index.d.ts +0 -17
- package/dist/hooks/auto-update-checker/types.d.ts +0 -22
- package/dist/utils/tmux-session-manager.d.ts +0 -63
- package/dist/utils/tmux.d.ts +0 -32
package/README.md
CHANGED
|
@@ -46,7 +46,10 @@ verification you can follow—without manually coordinating every agent.
|
|
|
46
46
|
- **Continuity between sessions.** Published installs include setup of
|
|
47
47
|
[thoth-mem](https://github.com/EremesNG/thoth-mem), the independent memory
|
|
48
48
|
companion for reusable decisions and project knowledge. thoth-mem owns its own
|
|
49
|
-
memory lifecycle, persistence, and storage; thoth-agents only invokes
|
|
49
|
+
memory lifecycle, persistence, and storage; thoth-agents only invokes
|
|
50
|
+
`npx -y "thoth-mem@>=0.7.0" setup <harness> --json` (adding `--plan` for
|
|
51
|
+
dry-run). Only exit 0 with `planned` for dry-run or `complete` for apply is
|
|
52
|
+
successful; see [provider outcomes](docs/installation.md#thoth-mem-companion-setup).
|
|
50
53
|
|
|
51
54
|
> [!NOTE]
|
|
52
55
|
> OpenCode is the CLI's default harness. Pi is our recommendation for the best
|
|
@@ -62,7 +65,7 @@ The commands below install at **global/user scope**.
|
|
|
62
65
|
|
|
63
66
|
| Harness | What you get | Install command |
|
|
64
67
|
| --- | --- | --- |
|
|
65
|
-
| <a href="https://github.com/anomalyco/opencode"><picture><source media="(prefers-color-scheme: dark)" srcset="https://svgl.app/library/opencode-dark.svg"><img src="https://svgl.app/library/opencode.svg" alt="OpenCode logo" width="48" height="48"></picture></a><br>**OpenCode** |
|
|
68
|
+
| <a href="https://github.com/anomalyco/opencode"><picture><source media="(prefers-color-scheme: dark)" srcset="https://svgl.app/library/opencode-dark.svg"><img src="https://svgl.app/library/opencode.svg" alt="OpenCode logo" width="48" height="48"></picture></a><br>**OpenCode** | OpenCode >=2.2.6 native v2 plugin, package skills, agent team, and memory setup. | `npx thoth-agents@latest install --agent=opencode` |
|
|
66
69
|
| <a href="https://github.com/openai/codex"><img src="https://github.com/openai.png?size=120" alt="OpenAI logo — Codex" width="48" height="48"></a><br>**Codex** | Native plugin plus the required global agent and instruction setup. **Close Codex first.** | `npx thoth-agents@latest install --agent=codex` |
|
|
67
70
|
| <a href="https://claude.com/product/claude-code"><img src="https://github.com/anthropics.png?size=120" alt="Anthropic logo — Claude Code" width="48" height="48"></a><br>**Claude Code** | Marketplace agents and skills, completed by the CLI's external skills and memory setup. | `npx thoth-agents@latest install --agent=claude` |
|
|
68
71
|
| <a href="https://github.com/earendil-works/pi"><img src="https://raw.githubusercontent.com/EremesNG/thoth-mem/master/img/pi.svg" alt="Pi logo" width="48" height="48"></a><br>**Pi** | Native package, five specialists, delegation, research, theme, sidebar and background-task extensions, workflow skills, and memory setup. **Recommended for the best experience.** | `npx thoth-agents@latest install --agent=pi` |
|
|
@@ -386,7 +389,6 @@ visible foreign-overlay focus. See [question controls](pi-packages/pi-questions-
|
|
|
386
389
|
| [Codex Model Customization](docs/codex-model-customization.md) | Adjust Codex specialist models. |
|
|
387
390
|
| [Claude Code Install](docs/claude-code-install.md) | Follow marketplace setup and activation. |
|
|
388
391
|
| [Pi Setup](docs/installation.md#pi) | Check Pi dependencies, permissions, and recovery steps. |
|
|
389
|
-
| [Tmux Integration](docs/tmux-integration.md) | Configure OpenCode's optional terminal-pane integration. |
|
|
390
392
|
|
|
391
393
|
### Technical guides
|
|
392
394
|
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/** Internal role-rendering input; translated to the host's v2 Agent.Info at registration. */
|
|
2
|
+
export interface AgentConfig {
|
|
3
|
+
model?: string;
|
|
4
|
+
variant?: string;
|
|
5
|
+
temperature?: number;
|
|
6
|
+
prompt?: string;
|
|
7
|
+
description?: string;
|
|
8
|
+
mode?: 'primary' | 'subagent' | 'all';
|
|
9
|
+
hidden?: boolean;
|
|
10
|
+
color?: string;
|
|
11
|
+
steps?: number;
|
|
12
|
+
permission?: 'allow' | 'ask' | 'deny' | Record<string, 'allow' | 'ask' | 'deny' | Record<string, 'allow' | 'ask' | 'deny'>>;
|
|
13
|
+
}
|
package/dist/agents/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { AgentConfig as SDKAgentConfig } from '@opencode-ai/sdk/v2';
|
|
2
1
|
import { type PluginConfig, SUBAGENT_NAMES } from '../config';
|
|
2
|
+
import type { AgentConfig as SDKAgentConfig } from './agent-config';
|
|
3
3
|
import { type AgentDefinition } from './orchestrator';
|
|
4
4
|
export type { AgentDefinition } from './orchestrator';
|
|
5
5
|
export type SubagentName = (typeof SUBAGENT_NAMES)[number];
|
|
@@ -332,12 +332,27 @@ function checkExpectations(options, issue) {
|
|
|
332
332
|
"Expected digest must be 64 lowercase hex characters."
|
|
333
333
|
);
|
|
334
334
|
}
|
|
335
|
+
var isFenceLine = (line) => /^(?:`{3,}|~{3,})/.test(line);
|
|
336
|
+
var isVerdictLine = (line) => line.startsWith("thoth-gate-verdict ");
|
|
337
|
+
function unwrapSubagent(message, lines) {
|
|
338
|
+
if (!message.startsWith("<subagent ")) return message;
|
|
339
|
+
if (lines.at(-1) !== "</subagent>") return "";
|
|
340
|
+
const opener = lines.lastIndexOf("```thoth-result");
|
|
341
|
+
if (opener < 1) return "";
|
|
342
|
+
const header = lines.slice(0, opener).join("\n").trimEnd();
|
|
343
|
+
if (!header.includes('state="completed"') || lines.slice(0, opener).some((line) => isFenceLine(line) || isVerdictLine(line)))
|
|
344
|
+
return "";
|
|
345
|
+
return lines.slice(opener, -1).join("\n").trim();
|
|
346
|
+
}
|
|
335
347
|
function parseEnvelope(message) {
|
|
336
|
-
const
|
|
348
|
+
const complete = typeof message === "string" ? message.trim() : "";
|
|
349
|
+
const lines = complete.split(/\r\n|\r|\n/);
|
|
350
|
+
const singleEnvelope = lines.filter(isFenceLine).length === 2 && !lines.some(isVerdictLine);
|
|
351
|
+
const trimmed = singleEnvelope ? unwrapSubagent(complete, lines) : "";
|
|
337
352
|
const block = new RegExp(
|
|
338
353
|
`^\`\`\`${result_contract_default.fence}\\r?\\n([\\s\\S]*?)\\r?\\n\`\`\`$`
|
|
339
354
|
).exec(trimmed);
|
|
340
|
-
if (!block
|
|
355
|
+
if (!block) {
|
|
341
356
|
return {
|
|
342
357
|
issues: [
|
|
343
358
|
{
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
// src/mcp/context7.ts
|
|
2
|
+
var CONTEXT7_MCP_URL = "https://mcp.context7.com/mcp";
|
|
3
|
+
var context7 = {
|
|
4
|
+
type: "remote",
|
|
5
|
+
url: CONTEXT7_MCP_URL,
|
|
6
|
+
headers: process.env.CONTEXT7_API_KEY ? { CONTEXT7_API_KEY: process.env.CONTEXT7_API_KEY } : void 0,
|
|
7
|
+
oauth: false
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
// src/mcp/exa.ts
|
|
11
|
+
var exa = {
|
|
12
|
+
type: "local",
|
|
13
|
+
command: ["npx", "-y", "exa-mcp-server"]
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
// src/mcp/grep-app.ts
|
|
17
|
+
var GREP_APP_MCP_URL = "https://mcp.grep.app";
|
|
18
|
+
var grep_app = {
|
|
19
|
+
type: "remote",
|
|
20
|
+
url: GREP_APP_MCP_URL,
|
|
21
|
+
oauth: false
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
// src/utils/subprocess.ts
|
|
25
|
+
import {
|
|
26
|
+
spawn as nodeSpawn,
|
|
27
|
+
spawnSync as nodeSpawnSync
|
|
28
|
+
} from "child_process";
|
|
29
|
+
import { Readable } from "stream";
|
|
30
|
+
function emptyReadableStream() {
|
|
31
|
+
return new ReadableStream({
|
|
32
|
+
start(controller) {
|
|
33
|
+
controller.close();
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
function toWebReadable(stream) {
|
|
38
|
+
if (!stream) {
|
|
39
|
+
return emptyReadableStream();
|
|
40
|
+
}
|
|
41
|
+
return Readable.toWeb(
|
|
42
|
+
stream
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
function fallbackStdin() {
|
|
46
|
+
return {
|
|
47
|
+
write: () => void 0,
|
|
48
|
+
end: () => void 0
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
function spawn(command, options = {}) {
|
|
52
|
+
const child = nodeSpawn(command[0], command.slice(1), {
|
|
53
|
+
cwd: options.cwd,
|
|
54
|
+
env: options.env,
|
|
55
|
+
stdio: [
|
|
56
|
+
options.stdin ?? "pipe",
|
|
57
|
+
options.stdout ?? "pipe",
|
|
58
|
+
options.stderr ?? "pipe"
|
|
59
|
+
],
|
|
60
|
+
shell: options.shell,
|
|
61
|
+
windowsHide: options.windowsHide ?? true
|
|
62
|
+
});
|
|
63
|
+
const managed = {
|
|
64
|
+
stdin: child.stdin ?? fallbackStdin(),
|
|
65
|
+
stdout: toWebReadable(child.stdout),
|
|
66
|
+
stderr: toWebReadable(child.stderr),
|
|
67
|
+
exited: new Promise((resolve) => {
|
|
68
|
+
child.on("exit", (code) => {
|
|
69
|
+
managed.exitCode = code;
|
|
70
|
+
resolve(code ?? 1);
|
|
71
|
+
});
|
|
72
|
+
child.on("error", () => {
|
|
73
|
+
managed.exitCode = 1;
|
|
74
|
+
resolve(1);
|
|
75
|
+
});
|
|
76
|
+
}),
|
|
77
|
+
exitCode: child.exitCode,
|
|
78
|
+
kill: () => {
|
|
79
|
+
child.kill();
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
return managed;
|
|
83
|
+
}
|
|
84
|
+
function spawnSync(command, options = {}) {
|
|
85
|
+
const result = nodeSpawnSync(command[0], command.slice(1), {
|
|
86
|
+
cwd: options.cwd,
|
|
87
|
+
env: options.env,
|
|
88
|
+
stdio: [
|
|
89
|
+
options.stdin ?? "ignore",
|
|
90
|
+
options.stdout ?? "pipe",
|
|
91
|
+
options.stderr ?? "pipe"
|
|
92
|
+
],
|
|
93
|
+
shell: options.shell,
|
|
94
|
+
windowsHide: options.windowsHide ?? true
|
|
95
|
+
});
|
|
96
|
+
return { exitCode: result.status };
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export {
|
|
100
|
+
CONTEXT7_MCP_URL,
|
|
101
|
+
context7,
|
|
102
|
+
exa,
|
|
103
|
+
GREP_APP_MCP_URL,
|
|
104
|
+
grep_app,
|
|
105
|
+
spawn,
|
|
106
|
+
spawnSync
|
|
107
|
+
};
|
|
@@ -19,20 +19,6 @@ function findPackageRoot(startDir) {
|
|
|
19
19
|
}
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
-
// src/config/loader.ts
|
|
23
|
-
import * as fs from "fs";
|
|
24
|
-
import * as path from "path";
|
|
25
|
-
|
|
26
|
-
// src/cli/config-io.ts
|
|
27
|
-
import {
|
|
28
|
-
copyFileSync,
|
|
29
|
-
existsSync as existsSync3,
|
|
30
|
-
readFileSync as readFileSync2,
|
|
31
|
-
renameSync,
|
|
32
|
-
statSync,
|
|
33
|
-
writeFileSync
|
|
34
|
-
} from "fs";
|
|
35
|
-
|
|
36
22
|
// src/config/constants.ts
|
|
37
23
|
var SUBAGENT_NAMES = [
|
|
38
24
|
"explorer",
|
|
@@ -99,7 +85,6 @@ function getDefaultOpenCodeVariant(name) {
|
|
|
99
85
|
}
|
|
100
86
|
return CONFIRMED_OPENAI_SUBAGENT_PRESET[name].effort;
|
|
101
87
|
}
|
|
102
|
-
var POLL_INTERVAL_BACKGROUND_MS = 2e3;
|
|
103
88
|
var DEFAULT_TIMEOUT_MS = 2 * 60 * 1e3;
|
|
104
89
|
var MAX_POLL_TIME_MS = 5 * 60 * 1e3;
|
|
105
90
|
|
|
@@ -195,27 +180,41 @@ function resolveExecutingPackageVersion(options = {}) {
|
|
|
195
180
|
return { ok: true, version, packageRoot };
|
|
196
181
|
}
|
|
197
182
|
|
|
183
|
+
// src/config/loader.ts
|
|
184
|
+
import * as fs from "fs";
|
|
185
|
+
import * as path from "path";
|
|
186
|
+
|
|
187
|
+
// src/cli/config-io.ts
|
|
188
|
+
import {
|
|
189
|
+
copyFileSync,
|
|
190
|
+
existsSync as existsSync3,
|
|
191
|
+
readFileSync as readFileSync2,
|
|
192
|
+
renameSync,
|
|
193
|
+
statSync,
|
|
194
|
+
writeFileSync
|
|
195
|
+
} from "fs";
|
|
196
|
+
|
|
198
197
|
// src/cli/paths.ts
|
|
199
198
|
import { existsSync as existsSync2, mkdirSync } from "fs";
|
|
200
199
|
import { homedir } from "os";
|
|
201
200
|
import { dirname as dirname3, join as join3 } from "path";
|
|
202
|
-
function getDefaultOpenCodeConfigDir() {
|
|
203
|
-
const userConfigDir = process.env.XDG_CONFIG_HOME ? process.env.XDG_CONFIG_HOME : join3(
|
|
201
|
+
function getDefaultOpenCodeConfigDir(homeDir) {
|
|
202
|
+
const userConfigDir = process.env.XDG_CONFIG_HOME ? process.env.XDG_CONFIG_HOME : join3(homeDir, ".config");
|
|
204
203
|
return join3(userConfigDir, "opencode");
|
|
205
204
|
}
|
|
206
205
|
function getCustomOpenCodeConfigDir() {
|
|
207
206
|
const configDir = process.env.OPENCODE_CONFIG_DIR?.trim();
|
|
208
207
|
return configDir || void 0;
|
|
209
208
|
}
|
|
210
|
-
function getConfigDir() {
|
|
209
|
+
function getConfigDir(homeDir = homedir()) {
|
|
211
210
|
const customConfigDir = getCustomOpenCodeConfigDir();
|
|
212
211
|
if (customConfigDir) {
|
|
213
212
|
return customConfigDir;
|
|
214
213
|
}
|
|
215
|
-
return getDefaultOpenCodeConfigDir();
|
|
214
|
+
return getDefaultOpenCodeConfigDir(homeDir);
|
|
216
215
|
}
|
|
217
216
|
function getOpenCodeConfigPaths() {
|
|
218
|
-
const configDir =
|
|
217
|
+
const configDir = getConfigDir();
|
|
219
218
|
return [join3(configDir, "opencode.json"), join3(configDir, "opencode.jsonc")];
|
|
220
219
|
}
|
|
221
220
|
function getConfigJson() {
|
|
@@ -328,24 +327,6 @@ var AgentOverrideConfigSchema = z.object({
|
|
|
328
327
|
steps: z.number().int().min(1).optional(),
|
|
329
328
|
variant: z.string().optional().catch(void 0)
|
|
330
329
|
});
|
|
331
|
-
var TmuxLayoutSchema = z.enum([
|
|
332
|
-
"main-horizontal",
|
|
333
|
-
// Main pane on top, agents stacked below
|
|
334
|
-
"main-vertical",
|
|
335
|
-
// Main pane on left, agents stacked on right
|
|
336
|
-
"tiled",
|
|
337
|
-
// All panes equal size grid
|
|
338
|
-
"even-horizontal",
|
|
339
|
-
// All panes side by side
|
|
340
|
-
"even-vertical"
|
|
341
|
-
// All panes stacked vertically
|
|
342
|
-
]);
|
|
343
|
-
var TmuxConfigSchema = z.object({
|
|
344
|
-
enabled: z.boolean().default(false),
|
|
345
|
-
layout: TmuxLayoutSchema.default("main-vertical"),
|
|
346
|
-
main_pane_size: z.number().min(20).max(80).default(60)
|
|
347
|
-
// percentage for main pane
|
|
348
|
-
});
|
|
349
330
|
var PresetSchema = z.record(
|
|
350
331
|
SupportedAgentRecordKeySchema,
|
|
351
332
|
AgentOverrideConfigSchema
|
|
@@ -378,7 +359,6 @@ var PluginConfigSchema = z.object({
|
|
|
378
359
|
presets: z.record(z.string(), PresetSchema).optional(),
|
|
379
360
|
agents: z.record(SupportedAgentRecordKeySchema, AgentOverrideConfigSchema).optional(),
|
|
380
361
|
disabled_mcps: z.array(z.string()).optional(),
|
|
381
|
-
tmux: TmuxConfigSchema.optional(),
|
|
382
362
|
fallback: FailoverConfigSchema.optional(),
|
|
383
363
|
codex: CodexGenerationConfigSchema.optional(),
|
|
384
364
|
claudeCode: ClaudeCodeGenerationConfigSchema.optional()
|
|
@@ -418,7 +398,7 @@ function buildOpenAIModelMappings() {
|
|
|
418
398
|
var MODEL_MAPPINGS = {
|
|
419
399
|
openai: buildOpenAIModelMappings()
|
|
420
400
|
};
|
|
421
|
-
function generateLiteConfig(
|
|
401
|
+
function generateLiteConfig(_installConfig) {
|
|
422
402
|
const config = {
|
|
423
403
|
$schema: THOTH_AGENTS_CONFIG_SCHEMA_URL,
|
|
424
404
|
preset: "openai",
|
|
@@ -440,13 +420,6 @@ function generateLiteConfig(installConfig) {
|
|
|
440
420
|
);
|
|
441
421
|
};
|
|
442
422
|
config.presets.openai = buildPreset("openai");
|
|
443
|
-
if (installConfig.hasTmux) {
|
|
444
|
-
config.tmux = {
|
|
445
|
-
enabled: true,
|
|
446
|
-
layout: "main-vertical",
|
|
447
|
-
main_pane_size: 60
|
|
448
|
-
};
|
|
449
|
-
}
|
|
450
423
|
return config;
|
|
451
424
|
}
|
|
452
425
|
|
|
@@ -500,24 +473,32 @@ function writeConfig(configPath, config) {
|
|
|
500
473
|
writeFileSync(tmpPath, content);
|
|
501
474
|
renameSync(tmpPath, configPath);
|
|
502
475
|
}
|
|
476
|
+
function pluginEntries(value) {
|
|
477
|
+
return Array.isArray(value) ? value : [];
|
|
478
|
+
}
|
|
479
|
+
function isManagedOpenCodePlugin(entry) {
|
|
480
|
+
const name = typeof entry === "string" ? entry : Array.isArray(entry) ? entry[0] : entry && typeof entry === "object" && "package" in entry ? entry.package : void 0;
|
|
481
|
+
return typeof name === "string" && (name === PACKAGE_NAME || name.startsWith(`${PACKAGE_NAME}@`));
|
|
482
|
+
}
|
|
483
|
+
function hasManagedPluginOptions(entry) {
|
|
484
|
+
if (!isManagedOpenCodePlugin(entry)) return false;
|
|
485
|
+
const options = Array.isArray(entry) ? entry[1] : entry && typeof entry === "object" && "options" in entry ? entry.options : void 0;
|
|
486
|
+
return !!options && typeof options === "object" && Object.keys(options).length > 0;
|
|
487
|
+
}
|
|
503
488
|
function mergeOpenCodeMainConfig(config, update) {
|
|
504
489
|
if (update.ensurePlugin) {
|
|
505
|
-
const
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
490
|
+
const legacy = pluginEntries(config.plugin).filter(
|
|
491
|
+
(entry) => !isManagedOpenCodePlugin(entry)
|
|
492
|
+
);
|
|
493
|
+
if (legacy.length > 0) config.plugin = legacy;
|
|
494
|
+
else delete config.plugin;
|
|
495
|
+
config.plugins = [
|
|
496
|
+
...pluginEntries(config.plugins).filter(
|
|
497
|
+
(entry) => !isManagedOpenCodePlugin(entry)
|
|
509
498
|
),
|
|
510
499
|
`${PACKAGE_NAME}@${update.pluginVersion}`
|
|
511
500
|
];
|
|
512
501
|
}
|
|
513
|
-
if (update.disableDefaults) {
|
|
514
|
-
const agent = config.agent && typeof config.agent === "object" ? { ...config.agent } : {};
|
|
515
|
-
const explore = agent.explore && typeof agent.explore === "object" ? { ...agent.explore } : {};
|
|
516
|
-
const general = agent.general && typeof agent.general === "object" ? { ...agent.general } : {};
|
|
517
|
-
agent.explore = { ...explore, disable: true };
|
|
518
|
-
agent.general = { ...general, disable: true };
|
|
519
|
-
config.agent = agent;
|
|
520
|
-
}
|
|
521
502
|
return config;
|
|
522
503
|
}
|
|
523
504
|
function updateOpenCodeMainConfig(update) {
|
|
@@ -547,10 +528,19 @@ function updateOpenCodeMainConfig(update) {
|
|
|
547
528
|
error: `Failed to parse config: ${error}`
|
|
548
529
|
};
|
|
549
530
|
}
|
|
531
|
+
const removedOptions = update.ensurePlugin && [
|
|
532
|
+
...pluginEntries(parsedConfig?.plugin),
|
|
533
|
+
...pluginEntries(parsedConfig?.plugins)
|
|
534
|
+
].some(hasManagedPluginOptions);
|
|
550
535
|
writeConfig(
|
|
551
536
|
configPath,
|
|
552
537
|
mergeOpenCodeMainConfig(parsedConfig ?? {}, update)
|
|
553
538
|
);
|
|
539
|
+
if (removedOptions) {
|
|
540
|
+
console.warn(
|
|
541
|
+
`[config-manager] Removed non-empty thoth-agents plugin options while pinning the v2 plugin. Original entries are preserved in ${configPath}.bak; configure the plugin via thoth-agents.json instead.`
|
|
542
|
+
);
|
|
543
|
+
}
|
|
554
544
|
return { success: true, configPath };
|
|
555
545
|
} catch (err) {
|
|
556
546
|
return {
|
|
@@ -634,13 +624,14 @@ function writeLiteConfig(installConfig, targetPath) {
|
|
|
634
624
|
function detectCurrentConfig() {
|
|
635
625
|
const result = {
|
|
636
626
|
isInstalled: false,
|
|
637
|
-
hasOpenAI: false
|
|
638
|
-
hasTmux: false
|
|
627
|
+
hasOpenAI: false
|
|
639
628
|
};
|
|
640
629
|
const { config } = parseConfig(getExistingConfigPath());
|
|
641
630
|
if (!config) return result;
|
|
642
|
-
|
|
643
|
-
|
|
631
|
+
result.isInstalled = [
|
|
632
|
+
...pluginEntries(config.plugin),
|
|
633
|
+
...pluginEntries(config.plugins)
|
|
634
|
+
].some(isManagedOpenCodePlugin);
|
|
644
635
|
const { config: liteConfig } = parseConfig(getLiteConfig());
|
|
645
636
|
if (liteConfig && typeof liteConfig === "object") {
|
|
646
637
|
const configObj = liteConfig;
|
|
@@ -651,10 +642,6 @@ function detectCurrentConfig() {
|
|
|
651
642
|
const models = Object.values(agents).map((a) => a?.model).filter(Boolean);
|
|
652
643
|
result.hasOpenAI = models.some((m) => m?.startsWith("openai/"));
|
|
653
644
|
}
|
|
654
|
-
if (configObj.tmux && typeof configObj.tmux === "object") {
|
|
655
|
-
const tmuxConfig = configObj.tmux;
|
|
656
|
-
result.hasTmux = tmuxConfig.enabled === true;
|
|
657
|
-
}
|
|
658
645
|
}
|
|
659
646
|
return result;
|
|
660
647
|
}
|
|
@@ -727,7 +714,6 @@ function loadPluginConfig(directory) {
|
|
|
727
714
|
...config,
|
|
728
715
|
...projectConfig,
|
|
729
716
|
agents: deepMerge(config.agents, projectConfig.agents),
|
|
730
|
-
tmux: deepMerge(config.tmux, projectConfig.tmux),
|
|
731
717
|
fallback: deepMerge(config.fallback, projectConfig.fallback),
|
|
732
718
|
codex: deepMerge(config.codex, projectConfig.codex),
|
|
733
719
|
claudeCode: deepMerge(config.claudeCode, projectConfig.claudeCode)
|
|
@@ -1381,25 +1367,30 @@ function piCapabilityDisclosure(capability) {
|
|
|
1381
1367
|
}
|
|
1382
1368
|
var OPENCODE_PROMPT_DIALECT = {
|
|
1383
1369
|
harness: "opencode",
|
|
1384
|
-
gateDeliveryInstruction: "
|
|
1370
|
+
gateDeliveryInstruction: "Foreground Oracle `subagent` gates get one `thoth-gate-verdict` line; background completions have none: use the explicit compact validator fallback.",
|
|
1385
1371
|
tools: {
|
|
1386
|
-
delegationTool: "
|
|
1387
|
-
backgroundDelegationTool: "
|
|
1388
|
-
|
|
1372
|
+
delegationTool: "subagent",
|
|
1373
|
+
backgroundDelegationTool: "subagent(background:true)",
|
|
1374
|
+
backgroundWaitInstruction: 'Native `<subagent sessionID=... state="completed">` completion wakes root. No status polling tool exists; never poll/sleep.',
|
|
1389
1375
|
userQuestionTool: "question",
|
|
1390
1376
|
progressTool: "todowrite",
|
|
1391
|
-
hostStatusSurface: "
|
|
1377
|
+
hostStatusSurface: "native subagent completion messages",
|
|
1392
1378
|
lifecycle: {
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1379
|
+
rootInstructions: [
|
|
1380
|
+
"- New objectives, phases, work units, mutable surfaces or independent judgments require fresh specialist sessions via `subagent` (agent, description, prompt; omit sessionID). These are fresh-session boundaries, not permission for root execution; never pool completed agents.",
|
|
1381
|
+
"- Use sessionID only to continue/clarify the same assignment, including while running. Optional model; background:true for independent work. Default nesting depth is 1.",
|
|
1382
|
+
"- Every Oracle plan review, verification round, and PASS judgment uses a fresh Oracle instance. Existing ones only clarify their findings."
|
|
1383
|
+
].join("\n"),
|
|
1384
|
+
freshDelegation: "`subagent` with agent, description and prompt, omitting sessionID",
|
|
1385
|
+
sameAssignmentContinuation: "`subagent` with the prior sessionID, including while running",
|
|
1386
|
+
independentContext: "omitting sessionID creates an isolated child session",
|
|
1387
|
+
statusAction: "receive native completion automatically; never poll",
|
|
1388
|
+
terminalState: "a completed subagent result/message",
|
|
1389
|
+
nonterminalState: "a running placeholder",
|
|
1390
|
+
sameSessionProbe: "continue or clarify with subagent and the same sessionID; never ask for status",
|
|
1400
1391
|
enforcement: "runtime-supported"
|
|
1401
1392
|
},
|
|
1402
|
-
roleReference: (role) =>
|
|
1393
|
+
roleReference: (role) => `subagent agent:"${role}"`
|
|
1403
1394
|
},
|
|
1404
1395
|
capabilities: supportedCapabilityProfile(OPENCODE_CAPABILITIES),
|
|
1405
1396
|
dispatchLabel(method) {
|
|
@@ -1407,11 +1398,11 @@ var OPENCODE_PROMPT_DIALECT = {
|
|
|
1407
1398
|
case "root-coordinator":
|
|
1408
1399
|
return "root coordinator";
|
|
1409
1400
|
case "task":
|
|
1410
|
-
return "
|
|
1401
|
+
return "subagent";
|
|
1411
1402
|
}
|
|
1412
1403
|
},
|
|
1413
1404
|
renderRoleInvocation(role) {
|
|
1414
|
-
return
|
|
1405
|
+
return `subagent agent:"${role}"`;
|
|
1415
1406
|
}
|
|
1416
1407
|
};
|
|
1417
1408
|
var CODEX_PROMPT_DIALECT = {
|
|
@@ -2231,7 +2222,7 @@ Use \`${dialect.tools.userQuestionTool}\` only for a blocking material choice, d
|
|
|
2231
2222
|
}
|
|
2232
2223
|
function renderSubagentRules(section, dialect) {
|
|
2233
2224
|
const rules = [
|
|
2234
|
-
dialect.tools.progressTool ? `- Do not delegate further or call \`${dialect.tools.progressTool}\`; root owns progress.` : "- Do not delegate further; root owns progress.",
|
|
2225
|
+
dialect.harness === "opencode" ? "- Do not delegate further; no `todowrite` (root-owned)." : dialect.tools.progressTool ? `- Do not delegate further or call \`${dialect.tools.progressTool}\`; root owns progress.` : "- Do not delegate further; root owns progress.",
|
|
2235
2226
|
"- Use terminating checks; avoid watch processes and indefinite waits.",
|
|
2236
2227
|
"- Preserve operator-selected model/effort. Stop after the assigned outcome and checks; never expand scope to fill a timeout.",
|
|
2237
2228
|
"- After two consecutive attempts without new evidence or progress, return partial evidence and the smallest blocker; do not repeat searches or unchanged failing commands.",
|
|
@@ -2428,19 +2419,19 @@ export {
|
|
|
2428
2419
|
DEFAULT_MODELS,
|
|
2429
2420
|
getDefaultOpenCodeModel,
|
|
2430
2421
|
getDefaultOpenCodeVariant,
|
|
2431
|
-
POLL_INTERVAL_BACKGROUND_MS,
|
|
2432
2422
|
findPackageRoot,
|
|
2433
2423
|
isValidPackageVersion,
|
|
2434
2424
|
resolveExecutingPackageVersion,
|
|
2435
|
-
|
|
2425
|
+
getConfigDir,
|
|
2436
2426
|
getOpenCodeManagedModelStatePath,
|
|
2437
2427
|
getExistingLiteConfigPath,
|
|
2438
2428
|
getExistingConfigPath,
|
|
2439
2429
|
ensureConfigDir,
|
|
2440
2430
|
generateLiteConfig,
|
|
2441
|
-
stripJsonComments,
|
|
2442
2431
|
parseConfig,
|
|
2443
2432
|
writeConfig,
|
|
2433
|
+
pluginEntries,
|
|
2434
|
+
isManagedOpenCodePlugin,
|
|
2444
2435
|
updateOpenCodeMainConfig,
|
|
2445
2436
|
writeLiteConfig,
|
|
2446
2437
|
detectCurrentConfig,
|