@oh-my-pi/pi-coding-agent 1.341.0 → 2.1.1337

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 (158) hide show
  1. package/CHANGELOG.md +86 -0
  2. package/README.md +1 -1
  3. package/examples/custom-tools/subagent/index.ts +1 -1
  4. package/package.json +10 -9
  5. package/src/bun-imports.d.ts +16 -0
  6. package/src/cli/args.ts +5 -6
  7. package/src/cli/file-processor.ts +3 -3
  8. package/src/cli/list-models.ts +2 -2
  9. package/src/cli/plugin-cli.ts +1 -1
  10. package/src/cli/session-picker.ts +2 -2
  11. package/src/cli/update-cli.ts +273 -0
  12. package/src/cli.ts +1 -1
  13. package/src/config.ts +23 -75
  14. package/src/core/agent-session.ts +158 -16
  15. package/src/core/auth-storage.ts +2 -3
  16. package/src/core/bash-executor.ts +50 -10
  17. package/src/core/compaction/branch-summarization.ts +5 -5
  18. package/src/core/compaction/compaction.ts +3 -3
  19. package/src/core/compaction/index.ts +3 -3
  20. package/src/core/custom-commands/bundled/review/index.ts +156 -0
  21. package/src/core/custom-commands/index.ts +15 -0
  22. package/src/core/custom-commands/loader.ts +232 -0
  23. package/src/core/custom-commands/types.ts +112 -0
  24. package/src/core/custom-tools/index.ts +3 -3
  25. package/src/core/custom-tools/loader.ts +10 -8
  26. package/src/core/custom-tools/types.ts +11 -6
  27. package/src/core/custom-tools/wrapper.ts +2 -1
  28. package/src/core/exec.ts +22 -12
  29. package/src/core/export-html/index.ts +38 -123
  30. package/src/core/export-html/template.css +0 -7
  31. package/src/core/export-html/template.html +3 -4
  32. package/src/core/export-html/template.macro.ts +24 -0
  33. package/src/core/file-mentions.ts +54 -0
  34. package/src/core/hooks/index.ts +5 -5
  35. package/src/core/hooks/loader.ts +21 -16
  36. package/src/core/hooks/runner.ts +6 -6
  37. package/src/core/hooks/tool-wrapper.ts +2 -2
  38. package/src/core/hooks/types.ts +12 -15
  39. package/src/core/index.ts +6 -6
  40. package/src/core/logger.ts +112 -0
  41. package/src/core/mcp/client.ts +3 -3
  42. package/src/core/mcp/config.ts +1 -1
  43. package/src/core/mcp/index.ts +12 -12
  44. package/src/core/mcp/loader.ts +2 -2
  45. package/src/core/mcp/manager.ts +6 -6
  46. package/src/core/mcp/tool-bridge.ts +3 -3
  47. package/src/core/mcp/transports/http.ts +1 -1
  48. package/src/core/mcp/transports/index.ts +2 -2
  49. package/src/core/mcp/transports/stdio.ts +1 -1
  50. package/src/core/messages.ts +22 -0
  51. package/src/core/model-registry.ts +2 -2
  52. package/src/core/model-resolver.ts +2 -2
  53. package/src/core/plugins/doctor.ts +1 -1
  54. package/src/core/plugins/index.ts +6 -6
  55. package/src/core/plugins/installer.ts +4 -4
  56. package/src/core/plugins/loader.ts +4 -9
  57. package/src/core/plugins/manager.ts +5 -5
  58. package/src/core/plugins/paths.ts +3 -3
  59. package/src/core/sdk.ts +77 -35
  60. package/src/core/session-manager.ts +6 -6
  61. package/src/core/settings-manager.ts +16 -3
  62. package/src/core/skills.ts +5 -5
  63. package/src/core/slash-commands.ts +60 -45
  64. package/src/core/system-prompt.ts +6 -6
  65. package/src/core/title-generator.ts +2 -2
  66. package/src/core/tools/bash.ts +32 -155
  67. package/src/core/tools/context.ts +2 -2
  68. package/src/core/tools/edit-diff.ts +3 -3
  69. package/src/core/tools/edit.ts +18 -5
  70. package/src/core/tools/exa/company.ts +3 -3
  71. package/src/core/tools/exa/index.ts +16 -17
  72. package/src/core/tools/exa/linkedin.ts +3 -3
  73. package/src/core/tools/exa/mcp-client.ts +9 -9
  74. package/src/core/tools/exa/render.ts +5 -5
  75. package/src/core/tools/exa/researcher.ts +3 -3
  76. package/src/core/tools/exa/search.ts +6 -5
  77. package/src/core/tools/exa/types.ts +5 -6
  78. package/src/core/tools/exa/websets.ts +3 -3
  79. package/src/core/tools/find.ts +3 -3
  80. package/src/core/tools/grep.ts +3 -3
  81. package/src/core/tools/index.ts +48 -34
  82. package/src/core/tools/ls.ts +4 -4
  83. package/src/core/tools/lsp/client.ts +161 -90
  84. package/src/core/tools/lsp/config.ts +1 -1
  85. package/src/core/tools/lsp/edits.ts +2 -2
  86. package/src/core/tools/lsp/index.ts +15 -13
  87. package/src/core/tools/lsp/render.ts +2 -2
  88. package/src/core/tools/lsp/rust-analyzer.ts +3 -3
  89. package/src/core/tools/lsp/utils.ts +1 -1
  90. package/src/core/tools/notebook.ts +1 -1
  91. package/src/core/tools/output.ts +175 -0
  92. package/src/core/tools/read.ts +7 -7
  93. package/src/core/tools/renderers.ts +92 -13
  94. package/src/core/tools/review.ts +268 -0
  95. package/src/core/tools/task/agents.ts +22 -38
  96. package/src/core/tools/task/bundled-agents/reviewer.md +52 -37
  97. package/src/core/tools/task/commands.ts +31 -10
  98. package/src/core/tools/task/discovery.ts +2 -2
  99. package/src/core/tools/task/executor.ts +145 -28
  100. package/src/core/tools/task/index.ts +78 -30
  101. package/src/core/tools/task/model-resolver.ts +30 -20
  102. package/src/core/tools/task/parallel.ts +1 -1
  103. package/src/core/tools/task/render.ts +219 -30
  104. package/src/core/tools/task/subprocess-tool-registry.ts +89 -0
  105. package/src/core/tools/task/types.ts +36 -2
  106. package/src/core/tools/web-fetch.ts +5 -3
  107. package/src/core/tools/web-search/auth.ts +1 -1
  108. package/src/core/tools/web-search/index.ts +17 -15
  109. package/src/core/tools/web-search/providers/anthropic.ts +2 -2
  110. package/src/core/tools/web-search/providers/exa.ts +3 -5
  111. package/src/core/tools/web-search/providers/perplexity.ts +1 -1
  112. package/src/core/tools/web-search/render.ts +3 -3
  113. package/src/core/tools/write.ts +4 -4
  114. package/src/index.ts +29 -18
  115. package/src/main.ts +50 -33
  116. package/src/migrations.ts +3 -3
  117. package/src/modes/index.ts +5 -5
  118. package/src/modes/interactive/components/armin.ts +1 -1
  119. package/src/modes/interactive/components/assistant-message.ts +1 -1
  120. package/src/modes/interactive/components/bash-execution.ts +4 -4
  121. package/src/modes/interactive/components/bordered-loader.ts +2 -2
  122. package/src/modes/interactive/components/branch-summary-message.ts +2 -2
  123. package/src/modes/interactive/components/compaction-summary-message.ts +2 -2
  124. package/src/modes/interactive/components/diff.ts +1 -1
  125. package/src/modes/interactive/components/dynamic-border.ts +1 -1
  126. package/src/modes/interactive/components/footer.ts +5 -5
  127. package/src/modes/interactive/components/hook-editor.ts +2 -2
  128. package/src/modes/interactive/components/hook-input.ts +2 -2
  129. package/src/modes/interactive/components/hook-message.ts +3 -3
  130. package/src/modes/interactive/components/hook-selector.ts +2 -2
  131. package/src/modes/interactive/components/model-selector.ts +281 -59
  132. package/src/modes/interactive/components/oauth-selector.ts +3 -3
  133. package/src/modes/interactive/components/plugin-settings.ts +4 -4
  134. package/src/modes/interactive/components/queue-mode-selector.ts +2 -2
  135. package/src/modes/interactive/components/session-selector.ts +4 -4
  136. package/src/modes/interactive/components/settings-defs.ts +1 -1
  137. package/src/modes/interactive/components/settings-selector.ts +5 -5
  138. package/src/modes/interactive/components/show-images-selector.ts +2 -2
  139. package/src/modes/interactive/components/theme-selector.ts +2 -2
  140. package/src/modes/interactive/components/thinking-selector.ts +2 -2
  141. package/src/modes/interactive/components/tool-execution.ts +26 -8
  142. package/src/modes/interactive/components/tree-selector.ts +3 -3
  143. package/src/modes/interactive/components/user-message-selector.ts +2 -2
  144. package/src/modes/interactive/components/user-message.ts +1 -1
  145. package/src/modes/interactive/components/welcome.ts +2 -2
  146. package/src/modes/interactive/interactive-mode.ts +86 -42
  147. package/src/modes/interactive/theme/theme.ts +15 -17
  148. package/src/modes/print-mode.ts +4 -3
  149. package/src/modes/rpc/rpc-client.ts +4 -4
  150. package/src/modes/rpc/rpc-mode.ts +22 -12
  151. package/src/modes/rpc/rpc-types.ts +3 -3
  152. package/src/utils/changelog.ts +2 -2
  153. package/src/utils/clipboard.ts +1 -1
  154. package/src/utils/shell-snapshot.ts +218 -0
  155. package/src/utils/shell.ts +93 -13
  156. package/src/utils/tools-manager.ts +1 -1
  157. package/examples/custom-tools/subagent/agents/reviewer.md +0 -35
  158. package/src/core/tools/exa/logger.ts +0 -56
