opencode-usage-coach 0.2.1 → 0.2.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/dist/index.js +37 -19
- package/dist/tui.js +5 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -3,7 +3,7 @@ import { mkdirSync, writeFileSync, appendFileSync, readFileSync, existsSync } fr
|
|
|
3
3
|
import { spawn } from "child_process";
|
|
4
4
|
import { createHash } from "crypto";
|
|
5
5
|
import { homedir } from "os";
|
|
6
|
-
import { join, resolve } from "path";
|
|
6
|
+
import { join, resolve, dirname } from "path";
|
|
7
7
|
import { tool } from "@opencode-ai/plugin";
|
|
8
8
|
var PLUGIN_NAME = "opencode-usage-coach";
|
|
9
9
|
var DEBUG = process.env.UC_DEBUG === "1";
|
|
@@ -38,19 +38,24 @@ function writeState(c) {
|
|
|
38
38
|
} catch {
|
|
39
39
|
}
|
|
40
40
|
}
|
|
41
|
-
function
|
|
41
|
+
function harnessFile(sessionID) {
|
|
42
|
+
return join(STATE_DIR, sessionID || "_default", "harness.json");
|
|
43
|
+
}
|
|
44
|
+
function readHarness(sessionID) {
|
|
42
45
|
try {
|
|
43
|
-
|
|
44
|
-
|
|
46
|
+
const f = harnessFile(sessionID);
|
|
47
|
+
if (!existsSync(f)) return null;
|
|
48
|
+
return JSON.parse(readFileSync(f, "utf8"));
|
|
45
49
|
} catch {
|
|
46
50
|
return null;
|
|
47
51
|
}
|
|
48
52
|
}
|
|
49
|
-
function writeHarness(h) {
|
|
53
|
+
function writeHarness(sessionID, h) {
|
|
50
54
|
try {
|
|
51
|
-
|
|
55
|
+
const f = harnessFile(sessionID);
|
|
56
|
+
mkdirSync(dirname(f), { recursive: true });
|
|
52
57
|
h.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
53
|
-
writeFileSync(
|
|
58
|
+
writeFileSync(f, JSON.stringify(h, null, 2));
|
|
54
59
|
} catch {
|
|
55
60
|
}
|
|
56
61
|
}
|
|
@@ -298,8 +303,8 @@ async function UsageCoachPlugin(input) {
|
|
|
298
303
|
harness_start: tool({
|
|
299
304
|
description: "Start the harness: register the total task count on the panel. Call once when the harness loop begins.",
|
|
300
305
|
args: { name: tool.schema.string(), total: tool.schema.number() },
|
|
301
|
-
async execute(args) {
|
|
302
|
-
writeHarness({ name: args.name, total: args.total, current: 0, tasks: [], usage: {}, startedAt: (/* @__PURE__ */ new Date()).toISOString() });
|
|
306
|
+
async execute(args, ctx) {
|
|
307
|
+
writeHarness(ctx.sessionID, { name: args.name, total: args.total, current: 0, tasks: [], usage: {}, active: true, startedAt: (/* @__PURE__ */ new Date()).toISOString() });
|
|
303
308
|
return `Harness '${args.name}' started (${args.total} tasks). Now report each task's status via task_update and run the loop.`;
|
|
304
309
|
}
|
|
305
310
|
}),
|
|
@@ -313,31 +318,31 @@ async function UsageCoachPlugin(input) {
|
|
|
313
318
|
score: tool.schema.string().optional().describe("PASS | FAIL"),
|
|
314
319
|
model: tool.schema.string().optional()
|
|
315
320
|
},
|
|
316
|
-
async execute(args) {
|
|
317
|
-
const h = readHarness() ?? { name: "batch", total: 0, current: 0, tasks: [], usage: {} };
|
|
321
|
+
async execute(args, ctx) {
|
|
322
|
+
const h = readHarness(ctx.sessionID) ?? { name: "batch", total: 0, current: 0, tasks: [], usage: {}, active: true };
|
|
318
323
|
h.tasks = h.tasks.filter((x) => x.id !== args.id);
|
|
319
324
|
h.tasks.push({ id: args.id, title: args.title, status: args.status, model: args.model ?? "", revisions: args.revisions ?? 0, score: args.score ?? null });
|
|
320
325
|
if (args.id > h.current) h.current = args.id;
|
|
321
|
-
writeHarness(h);
|
|
326
|
+
writeHarness(ctx.sessionID, h);
|
|
322
327
|
return `task ${args.id} -> ${args.status}${args.score ? ` (${args.score})` : ""}`;
|
|
323
328
|
}
|
|
324
329
|
}),
|
|
325
330
|
harness_done: tool({
|
|
326
331
|
description: "Mark the harness as complete \u2014 call when the loop ends.",
|
|
327
332
|
args: {},
|
|
328
|
-
async execute() {
|
|
329
|
-
const h = readHarness();
|
|
333
|
+
async execute(_args, ctx) {
|
|
334
|
+
const h = readHarness(ctx.sessionID);
|
|
330
335
|
if (h) {
|
|
331
336
|
h.current = h.total;
|
|
332
|
-
|
|
337
|
+
h.active = false;
|
|
338
|
+
writeHarness(ctx.sessionID, h);
|
|
333
339
|
}
|
|
334
340
|
return "Harness complete.";
|
|
335
341
|
}
|
|
336
342
|
}),
|
|
337
|
-
// Per-role model execution (config-driven
|
|
338
|
-
// on the same server — enables multi-model (e.g. GLM generate + free mimo grade) in 1 terminal.
|
|
343
|
+
// Per-role model execution (config-driven, same server, no deadlock).
|
|
339
344
|
generate: tool({
|
|
340
|
-
description: "Run the GENERATOR model
|
|
345
|
+
description: "Run the GENERATOR model on a prompt. The generator can use tools (write/edit files). Returns the model's text response.",
|
|
341
346
|
args: { prompt: tool.schema.string() },
|
|
342
347
|
async execute(args, ctx) {
|
|
343
348
|
const cfg = readHarnessCfg(ctx.directory);
|
|
@@ -346,8 +351,21 @@ async function UsageCoachPlugin(input) {
|
|
|
346
351
|
return out ?? `(generator ${model} produced no text)`;
|
|
347
352
|
}
|
|
348
353
|
}),
|
|
354
|
+
generate_batch: tool({
|
|
355
|
+
description: "Run the GENERATOR model on MULTIPLE tasks in PARALLEL. Pass an array of {id, prompt}. Returns all results at once. Use for INDEPENDENT tasks (much faster than sequential generate calls).",
|
|
356
|
+
args: { tasks: tool.schema.array(tool.schema.object({ id: tool.schema.number(), prompt: tool.schema.string() })) },
|
|
357
|
+
async execute(args, ctx) {
|
|
358
|
+
const cfg = readHarnessCfg(ctx.directory);
|
|
359
|
+
const model = cfg.generator ?? "zai-coding-plan/glm-5.1";
|
|
360
|
+
const results = await Promise.all(args.tasks.map(async (t) => {
|
|
361
|
+
const out = await runModel(input.client, model, t.prompt, ctx.directory);
|
|
362
|
+
return `[task ${t.id}] ${out ?? "(no output)"}`;
|
|
363
|
+
}));
|
|
364
|
+
return results.join("\n\n");
|
|
365
|
+
}
|
|
366
|
+
}),
|
|
349
367
|
grade: tool({
|
|
350
|
-
description: "Run the GRADER model
|
|
368
|
+
description: "Run the GRADER model on a prompt. Returns PASS/FAIL on the first line. Falls back to generator if grader quota is out.",
|
|
351
369
|
args: { prompt: tool.schema.string() },
|
|
352
370
|
async execute(args, ctx) {
|
|
353
371
|
const cfg = readHarnessCfg(ctx.directory);
|
package/dist/tui.js
CHANGED
|
@@ -132,7 +132,11 @@ function initializeTui(api, disposeRoot) {
|
|
|
132
132
|
}
|
|
133
133
|
let h = null;
|
|
134
134
|
try {
|
|
135
|
-
|
|
135
|
+
const sid = ctx.session_id ?? "";
|
|
136
|
+
if (sid) {
|
|
137
|
+
const hf = join(STATE_DIR, sid, "harness.json");
|
|
138
|
+
if (existsSync(hf)) h = JSON.parse(readFileSync(hf, "utf8"));
|
|
139
|
+
}
|
|
136
140
|
} catch {
|
|
137
141
|
h = null;
|
|
138
142
|
}
|
package/package.json
CHANGED