refactor(reference): normalize config entries (#28178)

This commit is contained in:
Shoubhit Dash
2026-05-18 20:42:41 +05:30
committed by GitHub
parent 54ff0a669b
commit eb389c58eb
4 changed files with 85 additions and 23 deletions

View File

@@ -19,7 +19,7 @@ import type { PromptInfo } from "./history"
import { useFrecency } from "./frecency"
import { useBindings } from "../../keymap"
import { Reference } from "@/reference/reference"
import type { Config } from "@/config/config"
import { ConfigReference } from "@/config/reference"
import { displayCharAt, mentionTriggerIndex } from "@/cli/cmd/prompt-display"
function removeLineRange(input: string) {
@@ -310,7 +310,7 @@ export function Autocomplete(props: {
`Referenced configured reference @${reference.name}.`,
...(reference.kind === "local" ? ["Kind: local directory"] : []),
...(reference.kind === "git" ? ["Kind: git repository"] : []),
...(reference.kind === "invalid" ? [`Repository: ${reference.repository}`] : []),
...(reference.kind === "invalid" && reference.repository ? [`Repository: ${reference.repository}`] : []),
...(reference.kind === "git" ? [`Repository: ${reference.repository}`] : []),
...(reference.kind === "git" && reference.branch ? [`Branch/ref: ${reference.branch}`] : []),
...(reference.kind === "invalid" ? [] : [`Reference root: ${reference.path}`]),
@@ -324,7 +324,7 @@ export function Autocomplete(props: {
const references = createMemo(() =>
Reference.resolveAll({
references: (sync.data.config.reference ?? {}) as NonNullable<Config.Info["reference"]>,
references: ConfigReference.normalize(sync.data.config.reference ?? {}),
directory: sync.path.directory || process.cwd(),
worktree: sync.path.worktree || sync.path.directory || process.cwd(),
}),

View File

@@ -18,6 +18,52 @@ const Local = Schema.Struct({
})
export const Entry = Schema.Union([Schema.String, Git, Local]).annotate({ identifier: "ReferenceConfigEntry" })
export type Entry = Schema.Schema.Type<typeof Entry>
export const Info = Schema.Record(Schema.String, Entry).annotate({ identifier: "ReferenceConfig" })
export type Info = Schema.Schema.Type<typeof Info>
export type NormalizedEntry =
| {
kind: "local"
path: string
}
| {
kind: "git"
repository: string
branch?: string
}
| {
kind: "invalid"
message: string
}
export type NormalizedInfo = Record<string, NormalizedEntry>
export function validateAlias(name: string) {
if (name.length === 0) return "Reference alias must not be empty"
if (/[\/\s`,]/.test(name)) {
return "Reference alias must not contain /, whitespace, comma, or backtick"
}
}
export function normalizeEntry(entry: Entry): NormalizedEntry {
if (typeof entry === "string") {
if (entry.startsWith(".") || entry.startsWith("/") || entry.startsWith("~")) {
return { kind: "local", path: entry }
}
return { kind: "git", repository: entry }
}
if ("path" in entry) return { kind: "local", path: entry.path }
return { kind: "git", repository: entry.repository, branch: entry.branch }
}
export function normalize(info: Info): NormalizedInfo {
return Object.fromEntries(
Object.entries(info).map(([name, entry]) => {
const aliasError = validateAlias(name)
return [name, aliasError ? { kind: "invalid" as const, message: aliasError } : normalizeEntry(entry)] as const
}),
)
}

View File

@@ -3,14 +3,13 @@ import { Effect, Context, Layer, Scope } from "effect"
import { AppFileSystem } from "@opencode-ai/core/filesystem"
import { Global } from "@opencode-ai/core/global"
import { Config } from "@/config/config"
import { ConfigReference } from "@/config/reference"
import { InstanceState } from "@/effect/instance-state"
import { RuntimeFlags } from "@/effect/runtime-flags"
import { Git } from "@/git"
import { parseRepositoryReference, repositoryCachePath, type Reference as RepositoryReference } from "@/util/repository"
import { RepositoryCache } from "./repository-cache"
type ReferenceEntry = NonNullable<Config.Info["reference"]>[string]
export type Resolved =
| {
name: string
@@ -28,7 +27,7 @@ export type Resolved =
| {
name: string
kind: "invalid"
repository: string
repository?: string
message: string
}
@@ -92,26 +91,21 @@ function containsReferencePath(referencePath: string, target: string) {
export function resolve(input: {
name: string
reference: ReferenceEntry
reference: ConfigReference.NormalizedEntry
directory: string
worktree: string
}): Resolved {
if (typeof input.reference === "string") {
if (input.reference.startsWith(".") || input.reference.startsWith("/") || input.reference.startsWith("~")) {
return { name: input.name, kind: "local", path: referencePath({ ...input, value: input.reference }) }
}
return resolveGit({ name: input.name, repository: input.reference })
if (input.reference.kind === "invalid") {
return { name: input.name, kind: "invalid", message: input.reference.message }
}
if ("path" in input.reference) {
if (input.reference.kind === "local") {
return { name: input.name, kind: "local", path: referencePath({ ...input, value: input.reference.path }) }
}
return resolveGit({ name: input.name, repository: input.reference.repository, branch: input.reference.branch })
}
export function resolveAll(input: {
references: NonNullable<Config.Info["reference"]>
references: ConfigReference.NormalizedInfo
directory: string
worktree: string
}) {
@@ -149,7 +143,7 @@ export const layer = Layer.effect(
Effect.fn("Reference.state")(function* (ctx) {
const cfg = yield* config.get()
const references = resolveAll({
references: cfg.reference ?? {},
references: ConfigReference.normalize(cfg.reference ?? {}),
directory: ctx.directory,
worktree: ctx.worktree,
})