expandai 0.0.2 → 0.0.3
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 +42 -5
- package/build/dts/ApiClient.d.ts +128 -194
- package/build/dts/ApiClient.d.ts.map +1 -1
- package/build/dts/Auth/Domain.d.ts +95 -0
- package/build/dts/Auth/Domain.d.ts.map +1 -0
- package/build/dts/Auth/ManualAuthorization.d.ts +107 -0
- package/build/dts/Auth/ManualAuthorization.d.ts.map +1 -0
- package/build/dts/Auth/PendingInit.d.ts +35 -0
- package/build/dts/Auth/PendingInit.d.ts.map +1 -0
- package/build/dts/Auth/Pkce.d.ts +10 -0
- package/build/dts/Auth/Pkce.d.ts.map +1 -0
- package/build/dts/Auth/SetupGrantAuthorization.d.ts +34 -0
- package/build/dts/Auth/SetupGrantAuthorization.d.ts.map +1 -0
- package/build/dts/Authentication.d.ts +10 -9
- package/build/dts/Authentication.d.ts.map +1 -1
- package/build/dts/BrowserOAuth.d.ts +7 -7
- package/build/dts/BrowserOAuth.d.ts.map +1 -1
- package/build/dts/CommandPath.d.ts +2 -0
- package/build/dts/CommandPath.d.ts.map +1 -0
- package/build/dts/Commands/Fetch.d.ts.map +1 -1
- package/build/dts/Commands/Hook.d.ts +5 -5
- package/build/dts/Commands/Init.d.ts +55 -0
- package/build/dts/Commands/Init.d.ts.map +1 -0
- package/build/dts/Commands/Mcp.d.ts +6 -6
- package/build/dts/Commands/Search.d.ts.map +1 -1
- package/build/dts/Commands/Skill.d.ts +4 -4
- package/build/dts/Commands/Status.d.ts +27 -0
- package/build/dts/Commands/Status.d.ts.map +1 -0
- package/build/dts/Commands/Telemetry.d.ts +7 -0
- package/build/dts/Commands/Telemetry.d.ts.map +1 -0
- package/build/dts/Commands/Uninstall.d.ts +4 -4
- package/build/dts/Config.d.ts +108 -17
- package/build/dts/Config.d.ts.map +1 -1
- package/build/dts/Hook/SnapshotNote.d.ts +8 -4
- package/build/dts/Hook/SnapshotNote.d.ts.map +1 -1
- package/build/dts/Init/ClaudeAdapter.d.ts +61 -0
- package/build/dts/Init/ClaudeAdapter.d.ts.map +1 -0
- package/build/dts/Init/ClaudeProfile.d.ts +78 -0
- package/build/dts/Init/ClaudeProfile.d.ts.map +1 -0
- package/build/dts/Init/Domain.d.ts +139 -0
- package/build/dts/Init/Domain.d.ts.map +1 -0
- package/build/dts/Init/HarnessAdapter.d.ts +33 -0
- package/build/dts/Init/HarnessAdapter.d.ts.map +1 -0
- package/build/dts/Init/HarnessDetector.d.ts +19 -0
- package/build/dts/Init/HarnessDetector.d.ts.map +1 -0
- package/build/dts/Init/HarnessRegistry.d.ts +50 -0
- package/build/dts/Init/HarnessRegistry.d.ts.map +1 -0
- package/build/dts/Init/MutationTransaction.d.ts +96 -0
- package/build/dts/Init/MutationTransaction.d.ts.map +1 -0
- package/build/dts/Init/Service.d.ts +72 -0
- package/build/dts/Init/Service.d.ts.map +1 -0
- package/build/dts/Init/StandardAdapters.d.ts +42 -0
- package/build/dts/Init/StandardAdapters.d.ts.map +1 -0
- package/build/dts/Init/Status.d.ts +149 -0
- package/build/dts/Init/Status.d.ts.map +1 -0
- package/build/dts/Install/Claude/Hook.d.ts +85 -25
- package/build/dts/Install/Claude/Hook.d.ts.map +1 -1
- package/build/dts/Install/Claude/Mcp.d.ts +21 -18
- package/build/dts/Install/Claude/Mcp.d.ts.map +1 -1
- package/build/dts/Install/Claude/Skill.d.ts +14 -15
- package/build/dts/Install/Claude/Skill.d.ts.map +1 -1
- package/build/dts/Install/Codex/Mcp.d.ts +14 -8
- package/build/dts/Install/Codex/Mcp.d.ts.map +1 -1
- package/build/dts/Install/Codex/Skill.d.ts +4 -2
- package/build/dts/Install/Codex/Skill.d.ts.map +1 -1
- package/build/dts/Install/Cursor/Mcp.d.ts +13 -13
- package/build/dts/Install/Cursor/Mcp.d.ts.map +1 -1
- package/build/dts/Install/Cursor/Skill.d.ts +4 -2
- package/build/dts/Install/Cursor/Skill.d.ts.map +1 -1
- package/build/dts/Install/Domain.d.ts +35 -5
- package/build/dts/Install/Domain.d.ts.map +1 -1
- package/build/dts/Install/Hook.d.ts +4 -4
- package/build/dts/Install/Hook.d.ts.map +1 -1
- package/build/dts/Install/Mcp.d.ts +5 -5
- package/build/dts/Install/Mcp.d.ts.map +1 -1
- package/build/dts/Install/Opencode/Hook.d.ts +4 -3
- package/build/dts/Install/Opencode/Hook.d.ts.map +1 -1
- package/build/dts/Install/Opencode/Mcp.d.ts +11 -11
- package/build/dts/Install/Opencode/Mcp.d.ts.map +1 -1
- package/build/dts/Install/Opencode/Skill.d.ts +4 -2
- package/build/dts/Install/Opencode/Skill.d.ts.map +1 -1
- package/build/dts/Install/Skill.d.ts +3 -3
- package/build/dts/Install/Uninstall.d.ts +6 -6
- package/build/dts/Install/Uninstall.d.ts.map +1 -1
- package/build/dts/MarkdownAnsi.d.ts +29 -0
- package/build/dts/MarkdownAnsi.d.ts.map +1 -0
- package/build/dts/Mcp/ExpandDocs.d.ts +17 -5
- package/build/dts/Mcp/ExpandDocs.d.ts.map +1 -1
- package/build/dts/Mcp/Server.d.ts +1 -1
- package/build/dts/Mcp/Server.d.ts.map +1 -1
- package/build/dts/Mcp/tools/Citations.d.ts +100 -71
- package/build/dts/Mcp/tools/Citations.d.ts.map +1 -1
- package/build/dts/Mcp/tools/Fetch.d.ts +16 -15
- package/build/dts/Mcp/tools/Fetch.d.ts.map +1 -1
- package/build/dts/SecureFile.d.ts +23 -0
- package/build/dts/SecureFile.d.ts.map +1 -0
- package/build/dts/Snippets.d.ts +11 -12
- package/build/dts/Snippets.d.ts.map +1 -1
- package/build/dts/Telemetry.d.ts +30 -0
- package/build/dts/Telemetry.d.ts.map +1 -0
- package/build/dts/Version.d.ts +2 -0
- package/build/dts/Version.d.ts.map +1 -0
- package/build/dts/Xdg.d.ts +11 -0
- package/build/dts/Xdg.d.ts.map +1 -0
- package/build/esm/ApiClient.js +133 -10
- package/build/esm/ApiClient.js.map +1 -1
- package/build/esm/Auth/Domain.js +56 -0
- package/build/esm/Auth/Domain.js.map +1 -0
- package/build/esm/Auth/ManualAuthorization.js +253 -0
- package/build/esm/Auth/ManualAuthorization.js.map +1 -0
- package/build/esm/Auth/PendingInit.js +267 -0
- package/build/esm/Auth/PendingInit.js.map +1 -0
- package/build/esm/Auth/Pkce.js +23 -0
- package/build/esm/Auth/Pkce.js.map +1 -0
- package/build/esm/Auth/SetupGrantAuthorization.js +91 -0
- package/build/esm/Auth/SetupGrantAuthorization.js.map +1 -0
- package/build/esm/Authentication.js +38 -7
- package/build/esm/Authentication.js.map +1 -1
- package/build/esm/BrowserOAuth.js +7 -10
- package/build/esm/BrowserOAuth.js.map +1 -1
- package/build/esm/CommandPath.js +31 -0
- package/build/esm/CommandPath.js.map +1 -0
- package/build/esm/Commands/Fetch.js +30 -6
- package/build/esm/Commands/Fetch.js.map +1 -1
- package/build/esm/Commands/Init.js +371 -0
- package/build/esm/Commands/Init.js.map +1 -0
- package/build/esm/Commands/Search.js +6 -3
- package/build/esm/Commands/Search.js.map +1 -1
- package/build/esm/Commands/Status.js +186 -0
- package/build/esm/Commands/Status.js.map +1 -0
- package/build/esm/Commands/Telemetry.js +23 -0
- package/build/esm/Commands/Telemetry.js.map +1 -0
- package/build/esm/Config.js +502 -28
- package/build/esm/Config.js.map +1 -1
- package/build/esm/Hook/Claude.js +1 -1
- package/build/esm/Hook/Claude.js.map +1 -1
- package/build/esm/Hook/SnapshotNote.js +54 -7
- package/build/esm/Hook/SnapshotNote.js.map +1 -1
- package/build/esm/Init/ClaudeAdapter.js +137 -0
- package/build/esm/Init/ClaudeAdapter.js.map +1 -0
- package/build/esm/Init/ClaudeProfile.js +380 -0
- package/build/esm/Init/ClaudeProfile.js.map +1 -0
- package/build/esm/Init/Domain.js +118 -0
- package/build/esm/Init/Domain.js.map +1 -0
- package/build/esm/Init/HarnessAdapter.js +21 -0
- package/build/esm/Init/HarnessAdapter.js.map +1 -0
- package/build/esm/Init/HarnessDetector.js +65 -0
- package/build/esm/Init/HarnessDetector.js.map +1 -0
- package/build/esm/Init/HarnessRegistry.js +58 -0
- package/build/esm/Init/HarnessRegistry.js.map +1 -0
- package/build/esm/Init/MutationTransaction.js +494 -0
- package/build/esm/Init/MutationTransaction.js.map +1 -0
- package/build/esm/Init/Service.js +319 -0
- package/build/esm/Init/Service.js.map +1 -0
- package/build/esm/Init/StandardAdapters.js +116 -0
- package/build/esm/Init/StandardAdapters.js.map +1 -0
- package/build/esm/Init/Status.js +215 -0
- package/build/esm/Init/Status.js.map +1 -0
- package/build/esm/Install/Claude/Hook.js +182 -50
- package/build/esm/Install/Claude/Hook.js.map +1 -1
- package/build/esm/Install/Claude/Mcp.js +56 -26
- package/build/esm/Install/Claude/Mcp.js.map +1 -1
- package/build/esm/Install/Claude/Skill.js +49 -27
- package/build/esm/Install/Claude/Skill.js.map +1 -1
- package/build/esm/Install/Codex/Mcp.js +9 -4
- package/build/esm/Install/Codex/Mcp.js.map +1 -1
- package/build/esm/Install/Codex/Skill.js +4 -1
- package/build/esm/Install/Codex/Skill.js.map +1 -1
- package/build/esm/Install/Cursor/Mcp.js +7 -4
- package/build/esm/Install/Cursor/Mcp.js.map +1 -1
- package/build/esm/Install/Cursor/Skill.js +4 -1
- package/build/esm/Install/Cursor/Skill.js.map +1 -1
- package/build/esm/Install/Domain.js +60 -3
- package/build/esm/Install/Domain.js.map +1 -1
- package/build/esm/Install/Hook.js.map +1 -1
- package/build/esm/Install/Mcp.js +1 -1
- package/build/esm/Install/Mcp.js.map +1 -1
- package/build/esm/Install/Opencode/Hook.js +1 -1
- package/build/esm/Install/Opencode/Hook.js.map +1 -1
- package/build/esm/Install/Opencode/Mcp.js +6 -3
- package/build/esm/Install/Opencode/Mcp.js.map +1 -1
- package/build/esm/Install/Opencode/Skill.js +4 -1
- package/build/esm/Install/Opencode/Skill.js.map +1 -1
- package/build/esm/Install/Opencode/expandai-webfetch.js +27 -9
- package/build/esm/Install/Skill.js.map +1 -1
- package/build/esm/Install/Uninstall.js +2 -2
- package/build/esm/Install/Uninstall.js.map +1 -1
- package/build/esm/MarkdownAnsi.js +142 -0
- package/build/esm/MarkdownAnsi.js.map +1 -0
- package/build/esm/Mcp/ExpandDocs.js +44 -52
- package/build/esm/Mcp/ExpandDocs.js.map +1 -1
- package/build/esm/Mcp/RequestHeaders.js.map +1 -1
- package/build/esm/Mcp/Server.js +2 -1
- package/build/esm/Mcp/Server.js.map +1 -1
- package/build/esm/Mcp/tools/Citations.js +109 -8
- package/build/esm/Mcp/tools/Citations.js.map +1 -1
- package/build/esm/Mcp/tools/Fetch.js +36 -12
- package/build/esm/Mcp/tools/Fetch.js.map +1 -1
- package/build/esm/SecureFile.js +36 -0
- package/build/esm/SecureFile.js.map +1 -0
- package/build/esm/Snippets.js +12 -1
- package/build/esm/Snippets.js.map +1 -1
- package/build/esm/Telemetry.js +157 -0
- package/build/esm/Telemetry.js.map +1 -0
- package/build/esm/Version.js +4 -0
- package/build/esm/Version.js.map +1 -0
- package/build/esm/Xdg.js +15 -0
- package/build/esm/Xdg.js.map +1 -0
- package/build/esm/main.js +122 -14
- package/build/esm/main.js.map +1 -1
- package/build/skills/expandai/SKILL.md +26 -3
- package/package.json +4 -4
- package/src/ApiClient.ts +206 -13
- package/src/Auth/Domain.ts +63 -0
- package/src/Auth/ManualAuthorization.ts +296 -0
- package/src/Auth/PendingInit.ts +338 -0
- package/src/Auth/Pkce.ts +26 -0
- package/src/Auth/SetupGrantAuthorization.ts +116 -0
- package/src/Authentication.ts +49 -11
- package/src/BrowserOAuth.ts +10 -12
- package/src/CommandPath.ts +30 -0
- package/src/Commands/Fetch.ts +42 -11
- package/src/Commands/Init.ts +489 -0
- package/src/Commands/Search.ts +8 -3
- package/src/Commands/Status.ts +228 -0
- package/src/Commands/Telemetry.ts +42 -0
- package/src/Config.ts +695 -50
- package/src/Hook/Claude.ts +1 -1
- package/src/Hook/SnapshotNote.ts +55 -7
- package/src/Init/ClaudeAdapter.ts +191 -0
- package/src/Init/ClaudeProfile.ts +496 -0
- package/src/Init/Domain.ts +153 -0
- package/src/Init/HarnessAdapter.ts +35 -0
- package/src/Init/HarnessDetector.ts +77 -0
- package/src/Init/HarnessRegistry.ts +87 -0
- package/src/Init/MutationTransaction.ts +747 -0
- package/src/Init/Service.ts +385 -0
- package/src/Init/StandardAdapters.ts +141 -0
- package/src/Init/Status.ts +253 -0
- package/src/Install/Claude/Hook.ts +234 -81
- package/src/Install/Claude/Mcp.ts +80 -33
- package/src/Install/Claude/Skill.ts +70 -37
- package/src/Install/Codex/Mcp.ts +14 -9
- package/src/Install/Codex/Skill.ts +9 -5
- package/src/Install/Cursor/Mcp.ts +12 -9
- package/src/Install/Cursor/Skill.ts +9 -5
- package/src/Install/Domain.ts +77 -4
- package/src/Install/Hook.ts +3 -3
- package/src/Install/Mcp.ts +6 -6
- package/src/Install/Opencode/Hook.ts +5 -5
- package/src/Install/Opencode/Mcp.ts +11 -8
- package/src/Install/Opencode/Skill.ts +9 -5
- package/src/Install/Opencode/expandai-webfetch.js +27 -9
- package/src/Install/Skill.ts +3 -3
- package/src/Install/Uninstall.ts +3 -3
- package/src/MarkdownAnsi.ts +162 -0
- package/src/Mcp/ExpandDocs.ts +46 -55
- package/src/Mcp/Server.ts +2 -1
- package/src/Mcp/tools/Citations.ts +117 -8
- package/src/Mcp/tools/Fetch.ts +40 -14
- package/src/SecureFile.ts +70 -0
- package/src/Snippets.ts +19 -12
- package/src/Telemetry.ts +186 -0
- package/src/Version.ts +3 -0
- package/src/Xdg.ts +18 -0
- package/src/main.ts +171 -12
- package/build/dts/DeviceAuth.d.ts +0 -87
- package/build/dts/DeviceAuth.d.ts.map +0 -1
- package/build/esm/DeviceAuth.js +0 -127
- package/build/esm/DeviceAuth.js.map +0 -1
- package/src/DeviceAuth.ts +0 -193
|
@@ -2,7 +2,7 @@ import { homedir } from 'node:os'
|
|
|
2
2
|
import { FileSystem, Path } from '@effect/platform'
|
|
3
3
|
import { NodeFileSystem, NodePath } from '@effect/platform-node'
|
|
4
4
|
import { Config, Console, Effect, Match } from 'effect'
|
|
5
|
-
import type {
|
|
5
|
+
import type { InstallScope } from '../Mcp.js'
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* OpenCode hook = a JS plugin file at `.opencode/plugins/` (project) or
|
|
@@ -26,7 +26,7 @@ export class OpencodeHook extends Effect.Service<OpencodeHook>()('@expandai/cli/
|
|
|
26
26
|
const home = yield* Config.string('HOME').pipe(Config.withDefault(homedir()))
|
|
27
27
|
const cwd = yield* Config.string('PWD').pipe(Config.withDefault(process.cwd()))
|
|
28
28
|
|
|
29
|
-
const pathFor = Effect.fn(function* (scope:
|
|
29
|
+
const pathFor = Effect.fn(function* (scope: InstallScope) {
|
|
30
30
|
return yield* Match.value(scope).pipe(
|
|
31
31
|
Match.when('global', () => Effect.succeed(`${home}/.config/opencode/plugins/${PLUGIN_FILE}`)),
|
|
32
32
|
Match.when('project', () => Effect.succeed(`${cwd}/.opencode/plugins/${PLUGIN_FILE}`)),
|
|
@@ -34,14 +34,14 @@ export class OpencodeHook extends Effect.Service<OpencodeHook>()('@expandai/cli/
|
|
|
34
34
|
)
|
|
35
35
|
})
|
|
36
36
|
|
|
37
|
-
const install = Effect.fn('OpencodeHook.install')(function* (scope:
|
|
37
|
+
const install = Effect.fn('OpencodeHook.install')(function* (scope: InstallScope) {
|
|
38
38
|
const target = yield* pathFor(scope)
|
|
39
39
|
yield* fs.makeDirectory(path.dirname(target), { recursive: true })
|
|
40
40
|
yield* fs.copyFile(source, target)
|
|
41
41
|
yield* Console.log(`Installed expandai webfetch plugin at ${target}`)
|
|
42
42
|
})
|
|
43
43
|
|
|
44
|
-
const uninstall = Effect.fn('OpencodeHook.uninstall')(function* (scope:
|
|
44
|
+
const uninstall = Effect.fn('OpencodeHook.uninstall')(function* (scope: InstallScope) {
|
|
45
45
|
const target = yield* pathFor(scope)
|
|
46
46
|
const exists = yield* fs.exists(target)
|
|
47
47
|
if (exists) {
|
|
@@ -50,6 +50,6 @@ export class OpencodeHook extends Effect.Service<OpencodeHook>()('@expandai/cli/
|
|
|
50
50
|
}
|
|
51
51
|
})
|
|
52
52
|
|
|
53
|
-
return { install, uninstall } as const
|
|
53
|
+
return { install, uninstall, pathFor } as const
|
|
54
54
|
}),
|
|
55
55
|
}) {}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { homedir } from 'node:os'
|
|
2
2
|
import { Config, Console, Effect, Match, Record, Schema } from 'effect'
|
|
3
|
-
import { ConfigIo, McpParseError, McpWriteError, OpencodeConfigSchema, SERVER_KEY } from '../Domain.js'
|
|
4
|
-
import type {
|
|
3
|
+
import { CliInvocation, ConfigIo, McpParseError, McpWriteError, OpencodeConfigSchema, SERVER_KEY } from '../Domain.js'
|
|
4
|
+
import type { InstallScope } from '../Mcp.js'
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* OpenCode MCP descriptor — its own shape (per opencode.ai/docs/mcp-servers):
|
|
@@ -20,13 +20,14 @@ export class Entry extends Schema.Class<Entry>('OpencodeMcpEntry')({
|
|
|
20
20
|
}) {}
|
|
21
21
|
|
|
22
22
|
export class OpencodeMcp extends Effect.Service<OpencodeMcp>()('@expandai/cli/Install/Opencode/Mcp', {
|
|
23
|
-
dependencies: [ConfigIo.Default],
|
|
23
|
+
dependencies: [ConfigIo.Default, CliInvocation.Default],
|
|
24
24
|
effect: Effect.gen(function* () {
|
|
25
25
|
const io = yield* ConfigIo
|
|
26
|
+
const cli = yield* CliInvocation
|
|
26
27
|
const home = yield* Config.string('HOME').pipe(Config.withDefault(homedir()))
|
|
27
28
|
const cwd = yield* Config.string('PWD').pipe(Config.withDefault(process.cwd()))
|
|
28
29
|
|
|
29
|
-
const pathFor = Effect.fn(function* (scope:
|
|
30
|
+
const pathFor = Effect.fn(function* (scope: InstallScope) {
|
|
30
31
|
return yield* Match.value(scope).pipe(
|
|
31
32
|
Match.when('global', () => Effect.succeed(`${home}/.config/opencode/opencode.json`)),
|
|
32
33
|
Match.when('project', () => Effect.succeed(`${cwd}/opencode.json`)),
|
|
@@ -46,16 +47,18 @@ export class OpencodeMcp extends Effect.Service<OpencodeMcp>()('@expandai/cli/In
|
|
|
46
47
|
.pipe(Effect.mapError((error) => new McpWriteError({ path: file, error })))
|
|
47
48
|
})
|
|
48
49
|
|
|
49
|
-
const install = Effect.fn(function* (scope:
|
|
50
|
+
const install = Effect.fn(function* (scope: InstallScope) {
|
|
50
51
|
const file = yield* pathFor(scope)
|
|
51
52
|
const config = yield* readConfig(file)
|
|
53
|
+
const invocation = yield* cli.resolve()
|
|
52
54
|
yield* writeConfig(file, {
|
|
53
55
|
...config,
|
|
54
56
|
mcp: {
|
|
55
57
|
...config.mcp,
|
|
56
58
|
[SERVER_KEY]: new Entry({
|
|
57
59
|
type: 'local',
|
|
58
|
-
command: [
|
|
60
|
+
command: [invocation.command, ...invocation.args, 'mcp', 'run'],
|
|
61
|
+
environment: { EXPANDAI_HARNESS: 'opencode' },
|
|
59
62
|
enabled: true,
|
|
60
63
|
}),
|
|
61
64
|
},
|
|
@@ -63,7 +66,7 @@ export class OpencodeMcp extends Effect.Service<OpencodeMcp>()('@expandai/cli/In
|
|
|
63
66
|
yield* Console.log(`Installed expandai MCP server into ${file}`)
|
|
64
67
|
})
|
|
65
68
|
|
|
66
|
-
const uninstall = Effect.fn(function* (scope:
|
|
69
|
+
const uninstall = Effect.fn(function* (scope: InstallScope) {
|
|
67
70
|
const file = yield* pathFor(scope)
|
|
68
71
|
const config = yield* readConfig(file)
|
|
69
72
|
if (!(SERVER_KEY in config.mcp)) {
|
|
@@ -73,7 +76,7 @@ export class OpencodeMcp extends Effect.Service<OpencodeMcp>()('@expandai/cli/In
|
|
|
73
76
|
yield* Console.log(`Removed expandai MCP server from ${file}`)
|
|
74
77
|
})
|
|
75
78
|
|
|
76
|
-
const isInstalled = Effect.fn(function* (scope:
|
|
79
|
+
const isInstalled = Effect.fn(function* (scope: InstallScope) {
|
|
77
80
|
const file = yield* pathFor(scope)
|
|
78
81
|
const config = yield* readConfig(file)
|
|
79
82
|
return SERVER_KEY in config.mcp
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { homedir } from 'node:os'
|
|
2
2
|
import { Config, Effect, Match } from 'effect'
|
|
3
3
|
import { SkillIo } from '../Domain.js'
|
|
4
|
-
import type {
|
|
4
|
+
import type { InstallScope } from '../Mcp.js'
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* OpenCode skills are Claude-Code-compatible Markdown files. Per
|
|
@@ -23,7 +23,7 @@ export class OpencodeSkill extends Effect.Service<OpencodeSkill>()('@expandai/cl
|
|
|
23
23
|
const home = yield* Config.string('HOME').pipe(Config.withDefault(homedir()))
|
|
24
24
|
const cwd = yield* Config.string('PWD').pipe(Config.withDefault(process.cwd()))
|
|
25
25
|
|
|
26
|
-
const pathFor = Effect.fn(function* (scope:
|
|
26
|
+
const pathFor = Effect.fn(function* (scope: InstallScope) {
|
|
27
27
|
return yield* Match.value(scope).pipe(
|
|
28
28
|
Match.when('global', () => Effect.succeed(`${home}/.config/opencode/skills/${SKILL_NAME}`)),
|
|
29
29
|
Match.when('project', () => Effect.succeed(`${cwd}/.opencode/skills/${SKILL_NAME}`)),
|
|
@@ -31,14 +31,18 @@ export class OpencodeSkill extends Effect.Service<OpencodeSkill>()('@expandai/cl
|
|
|
31
31
|
)
|
|
32
32
|
})
|
|
33
33
|
|
|
34
|
-
const install = Effect.fn(function* (scope:
|
|
34
|
+
const install = Effect.fn(function* (scope: InstallScope) {
|
|
35
35
|
return yield* io.install(yield* pathFor(scope))
|
|
36
36
|
})
|
|
37
37
|
|
|
38
|
-
const uninstall = Effect.fn(function* (scope:
|
|
38
|
+
const uninstall = Effect.fn(function* (scope: InstallScope) {
|
|
39
39
|
return yield* io.uninstall(yield* pathFor(scope))
|
|
40
40
|
})
|
|
41
41
|
|
|
42
|
-
|
|
42
|
+
const isCurrent = Effect.fn(function* (scope: InstallScope) {
|
|
43
|
+
return yield* io.isCurrent(yield* pathFor(scope))
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
return { install, uninstall, isCurrent, pathFor } as const
|
|
43
47
|
}),
|
|
44
48
|
}) {}
|
|
@@ -8,6 +8,32 @@
|
|
|
8
8
|
// dist/index.d.ts.
|
|
9
9
|
import { spawn } from 'node:child_process'
|
|
10
10
|
|
|
11
|
+
const runHook = (command, args, payload) =>
|
|
12
|
+
new Promise((resolve, reject) => {
|
|
13
|
+
const child = spawn(command, args, {
|
|
14
|
+
stdio: ['pipe', 'pipe', 'inherit'],
|
|
15
|
+
env: { ...process.env, EXPANDAI_CLI_CONTEXT: 'agent', EXPANDAI_HARNESS: 'opencode' },
|
|
16
|
+
})
|
|
17
|
+
let stdout = ''
|
|
18
|
+
child.stdout.setEncoding('utf8')
|
|
19
|
+
child.stdout.on('data', (chunk) => {
|
|
20
|
+
stdout += chunk
|
|
21
|
+
})
|
|
22
|
+
child.on('error', reject)
|
|
23
|
+
child.on('close', (exitCode) => resolve({ exitCode, stdout }))
|
|
24
|
+
// Writing to stdin of a binary that failed to spawn raises EPIPE; the
|
|
25
|
+
// spawn failure itself is reported through the 'error' handler above.
|
|
26
|
+
child.stdin.on('error', () => {})
|
|
27
|
+
child.stdin.end(payload)
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
// Prefer the installed binary; fall back to `npx -y expandai` so the plugin
|
|
31
|
+
// works for people who have not installed the expandai CLI globally.
|
|
32
|
+
const runExpandai = (args, payload) =>
|
|
33
|
+
runHook('expandai', args, payload).catch((error) =>
|
|
34
|
+
error?.code === 'ENOENT' ? runHook('npx', ['-y', 'expandai', ...args], payload) : Promise.reject(error),
|
|
35
|
+
)
|
|
36
|
+
|
|
11
37
|
export const ExpandaiWebfetch = async () => ({
|
|
12
38
|
'tool.execute.after': async (input, output) => {
|
|
13
39
|
if (input.tool !== 'webfetch') return
|
|
@@ -15,15 +41,7 @@ export const ExpandaiWebfetch = async () => ({
|
|
|
15
41
|
if (typeof url !== 'string' || url.length === 0) return
|
|
16
42
|
|
|
17
43
|
try {
|
|
18
|
-
const
|
|
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))
|
|
44
|
+
const { exitCode, stdout } = await runExpandai(['hook', 'opencode'], JSON.stringify({ url }))
|
|
27
45
|
if (exitCode !== 0 || stdout.trim().length === 0) return
|
|
28
46
|
|
|
29
47
|
const { markdown } = JSON.parse(stdout)
|
package/src/Install/Skill.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { Console, Effect, Match } from 'effect'
|
|
|
2
2
|
import { ClaudeSkill } from './Claude/Skill.js'
|
|
3
3
|
import { CodexSkill } from './Codex/Skill.js'
|
|
4
4
|
import { CursorSkill } from './Cursor/Skill.js'
|
|
5
|
-
import type { Host,
|
|
5
|
+
import type { Host, InstallScope } from './Mcp.js'
|
|
6
6
|
import { OpencodeSkill } from './Opencode/Skill.js'
|
|
7
7
|
|
|
8
8
|
/**
|
|
@@ -30,7 +30,7 @@ export class Skill extends Effect.Service<Skill>()('@expandai/cli/Install/Skill'
|
|
|
30
30
|
const opencode = yield* OpencodeSkill
|
|
31
31
|
const codex = yield* CodexSkill
|
|
32
32
|
|
|
33
|
-
const install = Effect.fn('Skill.install')(function* (host: Host, scope:
|
|
33
|
+
const install = Effect.fn('Skill.install')(function* (host: Host, scope: InstallScope) {
|
|
34
34
|
const target = yield* Match.value(host).pipe(
|
|
35
35
|
Match.when('claude-code', () => claude.install(scope)),
|
|
36
36
|
Match.when('cursor', () => cursor.install(scope)),
|
|
@@ -41,7 +41,7 @@ export class Skill extends Effect.Service<Skill>()('@expandai/cli/Install/Skill'
|
|
|
41
41
|
yield* Console.log(`Installed expandai skill into ${target}`)
|
|
42
42
|
})
|
|
43
43
|
|
|
44
|
-
const uninstall = Effect.fn('Skill.uninstall')(function* (host: Host, scope:
|
|
44
|
+
const uninstall = Effect.fn('Skill.uninstall')(function* (host: Host, scope: InstallScope) {
|
|
45
45
|
const target = yield* Match.value(host).pipe(
|
|
46
46
|
Match.when('claude-code', () => claude.uninstall(scope)),
|
|
47
47
|
Match.when('cursor', () => cursor.uninstall(scope)),
|
package/src/Install/Uninstall.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Array, Effect, Match, Schema } from 'effect'
|
|
2
2
|
import { type HookHost, HookInstaller } from './Hook.js'
|
|
3
|
-
import { Host,
|
|
3
|
+
import { Host, InstallScope, Mcp } from './Mcp.js'
|
|
4
4
|
import { Skill } from './Skill.js'
|
|
5
5
|
|
|
6
6
|
export const UninstallTarget = Schema.Literal('all', 'hook', 'skill', 'mcp')
|
|
@@ -8,10 +8,10 @@ export const UninstallTarget = Schema.Literal('all', 'hook', 'skill', 'mcp')
|
|
|
8
8
|
export class UninstallOptions extends Schema.Class<UninstallOptions>('UninstallOptions')({
|
|
9
9
|
target: Schema.optional(UninstallTarget),
|
|
10
10
|
host: Schema.optional(Host),
|
|
11
|
-
scope: Schema.optional(
|
|
11
|
+
scope: Schema.optional(InstallScope),
|
|
12
12
|
}) {}
|
|
13
13
|
|
|
14
|
-
const SCOPES: (typeof
|
|
14
|
+
const SCOPES: (typeof InstallScope.Type)[] = ['global', 'project']
|
|
15
15
|
const HOSTS: (typeof Host.Type)[] = ['claude-code', 'cursor', 'opencode', 'codex']
|
|
16
16
|
|
|
17
17
|
const isHookHost = (host: typeof Host.Type): host is HookHost => host === 'claude-code' || host === 'opencode'
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Zero-dependency ANSI syntax highlighting for markdown printed to an
|
|
3
|
+
* interactive terminal.
|
|
4
|
+
*
|
|
5
|
+
* This is a highlighter, not a renderer: the input text is preserved
|
|
6
|
+
* byte-for-byte and only wrapped in ANSI escape sequences, so copying
|
|
7
|
+
* from the terminal or stripping the escapes yields the exact document
|
|
8
|
+
* the API returned. Piped output (non-TTY) must stay unstyled — gate
|
|
9
|
+
* calls with `shouldColorizeMarkdown`.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
// Styling is intentionally limited to 4-bit SGR (bold/dim/underline + the 8
|
|
13
|
+
// base colors): it renders on every color-capable terminal and inherits the
|
|
14
|
+
// user's palette. Do NOT introduce 256-color (38;5;n) or truecolor (38;2;r;g;b)
|
|
15
|
+
// sequences without adding capability detection first — truecolor needs
|
|
16
|
+
// COLORTERM=truecolor|24bit (TERM alone is not enough: e.g. ghostty sets
|
|
17
|
+
// TERM=xterm-ghostty), and 256-color needs TERM=*-256color; emitting either
|
|
18
|
+
// tier on a lesser terminal produces garbage.
|
|
19
|
+
const RESET = '\x1b[0m'
|
|
20
|
+
const BOLD = '\x1b[1m'
|
|
21
|
+
const DIM = '\x1b[2m'
|
|
22
|
+
const CYAN = '\x1b[36m'
|
|
23
|
+
const YELLOW = '\x1b[33m'
|
|
24
|
+
const GREEN = '\x1b[32m'
|
|
25
|
+
const BLUE_UNDERLINE = '\x1b[34;4m'
|
|
26
|
+
const HEADING = '\x1b[1;36m'
|
|
27
|
+
|
|
28
|
+
export interface ColorizeEnvironment {
|
|
29
|
+
readonly isTty: boolean
|
|
30
|
+
readonly env: Readonly<Record<string, string | undefined>>
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Standard CLI color negotiation: color only on an interactive terminal,
|
|
35
|
+
* `NO_COLOR` (https://no-color.org) and `TERM=dumb` opt out, a non-zero
|
|
36
|
+
* `FORCE_COLOR` opts in regardless of the terminal.
|
|
37
|
+
*/
|
|
38
|
+
export function shouldColorizeMarkdown(
|
|
39
|
+
environment: ColorizeEnvironment = { isTty: process.stdout.isTTY === true, env: process.env },
|
|
40
|
+
): boolean {
|
|
41
|
+
const { env, isTty } = environment
|
|
42
|
+
const forceColor = env.FORCE_COLOR?.trim()
|
|
43
|
+
if (forceColor !== undefined && forceColor !== '') return forceColor !== '0'
|
|
44
|
+
if (env.NO_COLOR !== undefined && env.NO_COLOR !== '') return false
|
|
45
|
+
if (env.TERM === 'dumb') return false
|
|
46
|
+
return isTty
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function styleLine(style: string, line: string): string {
|
|
50
|
+
return line === '' ? line : `${style}${line}${RESET}`
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Inline code spans are styled first and must be shielded from the link,
|
|
54
|
+
// bold, and table-pipe passes; ANSI escapes never contain \x00, so a
|
|
55
|
+
// NUL-delimited stash is collision-free.
|
|
56
|
+
function styleInline(line: string, options?: { readonly dimPipes: boolean }): string {
|
|
57
|
+
const stash: string[] = []
|
|
58
|
+
let out = line.replace(/`[^`\n]+`/g, (code) => {
|
|
59
|
+
stash.push(`${CYAN}${code}${RESET}`)
|
|
60
|
+
return `\x00${stash.length - 1}\x00`
|
|
61
|
+
})
|
|
62
|
+
if (options?.dimPipes) {
|
|
63
|
+
// While code spans are stashed, so pipes inside `...` keep their
|
|
64
|
+
// code styling instead of being re-wrapped in DIM.
|
|
65
|
+
out = out.replaceAll('|', `${DIM}|${RESET}`)
|
|
66
|
+
}
|
|
67
|
+
out = out.replace(
|
|
68
|
+
/\[([^\]\n]*)\]\(([^)\n]*)\)/g,
|
|
69
|
+
(_match, text: string, target: string) =>
|
|
70
|
+
`${DIM}[${RESET}${BLUE_UNDERLINE}${text}${RESET}${DIM}](${target})${RESET}`,
|
|
71
|
+
)
|
|
72
|
+
out = out.replace(/\*\*([^*\n]+)\*\*/g, (_match, text: string) => `${BOLD}**${text}**${RESET}`)
|
|
73
|
+
return out.replace(/\x00(\d+)\x00/g, (_match, index: string) => stash[Number(index)] ?? '')
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const FENCE_PATTERN = /^(\s*)(`{3,}|~{3,})(.*)$/
|
|
77
|
+
const HEADING_PATTERN = /^#{1,6}\s/
|
|
78
|
+
const HR_PATTERN = /^ {0,3}(-{3,}|\*{3,}|_{3,})\s*$/
|
|
79
|
+
const LIST_MARKER_PATTERN = /^(\s*)([-*+]|\d{1,9}[.)])(\s+)(.*)$/
|
|
80
|
+
const FRONTMATTER_KEY_PATTERN = /^(\s*)([\w.-]+):(.*)$/
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Wrap a markdown document in ANSI styles for terminal display. Line-based:
|
|
84
|
+
* headings, fences, front matter, blockquotes, list markers, and table pipes
|
|
85
|
+
* get block styling; plain text lines get inline code / link / bold styling.
|
|
86
|
+
*/
|
|
87
|
+
export function highlightMarkdownAnsi(markdown: string): string {
|
|
88
|
+
const lines = markdown.split('\n')
|
|
89
|
+
const out: string[] = []
|
|
90
|
+
let inFrontmatter = false
|
|
91
|
+
let fenceClose: RegExp | undefined
|
|
92
|
+
|
|
93
|
+
lines.forEach((line, index) => {
|
|
94
|
+
if (fenceClose) {
|
|
95
|
+
if (FENCE_PATTERN.test(line) && fenceClose.test(line)) {
|
|
96
|
+
fenceClose = undefined
|
|
97
|
+
out.push(styleLine(DIM, line))
|
|
98
|
+
} else {
|
|
99
|
+
out.push(styleLine(YELLOW, line))
|
|
100
|
+
}
|
|
101
|
+
return
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
if (index === 0 && line === '---') {
|
|
105
|
+
inFrontmatter = true
|
|
106
|
+
out.push(styleLine(DIM, line))
|
|
107
|
+
return
|
|
108
|
+
}
|
|
109
|
+
if (inFrontmatter) {
|
|
110
|
+
if (line === '---') {
|
|
111
|
+
inFrontmatter = false
|
|
112
|
+
out.push(styleLine(DIM, line))
|
|
113
|
+
return
|
|
114
|
+
}
|
|
115
|
+
const keyMatch = line.match(FRONTMATTER_KEY_PATTERN)
|
|
116
|
+
out.push(
|
|
117
|
+
keyMatch ? `${keyMatch[1]}${CYAN}${keyMatch[2]}${RESET}${DIM}:${keyMatch[3]}${RESET}` : styleLine(DIM, line),
|
|
118
|
+
)
|
|
119
|
+
return
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
const fenceMatch = line.match(FENCE_PATTERN)
|
|
123
|
+
if (fenceMatch) {
|
|
124
|
+
const marker = fenceMatch[2] ?? '```'
|
|
125
|
+
fenceClose = new RegExp(`^\\s*${marker[0] === '`' ? '`' : '~'}{${marker.length},}\\s*$`)
|
|
126
|
+
out.push(styleLine(DIM, line))
|
|
127
|
+
return
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
if (HEADING_PATTERN.test(line)) {
|
|
131
|
+
out.push(styleLine(HEADING, line))
|
|
132
|
+
return
|
|
133
|
+
}
|
|
134
|
+
if (HR_PATTERN.test(line)) {
|
|
135
|
+
out.push(styleLine(DIM, line))
|
|
136
|
+
return
|
|
137
|
+
}
|
|
138
|
+
if (line.trimStart().startsWith('>')) {
|
|
139
|
+
out.push(styleLine(GREEN, line))
|
|
140
|
+
return
|
|
141
|
+
}
|
|
142
|
+
if (line.trimStart().startsWith('|')) {
|
|
143
|
+
out.push(styleInline(line, { dimPipes: true }))
|
|
144
|
+
return
|
|
145
|
+
}
|
|
146
|
+
const listMatch = line.match(LIST_MARKER_PATTERN)
|
|
147
|
+
if (listMatch) {
|
|
148
|
+
out.push(`${listMatch[1]}${YELLOW}${listMatch[2]}${RESET}${listMatch[3]}${styleInline(listMatch[4] ?? '')}`)
|
|
149
|
+
return
|
|
150
|
+
}
|
|
151
|
+
out.push(styleInline(line))
|
|
152
|
+
})
|
|
153
|
+
|
|
154
|
+
return out.join('\n')
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/** Strip the escape sequences this module emits; used to verify lossless styling. */
|
|
158
|
+
export function stripAnsi(text: string): string {
|
|
159
|
+
// Only SGR sequences are emitted by this module.
|
|
160
|
+
// biome-ignore lint/suspicious/noControlCharactersInRegex: ANSI escapes are control characters by definition.
|
|
161
|
+
return text.replace(/\x1b\[[0-9;]*m/g, '')
|
|
162
|
+
}
|
package/src/Mcp/ExpandDocs.ts
CHANGED
|
@@ -1,71 +1,62 @@
|
|
|
1
1
|
import { McpServer } from '@effect/ai'
|
|
2
2
|
import { Effect, Layer, String } from 'effect'
|
|
3
|
+
import { ConfigManager } from '../Config.js'
|
|
3
4
|
|
|
4
|
-
|
|
5
|
-
|
|
5
|
+
/**
|
|
6
|
+
* These resources are read by an agent that will follow their links, so every
|
|
7
|
+
* URL must resolve to the stack this CLI is configured against — production by
|
|
8
|
+
* default, or whatever `EXPAND_APP_URL` names for local and self-hosted setups.
|
|
9
|
+
*/
|
|
10
|
+
export function makeAgentSetupPrompt(appUrl: string): string {
|
|
11
|
+
return `Read ${new URL('/start.md', appUrl).toString()} and set up Expand. Fetch it as raw text with curl — a summarizing web-fetch tool drops the exact commands.`
|
|
12
|
+
}
|
|
6
13
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
|
41
|
-
|## Codex
|
|
42
|
-
|
|
|
43
|
-
|\`\`\`sh
|
|
44
|
-
|expandai skill install codex project
|
|
45
|
-
|expandai mcp install codex project
|
|
46
|
-
|\`\`\`
|
|
47
|
-
|`)
|
|
14
|
+
/**
|
|
15
|
+
* Points at the hosted guide instead of restating it. A local copy of the setup
|
|
16
|
+
* procedure drifts silently the moment the commands change, and this resource
|
|
17
|
+
* is read by an agent that can fetch the current one itself.
|
|
18
|
+
*/
|
|
19
|
+
export function makeStartGuideMarkdown(appUrl: string): string {
|
|
20
|
+
return String.stripMargin(`
|
|
21
|
+
|# Expand Start Guide
|
|
22
|
+
|
|
|
23
|
+
|The setup procedure is served as a single document. Fetch it and follow it:
|
|
24
|
+
|
|
|
25
|
+
|${new URL('/start.md', appUrl).toString()}
|
|
26
|
+
|
|
|
27
|
+
|## Agent Setup Prompt
|
|
28
|
+
|
|
|
29
|
+
|${makeAgentSetupPrompt(appUrl)}
|
|
30
|
+
|`)
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function makeAboutMarkdown(appUrl: string): string {
|
|
34
|
+
return String.stripMargin(`
|
|
35
|
+
|# expand.ai
|
|
36
|
+
|
|
|
37
|
+
|- Website: ${appUrl}
|
|
38
|
+
|- Quickstart: ${new URL('/docs', appUrl).toString()}
|
|
39
|
+
|- Dashboard: ${new URL('/dashboard', appUrl).toString()}
|
|
40
|
+
|`)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const appUrl = Effect.gen(function* () {
|
|
44
|
+
const configManager = yield* ConfigManager
|
|
45
|
+
return yield* configManager.getAppUrl()
|
|
46
|
+
})
|
|
48
47
|
|
|
49
48
|
export const ExpandDocs = McpServer.resource({
|
|
50
49
|
uri: 'expand://about',
|
|
51
50
|
name: 'About expand.ai',
|
|
52
51
|
description: 'Key links for the expand.ai platform',
|
|
53
|
-
content: Effect.
|
|
54
|
-
String.stripMargin(`
|
|
55
|
-
|# expand.ai
|
|
56
|
-
|
|
|
57
|
-
|- Website: https://expand.ai
|
|
58
|
-
|- Quickstart: https://expand.ai/docs
|
|
59
|
-
|- Dashboard: https://expand.ai/dashboard
|
|
60
|
-
|`),
|
|
61
|
-
),
|
|
52
|
+
content: Effect.map(appUrl, makeAboutMarkdown),
|
|
62
53
|
})
|
|
63
54
|
|
|
64
55
|
export const ExpandStartDocs = McpServer.resource({
|
|
65
56
|
uri: 'expand://start',
|
|
66
57
|
name: 'Expand Start Guide',
|
|
67
|
-
description: '
|
|
68
|
-
content: Effect.
|
|
58
|
+
description: 'Where to find the Expand agent setup guide, and the prompt that runs it',
|
|
59
|
+
content: Effect.map(appUrl, makeStartGuideMarkdown),
|
|
69
60
|
})
|
|
70
61
|
|
|
71
|
-
export const ExpandDocsLayer = Layer.mergeAll(ExpandDocs, ExpandStartDocs)
|
|
62
|
+
export const ExpandDocsLayer = Layer.mergeAll(ExpandDocs, ExpandStartDocs).pipe(Layer.provide(ConfigManager.Default))
|
package/src/Mcp/Server.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Layer } from 'effect'
|
|
2
2
|
import { SERVER_KEY } from '../Install/Domain.js'
|
|
3
|
+
import { CLI_VERSION } from '../Version.js'
|
|
3
4
|
import { ExpandDocsLayer } from './ExpandDocs.js'
|
|
4
5
|
import { ExpandToolKit } from './Toolkit.js'
|
|
5
6
|
|
|
@@ -7,7 +8,7 @@ export { CurrentRequestHeaders } from './RequestHeaders.js'
|
|
|
7
8
|
|
|
8
9
|
export const ServerInfo = {
|
|
9
10
|
name: SERVER_KEY,
|
|
10
|
-
version:
|
|
11
|
+
version: CLI_VERSION,
|
|
11
12
|
} as const
|
|
12
13
|
|
|
13
14
|
export const makeServerLayer = (options: { readonly includeDocs?: boolean } = {}) =>
|