opencode-resolve 0.1.10 → 0.1.12

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
@@ -156,8 +156,8 @@ npm install -g opencode-resolve
156
156
 
157
157
  1. `opencode-resolve`를 `~/.config/opencode/opencode.json`의 `plugin` 배열에 추가 (이미 없는 경우).
158
158
  2. 파일이 존재하지 않는 경우, 현재 모델 프로바이더에 맞게 적응된 `~/.config/opencode/resolve.json`을 생성:
159
- - **인터랙티브 터미널** → 항상 `mix` / `gpt` / `glm`을 묻고, `bronze` / `silver` / `gold` 3티어 모델을 고르게 합니다. `mix`에서는 전용 `codex`, `glm` primary 에이전트를 켤지도 묻습니다.
160
- - **비대화형 설치** → 모델 pinning을 추측하지 않습니다. `profile: "mix"`, `models: {}`를 쓰고 세 primary 경로(`resolver`, `codex`, `glm`)를 활성화하므로 이후 명시적으로 모델을 고르면 됩니다.
159
+ - **인터랙티브 터미널** → 항상 `mix` / `gpt` / `glm`을 묻고, `bronze` / `silver` / `gold` 3티어 모델을 고르게 합니다. `mix`에서는 전용 `gpt`, `glm` primary 에이전트를 켤지도 묻습니다.
160
+ - **비대화형 설치** → opencode.json에서 프로바이더를 자동 감지하여 모델 적응 프리셋을 작성합니다. `resolver`, `gpt`, `glm` primary 경로를 활성화합니다.
161
161
  - **GLM/ZAI 모델 감지** → 비밀값 없는 로컬 ZAI MCP 부트스트랩은 계속 추가합니다.
162
162
 
163
163
  기존 `resolve.json` 파일은 **동의 없이 덮어쓰지 않습니다**. 재설치 시 인터랙티브 환경이면 기존 파일을 업데이트할지, 백업 후 fresh setup을 다시 돌릴지 묻습니다. 비대화형 자동화에서는 `OPENCODE_RESOLVE_REINSTALL=fresh` 또는 `OPENCODE_RESOLVE_REINSTALL=update`를 설정하세요.
@@ -176,6 +176,30 @@ OPENCODE_RESOLVE_SKIP_POSTINSTALL=1 npm install -g opencode-resolve
176
176
  opencode plugin opencode-resolve --global --force
177
177
  ```
178
178
 
179
+ 그래도 OpenCode가 계속 예전 패키지를 로드하면, OpenCode 플러그인 캐시 항목만 지우고 다시 설치하세요. 이 절차는 `~/.config/opencode/resolve.json`을 삭제하지 않습니다.
180
+
181
+ Linux/macOS:
182
+
183
+ ```sh
184
+ export OPENCODE_CACHE_ROOT="${XDG_CACHE_HOME:-$HOME/.cache}/opencode"
185
+ rm -rf "$OPENCODE_CACHE_ROOT/packages/opencode-resolve@latest"
186
+ opencode plugin opencode-resolve@latest --global --force
187
+ node -e "console.log(require(process.env.OPENCODE_CACHE_ROOT + '/packages/opencode-resolve@latest/node_modules/opencode-resolve/package.json').version)"
188
+ ```
189
+
190
+ Windows PowerShell:
191
+
192
+ ```powershell
193
+ $OpenCodeCacheRoot = if ($env:XDG_CACHE_HOME) { Join-Path $env:XDG_CACHE_HOME "opencode" } else { Join-Path $env:LOCALAPPDATA "opencode" }
194
+ $PluginCache = Join-Path $OpenCodeCacheRoot "packages\opencode-resolve@latest"
195
+ Remove-Item -Recurse -Force $PluginCache -ErrorAction SilentlyContinue
196
+ opencode plugin opencode-resolve@latest --global --force
197
+ $Pkg = Join-Path $PluginCache "node_modules\opencode-resolve\package.json"
198
+ node -e "console.log(require(process.argv[1]).version)" $Pkg
199
+ ```
200
+
201
+ 캐시 새로고침 후 OpenCode를 재시작하세요.
202
+
179
203
  ### 수동 대안
180
204
 
181
205
  `postinstall`이 플러그인을 등록하지 않았다면, `~/.config/opencode/opencode.json`에 직접 추가:
@@ -655,8 +679,8 @@ opencode-resolve는 전체 저장소를 프롬프트에 밀어 넣지 않고도
655
679
 
656
680
  | 감지된 프로바이더 | 프리셋 |
657
681
  |---|---|
658
- | 인터랙티브 터미널 | 항상 `mix` / `gpt` / `glm`을 묻고 3티어 모델을 고르게 하며, `mix`에서는 `codex`와 `glm` primary 에이전트 활성화도 묻습니다 |
659
- | 비대화형 설치 | 모델 pinning을 추측하지 않음; `profile: "mix"`, `models: {}`를 쓰고 `resolver`, `codex`, `glm` primary 경로를 활성화 |
682
+ | 인터랙티브 터미널 | 항상 `mix` / `gpt` / `glm`을 묻고 3티어 모델을 고르게 하며, `mix`에서는 `gpt`와 `glm` primary 에이전트 활성화도 묻습니다 |
683
+ | 비대화형 설치 | opencode.json에서 프로바이더를 자동 감지하여 모델 적응 프리셋 작성. `resolver`, `gpt`, `glm` primary 경로 활성화 |
660
684
  | 레거시 opt-in | `OPENCODE_RESOLVE_AUTO_PRESET=1`을 설정하면 비대화형 provider-adapted 프리셋 허용 |
661
685
  | GLM/ZAI 감지 | API 키를 복사하지 않고 ZAI MCP 부트스트랩 추가 |
662
686
 
@@ -748,7 +772,7 @@ OPENCODE_RESOLVE_SKIP_POSTINSTALL=1 npm install -g opencode-resolve
748
772
  | `fast` | 빠른/저렴한 모델의 프로바이더 중립적 별칭 |
749
773
  | `strong` | 강력한/비싼 모델의 프로바이더 중립적 별칭 |
750
774
  | `mini` | 미니/효율적 모델의 프로바이더 중립적 별칭 |
751
- | `codex` | 코덱스 스타일 코딩 모델의 프로바이더 중립적 별칭 |
775
+ | `codex` | 코덱스 스타일 코딩 모델의 프로바이더 중립적 별칭 (레거시) |
752
776
  | `bronze` / `silver` / `gold` | scout / coder / reasoner 3티어 별칭 |
753
777
  | `gpt-bronze` / `gpt-silver` / `gpt-gold` | mixed 설정의 GPT/Codex 전용 3티어 별칭 |
754
778
  | `glm-bronze` / `glm-silver` / `glm-gold` | mixed 설정의 GLM 전용 3티어 별칭 |
@@ -766,7 +790,8 @@ OPENCODE_RESOLVE_SKIP_POSTINSTALL=1 npm install -g opencode-resolve
766
790
  | 에이전트 | 기본 | 모드 | Edit | Bash | WebFetch | 용도 |
767
791
  |---|:---:|---|---|---|---|---|
768
792
  | `resolver` | 예 (핵심) | `all` | allow | ask (분류기 라우팅) | allow | 컨텍스트 효율적 오케스트레이터. 작업을 검증된 체크포인트로 분해, coder 디스패치, 각각 검증, 반복 회복 실패 시 차단 사항 보고. |
769
- | `codex` | 아니오 | `all` | allow | ask (분류기 라우팅) | allow | `resolver`와 같은 검증 resolve-loop 스타일의 Codex 최적화 primary. 최초 설치 GPT/mix 프리셋 또는 명시 설정으로 활성화. |
793
+ | `codex` | 아니오 | `all` | allow | ask (분류기 라우팅) | allow | `resolver`와 같은 검증 resolve-loop 스타일의 Codex 최적화 primary. 레거시 GPT 설정에서는 `gpt` 권장. |
794
+ | `gpt` | 아니오 | `all` | allow | ask (분류기 라우팅) | allow | `resolver`와 같은 검증 resolve-loop 스타일의 GPT 최적화 primary. 최초 설치 GPT/mix 프리셋 또는 명시 설정으로 활성화. |
770
795
  | `glm` | 아니오 | `all` | allow | ask (분류기 라우팅) | allow | `resolver`와 같은 검증 resolve-loop 스타일의 GLM 최적화 primary. 최초 설치 GLM/mix 프리셋 또는 명시 설정으로 활성화. |
771
796
  | `coder` | 예 (핵심) | `subagent` | allow | ask (분류기 라우팅) | allow | 집중된 구현자. 가장 작은 올바른 패치. 필요한 파일만 읽음. |
772
797
  | `explorer` | 예 (서브에이전트) | `subagent` | **deny** | **deny** | allow | 내부 빠른 코드베이스 스카우트. Resolver가 범위가 불명확할 때만 디스패치; 좁은 범위는 로컬 read/grep/glob 선호. |
@@ -864,6 +889,28 @@ opencode plugin opencode-resolve --global --force
864
889
  # OpenCode 재시작
865
890
  ```
