mirror of
https://github.com/anomalyco/opencode.git
synced 2026-08-06 09:10:47 -04:00
Compare commits
26 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f840b3e3a2 | |||
| 05c3866788 | |||
| 3eca11a7da | |||
| 794283057a | |||
| 56c33e84a3 | |||
| 73581b3c3b | |||
| 6e4d01f846 | |||
| 8646587c95 | |||
| fb47f06228 | |||
| 3acaa5a359 | |||
| 0726a25142 | |||
| 0df96ddeb0 | |||
| 887673310b | |||
| 693a1bff81 | |||
| b40ed3aa85 | |||
| 732bb9c3cb | |||
| 2fd1660b4d | |||
| 681526d348 | |||
| e78869c849 | |||
| 934935963d | |||
| f3912a2a8a | |||
| 45d58717a4 | |||
| 74e3155ef0 | |||
| 0af6c82563 | |||
| 686127f809 | |||
| 5256655c4d |
@@ -248,11 +248,6 @@ export function formatKeybind(config: string, t?: (key: KeyLabel) => string): st
|
|||||||
return IS_MAC ? parts.join("") : parts.join("+")
|
return IS_MAC ? parts.join("") : parts.join("+")
|
||||||
}
|
}
|
||||||
|
|
||||||
// KeybindV2 takes an array instead of a string
|
|
||||||
export function formatKeybindKeys(config: string, t?: (key: KeyLabel) => string): string[] {
|
|
||||||
return formatKeybindParts(config, t)
|
|
||||||
}
|
|
||||||
|
|
||||||
function isEditableTarget(target: EventTarget | null) {
|
function isEditableTarget(target: EventTarget | null) {
|
||||||
if (!(target instanceof HTMLElement)) return false
|
if (!(target instanceof HTMLElement)) return false
|
||||||
if (target.isContentEditable) return true
|
if (target.isContentEditable) return true
|
||||||
|
|||||||
@@ -286,13 +286,6 @@ export const { use: useFile, provider: FileProvider } = createSimpleContext({
|
|||||||
children: tree.children,
|
children: tree.children,
|
||||||
expand: tree.expandDir,
|
expand: tree.expandDir,
|
||||||
collapse: tree.collapseDir,
|
collapse: tree.collapseDir,
|
||||||
toggle(input: string) {
|
|
||||||
if (tree.dirState(input)?.expanded) {
|
|
||||||
tree.collapseDir(input)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
tree.expandDir(input)
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
get,
|
get,
|
||||||
load,
|
load,
|
||||||
|
|||||||
@@ -153,18 +153,6 @@ export function normalizeProviderList(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function sanitizeProject(project: Project) {
|
|
||||||
if (!project.icon?.url && !project.icon?.override) return project
|
|
||||||
return {
|
|
||||||
...project,
|
|
||||||
icon: {
|
|
||||||
...project.icon,
|
|
||||||
url: undefined,
|
|
||||||
override: undefined,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function normalizeProjectInfo(project: Project | CurrentProject): Project {
|
export function normalizeProjectInfo(project: Project | CurrentProject): Project {
|
||||||
return {
|
return {
|
||||||
...project,
|
...project,
|
||||||
|
|||||||
@@ -753,9 +753,6 @@ export const { use: useLayout, provider: LayoutProvider } = createSimpleContext(
|
|||||||
},
|
},
|
||||||
mobileSidebar: {
|
mobileSidebar: {
|
||||||
opened: createMemo(() => store.mobileSidebar?.opened ?? false),
|
opened: createMemo(() => store.mobileSidebar?.opened ?? false),
|
||||||
show() {
|
|
||||||
setStore("mobileSidebar", "opened", true)
|
|
||||||
},
|
|
||||||
hide() {
|
hide() {
|
||||||
setStore("mobileSidebar", "opened", false)
|
setStore("mobileSidebar", "opened", false)
|
||||||
},
|
},
|
||||||
@@ -961,33 +958,6 @@ export const { use: useLayout, provider: LayoutProvider } = createSimpleContext(
|
|||||||
if (current.reviewOpen.includes(path)) return
|
if (current.reviewOpen.includes(path)) return
|
||||||
setStore("sessionView", session, "reviewOpen", current.reviewOpen.length, path)
|
setStore("sessionView", session, "reviewOpen", current.reviewOpen.length, path)
|
||||||
},
|
},
|
||||||
closePath(path: string) {
|
|
||||||
const session = key()
|
|
||||||
const current = store.sessionView[session]?.reviewOpen
|
|
||||||
if (!current) return
|
|
||||||
|
|
||||||
const index = current.indexOf(path)
|
|
||||||
if (index === -1) return
|
|
||||||
setStore(
|
|
||||||
"sessionView",
|
|
||||||
session,
|
|
||||||
"reviewOpen",
|
|
||||||
produce((draft) => {
|
|
||||||
if (!draft) return
|
|
||||||
draft.splice(index, 1)
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
},
|
|
||||||
togglePath(path: string) {
|
|
||||||
const session = key()
|
|
||||||
const current = store.sessionView[session]?.reviewOpen
|
|
||||||
if (!current || !current.includes(path)) {
|
|
||||||
this.openPath(path)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
this.closePath(path)
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -22,8 +22,6 @@ type TabsInput = {
|
|||||||
fileBrowser?: Accessor<boolean>
|
fileBrowser?: Accessor<boolean>
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getSessionKey = (dir: string | undefined, id: string | undefined) => `${dir ?? ""}${id ? `/${id}` : ""}`
|
|
||||||
|
|
||||||
export function shouldShowFileTree(input: { visible: boolean; opened: boolean }) {
|
export function shouldShowFileTree(input: { visible: boolean; opened: boolean }) {
|
||||||
return input.opened && input.visible
|
return input.opened && input.visible
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -86,7 +86,7 @@ export async function runMini(input: MiniCommandInput) {
|
|||||||
) =>
|
) =>
|
||||||
resolveSessionTarget({
|
resolveSessionTarget({
|
||||||
client,
|
client,
|
||||||
location: { directory: next.location.directory, workspace: next.location.workspaceID },
|
location: { directory: next.location.directory },
|
||||||
agent: next.agent,
|
agent: next.agent,
|
||||||
model: next.model
|
model: next.model
|
||||||
? { providerID: next.model.providerID, id: next.model.modelID, variant: next.variant }
|
? { providerID: next.model.providerID, id: next.model.modelID, variant: next.variant }
|
||||||
|
|||||||
@@ -703,7 +703,7 @@ export async function runNonInteractivePrompt(input: Input) {
|
|||||||
? Promise.resolve(undefined)
|
? Promise.resolve(undefined)
|
||||||
: input.client.form.request
|
: input.client.form.request
|
||||||
.list({
|
.list({
|
||||||
location: { directory: input.location.directory, workspace: input.location.workspaceID },
|
location: { directory: input.location.directory },
|
||||||
})
|
})
|
||||||
.catch(() => undefined),
|
.catch(() => undefined),
|
||||||
])
|
])
|
||||||
@@ -757,7 +757,6 @@ function formRequestOptions(location: LocationRef | undefined): [] | [{ headers:
|
|||||||
{
|
{
|
||||||
headers: {
|
headers: {
|
||||||
"x-opencode-directory": encodeURIComponent(location.directory),
|
"x-opencode-directory": encodeURIComponent(location.directory),
|
||||||
...(location.workspaceID ? { "x-opencode-workspace": location.workspaceID } : {}),
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -96,7 +96,7 @@ async function execute(input: RunCommandInput, prepared: Prepared, endpoint: End
|
|||||||
next.model ??
|
next.model ??
|
||||||
(options.variant
|
(options.variant
|
||||||
? await client.model
|
? await client.model
|
||||||
.default({ location: { directory: next.location.directory, workspace: next.location.workspaceID } })
|
.default({ location: { directory: next.location.directory } })
|
||||||
.then((result) => result.data)
|
.then((result) => result.data)
|
||||||
: undefined)
|
: undefined)
|
||||||
const model = selected
|
const model = selected
|
||||||
|
|||||||
@@ -136,7 +136,6 @@ async function latestSession(
|
|||||||
const page = await client.session.list(
|
const page = await client.session.list(
|
||||||
{
|
{
|
||||||
directory: location.directory,
|
directory: location.directory,
|
||||||
workspace: location.workspaceID,
|
|
||||||
parentID: null,
|
parentID: null,
|
||||||
limit: SESSION_PAGE_LIMIT,
|
limit: SESSION_PAGE_LIMIT,
|
||||||
order: "desc",
|
order: "desc",
|
||||||
|
|||||||
@@ -426,14 +426,13 @@ describe("runNonInteractivePrompt", () => {
|
|||||||
const globalOptions = {
|
const globalOptions = {
|
||||||
headers: {
|
headers: {
|
||||||
"x-opencode-directory": "%2Fwork%20tree",
|
"x-opencode-directory": "%2Fwork%20tree",
|
||||||
"x-opencode-workspace": "wrk_1",
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
expect(sdk.form.cancel).toHaveBeenCalledWith({ sessionID: "global", formID: "frm_live" }, globalOptions)
|
expect(sdk.form.cancel).toHaveBeenCalledWith({ sessionID: "global", formID: "frm_live" }, globalOptions)
|
||||||
expect(sdk.form.cancel).toHaveBeenCalledWith({ sessionID: "ses_1", formID: "frm_pending" })
|
expect(sdk.form.cancel).toHaveBeenCalledWith({ sessionID: "ses_1", formID: "frm_pending" })
|
||||||
expect(sdk.form.cancel).toHaveBeenCalledWith({ sessionID: "global", formID: "frm_pending_global" }, globalOptions)
|
expect(sdk.form.cancel).toHaveBeenCalledWith({ sessionID: "global", formID: "frm_pending_global" }, globalOptions)
|
||||||
expect(sdk.form.request.list).toHaveBeenCalledWith({
|
expect(sdk.form.request.list).toHaveBeenCalledWith({
|
||||||
location: { directory: "/work tree", workspace: "wrk_1" },
|
location: { directory: "/work tree" },
|
||||||
})
|
})
|
||||||
expect(sdk.question.list).not.toHaveBeenCalled()
|
expect(sdk.question.list).not.toHaveBeenCalled()
|
||||||
expect(sdk.question.reject).not.toHaveBeenCalled()
|
expect(sdk.question.reject).not.toHaveBeenCalled()
|
||||||
|
|||||||
@@ -3,13 +3,13 @@ import type { Effect, Stream } from "effect"
|
|||||||
import type { Location } from "@opencode-ai/schema/location"
|
import type { Location } from "@opencode-ai/schema/location"
|
||||||
import type { Agent } from "@opencode-ai/schema/agent"
|
import type { Agent } from "@opencode-ai/schema/agent"
|
||||||
import type { Plugin } from "@opencode-ai/schema/plugin"
|
import type { Plugin } from "@opencode-ai/schema/plugin"
|
||||||
import type { Workspace } from "@opencode-ai/schema/workspace"
|
|
||||||
import type { Session } from "@opencode-ai/schema/session"
|
import type { Session } from "@opencode-ai/schema/session"
|
||||||
import type { AbsolutePath } from "@opencode-ai/schema/schema"
|
import type { AbsolutePath } from "@opencode-ai/schema/schema"
|
||||||
import type { Project } from "@opencode-ai/schema/project"
|
import type { Project } from "@opencode-ai/schema/project"
|
||||||
import type { RelativePath } from "@opencode-ai/schema/schema"
|
import type { RelativePath } from "@opencode-ai/schema/schema"
|
||||||
import type { Brand } from "effect"
|
import type { Brand } from "effect"
|
||||||
import type { Model } from "@opencode-ai/schema/model"
|
import type { Model } from "@opencode-ai/schema/model"
|
||||||
|
import type { Workspace } from "@opencode-ai/schema/workspace"
|
||||||
import type { SessionMessage } from "@opencode-ai/schema/session-message"
|
import type { SessionMessage } from "@opencode-ai/schema/session-message"
|
||||||
import type { PromptInput } from "@opencode-ai/schema/prompt-input"
|
import type { PromptInput } from "@opencode-ai/schema/prompt-input"
|
||||||
import type { AgentAttachment } from "@opencode-ai/schema/prompt"
|
import type { AgentAttachment } from "@opencode-ai/schema/prompt"
|
||||||
@@ -58,9 +58,7 @@ export interface ServerApi<E = never> {
|
|||||||
readonly get: ServerGetOperation<E>
|
readonly get: ServerGetOperation<E>
|
||||||
}
|
}
|
||||||
|
|
||||||
export type Endpoint2_0Input = {
|
export type Endpoint2_0Input = { readonly location?: { readonly directory?: string | undefined } | undefined }
|
||||||
readonly location?: { readonly directory?: string | undefined; readonly workspace?: string | undefined } | undefined
|
|
||||||
}
|
|
||||||
export type Endpoint2_0Output = Location.Info
|
export type Endpoint2_0Output = Location.Info
|
||||||
export type LocationGetOperation<E = never> = (input?: Endpoint2_0Input) => Effect.Effect<Endpoint2_0Output, E>
|
export type LocationGetOperation<E = never> = (input?: Endpoint2_0Input) => Effect.Effect<Endpoint2_0Output, E>
|
||||||
|
|
||||||
@@ -68,15 +66,13 @@ export interface LocationApi<E = never> {
|
|||||||
readonly get: LocationGetOperation<E>
|
readonly get: LocationGetOperation<E>
|
||||||
}
|
}
|
||||||
|
|
||||||
export type Endpoint3_0Input = {
|
export type Endpoint3_0Input = { readonly location?: { readonly directory?: string | undefined } | undefined }
|
||||||
readonly location?: { readonly directory?: string | undefined; readonly workspace?: string | undefined } | undefined
|
|
||||||
}
|
|
||||||
export type Endpoint3_0Output = { readonly location: Location.Info; readonly data: ReadonlyArray<Agent.Info> }
|
export type Endpoint3_0Output = { readonly location: Location.Info; readonly data: ReadonlyArray<Agent.Info> }
|
||||||
export type AgentListOperation<E = never> = (input?: Endpoint3_0Input) => Effect.Effect<Endpoint3_0Output, E>
|
export type AgentListOperation<E = never> = (input?: Endpoint3_0Input) => Effect.Effect<Endpoint3_0Output, E>
|
||||||
|
|
||||||
export type Endpoint3_1Input = {
|
export type Endpoint3_1Input = {
|
||||||
readonly agentID: Agent.ID
|
readonly agentID: Agent.ID
|
||||||
readonly location?: { readonly directory?: string | undefined; readonly workspace?: string | undefined } | undefined
|
readonly location?: { readonly directory?: string | undefined } | undefined
|
||||||
}
|
}
|
||||||
export type Endpoint3_1Output = { readonly location: Location.Info; readonly data: Agent.Info }
|
export type Endpoint3_1Output = { readonly location: Location.Info; readonly data: Agent.Info }
|
||||||
export type AgentGetOperation<E = never> = (input: Endpoint3_1Input) => Effect.Effect<Endpoint3_1Output, E>
|
export type AgentGetOperation<E = never> = (input: Endpoint3_1Input) => Effect.Effect<Endpoint3_1Output, E>
|
||||||
@@ -86,9 +82,7 @@ export interface AgentApi<E = never> {
|
|||||||
readonly get: AgentGetOperation<E>
|
readonly get: AgentGetOperation<E>
|
||||||
}
|
}
|
||||||
|
|
||||||
export type Endpoint4_0Input = {
|
export type Endpoint4_0Input = { readonly location?: { readonly directory?: string | undefined } | undefined }
|
||||||
readonly location?: { readonly directory?: string | undefined; readonly workspace?: string | undefined } | undefined
|
|
||||||
}
|
|
||||||
export type Endpoint4_0Output = { readonly location: Location.Info; readonly data: ReadonlyArray<Plugin.Info> }
|
export type Endpoint4_0Output = { readonly location: Location.Info; readonly data: ReadonlyArray<Plugin.Info> }
|
||||||
export type PluginListOperation<E = never> = (input?: Endpoint4_0Input) => Effect.Effect<Endpoint4_0Output, E>
|
export type PluginListOperation<E = never> = (input?: Endpoint4_0Input) => Effect.Effect<Endpoint4_0Output, E>
|
||||||
|
|
||||||
@@ -97,7 +91,6 @@ export interface PluginApi<E = never> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export type Endpoint5_0Input = {
|
export type Endpoint5_0Input = {
|
||||||
readonly workspace?: Workspace.ID | undefined
|
|
||||||
readonly limit?: number | undefined
|
readonly limit?: number | undefined
|
||||||
readonly order?: "asc" | "desc" | undefined
|
readonly order?: "asc" | "desc" | undefined
|
||||||
readonly search?: string | undefined
|
readonly search?: string | undefined
|
||||||
@@ -898,15 +891,11 @@ export interface MessageApi<E = never> {
|
|||||||
readonly list: MessageListOperation<E>
|
readonly list: MessageListOperation<E>
|
||||||
}
|
}
|
||||||
|
|
||||||
export type Endpoint7_0Input = {
|
export type Endpoint7_0Input = { readonly location?: { readonly directory?: string | undefined } | undefined }
|
||||||
readonly location?: { readonly directory?: string | undefined; readonly workspace?: string | undefined } | undefined
|
|
||||||
}
|
|
||||||
export type Endpoint7_0Output = { readonly location: Location.Info; readonly data: ReadonlyArray<Model.Info> }
|
export type Endpoint7_0Output = { readonly location: Location.Info; readonly data: ReadonlyArray<Model.Info> }
|
||||||
export type ModelListOperation<E = never> = (input?: Endpoint7_0Input) => Effect.Effect<Endpoint7_0Output, E>
|
export type ModelListOperation<E = never> = (input?: Endpoint7_0Input) => Effect.Effect<Endpoint7_0Output, E>
|
||||||
|
|
||||||
export type Endpoint7_1Input = {
|
export type Endpoint7_1Input = { readonly location?: { readonly directory?: string | undefined } | undefined }
|
||||||
readonly location?: { readonly directory?: string | undefined; readonly workspace?: string | undefined } | undefined
|
|
||||||
}
|
|
||||||
export type Endpoint7_1Output = { readonly location: Location.Info; readonly data: Model.Info | undefined }
|
export type Endpoint7_1Output = { readonly location: Location.Info; readonly data: Model.Info | undefined }
|
||||||
export type ModelDefaultOperation<E = never> = (input?: Endpoint7_1Input) => Effect.Effect<Endpoint7_1Output, E>
|
export type ModelDefaultOperation<E = never> = (input?: Endpoint7_1Input) => Effect.Effect<Endpoint7_1Output, E>
|
||||||
|
|
||||||
@@ -916,7 +905,7 @@ export interface ModelApi<E = never> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export type Endpoint8_0Input = {
|
export type Endpoint8_0Input = {
|
||||||
readonly location?: { readonly directory?: string | undefined; readonly workspace?: string | undefined } | undefined
|
readonly location?: { readonly directory?: string | undefined } | undefined
|
||||||
readonly prompt: string
|
readonly prompt: string
|
||||||
readonly model?: Model.Ref | undefined
|
readonly model?: Model.Ref | undefined
|
||||||
}
|
}
|
||||||
@@ -927,15 +916,13 @@ export interface GenerateApi<E = never> {
|
|||||||
readonly text: GenerateTextOperation<E>
|
readonly text: GenerateTextOperation<E>
|
||||||
}
|
}
|
||||||
|
|
||||||
export type Endpoint9_0Input = {
|
export type Endpoint9_0Input = { readonly location?: { readonly directory?: string | undefined } | undefined }
|
||||||
readonly location?: { readonly directory?: string | undefined; readonly workspace?: string | undefined } | undefined
|
|
||||||
}
|
|
||||||
export type Endpoint9_0Output = { readonly location: Location.Info; readonly data: ReadonlyArray<Provider.Info> }
|
export type Endpoint9_0Output = { readonly location: Location.Info; readonly data: ReadonlyArray<Provider.Info> }
|
||||||
export type ProviderListOperation<E = never> = (input?: Endpoint9_0Input) => Effect.Effect<Endpoint9_0Output, E>
|
export type ProviderListOperation<E = never> = (input?: Endpoint9_0Input) => Effect.Effect<Endpoint9_0Output, E>
|
||||||
|
|
||||||
export type Endpoint9_1Input = {
|
export type Endpoint9_1Input = {
|
||||||
readonly providerID: Provider.ID
|
readonly providerID: Provider.ID
|
||||||
readonly location?: { readonly directory?: string | undefined; readonly workspace?: string | undefined } | undefined
|
readonly location?: { readonly directory?: string | undefined } | undefined
|
||||||
}
|
}
|
||||||
export type Endpoint9_1Output = { readonly location: Location.Info; readonly data: Provider.Info }
|
export type Endpoint9_1Output = { readonly location: Location.Info; readonly data: Provider.Info }
|
||||||
export type ProviderGetOperation<E = never> = (input: Endpoint9_1Input) => Effect.Effect<Endpoint9_1Output, E>
|
export type ProviderGetOperation<E = never> = (input: Endpoint9_1Input) => Effect.Effect<Endpoint9_1Output, E>
|
||||||
@@ -945,21 +932,19 @@ export interface ProviderApi<E = never> {
|
|||||||
readonly get: ProviderGetOperation<E>
|
readonly get: ProviderGetOperation<E>
|
||||||
}
|
}
|
||||||
|
|
||||||
export type Endpoint10_0Input = {
|
export type Endpoint10_0Input = { readonly location?: { readonly directory?: string | undefined } | undefined }
|
||||||
readonly location?: { readonly directory?: string | undefined; readonly workspace?: string | undefined } | undefined
|
|
||||||
}
|
|
||||||
export type Endpoint10_0Output = { readonly location: Location.Info; readonly data: ReadonlyArray<Integration.Info> }
|
export type Endpoint10_0Output = { readonly location: Location.Info; readonly data: ReadonlyArray<Integration.Info> }
|
||||||
export type IntegrationListOperation<E = never> = (input?: Endpoint10_0Input) => Effect.Effect<Endpoint10_0Output, E>
|
export type IntegrationListOperation<E = never> = (input?: Endpoint10_0Input) => Effect.Effect<Endpoint10_0Output, E>
|
||||||
|
|
||||||
export type Endpoint10_1Input = {
|
export type Endpoint10_1Input = {
|
||||||
readonly integrationID: Integration.ID
|
readonly integrationID: Integration.ID
|
||||||
readonly location?: { readonly directory?: string | undefined; readonly workspace?: string | undefined } | undefined
|
readonly location?: { readonly directory?: string | undefined } | undefined
|
||||||
}
|
}
|
||||||
export type Endpoint10_1Output = { readonly location: Location.Info; readonly data: Integration.Info | undefined }
|
export type Endpoint10_1Output = { readonly location: Location.Info; readonly data: Integration.Info | undefined }
|
||||||
export type IntegrationGetOperation<E = never> = (input: Endpoint10_1Input) => Effect.Effect<Endpoint10_1Output, E>
|
export type IntegrationGetOperation<E = never> = (input: Endpoint10_1Input) => Effect.Effect<Endpoint10_1Output, E>
|
||||||
|
|
||||||
export type Endpoint10_2Input = {
|
export type Endpoint10_2Input = {
|
||||||
readonly location?: { readonly directory?: string | undefined; readonly workspace?: string | undefined } | undefined
|
readonly location?: { readonly directory?: string | undefined } | undefined
|
||||||
readonly url: string
|
readonly url: string
|
||||||
}
|
}
|
||||||
export type Endpoint10_2Output = void
|
export type Endpoint10_2Output = void
|
||||||
@@ -969,7 +954,7 @@ export type IntegrationWellknownAddOperation<E = never> = (
|
|||||||
|
|
||||||
export type Endpoint10_3Input = {
|
export type Endpoint10_3Input = {
|
||||||
readonly integrationID: Integration.ID
|
readonly integrationID: Integration.ID
|
||||||
readonly location?: { readonly directory?: string | undefined; readonly workspace?: string | undefined } | undefined
|
readonly location?: { readonly directory?: string | undefined } | undefined
|
||||||
readonly key: string
|
readonly key: string
|
||||||
readonly label?: string | undefined
|
readonly label?: string | undefined
|
||||||
}
|
}
|
||||||
@@ -980,7 +965,7 @@ export type IntegrationConnectKeyOperation<E = never> = (
|
|||||||
|
|
||||||
export type Endpoint10_4Input = {
|
export type Endpoint10_4Input = {
|
||||||
readonly integrationID: Integration.ID
|
readonly integrationID: Integration.ID
|
||||||
readonly location?: { readonly directory?: string | undefined; readonly workspace?: string | undefined } | undefined
|
readonly location?: { readonly directory?: string | undefined } | undefined
|
||||||
readonly methodID: Integration.MethodID
|
readonly methodID: Integration.MethodID
|
||||||
readonly inputs: { readonly [x: string]: string }
|
readonly inputs: { readonly [x: string]: string }
|
||||||
readonly label?: string | undefined
|
readonly label?: string | undefined
|
||||||
@@ -993,7 +978,7 @@ export type IntegrationOauthConnectOperation<E = never> = (
|
|||||||
export type Endpoint10_5Input = {
|
export type Endpoint10_5Input = {
|
||||||
readonly integrationID: Integration.ID
|
readonly integrationID: Integration.ID
|
||||||
readonly attemptID: Integration.AttemptID
|
readonly attemptID: Integration.AttemptID
|
||||||
readonly location?: { readonly directory?: string | undefined; readonly workspace?: string | undefined } | undefined
|
readonly location?: { readonly directory?: string | undefined } | undefined
|
||||||
}
|
}
|
||||||
export type Endpoint10_5Output = { readonly location: Location.Info; readonly data: Integration.AttemptStatus }
|
export type Endpoint10_5Output = { readonly location: Location.Info; readonly data: Integration.AttemptStatus }
|
||||||
export type IntegrationOauthStatusOperation<E = never> = (
|
export type IntegrationOauthStatusOperation<E = never> = (
|
||||||
@@ -1003,7 +988,7 @@ export type IntegrationOauthStatusOperation<E = never> = (
|
|||||||
export type Endpoint10_6Input = {
|
export type Endpoint10_6Input = {
|
||||||
readonly integrationID: Integration.ID
|
readonly integrationID: Integration.ID
|
||||||
readonly attemptID: Integration.AttemptID
|
readonly attemptID: Integration.AttemptID
|
||||||
readonly location?: { readonly directory?: string | undefined; readonly workspace?: string | undefined } | undefined
|
readonly location?: { readonly directory?: string | undefined } | undefined
|
||||||
readonly code?: string | undefined
|
readonly code?: string | undefined
|
||||||
}
|
}
|
||||||
export type Endpoint10_6Output = void
|
export type Endpoint10_6Output = void
|
||||||
@@ -1014,7 +999,7 @@ export type IntegrationOauthCompleteOperation<E = never> = (
|
|||||||
export type Endpoint10_7Input = {
|
export type Endpoint10_7Input = {
|
||||||
readonly integrationID: Integration.ID
|
readonly integrationID: Integration.ID
|
||||||
readonly attemptID: Integration.AttemptID
|
readonly attemptID: Integration.AttemptID
|
||||||
readonly location?: { readonly directory?: string | undefined; readonly workspace?: string | undefined } | undefined
|
readonly location?: { readonly directory?: string | undefined } | undefined
|
||||||
}
|
}
|
||||||
export type Endpoint10_7Output = void
|
export type Endpoint10_7Output = void
|
||||||
export type IntegrationOauthCancelOperation<E = never> = (
|
export type IntegrationOauthCancelOperation<E = never> = (
|
||||||
@@ -1023,7 +1008,7 @@ export type IntegrationOauthCancelOperation<E = never> = (
|
|||||||
|
|
||||||
export type Endpoint10_8Input = {
|
export type Endpoint10_8Input = {
|
||||||
readonly integrationID: Integration.ID
|
readonly integrationID: Integration.ID
|
||||||
readonly location?: { readonly directory?: string | undefined; readonly workspace?: string | undefined } | undefined
|
readonly location?: { readonly directory?: string | undefined } | undefined
|
||||||
readonly methodID: Integration.MethodID
|
readonly methodID: Integration.MethodID
|
||||||
readonly label?: string | undefined
|
readonly label?: string | undefined
|
||||||
}
|
}
|
||||||
@@ -1035,7 +1020,7 @@ export type IntegrationCommandConnectOperation<E = never> = (
|
|||||||
export type Endpoint10_9Input = {
|
export type Endpoint10_9Input = {
|
||||||
readonly integrationID: Integration.ID
|
readonly integrationID: Integration.ID
|
||||||
readonly attemptID: Integration.AttemptID
|
readonly attemptID: Integration.AttemptID
|
||||||
readonly location?: { readonly directory?: string | undefined; readonly workspace?: string | undefined } | undefined
|
readonly location?: { readonly directory?: string | undefined } | undefined
|
||||||
}
|
}
|
||||||
export type Endpoint10_9Output = { readonly location: Location.Info; readonly data: Integration.CommandAttemptStatus }
|
export type Endpoint10_9Output = { readonly location: Location.Info; readonly data: Integration.CommandAttemptStatus }
|
||||||
export type IntegrationCommandStatusOperation<E = never> = (
|
export type IntegrationCommandStatusOperation<E = never> = (
|
||||||
@@ -1045,7 +1030,7 @@ export type IntegrationCommandStatusOperation<E = never> = (
|
|||||||
export type Endpoint10_10Input = {
|
export type Endpoint10_10Input = {
|
||||||
readonly integrationID: Integration.ID
|
readonly integrationID: Integration.ID
|
||||||
readonly attemptID: Integration.AttemptID
|
readonly attemptID: Integration.AttemptID
|
||||||
readonly location?: { readonly directory?: string | undefined; readonly workspace?: string | undefined } | undefined
|
readonly location?: { readonly directory?: string | undefined } | undefined
|
||||||
}
|
}
|
||||||
export type Endpoint10_10Output = void
|
export type Endpoint10_10Output = void
|
||||||
export type IntegrationCommandCancelOperation<E = never> = (
|
export type IntegrationCommandCancelOperation<E = never> = (
|
||||||
@@ -1070,15 +1055,13 @@ export interface IntegrationApi<E = never> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export type Endpoint11_0Input = {
|
export type Endpoint11_0Input = { readonly location?: { readonly directory?: string | undefined } | undefined }
|
||||||
readonly location?: { readonly directory?: string | undefined; readonly workspace?: string | undefined } | undefined
|
|
||||||
}
|
|
||||||
export type Endpoint11_0Output = { readonly location: Location.Info; readonly data: ReadonlyArray<Mcp.Server> }
|
export type Endpoint11_0Output = { readonly location: Location.Info; readonly data: ReadonlyArray<Mcp.Server> }
|
||||||
export type McpListOperation<E = never> = (input?: Endpoint11_0Input) => Effect.Effect<Endpoint11_0Output, E>
|
export type McpListOperation<E = never> = (input?: Endpoint11_0Input) => Effect.Effect<Endpoint11_0Output, E>
|
||||||
|
|
||||||
export type Endpoint11_1Input = {
|
export type Endpoint11_1Input = {
|
||||||
readonly server: string
|
readonly server: string
|
||||||
readonly location?: { readonly directory?: string | undefined; readonly workspace?: string | undefined } | undefined
|
readonly location?: { readonly directory?: string | undefined } | undefined
|
||||||
readonly config: Mcp.LocalConfig | Mcp.RemoteConfig
|
readonly config: Mcp.LocalConfig | Mcp.RemoteConfig
|
||||||
}
|
}
|
||||||
export type Endpoint11_1Output = void
|
export type Endpoint11_1Output = void
|
||||||
@@ -1086,28 +1069,26 @@ export type McpAddOperation<E = never> = (input: Endpoint11_1Input) => Effect.Ef
|
|||||||
|
|
||||||
export type Endpoint11_2Input = {
|
export type Endpoint11_2Input = {
|
||||||
readonly server: string
|
readonly server: string
|
||||||
readonly location?: { readonly directory?: string | undefined; readonly workspace?: string | undefined } | undefined
|
readonly location?: { readonly directory?: string | undefined } | undefined
|
||||||
}
|
}
|
||||||
export type Endpoint11_2Output = void
|
export type Endpoint11_2Output = void
|
||||||
export type McpRemoveOperation<E = never> = (input: Endpoint11_2Input) => Effect.Effect<Endpoint11_2Output, E>
|
export type McpRemoveOperation<E = never> = (input: Endpoint11_2Input) => Effect.Effect<Endpoint11_2Output, E>
|
||||||
|
|
||||||
export type Endpoint11_3Input = {
|
export type Endpoint11_3Input = {
|
||||||
readonly server: string
|
readonly server: string
|
||||||
readonly location?: { readonly directory?: string | undefined; readonly workspace?: string | undefined } | undefined
|
readonly location?: { readonly directory?: string | undefined } | undefined
|
||||||
}
|
}
|
||||||
export type Endpoint11_3Output = void
|
export type Endpoint11_3Output = void
|
||||||
export type McpConnectOperation<E = never> = (input: Endpoint11_3Input) => Effect.Effect<Endpoint11_3Output, E>
|
export type McpConnectOperation<E = never> = (input: Endpoint11_3Input) => Effect.Effect<Endpoint11_3Output, E>
|
||||||
|
|
||||||
export type Endpoint11_4Input = {
|
export type Endpoint11_4Input = {
|
||||||
readonly server: string
|
readonly server: string
|
||||||
readonly location?: { readonly directory?: string | undefined; readonly workspace?: string | undefined } | undefined
|
readonly location?: { readonly directory?: string | undefined } | undefined
|
||||||
}
|
}
|
||||||
export type Endpoint11_4Output = void
|
export type Endpoint11_4Output = void
|
||||||
export type McpDisconnectOperation<E = never> = (input: Endpoint11_4Input) => Effect.Effect<Endpoint11_4Output, E>
|
export type McpDisconnectOperation<E = never> = (input: Endpoint11_4Input) => Effect.Effect<Endpoint11_4Output, E>
|
||||||
|
|
||||||
export type Endpoint11_5Input = {
|
export type Endpoint11_5Input = { readonly location?: { readonly directory?: string | undefined } | undefined }
|
||||||
readonly location?: { readonly directory?: string | undefined; readonly workspace?: string | undefined } | undefined
|
|
||||||
}
|
|
||||||
export type Endpoint11_5Output = { readonly location: Location.Info; readonly data: Mcp.ResourceCatalog }
|
export type Endpoint11_5Output = { readonly location: Location.Info; readonly data: Mcp.ResourceCatalog }
|
||||||
export type McpResourceCatalogOperation<E = never> = (input?: Endpoint11_5Input) => Effect.Effect<Endpoint11_5Output, E>
|
export type McpResourceCatalogOperation<E = never> = (input?: Endpoint11_5Input) => Effect.Effect<Endpoint11_5Output, E>
|
||||||
|
|
||||||
@@ -1122,7 +1103,7 @@ export interface McpApi<E = never> {
|
|||||||
|
|
||||||
export type Endpoint12_0Input = {
|
export type Endpoint12_0Input = {
|
||||||
readonly credentialID: Credential.ID
|
readonly credentialID: Credential.ID
|
||||||
readonly location?: { readonly directory?: string | undefined; readonly workspace?: string | undefined } | undefined
|
readonly location?: { readonly directory?: string | undefined } | undefined
|
||||||
readonly label: string
|
readonly label: string
|
||||||
}
|
}
|
||||||
export type Endpoint12_0Output = void
|
export type Endpoint12_0Output = void
|
||||||
@@ -1130,7 +1111,7 @@ export type CredentialUpdateOperation<E = never> = (input: Endpoint12_0Input) =>
|
|||||||
|
|
||||||
export type Endpoint12_1Input = {
|
export type Endpoint12_1Input = {
|
||||||
readonly credentialID: Credential.ID
|
readonly credentialID: Credential.ID
|
||||||
readonly location?: { readonly directory?: string | undefined; readonly workspace?: string | undefined } | undefined
|
readonly location?: { readonly directory?: string | undefined } | undefined
|
||||||
}
|
}
|
||||||
export type Endpoint12_1Output = void
|
export type Endpoint12_1Output = void
|
||||||
export type CredentialRemoveOperation<E = never> = (input: Endpoint12_1Input) => Effect.Effect<Endpoint12_1Output, E>
|
export type CredentialRemoveOperation<E = never> = (input: Endpoint12_1Input) => Effect.Effect<Endpoint12_1Output, E>
|
||||||
@@ -1143,15 +1124,13 @@ export interface CredentialApi<E = never> {
|
|||||||
export type Endpoint13_0Output = ReadonlyArray<Project.Info>
|
export type Endpoint13_0Output = ReadonlyArray<Project.Info>
|
||||||
export type ProjectListOperation<E = never> = () => Effect.Effect<Endpoint13_0Output, E>
|
export type ProjectListOperation<E = never> = () => Effect.Effect<Endpoint13_0Output, E>
|
||||||
|
|
||||||
export type Endpoint13_1Input = {
|
export type Endpoint13_1Input = { readonly location?: { readonly directory?: string | undefined } | undefined }
|
||||||
readonly location?: { readonly directory?: string | undefined; readonly workspace?: string | undefined } | undefined
|
|
||||||
}
|
|
||||||
export type Endpoint13_1Output = Project.Current
|
export type Endpoint13_1Output = Project.Current
|
||||||
export type ProjectCurrentOperation<E = never> = (input?: Endpoint13_1Input) => Effect.Effect<Endpoint13_1Output, E>
|
export type ProjectCurrentOperation<E = never> = (input?: Endpoint13_1Input) => Effect.Effect<Endpoint13_1Output, E>
|
||||||
|
|
||||||
export type Endpoint13_2Input = {
|
export type Endpoint13_2Input = {
|
||||||
readonly projectID: Project.ID
|
readonly projectID: Project.ID
|
||||||
readonly location?: { readonly directory?: string | undefined; readonly workspace?: string | undefined } | undefined
|
readonly location?: { readonly directory?: string | undefined } | undefined
|
||||||
}
|
}
|
||||||
export type Endpoint13_2Output = Project.Directories
|
export type Endpoint13_2Output = Project.Directories
|
||||||
export type ProjectDirectoriesOperation<E = never> = (input: Endpoint13_2Input) => Effect.Effect<Endpoint13_2Output, E>
|
export type ProjectDirectoriesOperation<E = never> = (input: Endpoint13_2Input) => Effect.Effect<Endpoint13_2Output, E>
|
||||||
@@ -1162,9 +1141,7 @@ export interface ProjectApi<E = never> {
|
|||||||
readonly directories: ProjectDirectoriesOperation<E>
|
readonly directories: ProjectDirectoriesOperation<E>
|
||||||
}
|
}
|
||||||
|
|
||||||
export type Endpoint14_0Input = {
|
export type Endpoint14_0Input = { readonly location?: { readonly directory?: string | undefined } | undefined }
|
||||||
readonly location?: { readonly directory?: string | undefined; readonly workspace?: string | undefined } | undefined
|
|
||||||
}
|
|
||||||
export type Endpoint14_0Output = { readonly location: Location.Info; readonly data: ReadonlyArray<Form.Info> }
|
export type Endpoint14_0Output = { readonly location: Location.Info; readonly data: ReadonlyArray<Form.Info> }
|
||||||
export type FormRequestListOperation<E = never> = (input?: Endpoint14_0Input) => Effect.Effect<Endpoint14_0Output, E>
|
export type FormRequestListOperation<E = never> = (input?: Endpoint14_0Input) => Effect.Effect<Endpoint14_0Output, E>
|
||||||
|
|
||||||
@@ -1208,9 +1185,7 @@ export interface FormApi<E = never> {
|
|||||||
readonly cancel: FormCancelOperation<E>
|
readonly cancel: FormCancelOperation<E>
|
||||||
}
|
}
|
||||||
|
|
||||||
export type Endpoint15_0Input = {
|
export type Endpoint15_0Input = { readonly location?: { readonly directory?: string | undefined } | undefined }
|
||||||
readonly location?: { readonly directory?: string | undefined; readonly workspace?: string | undefined } | undefined
|
|
||||||
}
|
|
||||||
export type Endpoint15_0Output = { readonly location: Location.Info; readonly data: ReadonlyArray<Permission.Request> }
|
export type Endpoint15_0Output = { readonly location: Location.Info; readonly data: ReadonlyArray<Permission.Request> }
|
||||||
export type PermissionRequestListOperation<E = never> = (
|
export type PermissionRequestListOperation<E = never> = (
|
||||||
input?: Endpoint15_0Input,
|
input?: Endpoint15_0Input,
|
||||||
@@ -1268,14 +1243,14 @@ export interface PermissionApi<E = never> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export type Endpoint16_0Input = {
|
export type Endpoint16_0Input = {
|
||||||
readonly location?: { readonly directory?: string | undefined; readonly workspace?: string | undefined } | undefined
|
readonly location?: { readonly directory?: string | undefined } | undefined
|
||||||
readonly path?: RelativePath | undefined
|
readonly path?: RelativePath | undefined
|
||||||
}
|
}
|
||||||
export type Endpoint16_0Output = { readonly location: Location.Info; readonly data: ReadonlyArray<FileSystem.Entry> }
|
export type Endpoint16_0Output = { readonly location: Location.Info; readonly data: ReadonlyArray<FileSystem.Entry> }
|
||||||
export type FileListOperation<E = never> = (input?: Endpoint16_0Input) => Effect.Effect<Endpoint16_0Output, E>
|
export type FileListOperation<E = never> = (input?: Endpoint16_0Input) => Effect.Effect<Endpoint16_0Output, E>
|
||||||
|
|
||||||
export type Endpoint16_1Input = {
|
export type Endpoint16_1Input = {
|
||||||
readonly location?: { readonly directory?: string | undefined; readonly workspace?: string | undefined } | undefined
|
readonly location?: { readonly directory?: string | undefined } | undefined
|
||||||
readonly query: string
|
readonly query: string
|
||||||
readonly type?: "file" | "directory" | undefined
|
readonly type?: "file" | "directory" | undefined
|
||||||
readonly limit?: number | undefined
|
readonly limit?: number | undefined
|
||||||
@@ -1288,9 +1263,7 @@ export interface FileApi<E = never> {
|
|||||||
readonly find: FileFindOperation<E>
|
readonly find: FileFindOperation<E>
|
||||||
}
|
}
|
||||||
|
|
||||||
export type Endpoint17_0Input = {
|
export type Endpoint17_0Input = { readonly location?: { readonly directory?: string | undefined } | undefined }
|
||||||
readonly location?: { readonly directory?: string | undefined; readonly workspace?: string | undefined } | undefined
|
|
||||||
}
|
|
||||||
export type Endpoint17_0Output = { readonly location: Location.Info; readonly data: ReadonlyArray<Command.Info> }
|
export type Endpoint17_0Output = { readonly location: Location.Info; readonly data: ReadonlyArray<Command.Info> }
|
||||||
export type CommandListOperation<E = never> = (input?: Endpoint17_0Input) => Effect.Effect<Endpoint17_0Output, E>
|
export type CommandListOperation<E = never> = (input?: Endpoint17_0Input) => Effect.Effect<Endpoint17_0Output, E>
|
||||||
|
|
||||||
@@ -1298,9 +1271,7 @@ export interface CommandApi<E = never> {
|
|||||||
readonly list: CommandListOperation<E>
|
readonly list: CommandListOperation<E>
|
||||||
}
|
}
|
||||||
|
|
||||||
export type Endpoint18_0Input = {
|
export type Endpoint18_0Input = { readonly location?: { readonly directory?: string | undefined } | undefined }
|
||||||
readonly location?: { readonly directory?: string | undefined; readonly workspace?: string | undefined } | undefined
|
|
||||||
}
|
|
||||||
export type Endpoint18_0Output = { readonly location: Location.Info; readonly data: ReadonlyArray<Skill.Info> }
|
export type Endpoint18_0Output = { readonly location: Location.Info; readonly data: ReadonlyArray<Skill.Info> }
|
||||||
export type SkillListOperation<E = never> = (input?: Endpoint18_0Input) => Effect.Effect<Endpoint18_0Output, E>
|
export type SkillListOperation<E = never> = (input?: Endpoint18_0Input) => Effect.Effect<Endpoint18_0Output, E>
|
||||||
|
|
||||||
@@ -1315,14 +1286,12 @@ export interface EventApi<E = never> {
|
|||||||
readonly subscribe: EventSubscribeOperation<E>
|
readonly subscribe: EventSubscribeOperation<E>
|
||||||
}
|
}
|
||||||
|
|
||||||
export type Endpoint20_0Input = {
|
export type Endpoint20_0Input = { readonly location?: { readonly directory?: string | undefined } | undefined }
|
||||||
readonly location?: { readonly directory?: string | undefined; readonly workspace?: string | undefined } | undefined
|
|
||||||
}
|
|
||||||
export type Endpoint20_0Output = { readonly location: Location.Info; readonly data: ReadonlyArray<Pty.Info> }
|
export type Endpoint20_0Output = { readonly location: Location.Info; readonly data: ReadonlyArray<Pty.Info> }
|
||||||
export type PtyListOperation<E = never> = (input?: Endpoint20_0Input) => Effect.Effect<Endpoint20_0Output, E>
|
export type PtyListOperation<E = never> = (input?: Endpoint20_0Input) => Effect.Effect<Endpoint20_0Output, E>
|
||||||
|
|
||||||
export type Endpoint20_1Input = {
|
export type Endpoint20_1Input = {
|
||||||
readonly location?: { readonly directory?: string | undefined; readonly workspace?: string | undefined } | undefined
|
readonly location?: { readonly directory?: string | undefined } | undefined
|
||||||
readonly command?: string | undefined
|
readonly command?: string | undefined
|
||||||
readonly args?: ReadonlyArray<string> | undefined
|
readonly args?: ReadonlyArray<string> | undefined
|
||||||
readonly cwd?: string | undefined
|
readonly cwd?: string | undefined
|
||||||
@@ -1334,14 +1303,14 @@ export type PtyCreateOperation<E = never> = (input?: Endpoint20_1Input) => Effec
|
|||||||
|
|
||||||
export type Endpoint20_2Input = {
|
export type Endpoint20_2Input = {
|
||||||
readonly ptyID: Pty.ID
|
readonly ptyID: Pty.ID
|
||||||
readonly location?: { readonly directory?: string | undefined; readonly workspace?: string | undefined } | undefined
|
readonly location?: { readonly directory?: string | undefined } | undefined
|
||||||
}
|
}
|
||||||
export type Endpoint20_2Output = { readonly location: Location.Info; readonly data: Pty.Info }
|
export type Endpoint20_2Output = { readonly location: Location.Info; readonly data: Pty.Info }
|
||||||
export type PtyGetOperation<E = never> = (input: Endpoint20_2Input) => Effect.Effect<Endpoint20_2Output, E>
|
export type PtyGetOperation<E = never> = (input: Endpoint20_2Input) => Effect.Effect<Endpoint20_2Output, E>
|
||||||
|
|
||||||
export type Endpoint20_3Input = {
|
export type Endpoint20_3Input = {
|
||||||
readonly ptyID: Pty.ID
|
readonly ptyID: Pty.ID
|
||||||
readonly location?: { readonly directory?: string | undefined; readonly workspace?: string | undefined } | undefined
|
readonly location?: { readonly directory?: string | undefined } | undefined
|
||||||
readonly title?: string | undefined
|
readonly title?: string | undefined
|
||||||
readonly size?: { readonly rows: number; readonly cols: number } | undefined
|
readonly size?: { readonly rows: number; readonly cols: number } | undefined
|
||||||
}
|
}
|
||||||
@@ -1350,7 +1319,7 @@ export type PtyUpdateOperation<E = never> = (input: Endpoint20_3Input) => Effect
|
|||||||
|
|
||||||
export type Endpoint20_4Input = {
|
export type Endpoint20_4Input = {
|
||||||
readonly ptyID: Pty.ID
|
readonly ptyID: Pty.ID
|
||||||
readonly location?: { readonly directory?: string | undefined; readonly workspace?: string | undefined } | undefined
|
readonly location?: { readonly directory?: string | undefined } | undefined
|
||||||
}
|
}
|
||||||
export type Endpoint20_4Output = void
|
export type Endpoint20_4Output = void
|
||||||
export type PtyRemoveOperation<E = never> = (input: Endpoint20_4Input) => Effect.Effect<Endpoint20_4Output, E>
|
export type PtyRemoveOperation<E = never> = (input: Endpoint20_4Input) => Effect.Effect<Endpoint20_4Output, E>
|
||||||
@@ -1363,14 +1332,12 @@ export interface PtyApi<E = never> {
|
|||||||
readonly remove: PtyRemoveOperation<E>
|
readonly remove: PtyRemoveOperation<E>
|
||||||
}
|
}
|
||||||
|
|
||||||
export type Endpoint21_0Input = {
|
export type Endpoint21_0Input = { readonly location?: { readonly directory?: string | undefined } | undefined }
|
||||||
readonly location?: { readonly directory?: string | undefined; readonly workspace?: string | undefined } | undefined
|
|
||||||
}
|
|
||||||
export type Endpoint21_0Output = { readonly location: Location.Info; readonly data: ReadonlyArray<Shell.Info> }
|
export type Endpoint21_0Output = { readonly location: Location.Info; readonly data: ReadonlyArray<Shell.Info> }
|
||||||
export type ShellListOperation<E = never> = (input?: Endpoint21_0Input) => Effect.Effect<Endpoint21_0Output, E>
|
export type ShellListOperation<E = never> = (input?: Endpoint21_0Input) => Effect.Effect<Endpoint21_0Output, E>
|
||||||
|
|
||||||
export type Endpoint21_1Input = {
|
export type Endpoint21_1Input = {
|
||||||
readonly location?: { readonly directory?: string | undefined; readonly workspace?: string | undefined } | undefined
|
readonly location?: { readonly directory?: string | undefined } | undefined
|
||||||
readonly command: string
|
readonly command: string
|
||||||
readonly cwd?: string | undefined
|
readonly cwd?: string | undefined
|
||||||
readonly timeout: number
|
readonly timeout: number
|
||||||
@@ -1381,14 +1348,14 @@ export type ShellCreateOperation<E = never> = (input: Endpoint21_1Input) => Effe
|
|||||||
|
|
||||||
export type Endpoint21_2Input = {
|
export type Endpoint21_2Input = {
|
||||||
readonly id: Shell.ID
|
readonly id: Shell.ID
|
||||||
readonly location?: { readonly directory?: string | undefined; readonly workspace?: string | undefined } | undefined
|
readonly location?: { readonly directory?: string | undefined } | undefined
|
||||||
}
|
}
|
||||||
export type Endpoint21_2Output = { readonly location: Location.Info; readonly data: Shell.Info }
|
export type Endpoint21_2Output = { readonly location: Location.Info; readonly data: Shell.Info }
|
||||||
export type ShellGetOperation<E = never> = (input: Endpoint21_2Input) => Effect.Effect<Endpoint21_2Output, E>
|
export type ShellGetOperation<E = never> = (input: Endpoint21_2Input) => Effect.Effect<Endpoint21_2Output, E>
|
||||||
|
|
||||||
export type Endpoint21_3Input = {
|
export type Endpoint21_3Input = {
|
||||||
readonly id: Shell.ID
|
readonly id: Shell.ID
|
||||||
readonly location?: { readonly directory?: string | undefined; readonly workspace?: string | undefined } | undefined
|
readonly location?: { readonly directory?: string | undefined } | undefined
|
||||||
readonly timeout: number
|
readonly timeout: number
|
||||||
}
|
}
|
||||||
export type Endpoint21_3Output = { readonly location: Location.Info; readonly data: Shell.Info }
|
export type Endpoint21_3Output = { readonly location: Location.Info; readonly data: Shell.Info }
|
||||||
@@ -1396,7 +1363,7 @@ export type ShellTimeoutOperation<E = never> = (input: Endpoint21_3Input) => Eff
|
|||||||
|
|
||||||
export type Endpoint21_4Input = {
|
export type Endpoint21_4Input = {
|
||||||
readonly id: Shell.ID
|
readonly id: Shell.ID
|
||||||
readonly location?: { readonly directory?: string | undefined; readonly workspace?: string | undefined } | undefined
|
readonly location?: { readonly directory?: string | undefined } | undefined
|
||||||
readonly cursor?: number | undefined
|
readonly cursor?: number | undefined
|
||||||
readonly limit?: number | undefined
|
readonly limit?: number | undefined
|
||||||
}
|
}
|
||||||
@@ -1413,7 +1380,7 @@ export type ShellOutputOperation<E = never> = (input: Endpoint21_4Input) => Effe
|
|||||||
|
|
||||||
export type Endpoint21_5Input = {
|
export type Endpoint21_5Input = {
|
||||||
readonly id: Shell.ID
|
readonly id: Shell.ID
|
||||||
readonly location?: { readonly directory?: string | undefined; readonly workspace?: string | undefined } | undefined
|
readonly location?: { readonly directory?: string | undefined } | undefined
|
||||||
}
|
}
|
||||||
export type Endpoint21_5Output = void
|
export type Endpoint21_5Output = void
|
||||||
export type ShellRemoveOperation<E = never> = (input: Endpoint21_5Input) => Effect.Effect<Endpoint21_5Output, E>
|
export type ShellRemoveOperation<E = never> = (input: Endpoint21_5Input) => Effect.Effect<Endpoint21_5Output, E>
|
||||||
@@ -1427,9 +1394,7 @@ export interface ShellApi<E = never> {
|
|||||||
readonly remove: ShellRemoveOperation<E>
|
readonly remove: ShellRemoveOperation<E>
|
||||||
}
|
}
|
||||||
|
|
||||||
export type Endpoint22_0Input = {
|
export type Endpoint22_0Input = { readonly location?: { readonly directory?: string | undefined } | undefined }
|
||||||
readonly location?: { readonly directory?: string | undefined; readonly workspace?: string | undefined } | undefined
|
|
||||||
}
|
|
||||||
export type Endpoint22_0Output = { readonly location: Location.Info; readonly data: ReadonlyArray<Question.Request> }
|
export type Endpoint22_0Output = { readonly location: Location.Info; readonly data: ReadonlyArray<Question.Request> }
|
||||||
export type QuestionRequestListOperation<E = never> = (
|
export type QuestionRequestListOperation<E = never> = (
|
||||||
input?: Endpoint22_0Input,
|
input?: Endpoint22_0Input,
|
||||||
@@ -1458,9 +1423,7 @@ export interface QuestionApi<E = never> {
|
|||||||
readonly reject: QuestionRejectOperation<E>
|
readonly reject: QuestionRejectOperation<E>
|
||||||
}
|
}
|
||||||
|
|
||||||
export type Endpoint23_0Input = {
|
export type Endpoint23_0Input = { readonly location?: { readonly directory?: string | undefined } | undefined }
|
||||||
readonly location?: { readonly directory?: string | undefined; readonly workspace?: string | undefined } | undefined
|
|
||||||
}
|
|
||||||
export type Endpoint23_0Output = { readonly location: Location.Info; readonly data: ReadonlyArray<Reference.Info> }
|
export type Endpoint23_0Output = { readonly location: Location.Info; readonly data: ReadonlyArray<Reference.Info> }
|
||||||
export type ReferenceListOperation<E = never> = (input?: Endpoint23_0Input) => Effect.Effect<Endpoint23_0Output, E>
|
export type ReferenceListOperation<E = never> = (input?: Endpoint23_0Input) => Effect.Effect<Endpoint23_0Output, E>
|
||||||
|
|
||||||
@@ -1470,7 +1433,7 @@ export interface ReferenceApi<E = never> {
|
|||||||
|
|
||||||
export type Endpoint24_0Input = {
|
export type Endpoint24_0Input = {
|
||||||
readonly projectID: Project.ID
|
readonly projectID: Project.ID
|
||||||
readonly location?: { readonly directory?: string | undefined; readonly workspace?: string | undefined } | undefined
|
readonly location?: { readonly directory?: string | undefined } | undefined
|
||||||
readonly strategy: ProjectCopy.StrategyID
|
readonly strategy: ProjectCopy.StrategyID
|
||||||
readonly directory: AbsolutePath
|
readonly directory: AbsolutePath
|
||||||
readonly name?: string | undefined
|
readonly name?: string | undefined
|
||||||
@@ -1480,7 +1443,7 @@ export type ProjectCopyCreateOperation<E = never> = (input: Endpoint24_0Input) =
|
|||||||
|
|
||||||
export type Endpoint24_1Input = {
|
export type Endpoint24_1Input = {
|
||||||
readonly projectID: Project.ID
|
readonly projectID: Project.ID
|
||||||
readonly location?: { readonly directory?: string | undefined; readonly workspace?: string | undefined } | undefined
|
readonly location?: { readonly directory?: string | undefined } | undefined
|
||||||
readonly directory: AbsolutePath
|
readonly directory: AbsolutePath
|
||||||
readonly force: boolean
|
readonly force: boolean
|
||||||
}
|
}
|
||||||
@@ -1489,7 +1452,7 @@ export type ProjectCopyRemoveOperation<E = never> = (input: Endpoint24_1Input) =
|
|||||||
|
|
||||||
export type Endpoint24_2Input = {
|
export type Endpoint24_2Input = {
|
||||||
readonly projectID: Project.ID
|
readonly projectID: Project.ID
|
||||||
readonly location?: { readonly directory?: string | undefined; readonly workspace?: string | undefined } | undefined
|
readonly location?: { readonly directory?: string | undefined } | undefined
|
||||||
}
|
}
|
||||||
export type Endpoint24_2Output = void
|
export type Endpoint24_2Output = void
|
||||||
export type ProjectCopyRefreshOperation<E = never> = (input: Endpoint24_2Input) => Effect.Effect<Endpoint24_2Output, E>
|
export type ProjectCopyRefreshOperation<E = never> = (input: Endpoint24_2Input) => Effect.Effect<Endpoint24_2Output, E>
|
||||||
@@ -1500,20 +1463,16 @@ export interface ProjectCopyApi<E = never> {
|
|||||||
readonly refresh: ProjectCopyRefreshOperation<E>
|
readonly refresh: ProjectCopyRefreshOperation<E>
|
||||||
}
|
}
|
||||||
|
|
||||||
export type Endpoint25_0Input = {
|
export type Endpoint25_0Input = { readonly location?: { readonly directory?: string | undefined } | undefined }
|
||||||
readonly location?: { readonly directory?: string | undefined; readonly workspace?: string | undefined } | undefined
|
|
||||||
}
|
|
||||||
export type Endpoint25_0Output = { readonly location: Location.Info; readonly data: Vcs.Info }
|
export type Endpoint25_0Output = { readonly location: Location.Info; readonly data: Vcs.Info }
|
||||||
export type VcsGetOperation<E = never> = (input?: Endpoint25_0Input) => Effect.Effect<Endpoint25_0Output, E>
|
export type VcsGetOperation<E = never> = (input?: Endpoint25_0Input) => Effect.Effect<Endpoint25_0Output, E>
|
||||||
|
|
||||||
export type Endpoint25_1Input = {
|
export type Endpoint25_1Input = { readonly location?: { readonly directory?: string | undefined } | undefined }
|
||||||
readonly location?: { readonly directory?: string | undefined; readonly workspace?: string | undefined } | undefined
|
|
||||||
}
|
|
||||||
export type Endpoint25_1Output = { readonly location: Location.Info; readonly data: ReadonlyArray<Vcs.FileStatus> }
|
export type Endpoint25_1Output = { readonly location: Location.Info; readonly data: ReadonlyArray<Vcs.FileStatus> }
|
||||||
export type VcsStatusOperation<E = never> = (input?: Endpoint25_1Input) => Effect.Effect<Endpoint25_1Output, E>
|
export type VcsStatusOperation<E = never> = (input?: Endpoint25_1Input) => Effect.Effect<Endpoint25_1Output, E>
|
||||||
|
|
||||||
export type Endpoint25_2Input = {
|
export type Endpoint25_2Input = {
|
||||||
readonly location?: { readonly directory?: string | undefined; readonly workspace?: string | undefined } | undefined
|
readonly location?: { readonly directory?: string | undefined } | undefined
|
||||||
readonly mode: Vcs.Mode
|
readonly mode: Vcs.Mode
|
||||||
readonly context?: number | undefined
|
readonly context?: number | undefined
|
||||||
}
|
}
|
||||||
@@ -1529,9 +1488,7 @@ export interface VcsApi<E = never> {
|
|||||||
export type Endpoint26_0Output = ReadonlyArray<Location.Ref>
|
export type Endpoint26_0Output = ReadonlyArray<Location.Ref>
|
||||||
export type DebugLocationListOperation<E = never> = () => Effect.Effect<Endpoint26_0Output, E>
|
export type DebugLocationListOperation<E = never> = () => Effect.Effect<Endpoint26_0Output, E>
|
||||||
|
|
||||||
export type Endpoint26_1Input = {
|
export type Endpoint26_1Input = { readonly location?: { readonly directory?: string | undefined } | undefined }
|
||||||
readonly location?: { readonly directory?: string | undefined; readonly workspace?: string | undefined } | undefined
|
|
||||||
}
|
|
||||||
export type Endpoint26_1Output = void
|
export type Endpoint26_1Output = void
|
||||||
export type DebugLocationEvictOperation<E = never> = (input?: Endpoint26_1Input) => Effect.Effect<Endpoint26_1Output, E>
|
export type DebugLocationEvictOperation<E = never> = (input?: Endpoint26_1Input) => Effect.Effect<Endpoint26_1Output, E>
|
||||||
|
|
||||||
@@ -1539,14 +1496,12 @@ export interface DebugApi<E = never> {
|
|||||||
readonly location: { readonly list: DebugLocationListOperation<E>; readonly evict: DebugLocationEvictOperation<E> }
|
readonly location: { readonly list: DebugLocationListOperation<E>; readonly evict: DebugLocationEvictOperation<E> }
|
||||||
}
|
}
|
||||||
|
|
||||||
export type Endpoint27_0Input = {
|
export type Endpoint27_0Input = { readonly location?: { readonly directory?: string | undefined } | undefined }
|
||||||
readonly location?: { readonly directory?: string | undefined; readonly workspace?: string | undefined } | undefined
|
|
||||||
}
|
|
||||||
export type Endpoint27_0Output = { readonly location: Location.Info; readonly data: ReadonlyArray<WebSearch.Provider> }
|
export type Endpoint27_0Output = { readonly location: Location.Info; readonly data: ReadonlyArray<WebSearch.Provider> }
|
||||||
export type WebsearchProvidersOperation<E = never> = (input?: Endpoint27_0Input) => Effect.Effect<Endpoint27_0Output, E>
|
export type WebsearchProvidersOperation<E = never> = (input?: Endpoint27_0Input) => Effect.Effect<Endpoint27_0Output, E>
|
||||||
|
|
||||||
export type Endpoint27_1Input = {
|
export type Endpoint27_1Input = {
|
||||||
readonly location?: { readonly directory?: string | undefined; readonly workspace?: string | undefined } | undefined
|
readonly location?: { readonly directory?: string | undefined } | undefined
|
||||||
readonly query: string
|
readonly query: string
|
||||||
readonly providerID?: WebSearch.ID | undefined
|
readonly providerID?: WebSearch.ID | undefined
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -285,7 +285,6 @@ const Endpoint5_0 = (raw: RawClient["server.session"]) => (input?: Endpoint5_0In
|
|||||||
preserveEffect<Endpoint5_0Output>()(
|
preserveEffect<Endpoint5_0Output>()(
|
||||||
raw["session.list"]({
|
raw["session.list"]({
|
||||||
query: {
|
query: {
|
||||||
workspace: input?.["workspace"],
|
|
||||||
limit: input?.["limit"],
|
limit: input?.["limit"],
|
||||||
order: input?.["order"],
|
order: input?.["order"],
|
||||||
search: input?.["search"],
|
search: input?.["search"],
|
||||||
|
|||||||
@@ -441,7 +441,6 @@ export function make(options: ClientOptions) {
|
|||||||
method: "GET",
|
method: "GET",
|
||||||
path: `/api/session`,
|
path: `/api/session`,
|
||||||
query: {
|
query: {
|
||||||
workspace: input?.["workspace"],
|
|
||||||
limit: input?.["limit"],
|
limit: input?.["limit"],
|
||||||
order: input?.["order"],
|
order: input?.["order"],
|
||||||
search: input?.["search"],
|
search: input?.["search"],
|
||||||
|
|||||||
@@ -2514,9 +2514,7 @@ export type HealthStopOutput = ServiceStopResponse
|
|||||||
export type ServerGetOutput = { urls: Array<string> }
|
export type ServerGetOutput = { urls: Array<string> }
|
||||||
|
|
||||||
export type LocationGetInput = {
|
export type LocationGetInput = {
|
||||||
readonly location?: {
|
readonly location?: { readonly location?: { readonly directory?: string | undefined } | undefined }["location"]
|
||||||
readonly location?: { readonly directory?: string | undefined; readonly workspace?: string | undefined } | undefined
|
|
||||||
}["location"]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export type LocationGetOutput = {
|
export type LocationGetOutput = {
|
||||||
@@ -2526,9 +2524,7 @@ export type LocationGetOutput = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export type AgentListInput = {
|
export type AgentListInput = {
|
||||||
readonly location?: {
|
readonly location?: { readonly location?: { readonly directory?: string | undefined } | undefined }["location"]
|
||||||
readonly location?: { readonly directory?: string | undefined; readonly workspace?: string | undefined } | undefined
|
|
||||||
}["location"]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export type AgentListOutput = {
|
export type AgentListOutput = {
|
||||||
@@ -2538,9 +2534,7 @@ export type AgentListOutput = {
|
|||||||
|
|
||||||
export type AgentGetInput = {
|
export type AgentGetInput = {
|
||||||
readonly agentID: { readonly agentID: string }["agentID"]
|
readonly agentID: { readonly agentID: string }["agentID"]
|
||||||
readonly location?: {
|
readonly location?: { readonly location?: { readonly directory?: string | undefined } | undefined }["location"]
|
||||||
readonly location?: { readonly directory?: string | undefined; readonly workspace?: string | undefined } | undefined
|
|
||||||
}["location"]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export type AgentGetOutput = {
|
export type AgentGetOutput = {
|
||||||
@@ -2549,9 +2543,7 @@ export type AgentGetOutput = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export type PluginListInput = {
|
export type PluginListInput = {
|
||||||
readonly location?: {
|
readonly location?: { readonly location?: { readonly directory?: string | undefined } | undefined }["location"]
|
||||||
readonly location?: { readonly directory?: string | undefined; readonly workspace?: string | undefined } | undefined
|
|
||||||
}["location"]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export type PluginListOutput = {
|
export type PluginListOutput = {
|
||||||
@@ -2560,19 +2552,7 @@ export type PluginListOutput = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export type SessionListInput = {
|
export type SessionListInput = {
|
||||||
readonly workspace?: {
|
|
||||||
readonly workspace?: string | undefined
|
|
||||||
readonly limit?: number | undefined
|
|
||||||
readonly order?: "asc" | "desc" | undefined
|
|
||||||
readonly search?: string | undefined
|
|
||||||
readonly parentID?: string | null | undefined
|
|
||||||
readonly directory?: string | undefined
|
|
||||||
readonly project?: string | undefined
|
|
||||||
readonly subpath?: string | undefined
|
|
||||||
readonly cursor?: string | undefined
|
|
||||||
}["workspace"]
|
|
||||||
readonly limit?: {
|
readonly limit?: {
|
||||||
readonly workspace?: string | undefined
|
|
||||||
readonly limit?: number | undefined
|
readonly limit?: number | undefined
|
||||||
readonly order?: "asc" | "desc" | undefined
|
readonly order?: "asc" | "desc" | undefined
|
||||||
readonly search?: string | undefined
|
readonly search?: string | undefined
|
||||||
@@ -2583,7 +2563,6 @@ export type SessionListInput = {
|
|||||||
readonly cursor?: string | undefined
|
readonly cursor?: string | undefined
|
||||||
}["limit"]
|
}["limit"]
|
||||||
readonly order?: {
|
readonly order?: {
|
||||||
readonly workspace?: string | undefined
|
|
||||||
readonly limit?: number | undefined
|
readonly limit?: number | undefined
|
||||||
readonly order?: "asc" | "desc" | undefined
|
readonly order?: "asc" | "desc" | undefined
|
||||||
readonly search?: string | undefined
|
readonly search?: string | undefined
|
||||||
@@ -2594,7 +2573,6 @@ export type SessionListInput = {
|
|||||||
readonly cursor?: string | undefined
|
readonly cursor?: string | undefined
|
||||||
}["order"]
|
}["order"]
|
||||||
readonly search?: {
|
readonly search?: {
|
||||||
readonly workspace?: string | undefined
|
|
||||||
readonly limit?: number | undefined
|
readonly limit?: number | undefined
|
||||||
readonly order?: "asc" | "desc" | undefined
|
readonly order?: "asc" | "desc" | undefined
|
||||||
readonly search?: string | undefined
|
readonly search?: string | undefined
|
||||||
@@ -2605,7 +2583,6 @@ export type SessionListInput = {
|
|||||||
readonly cursor?: string | undefined
|
readonly cursor?: string | undefined
|
||||||
}["search"]
|
}["search"]
|
||||||
readonly parentID?: {
|
readonly parentID?: {
|
||||||
readonly workspace?: string | undefined
|
|
||||||
readonly limit?: number | undefined
|
readonly limit?: number | undefined
|
||||||
readonly order?: "asc" | "desc" | undefined
|
readonly order?: "asc" | "desc" | undefined
|
||||||
readonly search?: string | undefined
|
readonly search?: string | undefined
|
||||||
@@ -2616,7 +2593,6 @@ export type SessionListInput = {
|
|||||||
readonly cursor?: string | undefined
|
readonly cursor?: string | undefined
|
||||||
}["parentID"]
|
}["parentID"]
|
||||||
readonly directory?: {
|
readonly directory?: {
|
||||||
readonly workspace?: string | undefined
|
|
||||||
readonly limit?: number | undefined
|
readonly limit?: number | undefined
|
||||||
readonly order?: "asc" | "desc" | undefined
|
readonly order?: "asc" | "desc" | undefined
|
||||||
readonly search?: string | undefined
|
readonly search?: string | undefined
|
||||||
@@ -2627,7 +2603,6 @@ export type SessionListInput = {
|
|||||||
readonly cursor?: string | undefined
|
readonly cursor?: string | undefined
|
||||||
}["directory"]
|
}["directory"]
|
||||||
readonly project?: {
|
readonly project?: {
|
||||||
readonly workspace?: string | undefined
|
|
||||||
readonly limit?: number | undefined
|
readonly limit?: number | undefined
|
||||||
readonly order?: "asc" | "desc" | undefined
|
readonly order?: "asc" | "desc" | undefined
|
||||||
readonly search?: string | undefined
|
readonly search?: string | undefined
|
||||||
@@ -2638,7 +2613,6 @@ export type SessionListInput = {
|
|||||||
readonly cursor?: string | undefined
|
readonly cursor?: string | undefined
|
||||||
}["project"]
|
}["project"]
|
||||||
readonly subpath?: {
|
readonly subpath?: {
|
||||||
readonly workspace?: string | undefined
|
|
||||||
readonly limit?: number | undefined
|
readonly limit?: number | undefined
|
||||||
readonly order?: "asc" | "desc" | undefined
|
readonly order?: "asc" | "desc" | undefined
|
||||||
readonly search?: string | undefined
|
readonly search?: string | undefined
|
||||||
@@ -2649,7 +2623,6 @@ export type SessionListInput = {
|
|||||||
readonly cursor?: string | undefined
|
readonly cursor?: string | undefined
|
||||||
}["subpath"]
|
}["subpath"]
|
||||||
readonly cursor?: {
|
readonly cursor?: {
|
||||||
readonly workspace?: string | undefined
|
|
||||||
readonly limit?: number | undefined
|
readonly limit?: number | undefined
|
||||||
readonly order?: "asc" | "desc" | undefined
|
readonly order?: "asc" | "desc" | undefined
|
||||||
readonly search?: string | undefined
|
readonly search?: string | undefined
|
||||||
@@ -3244,9 +3217,7 @@ export type MessageListInput = {
|
|||||||
export type MessageListOutput = SessionMessagesResponse
|
export type MessageListOutput = SessionMessagesResponse
|
||||||
|
|
||||||
export type ModelListInput = {
|
export type ModelListInput = {
|
||||||
readonly location?: {
|
readonly location?: { readonly location?: { readonly directory?: string | undefined } | undefined }["location"]
|
||||||
readonly location?: { readonly directory?: string | undefined; readonly workspace?: string | undefined } | undefined
|
|
||||||
}["location"]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export type ModelListOutput = {
|
export type ModelListOutput = {
|
||||||
@@ -3255,9 +3226,7 @@ export type ModelListOutput = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export type ModelDefaultInput = {
|
export type ModelDefaultInput = {
|
||||||
readonly location?: {
|
readonly location?: { readonly location?: { readonly directory?: string | undefined } | undefined }["location"]
|
||||||
readonly location?: { readonly directory?: string | undefined; readonly workspace?: string | undefined } | undefined
|
|
||||||
}["location"]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export type ModelDefaultOutput = {
|
export type ModelDefaultOutput = {
|
||||||
@@ -3266,9 +3235,7 @@ export type ModelDefaultOutput = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export type GenerateTextInput = {
|
export type GenerateTextInput = {
|
||||||
readonly location?: {
|
readonly location?: { readonly location?: { readonly directory?: string | undefined } | undefined }["location"]
|
||||||
readonly location?: { readonly directory?: string | undefined; readonly workspace?: string | undefined } | undefined
|
|
||||||
}["location"]
|
|
||||||
readonly prompt: {
|
readonly prompt: {
|
||||||
readonly prompt: string
|
readonly prompt: string
|
||||||
readonly model?: { readonly id: string; readonly providerID: string; readonly variant?: string } | null
|
readonly model?: { readonly id: string; readonly providerID: string; readonly variant?: string } | null
|
||||||
@@ -3282,9 +3249,7 @@ export type GenerateTextInput = {
|
|||||||
export type GenerateTextOutput = GenerateTextResponse["data"]
|
export type GenerateTextOutput = GenerateTextResponse["data"]
|
||||||
|
|
||||||
export type ProviderListInput = {
|
export type ProviderListInput = {
|
||||||
readonly location?: {
|
readonly location?: { readonly location?: { readonly directory?: string | undefined } | undefined }["location"]
|
||||||
readonly location?: { readonly directory?: string | undefined; readonly workspace?: string | undefined } | undefined
|
|
||||||
}["location"]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export type ProviderListOutput = {
|
export type ProviderListOutput = {
|
||||||
@@ -3294,9 +3259,7 @@ export type ProviderListOutput = {
|
|||||||
|
|
||||||
export type ProviderGetInput = {
|
export type ProviderGetInput = {
|
||||||
readonly providerID: { readonly providerID: string }["providerID"]
|
readonly providerID: { readonly providerID: string }["providerID"]
|
||||||
readonly location?: {
|
readonly location?: { readonly location?: { readonly directory?: string | undefined } | undefined }["location"]
|
||||||
readonly location?: { readonly directory?: string | undefined; readonly workspace?: string | undefined } | undefined
|
|
||||||
}["location"]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export type ProviderGetOutput = {
|
export type ProviderGetOutput = {
|
||||||
@@ -3305,9 +3268,7 @@ export type ProviderGetOutput = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export type IntegrationListInput = {
|
export type IntegrationListInput = {
|
||||||
readonly location?: {
|
readonly location?: { readonly location?: { readonly directory?: string | undefined } | undefined }["location"]
|
||||||
readonly location?: { readonly directory?: string | undefined; readonly workspace?: string | undefined } | undefined
|
|
||||||
}["location"]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export type IntegrationListOutput = {
|
export type IntegrationListOutput = {
|
||||||
@@ -3317,9 +3278,7 @@ export type IntegrationListOutput = {
|
|||||||
|
|
||||||
export type IntegrationGetInput = {
|
export type IntegrationGetInput = {
|
||||||
readonly integrationID: { readonly integrationID: string }["integrationID"]
|
readonly integrationID: { readonly integrationID: string }["integrationID"]
|
||||||
readonly location?: {
|
readonly location?: { readonly location?: { readonly directory?: string | undefined } | undefined }["location"]
|
||||||
readonly location?: { readonly directory?: string | undefined; readonly workspace?: string | undefined } | undefined
|
|
||||||
}["location"]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export type IntegrationGetOutput = {
|
export type IntegrationGetOutput = {
|
||||||
@@ -3328,9 +3287,7 @@ export type IntegrationGetOutput = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export type IntegrationWellknownAddInput = {
|
export type IntegrationWellknownAddInput = {
|
||||||
readonly location?: {
|
readonly location?: { readonly location?: { readonly directory?: string | undefined } | undefined }["location"]
|
||||||
readonly location?: { readonly directory?: string | undefined; readonly workspace?: string | undefined } | undefined
|
|
||||||
}["location"]
|
|
||||||
readonly url: { readonly url: string }["url"]
|
readonly url: { readonly url: string }["url"]
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3338,9 +3295,7 @@ export type IntegrationWellknownAddOutput = void
|
|||||||
|
|
||||||
export type IntegrationConnectKeyInput = {
|
export type IntegrationConnectKeyInput = {
|
||||||
readonly integrationID: { readonly integrationID: string }["integrationID"]
|
readonly integrationID: { readonly integrationID: string }["integrationID"]
|
||||||
readonly location?: {
|
readonly location?: { readonly location?: { readonly directory?: string | undefined } | undefined }["location"]
|
||||||
readonly location?: { readonly directory?: string | undefined; readonly workspace?: string | undefined } | undefined
|
|
||||||
}["location"]
|
|
||||||
readonly key: { readonly key: string; readonly label?: string | undefined }["key"]
|
readonly key: { readonly key: string; readonly label?: string | undefined }["key"]
|
||||||
readonly label?: { readonly key: string; readonly label?: string | undefined }["label"]
|
readonly label?: { readonly key: string; readonly label?: string | undefined }["label"]
|
||||||
}
|
}
|
||||||
@@ -3349,9 +3304,7 @@ export type IntegrationConnectKeyOutput = void
|
|||||||
|
|
||||||
export type IntegrationOauthConnectInput = {
|
export type IntegrationOauthConnectInput = {
|
||||||
readonly integrationID: { readonly integrationID: string }["integrationID"]
|
readonly integrationID: { readonly integrationID: string }["integrationID"]
|
||||||
readonly location?: {
|
readonly location?: { readonly location?: { readonly directory?: string | undefined } | undefined }["location"]
|
||||||
readonly location?: { readonly directory?: string | undefined; readonly workspace?: string | undefined } | undefined
|
|
||||||
}["location"]
|
|
||||||
readonly methodID: {
|
readonly methodID: {
|
||||||
readonly methodID: string
|
readonly methodID: string
|
||||||
readonly inputs: { readonly [x: string]: string }
|
readonly inputs: { readonly [x: string]: string }
|
||||||
@@ -3383,9 +3336,7 @@ export type IntegrationOauthConnectOutput = {
|
|||||||
export type IntegrationOauthStatusInput = {
|
export type IntegrationOauthStatusInput = {
|
||||||
readonly integrationID: { readonly integrationID: string; readonly attemptID: string }["integrationID"]
|
readonly integrationID: { readonly integrationID: string; readonly attemptID: string }["integrationID"]
|
||||||
readonly attemptID: { readonly integrationID: string; readonly attemptID: string }["attemptID"]
|
readonly attemptID: { readonly integrationID: string; readonly attemptID: string }["attemptID"]
|
||||||
readonly location?: {
|
readonly location?: { readonly location?: { readonly directory?: string | undefined } | undefined }["location"]
|
||||||
readonly location?: { readonly directory?: string | undefined; readonly workspace?: string | undefined } | undefined
|
|
||||||
}["location"]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export type IntegrationOauthStatusOutput = {
|
export type IntegrationOauthStatusOutput = {
|
||||||
@@ -3396,9 +3347,7 @@ export type IntegrationOauthStatusOutput = {
|
|||||||
export type IntegrationOauthCompleteInput = {
|
export type IntegrationOauthCompleteInput = {
|
||||||
readonly integrationID: { readonly integrationID: string; readonly attemptID: string }["integrationID"]
|
readonly integrationID: { readonly integrationID: string; readonly attemptID: string }["integrationID"]
|
||||||
readonly attemptID: { readonly integrationID: string; readonly attemptID: string }["attemptID"]
|
readonly attemptID: { readonly integrationID: string; readonly attemptID: string }["attemptID"]
|
||||||
readonly location?: {
|
readonly location?: { readonly location?: { readonly directory?: string | undefined } | undefined }["location"]
|
||||||
readonly location?: { readonly directory?: string | undefined; readonly workspace?: string | undefined } | undefined
|
|
||||||
}["location"]
|
|
||||||
readonly code?: { readonly code?: string | undefined }["code"]
|
readonly code?: { readonly code?: string | undefined }["code"]
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3407,18 +3356,14 @@ export type IntegrationOauthCompleteOutput = void
|
|||||||
export type IntegrationOauthCancelInput = {
|
export type IntegrationOauthCancelInput = {
|
||||||
readonly integrationID: { readonly integrationID: string; readonly attemptID: string }["integrationID"]
|
readonly integrationID: { readonly integrationID: string; readonly attemptID: string }["integrationID"]
|
||||||
readonly attemptID: { readonly integrationID: string; readonly attemptID: string }["attemptID"]
|
readonly attemptID: { readonly integrationID: string; readonly attemptID: string }["attemptID"]
|
||||||
readonly location?: {
|
readonly location?: { readonly location?: { readonly directory?: string | undefined } | undefined }["location"]
|
||||||
readonly location?: { readonly directory?: string | undefined; readonly workspace?: string | undefined } | undefined
|
|
||||||
}["location"]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export type IntegrationOauthCancelOutput = void
|
export type IntegrationOauthCancelOutput = void
|
||||||
|
|
||||||
export type IntegrationCommandConnectInput = {
|
export type IntegrationCommandConnectInput = {
|
||||||
readonly integrationID: { readonly integrationID: string }["integrationID"]
|
readonly integrationID: { readonly integrationID: string }["integrationID"]
|
||||||
readonly location?: {
|
readonly location?: { readonly location?: { readonly directory?: string | undefined } | undefined }["location"]
|
||||||
readonly location?: { readonly directory?: string | undefined; readonly workspace?: string | undefined } | undefined
|
|
||||||
}["location"]
|
|
||||||
readonly methodID: { readonly methodID: string; readonly label?: string | undefined }["methodID"]
|
readonly methodID: { readonly methodID: string; readonly label?: string | undefined }["methodID"]
|
||||||
readonly label?: { readonly methodID: string; readonly label?: string | undefined }["label"]
|
readonly label?: { readonly methodID: string; readonly label?: string | undefined }["label"]
|
||||||
}
|
}
|
||||||
@@ -3431,9 +3376,7 @@ export type IntegrationCommandConnectOutput = {
|
|||||||
export type IntegrationCommandStatusInput = {
|
export type IntegrationCommandStatusInput = {
|
||||||
readonly integrationID: { readonly integrationID: string; readonly attemptID: string }["integrationID"]
|
readonly integrationID: { readonly integrationID: string; readonly attemptID: string }["integrationID"]
|
||||||
readonly attemptID: { readonly integrationID: string; readonly attemptID: string }["attemptID"]
|
readonly attemptID: { readonly integrationID: string; readonly attemptID: string }["attemptID"]
|
||||||
readonly location?: {
|
readonly location?: { readonly location?: { readonly directory?: string | undefined } | undefined }["location"]
|
||||||
readonly location?: { readonly directory?: string | undefined; readonly workspace?: string | undefined } | undefined
|
|
||||||
}["location"]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export type IntegrationCommandStatusOutput = {
|
export type IntegrationCommandStatusOutput = {
|
||||||
@@ -3444,17 +3387,13 @@ export type IntegrationCommandStatusOutput = {
|
|||||||
export type IntegrationCommandCancelInput = {
|
export type IntegrationCommandCancelInput = {
|
||||||
readonly integrationID: { readonly integrationID: string; readonly attemptID: string }["integrationID"]
|
readonly integrationID: { readonly integrationID: string; readonly attemptID: string }["integrationID"]
|
||||||
readonly attemptID: { readonly integrationID: string; readonly attemptID: string }["attemptID"]
|
readonly attemptID: { readonly integrationID: string; readonly attemptID: string }["attemptID"]
|
||||||
readonly location?: {
|
readonly location?: { readonly location?: { readonly directory?: string | undefined } | undefined }["location"]
|
||||||
readonly location?: { readonly directory?: string | undefined; readonly workspace?: string | undefined } | undefined
|
|
||||||
}["location"]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export type IntegrationCommandCancelOutput = void
|
export type IntegrationCommandCancelOutput = void
|
||||||
|
|
||||||
export type McpListInput = {
|
export type McpListInput = {
|
||||||
readonly location?: {
|
readonly location?: { readonly location?: { readonly directory?: string | undefined } | undefined }["location"]
|
||||||
readonly location?: { readonly directory?: string | undefined; readonly workspace?: string | undefined } | undefined
|
|
||||||
}["location"]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export type McpListOutput = {
|
export type McpListOutput = {
|
||||||
@@ -3464,9 +3403,7 @@ export type McpListOutput = {
|
|||||||
|
|
||||||
export type McpAddInput = {
|
export type McpAddInput = {
|
||||||
readonly server: { readonly server: string }["server"]
|
readonly server: { readonly server: string }["server"]
|
||||||
readonly location?: {
|
readonly location?: { readonly location?: { readonly directory?: string | undefined } | undefined }["location"]
|
||||||
readonly location?: { readonly directory?: string | undefined; readonly workspace?: string | undefined } | undefined
|
|
||||||
}["location"]
|
|
||||||
readonly config: {
|
readonly config: {
|
||||||
readonly config:
|
readonly config:
|
||||||
| {
|
| {
|
||||||
@@ -3515,35 +3452,27 @@ export type McpAddOutput = void
|
|||||||
|
|
||||||
export type McpRemoveInput = {
|
export type McpRemoveInput = {
|
||||||
readonly server: { readonly server: string }["server"]
|
readonly server: { readonly server: string }["server"]
|
||||||
readonly location?: {
|
readonly location?: { readonly location?: { readonly directory?: string | undefined } | undefined }["location"]
|
||||||
readonly location?: { readonly directory?: string | undefined; readonly workspace?: string | undefined } | undefined
|
|
||||||
}["location"]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export type McpRemoveOutput = void
|
export type McpRemoveOutput = void
|
||||||
|
|
||||||
export type McpConnectInput = {
|
export type McpConnectInput = {
|
||||||
readonly server: { readonly server: string }["server"]
|
readonly server: { readonly server: string }["server"]
|
||||||
readonly location?: {
|
readonly location?: { readonly location?: { readonly directory?: string | undefined } | undefined }["location"]
|
||||||
readonly location?: { readonly directory?: string | undefined; readonly workspace?: string | undefined } | undefined
|
|
||||||
}["location"]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export type McpConnectOutput = void
|
export type McpConnectOutput = void
|
||||||
|
|
||||||
export type McpDisconnectInput = {
|
export type McpDisconnectInput = {
|
||||||
readonly server: { readonly server: string }["server"]
|
readonly server: { readonly server: string }["server"]
|
||||||
readonly location?: {
|
readonly location?: { readonly location?: { readonly directory?: string | undefined } | undefined }["location"]
|
||||||
readonly location?: { readonly directory?: string | undefined; readonly workspace?: string | undefined } | undefined
|
|
||||||
}["location"]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export type McpDisconnectOutput = void
|
export type McpDisconnectOutput = void
|
||||||
|
|
||||||
export type McpResourceCatalogInput = {
|
export type McpResourceCatalogInput = {
|
||||||
readonly location?: {
|
readonly location?: { readonly location?: { readonly directory?: string | undefined } | undefined }["location"]
|
||||||
readonly location?: { readonly directory?: string | undefined; readonly workspace?: string | undefined } | undefined
|
|
||||||
}["location"]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export type McpResourceCatalogOutput = {
|
export type McpResourceCatalogOutput = {
|
||||||
@@ -3553,9 +3482,7 @@ export type McpResourceCatalogOutput = {
|
|||||||
|
|
||||||
export type CredentialUpdateInput = {
|
export type CredentialUpdateInput = {
|
||||||
readonly credentialID: { readonly credentialID: string }["credentialID"]
|
readonly credentialID: { readonly credentialID: string }["credentialID"]
|
||||||
readonly location?: {
|
readonly location?: { readonly location?: { readonly directory?: string | undefined } | undefined }["location"]
|
||||||
readonly location?: { readonly directory?: string | undefined; readonly workspace?: string | undefined } | undefined
|
|
||||||
}["location"]
|
|
||||||
readonly label: { readonly label: string }["label"]
|
readonly label: { readonly label: string }["label"]
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3563,9 +3490,7 @@ export type CredentialUpdateOutput = void
|
|||||||
|
|
||||||
export type CredentialRemoveInput = {
|
export type CredentialRemoveInput = {
|
||||||
readonly credentialID: { readonly credentialID: string }["credentialID"]
|
readonly credentialID: { readonly credentialID: string }["credentialID"]
|
||||||
readonly location?: {
|
readonly location?: { readonly location?: { readonly directory?: string | undefined } | undefined }["location"]
|
||||||
readonly location?: { readonly directory?: string | undefined; readonly workspace?: string | undefined } | undefined
|
|
||||||
}["location"]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export type CredentialRemoveOutput = void
|
export type CredentialRemoveOutput = void
|
||||||
@@ -3573,26 +3498,20 @@ export type CredentialRemoveOutput = void
|
|||||||
export type ProjectListOutput = Array<Project>
|
export type ProjectListOutput = Array<Project>
|
||||||
|
|
||||||
export type ProjectCurrentInput = {
|
export type ProjectCurrentInput = {
|
||||||
readonly location?: {
|
readonly location?: { readonly location?: { readonly directory?: string | undefined } | undefined }["location"]
|
||||||
readonly location?: { readonly directory?: string | undefined; readonly workspace?: string | undefined } | undefined
|
|
||||||
}["location"]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export type ProjectCurrentOutput = ProjectCurrent
|
export type ProjectCurrentOutput = ProjectCurrent
|
||||||
|
|
||||||
export type ProjectDirectoriesInput = {
|
export type ProjectDirectoriesInput = {
|
||||||
readonly projectID: { readonly projectID: string }["projectID"]
|
readonly projectID: { readonly projectID: string }["projectID"]
|
||||||
readonly location?: {
|
readonly location?: { readonly location?: { readonly directory?: string | undefined } | undefined }["location"]
|
||||||
readonly location?: { readonly directory?: string | undefined; readonly workspace?: string | undefined } | undefined
|
|
||||||
}["location"]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export type ProjectDirectoriesOutput = ProjectDirectories
|
export type ProjectDirectoriesOutput = ProjectDirectories
|
||||||
|
|
||||||
export type FormRequestListInput = {
|
export type FormRequestListInput = {
|
||||||
readonly location?: {
|
readonly location?: { readonly location?: { readonly directory?: string | undefined } | undefined }["location"]
|
||||||
readonly location?: { readonly directory?: string | undefined; readonly workspace?: string | undefined } | undefined
|
|
||||||
}["location"]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export type FormRequestListOutput = {
|
export type FormRequestListOutput = {
|
||||||
@@ -4446,9 +4365,7 @@ export type FormCancelInput = {
|
|||||||
export type FormCancelOutput = void
|
export type FormCancelOutput = void
|
||||||
|
|
||||||
export type PermissionRequestListInput = {
|
export type PermissionRequestListInput = {
|
||||||
readonly location?: {
|
readonly location?: { readonly location?: { readonly directory?: string | undefined } | undefined }["location"]
|
||||||
readonly location?: { readonly directory?: string | undefined; readonly workspace?: string | undefined } | undefined
|
|
||||||
}["location"]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export type PermissionRequestListOutput = {
|
export type PermissionRequestListOutput = {
|
||||||
@@ -4554,9 +4471,7 @@ export type PermissionReplyInput = {
|
|||||||
export type PermissionReplyOutput = void
|
export type PermissionReplyOutput = void
|
||||||
|
|
||||||
export type FileReadInput = {
|
export type FileReadInput = {
|
||||||
readonly location?: {
|
readonly location?: { readonly location?: { readonly directory?: string | undefined } | undefined }["location"]
|
||||||
readonly location?: { readonly directory?: string | undefined; readonly workspace?: string | undefined } | undefined
|
|
||||||
}["location"]
|
|
||||||
readonly path: string
|
readonly path: string
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4564,11 +4479,11 @@ export type FileReadOutput = globalThis.Uint8Array
|
|||||||
|
|
||||||
export type FileListInput = {
|
export type FileListInput = {
|
||||||
readonly location?: {
|
readonly location?: {
|
||||||
readonly location?: { readonly directory?: string | undefined; readonly workspace?: string | undefined } | undefined
|
readonly location?: { readonly directory?: string | undefined } | undefined
|
||||||
readonly path?: string | undefined
|
readonly path?: string | undefined
|
||||||
}["location"]
|
}["location"]
|
||||||
readonly path?: {
|
readonly path?: {
|
||||||
readonly location?: { readonly directory?: string | undefined; readonly workspace?: string | undefined } | undefined
|
readonly location?: { readonly directory?: string | undefined } | undefined
|
||||||
readonly path?: string | undefined
|
readonly path?: string | undefined
|
||||||
}["path"]
|
}["path"]
|
||||||
}
|
}
|
||||||
@@ -4580,25 +4495,25 @@ export type FileListOutput = {
|
|||||||
|
|
||||||
export type FileFindInput = {
|
export type FileFindInput = {
|
||||||
readonly location?: {
|
readonly location?: {
|
||||||
readonly location?: { readonly directory?: string | undefined; readonly workspace?: string | undefined } | undefined
|
readonly location?: { readonly directory?: string | undefined } | undefined
|
||||||
readonly query: string
|
readonly query: string
|
||||||
readonly type?: "file" | "directory" | undefined
|
readonly type?: "file" | "directory" | undefined
|
||||||
readonly limit?: number | undefined
|
readonly limit?: number | undefined
|
||||||
}["location"]
|
}["location"]
|
||||||
readonly query: {
|
readonly query: {
|
||||||
readonly location?: { readonly directory?: string | undefined; readonly workspace?: string | undefined } | undefined
|
readonly location?: { readonly directory?: string | undefined } | undefined
|
||||||
readonly query: string
|
readonly query: string
|
||||||
readonly type?: "file" | "directory" | undefined
|
readonly type?: "file" | "directory" | undefined
|
||||||
readonly limit?: number | undefined
|
readonly limit?: number | undefined
|
||||||
}["query"]
|
}["query"]
|
||||||
readonly type?: {
|
readonly type?: {
|
||||||
readonly location?: { readonly directory?: string | undefined; readonly workspace?: string | undefined } | undefined
|
readonly location?: { readonly directory?: string | undefined } | undefined
|
||||||
readonly query: string
|
readonly query: string
|
||||||
readonly type?: "file" | "directory" | undefined
|
readonly type?: "file" | "directory" | undefined
|
||||||
readonly limit?: number | undefined
|
readonly limit?: number | undefined
|
||||||
}["type"]
|
}["type"]
|
||||||
readonly limit?: {
|
readonly limit?: {
|
||||||
readonly location?: { readonly directory?: string | undefined; readonly workspace?: string | undefined } | undefined
|
readonly location?: { readonly directory?: string | undefined } | undefined
|
||||||
readonly query: string
|
readonly query: string
|
||||||
readonly type?: "file" | "directory" | undefined
|
readonly type?: "file" | "directory" | undefined
|
||||||
readonly limit?: number | undefined
|
readonly limit?: number | undefined
|
||||||
@@ -4611,9 +4526,7 @@ export type FileFindOutput = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export type CommandListInput = {
|
export type CommandListInput = {
|
||||||
readonly location?: {
|
readonly location?: { readonly location?: { readonly directory?: string | undefined } | undefined }["location"]
|
||||||
readonly location?: { readonly directory?: string | undefined; readonly workspace?: string | undefined } | undefined
|
|
||||||
}["location"]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export type CommandListOutput = {
|
export type CommandListOutput = {
|
||||||
@@ -4622,9 +4535,7 @@ export type CommandListOutput = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export type SkillListInput = {
|
export type SkillListInput = {
|
||||||
readonly location?: {
|
readonly location?: { readonly location?: { readonly directory?: string | undefined } | undefined }["location"]
|
||||||
readonly location?: { readonly directory?: string | undefined; readonly workspace?: string | undefined } | undefined
|
|
||||||
}["location"]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export type SkillListOutput = {
|
export type SkillListOutput = {
|
||||||
@@ -4635,9 +4546,7 @@ export type SkillListOutput = {
|
|||||||
export type EventSubscribeOutput = V2Event
|
export type EventSubscribeOutput = V2Event
|
||||||
|
|
||||||
export type PtyListInput = {
|
export type PtyListInput = {
|
||||||
readonly location?: {
|
readonly location?: { readonly location?: { readonly directory?: string | undefined } | undefined }["location"]
|
||||||
readonly location?: { readonly directory?: string | undefined; readonly workspace?: string | undefined } | undefined
|
|
||||||
}["location"]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export type PtyListOutput = {
|
export type PtyListOutput = {
|
||||||
@@ -4646,9 +4555,7 @@ export type PtyListOutput = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export type PtyCreateInput = {
|
export type PtyCreateInput = {
|
||||||
readonly location?: {
|
readonly location?: { readonly location?: { readonly directory?: string | undefined } | undefined }["location"]
|
||||||
readonly location?: { readonly directory?: string | undefined; readonly workspace?: string | undefined } | undefined
|
|
||||||
}["location"]
|
|
||||||
readonly command?: {
|
readonly command?: {
|
||||||
readonly command?: string
|
readonly command?: string
|
||||||
readonly args?: ReadonlyArray<string>
|
readonly args?: ReadonlyArray<string>
|
||||||
@@ -4693,9 +4600,7 @@ export type PtyCreateOutput = {
|
|||||||
|
|
||||||
export type PtyGetInput = {
|
export type PtyGetInput = {
|
||||||
readonly ptyID: { readonly ptyID: string }["ptyID"]
|
readonly ptyID: { readonly ptyID: string }["ptyID"]
|
||||||
readonly location?: {
|
readonly location?: { readonly location?: { readonly directory?: string | undefined } | undefined }["location"]
|
||||||
readonly location?: { readonly directory?: string | undefined; readonly workspace?: string | undefined } | undefined
|
|
||||||
}["location"]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export type PtyGetOutput = {
|
export type PtyGetOutput = {
|
||||||
@@ -4705,9 +4610,7 @@ export type PtyGetOutput = {
|
|||||||
|
|
||||||
export type PtyUpdateInput = {
|
export type PtyUpdateInput = {
|
||||||
readonly ptyID: { readonly ptyID: string }["ptyID"]
|
readonly ptyID: { readonly ptyID: string }["ptyID"]
|
||||||
readonly location?: {
|
readonly location?: { readonly location?: { readonly directory?: string | undefined } | undefined }["location"]
|
||||||
readonly location?: { readonly directory?: string | undefined; readonly workspace?: string | undefined } | undefined
|
|
||||||
}["location"]
|
|
||||||
readonly title?: {
|
readonly title?: {
|
||||||
readonly title?: string
|
readonly title?: string
|
||||||
readonly size?: { readonly rows: number; readonly cols: number }
|
readonly size?: { readonly rows: number; readonly cols: number }
|
||||||
@@ -4722,17 +4625,13 @@ export type PtyUpdateOutput = {
|
|||||||
|
|
||||||
export type PtyRemoveInput = {
|
export type PtyRemoveInput = {
|
||||||
readonly ptyID: { readonly ptyID: string }["ptyID"]
|
readonly ptyID: { readonly ptyID: string }["ptyID"]
|
||||||
readonly location?: {
|
readonly location?: { readonly location?: { readonly directory?: string | undefined } | undefined }["location"]
|
||||||
readonly location?: { readonly directory?: string | undefined; readonly workspace?: string | undefined } | undefined
|
|
||||||
}["location"]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export type PtyRemoveOutput = void
|
export type PtyRemoveOutput = void
|
||||||
|
|
||||||
export type ShellListInput = {
|
export type ShellListInput = {
|
||||||
readonly location?: {
|
readonly location?: { readonly location?: { readonly directory?: string | undefined } | undefined }["location"]
|
||||||
readonly location?: { readonly directory?: string | undefined; readonly workspace?: string | undefined } | undefined
|
|
||||||
}["location"]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export type ShellListOutput = {
|
export type ShellListOutput = {
|
||||||
@@ -4741,9 +4640,7 @@ export type ShellListOutput = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export type ShellCreateInput = {
|
export type ShellCreateInput = {
|
||||||
readonly location?: {
|
readonly location?: { readonly location?: { readonly directory?: string | undefined } | undefined }["location"]
|
||||||
readonly location?: { readonly directory?: string | undefined; readonly workspace?: string | undefined } | undefined
|
|
||||||
}["location"]
|
|
||||||
readonly command: {
|
readonly command: {
|
||||||
readonly command: string
|
readonly command: string
|
||||||
readonly cwd?: string
|
readonly cwd?: string
|
||||||
@@ -4777,9 +4674,7 @@ export type ShellCreateOutput = {
|
|||||||
|
|
||||||
export type ShellGetInput = {
|
export type ShellGetInput = {
|
||||||
readonly id: { readonly id: string }["id"]
|
readonly id: { readonly id: string }["id"]
|
||||||
readonly location?: {
|
readonly location?: { readonly location?: { readonly directory?: string | undefined } | undefined }["location"]
|
||||||
readonly location?: { readonly directory?: string | undefined; readonly workspace?: string | undefined } | undefined
|
|
||||||
}["location"]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export type ShellGetOutput = {
|
export type ShellGetOutput = {
|
||||||
@@ -4789,9 +4684,7 @@ export type ShellGetOutput = {
|
|||||||
|
|
||||||
export type ShellTimeoutInput = {
|
export type ShellTimeoutInput = {
|
||||||
readonly id: { readonly id: string }["id"]
|
readonly id: { readonly id: string }["id"]
|
||||||
readonly location?: {
|
readonly location?: { readonly location?: { readonly directory?: string | undefined } | undefined }["location"]
|
||||||
readonly location?: { readonly directory?: string | undefined; readonly workspace?: string | undefined } | undefined
|
|
||||||
}["location"]
|
|
||||||
readonly timeout: { readonly timeout: number }["timeout"]
|
readonly timeout: { readonly timeout: number }["timeout"]
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4803,17 +4696,17 @@ export type ShellTimeoutOutput = {
|
|||||||
export type ShellOutputInput = {
|
export type ShellOutputInput = {
|
||||||
readonly id: { readonly id: string }["id"]
|
readonly id: { readonly id: string }["id"]
|
||||||
readonly location?: {
|
readonly location?: {
|
||||||
readonly location?: { readonly directory?: string | undefined; readonly workspace?: string | undefined } | undefined
|
readonly location?: { readonly directory?: string | undefined } | undefined
|
||||||
readonly cursor?: number | undefined
|
readonly cursor?: number | undefined
|
||||||
readonly limit?: number | undefined
|
readonly limit?: number | undefined
|
||||||
}["location"]
|
}["location"]
|
||||||
readonly cursor?: {
|
readonly cursor?: {
|
||||||
readonly location?: { readonly directory?: string | undefined; readonly workspace?: string | undefined } | undefined
|
readonly location?: { readonly directory?: string | undefined } | undefined
|
||||||
readonly cursor?: number | undefined
|
readonly cursor?: number | undefined
|
||||||
readonly limit?: number | undefined
|
readonly limit?: number | undefined
|
||||||
}["cursor"]
|
}["cursor"]
|
||||||
readonly limit?: {
|
readonly limit?: {
|
||||||
readonly location?: { readonly directory?: string | undefined; readonly workspace?: string | undefined } | undefined
|
readonly location?: { readonly directory?: string | undefined } | undefined
|
||||||
readonly cursor?: number | undefined
|
readonly cursor?: number | undefined
|
||||||
readonly limit?: number | undefined
|
readonly limit?: number | undefined
|
||||||
}["limit"]
|
}["limit"]
|
||||||
@@ -4826,17 +4719,13 @@ export type ShellOutputOutput = {
|
|||||||
|
|
||||||
export type ShellRemoveInput = {
|
export type ShellRemoveInput = {
|
||||||
readonly id: { readonly id: string }["id"]
|
readonly id: { readonly id: string }["id"]
|
||||||
readonly location?: {
|
readonly location?: { readonly location?: { readonly directory?: string | undefined } | undefined }["location"]
|
||||||
readonly location?: { readonly directory?: string | undefined; readonly workspace?: string | undefined } | undefined
|
|
||||||
}["location"]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export type ShellRemoveOutput = void
|
export type ShellRemoveOutput = void
|
||||||
|
|
||||||
export type QuestionRequestListInput = {
|
export type QuestionRequestListInput = {
|
||||||
readonly location?: {
|
readonly location?: { readonly location?: { readonly directory?: string | undefined } | undefined }["location"]
|
||||||
readonly location?: { readonly directory?: string | undefined; readonly workspace?: string | undefined } | undefined
|
|
||||||
}["location"]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export type QuestionRequestListOutput = {
|
export type QuestionRequestListOutput = {
|
||||||
@@ -4864,9 +4753,7 @@ export type QuestionRejectInput = {
|
|||||||
export type QuestionRejectOutput = void
|
export type QuestionRejectOutput = void
|
||||||
|
|
||||||
export type ReferenceListInput = {
|
export type ReferenceListInput = {
|
||||||
readonly location?: {
|
readonly location?: { readonly location?: { readonly directory?: string | undefined } | undefined }["location"]
|
||||||
readonly location?: { readonly directory?: string | undefined; readonly workspace?: string | undefined } | undefined
|
|
||||||
}["location"]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export type ReferenceListOutput = {
|
export type ReferenceListOutput = {
|
||||||
@@ -4876,9 +4763,7 @@ export type ReferenceListOutput = {
|
|||||||
|
|
||||||
export type ProjectCopyCreateInput = {
|
export type ProjectCopyCreateInput = {
|
||||||
readonly projectID: { readonly projectID: string }["projectID"]
|
readonly projectID: { readonly projectID: string }["projectID"]
|
||||||
readonly location?: {
|
readonly location?: { readonly location?: { readonly directory?: string | undefined } | undefined }["location"]
|
||||||
readonly location?: { readonly directory?: string | undefined; readonly workspace?: string | undefined } | undefined
|
|
||||||
}["location"]
|
|
||||||
readonly strategy: { readonly strategy: string; readonly directory: string; readonly name?: string }["strategy"]
|
readonly strategy: { readonly strategy: string; readonly directory: string; readonly name?: string }["strategy"]
|
||||||
readonly directory: { readonly strategy: string; readonly directory: string; readonly name?: string }["directory"]
|
readonly directory: { readonly strategy: string; readonly directory: string; readonly name?: string }["directory"]
|
||||||
readonly name?: { readonly strategy: string; readonly directory: string; readonly name?: string }["name"]
|
readonly name?: { readonly strategy: string; readonly directory: string; readonly name?: string }["name"]
|
||||||
@@ -4888,9 +4773,7 @@ export type ProjectCopyCreateOutput = ProjectCopyCopy
|
|||||||
|
|
||||||
export type ProjectCopyRemoveInput = {
|
export type ProjectCopyRemoveInput = {
|
||||||
readonly projectID: { readonly projectID: string }["projectID"]
|
readonly projectID: { readonly projectID: string }["projectID"]
|
||||||
readonly location?: {
|
readonly location?: { readonly location?: { readonly directory?: string | undefined } | undefined }["location"]
|
||||||
readonly location?: { readonly directory?: string | undefined; readonly workspace?: string | undefined } | undefined
|
|
||||||
}["location"]
|
|
||||||
readonly directory: { readonly directory: string; readonly force: boolean }["directory"]
|
readonly directory: { readonly directory: string; readonly force: boolean }["directory"]
|
||||||
readonly force: { readonly directory: string; readonly force: boolean }["force"]
|
readonly force: { readonly directory: string; readonly force: boolean }["force"]
|
||||||
}
|
}
|
||||||
@@ -4899,17 +4782,13 @@ export type ProjectCopyRemoveOutput = void
|
|||||||
|
|
||||||
export type ProjectCopyRefreshInput = {
|
export type ProjectCopyRefreshInput = {
|
||||||
readonly projectID: { readonly projectID: string }["projectID"]
|
readonly projectID: { readonly projectID: string }["projectID"]
|
||||||
readonly location?: {
|
readonly location?: { readonly location?: { readonly directory?: string | undefined } | undefined }["location"]
|
||||||
readonly location?: { readonly directory?: string | undefined; readonly workspace?: string | undefined } | undefined
|
|
||||||
}["location"]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export type ProjectCopyRefreshOutput = void
|
export type ProjectCopyRefreshOutput = void
|
||||||
|
|
||||||
export type VcsGetInput = {
|
export type VcsGetInput = {
|
||||||
readonly location?: {
|
readonly location?: { readonly location?: { readonly directory?: string | undefined } | undefined }["location"]
|
||||||
readonly location?: { readonly directory?: string | undefined; readonly workspace?: string | undefined } | undefined
|
|
||||||
}["location"]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export type VcsGetOutput = {
|
export type VcsGetOutput = {
|
||||||
@@ -4918,9 +4797,7 @@ export type VcsGetOutput = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export type VcsStatusInput = {
|
export type VcsStatusInput = {
|
||||||
readonly location?: {
|
readonly location?: { readonly location?: { readonly directory?: string | undefined } | undefined }["location"]
|
||||||
readonly location?: { readonly directory?: string | undefined; readonly workspace?: string | undefined } | undefined
|
|
||||||
}["location"]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export type VcsStatusOutput = {
|
export type VcsStatusOutput = {
|
||||||
@@ -4930,17 +4807,17 @@ export type VcsStatusOutput = {
|
|||||||
|
|
||||||
export type VcsDiffInput = {
|
export type VcsDiffInput = {
|
||||||
readonly location?: {
|
readonly location?: {
|
||||||
readonly location?: { readonly directory?: string | undefined; readonly workspace?: string | undefined } | undefined
|
readonly location?: { readonly directory?: string | undefined } | undefined
|
||||||
readonly mode: "working" | "branch"
|
readonly mode: "working" | "branch"
|
||||||
readonly context?: number | undefined
|
readonly context?: number | undefined
|
||||||
}["location"]
|
}["location"]
|
||||||
readonly mode: {
|
readonly mode: {
|
||||||
readonly location?: { readonly directory?: string | undefined; readonly workspace?: string | undefined } | undefined
|
readonly location?: { readonly directory?: string | undefined } | undefined
|
||||||
readonly mode: "working" | "branch"
|
readonly mode: "working" | "branch"
|
||||||
readonly context?: number | undefined
|
readonly context?: number | undefined
|
||||||
}["mode"]
|
}["mode"]
|
||||||
readonly context?: {
|
readonly context?: {
|
||||||
readonly location?: { readonly directory?: string | undefined; readonly workspace?: string | undefined } | undefined
|
readonly location?: { readonly directory?: string | undefined } | undefined
|
||||||
readonly mode: "working" | "branch"
|
readonly mode: "working" | "branch"
|
||||||
readonly context?: number | undefined
|
readonly context?: number | undefined
|
||||||
}["context"]
|
}["context"]
|
||||||
@@ -4954,17 +4831,13 @@ export type VcsDiffOutput = {
|
|||||||
export type DebugLocationListOutput = Array<LocationRef>
|
export type DebugLocationListOutput = Array<LocationRef>
|
||||||
|
|
||||||
export type DebugLocationEvictInput = {
|
export type DebugLocationEvictInput = {
|
||||||
readonly location?: {
|
readonly location?: { readonly location?: { readonly directory?: string | undefined } | undefined }["location"]
|
||||||
readonly location?: { readonly directory?: string | undefined; readonly workspace?: string | undefined } | undefined
|
|
||||||
}["location"]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export type DebugLocationEvictOutput = void
|
export type DebugLocationEvictOutput = void
|
||||||
|
|
||||||
export type WebsearchProvidersInput = {
|
export type WebsearchProvidersInput = {
|
||||||
readonly location?: {
|
readonly location?: { readonly location?: { readonly directory?: string | undefined } | undefined }["location"]
|
||||||
readonly location?: { readonly directory?: string | undefined; readonly workspace?: string | undefined } | undefined
|
|
||||||
}["location"]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export type WebsearchProvidersOutput = {
|
export type WebsearchProvidersOutput = {
|
||||||
@@ -4973,9 +4846,7 @@ export type WebsearchProvidersOutput = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export type WebsearchQueryInput = {
|
export type WebsearchQueryInput = {
|
||||||
readonly location?: {
|
readonly location?: { readonly location?: { readonly directory?: string | undefined } | undefined }["location"]
|
||||||
readonly location?: { readonly directory?: string | undefined; readonly workspace?: string | undefined } | undefined
|
|
||||||
}["location"]
|
|
||||||
readonly query: { readonly query: string; readonly providerID?: string }["query"]
|
readonly query: { readonly query: string; readonly providerID?: string }["query"]
|
||||||
readonly providerID?: { readonly query: string; readonly providerID?: string }["providerID"]
|
readonly providerID?: { readonly query: string; readonly providerID?: string }["providerID"]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -58,13 +58,3 @@ export const setMethods = new Set([
|
|||||||
"isSupersetOf",
|
"isSupersetOf",
|
||||||
"isDisjointFrom",
|
"isDisjointFrom",
|
||||||
])
|
])
|
||||||
|
|
||||||
export const spreadItems = (value: unknown): Array<unknown> | undefined => {
|
|
||||||
if (Array.isArray(value)) return value
|
|
||||||
if (typeof value === "string") return Array.from(value)
|
|
||||||
if (value instanceof CodeModeMap) return Array.from(value.map.entries(), ([key, item]) => [key, item])
|
|
||||||
if (value instanceof CodeModeSet) return Array.from(value.set.values())
|
|
||||||
if (value instanceof CodeModeURLSearchParams) return Array.from(value.params.entries(), ([key, item]) => [key, item])
|
|
||||||
return undefined
|
|
||||||
}
|
|
||||||
import { CodeModeMap, CodeModeSet, CodeModeURLSearchParams } from "../values.js"
|
|
||||||
|
|||||||
@@ -1021,13 +1021,12 @@ describe("OpenAPI.fromSpec", () => {
|
|||||||
|
|
||||||
await Effect.runPromise(
|
await Effect.runPromise(
|
||||||
location
|
location
|
||||||
.execute({ location: { directory: "/tmp", workspace: "workspace-1" } })
|
.execute({ location: { directory: "/tmp" } })
|
||||||
.pipe(Effect.provide(client.layer)),
|
.pipe(Effect.provide(client.layer)),
|
||||||
)
|
)
|
||||||
|
|
||||||
const url = new URL(client.requests[0]!.url)
|
const url = new URL(client.requests[0]!.url)
|
||||||
expect(url.searchParams.get("location[directory]")).toBe("/tmp")
|
expect(url.searchParams.get("location[directory]")).toBe("/tmp")
|
||||||
expect(url.searchParams.get("location[workspace]")).toBe("workspace-1")
|
|
||||||
})
|
})
|
||||||
|
|
||||||
test("serializes supported simple and form parameter shapes", async () => {
|
test("serializes supported simple and form parameter shapes", async () => {
|
||||||
|
|||||||
@@ -1,103 +0,0 @@
|
|||||||
[data-component="desktop-promo"] {
|
|
||||||
--promo-background: hsl(0, 20%, 99%);
|
|
||||||
--promo-background-weak: hsl(0, 8%, 97%);
|
|
||||||
--promo-text: hsl(0, 1%, 39%);
|
|
||||||
--promo-text-strong: hsl(0, 5%, 12%);
|
|
||||||
--promo-border: hsla(0, 100%, 3%, 0.12);
|
|
||||||
|
|
||||||
position: fixed;
|
|
||||||
z-index: 20;
|
|
||||||
right: 1.5rem;
|
|
||||||
bottom: 1.5rem;
|
|
||||||
width: min(28rem, calc(100vw - 2rem));
|
|
||||||
padding: 4px;
|
|
||||||
overflow: hidden;
|
|
||||||
color: var(--promo-text);
|
|
||||||
border: 1px solid var(--promo-border);
|
|
||||||
border-radius: 8px;
|
|
||||||
background: var(--promo-background);
|
|
||||||
box-shadow: 0 0.75rem 2rem rgb(0 0 0 / 15%);
|
|
||||||
font-family: var(--font-mono);
|
|
||||||
|
|
||||||
@media (prefers-color-scheme: dark) {
|
|
||||||
--promo-background: hsl(0, 9%, 7%);
|
|
||||||
--promo-background-weak: hsl(0, 6%, 10%);
|
|
||||||
--promo-text: hsl(0, 4%, 71%);
|
|
||||||
--promo-text-strong: hsl(0, 15%, 94%);
|
|
||||||
--promo-border: hsl(0, 4%, 23%);
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (max-width: 40rem) {
|
|
||||||
right: 1rem;
|
|
||||||
bottom: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
[data-slot="desktop-promo-link"] {
|
|
||||||
display: block;
|
|
||||||
color: var(--promo-text);
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
[data-slot="desktop-promo-link"]:focus-visible {
|
|
||||||
outline: 2px solid var(--promo-text-strong);
|
|
||||||
outline-offset: -3px;
|
|
||||||
}
|
|
||||||
|
|
||||||
video {
|
|
||||||
display: block;
|
|
||||||
width: 100%;
|
|
||||||
aspect-ratio: 16 / 9;
|
|
||||||
object-fit: cover;
|
|
||||||
border-radius: 4px;
|
|
||||||
background: var(--promo-background-weak);
|
|
||||||
}
|
|
||||||
|
|
||||||
[data-slot="desktop-promo-copy"] {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: 0.35rem;
|
|
||||||
padding: 1rem;
|
|
||||||
font-size: 0.875rem;
|
|
||||||
line-height: 1.4;
|
|
||||||
}
|
|
||||||
|
|
||||||
[data-slot="desktop-promo-copy"] strong {
|
|
||||||
color: var(--promo-text-strong);
|
|
||||||
font-weight: 500;
|
|
||||||
}
|
|
||||||
|
|
||||||
[data-slot="desktop-promo-close"] {
|
|
||||||
position: absolute;
|
|
||||||
top: 0.5rem;
|
|
||||||
right: 0.5rem;
|
|
||||||
display: grid;
|
|
||||||
width: 2rem;
|
|
||||||
height: 2rem;
|
|
||||||
padding: 0;
|
|
||||||
place-items: center;
|
|
||||||
cursor: pointer;
|
|
||||||
color: white;
|
|
||||||
border: none;
|
|
||||||
border-radius: 0.25rem;
|
|
||||||
background: rgb(0 0 0 / 70%);
|
|
||||||
opacity: 0;
|
|
||||||
transition:
|
|
||||||
opacity 150ms ease,
|
|
||||||
background 150ms ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:hover [data-slot="desktop-promo-close"],
|
|
||||||
[data-slot="desktop-promo-close"]:focus-visible {
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
[data-slot="desktop-promo-close"]:hover {
|
|
||||||
background: rgb(0 0 0 / 90%);
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (hover: none) {
|
|
||||||
[data-slot="desktop-promo-close"] {
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,60 +0,0 @@
|
|||||||
import "./desktop-promo.css"
|
|
||||||
import { A, useLocation } from "@solidjs/router"
|
|
||||||
import { createSignal, Show } from "solid-js"
|
|
||||||
import { getRequestEvent } from "solid-js/web"
|
|
||||||
import desktopPromoVideo from "~/asset/lander/desktop-tabs-landscape.mp4"
|
|
||||||
import { useI18n } from "~/context/i18n"
|
|
||||||
import { useLanguage } from "~/context/language"
|
|
||||||
import { strip } from "~/lib/language"
|
|
||||||
|
|
||||||
const DISMISSED_COOKIE = "desktop_promo_dismissed"
|
|
||||||
|
|
||||||
export function DesktopPromo() {
|
|
||||||
const i18n = useI18n()
|
|
||||||
const language = useLanguage()
|
|
||||||
const location = useLocation()
|
|
||||||
const request = getRequestEvent()?.request
|
|
||||||
const cookie = request?.headers.get("cookie") ?? (typeof document === "object" ? document.cookie : "")
|
|
||||||
const [visible, setVisible] = createSignal(
|
|
||||||
!cookie.split(";").some((value) => value.trim() === `${DISMISSED_COOKIE}=1`),
|
|
||||||
)
|
|
||||||
const hostname = request ? new URL(request.url).hostname : typeof window === "object" ? window.location.hostname : ""
|
|
||||||
const primaryHost =
|
|
||||||
hostname === "opencode.ai" || hostname === "localhost" || hostname === "127.0.0.1" || hostname === "::1"
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Show
|
|
||||||
when={
|
|
||||||
visible() &&
|
|
||||||
primaryHost &&
|
|
||||||
strip(location.pathname) !== "/download" &&
|
|
||||||
!strip(location.pathname).startsWith("/download/")
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<aside data-component="desktop-promo">
|
|
||||||
<A href={language.route("/download")} data-slot="desktop-promo-link">
|
|
||||||
<video src={desktopPromoVideo} autoplay playsinline loop muted preload="metadata" aria-hidden="true" />
|
|
||||||
<span data-slot="desktop-promo-copy">
|
|
||||||
<strong>{i18n.t("home.promo.title")}</strong>
|
|
||||||
<span>
|
|
||||||
{i18n.t("home.promo.body")} {i18n.t("home.promo.cta")}
|
|
||||||
</span>
|
|
||||||
</span>
|
|
||||||
</A>
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
data-slot="desktop-promo-close"
|
|
||||||
onClick={() => {
|
|
||||||
document.cookie = `${DISMISSED_COOKIE}=1; Path=/; Max-Age=31536000; SameSite=Lax`
|
|
||||||
setVisible(false)
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<span class="sr-only">{i18n.t("home.promo.close")}</span>
|
|
||||||
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" aria-hidden="true">
|
|
||||||
<path d="M5 5L15 15M15 5L5 15" stroke="currentColor" stroke-width="1.5" />
|
|
||||||
</svg>
|
|
||||||
</button>
|
|
||||||
</aside>
|
|
||||||
</Show>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -19,10 +19,6 @@ export function Span({ children, ...props }: SpanProps) {
|
|||||||
return React.createElement("span", props, children)
|
return React.createElement("span", props, children)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function Wbr({ children, ...props }: WbrProps) {
|
|
||||||
return React.createElement("wbr", props, children)
|
|
||||||
}
|
|
||||||
|
|
||||||
export function Fonts({ assetsUrl }: { assetsUrl: string }) {
|
export function Fonts({ assetsUrl }: { assetsUrl: string }) {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@@ -59,14 +55,3 @@ export function Fonts({ assetsUrl }: { assetsUrl: string }) {
|
|||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function SplitString({ text, split }: { text: string; split: number }) {
|
|
||||||
const segments: JSX.Element[] = []
|
|
||||||
for (let i = 0; i < text.length; i += split) {
|
|
||||||
segments.push(<>{text.slice(i, i + split)}</>)
|
|
||||||
if (i + split < text.length) {
|
|
||||||
segments.push(<Wbr key={`${i}wbr`} />)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return <>{segments}</>
|
|
||||||
}
|
|
||||||
|
|||||||
+2
-110
@@ -1,15 +1,11 @@
|
|||||||
{
|
{
|
||||||
"version": "7",
|
"version": "7",
|
||||||
"dialect": "sqlite",
|
"dialect": "sqlite",
|
||||||
"id": "e43ed7e2-b9fc-4178-beae-3646e4a976e1",
|
"id": "6307bc18-2612-47e2-acfc-2a6a68ff28c5",
|
||||||
"prevIds": [
|
"prevIds": [
|
||||||
"db37a97f-9b5e-4c87-be8b-4feace35136c"
|
"e43ed7e2-b9fc-4178-beae-3646e4a976e1"
|
||||||
],
|
],
|
||||||
"ddl": [
|
"ddl": [
|
||||||
{
|
|
||||||
"name": "workspace",
|
|
||||||
"entityType": "tables"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "data_migration",
|
"name": "data_migration",
|
||||||
"entityType": "tables"
|
"entityType": "tables"
|
||||||
@@ -90,86 +86,6 @@
|
|||||||
"name": "session_share",
|
"name": "session_share",
|
||||||
"entityType": "tables"
|
"entityType": "tables"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"type": "text",
|
|
||||||
"notNull": false,
|
|
||||||
"autoincrement": false,
|
|
||||||
"default": null,
|
|
||||||
"generated": null,
|
|
||||||
"name": "id",
|
|
||||||
"entityType": "columns",
|
|
||||||
"table": "workspace"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "text",
|
|
||||||
"notNull": true,
|
|
||||||
"autoincrement": false,
|
|
||||||
"default": null,
|
|
||||||
"generated": null,
|
|
||||||
"name": "type",
|
|
||||||
"entityType": "columns",
|
|
||||||
"table": "workspace"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "text",
|
|
||||||
"notNull": true,
|
|
||||||
"autoincrement": false,
|
|
||||||
"default": "''",
|
|
||||||
"generated": null,
|
|
||||||
"name": "name",
|
|
||||||
"entityType": "columns",
|
|
||||||
"table": "workspace"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "text",
|
|
||||||
"notNull": false,
|
|
||||||
"autoincrement": false,
|
|
||||||
"default": null,
|
|
||||||
"generated": null,
|
|
||||||
"name": "branch",
|
|
||||||
"entityType": "columns",
|
|
||||||
"table": "workspace"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "text",
|
|
||||||
"notNull": false,
|
|
||||||
"autoincrement": false,
|
|
||||||
"default": null,
|
|
||||||
"generated": null,
|
|
||||||
"name": "directory",
|
|
||||||
"entityType": "columns",
|
|
||||||
"table": "workspace"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "text",
|
|
||||||
"notNull": false,
|
|
||||||
"autoincrement": false,
|
|
||||||
"default": null,
|
|
||||||
"generated": null,
|
|
||||||
"name": "extra",
|
|
||||||
"entityType": "columns",
|
|
||||||
"table": "workspace"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "text",
|
|
||||||
"notNull": true,
|
|
||||||
"autoincrement": false,
|
|
||||||
"default": null,
|
|
||||||
"generated": null,
|
|
||||||
"name": "project_id",
|
|
||||||
"entityType": "columns",
|
|
||||||
"table": "workspace"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "integer",
|
|
||||||
"notNull": true,
|
|
||||||
"autoincrement": false,
|
|
||||||
"default": null,
|
|
||||||
"generated": null,
|
|
||||||
"name": "time_used",
|
|
||||||
"entityType": "columns",
|
|
||||||
"table": "workspace"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"type": "text",
|
"type": "text",
|
||||||
"notNull": false,
|
"notNull": false,
|
||||||
@@ -1590,21 +1506,6 @@
|
|||||||
"entityType": "columns",
|
"entityType": "columns",
|
||||||
"table": "session_share"
|
"table": "session_share"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"columns": [
|
|
||||||
"project_id"
|
|
||||||
],
|
|
||||||
"tableTo": "project",
|
|
||||||
"columnsTo": [
|
|
||||||
"id"
|
|
||||||
],
|
|
||||||
"onUpdate": "NO ACTION",
|
|
||||||
"onDelete": "CASCADE",
|
|
||||||
"nameExplicit": false,
|
|
||||||
"name": "fk_workspace_project_id_project_id_fk",
|
|
||||||
"entityType": "fks",
|
|
||||||
"table": "workspace"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"columns": [
|
"columns": [
|
||||||
"active_account_id"
|
"active_account_id"
|
||||||
@@ -1815,15 +1716,6 @@
|
|||||||
"entityType": "pks",
|
"entityType": "pks",
|
||||||
"table": "instruction_entry"
|
"table": "instruction_entry"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"columns": [
|
|
||||||
"id"
|
|
||||||
],
|
|
||||||
"nameExplicit": false,
|
|
||||||
"name": "workspace_pk",
|
|
||||||
"table": "workspace",
|
|
||||||
"entityType": "pks"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"columns": [
|
"columns": [
|
||||||
"name"
|
"name"
|
||||||
|
|||||||
@@ -44,7 +44,6 @@ export type Draft = {
|
|||||||
|
|
||||||
export interface Interface extends State.Transformable<Draft> {
|
export interface Interface extends State.Transformable<Draft> {
|
||||||
readonly get: (id: ID) => Effect.Effect<Info | undefined>
|
readonly get: (id: ID) => Effect.Effect<Info | undefined>
|
||||||
readonly default: () => Effect.Effect<Info | undefined>
|
|
||||||
readonly resolve: (id?: ID | string) => Effect.Effect<Info | undefined>
|
readonly resolve: (id?: ID | string) => Effect.Effect<Info | undefined>
|
||||||
readonly select: (id?: ID | string) => Effect.Effect<Selection>
|
readonly select: (id?: ID | string) => Effect.Effect<Selection>
|
||||||
readonly list: () => Effect.Effect<Info[]>
|
readonly list: () => Effect.Effect<Info[]>
|
||||||
@@ -110,9 +109,6 @@ const layer = Layer.effect(
|
|||||||
get: Effect.fn("Agent.get")(function* (id) {
|
get: Effect.fn("Agent.get")(function* (id) {
|
||||||
return state.get().agents.get(id)
|
return state.get().agents.get(id)
|
||||||
}),
|
}),
|
||||||
default: Effect.fn("Agent.default")(function* () {
|
|
||||||
return selectedDefault()
|
|
||||||
}),
|
|
||||||
resolve: Effect.fn("Agent.resolve")(function* (id) {
|
resolve: Effect.fn("Agent.resolve")(function* (id) {
|
||||||
if (id !== undefined) return state.get().agents.get(ID.make(id))
|
if (id !== undefined) return state.get().agents.get(ID.make(id))
|
||||||
return selectedDefault()
|
return selectedDefault()
|
||||||
|
|||||||
@@ -1,20 +0,0 @@
|
|||||||
import { sqliteTable, text, integer } from "drizzle-orm/sqlite-core"
|
|
||||||
import { ProjectTable } from "../project/sql"
|
|
||||||
import { Project } from "../project"
|
|
||||||
import { Workspace } from "../workspace"
|
|
||||||
|
|
||||||
export const WorkspaceTable = sqliteTable("workspace", {
|
|
||||||
id: text().$type<Workspace.ID>().primaryKey(),
|
|
||||||
type: text().notNull(),
|
|
||||||
name: text().notNull().default(""),
|
|
||||||
branch: text(),
|
|
||||||
directory: text(),
|
|
||||||
extra: text({ mode: "json" }),
|
|
||||||
project_id: text()
|
|
||||||
.$type<Project.ID>()
|
|
||||||
.notNull()
|
|
||||||
.references(() => ProjectTable.id, { onDelete: "cascade" }),
|
|
||||||
time_used: integer()
|
|
||||||
.notNull()
|
|
||||||
.$default(() => Date.now()),
|
|
||||||
})
|
|
||||||
+1
@@ -59,5 +59,6 @@ export const migrations = (
|
|||||||
import("./migration/20260722170000_canonical_tool_results"),
|
import("./migration/20260722170000_canonical_tool_results"),
|
||||||
import("./migration/20260729022634_session_fork_boundary"),
|
import("./migration/20260729022634_session_fork_boundary"),
|
||||||
import("./migration/20260730195856_optional_session_title"),
|
import("./migration/20260730195856_optional_session_title"),
|
||||||
|
import("./migration/20260805225117_remove_workspace"),
|
||||||
])
|
])
|
||||||
).map((module) => module.default) satisfies DatabaseMigration.Migration[]
|
).map((module) => module.default) satisfies DatabaseMigration.Migration[]
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
import { Effect } from "effect"
|
||||||
|
import type { DatabaseMigration } from "../migration"
|
||||||
|
|
||||||
|
export default {
|
||||||
|
id: "20260805225117_remove_workspace",
|
||||||
|
up(tx) {
|
||||||
|
return Effect.gen(function* () {
|
||||||
|
yield* tx.run(`DROP TABLE \`workspace\`;`)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
} satisfies DatabaseMigration.Migration
|
||||||
@@ -4,19 +4,6 @@ import type { DatabaseMigration } from "./migration"
|
|||||||
export default {
|
export default {
|
||||||
up(tx) {
|
up(tx) {
|
||||||
return Effect.gen(function* () {
|
return Effect.gen(function* () {
|
||||||
yield* tx.run(`
|
|
||||||
CREATE TABLE \`workspace\` (
|
|
||||||
\`id\` text PRIMARY KEY,
|
|
||||||
\`type\` text NOT NULL,
|
|
||||||
\`name\` text DEFAULT '' NOT NULL,
|
|
||||||
\`branch\` text,
|
|
||||||
\`directory\` text,
|
|
||||||
\`extra\` text,
|
|
||||||
\`project_id\` text NOT NULL,
|
|
||||||
\`time_used\` integer NOT NULL,
|
|
||||||
CONSTRAINT \`fk_workspace_project_id_project_id_fk\` FOREIGN KEY (\`project_id\`) REFERENCES \`project\`(\`id\`) ON DELETE CASCADE
|
|
||||||
);
|
|
||||||
`)
|
|
||||||
yield* tx.run(`
|
yield* tx.run(`
|
||||||
CREATE TABLE \`data_migration\` (
|
CREATE TABLE \`data_migration\` (
|
||||||
\`name\` text PRIMARY KEY,
|
\`name\` text PRIMARY KEY,
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import { FSUtil } from "@opencode-ai/util/fs-util"
|
|||||||
import { Location } from "./location"
|
import { Location } from "./location"
|
||||||
import { PositiveInt, RelativePath } from "./schema"
|
import { PositiveInt, RelativePath } from "./schema"
|
||||||
import { FileSystemSearch } from "./filesystem/search"
|
import { FileSystemSearch } from "./filesystem/search"
|
||||||
import { Entry, FileSystem, FindInput, Match } from "@opencode-ai/schema/filesystem"
|
import { Entry, FileSystem, FindInput } from "@opencode-ai/schema/filesystem"
|
||||||
export { Entry, Match, Submatch } from "@opencode-ai/schema/filesystem"
|
export { Entry, Match, Submatch } from "@opencode-ai/schema/filesystem"
|
||||||
|
|
||||||
export const ReadInput = Schema.Struct({
|
export const ReadInput = Schema.Struct({
|
||||||
@@ -53,8 +53,6 @@ export interface Interface {
|
|||||||
readonly read: (input: ReadInput) => Effect.Effect<{ readonly content: Uint8Array; readonly mime: string }>
|
readonly read: (input: ReadInput) => Effect.Effect<{ readonly content: Uint8Array; readonly mime: string }>
|
||||||
readonly list: (input?: ListInput) => Effect.Effect<Entry[]>
|
readonly list: (input?: ListInput) => Effect.Effect<Entry[]>
|
||||||
readonly find: (input: FindInput) => Effect.Effect<Entry[]>
|
readonly find: (input: FindInput) => Effect.Effect<Entry[]>
|
||||||
readonly glob: (input: GlobInput) => Effect.Effect<readonly Entry[]>
|
|
||||||
readonly grep: (input: GrepInput) => Effect.Effect<readonly Match[]>
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Service extends Context.Service<Service, Interface>()("@opencode/FileSystem") {}
|
export class Service extends Context.Service<Service, Interface>()("@opencode/FileSystem") {}
|
||||||
@@ -76,8 +74,6 @@ const baseLayer = Layer.effect(
|
|||||||
})
|
})
|
||||||
return Service.of({
|
return Service.of({
|
||||||
find: search.find,
|
find: search.find,
|
||||||
glob: search.glob,
|
|
||||||
grep: search.grep,
|
|
||||||
read: Effect.fn("FileSystem.read")(function* (input) {
|
read: Effect.fn("FileSystem.read")(function* (input) {
|
||||||
const target = yield* resolve(input.path)
|
const target = yield* resolve(input.path)
|
||||||
const info = yield* fs.stat(target.real).pipe(Effect.orDie)
|
const info = yield* fs.stat(target.real).pipe(Effect.orDie)
|
||||||
|
|||||||
@@ -3,9 +3,6 @@ import {
|
|||||||
type DirItem,
|
type DirItem,
|
||||||
type DirSearchResult,
|
type DirSearchResult,
|
||||||
type FileItem,
|
type FileItem,
|
||||||
type GrepCursor,
|
|
||||||
type GrepMatch,
|
|
||||||
type GrepResult,
|
|
||||||
type InitOptions,
|
type InitOptions,
|
||||||
type MixedItem,
|
type MixedItem,
|
||||||
type MixedSearchResult,
|
type MixedSearchResult,
|
||||||
@@ -45,19 +42,6 @@ export interface MixedSearch {
|
|||||||
export type File = FileItem
|
export type File = FileItem
|
||||||
export type Directory = DirItem
|
export type Directory = DirItem
|
||||||
export type Mixed = MixedItem
|
export type Mixed = MixedItem
|
||||||
export type Cursor = GrepCursor | null
|
|
||||||
export type Hit = GrepMatch
|
|
||||||
|
|
||||||
export interface Grep {
|
|
||||||
items: GrepResult["items"]
|
|
||||||
totalMatched: number
|
|
||||||
totalFilesSearched: number
|
|
||||||
totalFiles: number
|
|
||||||
filteredFileCount: number
|
|
||||||
nextCursor: Cursor
|
|
||||||
regexFallbackError?: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Picker {
|
export interface Picker {
|
||||||
destroy(): void
|
destroy(): void
|
||||||
isScanning(): boolean
|
isScanning(): boolean
|
||||||
@@ -71,14 +55,6 @@ export interface Picker {
|
|||||||
pageSize?: number
|
pageSize?: number
|
||||||
},
|
},
|
||||||
): Result<Search>
|
): Result<Search>
|
||||||
glob(
|
|
||||||
pattern: string,
|
|
||||||
opts?: {
|
|
||||||
currentFile?: string
|
|
||||||
pageIndex?: number
|
|
||||||
pageSize?: number
|
|
||||||
},
|
|
||||||
): Result<Search>
|
|
||||||
directorySearch(
|
directorySearch(
|
||||||
query: string,
|
query: string,
|
||||||
opts?: {
|
opts?: {
|
||||||
@@ -95,18 +71,6 @@ export interface Picker {
|
|||||||
pageSize?: number
|
pageSize?: number
|
||||||
},
|
},
|
||||||
): Result<MixedSearch>
|
): Result<MixedSearch>
|
||||||
grep(
|
|
||||||
query: string,
|
|
||||||
opts?: {
|
|
||||||
mode?: "plain" | "regex" | "fuzzy"
|
|
||||||
maxMatchesPerFile?: number
|
|
||||||
timeBudgetMs?: number
|
|
||||||
beforeContext?: number
|
|
||||||
afterContext?: number
|
|
||||||
cursor?: Cursor
|
|
||||||
pageSize?: number
|
|
||||||
},
|
|
||||||
): Result<Grep>
|
|
||||||
trackQuery(query: string, file: string): Result<boolean>
|
trackQuery(query: string, file: string): Result<boolean>
|
||||||
getHistoricalQuery(offset: number): Result<string | null>
|
getHistoricalQuery(offset: number): Result<string | null>
|
||||||
}
|
}
|
||||||
@@ -127,10 +91,8 @@ export function create(opts: Init): Result<Picker> {
|
|||||||
waitForScan: (timeoutMs) => pick.waitForScan(timeoutMs),
|
waitForScan: (timeoutMs) => pick.waitForScan(timeoutMs),
|
||||||
refreshGitStatus: () => pick.refreshGitStatus(),
|
refreshGitStatus: () => pick.refreshGitStatus(),
|
||||||
fileSearch: (query, next) => pick.fileSearch(query, next),
|
fileSearch: (query, next) => pick.fileSearch(query, next),
|
||||||
glob: (pattern, next) => pick.glob(pattern, next),
|
|
||||||
directorySearch: (query, next) => pick.directorySearch(query, next),
|
directorySearch: (query, next) => pick.directorySearch(query, next),
|
||||||
mixedSearch: (query, next) => pick.mixedSearch(query, next),
|
mixedSearch: (query, next) => pick.mixedSearch(query, next),
|
||||||
grep: (query, next) => pick.grep(query, next),
|
|
||||||
trackQuery: (query, file) => pick.trackQuery(query, file),
|
trackQuery: (query, file) => pick.trackQuery(query, file),
|
||||||
getHistoricalQuery: (offset) => pick.getHistoricalQuery(offset),
|
getHistoricalQuery: (offset) => pick.getHistoricalQuery(offset),
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -2,9 +2,6 @@ import type {
|
|||||||
DirItem,
|
DirItem,
|
||||||
DirSearchResult,
|
DirSearchResult,
|
||||||
FileItem,
|
FileItem,
|
||||||
GrepCursor,
|
|
||||||
GrepMatch,
|
|
||||||
GrepResult,
|
|
||||||
InitOptions,
|
InitOptions,
|
||||||
MixedItem,
|
MixedItem,
|
||||||
MixedSearchResult,
|
MixedSearchResult,
|
||||||
@@ -42,19 +39,6 @@ export interface MixedSearch {
|
|||||||
export type File = FileItem
|
export type File = FileItem
|
||||||
export type Directory = DirItem
|
export type Directory = DirItem
|
||||||
export type Mixed = MixedItem
|
export type Mixed = MixedItem
|
||||||
export type Cursor = GrepCursor | null
|
|
||||||
export type Hit = GrepMatch
|
|
||||||
|
|
||||||
export interface Grep {
|
|
||||||
items: GrepResult["items"]
|
|
||||||
totalMatched: number
|
|
||||||
totalFilesSearched: number
|
|
||||||
totalFiles: number
|
|
||||||
filteredFileCount: number
|
|
||||||
nextCursor: Cursor
|
|
||||||
regexFallbackError?: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Picker {
|
export interface Picker {
|
||||||
destroy(): void
|
destroy(): void
|
||||||
isScanning(): boolean
|
isScanning(): boolean
|
||||||
@@ -68,14 +52,6 @@ export interface Picker {
|
|||||||
pageSize?: number
|
pageSize?: number
|
||||||
},
|
},
|
||||||
): Result<Search>
|
): Result<Search>
|
||||||
glob(
|
|
||||||
pattern: string,
|
|
||||||
opts?: {
|
|
||||||
currentFile?: string
|
|
||||||
pageIndex?: number
|
|
||||||
pageSize?: number
|
|
||||||
},
|
|
||||||
): Result<Search>
|
|
||||||
directorySearch(
|
directorySearch(
|
||||||
query: string,
|
query: string,
|
||||||
opts?: {
|
opts?: {
|
||||||
@@ -92,18 +68,6 @@ export interface Picker {
|
|||||||
pageSize?: number
|
pageSize?: number
|
||||||
},
|
},
|
||||||
): Result<MixedSearch>
|
): Result<MixedSearch>
|
||||||
grep(
|
|
||||||
query: string,
|
|
||||||
opts?: {
|
|
||||||
mode?: "plain" | "regex" | "fuzzy"
|
|
||||||
maxMatchesPerFile?: number
|
|
||||||
timeBudgetMs?: number
|
|
||||||
beforeContext?: number
|
|
||||||
afterContext?: number
|
|
||||||
cursor?: Cursor
|
|
||||||
pageSize?: number
|
|
||||||
},
|
|
||||||
): Result<Grep>
|
|
||||||
trackQuery(query: string, file: string): Result<boolean>
|
trackQuery(query: string, file: string): Result<boolean>
|
||||||
getHistoricalQuery(offset: number): Result<string | null>
|
getHistoricalQuery(offset: number): Result<string | null>
|
||||||
}
|
}
|
||||||
@@ -125,10 +89,8 @@ export function create(opts: Init): Result<Picker> {
|
|||||||
waitForScan: (timeoutMs) => pick.waitForScan(timeoutMs),
|
waitForScan: (timeoutMs) => pick.waitForScan(timeoutMs),
|
||||||
refreshGitStatus: () => pick.refreshGitStatus(),
|
refreshGitStatus: () => pick.refreshGitStatus(),
|
||||||
fileSearch: (query, next) => pick.fileSearch(query, next),
|
fileSearch: (query, next) => pick.fileSearch(query, next),
|
||||||
glob: (pattern, next) => pick.glob(pattern, next),
|
|
||||||
directorySearch: (query, next) => pick.directorySearch(query, next),
|
directorySearch: (query, next) => pick.directorySearch(query, next),
|
||||||
mixedSearch: (query, next) => pick.mixedSearch(query, next),
|
mixedSearch: (query, next) => pick.mixedSearch(query, next),
|
||||||
grep: (query, next) => pick.grep(query, next),
|
|
||||||
trackQuery: (query, file) => pick.trackQuery(query, file),
|
trackQuery: (query, file) => pick.trackQuery(query, file),
|
||||||
getHistoricalQuery: (offset) => pick.getHistoricalQuery(offset),
|
getHistoricalQuery: (offset) => pick.getHistoricalQuery(offset),
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
import { Glob } from "@opencode-ai/util/glob"
|
|
||||||
|
|
||||||
const FOLDERS = new Set([
|
const FOLDERS = new Set([
|
||||||
"node_modules",
|
"node_modules",
|
||||||
"bower_components",
|
"bower_components",
|
||||||
@@ -47,21 +45,4 @@ const FILES = [
|
|||||||
|
|
||||||
export const PATTERNS = [...FILES, ...FOLDERS, `**/{${Array.from(FOLDERS).join(",")}}/**`]
|
export const PATTERNS = [...FILES, ...FOLDERS, `**/{${Array.from(FOLDERS).join(",")}}/**`]
|
||||||
|
|
||||||
export function match(filepath: string, opts?: { extra?: string[]; whitelist?: string[] }) {
|
|
||||||
for (const pattern of opts?.whitelist || []) {
|
|
||||||
if (Glob.match(pattern, filepath)) return false
|
|
||||||
}
|
|
||||||
|
|
||||||
const parts = filepath.split(/[/\\]/)
|
|
||||||
for (const part of parts) {
|
|
||||||
if (FOLDERS.has(part)) return true
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const pattern of [...FILES, ...(opts?.extra || [])]) {
|
|
||||||
if (Glob.match(pattern, filepath)) return true
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
export * as Ignore from "./ignore"
|
export * as Ignore from "./ignore"
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ export * as LocationWatcher from "./location-watcher"
|
|||||||
import { makeLocationNode } from "@opencode-ai/util/effect/app-node"
|
import { makeLocationNode } from "@opencode-ai/util/effect/app-node"
|
||||||
import { Context, Effect, Layer, Stream } from "effect"
|
import { Context, Effect, Layer, Stream } from "effect"
|
||||||
import { FileSystem } from "@opencode-ai/schema/filesystem"
|
import { FileSystem } from "@opencode-ai/schema/filesystem"
|
||||||
import os from "os"
|
|
||||||
import path from "path"
|
import path from "path"
|
||||||
import { Config } from "../config"
|
import { Config } from "../config"
|
||||||
import { Bus } from "../bus"
|
import { Bus } from "../bus"
|
||||||
@@ -44,7 +43,7 @@ const layer = Layer.effect(
|
|||||||
const config = (yield* configService.entries())
|
const config = (yield* configService.entries())
|
||||||
.filter((entry): entry is Config.Document => entry.type === "document")
|
.filter((entry): entry is Config.Document => entry.type === "document")
|
||||||
.flatMap((item) => item.info.watcher?.ignore ?? [])
|
.flatMap((item) => item.info.watcher?.ignore ?? [])
|
||||||
const home = path.resolve(location.directory) === path.resolve(os.homedir())
|
const home = Protected.isHome(location.directory)
|
||||||
|
|
||||||
if (!home && location.vcs) {
|
if (!home && location.vcs) {
|
||||||
const updates = yield* watcher.subscribe({
|
const updates = yield* watcher.subscribe({
|
||||||
|
|||||||
@@ -3,6 +3,10 @@ import path from "path"
|
|||||||
|
|
||||||
const home = os.homedir()
|
const home = os.homedir()
|
||||||
|
|
||||||
|
export function isHome(directory: string) {
|
||||||
|
return path.resolve(directory) === path.resolve(home)
|
||||||
|
}
|
||||||
|
|
||||||
const DARWIN_HOME = [
|
const DARWIN_HOME = [
|
||||||
"Music",
|
"Music",
|
||||||
"Pictures",
|
"Pictures",
|
||||||
|
|||||||
@@ -6,15 +6,13 @@ import { Context, Effect, Layer, Schema, Scope } from "effect"
|
|||||||
import { Fff } from "#fff"
|
import { Fff } from "#fff"
|
||||||
import fuzzysort from "fuzzysort"
|
import fuzzysort from "fuzzysort"
|
||||||
import { FileSystem } from "../filesystem"
|
import { FileSystem } from "../filesystem"
|
||||||
import { FSUtil } from "@opencode-ai/util/fs-util"
|
|
||||||
import { Location } from "../location"
|
import { Location } from "../location"
|
||||||
import { Ripgrep } from "../ripgrep"
|
import { Ripgrep } from "../ripgrep"
|
||||||
import { RelativePath } from "../schema"
|
import { RelativePath } from "../schema"
|
||||||
|
import { Protected } from "./protected"
|
||||||
|
|
||||||
export interface Interface {
|
export interface Interface {
|
||||||
readonly find: (input: FileSystem.FindInput) => Effect.Effect<FileSystem.Entry[]>
|
readonly find: (input: FileSystem.FindInput) => Effect.Effect<FileSystem.Entry[]>
|
||||||
readonly glob: (input: FileSystem.GlobInput) => Effect.Effect<readonly FileSystem.Entry[]>
|
|
||||||
readonly grep: (input: FileSystem.GrepInput) => Effect.Effect<readonly FileSystem.Match[]>
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Options = Schema.Struct({
|
export const Options = Schema.Struct({
|
||||||
@@ -27,17 +25,18 @@ export class Service extends Context.Service<Service, Interface>()("@opencode/Fi
|
|||||||
export const ripgrepLayer = Layer.effect(
|
export const ripgrepLayer = Layer.effect(
|
||||||
Service,
|
Service,
|
||||||
Effect.gen(function* () {
|
Effect.gen(function* () {
|
||||||
const fs = yield* FSUtil.Service
|
|
||||||
const location = yield* Location.Service
|
const location = yield* Location.Service
|
||||||
const ripgrep = yield* Ripgrep.Service
|
const ripgrep = yield* Ripgrep.Service
|
||||||
const scope = yield* Scope.Scope
|
const scope = yield* Scope.Scope
|
||||||
const files: string[] = []
|
const files: string[] = []
|
||||||
const directories = new Set<string>()
|
const directories = new Set<string>()
|
||||||
|
const home = Protected.isHome(location.directory)
|
||||||
yield* ripgrep
|
yield* ripgrep
|
||||||
.find({
|
.find({
|
||||||
cwd: location.directory,
|
cwd: location.directory,
|
||||||
pattern: "*",
|
pattern: "*",
|
||||||
limit: location.vcs ? Number.MAX_SAFE_INTEGER : 100_000,
|
limit: location.vcs && !home ? Number.MAX_SAFE_INTEGER : 100_000,
|
||||||
|
exclude: home ? [...Protected.names()].map((name) => `${name}/**`) : undefined,
|
||||||
onEntry: (entry) =>
|
onEntry: (entry) =>
|
||||||
Effect.sync(() => {
|
Effect.sync(() => {
|
||||||
files.push(entry.path)
|
files.push(entry.path)
|
||||||
@@ -47,57 +46,6 @@ export const ripgrepLayer = Layer.effect(
|
|||||||
})
|
})
|
||||||
.pipe(Effect.orDie, Effect.asVoid, Effect.forkIn(scope))
|
.pipe(Effect.orDie, Effect.asVoid, Effect.forkIn(scope))
|
||||||
return Service.of({
|
return Service.of({
|
||||||
glob: (input) =>
|
|
||||||
Effect.gen(function* () {
|
|
||||||
const target = path.resolve(location.directory, input.path ?? ".")
|
|
||||||
const info = yield* fs.stat(target).pipe(Effect.orDie)
|
|
||||||
const cwd = info.type === "File" ? path.dirname(target) : target
|
|
||||||
return yield* ripgrep
|
|
||||||
.glob({
|
|
||||||
cwd,
|
|
||||||
pattern: input.pattern,
|
|
||||||
limit: input.limit ?? FileSystem.DEFAULT_SEARCH_LIMIT,
|
|
||||||
})
|
|
||||||
.pipe(
|
|
||||||
Effect.map((result) =>
|
|
||||||
result.map((entry) =>
|
|
||||||
FileSystem.Entry.make({
|
|
||||||
...entry,
|
|
||||||
path: RelativePath.make(path.relative(location.directory, path.resolve(cwd, entry.path))),
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Effect.orDie,
|
|
||||||
)
|
|
||||||
}),
|
|
||||||
grep: (input) =>
|
|
||||||
Effect.gen(function* () {
|
|
||||||
const target = path.resolve(location.directory, input.path ?? ".")
|
|
||||||
const info = yield* fs.stat(target).pipe(Effect.orDie)
|
|
||||||
const cwd = info.type === "File" ? path.dirname(target) : target
|
|
||||||
return yield* ripgrep
|
|
||||||
.grep({
|
|
||||||
cwd,
|
|
||||||
pattern: input.pattern,
|
|
||||||
file: info.type === "File" ? path.basename(target) : undefined,
|
|
||||||
include: input.include,
|
|
||||||
limit: input.limit ?? FileSystem.DEFAULT_SEARCH_LIMIT,
|
|
||||||
})
|
|
||||||
.pipe(
|
|
||||||
Effect.map((result) =>
|
|
||||||
result.map((match) =>
|
|
||||||
FileSystem.Match.make({
|
|
||||||
...match,
|
|
||||||
entry: FileSystem.Entry.make({
|
|
||||||
...match.entry,
|
|
||||||
path: RelativePath.make(path.relative(location.directory, path.resolve(cwd, match.entry.path))),
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Effect.orDie,
|
|
||||||
)
|
|
||||||
}),
|
|
||||||
find: (input) =>
|
find: (input) =>
|
||||||
Effect.gen(function* () {
|
Effect.gen(function* () {
|
||||||
const items =
|
const items =
|
||||||
@@ -139,55 +87,10 @@ export const fffLayer = Layer.effect(
|
|||||||
if (result) yield* Effect.logWarning("failed to initialize fff", { error: result.error })
|
if (result) yield* Effect.logWarning("failed to initialize fff", { error: result.error })
|
||||||
return Service.of({
|
return Service.of({
|
||||||
find: () => Effect.succeed([]),
|
find: () => Effect.succeed([]),
|
||||||
glob: () => Effect.succeed([]),
|
|
||||||
grep: () => Effect.succeed([]),
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
yield* Effect.addFinalizer(() => Effect.sync(() => result.value.destroy()).pipe(Effect.ignore))
|
yield* Effect.addFinalizer(() => Effect.sync(() => result.value.destroy()).pipe(Effect.ignore))
|
||||||
return Service.of({
|
return Service.of({
|
||||||
glob: (input) =>
|
|
||||||
Effect.sync(() => {
|
|
||||||
const prefix = input.path?.replaceAll("\\", "/").replace(/\/$/, "")
|
|
||||||
const found = result.value.glob(prefix ? `${prefix}/${input.pattern}` : input.pattern, {
|
|
||||||
pageIndex: 0,
|
|
||||||
pageSize: input.limit ?? FileSystem.DEFAULT_SEARCH_LIMIT,
|
|
||||||
})
|
|
||||||
if (!found.ok) throw found.error
|
|
||||||
return found.value.items.map((item) =>
|
|
||||||
FileSystem.Entry.make({
|
|
||||||
path: RelativePath.make(item.relativePath.replaceAll("\\", "/")),
|
|
||||||
type: "file",
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
}),
|
|
||||||
grep: (input) =>
|
|
||||||
Effect.sync(() => {
|
|
||||||
const prefix = input.path?.replaceAll("\\", "/").replace(/\/$/, "")
|
|
||||||
const found = result.value.grep(
|
|
||||||
[prefix ? `${prefix}/**` : undefined, input.include, input.pattern]
|
|
||||||
.filter((value) => value !== undefined)
|
|
||||||
.join(" "),
|
|
||||||
{ mode: "regex", pageSize: input.limit ?? FileSystem.DEFAULT_SEARCH_LIMIT, timeBudgetMs: 1_500 },
|
|
||||||
)
|
|
||||||
if (!found.ok) throw found.error
|
|
||||||
return found.value.items.map((match) => {
|
|
||||||
const bytes = Buffer.from(match.lineContent)
|
|
||||||
return FileSystem.Match.make({
|
|
||||||
entry: FileSystem.Entry.make({
|
|
||||||
path: RelativePath.make(match.relativePath.replaceAll("\\", "/")),
|
|
||||||
type: "file",
|
|
||||||
}),
|
|
||||||
line: match.lineNumber,
|
|
||||||
offset: match.byteOffset,
|
|
||||||
text: match.lineContent.length > 2_000 ? match.lineContent.slice(0, 2_000) + "..." : match.lineContent,
|
|
||||||
submatches: match.matchRanges.map(([start, end]) => ({
|
|
||||||
text: bytes.subarray(start, end).toString("utf8"),
|
|
||||||
start,
|
|
||||||
end,
|
|
||||||
})),
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}),
|
|
||||||
find: (input) =>
|
find: (input) =>
|
||||||
Effect.sync(() => {
|
Effect.sync(() => {
|
||||||
const options = { pageIndex: 0, pageSize: input.limit ?? 50 }
|
const options = { pageIndex: 0, pageSize: input.limit ?? 50 }
|
||||||
@@ -232,18 +135,19 @@ export const fffLayer = Layer.effect(
|
|||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
|
|
||||||
export const layer = (options?: Options) => Layer.unwrap(
|
export const layer = (options?: Options) =>
|
||||||
Effect.gen(function* () {
|
Layer.unwrap(
|
||||||
if (options?.fff === false || (options?.fff === undefined && process.platform === "win32") || !Fff.available())
|
Effect.gen(function* () {
|
||||||
return ripgrepLayer
|
if (options?.fff === false || (options?.fff === undefined && process.platform === "win32") || !Fff.available())
|
||||||
const location = yield* Location.Service
|
return ripgrepLayer
|
||||||
// Non-VCS locations can contain many repositories, so avoid eagerly content-indexing the entire aggregate tree.
|
const location = yield* Location.Service
|
||||||
return location.vcs ? fffLayer : ripgrepLayer
|
// Non-VCS locations can contain many repositories, so avoid eagerly content-indexing the entire aggregate tree.
|
||||||
}),
|
return location.vcs && !Protected.isHome(location.directory) ? fffLayer : ripgrepLayer
|
||||||
)
|
}),
|
||||||
|
)
|
||||||
|
|
||||||
export function configured(options?: Options) {
|
export function configured(options?: Options) {
|
||||||
return makeLocationNode({ service: Service, layer: layer(options), deps: [FSUtil.node, Location.node, Ripgrep.node] })
|
return makeLocationNode({ service: Service, layer: layer(options), deps: [Location.node, Ripgrep.node] })
|
||||||
}
|
}
|
||||||
|
|
||||||
export const node = configured()
|
export const node = configured()
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ const prefixes = {
|
|||||||
part: "prt",
|
part: "prt",
|
||||||
pty: "pty",
|
pty: "pty",
|
||||||
tool: "tool",
|
tool: "tool",
|
||||||
workspace: "wrk",
|
|
||||||
} as const
|
} as const
|
||||||
|
|
||||||
export function ascending(prefix: keyof typeof prefixes, given?: string) {
|
export function ascending(prefix: keyof typeof prefixes, given?: string) {
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ import { Credential } from "../credential"
|
|||||||
import { Bus } from "../bus"
|
import { Bus } from "../bus"
|
||||||
import { Form } from "../form"
|
import { Form } from "../form"
|
||||||
import { Integration } from "../integration"
|
import { Integration } from "../integration"
|
||||||
import { IntegrationConnection } from "../integration/connection"
|
|
||||||
import { KeyedMutex } from "../effect/keyed-mutex"
|
import { KeyedMutex } from "../effect/keyed-mutex"
|
||||||
import { Location } from "../location"
|
import { Location } from "../location"
|
||||||
import { waitForAbort } from "@opencode-ai/util/process"
|
import { waitForAbort } from "@opencode-ai/util/process"
|
||||||
@@ -31,7 +30,6 @@ export class ServerInfo extends Schema.Class<ServerInfo>("MCP.ServerInfo")({
|
|||||||
name: ServerName,
|
name: ServerName,
|
||||||
status: Status,
|
status: Status,
|
||||||
integrationID: Integration.ID.pipe(Schema.optional),
|
integrationID: Integration.ID.pipe(Schema.optional),
|
||||||
connection: IntegrationConnection.Info.pipe(Schema.optional),
|
|
||||||
}) {}
|
}) {}
|
||||||
|
|
||||||
export class ServerInstructions extends Schema.Class<ServerInstructions>("MCP.ServerInstructions")({
|
export class ServerInstructions extends Schema.Class<ServerInstructions>("MCP.ServerInstructions")({
|
||||||
@@ -247,14 +245,6 @@ export const layer = (options?: Options) => Layer.effect(
|
|||||||
return { name, entry }
|
return { name, entry }
|
||||||
})
|
})
|
||||||
|
|
||||||
const info = (name: ServerName, entry: ServerEntry, connection: IntegrationConnection.Info | undefined) =>
|
|
||||||
new ServerInfo({
|
|
||||||
name,
|
|
||||||
status: entry.status,
|
|
||||||
integrationID: entry.integrationID,
|
|
||||||
connection,
|
|
||||||
})
|
|
||||||
|
|
||||||
// Builds the connect-time auth provider for a remote OAuth-integration server. The SDK presents and
|
// Builds the connect-time auth provider for a remote OAuth-integration server. The SDK presents and
|
||||||
// refreshes stored tokens, persisting refreshes back to the same credential row. The provider never
|
// refreshes stored tokens, persisting refreshes back to the same credential row. The provider never
|
||||||
// opens a browser, so an auth-gated connect ends in UnauthorizedError -> needs_auth rather than a redirect.
|
// opens a browser, so an auth-gated connect ends in UnauthorizedError -> needs_auth rather than a redirect.
|
||||||
@@ -603,15 +593,12 @@ export const layer = (options?: Options) => Layer.effect(
|
|||||||
)
|
)
|
||||||
return Service.of({
|
return Service.of({
|
||||||
servers: Effect.fn("MCP.servers")(function* () {
|
servers: Effect.fn("MCP.servers")(function* () {
|
||||||
const entries = Array.from(runtime).toSorted(([a], [b]) => a.localeCompare(b))
|
return Array.from(runtime)
|
||||||
return yield* Effect.forEach(entries, ([name, entry]) =>
|
.toSorted(([a], [b]) => a.localeCompare(b))
|
||||||
Effect.gen(function* () {
|
.map(
|
||||||
const connection = entry.integrationID
|
([name, entry]) =>
|
||||||
? yield* integration.connection.active(entry.integrationID)
|
new ServerInfo({ name, status: entry.status, integrationID: entry.integrationID }),
|
||||||
: undefined
|
)
|
||||||
return info(name, entry, connection)
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
}),
|
}),
|
||||||
add: Effect.fn("MCP.add")(function* (server, config) {
|
add: Effect.fn("MCP.add")(function* (server, config) {
|
||||||
const name = ServerName.make(server)
|
const name = ServerName.make(server)
|
||||||
|
|||||||
@@ -59,16 +59,6 @@ export interface Interface {
|
|||||||
readonly list: () => Effect.Effect<ReadonlyArray<Info>>
|
readonly list: () => Effect.Effect<ReadonlyArray<Info>>
|
||||||
readonly directories: (input: DirectoriesInput) => Effect.Effect<Directories>
|
readonly directories: (input: DirectoriesInput) => Effect.Effect<Directories>
|
||||||
readonly resolve: (input: AbsolutePath) => Effect.Effect<Resolved>
|
readonly resolve: (input: AbsolutePath) => Effect.Effect<Resolved>
|
||||||
/**
|
|
||||||
* Temporary bridge method for writing the resolved project ID to the repo-local cache.
|
|
||||||
*
|
|
||||||
* This exists while the old opencode project service and this core project
|
|
||||||
* service work together: core resolves the ID, while the old service still owns
|
|
||||||
* database migration and persistence. The old service should call this after it
|
|
||||||
* finishes migrating from `resolve().previous` to `resolve().id`; once project
|
|
||||||
* persistence moves into core, this separate bridge method can go away.
|
|
||||||
*/
|
|
||||||
readonly commit: (input: { store: AbsolutePath; id: ID }) => Effect.Effect<void>
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Service extends Context.Service<Service, Interface>()("@opencode/Project") {}
|
export class Service extends Context.Service<Service, Interface>()("@opencode/Project") {}
|
||||||
@@ -268,11 +258,7 @@ const layer = Layer.effect(
|
|||||||
return yield* persist({ id: ID.global, directory, canonical: directory, vcs: undefined })
|
return yield* persist({ id: ID.global, directory, canonical: directory, vcs: undefined })
|
||||||
})
|
})
|
||||||
|
|
||||||
const commit = Effect.fn("Project.commit")(function* (input: { store: AbsolutePath; id: ID }) {
|
return Service.of({ list, directories, resolve })
|
||||||
yield* fs.writeFileString(path.join(input.store, "opencode"), input.id).pipe(Effect.ignore)
|
|
||||||
})
|
|
||||||
|
|
||||||
return Service.of({ list, directories, resolve, commit })
|
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -70,11 +70,6 @@ export class StrategyUnavailableError extends Schema.TaggedErrorClass<StrategyUn
|
|||||||
{ strategy: StrategyID },
|
{ strategy: StrategyID },
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
export class DuplicateStrategyError extends Schema.TaggedErrorClass<DuplicateStrategyError>()(
|
|
||||||
"ProjectCopy.DuplicateStrategyError",
|
|
||||||
{ strategy: StrategyID },
|
|
||||||
) {}
|
|
||||||
|
|
||||||
export type Error =
|
export type Error =
|
||||||
| SourceDirectoryNotFoundError
|
| SourceDirectoryNotFoundError
|
||||||
| DestinationExistsError
|
| DestinationExistsError
|
||||||
@@ -99,7 +94,6 @@ export interface Strategy {
|
|||||||
export { Event }
|
export { Event }
|
||||||
|
|
||||||
export interface Interface {
|
export interface Interface {
|
||||||
readonly register: (strategy: Strategy) => Effect.Effect<void, DuplicateStrategyError>
|
|
||||||
readonly create: (input: CreateInput) => Effect.Effect<Copy, Error>
|
readonly create: (input: CreateInput) => Effect.Effect<Copy, Error>
|
||||||
readonly remove: (input: RemoveInput) => Effect.Effect<void, Error>
|
readonly remove: (input: RemoveInput) => Effect.Effect<void, Error>
|
||||||
readonly refresh: (input: RefreshInput) => Effect.Effect<RefreshResult, Error>
|
readonly refresh: (input: RefreshInput) => Effect.Effect<RefreshResult, Error>
|
||||||
@@ -144,29 +138,18 @@ const layer = Layer.effect(
|
|||||||
return resolved
|
return resolved
|
||||||
})
|
})
|
||||||
|
|
||||||
const registry = new Map<StrategyID, Strategy>()
|
const strategy = makeGitWorktreeStrategy({ git, canonical })
|
||||||
|
|
||||||
const register = Effect.fn("ProjectCopy.register")(function* (strategy: Strategy) {
|
|
||||||
if (registry.has(strategy.id)) return yield* new DuplicateStrategyError({ strategy: strategy.id })
|
|
||||||
registry.set(strategy.id, strategy)
|
|
||||||
})
|
|
||||||
|
|
||||||
// Register default strategies
|
|
||||||
yield* register(makeGitWorktreeStrategy({ git, canonical })).pipe(Effect.orDie)
|
|
||||||
|
|
||||||
const strategies = () => Array.from(registry.values())
|
|
||||||
|
|
||||||
const source = Effect.fnUntraced(function* (input: AbsolutePath, projectID: Project.ID) {
|
const source = Effect.fnUntraced(function* (input: AbsolutePath, projectID: Project.ID) {
|
||||||
const sourceDirectory = yield* canonical(input)
|
const sourceDirectory = yield* canonical(input)
|
||||||
if (!(yield* directories.contains({ projectID, directory: sourceDirectory })))
|
if ((yield* directories.get({ projectID, directory: sourceDirectory })) === undefined)
|
||||||
return yield* new SourceDirectoryNotFoundError({ directory: sourceDirectory })
|
return yield* new SourceDirectoryNotFoundError({ directory: sourceDirectory })
|
||||||
return sourceDirectory
|
return sourceDirectory
|
||||||
})
|
})
|
||||||
|
|
||||||
const getStrategy = Effect.fnUntraced(function* (id: StrategyID) {
|
const getStrategy = Effect.fnUntraced(function* (id: StrategyID) {
|
||||||
const found = registry.get(id)
|
if (id !== strategy.id) return yield* new StrategyUnavailableError({ strategy: id })
|
||||||
if (!found) return yield* new StrategyUnavailableError({ strategy: id })
|
return strategy
|
||||||
return found
|
|
||||||
})
|
})
|
||||||
|
|
||||||
const create = Effect.fn("ProjectCopy.create")(function* (input: CreateInput) {
|
const create = Effect.fn("ProjectCopy.create")(function* (input: CreateInput) {
|
||||||
@@ -226,20 +209,18 @@ const layer = Layer.effect(
|
|||||||
const discovered = yield* Effect.forEach(
|
const discovered = yield* Effect.forEach(
|
||||||
sourceDirectories,
|
sourceDirectories,
|
||||||
(sourceDirectory) =>
|
(sourceDirectory) =>
|
||||||
Effect.forEach(strategies(), (strategy) =>
|
strategy.list(sourceDirectory).pipe(
|
||||||
strategy.list(sourceDirectory).pipe(
|
Effect.catchTag("ProjectCopy.DirectoryUnavailableError", () => Effect.succeed([])),
|
||||||
Effect.catchTag("ProjectCopy.DirectoryUnavailableError", () => Effect.succeed([])),
|
Effect.map((items) =>
|
||||||
Effect.map((items) =>
|
items.map((item) => ({
|
||||||
items.map((item) => ({
|
directory: item.directory,
|
||||||
directory: item.directory,
|
strategy: item.type === "copy" ? strategy.id : undefined,
|
||||||
strategy: item.type === "copy" ? strategy.id : undefined,
|
})),
|
||||||
})),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
{ concurrency: "unbounded" },
|
{ concurrency: "unbounded" },
|
||||||
).pipe(
|
).pipe(
|
||||||
Effect.map((sets) => new Map(sets.flat(2).map((item) => [item.directory, item] as const)).values().toArray()),
|
Effect.map((sets) => new Map(sets.flat().map((item) => [item.directory, item] as const)).values().toArray()),
|
||||||
)
|
)
|
||||||
const removed = checked.filter((item) => !item.exists).map((item) => item.directory)
|
const removed = checked.filter((item) => !item.exists).map((item) => item.directory)
|
||||||
const result = yield* db
|
const result = yield* db
|
||||||
@@ -271,7 +252,6 @@ const layer = Layer.effect(
|
|||||||
})
|
})
|
||||||
|
|
||||||
return Service.of({
|
return Service.of({
|
||||||
register,
|
|
||||||
create,
|
create,
|
||||||
remove,
|
remove,
|
||||||
refresh,
|
refresh,
|
||||||
|
|||||||
@@ -41,7 +41,6 @@ export interface Interface {
|
|||||||
projectID: ProjectSchema.ID
|
projectID: ProjectSchema.ID
|
||||||
directory: AbsolutePath
|
directory: AbsolutePath
|
||||||
}) => Effect.Effect<Directory | undefined>
|
}) => Effect.Effect<Directory | undefined>
|
||||||
readonly contains: (input: { projectID: ProjectSchema.ID; directory: AbsolutePath }) => Effect.Effect<boolean>
|
|
||||||
readonly create: (input: CreateInput, tx?: Transaction) => Effect.Effect<boolean>
|
readonly create: (input: CreateInput, tx?: Transaction) => Effect.Effect<boolean>
|
||||||
readonly remove: (input: RemoveInput, tx?: Transaction) => Effect.Effect<boolean>
|
readonly remove: (input: RemoveInput, tx?: Transaction) => Effect.Effect<boolean>
|
||||||
}
|
}
|
||||||
@@ -99,25 +98,6 @@ const layer = Layer.effect(
|
|||||||
return rows.map((row) => ({ directory: row.directory, strategy: row.strategy ?? undefined }))
|
return rows.map((row) => ({ directory: row.directory, strategy: row.strategy ?? undefined }))
|
||||||
})
|
})
|
||||||
|
|
||||||
const contains = Effect.fn("ProjectDirectories.contains")(function* (input: {
|
|
||||||
projectID: ProjectSchema.ID
|
|
||||||
directory: AbsolutePath
|
|
||||||
}) {
|
|
||||||
return (
|
|
||||||
(yield* db
|
|
||||||
.select({ directory: ProjectDirectoryTable.directory })
|
|
||||||
.from(ProjectDirectoryTable)
|
|
||||||
.where(
|
|
||||||
and(
|
|
||||||
eq(ProjectDirectoryTable.project_id, input.projectID),
|
|
||||||
eq(ProjectDirectoryTable.directory, input.directory),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.get()
|
|
||||||
.pipe(Effect.orDie)) !== undefined
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
||||||
const get = Effect.fn("ProjectDirectories.get")(function* (input: {
|
const get = Effect.fn("ProjectDirectories.get")(function* (input: {
|
||||||
projectID: ProjectSchema.ID
|
projectID: ProjectSchema.ID
|
||||||
directory: AbsolutePath
|
directory: AbsolutePath
|
||||||
@@ -139,7 +119,6 @@ const layer = Layer.effect(
|
|||||||
return Service.of({
|
return Service.of({
|
||||||
list,
|
list,
|
||||||
get,
|
get,
|
||||||
contains,
|
|
||||||
create,
|
create,
|
||||||
remove,
|
remove,
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
export * as PtyTicket from "./ticket"
|
export * as PtyTicket from "./ticket"
|
||||||
|
|
||||||
import { Workspace } from "../workspace"
|
|
||||||
import { PtyTicket } from "@opencode-ai/schema/pty-ticket"
|
import { PtyTicket } from "@opencode-ai/schema/pty-ticket"
|
||||||
import { PtyID } from "./schema"
|
import { PtyID } from "./schema"
|
||||||
import { Cache, Context, Duration, Effect, Layer } from "effect"
|
import { Cache, Context, Duration, Effect, Layer } from "effect"
|
||||||
@@ -14,7 +13,6 @@ export const ConnectToken = PtyTicket.ConnectToken
|
|||||||
export type Scope = {
|
export type Scope = {
|
||||||
readonly ptyID: PtyID
|
readonly ptyID: PtyID
|
||||||
readonly directory?: string
|
readonly directory?: string
|
||||||
readonly workspaceID?: Workspace.ID
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Interface {
|
export interface Interface {
|
||||||
@@ -25,9 +23,7 @@ export interface Interface {
|
|||||||
export class Service extends Context.Service<Service, Interface>()("@opencode/PtyTicket") {}
|
export class Service extends Context.Service<Service, Interface>()("@opencode/PtyTicket") {}
|
||||||
|
|
||||||
function matches(record: Scope, input: Scope) {
|
function matches(record: Scope, input: Scope) {
|
||||||
return (
|
return record.ptyID === input.ptyID && record.directory === input.directory
|
||||||
record.ptyID === input.ptyID && record.directory === input.directory && record.workspaceID === input.workspaceID
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tickets are inserted via Cache.set and removed atomically via invalidateWhen. The lookup is
|
// Tickets are inserted via Cache.set and removed atomically via invalidateWhen. The lookup is
|
||||||
|
|||||||
@@ -31,14 +31,6 @@ export type EnsureInput = {
|
|||||||
readonly branch?: string
|
readonly branch?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export class InvalidRepositoryError extends Schema.TaggedErrorClass<InvalidRepositoryError>()(
|
|
||||||
"RepositoryCacheInvalidRepositoryError",
|
|
||||||
{
|
|
||||||
repository: Schema.String,
|
|
||||||
message: Schema.String,
|
|
||||||
},
|
|
||||||
) {}
|
|
||||||
|
|
||||||
export class InvalidBranchError extends Schema.TaggedErrorClass<InvalidBranchError>()(
|
export class InvalidBranchError extends Schema.TaggedErrorClass<InvalidBranchError>()(
|
||||||
"RepositoryCacheInvalidBranchError",
|
"RepositoryCacheInvalidBranchError",
|
||||||
{
|
{
|
||||||
@@ -86,7 +78,6 @@ export class CacheOperationError extends Schema.TaggedErrorClass<CacheOperationE
|
|||||||
) {}
|
) {}
|
||||||
|
|
||||||
export type Error =
|
export type Error =
|
||||||
| InvalidRepositoryError
|
|
||||||
| InvalidBranchError
|
| InvalidBranchError
|
||||||
| CloneFailedError
|
| CloneFailedError
|
||||||
| FetchFailedError
|
| FetchFailedError
|
||||||
@@ -103,7 +94,6 @@ export class Service extends Context.Service<Service, Interface>()("@opencode/Re
|
|||||||
|
|
||||||
export function isError(error: unknown): error is Error {
|
export function isError(error: unknown): error is Error {
|
||||||
return (
|
return (
|
||||||
error instanceof InvalidRepositoryError ||
|
|
||||||
error instanceof InvalidBranchError ||
|
error instanceof InvalidBranchError ||
|
||||||
error instanceof CloneFailedError ||
|
error instanceof CloneFailedError ||
|
||||||
error instanceof FetchFailedError ||
|
error instanceof FetchFailedError ||
|
||||||
@@ -114,13 +104,6 @@ export function isError(error: unknown): error is Error {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export const parseRemote = Effect.fn("RepositoryCache.parseRemote")(function* (repository: string) {
|
|
||||||
return yield* Effect.try({
|
|
||||||
try: () => Repository.parseRemote(repository),
|
|
||||||
catch: (error) => new InvalidRepositoryError({ repository, message: errorMessage(error) }),
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
export const validateBranch = Effect.fn("RepositoryCache.validateBranch")(function* (branch: string) {
|
export const validateBranch = Effect.fn("RepositoryCache.validateBranch")(function* (branch: string) {
|
||||||
return yield* Effect.try({
|
return yield* Effect.try({
|
||||||
try: () => Repository.validateBranch(branch),
|
try: () => Repository.validateBranch(branch),
|
||||||
|
|||||||
@@ -44,16 +44,6 @@ export class InvalidBranchError extends Schema.TaggedErrorClass<InvalidBranchErr
|
|||||||
message: Schema.String,
|
message: Schema.String,
|
||||||
}) {}
|
}) {}
|
||||||
|
|
||||||
export type Error = InvalidReferenceError | UnsupportedLocalRepositoryError | InvalidBranchError
|
|
||||||
|
|
||||||
export function isError(error: unknown): error is Error {
|
|
||||||
return (
|
|
||||||
error instanceof InvalidReferenceError ||
|
|
||||||
error instanceof UnsupportedLocalRepositoryError ||
|
|
||||||
error instanceof InvalidBranchError
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export function parse(input: string): Reference | undefined {
|
export function parse(input: string): Reference | undefined {
|
||||||
const cleaned = normalizeInput(input)
|
const cleaned = normalizeInput(input)
|
||||||
if (!cleaned) return
|
if (!cleaned) return
|
||||||
|
|||||||
@@ -52,6 +52,7 @@ export interface FindInput {
|
|||||||
readonly cwd: string
|
readonly cwd: string
|
||||||
readonly pattern: string
|
readonly pattern: string
|
||||||
readonly limit: number
|
readonly limit: number
|
||||||
|
readonly exclude?: readonly string[]
|
||||||
readonly hidden?: boolean
|
readonly hidden?: boolean
|
||||||
readonly follow?: boolean
|
readonly follow?: boolean
|
||||||
readonly signal?: AbortSignal
|
readonly signal?: AbortSignal
|
||||||
@@ -195,6 +196,7 @@ const layer = Layer.effect(
|
|||||||
...(input.hidden ? ["--hidden"] : []),
|
...(input.hidden ? ["--hidden"] : []),
|
||||||
...(input.follow ? ["--follow"] : []),
|
...(input.follow ? ["--follow"] : []),
|
||||||
...(input.pattern === "*" ? [] : [`--glob=${input.pattern}`]),
|
...(input.pattern === "*" ? [] : [`--glob=${input.pattern}`]),
|
||||||
|
...(input.exclude ?? []).map((pattern) => `--glob=!${pattern}`),
|
||||||
"--glob=!**/.git/**",
|
"--glob=!**/.git/**",
|
||||||
".",
|
".",
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import { Effect, Layer, Schema, Context, Stream, Scope } from "effect"
|
|||||||
import { ListAnchor } from "@opencode-ai/schema/session"
|
import { ListAnchor } from "@opencode-ai/schema/session"
|
||||||
import { and, asc, desc, eq, gt, isNotNull, isNull, like, lt, ne, or, type SQL } from "drizzle-orm"
|
import { and, asc, desc, eq, gt, isNotNull, isNull, like, lt, ne, or, type SQL } from "drizzle-orm"
|
||||||
import { Project } from "./project"
|
import { Project } from "./project"
|
||||||
import { Workspace } from "./workspace"
|
|
||||||
import { Model } from "./model"
|
import { Model } from "./model"
|
||||||
import { Location } from "./location"
|
import { Location } from "./location"
|
||||||
import { SessionMessage } from "./session/message"
|
import { SessionMessage } from "./session/message"
|
||||||
@@ -52,9 +51,6 @@ import { Shell as ShellSchema } from "@opencode-ai/schema/shell"
|
|||||||
import { KeyedMutex } from "./effect/keyed-mutex"
|
import { KeyedMutex } from "./effect/keyed-mutex"
|
||||||
import { fileURLToPath } from "url"
|
import { fileURLToPath } from "url"
|
||||||
|
|
||||||
export const RevertState = Session.Revert
|
|
||||||
export type RevertState = Session.Revert
|
|
||||||
|
|
||||||
// get project -> project.locations
|
// get project -> project.locations
|
||||||
//
|
//
|
||||||
// get all sessions
|
// get all sessions
|
||||||
@@ -62,12 +58,9 @@ export type RevertState = Session.Revert
|
|||||||
|
|
||||||
// - by project
|
// - by project
|
||||||
// - by subpath
|
// - by subpath
|
||||||
// - by workspace (home is special)
|
|
||||||
|
|
||||||
export { ListAnchor }
|
export { ListAnchor }
|
||||||
|
|
||||||
const ListInputBase = {
|
const ListInputBase = {
|
||||||
workspaceID: Workspace.ID.pipe(Schema.optional),
|
|
||||||
search: Schema.String.pipe(Schema.optional),
|
search: Schema.String.pipe(Schema.optional),
|
||||||
limit: PositiveInt.pipe(Schema.optional),
|
limit: PositiveInt.pipe(Schema.optional),
|
||||||
order: Schema.Literals(["asc", "desc"]).pipe(Schema.optional),
|
order: Schema.Literals(["asc", "desc"]).pipe(Schema.optional),
|
||||||
@@ -110,13 +103,6 @@ type ForkInput = {
|
|||||||
boundary: Session.ForkRequestBoundary
|
boundary: Session.ForkRequestBoundary
|
||||||
}
|
}
|
||||||
|
|
||||||
export class OperationUnavailableError extends Schema.TaggedErrorClass<OperationUnavailableError>()(
|
|
||||||
"Session.OperationUnavailableError",
|
|
||||||
{
|
|
||||||
operation: Schema.Literals(["move", "skill", "switchAgent", "compact"]),
|
|
||||||
},
|
|
||||||
) {}
|
|
||||||
|
|
||||||
export { MessageDecodeError, NotFoundError }
|
export { MessageDecodeError, NotFoundError }
|
||||||
|
|
||||||
export class PromptConflictError extends Schema.TaggedErrorClass<PromptConflictError>()("Session.PromptConflictError", {
|
export class PromptConflictError extends Schema.TaggedErrorClass<PromptConflictError>()("Session.PromptConflictError", {
|
||||||
@@ -160,23 +146,6 @@ export class DestinationNotDirectoryError extends Schema.TaggedErrorClass<Destin
|
|||||||
export const MessageNotFoundError = SessionRevert.MessageNotFoundError
|
export const MessageNotFoundError = SessionRevert.MessageNotFoundError
|
||||||
export type MessageNotFoundError = SessionRevert.MessageNotFoundError
|
export type MessageNotFoundError = SessionRevert.MessageNotFoundError
|
||||||
|
|
||||||
export type Error =
|
|
||||||
| NotFoundError
|
|
||||||
| MessageDecodeError
|
|
||||||
| OperationUnavailableError
|
|
||||||
| PromptConflictError
|
|
||||||
| SyntheticConflictError
|
|
||||||
| AttachmentError
|
|
||||||
| CompactionConflictError
|
|
||||||
| BusyError
|
|
||||||
| SkillNotFoundError
|
|
||||||
| DestinationNotFoundError
|
|
||||||
| DestinationNotDirectoryError
|
|
||||||
| Command.NotFoundError
|
|
||||||
| Command.EvaluationError
|
|
||||||
| MessageNotFoundError
|
|
||||||
| SessionGenerate.Error
|
|
||||||
|
|
||||||
export interface Interface {
|
export interface Interface {
|
||||||
readonly list: (input?: ListInput) => Effect.Effect<{
|
readonly list: (input?: ListInput) => Effect.Effect<{
|
||||||
readonly data: SessionSchema.Info[]
|
readonly data: SessionSchema.Info[]
|
||||||
@@ -233,7 +202,6 @@ export interface Interface {
|
|||||||
readonly move: (input: {
|
readonly move: (input: {
|
||||||
sessionID: SessionSchema.ID
|
sessionID: SessionSchema.ID
|
||||||
directory: AbsolutePath
|
directory: AbsolutePath
|
||||||
workspaceID?: Location.Ref["workspaceID"]
|
|
||||||
}) => Effect.Effect<void, NotFoundError | DestinationNotFoundError | DestinationNotDirectoryError>
|
}) => Effect.Effect<void, NotFoundError | DestinationNotFoundError | DestinationNotDirectoryError>
|
||||||
readonly prompt: (input: {
|
readonly prompt: (input: {
|
||||||
id?: SessionMessage.ID
|
id?: SessionMessage.ID
|
||||||
@@ -373,7 +341,6 @@ const layer = Layer.effect(
|
|||||||
parentID: input.parentID,
|
parentID: input.parentID,
|
||||||
directory: location.directory,
|
directory: location.directory,
|
||||||
path: path.relative(project.directory, location.directory).replaceAll("\\", "/"),
|
path: path.relative(project.directory, location.directory).replaceAll("\\", "/"),
|
||||||
workspaceID: location.workspaceID ? Workspace.ID.make(location.workspaceID) : undefined,
|
|
||||||
title: input.title,
|
title: input.title,
|
||||||
agent: input.agent,
|
agent: input.agent,
|
||||||
model: input.model
|
model: input.model
|
||||||
@@ -461,7 +428,6 @@ const layer = Layer.effect(
|
|||||||
const sortColumn = SessionTable.time_updated
|
const sortColumn = SessionTable.time_updated
|
||||||
const conditions: SQL[] = []
|
const conditions: SQL[] = []
|
||||||
if ("directory" in input) conditions.push(eq(SessionTable.directory, input.directory))
|
if ("directory" in input) conditions.push(eq(SessionTable.directory, input.directory))
|
||||||
if (input.workspaceID) conditions.push(eq(SessionTable.workspace_id, input.workspaceID))
|
|
||||||
if ("project" in input) conditions.push(eq(SessionTable.project_id, input.project))
|
if ("project" in input) conditions.push(eq(SessionTable.project_id, input.project))
|
||||||
if ("project" in input && input.subpath !== undefined) conditions.push(eq(SessionTable.path, input.subpath))
|
if ("project" in input && input.subpath !== undefined) conditions.push(eq(SessionTable.path, input.subpath))
|
||||||
if (input.search) conditions.push(like(SessionTable.title, `%${input.search}%`))
|
if (input.search) conditions.push(like(SessionTable.title, `%${input.search}%`))
|
||||||
@@ -739,11 +705,7 @@ const layer = Layer.effect(
|
|||||||
const info = yield* fs.stat(directory).pipe(Effect.catch(() => Effect.succeed(undefined)))
|
const info = yield* fs.stat(directory).pipe(Effect.catch(() => Effect.succeed(undefined)))
|
||||||
if (!info) return yield* new DestinationNotFoundError({ directory })
|
if (!info) return yield* new DestinationNotFoundError({ directory })
|
||||||
if (info.type !== "Directory") return yield* new DestinationNotDirectoryError({ directory })
|
if (info.type !== "Directory") return yield* new DestinationNotDirectoryError({ directory })
|
||||||
if (
|
if (current.location.directory === directory) return
|
||||||
current.location.directory === directory &&
|
|
||||||
current.location.workspaceID === input.workspaceID
|
|
||||||
)
|
|
||||||
return
|
|
||||||
const project = yield* projects.resolve(directory)
|
const project = yield* projects.resolve(directory)
|
||||||
yield* persistProject(project)
|
yield* persistProject(project)
|
||||||
if ((yield* execution.active).has(input.sessionID)) {
|
if ((yield* execution.active).has(input.sessionID)) {
|
||||||
@@ -752,7 +714,7 @@ const layer = Layer.effect(
|
|||||||
}
|
}
|
||||||
yield* bus.publish(SessionEvent.Moved, {
|
yield* bus.publish(SessionEvent.Moved, {
|
||||||
sessionID: input.sessionID,
|
sessionID: input.sessionID,
|
||||||
location: Location.Ref.make({ directory, workspaceID: input.workspaceID }),
|
location: Location.Ref.make({ directory }),
|
||||||
projectID: project.id,
|
projectID: project.id,
|
||||||
subpath: RelativePath.make(path.relative(project.directory, directory).replaceAll("\\", "/")),
|
subpath: RelativePath.make(path.relative(project.directory, directory).replaceAll("\\", "/")),
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,12 +1,8 @@
|
|||||||
import { castDraft, produce, type WritableDraft } from "immer"
|
import { castDraft, produce, type WritableDraft } from "immer"
|
||||||
import { DateTime, Effect } from "effect"
|
import { DateTime, Effect, Match, pipe } from "effect"
|
||||||
import { SessionEvent } from "./event"
|
import { SessionEvent } from "./event"
|
||||||
import { SessionMessage } from "./message"
|
import { SessionMessage } from "./message"
|
||||||
|
|
||||||
export type MemoryState = {
|
|
||||||
messages: SessionMessage.Info[]
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Adapter {
|
export interface Adapter {
|
||||||
readonly getModel: () => Effect.Effect<SessionMessage.ModelSelected["model"] | undefined, never, never>
|
readonly getModel: () => Effect.Effect<SessionMessage.ModelSelected["model"] | undefined, never, never>
|
||||||
readonly getCurrentAssistant: () => Effect.Effect<SessionMessage.Assistant | undefined, never, never>
|
readonly getCurrentAssistant: () => Effect.Effect<SessionMessage.Assistant | undefined, never, never>
|
||||||
@@ -23,89 +19,7 @@ export interface Adapter {
|
|||||||
readonly appendMessage: (message: SessionMessage.Info) => Effect.Effect<void, never, never>
|
readonly appendMessage: (message: SessionMessage.Info) => Effect.Effect<void, never, never>
|
||||||
}
|
}
|
||||||
|
|
||||||
export function memory(state: MemoryState): Adapter {
|
export function update(adapter: Adapter, event: SessionEvent.DurableEvent) {
|
||||||
const assistantIndex = (messageID: SessionMessage.ID) =>
|
|
||||||
state.messages.findLastIndex((message) => message.id === messageID)
|
|
||||||
const shellIndex = (messageID: SessionMessage.ID) =>
|
|
||||||
state.messages.findLastIndex((message) => message.id === messageID)
|
|
||||||
const compactionIndex = () =>
|
|
||||||
state.messages.findLastIndex((message) => message.type === "compaction" && message.status === "running")
|
|
||||||
// A newer step supersedes stale incomplete rows; never resume an older assistant projection.
|
|
||||||
const latestAssistantIndex = () => state.messages.findLastIndex((message) => message.type === "assistant")
|
|
||||||
|
|
||||||
return {
|
|
||||||
getModel() {
|
|
||||||
return Effect.sync(
|
|
||||||
() =>
|
|
||||||
state.messages.findLast(
|
|
||||||
(message): message is SessionMessage.ModelSelected | SessionMessage.Assistant =>
|
|
||||||
message.type === "model-switched" || message.type === "assistant",
|
|
||||||
)?.model,
|
|
||||||
)
|
|
||||||
},
|
|
||||||
getCurrentAssistant() {
|
|
||||||
return Effect.sync(() => {
|
|
||||||
const index = latestAssistantIndex()
|
|
||||||
if (index < 0) return
|
|
||||||
const assistant = state.messages[index]
|
|
||||||
return assistant?.type === "assistant" && !assistant.time.completed ? assistant : undefined
|
|
||||||
})
|
|
||||||
},
|
|
||||||
getAssistant(messageID) {
|
|
||||||
return Effect.sync(() => {
|
|
||||||
const index = assistantIndex(messageID)
|
|
||||||
if (index < 0) return
|
|
||||||
const assistant = state.messages[index]
|
|
||||||
return assistant?.type === "assistant" ? assistant : undefined
|
|
||||||
})
|
|
||||||
},
|
|
||||||
getShell(shellID) {
|
|
||||||
return Effect.sync(() => {
|
|
||||||
return state.messages.find((message): message is SessionMessage.Shell => {
|
|
||||||
return message.type === "shell" && message.shellID === shellID
|
|
||||||
})
|
|
||||||
})
|
|
||||||
},
|
|
||||||
getCompaction() {
|
|
||||||
return Effect.sync(() => {
|
|
||||||
const index = compactionIndex()
|
|
||||||
const message = state.messages[index]
|
|
||||||
return message?.type === "compaction" ? message : undefined
|
|
||||||
})
|
|
||||||
},
|
|
||||||
updateAssistant(assistant) {
|
|
||||||
return Effect.sync(() => {
|
|
||||||
const index = assistantIndex(assistant.id)
|
|
||||||
if (index < 0) return
|
|
||||||
const current = state.messages[index]
|
|
||||||
if (current?.type !== "assistant") return
|
|
||||||
state.messages[index] = assistant
|
|
||||||
})
|
|
||||||
},
|
|
||||||
updateShell(shell) {
|
|
||||||
return Effect.sync(() => {
|
|
||||||
const index = shellIndex(shell.id)
|
|
||||||
if (index < 0) return
|
|
||||||
const current = state.messages[index]
|
|
||||||
if (current?.type !== "shell") return
|
|
||||||
state.messages[index] = shell
|
|
||||||
})
|
|
||||||
},
|
|
||||||
updateCompaction(compaction) {
|
|
||||||
return Effect.sync(() => {
|
|
||||||
const index = state.messages.findLastIndex((message) => message.id === compaction.id)
|
|
||||||
if (index >= 0) state.messages[index] = compaction
|
|
||||||
})
|
|
||||||
},
|
|
||||||
appendMessage(message) {
|
|
||||||
return Effect.sync(() => {
|
|
||||||
state.messages.push(message)
|
|
||||||
})
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function update(adapter: Adapter, event: SessionEvent.Event) {
|
|
||||||
type DraftAssistant = WritableDraft<SessionMessage.Assistant>
|
type DraftAssistant = WritableDraft<SessionMessage.Assistant>
|
||||||
type DraftTool = WritableDraft<SessionMessage.AssistantTool>
|
type DraftTool = WritableDraft<SessionMessage.AssistantTool>
|
||||||
type DraftText = WritableDraft<SessionMessage.AssistantText>
|
type DraftText = WritableDraft<SessionMessage.AssistantText>
|
||||||
@@ -139,9 +53,9 @@ export function update(adapter: Adapter, event: SessionEvent.Event) {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
return Effect.gen(function* () {
|
const project = pipe(
|
||||||
yield* SessionEvent.All.match(event, {
|
Match.type<SessionEvent.DurableEvent>(),
|
||||||
"session.usage.updated": () => Effect.void,
|
Match.discriminatorsExhaustive("type")({
|
||||||
"session.usage.recorded": () => Effect.void,
|
"session.usage.recorded": () => Effect.void,
|
||||||
"session.agent.selected": (event) => {
|
"session.agent.selected": (event) => {
|
||||||
return adapter.appendMessage(
|
return adapter.appendMessage(
|
||||||
@@ -321,12 +235,6 @@ export function update(adapter: Adapter, event: SessionEvent.Event) {
|
|||||||
draft.content.push(castDraft(SessionMessage.AssistantText.make({ type: "text", text: "" })))
|
draft.content.push(castDraft(SessionMessage.AssistantText.make({ type: "text", text: "" })))
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
"session.text.delta": (event) => {
|
|
||||||
return updateOwnedAssistant(event.data.assistantMessageID, (draft) => {
|
|
||||||
const match = latestText(draft)
|
|
||||||
if (match) match.text += event.data.delta
|
|
||||||
})
|
|
||||||
},
|
|
||||||
"session.text.ended": (event) => {
|
"session.text.ended": (event) => {
|
||||||
return updateOwnedAssistant(event.data.assistantMessageID, (draft) => {
|
return updateOwnedAssistant(event.data.assistantMessageID, (draft) => {
|
||||||
const match = latestText(draft)
|
const match = latestText(draft)
|
||||||
@@ -351,7 +259,6 @@ export function update(adapter: Adapter, event: SessionEvent.Event) {
|
|||||||
)
|
)
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
"session.tool.input.delta": () => Effect.void,
|
|
||||||
"session.tool.input.ended": (event) => {
|
"session.tool.input.ended": (event) => {
|
||||||
return updateOwnedAssistant(event.data.assistantMessageID, (draft) => {
|
return updateOwnedAssistant(event.data.assistantMessageID, (draft) => {
|
||||||
const match = latestTool(draft, event.data.id)
|
const match = latestTool(draft, event.data.id)
|
||||||
@@ -375,14 +282,6 @@ export function update(adapter: Adapter, event: SessionEvent.Event) {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
"session.tool.progress": (event) => {
|
|
||||||
return updateOwnedAssistant(event.data.assistantMessageID, (draft) => {
|
|
||||||
const match = latestTool(draft, event.data.id)
|
|
||||||
if (match && match.state.status === "running") {
|
|
||||||
match.state.metadata = event.data.metadata
|
|
||||||
}
|
|
||||||
})
|
|
||||||
},
|
|
||||||
// Terminal tool events are self-contained; projection is a direct copy and
|
// Terminal tool events are self-contained; projection is a direct copy and
|
||||||
// never reaches into ephemeral progress history.
|
// never reaches into ephemeral progress history.
|
||||||
"session.tool.success": (event) => {
|
"session.tool.success": (event) => {
|
||||||
@@ -436,12 +335,6 @@ export function update(adapter: Adapter, event: SessionEvent.Event) {
|
|||||||
)
|
)
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
"session.reasoning.delta": (event) => {
|
|
||||||
return updateOwnedAssistant(event.data.assistantMessageID, (draft) => {
|
|
||||||
const match = latestReasoning(draft)
|
|
||||||
if (match) match.text += event.data.delta
|
|
||||||
})
|
|
||||||
},
|
|
||||||
"session.reasoning.ended": (event) => {
|
"session.reasoning.ended": (event) => {
|
||||||
return updateOwnedAssistant(event.data.assistantMessageID, (draft) => {
|
return updateOwnedAssistant(event.data.assistantMessageID, (draft) => {
|
||||||
const match = latestReasoning(draft)
|
const match = latestReasoning(draft)
|
||||||
@@ -475,12 +368,6 @@ export function update(adapter: Adapter, event: SessionEvent.Event) {
|
|||||||
time: { created: event.created },
|
time: { created: event.created },
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
"session.compaction.delta": (event) =>
|
|
||||||
Effect.gen(function* () {
|
|
||||||
const current = yield* adapter.getCompaction()
|
|
||||||
if (current?.status !== "running") return
|
|
||||||
yield* adapter.updateCompaction({ ...current, summary: current.summary + event.data.text })
|
|
||||||
}),
|
|
||||||
"session.compaction.ended": (event) => {
|
"session.compaction.ended": (event) => {
|
||||||
return Effect.gen(function* () {
|
return Effect.gen(function* () {
|
||||||
const current = yield* adapter.getCompaction()
|
const current = yield* adapter.getCompaction()
|
||||||
@@ -526,8 +413,9 @@ export function update(adapter: Adapter, event: SessionEvent.Event) {
|
|||||||
"session.revert.staged": () => Effect.void,
|
"session.revert.staged": () => Effect.void,
|
||||||
"session.revert.cleared": () => Effect.void,
|
"session.revert.cleared": () => Effect.void,
|
||||||
"session.revert.committed": () => Effect.void,
|
"session.revert.committed": () => Effect.void,
|
||||||
})
|
}),
|
||||||
})
|
)
|
||||||
|
return project(event)
|
||||||
}
|
}
|
||||||
|
|
||||||
export * as SessionMessageUpdater from "./message-updater"
|
export * as SessionMessageUpdater from "./message-updater"
|
||||||
|
|||||||
@@ -8,11 +8,9 @@ import { makeGlobalNode } from "@opencode-ai/util/effect/app-node"
|
|||||||
import { Model } from "../model"
|
import { Model } from "../model"
|
||||||
import { SessionEvent } from "./event"
|
import { SessionEvent } from "./event"
|
||||||
import { SessionV1 } from "../v1/session"
|
import { SessionV1 } from "../v1/session"
|
||||||
import { WorkspaceTable } from "../control-plane/workspace.sql"
|
|
||||||
import { SessionMessage } from "./message"
|
import { SessionMessage } from "./message"
|
||||||
import { SessionMessageUpdater } from "./message-updater"
|
import { SessionMessageUpdater } from "./message-updater"
|
||||||
import { SessionPending } from "./pending"
|
import { SessionPending } from "./pending"
|
||||||
import { Workspace } from "../workspace"
|
|
||||||
import { InstructionState } from "./instruction-state"
|
import { InstructionState } from "./instruction-state"
|
||||||
import { MessageTable, PartTable, SessionPendingTable, SessionMessageTable, SessionTable } from "./sql"
|
import { MessageTable, PartTable, SessionPendingTable, SessionMessageTable, SessionTable } from "./sql"
|
||||||
import type { DeepMutable } from "../schema"
|
import type { DeepMutable } from "../schema"
|
||||||
@@ -59,7 +57,7 @@ function sessionRow(info: SessionV1.SessionInfo): typeof SessionTable.$inferInse
|
|||||||
return {
|
return {
|
||||||
id: info.id,
|
id: info.id,
|
||||||
project_id: info.projectID,
|
project_id: info.projectID,
|
||||||
workspace_id: info.workspaceID ?? null,
|
workspace_id: null,
|
||||||
parent_id: info.parentID,
|
parent_id: info.parentID,
|
||||||
slug: info.slug,
|
slug: info.slug,
|
||||||
directory: info.directory,
|
directory: info.directory,
|
||||||
@@ -429,14 +427,6 @@ const layer = Layer.effectDiscard(
|
|||||||
.get()
|
.get()
|
||||||
.pipe(Effect.orDie)
|
.pipe(Effect.orDie)
|
||||||
if (!stored) return yield* Effect.die(new SessionAlreadyProjected())
|
if (!stored) return yield* Effect.die(new SessionAlreadyProjected())
|
||||||
if (event.data.info.workspaceID) {
|
|
||||||
yield* db
|
|
||||||
.update(WorkspaceTable)
|
|
||||||
.set({ time_used: Date.now() })
|
|
||||||
.where(eq(WorkspaceTable.id, event.data.info.workspaceID))
|
|
||||||
.run()
|
|
||||||
.pipe(Effect.orDie)
|
|
||||||
}
|
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
yield* bus.project(SessionV1.Event.Updated, (event) =>
|
yield* bus.project(SessionV1.Event.Updated, (event) =>
|
||||||
@@ -455,7 +445,7 @@ const layer = Layer.effectDiscard(
|
|||||||
directory: event.data.location.directory,
|
directory: event.data.location.directory,
|
||||||
path: event.data.subpath,
|
path: event.data.subpath,
|
||||||
...(event.data.projectID ? { project_id: event.data.projectID } : {}),
|
...(event.data.projectID ? { project_id: event.data.projectID } : {}),
|
||||||
workspace_id: event.data.location.workspaceID ? Workspace.ID.make(event.data.location.workspaceID) : null,
|
workspace_id: null,
|
||||||
time_updated: DateTime.toEpochMillis(event.created),
|
time_updated: DateTime.toEpochMillis(event.created),
|
||||||
})
|
})
|
||||||
.where(eq(SessionTable.id, event.data.sessionID))
|
.where(eq(SessionTable.id, event.data.sessionID))
|
||||||
|
|||||||
@@ -7,16 +7,16 @@ import { Schema } from "effect"
|
|||||||
import { FSUtil } from "@opencode-ai/util/fs-util"
|
import { FSUtil } from "@opencode-ai/util/fs-util"
|
||||||
import { which } from "../util/which"
|
import { which } from "../util/which"
|
||||||
|
|
||||||
const META: Record<string, { deny?: boolean; login?: boolean; posix?: boolean; ps?: boolean }> = {
|
const META: Record<string, { deny?: boolean; login?: boolean; ps?: boolean }> = {
|
||||||
bash: { login: true, posix: true },
|
bash: { login: true },
|
||||||
dash: { login: true, posix: true },
|
dash: { login: true },
|
||||||
fish: { deny: true, login: true },
|
fish: { deny: true, login: true },
|
||||||
ksh: { login: true, posix: true },
|
ksh: { login: true },
|
||||||
nu: { deny: true },
|
nu: { deny: true },
|
||||||
powershell: { ps: true },
|
powershell: { ps: true },
|
||||||
pwsh: { ps: true },
|
pwsh: { ps: true },
|
||||||
sh: { login: true, posix: true },
|
sh: { login: true },
|
||||||
zsh: { login: true, posix: true },
|
zsh: { login: true },
|
||||||
}
|
}
|
||||||
|
|
||||||
export type Item = {
|
export type Item = {
|
||||||
@@ -116,10 +116,6 @@ export function login(file: string) {
|
|||||||
return meta(file)?.login === true
|
return meta(file)?.login === true
|
||||||
}
|
}
|
||||||
|
|
||||||
export function posix(file: string) {
|
|
||||||
return meta(file)?.posix === true
|
|
||||||
}
|
|
||||||
|
|
||||||
export function ps(file: string) {
|
export function ps(file: string) {
|
||||||
return meta(file)?.ps === true
|
return meta(file)?.ps === true
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -967,9 +967,6 @@ describe("DatabaseMigration", () => {
|
|||||||
yield* db.run(
|
yield* db.run(
|
||||||
sql`INSERT INTO project (id, worktree, time_created, time_updated, sandboxes) VALUES ('global', '/project', 1, 1, '[]')`,
|
sql`INSERT INTO project (id, worktree, time_created, time_updated, sandboxes) VALUES ('global', '/project', 1, 1, '[]')`,
|
||||||
)
|
)
|
||||||
yield* db.run(
|
|
||||||
sql`INSERT INTO workspace (id, type, project_id, time_used) VALUES ('workspace', 'local', 'global', 1)`,
|
|
||||||
)
|
|
||||||
yield* db.run(
|
yield* db.run(
|
||||||
sql`INSERT INTO session (id, project_id, workspace_id, slug, directory, title, version, time_created, time_updated) VALUES ('session', 'global', 'workspace', 'session', '/project', 'Before', 'test', 1, 1)`,
|
sql`INSERT INTO session (id, project_id, workspace_id, slug, directory, title, version, time_created, time_updated) VALUES ('session', 'global', 'workspace', 'session', '/project', 'Before', 'test', 1, 1)`,
|
||||||
)
|
)
|
||||||
@@ -994,6 +991,7 @@ describe("DatabaseMigration", () => {
|
|||||||
// must drop before the historical rename dance and recreate after.
|
// must drop before the historical rename dance and recreate after.
|
||||||
yield* db.run(sql`DROP INDEX session_pending_session_compaction_idx`)
|
yield* db.run(sql`DROP INDEX session_pending_session_compaction_idx`)
|
||||||
yield* db.run(sql`ALTER TABLE session_pending RENAME TO session_input`)
|
yield* db.run(sql`ALTER TABLE session_pending RENAME TO session_input`)
|
||||||
|
yield* db.run(sql`CREATE TABLE workspace (id text PRIMARY KEY)`)
|
||||||
yield* db.run(sql`DELETE FROM migration WHERE id = ${simplifySessionPendingMigration.id}`)
|
yield* db.run(sql`DELETE FROM migration WHERE id = ${simplifySessionPendingMigration.id}`)
|
||||||
yield* DatabaseMigration.applyOnly(db, [simplifySessionPendingMigration])
|
yield* DatabaseMigration.applyOnly(db, [simplifySessionPendingMigration])
|
||||||
yield* db.run(sql`DROP TABLE session_context_epoch`)
|
yield* db.run(sql`DROP TABLE session_context_epoch`)
|
||||||
@@ -1029,7 +1027,6 @@ describe("DatabaseMigration", () => {
|
|||||||
(SELECT workspace_id FROM session WHERE id = 'session') AS workspaceID,
|
(SELECT workspace_id FROM session WHERE id = 'session') AS workspaceID,
|
||||||
(SELECT COUNT(*) FROM message WHERE id = 'message') AS messages,
|
(SELECT COUNT(*) FROM message WHERE id = 'message') AS messages,
|
||||||
(SELECT COUNT(*) FROM part WHERE id = 'part') AS parts,
|
(SELECT COUNT(*) FROM part WHERE id = 'part') AS parts,
|
||||||
(SELECT COUNT(*) FROM workspace) AS workspaces,
|
|
||||||
(SELECT COUNT(*) FROM session_pending) AS sessionInputs,
|
(SELECT COUNT(*) FROM session_pending) AS sessionInputs,
|
||||||
(SELECT COUNT(*) FROM session_message) AS sessionMessages,
|
(SELECT COUNT(*) FROM session_message) AS sessionMessages,
|
||||||
(SELECT COUNT(*) FROM instruction_state) AS instructionStates,
|
(SELECT COUNT(*) FROM instruction_state) AS instructionStates,
|
||||||
@@ -1041,7 +1038,6 @@ describe("DatabaseMigration", () => {
|
|||||||
workspaceID: null,
|
workspaceID: null,
|
||||||
messages: 1,
|
messages: 1,
|
||||||
parts: 1,
|
parts: 1,
|
||||||
workspaces: 0,
|
|
||||||
sessionInputs: 0,
|
sessionInputs: 0,
|
||||||
sessionMessages: 0,
|
sessionMessages: 0,
|
||||||
instructionStates: 0,
|
instructionStates: 0,
|
||||||
|
|||||||
@@ -80,7 +80,6 @@ describe("node build", () => {
|
|||||||
list: () => Effect.succeed([]),
|
list: () => Effect.succeed([]),
|
||||||
directories: () => Effect.succeed([]),
|
directories: () => Effect.succeed([]),
|
||||||
resolve: (directory) => Effect.succeed({ id: Project.ID.global, directory, canonical: directory }),
|
resolve: (directory) => Effect.succeed({ id: Project.ID.global, directory, canonical: directory }),
|
||||||
commit: () => Effect.void,
|
|
||||||
})
|
})
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -3,14 +3,6 @@ import { Ignore } from "@opencode-ai/core/filesystem/ignore"
|
|||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
import { createWrapper } from "@parcel/watcher/wrapper"
|
import { createWrapper } from "@parcel/watcher/wrapper"
|
||||||
|
|
||||||
test("match nested and non-nested", () => {
|
|
||||||
expect(Ignore.match("node_modules/index.js")).toBe(true)
|
|
||||||
expect(Ignore.match("node_modules")).toBe(true)
|
|
||||||
expect(Ignore.match("node_modules/")).toBe(true)
|
|
||||||
expect(Ignore.match("node_modules/bar")).toBe(true)
|
|
||||||
expect(Ignore.match("node_modules/bar/")).toBe(true)
|
|
||||||
})
|
|
||||||
|
|
||||||
test("parcel patterns ignore built-in folders at any depth", async () => {
|
test("parcel patterns ignore built-in folders at any depth", async () => {
|
||||||
let ignoreGlobs: string[] = []
|
let ignoreGlobs: string[] = []
|
||||||
const watcher = createWrapper({
|
const watcher = createWrapper({
|
||||||
|
|||||||
@@ -1,44 +1,59 @@
|
|||||||
import { describe, expect } from "bun:test"
|
import { describe, expect, test } from "bun:test"
|
||||||
import fs from "fs/promises"
|
import os from "os"
|
||||||
import path from "path"
|
import path from "path"
|
||||||
import { Effect } from "effect"
|
import { Effect, Layer } from "effect"
|
||||||
import { LayerNode } from "@opencode-ai/util/effect/layer-node"
|
import { AppNodeBuilder } from "@opencode-ai/core/effect/app-node-builder"
|
||||||
|
import { FileSystem } from "@opencode-ai/core/filesystem"
|
||||||
|
import { Protected } from "@opencode-ai/core/filesystem/protected"
|
||||||
|
import { FileSystemSearch } from "@opencode-ai/core/filesystem/search"
|
||||||
|
import { Location } from "@opencode-ai/core/location"
|
||||||
import { Ripgrep } from "@opencode-ai/core/ripgrep"
|
import { Ripgrep } from "@opencode-ai/core/ripgrep"
|
||||||
import { AbsolutePath, RelativePath } from "@opencode-ai/core/schema"
|
import { AbsolutePath, RelativePath } from "@opencode-ai/core/schema"
|
||||||
import { tmpdir } from "../fixture/tmpdir"
|
import { location } from "../fixture/location"
|
||||||
import { testEffect } from "../lib/effect"
|
|
||||||
|
|
||||||
const it = testEffect(LayerNode.compile(Ripgrep.node))
|
describe("FileSystemSearch", () => {
|
||||||
|
test("bounds a home scan even when home is detected as a repository", async () => {
|
||||||
|
let observed: Ripgrep.FindInput | undefined
|
||||||
|
const home = AbsolutePath.make(os.homedir())
|
||||||
|
const layer = AppNodeBuilder.build(FileSystemSearch.node, [
|
||||||
|
[
|
||||||
|
Location.node,
|
||||||
|
Layer.succeed(
|
||||||
|
Location.Service,
|
||||||
|
Location.Service.of(
|
||||||
|
location({ directory: home }, { vcs: { type: "git", store: AbsolutePath.make(path.join(home, ".git")) } }),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
[
|
||||||
|
Ripgrep.node,
|
||||||
|
Layer.succeed(
|
||||||
|
Ripgrep.Service,
|
||||||
|
Ripgrep.Service.of({
|
||||||
|
find: (input) =>
|
||||||
|
Effect.gen(function* () {
|
||||||
|
observed = input
|
||||||
|
if (input.onEntry)
|
||||||
|
yield* input.onEntry(FileSystem.Entry.make({ path: RelativePath.make("src/index.ts"), type: "file" }))
|
||||||
|
return []
|
||||||
|
}),
|
||||||
|
glob: () => Effect.succeed([]),
|
||||||
|
grep: () => Effect.succeed([]),
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
])
|
||||||
|
|
||||||
const withTmp = <A, E, R>(f: (directory: AbsolutePath) => Effect.Effect<A, E, R>) =>
|
await Effect.runPromise(
|
||||||
Effect.acquireRelease(
|
|
||||||
Effect.promise(() => tmpdir()),
|
|
||||||
(tmp) => Effect.promise(() => tmp[Symbol.asyncDispose]()),
|
|
||||||
).pipe(Effect.flatMap((tmp) => f(AbsolutePath.make(tmp.path))))
|
|
||||||
|
|
||||||
describe("Ripgrep", () => {
|
|
||||||
it.live("globs files as an array", () =>
|
|
||||||
withTmp((cwd) =>
|
|
||||||
Effect.gen(function* () {
|
Effect.gen(function* () {
|
||||||
yield* Effect.promise(() => fs.mkdir(path.join(cwd, "src")))
|
const search = yield* FileSystemSearch.Service
|
||||||
yield* Effect.promise(() => fs.writeFile(path.join(cwd, "src", "match.ts"), "needle\n"))
|
yield* Effect.sleep("10 millis")
|
||||||
const result = yield* (yield* Ripgrep.Service).glob({ cwd, pattern: "**/*.ts", limit: 10 })
|
expect(observed?.limit).toBe(100_000)
|
||||||
expect(result.map((item) => item.path)).toEqual([RelativePath.make("src/match.ts")])
|
expect(observed?.exclude).toEqual([...Protected.names()].map((name) => `${name}/**`))
|
||||||
}),
|
expect((yield* search.find({ query: "src", type: "directory" }))[0]?.path).toBe(
|
||||||
),
|
RelativePath.make(`src${path.sep}`),
|
||||||
)
|
)
|
||||||
|
}).pipe(Effect.provide(layer), Effect.scoped),
|
||||||
it.live("greps files with include filtering", () =>
|
)
|
||||||
withTmp((cwd) =>
|
})
|
||||||
Effect.gen(function* () {
|
|
||||||
yield* Effect.promise(() => fs.mkdir(path.join(cwd, "src")))
|
|
||||||
yield* Effect.promise(() => fs.writeFile(path.join(cwd, "src", "match.ts"), "needle\n"))
|
|
||||||
yield* Effect.promise(() => fs.writeFile(path.join(cwd, "src", "skip.txt"), "needle\n"))
|
|
||||||
const result = yield* (yield* Ripgrep.Service).grep({ cwd, pattern: "needle", include: "*.ts", limit: 10 })
|
|
||||||
expect(result).toHaveLength(1)
|
|
||||||
expect(result[0]?.entry.path).toBe(RelativePath.make("src/match.ts"))
|
|
||||||
expect(result[0]?.submatches[0]?.text).toBe("needle")
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -21,7 +21,6 @@ const projectLayer = Layer.succeed(
|
|||||||
canonical: AbsolutePath.make("/main/repo"),
|
canonical: AbsolutePath.make("/main/repo"),
|
||||||
vcs: { type: "git", store: AbsolutePath.make("/repo/.git") },
|
vcs: { type: "git", store: AbsolutePath.make("/repo/.git") },
|
||||||
}),
|
}),
|
||||||
commit: () => Effect.void,
|
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
const it = testEffect(AppNodeBuilder.build(Location.boundNode(ref), [[Project.node, projectLayer]]))
|
const it = testEffect(AppNodeBuilder.build(Location.boundNode(ref), [[Project.node, projectLayer]]))
|
||||||
|
|||||||
@@ -83,20 +83,10 @@ describe("ProjectCopy", () => {
|
|||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
|
|
||||||
it.effect("rejects duplicate strategies and reports unavailable ids", () =>
|
it.effect("reports unavailable strategy ids", () =>
|
||||||
Effect.gen(function* () {
|
Effect.gen(function* () {
|
||||||
const input = yield* setup()
|
const input = yield* setup()
|
||||||
const copy = yield* ProjectCopy.Service
|
const copy = yield* ProjectCopy.Service
|
||||||
const strategy: ProjectCopy.Strategy = {
|
|
||||||
id: ProjectCopy.StrategyID.make("test/duplicate"),
|
|
||||||
create: () => Effect.die("unused"),
|
|
||||||
remove: () => Effect.die("unused"),
|
|
||||||
list: () => Effect.succeed([]),
|
|
||||||
}
|
|
||||||
|
|
||||||
yield* copy.register(strategy)
|
|
||||||
expect(yield* copy.register(strategy).pipe(Effect.flip)).toBeInstanceOf(ProjectCopy.DuplicateStrategyError)
|
|
||||||
|
|
||||||
const unavailable = ProjectCopy.StrategyID.make("acme/missing")
|
const unavailable = ProjectCopy.StrategyID.make("acme/missing")
|
||||||
const error = yield* copy
|
const error = yield* copy
|
||||||
.create({
|
.create({
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ import { Effect, Layer } from "effect"
|
|||||||
import { LayerNode } from "@opencode-ai/util/effect/layer-node"
|
import { LayerNode } from "@opencode-ai/util/effect/layer-node"
|
||||||
import { PtyID } from "@opencode-ai/core/pty/schema"
|
import { PtyID } from "@opencode-ai/core/pty/schema"
|
||||||
import { PtyTicket } from "@opencode-ai/core/pty/ticket"
|
import { PtyTicket } from "@opencode-ai/core/pty/ticket"
|
||||||
import { Workspace } from "@opencode-ai/core/workspace"
|
|
||||||
import { testEffect } from "../lib/effect"
|
import { testEffect } from "../lib/effect"
|
||||||
|
|
||||||
const it = testEffect(LayerNode.compile(PtyTicket.node))
|
const it = testEffect(LayerNode.compile(PtyTicket.node))
|
||||||
@@ -46,17 +45,14 @@ describe("PTY websocket tickets", () => {
|
|||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
|
|
||||||
it.live("rejects tickets scoped to a different workspace", () =>
|
it.live("rejects tickets scoped to a different pty", () =>
|
||||||
Effect.gen(function* () {
|
Effect.gen(function* () {
|
||||||
const tickets = yield* PtyTicket.Service
|
const tickets = yield* PtyTicket.Service
|
||||||
const ptyID = PtyID.ascending()
|
const ptyID = PtyID.ascending()
|
||||||
const workspaceID = Workspace.ID.ascending()
|
const issued = yield* tickets.issue({ ptyID })
|
||||||
const issued = yield* tickets.issue({ ptyID, workspaceID })
|
|
||||||
|
|
||||||
expect(yield* tickets.consume({ ptyID, workspaceID: Workspace.ID.ascending(), ticket: issued.ticket })).toBe(
|
expect(yield* tickets.consume({ ptyID: PtyID.ascending(), ticket: issued.ticket })).toBe(false)
|
||||||
false,
|
expect(yield* tickets.consume({ ptyID, ticket: issued.ticket })).toBe(true)
|
||||||
)
|
|
||||||
expect(yield* tickets.consume({ ptyID, workspaceID, ticket: issued.ticket })).toBe(true)
|
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -101,13 +101,10 @@ describe("RepositoryCache", () => {
|
|||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
it.live("returns typed validation and clone failures", () =>
|
it.live("returns typed branch validation and clone failures", () =>
|
||||||
withRemote((fixture) =>
|
withRemote((fixture) =>
|
||||||
Effect.gen(function* () {
|
Effect.gen(function* () {
|
||||||
const cache = yield* RepositoryCache.Service
|
const cache = yield* RepositoryCache.Service
|
||||||
const invalidRepository = yield* Effect.flip(RepositoryCache.parseRemote("not-a-repo"))
|
|
||||||
expect(invalidRepository).toBeInstanceOf(RepositoryCache.InvalidRepositoryError)
|
|
||||||
|
|
||||||
const invalidBranch = yield* Effect.flip(cache.ensure({ reference: fixture.reference, branch: "../unsafe" }))
|
const invalidBranch = yield* Effect.flip(cache.ensure({ reference: fixture.reference, branch: "../unsafe" }))
|
||||||
expect(invalidBranch).toBeInstanceOf(RepositoryCache.InvalidBranchError)
|
expect(invalidBranch).toBeInstanceOf(RepositoryCache.InvalidBranchError)
|
||||||
|
|
||||||
|
|||||||
@@ -11,6 +11,44 @@ import { testEffect } from "./lib/effect"
|
|||||||
const it = testEffect(LayerNode.compile(Ripgrep.node))
|
const it = testEffect(LayerNode.compile(Ripgrep.node))
|
||||||
|
|
||||||
describe("Ripgrep", () => {
|
describe("Ripgrep", () => {
|
||||||
|
it.live("globs files as an array", () =>
|
||||||
|
Effect.acquireUseRelease(
|
||||||
|
Effect.promise(() => tmpdir()),
|
||||||
|
(tmp) =>
|
||||||
|
Effect.gen(function* () {
|
||||||
|
yield* Effect.promise(() => fs.mkdir(path.join(tmp.path, "src")))
|
||||||
|
yield* Effect.promise(() => fs.writeFile(path.join(tmp.path, "src", "match.ts"), "needle\n"))
|
||||||
|
|
||||||
|
const result = yield* (yield* Ripgrep.Service).glob({ cwd: tmp.path, pattern: "**/*.ts", limit: 10 })
|
||||||
|
expect(result.map((item) => item.path)).toEqual([RelativePath.make("src/match.ts")])
|
||||||
|
}),
|
||||||
|
(tmp) => Effect.promise(() => tmp[Symbol.asyncDispose]()),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
it.live("greps files with include filtering", () =>
|
||||||
|
Effect.acquireUseRelease(
|
||||||
|
Effect.promise(() => tmpdir()),
|
||||||
|
(tmp) =>
|
||||||
|
Effect.gen(function* () {
|
||||||
|
yield* Effect.promise(() => fs.mkdir(path.join(tmp.path, "src")))
|
||||||
|
yield* Effect.promise(() => fs.writeFile(path.join(tmp.path, "src", "match.ts"), "needle\n"))
|
||||||
|
yield* Effect.promise(() => fs.writeFile(path.join(tmp.path, "src", "skip.txt"), "needle\n"))
|
||||||
|
|
||||||
|
const result = yield* (yield* Ripgrep.Service).grep({
|
||||||
|
cwd: tmp.path,
|
||||||
|
pattern: "needle",
|
||||||
|
include: "*.ts",
|
||||||
|
limit: 10,
|
||||||
|
})
|
||||||
|
expect(result).toHaveLength(1)
|
||||||
|
expect(result[0]?.entry.path).toBe(RelativePath.make("src/match.ts"))
|
||||||
|
expect(result[0]?.submatches[0]?.text).toBe("needle")
|
||||||
|
}),
|
||||||
|
(tmp) => Effect.promise(() => tmp[Symbol.asyncDispose]()),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
it.live("keeps ignored files out of catch-all find results", () =>
|
it.live("keeps ignored files out of catch-all find results", () =>
|
||||||
Effect.acquireUseRelease(
|
Effect.acquireUseRelease(
|
||||||
Effect.promise(() => tmpdir()),
|
Effect.promise(() => tmpdir()),
|
||||||
@@ -63,6 +101,29 @@ describe("Ripgrep", () => {
|
|||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
it.live("excludes protected directory trees from catch-all find results", () =>
|
||||||
|
Effect.acquireUseRelease(
|
||||||
|
Effect.promise(() => tmpdir()),
|
||||||
|
(tmp) =>
|
||||||
|
Effect.gen(function* () {
|
||||||
|
yield* Effect.promise(() => fs.mkdir(path.join(tmp.path, "Pictures")))
|
||||||
|
yield* Effect.promise(() => fs.writeFile(path.join(tmp.path, "Pictures", "private.jpg"), "private\n"))
|
||||||
|
yield* Effect.promise(() => fs.writeFile(path.join(tmp.path, "visible.txt"), "visible\n"))
|
||||||
|
|
||||||
|
const files = yield* (yield* Ripgrep.Service).find({
|
||||||
|
cwd: tmp.path,
|
||||||
|
pattern: "*",
|
||||||
|
limit: 10,
|
||||||
|
exclude: ["Pictures/**"],
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(files.map((item) => item.path)).toContain(RelativePath.make("visible.txt"))
|
||||||
|
expect(files.map((item) => item.path)).not.toContain(RelativePath.make("Pictures/private.jpg"))
|
||||||
|
}),
|
||||||
|
(tmp) => Effect.promise(() => tmp[Symbol.asyncDispose]()),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
it.live("returns a bounded preview for matches on oversized lines", () =>
|
it.live("returns a bounded preview for matches on oversized lines", () =>
|
||||||
Effect.acquireUseRelease(
|
Effect.acquireUseRelease(
|
||||||
Effect.promise(() => tmpdir()),
|
Effect.promise(() => tmpdir()),
|
||||||
|
|||||||
@@ -36,7 +36,6 @@ const projects = Layer.succeed(
|
|||||||
list: () => Effect.succeed([]),
|
list: () => Effect.succeed([]),
|
||||||
resolve: (directory) => Effect.succeed({ id: Project.ID.global, directory, canonical: directory }),
|
resolve: (directory) => Effect.succeed({ id: Project.ID.global, directory, canonical: directory }),
|
||||||
directories: () => Effect.succeed([]),
|
directories: () => Effect.succeed([]),
|
||||||
commit: () => Effect.void,
|
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
let requests: LLMRequest[] = []
|
let requests: LLMRequest[] = []
|
||||||
|
|||||||
@@ -24,7 +24,6 @@ import { SessionPending } from "@opencode-ai/core/session/pending"
|
|||||||
import { SessionEvent } from "@opencode-ai/core/session/event"
|
import { SessionEvent } from "@opencode-ai/core/session/event"
|
||||||
import { SessionTable } from "@opencode-ai/core/session/sql"
|
import { SessionTable } from "@opencode-ai/core/session/sql"
|
||||||
import { SessionStore } from "@opencode-ai/core/session/store"
|
import { SessionStore } from "@opencode-ai/core/session/store"
|
||||||
import { Workspace } from "@opencode-ai/core/workspace"
|
|
||||||
import { testEffect } from "./lib/effect"
|
import { testEffect } from "./lib/effect"
|
||||||
import { tmpdir } from "./fixture/tmpdir"
|
import { tmpdir } from "./fixture/tmpdir"
|
||||||
|
|
||||||
@@ -34,7 +33,6 @@ const projects = Layer.succeed(
|
|||||||
list: () => Effect.succeed([]),
|
list: () => Effect.succeed([]),
|
||||||
resolve: (directory) => Effect.succeed({ id: Project.ID.global, directory, canonical: directory }),
|
resolve: (directory) => Effect.succeed({ id: Project.ID.global, directory, canonical: directory }),
|
||||||
directories: () => Effect.succeed([]),
|
directories: () => Effect.succeed([]),
|
||||||
commit: () => Effect.void,
|
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
const it = testEffect(
|
const it = testEffect(
|
||||||
@@ -120,7 +118,6 @@ describe("Session.create", () => {
|
|||||||
it.effect("stores supplied immutable create attributes", () =>
|
it.effect("stores supplied immutable create attributes", () =>
|
||||||
Effect.gen(function* () {
|
Effect.gen(function* () {
|
||||||
const session = yield* Session.Service
|
const session = yield* Session.Service
|
||||||
const workspaceID = Workspace.ID.make("wrk_test")
|
|
||||||
const model = Model.Ref.make({
|
const model = Model.Ref.make({
|
||||||
id: Model.ID.make("sonnet"),
|
id: Model.ID.make("sonnet"),
|
||||||
providerID: Provider.ID.anthropic,
|
providerID: Provider.ID.anthropic,
|
||||||
@@ -129,11 +126,11 @@ describe("Session.create", () => {
|
|||||||
|
|
||||||
expect(
|
expect(
|
||||||
yield* session.create({
|
yield* session.create({
|
||||||
location: Location.Ref.make({ directory: location.directory, workspaceID }),
|
location: Location.Ref.make({ directory: location.directory }),
|
||||||
agent: Agent.ID.make("build"),
|
agent: Agent.ID.make("build"),
|
||||||
model,
|
model,
|
||||||
}),
|
}),
|
||||||
).toMatchObject({ location: { directory: location.directory, workspaceID }, agent: "build", model })
|
).toMatchObject({ location: { directory: location.directory }, agent: "build", model })
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -56,7 +56,6 @@ const projects = Layer.succeed(
|
|||||||
list: () => Effect.succeed([]),
|
list: () => Effect.succeed([]),
|
||||||
resolve: (directory) => Effect.succeed({ id: Project.ID.global, directory, canonical: directory }),
|
resolve: (directory) => Effect.succeed({ id: Project.ID.global, directory, canonical: directory }),
|
||||||
directories: () => Effect.succeed([]),
|
directories: () => Effect.succeed([]),
|
||||||
commit: () => Effect.void,
|
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
const permission = Layer.succeed(
|
const permission = Layer.succeed(
|
||||||
|
|||||||
@@ -23,7 +23,6 @@ const projects = Layer.succeed(
|
|||||||
list: () => Effect.succeed([]),
|
list: () => Effect.succeed([]),
|
||||||
resolve: (directory) => Effect.succeed({ id: Project.ID.global, directory, canonical: directory }),
|
resolve: (directory) => Effect.succeed({ id: Project.ID.global, directory, canonical: directory }),
|
||||||
directories: () => Effect.succeed([]),
|
directories: () => Effect.succeed([]),
|
||||||
commit: () => Effect.void,
|
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
const it = testEffect(
|
const it = testEffect(
|
||||||
|
|||||||
@@ -17,7 +17,6 @@ import { Session } from "@opencode-ai/core/session"
|
|||||||
import { SessionEvent } from "@opencode-ai/core/session/event"
|
import { SessionEvent } from "@opencode-ai/core/session/event"
|
||||||
import { SessionMessage } from "@opencode-ai/core/session/message"
|
import { SessionMessage } from "@opencode-ai/core/session/message"
|
||||||
import { Money } from "@opencode-ai/schema/money"
|
import { Money } from "@opencode-ai/schema/money"
|
||||||
import { SessionMessageUpdater } from "@opencode-ai/core/session/message-updater"
|
|
||||||
import { SessionProjector } from "@opencode-ai/core/session/projector"
|
import { SessionProjector } from "@opencode-ai/core/session/projector"
|
||||||
import { SessionExecution } from "@opencode-ai/core/session/execution"
|
import { SessionExecution } from "@opencode-ai/core/session/execution"
|
||||||
import { fromRow } from "@opencode-ai/core/session/info"
|
import { fromRow } from "@opencode-ai/core/session/info"
|
||||||
@@ -126,34 +125,6 @@ describe("SessionProjector", () => {
|
|||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
|
|
||||||
it.effect("folds live compaction deltas into running memory state", () =>
|
|
||||||
Effect.gen(function* () {
|
|
||||||
const state = {
|
|
||||||
messages: [
|
|
||||||
SessionMessage.CompactionRunning.make({
|
|
||||||
id: SessionMessage.ID.make("msg_compaction"),
|
|
||||||
type: "compaction",
|
|
||||||
status: "running",
|
|
||||||
reason: "manual",
|
|
||||||
summary: "partial ",
|
|
||||||
recent: "recent",
|
|
||||||
time: { created },
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
}
|
|
||||||
yield* SessionMessageUpdater.update(
|
|
||||||
SessionMessageUpdater.memory(state),
|
|
||||||
SessionEvent.Compaction.Delta.make({
|
|
||||||
id: Event.ID.make("evt_delta"),
|
|
||||||
type: "session.compaction.delta",
|
|
||||||
created,
|
|
||||||
data: { sessionID, text: "summary" },
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
expect(state.messages[0]).toMatchObject({ status: "running", summary: "partial summary", recent: "recent" })
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
|
|
||||||
it.effect("projects staged, cleared, and committed reverts", () =>
|
it.effect("projects staged, cleared, and committed reverts", () =>
|
||||||
Effect.gen(function* () {
|
Effect.gen(function* () {
|
||||||
const db = (yield* Database.Service).db
|
const db = (yield* Database.Service).db
|
||||||
@@ -550,31 +521,6 @@ describe("SessionProjector", () => {
|
|||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
|
|
||||||
it.effect("does not revive a stale incomplete in-memory assistant projection", () =>
|
|
||||||
Effect.gen(function* () {
|
|
||||||
const stale = SessionMessage.Assistant.make({
|
|
||||||
id: SessionMessage.ID.make("msg_assistant_stale"),
|
|
||||||
type: "assistant",
|
|
||||||
agent: build,
|
|
||||||
model,
|
|
||||||
content: [],
|
|
||||||
time: { created },
|
|
||||||
})
|
|
||||||
const completed = SessionMessage.Assistant.make({
|
|
||||||
id: SessionMessage.ID.make("msg_assistant_completed"),
|
|
||||||
type: "assistant",
|
|
||||||
agent: build,
|
|
||||||
model,
|
|
||||||
content: [],
|
|
||||||
time: { created: DateTime.makeUnsafe(1), completed: DateTime.makeUnsafe(2) },
|
|
||||||
})
|
|
||||||
|
|
||||||
expect(
|
|
||||||
yield* SessionMessageUpdater.memory({ messages: [stale, completed] }).getCurrentAssistant(),
|
|
||||||
).toBeUndefined()
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
|
|
||||||
it.effect("projects retry state and clears it at the next step or execution terminal", () =>
|
it.effect("projects retry state and clears it at the next step or execution terminal", () =>
|
||||||
Effect.gen(function* () {
|
Effect.gen(function* () {
|
||||||
const { db } = yield* Database.Service
|
const { db } = yield* Database.Service
|
||||||
|
|||||||
@@ -19,7 +19,6 @@ const projects = Layer.succeed(
|
|||||||
list: () => Effect.succeed([]),
|
list: () => Effect.succeed([]),
|
||||||
resolve: (directory) => Effect.succeed({ id: Project.ID.global, directory, canonical: directory }),
|
resolve: (directory) => Effect.succeed({ id: Project.ID.global, directory, canonical: directory }),
|
||||||
directories: () => Effect.succeed([]),
|
directories: () => Effect.succeed([]),
|
||||||
commit: () => Effect.void,
|
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
const it = testEffect(
|
const it = testEffect(
|
||||||
|
|||||||
@@ -34,12 +34,6 @@ describe("shell", () => {
|
|||||||
expect(ShellSelect.login("C:/tools/pwsh.exe")).toBe(false)
|
expect(ShellSelect.login("C:/tools/pwsh.exe")).toBe(false)
|
||||||
})
|
})
|
||||||
|
|
||||||
test("detects posix shells", () => {
|
|
||||||
expect(ShellSelect.posix("/bin/bash")).toBe(true)
|
|
||||||
expect(ShellSelect.posix("/bin/fish")).toBe(false)
|
|
||||||
expect(ShellSelect.posix("C:/tools/pwsh.exe")).toBe(false)
|
|
||||||
})
|
|
||||||
|
|
||||||
test("falls back when configured shell cannot be resolved", async () => {
|
test("falls back when configured shell cannot be resolved", async () => {
|
||||||
await withShell(undefined, async () => {
|
await withShell(undefined, async () => {
|
||||||
const preferred = ShellSelect.preferred()
|
const preferred = ShellSelect.preferred()
|
||||||
|
|||||||
Vendored
-12
@@ -5,15 +5,3 @@ interface ImportMetaEnv {
|
|||||||
interface ImportMeta {
|
interface ImportMeta {
|
||||||
readonly env: ImportMetaEnv
|
readonly env: ImportMetaEnv
|
||||||
}
|
}
|
||||||
|
|
||||||
declare module "virtual:opencode-server" {
|
|
||||||
export namespace Server {
|
|
||||||
export const listen: typeof import("../../../opencode/dist/types/src/node").Server.listen
|
|
||||||
export type Listener = import("../../../opencode/dist/types/src/node").Server.Listener
|
|
||||||
}
|
|
||||||
export namespace Config {
|
|
||||||
export const get: typeof import("../../../opencode/dist/types/src/node").Config.get
|
|
||||||
export type Info = import("../../../opencode/dist/types/src/node").Config.Info
|
|
||||||
}
|
|
||||||
export const bootstrap: typeof import("../../../opencode/dist/types/src/node").bootstrap
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,32 +1,8 @@
|
|||||||
import { dirname, join } from "node:path"
|
|
||||||
import { fileURLToPath } from "node:url"
|
|
||||||
import { app, utilityProcess } from "electron"
|
|
||||||
import type { Details } from "electron"
|
|
||||||
import { getLogger } from "./logging"
|
import { getLogger } from "./logging"
|
||||||
import { getUserShell, loadShellEnv } from "./shell-env"
|
import { getUserShell, loadShellEnv } from "./shell-env"
|
||||||
import { getStore } from "./store"
|
import { getStore } from "./store"
|
||||||
import { DEFAULT_SERVER_URL_KEY } from "./store-keys"
|
import { DEFAULT_SERVER_URL_KEY } from "./store-keys"
|
||||||
|
|
||||||
export type HealthCheck = { wait: Promise<void> }
|
|
||||||
|
|
||||||
type SidecarMessage =
|
|
||||||
| { type: "ready" }
|
|
||||||
| { type: "stopped" }
|
|
||||||
| { type: "error"; error: { message: string; stack?: string } }
|
|
||||||
|
|
||||||
export type SidecarListener = { stop: () => Promise<void> }
|
|
||||||
|
|
||||||
const SIDECAR_SERVICE_NAME = "opencode server"
|
|
||||||
const SIDECAR_START_STALL_TIMEOUT = 60_000
|
|
||||||
const SIDECAR_STOP_TIMEOUT = 6_000
|
|
||||||
|
|
||||||
type SpawnLocalServerOptions = {
|
|
||||||
userDataPath: string
|
|
||||||
onStdout?: (message: string) => void
|
|
||||||
onStderr?: (message: string) => void
|
|
||||||
onExit?: (code: number) => void
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getDefaultServerUrl(): string | null {
|
export function getDefaultServerUrl(): string | null {
|
||||||
const value = getStore().get(DEFAULT_SERVER_URL_KEY)
|
const value = getStore().get(DEFAULT_SERVER_URL_KEY)
|
||||||
return typeof value === "string" ? value : null
|
return typeof value === "string" ? value : null
|
||||||
@@ -54,135 +30,6 @@ export function preferAppEnv(userDataPath: string) {
|
|||||||
return shellEnv
|
return shellEnv
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function spawnLocalServer(
|
|
||||||
hostname: string,
|
|
||||||
port: number,
|
|
||||||
password: string,
|
|
||||||
options: SpawnLocalServerOptions,
|
|
||||||
) {
|
|
||||||
const sidecar = join(dirname(fileURLToPath(import.meta.url)), "sidecar.js")
|
|
||||||
const child = utilityProcess.fork(sidecar, [], {
|
|
||||||
cwd: process.cwd(),
|
|
||||||
env: createSidecarEnv(),
|
|
||||||
serviceName: SIDECAR_SERVICE_NAME,
|
|
||||||
stdio: "pipe",
|
|
||||||
})
|
|
||||||
let exited = false
|
|
||||||
const exit = defer<number>()
|
|
||||||
|
|
||||||
const onProcessGone = (_event: unknown, details: Details) => {
|
|
||||||
if (details.type !== "Utility" || details.name !== SIDECAR_SERVICE_NAME) return
|
|
||||||
options.onStderr?.(`utility process gone reason=${details.reason} exitCode=${details.exitCode}`)
|
|
||||||
}
|
|
||||||
|
|
||||||
app.on("child-process-gone", onProcessGone)
|
|
||||||
child.once("exit", (code) => {
|
|
||||||
exited = true
|
|
||||||
app.off("child-process-gone", onProcessGone)
|
|
||||||
options.onExit?.(code)
|
|
||||||
exit.resolve(code)
|
|
||||||
})
|
|
||||||
child.on("error", (error) => options.onStderr?.(`utility process error: ${serializeError(error).message}`))
|
|
||||||
|
|
||||||
child.stdout?.on("data", (chunk: Buffer) => options.onStdout?.(chunk.toString("utf8").trimEnd()))
|
|
||||||
child.stderr?.on("data", (chunk: Buffer) => options.onStderr?.(chunk.toString("utf8").trimEnd()))
|
|
||||||
|
|
||||||
await new Promise<void>((resolve, reject) => {
|
|
||||||
let done = false
|
|
||||||
let timeout: NodeJS.Timeout
|
|
||||||
|
|
||||||
const fail = (error: Error) => {
|
|
||||||
if (done) return
|
|
||||||
done = true
|
|
||||||
cleanup()
|
|
||||||
reject(error)
|
|
||||||
}
|
|
||||||
|
|
||||||
const refreshTimeout = () => {
|
|
||||||
clearTimeout(timeout)
|
|
||||||
timeout = setTimeout(() => {
|
|
||||||
fail(new Error(`Sidecar did not become ready within ${SIDECAR_START_STALL_TIMEOUT}ms: ${sidecar}`))
|
|
||||||
}, SIDECAR_START_STALL_TIMEOUT)
|
|
||||||
}
|
|
||||||
|
|
||||||
const onMessage = (message: SidecarMessage) => {
|
|
||||||
if (message.type === "ready") {
|
|
||||||
if (done) return
|
|
||||||
done = true
|
|
||||||
cleanup()
|
|
||||||
resolve()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if (message.type === "error") {
|
|
||||||
fail(Object.assign(new Error(message.error.message), { stack: message.error.stack }))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const onExit = (code: number) => {
|
|
||||||
fail(new Error(`Sidecar exited before ready with code ${code}`))
|
|
||||||
}
|
|
||||||
const cleanup = () => {
|
|
||||||
clearTimeout(timeout)
|
|
||||||
child.off("message", onMessage)
|
|
||||||
child.off("exit", onExit)
|
|
||||||
}
|
|
||||||
|
|
||||||
child.on("message", onMessage)
|
|
||||||
child.on("exit", onExit)
|
|
||||||
refreshTimeout()
|
|
||||||
child.postMessage({
|
|
||||||
type: "start",
|
|
||||||
hostname,
|
|
||||||
port,
|
|
||||||
password,
|
|
||||||
userDataPath: options.userDataPath,
|
|
||||||
})
|
|
||||||
}).catch((error) => {
|
|
||||||
if (!exited) child.kill()
|
|
||||||
throw error
|
|
||||||
})
|
|
||||||
|
|
||||||
const wait = (async () => {
|
|
||||||
const url = `http://${hostname}:${port}`
|
|
||||||
let healthy = false
|
|
||||||
const gone = exit.promise.then((code) => {
|
|
||||||
if (healthy) return
|
|
||||||
throw new Error(`Sidecar exited before health check passed with code ${code}`)
|
|
||||||
})
|
|
||||||
|
|
||||||
const ready = async () => {
|
|
||||||
while (true) {
|
|
||||||
await new Promise((resolve) => setTimeout(resolve, 100))
|
|
||||||
if (await checkHealth(url, password)) {
|
|
||||||
healthy = true
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
await Promise.race([ready(), gone])
|
|
||||||
})()
|
|
||||||
|
|
||||||
let stopping: Promise<void> | undefined
|
|
||||||
|
|
||||||
return {
|
|
||||||
listener: {
|
|
||||||
stop: () => {
|
|
||||||
if (stopping) return stopping
|
|
||||||
if (exited) return Promise.resolve()
|
|
||||||
child.postMessage({ type: "stop" })
|
|
||||||
stopping = Promise.race([
|
|
||||||
exit.promise.then(() => undefined),
|
|
||||||
delay(SIDECAR_STOP_TIMEOUT).then(() => {
|
|
||||||
if (!exited) child.kill()
|
|
||||||
}),
|
|
||||||
])
|
|
||||||
return stopping
|
|
||||||
},
|
|
||||||
},
|
|
||||||
health: { wait },
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function checkHealth(url: string, password?: string | null): Promise<boolean> {
|
export async function checkHealth(url: string, password?: string | null): Promise<boolean> {
|
||||||
let healthUrls: URL[]
|
let healthUrls: URL[]
|
||||||
try {
|
try {
|
||||||
@@ -209,31 +56,3 @@ export async function checkHealth(url: string, password?: string | null): Promis
|
|||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
function createSidecarEnv(): Record<string, string> {
|
|
||||||
const env = Object.fromEntries(
|
|
||||||
Object.entries(process.env).flatMap(([key, value]) => (value === undefined ? [] : [[key, String(value)]])),
|
|
||||||
)
|
|
||||||
delete env.DEBUG
|
|
||||||
if (process.platform === "linux") delete env.LD_PRELOAD
|
|
||||||
return env
|
|
||||||
}
|
|
||||||
|
|
||||||
function delay(ms: number) {
|
|
||||||
return new Promise<void>((resolve) => setTimeout(resolve, ms))
|
|
||||||
}
|
|
||||||
|
|
||||||
function serializeError(error: unknown) {
|
|
||||||
if (error instanceof Error) return { message: error.message, stack: error.stack }
|
|
||||||
return { message: String(error) }
|
|
||||||
}
|
|
||||||
|
|
||||||
function defer<T>() {
|
|
||||||
let resolve!: (value: T) => void
|
|
||||||
let reject!: (error: Error) => void
|
|
||||||
const promise = new Promise<T>((res, rej) => {
|
|
||||||
resolve = res
|
|
||||||
reject = rej
|
|
||||||
})
|
|
||||||
return { promise, resolve, reject }
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,157 +0,0 @@
|
|||||||
import * as http from "node:http"
|
|
||||||
import * as tls from "node:tls"
|
|
||||||
|
|
||||||
type NodeHttpWithEnvProxy = typeof http & {
|
|
||||||
setGlobalProxyFromEnv: () => void
|
|
||||||
}
|
|
||||||
|
|
||||||
type NodeTlsWithSystemCertificates = typeof tls & {
|
|
||||||
getCACertificates: (type: "default" | "system") => string[]
|
|
||||||
setDefaultCACertificates: (certificates: string[]) => void
|
|
||||||
}
|
|
||||||
|
|
||||||
type StartCommand = {
|
|
||||||
type: "start"
|
|
||||||
hostname: string
|
|
||||||
port: number
|
|
||||||
password: string
|
|
||||||
userDataPath: string
|
|
||||||
}
|
|
||||||
|
|
||||||
type StopCommand = { type: "stop" }
|
|
||||||
type SidecarCommand = StartCommand | StopCommand
|
|
||||||
|
|
||||||
type SidecarMessage =
|
|
||||||
| { type: "ready" }
|
|
||||||
| { type: "stopped" }
|
|
||||||
| { type: "error"; error: { message: string; stack?: string } }
|
|
||||||
|
|
||||||
type ParentPort = {
|
|
||||||
postMessage(message: SidecarMessage): void
|
|
||||||
on(event: "message", listener: (event: { data: unknown }) => void): void
|
|
||||||
}
|
|
||||||
|
|
||||||
type Listener = {
|
|
||||||
stop(close?: boolean): void | Promise<void>
|
|
||||||
}
|
|
||||||
|
|
||||||
const parentPort = getParentPort()
|
|
||||||
let listener: Listener | undefined
|
|
||||||
|
|
||||||
parentPort.on("message", (event) => {
|
|
||||||
const command = parseCommand(event.data)
|
|
||||||
if (!command) return
|
|
||||||
if (command.type === "stop") {
|
|
||||||
void stop()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
void start(command)
|
|
||||||
})
|
|
||||||
|
|
||||||
async function start(command: StartCommand) {
|
|
||||||
try {
|
|
||||||
prepareSidecarEnv(command.password, command.userDataPath)
|
|
||||||
ensureLoopbackNoProxy()
|
|
||||||
useSystemCertificates()
|
|
||||||
useEnvProxy()
|
|
||||||
const { Server } = await import("virtual:opencode-server")
|
|
||||||
|
|
||||||
listener = await Server.listen({
|
|
||||||
port: command.port,
|
|
||||||
hostname: command.hostname,
|
|
||||||
username: "opencode",
|
|
||||||
password: command.password,
|
|
||||||
cors: ["oc://renderer"],
|
|
||||||
})
|
|
||||||
parentPort.postMessage({ type: "ready" })
|
|
||||||
} catch (error) {
|
|
||||||
parentPort.postMessage({ type: "error", error: serializeError(error) })
|
|
||||||
setImmediate(() => process.exit(1))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function stop() {
|
|
||||||
try {
|
|
||||||
await listener?.stop()
|
|
||||||
} finally {
|
|
||||||
listener = undefined
|
|
||||||
parentPort.postMessage({ type: "stopped" })
|
|
||||||
setImmediate(() => process.exit(0))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function prepareSidecarEnv(password: string, userDataPath: string) {
|
|
||||||
Object.assign(process.env, {
|
|
||||||
OPENCODE_SERVER_USERNAME: "opencode",
|
|
||||||
OPENCODE_SERVER_PASSWORD: password,
|
|
||||||
XDG_STATE_HOME: process.env.XDG_STATE_HOME ?? userDataPath,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
function ensureLoopbackNoProxy() {
|
|
||||||
const loopback = ["127.0.0.1", "localhost", "::1"]
|
|
||||||
const upsert = (key: string) => {
|
|
||||||
const items = (process.env[key] ?? "")
|
|
||||||
.split(",")
|
|
||||||
.map((value: string) => value.trim())
|
|
||||||
.filter((value: string) => Boolean(value))
|
|
||||||
|
|
||||||
for (const host of loopback) {
|
|
||||||
if (items.some((value: string) => value.toLowerCase() === host)) continue
|
|
||||||
items.push(host)
|
|
||||||
}
|
|
||||||
|
|
||||||
process.env[key] = items.join(",")
|
|
||||||
}
|
|
||||||
|
|
||||||
upsert("NO_PROXY")
|
|
||||||
upsert("no_proxy")
|
|
||||||
}
|
|
||||||
|
|
||||||
function useSystemCertificates() {
|
|
||||||
try {
|
|
||||||
const nodeTls = tls as NodeTlsWithSystemCertificates
|
|
||||||
nodeTls.setDefaultCACertificates([
|
|
||||||
...new Set([...nodeTls.getCACertificates("default"), ...nodeTls.getCACertificates("system")]),
|
|
||||||
])
|
|
||||||
} catch (error) {
|
|
||||||
console.warn("failed to load system certificates", error)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function useEnvProxy() {
|
|
||||||
try {
|
|
||||||
;(http as NodeHttpWithEnvProxy).setGlobalProxyFromEnv()
|
|
||||||
} catch (error) {
|
|
||||||
console.warn("failed to load proxy environment", error)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function parseCommand(value: unknown): SidecarCommand | undefined {
|
|
||||||
if (!value || typeof value !== "object") return
|
|
||||||
const command = value as Partial<StartCommand | StopCommand>
|
|
||||||
if (command.type === "stop") return { type: "stop" }
|
|
||||||
if (command.type !== "start") return
|
|
||||||
if (typeof command.hostname !== "string") return
|
|
||||||
if (typeof command.port !== "number") return
|
|
||||||
if (typeof command.password !== "string") return
|
|
||||||
if (typeof command.userDataPath !== "string") return
|
|
||||||
return {
|
|
||||||
type: "start",
|
|
||||||
hostname: command.hostname,
|
|
||||||
port: command.port,
|
|
||||||
password: command.password,
|
|
||||||
userDataPath: command.userDataPath,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function serializeError(error: unknown) {
|
|
||||||
if (error instanceof Error) return { message: error.message, stack: error.stack }
|
|
||||||
return { message: String(error) }
|
|
||||||
}
|
|
||||||
|
|
||||||
function getParentPort() {
|
|
||||||
const port = process.parentPort as ParentPort | undefined
|
|
||||||
if (!port) throw new Error("Sidecar parent port unavailable")
|
|
||||||
return port
|
|
||||||
}
|
|
||||||
@@ -23,44 +23,11 @@ export type ProviderContext = {
|
|||||||
options: Record<string, any>
|
options: Record<string, any>
|
||||||
}
|
}
|
||||||
|
|
||||||
export type WorkspaceInfo = {
|
|
||||||
id: string
|
|
||||||
type: string
|
|
||||||
name: string
|
|
||||||
branch: string | null
|
|
||||||
directory: string | null
|
|
||||||
extra: unknown | null
|
|
||||||
projectID: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export type WorkspaceTarget =
|
|
||||||
| {
|
|
||||||
type: "local"
|
|
||||||
directory: string
|
|
||||||
}
|
|
||||||
| {
|
|
||||||
type: "remote"
|
|
||||||
url: string | URL
|
|
||||||
headers?: HeadersInit
|
|
||||||
}
|
|
||||||
|
|
||||||
export type WorkspaceAdapter = {
|
|
||||||
name: string
|
|
||||||
description: string
|
|
||||||
configure(config: WorkspaceInfo): WorkspaceInfo | Promise<WorkspaceInfo>
|
|
||||||
create(config: WorkspaceInfo, env: Record<string, string | undefined>, from?: WorkspaceInfo): Promise<void>
|
|
||||||
remove(config: WorkspaceInfo): Promise<void>
|
|
||||||
target(config: WorkspaceInfo): WorkspaceTarget | Promise<WorkspaceTarget>
|
|
||||||
}
|
|
||||||
|
|
||||||
export type PluginInput = {
|
export type PluginInput = {
|
||||||
client: ReturnType<typeof createOpencodeClient>
|
client: ReturnType<typeof createOpencodeClient>
|
||||||
project: Project
|
project: Project
|
||||||
directory: string
|
directory: string
|
||||||
worktree: string
|
worktree: string
|
||||||
experimental_workspace: {
|
|
||||||
register(type: string, adapter: WorkspaceAdapter): void
|
|
||||||
}
|
|
||||||
serverUrl: URL
|
serverUrl: URL
|
||||||
$: BunShell
|
$: BunShell
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ export const LocationQuery = Schema.Struct({
|
|||||||
location: Schema.optional(
|
location: Schema.optional(
|
||||||
Schema.Struct({
|
Schema.Struct({
|
||||||
directory: Schema.optional(Schema.String),
|
directory: Schema.optional(Schema.String),
|
||||||
workspace: Schema.optional(Schema.String),
|
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
}).annotate({ identifier: "LocationQuery" })
|
}).annotate({ identifier: "LocationQuery" })
|
||||||
|
|||||||
@@ -130,7 +130,7 @@ export const PtyGroup = HttpApiGroup.make("server.pty")
|
|||||||
"x-websocket": true,
|
"x-websocket": true,
|
||||||
parameters: [
|
parameters: [
|
||||||
...(operation.parameters ?? []),
|
...(operation.parameters ?? []),
|
||||||
...["location[directory]", "location[workspace]", "cursor", PTY_CONNECT_TICKET_QUERY].map((name) => ({
|
...["location[directory]", "cursor", PTY_CONNECT_TICKET_QUERY].map((name) => ({
|
||||||
in: "query",
|
in: "query",
|
||||||
name,
|
name,
|
||||||
schema: { type: "string" },
|
schema: { type: "string" },
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import { InstructionEntry } from "@opencode-ai/schema/instruction-entry"
|
|||||||
import { Project } from "@opencode-ai/schema/project"
|
import { Project } from "@opencode-ai/schema/project"
|
||||||
import { AbsolutePath, PositiveInt, RelativePath, statics } from "@opencode-ai/schema/schema"
|
import { AbsolutePath, PositiveInt, RelativePath, statics } from "@opencode-ai/schema/schema"
|
||||||
import { Event } from "@opencode-ai/schema/event"
|
import { Event } from "@opencode-ai/schema/event"
|
||||||
import { Workspace } from "@opencode-ai/schema/workspace"
|
|
||||||
import { Context, Effect, Encoding, Result, Schema, SchemaGetter, Struct } from "effect"
|
import { Context, Effect, Encoding, Result, Schema, SchemaGetter, Struct } from "effect"
|
||||||
import { HttpApiEndpoint, HttpApiGroup, HttpApiMiddleware, HttpApiSchema, OpenApi } from "effect/unstable/httpapi"
|
import { HttpApiEndpoint, HttpApiGroup, HttpApiMiddleware, HttpApiSchema, OpenApi } from "effect/unstable/httpapi"
|
||||||
import {
|
import {
|
||||||
@@ -42,7 +41,6 @@ const ParentIDFilter = Schema.Union([
|
|||||||
})
|
})
|
||||||
|
|
||||||
const SessionsQueryFields = {
|
const SessionsQueryFields = {
|
||||||
workspace: Workspace.ID.pipe(Schema.optional),
|
|
||||||
limit: Schema.NumberFromString.pipe(Schema.decodeTo(PositiveInt), Schema.optional).annotate({
|
limit: Schema.NumberFromString.pipe(Schema.decodeTo(PositiveInt), Schema.optional).annotate({
|
||||||
description: "Maximum number of sessions to return. Defaults to the newest 50 sessions.",
|
description: "Maximum number of sessions to return. Defaults to the newest 50 sessions.",
|
||||||
}),
|
}),
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import { Session } from "@opencode-ai/schema/session"
|
|||||||
describe("SessionsCursor", () => {
|
describe("SessionsCursor", () => {
|
||||||
test("round trips without Node globals", async () => {
|
test("round trips without Node globals", async () => {
|
||||||
const input = {
|
const input = {
|
||||||
workspace: undefined,
|
|
||||||
search: "protocol",
|
search: "protocol",
|
||||||
order: "desc" as const,
|
order: "desc" as const,
|
||||||
anchor: { id: Session.ID.make("ses_test"), time: 1, direction: "next" as const },
|
anchor: { id: Session.ID.make("ses_test"), time: 1, direction: "next" as const },
|
||||||
|
|||||||
@@ -32,7 +32,6 @@ import { SessionStatusEvent } from "./session-status-event.js"
|
|||||||
import { SessionV1 } from "./session-v1.js"
|
import { SessionV1 } from "./session-v1.js"
|
||||||
import { TuiEvent } from "./tui-event.js"
|
import { TuiEvent } from "./tui-event.js"
|
||||||
import { VcsEvent } from "./vcs-event.js"
|
import { VcsEvent } from "./vcs-event.js"
|
||||||
import { WorkspaceEvent } from "./workspace-event.js"
|
|
||||||
import { WorktreeEvent } from "./worktree-event.js"
|
import { WorktreeEvent } from "./worktree-event.js"
|
||||||
import { WebSearch } from "./websearch.js"
|
import { WebSearch } from "./websearch.js"
|
||||||
|
|
||||||
@@ -100,7 +99,6 @@ export const Definitions = Event.inventory(
|
|||||||
...SessionStatusEvent.Definitions,
|
...SessionStatusEvent.Definitions,
|
||||||
...SessionCompactionEvent.Definitions,
|
...SessionCompactionEvent.Definitions,
|
||||||
...VcsEvent.Definitions,
|
...VcsEvent.Definitions,
|
||||||
...WorkspaceEvent.Definitions,
|
|
||||||
...WorktreeEvent.Definitions,
|
...WorktreeEvent.Definitions,
|
||||||
...ServerEvent.Definitions,
|
...ServerEvent.Definitions,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,32 +0,0 @@
|
|||||||
export * as WorkspaceEvent from "./workspace-event.js"
|
|
||||||
|
|
||||||
import { Schema } from "effect"
|
|
||||||
import { Event } from "./event.js"
|
|
||||||
import { WorkspaceID } from "./workspace-id.js"
|
|
||||||
|
|
||||||
export const ConnectionStatus = Schema.Struct({
|
|
||||||
workspaceID: WorkspaceID,
|
|
||||||
status: Schema.Literals(["connected", "connecting", "disconnected", "error"]),
|
|
||||||
}).annotate({ identifier: "WorkspaceEvent.ConnectionStatus" })
|
|
||||||
export interface ConnectionStatus extends Schema.Schema.Type<typeof ConnectionStatus> {}
|
|
||||||
|
|
||||||
export const Ready = Event.ephemeral({
|
|
||||||
type: "workspace.ready",
|
|
||||||
schema: {
|
|
||||||
name: Schema.String,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
export const Failed = Event.ephemeral({
|
|
||||||
type: "workspace.failed",
|
|
||||||
schema: {
|
|
||||||
message: Schema.String,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
export const Status = Event.ephemeral({
|
|
||||||
type: "workspace.status",
|
|
||||||
schema: ConnectionStatus.fields,
|
|
||||||
})
|
|
||||||
|
|
||||||
export const Definitions = Event.inventory(Ready, Failed, Status)
|
|
||||||
@@ -1,9 +1,6 @@
|
|||||||
export * as Workspace from "./workspace.js"
|
export * as Workspace from "./workspace.js"
|
||||||
|
|
||||||
import { WorkspaceEvent } from "./workspace-event.js"
|
|
||||||
import { WorkspaceID } from "./workspace-id.js"
|
import { WorkspaceID } from "./workspace-id.js"
|
||||||
|
|
||||||
export const ID = WorkspaceID
|
export const ID = WorkspaceID
|
||||||
export type ID = WorkspaceID
|
export type ID = WorkspaceID
|
||||||
|
|
||||||
export const Event = WorkspaceEvent
|
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ import {
|
|||||||
Project,
|
Project,
|
||||||
Reference,
|
Reference,
|
||||||
Session,
|
Session,
|
||||||
Workspace,
|
|
||||||
} from "../src/index.js"
|
} from "../src/index.js"
|
||||||
import { EventManifest } from "../src/event-manifest.js"
|
import { EventManifest } from "../src/event-manifest.js"
|
||||||
import { FileSystemV1 } from "../src/filesystem-v1.js"
|
import { FileSystemV1 } from "../src/filesystem-v1.js"
|
||||||
@@ -20,7 +19,6 @@ import { SessionEvent } from "../src/session-event.js"
|
|||||||
import { SessionID } from "../src/session-id.js"
|
import { SessionID } from "../src/session-id.js"
|
||||||
import { SessionMessage } from "../src/session-message.js"
|
import { SessionMessage } from "../src/session-message.js"
|
||||||
import { SessionV1 } from "../src/session-v1.js"
|
import { SessionV1 } from "../src/session-v1.js"
|
||||||
import { WorkspaceEvent } from "../src/workspace-event.js"
|
|
||||||
|
|
||||||
describe("public event manifest", () => {
|
describe("public event manifest", () => {
|
||||||
test("owns the complete public event surface", () => {
|
test("owns the complete public event surface", () => {
|
||||||
@@ -60,8 +58,6 @@ describe("public event manifest", () => {
|
|||||||
test("uses canonical definitions for current public events", () => {
|
test("uses canonical definitions for current public events", () => {
|
||||||
expect(Session.Event).toBe(SessionEvent)
|
expect(Session.Event).toBe(SessionEvent)
|
||||||
expect(Session.Event.Definitions).toBe(SessionEvent.Definitions)
|
expect(Session.Event.Definitions).toBe(SessionEvent.Definitions)
|
||||||
expect(Workspace.Event).toBe(WorkspaceEvent)
|
|
||||||
expect(Workspace.Event.Definitions).toBe(WorkspaceEvent.Definitions)
|
|
||||||
expect(EventManifest.Latest.get("session.step.ended")).toBe(SessionEvent.Step.Ended)
|
expect(EventManifest.Latest.get("session.step.ended")).toBe(SessionEvent.Step.Ended)
|
||||||
expect(EventManifest.Latest.get("agent.updated")).toBe(Agent.Event.Updated)
|
expect(EventManifest.Latest.get("agent.updated")).toBe(Agent.Event.Updated)
|
||||||
expect(EventManifest.Latest.get("project.updated")).toBe(Project.Event.Updated)
|
expect(EventManifest.Latest.get("project.updated")).toBe(Project.Event.Updated)
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ export const LocationHandler = HttpApiBuilder.group(Api, "server.location", (han
|
|||||||
const location = yield* Location.Service
|
const location = yield* Location.Service
|
||||||
return new Location.Info({
|
return new Location.Info({
|
||||||
directory: location.directory,
|
directory: location.directory,
|
||||||
workspaceID: location.workspaceID,
|
|
||||||
project: location.project,
|
project: location.project,
|
||||||
})
|
})
|
||||||
}),
|
}),
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ import { PtyEnvironment } from "../pty-environment"
|
|||||||
|
|
||||||
const ticketScope = Effect.gen(function* () {
|
const ticketScope = Effect.gen(function* () {
|
||||||
const location = yield* Location.Service
|
const location = yield* Location.Service
|
||||||
return { directory: location.directory as string, workspaceID: location.workspaceID }
|
return { directory: location.directory as string }
|
||||||
})
|
})
|
||||||
|
|
||||||
export const PtyHandler = HttpApiBuilder.group(Api, "server.pty", (handlers) =>
|
export const PtyHandler = HttpApiBuilder.group(Api, "server.pty", (handlers) =>
|
||||||
|
|||||||
@@ -37,7 +37,6 @@ export const SessionHandler = HttpApiBuilder.group(Api, "server.session", (handl
|
|||||||
: ctx.query
|
: ctx.query
|
||||||
const page = yield* session.list({
|
const page = yield* session.list({
|
||||||
...query,
|
...query,
|
||||||
workspaceID: query.workspace,
|
|
||||||
limit: ctx.query.limit ?? DefaultSessionsLimit,
|
limit: ctx.query.limit ?? DefaultSessionsLimit,
|
||||||
})
|
})
|
||||||
const sessions = page.data
|
const sessions = page.data
|
||||||
@@ -213,7 +212,6 @@ export const SessionHandler = HttpApiBuilder.group(Api, "server.session", (handl
|
|||||||
.move({
|
.move({
|
||||||
sessionID: ctx.params.sessionID,
|
sessionID: ctx.params.sessionID,
|
||||||
directory: ctx.payload.directory,
|
directory: ctx.payload.directory,
|
||||||
workspaceID: ctx.payload.workspaceID,
|
|
||||||
})
|
})
|
||||||
.pipe(
|
.pipe(
|
||||||
Effect.catchTag("Session.NotFoundError", (error) =>
|
Effect.catchTag("Session.NotFoundError", (error) =>
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import { Location } from "@opencode-ai/core/location"
|
import { Location } from "@opencode-ai/core/location"
|
||||||
import { LocationServiceMap } from "@opencode-ai/core/location-services"
|
import { LocationServiceMap } from "@opencode-ai/core/location-services"
|
||||||
import { AbsolutePath } from "@opencode-ai/core/schema"
|
import { AbsolutePath } from "@opencode-ai/core/schema"
|
||||||
import { Workspace } from "@opencode-ai/core/workspace"
|
|
||||||
import { Effect, Layer } from "effect"
|
import { Effect, Layer } from "effect"
|
||||||
import { HttpServerRequest } from "effect/unstable/http"
|
import { HttpServerRequest } from "effect/unstable/http"
|
||||||
import { HttpApiMiddleware } from "effect/unstable/httpapi"
|
import { HttpApiMiddleware } from "effect/unstable/httpapi"
|
||||||
@@ -18,7 +17,6 @@ export function response<A, E, R>(data: Effect.Effect<A, E, R>) {
|
|||||||
return {
|
return {
|
||||||
location: new Location.Info({
|
location: new Location.Info({
|
||||||
directory: location.directory,
|
directory: location.directory,
|
||||||
workspaceID: location.workspaceID,
|
|
||||||
project: location.project,
|
project: location.project,
|
||||||
}),
|
}),
|
||||||
data: yield* data,
|
data: yield* data,
|
||||||
@@ -28,13 +26,11 @@ export function response<A, E, R>(data: Effect.Effect<A, E, R>) {
|
|||||||
|
|
||||||
export function requestRef(request: HttpServerRequest.HttpServerRequest): Location.Ref {
|
export function requestRef(request: HttpServerRequest.HttpServerRequest): Location.Ref {
|
||||||
const query = new URL(request.url, "http://localhost").searchParams
|
const query = new URL(request.url, "http://localhost").searchParams
|
||||||
const workspaceID = query.get("location[workspace]") || request.headers["x-opencode-workspace"]
|
|
||||||
const directory =
|
const directory =
|
||||||
query.get("location[directory]") ||
|
query.get("location[directory]") ||
|
||||||
(request.headers["x-opencode-directory"] ? decode(request.headers["x-opencode-directory"]) : process.cwd())
|
(request.headers["x-opencode-directory"] ? decode(request.headers["x-opencode-directory"]) : process.cwd())
|
||||||
return Location.Ref.make({
|
return Location.Ref.make({
|
||||||
directory: AbsolutePath.make(directory),
|
directory: AbsolutePath.make(directory),
|
||||||
workspaceID: workspaceID ? Workspace.ID.make(workspaceID) : undefined,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import { Location } from "@opencode-ai/core/location"
|
|||||||
import { AbsolutePath } from "@opencode-ai/core/schema"
|
import { AbsolutePath } from "@opencode-ai/core/schema"
|
||||||
import { Session } from "@opencode-ai/core/session"
|
import { Session } from "@opencode-ai/core/session"
|
||||||
import { SessionTable } from "@opencode-ai/core/session/sql"
|
import { SessionTable } from "@opencode-ai/core/session/sql"
|
||||||
import { Workspace } from "@opencode-ai/core/workspace"
|
|
||||||
import { eq } from "drizzle-orm"
|
import { eq } from "drizzle-orm"
|
||||||
import { Effect, Layer, Schema } from "effect"
|
import { Effect, Layer, Schema } from "effect"
|
||||||
import { HttpRouter } from "effect/unstable/http"
|
import { HttpRouter } from "effect/unstable/http"
|
||||||
@@ -40,7 +39,7 @@ export const sessionLocationLayer = Layer.effect(
|
|||||||
),
|
),
|
||||||
)
|
)
|
||||||
const row = yield* db
|
const row = yield* db
|
||||||
.select({ directory: SessionTable.directory, workspaceID: SessionTable.workspace_id })
|
.select({ directory: SessionTable.directory })
|
||||||
.from(SessionTable)
|
.from(SessionTable)
|
||||||
.where(eq(SessionTable.id, sessionID))
|
.where(eq(SessionTable.id, sessionID))
|
||||||
.get()
|
.get()
|
||||||
@@ -56,7 +55,6 @@ export const sessionLocationLayer = Layer.effect(
|
|||||||
locations.get(
|
locations.get(
|
||||||
Location.Ref.make({
|
Location.Ref.make({
|
||||||
directory: AbsolutePath.make(row.directory),
|
directory: AbsolutePath.make(row.directory),
|
||||||
workspaceID: row.workspaceID ? Workspace.ID.make(row.workspaceID) : undefined,
|
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -36,10 +36,6 @@ export const lineCommentStyles = `
|
|||||||
border: none;
|
border: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
[data-component="line-comment"][data-variant="add"] [data-slot="line-comment-button"] {
|
|
||||||
background: var(--syntax-diff-add);
|
|
||||||
}
|
|
||||||
|
|
||||||
[data-component="line-comment"] [data-component="icon"] {
|
[data-component="line-comment"] [data-component="icon"] {
|
||||||
color: var(--white);
|
color: var(--white);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import { useI18n } from "@opencode-ai/ui/context/i18n"
|
|||||||
|
|
||||||
installLineCommentStyles()
|
installLineCommentStyles()
|
||||||
|
|
||||||
export type LineCommentVariant = "default" | "editor" | "add"
|
export type LineCommentVariant = "default" | "editor"
|
||||||
|
|
||||||
function InlineGlyph(props: { icon: "comment" | "plus" }) {
|
function InlineGlyph(props: { icon: "comment" | "plus" }) {
|
||||||
return (
|
return (
|
||||||
@@ -156,25 +156,6 @@ export const LineComment = (props: LineCommentProps) => {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export type LineCommentAddProps = Omit<LineCommentAnchorProps, "children" | "variant" | "open" | "icon"> & {
|
|
||||||
label?: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export const LineCommentAdd = (props: LineCommentAddProps) => {
|
|
||||||
const [split, rest] = splitProps(props, ["label"])
|
|
||||||
const i18n = useI18n()
|
|
||||||
|
|
||||||
return (
|
|
||||||
<LineCommentAnchor
|
|
||||||
{...rest}
|
|
||||||
open={false}
|
|
||||||
variant="add"
|
|
||||||
icon="plus"
|
|
||||||
buttonLabel={split.label ?? i18n.t("ui.lineComment.submit")}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export type LineCommentEditorProps = Omit<LineCommentAnchorProps, "children" | "open" | "variant" | "onClick"> & {
|
export type LineCommentEditorProps = Omit<LineCommentAnchorProps, "children" | "open" | "variant" | "onClick"> & {
|
||||||
value: string
|
value: string
|
||||||
selection: JSX.Element
|
selection: JSX.Element
|
||||||
|
|||||||
@@ -948,10 +948,6 @@ function ExaOutput(props: { output?: string }) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function registerPartComponent(type: string, component: PartComponent) {
|
|
||||||
PART_MAPPING[type] = component
|
|
||||||
}
|
|
||||||
|
|
||||||
export function Message(props: MessageProps) {
|
export function Message(props: MessageProps) {
|
||||||
return (
|
return (
|
||||||
<Switch>
|
<Switch>
|
||||||
|
|||||||
@@ -34,10 +34,6 @@ export function SessionFilePanelV2(props: {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function SessionFilePanelV2Title(props: ParentProps) {
|
|
||||||
return <div data-slot="session-review-v2-toolbar-title">{props.children}</div>
|
|
||||||
}
|
|
||||||
|
|
||||||
export function SessionFilePanelV2Empty(props: ParentProps) {
|
export function SessionFilePanelV2Empty(props: ParentProps) {
|
||||||
return <div data-slot="session-review-v2-empty">{props.children}</div>
|
return <div data-slot="session-review-v2-empty">{props.children}</div>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -600,7 +600,6 @@ function App(props: { pair?: DialogPairCredentials }) {
|
|||||||
order: "desc",
|
order: "desc",
|
||||||
parentID: null,
|
parentID: null,
|
||||||
directory: location.directory,
|
directory: location.directory,
|
||||||
workspace: location.workspaceID,
|
|
||||||
})
|
})
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
const match = response.data[0]?.id
|
const match = response.data[0]?.id
|
||||||
|
|||||||
@@ -684,7 +684,7 @@ async function disconnected(
|
|||||||
|
|
||||||
function location(data: ReturnType<typeof useData>) {
|
function location(data: ReturnType<typeof useData>) {
|
||||||
const current = data.location.default()
|
const current = data.location.default()
|
||||||
return { directory: current.directory, workspace: current.workspaceID }
|
return { directory: current.directory }
|
||||||
}
|
}
|
||||||
|
|
||||||
function message(cause: unknown) {
|
function message(cause: unknown) {
|
||||||
|
|||||||
@@ -81,7 +81,7 @@ export function DialogMcp() {
|
|||||||
if (!server || server.status.status === "pending") return
|
if (!server || server.status.status === "pending") return
|
||||||
setLoading(name)
|
setLoading(name)
|
||||||
const current = data.location.default()
|
const current = data.location.default()
|
||||||
const input = { server: name, location: { directory: current.directory, workspace: current.workspaceID } }
|
const input = { server: name, location: { directory: current.directory } }
|
||||||
const call = server.status.status === "connected" ? client.api.mcp.disconnect(input) : client.api.mcp.connect(input)
|
const call = server.status.status === "connected" ? client.api.mcp.disconnect(input) : client.api.mcp.connect(input)
|
||||||
void call.catch(toast.error).finally(() => setLoading(null))
|
void call.catch(toast.error).finally(() => setLoading(null))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,12 +7,14 @@ import { DialogVariant } from "./dialog-variant"
|
|||||||
import * as fuzzysort from "fuzzysort"
|
import * as fuzzysort from "fuzzysort"
|
||||||
import { useConnected } from "./use-connected"
|
import { useConnected } from "./use-connected"
|
||||||
import { useData } from "../context/data"
|
import { useData } from "../context/data"
|
||||||
|
import { modelPreferenceKey } from "../model-preference"
|
||||||
|
|
||||||
export function DialogModel(props: { providerID?: string }) {
|
export function DialogModel(props: { providerID?: string }) {
|
||||||
const local = useLocal()
|
const local = useLocal()
|
||||||
const data = useData()
|
const data = useData()
|
||||||
const dialog = useDialog()
|
const dialog = useDialog()
|
||||||
const [query, setQuery] = createSignal("")
|
const [query, setQuery] = createSignal("")
|
||||||
|
const favoritePriority = new Set(local.model.favorite().map(modelPreferenceKey))
|
||||||
|
|
||||||
const connected = useConnected()
|
const connected = useConnected()
|
||||||
const providers = createMemo(() => new Map((data.location.provider.list() ?? []).map((item) => [item.id, item])))
|
const providers = createMemo(() => new Map((data.location.provider.list() ?? []).map((item) => [item.id, item])))
|
||||||
@@ -63,14 +65,14 @@ export function DialogModel(props: { providerID?: string }) {
|
|||||||
.filter((model) => (props.providerID ? model.providerID === props.providerID : true))
|
.filter((model) => (props.providerID ? model.providerID === props.providerID : true))
|
||||||
.map((model) => {
|
.map((model) => {
|
||||||
const provider = providers().get(model.providerID)
|
const provider = providers().get(model.providerID)
|
||||||
const favorite = favorites.some((item) => item.providerID === model.providerID && item.modelID === model.id)
|
const key = modelPreferenceKey({ providerID: model.providerID, modelID: model.id })
|
||||||
|
const favorite = favorites.some((item) => modelPreferenceKey(item) === key)
|
||||||
return {
|
return {
|
||||||
value: { providerID: model.providerID, modelID: model.id },
|
value: { providerID: model.providerID, modelID: model.id },
|
||||||
providerID: model.providerID,
|
providerID: model.providerID,
|
||||||
providerName: provider?.name ?? model.providerID,
|
providerName: provider?.name ?? model.providerID,
|
||||||
title: model.name,
|
title: model.name,
|
||||||
releaseDate: model.time.released,
|
releaseDate: model.time.released,
|
||||||
favorite,
|
|
||||||
description: favorite ? "(Favorite)" : undefined,
|
description: favorite ? "(Favorite)" : undefined,
|
||||||
category: connected() ? (provider?.name ?? model.providerID) : undefined,
|
category: connected() ? (provider?.name ?? model.providerID) : undefined,
|
||||||
footer: free(model) ? "Free" : undefined,
|
footer: free(model) ? "Free" : undefined,
|
||||||
@@ -98,6 +100,7 @@ export function DialogModel(props: { providerID?: string }) {
|
|||||||
if (needle) {
|
if (needle) {
|
||||||
return prioritizeFavorites(
|
return prioritizeFavorites(
|
||||||
fuzzysort.go(needle, modelOptions, { keys: ["title", "category"] }).map((item) => item.obj),
|
fuzzysort.go(needle, modelOptions, { keys: ["title", "category"] }).map((item) => item.obj),
|
||||||
|
favoritePriority,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -162,8 +165,13 @@ export function DialogModel(props: { providerID?: string }) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function prioritizeFavorites<T extends { favorite: boolean }>(options: T[]) {
|
export function prioritizeFavorites<T extends { value: { providerID: string; modelID: string } }>(
|
||||||
return options.toSorted((a, b) => Number(b.favorite) - Number(a.favorite))
|
options: T[],
|
||||||
|
favorites: Set<string>,
|
||||||
|
) {
|
||||||
|
return options.toSorted(
|
||||||
|
(a, b) => Number(favorites.has(modelPreferenceKey(b.value))) - Number(favorites.has(modelPreferenceKey(a.value))),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function sortModelOptions<
|
export function sortModelOptions<
|
||||||
|
|||||||
@@ -290,7 +290,6 @@ export function Autocomplete(props: {
|
|||||||
limit: 20,
|
limit: 20,
|
||||||
location: {
|
location: {
|
||||||
directory: input.location?.directory,
|
directory: input.location?.directory,
|
||||||
workspace: input.location?.workspaceID ?? data.location.default().workspaceID,
|
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
.then(
|
.then(
|
||||||
|
|||||||
@@ -19,7 +19,6 @@ function location(ref: LocationRef) {
|
|||||||
return {
|
return {
|
||||||
location: {
|
location: {
|
||||||
directory: ref.directory,
|
directory: ref.directory,
|
||||||
workspace: ref.workspaceID,
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -151,7 +151,6 @@ function formRequestOptions(location: LocationRef | undefined) {
|
|||||||
return {
|
return {
|
||||||
headers: {
|
headers: {
|
||||||
"x-opencode-directory": encodeURIComponent(location.directory),
|
"x-opencode-directory": encodeURIComponent(location.directory),
|
||||||
...(location.workspaceID ? { "x-opencode-workspace": location.workspaceID } : {}),
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -236,7 +235,7 @@ async function runInteractiveRuntime(input: RunRuntimeInput, deps: RunRuntimeDep
|
|||||||
.find({
|
.find({
|
||||||
query,
|
query,
|
||||||
type: "file",
|
type: "file",
|
||||||
location: { directory: state.location.directory, workspace: state.location.workspaceID },
|
location: { directory: state.location.directory },
|
||||||
})
|
})
|
||||||
.then((result) => result.data.map((file) => file.path))
|
.then((result) => result.data.map((file) => file.path))
|
||||||
.catch(() => []),
|
.catch(() => []),
|
||||||
@@ -651,7 +650,6 @@ async function runInteractiveRuntime(input: RunRuntimeInput, deps: RunRuntimeDep
|
|||||||
{
|
{
|
||||||
location: {
|
location: {
|
||||||
directory: state.location.directory,
|
directory: state.location.directory,
|
||||||
workspace: state.location.workspaceID,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{ signal: attempt.signal },
|
{ signal: attempt.signal },
|
||||||
|
|||||||
@@ -421,7 +421,6 @@ async function resolveSelectedModel(
|
|||||||
? {
|
? {
|
||||||
location: {
|
location: {
|
||||||
directory: input.location.directory,
|
directory: input.location.directory,
|
||||||
workspace: input.location.workspaceID,
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
: undefined,
|
: undefined,
|
||||||
@@ -819,7 +818,7 @@ export async function createSessionTransport(input: StreamInput): Promise<Sessio
|
|||||||
input.location
|
input.location
|
||||||
? client.form.request.list(
|
? client.form.request.list(
|
||||||
{
|
{
|
||||||
location: { directory: input.location.directory, workspace: input.location.workspaceID },
|
location: { directory: input.location.directory },
|
||||||
},
|
},
|
||||||
options,
|
options,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -85,7 +85,7 @@ export function ShellTab(props: { sessionID: string }) {
|
|||||||
if (!entry) return
|
if (!entry) return
|
||||||
void client.api.shell.remove({
|
void client.api.shell.remove({
|
||||||
id: entry.id,
|
id: entry.id,
|
||||||
location: { directory: entry.location.directory, workspace: entry.location.workspaceID },
|
location: { directory: entry.location.directory },
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -37,7 +37,6 @@ function requestOptions(form: FormWithLocation) {
|
|||||||
return {
|
return {
|
||||||
headers: {
|
headers: {
|
||||||
"x-opencode-directory": encodeURIComponent(form.location.directory),
|
"x-opencode-directory": encodeURIComponent(form.location.directory),
|
||||||
...(form.location.workspaceID ? { "x-opencode-workspace": form.location.workspaceID } : {}),
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -96,7 +96,6 @@ import { findMessageBoundary, messageNavigationSlack } from "./message-navigatio
|
|||||||
import { stringWidth } from "../../util/string-width"
|
import { stringWidth } from "../../util/string-width"
|
||||||
import { useArgs } from "../../context/args"
|
import { useArgs } from "../../context/args"
|
||||||
import { withTimestampedFallback } from "@opencode-ai/util/session-title-fallback"
|
import { withTimestampedFallback } from "@opencode-ai/util/session-title-fallback"
|
||||||
import { installSyntaxHighlightCache } from "../../util/syntax-highlight-cache"
|
|
||||||
|
|
||||||
addDefaultParsers(parsers.parsers)
|
addDefaultParsers(parsers.parsers)
|
||||||
|
|
||||||
@@ -129,7 +128,6 @@ function use() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function Session() {
|
export function Session() {
|
||||||
installSyntaxHighlightCache()
|
|
||||||
const setEpilogue = useEpilogue()
|
const setEpilogue = useEpilogue()
|
||||||
const clipboard = useClipboard()
|
const clipboard = useClipboard()
|
||||||
const writeExport = async (file: string, content: string) => {
|
const writeExport = async (file: string, content: string) => {
|
||||||
@@ -2542,7 +2540,7 @@ function Shell(props: ToolProps) {
|
|||||||
id,
|
id,
|
||||||
cursor,
|
cursor,
|
||||||
limit: SHELL_DISPLAY_LIMIT,
|
limit: SHELL_DISPLAY_LIMIT,
|
||||||
location: location ? { directory: location.directory, workspace: location.workspaceID } : undefined,
|
location: location ? { directory: location.directory } : undefined,
|
||||||
})
|
})
|
||||||
.catch(() => undefined)
|
.catch(() => undefined)
|
||||||
if (!response) break
|
if (!response) break
|
||||||
|
|||||||
@@ -1,38 +0,0 @@
|
|||||||
import { getTreeSitterClient, type TreeSitterClient } from "@opentui/core"
|
|
||||||
|
|
||||||
const CACHE_SIZE = 500
|
|
||||||
const installed = new WeakSet<TreeSitterClient>()
|
|
||||||
|
|
||||||
export function installSyntaxHighlightCache() {
|
|
||||||
const client = getTreeSitterClient()
|
|
||||||
if (installed.has(client)) return
|
|
||||||
installed.add(client)
|
|
||||||
client.highlightOnce = cacheHighlights(client.highlightOnce.bind(client))
|
|
||||||
}
|
|
||||||
|
|
||||||
export function cacheHighlights(highlight: TreeSitterClient["highlightOnce"], capacity = CACHE_SIZE) {
|
|
||||||
const cache = new Map<string, ReturnType<TreeSitterClient["highlightOnce"]>>()
|
|
||||||
|
|
||||||
return (content: string, filetype: string) => {
|
|
||||||
const key = `${filetype}\0${content}`
|
|
||||||
const cached = cache.get(key)
|
|
||||||
if (cached) {
|
|
||||||
cache.delete(key)
|
|
||||||
cache.set(key, cached)
|
|
||||||
return cached
|
|
||||||
}
|
|
||||||
|
|
||||||
const result = highlight(content, filetype)
|
|
||||||
cache.set(key, result)
|
|
||||||
if (cache.size > capacity) cache.delete(cache.keys().next().value!)
|
|
||||||
|
|
||||||
void result
|
|
||||||
.then((value) => {
|
|
||||||
if (value.error && cache.get(key) === result) cache.delete(key)
|
|
||||||
})
|
|
||||||
.catch(() => {
|
|
||||||
if (cache.get(key) === result) cache.delete(key)
|
|
||||||
})
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -2,13 +2,16 @@ import { describe, expect, test } from "bun:test"
|
|||||||
import { prioritizeFavorites, sortModelOptions } from "../../../../src/component/dialog-model"
|
import { prioritizeFavorites, sortModelOptions } from "../../../../src/component/dialog-model"
|
||||||
|
|
||||||
describe("prioritizeFavorites", () => {
|
describe("prioritizeFavorites", () => {
|
||||||
test("moves favorites first while preserving fuzzy result order", () => {
|
test("uses the favorite order captured when the dialog opened", () => {
|
||||||
const prioritized = prioritizeFavorites([
|
const prioritized = prioritizeFavorites(
|
||||||
{ title: "Best match", favorite: false },
|
[
|
||||||
{ title: "Favorite match", favorite: true },
|
{ title: "Best match", value: { providerID: "test", modelID: "best" } },
|
||||||
{ title: "Second best match", favorite: false },
|
{ title: "Favorite match", value: { providerID: "test", modelID: "favorite" } },
|
||||||
{ title: "Second favorite match", favorite: true },
|
{ title: "Second best match", value: { providerID: "test", modelID: "second-best" } },
|
||||||
])
|
{ title: "Second favorite match", value: { providerID: "test", modelID: "second-favorite" } },
|
||||||
|
],
|
||||||
|
new Set(["test/favorite", "test/second-favorite"]),
|
||||||
|
)
|
||||||
|
|
||||||
expect(prioritized.map((model) => model.title)).toEqual([
|
expect(prioritized.map((model) => model.title)).toEqual([
|
||||||
"Favorite match",
|
"Favorite match",
|
||||||
|
|||||||
@@ -1916,7 +1916,7 @@ test("keeps shell state scoped to location", async () => {
|
|||||||
app.mockInput.pressKey("d", { ctrl: true })
|
app.mockInput.pressKey("d", { ctrl: true })
|
||||||
await wait(() => removed !== undefined)
|
await wait(() => removed !== undefined)
|
||||||
expect(removed?.searchParams.get("location[directory]")).toBe(other)
|
expect(removed?.searchParams.get("location[directory]")).toBe(other)
|
||||||
expect(removed?.searchParams.get("location[workspace]")).toBe(workspace)
|
expect(removed?.searchParams.get("location[workspace]")).toBeNull()
|
||||||
|
|
||||||
events.emit({
|
events.emit({
|
||||||
id: "evt_shell_created",
|
id: "evt_shell_created",
|
||||||
|
|||||||
@@ -240,7 +240,6 @@ describe("run interactive runtime", () => {
|
|||||||
{
|
{
|
||||||
headers: {
|
headers: {
|
||||||
"x-opencode-directory": "%2Fremote%20work",
|
"x-opencode-directory": "%2Fremote%20work",
|
||||||
"x-opencode-workspace": "wrk_1",
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
@@ -575,7 +574,7 @@ describe("run interactive runtime", () => {
|
|||||||
painted.resolve()
|
painted.resolve()
|
||||||
await task
|
await task
|
||||||
|
|
||||||
const query = { location: { directory: "/session", workspace: "work-1" } }
|
const query = { location: { directory: "/session" } }
|
||||||
expect(getDirectory?.()).toBe("/session")
|
expect(getDirectory?.()).toBe("/session")
|
||||||
expect(transportLocation).toMatchObject({ directory: "/session", workspaceID: "work-1" })
|
expect(transportLocation).toMatchObject({ directory: "/session", workspaceID: "work-1" })
|
||||||
expect(catalogs.provider).toHaveBeenCalledWith(query, { signal: expect.any(AbortSignal) })
|
expect(catalogs.provider).toHaveBeenCalledWith(query, { signal: expect.any(AbortSignal) })
|
||||||
|
|||||||
@@ -2219,7 +2219,7 @@ describe("V2 mini transport", () => {
|
|||||||
{ signal: undefined },
|
{ signal: undefined },
|
||||||
)
|
)
|
||||||
expect(defaultModel).toHaveBeenCalledWith(
|
expect(defaultModel).toHaveBeenCalledWith(
|
||||||
{ location: { directory: "/project", workspace: "wrk_1" } },
|
{ location: { directory: "/project" } },
|
||||||
{ signal: undefined },
|
{ signal: undefined },
|
||||||
)
|
)
|
||||||
await transport.close()
|
await transport.close()
|
||||||
|
|||||||
@@ -1,69 +0,0 @@
|
|||||||
import { describe, expect, test } from "bun:test"
|
|
||||||
import { cacheHighlights } from "../../src/util/syntax-highlight-cache"
|
|
||||||
|
|
||||||
describe("syntax highlight cache", () => {
|
|
||||||
test("reuses completed and in-flight highlights", async () => {
|
|
||||||
let calls = 0
|
|
||||||
const highlight = cacheHighlights(async () => {
|
|
||||||
calls++
|
|
||||||
return { highlights: [[0, 5, "keyword"]] }
|
|
||||||
})
|
|
||||||
|
|
||||||
const first = highlight("const", "typescript")
|
|
||||||
const second = highlight("const", "typescript")
|
|
||||||
|
|
||||||
expect(second).toBe(first)
|
|
||||||
expect(await second).toEqual({ highlights: [[0, 5, "keyword"]] })
|
|
||||||
expect(await highlight("const", "typescript")).toEqual({ highlights: [[0, 5, "keyword"]] })
|
|
||||||
expect(calls).toBe(1)
|
|
||||||
})
|
|
||||||
|
|
||||||
test("evicts least recently used highlights", async () => {
|
|
||||||
let calls = 0
|
|
||||||
const highlight = cacheHighlights(async () => {
|
|
||||||
calls++
|
|
||||||
return { highlights: [] }
|
|
||||||
}, 2)
|
|
||||||
|
|
||||||
await highlight("one", "text")
|
|
||||||
await highlight("two", "text")
|
|
||||||
await highlight("one", "text")
|
|
||||||
await highlight("three", "text")
|
|
||||||
await highlight("two", "text")
|
|
||||||
|
|
||||||
expect(calls).toBe(4)
|
|
||||||
})
|
|
||||||
|
|
||||||
test("retries failed highlights", async () => {
|
|
||||||
let calls = 0
|
|
||||||
const highlight = cacheHighlights(async () => {
|
|
||||||
calls++
|
|
||||||
if (calls === 1) return { error: "parser unavailable" }
|
|
||||||
return { highlights: [] }
|
|
||||||
})
|
|
||||||
|
|
||||||
await highlight("const", "typescript")
|
|
||||||
await highlight("const", "typescript")
|
|
||||||
|
|
||||||
expect(calls).toBe(2)
|
|
||||||
})
|
|
||||||
|
|
||||||
test("an evicted failure does not delete its replacement", async () => {
|
|
||||||
const pending = Promise.withResolvers<{ highlights: [] }>()
|
|
||||||
let calls = 0
|
|
||||||
const highlight = cacheHighlights(() => {
|
|
||||||
calls++
|
|
||||||
if (calls === 1) return pending.promise
|
|
||||||
return Promise.resolve({ highlights: [] })
|
|
||||||
}, 1)
|
|
||||||
|
|
||||||
const stale = highlight("one", "text")
|
|
||||||
await highlight("two", "text")
|
|
||||||
const current = highlight("one", "text")
|
|
||||||
pending.reject(new Error("parser unavailable"))
|
|
||||||
|
|
||||||
await expect(stale).rejects.toThrow("parser unavailable")
|
|
||||||
expect(highlight("one", "text")).toBe(current)
|
|
||||||
expect(calls).toBe(3)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
File diff suppressed because one or more lines are too long
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user