mirror of
https://github.com/stablyai/orca.git
synced 2026-10-22 00:03:47 +00:00
fix(skills): preserve ssh failure categories
This commit is contained in:
@@ -20,13 +20,19 @@ export function skillInstallFailureFromError(error: unknown): SkillInstallFailur
|
||||
if (error instanceof SkillInstallOperationError) {
|
||||
return error.data
|
||||
}
|
||||
if (error && typeof error === 'object' && 'data' in error) {
|
||||
const parsed = SkillInstallFailureSchema.safeParse((error as { data: unknown }).data)
|
||||
if (parsed.success) {
|
||||
return parsed.data
|
||||
}
|
||||
}
|
||||
if (error instanceof Error) {
|
||||
const classified = classifySkillInstallFailureCode(error.message)
|
||||
if (classified) {
|
||||
return classified
|
||||
}
|
||||
const code = (error as NodeJS.ErrnoException).code
|
||||
if (code) {
|
||||
if (typeof code === 'string') {
|
||||
return {
|
||||
category: 'filesystem',
|
||||
code: 'skill-install-filesystem-failed',
|
||||
@@ -34,9 +40,5 @@ export function skillInstallFailureFromError(error: unknown): SkillInstallFailur
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!error || typeof error !== 'object' || !('data' in error)) {
|
||||
return null
|
||||
}
|
||||
const parsed = SkillInstallFailureSchema.safeParse((error as { data: unknown }).data)
|
||||
return parsed.success ? parsed.data : null
|
||||
return null
|
||||
}
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
import type { IPtyProvider } from '../providers/pty-provider-contract'
|
||||
import {
|
||||
SkillInstallFailureCategorySchema,
|
||||
type SkillInstallFailure
|
||||
} from '../../shared/skill-install-failure'
|
||||
import type { SkillInstallRequest } from '../../shared/skill-install-contract'
|
||||
|
||||
const mocks = vi.hoisted(() => ({ callRuntimeEnvironment: vi.fn() }))
|
||||
|
||||
vi.mock('../ipc/runtime-environment-transport-routing', () => ({
|
||||
callRuntimeEnvironment: mocks.callRuntimeEnvironment
|
||||
}))
|
||||
|
||||
import { skillInstallFailureFromError } from './skill-install-operation-error'
|
||||
import { installSkillOnRemoteRuntime } from './skill-remote-install-service'
|
||||
import { installSkillOnSshHost } from './skill-ssh-relay-service'
|
||||
|
||||
const request: SkillInstallRequest = {
|
||||
operationId: 'operation-1',
|
||||
package: {
|
||||
packageId: 'package-1',
|
||||
versionId: 'version-1',
|
||||
packageDigest: 'a'.repeat(64),
|
||||
archiveSha256: 'b'.repeat(64),
|
||||
compressedBytes: 12
|
||||
},
|
||||
ingress: {
|
||||
kind: 'download-grant',
|
||||
url: 'https://storage.googleapis.com/bucket/package.tar.gz',
|
||||
expiresAt: '2099-01-01T00:00:00.000Z'
|
||||
},
|
||||
destination: { scope: 'global' }
|
||||
}
|
||||
|
||||
const failures = SkillInstallFailureCategorySchema.options.map(
|
||||
(category, index): SkillInstallFailure => ({
|
||||
category,
|
||||
code: `skill-contract-${category}`,
|
||||
retryable: index % 2 === 0
|
||||
})
|
||||
)
|
||||
|
||||
async function capturedFailure(promise: Promise<unknown>): Promise<SkillInstallFailure | null> {
|
||||
try {
|
||||
await promise
|
||||
throw new Error('expected-skill-install-failure')
|
||||
} catch (error) {
|
||||
return skillInstallFailureFromError(error)
|
||||
}
|
||||
}
|
||||
|
||||
describe('remote skill failure category parity', () => {
|
||||
beforeEach(() => {
|
||||
mocks.callRuntimeEnvironment.mockReset()
|
||||
})
|
||||
|
||||
it.each(failures)('preserves $category across paired runtime and SSH', async (failure) => {
|
||||
mocks.callRuntimeEnvironment.mockResolvedValue({
|
||||
id: 'rpc-1',
|
||||
ok: false,
|
||||
error: { code: 'skill_install_failure', message: failure.code, data: failure },
|
||||
_meta: { runtimeId: 'runtime-1' }
|
||||
})
|
||||
const paired = await capturedFailure(
|
||||
installSkillOnRemoteRuntime({
|
||||
userDataPath: '/state',
|
||||
environmentId: 'environment-1',
|
||||
request,
|
||||
capabilities: ['skills.install.v1'],
|
||||
requireHttps: true
|
||||
})
|
||||
)
|
||||
|
||||
const requestHostRpc = vi.fn(async (method: string) => {
|
||||
if (method === 'relay.status') {
|
||||
return { capabilities: ['skills.install.v1'] }
|
||||
}
|
||||
throw Object.assign(new Error(failure.code), { code: -32000, data: failure })
|
||||
})
|
||||
const ssh = await capturedFailure(
|
||||
installSkillOnSshHost({
|
||||
provider: { requestHostRpc } as unknown as IPtyProvider,
|
||||
userDataPath: '/state',
|
||||
request,
|
||||
requireHttps: true
|
||||
})
|
||||
)
|
||||
|
||||
expect({ paired, ssh }).toEqual({ paired: failure, ssh: failure })
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user