oh-my-opencode 2.0.3 → 2.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.ko.md CHANGED
@@ -608,7 +608,7 @@ OmO를 비활성화하고 원래 build/plan 에이전트를 복원하려면:
608
608
  }
609
609
  ```
610
610
 
611
- 사용 가능한 훅: `todo-continuation-enforcer`, `context-window-monitor`, `session-recovery`, `session-notification`, `comment-checker`, `grep-output-truncator`, `tool-output-truncator`, `directory-agents-injector`, `directory-readme-injector`, `empty-task-response-detector`, `think-mode`, `anthropic-auto-compact`, `rules-injector`, `background-notification`, `auto-update-checker`, `startup-toast`, `keyword-detector`, `agent-usage-reminder`
611
+ 사용 가능한 훅: `todo-continuation-enforcer`, `context-window-monitor`, `session-recovery`, `session-notification`, `comment-checker`, `grep-output-truncator`, `tool-output-truncator`, `directory-agents-injector`, `directory-readme-injector`, `empty-task-response-detector`, `think-mode`, `anthropic-auto-compact`, `rules-injector`, `background-notification`, `auto-update-checker`, `startup-toast`, `keyword-detector`, `agent-usage-reminder`, `non-interactive-env`
612
612
 
613
613
  ### MCPs
614
614
 
package/README.md CHANGED
@@ -609,7 +609,7 @@ Disable specific built-in hooks via `disabled_hooks` in `~/.config/opencode/oh-m
609
609
  }
