@oh-my-pi/pi-coding-agent 0.1.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 (337) hide show
  1. package/CHANGELOG.md +1629 -0
  2. package/README.md +1041 -0
  3. package/docs/compaction.md +403 -0
  4. package/docs/config-usage.md +113 -0
  5. package/docs/custom-tools.md +541 -0
  6. package/docs/extension-loading.md +1004 -0
  7. package/docs/hooks.md +867 -0
  8. package/docs/rpc.md +1040 -0
  9. package/docs/sdk.md +994 -0
  10. package/docs/session-tree-plan.md +441 -0
  11. package/docs/session.md +240 -0
  12. package/docs/skills.md +290 -0
  13. package/docs/theme.md +670 -0
  14. package/docs/tree.md +197 -0
  15. package/docs/tui.md +341 -0
  16. package/examples/README.md +21 -0
  17. package/examples/custom-tools/README.md +124 -0
  18. package/examples/custom-tools/hello/index.ts +20 -0
  19. package/examples/custom-tools/question/index.ts +84 -0
  20. package/examples/custom-tools/subagent/README.md +172 -0
  21. package/examples/custom-tools/subagent/agents/planner.md +37 -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 +89 -0
  57. package/src/bun-imports.d.ts +16 -0
  58. package/src/capability/context-file.ts +40 -0
  59. package/src/capability/extension.ts +48 -0
  60. package/src/capability/hook.ts +40 -0
  61. package/src/capability/index.ts +616 -0
  62. package/src/capability/instruction.ts +37 -0
  63. package/src/capability/mcp.ts +52 -0
  64. package/src/capability/prompt.ts +35 -0
  65. package/src/capability/rule.ts +56 -0
  66. package/src/capability/settings.ts +35 -0
  67. package/src/capability/skill.ts +49 -0
  68. package/src/capability/slash-command.ts +40 -0
  69. package/src/capability/system-prompt.ts +35 -0
  70. package/src/capability/tool.ts +38 -0
  71. package/src/capability/types.ts +166 -0
  72. package/src/cli/args.ts +259 -0
  73. package/src/cli/file-processor.ts +121 -0
  74. package/src/cli/list-models.ts +104 -0
  75. package/src/cli/plugin-cli.ts +661 -0
  76. package/src/cli/session-picker.ts +41 -0
  77. package/src/cli/update-cli.ts +274 -0
  78. package/src/cli.ts +10 -0
  79. package/src/config.ts +391 -0
  80. package/src/core/agent-session.ts +2178 -0
  81. package/src/core/auth-storage.ts +258 -0
  82. package/src/core/bash-executor.ts +197 -0
  83. package/src/core/compaction/branch-summarization.ts +315 -0
  84. package/src/core/compaction/compaction.ts +664 -0
  85. package/src/core/compaction/index.ts +7 -0
  86. package/src/core/compaction/utils.ts +153 -0
  87. package/src/core/custom-commands/bundled/review/index.ts +156 -0
  88. package/src/core/custom-commands/index.ts +15 -0
  89. package/src/core/custom-commands/loader.ts +226 -0
  90. package/src/core/custom-commands/types.ts +112 -0
  91. package/src/core/custom-tools/index.ts +22 -0
  92. package/src/core/custom-tools/loader.ts +248 -0
  93. package/src/core/custom-tools/types.ts +185 -0
  94. package/src/core/custom-tools/wrapper.ts +29 -0
  95. package/src/core/exec.ts +139 -0
  96. package/src/core/export-html/index.ts +159 -0
  97. package/src/core/export-html/template.css +774 -0
  98. package/src/core/export-html/template.generated.ts +2 -0
  99. package/src/core/export-html/template.html +45 -0
  100. package/src/core/export-html/template.js +1185 -0
  101. package/src/core/export-html/template.macro.ts +24 -0
  102. package/src/core/file-mentions.ts +54 -0
  103. package/src/core/hooks/index.ts +16 -0
  104. package/src/core/hooks/loader.ts +288 -0
  105. package/src/core/hooks/runner.ts +434 -0
  106. package/src/core/hooks/tool-wrapper.ts +98 -0
  107. package/src/core/hooks/types.ts +770 -0
  108. package/src/core/index.ts +53 -0
  109. package/src/core/logger.ts +112 -0
  110. package/src/core/mcp/client.ts +185 -0
  111. package/src/core/mcp/config.ts +248 -0
  112. package/src/core/mcp/index.ts +45 -0
  113. package/src/core/mcp/loader.ts +99 -0
  114. package/src/core/mcp/manager.ts +235 -0
  115. package/src/core/mcp/tool-bridge.ts +156 -0
  116. package/src/core/mcp/transports/http.ts +316 -0
  117. package/src/core/mcp/transports/index.ts +6 -0
  118. package/src/core/mcp/transports/stdio.ts +252 -0
  119. package/src/core/mcp/types.ts +228 -0
  120. package/src/core/messages.ts +211 -0
  121. package/src/core/model-registry.ts +334 -0
  122. package/src/core/model-resolver.ts +494 -0
  123. package/src/core/plugins/doctor.ts +67 -0
  124. package/src/core/plugins/index.ts +38 -0
  125. package/src/core/plugins/installer.ts +189 -0
  126. package/src/core/plugins/loader.ts +339 -0
  127. package/src/core/plugins/manager.ts +672 -0
  128. package/src/core/plugins/parser.ts +105 -0
  129. package/src/core/plugins/paths.ts +37 -0
  130. package/src/core/plugins/types.ts +190 -0
  131. package/src/core/sdk.ts +900 -0
  132. package/src/core/session-manager.ts +1837 -0
  133. package/src/core/settings-manager.ts +860 -0
  134. package/src/core/skills.ts +352 -0
  135. package/src/core/slash-commands.ts +132 -0
  136. package/src/core/system-prompt.ts +442 -0
  137. package/src/core/timings.ts +25 -0
  138. package/src/core/title-generator.ts +110 -0
  139. package/src/core/tools/ask.ts +193 -0
  140. package/src/core/tools/bash-interceptor.ts +120 -0
  141. package/src/core/tools/bash.ts +91 -0
  142. package/src/core/tools/context.ts +32 -0
  143. package/src/core/tools/edit-diff.ts +487 -0
  144. package/src/core/tools/edit.ts +140 -0
  145. package/src/core/tools/exa/company.ts +59 -0
  146. package/src/core/tools/exa/index.ts +63 -0
  147. package/src/core/tools/exa/linkedin.ts +59 -0
  148. package/src/core/tools/exa/mcp-client.ts +368 -0
  149. package/src/core/tools/exa/render.ts +200 -0
  150. package/src/core/tools/exa/researcher.ts +90 -0
  151. package/src/core/tools/exa/search.ts +338 -0
  152. package/src/core/tools/exa/types.ts +167 -0
  153. package/src/core/tools/exa/websets.ts +248 -0
  154. package/src/core/tools/find.ts +244 -0
  155. package/src/core/tools/grep.ts +584 -0
  156. package/src/core/tools/index.ts +283 -0
  157. package/src/core/tools/ls.ts +142 -0
  158. package/src/core/tools/lsp/client.ts +767 -0
  159. package/src/core/tools/lsp/clients/biome-client.ts +207 -0
  160. package/src/core/tools/lsp/clients/index.ts +49 -0
  161. package/src/core/tools/lsp/clients/lsp-linter-client.ts +98 -0
  162. package/src/core/tools/lsp/config.ts +845 -0
  163. package/src/core/tools/lsp/edits.ts +110 -0
  164. package/src/core/tools/lsp/index.ts +1364 -0
  165. package/src/core/tools/lsp/render.ts +560 -0
  166. package/src/core/tools/lsp/rust-analyzer.ts +145 -0
  167. package/src/core/tools/lsp/types.ts +495 -0
  168. package/src/core/tools/lsp/utils.ts +526 -0
  169. package/src/core/tools/notebook.ts +182 -0
  170. package/src/core/tools/output.ts +198 -0
  171. package/src/core/tools/path-utils.ts +61 -0
  172. package/src/core/tools/read.ts +507 -0
  173. package/src/core/tools/renderers.ts +820 -0
  174. package/src/core/tools/review.ts +275 -0
  175. package/src/core/tools/rulebook.ts +124 -0
  176. package/src/core/tools/task/agents.ts +158 -0
  177. package/src/core/tools/task/artifacts.ts +114 -0
  178. package/src/core/tools/task/commands.ts +157 -0
  179. package/src/core/tools/task/discovery.ts +217 -0
  180. package/src/core/tools/task/executor.ts +531 -0
  181. package/src/core/tools/task/index.ts +548 -0
  182. package/src/core/tools/task/model-resolver.ts +176 -0
  183. package/src/core/tools/task/parallel.ts +38 -0
  184. package/src/core/tools/task/render.ts +502 -0
  185. package/src/core/tools/task/subprocess-tool-registry.ts +89 -0
  186. package/src/core/tools/task/types.ts +142 -0
  187. package/src/core/tools/truncate.ts +265 -0
  188. package/src/core/tools/web-fetch.ts +2511 -0
  189. package/src/core/tools/web-search/auth.ts +199 -0
  190. package/src/core/tools/web-search/index.ts +583 -0
  191. package/src/core/tools/web-search/providers/anthropic.ts +198 -0
  192. package/src/core/tools/web-search/providers/exa.ts +196 -0
  193. package/src/core/tools/web-search/providers/perplexity.ts +195 -0
  194. package/src/core/tools/web-search/render.ts +372 -0
  195. package/src/core/tools/web-search/types.ts +180 -0
  196. package/src/core/tools/write.ts +63 -0
  197. package/src/core/ttsr.ts +211 -0
  198. package/src/core/utils.ts +187 -0
  199. package/src/discovery/agents-md.ts +75 -0
  200. package/src/discovery/builtin.ts +647 -0
  201. package/src/discovery/claude.ts +623 -0
  202. package/src/discovery/cline.ts +104 -0
  203. package/src/discovery/codex.ts +571 -0
  204. package/src/discovery/cursor.ts +266 -0
  205. package/src/discovery/gemini.ts +368 -0
  206. package/src/discovery/github.ts +120 -0
  207. package/src/discovery/helpers.test.ts +127 -0
  208. package/src/discovery/helpers.ts +249 -0
  209. package/src/discovery/index.ts +84 -0
  210. package/src/discovery/mcp-json.ts +127 -0
  211. package/src/discovery/vscode.ts +99 -0
  212. package/src/discovery/windsurf.ts +219 -0
  213. package/src/index.ts +192 -0
  214. package/src/main.ts +507 -0
  215. package/src/migrations.ts +156 -0
  216. package/src/modes/cleanup.ts +23 -0
  217. package/src/modes/index.ts +48 -0
  218. package/src/modes/interactive/components/armin.ts +382 -0
  219. package/src/modes/interactive/components/assistant-message.ts +86 -0
  220. package/src/modes/interactive/components/bash-execution.ts +199 -0
  221. package/src/modes/interactive/components/bordered-loader.ts +41 -0
  222. package/src/modes/interactive/components/branch-summary-message.ts +42 -0
  223. package/src/modes/interactive/components/compaction-summary-message.ts +45 -0
  224. package/src/modes/interactive/components/custom-editor.ts +122 -0
  225. package/src/modes/interactive/components/diff.ts +147 -0
  226. package/src/modes/interactive/components/dynamic-border.ts +25 -0
  227. package/src/modes/interactive/components/extensions/extension-dashboard.ts +296 -0
  228. package/src/modes/interactive/components/extensions/extension-list.ts +479 -0
  229. package/src/modes/interactive/components/extensions/index.ts +9 -0
  230. package/src/modes/interactive/components/extensions/inspector-panel.ts +313 -0
  231. package/src/modes/interactive/components/extensions/state-manager.ts +558 -0
  232. package/src/modes/interactive/components/extensions/types.ts +191 -0
  233. package/src/modes/interactive/components/hook-editor.ts +117 -0
  234. package/src/modes/interactive/components/hook-input.ts +64 -0
  235. package/src/modes/interactive/components/hook-message.ts +96 -0
  236. package/src/modes/interactive/components/hook-selector.ts +91 -0
  237. package/src/modes/interactive/components/model-selector.ts +560 -0
  238. package/src/modes/interactive/components/oauth-selector.ts +136 -0
  239. package/src/modes/interactive/components/plugin-settings.ts +481 -0
  240. package/src/modes/interactive/components/queue-mode-selector.ts +56 -0
  241. package/src/modes/interactive/components/session-selector.ts +220 -0
  242. package/src/modes/interactive/components/settings-defs.ts +597 -0
  243. package/src/modes/interactive/components/settings-selector.ts +545 -0
  244. package/src/modes/interactive/components/show-images-selector.ts +45 -0
  245. package/src/modes/interactive/components/status-line/index.ts +4 -0
  246. package/src/modes/interactive/components/status-line/presets.ts +94 -0
  247. package/src/modes/interactive/components/status-line/segments.ts +350 -0
  248. package/src/modes/interactive/components/status-line/separators.ts +55 -0
  249. package/src/modes/interactive/components/status-line/types.ts +81 -0
  250. package/src/modes/interactive/components/status-line-segment-editor.ts +357 -0
  251. package/src/modes/interactive/components/status-line.ts +384 -0
  252. package/src/modes/interactive/components/theme-selector.ts +62 -0
  253. package/src/modes/interactive/components/thinking-selector.ts +64 -0
  254. package/src/modes/interactive/components/tool-execution.ts +946 -0
  255. package/src/modes/interactive/components/tree-selector.ts +877 -0
  256. package/src/modes/interactive/components/ttsr-notification.ts +82 -0
  257. package/src/modes/interactive/components/user-message-selector.ts +159 -0
  258. package/src/modes/interactive/components/user-message.ts +18 -0
  259. package/src/modes/interactive/components/visual-truncate.ts +50 -0
  260. package/src/modes/interactive/components/welcome.ts +228 -0
  261. package/src/modes/interactive/interactive-mode.ts +2669 -0
  262. package/src/modes/interactive/theme/dark.json +102 -0
  263. package/src/modes/interactive/theme/defaults/dark-arctic.json +111 -0
  264. package/src/modes/interactive/theme/defaults/dark-catppuccin.json +106 -0
  265. package/src/modes/interactive/theme/defaults/dark-cyberpunk.json +109 -0
  266. package/src/modes/interactive/theme/defaults/dark-dracula.json +105 -0
  267. package/src/modes/interactive/theme/defaults/dark-forest.json +103 -0
  268. package/src/modes/interactive/theme/defaults/dark-github.json +112 -0
  269. package/src/modes/interactive/theme/defaults/dark-gruvbox.json +119 -0
  270. package/src/modes/interactive/theme/defaults/dark-monochrome.json +101 -0
  271. package/src/modes/interactive/theme/defaults/dark-monokai.json +105 -0
  272. package/src/modes/interactive/theme/defaults/dark-nord.json +104 -0
  273. package/src/modes/interactive/theme/defaults/dark-ocean.json +108 -0
  274. package/src/modes/interactive/theme/defaults/dark-one.json +107 -0
  275. package/src/modes/interactive/theme/defaults/dark-retro.json +99 -0
  276. package/src/modes/interactive/theme/defaults/dark-rose-pine.json +95 -0
  277. package/src/modes/interactive/theme/defaults/dark-solarized.json +96 -0
  278. package/src/modes/interactive/theme/defaults/dark-sunset.json +106 -0
  279. package/src/modes/interactive/theme/defaults/dark-synthwave.json +102 -0
  280. package/src/modes/interactive/theme/defaults/dark-tokyo-night.json +108 -0
  281. package/src/modes/interactive/theme/defaults/index.ts +67 -0
  282. package/src/modes/interactive/theme/defaults/light-arctic.json +106 -0
  283. package/src/modes/interactive/theme/defaults/light-catppuccin.json +105 -0
  284. package/src/modes/interactive/theme/defaults/light-cyberpunk.json +103 -0
  285. package/src/modes/interactive/theme/defaults/light-forest.json +107 -0
  286. package/src/modes/interactive/theme/defaults/light-github.json +114 -0
  287. package/src/modes/interactive/theme/defaults/light-gruvbox.json +115 -0
  288. package/src/modes/interactive/theme/defaults/light-monochrome.json +100 -0
  289. package/src/modes/interactive/theme/defaults/light-ocean.json +106 -0
  290. package/src/modes/interactive/theme/defaults/light-one.json +105 -0
  291. package/src/modes/interactive/theme/defaults/light-retro.json +105 -0
  292. package/src/modes/interactive/theme/defaults/light-solarized.json +101 -0
  293. package/src/modes/interactive/theme/defaults/light-sunset.json +106 -0
  294. package/src/modes/interactive/theme/defaults/light-synthwave.json +105 -0
  295. package/src/modes/interactive/theme/defaults/light-tokyo-night.json +118 -0
  296. package/src/modes/interactive/theme/light.json +99 -0
  297. package/src/modes/interactive/theme/theme-schema.json +424 -0
  298. package/src/modes/interactive/theme/theme.ts +2211 -0
  299. package/src/modes/print-mode.ts +163 -0
  300. package/src/modes/rpc/rpc-client.ts +527 -0
  301. package/src/modes/rpc/rpc-mode.ts +494 -0
  302. package/src/modes/rpc/rpc-types.ts +203 -0
  303. package/src/prompts/architect-plan.md +10 -0
  304. package/src/prompts/branch-summary-preamble.md +3 -0
  305. package/src/prompts/branch-summary.md +28 -0
  306. package/src/prompts/browser.md +71 -0
  307. package/src/prompts/compaction-summary.md +34 -0
  308. package/src/prompts/compaction-turn-prefix.md +16 -0
  309. package/src/prompts/compaction-update-summary.md +41 -0
  310. package/src/prompts/explore.md +82 -0
  311. package/src/prompts/implement-with-critic.md +11 -0
  312. package/src/prompts/implement.md +11 -0
  313. package/src/prompts/init.md +30 -0
  314. package/src/prompts/plan.md +54 -0
  315. package/src/prompts/reviewer.md +81 -0
  316. package/src/prompts/summarization-system.md +3 -0
  317. package/src/prompts/system-prompt.md +27 -0
  318. package/src/prompts/task.md +56 -0
  319. package/src/prompts/title-system.md +8 -0
  320. package/src/prompts/tools/ask.md +24 -0
  321. package/src/prompts/tools/bash.md +23 -0
  322. package/src/prompts/tools/edit.md +9 -0
  323. package/src/prompts/tools/find.md +6 -0
  324. package/src/prompts/tools/grep.md +12 -0
  325. package/src/prompts/tools/lsp.md +14 -0
  326. package/src/prompts/tools/output.md +23 -0
  327. package/src/prompts/tools/read.md +25 -0
  328. package/src/prompts/tools/web-fetch.md +8 -0
  329. package/src/prompts/tools/web-search.md +10 -0
  330. package/src/prompts/tools/write.md +10 -0
  331. package/src/utils/changelog.ts +99 -0
  332. package/src/utils/clipboard.ts +265 -0
  333. package/src/utils/fuzzy.ts +108 -0
  334. package/src/utils/mime.ts +30 -0
  335. package/src/utils/shell-snapshot.ts +218 -0
  336. package/src/utils/shell.ts +364 -0
  337. package/src/utils/tools-manager.ts +265 -0
