@truss-harness/tui 0.1.3 → 0.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/bin.js +16 -14
  2. package/package.json +53 -53
package/dist/bin.js CHANGED
@@ -9,23 +9,23 @@ import { promisify } from "node:util";
9
9
  import { fileURLToPath } from "node:url";
10
10
  import { Box, render, Text, useApp, useInput } from "ink";
11
11
  import { useEffect, useMemo, useRef, useState } from "react";
12
- import { detectLocalEndpoints, listLocalModels } from "@truss-harness/provider-openai-compatible";
12
+ import { cloudProviderDefinition, detectLocalEndpoints, isCloudProviderId, isLocalEndpointKind, listLocalModels } from "@truss-harness/provider-openai-compatible";
13
13
  import { brand } from "@truss-harness/branding";
14
14
  import { resolveConfiguration } from "@truss-harness/cli/config";
15
15
  import { createClientRuntime } from "@truss-harness/cli/runtime";
16
16
  import { executeWorkspaceCommand, FileWorkspacePlanStore, workspaceCommandHelp } from "@truss-harness/runtime";
17
17
  import { buildFileTree, fuzzyFiles, syntaxTokens, wrapSyntaxTokens } from "./file-browser.js";
18
18
  import { tuiTheme, tuiThemeNames } from "./theme.js";
