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
package/src/main.ts
CHANGED
|
@@ -3,21 +3,46 @@ import { CliConfig, Command, ValidationError } from '@effect/cli'
|
|
|
3
3
|
import { Terminal } from '@effect/platform'
|
|
4
4
|
import { NodeContext, NodeRuntime } from '@effect/platform-node'
|
|
5
5
|
import { Cause, Config, Console, Effect, Layer, Logger, LogLevel, Option, Schema, String } from 'effect'
|
|
6
|
+
import { ManualAuthorization } from './Auth/ManualAuthorization.js'
|
|
7
|
+
import { PendingInitStore } from './Auth/PendingInit.js'
|
|
8
|
+
import { SetupGrantAuthorization } from './Auth/SetupGrantAuthorization.js'
|
|
6
9
|
import { Authentication, LoginCommand, LogoutCommand, WhoamiCommand } from './Authentication.js'
|
|
10
|
+
import { commandFromArgv } from './CommandPath.js'
|
|
7
11
|
import { FetchCommand } from './Commands/Fetch.js'
|
|
8
12
|
import { AgentHookCommand, HumanHookCommand } from './Commands/Hook.js'
|
|
13
|
+
import {
|
|
14
|
+
AgentInitCommand,
|
|
15
|
+
HumanInitCommand,
|
|
16
|
+
InitTerminalInteraction,
|
|
17
|
+
preflightAgentInitArgv,
|
|
18
|
+
resolveInitExecutionMode,
|
|
19
|
+
} from './Commands/Init.js'
|
|
9
20
|
import { InstallSubCommand, UninstallSubCommand } from './Commands/Mcp.js'
|
|
10
21
|
import { McpRunCommand } from './Commands/McpRun.js'
|
|
11
22
|
import { SearchCommand } from './Commands/Search.js'
|
|
12
23
|
import { SkillCommand } from './Commands/Skill.js'
|
|
24
|
+
import {
|
|
25
|
+
AgentStatusCommand,
|
|
26
|
+
HumanStatusCommand,
|
|
27
|
+
preflightAgentStatusArgv,
|
|
28
|
+
resolveStatusExecutionMode,
|
|
29
|
+
StatusTerminalInteraction,
|
|
30
|
+
} from './Commands/Status.js'
|
|
31
|
+
import { TelemetryCommand } from './Commands/Telemetry.js'
|
|
13
32
|
import { UninstallCommand } from './Commands/Uninstall.js'
|
|
14
|
-
import { ConfigManager } from './Config.js'
|
|
33
|
+
import { ConfigManager, envFlag, envLiteral } from './Config.js'
|
|
15
34
|
import { ClaudeHook } from './Hook/Claude.js'
|
|
16
35
|
import { OpencodeHook } from './Hook/Opencode.js'
|
|
36
|
+
import { HarnessDetector } from './Init/HarnessDetector.js'
|
|
37
|
+
import { HarnessRegistry } from './Init/HarnessRegistry.js'
|
|
38
|
+
import { InitService } from './Init/Service.js'
|
|
39
|
+
import { StatusService } from './Init/Status.js'
|
|
17
40
|
import { HookInstaller } from './Install/Hook.js'
|
|
18
41
|
import { Mcp } from './Install/Mcp.js'
|
|
19
42
|
import { Skill as SkillInstaller } from './Install/Skill.js'
|
|
20
43
|
import { Uninstall } from './Install/Uninstall.js'
|
|
44
|
+
import { Telemetry } from './Telemetry.js'
|
|
45
|
+
import { CLI_VERSION } from './Version.js'
|
|
21
46
|
|
|
22
47
|
/**
|
|
23
48
|
* Where this process is running:
|
|
@@ -27,18 +52,39 @@ import { Uninstall } from './Install/Uninstall.js'
|
|
|
27
52
|
* - 'mcp': the binary is serving as the MCP transport. MCP only runs in agents.
|
|
28
53
|
*/
|
|
29
54
|
|
|
55
|
+
// envFlag / envLiteral read leniently: a malformed value (CLAUDECODE=banana,
|
|
56
|
+
// EXPANDAI_CLI_CONTEXT=bogus) must degrade instead of crashing the CLI —
|
|
57
|
+
// Config.option / Config.withDefault only absorb missing data, not invalid.
|
|
30
58
|
const EnvironmentSignals = Config.all({
|
|
31
|
-
override:
|
|
59
|
+
override: envLiteral('EXPANDAI_CLI_CONTEXT', Schema.Literal('human', 'agent')),
|
|
32
60
|
mcpTransport: Config.string('MCP_TRANSPORT').pipe(Config.option, Config.map(Option.isSome)),
|
|
33
|
-
claudeCode:
|
|
61
|
+
claudeCode: envFlag('CLAUDECODE'),
|
|
34
62
|
cursor: Config.string('CURSOR_TRACE_ID').pipe(Config.option, Config.map(Option.isSome)),
|
|
35
63
|
codex: Config.string('CODEX_RUN_ID').pipe(Config.option, Config.map(Option.isSome)),
|
|
36
64
|
})
|
|
37
65
|
|
|
38
|
-
const detectContext = Effect.
|
|
66
|
+
const detectContext = Effect.fnUntraced(function* (command: string) {
|
|
67
|
+
const initMode = resolveInitExecutionMode({
|
|
68
|
+
argv: process.argv,
|
|
69
|
+
environment: process.env,
|
|
70
|
+
stdinIsTty: process.stdin.isTTY === true,
|
|
71
|
+
stdoutIsTty: process.stdout.isTTY === true,
|
|
72
|
+
})
|
|
73
|
+
if (initMode !== undefined) return initMode === 'machine' ? ('agent' as const) : ('human' as const)
|
|
74
|
+
const statusMode = resolveStatusExecutionMode({
|
|
75
|
+
argv: process.argv,
|
|
76
|
+
environment: process.env,
|
|
77
|
+
stdinIsTty: process.stdin.isTTY === true,
|
|
78
|
+
stdoutIsTty: process.stdout.isTTY === true,
|
|
79
|
+
})
|
|
80
|
+
if (statusMode !== undefined) return statusMode === 'machine' ? ('agent' as const) : ('human' as const)
|
|
81
|
+
|
|
39
82
|
const signals = yield* EnvironmentSignals
|
|
40
83
|
|
|
41
|
-
|
|
84
|
+
// Installed MCP entries invoke `expandai mcp run` without any transport env
|
|
85
|
+
// var, so the resolved command is the reliable signal; MCP_TRANSPORT stays
|
|
86
|
+
// as a secondary hint for hand-written configs that set it.
|
|
87
|
+
const mcp = command === 'mcp run' || signals.mcpTransport ? Option.some('mcp' as const) : Option.none<'mcp'>()
|
|
42
88
|
// Authentication.logout uses both stdout and stdin TTY checks because Prompt
|
|
43
89
|
// reads from stdin; for context detection a non-TTY stdout alone is enough
|
|
44
90
|
// to identify a non-interactive caller.
|
|
@@ -60,6 +106,21 @@ const AgentMcp = Command.make('mcp').pipe(
|
|
|
60
106
|
Command.withSubcommands([McpRunCommand]),
|
|
61
107
|
)
|
|
62
108
|
|
|
109
|
+
const InitServiceLive = InitService.DefaultWithoutDependencies.pipe(
|
|
110
|
+
Layer.provide(
|
|
111
|
+
Layer.mergeAll(
|
|
112
|
+
Authentication.Default,
|
|
113
|
+
ManualAuthorization.Default,
|
|
114
|
+
SetupGrantAuthorization.Default,
|
|
115
|
+
HarnessRegistry.Default,
|
|
116
|
+
),
|
|
117
|
+
),
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
const StatusServiceLive = StatusService.DefaultWithoutDependencies.pipe(
|
|
121
|
+
Layer.provide(Layer.mergeAll(ConfigManager.Default, PendingInitStore.Default, HarnessRegistry.Default)),
|
|
122
|
+
)
|
|
123
|
+
|
|
63
124
|
const HumanCli = Command.make('expandai').pipe(
|
|
64
125
|
Command.withDescription('expand.ai CLI and MCP server'),
|
|
65
126
|
Command.withSubcommands([
|
|
@@ -68,10 +129,13 @@ const HumanCli = Command.make('expandai').pipe(
|
|
|
68
129
|
LoginCommand,
|
|
69
130
|
WhoamiCommand,
|
|
70
131
|
LogoutCommand,
|
|
132
|
+
HumanInitCommand,
|
|
133
|
+
HumanStatusCommand,
|
|
71
134
|
UninstallCommand,
|
|
72
135
|
HumanMcp,
|
|
73
136
|
SkillCommand,
|
|
74
137
|
HumanHookCommand,
|
|
138
|
+
TelemetryCommand,
|
|
75
139
|
]),
|
|
76
140
|
Command.provide(
|
|
77
141
|
Layer.mergeAll(
|
|
@@ -83,6 +147,11 @@ const HumanCli = Command.make('expandai').pipe(
|
|
|
83
147
|
Uninstall.Default,
|
|
84
148
|
ClaudeHook.Default,
|
|
85
149
|
OpencodeHook.Default,
|
|
150
|
+
InitServiceLive,
|
|
151
|
+
HarnessDetector.Default,
|
|
152
|
+
InitTerminalInteraction.Default,
|
|
153
|
+
StatusServiceLive,
|
|
154
|
+
StatusTerminalInteraction.Default,
|
|
86
155
|
),
|
|
87
156
|
),
|
|
88
157
|
)
|
|
@@ -95,27 +164,98 @@ const AgentCli = Command.make('expandai').pipe(
|
|
|
95
164
|
LoginCommand,
|
|
96
165
|
WhoamiCommand,
|
|
97
166
|
LogoutCommand,
|
|
167
|
+
AgentInitCommand,
|
|
168
|
+
AgentStatusCommand,
|
|
169
|
+
// The consent step tells the user `expandai uninstall` is how to undo
|
|
170
|
+
// setup — including removing the machine-wide `WebFetch` deny rule. That
|
|
171
|
+
// text is read by an agent, so the command has to exist in this tree too;
|
|
172
|
+
// it was human-only, and an agent running it got "Invalid subcommand".
|
|
173
|
+
UninstallCommand,
|
|
98
174
|
AgentMcp,
|
|
99
175
|
AgentHookCommand,
|
|
176
|
+
TelemetryCommand,
|
|
100
177
|
]),
|
|
101
178
|
Command.provide(
|
|
102
|
-
Layer.mergeAll(
|
|
179
|
+
Layer.mergeAll(
|
|
180
|
+
ConfigManager.Default,
|
|
181
|
+
Authentication.Default,
|
|
182
|
+
ClaudeHook.Default,
|
|
183
|
+
OpencodeHook.Default,
|
|
184
|
+
Mcp.Default,
|
|
185
|
+
HookInstaller.Default,
|
|
186
|
+
SkillInstaller.Default,
|
|
187
|
+
Uninstall.Default,
|
|
188
|
+
InitServiceLive,
|
|
189
|
+
HarnessDetector.Default,
|
|
190
|
+
StatusServiceLive,
|
|
191
|
+
),
|
|
103
192
|
),
|
|
104
193
|
)
|
|
105
194
|
|
|
106
195
|
const LoggerLive = Layer.unwrapEffect(
|
|
107
196
|
Effect.gen(function* () {
|
|
108
197
|
const isDebug = yield* Config.boolean('DEBUG').pipe(Config.withDefault(false))
|
|
109
|
-
|
|
198
|
+
// stdout is a protocol/data surface (hook JSON payloads, fetched
|
|
199
|
+
// markdown) — a log line ahead of the payload corrupts it for the
|
|
200
|
+
// consumer, so diagnostics go to stderr.
|
|
201
|
+
return Layer.mergeAll(
|
|
202
|
+
Logger.replace(Logger.defaultLogger, Logger.prettyLogger({ stderr: true })),
|
|
203
|
+
Logger.minimumLogLevel(isDebug ? LogLevel.All : LogLevel.Info),
|
|
204
|
+
)
|
|
110
205
|
}),
|
|
111
206
|
)
|
|
112
207
|
|
|
113
|
-
|
|
208
|
+
// Status is a read-only diagnostic contract, and `init --detect` documents itself
|
|
209
|
+
// as changing nothing — the guide prints "This changes nothing:" directly above
|
|
210
|
+
// it. Select the no-op service before layer acquisition so Telemetry.Default
|
|
211
|
+
// cannot persist a distinct id, repair config permissions, display a notice, or
|
|
212
|
+
// send a request. A brand-new HOME came back from `--detect` with a config.json
|
|
213
|
+
// holding a telemetry id, which is a write however small. Other commands retain
|
|
214
|
+
// the ordinary telemetry service unchanged.
|
|
215
|
+
const writesNothing =
|
|
216
|
+
commandFromArgv(process.argv) === 'status' ||
|
|
217
|
+
(commandFromArgv(process.argv) === 'init' && process.argv.includes('--detect'))
|
|
218
|
+
const TelemetryLive = writesNothing ? Telemetry.DISABLED : Telemetry.Default
|
|
219
|
+
const Env = Layer.mergeAll(NodeContext.layer, CliConfig.layer({ showBuiltIns: false }), LoggerLive, TelemetryLive)
|
|
220
|
+
|
|
221
|
+
const errorTagFromCause = (cause: Cause.Cause<unknown>): string =>
|
|
222
|
+
Cause.failureOption(cause).pipe(
|
|
223
|
+
Option.match({
|
|
224
|
+
onNone: () => 'Defect',
|
|
225
|
+
onSome: (error) =>
|
|
226
|
+
typeof error === 'object' && error !== null && '_tag' in error && typeof error._tag === 'string'
|
|
227
|
+
? error._tag
|
|
228
|
+
: 'UnknownError',
|
|
229
|
+
}),
|
|
230
|
+
)
|
|
231
|
+
|
|
232
|
+
function startupOnboardingPreflightError(): string | undefined {
|
|
233
|
+
const initMode = resolveInitExecutionMode({
|
|
234
|
+
argv: process.argv,
|
|
235
|
+
environment: process.env,
|
|
236
|
+
stdinIsTty: process.stdin.isTTY === true,
|
|
237
|
+
stdoutIsTty: process.stdout.isTTY === true,
|
|
238
|
+
})
|
|
239
|
+
if (initMode === 'machine') return preflightAgentInitArgv(process.argv)
|
|
240
|
+
const statusMode = resolveStatusExecutionMode({
|
|
241
|
+
argv: process.argv,
|
|
242
|
+
environment: process.env,
|
|
243
|
+
stdinIsTty: process.stdin.isTTY === true,
|
|
244
|
+
stdoutIsTty: process.stdout.isTTY === true,
|
|
245
|
+
})
|
|
246
|
+
return statusMode === 'machine' ? preflightAgentStatusArgv(process.argv) : undefined
|
|
247
|
+
}
|
|
114
248
|
|
|
115
249
|
const program = Effect.gen(function* () {
|
|
116
|
-
const
|
|
250
|
+
const command = commandFromArgv(process.argv)
|
|
251
|
+
const context = yield* detectContext(command)
|
|
252
|
+
const telemetry = yield* Telemetry
|
|
253
|
+
if (context === 'human') {
|
|
254
|
+
yield* telemetry.showNoticeIfNeeded()
|
|
255
|
+
}
|
|
256
|
+
yield* telemetry.capture('cli_command_run', { command, context })
|
|
117
257
|
const cli = context === 'human' ? HumanCli : AgentCli
|
|
118
|
-
return yield* Command.run(cli, { name: 'expand.ai CLI', version:
|
|
258
|
+
return yield* Command.run(cli, { name: 'expand.ai CLI', version: CLI_VERSION })(process.argv)
|
|
119
259
|
}).pipe(
|
|
120
260
|
Effect.catchAllCause((cause) => {
|
|
121
261
|
const failure = Cause.failureOption(cause)
|
|
@@ -138,9 +278,28 @@ const program = Effect.gen(function* () {
|
|
|
138
278
|
),
|
|
139
279
|
})
|
|
140
280
|
const debug = Effect.logDebug('Error cause').pipe(Effect.annotateLogs({ cause: Cause.pretty(cause) }))
|
|
141
|
-
|
|
281
|
+
const trackFailure = Effect.flatMap(Telemetry, (telemetry) =>
|
|
282
|
+
telemetry.capture('cli_command_failed', {
|
|
283
|
+
command: commandFromArgv(process.argv),
|
|
284
|
+
error_tag: errorTagFromCause(cause),
|
|
285
|
+
}),
|
|
286
|
+
)
|
|
287
|
+
return print.pipe(Effect.zipRight(debug), Effect.zipRight(trackFailure), Effect.zipRight(Effect.failCause(cause)))
|
|
142
288
|
}),
|
|
289
|
+
// Deliver any pending telemetry before the process exits; capped at 1s by
|
|
290
|
+
// Telemetry.flush so it can never hold a short-lived invocation open.
|
|
291
|
+
Effect.ensuring(Effect.flatMap(Telemetry, (telemetry) => telemetry.flush)),
|
|
143
292
|
Effect.provide(Env),
|
|
144
293
|
)
|
|
145
294
|
|
|
146
|
-
|
|
295
|
+
// disablePrettyLogger: runMain's own pretty logger writes to stdout, which
|
|
296
|
+
// would put diagnostics back on the protocol/data stream LoggerLive keeps clean.
|
|
297
|
+
const preflightError = startupOnboardingPreflightError()
|
|
298
|
+
if (preflightError !== undefined) {
|
|
299
|
+
// This validation must finish before the Effect runtime acquires Telemetry,
|
|
300
|
+
// otherwise an invalid machine command could still create local state.
|
|
301
|
+
process.stderr.write(`${preflightError}\n`)
|
|
302
|
+
process.exitCode = 2
|
|
303
|
+
} else {
|
|
304
|
+
NodeRuntime.runMain(program, { disableErrorReporting: true, disablePrettyLogger: true })
|
|
305
|
+
}
|
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
import { HttpClient } from '@effect/platform';
|
|
2
|
-
import { Duration, Effect, Schema } from 'effect';
|
|
3
|
-
import { ConfigManager } from './Config.js';
|
|
4
|
-
declare const DeviceCodeResponse_base: Schema.Class<DeviceCodeResponse, {
|
|
5
|
-
device_code: typeof Schema.String;
|
|
6
|
-
user_code: Schema.transform<typeof Schema.String, typeof Schema.String>;
|
|
7
|
-
verification_uri: typeof Schema.String;
|
|
8
|
-
verification_uri_complete: typeof Schema.String;
|
|
9
|
-
expires_in: Schema.transform<typeof Schema.Number, typeof Schema.DurationFromSelf>;
|
|
10
|
-
interval: Schema.transform<typeof Schema.Number, typeof Schema.DurationFromSelf>;
|
|
11
|
-
}, Schema.Struct.Encoded<{
|
|
12
|
-
device_code: typeof Schema.String;
|
|
13
|
-
user_code: Schema.transform<typeof Schema.String, typeof Schema.String>;
|
|
14
|
-
verification_uri: typeof Schema.String;
|
|
15
|
-
verification_uri_complete: typeof Schema.String;
|
|
16
|
-
expires_in: Schema.transform<typeof Schema.Number, typeof Schema.DurationFromSelf>;
|
|
17
|
-
interval: Schema.transform<typeof Schema.Number, typeof Schema.DurationFromSelf>;
|
|
18
|
-
}>, never, {
|
|
19
|
-
readonly expires_in: Duration.Duration;
|
|
20
|
-
} & {
|
|
21
|
-
readonly device_code: string;
|
|
22
|
-
} & {
|
|
23
|
-
readonly user_code: string;
|
|
24
|
-
} & {
|
|
25
|
-
readonly verification_uri: string;
|
|
26
|
-
} & {
|
|
27
|
-
readonly verification_uri_complete: string;
|
|
28
|
-
} & {
|
|
29
|
-
readonly interval: Duration.Duration;
|
|
30
|
-
}, {}, {}>;
|
|
31
|
-
export declare class DeviceCodeResponse extends DeviceCodeResponse_base {
|
|
32
|
-
}
|
|
33
|
-
declare const TokenResponse_base: Schema.Class<TokenResponse, {
|
|
34
|
-
access_token: typeof Schema.String;
|
|
35
|
-
expires_in: Schema.transform<typeof Schema.Number, typeof Schema.DurationFromSelf>;
|
|
36
|
-
token_type: typeof Schema.String;
|
|
37
|
-
scope: Schema.optional<typeof Schema.String>;
|
|
38
|
-
}, Schema.Struct.Encoded<{
|
|
39
|
-
access_token: typeof Schema.String;
|
|
40
|
-
expires_in: Schema.transform<typeof Schema.Number, typeof Schema.DurationFromSelf>;
|
|
41
|
-
token_type: typeof Schema.String;
|
|
42
|
-
scope: Schema.optional<typeof Schema.String>;
|
|
43
|
-
}>, never, {
|
|
44
|
-
readonly access_token: string;
|
|
45
|
-
} & {
|
|
46
|
-
readonly expires_in: Duration.Duration;
|
|
47
|
-
} & {
|
|
48
|
-
readonly token_type: string;
|
|
49
|
-
} & {
|
|
50
|
-
readonly scope?: string | undefined;
|
|
51
|
-
}, {}, {}>;
|
|
52
|
-
export declare class TokenResponse extends TokenResponse_base {
|
|
53
|
-
}
|
|
54
|
-
declare const DeviceAuthRequestFailed_base: Schema.TaggedErrorClass<DeviceAuthRequestFailed, "DeviceAuthRequestFailed", {
|
|
55
|
-
readonly _tag: Schema.tag<"DeviceAuthRequestFailed">;
|
|
56
|
-
} & {
|
|
57
|
-
endpoint: typeof Schema.String;
|
|
58
|
-
error: typeof Schema.Defect;
|
|
59
|
-
status: Schema.optional<typeof Schema.Number>;
|
|
60
|
-
}>;
|
|
61
|
-
export declare class DeviceAuthRequestFailed extends DeviceAuthRequestFailed_base {
|
|
62
|
-
get message(): string;
|
|
63
|
-
}
|
|
64
|
-
declare const DeviceAuthorizationDenied_base: Schema.TaggedErrorClass<DeviceAuthorizationDenied, "DeviceAuthorizationDenied", {
|
|
65
|
-
readonly _tag: Schema.tag<"DeviceAuthorizationDenied">;
|
|
66
|
-
}>;
|
|
67
|
-
export declare class DeviceAuthorizationDenied extends DeviceAuthorizationDenied_base {
|
|
68
|
-
get message(): string;
|
|
69
|
-
}
|
|
70
|
-
declare const DeviceAuthorizationExpired_base: Schema.TaggedErrorClass<DeviceAuthorizationExpired, "DeviceAuthorizationExpired", {
|
|
71
|
-
readonly _tag: Schema.tag<"DeviceAuthorizationExpired">;
|
|
72
|
-
}>;
|
|
73
|
-
export declare class DeviceAuthorizationExpired extends DeviceAuthorizationExpired_base {
|
|
74
|
-
get message(): string;
|
|
75
|
-
}
|
|
76
|
-
declare const DeviceAuthService_base: Effect.Service.Class<DeviceAuthService, "@expandai/cli/DeviceAuthService", {
|
|
77
|
-
readonly dependencies: readonly [import("effect/Layer").Layer<HttpClient.HttpClient, never, never>, import("effect/Layer").Layer<ConfigManager, import("effect/ConfigError").ConfigError, never>];
|
|
78
|
-
readonly effect: Effect.Effect<{
|
|
79
|
-
readonly requestDeviceCode: () => Effect.Effect<DeviceCodeResponse, import("@effect/platform/HttpBody").HttpBodyError | DeviceAuthRequestFailed, never>;
|
|
80
|
-
readonly pollForToken: (deviceCode: string, interval: Duration.Duration, expiresIn: Duration.Duration) => Effect.Effect<TokenResponse, DeviceAuthRequestFailed | DeviceAuthorizationDenied | DeviceAuthorizationExpired, never>;
|
|
81
|
-
readonly saveToken: (tokenResponse: TokenResponse) => Effect.Effect<void, import("./Config.js").ConfigNotWritable | import("effect/ParseResult").ParseError, never>;
|
|
82
|
-
}, import("./Config.js").ConfigParseError | import("effect/ConfigError").ConfigError | import("@effect/platform/Error").PlatformError, ConfigManager | HttpClient.HttpClient>;
|
|
83
|
-
}>;
|
|
84
|
-
export declare class DeviceAuthService extends DeviceAuthService_base {
|
|
85
|
-
}
|
|
86
|
-
export {};
|
|
87
|
-
//# sourceMappingURL=DeviceAuth.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"DeviceAuth.d.ts","sourceRoot":"","sources":["../../src/DeviceAuth.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAyC,MAAM,kBAAkB,CAAA;AAEpF,OAAO,EAAY,QAAQ,EAAE,MAAM,EAA6C,MAAM,EAAU,MAAM,QAAQ,CAAA;AAC9G,OAAO,EAAE,aAAa,EAAe,MAAM,aAAa,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAiBxD,qBAAa,kBAAmB,SAAQ,uBAOtC;CAAG;;;;;;;;;;;;;;;;;;;;AAEL,qBAAa,aAAc,SAAQ,kBAKjC;CAAG;;;;;;;;AAEL,qBAAa,uBAAwB,SAAQ,4BAI3C;IACD,IAAI,OAAO,WAEV;CACD;;;;AAED,qBAAa,yBAA0B,SAAQ,8BAG9C;IACA,IAAI,OAAO,WAEV;CACD;;;;AAED,qBAAa,0BAA2B,SAAQ,+BAG/C;IACA,IAAI,OAAO,WAEV;CACD;;;;;;;;;AAID,qBAAa,iBAAkB,SAAQ,sBA8HrC;CAAG"}
|
package/build/esm/DeviceAuth.js
DELETED
|
@@ -1,127 +0,0 @@
|
|
|
1
|
-
import { HttpClient, HttpClientRequest, HttpClientResponse } from '@effect/platform';
|
|
2
|
-
import { NodeHttpClient } from '@effect/platform-node';
|
|
3
|
-
import { DateTime, Duration, Effect, Inspectable, Match, Option, Redacted, Ref, Schema, String } from 'effect';
|
|
4
|
-
import { ConfigManager, OAuthConfig } from './Config.js';
|
|
5
|
-
const FormattedUserCode = Schema.transform(Schema.String, Schema.String, {
|
|
6
|
-
strict: true,
|
|
7
|
-
decode: (raw) => {
|
|
8
|
-
const upper = String.toUpperCase(raw);
|
|
9
|
-
return upper.length > 4 ? `${String.takeLeft(upper, 4)}-${String.takeRight(upper, upper.length - 4)}` : upper;
|
|
10
|
-
},
|
|
11
|
-
encode: (formatted) => formatted.replace('-', ''),
|
|
12
|
-
});
|
|
13
|
-
const DurationFromSeconds = Schema.transform(Schema.Number, Schema.DurationFromSelf, {
|
|
14
|
-
strict: true,
|
|
15
|
-
decode: Duration.seconds,
|
|
16
|
-
encode: Duration.toSeconds,
|
|
17
|
-
});
|
|
18
|
-
export class DeviceCodeResponse extends Schema.Class('DeviceCodeResponse')({
|
|
19
|
-
device_code: Schema.String,
|
|
20
|
-
user_code: FormattedUserCode,
|
|
21
|
-
verification_uri: Schema.String,
|
|
22
|
-
verification_uri_complete: Schema.String,
|
|
23
|
-
expires_in: DurationFromSeconds,
|
|
24
|
-
interval: DurationFromSeconds,
|
|
25
|
-
}) {
|
|
26
|
-
}
|
|
27
|
-
export class TokenResponse extends Schema.Class('TokenResponse')({
|
|
28
|
-
access_token: Schema.String,
|
|
29
|
-
expires_in: DurationFromSeconds,
|
|
30
|
-
token_type: Schema.String,
|
|
31
|
-
scope: Schema.optional(Schema.String),
|
|
32
|
-
}) {
|
|
33
|
-
}
|
|
34
|
-
export class DeviceAuthRequestFailed extends Schema.TaggedError()('DeviceAuthRequestFailed', {
|
|
35
|
-
endpoint: Schema.String,
|
|
36
|
-
error: Schema.Defect,
|
|
37
|
-
status: Schema.optional(Schema.Number),
|
|
38
|
-
}) {
|
|
39
|
-
get message() {
|
|
40
|
-
return `Device auth request to ${this.endpoint} failed${this.status ? ` (${this.status})` : ''}: ${Inspectable.format(this.error)}`;
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
export class DeviceAuthorizationDenied extends Schema.TaggedError()('DeviceAuthorizationDenied', {}) {
|
|
44
|
-
get message() {
|
|
45
|
-
return 'Authorization was denied by the user';
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
export class DeviceAuthorizationExpired extends Schema.TaggedError()('DeviceAuthorizationExpired', {}) {
|
|
49
|
-
get message() {
|
|
50
|
-
return 'Device authorization code expired';
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
const CLIENT_ID = 'expandai-cli';
|
|
54
|
-
export class DeviceAuthService extends Effect.Service()('@expandai/cli/DeviceAuthService', {
|
|
55
|
-
dependencies: [NodeHttpClient.layer, ConfigManager.Default],
|
|
56
|
-
effect: Effect.gen(function* () {
|
|
57
|
-
const httpClient = yield* HttpClient.HttpClient;
|
|
58
|
-
const configManager = yield* ConfigManager;
|
|
59
|
-
const apiUrl = yield* configManager.getApiUrl();
|
|
60
|
-
const requestDeviceCode = Effect.fn('DeviceAuthService.requestDeviceCode')(function* () {
|
|
61
|
-
const DEVICE_AUTH_CODE_ENDPOINT = '/api/auth/device/code';
|
|
62
|
-
const request = yield* HttpClientRequest.post(new URL(DEVICE_AUTH_CODE_ENDPOINT, apiUrl)).pipe(HttpClientRequest.bodyJson({ client_id: CLIENT_ID }));
|
|
63
|
-
return yield* httpClient.execute(request).pipe(Effect.flatMap(HttpClientResponse.schemaBodyJson(DeviceCodeResponse)), Effect.mapError((error) => new DeviceAuthRequestFailed({
|
|
64
|
-
endpoint: DEVICE_AUTH_CODE_ENDPOINT,
|
|
65
|
-
error,
|
|
66
|
-
})));
|
|
67
|
-
});
|
|
68
|
-
const pollForToken = Effect.fn('DeviceAuthService.pollForToken')(function* (deviceCode, interval, expiresIn) {
|
|
69
|
-
const DEVICE_AUTH_TOKEN_ENDPOINT = '/api/auth/device/token';
|
|
70
|
-
// RFC 8628 §3.5: on `slow_down`, the polling interval MUST be increased by 5
|
|
71
|
-
// seconds for this and all subsequent requests.
|
|
72
|
-
const SLOW_DOWN_BUMP = Duration.seconds(5);
|
|
73
|
-
const intervalRef = yield* Ref.make(interval);
|
|
74
|
-
const PollErrorBody = Schema.Struct({
|
|
75
|
-
error: Schema.String,
|
|
76
|
-
error_description: Schema.optional(Schema.String),
|
|
77
|
-
});
|
|
78
|
-
// better-auth's `deviceAuthorization` plugin accepts JSON; RFC 8628 §3.4
|
|
79
|
-
// would normally require `application/x-www-form-urlencoded`. If we ever
|
|
80
|
-
// target a non-better-auth server, switch to `HttpClientRequest.bodyUrlParams`.
|
|
81
|
-
const singlePoll = HttpClientRequest.post(new URL(DEVICE_AUTH_TOKEN_ENDPOINT, apiUrl)).pipe(HttpClientRequest.bodyJson({
|
|
82
|
-
grant_type: 'urn:ietf:params:oauth:grant-type:device_code',
|
|
83
|
-
device_code: deviceCode,
|
|
84
|
-
client_id: CLIENT_ID,
|
|
85
|
-
}), Effect.flatMap(httpClient.execute), Effect.flatMap(HttpClientResponse.matchStatus({
|
|
86
|
-
'200': (response) => HttpClientResponse.schemaBodyJson(TokenResponse)(response).pipe(Effect.map(Option.some)),
|
|
87
|
-
orElse: (response) => HttpClientResponse.schemaBodyJson(PollErrorBody)(response).pipe(Effect.flatMap(({ error, error_description }) => Match.value(error).pipe(Match.when('authorization_pending', () => Ref.get(intervalRef).pipe(Effect.flatMap(Effect.sleep), Effect.as(Option.none()))), Match.when('slow_down', () => Ref.updateAndGet(intervalRef, (current) => Duration.sum(current, SLOW_DOWN_BUMP)).pipe(Effect.flatMap(Effect.sleep), Effect.as(Option.none()))), Match.when('access_denied', () => Effect.fail(new DeviceAuthorizationDenied())), Match.when('expired_token', () => Effect.fail(new DeviceAuthorizationExpired())), Match.orElse(() => Effect.fail(new DeviceAuthRequestFailed({
|
|
88
|
-
endpoint: DEVICE_AUTH_TOKEN_ENDPOINT,
|
|
89
|
-
status: response.status,
|
|
90
|
-
error: error_description ?? error,
|
|
91
|
-
})))))),
|
|
92
|
-
})), Effect.catchTags({
|
|
93
|
-
RequestError: (error) => new DeviceAuthRequestFailed({ endpoint: DEVICE_AUTH_TOKEN_ENDPOINT, error }),
|
|
94
|
-
ResponseError: (error) => new DeviceAuthRequestFailed({ endpoint: DEVICE_AUTH_TOKEN_ENDPOINT, error }),
|
|
95
|
-
HttpBodyError: (error) => new DeviceAuthRequestFailed({ endpoint: DEVICE_AUTH_TOKEN_ENDPOINT, error }),
|
|
96
|
-
ParseError: (error) => new DeviceAuthRequestFailed({ endpoint: DEVICE_AUTH_TOKEN_ENDPOINT, error }),
|
|
97
|
-
}));
|
|
98
|
-
const result = yield* Effect.repeat(singlePoll, { until: Option.isSome }).pipe(Effect.timeoutFail({
|
|
99
|
-
duration: expiresIn,
|
|
100
|
-
onTimeout: () => new DeviceAuthorizationExpired(),
|
|
101
|
-
}));
|
|
102
|
-
return yield* Option.match(result, {
|
|
103
|
-
onNone: () => new DeviceAuthorizationExpired(),
|
|
104
|
-
onSome: Effect.succeed,
|
|
105
|
-
});
|
|
106
|
-
});
|
|
107
|
-
// INFO: better-auth's `deviceAuthorization` plugin issues access tokens
|
|
108
|
-
// with no refresh flow — `/api/auth/device/token` only accepts
|
|
109
|
-
// `grant_type=urn:ietf:params:oauth:grant-type:device_code`. Refresh is
|
|
110
|
-
// not part of the auth surface we're using, so we don't persist the
|
|
111
|
-
// refresh_token at all; ApiClient pre-empts the post-expiry 401 with
|
|
112
|
-
// `OAuthTokenExpired` and asks the user to re-login.
|
|
113
|
-
const saveToken = Effect.fn('DeviceAuthService.saveToken')(function* (tokenResponse) {
|
|
114
|
-
const now = yield* DateTime.now;
|
|
115
|
-
const expiresAt = DateTime.addDuration(now, tokenResponse.expires_in);
|
|
116
|
-
yield* configManager.updateConfig({
|
|
117
|
-
authMethod: OAuthConfig.make({
|
|
118
|
-
accessToken: Redacted.make(tokenResponse.access_token),
|
|
119
|
-
expiresAt,
|
|
120
|
-
}),
|
|
121
|
-
});
|
|
122
|
-
});
|
|
123
|
-
return { requestDeviceCode, pollForToken, saveToken };
|
|
124
|
-
}),
|
|
125
|
-
}) {
|
|
126
|
-
}
|
|
127
|
-
//# sourceMappingURL=DeviceAuth.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"DeviceAuth.js","sourceRoot":"","sources":["../../src/DeviceAuth.ts"],"names":[],"mappings":"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"}
|