thincoder 0.12.7 → 0.12.8

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 CHANGED
@@ -209,6 +209,9 @@ Code conventions: pure `.mjs`, no semicolons, no npm dependencies allowed (inclu
209
209
 
210
210
  ## Changelog
211
211
 
212
+ ### 0.12.8 (2026-08)
213
+ - **Fix: pending-task pushback fires at most once** — the completion guard that reminds the model to update pending tasks before finishing could loop forever when a pending item could not be resolved. Now each task-list state earns exactly one reminder; if the model insists on finishing anyway, it is allowed to (updating the list via the task tool resets the budget). VS Code extension synced.
214
+
212
215
  ### 0.12.7 (2026-08)
213
216
  - **Fix: long replies and thinking are never folded** — the long-message folding feature (0.12.6) collapsed main output and reasoning behind a click when they exceeded 12 lines, hurting readability. Folding now applies to secondary dim-colored content (tool summaries/status) only; expanded blocks are exempt from the consecutive-dim folding so nothing folds twice.
214
217
  - **Fix: wide tables misaligned in narrow terminals** — a many-column table that still exceeded the terminal width after column shrinking (e.g. 8 columns at 40 cols) wrapped at the terminal and misaligned. Table rows are now clipped with an ellipsis instead of ever exceeding the width.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "thincoder",
3
- "version": "0.12.7",
3
+ "version": "0.12.8",
4
4
  "description": "Thin coding agent - zero dependencies, no build step, Node.js native. Sharp code, zero bloat.",
5
5
  "keywords": [
6
6
  "ai",
@@ -54,13 +54,18 @@ export function handleCompletion(agent, response, depth, turn, guardPushbacks, h
54
54
  )
55
55
  }
56
56
 
57
- // Pending tasks: remind the model before it declares itself done
58
- if (depth === 0 && agent.tasks.some((t) => t.status === "pending")) {
57
+ // Pending tasks: remind the model ONCE before it declares itself done.
58
+ // Deliberately capped at one pushback (reported pain: unbounded looping when a
59
+ // pending item can't be resolved). After the single reminder the model is free
60
+ // to finish — updating the task list (task tool) resets the budget, so a fresh
61
+ // list state earns one fresh reminder.
62
+ if (depth === 0 && agent.tasks.some((t) => t.status === "pending") && (agent._taskPushbacks ?? 0) < 1) {
63
+ agent._taskPushbacks = (agent._taskPushbacks ?? 0) + 1
59
64
  const pending = agent.tasks.filter((t) => t.status === "pending").map((t) => t.title).join(", ")
60
65
  pushReal(agent, { role: "assistant", content: response.content })
61
66
  agent.history.push({
62
67
  role: "user",
63
- content: `[System reminder: you still have pending tasks: ${pending}. Update their status with the task tool before finishing — if they're done, mark them done; if they're not applicable, remove them.]`,
68
+ content: `[System reminder: you still have pending tasks: ${pending}. Update their status with the task tool before finishing — if they're done, mark them done; if they're not applicable, remove them. (This is your only reminder — if you choose not to, finish anyway.)]`,
64
69
  })
65
70
  callbacks.onTurnEnd?.(agent, turn)
66
71
  return { action: "continue", guardPushbacks, honestReminderInjected, advisorPushbacks }
@@ -77,6 +77,7 @@ export const taskTool = {
77
77
  const recentDone = raw.filter((t) => t.status === "done").slice(-3)
78
78
  const items = [...pending, ...recentDone].slice(0, 20)
79
79
  ctx.agent.tasks = items
80
+ ctx.agent._taskPushbacks = 0 // task list changed — the completion gate earns a fresh reminder
80
81
  ctx.agent._onTaskUpdate?.(items)
81
82
  const done = items.filter((i) => i.status === "done").length
82
83
  const open = items.length - done