Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions src/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,18 @@ export const sharedGlobalSettingsPath = () =>
export const sharedConfigPath = (configPathOverride?: string) =>
configPathOverride ? path.resolve(configPathOverride) : sharedGlobalSettingsPath()

const endpointBaseUrl = (scope: unknown) => {
const endpoint = isRecord(scope) ? scope.endpoint : undefined
return isRecord(endpoint) && typeof endpoint.baseUrl === "string" ? endpoint.baseUrl.trim() : ""
}

/** `baseUrl`, else the `endpoint.baseUrl` other Honcho integrations write (host block, then top level). */
export const resolveBaseUrl = (raw: Record<string, unknown>, hostId = "opencode") => {
const baseUrl = typeof raw.baseUrl === "string" ? raw.baseUrl.trim() : ""
if (baseUrl) return baseUrl
return endpointBaseUrl(isRecord(raw.hosts) ? raw.hosts[hostId] : undefined) || endpointBaseUrl(raw)
}

export const normalizeId = (value: string) =>
value.toLowerCase().replace(/[^a-z0-9_-]+/g, "-").replace(/^-+|-+$/g, "") || "default"

Expand Down
3 changes: 3 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import {
normalizeId,
observationUpgradeNextSteps,
observationUpgradeNotice,
resolveBaseUrl,
resolveSessionPeerIds,
SETTING_ENUMS,
sharedConfigPath,
Expand Down Expand Up @@ -623,6 +624,8 @@ const normalizeScopedSettings = (raw: Record<string, unknown>, hostId = "opencod
if (typeof value === "string" && !value.trim() && INHERITABLE_STRING_KEYS.has(field)) continue
normalized[field] = value
}
const baseUrl = resolveBaseUrl(raw, hostId)
if (baseUrl) normalized.baseUrl = baseUrl
const hostBlock = isRecord(raw.hosts) ? hostScopedSettings(raw.hosts[hostId]) : null

if (hostBlock) {
Expand Down
12 changes: 5 additions & 7 deletions src/tui/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
isRecord,
needsObservationUpgradePrompt,
observationUpgradeNotice,
resolveBaseUrl,
resolveSessionPeerIds,
sharedConfigPath,
unifiedImportFollowUp,
Expand Down Expand Up @@ -143,10 +144,7 @@ const writeGlobalSettings = async (settings: GlobalSettings) => {
}

export const normalizeSettings = (settings: GlobalSettings) => ({
baseUrl:
typeof settings.baseUrl === "string" && settings.baseUrl.trim()
? settings.baseUrl
: DEFAULT_SETTINGS.baseUrl,
baseUrl: resolveBaseUrl(settings as Record<string, unknown>) || DEFAULT_SETTINGS.baseUrl,
apiKey: typeof settings.apiKey === "string" && settings.apiKey.trim() ? settings.apiKey.trim() : "",
peerName: typeof settings.peerName === "string" ? settings.peerName.trim() : "",
})
Expand Down Expand Up @@ -188,7 +186,7 @@ export const settingsMessage = (settings: GlobalSettings) => {
`Config path: ${resolveConfigPath()}`,
`API key: ${settings.apiKey?.trim() ? "set" : "not set"}`,
`Peer name: ${settings.peerName?.trim() || "user"}`,
`Base URL: ${settings.baseUrl?.trim() || DEFAULT_SETTINGS.baseUrl}`,
`Base URL: ${resolveBaseUrl(settings as Record<string, unknown>) || DEFAULT_SETTINGS.baseUrl}`,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ideally in the future we don't have to cast this as Record<string, unknown>. I wonder if we can expose the structured type for this from the harness integration core?

`Workspace: ${host.workspace || DEFAULT_SETTINGS.workspace}`,
`AI peer: ${host.aiPeer || DEFAULT_SETTINGS.aiPeer}`,
`Recall mode: ${host.recallMode || DEFAULT_SETTINGS.recallMode}`,
Expand Down Expand Up @@ -271,7 +269,7 @@ const importConfigFromSettings = (settings: GlobalSettings) => {
)
return {
apiKey: settings.apiKey || "",
baseUrl: settings.baseUrl || DEFAULT_SETTINGS.baseUrl,
baseUrl: resolveBaseUrl(settings as Record<string, unknown>) || DEFAULT_SETTINGS.baseUrl,
workspaceId,
userPeerId,
agentPeerId,
Expand All @@ -297,7 +295,7 @@ const formatImportPreview = (plan: Awaited<ReturnType<typeof planOpenCodeImport>
}

const isConfigured = (settings: GlobalSettings) =>
Boolean(settings.apiKey?.trim()) || isLocalBaseUrl(settings.baseUrl || "")
Boolean(settings.apiKey?.trim()) || isLocalBaseUrl(resolveBaseUrl(settings as Record<string, unknown>))

/** true when the user chose a mode and it was saved; false when they dismissed. */
export const runObservationUpgrade = async (session: TuiSession, followUpLines: string[]) => {
Expand Down
9 changes: 9 additions & 0 deletions tests/tui-behavior.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -106,3 +106,12 @@ test("tui honors OPENCODE_HONCHO_CONFIG_PATH override for reads, writes, and dis
else process.env.OPENCODE_HONCHO_CONFIG_PATH = previousOverride
}
})

test("tui shows endpoint.baseUrl when there is no top-level baseUrl", () => {
const url = (settings) => __testing.settingsMessage(settings).match(/Base URL: (.*)/)[1]
const endpoint = { baseUrl: "http://selfhosted:8000" }
assert.equal(url({ endpoint }), "http://selfhosted:8000")
assert.equal(url({ endpoint: { baseUrl: "http://top:1" }, hosts: { opencode: { endpoint } } }), "http://selfhosted:8000")
assert.equal(url({ baseUrl: "http://explicit:9", endpoint }), "http://explicit:9")
assert.equal(url({}), "https://api.honcho.dev")
})
Loading