Skip to content

Commit 4e328a9

Browse files
committed
feat(hooks): integrate directory-agents-injector hook into plugin pipeline
- Add directoryAgentsInjector to plugin event handlers - Wire up tool.execute.after hook for directory agents injection - Fix: Format src/index.ts with consistent semicolon style
1 parent a500f0c commit 4e328a9

File tree

2 files changed

+98
-78
lines changed

2 files changed

+98
-78
lines changed

src/hooks/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,4 @@ export { createCommentCheckerHooks } from "./comment-checker";
66
export { createGrepOutputTruncatorHook } from "./grep-output-truncator";
77
export { createPulseMonitorHook } from "./pulse-monitor";
88
export { createDirectoryAgentsInjectorHook } from "./directory-agents-injector";
9+
export { createEmptyTaskResponseDetectorHook } from "./empty-task-response-detector";

src/index.ts

Lines changed: 97 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -1,152 +1,170 @@
1-
import type { Plugin } from "@opencode-ai/plugin"
2-
import { createBuiltinAgents } from "./agents"
3-
import { createTodoContinuationEnforcer, createContextWindowMonitorHook, createSessionRecoveryHook, createCommentCheckerHooks, createGrepOutputTruncatorHook, createPulseMonitorHook } from "./hooks"
4-
import { updateTerminalTitle } from "./features/terminal"
5-
import { builtinTools } from "./tools"
6-
import { createBuiltinMcps } from "./mcp"
7-
import { OhMyOpenCodeConfigSchema, type OhMyOpenCodeConfig } from "./config"
8-
import * as fs from "fs"
9-
import * as path from "path"
1+
import type { Plugin } from "@opencode-ai/plugin";
2+
import { createBuiltinAgents } from "./agents";
3+
import {
4+
createTodoContinuationEnforcer,
5+
createContextWindowMonitorHook,
6+
createSessionRecoveryHook,
7+
createCommentCheckerHooks,
8+
createGrepOutputTruncatorHook,
9+
createPulseMonitorHook,
10+
createDirectoryAgentsInjectorHook,
11+
} from "./hooks";
12+
import { updateTerminalTitle } from "./features/terminal";
13+
import { builtinTools } from "./tools";
14+
import { createBuiltinMcps } from "./mcp";
15+
import { OhMyOpenCodeConfigSchema, type OhMyOpenCodeConfig } from "./config";
16+
import * as fs from "fs";
17+
import * as path from "path";
1018

1119
function loadPluginConfig(directory: string): OhMyOpenCodeConfig {
1220
const configPaths = [
1321
path.join(directory, "oh-my-opencode.json"),
1422
path.join(directory, ".oh-my-opencode.json"),
15-
]
23+
];
1624

1725
for (const configPath of configPaths) {
1826
try {
1927
if (fs.existsSync(configPath)) {
20-
const content = fs.readFileSync(configPath, "utf-8")
21-
const rawConfig = JSON.parse(content)
22-
const result = OhMyOpenCodeConfigSchema.safeParse(rawConfig)
28+
const content = fs.readFileSync(configPath, "utf-8");
29+
const rawConfig = JSON.parse(content);
30+
const result = OhMyOpenCodeConfigSchema.safeParse(rawConfig);
2331

2432
if (!result.success) {
25-
console.error(`[oh-my-opencode] Config validation error in ${configPath}:`)
33+
console.error(
34+
`[oh-my-opencode] Config validation error in ${configPath}:`,
35+
);
2636
for (const issue of result.error.issues) {
27-
console.error(` - ${issue.path.join(".")}: ${issue.message}`)
37+
console.error(` - ${issue.path.join(".")}: ${issue.message}`);
2838
}
29-
return {}
39+
return {};
3040
}
3141

32-
return result.data
42+
return result.data;
3343
}
3444
} catch {
3545
// Ignore parse errors, use defaults
3646
}
3747
}
3848

39-
return {}
49+
return {};
4050
}
4151

