oh-my-opencode 2.8.0 → 2.8.2

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.ja.md CHANGED
@@ -874,7 +874,7 @@ Oh My OpenCode は以下の場所からフックを読み込んで実行しま
874
874
  }
875
875
  ```
876
876
 
877
- 利用可能なフック:`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-context-window-limit-recovery`, `rules-injector`, `background-notification`, `auto-update-checker`, `startup-toast`, `keyword-detector`, `agent-usage-reminder`, `non-interactive-env`, `interactive-bash-session`, `empty-message-sanitizer`, `preemptive-compaction`, `compaction-context-injector`, `thinking-block-validator`, `claude-code-hooks`, `ralph-loop`, `dcp-for-compaction`
877
+ 利用可能なフック:`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-context-window-limit-recovery`, `rules-injector`, `background-notification`, `auto-update-checker`, `startup-toast`, `keyword-detector`, `agent-usage-reminder`, `non-interactive-env`, `interactive-bash-session`, `empty-message-sanitizer`, `compaction-context-injector`, `thinking-block-validator`, `claude-code-hooks`, `ralph-loop`
878
878
 
879
879
  **`auto-update-checker`と`startup-toast`について**: `startup-toast` フックは `auto-update-checker` のサブ機能です。アップデートチェックは有効なまま起動トースト通知のみを無効化するには、`disabled_hooks` に `"startup-toast"` を追加してください。すべてのアップデートチェック機能(トーストを含む)を無効化するには、`"auto-update-checker"` を追加してください。
880
880
 
@@ -926,20 +926,22 @@ OpenCode でサポートされるすべての LSP 構成およびカスタム設
926
926
  ```json
927
927
  {
928
928
  "experimental": {
929
+ "preemptive_compaction": true,
930
+ "truncate_all_tool_outputs": true,
929
931
  "aggressive_truncation": true,
930
- "auto_resume": true,
931
- "truncate_all_tool_outputs": false
932
+ "auto_resume": true
932
933
  }
933
934
  }
934
935
  ```
935
936
 
936
- | オプション | デフォルト | 説明 |
937
- | --------------------------- | ---------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
938
- | `aggressive_truncation` | `false` | トークン制限を超えた場合、ツール出力を積極的に切り詰めて制限内に収めます。デフォルトの切り詰めより積極的です。不十分な場合は要約/復元にフォールバックします。 |
939
- | `auto_resume` | `false` | thinking block エラーや thinking disabled violation からの回復成功後、自動的にセッションを再開します。最後のユーザーメッセージを抽出して続行します。 |
940
- | `truncate_all_tool_outputs` | `true` | プロンプトが長くなりすぎるのを防ぐため、コンテキストウィンドウの使用状況に基づいてすべてのツール出力を動的に切り詰めます。完全なツール出力が必要な場合は`false`に設定して無効化します。 |
941
-
942
- **注意**: `dcp-for-compaction`(コンパクション用動的コンテキスト整理)はフックとして管理されるようになりました。デフォルトで有効で、`disabled_hooks: ["dcp-for-compaction"]`で無効化できます。
937
+ | オプション | デフォルト | 説明 |
938
+ | --------------------------------- | ---------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
939
+ | `preemptive_compaction` | `false` | トークン制限に達する前にセッションを事前にコンパクションします。デフォルトでコンテキストウィンドウ使用率80%で実行されます。 |
940
+ | `preemptive_compaction_threshold` | `0.80` | プリエンプティブコンパクションをトリガーする閾値(0.5-0.95)。`preemptive_compaction`が有効な場合のみ適用されます。 |
941
+ | `truncate_all_tool_outputs` | `false` | ホワイトリストのツール(Grep、Glob、LSP、AST-grep)だけでなく、すべてのツール出力を切り詰めます。Tool output truncator はデフォルトで有効です - `disabled_hooks`で無効化できます。 |
942
+ | `aggressive_truncation` | `false` | トークン制限を超えた場合、ツール出力を積極的に切り詰めて制限内に収めます。デフォルトの切り詰めより積極的です。不十分な場合は要約/復元にフォールバックします。 |
943
+ | `auto_resume` | `false` | thinking block エラーや thinking disabled violation からの回復成功後、自動的にセッションを再開します。最後のユーザーメッセージを抽出して続行します。 |
944
+ | `dcp_for_compaction` | `false` | コンパクション用DCP(動的コンテキスト整理)を有効化 - トークン制限超過時に最初に実行されます。コンパクション前に重複したツール呼び出しと古いツール出力を整理します。 |
943
945
 
944
946
  **警告**:これらの機能は実験的であり、予期しない動作を引き起こす可能性があります。影響を理解した場合にのみ有効にしてください。
945
947
 
package/README.ko.md CHANGED
@@ -871,7 +871,7 @@ Schema 자동 완성이 지원됩니다:
871
871
  }
872
872
  ```
873
873
 
874
- 사용 가능한 훅: `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-context-window-limit-recovery`, `rules-injector`, `background-notification`, `auto-update-checker`, `startup-toast`, `keyword-detector`, `agent-usage-reminder`, `non-interactive-env`, `interactive-bash-session`, `empty-message-sanitizer`, `preemptive-compaction`, `compaction-context-injector`, `thinking-block-validator`, `claude-code-hooks`, `ralph-loop`, `dcp-for-compaction`
874
+ 사용 가능한 훅: `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-context-window-limit-recovery`, `rules-injector`, `background-notification`, `auto-update-checker`, `startup-toast`, `keyword-detector`, `agent-usage-reminder`, `non-interactive-env`, `interactive-bash-session`, `empty-message-sanitizer`, `compaction-context-injector`, `thinking-block-validator`, `claude-code-hooks`, `ralph-loop`
875
875
 
876
876
  **`auto-update-checker`와 `startup-toast`에 대한 참고사항**: `startup-toast` 훅은 `auto-update-checker`의 하위 기능입니다. 업데이트 확인은 유지하면서 시작 토스트 알림만 비활성화하려면 `disabled_hooks`에 `"startup-toast"`를 추가하세요. 모든 업데이트 확인 기능(토스트 포함)을 비활성화하려면 `"auto-update-checker"`를 추가하세요.
877
877
 
