oh-my-opencode-slim 0.7.0 → 0.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -1
- package/dist/agents/index.d.ts +1 -1
- package/dist/agents/orchestrator.d.ts +1 -1
- package/dist/background/background-manager.d.ts +42 -0
- package/dist/background/tmux-session-manager.d.ts +5 -0
- package/dist/cli/config-manager.d.ts +3 -0
- package/dist/cli/dynamic-model-selection.d.ts +14 -2
- package/dist/cli/external-rankings.d.ts +8 -0
- package/dist/cli/index.js +1897 -272
- package/dist/cli/model-key-normalization.d.ts +1 -0
- package/dist/cli/opencode-models.d.ts +4 -0
- package/dist/cli/paths.d.ts +2 -0
- package/dist/cli/precedence-resolver.d.ts +16 -0
- package/dist/cli/providers.d.ts +1 -1
- package/dist/cli/scoring-v2/engine.d.ts +4 -0
- package/dist/cli/scoring-v2/features.d.ts +3 -0
- package/dist/cli/scoring-v2/index.d.ts +4 -0
- package/dist/cli/scoring-v2/types.d.ts +17 -0
- package/dist/cli/scoring-v2/weights.d.ts +2 -0
- package/dist/cli/skills.d.ts +17 -0
- package/dist/cli/system.d.ts +2 -0
- package/dist/cli/types.d.ts +45 -1
- package/dist/config/constants.d.ts +1 -0
- package/dist/config/schema.d.ts +94 -2
- package/dist/hooks/autopilot/index.d.ts +43 -0
- package/dist/hooks/delegate-task-retry/guidance.d.ts +2 -0
- package/dist/hooks/delegate-task-retry/hook.d.ts +8 -0
- package/dist/hooks/delegate-task-retry/index.d.ts +4 -0
- package/dist/hooks/delegate-task-retry/patterns.d.ts +11 -0
- package/dist/hooks/index.d.ts +2 -0
- package/dist/hooks/json-error-recovery/hook.d.ts +18 -0
- package/dist/hooks/json-error-recovery/index.d.ts +1 -0
- package/dist/index.js +356 -16
- package/dist/utils/env.d.ts +1 -0
- package/dist/utils/index.d.ts +1 -0
- package/package.json +8 -8
package/dist/index.js
CHANGED
|
@@ -3277,6 +3277,16 @@ var require_main = __commonJS((exports) => {
|
|
|
3277
3277
|
exports.createMessageConnection = createMessageConnection;
|
|
3278
3278
|
});
|
|
3279
3279
|
|
|
3280
|
+
// src/cli/custom-skills.ts
|
|
3281
|
+
var CUSTOM_SKILLS = [
|
|
3282
|
+
{
|
|
3283
|
+
name: "cartography",
|
|
3284
|
+
description: "Repository understanding and hierarchical codemap generation",
|
|
3285
|
+
allowedAgents: ["orchestrator", "explorer"],
|
|
3286
|
+
sourcePath: "src/skills/cartography"
|
|
3287
|
+
}
|
|
3288
|
+
];
|
|
3289
|
+
|
|
3280
3290
|
// src/cli/skills.ts
|
|
3281
3291
|
var RECOMMENDED_SKILLS = [
|
|
3282
3292
|
{
|
|
@@ -3298,6 +3308,13 @@ var RECOMMENDED_SKILLS = [
|
|
|
3298
3308
|
]
|
|
3299
3309
|
}
|
|
3300
3310
|
];
|
|
3311
|
+
var PERMISSION_ONLY_SKILLS = [
|
|
3312
|
+
{
|
|
3313
|
+
name: "requesting-code-review",
|
|
3314
|
+
allowedAgents: ["oracle"],
|
|
3315
|
+
description: "Code review template for reviewer subagents in multi-step workflows"
|
|
3316
|
+
}
|
|
3317
|
+
];
|
|
3301
3318
|
function getSkillPermissionsForAgent(agentName, skillList) {
|
|
3302
3319
|
const permissions = {
|
|
3303
3320
|
"*": agentName === "orchestrator" ? "allow" : "deny"
|
|
@@ -3321,6 +3338,18 @@ function getSkillPermissionsForAgent(agentName, skillList) {
|
|
|
3321
3338
|
permissions[skill.skillName] = "allow";
|
|
3322
3339
|
}
|
|
3323
3340
|
}
|
|
3341
|
+
for (const skill of CUSTOM_SKILLS) {
|
|
3342
|
+
const isAllowed = skill.allowedAgents.includes("*") || skill.allowedAgents.includes(agentName);
|
|
3343
|
+
if (isAllowed) {
|
|
3344
|
+
permissions[skill.name] = "allow";
|
|
3345
|
+
}
|
|
3346
|
+
}
|
|
3347
|
+
for (const skill of PERMISSION_ONLY_SKILLS) {
|
|
3348
|
+
const isAllowed = skill.allowedAgents.includes("*") || skill.allowedAgents.includes(agentName);
|
|
3349
|
+
if (isAllowed) {
|
|
3350
|
+
permissions[skill.name] = "allow";
|
|
3351
|
+
}
|
|
3352
|
+
}
|
|
3324
3353
|
return permissions;
|
|
3325
3354
|
}
|
|
3326
3355
|
|
|
@@ -3338,6 +3367,14 @@ var SUBAGENT_NAMES = [
|
|
|
3338
3367
|
];
|
|
3339
3368
|
var ORCHESTRATOR_NAME = "orchestrator";
|
|
3340
3369
|
var ALL_AGENT_NAMES = [ORCHESTRATOR_NAME, ...SUBAGENT_NAMES];
|
|
3370
|
+
var SUBAGENT_DELEGATION_RULES = {
|
|
3371
|
+
orchestrator: SUBAGENT_NAMES,
|
|
3372
|
+
fixer: [],
|
|
3373
|
+
designer: [],
|
|
3374
|
+
explorer: [],
|
|
3375
|
+
librarian: [],
|
|
3376
|
+
oracle: []
|
|
3377
|
+
};
|
|
3341
3378
|
var DEFAULT_MODELS = {
|
|
3342
3379
|
orchestrator: "kimi-for-coding/k2p5",
|
|
3343
3380
|
oracle: "openai/gpt-5.2-codex",
|
|
@@ -16939,6 +16976,34 @@ function date4(params) {
|
|
|
16939
16976
|
// node_modules/zod/v4/classic/external.js
|
|
16940
16977
|
config(en_default());
|
|
16941
16978
|
// src/config/schema.ts
|
|
16979
|
+
var ProviderModelIdSchema = exports_external.string().regex(/^[^/\s]+\/[^\s]+$/, "Expected provider/model format (provider/.../model)");
|
|
16980
|
+
var ManualAgentPlanSchema = exports_external.object({
|
|
16981
|
+
primary: ProviderModelIdSchema,
|
|
16982
|
+
fallback1: ProviderModelIdSchema,
|
|
16983
|
+
fallback2: ProviderModelIdSchema,
|
|
16984
|
+
fallback3: ProviderModelIdSchema
|
|
16985
|
+
}).superRefine((value, ctx) => {
|
|
16986
|
+
const unique = new Set([
|
|
16987
|
+
value.primary,
|
|
16988
|
+
value.fallback1,
|
|
16989
|
+
value.fallback2,
|
|
16990
|
+
value.fallback3
|
|
16991
|
+
]);
|
|
16992
|
+
if (unique.size !== 4) {
|
|
16993
|
+
ctx.addIssue({
|
|
16994
|
+
code: exports_external.ZodIssueCode.custom,
|
|
16995
|
+
message: "primary and fallbacks must be unique per agent"
|
|
16996
|
+
});
|
|
16997
|
+
}
|
|
16998
|
+
});
|
|
16999
|
+
var ManualPlanSchema = exports_external.object({
|
|
17000
|
+
orchestrator: ManualAgentPlanSchema,
|
|
17001
|
+
oracle: ManualAgentPlanSchema,
|
|
17002
|
+
designer: ManualAgentPlanSchema,
|
|
17003
|
+
explorer: ManualAgentPlanSchema,
|
|
17004
|
+
librarian: ManualAgentPlanSchema,
|
|
17005
|
+
fixer: ManualAgentPlanSchema
|
|
17006
|
+
}).strict();
|
|
16942
17007
|
var AgentModelChainSchema = exports_external.array(exports_external.string()).min(1);
|
|
16943
17008
|
var FallbackChainsSchema = exports_external.object({
|
|
16944
17009
|
orchestrator: AgentModelChainSchema.optional(),
|
|
@@ -16947,7 +17012,7 @@ var FallbackChainsSchema = exports_external.object({
|
|
|
16947
17012
|
explorer: AgentModelChainSchema.optional(),
|
|
16948
17013
|
librarian: AgentModelChainSchema.optional(),
|
|
16949
17014
|
fixer: AgentModelChainSchema.optional()
|
|
16950
|
-
}).
|
|
17015
|
+
}).catchall(AgentModelChainSchema);
|
|
16951
17016
|
var AgentOverrideConfigSchema = exports_external.object({
|
|
16952
17017
|
model: exports_external.string().optional(),
|
|
16953
17018
|
temperature: exports_external.number().min(0).max(2).optional(),
|
|
@@ -16974,11 +17039,14 @@ var BackgroundTaskConfigSchema = exports_external.object({
|
|
|
16974
17039
|
});
|
|
16975
17040
|
var FailoverConfigSchema = exports_external.object({
|
|
16976
17041
|
enabled: exports_external.boolean().default(true),
|
|
16977
|
-
timeoutMs: exports_external.number().min(
|
|
17042
|
+
timeoutMs: exports_external.number().min(0).default(15000),
|
|
16978
17043
|
chains: FallbackChainsSchema.default({})
|
|
16979
17044
|
});
|
|
16980
17045
|
var PluginConfigSchema = exports_external.object({
|
|
16981
17046
|
preset: exports_external.string().optional(),
|
|
17047
|
+
scoringEngineVersion: exports_external.enum(["v1", "v2-shadow", "v2"]).optional(),
|
|
17048
|
+
balanceProviderUsage: exports_external.boolean().optional(),
|
|
17049
|
+
manualPlan: ManualPlanSchema.optional(),
|
|
16982
17050
|
presets: exports_external.record(exports_external.string(), PresetSchema).optional(),
|
|
16983
17051
|
agents: exports_external.record(exports_external.string(), AgentOverrideConfigSchema).optional(),
|
|
16984
17052
|
disabled_mcps: exports_external.array(exports_external.string()).optional(),
|
|
@@ -17241,9 +17309,10 @@ var FIXER_PROMPT = `You are Fixer - a fast, focused implementation specialist.
|
|
|
17241
17309
|
|
|
17242
17310
|
**Constraints**:
|
|
17243
17311
|
- NO external research (no websearch, context7, grep_app)
|
|
17244
|
-
- NO delegation (no background_task)
|
|
17312
|
+
- NO delegation (no background_task, no spawning subagents)
|
|
17245
17313
|
- No multi-step research/planning; minimal execution sequence ok
|
|
17246
|
-
- If context is insufficient
|
|
17314
|
+
- If context is insufficient: use grep/glob/lsp_diagnostics directly \u2014 do not delegate
|
|
17315
|
+
- Only ask for missing inputs you truly cannot retrieve yourself
|
|
17247
17316
|
|
|
17248
17317
|
**Output Format**:
|
|
17249
17318
|
<summary>
|
|
@@ -17430,7 +17499,7 @@ Each specialist delivers 10x results in their domain:
|
|
|
17430
17499
|
- @explorer \u2192 Parallel discovery when you need to find unknowns, not read knowns
|
|
17431
17500
|
- @librarian \u2192 Complex/evolving APIs where docs prevent errors, not basic usage
|
|
17432
17501
|
- @oracle \u2192 High-stakes decisions where wrong choice is costly, not routine calls
|
|
17433
|
-
- @designer \u2192 User-facing experiences where polish matters, not internal logic
|
|
17502
|
+
- @designer \u2192 User-facing experiences where polish matters, not internal logic
|
|
17434
17503
|
- @fixer \u2192 Parallel execution of clear specs, not explaining trivial changes
|
|
17435
17504
|
|
|
17436
17505
|
**Delegation efficiency:**
|
|
@@ -17465,6 +17534,10 @@ Balance: respect dependencies, avoid parallelizing what must be sequential.
|
|
|
17465
17534
|
- Confirm specialists completed successfully
|
|
17466
17535
|
- Verify solution meets requirements
|
|
17467
17536
|
|
|
17537
|
+
## Agent Role Mapping
|
|
17538
|
+
When a workflow calls for an **implementer** subagent: dispatch \`@fixer\`. Fixer has enforced constraints (no research, no delegation, structured output) that match the implementer role exactly.
|
|
17539
|
+
When a workflow calls for a **reviewer** subagent: dispatch \`@oracle\`. Oracle has the depth for architectural review and access to code review skills.
|
|
17540
|
+
|
|
17468
17541
|
</Workflow>
|
|
17469
17542
|
|
|
17470
17543
|
<Communication>
|
|
@@ -17522,6 +17595,8 @@ ${customAppendPrompt}`;
|
|
|
17522
17595
|
function applyOverrides(agent, override) {
|
|
17523
17596
|
if (override.model)
|
|
17524
17597
|
agent.config.model = override.model;
|
|
17598
|
+
if (override.variant)
|
|
17599
|
+
agent.config.variant = override.variant;
|
|
17525
17600
|
if (override.temperature !== undefined)
|
|
17526
17601
|
agent.config.temperature = override.temperature;
|
|
17527
17602
|
}
|
|
@@ -17829,6 +17904,16 @@ async function closeTmuxPane(paneId) {
|
|
|
17829
17904
|
return false;
|
|
17830
17905
|
}
|
|
17831
17906
|
try {
|
|
17907
|
+
log("[tmux] closeTmuxPane: sending Ctrl+C for graceful shutdown", {
|
|
17908
|
+
paneId
|
|
17909
|
+
});
|
|
17910
|
+
const ctrlCProc = spawn([tmux, "send-keys", "-t", paneId, "C-c"], {
|
|
17911
|
+
stdout: "pipe",
|
|
17912
|
+
stderr: "pipe"
|
|
17913
|
+
});
|
|
17914
|
+
await ctrlCProc.exited;
|
|
17915
|
+
await new Promise((r) => setTimeout(r, 250));
|
|
17916
|
+
log("[tmux] closeTmuxPane: killing pane", { paneId });
|
|
17832
17917
|
const proc = spawn([tmux, "kill-pane", "-t", paneId], {
|
|
17833
17918
|
stdout: "pipe",
|
|
17834
17919
|
stderr: "pipe"
|
|
@@ -17959,6 +18044,7 @@ function generateTaskId() {
|
|
|
17959
18044
|
class BackgroundTaskManager {
|
|
17960
18045
|
tasks = new Map;
|
|
17961
18046
|
tasksBySessionId = new Map;
|
|
18047
|
+
agentBySessionId = new Map;
|
|
17962
18048
|
client;
|
|
17963
18049
|
directory;
|
|
17964
18050
|
tmuxEnabled;
|
|
@@ -17978,6 +18064,20 @@ class BackgroundTaskManager {
|
|
|
17978
18064
|
};
|
|
17979
18065
|
this.maxConcurrentStarts = this.backgroundConfig.maxConcurrentStarts;
|
|
17980
18066
|
}
|
|
18067
|
+
getSubagentRules(agentName) {
|
|
18068
|
+
return SUBAGENT_DELEGATION_RULES[agentName] ?? ["explorer"];
|
|
18069
|
+
}
|
|
18070
|
+
isAgentAllowed(parentSessionId, requestedAgent) {
|
|
18071
|
+
const parentAgentName = this.agentBySessionId.get(parentSessionId) ?? "orchestrator";
|
|
18072
|
+
const allowedSubagents = this.getSubagentRules(parentAgentName);
|
|
18073
|
+
if (allowedSubagents.length === 0)
|
|
18074
|
+
return false;
|
|
18075
|
+
return allowedSubagents.includes(requestedAgent);
|
|
18076
|
+
}
|
|
18077
|
+
getAllowedSubagents(parentSessionId) {
|
|
18078
|
+
const parentAgentName = this.agentBySessionId.get(parentSessionId) ?? "orchestrator";
|
|
18079
|
+
return this.getSubagentRules(parentAgentName);
|
|
18080
|
+
}
|
|
17981
18081
|
launch(opts) {
|
|
17982
18082
|
const task = {
|
|
17983
18083
|
id: generateTaskId(),
|
|
@@ -18028,6 +18128,10 @@ class BackgroundTaskManager {
|
|
|
18028
18128
|
return chain;
|
|
18029
18129
|
}
|
|
18030
18130
|
async promptWithTimeout(args, timeoutMs) {
|
|
18131
|
+
if (timeoutMs <= 0) {
|
|
18132
|
+
await this.client.session.prompt(args);
|
|
18133
|
+
return;
|
|
18134
|
+
}
|
|
18031
18135
|
await Promise.race([
|
|
18032
18136
|
this.client.session.prompt(args),
|
|
18033
18137
|
new Promise((_, reject) => {
|
|
@@ -18037,6 +18141,13 @@ class BackgroundTaskManager {
|
|
|
18037
18141
|
})
|
|
18038
18142
|
]);
|
|
18039
18143
|
}
|
|
18144
|
+
calculateToolPermissions(agentName) {
|
|
18145
|
+
const allowedSubagents = this.getSubagentRules(agentName);
|
|
18146
|
+
if (allowedSubagents.length === 0) {
|
|
18147
|
+
return { background_task: false, task: false };
|
|
18148
|
+
}
|
|
18149
|
+
return { background_task: true, task: true };
|
|
18150
|
+
}
|
|
18040
18151
|
async startTask(task) {
|
|
18041
18152
|
task.status = "starting";
|
|
18042
18153
|
this.activeStarts++;
|
|
@@ -18057,19 +18168,21 @@ class BackgroundTaskManager {
|
|
|
18057
18168
|
}
|
|
18058
18169
|
task.sessionId = session.data.id;
|
|
18059
18170
|
this.tasksBySessionId.set(session.data.id, task.id);
|
|
18171
|
+
this.agentBySessionId.set(session.data.id, task.agent);
|
|
18060
18172
|
task.status = "running";
|
|
18061
18173
|
if (this.tmuxEnabled) {
|
|
18062
18174
|
await new Promise((r) => setTimeout(r, 500));
|
|
18063
18175
|
}
|
|
18176
|
+
const toolPermissions = this.calculateToolPermissions(task.agent);
|
|
18064
18177
|
const promptQuery = { directory: this.directory };
|
|
18065
18178
|
const resolvedVariant = resolveAgentVariant(this.config, task.agent);
|
|
18066
18179
|
const basePromptBody = applyAgentVariant(resolvedVariant, {
|
|
18067
18180
|
agent: task.agent,
|
|
18068
|
-
tools:
|
|
18181
|
+
tools: toolPermissions,
|
|
18069
18182
|
parts: [{ type: "text", text: task.prompt }]
|
|
18070
18183
|
});
|
|
18071
|
-
const timeoutMs = this.config?.fallback?.timeoutMs ?? FALLBACK_FAILOVER_TIMEOUT_MS;
|
|
18072
18184
|
const fallbackEnabled = this.config?.fallback?.enabled ?? true;
|
|
18185
|
+
const timeoutMs = fallbackEnabled ? this.config?.fallback?.timeoutMs ?? FALLBACK_FAILOVER_TIMEOUT_MS : 0;
|
|
18073
18186
|
const chain = fallbackEnabled ? this.resolveFallbackChain(task.agent) : [];
|
|
18074
18187
|
const attemptModels = chain.length > 0 ? chain : [undefined];
|
|
18075
18188
|
const errors3 = [];
|
|
@@ -18133,6 +18246,33 @@ class BackgroundTaskManager {
|
|
|
18133
18246
|
await this.extractAndCompleteTask(task);
|
|
18134
18247
|
}
|
|
18135
18248
|
}
|
|
18249
|
+
async handleSessionDeleted(event) {
|
|
18250
|
+
if (event.type !== "session.deleted")
|
|
18251
|
+
return;
|
|
18252
|
+
const sessionId = event.properties?.info?.id ?? event.properties?.sessionID;
|
|
18253
|
+
if (!sessionId)
|
|
18254
|
+
return;
|
|
18255
|
+
const taskId = this.tasksBySessionId.get(sessionId);
|
|
18256
|
+
if (!taskId)
|
|
18257
|
+
return;
|
|
18258
|
+
const task = this.tasks.get(taskId);
|
|
18259
|
+
if (!task)
|
|
18260
|
+
return;
|
|
18261
|
+
if (task.status === "running" || task.status === "pending") {
|
|
18262
|
+
log(`[background-manager] Session deleted, cancelling task: ${task.id}`);
|
|
18263
|
+
task.status = "cancelled";
|
|
18264
|
+
task.completedAt = new Date;
|
|
18265
|
+
task.error = "Session deleted";
|
|
18266
|
+
this.tasksBySessionId.delete(sessionId);
|
|
18267
|
+
this.agentBySessionId.delete(sessionId);
|
|
18268
|
+
const resolver = this.completionResolvers.get(taskId);
|
|
18269
|
+
if (resolver) {
|
|
18270
|
+
resolver(task);
|
|
18271
|
+
this.completionResolvers.delete(taskId);
|
|
18272
|
+
}
|
|
18273
|
+
log(`[background-manager] Task cancelled due to session deletion: ${task.id}`);
|
|
18274
|
+
}
|
|
18275
|
+
}
|
|
18136
18276
|
async extractAndCompleteTask(task) {
|
|
18137
18277
|
if (!task.sessionId)
|
|
18138
18278
|
return;
|
|
@@ -18175,6 +18315,12 @@ class BackgroundTaskManager {
|
|
|
18175
18315
|
}
|
|
18176
18316
|
if (task.sessionId) {
|
|
18177
18317
|
this.tasksBySessionId.delete(task.sessionId);
|
|
18318
|
+
this.agentBySessionId.delete(task.sessionId);
|
|
18319
|
+
}
|
|
18320
|
+
if (task.sessionId) {
|
|
18321
|
+
this.client.session.abort({
|
|
18322
|
+
path: { id: task.sessionId }
|
|
18323
|
+
}).catch(() => {});
|
|
18178
18324
|
}
|
|
18179
18325
|
if (task.parentSessionId) {
|
|
18180
18326
|
this.sendCompletionNotification(task).catch((err) => {
|
|
@@ -18261,6 +18407,7 @@ class BackgroundTaskManager {
|
|
|
18261
18407
|
this.completionResolvers.clear();
|
|
18262
18408
|
this.tasks.clear();
|
|
18263
18409
|
this.tasksBySessionId.clear();
|
|
18410
|
+
this.agentBySessionId.clear();
|
|
18264
18411
|
}
|
|
18265
18412
|
}
|
|
18266
18413
|
// src/background/tmux-session-manager.ts
|
|
@@ -18342,6 +18489,19 @@ class TmuxSessionManager {
|
|
|
18342
18489
|
await this.closeSession(sessionId);
|
|
18343
18490
|
}
|
|
18344
18491
|
}
|
|
18492
|
+
async onSessionDeleted(event) {
|
|
18493
|
+
if (!this.enabled)
|
|
18494
|
+
return;
|
|
18495
|
+
if (event.type !== "session.deleted")
|
|
18496
|
+
return;
|
|
18497
|
+
const sessionId = event.properties?.sessionID;
|
|
18498
|
+
if (!sessionId)
|
|
18499
|
+
return;
|
|
18500
|
+
log("[tmux-session-manager] session deleted, closing pane", {
|
|
18501
|
+
sessionId
|
|
18502
|
+
});
|
|
18503
|
+
await this.closeSession(sessionId);
|
|
18504
|
+
}
|
|
18345
18505
|
startPolling() {
|
|
18346
18506
|
if (this.pollInterval)
|
|
18347
18507
|
return;
|
|
@@ -18420,6 +18580,8 @@ class TmuxSessionManager {
|
|
|
18420
18580
|
// src/hooks/auto-update-checker/cache.ts
|
|
18421
18581
|
import * as fs3 from "fs";
|
|
18422
18582
|
import * as path4 from "path";
|
|
18583
|
+
// src/cli/dynamic-model-selection.ts
|
|
18584
|
+
var FREE_BIASED_PROVIDERS = new Set(["opencode"]);
|
|
18423
18585
|
// src/hooks/auto-update-checker/constants.ts
|
|
18424
18586
|
import * as os3 from "os";
|
|
18425
18587
|
import * as path3 from "path";
|
|
@@ -18809,10 +18971,169 @@ function showToast(ctx, title, message, variant = "info", duration3 = 3000) {
|
|
|
18809
18971
|
body: { title, message, variant, duration: duration3 }
|
|
18810
18972
|
}).catch(() => {});
|
|
18811
18973
|
}
|
|
18974
|
+
// src/hooks/delegate-task-retry/patterns.ts
|
|
18975
|
+
var DELEGATE_TASK_ERROR_PATTERNS = [
|
|
18976
|
+
{
|
|
18977
|
+
pattern: "run_in_background",
|
|
18978
|
+
errorType: "missing_run_in_background",
|
|
18979
|
+
fixHint: "Add run_in_background=false (delegation) or run_in_background=true (parallel exploration)."
|
|
18980
|
+
},
|
|
18981
|
+
{
|
|
18982
|
+
pattern: "load_skills",
|
|
18983
|
+
errorType: "missing_load_skills",
|
|
18984
|
+
fixHint: "Add load_skills=[] (empty array when no skill is needed)."
|
|
18985
|
+
},
|
|
18986
|
+
{
|
|
18987
|
+
pattern: "category OR subagent_type",
|
|
18988
|
+
errorType: "mutual_exclusion",
|
|
18989
|
+
fixHint: 'Provide only one: category (e.g., "unspecified-low") OR subagent_type (e.g., "explorer").'
|
|
18990
|
+
},
|
|
18991
|
+
{
|
|
18992
|
+
pattern: "Must provide either category or subagent_type",
|
|
18993
|
+
errorType: "missing_category_or_agent",
|
|
18994
|
+
fixHint: 'Add either category="unspecified-low" or subagent_type="explorer".'
|
|
18995
|
+
},
|
|
18996
|
+
{
|
|
18997
|
+
pattern: "Unknown category",
|
|
18998
|
+
errorType: "unknown_category",
|
|
18999
|
+
fixHint: "Use a valid category listed in the error output."
|
|
19000
|
+
},
|
|
19001
|
+
{
|
|
19002
|
+
pattern: "Unknown agent",
|
|
19003
|
+
errorType: "unknown_agent",
|
|
19004
|
+
fixHint: "Use a valid agent name from the available list."
|
|
19005
|
+
},
|
|
19006
|
+
{
|
|
19007
|
+
pattern: "Skills not found",
|
|
19008
|
+
errorType: "unknown_skills",
|
|
19009
|
+
fixHint: "Use valid skill names listed in the error output."
|
|
19010
|
+
},
|
|
19011
|
+
{
|
|
19012
|
+
pattern: "is not allowed. Allowed agents:",
|
|
19013
|
+
errorType: "background_agent_not_allowed",
|
|
19014
|
+
fixHint: "Use one of the allowed agents shown in the error or delegate from a parent agent that can call this subagent."
|
|
19015
|
+
}
|
|
19016
|
+
];
|
|
19017
|
+
function detectDelegateTaskError(output) {
|
|
19018
|
+
if (!output || typeof output !== "string")
|
|
19019
|
+
return null;
|
|
19020
|
+
const hasErrorSignal = output.includes("[ERROR]") || output.includes("Invalid arguments") || output.includes("is not allowed. Allowed agents:");
|
|
19021
|
+
if (!hasErrorSignal)
|
|
19022
|
+
return null;
|
|
19023
|
+
for (const pattern of DELEGATE_TASK_ERROR_PATTERNS) {
|
|
19024
|
+
if (output.includes(pattern.pattern)) {
|
|
19025
|
+
return {
|
|
19026
|
+
errorType: pattern.errorType,
|
|
19027
|
+
originalOutput: output
|
|
19028
|
+
};
|
|
19029
|
+
}
|
|
19030
|
+
}
|
|
19031
|
+
return null;
|
|
19032
|
+
}
|
|
19033
|
+
// src/hooks/delegate-task-retry/guidance.ts
|
|
19034
|
+
function extractAvailableList(output) {
|
|
19035
|
+
const match = output.match(/Allowed agents:\s*(.+)$/m);
|
|
19036
|
+
if (match)
|
|
19037
|
+
return match[1].trim();
|
|
19038
|
+
const available = output.match(/Available[^:]*:\s*(.+)$/m);
|
|
19039
|
+
if (available)
|
|
19040
|
+
return available[1].trim();
|
|
19041
|
+
return null;
|
|
19042
|
+
}
|
|
19043
|
+
function buildRetryGuidance(errorInfo) {
|
|
19044
|
+
const pattern = DELEGATE_TASK_ERROR_PATTERNS.find((p) => p.errorType === errorInfo.errorType);
|
|
19045
|
+
if (!pattern) {
|
|
19046
|
+
return `
|
|
19047
|
+
[delegate-task retry] Fix parameters and retry with corrected arguments.`;
|
|
19048
|
+
}
|
|
19049
|
+
const available = extractAvailableList(errorInfo.originalOutput);
|
|
19050
|
+
const lines = [
|
|
19051
|
+
"",
|
|
19052
|
+
"[delegate-task retry suggestion]",
|
|
19053
|
+
`Error type: ${errorInfo.errorType}`,
|
|
19054
|
+
`Fix: ${pattern.fixHint}`
|
|
19055
|
+
];
|
|
19056
|
+
if (available) {
|
|
19057
|
+
lines.push(`Available: ${available}`);
|
|
19058
|
+
}
|
|
19059
|
+
lines.push("Retry now with corrected parameters. Example:", 'task(description="...", prompt="...", category="unspecified-low", run_in_background=false, load_skills=[])');
|
|
19060
|
+
return lines.join(`
|
|
19061
|
+
`);
|
|
19062
|
+
}
|
|
19063
|
+
// src/hooks/delegate-task-retry/hook.ts
|
|
19064
|
+
function createDelegateTaskRetryHook(_ctx) {
|
|
19065
|
+
return {
|
|
19066
|
+
"tool.execute.after": async (input, output) => {
|
|
19067
|
+
const toolName = input.tool.toLowerCase();
|
|
19068
|
+
const isDelegateTool = toolName === "task" || toolName === "background_task";
|
|
19069
|
+
if (!isDelegateTool)
|
|
19070
|
+
return;
|
|
19071
|
+
if (typeof output.output !== "string")
|
|
19072
|
+
return;
|
|
19073
|
+
const detected = detectDelegateTaskError(output.output);
|
|
19074
|
+
if (!detected)
|
|
19075
|
+
return;
|
|
19076
|
+
output.output += `
|
|
19077
|
+
${buildRetryGuidance(detected)}`;
|
|
19078
|
+
}
|
|
19079
|
+
};
|
|
19080
|
+
}
|
|
19081
|
+
// src/hooks/json-error-recovery/hook.ts
|
|
19082
|
+
var JSON_ERROR_TOOL_EXCLUDE_LIST = [
|
|
19083
|
+
"bash",
|
|
19084
|
+
"read",
|
|
19085
|
+
"glob",
|
|
19086
|
+
"grep",
|
|
19087
|
+
"webfetch",
|
|
19088
|
+
"grep_app_searchgithub",
|
|
19089
|
+
"websearch_web_search_exa"
|
|
19090
|
+
];
|
|
19091
|
+
var JSON_ERROR_PATTERNS = [
|
|
19092
|
+
/json parse error/i,
|
|
19093
|
+
/failed to parse json/i,
|
|
19094
|
+
/invalid json/i,
|
|
19095
|
+
/malformed json/i,
|
|
19096
|
+
/unexpected end of json input/i,
|
|
19097
|
+
/syntaxerror:\s*unexpected token.*json/i,
|
|
19098
|
+
/json[^\n]*expected '\}'/i,
|
|
19099
|
+
/json[^\n]*unexpected eof/i
|
|
19100
|
+
];
|
|
19101
|
+
var JSON_ERROR_REMINDER_MARKER = "[JSON PARSE ERROR - IMMEDIATE ACTION REQUIRED]";
|
|
19102
|
+
var JSON_ERROR_EXCLUDED_TOOLS = new Set(JSON_ERROR_TOOL_EXCLUDE_LIST);
|
|
19103
|
+
var JSON_ERROR_REMINDER = `
|
|
19104
|
+
[JSON PARSE ERROR - IMMEDIATE ACTION REQUIRED]
|
|
19105
|
+
|
|
19106
|
+
You sent invalid JSON arguments. The system could not parse your tool call.
|
|
19107
|
+
STOP and do this NOW:
|
|
19108
|
+
|
|
19109
|
+
1. LOOK at the error message above to see what was expected vs what you sent.
|
|
19110
|
+
2. CORRECT your JSON syntax (missing braces, unescaped quotes, trailing commas, etc).
|
|
19111
|
+
3. RETRY the tool call with valid JSON.
|
|
19112
|
+
|
|
19113
|
+
DO NOT repeat the exact same invalid call.
|
|
19114
|
+
`;
|
|
19115
|
+
function createJsonErrorRecoveryHook(_ctx) {
|
|
19116
|
+
return {
|
|
19117
|
+
"tool.execute.after": async (input, output) => {
|
|
19118
|
+
if (JSON_ERROR_EXCLUDED_TOOLS.has(input.tool.toLowerCase()))
|
|
19119
|
+
return;
|
|
19120
|
+
if (typeof output.output !== "string")
|
|
19121
|
+
return;
|
|
19122
|
+
if (output.output.includes(JSON_ERROR_REMINDER_MARKER))
|
|
19123
|
+
return;
|
|
19124
|
+
const outputText = output.output;
|
|
19125
|
+
const hasJsonError = JSON_ERROR_PATTERNS.some((pattern) => pattern.test(outputText));
|
|
19126
|
+
if (hasJsonError) {
|
|
19127
|
+
output.output += `
|
|
19128
|
+
${JSON_ERROR_REMINDER}`;
|
|
19129
|
+
}
|
|
19130
|
+
}
|
|
19131
|
+
};
|
|
19132
|
+
}
|
|
18812
19133
|
// src/hooks/phase-reminder/index.ts
|
|
18813
|
-
var PHASE_REMINDER = `<reminder
|
|
18814
|
-
|
|
18815
|
-
|
|
19134
|
+
var PHASE_REMINDER = `<reminder>Recall Workflow Rules:
|
|
19135
|
+
Understand \u2192 find the best path (delegate based on rules and parallelize independent work) \u2192 execute \u2192 verify.
|
|
19136
|
+
If delegating, launch the specialist in the same turn you mention it.</reminder>`;
|
|
18816
19137
|
function createPhaseReminderHook() {
|
|
18817
19138
|
return {
|
|
18818
19139
|
"experimental.chat.messages.transform": async (_input, output) => {
|
|
@@ -18852,7 +19173,7 @@ ${originalText}`;
|
|
|
18852
19173
|
var NUDGE = `
|
|
18853
19174
|
|
|
18854
19175
|
---
|
|
18855
|
-
Reminder
|
|
19176
|
+
Workflow Reminder: delegate based on rules; If mentioning a specialist, launch it in this same turn.`;
|
|
18856
19177
|
function createPostReadNudgeHook() {
|
|
18857
19178
|
return {
|
|
18858
19179
|
"tool.execute.after": async (input, output) => {
|
|
@@ -31789,11 +32110,16 @@ Key behaviors:
|
|
|
31789
32110
|
const agent = String(args.agent);
|
|
31790
32111
|
const prompt = String(args.prompt);
|
|
31791
32112
|
const description = String(args.description);
|
|
32113
|
+
const parentSessionId = toolContext.sessionID;
|
|
32114
|
+
if (!manager.isAgentAllowed(parentSessionId, agent)) {
|
|
32115
|
+
const allowed = manager.getAllowedSubagents(parentSessionId);
|
|
32116
|
+
return `Agent '${agent}' is not allowed. Allowed agents: ${allowed.join(", ")}`;
|
|
32117
|
+
}
|
|
31792
32118
|
const task = manager.launch({
|
|
31793
32119
|
agent,
|
|
31794
32120
|
prompt,
|
|
31795
32121
|
description,
|
|
31796
|
-
parentSessionId
|
|
32122
|
+
parentSessionId
|
|
31797
32123
|
});
|
|
31798
32124
|
return `Background task launched.
|
|
31799
32125
|
|
|
@@ -32164,11 +32490,14 @@ ${summary}`);
|
|
|
32164
32490
|
|
|
32165
32491
|
// src/tools/grep/tools.ts
|
|
32166
32492
|
var grep = tool({
|
|
32167
|
-
description: "Fast content search tool with safety limits (60s timeout, 10MB output). " + "Searches file contents using regular expressions. " + 'Supports full regex syntax (eg. "log.*Error", "function\\s+\\w+", etc.). ' + 'Filter files by pattern with the include parameter (
|
|
32493
|
+
description: "Fast content search tool with safety limits (60s timeout, 10MB output). " + "Searches file contents using regular expressions. " + 'Supports full regex syntax (eg. "log.*Error", "function\\s+\\w+", etc.). ' + 'Filter files by pattern with the include parameter (e.g. "*.js", "*.{ts,tsx}"). ' + "Returns file paths with matches sorted by modification time.",
|
|
32168
32494
|
args: {
|
|
32169
32495
|
pattern: tool.schema.string().describe("The regex pattern to search for in file contents"),
|
|
32170
32496
|
include: tool.schema.string().optional().describe('File pattern to include in the search (e.g. "*.js", "*.{ts,tsx}")'),
|
|
32171
|
-
path: tool.schema.string().optional().describe("The directory to search in. Defaults to the current working directory.")
|
|
32497
|
+
path: tool.schema.string().optional().describe("The directory to search in. Defaults to the current working directory."),
|
|
32498
|
+
caseSensitive: tool.schema.boolean().optional().default(false).describe("Perform case-sensitive search (default: false)"),
|
|
32499
|
+
wholeWord: tool.schema.boolean().optional().default(false).describe("Match whole words only (default: false)"),
|
|
32500
|
+
fixedStrings: tool.schema.boolean().optional().default(false).describe("Treat pattern as literal string (default: false)")
|
|
32172
32501
|
},
|
|
32173
32502
|
execute: async (args) => {
|
|
32174
32503
|
try {
|
|
@@ -32178,7 +32507,10 @@ var grep = tool({
|
|
|
32178
32507
|
pattern: args.pattern,
|
|
32179
32508
|
paths: paths2,
|
|
32180
32509
|
globs,
|
|
32181
|
-
context: 0
|
|
32510
|
+
context: 0,
|
|
32511
|
+
caseSensitive: args.caseSensitive ?? false,
|
|
32512
|
+
wholeWord: args.wholeWord ?? false,
|
|
32513
|
+
fixedStrings: args.fixedStrings ?? false
|
|
32182
32514
|
});
|
|
32183
32515
|
return formatGrepResult(result);
|
|
32184
32516
|
} catch (e) {
|
|
@@ -33107,6 +33439,8 @@ var OhMyOpenCodeLite = async (ctx) => {
|
|
|
33107
33439
|
});
|
|
33108
33440
|
const phaseReminderHook = createPhaseReminderHook();
|
|
33109
33441
|
const postReadNudgeHook = createPostReadNudgeHook();
|
|
33442
|
+
const delegateTaskRetryHook = createDelegateTaskRetryHook(ctx);
|
|
33443
|
+
const jsonErrorRecoveryHook = createJsonErrorRecoveryHook(ctx);
|
|
33110
33444
|
return {
|
|
33111
33445
|
name: "oh-my-opencode-slim",
|
|
33112
33446
|
agent: agents,
|
|
@@ -33162,9 +33496,15 @@ var OhMyOpenCodeLite = async (ctx) => {
|
|
|
33162
33496
|
await tmuxSessionManager.onSessionCreated(input.event);
|
|
33163
33497
|
await backgroundManager.handleSessionStatus(input.event);
|
|
33164
33498
|
await tmuxSessionManager.onSessionStatus(input.event);
|
|
33499
|
+
await backgroundManager.handleSessionDeleted(input.event);
|
|
33500
|
+
await tmuxSessionManager.onSessionDeleted(input.event);
|
|
33165
33501
|
},
|
|
33166
33502
|
"experimental.chat.messages.transform": phaseReminderHook["experimental.chat.messages.transform"],
|
|
33167
|
-
"tool.execute.after":
|
|
33503
|
+
"tool.execute.after": async (input, output) => {
|
|
33504
|
+
await delegateTaskRetryHook["tool.execute.after"](input, output);
|
|
33505
|
+
await jsonErrorRecoveryHook["tool.execute.after"](input, output);
|
|
33506
|
+
await postReadNudgeHook["tool.execute.after"](input, output);
|
|
33507
|
+
}
|
|
33168
33508
|
};
|
|
33169
33509
|
};
|
|
33170
33510
|
var src_default = OhMyOpenCodeLite;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function getEnv(name: string): string | undefined;
|
package/dist/utils/index.d.ts
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "oh-my-opencode-slim",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.1",
|
|
4
4
|
"description": "Lightweight agent orchestration plugin for OpenCode - a slimmed-down fork of oh-my-opencode",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -50,17 +50,17 @@
|
|
|
50
50
|
},
|
|
51
51
|
"dependencies": {
|
|
52
52
|
"@ast-grep/cli": "^0.40.0",
|
|
53
|
-
"@modelcontextprotocol/sdk": "^1.
|
|
54
|
-
"@opencode-ai/plugin": "^1.
|
|
55
|
-
"@opencode-ai/sdk": "^1.
|
|
53
|
+
"@modelcontextprotocol/sdk": "^1.26.0",
|
|
54
|
+
"@opencode-ai/plugin": "^1.2.6",
|
|
55
|
+
"@opencode-ai/sdk": "^1.2.6",
|
|
56
56
|
"vscode-jsonrpc": "^8.2.0",
|
|
57
57
|
"vscode-languageserver-protocol": "^3.17.5",
|
|
58
|
-
"zod": "^4.
|
|
58
|
+
"zod": "^4.3.6"
|
|
59
59
|
},
|
|
60
60
|
"devDependencies": {
|
|
61
|
-
"@biomejs/biome": "2.
|
|
62
|
-
"bun-types": "
|
|
63
|
-
"typescript": "^5.
|
|
61
|
+
"@biomejs/biome": "2.4.2",
|
|
62
|
+
"bun-types": "1.3.9",
|
|
63
|
+
"typescript": "^5.9.3"
|
|
64
64
|
},
|
|
65
65
|
"trustedDependencies": [
|
|
66
66
|
"@ast-grep/cli"
|