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,228 @@
|
|
|
1
|
+
import { Command, Options, Prompt } from '@effect/cli'
|
|
2
|
+
import { Terminal } from '@effect/platform'
|
|
3
|
+
import { Console, Effect, Either, Logger, LogLevel, Option, Schema } from 'effect'
|
|
4
|
+
import { InitErrorEnvelope, InitHarness, InitScope } from '../Init/Domain.js'
|
|
5
|
+
import { StatusRequest, StatusResult, StatusService, StatusServiceError } from '../Init/Status.js'
|
|
6
|
+
import { type OnboardingExecutionModeInput, resolveOnboardingExecutionMode } from './Init.js'
|
|
7
|
+
|
|
8
|
+
const harness = Options.text('harness').pipe(Options.optional, Options.withDescription('Agent harness to inspect'))
|
|
9
|
+
const scope = Options.text('scope').pipe(Options.optional, Options.withDescription('Configuration scope'))
|
|
10
|
+
const json = Options.boolean('json').pipe(Options.withDescription('Emit one machine-readable JSON result'))
|
|
11
|
+
const config = { harness, scope, json }
|
|
12
|
+
|
|
13
|
+
const ErrorJson = Schema.parseJson(InitErrorEnvelope)
|
|
14
|
+
const StatusResultJson = Schema.parseJson(StatusResult)
|
|
15
|
+
const INVALID_ARGUMENTS_MESSAGE =
|
|
16
|
+
'Agent status requires --harness claude-code|cursor|opencode|codex, --scope project|global, and --json.'
|
|
17
|
+
|
|
18
|
+
function errorJson(code: string, message: string, recoverable: boolean): string {
|
|
19
|
+
return Schema.encodeSync(ErrorJson)(
|
|
20
|
+
new InitErrorEnvelope({ schemaVersion: 1, status: 'error', code, message, recoverable }),
|
|
21
|
+
)
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function invalidArgumentsJson(): string {
|
|
25
|
+
return errorJson('invalid_arguments', INVALID_ARGUMENTS_MESSAGE, true)
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function emitError(code: string, message: string, recoverable: boolean, exitCode: number) {
|
|
29
|
+
return Console.error(errorJson(code, message, recoverable)).pipe(
|
|
30
|
+
Effect.zipRight(Effect.sync(() => void (process.exitCode = exitCode))),
|
|
31
|
+
)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export interface StatusCommandOptions {
|
|
35
|
+
readonly harness: Option.Option<string>
|
|
36
|
+
readonly json: boolean
|
|
37
|
+
readonly scope: Option.Option<string>
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/** Selects the status surface using the same machine-safety precedence as init. */
|
|
41
|
+
export function resolveStatusExecutionMode(input: OnboardingExecutionModeInput): 'human' | 'machine' | undefined {
|
|
42
|
+
return resolveOnboardingExecutionMode(input, 'status')
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function parseMachineArguments(args: readonly string[]): StatusCommandOptions | undefined {
|
|
46
|
+
function parse(index: number, parsed: StatusCommandOptions): StatusCommandOptions | undefined {
|
|
47
|
+
if (index >= args.length) return parsed
|
|
48
|
+
const token = args[index]
|
|
49
|
+
if (token === '--json' && !parsed.json) return parse(index + 1, { ...parsed, json: true })
|
|
50
|
+
if (token !== '--harness' && token !== '--scope') return undefined
|
|
51
|
+
const value = args[index + 1]
|
|
52
|
+
if (value === undefined || value.startsWith('-')) return undefined
|
|
53
|
+
if (token === '--harness' && Option.isNone(parsed.harness)) {
|
|
54
|
+
return parse(index + 2, { ...parsed, harness: Option.some(value) })
|
|
55
|
+
}
|
|
56
|
+
if (token === '--scope' && Option.isNone(parsed.scope)) {
|
|
57
|
+
return parse(index + 2, { ...parsed, scope: Option.some(value) })
|
|
58
|
+
}
|
|
59
|
+
return undefined
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return parse(0, { harness: Option.none(), json: false, scope: Option.none() })
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/** Returns safe JSON before Effect CLI can render parser help or acquire services. */
|
|
66
|
+
export function preflightAgentStatusArgv(argv: readonly string[]): string | undefined {
|
|
67
|
+
if (argv[2] !== 'status') return undefined
|
|
68
|
+
const args = argv.slice(3)
|
|
69
|
+
if (args.length === 1 && (args[0] === '--help' || args[0] === '-h')) return undefined
|
|
70
|
+
const parsed = parseMachineArguments(args)
|
|
71
|
+
if (parsed === undefined || !parsed.json) return invalidArgumentsJson()
|
|
72
|
+
if (Option.isNone(Option.flatMap(parsed.harness, (value) => Schema.decodeUnknownOption(InitHarness)(value)))) {
|
|
73
|
+
return invalidArgumentsJson()
|
|
74
|
+
}
|
|
75
|
+
if (!Option.contains(parsed.scope, 'project') && !Option.contains(parsed.scope, 'global')) {
|
|
76
|
+
return invalidArgumentsJson()
|
|
77
|
+
}
|
|
78
|
+
return undefined
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const HARNESS_LABELS: Record<typeof InitHarness.Type, string> = {
|
|
82
|
+
'claude-code': 'Claude Code',
|
|
83
|
+
cursor: 'Cursor',
|
|
84
|
+
codex: 'Codex',
|
|
85
|
+
opencode: 'OpenCode',
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/** Only these install a web-fetch hook; the line is meaningless for the rest. */
|
|
89
|
+
const HOOK_HARNESSES: ReadonlyArray<typeof InitHarness.Type> = ['claude-code', 'opencode']
|
|
90
|
+
|
|
91
|
+
function renderHumanStatus(result: StatusResult): string {
|
|
92
|
+
const pending = result.pendingAuthorization.count === 1 ? 'approval pending' : 'none'
|
|
93
|
+
const installation = result.installation.configured ? 'configured' : 'partial or not configured'
|
|
94
|
+
const configured = (present: boolean) => (present ? 'configured' : 'not configured')
|
|
95
|
+
// `result.harness` was never read: every harness printed as "Claude Code", and
|
|
96
|
+
// a correctly configured Cursor machine also reported a missing WebFetch hook
|
|
97
|
+
// it never installs. The guide sends users here to confirm setup, so this was
|
|
98
|
+
// the last thing they saw.
|
|
99
|
+
return [
|
|
100
|
+
'Expand status',
|
|
101
|
+
`Auth: ${result.auth.state}`,
|
|
102
|
+
`Pending authorization: ${pending}`,
|
|
103
|
+
`${HARNESS_LABELS[result.harness]}: ${installation}`,
|
|
104
|
+
...(HOOK_HARNESSES.includes(result.harness)
|
|
105
|
+
? [`WebFetch hook: ${configured(result.installation.components.webfetchHook)}`]
|
|
106
|
+
: []),
|
|
107
|
+
`Runtime skill: ${configured(result.installation.components.runtimeSkill)}`,
|
|
108
|
+
`MCP: ${configured(result.installation.components.mcp)}`,
|
|
109
|
+
`Runtime: ${result.installation.runtimeState}`,
|
|
110
|
+
].join('\n')
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const runStatusService = Effect.fnUntraced(function* (request: StatusRequest, jsonOutput: boolean) {
|
|
114
|
+
const service = yield* StatusService
|
|
115
|
+
// Log suppression belongs here, not in the service, and only for machine
|
|
116
|
+
// output: `--json` writes its result *and* its structured error envelope to
|
|
117
|
+
// stderr, so a warning interleaved there breaks the one-object contract an
|
|
118
|
+
// agent parses. Human status keeps its diagnostics — it is the command
|
|
119
|
+
// someone runs when something is already wrong.
|
|
120
|
+
const result = yield* Effect.either(
|
|
121
|
+
jsonOutput ? service.run(request).pipe(Logger.withMinimumLogLevel(LogLevel.None)) : service.run(request),
|
|
122
|
+
)
|
|
123
|
+
if (Either.isLeft(result)) {
|
|
124
|
+
const error = result.left
|
|
125
|
+
if (error instanceof StatusServiceError) {
|
|
126
|
+
yield* emitError(error.code, error.message, error.recoverable, 1)
|
|
127
|
+
return
|
|
128
|
+
}
|
|
129
|
+
yield* emitError('status_failed', 'Expand status could not be inspected safely.', true, 1)
|
|
130
|
+
return
|
|
131
|
+
}
|
|
132
|
+
if (!jsonOutput) {
|
|
133
|
+
yield* Console.log(renderHumanStatus(result.right))
|
|
134
|
+
return
|
|
135
|
+
}
|
|
136
|
+
const encoded = yield* Schema.encode(StatusResultJson)(result.right).pipe(
|
|
137
|
+
Effect.catchAll(() =>
|
|
138
|
+
emitError('invalid_status_result', 'Expand status returned an invalid result.', false, 1).pipe(
|
|
139
|
+
Effect.as(undefined),
|
|
140
|
+
),
|
|
141
|
+
),
|
|
142
|
+
)
|
|
143
|
+
if (typeof encoded === 'string') yield* Console.log(encoded)
|
|
144
|
+
})
|
|
145
|
+
|
|
146
|
+
const runMachineStatus = Effect.fnUntraced(function* ({ harness, json, scope }: StatusCommandOptions) {
|
|
147
|
+
if (
|
|
148
|
+
!json ||
|
|
149
|
+
Option.isNone(Option.flatMap(harness, (value) => Schema.decodeUnknownOption(InitHarness)(value))) ||
|
|
150
|
+
(!Option.contains(scope, 'project') && !Option.contains(scope, 'global'))
|
|
151
|
+
) {
|
|
152
|
+
yield* emitError('invalid_arguments', INVALID_ARGUMENTS_MESSAGE, true, 2)
|
|
153
|
+
return
|
|
154
|
+
}
|
|
155
|
+
const request = yield* Schema.decodeUnknown(StatusRequest)({
|
|
156
|
+
harness: Option.getOrUndefined(harness),
|
|
157
|
+
scope: Option.getOrUndefined(scope),
|
|
158
|
+
}).pipe(
|
|
159
|
+
Effect.catchAll(() =>
|
|
160
|
+
emitError('invalid_arguments', INVALID_ARGUMENTS_MESSAGE, true, 2).pipe(Effect.as(undefined)),
|
|
161
|
+
),
|
|
162
|
+
)
|
|
163
|
+
if (request !== undefined) yield* runStatusService(request, true)
|
|
164
|
+
})
|
|
165
|
+
|
|
166
|
+
export class StatusTerminalInteraction extends Effect.Service<StatusTerminalInteraction>()(
|
|
167
|
+
'@expandai/cli/Commands/StatusTerminalInteraction',
|
|
168
|
+
{
|
|
169
|
+
effect: Effect.gen(function* () {
|
|
170
|
+
const terminal = yield* Terminal.Terminal
|
|
171
|
+
const chooseHarness = Effect.fnUntraced(function* () {
|
|
172
|
+
return yield* Prompt.select({
|
|
173
|
+
message: 'Which agent harness should Expand inspect?',
|
|
174
|
+
// init configures all four, so inspection must cover all four.
|
|
175
|
+
choices: [
|
|
176
|
+
{ title: 'Claude Code', value: 'claude-code' as const },
|
|
177
|
+
{ title: 'Cursor', value: 'cursor' as const },
|
|
178
|
+
{ title: 'opencode', value: 'opencode' as const },
|
|
179
|
+
{ title: 'Codex', value: 'codex' as const },
|
|
180
|
+
],
|
|
181
|
+
}).pipe(Effect.provideService(Terminal.Terminal, terminal))
|
|
182
|
+
})
|
|
183
|
+
const chooseScope = Effect.fnUntraced(function* () {
|
|
184
|
+
return yield* Prompt.select({
|
|
185
|
+
message: 'Which configuration scope should Expand inspect?',
|
|
186
|
+
choices: [
|
|
187
|
+
{ title: 'This project', value: 'project' as const },
|
|
188
|
+
{ title: 'All projects for this user', value: 'global' as const },
|
|
189
|
+
],
|
|
190
|
+
}).pipe(Effect.provideService(Terminal.Terminal, terminal))
|
|
191
|
+
})
|
|
192
|
+
return { chooseHarness, chooseScope } as const
|
|
193
|
+
}),
|
|
194
|
+
},
|
|
195
|
+
) {}
|
|
196
|
+
|
|
197
|
+
export const runHumanStatus = Effect.fnUntraced(function* (options: StatusCommandOptions) {
|
|
198
|
+
if (options.json) {
|
|
199
|
+
yield* runMachineStatus(options)
|
|
200
|
+
return
|
|
201
|
+
}
|
|
202
|
+
const interaction = yield* StatusTerminalInteraction
|
|
203
|
+
const harnessInput = Option.isSome(options.harness) ? options.harness.value : yield* interaction.chooseHarness()
|
|
204
|
+
const scopeInput = Option.isSome(options.scope) ? options.scope.value : yield* interaction.chooseScope()
|
|
205
|
+
const decodedHarness = Schema.decodeUnknownOption(InitHarness)(harnessInput)
|
|
206
|
+
const decodedScope = Schema.decodeUnknownOption(InitScope)(scopeInput)
|
|
207
|
+
if (Option.isNone(decodedHarness) || Option.isNone(decodedScope)) {
|
|
208
|
+
yield* emitError('invalid_arguments', INVALID_ARGUMENTS_MESSAGE, true, 2)
|
|
209
|
+
return
|
|
210
|
+
}
|
|
211
|
+
const request = new StatusRequest({
|
|
212
|
+
harness: decodedHarness.value,
|
|
213
|
+
scope: decodedScope.value,
|
|
214
|
+
})
|
|
215
|
+
yield* runStatusService(request, false)
|
|
216
|
+
})
|
|
217
|
+
|
|
218
|
+
const description = 'Inspect redacted local Expand onboarding status'
|
|
219
|
+
|
|
220
|
+
export const HumanStatusCommand = Command.make('status', config).pipe(
|
|
221
|
+
Command.withDescription(description),
|
|
222
|
+
Command.withHandler(runHumanStatus),
|
|
223
|
+
)
|
|
224
|
+
|
|
225
|
+
export const AgentStatusCommand = Command.make('status', config).pipe(
|
|
226
|
+
Command.withDescription(description),
|
|
227
|
+
Command.withHandler(runMachineStatus),
|
|
228
|
+
)
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { Command } from '@effect/cli'
|
|
2
|
+
import { Console, Effect } from 'effect'
|
|
3
|
+
import { ConfigManager } from '../Config.js'
|
|
4
|
+
import { Telemetry } from '../Telemetry.js'
|
|
5
|
+
|
|
6
|
+
const setEnabled = Effect.fnUntraced(function* (enabled: boolean) {
|
|
7
|
+
const configManager = yield* ConfigManager
|
|
8
|
+
const { config } = yield* configManager.readConfigFile()
|
|
9
|
+
// updateConfig fails with ConfigParseError on an undecodable file — surfaced
|
|
10
|
+
// to the user rather than overwriting whatever the file held.
|
|
11
|
+
yield* configManager.updateConfig({ telemetry: { ...config.telemetry, enabled } })
|
|
12
|
+
yield* Console.log(`Telemetry ${enabled ? 'enabled' : 'disabled'}.`)
|
|
13
|
+
})
|
|
14
|
+
|
|
15
|
+
const showStatus = Effect.fnUntraced(function* () {
|
|
16
|
+
const telemetry = yield* Telemetry
|
|
17
|
+
yield* Console.log(
|
|
18
|
+
telemetry.enabled
|
|
19
|
+
? 'Telemetry is enabled. Disable with `expandai telemetry disable` or EXPANDAI_NO_TELEMETRY=1.'
|
|
20
|
+
: 'Telemetry is disabled.',
|
|
21
|
+
)
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
const StatusCommand = Command.make('status').pipe(
|
|
25
|
+
Command.withDescription('Show whether anonymous usage telemetry is enabled'),
|
|
26
|
+
Command.withHandler(() => showStatus()),
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
const EnableCommand = Command.make('enable').pipe(
|
|
30
|
+
Command.withDescription('Enable anonymous usage telemetry'),
|
|
31
|
+
Command.withHandler(() => setEnabled(true)),
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
const DisableCommand = Command.make('disable').pipe(
|
|
35
|
+
Command.withDescription('Disable anonymous usage telemetry'),
|
|
36
|
+
Command.withHandler(() => setEnabled(false)),
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
export const TelemetryCommand = Command.make('telemetry').pipe(
|
|
40
|
+
Command.withDescription('Manage anonymous usage telemetry'),
|
|
41
|
+
Command.withSubcommands([StatusCommand, EnableCommand, DisableCommand]),
|
|
42
|
+
)
|