expandai 0.0.0 → 0.0.2

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 (209) hide show
  1. package/README.md +241 -6
  2. package/build/dts/ApiClient.d.ts +231 -0
  3. package/build/dts/ApiClient.d.ts.map +1 -0
  4. package/build/dts/Authentication.d.ts +23 -0
  5. package/build/dts/Authentication.d.ts.map +1 -0
  6. package/build/dts/BrowserOAuth.d.ts +99 -0
  7. package/build/dts/BrowserOAuth.d.ts.map +1 -0
  8. package/build/dts/Commands/Fetch.d.ts +30 -0
  9. package/build/dts/Commands/Fetch.d.ts.map +1 -0
  10. package/build/dts/Commands/Hook.d.ts +17 -0
  11. package/build/dts/Commands/Hook.d.ts.map +1 -0
  12. package/build/dts/Commands/Mcp.d.ts +11 -0
  13. package/build/dts/Commands/Mcp.d.ts.map +1 -0
  14. package/build/dts/Commands/McpRun.d.ts +5 -0
  15. package/build/dts/Commands/McpRun.d.ts.map +1 -0
  16. package/build/dts/Commands/Search.d.ts +21 -0
  17. package/build/dts/Commands/Search.d.ts.map +1 -0
  18. package/build/dts/Commands/Skill.d.ts +12 -0
  19. package/build/dts/Commands/Skill.d.ts.map +1 -0
  20. package/build/dts/Commands/Uninstall.d.ts +9 -0
  21. package/build/dts/Commands/Uninstall.d.ts.map +1 -0
  22. package/build/dts/Config.d.ts +105 -0
  23. package/build/dts/Config.d.ts.map +1 -0
  24. package/build/dts/DeviceAuth.d.ts +87 -0
  25. package/build/dts/DeviceAuth.d.ts.map +1 -0
  26. package/build/dts/Hook/Claude.d.ts +13 -0
  27. package/build/dts/Hook/Claude.d.ts.map +1 -0
  28. package/build/dts/Hook/Errors.d.ts +20 -0
  29. package/build/dts/Hook/Errors.d.ts.map +1 -0
  30. package/build/dts/Hook/Opencode.d.ts +13 -0
  31. package/build/dts/Hook/Opencode.d.ts.map +1 -0
  32. package/build/dts/Hook/SnapshotNote.d.ts +8 -0
  33. package/build/dts/Hook/SnapshotNote.d.ts.map +1 -0
  34. package/build/dts/Install/Claude/Hook.d.ts +60 -0
  35. package/build/dts/Install/Claude/Hook.d.ts.map +1 -0
  36. package/build/dts/Install/Claude/Mcp.d.ts +45 -0
  37. package/build/dts/Install/Claude/Mcp.d.ts.map +1 -0
  38. package/build/dts/Install/Claude/Skill.d.ts +24 -0
  39. package/build/dts/Install/Claude/Skill.d.ts.map +1 -0
  40. package/build/dts/Install/Codex/Mcp.d.ts +39 -0
  41. package/build/dts/Install/Codex/Mcp.d.ts.map +1 -0
  42. package/build/dts/Install/Codex/Skill.d.ts +20 -0
  43. package/build/dts/Install/Codex/Skill.d.ts.map +1 -0
  44. package/build/dts/Install/Cursor/Mcp.d.ts +45 -0
  45. package/build/dts/Install/Cursor/Mcp.d.ts.map +1 -0
  46. package/build/dts/Install/Cursor/Skill.d.ts +27 -0
  47. package/build/dts/Install/Cursor/Skill.d.ts.map +1 -0
  48. package/build/dts/Install/Domain.d.ts +73 -0
  49. package/build/dts/Install/Domain.d.ts.map +1 -0
  50. package/build/dts/Install/Hook.d.ts +30 -0
  51. package/build/dts/Install/Hook.d.ts.map +1 -0
  52. package/build/dts/Install/Mcp.d.ts +28 -0
  53. package/build/dts/Install/Mcp.d.ts.map +1 -0
  54. package/build/dts/Install/Opencode/Hook.d.ts +23 -0
  55. package/build/dts/Install/Opencode/Hook.d.ts.map +1 -0
  56. package/build/dts/Install/Opencode/Mcp.d.ts +47 -0
  57. package/build/dts/Install/Opencode/Mcp.d.ts.map +1 -0
  58. package/build/dts/Install/Opencode/Skill.d.ts +24 -0
  59. package/build/dts/Install/Opencode/Skill.d.ts.map +1 -0
  60. package/build/dts/Install/Skill.d.ts +32 -0
  61. package/build/dts/Install/Skill.d.ts.map +1 -0
  62. package/build/dts/Install/Uninstall.d.ts +32 -0
  63. package/build/dts/Install/Uninstall.d.ts.map +1 -0
  64. package/build/dts/Mcp/ExpandDocs.d.ts +7 -0
  65. package/build/dts/Mcp/ExpandDocs.d.ts.map +1 -0
  66. package/build/dts/Mcp/RequestHeaders.d.ts +15 -0
  67. package/build/dts/Mcp/RequestHeaders.d.ts.map +1 -0
  68. package/build/dts/Mcp/Server.d.ts +10 -0
  69. package/build/dts/Mcp/Server.d.ts.map +1 -0
  70. package/build/dts/Mcp/Toolkit.d.ts +3 -0
  71. package/build/dts/Mcp/Toolkit.d.ts.map +1 -0
  72. package/build/dts/Mcp/tools/Citations.d.ts +237 -0
  73. package/build/dts/Mcp/tools/Citations.d.ts.map +1 -0
  74. package/build/dts/Mcp/tools/Fetch.d.ts +167 -0
  75. package/build/dts/Mcp/tools/Fetch.d.ts.map +1 -0
  76. package/build/dts/Snippets.d.ts +19 -0
  77. package/build/dts/Snippets.d.ts.map +1 -0
  78. package/build/dts/index.d.ts +2 -0
  79. package/build/dts/index.d.ts.map +1 -0
  80. package/build/dts/main.d.ts +3 -0
  81. package/build/dts/main.d.ts.map +1 -0
  82. package/build/esm/ApiClient.js +182 -0
  83. package/build/esm/ApiClient.js.map +1 -0
  84. package/build/esm/Authentication.js +112 -0
  85. package/build/esm/Authentication.js.map +1 -0
  86. package/build/esm/BrowserOAuth.js +254 -0
  87. package/build/esm/BrowserOAuth.js.map +1 -0
  88. package/build/esm/Commands/Fetch.js +95 -0
  89. package/build/esm/Commands/Fetch.js.map +1 -0
  90. package/build/esm/Commands/Hook.js +20 -0
  91. package/build/esm/Commands/Hook.js.map +1 -0
  92. package/build/esm/Commands/Mcp.js +19 -0
  93. package/build/esm/Commands/Mcp.js.map +1 -0
  94. package/build/esm/Commands/McpRun.js +15 -0
  95. package/build/esm/Commands/McpRun.js.map +1 -0
  96. package/build/esm/Commands/Search.js +43 -0
  97. package/build/esm/Commands/Search.js.map +1 -0
  98. package/build/esm/Commands/Skill.js +17 -0
  99. package/build/esm/Commands/Skill.js.map +1 -0
  100. package/build/esm/Commands/Uninstall.js +28 -0
  101. package/build/esm/Commands/Uninstall.js.map +1 -0
  102. package/build/esm/Config.js +145 -0
  103. package/build/esm/Config.js.map +1 -0
  104. package/build/esm/DeviceAuth.js +127 -0
  105. package/build/esm/DeviceAuth.js.map +1 -0
  106. package/build/esm/Hook/Claude.js +74 -0
  107. package/build/esm/Hook/Claude.js.map +1 -0
  108. package/build/esm/Hook/Errors.js +18 -0
  109. package/build/esm/Hook/Errors.js.map +1 -0
  110. package/build/esm/Hook/Opencode.js +50 -0
  111. package/build/esm/Hook/Opencode.js.map +1 -0
  112. package/build/esm/Hook/SnapshotNote.js +18 -0
  113. package/build/esm/Hook/SnapshotNote.js.map +1 -0
  114. package/build/esm/Install/Claude/Hook.js +89 -0
  115. package/build/esm/Install/Claude/Hook.js.map +1 -0
  116. package/build/esm/Install/Claude/Mcp.js +71 -0
  117. package/build/esm/Install/Claude/Mcp.js.map +1 -0
  118. package/build/esm/Install/Claude/Skill.js +34 -0
  119. package/build/esm/Install/Claude/Skill.js.map +1 -0
  120. package/build/esm/Install/Codex/Mcp.js +92 -0
  121. package/build/esm/Install/Codex/Mcp.js.map +1 -0
  122. package/build/esm/Install/Codex/Skill.js +30 -0
  123. package/build/esm/Install/Codex/Skill.js.map +1 -0
  124. package/build/esm/Install/Cursor/Mcp.js +71 -0
  125. package/build/esm/Install/Cursor/Mcp.js.map +1 -0
  126. package/build/esm/Install/Cursor/Skill.js +37 -0
  127. package/build/esm/Install/Cursor/Skill.js.map +1 -0
  128. package/build/esm/Install/Domain.js +105 -0
  129. package/build/esm/Install/Domain.js.map +1 -0
  130. package/build/esm/Install/Hook.js +38 -0
  131. package/build/esm/Install/Hook.js.map +1 -0
  132. package/build/esm/Install/Mcp.js +40 -0
  133. package/build/esm/Install/Mcp.js.map +1 -0
  134. package/build/esm/Install/Opencode/Hook.js +44 -0
  135. package/build/esm/Install/Opencode/Hook.js.map +1 -0
  136. package/build/esm/Install/Opencode/Mcp.js +73 -0
  137. package/build/esm/Install/Opencode/Mcp.js.map +1 -0
  138. package/build/esm/Install/Opencode/Skill.js +34 -0
  139. package/build/esm/Install/Opencode/Skill.js.map +1 -0
  140. package/build/esm/Install/Opencode/expandai-webfetch.js +38 -0
  141. package/build/esm/Install/Skill.js +41 -0
  142. package/build/esm/Install/Skill.js.map +1 -0
  143. package/build/esm/Install/Uninstall.js +49 -0
  144. package/build/esm/Install/Uninstall.js.map +1 -0
  145. package/build/esm/Mcp/ExpandDocs.js +64 -0
  146. package/build/esm/Mcp/ExpandDocs.js.map +1 -0
  147. package/build/esm/Mcp/RequestHeaders.js +13 -0
  148. package/build/esm/Mcp/RequestHeaders.js.map +1 -0
  149. package/build/esm/Mcp/Server.js +11 -0
  150. package/build/esm/Mcp/Server.js.map +1 -0
  151. package/build/esm/Mcp/Toolkit.js +16 -0
  152. package/build/esm/Mcp/Toolkit.js.map +1 -0
  153. package/build/esm/Mcp/tools/Citations.js +92 -0
  154. package/build/esm/Mcp/tools/Citations.js.map +1 -0
  155. package/build/esm/Mcp/tools/Fetch.js +141 -0
  156. package/build/esm/Mcp/tools/Fetch.js.map +1 -0
  157. package/build/esm/Snippets.js +18 -0
  158. package/build/esm/Snippets.js.map +1 -0
  159. package/build/esm/index.js +2 -0
  160. package/build/esm/index.js.map +1 -0
  161. package/build/esm/main.js +97 -0
  162. package/build/esm/main.js.map +1 -0
  163. package/build/skills/expandai/SKILL.md +72 -0
  164. package/package.json +72 -10
  165. package/src/ApiClient.ts +257 -0
  166. package/src/Authentication.ts +164 -0
  167. package/src/BrowserOAuth.ts +361 -0
  168. package/src/Commands/Fetch.ts +157 -0
  169. package/src/Commands/Hook.ts +48 -0
  170. package/src/Commands/Mcp.ts +30 -0
  171. package/src/Commands/McpRun.ts +25 -0
  172. package/src/Commands/Search.ts +92 -0
  173. package/src/Commands/Skill.ts +30 -0
  174. package/src/Commands/Uninstall.ts +38 -0
  175. package/src/Config.ts +195 -0
  176. package/src/DeviceAuth.ts +193 -0
  177. package/src/Hook/Claude.ts +81 -0
  178. package/src/Hook/Errors.ts +19 -0
  179. package/src/Hook/Opencode.ts +58 -0
  180. package/src/Hook/SnapshotNote.ts +18 -0
  181. package/src/Install/Claude/Hook.ts +133 -0
  182. package/src/Install/Claude/Mcp.ts +82 -0
  183. package/src/Install/Claude/Skill.ts +44 -0
  184. package/src/Install/Codex/Mcp.ts +109 -0
  185. package/src/Install/Codex/Skill.ts +40 -0
  186. package/src/Install/Cursor/Mcp.ts +82 -0
  187. package/src/Install/Cursor/Skill.ts +47 -0
  188. package/src/Install/Domain.ts +148 -0
  189. package/src/Install/Hook.ts +50 -0
  190. package/src/Install/Mcp.ts +71 -0
  191. package/src/Install/Opencode/Hook.ts +55 -0
  192. package/src/Install/Opencode/Mcp.ts +84 -0
  193. package/src/Install/Opencode/Skill.ts +44 -0
  194. package/src/Install/Opencode/expandai-webfetch.d.ts +23 -0
  195. package/src/Install/Opencode/expandai-webfetch.js +38 -0
  196. package/src/Install/Skill.ts +57 -0
  197. package/src/Install/Uninstall.ts +82 -0
  198. package/src/Mcp/ExpandDocs.ts +71 -0
  199. package/src/Mcp/RequestHeaders.ts +16 -0
  200. package/src/Mcp/Server.ts +14 -0
  201. package/src/Mcp/Toolkit.ts +21 -0
  202. package/src/Mcp/tools/Citations.ts +110 -0
  203. package/src/Mcp/tools/Fetch.ts +177 -0
  204. package/src/Snippets.ts +32 -0
  205. package/src/index.ts +1 -0
  206. package/src/main.ts +146 -0
  207. package/bun.lockb +0 -0
  208. package/index.ts +0 -1
  209. package/tsconfig.json +0 -27