@@ -1,7 +1,58 @@
1
- import { existsSync } from "node:fs";
2
- import { SettingsManager } from "../core/settings-manager.js";
1
+ import { accessSync, constants, existsSync } from "node:fs";
2
+ import { SettingsManager } from "../core/settings-manager";
3
+
4
+ export interface ShellConfig {
5
+ shell: string;
6
+ args: string[];
7
+ env: Record<string, string | undefined>;
8
+ prefix: string | undefined;
9
+ }
10
+
11
+ let cachedShellConfig: ShellConfig | null = null;
12
+
13
+ /**
14
+ * Check if a shell binary is executable.
15
+ */
16
+ function isExecutable(path: string): boolean {
17
+ try {
18
+ accessSync(path, constants.X_OK);
19
+ return true;
20
+ } catch {
21
+ return false;
22
+ }
23
+ }
24
+
25
+ /**
26
+ * Build the spawn environment (cached).
27
+ */
28
+ function buildSpawnEnv(shell: string): Record<string, string | undefined> {
29
+ const noCI = process.env.PI_BASH_NO_CI || process.env.CLAUDE_BASH_NO_CI;
30
+ return {
31
+ ...process.env,
32
+ SHELL: shell,
33
+ GIT_EDITOR: "true",
34
+ GPG_TTY: "not a tty",
35
+ PICODE: "1",
36
+ CLAUDECODE: "1",
37
+ ...(noCI ? {} : { CI: "true" }),
38
+ };
39
+ }
40
+
41
+ /**
42
+ * Get shell args, optionally including login shell flag.
43
+ * Supports PI_BASH_NO_LOGIN and CLAUDE_BASH_NO_LOGIN to skip -l.
44
+ */
45
+ function getShellArgs(): string[] {
46
+ const noLogin = process.env.PI_BASH_NO_LOGIN || process.env.CLAUDE_BASH_NO_LOGIN;
47
+ return noLogin ? ["-c"] : ["-l", "-c"];
48
+ }
3
49
 