866
891
 
892
+ 그래도 버전이 바뀌지 않으면 OpenCode가 패키지 캐시를 재사용하는 상태입니다. 해당 플러그인 캐시 항목만 hard refresh 하세요:
893
+
894
+ Linux/macOS:
895
+
896
+ ```sh
897
+ export OPENCODE_CACHE_ROOT="${XDG_CACHE_HOME:-$HOME/.cache}/opencode"
898
+ rm -rf "$OPENCODE_CACHE_ROOT/packages/opencode-resolve@latest"
899
+ opencode plugin opencode-resolve@latest --global --force
900
+ node -e "console.log(require(process.env.OPENCODE_CACHE_ROOT + '/packages/opencode-resolve@latest/node_modules/opencode-resolve/package.json').version)"
901
+ ```
902
+
903
+ Windows PowerShell:
904
+
905
+ ```powershell
906
+ $OpenCodeCacheRoot = if ($env:XDG_CACHE_HOME) { Join-Path $env:XDG_CACHE_HOME "opencode" } else { Join-Path $env:LOCALAPPDATA "opencode" }
907
+ $PluginCache = Join-Path $OpenCodeCacheRoot "packages\opencode-resolve@latest"
908
+ Remove-Item -Recurse -Force $PluginCache -ErrorAction SilentlyContinue
909
+ opencode plugin opencode-resolve@latest --global --force
910
+ $Pkg = Join-Path $PluginCache "node_modules\opencode-resolve\package.json"
911
+ node -e "console.log(require(process.argv[1]).version)" $Pkg
912
+ ```
913
+
867
914
  업그레이드 후 `postinstall`이 `resolve.json`에 추가적 마이그레이션을 실행합니다 — 새 키가 추가되고, 기존 키는 절대 수정되지 않습니다.
868
915
 
869
916
  ### 특정 버전 고정
package/README.md CHANGED
@@ -156,8 +156,8 @@ The `postinstall` script automatically:
156
156
 
157
157
  1. Adds `opencode-resolve` to `~/.config/opencode/opencode.json` `plugin` array (if not already present).
158
158
  2. Creates `~/.config/opencode/resolve.json` adapted to your current model provider when the file does not exist:
159
- - **Interactive terminal** → always asks for `mix` / `gpt` / `glm`, then lets you pick three-tier `bronze` / `silver` / `gold` models. In `mix`, it also asks whether to enable dedicated `codex` and `glm` primary agents.
160
- - **Non-interactive install** → does not guess model pinning. It writes `profile: "mix"`, leaves `models: {}`, and enables the three primary routes (`resolver`, `codex`, `glm`) so you can pin models explicitly afterward.
159
+ - **Interactive terminal** → always asks for `mix` / `gpt` / `glm`, then lets you pick three-tier `bronze` / `silver` / `gold` models. In `mix`, it also asks whether to enable dedicated `gpt` and `glm` primary agents.
160
+ - **Non-interactive install** → auto-detects providers from opencode.json and writes a model-adapted preset. Enables `resolver`, `gpt`, and `glm` as primary routes.
161
161
  - **GLM/ZAI model detected** → still adds the non-secret local ZAI MCP bootstrap.
