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
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { homedir } from 'node:os'
|
|
2
|
+
import { FileSystem, Path } from '@effect/platform'
|
|
3
|
+
import { NodeFileSystem, NodePath } from '@effect/platform-node'
|
|
4
|
+
import { Effect, Option, Schema } from 'effect'
|
|
5
|
+
import { InitHarness, type InitHarnesses } from './Domain.js'
|
|
6
|
+
|
|
7
|
+
interface HarnessDetectionInput {
|
|
8
|
+
readonly cwd?: string
|
|
9
|
+
readonly environment?: Readonly<Record<string, string | undefined>>
|
|
10
|
+
readonly hint?: typeof InitHarness.Type
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const HARNESS_ORDER: InitHarnesses = ['claude-code', 'cursor', 'opencode', 'codex']
|
|
14
|
+
|
|
15
|
+
function enabled(value: string | undefined): boolean {
|
|
16
|
+
return value !== undefined && value !== '' && value !== '0' && value !== 'false'
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function currentHarness(
|
|
20
|
+
environment: Readonly<Record<string, string | undefined>>,
|
|
21
|
+
): Option.Option<typeof InitHarness.Type> {
|
|
22
|
+
const explicit = Schema.decodeUnknownOption(InitHarness)(environment.EXPANDAI_HARNESS)
|
|
23
|
+
if (Option.isSome(explicit)) return explicit
|
|
24
|
+
if (enabled(environment.CLAUDECODE)) return Option.some('claude-code')
|
|
25
|
+
if (environment.CURSOR_TRACE_ID !== undefined) return Option.some('cursor')
|
|
26
|
+
if (environment.CODEX_RUN_ID !== undefined) return Option.some('codex')
|
|
27
|
+
return Option.none()
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export class HarnessDetector extends Effect.Service<HarnessDetector>()('@expandai/cli/Init/HarnessDetector', {
|
|
31
|
+
dependencies: [NodeFileSystem.layer, NodePath.layer],
|
|
32
|
+
effect: Effect.gen(function* () {
|
|
33
|
+
const fileSystem = yield* FileSystem.FileSystem
|
|
34
|
+
const path = yield* Path.Path
|
|
35
|
+
|
|
36
|
+
const detect = Effect.fn('HarnessDetector.detect')(function* (input: HarnessDetectionInput = {}) {
|
|
37
|
+
const environment = input.environment ?? process.env
|
|
38
|
+
const cwd = input.cwd ?? environment.PWD ?? process.cwd()
|
|
39
|
+
const home = environment.HOME ?? homedir()
|
|
40
|
+
const candidates = new Map<typeof InitHarness.Type, string[]>([
|
|
41
|
+
['claude-code', [path.join(home, '.claude'), path.join(cwd, '.claude')]],
|
|
42
|
+
['cursor', [path.join(home, '.cursor'), path.join(cwd, '.cursor')]],
|
|
43
|
+
[
|
|
44
|
+
'opencode',
|
|
45
|
+
[path.join(home, '.config', 'opencode'), path.join(cwd, '.opencode'), path.join(cwd, 'opencode.json')],
|
|
46
|
+
],
|
|
47
|
+
['codex', [path.join(home, '.codex'), path.join(cwd, '.codex')]],
|
|
48
|
+
])
|
|
49
|
+
const detected = new Set<typeof InitHarness.Type>()
|
|
50
|
+
const current = currentHarness(environment)
|
|
51
|
+
if (Option.isSome(current)) detected.add(current.value)
|
|
52
|
+
if (input.hint !== undefined) detected.add(input.hint)
|
|
53
|
+
// Collect, then filter. The previous version mutated `detected` from inside
|
|
54
|
+
// a `tap` under unbounded concurrency — safe on one thread, but it read as
|
|
55
|
+
// a race and expressed "keep the ones that exist" as a side effect.
|
|
56
|
+
const present = yield* Effect.forEach(
|
|
57
|
+
HARNESS_ORDER,
|
|
58
|
+
(harness) =>
|
|
59
|
+
Effect.exists(candidates.get(harness) ?? [], (candidate) =>
|
|
60
|
+
fileSystem.exists(candidate).pipe(Effect.orElseSucceed(() => false)),
|
|
61
|
+
).pipe(Effect.map((exists) => ({ harness, exists }))),
|
|
62
|
+
{ concurrency: 'unbounded' },
|
|
63
|
+
)
|
|
64
|
+
for (const { harness, exists } of present) if (exists) detected.add(harness)
|
|
65
|
+
return HARNESS_ORDER.filter((harness) => detected.has(harness))
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
/** The harness this process is running inside, when it announces itself. */
|
|
69
|
+
const detectCurrent = Effect.fnUntraced(function* (input: Pick<HarnessDetectionInput, 'environment'> = {}) {
|
|
70
|
+
// Reads ambient `process.env` when no environment is supplied, so it stays
|
|
71
|
+
// an Effect — but it does no work worth a span.
|
|
72
|
+
return currentHarness(input.environment ?? process.env)
|
|
73
|
+
})
|
|
74
|
+
|
|
75
|
+
return { detect, detectCurrent } as const
|
|
76
|
+
}),
|
|
77
|
+
}) {}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { Effect, Schema } from 'effect'
|
|
2
|
+
import { ClaudeAdapter } from './ClaudeAdapter.js'
|
|
3
|
+
import type { InitHarness, InitScope } from './Domain.js'
|
|
4
|
+
import type { HarnessConfigurationError, HarnessInspection, HarnessInspectionError } from './HarnessAdapter.js'
|
|
5
|
+
import { CodexAdapter, CursorAdapter, OpencodeAdapter } from './StandardAdapters.js'
|
|
6
|
+
|
|
7
|
+
export interface HarnessAdapterContract {
|
|
8
|
+
readonly harness: InitHarness
|
|
9
|
+
readonly inspect: (scope: InitScope) => Effect.Effect<HarnessInspection, HarnessInspectionError>
|
|
10
|
+
readonly configure: (scope: InitScope) => Effect.Effect<HarnessInspection, HarnessConfigurationError>
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
interface HarnessRegistryContract {
|
|
14
|
+
readonly inspect: (
|
|
15
|
+
harness: InitHarness,
|
|
16
|
+
scope: InitScope,
|
|
17
|
+
) => Effect.Effect<HarnessInspection, UnsupportedInitHarnessError | HarnessInspectionError>
|
|
18
|
+
readonly configure: (
|
|
19
|
+
harness: InitHarness,
|
|
20
|
+
scope: InitScope,
|
|
21
|
+
) => Effect.Effect<HarnessInspection, UnsupportedInitHarnessError | HarnessConfigurationError>
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export class UnsupportedInitHarnessError extends Schema.TaggedError<UnsupportedInitHarnessError>()(
|
|
25
|
+
'UnsupportedInitHarnessError',
|
|
26
|
+
{
|
|
27
|
+
harness: Schema.String,
|
|
28
|
+
},
|
|
29
|
+
) {
|
|
30
|
+
get message() {
|
|
31
|
+
return `No init adapter is registered for ${this.harness}`
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function makeRegistry(adapters: ReadonlyArray<HarnessAdapterContract>): HarnessRegistryContract {
|
|
36
|
+
const adaptersByHarness = new Map(adapters.map((adapter) => [adapter.harness, adapter]))
|
|
37
|
+
|
|
38
|
+
const find = Effect.fn('HarnessRegistry.find')(function* (harness: InitHarness) {
|
|
39
|
+
const adapter = adaptersByHarness.get(harness)
|
|
40
|
+
if (adapter === undefined) {
|
|
41
|
+
return yield* new UnsupportedInitHarnessError({ harness })
|
|
42
|
+
}
|
|
43
|
+
return adapter
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
const inspect = Effect.fn('HarnessRegistry.inspect')(function* (harness: InitHarness, scope: InitScope) {
|
|
47
|
+
const adapter = yield* find(harness)
|
|
48
|
+
return yield* adapter.inspect(scope)
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
const configure = Effect.fn('HarnessRegistry.configure')(function* (harness: InitHarness, scope: InitScope) {
|
|
52
|
+
const adapter = yield* find(harness)
|
|
53
|
+
return yield* adapter.configure(scope)
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
return { inspect, configure }
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* `Default` is the **real** registry, wired to the four adapters.
|
|
61
|
+
*
|
|
62
|
+
* It used to be `sync: () => makeRegistry([])` — an empty registry that reported
|
|
63
|
+
* every harness as unsupported. Nothing consumed it, because `main.ts` and the
|
|
64
|
+
* tests both built `DefaultWithoutDependencies` with a registry supplied by
|
|
65
|
+
* hand; but `InitService` and `StatusService` still *declared* it in their
|
|
66
|
+
* `dependencies`, so the declaration was decorative and would have silently
|
|
67
|
+
* produced an empty registry for anyone who reached for the obvious layer.
|
|
68
|
+
* `Effect.Service` always generates `Default`, so the fix is to make it correct
|
|
69
|
+
* rather than to remove it.
|
|
70
|
+
*/
|
|
71
|
+
export class HarnessRegistry extends Effect.Service<HarnessRegistry>()('@expandai/cli/Init/HarnessRegistry', {
|
|
72
|
+
dependencies: [ClaudeAdapter.Default, CursorAdapter.Default, OpencodeAdapter.Default, CodexAdapter.Default],
|
|
73
|
+
effect: Effect.gen(function* () {
|
|
74
|
+
const adapters = yield* Effect.all([ClaudeAdapter, CursorAdapter, OpencodeAdapter, CodexAdapter])
|
|
75
|
+
return makeRegistry(adapters)
|
|
76
|
+
}),
|
|
77
|
+
}) {
|
|
78
|
+
/**
|
|
79
|
+
* The adapters are statically known at the composition root, so the contract
|
|
80
|
+
* is enforced by the type. The previous version took `ReadonlyArray<object>`
|
|
81
|
+
* and proved membership at runtime by walking prototypes and calling
|
|
82
|
+
* `Context.isTag` on the constructor — reflection standing in for a type, plus
|
|
83
|
+
* an error channel for a condition the compiler already rules out.
|
|
84
|
+
*/
|
|
85
|
+
static readonly fromAdapters = (adapters: ReadonlyArray<HarnessAdapterContract>) =>
|
|
86
|
+
HarnessRegistry.make(makeRegistry(adapters))
|
|
87
|
+
}
|