@oh-my-pi/pi-coding-agent 1.337.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.
Files changed (224) hide show
  1. package/CHANGELOG.md +1228 -0
  2. package/README.md +1041 -0
  3. package/docs/compaction.md +403 -0
  4. package/docs/custom-tools.md +541 -0
  5. package/docs/extension-loading.md +1004 -0
  6. package/docs/hooks.md +867 -0
  7. package/docs/rpc.md +1040 -0
  8. package/docs/sdk.md +994 -0
  9. package/docs/session-tree-plan.md +441 -0
  10. package/docs/session.md +240 -0
  11. package/docs/skills.md +290 -0
  12. package/docs/theme.md +637 -0
  13. package/docs/tree.md +197 -0
  14. package/docs/tui.md +341 -0
  15. package/examples/README.md +21 -0
  16. package/examples/custom-tools/README.md +124 -0
  17. package/examples/custom-tools/hello/index.ts +20 -0
  18. package/examples/custom-tools/question/index.ts +84 -0
  19. package/examples/custom-tools/subagent/README.md +172 -0
  20. package/examples/custom-tools/subagent/agents/planner.md +37 -0
  21. package/examples/custom-tools/subagent/agents/reviewer.md +35 -0
  22. package/examples/custom-tools/subagent/agents/scout.md +50 -0
  23. package/examples/custom-tools/subagent/agents/worker.md +24 -0
  24. package/examples/custom-tools/subagent/agents.ts +156 -0
  25. package/examples/custom-tools/subagent/commands/implement-and-review.md +10 -0
  26. package/examples/custom-tools/subagent/commands/implement.md +10 -0
  27. package/examples/custom-tools/subagent/commands/scout-and-plan.md +9 -0
  28. package/examples/custom-tools/subagent/index.ts +1002 -0
  29. package/examples/custom-tools/todo/index.ts +212 -0
  30. package/examples/hooks/README.md +56 -0
  31. package/examples/hooks/auto-commit-on-exit.ts +49 -0
  32. package/examples/hooks/confirm-destructive.ts +59 -0
  33. package/examples/hooks/custom-compaction.ts +116 -0
  34. package/examples/hooks/dirty-repo-guard.ts +52 -0
  35. package/examples/hooks/file-trigger.ts +41 -0
  36. package/examples/hooks/git-checkpoint.ts +53 -0
  37. package/examples/hooks/handoff.ts +150 -0
  38. package/examples/hooks/permission-gate.ts +34 -0
  39. package/examples/hooks/protected-paths.ts +30 -0
  40. package/examples/hooks/qna.ts +119 -0
  41. package/examples/hooks/snake.ts +343 -0
  42. package/examples/hooks/status-line.ts +40 -0
  43. package/examples/sdk/01-minimal.ts +22 -0
  44. package/examples/sdk/02-custom-model.ts +49 -0
  45. package/examples/sdk/03-custom-prompt.ts +44 -0
  46. package/examples/sdk/04-skills.ts +44 -0
  47. package/examples/sdk/05-tools.ts +90 -0
  48. package/examples/sdk/06-hooks.ts +61 -0
  49. package/examples/sdk/07-context-files.ts +36 -0
  50. package/examples/sdk/08-slash-commands.ts +42 -0
  51. package/examples/sdk/09-api-keys-and-oauth.ts +55 -0
  52. package/examples/sdk/10-settings.ts +38 -0
  53. package/examples/sdk/11-sessions.ts +48 -0
  54. package/examples/sdk/12-full-control.ts +95 -0
  55. package/examples/sdk/README.md +154 -0
  56. package/package.json +81 -0
  57. package/src/cli/args.ts +246 -0
  58. package/src/cli/file-processor.ts +72 -0
  59. package/src/cli/list-models.ts +104 -0
  60. package/src/cli/plugin-cli.ts +650 -0
  61. package/src/cli/session-picker.ts +41 -0
  62. package/src/cli.ts +10 -0
  63. package/src/commands/init.md +20 -0
  64. package/src/config.ts +159 -0
  65. package/src/core/agent-session.ts +1900 -0
  66. package/src/core/auth-storage.ts +236 -0
  67. package/src/core/bash-executor.ts +196 -0
  68. package/src/core/compaction/branch-summarization.ts +343 -0
  69. package/src/core/compaction/compaction.ts +742 -0
  70. package/src/core/compaction/index.ts +7 -0
  71. package/src/core/compaction/utils.ts +154 -0
  72. package/src/core/custom-tools/index.ts +21 -0
  73. package/src/core/custom-tools/loader.ts +248 -0
  74. package/src/core/custom-tools/types.ts +169 -0
  75. package/src/core/custom-tools/wrapper.ts +28 -0
  76. package/src/core/exec.ts +129 -0
  77. package/src/core/export-html/index.ts +211 -0
  78. package/src/core/export-html/template.css +781 -0
  79. package/src/core/export-html/template.html +54 -0
  80. package/src/core/export-html/template.js +1185 -0
  81. package/src/core/export-html/vendor/highlight.min.js +1213 -0
  82. package/src/core/export-html/vendor/marked.min.js +6 -0
  83. package/src/core/hooks/index.ts +16 -0
  84. package/src/core/hooks/loader.ts +312 -0
  85. package/src/core/hooks/runner.ts +434 -0
  86. package/src/core/hooks/tool-wrapper.ts +99 -0
  87. package/src/core/hooks/types.ts +773 -0
  88. package/src/core/index.ts +52 -0
  89. package/src/core/mcp/client.ts +158 -0
  90. package/src/core/mcp/config.ts +154 -0
  91. package/src/core/mcp/index.ts +45 -0
  92. package/src/core/mcp/loader.ts +68 -0
  93. package/src/core/mcp/manager.ts +181 -0
  94. package/src/core/mcp/tool-bridge.ts +148 -0
  95. package/src/core/mcp/transports/http.ts +316 -0
  96. package/src/core/mcp/transports/index.ts +6 -0
  97. package/src/core/mcp/transports/stdio.ts +252 -0
  98. package/src/core/mcp/types.ts +220 -0
  99. package/src/core/messages.ts +189 -0
  100. package/src/core/model-registry.ts +317 -0
  101. package/src/core/model-resolver.ts +393 -0
  102. package/src/core/plugins/doctor.ts +59 -0
  103. package/src/core/plugins/index.ts +38 -0
  104. package/src/core/plugins/installer.ts +189 -0
  105. package/src/core/plugins/loader.ts +338 -0
  106. package/src/core/plugins/manager.ts +672 -0
  107. package/src/core/plugins/parser.ts +105 -0
  108. package/src/core/plugins/paths.ts +32 -0
  109. package/src/core/plugins/types.ts +190 -0
  110. package/src/core/sdk.ts +760 -0
  111. package/src/core/session-manager.ts +1128 -0
  112. package/src/core/settings-manager.ts +443 -0
  113. package/src/core/skills.ts +437 -0
  114. package/src/core/slash-commands.ts +248 -0
  115. package/src/core/system-prompt.ts +439 -0
  116. package/src/core/timings.ts +25 -0
  117. package/src/core/tools/ask.ts +211 -0
  118. package/src/core/tools/bash-interceptor.ts +120 -0
  119. package/src/core/tools/bash.ts +250 -0
  120. package/src/core/tools/context.ts +32 -0
  121. package/src/core/tools/edit-diff.ts +475 -0
  122. package/src/core/tools/edit.ts +208 -0
  123. package/src/core/tools/exa/company.ts +59 -0
  124. package/src/core/tools/exa/index.ts +64 -0
  125. package/src/core/tools/exa/linkedin.ts +59 -0
  126. package/src/core/tools/exa/logger.ts +56 -0
  127. package/src/core/tools/exa/mcp-client.ts +368 -0
  128. package/src/core/tools/exa/render.ts +196 -0
  129. package/src/core/tools/exa/researcher.ts +90 -0
  130. package/src/core/tools/exa/search.ts +337 -0
  131. package/src/core/tools/exa/types.ts +168 -0
  132. package/src/core/tools/exa/websets.ts +248 -0
  133. package/src/core/tools/find.ts +261 -0
  134. package/src/core/tools/grep.ts +555 -0
  135. package/src/core/tools/index.ts +202 -0
  136. package/src/core/tools/ls.ts +140 -0
  137. package/src/core/tools/lsp/client.ts +605 -0
  138. package/src/core/tools/lsp/config.ts +147 -0
  139. package/src/core/tools/lsp/edits.ts +101 -0
  140. package/src/core/tools/lsp/index.ts +804 -0
  141. package/src/core/tools/lsp/render.ts +447 -0
  142. package/src/core/tools/lsp/rust-analyzer.ts +145 -0
  143. package/src/core/tools/lsp/types.ts +463 -0
  144. package/src/core/tools/lsp/utils.ts +486 -0
  145. package/src/core/tools/notebook.ts +229 -0
  146. package/src/core/tools/path-utils.ts +61 -0
  147. package/src/core/tools/read.ts +240 -0
  148. package/src/core/tools/renderers.ts +540 -0
  149. package/src/core/tools/task/agents.ts +153 -0
  150. package/src/core/tools/task/artifacts.ts +114 -0
  151. package/src/core/tools/task/bundled-agents/browser.md +71 -0
  152. package/src/core/tools/task/bundled-agents/explore.md +82 -0
  153. package/src/core/tools/task/bundled-agents/plan.md +54 -0
  154. package/src/core/tools/task/bundled-agents/reviewer.md +59 -0
  155. package/src/core/tools/task/bundled-agents/task.md +53 -0
  156. package/src/core/tools/task/bundled-commands/architect-plan.md +10 -0
  157. package/src/core/tools/task/bundled-commands/implement-with-critic.md +11 -0
  158. package/src/core/tools/task/bundled-commands/implement.md +11 -0
  159. package/src/core/tools/task/commands.ts +213 -0
  160. package/src/core/tools/task/discovery.ts +208 -0
  161. package/src/core/tools/task/executor.ts +367 -0
  162. package/src/core/tools/task/index.ts +388 -0
  163. package/src/core/tools/task/model-resolver.ts +115 -0
  164. package/src/core/tools/task/parallel.ts +38 -0
  165. package/src/core/tools/task/render.ts +232 -0
  166. package/src/core/tools/task/types.ts +99 -0
  167. package/src/core/tools/truncate.ts +265 -0
  168. package/src/core/tools/web-fetch.ts +2370 -0
  169. package/src/core/tools/web-search/auth.ts +193 -0
  170. package/src/core/tools/web-search/index.ts +537 -0
  171. package/src/core/tools/web-search/providers/anthropic.ts +198 -0
  172. package/src/core/tools/web-search/providers/exa.ts +302 -0
  173. package/src/core/tools/web-search/providers/perplexity.ts +195 -0
  174. package/src/core/tools/web-search/render.ts +182 -0
  175. package/src/core/tools/web-search/types.ts +180 -0
  176. package/src/core/tools/write.ts +99 -0
  177. package/src/index.ts +176 -0
  178. package/src/main.ts +464 -0
  179. package/src/migrations.ts +135 -0
  180. package/src/modes/index.ts +43 -0
  181. package/src/modes/interactive/components/armin.ts +382 -0
  182. package/src/modes/interactive/components/assistant-message.ts +86 -0
  183. package/src/modes/interactive/components/bash-execution.ts +196 -0
  184. package/src/modes/interactive/components/bordered-loader.ts +41 -0
  185. package/src/modes/interactive/components/branch-summary-message.ts +42 -0
  186. package/src/modes/interactive/components/compaction-summary-message.ts +45 -0
  187. package/src/modes/interactive/components/custom-editor.ts +122 -0
  188. package/src/modes/interactive/components/diff.ts +147 -0
  189. package/src/modes/interactive/components/dynamic-border.ts +25 -0
  190. package/src/modes/interactive/components/footer.ts +381 -0
  191. package/src/modes/interactive/components/hook-editor.ts +117 -0
  192. package/src/modes/interactive/components/hook-input.ts +64 -0
  193. package/src/modes/interactive/components/hook-message.ts +96 -0
  194. package/src/modes/interactive/components/hook-selector.ts +91 -0
  195. package/src/modes/interactive/components/model-selector.ts +247 -0
  196. package/src/modes/interactive/components/oauth-selector.ts +120 -0
  197. package/src/modes/interactive/components/plugin-settings.ts +479 -0
  198. package/src/modes/interactive/components/queue-mode-selector.ts +56 -0
  199. package/src/modes/interactive/components/session-selector.ts +204 -0
  200. package/src/modes/interactive/components/settings-selector.ts +453 -0
  201. package/src/modes/interactive/components/show-images-selector.ts +45 -0
  202. package/src/modes/interactive/components/theme-selector.ts +62 -0
  203. package/src/modes/interactive/components/thinking-selector.ts +64 -0
  204. package/src/modes/interactive/components/tool-execution.ts +675 -0
  205. package/src/modes/interactive/components/tree-selector.ts +866 -0
  206. package/src/modes/interactive/components/user-message-selector.ts +159 -0
  207. package/src/modes/interactive/components/user-message.ts +18 -0
  208. package/src/modes/interactive/components/visual-truncate.ts +50 -0
  209. package/src/modes/interactive/components/welcome.ts +183 -0
  210. package/src/modes/interactive/interactive-mode.ts +2516 -0
  211. package/src/modes/interactive/theme/dark.json +101 -0
  212. package/src/modes/interactive/theme/light.json +98 -0
  213. package/src/modes/interactive/theme/theme-schema.json +308 -0
  214. package/src/modes/interactive/theme/theme.ts +998 -0
  215. package/src/modes/print-mode.ts +128 -0
  216. package/src/modes/rpc/rpc-client.ts +527 -0
  217. package/src/modes/rpc/rpc-mode.ts +483 -0
  218. package/src/modes/rpc/rpc-types.ts +203 -0
  219. package/src/utils/changelog.ts +99 -0
  220. package/src/utils/clipboard.ts +265 -0
  221. package/src/utils/fuzzy.ts +108 -0
  222. package/src/utils/mime.ts +30 -0
  223. package/src/utils/shell.ts +276 -0
  224. package/src/utils/tools-manager.ts +274 -0