610
610
  ```
611
611
 
612
- Available hooks: `todo-continuation-enforcer`, `context-window-monitor`, `session-recovery`, `session-notification`, `comment-checker`, `grep-output-truncator`, `tool-output-truncator`, `directory-agents-injector`, `directory-readme-injector`, `empty-task-response-detector`, `think-mode`, `anthropic-auto-compact`, `rules-injector`, `background-notification`, `auto-update-checker`, `startup-toast`, `keyword-detector`, `agent-usage-reminder`
612
+ Available hooks: `todo-continuation-enforcer`, `context-window-monitor`, `session-recovery`, `session-notification`, `comment-checker`, `grep-output-truncator`, `tool-output-truncator`, `directory-agents-injector`, `directory-readme-injector`, `empty-task-response-detector`, `think-mode`, `anthropic-auto-compact`, `rules-injector`, `background-notification`, `auto-update-checker`, `startup-toast`, `keyword-detector`, `agent-usage-reminder`, `non-interactive-env`
613
613
 
614
614
  ### MCPs
615
615
 
@@ -33,6 +33,7 @@ export declare const HookNameSchema: z.ZodEnum<{
33
33
  "comment-checker": "comment-checker";
34
34
  "rules-injector": "rules-injector";
35
35
  "agent-usage-reminder": "agent-usage-reminder";
36
+ "non-interactive-env": "non-interactive-env";
36
37
  "todo-continuation-enforcer": "todo-continuation-enforcer";
37
38
  "context-window-monitor": "context-window-monitor";
38
39
  "session-recovery": "session-recovery";
@@ -587,6 +588,7 @@ export declare const OhMyOpenCodeConfigSchema: z.ZodObject<{
587
588
  "comment-checker": "comment-checker";
588
589
  "rules-injector": "rules-injector";
589
590
  "agent-usage-reminder": "agent-usage-reminder";
591
+ "non-interactive-env": "non-interactive-env";
590
592
  "todo-continuation-enforcer": "todo-continuation-enforcer";
591
593
  "context-window-monitor": "context-window-monitor";
592
594
  "session-recovery": "session-recovery";
@@ -6,3 +6,4 @@ export declare const VERSION_FILE: string;
6
6
  export declare const INSTALLED_PACKAGE_JSON: string;
7
7
  export declare const USER_CONFIG_DIR: string;
8
8
  export declare const USER_OPENCODE_CONFIG: string;
9
+ export declare const USER_OPENCODE_CONFIG_JSONC: string;
@@ -16,3 +16,4 @@ export { createBackgroundNotificationHook } from "./background-notification";
16
16
  export { createAutoUpdateCheckerHook } from "./auto-update-checker";
17
17
  export { createAgentUsageReminderHook } from "./agent-usage-reminder";
18
18
  export { createKeywordDetectorHook } from "./keyword-detector";
19
+ export { createNonInteractiveEnvHook } from "./non-interactive-env";
@@ -0,0 +1,2 @@
1
+ export declare const HOOK_NAME = "non-interactive-env";
2
+ export declare const NON_INTERACTIVE_ENV: Record<string, string>;
@@ -0,0 +1,12 @@
1
+ import type { PluginInput } from "@opencode-ai/plugin";
2
+ export * from "./constants";
3
+ export * from "./types";
4
+ export declare function createNonInteractiveEnvHook(_ctx: PluginInput): {
5
+ "tool.execute.before": (input: {
6
+ tool: string;
7
+ sessionID: string;
8
+ callID: string;
9
+ }, output: {
10
+ args: Record<string, unknown>;
11
+ }) => Promise<void>;
12
+ };
@@ -0,0 +1,3 @@
1
+ export interface NonInteractiveEnvConfig {
2
+ disabled?: boolean;
3
+ }
@@ -10,6 +10,7 @@ export declare function findEmptyMessages(sessionID: string): string[];
10
10
  export declare function findEmptyMessageByIndex(sessionID: string, targetIndex: number): string | null;
11
11
  export declare function findFirstEmptyMessage(sessionID: string): string | null;
12
12
  export declare function findMessagesWithThinkingBlocks(sessionID: string): string[];
13
+ export declare function findMessagesWithThinkingOnly(sessionID: string): string[];
13
14
  export declare function findMessagesWithOrphanThinking(sessionID: string): string[];
14
15
  export declare function prependThinkingPart(sessionID: string, messageID: string): boolean;
15
16
  export declare function stripThinkingParts(messageID: string): boolean;
package/dist/index.js CHANGED
@@ -3879,7 +3879,7 @@ function findEmptyMessages(sessionID) {
3879
3879
  }
3880
3880
  function findEmptyMessageByIndex(sessionID, targetIndex) {
3881
3881
  const messages = readMessages(sessionID);
3882
- const indicesToTry = [targetIndex, targetIndex - 1];
3882
+ const indicesToTry = [targetIndex, targetIndex - 1, targetIndex - 2];
3883
3883
  for (const idx of indicesToTry) {
3884
3884
  if (idx < 0 || idx >= messages.length)
3885
3885
  continue;
@@ -3904,6 +3904,23 @@ function findMessagesWithThinkingBlocks(sessionID) {
3904
3904
  }
3905
3905
  return result;
3906
3906
  }
3907
+ function findMessagesWithThinkingOnly(sessionID) {
3908
+ const messages = readMessages(sessionID);
3909
+ const result = [];
3910
+ for (const msg of messages) {
3911
+ if (msg.role !== "assistant")
3912
+ continue;
3913
+ const parts = readParts(msg.id);
3914
+ if (parts.length === 0)
3915
+ continue;
3916
+ const hasThinking = parts.some((p) => THINKING_TYPES.has(p.type));
3917
+ const hasTextContent = parts.some(hasContent);
3918
+ if (hasThinking && !hasTextContent) {
3919
+ result.push(msg.id);
3920
+ }
3921
+ }
3922
+ return result;
3923
+ }
3907
3924
  function findMessagesWithOrphanThinking(sessionID) {
3908
3925
  const messages = readMessages(sessionID);
3909
3926
  const result = [];
@@ -4072,24 +4089,29 @@ async function recoverThinkingDisabledViolation(_client, sessionID, _failedAssis
4072
4089
  }
4073
4090
  return anySuccess;
4074
4091
  }
4092
+ var PLACEHOLDER_TEXT = "[user interrupted]";
4075
4093
  async function recoverEmptyContentMessage(_client, sessionID, failedAssistantMsg, _directory, error) {
4076
4094
  const targetIndex = extractMessageIndex(error);
4077
4095
  const failedID = failedAssistantMsg.info?.id;
4096
+ const thinkingOnlyIDs = findMessagesWithThinkingOnly(sessionID);
4097
+ for (const messageID of thinkingOnlyIDs) {
4098
+ injectTextPart(sessionID, messageID, PLACEHOLDER_TEXT);
4099
+ }
4078
4100
  if (targetIndex !== null) {
4079
4101
  const targetMessageID = findEmptyMessageByIndex(sessionID, targetIndex);
4080
4102
  if (targetMessageID) {
4081
- return injectTextPart(sessionID, targetMessageID, "(interrupted)");
4103
+ return injectTextPart(sessionID, targetMessageID, PLACEHOLDER_TEXT);
4082
4104
  }
4083
4105
  }
4084
4106
  if (failedID) {
4085
- if (injectTextPart(sessionID, failedID, "(interrupted)")) {
4107
+ if (injectTextPart(sessionID, failedID, PLACEHOLDER_TEXT)) {
4086
4108
  return true;
4087
4109
  }
4088
4110
  }
4089
4111
  const emptyMessageIDs = findEmptyMessages(sessionID);
4090
- let anySuccess = false;
4112
+ let anySuccess = thinkingOnlyIDs.length > 0;
4091
4113
  for (const messageID of emptyMessageIDs) {
4092
- if (injectTextPart(sessionID, messageID, "(interrupted)")) {
4114
+ if (injectTextPart(sessionID, messageID, PLACEHOLDER_TEXT)) {
4093
4115
  anySuccess = true;
4094
4116
  }
4095
4117
  }
@@ -6979,17 +7001,25 @@ function getUserConfigDir() {
6979
7001
  }
6980
7002
  var USER_CONFIG_DIR = getUserConfigDir();
6981
7003
  var USER_OPENCODE_CONFIG = path3.join(USER_CONFIG_DIR, "opencode", "opencode.json");
7004
+ var USER_OPENCODE_CONFIG_JSONC = path3.join(USER_CONFIG_DIR, "opencode", "opencode.jsonc");
6982
7005
 
6983
7006
  // src/hooks/auto-update-checker/checker.ts
6984
7007
  function isLocalDevMode(directory) {
6985
7008
  return getLocalDevPath(directory) !== null;
6986
7009
  }
6987
7010
  function stripJsonComments(json) {
6988
- return json.replace(/^\s*\/\/.*$/gm, "").replace(/,(\s*[}\]])/g, "$1");
7011
+ return json.replace(/\\"|"(?:\\"|[^"])*"|(\/\/.*|\/\*[\s\S]*?\*\/)/g, (m, g) => g ? "" : m).replace(/,(\s*[}\]])/g, "$1");
7012
+ }
7013
+ function getConfigPaths(directory) {
7014
+ return [
7015
+ path4.join(directory, ".opencode", "opencode.json"),
7016
+ path4.join(directory, ".opencode", "opencode.jsonc"),
7017
+ USER_OPENCODE_CONFIG,
7018
+ USER_OPENCODE_CONFIG_JSONC
7019
+ ];
6989
7020
  }
6990
7021
  function getLocalDevPath(directory) {
6991
- const projectConfig = path4.join(directory, ".opencode", "opencode.json");
6992
- for (const configPath of [projectConfig, USER_OPENCODE_CONFIG]) {
7022
+ for (const configPath of getConfigPaths(directory)) {
6993
7023
  try {
6994
7024
  if (!fs4.existsSync(configPath))
6995
7025
  continue;
@@ -6998,7 +7028,11 @@ function getLocalDevPath(directory) {
6998
7028
  const plugins = config.plugin ?? [];
6999
7029
  for (const entry of plugins) {
7000
7030
  if (entry.startsWith("file://") && entry.includes(PACKAGE_NAME)) {
7001
- return entry.replace("file://", "");
7031
+ try {
7032
+ return fileURLToPath(entry);
7033
+ } catch {
7034
+ return entry.replace("file://", "");
7035
+ }
7002
7036
  }
7003
7037
  }
7004
7038
  } catch {
@@ -7045,8 +7079,7 @@ function getLocalDevVersion(directory) {
7045
7079
  }
7046
7080
  }
7047
7081
  function findPluginEntry(directory) {
7048
- const projectConfig = path4.join(directory, ".opencode", "opencode.json");
7049
- for (const configPath of [projectConfig, USER_OPENCODE_CONFIG]) {
7082
+ for (const configPath of getConfigPaths(directory)) {
7050
7083
  try {
7051
7084
  if (!fs4.existsSync(configPath))
7052
7085
  continue;
@@ -7508,6 +7541,38 @@ function createKeywordDetectorHook() {
7508
7541
  }
7509
7542
  };
7510
7543
  }
7544
+ // src/hooks/non-interactive-env/constants.ts
7545
+ var HOOK_NAME = "non-interactive-env";
7546
+ var NON_INTERACTIVE_ENV = {
7547
+ CI: "true",
7548
+ DEBIAN_FRONTEND: "noninteractive",
7549
+ GIT_TERMINAL_PROMPT: "0",
7550
+ GCM_INTERACTIVE: "never",
7551
+ HOMEBREW_NO_AUTO_UPDATE: "1"
7552
+ };
7553
+
7554
+ // src/hooks/non-interactive-env/index.ts
7555
+ function createNonInteractiveEnvHook(_ctx) {
7556
+ return {
7557
+ "tool.execute.before": async (input, output) => {
7558
+ if (input.tool.toLowerCase() !== "bash") {
7559
+ return;
7560
+ }
7561
+ const command = output.args.command;
7562
+ if (!command) {
7563
+ return;
7564
+ }
7565
+ output.args.env = {
7566
+ ...output.args.env,
7567
+ ...NON_INTERACTIVE_ENV
7568
+ };
7569
+ log(`[${HOOK_NAME}] Set non-interactive environment variables`, {
7570
+ sessionID: input.sessionID,
7571
+ env: NON_INTERACTIVE_ENV
7572
+ });
7573
+ }
7574
+ };
7575
+ }
7511
7576
  // src/auth/antigravity/constants.ts
7512
7577
  var ANTIGRAVITY_CLIENT_ID = "1071006060591-tmhssin2h21lcre235vtolojh4g403ep.apps.googleusercontent.com";
7513
7578
  var ANTIGRAVITY_CLIENT_SECRET = "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";
@@ -9661,7 +9726,7 @@ function loadJsonFile(path6) {
9661
9726
  return null;
9662
9727
  }
9663
9728
  }
9664
- function getConfigPaths() {
9729
+ function getConfigPaths2() {
9665
9730
  const cwd = process.cwd();
9666
9731
  return {
9667
9732
  project: join31(cwd, ".opencode", "oh-my-opencode.json"),
@@ -9670,7 +9735,7 @@ function getConfigPaths() {
9670
9735
  };
9671
9736
  }
9672
9737
  function loadAllConfigs() {
9673
- const paths = getConfigPaths();
9738
+ const paths = getConfigPaths2();
9674
9739
  const configs = new Map;
9675
9740
  const project2 = loadJsonFile(paths.project);
9676
9741
  if (project2)
@@ -20693,10 +20758,10 @@ function _property(property, schema, params) {
20693
20758
  ...normalizeParams(params)
20694
20759
  });
20695
20760
  }
20696
- function _mime(types10, params) {
20761
+ function _mime(types11, params) {
20697
20762
  return new $ZodCheckMimeType({
20698
20763
  check: "mime_type",
20699
- mime: types10,
20764
+ mime: types11,
20700
20765
  ...normalizeParams(params)
20701
20766
  });
20702
20767
  }
@@ -22606,7 +22671,7 @@ var ZodFile = /* @__PURE__ */ $constructor("ZodFile", (inst, def) => {
22606
22671
  ZodType.init(inst, def);
22607
22672
  inst.min = (size, params) => inst.check(_minSize(size, params));
22608
22673
  inst.max = (size, params) => inst.check(_maxSize(size, params));
22609
- inst.mime = (types10, params) => inst.check(_mime(Array.isArray(types10) ? types10 : [types10], params));
22674
+ inst.mime = (types11, params) => inst.check(_mime(Array.isArray(types11) ? types11 : [types11], params));
22610
22675
  });
22611
22676
  function file(params) {
22612
22677
  return _file(ZodFile, params);
@@ -25599,7 +25664,8 @@ var HookNameSchema = exports_external.enum([
25599
25664
  "auto-update-checker",
25600
25665
  "startup-toast",
25601
25666
  "keyword-detector",
25602
- "agent-usage-reminder"
25667
+ "agent-usage-reminder",
25668
+ "non-interactive-env"
25603
25669
  ]);
25604
25670
  var AgentOverrideConfigSchema = exports_external.object({
25605
25671
  model: exports_external.string().optional(),
@@ -25765,6 +25831,7 @@ var OhMyOpenCodePlugin = async (ctx) => {
25765
25831
  }) : null;
25766
25832
  const keywordDetector = isHookEnabled("keyword-detector") ? createKeywordDetectorHook() : null;
25767
25833
  const agentUsageReminder = isHookEnabled("agent-usage-reminder") ? createAgentUsageReminderHook(ctx) : null;
25834
+ const nonInteractiveEnv = isHookEnabled("non-interactive-env") ? createNonInteractiveEnvHook(ctx) : null;
25768
25835
  updateTerminalTitle({ sessionId: "main" });
25769
25836
  const backgroundManager = new BackgroundManager(ctx);
25770
25837
  const backgroundNotificationHook = isHookEnabled("background-notification") ? createBackgroundNotificationHook(backgroundManager) : null;
@@ -25957,6 +26024,7 @@ var OhMyOpenCodePlugin = async (ctx) => {
25957
26024
  },
25958
26025
  "tool.execute.before": async (input, output) => {
25959
26026
  await claudeCodeHooks["tool.execute.before"](input, output);
26027
+ await nonInteractiveEnv?.["tool.execute.before"](input, output);
25960
26028
  await commentChecker?.["tool.execute.before"](input, output);
25961
26029
  if (input.sessionID === getMainSessionID()) {
25962
26030
  updateTerminalTitle({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "oh-my-opencode",
3
- "version": "2.0.3",
3
+ "version": "2.0.4",
4
4
  "description": "OpenCode plugin - custom agents (oracle, librarian) and enhanced features",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",