@@ -0,0 +1,99 @@
1
+ /**
2
+ * VS Code Provider
3
+ *
4
+ * Loads config from `.vscode` directory (project-only).
5
+ * Supports MCP server discovery from `mcp.json` with nested `mcp.servers` structure.
6
+ */
7
+
8
+ import { registerProvider } from "../capability/index";
9
+ import { type MCPServer, mcpCapability } from "../capability/mcp";
10
+ import type { LoadContext, LoadResult } from "../capability/types";
11
+ import { createSourceMeta, expandEnvVarsDeep, getProjectPath, parseJSON } from "./helpers";
12
+
13
+ const PROVIDER_ID = "vscode";
14
+ const DISPLAY_NAME = "VS Code";
15
+ const PRIORITY = 20;
16
+
17
+ // =============================================================================
18
+ // MCP Servers
19
+ // =============================================================================
20
+
21
+ registerProvider<MCPServer>(mcpCapability.id, {
22
+ id: PROVIDER_ID,
23
+ displayName: DISPLAY_NAME,
24
+ description: "Load MCP servers from .vscode/mcp.json",
25
+ priority: PRIORITY,
26
+ load(ctx: LoadContext): LoadResult<MCPServer> {
27
+ const items: MCPServer[] = [];
28
+ const warnings: string[] = [];
29
+
30
+ // Project-only (VS Code doesn't support user-level MCP config)
31
+ const projectPath = getProjectPath(ctx, "vscode", "mcp.json");
32
+ if (projectPath && ctx.fs.isFile(projectPath)) {
33
+ const result = loadMCPConfig(ctx, projectPath, "project");
34
+ items.push(...result.items);
35
+ if (result.warnings) warnings.push(...result.warnings);
36
+ }
37
+
38
+ return { items, warnings };
39
+ },
40
+ });
41
+
42
+ /**
43
+ * Load MCP servers from a mcp.json file.
44
+ * VS Code uses nested structure: { "mcp": { "servers": { ... } } }
45
+ */
46
+ function loadMCPConfig(ctx: LoadContext, path: string, level: "user" | "project"): LoadResult<MCPServer> {
47
+ const items: MCPServer[] = [];
48
+ const warnings: string[] = [];
49
+
50
+ const content = ctx.fs.readFile(path);
51
+ if (!content) {
52
+ warnings.push(`Failed to read ${path}`);
53
+ return { items, warnings };
54
+ }
55
+
56
+ const parsed = parseJSON<{ mcp?: { servers?: Record<string, unknown> } }>(content);
57
+ if (!parsed) {
58
+ warnings.push(`Invalid JSON in ${path}`);
59
+ return { items, warnings };
60
+ }
61
+
62
+ // VS Code uses nested structure: mcp.servers
63
+ const servers = parsed.mcp?.servers;
64
+ if (!servers || typeof servers !== "object") {
65
+ return { items, warnings };
66
+ }
67
+
68
+ for (const [name, config] of Object.entries(servers)) {
69
+ if (!config || typeof config !== "object") {
70
+ warnings.push(`Invalid config for server "${name}" in ${path}`);
71
+ continue;
72
+ }
73
+
74
+ const raw = config as Record<string, unknown>;
75
+
76
+ // Expand environment variables
77
+ const expanded = expandEnvVarsDeep(raw);
78
+
79
+ const server: MCPServer = {
80
+ name,
81
+ command: typeof expanded.command === "string" ? expanded.command : undefined,
82
+ args: Array.isArray(expanded.args) ? (expanded.args as string[]) : undefined,
83
+ env: expanded.env && typeof expanded.env === "object" ? (expanded.env as Record<string, string>) : undefined,
84
+ url: typeof expanded.url === "string" ? expanded.url : undefined,
85
+ headers:
86
+ expanded.headers && typeof expanded.headers === "object"
87
+ ? (expanded.headers as Record<string, string>)
88
+ : undefined,
89
+ transport: ["stdio", "sse", "http"].includes(expanded.transport as string)
90
+ ? (expanded.transport as "stdio" | "sse" | "http")
91
+ : undefined,
92
+ _source: createSourceMeta(PROVIDER_ID, path, level),
93
+ };
94
+
95
+ items.push(server);
96
+ }
97
+
98
+ return { items, warnings };
99
+ }
@@ -0,0 +1,219 @@
1
+ /**
2
+ * Windsurf (Codeium) Provider
3
+ *
4
+ * Loads configuration from Windsurf's config locations:
5
+ * - User: ~/.codeium/windsurf
6
+ * - Project: .windsurf
7
+ *
8
+ * Supports:
9
+ * - MCP servers from mcp_config.json
10
+ * - Rules from .windsurf/rules/*.md and ~/.codeium/windsurf/memories/global_rules.md
11
+ * - Legacy .windsurfrules file
12
+ */
13
+
14
+ import { registerProvider } from "../capability/index";
15
+ import { type MCPServer, mcpCapability } from "../capability/mcp";
16
+ import { type Rule, ruleCapability } from "../capability/rule";
17
+ import type { LoadContext, LoadResult } from "../capability/types";
18
+ import {
19
+ createSourceMeta,
20
+ expandEnvVarsDeep,
21
+ getProjectPath,
22
+ getUserPath,
23
+ loadFilesFromDir,
24
+ parseFrontmatter,
25
+ parseJSON,
26
+ } from "./helpers";
27
+
28
+ const PROVIDER_ID = "windsurf";
29
+ const DISPLAY_NAME = "Windsurf";
30
+ const PRIORITY = 50;
31
+
32
+ // =============================================================================
33
+ // MCP Servers
34
+ // =============================================================================
35
+
36
+ function loadMCPServers(ctx: LoadContext): LoadResult<MCPServer> {
37
+ const items: MCPServer[] = [];
38
+ const warnings: string[] = [];
39
+
40
+ // User-level: ~/.codeium/windsurf/mcp_config.json
41
+ const userPath = getUserPath(ctx, "windsurf", "mcp_config.json");
42
+ if (userPath && ctx.fs.isFile(userPath)) {
43
+ const content = ctx.fs.readFile(userPath);
44
+ if (content) {
45
+ const config = parseJSON<{ mcpServers?: Record<string, unknown> }>(content);
46
+ if (config?.mcpServers) {
47
+ for (const [name, serverConfig] of Object.entries(config.mcpServers)) {
48
+ if (typeof serverConfig !== "object" || serverConfig === null) {
49
+ warnings.push(`Invalid server config for "${name}" in ${userPath}`);
50
+ continue;
51
+ }
52
+
53
+ const server = expandEnvVarsDeep(serverConfig as Record<string, unknown>);
54
+ items.push({
55
+ name,
56
+ command: server.command as string | undefined,
57
+ args: server.args as string[] | undefined,
58
+ env: server.env as Record<string, string> | undefined,
59
+ url: server.url as string | undefined,
60
+ headers: server.headers as Record<string, string> | undefined,
61
+ transport: server.type as "stdio" | "sse" | "http" | undefined,
62
+ _source: createSourceMeta(PROVIDER_ID, userPath, "user"),
63
+ });
64
+ }
65
+ }
66
+ }
67
+ }
68
+
69
+ // Project-level: .windsurf/mcp_config.json
70
+ const projectPath = getProjectPath(ctx, "windsurf", "mcp_config.json");
71
+ if (projectPath && ctx.fs.isFile(projectPath)) {
72
+ const content = ctx.fs.readFile(projectPath);
73
+ if (content) {
74
+ const config = parseJSON<{ mcpServers?: Record<string, unknown> }>(content);
75
+ if (config?.mcpServers) {
76
+ for (const [name, serverConfig] of Object.entries(config.mcpServers)) {
77
+ if (typeof serverConfig !== "object" || serverConfig === null) {
78
+ warnings.push(`Invalid server config for "${name}" in ${projectPath}`);
79
+ continue;
80
+ }
81
+
82
+ const server = expandEnvVarsDeep(serverConfig as Record<string, unknown>);
83
+ items.push({
84
+ name,
85
+ command: server.command as string | undefined,
86
+ args: server.args as string[] | undefined,
87
+ env: server.env as Record<string, string> | undefined,
88
+ url: server.url as string | undefined,
89
+ headers: server.headers as Record<string, string> | undefined,
90
+ transport: server.type as "stdio" | "sse" | "http" | undefined,
91
+ _source: createSourceMeta(PROVIDER_ID, projectPath, "project"),
92
+ });
93
+ }
94
+ }
95
+ }
96
+ }
97
+
98
+ return { items, warnings };
99
+ }
100
+
101
+ // =============================================================================
102
+ // Rules
103
+ // =============================================================================
104
+
105
+ function loadRules(ctx: LoadContext): LoadResult<Rule> {
106
+ const items: Rule[] = [];
107
+ const warnings: string[] = [];
108
+
109
+ // User-level: ~/.codeium/windsurf/memories/global_rules.md
110
+ const userPath = getUserPath(ctx, "windsurf", "memories/global_rules.md");
111
+ if (userPath && ctx.fs.isFile(userPath)) {
112
+ const content = ctx.fs.readFile(userPath);
113
+ if (content) {
114
+ const { frontmatter, body } = parseFrontmatter(content);
115
+
116
+ // Validate and normalize globs
117
+ let globs: string[] | undefined;
118
+ if (Array.isArray(frontmatter.globs)) {
119
+ globs = frontmatter.globs.filter((g): g is string => typeof g === "string");
120
+ } else if (typeof frontmatter.globs === "string") {
121
+ globs = [frontmatter.globs];
122
+ }
123
+
124
+ items.push({
125
+ name: "global_rules",
126
+ path: userPath,
127
+ content: body,
128
+ globs,
129
+ alwaysApply: frontmatter.alwaysApply as boolean | undefined,
130
+ description: frontmatter.description as string | undefined,
131
+ ttsrTrigger: typeof frontmatter.ttsr_trigger === "string" ? frontmatter.ttsr_trigger : undefined,
132
+ _source: createSourceMeta(PROVIDER_ID, userPath, "user"),
133
+ });
134
+ }
135
+ }
136
+
137
+ // Project-level: .windsurf/rules/*.md
138
+ const projectRulesDir = getProjectPath(ctx, "windsurf", "rules");
139
+ if (projectRulesDir) {
140
+ const result = loadFilesFromDir<Rule>(ctx, projectRulesDir, PROVIDER_ID, "project", {
141
+ extensions: ["md"],
142
+ transform: (name, content, path, source) => {
143
+ const { frontmatter, body } = parseFrontmatter(content);
144
+ const ruleName = name.replace(/\.md$/, "");
145
+
146
+ // Validate and normalize globs
147
+ let globs: string[] | undefined;
148
+ if (Array.isArray(frontmatter.globs)) {
149
+ globs = frontmatter.globs.filter((g): g is string => typeof g === "string");
150
+ } else if (typeof frontmatter.globs === "string") {
151
+ globs = [frontmatter.globs];
152
+ }
153
+
154
+ return {
155
+ name: ruleName,
156
+ path,
157
+ content: body,
158
+ globs,
159
+ alwaysApply: frontmatter.alwaysApply as boolean | undefined,
160
+ description: frontmatter.description as string | undefined,
161
+ ttsrTrigger: typeof frontmatter.ttsr_trigger === "string" ? frontmatter.ttsr_trigger : undefined,
162
+ _source: source,
163
+ };
164
+ },
165
+ });
166
+ items.push(...result.items);
167
+ if (result.warnings) warnings.push(...result.warnings);
168
+ }
169
+
170
+ // Legacy: .windsurfrules in project root
171
+ const legacyPath = ctx.fs.walkUp(".windsurfrules", { file: true });
172
+ if (legacyPath) {
173
+ const content = ctx.fs.readFile(legacyPath);
174
+ if (content) {
175
+ const { frontmatter, body } = parseFrontmatter(content);
176
+
177
+ // Validate and normalize globs
178
+ let globs: string[] | undefined;
179
+ if (Array.isArray(frontmatter.globs)) {
180
+ globs = frontmatter.globs.filter((g): g is string => typeof g === "string");
181
+ } else if (typeof frontmatter.globs === "string") {
182
+ globs = [frontmatter.globs];
183
+ }
184
+
185
+ items.push({
186
+ name: "windsurfrules",
187
+ path: legacyPath,
188
+ content: body,
189
+ globs,
190
+ alwaysApply: frontmatter.alwaysApply as boolean | undefined,
191
+ description: frontmatter.description as string | undefined,
192
+ ttsrTrigger: typeof frontmatter.ttsr_trigger === "string" ? frontmatter.ttsr_trigger : undefined,
193
+ _source: createSourceMeta(PROVIDER_ID, legacyPath, "project"),
194
+ });
195
+ }
196
+ }
197
+
198
+ return { items, warnings };
199
+ }
200
+
201
+ // =============================================================================
202
+ // Provider Registration
203
+ // =============================================================================
204
+
205
+ registerProvider<MCPServer>(mcpCapability.id, {
206
+ id: PROVIDER_ID,
207
+ displayName: DISPLAY_NAME,
208
+ description: "Load MCP servers from Windsurf config (mcp_config.json)",
209
+ priority: PRIORITY,
210
+ load: loadMCPServers,
211
+ });
212
+
213
+ registerProvider<Rule>(ruleCapability.id, {
214
+ id: PROVIDER_ID,
215
+ displayName: DISPLAY_NAME,
216
+ description: "Load rules from Windsurf (.windsurf/rules/*.md, memories/global_rules.md, .windsurfrules)",
217
+ priority: PRIORITY,
218
+ load: loadRules,
219
+ });
package/src/index.ts ADDED
@@ -0,0 +1,192 @@
1
+ // Core session management
2
+
3
+ // Re-export TUI components for custom tool rendering
4
+ export { Container, Markdown, Spacer, Text } from "@oh-my-pi/pi-tui";
5
+ export {
6
+ AgentSession,
7
+ type AgentSessionConfig,
8
+ type AgentSessionEvent,
9
+ type AgentSessionEventListener,
10
+ type ModelCycleResult,
11
+ type PromptOptions,
12
+ type SessionStats,
13
+ } from "./core/agent-session";
14
+ // Auth and model registry
15
+ export { type ApiKeyCredential, type AuthCredential, AuthStorage, type OAuthCredential } from "./core/auth-storage";
16
+ // Compaction
17
+ export {
18
+ type BranchPreparation,
19
+ type BranchSummaryResult,
20
+ type CollectEntriesResult,
21
+ type CompactionResult,
22
+ type CutPointResult,
23
+ calculateContextTokens,
24
+ collectEntriesForBranchSummary,
25
+ compact,
26
+ DEFAULT_COMPACTION_SETTINGS,
27
+ estimateTokens,
28
+ type FileOperations,
29
+ findCutPoint,
30
+ findTurnStartIndex,
31
+ type GenerateBranchSummaryOptions,
32
+ generateBranchSummary,
33
+ generateSummary,
34
+ getLastAssistantUsage,
35
+ prepareBranchEntries,
36
+ serializeConversation,
37
+ shouldCompact,
38
+ } from "./core/compaction/index";
39
+ // Custom commands
40
+ export type {
41
+ CustomCommand,
42
+ CustomCommandAPI,
43
+ CustomCommandFactory,
44
+ CustomCommandSource,
45
+ CustomCommandsLoadResult,
46
+ LoadedCustomCommand,
47
+ } from "./core/custom-commands/types";
48
+ // Custom tools
49
+ export type {
50
+ AgentToolUpdateCallback,
51
+ CustomTool,
52
+ CustomToolAPI,
53
+ CustomToolContext,
54
+ CustomToolFactory,
55
+ CustomToolSessionEvent,
56
+ CustomToolsLoadResult,
57
+ CustomToolUIContext,
58
+ ExecResult,
59
+ LoadedCustomTool,
60
+ RenderResultOptions,
61
+ } from "./core/custom-tools/index";
62
+ export { discoverAndLoadCustomTools, loadCustomTools } from "./core/custom-tools/index";
63
+ export type * from "./core/hooks/index";
64
+ // Hook system types and type guards
65
+ export {
66
+ isBashToolResult,
67
+ isEditToolResult,
68
+ isFindToolResult,
69
+ isGrepToolResult,
70
+ isLsToolResult,
71
+ isReadToolResult,
72
+ isWriteToolResult,
73
+ } from "./core/hooks/index";
74
+ // Logging
75
+ export { type Logger, logger } from "./core/logger";
76
+ export { convertToLlm } from "./core/messages";
77
+ export { ModelRegistry } from "./core/model-registry";
78
+ // SDK for programmatic usage
79
+ export {
80
+ type BuildSystemPromptOptions,
81
+ buildSystemPrompt,
82
+ type CreateAgentSessionOptions,
83
+ type CreateAgentSessionResult,
84
+ // Factory
85
+ createAgentSession,
86
+ createBashTool,
87
+ // Tool factories (for custom cwd)
88
+ createCodingTools,
89
+ createEditTool,
90
+ createFindTool,
91
+ createGrepTool,
92
+ createLsTool,
93
+ createReadOnlyTools,
94
+ createReadTool,
95
+ createWriteTool,
96
+ // Discovery
97
+ discoverAuthStorage,
98
+ discoverContextFiles,
99
+ discoverCustomTools,
100
+ discoverHooks,
101
+ discoverModels,
102
+ discoverSkills,
103
+ discoverSlashCommands,
104
+ type FileSlashCommand,
105
+ // Hook types
106
+ type HookAPI,
107
+ type HookContext,
108
+ type HookFactory,
109
+ loadSettings,
110
+ // Pre-built tools (use process.cwd())
111
+ readOnlyTools,
112
+ } from "./core/sdk";
113
+ export {
114
+ type BranchSummaryEntry,
115
+ buildSessionContext,
116
+ type CompactionEntry,
117
+ CURRENT_SESSION_VERSION,
118
+ type CustomEntry,
119
+ type CustomMessageEntry,
120
+ type FileEntry,
121
+ getLatestCompactionEntry,
122
+ type ModelChangeEntry,
123
+ migrateSessionEntries,
124
+ type NewSessionOptions,
125
+ parseSessionEntries,
126
+ type SessionContext,
127
+ type SessionEntry,
128
+ type SessionEntryBase,
129
+ type SessionHeader,
130
+ type SessionInfo,
131
+ SessionManager,
132
+ type SessionMessageEntry,
133
+ type ThinkingLevelChangeEntry,
134
+ } from "./core/session-manager";
135
+ export {
136
+ type CompactionSettings,
137
+ type LspSettings,
138
+ type RetrySettings,
139
+ type Settings,
140
+ SettingsManager,
141
+ type SkillsSettings,
142
+ } from "./core/settings-manager";
143
+ // Skills
144
+ export {
145
+ formatSkillsForPrompt,
146
+ type LoadSkillsFromDirOptions,
147
+ type LoadSkillsResult,
148
+ loadSkills,
149
+ loadSkillsFromDir,
150
+ type Skill,
151
+ type SkillFrontmatter,
152
+ type SkillWarning,
153
+ } from "./core/skills";
154
+ // Tools
155
+ export {
156
+ type BashToolDetails,
157
+ bashTool,
158
+ type CodingToolsOptions,
159
+ codingTools,
160
+ editTool,
161
+ type FindToolDetails,
162
+ findTool,
163
+ type GrepToolDetails,
164
+ grepTool,
165
+ type LsToolDetails,
166
+ lsTool,
167
+ type ReadToolDetails,
168
+ readTool,
169
+ type TruncationResult,
170
+ type WriteToolDetails,
171
+ type WriteToolOptions,
172
+ writeTool,
173
+ } from "./core/tools/index";
174
+ export type { FileDiagnosticsResult } from "./core/tools/lsp/index";
175
+ // Main entry point
176
+ export { main } from "./main";
177
+ // UI components for hooks and custom tools
178
+ export { BorderedLoader } from "./modes/interactive/components/bordered-loader";
179
+ // Theme utilities for custom tools
180
+ export { getMarkdownTheme } from "./modes/interactive/theme/theme";
181
+
182
+ // TypeBox helper for string enums (convenience for custom tools)
183
+ import { type TSchema, Type } from "@sinclair/typebox";
184
+ export function StringEnum<T extends readonly string[]>(
185
+ values: T,
186
+ options?: { description?: string; default?: T[number] },
187
+ ): TSchema {
188
+ return Type.Union(
189
+ values.map((v) => Type.Literal(v)),
190
+ options,
191
+ );
192
+ }