oh-my-opencode 1.1.2 → 1.1.4

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.
@@ -0,0 +1 @@
1
+ export declare const BUILD_AGENT_PROMPT_EXTENSION = "\n# Agent Orchestration & Task Management\n\nYou are not just a coder - you are an **ORCHESTRATOR**. Your primary job is to delegate work to specialized agents and track progress obsessively.\n\n## Think Before Acting\n\nWhen you receive a user request, STOP and think deeply:\n\n1. **What specialized agents can handle this better than me?**\n - explore: File search, codebase navigation, pattern matching\n - librarian: Documentation lookup, API references, implementation examples\n - oracle: Architecture decisions, code review, complex logic analysis\n - frontend-ui-ux-engineer: UI/UX implementation, component design\n - document-writer: Documentation, README, technical writing\n\n2. **Can I parallelize this work?**\n - Fire multiple background_task calls simultaneously\n - Continue working on other parts while agents investigate\n - Aggregate results when notified\n\n3. **Have I planned this in my TODO list?**\n - Break down the task into atomic steps FIRST\n - Track every investigation, every delegation\n\n## TODO Tool Obsession\n\n**USE TODO TOOLS AGGRESSIVELY.** This is non-negotiable.\n\n### When to Use TodoWrite:\n- IMMEDIATELY after receiving a user request\n- Before ANY multi-step task (even if it seems \"simple\")\n- When delegating to agents (track what you delegated)\n- After completing each step (mark it done)\n\n### TODO Workflow:\n```\nUser Request \u2192 TodoWrite (plan) \u2192 Mark in_progress \u2192 Execute/Delegate \u2192 Mark complete \u2192 Next\n```\n\n### Rules:\n- Only ONE task in_progress at a time\n- Mark complete IMMEDIATELY after finishing (never batch)\n- Never proceed without updating TODO status\n\n## Delegation Pattern\n\n```typescript\n// 1. PLAN with TODO first\ntodowrite([\n { id: \"research\", content: \"Research X implementation\", status: \"in_progress\", priority: \"high\" },\n { id: \"impl\", content: \"Implement X feature\", status: \"pending\", priority: \"high\" },\n { id: \"test\", content: \"Test X feature\", status: \"pending\", priority: \"medium\" }\n])\n\n// 2. DELEGATE research in parallel\nbackground_task(agent=\"explore\", prompt=\"Find all files related to X\")\nbackground_task(agent=\"librarian\", prompt=\"Look up X documentation\")\n\n// 3. CONTINUE working on implementation skeleton while agents research\n// 4. When notified, INTEGRATE findings and mark TODO complete\n```\n\n## Anti-Patterns (AVOID):\n- Doing everything yourself when agents can help\n- Skipping TODO planning for \"quick\" tasks\n- Forgetting to mark tasks complete\n- Sequential execution when parallel is possible\n- Direct tool calls without considering delegation\n\n## Remember:\n- You are the **team lead**, not the grunt worker\n- Your context window is precious - delegate to preserve it\n- Agents have specialized expertise - USE THEM\n- TODO tracking gives users visibility into your progress\n- Parallel execution = faster results\n";
@@ -2,3 +2,4 @@ import type { AgentConfig } from "@opencode-ai/sdk";
2
2
  export declare const builtinAgents: Record<string, AgentConfig>;
3
3
  export * from "./types";
4
4
  export { createBuiltinAgents } from "./utils";
5
+ export { BUILD_AGENT_PROMPT_EXTENSION } from "./build";
@@ -1,4 +1,6 @@
1
1
  import type { AgentConfig } from "@opencode-ai/sdk";
2
- export type AgentName = "oracle" | "librarian" | "explore" | "frontend-ui-ux-engineer" | "document-writer" | "multimodal-looker";
2
+ export type BuiltinAgentName = "oracle" | "librarian" | "explore" | "frontend-ui-ux-engineer" | "document-writer" | "multimodal-looker";
3
+ export type OverridableAgentName = "build" | BuiltinAgentName;
4
+ export type AgentName = BuiltinAgentName;
3
5
  export type AgentOverrideConfig = Partial<AgentConfig>;
4
- export type AgentOverrides = Partial<Record<AgentName, AgentOverrideConfig>>;
6
+ export type AgentOverrides = Partial<Record<OverridableAgentName, AgentOverrideConfig>>;
@@ -1,3 +1,3 @@
1
1
  import type { AgentConfig } from "@opencode-ai/sdk";
2
- import type { AgentName, AgentOverrides } from "./types";
3
- export declare function createBuiltinAgents(disabledAgents?: AgentName[], agentOverrides?: AgentOverrides): Record<string, AgentConfig>;
2
+ import type { BuiltinAgentName, AgentOverrides } from "./types";
3
+ export declare function createBuiltinAgents(disabledAgents?: BuiltinAgentName[], agentOverrides?: AgentOverrides): Record<string, AgentConfig>;
@@ -1,4 +1,21 @@
1
1
  import { z } from "zod";
