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.
- package/README.md +241 -6
- package/build/dts/ApiClient.d.ts +231 -0
- package/build/dts/ApiClient.d.ts.map +1 -0
- package/build/dts/Authentication.d.ts +23 -0
- package/build/dts/Authentication.d.ts.map +1 -0
- package/build/dts/BrowserOAuth.d.ts +99 -0
- package/build/dts/BrowserOAuth.d.ts.map +1 -0
- package/build/dts/Commands/Fetch.d.ts +30 -0
- package/build/dts/Commands/Fetch.d.ts.map +1 -0
- package/build/dts/Commands/Hook.d.ts +17 -0
- package/build/dts/Commands/Hook.d.ts.map +1 -0
- package/build/dts/Commands/Mcp.d.ts +11 -0
- package/build/dts/Commands/Mcp.d.ts.map +1 -0
- package/build/dts/Commands/McpRun.d.ts +5 -0
- package/build/dts/Commands/McpRun.d.ts.map +1 -0
- package/build/dts/Commands/Search.d.ts +21 -0
- package/build/dts/Commands/Search.d.ts.map +1 -0
- package/build/dts/Commands/Skill.d.ts +12 -0
- package/build/dts/Commands/Skill.d.ts.map +1 -0
- package/build/dts/Commands/Uninstall.d.ts +9 -0
- package/build/dts/Commands/Uninstall.d.ts.map +1 -0
- package/build/dts/Config.d.ts +105 -0
- package/build/dts/Config.d.ts.map +1 -0
- package/build/dts/DeviceAuth.d.ts +87 -0
- package/build/dts/DeviceAuth.d.ts.map +1 -0
- package/build/dts/Hook/Claude.d.ts +13 -0
- package/build/dts/Hook/Claude.d.ts.map +1 -0
- package/build/dts/Hook/Errors.d.ts +20 -0
- package/build/dts/Hook/Errors.d.ts.map +1 -0
- package/build/dts/Hook/Opencode.d.ts +13 -0
- package/build/dts/Hook/Opencode.d.ts.map +1 -0
- package/build/dts/Hook/SnapshotNote.d.ts +8 -0
- package/build/dts/Hook/SnapshotNote.d.ts.map +1 -0
- package/build/dts/Install/Claude/Hook.d.ts +60 -0
- package/build/dts/Install/Claude/Hook.d.ts.map +1 -0
- package/build/dts/Install/Claude/Mcp.d.ts +45 -0
- package/build/dts/Install/Claude/Mcp.d.ts.map +1 -0
- package/build/dts/Install/Claude/Skill.d.ts +24 -0
- package/build/dts/Install/Claude/Skill.d.ts.map +1 -0
- package/build/dts/Install/Codex/Mcp.d.ts +39 -0
- package/build/dts/Install/Codex/Mcp.d.ts.map +1 -0
- package/build/dts/Install/Codex/Skill.d.ts +20 -0
- package/build/dts/Install/Codex/Skill.d.ts.map +1 -0
- package/build/dts/Install/Cursor/Mcp.d.ts +45 -0
- package/build/dts/Install/Cursor/Mcp.d.ts.map +1 -0
- package/build/dts/Install/Cursor/Skill.d.ts +27 -0
- package/build/dts/Install/Cursor/Skill.d.ts.map +1 -0
- package/build/dts/Install/Domain.d.ts +73 -0
- package/build/dts/Install/Domain.d.ts.map +1 -0
- package/build/dts/Install/Hook.d.ts +30 -0
- package/build/dts/Install/Hook.d.ts.map +1 -0
- package/build/dts/Install/Mcp.d.ts +28 -0
- package/build/dts/Install/Mcp.d.ts.map +1 -0
- package/build/dts/Install/Opencode/Hook.d.ts +23 -0
- package/build/dts/Install/Opencode/Hook.d.ts.map +1 -0
- package/build/dts/Install/Opencode/Mcp.d.ts +47 -0
- package/build/dts/Install/Opencode/Mcp.d.ts.map +1 -0
- package/build/dts/Install/Opencode/Skill.d.ts +24 -0
- package/build/dts/Install/Opencode/Skill.d.ts.map +1 -0
- package/build/dts/Install/Skill.d.ts +32 -0
- package/build/dts/Install/Skill.d.ts.map +1 -0
- package/build/dts/Install/Uninstall.d.ts +32 -0
- package/build/dts/Install/Uninstall.d.ts.map +1 -0
- package/build/dts/Mcp/ExpandDocs.d.ts +7 -0
- package/build/dts/Mcp/ExpandDocs.d.ts.map +1 -0
- package/build/dts/Mcp/RequestHeaders.d.ts +15 -0
- package/build/dts/Mcp/RequestHeaders.d.ts.map +1 -0
- package/build/dts/Mcp/Server.d.ts +10 -0
- package/build/dts/Mcp/Server.d.ts.map +1 -0
- package/build/dts/Mcp/Toolkit.d.ts +3 -0
- package/build/dts/Mcp/Toolkit.d.ts.map +1 -0
- package/build/dts/Mcp/tools/Citations.d.ts +237 -0
- package/build/dts/Mcp/tools/Citations.d.ts.map +1 -0
- package/build/dts/Mcp/tools/Fetch.d.ts +167 -0
- package/build/dts/Mcp/tools/Fetch.d.ts.map +1 -0
- package/build/dts/Snippets.d.ts +19 -0
- package/build/dts/Snippets.d.ts.map +1 -0
- package/build/dts/index.d.ts +2 -0
- package/build/dts/index.d.ts.map +1 -0
- package/build/dts/main.d.ts +3 -0
- package/build/dts/main.d.ts.map +1 -0
- package/build/esm/ApiClient.js +182 -0
- package/build/esm/ApiClient.js.map +1 -0
- package/build/esm/Authentication.js +112 -0
- package/build/esm/Authentication.js.map +1 -0
- package/build/esm/BrowserOAuth.js +254 -0
- package/build/esm/BrowserOAuth.js.map +1 -0
- package/build/esm/Commands/Fetch.js +95 -0
- package/build/esm/Commands/Fetch.js.map +1 -0
- package/build/esm/Commands/Hook.js +20 -0
- package/build/esm/Commands/Hook.js.map +1 -0
- package/build/esm/Commands/Mcp.js +19 -0
- package/build/esm/Commands/Mcp.js.map +1 -0
- package/build/esm/Commands/McpRun.js +15 -0
- package/build/esm/Commands/McpRun.js.map +1 -0
- package/build/esm/Commands/Search.js +43 -0
- package/build/esm/Commands/Search.js.map +1 -0
- package/build/esm/Commands/Skill.js +17 -0
- package/build/esm/Commands/Skill.js.map +1 -0
- package/build/esm/Commands/Uninstall.js +28 -0
- package/build/esm/Commands/Uninstall.js.map +1 -0
- package/build/esm/Config.js +145 -0
- package/build/esm/Config.js.map +1 -0
- package/build/esm/DeviceAuth.js +127 -0
- package/build/esm/DeviceAuth.js.map +1 -0
- package/build/esm/Hook/Claude.js +74 -0
- package/build/esm/Hook/Claude.js.map +1 -0
- package/build/esm/Hook/Errors.js +18 -0
- package/build/esm/Hook/Errors.js.map +1 -0
- package/build/esm/Hook/Opencode.js +50 -0
- package/build/esm/Hook/Opencode.js.map +1 -0
- package/build/esm/Hook/SnapshotNote.js +18 -0
- package/build/esm/Hook/SnapshotNote.js.map +1 -0
- package/build/esm/Install/Claude/Hook.js +89 -0
- package/build/esm/Install/Claude/Hook.js.map +1 -0
- package/build/esm/Install/Claude/Mcp.js +71 -0
- package/build/esm/Install/Claude/Mcp.js.map +1 -0
- package/build/esm/Install/Claude/Skill.js +34 -0
- package/build/esm/Install/Claude/Skill.js.map +1 -0
- package/build/esm/Install/Codex/Mcp.js +92 -0
- package/build/esm/Install/Codex/Mcp.js.map +1 -0
- package/build/esm/Install/Codex/Skill.js +30 -0
- package/build/esm/Install/Codex/Skill.js.map +1 -0
- package/build/esm/Install/Cursor/Mcp.js +71 -0
- package/build/esm/Install/Cursor/Mcp.js.map +1 -0
- package/build/esm/Install/Cursor/Skill.js +37 -0
- package/build/esm/Install/Cursor/Skill.js.map +1 -0
- package/build/esm/Install/Domain.js +105 -0
- package/build/esm/Install/Domain.js.map +1 -0
- package/build/esm/Install/Hook.js +38 -0
- package/build/esm/Install/Hook.js.map +1 -0
- package/build/esm/Install/Mcp.js +40 -0
- package/build/esm/Install/Mcp.js.map +1 -0
- package/build/esm/Install/Opencode/Hook.js +44 -0
- package/build/esm/Install/Opencode/Hook.js.map +1 -0
- package/build/esm/Install/Opencode/Mcp.js +73 -0
- package/build/esm/Install/Opencode/Mcp.js.map +1 -0
- package/build/esm/Install/Opencode/Skill.js +34 -0
- package/build/esm/Install/Opencode/Skill.js.map +1 -0
- package/build/esm/Install/Opencode/expandai-webfetch.js +38 -0
- package/build/esm/Install/Skill.js +41 -0
- package/build/esm/Install/Skill.js.map +1 -0
- package/build/esm/Install/Uninstall.js +49 -0
- package/build/esm/Install/Uninstall.js.map +1 -0
- package/build/esm/Mcp/ExpandDocs.js +64 -0
- package/build/esm/Mcp/ExpandDocs.js.map +1 -0
- package/build/esm/Mcp/RequestHeaders.js +13 -0
- package/build/esm/Mcp/RequestHeaders.js.map +1 -0
- package/build/esm/Mcp/Server.js +11 -0
- package/build/esm/Mcp/Server.js.map +1 -0
- package/build/esm/Mcp/Toolkit.js +16 -0
- package/build/esm/Mcp/Toolkit.js.map +1 -0
- package/build/esm/Mcp/tools/Citations.js +92 -0
- package/build/esm/Mcp/tools/Citations.js.map +1 -0
- package/build/esm/Mcp/tools/Fetch.js +141 -0
- package/build/esm/Mcp/tools/Fetch.js.map +1 -0
- package/build/esm/Snippets.js +18 -0
- package/build/esm/Snippets.js.map +1 -0
- package/build/esm/index.js +2 -0
- package/build/esm/index.js.map +1 -0
- package/build/esm/main.js +97 -0
- package/build/esm/main.js.map +1 -0
- package/build/skills/expandai/SKILL.md +72 -0
- package/package.json +72 -10
- package/src/ApiClient.ts +257 -0
- package/src/Authentication.ts +164 -0
- package/src/BrowserOAuth.ts +361 -0
- package/src/Commands/Fetch.ts +157 -0
- package/src/Commands/Hook.ts +48 -0
- package/src/Commands/Mcp.ts +30 -0
- package/src/Commands/McpRun.ts +25 -0
- package/src/Commands/Search.ts +92 -0
- package/src/Commands/Skill.ts +30 -0
- package/src/Commands/Uninstall.ts +38 -0
- package/src/Config.ts +195 -0
- package/src/DeviceAuth.ts +193 -0
- package/src/Hook/Claude.ts +81 -0
- package/src/Hook/Errors.ts +19 -0
- package/src/Hook/Opencode.ts +58 -0
- package/src/Hook/SnapshotNote.ts +18 -0
- package/src/Install/Claude/Hook.ts +133 -0
- package/src/Install/Claude/Mcp.ts +82 -0
- package/src/Install/Claude/Skill.ts +44 -0
- package/src/Install/Codex/Mcp.ts +109 -0
- package/src/Install/Codex/Skill.ts +40 -0
- package/src/Install/Cursor/Mcp.ts +82 -0
- package/src/Install/Cursor/Skill.ts +47 -0
- package/src/Install/Domain.ts +148 -0
- package/src/Install/Hook.ts +50 -0
- package/src/Install/Mcp.ts +71 -0
- package/src/Install/Opencode/Hook.ts +55 -0
- package/src/Install/Opencode/Mcp.ts +84 -0
- package/src/Install/Opencode/Skill.ts +44 -0
- package/src/Install/Opencode/expandai-webfetch.d.ts +23 -0
- package/src/Install/Opencode/expandai-webfetch.js +38 -0
- package/src/Install/Skill.ts +57 -0
- package/src/Install/Uninstall.ts +82 -0
- package/src/Mcp/ExpandDocs.ts +71 -0
- package/src/Mcp/RequestHeaders.ts +16 -0
- package/src/Mcp/Server.ts +14 -0
- package/src/Mcp/Toolkit.ts +21 -0
- package/src/Mcp/tools/Citations.ts +110 -0
- package/src/Mcp/tools/Fetch.ts +177 -0
- package/src/Snippets.ts +32 -0
- package/src/index.ts +1 -0
- package/src/main.ts +146 -0
- package/bun.lockb +0 -0
- package/index.ts +0 -1
- 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"}
|