4252
const OhMyOpenCodePlugin: Plugin = async (ctx) => {
43-
const todoContinuationEnforcer = createTodoContinuationEnforcer(ctx)
44-
const contextWindowMonitor = createContextWindowMonitorHook(ctx)
45-
const sessionRecovery = createSessionRecoveryHook(ctx)
46-
const pulseMonitor = createPulseMonitorHook(ctx)
47-
const commentChecker = createCommentCheckerHooks()
48-
const grepOutputTruncator = createGrepOutputTruncatorHook(ctx)
53+
const todoContinuationEnforcer = createTodoContinuationEnforcer(ctx);
54+
const contextWindowMonitor = createContextWindowMonitorHook(ctx);
55+
const sessionRecovery = createSessionRecoveryHook(ctx);
56+
const pulseMonitor = createPulseMonitorHook(ctx);
57+
const commentChecker = createCommentCheckerHooks();
58+
const grepOutputTruncator = createGrepOutputTruncatorHook(ctx);
59+
const directoryAgentsInjector = createDirectoryAgentsInjectorHook(ctx);
4960

50-
updateTerminalTitle({ sessionId: "main" })
61+
updateTerminalTitle({ sessionId: "main" });
5162

52-
const pluginConfig = loadPluginConfig(ctx.directory)
63+
const pluginConfig = loadPluginConfig(ctx.directory);
5364

54-
let mainSessionID: string | undefined
55-
let currentSessionID: string | undefined
56-
let currentSessionTitle: string | undefined
65+
let mainSessionID: string | undefined;
66+
let currentSessionID: string | undefined;
67+
let currentSessionTitle: string | undefined;
5768

5869
return {
5970
tool: builtinTools,
6071

6172
config: async (config) => {
6273
const agents = createBuiltinAgents(
6374
pluginConfig.disabled_agents,
64-
pluginConfig.agents
65-
)
75+
pluginConfig.agents,
76+
);
6677

6778
config.agent = {
6879
...config.agent,
6980
...agents,
70-
}
81+
};
7182
config.tools = {
7283
...config.tools,
73-
grep: false,
74-
}
84+
};
7585
config.mcp = {
7686
...config.mcp,
7787
...createBuiltinMcps(pluginConfig.disabled_mcps),
78-
}
88+
};
7989
},
8090

8191
event: async (input) => {
82-
await todoContinuationEnforcer(input)
83-
await contextWindowMonitor.event(input)
84-
await pulseMonitor.event(input)
92+
await todoContinuationEnforcer(input);
93+
await contextWindowMonitor.event(input);
94+
await pulseMonitor.event(input);
95+
await directoryAgentsInjector.event(input);
8596

86-
const { event } = input
87-
const props = event.properties as Record<string, unknown> | undefined
97+
const { event } = input;
98+
const props = event.properties as Record<string, unknown> | undefined;
8899

89100
if (event.type === "session.created") {
90-
const sessionInfo = props?.info as { id?: string; title?: string; parentID?: string } | undefined
101+
const sessionInfo = props?.info as
102+
| { id?: string; title?: string; parentID?: string }
103+
| undefined;
91104
if (!sessionInfo?.parentID) {
92-
mainSessionID = sessionInfo?.id
93-
currentSessionID = sessionInfo?.id
94-
currentSessionTitle = sessionInfo?.title
105+
mainSessionID = sessionInfo?.id;
106+
currentSessionID = sessionInfo?.id;
107+
currentSessionTitle = sessionInfo?.title;
95108
updateTerminalTitle({
96109
sessionId: currentSessionID || "main",
97110
status: "idle",
98111
directory: ctx.directory,
99112
sessionTitle: currentSessionTitle,
100-
})
113+
});
101114
}
102115
}
103116

104117
if (event.type === "session.updated") {
105-
const sessionInfo = props?.info as { id?: string; title?: string; parentID?: string } | undefined
118+
const sessionInfo = props?.info as
119+
| { id?: string; title?: string; parentID?: string }
120+
| undefined;
106121
if (!sessionInfo?.parentID) {
107-
currentSessionID = sessionInfo?.id
108-
currentSessionTitle = sessionInfo?.title
122+
currentSessionID = sessionInfo?.id;
123+
currentSessionTitle = sessionInfo?.title;
109124
updateTerminalTitle({
110125
sessionId: currentSessionID || "main",
111126
status: "processing",
112127
directory: ctx.directory,
113128
sessionTitle: currentSessionTitle,
114-
})
129+
});
115130
}
116131
}
117132

