@shanepadgett/tau-agent 0.39.1 → 0.39.2

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.
@@ -6,4 +6,4 @@ Set `extensions.autoCompact.tokenLimit` to change the limit. It defaults to 175,
6
6
 
7
7
  After changing this extension, run `/reload` before testing it.
8
8
 
9
- Automatic compaction holds attention notifications while it runs and while the hidden continuation resumes the interrupted work. The notification is released only after that resumed work settles.
9
+ Automatic compaction holds attention notifications while it runs and while the hidden continuation resumes the interrupted work. The notification is released only after that resumed work settles. It also pauses silent post-edit checks across the compact so they do not run on incomplete work.
@@ -14,6 +14,7 @@ export default function autoCompactExtension(pi: ExtensionAPI): void {
14
14
  let sessionVersion = 0;
15
15
  let attentionHoldSequence = 0;
16
16
  let attentionHoldId: string | undefined;
17
+ let silentCheckPauseId: string | undefined;
17
18
  let continuationPending = false;
18
19
 
19
20
  function releaseAttentionHold(disposition: "notify" | "discard"): void {
@@ -22,6 +23,18 @@ export default function autoCompactExtension(pi: ExtensionAPI): void {
22
23
  if (holdId) emitTauEvent(pi, "tau:attention.hold.release", { id: holdId, disposition });
23
24
  }
24
25
 
26
+ function pauseSilentChecks(): void {
27
+ if (silentCheckPauseId) return;
28
+ silentCheckPauseId = `auto-compact:${++attentionHoldSequence}`;
29
+ emitTauEvent(pi, "tau:silent-command-runner.pause", { id: silentCheckPauseId });
30
+ }
31
+
32
+ function resumeSilentChecks(disposition: "continue" | "settle"): void {
33
+ const pauseId = silentCheckPauseId;
34
+ silentCheckPauseId = undefined;
35
+ if (pauseId) emitTauEvent(pi, "tau:silent-command-runner.resume", { id: pauseId, disposition });
36
+ }
37
+
25
38
  pi.on("session_start", async (_event, ctx) => {
26
39
  const version = ++sessionVersion;
27
40
  const settings = await loadTauExtensionSettings(ctx, autoCompactSettings);
@@ -31,6 +44,7 @@ export default function autoCompactExtension(pi: ExtensionAPI): void {
31
44
  compacting = false;
32
45
  attentionHoldSequence = 0;
33
46
  attentionHoldId = undefined;
47
+ silentCheckPauseId = undefined;
34
48
  continuationPending = false;
35
49
  });
36
50
  pi.on("session_shutdown", () => {
@@ -38,6 +52,7 @@ export default function autoCompactExtension(pi: ExtensionAPI): void {
38
52
  armed = true;
39
53
  compacting = false;
40
54
  attentionHoldId = undefined;
55
+ silentCheckPauseId = undefined;
41
56
  continuationPending = false;
42
57
  });
43
58
  pi.on("session_tree", () => {
@@ -64,6 +79,8 @@ export default function autoCompactExtension(pi: ExtensionAPI): void {
64
79
 
65
80
  armed = false;
66
81
  compacting = true;
82
+ // Pause before compact: compact aborts the agent, and that agent_end must not run checks.
83
+ pauseSilentChecks();
67
84
  if (ctx.mode !== "print") {
68
85
  attentionHoldId = `auto-compact:${++attentionHoldSequence}`;
69
86
  emitTauEvent(pi, "tau:attention.hold.acquire", { id: attentionHoldId });
@@ -72,6 +89,8 @@ export default function autoCompactExtension(pi: ExtensionAPI): void {
72
89
  const continueWork = (): void => {
73
90
  if (version !== sessionVersion) return;
74
91
  compacting = false;
92
+ // Keep the silent-check baseline across the new agent run started below.
93
+ resumeSilentChecks("continue");
75
94
  continuationPending = true;
76
95
  pi.sendMessage(
77
96
  {
@@ -90,6 +109,7 @@ export default function autoCompactExtension(pi: ExtensionAPI): void {
90
109
  if (version !== sessionVersion) return;
91
110
  compacting = false;
92
111
  if (error.name === "AbortError" || error.message === "Compaction cancelled") {
112
+ resumeSilentChecks("settle");
93
113
  releaseAttentionHold("notify");
94
114
  return;
95
115
  }
@@ -23,3 +23,5 @@ Configure it in Tau settings under `extensions.silentCommandRunner`:
23
23
  ```
24
24
 
25
25
  Passes are notifications only. Failures are shown in chat and sent to the agent. Tau's ready-for-input notification waits for these checks and stays quiet when a failure starts another agent turn.
26
+
27
+ When auto-compact pauses a long run to compact context, checks wait until that work chain finishes. They do not run on the compact abort, and file changes from before the compact still count.
@@ -2,7 +2,7 @@ import { readdir, stat } from "node:fs/promises";
2
2
  import { resolve } from "node:path";
3
3
  import { type ExecResult, type ExtensionAPI, keyText, type Theme } from "@earendil-works/pi-coding-agent";
4
4
  import { Box, Text } from "@earendil-works/pi-tui";
5
- import { emitTauEvent } from "../../shared/events.ts";
5
+ import { emitTauEvent, onTauEvent } from "../../shared/events.ts";
6
6
  import { matchGlob, posixPath } from "../../shared/glob.ts";
7
7
  import { loadTauExtensionSettings } from "../../shared/settings/load.ts";
8
8
  import { resolveProjectRoot } from "../../shared/settings/paths.ts";
@@ -84,11 +84,40 @@ export default function silentCommandRunnerExtension(pi: ExtensionAPI): void {
84
84
  let chainActive = false;
85
85
  let attentionHoldSequence = 0;
86
86
  let attentionHoldId: string | undefined;
87
+ const checkPauses = new Set<string>();
88
+ let settleDeferred = false;
89
+
90
+ function checksPaused(): boolean {
91
+ return checkPauses.size > 0;
92
+ }
93
+
94
+ function finalizeChain(): void {
95
+ settleDeferred = false;
96
+ chainActive = false;
97
+ const holdId = attentionHoldId;
98
+ attentionHoldId = undefined;
99
+ if (holdId) emitTauEvent(pi, "tau:attention.hold.release", { id: holdId, disposition: "notify" });
100
+ }
87
101
 
88
102
  pi.registerMessageRenderer<FailureDetails>(MESSAGE_TYPE, (message, { expanded }, theme) =>
89
103
  renderFailure(asFailureDetails(message.details), expanded, theme),
90
104
  );
91
105
 
106
+ onTauEvent(pi, "silent-command-runner.pause", "tau:silent-command-runner.pause", ({ id }) => {
107
+ checkPauses.add(id);
108
+ });
109
+
110
+ onTauEvent(pi, "silent-command-runner.resume", "tau:silent-command-runner.resume", ({ id, disposition }) => {
111
+ checkPauses.delete(id);
112
+ if (checksPaused()) return;
113
+ if (disposition === "continue") {
114
+ // Compact will start a new agent run on the same work chain; keep baseline + hold.
115
+ settleDeferred = false;
116
+ return;
117
+ }
118
+ if (settleDeferred || chainActive) finalizeChain();
119
+ });
120
+
92
121
  pi.on("session_start", async (_event, ctx) => {
93
122
  settings = normalizeSettings(await loadTauExtensionSettings(ctx, silentCommandRunnerSettings));
94
123
  sessionActive = true;
@@ -97,6 +126,8 @@ export default function silentCommandRunnerExtension(pi: ExtensionAPI): void {
97
126
  chainActive = false;
98
127
  attentionHoldSequence = 0;
99
128
  attentionHoldId = undefined;
129
+ checkPauses.clear();
130
+ settleDeferred = false;
100
131
  });
101
132
 
102
133
  pi.on("before_agent_start", async (event, ctx) => {
@@ -108,20 +139,24 @@ export default function silentCommandRunnerExtension(pi: ExtensionAPI): void {
108
139
  pi.on("agent_start", async (_event, ctx) => {
109
140
  const startingChain = !chainActive;
110
141
  chainActive = true;
111
- turnStart = Date.now();
142
+ settleDeferred = false;
112
143
  if (!settings.enabled || settings.commands.length === 0) {
113
- turnPaths = new Set();
144
+ if (startingChain) {
145
+ turnStart = Date.now();
146
+ turnPaths = new Set();
147
+ }
114
148
  return;
115
149
  }
116
- if (startingChain) {
117
- attentionHoldId = `silent-command-runner:${++attentionHoldSequence}`;
118
- emitTauEvent(pi, "tau:attention.hold.acquire", { id: attentionHoldId });
119
- }
150
+ if (!startingChain) return;
151
+ attentionHoldId = `silent-command-runner:${++attentionHoldSequence}`;
152
+ emitTauEvent(pi, "tau:attention.hold.acquire", { id: attentionHoldId });
153
+ turnStart = Date.now();
120
154
  const projectRoot = await resolveProjectRoot(ctx.cwd);
121
155
  turnPaths = new Set(await walkFiles(projectRoot));
122
156
  });
123
157
 
124
158
  pi.on("agent_end", async (event, ctx) => {
159
+ if (checksPaused()) return;
125
160
  if (hasAbortedAssistantMessage(event.messages)) return;
126
161
  try {
127
162
  await runChangedCommands(ctx.cwd, turnStart, ctx.ui.notify);
@@ -131,10 +166,12 @@ export default function silentCommandRunnerExtension(pi: ExtensionAPI): void {
131
166
  });
132
167
 
133
168
  pi.on("agent_settled", () => {
134
- chainActive = false;
135
- const holdId = attentionHoldId;
136
- attentionHoldId = undefined;
137
- if (holdId) emitTauEvent(pi, "tau:attention.hold.release", { id: holdId, disposition: "notify" });
169
+ if (checksPaused()) {
170
+ // Compact aborted this run; keep chain + file baseline until resume.
171
+ settleDeferred = true;
172
+ return;
173
+ }
174
+ finalizeChain();
138
175
  });
139
176
 
140
177
  pi.on("session_shutdown", () => {
@@ -144,6 +181,8 @@ export default function silentCommandRunnerExtension(pi: ExtensionAPI): void {
144
181
  turnPaths = new Set();
145
182
  chainActive = false;
146
183
  attentionHoldId = undefined;
184
+ checkPauses.clear();
185
+ settleDeferred = false;
147
186
  });
148
187
 
149
188
  async function collectCommandFailures(
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shanepadgett/tau-agent",
3
- "version": "0.39.1",
3
+ "version": "0.39.2",
4
4
  "description": "Tau is a custom agentic harness built with pi extensions",
5
5
  "type": "module",
6
6
  "main": "./src/index.ts",
@@ -35,7 +35,7 @@
35
35
  ],
36
36
  "dependencies": {
37
37
  "@ast-grep/wasm": "0.45.1",
38
- "@shanepadgett/tau-tui": "0.39.1",
38
+ "@shanepadgett/tau-tui": "0.39.2",
39
39
  "@vscode/tree-sitter-wasm": "0.3.1",
40
40
  "image-size": "2.0.2",
41
41
  "smol-toml": "1.8.0",
package/shared/events.ts CHANGED
@@ -16,6 +16,15 @@ export type TauAgentEvents = {
16
16
  id: string;
17
17
  disposition: "notify" | "discard";
18
18
  };
19
+ /** Pause silent post-edit checks across a compact that will resume the same work chain. */
20
+ "tau:silent-command-runner.pause": {
21
+ id: string;
22
+ };
23
+ /** End a silent-check pause. continue keeps the chain open; settle finalizes a deferred settle. */
24
+ "tau:silent-command-runner.resume": {
25
+ id: string;
26
+ disposition: "continue" | "settle";
27
+ };
19
28
  "tau:file-mutation.applied": {
20
29
  source: "patch";
21
30
  toolCallId: string;