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
434 changes: 434 additions & 0 deletions .opencode/skill/tui-design/SKILL.md

Large diffs are not rendered by default.

11 changes: 7 additions & 4 deletions packages/workbench-cli/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { executeInitialise, executeCreateRemote, validateInitialiseState, runIni
import { parseCliArgs, printHelp, type CliArgs } from "./args.ts"
import { buildRepoFromUrl } from "./utils/repo.ts"
import type { Repo } from "./screens/repoSelect.ts"
import { theme, detectMode } from "./theme"

const args = parseCliArgs()

Expand All @@ -33,6 +34,7 @@ async function runTuiMode(): Promise<void> {
checkAuth()
checkRepoRoot()

await detectMode()
const renderer: CliRenderer = await createCliRenderer({
exitOnCtrlC: false,
exitSignals: ["SIGTERM", "SIGQUIT", "SIGABRT", "SIGHUP"],
Expand All @@ -47,7 +49,7 @@ async function runTuiMode(): Promise<void> {
const versionBadge = new TextRenderable(renderer, {
id: "version-badge",
content: `v${version}`,
fg: "#888888",
fg: theme.tokens.subtitle.fg,
position: "absolute",
right: 1,
bottom: 0,
Expand All @@ -68,7 +70,7 @@ async function runTuiMode(): Promise<void> {
ctrlCNode = new TextRenderable(renderer, {
id: "ctrl-c-prompt",
content: "Press Ctrl+C again to exit",
fg: "#FFFF00",
fg: theme.tokens.ctrlCPrompt.fg,
})
renderer.root.add(ctrlCNode)
ctrlCTimer = setTimeout(() => {
Expand Down Expand Up @@ -257,6 +259,7 @@ async function runNonInteractiveInitCmd(args: CliArgs): Promise<void> {
}

async function runTuiInitMode(args: CliArgs): Promise<void> {
await detectMode()
const renderer: CliRenderer = await createCliRenderer({
exitOnCtrlC: false,
exitSignals: ["SIGTERM", "SIGQUIT", "SIGABRT", "SIGHUP"],
Expand All @@ -271,7 +274,7 @@ async function runTuiInitMode(args: CliArgs): Promise<void> {
const versionBadge = new TextRenderable(renderer, {
id: "version-badge",
content: `v${version}`,
fg: "#888888",
fg: theme.tokens.subtitle.fg,
position: "absolute",
right: 1,
bottom: 0,
Expand All @@ -292,7 +295,7 @@ async function runTuiInitMode(args: CliArgs): Promise<void> {
ctrlCNode = new TextRenderable(renderer, {
id: "ctrl-c-prompt",
content: "Press Ctrl+C again to exit",
fg: "#FFFF00",
fg: theme.tokens.ctrlCPrompt.fg,
})
renderer.root.add(ctrlCNode)
ctrlCTimer = setTimeout(() => {
Expand Down
13 changes: 7 additions & 6 deletions packages/workbench-cli/src/screens/branchConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
type KeyEvent,
} from "@opentui/core"
import type { Repo } from "./repoSelect.ts"
import { theme } from "../theme"

const SCREEN_ID = "branch-config-screen"

Expand All @@ -32,14 +33,14 @@ export function showBranchConfig(
const title = new TextRenderable(renderer, {
id: "branch-title",
content: "Configure Branches",
fg: "#00FFFF",
fg: theme.tokens.title.fg,
})
container.add(title)

const hint = new TextRenderable(renderer, {
id: "branch-hint",
content: "Tab to navigate between rows | Enter on last row to continue",
fg: "#888888",
fg: theme.tokens.subtitle.fg,
})
container.add(hint)

Expand All @@ -66,16 +67,16 @@ export function showBranchConfig(
id: `branch-name-${i}`,
content: repo.name.substring(0, 34).padEnd(35),
width: 35,
fg: "#FFFFFF",
fg: theme.tokens.output.header.fg,
})

const branchInput = new InputRenderable(renderer, {
id: `branch-input-${i}`,
width: 25,
value: repo.defaultBranch,
backgroundColor: "#1a1a1a",
textColor: "#FFFFFF",
focusedBackgroundColor: "#2a2a2a",
backgroundColor: theme.tokens.input.background,
textColor: theme.tokens.input.text.fg,
focusedBackgroundColor: theme.tokens.input.focusedBackground,
})

branchInput.on(InputRenderableEvents.CHANGE, (value: string) => {
Expand Down
8 changes: 5 additions & 3 deletions packages/workbench-cli/src/screens/executing.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
ScrollBoxRenderable,
type CliRenderer,
} from "@opentui/core"
import { theme } from "../theme"

const SCREEN_ID = "executing-screen"

Expand Down Expand Up @@ -39,7 +40,7 @@ export function showExecutingScreen(renderer: CliRenderer): ExecutingScreen {
const title = new TextRenderable(renderer, {
id: "executing-title",
content: "Executing init...",
fg: "#00FFFF",
fg: theme.tokens.title.fg,
})
container.add(title)

Expand Down Expand Up @@ -69,11 +70,12 @@ export function showExecutingScreen(renderer: CliRenderer): ExecutingScreen {
lastTextNode.content = line || " "
} else {
lineCount++
const lineToken = isHeader ? theme.tokens.output.header : theme.tokens.output.line
const textNode = new TextRenderable(renderer, {
id: `exec-line-${lineCount}`,
content: line || " ",
fg: isHeader ? "#FFFFFF" : "#666666",
attributes: isHeader ? TextAttributes.BOLD : TextAttributes.DIM,
fg: lineToken.fg,
attributes: lineToken.attributes,
})
scrollBox.add(textNode)
scrollBox.scrollTo(999999)
Expand Down
5 changes: 3 additions & 2 deletions packages/workbench-cli/src/screens/indexPrompt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
BoxRenderable,
type CliRenderer,
} from "@opentui/core"
import { theme } from "../theme"

const SCREEN_ID = "index-prompt-screen"

Expand All @@ -27,14 +28,14 @@ export function showIndexPrompt(
const title = new TextRenderable(renderer, {
id: "index-title",
content: "Index the repository after setup?",
fg: "#00FFFF",
fg: theme.tokens.title.fg,
})
container.add(title)

const hint = new TextRenderable(renderer, {
id: "index-hint",
content: "Running ck --index may take a few minutes",
fg: "#888888",
fg: theme.tokens.subtitle.fg,
})
container.add(hint)

Expand Down
13 changes: 7 additions & 6 deletions packages/workbench-cli/src/screens/initNameInput.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
type KeyEvent,
} from "@opentui/core"
import { validateRepoName } from "../utils/gh.ts"
import { theme } from "../theme"

const SCREEN_ID = "init-name-input-screen"

Expand All @@ -28,30 +29,30 @@ export function showInitNameInput(
const title = new TextRenderable(renderer, {
id: "init-name-title",
content: "Name Your Workbench",
fg: "#00FFFF",
fg: theme.tokens.title.fg,
})
container.add(title)

const hint = new TextRenderable(renderer, {
id: "init-name-hint",
content: "Enter a name (alphanumeric, -, ., _) | Enter to confirm",
fg: "#888888",
fg: theme.tokens.subtitle.fg,
})
container.add(hint)

const nameInput = new InputRenderable(renderer, {
id: "init-name-input",
width: 50,
value: prefilledName,
backgroundColor: "#1a1a1a",
textColor: "#FFFFFF",
focusedBackgroundColor: "#2a2a2a",
backgroundColor: theme.tokens.input.background,
textColor: theme.tokens.input.text.fg,
focusedBackgroundColor: theme.tokens.input.focusedBackground,
})

const errorText = new TextRenderable(renderer, {
id: "init-name-error",
content: "",
fg: "#FF4444",
fg: theme.tokens.error.fg,
})
errorText.visible = false

Expand Down
13 changes: 7 additions & 6 deletions packages/workbench-cli/src/screens/initOrgSelect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
} from "@opentui/core"
import { getOrgs, type GhOrg } from "../utils/gh.ts"
import { createSpinner } from "../utils/spinner.ts"
import { theme } from "../theme"

const SCREEN_ID = "init-org-select-screen"

Expand Down Expand Up @@ -42,7 +43,7 @@ export async function showInitOrgSelect(
const errText = new TextRenderable(renderer, {
id: "init-org-error",
content: `Error fetching orgs: ${err}`,
fg: "#FF4444",
fg: theme.tokens.error.fg,
})
container.add(errText)
return
Expand All @@ -52,24 +53,24 @@ export async function showInitOrgSelect(
const titleText = new TextRenderable(renderer, {
id: "init-org-title",
content: title,
fg: "#00FFFF",
fg: theme.tokens.title.fg,
})
container.add(titleText)

const hint = new TextRenderable(renderer, {
id: "init-org-hint",
content: "Type to filter | Tab to switch focus | Enter to select",
fg: "#888888",
fg: theme.tokens.subtitle.fg,
})
container.add(hint)

const filterInput = new InputRenderable(renderer, {
id: "init-org-filter",
width: 50,
placeholder: "Type to filter...",
backgroundColor: "#1a1a1a",
textColor: "#FFFFFF",
focusedBackgroundColor: "#2a2a2a",
backgroundColor: theme.tokens.input.background,
textColor: theme.tokens.input.text.fg,
focusedBackgroundColor: theme.tokens.input.focusedBackground,
})

const allOptions = orgs.map((o) => ({
Expand Down
13 changes: 7 additions & 6 deletions packages/workbench-cli/src/screens/initRemoteNameInput.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
type KeyEvent,
} from "@opentui/core"
import { validateRepoName } from "../utils/gh.ts"
import { theme } from "../theme"

const SCREEN_ID = "remote-name-input-screen"

Expand All @@ -28,30 +29,30 @@ export function showRemoteNameInput(
const title = new TextRenderable(renderer, {
id: "remote-name-title",
content: "Remote Repository Name",
fg: "#00FFFF",
fg: theme.tokens.title.fg,
})
container.add(title)

const hint = new TextRenderable(renderer, {
id: "remote-name-hint",
content: "Enter a name (alphanumeric, -, ., _) | Enter to confirm",
fg: "#888888",
fg: theme.tokens.subtitle.fg,
})
container.add(hint)

const nameInput = new InputRenderable(renderer, {
id: "remote-name-input",
width: 50,
value: prefilledName,
backgroundColor: "#1a1a1a",
textColor: "#FFFFFF",
focusedBackgroundColor: "#2a2a2a",
backgroundColor: theme.tokens.input.background,
textColor: theme.tokens.input.text.fg,
focusedBackgroundColor: theme.tokens.input.focusedBackground,
})

const errorText = new TextRenderable(renderer, {
id: "remote-name-error",
content: "",
fg: "#FF4444",
fg: theme.tokens.error.fg,
})
errorText.visible = false

Expand Down
5 changes: 3 additions & 2 deletions packages/workbench-cli/src/screens/initRemotePrompt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
BoxRenderable,
type CliRenderer,
} from "@opentui/core"
import { theme } from "../theme"

const SCREEN_ID = "remote-prompt-screen"

Expand All @@ -26,14 +27,14 @@ export function showRemotePrompt(
const title = new TextRenderable(renderer, {
id: "remote-prompt-title",
content: "Set up a remote?",
fg: "#00FFFF",
fg: theme.tokens.title.fg,
})
container.add(title)

const hint = new TextRenderable(renderer, {
id: "remote-prompt-hint",
content: "A private repo will be created on GitHub and set as origin",
fg: "#888888",
fg: theme.tokens.subtitle.fg,
})
container.add(hint)

Expand Down
5 changes: 3 additions & 2 deletions packages/workbench-cli/src/screens/initSetupPrompt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
BoxRenderable,
type CliRenderer,
} from "@opentui/core"
import { theme } from "../theme"

const SCREEN_ID = "init-setup-prompt-screen"

Expand All @@ -26,14 +27,14 @@ export function showInitSetupPrompt(
const title = new TextRenderable(renderer, {
id: "init-setup-title",
content: "Set up your workbench now?",
fg: "#00FFFF",
fg: theme.tokens.title.fg,
})
container.add(title)

const hint = new TextRenderable(renderer, {
id: "init-setup-hint",
content: "Running setup configures git submodules for your project",
fg: "#888888",
fg: theme.tokens.subtitle.fg,
})
container.add(hint)

Expand Down
13 changes: 7 additions & 6 deletions packages/workbench-cli/src/screens/initSourceInput.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
type CliRenderer,
type KeyEvent,
} from "@opentui/core"
import { theme } from "../theme"

const SCREEN_ID = "source-input-screen"

Expand All @@ -27,30 +28,30 @@ export function showSourceInput(
const title = new TextRenderable(renderer, {
id: "source-input-title",
content: "Source Repository",
fg: "#00FFFF",
fg: theme.tokens.title.fg,
})
container.add(title)

const hint = new TextRenderable(renderer, {
id: "source-input-hint",
content: "Enter source repo (owner/repo or URL) | Enter to confirm",
fg: "#888888",
fg: theme.tokens.subtitle.fg,
})
container.add(hint)

const sourceInput = new InputRenderable(renderer, {
id: "source-input-field",
width: 50,
value: prefilledSource,
backgroundColor: "#1a1a1a",
textColor: "#FFFFFF",
focusedBackgroundColor: "#2a2a2a",
backgroundColor: theme.tokens.input.background,
textColor: theme.tokens.input.text.fg,
focusedBackgroundColor: theme.tokens.input.focusedBackground,
})

const errorText = new TextRenderable(renderer, {
id: "source-input-error",
content: "",
fg: "#FF4444",
fg: theme.tokens.error.fg,
})
errorText.visible = false

Expand Down
Loading
Loading