19
- const tuiHelp = `${brand.productName} TUI
20
-
21
- Full-screen terminal workspace for local coding models.
22
-
23
- Usage:
24
- ${brand.tuiCommand}
25
-
26
- The TUI starts in the current workspace and reads the same configuration
27
- profiles as ${brand.cliCommand}. Press ? inside the TUI for its complete
28
- keyboard-control reference.
19
+ const tuiHelp = `${brand.productName} TUI
20
+
21
+ Full-screen terminal workspace for local coding models.
22
+
23
+ Usage:
24
+ ${brand.tuiCommand}
25
+
26
+ The TUI starts in the current workspace and reads the same configuration
27
+ profiles as ${brand.cliCommand}. Press ? inside the TUI for its complete
28
+ keyboard-control reference.
29
29
  `;
30
30
  const tuiControlHelp = [
31
31
  ["NAVIGATION", "Tab / Shift+Tab move focus; Ctrl+Left / Ctrl+Right move to an adjacent pane."],
@@ -327,7 +327,7 @@ function App({ initialConfiguration }) {
327
327
  return () => { process.stdout.off("resize", refreshViewport); };
328
328
  }, []);
329
329
  useEffect(() => {
330
- if (!selectedEndpoint || !endpointInput)
330
+ if (!selectedEndpoint || !endpointInput || !isLocalEndpointKind(providerKind))
331
331
  return;
332
332
  const endpoint = { ...selectedEndpoint, kind: providerKind, baseUrl: endpointInput };
333
333
  void listLocalModels(endpoint).then((available) => {
@@ -444,7 +444,9 @@ function App({ initialConfiguration }) {
444
444
  provider: providerKind,
445
445
  baseUrl: endpointInput.trim(),
446
446
  model: modelInput.trim(),
447
- apiKey: process.env.TRUSS_HARNESS_API_KEY,
447
+ apiKey: initialConfiguration?.provider === providerKind
448
+ ? initialConfiguration.apiKey
449
+ : process.env.TRUSS_HARNESS_API_KEY ?? (isCloudProviderId(providerKind) ? process.env[cloudProviderDefinition(providerKind).apiKeyEnvironmentVariable] : undefined),
448
450
  systemPrompt: process.env.TRUSS_HARNESS_SYSTEM_PROMPT,
449
451
  mode: agentMode,
450
452
  internetAccess,
@@ -824,7 +826,7 @@ function App({ initialConfiguration }) {
824
826
  const selected = index === Math.min(fileSearchIndex, Math.max(0, fileSearchResults.length - 1));
825
827
  const fileName = entry.path.split("/").at(-1) ?? entry.path;
826
828
  return _jsxs(Text, { color: selected ? theme.focus : theme.text, bold: selected, children: [selected ? "> " : " ", fileName, _jsxs(Text, { color: theme.muted, children: [" ", truncate(entry.path, Math.max(12, overlayWidth - fileName.length - 10))] })] }, entry.path);
827
- }), !fileSearchResults.length && _jsx(Text, { color: theme.warning, children: "No matching files." })] })] }), screen === "settings" && _jsxs(Box, { position: "absolute", flexDirection: "column", borderStyle: "double", borderColor: theme.focus, paddingX: 2, paddingY: 1, width: overlayWidth, marginLeft: 2, marginTop: 3, backgroundColor: theme.overlay, children: [_jsx(Text, { bold: true, color: theme.accent, children: "LOCAL MODEL CONFIGURATION" }), _jsx(Text, { color: theme.muted, children: "Tab changes fields. Enter selects an item or saves when endpoint and model are set." }), _jsxs(Text, { color: settingsField === "server" ? theme.focus : theme.text, children: ["SERVER: ", selectedEndpoint?.label ?? "Scanning local servers..."] }), _jsxs(Text, { color: settingsField === "endpoint" ? theme.focus : theme.text, children: ["ENDPOINT: ", endpointInput] }), _jsxs(Text, { color: settingsField === "model" ? theme.focus : theme.text, children: ["MODEL: ", modelInput || models[modelIndex] || "Choose or type a model"] }), _jsxs(Text, { color: settingsField === "internet" ? theme.focus : theme.text, children: ["INTERNET RESEARCH: ", internetAccess ? "enabled" : "disabled", " ", settingsField === "internet" ? "[Space toggles]" : ""] }), _jsxs(Text, { color: settingsField === "theme" ? theme.focus : theme.text, children: ["THEME: ", themeName, " ", settingsField === "theme" ? "[Left/Right changes]" : ""] }), _jsxs(Text, { color: theme.muted, children: ["Detected models: ", models.slice(0, 5).join(", ") || "none; type one manually"] }), _jsxs(Text, { color: theme.warning, children: ["Provider: ", providerKind, ". Use the server selector for Ollama or compatible endpoints."] })] }), screen === "approval" && _jsxs(Box, { position: "absolute", flexDirection: "column", borderStyle: "double", borderColor: theme.warning, paddingX: 2, paddingY: 1, width: overlayWidth, marginLeft: 2, marginTop: 8, backgroundColor: theme.overlay, children: [_jsx(Text, { bold: true, color: theme.warning, children: "TOOL APPROVAL REQUIRED" }), _jsxs(Text, { color: theme.text, children: [pendingTool?.name, " ", JSON.stringify(pendingTool?.input)] }), _jsx(Text, { color: theme.muted, children: "Press Y or Enter to allow. Press N or Escape to deny." })] }), screen === "help" && _jsxs(Box, { position: "absolute", flexDirection: "column", borderStyle: "double", borderColor: theme.focus, paddingX: 2, paddingY: 1, width: overlayWidth, marginLeft: 2, marginTop: 7, backgroundColor: theme.overlay, children: [_jsx(Text, { bold: true, color: theme.accent, children: "TUI CONTROLS" }), tuiControlHelp.map(([label, detail]) => _jsxs(Text, { color: theme.text, wrap: "wrap", children: [_jsxs(Text, { bold: true, color: theme.focus, children: [label, ": "] }), detail] }, label)), _jsx(Box, { marginTop: 1, children: _jsx(Text, { bold: true, color: theme.accent, children: "WORKSPACE COMMANDS" }) }), workspaceCommandHelp().split("\n").slice(1).map((line) => _jsx(Text, { color: theme.text, children: line }, line)), _jsx(Text, { color: theme.muted, children: "Press any key to close this reference." })] })] });
829
+ }), !fileSearchResults.length && _jsx(Text, { color: theme.warning, children: "No matching files." })] })] }), screen === "settings" && _jsxs(Box, { position: "absolute", flexDirection: "column", borderStyle: "double", borderColor: theme.focus, paddingX: 2, paddingY: 1, width: overlayWidth, marginLeft: 2, marginTop: 3, backgroundColor: theme.overlay, children: [_jsx(Text, { bold: true, color: theme.accent, children: "LOCAL MODEL CONFIGURATION" }), _jsx(Text, { color: theme.muted, children: "Tab changes fields. Enter selects an item or saves when endpoint and model are set." }), _jsxs(Text, { color: settingsField === "server" ? theme.focus : theme.text, children: ["SERVER: ", selectedEndpoint?.label ?? "Scanning local servers..."] }), _jsxs(Text, { color: settingsField === "endpoint" ? theme.focus : theme.text, children: ["ENDPOINT: ", endpointInput] }), _jsxs(Text, { color: settingsField === "model" ? theme.focus : theme.text, children: ["MODEL: ", modelInput || models[modelIndex] || "Choose or type a model"] }), _jsxs(Text, { color: settingsField === "internet" ? theme.focus : theme.text, children: ["INTERNET RESEARCH: ", internetAccess ? "enabled" : "disabled", " ", settingsField === "internet" ? "[Space toggles]" : ""] }), _jsxs(Text, { color: settingsField === "theme" ? theme.focus : theme.text, children: ["THEME: ", themeName, " ", settingsField === "theme" ? "[Left/Right changes]" : ""] }), _jsxs(Text, { color: theme.muted, children: ["Detected models: ", models.slice(0, 5).join(", ") || "none; type one manually"] }), _jsxs(Text, { color: theme.warning, children: ["Provider: ", providerKind, ". Local endpoints use the server selector. Configure cloud BYOK profiles with truss-cli setup, then relaunch the TUI."] })] }), screen === "approval" && _jsxs(Box, { position: "absolute", flexDirection: "column", borderStyle: "double", borderColor: theme.warning, paddingX: 2, paddingY: 1, width: overlayWidth, marginLeft: 2, marginTop: 8, backgroundColor: theme.overlay, children: [_jsx(Text, { bold: true, color: theme.warning, children: "TOOL APPROVAL REQUIRED" }), _jsxs(Text, { color: theme.text, children: [pendingTool?.name, " ", JSON.stringify(pendingTool?.input)] }), _jsx(Text, { color: theme.muted, children: "Press Y or Enter to allow. Press N or Escape to deny." })] }), screen === "help" && _jsxs(Box, { position: "absolute", flexDirection: "column", borderStyle: "double", borderColor: theme.focus, paddingX: 2, paddingY: 1, width: overlayWidth, marginLeft: 2, marginTop: 7, backgroundColor: theme.overlay, children: [_jsx(Text, { bold: true, color: theme.accent, children: "TUI CONTROLS" }), tuiControlHelp.map(([label, detail]) => _jsxs(Text, { color: theme.text, wrap: "wrap", children: [_jsxs(Text, { bold: true, color: theme.focus, children: [label, ": "] }), detail] }, label)), _jsx(Box, { marginTop: 1, children: _jsx(Text, { bold: true, color: theme.accent, children: "WORKSPACE COMMANDS" }) }), workspaceCommandHelp().split("\n").slice(1).map((line) => _jsx(Text, { color: theme.text, children: line }, line)), _jsx(Text, { color: theme.muted, children: "Press any key to close this reference." })] })] });
828
830
  }
829
831
  const initialConfiguration = await resolveConfiguration({ workspaceRoot: cwd() }).catch((error) => {
830
832
  const message = error instanceof Error ? error.message : String(error);
package/package.json CHANGED
@@ -1,53 +1,53 @@
1
- {
2
- "name": "@truss-harness/tui",
3
- "version": "0.1.3",
4
- "description": "Interactive terminal client for Truss.",
5
- "type": "module",
6
- "bin": {
7
- "truss-tui": "dist/bin.js"
8
- },
9
- "scripts": {
10
- "build": "tsc -b",
11
- "prepack": "node ../../scripts/clean-publish-tests.mjs",
12
- "prepublishOnly": "npm run build"
13
- },
14
- "files": [
15
- "dist",
16
- "README.md",
17
- "logo.png"
18
- ],
19
- "engines": {
20
- "node": ">=20"
21
- },
22
- "license": "MIT",
23
- "repository": {
24
- "type": "git",
25
- "url": "git+https://github.com/truss-agent/truss-harness.git"
26
- },
27
- "bugs": {
28
- "url": "https://github.com/truss-agent/truss-harness/issues"
29
- },
30
- "homepage": "https://github.com/truss-agent/truss-harness#readme",
31
- "publishConfig": {
32
- "access": "public"
33
- },
34
- "keywords": [
35
- "ai",
36
- "coding-agent",
37
- "tui",
38
- "terminal",
39
- "ollama",
40
- "local-first"
41
- ],
42
- "dependencies": {
43
- "ink": "^6.8.0",
44
- "react": "^19.2.0",
45
- "@truss-harness/branding": "0.1.0",
46
- "@truss-harness/cli": "0.1.3",
47
- "@truss-harness/provider-openai-compatible": "0.1.0",
48
- "@truss-harness/runtime": "0.1.0"
49
- },
50
- "devDependencies": {
51
- "@types/react": "^19.2.0"
52
- }
53
- }
1
+ {
2
+ "name": "@truss-harness/tui",
3
+ "version": "0.1.5",
4
+ "description": "Interactive terminal client for Truss.",
5
+ "type": "module",
6
+ "bin": {
7
+ "truss-tui": "dist/bin.js"
8
+ },
9
+ "scripts": {
10
+ "build": "tsc -b",
11
+ "prepack": "node ../../scripts/clean-publish-tests.mjs",
12
+ "prepublishOnly": "npm run build"
13
+ },
14
+ "files": [
15
+ "dist",
16
+ "README.md",
17
+ "logo.png"
18
+ ],
19
+ "engines": {
20
+ "node": ">=20"
21
+ },
22
+ "license": "MIT",
23
+ "repository": {
24
+ "type": "git",
25
+ "url": "git+https://github.com/truss-agent/truss-harness.git"
26
+ },
27
+ "bugs": {
28
+ "url": "https://github.com/truss-agent/truss-harness/issues"
29
+ },
30
+ "homepage": "https://github.com/truss-agent/truss-harness#readme",
31
+ "publishConfig": {
32
+ "access": "public"
33
+ },
34
+ "keywords": [
35
+ "ai",
36
+ "coding-agent",
37
+ "tui",
38
+ "terminal",
39
+ "ollama",
40
+ "local-first"
41
+ ],
42
+ "dependencies": {
43
+ "ink": "^6.8.0",
44
+ "react": "^19.2.0",
45
+ "@truss-harness/branding": "0.1.0",
46
+ "@truss-harness/cli": "0.1.5",
47
+ "@truss-harness/provider-openai-compatible": "0.1.2",
48
+ "@truss-harness/runtime": "0.1.2"
49
+ },
50
+ "devDependencies": {
51
+ "@types/react": "^19.2.0"
52
+ }
53
+ }