162
162
 
163
163
  Existing `resolve.json` files are **never overwritten without consent**. On reinstall, interactive setup asks whether to update the existing file or back it up and run fresh setup. For non-interactive automation, set `OPENCODE_RESOLVE_REINSTALL=fresh` or `OPENCODE_RESOLVE_REINSTALL=update`.
@@ -176,6 +176,30 @@ OPENCODE_RESOLVE_SKIP_POSTINSTALL=1 npm install -g opencode-resolve
176
176
  opencode plugin opencode-resolve --global --force
177
177
  ```
178
178
 
179
+ If OpenCode keeps loading the old package anyway, clear only the OpenCode plugin cache entry and install again. This does **not** delete `~/.config/opencode/resolve.json`.
180
+
181
+ Linux/macOS:
182
+
183
+ ```sh
184
+ export OPENCODE_CACHE_ROOT="${XDG_CACHE_HOME:-$HOME/.cache}/opencode"
185
+ rm -rf "$OPENCODE_CACHE_ROOT/packages/opencode-resolve@latest"
186
+ opencode plugin opencode-resolve@latest --global --force
187
+ node -e "console.log(require(process.env.OPENCODE_CACHE_ROOT + '/packages/opencode-resolve@latest/node_modules/opencode-resolve/package.json').version)"
188
+ ```
189
+
190
+ Windows PowerShell:
191
+
192
+ ```powershell
193
+ $OpenCodeCacheRoot = if ($env:XDG_CACHE_HOME) { Join-Path $env:XDG_CACHE_HOME "opencode" } else { Join-Path $env:LOCALAPPDATA "opencode" }
194
+ $PluginCache = Join-Path $OpenCodeCacheRoot "packages\opencode-resolve@latest"
195
+ Remove-Item -Recurse -Force $PluginCache -ErrorAction SilentlyContinue
196
+ opencode plugin opencode-resolve@latest --global --force
197
+ $Pkg = Join-Path $PluginCache "node_modules\opencode-resolve\package.json"
198
+ node -e "console.log(require(process.argv[1]).version)" $Pkg
199
+ ```
200
+
201
+ Restart OpenCode after the cache refresh.
202
+
179
203
  ### Manual fallback
180
204
 
181
205
  If `postinstall` didn't register the plugin, add it to `~/.config/opencode/opencode.json` yourself:
@@ -655,8 +679,8 @@ When `resolve.json` does **not** exist, postinstall inspects your OpenCode model
655
679
 
656
680
  | Detected provider | Preset |
657
681
  |---|---|
658
- | Interactive terminal | Always prompts for `mix` / `gpt` / `glm`, asks for three-tier model picks, and in `mix` asks whether to enable `codex` and `glm` primary agents |
659
- | Non-interactive install | Does not guess model pinning; writes `profile: "mix"`, `models: {}`, and enables `resolver`, `codex`, and `glm` as primary routes |
682
+ | Interactive terminal | Always prompts for `mix` / `gpt` / `glm`, asks for three-tier model picks, and in `mix` asks whether to enable `gpt` and `glm` primary agents |
683
+ | Non-interactive install | Auto-detects providers from opencode.json and writes a model-adapted preset with `resolver`, `gpt`, and `glm` enabled |
660
684
  | Legacy opt-in | Set `OPENCODE_RESOLVE_AUTO_PRESET=1` to allow non-interactive provider-adapted presets |
661
685
  | GLM/ZAI detected | Adds the ZAI MCP bootstrap without copying API keys |
662
686
 
@@ -748,9 +772,9 @@ In this setup, `plan` uses `openai/gpt-5.3-codex`; native `build`, resolve `code
748
772
  | `fast` | Provider-neutral alias for a fast/cheap model |
749
773
  | `strong` | Provider-neutral alias for a strong/expensive model |
750
774
  | `mini` | Provider-neutral alias for a mini/efficient model |
751
- | `codex` | Provider-neutral alias for a codex-style coding model |
775
+ | `codex` | Provider-neutral alias for a codex-style coding model (legacy) |
752
776
  | `bronze` / `silver` / `gold` | Three-tier scout / coder / reasoner aliases |
753
- | `gpt-bronze` / `gpt-silver` / `gpt-gold` | GPT/Codex-specific three-tier aliases for mixed setups |
777
+ | `gpt-bronze` / `gpt-silver` / `gpt-gold` | GPT-specific three-tier aliases for mixed setups |
754
778
  | `glm-bronze` / `glm-silver` / `glm-gold` | GLM-specific three-tier aliases for mixed setups |
755
779
  | `quick` | Legacy alias (equivalent to `fast`) |
756
780
  | `deep` | Legacy alias (equivalent to `strong`) |
