oh-my-opencode 2.4.1 → 2.4.3

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.
@@ -9,6 +9,9 @@ interface ToolExecuteOutput {
9
9
  output: string;
10
10
  metadata: unknown;
11
11
  }
12
+ interface ToolExecuteBeforeOutput {
13
+ args: unknown;
14
+ }
12
15
  interface EventInput {
13
16
  event: {
14
17
  type: string;
@@ -16,6 +19,7 @@ interface EventInput {
16
19
  };
17
20
  }
18
21
  export declare function createDirectoryAgentsInjectorHook(ctx: PluginInput): {
22
+ "tool.execute.before": (input: ToolExecuteInput, output: ToolExecuteBeforeOutput) => Promise<void>;
19
23
  "tool.execute.after": (input: ToolExecuteInput, output: ToolExecuteOutput) => Promise<void>;
20
24
  event: ({ event }: EventInput) => Promise<void>;
21
25
  };
@@ -9,6 +9,9 @@ interface ToolExecuteOutput {
9
9
  output: string;
10
10
  metadata: unknown;
11
11
  }
12
+ interface ToolExecuteBeforeOutput {
13
+ args: unknown;
14
+ }
12
15
  interface EventInput {
13
16
  event: {
14
17
  type: string;
@@ -16,6 +19,7 @@ interface EventInput {
16
19
  };
17
20
  }
18
21
  export declare function createDirectoryReadmeInjectorHook(ctx: PluginInput): {
22
+ "tool.execute.before": (input: ToolExecuteInput, output: ToolExecuteBeforeOutput) => Promise<void>;
19
23
  "tool.execute.after": (input: ToolExecuteInput, output: ToolExecuteOutput) => Promise<void>;
20
24
  event: ({ event }: EventInput) => Promise<void>;
21
25
  };
@@ -9,6 +9,9 @@ interface ToolExecuteOutput {
9
9
  output: string;
10
10
  metadata: unknown;
11
11
  }
12
+ interface ToolExecuteBeforeOutput {
13
+ args: unknown;
14
+ }
12
15
  interface EventInput {
13
16
  event: {
14
17
  type: string;
@@ -16,6 +19,7 @@ interface EventInput {
16
19
  };
17
20
  }
18
21
  export declare function createRulesInjectorHook(ctx: PluginInput): {
22
+ "tool.execute.before": (input: ToolExecuteInput, output: ToolExecuteBeforeOutput) => Promise<void>;
19
23
  "tool.execute.after": (input: ToolExecuteInput, output: ToolExecuteOutput) => Promise<void>;
20
24
  event: ({ event }: EventInput) => Promise<void>;
21
25
  };
package/dist/index.js CHANGED
@@ -3271,8 +3271,7 @@ function createBuiltinAgents(disabledAgents = [], agentOverrides = {}, directory
3271
3271
  config = { ...config, prompt: config.prompt + envContext };
3272
3272
  }
3273
3273
  if (override) {
3274
- const { model: _, ...restOverride } = override;
3275
- config = mergeAgentConfig(config, restOverride);
3274
+ config = mergeAgentConfig(config, override);
3276
3275
  }
3277
3276
  result[name] = config;
3278
3277
  }
@@ -4921,18 +4920,19 @@ function clearInjectedPaths(sessionID) {
4921
4920
  // src/hooks/directory-agents-injector/index.ts
4922
4921
  function createDirectoryAgentsInjectorHook(ctx) {
4923
4922
  const sessionCaches = new Map;
4923
+ const pendingBatchReads = new Map;
4924
4924
  function getSessionCache(sessionID) {
4925
4925
  if (!sessionCaches.has(sessionID)) {
4926
4926
  sessionCaches.set(sessionID, loadInjectedPaths(sessionID));
4927
4927
  }
4928
4928
  return sessionCaches.get(sessionID);
4929
4929
  }
4930
- function resolveFilePath2(title) {
4931
- if (!title)
4930
+ function resolveFilePath2(path4) {
4931
+ if (!path4)
4932
4932
  return null;
4933
- if (title.startsWith("/"))
4934
- return title;
4935
- return resolve2(ctx.directory, title);
4933
+ if (path4.startsWith("/"))
4934
+ return path4;
4935
+ return resolve2(ctx.directory, path4);
4936
4936
  }
4937
4937
  function findAgentsMdUp(startDir) {
4938
4938
  const found = [];
@@ -4953,35 +4953,59 @@ function createDirectoryAgentsInjectorHook(ctx) {
4953
4953
  }
4954
4954
  return found.reverse();
4955
4955
  }
4956
- const toolExecuteAfter = async (input, output) => {
4957
- if (input.tool.toLowerCase() !== "read")
4958
- return;
4959
- const filePath = resolveFilePath2(output.title);
4960
- if (!filePath)
4956
+ function processFilePathForInjection(filePath, sessionID, output) {
4957
+ const resolved = resolveFilePath2(filePath);
4958
+ if (!resolved)
4961
4959
  return;
4962
- const dir = dirname2(filePath);
4963
- const cache = getSessionCache(input.sessionID);
4960
+ const dir = dirname2(resolved);
4961
+ const cache = getSessionCache(sessionID);
4964
4962
  const agentsPaths = findAgentsMdUp(dir);
4965
- const toInject = [];
4966
4963
  for (const agentsPath of agentsPaths) {
4967
4964
  const agentsDir = dirname2(agentsPath);
4968
4965
  if (cache.has(agentsDir))
4969
4966
  continue;
4970
4967
  try {
4971
4968
  const content = readFileSync5(agentsPath, "utf-8");
4972
- toInject.push({ path: agentsPath, content });
4969
+ output.output += `
4970
+
4971
+ [Directory Context: ${agentsPath}]
4972
+ ${content}`;
4973
4973
  cache.add(agentsDir);
4974
4974
  } catch {}
4975
4975
  }
4976
- if (toInject.length === 0)
4976
+ saveInjectedPaths(sessionID, cache);
4977
+ }
4978
+ const toolExecuteBefore = async (input, output) => {
4979
+ if (input.tool.toLowerCase() !== "batch")
4977
4980
  return;
4978
- for (const { path: path4, content } of toInject) {
4979
- output.output += `
4980
-
4981
- [Directory Context: ${path4}]
4982
- ${content}`;
4981
+ const args = output.args;
4982
+ if (!args?.tool_calls)
4983
+ return;
4984
+ const readFilePaths = [];
4985
+ for (const call of args.tool_calls) {
4986
+ if (call.tool.toLowerCase() === "read" && call.parameters?.filePath) {
4987
+ readFilePaths.push(call.parameters.filePath);
4988
+ }
4989
+ }
4990
+ if (readFilePaths.length > 0) {
4991
+ pendingBatchReads.set(input.callID, readFilePaths);
4992
+ }
4993
+ };
4994
+ const toolExecuteAfter = async (input, output) => {
4995
+ const toolName = input.tool.toLowerCase();
4996
+ if (toolName === "read") {
4997
+ processFilePathForInjection(output.title, input.sessionID, output);
4998
+ return;
4999
+ }
5000
+ if (toolName === "batch") {
5001
+ const filePaths = pendingBatchReads.get(input.callID);
5002
+ if (filePaths) {
5003
+ for (const filePath of filePaths) {
5004
+ processFilePathForInjection(filePath, input.sessionID, output);
5005
+ }
5006
+ pendingBatchReads.delete(input.callID);
5007
+ }
4983
5008
  }
4984
- saveInjectedPaths(input.sessionID, cache);
4985
5009
  };
4986
5010
  const eventHandler = async ({ event }) => {
4987
5011
  const props = event.properties;
@@ -5001,6 +5025,7 @@ ${content}`;
5001
5025
  }
5002
5026
  };
5003
5027
  return {
5028
+ "tool.execute.before": toolExecuteBefore,
5004
5029
  "tool.execute.after": toolExecuteAfter,
5005
5030
  event: eventHandler
5006
5031
  };
@@ -5062,18 +5087,19 @@ function clearInjectedPaths2(sessionID) {
5062
5087
  // src/hooks/directory-readme-injector/index.ts
5063
5088
  function createDirectoryReadmeInjectorHook(ctx) {
5064
5089
  const sessionCaches = new Map;
5090
+ const pendingBatchReads = new Map;
5065
5091
  function getSessionCache(sessionID) {
5066
5092
  if (!sessionCaches.has(sessionID)) {
5067
5093
  sessionCaches.set(sessionID, loadInjectedPaths2(sessionID));
5068
5094
  }
5069
5095
  return sessionCaches.get(sessionID);
5070
5096
  }
5071
- function resolveFilePath2(title) {
5072
- if (!title)
5097
+ function resolveFilePath2(path4) {
5098
+ if (!path4)
5073
5099
  return null;
5074
- if (title.startsWith("/"))
5075
- return title;
5076
- return resolve3(ctx.directory, title);
5100
+ if (path4.startsWith("/"))
5101
+ return path4;
5102
+ return resolve3(ctx.directory, path4);
5077
5103
  }
5078
5104
  function findReadmeMdUp(startDir) {
5079
5105
  const found = [];
@@ -5094,35 +5120,59 @@ function createDirectoryReadmeInjectorHook(ctx) {
5094
5120
  }
5095
5121
  return found.reverse();
5096
5122
  }
5097
- const toolExecuteAfter = async (input, output) => {
5098
- if (input.tool.toLowerCase() !== "read")
5099
- return;
5100
- const filePath = resolveFilePath2(output.title);
5101
- if (!filePath)
5123
+ function processFilePathForInjection(filePath, sessionID, output) {
5124
+ const resolved = resolveFilePath2(filePath);
5125
+ if (!resolved)
5102
5126
  return;
5103
- const dir = dirname3(filePath);
5104
- const cache = getSessionCache(input.sessionID);
5127
+ const dir = dirname3(resolved);
5128
+ const cache = getSessionCache(sessionID);
5105
5129
  const readmePaths = findReadmeMdUp(dir);
5106
- const toInject = [];
5107
5130
  for (const readmePath of readmePaths) {
5108
5131
  const readmeDir = dirname3(readmePath);
5109
5132
  if (cache.has(readmeDir))
5110
5133
  continue;
5111
5134
  try {
5112
5135
  const content = readFileSync7(readmePath, "utf-8");
5113
- toInject.push({ path: readmePath, content });
5136
+ output.output += `
5137
+
5138
+ [Project README: ${readmePath}]
5139
+ ${content}`;
5114
5140
  cache.add(readmeDir);
5115
5141
  } catch {}
5116
5142
  }
5117
- if (toInject.length === 0)
5143
+ saveInjectedPaths2(sessionID, cache);
5144
+ }
5145
+ const toolExecuteBefore = async (input, output) => {
5146
+ if (input.tool.toLowerCase() !== "batch")
5118
5147
  return;
5119
- for (const { path: path4, content } of toInject) {
5120
- output.output += `
5121
-
5122
- [Project README: ${path4}]
5123
- ${content}`;
5148
+ const args = output.args;
5149
+ if (!args?.tool_calls)
5150
+ return;
5151
+ const readFilePaths = [];
5152
+ for (const call of args.tool_calls) {
5153
+ if (call.tool.toLowerCase() === "read" && call.parameters?.filePath) {
5154
+ readFilePaths.push(call.parameters.filePath);
5155
+ }
5156
+ }
5157
+ if (readFilePaths.length > 0) {
5158
+ pendingBatchReads.set(input.callID, readFilePaths);
5159
+ }
5160
+ };
5161
+ const toolExecuteAfter = async (input, output) => {
5162
+ const toolName = input.tool.toLowerCase();
5163
+ if (toolName === "read") {
5164
+ processFilePathForInjection(output.title, input.sessionID, output);
5165
+ return;
5166
+ }
5167
+ if (toolName === "batch") {
5168
+ const filePaths = pendingBatchReads.get(input.callID);
5169
+ if (filePaths) {
5170
+ for (const filePath of filePaths) {
5171
+ processFilePathForInjection(filePath, input.sessionID, output);
5172
+ }
5173
+ pendingBatchReads.delete(input.callID);
5174
+ }
5124
5175
  }
5125
- saveInjectedPaths2(input.sessionID, cache);
5126
5176
  };
5127
5177
  const eventHandler = async ({ event }) => {
5128
5178
  const props = event.properties;
@@ -5142,6 +5192,7 @@ ${content}`;
5142
5192
  }
5143
5193
  };
5144
5194
  return {
5195
+ "tool.execute.before": toolExecuteBefore,
5145
5196
  "tool.execute.after": toolExecuteAfter,
5146
5197
  event: eventHandler
5147
5198
  };
@@ -6100,11 +6151,22 @@ function createPreemptiveCompactionHook(ctx, options) {
6100
6151
  await ctx.client.tui.showToast({
6101
6152
  body: {
6102
6153
  title: "Compaction Complete",
6103
- message: "Session compacted successfully",
6154
+ message: "Session compacted successfully. Resuming...",
6104
6155
  variant: "success",
6105
6156
  duration: 2000
6106
6157
  }
6107
6158
  }).catch(() => {});
6159
+ state2.compactionInProgress.delete(sessionID);
6160
+ setTimeout(async () => {
6161
+ try {
6162
+ await ctx.client.session.promptAsync({
6163
+ path: { id: sessionID },
6164
+ body: { parts: [{ type: "text", text: "Continue" }] },
6165
+ query: { directory: ctx.directory }
6166
+ });
6167
+ } catch {}
6168
+ }, 500);
6169
+ return;
6108
6170
  } catch (err) {
6109
6171
  log("[preemptive-compaction] compaction failed", { sessionID, error: err });
6110
6172
  } finally {
@@ -7740,29 +7802,28 @@ function clearInjectedRules(sessionID) {
7740
7802
  var TRACKED_TOOLS = ["read", "write", "edit", "multiedit"];
7741
7803
  function createRulesInjectorHook(ctx) {
7742
7804
  const sessionCaches = new Map;
7805
+ const pendingBatchFiles = new Map;
7743
7806
  function getSessionCache(sessionID) {
7744
7807
  if (!sessionCaches.has(sessionID)) {
7745
7808
  sessionCaches.set(sessionID, loadInjectedRules(sessionID));
7746
7809
  }
7747
7810
  return sessionCaches.get(sessionID);
7748
7811
  }
7749
- function resolveFilePath2(title) {
7750
- if (!title)
7812
+ function resolveFilePath2(path4) {
7813
+ if (!path4)
7751
7814
  return null;
7752
- if (title.startsWith("/"))
7753
- return title;
7754
- return resolve4(ctx.directory, title);
7815
+ if (path4.startsWith("/"))
7816
+ return path4;
7817
+ return resolve4(ctx.directory, path4);
7755
7818
  }
7756
- const toolExecuteAfter = async (input, output) => {
7757
- if (!TRACKED_TOOLS.includes(input.tool.toLowerCase()))
7819
+ function processFilePathForInjection(filePath, sessionID, output) {
7820
+ const resolved = resolveFilePath2(filePath);
7821
+ if (!resolved)
7758
7822
  return;
7759
- const filePath = resolveFilePath2(output.title);
7760
- if (!filePath)
7761
- return;
7762
- const projectRoot = findProjectRoot(filePath);
7763
- const cache2 = getSessionCache(input.sessionID);
7823
+ const projectRoot = findProjectRoot(resolved);
7824
+ const cache2 = getSessionCache(sessionID);
7764
7825
  const home = homedir10();
7765
- const ruleFileCandidates = findRuleFiles(projectRoot, home, filePath);
7826
+ const ruleFileCandidates = findRuleFiles(projectRoot, home, resolved);
7766
7827
  const toInject = [];
7767
7828
  for (const candidate of ruleFileCandidates) {
7768
7829
  if (isDuplicateByRealPath(candidate.realPath, cache2.realPaths))
@@ -7770,7 +7831,7 @@ function createRulesInjectorHook(ctx) {
7770
7831
  try {
7771
7832
  const rawContent = readFileSync10(candidate.path, "utf-8");
7772
7833
  const { metadata, body } = parseRuleFrontmatter(rawContent);
7773
- const matchResult = shouldApplyRule(metadata, filePath, projectRoot);
7834
+ const matchResult = shouldApplyRule(metadata, resolved, projectRoot);
7774
7835
  if (!matchResult.applies)
7775
7836
  continue;
7776
7837
  const contentHash = createContentHash(body);
@@ -7797,7 +7858,46 @@ function createRulesInjectorHook(ctx) {
7797
7858
  [Match: ${rule.matchReason}]
7798
7859
  ${rule.content}`;
7799
7860
  }
7800
- saveInjectedRules(input.sessionID, cache2);
7861
+ saveInjectedRules(sessionID, cache2);
7862
+ }
7863
+ function extractFilePathFromToolCall(call) {
7864
+ const params = call.parameters;
7865
+ return params?.filePath ?? params?.file_path ?? params?.path;
7866
+ }
7867
+ const toolExecuteBefore = async (input, output) => {
7868
+ if (input.tool.toLowerCase() !== "batch")
7869
+ return;
7870
+ const args = output.args;
7871
+ if (!args?.tool_calls)
7872
+ return;
7873
+ const filePaths = [];
7874
+ for (const call of args.tool_calls) {
7875
+ if (TRACKED_TOOLS.includes(call.tool.toLowerCase())) {
7876
+ const filePath = extractFilePathFromToolCall(call);
7877
+ if (filePath) {
7878
+ filePaths.push(filePath);
7879
+ }
7880
+ }
7881
+ }
7882
+ if (filePaths.length > 0) {
7883
+ pendingBatchFiles.set(input.callID, filePaths);
7884
+ }
7885
+ };
7886
+ const toolExecuteAfter = async (input, output) => {
7887
+ const toolName = input.tool.toLowerCase();
7888
+ if (TRACKED_TOOLS.includes(toolName)) {
7889
+ processFilePathForInjection(output.title, input.sessionID, output);
7890
+ return;
7891
+ }
7892
+ if (toolName === "batch") {
7893
+ const filePaths = pendingBatchFiles.get(input.callID);
7894
+ if (filePaths) {
7895
+ for (const filePath of filePaths) {
7896
+ processFilePathForInjection(filePath, input.sessionID, output);
7897
+ }
7898
+ pendingBatchFiles.delete(input.callID);
7899
+ }
7900
+ }
7801
7901
  };
7802
7902
  const eventHandler = async ({ event }) => {
7803
7903
  const props = event.properties;
@@ -7817,6 +7917,7 @@ ${rule.content}`;
7817
7917
  }
7818
7918
  };
7819
7919
  return {
7920
+ "tool.execute.before": toolExecuteBefore,
7820
7921
  "tool.execute.after": toolExecuteAfter,
7821
7922
  event: eventHandler
7822
7923
  };
@@ -27826,6 +27927,9 @@ var OhMyOpenCodePlugin = async (ctx) => {
27826
27927
  await claudeCodeHooks["tool.execute.before"](input, output);
27827
27928
  await nonInteractiveEnv?.["tool.execute.before"](input, output);
27828
27929
  await commentChecker?.["tool.execute.before"](input, output);
27930
+ await directoryAgentsInjector?.["tool.execute.before"]?.(input, output);
27931
+ await directoryReadmeInjector?.["tool.execute.before"]?.(input, output);
27932
+ await rulesInjector?.["tool.execute.before"]?.(input, output);
27829
27933
  if (input.tool === "task") {
27830
27934
  const args = output.args;
27831
27935
  const subagentType = args.subagent_type;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "oh-my-opencode",
3
- "version": "2.4.1",
3
+ "version": "2.4.3",
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",