opencode-ultra 0.9.7 → 0.9.9

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.md CHANGED
@@ -174,6 +174,45 @@ Two-level merge via `opencode-ultra.json` (or `.jsonc`):
174
174
 
175
175
  Project config overrides user config.
176
176
 
177
+ ### Profiles
178
+
179
+ Define multiple configurations and switch between them via `activeProfile` or the `OPENCODE_ULTRA_PROFILE` environment variable:
180
+
181
+ ```jsonc
182
+ {
183
+ "activeProfile": "cloud",
184
+ "profiles": {
185
+ "cloud": {
186
+ "agents": {
187
+ "sisyphus": { "model": "anthropic/claude-opus-4" },
188
+ "hephaestus": { "model": "openai/gpt-4o" },
189
+ "explore": { "model": "anthropic/claude-haiku-4" }
190
+ },
191
+ "background_task": { "defaultConcurrency": 4 }
192
+ },
193
+ "local": {
194
+ "agents": {
195
+ "sisyphus": { "model": "ollama/llama3:70b" },
196
+ "hephaestus": { "model": "ollama/qwen3:32b" },
197
+ "explore": { "model": "ollama/mistral:7b" }
198
+ },
199
+ "background_task": { "defaultConcurrency": 2 }
200
+ }
201
+ }
202
+ }
203
+ ```
204
+
205
+ Switch profiles at runtime:
206
+
207
+ ```bash
208
+ # Via environment variable (takes priority over activeProfile)
209
+ OPENCODE_ULTRA_PROFILE=local opencode exec --agent sisyphus "implement feature X"
210
+
211
+ # Or set activeProfile in config for the default
212
+ ```
213
+
214
+ Profile settings are deep-merged on top of base config values defined outside `profiles`. You can override just the fields you need per profile — everything else inherits from the base config.
215
+
177
216
  ### Configuration Schema
178
217
 
