tau-coding-agent 0.1.3 → 0.1.5

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.
Files changed (60) hide show
  1. package/README.md +1 -1
  2. package/extensions/answer.ts +49 -43
  3. package/extensions/branch-term.ts +11 -16
  4. package/extensions/btw.ts +8 -8
  5. package/extensions/ghostty.ts +65 -12
  6. package/extensions/git-diff-stats.ts +1 -1
  7. package/extensions/git-pr-status.ts +1 -1
  8. package/extensions/insights.ts +6 -5
  9. package/extensions/loop.ts +39 -11
  10. package/extensions/memory.ts +6 -5
  11. package/extensions/notify.ts +25 -6
  12. package/extensions/openai-fast.ts +6 -4
  13. package/extensions/openai-verbosity.ts +6 -4
  14. package/extensions/review/fix.ts +239 -0
  15. package/extensions/review/git.ts +517 -0
  16. package/extensions/review/index.ts +232 -0
  17. package/extensions/review/message-queue.ts +249 -0
  18. package/extensions/review/models.ts +589 -0
  19. package/extensions/review/prompts.ts +337 -0
  20. package/extensions/review/renderers/inline.ts +126 -0
  21. package/extensions/review/request.ts +504 -0
  22. package/extensions/review/review.ts +1305 -0
  23. package/extensions/review/runner.ts +522 -0
  24. package/extensions/review/runtime.ts +275 -0
  25. package/extensions/review/schema.ts +160 -0
  26. package/extensions/review/submit-review-tool.ts +66 -0
  27. package/extensions/review/submit-triage-tool.ts +59 -0
  28. package/extensions/review/triage.ts +746 -0
  29. package/extensions/sandbox/index.ts +428 -103
  30. package/extensions/{interlude.ts → stash.ts} +13 -11
  31. package/extensions/tool-display-mode.ts +173 -17
  32. package/extensions/usage/anthropic.ts +1 -1
  33. package/extensions/usage/github-copilot.ts +1 -1
  34. package/extensions/usage/index.ts +9 -5
  35. package/extensions/usage/minimax.ts +1 -1
  36. package/extensions/usage/openai-codex.ts +1 -1
  37. package/extensions/usage/openrouter.ts +1 -1
  38. package/extensions/usage/providers.ts +0 -2
  39. package/extensions/usage/types.ts +1 -2
  40. package/extensions/usage/zai.ts +1 -1
  41. package/extensions/websearch/README.md +1 -1
  42. package/extensions/websearch/browser/chromium.ts +42 -31
  43. package/extensions/websearch/browser/discovery.ts +11 -9
  44. package/extensions/websearch/browser/firefox.ts +10 -7
  45. package/extensions/websearch/browser/fs.ts +10 -0
  46. package/extensions/websearch/browser/sqlite.ts +22 -15
  47. package/extensions/websearch/config.ts +2 -2
  48. package/extensions/websearch/index.ts +9 -9
  49. package/extensions/websearch/providers/anthropic.pi.ts +1 -1
  50. package/extensions/websearch/providers/gemini.pi.ts +1 -1
  51. package/extensions/websearch/providers/openai-codex.pi.ts +1 -1
  52. package/extensions/websearch/providers/pi-model.shared.ts +2 -2
  53. package/extensions/worktree.ts +36 -36
  54. package/package.json +7 -7
  55. package/skills/git-clean-history/SKILL.md +1 -0
  56. package/skills/git-commit/SKILL.md +2 -2
  57. package/skills/oracle/scripts/oracle +28 -12
  58. package/themes/tau-dark.json +2 -1
  59. package/extensions/review.ts +0 -4347
  60. package/extensions/usage/google-gemini-cli.ts +0 -232
@@ -1,9 +1,10 @@
1
- import { existsSync, readFileSync } from "node:fs";
1
+ import { readFile } from "node:fs/promises";
2
2
  import { DatabaseSync } from "node:sqlite";
3
3
  import os from "node:os";
4
4
  import path from "node:path";
5
5
 
6
6
  import type { BrowserCookie, BrowserProfile } from "../types.js";
7
+ import { pathExists } from "./fs.js";
7
8
  import { withSqliteSnapshot } from "./sqlite.js";
8
9
 