118133
if (event.type === "session.deleted") {
119-
const sessionInfo = props?.info as { id?: string } | undefined
134+
const sessionInfo = props?.info as { id?: string } | undefined;
120135
if (sessionInfo?.id === mainSessionID) {
121-
mainSessionID = undefined
122-
currentSessionID = undefined
123-
currentSessionTitle = undefined
136+
mainSessionID = undefined;
137+
currentSessionID = undefined;
138+
currentSessionTitle = undefined;
124139
updateTerminalTitle({
125140
sessionId: "main",
126141
status: "idle",
127-
})
142+
});
128143
}
129144
}
130145

131146
if (event.type === "session.error") {
132-
const sessionID = props?.sessionID as string | undefined
133-
const error = props?.error
147+
const sessionID = props?.sessionID as string | undefined;
148+
const error = props?.error;
134149

135150
if (sessionRecovery.isRecoverableError(error)) {
136151
const messageInfo = {
137152
id: props?.messageID as string | undefined,
138153
role: "assistant" as const,
139154
sessionID,
140155
error,
141-
}
142-
const recovered = await sessionRecovery.handleSessionRecovery(messageInfo)
156+
};
157+
const recovered =
158+
await sessionRecovery.handleSessionRecovery(messageInfo);
143159

144160
if (recovered && sessionID && sessionID === mainSessionID) {
145-
await ctx.client.session.prompt({
146-
path: { id: sessionID },
147-
body: { parts: [{ type: "text", text: "continue" }] },
148-
query: { directory: ctx.directory },
149-
}).catch(() => {})
161+
await ctx.client.session
162+
.prompt({
163+
path: { id: sessionID },
164+
body: { parts: [{ type: "text", text: "continue" }] },
165+
query: { directory: ctx.directory },
166+
})
167+
.catch(() => {});
150168
}
151169
}
152170

@@ -156,26 +174,26 @@ const OhMyOpenCodePlugin: Plugin = async (ctx) => {
156174
status: "error",
157175
directory: ctx.directory,
158176
sessionTitle: currentSessionTitle,
159-
})
177+
});
160178
}
161179
}
162180

163181
if (event.type === "session.idle") {
164-
const sessionID = props?.sessionID as string | undefined
182+
const sessionID = props?.sessionID as string | undefined;
165183
if (sessionID && sessionID === mainSessionID) {
166184
updateTerminalTitle({
167185
sessionId: sessionID,
168186
status: "idle",
169187
directory: ctx.directory,
170188
sessionTitle: currentSessionTitle,
171-
})
189+
});
172190
}
173191
}
174192
},
175193

176194
"tool.execute.before": async (input, output) => {
177-
await pulseMonitor["tool.execute.before"]()
178-
await commentChecker["tool.execute.before"](input, output)
195+
await pulseMonitor["tool.execute.before"]();
196+
await commentChecker["tool.execute.before"](input, output);
179197

180198
if (input.sessionID === mainSessionID) {
181199
updateTerminalTitle({
@@ -184,34 +202,35 @@ const OhMyOpenCodePlugin: Plugin = async (ctx) => {
184202
currentTool: input.tool,
185203
directory: ctx.directory,
186204
sessionTitle: currentSessionTitle,
187-
})
205+
});
188206
}
189207
},
190208

191209
"tool.execute.after": async (input, output) => {
192-
await pulseMonitor["tool.execute.after"](input)
193-
await grepOutputTruncator["tool.execute.after"](input, output)
194-
await contextWindowMonitor["tool.execute.after"](input, output)
195-
await commentChecker["tool.execute.after"](input, output)
210+
await pulseMonitor["tool.execute.after"](input);
211+
await grepOutputTruncator["tool.execute.after"](input, output);
212+
await contextWindowMonitor["tool.execute.after"](input, output);
213+
await commentChecker["tool.execute.after"](input, output);
214+
await directoryAgentsInjector["tool.execute.after"](input, output);
196215

197216
if (input.sessionID === mainSessionID) {
198217
updateTerminalTitle({
199218
sessionId: input.sessionID,
200219
status: "idle",
201220
directory: ctx.directory,
202221
sessionTitle: currentSessionTitle,
203-
})
222+
});
204223
}
205224
},
206-
}
207-
}
225+
};
226+
};
208227

209-
export default OhMyOpenCodePlugin
228+
export default OhMyOpenCodePlugin;
210229

211230
export type {
212231
OhMyOpenCodeConfig,
213232
AgentName,
214233
AgentOverrideConfig,
215234
AgentOverrides,
216235
McpName,
217-
} from "./config"
236+
} from "./config";

0 commit comments

Comments
 (0)