mirror of
https://github.com/stablyai/orca.git
synced 2026-09-22 16:02:32 +00:00
* refactor(cli): split runtime-client.ts into runtime/ subsystem
Break the 413-line src/cli/runtime-client.ts into focused modules under
src/cli/runtime/:
- types.ts — RuntimeRpcSuccess/Failure, RuntimeClientError,
RuntimeRpcFailureError
- metadata.ts — readMetadata / tryReadMetadata /
getDefaultUserDataPath
- transport.ts — sendRequest: Unix-socket newline-framed JSON with
id and runtimeId verification and timeout handling
- status.ts — getCliStatus + buildCliStatusResponse +
isProcessRunning
- launch.ts — launchOrcaApp + macOS .app-bundle resolution +
ELECTRON_RUN_AS_NODE env handling
- client.ts — RuntimeClient class, now a thin composer
- index.ts — subsystem barrel
runtime-client.ts becomes a backward-compat re-export barrel so
src/cli/index.ts and the existing tests import the same symbols from
the same path. No behavior changes.
Motivation: the file had an eslint-disable max-lines override and
mixed five concerns (envelope types, wire transport, metadata I/O,
status aggregation, cross-platform app launch). Splitting them makes
each concern independently testable and unblocks adding schema
validation at the RPC boundary.
* feat(cli): validate runtime RPC envelope with Zod at decode boundary
Add RuntimeRpcEnvelopeSchema and apply it inside sendRequest so every
response frame is validated against the id/ok/result/error/_meta shape
before the CLI hands it to the caller. The payload (`result`) is left
as unknown — the TResult generic remains the caller's responsibility —
so only the envelope itself is the contract this schema enforces.
Motivation: the CLI and the Orca main runtime are separate processes
and can drift in version (older CLI vs newer app, or vice versa during
dev HMR). A malformed or partial frame used to risk mis-typed field
access downstream; it now surfaces as a single structured
`invalid_runtime_response` error.
Behavior:
- Well-formed success and failure frames continue to decode unchanged.
- Failure frames without `_meta` are accepted (the runtime may fail
before resolving its own runtimeId).
- Valid JSON that does not match the envelope shape now rejects with
`invalid_runtime_response`, matching the existing error code for
non-JSON frames.
Tests: adds a pure schema test file
(src/cli/runtime/envelope-schema.test.ts) covering accept/reject cases.
The existing integration tests in runtime-client.test.ts continue to
pass unchanged.
67 lines
2.3 KiB
TypeScript
67 lines
2.3 KiB
TypeScript
import { homedir } from 'os'
|
|
import { join } from 'path'
|
|
import { readFileSync } from 'fs'
|
|
import { getRuntimeMetadataPath, type RuntimeMetadata } from '../../shared/runtime-bootstrap'
|
|
import { RuntimeClientError } from './types'
|
|
|
|
export function readMetadata(userDataPath: string): RuntimeMetadata {
|
|
const metadataPath = getRuntimeMetadataPath(userDataPath)
|
|
try {
|
|
const metadata = JSON.parse(readFileSync(metadataPath, 'utf8')) as RuntimeMetadata | null
|
|
if (!metadata?.transport || !metadata.authToken) {
|
|
throw new RuntimeClientError(
|
|
'runtime_unavailable',
|
|
`Orca runtime metadata is incomplete at ${metadataPath}`
|
|
)
|
|
}
|
|
return metadata
|
|
} catch (error) {
|
|
if (error instanceof RuntimeClientError) {
|
|
throw error
|
|
}
|
|
throw new RuntimeClientError(
|
|
'runtime_unavailable',
|
|
`Could not read Orca runtime metadata at ${metadataPath}. Start the Orca app first.`
|
|
)
|
|
}
|
|
}
|
|
|
|
export function tryReadMetadata(userDataPath: string): RuntimeMetadata | null {
|
|
const metadataPath = getRuntimeMetadataPath(userDataPath)
|
|
try {
|
|
return JSON.parse(readFileSync(metadataPath, 'utf8')) as RuntimeMetadata | null
|
|
} catch {
|
|
return null
|
|
}
|
|
}
|
|
|
|
export function getDefaultUserDataPath(
|
|
platform: NodeJS.Platform = process.platform,
|
|
homeDir = homedir()
|
|
): string {
|
|
// Why: in dev mode (and for parallel Orca instances), the Electron app writes
|
|
// runtime metadata to a separate userData directory (e.g. `orca-dev`) to avoid
|
|
// clobbering the production app's metadata. The CLI needs to find the same
|
|
// metadata file, so this env var lets the CLI target a specific instance.
|
|
if (process.env.ORCA_USER_DATA_PATH) {
|
|
return process.env.ORCA_USER_DATA_PATH
|
|
}
|
|
if (platform === 'darwin') {
|
|
return join(homeDir, 'Library', 'Application Support', 'orca')
|
|
}
|
|
if (platform === 'win32') {
|
|
const appData = process.env.APPDATA
|
|
if (!appData) {
|
|
throw new RuntimeClientError(
|
|
'runtime_unavailable',
|
|
'APPDATA is not set, so the Orca runtime metadata path cannot be resolved.'
|
|
)
|
|
}
|
|
return join(appData, 'orca')
|
|
}
|
|
// Why: the CLI must find the same metadata file Electron writes in packaged
|
|
// runs, so this mirrors Electron's default userData base instead of inventing
|
|
// a CLI-specific config path.
|
|
return join(process.env.XDG_CONFIG_HOME || join(homeDir, '.config'), 'orca')
|
|
}
|