opencode-usage-coach 0.1.2 → 0.1.3
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/agents/usage-coach-harness.md +3 -1
- package/dist/tui.js +129 -100
- package/package.json +1 -1
|
@@ -32,8 +32,10 @@ Default to the loop only when it genuinely adds value. Do not over-engineer smal
|
|
|
32
32
|
## Harness loop (only for substantive work)
|
|
33
33
|
The user's message is the task source. If it has multiple distinct parts, decompose into discrete tasks (N); if it is one unit, N = 1.
|
|
34
34
|
|
|
35
|
+
**Parallel dispatch (independent tasks):** If the decomposed tasks are INDEPENDENT (no data dependency), dispatch them concurrently — issue **multiple `task` calls in the same turn** so they run as parallel subagents. (This is the only reliable parallel path — the deterministic script cannot parallelize due to opencode's single-server model.) Cap concurrency by quota coaching: "big tasks OK" → up to 3-4 parallel; "moderate/small" → 1-2; STOP → don't dispatch. For DEPENDENT tasks (B needs A's output), run sequentially.
|
|
36
|
+
|
|
35
37
|
1. Call `harness_start(name, N)` to register the run on the panel.
|
|
36
|
-
2. For each task i (1..N):
|
|
38
|
+
2. For each task i (1..N) — in parallel batches when independent:
|
|
37
39
|
a. `task_update(i, title, "generating")`.
|
|
38
40
|
b. **Generate** — delegate to a subagent via the `task` tool (`subagent_type: "general"`):
|
|
39
41
|
prompt: `"Task: {title}. Perform it for real in the current directory (write/edit files, run commands as needed)."`
|
package/dist/tui.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// src/tui.tsx
|
|
2
|
+
import { insert as _$insert } from "@opentui/solid";
|
|
2
3
|
import { setProp as _$setProp } from "@opentui/solid";
|
|
3
4
|
import { effect as _$effect } from "@opentui/solid";
|
|
4
|
-
import { insert as _$insert } from "@opentui/solid";
|
|
5
5
|
import { createTextNode as _$createTextNode } from "@opentui/solid";
|
|
6
6
|
import { insertNode as _$insertNode } from "@opentui/solid";
|
|
7
7
|
import { createElement as _$createElement } from "@opentui/solid";
|
|
@@ -79,6 +79,26 @@ function initializeTui(api, disposeRoot) {
|
|
|
79
79
|
}, 3e3);
|
|
80
80
|
onCleanup(() => clearInterval(timer));
|
|
81
81
|
onCleanup(() => disposeRoot());
|
|
82
|
+
const [collapsed, setCollapsed] = createSignal(false);
|
|
83
|
+
let cmdDispose;
|
|
84
|
+
try {
|
|
85
|
+
cmdDispose = api.command?.register?.(() => [{
|
|
86
|
+
title: "Toggle usage-coach panel",
|
|
87
|
+
value: "usage-coach-toggle",
|
|
88
|
+
category: "usage-coach",
|
|
89
|
+
keybind: "alt+h",
|
|
90
|
+
onSelect: () => {
|
|
91
|
+
setCollapsed((c) => !c);
|
|
92
|
+
}
|
|
93
|
+
}]);
|
|
94
|
+
} catch {
|
|
95
|
+
}
|
|
96
|
+
onCleanup(() => {
|
|
97
|
+
try {
|
|
98
|
+
cmdDispose?.();
|
|
99
|
+
} catch {
|
|
100
|
+
}
|
|
101
|
+
});
|
|
82
102
|
const statusKey = {
|
|
83
103
|
generating: "info",
|
|
84
104
|
grading: "accent",
|
|
@@ -93,6 +113,15 @@ function initializeTui(api, disposeRoot) {
|
|
|
93
113
|
const st = (k) => ({
|
|
94
114
|
fg: th[k]
|
|
95
115
|
});
|
|
116
|
+
if (collapsed()) {
|
|
117
|
+
return (() => {
|
|
118
|
+
var _el$ = _$createElement("box"), _el$2 = _$createElement("text");
|
|
119
|
+
_$insertNode(_el$, _el$2);
|
|
120
|
+
_$insertNode(_el$2, _$createTextNode(`usage-coach (hidden \u2014 Alt+H)`));
|
|
121
|
+
_$effect((_$p) => _$setProp(_el$2, "style", st("textMuted"), _$p));
|
|
122
|
+
return _el$;
|
|
123
|
+
})();
|
|
124
|
+
}
|
|
96
125
|
let s = null;
|
|
97
126
|
try {
|
|
98
127
|
s = getState();
|
|
@@ -109,106 +138,106 @@ function initializeTui(api, disposeRoot) {
|
|
|
109
138
|
if (s) {
|
|
110
139
|
const dKey = s.decision === "GO" ? "success" : s.decision === "THROTTLE" ? "warning" : "error";
|
|
111
140
|
nodes.push((() => {
|
|
112
|
-
var _el$ = _$createElement("text"), _el$
|
|
113
|
-
_$insertNode(_el
|
|
114
|
-
_$insertNode(_el
|
|
115
|
-
_$insert(_el
|
|
116
|
-
_$effect((_$p) => _$setProp(_el
|
|
117
|
-
return _el
|
|
141
|
+
var _el$4 = _$createElement("text"), _el$5 = _$createTextNode(`usage-coach [`), _el$6 = _$createTextNode(`]`);
|
|
142
|
+
_$insertNode(_el$4, _el$5);
|
|
143
|
+
_$insertNode(_el$4, _el$6);
|
|
144
|
+
_$insert(_el$4, () => TAG[s.decision], _el$6);
|
|
145
|
+
_$effect((_$p) => _$setProp(_el$4, "style", st(dKey), _$p));
|
|
146
|
+
return _el$4;
|
|
118
147
|
})());
|
|
119
148
|
if (s.providers && s.providers.length > 0) {
|
|
120
149
|
for (const p of s.providers) {
|
|
121
150
|
nodes.push((() => {
|
|
122
|
-
var _el$
|
|
123
|
-
_$insertNode(_el$
|
|
124
|
-
_$insert(_el$
|
|
125
|
-
_$effect((_$p) => _$setProp(_el$
|
|
126
|
-
return _el$
|
|
151
|
+
var _el$7 = _$createElement("text"), _el$8 = _$createTextNode(` `);
|
|
152
|
+
_$insertNode(_el$7, _el$8);
|
|
153
|
+
_$insert(_el$7, () => p.name, null);
|
|
154
|
+
_$effect((_$p) => _$setProp(_el$7, "style", st("textMuted"), _$p));
|
|
155
|
+
return _el$7;
|
|
127
156
|
})());
|
|
128
157
|
const k5 = p.fiveHour >= 70 ? "error" : p.fiveHour >= 40 ? "warning" : "success";
|
|
129
158
|
const kw = p.weekly >= 85 ? "error" : p.weekly >= 60 ? "warning" : "success";
|
|
130
159
|
nodes.push((() => {
|
|
131
|
-
var _el$
|
|
132
|
-
_$insertNode(_el$
|
|
133
|
-
_$insertNode(_el$
|
|
134
|
-
_$insertNode(_el$
|
|
135
|
-
_$insert(_el$
|
|
136
|
-
_$insert(_el$
|
|
137
|
-
_$insert(_el$
|
|
138
|
-
_$effect((_$p) => _$setProp(_el$
|
|
139
|
-
return _el$
|
|
160
|
+
var _el$9 = _$createElement("text"), _el$0 = _$createTextNode(` 5h `), _el$1 = _$createTextNode(` `), _el$10 = _$createTextNode(`% `);
|
|
161
|
+
_$insertNode(_el$9, _el$0);
|
|
162
|
+
_$insertNode(_el$9, _el$1);
|
|
163
|
+
_$insertNode(_el$9, _el$10);
|
|
164
|
+
_$insert(_el$9, () => bar(p.fiveHour), _el$1);
|
|
165
|
+
_$insert(_el$9, () => p.fiveHour, _el$10);
|
|
166
|
+
_$insert(_el$9, () => p.fiveHourReset, null);
|
|
167
|
+
_$effect((_$p) => _$setProp(_el$9, "style", st(k5), _$p));
|
|
168
|
+
return _el$9;
|
|
140
169
|
})());
|
|
141
170
|
nodes.push((() => {
|
|
142
|
-
var _el$
|
|
143
|
-
_$insertNode(_el$
|
|
144
|
-
_$insertNode(_el$
|
|
145
|
-
_$insertNode(_el$
|
|
146
|
-
_$insert(_el$
|
|
147
|
-
_$insert(_el$
|
|
148
|
-
_$insert(_el$
|
|
149
|
-
_$effect((_$p) => _$setProp(_el$
|
|
150
|
-
return _el$
|
|
171
|
+
var _el$11 = _$createElement("text"), _el$12 = _$createTextNode(` wk `), _el$13 = _$createTextNode(` `), _el$14 = _$createTextNode(`% `);
|
|
172
|
+
_$insertNode(_el$11, _el$12);
|
|
173
|
+
_$insertNode(_el$11, _el$13);
|
|
174
|
+
_$insertNode(_el$11, _el$14);
|
|
175
|
+
_$insert(_el$11, () => bar(p.weekly), _el$13);
|
|
176
|
+
_$insert(_el$11, () => p.weekly, _el$14);
|
|
177
|
+
_$insert(_el$11, () => p.weeklyReset, null);
|
|
178
|
+
_$effect((_$p) => _$setProp(_el$11, "style", st(kw), _$p));
|
|
179
|
+
return _el$11;
|
|
151
180
|
})());
|
|
152
181
|
nodes.push((() => {
|
|
153
|
-
var _el$
|
|
154
|
-
_$insertNode(_el$
|
|
155
|
-
_$insert(_el$
|
|
156
|
-
_$effect((_$p) => _$setProp(_el$
|
|
157
|
-
return _el$
|
|
182
|
+
var _el$15 = _$createElement("text"), _el$16 = _$createTextNode(` -> `);
|
|
183
|
+
_$insertNode(_el$15, _el$16);
|
|
184
|
+
_$insert(_el$15, () => p.advice, null);
|
|
185
|
+
_$effect((_$p) => _$setProp(_el$15, "style", st(dKey), _$p));
|
|
186
|
+
return _el$15;
|
|
158
187
|
})());
|
|
159
188
|
}
|
|
160
189
|
} else {
|
|
161
190
|
nodes.push((() => {
|
|
162
|
-
var _el$
|
|
163
|
-
_$insertNode(_el$
|
|
164
|
-
_$insertNode(_el$
|
|
165
|
-
_$insertNode(_el$
|
|
166
|
-
_$insert(_el$
|
|
167
|
-
_$insert(_el$
|
|
168
|
-
return _el$
|
|
191
|
+
var _el$19 = _$createElement("text"), _el$20 = _$createTextNode(` 5h `), _el$21 = _$createTextNode(` `), _el$22 = _$createTextNode(`%`);
|
|
192
|
+
_$insertNode(_el$19, _el$20);
|
|
193
|
+
_$insertNode(_el$19, _el$21);
|
|
194
|
+
_$insertNode(_el$19, _el$22);
|
|
195
|
+
_$insert(_el$19, () => bar(s.fiveHour), _el$21);
|
|
196
|
+
_$insert(_el$19, () => s.fiveHour, _el$22);
|
|
197
|
+
return _el$19;
|
|
169
198
|
})());
|
|
170
199
|
nodes.push((() => {
|
|
171
|
-
var _el$
|
|
172
|
-
_$insertNode(_el$
|
|
173
|
-
_$insertNode(_el$
|
|
174
|
-
_$insertNode(_el$
|
|
175
|
-
_$insert(_el$
|
|
176
|
-
_$insert(_el$
|
|
177
|
-
return _el$
|
|
200
|
+
var _el$23 = _$createElement("text"), _el$24 = _$createTextNode(` wk `), _el$25 = _$createTextNode(` `), _el$26 = _$createTextNode(`%`);
|
|
201
|
+
_$insertNode(_el$23, _el$24);
|
|
202
|
+
_$insertNode(_el$23, _el$25);
|
|
203
|
+
_$insertNode(_el$23, _el$26);
|
|
204
|
+
_$insert(_el$23, () => bar(s.weekly), _el$25);
|
|
205
|
+
_$insert(_el$23, () => s.weekly, _el$26);
|
|
206
|
+
return _el$23;
|
|
178
207
|
})());
|
|
179
208
|
nodes.push((() => {
|
|
180
|
-
var _el$
|
|
181
|
-
_$insertNode(_el$
|
|
182
|
-
_$insertNode(_el$
|
|
183
|
-
_$insertNode(_el$
|
|
184
|
-
_$insert(_el$
|
|
185
|
-
_$insert(_el$
|
|
186
|
-
return _el$
|
|
209
|
+
var _el$27 = _$createElement("text"), _el$28 = _$createTextNode(` mo `), _el$29 = _$createTextNode(` `), _el$30 = _$createTextNode(`%`);
|
|
210
|
+
_$insertNode(_el$27, _el$28);
|
|
211
|
+
_$insertNode(_el$27, _el$29);
|
|
212
|
+
_$insertNode(_el$27, _el$30);
|
|
213
|
+
_$insert(_el$27, () => bar(s.monthly), _el$29);
|
|
214
|
+
_$insert(_el$27, () => s.monthly, _el$30);
|
|
215
|
+
return _el$27;
|
|
187
216
|
})());
|
|
188
217
|
}
|
|
189
218
|
} else {
|
|
190
219
|
nodes.push((() => {
|
|
191
|
-
var _el$
|
|
192
|
-
_$insertNode(_el$
|
|
193
|
-
return _el$
|
|
220
|
+
var _el$31 = _$createElement("text");
|
|
221
|
+
_$insertNode(_el$31, _$createTextNode(`usage-coach: ...`));
|
|
222
|
+
return _el$31;
|
|
194
223
|
})());
|
|
195
224
|
}
|
|
196
225
|
if (h && h.active !== false && h.tasks.length > 0) {
|
|
197
226
|
nodes.push((() => {
|
|
198
|
-
var _el$
|
|
199
|
-
_$insertNode(_el$
|
|
200
|
-
return _el$
|
|
227
|
+
var _el$33 = _$createElement("text");
|
|
228
|
+
_$insertNode(_el$33, _$createTextNode(` `));
|
|
229
|
+
return _el$33;
|
|
201
230
|
})());
|
|
202
231
|
nodes.push((() => {
|
|
203
|
-
var _el$
|
|
204
|
-
_$insertNode(_el$
|
|
205
|
-
_$insertNode(_el$
|
|
206
|
-
_$insertNode(_el$
|
|
207
|
-
_$insert(_el$
|
|
208
|
-
_$insert(_el$
|
|
209
|
-
_$insert(_el$
|
|
210
|
-
_$effect((_$p) => _$setProp(_el$
|
|
211
|
-
return _el$
|
|
232
|
+
var _el$35 = _$createElement("text"), _el$36 = _$createTextNode(`harness: `), _el$37 = _$createTextNode(` `), _el$38 = _$createTextNode(`/`);
|
|
233
|
+
_$insertNode(_el$35, _el$36);
|
|
234
|
+
_$insertNode(_el$35, _el$37);
|
|
235
|
+
_$insertNode(_el$35, _el$38);
|
|
236
|
+
_$insert(_el$35, () => h.name, _el$37);
|
|
237
|
+
_$insert(_el$35, () => h.current, _el$38);
|
|
238
|
+
_$insert(_el$35, () => h.total, null);
|
|
239
|
+
_$effect((_$p) => _$setProp(_el$35, "style", st("textMuted"), _$p));
|
|
240
|
+
return _el$35;
|
|
212
241
|
})());
|
|
213
242
|
for (const t of h.tasks) {
|
|
214
243
|
const sKey = statusKey[t.status] ?? "text";
|
|
@@ -216,39 +245,39 @@ function initializeTui(api, disposeRoot) {
|
|
|
216
245
|
const rev = t.revisions > 0 && t.status === "revising" ? `(${t.revisions})` : "";
|
|
217
246
|
const mdl = t.model ? ` ${t.model.split("/").pop() ?? t.model}` : "";
|
|
218
247
|
nodes.push((() => {
|
|
219
|
-
var _el$
|
|
220
|
-
_$insertNode(_el$
|
|
221
|
-
_$insertNode(_el$
|
|
222
|
-
_$insertNode(_el$
|
|
223
|
-
_$insert(_el$
|
|
224
|
-
_$insert(_el$
|
|
225
|
-
_$insert(_el$
|
|
226
|
-
_$insert(_el$
|
|
227
|
-
_$insert(_el$
|
|
228
|
-
_$effect((_$p) => _$setProp(_el$
|
|
229
|
-
return _el$
|
|
248
|
+
var _el$39 = _$createElement("text"), _el$40 = _$createTextNode(` \u25CF `), _el$41 = _$createTextNode(` `), _el$42 = _$createTextNode(` `);
|
|
249
|
+
_$insertNode(_el$39, _el$40);
|
|
250
|
+
_$insertNode(_el$39, _el$41);
|
|
251
|
+
_$insertNode(_el$39, _el$42);
|
|
252
|
+
_$insert(_el$39, () => t.id, _el$41);
|
|
253
|
+
_$insert(_el$39, mdl, _el$41);
|
|
254
|
+
_$insert(_el$39, lbl, _el$42);
|
|
255
|
+
_$insert(_el$39, rev, _el$42);
|
|
256
|
+
_$insert(_el$39, () => short(t.title, 12), null);
|
|
257
|
+
_$effect((_$p) => _$setProp(_el$39, "style", st(sKey), _$p));
|
|
258
|
+
return _el$39;
|
|
230
259
|
})());
|
|
231
260
|
const pv = t.model ? t.model.startsWith("zai") ? "zai" : (t.model.split("/")[0] ?? "").split("-")[0] : "";
|
|
232
261
|
const q = pv && h.quotas?.[pv] ? h.quotas[pv] : null;
|
|
233
262
|
const pct = q ? q.fiveHour : 0;
|
|
234
263
|
const qKey = pct >= 70 ? "error" : pct >= 40 ? "warning" : "success";
|
|
235
264
|
nodes.push((() => {
|
|
236
|
-
var _el$
|
|
237
|
-
_$insertNode(_el$
|
|
238
|
-
_$insertNode(_el$
|
|
239
|
-
_$insertNode(_el$
|
|
240
|
-
_$insert(_el$
|
|
241
|
-
_$insert(_el$
|
|
242
|
-
_$effect((_$p) => _$setProp(_el$
|
|
243
|
-
return _el$
|
|
265
|
+
var _el$43 = _$createElement("text"), _el$44 = _$createTextNode(` 5h `), _el$45 = _$createTextNode(` `), _el$46 = _$createTextNode(`%`);
|
|
266
|
+
_$insertNode(_el$43, _el$44);
|
|
267
|
+
_$insertNode(_el$43, _el$45);
|
|
268
|
+
_$insertNode(_el$43, _el$46);
|
|
269
|
+
_$insert(_el$43, () => bar(pct), _el$45);
|
|
270
|
+
_$insert(_el$43, pct, _el$46);
|
|
271
|
+
_$effect((_$p) => _$setProp(_el$43, "style", st(qKey), _$p));
|
|
272
|
+
return _el$43;
|
|
244
273
|
})());
|
|
245
274
|
}
|
|
246
275
|
}
|
|
247
276
|
return (() => {
|
|
248
|
-
var _el$
|
|
249
|
-
_$setProp(_el$
|
|
250
|
-
_$insert(_el$
|
|
251
|
-
return _el$
|
|
277
|
+
var _el$47 = _$createElement("box");
|
|
278
|
+
_$setProp(_el$47, "flexDirection", "column");
|
|
279
|
+
_$insert(_el$47, nodes);
|
|
280
|
+
return _el$47;
|
|
252
281
|
})();
|
|
253
282
|
};
|
|
254
283
|
api.slots.register({
|
|
@@ -259,9 +288,9 @@ function initializeTui(api, disposeRoot) {
|
|
|
259
288
|
return panel(ctx);
|
|
260
289
|
} catch {
|
|
261
290
|
return (() => {
|
|
262
|
-
var _el$
|
|
263
|
-
_$insertNode(_el$
|
|
264
|
-
return _el$
|
|
291
|
+
var _el$48 = _$createElement("text");
|
|
292
|
+
_$insertNode(_el$48, _$createTextNode(`usage-coach`));
|
|
293
|
+
return _el$48;
|
|
265
294
|
})();
|
|
266
295
|
}
|
|
267
296
|
},
|
|
@@ -270,9 +299,9 @@ function initializeTui(api, disposeRoot) {
|
|
|
270
299
|
return panel(ctx);
|
|
271
300
|
} catch {
|
|
272
301
|
return (() => {
|
|
273
|
-
var _el$
|
|
274
|
-
_$insertNode(_el$
|
|
275
|
-
return _el$
|
|
302
|
+
var _el$50 = _$createElement("text");
|
|
303
|
+
_$insertNode(_el$50, _$createTextNode(`usage-coach`));
|
|
304
|
+
return _el$50;
|
|
276
305
|
})();
|
|
277
306
|
}
|
|
278
307
|
}
|
package/package.json
CHANGED