oh-my-opencode-slim 0.8.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/dist/cli/index.js CHANGED
@@ -80,11 +80,11 @@ function pickSupportChutesModel(models, primaryModel) {
80
80
  }
81
81
  // src/cli/config-io.ts
82
82
  import {
83
- copyFileSync,
84
- existsSync as existsSync2,
83
+ copyFileSync as copyFileSync2,
84
+ existsSync as existsSync3,
85
85
  readFileSync,
86
86
  renameSync,
87
- statSync,
87
+ statSync as statSync2,
88
88
  writeFileSync
89
89
  } from "fs";
90
90
 
@@ -13729,7 +13729,7 @@ var BackgroundTaskConfigSchema = exports_external.object({
13729
13729
  });
13730
13730
  var FailoverConfigSchema = exports_external.object({
13731
13731
  enabled: exports_external.boolean().default(true),
13732
- timeoutMs: exports_external.number().min(1000).max(120000).default(15000),
13732
+ timeoutMs: exports_external.number().min(0).default(15000),
13733
13733
  chains: FallbackChainsSchema.default({})
13734
13734
  });
13735
13735
  var PluginConfigSchema = exports_external.object({
@@ -13756,6 +13756,67 @@ var DEFAULT_AGENT_MCPS = {
13756
13756
 
13757
13757
  // src/cli/skills.ts
13758
13758
  import { spawnSync } from "child_process";
13759
+
13760
+ // src/cli/custom-skills.ts
13761
+ import {
13762
+ copyFileSync,
13763
+ existsSync as existsSync2,
13764
+ mkdirSync as mkdirSync2,
13765
+ readdirSync,
13766
+ statSync
13767
+ } from "fs";
13768
+ import { homedir as homedir2 } from "os";
13769
+ import { dirname, join as join2 } from "path";
13770
+ import { fileURLToPath } from "url";
13771
+ var CUSTOM_SKILLS = [
13772
+ {
13773
+ name: "cartography",
13774
+ description: "Repository understanding and hierarchical codemap generation",
13775
+ allowedAgents: ["orchestrator", "explorer"],
13776
+ sourcePath: "src/skills/cartography"
13777
+ }
13778
+ ];
13779
+ function getCustomSkillsDir() {
13780
+ return join2(homedir2(), ".config", "opencode", "skills");
13781
+ }
13782
+ function copyDirRecursive(src, dest) {
13783
+ if (!existsSync2(dest)) {
13784
+ mkdirSync2(dest, { recursive: true });
13785
+ }
13786
+ const entries = readdirSync(src);
13787
+ for (const entry of entries) {
13788
+ const srcPath = join2(src, entry);
13789
+ const destPath = join2(dest, entry);
13790
+ const stat = statSync(srcPath);
13791
+ if (stat.isDirectory()) {
13792
+ copyDirRecursive(srcPath, destPath);
13793
+ } else {
13794
+ const destDir = dirname(destPath);
13795
+ if (!existsSync2(destDir)) {
13796
+ mkdirSync2(destDir, { recursive: true });
13797
+ }
13798
+ copyFileSync(srcPath, destPath);
13799
+ }
13800
+ }
13801
+ }
13802
+ function installCustomSkill(skill) {
13803
+ try {
13804
+ const packageRoot = fileURLToPath(new URL("../..", import.meta.url));
13805
+ const sourcePath = join2(packageRoot, skill.sourcePath);
13806
+ const targetPath = join2(getCustomSkillsDir(), skill.name);
13807
+ if (!existsSync2(sourcePath)) {
13808
+ console.error(`Custom skill source not found: ${sourcePath}`);
13809
+ return false;
13810
+ }
13811
+ copyDirRecursive(sourcePath, targetPath);
13812
+ return true;
13813
+ } catch (error48) {
13814
+ console.error(`Failed to install custom skill: ${skill.name}`, error48);
13815
+ return false;
13816
+ }
13817
+ }
13818
+
13819
+ // src/cli/skills.ts
13759
13820
  var RECOMMENDED_SKILLS = [
13760
13821
  {
13761
13822
  name: "simplify",
@@ -13863,7 +13924,7 @@ var MODEL_MAPPINGS = {
13863
13924
  },
13864
13925
  antigravity: {
13865
13926
  orchestrator: { model: "google/antigravity-gemini-3-flash" },
13866
- oracle: { model: "google/antigravity-gemini-3-pro" },
13927
+ oracle: { model: "google/antigravity-gemini-3.1-pro" },
13867
13928
  librarian: {
13868
13929
  model: "google/antigravity-gemini-3-flash",
13869
13930
  variant: "low"
@@ -14203,9 +14264,9 @@ function stripJsonComments(json2) {
14203
14264
  }
14204
14265
  function parseConfigFile(path) {
14205
14266
  try {
14206
- if (!existsSync2(path))
14267
+ if (!existsSync3(path))
14207
14268
  return { config: null };
14208
- const stat = statSync(path);
14269
+ const stat = statSync2(path);
14209
14270
  if (stat.size === 0)
14210
14271
  return { config: null };
14211
14272
  const content = readFileSync(path, "utf-8");
@@ -14234,8 +14295,8 @@ function writeConfig(configPath, config2) {
14234
14295
  const bakPath = `${configPath}.bak`;
14235
14296
  const content = `${JSON.stringify(config2, null, 2)}
14236
14297
  `;
14237
- if (existsSync2(configPath)) {
14238
- copyFileSync(configPath, bakPath);
14298
+ if (existsSync3(configPath)) {
14299
+ copyFileSync2(configPath, bakPath);
14239
14300
  }
14240
14301
  writeFileSync(tmpPath, content);
14241
14302
  renameSync(tmpPath, configPath);
@@ -14284,8 +14345,8 @@ function writeLiteConfig(installConfig) {
14284
14345
  const bakPath = `${configPath}.bak`;
14285
14346
  const content = `${JSON.stringify(config2, null, 2)}
14286
14347
  `;
14287
- if (existsSync2(configPath)) {
14288
- copyFileSync(configPath, bakPath);
14348
+ if (existsSync3(configPath)) {
14349
+ copyFileSync2(configPath, bakPath);
14289
14350
  }
14290
14351
  writeFileSync(tmpPath, content);
14291
14352
  renameSync(tmpPath, configPath);
@@ -14368,8 +14429,8 @@ function addGoogleProvider() {
14368
14429
  const providers = config2.provider ?? {};
14369
14430
  providers.google = {
14370
14431
  models: {
14371
- "antigravity-gemini-3-pro": {
14372
- name: "Gemini 3 Pro (Antigravity)",
14432
+ "antigravity-gemini-3.1-pro": {
14433
+ name: "Gemini 3.1 Pro (Antigravity)",
14373
14434
  limit: { context: 1048576, output: 65535 },
14374
14435
  modalities: { input: ["text", "image", "pdf"], output: ["text"] },
14375
14436
  variants: {
@@ -14426,8 +14487,8 @@ function addGoogleProvider() {
14426
14487
  limit: { context: 1048576, output: 65536 },
14427
14488
  modalities: { input: ["text", "image", "pdf"], output: ["text"] }
14428
14489
  },
14429
- "gemini-3-pro-preview": {
14430
- name: "Gemini 3 Pro Preview (Gemini CLI)",
14490
+ "gemini-3.1-pro-preview": {
14491
+ name: "Gemini 3.1 Pro Preview (Gemini CLI)",
14431
14492
  limit: { context: 1048576, output: 65535 },
14432
14493
  modalities: { input: ["text", "image", "pdf"], output: ["text"] }
14433
14494
  }
@@ -15751,7 +15812,7 @@ async function fetchExternalModelSignals(options) {
15751
15812
  return { signals: aggregate, warnings };
15752
15813
  }
15753
15814
  // src/cli/system.ts
15754
- import { statSync as statSync2 } from "fs";
15815
+ import { statSync as statSync3 } from "fs";
15755
15816
  var cachedOpenCodePath = null;
15756
15817
  function getOpenCodePaths() {
15757
15818
  const home = process.env.HOME || process.env.USERPROFILE || "";
@@ -15793,7 +15854,7 @@ function resolveOpenCodePath() {
15793
15854
  if (opencodePath === "opencode")
15794
15855
  continue;
15795
15856
  try {
15796
- const stat = statSync2(opencodePath);
15857
+ const stat = statSync3(opencodePath);
15797
15858
  if (stat.isFile()) {
15798
15859
  cachedOpenCodePath = opencodePath;
15799
15860
  return opencodePath;
@@ -16023,65 +16084,6 @@ function pickSupportOpenCodeModel(models, primaryModel) {
16023
16084
  }, primaryModel);
16024
16085
  return support;
16025
16086
  }
16026
- // src/cli/custom-skills.ts
16027
- import {
16028
- copyFileSync as copyFileSync2,
16029
- existsSync as existsSync3,
16030
- mkdirSync as mkdirSync2,
16031
- readdirSync,
16032
- statSync as statSync3
16033
- } from "fs";
16034
- import { homedir as homedir2 } from "os";
16035
- import { dirname, join as join3 } from "path";
16036
- import { fileURLToPath } from "url";
16037
- var CUSTOM_SKILLS = [
16038
- {
16039
- name: "cartography",
16040
- description: "Repository understanding and hierarchical codemap generation",
16041
- allowedAgents: ["orchestrator"],
16042
- sourcePath: "src/skills/cartography"
16043
- }
16044
- ];
16045
- function getCustomSkillsDir() {
16046
- return join3(homedir2(), ".config", "opencode", "skills");
16047
- }
16048
- function copyDirRecursive(src, dest) {
16049
- if (!existsSync3(dest)) {
16050
- mkdirSync2(dest, { recursive: true });
16051
- }
16052
- const entries = readdirSync(src);
16053
- for (const entry of entries) {
16054
- const srcPath = join3(src, entry);
16055
- const destPath = join3(dest, entry);
16056
- const stat = statSync3(srcPath);
16057
- if (stat.isDirectory()) {
16058
- copyDirRecursive(srcPath, destPath);
16059
- } else {
16060
- const destDir = dirname(destPath);
16061
- if (!existsSync3(destDir)) {
16062
- mkdirSync2(destDir, { recursive: true });
16063
- }
16064
- copyFileSync2(srcPath, destPath);
16065
- }
16066
- }
16067
- }
16068
- function installCustomSkill(skill) {
16069
- try {
16070
- const packageRoot = fileURLToPath(new URL("../..", import.meta.url));
16071
- const sourcePath = join3(packageRoot, skill.sourcePath);
16072
- const targetPath = join3(getCustomSkillsDir(), skill.name);
16073
- if (!existsSync3(sourcePath)) {
16074
- console.error(`Custom skill source not found: ${sourcePath}`);
16075
- return false;
16076
- }
16077
- copyDirRecursive(sourcePath, targetPath);
16078
- return true;
16079
- } catch (error48) {
16080
- console.error(`Failed to install custom skill: ${skill.name}`, error48);
16081
- return false;
16082
- }
16083
- }
16084
-
16085
16087
  // src/cli/install.ts
16086
16088
  var GREEN = "\x1B[32m";
16087
16089
  var BLUE = "\x1B[34m";
@@ -16430,8 +16432,8 @@ async function runManualSetupMode(rl, detected, modelsOnly = false) {
16430
16432
  }
16431
16433
  if (antigravity === "yes") {
16432
16434
  availableModels.push({
16433
- model: "google/antigravity-gemini-3-pro",
16434
- name: "Gemini 3 Pro"
16435
+ model: "google/antigravity-gemini-3.1-pro",
16436
+ name: "Gemini 3.1 Pro"
16435
16437
  });
16436
16438
  availableModels.push({
16437
16439
  model: "google/antigravity-gemini-3-flash",
@@ -130,7 +130,7 @@ export declare const MODEL_MAPPINGS: {
130
130
  readonly model: "google/antigravity-gemini-3-flash";
131
131
  };
132
132
  readonly oracle: {
133
- readonly model: "google/antigravity-gemini-3-pro";
133
+ readonly model: "google/antigravity-gemini-3.1-pro";
134
134
  };
135
135
  readonly librarian: {
136
136
  readonly model: "google/antigravity-gemini-3-flash";
@@ -15,11 +15,28 @@ export interface RecommendedSkill {
15
15
  /** Optional commands to run after the skill is added */
16
16
  postInstallCommands?: string[];
17
17
  }
18
+ /**
19
+ * A skill that is managed externally (e.g. user-installed) and needs
20
+ * permission grants but is NOT installed by this plugin's CLI.
21
+ */
22
+ export interface PermissionOnlySkill {
23
+ /** Skill name — must match the name OpenCode uses for permission checks */
24
+ name: string;
25
+ /** List of agents that should auto-allow this skill */
26
+ allowedAgents: string[];
27
+ /** Human-readable description (for documentation only) */
28
+ description: string;
29
+ }
18
30
  /**
19
31
  * List of recommended skills.
20
32
  * Add new skills here to include them in the installation flow.
21
33
  */
22
34
  export declare const RECOMMENDED_SKILLS: RecommendedSkill[];
35
+ /**
36
+ * Skills managed externally (not installed by this plugin's CLI).
37
+ * Entries here only affect agent permission grants — nothing is installed.
38
+ */
39
+ export declare const PERMISSION_ONLY_SKILLS: PermissionOnlySkill[];
23
40
  /**
24
41
  * Install a skill using `npx skills add`.
25
42
  * @param skill - The skill to install
@@ -0,0 +1,43 @@
1
+ import type { PluginInput } from '@opencode-ai/plugin';
2
+ import type { PluginConfig } from '../../config';
3
+ declare const AUTOPILOT_CONTINUE_PROMPT = "[AUTOPILOT] Continue executing work in this same session now. Do not acknowledge autopilot, do not ask for confirmation, and do not stop after a status message. Perform the next concrete action immediately (run a tool/command, edit files, or advance the active todo). Only stop when all todos are completed/cancelled or the user explicitly disables autopilot.";
4
+ interface MessagePart {
5
+ type: string;
6
+ text?: string;
7
+ }
8
+ interface TodoEntry {
9
+ status?: string;
10
+ }
11
+ type AutopilotCommand = 'enable' | 'disable' | 'status' | null;
12
+ declare function parseAutopilotCommand(text: string, keyword: string, disableKeyword: string): AutopilotCommand;
13
+ declare function extractTodoList(data: unknown): TodoEntry[];
14
+ declare function isActiveTodo(todo: TodoEntry): boolean;
15
+ export declare function createAutopilotHook(ctx: PluginInput, config: PluginConfig): {
16
+ 'chat.message': (input: {
17
+ sessionID: string;
18
+ agent?: string;
19
+ messageID?: string;
20
+ }, output: {
21
+ parts: MessagePart[];
22
+ }) => Promise<void>;
23
+ event: (input: {
24
+ event: {
25
+ type: string;
26
+ properties?: {
27
+ sessionID?: string;
28
+ status?: {
29
+ type?: string;
30
+ };
31
+ info?: {
32
+ id?: string;
33
+ role?: string;
34
+ sessionID?: string;
35
+ time?: {
36
+ completed?: number;
37
+ };
38
+ };
39
+ };
40
+ };
41
+ }) => Promise<void>;
42
+ };
43
+ export { AUTOPILOT_CONTINUE_PROMPT, extractTodoList, isActiveTodo, parseAutopilotCommand, };
@@ -0,0 +1,2 @@
1
+ import { type DetectedError } from './patterns';
2
+ export declare function buildRetryGuidance(errorInfo: DetectedError): string;
@@ -0,0 +1,8 @@
1
+ import type { PluginInput } from '@opencode-ai/plugin';
2
+ export declare function createDelegateTaskRetryHook(_ctx: PluginInput): {
3
+ 'tool.execute.after': (input: {
4
+ tool: string;
5
+ }, output: {
6
+ output: unknown;
7
+ }) => Promise<void>;
8
+ };
@@ -0,0 +1,4 @@
1
+ export type { DelegateTaskErrorPattern, DetectedError } from './patterns';
2
+ export { DELEGATE_TASK_ERROR_PATTERNS, detectDelegateTaskError } from './patterns';
3
+ export { buildRetryGuidance } from './guidance';
4
+ export { createDelegateTaskRetryHook } from './hook';
@@ -0,0 +1,11 @@
1
+ export interface DelegateTaskErrorPattern {
2
+ pattern: string;
3
+ errorType: string;
4
+ fixHint: string;
5
+ }
6
+ export declare const DELEGATE_TASK_ERROR_PATTERNS: DelegateTaskErrorPattern[];
7
+ export interface DetectedError {
8
+ errorType: string;
9
+ originalOutput: string;
10
+ }
11
+ export declare function detectDelegateTaskError(output: string): DetectedError | null;
@@ -1,4 +1,6 @@
1
1
  export type { AutoUpdateCheckerOptions } from './auto-update-checker';
2
2
  export { createAutoUpdateCheckerHook } from './auto-update-checker';
3
+ export { createDelegateTaskRetryHook } from './delegate-task-retry';
4
+ export { createJsonErrorRecoveryHook } from './json-error-recovery';
3
5
  export { createPhaseReminderHook } from './phase-reminder';
4
6
  export { createPostReadNudgeHook } from './post-read-nudge';
@@ -0,0 +1,18 @@
1
+ import type { PluginInput } from '@opencode-ai/plugin';
2
+ export declare const JSON_ERROR_TOOL_EXCLUDE_LIST: readonly ["bash", "read", "glob", "grep", "webfetch", "grep_app_searchgithub", "websearch_web_search_exa"];
3
+ export declare const JSON_ERROR_PATTERNS: readonly [RegExp, RegExp, RegExp, RegExp, RegExp, RegExp, RegExp, RegExp];
4
+ export declare const JSON_ERROR_REMINDER = "\n[JSON PARSE ERROR - IMMEDIATE ACTION REQUIRED]\n\nYou sent invalid JSON arguments. The system could not parse your tool call.\nSTOP and do this NOW:\n\n1. LOOK at the error message above to see what was expected vs what you sent.\n2. CORRECT your JSON syntax (missing braces, unescaped quotes, trailing commas, etc).\n3. RETRY the tool call with valid JSON.\n\nDO NOT repeat the exact same invalid call.\n";
5
+ interface ToolExecuteAfterInput {
6
+ tool: string;
7
+ sessionID: string;
8
+ callID: string;
9
+ }
10
+ interface ToolExecuteAfterOutput {
11
+ title: string;
12
+ output: unknown;
13
+ metadata: unknown;
14
+ }
15
+ export declare function createJsonErrorRecoveryHook(_ctx: PluginInput): {
16
+ 'tool.execute.after': (input: ToolExecuteAfterInput, output: ToolExecuteAfterOutput) => Promise<void>;
17
+ };
18
+ export {};
@@ -0,0 +1 @@
1
+ export { createJsonErrorRecoveryHook, JSON_ERROR_PATTERNS, JSON_ERROR_REMINDER, JSON_ERROR_TOOL_EXCLUDE_LIST, } from './hook';
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
 
@@ -3340,8 +3369,8 @@ var ORCHESTRATOR_NAME = "orchestrator";
3340
3369
  var ALL_AGENT_NAMES = [ORCHESTRATOR_NAME, ...SUBAGENT_NAMES];
3341
3370
  var SUBAGENT_DELEGATION_RULES = {
3342
3371
  orchestrator: SUBAGENT_NAMES,
3343
- fixer: ["explorer"],
3344
- designer: ["explorer"],
3372
+ fixer: [],
3373
+ designer: [],
3345
3374
  explorer: [],
3346
3375
  librarian: [],
3347
3376
  oracle: []
@@ -17010,7 +17039,7 @@ var BackgroundTaskConfigSchema = exports_external.object({
17010
17039
  });
17011
17040
  var FailoverConfigSchema = exports_external.object({
17012
17041
  enabled: exports_external.boolean().default(true),
17013
- timeoutMs: exports_external.number().min(1000).max(120000).default(15000),
17042
+ timeoutMs: exports_external.number().min(0).default(15000),
17014
17043
  chains: FallbackChainsSchema.default({})
17015
17044
  });
17016
17045
  var PluginConfigSchema = exports_external.object({
@@ -17280,9 +17309,10 @@ var FIXER_PROMPT = `You are Fixer - a fast, focused implementation specialist.
17280
17309
 
17281
17310
  **Constraints**:
17282
17311
  - NO external research (no websearch, context7, grep_app)
17283
- - NO delegation (no background_task)
17312
+ - NO delegation (no background_task, no spawning subagents)
17284
17313
  - No multi-step research/planning; minimal execution sequence ok
17285
- - If context is insufficient, read the files listed; only ask for missing inputs you cannot retrieve
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
17286
17316
 
17287
17317
  **Output Format**:
17288
17318
  <summary>
@@ -17504,6 +17534,10 @@ Balance: respect dependencies, avoid parallelizing what must be sequential.
17504
17534
  - Confirm specialists completed successfully
17505
17535
  - Verify solution meets requirements
17506
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
+
17507
17541
  </Workflow>
17508
17542
 
17509
17543
  <Communication>
@@ -18094,6 +18128,10 @@ class BackgroundTaskManager {
18094
18128
  return chain;
18095
18129
  }
18096
18130
  async promptWithTimeout(args, timeoutMs) {
18131
+ if (timeoutMs <= 0) {
18132
+ await this.client.session.prompt(args);
18133
+ return;
18134
+ }
18097
18135
  await Promise.race([
18098
18136
  this.client.session.prompt(args),
18099
18137
  new Promise((_, reject) => {
@@ -18143,8 +18181,8 @@ class BackgroundTaskManager {
18143
18181
  tools: toolPermissions,
18144
18182
  parts: [{ type: "text", text: task.prompt }]
18145
18183
  });
18146
- const timeoutMs = this.config?.fallback?.timeoutMs ?? FALLBACK_FAILOVER_TIMEOUT_MS;
18147
18184
  const fallbackEnabled = this.config?.fallback?.enabled ?? true;
18185
+ const timeoutMs = fallbackEnabled ? this.config?.fallback?.timeoutMs ?? FALLBACK_FAILOVER_TIMEOUT_MS : 0;
18148
18186
  const chain = fallbackEnabled ? this.resolveFallbackChain(task.agent) : [];
18149
18187
  const attemptModels = chain.length > 0 ? chain : [undefined];
18150
18188
  const errors3 = [];
@@ -18933,10 +18971,169 @@ function showToast(ctx, title, message, variant = "info", duration3 = 3000) {
18933
18971
  body: { title, message, variant, duration: duration3 }
18934
18972
  }).catch(() => {});
18935
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
+ }
18936
19133
  // src/hooks/phase-reminder/index.ts
18937
- var PHASE_REMINDER = `<reminder>\u26A0\uFE0F MANDATORY: Understand\u2192DELEGATE(! based on each agent rules)\u2192Split-and-Parallelize(?)\u2192Plan\u2192Execute\u2192Verify
18938
- Available Specialist: @oracle @librarian @explorer @designer @fixer
18939
- </reminder>`;
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>`;
18940
19137
  function createPhaseReminderHook() {
18941
19138
  return {
18942
19139
  "experimental.chat.messages.transform": async (_input, output) => {
@@ -18976,7 +19173,7 @@ ${originalText}`;
18976
19173
  var NUDGE = `
18977
19174
 
18978
19175
  ---
18979
- Reminder to follow the workflow instructions, consider delegation to specialist(s)`;
19176
+ Workflow Reminder: delegate based on rules; If mentioning a specialist, launch it in this same turn.`;
18980
19177
  function createPostReadNudgeHook() {
18981
19178
  return {
18982
19179
  "tool.execute.after": async (input, output) => {
@@ -33242,6 +33439,8 @@ var OhMyOpenCodeLite = async (ctx) => {
33242
33439
  });
33243
33440
  const phaseReminderHook = createPhaseReminderHook();
33244
33441
  const postReadNudgeHook = createPostReadNudgeHook();
33442
+ const delegateTaskRetryHook = createDelegateTaskRetryHook(ctx);
33443
+ const jsonErrorRecoveryHook = createJsonErrorRecoveryHook(ctx);
33245
33444
  return {
33246
33445
  name: "oh-my-opencode-slim",
33247
33446
  agent: agents,
@@ -33301,7 +33500,11 @@ var OhMyOpenCodeLite = async (ctx) => {
33301
33500
  await tmuxSessionManager.onSessionDeleted(input.event);
33302
33501
  },
33303
33502
  "experimental.chat.messages.transform": phaseReminderHook["experimental.chat.messages.transform"],
33304
- "tool.execute.after": postReadNudgeHook["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
+ }
33305
33508
  };
33306
33509
  };
33307
33510
  var src_default = OhMyOpenCodeLite;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "oh-my-opencode-slim",
3
- "version": "0.8.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",
@@ -1,5 +0,0 @@
1
- import type { Account, AccountQuotaResult, AccountsConfig } from './types';
2
- export declare const CONFIG_PATHS: string[];
3
- export declare function loadAccountsConfig(): AccountsConfig | null;
4
- export declare function fetchAccountQuota(account: Account): Promise<AccountQuotaResult>;
5
- export declare function fetchAllQuotas(accounts: Account[]): Promise<AccountQuotaResult[]>;
@@ -1 +0,0 @@
1
- export {};
@@ -1,21 +0,0 @@
1
- /**
2
- * Compact quota display tool - groups models by quota family
3
- *
4
- * Output format:
5
- * ```
6
- * tornikevault
7
- * Claude [░░░░░░░░░░] 0% 3h23m
8
- * G-Flash [██████████] 100% 4h59m
9
- * G-Pro [██████████] 100% 4h59m
10
- *
11
- * tzedgin
12
- * Claude [░░░░░░░░░░] 0% 1h41m
13
- * G-Flash [██████████] 100% 4h59m
14
- * G-Pro [██████████] 100% 4h59m
15
- * ```
16
- */
17
- export declare const antigravity_quota: {
18
- description: string;
19
- args: {};
20
- execute(args: Record<string, never>, context: import("@opencode-ai/plugin").ToolContext): Promise<string>;
21
- };
@@ -1,41 +0,0 @@
1
- export interface Account {
2
- email: string;
3
- refreshToken: string;
4
- projectId?: string;
5
- managedProjectId?: string;
6
- rateLimitResetTimes: Record<string, number>;
7
- }
8
- export interface AccountsConfig {
9
- accounts: Account[];
10
- activeIndex: number;
11
- }
12
- export interface QuotaInfo {
13
- remainingFraction?: number;
14
- resetTime?: string;
15
- }
16
- export interface ModelInfo {
17
- displayName?: string;
18
- model?: string;
19
- quotaInfo?: QuotaInfo;
20
- recommended?: boolean;
21
- }
22
- export interface QuotaResponse {
23
- models?: Record<string, ModelInfo>;
24
- }
25
- export interface TokenResponse {
26
- access_token: string;
27
- }
28
- export interface LoadCodeAssistResponse {
29
- cloudaicompanionProject?: unknown;
30
- }
31
- export interface ModelQuota {
32
- name: string;
33
- percent: number;
34
- resetIn: string;
35
- }
36
- export interface AccountQuotaResult {
37
- email: string;
38
- success: boolean;
39
- error?: string;
40
- models: ModelQuota[];
41
- }