refactor(tui): simplify config and tool display
This commit is contained in:
@@ -6,7 +6,7 @@
|
|||||||
// history ring. All are async because they read config or hit the SDK, but
|
// history ring. All are async because they read config or hit the SDK, but
|
||||||
// none block each other.
|
// none block each other.
|
||||||
import { Context, Effect, Layer } from "effect"
|
import { Context, Effect, Layer } from "effect"
|
||||||
import { resolve } from "@opencode-ai/tui/config"
|
import { resolve } from "@opencode-ai/tui/config/v1"
|
||||||
import { AppNodeBuilder } from "@opencode-ai/core/effect/app-node-builder"
|
import { AppNodeBuilder } from "@opencode-ai/core/effect/app-node-builder"
|
||||||
import { makeGlobalNode } from "@opencode-ai/core/effect/app-node"
|
import { makeGlobalNode } from "@opencode-ai/core/effect/app-node"
|
||||||
import { makeRuntime } from "@opencode-ai/core/effect/runtime"
|
import { makeRuntime } from "@opencode-ai/core/effect/runtime"
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
// → OpenTUI split-footer renderer writes to terminal
|
// → OpenTUI split-footer renderer writes to terminal
|
||||||
import type { OpenCodeClient, ReferenceListOutput } from "@opencode-ai/client/promise"
|
import type { OpenCodeClient, ReferenceListOutput } from "@opencode-ai/client/promise"
|
||||||
import type { FilePart, PermissionRequest, QuestionRequest, ToolPart } from "@opencode-ai/sdk/v2"
|
import type { FilePart, PermissionRequest, QuestionRequest, ToolPart } from "@opencode-ai/sdk/v2"
|
||||||
import type { TuiConfig } from "@opencode-ai/tui/config"
|
import type { TuiConfig } from "@opencode-ai/tui/config/v1"
|
||||||
|
|
||||||
export type RunFilePart = {
|
export type RunFilePart = {
|
||||||
type: "file"
|
type: "file"
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
export * as TuiConfig from "./tui-config"
|
export * as TuiConfig from "./tui-config"
|
||||||
|
|
||||||
import { Global } from "@opencode-ai/core/global"
|
import { Global } from "@opencode-ai/core/global"
|
||||||
import { TuiConfig } from "@opencode-ai/tui/config"
|
import { TuiConfig } from "@opencode-ai/tui/config/v1"
|
||||||
import { Effect, FileSystem, Option, Schema } from "effect"
|
import { Effect, FileSystem, Option, Schema } from "effect"
|
||||||
import { parse, type ParseError } from "jsonc-parser"
|
import { parse, type ParseError } from "jsonc-parser"
|
||||||
import path from "path"
|
import path from "path"
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
import { createDefaultOpenTuiKeymap } from "@opentui/keymap/opentui"
|
import { createDefaultOpenTuiKeymap } from "@opentui/keymap/opentui"
|
||||||
import { testRender, useRenderer } from "@opentui/solid"
|
import { testRender, useRenderer } from "@opentui/solid"
|
||||||
import { OpencodeKeymapProvider, registerOpencodeKeymap } from "@opencode-ai/tui/keymap"
|
import { OpencodeKeymapProvider, registerOpencodeKeymap } from "@opencode-ai/tui/keymap"
|
||||||
import { resolve } from "@opencode-ai/tui/config"
|
import { resolve } from "@opencode-ai/tui/config/v1"
|
||||||
import { expect, test } from "bun:test"
|
import { expect, test } from "bun:test"
|
||||||
import { createComponent, createSignal } from "solid-js"
|
import { createComponent, createSignal } from "solid-js"
|
||||||
import { RunFooterView } from "../src/mini/footer.view"
|
import { RunFooterView } from "../src/mini/footer.view"
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
import { Config } from "@/config/config"
|
import { Config } from "@/config/config"
|
||||||
import { ConfigV1 } from "@opencode-ai/core/v1/config/config"
|
import { ConfigV1 } from "@opencode-ai/core/v1/config/config"
|
||||||
import { TuiConfig } from "@opencode-ai/tui/config"
|
import { TuiConfig } from "@opencode-ai/tui/config/v1"
|
||||||
import { Schema } from "effect"
|
import { Schema } from "effect"
|
||||||
|
|
||||||
type JsonSchema = Record<string, unknown>
|
type JsonSchema = Record<string, unknown>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { TuiConfig } from "@opencode-ai/tui/config"
|
import { TuiConfig } from "@opencode-ai/tui/config/v1"
|
||||||
import { isRecord } from "@opencode-ai/tui/util/record"
|
import { isRecord } from "@opencode-ai/tui/util/record"
|
||||||
import { Filesystem } from "@/util/filesystem"
|
import { Filesystem } from "@/util/filesystem"
|
||||||
import { Schema } from "effect"
|
import { Schema } from "effect"
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import path from "path"
|
|||||||
import { type ParseError as JsoncParseError, applyEdits, modify, parse as parseJsonc } from "jsonc-parser"
|
import { type ParseError as JsoncParseError, applyEdits, modify, parse as parseJsonc } from "jsonc-parser"
|
||||||
import { unique } from "remeda"
|
import { unique } from "remeda"
|
||||||
import { Option, Schema } from "effect"
|
import { Option, Schema } from "effect"
|
||||||
import { TuiConfig } from "@opencode-ai/tui/config"
|
import { TuiConfig } from "@opencode-ai/tui/config/v1"
|
||||||
import { Flag } from "@opencode-ai/core/flag/flag"
|
import { Flag } from "@opencode-ai/core/flag/flag"
|
||||||
import { Global } from "@opencode-ai/core/global"
|
import { Global } from "@opencode-ai/core/global"
|
||||||
import { Filesystem } from "@/util/filesystem"
|
import { Filesystem } from "@/util/filesystem"
|
||||||
|
|||||||
@@ -15,14 +15,14 @@ import { Global } from "@opencode-ai/core/global"
|
|||||||
import { FSUtil } from "@opencode-ai/core/fs-util"
|
import { FSUtil } from "@opencode-ai/core/fs-util"
|
||||||
import { CurrentWorkingDirectory } from "./tui-cwd"
|
import { CurrentWorkingDirectory } from "./tui-cwd"
|
||||||
import { ConfigPlugin } from "@/config/plugin"
|
import { ConfigPlugin } from "@/config/plugin"
|
||||||
import { TuiKeybind } from "@opencode-ai/tui/config/keybind"
|
import { TuiKeybind } from "@opencode-ai/tui/config/v1/keybind"
|
||||||
import { InstallationLocal, InstallationVersion } from "@opencode-ai/core/installation/version"
|
import { InstallationLocal, InstallationVersion } from "@opencode-ai/core/installation/version"
|
||||||
import { makeRuntime } from "@opencode-ai/core/effect/runtime"
|
import { makeRuntime } from "@opencode-ai/core/effect/runtime"
|
||||||
import { Filesystem } from "@/util/filesystem"
|
import { Filesystem } from "@/util/filesystem"
|
||||||
import { ConfigVariable } from "@/config/variable"
|
import { ConfigVariable } from "@/config/variable"
|
||||||
import { Npm } from "@opencode-ai/core/npm"
|
import { Npm } from "@opencode-ai/core/npm"
|
||||||
import { FormatError, FormatUnknownError } from "@/cli/error"
|
import { FormatError, FormatUnknownError } from "@/cli/error"
|
||||||
import { TuiConfig } from "@opencode-ai/tui/config"
|
import { TuiConfig } from "@opencode-ai/tui/config/v1"
|
||||||
|
|
||||||
export const Info = TuiConfig.Info
|
export const Info = TuiConfig.Info
|
||||||
export type Info = TuiConfig.Info
|
export type Info = TuiConfig.Info
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { describe, expect, test } from "bun:test"
|
import { describe, expect, test } from "bun:test"
|
||||||
import type { AudioPlayOptions, AudioSound } from "@opentui/core"
|
import type { AudioPlayOptions, AudioSound } from "@opentui/core"
|
||||||
import { createTuiAttention } from "@opencode-ai/tui/attention"
|
import { createTuiAttention } from "@opencode-ai/tui/attention"
|
||||||
import type { TuiConfig } from "@opencode-ai/tui/config"
|
import type { TuiConfig } from "@opencode-ai/tui/config/v1"
|
||||||
|
|
||||||
type FocusEvent = "focus" | "blur"
|
type FocusEvent = "focus" | "blur"
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { afterEach, describe, expect, mock, spyOn, test } from "bun:test"
|
import { afterEach, describe, expect, mock, spyOn, test } from "bun:test"
|
||||||
import { OpenCode } from "@opencode-ai/client/promise"
|
import { OpenCode } from "@opencode-ai/client/promise"
|
||||||
import type { Resolved } from "@opencode-ai/tui/config"
|
import type { Resolved } from "@opencode-ai/tui/config/v1"
|
||||||
import { resolveDiffStyle, resolveModelInfo, resolveRunTuiConfig } from "@opencode-ai/cli/mini/runtime.boot"
|
import { resolveDiffStyle, resolveModelInfo, resolveRunTuiConfig } from "@opencode-ai/cli/mini/runtime.boot"
|
||||||
import { createTuiResolvedConfig } from "../../fixture/tui-runtime"
|
import { createTuiResolvedConfig } from "../../fixture/tui-runtime"
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import { spyOn } from "bun:test"
|
import { spyOn } from "bun:test"
|
||||||
import path from "path"
|
import path from "path"
|
||||||
import { resolve, type Info, type Resolved } from "@opencode-ai/tui/config"
|
import { resolve, type Info, type Resolved } from "@opencode-ai/tui/config/v1"
|
||||||
import { TuiConfig } from "../../src/config/tui"
|
import { TuiConfig } from "../../src/config/tui"
|
||||||
import { TuiKeybind } from "@opencode-ai/tui/config/keybind"
|
import { TuiKeybind } from "@opencode-ai/tui/config/v1/keybind"
|
||||||
|
|
||||||
type PluginSpec = string | [string, Record<string, unknown>]
|
type PluginSpec = string | [string, Record<string, unknown>]
|
||||||
type PluginOrigin = {
|
type PluginOrigin = {
|
||||||
|
|||||||
@@ -12,7 +12,10 @@
|
|||||||
"exports": {
|
"exports": {
|
||||||
".": "./src/index.tsx",
|
".": "./src/index.tsx",
|
||||||
"./builtins": "./src/feature-plugins/builtins.ts",
|
"./builtins": "./src/feature-plugins/builtins.ts",
|
||||||
"./config": "./src/config/index.tsx",
|
"./config/v1": "./src/config/v1/index.tsx",
|
||||||
|
"./config/v1/keybind": "./src/config/v1/keybind.ts",
|
||||||
|
"./config/v2": "./src/config/v2/index.ts",
|
||||||
|
"./config/v2/keybind": "./src/config/v2/keybind.ts",
|
||||||
"./context/args": "./src/context/args.tsx",
|
"./context/args": "./src/context/args.tsx",
|
||||||
"./context/epilogue": "./src/context/epilogue.tsx",
|
"./context/epilogue": "./src/context/epilogue.tsx",
|
||||||
"./context/exit": "./src/context/exit.tsx",
|
"./context/exit": "./src/context/exit.tsx",
|
||||||
@@ -30,7 +33,6 @@
|
|||||||
"./editor-zed": "./src/editor-zed.ts",
|
"./editor-zed": "./src/editor-zed.ts",
|
||||||
"./runtime": "./src/runtime.tsx",
|
"./runtime": "./src/runtime.tsx",
|
||||||
"./terminal-win32": "./src/terminal-win32.ts",
|
"./terminal-win32": "./src/terminal-win32.ts",
|
||||||
"./config/keybind": "./src/config/keybind.ts",
|
|
||||||
"./keymap": "./src/keymap.tsx",
|
"./keymap": "./src/keymap.tsx",
|
||||||
"./prompt/content": "./src/prompt/content.ts",
|
"./prompt/content": "./src/prompt/content.ts",
|
||||||
"./prompt/display": "./src/prompt/display.ts",
|
"./prompt/display": "./src/prompt/display.ts",
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ import * as Model from "./util/model"
|
|||||||
import { ArgsProvider, useArgs, type Args } from "./context/args"
|
import { ArgsProvider, useArgs, type Args } from "./context/args"
|
||||||
import open from "open"
|
import open from "open"
|
||||||
import { PromptRefProvider, usePromptRef } from "./context/prompt"
|
import { PromptRefProvider, usePromptRef } from "./context/prompt"
|
||||||
import { TuiConfigProvider, useTuiConfig, type TuiConfig } from "./config"
|
import { TuiConfigProvider, useTuiConfig, type TuiConfig } from "./config/v1"
|
||||||
import { createTuiApiAdapters } from "./plugin/adapters"
|
import { createTuiApiAdapters } from "./plugin/adapters"
|
||||||
import { createTuiApi } from "./plugin/api"
|
import { createTuiApi } from "./plugin/api"
|
||||||
import { createPluginRuntime, PluginRuntimeProvider, usePluginRuntime, type TuiPluginHost } from "./plugin/runtime"
|
import { createPluginRuntime, PluginRuntimeProvider, usePluginRuntime, type TuiPluginHost } from "./plugin/runtime"
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import type {
|
|||||||
TuiAttentionSoundPack,
|
TuiAttentionSoundPack,
|
||||||
TuiAttentionSoundPackInfo,
|
TuiAttentionSoundPackInfo,
|
||||||
} from "@opencode-ai/plugin/tui"
|
} from "@opencode-ai/plugin/tui"
|
||||||
import { AttentionSoundName, type TuiConfig } from "./config"
|
import { AttentionSoundName, type TuiConfig } from "./config/v1"
|
||||||
import { Schema } from "effect"
|
import { Schema } from "effect"
|
||||||
import stripAnsi from "strip-ansi"
|
import stripAnsi from "strip-ansi"
|
||||||
import * as TuiAudio from "./audio"
|
import * as TuiAudio from "./audio"
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import {
|
|||||||
useKeymapSelector,
|
useKeymapSelector,
|
||||||
useOpencodeKeymap,
|
useOpencodeKeymap,
|
||||||
} from "../keymap"
|
} from "../keymap"
|
||||||
import { useTuiConfig } from "../config"
|
import { useTuiConfig } from "../config/v1"
|
||||||
|
|
||||||
type PaletteCommandEntry = ReturnType<OpenTuiKeymap["getCommandEntries"]>[number]
|
type PaletteCommandEntry = ReturnType<OpenTuiKeymap["getCommandEntries"]>[number]
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import type { McpServer } from "@opencode-ai/client"
|
|||||||
import { useClipboard } from "../context/clipboard"
|
import { useClipboard } from "../context/clipboard"
|
||||||
import { useToast } from "../ui/toast"
|
import { useToast } from "../ui/toast"
|
||||||
import { useKeyboard, useTerminalDimensions } from "@opentui/solid"
|
import { useKeyboard, useTerminalDimensions } from "@opentui/solid"
|
||||||
import { useTuiConfig } from "../config"
|
import { useTuiConfig } from "../config/v1"
|
||||||
import { getScrollAcceleration } from "../util/scroll"
|
import { getScrollAcceleration } from "../util/scroll"
|
||||||
import { useBindings } from "../keymap"
|
import { useBindings } from "../keymap"
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { InputRenderable, TextAttributes } from "@opentui/core"
|
import { InputRenderable, TextAttributes } from "@opentui/core"
|
||||||
import { Slug } from "@opencode-ai/core/util/slug"
|
import { Slug } from "@opencode-ai/core/util/slug"
|
||||||
import { createSignal, onMount } from "solid-js"
|
import { createSignal, onMount } from "solid-js"
|
||||||
import { useTuiConfig } from "../config"
|
import { useTuiConfig } from "../config/v1"
|
||||||
import { useTheme } from "../context/theme"
|
import { useTheme } from "../context/theme"
|
||||||
import { useBindings, useCommandShortcut } from "../keymap"
|
import { useBindings, useCommandShortcut } from "../keymap"
|
||||||
import { useDialog, type DialogContext } from "../ui/dialog"
|
import { useDialog, type DialogContext } from "../ui/dialog"
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { createMemo, For } from "solid-js"
|
|||||||
import { createStore } from "solid-js/store"
|
import { createStore } from "solid-js/store"
|
||||||
import { FilePath } from "../ui/file-path"
|
import { FilePath } from "../ui/file-path"
|
||||||
import { useTheme } from "../context/theme"
|
import { useTheme } from "../context/theme"
|
||||||
import { useTuiConfig } from "../config"
|
import { useTuiConfig } from "../config/v1"
|
||||||
import { useDialog, type DialogContext } from "../ui/dialog"
|
import { useDialog, type DialogContext } from "../ui/dialog"
|
||||||
import { getScrollAcceleration } from "../util/scroll"
|
import { getScrollAcceleration } from "../util/scroll"
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import { useSDK } from "../../context/sdk"
|
|||||||
import { useData } from "../../context/data"
|
import { useData } from "../../context/data"
|
||||||
import { getScrollAcceleration } from "../../util/scroll"
|
import { getScrollAcceleration } from "../../util/scroll"
|
||||||
import { useTuiPaths } from "../../context/runtime"
|
import { useTuiPaths } from "../../context/runtime"
|
||||||
import { useTuiConfig } from "../../config"
|
import { useTuiConfig } from "../../config/v1"
|
||||||
import { useLocation } from "../../context/location"
|
import { useLocation } from "../../context/location"
|
||||||
import { useTheme, selectedForeground } from "../../context/theme"
|
import { useTheme, selectedForeground } from "../../context/theme"
|
||||||
import { SplitBorder } from "../../ui/border"
|
import { SplitBorder } from "../../ui/border"
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ import { createFadeIn } from "../../util/signal"
|
|||||||
import { DialogSkill } from "../dialog-skill"
|
import { DialogSkill } from "../dialog-skill"
|
||||||
import { useArgs } from "../../context/args"
|
import { useArgs } from "../../context/args"
|
||||||
import { OPENCODE_BASE_MODE, useBindings, useCommandShortcut, useLeaderActive, useOpencodeKeymap } from "../../keymap"
|
import { OPENCODE_BASE_MODE, useBindings, useCommandShortcut, useLeaderActive, useOpencodeKeymap } from "../../keymap"
|
||||||
import { useTuiConfig } from "../../config"
|
import { useTuiConfig } from "../../config/v1"
|
||||||
import { usePromptMove } from "./move"
|
import { usePromptMove } from "./move"
|
||||||
import { readLocalAttachment } from "./local-attachment"
|
import { readLocalAttachment } from "./local-attachment"
|
||||||
import { useData } from "../../context/data"
|
import { useData } from "../../context/data"
|
||||||
|
|||||||
@@ -97,8 +97,6 @@ export const Definitions = {
|
|||||||
session_interrupt: keybind("escape", "Interrupt current session"),
|
session_interrupt: keybind("escape", "Interrupt current session"),
|
||||||
session_background: keybind("ctrl+b", "Background blocking session tools"),
|
session_background: keybind("ctrl+b", "Background blocking session tools"),
|
||||||
session_compact: keybind("<leader>c", "Compact the session"),
|
session_compact: keybind("<leader>c", "Compact the session"),
|
||||||
session_toggle_timestamps: keybind("none", "Toggle message timestamps"),
|
|
||||||
session_toggle_generic_tool_output: keybind("none", "Toggle generic tool output"),
|
|
||||||
session_queued_prompts: keybind("<leader>q", "Manage queued prompts"),
|
session_queued_prompts: keybind("<leader>q", "Manage queued prompts"),
|
||||||
session_child_first: keybind("down,<leader>down", "Toggle subagent picker"),
|
session_child_first: keybind("down,<leader>down", "Toggle subagent picker"),
|
||||||
session_child_cycle: keybind("right", "Go to next child session"),
|
session_child_cycle: keybind("right", "Go to next child session"),
|
||||||
@@ -146,7 +144,6 @@ export const Definitions = {
|
|||||||
messages_undo: keybind("<leader>u", "Undo message"),
|
messages_undo: keybind("<leader>u", "Undo message"),
|
||||||
messages_redo: keybind("<leader>r", "Redo message"),
|
messages_redo: keybind("<leader>r", "Redo message"),
|
||||||
messages_toggle_conceal: keybind("<leader>h", "Toggle code block concealment in messages"),
|
messages_toggle_conceal: keybind("<leader>h", "Toggle code block concealment in messages"),
|
||||||
tool_details: keybind("none", "Toggle tool details visibility"),
|
|
||||||
display_thinking: keybind("none", "Toggle thinking blocks visibility"),
|
display_thinking: keybind("none", "Toggle thinking blocks visibility"),
|
||||||
|
|
||||||
prompt_submit: keybind("none", "Submit prompt"),
|
prompt_submit: keybind("none", "Submit prompt"),
|
||||||
@@ -303,8 +300,6 @@ export const CommandMap = {
|
|||||||
session_interrupt: "session.interrupt",
|
session_interrupt: "session.interrupt",
|
||||||
session_background: "session.background",
|
session_background: "session.background",
|
||||||
session_compact: "session.compact",
|
session_compact: "session.compact",
|
||||||
session_toggle_timestamps: "session.toggle.timestamps",
|
|
||||||
session_toggle_generic_tool_output: "session.toggle.generic_tool_output",
|
|
||||||
session_queued_prompts: "session.queued_prompts",
|
session_queued_prompts: "session.queued_prompts",
|
||||||
session_child_first: "session.child.first",
|
session_child_first: "session.child.first",
|
||||||
session_child_cycle: "session.child.next",
|
session_child_cycle: "session.child.next",
|
||||||
@@ -350,7 +345,6 @@ export const CommandMap = {
|
|||||||
messages_undo: "session.undo",
|
messages_undo: "session.undo",
|
||||||
messages_redo: "session.redo",
|
messages_redo: "session.redo",
|
||||||
messages_toggle_conceal: "session.toggle.conceal",
|
messages_toggle_conceal: "session.toggle.conceal",
|
||||||
tool_details: "session.toggle.actions",
|
|
||||||
display_thinking: "session.toggle.thinking",
|
display_thinking: "session.toggle.thinking",
|
||||||
prompt_submit: "prompt.submit",
|
prompt_submit: "prompt.submit",
|
||||||
prompt_editor_context_clear: "prompt.editor_context.clear",
|
prompt_editor_context_clear: "prompt.editor_context.clear",
|
||||||
@@ -0,0 +1,97 @@
|
|||||||
|
export * as TuiConfigV2 from "."
|
||||||
|
|
||||||
|
import { Schema } from "effect"
|
||||||
|
import { TuiKeybind } from "./keybind"
|
||||||
|
|
||||||
|
export const Plugin = Schema.Union([
|
||||||
|
Schema.String,
|
||||||
|
Schema.Struct({
|
||||||
|
package: Schema.String,
|
||||||
|
options: Schema.optional(Schema.Record(Schema.String, Schema.Any)),
|
||||||
|
}),
|
||||||
|
])
|
||||||
|
|
||||||
|
export const Info = Schema.Struct({
|
||||||
|
theme: Schema.optional(
|
||||||
|
Schema.Struct({
|
||||||
|
name: Schema.optional(Schema.String),
|
||||||
|
mode: Schema.optional(Schema.Literals(["system", "dark", "light"])),
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
keybinds: Schema.optional(TuiKeybind.KeybindOverrides),
|
||||||
|
plugins: Schema.optional(Schema.Array(Plugin)),
|
||||||
|
leader: Schema.optional(
|
||||||
|
Schema.Struct({
|
||||||
|
timeout: Schema.optional(Schema.Int.check(Schema.isGreaterThan(0))),
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
scroll: Schema.optional(
|
||||||
|
Schema.Struct({
|
||||||
|
speed: Schema.optional(Schema.Number.check(Schema.isGreaterThanOrEqualTo(0.001))),
|
||||||
|
acceleration: Schema.optional(Schema.Boolean),
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
attention: Schema.optional(
|
||||||
|
Schema.Struct({
|
||||||
|
enabled: Schema.optional(Schema.Boolean),
|
||||||
|
notifications: Schema.optional(Schema.Boolean),
|
||||||
|
sound: Schema.optional(Schema.Boolean),
|
||||||
|
volume: Schema.optional(Schema.Number.check(Schema.isGreaterThanOrEqualTo(0), Schema.isLessThanOrEqualTo(1))),
|
||||||
|
sound_pack: Schema.optional(Schema.String),
|
||||||
|
sounds: Schema.optional(
|
||||||
|
Schema.Record(
|
||||||
|
Schema.Literals(["default", "question", "permission", "error", "done", "subagent_done"]),
|
||||||
|
Schema.optionalKey(Schema.String),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
diffs: Schema.optional(
|
||||||
|
Schema.Struct({
|
||||||
|
wrap: Schema.optional(Schema.Literals(["word", "none"])),
|
||||||
|
tree: Schema.optional(Schema.Boolean),
|
||||||
|
single: Schema.optional(Schema.Boolean),
|
||||||
|
view: Schema.optional(Schema.Literals(["auto", "split", "unified"])),
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
terminal: Schema.optional(
|
||||||
|
Schema.Struct({
|
||||||
|
title: Schema.optional(Schema.Boolean),
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
composer: Schema.optional(
|
||||||
|
Schema.Struct({
|
||||||
|
file_context: Schema.optional(Schema.Boolean),
|
||||||
|
paste_summary: Schema.optional(Schema.Boolean),
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
session: Schema.optional(
|
||||||
|
Schema.Struct({
|
||||||
|
sidebar: Schema.optional(Schema.Literals(["auto", "hide"])),
|
||||||
|
scrollbar: Schema.optional(Schema.Boolean),
|
||||||
|
thinking: Schema.optional(Schema.Literals(["show", "hide"])),
|
||||||
|
group_exploration: Schema.optional(Schema.Boolean),
|
||||||
|
directory_filter: Schema.optional(Schema.Boolean),
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
which_key: Schema.optional(
|
||||||
|
Schema.Struct({
|
||||||
|
layout: Schema.optional(Schema.Literals(["dock", "overlay"])),
|
||||||
|
pending_preview: Schema.optional(Schema.Boolean),
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
hints: Schema.optional(
|
||||||
|
Schema.Struct({
|
||||||
|
tips: Schema.optional(Schema.Boolean),
|
||||||
|
getting_started: Schema.optional(Schema.Boolean),
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
updates: Schema.optional(
|
||||||
|
Schema.Struct({
|
||||||
|
skipped: Schema.optional(Schema.String),
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
animations: Schema.optional(Schema.Boolean),
|
||||||
|
mouse: Schema.optional(Schema.Boolean),
|
||||||
|
})
|
||||||
|
export type Info = Schema.Schema.Type<typeof Info>
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
export * as TuiKeybind from "./keybind"
|
||||||
|
|
||||||
|
import { Schema } from "effect"
|
||||||
|
|
||||||
|
export const KeybindOverrides = Schema.Struct({})
|
||||||
|
export type KeybindOverrides = Schema.Schema.Type<typeof KeybindOverrides>
|
||||||
@@ -23,7 +23,7 @@ import { createEffect, createMemo, onCleanup, onMount } from "solid-js"
|
|||||||
import { createStore, produce } from "solid-js/store"
|
import { createStore, produce } from "solid-js/store"
|
||||||
import { createSimpleContext } from "./helper"
|
import { createSimpleContext } from "./helper"
|
||||||
import { useKV } from "./kv"
|
import { useKV } from "./kv"
|
||||||
import { useTuiConfig } from "../config"
|
import { useTuiConfig } from "../config/v1"
|
||||||
import { Global } from "@opencode-ai/core/global"
|
import { Global } from "@opencode-ai/core/global"
|
||||||
import { Glob } from "@opencode-ai/core/util/glob"
|
import { Glob } from "@opencode-ai/core/util/glob"
|
||||||
import { readFile } from "node:fs/promises"
|
import { readFile } from "node:fs/promises"
|
||||||
|
|||||||
@@ -14,8 +14,8 @@ import {
|
|||||||
} from "@opentui/keymap/extras"
|
} from "@opentui/keymap/extras"
|
||||||
import { KeymapProvider, useKeymap, useKeymapSelector, useBindings } from "@opentui/keymap/solid"
|
import { KeymapProvider, useKeymap, useKeymapSelector, useBindings } from "@opentui/keymap/solid"
|
||||||
import { createMemo, type Accessor } from "solid-js"
|
import { createMemo, type Accessor } from "solid-js"
|
||||||
import { useTuiConfig } from "./config"
|
import { useTuiConfig } from "./config/v1"
|
||||||
import { TuiKeybind } from "./config/keybind"
|
import { TuiKeybind } from "./config/v1/keybind"
|
||||||
|
|
||||||
export const LEADER_TOKEN = "leader"
|
export const LEADER_TOKEN = "leader"
|
||||||
export const OPENCODE_BASE_MODE = "base"
|
export const OPENCODE_BASE_MODE = "base"
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import type { TuiDialogSelectOption, TuiPluginApi, TuiSlotProps } from "@opencode-ai/plugin/tui"
|
import type { TuiDialogSelectOption, TuiPluginApi, TuiSlotProps } from "@opencode-ai/plugin/tui"
|
||||||
import type { TuiConfig } from "../config"
|
import type { TuiConfig } from "../config/v1"
|
||||||
import type { useEvent } from "../context/event"
|
import type { useEvent } from "../context/event"
|
||||||
import type { useRoute } from "../context/route"
|
import type { useRoute } from "../context/route"
|
||||||
import type { useSDK } from "../context/sdk"
|
import type { useSDK } from "../context/sdk"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// Legacy `api.command` bridge for v1 plugins; remove in v2.
|
// Legacy `api.command` bridge for v1 plugins; remove in v2.
|
||||||
import type { TuiCommand, TuiPluginApi } from "@opencode-ai/plugin/tui"
|
import type { TuiCommand, TuiPluginApi } from "@opencode-ai/plugin/tui"
|
||||||
import { TuiKeybind } from "../config/keybind"
|
import { TuiKeybind } from "../config/v1/keybind"
|
||||||
import type { DialogContext } from "../ui/dialog"
|
import type { DialogContext } from "../ui/dialog"
|
||||||
|
|
||||||
const COMMAND_PALETTE_SHOW = "command.palette.show"
|
const COMMAND_PALETTE_SHOW = "command.palette.show"
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import type {
|
|||||||
TuiPluginInstallResult,
|
TuiPluginInstallResult,
|
||||||
TuiPluginStatus,
|
TuiPluginStatus,
|
||||||
} from "@opencode-ai/plugin/tui"
|
} from "@opencode-ai/plugin/tui"
|
||||||
import type { TuiConfig } from "../config"
|
import type { TuiConfig } from "../config/v1"
|
||||||
import { createContext, createSignal, useContext, type JSX, type ParentProps } from "solid-js"
|
import { createContext, createSignal, useContext, type JSX, type ParentProps } from "solid-js"
|
||||||
import { createPluginRoutes } from "./api"
|
import { createPluginRoutes } from "./api"
|
||||||
import { createSlots, type HostSlots } from "./slots"
|
import { createSlots, type HostSlots } from "./slots"
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import { useLocal } from "../context/local"
|
|||||||
import { usePluginRuntime } from "../plugin/runtime"
|
import { usePluginRuntime } from "../plugin/runtime"
|
||||||
import { useEditorContext } from "../context/editor"
|
import { useEditorContext } from "../context/editor"
|
||||||
import { useTerminalDimensions } from "@opentui/solid"
|
import { useTerminalDimensions } from "@opentui/solid"
|
||||||
import { useTuiConfig } from "../config"
|
import { useTuiConfig } from "../config/v1"
|
||||||
import { HomeSessionDestinationProvider } from "./home/session-destination"
|
import { HomeSessionDestinationProvider } from "./home/session-destination"
|
||||||
import { useData } from "../context/data"
|
import { useData } from "../context/data"
|
||||||
import { LocationProvider } from "../context/location"
|
import { LocationProvider } from "../context/location"
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import { useSDK } from "../../context/sdk"
|
|||||||
import { useClipboard } from "../../context/clipboard"
|
import { useClipboard } from "../../context/clipboard"
|
||||||
import { SplitBorder } from "../../ui/border"
|
import { SplitBorder } from "../../ui/border"
|
||||||
import { useToast } from "../../ui/toast"
|
import { useToast } from "../../ui/toast"
|
||||||
import { useTuiConfig } from "../../config"
|
import { useTuiConfig } from "../../config/v1"
|
||||||
import { useBindings, useOpencodeModeStack } from "../../keymap"
|
import { useBindings, useOpencodeModeStack } from "../../keymap"
|
||||||
|
|
||||||
const FORM_MODE = "form"
|
const FORM_MODE = "form"
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ import { FormPrompt } from "./form"
|
|||||||
import { DialogExportOptions } from "../../ui/dialog-export-options"
|
import { DialogExportOptions } from "../../ui/dialog-export-options"
|
||||||
import { DialogExportResult } from "../../ui/dialog-export-result"
|
import { DialogExportResult } from "../../ui/dialog-export-result"
|
||||||
import { sessionEpilogue } from "../../util/presentation"
|
import { sessionEpilogue } from "../../util/presentation"
|
||||||
import { useTuiConfig } from "../../config"
|
import { useTuiConfig } from "../../config/v1"
|
||||||
import { useClipboard } from "../../context/clipboard"
|
import { useClipboard } from "../../context/clipboard"
|
||||||
import { nextThinkingMode, reasoningSummary, useThinkingMode, type ThinkingMode } from "../../context/thinking"
|
import { nextThinkingMode, reasoningSummary, useThinkingMode, type ThinkingMode } from "../../context/thinking"
|
||||||
import { getScrollAcceleration } from "../../util/scroll"
|
import { getScrollAcceleration } from "../../util/scroll"
|
||||||
@@ -89,11 +89,8 @@ const sessionBindingCommands = [
|
|||||||
"session.redo",
|
"session.redo",
|
||||||
"session.sidebar.toggle",
|
"session.sidebar.toggle",
|
||||||
"session.toggle.conceal",
|
"session.toggle.conceal",
|
||||||
"session.toggle.timestamps",
|
|
||||||
"session.toggle.thinking",
|
"session.toggle.thinking",
|
||||||
"session.toggle.actions",
|
|
||||||
"session.toggle.scrollbar",
|
"session.toggle.scrollbar",
|
||||||
"session.toggle.generic_tool_output",
|
|
||||||
"session.toggle.exploration_grouping",
|
"session.toggle.exploration_grouping",
|
||||||
"session.first",
|
"session.first",
|
||||||
"session.last",
|
"session.last",
|
||||||
@@ -127,9 +124,6 @@ const context = createContext<{
|
|||||||
conceal: () => boolean
|
conceal: () => boolean
|
||||||
thinkingMode: () => ThinkingMode
|
thinkingMode: () => ThinkingMode
|
||||||
showThinking: () => boolean
|
showThinking: () => boolean
|
||||||
showTimestamps: () => boolean
|
|
||||||
showDetails: () => boolean
|
|
||||||
showGenericToolOutput: () => boolean
|
|
||||||
groupExploration: () => boolean
|
groupExploration: () => boolean
|
||||||
diffWrapMode: () => "word" | "none"
|
diffWrapMode: () => "word" | "none"
|
||||||
models: () => ModelInfo[]
|
models: () => ModelInfo[]
|
||||||
@@ -208,13 +202,9 @@ export function Session() {
|
|||||||
const thinking = useThinkingMode()
|
const thinking = useThinkingMode()
|
||||||
const thinkingMode = thinking.mode
|
const thinkingMode = thinking.mode
|
||||||
const showThinking = createMemo(() => true)
|
const showThinking = createMemo(() => true)
|
||||||
const [timestamps, setTimestamps] = kv.signal<"hide" | "show">("timestamps", "hide")
|
|
||||||
const [showDetails, setShowDetails] = kv.signal("tool_details_visibility", true)
|
|
||||||
const [showAssistantMetadata, _setShowAssistantMetadata] = kv.signal("assistant_metadata_visibility", true)
|
|
||||||
const [showScrollbar, setShowScrollbar] = kv.signal("scrollbar_visible", false)
|
const [showScrollbar, setShowScrollbar] = kv.signal("scrollbar_visible", false)
|
||||||
const [diffWrapMode] = kv.signal<"word" | "none">("diff_wrap_mode", "word")
|
const [diffWrapMode] = kv.signal<"word" | "none">("diff_wrap_mode", "word")
|
||||||
const [_animationsEnabled, _setAnimationsEnabled] = kv.signal("animations_enabled", true)
|
const [_animationsEnabled, _setAnimationsEnabled] = kv.signal("animations_enabled", true)
|
||||||
const [showGenericToolOutput, setShowGenericToolOutput] = kv.signal("generic_tool_output_visibility", false)
|
|
||||||
const [groupExploration, setGroupExploration] = kv.signal("exploration_grouping", true)
|
const [groupExploration, setGroupExploration] = kv.signal("exploration_grouping", true)
|
||||||
|
|
||||||
const wide = createMemo(() => dimensions().width > 120)
|
const wide = createMemo(() => dimensions().width > 120)
|
||||||
@@ -224,7 +214,6 @@ export function Session() {
|
|||||||
if (sidebar() === "auto" && wide()) return true
|
if (sidebar() === "auto" && wide()) return true
|
||||||
return false
|
return false
|
||||||
})
|
})
|
||||||
const showTimestamps = createMemo(() => timestamps() === "show")
|
|
||||||
const contentWidth = createMemo(() => dimensions().width - (sidebarVisible() ? 42 : 0) - 4)
|
const contentWidth = createMemo(() => dimensions().width - (sidebarVisible() ? 42 : 0) - 4)
|
||||||
const models = createMemo(() => data.location.model.list(location()) ?? [])
|
const models = createMemo(() => data.location.model.list(location()) ?? [])
|
||||||
|
|
||||||
@@ -491,19 +480,6 @@ export function Session() {
|
|||||||
dialog.clear()
|
dialog.clear()
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
title: showTimestamps() ? "Hide timestamps" : "Show timestamps",
|
|
||||||
value: "session.toggle.timestamps",
|
|
||||||
category: "Session",
|
|
||||||
slash: {
|
|
||||||
name: "timestamps",
|
|
||||||
aliases: ["toggle-timestamps"],
|
|
||||||
},
|
|
||||||
run: () => {
|
|
||||||
setTimestamps((prev) => (prev === "show" ? "hide" : "show"))
|
|
||||||
dialog.clear()
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
title: (() => {
|
title: (() => {
|
||||||
const next = nextThinkingMode(thinkingMode())
|
const next = nextThinkingMode(thinkingMode())
|
||||||
@@ -521,15 +497,6 @@ export function Session() {
|
|||||||
dialog.clear()
|
dialog.clear()
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
title: showDetails() ? "Hide tool details" : "Show tool details",
|
|
||||||
value: "session.toggle.actions",
|
|
||||||
category: "Session",
|
|
||||||
run: () => {
|
|
||||||
setShowDetails((prev) => !prev)
|
|
||||||
dialog.clear()
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
title: "Toggle session scrollbar",
|
title: "Toggle session scrollbar",
|
||||||
value: "session.toggle.scrollbar",
|
value: "session.toggle.scrollbar",
|
||||||
@@ -539,15 +506,6 @@ export function Session() {
|
|||||||
dialog.clear()
|
dialog.clear()
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
title: showGenericToolOutput() ? "Hide generic tool output" : "Show generic tool output",
|
|
||||||
value: "session.toggle.generic_tool_output",
|
|
||||||
category: "Session",
|
|
||||||
run: () => {
|
|
||||||
setShowGenericToolOutput((prev) => !prev)
|
|
||||||
dialog.clear()
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
title: groupExploration() ? "Show exploration tools individually" : "Group exploration tools",
|
title: groupExploration() ? "Show exploration tools individually" : "Group exploration tools",
|
||||||
value: "session.toggle.exploration_grouping",
|
value: "session.toggle.exploration_grouping",
|
||||||
@@ -727,13 +685,7 @@ export function Session() {
|
|||||||
try {
|
try {
|
||||||
const sessionData = session()
|
const sessionData = session()
|
||||||
if (!sessionData) return
|
if (!sessionData) return
|
||||||
const transcript = formatSessionTranscript(
|
const transcript = formatSessionTranscript(sessionData, messages(), showThinking())
|
||||||
sessionData,
|
|
||||||
messages(),
|
|
||||||
showThinking(),
|
|
||||||
showDetails(),
|
|
||||||
showAssistantMetadata(),
|
|
||||||
)
|
|
||||||
await clipboard.write?.(transcript)
|
await clipboard.write?.(transcript)
|
||||||
toast.show({ message: "Session transcript copied to clipboard!", variant: "success" })
|
toast.show({ message: "Session transcript copied to clipboard!", variant: "success" })
|
||||||
} catch {
|
} catch {
|
||||||
@@ -754,19 +706,13 @@ export function Session() {
|
|||||||
const sessionData = session()
|
const sessionData = session()
|
||||||
if (!sessionData) return
|
if (!sessionData) return
|
||||||
|
|
||||||
const options = await DialogExportOptions.show(dialog, showThinking(), showDetails(), showAssistantMetadata())
|
const options = await DialogExportOptions.show(dialog, showThinking())
|
||||||
|
|
||||||
if (options === null) return
|
if (options === null) return
|
||||||
|
|
||||||
const content =
|
const content =
|
||||||
options.format === "markdown"
|
options.format === "markdown"
|
||||||
? formatSessionTranscript(
|
? formatSessionTranscript(sessionData, messages(), options.thinking)
|
||||||
sessionData,
|
|
||||||
messages(),
|
|
||||||
options.thinking,
|
|
||||||
options.toolDetails,
|
|
||||||
options.assistantMetadata,
|
|
||||||
)
|
|
||||||
: await (async () => {
|
: await (async () => {
|
||||||
if (options.debug) {
|
if (options.debug) {
|
||||||
const events: { readonly created: number }[] = []
|
const events: { readonly created: number }[] = []
|
||||||
@@ -922,9 +868,6 @@ export function Session() {
|
|||||||
conceal,
|
conceal,
|
||||||
thinkingMode,
|
thinkingMode,
|
||||||
showThinking,
|
showThinking,
|
||||||
showTimestamps,
|
|
||||||
showDetails,
|
|
||||||
showGenericToolOutput,
|
|
||||||
groupExploration,
|
groupExploration,
|
||||||
diffWrapMode,
|
diffWrapMode,
|
||||||
models,
|
models,
|
||||||
@@ -1534,13 +1477,7 @@ function UserMessage(props: { message: SessionMessageUser }) {
|
|||||||
>
|
>
|
||||||
<text fg={theme.text}>{props.message.text}</text>
|
<text fg={theme.text}>{props.message.text}</text>
|
||||||
<Show when={files().length}>
|
<Show when={files().length}>
|
||||||
<box
|
<box flexDirection="row" paddingTop={1} gap={1} flexWrap="wrap">
|
||||||
flexDirection="row"
|
|
||||||
paddingBottom={ctx.showTimestamps() ? 1 : 0}
|
|
||||||
paddingTop={1}
|
|
||||||
gap={1}
|
|
||||||
flexWrap="wrap"
|
|
||||||
>
|
|
||||||
<For each={files()}>
|
<For each={files()}>
|
||||||
{(file) => {
|
{(file) => {
|
||||||
const label = file.mime === "application/x-directory" ? "dir" : "file"
|
const label = file.mime === "application/x-directory" ? "dir" : "file"
|
||||||
@@ -1557,11 +1494,6 @@ function UserMessage(props: { message: SessionMessageUser }) {
|
|||||||
</For>
|
</For>
|
||||||
</box>
|
</box>
|
||||||
</Show>
|
</Show>
|
||||||
<Show when={ctx.showTimestamps()}>
|
|
||||||
<text fg={theme.textMuted}>
|
|
||||||
<span style={{ fg: theme.textMuted }}>{Locale.todayTimeOrDateTime(props.message.time.created)}</span>
|
|
||||||
</text>
|
|
||||||
</Show>
|
|
||||||
</box>
|
</box>
|
||||||
</box>
|
</box>
|
||||||
</Show>
|
</Show>
|
||||||
@@ -1865,31 +1797,7 @@ function TextPart(props: { last: boolean; part: SessionMessageAssistantText }) {
|
|||||||
// Pending messages moved to individual tool pending functions
|
// Pending messages moved to individual tool pending functions
|
||||||
|
|
||||||
function ToolPart(props: { part: SessionMessageAssistantTool }) {
|
function ToolPart(props: { part: SessionMessageAssistantTool }) {
|
||||||
const ctx = use()
|
|
||||||
const data = useData()
|
|
||||||
const display = createMemo(() => toolDisplay(props.part.name))
|
const display = createMemo(() => toolDisplay(props.part.name))
|
||||||
const activeBackgroundWork = createMemo(() => {
|
|
||||||
if (props.part.state.status === "streaming") return false
|
|
||||||
if (display() === "shell") {
|
|
||||||
const shellID = stringValue(props.part.state.structured.shellID)
|
|
||||||
return Boolean(shellID && data.shell.get(shellID))
|
|
||||||
}
|
|
||||||
if (display() === "subagent") {
|
|
||||||
const sessionID =
|
|
||||||
stringValue(props.part.state.structured.sessionID) ?? stringValue(props.part.state.structured.sessionId)
|
|
||||||
return Boolean(sessionID && data.session.status(sessionID) === "running")
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
})
|
|
||||||
|
|
||||||
// Hide tool if showDetails is false and tool completed successfully
|
|
||||||
const shouldHide = createMemo(() => {
|
|
||||||
if (ctx.showDetails()) return false
|
|
||||||
if (activeBackgroundWork()) return false
|
|
||||||
if (props.part.state.status !== "completed") return false
|
|
||||||
if (display() === "shell") return false
|
|
||||||
return true
|
|
||||||
})
|
|
||||||
|
|
||||||
const toolprops = {
|
const toolprops = {
|
||||||
get metadata() {
|
get metadata() {
|
||||||
@@ -1913,52 +1821,50 @@ function ToolPart(props: { part: SessionMessageAssistantTool }) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Show when={!shouldHide()}>
|
<Switch>
|
||||||
<Switch>
|
<Match when={display() === "shell"}>
|
||||||
<Match when={display() === "shell"}>
|
<Shell {...toolprops} />
|
||||||
<Shell {...toolprops} />
|
</Match>
|
||||||
</Match>
|
<Match when={display() === "glob"}>
|
||||||
<Match when={display() === "glob"}>
|
<Glob {...toolprops} />
|
||||||
<Glob {...toolprops} />
|
</Match>
|
||||||
</Match>
|
<Match when={display() === "read"}>
|
||||||
<Match when={display() === "read"}>
|
<Read {...toolprops} />
|
||||||
<Read {...toolprops} />
|
</Match>
|
||||||
</Match>
|
<Match when={display() === "grep"}>
|
||||||
<Match when={display() === "grep"}>
|
<Grep {...toolprops} />
|
||||||
<Grep {...toolprops} />
|
</Match>
|
||||||
</Match>
|
<Match when={display() === "webfetch"}>
|
||||||
<Match when={display() === "webfetch"}>
|
<WebFetch {...toolprops} />
|
||||||
<WebFetch {...toolprops} />
|
</Match>
|
||||||
</Match>
|
<Match when={display() === "websearch"}>
|
||||||
<Match when={display() === "websearch"}>
|
<WebSearch {...toolprops} />
|
||||||
<WebSearch {...toolprops} />
|
</Match>
|
||||||
</Match>
|
<Match when={display() === "write"}>
|
||||||
<Match when={display() === "write"}>
|
<Write {...toolprops} />
|
||||||
<Write {...toolprops} />
|
</Match>
|
||||||
</Match>
|
<Match when={display() === "edit"}>
|
||||||
<Match when={display() === "edit"}>
|
<Edit {...toolprops} />
|
||||||
<Edit {...toolprops} />
|
</Match>
|
||||||
</Match>
|
<Match when={display() === "subagent"}>
|
||||||
<Match when={display() === "subagent"}>
|
<Subagent {...toolprops} />
|
||||||
<Subagent {...toolprops} />
|
</Match>
|
||||||
</Match>
|
<Match when={display() === "execute"}>
|
||||||
<Match when={display() === "execute"}>
|
<Execute {...toolprops} />
|
||||||
<Execute {...toolprops} />
|
</Match>
|
||||||
</Match>
|
<Match when={display() === "patch"}>
|
||||||
<Match when={display() === "patch"}>
|
<ApplyPatch {...toolprops} />
|
||||||
<ApplyPatch {...toolprops} />
|
</Match>
|
||||||
</Match>
|
<Match when={display() === "question"}>
|
||||||
<Match when={display() === "question"}>
|
<Question {...toolprops} />
|
||||||
<Question {...toolprops} />
|
</Match>
|
||||||
</Match>
|
<Match when={display() === "skill"}>
|
||||||
<Match when={display() === "skill"}>
|
<Skill {...toolprops} />
|
||||||
<Skill {...toolprops} />
|
</Match>
|
||||||
</Match>
|
<Match when={true}>
|
||||||
<Match when={true}>
|
<GenericTool {...toolprops} />
|
||||||
<GenericTool {...toolprops} />
|
</Match>
|
||||||
</Match>
|
</Switch>
|
||||||
</Switch>
|
|
||||||
</Show>
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1970,40 +1876,55 @@ type ToolProps = {
|
|||||||
part: SessionMessageAssistantTool
|
part: SessionMessageAssistantTool
|
||||||
}
|
}
|
||||||
function GenericTool(props: ToolProps) {
|
function GenericTool(props: ToolProps) {
|
||||||
const { theme } = useTheme()
|
const { theme, syntax } = useTheme()
|
||||||
const ctx = use()
|
|
||||||
const output = createMemo(() => props.output?.trim() ?? "")
|
const output = createMemo(() => props.output?.trim() ?? "")
|
||||||
|
const args = createMemo(() => JSON.stringify(props.input, null, 2))
|
||||||
const [expanded, setExpanded] = createSignal(false)
|
const [expanded, setExpanded] = createSignal(false)
|
||||||
const maxLines = 3
|
const expandable = createMemo(() => Object.keys(props.input).length > 0 || output().length > 0)
|
||||||
const maxChars = createMemo(() => maxLines * Math.max(20, ctx.width - 6))
|
|
||||||
const collapsed = createMemo(() => collapseToolOutput(output(), maxLines, maxChars()))
|
|
||||||
const limited = createMemo(() => {
|
|
||||||
if (expanded() || !collapsed().overflow) return output()
|
|
||||||
return collapsed().output
|
|
||||||
})
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Show
|
<BlockTool
|
||||||
when={props.output && ctx.showGenericToolOutput()}
|
title={`◆ ${props.tool}`}
|
||||||
fallback={
|
part={props.part}
|
||||||
<InlineTool icon="⚙" pending="Writing command..." complete={true} part={props.part}>
|
spinner={props.part.state.status === "streaming" || props.part.state.status === "running"}
|
||||||
{props.tool} {input(props.input)}
|
onClick={expandable() ? () => setExpanded((value) => !value) : undefined}
|
||||||
</InlineTool>
|
|
||||||
}
|
|
||||||
>
|
>
|
||||||
<BlockTool
|
<Show when={expanded()}>
|
||||||
title={`# ${props.tool} ${input(props.input)}`}
|
<box gap={1} paddingTop={1}>
|
||||||
part={props.part}
|
<Show when={Object.keys(props.input).length > 0}>
|
||||||
onClick={collapsed().overflow ? () => setExpanded((prev) => !prev) : undefined}
|
<box gap={1}>
|
||||||
>
|
<text>
|
||||||
<box gap={1}>
|
<span style={{ bg: theme.backgroundElement, fg: theme.textMuted }}> Input </span>
|
||||||
<text fg={theme.text}>{limited()}</text>
|
</text>
|
||||||
<Show when={collapsed().overflow}>
|
<box paddingLeft={1}>
|
||||||
<text fg={theme.textMuted}>{expanded() ? "Click to collapse" : "Click to expand"}</text>
|
<code
|
||||||
|
content={args()}
|
||||||
|
filetype="json"
|
||||||
|
syntaxStyle={syntax()}
|
||||||
|
conceal={false}
|
||||||
|
drawUnstyledText={false}
|
||||||
|
fg={theme.text}
|
||||||
|
/>
|
||||||
|
</box>
|
||||||
|
</box>
|
||||||
|
</Show>
|
||||||
|
<Show when={output()}>
|
||||||
|
{(value) => (
|
||||||
|
<box gap={1}>
|
||||||
|
<text>
|
||||||
|
<span style={{ bg: theme.backgroundElement, fg: theme.textMuted }}> Output </span>
|
||||||
|
</text>
|
||||||
|
<box paddingLeft={1}>
|
||||||
|
<text fg={theme.text} wrapMode="word">
|
||||||
|
{value()}
|
||||||
|
</text>
|
||||||
|
</box>
|
||||||
|
</box>
|
||||||
|
)}
|
||||||
</Show>
|
</Show>
|
||||||
</box>
|
</box>
|
||||||
</BlockTool>
|
</Show>
|
||||||
</Show>
|
</BlockTool>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2106,12 +2027,7 @@ export function InlineToolRow(props: {
|
|||||||
<Spinner color={props.color} children={props.children} />
|
<Spinner color={props.color} children={props.children} />
|
||||||
</Match>
|
</Match>
|
||||||
<Match when={true}>
|
<Match when={true}>
|
||||||
<Show
|
<Show fallback={<Spinner color={props.color}>{props.pending}</Spinner>} when={props.complete || props.failed}>
|
||||||
fallback={
|
|
||||||
<Spinner color={props.color}>{props.pending}</Spinner>
|
|
||||||
}
|
|
||||||
when={props.complete || props.failed}
|
|
||||||
>
|
|
||||||
<box flexDirection="row">
|
<box flexDirection="row">
|
||||||
<text
|
<text
|
||||||
width={INLINE_TOOL_ICON_WIDTH}
|
width={INLINE_TOOL_ICON_WIDTH}
|
||||||
@@ -2183,11 +2099,7 @@ function BlockTool(props: {
|
|||||||
{(title) => (
|
{(title) => (
|
||||||
<Show
|
<Show
|
||||||
when={props.spinner}
|
when={props.spinner}
|
||||||
fallback={
|
fallback={<text fg={permission() ? theme.warning : theme.textMuted}>{title()}</text>}
|
||||||
<text fg={permission() ? theme.warning : theme.textMuted}>
|
|
||||||
{title()}
|
|
||||||
</text>
|
|
||||||
}
|
|
||||||
>
|
>
|
||||||
<Spinner color={permission() ? theme.warning : theme.textMuted}>{title().replace(/^# /, "")}</Spinner>
|
<Spinner color={permission() ? theme.warning : theme.textMuted}>{title().replace(/^# /, "")}</Spinner>
|
||||||
</Show>
|
</Show>
|
||||||
@@ -2676,11 +2588,7 @@ function ApplyPatch(props: ToolProps) {
|
|||||||
: undefined
|
: undefined
|
||||||
}
|
}
|
||||||
title={
|
title={
|
||||||
targets().length === 1
|
targets().length === 1 ? undefined : props.part.state.status === "error" ? "# Patch failed" : "Patching"
|
||||||
? undefined
|
|
||||||
: props.part.state.status === "error"
|
|
||||||
? "# Patch failed"
|
|
||||||
: "Patching"
|
|
||||||
}
|
}
|
||||||
part={props.part}
|
part={props.part}
|
||||||
spinner={props.part.state.status === "streaming" || props.part.state.status === "running"}
|
spinner={props.part.state.status === "streaming" || props.part.state.status === "running"}
|
||||||
@@ -2806,13 +2714,7 @@ function recordValue(value: unknown): Record<string, unknown> | undefined {
|
|||||||
return value as Record<string, unknown>
|
return value as Record<string, unknown>
|
||||||
}
|
}
|
||||||
|
|
||||||
function formatSessionTranscript(
|
function formatSessionTranscript(session: SessionInfo, messages: SessionMessageInfo[], thinking: boolean) {
|
||||||
session: SessionInfo,
|
|
||||||
messages: SessionMessageInfo[],
|
|
||||||
thinking: boolean,
|
|
||||||
toolDetails: boolean,
|
|
||||||
assistantMetadata: boolean,
|
|
||||||
) {
|
|
||||||
const body = messages.flatMap((message) => {
|
const body = messages.flatMap((message) => {
|
||||||
if (message.type === "user") return [`## User\n\n${message.text}`]
|
if (message.type === "user") return [`## User\n\n${message.text}`]
|
||||||
if (message.type === "shell")
|
if (message.type === "shell")
|
||||||
@@ -2821,7 +2723,6 @@ function formatSessionTranscript(
|
|||||||
const content = message.content.flatMap((item) => {
|
const content = message.content.flatMap((item) => {
|
||||||
if (item.type === "text") return [item.text]
|
if (item.type === "text") return [item.text]
|
||||||
if (item.type === "reasoning") return thinking ? [`_Thinking:_\n\n${item.text}`] : []
|
if (item.type === "reasoning") return thinking ? [`_Thinking:_\n\n${item.text}`] : []
|
||||||
if (!toolDetails) return [`**Tool: ${item.name}**`]
|
|
||||||
const input = typeof item.state.input === "string" ? item.state.input : JSON.stringify(item.state.input, null, 2)
|
const input = typeof item.state.input === "string" ? item.state.input : JSON.stringify(item.state.input, null, 2)
|
||||||
const output =
|
const output =
|
||||||
item.state.status === "error"
|
item.state.status === "error"
|
||||||
@@ -2833,13 +2734,7 @@ function formatSessionTranscript(
|
|||||||
.join("\n")
|
.join("\n")
|
||||||
return [`**Tool: ${item.name}**\n\n**Input:**\n\`\`\`json\n${input}\n\`\`\`\n\n${output}`]
|
return [`**Tool: ${item.name}**\n\n**Input:**\n\`\`\`json\n${input}\n\`\`\`\n\n${output}`]
|
||||||
})
|
})
|
||||||
const duration = message.time.completed
|
return [`## Assistant\n\n${content.join("\n\n")}`]
|
||||||
? ` · ${((message.time.completed - message.time.created) / 1000).toFixed(1)}s`
|
|
||||||
: ""
|
|
||||||
const heading = assistantMetadata
|
|
||||||
? `## Assistant (${message.agent} · ${message.model.providerID}/${message.model.id}${duration})`
|
|
||||||
: "## Assistant"
|
|
||||||
return [`${heading}\n\n${content.join("\n\n")}`]
|
|
||||||
})
|
})
|
||||||
return `# ${session.title}\n\n**Session ID:** ${session.id}\n**Created:** ${new Date(session.time.created).toLocaleString()}\n**Updated:** ${new Date(session.time.updated).toLocaleString()}\n\n---\n\n${body.join("\n\n---\n\n")}\n`
|
return `# ${session.title}\n\n**Session ID:** ${session.id}\n**Created:** ${new Date(session.time.created).toLocaleString()}\n**Updated:** ${new Date(session.time.updated).toLocaleString()}\n\n---\n\n${body.join("\n\n---\n\n")}\n`
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import { filetype } from "../../util/filetype"
|
|||||||
import { Locale } from "../../util/locale"
|
import { Locale } from "../../util/locale"
|
||||||
import { webSearchProviderLabel } from "../../util/tool-display"
|
import { webSearchProviderLabel } from "../../util/tool-display"
|
||||||
import { getScrollAcceleration } from "../../util/scroll"
|
import { getScrollAcceleration } from "../../util/scroll"
|
||||||
import { useTuiConfig } from "../../config"
|
import { useTuiConfig } from "../../config/v1"
|
||||||
import { OPENCODE_BASE_MODE, useBindings, useCommandShortcut } from "../../keymap"
|
import { OPENCODE_BASE_MODE, useBindings, useCommandShortcut } from "../../keymap"
|
||||||
import { usePathFormatter } from "../../context/path-format"
|
import { usePathFormatter } from "../../context/path-format"
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { useData } from "../../context/data"
|
import { useData } from "../../context/data"
|
||||||
import { createMemo, Show } from "solid-js"
|
import { createMemo, Show } from "solid-js"
|
||||||
import { useTheme } from "../../context/theme"
|
import { useTheme } from "../../context/theme"
|
||||||
import { useTuiConfig } from "../../config"
|
import { useTuiConfig } from "../../config/v1"
|
||||||
import { InstallationVersion } from "@opencode-ai/core/installation/version"
|
import { InstallationVersion } from "@opencode-ai/core/installation/version"
|
||||||
import { usePluginRuntime } from "../../plugin/runtime"
|
import { usePluginRuntime } from "../../plugin/runtime"
|
||||||
|
|
||||||
|
|||||||
@@ -9,20 +9,11 @@ export type ExportFormat = "markdown" | "json"
|
|||||||
|
|
||||||
export type DialogExportOptionsProps = {
|
export type DialogExportOptionsProps = {
|
||||||
defaultThinking: boolean
|
defaultThinking: boolean
|
||||||
defaultToolDetails: boolean
|
onConfirm?: (options: { action: "copy" | "export"; format: ExportFormat; debug: boolean; thinking: boolean }) => void
|
||||||
defaultAssistantMetadata: boolean
|
|
||||||
onConfirm?: (options: {
|
|
||||||
action: "copy" | "export"
|
|
||||||
format: ExportFormat
|
|
||||||
debug: boolean
|
|
||||||
thinking: boolean
|
|
||||||
toolDetails: boolean
|
|
||||||
assistantMetadata: boolean
|
|
||||||
}) => void
|
|
||||||
onCancel?: () => void
|
onCancel?: () => void
|
||||||
}
|
}
|
||||||
|
|
||||||
type Active = ExportFormat | "debug" | "thinking" | "toolDetails" | "assistantMetadata" | "copy" | "export"
|
type Active = ExportFormat | "debug" | "thinking" | "copy" | "export"
|
||||||
|
|
||||||
export function DialogExportOptions(props: DialogExportOptionsProps) {
|
export function DialogExportOptions(props: DialogExportOptionsProps) {
|
||||||
const dialog = useDialog()
|
const dialog = useDialog()
|
||||||
@@ -31,8 +22,6 @@ export function DialogExportOptions(props: DialogExportOptionsProps) {
|
|||||||
format: "markdown" as ExportFormat,
|
format: "markdown" as ExportFormat,
|
||||||
debug: false,
|
debug: false,
|
||||||
thinking: props.defaultThinking,
|
thinking: props.defaultThinking,
|
||||||
toolDetails: props.defaultToolDetails,
|
|
||||||
assistantMetadata: props.defaultAssistantMetadata,
|
|
||||||
active: "markdown" as Active,
|
active: "markdown" as Active,
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -42,8 +31,6 @@ export function DialogExportOptions(props: DialogExportOptionsProps) {
|
|||||||
format: store.format,
|
format: store.format,
|
||||||
debug: store.debug,
|
debug: store.debug,
|
||||||
thinking: store.thinking,
|
thinking: store.thinking,
|
||||||
toolDetails: store.toolDetails,
|
|
||||||
assistantMetadata: store.assistantMetadata,
|
|
||||||
})
|
})
|
||||||
|
|
||||||
const activate = () => {
|
const activate = () => {
|
||||||
@@ -53,8 +40,6 @@ export function DialogExportOptions(props: DialogExportOptionsProps) {
|
|||||||
}
|
}
|
||||||
if (store.active === "debug") setStore("debug", !store.debug)
|
if (store.active === "debug") setStore("debug", !store.debug)
|
||||||
if (store.active === "thinking") setStore("thinking", !store.thinking)
|
if (store.active === "thinking") setStore("thinking", !store.thinking)
|
||||||
if (store.active === "toolDetails") setStore("toolDetails", !store.toolDetails)
|
|
||||||
if (store.active === "assistantMetadata") setStore("assistantMetadata", !store.assistantMetadata)
|
|
||||||
if (store.active === "copy" || store.active === "export") confirm(store.active)
|
if (store.active === "copy" || store.active === "export") confirm(store.active)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -67,7 +52,7 @@ export function DialogExportOptions(props: DialogExportOptionsProps) {
|
|||||||
cmd: () => {
|
cmd: () => {
|
||||||
const order: Active[] =
|
const order: Active[] =
|
||||||
store.format === "markdown"
|
store.format === "markdown"
|
||||||
? ["markdown", "json", "thinking", "toolDetails", "assistantMetadata", "copy", "export"]
|
? ["markdown", "json", "thinking", "copy", "export"]
|
||||||
: ["markdown", "json", "debug", "copy", "export"]
|
: ["markdown", "json", "debug", "copy", "export"]
|
||||||
setStore("active", order[(order.indexOf(store.active) + 1) % order.length])
|
setStore("active", order[(order.indexOf(store.active) + 1) % order.length])
|
||||||
},
|
},
|
||||||
@@ -86,11 +71,6 @@ export function DialogExportOptions(props: DialogExportOptionsProps) {
|
|||||||
setStore("active", format)
|
setStore("active", format)
|
||||||
}
|
}
|
||||||
|
|
||||||
const toggle = (option: "thinking" | "toolDetails" | "assistantMetadata") => {
|
|
||||||
setStore("active", option)
|
|
||||||
setStore(option, !store[option])
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<box paddingLeft={2} paddingRight={2} gap={1}>
|
<box paddingLeft={2} paddingRight={2} gap={1}>
|
||||||
<box flexDirection="row" justifyContent="space-between">
|
<box flexDirection="row" justifyContent="space-between">
|
||||||
@@ -121,30 +101,19 @@ export function DialogExportOptions(props: DialogExportOptionsProps) {
|
|||||||
</box>
|
</box>
|
||||||
</box>
|
</box>
|
||||||
<Show when={store.format === "markdown"}>
|
<Show when={store.format === "markdown"}>
|
||||||
<box flexDirection="column">
|
<box
|
||||||
<For
|
flexDirection="row"
|
||||||
each={
|
gap={1}
|
||||||
[
|
backgroundColor={store.active === "thinking" ? theme.backgroundElement : undefined}
|
||||||
["thinking", "Include thinking"],
|
onMouseUp={() => {
|
||||||
["toolDetails", "Include tool details"],
|
setStore("active", "thinking")
|
||||||
["assistantMetadata", "Include assistant metadata"],
|
setStore("thinking", !store.thinking)
|
||||||
] as const
|
}}
|
||||||
}
|
>
|
||||||
>
|
<text fg={store.active === "thinking" ? theme.primary : theme.textMuted}>
|
||||||
{(item) => (
|
{store.thinking ? "[x]" : "[ ]"}
|
||||||
<box
|
</text>
|
||||||
flexDirection="row"
|
<text fg={store.active === "thinking" ? theme.primary : theme.text}>Include thinking</text>
|
||||||
gap={1}
|
|
||||||
backgroundColor={store.active === item[0] ? theme.backgroundElement : undefined}
|
|
||||||
onMouseUp={() => toggle(item[0])}
|
|
||||||
>
|
|
||||||
<text fg={store.active === item[0] ? theme.primary : theme.textMuted}>
|
|
||||||
{store[item[0]] ? "[x]" : "[ ]"}
|
|
||||||
</text>
|
|
||||||
<text fg={store.active === item[0] ? theme.primary : theme.text}>{item[1]}</text>
|
|
||||||
</box>
|
|
||||||
)}
|
|
||||||
</For>
|
|
||||||
</box>
|
</box>
|
||||||
</Show>
|
</Show>
|
||||||
<Show when={store.format === "json"}>
|
<Show when={store.format === "json"}>
|
||||||
@@ -170,12 +139,7 @@ export function DialogExportOptions(props: DialogExportOptionsProps) {
|
|||||||
>
|
>
|
||||||
<text fg={theme.text}>Copy</text>
|
<text fg={theme.text}>Copy</text>
|
||||||
</box>
|
</box>
|
||||||
<box
|
<box paddingLeft={4} paddingRight={4} backgroundColor={theme.primary} onMouseUp={() => confirm("export")}>
|
||||||
paddingLeft={4}
|
|
||||||
paddingRight={4}
|
|
||||||
backgroundColor={theme.primary}
|
|
||||||
onMouseUp={() => confirm("export")}
|
|
||||||
>
|
|
||||||
<text fg={theme.selectedListItemText}>Export</text>
|
<text fg={theme.selectedListItemText}>Export</text>
|
||||||
</box>
|
</box>
|
||||||
</box>
|
</box>
|
||||||
@@ -183,26 +147,17 @@ export function DialogExportOptions(props: DialogExportOptionsProps) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
DialogExportOptions.show = (
|
DialogExportOptions.show = (dialog: DialogContext, defaultThinking: boolean) => {
|
||||||
dialog: DialogContext,
|
|
||||||
defaultThinking: boolean,
|
|
||||||
defaultToolDetails: boolean,
|
|
||||||
defaultAssistantMetadata: boolean,
|
|
||||||
) => {
|
|
||||||
return new Promise<{
|
return new Promise<{
|
||||||
action: "copy" | "export"
|
action: "copy" | "export"
|
||||||
format: ExportFormat
|
format: ExportFormat
|
||||||
debug: boolean
|
debug: boolean
|
||||||
thinking: boolean
|
thinking: boolean
|
||||||
toolDetails: boolean
|
|
||||||
assistantMetadata: boolean
|
|
||||||
} | null>((resolve) => {
|
} | null>((resolve) => {
|
||||||
dialog.replace(
|
dialog.replace(
|
||||||
() => (
|
() => (
|
||||||
<DialogExportOptions
|
<DialogExportOptions
|
||||||
defaultThinking={defaultThinking}
|
defaultThinking={defaultThinking}
|
||||||
defaultToolDetails={defaultToolDetails}
|
|
||||||
defaultAssistantMetadata={defaultAssistantMetadata}
|
|
||||||
onConfirm={(options) => resolve(options)}
|
onConfirm={(options) => resolve(options)}
|
||||||
onCancel={() => resolve(null)}
|
onCancel={() => resolve(null)}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { useTheme } from "../context/theme"
|
|||||||
import { useDialog, type DialogContext } from "./dialog"
|
import { useDialog, type DialogContext } from "./dialog"
|
||||||
import { Show, createEffect, createSignal, onMount, type JSX } from "solid-js"
|
import { Show, createEffect, createSignal, onMount, type JSX } from "solid-js"
|
||||||
import { Spinner } from "../component/spinner"
|
import { Spinner } from "../component/spinner"
|
||||||
import { useTuiConfig } from "../config"
|
import { useTuiConfig } from "../config/v1"
|
||||||
import { useBindings, useCommandShortcut } from "../keymap"
|
import { useBindings, useCommandShortcut } from "../keymap"
|
||||||
|
|
||||||
export type DialogPromptProps = {
|
export type DialogPromptProps = {
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ import { isDeepEqual } from "remeda"
|
|||||||
import { useDialog, type DialogContext } from "./dialog"
|
import { useDialog, type DialogContext } from "./dialog"
|
||||||
import { Locale } from "../util/locale"
|
import { Locale } from "../util/locale"
|
||||||
import { getScrollAcceleration } from "../util/scroll"
|
import { getScrollAcceleration } from "../util/scroll"
|
||||||
import { useTuiConfig } from "../config"
|
import { useTuiConfig } from "../config/v1"
|
||||||
import { formatKeyBindings, useBindings, useKeymapSelector } from "../keymap"
|
import { formatKeyBindings, useBindings, useKeymapSelector } from "../keymap"
|
||||||
|
|
||||||
export interface DialogSelectProps<T> {
|
export interface DialogSelectProps<T> {
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import path from "node:path"
|
|||||||
import { onCleanup } from "solid-js"
|
import { onCleanup } from "solid-js"
|
||||||
import { tmpdir } from "../../fixture/fixture"
|
import { tmpdir } from "../../fixture/fixture"
|
||||||
import { createTuiResolvedConfig } from "../../fixture/tui-runtime"
|
import { createTuiResolvedConfig } from "../../fixture/tui-runtime"
|
||||||
import type { TuiKeybind } from "../../../src/config/keybind"
|
import type { TuiKeybind } from "../../../src/config/v1/keybind"
|
||||||
import { TestTuiContexts } from "../../fixture/tui-environment"
|
import { TestTuiContexts } from "../../fixture/tui-environment"
|
||||||
|
|
||||||
async function wait(fn: () => boolean, timeout = 2000) {
|
async function wait(fn: () => boolean, timeout = 2000) {
|
||||||
@@ -41,7 +41,7 @@ async function mountPrompt(input: {
|
|||||||
import("../../../src/ui/dialog-prompt"),
|
import("../../../src/ui/dialog-prompt"),
|
||||||
import("../../../src/context/kv"),
|
import("../../../src/context/kv"),
|
||||||
import("../../../src/context/theme"),
|
import("../../../src/context/theme"),
|
||||||
import("../../../src/config"),
|
import("../../../src/config/v1"),
|
||||||
import("../../../src/ui/toast"),
|
import("../../../src/ui/toast"),
|
||||||
import("../../../src/keymap"),
|
import("../../../src/keymap"),
|
||||||
])
|
])
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import type { JSX } from "solid-js"
|
|||||||
import { createTuiResolvedConfig } from "../../fixture/tui-runtime"
|
import { createTuiResolvedConfig } from "../../fixture/tui-runtime"
|
||||||
import { KVProvider } from "../../../src/context/kv"
|
import { KVProvider } from "../../../src/context/kv"
|
||||||
import { ThemeProvider } from "../../../src/context/theme"
|
import { ThemeProvider } from "../../../src/context/theme"
|
||||||
import { TuiConfigProvider } from "../../../src/config"
|
import { TuiConfigProvider } from "../../../src/config/v1"
|
||||||
import { DiffViewerFileTree } from "../../../src/feature-plugins/system/diff-viewer-file-tree"
|
import { DiffViewerFileTree } from "../../../src/feature-plugins/system/diff-viewer-file-tree"
|
||||||
import { TestTuiContexts } from "../../fixture/tui-environment"
|
import { TestTuiContexts } from "../../fixture/tui-environment"
|
||||||
import {
|
import {
|
||||||
|
|||||||
@@ -7,9 +7,9 @@ import type { TuiPluginApi, TuiPluginMeta, TuiRouteCurrent, TuiRouteDefinition }
|
|||||||
import type { Session } from "@opencode-ai/sdk/v2"
|
import type { Session } from "@opencode-ai/sdk/v2"
|
||||||
import { KVProvider } from "../../../src/context/kv"
|
import { KVProvider } from "../../../src/context/kv"
|
||||||
import { ThemeProvider } from "../../../src/context/theme"
|
import { ThemeProvider } from "../../../src/context/theme"
|
||||||
import { TuiConfigProvider } from "../../../src/config"
|
import { TuiConfigProvider } from "../../../src/config/v1"
|
||||||
import { SDKProvider } from "../../../src/context/sdk"
|
import { SDKProvider } from "../../../src/context/sdk"
|
||||||
import { TuiKeybind } from "../../../src/config/keybind"
|
import { TuiKeybind } from "../../../src/config/v1/keybind"
|
||||||
import { OpencodeKeymapProvider } from "../../../src/keymap"
|
import { OpencodeKeymapProvider } from "../../../src/keymap"
|
||||||
import diffViewerPlugin from "../../../src/feature-plugins/system/diff-viewer"
|
import diffViewerPlugin from "../../../src/feature-plugins/system/diff-viewer"
|
||||||
import { createTuiPluginApi } from "../../fixture/tui-plugin"
|
import { createTuiPluginApi } from "../../fixture/tui-plugin"
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import type { FormWithLocation } from "../../../src/context/data"
|
|||||||
import { KVProvider } from "../../../src/context/kv"
|
import { KVProvider } from "../../../src/context/kv"
|
||||||
import { SDKProvider } from "../../../src/context/sdk"
|
import { SDKProvider } from "../../../src/context/sdk"
|
||||||
import { ThemeProvider } from "../../../src/context/theme"
|
import { ThemeProvider } from "../../../src/context/theme"
|
||||||
import { TuiConfigProvider } from "../../../src/config"
|
import { TuiConfigProvider } from "../../../src/config/v1"
|
||||||
import { OpencodeKeymapProvider, registerOpencodeKeymap } from "../../../src/keymap"
|
import { OpencodeKeymapProvider, registerOpencodeKeymap } from "../../../src/keymap"
|
||||||
import { ToastProvider } from "../../../src/ui/toast"
|
import { ToastProvider } from "../../../src/ui/toast"
|
||||||
import { tmpdir } from "../../fixture/fixture"
|
import { tmpdir } from "../../fixture/fixture"
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import {
|
|||||||
TuiConfigProvider,
|
TuiConfigProvider,
|
||||||
type Info as TuiConfigInfo,
|
type Info as TuiConfigInfo,
|
||||||
useTuiConfig,
|
useTuiConfig,
|
||||||
} from "../src/config"
|
} from "../src/config/v1"
|
||||||
|
|
||||||
const decodeInfo = Schema.decodeUnknownSync(Info)
|
const decodeInfo = Schema.decodeUnknownSync(Info)
|
||||||
const decodePlugin = Schema.decodeUnknownSync(PluginSpec)
|
const decodePlugin = Schema.decodeUnknownSync(PluginSpec)
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { resolve, type Info, type Resolved } from "../../src/config"
|
import { resolve, type Info, type Resolved } from "../../src/config/v1"
|
||||||
import { TuiKeybind } from "../../src/config/keybind"
|
import { TuiKeybind } from "../../src/config/v1/keybind"
|
||||||
|
|
||||||
type ResolvedInput = Omit<Info, "attention" | "keybinds" | "leader_timeout"> & {
|
type ResolvedInput = Omit<Info, "attention" | "keybinds" | "leader_timeout"> & {
|
||||||
attention?: Partial<Resolved["attention"]>
|
attention?: Partial<Resolved["attention"]>
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { createBindingLookup } from "@opentui/keymap/extras"
|
|||||||
import { testRender, useRenderer } from "@opentui/solid"
|
import { testRender, useRenderer } from "@opentui/solid"
|
||||||
import { expect, test } from "bun:test"
|
import { expect, test } from "bun:test"
|
||||||
import { onCleanup } from "solid-js"
|
import { onCleanup } from "solid-js"
|
||||||
import { TuiKeybind } from "../src/config/keybind"
|
import { TuiKeybind } from "../src/config/v1/keybind"
|
||||||
import {
|
import {
|
||||||
formatKeySequence,
|
formatKeySequence,
|
||||||
getOpencodeModeStack,
|
getOpencodeModeStack,
|
||||||
|
|||||||
Reference in New Issue
Block a user