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,89 @@
|
|
|
1
|
+
import { homedir } from 'node:os';
|
|
2
|
+
import { Array, Config, Console, Effect, Match, Schema } from 'effect';
|
|
3
|
+
import { ConfigIo } from '../Domain.js';
|
|
4
|
+
/**
|
|
5
|
+
* Claude Code hook config — `~/.claude/settings.json` (global) or
|
|
6
|
+
* `<cwd>/.claude/settings.json` (project). PreToolUse hooks fire on built-in
|
|
7
|
+
* tools; we register the WebFetch matcher to route to `expandai hook claude-code`.
|
|
8
|
+
*/
|
|
9
|
+
export const HOOK_COMMAND = 'expandai hook claude-code';
|
|
10
|
+
export const WEBFETCH_MATCHER = 'WebFetch';
|
|
11
|
+
export const HookCommandEntry = Schema.Struct({
|
|
12
|
+
type: Schema.Literal('command'),
|
|
13
|
+
command: Schema.String,
|
|
14
|
+
});
|
|
15
|
+
export const HookMatcher = Schema.Struct({
|
|
16
|
+
matcher: Schema.optional(Schema.String),
|
|
17
|
+
hooks: Schema.Array(HookCommandEntry),
|
|
18
|
+
});
|
|
19
|
+
const HooksSection = Schema.Struct({ PreToolUse: Schema.optional(Schema.Array(HookMatcher)) }, Schema.Record({ key: Schema.String, value: Schema.Unknown }));
|
|
20
|
+
export const SettingsSchema = Schema.parseJson(Schema.Struct({ hooks: Schema.optionalWith(HooksSection, { default: () => ({}) }) }, Schema.Record({ key: Schema.String, value: Schema.Unknown })), { space: 2 });
|
|
21
|
+
export const expandaiMatcher = {
|
|
22
|
+
matcher: WEBFETCH_MATCHER,
|
|
23
|
+
hooks: [{ type: 'command', command: HOOK_COMMAND }],
|
|
24
|
+
};
|
|
25
|
+
export class ClaudeHook extends Effect.Service()('@expandai/cli/Install/Claude/Hook', {
|
|
26
|
+
dependencies: [ConfigIo.Default],
|
|
27
|
+
effect: Effect.gen(function* () {
|
|
28
|
+
const io = yield* ConfigIo;
|
|
29
|
+
const home = yield* Config.string('HOME').pipe(Config.withDefault(homedir()));
|
|
30
|
+
const cwd = yield* Config.string('PWD').pipe(Config.withDefault(process.cwd()));
|
|
31
|
+
const pathFor = Effect.fn(function* (scope) {
|
|
32
|
+
return yield* Match.value(scope).pipe(Match.when('global', () => Effect.succeed(`${home}/.claude/settings.json`)), Match.when('project', () => Effect.succeed(`${cwd}/.claude/settings.json`)), Match.exhaustive);
|
|
33
|
+
});
|
|
34
|
+
const install = Effect.fn('ClaudeHook.install')(function* (scope) {
|
|
35
|
+
const target = yield* pathFor(scope);
|
|
36
|
+
const settings = yield* io.read(target, SettingsSchema);
|
|
37
|
+
const preToolUse = settings.hooks.PreToolUse ?? [];
|
|
38
|
+
const alreadyInstalled = preToolUse.some((entry) => entry.matcher === WEBFETCH_MATCHER && entry.hooks.some((hook) => hook.command === HOOK_COMMAND));
|
|
39
|
+
if (alreadyInstalled) {
|
|
40
|
+
yield* Console.log(`expandai WebFetch hook already installed at ${target}`);
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
yield* io.write(target, {
|
|
44
|
+
...settings,
|
|
45
|
+
hooks: {
|
|
46
|
+
...settings.hooks,
|
|
47
|
+
PreToolUse: [...preToolUse, expandaiMatcher],
|
|
48
|
+
},
|
|
49
|
+
}, SettingsSchema);
|
|
50
|
+
yield* Console.log(`Installed expandai WebFetch hook at ${target}`);
|
|
51
|
+
});
|
|
52
|
+
const uninstall = Effect.fn('ClaudeHook.uninstall')(function* (scope) {
|
|
53
|
+
const target = yield* pathFor(scope);
|
|
54
|
+
const exists = yield* io.exists(target);
|
|
55
|
+
if (!exists) {
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
const settings = yield* io.read(target, SettingsSchema);
|
|
59
|
+
const preToolUse = settings.hooks.PreToolUse ?? [];
|
|
60
|
+
const updatedPreToolUse = Array.filter(Array.map(preToolUse, (entry) => ({
|
|
61
|
+
...entry,
|
|
62
|
+
hooks: Array.filter(entry.hooks, (hook) => hook.command !== HOOK_COMMAND),
|
|
63
|
+
})), (entry) => entry.matcher !== WEBFETCH_MATCHER || entry.hooks.length > 0);
|
|
64
|
+
// Compare total hook-command count rather than outer-array length:
|
|
65
|
+
// our HOOK_COMMAND can sit alongside other hooks in a shared matcher
|
|
66
|
+
// entry (e.g. a user merged it in by hand), in which case the entry
|
|
67
|
+
// stays after filtering but the inner hook count drops.
|
|
68
|
+
const countCommands = Effect.fn(function* (entries) {
|
|
69
|
+
return Array.reduce(entries, 0, (n, entry) => n + entry.hooks.length);
|
|
70
|
+
});
|
|
71
|
+
const before = yield* countCommands(preToolUse);
|
|
72
|
+
const after = yield* countCommands(updatedPreToolUse);
|
|
73
|
+
if (before === after) {
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
yield* io.write(target, {
|
|
77
|
+
...settings,
|
|
78
|
+
hooks: {
|
|
79
|
+
...settings.hooks,
|
|
80
|
+
PreToolUse: updatedPreToolUse,
|
|
81
|
+
},
|
|
82
|
+
}, SettingsSchema);
|
|
83
|
+
yield* Console.log(`Removed expandai WebFetch hook from ${target}`);
|
|
84
|
+
});
|
|
85
|
+
return { install, uninstall };
|
|
86
|
+
}),
|
|
87
|
+
}) {
|
|
88
|
+
}
|
|
89
|
+
//# sourceMappingURL=Hook.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Hook.js","sourceRoot":"","sources":["../../../../src/Install/Claude/Hook.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAA;AACjC,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AACtE,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAA;AAGvC;;;;GAIG;AAEH,MAAM,CAAC,MAAM,YAAY,GAAG,2BAA2B,CAAA;AACvD,MAAM,CAAC,MAAM,gBAAgB,GAAG,UAAU,CAAA;AAE1C,MAAM,CAAC,MAAM,gBAAgB,GAAG,MAAM,CAAC,MAAM,CAAC;IAC7C,IAAI,EAAE,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC;IAC/B,OAAO,EAAE,MAAM,CAAC,MAAM;CACtB,CAAC,CAAA;AAEF,MAAM,CAAC,MAAM,WAAW,GAAG,MAAM,CAAC,MAAM,CAAC;IACxC,OAAO,EAAE,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC;IACvC,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC,gBAAgB,CAAC;CACrC,CAAC,CAAA;AAEF,MAAM,YAAY,GAAG,MAAM,CAAC,MAAM,CACjC,EAAE,UAAU,EAAE,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,EAAE,EAC1D,MAAM,CAAC,MAAM,CAAC,EAAE,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,OAAO,EAAE,CAAC,CAC5D,CAAA;AAED,MAAM,CAAC,MAAM,cAAc,GAAG,MAAM,CAAC,SAAS,CAC7C,MAAM,CAAC,MAAM,CACZ,EAAE,KAAK,EAAE,MAAM,CAAC,YAAY,CAAC,YAAY,EAAE,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,CAA6B,EAAE,CAAC,EAAE,EACjG,MAAM,CAAC,MAAM,CAAC,EAAE,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,OAAO,EAAE,CAAC,CAC5D,EACD,EAAE,KAAK,EAAE,CAAC,EAAE,CACZ,CAAA;AAED,MAAM,CAAC,MAAM,eAAe,GAAG;IAC9B,OAAO,EAAE,gBAAgB;IACzB,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,SAAkB,EAAE,OAAO,EAAE,YAAY,EAAE,CAAC;CAC5D,CAAA;AAED,MAAM,OAAO,UAAW,SAAQ,MAAM,CAAC,OAAO,EAAc,CAAC,mCAAmC,EAAE;IACjG,YAAY,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC;IAChC,MAAM,EAAE,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;QAC3B,MAAM,EAAE,GAAG,KAAK,CAAC,CAAC,QAAQ,CAAA;QAC1B,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,wBAAwB,CAAC,CAAC,EAC3E,KAAK,CAAC,IAAI,CAAC,SAAS,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,GAAG,wBAAwB,CAAC,CAAC,EAC3E,KAAK,CAAC,UAAU,CAChB,CAAA;QACF,CAAC,CAAC,CAAA;QAEF,MAAM,OAAO,GAAG,MAAM,CAAC,EAAE,CAAC,oBAAoB,CAAC,CAAC,QAAQ,CAAC,EAAE,KAAY;YACtE,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAA;YACpC,MAAM,QAAQ,GAAG,KAAK,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,EAAE,cAAc,CAAC,CAAA;YAEvD,MAAM,UAAU,GAAG,QAAQ,CAAC,KAAK,CAAC,UAAU,IAAI,EAAE,CAAA;YAClD,MAAM,gBAAgB,GAAG,UAAU,CAAC,IAAI,CACvC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,OAAO,KAAK,gBAAgB,IAAI,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,OAAO,KAAK,YAAY,CAAC,CAC1G,CAAA;YAED,IAAI,gBAAgB,EAAE,CAAC;gBACtB,KAAK,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,+CAA+C,MAAM,EAAE,CAAC,CAAA;gBAC3E,OAAM;YACP,CAAC;YAED,KAAK,CAAC,CAAC,EAAE,CAAC,KAAK,CACd,MAAM,EACN;gBACC,GAAG,QAAQ;gBACX,KAAK,EAAE;oBACN,GAAG,QAAQ,CAAC,KAAK;oBACjB,UAAU,EAAE,CAAC,GAAG,UAAU,EAAE,eAAe,CAAC;iBAC5C;aACD,EACD,cAAc,CACd,CAAA;YACD,KAAK,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,uCAAuC,MAAM,EAAE,CAAC,CAAA;QACpE,CAAC,CAAC,CAAA;QAEF,MAAM,SAAS,GAAG,MAAM,CAAC,EAAE,CAAC,sBAAsB,CAAC,CAAC,QAAQ,CAAC,EAAE,KAAY;YAC1E,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAA;YACpC,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,CAAA;YACvC,IAAI,CAAC,MAAM,EAAE,CAAC;gBACb,OAAM;YACP,CAAC;YAED,MAAM,QAAQ,GAAG,KAAK,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,EAAE,cAAc,CAAC,CAAA;YACvD,MAAM,UAAU,GAAG,QAAQ,CAAC,KAAK,CAAC,UAAU,IAAI,EAAE,CAAA;YAClD,MAAM,iBAAiB,GAAG,KAAK,CAAC,MAAM,CACrC,KAAK,CAAC,GAAG,CAAC,UAAU,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;gBACjC,GAAG,KAAK;gBACR,KAAK,EAAE,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,OAAO,KAAK,YAAY,CAAC;aACzE,CAAC,CAAC,EACH,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,OAAO,KAAK,gBAAgB,IAAI,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CACvE,CAAA;YAED,mEAAmE;YACnE,qEAAqE;YACrE,oEAAoE;YACpE,wDAAwD;YACxD,MAAM,aAAa,GAAG,MAAM,CAAC,EAAE,CAAC,QAAQ,CAAC,EAAE,OAA0B;gBACpE,OAAO,KAAK,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,CAAA;YACtE,CAAC,CAAC,CAAA;YAEF,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,aAAa,CAAC,UAAU,CAAC,CAAA;YAC/C,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,aAAa,CAAC,iBAAiB,CAAC,CAAA;YACrD,IAAI,MAAM,KAAK,KAAK,EAAE,CAAC;gBACtB,OAAM;YACP,CAAC;YAED,KAAK,CAAC,CAAC,EAAE,CAAC,KAAK,CACd,MAAM,EACN;gBACC,GAAG,QAAQ;gBACX,KAAK,EAAE;oBACN,GAAG,QAAQ,CAAC,KAAK;oBACjB,UAAU,EAAE,iBAAiB;iBAC7B;aACD,EACD,cAAc,CACd,CAAA;YACD,KAAK,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,uCAAuC,MAAM,EAAE,CAAC,CAAA;QACpE,CAAC,CAAC,CAAA;QAEF,OAAO,EAAE,OAAO,EAAE,SAAS,EAAW,CAAA;IACvC,CAAC,CAAC;CACF,CAAC;CAAG"}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { homedir } from 'node:os';
|
|
2
|
+
import { Config, Console, Effect, Match, Record, Schema } from 'effect';
|
|
3
|
+
import { ConfigIo, McpParseError, McpServersConfigSchema, McpWriteError, SERVER_KEY } from '../Domain.js';
|
|
4
|
+
/**
|
|
5
|
+
* Claude Code MCP descriptor — `mcpServers` shape (de facto Claude Desktop
|
|
6
|
+
* convention; also read by Cursor and other clients).
|
|
7
|
+
*
|
|
8
|
+
* - global → `~/.claude.json` (Claude Code's user-scope store)
|
|
9
|
+
* - project → `<cwd>/.mcp.json` (the agent-agnostic project file)
|
|
10
|
+
*/
|
|
11
|
+
export class Entry extends Schema.Class('ClaudeMcpEntry')({
|
|
12
|
+
type: Schema.Literal('stdio'),
|
|
13
|
+
command: Schema.NonEmptyTrimmedString,
|
|
14
|
+
args: Schema.Array(Schema.String),
|
|
15
|
+
env: Schema.optional(Schema.Record({ key: Schema.String, value: Schema.String })),
|
|
16
|
+
}) {
|
|
17
|
+
}
|
|
18
|
+
export class ClaudeMcp extends Effect.Service()('@expandai/cli/Install/Claude/Mcp', {
|
|
19
|
+
dependencies: [ConfigIo.Default],
|
|
20
|
+
effect: Effect.gen(function* () {
|
|
21
|
+
const io = yield* ConfigIo;
|
|
22
|
+
const home = yield* Config.string('HOME').pipe(Config.withDefault(homedir()));
|
|
23
|
+
const cwd = yield* Config.string('PWD').pipe(Config.withDefault(process.cwd()));
|
|
24
|
+
const pathFor = Effect.fn(function* (scope) {
|
|
25
|
+
return yield* Match.value(scope).pipe(Match.when('global', () => Effect.succeed(`${home}/.claude.json`)), Match.when('project', () => Effect.succeed(`${cwd}/.mcp.json`)), Match.exhaustive);
|
|
26
|
+
});
|
|
27
|
+
const readConfig = Effect.fn(function* (file) {
|
|
28
|
+
return yield* io
|
|
29
|
+
.read(file, McpServersConfigSchema)
|
|
30
|
+
.pipe(Effect.mapError((error) => new McpParseError({ path: file, error })));
|
|
31
|
+
});
|
|
32
|
+
const writeConfig = Effect.fn(function* (file, value) {
|
|
33
|
+
yield* io
|
|
34
|
+
.write(file, value, McpServersConfigSchema)
|
|
35
|
+
.pipe(Effect.mapError((error) => new McpWriteError({ path: file, error })));
|
|
36
|
+
});
|
|
37
|
+
const install = Effect.fn(function* (scope) {
|
|
38
|
+
const file = yield* pathFor(scope);
|
|
39
|
+
const config = yield* readConfig(file);
|
|
40
|
+
yield* writeConfig(file, {
|
|
41
|
+
...config,
|
|
42
|
+
mcpServers: {
|
|
43
|
+
...config.mcpServers,
|
|
44
|
+
[SERVER_KEY]: new Entry({
|
|
45
|
+
type: 'stdio',
|
|
46
|
+
command: 'expandai',
|
|
47
|
+
args: ['mcp', 'run'],
|
|
48
|
+
}),
|
|
49
|
+
},
|
|
50
|
+
});
|
|
51
|
+
yield* Console.log(`Installed expandai MCP server into ${file}`);
|
|
52
|
+
});
|
|
53
|
+
const uninstall = Effect.fn(function* (scope) {
|
|
54
|
+
const file = yield* pathFor(scope);
|
|
55
|
+
const config = yield* readConfig(file);
|
|
56
|
+
if (!(SERVER_KEY in config.mcpServers)) {
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
yield* writeConfig(file, { ...config, mcpServers: Record.remove(config.mcpServers, SERVER_KEY) });
|
|
60
|
+
yield* Console.log(`Removed expandai MCP server from ${file}`);
|
|
61
|
+
});
|
|
62
|
+
const isInstalled = Effect.fn(function* (scope) {
|
|
63
|
+
const file = yield* pathFor(scope);
|
|
64
|
+
const config = yield* readConfig(file);
|
|
65
|
+
return SERVER_KEY in config.mcpServers;
|
|
66
|
+
});
|
|
67
|
+
return { install, uninstall, isInstalled, pathFor };
|
|
68
|
+
}),
|
|
69
|
+
}) {
|
|
70
|
+
}
|
|
71
|
+
//# sourceMappingURL=Mcp.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Mcp.js","sourceRoot":"","sources":["../../../../src/Install/Claude/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
|
+
* Claude Code skills live under `<scope>/.claude/skills/<name>/SKILL.md`.
|
|
6
|
+
*
|
|
7
|
+
* - global → `~/.claude/skills/expandai/SKILL.md`
|
|
8
|
+
* - project → `<cwd>/.claude/skills/expandai/SKILL.md`
|
|
9
|
+
*
|
|
10
|
+
* (Globally-scoped Claude Code skills are also reachable via `npx skills`,
|
|
11
|
+
* but file-copy gives us a uniform install path with OpenCode and works
|
|
12
|
+
* without npm.)
|
|
13
|
+
*/
|
|
14
|
+
export const SKILL_NAME = 'expandai';
|
|
15
|
+
export class ClaudeSkill extends Effect.Service()('@expandai/cli/Install/Claude/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}/.claude/skills/${SKILL_NAME}`)), Match.when('project', () => Effect.succeed(`${cwd}/.claude/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/Claude/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,WAAY,SAAQ,MAAM,CAAC,OAAO,EAAe,CAAC,oCAAoC,EAAE;IACpG,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,mBAAmB,UAAU,EAAE,CAAC,CAAC,EAClF,KAAK,CAAC,IAAI,CAAC,SAAS,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,GAAG,mBAAmB,UAAU,EAAE,CAAC,CAAC,EAClF,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,92 @@
|
|
|
1
|
+
import { homedir } from 'node:os';
|
|
2
|
+
import { Config, Console, Effect, Match, Record, Schema } from 'effect';
|
|
3
|
+
import { parse, stringify } from 'smol-toml';
|
|
4
|
+
import { ConfigIo, McpParseError, McpWriteError, SERVER_KEY } from '../Domain.js';
|
|
5
|
+
export class Entry extends Schema.Class('CodexMcpEntry')({
|
|
6
|
+
command: Schema.NonEmptyTrimmedString,
|
|
7
|
+
args: Schema.Array(Schema.String),
|
|
8
|
+
enabled: Schema.Boolean,
|
|
9
|
+
}) {
|
|
10
|
+
}
|
|
11
|
+
function isRecord(value) {
|
|
12
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
13
|
+
}
|
|
14
|
+
const getMcpServers = Effect.fn(function* (config) {
|
|
15
|
+
const servers = config.mcp_servers;
|
|
16
|
+
return isRecord(servers) ? servers : {};
|
|
17
|
+
});
|
|
18
|
+
function toStringifyValue(value) {
|
|
19
|
+
// smol-toml's stringify type accepts any; keep the unsafe boundary local.
|
|
20
|
+
return value;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Codex MCP descriptor — Codex stores MCP servers in TOML config under
|
|
24
|
+
* `[mcp_servers.<name>]`.
|
|
25
|
+
*
|
|
26
|
+
* - global → `~/.codex/config.toml`
|
|
27
|
+
* - project → `<cwd>/.codex/config.toml`
|
|
28
|
+
*/
|
|
29
|
+
export class CodexMcp extends Effect.Service()('@expandai/cli/Install/Codex/Mcp', {
|
|
30
|
+
dependencies: [ConfigIo.Default],
|
|
31
|
+
effect: Effect.gen(function* () {
|
|
32
|
+
const io = yield* ConfigIo;
|
|
33
|
+
const home = yield* Config.string('HOME').pipe(Config.withDefault(homedir()));
|
|
34
|
+
const cwd = yield* Config.string('PWD').pipe(Config.withDefault(process.cwd()));
|
|
35
|
+
const pathFor = Effect.fn(function* (scope) {
|
|
36
|
+
return yield* Match.value(scope).pipe(Match.when('global', () => Effect.succeed(`${home}/.codex/config.toml`)), Match.when('project', () => Effect.succeed(`${cwd}/.codex/config.toml`)), Match.exhaustive);
|
|
37
|
+
});
|
|
38
|
+
const readConfig = Effect.fn(function* (file) {
|
|
39
|
+
const text = yield* io.readText(file);
|
|
40
|
+
return yield* Effect.try({
|
|
41
|
+
try: () => parse(text, { integersAsBigInt: false }),
|
|
42
|
+
catch: (error) => new McpParseError({ path: file, error }),
|
|
43
|
+
});
|
|
44
|
+
});
|
|
45
|
+
const writeConfig = Effect.fn(function* (file, value) {
|
|
46
|
+
const encoded = yield* Effect.try({
|
|
47
|
+
try: () => stringify(toStringifyValue(value)),
|
|
48
|
+
catch: (error) => new McpWriteError({ path: file, error }),
|
|
49
|
+
});
|
|
50
|
+
yield* io.writeText(file, encoded).pipe(Effect.mapError((error) => new McpWriteError({ path: file, error })));
|
|
51
|
+
});
|
|
52
|
+
const install = Effect.fn(function* (scope) {
|
|
53
|
+
const file = yield* pathFor(scope);
|
|
54
|
+
const config = yield* readConfig(file);
|
|
55
|
+
const servers = yield* getMcpServers(config);
|
|
56
|
+
const entryModel = new Entry({
|
|
57
|
+
command: 'expandai',
|
|
58
|
+
args: ['mcp', 'run'],
|
|
59
|
+
enabled: true,
|
|
60
|
+
});
|
|
61
|
+
const entry = {
|
|
62
|
+
command: entryModel.command,
|
|
63
|
+
args: [...entryModel.args],
|
|
64
|
+
enabled: entryModel.enabled,
|
|
65
|
+
};
|
|
66
|
+
yield* writeConfig(file, {
|
|
67
|
+
...config,
|
|
68
|
+
mcp_servers: Record.set(servers, SERVER_KEY, entry),
|
|
69
|
+
});
|
|
70
|
+
yield* Console.log(`Installed expandai MCP server into ${file}`);
|
|
71
|
+
});
|
|
72
|
+
const uninstall = Effect.fn(function* (scope) {
|
|
73
|
+
const file = yield* pathFor(scope);
|
|
74
|
+
const config = yield* readConfig(file);
|
|
75
|
+
const servers = yield* getMcpServers(config);
|
|
76
|
+
if (!(SERVER_KEY in servers)) {
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
yield* writeConfig(file, { ...config, mcp_servers: Record.remove(servers, SERVER_KEY) });
|
|
80
|
+
yield* Console.log(`Removed expandai MCP server from ${file}`);
|
|
81
|
+
});
|
|
82
|
+
const isInstalled = Effect.fn(function* (scope) {
|
|
83
|
+
const file = yield* pathFor(scope);
|
|
84
|
+
const config = yield* readConfig(file);
|
|
85
|
+
const servers = yield* getMcpServers(config);
|
|
86
|
+
return SERVER_KEY in servers;
|
|
87
|
+
});
|
|
88
|
+
return { install, uninstall, isInstalled, pathFor };
|
|
89
|
+
}),
|
|
90
|
+
}) {
|
|
91
|
+
}
|
|
92
|
+
//# sourceMappingURL=Mcp.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Mcp.js","sourceRoot":"","sources":["../../../../src/Install/Codex/Mcp.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { homedir } from 'node:os';
|
|
2
|
+
import { Config, Effect, Match } from 'effect';
|
|
3
|
+
import { SkillIo } from '../Domain.js';
|
|
4
|
+
/**
|
|
5
|
+
* Codex skills use the open agent skills locations:
|
|
6
|
+
*
|
|
7
|
+
* - global → `~/.agents/skills/<name>/`
|
|
8
|
+
* - project → `<cwd>/.agents/skills/<name>/`
|
|
9
|
+
*/
|
|
10
|
+
export const SKILL_NAME = 'expandai';
|
|
11
|
+
export class CodexSkill extends Effect.Service()('@expandai/cli/Install/Codex/Skill', {
|
|
12
|
+
dependencies: [SkillIo.Default],
|
|
13
|
+
effect: Effect.gen(function* () {
|
|
14
|
+
const io = yield* SkillIo;
|
|
15
|
+
const home = yield* Config.string('HOME').pipe(Config.withDefault(homedir()));
|
|
16
|
+
const cwd = yield* Config.string('PWD').pipe(Config.withDefault(process.cwd()));
|
|
17
|
+
const pathFor = Effect.fn(function* (scope) {
|
|
18
|
+
return yield* Match.value(scope).pipe(Match.when('global', () => Effect.succeed(`${home}/.agents/skills/${SKILL_NAME}`)), Match.when('project', () => Effect.succeed(`${cwd}/.agents/skills/${SKILL_NAME}`)), Match.exhaustive);
|
|
19
|
+
});
|
|
20
|
+
const install = Effect.fn(function* (scope) {
|
|
21
|
+
return yield* io.install(yield* pathFor(scope));
|
|
22
|
+
});
|
|
23
|
+
const uninstall = Effect.fn(function* (scope) {
|
|
24
|
+
return yield* io.uninstall(yield* pathFor(scope));
|
|
25
|
+
});
|
|
26
|
+
return { install, uninstall };
|
|
27
|
+
}),
|
|
28
|
+
}) {
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=Skill.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Skill.js","sourceRoot":"","sources":["../../../../src/Install/Codex/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;;;;;GAKG;AAEH,MAAM,CAAC,MAAM,UAAU,GAAG,UAAU,CAAA;AAEpC,MAAM,OAAO,UAAW,SAAQ,MAAM,CAAC,OAAO,EAAc,CAAC,mCAAmC,EAAE;IACjG,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,mBAAmB,UAAU,EAAE,CAAC,CAAC,EAClF,KAAK,CAAC,IAAI,CAAC,SAAS,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,GAAG,mBAAmB,UAAU,EAAE,CAAC,CAAC,EAClF,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,71 @@
|
|
|
1
|
+
import { homedir } from 'node:os';
|
|
2
|
+
import { Config, Console, Effect, Match, Record, Schema } from 'effect';
|
|
3
|
+
import { ConfigIo, McpParseError, McpServersConfigSchema, McpWriteError, SERVER_KEY } from '../Domain.js';
|
|
4
|
+
/**
|
|
5
|
+
* Cursor MCP descriptor — same `mcpServers` shape as Claude Code, different
|
|
6
|
+
* paths.
|
|
7
|
+
*
|
|
8
|
+
* - global → `~/.cursor/mcp.json`
|
|
9
|
+
* - project → `<cwd>/.cursor/mcp.json`
|
|
10
|
+
*/
|
|
11
|
+
export class Entry extends Schema.Class('CursorMcpEntry')({
|
|
12
|
+
type: Schema.Literal('stdio'),
|
|
13
|
+
command: Schema.NonEmptyTrimmedString,
|
|
14
|
+
args: Schema.Array(Schema.String),
|
|
15
|
+
env: Schema.optional(Schema.Record({ key: Schema.String, value: Schema.String })),
|
|
16
|
+
}) {
|
|
17
|
+
}
|
|
18
|
+
export class CursorMcp extends Effect.Service()('@expandai/cli/Install/Cursor/Mcp', {
|
|
19
|
+
dependencies: [ConfigIo.Default],
|
|
20
|
+
effect: Effect.gen(function* () {
|
|
21
|
+
const io = yield* ConfigIo;
|
|
22
|
+
const home = yield* Config.string('HOME').pipe(Config.withDefault(homedir()));
|
|
23
|
+
const cwd = yield* Config.string('PWD').pipe(Config.withDefault(process.cwd()));
|
|
24
|
+
const pathFor = Effect.fn(function* (scope) {
|
|
25
|
+
return yield* Match.value(scope).pipe(Match.when('global', () => Effect.succeed(`${home}/.cursor/mcp.json`)), Match.when('project', () => Effect.succeed(`${cwd}/.cursor/mcp.json`)), Match.exhaustive);
|
|
26
|
+
});
|
|
27
|
+
const readConfig = Effect.fn(function* (file) {
|
|
28
|
+
return yield* io
|
|
29
|
+
.read(file, McpServersConfigSchema)
|
|
30
|
+
.pipe(Effect.mapError((error) => new McpParseError({ path: file, error })));
|
|
31
|
+
});
|
|
32
|
+
const writeConfig = Effect.fn(function* (file, value) {
|
|
33
|
+
yield* io
|
|
34
|
+
.write(file, value, McpServersConfigSchema)
|
|
35
|
+
.pipe(Effect.mapError((error) => new McpWriteError({ path: file, error })));
|
|
36
|
+
});
|
|
37
|
+
const install = Effect.fn(function* (scope) {
|
|
38
|
+
const file = yield* pathFor(scope);
|
|
39
|
+
const config = yield* readConfig(file);
|
|
40
|
+
yield* writeConfig(file, {
|
|
41
|
+
...config,
|
|
42
|
+
mcpServers: {
|
|
43
|
+
...config.mcpServers,
|
|
44
|
+
[SERVER_KEY]: new Entry({
|
|
45
|
+
type: 'stdio',
|
|
46
|
+
command: 'expandai',
|
|
47
|
+
args: ['mcp', 'run'],
|
|
48
|
+
}),
|
|
49
|
+
},
|
|
50
|
+
});
|
|
51
|
+
yield* Console.log(`Installed expandai MCP server into ${file}`);
|
|
52
|
+
});
|
|
53
|
+
const uninstall = Effect.fn(function* (scope) {
|
|
54
|
+
const file = yield* pathFor(scope);
|
|
55
|
+
const config = yield* readConfig(file);
|
|
56
|
+
if (!(SERVER_KEY in config.mcpServers)) {
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
yield* writeConfig(file, { ...config, mcpServers: Record.remove(config.mcpServers, SERVER_KEY) });
|
|
60
|
+
yield* Console.log(`Removed expandai MCP server from ${file}`);
|
|
61
|
+
});
|
|
62
|
+
const isInstalled = Effect.fn(function* (scope) {
|
|
63
|
+
const file = yield* pathFor(scope);
|
|
64
|
+
const config = yield* readConfig(file);
|
|
65
|
+
return SERVER_KEY in config.mcpServers;
|
|
66
|
+
});
|
|
67
|
+
return { install, uninstall, isInstalled, pathFor };
|
|
68
|
+
}),
|
|
69
|
+
}) {
|
|
70
|
+
}
|
|
71
|
+
//# sourceMappingURL=Mcp.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Mcp.js","sourceRoot":"","sources":["../../../../src/Install/Cursor/Mcp.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { homedir } from 'node:os';
|
|
2
|
+
import { Config, Effect, Match } from 'effect';
|
|
3
|
+
import { SkillIo } from '../Domain.js';
|
|
4
|
+
/**
|
|
5
|
+
* Cursor skills are auto-loaded from these locations (per
|
|
6
|
+
* cursor.com/docs/skills):
|
|
7
|
+
*
|
|
8
|
+
* - global → `~/.cursor/skills/<name>/`
|
|
9
|
+
* - project → `<cwd>/.cursor/skills/<name>/`
|
|
10
|
+
*
|
|
11
|
+
* Cursor also compat-loads `.claude/skills/`, `.codex/skills/`, `.agents/skills/`
|
|
12
|
+
* at both project and user scope, but we ship to Cursor's native paths.
|
|
13
|
+
*
|
|
14
|
+
* Format is the same SKILL.md + YAML frontmatter open standard as Claude Code
|
|
15
|
+
* and OpenCode, so the bundled `skills/expandai/` directory copies in unchanged.
|
|
16
|
+
*/
|
|
17
|
+
export const SKILL_NAME = 'expandai';
|
|
18
|
+
export class CursorSkill extends Effect.Service()('@expandai/cli/Install/Cursor/Skill', {
|
|
19
|
+
dependencies: [SkillIo.Default],
|
|
20
|
+
effect: Effect.gen(function* () {
|
|
21
|
+
const io = yield* SkillIo;
|
|
22
|
+
const home = yield* Config.string('HOME').pipe(Config.withDefault(homedir()));
|
|
23
|
+
const cwd = yield* Config.string('PWD').pipe(Config.withDefault(process.cwd()));
|
|
24
|
+
const pathFor = Effect.fn(function* (scope) {
|
|
25
|
+
return yield* Match.value(scope).pipe(Match.when('global', () => Effect.succeed(`${home}/.cursor/skills/${SKILL_NAME}`)), Match.when('project', () => Effect.succeed(`${cwd}/.cursor/skills/${SKILL_NAME}`)), Match.exhaustive);
|
|
26
|
+
});
|
|
27
|
+
const install = Effect.fn(function* (scope) {
|
|
28
|
+
return yield* io.install(yield* pathFor(scope));
|
|
29
|
+
});
|
|
30
|
+
const uninstall = Effect.fn(function* (scope) {
|
|
31
|
+
return yield* io.uninstall(yield* pathFor(scope));
|
|
32
|
+
});
|
|
33
|
+
return { install, uninstall };
|
|
34
|
+
}),
|
|
35
|
+
}) {
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=Skill.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Skill.js","sourceRoot":"","sources":["../../../../src/Install/Cursor/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;;;;;;;;;;;;GAYG;AAEH,MAAM,CAAC,MAAM,UAAU,GAAG,UAAU,CAAA;AAEpC,MAAM,OAAO,WAAY,SAAQ,MAAM,CAAC,OAAO,EAAe,CAAC,oCAAoC,EAAE;IACpG,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,mBAAmB,UAAU,EAAE,CAAC,CAAC,EAClF,KAAK,CAAC,IAAI,CAAC,SAAS,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,GAAG,mBAAmB,UAAU,EAAE,CAAC,CAAC,EAClF,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,105 @@
|
|
|
1
|
+
import { FileSystem, Path } from '@effect/platform';
|
|
2
|
+
import { NodeFileSystem, NodePath } from '@effect/platform-node';
|
|
3
|
+
import { Effect, Inspectable, Schema } from 'effect';
|
|
4
|
+
export class McpParseError extends Schema.TaggedError()('McpParseError', {
|
|
5
|
+
path: Schema.String,
|
|
6
|
+
error: Schema.Defect,
|
|
7
|
+
}) {
|
|
8
|
+
get message() {
|
|
9
|
+
return `Failed to parse MCP config at ${this.path}: ${Inspectable.format(this.error)}`;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
export class McpWriteError extends Schema.TaggedError()('McpWriteError', {
|
|
13
|
+
path: Schema.String,
|
|
14
|
+
error: Schema.Defect,
|
|
15
|
+
}) {
|
|
16
|
+
get message() {
|
|
17
|
+
return `Failed to write MCP config at ${this.path}: ${Inspectable.format(this.error)}`;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
export const Host = Schema.Literal('claude-code', 'cursor', 'opencode', 'codex');
|
|
21
|
+
export const Scope = Schema.Literal('project', 'global');
|
|
22
|
+
const McpServerMap = Schema.Record({ key: Schema.String, value: Schema.Unknown });
|
|
23
|
+
export const McpServersConfigSchema = Schema.parseJson(Schema.Struct({ mcpServers: Schema.optionalWith(McpServerMap, { default: () => ({}) }) }, McpServerMap), { space: 2 });
|
|
24
|
+
export const OpencodeConfigSchema = Schema.parseJson(Schema.Struct({ mcp: Schema.optionalWith(McpServerMap, { default: () => ({}) }) }, McpServerMap), { space: 2 });
|
|
25
|
+
export const SERVER_KEY = 'expandai';
|
|
26
|
+
export const readConfigText = Effect.fn(function* (file) {
|
|
27
|
+
const fs = yield* FileSystem.FileSystem;
|
|
28
|
+
const exists = yield* fs.exists(file);
|
|
29
|
+
if (!exists) {
|
|
30
|
+
return '{}';
|
|
31
|
+
}
|
|
32
|
+
return yield* fs.readFileString(file);
|
|
33
|
+
});
|
|
34
|
+
export const writeConfigText = Effect.fn(function* (file, text) {
|
|
35
|
+
const fs = yield* FileSystem.FileSystem;
|
|
36
|
+
const path = yield* Path.Path;
|
|
37
|
+
yield* fs.makeDirectory(path.dirname(file), { recursive: true });
|
|
38
|
+
yield* fs.writeFileString(file, `${text}\n`);
|
|
39
|
+
});
|
|
40
|
+
/**
|
|
41
|
+
* Captures `FileSystem` + `Path` once and exposes string-encoded JSON read/
|
|
42
|
+
* write methods that don't re-yield them on every call. Use this from inside
|
|
43
|
+
* an `Effect.Service` gen block so the install/uninstall methods don't have
|
|
44
|
+
* to re-thread `provideService` calls.
|
|
45
|
+
*/
|
|
46
|
+
export class ConfigIo extends Effect.Service()('@expandai/cli/Install/ConfigIo', {
|
|
47
|
+
dependencies: [NodeFileSystem.layer, NodePath.layer],
|
|
48
|
+
effect: Effect.gen(function* () {
|
|
49
|
+
const fs = yield* FileSystem.FileSystem;
|
|
50
|
+
const path = yield* Path.Path;
|
|
51
|
+
const read = Effect.fn('ConfigIo.read')(function* (file, schema) {
|
|
52
|
+
const text = yield* readConfigText(file).pipe(Effect.provideService(FileSystem.FileSystem, fs));
|
|
53
|
+
return yield* Schema.decode(schema)(text);
|
|
54
|
+
});
|
|
55
|
+
const write = Effect.fn('ConfigIo.write')(function* (file, value, schema) {
|
|
56
|
+
const encoded = yield* Schema.encodeUnknown(schema)(value);
|
|
57
|
+
yield* writeConfigText(file, encoded).pipe(Effect.provideService(FileSystem.FileSystem, fs), Effect.provideService(Path.Path, path));
|
|
58
|
+
});
|
|
59
|
+
const exists = Effect.fn('ConfigIo.exists')(function* (file) {
|
|
60
|
+
return yield* fs.exists(file);
|
|
61
|
+
});
|
|
62
|
+
// Raw text I/O for formats `ConfigIo.read`/`write` can't handle through a
|
|
63
|
+
// `Schema.parseJson(...)` schema (e.g. Codex's TOML). Missing file reads
|
|
64
|
+
// as an empty string — callers attach their own parser-specific default.
|
|
65
|
+
const readText = Effect.fn('ConfigIo.readText')(function* (file) {
|
|
66
|
+
const present = yield* fs.exists(file);
|
|
67
|
+
return present ? yield* fs.readFileString(file) : '';
|
|
68
|
+
});
|
|
69
|
+
const writeText = Effect.fn('ConfigIo.writeText')(function* (file, text) {
|
|
70
|
+
yield* writeConfigText(file, text).pipe(Effect.provideService(FileSystem.FileSystem, fs), Effect.provideService(Path.Path, path));
|
|
71
|
+
});
|
|
72
|
+
return { read, write, exists, readText, writeText };
|
|
73
|
+
}),
|
|
74
|
+
}) {
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Captures `FileSystem` + `Path` once and exposes skill directory copy/remove
|
|
78
|
+
* operations. The bundled `SKILL.md` lives at `<cli>/skills/expandai/` (or
|
|
79
|
+
* `<build>/skills/expandai/` in production); this service computes that path
|
|
80
|
+
* from its own `import.meta.url`, so per-host skill descriptors only need to
|
|
81
|
+
* provide `pathFor` and call `io.install(target)` / `io.uninstall(target)`.
|
|
82
|
+
*/
|
|
83
|
+
export class SkillIo extends Effect.Service()('@expandai/cli/Install/SkillIo', {
|
|
84
|
+
dependencies: [NodeFileSystem.layer, NodePath.layer],
|
|
85
|
+
effect: Effect.gen(function* () {
|
|
86
|
+
const fs = yield* FileSystem.FileSystem;
|
|
87
|
+
const path = yield* Path.Path;
|
|
88
|
+
const sourceDir = path.resolve(path.dirname(yield* path.fromFileUrl(new URL(import.meta.url))), '..', '..', 'skills', 'expandai');
|
|
89
|
+
const install = Effect.fn('SkillIo.install')(function* (target) {
|
|
90
|
+
yield* fs.makeDirectory(path.dirname(target), { recursive: true });
|
|
91
|
+
yield* fs.copy(sourceDir, target, { overwrite: true });
|
|
92
|
+
return target;
|
|
93
|
+
});
|
|
94
|
+
const uninstall = Effect.fn('SkillIo.uninstall')(function* (target) {
|
|
95
|
+
const exists = yield* fs.exists(target);
|
|
96
|
+
if (exists) {
|
|
97
|
+
yield* fs.remove(target, { recursive: true });
|
|
98
|
+
}
|
|
99
|
+
return target;
|
|
100
|
+
});
|
|
101
|
+
return { install, uninstall };
|
|
102
|
+
}),
|
|
103
|
+
}) {
|
|
104
|
+
}
|
|
105
|
+
//# sourceMappingURL=Domain.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Domain.js","sourceRoot":"","sources":["../../../src/Install/Domain.ts"],"names":[],"mappings":"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"}
|