@@ -0,0 +1,38 @@
1
+ import { Effect, Match, Schema } from 'effect';
2
+ import { ClaudeHook } from './Claude/Hook.js';
3
+ import { Mcp } from './Mcp.js';
4
+ import { OpencodeHook } from './Opencode/Hook.js';
5
+ /**
6
+ * Hook install dispatcher. Bundles MCP install + per-host hook config:
7
+ *
8
+ * - claude-code: writes the matcher into `~/.claude/settings.json` (global)
9
+ * or `<cwd>/.claude/settings.json` (project), then registers expandai as
10
+ * an MCP server at the matching scope.
11
+ * - opencode: writes the webfetch plugin file into `.opencode/plugins/`
12
+ * (project) or `~/.config/opencode/plugins/` (global), plus registers
13
+ * expandai as an MCP server.
14
+ *
15
+ * Cursor has no hook system per opencode.ai/docs and Cursor's docs, so it's
16
+ * absent from this Host union (compare with `Mcp.Host` which includes Cursor).
17
+ */
18
+ export const HookHost = Schema.Literal('claude-code', 'opencode');
19
+ export class HookInstaller extends Effect.Service()('@expandai/cli/Install/Hook', {
20
+ dependencies: [Mcp.Default, ClaudeHook.Default, OpencodeHook.Default],
21
+ effect: Effect.gen(function* () {
22
+ const mcp = yield* Mcp;
23
+ const claudeHook = yield* ClaudeHook;
24
+ const opencodeHook = yield* OpencodeHook;
25
+ const install = Effect.fn('HookInstaller.install')(function* (host, scope) {
26
+ // Bundle: MCP install first, then host-specific hook config.
27
+ yield* mcp.install(host, scope);
28
+ yield* Match.value(host).pipe(Match.when('claude-code', () => claudeHook.install(scope)), Match.when('opencode', () => opencodeHook.install(scope)), Match.exhaustive);
29
+ });
30
+ const uninstall = Effect.fn('HookInstaller.uninstall')(function* (host, scope) {
31
+ yield* Match.value(host).pipe(Match.when('claude-code', () => claudeHook.uninstall(scope)), Match.when('opencode', () => opencodeHook.uninstall(scope)), Match.exhaustive);
32
+ yield* mcp.uninstall(host, scope);
33
+ });
34
+ return { install, uninstall };
35
+ }),
36
+ }) {
37
+ }
38
+ //# sourceMappingURL=Hook.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Hook.js","sourceRoot":"","sources":["../../../src/Install/Hook.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAC9C,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAC7C,OAAO,EAAE,GAAG,EAAc,MAAM,UAAU,CAAA;AAC1C,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AAEjD;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,MAAM,QAAQ,GAAG,MAAM,CAAC,OAAO,CAAC,aAAa,EAAE,UAAU,CAAC,CAAA;AAGjE,MAAM,OAAO,aAAc,SAAQ,MAAM,CAAC,OAAO,EAAiB,CAAC,4BAA4B,EAAE;IAChG,YAAY,EAAE,CAAC,GAAG,CAAC,OAAO,EAAE,UAAU,CAAC,OAAO,EAAE,YAAY,CAAC,OAAO,CAAC;IACrE,MAAM,EAAE,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;QAC3B,MAAM,GAAG,GAAG,KAAK,CAAC,CAAC,GAAG,CAAA;QACtB,MAAM,UAAU,GAAG,KAAK,CAAC,CAAC,UAAU,CAAA;QACpC,MAAM,YAAY,GAAG,KAAK,CAAC,CAAC,YAAY,CAAA;QAExC,MAAM,OAAO,GAAG,MAAM,CAAC,EAAE,CAAC,uBAAuB,CAAC,CAAC,QAAQ,CAAC,EAAE,IAAc,EAAE,KAAY;YACzF,6DAA6D;YAC7D,KAAK,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,CAAA;YAC/B,KAAK,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,CAC5B,KAAK,CAAC,IAAI,CAAC,aAAa,EAAE,GAAG,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAC1D,KAAK,CAAC,IAAI,CAAC,UAAU,EAAE,GAAG,EAAE,CAAC,YAAY,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EACzD,KAAK,CAAC,UAAU,CAChB,CAAA;QACF,CAAC,CAAC,CAAA;QAEF,MAAM,SAAS,GAAG,MAAM,CAAC,EAAE,CAAC,yBAAyB,CAAC,CAAC,QAAQ,CAAC,EAAE,IAAc,EAAE,KAAY;YAC7F,KAAK,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,CAC5B,KAAK,CAAC,IAAI,CAAC,aAAa,EAAE,GAAG,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,EAC5D,KAAK,CAAC,IAAI,CAAC,UAAU,EAAE,GAAG,EAAE,CAAC,YAAY,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,EAC3D,KAAK,CAAC,UAAU,CAChB,CAAA;YACD,KAAK,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,EAAE,KAAK,CAAC,CAAA;QAClC,CAAC,CAAC,CAAA;QAEF,OAAO,EAAE,OAAO,EAAE,SAAS,EAAW,CAAA;IACvC,CAAC,CAAC;CACF,CAAC;CAAG"}
@@ -0,0 +1,40 @@
1
+ import { Effect, Match } from 'effect';
2
+ import { ClaudeMcp } from './Claude/Mcp.js';
3
+ import { CodexMcp } from './Codex/Mcp.js';
4
+ import { CursorMcp } from './Cursor/Mcp.js';
5
+ import { OpencodeMcp } from './Opencode/Mcp.js';
6
+ export { Host, McpParseError, McpWriteError, Scope } from './Domain.js';
7
+ /**
8
+ * MCP install dispatcher. Per-host descriptors live in `Install/<Host>/Mcp.ts`
9
+ * and contribute their path resolution + entry shape; this service handles
10
+ * the file I/O (read existing config, merge, write back) and routes by host.
11
+ *
12
+ * - claude-code (~/.claude.json | <cwd>/.mcp.json) → mcpServers shape
13
+ * - cursor (~/.cursor/mcp.json | <cwd>/.cursor/mcp.json) → mcpServers
14
+ * - opencode (~/.config/opencode/opencode.json | <cwd>/opencode.json) → opencode `mcp` shape
15
+ * - codex (~/.codex/config.toml | <cwd>/.codex/config.toml) → Codex TOML `mcp_servers`
16
+ */
17
+ export class Mcp extends Effect.Service()('@expandai/cli/Install/Mcp', {
18
+ dependencies: [ClaudeMcp.Default, CursorMcp.Default, OpencodeMcp.Default, CodexMcp.Default],
19
+ effect: Effect.gen(function* () {
20
+ const claude = yield* ClaudeMcp;
21
+ const cursor = yield* CursorMcp;
22
+ const opencode = yield* OpencodeMcp;
23
+ const codex = yield* CodexMcp;
24
+ const pathFor = Effect.fn('Mcp.pathFor')(function* (host, scope) {
25
+ return yield* Match.value(host).pipe(Match.when('claude-code', () => claude.pathFor(scope)), Match.when('cursor', () => cursor.pathFor(scope)), Match.when('opencode', () => opencode.pathFor(scope)), Match.when('codex', () => codex.pathFor(scope)), Match.exhaustive);
26
+ });
27
+ const install = Effect.fn('Mcp.install')(function* (host, scope) {
28
+ yield* Match.value(host).pipe(Match.when('claude-code', () => claude.install(scope)), Match.when('cursor', () => cursor.install(scope)), Match.when('opencode', () => opencode.install(scope)), Match.when('codex', () => codex.install(scope)), Match.exhaustive);
29
+ });
30
+ const uninstall = Effect.fn('Mcp.uninstall')(function* (host, scope) {
31
+ yield* Match.value(host).pipe(Match.when('claude-code', () => claude.uninstall(scope)), Match.when('cursor', () => cursor.uninstall(scope)), Match.when('opencode', () => opencode.uninstall(scope)), Match.when('codex', () => codex.uninstall(scope)), Match.exhaustive);
32
+ });
33
+ const isInstalled = Effect.fn('Mcp.isInstalled')(function* (host, scope) {
34
+ return yield* Match.value(host).pipe(Match.when('claude-code', () => claude.isInstalled(scope)), Match.when('cursor', () => cursor.isInstalled(scope)), Match.when('opencode', () => opencode.isInstalled(scope)), Match.when('codex', () => codex.isInstalled(scope)), Match.exhaustive);
35
+ });
36
+ return { install, uninstall, isInstalled, pathFor };
37
+ }),
38
+ }) {
39
+ }
40
+ //# sourceMappingURL=Mcp.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Mcp.js","sourceRoot":"","sources":["../../../src/Install/Mcp.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,44 @@
1
+ import { homedir } from 'node:os';
2
+ import { FileSystem, Path } from '@effect/platform';
3
+ import { NodeFileSystem, NodePath } from '@effect/platform-node';
4
+ import { Config, Console, Effect, Match } from 'effect';
5
+ /**
6
+ * OpenCode hook = a JS plugin file at `.opencode/plugins/` (project) or
7
+ * `~/.config/opencode/plugins/` (global). The plugin shells out to
8
+ * `expandai hook opencode` so all fetch logic stays in the CLI.
9
+ *
10
+ * The plugin uses `tool.execute.after` (the only hook whose contract lets us
11
+ * replace the rendered result via `output.output`); `tool.execute.before` is
12
+ * limited to mutating tool args. See @opencode-ai/plugin's dist/index.d.ts.
13
+ */
14
+ export const PLUGIN_FILE = 'expandai-webfetch.js';
15
+ export class OpencodeHook extends Effect.Service()('@expandai/cli/Install/Opencode/Hook', {
16
+ dependencies: [NodeFileSystem.layer, NodePath.layer],
17
+ effect: Effect.gen(function* () {
18
+ const fs = yield* FileSystem.FileSystem;
19
+ const path = yield* Path.Path;
20
+ const source = path.join(path.dirname(yield* path.fromFileUrl(new URL(import.meta.url))), PLUGIN_FILE);
21
+ const home = yield* Config.string('HOME').pipe(Config.withDefault(homedir()));
22
+ const cwd = yield* Config.string('PWD').pipe(Config.withDefault(process.cwd()));
23
+ const pathFor = Effect.fn(function* (scope) {
24
+ return yield* Match.value(scope).pipe(Match.when('global', () => Effect.succeed(`${home}/.config/opencode/plugins/${PLUGIN_FILE}`)), Match.when('project', () => Effect.succeed(`${cwd}/.opencode/plugins/${PLUGIN_FILE}`)), Match.exhaustive);
25
+ });
26
+ const install = Effect.fn('OpencodeHook.install')(function* (scope) {
27
+ const target = yield* pathFor(scope);
28
+ yield* fs.makeDirectory(path.dirname(target), { recursive: true });
29
+ yield* fs.copyFile(source, target);
30
+ yield* Console.log(`Installed expandai webfetch plugin at ${target}`);
31
+ });
32
+ const uninstall = Effect.fn('OpencodeHook.uninstall')(function* (scope) {
33
+ const target = yield* pathFor(scope);
34
+ const exists = yield* fs.exists(target);
35
+ if (exists) {
36
+ yield* fs.remove(target);
37
+ yield* Console.log(`Removed expandai webfetch plugin from ${target}`);
38
+ }
39
+ });
40
+ return { install, uninstall };
41
+ }),
42
+ }) {
43
+ }
44
+ //# sourceMappingURL=Hook.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Hook.js","sourceRoot":"","sources":["../../../../src/Install/Opencode/Hook.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,73 @@
1
+ import { homedir } from 'node:os';
2
+ import { Config, Console, Effect, Match, Record, Schema } from 'effect';
3
+ import { ConfigIo, McpParseError, McpWriteError, OpencodeConfigSchema, SERVER_KEY } from '../Domain.js';
4
+ /**
5
+ * OpenCode MCP descriptor — its own shape (per opencode.ai/docs/mcp-servers):
6
+ * top-level key is `mcp` (not `mcpServers`), `command` is an array (no
7
+ * separate args), env is called `environment`, and `type` uses
8
+ * `local` / `remote` rather than `stdio` / `http`.
9
+ *
10
+ * - global → `~/.config/opencode/opencode.json`
11
+ * - project → `<cwd>/opencode.json`
12
+ */
13
+ export class Entry extends Schema.Class('OpencodeMcpEntry')({
14
+ type: Schema.Literal('local'),
15
+ command: Schema.Array(Schema.String),
16
+ environment: Schema.optional(Schema.Record({ key: Schema.String, value: Schema.String })),
17
+ enabled: Schema.optional(Schema.Boolean),
18
+ }) {
19
+ }
20
+ export class OpencodeMcp extends Effect.Service()('@expandai/cli/Install/Opencode/Mcp', {
21
+ dependencies: [ConfigIo.Default],
22
+ effect: Effect.gen(function* () {
23
+ const io = yield* ConfigIo;
24
+ const home = yield* Config.string('HOME').pipe(Config.withDefault(homedir()));
25
+ const cwd = yield* Config.string('PWD').pipe(Config.withDefault(process.cwd()));
26
+ const pathFor = Effect.fn(function* (scope) {
27
+ return yield* Match.value(scope).pipe(Match.when('global', () => Effect.succeed(`${home}/.config/opencode/opencode.json`)), Match.when('project', () => Effect.succeed(`${cwd}/opencode.json`)), Match.exhaustive);
28
+ });
29
+ const readConfig = Effect.fn(function* (file) {
30
+ return yield* io
31
+ .read(file, OpencodeConfigSchema)
32
+ .pipe(Effect.mapError((error) => new McpParseError({ path: file, error })));
33
+ });
34
+ const writeConfig = Effect.fn(function* (file, value) {
35
+ yield* io
36
+ .write(file, value, OpencodeConfigSchema)
37
+ .pipe(Effect.mapError((error) => new McpWriteError({ path: file, error })));
38
+ });
39
+ const install = Effect.fn(function* (scope) {
40
+ const file = yield* pathFor(scope);
41
+ const config = yield* readConfig(file);
42
+ yield* writeConfig(file, {
43
+ ...config,
44
+ mcp: {
45
+ ...config.mcp,
46
+ [SERVER_KEY]: new Entry({
47
+ type: 'local',
48
+ command: ['expandai', 'mcp', 'run'],
49
+ enabled: true,
50
+ }),
51
+ },
52
+ });
53
+ yield* Console.log(`Installed expandai MCP server into ${file}`);
54
+ });
55
+ const uninstall = Effect.fn(function* (scope) {
56
+ const file = yield* pathFor(scope);
57
+ const config = yield* readConfig(file);
58
+ if (!(SERVER_KEY in config.mcp)) {
59
+ return;
60
+ }
61
+ yield* writeConfig(file, { ...config, mcp: Record.remove(config.mcp, SERVER_KEY) });
62
+ yield* Console.log(`Removed expandai MCP server from ${file}`);
63
+ });
64
+ const isInstalled = Effect.fn(function* (scope) {
65
+ const file = yield* pathFor(scope);
66
+ const config = yield* readConfig(file);
67
+ return SERVER_KEY in config.mcp;
68
+ });
69
+ return { install, uninstall, isInstalled, pathFor };
70
+ }),
71
+ }) {
72
+ }
73
+ //# sourceMappingURL=Mcp.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Mcp.js","sourceRoot":"","sources":["../../../../src/Install/Opencode/Mcp.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,34 @@
1
+ import { homedir } from 'node:os';
2
+ import { Config, Effect, Match } from 'effect';
3
+ import { SkillIo } from '../Domain.js';
4
+ /**
5
+ * OpenCode skills are Claude-Code-compatible Markdown files. Per
6
+ * opencode.ai/docs/skills, OpenCode auto-discovers them under either
7
+ * `.opencode/skills/<name>/`, `.claude/skills/<name>/`, or
8
+ * `.agents/skills/<name>/` (and the `~/.config/opencode/...` equivalents
9
+ * for global). We ship to OpenCode-native paths.
10
+ *
11
+ * - global → `~/.config/opencode/skills/expandai/SKILL.md`
12
+ * - project → `<cwd>/.opencode/skills/expandai/SKILL.md`
13
+ */
14
+ export const SKILL_NAME = 'expandai';
15
+ export class OpencodeSkill extends Effect.Service()('@expandai/cli/Install/Opencode/Skill', {
16
+ dependencies: [SkillIo.Default],
17
+ effect: Effect.gen(function* () {
18
+ const io = yield* SkillIo;
19
+ const home = yield* Config.string('HOME').pipe(Config.withDefault(homedir()));
20
+ const cwd = yield* Config.string('PWD').pipe(Config.withDefault(process.cwd()));
21
+ const pathFor = Effect.fn(function* (scope) {
22
+ return yield* Match.value(scope).pipe(Match.when('global', () => Effect.succeed(`${home}/.config/opencode/skills/${SKILL_NAME}`)), Match.when('project', () => Effect.succeed(`${cwd}/.opencode/skills/${SKILL_NAME}`)), Match.exhaustive);
23
+ });
24
+ const install = Effect.fn(function* (scope) {
25
+ return yield* io.install(yield* pathFor(scope));
26
+ });
27
+ const uninstall = Effect.fn(function* (scope) {
28
+ return yield* io.uninstall(yield* pathFor(scope));
29
+ });
30
+ return { install, uninstall };
31
+ }),
32
+ }) {
33
+ }
34
+ //# sourceMappingURL=Skill.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Skill.js","sourceRoot":"","sources":["../../../../src/Install/Opencode/Skill.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAA;AACjC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAA;AAC9C,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AAGtC;;;;;;;;;GASG;AAEH,MAAM,CAAC,MAAM,UAAU,GAAG,UAAU,CAAA;AAEpC,MAAM,OAAO,aAAc,SAAQ,MAAM,CAAC,OAAO,EAAiB,CAAC,sCAAsC,EAAE;IAC1G,YAAY,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC;IAC/B,MAAM,EAAE,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;QAC3B,MAAM,EAAE,GAAG,KAAK,CAAC,CAAC,OAAO,CAAA;QACzB,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,OAAO,EAAE,CAAC,CAAC,CAAA;QAC7E,MAAM,GAAG,GAAG,KAAK,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC,CAAA;QAE/E,MAAM,OAAO,GAAG,MAAM,CAAC,EAAE,CAAC,QAAQ,CAAC,EAAE,KAAY;YAChD,OAAO,KAAK,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,IAAI,CACpC,KAAK,CAAC,IAAI,CAAC,QAAQ,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,IAAI,4BAA4B,UAAU,EAAE,CAAC,CAAC,EAC3F,KAAK,CAAC,IAAI,CAAC,SAAS,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,GAAG,qBAAqB,UAAU,EAAE,CAAC,CAAC,EACpF,KAAK,CAAC,UAAU,CAChB,CAAA;QACF,CAAC,CAAC,CAAA;QAEF,MAAM,OAAO,GAAG,MAAM,CAAC,EAAE,CAAC,QAAQ,CAAC,EAAE,KAAY;YAChD,OAAO,KAAK,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAA;QAChD,CAAC,CAAC,CAAA;QAEF,MAAM,SAAS,GAAG,MAAM,CAAC,EAAE,CAAC,QAAQ,CAAC,EAAE,KAAY;YAClD,OAAO,KAAK,CAAC,CAAC,EAAE,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAA;QAClD,CAAC,CAAC,CAAA;QAEF,OAAO,EAAE,OAAO,EAAE,SAAS,EAAW,CAAA;IACvC,CAAC,CAAC;CACF,CAAC;CAAG"}
@@ -0,0 +1,38 @@
1
+ // expandai OpenCode plugin - routes webfetch through the expandai CLI.
2
+ // Generated by `expandai hook install opencode <scope>`.
3
+ //
4
+ // We hook `tool.execute.after` rather than `.before` because OpenCode's plugin
5
+ // contract only lets `before` mutate args (`output.args`); replacing the
6
+ // rendered result is only possible from `after`, where `output` is the tool
7
+ // output object (`{ title, output, metadata }`). See @opencode-ai/plugin's
8
+ // dist/index.d.ts.
9
+ import { spawn } from 'node:child_process'
10
+
11
+ export const ExpandaiWebfetch = async () => ({
12
+ 'tool.execute.after': async (input, output) => {
13
+ if (input.tool !== 'webfetch') return
14
+ const url = input.args?.url
15
+ if (typeof url !== 'string' || url.length === 0) return
16
+
17
+ try {
18
+ const child = spawn('expandai', ['hook', 'opencode'], {
19
+ stdio: ['pipe', 'pipe', 'inherit'],
20
+ env: { ...process.env, EXPANDAI_CLI_CONTEXT: 'agent' },
21
+ })
22
+ child.stdin.end(JSON.stringify({ url }))
23
+ let stdout = ''
24
+ child.stdout.setEncoding('utf8')
25
+ for await (const chunk of child.stdout) stdout += chunk
26
+ const exitCode = await new Promise((resolve) => child.on('close', resolve))
27
+ if (exitCode !== 0 || stdout.trim().length === 0) return
28
+
29
+ const { markdown } = JSON.parse(stdout)
30
+ if (typeof markdown !== 'string' || markdown.length === 0) return
31
+
32
+ output.output = markdown
33
+ output.title = url
34
+ } catch (error) {
35
+ console.error(`expandai-webfetch plugin failed: ${error?.message ?? error}`)
36
+ }
37
+ },
38
+ })
@@ -0,0 +1,41 @@
1
+ import { Console, Effect, Match } from 'effect';
2
+ import { ClaudeSkill } from './Claude/Skill.js';
3
+ import { CodexSkill } from './Codex/Skill.js';
4
+ import { CursorSkill } from './Cursor/Skill.js';
5
+ import { OpencodeSkill } from './Opencode/Skill.js';
6
+ /**
7
+ * Skill install dispatcher. Copies the bundled `SKILL.md` from the CLI's
8
+ * own `skills/expandai/` source into the host-specific destination.
9
+ *
10
+ * - claude-code: `~/.claude/skills/expandai/` (global) or
11
+ * `<cwd>/.claude/skills/expandai/` (project)
12
+ * - cursor: `~/.cursor/skills/expandai/` (global) or
13
+ * `<cwd>/.cursor/skills/expandai/` (project)
14
+ * - opencode: `~/.config/opencode/skills/expandai/` (global) or
15
+ * `<cwd>/.opencode/skills/expandai/` (project)
16
+ * - codex: `~/.agents/skills/expandai/` (global) or
17
+ * `<cwd>/.agents/skills/expandai/` (project)
18
+ *
19
+ * All hosts use the same `SKILL.md` + YAML frontmatter open standard,
20
+ * so the bundled skill directory copies in unchanged.
21
+ */
22
+ export class Skill extends Effect.Service()('@expandai/cli/Install/Skill', {
23
+ dependencies: [ClaudeSkill.Default, CursorSkill.Default, OpencodeSkill.Default, CodexSkill.Default],
24
+ effect: Effect.gen(function* () {
25
+ const claude = yield* ClaudeSkill;
26
+ const cursor = yield* CursorSkill;
27
+ const opencode = yield* OpencodeSkill;
28
+ const codex = yield* CodexSkill;
29
+ const install = Effect.fn('Skill.install')(function* (host, scope) {
30
+ const target = yield* Match.value(host).pipe(Match.when('claude-code', () => claude.install(scope)), Match.when('cursor', () => cursor.install(scope)), Match.when('opencode', () => opencode.install(scope)), Match.when('codex', () => codex.install(scope)), Match.exhaustive);
31
+ yield* Console.log(`Installed expandai skill into ${target}`);
32
+ });
33
+ const uninstall = Effect.fn('Skill.uninstall')(function* (host, scope) {
34
+ const target = yield* Match.value(host).pipe(Match.when('claude-code', () => claude.uninstall(scope)), Match.when('cursor', () => cursor.uninstall(scope)), Match.when('opencode', () => opencode.uninstall(scope)), Match.when('codex', () => codex.uninstall(scope)), Match.exhaustive);
35
+ yield* Console.log(`Removed expandai skill from ${target}`);
36
+ });
37
+ return { install, uninstall };
38
+ }),
39
+ }) {
40
+ }
41
+ //# sourceMappingURL=Skill.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Skill.js","sourceRoot":"","sources":["../../../src/Install/Skill.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAA;AAC/C,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAC/C,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAC7C,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAE/C,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AAEnD;;;;;;;;;;;;;;;GAeG;AAEH,MAAM,OAAO,KAAM,SAAQ,MAAM,CAAC,OAAO,EAAS,CAAC,6BAA6B,EAAE;IACjF,YAAY,EAAE,CAAC,WAAW,CAAC,OAAO,EAAE,WAAW,CAAC,OAAO,EAAE,aAAa,CAAC,OAAO,EAAE,UAAU,CAAC,OAAO,CAAC;IACnG,MAAM,EAAE,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;QAC3B,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,WAAW,CAAA;QACjC,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,WAAW,CAAA;QACjC,MAAM,QAAQ,GAAG,KAAK,CAAC,CAAC,aAAa,CAAA;QACrC,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,UAAU,CAAA;QAE/B,MAAM,OAAO,GAAG,MAAM,CAAC,EAAE,CAAC,eAAe,CAAC,CAAC,QAAQ,CAAC,EAAE,IAAU,EAAE,KAAY;YAC7E,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,CAC3C,KAAK,CAAC,IAAI,CAAC,aAAa,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EACtD,KAAK,CAAC,IAAI,CAAC,QAAQ,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EACjD,KAAK,CAAC,IAAI,CAAC,UAAU,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EACrD,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAC/C,KAAK,CAAC,UAAU,CAChB,CAAA;YACD,KAAK,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,iCAAiC,MAAM,EAAE,CAAC,CAAA;QAC9D,CAAC,CAAC,CAAA;QAEF,MAAM,SAAS,GAAG,MAAM,CAAC,EAAE,CAAC,iBAAiB,CAAC,CAAC,QAAQ,CAAC,EAAE,IAAU,EAAE,KAAY;YACjF,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,CAC3C,KAAK,CAAC,IAAI,CAAC,aAAa,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,EACxD,KAAK,CAAC,IAAI,CAAC,QAAQ,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,EACnD,KAAK,CAAC,IAAI,CAAC,UAAU,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,EACvD,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,EACjD,KAAK,CAAC,UAAU,CAChB,CAAA;YACD,KAAK,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,+BAA+B,MAAM,EAAE,CAAC,CAAA;QAC5D,CAAC,CAAC,CAAA;QAEF,OAAO,EAAE,OAAO,EAAE,SAAS,EAAW,CAAA;IACvC,CAAC,CAAC;CACF,CAAC;CAAG"}
@@ -0,0 +1,49 @@
1
+ import { Array, Effect, Match, Schema } from 'effect';
2
+ import { HookInstaller } from './Hook.js';
3
+ import { Host, Mcp, Scope } from './Mcp.js';
4
+ import { Skill } from './Skill.js';
5
+ export const UninstallTarget = Schema.Literal('all', 'hook', 'skill', 'mcp');
6
+ export class UninstallOptions extends Schema.Class('UninstallOptions')({
7
+ target: Schema.optional(UninstallTarget),
8
+ host: Schema.optional(Host),
9
+ scope: Schema.optional(Scope),
10
+ }) {
11
+ }
12
+ const SCOPES = ['global', 'project'];
13
+ const HOSTS = ['claude-code', 'cursor', 'opencode', 'codex'];
14
+ const isHookHost = (host) => host === 'claude-code' || host === 'opencode';
15
+ export class Uninstall extends Effect.Service()('@expandai/cli/Install/Uninstall', {
16
+ dependencies: [HookInstaller.Default, Mcp.Default, Skill.Default],
17
+ effect: Effect.gen(function* () {
18
+ const hook = yield* HookInstaller;
19
+ const mcp = yield* Mcp;
20
+ const skill = yield* Skill;
21
+ const uninstall = Effect.fn(function* (options = new UninstallOptions({})) {
22
+ const target = options.target ?? 'all';
23
+ const hosts = options.host ? [options.host] : HOSTS;
24
+ const scopes = options.scope ? [options.scope] : SCOPES;
25
+ // Sequential by default: a future change that merges any two `(host,
26
+ // scope)` config paths into the same file shouldn't silently race.
27
+ // Logout/uninstall happens once per session; throughput isn't the
28
+ // bottleneck.
29
+ const uninstallHooks = Effect.fnUntraced(function* () {
30
+ const hookHosts = Array.filter(hosts, isHookHost);
31
+ yield* Effect.forEach(hookHosts, (host) => Effect.forEach(scopes, (scope) => hook.uninstall(host, scope), { discard: true }), { discard: true });
32
+ });
33
+ const uninstallSkills = Effect.fnUntraced(function* () {
34
+ yield* Effect.forEach(hosts, (host) => Effect.forEach(scopes, (scope) => skill.uninstall(host, scope), { discard: true }), { discard: true });
35
+ });
36
+ const uninstallMcp = Effect.fnUntraced(function* () {
37
+ yield* Effect.forEach(hosts, (host) => Effect.forEach(scopes, (scope) => mcp.uninstall(host, scope), { discard: true }), { discard: true });
38
+ });
39
+ const uninstallMcpWithoutHooks = Effect.fnUntraced(function* () {
40
+ const mcpOnlyHosts = Array.filter(hosts, (host) => !isHookHost(host));
41
+ yield* Effect.forEach(mcpOnlyHosts, (host) => Effect.forEach(scopes, (scope) => mcp.uninstall(host, scope), { discard: true }), { discard: true });
42
+ });
43
+ yield* Match.value(target).pipe(Match.when('all', () => uninstallHooks().pipe(Effect.zipRight(uninstallMcpWithoutHooks()), Effect.zipRight(uninstallSkills()))), Match.when('hook', () => uninstallHooks()), Match.when('skill', () => uninstallSkills()), Match.when('mcp', () => uninstallMcp()), Match.exhaustive);
44
+ });
45
+ return { uninstall };
46
+ }),
47
+ }) {
48
+ }
49
+ //# sourceMappingURL=Uninstall.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Uninstall.js","sourceRoot":"","sources":["../../../src/Install/Uninstall.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,64 @@
1
+ import { McpServer } from '@effect/ai';
2
+ import { Effect, Layer, String } from 'effect';
3
+ export const EXPAND_AGENT_SETUP_PROMPT = 'Read https://expand.ai/start.md and set up Expand for this project. Ask whether I want SDK/API, CLI, or agent-harness integration, then follow the matching instructions.';
4
+ export const EXPAND_START_GUIDE_MARKDOWN = String.stripMargin(`
5
+ |# Expand Start Guide
6
+ |
7
+ |Use this local copy when an MCP client needs setup guidance without fetching the hosted guide first.
8
+ |
9
+ |## Agent Setup Prompt
10
+ |
11
+ |${EXPAND_AGENT_SETUP_PROMPT}
12
+ |
13
+ |## Required CLI Setup
14
+ |
15
+ |\`\`\`sh
16
+ |expandai login
17
+ |\`\`\`
18
+ |
19
+ |## Claude Code
20
+ |
21
+ |\`\`\`sh
22
+ |expandai hook install claude-code project
23
+ |\`\`\`
24
+ |
25
+ |## OpenCode
26
+ |
27
+ |\`\`\`sh
28
+ |expandai hook install opencode project
29
+ |\`\`\`
30
+ |
31
+ |## Cursor
32
+ |
33
+ |\`\`\`sh
34
+ |expandai skill install cursor project
35
+ |expandai mcp install cursor project
36
+ |\`\`\`
37
+ |
38
+ |## Codex
39
+ |
40
+ |\`\`\`sh
41
+ |expandai skill install codex project
42
+ |expandai mcp install codex project
43
+ |\`\`\`
44
+ |`);
45
+ export const ExpandDocs = McpServer.resource({
46
+ uri: 'expand://about',
47
+ name: 'About expand.ai',
48
+ description: 'Key links for the expand.ai platform',
49
+ content: Effect.succeed(String.stripMargin(`
50
+ |# expand.ai
51
+ |
52
+ |- Website: https://expand.ai
53
+ |- Quickstart: https://expand.ai/docs
54
+ |- Dashboard: https://expand.ai/dashboard
55
+ |`)),
56
+ });
57
+ export const ExpandStartDocs = McpServer.resource({
58
+ uri: 'expand://start',
59
+ name: 'Expand Start Guide',
60
+ description: 'Local copy of the Expand agent and editor setup guide',
61
+ content: Effect.succeed(EXPAND_START_GUIDE_MARKDOWN),
62
+ });
63
+ export const ExpandDocsLayer = Layer.mergeAll(ExpandDocs, ExpandStartDocs);
64
+ //# sourceMappingURL=ExpandDocs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ExpandDocs.js","sourceRoot":"","sources":["../../../src/Mcp/ExpandDocs.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAA;AACtC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAE9C,MAAM,CAAC,MAAM,yBAAyB,GACrC,2KAA2K,CAAA;AAE5K,MAAM,CAAC,MAAM,2BAA2B,GAAG,MAAM,CAAC,WAAW,CAAC;;;;;;;IAO1D,yBAAyB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiC1B,CAAC,CAAA;AAEJ,MAAM,CAAC,MAAM,UAAU,GAAG,SAAS,CAAC,QAAQ,CAAC;IAC5C,GAAG,EAAE,gBAAgB;IACrB,IAAI,EAAE,iBAAiB;IACvB,WAAW,EAAE,sCAAsC;IACnD,OAAO,EAAE,MAAM,CAAC,OAAO,CACtB,MAAM,CAAC,WAAW,CAAC;;;;;;KAMhB,CAAC,CACJ;CACD,CAAC,CAAA;AAEF,MAAM,CAAC,MAAM,eAAe,GAAG,SAAS,CAAC,QAAQ,CAAC;IACjD,GAAG,EAAE,gBAAgB;IACrB,IAAI,EAAE,oBAAoB;IAC1B,WAAW,EAAE,uDAAuD;IACpE,OAAO,EAAE,MAAM,CAAC,OAAO,CAAC,2BAA2B,CAAC;CACpD,CAAC,CAAA;AAEF,MAAM,CAAC,MAAM,eAAe,GAAG,KAAK,CAAC,QAAQ,CAAC,UAAU,EAAE,eAAe,CAAC,CAAA"}
@@ -0,0 +1,13 @@
1
+ import { Context, Layer } from 'effect';
2
+ /**
3
+ * Per-request HTTP headers (lowercase keys per WHATWG Headers).
4
+ *
5
+ * Consumers should read this via `Effect.serviceOption(CurrentRequestHeaders)`
6
+ * so the requirement does not leak into their `R`. The API's MCP route
7
+ * overlays a fresh `Context.make` per request; the stdio CLI path leaves
8
+ * the option as `none`.
9
+ */
10
+ export class CurrentRequestHeaders extends Context.Tag('@expandai/cli/Mcp/RequestHeaders/CurrentRequestHeaders')() {
11
+ static Default = Layer.succeed(this, {});
12
+ }
13
+ //# sourceMappingURL=RequestHeaders.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RequestHeaders.js","sourceRoot":"","sources":["../../../src/Mcp/RequestHeaders.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAA;AAEvC;;;;;;;GAOG;AACH,MAAM,OAAO,qBAAsB,SAAQ,OAAO,CAAC,GAAG,CAAC,wDAAwD,CAAC,EAG7G;IACF,MAAM,CAAU,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,CAAA"}
@@ -0,0 +1,11 @@
1
+ import { Layer } from 'effect';
2
+ import { SERVER_KEY } from '../Install/Domain.js';
3
+ import { ExpandDocsLayer } from './ExpandDocs.js';
4
+ import { ExpandToolKit } from './Toolkit.js';
5
+ export { CurrentRequestHeaders } from './RequestHeaders.js';
6
+ export const ServerInfo = {
7
+ name: SERVER_KEY,
8
+ version: '0.0.1',
9
+ };
10
+ export const makeServerLayer = (options = {}) => options.includeDocs ? Layer.mergeAll(ExpandToolKit, ExpandDocsLayer) : ExpandToolKit;
11
+ //# sourceMappingURL=Server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Server.js","sourceRoot":"","sources":["../../../src/Mcp/Server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAA;AAC9B,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAA;AACjD,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AACjD,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAA;AAE5C,OAAO,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAA;AAE3D,MAAM,CAAC,MAAM,UAAU,GAAG;IACzB,IAAI,EAAE,UAAU;IAChB,OAAO,EAAE,OAAO;CACP,CAAA;AAEV,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,UAA8C,EAAE,EAAE,EAAE,CACnF,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,aAAa,EAAE,eAAe,CAAC,CAAC,CAAC,CAAC,aAAa,CAAA"}
@@ -0,0 +1,16 @@
1
+ import { McpServer, Toolkit } from '@effect/ai';
2
+ import { Effect, Layer } from 'effect';
3
+ import { ApiClient } from '../ApiClient.js';
4
+ import { Fetch, FetchSearchTool, FetchTool } from './tools/Fetch.js';
5
+ const toolkit = Toolkit.make(FetchTool, FetchSearchTool);
6
+ const ToolkitLayer = toolkit
7
+ .toLayer(Effect.gen(function* () {
8
+ const fetchService = yield* Fetch;
9
+ return toolkit.of({
10
+ fetch: fetchService.fetch,
11
+ fetch_search: fetchService.fetchSearch,
12
+ });
13
+ }))
14
+ .pipe(Layer.provide(Fetch.Default), Layer.provide(ApiClient.Default));
15
+ export const ExpandToolKit = McpServer.toolkit(toolkit).pipe(Layer.provide(ToolkitLayer));
16
+ //# sourceMappingURL=Toolkit.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Toolkit.js","sourceRoot":"","sources":["../../../src/Mcp/Toolkit.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,YAAY,CAAA;AAC/C,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAA;AACtC,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAC3C,OAAO,EAAE,KAAK,EAAE,eAAe,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAA;AAEpE,MAAM,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,SAAS,EAAE,eAAe,CAAC,CAAA;AAExD,MAAM,YAAY,GAAG,OAAO;KAC1B,OAAO,CACP,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;IACnB,MAAM,YAAY,GAAG,KAAK,CAAC,CAAC,KAAK,CAAA;IAEjC,OAAO,OAAO,CAAC,EAAE,CAAC;QACjB,KAAK,EAAE,YAAY,CAAC,KAAK;QACzB,YAAY,EAAE,YAAY,CAAC,WAAW;KACtC,CAAC,CAAA;AACH,CAAC,CAAC,CACF;KACA,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAA;AAEtE,MAAM,CAAC,MAAM,aAAa,GAAG,SAAS,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC,CAAA"}