2
+ export declare const BuiltinAgentNameSchema: z.ZodEnum<{
3
+ oracle: "oracle";
4
+ librarian: "librarian";
5
+ explore: "explore";
6
+ "frontend-ui-ux-engineer": "frontend-ui-ux-engineer";
7
+ "document-writer": "document-writer";
8
+ "multimodal-looker": "multimodal-looker";
9
+ }>;
10
+ export declare const OverridableAgentNameSchema: z.ZodEnum<{
11
+ oracle: "oracle";
12
+ librarian: "librarian";
13
+ explore: "explore";
14
+ "frontend-ui-ux-engineer": "frontend-ui-ux-engineer";
15
+ "document-writer": "document-writer";
16
+ "multimodal-looker": "multimodal-looker";
17
+ build: "build";
18
+ }>;
2
19
  export declare const AgentNameSchema: z.ZodEnum<{
3
20
  oracle: "oracle";
4
21
  librarian: "librarian";
@@ -10,6 +27,7 @@ export declare const AgentNameSchema: z.ZodEnum<{
10
27
  export declare const HookNameSchema: z.ZodEnum<{
11
28
  "comment-checker": "comment-checker";
12
29
  "rules-injector": "rules-injector";
30
+ "agent-usage-reminder": "agent-usage-reminder";
13
31
  "todo-continuation-enforcer": "todo-continuation-enforcer";
14
32
  "context-window-monitor": "context-window-monitor";
15
33
  "session-recovery": "session-recovery";
@@ -71,6 +89,52 @@ export declare const AgentOverrideConfigSchema: z.ZodObject<{
71
89
  }, z.core.$strip>>;
72
90
  }, z.core.$strip>;
73
91
  export declare const AgentOverridesSchema: z.ZodObject<{
92
+ build: z.ZodOptional<z.ZodOptional<z.ZodObject<{
93
+ model: z.ZodOptional<z.ZodString>;
94
+ temperature: z.ZodOptional<z.ZodNumber>;
95
+ top_p: z.ZodOptional<z.ZodNumber>;
96
+ prompt: z.ZodOptional<z.ZodString>;
97
+ tools: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodBoolean>>;
98
+ disable: z.ZodOptional<z.ZodBoolean>;
99
+ description: z.ZodOptional<z.ZodString>;
100
+ mode: z.ZodOptional<z.ZodEnum<{
101
+ subagent: "subagent";
102
+ primary: "primary";
103
+ all: "all";
104
+ }>>;
105
+ color: z.ZodOptional<z.ZodString>;
106
+ permission: z.ZodOptional<z.ZodObject<{
107
+ edit: z.ZodOptional<z.ZodEnum<{
108
+ allow: "allow";
109
+ deny: "deny";
110
+ ask: "ask";
111
+ }>>;
112
+ bash: z.ZodOptional<z.ZodUnion<readonly [z.ZodEnum<{
113
+ allow: "allow";
114
+ deny: "deny";
115
+ ask: "ask";
116
+ }>, z.ZodRecord<z.ZodString, z.ZodEnum<{
117
+ allow: "allow";
118
+ deny: "deny";
119
+ ask: "ask";
120
+ }>>]>>;
121
+ webfetch: z.ZodOptional<z.ZodEnum<{
122
+ allow: "allow";
123
+ deny: "deny";
124
+ ask: "ask";
125
+ }>>;
126
+ doom_loop: z.ZodOptional<z.ZodEnum<{
127
+ allow: "allow";
128
+ deny: "deny";
129
+ ask: "ask";
130
+ }>>;
131
+ external_directory: z.ZodOptional<z.ZodEnum<{
132
+ allow: "allow";
133
+ deny: "deny";
134
+ ask: "ask";
135
+ }>>;
136
+ }, z.core.$strip>>;
137
+ }, z.core.$strip>>>;
74
138
  oracle: z.ZodOptional<z.ZodOptional<z.ZodObject<{
75
139
  model: z.ZodOptional<z.ZodString>;
76
140
  temperature: z.ZodOptional<z.ZodNumber>;
@@ -373,6 +437,7 @@ export declare const OhMyOpenCodeConfigSchema: z.ZodObject<{
373
437
  disabled_hooks: z.ZodOptional<z.ZodArray<z.ZodEnum<{
374
438
  "comment-checker": "comment-checker";
375
439
  "rules-injector": "rules-injector";
440
+ "agent-usage-reminder": "agent-usage-reminder";
376
441
  "todo-continuation-enforcer": "todo-continuation-enforcer";
377
442
  "context-window-monitor": "context-window-monitor";
378
443
  "session-recovery": "session-recovery";
@@ -388,6 +453,52 @@ export declare const OhMyOpenCodeConfigSchema: z.ZodObject<{
388
453
  "ultrawork-mode": "ultrawork-mode";
389
454
  }>>>;
390
455
  agents: z.ZodOptional<z.ZodObject<{
456
+ build: z.ZodOptional<z.ZodOptional<z.ZodObject<{
457
+ model: z.ZodOptional<z.ZodString>;
458
+ temperature: z.ZodOptional<z.ZodNumber>;
459
+ top_p: z.ZodOptional<z.ZodNumber>;
460
+ prompt: z.ZodOptional<z.ZodString>;
461
+ tools: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodBoolean>>;
462
+ disable: z.ZodOptional<z.ZodBoolean>;
463
+ description: z.ZodOptional<z.ZodString>;
464
+ mode: z.ZodOptional<z.ZodEnum<{
465
+ subagent: "subagent";
466
+ primary: "primary";
467
+ all: "all";
468
+ }>>;
469
+ color: z.ZodOptional<z.ZodString>;
470
+ permission: z.ZodOptional<z.ZodObject<{
471
+ edit: z.ZodOptional<z.ZodEnum<{
472
+ allow: "allow";
473
+ deny: "deny";
474
+ ask: "ask";
475
+ }>>;
476
+ bash: z.ZodOptional<z.ZodUnion<readonly [z.ZodEnum<{
477
+ allow: "allow";
478
+ deny: "deny";
479
+ ask: "ask";
480
+ }>, z.ZodRecord<z.ZodString, z.ZodEnum<{
481
+ allow: "allow";
482
+ deny: "deny";
483
+ ask: "ask";
484
+ }>>]>>;
485
+ webfetch: z.ZodOptional<z.ZodEnum<{
486
+ allow: "allow";
487
+ deny: "deny";
488
+ ask: "ask";
489
+ }>>;
490
+ doom_loop: z.ZodOptional<z.ZodEnum<{
491
+ allow: "allow";
492
+ deny: "deny";
493
+ ask: "ask";
494
+ }>>;
495
+ external_directory: z.ZodOptional<z.ZodEnum<{
496
+ allow: "allow";
497
+ deny: "deny";
498
+ ask: "ask";
499
+ }>>;
500
+ }, z.core.$strip>>;
501
+ }, z.core.$strip>>>;
391
502
  oracle: z.ZodOptional<z.ZodOptional<z.ZodObject<{
392
503
  model: z.ZodOptional<z.ZodString>;
393
504
  temperature: z.ZodOptional<z.ZodNumber>;
@@ -0,0 +1,5 @@
1
+ export declare const OPENCODE_STORAGE: string;
2
+ export declare const AGENT_USAGE_REMINDER_STORAGE: string;
3
+ export declare const TARGET_TOOLS: Set<string>;
4
+ export declare const AGENT_TOOLS: Set<string>;
5
+ export declare const REMINDER_MESSAGE = "\n[Agent Usage Reminder]\n\nYou called a search/fetch tool directly without leveraging specialized agents.\n\nRECOMMENDED: Use background_task with explore/librarian agents for better results:\n\n```\n// Parallel exploration - fire multiple agents simultaneously\nbackground_task(agent=\"explore\", prompt=\"Find all files matching pattern X\")\nbackground_task(agent=\"explore\", prompt=\"Search for implementation of Y\") \nbackground_task(agent=\"librarian\", prompt=\"Lookup documentation for Z\")\n\n// Then continue your work while they run in background\n// System will notify you when each completes\n```\n\nWHY:\n- Agents can perform deeper, more thorough searches\n- Background tasks run in parallel, saving time\n- Specialized agents have domain expertise\n- Reduces context window usage in main session\n\nALWAYS prefer: Multiple parallel background_task calls > Direct tool calls\n";
@@ -0,0 +1,22 @@
1
+ import type { PluginInput } from "@opencode-ai/plugin";
2
+ interface ToolExecuteInput {
3
+ tool: string;
4
+ sessionID: string;
5
+ callID: string;
6
+ }
7
+ interface ToolExecuteOutput {
8
+ title: string;
9
+ output: string;
10
+ metadata: unknown;
11
+ }
12
+ interface EventInput {
13
+ event: {
14
+ type: string;
15
+ properties?: unknown;
16
+ };
17
+ }
18
+ export declare function createAgentUsageReminderHook(_ctx: PluginInput): {
19
+ "tool.execute.after": (input: ToolExecuteInput, output: ToolExecuteOutput) => Promise<void>;
20
+ event: ({ event }: EventInput) => Promise<void>;
21
+ };
22
+ export {};
@@ -0,0 +1,4 @@
1
+ import type { AgentUsageState } from "./types";
2
+ export declare function loadAgentUsageState(sessionID: string): AgentUsageState | null;
3
+ export declare function saveAgentUsageState(state: AgentUsageState): void;
4
+ export declare function clearAgentUsageState(sessionID: string): void;
@@ -0,0 +1,6 @@
1
+ export interface AgentUsageState {
2
+ sessionID: string;
3
+ agentUsed: boolean;
4
+ reminderCount: number;
5
+ updatedAt: number;
6
+ }
@@ -14,3 +14,4 @@ export { createRulesInjectorHook } from "./rules-injector";
14
14
  export { createBackgroundNotificationHook } from "./background-notification";
15
15
  export { createAutoUpdateCheckerHook } from "./auto-update-checker";
16
16
  export { createUltraworkModeHook } from "./ultrawork-mode";
17
+ export { createAgentUsageReminderHook } from "./agent-usage-reminder";
package/dist/index.js CHANGED
@@ -1482,7 +1482,7 @@ var oracleAgent = {
1482
1482
  temperature: 0.1,
1483
1483
  reasoningEffort: "medium",
1484
1484
  textVerbosity: "high",
1485
- tools: { write: false, edit: false },
1485
+ tools: { write: false, edit: false, read: true, call_omo_agent: true },
1486
1486
  prompt: `You are the Oracle - an expert AI advisor with advanced reasoning capabilities.
1487
1487
 
1488
1488
  Your role is to provide high-quality technical guidance, code reviews, architectural advice, and strategic planning for software engineering tasks.
@@ -1536,7 +1536,7 @@ var librarianAgent = {
1536
1536
  mode: "subagent",
1537
1537
  model: "anthropic/claude-sonnet-4-5",
1538
1538
  temperature: 0.1,
1539
- tools: { write: false, edit: false },
1539
+ tools: { write: false, edit: false, bash: true, read: true },
1540
1540
  prompt: `# THE LIBRARIAN
1541
1541
 
1542
1542
  You are **THE LIBRARIAN**, a specialized codebase understanding agent that helps users answer questions about large, complex codebases across repositories.
@@ -1864,7 +1864,7 @@ var exploreAgent = {
1864
1864
  mode: "subagent",
1865
1865
  model: "opencode/grok-code",
1866
1866
  temperature: 0.1,
1867
- tools: { write: false, edit: false },
1867
+ tools: { write: false, edit: false, bash: true, read: true },
1868
1868
  prompt: `You are a file search specialist. You excel at thoroughly navigating and exploring codebases.
1869
1869
 
1870
1870
  === CRITICAL: READ-ONLY MODE - NO FILE MODIFICATIONS ===
@@ -2826,6 +2826,84 @@ function createBuiltinAgents(disabledAgents = [], agentOverrides = {}) {
2826
2826
  }
2827
2827
  return result;
2828
2828
  }
2829
+ // src/agents/build.ts
2830
+ var BUILD_AGENT_PROMPT_EXTENSION = `
2831
+ # Agent Orchestration & Task Management
2832
+
2833
+ You are not just a coder - you are an **ORCHESTRATOR**. Your primary job is to delegate work to specialized agents and track progress obsessively.
2834
+
2835
+ ## Think Before Acting
2836
+
2837
+ When you receive a user request, STOP and think deeply:
2838
+
2839
+ 1. **What specialized agents can handle this better than me?**
2840
+ - explore: File search, codebase navigation, pattern matching
2841
+ - librarian: Documentation lookup, API references, implementation examples
2842
+ - oracle: Architecture decisions, code review, complex logic analysis
2843
+ - frontend-ui-ux-engineer: UI/UX implementation, component design
2844
+ - document-writer: Documentation, README, technical writing
2845
+
2846
+ 2. **Can I parallelize this work?**
2847
+ - Fire multiple background_task calls simultaneously
2848
+ - Continue working on other parts while agents investigate
2849
+ - Aggregate results when notified
2850
+
2851
+ 3. **Have I planned this in my TODO list?**
2852
+ - Break down the task into atomic steps FIRST
2853
+ - Track every investigation, every delegation
2854
+
2855
+ ## TODO Tool Obsession
2856
+
2857
+ **USE TODO TOOLS AGGRESSIVELY.** This is non-negotiable.
2858
+
2859
+ ### When to Use TodoWrite:
2860
+ - IMMEDIATELY after receiving a user request
2861
+ - Before ANY multi-step task (even if it seems "simple")
2862
+ - When delegating to agents (track what you delegated)
2863
+ - After completing each step (mark it done)
2864
+
2865
+ ### TODO Workflow:
2866
+ \`\`\`
2867
+ User Request \u2192 TodoWrite (plan) \u2192 Mark in_progress \u2192 Execute/Delegate \u2192 Mark complete \u2192 Next
2868
+ \`\`\`
2869
+
2870
+ ### Rules:
2871
+ - Only ONE task in_progress at a time
2872
+ - Mark complete IMMEDIATELY after finishing (never batch)
2873
+ - Never proceed without updating TODO status
2874
+
2875
+ ## Delegation Pattern
2876
+
2877
+ \`\`\`typescript
2878
+ // 1. PLAN with TODO first
2879
+ todowrite([
2880
+ { id: "research", content: "Research X implementation", status: "in_progress", priority: "high" },
2881
+ { id: "impl", content: "Implement X feature", status: "pending", priority: "high" },
2882
+ { id: "test", content: "Test X feature", status: "pending", priority: "medium" }
2883
+ ])
2884
+
2885
+ // 2. DELEGATE research in parallel
2886
+ background_task(agent="explore", prompt="Find all files related to X")
2887
+ background_task(agent="librarian", prompt="Look up X documentation")
2888
+
2889
+ // 3. CONTINUE working on implementation skeleton while agents research
2890
+ // 4. When notified, INTEGRATE findings and mark TODO complete
2891
+ \`\`\`
2892
+
2893
+ ## Anti-Patterns (AVOID):
2894
+ - Doing everything yourself when agents can help
2895
+ - Skipping TODO planning for "quick" tasks
2896
+ - Forgetting to mark tasks complete
2897
+ - Sequential execution when parallel is possible
2898
+ - Direct tool calls without considering delegation
2899
+
2900
+ ## Remember:
2901
+ - You are the **team lead**, not the grunt worker
2902
+ - Your context window is precious - delegate to preserve it
2903
+ - Agents have specialized expertise - USE THEM
2904
+ - TODO tracking gives users visibility into your progress
2905
+ - Parallel execution = faster results
2906
+ `;
2829
2907
  // src/hooks/todo-continuation-enforcer.ts
2830
2908
  var CONTINUATION_PROMPT = `[SYSTEM REMINDER - TODO CONTINUATION]
2831
2909
 
@@ -6783,6 +6861,156 @@ function createUltraworkModeHook() {
6783
6861
  }
6784
6862
  };
6785
6863
  }
6864
+ // src/hooks/agent-usage-reminder/storage.ts
6865
+ import {
6866
+ existsSync as existsSync19,
6867
+ mkdirSync as mkdirSync8,
6868
+ readFileSync as readFileSync11,
6869
+ writeFileSync as writeFileSync7,
6870
+ unlinkSync as unlinkSync8
6871
+ } from "fs";
6872
+ import { join as join25 } from "path";
6873
+
6874
+ // src/hooks/agent-usage-reminder/constants.ts
6875
+ import { join as join24 } from "path";
6876
+ var OPENCODE_STORAGE6 = join24(xdgData ?? "", "opencode", "storage");
6877
+ var AGENT_USAGE_REMINDER_STORAGE = join24(OPENCODE_STORAGE6, "agent-usage-reminder");
6878
+ var TARGET_TOOLS = new Set([
6879
+ "grep",
6880
+ "safe_grep",
6881
+ "glob",
6882
+ "safe_glob",
6883
+ "webfetch",
6884
+ "context7_resolve-library-id",
6885
+ "context7_get-library-docs",
6886
+ "websearch_exa_web_search_exa",
6887
+ "grep_app_searchgithub"
6888
+ ]);
6889
+ var AGENT_TOOLS = new Set([
6890
+ "task",
6891
+ "call_omo_agent",
6892
+ "background_task"
6893
+ ]);
6894
+ var REMINDER_MESSAGE = `
6895
+ [Agent Usage Reminder]
6896
+
6897
+ You called a search/fetch tool directly without leveraging specialized agents.
6898
+
6899
+ RECOMMENDED: Use background_task with explore/librarian agents for better results:
6900
+
6901
+ \`\`\`
6902
+ // Parallel exploration - fire multiple agents simultaneously
6903
+ background_task(agent="explore", prompt="Find all files matching pattern X")
6904
+ background_task(agent="explore", prompt="Search for implementation of Y")
6905
+ background_task(agent="librarian", prompt="Lookup documentation for Z")
6906
+
6907
+ // Then continue your work while they run in background
6908
+ // System will notify you when each completes
6909
+ \`\`\`
6910
+
6911
+ WHY:
6912
+ - Agents can perform deeper, more thorough searches
6913
+ - Background tasks run in parallel, saving time
6914
+ - Specialized agents have domain expertise
6915
+ - Reduces context window usage in main session
6916
+
6917
+ ALWAYS prefer: Multiple parallel background_task calls > Direct tool calls
6918
+ `;
6919
+
6920
+ // src/hooks/agent-usage-reminder/storage.ts
6921
+ function getStoragePath4(sessionID) {
6922
+ return join25(AGENT_USAGE_REMINDER_STORAGE, `${sessionID}.json`);
6923
+ }
6924
+ function loadAgentUsageState(sessionID) {
6925
+ const filePath = getStoragePath4(sessionID);
6926
+ if (!existsSync19(filePath))
6927
+ return null;
6928
+ try {
6929
+ const content = readFileSync11(filePath, "utf-8");
6930
+ return JSON.parse(content);
6931
+ } catch {
6932
+ return null;
6933
+ }
6934
+ }
6935
+ function saveAgentUsageState(state) {
6936
+ if (!existsSync19(AGENT_USAGE_REMINDER_STORAGE)) {
6937
+ mkdirSync8(AGENT_USAGE_REMINDER_STORAGE, { recursive: true });
6938
+ }
6939
+ const filePath = getStoragePath4(state.sessionID);
6940
+ writeFileSync7(filePath, JSON.stringify(state, null, 2));
6941
+ }
6942
+ function clearAgentUsageState(sessionID) {
6943
+ const filePath = getStoragePath4(sessionID);
6944
+ if (existsSync19(filePath)) {
6945
+ unlinkSync8(filePath);
6946
+ }
6947
+ }
6948
+
6949
+ // src/hooks/agent-usage-reminder/index.ts
6950
+ function createAgentUsageReminderHook(_ctx) {
6951
+ const sessionStates = new Map;
6952
+ function getOrCreateState(sessionID) {
6953
+ if (!sessionStates.has(sessionID)) {
6954
+ const persisted = loadAgentUsageState(sessionID);
6955
+ const state = persisted ?? {
6956
+ sessionID,
6957
+ agentUsed: false,
6958
+ reminderCount: 0,
6959
+ updatedAt: Date.now()
6960
+ };
6961
+ sessionStates.set(sessionID, state);
6962
+ }
6963
+ return sessionStates.get(sessionID);
6964
+ }
6965
+ function markAgentUsed(sessionID) {
6966
+ const state = getOrCreateState(sessionID);
6967
+ state.agentUsed = true;
6968
+ state.updatedAt = Date.now();
6969
+ saveAgentUsageState(state);
6970
+ }
6971
+ function resetState(sessionID) {
6972
+ sessionStates.delete(sessionID);
6973
+ clearAgentUsageState(sessionID);
6974
+ }
6975
+ const toolExecuteAfter = async (input, output) => {
6976
+ const { tool, sessionID } = input;
6977
+ const toolLower = tool.toLowerCase();
6978
+ if (AGENT_TOOLS.has(toolLower)) {
6979
+ markAgentUsed(sessionID);
6980
+ return;
6981
+ }
6982
+ if (!TARGET_TOOLS.has(toolLower)) {
6983
+ return;
6984
+ }
6985
+ const state = getOrCreateState(sessionID);
6986
+ if (state.agentUsed) {
6987
+ return;
6988
+ }
6989
+ output.output += REMINDER_MESSAGE;
6990
+ state.reminderCount++;
6991
+ state.updatedAt = Date.now();
6992
+ saveAgentUsageState(state);
6993
+ };
6994
+ const eventHandler = async ({ event }) => {
6995
+ const props = event.properties;
6996
+ if (event.type === "session.deleted") {
6997
+ const sessionInfo = props?.info;
6998
+ if (sessionInfo?.id) {
6999
+ resetState(sessionInfo.id);
7000
+ }
7001
+ }
7002
+ if (event.type === "session.compacted") {
7003
+ const sessionID = props?.sessionID ?? props?.info?.id;
7004
+ if (sessionID) {
7005
+ resetState(sessionID);
7006
+ }
7007
+ }
7008
+ };
7009
+ return {
7010
+ "tool.execute.after": toolExecuteAfter,
7011
+ event: eventHandler
7012
+ };
7013
+ }
6786
7014
  // src/auth/antigravity/constants.ts
6787
7015
  var ANTIGRAVITY_CLIENT_ID = "1071006060591-tmhssin2h21lcre235vtolojh4g403ep.apps.googleusercontent.com";
6788
7016
  var ANTIGRAVITY_CLIENT_SECRET = "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";
@@ -8289,11 +8517,11 @@ async function createGoogleAntigravityAuthPlugin({
8289
8517
  };
8290
8518
  }
8291
8519
  // src/features/claude-code-command-loader/loader.ts
8292
- import { existsSync as existsSync19, readdirSync as readdirSync4, readFileSync as readFileSync11 } from "fs";
8520
+ import { existsSync as existsSync20, readdirSync as readdirSync4, readFileSync as readFileSync12 } from "fs";
8293
8521
  import { homedir as homedir9 } from "os";
8294
- import { join as join24, basename } from "path";
8522
+ import { join as join26, basename } from "path";
8295
8523
  function loadCommandsFromDir(commandsDir, scope) {
8296
- if (!existsSync19(commandsDir)) {
8524
+ if (!existsSync20(commandsDir)) {
8297
8525
  return [];
8298
8526
  }
8299
8527
  const entries = readdirSync4(commandsDir, { withFileTypes: true });
@@ -8301,10 +8529,10 @@ function loadCommandsFromDir(commandsDir, scope) {
8301
8529
  for (const entry of entries) {
8302
8530
  if (!isMarkdownFile(entry))
8303
8531
  continue;
8304
- const commandPath = join24(commandsDir, entry.name);
8532
+ const commandPath = join26(commandsDir, entry.name);
8305
8533
  const commandName = basename(entry.name, ".md");
8306
8534
  try {
8307
- const content = readFileSync11(commandPath, "utf-8");
8535
+ const content = readFileSync12(commandPath, "utf-8");
8308
8536
  const { data, body } = parseFrontmatter(content);
8309
8537
  const wrappedTemplate = `<command-instruction>
8310
8538
  ${body.trim()}
@@ -8343,31 +8571,31 @@ function commandsToRecord(commands) {
8343
8571
  return result;
8344
8572
  }
8345
8573
  function loadUserCommands() {
8346
- const userCommandsDir = join24(homedir9(), ".claude", "commands");
8574
+ const userCommandsDir = join26(homedir9(), ".claude", "commands");
8347
8575
  const commands = loadCommandsFromDir(userCommandsDir, "user");
8348
8576
  return commandsToRecord(commands);
8349
8577
  }
8350
8578
  function loadProjectCommands() {
8351
- const projectCommandsDir = join24(process.cwd(), ".claude", "commands");
8579
+ const projectCommandsDir = join26(process.cwd(), ".claude", "commands");
8352
8580
  const commands = loadCommandsFromDir(projectCommandsDir, "project");
8353
8581
  return commandsToRecord(commands);
8354
8582
  }
8355
8583
  function loadOpencodeGlobalCommands() {
8356
- const opencodeCommandsDir = join24(homedir9(), ".config", "opencode", "command");
8584
+ const opencodeCommandsDir = join26(homedir9(), ".config", "opencode", "command");
8357
8585
  const commands = loadCommandsFromDir(opencodeCommandsDir, "opencode");
8358
8586
  return commandsToRecord(commands);
8359
8587
  }
8360
8588
  function loadOpencodeProjectCommands() {
8361
- const opencodeProjectDir = join24(process.cwd(), ".opencode", "command");
8589
+ const opencodeProjectDir = join26(process.cwd(), ".opencode", "command");
8362
8590
  const commands = loadCommandsFromDir(opencodeProjectDir, "opencode-project");
8363
8591
  return commandsToRecord(commands);
8364
8592
  }
8365
8593
  // src/features/claude-code-skill-loader/loader.ts
8366
- import { existsSync as existsSync20, readdirSync as readdirSync5, readFileSync as readFileSync12 } from "fs";
8594
+ import { existsSync as existsSync21, readdirSync as readdirSync5, readFileSync as readFileSync13 } from "fs";
8367
8595
  import { homedir as homedir10 } from "os";
8368
- import { join as join25 } from "path";
8596
+ import { join as join27 } from "path";
8369
8597
  function loadSkillsFromDir(skillsDir, scope) {
8370
- if (!existsSync20(skillsDir)) {
8598
+ if (!existsSync21(skillsDir)) {
8371
8599
  return [];
8372
8600
  }
8373
8601
  const entries = readdirSync5(skillsDir, { withFileTypes: true });
@@ -8375,15 +8603,15 @@ function loadSkillsFromDir(skillsDir, scope) {
8375
8603
  for (const entry of entries) {
8376
8604
  if (entry.name.startsWith("."))
8377
8605
  continue;
8378
- const skillPath = join25(skillsDir, entry.name);
8606
+ const skillPath = join27(skillsDir, entry.name);
8379
8607
  if (!entry.isDirectory() && !entry.isSymbolicLink())
8380
8608
  continue;
8381
8609
  const resolvedPath = resolveSymlink(skillPath);
8382
- const skillMdPath = join25(resolvedPath, "SKILL.md");
8383
- if (!existsSync20(skillMdPath))
8610
+ const skillMdPath = join27(resolvedPath, "SKILL.md");
8611
+ if (!existsSync21(skillMdPath))
8384
8612
  continue;
8385
8613
  try {
8386
- const content = readFileSync12(skillMdPath, "utf-8");
8614
+ const content = readFileSync13(skillMdPath, "utf-8");
8387
8615
  const { data, body } = parseFrontmatter(content);
8388
8616
  const skillName = data.name || entry.name;
8389
8617
  const originalDescription = data.description || "";
@@ -8414,7 +8642,7 @@ $ARGUMENTS
8414
8642
  return skills;
8415
8643
  }
8416
8644
  function loadUserSkillsAsCommands() {
8417
- const userSkillsDir = join25(homedir10(), ".claude", "skills");
8645
+ const userSkillsDir = join27(homedir10(), ".claude", "skills");
8418
8646
  const skills = loadSkillsFromDir(userSkillsDir, "user");
8419
8647
  return skills.reduce((acc, skill) => {
8420
8648
  acc[skill.name] = skill.definition;
@@ -8422,7 +8650,7 @@ function loadUserSkillsAsCommands() {
8422
8650
  }, {});
8423
8651
  }
8424
8652
  function loadProjectSkillsAsCommands() {
8425
- const projectSkillsDir = join25(process.cwd(), ".claude", "skills");
8653
+ const projectSkillsDir = join27(process.cwd(), ".claude", "skills");
8426
8654
  const skills = loadSkillsFromDir(projectSkillsDir, "project");
8427
8655
  return skills.reduce((acc, skill) => {
8428
8656
  acc[skill.name] = skill.definition;
@@ -8430,9 +8658,9 @@ function loadProjectSkillsAsCommands() {
8430
8658
  }, {});
8431
8659
  }
8432
8660
  // src/features/claude-code-agent-loader/loader.ts
8433
- import { existsSync as existsSync21, readdirSync as readdirSync6, readFileSync as readFileSync13 } from "fs";
8661
+ import { existsSync as existsSync22, readdirSync as readdirSync6, readFileSync as readFileSync14 } from "fs";
8434
8662
  import { homedir as homedir11 } from "os";
8435
- import { join as join26, basename as basename2 } from "path";
8663
+ import { join as join28, basename as basename2 } from "path";
8436
8664
  function parseToolsConfig(toolsStr) {
8437
8665
  if (!toolsStr)
8438
8666
  return;
@@ -8446,7 +8674,7 @@ function parseToolsConfig(toolsStr) {
8446
8674
  return result;
8447
8675
  }
8448
8676
  function loadAgentsFromDir(agentsDir, scope) {
8449
- if (!existsSync21(agentsDir)) {
8677
+ if (!existsSync22(agentsDir)) {
8450
8678
  return [];
8451
8679
  }
8452
8680
  const entries = readdirSync6(agentsDir, { withFileTypes: true });
@@ -8454,10 +8682,10 @@ function loadAgentsFromDir(agentsDir, scope) {
8454
8682
  for (const entry of entries) {
8455
8683
  if (!isMarkdownFile(entry))
8456
8684
  continue;
8457
- const agentPath = join26(agentsDir, entry.name);
8685
+ const agentPath = join28(agentsDir, entry.name);
8458
8686
  const agentName = basename2(entry.name, ".md");
8459
8687
  try {
8460
- const content = readFileSync13(agentPath, "utf-8");
8688
+ const content = readFileSync14(agentPath, "utf-8");
8461
8689
  const { data, body } = parseFrontmatter(content);
8462
8690
  const name = data.name || agentName;
8463
8691
  const originalDescription = data.description || "";
@@ -8484,7 +8712,7 @@ function loadAgentsFromDir(agentsDir, scope) {
8484
8712
  return agents;
8485
8713
  }
8486
8714
  function loadUserAgents() {
8487
- const userAgentsDir = join26(homedir11(), ".claude", "agents");
8715
+ const userAgentsDir = join28(homedir11(), ".claude", "agents");
8488
8716
  const agents = loadAgentsFromDir(userAgentsDir, "user");
8489
8717
  const result = {};
8490
8718
  for (const agent of agents) {
@@ -8493,7 +8721,7 @@ function loadUserAgents() {
8493
8721
  return result;
8494
8722
  }
8495
8723
  function loadProjectAgents() {
8496
- const projectAgentsDir = join26(process.cwd(), ".claude", "agents");
8724
+ const projectAgentsDir = join28(process.cwd(), ".claude", "agents");
8497
8725
  const agents = loadAgentsFromDir(projectAgentsDir, "project");
8498
8726
  const result = {};
8499
8727
  for (const agent of agents) {
@@ -8502,9 +8730,9 @@ function loadProjectAgents() {
8502
8730
  return result;
8503
8731
  }
8504
8732
  // src/features/claude-code-mcp-loader/loader.ts
8505
- import { existsSync as existsSync22 } from "fs";
8733
+ import { existsSync as existsSync23 } from "fs";
8506
8734
  import { homedir as homedir12 } from "os";
8507
- import { join as join27 } from "path";
8735
+ import { join as join29 } from "path";
8508
8736
 
8509
8737
  // src/features/claude-code-mcp-loader/env-expander.ts
8510
8738
  function expandEnvVars(value) {
@@ -8573,13 +8801,13 @@ function getMcpConfigPaths() {
8573
8801
  const home = homedir12();
8574
8802
  const cwd = process.cwd();
8575
8803
  return [
8576
- { path: join27(home, ".claude", ".mcp.json"), scope: "user" },
8577
- { path: join27(cwd, ".mcp.json"), scope: "project" },
8578
- { path: join27(cwd, ".claude", ".mcp.json"), scope: "local" }
8804
+ { path: join29(home, ".claude", ".mcp.json"), scope: "user" },
8805
+ { path: join29(cwd, ".mcp.json"), scope: "project" },
8806
+ { path: join29(cwd, ".claude", ".mcp.json"), scope: "local" }
8579
8807
  ];
8580
8808
  }
8581
8809
  async function loadMcpConfigFile(filePath) {
8582
- if (!existsSync22(filePath)) {
8810
+ if (!existsSync23(filePath)) {
8583
8811
  return null;
8584
8812
  }
8585
8813
  try {
@@ -8865,14 +9093,14 @@ var EXT_TO_LANG = {
8865
9093
  ".tfvars": "terraform"
8866
9094
  };
8867
9095
  // src/tools/lsp/config.ts
8868
- import { existsSync as existsSync23, readFileSync as readFileSync14 } from "fs";
8869
- import { join as join28 } from "path";
9096
+ import { existsSync as existsSync24, readFileSync as readFileSync15 } from "fs";
9097
+ import { join as join30 } from "path";
8870
9098
  import { homedir as homedir13 } from "os";
8871
9099
  function loadJsonFile(path5) {
8872
- if (!existsSync23(path5))
9100
+ if (!existsSync24(path5))
8873
9101
  return null;
8874
9102
  try {
8875
- return JSON.parse(readFileSync14(path5, "utf-8"));
9103
+ return JSON.parse(readFileSync15(path5, "utf-8"));
8876
9104
  } catch {
8877
9105
  return null;
8878
9106
  }
@@ -8880,9 +9108,9 @@ function loadJsonFile(path5) {
8880
9108
  function getConfigPaths() {
8881
9109
  const cwd = process.cwd();
8882
9110
  return {
8883
- project: join28(cwd, ".opencode", "oh-my-opencode.json"),
8884
- user: join28(homedir13(), ".config", "opencode", "oh-my-opencode.json"),
8885
- opencode: join28(homedir13(), ".config", "opencode", "opencode.json")
9111
+ project: join30(cwd, ".opencode", "oh-my-opencode.json"),
9112
+ user: join30(homedir13(), ".config", "opencode", "oh-my-opencode.json"),
9113
+ opencode: join30(homedir13(), ".config", "opencode", "opencode.json")
8886
9114
  };
8887
9115
  }
8888
9116
  function loadAllConfigs() {
@@ -8975,7 +9203,7 @@ function isServerInstalled(command) {
8975
9203
  const pathEnv = process.env.PATH || "";
8976
9204
  const paths = pathEnv.split(":");
8977
9205
  for (const p of paths) {
8978
- if (existsSync23(join28(p, cmd))) {
9206
+ if (existsSync24(join30(p, cmd))) {
8979
9207
  return true;
8980
9208
  }
8981
9209
  }
@@ -9025,7 +9253,7 @@ function getAllServers() {
9025
9253
  }
9026
9254
  // src/tools/lsp/client.ts
9027
9255
  var {spawn: spawn4 } = globalThis.Bun;
9028
- import { readFileSync as readFileSync15 } from "fs";
9256
+ import { readFileSync as readFileSync16 } from "fs";
9029
9257
  import { extname, resolve as resolve5 } from "path";
9030
9258
  class LSPServerManager {
9031
9259
  static instance;
@@ -9425,7 +9653,7 @@ ${msg}`);
9425
9653
  const absPath = resolve5(filePath);
9426
9654
  if (this.openedFiles.has(absPath))
9427
9655
  return;
9428
- const text = readFileSync15(absPath, "utf-8");
9656
+ const text = readFileSync16(absPath, "utf-8");
9429
9657
  const ext = extname(absPath);
9430
9658
  const languageId = getLanguageId(ext);
9431
9659
  this.notify("textDocument/didOpen", {
@@ -9540,16 +9768,16 @@ ${msg}`);
9540
9768
  }
9541
9769
  // src/tools/lsp/utils.ts
9542
9770
  import { extname as extname2, resolve as resolve6 } from "path";
9543
- import { existsSync as existsSync24, readFileSync as readFileSync16, writeFileSync as writeFileSync7 } from "fs";
9771
+ import { existsSync as existsSync25, readFileSync as readFileSync17, writeFileSync as writeFileSync8 } from "fs";
9544
9772
  function findWorkspaceRoot(filePath) {
9545
9773
  let dir = resolve6(filePath);
9546
- if (!existsSync24(dir) || !__require("fs").statSync(dir).isDirectory()) {
9774
+ if (!existsSync25(dir) || !__require("fs").statSync(dir).isDirectory()) {
9547
9775
  dir = __require("path").dirname(dir);
9548
9776
  }
9549
9777
  const markers = [".git", "package.json", "pyproject.toml", "Cargo.toml", "go.mod", "pom.xml", "build.gradle"];
9550
9778
  while (dir !== "/") {
9551
9779
  for (const marker of markers) {
9552
- if (existsSync24(__require("path").join(dir, marker))) {
9780
+ if (existsSync25(__require("path").join(dir, marker))) {
9553
9781
  return dir;
9554
9782
  }
9555
9783
  }
@@ -9707,7 +9935,7 @@ function formatCodeActions(actions) {
9707
9935
  }
9708
9936
  function applyTextEditsToFile(filePath, edits) {
9709
9937
  try {
9710
- let content = readFileSync16(filePath, "utf-8");
9938
+ let content = readFileSync17(filePath, "utf-8");
9711
9939
  const lines = content.split(`
9712
9940
  `);
9713
9941
  const sortedEdits = [...edits].sort((a, b) => {
@@ -9732,7 +9960,7 @@ function applyTextEditsToFile(filePath, edits) {
9732
9960
  `));
9733
9961
  }
9734
9962
  }
9735
- writeFileSync7(filePath, lines.join(`
9963
+ writeFileSync8(filePath, lines.join(`
9736
9964
  `), "utf-8");
9737
9965
  return { success: true, editCount: edits.length };
9738
9966
  } catch (err) {
@@ -9763,7 +9991,7 @@ function applyWorkspaceEdit(edit) {
9763
9991
  if (change.kind === "create") {
9764
9992
  try {
9765
9993
  const filePath = change.uri.replace("file://", "");
9766
- writeFileSync7(filePath, "", "utf-8");
9994
+ writeFileSync8(filePath, "", "utf-8");
9767
9995
  result.filesModified.push(filePath);
9768
9996
  } catch (err) {
9769
9997
  result.success = false;
@@ -9773,8 +10001,8 @@ function applyWorkspaceEdit(edit) {
9773
10001
  try {
9774
10002
  const oldPath = change.oldUri.replace("file://", "");
9775
10003
  const newPath = change.newUri.replace("file://", "");
9776
- const content = readFileSync16(oldPath, "utf-8");
9777
- writeFileSync7(newPath, content, "utf-8");
10004
+ const content = readFileSync17(oldPath, "utf-8");
10005
+ writeFileSync8(newPath, content, "utf-8");
9778
10006
  __require("fs").unlinkSync(oldPath);
9779
10007
  result.filesModified.push(newPath);
9780
10008
  } catch (err) {
@@ -22474,13 +22702,13 @@ var lsp_code_action_resolve = tool({
22474
22702
  });
22475
22703
  // src/tools/ast-grep/constants.ts
22476
22704
  import { createRequire as createRequire4 } from "module";
22477
- import { dirname as dirname5, join as join30 } from "path";
22478
- import { existsSync as existsSync26, statSync as statSync3 } from "fs";
22705
+ import { dirname as dirname5, join as join32 } from "path";
22706
+ import { existsSync as existsSync27, statSync as statSync3 } from "fs";
22479
22707
 
22480
22708
  // src/tools/ast-grep/downloader.ts
22481
22709
  var {spawn: spawn5 } = globalThis.Bun;
22482
- import { existsSync as existsSync25, mkdirSync as mkdirSync8, chmodSync as chmodSync2, unlinkSync as unlinkSync8 } from "fs";
22483
- import { join as join29 } from "path";
22710
+ import { existsSync as existsSync26, mkdirSync as mkdirSync9, chmodSync as chmodSync2, unlinkSync as unlinkSync9 } from "fs";
22711
+ import { join as join31 } from "path";
22484
22712
  import { homedir as homedir14 } from "os";
22485
22713
  import { createRequire as createRequire3 } from "module";
22486
22714
  var REPO2 = "ast-grep/ast-grep";
@@ -22506,19 +22734,19 @@ var PLATFORM_MAP2 = {
22506
22734
  function getCacheDir3() {
22507
22735
  if (process.platform === "win32") {
22508
22736
  const localAppData = process.env.LOCALAPPDATA || process.env.APPDATA;
22509
- const base2 = localAppData || join29(homedir14(), "AppData", "Local");
22510
- return join29(base2, "oh-my-opencode", "bin");
22737
+ const base2 = localAppData || join31(homedir14(), "AppData", "Local");
22738
+ return join31(base2, "oh-my-opencode", "bin");
22511
22739
  }
22512
22740
  const xdgCache2 = process.env.XDG_CACHE_HOME;
22513
- const base = xdgCache2 || join29(homedir14(), ".cache");
22514
- return join29(base, "oh-my-opencode", "bin");
22741
+ const base = xdgCache2 || join31(homedir14(), ".cache");
22742
+ return join31(base, "oh-my-opencode", "bin");
22515
22743
  }
22516
22744
  function getBinaryName3() {
22517
22745
  return process.platform === "win32" ? "sg.exe" : "sg";
22518
22746
  }
22519
22747
  function getCachedBinaryPath2() {
22520
- const binaryPath = join29(getCacheDir3(), getBinaryName3());
22521
- return existsSync25(binaryPath) ? binaryPath : null;
22748
+ const binaryPath = join31(getCacheDir3(), getBinaryName3());
22749
+ return existsSync26(binaryPath) ? binaryPath : null;
22522
22750
  }
22523
22751
  async function extractZip2(archivePath, destDir) {
22524
22752
  const proc = process.platform === "win32" ? spawn5([
@@ -22544,8 +22772,8 @@ async function downloadAstGrep(version2 = DEFAULT_VERSION) {
22544
22772
  }
22545
22773
  const cacheDir = getCacheDir3();
22546
22774
  const binaryName = getBinaryName3();
22547
- const binaryPath = join29(cacheDir, binaryName);
22548
- if (existsSync25(binaryPath)) {
22775
+ const binaryPath = join31(cacheDir, binaryName);
22776
+ if (existsSync26(binaryPath)) {
22549
22777
  return binaryPath;
22550
22778
  }
22551
22779
  const { arch, os: os4 } = platformInfo;
@@ -22553,21 +22781,21 @@ async function downloadAstGrep(version2 = DEFAULT_VERSION) {
22553
22781
  const downloadUrl = `https://github.com/${REPO2}/releases/download/${version2}/${assetName}`;
22554
22782
  console.log(`[oh-my-opencode] Downloading ast-grep binary...`);
22555
22783
  try {
22556
- if (!existsSync25(cacheDir)) {
22557
- mkdirSync8(cacheDir, { recursive: true });
22784
+ if (!existsSync26(cacheDir)) {
22785
+ mkdirSync9(cacheDir, { recursive: true });
22558
22786
  }
22559
22787
  const response2 = await fetch(downloadUrl, { redirect: "follow" });
22560
22788
  if (!response2.ok) {
22561
22789
  throw new Error(`HTTP ${response2.status}: ${response2.statusText}`);
22562
22790
  }
22563
- const archivePath = join29(cacheDir, assetName);
22791
+ const archivePath = join31(cacheDir, assetName);
22564
22792
  const arrayBuffer = await response2.arrayBuffer();
22565
22793
  await Bun.write(archivePath, arrayBuffer);
22566
22794
  await extractZip2(archivePath, cacheDir);
22567
- if (existsSync25(archivePath)) {
22568
- unlinkSync8(archivePath);
22795
+ if (existsSync26(archivePath)) {
22796
+ unlinkSync9(archivePath);
22569
22797
  }
22570
- if (process.platform !== "win32" && existsSync25(binaryPath)) {
22798
+ if (process.platform !== "win32" && existsSync26(binaryPath)) {
22571
22799
  chmodSync2(binaryPath, 493);
22572
22800
  }
22573
22801
  console.log(`[oh-my-opencode] ast-grep binary ready.`);
@@ -22618,8 +22846,8 @@ function findSgCliPathSync() {
22618
22846
  const require2 = createRequire4(import.meta.url);
22619
22847
  const cliPkgPath = require2.resolve("@ast-grep/cli/package.json");
22620
22848
  const cliDir = dirname5(cliPkgPath);
22621
- const sgPath = join30(cliDir, binaryName);
22622
- if (existsSync26(sgPath) && isValidBinary(sgPath)) {
22849
+ const sgPath = join32(cliDir, binaryName);
22850
+ if (existsSync27(sgPath) && isValidBinary(sgPath)) {
22623
22851
  return sgPath;
22624
22852
  }
22625
22853
  } catch {}
@@ -22630,8 +22858,8 @@ function findSgCliPathSync() {
22630
22858
  const pkgPath = require2.resolve(`${platformPkg}/package.json`);
22631
22859
  const pkgDir = dirname5(pkgPath);
22632
22860
  const astGrepName = process.platform === "win32" ? "ast-grep.exe" : "ast-grep";
22633
- const binaryPath = join30(pkgDir, astGrepName);
22634
- if (existsSync26(binaryPath) && isValidBinary(binaryPath)) {
22861
+ const binaryPath = join32(pkgDir, astGrepName);
22862
+ if (existsSync27(binaryPath) && isValidBinary(binaryPath)) {
22635
22863
  return binaryPath;
22636
22864
  }
22637
22865
  } catch {}
@@ -22639,7 +22867,7 @@ function findSgCliPathSync() {
22639
22867
  if (process.platform === "darwin") {
22640
22868
  const homebrewPaths = ["/opt/homebrew/bin/sg", "/usr/local/bin/sg"];
22641
22869
  for (const path5 of homebrewPaths) {
22642
- if (existsSync26(path5) && isValidBinary(path5)) {
22870
+ if (existsSync27(path5) && isValidBinary(path5)) {
22643
22871
  return path5;
22644
22872
  }
22645
22873
  }
@@ -22695,11 +22923,11 @@ var DEFAULT_MAX_MATCHES = 500;
22695
22923
 
22696
22924
  // src/tools/ast-grep/cli.ts
22697
22925
  var {spawn: spawn6 } = globalThis.Bun;
22698
- import { existsSync as existsSync27 } from "fs";
22926
+ import { existsSync as existsSync28 } from "fs";
22699
22927
  var resolvedCliPath3 = null;
22700
22928
  var initPromise2 = null;
22701
22929
  async function getAstGrepPath() {
22702
- if (resolvedCliPath3 !== null && existsSync27(resolvedCliPath3)) {
22930
+ if (resolvedCliPath3 !== null && existsSync28(resolvedCliPath3)) {
22703
22931
  return resolvedCliPath3;
22704
22932
  }
22705
22933
  if (initPromise2) {
@@ -22707,7 +22935,7 @@ async function getAstGrepPath() {
22707
22935
  }
22708
22936
  initPromise2 = (async () => {
22709
22937
  const syncPath = findSgCliPathSync();
22710
- if (syncPath && existsSync27(syncPath)) {
22938
+ if (syncPath && existsSync28(syncPath)) {
22711
22939
  resolvedCliPath3 = syncPath;
22712
22940
  setSgCliPath(syncPath);
22713
22941
  return syncPath;
@@ -22741,7 +22969,7 @@ async function runSg(options) {
22741
22969
  const paths = options.paths && options.paths.length > 0 ? options.paths : ["."];
22742
22970
  args.push(...paths);
22743
22971
  let cliPath = getSgCliPath();
22744
- if (!existsSync27(cliPath) && cliPath !== "sg") {
22972
+ if (!existsSync28(cliPath) && cliPath !== "sg") {
22745
22973
  const downloadedPath = await getAstGrepPath();
22746
22974
  if (downloadedPath) {
22747
22975
  cliPath = downloadedPath;
@@ -23005,8 +23233,8 @@ var ast_grep_replace = tool({
23005
23233
  var {spawn: spawn7 } = globalThis.Bun;
23006
23234
 
23007
23235
  // src/tools/grep/constants.ts
23008
- import { existsSync as existsSync28 } from "fs";
23009
- import { join as join31, dirname as dirname6 } from "path";
23236
+ import { existsSync as existsSync29 } from "fs";
23237
+ import { join as join33, dirname as dirname6 } from "path";
23010
23238
  import { spawnSync } from "child_process";
23011
23239
  var cachedCli = null;
23012
23240
  function findExecutable(name) {
@@ -23027,13 +23255,13 @@ function getOpenCodeBundledRg() {
23027
23255
  const isWindows = process.platform === "win32";
23028
23256
  const rgName = isWindows ? "rg.exe" : "rg";
23029
23257
  const candidates = [
23030
- join31(execDir, rgName),
23031
- join31(execDir, "bin", rgName),
23032
- join31(execDir, "..", "bin", rgName),
23033
- join31(execDir, "..", "libexec", rgName)
23258
+ join33(execDir, rgName),
23259
+ join33(execDir, "bin", rgName),
23260
+ join33(execDir, "..", "bin", rgName),
23261
+ join33(execDir, "..", "libexec", rgName)
23034
23262
  ];
23035
23263
  for (const candidate of candidates) {
23036
- if (existsSync28(candidate)) {
23264
+ if (existsSync29(candidate)) {
23037
23265
  return candidate;
23038
23266
  }
23039
23267
  }
@@ -23431,11 +23659,11 @@ var glob = tool({
23431
23659
  }
23432
23660
  });
23433
23661
  // src/tools/slashcommand/tools.ts
23434
- import { existsSync as existsSync29, readdirSync as readdirSync7, readFileSync as readFileSync17 } from "fs";
23662
+ import { existsSync as existsSync30, readdirSync as readdirSync7, readFileSync as readFileSync18 } from "fs";
23435
23663
  import { homedir as homedir15 } from "os";
23436
- import { join as join32, basename as basename3, dirname as dirname7 } from "path";
23664
+ import { join as join34, basename as basename3, dirname as dirname7 } from "path";
23437
23665
  function discoverCommandsFromDir(commandsDir, scope) {
23438
- if (!existsSync29(commandsDir)) {
23666
+ if (!existsSync30(commandsDir)) {
23439
23667
  return [];
23440
23668
  }
23441
23669
  const entries = readdirSync7(commandsDir, { withFileTypes: true });
@@ -23443,10 +23671,10 @@ function discoverCommandsFromDir(commandsDir, scope) {
23443
23671
  for (const entry of entries) {
23444
23672
  if (!isMarkdownFile(entry))
23445
23673
  continue;
23446
- const commandPath = join32(commandsDir, entry.name);
23674
+ const commandPath = join34(commandsDir, entry.name);
23447
23675
  const commandName = basename3(entry.name, ".md");
23448
23676
  try {
23449
- const content = readFileSync17(commandPath, "utf-8");
23677
+ const content = readFileSync18(commandPath, "utf-8");
23450
23678
  const { data, body } = parseFrontmatter(content);
23451
23679
  const metadata = {
23452
23680
  name: commandName,
@@ -23470,10 +23698,10 @@ function discoverCommandsFromDir(commandsDir, scope) {
23470
23698
  return commands;
23471
23699
  }
23472
23700
  function discoverCommandsSync() {
23473
- const userCommandsDir = join32(homedir15(), ".claude", "commands");
23474
- const projectCommandsDir = join32(process.cwd(), ".claude", "commands");
23475
- const opencodeGlobalDir = join32(homedir15(), ".config", "opencode", "command");
23476
- const opencodeProjectDir = join32(process.cwd(), ".opencode", "command");
23701
+ const userCommandsDir = join34(homedir15(), ".claude", "commands");
23702
+ const projectCommandsDir = join34(process.cwd(), ".claude", "commands");
23703
+ const opencodeGlobalDir = join34(homedir15(), ".config", "opencode", "command");
23704
+ const opencodeProjectDir = join34(process.cwd(), ".opencode", "command");
23477
23705
  const userCommands = discoverCommandsFromDir(userCommandsDir, "user");
23478
23706
  const opencodeGlobalCommands = discoverCommandsFromDir(opencodeGlobalDir, "opencode");
23479
23707
  const projectCommands = discoverCommandsFromDir(projectCommandsDir, "project");
@@ -23605,9 +23833,9 @@ var SkillFrontmatterSchema = exports_external.object({
23605
23833
  metadata: exports_external.record(exports_external.string(), exports_external.string()).optional()
23606
23834
  });
23607
23835
  // src/tools/skill/tools.ts
23608
- import { existsSync as existsSync30, readdirSync as readdirSync8, readFileSync as readFileSync18 } from "fs";
23836
+ import { existsSync as existsSync31, readdirSync as readdirSync8, readFileSync as readFileSync19 } from "fs";
23609
23837
  import { homedir as homedir16 } from "os";
23610
- import { join as join33, basename as basename4 } from "path";
23838
+ import { join as join35, basename as basename4 } from "path";
23611
23839
  function parseSkillFrontmatter(data) {
23612
23840
  return {
23613
23841
  name: typeof data.name === "string" ? data.name : "",
@@ -23618,7 +23846,7 @@ function parseSkillFrontmatter(data) {
23618
23846
  };
23619
23847
  }
23620
23848
  function discoverSkillsFromDir(skillsDir, scope) {
23621
- if (!existsSync30(skillsDir)) {
23849
+ if (!existsSync31(skillsDir)) {
23622
23850
  return [];
23623
23851
  }
23624
23852
  const entries = readdirSync8(skillsDir, { withFileTypes: true });
@@ -23626,14 +23854,14 @@ function discoverSkillsFromDir(skillsDir, scope) {
23626
23854
  for (const entry of entries) {
23627
23855
  if (entry.name.startsWith("."))
23628
23856
  continue;
23629
- const skillPath = join33(skillsDir, entry.name);
23857
+ const skillPath = join35(skillsDir, entry.name);
23630
23858
  if (entry.isDirectory() || entry.isSymbolicLink()) {
23631
23859
  const resolvedPath = resolveSymlink(skillPath);
23632
- const skillMdPath = join33(resolvedPath, "SKILL.md");
23633
- if (!existsSync30(skillMdPath))
23860
+ const skillMdPath = join35(resolvedPath, "SKILL.md");
23861
+ if (!existsSync31(skillMdPath))
23634
23862
  continue;
23635
23863
  try {
23636
- const content = readFileSync18(skillMdPath, "utf-8");
23864
+ const content = readFileSync19(skillMdPath, "utf-8");
23637
23865
  const { data } = parseFrontmatter(content);
23638
23866
  skills.push({
23639
23867
  name: data.name || entry.name,
@@ -23648,8 +23876,8 @@ function discoverSkillsFromDir(skillsDir, scope) {
23648
23876
  return skills;
23649
23877
  }
23650
23878
  function discoverSkillsSync() {
23651
- const userSkillsDir = join33(homedir16(), ".claude", "skills");
23652
- const projectSkillsDir = join33(process.cwd(), ".claude", "skills");
23879
+ const userSkillsDir = join35(homedir16(), ".claude", "skills");
23880
+ const projectSkillsDir = join35(process.cwd(), ".claude", "skills");
23653
23881
  const userSkills = discoverSkillsFromDir(userSkillsDir, "user");
23654
23882
  const projectSkills = discoverSkillsFromDir(projectSkillsDir, "project");
23655
23883
  return [...projectSkills, ...userSkills];
@@ -23659,12 +23887,12 @@ var skillListForDescription = availableSkills.map((s) => `- ${s.name}: ${s.descr
23659
23887
  `);
23660
23888
  async function parseSkillMd(skillPath) {
23661
23889
  const resolvedPath = resolveSymlink(skillPath);
23662
- const skillMdPath = join33(resolvedPath, "SKILL.md");
23663
- if (!existsSync30(skillMdPath)) {
23890
+ const skillMdPath = join35(resolvedPath, "SKILL.md");
23891
+ if (!existsSync31(skillMdPath)) {
23664
23892
  return null;
23665
23893
  }
23666
23894
  try {
23667
- let content = readFileSync18(skillMdPath, "utf-8");
23895
+ let content = readFileSync19(skillMdPath, "utf-8");
23668
23896
  content = await resolveCommandsInText(content);
23669
23897
  const { data, body } = parseFrontmatter(content);
23670
23898
  const frontmatter2 = parseSkillFrontmatter(data);
@@ -23675,12 +23903,12 @@ async function parseSkillMd(skillPath) {
23675
23903
  allowedTools: frontmatter2["allowed-tools"],
23676
23904
  metadata: frontmatter2.metadata
23677
23905
  };
23678
- const referencesDir = join33(resolvedPath, "references");
23679
- const scriptsDir = join33(resolvedPath, "scripts");
23680
- const assetsDir = join33(resolvedPath, "assets");
23681
- const references = existsSync30(referencesDir) ? readdirSync8(referencesDir).filter((f) => !f.startsWith(".")) : [];
23682
- const scripts = existsSync30(scriptsDir) ? readdirSync8(scriptsDir).filter((f) => !f.startsWith(".") && !f.startsWith("__")) : [];
23683
- const assets = existsSync30(assetsDir) ? readdirSync8(assetsDir).filter((f) => !f.startsWith(".")) : [];
23906
+ const referencesDir = join35(resolvedPath, "references");
23907
+ const scriptsDir = join35(resolvedPath, "scripts");
23908
+ const assetsDir = join35(resolvedPath, "assets");
23909
+ const references = existsSync31(referencesDir) ? readdirSync8(referencesDir).filter((f) => !f.startsWith(".")) : [];
23910
+ const scripts = existsSync31(scriptsDir) ? readdirSync8(scriptsDir).filter((f) => !f.startsWith(".") && !f.startsWith("__")) : [];
23911
+ const assets = existsSync31(assetsDir) ? readdirSync8(assetsDir).filter((f) => !f.startsWith(".")) : [];
23684
23912
  return {
23685
23913
  name: metadata.name,
23686
23914
  path: resolvedPath,
@@ -23696,7 +23924,7 @@ async function parseSkillMd(skillPath) {
23696
23924
  }
23697
23925
  }
23698
23926
  async function discoverSkillsFromDirAsync(skillsDir) {
23699
- if (!existsSync30(skillsDir)) {
23927
+ if (!existsSync31(skillsDir)) {
23700
23928
  return [];
23701
23929
  }
23702
23930
  const entries = readdirSync8(skillsDir, { withFileTypes: true });
@@ -23704,7 +23932,7 @@ async function discoverSkillsFromDirAsync(skillsDir) {
23704
23932
  for (const entry of entries) {
23705
23933
  if (entry.name.startsWith("."))
23706
23934
  continue;
23707
- const skillPath = join33(skillsDir, entry.name);
23935
+ const skillPath = join35(skillsDir, entry.name);
23708
23936
  if (entry.isDirectory() || entry.isSymbolicLink()) {
23709
23937
  const skillInfo = await parseSkillMd(skillPath);
23710
23938
  if (skillInfo) {
@@ -23715,8 +23943,8 @@ async function discoverSkillsFromDirAsync(skillsDir) {
23715
23943
  return skills;
23716
23944
  }
23717
23945
  async function discoverSkills() {
23718
- const userSkillsDir = join33(homedir16(), ".claude", "skills");
23719
- const projectSkillsDir = join33(process.cwd(), ".claude", "skills");
23946
+ const userSkillsDir = join35(homedir16(), ".claude", "skills");
23947
+ const projectSkillsDir = join35(process.cwd(), ".claude", "skills");
23720
23948
  const userSkills = await discoverSkillsFromDirAsync(userSkillsDir);
23721
23949
  const projectSkills = await discoverSkillsFromDirAsync(projectSkillsDir);
23722
23950
  return [...projectSkills, ...userSkills];
@@ -23745,9 +23973,9 @@ async function loadSkillWithReferences(skill, includeRefs) {
23745
23973
  const referencesLoaded = [];
23746
23974
  if (includeRefs && skill.references.length > 0) {
23747
23975
  for (const ref of skill.references) {
23748
- const refPath = join33(skill.path, "references", ref);
23976
+ const refPath = join35(skill.path, "references", ref);
23749
23977
  try {
23750
- let content = readFileSync18(refPath, "utf-8");
23978
+ let content = readFileSync19(refPath, "utf-8");
23751
23979
  content = await resolveCommandsInText(content);
23752
23980
  referencesLoaded.push({ path: ref, content });
23753
23981
  } catch {}
@@ -23939,10 +24167,9 @@ function formatTaskStatus(task) {
23939
24167
  const duration3 = formatDuration(task.startedAt, task.completedAt);
23940
24168
  const promptPreview = truncateText(task.prompt, 500);
23941
24169
  let progressSection = "";
23942
- if (task.progress) {
24170
+ if (task.progress?.lastTool) {
23943
24171
  progressSection = `
23944
- Tool calls: ${task.progress.toolCalls}
23945
- Last tool: ${task.progress.lastTool ?? "N/A"}`;
24172
+ | Last tool | ${task.progress.lastTool} |`;
23946
24173
  }
23947
24174
  let lastMessageSection = "";
23948
24175
  if (task.progress?.lastMessage) {
@@ -23955,6 +24182,16 @@ Last tool: ${task.progress.lastTool ?? "N/A"}`;
23955
24182
  \`\`\`
23956
24183
  ${truncated}
23957
24184
  \`\`\``;
24185
+ }
24186
+ let statusNote = "";
24187
+ if (task.status === "running") {
24188
+ statusNote = `
24189
+
24190
+ > **Note**: No need to wait explicitly - the system will notify you when this task completes.`;
24191
+ } else if (task.status === "error") {
24192
+ statusNote = `
24193
+
24194
+ > **Failed**: The task encountered an error. Check the last message for details.`;
23958
24195
  }
23959
24196
  return `# Task Status
23960
24197
 
@@ -23966,7 +24203,7 @@ ${truncated}
23966
24203
  | Status | **${task.status}** |
23967
24204
  | Duration | ${duration3} |
23968
24205
  | Session ID | \`${task.sessionID}\` |${progressSection}
23969
-
24206
+ ${statusNote}
23970
24207
  ## Original Prompt
23971
24208
 
23972
24209
  \`\`\`
@@ -24712,7 +24949,16 @@ var AgentPermissionSchema = exports_external.object({
24712
24949
  doom_loop: PermissionValue.optional(),
24713
24950
  external_directory: PermissionValue.optional()
24714
24951
  });
24715
- var AgentNameSchema = exports_external.enum([
24952
+ var BuiltinAgentNameSchema = exports_external.enum([
24953
+ "oracle",
24954
+ "librarian",
24955
+ "explore",
24956
+ "frontend-ui-ux-engineer",
24957
+ "document-writer",
24958
+ "multimodal-looker"
24959
+ ]);
24960
+ var OverridableAgentNameSchema = exports_external.enum([
24961
+ "build",
24716
24962
  "oracle",
24717
24963
  "librarian",
24718
24964
  "explore",
@@ -24735,7 +24981,8 @@ var HookNameSchema = exports_external.enum([
24735
24981
  "rules-injector",
24736
24982
  "background-notification",
24737
24983
  "auto-update-checker",
24738
- "ultrawork-mode"
24984
+ "ultrawork-mode",
24985
+ "agent-usage-reminder"
24739
24986
  ]);
24740
24987
  var AgentOverrideConfigSchema = exports_external.object({
24741
24988
  model: exports_external.string().optional(),
@@ -24750,6 +24997,7 @@ var AgentOverrideConfigSchema = exports_external.object({
24750
24997
  permission: AgentPermissionSchema.optional()
24751
24998
  });
24752
24999
  var AgentOverridesSchema = exports_external.object({
25000
+ build: AgentOverrideConfigSchema.optional(),
24753
25001
  oracle: AgentOverrideConfigSchema.optional(),
24754
25002
  librarian: AgentOverrideConfigSchema.optional(),
24755
25003
  explore: AgentOverrideConfigSchema.optional(),
@@ -24767,7 +25015,7 @@ var ClaudeCodeConfigSchema = exports_external.object({
24767
25015
  var OhMyOpenCodeConfigSchema = exports_external.object({
24768
25016
  $schema: exports_external.string().optional(),
24769
25017
  disabled_mcps: exports_external.array(McpNameSchema).optional(),
24770
- disabled_agents: exports_external.array(AgentNameSchema).optional(),
25018
+ disabled_agents: exports_external.array(BuiltinAgentNameSchema).optional(),
24771
25019
  disabled_hooks: exports_external.array(HookNameSchema).optional(),
24772
25020
  agents: AgentOverridesSchema.optional(),
24773
25021
  claude_code: ClaudeCodeConfigSchema.optional(),
@@ -24869,6 +25117,7 @@ var OhMyOpenCodePlugin = async (ctx) => {
24869
25117
  const rulesInjector = isHookEnabled("rules-injector") ? createRulesInjectorHook(ctx) : null;
24870
25118
  const autoUpdateChecker = isHookEnabled("auto-update-checker") ? createAutoUpdateCheckerHook(ctx) : null;
24871
25119
  const ultraworkMode = isHookEnabled("ultrawork-mode") ? createUltraworkModeHook() : null;
25120
+ const agentUsageReminder = isHookEnabled("agent-usage-reminder") ? createAgentUsageReminderHook(ctx) : null;
24872
25121
  updateTerminalTitle({ sessionId: "main" });
24873
25122
  const backgroundManager = new BackgroundManager(ctx);
24874
25123
  const backgroundNotificationHook = isHookEnabled("background-notification") ? createBackgroundNotificationHook(backgroundManager) : null;
@@ -24898,6 +25147,14 @@ var OhMyOpenCodePlugin = async (ctx) => {
24898
25147
  ...projectAgents,
24899
25148
  ...config3.agent
24900
25149
  };
25150
+ if (config3.agent.build) {
25151
+ const existingPrompt = config3.agent.build.prompt || "";
25152
+ const userOverride = pluginConfig.agents?.build?.prompt || "";
25153
+ config3.agent.build = {
25154
+ ...config3.agent.build,
25155
+ prompt: existingPrompt + BUILD_AGENT_PROMPT_EXTENSION + userOverride
25156
+ };
25157
+ }
24901
25158
  config3.tools = {
24902
25159
  ...config3.tools
24903
25160
  };
@@ -24957,6 +25214,7 @@ var OhMyOpenCodePlugin = async (ctx) => {
24957
25214
  await thinkMode?.event(input);
24958
25215
  await anthropicAutoCompact?.event(input);
24959
25216
  await ultraworkMode?.event(input);
25217
+ await agentUsageReminder?.event(input);
24960
25218
  const { event } = input;
24961
25219
  const props = event.properties;
24962
25220
  if (event.type === "session.created") {
@@ -25057,6 +25315,7 @@ var OhMyOpenCodePlugin = async (ctx) => {
25057
25315
  await directoryReadmeInjector?.["tool.execute.after"](input, output);
25058
25316
  await rulesInjector?.["tool.execute.after"](input, output);
25059
25317
  await emptyTaskResponseDetector?.["tool.execute.after"](input, output);
25318
+ await agentUsageReminder?.["tool.execute.after"](input, output);
25060
25319
  if (input.sessionID === getMainSessionID()) {
25061
25320
  updateTerminalTitle({
25062
25321
  sessionId: input.sessionID,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "oh-my-opencode",
3
- "version": "1.1.2",
3
+ "version": "1.1.4",
4
4
  "description": "OpenCode plugin - custom agents (oracle, librarian) and enhanced features",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",