opencode-usage-coach 0.9.1 → 0.10.0

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.
Files changed (2) hide show
  1. package/dist/index.js +78 -1
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -909,6 +909,25 @@ function readHarnessCfg(dir) {
909
909
  ...tryRead(join2(dir, "harness.config.json"))
910
910
  };
911
911
  }
912
+ function writeHarnessCfg(updates) {
913
+ const configDir = join2(homedir(), ".config", "opencode-usage-coach");
914
+ const configPath = join2(configDir, "harness.config.json");
915
+ try {
916
+ mkdirSync2(configDir, { recursive: true });
917
+ const existing = (() => {
918
+ try {
919
+ return JSON.parse(readFileSync2(configPath, "utf8"));
920
+ } catch {
921
+ return {};
922
+ }
923
+ })();
924
+ const merged = { ...existing, ...updates };
925
+ writeFileSync2(configPath, JSON.stringify(merged, null, 2) + "\n");
926
+ return configPath;
927
+ } catch (e) {
928
+ throw new Error(`Failed to write harness config: ${String(e)}`, { cause: e });
929
+ }
930
+ }
912
931
  async function runModel(client, model, prompt, directory, track, maxSteps = DEFAULT_MAX_STEPS) {
913
932
  const t0 = Date.now();
914
933
  const subStart = Date.now();
@@ -2139,6 +2158,62 @@ If the task is already well-specified with no significant ambiguities, return {"
2139
2158
  const qNum = state.currentIndex + 1;
2140
2159
  return formatQuestionOutput(qNum, total, q);
2141
2160
  }
2161
+ }),
2162
+ coach_config: tool({
2163
+ description: 'View or update harness model configuration (generator, grader, lighterModel, provider). Call with no args to view current config. Pass any combination of generator/grader/lighterModel/provider to update. Example: coach_config({ generator: "anthropic/claude-sonnet-4-20250514", grader: "opencode/mimo-v2.5-free" })',
2164
+ args: {
2165
+ generator: tool.schema.string().optional(),
2166
+ grader: tool.schema.string().optional(),
2167
+ lighterModel: tool.schema.string().optional(),
2168
+ provider: tool.schema.string().optional()
2169
+ },
2170
+ async execute(args, ctx) {
2171
+ const dir = ctx?.directory ?? input.directory;
2172
+ const current2 = readHarnessCfg(dir);
2173
+ const hasUpdates = args.generator !== void 0 || args.grader !== void 0 || args.lighterModel !== void 0 || args.provider !== void 0;
2174
+ if (!hasUpdates) {
2175
+ const envOverrides = [];
2176
+ if (process.env.UC_PROVIDER) envOverrides.push(`UC_PROVIDER=${process.env.UC_PROVIDER}`);
2177
+ if (process.env.UC_LIGHTER_MODEL) envOverrides.push(`UC_LIGHTER_MODEL=${process.env.UC_LIGHTER_MODEL}`);
2178
+ return [
2179
+ `Harness Configuration`,
2180
+ `\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550`,
2181
+ ` generator: ${current2.generator ?? "(not set \u2014 harness won't work!)"}`,
2182
+ ` grader: ${current2.grader ?? "(defaults to generator)"}`,
2183
+ ` lighterModel: ${current2.lighterModel ?? "(not set \u2014 no THROTTLE fallback)"}`,
2184
+ ` provider: ${current2.provider ?? "(auto-detected from model)"}`,
2185
+ `\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550`,
2186
+ envOverrides.length > 0 ? `
2187
+ Environment overrides (take precedence):
2188
+ ${envOverrides.join("\n ")}` : "",
2189
+ `
2190
+ Config file: ~/.config/opencode-usage-coach/harness.config.json`,
2191
+ `
2192
+ To update, call: coach_config({ generator: "provider/model-id", ... })`
2193
+ ].filter(Boolean).join("\n");
2194
+ }
2195
+ const updates = {};
2196
+ if (args.generator !== void 0) updates.generator = args.generator.trim();
2197
+ if (args.grader !== void 0) updates.grader = args.grader.trim();
2198
+ if (args.lighterModel !== void 0) updates.lighterModel = args.lighterModel.trim();
2199
+ if (args.provider !== void 0) updates.provider = args.provider.trim();
2200
+ const writtenPath = writeHarnessCfg(updates);
2201
+ const updated = readHarnessCfg(dir);
2202
+ return [
2203
+ `\u2705 Harness config updated successfully!`,
2204
+ `\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550`,
2205
+ ` generator: ${updated.generator ?? "(not set)"}`,
2206
+ ` grader: ${updated.grader ?? "(defaults to generator)"}`,
2207
+ ` lighterModel: ${updated.lighterModel ?? "(not set)"}`,
2208
+ ` provider: ${updated.provider ?? "(auto-detected)"}`,
2209
+ `\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550`,
2210
+ `
2211
+ Saved to: ${writtenPath}`,
2212
+ `
2213
+ Note: Changes take effect immediately for new generate/grade calls.`,
2214
+ ` A running harness will pick up the new config on the next tool call.`
2215
+ ].join("\n");
2216
+ }
2142
2217
  })
2143
2218
  }
2144
2219
  };
@@ -2168,8 +2243,10 @@ export {
2168
2243
  providerAdvice,
2169
2244
  providerToCodexbar,
2170
2245
  readHarness,
2246
+ readHarnessCfg,
2171
2247
  readRules,
2172
2248
  setStateDir,
2173
2249
  updateSubSession,
2174
- writeHarness
2250
+ writeHarness,
2251
+ writeHarnessCfg
2175
2252
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-usage-coach",
3
- "version": "0.9.1",
3
+ "version": "0.10.0",
4
4
  "description": "opencode closed-loop usage coach — quota SENSE -> coaching DECIDE -> loop ACT + TUI integration",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",