179
218
  ```jsonc
package/dist/config.d.ts CHANGED
@@ -82,6 +82,91 @@ declare const PluginConfigSchema: z.ZodObject<{
82
82
  implementAgent: z.ZodOptional<z.ZodString>;
83
83
  reviewAgent: z.ZodOptional<z.ZodString>;
84
84
  }, z.core.$strip>>;
85
+ activeProfile: z.ZodOptional<z.ZodString>;
86
+ profiles: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
87
+ agents: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodOptional<z.ZodObject<{
88
+ model: z.ZodOptional<z.ZodString>;
89
+ variant: z.ZodOptional<z.ZodString>;
90
+ category: z.ZodOptional<z.ZodString>;
91
+ temperature: z.ZodOptional<z.ZodNumber>;
92
+ top_p: z.ZodOptional<z.ZodNumber>;
93
+ prompt: z.ZodOptional<z.ZodString>;
94
+ prompt_append: z.ZodOptional<z.ZodString>;
95
+ disable: z.ZodOptional<z.ZodBoolean>;
96
+ description: z.ZodOptional<z.ZodString>;
97
+ mode: z.ZodOptional<z.ZodEnum<{
98
+ subagent: "subagent";
99
+ primary: "primary";
100
+ all: "all";
101
+ }>>;
102
+ maxTokens: z.ZodOptional<z.ZodNumber>;
103
+ thinking: z.ZodOptional<z.ZodObject<{
104
+ type: z.ZodEnum<{
105
+ enabled: "enabled";
106
+ disabled: "disabled";
107
+ }>;
108
+ budgetTokens: z.ZodOptional<z.ZodNumber>;
109
+ }, z.core.$strip>>;
110
+ reasoningEffort: z.ZodOptional<z.ZodEnum<{
111
+ low: "low";
112
+ medium: "medium";
113
+ high: "high";
114
+ xhigh: "xhigh";
115
+ }>>;
116
+ }, z.core.$loose>>>>;
117
+ categories: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
118
+ model: z.ZodOptional<z.ZodString>;
119
+ variant: z.ZodOptional<z.ZodString>;
120
+ }, z.core.$loose>>>;
121
+ fragments: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodArray<z.ZodString>>>;
122
+ prompt_renderer: z.ZodOptional<z.ZodObject<{
123
+ default: z.ZodOptional<z.ZodEnum<{
124
+ markdown: "markdown";
125
+ xml: "xml";
126
+ json: "json";
127
+ }>>;
128
+ model_overrides: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodEnum<{
129
+ markdown: "markdown";
130
+ xml: "xml";
131
+ json: "json";
132
+ }>>>;
133
+ }, z.core.$strip>>;
134
+ disabled_agents: z.ZodOptional<z.ZodArray<z.ZodString>>;
135
+ disabled_hooks: z.ZodOptional<z.ZodArray<z.ZodString>>;
136
+ disabled_tools: z.ZodOptional<z.ZodArray<z.ZodString>>;
137
+ disabled_mcps: z.ZodOptional<z.ZodArray<z.ZodString>>;
138
+ token_truncation: z.ZodOptional<z.ZodObject<{
139
+ maxChars: z.ZodOptional<z.ZodNumber>;
140
+ }, z.core.$strip>>;
141
+ demote_builtin: z.ZodOptional<z.ZodBoolean>;
142
+ background_task: z.ZodOptional<z.ZodObject<{
143
+ defaultConcurrency: z.ZodOptional<z.ZodNumber>;
144
+ providerConcurrency: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodNumber>>;
145
+ modelConcurrency: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodNumber>>;
146
+ staleTimeoutMs: z.ZodOptional<z.ZodNumber>;
147
+ }, z.core.$strip>>;
148
+ comment_checker: z.ZodOptional<z.ZodObject<{
149
+ maxRatio: z.ZodOptional<z.ZodNumber>;
150
+ slopThreshold: z.ZodOptional<z.ZodNumber>;
151
+ }, z.core.$strip>>;
152
+ todo_enforcer: z.ZodOptional<z.ZodObject<{
153
+ maxEnforcements: z.ZodOptional<z.ZodNumber>;
154
+ }, z.core.$strip>>;
155
+ mcp_api_keys: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
156
+ safety: z.ZodOptional<z.ZodObject<{
157
+ maxTotalSpawned: z.ZodOptional<z.ZodNumber>;
158
+ agentTimeoutMs: z.ZodOptional<z.ZodNumber>;
159
+ }, z.core.$strip>>;
160
+ evolve_exe: z.ZodOptional<z.ZodObject<{
161
+ maxIterations: z.ZodOptional<z.ZodNumber>;
162
+ iterationTimeoutMs: z.ZodOptional<z.ZodNumber>;
163
+ totalTimeoutMs: z.ZodOptional<z.ZodNumber>;
164
+ skipReview: z.ZodOptional<z.ZodBoolean>;
165
+ skipTests: z.ZodOptional<z.ZodBoolean>;
166
+ implementAgent: z.ZodOptional<z.ZodString>;
167
+ reviewAgent: z.ZodOptional<z.ZodString>;
168
+ }, z.core.$strip>>;
169
+ }, z.core.$loose>>>;
85
170
  }, z.core.$loose>;
86
171
  export type PluginConfig = z.infer<typeof PluginConfigSchema>;
87
172
  export declare function parsePluginConfig(raw: unknown): PluginConfig;
package/dist/index.js CHANGED
@@ -14661,7 +14661,7 @@ var CategoryConfigSchema = exports_external.object({
14661
14661
  model: exports_external.string().optional(),
14662
14662
  variant: exports_external.string().optional()
14663
14663
  }).passthrough();
14664
- var PluginConfigSchema = exports_external.object({
14664
+ var BaseConfigSchema = exports_external.object({
14665
14665
  agents: AgentOverridesSchema.optional(),
14666
14666
  categories: exports_external.record(exports_external.string(), CategoryConfigSchema).optional(),
14667
14667
  fragments: exports_external.record(exports_external.string(), exports_external.array(exports_external.string())).optional(),
@@ -14705,6 +14705,10 @@ var PluginConfigSchema = exports_external.object({
14705
14705
  reviewAgent: exports_external.string().optional()
14706
14706
  }).optional()
14707
14707
  }).passthrough();
14708
+ var PluginConfigSchema = BaseConfigSchema.extend({
14709
+ activeProfile: exports_external.string().optional(),
14710
+ profiles: exports_external.record(exports_external.string(), BaseConfigSchema).optional()
14711
+ });
14708
14712
  function parsePluginConfig(raw) {
14709
14713
  const result = PluginConfigSchema.safeParse(raw);
14710
14714
  if (result.success)
@@ -14772,6 +14776,23 @@ function detectConfigFile(basePath) {
14772
14776
  return basePath + ".json";
14773
14777
  return null;
14774
14778
  }
14779
+ function resolveProfile(config2) {
14780
+ const profiles = config2.profiles;
14781
+ if (!profiles)
14782
+ return config2;
14783
+ const profileName = process.env.OPENCODE_ULTRA_PROFILE || config2.activeProfile;
14784
+ if (!profileName)
14785
+ return config2;
14786
+ const profile = profiles[profileName];
14787
+ if (!profile) {
14788
+ log(`Profile "${profileName}" not found. Available: ${Object.keys(profiles).join(", ")}`);
14789
+ return config2;
14790
+ }
14791
+ const { profiles: _p, activeProfile: _a2, ...base } = config2;
14792
+ const merged = mergeConfigs(base, profile);
14793
+ log(`Profile "${profileName}" activated`);
14794
+ return merged;
14795
+ }
14775
14796
  function loadConfig(projectDir) {
14776
14797
  const userPath = detectConfigFile(path.join(getConfigDir(), "opencode-ultra"));
14777
14798
  let config2 = {};
@@ -14795,6 +14816,7 @@ function loadConfig(projectDir) {
14795
14816
  log(`Error loading project config: ${err}`);
14796
14817
  }
14797
14818
  }
14819
+ config2 = resolveProfile(config2);
14798
14820
  return config2;
14799
14821
  }
14800
14822
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-ultra",
3
- "version": "0.9.7",
3
+ "version": "0.9.9",
4
4
  "description": "Lightweight OpenCode 1.2.x plugin — ultrawork mode, multi-agent orchestration, rules injection",
5
5
  "keywords": [
6
6
  "opencode",