@@ -923,20 +923,22 @@ OpenCode 에서 지원하는 모든 LSP 구성 및 커스텀 설정 (opencode.js
923
923
  ```json
924
924
  {
925
925
  "experimental": {
926
+ "preemptive_compaction": true,
927
+ "truncate_all_tool_outputs": true,
926
928
  "aggressive_truncation": true,
927
- "auto_resume": true,
928
- "truncate_all_tool_outputs": false
929
+ "auto_resume": true
929
930
  }
930
931
  }
931
932
  ```
932
933
 
933
- | 옵션 | 기본값 | 설명 |
934
- | --------------------------- | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- |
935
- | `aggressive_truncation` | `false` | 토큰 제한을 초과하면 도구 출력을 공격적으로 잘라내어 제한 내에 맞춥니다. 기본 truncation보다 공격적입니다. 부족하면 요약/복구로 fallback합니다. |
936
- | `auto_resume` | `false` | thinking block 에러나 thinking disabled violation으로부터 성공적으로 복구한 후 자동으로 세션을 재개합니다. 마지막 사용자 메시지를 추출하여 계속합니다. |
937
- | `truncate_all_tool_outputs` | `true` | 프롬프트가 너무 길어지는 것을 방지하기 위해 컨텍스트 윈도우 사용량에 따라 모든 도구 출력을 동적으로 잘라냅니다. 전체 도구 출력이 필요한 경우 `false`로 설정하여 비활성화하세요. |
938
-
939
- **참고**: `dcp-for-compaction` (컴팩션용 동적 컨텍스트 정리)은 이제 훅으로 관리됩니다. 기본으로 활성화되어 있으며, `disabled_hooks: ["dcp-for-compaction"]`으로 비활성화할 있습니다.
934
+ | 옵션 | 기본값 | 설명 |
935
+ | --------------------------------- | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- |
936
+ | `preemptive_compaction` | `false` | 토큰 제한에 도달하기 전에 세션을 미리 컴팩션합니다. 기본적으로 컨텍스트 윈도우 사용량이 80%일 실행됩니다. |
937
+ | `preemptive_compaction_threshold` | `0.80` | 선제적 컴팩션을 트리거할 임계값 비율(0.5-0.95). `preemptive_compaction`이 활성화된 경우에만 적용됩니다. |
938
+ | `truncate_all_tool_outputs` | `false` | 화이트리스트 도구(Grep, Glob, LSP, AST-grep)만이 아닌 모든 도구 출력을 잘라냅니다. Tool output truncator는 기본적으로 활성화됩니다 - `disabled_hooks`로 비활성화 가능합니다. |
939
+ | `aggressive_truncation` | `false` | 토큰 제한을 초과하면 도구 출력을 공격적으로 잘라내어 제한 내에 맞춥니다. 기본 truncation보다 더 공격적입니다. 부족하면 요약/복구로 fallback합니다. |
940
+ | `auto_resume` | `false` | thinking block 에러나 thinking disabled violation으로부터 성공적으로 복구한 자동으로 세션을 재개합니다. 마지막 사용자 메시지를 추출하여 계속합니다. |
941
+ | `dcp_for_compaction` | `false` | 컴팩션용 DCP(동적 컨텍스트 정리) 활성화 - 토큰 제한 초과 시 먼저 실행됩니다. 컴팩션 전에 중복 도구 호출과 오래된 도구 출력을 정리합니다. |
940
942
 
941
943
  **경고**: 이 기능들은 실험적이며 예상치 못한 동작을 유발할 수 있습니다. 의미를 이해한 경우에만 활성화하세요.
942
944
 
package/README.md CHANGED
@@ -910,7 +910,7 @@ Disable specific built-in hooks via `disabled_hooks` in `~/.config/opencode/oh-m
910
910
  }
911
911
  ```
912
912
 
913
- 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-context-window-limit-recovery`, `rules-injector`, `background-notification`, `auto-update-checker`, `startup-toast`, `keyword-detector`, `agent-usage-reminder`, `non-interactive-env`, `interactive-bash-session`, `empty-message-sanitizer`, `preemptive-compaction`, `compaction-context-injector`, `thinking-block-validator`, `claude-code-hooks`, `ralph-loop`, `dcp-for-compaction`
913
+ 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-context-window-limit-recovery`, `rules-injector`, `background-notification`, `auto-update-checker`, `startup-toast`, `keyword-detector`, `agent-usage-reminder`, `non-interactive-env`, `interactive-bash-session`, `empty-message-sanitizer`, `compaction-context-injector`, `thinking-block-validator`, `claude-code-hooks`, `ralph-loop`
914
914
 
915
915
  **Note on `auto-update-checker` and `startup-toast`**: The `startup-toast` hook is a sub-feature of `auto-update-checker`. To disable only the startup toast notification while keeping update checking enabled, add `"startup-toast"` to `disabled_hooks`. To disable all update checking features (including the toast), add `"auto-update-checker"` to `disabled_hooks`.
916
916
 
@@ -962,20 +962,22 @@ Opt-in experimental features that may change or be removed in future versions. U
962
962
  ```json
963
963
  {
964
964
  "experimental": {
965
+ "preemptive_compaction": true,
966
+ "truncate_all_tool_outputs": true,
965
967
  "aggressive_truncation": true,
966
- "auto_resume": true,
967
- "truncate_all_tool_outputs": false
968
+ "auto_resume": true
968
969
  }
969
970
  }
970
971
  ```
971
972
 
972
973
  | Option | Default | Description |
973
974
  | --------------------------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
975
+ | `preemptive_compaction` | `false` | Compacts session proactively before hitting hard token limits. Runs at 80% context window usage by default. |
976
+ | `preemptive_compaction_threshold` | `0.80` | Threshold percentage (0.5-0.95) to trigger preemptive compaction. Only applies when `preemptive_compaction` is enabled. |
977
+ | `truncate_all_tool_outputs` | `false` | Truncates ALL tool outputs instead of just whitelisted tools (Grep, Glob, LSP, AST-grep). Tool output truncator is enabled by default - disable via `disabled_hooks`. |
974
978
  | `aggressive_truncation` | `false` | When token limit is exceeded, aggressively truncates tool outputs to fit within limits. More aggressive than the default truncation behavior. Falls back to summarize/revert if insufficient. |
975
979
  | `auto_resume` | `false` | Automatically resumes session after successful recovery from thinking block errors or thinking disabled violations. Extracts the last user message and continues. |
976
- | `truncate_all_tool_outputs` | `true` | Dynamically truncates ALL tool outputs based on context window usage to prevent prompts from becoming too long. Disable by setting to `false` if you need full tool outputs. |
977
-
978
- **Note**: `dcp-for-compaction` (Dynamic Context Pruning for compaction) is now a hook, not an experimental feature. It's enabled by default and can be disabled via `disabled_hooks: ["dcp-for-compaction"]`.
980
+ | `dcp_for_compaction` | `false` | Enable DCP (Dynamic Context Pruning) for compaction - runs first when token limit exceeded. Prunes duplicate tool calls and old tool outputs before running compaction. |
979
981
 
980
982
  **Warning**: These features are experimental and may cause unexpected behavior. Enable only if you understand the implications.
981
983
 
package/README.zh-cn.md CHANGED
@@ -878,7 +878,7 @@ Sisyphus Agent 也能自定义:
878
878
  }
