- Store runtime selection as { provider?, model? } layers and resolve them per
field (conversation -> project -> global); drop the legacy auto provider.
- Migrate stored selections (database v49) and clear deleted profile ids.
- Re-resolve selections in Main per request and at queue dispatch.
- Add ProjectRuntimeSelector and a two-column RuntimeModelPicker; manage
link opens model connections; restore per-runtime default model tabs.
- Stop duplicating trusted instructions and history across OpenCode,
Continue and DeepSeek Harness runtimes.
- Document the layered design, global provider removal plan and planned
purpose-specific models.
95 lines
2.4 KiB
TypeScript
95 lines
2.4 KiB
TypeScript
import { z } from 'zod'
|
|
import { assistantIdSchema, projectCreateSchema } from './assistant-contracts'
|
|
import {
|
|
REMOTE_WORKSPACE_LIMITS,
|
|
remoteAbsolutePathSchema
|
|
} from './remote-agent-contracts'
|
|
import { runtimeSelectionLayerSchema } from './runtime-selection-contracts'
|
|
import { sshHostIdSchema } from './ssh-host-contracts'
|
|
|
|
export const REMOTE_PROJECT_SAVE_LIMITS = {
|
|
maximumAbsolutePathBytes:
|
|
REMOTE_WORKSPACE_LIMITS.maximumAbsolutePathBytes
|
|
} as const
|
|
|
|
export const remoteProjectRootPathSchema = remoteAbsolutePathSchema
|
|
.refine(
|
|
(value) => !/[\p{Cc}\p{Cs}\u2028\u2029\ufffd]/u.test(value),
|
|
'Remote project root cannot contain control characters'
|
|
)
|
|
.refine(
|
|
(value) =>
|
|
!value.includes('//') &&
|
|
!value
|
|
.split('/')
|
|
.some((segment) => segment === '.' || segment === '..'),
|
|
'Remote project root cannot contain empty, dot, or parent segments'
|
|
)
|
|
|
|
const commonDraftFields = {
|
|
name: projectCreateSchema.shape.name,
|
|
description: projectCreateSchema.shape.description,
|
|
defaultWorkMode: projectCreateSchema.shape.defaultWorkMode,
|
|
runtimeSelection: runtimeSelectionLayerSchema.optional(),
|
|
hostId: sshHostIdSchema,
|
|
remoteRootPath: remoteProjectRootPathSchema
|
|
} as const
|
|
|
|
export const remoteProjectCreateDraftSchema =
|
|
z.object(commonDraftFields).strict()
|
|
|
|
export const remoteProjectUpdateDraftSchema = z
|
|
.object({
|
|
projectId: assistantIdSchema,
|
|
...commonDraftFields
|
|
})
|
|
.strict()
|
|
|
|
export const remoteProjectSaveRequestSchema = z.discriminatedUnion(
|
|
'intent',
|
|
[
|
|
z
|
|
.object({
|
|
intent: z.literal('create'),
|
|
draft: remoteProjectCreateDraftSchema
|
|
})
|
|
.strict(),
|
|
z
|
|
.object({
|
|
intent: z.literal('update'),
|
|
draft: remoteProjectUpdateDraftSchema
|
|
})
|
|
.strict()
|
|
]
|
|
)
|
|
|
|
export const remoteProjectSavePhaseSchema = z.enum([
|
|
'host',
|
|
'agent',
|
|
'workspace',
|
|
'runtime',
|
|
'saving'
|
|
])
|
|
|
|
export const remoteProjectSaveProgressSchema = z
|
|
.object({
|
|
phase: remoteProjectSavePhaseSchema
|
|
})
|
|
.strict()
|
|
|
|
export type RemoteProjectCreateDraft = z.infer<
|
|
typeof remoteProjectCreateDraftSchema
|
|
>
|
|
export type RemoteProjectUpdateDraft = z.infer<
|
|
typeof remoteProjectUpdateDraftSchema
|
|
>
|
|
export type RemoteProjectSaveRequest = z.infer<
|
|
typeof remoteProjectSaveRequestSchema
|
|
>
|
|
export type RemoteProjectSavePhase = z.infer<
|
|
typeof remoteProjectSavePhaseSchema
|
|
>
|
|
export type RemoteProjectSaveProgress = z.infer<
|
|
typeof remoteProjectSaveProgressSchema
|
|
>
|