4
- let cachedShellConfig: { shell: string; args: string[] } | null = null;
50
+ /**
51
+ * Get shell prefix for wrapping commands (profilers, strace, etc.).
52
+ */
53
+ function getShellPrefix(): string | undefined {
54
+ return process.env.PI_SHELL_PREFIX || process.env.CLAUDE_CODE_SHELL_PREFIX;
55
+ }
5
56
 
6
57
  /**
7
58
  * Find bash executable on PATH (Windows)
@@ -21,15 +72,27 @@ function findBashOnPath(): string | null {
21
72
  return null;
22
73
  }
23
74
 
75
+ /**
76
+ * Build full shell config from a shell path.
77
+ */
78
+ function buildConfig(shell: string): ShellConfig {
79
+ return {
80
+ shell,
81
+ args: getShellArgs(),
82
+ env: buildSpawnEnv(shell),
83
+ prefix: getShellPrefix(),
84
+ };
85
+ }
86
+
24
87
  /**
25
88
  * Get shell configuration based on platform.
26
89
  * Resolution order:
27
90
  * 1. User-specified shellPath in settings.json
28
91
  * 2. On Windows: Git Bash in known locations, then bash on PATH
29
- * 3. On Unix: /bin/bash
92
+ * 3. On Unix: $SHELL if bash/zsh, then fallback paths
30
93
  * 4. Fallback: sh
31
94
  */
