mirror of
https://github.com/stablyai/orca.git
synced 2026-10-01 16:02:03 +00:00
Add read-only orca linear CLI with trusted launch-prompt pointer (V1) (#5126)
Co-authored-by: Orca <help@stably.ai>
This commit is contained in:
@@ -2,6 +2,12 @@ import type { CliStatusResult, RuntimeStatus } from '../../shared/runtime-types'
|
||||
import { RpcDispatcher } from '../runtime/rpc/dispatcher'
|
||||
import type { RpcResponse } from '../runtime/rpc/core'
|
||||
import type { OrcaRuntimeService } from '../runtime/orca-runtime'
|
||||
import { formatRemoteCli } from './ssh-remote-cli-format'
|
||||
import {
|
||||
RemoteCliArgumentError,
|
||||
getRemoteLinearHelp,
|
||||
tryDispatchRemoteLinearCli
|
||||
} from './ssh-remote-linear-cli'
|
||||
|
||||
export type RemoteOrcaCliRequest = {
|
||||
argv: string[]
|
||||
@@ -20,6 +26,21 @@ type ParsedRemoteCli = {
|
||||
flags: Map<string, string | boolean>
|
||||
}
|
||||
|
||||
const REMOTE_BOOLEAN_FLAGS = new Set([
|
||||
'all',
|
||||
'attachments',
|
||||
'children',
|
||||
'comments',
|
||||
'current',
|
||||
'full',
|
||||
'help',
|
||||
'inject',
|
||||
'json',
|
||||
'relations',
|
||||
'unread',
|
||||
'wait'
|
||||
])
|
||||
|
||||
export async function runRemoteOrcaCli(
|
||||
runtime: OrcaRuntimeService,
|
||||
request: RemoteOrcaCliRequest
|
||||
@@ -27,19 +48,34 @@ export async function runRemoteOrcaCli(
|
||||
const dispatcher = new RpcDispatcher({ runtime })
|
||||
const parsed = parseRemoteCliArgs(request.argv)
|
||||
const json = parsed.flags.has('json')
|
||||
const help = getRemoteLinearHelp(parsed)
|
||||
if (help) {
|
||||
return { stdout: `${help}\n`, stderr: '', exitCode: 0 }
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await dispatchRemoteCli(dispatcher, parsed, request.env)
|
||||
const formatted = json
|
||||
? { stdout: `${JSON.stringify(response, null, 2)}\n`, stderr: '' }
|
||||
: formatRemoteCli(response)
|
||||
return {
|
||||
stdout: json ? `${JSON.stringify(response, null, 2)}\n` : `${formatRemoteCli(response)}\n`,
|
||||
stderr: '',
|
||||
stdout: formatted.stdout,
|
||||
stderr: formatted.stderr,
|
||||
exitCode: response.ok ? 0 : 1
|
||||
}
|
||||
} catch (err) {
|
||||
const message = err instanceof Error ? err.message : String(err)
|
||||
const code =
|
||||
err instanceof RemoteCliArgumentError
|
||||
? err.code
|
||||
: err instanceof Error &&
|
||||
'code' in err &&
|
||||
typeof (err as { code: unknown }).code === 'string'
|
||||
? (err as { code: string }).code
|
||||
: 'runtime_error'
|
||||
if (json) {
|
||||
return {
|
||||
stdout: `${JSON.stringify(buildLocalError(message), null, 2)}\n`,
|
||||
stdout: `${JSON.stringify(buildLocalError(message, code), null, 2)}\n`,
|
||||
stderr: '',
|
||||
exitCode: 1
|
||||
}
|
||||
@@ -54,6 +90,10 @@ async function dispatchRemoteCli(
|
||||
env: Record<string, string>
|
||||
): Promise<RpcResponse> {
|
||||
const command = parsed.commandPath.join(' ')
|
||||
const linearResponse = await tryDispatchRemoteLinearCli(dispatcher, parsed, env)
|
||||
if (linearResponse) {
|
||||
return linearResponse
|
||||
}
|
||||
switch (command) {
|
||||
case 'status': {
|
||||
const response = await call(dispatcher, 'status.get')
|
||||
@@ -147,7 +187,7 @@ function parseRemoteCliArgs(argv: string[]): ParsedRemoteCli {
|
||||
|
||||
const flag = assignment
|
||||
const next = argv[i + 1]
|
||||
if (next && !next.startsWith('--')) {
|
||||
if (!REMOTE_BOOLEAN_FLAGS.has(flag) && next && !next.startsWith('--')) {
|
||||
flags.set(flag, next)
|
||||
i += 1
|
||||
} else {
|
||||
@@ -184,33 +224,17 @@ function optionalNumber(flags: Map<string, string | boolean>, name: string): num
|
||||
return undefined
|
||||
}
|
||||
const parsed = Number(value)
|
||||
return Number.isFinite(parsed) ? parsed : undefined
|
||||
if (!Number.isFinite(parsed)) {
|
||||
throw new RemoteCliArgumentError('invalid_argument', `Invalid numeric value for --${name}`)
|
||||
}
|
||||
return parsed
|
||||
}
|
||||
|
||||
function formatRemoteCli(response: RpcResponse): string {
|
||||
if (!response.ok) {
|
||||
return response.error.message
|
||||
}
|
||||
const result = response.result as Record<string, unknown>
|
||||
if ('app' in result && 'runtime' in result && 'graph' in result) {
|
||||
const status = result as CliStatusResult
|
||||
return [
|
||||
`appRunning: ${status.app.running}`,
|
||||
`pid: ${status.app.pid ?? 'none'}`,
|
||||
`runtimeState: ${status.runtime.state}`,
|
||||
`runtimeReachable: ${status.runtime.reachable}`,
|
||||
`runtimeId: ${status.runtime.runtimeId ?? 'none'}`,
|
||||
`graphState: ${status.graph.state}`
|
||||
].join('\n')
|
||||
}
|
||||
return JSON.stringify(response.result)
|
||||
}
|
||||
|
||||
function buildLocalError(message: string): RpcResponse {
|
||||
function buildLocalError(message: string, code = 'runtime_error'): RpcResponse {
|
||||
return {
|
||||
id: 'remote-cli-local',
|
||||
ok: false,
|
||||
error: { code: 'runtime_error', message },
|
||||
error: { code, message },
|
||||
_meta: { runtimeId: 'unknown' }
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user