oh-my-opencode 1.1.3 → 1.1.5
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/agents/build.d.ts +1 -0
- package/dist/agents/index.d.ts +1 -0
- package/dist/agents/types.d.ts +4 -2
- package/dist/agents/utils.d.ts +2 -2
- package/dist/config/schema.d.ts +111 -0
- package/dist/hooks/agent-usage-reminder/constants.d.ts +5 -0
- package/dist/hooks/agent-usage-reminder/index.d.ts +22 -0
- package/dist/hooks/agent-usage-reminder/storage.d.ts +4 -0
- package/dist/hooks/agent-usage-reminder/types.d.ts +6 -0
- package/dist/hooks/index.d.ts +1 -0
- package/dist/index.js +440 -123
- package/package.json +1 -1
|
@@ -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## PARALLEL TOOL CALLS - MANDATORY\n\n**ALWAYS USE PARALLEL TOOLS WHEN APPLICABLE.** This is non-negotiable.\n\nThis parallel approach allows you to:\n- Gather comprehensive context faster\n- Cross-reference information simultaneously\n- Reduce total execution time dramatically\n- Maintain high accuracy through concurrent validation\n- Complete multi-file modifications in a single turn\n\n**ALWAYS prefer parallel tool calls over sequential ones when the operations are independent.**\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 - FIRE MULTIPLE AT ONCE\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## Subagent Prompt Structure - MANDATORY 7 SECTIONS\n\nWhen invoking Task() or background_task() with any subagent, ALWAYS structure your prompt with these 7 sections to prevent AI slop:\n\n1. **TASK**: What exactly needs to be done (be obsessively specific)\n2. **EXPECTED OUTCOME**: Concrete deliverables when complete (files, behaviors, states)\n3. **REQUIRED SKILLS**: Which skills the agent MUST invoke\n4. **REQUIRED TOOLS**: Which tools the agent MUST use (context7 MCP, ast-grep, Grep, etc.)\n5. **MUST DO**: Exhaustive list of requirements (leave NOTHING implicit)\n6. **MUST NOT DO**: Forbidden actions (anticipate every way agent could go rogue)\n7. **CONTEXT**: Additional info agent needs (file paths, patterns, dependencies)\n\nExample:\n```\nbackground_task(agent=\"explore\", prompt=\"\"\"\nTASK: Find all authentication-related files in the codebase\n\nEXPECTED OUTCOME:\n- List of all auth files with their purposes\n- Identified patterns for token handling\n\nREQUIRED TOOLS:\n- ast-grep: Find function definitions with `sg --pattern 'def $FUNC($$$):' --lang python`\n- Grep: Search for 'auth', 'token', 'jwt' patterns\n\nMUST DO:\n- Search in src/, lib/, and utils/ directories\n- Include test files for context\n\nMUST NOT DO:\n- Do NOT modify any files\n- Do NOT make assumptions about implementation\n\nCONTEXT:\n- Project uses Python/Django\n- Auth system is custom-built\n\"\"\")\n```\n\n**Vague prompts = agent goes rogue. Lock them down.**\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- Vague subagent prompts without the 7 sections\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- **ALWAYS fire multiple independent operations simultaneously**\n";
|
package/dist/agents/index.d.ts
CHANGED
package/dist/agents/types.d.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import type { AgentConfig } from "@opencode-ai/sdk";
|
|
2
|
-
export type
|
|
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<
|
|
6
|
+
export type AgentOverrides = Partial<Record<OverridableAgentName, AgentOverrideConfig>>;
|
package/dist/agents/utils.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import type { AgentConfig } from "@opencode-ai/sdk";
|
|
2
|
-
import type {
|
|
3
|
-
export declare function createBuiltinAgents(disabledAgents?:
|
|
2
|
+
import type { BuiltinAgentName, AgentOverrides } from "./types";
|
|
3
|
+
export declare function createBuiltinAgents(disabledAgents?: BuiltinAgentName[], agentOverrides?: AgentOverrides): Record<string, AgentConfig>;
|
package/dist/config/schema.d.ts
CHANGED
|
@@ -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;
|
package/dist/hooks/index.d.ts
CHANGED
|
@@ -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
|
@@ -2826,6 +2826,140 @@ 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
|
+
## PARALLEL TOOL CALLS - MANDATORY
|
|
2856
|
+
|
|
2857
|
+
**ALWAYS USE PARALLEL TOOLS WHEN APPLICABLE.** This is non-negotiable.
|
|
2858
|
+
|
|
2859
|
+
This parallel approach allows you to:
|
|
2860
|
+
- Gather comprehensive context faster
|
|
2861
|
+
- Cross-reference information simultaneously
|
|
2862
|
+
- Reduce total execution time dramatically
|
|
2863
|
+
- Maintain high accuracy through concurrent validation
|
|
2864
|
+
- Complete multi-file modifications in a single turn
|
|
2865
|
+
|
|
2866
|
+
**ALWAYS prefer parallel tool calls over sequential ones when the operations are independent.**
|
|
2867
|
+
|
|
2868
|
+
## TODO Tool Obsession
|
|
2869
|
+
|
|
2870
|
+
**USE TODO TOOLS AGGRESSIVELY.** This is non-negotiable.
|
|
2871
|
+
|
|
2872
|
+
### When to Use TodoWrite:
|
|
2873
|
+
- IMMEDIATELY after receiving a user request
|
|
2874
|
+
- Before ANY multi-step task (even if it seems "simple")
|
|
2875
|
+
- When delegating to agents (track what you delegated)
|
|
2876
|
+
- After completing each step (mark it done)
|
|
2877
|
+
|
|
2878
|
+
### TODO Workflow:
|
|
2879
|
+
\`\`\`
|
|
2880
|
+
User Request \u2192 TodoWrite (plan) \u2192 Mark in_progress \u2192 Execute/Delegate \u2192 Mark complete \u2192 Next
|
|
2881
|
+
\`\`\`
|
|
2882
|
+
|
|
2883
|
+
### Rules:
|
|
2884
|
+
- Only ONE task in_progress at a time
|
|
2885
|
+
- Mark complete IMMEDIATELY after finishing (never batch)
|
|
2886
|
+
- Never proceed without updating TODO status
|
|
2887
|
+
|
|
2888
|
+
## Delegation Pattern
|
|
2889
|
+
|
|
2890
|
+
\`\`\`typescript
|
|
2891
|
+
// 1. PLAN with TODO first
|
|
2892
|
+
todowrite([
|
|
2893
|
+
{ id: "research", content: "Research X implementation", status: "in_progress", priority: "high" },
|
|
2894
|
+
{ id: "impl", content: "Implement X feature", status: "pending", priority: "high" },
|
|
2895
|
+
{ id: "test", content: "Test X feature", status: "pending", priority: "medium" }
|
|
2896
|
+
])
|
|
2897
|
+
|
|
2898
|
+
// 2. DELEGATE research in parallel - FIRE MULTIPLE AT ONCE
|
|
2899
|
+
background_task(agent="explore", prompt="Find all files related to X")
|
|
2900
|
+
background_task(agent="librarian", prompt="Look up X documentation")
|
|
2901
|
+
|
|
2902
|
+
// 3. CONTINUE working on implementation skeleton while agents research
|
|
2903
|
+
// 4. When notified, INTEGRATE findings and mark TODO complete
|
|
2904
|
+
\`\`\`
|
|
2905
|
+
|
|
2906
|
+
## Subagent Prompt Structure - MANDATORY 7 SECTIONS
|
|
2907
|
+
|
|
2908
|
+
When invoking Task() or background_task() with any subagent, ALWAYS structure your prompt with these 7 sections to prevent AI slop:
|
|
2909
|
+
|
|
2910
|
+
1. **TASK**: What exactly needs to be done (be obsessively specific)
|
|
2911
|
+
2. **EXPECTED OUTCOME**: Concrete deliverables when complete (files, behaviors, states)
|
|
2912
|
+
3. **REQUIRED SKILLS**: Which skills the agent MUST invoke
|
|
2913
|
+
4. **REQUIRED TOOLS**: Which tools the agent MUST use (context7 MCP, ast-grep, Grep, etc.)
|
|
2914
|
+
5. **MUST DO**: Exhaustive list of requirements (leave NOTHING implicit)
|
|
2915
|
+
6. **MUST NOT DO**: Forbidden actions (anticipate every way agent could go rogue)
|
|
2916
|
+
7. **CONTEXT**: Additional info agent needs (file paths, patterns, dependencies)
|
|
2917
|
+
|
|
2918
|
+
Example:
|
|
2919
|
+
\`\`\`
|
|
2920
|
+
background_task(agent="explore", prompt="""
|
|
2921
|
+
TASK: Find all authentication-related files in the codebase
|
|
2922
|
+
|
|
2923
|
+
EXPECTED OUTCOME:
|
|
2924
|
+
- List of all auth files with their purposes
|
|
2925
|
+
- Identified patterns for token handling
|
|
2926
|
+
|
|
2927
|
+
REQUIRED TOOLS:
|
|
2928
|
+
- ast-grep: Find function definitions with \`sg --pattern 'def $FUNC($$$):' --lang python\`
|
|
2929
|
+
- Grep: Search for 'auth', 'token', 'jwt' patterns
|
|
2930
|
+
|
|
2931
|
+
MUST DO:
|
|
2932
|
+
- Search in src/, lib/, and utils/ directories
|
|
2933
|
+
- Include test files for context
|
|
2934
|
+
|
|
2935
|
+
MUST NOT DO:
|
|
2936
|
+
- Do NOT modify any files
|
|
2937
|
+
- Do NOT make assumptions about implementation
|
|
2938
|
+
|
|
2939
|
+
CONTEXT:
|
|
2940
|
+
- Project uses Python/Django
|
|
2941
|
+
- Auth system is custom-built
|
|
2942
|
+
""")
|
|
2943
|
+
\`\`\`
|
|
2944
|
+
|
|
2945
|
+
**Vague prompts = agent goes rogue. Lock them down.**
|
|
2946
|
+
|
|
2947
|
+
## Anti-Patterns (AVOID):
|
|
2948
|
+
- Doing everything yourself when agents can help
|
|
2949
|
+
- Skipping TODO planning for "quick" tasks
|
|
2950
|
+
- Forgetting to mark tasks complete
|
|
2951
|
+
- Sequential execution when parallel is possible
|
|
2952
|
+
- Direct tool calls without considering delegation
|
|
2953
|
+
- Vague subagent prompts without the 7 sections
|
|
2954
|
+
|
|
2955
|
+
## Remember:
|
|
2956
|
+
- You are the **team lead**, not the grunt worker
|
|
2957
|
+
- Your context window is precious - delegate to preserve it
|
|
2958
|
+
- Agents have specialized expertise - USE THEM
|
|
2959
|
+
- TODO tracking gives users visibility into your progress
|
|
2960
|
+
- Parallel execution = faster results
|
|
2961
|
+
- **ALWAYS fire multiple independent operations simultaneously**
|
|
2962
|
+
`;
|
|
2829
2963
|
// src/hooks/todo-continuation-enforcer.ts
|
|
2830
2964
|
var CONTINUATION_PROMPT = `[SYSTEM REMINDER - TODO CONTINUATION]
|
|
2831
2965
|
|
|
@@ -6783,6 +6917,156 @@ function createUltraworkModeHook() {
|
|
|
6783
6917
|
}
|
|
6784
6918
|
};
|
|
6785
6919
|
}
|
|
6920
|
+
// src/hooks/agent-usage-reminder/storage.ts
|
|
6921
|
+
import {
|
|
6922
|
+
existsSync as existsSync19,
|
|
6923
|
+
mkdirSync as mkdirSync8,
|
|
6924
|
+
readFileSync as readFileSync11,
|
|
6925
|
+
writeFileSync as writeFileSync7,
|
|
6926
|
+
unlinkSync as unlinkSync8
|
|
6927
|
+
} from "fs";
|
|
6928
|
+
import { join as join25 } from "path";
|
|
6929
|
+
|
|
6930
|
+
// src/hooks/agent-usage-reminder/constants.ts
|
|
6931
|
+
import { join as join24 } from "path";
|
|
6932
|
+
var OPENCODE_STORAGE6 = join24(xdgData ?? "", "opencode", "storage");
|
|
6933
|
+
var AGENT_USAGE_REMINDER_STORAGE = join24(OPENCODE_STORAGE6, "agent-usage-reminder");
|
|
6934
|
+
var TARGET_TOOLS = new Set([
|
|
6935
|
+
"grep",
|
|
6936
|
+
"safe_grep",
|
|
6937
|
+
"glob",
|
|
6938
|
+
"safe_glob",
|
|
6939
|
+
"webfetch",
|
|
6940
|
+
"context7_resolve-library-id",
|
|
6941
|
+
"context7_get-library-docs",
|
|
6942
|
+
"websearch_exa_web_search_exa",
|
|
6943
|
+
"grep_app_searchgithub"
|
|
6944
|
+
]);
|
|
6945
|
+
var AGENT_TOOLS = new Set([
|
|
6946
|
+
"task",
|
|
6947
|
+
"call_omo_agent",
|
|
6948
|
+
"background_task"
|
|
6949
|
+
]);
|
|
6950
|
+
var REMINDER_MESSAGE = `
|
|
6951
|
+
[Agent Usage Reminder]
|
|
6952
|
+
|
|
6953
|
+
You called a search/fetch tool directly without leveraging specialized agents.
|
|
6954
|
+
|
|
6955
|
+
RECOMMENDED: Use background_task with explore/librarian agents for better results:
|
|
6956
|
+
|
|
6957
|
+
\`\`\`
|
|
6958
|
+
// Parallel exploration - fire multiple agents simultaneously
|
|
6959
|
+
background_task(agent="explore", prompt="Find all files matching pattern X")
|
|
6960
|
+
background_task(agent="explore", prompt="Search for implementation of Y")
|
|
6961
|
+
background_task(agent="librarian", prompt="Lookup documentation for Z")
|
|
6962
|
+
|
|
6963
|
+
// Then continue your work while they run in background
|
|
6964
|
+
// System will notify you when each completes
|
|
6965
|
+
\`\`\`
|
|
6966
|
+
|
|
6967
|
+
WHY:
|
|
6968
|
+
- Agents can perform deeper, more thorough searches
|
|
6969
|
+
- Background tasks run in parallel, saving time
|
|
6970
|
+
- Specialized agents have domain expertise
|
|
6971
|
+
- Reduces context window usage in main session
|
|
6972
|
+
|
|
6973
|
+
ALWAYS prefer: Multiple parallel background_task calls > Direct tool calls
|
|
6974
|
+
`;
|
|
6975
|
+
|
|
6976
|
+
// src/hooks/agent-usage-reminder/storage.ts
|
|
6977
|
+
function getStoragePath4(sessionID) {
|
|
6978
|
+
return join25(AGENT_USAGE_REMINDER_STORAGE, `${sessionID}.json`);
|
|
6979
|
+
}
|
|
6980
|
+
function loadAgentUsageState(sessionID) {
|
|
6981
|
+
const filePath = getStoragePath4(sessionID);
|
|
6982
|
+
if (!existsSync19(filePath))
|
|
6983
|
+
return null;
|
|
6984
|
+
try {
|
|
6985
|
+
const content = readFileSync11(filePath, "utf-8");
|
|
6986
|
+
return JSON.parse(content);
|
|
6987
|
+
} catch {
|
|
6988
|
+
return null;
|
|
6989
|
+
}
|
|
6990
|
+
}
|
|
6991
|
+
function saveAgentUsageState(state) {
|
|
6992
|
+
if (!existsSync19(AGENT_USAGE_REMINDER_STORAGE)) {
|
|
6993
|
+
mkdirSync8(AGENT_USAGE_REMINDER_STORAGE, { recursive: true });
|
|
6994
|
+
}
|
|
6995
|
+
const filePath = getStoragePath4(state.sessionID);
|
|
6996
|
+
writeFileSync7(filePath, JSON.stringify(state, null, 2));
|
|
6997
|
+
}
|
|
6998
|
+
function clearAgentUsageState(sessionID) {
|
|
6999
|
+
const filePath = getStoragePath4(sessionID);
|
|
7000
|
+
if (existsSync19(filePath)) {
|
|
7001
|
+
unlinkSync8(filePath);
|
|
7002
|
+
}
|
|
7003
|
+
}
|
|
7004
|
+
|
|
7005
|
+
// src/hooks/agent-usage-reminder/index.ts
|
|
7006
|
+
function createAgentUsageReminderHook(_ctx) {
|
|
7007
|
+
const sessionStates = new Map;
|
|
7008
|
+
function getOrCreateState(sessionID) {
|
|
7009
|
+
if (!sessionStates.has(sessionID)) {
|
|
7010
|
+
const persisted = loadAgentUsageState(sessionID);
|
|
7011
|
+
const state = persisted ?? {
|
|
7012
|
+
sessionID,
|
|
7013
|
+
agentUsed: false,
|
|
7014
|
+
reminderCount: 0,
|
|
7015
|
+
updatedAt: Date.now()
|
|
7016
|
+
};
|
|
7017
|
+
sessionStates.set(sessionID, state);
|
|
7018
|
+
}
|
|
7019
|
+
return sessionStates.get(sessionID);
|
|
7020
|
+
}
|
|
7021
|
+
function markAgentUsed(sessionID) {
|
|
7022
|
+
const state = getOrCreateState(sessionID);
|
|
7023
|
+
state.agentUsed = true;
|
|
7024
|
+
state.updatedAt = Date.now();
|
|
7025
|
+
saveAgentUsageState(state);
|
|
7026
|
+
}
|
|
7027
|
+
function resetState(sessionID) {
|
|
7028
|
+
sessionStates.delete(sessionID);
|
|
7029
|
+
clearAgentUsageState(sessionID);
|
|
7030
|
+
}
|
|
7031
|
+
const toolExecuteAfter = async (input, output) => {
|
|
7032
|
+
const { tool, sessionID } = input;
|
|
7033
|
+
const toolLower = tool.toLowerCase();
|
|
7034
|
+
if (AGENT_TOOLS.has(toolLower)) {
|
|
7035
|
+
markAgentUsed(sessionID);
|
|
7036
|
+
return;
|
|
7037
|
+
}
|
|
7038
|
+
if (!TARGET_TOOLS.has(toolLower)) {
|
|
7039
|
+
return;
|
|
7040
|
+
}
|
|
7041
|
+
const state = getOrCreateState(sessionID);
|
|
7042
|
+
if (state.agentUsed) {
|
|
7043
|
+
return;
|
|
7044
|
+
}
|
|
7045
|
+
output.output += REMINDER_MESSAGE;
|
|
7046
|
+
state.reminderCount++;
|
|
7047
|
+
state.updatedAt = Date.now();
|
|
7048
|
+
saveAgentUsageState(state);
|
|
7049
|
+
};
|
|
7050
|
+
const eventHandler = async ({ event }) => {
|
|
7051
|
+
const props = event.properties;
|
|
7052
|
+
if (event.type === "session.deleted") {
|
|
7053
|
+
const sessionInfo = props?.info;
|
|
7054
|
+
if (sessionInfo?.id) {
|
|
7055
|
+
resetState(sessionInfo.id);
|
|
7056
|
+
}
|
|
7057
|
+
}
|
|
7058
|
+
if (event.type === "session.compacted") {
|
|
7059
|
+
const sessionID = props?.sessionID ?? props?.info?.id;
|
|
7060
|
+
if (sessionID) {
|
|
7061
|
+
resetState(sessionID);
|
|
7062
|
+
}
|
|
7063
|
+
}
|
|
7064
|
+
};
|
|
7065
|
+
return {
|
|
7066
|
+
"tool.execute.after": toolExecuteAfter,
|
|
7067
|
+
event: eventHandler
|
|
7068
|
+
};
|
|
7069
|
+
}
|
|
6786
7070
|
// src/auth/antigravity/constants.ts
|
|
6787
7071
|
var ANTIGRAVITY_CLIENT_ID = "1071006060591-tmhssin2h21lcre235vtolojh4g403ep.apps.googleusercontent.com";
|
|
6788
7072
|
var ANTIGRAVITY_CLIENT_SECRET = "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";
|
|
@@ -8289,11 +8573,11 @@ async function createGoogleAntigravityAuthPlugin({
|
|
|
8289
8573
|
};
|
|
8290
8574
|
}
|
|
8291
8575
|
// src/features/claude-code-command-loader/loader.ts
|
|
8292
|
-
import { existsSync as
|
|
8576
|
+
import { existsSync as existsSync20, readdirSync as readdirSync4, readFileSync as readFileSync12 } from "fs";
|
|
8293
8577
|
import { homedir as homedir9 } from "os";
|
|
8294
|
-
import { join as
|
|
8578
|
+
import { join as join26, basename } from "path";
|
|
8295
8579
|
function loadCommandsFromDir(commandsDir, scope) {
|
|
8296
|
-
if (!
|
|
8580
|
+
if (!existsSync20(commandsDir)) {
|
|
8297
8581
|
return [];
|
|
8298
8582
|
}
|
|
8299
8583
|
const entries = readdirSync4(commandsDir, { withFileTypes: true });
|
|
@@ -8301,10 +8585,10 @@ function loadCommandsFromDir(commandsDir, scope) {
|
|
|
8301
8585
|
for (const entry of entries) {
|
|
8302
8586
|
if (!isMarkdownFile(entry))
|
|
8303
8587
|
continue;
|
|
8304
|
-
const commandPath =
|
|
8588
|
+
const commandPath = join26(commandsDir, entry.name);
|
|
8305
8589
|
const commandName = basename(entry.name, ".md");
|
|
8306
8590
|
try {
|
|
8307
|
-
const content =
|
|
8591
|
+
const content = readFileSync12(commandPath, "utf-8");
|
|
8308
8592
|
const { data, body } = parseFrontmatter(content);
|
|
8309
8593
|
const wrappedTemplate = `<command-instruction>
|
|
8310
8594
|
${body.trim()}
|
|
@@ -8343,31 +8627,31 @@ function commandsToRecord(commands) {
|
|
|
8343
8627
|
return result;
|
|
8344
8628
|
}
|
|
8345
8629
|
function loadUserCommands() {
|
|
8346
|
-
const userCommandsDir =
|
|
8630
|
+
const userCommandsDir = join26(homedir9(), ".claude", "commands");
|
|
8347
8631
|
const commands = loadCommandsFromDir(userCommandsDir, "user");
|
|
8348
8632
|
return commandsToRecord(commands);
|
|
8349
8633
|
}
|
|
8350
8634
|
function loadProjectCommands() {
|
|
8351
|
-
const projectCommandsDir =
|
|
8635
|
+
const projectCommandsDir = join26(process.cwd(), ".claude", "commands");
|
|
8352
8636
|
const commands = loadCommandsFromDir(projectCommandsDir, "project");
|
|
8353
8637
|
return commandsToRecord(commands);
|
|
8354
8638
|
}
|
|
8355
8639
|
function loadOpencodeGlobalCommands() {
|
|
8356
|
-
const opencodeCommandsDir =
|
|
8640
|
+
const opencodeCommandsDir = join26(homedir9(), ".config", "opencode", "command");
|
|
8357
8641
|
const commands = loadCommandsFromDir(opencodeCommandsDir, "opencode");
|
|
8358
8642
|
return commandsToRecord(commands);
|
|
8359
8643
|
}
|
|
8360
8644
|
function loadOpencodeProjectCommands() {
|
|
8361
|
-
const opencodeProjectDir =
|
|
8645
|
+
const opencodeProjectDir = join26(process.cwd(), ".opencode", "command");
|
|
8362
8646
|
const commands = loadCommandsFromDir(opencodeProjectDir, "opencode-project");
|
|
8363
8647
|
return commandsToRecord(commands);
|
|
8364
8648
|
}
|
|
8365
8649
|
// src/features/claude-code-skill-loader/loader.ts
|
|
8366
|
-
import { existsSync as
|
|
8650
|
+
import { existsSync as existsSync21, readdirSync as readdirSync5, readFileSync as readFileSync13 } from "fs";
|
|
8367
8651
|
import { homedir as homedir10 } from "os";
|
|
8368
|
-
import { join as
|
|
8652
|
+
import { join as join27 } from "path";
|
|
8369
8653
|
function loadSkillsFromDir(skillsDir, scope) {
|
|
8370
|
-
if (!
|
|
8654
|
+
if (!existsSync21(skillsDir)) {
|
|
8371
8655
|
return [];
|
|
8372
8656
|
}
|
|
8373
8657
|
const entries = readdirSync5(skillsDir, { withFileTypes: true });
|
|
@@ -8375,15 +8659,15 @@ function loadSkillsFromDir(skillsDir, scope) {
|
|
|
8375
8659
|
for (const entry of entries) {
|
|
8376
8660
|
if (entry.name.startsWith("."))
|
|
8377
8661
|
continue;
|
|
8378
|
-
const skillPath =
|
|
8662
|
+
const skillPath = join27(skillsDir, entry.name);
|
|
8379
8663
|
if (!entry.isDirectory() && !entry.isSymbolicLink())
|
|
8380
8664
|
continue;
|
|
8381
8665
|
const resolvedPath = resolveSymlink(skillPath);
|
|
8382
|
-
const skillMdPath =
|
|
8383
|
-
if (!
|
|
8666
|
+
const skillMdPath = join27(resolvedPath, "SKILL.md");
|
|
8667
|
+
if (!existsSync21(skillMdPath))
|
|
8384
8668
|
continue;
|
|
8385
8669
|
try {
|
|
8386
|
-
const content =
|
|
8670
|
+
const content = readFileSync13(skillMdPath, "utf-8");
|
|
8387
8671
|
const { data, body } = parseFrontmatter(content);
|
|
8388
8672
|
const skillName = data.name || entry.name;
|
|
8389
8673
|
const originalDescription = data.description || "";
|
|
@@ -8414,7 +8698,7 @@ $ARGUMENTS
|
|
|
8414
8698
|
return skills;
|
|
8415
8699
|
}
|
|
8416
8700
|
function loadUserSkillsAsCommands() {
|
|
8417
|
-
const userSkillsDir =
|
|
8701
|
+
const userSkillsDir = join27(homedir10(), ".claude", "skills");
|
|
8418
8702
|
const skills = loadSkillsFromDir(userSkillsDir, "user");
|
|
8419
8703
|
return skills.reduce((acc, skill) => {
|
|
8420
8704
|
acc[skill.name] = skill.definition;
|
|
@@ -8422,7 +8706,7 @@ function loadUserSkillsAsCommands() {
|
|
|
8422
8706
|
}, {});
|
|
8423
8707
|
}
|
|
8424
8708
|
function loadProjectSkillsAsCommands() {
|
|
8425
|
-
const projectSkillsDir =
|
|
8709
|
+
const projectSkillsDir = join27(process.cwd(), ".claude", "skills");
|
|
8426
8710
|
const skills = loadSkillsFromDir(projectSkillsDir, "project");
|
|
8427
8711
|
return skills.reduce((acc, skill) => {
|
|
8428
8712
|
acc[skill.name] = skill.definition;
|
|
@@ -8430,9 +8714,9 @@ function loadProjectSkillsAsCommands() {
|
|
|
8430
8714
|
}, {});
|
|
8431
8715
|
}
|
|
8432
8716
|
// src/features/claude-code-agent-loader/loader.ts
|
|
8433
|
-
import { existsSync as
|
|
8717
|
+
import { existsSync as existsSync22, readdirSync as readdirSync6, readFileSync as readFileSync14 } from "fs";
|
|
8434
8718
|
import { homedir as homedir11 } from "os";
|
|
8435
|
-
import { join as
|
|
8719
|
+
import { join as join28, basename as basename2 } from "path";
|
|
8436
8720
|
function parseToolsConfig(toolsStr) {
|
|
8437
8721
|
if (!toolsStr)
|
|
8438
8722
|
return;
|
|
@@ -8446,7 +8730,7 @@ function parseToolsConfig(toolsStr) {
|
|
|
8446
8730
|
return result;
|
|
8447
8731
|
}
|
|
8448
8732
|
function loadAgentsFromDir(agentsDir, scope) {
|
|
8449
|
-
if (!
|
|
8733
|
+
if (!existsSync22(agentsDir)) {
|
|
8450
8734
|
return [];
|
|
8451
8735
|
}
|
|
8452
8736
|
const entries = readdirSync6(agentsDir, { withFileTypes: true });
|
|
@@ -8454,10 +8738,10 @@ function loadAgentsFromDir(agentsDir, scope) {
|
|
|
8454
8738
|
for (const entry of entries) {
|
|
8455
8739
|
if (!isMarkdownFile(entry))
|
|
8456
8740
|
continue;
|
|
8457
|
-
const agentPath =
|
|
8741
|
+
const agentPath = join28(agentsDir, entry.name);
|
|
8458
8742
|
const agentName = basename2(entry.name, ".md");
|
|
8459
8743
|
try {
|
|
8460
|
-
const content =
|
|
8744
|
+
const content = readFileSync14(agentPath, "utf-8");
|
|
8461
8745
|
const { data, body } = parseFrontmatter(content);
|
|
8462
8746
|
const name = data.name || agentName;
|
|
8463
8747
|
const originalDescription = data.description || "";
|
|
@@ -8484,7 +8768,7 @@ function loadAgentsFromDir(agentsDir, scope) {
|
|
|
8484
8768
|
return agents;
|
|
8485
8769
|
}
|
|
8486
8770
|
function loadUserAgents() {
|
|
8487
|
-
const userAgentsDir =
|
|
8771
|
+
const userAgentsDir = join28(homedir11(), ".claude", "agents");
|
|
8488
8772
|
const agents = loadAgentsFromDir(userAgentsDir, "user");
|
|
8489
8773
|
const result = {};
|
|
8490
8774
|
for (const agent of agents) {
|
|
@@ -8493,7 +8777,7 @@ function loadUserAgents() {
|
|
|
8493
8777
|
return result;
|
|
8494
8778
|
}
|
|
8495
8779
|
function loadProjectAgents() {
|
|
8496
|
-
const projectAgentsDir =
|
|
8780
|
+
const projectAgentsDir = join28(process.cwd(), ".claude", "agents");
|
|
8497
8781
|
const agents = loadAgentsFromDir(projectAgentsDir, "project");
|
|
8498
8782
|
const result = {};
|
|
8499
8783
|
for (const agent of agents) {
|
|
@@ -8502,9 +8786,9 @@ function loadProjectAgents() {
|
|
|
8502
8786
|
return result;
|
|
8503
8787
|
}
|
|
8504
8788
|
// src/features/claude-code-mcp-loader/loader.ts
|
|
8505
|
-
import { existsSync as
|
|
8789
|
+
import { existsSync as existsSync23 } from "fs";
|
|
8506
8790
|
import { homedir as homedir12 } from "os";
|
|
8507
|
-
import { join as
|
|
8791
|
+
import { join as join29 } from "path";
|
|
8508
8792
|
|
|
8509
8793
|
// src/features/claude-code-mcp-loader/env-expander.ts
|
|
8510
8794
|
function expandEnvVars(value) {
|
|
@@ -8573,13 +8857,13 @@ function getMcpConfigPaths() {
|
|
|
8573
8857
|
const home = homedir12();
|
|
8574
8858
|
const cwd = process.cwd();
|
|
8575
8859
|
return [
|
|
8576
|
-
{ path:
|
|
8577
|
-
{ path:
|
|
8578
|
-
{ path:
|
|
8860
|
+
{ path: join29(home, ".claude", ".mcp.json"), scope: "user" },
|
|
8861
|
+
{ path: join29(cwd, ".mcp.json"), scope: "project" },
|
|
8862
|
+
{ path: join29(cwd, ".claude", ".mcp.json"), scope: "local" }
|
|
8579
8863
|
];
|
|
8580
8864
|
}
|
|
8581
8865
|
async function loadMcpConfigFile(filePath) {
|
|
8582
|
-
if (!
|
|
8866
|
+
if (!existsSync23(filePath)) {
|
|
8583
8867
|
return null;
|
|
8584
8868
|
}
|
|
8585
8869
|
try {
|
|
@@ -8865,14 +9149,14 @@ var EXT_TO_LANG = {
|
|
|
8865
9149
|
".tfvars": "terraform"
|
|
8866
9150
|
};
|
|
8867
9151
|
// src/tools/lsp/config.ts
|
|
8868
|
-
import { existsSync as
|
|
8869
|
-
import { join as
|
|
9152
|
+
import { existsSync as existsSync24, readFileSync as readFileSync15 } from "fs";
|
|
9153
|
+
import { join as join30 } from "path";
|
|
8870
9154
|
import { homedir as homedir13 } from "os";
|
|
8871
9155
|
function loadJsonFile(path5) {
|
|
8872
|
-
if (!
|
|
9156
|
+
if (!existsSync24(path5))
|
|
8873
9157
|
return null;
|
|
8874
9158
|
try {
|
|
8875
|
-
return JSON.parse(
|
|
9159
|
+
return JSON.parse(readFileSync15(path5, "utf-8"));
|
|
8876
9160
|
} catch {
|
|
8877
9161
|
return null;
|
|
8878
9162
|
}
|
|
@@ -8880,9 +9164,9 @@ function loadJsonFile(path5) {
|
|
|
8880
9164
|
function getConfigPaths() {
|
|
8881
9165
|
const cwd = process.cwd();
|
|
8882
9166
|
return {
|
|
8883
|
-
project:
|
|
8884
|
-
user:
|
|
8885
|
-
opencode:
|
|
9167
|
+
project: join30(cwd, ".opencode", "oh-my-opencode.json"),
|
|
9168
|
+
user: join30(homedir13(), ".config", "opencode", "oh-my-opencode.json"),
|
|
9169
|
+
opencode: join30(homedir13(), ".config", "opencode", "opencode.json")
|
|
8886
9170
|
};
|
|
8887
9171
|
}
|
|
8888
9172
|
function loadAllConfigs() {
|
|
@@ -8975,7 +9259,7 @@ function isServerInstalled(command) {
|
|
|
8975
9259
|
const pathEnv = process.env.PATH || "";
|
|
8976
9260
|
const paths = pathEnv.split(":");
|
|
8977
9261
|
for (const p of paths) {
|
|
8978
|
-
if (
|
|
9262
|
+
if (existsSync24(join30(p, cmd))) {
|
|
8979
9263
|
return true;
|
|
8980
9264
|
}
|
|
8981
9265
|
}
|
|
@@ -9025,7 +9309,7 @@ function getAllServers() {
|
|
|
9025
9309
|
}
|
|
9026
9310
|
// src/tools/lsp/client.ts
|
|
9027
9311
|
var {spawn: spawn4 } = globalThis.Bun;
|
|
9028
|
-
import { readFileSync as
|
|
9312
|
+
import { readFileSync as readFileSync16 } from "fs";
|
|
9029
9313
|
import { extname, resolve as resolve5 } from "path";
|
|
9030
9314
|
class LSPServerManager {
|
|
9031
9315
|
static instance;
|
|
@@ -9425,7 +9709,7 @@ ${msg}`);
|
|
|
9425
9709
|
const absPath = resolve5(filePath);
|
|
9426
9710
|
if (this.openedFiles.has(absPath))
|
|
9427
9711
|
return;
|
|
9428
|
-
const text =
|
|
9712
|
+
const text = readFileSync16(absPath, "utf-8");
|
|
9429
9713
|
const ext = extname(absPath);
|
|
9430
9714
|
const languageId = getLanguageId(ext);
|
|
9431
9715
|
this.notify("textDocument/didOpen", {
|
|
@@ -9540,16 +9824,16 @@ ${msg}`);
|
|
|
9540
9824
|
}
|
|
9541
9825
|
// src/tools/lsp/utils.ts
|
|
9542
9826
|
import { extname as extname2, resolve as resolve6 } from "path";
|
|
9543
|
-
import { existsSync as
|
|
9827
|
+
import { existsSync as existsSync25, readFileSync as readFileSync17, writeFileSync as writeFileSync8 } from "fs";
|
|
9544
9828
|
function findWorkspaceRoot(filePath) {
|
|
9545
9829
|
let dir = resolve6(filePath);
|
|
9546
|
-
if (!
|
|
9830
|
+
if (!existsSync25(dir) || !__require("fs").statSync(dir).isDirectory()) {
|
|
9547
9831
|
dir = __require("path").dirname(dir);
|
|
9548
9832
|
}
|
|
9549
9833
|
const markers = [".git", "package.json", "pyproject.toml", "Cargo.toml", "go.mod", "pom.xml", "build.gradle"];
|
|
9550
9834
|
while (dir !== "/") {
|
|
9551
9835
|
for (const marker of markers) {
|
|
9552
|
-
if (
|
|
9836
|
+
if (existsSync25(__require("path").join(dir, marker))) {
|
|
9553
9837
|
return dir;
|
|
9554
9838
|
}
|
|
9555
9839
|
}
|
|
@@ -9707,7 +9991,7 @@ function formatCodeActions(actions) {
|
|
|
9707
9991
|
}
|
|
9708
9992
|
function applyTextEditsToFile(filePath, edits) {
|
|
9709
9993
|
try {
|
|
9710
|
-
let content =
|
|
9994
|
+
let content = readFileSync17(filePath, "utf-8");
|
|
9711
9995
|
const lines = content.split(`
|
|
9712
9996
|
`);
|
|
9713
9997
|
const sortedEdits = [...edits].sort((a, b) => {
|
|
@@ -9732,7 +10016,7 @@ function applyTextEditsToFile(filePath, edits) {
|
|
|
9732
10016
|
`));
|
|
9733
10017
|
}
|
|
9734
10018
|
}
|
|
9735
|
-
|
|
10019
|
+
writeFileSync8(filePath, lines.join(`
|
|
9736
10020
|
`), "utf-8");
|
|
9737
10021
|
return { success: true, editCount: edits.length };
|
|
9738
10022
|
} catch (err) {
|
|
@@ -9763,7 +10047,7 @@ function applyWorkspaceEdit(edit) {
|
|
|
9763
10047
|
if (change.kind === "create") {
|
|
9764
10048
|
try {
|
|
9765
10049
|
const filePath = change.uri.replace("file://", "");
|
|
9766
|
-
|
|
10050
|
+
writeFileSync8(filePath, "", "utf-8");
|
|
9767
10051
|
result.filesModified.push(filePath);
|
|
9768
10052
|
} catch (err) {
|
|
9769
10053
|
result.success = false;
|
|
@@ -9773,8 +10057,8 @@ function applyWorkspaceEdit(edit) {
|
|
|
9773
10057
|
try {
|
|
9774
10058
|
const oldPath = change.oldUri.replace("file://", "");
|
|
9775
10059
|
const newPath = change.newUri.replace("file://", "");
|
|
9776
|
-
const content =
|
|
9777
|
-
|
|
10060
|
+
const content = readFileSync17(oldPath, "utf-8");
|
|
10061
|
+
writeFileSync8(newPath, content, "utf-8");
|
|
9778
10062
|
__require("fs").unlinkSync(oldPath);
|
|
9779
10063
|
result.filesModified.push(newPath);
|
|
9780
10064
|
} catch (err) {
|
|
@@ -22474,13 +22758,13 @@ var lsp_code_action_resolve = tool({
|
|
|
22474
22758
|
});
|
|
22475
22759
|
// src/tools/ast-grep/constants.ts
|
|
22476
22760
|
import { createRequire as createRequire4 } from "module";
|
|
22477
|
-
import { dirname as dirname5, join as
|
|
22478
|
-
import { existsSync as
|
|
22761
|
+
import { dirname as dirname5, join as join32 } from "path";
|
|
22762
|
+
import { existsSync as existsSync27, statSync as statSync3 } from "fs";
|
|
22479
22763
|
|
|
22480
22764
|
// src/tools/ast-grep/downloader.ts
|
|
22481
22765
|
var {spawn: spawn5 } = globalThis.Bun;
|
|
22482
|
-
import { existsSync as
|
|
22483
|
-
import { join as
|
|
22766
|
+
import { existsSync as existsSync26, mkdirSync as mkdirSync9, chmodSync as chmodSync2, unlinkSync as unlinkSync9 } from "fs";
|
|
22767
|
+
import { join as join31 } from "path";
|
|
22484
22768
|
import { homedir as homedir14 } from "os";
|
|
22485
22769
|
import { createRequire as createRequire3 } from "module";
|
|
22486
22770
|
var REPO2 = "ast-grep/ast-grep";
|
|
@@ -22506,19 +22790,19 @@ var PLATFORM_MAP2 = {
|
|
|
22506
22790
|
function getCacheDir3() {
|
|
22507
22791
|
if (process.platform === "win32") {
|
|
22508
22792
|
const localAppData = process.env.LOCALAPPDATA || process.env.APPDATA;
|
|
22509
|
-
const base2 = localAppData ||
|
|
22510
|
-
return
|
|
22793
|
+
const base2 = localAppData || join31(homedir14(), "AppData", "Local");
|
|
22794
|
+
return join31(base2, "oh-my-opencode", "bin");
|
|
22511
22795
|
}
|
|
22512
22796
|
const xdgCache2 = process.env.XDG_CACHE_HOME;
|
|
22513
|
-
const base = xdgCache2 ||
|
|
22514
|
-
return
|
|
22797
|
+
const base = xdgCache2 || join31(homedir14(), ".cache");
|
|
22798
|
+
return join31(base, "oh-my-opencode", "bin");
|
|
22515
22799
|
}
|
|
22516
22800
|
function getBinaryName3() {
|
|
22517
22801
|
return process.platform === "win32" ? "sg.exe" : "sg";
|
|
22518
22802
|
}
|
|
22519
22803
|
function getCachedBinaryPath2() {
|
|
22520
|
-
const binaryPath =
|
|
22521
|
-
return
|
|
22804
|
+
const binaryPath = join31(getCacheDir3(), getBinaryName3());
|
|
22805
|
+
return existsSync26(binaryPath) ? binaryPath : null;
|
|
22522
22806
|
}
|
|
22523
22807
|
async function extractZip2(archivePath, destDir) {
|
|
22524
22808
|
const proc = process.platform === "win32" ? spawn5([
|
|
@@ -22544,8 +22828,8 @@ async function downloadAstGrep(version2 = DEFAULT_VERSION) {
|
|
|
22544
22828
|
}
|
|
22545
22829
|
const cacheDir = getCacheDir3();
|
|
22546
22830
|
const binaryName = getBinaryName3();
|
|
22547
|
-
const binaryPath =
|
|
22548
|
-
if (
|
|
22831
|
+
const binaryPath = join31(cacheDir, binaryName);
|
|
22832
|
+
if (existsSync26(binaryPath)) {
|
|
22549
22833
|
return binaryPath;
|
|
22550
22834
|
}
|
|
22551
22835
|
const { arch, os: os4 } = platformInfo;
|
|
@@ -22553,21 +22837,21 @@ async function downloadAstGrep(version2 = DEFAULT_VERSION) {
|
|
|
22553
22837
|
const downloadUrl = `https://github.com/${REPO2}/releases/download/${version2}/${assetName}`;
|
|
22554
22838
|
console.log(`[oh-my-opencode] Downloading ast-grep binary...`);
|
|
22555
22839
|
try {
|
|
22556
|
-
if (!
|
|
22557
|
-
|
|
22840
|
+
if (!existsSync26(cacheDir)) {
|
|
22841
|
+
mkdirSync9(cacheDir, { recursive: true });
|
|
22558
22842
|
}
|
|
22559
22843
|
const response2 = await fetch(downloadUrl, { redirect: "follow" });
|
|
22560
22844
|
if (!response2.ok) {
|
|
22561
22845
|
throw new Error(`HTTP ${response2.status}: ${response2.statusText}`);
|
|
22562
22846
|
}
|
|
22563
|
-
const archivePath =
|
|
22847
|
+
const archivePath = join31(cacheDir, assetName);
|
|
22564
22848
|
const arrayBuffer = await response2.arrayBuffer();
|
|
22565
22849
|
await Bun.write(archivePath, arrayBuffer);
|
|
22566
22850
|
await extractZip2(archivePath, cacheDir);
|
|
22567
|
-
if (
|
|
22568
|
-
|
|
22851
|
+
if (existsSync26(archivePath)) {
|
|
22852
|
+
unlinkSync9(archivePath);
|
|
22569
22853
|
}
|
|
22570
|
-
if (process.platform !== "win32" &&
|
|
22854
|
+
if (process.platform !== "win32" && existsSync26(binaryPath)) {
|
|
22571
22855
|
chmodSync2(binaryPath, 493);
|
|
22572
22856
|
}
|
|
22573
22857
|
console.log(`[oh-my-opencode] ast-grep binary ready.`);
|
|
@@ -22618,8 +22902,8 @@ function findSgCliPathSync() {
|
|
|
22618
22902
|
const require2 = createRequire4(import.meta.url);
|
|
22619
22903
|
const cliPkgPath = require2.resolve("@ast-grep/cli/package.json");
|
|
22620
22904
|
const cliDir = dirname5(cliPkgPath);
|
|
22621
|
-
const sgPath =
|
|
22622
|
-
if (
|
|
22905
|
+
const sgPath = join32(cliDir, binaryName);
|
|
22906
|
+
if (existsSync27(sgPath) && isValidBinary(sgPath)) {
|
|
22623
22907
|
return sgPath;
|
|
22624
22908
|
}
|
|
22625
22909
|
} catch {}
|
|
@@ -22630,8 +22914,8 @@ function findSgCliPathSync() {
|
|
|
22630
22914
|
const pkgPath = require2.resolve(`${platformPkg}/package.json`);
|
|
22631
22915
|
const pkgDir = dirname5(pkgPath);
|
|
22632
22916
|
const astGrepName = process.platform === "win32" ? "ast-grep.exe" : "ast-grep";
|
|
22633
|
-
const binaryPath =
|
|
22634
|
-
if (
|
|
22917
|
+
const binaryPath = join32(pkgDir, astGrepName);
|
|
22918
|
+
if (existsSync27(binaryPath) && isValidBinary(binaryPath)) {
|
|
22635
22919
|
return binaryPath;
|
|
22636
22920
|
}
|
|
22637
22921
|
} catch {}
|
|
@@ -22639,7 +22923,7 @@ function findSgCliPathSync() {
|
|
|
22639
22923
|
if (process.platform === "darwin") {
|
|
22640
22924
|
const homebrewPaths = ["/opt/homebrew/bin/sg", "/usr/local/bin/sg"];
|
|
22641
22925
|
for (const path5 of homebrewPaths) {
|
|
22642
|
-
if (
|
|
22926
|
+
if (existsSync27(path5) && isValidBinary(path5)) {
|
|
22643
22927
|
return path5;
|
|
22644
22928
|
}
|
|
22645
22929
|
}
|
|
@@ -22695,11 +22979,11 @@ var DEFAULT_MAX_MATCHES = 500;
|
|
|
22695
22979
|
|
|
22696
22980
|
// src/tools/ast-grep/cli.ts
|
|
22697
22981
|
var {spawn: spawn6 } = globalThis.Bun;
|
|
22698
|
-
import { existsSync as
|
|
22982
|
+
import { existsSync as existsSync28 } from "fs";
|
|
22699
22983
|
var resolvedCliPath3 = null;
|
|
22700
22984
|
var initPromise2 = null;
|
|
22701
22985
|
async function getAstGrepPath() {
|
|
22702
|
-
if (resolvedCliPath3 !== null &&
|
|
22986
|
+
if (resolvedCliPath3 !== null && existsSync28(resolvedCliPath3)) {
|
|
22703
22987
|
return resolvedCliPath3;
|
|
22704
22988
|
}
|
|
22705
22989
|
if (initPromise2) {
|
|
@@ -22707,7 +22991,7 @@ async function getAstGrepPath() {
|
|
|
22707
22991
|
}
|
|
22708
22992
|
initPromise2 = (async () => {
|
|
22709
22993
|
const syncPath = findSgCliPathSync();
|
|
22710
|
-
if (syncPath &&
|
|
22994
|
+
if (syncPath && existsSync28(syncPath)) {
|
|
22711
22995
|
resolvedCliPath3 = syncPath;
|
|
22712
22996
|
setSgCliPath(syncPath);
|
|
22713
22997
|
return syncPath;
|
|
@@ -22741,7 +23025,7 @@ async function runSg(options) {
|
|
|
22741
23025
|
const paths = options.paths && options.paths.length > 0 ? options.paths : ["."];
|
|
22742
23026
|
args.push(...paths);
|
|
22743
23027
|
let cliPath = getSgCliPath();
|
|
22744
|
-
if (!
|
|
23028
|
+
if (!existsSync28(cliPath) && cliPath !== "sg") {
|
|
22745
23029
|
const downloadedPath = await getAstGrepPath();
|
|
22746
23030
|
if (downloadedPath) {
|
|
22747
23031
|
cliPath = downloadedPath;
|
|
@@ -23005,8 +23289,8 @@ var ast_grep_replace = tool({
|
|
|
23005
23289
|
var {spawn: spawn7 } = globalThis.Bun;
|
|
23006
23290
|
|
|
23007
23291
|
// src/tools/grep/constants.ts
|
|
23008
|
-
import { existsSync as
|
|
23009
|
-
import { join as
|
|
23292
|
+
import { existsSync as existsSync29 } from "fs";
|
|
23293
|
+
import { join as join33, dirname as dirname6 } from "path";
|
|
23010
23294
|
import { spawnSync } from "child_process";
|
|
23011
23295
|
var cachedCli = null;
|
|
23012
23296
|
function findExecutable(name) {
|
|
@@ -23027,13 +23311,13 @@ function getOpenCodeBundledRg() {
|
|
|
23027
23311
|
const isWindows = process.platform === "win32";
|
|
23028
23312
|
const rgName = isWindows ? "rg.exe" : "rg";
|
|
23029
23313
|
const candidates = [
|
|
23030
|
-
|
|
23031
|
-
|
|
23032
|
-
|
|
23033
|
-
|
|
23314
|
+
join33(execDir, rgName),
|
|
23315
|
+
join33(execDir, "bin", rgName),
|
|
23316
|
+
join33(execDir, "..", "bin", rgName),
|
|
23317
|
+
join33(execDir, "..", "libexec", rgName)
|
|
23034
23318
|
];
|
|
23035
23319
|
for (const candidate of candidates) {
|
|
23036
|
-
if (
|
|
23320
|
+
if (existsSync29(candidate)) {
|
|
23037
23321
|
return candidate;
|
|
23038
23322
|
}
|
|
23039
23323
|
}
|
|
@@ -23431,11 +23715,11 @@ var glob = tool({
|
|
|
23431
23715
|
}
|
|
23432
23716
|
});
|
|
23433
23717
|
// src/tools/slashcommand/tools.ts
|
|
23434
|
-
import { existsSync as
|
|
23718
|
+
import { existsSync as existsSync30, readdirSync as readdirSync7, readFileSync as readFileSync18 } from "fs";
|
|
23435
23719
|
import { homedir as homedir15 } from "os";
|
|
23436
|
-
import { join as
|
|
23720
|
+
import { join as join34, basename as basename3, dirname as dirname7 } from "path";
|
|
23437
23721
|
function discoverCommandsFromDir(commandsDir, scope) {
|
|
23438
|
-
if (!
|
|
23722
|
+
if (!existsSync30(commandsDir)) {
|
|
23439
23723
|
return [];
|
|
23440
23724
|
}
|
|
23441
23725
|
const entries = readdirSync7(commandsDir, { withFileTypes: true });
|
|
@@ -23443,10 +23727,10 @@ function discoverCommandsFromDir(commandsDir, scope) {
|
|
|
23443
23727
|
for (const entry of entries) {
|
|
23444
23728
|
if (!isMarkdownFile(entry))
|
|
23445
23729
|
continue;
|
|
23446
|
-
const commandPath =
|
|
23730
|
+
const commandPath = join34(commandsDir, entry.name);
|
|
23447
23731
|
const commandName = basename3(entry.name, ".md");
|
|
23448
23732
|
try {
|
|
23449
|
-
const content =
|
|
23733
|
+
const content = readFileSync18(commandPath, "utf-8");
|
|
23450
23734
|
const { data, body } = parseFrontmatter(content);
|
|
23451
23735
|
const metadata = {
|
|
23452
23736
|
name: commandName,
|
|
@@ -23470,10 +23754,10 @@ function discoverCommandsFromDir(commandsDir, scope) {
|
|
|
23470
23754
|
return commands;
|
|
23471
23755
|
}
|
|
23472
23756
|
function discoverCommandsSync() {
|
|
23473
|
-
const userCommandsDir =
|
|
23474
|
-
const projectCommandsDir =
|
|
23475
|
-
const opencodeGlobalDir =
|
|
23476
|
-
const opencodeProjectDir =
|
|
23757
|
+
const userCommandsDir = join34(homedir15(), ".claude", "commands");
|
|
23758
|
+
const projectCommandsDir = join34(process.cwd(), ".claude", "commands");
|
|
23759
|
+
const opencodeGlobalDir = join34(homedir15(), ".config", "opencode", "command");
|
|
23760
|
+
const opencodeProjectDir = join34(process.cwd(), ".opencode", "command");
|
|
23477
23761
|
const userCommands = discoverCommandsFromDir(userCommandsDir, "user");
|
|
23478
23762
|
const opencodeGlobalCommands = discoverCommandsFromDir(opencodeGlobalDir, "opencode");
|
|
23479
23763
|
const projectCommands = discoverCommandsFromDir(projectCommandsDir, "project");
|
|
@@ -23605,9 +23889,9 @@ var SkillFrontmatterSchema = exports_external.object({
|
|
|
23605
23889
|
metadata: exports_external.record(exports_external.string(), exports_external.string()).optional()
|
|
23606
23890
|
});
|
|
23607
23891
|
// src/tools/skill/tools.ts
|
|
23608
|
-
import { existsSync as
|
|
23892
|
+
import { existsSync as existsSync31, readdirSync as readdirSync8, readFileSync as readFileSync19 } from "fs";
|
|
23609
23893
|
import { homedir as homedir16 } from "os";
|
|
23610
|
-
import { join as
|
|
23894
|
+
import { join as join35, basename as basename4 } from "path";
|
|
23611
23895
|
function parseSkillFrontmatter(data) {
|
|
23612
23896
|
return {
|
|
23613
23897
|
name: typeof data.name === "string" ? data.name : "",
|
|
@@ -23618,7 +23902,7 @@ function parseSkillFrontmatter(data) {
|
|
|
23618
23902
|
};
|
|
23619
23903
|
}
|
|
23620
23904
|
function discoverSkillsFromDir(skillsDir, scope) {
|
|
23621
|
-
if (!
|
|
23905
|
+
if (!existsSync31(skillsDir)) {
|
|
23622
23906
|
return [];
|
|
23623
23907
|
}
|
|
23624
23908
|
const entries = readdirSync8(skillsDir, { withFileTypes: true });
|
|
@@ -23626,14 +23910,14 @@ function discoverSkillsFromDir(skillsDir, scope) {
|
|
|
23626
23910
|
for (const entry of entries) {
|
|
23627
23911
|
if (entry.name.startsWith("."))
|
|
23628
23912
|
continue;
|
|
23629
|
-
const skillPath =
|
|
23913
|
+
const skillPath = join35(skillsDir, entry.name);
|
|
23630
23914
|
if (entry.isDirectory() || entry.isSymbolicLink()) {
|
|
23631
23915
|
const resolvedPath = resolveSymlink(skillPath);
|
|
23632
|
-
const skillMdPath =
|
|
23633
|
-
if (!
|
|
23916
|
+
const skillMdPath = join35(resolvedPath, "SKILL.md");
|
|
23917
|
+
if (!existsSync31(skillMdPath))
|
|
23634
23918
|
continue;
|
|
23635
23919
|
try {
|
|
23636
|
-
const content =
|
|
23920
|
+
const content = readFileSync19(skillMdPath, "utf-8");
|
|
23637
23921
|
const { data } = parseFrontmatter(content);
|
|
23638
23922
|
skills.push({
|
|
23639
23923
|
name: data.name || entry.name,
|
|
@@ -23648,8 +23932,8 @@ function discoverSkillsFromDir(skillsDir, scope) {
|
|
|
23648
23932
|
return skills;
|
|
23649
23933
|
}
|
|
23650
23934
|
function discoverSkillsSync() {
|
|
23651
|
-
const userSkillsDir =
|
|
23652
|
-
const projectSkillsDir =
|
|
23935
|
+
const userSkillsDir = join35(homedir16(), ".claude", "skills");
|
|
23936
|
+
const projectSkillsDir = join35(process.cwd(), ".claude", "skills");
|
|
23653
23937
|
const userSkills = discoverSkillsFromDir(userSkillsDir, "user");
|
|
23654
23938
|
const projectSkills = discoverSkillsFromDir(projectSkillsDir, "project");
|
|
23655
23939
|
return [...projectSkills, ...userSkills];
|
|
@@ -23659,12 +23943,12 @@ var skillListForDescription = availableSkills.map((s) => `- ${s.name}: ${s.descr
|
|
|
23659
23943
|
`);
|
|
23660
23944
|
async function parseSkillMd(skillPath) {
|
|
23661
23945
|
const resolvedPath = resolveSymlink(skillPath);
|
|
23662
|
-
const skillMdPath =
|
|
23663
|
-
if (!
|
|
23946
|
+
const skillMdPath = join35(resolvedPath, "SKILL.md");
|
|
23947
|
+
if (!existsSync31(skillMdPath)) {
|
|
23664
23948
|
return null;
|
|
23665
23949
|
}
|
|
23666
23950
|
try {
|
|
23667
|
-
let content =
|
|
23951
|
+
let content = readFileSync19(skillMdPath, "utf-8");
|
|
23668
23952
|
content = await resolveCommandsInText(content);
|
|
23669
23953
|
const { data, body } = parseFrontmatter(content);
|
|
23670
23954
|
const frontmatter2 = parseSkillFrontmatter(data);
|
|
@@ -23675,12 +23959,12 @@ async function parseSkillMd(skillPath) {
|
|
|
23675
23959
|
allowedTools: frontmatter2["allowed-tools"],
|
|
23676
23960
|
metadata: frontmatter2.metadata
|
|
23677
23961
|
};
|
|
23678
|
-
const referencesDir =
|
|
23679
|
-
const scriptsDir =
|
|
23680
|
-
const assetsDir =
|
|
23681
|
-
const references =
|
|
23682
|
-
const scripts =
|
|
23683
|
-
const assets =
|
|
23962
|
+
const referencesDir = join35(resolvedPath, "references");
|
|
23963
|
+
const scriptsDir = join35(resolvedPath, "scripts");
|
|
23964
|
+
const assetsDir = join35(resolvedPath, "assets");
|
|
23965
|
+
const references = existsSync31(referencesDir) ? readdirSync8(referencesDir).filter((f) => !f.startsWith(".")) : [];
|
|
23966
|
+
const scripts = existsSync31(scriptsDir) ? readdirSync8(scriptsDir).filter((f) => !f.startsWith(".") && !f.startsWith("__")) : [];
|
|
23967
|
+
const assets = existsSync31(assetsDir) ? readdirSync8(assetsDir).filter((f) => !f.startsWith(".")) : [];
|
|
23684
23968
|
return {
|
|
23685
23969
|
name: metadata.name,
|
|
23686
23970
|
path: resolvedPath,
|
|
@@ -23696,7 +23980,7 @@ async function parseSkillMd(skillPath) {
|
|
|
23696
23980
|
}
|
|
23697
23981
|
}
|
|
23698
23982
|
async function discoverSkillsFromDirAsync(skillsDir) {
|
|
23699
|
-
if (!
|
|
23983
|
+
if (!existsSync31(skillsDir)) {
|
|
23700
23984
|
return [];
|
|
23701
23985
|
}
|
|
23702
23986
|
const entries = readdirSync8(skillsDir, { withFileTypes: true });
|
|
@@ -23704,7 +23988,7 @@ async function discoverSkillsFromDirAsync(skillsDir) {
|
|
|
23704
23988
|
for (const entry of entries) {
|
|
23705
23989
|
if (entry.name.startsWith("."))
|
|
23706
23990
|
continue;
|
|
23707
|
-
const skillPath =
|
|
23991
|
+
const skillPath = join35(skillsDir, entry.name);
|
|
23708
23992
|
if (entry.isDirectory() || entry.isSymbolicLink()) {
|
|
23709
23993
|
const skillInfo = await parseSkillMd(skillPath);
|
|
23710
23994
|
if (skillInfo) {
|
|
@@ -23715,8 +23999,8 @@ async function discoverSkillsFromDirAsync(skillsDir) {
|
|
|
23715
23999
|
return skills;
|
|
23716
24000
|
}
|
|
23717
24001
|
async function discoverSkills() {
|
|
23718
|
-
const userSkillsDir =
|
|
23719
|
-
const projectSkillsDir =
|
|
24002
|
+
const userSkillsDir = join35(homedir16(), ".claude", "skills");
|
|
24003
|
+
const projectSkillsDir = join35(process.cwd(), ".claude", "skills");
|
|
23720
24004
|
const userSkills = await discoverSkillsFromDirAsync(userSkillsDir);
|
|
23721
24005
|
const projectSkills = await discoverSkillsFromDirAsync(projectSkillsDir);
|
|
23722
24006
|
return [...projectSkills, ...userSkills];
|
|
@@ -23745,9 +24029,9 @@ async function loadSkillWithReferences(skill, includeRefs) {
|
|
|
23745
24029
|
const referencesLoaded = [];
|
|
23746
24030
|
if (includeRefs && skill.references.length > 0) {
|
|
23747
24031
|
for (const ref of skill.references) {
|
|
23748
|
-
const refPath =
|
|
24032
|
+
const refPath = join35(skill.path, "references", ref);
|
|
23749
24033
|
try {
|
|
23750
|
-
let content =
|
|
24034
|
+
let content = readFileSync19(refPath, "utf-8");
|
|
23751
24035
|
content = await resolveCommandsInText(content);
|
|
23752
24036
|
referencesLoaded.push({ path: ref, content });
|
|
23753
24037
|
} catch {}
|
|
@@ -23939,10 +24223,9 @@ function formatTaskStatus(task) {
|
|
|
23939
24223
|
const duration3 = formatDuration(task.startedAt, task.completedAt);
|
|
23940
24224
|
const promptPreview = truncateText(task.prompt, 500);
|
|
23941
24225
|
let progressSection = "";
|
|
23942
|
-
if (task.progress) {
|
|
24226
|
+
if (task.progress?.lastTool) {
|
|
23943
24227
|
progressSection = `
|
|
23944
|
-
|
|
23945
|
-
Last tool: ${task.progress.lastTool ?? "N/A"}`;
|
|
24228
|
+
| Last tool | ${task.progress.lastTool} |`;
|
|
23946
24229
|
}
|
|
23947
24230
|
let lastMessageSection = "";
|
|
23948
24231
|
if (task.progress?.lastMessage) {
|
|
@@ -23955,6 +24238,16 @@ Last tool: ${task.progress.lastTool ?? "N/A"}`;
|
|
|
23955
24238
|
\`\`\`
|
|
23956
24239
|
${truncated}
|
|
23957
24240
|
\`\`\``;
|
|
24241
|
+
}
|
|
24242
|
+
let statusNote = "";
|
|
24243
|
+
if (task.status === "running") {
|
|
24244
|
+
statusNote = `
|
|
24245
|
+
|
|
24246
|
+
> **Note**: No need to wait explicitly - the system will notify you when this task completes.`;
|
|
24247
|
+
} else if (task.status === "error") {
|
|
24248
|
+
statusNote = `
|
|
24249
|
+
|
|
24250
|
+
> **Failed**: The task encountered an error. Check the last message for details.`;
|
|
23958
24251
|
}
|
|
23959
24252
|
return `# Task Status
|
|
23960
24253
|
|
|
@@ -23966,7 +24259,7 @@ ${truncated}
|
|
|
23966
24259
|
| Status | **${task.status}** |
|
|
23967
24260
|
| Duration | ${duration3} |
|
|
23968
24261
|
| Session ID | \`${task.sessionID}\` |${progressSection}
|
|
23969
|
-
|
|
24262
|
+
${statusNote}
|
|
23970
24263
|
## Original Prompt
|
|
23971
24264
|
|
|
23972
24265
|
\`\`\`
|
|
@@ -24712,7 +25005,16 @@ var AgentPermissionSchema = exports_external.object({
|
|
|
24712
25005
|
doom_loop: PermissionValue.optional(),
|
|
24713
25006
|
external_directory: PermissionValue.optional()
|
|
24714
25007
|
});
|
|
24715
|
-
var
|
|
25008
|
+
var BuiltinAgentNameSchema = exports_external.enum([
|
|
25009
|
+
"oracle",
|
|
25010
|
+
"librarian",
|
|
25011
|
+
"explore",
|
|
25012
|
+
"frontend-ui-ux-engineer",
|
|
25013
|
+
"document-writer",
|
|
25014
|
+
"multimodal-looker"
|
|
25015
|
+
]);
|
|
25016
|
+
var OverridableAgentNameSchema = exports_external.enum([
|
|
25017
|
+
"build",
|
|
24716
25018
|
"oracle",
|
|
24717
25019
|
"librarian",
|
|
24718
25020
|
"explore",
|
|
@@ -24735,7 +25037,8 @@ var HookNameSchema = exports_external.enum([
|
|
|
24735
25037
|
"rules-injector",
|
|
24736
25038
|
"background-notification",
|
|
24737
25039
|
"auto-update-checker",
|
|
24738
|
-
"ultrawork-mode"
|
|
25040
|
+
"ultrawork-mode",
|
|
25041
|
+
"agent-usage-reminder"
|
|
24739
25042
|
]);
|
|
24740
25043
|
var AgentOverrideConfigSchema = exports_external.object({
|
|
24741
25044
|
model: exports_external.string().optional(),
|
|
@@ -24750,6 +25053,7 @@ var AgentOverrideConfigSchema = exports_external.object({
|
|
|
24750
25053
|
permission: AgentPermissionSchema.optional()
|
|
24751
25054
|
});
|
|
24752
25055
|
var AgentOverridesSchema = exports_external.object({
|
|
25056
|
+
build: AgentOverrideConfigSchema.optional(),
|
|
24753
25057
|
oracle: AgentOverrideConfigSchema.optional(),
|
|
24754
25058
|
librarian: AgentOverrideConfigSchema.optional(),
|
|
24755
25059
|
explore: AgentOverrideConfigSchema.optional(),
|
|
@@ -24767,7 +25071,7 @@ var ClaudeCodeConfigSchema = exports_external.object({
|
|
|
24767
25071
|
var OhMyOpenCodeConfigSchema = exports_external.object({
|
|
24768
25072
|
$schema: exports_external.string().optional(),
|
|
24769
25073
|
disabled_mcps: exports_external.array(McpNameSchema).optional(),
|
|
24770
|
-
disabled_agents: exports_external.array(
|
|
25074
|
+
disabled_agents: exports_external.array(BuiltinAgentNameSchema).optional(),
|
|
24771
25075
|
disabled_hooks: exports_external.array(HookNameSchema).optional(),
|
|
24772
25076
|
agents: AgentOverridesSchema.optional(),
|
|
24773
25077
|
claude_code: ClaudeCodeConfigSchema.optional(),
|
|
@@ -24869,6 +25173,7 @@ var OhMyOpenCodePlugin = async (ctx) => {
|
|
|
24869
25173
|
const rulesInjector = isHookEnabled("rules-injector") ? createRulesInjectorHook(ctx) : null;
|
|
24870
25174
|
const autoUpdateChecker = isHookEnabled("auto-update-checker") ? createAutoUpdateCheckerHook(ctx) : null;
|
|
24871
25175
|
const ultraworkMode = isHookEnabled("ultrawork-mode") ? createUltraworkModeHook() : null;
|
|
25176
|
+
const agentUsageReminder = isHookEnabled("agent-usage-reminder") ? createAgentUsageReminderHook(ctx) : null;
|
|
24872
25177
|
updateTerminalTitle({ sessionId: "main" });
|
|
24873
25178
|
const backgroundManager = new BackgroundManager(ctx);
|
|
24874
25179
|
const backgroundNotificationHook = isHookEnabled("background-notification") ? createBackgroundNotificationHook(backgroundManager) : null;
|
|
@@ -24898,6 +25203,16 @@ var OhMyOpenCodePlugin = async (ctx) => {
|
|
|
24898
25203
|
...projectAgents,
|
|
24899
25204
|
...config3.agent
|
|
24900
25205
|
};
|
|
25206
|
+
for (const [agentName, agentConfig] of Object.entries(config3.agent ?? {})) {
|
|
25207
|
+
if (agentConfig && agentConfig.mode !== "subagent") {
|
|
25208
|
+
const existingPrompt = agentConfig.prompt || "";
|
|
25209
|
+
const userOverride = pluginConfig.agents?.[agentName]?.prompt || "";
|
|
25210
|
+
config3.agent[agentName] = {
|
|
25211
|
+
...agentConfig,
|
|
25212
|
+
prompt: existingPrompt + BUILD_AGENT_PROMPT_EXTENSION + userOverride
|
|
25213
|
+
};
|
|
25214
|
+
}
|
|
25215
|
+
}
|
|
24901
25216
|
config3.tools = {
|
|
24902
25217
|
...config3.tools
|
|
24903
25218
|
};
|
|
@@ -24957,6 +25272,7 @@ var OhMyOpenCodePlugin = async (ctx) => {
|
|
|
24957
25272
|
await thinkMode?.event(input);
|
|
24958
25273
|
await anthropicAutoCompact?.event(input);
|
|
24959
25274
|
await ultraworkMode?.event(input);
|
|
25275
|
+
await agentUsageReminder?.event(input);
|
|
24960
25276
|
const { event } = input;
|
|
24961
25277
|
const props = event.properties;
|
|
24962
25278
|
if (event.type === "session.created") {
|
|
@@ -25057,6 +25373,7 @@ var OhMyOpenCodePlugin = async (ctx) => {
|
|
|
25057
25373
|
await directoryReadmeInjector?.["tool.execute.after"](input, output);
|
|
25058
25374
|
await rulesInjector?.["tool.execute.after"](input, output);
|
|
25059
25375
|
await emptyTaskResponseDetector?.["tool.execute.after"](input, output);
|
|
25376
|
+
await agentUsageReminder?.["tool.execute.after"](input, output);
|
|
25060
25377
|
if (input.sessionID === getMainSessionID()) {
|
|
25061
25378
|
updateTerminalTitle({
|
|
25062
25379
|
sessionId: input.sessionID,
|