opencode-usage-coach 0.11.1 → 0.11.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.
Files changed (2) hide show
  1. package/dist/index.js +17 -8
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -217,7 +217,7 @@ function truncate(input, max) {
217
217
  return text.length > max ? `${text.slice(0, max)}...` : text;
218
218
  }
219
219
  function sanitizeQuery(raw) {
220
- return raw.replace(/```[\s\S]*?```/g, " ").replace(/`[^`]*`/g, " ").replace(/[#*_[\]()>|]/g, " ").replace(/[\r\n\t]+/g, " ").replace(/\s+/g, " ").trim().slice(0, GH_QUERY_MAX);
220
+ return raw.replace(/```[\s\S]*?```/g, " ").replace(/`[^`]*`/g, " ").replace(/https?:\/\/\S+/g, " ").replace(/[^\p{L}\p{N}\s]/gu, " ").replace(/\b(NOT|AND|OR)\b/gi, " ").replace(/\s+/g, " ").trim().slice(0, GH_QUERY_MAX);
221
221
  }
222
222
  function effectiveFrameworks(frameworks, keyDeps) {
223
223
  const set = new Set((frameworks || []).filter(Boolean));
@@ -249,13 +249,15 @@ async function tier1OfficialDocs(query, fws, results, docRefs, seen, signal) {
249
249
  if (entry) docRefs.push({ name: entry.name, url: entry.docs });
250
250
  }
251
251
  if (!query) return errors;
252
+ const cleanQuery = sanitizeQuery(query);
253
+ if (!cleanQuery) return errors;
252
254
  for (const fw of fws) {
253
255
  if (signal.aborted || results.length >= TARGET_RESULT_COUNT) break;
254
256
  const entry = FRAMEWORK_DOCS[fw];
255
257
  if (!entry?.githubOrg) continue;
256
258
  try {
257
- const q = `${query} org:${entry.githubOrg}`;
258
- const url = `https://api.github.com/search/issues?q=${encodeURIComponent(sanitizeQuery(q))}&per_page=3`;
259
+ const fullQ = `${cleanQuery} org:${entry.githubOrg}`;
260
+ const url = `https://api.github.com/search/issues?q=${encodeURIComponent(fullQ)}&per_page=3`;
259
261
  const data = await ghFetch(url, signal);
260
262
  for (const item of data.items ?? []) {
261
263
  pushResult(results, seen, {
@@ -276,7 +278,9 @@ async function tier1OfficialDocs(query, fws, results, docRefs, seen, signal) {
276
278
  async function tier2GitHubIssues(query, results, seen, signal) {
277
279
  const errors = [];
278
280
  try {
279
- const url = `https://api.github.com/search/issues?q=${encodeURIComponent(sanitizeQuery(query))}&per_page=5`;
281
+ const q = sanitizeQuery(query);
282
+ if (!q) return errors;
283
+ const url = `https://api.github.com/search/issues?q=${encodeURIComponent(q)}&per_page=5`;
280
284
  const data = await ghFetch(url, signal);
281
285
  for (const item of data.items ?? []) {
282
286
  pushResult(results, seen, {
@@ -297,7 +301,9 @@ async function tier3GitHubCode(query, results, seen, signal) {
297
301
  const errors = [];
298
302
  if (!ghToken()) return errors;
299
303
  try {
300
- const url = `https://api.github.com/search/code?q=${encodeURIComponent(sanitizeQuery(query))}&per_page=3`;
304
+ const q = sanitizeQuery(query);
305
+ if (!q) return errors;
306
+ const url = `https://api.github.com/search/code?q=${encodeURIComponent(q)}&per_page=3`;
301
307
  const data = await ghFetch(url, signal);
302
308
  for (const item of data.items ?? []) {
303
309
  const repo = item.repository?.full_name;
@@ -1613,6 +1619,7 @@ PATH A \u2014 INDEPENDENT (parallel via generate_batch):
1613
1619
  4. for each i: PASS -> task_update(i, title, "completed", "PASS"); FAIL -> revise (up to 2x) or task_update(i, title, "failed", "FAIL")
1614
1620
 
1615
1621
  PATH B \u2014 DEPENDENT (sequential):
1622
+ Optional: task_update(1..N, title, "pending") \u2190 pre-register all tasks first
1616
1623
  for i in 1..${args.total}:
1617
1624
  1. task_update(i, title, "generating")
1618
1625
  2. generate({prompt:"Task: <title>. Perform it."}) -> work + NEXT
@@ -1795,21 +1802,23 @@ Then: harness_done(). Follow the [usage-coach NEXT] directive each tool returns.
1795
1802
  args: {
1796
1803
  id: tool.schema.number(),
1797
1804
  title: tool.schema.string(),
1798
- status: tool.schema.string().describe("generating | grading | revising | completed | failed | timed_out"),
1805
+ status: tool.schema.string().describe("pending | generating | grading | revising | completed | failed | timed_out"),
1799
1806
  revisions: tool.schema.number().optional(),
1800
1807
  score: tool.schema.string().optional().describe("PASS | FAIL"),
1801
1808
  model: tool.schema.string().optional()
1802
1809
  },
1803
1810
  async execute(args, ctx) {
1811
+ const VALID_STATUSES = ["pending", "generating", "grading", "revising", "completed", "failed", "timed_out", "halted_quota"];
1812
+ const status = args.status && VALID_STATUSES.includes(args.status) ? args.status : "generating";
1804
1813
  const cfg = readHarnessCfg(ctx.directory);
1805
1814
  const h = readHarness(ctx.sessionID) ?? { name: "batch", total: 0, current: 0, tasks: [], usage: {}, active: true };
1806
1815
  h.tasks = h.tasks.filter((x) => x.id !== args.id);
1807
1816
  const model = args.model || cfg.generator || "";
1808
1817
  if (!model) return `ERROR: task ${args.id} has no model and no generator configured. Set "generator" in harness.config.json.`;
1809
- h.tasks.push({ id: args.id, title: args.title, status: args.status, model, revisions: args.revisions ?? 0, score: args.score ?? null, startedAt: (/* @__PURE__ */ new Date()).toISOString() });
1818
+ h.tasks.push({ id: args.id, title: args.title, status, model, revisions: args.revisions ?? 0, score: args.score ?? null, startedAt: (/* @__PURE__ */ new Date()).toISOString() });
1810
1819
  if (args.id > h.current) h.current = args.id;
1811
1820
  writeHarness(ctx.sessionID, h);
1812
- return `task ${args.id} -> ${args.status}${args.score ? ` (${args.score})` : ""}`;
1821
+ return `task ${args.id} -> ${status}${args.score ? ` (${args.score})` : ""}`;
1813
1822
  }
1814
1823
  }),
1815
1824
  harness_done: tool({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-usage-coach",
3
- "version": "0.11.1",
3
+ "version": "0.11.3",
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",