@shanepadgett/tau-agent 0.26.0 → 0.28.0
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/docs/subagents.md +1 -1
- package/extensions/appshot/README.md +1 -1
- package/extensions/appshot/index.ts +5 -11
- package/extensions/context/sync.ts +1 -9
- package/extensions/context-pruning/README.md +2 -2
- package/extensions/context-pruning/index.ts +58 -57
- package/extensions/context-pruning/prune.ts +2 -2
- package/extensions/context-pruning/render.ts +51 -39
- package/extensions/context-pruning/settings.ts +4 -5
- package/extensions/explore/README.md +13 -14
- package/extensions/explore/ast/adapter.ts +97 -0
- package/extensions/explore/ast/engine.ts +470 -0
- package/extensions/explore/ast/format/ast-search.ts +97 -0
- package/extensions/explore/ast/format/composite.ts +26 -0
- package/extensions/explore/ast/format/context.ts +66 -0
- package/extensions/explore/ast/format/deps.ts +86 -0
- package/extensions/explore/ast/format/discover.ts +85 -0
- package/extensions/explore/ast/format/impact.ts +105 -0
- package/extensions/explore/ast/format/outline.ts +66 -0
- package/extensions/explore/ast/format/relationships.ts +81 -0
- package/extensions/explore/ast/format/show.ts +38 -0
- package/extensions/explore/ast/grammars/kotlin.wasm +0 -0
- package/extensions/explore/ast/grammars/manifest.json +41 -0
- package/extensions/explore/ast/grammars/manifest.ts +99 -0
- package/extensions/explore/ast/grammars/odin.wasm +0 -0
- package/extensions/explore/ast/grammars/swift.wasm +0 -0
- package/extensions/explore/ast/graph/file-graph.ts +360 -0
- package/extensions/explore/ast/graph/relationships.ts +597 -0
- package/extensions/explore/ast/identity.ts +119 -0
- package/extensions/explore/ast/ir.ts +130 -0
- package/extensions/explore/ast/languages/csharp-file-deps.ts +189 -0
- package/extensions/explore/ast/languages/csharp.ts +493 -0
- package/extensions/explore/ast/languages/file-dep-util.ts +120 -0
- package/extensions/explore/ast/languages/fixtures/sample.cs +17 -0
- package/extensions/explore/ast/languages/fixtures/sample.java +21 -0
- package/extensions/explore/ast/languages/fixtures/sample.kt +15 -0
- package/extensions/explore/ast/languages/fixtures/sample.odin +28 -0
- package/extensions/explore/ast/languages/fixtures/sample.rs +31 -0
- package/extensions/explore/ast/languages/fixtures/sample.swift +25 -0
- package/extensions/explore/ast/languages/go-file-deps.ts +139 -0
- package/extensions/explore/ast/languages/go.ts +545 -0
- package/extensions/explore/ast/languages/java.ts +412 -0
- package/extensions/explore/ast/languages/jvm-file-deps.ts +217 -0
- package/extensions/explore/ast/languages/kotlin.ts +611 -0
- package/extensions/explore/ast/languages/odin-file-deps.ts +175 -0
- package/extensions/explore/ast/languages/odin.ts +407 -0
- package/extensions/explore/ast/languages/rust-file-deps.ts +159 -0
- package/extensions/explore/ast/languages/rust.ts +506 -0
- package/extensions/explore/ast/languages/swift-file-deps.ts +59 -0
- package/extensions/explore/ast/languages/swift.ts +466 -0
- package/extensions/explore/ast/languages/tree.ts +220 -0
- package/extensions/explore/ast/languages/typescript-file-deps.ts +259 -0
- package/extensions/explore/ast/languages/typescript-package-surface.ts +440 -0
- package/extensions/explore/ast/languages/typescript.ts +716 -0
- package/extensions/explore/ast/markdown.ts +145 -0
- package/extensions/explore/ast/package-surface.ts +42 -0
- package/extensions/explore/ast/queries/ast-search.ts +306 -0
- package/extensions/explore/ast/queries/composite-target.ts +77 -0
- package/extensions/explore/ast/queries/context.ts +406 -0
- package/extensions/explore/ast/queries/discover.ts +427 -0
- package/extensions/explore/ast/queries/impact.ts +250 -0
- package/extensions/explore/ast/queries/outline.ts +203 -0
- package/extensions/explore/ast/queries/show.ts +262 -0
- package/extensions/explore/ast/query.ts +48 -0
- package/extensions/explore/ast/read/hook.ts +125 -0
- package/extensions/explore/ast/read/policy.ts +55 -0
- package/extensions/explore/ast/registry.ts +120 -0
- package/extensions/explore/ast/scan.ts +76 -0
- package/extensions/explore/ast/slice.ts +31 -0
- package/extensions/explore/ast/tools/ast-search.ts +138 -0
- package/extensions/explore/ast/tools/context.ts +126 -0
- package/extensions/explore/ast/tools/deps.ts +72 -0
- package/extensions/explore/ast/tools/discover.ts +208 -0
- package/extensions/explore/ast/tools/impact.ts +135 -0
- package/extensions/explore/ast/tools/outline.ts +200 -0
- package/extensions/explore/ast/tools/relationships.ts +160 -0
- package/extensions/explore/ast/tools/render.ts +121 -0
- package/extensions/explore/ast/tools/reverse-deps.ts +72 -0
- package/extensions/explore/ast/tools/show.ts +116 -0
- package/extensions/explore/guidance.ts +52 -0
- package/extensions/explore/index.ts +91 -45
- package/extensions/explore/read/autoread.ts +118 -0
- package/extensions/explore/settings.ts +64 -0
- package/extensions/explore/traverse.ts +260 -86
- package/extensions/handoff/index.ts +1 -1
- package/extensions/patch/executor.ts +95 -1
- package/extensions/patch/index.ts +1 -0
- package/extensions/publish/index.ts +18 -85
- package/extensions/publish/publish-ui.ts +0 -4
- package/extensions/soul/README.md +7 -4
- package/extensions/soul/index.ts +11 -5
- package/extensions/soul/prompt.ts +30 -14
- package/extensions/soul/settings.ts +7 -2
- package/extensions/subagent/agents/context-sync.md +6 -10
- package/extensions/subagent/agents/review.md +44 -24
- package/extensions/subagent/agents/scout.md +53 -34
- package/extensions/subagent/run.ts +1 -1
- package/extensions/tau-help/help.md +2 -2
- package/package.json +6 -5
- package/schemas/tau.schema.json +51 -6
- package/{extensions/explore → shared}/autoread.ts +21 -7
- package/shared/bounded-text-result.ts +304 -0
- package/shared/events.ts +1 -0
- package/shared/full-file-knowledge.ts +49 -0
- package/shared/temporary-output-store.ts +275 -0
- package/extensions/explore/ast-tools.ts +0 -828
- package/extensions/explore/ast-worker.ts +0 -356
- package/extensions/explore/find.ts +0 -147
- package/extensions/explore/full-file-knowledge.ts +0 -234
- package/extensions/explore/grep.ts +0 -749
- package/extensions/explore/limits.ts +0 -22
- package/extensions/explore/ls.ts +0 -113
- package/extensions/explore/path-display.ts +0 -41
- package/extensions/explore/path-tree.ts +0 -150
- package/extensions/explore/read-cache.ts +0 -273
- package/extensions/explore/read-snapshots.ts +0 -57
- package/extensions/explore/read-stats-panel.ts +0 -154
- package/extensions/explore/read-stats.ts +0 -120
- package/extensions/explore/read.ts +0 -335
- package/extensions/explore/result.ts +0 -29
- package/native-bin/darwin-arm64/tau-ast +0 -0
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { access, mkdir, readFile, realpath, rmdir, stat, unlink, writeFile } from "node:fs/promises";
|
|
2
3
|
import { dirname, isAbsolute, relative, resolve } from "node:path";
|
|
3
4
|
import { withFileMutationQueue } from "@earendil-works/pi-coding-agent";
|
|
4
5
|
import { applyChunksWithRanges, countLogicalLines, UpdateChunkApplyError } from "./matcher.ts";
|
|
@@ -11,6 +12,7 @@ export interface ApplyPatchChange {
|
|
|
11
12
|
move?: { from: string; to: string };
|
|
12
13
|
linesAdded: number;
|
|
13
14
|
linesRemoved: number;
|
|
15
|
+
resultingFingerprint: string | null;
|
|
14
16
|
snapshotRanges?: Array<{ startLine: number; endLine: number }>;
|
|
15
17
|
}
|
|
16
18
|
|
|
@@ -32,6 +34,12 @@ export interface ApplyPatchStats {
|
|
|
32
34
|
completedOperations: number;
|
|
33
35
|
}
|
|
34
36
|
|
|
37
|
+
export interface ExactSourceMutation {
|
|
38
|
+
path: string;
|
|
39
|
+
expectedFingerprint: string;
|
|
40
|
+
source: string;
|
|
41
|
+
}
|
|
42
|
+
|
|
35
43
|
export function deriveStats(summary: ApplyPatchSummary): ApplyPatchStats {
|
|
36
44
|
const added: string[] = [];
|
|
37
45
|
const replaced: string[] = [];
|
|
@@ -80,6 +88,10 @@ function throwIfAborted(signal: AbortSignal | undefined): void {
|
|
|
80
88
|
if (signal?.aborted) throw new Error("Operation aborted");
|
|
81
89
|
}
|
|
82
90
|
|
|
91
|
+
function fingerprint(source: string): string {
|
|
92
|
+
return `sha256:${createHash("sha256").update(source, "utf8").digest("hex")}`;
|
|
93
|
+
}
|
|
94
|
+
|
|
83
95
|
async function pathExists(path: string): Promise<boolean> {
|
|
84
96
|
try {
|
|
85
97
|
await access(path);
|
|
@@ -136,6 +148,7 @@ async function stageWholeFile(
|
|
|
136
148
|
path: op.path,
|
|
137
149
|
linesAdded: op.linesAdded,
|
|
138
150
|
linesRemoved,
|
|
151
|
+
resultingFingerprint: fingerprint(op.content),
|
|
139
152
|
snapshotRanges: lineCount > 0 ? [{ startLine: 1, endLine: Math.min(lineCount, 120) }] : undefined,
|
|
140
153
|
},
|
|
141
154
|
async commit() {
|
|
@@ -156,6 +169,7 @@ async function stageDelete(cwd: string, op: Extract<PatchOperation, { type: "del
|
|
|
156
169
|
path: op.path,
|
|
157
170
|
linesAdded: 0,
|
|
158
171
|
linesRemoved: countLogicalLines(current),
|
|
172
|
+
resultingFingerprint: null,
|
|
159
173
|
},
|
|
160
174
|
async commit() {
|
|
161
175
|
await unlink(target);
|
|
@@ -180,6 +194,7 @@ async function stageUpdate(cwd: string, op: Extract<PatchOperation, { type: "upd
|
|
|
180
194
|
path: op.path,
|
|
181
195
|
linesAdded: op.linesAdded,
|
|
182
196
|
linesRemoved: op.linesRemoved,
|
|
197
|
+
resultingFingerprint: fingerprint(next),
|
|
183
198
|
snapshotRanges: result?.snapshotRanges,
|
|
184
199
|
},
|
|
185
200
|
async commit() {
|
|
@@ -203,6 +218,7 @@ async function stageUpdate(cwd: string, op: Extract<PatchOperation, { type: "upd
|
|
|
203
218
|
move: { from: op.path, to: movePath },
|
|
204
219
|
linesAdded: op.linesAdded,
|
|
205
220
|
linesRemoved: op.linesRemoved,
|
|
221
|
+
resultingFingerprint: fingerprint(next),
|
|
206
222
|
snapshotRanges: result?.snapshotRanges,
|
|
207
223
|
},
|
|
208
224
|
async commit() {
|
|
@@ -256,6 +272,84 @@ function withMutationQueuePaths<T>(paths: string[], fn: () => Promise<T>): Promi
|
|
|
256
272
|
return current();
|
|
257
273
|
}
|
|
258
274
|
|
|
275
|
+
export async function applyExactSourceMutations(
|
|
276
|
+
cwd: string,
|
|
277
|
+
mutations: readonly ExactSourceMutation[],
|
|
278
|
+
signal?: AbortSignal,
|
|
279
|
+
): Promise<ApplyPatchSummary> {
|
|
280
|
+
throwIfAborted(signal);
|
|
281
|
+
if (mutations.length === 0) throw new Error("Exact-source mutation requires at least one file.");
|
|
282
|
+
const byPath = new Map<string, ExactSourceMutation>();
|
|
283
|
+
for (const mutation of mutations) {
|
|
284
|
+
const path = resolvePath(cwd, mutation.path);
|
|
285
|
+
if (byPath.has(path)) throw new Error(`Conflicting exact-source mutations for path: ${mutation.path}`);
|
|
286
|
+
byPath.set(path, { ...mutation, path });
|
|
287
|
+
}
|
|
288
|
+
const ordered = [...byPath.values()].sort((left, right) => left.path.localeCompare(right.path));
|
|
289
|
+
|
|
290
|
+
return withMutationQueuePaths(
|
|
291
|
+
ordered.map((mutation) => mutation.path),
|
|
292
|
+
async () => {
|
|
293
|
+
const staged: Array<{ mutation: ExactSourceMutation; change: ApplyPatchChange }> = [];
|
|
294
|
+
for (const [sectionIndex, mutation] of ordered.entries()) {
|
|
295
|
+
throwIfAborted(signal);
|
|
296
|
+
await assertExistingFile(mutation.path, mutation.path);
|
|
297
|
+
const canonical = await realpath(mutation.path);
|
|
298
|
+
if (canonical !== mutation.path) {
|
|
299
|
+
throw new Error(`Exact-source mutation path is not canonical: ${mutation.path}`);
|
|
300
|
+
}
|
|
301
|
+
const current = await readUtf8(mutation.path, mutation.path);
|
|
302
|
+
const currentFingerprint = fingerprint(current);
|
|
303
|
+
if (currentFingerprint !== mutation.expectedFingerprint) {
|
|
304
|
+
throw new Error(
|
|
305
|
+
`Source changed before exact-source mutation for ${mutation.path}; expected ${mutation.expectedFingerprint}, found ${currentFingerprint}.`,
|
|
306
|
+
);
|
|
307
|
+
}
|
|
308
|
+
const displayPath = relative(resolve(cwd), mutation.path);
|
|
309
|
+
const lineCount = countLogicalLines(mutation.source);
|
|
310
|
+
staged.push({
|
|
311
|
+
mutation,
|
|
312
|
+
change: {
|
|
313
|
+
sectionIndex,
|
|
314
|
+
kind: "update",
|
|
315
|
+
path: displayPath.startsWith("..") || isAbsolute(displayPath) ? mutation.path : displayPath,
|
|
316
|
+
linesAdded: lineCount,
|
|
317
|
+
linesRemoved: countLogicalLines(current),
|
|
318
|
+
resultingFingerprint: fingerprint(mutation.source),
|
|
319
|
+
snapshotRanges: lineCount > 0 ? [{ startLine: 1, endLine: Math.min(lineCount, 120) }] : undefined,
|
|
320
|
+
},
|
|
321
|
+
});
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
throwIfAborted(signal);
|
|
325
|
+
const changes: ApplyPatchChange[] = [];
|
|
326
|
+
for (const { mutation, change } of staged) {
|
|
327
|
+
try {
|
|
328
|
+
throwIfAborted(signal);
|
|
329
|
+
await writeFile(mutation.path, mutation.source, "utf8");
|
|
330
|
+
changes.push(change);
|
|
331
|
+
} catch (error) {
|
|
332
|
+
return {
|
|
333
|
+
status: changes.length === 0 ? "failed" : "partial",
|
|
334
|
+
changes,
|
|
335
|
+
failures: [
|
|
336
|
+
{
|
|
337
|
+
phase: "apply",
|
|
338
|
+
sectionIndex: change.sectionIndex,
|
|
339
|
+
path: change.path,
|
|
340
|
+
kind: "update",
|
|
341
|
+
message: error instanceof Error ? error.message : String(error),
|
|
342
|
+
},
|
|
343
|
+
],
|
|
344
|
+
totalSections: staged.length,
|
|
345
|
+
};
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
return { status: "completed", changes, failures: [], totalSections: staged.length };
|
|
349
|
+
},
|
|
350
|
+
);
|
|
351
|
+
}
|
|
352
|
+
|
|
259
353
|
export async function applyPatch(
|
|
260
354
|
cwd: string,
|
|
261
355
|
input: string,
|
|
@@ -165,6 +165,7 @@ export default function patchExtension(pi: ExtensionAPI): void {
|
|
|
165
165
|
move: change.move,
|
|
166
166
|
linesAdded: change.linesAdded,
|
|
167
167
|
linesRemoved: change.linesRemoved,
|
|
168
|
+
resultingFingerprint: change.resultingFingerprint,
|
|
168
169
|
snapshotRanges: change.snapshotRanges,
|
|
169
170
|
})),
|
|
170
171
|
});
|
|
@@ -11,8 +11,6 @@ const WORKFLOW_NAME = "publish.yml";
|
|
|
11
11
|
const WORKFLOW_WAIT_MS = 10 * 60_000;
|
|
12
12
|
const POLL_INTERVAL_MS = 5_000;
|
|
13
13
|
const DEFAULT_COMMAND_TIMEOUT_MS = 120_000;
|
|
14
|
-
const CARGO_BUILD_TIMEOUT_MS = 15 * 60_000;
|
|
15
|
-
const TAU_AST_SCRIPT = "packages/agent/scripts/package-tau-ast.ts";
|
|
16
14
|
|
|
17
15
|
type Bump = "patch" | "minor" | "major";
|
|
18
16
|
|
|
@@ -68,8 +66,6 @@ async function publish(pi: ExtensionAPI, ctx: ExtensionCommandContext): Promise<
|
|
|
68
66
|
if (!repo) throw new Error("No git repository found.");
|
|
69
67
|
if (repo.fileCount > 0)
|
|
70
68
|
throw new Error("Working tree is not clean. Commit or stash every change before publishing.");
|
|
71
|
-
if (process.platform !== "darwin" || process.arch !== "arm64")
|
|
72
|
-
throw new Error(`/publish requires darwin-arm64; this host is ${process.platform}-${process.arch}.`);
|
|
73
69
|
await run(pi, ctx, "gh", ["auth", "status"], repo.root, DEFAULT_COMMAND_TIMEOUT_MS);
|
|
74
70
|
await run(pi, ctx, "npm", ["run", "check:package-sources"], repo.root, DEFAULT_COMMAND_TIMEOUT_MS);
|
|
75
71
|
|
|
@@ -129,87 +125,24 @@ async function completePublish(
|
|
|
129
125
|
progress?.update("write package versions");
|
|
130
126
|
await writeReleaseVersion(root, manifests, version);
|
|
131
127
|
}
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
progress?.update("stage tau-ast");
|
|
151
|
-
await run(
|
|
152
|
-
pi,
|
|
153
|
-
ctx,
|
|
154
|
-
process.execPath,
|
|
155
|
-
["--experimental-strip-types", TAU_AST_SCRIPT, "stage"],
|
|
156
|
-
root,
|
|
157
|
-
DEFAULT_COMMAND_TIMEOUT_MS,
|
|
158
|
-
);
|
|
159
|
-
progress?.update("smoke test tau-ast");
|
|
160
|
-
await run(
|
|
161
|
-
pi,
|
|
162
|
-
ctx,
|
|
163
|
-
process.execPath,
|
|
164
|
-
["--experimental-strip-types", TAU_AST_SCRIPT, "smoke"],
|
|
165
|
-
root,
|
|
166
|
-
DEFAULT_COMMAND_TIMEOUT_MS,
|
|
167
|
-
);
|
|
168
|
-
progress?.update("npm pack --dry-run @shanepadgett/tau-tui");
|
|
169
|
-
await run(
|
|
170
|
-
pi,
|
|
171
|
-
ctx,
|
|
172
|
-
"npm",
|
|
173
|
-
["pack", "--dry-run", "--workspace", "@shanepadgett/tau-tui"],
|
|
174
|
-
root,
|
|
175
|
-
DEFAULT_COMMAND_TIMEOUT_MS,
|
|
176
|
-
);
|
|
177
|
-
progress?.update("npm pack --dry-run @shanepadgett/tau-agent");
|
|
178
|
-
await run(
|
|
179
|
-
pi,
|
|
180
|
-
ctx,
|
|
181
|
-
"npm",
|
|
182
|
-
["pack", "--dry-run", "--workspace", "@shanepadgett/tau-agent"],
|
|
183
|
-
root,
|
|
184
|
-
DEFAULT_COMMAND_TIMEOUT_MS,
|
|
185
|
-
);
|
|
186
|
-
progress?.update("verify packed tau-ast");
|
|
187
|
-
await run(
|
|
188
|
-
pi,
|
|
189
|
-
ctx,
|
|
190
|
-
process.execPath,
|
|
191
|
-
["--experimental-strip-types", TAU_AST_SCRIPT, "verify-pack"],
|
|
192
|
-
root,
|
|
193
|
-
DEFAULT_COMMAND_TIMEOUT_MS,
|
|
194
|
-
);
|
|
195
|
-
} finally {
|
|
196
|
-
await run(
|
|
197
|
-
pi,
|
|
198
|
-
ctx,
|
|
199
|
-
process.execPath,
|
|
200
|
-
["--experimental-strip-types", TAU_AST_SCRIPT, "clean"],
|
|
201
|
-
root,
|
|
202
|
-
DEFAULT_COMMAND_TIMEOUT_MS,
|
|
203
|
-
);
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
const trackedNativeFiles = await git.run(["ls-files", "--", "packages/agent/native-bin"], { cwd: root });
|
|
207
|
-
const stagedNativeFiles = await git.run(["diff", "--cached", "--name-only", "--", "packages/agent/native-bin"], {
|
|
208
|
-
cwd: root,
|
|
209
|
-
});
|
|
210
|
-
if (trackedNativeFiles || stagedNativeFiles)
|
|
211
|
-
throw new Error("Release blocked: packages/agent/native-bin/ contains tracked or staged files.");
|
|
212
|
-
|
|
128
|
+
progress?.update("npm pack --dry-run @shanepadgett/tau-tui");
|
|
129
|
+
await run(
|
|
130
|
+
pi,
|
|
131
|
+
ctx,
|
|
132
|
+
"npm",
|
|
133
|
+
["pack", "--dry-run", "--workspace", "@shanepadgett/tau-tui"],
|
|
134
|
+
root,
|
|
135
|
+
DEFAULT_COMMAND_TIMEOUT_MS,
|
|
136
|
+
);
|
|
137
|
+
progress?.update("npm pack --dry-run @shanepadgett/tau-agent");
|
|
138
|
+
await run(
|
|
139
|
+
pi,
|
|
140
|
+
ctx,
|
|
141
|
+
"npm",
|
|
142
|
+
["pack", "--dry-run", "--workspace", "@shanepadgett/tau-agent"],
|
|
143
|
+
root,
|
|
144
|
+
DEFAULT_COMMAND_TIMEOUT_MS,
|
|
145
|
+
);
|
|
213
146
|
if (tag) {
|
|
214
147
|
progress?.update("git add release files");
|
|
215
148
|
await git.run(["add", ...PACKAGE_PATHS, LOCKFILE_PATH], { cwd: root });
|
|
@@ -4,12 +4,8 @@ import { ToolPanel } from "@shanepadgett/tau-tui";
|
|
|
4
4
|
|
|
5
5
|
const RELEASE_STEPS = [
|
|
6
6
|
"write package versions",
|
|
7
|
-
"build tau-ast darwin-arm64",
|
|
8
|
-
"stage tau-ast",
|
|
9
|
-
"smoke test tau-ast",
|
|
10
7
|
"npm pack --dry-run @shanepadgett/tau-tui",
|
|
11
8
|
"npm pack --dry-run @shanepadgett/tau-agent",
|
|
12
|
-
"verify packed tau-ast",
|
|
13
9
|
"git add release files",
|
|
14
10
|
"git commit",
|
|
15
11
|
"git tag",
|
|
@@ -1,19 +1,22 @@
|
|
|
1
1
|
# Soul
|
|
2
2
|
|
|
3
|
-
Soul
|
|
3
|
+
Soul shapes how Tau works and talks by adding two independent sections to Pi's native assistant prompt:
|
|
4
|
+
|
|
5
|
+
- **ponytail** — a lazy-senior-dev build ethos: do the smallest correct thing, reuse before writing, YAGNI, fix bugs at the root, never cut validation, security, or accessibility.
|
|
6
|
+
- **caveman** — a terse communication style: drop filler, keep technical substance exact, quote the shortest decisive line, spell out anything where brevity would risk safety.
|
|
4
7
|
|
|
5
8
|
Pi continues to own tool guidance, project instructions, skills, documentation paths, custom prompts, and working-directory context.
|
|
6
9
|
|
|
7
|
-
|
|
10
|
+
Toggle each section in Tau settings (both on by default):
|
|
8
11
|
|
|
9
12
|
```json
|
|
10
13
|
{
|
|
11
14
|
"extensions": {
|
|
12
|
-
"soul": { "
|
|
15
|
+
"soul": { "ponytail": true, "caveman": false }
|
|
13
16
|
}
|
|
14
17
|
}
|
|
15
18
|
```
|
|
16
19
|
|
|
17
|
-
|
|
20
|
+
Settings take effect on session start.
|
|
18
21
|
|
|
19
22
|
After changing this extension, run `/reload` before testing the new behavior.
|
package/extensions/soul/index.ts
CHANGED
|
@@ -1,17 +1,23 @@
|
|
|
1
1
|
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
2
2
|
import { loadTauExtensionSettings } from "../../shared/settings/load.ts";
|
|
3
|
-
import {
|
|
3
|
+
import { CAVEMAN_STYLE, PONYTAIL_ETHOS } from "./prompt.ts";
|
|
4
4
|
import soulSettings from "./settings.ts";
|
|
5
5
|
|
|
6
6
|
export default function soulExtension(pi: ExtensionAPI): void {
|
|
7
|
-
let
|
|
7
|
+
let ponytail = true;
|
|
8
|
+
let caveman = true;
|
|
8
9
|
|
|
9
10
|
pi.on("session_start", async (_event, ctx) => {
|
|
10
|
-
|
|
11
|
+
const settings = await loadTauExtensionSettings(ctx, soulSettings);
|
|
12
|
+
ponytail = settings.ponytail;
|
|
13
|
+
caveman = settings.caveman;
|
|
11
14
|
});
|
|
12
15
|
|
|
13
16
|
pi.on("before_agent_start", (event) => {
|
|
14
|
-
|
|
15
|
-
|
|
17
|
+
const sections: string[] = [];
|
|
18
|
+
if (ponytail) sections.push(PONYTAIL_ETHOS);
|
|
19
|
+
if (caveman) sections.push(CAVEMAN_STYLE);
|
|
20
|
+
if (sections.length === 0) return undefined;
|
|
21
|
+
return { systemPrompt: [event.systemPrompt, ...sections].join("\n\n") };
|
|
16
22
|
});
|
|
17
23
|
}
|
|
@@ -1,27 +1,43 @@
|
|
|
1
|
-
export const
|
|
1
|
+
export const PONYTAIL_ETHOS = `## Build ethos
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Lazy senior developer. Lazy means efficient, not careless. The best code is the code never written.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Understand first. Read the task and the code it touches, trace the real flow end to end. Then, before writing code, stop at the first rung that holds:
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
1. Does this need to exist at all? Speculative need, skip it and say so. (YAGNI)
|
|
8
|
+
2. Already in this codebase? Reuse the helper, util, type, or pattern that lives here.
|
|
9
|
+
3. Stdlib does it? Use it.
|
|
10
|
+
4. Native platform feature covers it? Use it.
|
|
11
|
+
5. Already-installed dependency solves it? Use it. Never add one for what a few lines do.
|
|
12
|
+
6. Can it be one line? One line.
|
|
13
|
+
7. Only then: the minimum code that works.
|
|
8
14
|
|
|
9
|
-
|
|
15
|
+
Bug fix means root cause, not symptom. A report names a symptom. Grep every caller of the function you touch and fix the shared function once. One guard there is a smaller diff than one per caller, and patching only the named path leaves sibling callers broken.
|
|
10
16
|
|
|
11
|
-
|
|
17
|
+
Deletion over addition. Boring over clever. Fewest files. Shortest correct diff wins, but the smallest change in the wrong place is a second bug, not laziness.
|
|
12
18
|
|
|
13
|
-
|
|
19
|
+
No abstraction, config, or boilerplate nobody asked for. No interface with one implementation, no factory for one product, no config for a value that never changes.
|
|
14
20
|
|
|
15
|
-
|
|
21
|
+
Build only what was asked. The ask approves that scope. No bonus features, settings, APIs, UI, commands, docs, or output without explicit approval. See a missing surface that truly helps? Ask in one line first. Do not sneak it into the diff.
|
|
16
22
|
|
|
17
|
-
|
|
23
|
+
Never lazy about: understanding the problem, input validation at trust boundaries, error handling that prevents data loss, security, accessibility, the calibration real hardware needs, anything explicitly requested.
|
|
18
24
|
|
|
19
|
-
|
|
25
|
+
Non-trivial logic leaves one runnable check behind: the smallest thing that fails if the logic breaks. Trivial one-liners need none.
|
|
20
26
|
|
|
21
|
-
|
|
27
|
+
Mark a deliberate simplification that cuts a real corner with a named ceiling and its upgrade path.`;
|
|
22
28
|
|
|
23
|
-
|
|
29
|
+
export const CAVEMAN_STYLE = `## Communication style
|
|
24
30
|
|
|
25
|
-
|
|
31
|
+
Primary directive: simple, terse, human-like conversation. Talk to the human the way a person does, not the way a document reads. A wall of text does not get read. Outside a plan or a file you were asked to write, keep replies short. All technical substance stays. Only fluff dies.
|
|
26
32
|
|
|
27
|
-
|
|
33
|
+
Drop articles (a/an/the), filler (just/really/basically/actually/simply), pleasantries (sure/certainly/of course/happy to), and hedging. Fragments OK. Short synonyms (big not extensive, fix not "implement a solution for"). No emoji, no decorative tables, no tool-call narration. Do not dump long raw logs. Quote the shortest decisive line.
|
|
34
|
+
|
|
35
|
+
Standard well-known acronyms OK (DB, API, HTTP). Never invent abbreviations (cfg, impl, req, fn). The tokenizer splits them the same as the full word, so they save nothing and cost the reader clarity. No causal arrows. Technical terms, code blocks, and error strings stay exact and verbatim.
|
|
36
|
+
|
|
37
|
+
Preserve the user's language. Compress the style, not the language.
|
|
38
|
+
|
|
39
|
+
No self-reference. Never name or announce the style.
|
|
40
|
+
|
|
41
|
+
No filler emphasis or manufactured insight. Skip "here's the thing", "that's the part that really matters", "and that's the key". Skip "not just X, it's Y" and "it's not X, it's Y" framing. Skip grand closers that restate the point as a lesson. State the fact, the mechanism, or the next step, then stop.
|
|
42
|
+
|
|
43
|
+
Full clear sentences, terse style dropped, for security warnings, irreversible-action confirmations, multi-step sequences where order matters, and anywhere compression would create ambiguity. Resume terse after.`;
|
|
@@ -3,10 +3,15 @@ import { defineTauExtensionSettings } from "../../shared/settings/define.ts";
|
|
|
3
3
|
|
|
4
4
|
export default defineTauExtensionSettings({
|
|
5
5
|
key: "soul",
|
|
6
|
-
defaults: {
|
|
6
|
+
defaults: { ponytail: true as boolean, caveman: true as boolean },
|
|
7
7
|
schema: Type.Object(
|
|
8
8
|
{
|
|
9
|
-
|
|
9
|
+
ponytail: Type.Optional(
|
|
10
|
+
Type.Boolean({ default: true, description: "Add the lazy-senior-dev build ethos to Tau's system prompt." }),
|
|
11
|
+
),
|
|
12
|
+
caveman: Type.Optional(
|
|
13
|
+
Type.Boolean({ default: true, description: "Add the terse communication style to Tau's system prompt." }),
|
|
14
|
+
),
|
|
10
15
|
},
|
|
11
16
|
{ additionalProperties: false },
|
|
12
17
|
),
|
|
@@ -8,9 +8,6 @@ description: >-
|
|
|
8
8
|
Task may include a short human/steer note. Harness may also auto-run this when context validation is enabled.
|
|
9
9
|
tools:
|
|
10
10
|
- read
|
|
11
|
-
- ls
|
|
12
|
-
- find
|
|
13
|
-
- grep
|
|
14
11
|
- bash
|
|
15
12
|
- patch
|
|
16
13
|
- context_sync_evidence
|
|
@@ -31,22 +28,21 @@ Tabs/folders are domains. TOML files are concepts. TOML sections are selectable
|
|
|
31
28
|
## Tools
|
|
32
29
|
|
|
33
30
|
- `context_sync_evidence` — git dirty set, catalog skeleton, deps, diffs, invariants. Prefer this first.
|
|
34
|
-
- `read`
|
|
35
|
-
- `bash` —
|
|
31
|
+
- `read` — open a known path when evidence is not enough.
|
|
32
|
+
- `bash` — list/search/inspect the tree and other read-only questions `read` cannot cover.
|
|
36
33
|
- `patch` — create/update/move/delete only under `.pi/contexts/**` (including whole concept TOML via `*** Delete File`).
|
|
37
34
|
|
|
38
35
|
### Bash limits
|
|
39
36
|
|
|
40
|
-
Prefer `
|
|
37
|
+
Prefer `context_sync_evidence` and `read` first. Use bash when those cannot cover the need.
|
|
41
38
|
|
|
42
|
-
Allowed bash
|
|
39
|
+
Allowed bash:
|
|
43
40
|
|
|
44
|
-
- Read-only inspection
|
|
41
|
+
- Read-only tree inspection — e.g. `ls`, `find`, `rg`/`grep`, `git log` / `git blame` / `git show` on existing commits, `file`, `wc`, small read-only pipelines
|
|
45
42
|
- After `patch` deletes the last file in a `.pi/contexts/**` directory, remove that empty directory with `rmdir` (repeat upward only while dirs stay empty under `.pi/contexts`). Prefer `rmdir` over `rm -r`.
|
|
46
43
|
|
|
47
44
|
Forbidden with bash:
|
|
48
45
|
|
|
49
|
-
- Anything `ls` / `find` / `grep` / `read` already do cleanly
|
|
50
46
|
- Creating, editing, moving, or deleting files (catalog files use `patch` only)
|
|
51
47
|
- Non-empty directory deletes; deletes outside `.pi/contexts`
|
|
52
48
|
- `git add` / `commit` / `push` / `checkout` / `restore` / `reset` / `stash` / branch changes
|
|
@@ -82,7 +78,7 @@ Path stuffing into the nearest feature bucket without climbing the ladder is fai
|
|
|
82
78
|
|
|
83
79
|
1. `context_sync_evidence` section `overview`.
|
|
84
80
|
2. `catalog` for the full skeleton. Do not invent domains you never inspected.
|
|
85
|
-
3. Pull `dirty`, `file`, `dependencies`, or `previews` as needed. Use `read`
|
|
81
|
+
3. Pull `dirty`, `file`, `dependencies`, or `previews` as needed. Use `read` for known paths. Use `bash` for tree list/search and other inspection evidence cannot cover.
|
|
86
82
|
4. Edit catalog TOML with `patch`.
|
|
87
83
|
5. `context_sync_evidence` section `invariants`. If failed, continue until it holds or you can explain a hard blocker.
|
|
88
84
|
6. Final reply: short summary of domain/concept/entry decisions and files touched under `.pi/contexts`. If no catalog edit was required, say why.
|
|
@@ -3,11 +3,19 @@ name: review
|
|
|
3
3
|
description: Perform an adversarial, read-only review for correctness, runtime risks, duplication, and over- or under-engineering
|
|
4
4
|
tools:
|
|
5
5
|
- read
|
|
6
|
-
- grep
|
|
7
|
-
- find
|
|
8
|
-
- ls
|
|
9
6
|
- bash
|
|
10
|
-
-
|
|
7
|
+
- outline
|
|
8
|
+
- show
|
|
9
|
+
- discover
|
|
10
|
+
- ast_search
|
|
11
|
+
- deps
|
|
12
|
+
- reverse_deps
|
|
13
|
+
- callers
|
|
14
|
+
- callees
|
|
15
|
+
- references
|
|
16
|
+
- implementations
|
|
17
|
+
- impact
|
|
18
|
+
- context
|
|
11
19
|
names:
|
|
12
20
|
- Auditor
|
|
13
21
|
- Inspector
|
|
@@ -15,34 +23,46 @@ names:
|
|
|
15
23
|
- Examiner
|
|
16
24
|
- Sentinel
|
|
17
25
|
model: openai-codex/gpt-5.6-sol
|
|
18
|
-
thinking:
|
|
26
|
+
thinking: high
|
|
19
27
|
---
|
|
20
28
|
|
|
21
|
-
|
|
29
|
+
Stay inside delegated change. Answer two questions:
|
|
30
|
+
|
|
31
|
+
1. Is runtime behavior correct?
|
|
32
|
+
2. Is this the simplest implementation of requested behavior?
|
|
33
|
+
|
|
34
|
+
Find concrete failures or needless complexity. Report. Stop. No mutations, unrelated review, or broad concern inventory.
|
|
35
|
+
|
|
36
|
+
## Evidence ladder
|
|
37
|
+
|
|
38
|
+
Use cheapest evidence that settles each question. Escalate only when answer could change verdict.
|
|
39
|
+
|
|
40
|
+
1. **Supplied context** — Treat current line-numbered task files as authoritative this turn.
|
|
41
|
+
2. **Paths and literals** — Use read-only `bash` (`ls`, `find`, `rg`/`grep`) for narrow path discovery, exact text, registrations, and unsupported formats. Use ranged `read` when formatting or source context matters.
|
|
42
|
+
3. **Structure and reuse** — Default to `outline`. Use `discover` only when changed code may duplicate an existing repository API but name or path is unknown. Use `ast_search` for a concrete risky or duplicated source shape.
|
|
43
|
+
4. **Exact declarations** — Use `show` with path + name (+ line when needed). Retrieve only contract, body, imports, or nearby lines needed for verdict.
|
|
44
|
+
5. **Runtime relationships** — Use `callers`, `callees`, `references`, or `implementations` after selecting a declaration. Use `deps`/`reverse_deps` for file imports. Use `impact` for full blast radius and `context` for one bounded declaration pack.
|
|
45
|
+
|
|
46
|
+
Keep roots and result limits narrow. Structural evidence proves bounded syntax, not dynamic dispatch. Preserve inferred and ambiguous labels.
|
|
22
47
|
|
|
23
48
|
## Review procedure
|
|
24
49
|
|
|
25
|
-
1.
|
|
26
|
-
2.
|
|
27
|
-
3.
|
|
28
|
-
4.
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
- under-engineering, missing validation, incomplete wiring, weak tests, and assumptions that should be enforced;
|
|
32
|
-
- tests that only mirror the implementation, miss realistic sequences, or fail to protect the requested behavior;
|
|
33
|
-
- dead code, stale documentation, and obsolete resources left behind by the change.
|
|
34
|
-
5. Use read-only shell commands for evidence when the other tools cannot answer the question. Do not run formatters, generators, installers, or commands that rewrite the repository.
|
|
35
|
-
6. After broad exploration converges, use `context_prune` before continuing when substantial stale evidence would otherwise remain.
|
|
50
|
+
1. Extract requested behavior, changed scope, and repository constraints from task and supplied files.
|
|
51
|
+
2. Inspect changed declarations. Form only actionable runtime and simplicity questions.
|
|
52
|
+
3. Runtime: follow shortest relevant path through callers, state transitions, boundaries, and error handling. Check realistic sequences, not theoretical branch inventory.
|
|
53
|
+
4. Simplicity: identify wrappers, helpers, option bags, duplicated logic, or staged abstractions that can disappear without changing requested behavior. Report only material reductions in concepts or ownership.
|
|
54
|
+
5. Inspect surrounding code only to confirm suspected failure, contract mismatch, missed caller, or existing simpler API.
|
|
55
|
+
6. Stop when both questions have evidence-backed answers.
|
|
36
56
|
|
|
37
|
-
|
|
57
|
+
Treat implementation as untrusted. Reject speculation, personal style preferences, and complexity complaints without concrete cost. Do not modify files.
|
|
38
58
|
|
|
39
59
|
## Output
|
|
40
60
|
|
|
41
|
-
List findings first, ordered by severity.
|
|
61
|
+
List findings first, ordered by severity. Each finding needs:
|
|
42
62
|
|
|
43
|
-
- severity and
|
|
44
|
-
- exact file and
|
|
45
|
-
-
|
|
46
|
-
-
|
|
63
|
+
- severity and direct title;
|
|
64
|
+
- exact file, line range, and declaration when one exists;
|
|
65
|
+
- runtime failure mechanism or concrete complexity cost;
|
|
66
|
+
- smallest credible fix direction.
|
|
47
67
|
|
|
48
|
-
Then list unresolved questions that materially affect correctness.
|
|
68
|
+
Then list only unresolved questions that materially affect runtime correctness. No findings: say runtime appears correct and implementation is already simplest credible version. Briefly name inspected scope. No preamble, search log, broad summary, or repeated evidence.
|