mirror of
https://github.com/stablyai/orca.git
synced 2026-11-13 17:37:40 +00:00
* fix: separate chat option input from inventory observations * fix: preserve scoped chat choices and publication ownership * fix: complete scoped catalog and applied control ownership * test: make catalog fixture dependency boundaries explicit * test: request catalog discovery explicitly in demand contracts * fix(chat): preserve option observations and operation boundaries * fix(chat): finish pending option and catalog lifetimes * fix(chat): project saved permissions without launch preparation * fix(chat): correct option rejection and catalog retirement * Preserve Claude effort validation advice through chat rejection * test: align refresh mocks and preserve fixture type evidence * fix: share catalog claims only across equivalent owners * test: use typed catalog corpus instrumentation * fix: consolidate structured launch imports * Validate SDK queue regression envelopes without assertions * fix: complete catalog runtime and fixture type contracts * Align native option fixtures with explicit discovery and applied facts * Keep initial compatibility catalog reads on held memory * Complete the installed catalog fixture envelope * Observe learned defaults after asynchronous projection settles * Consolidate host fixture journal type imports * test(native-chat): align goal and seed fixtures with applied inputs * fix(codex): retain applied proof when goal settings skip a write * test: load rejection wording before timed queue regression * Fix catalog fixtures and queued option snapshot typing * Align permission publication fixture with passive option reads * Separate startup config from held turn permission fixture * Align input lifecycle fixtures with sparse applied choices * Simplify scoped catalog refresh ownership and coalesce cache snapshots * Load catalog persistence real-module fixture during collection * Compose catalog availability fixtures from valid session records * Align catalog and startup fixtures with current option contracts * Fix permission read types and separate catalog fixture preparation * Align option and restart fixtures with current lifecycle owners * test(mobile): retain reported model alongside discovery * test(mobile): recalibrate the measured route script envelope * test: let the preflight shell-capture mock run its detection callback
106 lines
4.2 KiB
TypeScript
106 lines
4.2 KiB
TypeScript
import { randomUUID } from 'node:crypto'
|
|
import { stat } from 'node:fs/promises'
|
|
import { FOLDER_WORKSPACE_INSTANCE_SEPARATOR } from '../../shared/worktree/id'
|
|
import type { Repo } from '../../shared/repo-types'
|
|
import type { Worktree } from '../../shared/worktree/types'
|
|
import { isENOENT } from '../ipc/filesystem/filesystem-path-containment'
|
|
import {
|
|
getLocalWorktreePathAccess,
|
|
toLocalWorktreeRuntimePath
|
|
} from '../local-worktree-filesystem'
|
|
import { isWorktreePathMissing } from '../worktree-removal-safety'
|
|
import { getRepoExecutionHostId } from '../../shared/execution-host'
|
|
import { getRepoOwnedWorktreeMeta } from '../worktree-metadata-ownership'
|
|
import type { WorktreeMeta } from '../../shared/worktree/meta-types'
|
|
import {
|
|
getRuntimeFolderWorkspaceRootId,
|
|
isRuntimeFolderWorkspaceIdForRepo,
|
|
mergeRuntimeFolderWorkspace
|
|
} from './runtime-folder-workspace'
|
|
import type { RuntimeStore } from './runtime-store-contract'
|
|
import { isWslMoveRepoBlocked } from '../persistence/moving-wsl-projects/wsl-move-background-backoff'
|
|
import { hostWorktreeTargetForRepo } from '../persistence/host-qualified-worktree-meta'
|
|
|
|
/** Callers hold a local removal route; an `ssh:` or `runtime:` host is refused before this. */
|
|
export async function isLocalRuntimeWorktreePathMissing(
|
|
worktreePath: string,
|
|
localWorktreeGitOptions: { wslDistro?: string } = {}
|
|
): Promise<boolean> {
|
|
const access = getLocalWorktreePathAccess(localWorktreeGitOptions)
|
|
return isWorktreePathMissing(
|
|
toLocalWorktreeRuntimePath(worktreePath, localWorktreeGitOptions),
|
|
access.statPath
|
|
)
|
|
}
|
|
|
|
function getRuntimeFolderWorkspaceInstanceIdentity(repo: Repo, worktreeId: string): string {
|
|
const prefix = `${getRuntimeFolderWorkspaceRootId(repo)}${FOLDER_WORKSPACE_INSTANCE_SEPARATOR}`
|
|
return worktreeId.startsWith(prefix) ? worktreeId.slice(prefix.length) : randomUUID()
|
|
}
|
|
|
|
function runtimeFolderWorkspaceRows(
|
|
store: Pick<RuntimeStore, 'getAllWorktreeMeta' | 'getRepos' | 'setWorktreeMeta'>,
|
|
repo: Repo,
|
|
repoOwnerCount: number,
|
|
stamp: boolean
|
|
): Worktree[] {
|
|
const rootId = getRuntimeFolderWorkspaceRootId(repo)
|
|
const allMeta = store.getAllWorktreeMeta()
|
|
const expectedHostId = getRepoExecutionHostId(repo)
|
|
// A project a WSL move is taking still lists, without stamping identities it lacks.
|
|
const canWrite = stamp && !isWslMoveRepoBlocked(repo)
|
|
const ids = Object.keys(allMeta).filter(
|
|
(worktreeId) =>
|
|
isRuntimeFolderWorkspaceIdForRepo(repo, worktreeId) &&
|
|
(repoOwnerCount === 1 || allMeta[worktreeId]?.hostId === expectedHostId)
|
|
)
|
|
if (!ids.includes(rootId)) {
|
|
ids.unshift(rootId)
|
|
} else {
|
|
ids.sort((left, right) => (left === rootId ? -1 : right === rootId ? 1 : 0))
|
|
}
|
|
return ids.map((worktreeId) => {
|
|
const existing = getRepoOwnedWorktreeMeta(repo, worktreeId, allMeta, repoOwnerCount)
|
|
const meta: Partial<WorktreeMeta> = existing?.instanceId
|
|
? existing
|
|
: canWrite && (existing || repoOwnerCount === 1)
|
|
? store.setWorktreeMeta(hostWorktreeTargetForRepo(worktreeId, repo), {
|
|
instanceId: getRuntimeFolderWorkspaceInstanceIdentity(repo, worktreeId),
|
|
...(existing ? {} : { displayName: repo.displayName, lastActivityAt: Date.now() })
|
|
})
|
|
: (existing ?? {})
|
|
return {
|
|
...mergeRuntimeFolderWorkspace(repo, worktreeId, meta),
|
|
hostId: repoOwnerCount === 1 ? (meta.hostId ?? expectedHostId) : expectedHostId
|
|
}
|
|
})
|
|
}
|
|
|
|
export function listRuntimeFolderWorkspaces(
|
|
store: Pick<RuntimeStore, 'getAllWorktreeMeta' | 'getRepos' | 'setWorktreeMeta'>,
|
|
repo: Repo,
|
|
repoOwnerCount = store.getRepos().filter((candidate) => candidate.id === repo.id).length
|
|
): Worktree[] {
|
|
return runtimeFolderWorkspaceRows(store, repo, repoOwnerCount, true)
|
|
}
|
|
|
|
export function projectRuntimeFolderWorkspaces(
|
|
store: Pick<RuntimeStore, 'getAllWorktreeMeta' | 'getRepos' | 'setWorktreeMeta'>,
|
|
repo: Repo,
|
|
repoOwnerCount: number
|
|
): Worktree[] {
|
|
return runtimeFolderWorkspaceRows(store, repo, repoOwnerCount, false)
|
|
}
|
|
|
|
export async function runtimePathExists(pathValue: string): Promise<boolean> {
|
|
try {
|
|
await stat(pathValue)
|
|
return true
|
|
} catch (error) {
|
|
if (isENOENT(error)) {
|
|
return false
|
|
}
|
|
throw error
|
|
}
|
|
}
|