teapot-coding-agent 0.37.48 → 0.37.50

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.
@@ -74,13 +74,6 @@ export const PROGRESS_REQUEST =
74
74
  // and every requested report appeared TWICE on the timeline
75
75
  "Record it with the report_progress TOOL (doing, goalStatus, recent, problems, next) — " +
76
76
  "call that tool; do NOT answer in prose, which would just duplicate this request.";
77
- /**
78
- * SYSTEM_TEMPLATE must stay byte-identical across every request of a session:
79
- * provider prefix caches key on it, so changing it (or injecting per-turn
80
- * state) re-prices the whole context. That is why session state lives behind
81
- * meta tools instead. The cache rationale itself stays HERE in a comment —
82
- * the model does not need our cost-engineering notes every turn.
83
- */
84
77
  /**
85
78
  * Recent context kept VERBATIM through a compaction, in tokens.
86
79
  *
@@ -235,6 +228,13 @@ const SUMMARY_CLOSE = "\n</conversation_checkpoint>";
235
228
  * claim, and must not be able to change what it is judging.
236
229
  */
237
230
  const AUDIT_READ_ONLY_TOOLS = new Set(["read_file", "list_dir", "grep", "bash"]);
231
+ /**
232
+ * SYSTEM_TEMPLATE must stay byte-identical across every request of a session:
233
+ * provider prefix caches key on it, so changing it (or injecting per-turn
234
+ * state) re-prices the whole context. That is why session state lives behind
235
+ * meta tools instead. The cache rationale itself stays HERE in a comment —
236
+ * the model does not need our cost-engineering notes every turn.
237
+ */
238
238
  const SYSTEM_TEMPLATE = `You are a coding agent working autonomously inside a workspace.
239
239
 
240
240
  Most session state is not injected into prompts — fetch it with tools instead:
@@ -665,31 +665,14 @@ export class Agent {
665
665
  * are exempt — those are not "keep trying", they are "the operator/provider asked".
666
666
  */
667
667
  consecutiveCompactFailures = 0;
668
- /**
669
- * Rescan skill roots — but only when something actually changed.
670
- * This used to run a readdir per root plus a read of every SKILL.md at the
671
- * top of EVERY turn; the cache is only ever read by list_skills, so that
672
- * was pure I/O on the hot path. A cheap stat fingerprint of the roots and
673
- * their SKILL.md files gates the real scan, so a turn only pays when a
674
- * skill was added, edited or removed (save_skill writes one, so a
675
- * self-created skill still shows up on the very next turn).
676
- */
677
- /**
678
- * Render the skill catalogue for the system prompt.
679
- *
680
- * Name + description only, one line each — the full SKILL.md is what
681
- * load_skill() is for, and this block goes into EVERY request of the session,
682
- * so it has to stay small. The description is what the model matches its task
683
- * against, so a skill with a poor description is effectively undiscoverable;
684
- * that is worth knowing when authoring one.
685
- */
686
668
  /**
687
669
  * A bounded DIGEST of memory.md: every heading, plus its first line.
688
670
  *
689
- * they are genuinely long — 2.6KB is the median, and the largest hold full project briefs. A
690
- * model that never sees them cannot decide to consult them: that is the whole finding of #48
691
- * (182 writes, 13 reads after a write). A model that sees the WHOLE file pays for it on every
692
- * request and breaks the prefix cache.
671
+ * Memory notes are worth this much because they are what a later session reads instead of
672
+ * re-learning the workspace: they are genuinely long — 2.6KB is the median, and the largest hold
673
+ * full project briefs. A model that never sees them cannot decide to consult them: that is the
674
+ * whole finding of #48 (182 writes, 13 reads after a write). A model that sees the WHOLE file
675
+ * pays for it on every request and breaks the prefix cache.
693
676
  *
694
677
  * Codex solves this with a `MEMORY_SUMMARY` in the prompt plus a searchable registry on disk.
695
678
  * This is the same shape: the digest says what memory HOLDS, `read_memory(query)` fetches the
@@ -977,6 +960,11 @@ export class Agent {
977
960
  this.parkedByTool ||
978
961
  this.compactPhase !== "");
979
962
  }
963
+ /** recently read workspace files (most recent first) — post-compact restore */
964
+ recentReads = [];
965
+ trackFileRead(p) {
966
+ this.recentReads = [p, ...this.recentReads.filter((x) => x !== p)].slice(0, 5);
967
+ }
980
968
  /**
981
969
  * A background shell (bash background=true) finished. Two channels:
982
970
  * 1. a system_note row in the timeline — the operator sees the outcome
@@ -985,11 +973,6 @@ export class Agent {
985
973
  * agent learns exit code + output tail WITHOUT having to poll
986
974
  * bash_output blindly. Failed jobs say so loudly so the model reacts.
987
975
  */
988
- /** recently read workspace files (most recent first) — post-compact restore */
989
- recentReads = [];
990
- trackFileRead(p) {
991
- this.recentReads = [p, ...this.recentReads.filter((x) => x !== p)].slice(0, 5);
992
- }
993
976
  onBackgroundJobExit(info) {
994
977
  const ok = info.code === 0;
995
978
  const one = info.cmd.replace(/\s+/g, " ").slice(0, 80);
@@ -4592,7 +4575,6 @@ export class Agent {
4592
4575
  bus.emit("update", { kind: "compaction-progress", agentId: this.opts.id, phase: "done" });
4593
4576
  }
4594
4577
  }
4595
- /** Ask the model for dense continuation notes over the compacted range. */
4596
4578
  /**
4597
4579
  * Summarize `old` into continuation notes.
4598
4580
  *
package/dist/master.js CHANGED
@@ -19,7 +19,6 @@ import { bus } from "./bus.js";
19
19
  import { mcp } from "./agent/mcp-registry.js";
20
20
  import { loadPlugins } from "./agent/plugins.js";
21
21
  import { fetchModelList, peekModelList, contextLengthFor, isReasoningEffort, } from "./model-meta.js";
22
- /** how deep sub-agent spawning may nest (parent=0, its subs=1, …) */
23
22
  /**
24
23
  * Did the effective data dir come from an ENV OVERRIDE that disagrees with the
25
24
  * config file's own `dataDir`?
@@ -282,7 +281,6 @@ export function loadConfig(configPath) {
282
281
  providers: Object.fromEntries(Object.entries(user.providers ?? {}).map(([name, p]) => [name, migrateProviderKeys(p)])),
283
282
  };
284
283
  }
285
- /** Raw parsed user config (for lossless persistence of web edits). */
286
284
  /**
287
285
  * Can this path be replaced by an atomic rename?
288
286
  *
@@ -587,7 +585,6 @@ export class Master {
587
585
  this.configDirty = false;
588
586
  this.saveConfig();
589
587
  }
590
- /** write-and-rename, so config.json is never observed empty or half-written */
591
588
  /**
592
589
  * The shared pool for a provider, created on first use.
593
590
  *
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "teapot-coding-agent",
3
- "version": "0.37.48",
3
+ "version": "0.37.50",
4
4
  "description": "A lightweight, always-on multi-agent harness for AI coding agents",
5
5
  "type": "module",
6
6
  "license": "AGPL-3.0-or-later",
@@ -37,6 +37,8 @@
37
37
  "typecheck-web": "tsc -p tsconfig.frontend.json",
38
38
  "typecheck:scripts": "tsc -p tsconfig.scripts.json",
39
39
  "lint": "oxlint src frontend test scripts",
40
+ "lint:comments": "node scripts/find-stacked-comments.ts",
41
+ "lint:comments:strict": "node scripts/find-stacked-comments.ts --strict",
40
42
  "start": "node dist/index.js",
41
43
  "dev": "node src/index.ts",
42
44
  "dev-web": "vite",