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.
- package/README.md +12 -0
- package/dist/index.js +24 -14
- 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
|
-
|
|
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 (
|
|
516
|
-
|
|
517
|
-
writeHarness(sessionID, h);
|
|
518
|
-
} catch {
|
|
519
|
-
}
|
|
529
|
+
if (t) Object.assign(t, fields);
|
|
530
|
+
});
|
|
520
531
|
}
|
|
521
532
|
function clearSubSession(sessionID, taskId) {
|
|
522
|
-
|
|
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
|
-
|
|
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