@@ -0,0 +1,147 @@
1
+ import { existsSync, readFileSync } from "node:fs";
2
+ import { homedir } from "node:os";
3
+ import { extname, join } from "node:path";
4
+ import type { ServerConfig } from "./types.js";
5
+
6
+ export interface LspConfig {
7
+ servers: Record<string, ServerConfig>;
8
+ }
9
+
10
+ // Predefined server configurations with capabilities
11
+ export const SERVERS: Record<string, ServerConfig> = {
12
+ "rust-analyzer": {
13
+ command: "rust-analyzer",
14
+ args: [],
15
+ fileTypes: [".rs"],
16
+ rootMarkers: ["Cargo.toml", "rust-analyzer.toml"],
17
+ initOptions: {
18
+ checkOnSave: { command: "clippy" },
19
+ cargo: { allFeatures: true },
20
+ procMacro: { enable: true },
21
+ },
22
+ capabilities: {
23
+ flycheck: true,
24
+ ssr: true,
25
+ expandMacro: true,
26
+ runnables: true,
27
+ relatedTests: true,
28
+ },
29
+ },
30
+ "typescript-language-server": {
31
+ command: "typescript-language-server",
32
+ args: ["--stdio"],
33
+ fileTypes: [".ts", ".tsx", ".js", ".jsx"],
34
+ rootMarkers: ["package.json", "tsconfig.json", "jsconfig.json"],
35
+ },
36
+ gopls: {
37
+ command: "gopls",
38
+ args: ["serve"],
39
+ fileTypes: [".go"],
40
+ rootMarkers: ["go.mod", "go.work"],
41
+ },
42
+ pyright: {
43
+ command: "pyright-langserver",
44
+ args: ["--stdio"],
45
+ fileTypes: [".py"],
46
+ rootMarkers: ["pyproject.toml", "setup.py", "requirements.txt", "Pipfile"],
47
+ },
48
+ zls: {
49
+ command: "zls",
50
+ args: [],
51
+ fileTypes: [".zig"],
52
+ rootMarkers: ["build.zig", "build.zig.zon", "zls.json"],
53
+ },
54
+ clangd: {
55
+ command: "clangd",
56
+ args: ["--background-index"],
57
+ fileTypes: [".c", ".cpp", ".cc", ".cxx", ".h", ".hpp"],
58
+ rootMarkers: ["compile_commands.json", "CMakeLists.txt", ".clangd"],
59
+ },
60
+ "lua-language-server": {
61
+ command: "lua-language-server",
62
+ args: [],
63
+ fileTypes: [".lua"],
64
+ rootMarkers: [".luarc.json", ".luarc.jsonc", ".luacheckrc"],
65
+ },
66
+ };
67
+
68
+ /**
69
+ * Check if any root marker file exists in the directory
70
+ */
71
+ export function hasRootMarkers(cwd: string, markers: string[]): boolean {
72
+ return markers.some((marker) => existsSync(join(cwd, marker)));
73
+ }
74
+
75
+ /**
76
+ * Load LSP configuration.
77
+ *
78
+ * Priority:
79
+ * 1. Project-level config from .pi/lsp.json in cwd
80
+ * 2. User-level config from ~/.pi/lsp.json
81
+ * 3. Auto-detect from project markers + available binaries
82
+ */
83
+ export function loadConfig(cwd: string): LspConfig {
84
+ // Try to load user config
85
+ const configPaths = [join(cwd, ".pi", "lsp.json"), join(homedir(), ".pi", "lsp.json")];
86
+
87
+ for (const configPath of configPaths) {
88
+ if (existsSync(configPath)) {
89
+ try {
90
+ const content = readFileSync(configPath, "utf-8");
91
+ const parsed = JSON.parse(content);
92
+ const servers = parsed.servers || parsed;
93
+
94
+ // Filter to only enabled servers with available commands
95
+ const available: Record<string, ServerConfig> = {};
96
+ for (const [name, config] of Object.entries(servers) as [string, ServerConfig][]) {
97
+ if (config.disabled) continue;
98
+ if (!Bun.which(config.command)) continue;
99
+ available[name] = config;
100
+ }
101
+
102
+ return { servers: available };
103
+ } catch {
104
+ // Ignore parse errors, fall through to auto-detect
105
+ }
106
+ }
107
+ }
108
+
109
+ // Auto-detect: find servers based on project markers AND available binaries
110
+ const detected: Record<string, ServerConfig> = {};
111
+
112
+ for (const [name, config] of Object.entries(SERVERS)) {
113
+ // Check if project has root markers for this language
114
+ if (!hasRootMarkers(cwd, config.rootMarkers)) continue;
115
+
116
+ // Check if the language server binary is available
117
+ if (!Bun.which(config.command)) continue;
118
+
119
+ detected[name] = config;
120
+ }
121
+
122
+ return { servers: detected };
123
+ }
124
+
125
+ /**
126
+ * Find the appropriate server for a file based on extension
127
+ */
128
+ export function getServerForFile(config: LspConfig, filePath: string): [string, ServerConfig] | null {
129
+ const ext = extname(filePath).toLowerCase();
130
+
131
+ for (const [name, serverConfig] of Object.entries(config.servers)) {
132
+ if (serverConfig.fileTypes.includes(ext)) {
133
+ return [name, serverConfig];
134
+ }
135
+ }
136
+ return null;
137
+ }
138
+
139
+ /**
140
+ * Check if a server has a specific capability
141
+ */
142
+ export function hasCapability(
143
+ config: ServerConfig,
144
+ capability: keyof NonNullable<ServerConfig["capabilities"]>,
145
+ ): boolean {
146
+ return config.capabilities?.[capability] === true;
147
+ }
@@ -0,0 +1,101 @@
1
+ import { mkdir, rename, rm } from "node:fs/promises";
2
+ import path from "node:path";
3
+ import type { CreateFile, DeleteFile, RenameFile, TextDocumentEdit, TextEdit, WorkspaceEdit } from "./types.js";
4
+ import { uriToFile } from "./utils.js";
5
+
6
+ // =============================================================================
7
+ // Text Edit Application
8
+ // =============================================================================
9
+
10
+ /**
11
+ * Apply text edits to a file.
12
+ * Edits are applied in reverse order (bottom-to-top) to preserve line/character indices.
13
+ */
14
+ export async function applyTextEdits(filePath: string, edits: TextEdit[]): Promise<void> {
15
+ const content = await Bun.file(filePath).text();
16
+ const lines = content.split("\n");
17
+
18
+ // Sort edits in reverse order (bottom-to-top, right-to-left)
19
+ const sortedEdits = [...edits].sort((a, b) => {
20
+ if (a.range.start.line !== b.range.start.line) {
21
+ return b.range.start.line - a.range.start.line;
22
+ }
23
+ return b.range.start.character - a.range.start.character;
24
+ });
25
+
26
+ for (const edit of sortedEdits) {
27
+ const { start, end } = edit.range;
28
+
29
+ // Single-line edit: replace substring within same line
30
+ if (start.line === end.line) {
31
+ const line = lines[start.line] || "";
32
+ lines[start.line] = line.slice(0, start.character) + edit.newText + line.slice(end.character);
33
+ } else {
34
+ // Multi-line edit: splice across multiple lines
35
+ const startLine = lines[start.line] || "";
36
+ const endLine = lines[end.line] || "";
37
+ const newContent = startLine.slice(0, start.character) + edit.newText + endLine.slice(end.character);
38
+ lines.splice(start.line, end.line - start.line + 1, ...newContent.split("\n"));
39
+ }
40
+ }
41
+
42
+ await Bun.write(filePath, lines.join("\n"));
43
+ }
44
+
45
+ // =============================================================================
46
+ // Workspace Edit Application
47
+ // =============================================================================
48
+
49
+ /**
50
+ * Apply a workspace edit (collection of file changes).
51
+ * Returns array of applied change descriptions.
52
+ */
53
+ export async function applyWorkspaceEdit(edit: WorkspaceEdit, cwd: string): Promise<string[]> {
54
+ const applied: string[] = [];
55
+
56
+ // Handle changes map (legacy format)
57
+ if (edit.changes) {
58
+ for (const [uri, textEdits] of Object.entries(edit.changes)) {
59
+ const filePath = uriToFile(uri);
60
+ await applyTextEdits(filePath, textEdits);
61
+ applied.push(`Applied ${textEdits.length} edit(s) to ${path.relative(cwd, filePath)}`);
62
+ }
63
+ }
64
+
65
+ // Handle documentChanges array (modern format)
66
+ if (edit.documentChanges) {
67
+ for (const change of edit.documentChanges) {
68
+ if ("textDocument" in change && change.textDocument && "edits" in change && change.edits) {
69
+ // TextDocumentEdit
70
+ const docChange = change as TextDocumentEdit;
71
+ const filePath = uriToFile(docChange.textDocument.uri);
72
+ const textEdits = docChange.edits.filter((e): e is TextEdit => "range" in e && "newText" in e);
73
+ await applyTextEdits(filePath, textEdits);
74
+ applied.push(`Applied ${textEdits.length} edit(s) to ${path.relative(cwd, filePath)}`);
75
+ } else if ("kind" in change && change.kind) {
76
+ // Resource operations
77
+ if (change.kind === "create") {
78
+ const createOp = change as CreateFile;
79
+ const filePath = uriToFile(createOp.uri);
80
+ await mkdir(path.dirname(filePath), { recursive: true });
81
+ await Bun.write(filePath, "");
82
+ applied.push(`Created ${path.relative(cwd, filePath)}`);
83
+ } else if (change.kind === "rename") {
84
+ const renameOp = change as RenameFile;
85
+ const oldPath = uriToFile(renameOp.oldUri);
86
+ const newPath = uriToFile(renameOp.newUri);
87
+ await mkdir(path.dirname(newPath), { recursive: true });
88
+ await rename(oldPath, newPath);
89
+ applied.push(`Renamed ${path.relative(cwd, oldPath)} → ${path.relative(cwd, newPath)}`);
90
+ } else if (change.kind === "delete") {
91
+ const deleteOp = change as DeleteFile;
92
+ const filePath = uriToFile(deleteOp.uri);
93
+ await rm(filePath, { recursive: true });
94
+ applied.push(`Deleted ${path.relative(cwd, filePath)}`);
95
+ }
96
+ }
97
+ }
98
+ }
99
+
100
+ return applied;
101
+ }