@@ -766,7 +790,8 @@ Aliases only resolve when defined in `models`. Agent names (`coder`, `resolver`,
766
790
  | Agent | Default | Mode | Edit | Bash | WebFetch | Purpose |
767
791
  |---|:---:|---|---|---|---|---|
768
792
  | `resolver` | Yes (core) | `all` | allow | ask (classifier-routed) | allow | Context-efficient orchestrator. Decomposes work into verified checkpoints, dispatches coder, verifies each, and reports blockers when repeated recovery fails. |
769
- | `codex` | No | `all` | allow | ask (classifier-routed) | allow | Codex-optimized primary resolver with the same verified resolve-loop style as `resolver`. Enabled by first-install GPT/mix presets or explicitly. |
793
+ | `codex` | No | `all` | allow | ask (classifier-routed) | allow | Codex-optimized primary resolver. Legacy prefer `gpt` for new GPT setups. |
794
+ | `gpt` | No | `all` | allow | ask (classifier-routed) | allow | GPT-optimized primary resolver with the same verified resolve-loop style as `resolver`. Enabled by first-install GPT/mix presets or explicitly. |
770
795
  | `glm` | No | `all` | allow | ask (classifier-routed) | allow | GLM-optimized primary resolver with the same verified resolve-loop style as `resolver`. Enabled by first-install GLM/mix presets or explicitly. |
771
796
  | `coder` | Yes (core) | `subagent` | allow | ask (classifier-routed) | allow | Focused implementer. Smallest correct patch. Reads only needed files. |
772
797
  | `explorer` | Yes (subagent) | `subagent` | **deny** | **deny** | allow | Internal fast codebase scout. Resolver dispatches when scope is genuinely unknown; prefers local read/grep/glob for narrow scope. |
@@ -864,6 +889,28 @@ opencode plugin opencode-resolve --global --force
864
889
  # Restart OpenCode
865
890
  ```
866
891
 
892
+ If the version still does not change, OpenCode is reusing its package cache. Hard-refresh that one plugin entry:
893
+
894
+ Linux/macOS:
895
+
896
+ ```sh
897
+ export OPENCODE_CACHE_ROOT="${XDG_CACHE_HOME:-$HOME/.cache}/opencode"
898
+ rm -rf "$OPENCODE_CACHE_ROOT/packages/opencode-resolve@latest"
899
+ opencode plugin opencode-resolve@latest --global --force
900
+ node -e "console.log(require(process.env.OPENCODE_CACHE_ROOT + '/packages/opencode-resolve@latest/node_modules/opencode-resolve/package.json').version)"
901
+ ```
902
+
903
+ Windows PowerShell:
904
+
905
+ ```powershell
906
+ $OpenCodeCacheRoot = if ($env:XDG_CACHE_HOME) { Join-Path $env:XDG_CACHE_HOME "opencode" } else { Join-Path $env:LOCALAPPDATA "opencode" }
907
+ $PluginCache = Join-Path $OpenCodeCacheRoot "packages\opencode-resolve@latest"
908
+ Remove-Item -Recurse -Force $PluginCache -ErrorAction SilentlyContinue
909
+ opencode plugin opencode-resolve@latest --global --force
910
+ $Pkg = Join-Path $PluginCache "node_modules\opencode-resolve\package.json"
911
+ node -e "console.log(require(process.argv[1]).version)" $Pkg
912
+ ```
913
+
867
914
  After upgrading, `postinstall` runs additive migration on your `resolve.json` — new keys are added, existing keys are never modified.
868
915
 
869
916
  ### Pinning a specific version
package/dist/agents.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { ResolveAgentName, ResolveAgentConfig, ModelAlias, TierName } from "./types.js";
2
2
  export declare const DEFAULT_MODELS: Partial<Record<ModelAlias, string>>;
3
3
  export declare const DEFAULT_ENABLED: ResolveAgentName[];
4
- export declare const VALID_AGENT_NAMES: readonly ["coder", "reviewer", "resolver", "codex", "glm", "architect", "gpt-coder", "debugger", "researcher", "explorer", "deep-reviewer", "planner"];
4
+ export declare const VALID_AGENT_NAMES: readonly ["coder", "reviewer", "resolver", "codex", "gpt", "glm", "architect", "gpt-coder", "debugger", "researcher", "explorer", "deep-reviewer", "planner"];
5
5
  export declare const VALID_AGENT_NAME_SET: Set<string>;
6
6
  export declare const DEFAULT_AGENT_CONFIG: Record<ResolveAgentName, Required<Pick<ResolveAgentConfig, "mode" | "description" | "prompt" | "color">> & ResolveAgentConfig>;
7
7
  export declare const GLM_CODER_PROMPT: string;
@@ -10,7 +10,7 @@ export declare function buildGLMResolverPrompt(maxParallelSubagents: number | un
10
10
  export declare function buildGPTResolverPrompt(): string;
11
11
  export declare function buildCodexResolverPrompt(): string;
12
12
  export declare function buildResolverPrompt(maxParallelSubagents: number | undefined): string;
13
- export declare const VALID_MODEL_ALIASES: readonly ["coder", "reviewer", "resolver", "codex", "glm", "architect", "gpt-coder", "debugger", "researcher", "explorer", "deep-reviewer", "planner", "glm", "gpt", "quick", "deep", "fast", "strong", "mini", "codex", "bronze", "silver", "gold", "gpt-bronze", "gpt-silver", "gpt-gold", "glm-bronze", "glm-silver", "glm-gold"];
13
+ export declare const VALID_MODEL_ALIASES: readonly ["coder", "reviewer", "resolver", "codex", "gpt", "glm", "architect", "gpt-coder", "debugger", "researcher", "explorer", "deep-reviewer", "planner", "glm", "gpt", "quick", "deep", "fast", "strong", "mini", "codex", "bronze", "silver", "gold", "gpt-bronze", "gpt-silver", "gpt-gold", "glm-bronze", "glm-silver", "glm-gold"];
14
14
  export declare const VALID_MODEL_ALIAS_SET: Set<string>;
15
15
  export declare const VALID_PROFILES: Set<string>;
16
16
  export declare const VALID_TIERS: Set<string>;
package/dist/agents.js CHANGED
@@ -5,6 +5,7 @@ export const VALID_AGENT_NAMES = [
5
5
  "reviewer",
6
6
  "resolver",
7
7
  "codex",
8
+ "gpt",
8
9
  "glm",
9
10
  "architect",
10
11
  "gpt-coder",
@@ -85,6 +86,18 @@ export const DEFAULT_AGENT_CONFIG = {
85
86
  webfetch: "allow",
86
87
  },
87
88
  },
89
+ gpt: {
90
+ mode: "all",
91
+ color: "#FFB347",
92
+ maxSteps: 35,
93
+ description: "GPT-optimized primary resolver for agentic coding work. Use when a GPT/OpenAI coding model is pinned and you want a dedicated user-facing route separate from the neutral resolver.",
94
+ prompt: buildGPTResolverPrompt(),
95
+ permission: {
96
+ edit: "allow",
97
+ bash: "ask",
98
+ webfetch: "allow",
99
+ },
100
+ },
88
101
  architect: {
89
102
  mode: "subagent",
90
103
  color: "#00BFFF",
@@ -368,11 +381,11 @@ export const VALID_MODEL_ALIAS_SET = new Set(VALID_MODEL_ALIASES);
368
381
  export const VALID_PROFILES = new Set(["mix", "glm", "gpt"]);
369
382
  export const VALID_TIERS = new Set(["bronze", "silver", "gold"]);
370
383
  export const GLM_ENABLED = ["coder", "resolver", "glm", "explorer", "reviewer", "planner"];
371
- export const GPT_ENABLED = ["coder", "resolver", "codex", "explorer", "reviewer", "deep-reviewer", "planner"];
384
+ export const GPT_ENABLED = ["coder", "resolver", "gpt", "explorer", "reviewer", "deep-reviewer", "planner"];
372
385
  export const TIER_ENABLED = {
373
386
  bronze: ["coder", "resolver"],
374
387
  silver: ["coder", "resolver", "explorer", "reviewer", "planner"],
375
- gold: ["coder", "resolver", "codex", "glm", "explorer", "reviewer", "deep-reviewer", "planner", "debugger", "researcher"],
388
+ gold: ["coder", "resolver", "codex", "gpt", "glm", "explorer", "reviewer", "deep-reviewer", "planner", "debugger", "researcher"],
376
389
  };
377
390
  export const GLM_AGENT_OVERRIDES = {
378
391
  coder: { maxSteps: 15 },
@@ -384,7 +397,7 @@ export const GLM_AGENT_OVERRIDES = {
384
397
  export const GPT_AGENT_OVERRIDES = {
385
398
  coder: { maxSteps: 25 },
386
399
  resolver: { maxSteps: 40 },
387
- codex: { maxSteps: 40 },
400
+ gpt: { maxSteps: 40 },
388
401
  explorer: { maxSteps: 8 },
389
402
  reviewer: { maxSteps: 10 },
390
403
  "deep-reviewer": { maxSteps: 15 },
package/dist/types.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  export type PermissionValue = "ask" | "allow" | "deny";
2
- export type ResolveAgentName = "coder" | "reviewer" | "resolver" | "codex" | "glm" | "architect" | "gpt-coder" | "debugger" | "researcher" | "explorer" | "deep-reviewer" | "planner";
2
+ export type ResolveAgentName = "coder" | "reviewer" | "resolver" | "codex" | "gpt" | "glm" | "architect" | "gpt-coder" | "debugger" | "researcher" | "explorer" | "deep-reviewer" | "planner";
3
3
  export type ModelAlias = ResolveAgentName | "glm" | "gpt" | "quick" | "deep" | "fast" | "strong" | "mini" | "codex" | "bronze" | "silver" | "gold" | "gpt-bronze" | "gpt-silver" | "gpt-gold" | "glm-bronze" | "glm-silver" | "glm-gold";
4
4
  export type AgentMode = "subagent" | "primary" | "all";
5
5
  export type ResolveAgentConfig = {
@@ -17,6 +17,9 @@
17
17
  "codex": {
18
18
  "enabled": false
19
19
  },
20
+ "gpt": {
21
+ "enabled": false
22
+ },
20
23
  "explorer": {
21
24
  "enabled": true,
22
25
  "mode": "subagent"
@@ -118,9 +118,9 @@
118
118
 
119
119
  // -----------------------------------------------------------------------
120
120
  // models (object)
121
- // Alias map. Keys are either an agent name (coder, reviewer, resolver,
122
- // codex, glm, architect, gpt-coder, debugger, researcher, explorer,
123
- // deep-reviewer, planner)
121
+ // Alias map. Keys are either an agent name (coder, reviewer, resolver,
122
+ // codex, gpt, glm, architect, gpt-coder, debugger, researcher, explorer,
123
+ // deep-reviewer, planner)
124
124
  // OR one of the well-known aliases (`glm`, `gpt`, `quick`, `deep`,
125
125
  // `fast`, `strong`, `mini`, `codex`, `bronze`, `silver`, `gold`,
126
126
  // `gpt-bronze`, `gpt-silver`, `gpt-gold`, `glm-bronze`, `glm-silver`,
@@ -168,12 +168,12 @@
168
168
  // third-party providers never blocks agent execution.
169
169
  // "models": {
170
170
  // "glm": "zai-coding-plan/glm-5.1",
171
- // "bronze": "zai-coding-plan/glm-5.1",
172
- // "silver": "zai-coding-plan/glm-5.1",
171
+ // "bronze": "zai-coding-plan/glm-4.7-flash",
172
+ // "silver": "zai-coding-plan/glm-5",
173
173
  // "gold": "zai-coding-plan/glm-5.1",
174
174
  // "fast": "bronze",
175
175
  // "strong": "gold",
176
- // "coder": "silver",
176
+ // "coder": "gold",
177
177
  // "resolver": "gold",
178
178
  // "reviewer": "gold",
179
179
  // "deep-reviewer": "gold",
@@ -223,13 +223,26 @@
223
223
 
224
224
  // codex — Codex-optimized primary resolver (selectable in agent picker)
225
225
  // Same verified resolve-loop style as resolver, with a Codex-specific
226
- // system prompt. Enabled by GPT/mix first-install presets when selected.
226
+ // system prompt. Legacy kept for backward compatibility. New GPT
227
+ // installs should prefer the "gpt" agent instead.
227
228
  "codex": {
228
229
  "enabled": false,
229
230
  "mode": "all",
230
231
  "maxSteps": 35
231
232
  },
232
233
 
234
+ // -----------------------------------------------------------------
235
+ // gpt — GPT-optimized primary resolver (selectable in agent picker)
236
+ // GPT-specific verified resolve-loop with parallel coder dispatch,
237
+ // full agent roster, and higher maxSteps. Enabled automatically when
238
+ // GPT profile is selected during install. Uses buildGPTResolverPrompt().
239
+ // -----------------------------------------------------------------
240
+ "gpt": {
241
+ "enabled": false,
242
+ "mode": "all",
243
+ "maxSteps": 35
244
+ },
245
+
233
246
  // Internal specialist subagents — enabled by default as subagents only.
234
247
  // Core path is resolver→coder. These are dispatched only when justified.
235
248
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-resolve",
3
- "version": "0.1.10",
3
+ "version": "0.1.12",
4
4
  "description": "OpenCode plugin that adds a lightweight resolver/coder harness for continuous agentic coding.",
5
5
  "type": "module",
6
6
  "homepage": "https://github.com/jshsakura/opencode-resolve#readme",
@@ -100,7 +100,7 @@ async function createAdaptiveResolveConfig() {
100
100
  resolveConfig.models = {}
101
101
  resolveConfig.agents = {
102
102
  ...resolveConfig.agents,
103
- codex: { ...(resolveConfig.agents?.codex ?? {}), enabled: true },
103
+ gpt: { ...(resolveConfig.agents?.gpt ?? {}), enabled: true },
104
104
  glm: { ...(resolveConfig.agents?.glm ?? {}), enabled: true },
105
105
  }
106
106
  }
@@ -53,9 +53,13 @@ const OPENAI_MODEL_HINTS = [
53
53
 
54
54
  const GLM_MODEL_HINTS = [
55
55
  "zai-coding-plan/glm-5.1",
56
+ "zai-coding-plan/glm-5",
57
+ "zai-coding-plan/glm-4.7-flash",
58
+ "zai-coding-plan/glm-4.5-flash",
56
59
  "zai/glm-5.1",
57
60
  "zai/glm-5",
58
61
  "zai/glm-4.7-flash",
62
+ "zai/glm-4.7",
59
63
  "zai/glm-4.5-flash",
60
64
  "zai/glm-4.5",
61
65
  "zai/glm-4.5-air",
@@ -91,30 +95,55 @@ async function registerPlugin() {
91
95
  await mkdir(configDir, { recursive: true })
92
96
  const scriptedAnswers = await readScriptedAnswersIfNeeded()
93
97
 
94
- const config = await readOpenCodeConfig()
95
- let configChanged = addPlugin(config)
96
-
97
- // Inject ZAI MCP servers when GLM is detected
98
- const allModels = detectAllModels(config)
98
+ const probe = await readOpenCodeConfig()
99
+ const allModels = detectAllModels(probe)
99
100
  const hasGLM = allModels.some((m) => isGLMModel(m))
100
- if (hasGLM) {
101
- const mcpChanged = await injectZAIMCPs(config)
102
- configChanged = configChanged || mcpChanged
103
- }
101
+ const pluginNeeded = !isPluginRegisteredIn(probe)
102
+ const missingMCPNames = hasGLM
103
+ ? Object.keys(ZAI_MCP_SERVERS).filter((name) => probe.mcp?.[name] === undefined)
104
+ : []
104
105
 
105
- if (configChanged) {
106
- await writeFile(opencodeConfigPath, `${JSON.stringify(config, null, 2)}\n`)
106
+ if (pluginNeeded || missingMCPNames.length > 0) {
107
+ const fresh = await readOpenCodeConfig()
108
+ if (pluginNeeded) applyPluginPatch(fresh)
109
+ if (missingMCPNames.length > 0) applyMCPPatches(fresh, missingMCPNames)
110
+ await writeFile(opencodeConfigPath, `${JSON.stringify(fresh, null, 2)}\n`)
107
111
  console.log(`[${packageName}] updated ${opencodeConfigPath}`)
108
112
  } else {
109
113
  console.log(`[${packageName}] already registered in ${opencodeConfigPath}`)
110
114
  }
111
115
 
112
116
  if (!(await exists(resolveConfigPath))) {
113
- await createAdaptiveResolveConfig(config, scriptedAnswers)
117
+ await createAdaptiveResolveConfig(probe, scriptedAnswers)
114
118
  return
115
119
  }
116
120
 
117
- await handleExistingResolveConfig(config, scriptedAnswers)
121
+ await handleExistingResolveConfig(probe, scriptedAnswers)
122
+ }
123
+
124
+ function isPluginRegisteredIn(config) {
125
+ return Array.isArray(config.plugin) && config.plugin.some(isRegisteredPluginEntry)
126
+ }
127
+
128
+ function applyPluginPatch(config) {
129
+ config.plugin ??= []
130
+ if (!Array.isArray(config.plugin)) {
131
+ throw new Error(`${opencodeConfigPath}.plugin must be an array`)
132
+ }
133
+ if (!config.plugin.some(isRegisteredPluginEntry)) {
134
+ config.plugin.push(packageName)
135
+ }
136
+ }
137
+
138
+ function applyMCPPatches(config, names) {
139
+ config.mcp ??= {}
140
+ for (const name of names) {
141
+ if (config.mcp[name] === undefined) {
142
+ config.mcp[name] = ZAI_MCP_SERVERS[name]
143
+ }
144
+ }
145
+ console.log(`[${packageName}] injected ZAI MCP server config: ${names.join(", ")}`)
146
+ console.log(`[${packageName}] note: API keys are not copied into opencode.json; export Z_AI_API_KEY if the MCP server requires it.`)
118
147
  }
119
148
 
120
149
  async function handleExistingResolveConfig(opencodeConfig, scriptedAnswers) {
@@ -196,29 +225,11 @@ async function createAdaptiveResolveConfig(opencodeConfig, scriptedAnswers) {
196
225
  return
197
226
  }
198
227
 
199
- if (process.env.OPENCODE_RESOLVE_AUTO_PRESET !== "1") {
200
- resolveConfig.profile = "mix"
201
- delete resolveConfig.tier
202
- resolveConfig.models = {}
203
- resolveConfig.agents = {
204
- ...resolveConfig.agents,
205
- codex: { ...(resolveConfig.agents?.codex ?? {}), enabled: true },
206
- glm: { ...(resolveConfig.agents?.glm ?? {}), enabled: true },
207
- }
208
- await writeFile(resolveConfigPath, `${JSON.stringify(resolveConfig, null, 2)}\n`)
209
- console.log(`[${packageName}] created ${resolveConfigPath} (preset: prompt-required)`)
210
- console.log(`[${packageName}] model pinning was not guessed because no interactive prompt was available.`)
211
- console.log(`[${packageName}] rerun setup in a TTY or edit ${resolveConfigPath} to choose GPT/GLM three-tier models.`)
212
- return
213
- }
214
-
215
- // Profile selection based on detected providers
216
228
  const hasGLM = allModels.some((m) => isGLMModel(m))
217
229
  const hasGPT = allModels.some((m) => isGPTModel(m))
218
230
  const preset = buildModelPreset(currentModel, allModels)
219
231
 
220
232
  if (hasGLM && !hasGPT) {
221
- // GLM only → GLM profile, silver tier (token-efficient, no deep-reviewer)
222
233
  resolveConfig.profile = "glm"
223
234
  resolveConfig.tier = "silver"
224
235
  resolveConfig.agents = {
@@ -226,20 +237,18 @@ async function createAdaptiveResolveConfig(opencodeConfig, scriptedAnswers) {
226
237
  glm: { ...(resolveConfig.agents?.glm ?? {}), enabled: true },
227
238
  }
228
239
  } else if (hasGPT && !hasGLM) {
229
- // GPT only → GPT profile, gold tier (full power)
230
240
  resolveConfig.profile = "gpt"
231
241
  resolveConfig.tier = "gold"
232
242
  resolveConfig.agents = {
233
243
  ...resolveConfig.agents,
234
- codex: { ...(resolveConfig.agents?.codex ?? {}), enabled: true },
244
+ gpt: { ...(resolveConfig.agents?.gpt ?? {}), enabled: true },
235
245
  }
236
246
  } else {
237
- // Mixed or unknown provider → explicit mix profile. No tier: use DEFAULT_ENABLED.
238
247
  resolveConfig.profile = "mix"
239
248
  if (hasGLM && hasGPT) {
240
249
  resolveConfig.agents = {
241
250
  ...resolveConfig.agents,
242
- codex: { ...(resolveConfig.agents?.codex ?? {}), enabled: true },
251
+ gpt: { ...(resolveConfig.agents?.gpt ?? {}), enabled: true },
243
252
  glm: { ...(resolveConfig.agents?.glm ?? {}), enabled: true },
244
253
  }
245
254
  }
@@ -247,6 +256,9 @@ async function createAdaptiveResolveConfig(opencodeConfig, scriptedAnswers) {
247
256
 
248
257
  if (preset && Object.keys(preset).length > 0) {
249
258
  resolveConfig.models = preset
259
+ } else {
260
+ console.log(`[${packageName}] no GPT/GLM models detected in opencode.json — agents inherit the top-level model`)
261
+ console.log(`[${packageName}] to configure model pinning, rerun setup in a TTY or edit ${resolveConfigPath}`)
250
262
  }
251
263
 
252
264
  await writeFile(resolveConfigPath, `${JSON.stringify(resolveConfig, null, 2)}\n`)
@@ -327,7 +339,11 @@ function buildModelPreset(currentModel, allModels = []) {
327
339
 
328
340
  // GLM / ZAI — GLM-only preset (no GPT dependency, avoids token-exhaustion errors)
329
341
  if (lower.includes("glm") || lower.includes("zai")) {
330
- return buildGLMOnlyPreset(currentModel)
342
+ return buildGLMOnlyPreset(currentModel, glmModels)
343
+ }
344
+
345
+ if (lower.includes("openai/") || lower.includes("gpt")) {
346
+ return buildGPTOnlyPreset(currentModel, gptModels)
331
347
  }
332
348
 
333
349
  // OpenAI / GPT single-provider preset
@@ -339,8 +355,9 @@ function buildModelPreset(currentModel, allModels = []) {
339
355
  return {}
340
356
  }
341
357
 
342
- function buildGLMOnlyPreset(model) {
343
- const tiers = chooseThreeTier(collectModelChoices([model], isGLMModel, GLM_MODEL_HINTS, false), "glm", false)
358
+ function buildGLMOnlyPreset(model, glmModels) {
359
+ const models = glmModels && glmModels.length > 0 ? glmModels : [model]
360
+ const tiers = chooseThreeTier(models, "glm", false)
344
361
  return {
345
362
  glm: tiers.gold,
346
363
  bronze: tiers.bronze,
@@ -349,7 +366,7 @@ function buildGLMOnlyPreset(model) {
349
366
  fast: "bronze",
350
367
  strong: "gold",
351
368
  mini: "bronze",
352
- coder: "silver",
369
+ coder: "gold",
353
370
  resolver: "gold",
354
371
  reviewer: "gold",
355
372
  "deep-reviewer": "gold",
@@ -358,8 +375,9 @@ function buildGLMOnlyPreset(model) {
358
375
  }
359
376
  }
360
377
 
361
- function buildGPTOnlyPreset(model) {
362
- const tiers = chooseThreeTier(collectModelChoices([model], isGPTModel, OPENAI_MODEL_HINTS, false), "gpt", false)
378
+ function buildGPTOnlyPreset(model, gptModels) {
379
+ const models = gptModels && gptModels.length > 0 ? gptModels : [model]
380
+ const tiers = chooseThreeTier(models, "gpt", false)
363
381
  return {
364
382
  gpt: tiers.gold,
365
383
  bronze: tiers.bronze,
@@ -404,12 +422,17 @@ async function buildInteractivePreset(currentModel, allModels, scriptedAnswers)
404
422
  profile: "gpt",
405
423
  tier: "gold",
406
424
  models: buildGPTThreeTierModels(tiers),
407
- agents: { codex: { enabled: true } },
425
+ agents: { gpt: { enabled: true } },
408
426
  }
409
427
  }
410
428
 
411
429
  if (profile === "glm") {
412
- const tiers = await askThreeTier(rl, "GLM", choices.glm)
430
+ const useCodingPlan = await askYesNo(rl, "Use coding-plan (zai-coding-plan) instead of standard (zai)? [y/N]: ", false)
431
+ const glmChoices = useCodingPlan
432
+ ? choices.glm.map((m) => m.replace(/^zai\//, "zai-coding-plan/"))
433
+ : choices.glm.map((m) => m.replace(/^zai-coding-plan\//, "zai/"))
434
+ const deduped = unique([...glmChoices.filter((m) => isGLMModel(m)), ...GLM_MODEL_HINTS])
435
+ const tiers = await askThreeTier(rl, "GLM", deduped)
413
436
  return {
414
437
  label: "glm-three-tier",
415
438
  profile: "glm",
@@ -419,16 +442,16 @@ async function buildInteractivePreset(currentModel, allModels, scriptedAnswers)
419
442
  }
420
443
  }
421
444
 
422
- const useCodex = await askYesNo(rl, "Enable dedicated Codex primary agent too? [Y/n]: ", true)
445
+ const useGPT = await askYesNo(rl, "Enable dedicated GPT primary agent too? [Y/n]: ", true)
423
446
  const useGLM = await askYesNo(rl, "Enable dedicated GLM primary agent too? [Y/n]: ", true)
424
- const gptTiers = await askThreeTier(rl, "Codex/GPT", choices.gpt)
447
+ const gptTiers = await askThreeTier(rl, "GPT", choices.gpt)
425
448
  const glmTiers = await askThreeTier(rl, "GLM", choices.glm)
426
449
  return {
427
450
  label: "mix-three-tier",
428
451
  profile: "mix",
429
452
  models: buildMixedThreeTierModels(gptTiers, glmTiers),
430
453
  agents: {
431
- codex: { enabled: useCodex },
454
+ gpt: { enabled: useGPT },
432
455
  glm: { enabled: useGLM },
433
456
  },
434
457
  }
@@ -539,7 +562,7 @@ function buildGLMThreeTierModels(tiers) {
539
562
  strong: "gold",
540
563
  mini: "bronze",
541
564
  explorer: "bronze",
542
- coder: "silver",
565
+ coder: "gold",
543
566
  resolver: "gold",
544
567
  reviewer: "gold",
545
568
  "deep-reviewer": "gold",
@@ -561,7 +584,7 @@ function chooseThreeTier(models, family, includeFallbackHints = true) {
561
584
  const choices = unique(includeFallbackHints ? [...models, ...fallback] : models)
562
585
  return {
563
586
  bronze: preferModel(choices, family === "glm" ? ["flash", "air", "mini"] : ["spark", "mini", "4o-mini"], choices[0]),
564
- silver: preferModel(choices, family === "glm" ? ["5.1", "4.5"] : ["codex", "5.3", "5.2"], choices[1] ?? choices[0]),
587
+ silver: preferModel(choices, family === "glm" ? ["4.7", "4.5", "5"] : ["codex", "5.3", "5.2"], choices[1] ?? choices[0]),
565
588
  gold: preferModel(choices, family === "glm" ? ["5.1", "5", "4.5"] : ["5.5", "5.4", "gpt-5.3-codex"], choices[2] ?? choices[1] ?? choices[0]),
566
589
  }
567
590
  }
@@ -724,38 +747,7 @@ async function readOpenCodeConfig() {
724
747
  return parsed
725
748
  }
726
749
 
727
- function addPlugin(config) {
728
- config.plugin ??= []
729
- if (!Array.isArray(config.plugin)) {
730
- throw new Error(`${opencodeConfigPath}.plugin must be an array`)
731
- }
732
-
733
- if (config.plugin.some(isRegisteredPluginEntry)) return false
734
- config.plugin.push(packageName)
735
- return true
736
- }
737
-
738
- async function injectZAIMCPs(config) {
739
- config.mcp ??= {}
740
- if (!isObject(config.mcp)) return false
741
-
742
- const added = []
743
- for (const [name, mcpConfig] of Object.entries(ZAI_MCP_SERVERS)) {
744
- if (config.mcp[name] === undefined) {
745
- config.mcp[name] = mcpConfig
746
- added.push(name)
747
- }
748
- }
749
-
750
- if (added.length > 0) {
751
- console.log(`[${packageName}] injected ZAI MCP server config: ${added.join(", ")}`)
752
- console.log(`[${packageName}] note: API keys are not copied into opencode.json; export Z_AI_API_KEY if the MCP server requires it.`)
753
- return true
754
- }
755
750
 
756
- console.log(`[${packageName}] ZAI MCP server already present — skipping`)
757
- return false
758
- }
759
751
 
760
752
  function isRegisteredPluginEntry(entry) {
761
753
  if (typeof entry === "string") return isResolvePluginName(entry)
@@ -879,13 +871,25 @@ async function installCompanion(pkg) {
879
871
  }
880
872
 
881
873
  async function addCompanionToOpenCodeConfig(pluginEntry) {
882
- const config = await readOpenCodeConfig()
883
- config.plugin ??= []
884
- if (!Array.isArray(config.plugin)) {
885
- throw new Error(`${opencodeConfigPath}.plugin must be an array`)
886
- }
887
874
  const baseName = stripVersionSuffix(pluginEntry)
888
- const alreadyPresent = config.plugin.some((entry) => {
875
+ const probe = await readOpenCodeConfig()
876
+ const alreadyPresent = isCompanionPresent(probe, baseName)
877
+ if (alreadyPresent) return
878
+
879
+ const fresh = await readOpenCodeConfig()
880
+ if (!isCompanionPresent(fresh, baseName)) {
881
+ fresh.plugin ??= []
882
+ if (!Array.isArray(fresh.plugin)) {
883
+ throw new Error(`${opencodeConfigPath}.plugin must be an array`)
884
+ }
885
+ fresh.plugin.push(pluginEntry)
886
+ await writeFile(opencodeConfigPath, `${JSON.stringify(fresh, null, 2)}\n`)
887
+ }
888
+ }
889
+
890
+ function isCompanionPresent(config, baseName) {
891
+ if (!Array.isArray(config.plugin)) return false
892
+ return config.plugin.some((entry) => {
889
893
  const raw = typeof entry === "string"
890
894
  ? entry
891
895
  : Array.isArray(entry) && typeof entry[0] === "string"
@@ -893,7 +897,4 @@ async function addCompanionToOpenCodeConfig(pluginEntry) {
893
897
  : null
894
898
  return raw !== null && stripVersionSuffix(raw) === baseName
895
899
  })
896
- if (alreadyPresent) return
897
- config.plugin.push(pluginEntry)
898
- await writeFile(opencodeConfigPath, `${JSON.stringify(config, null, 2)}\n`)
899
900
  }