mirror of
https://github.com/stablyai/orca.git
synced 2026-10-30 16:47:34 +00:00
fix(orcad): ship computer use with the server and say when it is unavailable (#31958)
* fix(orcad): ship computer use with the server and say when it is unavailable * test(computer): drop the type assertion in the sidecar app-environment mock * fix(cli): carry the server reprovision hint into --json computer failures
This commit is contained in:
@@ -10,7 +10,7 @@ export const MAIN_BUILD_ENTRY_POINTS: Record<string, string> = {
|
||||
'doc-preview-link-preload': resolve('src/preload/doc-preview-link.ts'),
|
||||
'daemon-entry': resolve('src/main/daemon/daemon-entry.ts'),
|
||||
'plugin-host-entry': resolve('src/main/plugins/plugin-host-entry.ts'),
|
||||
'computer-sidecar': resolve('src/main/computer/sidecar-entry.ts'),
|
||||
'computer-sidecar': resolve('src/main/computer/computer-sidecar.ts'),
|
||||
'stt-worker': resolve('src/main/speech/stt-worker.ts'),
|
||||
'warp-theme-parser-worker': resolve('src/main/warp-themes/warp-theme-parser-worker.ts'),
|
||||
'foreign-sqlite-reader-entry': resolve(
|
||||
|
||||
+1
-1
@@ -6,7 +6,7 @@
|
||||
"src/preload/browser-window-close.ts",
|
||||
"src/main/daemon/daemon-entry.ts",
|
||||
"src/main/plugins/plugin-host-entry.ts",
|
||||
"src/main/computer/sidecar-entry.ts",
|
||||
"src/main/computer/computer-sidecar.ts",
|
||||
"src/main/speech/stt-worker.ts",
|
||||
"src/main/warp-themes/warp-theme-parser-worker.ts",
|
||||
"src/main/foreign-sqlite-readers/foreign-sqlite-reader-entry.ts",
|
||||
|
||||
@@ -40,6 +40,7 @@ import {
|
||||
ORCAD_EMOJI_SHORTCODE_DATASET,
|
||||
ORCAD_CLI_ENTRY_FILENAME,
|
||||
ORCAD_CLI_PACKAGE_FILENAME,
|
||||
ORCAD_COMPUTER_USE_RUNTIME_ARTIFACTS,
|
||||
ORCAD_LAUNCHER_FILENAME,
|
||||
ORCAD_SERVER_ENTRY_FILENAME,
|
||||
ORCAD_NODE_PTY_DIR,
|
||||
@@ -210,6 +211,10 @@ cpSync(join(ROOT, 'resources', 'licenses', 'ripgrep'), join(OUT_DIR, 'ripgrep',
|
||||
cpSync(join(ROOT, 'resources', 'native-chat-visuals'), join(OUT_DIR, 'native-chat-visuals'), {
|
||||
recursive: true
|
||||
})
|
||||
for (const artifact of ORCAD_COMPUTER_USE_RUNTIME_ARTIFACTS) {
|
||||
mkdirSync(dirname(join(OUT_DIR, artifact)), { recursive: true })
|
||||
copyFileSync(join(ROOT, 'native', ...artifact.split('/')), join(OUT_DIR, ...artifact.split('/')))
|
||||
}
|
||||
stageOrcadMobileWebBundle(OUT_DIR)
|
||||
|
||||
/** Why one call per child and not one `outdir` build: esbuild mirrors each entry's source
|
||||
|
||||
@@ -21,7 +21,8 @@ export const ORCAD_CHILD_ENTRY_POINTS = {
|
||||
workerThreadChildProcess:
|
||||
'src/main/worker-thread-child-process/worker-thread-child-process-entry.ts',
|
||||
claudeProfileSetup: 'src/main/claude-accounts/claude-profile-setup-worker-entry.ts',
|
||||
sttWorker: 'src/main/speech/stt-worker.ts'
|
||||
sttWorker: 'src/main/speech/stt-worker.ts',
|
||||
computerSidecar: 'src/main/computer/computer-sidecar.ts'
|
||||
}
|
||||
|
||||
/** Each child ships flat beside orcad.js under its source basename; the runtime resolvers look there. */
|
||||
|
||||
@@ -18,9 +18,14 @@ import time
|
||||
import uuid
|
||||
from dataclasses import dataclass
|
||||
|
||||
import gi
|
||||
try:
|
||||
import gi
|
||||
|
||||
gi.require_version("Atspi", "2.0")
|
||||
gi.require_version("Atspi", "2.0")
|
||||
except (ImportError, ValueError) as error:
|
||||
# Why name it: PATH often puts a pyenv/Nix python3 without gi ahead of the system one.
|
||||
sys.stderr.write(f"PyGObject unavailable in interpreter: {sys.executable}\n{error}\n")
|
||||
sys.exit(1)
|
||||
try:
|
||||
gi.require_version("Gdk", "3.0")
|
||||
gi.require_version("GdkPixbuf", "2.0")
|
||||
|
||||
+25
-1
@@ -84,6 +84,10 @@ export function formatCliError(error: unknown, context: CliErrorContext = {}): s
|
||||
if (conflict) {
|
||||
return formatMessageWithNextSteps(stripAutomationOwnerConflictCode(message), conflict.nextSteps)
|
||||
}
|
||||
const sidecarExit = computerSidecarExitRecovery(error, context)
|
||||
if (sidecarExit) {
|
||||
return formatMessageWithNextSteps(message, sidecarExit.nextSteps)
|
||||
}
|
||||
if (error instanceof RuntimeClientError) {
|
||||
const nextSteps = nextStepsFromData(error.data)
|
||||
if (nextSteps.length > 0) {
|
||||
@@ -120,7 +124,10 @@ export function reportCliError(error: unknown, json: boolean, context: CliErrorC
|
||||
const selector = contextRecovery(errorCode(error), context)
|
||||
if (json) {
|
||||
if (error instanceof RuntimeRpcFailureError) {
|
||||
const response = withAutomationOwnerConflictRecovery(error.response)
|
||||
const sidecarExit = computerSidecarExitRecovery(error, context)
|
||||
const response = sidecarExit
|
||||
? { ...error.response, error: { ...error.response.error, data: sidecarExit } }
|
||||
: withAutomationOwnerConflictRecovery(error.response)
|
||||
console.log(
|
||||
JSON.stringify(
|
||||
selector
|
||||
@@ -217,7 +224,24 @@ function nextStepsFromData(data: unknown): string[] {
|
||||
return []
|
||||
}
|
||||
|
||||
/** Read here, not from the error's data: the servers that send this predate the hint (#31777). */
|
||||
function computerSidecarExitRecovery(error: unknown, context: CliErrorContext) {
|
||||
if (
|
||||
context.commandPath?.[0] !== 'computer' ||
|
||||
errorCode(error) !== 'accessibility_error' ||
|
||||
!(error instanceof Error) ||
|
||||
!error.message.startsWith('computer sidecar exited with code')
|
||||
) {
|
||||
return undefined
|
||||
}
|
||||
return computerUseErrorRecoveryData('accessibility_error', error.message)
|
||||
}
|
||||
|
||||
function localCliErrorData(error: unknown, context: CliErrorContext): unknown {
|
||||
const sidecarExit = computerSidecarExitRecovery(error, context)
|
||||
if (sidecarExit) {
|
||||
return sidecarExit
|
||||
}
|
||||
const selector = contextRecovery(errorCode(error), context)
|
||||
// Why: error-specific recovery must win over the generic computer fallback.
|
||||
if (error instanceof RuntimeClientError && error.data !== undefined) {
|
||||
|
||||
@@ -217,6 +217,41 @@ describe('CLI error recovery', () => {
|
||||
expect(output).toContain('Fix the command flags or RPC params')
|
||||
})
|
||||
|
||||
it('tells an older server to reprovision when its computer sidecar is missing', () => {
|
||||
// An older orcad answers with the generic provider steps, which never name the server install.
|
||||
const error = new RuntimeRpcFailureError({
|
||||
id: 'req_sidecar_exit',
|
||||
ok: false,
|
||||
error: {
|
||||
code: 'accessibility_error',
|
||||
message: 'computer sidecar exited with code 1',
|
||||
data: {
|
||||
nextSteps: [
|
||||
'Run `orca computer capabilities --json` to confirm the provider is available before retrying.'
|
||||
]
|
||||
}
|
||||
},
|
||||
_meta: { runtimeId: 'runtime_orcad' }
|
||||
})
|
||||
|
||||
const output = formatCliError(error, { commandPath: ['computer', 'list-apps'] })
|
||||
expect(output).toContain('update or reprovision the server')
|
||||
|
||||
const log = vi.spyOn(console, 'log').mockImplementation(() => {})
|
||||
reportCliError(error, true, { commandPath: ['computer', 'list-apps'] })
|
||||
expect(JSON.parse(String(log.mock.calls[0]?.[0]))).toMatchObject({
|
||||
error: {
|
||||
code: 'accessibility_error',
|
||||
data: {
|
||||
nextSteps: expect.arrayContaining([
|
||||
expect.stringContaining('update or reprovision the server')
|
||||
])
|
||||
}
|
||||
}
|
||||
})
|
||||
log.mockRestore()
|
||||
})
|
||||
|
||||
it('does not replace mutation recovery with generic runtime startup advice', () => {
|
||||
const error = new RuntimeClientError(
|
||||
'runtime_unavailable',
|
||||
|
||||
@@ -11,6 +11,13 @@ describe('computerProviderUnavailableMessage', () => {
|
||||
)
|
||||
})
|
||||
|
||||
it('names the runtime file a Linux or Windows install is missing', () => {
|
||||
expect(computerProviderUnavailableMessage('linux')).toContain('computer-use-linux/runtime.py')
|
||||
expect(computerProviderUnavailableMessage('win32')).toContain(
|
||||
'computer-use-windows/runtime.ps1'
|
||||
)
|
||||
})
|
||||
|
||||
it('keeps unsupported platforms explicit', () => {
|
||||
expect(computerProviderUnavailableMessage('freebsd')).toBe(
|
||||
'computer-use has no native provider for freebsd'
|
||||
|
||||
@@ -6,7 +6,9 @@ export function computerProviderUnavailableMessage(platform: NodeJS.Platform): s
|
||||
].join(' ')
|
||||
}
|
||||
if (platform === 'linux' || platform === 'win32') {
|
||||
return `computer-use has no native provider for ${platform}; the platform runtime file was not found`
|
||||
const runtime =
|
||||
platform === 'linux' ? 'computer-use-linux/runtime.py' : 'computer-use-windows/runtime.ps1'
|
||||
return `Computer use isn't available on this host: its Orca install has no ${runtime}. On an Orca server installed before computer use shipped with it, update or reprovision the server.`
|
||||
}
|
||||
return `computer-use has no native provider for ${platform}`
|
||||
}
|
||||
|
||||
@@ -18,4 +18,18 @@ describe('mapBridgeError', () => {
|
||||
expect(mapBridgeError('unknown element_index').code).toBe('element_not_found')
|
||||
expect(mapBridgeError('element metadata unavailable').code).toBe('accessibility_error')
|
||||
})
|
||||
|
||||
it('names the python3 that could not load PyGObject', () => {
|
||||
const error = mapBridgeError(
|
||||
"PyGObject unavailable in interpreter: /home/me/.pyenv/shims/python3\nNo module named 'gi'"
|
||||
)
|
||||
expect(error.code).toBe('unsupported_capability')
|
||||
expect(error.message).toContain('(/home/me/.pyenv/shims/python3)')
|
||||
})
|
||||
|
||||
it('says computer use is unavailable when no python3 is on PATH', () => {
|
||||
const error = mapBridgeError('spawn python3 ENOENT')
|
||||
expect(error.code).toBe('unsupported_capability')
|
||||
expect(error.message).toContain("Computer use isn't available on this host")
|
||||
})
|
||||
})
|
||||
|
||||
@@ -195,9 +195,18 @@ export function mapBridgeError(message: string): RuntimeClientError {
|
||||
return new RuntimeClientError('invalid_argument', text)
|
||||
}
|
||||
if (/ModuleNotFoundError: No module named 'gi'|PyGObject|python3-gi/i.test(text)) {
|
||||
const interpreter = /PyGObject unavailable in interpreter: (.+)/.exec(text)?.[1]?.trim()
|
||||
return new RuntimeClientError(
|
||||
'unsupported_capability',
|
||||
'Linux Computer Use requires python3-gi and AT-SPI packages. Install python3-gi gir1.2-atspi-2.0 at-spi2-core, then retry.'
|
||||
interpreter
|
||||
? `Linux Computer Use requires python3-gi and AT-SPI packages, which the python3 it ran (${interpreter}) cannot load. Install python3-gi gir1.2-atspi-2.0 at-spi2-core for that interpreter, or put a python3 that has them (usually /usr/bin/python3) first on PATH, then retry.`
|
||||
: 'Linux Computer Use requires python3-gi and AT-SPI packages. Install python3-gi gir1.2-atspi-2.0 at-spi2-core, then retry.'
|
||||
)
|
||||
}
|
||||
if (/spawn python3 ENOENT/.test(text)) {
|
||||
return new RuntimeClientError(
|
||||
'unsupported_capability',
|
||||
"Computer use isn't available on this host: Linux Computer Use runs python3, and none is on PATH. Install python3 with python3-gi gir1.2-atspi-2.0 at-spi2-core, then retry."
|
||||
)
|
||||
}
|
||||
if (/not a valid secondary action|action.*not supported/i.test(text)) {
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
import type * as NodeFs from 'node:fs'
|
||||
import { join } from 'node:path'
|
||||
import { afterEach, describe, expect, it, vi } from 'vitest'
|
||||
|
||||
const { existsSyncMock } = vi.hoisted(() => ({ existsSyncMock: vi.fn((_path: string) => false) }))
|
||||
|
||||
vi.mock('node:fs', async (importOriginal) => ({
|
||||
...(await importOriginal<typeof NodeFs>()),
|
||||
existsSync: existsSyncMock
|
||||
}))
|
||||
|
||||
import { resolveDesktopScriptProviderPath } from './desktop-script-provider-paths'
|
||||
|
||||
describe('resolveDesktopScriptProviderPath', () => {
|
||||
afterEach(() => {
|
||||
existsSyncMock.mockReset()
|
||||
})
|
||||
|
||||
it('finds the runtime orcad ships beside its sidecar when there is no resourcesPath', () => {
|
||||
// orcad's sidecar bundle is flat at the install root, so its runtimes sit beside it.
|
||||
const bundled = join(__dirname, 'computer-use-linux', 'runtime.py')
|
||||
existsSyncMock.mockImplementation((path) => path === bundled)
|
||||
|
||||
expect(resolveDesktopScriptProviderPath('linux')).toBe(bundled)
|
||||
})
|
||||
})
|
||||
@@ -29,11 +29,13 @@ export function resolveDesktopScriptProviderPath(
|
||||
const sourceDirectory =
|
||||
platform === 'windows' ? 'native/computer-use-windows' : 'native/computer-use-linux'
|
||||
const packaged = [join(process.resourcesPath ?? '', directory, filename)]
|
||||
// orcad has no resourcesPath; its bundled sidecar (this module's __dirname) holds the runtimes.
|
||||
const bundled = join(__dirname, directory, filename)
|
||||
const dev = [
|
||||
join(process.cwd(), sourceDirectory, filename),
|
||||
resolve(__dirname, '../../', sourceDirectory, filename)
|
||||
]
|
||||
const candidates = process.resourcesPath ? [...packaged, ...dev] : dev
|
||||
const candidates = process.resourcesPath ? [...packaged, bundled, ...dev] : [bundled, ...dev]
|
||||
|
||||
return candidates.find((candidate) => candidate && existsSync(candidate)) ?? null
|
||||
}
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import type * as NodeFs from 'node:fs'
|
||||
import { EventEmitter } from 'node:events'
|
||||
import { join } from 'node:path'
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
import {
|
||||
CLIPBOARD_TEXT_MEASURE_YIELD_CODE_UNITS,
|
||||
@@ -11,14 +13,31 @@ import {
|
||||
resetComputerSidecarForTest
|
||||
} from './sidecar-client'
|
||||
|
||||
const { forkMock } = vi.hoisted(() => ({
|
||||
forkMock: vi.fn()
|
||||
}))
|
||||
type TestAppEnvironment = { getAppPath(): string; isPackaged(): boolean }
|
||||
|
||||
const { forkMock, existsSyncMock, appEnvironment } = vi.hoisted(() => {
|
||||
const environment: { current: TestAppEnvironment | null } = { current: null }
|
||||
return {
|
||||
forkMock: vi.fn(),
|
||||
existsSyncMock: vi.fn((_path: string) => true),
|
||||
appEnvironment: environment
|
||||
}
|
||||
})
|
||||
|
||||
vi.mock('child_process', () => ({
|
||||
fork: forkMock
|
||||
}))
|
||||
|
||||
vi.mock('node:fs', async (importOriginal) => ({
|
||||
...(await importOriginal<typeof NodeFs>()),
|
||||
existsSync: existsSyncMock
|
||||
}))
|
||||
|
||||
vi.mock('../../shared/app-environment', () => ({
|
||||
hasAppEnvironment: () => appEnvironment.current !== null,
|
||||
getAppEnvironment: () => appEnvironment.current
|
||||
}))
|
||||
|
||||
type SentRequest = {
|
||||
id: number
|
||||
method: string
|
||||
@@ -72,9 +91,37 @@ describe('computer sidecar client', () => {
|
||||
afterEach(() => {
|
||||
resetComputerSidecarForTest()
|
||||
forkMock.mockReset()
|
||||
existsSyncMock.mockImplementation(() => true)
|
||||
appEnvironment.current = null
|
||||
vi.useRealTimers()
|
||||
})
|
||||
|
||||
it('forks the sidecar orcad ships beside orcad.js, not a desktop out/main path', async () => {
|
||||
appEnvironment.current = { getAppPath: () => '/srv/orcad', isPackaged: () => true }
|
||||
existsSyncMock.mockImplementation((path) => path === join('/srv/orcad', 'computer-sidecar.js'))
|
||||
|
||||
const call = callComputerSidecarCapabilities()
|
||||
children[0]!.emit('message', { id: children[0]!.sent[0]!.id, ok: true, result: {} })
|
||||
|
||||
await expect(call).resolves.toEqual({})
|
||||
expect(forkMock).toHaveBeenCalledWith(
|
||||
join('/srv/orcad', 'computer-sidecar.js'),
|
||||
[],
|
||||
expect.anything()
|
||||
)
|
||||
})
|
||||
|
||||
it('says computer use is unavailable when an older server install has no sidecar', async () => {
|
||||
appEnvironment.current = { getAppPath: () => '/srv/orcad', isPackaged: () => true }
|
||||
existsSyncMock.mockImplementation(() => false)
|
||||
|
||||
await expect(callComputerSidecarCapabilities()).rejects.toMatchObject({
|
||||
code: 'unsupported_capability',
|
||||
message: expect.stringContaining("Computer use isn't available on this host")
|
||||
})
|
||||
expect(forkMock).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('ignores stale child exit and error after a replacement sidecar starts', async () => {
|
||||
const firstCall = callComputerSidecarCapabilities()
|
||||
const firstRejection = expect(firstCall).rejects.toThrow(
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { fork, type ChildProcess } from 'node:child_process'
|
||||
import { getAppEnvironment, hasAppEnvironment } from '../../shared/app-environment'
|
||||
import { join } from 'node:path'
|
||||
import { existsSync } from 'node:fs'
|
||||
import type {
|
||||
ComputerActionResult,
|
||||
ComputerListAppsResult,
|
||||
@@ -12,6 +11,10 @@ import { normalizeComputerActionResult } from './computer-action-verification-no
|
||||
import { isComputerSidecarDiagnostic, logComputerDiagnostic } from './computer-sidecar-diagnostics'
|
||||
import { validateComputerSidecarPasteText } from './computer-sidecar-paste-validation'
|
||||
import { RuntimeClientError } from './runtime-client-error'
|
||||
import { getForkedChildEntryPath } from '../forked-child-entry-path'
|
||||
|
||||
// orcad ships it beside orcad.js (ORCAD_CHILD_ENTRY_POINTS); the desktop under out/main.
|
||||
export const COMPUTER_SIDECAR_ENTRY_FILENAME = 'computer-sidecar.js'
|
||||
|
||||
type ComputerSidecarMethod =
|
||||
| 'capabilities'
|
||||
@@ -94,30 +97,13 @@ export function resetComputerSidecarForTest(): void {
|
||||
|
||||
function getComputerSidecar(): ComputerSidecarProcess {
|
||||
if (!sidecar) {
|
||||
sidecar = new ComputerSidecarProcess(getComputerSidecarEntryPath())
|
||||
sidecar = new ComputerSidecarProcess(getForkedChildEntryPath(COMPUTER_SIDECAR_ENTRY_FILENAME))
|
||||
}
|
||||
return sidecar
|
||||
}
|
||||
|
||||
function getComputerSidecarEntryPath(): string {
|
||||
const app = loadElectronApp()
|
||||
const appPath = app?.getAppPath() ?? process.cwd()
|
||||
const isPackaged = app?.isPackaged ?? false
|
||||
// Why: packaged sidecars must be forked from app.asar.unpacked because
|
||||
// ELECTRON_RUN_AS_NODE bypasses Electron's asar require integration.
|
||||
const basePath = isPackaged ? appPath.replace('app.asar', 'app.asar.unpacked') : appPath
|
||||
return join(basePath, 'out', 'main', 'computer-sidecar.js')
|
||||
}
|
||||
|
||||
// Why the port and not require('electron'): the literal text fails the plain-Node
|
||||
// entry guard even inside a try/catch, and hasAppEnvironment() gives the same
|
||||
// "no app root here" answer without it.
|
||||
function loadElectronApp(): { getAppPath(): string; isPackaged: boolean } | null {
|
||||
if (!hasAppEnvironment()) {
|
||||
return null
|
||||
}
|
||||
const environment = getAppEnvironment()
|
||||
return { getAppPath: () => environment.getAppPath(), isPackaged: environment.isPackaged() }
|
||||
export function computerSidecarMissingMessage(entryPath: string): string {
|
||||
return `Computer use isn't available on this host: its Orca install has no computer-use sidecar (${entryPath}). On an Orca server installed before computer use shipped with it, update or reprovision the server.`
|
||||
}
|
||||
|
||||
class ComputerSidecarProcess {
|
||||
@@ -211,6 +197,13 @@ class ComputerSidecarProcess {
|
||||
}
|
||||
this.cleanupActiveChildListeners()
|
||||
this.child = null
|
||||
// Why before fork: a missing entry only surfaces as "exited with code 1", which names nothing.
|
||||
if (!existsSync(this.entryPath)) {
|
||||
throw new RuntimeClientError(
|
||||
'unsupported_capability',
|
||||
computerSidecarMissingMessage(this.entryPath)
|
||||
)
|
||||
}
|
||||
|
||||
const child = fork(this.entryPath, [], {
|
||||
stdio: ['ignore', 'pipe', 'pipe', 'ipc'],
|
||||
|
||||
@@ -14,7 +14,7 @@ describe.skipIf(process.platform === 'win32')('real sidecar exit reaping', () =>
|
||||
directory = await mkdtemp(join(tmpdir(), 'orca-sidecar-reaping-'))
|
||||
entry = join(directory, 'sidecar.cjs')
|
||||
await build({
|
||||
entryPoints: [join(__dirname, 'sidecar-entry.ts')],
|
||||
entryPoints: [join(__dirname, 'computer-sidecar.ts')],
|
||||
outfile: entry,
|
||||
bundle: true,
|
||||
platform: 'node',
|
||||
|
||||
@@ -92,6 +92,13 @@ export function computerUseErrorRecoveryData(
|
||||
'If the message mentions the payload cap, target a smaller/current window or use `--no-screenshot`.'
|
||||
)
|
||||
case 'accessibility_error':
|
||||
// Why: an Orca server installed before it bundled computer use reports only this exit (#31777).
|
||||
if (message?.startsWith('computer sidecar exited with code')) {
|
||||
return recoverWith(
|
||||
'If this targets an Orca server (`orca serve`, SSH or WSL), its install may not include computer use: update or reprovision the server, then retry.',
|
||||
'Run `orca computer capabilities --json` to confirm the provider is available before retrying.'
|
||||
)
|
||||
}
|
||||
return recoverWith(
|
||||
'Run `orca computer capabilities --json` to confirm the provider is available before retrying.',
|
||||
'If the message mentions permissions, run `orca computer permissions --id accessibility --json` and grant access.',
|
||||
|
||||
@@ -120,6 +120,13 @@ export const ORCAD_FOREIGN_SQLITE_READER_ENTRY = 'foreign-sqlite-reader-entry.js
|
||||
export const ORCAD_PORT_SCAN_COMMAND_WORKER_ENTRY = 'port-scan-command-worker-entry.js'
|
||||
// Equals AI_VAULT_SERVICE_ENTRY_FILENAME: the forked child that lists agent sessions.
|
||||
export const ORCAD_SESSION_SCANNER_SERVICE_ENTRY = 'session-scanner-service-entry.js'
|
||||
// Equals COMPUTER_SIDECAR_ENTRY_FILENAME, and the desktop's out/main entry name.
|
||||
export const ORCAD_COMPUTER_SIDECAR_ENTRY = 'computer-sidecar.js'
|
||||
/** Plain scripts, one copy for every target: each platform's sidecar runs only its own. */
|
||||
export const ORCAD_COMPUTER_USE_RUNTIME_ARTIFACTS = [
|
||||
'computer-use-linux/runtime.py',
|
||||
'computer-use-windows/runtime.ps1'
|
||||
] as const
|
||||
|
||||
// Kept here because build-orcad.mjs imports this manifest directly under Node type stripping.
|
||||
export const ORCAD_RIPGREP_ARTIFACTS = [
|
||||
@@ -248,6 +255,9 @@ export const ORCAD_ARTIFACTS: readonly OrcadArtifact[] = [
|
||||
{ filename: 'claude-profile-setup-worker-entry.js' },
|
||||
// Dictation's worker thread; it loads the recognizer `orca serve` names (#31174).
|
||||
{ filename: 'stt-worker.js' },
|
||||
// `orca computer` forks it; it finds the platform runtimes below beside itself (#31777).
|
||||
{ filename: ORCAD_COMPUTER_SIDECAR_ENTRY },
|
||||
...ORCAD_COMPUTER_USE_RUNTIME_ARTIFACTS.map((filename) => ({ filename })),
|
||||
// Target-specific even when the JavaScript bundle is shared across packaged slots.
|
||||
{ filename: ORCAD_SERVER_TARGET_FILENAME },
|
||||
// orcad never depends on a host runtime or host-installed native module.
|
||||
|
||||
Reference in New Issue
Block a user