teapot-coding-agent 0.14.6 → 0.14.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/dist/agent/agent.js +100 -8
- package/package.json +1 -1
- package/public/assets/index-CNYEpUp6.js +28 -0
- package/public/assets/index-CNYEpUp6.js.map +1 -0
- package/public/assets/{shiki-BLFDwcS0.js → shiki-B972ox6D.js} +2 -2
- package/public/assets/{shiki-BLFDwcS0.js.map → shiki-B972ox6D.js.map} +1 -1
- package/public/index.html +1 -1
- package/public/assets/index-BjELe1k2.js +0 -28
- package/public/assets/index-BjELe1k2.js.map +0 -1
package/dist/agent/agent.js
CHANGED
|
@@ -493,6 +493,54 @@ export class Agent {
|
|
|
493
493
|
await fs.writeFile(this.todoFile, text, "utf8");
|
|
494
494
|
await this.log.append("todo", this.currentSession, this.currentBranch, { event: "set", by });
|
|
495
495
|
}
|
|
496
|
+
/**
|
|
497
|
+
* Update SPECIFIC checkbox items without rewriting the whole list — the
|
|
498
|
+
* full-replacement path made agents lazy (a mid-task progress tick meant
|
|
499
|
+
* re-emitting the entire markdown, so they skipped updates) and risky (one
|
|
500
|
+
* sloppy regeneration mangled unrelated sections). Items are matched by
|
|
501
|
+
* normalized text; unknown items are reported back instead of silently
|
|
502
|
+
* dropped. Returns a short human-readable summary for the tool result.
|
|
503
|
+
*/
|
|
504
|
+
async updateTodoItems(updates, by = "agent") {
|
|
505
|
+
const norm = (s) => s.replace(/\s+/g, " ").trim().toLowerCase();
|
|
506
|
+
const lines = this.todo.split("\n");
|
|
507
|
+
let matched = 0;
|
|
508
|
+
const unmatched = [];
|
|
509
|
+
for (const u of updates) {
|
|
510
|
+
const target = norm(u.item);
|
|
511
|
+
// find the LAST matching checkbox line (later duplicates win)
|
|
512
|
+
let idx = -1;
|
|
513
|
+
for (let i = lines.length - 1; i >= 0; i--) {
|
|
514
|
+
const m = lines[i].match(/^(\s*[-*+] \[)([ xX])(\].*)$/);
|
|
515
|
+
if (!m)
|
|
516
|
+
continue;
|
|
517
|
+
if (norm(m[3].slice(1)) === target) {
|
|
518
|
+
idx = i;
|
|
519
|
+
break;
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
if (idx === -1) {
|
|
523
|
+
unmatched.push(u.item);
|
|
524
|
+
continue;
|
|
525
|
+
}
|
|
526
|
+
lines[idx] = lines[idx].replace(/^(.* \[)[ xX](\].*)$/, (_s, a, b) => `${a}${u.done ? "x" : " "}${b}`);
|
|
527
|
+
matched++;
|
|
528
|
+
}
|
|
529
|
+
if (matched > 0) {
|
|
530
|
+
this.todo = lines.join("\n");
|
|
531
|
+
await fs.writeFile(this.todoFile, this.todo, "utf8");
|
|
532
|
+
await this.log.append("todo", this.currentSession, this.currentBranch, {
|
|
533
|
+
event: "items",
|
|
534
|
+
by,
|
|
535
|
+
matched,
|
|
536
|
+
...(unmatched.length ? { unknown: unmatched } : {}),
|
|
537
|
+
});
|
|
538
|
+
}
|
|
539
|
+
const parts = [`${matched} item(s) updated`];
|
|
540
|
+
if (unmatched.length)
|
|
541
|
+
parts.push(`NOT FOUND in todo.md: ${unmatched.map((s) => `"${s}"`).join(", ")} — check get_todo and retry with the exact wording`);
|
|
542
|
+
return parts.join(". ");
|
|
543
|
+
}
|
|
496
544
|
async setGoalStatus(status) {
|
|
497
545
|
this.goal = { ...this.goal, status, updatedAt: new Date().toISOString() };
|
|
498
546
|
await this.writeGoalFile();
|
|
@@ -595,15 +643,22 @@ export class Agent {
|
|
|
595
643
|
});
|
|
596
644
|
}
|
|
597
645
|
setStatus(s, reason = "") {
|
|
598
|
-
|
|
646
|
+
// Update the field FIRST. log.append fires onEvent synchronously, and the
|
|
647
|
+
// master's child-event hook wakes parked wait_children callers — those
|
|
648
|
+
// re-check agent.status at that instant. Updating after the append made
|
|
649
|
+
// every waiter observe the OLD status ("running"), conclude "someone is
|
|
650
|
+
// still working", and stay parked until timeout even though the child had
|
|
651
|
+
// just settled.
|
|
652
|
+
const prev = this.status;
|
|
653
|
+
this.status = s;
|
|
654
|
+
this.statusReason = reason;
|
|
655
|
+
if (prev !== s) {
|
|
599
656
|
void this.log.append("state", this.currentSession, this.currentBranch, {
|
|
600
|
-
from:
|
|
657
|
+
from: prev,
|
|
601
658
|
to: s,
|
|
602
659
|
reason,
|
|
603
660
|
});
|
|
604
661
|
}
|
|
605
|
-
this.status = s;
|
|
606
|
-
this.statusReason = reason;
|
|
607
662
|
bus.emit("update", { kind: "agent-update", agentId: this.opts.id });
|
|
608
663
|
}
|
|
609
664
|
/** Main auto-run loop: turn -> tools -> turn ... -> done/idle/stop. */
|
|
@@ -849,9 +904,28 @@ export class Agent {
|
|
|
849
904
|
}
|
|
850
905
|
if (call.function.name === "set_todo") {
|
|
851
906
|
const a = safeParse(call.function.arguments);
|
|
907
|
+
// Preferred: surgical checkbox updates — no full rewrite, no risk
|
|
908
|
+
// of mangling unrelated sections, cheap enough to do mid-task.
|
|
909
|
+
const updates = Array.isArray(a.updates)
|
|
910
|
+
? a.updates
|
|
911
|
+
.map((u) => {
|
|
912
|
+
const o = (u ?? {});
|
|
913
|
+
return { item: String(o.item ?? ""), done: o.done !== false };
|
|
914
|
+
})
|
|
915
|
+
.filter((u) => u.item.trim())
|
|
916
|
+
: [];
|
|
917
|
+
if (updates.length > 0) {
|
|
918
|
+
const note = await this.updateTodoItems(updates, "agent");
|
|
919
|
+
await this.answerMeta(call, `${note} (visible to the operator)`);
|
|
920
|
+
continue;
|
|
921
|
+
}
|
|
852
922
|
const content = String(a.content ?? "").slice(0, 32_000);
|
|
923
|
+
if (!content.trim()) {
|
|
924
|
+
await this.answerMeta(call, "nothing to do: pass updates:[{item,done}] to check items off, or content to replace the whole list");
|
|
925
|
+
continue;
|
|
926
|
+
}
|
|
853
927
|
await this.setTodo(content, "agent");
|
|
854
|
-
await this.answerMeta(call, "task list
|
|
928
|
+
await this.answerMeta(call, "task list replaced (visible to the operator)");
|
|
855
929
|
continue;
|
|
856
930
|
}
|
|
857
931
|
if (call.function.name === "get_feedback") {
|
|
@@ -1443,11 +1517,29 @@ function allToolSpecs() {
|
|
|
1443
1517
|
type: "function",
|
|
1444
1518
|
function: {
|
|
1445
1519
|
name: "set_todo",
|
|
1446
|
-
description: "
|
|
1520
|
+
description: "Update the operator-visible task list (todo.md). PREFERRED: pass updates to check specific " +
|
|
1521
|
+
"items off as you finish them — cheap, surgical, no risk of mangling other sections. Only pass " +
|
|
1522
|
+
"content to rewrite the whole list when restructuring it. Call this promptly on every item you complete.",
|
|
1447
1523
|
parameters: {
|
|
1448
1524
|
type: "object",
|
|
1449
|
-
properties: {
|
|
1450
|
-
|
|
1525
|
+
properties: {
|
|
1526
|
+
updates: {
|
|
1527
|
+
type: "array",
|
|
1528
|
+
description: "surgical checkbox flips — match items by their exact text in todo.md",
|
|
1529
|
+
items: {
|
|
1530
|
+
type: "object",
|
|
1531
|
+
properties: {
|
|
1532
|
+
item: { type: "string", description: "checkbox item text (without the \"- [ ]\" marker)" },
|
|
1533
|
+
done: { type: "boolean", description: "true = check off, false = reopen (default true)" },
|
|
1534
|
+
},
|
|
1535
|
+
required: ["item"],
|
|
1536
|
+
},
|
|
1537
|
+
},
|
|
1538
|
+
content: {
|
|
1539
|
+
type: "string",
|
|
1540
|
+
description: "full replacement markdown — only for restructures; prefer updates",
|
|
1541
|
+
},
|
|
1542
|
+
},
|
|
1451
1543
|
},
|
|
1452
1544
|
},
|
|
1453
1545
|
},
|