opencode-usage-coach 0.10.0 → 0.10.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.
Files changed (3) hide show
  1. package/README.md +12 -0
  2. package/dist/index.js +24 -14
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -49,6 +49,18 @@ For local dev without npm: `bun install && bun run build`, then point both confi
49
49
 
50
50
  Four config surfaces; only the first two (install config + codexbar) are required to run. The **harness config** (`harness.config.json`) maps roles to models so per-model quota is tracked — set `generator` (required) and optionally `grader`, `lighterModel`, and `provider`. Thresholds and tuning live in env vars (`UC_STOP_5H`, `UC_THROTTLE_5H`, …).
51
51
 
52
+ ### Changing models at runtime
53
+
54
+ Type `/coach-config` in the TUI to view or update harness models interactively. The AI calls the `coach_config` tool, which reads/writes `harness.config.json` with merge semantics — no manual JSON editing required:
55
+
56
+ ```
57
+ /coach-config # view current config
58
+ "change generator to anthropic/claude-sonnet-4-20250514"
59
+ "set grader and lighterModel to opencode/mimo-v2.5-free"
60
+ ```
61
+
62
+ Changes take effect immediately for new `generate` / `grade` calls.
63
+
52
64
  See **[docs/configuration.md](docs/configuration.md)** for the full reference (env var table, harness config fields, agent-mode scoping, local dev setup).
53
65
 
54
66
  ## Harness Loop
package/dist/index.js CHANGED
@@ -377,6 +377,22 @@ function writeHarness(sessionID, h) {
377
377
  } catch {
378
378
  }
379
379
  }
380
+ var harnessQueue = /* @__PURE__ */ new Map();
381
+ function mutateHarness(sessionID, fn) {
382
+ const prev = harnessQueue.get(sessionID) ?? Promise.resolve();
383
+ const next = prev.then(() => {
384
+ const h = readHarness(sessionID);
385
+ if (!h) return;
386
+ const result = fn(h);
387
+ writeHarness(sessionID, result ?? h);
388
+ }).catch(() => {
389
+ });
390
+ harnessQueue.set(sessionID, next);
391
+ next.finally(() => {
392
+ if (harnessQueue.get(sessionID) === next) harnessQueue.delete(sessionID);
393
+ });
394
+ return next;
395
+ }
380
396
  function interviewFile(sessionID) {
381
397
  return join2(STATE_DIR, sessionID || "_default", "interview.json");
382
398
  }
@@ -508,29 +524,20 @@ Output JSON ONLY (no markdown fences, no prose):
508
524
  return formatCompleteOutput(state);
509
525
  }
510
526
  function updateSubSession(sessionID, taskId, fields) {
511
- try {
512
- const h = readHarness(sessionID);
513
- if (!h) return;
527
+ return mutateHarness(sessionID, (h) => {
514
528
  const t = h.tasks.find((x) => x.id === taskId);
515
- if (!t) return;
516
- Object.assign(t, fields);
517
- writeHarness(sessionID, h);
518
- } catch {
519
- }
529
+ if (t) Object.assign(t, fields);
530
+ });
520
531
  }
521
532
  function clearSubSession(sessionID, taskId) {
522
- try {
523
- const h = readHarness(sessionID);
524
- if (!h) return;
533
+ return mutateHarness(sessionID, (h) => {
525
534
  const t = h.tasks.find((x) => x.id === taskId);
526
535
  if (!t) return;
527
536
  t.subSessionId = void 0;
528
537
  t.subStep = void 0;
529
538
  t.lastActivity = void 0;
530
539
  t.subElapsed = void 0;
531
- writeHarness(sessionID, h);
532
- } catch {
533
- }
540
+ });
534
541
  }
535
542
  function findActiveTaskId(sessionID, status) {
536
543
  try {
@@ -1264,6 +1271,7 @@ function isHarnessAgent(agent) {
1264
1271
  }
1265
1272
  var LOADING = { decision: "GO", advice: "quota loading\u2026", weekly: -1, monthly: -1, fiveHour: -1 };
1266
1273
  async function UsageCoachPlugin(input) {
1274
+ pipeLog(`UsageCoachPlugin CALLED | dir=${input.directory} | worktree=${input.worktree}`);
1267
1275
  try {
1268
1276
  setStateDir(input.directory);
1269
1277
  initDomain(STATE_DIR);
@@ -2218,6 +2226,7 @@ Note: Changes take effect immediately for new generate/grade calls.`,
2218
2226
  }
2219
2227
  };
2220
2228
  } catch (e) {
2229
+ pipeLog(`PLUGIN INIT FAILED (no-op): ${String(e)}`);
2221
2230
  log(`PLUGIN INIT FAILED (no-op): ${String(e)}`);
2222
2231
  return NOOP_HOOKS;
2223
2232
  }
@@ -2245,6 +2254,7 @@ export {
2245
2254
  readHarness,
2246
2255
  readHarnessCfg,
2247
2256
  readRules,
2257
+ UsageCoachPlugin as server,
2248
2258
  setStateDir,
2249
2259
  updateSubSession,
2250
2260
  writeHarness,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-usage-coach",
3
- "version": "0.10.0",
3
+ "version": "0.10.2",
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",