oh-my-opencode 2.5.3 → 2.5.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.ja.md CHANGED
@@ -56,6 +56,8 @@
56
56
 
57
57
  > "Oh My Opencodeは頂点に立っています、敵はいません" — [RyanOnThePath](https://x.com/RyanOnThePath/status/2001438321252118548)
58
58
 
59
+ > "シジフォスという名前自体が美しいじゃないですか?" — Sigrid ([@sigridjin_eth](https://x.com/sigridjin_eth))
60
+
59
61
  ---
60
62
 
61
63
  ## 目次
@@ -717,8 +719,8 @@ Oh My OpenCode は以下の場所からフックを読み込んで実行しま
717
719
  有効時(デフォルト)、Sisyphus はオプションの特殊エージェントを備えた強力なオーケストレーターを提供します:
718
720
 
719
721
  - **Sisyphus**: プライマリオーケストレーターエージェント (Claude Opus 4.5)
720
- - **Builder-Sisyphus**: OhMyOpenCode 強化版のビルドエージェント(デフォルトで無効)
721
- - **Planner-Sisyphus**: OhMyOpenCode 強化版のプランエージェント(デフォルトで有効)
722
+ - **Builder-Sisyphus**: OpenCode のデフォルトビルドエージェント(SDK 制限により名前変更、デフォルトで無効)
723
+ - **Planner-Sisyphus**: OpenCode のデフォルトプランエージェント(SDK 制限により名前変更、デフォルトで有効)
722
724
 
723
725
  **設定オプション:**
724
726
 
@@ -726,26 +728,24 @@ Oh My OpenCode は以下の場所からフックを読み込んで実行しま
726
728
  {
727
729
  "sisyphus_agent": {
728
730
  "disabled": false,
729
- "builder_enabled": false,
731
+ "default_builder_enabled": false,
730
732
  "planner_enabled": true,
731
- "replace_build": true,
732
733
  "replace_plan": true
733
734
  }
734
735
  }
735
736
  ```
736
737
 
737
- **例:Builder-Sisyphus を有効化し、デフォルトのビルドモードも維持する:**
738
+ **例:Builder-Sisyphus を有効化:**
738
739
 
739
740
  ```json
740
741
  {
741
742
  "sisyphus_agent": {
742
- "builder_enabled": true,
743
- "replace_build": false
743
+ "default_builder_enabled": true
744
744
  }
745
745
  }
746
746
  ```
747
747
 
748
- これにより、Builder-Sisyphus とデフォルトのビルドエージェントの両方を同時に利用できます。
748
+ これにより、Sisyphus と並行して Builder-Sisyphus エージェントを有効化できます。Sisyphus が有効な場合、デフォルトのビルドエージェントは常にサブエージェントモードに降格されます。
749
749
 
750
750
  **例:すべての Sisyphus オーケストレーションを無効化:**
751
751
 
@@ -776,13 +776,12 @@ Oh My OpenCode は以下の場所からフックを読み込んで実行しま
776
776
  }
777
777
  ```
778
778
 
779
- | オプション | デフォルト | 説明 |
780
- | ------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ |
781
- | `disabled` | `false` | `true` の場合、すべての Sisyphus オーケストレーションを無効化し、元の build/plan をプライマリとして復元します。 |
782
- | `builder_enabled` | `false` | `true` の場合、Builder-Sisyphus エージェント(OhMyOpenCode 強化版ビルドモード)を有効化します。デフォルトの OpenCode ビルド体験を維持するため、デフォルトでは無効です。 |
783
- | `planner_enabled` | `true` | `true` の場合、Planner-Sisyphus エージェント(OhMyOpenCode 強化版プランモード)を有効化します。デフォルトで有効です。 |
784
- | `replace_build` | `true` | `true` の場合、デフォルトのビルドエージェントをサブエージェントモードに降格させます。`false` に設定すると、Builder-Sisyphus とデフォルトのビルドの両方を利用できます。 |
785
- | `replace_plan` | `true` | `true` の場合、デフォルトのプランエージェントをサブエージェントモードに降格させます。`false` に設定すると、Planner-Sisyphus とデフォルトのプランの両方を利用できます。 |
779
+ | オプション | デフォルト | 説明 |
780
+ | --------------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ |
781
+ | `disabled` | `false` | `true` の場合、すべての Sisyphus オーケストレーションを無効化し、元の build/plan をプライマリとして復元します。 |
782
+ | `default_builder_enabled` | `false` | `true` の場合、Builder-Sisyphus エージェントを有効化します(OpenCode build と同じ、SDK 制限により名前変更)。デフォルトでは無効です。 |
783
+ | `planner_enabled` | `true` | `true` の場合、Planner-Sisyphus エージェントを有効化します(OpenCode plan と同じ、SDK 制限により名前変更)。デフォルトで有効です。 |
784
+ | `replace_plan` | `true` | `true` の場合、デフォルトのプランエージェントをサブエージェントモードに降格させます。`false` に設定すると、Planner-Sisyphus とデフォルトのプランの両方を利用できます。 |
786
785
 
787
786
  ### Hooks
788
787
 
package/README.ko.md CHANGED
@@ -53,6 +53,8 @@
53
53
 
54
54
  > "Oh My Opencode는 독보적입니다, 경쟁자가 없습니다" — [RyanOnThePath](https://x.com/RyanOnThePath/status/2001438321252118548)
55
55
 
56
+ > "시지푸스 이름 자체가 이쁘잖아요?" — Sigrid ([@sigridjin_eth](https://x.com/sigridjin_eth))
57
+
56
58
  ---
57
59
 
58
60
  ## 목차
@@ -711,8 +713,8 @@ Schema 자동 완성이 지원됩니다:
711
713
  활성화 시 (기본값), Sisyphus는 옵션으로 선택 가능한 특화 에이전트들과 함께 강력한 오케스트레이터를 제공합니다:
712
714
 
713
715
  - **Sisyphus**: Primary 오케스트레이터 에이전트 (Claude Opus 4.5)
714
- - **Builder-Sisyphus**: OhMyOpenCode 강화 버전 빌드 에이전트 (기본적으로 비활성화)
715
- - **Planner-Sisyphus**: OhMyOpenCode 강화 버전 플랜 에이전트 (기본적으로 활성화)
716
+ - **Builder-Sisyphus**: OpenCode 기본 빌드 에이전트 (SDK 제한으로 이름만 변경, 기본적으로 비활성화)
717
+ - **Planner-Sisyphus**: OpenCode 기본 플랜 에이전트 (SDK 제한으로 이름만 변경, 기본적으로 활성화)
716
718
 
717
719
  **설정 옵션:**
718
720
 
@@ -720,26 +722,24 @@ Schema 자동 완성이 지원됩니다:
720
722
  {
721
723
  "sisyphus_agent": {
722
724
  "disabled": false,
723
- "builder_enabled": false,
725
+ "default_builder_enabled": false,
724
726
  "planner_enabled": true,
725
- "replace_build": true,
726
727
  "replace_plan": true
727
728
  }
728
729
  }
729
730
  ```
730
731
 
731
- **예시: Builder-Sisyphus 활성화하면서 기본 빌드 모드도 유지하기:**
732
+ **예시: Builder-Sisyphus 활성화하기:**
732
733
 
733
734
  ```json
734
735
  {
735
736
  "sisyphus_agent": {
736
- "builder_enabled": true,
737
- "replace_build": false
737
+ "default_builder_enabled": true
738
738
  }
739
739
  }
740
740
  ```
741
741
 
742
- 이렇게 하면 Builder-Sisyphus 기본 빌드 에이전트를 동시에 사용할 있습니다.
742
+ 이렇게 하면 Sisyphus와 함께 Builder-Sisyphus 에이전트를 활성화할 수 있습니다. Sisyphus가 활성화되면 기본 빌드 에이전트는 항상 subagent 모드로 강등됩니다.
743
743
 
744
744
  **예시: 모든 Sisyphus 오케스트레이션 비활성화:**
745
745
 
@@ -770,13 +770,12 @@ Schema 자동 완성이 지원됩니다:
770
770
  }
771
771
  ```
772
772
 
773
- | 옵션 | 기본값 | 설명 |
774
- | ------------------- | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- |
775
- | `disabled` | `false` | `true`면 모든 Sisyphus 오케스트레이션을 비활성화하고 원래 build/plan을 primary로 복원합니다. |
776
- | `builder_enabled` | `false` | `true`면 Builder-Sisyphus 에이전트 (OhMyOpenCode 강화 빌드 모드)를 활성화합니다. 기본 OpenCode 빌드 경험을 보존하기 위해 기본적으로 비활성화되어 있습니다. |
777
- | `planner_enabled` | `true` | `true`면 Planner-Sisyphus 에이전트 (OhMyOpenCode 강화 플랜 모드) 활성화합니다. 기본적으로 활성화되어 있습니다. |
778
- | `replace_build` | `true` | `true`면 기본 빌드 에이전트를 subagent 모드로 강등시킵니다. `false`로 설정하면 Builder-Sisyphus와 기본 빌드를 모두 사용할 수 있습니다. |
779
- | `replace_plan` | `true` | `true`면 기본 플랜 에이전트를 subagent 모드로 강등시킵니다. `false`로 설정하면 Planner-Sisyphus와 기본 플랜을 모두 사용할 수 있습니다. |
773
+ | 옵션 | 기본값 | 설명 |
774
+ | --------------------------- | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- |
775
+ | `disabled` | `false` | `true`면 모든 Sisyphus 오케스트레이션을 비활성화하고 원래 build/plan을 primary로 복원합니다. |
776
+ | `default_builder_enabled` | `false` | `true`면 Builder-Sisyphus 에이전트를 활성화합니다 (OpenCode build와 동일, SDK 제한으로 이름만 변경). 기본적으로 비활성화되어 있습니다. |
777
+ | `planner_enabled` | `true` | `true`면 Planner-Sisyphus 에이전트를 활성화합니다 (OpenCode plan과 동일, SDK 제한으로 이름만 변경). 기본적으로 활성화되어 있습니다. |
778
+ | `replace_plan` | `true` | `true`면 기본 플랜 에이전트를 subagent 모드로 강등시킵니다. `false`로 설정하면 Planner-Sisyphus와 기본 플랜을 모두 사용할 수 있습니다. |
780
779
 
781
780
  ### Hooks
782
781
 
package/README.md CHANGED
@@ -61,6 +61,8 @@ No stupid token consumption massive subagents here. No bloat tools here.
61
61
 
62
62
  > "Oh My Opencode is king of the hill and has no contenders" — [RyanOnThePath](https://x.com/RyanOnThePath/status/2001438321252118548)
63
63
 
64
+ > "Isn't the name Sisyphus itself beautiful?" — Sigrid ([@sigridjin_eth](https://x.com/sigridjin_eth))
65
+
64
66
  ---
65
67
 
66
68
  ## Contents
@@ -783,8 +785,8 @@ Available agents: `oracle`, `librarian`, `explore`, `frontend-ui-ux-engineer`, `
783
785
  When enabled (default), Sisyphus provides a powerful orchestrator with optional specialized agents:
784
786
 
785
787
  - **Sisyphus**: Primary orchestrator agent (Claude Opus 4.5)
786
- - **Builder-Sisyphus**: Optional build agent with OhMyOpenCode enhancements (disabled by default)
787
- - **Planner-Sisyphus**: Plan agent with OhMyOpenCode enhancements (enabled by default)
788
+ - **Builder-Sisyphus**: OpenCode's default build agent, renamed due to SDK limitations (disabled by default)
789
+ - **Planner-Sisyphus**: OpenCode's default plan agent, renamed due to SDK limitations (enabled by default)
788
790
 
789
791
  **Configuration Options:**
790
792
 
@@ -792,26 +794,24 @@ When enabled (default), Sisyphus provides a powerful orchestrator with optional
792
794
  {
793
795
  "sisyphus_agent": {
794
796
  "disabled": false,
795
- "builder_enabled": false,
797
+ "default_builder_enabled": false,
796
798
  "planner_enabled": true,
797
- "replace_build": true,
798
799
  "replace_plan": true
799
800
  }
800
801
  }
801
802
  ```
802
803
 
803
- **Example: Enable Builder-Sisyphus and keep default build mode:**
804
+ **Example: Enable Builder-Sisyphus:**
804
805
 
805
806
  ```json
806
807
  {
807
808
  "sisyphus_agent": {
808
- "builder_enabled": true,
809
- "replace_build": false
809
+ "default_builder_enabled": true
810
810
  }
811
811
  }
812
812
  ```
813
813
 
814
- This allows you to have both Builder-Sisyphus AND the default build agent available simultaneously.
814
+ This enables Builder-Sisyphus agent alongside Sisyphus. The default build agent is always demoted to subagent mode when Sisyphus is enabled.
815
815
 
816
816
  **Example: Disable all Sisyphus orchestration:**
817
817
 
@@ -842,13 +842,12 @@ You can also customize Sisyphus agents like other agents:
842
842
  }
843
843
  ```
844
844
 
845
- | Option | Default | Description |
846
- | ------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------- |
847
- | `disabled` | `false` | When `true`, disables all Sisyphus orchestration and restores original build/plan as primary. |
848
- | `builder_enabled` | `false` | When `true`, enables Builder-Sisyphus agent (OhMyOpenCode enhanced build mode). Disabled by default to preserve default OpenCode build experience. |
849
- | `planner_enabled` | `true` | When `true`, enables Planner-Sisyphus agent (OhMyOpenCode enhanced plan mode). Enabled by default. |
850
- | `replace_build` | `true` | When `true`, demotes default build agent to subagent mode. Set to `false` to keep both Builder-Sisyphus and default build available. |
851
- | `replace_plan` | `true` | When `true`, demotes default plan agent to subagent mode. Set to `false` to keep both Planner-Sisyphus and default plan available. |
845
+ | Option | Default | Description |
846
+ | --------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------- |
847
+ | `disabled` | `false` | When `true`, disables all Sisyphus orchestration and restores original build/plan as primary. |
848
+ | `default_builder_enabled` | `false` | When `true`, enables Builder-Sisyphus agent (same as OpenCode build, renamed due to SDK limitations). Disabled by default. |
849
+ | `planner_enabled` | `true` | When `true`, enables Planner-Sisyphus agent (same as OpenCode plan, renamed due to SDK limitations). Enabled by default. |
850
+ | `replace_plan` | `true` | When `true`, demotes default plan agent to subagent mode. Set to `false` to keep both Planner-Sisyphus and default plan available. |
852
851
 
853
852
  ### Hooks
854
853
 
package/README.zh-cn.md CHANGED
@@ -58,6 +58,8 @@
58
58
 
59
59
  > "Oh My Opencode 独孤求败,没有对手" — [RyanOnThePath](https://x.com/RyanOnThePath/status/2001438321252118548)
60
60
 
61
+ > "西西弗斯这个名字本身不就很美吗?" — Sigrid ([@sigridjin_eth](https://x.com/sigridjin_eth))
62
+
61
63
  ---
62
64
 
63
65
  ## 目录
@@ -717,8 +719,8 @@ Agent 爽了,你自然也爽。但我还想直接让你爽。
717
719
  默认开启。Sisyphus 提供一个强力的编排器,带可选的专门 Agent:
718
720
 
719
721
  - **Sisyphus**:主编排 Agent(Claude Opus 4.5)
720
- - **Builder-Sisyphus**:OhMyOpenCode 增强版构建 Agent(默认禁用)
721
- - **Planner-Sisyphus**:OhMyOpenCode 增强版计划 Agent(默认启用)
722
+ - **Builder-Sisyphus**:OpenCode 默认构建 Agent(因 SDK 限制仅改名,默认禁用)
723
+ - **Planner-Sisyphus**:OpenCode 默认计划 Agent(因 SDK 限制仅改名,默认启用)
722
724
 
723
725
  **配置选项:**
724
726
 
@@ -726,26 +728,24 @@ Agent 爽了,你自然也爽。但我还想直接让你爽。
726
728
  {
727
729
  "sisyphus_agent": {
728
730
  "disabled": false,
729
- "builder_enabled": false,
731
+ "default_builder_enabled": false,
730
732
  "planner_enabled": true,
731
- "replace_build": true,
732
733
  "replace_plan": true
733
734
  }
734
735
  }
735
736
  ```
736
737
 
737
- **示例:启用 Builder-Sisyphus,同时保留默认构建模式:**
738
+ **示例:启用 Builder-Sisyphus:**
738
739
 
739
740
  ```json
740
741
  {
741
742
  "sisyphus_agent": {
742
- "builder_enabled": true,
743
- "replace_build": false
743
+ "default_builder_enabled": true
744
744
  }
745
745
  }
746
746
  ```
747
747
 
748
- 这样你就能同时使用 Builder-Sisyphus 和默认构建 Agent
748
+ 这样能和 Sisyphus 一起启用 Builder-Sisyphus Agent。启用 Sisyphus 后,默认构建 Agent 总会降级为子 Agent 模式。
749
749
 
750
750
  **示例:禁用所有 Sisyphus 编排:**
751
751
 
@@ -776,13 +776,12 @@ Sisyphus Agent 也能自定义:
776
776
  }
777
777
  ```
778
778
 
779
- | 选项 | 默认值 | 说明 |
780
- | ------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |
781
- | `disabled` | `false` | 设为 `true` 就禁用所有 Sisyphus 编排,恢复原来的 build/plan。 |
782
- | `builder_enabled` | `false` | 设为 `true` 就启用 Builder-Sisyphus Agent(OhMyOpenCode 增强构建模式)。为了保留默认 OpenCode 构建体验,默认禁用。 |
783
- | `planner_enabled` | `true` | 设为 `true` 就启用 Planner-Sisyphus Agent(OhMyOpenCode 增强计划模式)。默认启用。 |
784
- | `replace_build` | `true` | 设为 `true` 就把默认构建 Agent 降级为子 Agent 模式。设为 `false` 可以同时保留 Builder-Sisyphus 和默认构建。 |
785
- | `replace_plan` | `true` | 设为 `true` 就把默认计划 Agent 降级为子 Agent 模式。设为 `false` 可以同时保留 Planner-Sisyphus 和默认计划。 |
779
+ | 选项 | 默认值 | 说明 |
780
+ | --------------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |
781
+ | `disabled` | `false` | 设为 `true` 就禁用所有 Sisyphus 编排,恢复原来的 build/plan。 |
782
+ | `default_builder_enabled` | `false` | 设为 `true` 就启用 Builder-Sisyphus Agent(与 OpenCode build 相同,因 SDK 限制仅改名)。默认禁用。 |
783
+ | `planner_enabled` | `true` | 设为 `true` 就启用 Planner-Sisyphus Agent(与 OpenCode plan 相同,因 SDK 限制仅改名)。默认启用。 |
784
+ | `replace_plan` | `true` | 设为 `true` 就把默认计划 Agent 降级为子 Agent 模式。设为 `false` 可以同时保留 Planner-Sisyphus 和默认计划。 |
786
785
 
787
786
  ### Hooks
788
787
 
package/dist/cli/index.js CHANGED
@@ -2244,7 +2244,7 @@ var require_picocolors = __commonJS((exports, module) => {
2244
2244
  var require_package = __commonJS((exports, module) => {
2245
2245
  module.exports = {
2246
2246
  name: "oh-my-opencode",
2247
- version: "2.5.2",
2247
+ version: "2.5.3",
2248
2248
  description: "OpenCode plugin - custom agents (oracle, librarian) and enhanced features",
2249
2249
  main: "dist/index.js",
2250
2250
  types: "dist/index.d.ts",
@@ -5152,7 +5152,7 @@ async function createOpencode(options) {
5152
5152
  }
5153
5153
 
5154
5154
  // src/cli/run/runner.ts
5155
- var import_picocolors4 = __toESM(require_picocolors(), 1);
5155
+ var import_picocolors5 = __toESM(require_picocolors(), 1);
5156
5156
 
5157
5157
  // src/cli/run/completion.ts
5158
5158
  var import_picocolors3 = __toESM(require_picocolors(), 1);
@@ -5165,7 +5165,8 @@ async function checkCompletionConditions(ctx) {
5165
5165
  return false;
5166
5166
  }
5167
5167
  return true;
5168
- } catch {
5168
+ } catch (err) {
5169
+ console.error(import_picocolors3.default.red(`[completion] API error: ${err}`));
5169
5170
  return false;
5170
5171
  }
5171
5172
  }
@@ -5207,10 +5208,15 @@ async function areAllDescendantsIdle(ctx, sessionID, allStatuses) {
5207
5208
  }
5208
5209
 
5209
5210
  // src/cli/run/events.ts
5211
+ var import_picocolors4 = __toESM(require_picocolors(), 1);
5210
5212
  function createEventState() {
5211
5213
  return {
5212
5214
  mainSessionIdle: false,
5213
- lastOutput: ""
5215
+ mainSessionError: false,
5216
+ lastError: null,
5217
+ lastOutput: "",
5218
+ lastPartText: "",
5219
+ currentTool: null
5214
5220
  };
5215
5221
  }
5216
5222
  async function processEvents(ctx, stream, state) {
@@ -5218,13 +5224,76 @@ async function processEvents(ctx, stream, state) {
5218
5224
  if (ctx.abortController.signal.aborted)
5219
5225
  break;
5220
5226
  try {
5221
- const payload = event.payload;
5222
- if (!payload)
5227
+ const payload = event;
5228
+ if (!payload?.type) {
5229
+ console.error(import_picocolors4.default.dim(`[event] no type: ${JSON.stringify(event)}`));
5223
5230
  continue;
5231
+ }
5232
+ logEventVerbose(ctx, payload);
5233
+ handleSessionError(ctx, payload, state);
5224
5234
  handleSessionIdle(ctx, payload, state);
5225
5235
  handleSessionStatus(ctx, payload, state);
5236
+ handleMessagePartUpdated(ctx, payload, state);
5226
5237
  handleMessageUpdated(ctx, payload, state);
5227
- } catch {}
5238
+ handleToolExecute(ctx, payload, state);
5239
+ handleToolResult(ctx, payload, state);
5240
+ } catch (err) {
5241
+ console.error(import_picocolors4.default.red(`[event error] ${err}`));
5242
+ }
5243
+ }
5244
+ }
5245
+ function logEventVerbose(ctx, payload) {
5246
+ const props = payload.properties;
5247
+ const info = props?.info;
5248
+ const sessionID = props?.sessionID ?? info?.sessionID;
5249
+ const isMainSession = sessionID === ctx.sessionID;
5250
+ const sessionTag = isMainSession ? import_picocolors4.default.green("[MAIN]") : import_picocolors4.default.yellow(`[${String(sessionID).slice(0, 8)}]`);
5251
+ switch (payload.type) {
5252
+ case "session.idle":
5253
+ case "session.status": {
5254
+ const status = props?.status?.type ?? "idle";
5255
+ console.error(import_picocolors4.default.dim(`${sessionTag} ${payload.type}: ${status}`));
5256
+ break;
5257
+ }
5258
+ case "message.part.updated": {
5259
+ const partProps = props;
5260
+ const role = partProps?.info?.role ?? "unknown";
5261
+ const part = partProps?.part;
5262
+ if (part?.type === "text" && part.text) {
5263
+ const preview = part.text.slice(0, 100).replace(/\n/g, "\\n");
5264
+ console.error(import_picocolors4.default.dim(`${sessionTag} message.part (${role}): "${preview}${part.text.length > 100 ? "..." : ""}"`));
5265
+ } else if (part?.type === "tool-invocation") {
5266
+ const toolPart = part;
5267
+ console.error(import_picocolors4.default.dim(`${sessionTag} message.part (tool): ${toolPart.toolName} [${toolPart.state}]`));
5268
+ }
5269
+ break;
5270
+ }
5271
+ case "message.updated": {
5272
+ const msgProps = props;
5273
+ const role = msgProps?.info?.role ?? "unknown";
5274
+ const content = msgProps?.content ?? "";
5275
+ const preview = content.slice(0, 100).replace(/\n/g, "\\n");
5276
+ console.error(import_picocolors4.default.dim(`${sessionTag} message.updated (${role}): "${preview}${content.length > 100 ? "..." : ""}"`));
5277
+ break;
5278
+ }
5279
+ case "tool.execute": {
5280
+ const toolProps = props;
5281
+ const toolName = toolProps?.name ?? "unknown";
5282
+ const input = toolProps?.input ?? {};
5283
+ const inputStr = JSON.stringify(input).slice(0, 150);
5284
+ console.error(import_picocolors4.default.cyan(`${sessionTag} \u26A1 TOOL.EXECUTE: ${import_picocolors4.default.bold(toolName)}`));
5285
+ console.error(import_picocolors4.default.dim(` input: ${inputStr}${inputStr.length >= 150 ? "..." : ""}`));
5286
+ break;
5287
+ }
5288
+ case "tool.result": {
5289
+ const resultProps = props;
5290
+ const output = resultProps?.output ?? "";
5291
+ const preview = output.slice(0, 200).replace(/\n/g, "\\n");
5292
+ console.error(import_picocolors4.default.green(`${sessionTag} \u2713 TOOL.RESULT: "${preview}${output.length > 200 ? "..." : ""}"`));
5293
+ break;
5294
+ }
5295
+ default:
5296
+ console.error(import_picocolors4.default.dim(`${sessionTag} ${payload.type}`));
5228
5297
  }
5229
5298
  }
5230
5299
  function handleSessionIdle(ctx, payload, state) {
@@ -5243,6 +5312,36 @@ function handleSessionStatus(ctx, payload, state) {
5243
5312
  state.mainSessionIdle = false;
5244
5313
  }
5245
5314
  }
5315
+ function handleSessionError(ctx, payload, state) {
5316
+ if (payload.type !== "session.error")
5317
+ return;
5318
+ const props = payload.properties;
5319
+ if (props?.sessionID === ctx.sessionID) {
5320
+ state.mainSessionError = true;
5321
+ state.lastError = props?.error ? String(props.error instanceof Error ? props.error.message : props.error) : "Unknown error";
5322
+ console.error(import_picocolors4.default.red(`
5323
+ [session.error] ${state.lastError}`));
5324
+ }
5325
+ }
5326
+ function handleMessagePartUpdated(ctx, payload, state) {
5327
+ if (payload.type !== "message.part.updated")
5328
+ return;
5329
+ const props = payload.properties;
5330
+ if (props?.info?.sessionID !== ctx.sessionID)
5331
+ return;
5332
+ if (props?.info?.role !== "assistant")
5333
+ return;
5334
+ const part = props.part;
5335
+ if (!part)
5336
+ return;
5337
+ if (part.type === "text" && part.text) {
5338
+ const newText = part.text.slice(state.lastPartText.length);
5339
+ if (newText) {
5340
+ process.stdout.write(newText);
5341
+ }
5342
+ state.lastPartText = part.text;
5343
+ }
5344
+ }
5246
5345
  function handleMessageUpdated(ctx, payload, state) {
5247
5346
  if (payload.type !== "message.updated")
5248
5347
  return;
@@ -5254,16 +5353,62 @@ function handleMessageUpdated(ctx, payload, state) {
5254
5353
  const content = props.content;
5255
5354
  if (!content || content === state.lastOutput)
5256
5355
  return;
5257
- const newContent = content.slice(state.lastOutput.length);
5258
- if (newContent) {
5259
- process.stdout.write(newContent);
5356
+ if (state.lastPartText.length === 0) {
5357
+ const newContent = content.slice(state.lastOutput.length);
5358
+ if (newContent) {
5359
+ process.stdout.write(newContent);
5360
+ }
5260
5361
  }
5261
5362
  state.lastOutput = content;
5262
5363
  }
5364
+ function handleToolExecute(ctx, payload, state) {
5365
+ if (payload.type !== "tool.execute")
5366
+ return;
5367
+ const props = payload.properties;
5368
+ if (props?.sessionID !== ctx.sessionID)
5369
+ return;
5370
+ const toolName = props?.name || "unknown";
5371
+ state.currentTool = toolName;
5372
+ let inputPreview = "";
5373
+ if (props?.input) {
5374
+ const input = props.input;
5375
+ if (input.command) {
5376
+ inputPreview = ` ${import_picocolors4.default.dim(String(input.command).slice(0, 60))}`;
5377
+ } else if (input.pattern) {
5378
+ inputPreview = ` ${import_picocolors4.default.dim(String(input.pattern).slice(0, 40))}`;
5379
+ } else if (input.filePath) {
5380
+ inputPreview = ` ${import_picocolors4.default.dim(String(input.filePath))}`;
5381
+ } else if (input.query) {
5382
+ inputPreview = ` ${import_picocolors4.default.dim(String(input.query).slice(0, 40))}`;
5383
+ }
5384
+ }
5385
+ process.stdout.write(`
5386
+ ${import_picocolors4.default.cyan("\u26A1")} ${import_picocolors4.default.bold(toolName)}${inputPreview}
5387
+ `);
5388
+ }
5389
+ function handleToolResult(ctx, payload, state) {
5390
+ if (payload.type !== "tool.result")
5391
+ return;
5392
+ const props = payload.properties;
5393
+ if (props?.sessionID !== ctx.sessionID)
5394
+ return;
5395
+ const output = props?.output || "";
5396
+ const maxLen = 200;
5397
+ const preview = output.length > maxLen ? output.slice(0, maxLen) + "..." : output;
5398
+ if (preview.trim()) {
5399
+ const lines = preview.split(`
5400
+ `).slice(0, 3);
5401
+ process.stdout.write(import_picocolors4.default.dim(` \u2514\u2500 ${lines.join(`
5402
+ `)}
5403
+ `));
5404
+ }
5405
+ state.currentTool = null;
5406
+ state.lastPartText = "";
5407
+ }
5263
5408
 
5264
5409
  // src/cli/run/runner.ts
5265
5410
  var POLL_INTERVAL_MS = 500;
5266
- var DEFAULT_TIMEOUT_MS = 30 * 60 * 1000;
5411
+ var DEFAULT_TIMEOUT_MS = 0;
5267
5412
  async function run(options) {
5268
5413
  const {
5269
5414
  message,
@@ -5271,23 +5416,27 @@ async function run(options) {
5271
5416
  directory = process.cwd(),
5272
5417
  timeout = DEFAULT_TIMEOUT_MS
5273
5418
  } = options;
5274
- console.log(import_picocolors4.default.cyan("Starting opencode server..."));
5419
+ console.log(import_picocolors5.default.cyan("Starting opencode server..."));
5275
5420
  const abortController = new AbortController;
5276
- const timeoutId = setTimeout(() => {
5277
- console.log(import_picocolors4.default.yellow(`
5421
+ let timeoutId = null;
5422
+ if (timeout > 0) {
5423
+ timeoutId = setTimeout(() => {
5424
+ console.log(import_picocolors5.default.yellow(`
5278
5425
  Timeout reached. Aborting...`));
5279
- abortController.abort();
5280
- }, timeout);
5426
+ abortController.abort();
5427
+ }, timeout);
5428
+ }
5281
5429
  try {
5282
5430
  const { client: client3, server: server2 } = await createOpencode({
5283
5431
  signal: abortController.signal
5284
5432
  });
5285
5433
  const cleanup = () => {
5286
- clearTimeout(timeoutId);
5434
+ if (timeoutId)
5435
+ clearTimeout(timeoutId);
5287
5436
  server2.close();
5288
5437
  };
5289
5438
  process.on("SIGINT", () => {
5290
- console.log(import_picocolors4.default.yellow(`
5439
+ console.log(import_picocolors5.default.yellow(`
5291
5440
  Interrupted. Shutting down...`));
5292
5441
  cleanup();
5293
5442
  process.exit(130);
@@ -5298,10 +5447,10 @@ Interrupted. Shutting down...`));
5298
5447
  });
5299
5448
  const sessionID = sessionRes.data?.id;
5300
5449
  if (!sessionID) {
5301
- console.error(import_picocolors4.default.red("Failed to create session"));
5450
+ console.error(import_picocolors5.default.red("Failed to create session"));
5302
5451
  return 1;
5303
5452
  }
5304
- console.log(import_picocolors4.default.dim(`Session: ${sessionID}`));
5453
+ console.log(import_picocolors5.default.dim(`Session: ${sessionID}`));
5305
5454
  const ctx = {
5306
5455
  client: client3,
5307
5456
  sessionID,
@@ -5311,7 +5460,7 @@ Interrupted. Shutting down...`));
5311
5460
  const events = await client3.event.subscribe();
5312
5461
  const eventState = createEventState();
5313
5462
  const eventProcessor = processEvents(ctx, events.stream, eventState);
5314
- console.log(import_picocolors4.default.dim(`
5463
+ console.log(import_picocolors5.default.dim(`
5315
5464
  Sending prompt...`));
5316
5465
  await client3.session.promptAsync({
5317
5466
  path: { id: sessionID },
@@ -5321,16 +5470,26 @@ Sending prompt...`));
5321
5470
  },
5322
5471
  query: { directory }
5323
5472
  });
5324
- console.log(import_picocolors4.default.dim(`Waiting for completion...
5473
+ console.log(import_picocolors5.default.dim(`Waiting for completion...
5325
5474
  `));
5326
5475
  while (!abortController.signal.aborted) {
5327
5476
  await new Promise((resolve) => setTimeout(resolve, POLL_INTERVAL_MS));
5328
5477
  if (!eventState.mainSessionIdle) {
5329
5478
  continue;
5330
5479
  }
5480
+ if (eventState.mainSessionError) {
5481
+ console.error(import_picocolors5.default.red(`
5482
+
5483
+ Session ended with error: ${eventState.lastError}`));
5484
+ console.error(import_picocolors5.default.yellow("Check if todos were completed before the error."));
5485
+ abortController.abort();
5486
+ await eventProcessor.catch(() => {});
5487
+ cleanup();
5488
+ return 1;
5489
+ }
5331
5490
  const shouldExit = await checkCompletionConditions(ctx);
5332
5491
  if (shouldExit) {
5333
- console.log(import_picocolors4.default.green(`
5492
+ console.log(import_picocolors5.default.green(`
5334
5493
 
5335
5494
  All tasks completed.`));
5336
5495
  abortController.abort();
@@ -5347,11 +5506,12 @@ All tasks completed.`));
5347
5506
  throw err;
5348
5507
  }
5349
5508
  } catch (err) {
5350
- clearTimeout(timeoutId);
5509
+ if (timeoutId)
5510
+ clearTimeout(timeoutId);
5351
5511
  if (err instanceof Error && err.name === "AbortError") {
5352
5512
  return 130;
5353
5513
  }
5354
- console.error(import_picocolors4.default.red(`Error: ${err}`));
5514
+ console.error(import_picocolors5.default.red(`Error: ${err}`));
5355
5515
  return 1;
5356
5516
  }
5357
5517
  }
@@ -1,7 +1,11 @@
1
1
  import type { RunContext } from "./types";
2
2
  export interface EventState {
3
3
  mainSessionIdle: boolean;
4
+ mainSessionError: boolean;
5
+ lastError: string | null;
4
6
  lastOutput: string;
7
+ lastPartText: string;
8
+ currentTool: string | null;
5
9
  }
6
10
  export declare function createEventState(): EventState;
7
11
  export declare function processEvents(ctx: RunContext, stream: AsyncIterable<unknown>, state: EventState): Promise<void>;
@@ -43,3 +43,29 @@ export interface MessageUpdatedProps {
43
43
  };
44
44
  content?: string;
45
45
  }
46
+ export interface MessagePartUpdatedProps {
47
+ info?: {
48
+ sessionID?: string;
49
+ role?: string;
50
+ };
51
+ part?: {
52
+ type?: string;
53
+ text?: string;
54
+ name?: string;
55
+ input?: unknown;
56
+ };
57
+ }
58
+ export interface ToolExecuteProps {
59
+ sessionID?: string;
60
+ name?: string;
61
+ input?: Record<string, unknown>;
62
+ }
63
+ export interface ToolResultProps {
64
+ sessionID?: string;
65
+ name?: string;
66
+ output?: string;
67
+ }
68
+ export interface SessionErrorProps {
69
+ sessionID?: string;
70
+ error?: unknown;
71
+ }