9
10
  function firefoxBaseDir(): string | null {
@@ -45,7 +46,9 @@ function parseIni(text: string): Array<Record<string, string>> {
45
46
  return sections;
46
47
  }
47
48
 
48
- export function discoverFirefoxProfiles(preferredProfileName?: string): BrowserProfile[] {
49
+ export async function discoverFirefoxProfiles(
50
+ preferredProfileName?: string,
51
+ ): Promise<BrowserProfile[]> {
49
52
  const baseDir = firefoxBaseDir();
50
53
  if (!baseDir) return [];
51
54
 
@@ -53,7 +56,7 @@ export function discoverFirefoxProfiles(preferredProfileName?: string): BrowserP
53
56
 
54
57
  let sections: Array<Record<string, string>> = [];
55
58
  try {
56
- sections = parseIni(readFileSync(profilesIniPath, "utf8"));
59
+ sections = parseIni(await readFile(profilesIniPath, "utf8"));
57
60
  } catch {
58
61
  return [];
59
62
  }
@@ -67,7 +70,7 @@ export function discoverFirefoxProfiles(preferredProfileName?: string): BrowserP
67
70
  const profilePath =
68
71
  section.IsRelative === "1" ? path.join(baseDir, profilePathValue) : profilePathValue;
69
72
  const cookiesPath = path.join(profilePath, "cookies.sqlite");
70
- if (!existsSync(cookiesPath)) continue;
73
+ if (!(await pathExists(cookiesPath))) continue;
71
74
 
72
75
  profiles.push({
73
76
  family: "firefox",
@@ -100,12 +103,12 @@ function isPreferredFirefoxProfile(
100
103
  );
101
104
  }
102
105
 
103
- export function loadFirefoxCookies(profile: BrowserProfile): BrowserCookie[] {
106
+ export async function loadFirefoxCookies(profile: BrowserProfile): Promise<BrowserCookie[]> {
104
107
  const cookiesPath = path.join(profile.profilePath, "cookies.sqlite");
105
- if (!existsSync(cookiesPath)) return [];
108
+ if (!(await pathExists(cookiesPath))) return [];
106
109
 
107
110
  try {
108
- return withSqliteSnapshot(cookiesPath, "websearch-firefox", (tempDbPath) => {
111
+ return await withSqliteSnapshot(cookiesPath, "websearch-firefox", (tempDbPath) => {
109
112
  const db = new DatabaseSync(tempDbPath, { readOnly: true });
110
113
  try {
111
114
  const rows = db
@@ -0,0 +1,10 @@
1
+ import { access } from "node:fs/promises";
2
+
3
+ export async function pathExists(filePath: string): Promise<boolean> {
4
+ try {
5
+ await access(filePath);
6
+ return true;
7
+ } catch {
8
+ return false;
9
+ }
10
+ }
@@ -1,33 +1,40 @@
1
- import { copyFileSync, existsSync, mkdirSync, rmSync } from "node:fs";
1
+ import { copyFile, mkdtemp, rm } from "node:fs/promises";
2
2
  import os from "node:os";
3
3
  import path from "node:path";
4
4
 
5
- export function withSqliteSnapshot<T>(
5
+ import { pathExists } from "./fs.js";
6
+
7
+ export async function withSqliteSnapshot<T>(
6
8
  sourceDbPath: string,
7
9
  tempPrefix: string,
8
- operation: (snapshotPath: string) => T,
9
- ): T {
10
- const tempDir = path.join(os.tmpdir(), `${tempPrefix}-${process.pid}-${Date.now()}`);
10
+ operation: (snapshotPath: string) => T | Promise<T>,
11
+ ): Promise<T> {
12
+ const tempDir = await mkdtemp(path.join(os.tmpdir(), `${tempPrefix}-${process.pid}-`));
11
13
  const snapshotPath = path.join(tempDir, path.basename(sourceDbPath));
12
14
 
13
15
  try {
14
- mkdirSync(tempDir, { recursive: true });
15
- copyFileSync(sourceDbPath, snapshotPath);
16
- copySidecar(sourceDbPath, snapshotPath, "-wal");
17
- copySidecar(sourceDbPath, snapshotPath, "-shm");
18
- copySidecar(sourceDbPath, snapshotPath, "-journal");
19
- return operation(snapshotPath);
16
+ await copyFile(sourceDbPath, snapshotPath);
17
+ await Promise.all([
18
+ copySidecar(sourceDbPath, snapshotPath, "-wal"),
19
+ copySidecar(sourceDbPath, snapshotPath, "-shm"),
20
+ copySidecar(sourceDbPath, snapshotPath, "-journal"),
21
+ ]);
22
+ return await operation(snapshotPath);
20
23
  } finally {
21
- rmSync(tempDir, { recursive: true, force: true });
24
+ await rm(tempDir, { recursive: true, force: true });
22
25
  }
23
26
  }
24
27
 
25
- export function copySidecar(sourceDbPath: string, targetDbPath: string, suffix: string): void {
28
+ export async function copySidecar(
29
+ sourceDbPath: string,
30
+ targetDbPath: string,
31
+ suffix: string,
32
+ ): Promise<void> {
26
33
  const source = `${sourceDbPath}${suffix}`;
27
- if (!existsSync(source)) return;
34
+ if (!(await pathExists(source))) return;
28
35
 
29
36
  try {
30
- copyFileSync(source, `${targetDbPath}${suffix}`);
37
+ await copyFile(source, `${targetDbPath}${suffix}`);
31
38
  } catch (error) {
32
39
  const code =
33
40
  error && typeof error === "object" && "code" in error
@@ -1,10 +1,10 @@
1
1
  import { readFileSync } from "node:fs";
2
- import { homedir } from "node:os";
3
2
  import path from "node:path";
3
+ import { getAgentDir } from "@earendil-works/pi-coding-agent";
4
4
 
5
5
  import type { WebsearchConfig, WebsearchRouteId } from "./types.js";
6
6
 
7
- const WEBSEARCH_CONFIG_PATH = path.join(homedir(), ".pi", "websearch.json");
7
+ const WEBSEARCH_CONFIG_PATH = path.join(getAgentDir(), "websearch.json");
8
8
 
9
9
  const DEFAULT_ROUTES: WebsearchRouteId[] = [
10
10
  "pi:openai-codex",
@@ -1,12 +1,12 @@
1
- import type { Api, Model } from "@mariozechner/pi-ai";
1
+ import type { Api, Model } from "@earendil-works/pi-ai";
2
2
  import {
3
3
  defineTool,
4
4
  getMarkdownTheme,
5
5
  keyHint,
6
6
  type ExtensionAPI,
7
7
  type ExtensionContext,
8
- } from "@mariozechner/pi-coding-agent";
9
- import { Container, Markdown, Spacer, Text } from "@mariozechner/pi-tui";
8
+ } from "@earendil-works/pi-coding-agent";
9
+ import { Container, Markdown, Spacer, Text } from "@earendil-works/pi-tui";
10
10
  import { Type } from "typebox";
11
11
 
12
12
  import { createBrowserSession, discoverProfiles } from "./browser/discovery.js";
@@ -128,15 +128,15 @@ function throwIfAborted(signal?: AbortSignal): void {
128
128
  throw signal.reason ?? new Error("The operation was aborted.");
129
129
  }
130
130
 
131
- function getBrowserProfiles(
131
+ async function getBrowserProfiles(
132
132
  cache: Partial<Record<WebsearchBrowserFamily, BrowserProfile[]>>,
133
133
  family: WebsearchBrowserFamily,
134
134
  config: WebsearchConfig,
135
- ): BrowserProfile[] {
135
+ ): Promise<BrowserProfile[]> {
136
136
  const cached = cache[family];
137
137
  if (cached) return cached;
138
138
 
139
- const profiles = discoverProfiles([family], config.profiles);
139
+ const profiles = await discoverProfiles([family], config.profiles);
140
140
  cache[family] = profiles;
141
141
  return profiles;
142
142
  }
@@ -153,7 +153,7 @@ async function searchBrowserRoute(
153
153
  : "chromium";
154
154
  const browserProvider = route.endsWith(":gemini") ? browserGemini : browserOpenAICodex;
155
155
  const configuredProfileName = config.profiles[profileFamily];
156
- const profiles = getBrowserProfiles(profileCache, profileFamily, config);
156
+ const profiles = await getBrowserProfiles(profileCache, profileFamily, config);
157
157
  let lastError: string | null = null;
158
158
 
159
159
  if (configuredProfileName && profiles.length === 0) {
@@ -164,7 +164,7 @@ async function searchBrowserRoute(
164
164
  throwIfAborted(signal);
165
165
 
166
166
  try {
167
- const session = createBrowserSession(profile, browserProvider.domains);
167
+ const session = await createBrowserSession(profile, browserProvider.domains);
168
168
  if (!session) {
169
169
  if (configuredProfileName) {
170
170
  throw new Error(
@@ -265,7 +265,7 @@ export default function (pi: ExtensionAPI) {
265
265
  promptSnippet:
266
266
  "Search the web for current or external information unavailable in local files",
267
267
  promptGuidelines: [
268
- "Use this for recent facts, live service behavior, or external documentation that is not already present in the repo.",
268
+ "Use websearch for recent facts, live service behavior, or external documentation that is not already present in the repo.",
269
269
  "Do not use websearch when repository files or supplied context already answer the question.",
270
270
  ],
271
271
  parameters: Type.Object({
@@ -1,4 +1,4 @@
1
- import type { Api, Model } from "@mariozechner/pi-ai";
1
+ import type { Api, Model } from "@earendil-works/pi-ai";
2
2
 
3
3
  import { dedupeSources, extractMarkdownSources } from "../normalize.js";
4
4
  import type { WebsearchResult } from "../types.js";
@@ -1,4 +1,4 @@
1
- import type { Api, Model } from "@mariozechner/pi-ai";
1
+ import type { Api, Model } from "@earendil-works/pi-ai";
2
2
 
3
3
  import { dedupeSources, extractMarkdownSources, normalizeSourceTitle } from "../normalize.js";
4
4
  import type { WebsearchResult, WebsearchSource } from "../types.js";
@@ -1,4 +1,4 @@
1
- import type { Api, Model } from "@mariozechner/pi-ai";
1
+ import type { Api, Model } from "@earendil-works/pi-ai";
2
2
 
3
3
  import type { WebsearchResult } from "../types.js";
4
4
  import { decodeJwtAccountId, runOpenAICodexSearch } from "./openai-codex.shared.js";
@@ -1,5 +1,5 @@
1
- import type { Api, Model } from "@mariozechner/pi-ai";
2
- import type { ExtensionContext } from "@mariozechner/pi-coding-agent";
1
+ import type { Api, Model } from "@earendil-works/pi-ai";
2
+ import type { ExtensionContext } from "@earendil-works/pi-coding-agent";
3
3
 
4
4
  export interface PiModelSelection {
5
5
  model: Model<Api>;
@@ -18,14 +18,14 @@
18
18
  * Lists worktrees and their status.
19
19
  */
20
20
 
21
- import type { ExtensionAPI, ExtensionCommandContext, Theme } from "@mariozechner/pi-coding-agent";
21
+ import type { ExtensionAPI, ExtensionCommandContext, Theme } from "@earendil-works/pi-coding-agent";
22
22
  import {
23
23
  CURRENT_SESSION_VERSION,
24
24
  DynamicBorder,
25
25
  SessionManager,
26
26
  highlightCode,
27
27
  type SessionHeader,
28
- } from "@mariozechner/pi-coding-agent";
28
+ } from "@earendil-works/pi-coding-agent";
29
29
  import {
30
30
  Box,
31
31
  Container,
@@ -33,16 +33,16 @@ import {
33
33
  SelectList,
34
34
  Text,
35
35
  matchesKey,
36
- } from "@mariozechner/pi-tui";
36
+ } from "@earendil-works/pi-tui";
37
37
  import { spawnSync } from "node:child_process";
38
38
  import { randomUUID } from "node:crypto";
39
39
  import * as fs from "node:fs";
40
40
  import * as path from "node:path";
41
41
 
42
42
  const STATUS_KEY = "0-worktree";
43
- const MANUAL_OPEN_MESSAGE_TYPE = "worktree-open-command";
44
- const RESTORE_STASH_MESSAGE_TYPE = "worktree-restore-command";
45
- const SCRIPT_RERUN_MESSAGE_TYPE = "worktree-script-rerun-command";
43
+ const MANUAL_OPEN_ENTRY_TYPE = "worktree-open-command";
44
+ const RESTORE_STASH_ENTRY_TYPE = "worktree-restore-command";
45
+ const SCRIPT_RERUN_ENTRY_TYPE = "worktree-script-rerun-command";
46
46
  const MANUAL_OPEN_INTRO =
47
47
  "Worktree ready. Open it in a separate terminal or tmux pane with this command";
48
48
 
@@ -224,15 +224,10 @@ function showCommandMessage(
224
224
  return;
225
225
  }
226
226
 
227
- pi.sendMessage({
228
- customType,
229
- content: intro,
230
- display: true,
231
- details: {
232
- intro,
233
- command,
234
- copiedToClipboard,
235
- } satisfies CommandMessageDetails,
227
+ pi.appendEntry<CommandMessageDetails>(customType, {
228
+ intro,
229
+ command,
230
+ copiedToClipboard,
236
231
  });
237
232
  }
238
233
 
@@ -241,7 +236,7 @@ function showManualOpenCommand(
241
236
  ctx: ExtensionCommandContext,
242
237
  command: string,
243
238
  ): void {
244
- showCommandMessage(pi, ctx, MANUAL_OPEN_MESSAGE_TYPE, MANUAL_OPEN_INTRO, command);
239
+ showCommandMessage(pi, ctx, MANUAL_OPEN_ENTRY_TYPE, MANUAL_OPEN_INTRO, command);
245
240
  }
246
241
 
247
242
  function showRestoreStashCommand(
@@ -253,7 +248,7 @@ function showRestoreStashCommand(
253
248
  showCommandMessage(
254
249
  pi,
255
250
  ctx,
256
- RESTORE_STASH_MESSAGE_TYPE,
251
+ RESTORE_STASH_ENTRY_TYPE,
257
252
  `Main-worktree changes were stashed as ${stashSpec}. Restore them in the new worktree with this command`,
258
253
  `cd ${shellQuoteCompact(targetPath)} && git stash apply ${shellQuote(stashSpec)}`,
259
254
  );
@@ -270,7 +265,7 @@ function showScriptRerunCommand(
270
265
  showCommandMessage(
271
266
  pi,
272
267
  ctx,
273
- SCRIPT_RERUN_MESSAGE_TYPE,
268
+ SCRIPT_RERUN_ENTRY_TYPE,
274
269
  `${label} failed (exit ${exitCode}). Re-run it manually with this command`,
275
270
  `cd ${shellQuoteCompact(worktreeRoot)} && ${command}`,
276
271
  );
@@ -2008,18 +2003,23 @@ async function handleList(pi: ExtensionAPI, ctx: ExtensionCommandContext): Promi
2008
2003
  return { repo, items };
2009
2004
  });
2010
2005
 
2011
- if (!ctx.hasUI) {
2012
- for (const item of items) {
2013
- const dirty = item.status === "dirty" ? " *" : "";
2014
- const meta: string[] = [];
2015
- if (item.tracked) meta.push("↑");
2016
- if (item.isMain) meta.push("[primary]");
2017
- if (item.pathState !== "ok") meta.push(item.pathState);
2018
- if (item.wt.locked)
2019
- meta.push(item.wt.lockedReason ? `locked:${item.wt.lockedReason}` : "locked");
2020
- const suffix = meta.length > 0 ? ` ${meta.join(" ")}` : "";
2021
- console.log(` ${item.branch}${dirty}${suffix} ${collapsePath(item.wt.path)}`);
2022
- }
2006
+ if (ctx.mode !== "tui") {
2007
+ const output = items
2008
+ .map((item) => {
2009
+ const dirty = item.status === "dirty" ? " *" : "";
2010
+ const meta: string[] = [];
2011
+ if (item.tracked) meta.push("↑");
2012
+ if (item.isMain) meta.push("[primary]");
2013
+ if (item.pathState !== "ok") meta.push(item.pathState);
2014
+ if (item.wt.locked)
2015
+ meta.push(item.wt.lockedReason ? `locked:${item.wt.lockedReason}` : "locked");
2016
+ const suffix = meta.length > 0 ? ` ${meta.join(" ")}` : "";
2017
+ return ` ${item.branch}${dirty}${suffix} ${collapsePath(item.wt.path)}`;
2018
+ })
2019
+ .join("\n");
2020
+
2021
+ if (ctx.mode === "print") console.log(output);
2022
+ else ctx.ui.notify(output, "info");
2023
2023
  return;
2024
2024
  }
2025
2025
 
@@ -2114,14 +2114,14 @@ function parseSubcommand(args: string): { subcommand: Subcommand | null; rest: s
2114
2114
 
2115
2115
  export default function worktreeExtension(pi: ExtensionAPI) {
2116
2116
  for (const customType of [
2117
- MANUAL_OPEN_MESSAGE_TYPE,
2118
- RESTORE_STASH_MESSAGE_TYPE,
2119
- SCRIPT_RERUN_MESSAGE_TYPE,
2117
+ MANUAL_OPEN_ENTRY_TYPE,
2118
+ RESTORE_STASH_ENTRY_TYPE,
2119
+ SCRIPT_RERUN_ENTRY_TYPE,
2120
2120
  ]) {
2121
- pi.registerMessageRenderer(customType, (message, _options, theme) => {
2122
- const details = message.details as CommandMessageDetails | undefined;
2121
+ pi.registerEntryRenderer<CommandMessageDetails>(customType, (entry, _options, theme) => {
2122
+ const details = entry.data;
2123
2123
  if (!details || typeof details.intro !== "string" || typeof details.command !== "string") {
2124
- return new Text(typeof message.content === "string" ? message.content : "", 0, 0);
2124
+ return undefined;
2125
2125
  }
2126
2126
 
2127
2127
  const box = new Box(1, 1, (text) => theme.bg("customMessageBg", text));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tau-coding-agent",
3
- "version": "0.1.3",
3
+ "version": "0.1.5",
4
4
  "description": "Opinionated Pi package with web search, review workflows, sandboxing, memory, usage reporting, skills, and a theme",
5
5
  "keywords": [
6
6
  "agent-tools",
@@ -35,10 +35,10 @@
35
35
  "turndown-plugin-gfm": "^1.0.2"
36
36
  },
37
37
  "peerDependencies": {
38
- "@mariozechner/pi-agent-core": "*",
39
- "@mariozechner/pi-ai": "*",
40
- "@mariozechner/pi-coding-agent": "*",
41
- "@mariozechner/pi-tui": "*",
38
+ "@earendil-works/pi-agent-core": "*",
39
+ "@earendil-works/pi-ai": "*",
40
+ "@earendil-works/pi-coding-agent": "*",
41
+ "@earendil-works/pi-tui": "*",
42
42
  "typebox": "*"
43
43
  },
44
44
  "engines": {
@@ -53,13 +53,13 @@
53
53
  "extensions/git-diff-stats.ts",
54
54
  "extensions/git-pr-status.ts",
55
55
  "extensions/insights.ts",
56
- "extensions/interlude.ts",
56
+ "extensions/stash.ts",
57
57
  "extensions/loop.ts",
58
58
  "extensions/memory.ts",
59
59
  "extensions/notify.ts",
60
60
  "extensions/openai-fast.ts",
61
61
  "extensions/openai-verbosity.ts",
62
- "extensions/review.ts",
62
+ "extensions/review/index.ts",
63
63
  "extensions/sandbox/index.ts",
64
64
  "extensions/tool-display-mode.ts",
65
65
  "extensions/usage/index.ts",
@@ -12,6 +12,7 @@ Use this skill to reimplement the current branch on a new branch with a clean, n
12
12
  1. **Validate the source branch**
13
13
  - Ensure no uncommitted changes or merge conflicts
14
14
  - Confirm it is up to date with `main`
15
+ - Confirm `main` is up to date with `origin/main`
15
16
 
16
17
  2. **Analyze the diff**
17
18
  - Study all changes between source branch and `main`
@@ -11,7 +11,7 @@ Use this skill as the playbook for producing reviewable commits and a clean, con
11
11
 
12
12
  1. Check what files have changed
13
13
  2. If there are no changes to commit, inform the user and stop
14
- 3. If there are unstaged changes, stage them with `git add`
14
+ 3. If there are unstaged changes, stage relevant hunks or files with `git add -p` or `git add`
15
15
 
16
16
  Rules:
17
17
 
@@ -21,7 +21,7 @@ Rules:
21
21
 
22
22
  ## Phase 2: Generate commit message
23
23
 
24
- 1. Remember commit messages best practices
24
+ 1. Remember commit message best practices
25
25
  2. Write a short subject line:
26
26
  - Up to 50 chars
27
27
  - Start subject with a capital letter, don’t end with a period
@@ -1,12 +1,21 @@
1
1
  #!/usr/bin/env node
2
2
  import { spawnSync } from "node:child_process";
3
3
  import { existsSync, readFileSync } from "node:fs";
4
- import { homedir } from "node:os";
5
4
  import path from "node:path";
5
+ import { getAgentDir } from "@earendil-works/pi-coding-agent";
6
6
  import { fileURLToPath } from "node:url";
7
7
 
8
- const THINKING_LEVEL = "xhigh";
8
+ const THINKING_LEVEL = "max";
9
9
  const SCRIPT_DIR = path.dirname(fileURLToPath(import.meta.url));
10
+ const BARE_PI_ARGS = [
11
+ "-p",
12
+ "--no-session",
13
+ "--no-tools",
14
+ "--no-extensions",
15
+ "--no-skills",
16
+ "--no-prompt-templates",
17
+ "--no-themes",
18
+ ];
10
19
 
11
20
  const FAMILY_ORDER = {
12
21
  openai: ["anthropic", "google", "openai"],
@@ -47,11 +56,15 @@ if (bundle.status !== 0) {
47
56
  process.exit(bundle.status ?? 1);
48
57
  }
49
58
 
50
- const pi = spawnSync("pi", ["-p", "--no-tools", "--model", oracleModel, "--thinking", THINKING_LEVEL], {
51
- cwd: repoRoot(),
52
- input: bundle.stdout,
53
- stdio: ["pipe", "inherit", "inherit"],
54
- });
59
+ const pi = spawnSync(
60
+ "pi",
61
+ [...BARE_PI_ARGS, "--model", oracleModel, "--thinking", THINKING_LEVEL],
62
+ {
63
+ cwd: repoRoot(),
64
+ input: bundle.stdout,
65
+ stdio: ["pipe", "inherit", "inherit"],
66
+ },
67
+ );
55
68
 
56
69
  if (pi.error) die(pi.error.message);
57
70
  process.exit(pi.status ?? 1);
@@ -75,7 +88,12 @@ function parseArgs(argv) {
75
88
  }
76
89
  }
77
90
 
78
- return { bundleArgs, currentModel: currentModel ? normalizeModelSpec(currentModel) : undefined, model, listModels };
91
+ return {
92
+ bundleArgs,
93
+ currentModel: currentModel ? normalizeModelSpec(currentModel) : undefined,
94
+ model,
95
+ listModels,
96
+ };
79
97
  }
80
98
 
81
99
  function requireValue(argv, index, flag) {
@@ -85,8 +103,7 @@ function requireValue(argv, index, flag) {
85
103
  }
86
104
 
87
105
  function readSettings() {
88
- const agentDir = process.env.PI_CODING_AGENT_DIR ?? path.join(homedir(), ".pi", "agent");
89
- const settingsPath = path.join(agentDir, "settings.json");
106
+ const settingsPath = path.join(getAgentDir(), "settings.json");
90
107
  if (!existsSync(settingsPath)) return {};
91
108
 
92
109
  try {
@@ -161,7 +178,6 @@ function providerScore(provider, family) {
161
178
  }
162
179
 
163
180
  if (family === "google") {
164
- if (normalized === "google-gemini-cli") return 700;
165
181
  if (normalized === "google") return 600;
166
182
  if (normalized === "github-copilot") return 500;
167
183
  if (normalized.includes("vertex")) return 450;
@@ -219,7 +235,7 @@ function modelFamily(spec) {
219
235
  }
220
236
 
221
237
  function normalizeModelSpec(spec) {
222
- return String(spec).trim().replace(/:(off|minimal|low|medium|high|xhigh)$/i, "");
238
+ return String(spec).trim().replace(/:(off|minimal|low|medium|high|xhigh|max)$/i, "");
223
239
  }
224
240
 
225
241
  function printModelPlan(models, enabledModels, currentModel, currentFamily) {
@@ -1,5 +1,5 @@
1
1
  {
2
- "$schema": "https://raw.githubusercontent.com/badlogic/pi-mono/main/packages/coding-agent/src/modes/interactive/theme/theme-schema.json",
2
+ "$schema": "https://raw.githubusercontent.com/earendil-works/pi/main/packages/coding-agent/src/modes/interactive/theme/theme-schema.json",
3
3
  "name": "tau-dark",
4
4
  "vars": {
5
5
  "accent": "#8abeb7",
@@ -74,6 +74,7 @@
74
74
  "thinkingMedium": "#6f9bb3",
75
75
  "thinkingHigh": "#78a8a1",
76
76
  "thinkingXhigh": "accent",
77
+ "thinkingMax": "#a8d8d1",
77
78
 
78
79
  "bashMode": "green"
79
80
  },