@shanepadgett/tau-agent 0.39.0 → 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
  }
@@ -11,6 +11,10 @@ Press `Ctrl+F` in the picker to fetch all configured remotes and refresh the
11
11
  open list. Selecting a remote branch creates a local branch that tracks it.
12
12
  Cancelling the picker does not switch branches.
13
13
 
14
+ After you pick a branch, Tau asks you to confirm. On confirm it switches, then
15
+ runs `git clean -fd` so untracked files and folders left from other branches
16
+ are removed. Ignored files such as `.env` stay.
17
+
14
18
  Run `/branch new`, choose `feature`, `fix`, or `chore`, then enter a branch
15
19
  name. The name is lowercased, punctuation and whitespace become hyphens, and
16
20
  leading or trailing hyphens are removed.
@@ -18,5 +22,5 @@ leading or trailing hyphens are removed.
18
22
  For example, selecting `fix` and entering `Fix login. Please` creates and
19
23
  switches to `fix/fix-login-please`.
20
24
 
21
- Cancelling either creation prompt creates nothing. Uncommitted changes follow
22
- normal `git switch` behavior for both switching and creation.
25
+ Cancelling either creation prompt creates nothing. Uncommitted tracked changes
26
+ follow normal `git switch` behavior for both switching and creation.
@@ -99,8 +99,15 @@ async function chooseBranch(git: GitRunner, ctx: ExtensionCommandContext): Promi
99
99
  });
100
100
  if (!choice) return;
101
101
 
102
+ const confirmed = await ctx.ui.confirm(
103
+ `Switch to ${choice.name}?`,
104
+ "After switch, untracked files and folders will be removed. Ignored files like .env stay.",
105
+ );
106
+ if (!confirmed) return;
107
+
102
108
  if (choice.kind === "local") await git.run(["switch", choice.name], { cwd: root });
103
109
  else await git.run(["switch", "--track", "-c", choice.name, choice.upstream], { cwd: root });
110
+ await git.run(["clean", "-fd"], { cwd: root });
104
111
  ctx.ui.notify(`Switched to ${choice.name}.`, "info");
105
112
  }
106
113
 
@@ -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(
@@ -24,7 +24,9 @@ Uses Pi's native compaction before a model turn when the current context reaches
24
24
 
25
25
  ## branch
26
26
 
27
- Adds `/branch` to create and switch Git branches from the TUI.
27
+ Adds `/branch` to create and switch Git branches from the TUI. Switching
28
+ confirms first, then removes untracked files with `git clean -fd` while keeping
29
+ ignored files. Press `Ctrl+F` in the picker to fetch remotes and refresh.
28
30
 
29
31
  ## cache-diagnostics
30
32
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shanepadgett/tau-agent",
3
- "version": "0.39.0",
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.0",
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;