mirror of
https://github.com/stablyai/orca.git
synced 2026-10-18 08:03:22 +00:00
Revert "fix(linear): migrate legacy skill installs"
This reverts commit 3ff45f9245.
This commit is contained in:
@@ -16,7 +16,8 @@ const UPDATE_COMMAND = 'npx skills update orca-linear --global'
|
||||
const mocks = vi.hoisted(() => ({
|
||||
panelProps: [] as Record<string, unknown>[],
|
||||
runtime: 'native' as 'native' | 'wsl',
|
||||
skillInstalled: true
|
||||
skillInstalled: true,
|
||||
updateSkillName: 'orca-linear'
|
||||
}))
|
||||
|
||||
vi.mock('./AgentSkillSetupPanel', () => ({
|
||||
@@ -40,6 +41,13 @@ vi.mock('./CliSkillRuntimeSetup', () => ({
|
||||
getWslCliDistroRequest: () => undefined
|
||||
}))
|
||||
|
||||
vi.mock('@/lib/linear-agent-skill-update-command', () => ({
|
||||
getLinearAgentSkillUpdateTarget: () => ({
|
||||
command: UPDATE_COMMAND,
|
||||
skillName: mocks.updateSkillName
|
||||
})
|
||||
}))
|
||||
|
||||
vi.mock('@/hooks/useInstalledAgentSkills', () => ({
|
||||
GLOBAL_AGENT_SKILL_SOURCE_KINDS: ['home'],
|
||||
useInstalledAgentSkillNames: () => ({
|
||||
@@ -86,6 +94,7 @@ describe('LinearAgentSkillPane', () => {
|
||||
mocks.panelProps.length = 0
|
||||
mocks.runtime = 'native'
|
||||
mocks.skillInstalled = true
|
||||
mocks.updateSkillName = 'orca-linear'
|
||||
})
|
||||
|
||||
it('renders the Linear skill card and the usage examples', () => {
|
||||
@@ -121,16 +130,10 @@ describe('LinearAgentSkillPane', () => {
|
||||
expect(mocks.panelProps.at(-1)?.freshnessSkillName).toBeUndefined()
|
||||
})
|
||||
|
||||
it('offers the canonical install when the accepted skill is missing', async () => {
|
||||
mocks.skillInstalled = false
|
||||
it('checks freshness under the legacy name when that is the installed update target', async () => {
|
||||
mocks.updateSkillName = 'linear-tickets'
|
||||
await renderPane()
|
||||
|
||||
expect(mocks.panelProps.at(-1)).toEqual(
|
||||
expect.objectContaining({
|
||||
installed: false,
|
||||
command: ORCA_LINEAR_SKILL_INSTALL_COMMAND,
|
||||
freshnessSkillName: ORCA_LINEAR_SKILL_NAME
|
||||
})
|
||||
)
|
||||
expect(mocks.panelProps.at(-1)?.freshnessSkillName).toBe('linear-tickets')
|
||||
})
|
||||
})
|
||||
|
||||
@@ -5,13 +5,13 @@ import { LinearIcon } from '@/components/icons/LinearIcon'
|
||||
import {
|
||||
LINEAR_AGENT_SKILL_NAMES,
|
||||
ORCA_LINEAR_SKILL_INSTALL_COMMAND,
|
||||
ORCA_LINEAR_SKILL_NAME,
|
||||
ORCA_LINEAR_SKILL_UPDATE_COMMAND
|
||||
ORCA_LINEAR_SKILL_NAME
|
||||
} from '@/lib/agent-feature-install-commands'
|
||||
import {
|
||||
AGENT_SKILL_CLI_PREREQUISITE_NOTICE,
|
||||
ensureOrcaCliAvailableForAgentSkillTerminal
|
||||
} from '@/lib/agent-skill-cli-prerequisite'
|
||||
import { getLinearAgentSkillUpdateTarget } from '@/lib/linear-agent-skill-update-command'
|
||||
import { getLinearUsageExamples } from '@/lib/linear-usage-examples'
|
||||
import type { SkillUsageExample } from '@/lib/skill-usage-example'
|
||||
import {
|
||||
@@ -52,6 +52,7 @@ export function LinearAgentSkillPane(): React.JSX.Element {
|
||||
installed: linearSkillInstalled,
|
||||
loading: linearSkillLoading,
|
||||
error: linearSkillError,
|
||||
skills: linearSkills,
|
||||
refresh: refreshLinearSkill
|
||||
} = useInstalledAgentSkillNames(LINEAR_AGENT_SKILL_NAMES, {
|
||||
discoveryTarget: activeSkillRuntime.discoveryTarget,
|
||||
@@ -68,14 +69,20 @@ export function LinearAgentSkillPane(): React.JSX.Element {
|
||||
),
|
||||
[activeSkillRuntime.agentRuntime, activeSkillRuntime.installDisabledReason]
|
||||
)
|
||||
const updateTarget = useMemo(
|
||||
() => getLinearAgentSkillUpdateTarget(linearSkills, linearSkillInstalled),
|
||||
[linearSkillInstalled, linearSkills]
|
||||
)
|
||||
const updateCommand = useMemo(() => {
|
||||
const command = updateTarget.command
|
||||
return activeSkillRuntime.installDisabledReason
|
||||
? ORCA_LINEAR_SKILL_UPDATE_COMMAND
|
||||
: buildSkillCommandForRuntime(
|
||||
ORCA_LINEAR_SKILL_UPDATE_COMMAND,
|
||||
activeSkillRuntime.agentRuntime
|
||||
)
|
||||
}, [activeSkillRuntime.agentRuntime, activeSkillRuntime.installDisabledReason])
|
||||
? command
|
||||
: buildSkillCommandForRuntime(command, activeSkillRuntime.agentRuntime)
|
||||
}, [
|
||||
activeSkillRuntime.agentRuntime,
|
||||
activeSkillRuntime.installDisabledReason,
|
||||
updateTarget.command
|
||||
])
|
||||
|
||||
return (
|
||||
<SearchableSetting
|
||||
@@ -130,7 +137,7 @@ export function LinearAgentSkillPane(): React.JSX.Element {
|
||||
// Why: the local-host-only freshness scan cannot vouch for a WSL runtime,
|
||||
// so fall back to the presence-only pill there (mirrors the other skills).
|
||||
freshnessSkillName={
|
||||
activeSkillRuntime.agentRuntime?.runtime === 'wsl' ? undefined : ORCA_LINEAR_SKILL_NAME
|
||||
activeSkillRuntime.agentRuntime?.runtime === 'wsl' ? undefined : updateTarget.skillName
|
||||
}
|
||||
/>
|
||||
|
||||
|
||||
@@ -24,10 +24,10 @@ const updateCapableCallers = new Map<string, readonly string[]>([
|
||||
['COMPUTER_USE_SKILL_UPDATE_COMMAND', 'installedCommand={updateCommand}']
|
||||
],
|
||||
[
|
||||
// Why: the Linear settings section must update only the canonical skill;
|
||||
// legacy-only discovery is treated as missing and follows the install path.
|
||||
// Why: the Linear settings section shares the update-target resolver so
|
||||
// legacy-only installs keep the command and freshness identity aligned.
|
||||
'src/renderer/src/components/settings/LinearAgentSkillPane.tsx',
|
||||
['ORCA_LINEAR_SKILL_UPDATE_COMMAND', 'installedCommand={updateCommand}']
|
||||
['getLinearAgentSkillUpdateTarget', 'installedCommand={updateCommand}']
|
||||
],
|
||||
[
|
||||
'src/renderer/src/components/settings/EphemeralVmsPane.tsx',
|
||||
@@ -50,8 +50,10 @@ const updateCapableCallers = new Map<string, readonly string[]>([
|
||||
['ORCA_CLI_SKILL_UPDATE_COMMAND', 'installedCommand={updateCommand}']
|
||||
],
|
||||
[
|
||||
// Why: the single-skill update command selection moved into
|
||||
// getLinearAgentSkillUpdateCommand so the settings install CTA shares it.
|
||||
'src/renderer/src/components/sidebar/LinearAgentSkillSetupPrompt.tsx',
|
||||
['ORCA_LINEAR_SKILL_UPDATE_COMMAND', 'installedCommand={installedCommand}']
|
||||
['getLinearAgentSkillUpdateCommand', 'installedCommand={installedCommand}']
|
||||
],
|
||||
[
|
||||
'src/renderer/src/components/sidebar/LinearAgentSkillSetupDialog.tsx',
|
||||
|
||||
@@ -146,8 +146,8 @@ describe('LinearAgentSkillInstallCta', () => {
|
||||
expect(rendered.textContent).not.toContain('Not installed')
|
||||
})
|
||||
|
||||
it('migrates a legacy-only install through the canonical install command', async () => {
|
||||
mocks.skillState.installed = false
|
||||
it('updates through the legacy skill name when only linear-tickets is installed', async () => {
|
||||
mocks.skillState.installed = true
|
||||
mocks.skillState.skills = [
|
||||
discoveredSkill({
|
||||
name: 'linear-tickets',
|
||||
@@ -158,11 +158,7 @@ describe('LinearAgentSkillInstallCta', () => {
|
||||
|
||||
const rendered = await renderCta()
|
||||
|
||||
expect(rendered.textContent).toContain(
|
||||
'npx skills add https://github.com/stablyai/orca --skill orca-linear --global'
|
||||
)
|
||||
expect(rendered.textContent).toContain('Not installed')
|
||||
expect(rendered.textContent).not.toContain('npx skills update linear-tickets --global')
|
||||
expect(rendered.textContent).toContain('npx skills update linear-tickets --global')
|
||||
})
|
||||
|
||||
it('notes that remote agent environments need their own setup', async () => {
|
||||
|
||||
@@ -11,9 +11,9 @@ import {
|
||||
import {
|
||||
LINEAR_AGENT_SKILL_NAMES,
|
||||
ORCA_LINEAR_SKILL_INSTALL_COMMAND,
|
||||
ORCA_LINEAR_SKILL_NAME,
|
||||
ORCA_LINEAR_SKILL_UPDATE_COMMAND
|
||||
ORCA_LINEAR_SKILL_NAME
|
||||
} from '@/lib/agent-feature-install-commands'
|
||||
import { getLinearAgentSkillUpdateCommand } from '@/lib/linear-agent-skill-update-command'
|
||||
import { cn } from '@/lib/utils'
|
||||
import { getLinearAgentSkillSetupInlineRuntimeCopy } from '../sidebar/linear-agent-skill-setup-copy'
|
||||
import {
|
||||
@@ -57,10 +57,12 @@ export function LinearAgentSkillInstallCta({
|
||||
const command = useMemo(
|
||||
() =>
|
||||
buildSkillCommandForRuntime(
|
||||
skill.installed ? ORCA_LINEAR_SKILL_UPDATE_COMMAND : ORCA_LINEAR_SKILL_INSTALL_COMMAND,
|
||||
skill.installed
|
||||
? getLinearAgentSkillUpdateCommand(skill.skills, skill.installed)
|
||||
: ORCA_LINEAR_SKILL_INSTALL_COMMAND,
|
||||
agentRuntime
|
||||
),
|
||||
[agentRuntime, skill.installed]
|
||||
[agentRuntime, skill.installed, skill.skills]
|
||||
)
|
||||
const subordinateRowClass = useIntegrationSubordinateRowClass('space-y-1.5')
|
||||
const commandRowClass = useIntegrationCommandRowClass()
|
||||
|
||||
@@ -9,9 +9,9 @@ import {
|
||||
} from '@/hooks/useInstalledAgentSkills'
|
||||
import {
|
||||
LINEAR_AGENT_SKILL_NAMES,
|
||||
ORCA_LINEAR_SKILL_INSTALL_COMMAND,
|
||||
ORCA_LINEAR_SKILL_UPDATE_COMMAND
|
||||
ORCA_LINEAR_SKILL_INSTALL_COMMAND
|
||||
} from '@/lib/agent-feature-install-commands'
|
||||
import { getLinearAgentSkillUpdateCommand } from '@/lib/linear-agent-skill-update-command'
|
||||
import {
|
||||
ensureOrcaCliAvailableForAgentSkillTerminal,
|
||||
isOrcaCliAvailableOnPath
|
||||
@@ -122,8 +122,12 @@ export function LinearAgentSkillSetupPrompt({
|
||||
[agentRuntime]
|
||||
)
|
||||
const installedCommand = useMemo(
|
||||
() => buildSkillCommandForRuntime(ORCA_LINEAR_SKILL_UPDATE_COMMAND, agentRuntime),
|
||||
[agentRuntime]
|
||||
() =>
|
||||
buildSkillCommandForRuntime(
|
||||
getLinearAgentSkillUpdateCommand(skill.skills, skill.installed),
|
||||
agentRuntime
|
||||
),
|
||||
[agentRuntime, skill.installed, skill.skills]
|
||||
)
|
||||
const terminalShellOverride = getLinearPromptTerminalShellOverride(
|
||||
currentPlatform,
|
||||
|
||||
+2
-7
@@ -160,18 +160,13 @@ describe('LinearAgentSkillSetupPrompt update command', () => {
|
||||
)
|
||||
})
|
||||
|
||||
it('migrates a legacy-only install through the canonical install command', async () => {
|
||||
mocks.skillState.installed = false
|
||||
it('uses the legacy update command when only the legacy Linear skill is installed', async () => {
|
||||
mocks.skillState.skills = [legacyLinearSkillPath()]
|
||||
|
||||
await renderPrompt()
|
||||
|
||||
expect(mocks.panelProps.at(-1)).toEqual(
|
||||
expect.objectContaining({
|
||||
installed: false,
|
||||
command: 'npx skills add https://github.com/stablyai/orca --skill orca-linear --global',
|
||||
installedCommand: 'npx skills update orca-linear --global'
|
||||
})
|
||||
expect.objectContaining({ installedCommand: 'npx skills update linear-tickets --global' })
|
||||
)
|
||||
})
|
||||
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import type { DiscoveredSkill } from '../../../shared/skills'
|
||||
import {
|
||||
LINEAR_TICKETS_SKILL_UPDATE_COMMAND,
|
||||
ORCA_LINEAR_SKILL_UPDATE_COMMAND
|
||||
} from './agent-feature-install-commands'
|
||||
import { getLinearAgentSkillUpdateTarget } from './linear-agent-skill-update-command'
|
||||
|
||||
function skill(name: string): DiscoveredSkill {
|
||||
return {
|
||||
id: name,
|
||||
name,
|
||||
description: null,
|
||||
providers: ['agent-skills'],
|
||||
sourceKind: 'home',
|
||||
sourceLabel: 'Agent skills home',
|
||||
rootPath: '/home/test/.agents/skills',
|
||||
directoryPath: `/home/test/.agents/skills/${name}`,
|
||||
skillFilePath: `/home/test/.agents/skills/${name}/SKILL.md`,
|
||||
installed: true,
|
||||
fileCount: 1,
|
||||
updatedAt: null
|
||||
}
|
||||
}
|
||||
|
||||
describe('getLinearAgentSkillUpdateTarget', () => {
|
||||
it('targets the canonical skill for missing, canonical, and dual-name installs', () => {
|
||||
expect(getLinearAgentSkillUpdateTarget([], false)).toEqual({
|
||||
skillName: 'orca-linear',
|
||||
command: ORCA_LINEAR_SKILL_UPDATE_COMMAND
|
||||
})
|
||||
expect(getLinearAgentSkillUpdateTarget([skill('orca-linear')], true)).toEqual({
|
||||
skillName: 'orca-linear',
|
||||
command: ORCA_LINEAR_SKILL_UPDATE_COMMAND
|
||||
})
|
||||
expect(
|
||||
getLinearAgentSkillUpdateTarget([skill('orca-linear'), skill('linear-tickets')], true)
|
||||
).toEqual({
|
||||
skillName: 'orca-linear',
|
||||
command: ORCA_LINEAR_SKILL_UPDATE_COMMAND
|
||||
})
|
||||
})
|
||||
|
||||
it('keeps the update and freshness identity on a legacy-only install', () => {
|
||||
expect(getLinearAgentSkillUpdateTarget([skill('linear-tickets')], true)).toEqual({
|
||||
skillName: 'linear-tickets',
|
||||
command: LINEAR_TICKETS_SKILL_UPDATE_COMMAND
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,40 @@
|
||||
import type { DiscoveredSkill } from '../../../shared/skills'
|
||||
import {
|
||||
GLOBAL_AGENT_SKILL_SOURCE_KINDS,
|
||||
hasInstalledAgentSkill
|
||||
} from '@/hooks/useInstalledAgentSkills'
|
||||
import {
|
||||
LINEAR_TICKETS_SKILL_NAME,
|
||||
LINEAR_TICKETS_SKILL_UPDATE_COMMAND,
|
||||
ORCA_LINEAR_SKILL_NAME,
|
||||
ORCA_LINEAR_SKILL_UPDATE_COMMAND
|
||||
} from '@/lib/agent-feature-install-commands'
|
||||
|
||||
export type LinearAgentSkillUpdateTarget = {
|
||||
skillName: typeof ORCA_LINEAR_SKILL_NAME | typeof LINEAR_TICKETS_SKILL_NAME
|
||||
command: string
|
||||
}
|
||||
|
||||
// Why: legacy-only installs must update and report freshness for the installed
|
||||
// legacy skill, while fresh/canonical/both-name states use the canonical name.
|
||||
export function getLinearAgentSkillUpdateTarget(
|
||||
skills: readonly DiscoveredSkill[],
|
||||
installed: boolean
|
||||
): LinearAgentSkillUpdateTarget {
|
||||
const canonicalSkillInstalled = hasInstalledAgentSkill(skills, ORCA_LINEAR_SKILL_NAME, {
|
||||
sourceKinds: GLOBAL_AGENT_SKILL_SOURCE_KINDS
|
||||
})
|
||||
const legacySkillInstalled = hasInstalledAgentSkill(skills, LINEAR_TICKETS_SKILL_NAME, {
|
||||
sourceKinds: GLOBAL_AGENT_SKILL_SOURCE_KINDS
|
||||
})
|
||||
return !installed || canonicalSkillInstalled || !legacySkillInstalled
|
||||
? { skillName: ORCA_LINEAR_SKILL_NAME, command: ORCA_LINEAR_SKILL_UPDATE_COMMAND }
|
||||
: { skillName: LINEAR_TICKETS_SKILL_NAME, command: LINEAR_TICKETS_SKILL_UPDATE_COMMAND }
|
||||
}
|
||||
|
||||
export function getLinearAgentSkillUpdateCommand(
|
||||
skills: readonly DiscoveredSkill[],
|
||||
installed: boolean
|
||||
): string {
|
||||
return getLinearAgentSkillUpdateTarget(skills, installed).command
|
||||
}
|
||||
@@ -4,7 +4,6 @@ import {
|
||||
buildAgentFeatureSkillUpdateCommand,
|
||||
COMPUTER_USE_SKILL_UPDATE_COMMAND,
|
||||
EPHEMERAL_VMS_SKILL_UPDATE_COMMAND,
|
||||
LINEAR_AGENT_SKILL_NAMES,
|
||||
LINEAR_TICKETS_SKILL_UPDATE_COMMAND,
|
||||
ORCA_LINEAR_SKILL_UPDATE_COMMAND,
|
||||
ORCA_CLI_ORCHESTRATION_SKILL_INSTALL_COMMAND,
|
||||
@@ -39,8 +38,4 @@ describe('agent feature skill commands', () => {
|
||||
buildAgentFeatureSkillInstallCommand(['orca-cli', 'orchestration'])
|
||||
)
|
||||
})
|
||||
|
||||
it('requires the canonical Linear skill so legacy installs migrate', () => {
|
||||
expect(LINEAR_AGENT_SKILL_NAMES).toEqual(['orca-linear'])
|
||||
})
|
||||
})
|
||||
|
||||
@@ -6,9 +6,7 @@ export const ORCHESTRATION_SKILL_NAME = 'orchestration'
|
||||
export const EPHEMERAL_VMS_SKILL_NAME = 'orca-per-workspace-env'
|
||||
export const ORCA_LINEAR_SKILL_NAME = 'orca-linear'
|
||||
export const LINEAR_TICKETS_SKILL_NAME = 'linear-tickets'
|
||||
// Why: linear-tickets is retired and must not satisfy setup readiness; legacy-only
|
||||
// users should be offered the canonical orca-linear install path.
|
||||
export const LINEAR_AGENT_SKILL_NAMES = [ORCA_LINEAR_SKILL_NAME] as const
|
||||
export const LINEAR_AGENT_SKILL_NAMES = [ORCA_LINEAR_SKILL_NAME, LINEAR_TICKETS_SKILL_NAME] as const
|
||||
|
||||
export function buildAgentFeatureSkillInstallCommand(skillNames: readonly string[]): string {
|
||||
if (skillNames.length === 0) {
|
||||
|
||||
Reference in New Issue
Block a user