879
879
  ```
880
880
 
881
- 可关的 hook:`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-context-window-limit-recovery`、`rules-injector`、`background-notification`、`auto-update-checker`、`startup-toast`、`keyword-detector`、`agent-usage-reminder`、`non-interactive-env`、`interactive-bash-session`、`empty-message-sanitizer`、`preemptive-compaction`、`compaction-context-injector`、`thinking-block-validator`、`claude-code-hooks`、`ralph-loop`、`dcp-for-compaction`
881
+ 可关的 hook:`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-context-window-limit-recovery`、`rules-injector`、`background-notification`、`auto-update-checker`、`startup-toast`、`keyword-detector`、`agent-usage-reminder`、`non-interactive-env`、`interactive-bash-session`、`empty-message-sanitizer`、`compaction-context-injector`、`thinking-block-validator`、`claude-code-hooks`、`ralph-loop`
882
882
 
883
883
  **关于 `auto-update-checker` 和 `startup-toast`**: `startup-toast` hook 是 `auto-update-checker` 的子功能。若想保持更新检查但只禁用启动提示通知,在 `disabled_hooks` 中添加 `"startup-toast"`。若要禁用所有更新检查功能(包括提示),添加 `"auto-update-checker"`。
884
884
 
@@ -930,20 +930,22 @@ Oh My OpenCode 送你重构工具(重命名、代码操作)。
930
930
  ```json
931
931
  {
932
932
  "experimental": {
933
+ "preemptive_compaction": true,
934
+ "truncate_all_tool_outputs": true,
933
935
  "aggressive_truncation": true,
934
- "auto_resume": true,
935
- "truncate_all_tool_outputs": false
936
+ "auto_resume": true
936
937
  }
937
938
  }
