mirror of
https://github.com/stablyai/orca.git
synced 2026-10-16 00:03:09 +00:00
Centralize automation run identity fallback
Co-authored-by: Orca <help@stably.ai>
This commit is contained in:
@@ -295,5 +295,6 @@ Done means: reviewers and future agents can understand the vision, implementatio
|
||||
- [x] 2026-06-13: Closed another request/cache ownership slice by routing right-sidebar search, create-review field generation, browser tab default profile selection, Smart Workspace GitHub/GitLab/Linear lookups, GitHub Project browse cache, Project slug comments, and standalone GitHub issue comments through explicit worktree/repo/source ownership instead of ambient focused runtime state. Verified with focused ownership/browser/smart-submit tests, targeted oxlint, `git diff --check`, and full `pnpm run typecheck`.
|
||||
- [x] 2026-06-13: Routed Quick Open file listing through the selected worktree runtime owner instead of ambient focused settings, matching File Explorer and sidebar search ownership. Verified with focused Quick Open and file-owner boundary tests, targeted oxlint, `git diff --check`, and full `pnpm run typecheck`.
|
||||
- [x] 2026-06-13: Routed typed GitHub issue/PR lookup entry points in Cmd-J, Smart Workspace cross-repo accept, and Composer submit fallback through source-aware local/SSH/runtime lookup helpers instead of direct preload calls. Verified with focused composer/palette/smart-submit tests, targeted oxlint, `git diff --check`, and full `pnpm run typecheck`.
|
||||
- [x] 2026-06-13: Centralized Automation run identity so renderer dispatch, Automations UI, main-process run-target resolution, persistence backfill, and CLI formatting resolve `runRepoId` through explicit `runContext` with a named `legacyRepoId` fallback instead of each caller reading the persisted compatibility field directly. The checklist row remains partial because `Automation.projectId` still exists for storage compatibility. Verified with shared identity, automation run-context, automation service, and CLI format tests, targeted oxlint, `git diff --check`, and full `pnpm run typecheck`.
|
||||
- [~] 2026-06-13: Remaining source-error gap: unavailable hosts, version-skewed runtimes, and GitHub/GitLab missing auth/tooling are surfaced for desktop-owned and runtime-owned source hosts, but unsupported-provider still has no production emitter per source host.
|
||||
- [~] 2026-06-13: Remaining Automation gap: run-host/source-host availability and missing project-host setup are handled for manual/internal/external actions, but `Automation.projectId` remains the legacy repo-id compatibility field.
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import type { Automation, AutomationRun } from '../shared/automations-types'
|
||||
import { getAutomationLegacyRepoId } from '../shared/automation-run-identity'
|
||||
import { formatAutomationPrecheckTimeout } from '../shared/automation-precheck'
|
||||
import { formatAutomationSchedule } from '../shared/automation-schedules'
|
||||
import type { PublicKnownRuntimeEnvironment } from '../shared/runtime-environments'
|
||||
@@ -186,9 +187,9 @@ export function formatAutomationShow(result: { automation: Automation }): string
|
||||
`projectHostSetupId: ${runContext.projectHostSetupId}`,
|
||||
`runRepoId: ${runContext.repoId}`,
|
||||
`runPath: ${runContext.path}`,
|
||||
`legacyRepoId: ${automation.projectId}`
|
||||
`legacyRepoId: ${getAutomationLegacyRepoId(automation)}`
|
||||
]
|
||||
: [`legacyRepoId: ${automation.projectId}`]
|
||||
: [`legacyRepoId: ${getAutomationLegacyRepoId(automation)}`]
|
||||
return [
|
||||
`id: ${automation.id}`,
|
||||
`name: ${automation.name}`,
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import type { Store } from '../persistence'
|
||||
import type { Automation } from '../../shared/automations-types'
|
||||
import { getAutomationLegacyRepoId } from '../../shared/automation-run-identity'
|
||||
import { getRepoExecutionHostId, parseExecutionHostId } from '../../shared/execution-host'
|
||||
import type { ProjectHostSetup, Repo } from '../../shared/types'
|
||||
import { splitWorktreeIdForFilesystem } from '../../shared/worktree-id'
|
||||
@@ -15,7 +16,7 @@ function getLegacyPrecheckCwd(store: Store, automation: Automation): string | nu
|
||||
: null
|
||||
return parsed?.worktreePath ?? null
|
||||
}
|
||||
return store.getRepo(automation.projectId)?.path ?? null
|
||||
return store.getRepo(getAutomationLegacyRepoId(automation))?.path ?? null
|
||||
}
|
||||
|
||||
export function resolveAutomationRunTarget(
|
||||
@@ -24,7 +25,7 @@ export function resolveAutomationRunTarget(
|
||||
): AutomationRunTargetResult {
|
||||
const context = automation.runContext ?? null
|
||||
if (!context) {
|
||||
const repo = store.getRepo(automation.projectId)
|
||||
const repo = store.getRepo(getAutomationLegacyRepoId(automation))
|
||||
const cwd = getLegacyPrecheckCwd(store, automation)
|
||||
if (!repo || !cwd) {
|
||||
return { ok: false, error: 'Automation run target is no longer available.' }
|
||||
|
||||
@@ -32,6 +32,7 @@ import {
|
||||
latestAutomationOccurrenceAtOrBefore,
|
||||
nextAutomationOccurrenceAfter
|
||||
} from '../shared/automation-schedules'
|
||||
import { getAutomationLegacyRepoId } from '../shared/automation-run-identity'
|
||||
import { normalizeAutomationPrecheck } from '../shared/automation-precheck'
|
||||
import type {
|
||||
PersistedState,
|
||||
@@ -682,7 +683,7 @@ function backfillLegacyAutomationContexts(
|
||||
const contextsByAutomationId = new Map<string, Pick<Automation, 'runContext' | 'sourceContext'>>()
|
||||
const automations = (state.automations ?? []).map((automation) => {
|
||||
const contexts = getAutomationContextsForRepo(
|
||||
state.repos.find((repo) => repo.id === automation.projectId),
|
||||
state.repos.find((repo) => repo.id === getAutomationLegacyRepoId(automation)),
|
||||
state.projectHostSetups ?? []
|
||||
)
|
||||
const next: Automation = { ...automation }
|
||||
|
||||
@@ -53,6 +53,7 @@ import type {
|
||||
AutomationRun,
|
||||
AutomationUpdateInput
|
||||
} from '../../../../shared/automations-types'
|
||||
import { getAutomationRunRepoId } from '../../../../shared/automation-run-identity'
|
||||
import { parseExecutionHostId } from '../../../../shared/execution-host'
|
||||
import { TASK_SOURCE_CONTEXT_RUNTIME_CAPABILITY } from '../../../../shared/protocol-version'
|
||||
import type { PreflightStatus } from '../../../../preload/api-types'
|
||||
@@ -142,10 +143,6 @@ function getDefaultWorktree(worktrees: readonly Worktree[]): Worktree | null {
|
||||
return worktrees.find((worktree) => worktree.isMainWorktree) ?? worktrees[0] ?? null
|
||||
}
|
||||
|
||||
function getAutomationRunRepoId(automation: Automation): string {
|
||||
return automation.runContext?.repoId ?? automation.projectId
|
||||
}
|
||||
|
||||
function getRepoBackedAutomationSourceContext(
|
||||
automation: Automation
|
||||
): RepoBackedAutomationSourceContext | null {
|
||||
|
||||
@@ -11,6 +11,7 @@ import type {
|
||||
AutomationDispatchResult,
|
||||
AutomationPrecheckResult
|
||||
} from '../../../shared/automations-types'
|
||||
import { getAutomationRunRepoId } from '../../../shared/automation-run-identity'
|
||||
import {
|
||||
didAutomationPrecheckPass,
|
||||
formatAutomationPrecheckFailure
|
||||
@@ -57,7 +58,7 @@ export function useAutomationDispatchEvents(): void {
|
||||
activeTabId: state.activeTabId,
|
||||
activeTabType: state.activeTabType
|
||||
}
|
||||
const runRepoId = automation.runContext?.repoId ?? automation.projectId
|
||||
const runRepoId = getAutomationRunRepoId(automation)
|
||||
const repo = state.repos.find((entry) => entry.id === runRepoId)
|
||||
const automationWorktree = automation.workspaceId
|
||||
? state.allWorktrees().find((entry) => entry.id === automation.workspaceId)
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import type { Automation } from './automations-types'
|
||||
import {
|
||||
getAutomationLegacyRepoId,
|
||||
getAutomationRunProjectId,
|
||||
getAutomationRunRepoId
|
||||
} from './automation-run-identity'
|
||||
|
||||
function automation(overrides: Partial<Automation> = {}): Automation {
|
||||
return {
|
||||
id: 'auto-1',
|
||||
name: 'Automation',
|
||||
prompt: 'Run this',
|
||||
precheck: null,
|
||||
agentId: 'claude',
|
||||
runContext: null,
|
||||
sourceContext: null,
|
||||
projectId: 'legacy-repo',
|
||||
executionTargetType: 'local',
|
||||
executionTargetId: 'local',
|
||||
schedulerOwner: 'local_host_service',
|
||||
workspaceMode: 'new_per_run',
|
||||
workspaceId: null,
|
||||
baseBranch: null,
|
||||
reuseSession: false,
|
||||
timezone: 'UTC',
|
||||
rrule: 'FREQ=DAILY',
|
||||
dtstart: 1,
|
||||
enabled: true,
|
||||
nextRunAt: 1,
|
||||
missedRunPolicy: 'run_once_within_grace',
|
||||
missedRunGraceMinutes: 720,
|
||||
createdAt: 1,
|
||||
updatedAt: 1,
|
||||
...overrides
|
||||
}
|
||||
}
|
||||
|
||||
describe('automation run identity', () => {
|
||||
it('uses explicit run context identity when present', () => {
|
||||
const value = automation({
|
||||
runContext: {
|
||||
kind: 'workspace-run',
|
||||
projectId: 'github:stablyai/orca',
|
||||
hostId: 'ssh:builder',
|
||||
projectHostSetupId: 'setup-builder',
|
||||
repoId: 'remote-repo',
|
||||
path: '/remote/orca'
|
||||
}
|
||||
})
|
||||
|
||||
expect(getAutomationLegacyRepoId(value)).toBe('legacy-repo')
|
||||
expect(getAutomationRunRepoId(value)).toBe('remote-repo')
|
||||
expect(getAutomationRunProjectId(value)).toBe('github:stablyai/orca')
|
||||
})
|
||||
|
||||
it('falls back to the legacy repo id for pre-host-context automations', () => {
|
||||
const value = automation()
|
||||
|
||||
expect(getAutomationLegacyRepoId(value)).toBe('legacy-repo')
|
||||
expect(getAutomationRunRepoId(value)).toBe('legacy-repo')
|
||||
expect(getAutomationRunProjectId(value)).toBe('legacy-repo')
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,15 @@
|
||||
import type { Automation } from './automations-types'
|
||||
|
||||
type AutomationRunIdentityFields = Pick<Automation, 'projectId' | 'runContext'>
|
||||
|
||||
export function getAutomationLegacyRepoId(automation: Pick<Automation, 'projectId'>): string {
|
||||
return automation.projectId
|
||||
}
|
||||
|
||||
export function getAutomationRunRepoId(automation: AutomationRunIdentityFields): string {
|
||||
return automation.runContext?.repoId ?? getAutomationLegacyRepoId(automation)
|
||||
}
|
||||
|
||||
export function getAutomationRunProjectId(automation: AutomationRunIdentityFields): string {
|
||||
return automation.runContext?.projectId ?? getAutomationLegacyRepoId(automation)
|
||||
}
|
||||
Reference in New Issue
Block a user