thoth-agents 0.2.11 → 0.3.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/.agents/plugins/marketplace.json +20 -0
- package/.claude-plugin/marketplace.json +21 -0
- package/README.md +301 -311
- package/dist/agents/configured-role-prompt.d.ts +9 -0
- package/dist/agents/prompt-sections.d.ts +8 -4
- package/dist/agents/prompt-utils.d.ts +0 -4
- package/dist/{chunk-ASKXWU6E.js → chunk-2MZ5C2RN.js} +1078 -1725
- package/dist/chunk-XO74DXBZ.js +1781 -0
- package/dist/{chunk-6BNAV534.js → chunk-YUCGIJPP.js} +12 -30
- package/dist/cli/claude-code-install.d.ts +24 -26
- package/dist/cli/claude-code-paths.d.ts +0 -28
- package/dist/cli/codex-install.d.ts +2 -2
- package/dist/cli/codex-paths.d.ts +0 -2
- package/dist/cli/index.js +279 -119
- package/dist/cli/install.d.ts +5 -1
- package/dist/cli/model-catalog/cache.d.ts +1 -1
- package/dist/cli/operations/claude-code.d.ts +6 -3
- package/dist/cli/operations/codex.d.ts +2 -1
- package/dist/cli/operations/opencode.d.ts +2 -1
- package/dist/cli/operations/types.d.ts +9 -1
- package/dist/cli/package-root.d.ts +1 -0
- package/dist/cli/providers.d.ts +6 -116
- package/dist/cli/skills.d.ts +19 -32
- package/dist/cli/thoth-mem-install.d.ts +45 -0
- package/dist/cli/tui/components/StatusView.d.ts +12 -1
- package/dist/cli/tui/index.js +256 -142
- package/dist/cli/tui/operations.d.ts +4 -3
- package/dist/cli/types.d.ts +0 -10
- package/dist/config/constants.d.ts +20 -16
- package/dist/config/index.d.ts +0 -1
- package/dist/config/loader.d.ts +1 -1
- package/dist/config/schema.d.ts +2 -38
- package/dist/config/utils.d.ts +1 -2
- package/dist/harness/adapters/codex-surfaces.d.ts +3 -3
- package/dist/harness/core/agent-pack.d.ts +37 -29
- package/dist/harness/core/memory-governance.d.ts +24 -48
- package/dist/harness/core/sdd.d.ts +364 -131
- package/dist/harness/generate-integration-packages.d.ts +20 -0
- package/dist/harness/opencode-init-command.d.ts +11 -0
- package/dist/harness/types.d.ts +14 -1
- package/dist/harness/writers/claude-code-subagent.d.ts +3 -1
- package/dist/hooks/index.d.ts +0 -5
- package/dist/index.js +562 -1314
- package/dist/mcp/index.d.ts +1 -2
- package/package.json +17 -12
- package/plugin/.claude-plugin/.thoth-agents-plugin-assets.json +50 -0
- package/plugin/.claude-plugin/plugin.json +8 -0
- package/plugin/.codex-plugin/.thoth-agents-plugin-assets.json +16 -0
- package/plugin/.codex-plugin/plugin.json +7 -0
- package/plugin/.mcp.json +19 -0
- package/plugin/agents/deep.md +89 -0
- package/plugin/agents/designer.md +89 -0
- package/plugin/agents/explorer.md +90 -0
- package/plugin/agents/librarian.md +90 -0
- package/plugin/agents/oracle.md +92 -0
- package/plugin/agents/orchestrator.md +128 -0
- package/plugin/agents/quick.md +89 -0
- package/plugin/codex.mcp.json +17 -0
- package/plugin/settings.json +3 -0
- package/plugin/skills/thoth-archive/SKILL.md +40 -0
- package/plugin/skills/thoth-archive/scripts/archive.mjs +748 -0
- package/plugin/skills/thoth-constitution/SKILL.md +45 -0
- package/plugin/skills/thoth-constitution/scripts/validate.mjs +167 -0
- package/plugin/skills/thoth-constitution/templates/constitution.md +54 -0
- package/plugin/skills/thoth-init/SKILL.md +30 -0
- package/plugin/skills/thoth-init/scripts/init.mjs +141 -0
- package/plugin/skills/thoth-sdd/SKILL.md +83 -0
- package/plugin/skills/thoth-sdd/references/phases/analyze.md +21 -0
- package/plugin/skills/thoth-sdd/references/phases/checklist.md +20 -0
- package/plugin/skills/thoth-sdd/references/phases/clarify.md +15 -0
- package/plugin/skills/thoth-sdd/references/phases/converge.md +14 -0
- package/plugin/skills/thoth-sdd/references/phases/explore.md +10 -0
- package/plugin/skills/thoth-sdd/references/phases/implement.md +19 -0
- package/plugin/skills/thoth-sdd/references/phases/plan.md +15 -0
- package/plugin/skills/thoth-sdd/references/phases/specify.md +21 -0
- package/plugin/skills/thoth-sdd/references/phases/tasks.md +20 -0
- package/plugin/skills/thoth-sdd/references/phases/verify.md +22 -0
- package/plugin/skills/thoth-sdd/scripts/validate.mjs +1117 -0
- package/plugin/skills/thoth-sdd/templates/archive-report.md +25 -0
- package/plugin/skills/thoth-sdd/templates/checklist.md +27 -0
- package/plugin/skills/thoth-sdd/templates/plan.md +38 -0
- package/plugin/skills/thoth-sdd/templates/spec.md +54 -0
- package/plugin/skills/thoth-sdd/templates/tasks.md +29 -0
- package/plugin/skills/thoth-sdd/templates/verify-report.md +28 -0
- package/skills/README.md +12 -0
- package/skills/thoth-archive/SKILL.md +40 -0
- package/skills/thoth-archive/scripts/archive.mjs +748 -0
- package/skills/thoth-constitution/SKILL.md +45 -0
- package/skills/thoth-constitution/scripts/validate.mjs +167 -0
- package/skills/thoth-constitution/templates/constitution.md +54 -0
- package/skills/thoth-init/SKILL.md +30 -0
- package/skills/thoth-init/scripts/init.mjs +141 -0
- package/skills/thoth-sdd/SKILL.md +83 -0
- package/skills/thoth-sdd/references/phases/analyze.md +21 -0
- package/skills/thoth-sdd/references/phases/checklist.md +20 -0
- package/skills/thoth-sdd/references/phases/clarify.md +15 -0
- package/skills/thoth-sdd/references/phases/converge.md +14 -0
- package/skills/thoth-sdd/references/phases/explore.md +10 -0
- package/skills/thoth-sdd/references/phases/implement.md +19 -0
- package/skills/thoth-sdd/references/phases/plan.md +15 -0
- package/skills/thoth-sdd/references/phases/specify.md +21 -0
- package/skills/thoth-sdd/references/phases/tasks.md +20 -0
- package/skills/thoth-sdd/references/phases/verify.md +22 -0
- package/skills/thoth-sdd/scripts/validate.mjs +1117 -0
- package/skills/thoth-sdd/templates/archive-report.md +25 -0
- package/skills/thoth-sdd/templates/checklist.md +27 -0
- package/skills/thoth-sdd/templates/plan.md +38 -0
- package/skills/thoth-sdd/templates/spec.md +54 -0
- package/skills/thoth-sdd/templates/tasks.md +29 -0
- package/skills/thoth-sdd/templates/verify-report.md +28 -0
- package/thoth-agents.schema.json +0 -39
- package/dist/chunk-OZE7JVGS.js +0 -2344
- package/dist/cli/custom-skills.d.ts +0 -49
- package/dist/cli/skill-manifest.d.ts +0 -32
- package/dist/harness/core/skills.d.ts +0 -211
- package/dist/harness/generate-codex-plugin.d.ts +0 -9
- package/dist/harness/writers/claude-code-skill-layout.d.ts +0 -16
- package/dist/harness/writers/fs-skill-collect.d.ts +0 -7
- package/dist/harness/writers/skill-layout.d.ts +0 -16
- package/dist/hooks/chat-headers.d.ts +0 -16
- package/dist/hooks/phase-reminder/index.d.ts +0 -28
- package/dist/hooks/post-read-nudge/index.d.ts +0 -18
- package/dist/hooks/skill-sync.d.ts +0 -10
- package/dist/hooks/thoth-mem/index.d.ts +0 -46
- package/dist/hooks/thoth-mem/protocol.d.ts +0 -7
- package/dist/mcp/thoth.d.ts +0 -3
- package/dist/sdd/artifact-governance/artifact-loader.d.ts +0 -130
- package/dist/sdd/artifact-governance/index.d.ts +0 -6
- package/dist/sdd/artifact-governance/tasks-validator.d.ts +0 -17
- package/dist/sdd/artifact-governance/types.d.ts +0 -52
- package/dist/thoth/client.d.ts +0 -14
- package/dist/thoth/index.d.ts +0 -2
- package/src/skills/_shared/openspec-convention.md +0 -350
- package/src/skills/_shared/persistence-contract.md +0 -163
- package/src/skills/_shared/thoth-mem-convention.md +0 -123
- package/src/skills/executing-plans/SKILL.md +0 -288
- package/src/skills/plan-reviewer/SKILL.md +0 -219
- package/src/skills/requirements-interview/SKILL.md +0 -233
- package/src/skills/sdd-apply/SKILL.md +0 -89
- package/src/skills/sdd-archive/SKILL.md +0 -92
- package/src/skills/sdd-clarify/SKILL.md +0 -105
- package/src/skills/sdd-constitution/SKILL.md +0 -107
- package/src/skills/sdd-design/SKILL.md +0 -155
- package/src/skills/sdd-init/SKILL.md +0 -233
- package/src/skills/sdd-propose/SKILL.md +0 -101
- package/src/skills/sdd-spec/SKILL.md +0 -136
- package/src/skills/sdd-tasks/SKILL.md +0 -232
- package/src/skills/sdd-verify/SKILL.md +0 -131
- package/src/skills/thoth-mem-agents/SKILL.md +0 -210
package/dist/chunk-OZE7JVGS.js
DELETED
|
@@ -1,2344 +0,0 @@
|
|
|
1
|
-
// src/config/loader.ts
|
|
2
|
-
import * as fs from "fs";
|
|
3
|
-
import * as path from "path";
|
|
4
|
-
|
|
5
|
-
// src/cli/config-io.ts
|
|
6
|
-
import {
|
|
7
|
-
copyFileSync,
|
|
8
|
-
existsSync as existsSync2,
|
|
9
|
-
readFileSync,
|
|
10
|
-
renameSync,
|
|
11
|
-
statSync,
|
|
12
|
-
writeFileSync
|
|
13
|
-
} from "fs";
|
|
14
|
-
|
|
15
|
-
// src/cli/paths.ts
|
|
16
|
-
import { existsSync, mkdirSync } from "fs";
|
|
17
|
-
import { homedir } from "os";
|
|
18
|
-
import { dirname, join } from "path";
|
|
19
|
-
function getDefaultOpenCodeConfigDir() {
|
|
20
|
-
const userConfigDir = process.env.XDG_CONFIG_HOME ? process.env.XDG_CONFIG_HOME : join(homedir(), ".config");
|
|
21
|
-
return join(userConfigDir, "opencode");
|
|
22
|
-
}
|
|
23
|
-
function getCustomOpenCodeConfigDir() {
|
|
24
|
-
const configDir = process.env.OPENCODE_CONFIG_DIR?.trim();
|
|
25
|
-
return configDir || void 0;
|
|
26
|
-
}
|
|
27
|
-
function getConfigDir() {
|
|
28
|
-
const customConfigDir = getCustomOpenCodeConfigDir();
|
|
29
|
-
if (customConfigDir) {
|
|
30
|
-
return customConfigDir;
|
|
31
|
-
}
|
|
32
|
-
return getDefaultOpenCodeConfigDir();
|
|
33
|
-
}
|
|
34
|
-
function getOpenCodeConfigPaths() {
|
|
35
|
-
const configDir = getDefaultOpenCodeConfigDir();
|
|
36
|
-
return [join(configDir, "opencode.json"), join(configDir, "opencode.jsonc")];
|
|
37
|
-
}
|
|
38
|
-
function getConfigJson() {
|
|
39
|
-
return getOpenCodeConfigPaths()[0];
|
|
40
|
-
}
|
|
41
|
-
function getConfigJsonc() {
|
|
42
|
-
return getOpenCodeConfigPaths()[1];
|
|
43
|
-
}
|
|
44
|
-
function getLiteConfig() {
|
|
45
|
-
return join(getConfigDir(), "thoth-agents.json");
|
|
46
|
-
}
|
|
47
|
-
function getLiteConfigJsonc() {
|
|
48
|
-
return join(getConfigDir(), "thoth-agents.jsonc");
|
|
49
|
-
}
|
|
50
|
-
function getOpenCodeManagedModelStatePath() {
|
|
51
|
-
return join(getConfigDir(), ".thoth-agents-managed-models.json");
|
|
52
|
-
}
|
|
53
|
-
function getExistingLiteConfigPath() {
|
|
54
|
-
const jsonPath = getLiteConfig();
|
|
55
|
-
if (existsSync(jsonPath)) return jsonPath;
|
|
56
|
-
const jsoncPath = getLiteConfigJsonc();
|
|
57
|
-
if (existsSync(jsoncPath)) return jsoncPath;
|
|
58
|
-
return jsonPath;
|
|
59
|
-
}
|
|
60
|
-
function getExistingConfigPath() {
|
|
61
|
-
const jsonPath = getConfigJson();
|
|
62
|
-
if (existsSync(jsonPath)) return jsonPath;
|
|
63
|
-
const jsoncPath = getConfigJsonc();
|
|
64
|
-
if (existsSync(jsoncPath)) return jsoncPath;
|
|
65
|
-
return jsonPath;
|
|
66
|
-
}
|
|
67
|
-
function ensureConfigDir() {
|
|
68
|
-
const configDir = getConfigDir();
|
|
69
|
-
if (!existsSync(configDir)) {
|
|
70
|
-
mkdirSync(configDir, { recursive: true });
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
function ensureOpenCodeConfigDir() {
|
|
74
|
-
const configDir = dirname(getConfigJson());
|
|
75
|
-
if (!existsSync(configDir)) {
|
|
76
|
-
mkdirSync(configDir, { recursive: true });
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
// src/config/constants.ts
|
|
81
|
-
var AGENT_ALIASES = {
|
|
82
|
-
explore: "explorer",
|
|
83
|
-
"frontend-ui-ux-engineer": "designer"
|
|
84
|
-
};
|
|
85
|
-
var SUBAGENT_NAMES = [
|
|
86
|
-
"explorer",
|
|
87
|
-
"librarian",
|
|
88
|
-
"oracle",
|
|
89
|
-
"designer",
|
|
90
|
-
"quick",
|
|
91
|
-
"deep"
|
|
92
|
-
];
|
|
93
|
-
var ORCHESTRATOR_NAME = "orchestrator";
|
|
94
|
-
var ALL_AGENT_NAMES = [
|
|
95
|
-
ORCHESTRATOR_NAME,
|
|
96
|
-
"explorer",
|
|
97
|
-
"librarian",
|
|
98
|
-
"oracle",
|
|
99
|
-
"designer",
|
|
100
|
-
"quick",
|
|
101
|
-
"deep"
|
|
102
|
-
];
|
|
103
|
-
var DEFAULT_MODELS = {
|
|
104
|
-
orchestrator: void 0,
|
|
105
|
-
oracle: "openai/gpt-5.4",
|
|
106
|
-
librarian: "openai/gpt-5.4-mini",
|
|
107
|
-
explorer: "openai/gpt-5.4-mini",
|
|
108
|
-
designer: "openai/gpt-5.4-mini",
|
|
109
|
-
quick: "openai/gpt-5.4-mini",
|
|
110
|
-
deep: "openai/gpt-5.4"
|
|
111
|
-
};
|
|
112
|
-
var CONFIRMED_OPENAI_SUBAGENT_PRESET = {
|
|
113
|
-
oracle: { model: "gpt-5.6-sol", effort: "high" },
|
|
114
|
-
librarian: { model: "gpt-5.6-luna", effort: "low" },
|
|
115
|
-
explorer: { model: "gpt-5.6-luna", effort: "low" },
|
|
116
|
-
designer: { model: "gpt-5.6-terra", effort: "high" },
|
|
117
|
-
quick: { model: "gpt-5.6-luna", effort: "medium" },
|
|
118
|
-
deep: { model: "gpt-5.6-terra", effort: "xhigh" }
|
|
119
|
-
};
|
|
120
|
-
var POLL_INTERVAL_BACKGROUND_MS = 2e3;
|
|
121
|
-
var DEFAULT_TIMEOUT_MS = 2 * 60 * 1e3;
|
|
122
|
-
var MAX_POLL_TIME_MS = 5 * 60 * 1e3;
|
|
123
|
-
var DEFAULT_THOTH_COMMAND = ["npx", "-y", "thoth-mem", "mcp"];
|
|
124
|
-
|
|
125
|
-
// src/config/schema.ts
|
|
126
|
-
import { z } from "zod";
|
|
127
|
-
var AGENT_NAMES = [
|
|
128
|
-
"orchestrator",
|
|
129
|
-
"oracle",
|
|
130
|
-
"designer",
|
|
131
|
-
"explorer",
|
|
132
|
-
"librarian",
|
|
133
|
-
"quick",
|
|
134
|
-
"deep"
|
|
135
|
-
];
|
|
136
|
-
var FALLBACK_AGENT_NAMES = [...AGENT_NAMES];
|
|
137
|
-
var MANUAL_AGENT_NAMES = [...AGENT_NAMES];
|
|
138
|
-
var ProviderModelIdSchema = z.string().regex(
|
|
139
|
-
/^[^/\s]+\/[^\s]+$/,
|
|
140
|
-
"Expected provider/model format (provider/.../model)"
|
|
141
|
-
);
|
|
142
|
-
var ManualAgentPlanSchema = z.object({
|
|
143
|
-
primary: ProviderModelIdSchema,
|
|
144
|
-
fallback1: ProviderModelIdSchema,
|
|
145
|
-
fallback2: ProviderModelIdSchema,
|
|
146
|
-
fallback3: ProviderModelIdSchema
|
|
147
|
-
}).superRefine((value, ctx) => {
|
|
148
|
-
const unique = /* @__PURE__ */ new Set([
|
|
149
|
-
value.primary,
|
|
150
|
-
value.fallback1,
|
|
151
|
-
value.fallback2,
|
|
152
|
-
value.fallback3
|
|
153
|
-
]);
|
|
154
|
-
if (unique.size !== 4) {
|
|
155
|
-
ctx.addIssue({
|
|
156
|
-
code: z.ZodIssueCode.custom,
|
|
157
|
-
message: "primary and fallbacks must be unique per agent"
|
|
158
|
-
});
|
|
159
|
-
}
|
|
160
|
-
});
|
|
161
|
-
var ManualPlanSchema = z.object({
|
|
162
|
-
orchestrator: ManualAgentPlanSchema,
|
|
163
|
-
oracle: ManualAgentPlanSchema,
|
|
164
|
-
designer: ManualAgentPlanSchema,
|
|
165
|
-
explorer: ManualAgentPlanSchema,
|
|
166
|
-
librarian: ManualAgentPlanSchema,
|
|
167
|
-
quick: ManualAgentPlanSchema,
|
|
168
|
-
deep: ManualAgentPlanSchema
|
|
169
|
-
}).strict();
|
|
170
|
-
var AgentModelChainSchema = z.array(z.string()).min(1);
|
|
171
|
-
var FallbackChainsSchema = z.object({
|
|
172
|
-
orchestrator: AgentModelChainSchema.optional(),
|
|
173
|
-
oracle: AgentModelChainSchema.optional(),
|
|
174
|
-
designer: AgentModelChainSchema.optional(),
|
|
175
|
-
explorer: AgentModelChainSchema.optional(),
|
|
176
|
-
librarian: AgentModelChainSchema.optional(),
|
|
177
|
-
quick: AgentModelChainSchema.optional(),
|
|
178
|
-
deep: AgentModelChainSchema.optional()
|
|
179
|
-
}).catchall(AgentModelChainSchema);
|
|
180
|
-
var AgentOverrideConfigSchema = z.object({
|
|
181
|
-
model: z.union([
|
|
182
|
-
z.string(),
|
|
183
|
-
z.array(
|
|
184
|
-
z.union([
|
|
185
|
-
z.string(),
|
|
186
|
-
z.object({
|
|
187
|
-
id: z.string(),
|
|
188
|
-
variant: z.string().optional()
|
|
189
|
-
})
|
|
190
|
-
])
|
|
191
|
-
)
|
|
192
|
-
]).optional(),
|
|
193
|
-
temperature: z.number().min(0).max(2).optional(),
|
|
194
|
-
steps: z.number().int().min(1).optional(),
|
|
195
|
-
variant: z.string().optional().catch(void 0)
|
|
196
|
-
});
|
|
197
|
-
var TmuxLayoutSchema = z.enum([
|
|
198
|
-
"main-horizontal",
|
|
199
|
-
// Main pane on top, agents stacked below
|
|
200
|
-
"main-vertical",
|
|
201
|
-
// Main pane on left, agents stacked on right
|
|
202
|
-
"tiled",
|
|
203
|
-
// All panes equal size grid
|
|
204
|
-
"even-horizontal",
|
|
205
|
-
// All panes side by side
|
|
206
|
-
"even-vertical"
|
|
207
|
-
// All panes stacked vertically
|
|
208
|
-
]);
|
|
209
|
-
var TmuxConfigSchema = z.object({
|
|
210
|
-
enabled: z.boolean().default(false),
|
|
211
|
-
layout: TmuxLayoutSchema.default("main-vertical"),
|
|
212
|
-
main_pane_size: z.number().min(20).max(80).default(60)
|
|
213
|
-
// percentage for main pane
|
|
214
|
-
});
|
|
215
|
-
var PresetSchema = z.record(z.string(), AgentOverrideConfigSchema);
|
|
216
|
-
var AgentNameSchema = z.enum(AGENT_NAMES);
|
|
217
|
-
var McpNameSchema = z.enum([
|
|
218
|
-
"exa",
|
|
219
|
-
"context7",
|
|
220
|
-
"grep_app",
|
|
221
|
-
"thoth_mem"
|
|
222
|
-
]);
|
|
223
|
-
var ThothConfigSchema = z.object({
|
|
224
|
-
command: z.array(z.string()).optional(),
|
|
225
|
-
data_dir: z.string().optional(),
|
|
226
|
-
environment: z.record(z.string(), z.string()).optional(),
|
|
227
|
-
timeout: z.number().optional(),
|
|
228
|
-
http_port: z.number().optional()
|
|
229
|
-
});
|
|
230
|
-
var ArtifactStoreModeSchema = z.enum([
|
|
231
|
-
"thoth-mem",
|
|
232
|
-
"openspec",
|
|
233
|
-
"hybrid"
|
|
234
|
-
]);
|
|
235
|
-
var ArtifactStoreConfigSchema = z.object({
|
|
236
|
-
mode: ArtifactStoreModeSchema.default("hybrid")
|
|
237
|
-
});
|
|
238
|
-
var CodexGenerationConfigSchema = z.object({
|
|
239
|
-
enabled: z.boolean().default(false),
|
|
240
|
-
outputRoot: z.string().optional(),
|
|
241
|
-
dryRun: z.boolean().default(true)
|
|
242
|
-
});
|
|
243
|
-
var ClaudeCodeGenerationConfigSchema = z.object({
|
|
244
|
-
enabled: z.boolean().default(false),
|
|
245
|
-
outputRoot: z.string().optional(),
|
|
246
|
-
dryRun: z.boolean().default(true)
|
|
247
|
-
});
|
|
248
|
-
var FailoverConfigSchema = z.object({
|
|
249
|
-
enabled: z.boolean().default(true),
|
|
250
|
-
timeoutMs: z.number().min(0).default(15e3),
|
|
251
|
-
retryDelayMs: z.number().min(0).default(500),
|
|
252
|
-
chains: FallbackChainsSchema.default({})
|
|
253
|
-
});
|
|
254
|
-
var PluginConfigSchema = z.object({
|
|
255
|
-
$schema: z.string().optional(),
|
|
256
|
-
preset: z.string().optional(),
|
|
257
|
-
setDefaultAgent: z.boolean().optional(),
|
|
258
|
-
scoringEngineVersion: z.enum(["v1", "v2-shadow", "v2"]).optional(),
|
|
259
|
-
balanceProviderUsage: z.boolean().optional(),
|
|
260
|
-
manualPlan: ManualPlanSchema.optional(),
|
|
261
|
-
presets: z.record(z.string(), PresetSchema).optional(),
|
|
262
|
-
agents: z.record(z.string(), AgentOverrideConfigSchema).optional(),
|
|
263
|
-
disabled_mcps: z.array(z.string()).optional(),
|
|
264
|
-
tmux: TmuxConfigSchema.optional(),
|
|
265
|
-
fallback: FailoverConfigSchema.optional(),
|
|
266
|
-
thoth: ThothConfigSchema.optional(),
|
|
267
|
-
artifactStore: ArtifactStoreConfigSchema.optional(),
|
|
268
|
-
codex: CodexGenerationConfigSchema.optional(),
|
|
269
|
-
claudeCode: ClaudeCodeGenerationConfigSchema.optional()
|
|
270
|
-
});
|
|
271
|
-
|
|
272
|
-
// src/config/utils.ts
|
|
273
|
-
function getAgentOverride(config, name) {
|
|
274
|
-
const overrides = config?.agents ?? {};
|
|
275
|
-
return overrides[name] ?? overrides[Object.keys(AGENT_ALIASES).find((k) => AGENT_ALIASES[k] === name) ?? ""];
|
|
276
|
-
}
|
|
277
|
-
function getPrimaryModelId(model) {
|
|
278
|
-
if (Array.isArray(model)) {
|
|
279
|
-
const first = model[0];
|
|
280
|
-
return typeof first === "string" ? first : first?.id;
|
|
281
|
-
}
|
|
282
|
-
return model;
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
// src/cli/providers.ts
|
|
286
|
-
var THOTH_AGENTS_CONFIG_SCHEMA_URL = "https://unpkg.com/thoth-agents@latest/thoth-agents.schema.json";
|
|
287
|
-
var MODEL_MAPPINGS = {
|
|
288
|
-
openai: {
|
|
289
|
-
orchestrator: { model: "openai/gpt-5.4" },
|
|
290
|
-
oracle: {
|
|
291
|
-
model: `openai/${CONFIRMED_OPENAI_SUBAGENT_PRESET.oracle.model}`,
|
|
292
|
-
variant: CONFIRMED_OPENAI_SUBAGENT_PRESET.oracle.effort
|
|
293
|
-
},
|
|
294
|
-
librarian: {
|
|
295
|
-
model: `openai/${CONFIRMED_OPENAI_SUBAGENT_PRESET.librarian.model}`,
|
|
296
|
-
variant: CONFIRMED_OPENAI_SUBAGENT_PRESET.librarian.effort
|
|
297
|
-
},
|
|
298
|
-
explorer: {
|
|
299
|
-
model: `openai/${CONFIRMED_OPENAI_SUBAGENT_PRESET.explorer.model}`,
|
|
300
|
-
variant: CONFIRMED_OPENAI_SUBAGENT_PRESET.explorer.effort
|
|
301
|
-
},
|
|
302
|
-
designer: {
|
|
303
|
-
model: `openai/${CONFIRMED_OPENAI_SUBAGENT_PRESET.designer.model}`,
|
|
304
|
-
variant: CONFIRMED_OPENAI_SUBAGENT_PRESET.designer.effort
|
|
305
|
-
},
|
|
306
|
-
quick: {
|
|
307
|
-
model: `openai/${CONFIRMED_OPENAI_SUBAGENT_PRESET.quick.model}`,
|
|
308
|
-
variant: CONFIRMED_OPENAI_SUBAGENT_PRESET.quick.effort
|
|
309
|
-
},
|
|
310
|
-
deep: {
|
|
311
|
-
model: `openai/${CONFIRMED_OPENAI_SUBAGENT_PRESET.deep.model}`,
|
|
312
|
-
variant: CONFIRMED_OPENAI_SUBAGENT_PRESET.deep.effort
|
|
313
|
-
}
|
|
314
|
-
},
|
|
315
|
-
kimi: {
|
|
316
|
-
orchestrator: { model: "kimi-for-coding/k2p5" },
|
|
317
|
-
oracle: { model: "kimi-for-coding/k2p5", variant: "high" },
|
|
318
|
-
librarian: { model: "kimi-for-coding/k2p5", variant: "low" },
|
|
319
|
-
explorer: { model: "kimi-for-coding/k2p5", variant: "low" },
|
|
320
|
-
designer: { model: "kimi-for-coding/k2p5", variant: "medium" },
|
|
321
|
-
quick: { model: "kimi-for-coding/k2p5", variant: "low" },
|
|
322
|
-
deep: { model: "kimi-for-coding/k2p5", variant: "high" }
|
|
323
|
-
},
|
|
324
|
-
copilot: {
|
|
325
|
-
orchestrator: { model: "github-copilot/claude-opus-4.6" },
|
|
326
|
-
oracle: { model: "github-copilot/claude-opus-4.6", variant: "high" },
|
|
327
|
-
librarian: { model: "github-copilot/grok-code-fast-1", variant: "low" },
|
|
328
|
-
explorer: { model: "github-copilot/grok-code-fast-1", variant: "low" },
|
|
329
|
-
designer: {
|
|
330
|
-
model: "github-copilot/gemini-3.1-pro-preview",
|
|
331
|
-
variant: "medium"
|
|
332
|
-
},
|
|
333
|
-
quick: { model: "github-copilot/claude-sonnet-4.6", variant: "low" },
|
|
334
|
-
deep: { model: "github-copilot/claude-opus-4.6", variant: "high" }
|
|
335
|
-
},
|
|
336
|
-
"zai-plan": {
|
|
337
|
-
orchestrator: { model: "zai-coding-plan/glm-5" },
|
|
338
|
-
oracle: { model: "zai-coding-plan/glm-5", variant: "high" },
|
|
339
|
-
librarian: { model: "zai-coding-plan/glm-5", variant: "low" },
|
|
340
|
-
explorer: { model: "zai-coding-plan/glm-5", variant: "low" },
|
|
341
|
-
designer: { model: "zai-coding-plan/glm-5", variant: "medium" },
|
|
342
|
-
quick: { model: "zai-coding-plan/glm-5", variant: "low" },
|
|
343
|
-
deep: { model: "zai-coding-plan/glm-5", variant: "high" }
|
|
344
|
-
}
|
|
345
|
-
};
|
|
346
|
-
function generateLiteConfig(installConfig) {
|
|
347
|
-
const config = {
|
|
348
|
-
$schema: THOTH_AGENTS_CONFIG_SCHEMA_URL,
|
|
349
|
-
preset: "openai",
|
|
350
|
-
presets: {}
|
|
351
|
-
};
|
|
352
|
-
const createAgentConfig = (modelInfo) => {
|
|
353
|
-
return {
|
|
354
|
-
model: modelInfo.model,
|
|
355
|
-
variant: modelInfo.variant
|
|
356
|
-
};
|
|
357
|
-
};
|
|
358
|
-
const buildPreset = (mappingName) => {
|
|
359
|
-
const mapping = MODEL_MAPPINGS[mappingName];
|
|
360
|
-
return Object.fromEntries(
|
|
361
|
-
Object.entries(mapping).map(([agentName, modelInfo]) => [
|
|
362
|
-
agentName,
|
|
363
|
-
createAgentConfig(modelInfo)
|
|
364
|
-
])
|
|
365
|
-
);
|
|
366
|
-
};
|
|
367
|
-
config.presets.openai = buildPreset("openai");
|
|
368
|
-
if (installConfig.hasTmux) {
|
|
369
|
-
config.tmux = {
|
|
370
|
-
enabled: true,
|
|
371
|
-
layout: "main-vertical",
|
|
372
|
-
main_pane_size: 60
|
|
373
|
-
};
|
|
374
|
-
}
|
|
375
|
-
return config;
|
|
376
|
-
}
|
|
377
|
-
|
|
378
|
-
// src/cli/config-io.ts
|
|
379
|
-
var PACKAGE_NAME = "thoth-agents";
|
|
380
|
-
function stripJsonComments(json) {
|
|
381
|
-
const commentPattern = /\\"|"(?:\\"|[^"])*"|(\/\/.*|\/\*[\s\S]*?\*\/)/g;
|
|
382
|
-
const trailingCommaPattern = /\\"|"(?:\\"|[^"])*"|(,)(\s*[}\]])/g;
|
|
383
|
-
return json.replace(
|
|
384
|
-
commentPattern,
|
|
385
|
-
(match, commentGroup) => commentGroup ? "" : match
|
|
386
|
-
).replace(
|
|
387
|
-
trailingCommaPattern,
|
|
388
|
-
(match, comma, closing) => comma ? closing : match
|
|
389
|
-
);
|
|
390
|
-
}
|
|
391
|
-
function parseConfigFile(path2) {
|
|
392
|
-
try {
|
|
393
|
-
if (!existsSync2(path2)) return { config: null };
|
|
394
|
-
const stat = statSync(path2);
|
|
395
|
-
if (stat.size === 0) return { config: null };
|
|
396
|
-
const content = readFileSync(path2, "utf-8");
|
|
397
|
-
if (content.trim().length === 0) return { config: null };
|
|
398
|
-
return { config: JSON.parse(stripJsonComments(content)) };
|
|
399
|
-
} catch (err) {
|
|
400
|
-
return { config: null, error: String(err) };
|
|
401
|
-
}
|
|
402
|
-
}
|
|
403
|
-
function parseConfig(path2) {
|
|
404
|
-
const result = parseConfigFile(path2);
|
|
405
|
-
if (result.config || result.error) return result;
|
|
406
|
-
if (path2.endsWith(".json")) {
|
|
407
|
-
const jsoncPath = path2.replace(/\.json$/, ".jsonc");
|
|
408
|
-
return parseConfigFile(jsoncPath);
|
|
409
|
-
}
|
|
410
|
-
return { config: null };
|
|
411
|
-
}
|
|
412
|
-
function writeConfig(configPath, config) {
|
|
413
|
-
if (configPath.endsWith(".jsonc")) {
|
|
414
|
-
console.warn(
|
|
415
|
-
"[config-manager] Writing to .jsonc file - comments will not be preserved"
|
|
416
|
-
);
|
|
417
|
-
}
|
|
418
|
-
const tmpPath = `${configPath}.tmp`;
|
|
419
|
-
const bakPath = `${configPath}.bak`;
|
|
420
|
-
const content = `${JSON.stringify(config, null, 2)}
|
|
421
|
-
`;
|
|
422
|
-
if (existsSync2(configPath)) {
|
|
423
|
-
copyFileSync(configPath, bakPath);
|
|
424
|
-
}
|
|
425
|
-
writeFileSync(tmpPath, content);
|
|
426
|
-
renameSync(tmpPath, configPath);
|
|
427
|
-
}
|
|
428
|
-
function mergeOpenCodeMainConfig(config, update) {
|
|
429
|
-
if (update.ensurePlugin) {
|
|
430
|
-
const plugins = Array.isArray(config.plugin) ? config.plugin : [];
|
|
431
|
-
config.plugin = [
|
|
432
|
-
...plugins.filter(
|
|
433
|
-
(plugin) => plugin !== PACKAGE_NAME && !plugin.startsWith(`${PACKAGE_NAME}@`)
|
|
434
|
-
),
|
|
435
|
-
`${PACKAGE_NAME}@latest`
|
|
436
|
-
];
|
|
437
|
-
}
|
|
438
|
-
if (update.disableDefaults) {
|
|
439
|
-
const agent = config.agent && typeof config.agent === "object" ? { ...config.agent } : {};
|
|
440
|
-
const explore = agent.explore && typeof agent.explore === "object" ? { ...agent.explore } : {};
|
|
441
|
-
const general = agent.general && typeof agent.general === "object" ? { ...agent.general } : {};
|
|
442
|
-
agent.explore = { ...explore, disable: true };
|
|
443
|
-
agent.general = { ...general, disable: true };
|
|
444
|
-
config.agent = agent;
|
|
445
|
-
}
|
|
446
|
-
return config;
|
|
447
|
-
}
|
|
448
|
-
function updateOpenCodeMainConfig(update) {
|
|
449
|
-
const configPath = getExistingConfigPath();
|
|
450
|
-
try {
|
|
451
|
-
ensureOpenCodeConfigDir();
|
|
452
|
-
} catch (err) {
|
|
453
|
-
return {
|
|
454
|
-
success: false,
|
|
455
|
-
configPath,
|
|
456
|
-
error: `Failed to create config directory: ${err}`
|
|
457
|
-
};
|
|
458
|
-
}
|
|
459
|
-
try {
|
|
460
|
-
const { config: parsedConfig, error } = parseConfig(configPath);
|
|
461
|
-
if (error) {
|
|
462
|
-
return {
|
|
463
|
-
success: false,
|
|
464
|
-
configPath,
|
|
465
|
-
error: `Failed to parse config: ${error}`
|
|
466
|
-
};
|
|
467
|
-
}
|
|
468
|
-
writeConfig(
|
|
469
|
-
configPath,
|
|
470
|
-
mergeOpenCodeMainConfig(parsedConfig ?? {}, update)
|
|
471
|
-
);
|
|
472
|
-
return { success: true, configPath };
|
|
473
|
-
} catch (err) {
|
|
474
|
-
return {
|
|
475
|
-
success: false,
|
|
476
|
-
configPath,
|
|
477
|
-
error: `Failed to update opencode config: ${err}`
|
|
478
|
-
};
|
|
479
|
-
}
|
|
480
|
-
}
|
|
481
|
-
function writeLiteConfig(installConfig, targetPath) {
|
|
482
|
-
const configPath = targetPath ?? getLiteConfig();
|
|
483
|
-
try {
|
|
484
|
-
ensureConfigDir();
|
|
485
|
-
const config = generateLiteConfig(installConfig);
|
|
486
|
-
const tmpPath = `${configPath}.tmp`;
|
|
487
|
-
const bakPath = `${configPath}.bak`;
|
|
488
|
-
const content = `${JSON.stringify(config, null, 2)}
|
|
489
|
-
`;
|
|
490
|
-
if (existsSync2(configPath)) {
|
|
491
|
-
copyFileSync(configPath, bakPath);
|
|
492
|
-
}
|
|
493
|
-
writeFileSync(tmpPath, content);
|
|
494
|
-
renameSync(tmpPath, configPath);
|
|
495
|
-
return { success: true, configPath };
|
|
496
|
-
} catch (err) {
|
|
497
|
-
return {
|
|
498
|
-
success: false,
|
|
499
|
-
configPath,
|
|
500
|
-
error: `Failed to write lite config: ${err}`
|
|
501
|
-
};
|
|
502
|
-
}
|
|
503
|
-
}
|
|
504
|
-
function detectCurrentConfig() {
|
|
505
|
-
const result = {
|
|
506
|
-
isInstalled: false,
|
|
507
|
-
hasKimi: false,
|
|
508
|
-
hasOpenAI: false,
|
|
509
|
-
hasAnthropic: false,
|
|
510
|
-
hasCopilot: false,
|
|
511
|
-
hasZaiPlan: false,
|
|
512
|
-
hasAntigravity: false,
|
|
513
|
-
hasChutes: false,
|
|
514
|
-
hasOpencodeZen: false,
|
|
515
|
-
hasTmux: false
|
|
516
|
-
};
|
|
517
|
-
const { config } = parseConfig(getExistingConfigPath());
|
|
518
|
-
if (!config) return result;
|
|
519
|
-
const plugins = config.plugin ?? [];
|
|
520
|
-
result.isInstalled = plugins.some((p) => p.startsWith(PACKAGE_NAME));
|
|
521
|
-
result.hasAntigravity = plugins.some(
|
|
522
|
-
(p) => p.startsWith("opencode-antigravity-auth")
|
|
523
|
-
);
|
|
524
|
-
const providers = config.provider;
|
|
525
|
-
result.hasKimi = !!providers?.kimi;
|
|
526
|
-
result.hasAnthropic = !!providers?.anthropic;
|
|
527
|
-
result.hasCopilot = !!providers?.["github-copilot"];
|
|
528
|
-
result.hasZaiPlan = !!providers?.["zai-coding-plan"];
|
|
529
|
-
result.hasChutes = !!providers?.chutes;
|
|
530
|
-
if (providers?.google) result.hasAntigravity = true;
|
|
531
|
-
const { config: liteConfig } = parseConfig(getLiteConfig());
|
|
532
|
-
if (liteConfig && typeof liteConfig === "object") {
|
|
533
|
-
const configObj = liteConfig;
|
|
534
|
-
const presetName = configObj.preset;
|
|
535
|
-
const presets = configObj.presets;
|
|
536
|
-
const agents = presets?.[presetName];
|
|
537
|
-
if (agents) {
|
|
538
|
-
const models = Object.values(agents).map((a) => a?.model).filter(Boolean);
|
|
539
|
-
result.hasOpenAI = models.some((m) => m?.startsWith("openai/"));
|
|
540
|
-
result.hasAnthropic = models.some((m) => m?.startsWith("anthropic/"));
|
|
541
|
-
result.hasCopilot = models.some((m) => m?.startsWith("github-copilot/"));
|
|
542
|
-
result.hasZaiPlan = models.some((m) => m?.startsWith("zai-coding-plan/"));
|
|
543
|
-
result.hasOpencodeZen = models.some((m) => m?.startsWith("opencode/"));
|
|
544
|
-
if (models.some((m) => m?.startsWith("google/"))) {
|
|
545
|
-
result.hasAntigravity = true;
|
|
546
|
-
}
|
|
547
|
-
if (models.some((m) => m?.startsWith("chutes/"))) {
|
|
548
|
-
result.hasChutes = true;
|
|
549
|
-
}
|
|
550
|
-
}
|
|
551
|
-
if (configObj.tmux && typeof configObj.tmux === "object") {
|
|
552
|
-
const tmuxConfig = configObj.tmux;
|
|
553
|
-
result.hasTmux = tmuxConfig.enabled === true;
|
|
554
|
-
}
|
|
555
|
-
}
|
|
556
|
-
return result;
|
|
557
|
-
}
|
|
558
|
-
|
|
559
|
-
// src/config/loader.ts
|
|
560
|
-
var PROMPTS_DIR_NAME = "thoth-agents";
|
|
561
|
-
function loadConfigFromPath(configPath) {
|
|
562
|
-
try {
|
|
563
|
-
const content = fs.readFileSync(configPath, "utf-8");
|
|
564
|
-
const rawConfig = JSON.parse(stripJsonComments(content));
|
|
565
|
-
const result = PluginConfigSchema.safeParse(rawConfig);
|
|
566
|
-
if (!result.success) {
|
|
567
|
-
console.warn(`[thoth-agents] Invalid config at ${configPath}:`);
|
|
568
|
-
console.warn(result.error.format());
|
|
569
|
-
return null;
|
|
570
|
-
}
|
|
571
|
-
return result.data;
|
|
572
|
-
} catch (error) {
|
|
573
|
-
if (error instanceof Error && "code" in error && error.code !== "ENOENT") {
|
|
574
|
-
console.warn(
|
|
575
|
-
`[thoth-agents] Error reading config from ${configPath}:`,
|
|
576
|
-
error.message
|
|
577
|
-
);
|
|
578
|
-
}
|
|
579
|
-
return null;
|
|
580
|
-
}
|
|
581
|
-
}
|
|
582
|
-
function findConfigPath(basePath) {
|
|
583
|
-
const jsoncPath = `${basePath}.jsonc`;
|
|
584
|
-
const jsonPath = `${basePath}.json`;
|
|
585
|
-
if (fs.existsSync(jsoncPath)) {
|
|
586
|
-
return jsoncPath;
|
|
587
|
-
}
|
|
588
|
-
if (fs.existsSync(jsonPath)) {
|
|
589
|
-
return jsonPath;
|
|
590
|
-
}
|
|
591
|
-
return null;
|
|
592
|
-
}
|
|
593
|
-
function deepMerge(base, override) {
|
|
594
|
-
if (!base) return override;
|
|
595
|
-
if (!override) return base;
|
|
596
|
-
const result = { ...base };
|
|
597
|
-
for (const key of Object.keys(override)) {
|
|
598
|
-
const baseVal = base[key];
|
|
599
|
-
const overrideVal = override[key];
|
|
600
|
-
if (typeof baseVal === "object" && baseVal !== null && typeof overrideVal === "object" && overrideVal !== null && !Array.isArray(baseVal) && !Array.isArray(overrideVal)) {
|
|
601
|
-
result[key] = deepMerge(
|
|
602
|
-
baseVal,
|
|
603
|
-
overrideVal
|
|
604
|
-
);
|
|
605
|
-
} else {
|
|
606
|
-
result[key] = overrideVal;
|
|
607
|
-
}
|
|
608
|
-
}
|
|
609
|
-
return result;
|
|
610
|
-
}
|
|
611
|
-
function loadPluginConfig(directory) {
|
|
612
|
-
const userConfigBasePath = path.join(getConfigDir(), "thoth-agents");
|
|
613
|
-
const projectConfigBasePath = path.join(
|
|
614
|
-
directory,
|
|
615
|
-
".opencode",
|
|
616
|
-
"thoth-agents"
|
|
617
|
-
);
|
|
618
|
-
const userConfigPath = findConfigPath(userConfigBasePath);
|
|
619
|
-
const projectConfigPath = findConfigPath(projectConfigBasePath);
|
|
620
|
-
let config = userConfigPath ? loadConfigFromPath(userConfigPath) ?? {} : {};
|
|
621
|
-
const projectConfig = projectConfigPath ? loadConfigFromPath(projectConfigPath) : null;
|
|
622
|
-
if (projectConfig) {
|
|
623
|
-
config = {
|
|
624
|
-
...config,
|
|
625
|
-
...projectConfig,
|
|
626
|
-
agents: deepMerge(config.agents, projectConfig.agents),
|
|
627
|
-
tmux: deepMerge(config.tmux, projectConfig.tmux),
|
|
628
|
-
fallback: deepMerge(config.fallback, projectConfig.fallback),
|
|
629
|
-
thoth: deepMerge(config.thoth, projectConfig.thoth),
|
|
630
|
-
artifactStore: deepMerge(
|
|
631
|
-
config.artifactStore,
|
|
632
|
-
projectConfig.artifactStore
|
|
633
|
-
),
|
|
634
|
-
codex: deepMerge(config.codex, projectConfig.codex)
|
|
635
|
-
};
|
|
636
|
-
}
|
|
637
|
-
const envPreset = process.env.THOTH_AGENTS_PRESET;
|
|
638
|
-
if (envPreset) {
|
|
639
|
-
config.preset = envPreset;
|
|
640
|
-
}
|
|
641
|
-
if (config.preset) {
|
|
642
|
-
const preset = config.presets?.[config.preset];
|
|
643
|
-
if (preset) {
|
|
644
|
-
config.agents = deepMerge(preset, config.agents);
|
|
645
|
-
} else {
|
|
646
|
-
const presetSource = envPreset === config.preset ? "environment variable" : "config file";
|
|
647
|
-
const availablePresets = config.presets ? Object.keys(config.presets).join(", ") : "none";
|
|
648
|
-
console.warn(
|
|
649
|
-
`[thoth-agents] Preset "${config.preset}" not found (from ${presetSource}). Available presets: ${availablePresets}`
|
|
650
|
-
);
|
|
651
|
-
}
|
|
652
|
-
}
|
|
653
|
-
return config;
|
|
654
|
-
}
|
|
655
|
-
function loadAgentPrompt(agentName, preset) {
|
|
656
|
-
const presetDirName = preset && /^[a-zA-Z0-9_-]+$/.test(preset) ? preset : void 0;
|
|
657
|
-
const promptsDir = path.join(getConfigDir(), PROMPTS_DIR_NAME);
|
|
658
|
-
const promptSearchDirs = presetDirName ? [path.join(promptsDir, presetDirName), promptsDir] : [promptsDir];
|
|
659
|
-
const result = {};
|
|
660
|
-
const readFirstPrompt = (fileName, errorPrefix) => {
|
|
661
|
-
for (const dir of promptSearchDirs) {
|
|
662
|
-
const promptPath = path.join(dir, fileName);
|
|
663
|
-
if (!fs.existsSync(promptPath)) {
|
|
664
|
-
continue;
|
|
665
|
-
}
|
|
666
|
-
try {
|
|
667
|
-
return fs.readFileSync(promptPath, "utf-8");
|
|
668
|
-
} catch (error) {
|
|
669
|
-
console.warn(
|
|
670
|
-
`[thoth-agents] ${errorPrefix} ${promptPath}:`,
|
|
671
|
-
error instanceof Error ? error.message : String(error)
|
|
672
|
-
);
|
|
673
|
-
}
|
|
674
|
-
}
|
|
675
|
-
return void 0;
|
|
676
|
-
};
|
|
677
|
-
result.prompt = readFirstPrompt(
|
|
678
|
-
`${agentName}.md`,
|
|
679
|
-
"Error reading prompt file"
|
|
680
|
-
);
|
|
681
|
-
result.appendPrompt = readFirstPrompt(
|
|
682
|
-
`${agentName}_append.md`,
|
|
683
|
-
"Error reading append prompt file"
|
|
684
|
-
);
|
|
685
|
-
return result;
|
|
686
|
-
}
|
|
687
|
-
|
|
688
|
-
// src/agents/prompt-dialects.ts
|
|
689
|
-
var OPENCODE_CAPABILITIES = {
|
|
690
|
-
agentDefinitions: "supported",
|
|
691
|
-
delegatedExecution: "supported",
|
|
692
|
-
parallelDelegation: "supported",
|
|
693
|
-
runtimeHooks: "supported",
|
|
694
|
-
mcpConfiguration: "supported",
|
|
695
|
-
skillPackaging: "supported",
|
|
696
|
-
rolePermissions: "supported",
|
|
697
|
-
parentContextInjection: "supported",
|
|
698
|
-
memoryGovernanceEnforcement: "supported"
|
|
699
|
-
};
|
|
700
|
-
var CODEX_PROMPT_CAPABILITIES = {
|
|
701
|
-
agentDefinitions: "supported",
|
|
702
|
-
delegatedExecution: "supported",
|
|
703
|
-
parallelDelegation: "supported",
|
|
704
|
-
runtimeHooks: "unknown",
|
|
705
|
-
mcpConfiguration: "supported",
|
|
706
|
-
skillPackaging: "supported",
|
|
707
|
-
rolePermissions: "instruction-only",
|
|
708
|
-
parentContextInjection: "instruction-only",
|
|
709
|
-
memoryGovernanceEnforcement: "instruction-only"
|
|
710
|
-
};
|
|
711
|
-
var CLAUDE_CODE_PROMPT_CAPABILITIES = {
|
|
712
|
-
agentDefinitions: "supported",
|
|
713
|
-
delegatedExecution: "supported",
|
|
714
|
-
parallelDelegation: "supported",
|
|
715
|
-
runtimeHooks: "supported",
|
|
716
|
-
mcpConfiguration: "supported",
|
|
717
|
-
skillPackaging: "supported",
|
|
718
|
-
rolePermissions: "supported",
|
|
719
|
-
parentContextInjection: "supported",
|
|
720
|
-
memoryGovernanceEnforcement: "supported"
|
|
721
|
-
};
|
|
722
|
-
function supportedCapabilityProfile(capabilities) {
|
|
723
|
-
return {
|
|
724
|
-
capabilities,
|
|
725
|
-
renderCapabilityDisclosure: () => void 0
|
|
726
|
-
};
|
|
727
|
-
}
|
|
728
|
-
function codexCapabilityDisclosure(capability) {
|
|
729
|
-
const status = CODEX_PROMPT_CAPABILITIES[capability];
|
|
730
|
-
if (status === "supported") {
|
|
731
|
-
return void 0;
|
|
732
|
-
}
|
|
733
|
-
if (status === "unknown") {
|
|
734
|
-
return `${capability}: unknown in Codex; treat related behavior as diagnostic-only unless the active Codex host documents support.`;
|
|
735
|
-
}
|
|
736
|
-
return `${capability}: ${status} in Codex; preserve the role responsibility as prompt guidance because equivalent runtime enforcement is not guaranteed.`;
|
|
737
|
-
}
|
|
738
|
-
var OPENCODE_PROMPT_DIALECT = {
|
|
739
|
-
harness: "opencode",
|
|
740
|
-
tools: {
|
|
741
|
-
delegationTool: "task",
|
|
742
|
-
backgroundDelegationTool: "task(background=true)",
|
|
743
|
-
backgroundStatusTool: "task_status",
|
|
744
|
-
userQuestionTool: "question",
|
|
745
|
-
progressTool: "todowrite",
|
|
746
|
-
hostStatusSurface: "task_status",
|
|
747
|
-
lifecycle: {
|
|
748
|
-
statusAction: "wait, poll, and collect",
|
|
749
|
-
terminalState: "terminal task_status result",
|
|
750
|
-
nonterminalState: "nonterminal task_status result",
|
|
751
|
-
sameSessionProbe: "task_status on the same task session",
|
|
752
|
-
enforcement: "runtime-supported"
|
|
753
|
-
},
|
|
754
|
-
roleReference: (role) => `@${role}`
|
|
755
|
-
},
|
|
756
|
-
capabilities: supportedCapabilityProfile(OPENCODE_CAPABILITIES),
|
|
757
|
-
dispatchLabel(method) {
|
|
758
|
-
switch (method) {
|
|
759
|
-
case "root-coordinator":
|
|
760
|
-
return "root coordinator";
|
|
761
|
-
case "task":
|
|
762
|
-
return "task";
|
|
763
|
-
case "synchronous-task-only":
|
|
764
|
-
return "synchronous task only";
|
|
765
|
-
}
|
|
766
|
-
},
|
|
767
|
-
renderRoleInvocation(role) {
|
|
768
|
-
return `@${role}`;
|
|
769
|
-
}
|
|
770
|
-
};
|
|
771
|
-
var CODEX_PROMPT_DIALECT = {
|
|
772
|
-
harness: "codex",
|
|
773
|
-
tools: {
|
|
774
|
-
delegationTool: "collaboration.spawn_agent",
|
|
775
|
-
backgroundDelegationTool: "collaboration.spawn_agent",
|
|
776
|
-
backgroundStatusTool: "collaboration.wait_agent",
|
|
777
|
-
userQuestionTool: "request_user_input",
|
|
778
|
-
progressTool: "functions.update_plan",
|
|
779
|
-
hostStatusSurface: "collaboration.list_agents",
|
|
780
|
-
lifecycle: {
|
|
781
|
-
statusAction: "wait and inspect status",
|
|
782
|
-
terminalState: "terminal mailbox completion or failure update",
|
|
783
|
-
nonterminalState: "collaboration.wait_agent timeout or silence",
|
|
784
|
-
sameSessionProbe: "collaboration.list_agents on the same task path",
|
|
785
|
-
enforcement: "runtime-supported"
|
|
786
|
-
},
|
|
787
|
-
roleReference: (role) => `${role} role agent`
|
|
788
|
-
},
|
|
789
|
-
capabilities: {
|
|
790
|
-
capabilities: CODEX_PROMPT_CAPABILITIES,
|
|
791
|
-
renderCapabilityDisclosure: codexCapabilityDisclosure
|
|
792
|
-
},
|
|
793
|
-
dispatchLabel(method) {
|
|
794
|
-
switch (method) {
|
|
795
|
-
case "root-coordinator":
|
|
796
|
-
return "ambient Codex root session coordinator";
|
|
797
|
-
case "task":
|
|
798
|
-
return "collaboration.spawn_agent";
|
|
799
|
-
case "synchronous-task-only":
|
|
800
|
-
return "synchronous collaboration.spawn_agent only";
|
|
801
|
-
}
|
|
802
|
-
},
|
|
803
|
-
renderRoleInvocation(role) {
|
|
804
|
-
return role === "orchestrator" ? "orchestrator role agent" : `${role} subagent`;
|
|
805
|
-
}
|
|
806
|
-
};
|
|
807
|
-
var CLAUDE_CODE_SUBAGENT_NAMESPACE = "thoth-agents";
|
|
808
|
-
function claudeCodeSubagentType(role) {
|
|
809
|
-
return `${CLAUDE_CODE_SUBAGENT_NAMESPACE}:${role}`;
|
|
810
|
-
}
|
|
811
|
-
var CLAUDE_CODE_PROMPT_DIALECT = {
|
|
812
|
-
harness: "claude",
|
|
813
|
-
tools: {
|
|
814
|
-
delegationTool: "Task",
|
|
815
|
-
backgroundDelegationTool: "Task(run_in_background=true)",
|
|
816
|
-
backgroundStatusTool: "TaskOutput",
|
|
817
|
-
userQuestionTool: "AskUserQuestion",
|
|
818
|
-
progressTool: "TodoWrite",
|
|
819
|
-
hostStatusSurface: "TodoWrite",
|
|
820
|
-
lifecycle: {
|
|
821
|
-
statusAction: "wait, poll, and collect",
|
|
822
|
-
terminalState: "terminal TaskOutput result",
|
|
823
|
-
nonterminalState: "nonterminal TaskOutput result",
|
|
824
|
-
sameSessionProbe: "TaskOutput on the same task session",
|
|
825
|
-
enforcement: "runtime-supported"
|
|
826
|
-
},
|
|
827
|
-
roleReference: (role) => role === "orchestrator" ? "the main-thread orchestrator" : `Task(subagent_type: ${claudeCodeSubagentType(role)})`
|
|
828
|
-
},
|
|
829
|
-
capabilities: supportedCapabilityProfile(CLAUDE_CODE_PROMPT_CAPABILITIES),
|
|
830
|
-
dispatchLabel(method) {
|
|
831
|
-
switch (method) {
|
|
832
|
-
case "root-coordinator":
|
|
833
|
-
return "main-session coordinator";
|
|
834
|
-
case "task":
|
|
835
|
-
return "Task tool";
|
|
836
|
-
case "synchronous-task-only":
|
|
837
|
-
return "synchronous Task only";
|
|
838
|
-
}
|
|
839
|
-
},
|
|
840
|
-
renderRoleInvocation(role) {
|
|
841
|
-
return role === "orchestrator" ? "main-thread orchestrator" : claudeCodeSubagentType(role);
|
|
842
|
-
}
|
|
843
|
-
};
|
|
844
|
-
|
|
845
|
-
// src/harness/core/sdd.ts
|
|
846
|
-
var SDD_VERIFY_MAX_ROUNDS = 3;
|
|
847
|
-
var SDD_PHASES = [
|
|
848
|
-
{
|
|
849
|
-
id: "requirements-interview",
|
|
850
|
-
order: 0,
|
|
851
|
-
requiredFor: ["direct", "accelerated", "full"],
|
|
852
|
-
prerequisites: [],
|
|
853
|
-
producesArtifact: false,
|
|
854
|
-
owner: "orchestrator",
|
|
855
|
-
delegationReason: "Root-owned requirements discovery, scope calibration, and route approval."
|
|
856
|
-
},
|
|
857
|
-
{
|
|
858
|
-
id: "init",
|
|
859
|
-
order: 1,
|
|
860
|
-
requiredFor: [],
|
|
861
|
-
prerequisites: ["requirements-interview"],
|
|
862
|
-
producesArtifact: true,
|
|
863
|
-
owner: "write-capable-agent",
|
|
864
|
-
artifactSkill: "sdd-init",
|
|
865
|
-
condition: "Only when OpenSpec persistence is selected and openspec/ is missing or stale (partial structure or missing mechanism sections).",
|
|
866
|
-
defaultAgentRole: "quick",
|
|
867
|
-
supportingAgentRoles: ["explorer"],
|
|
868
|
-
delegationReason: "Fast mechanical bootstrap, with explorer supplying repository facts when needed."
|
|
869
|
-
},
|
|
870
|
-
{
|
|
871
|
-
id: "explore",
|
|
872
|
-
order: 2,
|
|
873
|
-
requiredFor: ["accelerated", "full"],
|
|
874
|
-
prerequisites: ["requirements-interview"],
|
|
875
|
-
producesArtifact: false,
|
|
876
|
-
owner: "read-only-agent",
|
|
877
|
-
defaultAgentRole: "explorer",
|
|
878
|
-
supportingAgentRoles: ["librarian"],
|
|
879
|
-
delegationReason: "Read-only repository discovery before artifact-producing SDD phases."
|
|
880
|
-
},
|
|
881
|
-
{
|
|
882
|
-
id: "proposal",
|
|
883
|
-
order: 3,
|
|
884
|
-
requiredFor: ["accelerated", "full"],
|
|
885
|
-
prerequisites: ["requirements-interview", "explore"],
|
|
886
|
-
producesArtifact: true,
|
|
887
|
-
owner: "write-capable-agent",
|
|
888
|
-
artifactSkill: "sdd-propose",
|
|
889
|
-
defaultAgentRole: "deep",
|
|
890
|
-
supportingAgentRoles: ["oracle"],
|
|
891
|
-
delegationReason: "Structured technical reasoning and trade-off synthesis before implementation.",
|
|
892
|
-
handoffHints: [
|
|
893
|
-
"Preserve accepted scope and explicit non-goals downstream.",
|
|
894
|
-
"Carry deferred or discovery affected areas forward as follow-up."
|
|
895
|
-
]
|
|
896
|
-
},
|
|
897
|
-
{
|
|
898
|
-
id: "spec",
|
|
899
|
-
order: 4,
|
|
900
|
-
requiredFor: ["full"],
|
|
901
|
-
prerequisites: ["proposal"],
|
|
902
|
-
producesArtifact: true,
|
|
903
|
-
owner: "write-capable-agent",
|
|
904
|
-
artifactSkill: "sdd-spec",
|
|
905
|
-
defaultAgentRole: "deep",
|
|
906
|
-
supportingAgentRoles: ["oracle"],
|
|
907
|
-
delegationReason: "High-quality requirement contract work where ambiguity propagates downstream.",
|
|
908
|
-
handoffHints: [
|
|
909
|
-
"Preserve recorded Assumptions and any [NEEDS CLARIFICATION] resolutions.",
|
|
910
|
-
"Keep the requirements-quality checklist resolved before tasks."
|
|
911
|
-
]
|
|
912
|
-
},
|
|
913
|
-
{
|
|
914
|
-
id: "clarify",
|
|
915
|
-
order: 5,
|
|
916
|
-
requiredFor: ["full"],
|
|
917
|
-
prerequisites: ["spec"],
|
|
918
|
-
producesArtifact: false,
|
|
919
|
-
owner: "write-capable-agent",
|
|
920
|
-
artifactSkill: "sdd-clarify",
|
|
921
|
-
defaultAgentRole: "deep",
|
|
922
|
-
supportingAgentRoles: ["oracle"],
|
|
923
|
-
delegationReason: "Resolve residual spec ambiguity in place before design consumes it.",
|
|
924
|
-
handoffHints: [
|
|
925
|
-
"Preserve clarified resolutions written back into the spec.",
|
|
926
|
-
"Keep the requirements-quality checklist re-validated before design."
|
|
927
|
-
]
|
|
928
|
-
},
|
|
929
|
-
{
|
|
930
|
-
id: "design",
|
|
931
|
-
order: 6,
|
|
932
|
-
requiredFor: ["full"],
|
|
933
|
-
prerequisites: ["proposal", "clarify"],
|
|
934
|
-
producesArtifact: true,
|
|
935
|
-
owner: "write-capable-agent",
|
|
936
|
-
artifactSkill: "sdd-design",
|
|
937
|
-
artifactMeaning: "technical-solution-design",
|
|
938
|
-
defaultAgentRole: "deep",
|
|
939
|
-
supportingAgentRoles: ["designer"],
|
|
940
|
-
delegationReason: "Technical architecture and file-change design; designer only supports UI/UX concerns.",
|
|
941
|
-
handoffHints: [
|
|
942
|
-
"Preserve coverage decisions and architecture constraints in tasks.",
|
|
943
|
-
"Honor the Constitution Check outcome recorded during design."
|
|
944
|
-
]
|
|
945
|
-
},
|
|
946
|
-
{
|
|
947
|
-
id: "tasks",
|
|
948
|
-
order: 7,
|
|
949
|
-
requiredFor: ["accelerated", "full"],
|
|
950
|
-
prerequisites: ["proposal", "spec", "design"],
|
|
951
|
-
producesArtifact: true,
|
|
952
|
-
owner: "write-capable-agent",
|
|
953
|
-
artifactSkill: "sdd-tasks",
|
|
954
|
-
defaultAgentRole: "quick",
|
|
955
|
-
alternateAgentRoles: ["deep"],
|
|
956
|
-
alternateAgentCondition: "Only when the task plan is complex.",
|
|
957
|
-
delegationReason: "Mechanical conversion of settled design into dependency-ordered execution tasks."
|
|
958
|
-
},
|
|
959
|
-
{
|
|
960
|
-
id: "plan-review",
|
|
961
|
-
order: 8,
|
|
962
|
-
requiredFor: ["accelerated", "full"],
|
|
963
|
-
prerequisites: ["tasks"],
|
|
964
|
-
producesArtifact: true,
|
|
965
|
-
gate: "oracle-review",
|
|
966
|
-
owner: "oracle",
|
|
967
|
-
artifactSkill: "plan-reviewer",
|
|
968
|
-
artifactMeaning: "durable-plan-review-result",
|
|
969
|
-
defaultAgentRole: "oracle",
|
|
970
|
-
persistenceAgentRole: "quick",
|
|
971
|
-
delegationReason: "Independent read-only executability review of tasks before implementation; quick persists the durable review artifact when writes are required."
|
|
972
|
-
},
|
|
973
|
-
{
|
|
974
|
-
id: "implementation-confirmation",
|
|
975
|
-
order: 9,
|
|
976
|
-
requiredFor: ["accelerated", "full"],
|
|
977
|
-
prerequisites: ["plan-review"],
|
|
978
|
-
producesArtifact: false,
|
|
979
|
-
gate: "user-confirmation",
|
|
980
|
-
owner: "user",
|
|
981
|
-
delegationReason: "Human approval gate after reviewed tasks and before workspace implementation."
|
|
982
|
-
},
|
|
983
|
-
{
|
|
984
|
-
id: "apply",
|
|
985
|
-
order: 10,
|
|
986
|
-
requiredFor: ["direct", "accelerated", "full"],
|
|
987
|
-
prerequisites: ["implementation-confirmation"],
|
|
988
|
-
producesArtifact: false,
|
|
989
|
-
owner: "write-capable-agent",
|
|
990
|
-
defaultAgentRole: "deep",
|
|
991
|
-
alternateAgentRoles: ["quick", "designer"],
|
|
992
|
-
delegationReason: "Correctness-heavy implementation by default; quick handles mechanical batches and designer owns UI/visual work."
|
|
993
|
-
},
|
|
994
|
-
{
|
|
995
|
-
id: "verify",
|
|
996
|
-
order: 11,
|
|
997
|
-
requiredFor: ["accelerated", "full"],
|
|
998
|
-
prerequisites: ["apply"],
|
|
999
|
-
producesArtifact: true,
|
|
1000
|
-
gate: "iterative-verify",
|
|
1001
|
-
maxRounds: SDD_VERIFY_MAX_ROUNDS,
|
|
1002
|
-
owner: "oracle",
|
|
1003
|
-
artifactSkill: "sdd-verify",
|
|
1004
|
-
defaultAgentRole: "oracle",
|
|
1005
|
-
persistenceAgentRole: "quick",
|
|
1006
|
-
delegationReason: "Independent verification review; quick persists the report when the selected store requires writes."
|
|
1007
|
-
},
|
|
1008
|
-
{
|
|
1009
|
-
id: "archive",
|
|
1010
|
-
order: 12,
|
|
1011
|
-
requiredFor: ["accelerated", "full"],
|
|
1012
|
-
prerequisites: ["verify"],
|
|
1013
|
-
producesArtifact: true,
|
|
1014
|
-
owner: "write-capable-agent",
|
|
1015
|
-
artifactSkill: "sdd-archive",
|
|
1016
|
-
defaultAgentRole: "quick",
|
|
1017
|
-
delegationReason: "Mechanical closeout, summary, and archive movement after verification passes."
|
|
1018
|
-
}
|
|
1019
|
-
];
|
|
1020
|
-
var SDD_WORKFLOW_CONTRACT = {
|
|
1021
|
-
phases: [...SDD_PHASES],
|
|
1022
|
-
routingRules: [
|
|
1023
|
-
"Requirements interview is step zero for all non-trivial work.",
|
|
1024
|
-
"Scope-faithful invariant: accepted user intent/scope is preserved; unresolved affected areas remain explicit as deferred/discovery follow-up.",
|
|
1025
|
-
"Direct implementation is reserved for low-complexity work.",
|
|
1026
|
-
"Accelerated SDD follows explore -> proposal -> tasks before execution.",
|
|
1027
|
-
"Full SDD follows explore -> proposal -> spec -> clarify -> design -> tasks before execution."
|
|
1028
|
-
],
|
|
1029
|
-
artifactRules: [
|
|
1030
|
-
"SDD delegation defaults are phase-specific: sdd-propose, sdd-spec, and sdd-design default to deep.",
|
|
1031
|
-
"sdd-tasks defaults to quick with deep as fallback when the task plan is complex.",
|
|
1032
|
-
"plan-reviewer defaults to oracle for independent read-only review; quick persists the plan-review artifact when repository or memory writes are required.",
|
|
1033
|
-
"sdd-verify defaults to oracle for independent review; quick persists the report when repository or memory writes are required.",
|
|
1034
|
-
"sdd-archive defaults to quick for mechanical closeout.",
|
|
1035
|
-
"OpenSpec design.md is technical solution design, not UI/UX design; sdd-design itself never routes to designer.",
|
|
1036
|
-
"Designer participates during apply only for user-facing UI, visual work, screenshots, or visual QA.",
|
|
1037
|
-
"Full-pipeline tasks require proposal, spec, and design artifacts.",
|
|
1038
|
-
"Oracle is read-only and performs plan review plus independent verification review; it does not persist artifacts.",
|
|
1039
|
-
"A fresh persisted plan-review approval satisfies only the plan-review gate; user implementation confirmation remains separate."
|
|
1040
|
-
],
|
|
1041
|
-
verificationRules: [
|
|
1042
|
-
"Plan review must complete before implementation confirmation.",
|
|
1043
|
-
"User confirmation is required after plan-review approval and before apply.",
|
|
1044
|
-
"Apply is followed by verify and archive for SDD pipelines.",
|
|
1045
|
-
"Verify runs as a bounded iterative gate of at most SDD_VERIFY_MAX_ROUNDS rounds; on exhausted failure escalate to the user."
|
|
1046
|
-
]
|
|
1047
|
-
};
|
|
1048
|
-
function getSddWorkflowContract() {
|
|
1049
|
-
return {
|
|
1050
|
-
phases: SDD_WORKFLOW_CONTRACT.phases.map((phase) => ({
|
|
1051
|
-
...phase,
|
|
1052
|
-
requiredFor: [...phase.requiredFor],
|
|
1053
|
-
prerequisites: [...phase.prerequisites],
|
|
1054
|
-
alternateAgentRoles: phase.alternateAgentRoles ? [...phase.alternateAgentRoles] : void 0,
|
|
1055
|
-
supportingAgentRoles: phase.supportingAgentRoles ? [...phase.supportingAgentRoles] : void 0,
|
|
1056
|
-
handoffHints: phase.handoffHints ? [...phase.handoffHints] : void 0
|
|
1057
|
-
})),
|
|
1058
|
-
routingRules: [...SDD_WORKFLOW_CONTRACT.routingRules],
|
|
1059
|
-
artifactRules: [...SDD_WORKFLOW_CONTRACT.artifactRules],
|
|
1060
|
-
verificationRules: [...SDD_WORKFLOW_CONTRACT.verificationRules]
|
|
1061
|
-
};
|
|
1062
|
-
}
|
|
1063
|
-
|
|
1064
|
-
// src/agents/prompt-sections.ts
|
|
1065
|
-
function createQuestionProtocolSection() {
|
|
1066
|
-
return {
|
|
1067
|
-
kind: "question-protocol",
|
|
1068
|
-
toolConcept: "userQuestion"
|
|
1069
|
-
};
|
|
1070
|
-
}
|
|
1071
|
-
function createSubagentRulesSection(memoryAccess = "base") {
|
|
1072
|
-
return {
|
|
1073
|
-
kind: "subagent-rules",
|
|
1074
|
-
memoryAccess,
|
|
1075
|
-
progressConcept: "progress",
|
|
1076
|
-
userQuestionConcept: "userQuestion"
|
|
1077
|
-
};
|
|
1078
|
-
}
|
|
1079
|
-
function createReasoningDisciplineSection() {
|
|
1080
|
-
return { kind: "reasoning-discipline" };
|
|
1081
|
-
}
|
|
1082
|
-
function createResponseBudgetSection() {
|
|
1083
|
-
return { kind: "response-budget" };
|
|
1084
|
-
}
|
|
1085
|
-
function createStepBudgetSection(steps) {
|
|
1086
|
-
if (steps === void 0 || !Number.isInteger(steps) || steps <= 0) {
|
|
1087
|
-
return void 0;
|
|
1088
|
-
}
|
|
1089
|
-
return { kind: "step-budget", steps };
|
|
1090
|
-
}
|
|
1091
|
-
function detectModelFamilyFromModel(model) {
|
|
1092
|
-
const id = getPrimaryModelId2(model)?.toLowerCase();
|
|
1093
|
-
if (!id) {
|
|
1094
|
-
return void 0;
|
|
1095
|
-
}
|
|
1096
|
-
if (id.includes("claude") || id.startsWith("anthropic/")) {
|
|
1097
|
-
return "claude";
|
|
1098
|
-
}
|
|
1099
|
-
if (id.includes("gpt") || id.startsWith("openai/")) {
|
|
1100
|
-
return "openai";
|
|
1101
|
-
}
|
|
1102
|
-
if (id.includes("gemini") || id.startsWith("google/")) {
|
|
1103
|
-
return "gemini";
|
|
1104
|
-
}
|
|
1105
|
-
if (id.includes("kimi") || id.includes("k2")) {
|
|
1106
|
-
return "kimi";
|
|
1107
|
-
}
|
|
1108
|
-
if (id.includes("glm") || id.startsWith("zai-")) {
|
|
1109
|
-
return "glm";
|
|
1110
|
-
}
|
|
1111
|
-
return void 0;
|
|
1112
|
-
}
|
|
1113
|
-
function createModelFamilySection(role, model) {
|
|
1114
|
-
const family = detectModelFamilyFromModel(model);
|
|
1115
|
-
if (!family) {
|
|
1116
|
-
return void 0;
|
|
1117
|
-
}
|
|
1118
|
-
return { kind: "model-family", role, family };
|
|
1119
|
-
}
|
|
1120
|
-
function roleText(template) {
|
|
1121
|
-
return { kind: "role-text", template };
|
|
1122
|
-
}
|
|
1123
|
-
function roleTemplate(role) {
|
|
1124
|
-
return `{{role.${role}}}`;
|
|
1125
|
-
}
|
|
1126
|
-
function renderRoleList(roles) {
|
|
1127
|
-
return roles.map(roleTemplate).join(", ");
|
|
1128
|
-
}
|
|
1129
|
-
function getDelegatedSddPhase(id) {
|
|
1130
|
-
const phase = getSddWorkflowContract().phases.find(
|
|
1131
|
-
(candidate) => candidate.id === id
|
|
1132
|
-
);
|
|
1133
|
-
if (!phase?.defaultAgentRole) {
|
|
1134
|
-
throw new Error(`Missing SDD delegation role for ${id}`);
|
|
1135
|
-
}
|
|
1136
|
-
return phase;
|
|
1137
|
-
}
|
|
1138
|
-
function primarySddRole(id) {
|
|
1139
|
-
return roleTemplate(getDelegatedSddPhase(id).defaultAgentRole);
|
|
1140
|
-
}
|
|
1141
|
-
function alternateSddRoles(id) {
|
|
1142
|
-
const phase = getDelegatedSddPhase(id);
|
|
1143
|
-
return phase.alternateAgentRoles?.length ? renderRoleList(phase.alternateAgentRoles) : "";
|
|
1144
|
-
}
|
|
1145
|
-
function alternateSddCondition(id) {
|
|
1146
|
-
const condition = getDelegatedSddPhase(id).alternateAgentCondition;
|
|
1147
|
-
return condition ? condition.replace(/^Only/, "only").replace(/\.$/, "") : "";
|
|
1148
|
-
}
|
|
1149
|
-
function supportSddRoles(id) {
|
|
1150
|
-
const phase = getDelegatedSddPhase(id);
|
|
1151
|
-
return phase.supportingAgentRoles?.length ? renderRoleList(phase.supportingAgentRoles) : "";
|
|
1152
|
-
}
|
|
1153
|
-
function persistenceSddRole(id) {
|
|
1154
|
-
const phase = getDelegatedSddPhase(id);
|
|
1155
|
-
return phase.persistenceAgentRole ? roleTemplate(phase.persistenceAgentRole) : "";
|
|
1156
|
-
}
|
|
1157
|
-
function renderSddDelegationMatrix() {
|
|
1158
|
-
return `<sdd-delegation-matrix>
|
|
1159
|
-
- sdd-init -> ${primarySddRole("init")} (+${supportSddRoles("init")}, if openspec/ missing); sdd-explore -> ${primarySddRole("explore")} (+${supportSddRoles("explore")})
|
|
1160
|
-
- sdd-propose/sdd-spec/sdd-design -> ${primarySddRole("proposal")}; sdd-clarify -> ${primarySddRole("clarify")}; sdd-tasks -> ${primarySddRole("tasks")} (fallback: ${alternateSddRoles("tasks")} ${alternateSddCondition("tasks")})
|
|
1161
|
-
- plan-reviewer -> ${primarySddRole("plan-review")}; sdd-apply -> ${primarySddRole("apply")} (fallback: ${alternateSddRoles("apply")}); sdd-verify -> ${primarySddRole("verify")} (persistence: ${persistenceSddRole("verify")}); sdd-archive -> ${primarySddRole("archive")}
|
|
1162
|
-
</sdd-delegation-matrix>`;
|
|
1163
|
-
}
|
|
1164
|
-
function specialistSections({
|
|
1165
|
-
role,
|
|
1166
|
-
mode,
|
|
1167
|
-
dispatch,
|
|
1168
|
-
scope,
|
|
1169
|
-
responsibility,
|
|
1170
|
-
rules,
|
|
1171
|
-
memoryAccess,
|
|
1172
|
-
output
|
|
1173
|
-
}) {
|
|
1174
|
-
const dispatchLabel = dispatch === "task" ? "{{dispatch.task}}" : "{{dispatch.synchronous-task-only}}";
|
|
1175
|
-
return [
|
|
1176
|
-
roleText(`<role>
|
|
1177
|
-
You are ${role}.
|
|
1178
|
-
</role>
|
|
1179
|
-
|
|
1180
|
-
<mode>
|
|
1181
|
-
- Mode: ${mode}
|
|
1182
|
-
- Dispatch method: ${dispatchLabel}
|
|
1183
|
-
- Scope: ${scope}
|
|
1184
|
-
</mode>
|
|
1185
|
-
|
|
1186
|
-
<responsibility>
|
|
1187
|
-
${responsibility}
|
|
1188
|
-
</responsibility>
|
|
1189
|
-
|
|
1190
|
-
`),
|
|
1191
|
-
createReasoningDisciplineSection(),
|
|
1192
|
-
roleText(`
|
|
1193
|
-
<rules>`),
|
|
1194
|
-
createSubagentRulesSection(memoryAccess),
|
|
1195
|
-
roleText(`${rules.join("\n")}
|
|
1196
|
-
</rules>`),
|
|
1197
|
-
createQuestionProtocolSection(),
|
|
1198
|
-
roleText(`<output>`),
|
|
1199
|
-
createResponseBudgetSection(),
|
|
1200
|
-
roleText(`${output}
|
|
1201
|
-
</output>`)
|
|
1202
|
-
];
|
|
1203
|
-
}
|
|
1204
|
-
function createOrchestratorPromptSections() {
|
|
1205
|
-
return [
|
|
1206
|
-
roleText(`<role>
|
|
1207
|
-
You are the delegate-first root coordinator and decision engine for thoth-agents.
|
|
1208
|
-
The root agent is the orchestrator/root coordinator for the session.
|
|
1209
|
-
Orchestrator-only, root-only, or orchestrator-owned rules still apply even if
|
|
1210
|
-
the harness does not name this agent "orchestrator".
|
|
1211
|
-
</role>
|
|
1212
|
-
|
|
1213
|
-
<style>
|
|
1214
|
-
Respond in the user's language. Be warm, direct, evidence-led, and concise.
|
|
1215
|
-
Push back when context, risk, or assumptions are weak. Avoid verbosity.
|
|
1216
|
-
</style>`),
|
|
1217
|
-
roleText(`
|
|
1218
|
-
|
|
1219
|
-
<core-rules>
|
|
1220
|
-
- Mode: primary coordinator. Mutation: coordination artifacts only.
|
|
1221
|
-
- Load \`thoth-mem-agents\` and \`requirements-interview\`.
|
|
1222
|
-
- Mutation remains limited to coordination artifacts such as \`openspec/\` during the SDD pipeline; implementation edits belong to write-capable sub-agents.
|
|
1223
|
-
- You may perform small bounded local inspection when cheaper, faster, or clearer than delegation: read a known file, confirm a script name, inspect a narrow artifact, or verify one concrete claim.
|
|
1224
|
-
- Keep any direct check narrow and evidence-led; do not become the default discovery, implementation, or verification worker.
|
|
1225
|
-
- Own the thinking: analyze, choose approach, handle task sequencing, synthesize facts, decide, ask \`{{userQuestionTool}}\` for blocking user input, manage progress, own root-session memory, and write the final report.
|
|
1226
|
-
- Use sub-agents for evidence and action, not to outsource architecture or planning.
|
|
1227
|
-
- Never request raw file dumps from sub-agents; ask for findings, paths, line anchors, diffs, verification, and blockers.
|
|
1228
|
-
- Use openspec/ for coordination artifacts, especially
|
|
1229
|
-
openspec/changes/{change-name}/tasks.md.
|
|
1230
|
-
- Visual or UX work and screenshots always go to {{role.designer}}.
|
|
1231
|
-
- Delegate broad search, multi-file edits, risky verification, UI visual QA, independent review, correctness-heavy debugging, and implementation-heavy work.
|
|
1232
|
-
- Verification should follow the user's project instructions and use the smallest sufficient delegated checks: typecheck, lint, focused tests, or build when appropriate.
|
|
1233
|
-
- When a harness cannot enforce a rule directly, preserve the rule as instruction-only guidance and disclose the enforcement gap instead of weakening the contract.
|
|
1234
|
-
</core-rules>
|
|
1235
|
-
|
|
1236
|
-
<epistemic-rigor>
|
|
1237
|
-
- Verify material user/agent claims before relying on them in implementation, architecture, verification, safety, or guidance.
|
|
1238
|
-
- Before solving/editing, post one short commentary update naming reasoning/root-cause check.
|
|
1239
|
-
- Do thought experiments: test competing explanations, edge cases, failure modes, root-cause fit.
|
|
1240
|
-
- Do not stop at first plausible explanation/superficial answer; validate with evidence, edge cases, tests, or fitting check.
|
|
1241
|
-
- If evidence disproves an assumption, correct it plainly, explain tradeoffs, and offer alternatives.
|
|
1242
|
-
</epistemic-rigor>
|
|
1243
|
-
|
|
1244
|
-
<session-bootstrap>
|
|
1245
|
-
- At the start of a new root session, when thoth-mem tools and session/project identity are available, load \`thoth-mem-agents\` and \`requirements-interview\`, then call \`mem_session(action="start")\` as step 0 before any other thoth-mem call.
|
|
1246
|
-
- Save only the real user request with \`mem_save(kind="prompt")\`; never save generated sub-agent prompts, handoffs, summaries, or tool scaffolding as user intent.
|
|
1247
|
-
- If thoth-mem tools or required session/project identity are unavailable, disclose that memory bootstrap could not run and continue without claiming memory was saved.
|
|
1248
|
-
</session-bootstrap>
|
|
1249
|
-
|
|
1250
|
-
<routing>
|
|
1251
|
-
{{role.explorer}}: read-only codebase discovery. Use for broad search, symbols, references, unknown paths, or multiple candidates.
|
|
1252
|
-
{{role.librarian}}: read-only external docs/public examples. Use for version-sensitive APIs, official docs, or unfamiliar libraries.
|
|
1253
|
-
{{role.oracle}}: read-only review/diagnosis. Use for architecture, security/correctness risk, plan review, persistent bugs, or high-stakes ambiguity.
|
|
1254
|
-
{{role.designer}}: write-capable UI/UX owner. Use for user-facing UI, styles, layout, interactions, and all visual QA.
|
|
1255
|
-
{{role.quick}}: write-capable narrow implementer. Use for clear, mechanical, low-risk, uniform edits.
|
|
1256
|
-
{{role.deep}}: write-capable thorough implementer. Use for backend logic, data flow, APIs, state, refactors, edge cases, or correctness-critical work.
|
|
1257
|
-
|
|
1258
|
-
Tiebreakers:
|
|
1259
|
-
- User-facing UI -> {{role.designer}}. Backend/system logic -> {{role.deep}}. Mechanical pattern -> {{role.quick}}.
|
|
1260
|
-
- Discovery first when paths or facts are unknown; implementation agent may read known local context for its own task, but should not redo broad discovery already assigned to {{role.explorer}}/{{role.librarian}}.
|
|
1261
|
-
- Do not use {{role.oracle}} for routine synthesis. After {{role.explorer}}/{{role.librarian}} results, you combine facts, inferences, unknowns, confidence, and next step.
|
|
1262
|
-
</routing>
|
|
1263
|
-
|
|
1264
|
-
<delegation-economics>
|
|
1265
|
-
- Choose direct action, delegation, parallelization, or review by net quality, speed, cost, and reliability.
|
|
1266
|
-
- Do not delegate when overhead exceeds a bounded direct check; delegate when breadth, risk, specialization, or independent review materially improves the result.
|
|
1267
|
-
- Parallelize only independent delegations; reconcile dependent steps after evidence returns.
|
|
1268
|
-
- Keep validation and final synthesis accountable to the root even when sub-agents gather evidence, implement, review, or verify.
|
|
1269
|
-
</delegation-economics>
|
|
1270
|
-
|
|
1271
|
-
<subagent-prompts>
|
|
1272
|
-
- Every sub-agent prompt you write must be in English, regardless of the user's language.
|
|
1273
|
-
- Keep user-facing replies in the user's language, but translate delegated task prompts, internal handoffs, SDD envelopes, and verification requests into English.
|
|
1274
|
-
- Prefer 2-3 surgical discovery probes over one broad exploration when independent facts can be gathered in parallel.
|
|
1275
|
-
- A surgical probe asks one narrow question and returns only the anchors needed for your decision.
|
|
1276
|
-
</subagent-prompts>
|
|
1277
|
-
|
|
1278
|
-
<internal-handoff>
|
|
1279
|
-
Before dispatching {{role.designer}}, {{role.quick}}, or {{role.deep}} after discovery, synthesize a compact internal handoff body for root-owned session context; it is not user-facing and must not be embedded in the initial sub-agent prompt.
|
|
1280
|
-
|
|
1281
|
-
Internal handoff fields: Goal, Decision, Evidence, Scope, Steps, Verification, Uncertainty, relevant files or symbols, suggested skills when applicable, constraints, non-goals, escalation conditions, and next focus.
|
|
1282
|
-
|
|
1283
|
-
When thoth-mem summary persistence and parent session/project identity are available, save or refresh that handoff body with root-owned \`mem_session(action="summary")\` or \`mem_save(kind="session_summary")\` before dispatch. If tooling or identity is unavailable, disclose that root-owned compaction could not be persisted and continue with explicit task instructions and local context; do not invent a fallback session or ask a sub-agent to create one.
|
|
1284
|
-
|
|
1285
|
-
The delegated prompt carries task instructions plus handoff recovery instructions only: parent \`session_id\`, project, persistence mode, memory permissions, the recall funnel \`mem_recall(mode="compact")\` -> \`mem_recall(mode="context")\` -> \`mem_get(...)\`, optional bounded \`mem_context(recall_query=...)\`/\`mem_project(...)\` guidance when permitted, non-goals, escalation conditions, and redaction requirements. It must not include the handoff body, raw transcripts, file dumps, secrets, credentials, irrelevant context, or generated sub-agent prompts as memory source material.
|
|
1286
|
-
|
|
1287
|
-
Never mention internal handoff preparation to the user, ask the user to prepare it, or present handoff preparation as the recommended next step. Describe the actual work instead.
|
|
1288
|
-
|
|
1289
|
-
For {{role.explorer}}/{{role.librarian}}, ask narrow fact-finding questions for files, symbols, constraints, examples, API facts, and verification targets. Require decision-ready findings, not raw context.
|
|
1290
|
-
</internal-handoff>
|
|
1291
|
-
|
|
1292
|
-
<dispatch>
|
|
1293
|
-
- If independent delegations are ready, launch them in the same response.
|
|
1294
|
-
- Default to normal synchronous \`{{delegationTool}}\` execution.
|
|
1295
|
-
- Experimental background \`{{backgroundDelegationTool}}\` is allowed only for {{role.explorer}} and {{role.librarian}} for asynchronous delegation.
|
|
1296
|
-
- {{role.oracle}}, {{role.designer}}, {{role.quick}}, and {{role.deep}} always use normal synchronous \`{{delegationTool}}\` execution.
|
|
1297
|
-
- When using background \`{{delegationTool}}\`, treat it as conditional and non-portable: if the host does not expose the experimental path, fall back to normal synchronous \`{{delegationTool}}\`.
|
|
1298
|
-
- Use \`{{backgroundStatusTool}}\` to {{lifecycleStatusAction}}: treat \`{{lifecycleNonterminalState}}\` as in progress and probe the same session via \`{{lifecycleSameSessionProbe}}\`; no retry/reroute/interruption before \`{{lifecycleTerminalState}}\`, an explicit user deadline, user cancellation, or a superseding request.
|
|
1299
|
-
- Terminal result-quality and required-artifact checks share one sharpened retry; nonterminal probes use none.
|
|
1300
|
-
- Capacity is separate: retry the named role up to 3 times; never switch to \`default\`, \`worker\`, or another role; then use a same-role model override or report a blocker.
|
|
1301
|
-
- Write-capable dispatches must include task instructions and handoff retrieval instructions when a root-owned handoff summary exists, so implementers can recover context without rediscovering settled scope.
|
|
1302
|
-
- Never tell sub-agents to discard working-tree changes.
|
|
1303
|
-
</dispatch>
|
|
1304
|
-
|
|
1305
|
-
<sdd>
|
|
1306
|
-
All work always starts with requirements-interview skill.
|
|
1307
|
-
Scope-faithful invariant: accepted user intent and scope must not be silently narrowed; unresolved affected areas stay visible as deferred/discovery follow-up, not hidden as out-of-scope.
|
|
1308
|
-
|
|
1309
|
-
Routes:
|
|
1310
|
-
- Direct implementation for low-complexity work.
|
|
1311
|
-
- Accelerated SDD: explore -> propose -> tasks.
|
|
1312
|
-
- Full SDD: explore -> propose -> spec -> clarify -> design -> tasks.
|
|
1313
|
-
|
|
1314
|
-
${renderSddDelegationMatrix()}
|
|
1315
|
-
|
|
1316
|
-
Hard gates:
|
|
1317
|
-
- Use the SDD delegation matrix as canonical phase routing.
|
|
1318
|
-
- Load the matching skill when a phase has one.
|
|
1319
|
-
- {{role.oracle}} is read-only for plan-reviewer and sdd-verify review; {{role.quick}} persists plan-review and verify artifacts when writes are required.
|
|
1320
|
-
- Never skip artifacts or jump from requirements-interview to implementation when SDD is selected.
|
|
1321
|
-
- Before SDD execution, load \`executing-plans\`; then track progress in {{progressTool}} plus the persistent artifact.
|
|
1322
|
-
- If openspec persistence is selected and openspec/ is missing or stale (partial structure or missing mechanism sections), dispatch sdd-init first.
|
|
1323
|
-
- During SDD execution, batch compatible implementation work.
|
|
1324
|
-
- Group consecutive ready SDD tasks for the same execution agent into one dispatch when dependencies, scope, and verification can be handled together. Keep per-task tracking and evidence; do not split a compatible {{role.designer}}/{{role.quick}}/{{role.deep}} run into one delegation per checkbox.
|
|
1325
|
-
|
|
1326
|
-
SDD dispatch envelope must include: skill name, persistence mode, pipeline type, change name, project name, needed prior artifact context, verification expectation, and return envelope.
|
|
1327
|
-
|
|
1328
|
-
Artifact governance handoff:
|
|
1329
|
-
- After \`sdd-tasks\`, you may surface report-only artifact governance findings before execution preparation starts.
|
|
1330
|
-
- Delegate governance inspection; do not treat findings as an execution gate or replacement for \`plan-reviewer\`/\`executing-plans\`.
|
|
1331
|
-
- Root thoth-mem ownership stays with you; sub-agents must not own session memory, prompts, or progress checkpoints.
|
|
1332
|
-
|
|
1333
|
-
Plan gate: after tasks, ask with \`{{userQuestionTool}}\`: "Review plan with {{role.oracle}} before executing (Recommended)" or "Proceed to execution".
|
|
1334
|
-
Plan review is complete only after fresh [OKAY] evidence in \`plan-review.md\` or \`sdd/{change-name}/plan-review\`; missing, stale, rejected, or unparsable evidence reruns oracle unless a user override is logged.
|
|
1335
|
-
Fresh [OKAY] satisfies only plan-review. If {{role.oracle}} returns [OKAY], or recovery accepts it, give an approved-plan overview, then ask with \`{{userQuestionTool}}\` whether to implement or stop. Cover scope, sequence, decisions, verification, risks, and uncertainty.
|
|
1336
|
-
Do not dispatch \`sdd-apply\` until user confirmation; never treat plan-review recovery as implementation confirmation.
|
|
1337
|
-
Post-execution verify-loop (mirrors the plan-review loop's discipline; bounded to 3 rounds = initial apply->verify plus up to 2 fix->re-verify):
|
|
1338
|
-
- Dispatch \`sdd-verify\` as an iterative gate, not a single shot; round 1 is the first verify after apply. Treat the \`round N\` marker in the verify report as the source of truth for the round counter and surface it in {{progressTool}}.
|
|
1339
|
-
- On clean \`pass\`: proceed through the existing pre-archive user gate above, then delegate \`sdd-archive\`. Do not auto-advance to archive merely because a verify report exists.
|
|
1340
|
-
- On \`fail\` with rounds remaining (round < 3): dispatch a TARGETED \`sdd-apply\` re-run scoped by the verify report's Critical Issue remediation anchors (file and/or scenario), then re-dispatch \`sdd-verify\` as round N+1. Do not expand a scoped fix into a full unscoped re-apply when anchors are present, and do not advance to archive while the verdict is \`fail\`.
|
|
1341
|
-
- On \`fail\` at the bound (round 3 still failing): escalate the unresolved failure to the user with \`{{userQuestionTool}}\`. Do not run another apply/verify round and do not silently abandon or auto-archive. If the harness lacks a blocking user-input primitive, report this as an unsupported-capability limitation instead of auto-advancing or looping.
|
|
1342
|
-
- On \`pass with warnings\`: escalate with \`{{userQuestionTool}}\` an advance-vs-iterate choice (advance to \`sdd-archive\` vs re-iterate to clear warnings). Never auto-advance and never auto-loop. If the user chooses re-iterate, dispatch a targeted \`sdd-apply\` scoped by the warning remediation anchors and re-verify, subject to the 3-round bound.
|
|
1343
|
-
</sdd>
|
|
1344
|
-
|
|
1345
|
-
<progress-memory>
|
|
1346
|
-
- Keep {{progressTool}} top-level and lean for multi-step work.
|
|
1347
|
-
- When SDD is active, update both {{progressTool}} and openspec/changes/{change-name}/tasks.md before dispatch and after results.
|
|
1348
|
-
- Root-session memory is yours: recall repeated work; save durable decisions, discoveries, bugs, patterns, constraints, summaries.
|
|
1349
|
-
- Use \`mem_save(kind="observation")\` for decisions, bugs, discoveries, conventions, preferences; stable topics; observations outside \`sdd/*\`.
|
|
1350
|
-
- Targeted recall funnel: \`mem_recall(mode="compact")\` -> \`mem_recall(mode="context")\` -> \`mem_get(...)\`; use \`mem_get(include_timeline=true)\` for time context.
|
|
1351
|
-
- Use HyDE/fused recall; set \`mem_recall\` \`limit\` from 1 to 20; narrow with \`topic_key\`, \`type\`, \`time_from\`/\`time_to\`, \`scope\`, \`project\`, \`session_id\`.
|
|
1352
|
-
- \`mem_get\`: \`kind="observation"|"prompt"\`, \`include_timeline=true\`, \`before\`/\`after\`, \`offset\`/\`max_length\`; supplement with bounded \`mem_context(recall_query=...)\` or \`mem_project(action="graph"|"topics"|"topic")\`.
|
|
1353
|
-
- Graph relations: HAS_TYPE, IN_PROJECT, HAS_TOPIC_KEY, HAS_WHAT, HAS_WHY, HAS_WHERE, HAS_LEARNED.
|
|
1354
|
-
- SDD memory artifacts use deterministic topic keys only in thoth-mem or hybrid persistence modes: \`sdd/{change}/{artifact}\`.
|
|
1355
|
-
- Before ending the root session, call \`mem_session(action="summary")\` or root-owned \`mem_save(kind="session_summary")\` with a concise Goal, Instructions, Discoveries, Accomplished, Next Steps, and Relevant Files summary. Do not claim memory was saved unless the tool call succeeded.
|
|
1356
|
-
- After compaction, first preserve the compacted summary with \`mem_session(action="summary")\`, then call \`mem_context(recall_query=...)\` and use the recall funnel before continuing work.
|
|
1357
|
-
</progress-memory>
|
|
1358
|
-
|
|
1359
|
-
<communication>
|
|
1360
|
-
State the plan briefly, delegate, then summarize outcomes without replaying raw work. Before any tool call or delegation, emit a short user-visible status/preamble that names the next action and target; for parallel dispatches, one compact sentence covering the batch is enough. Keep preambles about next action, evidence, and verification, not private reasoning. Separate evidence, inference, and uncertainty when it matters. Never ask blocking questions in prose.
|
|
1361
|
-
</communication>`),
|
|
1362
|
-
createQuestionProtocolSection()
|
|
1363
|
-
];
|
|
1364
|
-
}
|
|
1365
|
-
function createReadOnlySpecialistPromptSections(role) {
|
|
1366
|
-
if (role === "explorer") {
|
|
1367
|
-
return specialistSections({
|
|
1368
|
-
role,
|
|
1369
|
-
mode: "read-only",
|
|
1370
|
-
dispatch: "task",
|
|
1371
|
-
scope: "local repository discovery",
|
|
1372
|
-
responsibility: "Find workspace facts fast. Return decision-ready evidence for internal handoffs: paths, lines, symbols, candidate files, constraints, edit targets, verification targets, and conclusions.",
|
|
1373
|
-
rules: [
|
|
1374
|
-
"- Questions should be rare; exhaust local evidence first.",
|
|
1375
|
-
"- Prefer paths, lines, symbols, and concise summaries over dumps.",
|
|
1376
|
-
"- Do not implement, edit files, mutate the repository, or own durable session memory.",
|
|
1377
|
-
"- When full content is explicitly requested, reproduce it faithfully."
|
|
1378
|
-
],
|
|
1379
|
-
memoryAccess: "readonly",
|
|
1380
|
-
output: `
|
|
1381
|
-
Return exactly these sections, in this order:
|
|
1382
|
-
|
|
1383
|
-
STATUS: one of CONFIRMED | PARTIAL | INCONCLUSIVE
|
|
1384
|
-
- CONFIRMED = direct evidence answers the question with high confidence.
|
|
1385
|
-
- PARTIAL = some direct evidence, but gaps remain or multiple candidates exist.
|
|
1386
|
-
- INCONCLUSIVE = no sufficient evidence found. Never fabricate a confident answer from naming similarity alone.
|
|
1387
|
-
|
|
1388
|
-
FINDINGS: bullets with claim, evidence type [direct|inferred|assumed], confidence [high|medium|low], and file:line anchors for concrete claims.
|
|
1389
|
-
|
|
1390
|
-
ALTERNATIVES CONSIDERED: ranked candidates when more than one plausible match exists. Omit if only one candidate.
|
|
1391
|
-
|
|
1392
|
-
UNRESOLVED QUESTIONS: ambiguity and what context would unblock it.
|
|
1393
|
-
|
|
1394
|
-
UNCHECKED AREAS: what you did not inspect that could change the answer. Omit if nothing notable.
|
|
1395
|
-
|
|
1396
|
-
SHORT EVIDENCE: at most one 2-line excerpt per key finding.
|
|
1397
|
-
|
|
1398
|
-
Lead with STATUS. Stay under 40 lines total when possible. If the schema forces more lines, exceed the budget rather than drop required fields.`
|
|
1399
|
-
});
|
|
1400
|
-
}
|
|
1401
|
-
if (role === "librarian") {
|
|
1402
|
-
return specialistSections({
|
|
1403
|
-
role,
|
|
1404
|
-
mode: "read-only",
|
|
1405
|
-
dispatch: "task",
|
|
1406
|
-
scope: "external docs and research plus local confirmation when needed",
|
|
1407
|
-
responsibility: "Gather authoritative external evidence that helps the orchestrator make implementation decisions. Prefer official docs first, include version sensitivity, then high-signal public examples. Every substantive claim must carry a source URL.",
|
|
1408
|
-
rules: [
|
|
1409
|
-
"- Questions should be rare; exhaust available sources first.",
|
|
1410
|
-
"- Prefer official documentation over commentary when both answer the same point.",
|
|
1411
|
-
"- Distinguish clearly between official guidance and community examples.",
|
|
1412
|
-
"- Do not mutate the repository, invent undocumented APIs, or perform broad implementation work."
|
|
1413
|
-
],
|
|
1414
|
-
memoryAccess: "readonly",
|
|
1415
|
-
output: `- Organize by finding. Include a source URL for every claim.
|
|
1416
|
-
- Distinguish official docs from community examples.
|
|
1417
|
-
- Return synthesized findings, not full documentation excerpts.
|
|
1418
|
-
- Target: under 40 lines total.`
|
|
1419
|
-
});
|
|
1420
|
-
}
|
|
1421
|
-
return specialistSections({
|
|
1422
|
-
role,
|
|
1423
|
-
mode: "read-only",
|
|
1424
|
-
dispatch: "synchronous task only",
|
|
1425
|
-
scope: "advice, diagnosis, architecture, code review, and plan review",
|
|
1426
|
-
responsibility: "Provide read-only review and strategic technical guidance anchored to evidence, including findings, risks, assumptions, and decision-ready conclusions. Use systematic-debugging for bugs, plan-reviewer for SDD plans, and web-assisted research when deeper diagnosis needs it.",
|
|
1427
|
-
rules: [
|
|
1428
|
-
"- Cite exact files and lines for local claims.",
|
|
1429
|
-
"- Separate observations, risks, and recommendations.",
|
|
1430
|
-
"- Ask only when tradeoffs, risk tolerance, or approval materially change the recommendation.",
|
|
1431
|
-
"- Do not produce SDD artifacts, implement edits, or mutate the workspace."
|
|
1432
|
-
],
|
|
1433
|
-
memoryAccess: "readonly",
|
|
1434
|
-
output: `- Cite exact files and lines \u2014 do not quote large code blocks.
|
|
1435
|
-
- Separate observations, risks, and recommendations.
|
|
1436
|
-
- For diagnosis: root cause + fix recommendation, not step-by-step trace.
|
|
1437
|
-
- Target: under 50 lines total.`
|
|
1438
|
-
});
|
|
1439
|
-
}
|
|
1440
|
-
function createWriteCapableSpecialistPromptSections(role) {
|
|
1441
|
-
if (role === "designer") {
|
|
1442
|
-
return specialistSections({
|
|
1443
|
-
role,
|
|
1444
|
-
mode: "write-capable",
|
|
1445
|
-
dispatch: "synchronous task only",
|
|
1446
|
-
scope: "UI/UX decisions, implementation, and visual verification",
|
|
1447
|
-
responsibility: "Own the user-facing solution: choose the UX approach, implement it, and verify it visually through the visual verification surface across responsive states. Capture evidence once in non-blocking single-run mode.\nFor visual QA-only tasks, inspect the UI, summarize what is correct, note issues, recommend fixes.",
|
|
1448
|
-
rules: [
|
|
1449
|
-
"- Treat the orchestrator's internal handoff as the handoff; do not rediscover settled scope or constraints.",
|
|
1450
|
-
"- Own UX decisions unless a real user preference is required.",
|
|
1451
|
-
"- Verify visually and check responsive behavior when feasible; do not stop at code that merely compiles.",
|
|
1452
|
-
"- Delete temporary evidence you generated, such as screenshots, once it is no longer needed; if it is for root/orchestrator review, list it in your final output as garbage to delete after review.",
|
|
1453
|
-
"- Keep changes focused on the user-facing outcome.",
|
|
1454
|
-
"- Preserve unrelated working-tree changes.",
|
|
1455
|
-
"- Avoid interactive or persistent visual verification unless explicitly requested; keep it single-run, evidence-driven."
|
|
1456
|
-
],
|
|
1457
|
-
memoryAccess: "writable",
|
|
1458
|
-
output: `For SDD tasks: use the Task Result envelope (Status, Task, What was done, Files changed, Verification, Issues).
|
|
1459
|
-
For non-SDD work: state what was implemented, verification status, and remaining caveats.
|
|
1460
|
-
- Include visual verification status when applicable.
|
|
1461
|
-
- Target: under 30 lines total.`
|
|
1462
|
-
});
|
|
1463
|
-
}
|
|
1464
|
-
if (role === "quick") {
|
|
1465
|
-
return specialistSections({
|
|
1466
|
-
role,
|
|
1467
|
-
mode: "write-capable",
|
|
1468
|
-
dispatch: "synchronous task only",
|
|
1469
|
-
scope: "fast bounded implementation",
|
|
1470
|
-
responsibility: "Implement well-defined changes quickly. Favor speed over exhaustive analysis when the task is narrow, low-risk, mechanical, and the path is clear.",
|
|
1471
|
-
rules: [
|
|
1472
|
-
"- Optimize for fast execution on narrow, clear tasks.",
|
|
1473
|
-
"- Treat the orchestrator's internal handoff as the starting point; follow its file anchors, scope, non-goals, and verification target.",
|
|
1474
|
-
"- Preserve unrelated working-tree changes.",
|
|
1475
|
-
"- Read only the context you need.",
|
|
1476
|
-
"- Do not redo broad discovery. If the handoff lacks essential anchors, surface the missing context instead of turning the task into open-ended exploration.",
|
|
1477
|
-
"- Avoid multi-step planning; if the task stops being bounded, surface it.",
|
|
1478
|
-
"- Ask only for implementation-local ambiguity, not orchestrator-level routing.",
|
|
1479
|
-
"- NEVER run git commands that discard changes (`git restore`, `git checkout --`, `git reset`, `git clean`). Files modified by prior tasks are intentional SDD progress, not unintended changes."
|
|
1480
|
-
],
|
|
1481
|
-
memoryAccess: "writable",
|
|
1482
|
-
output: `For SDD tasks: use the Task Result envelope (Status, Task, What was done, Files changed, Verification, Issues).
|
|
1483
|
-
For non-SDD work: status + summary + files changed + issues. Nothing more.
|
|
1484
|
-
- Target: under 20 lines total.`
|
|
1485
|
-
});
|
|
1486
|
-
}
|
|
1487
|
-
return specialistSections({
|
|
1488
|
-
role,
|
|
1489
|
-
mode: "write-capable",
|
|
1490
|
-
dispatch: "synchronous task only",
|
|
1491
|
-
scope: "thorough implementation and verification",
|
|
1492
|
-
responsibility: "Handle correctness-critical, multi-file, or edge-case-heavy changes with full local context analysis. Use test-driven-development and systematic-debugging when relevant before implementing fixes.",
|
|
1493
|
-
rules: [
|
|
1494
|
-
"- Treat the orchestrator's internal handoff as the architecture handoff; validate it against nearby code, but do not restart upstream discovery unless evidence contradicts it.",
|
|
1495
|
-
"- Do not skip verification \u2014 thoroughness is your value proposition.",
|
|
1496
|
-
"- Investigate related files, types, and call sites before changing shared behavior, prioritizing the anchors and constraints in the handoff.",
|
|
1497
|
-
"- Preserve unrelated working-tree changes.",
|
|
1498
|
-
"- Ask when a real architecture or implementation tradeoff blocks correct execution."
|
|
1499
|
-
],
|
|
1500
|
-
memoryAccess: "writable",
|
|
1501
|
-
output: `For SDD tasks: use the Task Result envelope (Status, Task, What was done, Files changed, Verification, Issues).
|
|
1502
|
-
For non-SDD work: summary + files changed + verification results + edge cases considered.
|
|
1503
|
-
- Save detailed analysis for follow-up requests; return only actionable conclusions.
|
|
1504
|
-
- Target: under 40 lines total.`
|
|
1505
|
-
});
|
|
1506
|
-
}
|
|
1507
|
-
function getPrimaryModelId2(model) {
|
|
1508
|
-
if (Array.isArray(model)) {
|
|
1509
|
-
const first = model[0];
|
|
1510
|
-
return typeof first === "string" ? first : first?.id;
|
|
1511
|
-
}
|
|
1512
|
-
return model;
|
|
1513
|
-
}
|
|
1514
|
-
function renderQuestionProtocol(_section, dialect) {
|
|
1515
|
-
return `<questions>
|
|
1516
|
-
Use \`${dialect.tools.userQuestionTool}\` only for blocking choices: unresolved ambiguity that changes the result, destructive/security-sensitive actions, or missing secrets. Do all non-blocked work first, ask one targeted question with a recommended default first, then stop.
|
|
1517
|
-
</questions>`;
|
|
1518
|
-
}
|
|
1519
|
-
function renderSubagentRules(section, dialect) {
|
|
1520
|
-
const rules = [
|
|
1521
|
-
`- Single-task leaf agent: do not delegate, manage SDD phases, act as orchestrator, or call \`${dialect.tools.progressTool}\`.`,
|
|
1522
|
-
`- Use \`${dialect.tools.userQuestionTool}\` only for local blocking decisions.`,
|
|
1523
|
-
"- Never discard working-tree changes: no `git restore`, `git checkout -- <path>`, `git reset --hard`, `git clean`, or `git stash`.",
|
|
1524
|
-
"- Avoid blocking/watch commands; use terminating checks only."
|
|
1525
|
-
];
|
|
1526
|
-
if (section.memoryAccess === "readonly") {
|
|
1527
|
-
rules.push(
|
|
1528
|
-
"- Use read-only thoth-mem only when dispatch gives parent session_id/project and handoff recovery instructions.",
|
|
1529
|
-
"- Parent-scoped reads: `mem_recall`, `mem_context`, `mem_get`, bounded `mem_project`; do not call `mem_save` or own any `mem_session(...)` lifecycle action.",
|
|
1530
|
-
"- If either parent session_id or project is missing, do NOT call thoth-mem; rely on task instructions and local evidence.",
|
|
1531
|
-
'- Recover the parent-session handoff summary through the recall funnel `mem_recall(mode="compact")` -> `mem_recall(mode="context")` -> `mem_get(...)` before using memory.',
|
|
1532
|
-
'- Use `mem_recall` `limit` from 1 to 20; use `mem_get` with `kind="observation"|"prompt"`, `include_timeline=true`, `before`/`after`, and `offset`/`max_length`.',
|
|
1533
|
-
"- Report when recalled context is missing, stale, contradictory, or insufficient.",
|
|
1534
|
-
'- Supplemental `mem_context(recall_query=...)` and bounded `mem_project(action="graph"|"topics"|"topic")` do not replace the recall funnel and require explicit delegated permission. Graph relations: `HAS_TYPE`, `IN_PROJECT`, `HAS_TOPIC_KEY`, `HAS_WHAT`, `HAS_WHY`, `HAS_WHERE`, `HAS_LEARNED`.',
|
|
1535
|
-
"- Never save prompts, generated subagent prompts, session summaries, or durable memory."
|
|
1536
|
-
);
|
|
1537
|
-
}
|
|
1538
|
-
if (section.memoryAccess === "writable") {
|
|
1539
|
-
rules.push(
|
|
1540
|
-
"- Use delegated thoth-mem tools only: `mem_save`, `mem_recall`, `mem_context`, `mem_get`, `mem_project`, `mem_session`.",
|
|
1541
|
-
"- Always use the parent session_id/project from dispatch for every thoth-mem call.",
|
|
1542
|
-
"- If either is missing, do NOT call thoth-mem.",
|
|
1543
|
-
"- Follow handoff recovery instructions from the delegated task before using persisted memory.",
|
|
1544
|
-
'- For reads, use the recall funnel `mem_recall(mode="compact")` -> `mem_recall(mode="context")` -> `mem_get(...)` and recover the parent-session handoff summary before treating memory as source material.',
|
|
1545
|
-
'- Use `mem_recall` `limit` from 1 to 20; use `mem_get` with `kind="observation"|"prompt"`, `include_timeline=true`, `before`/`after`, and `offset`/`max_length`.',
|
|
1546
|
-
'- Keep the recall funnel canonical; use `mem_context(recall_query=...)` and bounded `mem_project(action="graph"|"topics"|"topic")` only with explicit project-read permission. Graph relations: `HAS_TYPE`, `IN_PROJECT`, `HAS_TOPIC_KEY`, `HAS_WHAT`, `HAS_WHY`, `HAS_WHERE`, `HAS_LEARNED`.',
|
|
1547
|
-
"- Report when recalled context is missing, stale, contradictory, or insufficient.",
|
|
1548
|
-
'- `mem_save(kind="observation")` is allowed only for delegated durable implementation observations or assigned deterministic SDD artifacts/apply-progress under the parent session/project.',
|
|
1549
|
-
'- Never own `mem_session(action="start"|"checkpoint"|"summary")`, save prompts, or save generated subagent prompts as user intent.',
|
|
1550
|
-
"- Protect the `sdd/*` namespace: deterministic SDD artifacts use `sdd/{change}/{artifact}`; general durable observations must stay outside `sdd/*`.",
|
|
1551
|
-
'- You do not own durable memory of your own; permitted `mem_save(kind="observation")` writes under the orchestrator\'s session/project only.'
|
|
1552
|
-
);
|
|
1553
|
-
}
|
|
1554
|
-
return rules.join("\n");
|
|
1555
|
-
}
|
|
1556
|
-
function renderReasoningDiscipline() {
|
|
1557
|
-
return `<reasoning-discipline>
|
|
1558
|
-
- Before solving/editing, post one short commentary update naming reasoning/root-cause check.
|
|
1559
|
-
- Do thought experiments: test competing explanations, edge cases, failure modes, root-cause fit.
|
|
1560
|
-
- Do not stop at first plausible explanation/superficial answer; validate with evidence, edge cases, tests, or fitting check.
|
|
1561
|
-
</reasoning-discipline>`;
|
|
1562
|
-
}
|
|
1563
|
-
function renderResponseBudget() {
|
|
1564
|
-
return "Return concise structured results: status, summary, files, verification/issues. Never return raw file dumps.";
|
|
1565
|
-
}
|
|
1566
|
-
function renderStepBudget(section) {
|
|
1567
|
-
return `<step-budget>
|
|
1568
|
-
- You have a hard execution budget of ${section.steps} steps.
|
|
1569
|
-
- Plan your tool use before acting, prioritize the highest-signal checks first, and stop once you have enough evidence to answer.
|
|
1570
|
-
- Avoid repeated searches or reads. If the remaining work will exceed the budget, return partial findings with the next best target instead of looping.
|
|
1571
|
-
</step-budget>`;
|
|
1572
|
-
}
|
|
1573
|
-
function getRoleModelProfile(role) {
|
|
1574
|
-
switch (role) {
|
|
1575
|
-
case "orchestrator":
|
|
1576
|
-
return "- Exploit your role by selecting the right specialist category, launching independent tasks together, and synthesizing facts/inferences/unknowns before the next dispatch.";
|
|
1577
|
-
case "explorer":
|
|
1578
|
-
return "- Exploit your role by scanning broadly first, then narrowing to symbol/path evidence with ranked candidates and confidence.";
|
|
1579
|
-
case "librarian":
|
|
1580
|
-
return "- Exploit your role by prioritizing official docs, dates, versions, and source quality before summarizing public examples.";
|
|
1581
|
-
case "oracle":
|
|
1582
|
-
return "- Exploit your role by challenging assumptions, identifying risk, and giving a decision-ready recommendation backed by evidence.";
|
|
1583
|
-
case "designer":
|
|
1584
|
-
return "- Exploit your role by making concrete UX choices, implementing them, and verifying the visible result instead of stopping at code review.";
|
|
1585
|
-
case "quick":
|
|
1586
|
-
return "- Exploit your role by applying the smallest clear edit, avoiding broad exploration, and returning immediately after focused verification.";
|
|
1587
|
-
case "deep":
|
|
1588
|
-
return "- Exploit your role by building a complete mental model of shared behavior, writing tests first when behavior changes, and verifying edge cases.";
|
|
1589
|
-
}
|
|
1590
|
-
}
|
|
1591
|
-
function renderModelFamily(section) {
|
|
1592
|
-
const roleGuidance = getRoleModelProfile(section.role);
|
|
1593
|
-
if (section.family === "claude") {
|
|
1594
|
-
return `<model-profile family="claude">
|
|
1595
|
-
- Use XML-like sections, label uncertainty, and delegate aggressively when agentic.
|
|
1596
|
-
${roleGuidance}
|
|
1597
|
-
</model-profile>`;
|
|
1598
|
-
}
|
|
1599
|
-
if (section.family === "openai") {
|
|
1600
|
-
return `<model-profile family="openai">
|
|
1601
|
-
- Plan briefly, then act. Keep tool dispatch explicit: action, target, return shape.
|
|
1602
|
-
${roleGuidance}
|
|
1603
|
-
</model-profile>`;
|
|
1604
|
-
}
|
|
1605
|
-
if (section.family === "gemini") {
|
|
1606
|
-
return `<model-profile family="gemini">
|
|
1607
|
-
- Use long-context breadth deliberately, then ground conclusions in exact anchors.
|
|
1608
|
-
${roleGuidance}
|
|
1609
|
-
</model-profile>`;
|
|
1610
|
-
}
|
|
1611
|
-
if (section.family === "kimi") {
|
|
1612
|
-
return `<model-profile family="kimi">
|
|
1613
|
-
- Favor repository-scale navigation before edits; keep patches grounded in current file state.
|
|
1614
|
-
${roleGuidance}
|
|
1615
|
-
</model-profile>`;
|
|
1616
|
-
}
|
|
1617
|
-
return `<model-profile family="glm">
|
|
1618
|
-
- Use compact checklists, conservative steps, clear verification, and concrete blockers.
|
|
1619
|
-
${roleGuidance}
|
|
1620
|
-
</model-profile>`;
|
|
1621
|
-
}
|
|
1622
|
-
function renderRoleText(section, dialect) {
|
|
1623
|
-
return section.template.replaceAll("{{delegationTool}}", dialect.tools.delegationTool).replaceAll(
|
|
1624
|
-
"{{backgroundDelegationTool}}",
|
|
1625
|
-
dialect.tools.backgroundDelegationTool ?? dialect.tools.delegationTool
|
|
1626
|
-
).replaceAll(
|
|
1627
|
-
"{{backgroundStatusTool}}",
|
|
1628
|
-
dialect.tools.backgroundStatusTool ?? dialect.tools.hostStatusSurface ?? ""
|
|
1629
|
-
).replaceAll("{{userQuestionTool}}", dialect.tools.userQuestionTool).replaceAll("{{progressTool}}", dialect.tools.progressTool).replaceAll(
|
|
1630
|
-
"{{lifecycleStatusAction}}",
|
|
1631
|
-
dialect.tools.lifecycle.statusAction
|
|
1632
|
-
).replaceAll(
|
|
1633
|
-
"{{lifecycleTerminalState}}",
|
|
1634
|
-
dialect.tools.lifecycle.terminalState
|
|
1635
|
-
).replaceAll(
|
|
1636
|
-
"{{lifecycleNonterminalState}}",
|
|
1637
|
-
dialect.tools.lifecycle.nonterminalState
|
|
1638
|
-
).replaceAll(
|
|
1639
|
-
"{{lifecycleSameSessionProbe}}",
|
|
1640
|
-
dialect.tools.lifecycle.sameSessionProbe
|
|
1641
|
-
).replaceAll("{{dispatch.task}}", dialect.dispatchLabel("task")).replaceAll(
|
|
1642
|
-
"{{dispatch.synchronous-task-only}}",
|
|
1643
|
-
dialect.dispatchLabel("synchronous-task-only")
|
|
1644
|
-
).replace(
|
|
1645
|
-
/\{\{role\.(\w+)\}\}/g,
|
|
1646
|
-
(_match, role) => dialect.renderRoleInvocation(role)
|
|
1647
|
-
);
|
|
1648
|
-
}
|
|
1649
|
-
function renderPromptSection(section, dialect) {
|
|
1650
|
-
switch (section.kind) {
|
|
1651
|
-
case "question-protocol":
|
|
1652
|
-
return renderQuestionProtocol(section, dialect);
|
|
1653
|
-
case "subagent-rules":
|
|
1654
|
-
return renderSubagentRules(section, dialect);
|
|
1655
|
-
case "reasoning-discipline":
|
|
1656
|
-
return renderReasoningDiscipline();
|
|
1657
|
-
case "response-budget":
|
|
1658
|
-
return renderResponseBudget();
|
|
1659
|
-
case "step-budget":
|
|
1660
|
-
return renderStepBudget(section);
|
|
1661
|
-
case "model-family":
|
|
1662
|
-
return renderModelFamily(section);
|
|
1663
|
-
case "role-text":
|
|
1664
|
-
return renderRoleText(section, dialect);
|
|
1665
|
-
}
|
|
1666
|
-
}
|
|
1667
|
-
function renderRolePrompt(sections, dialect) {
|
|
1668
|
-
return sections.map((section) => renderPromptSection(section, dialect).trim()).filter(Boolean).join("\n\n");
|
|
1669
|
-
}
|
|
1670
|
-
|
|
1671
|
-
// src/agents/prompt-utils.ts
|
|
1672
|
-
var QUESTION_PROTOCOL = renderPromptSection(
|
|
1673
|
-
createQuestionProtocolSection(),
|
|
1674
|
-
OPENCODE_PROMPT_DIALECT
|
|
1675
|
-
);
|
|
1676
|
-
var SUBAGENT_RULES = renderPromptSection(
|
|
1677
|
-
createSubagentRulesSection("base"),
|
|
1678
|
-
OPENCODE_PROMPT_DIALECT
|
|
1679
|
-
);
|
|
1680
|
-
var SUBAGENT_RULES_READONLY = renderPromptSection(
|
|
1681
|
-
createSubagentRulesSection("readonly"),
|
|
1682
|
-
OPENCODE_PROMPT_DIALECT
|
|
1683
|
-
);
|
|
1684
|
-
var SUBAGENT_RULES_WRITABLE = renderPromptSection(
|
|
1685
|
-
createSubagentRulesSection("writable"),
|
|
1686
|
-
OPENCODE_PROMPT_DIALECT
|
|
1687
|
-
);
|
|
1688
|
-
var RESPONSE_BUDGET = renderPromptSection(
|
|
1689
|
-
createResponseBudgetSection(),
|
|
1690
|
-
OPENCODE_PROMPT_DIALECT
|
|
1691
|
-
);
|
|
1692
|
-
function trimPromptSection(section) {
|
|
1693
|
-
const trimmed = section?.trim();
|
|
1694
|
-
return trimmed ? trimmed : void 0;
|
|
1695
|
-
}
|
|
1696
|
-
function appendPromptSections(...sections) {
|
|
1697
|
-
return sections.map(trimPromptSection).filter(Boolean).join("\n\n");
|
|
1698
|
-
}
|
|
1699
|
-
function detectModelFamily(model) {
|
|
1700
|
-
return detectModelFamilyFromModel(model);
|
|
1701
|
-
}
|
|
1702
|
-
function getStepBudgetPromptSection(steps) {
|
|
1703
|
-
const section = createStepBudgetSection(steps);
|
|
1704
|
-
if (!section) {
|
|
1705
|
-
return void 0;
|
|
1706
|
-
}
|
|
1707
|
-
return renderPromptSection(section, OPENCODE_PROMPT_DIALECT);
|
|
1708
|
-
}
|
|
1709
|
-
function getModelFamilyPromptSection(role, model) {
|
|
1710
|
-
const section = createModelFamilySection(role, model);
|
|
1711
|
-
if (!section) {
|
|
1712
|
-
return void 0;
|
|
1713
|
-
}
|
|
1714
|
-
return renderPromptSection(section, OPENCODE_PROMPT_DIALECT);
|
|
1715
|
-
}
|
|
1716
|
-
function replacePromptPlaceholders(template, placeholders = {}) {
|
|
1717
|
-
return Object.entries(placeholders).reduce((prompt, [key, value]) => {
|
|
1718
|
-
if (value === void 0) {
|
|
1719
|
-
return prompt;
|
|
1720
|
-
}
|
|
1721
|
-
return prompt.replaceAll(`{{${key}}}`, String(value));
|
|
1722
|
-
}, template);
|
|
1723
|
-
}
|
|
1724
|
-
function composeAgentPrompt({
|
|
1725
|
-
basePrompt,
|
|
1726
|
-
customPrompt,
|
|
1727
|
-
customAppendPrompt,
|
|
1728
|
-
placeholders
|
|
1729
|
-
}) {
|
|
1730
|
-
const resolvedBase = replacePromptPlaceholders(basePrompt, placeholders);
|
|
1731
|
-
if (customPrompt) {
|
|
1732
|
-
return replacePromptPlaceholders(customPrompt, placeholders);
|
|
1733
|
-
}
|
|
1734
|
-
return appendPromptSections(
|
|
1735
|
-
resolvedBase,
|
|
1736
|
-
replacePromptPlaceholders(customAppendPrompt ?? "", placeholders)
|
|
1737
|
-
);
|
|
1738
|
-
}
|
|
1739
|
-
|
|
1740
|
-
// src/cli/custom-skills.ts
|
|
1741
|
-
import {
|
|
1742
|
-
copyFileSync as copyFileSync2,
|
|
1743
|
-
existsSync as existsSync5,
|
|
1744
|
-
mkdirSync as mkdirSync3,
|
|
1745
|
-
readdirSync as readdirSync2,
|
|
1746
|
-
rmSync,
|
|
1747
|
-
statSync as statSync3
|
|
1748
|
-
} from "fs";
|
|
1749
|
-
import { dirname as dirname2, join as join4, parse } from "path";
|
|
1750
|
-
import { fileURLToPath } from "url";
|
|
1751
|
-
|
|
1752
|
-
// src/harness/core/skills.ts
|
|
1753
|
-
var ORCHESTRATOR_ONLY = ["orchestrator"];
|
|
1754
|
-
var SHARED_SKILL_SUPPORT = {
|
|
1755
|
-
name: "_shared",
|
|
1756
|
-
description: "Shared OpenSpec, persistence, and thoth-mem SDD conventions",
|
|
1757
|
-
allowedRoles: [
|
|
1758
|
-
"orchestrator",
|
|
1759
|
-
"explorer",
|
|
1760
|
-
"librarian",
|
|
1761
|
-
"oracle",
|
|
1762
|
-
"designer",
|
|
1763
|
-
"quick",
|
|
1764
|
-
"deep"
|
|
1765
|
-
],
|
|
1766
|
-
sourcePath: "src/skills/_shared",
|
|
1767
|
-
kind: "shared-support",
|
|
1768
|
-
purpose: "support"
|
|
1769
|
-
};
|
|
1770
|
-
var BUNDLED_SKILL_REGISTRY = [
|
|
1771
|
-
{
|
|
1772
|
-
name: "requirements-interview",
|
|
1773
|
-
description: "Mandatory step-0 discovery interview to understand user intent, clarify scope, and choose the right path before implementation",
|
|
1774
|
-
allowedRoles: ORCHESTRATOR_ONLY,
|
|
1775
|
-
sourcePath: "src/skills/requirements-interview",
|
|
1776
|
-
kind: "skill",
|
|
1777
|
-
purpose: "requirements"
|
|
1778
|
-
},
|
|
1779
|
-
{
|
|
1780
|
-
name: "thoth-mem-agents",
|
|
1781
|
-
description: "Orchestrator/subagent thoth-mem workflow contract for parent session_id/project ownership, prompt-save prohibitions, and safe durable memory usage",
|
|
1782
|
-
allowedRoles: [
|
|
1783
|
-
"orchestrator",
|
|
1784
|
-
"explorer",
|
|
1785
|
-
"librarian",
|
|
1786
|
-
"oracle",
|
|
1787
|
-
"designer",
|
|
1788
|
-
"quick",
|
|
1789
|
-
"deep"
|
|
1790
|
-
],
|
|
1791
|
-
sourcePath: "src/skills/thoth-mem-agents",
|
|
1792
|
-
kind: "skill",
|
|
1793
|
-
purpose: "memory"
|
|
1794
|
-
},
|
|
1795
|
-
{
|
|
1796
|
-
name: "plan-reviewer",
|
|
1797
|
-
description: "Review SDD task plans for execution blockers and valid references",
|
|
1798
|
-
allowedRoles: ["orchestrator", "oracle"],
|
|
1799
|
-
sourcePath: "src/skills/plan-reviewer",
|
|
1800
|
-
kind: "skill",
|
|
1801
|
-
purpose: "review"
|
|
1802
|
-
},
|
|
1803
|
-
{
|
|
1804
|
-
name: "sdd-init",
|
|
1805
|
-
description: "Initialize OpenSpec structure and SDD project context",
|
|
1806
|
-
allowedRoles: ORCHESTRATOR_ONLY,
|
|
1807
|
-
sourcePath: "src/skills/sdd-init",
|
|
1808
|
-
kind: "skill",
|
|
1809
|
-
purpose: "sdd"
|
|
1810
|
-
},
|
|
1811
|
-
{
|
|
1812
|
-
name: "sdd-propose",
|
|
1813
|
-
description: "Create change proposals for OpenSpec workflows",
|
|
1814
|
-
allowedRoles: ORCHESTRATOR_ONLY,
|
|
1815
|
-
sourcePath: "src/skills/sdd-propose",
|
|
1816
|
-
kind: "skill",
|
|
1817
|
-
purpose: "sdd"
|
|
1818
|
-
},
|
|
1819
|
-
{
|
|
1820
|
-
name: "sdd-spec",
|
|
1821
|
-
description: "Write OpenSpec delta specifications",
|
|
1822
|
-
allowedRoles: ORCHESTRATOR_ONLY,
|
|
1823
|
-
sourcePath: "src/skills/sdd-spec",
|
|
1824
|
-
kind: "skill",
|
|
1825
|
-
purpose: "sdd"
|
|
1826
|
-
},
|
|
1827
|
-
{
|
|
1828
|
-
name: "sdd-clarify",
|
|
1829
|
-
description: "Resolve residual spec ambiguity in place before design, with a bounded taxonomy-driven clarification pass.",
|
|
1830
|
-
allowedRoles: ORCHESTRATOR_ONLY,
|
|
1831
|
-
sourcePath: "src/skills/sdd-clarify",
|
|
1832
|
-
kind: "skill",
|
|
1833
|
-
purpose: "sdd"
|
|
1834
|
-
},
|
|
1835
|
-
{
|
|
1836
|
-
name: "sdd-design",
|
|
1837
|
-
description: "Create technical solution design artifacts for changes",
|
|
1838
|
-
allowedRoles: ORCHESTRATOR_ONLY,
|
|
1839
|
-
sourcePath: "src/skills/sdd-design",
|
|
1840
|
-
kind: "skill",
|
|
1841
|
-
purpose: "sdd"
|
|
1842
|
-
},
|
|
1843
|
-
{
|
|
1844
|
-
name: "sdd-tasks",
|
|
1845
|
-
description: "Generate phased implementation task checklists",
|
|
1846
|
-
allowedRoles: ORCHESTRATOR_ONLY,
|
|
1847
|
-
sourcePath: "src/skills/sdd-tasks",
|
|
1848
|
-
kind: "skill",
|
|
1849
|
-
purpose: "sdd"
|
|
1850
|
-
},
|
|
1851
|
-
{
|
|
1852
|
-
name: "sdd-apply",
|
|
1853
|
-
description: "Execute tasks and persist implementation progress",
|
|
1854
|
-
allowedRoles: ORCHESTRATOR_ONLY,
|
|
1855
|
-
sourcePath: "src/skills/sdd-apply",
|
|
1856
|
-
kind: "skill",
|
|
1857
|
-
purpose: "sdd"
|
|
1858
|
-
},
|
|
1859
|
-
{
|
|
1860
|
-
name: "executing-plans",
|
|
1861
|
-
description: "Execute SDD task lists with real-time progress tracking, sub-agent dispatch, and verification checkpoints",
|
|
1862
|
-
allowedRoles: ORCHESTRATOR_ONLY,
|
|
1863
|
-
sourcePath: "src/skills/executing-plans",
|
|
1864
|
-
kind: "skill",
|
|
1865
|
-
purpose: "sdd"
|
|
1866
|
-
},
|
|
1867
|
-
{
|
|
1868
|
-
name: "sdd-verify",
|
|
1869
|
-
description: "Build verification reports and compliance matrices",
|
|
1870
|
-
allowedRoles: ORCHESTRATOR_ONLY,
|
|
1871
|
-
sourcePath: "src/skills/sdd-verify",
|
|
1872
|
-
kind: "skill",
|
|
1873
|
-
purpose: "sdd"
|
|
1874
|
-
},
|
|
1875
|
-
{
|
|
1876
|
-
name: "sdd-archive",
|
|
1877
|
-
description: "Archive completed OpenSpec changes with audit trails",
|
|
1878
|
-
allowedRoles: ORCHESTRATOR_ONLY,
|
|
1879
|
-
sourcePath: "src/skills/sdd-archive",
|
|
1880
|
-
kind: "skill",
|
|
1881
|
-
purpose: "sdd"
|
|
1882
|
-
},
|
|
1883
|
-
{
|
|
1884
|
-
name: "sdd-constitution",
|
|
1885
|
-
description: "Guide a semver constitution amendment and Sync-Impact Report entry.",
|
|
1886
|
-
allowedRoles: ORCHESTRATOR_ONLY,
|
|
1887
|
-
sourcePath: "src/skills/sdd-constitution",
|
|
1888
|
-
kind: "skill",
|
|
1889
|
-
purpose: "sdd"
|
|
1890
|
-
}
|
|
1891
|
-
];
|
|
1892
|
-
var SKILL_REGISTRY = [
|
|
1893
|
-
...BUNDLED_SKILL_REGISTRY,
|
|
1894
|
-
SHARED_SKILL_SUPPORT
|
|
1895
|
-
];
|
|
1896
|
-
function getSkillRegistry() {
|
|
1897
|
-
return SKILL_REGISTRY.map((entry) => ({
|
|
1898
|
-
...entry,
|
|
1899
|
-
allowedRoles: [...entry.allowedRoles]
|
|
1900
|
-
}));
|
|
1901
|
-
}
|
|
1902
|
-
|
|
1903
|
-
// src/cli/skill-manifest.ts
|
|
1904
|
-
import { createHash } from "crypto";
|
|
1905
|
-
import {
|
|
1906
|
-
existsSync as existsSync4,
|
|
1907
|
-
mkdirSync as mkdirSync2,
|
|
1908
|
-
readdirSync,
|
|
1909
|
-
readFileSync as readFileSync3,
|
|
1910
|
-
statSync as statSync2,
|
|
1911
|
-
writeFileSync as writeFileSync2
|
|
1912
|
-
} from "fs";
|
|
1913
|
-
import { join as join3, relative } from "path";
|
|
1914
|
-
var SHARED_SKILL_DIRECTORY = "_shared";
|
|
1915
|
-
var SKILLS_SOURCE_ROOT = join3("src", "skills");
|
|
1916
|
-
var MANIFEST_FILE_NAME = ".skill-manifest.json";
|
|
1917
|
-
function getManifestPath() {
|
|
1918
|
-
return join3(getCustomSkillsDir(), MANIFEST_FILE_NAME);
|
|
1919
|
-
}
|
|
1920
|
-
function listFilesRecursive(dirPath) {
|
|
1921
|
-
if (!existsSync4(dirPath)) {
|
|
1922
|
-
return [];
|
|
1923
|
-
}
|
|
1924
|
-
const files = [];
|
|
1925
|
-
const entries = readdirSync(dirPath).sort(
|
|
1926
|
-
(left, right) => left.localeCompare(right)
|
|
1927
|
-
);
|
|
1928
|
-
for (const entry of entries) {
|
|
1929
|
-
const entryPath = join3(dirPath, entry);
|
|
1930
|
-
const stat = statSync2(entryPath);
|
|
1931
|
-
if (stat.isDirectory()) {
|
|
1932
|
-
files.push(...listFilesRecursive(entryPath));
|
|
1933
|
-
continue;
|
|
1934
|
-
}
|
|
1935
|
-
files.push(entryPath);
|
|
1936
|
-
}
|
|
1937
|
-
return files;
|
|
1938
|
-
}
|
|
1939
|
-
function readPackageVersion(packageRoot) {
|
|
1940
|
-
const packageJsonPath = join3(packageRoot, "package.json");
|
|
1941
|
-
const packageJson = JSON.parse(readFileSync3(packageJsonPath, "utf-8"));
|
|
1942
|
-
if (typeof packageJson.version !== "string" || packageJson.version.length === 0) {
|
|
1943
|
-
throw new Error(`Invalid package version in ${packageJsonPath}`);
|
|
1944
|
-
}
|
|
1945
|
-
return packageJson.version;
|
|
1946
|
-
}
|
|
1947
|
-
function readManifest() {
|
|
1948
|
-
const manifestPath = getManifestPath();
|
|
1949
|
-
if (!existsSync4(manifestPath)) {
|
|
1950
|
-
return null;
|
|
1951
|
-
}
|
|
1952
|
-
try {
|
|
1953
|
-
return JSON.parse(readFileSync3(manifestPath, "utf-8"));
|
|
1954
|
-
} catch (error) {
|
|
1955
|
-
console.warn(`Failed to read skill manifest: ${manifestPath}`, error);
|
|
1956
|
-
return null;
|
|
1957
|
-
}
|
|
1958
|
-
}
|
|
1959
|
-
function writeManifest(manifest) {
|
|
1960
|
-
const manifestPath = getManifestPath();
|
|
1961
|
-
mkdirSync2(getCustomSkillsDir(), { recursive: true });
|
|
1962
|
-
writeFileSync2(manifestPath, `${JSON.stringify(manifest, null, 2)}
|
|
1963
|
-
`);
|
|
1964
|
-
}
|
|
1965
|
-
function computeSkillHash(skillDirPath) {
|
|
1966
|
-
const hash = createHash("sha256");
|
|
1967
|
-
for (const filePath of listFilesRecursive(skillDirPath)) {
|
|
1968
|
-
hash.update(`${relative(skillDirPath, filePath)}
|
|
1969
|
-
`);
|
|
1970
|
-
hash.update(readFileSync3(filePath));
|
|
1971
|
-
hash.update("\n");
|
|
1972
|
-
}
|
|
1973
|
-
return hash.digest("hex");
|
|
1974
|
-
}
|
|
1975
|
-
function findRemovedSkills(manifest) {
|
|
1976
|
-
const currentSkillNames = new Set(CUSTOM_SKILLS.map((skill) => skill.name));
|
|
1977
|
-
return Object.keys(manifest.skills).filter(
|
|
1978
|
-
(skillName) => !currentSkillNames.has(skillName)
|
|
1979
|
-
);
|
|
1980
|
-
}
|
|
1981
|
-
function checkSkillsNeedUpdate(packageRoot) {
|
|
1982
|
-
const manifest = readManifest();
|
|
1983
|
-
const pluginVersion = readPackageVersion(packageRoot);
|
|
1984
|
-
const sharedHash = computeSkillHash(
|
|
1985
|
-
join3(packageRoot, SKILLS_SOURCE_ROOT, SHARED_SKILL_DIRECTORY)
|
|
1986
|
-
);
|
|
1987
|
-
const versionChanged = manifest !== null && manifest.pluginVersion !== pluginVersion;
|
|
1988
|
-
const sharedChanged = manifest !== null && manifest.sharedHash !== sharedHash;
|
|
1989
|
-
const removedSkills = manifest ? findRemovedSkills(manifest) : [];
|
|
1990
|
-
const skillsNeedingUpdate = CUSTOM_SKILLS.flatMap((skill) => {
|
|
1991
|
-
const sourcePath = join3(packageRoot, skill.sourcePath);
|
|
1992
|
-
const targetPath = join3(getCustomSkillsDir(), skill.name);
|
|
1993
|
-
const sourceHash = computeSkillHash(sourcePath);
|
|
1994
|
-
const manifestEntry = manifest?.skills[skill.name];
|
|
1995
|
-
const reasons = [];
|
|
1996
|
-
if (!manifest) {
|
|
1997
|
-
reasons.push("manifest-missing");
|
|
1998
|
-
}
|
|
1999
|
-
if (versionChanged) {
|
|
2000
|
-
reasons.push("version-change");
|
|
2001
|
-
}
|
|
2002
|
-
if (sharedChanged) {
|
|
2003
|
-
reasons.push("shared-hash-mismatch");
|
|
2004
|
-
}
|
|
2005
|
-
if (!manifestEntry) {
|
|
2006
|
-
reasons.push("new-skill");
|
|
2007
|
-
} else if (manifestEntry.hash !== sourceHash) {
|
|
2008
|
-
reasons.push("hash-mismatch");
|
|
2009
|
-
}
|
|
2010
|
-
if (!existsSync4(targetPath)) {
|
|
2011
|
-
reasons.push("missing-install");
|
|
2012
|
-
}
|
|
2013
|
-
if (reasons.length === 0) {
|
|
2014
|
-
return [];
|
|
2015
|
-
}
|
|
2016
|
-
return [
|
|
2017
|
-
{
|
|
2018
|
-
skill,
|
|
2019
|
-
sourceHash,
|
|
2020
|
-
targetPath,
|
|
2021
|
-
reasons
|
|
2022
|
-
}
|
|
2023
|
-
];
|
|
2024
|
-
});
|
|
2025
|
-
return {
|
|
2026
|
-
pluginVersion,
|
|
2027
|
-
sharedHash,
|
|
2028
|
-
manifest,
|
|
2029
|
-
versionChanged,
|
|
2030
|
-
sharedChanged,
|
|
2031
|
-
needsUpdate: skillsNeedingUpdate.length > 0 || removedSkills.length > 0,
|
|
2032
|
-
skillsNeedingUpdate,
|
|
2033
|
-
removedSkills
|
|
2034
|
-
};
|
|
2035
|
-
}
|
|
2036
|
-
|
|
2037
|
-
// src/cli/custom-skills.ts
|
|
2038
|
-
var SHARED_SKILL_DIRECTORY2 = "_shared";
|
|
2039
|
-
var SHARED_SKILL_SOURCE_PATH = `src/skills/${SHARED_SKILL_DIRECTORY2}`;
|
|
2040
|
-
var CUSTOM_SKILLS = BUNDLED_SKILL_REGISTRY.map(
|
|
2041
|
-
(skill) => ({
|
|
2042
|
-
name: skill.name,
|
|
2043
|
-
description: skill.description,
|
|
2044
|
-
allowedAgents: [...skill.allowedRoles],
|
|
2045
|
-
sourcePath: skill.sourcePath
|
|
2046
|
-
})
|
|
2047
|
-
);
|
|
2048
|
-
function getCustomSkillsDir() {
|
|
2049
|
-
return join4(getConfigDir(), "skills");
|
|
2050
|
-
}
|
|
2051
|
-
function copyDirRecursive(src, dest) {
|
|
2052
|
-
if (!existsSync5(dest)) {
|
|
2053
|
-
mkdirSync3(dest, { recursive: true });
|
|
2054
|
-
}
|
|
2055
|
-
const entries = readdirSync2(src);
|
|
2056
|
-
for (const entry of entries) {
|
|
2057
|
-
const srcPath = join4(src, entry);
|
|
2058
|
-
const destPath = join4(dest, entry);
|
|
2059
|
-
const stat = statSync3(srcPath);
|
|
2060
|
-
if (stat.isDirectory()) {
|
|
2061
|
-
copyDirRecursive(srcPath, destPath);
|
|
2062
|
-
} else {
|
|
2063
|
-
const destDir = dirname2(destPath);
|
|
2064
|
-
if (!existsSync5(destDir)) {
|
|
2065
|
-
mkdirSync3(destDir, { recursive: true });
|
|
2066
|
-
}
|
|
2067
|
-
copyFileSync2(srcPath, destPath);
|
|
2068
|
-
}
|
|
2069
|
-
}
|
|
2070
|
-
}
|
|
2071
|
-
function installSharedSkillAssets(packageRoot) {
|
|
2072
|
-
const sharedSourcePath = join4(packageRoot, SHARED_SKILL_SOURCE_PATH);
|
|
2073
|
-
const sharedTargetPath = join4(getCustomSkillsDir(), SHARED_SKILL_DIRECTORY2);
|
|
2074
|
-
if (!existsSync5(sharedSourcePath)) {
|
|
2075
|
-
console.error(`Custom skill shared assets not found: ${sharedSourcePath}`);
|
|
2076
|
-
return false;
|
|
2077
|
-
}
|
|
2078
|
-
rmSync(sharedTargetPath, { recursive: true, force: true });
|
|
2079
|
-
copyDirRecursive(sharedSourcePath, sharedTargetPath);
|
|
2080
|
-
return true;
|
|
2081
|
-
}
|
|
2082
|
-
function findPackageRoot(startDir) {
|
|
2083
|
-
let currentDir = startDir;
|
|
2084
|
-
const filesystemRoot = parse(startDir).root;
|
|
2085
|
-
while (true) {
|
|
2086
|
-
if (existsSync5(join4(currentDir, "package.json")) && existsSync5(join4(currentDir, "src", "skills"))) {
|
|
2087
|
-
return currentDir;
|
|
2088
|
-
}
|
|
2089
|
-
if (currentDir === filesystemRoot) {
|
|
2090
|
-
return null;
|
|
2091
|
-
}
|
|
2092
|
-
const parentDir = dirname2(currentDir);
|
|
2093
|
-
if (parentDir === currentDir) {
|
|
2094
|
-
return null;
|
|
2095
|
-
}
|
|
2096
|
-
currentDir = parentDir;
|
|
2097
|
-
}
|
|
2098
|
-
}
|
|
2099
|
-
function resolvePackageRoot(packageRoot) {
|
|
2100
|
-
if (packageRoot) {
|
|
2101
|
-
return packageRoot;
|
|
2102
|
-
}
|
|
2103
|
-
const moduleDir = fileURLToPath(new URL(".", import.meta.url));
|
|
2104
|
-
return findPackageRoot(moduleDir) ?? fileURLToPath(new URL("../..", import.meta.url));
|
|
2105
|
-
}
|
|
2106
|
-
function checkCustomSkillsNeedUpdate(packageRoot) {
|
|
2107
|
-
return checkSkillsNeedUpdate(resolvePackageRoot(packageRoot));
|
|
2108
|
-
}
|
|
2109
|
-
function installCustomSkillFiles(skill, packageRoot) {
|
|
2110
|
-
const sourcePath = join4(packageRoot, skill.sourcePath);
|
|
2111
|
-
const targetPath = join4(getCustomSkillsDir(), skill.name);
|
|
2112
|
-
if (!existsSync5(sourcePath)) {
|
|
2113
|
-
console.error(`Custom skill source not found: ${sourcePath}`);
|
|
2114
|
-
return false;
|
|
2115
|
-
}
|
|
2116
|
-
rmSync(targetPath, { recursive: true, force: true });
|
|
2117
|
-
copyDirRecursive(sourcePath, targetPath);
|
|
2118
|
-
return true;
|
|
2119
|
-
}
|
|
2120
|
-
function removeObsoleteSkills(removedSkillNames) {
|
|
2121
|
-
const removedSkills = [];
|
|
2122
|
-
for (const skillName of removedSkillNames) {
|
|
2123
|
-
const targetPath = join4(getCustomSkillsDir(), skillName);
|
|
2124
|
-
try {
|
|
2125
|
-
console.log(`Removing obsolete bundled skill: ${skillName}`);
|
|
2126
|
-
rmSync(targetPath, { recursive: true, force: true });
|
|
2127
|
-
removedSkills.push(skillName);
|
|
2128
|
-
} catch (error) {
|
|
2129
|
-
console.warn(`Failed to remove obsolete bundled skill: ${skillName}`);
|
|
2130
|
-
console.warn(error);
|
|
2131
|
-
}
|
|
2132
|
-
}
|
|
2133
|
-
return removedSkills;
|
|
2134
|
-
}
|
|
2135
|
-
function buildManifest(packageRoot, updatedSkills, previousManifest, pluginVersion, sharedHash) {
|
|
2136
|
-
const installedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
2137
|
-
const updatedSkillNames = new Set(
|
|
2138
|
-
updatedSkills.map(({ skill }) => skill.name)
|
|
2139
|
-
);
|
|
2140
|
-
const skills = Object.fromEntries(
|
|
2141
|
-
CUSTOM_SKILLS.map((skill) => {
|
|
2142
|
-
const previousEntry = previousManifest?.skills[skill.name];
|
|
2143
|
-
const nextInstalledAt = updatedSkillNames.has(skill.name) ? installedAt : previousEntry?.installedAt ?? installedAt;
|
|
2144
|
-
return [
|
|
2145
|
-
skill.name,
|
|
2146
|
-
{
|
|
2147
|
-
hash: computeSkillHash(join4(packageRoot, skill.sourcePath)),
|
|
2148
|
-
installedAt: nextInstalledAt
|
|
2149
|
-
}
|
|
2150
|
-
];
|
|
2151
|
-
})
|
|
2152
|
-
);
|
|
2153
|
-
return {
|
|
2154
|
-
pluginVersion,
|
|
2155
|
-
sharedHash,
|
|
2156
|
-
skills
|
|
2157
|
-
};
|
|
2158
|
-
}
|
|
2159
|
-
function pruneRemovedSkillsFromManifest(manifest, removedSkills) {
|
|
2160
|
-
const removedSkillNames = new Set(removedSkills);
|
|
2161
|
-
return {
|
|
2162
|
-
...manifest,
|
|
2163
|
-
skills: Object.fromEntries(
|
|
2164
|
-
Object.entries(manifest.skills).filter(
|
|
2165
|
-
([skillName]) => !removedSkillNames.has(skillName)
|
|
2166
|
-
)
|
|
2167
|
-
)
|
|
2168
|
-
};
|
|
2169
|
-
}
|
|
2170
|
-
function installCustomSkills(packageRoot = resolvePackageRoot()) {
|
|
2171
|
-
const updateCheck = checkSkillsNeedUpdate(packageRoot);
|
|
2172
|
-
if (!updateCheck.needsUpdate) {
|
|
2173
|
-
return {
|
|
2174
|
-
success: true,
|
|
2175
|
-
updatedSkills: [],
|
|
2176
|
-
skippedSkills: [...CUSTOM_SKILLS],
|
|
2177
|
-
failedSkills: [],
|
|
2178
|
-
removedSkills: []
|
|
2179
|
-
};
|
|
2180
|
-
}
|
|
2181
|
-
const removedSkills = removeObsoleteSkills(updateCheck.removedSkills);
|
|
2182
|
-
if (removedSkills.length > 0 && updateCheck.manifest) {
|
|
2183
|
-
writeManifest(
|
|
2184
|
-
pruneRemovedSkillsFromManifest(updateCheck.manifest, removedSkills)
|
|
2185
|
-
);
|
|
2186
|
-
}
|
|
2187
|
-
if (updateCheck.skillsNeedingUpdate.length === 0) {
|
|
2188
|
-
writeManifest(
|
|
2189
|
-
buildManifest(
|
|
2190
|
-
packageRoot,
|
|
2191
|
-
[],
|
|
2192
|
-
updateCheck.manifest,
|
|
2193
|
-
updateCheck.pluginVersion,
|
|
2194
|
-
updateCheck.sharedHash
|
|
2195
|
-
)
|
|
2196
|
-
);
|
|
2197
|
-
return {
|
|
2198
|
-
success: true,
|
|
2199
|
-
updatedSkills: [],
|
|
2200
|
-
skippedSkills: [...CUSTOM_SKILLS],
|
|
2201
|
-
failedSkills: [],
|
|
2202
|
-
removedSkills
|
|
2203
|
-
};
|
|
2204
|
-
}
|
|
2205
|
-
if (!installSharedSkillAssets(packageRoot)) {
|
|
2206
|
-
return {
|
|
2207
|
-
success: false,
|
|
2208
|
-
updatedSkills: [],
|
|
2209
|
-
skippedSkills: [],
|
|
2210
|
-
failedSkills: updateCheck.skillsNeedingUpdate.map(
|
|
2211
|
-
({ skill, reasons }) => ({
|
|
2212
|
-
skill,
|
|
2213
|
-
reasons
|
|
2214
|
-
})
|
|
2215
|
-
),
|
|
2216
|
-
removedSkills
|
|
2217
|
-
};
|
|
2218
|
-
}
|
|
2219
|
-
const updatesBySkillName = new Map(
|
|
2220
|
-
updateCheck.skillsNeedingUpdate.map((entry) => [entry.skill.name, entry])
|
|
2221
|
-
);
|
|
2222
|
-
const updatedSkills = [];
|
|
2223
|
-
const skippedSkills = [];
|
|
2224
|
-
const failedSkills = [];
|
|
2225
|
-
for (const skill of CUSTOM_SKILLS) {
|
|
2226
|
-
const pendingUpdate = updatesBySkillName.get(skill.name);
|
|
2227
|
-
if (!pendingUpdate) {
|
|
2228
|
-
skippedSkills.push(skill);
|
|
2229
|
-
continue;
|
|
2230
|
-
}
|
|
2231
|
-
if (installCustomSkillFiles(skill, packageRoot)) {
|
|
2232
|
-
updatedSkills.push({
|
|
2233
|
-
skill,
|
|
2234
|
-
reasons: pendingUpdate.reasons
|
|
2235
|
-
});
|
|
2236
|
-
continue;
|
|
2237
|
-
}
|
|
2238
|
-
failedSkills.push({
|
|
2239
|
-
skill,
|
|
2240
|
-
reasons: pendingUpdate.reasons
|
|
2241
|
-
});
|
|
2242
|
-
}
|
|
2243
|
-
if (failedSkills.length > 0) {
|
|
2244
|
-
return {
|
|
2245
|
-
success: false,
|
|
2246
|
-
updatedSkills,
|
|
2247
|
-
skippedSkills,
|
|
2248
|
-
failedSkills,
|
|
2249
|
-
removedSkills
|
|
2250
|
-
};
|
|
2251
|
-
}
|
|
2252
|
-
writeManifest(
|
|
2253
|
-
buildManifest(
|
|
2254
|
-
packageRoot,
|
|
2255
|
-
updatedSkills,
|
|
2256
|
-
updateCheck.manifest,
|
|
2257
|
-
updateCheck.pluginVersion,
|
|
2258
|
-
updateCheck.sharedHash
|
|
2259
|
-
)
|
|
2260
|
-
);
|
|
2261
|
-
return {
|
|
2262
|
-
success: true,
|
|
2263
|
-
updatedSkills,
|
|
2264
|
-
skippedSkills,
|
|
2265
|
-
failedSkills,
|
|
2266
|
-
removedSkills
|
|
2267
|
-
};
|
|
2268
|
-
}
|
|
2269
|
-
|
|
2270
|
-
// src/mcp/context7.ts
|
|
2271
|
-
var CONTEXT7_MCP_URL = "https://mcp.context7.com/mcp";
|
|
2272
|
-
var context7 = {
|
|
2273
|
-
type: "remote",
|
|
2274
|
-
url: CONTEXT7_MCP_URL,
|
|
2275
|
-
headers: process.env.CONTEXT7_API_KEY ? { CONTEXT7_API_KEY: process.env.CONTEXT7_API_KEY } : void 0,
|
|
2276
|
-
oauth: false
|
|
2277
|
-
};
|
|
2278
|
-
|
|
2279
|
-
// src/mcp/exa.ts
|
|
2280
|
-
var exa = {
|
|
2281
|
-
type: "local",
|
|
2282
|
-
command: ["npx", "-y", "exa-mcp-server"]
|
|
2283
|
-
};
|
|
2284
|
-
|
|
2285
|
-
// src/mcp/grep-app.ts
|
|
2286
|
-
var GREP_APP_MCP_URL = "https://mcp.grep.app";
|
|
2287
|
-
var grep_app = {
|
|
2288
|
-
type: "remote",
|
|
2289
|
-
url: GREP_APP_MCP_URL,
|
|
2290
|
-
oauth: false
|
|
2291
|
-
};
|
|
2292
|
-
|
|
2293
|
-
export {
|
|
2294
|
-
SUBAGENT_NAMES,
|
|
2295
|
-
ALL_AGENT_NAMES,
|
|
2296
|
-
DEFAULT_MODELS,
|
|
2297
|
-
CONFIRMED_OPENAI_SUBAGENT_PRESET,
|
|
2298
|
-
POLL_INTERVAL_BACKGROUND_MS,
|
|
2299
|
-
DEFAULT_THOTH_COMMAND,
|
|
2300
|
-
getOpenCodeConfigPaths,
|
|
2301
|
-
getOpenCodeManagedModelStatePath,
|
|
2302
|
-
getExistingLiteConfigPath,
|
|
2303
|
-
getExistingConfigPath,
|
|
2304
|
-
ensureConfigDir,
|
|
2305
|
-
generateLiteConfig,
|
|
2306
|
-
stripJsonComments,
|
|
2307
|
-
parseConfig,
|
|
2308
|
-
writeConfig,
|
|
2309
|
-
updateOpenCodeMainConfig,
|
|
2310
|
-
writeLiteConfig,
|
|
2311
|
-
detectCurrentConfig,
|
|
2312
|
-
loadPluginConfig,
|
|
2313
|
-
loadAgentPrompt,
|
|
2314
|
-
getAgentOverride,
|
|
2315
|
-
getPrimaryModelId,
|
|
2316
|
-
OPENCODE_PROMPT_DIALECT,
|
|
2317
|
-
CODEX_PROMPT_DIALECT,
|
|
2318
|
-
CLAUDE_CODE_SUBAGENT_NAMESPACE,
|
|
2319
|
-
claudeCodeSubagentType,
|
|
2320
|
-
CLAUDE_CODE_PROMPT_DIALECT,
|
|
2321
|
-
createStepBudgetSection,
|
|
2322
|
-
createModelFamilySection,
|
|
2323
|
-
createOrchestratorPromptSections,
|
|
2324
|
-
createReadOnlySpecialistPromptSections,
|
|
2325
|
-
createWriteCapableSpecialistPromptSections,
|
|
2326
|
-
renderPromptSection,
|
|
2327
|
-
renderRolePrompt,
|
|
2328
|
-
appendPromptSections,
|
|
2329
|
-
detectModelFamily,
|
|
2330
|
-
getStepBudgetPromptSection,
|
|
2331
|
-
getModelFamilyPromptSection,
|
|
2332
|
-
composeAgentPrompt,
|
|
2333
|
-
getSkillRegistry,
|
|
2334
|
-
CUSTOM_SKILLS,
|
|
2335
|
-
getCustomSkillsDir,
|
|
2336
|
-
findPackageRoot,
|
|
2337
|
-
checkCustomSkillsNeedUpdate,
|
|
2338
|
-
installCustomSkills,
|
|
2339
|
-
CONTEXT7_MCP_URL,
|
|
2340
|
-
context7,
|
|
2341
|
-
exa,
|
|
2342
|
-
GREP_APP_MCP_URL,
|
|
2343
|
-
grep_app
|
|
2344
|
-
};
|