938
939
  ```
939
940
 
940
- | 选项 | 默认值 | 说明 |
941
- | --------------------------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------- |
942
- | `aggressive_truncation` | `false` | 超出 token 限制时,激进地截断工具输出以适应限制。比默认截断更激进。不够的话会回退到摘要/恢复。 |
943
- | `auto_resume` | `false` | thinking block 错误或 thinking disabled violation 成功恢复后,自动恢复会话。提取最后一条用户消息继续执行。 |
944
- | `truncate_all_tool_outputs` | `true` | 为防止提示过长,根据上下文窗口使用情况动态截断所有工具输出。如需完整工具输出,设置为 `false` 禁用此功能。 |
945
-
946
- **注意**: `dcp-for-compaction`(压缩用动态上下文剪枝)现在作为 hook 管理。默认启用,可通过 `disabled_hooks: ["dcp-for-compaction"]` 禁用。
941
+ | 选项 | 默认值 | 说明 |
942
+ | --------------------------------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------- |
943
+ | `preemptive_compaction` | `false` | 在达到 token 限制之前主动压缩会话。默认在上下文窗口使用率达到 80% 时运行。 |
944
+ | `preemptive_compaction_threshold` | `0.80` | 触发预先压缩的阈值比例(0.5-0.95)。仅在 `preemptive_compaction` 启用时生效。 |
945
+ | `truncate_all_tool_outputs` | `false` | 截断所有工具输出,而不仅仅是白名单工具(Grep、Glob、LSP、AST-grep)。Tool output truncator 默认启用 - 使用 `disabled_hooks` 禁用。 |
946
+ | `aggressive_truncation` | `false` | 超出 token 限制时,激进地截断工具输出以适应限制。比默认截断更激进。不够的话会回退到摘要/恢复。 |
947
+ | `auto_resume` | `false` | thinking block 错误或 thinking disabled violation 成功恢复后,自动恢复会话。提取最后一条用户消息继续执行。 |
948
+ | `dcp_for_compaction` | `false` | 启用压缩用 DCP(动态上下文剪枝)- 在超出 token 限制时首先执行。在压缩前清理重复的工具调用和旧的工具输出。 |
947
949
 
948
950
  **警告**:这些功能是实验性的,可能会导致意外行为。只有在理解其影响的情况下才启用。
949
951
 
@@ -12,7 +12,13 @@ export declare function isOpenCodeInstalled(): Promise<boolean>;
12
12
  export declare function getOpenCodeVersion(): Promise<string | null>;
13
13
  export declare function addAuthPlugins(config: InstallConfig): Promise<ConfigMergeResult>;
14
14
  export declare function setupChatGPTHotfix(): ConfigMergeResult;
15
+ export interface BunInstallResult {
16
+ success: boolean;
17
+ timedOut?: boolean;
18
+ error?: string;
19
+ }
15
20
  export declare function runBunInstall(): Promise<boolean>;
21
+ export declare function runBunInstallWithDetails(): Promise<BunInstallResult>;
16
22
  export declare const ANTIGRAVITY_PROVIDER_CONFIG: {
17
23
  google: {
18
24
  name: string;
package/dist/cli/index.js CHANGED
@@ -2657,7 +2657,7 @@ var require_napi = __commonJS((exports, module) => {
2657
2657
  var require_package = __commonJS((exports, module) => {
2658
2658
  module.exports = {
2659
2659
  name: "oh-my-opencode",
2660
- version: "2.7.2",
2660
+ version: "2.8.1",
2661
2661
  description: "OpenCode plugin - custom agents (oracle, librarian) and enhanced features",
2662
2662
  main: "dist/index.js",
2663
2663
  types: "dist/index.d.ts",
@@ -2680,7 +2680,7 @@ var require_package = __commonJS((exports, module) => {
2680
2680
  "./schema.json": "./dist/oh-my-opencode.schema.json"
2681
2681
  },
2682
2682
  scripts: {
2683
- build: "bun build src/index.ts src/google-auth.ts --outdir dist --target bun --format esm --external @ast-grep/napi && tsc --emitDeclarationOnly && bun build src/cli/index.ts --outdir dist/cli --target bun --format esm && bun run build:schema",
2683
+ build: "bun build src/index.ts src/google-auth.ts --outdir dist --target bun --format esm --external @ast-grep/napi && tsc --emitDeclarationOnly && bun build src/cli/index.ts --outdir dist/cli --target bun --format esm --external @ast-grep/napi && bun run build:schema",
2684
2684
  "build:schema": "bun run script/build-schema.ts",
2685
2685
  clean: "rm -rf dist",
2686
2686
  prepublishOnly: "bun run clean && bun run build",
@@ -3335,7 +3335,7 @@ var Y2 = ({ indicator: t = "dots" } = {}) => {
3335
3335
  var import_picocolors2 = __toESM(require_picocolors(), 1);
3336
3336
 
3337
3337
  // src/cli/config-manager.ts
3338
- import { existsSync as existsSync2, mkdirSync, readFileSync as readFileSync2, writeFileSync } from "fs";
3338
+ import { existsSync as existsSync2, mkdirSync, readFileSync as readFileSync2, writeFileSync, statSync } from "fs";
3339
3339
  import { homedir } from "os";
3340
3340
  import { join as join2 } from "path";
3341
3341
  // src/shared/command-executor.ts
@@ -4233,6 +4233,35 @@ var OPENCODE_PACKAGE_JSON = join2(OPENCODE_CONFIG_DIR, "package.json");
4233
4233
  var OMO_CONFIG = join2(OPENCODE_CONFIG_DIR, "oh-my-opencode.json");
4234
4234
  var OPENCODE_BINARIES = ["opencode", "opencode-desktop"];
4235
4235
  var CHATGPT_HOTFIX_REPO = "code-yeongyu/opencode-openai-codex-auth#fix/orphaned-function-call-output-with-tools";
4236
+ var BUN_INSTALL_TIMEOUT_SECONDS = 60;
4237
+ var BUN_INSTALL_TIMEOUT_MS = BUN_INSTALL_TIMEOUT_SECONDS * 1000;
4238
+ function isPermissionError(err) {
4239
+ const nodeErr = err;
4240
+ return nodeErr?.code === "EACCES" || nodeErr?.code === "EPERM";
4241
+ }
4242
+ function isFileNotFoundError(err) {
4243
+ const nodeErr = err;
4244
+ return nodeErr?.code === "ENOENT";
4245
+ }
4246
+ function formatErrorWithSuggestion(err, context) {
4247
+ if (isPermissionError(err)) {
4248
+ return `Permission denied: Cannot ${context}. Try running with elevated permissions or check file ownership.`;
4249
+ }
4250
+ if (isFileNotFoundError(err)) {
4251
+ return `File not found while trying to ${context}. The file may have been deleted or moved.`;
4252
+ }
4253
+ if (err instanceof SyntaxError) {
4254
+ return `JSON syntax error while trying to ${context}: ${err.message}. Check for missing commas, brackets, or invalid characters.`;
4255
+ }
4256
+ const message = err instanceof Error ? err.message : String(err);
4257
+ if (message.includes("ENOSPC")) {
4258
+ return `Disk full: Cannot ${context}. Free up disk space and try again.`;
4259
+ }
4260
+ if (message.includes("EROFS")) {
4261
+ return `Read-only filesystem: Cannot ${context}. Check if the filesystem is mounted read-only.`;
4262
+ }
4263
+ return `Failed to ${context}: ${message}`;
4264
+ }
4236
4265
  async function fetchLatestVersion(packageName) {
4237
4266
  try {
4238
4267
  const res = await fetch(`https://registry.npmjs.org/${packageName}/latest`);
@@ -4253,12 +4282,29 @@ function detectConfigFormat() {
4253
4282
  }
4254
4283
  return { format: "none", path: OPENCODE_JSON };
4255
4284
  }