32
- export function getShellConfig(): { shell: string; args: string[] } {
95
+ export function getShellConfig(): ShellConfig {
33
96
  if (cachedShellConfig) {
34
97
  return cachedShellConfig;
35
98
  }
@@ -40,7 +103,7 @@ export function getShellConfig(): { shell: string; args: string[] } {
40
103
  // 1. Check user-specified shell path
41
104
  if (customShellPath) {
42
105
  if (existsSync(customShellPath)) {
43
- cachedShellConfig = { shell: customShellPath, args: ["-c"] };
106
+ cachedShellConfig = buildConfig(customShellPath);
44
107
  return cachedShellConfig;
45
108
  }
46
109
  throw new Error(
@@ -62,7 +125,7 @@ export function getShellConfig(): { shell: string; args: string[] } {
62
125
 
63
126
  for (const path of paths) {
64
127
  if (existsSync(path)) {
65
- cachedShellConfig = { shell: path, args: ["-c"] };
128
+ cachedShellConfig = buildConfig(path);
66
129
  return cachedShellConfig;
67
130
  }
68
131
  }
@@ -70,7 +133,7 @@ export function getShellConfig(): { shell: string; args: string[] } {
70
133
  // 3. Fallback: search bash.exe on PATH (Cygwin, MSYS2, WSL, etc.)
71
134
  const bashOnPath = findBashOnPath();
72
135
  if (bashOnPath) {
73
- cachedShellConfig = { shell: bashOnPath, args: ["-c"] };
136
+ cachedShellConfig = buildConfig(bashOnPath);
74
137
  return cachedShellConfig;
75
138
  }
76
139
 
@@ -83,21 +146,38 @@ export function getShellConfig(): { shell: string; args: string[] } {
83
146
  );
84
147
  }
85
148
 
86
- // Unix: prefer user's shell from $SHELL, fallback to bash, then sh
149
+ // Unix: prefer user's shell from $SHELL if it's bash/zsh and executable
87
150
  const userShell = process.env.SHELL;
88
- if (userShell && existsSync(userShell)) {
89
- cachedShellConfig = { shell: userShell, args: ["-c"] };
151
+ const isValidShell = userShell && (userShell.includes("bash") || userShell.includes("zsh"));
152
+ if (isValidShell && isExecutable(userShell)) {
153
+ cachedShellConfig = buildConfig(userShell);
90
154
  return cachedShellConfig;
91
155
  }
92
156
 
157
+ // Fallback paths (Claude's approach: check known locations)
158
+ const fallbackPaths = ["/bin", "/usr/bin", "/usr/local/bin", "/opt/homebrew/bin"];
159
+ const preferZsh = !userShell?.includes("bash");
160
+ const shellOrder = preferZsh ? ["zsh", "bash"] : ["bash", "zsh"];
161
+
162
+ for (const shellName of shellOrder) {
163
+ for (const dir of fallbackPaths) {
164
+ const shellPath = `${dir}/${shellName}`;
165
+ if (isExecutable(shellPath)) {
166
+ cachedShellConfig = buildConfig(shellPath);
167
+ return cachedShellConfig;
168
+ }
169
+ }
170
+ }
171
+
172
+ // Last resort: use Bun.which
93
173
  const bashPath = Bun.which("bash");
94
174
  if (bashPath) {
95
- cachedShellConfig = { shell: bashPath, args: ["-c"] };
175
+ cachedShellConfig = buildConfig(bashPath);
96
176
  return cachedShellConfig;
97
177
  }
98
178
 
99
179
  const shPath = Bun.which("sh");
100
- cachedShellConfig = { shell: shPath || "sh", args: ["-c"] };
180
+ cachedShellConfig = buildConfig(shPath || "sh");
101
181
  return cachedShellConfig;
102
182
  }
103
183
 
@@ -2,7 +2,7 @@ import { chmodSync, createWriteStream, existsSync, mkdirSync, renameSync, rmSync
2
2
  import { arch, platform } from "node:os";
3
3
  import { join } from "node:path";
4
4
  import chalk from "chalk";
5
- import { APP_NAME, getToolsDir } from "../config.js";
5
+ import { APP_NAME, getToolsDir } from "../config";
6
6
 
7
7
  const TOOLS_DIR = getToolsDir();
8
8
 
@@ -1,35 +0,0 @@
1
- ---
2
- name: reviewer
3
- description: Code review specialist for quality and security analysis
4
- tools: read, grep, find, ls, bash
5
- model: claude-sonnet-4-5
6
- ---
7
-
8
- You are a senior code reviewer. Analyze code for quality, security, and maintainability.
9
-
10
- Bash is for read-only commands only: `git diff`, `git log`, `git show`. Do NOT modify files or run builds.
11
- Assume tool permissions are not perfectly enforceable; keep all bash usage strictly read-only.
12
-
13
- Strategy:
14
- 1. Run `git diff` to see recent changes (if applicable)
15
- 2. Read the modified files
16
- 3. Check for bugs, security issues, code smells
17
-
18
- Output format:
19
-
20
- ## Files Reviewed
21
- - `path/to/file.ts` (lines X-Y)
22
-
23
- ## Critical (must fix)
24
- - `file.ts:42` - Issue description
25
-
26
- ## Warnings (should fix)
27
- - `file.ts:100` - Issue description
28
-
29
- ## Suggestions (consider)
30
- - `file.ts:150` - Improvement idea
31
-
32
- ## Summary
33
- Overall assessment in 2-3 sentences.
34
-
35
- Be specific with file paths and line numbers.
@@ -1,56 +0,0 @@
1
- /**
2
- * Exa Error Logger
3
- *
4
- * Append-only logging to ~/.pi/ for debugging production issues.
5
- */
6
-
7
- import { appendFileSync, existsSync, mkdirSync } from "fs";
8
- import { homedir } from "os";
9
- import { join } from "path";
10
- import { CONFIG_DIR_NAME } from "../../../config.js";
11
-
12
- /** Get the base config directory (e.g., ~/.pi/) */
13
- function getConfigDir(): string {
14
- return join(homedir(), CONFIG_DIR_NAME);
15
- }
16
-
17
- /** Log file paths */
18
- const LOG_FILES = {
19
- exa: "exa_errors.log",
20
- view: "view_errors.log",
21
- } as const;
22
-
23
- type LogType = keyof typeof LOG_FILES;
24
-
25
- /** Format a log entry with timestamp */
26
- function formatEntry(message: string, context?: Record<string, unknown>): string {
27
- const timestamp = new Date().toISOString();
28
- const contextStr = context ? ` ${JSON.stringify(context)}` : "";
29
- return `[${timestamp}] ${message}${contextStr}\n`;
30
- }
31
-
32
- /** Append to log file (creates directory if needed) */
33
- export function logError(type: LogType, message: string, context?: Record<string, unknown>): void {
34
- try {
35
- const configDir = getConfigDir();
36
- if (!existsSync(configDir)) {
37
- mkdirSync(configDir, { recursive: true });
38
- }
39
-
40
- const logPath = join(configDir, LOG_FILES[type]);
41
- const entry = formatEntry(message, context);
42
- appendFileSync(logPath, entry);
43
- } catch {
44
- // Silently ignore logging failures - we don't want to break tool execution
45
- }
46
- }
47
-
48
- /** Log MCP fetch/call errors */
49
- export function logExaError(message: string, context?: Record<string, unknown>): void {
50
- logError("exa", message, context);
51
- }
52
-
53
- /** Log render/view errors */
54
- export function logViewError(message: string, context?: Record<string, unknown>): void {
55
- logError("view", message, context);
56
- }