4256
- function parseConfig(path2, isJsonc) {
4285
+ function isEmptyOrWhitespace(content) {
4286
+ return content.trim().length === 0;
4287
+ }
4288
+ function parseConfigWithError(path2) {
4257
4289
  try {
4290
+ const stat = statSync(path2);
4291
+ if (stat.size === 0) {
4292
+ return { config: null, error: `Config file is empty: ${path2}. Delete it or add valid JSON content.` };
4293
+ }
4258
4294
  const content = readFileSync2(path2, "utf-8");
4259
- return parseJsonc(content);
4260
- } catch {
4261
- return null;
4295
+ if (isEmptyOrWhitespace(content)) {
4296
+ return { config: null, error: `Config file contains only whitespace: ${path2}. Delete it or add valid JSON content.` };
4297
+ }
4298
+ const config = parseJsonc(content);
4299
+ if (config === null || config === undefined) {
4300
+ return { config: null, error: `Config file parsed to null/undefined: ${path2}. Ensure it contains valid JSON.` };
4301
+ }
4302
+ if (typeof config !== "object" || Array.isArray(config)) {
4303
+ return { config: null, error: `Config file must contain a JSON object, not ${Array.isArray(config) ? "an array" : typeof config}: ${path2}` };
4304
+ }
4305
+ return { config };
4306
+ } catch (err) {
4307
+ return { config: null, error: formatErrorWithSuggestion(err, `parse config file ${path2}`) };
4262
4308
  }
4263
4309
  }
4264
4310
  function ensureConfigDir() {
@@ -4267,7 +4313,11 @@ function ensureConfigDir() {
4267
4313
  }
4268
4314
  }
4269
4315
  function addPluginToOpenCodeConfig() {
4270
- ensureConfigDir();
4316
+ try {
4317
+ ensureConfigDir();
4318
+ } catch (err) {
4319
+ return { success: false, configPath: OPENCODE_CONFIG_DIR, error: formatErrorWithSuggestion(err, "create config directory") };
4320
+ }
4271
4321
  const { format: format2, path: path2 } = detectConfigFormat();
4272
4322
  const pluginName = "oh-my-opencode";
4273
4323
  try {
@@ -4277,10 +4327,11 @@ function addPluginToOpenCodeConfig() {
4277
4327
  `);
4278
4328
  return { success: true, configPath: path2 };
4279
4329
  }
4280
- const config = parseConfig(path2, format2 === "jsonc");
4281
- if (!config) {
4282
- return { success: false, configPath: path2, error: "Failed to parse config" };
4330
+ const parseResult = parseConfigWithError(path2);
4331
+ if (!parseResult.config) {
4332
+ return { success: false, configPath: path2, error: parseResult.error ?? "Failed to parse config file" };
4283
4333
  }
4334
+ const config = parseResult.config;
4284
4335
  const plugins = config.plugin ?? [];
4285
4336
  if (plugins.some((p2) => p2.startsWith(pluginName))) {
4286
4337
  return { success: true, configPath: path2 };
@@ -4309,7 +4360,7 @@ function addPluginToOpenCodeConfig() {
4309
4360
  }
4310
4361
  return { success: true, configPath: path2 };
4311
4362
  } catch (err) {
4312
- return { success: false, configPath: path2, error: String(err) };
4363
+ return { success: false, configPath: path2, error: formatErrorWithSuggestion(err, "update opencode config") };
4313
4364
  }
4314
4365
  }
4315
4366
  function deepMerge(target, source) {
@@ -4366,23 +4417,47 @@ function generateOmoConfig(installConfig) {
4366
4417
  return config;
4367
4418
  }
4368
4419
  function writeOmoConfig(installConfig) {
4369
- ensureConfigDir();
4420
+ try {
4421
+ ensureConfigDir();
4422
+ } catch (err) {
4423
+ return { success: false, configPath: OPENCODE_CONFIG_DIR, error: formatErrorWithSuggestion(err, "create config directory") };
4424
+ }
4370
4425
  try {
4371
4426
  const newConfig = generateOmoConfig(installConfig);
4372
4427
  if (existsSync2(OMO_CONFIG)) {
4373
- const content = readFileSync2(OMO_CONFIG, "utf-8");
4374
- const existing = parseJsonc(content);
4375
- delete existing.agents;
4376
- const merged = deepMerge(existing, newConfig);
4377
- writeFileSync(OMO_CONFIG, JSON.stringify(merged, null, 2) + `
4428
+ try {
4429
+ const stat = statSync(OMO_CONFIG);
4430
+ const content = readFileSync2(OMO_CONFIG, "utf-8");
4431
+ if (stat.size === 0 || isEmptyOrWhitespace(content)) {
4432
+ writeFileSync(OMO_CONFIG, JSON.stringify(newConfig, null, 2) + `
4433
+ `);
4434
+ return { success: true, configPath: OMO_CONFIG };
4435
+ }
4436
+ const existing = parseJsonc(content);
4437
+ if (!existing || typeof existing !== "object" || Array.isArray(existing)) {
4438
+ writeFileSync(OMO_CONFIG, JSON.stringify(newConfig, null, 2) + `
4439
+ `);
4440
+ return { success: true, configPath: OMO_CONFIG };
4441
+ }
4442
+ delete existing.agents;
4443
+ const merged = deepMerge(existing, newConfig);
4444
+ writeFileSync(OMO_CONFIG, JSON.stringify(merged, null, 2) + `
4445
+ `);
4446
+ } catch (parseErr) {
4447
+ if (parseErr instanceof SyntaxError) {
4448
+ writeFileSync(OMO_CONFIG, JSON.stringify(newConfig, null, 2) + `
4378
4449
  `);
4450
+ return { success: true, configPath: OMO_CONFIG };
4451
+ }
4452
+ throw parseErr;
4453
+ }
4379
4454
  } else {
4380
4455
  writeFileSync(OMO_CONFIG, JSON.stringify(newConfig, null, 2) + `
4381
4456
  `);
4382
4457
  }
4383
4458
  return { success: true, configPath: OMO_CONFIG };
4384
4459
  } catch (err) {
4385
- return { success: false, configPath: OMO_CONFIG, error: String(err) };
4460
+ return { success: false, configPath: OMO_CONFIG, error: formatErrorWithSuggestion(err, "write oh-my-opencode config") };
4386
4461
  }
4387
4462
  }
4388
4463
  async function findOpenCodeBinaryWithVersion() {
@@ -4412,10 +4487,22 @@ async function getOpenCodeVersion() {
4412
4487
  return result?.version ?? null;
4413
4488
  }
4414
4489
  async function addAuthPlugins(config) {
4415
- ensureConfigDir();
4490
+ try {
4491
+ ensureConfigDir();
4492
+ } catch (err) {
4493
+ return { success: false, configPath: OPENCODE_CONFIG_DIR, error: formatErrorWithSuggestion(err, "create config directory") };
4494
+ }
4416
4495
  const { format: format2, path: path2 } = detectConfigFormat();
4417
4496
  try {
4418
- const existingConfig = format2 !== "none" ? parseConfig(path2, format2 === "jsonc") : null;
4497
+ let existingConfig = null;
4498
+ if (format2 !== "none") {
4499
+ const parseResult = parseConfigWithError(path2);
4500
+ if (parseResult.error && !parseResult.config) {
4501
+ existingConfig = {};
4502
+ } else {
4503
+ existingConfig = parseResult.config;
4504
+ }
4505
+ }
4419
4506
  const plugins = existingConfig?.plugin ?? [];
4420
4507
  if (config.hasGemini) {
4421
4508
  const version = await fetchLatestVersion("opencode-antigravity-auth");
@@ -4434,16 +4521,34 @@ async function addAuthPlugins(config) {
4434
4521
  `);
4435
4522
  return { success: true, configPath: path2 };
4436
4523
  } catch (err) {
4437
- return { success: false, configPath: path2, error: String(err) };
4524
+ return { success: false, configPath: path2, error: formatErrorWithSuggestion(err, "add auth plugins to config") };
4438
4525
  }
4439
4526
  }
4440
4527
  function setupChatGPTHotfix() {
4441
- ensureConfigDir();
4528
+ try {
4529
+ ensureConfigDir();
4530
+ } catch (err) {
4531
+ return { success: false, configPath: OPENCODE_CONFIG_DIR, error: formatErrorWithSuggestion(err, "create config directory") };
4532
+ }
4442
4533
  try {
4443
4534
  let packageJson = {};
4444
4535
  if (existsSync2(OPENCODE_PACKAGE_JSON)) {
4445
- const content = readFileSync2(OPENCODE_PACKAGE_JSON, "utf-8");
4446
- packageJson = JSON.parse(content);
4536
+ try {
4537
+ const stat = statSync(OPENCODE_PACKAGE_JSON);
4538
+ const content = readFileSync2(OPENCODE_PACKAGE_JSON, "utf-8");
4539
+ if (stat.size > 0 && !isEmptyOrWhitespace(content)) {
4540
+ packageJson = JSON.parse(content);
4541
+ if (typeof packageJson !== "object" || packageJson === null || Array.isArray(packageJson)) {
4542
+ packageJson = {};
4543
+ }
4544
+ }
4545
+ } catch (parseErr) {
4546
+ if (parseErr instanceof SyntaxError) {
4547
+ packageJson = {};
4548
+ } else {
4549
+ throw parseErr;
4550
+ }
4551
+ }
4447
4552
  }
4448
4553
  const deps = packageJson.dependencies ?? {};
4449
4554
  deps["opencode-openai-codex-auth"] = CHATGPT_HOTFIX_REPO;
@@ -4452,20 +4557,47 @@ function setupChatGPTHotfix() {
4452
4557
  `);
4453
4558
  return { success: true, configPath: OPENCODE_PACKAGE_JSON };
4454
4559
  } catch (err) {
4455
- return { success: false, configPath: OPENCODE_PACKAGE_JSON, error: String(err) };
4560
+ return { success: false, configPath: OPENCODE_PACKAGE_JSON, error: formatErrorWithSuggestion(err, "setup ChatGPT hotfix in package.json") };
4456
4561
  }
4457
4562
  }
4458
4563
  async function runBunInstall() {
4564
+ const result = await runBunInstallWithDetails();
4565
+ return result.success;
4566
+ }
4567
+ async function runBunInstallWithDetails() {
4459
4568
  try {
4460
4569
  const proc = Bun.spawn(["bun", "install"], {
4461
4570
  cwd: OPENCODE_CONFIG_DIR,
4462
4571
  stdout: "pipe",
4463
4572
  stderr: "pipe"
4464
4573
  });
4465
- await proc.exited;
4466
- return proc.exitCode === 0;
4467
- } catch {
4468
- return false;
4574
+ const timeoutPromise = new Promise((resolve) => setTimeout(() => resolve("timeout"), BUN_INSTALL_TIMEOUT_MS));
4575
+ const exitPromise = proc.exited.then(() => "completed");
4576
+ const result = await Promise.race([exitPromise, timeoutPromise]);
4577
+ if (result === "timeout") {
4578
+ try {
4579
+ proc.kill();
4580
+ } catch {}
4581
+ return {
4582
+ success: false,
4583
+ timedOut: true,
4584
+ error: `bun install timed out after ${BUN_INSTALL_TIMEOUT_SECONDS} seconds. Try running manually: cd ~/.config/opencode && bun i`
4585
+ };
4586
+ }
4587
+ if (proc.exitCode !== 0) {
4588
+ const stderr = await new Response(proc.stderr).text();
4589
+ return {
4590
+ success: false,
4591
+ error: stderr.trim() || `bun install failed with exit code ${proc.exitCode}`
4592
+ };
4593
+ }
4594
+ return { success: true };
4595
+ } catch (err) {
4596
+ const message = err instanceof Error ? err.message : String(err);
4597
+ return {
4598
+ success: false,
4599
+ error: `bun install failed: ${message}. Is bun installed? Try: curl -fsSL https://bun.sh/install | bash`
4600
+ };
4469
4601
  }
4470
4602
  }
4471
4603
  var ANTIGRAVITY_PROVIDER_CONFIG = {
@@ -4521,10 +4653,22 @@ var CODEX_PROVIDER_CONFIG = {
4521
4653
  }
4522
4654
  };
4523
4655
  function addProviderConfig(config) {
4524
- ensureConfigDir();
4656
+ try {
4657
+ ensureConfigDir();
4658
+ } catch (err) {
4659
+ return { success: false, configPath: OPENCODE_CONFIG_DIR, error: formatErrorWithSuggestion(err, "create config directory") };
4660
+ }
4525
4661
  const { format: format2, path: path2 } = detectConfigFormat();
4526
4662
  try {
4527
- const existingConfig = format2 !== "none" ? parseConfig(path2, format2 === "jsonc") : null;
4663
+ let existingConfig = null;
4664
+ if (format2 !== "none") {
4665
+ const parseResult = parseConfigWithError(path2);
4666
+ if (parseResult.error && !parseResult.config) {
4667
+ existingConfig = {};
4668
+ } else {
4669
+ existingConfig = parseResult.config;
4670
+ }
4671
+ }
4528
4672
  const newConfig = { ...existingConfig ?? {} };
4529
4673
  const providers = newConfig.provider ?? {};
4530
4674
  if (config.hasGemini) {
@@ -4540,7 +4684,7 @@ function addProviderConfig(config) {
4540
4684
  `);
4541
4685
  return { success: true, configPath: path2 };
4542
4686
  } catch (err) {
4543
- return { success: false, configPath: path2, error: String(err) };
4687
+ return { success: false, configPath: path2, error: formatErrorWithSuggestion(err, "add provider config") };
4544
4688
  }
4545
4689
  }
4546
4690
  function detectCurrentConfig() {
@@ -4555,10 +4699,11 @@ function detectCurrentConfig() {
4555
4699
  if (format2 === "none") {
4556
4700
  return result;
4557
4701
  }
4558
- const openCodeConfig = parseConfig(path2, format2 === "jsonc");
4559
- if (!openCodeConfig) {
4702
+ const parseResult = parseConfigWithError(path2);
4703
+ if (!parseResult.config) {
4560
4704
  return result;
4561
4705
  }
4706
+ const openCodeConfig = parseResult.config;
4562
4707
  const plugins = openCodeConfig.plugin ?? [];
4563
4708
  result.isInstalled = plugins.some((p2) => p2.startsWith("oh-my-opencode"));
4564
4709
  if (!result.isInstalled) {
@@ -4570,8 +4715,18 @@ function detectCurrentConfig() {
4570
4715
  return result;
4571
4716
  }
4572
4717
  try {
4718
+ const stat = statSync(OMO_CONFIG);
4719
+ if (stat.size === 0) {
4720
+ return result;
4721
+ }
4573
4722
  const content = readFileSync2(OMO_CONFIG, "utf-8");
4723
+ if (isEmptyOrWhitespace(content)) {
4724
+ return result;
4725
+ }
4574
4726
  const omoConfig = parseJsonc(content);
4727
+ if (!omoConfig || typeof omoConfig !== "object") {
4728
+ return result;
4729
+ }
4575
4730
  const agents = omoConfig.agents ?? {};
4576
4731
  if (agents["Sisyphus"]?.model === "opencode/big-pickle") {
4577
4732
  result.hasClaude = false;
@@ -19720,8 +19875,7 @@ var HookNameSchema = exports_external.enum([
19720
19875
  "interactive-bash-session",
19721
19876
  "empty-message-sanitizer",
19722
19877
  "thinking-block-validator",
19723
- "ralph-loop",
19724
- "dcp-for-compaction"
19878
+ "ralph-loop"
19725
19879
  ]);
19726
19880
  var BuiltinCommandNameSchema = exports_external.enum([
19727
19881
  "init-deep"
@@ -19806,8 +19960,9 @@ var ExperimentalConfigSchema = exports_external.object({
19806
19960
  auto_resume: exports_external.boolean().optional(),
19807
19961
  preemptive_compaction: exports_external.boolean().optional(),
19808
19962
  preemptive_compaction_threshold: exports_external.number().min(0.5).max(0.95).optional(),
19809
- truncate_all_tool_outputs: exports_external.boolean().default(true),
19810
- dynamic_context_pruning: DynamicContextPruningConfigSchema.optional()
19963
+ truncate_all_tool_outputs: exports_external.boolean().optional(),
19964
+ dynamic_context_pruning: DynamicContextPruningConfigSchema.optional(),
19965
+ dcp_for_compaction: exports_external.boolean().optional()
19811
19966
  });
19812
19967
  var SkillSourceSchema = exports_external.union([
19813
19968
  exports_external.string(),
@@ -54,7 +54,6 @@ export declare const HookNameSchema: z.ZodEnum<{
54
54
  "empty-message-sanitizer": "empty-message-sanitizer";
55
55
  "thinking-block-validator": "thinking-block-validator";
56
56
  "ralph-loop": "ralph-loop";
57
- "dcp-for-compaction": "dcp-for-compaction";
58
57
  }>;
59
58
  export declare const BuiltinCommandNameSchema: z.ZodEnum<{
60
59
  "init-deep": "init-deep";
@@ -674,7 +673,7 @@ export declare const ExperimentalConfigSchema: z.ZodObject<{
674
673
  auto_resume: z.ZodOptional<z.ZodBoolean>;
675
674
  preemptive_compaction: z.ZodOptional<z.ZodBoolean>;
676
675
  preemptive_compaction_threshold: z.ZodOptional<z.ZodNumber>;
677
- truncate_all_tool_outputs: z.ZodDefault<z.ZodBoolean>;
676
+ truncate_all_tool_outputs: z.ZodOptional<z.ZodBoolean>;
678
677
  dynamic_context_pruning: z.ZodOptional<z.ZodObject<{
679
678
  enabled: z.ZodDefault<z.ZodBoolean>;
680
679
  notification: z.ZodDefault<z.ZodEnum<{
@@ -701,6 +700,7 @@ export declare const ExperimentalConfigSchema: z.ZodObject<{
701
700
  }, z.core.$strip>>;
702
701
  }, z.core.$strip>>;
703
702
  }, z.core.$strip>>;
703
+ dcp_for_compaction: z.ZodOptional<z.ZodBoolean>;
704
704
  }, z.core.$strip>;
705
705
  export declare const SkillSourceSchema: z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
706
706
  path: z.ZodString;
@@ -802,7 +802,6 @@ export declare const OhMyOpenCodeConfigSchema: z.ZodObject<{
802
802
  "empty-message-sanitizer": "empty-message-sanitizer";
803
803
  "thinking-block-validator": "thinking-block-validator";
804
804
  "ralph-loop": "ralph-loop";
805
- "dcp-for-compaction": "dcp-for-compaction";
806
805
  }>>>;
807
806
  disabled_commands: z.ZodOptional<z.ZodArray<z.ZodEnum<{
808
807
  "init-deep": "init-deep";
@@ -1350,7 +1349,7 @@ export declare const OhMyOpenCodeConfigSchema: z.ZodObject<{
1350
1349
  auto_resume: z.ZodOptional<z.ZodBoolean>;
1351
1350
  preemptive_compaction: z.ZodOptional<z.ZodBoolean>;
1352
1351
  preemptive_compaction_threshold: z.ZodOptional<z.ZodNumber>;
1353
- truncate_all_tool_outputs: z.ZodDefault<z.ZodBoolean>;
1352
+ truncate_all_tool_outputs: z.ZodOptional<z.ZodBoolean>;
1354
1353
  dynamic_context_pruning: z.ZodOptional<z.ZodObject<{
1355
1354
  enabled: z.ZodDefault<z.ZodBoolean>;
1356
1355
  notification: z.ZodDefault<z.ZodEnum<{
@@ -1377,6 +1376,7 @@ export declare const OhMyOpenCodeConfigSchema: z.ZodObject<{
1377
1376
  }, z.core.$strip>>;
1378
1377
  }, z.core.$strip>>;
1379
1378
  }, z.core.$strip>>;
1379
+ dcp_for_compaction: z.ZodOptional<z.ZodBoolean>;
1380
1380
  }, z.core.$strip>>;
1381
1381
  auto_update: z.ZodOptional<z.ZodBoolean>;
1382
1382
  skills: z.ZodOptional<z.ZodUnion<readonly [z.ZodArray<z.ZodString>, z.ZodIntersection<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodBoolean, z.ZodObject<{
@@ -1,6 +1,7 @@
1
1
  /**
2
2
  * Get the cache directory for oh-my-opencode binaries.
3
- * Follows XDG Base Directory Specification.
3
+ * On Windows: Uses %LOCALAPPDATA% or %APPDATA% (Windows conventions)
4
+ * On Unix: Follows XDG Base Directory Specification
4
5
  */
5
6
  export declare function getCacheDir(): string;
6
7
  /**
package/dist/index.js CHANGED
@@ -5659,6 +5659,11 @@ var PLATFORM_MAP = {
5659
5659
  "win32-x64": { os: "windows", arch: "amd64", ext: "zip" }
5660
5660
  };
5661
5661
  function getCacheDir() {
5662
+ if (process.platform === "win32") {
5663
+ const localAppData = process.env.LOCALAPPDATA || process.env.APPDATA;
5664
+ const base2 = localAppData || join11(homedir5(), "AppData", "Local");
5665
+ return join11(base2, "oh-my-opencode", "bin");
5666
+ }
5662
5667
  const xdgCache = process.env.XDG_CACHE_HOME;
5663
5668
  const base = xdgCache || join11(homedir5(), ".cache");
5664
5669
  return join11(base, "oh-my-opencode", "bin");
@@ -5783,6 +5788,15 @@ function getBinaryName2() {
5783
5788
  }
5784
5789
  function findCommentCheckerPathSync() {
5785
5790
  const binaryName = getBinaryName2();
5791
+ const cachedPath = getCachedBinaryPath();
5792
+ if (cachedPath) {
5793
+ debugLog2("found binary in cache:", cachedPath);
5794
+ return cachedPath;
5795
+ }
5796
+ if (!import.meta.url) {
5797
+ debugLog2("import.meta.url is undefined, skipping package resolution");
5798
+ return null;
5799
+ }
5786
5800
  try {
5787
5801
  const require2 = createRequire2(import.meta.url);
5788
5802
  const cliPkgPath = require2.resolve("@code-yeongyu/comment-checker/package.json");
@@ -5792,13 +5806,8 @@ function findCommentCheckerPathSync() {
5792
5806
  debugLog2("found binary in main package:", binaryPath);
5793
5807
  return binaryPath;
5794
5808
  }
5795
- } catch {
5796
- debugLog2("main package not installed");
5797
- }
5798
- const cachedPath = getCachedBinaryPath();
5799
- if (cachedPath) {
5800
- debugLog2("found binary in cache:", cachedPath);
5801
- return cachedPath;
5809
+ } catch (err) {
5810
+ debugLog2("main package not installed or resolution failed:", err);
5802
5811
  }
5803
5812
  debugLog2("no binary found in known locations");
5804
5813
  return null;
@@ -6026,7 +6035,7 @@ var TRUNCATABLE_TOOLS = [
6026
6035
  ];
6027
6036
  function createToolOutputTruncatorHook(ctx, options) {
6028
6037
  const truncator = createDynamicTruncator(ctx);
6029
- const truncateAll = options?.experimental?.truncate_all_tool_outputs ?? true;
6038
+ const truncateAll = options?.experimental?.truncate_all_tool_outputs ?? false;
6030
6039
  const toolExecuteAfter = async (input, output) => {
6031
6040
  if (!truncateAll && !TRUNCATABLE_TOOLS.includes(input.tool))
6032
6041
  return;
@@ -7958,7 +7967,7 @@ function createPreemptiveCompactionHook(ctx, options) {
7958
7967
  const experimental = options?.experimental;
7959
7968
  const onBeforeSummarize = options?.onBeforeSummarize;
7960
7969
  const getModelLimit = options?.getModelLimit;
7961
- const enabled = experimental?.preemptive_compaction !== false;
7970
+ const enabled = experimental?.preemptive_compaction === true;
7962
7971
  const threshold = experimental?.preemptive_compaction_threshold ?? DEFAULT_THRESHOLD;
7963
7972
  if (!enabled) {
7964
7973
  return { event: async () => {} };
@@ -31934,8 +31943,7 @@ var HookNameSchema = exports_external.enum([
31934
31943
  "interactive-bash-session",
31935
31944
  "empty-message-sanitizer",
31936
31945
  "thinking-block-validator",
31937
- "ralph-loop",
31938
- "dcp-for-compaction"
31946
+ "ralph-loop"
31939
31947
  ]);
31940
31948
  var BuiltinCommandNameSchema = exports_external.enum([
31941
31949
  "init-deep"
@@ -32020,8 +32028,9 @@ var ExperimentalConfigSchema = exports_external.object({
32020
32028
  auto_resume: exports_external.boolean().optional(),
32021
32029
  preemptive_compaction: exports_external.boolean().optional(),
32022
32030
  preemptive_compaction_threshold: exports_external.number().min(0.5).max(0.95).optional(),
32023
- truncate_all_tool_outputs: exports_external.boolean().default(true),
32024
- dynamic_context_pruning: DynamicContextPruningConfigSchema.optional()
32031
+ truncate_all_tool_outputs: exports_external.boolean().optional(),
32032
+ dynamic_context_pruning: DynamicContextPruningConfigSchema.optional(),
32033
+ dcp_for_compaction: exports_external.boolean().optional()
32025
32034
  });
32026
32035
  var SkillSourceSchema = exports_external.union([
32027
32036
  exports_external.string(),
@@ -32310,7 +32319,7 @@ var OhMyOpenCodePlugin = async (ctx) => {
32310
32319
  });
32311
32320
  const anthropicContextWindowLimitRecovery = isHookEnabled("anthropic-context-window-limit-recovery") ? createAnthropicContextWindowLimitRecoveryHook(ctx, {
32312
32321
  experimental: pluginConfig.experimental,
32313
- dcpForCompaction: isHookEnabled("dcp-for-compaction")
32322
+ dcpForCompaction: pluginConfig.experimental?.dcp_for_compaction
32314
32323
  }) : null;
32315
32324
  const compactionContextInjector = createCompactionContextInjector();
32316
32325
  const preemptiveCompaction = createPreemptiveCompactionHook(ctx, {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "oh-my-opencode",
3
- "version": "2.8.0",
3
+ "version": "2.8.2",
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",
@@ -23,7 +23,7 @@
23
23
  "./schema.json": "./dist/oh-my-opencode.schema.json"
24
24
  },
25
25
  "scripts": {
26
- "build": "bun build src/index.ts src/google-auth.ts --outdir dist --target bun --format esm --external @ast-grep/napi && tsc --emitDeclarationOnly && bun build src/cli/index.ts --outdir dist/cli --target bun --format esm && bun run build:schema",
26
+ "build": "bun build src/index.ts src/google-auth.ts --outdir dist --target bun --format esm --external @ast-grep/napi && tsc --emitDeclarationOnly && bun build src/cli/index.ts --outdir dist/cli --target bun --format esm --external @ast-grep/napi && bun run build:schema",
27
27
  "build:schema": "bun run script/build-schema.ts",
28
28
  "clean": "rm -rf dist",
29
29
  "prepublishOnly": "bun run clean && bun run build",