@truss-harness/tui 0.1.9 → 0.1.13

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 (4) hide show
  1. package/LICENSE +233 -21
  2. package/README.md +15 -1
  3. package/dist/bin.js +45 -2
  4. package/package.json +5 -5
package/LICENSE CHANGED
@@ -1,21 +1,233 @@
1
- MIT License
2
-
3
- Copyright (c) 2026 Truss contributors
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
1
+ Truss Collaborative Source License, Version 1.0
2
+
3
+ Copyright (c) 2026 Jared Hooker and Truss contributors
4
+
5
+ Required Notice: This software is based on Truss.
6
+ Required Notice: Truss original project: https://github.com/truss-agent/truss-harness
7
+
8
+ This is a source-available license. It is not an Open Source Initiative
9
+ approved open-source license.
10
+
11
+ 1. Acceptance
12
+
13
+ To receive any license under these terms, you must accept them as strict
14
+ obligations and as conditions of every license granted below. If you do not
15
+ accept these terms, you receive no license.
16
+
17
+ 2. Definitions
18
+
19
+ "Software" means the Truss source code, object code, documentation, artwork,
20
+ and other material distributed with these terms, excluding Third-Party
21
+ Components identified below.
22
+
23
+ "Licensor" means each person or entity that owns copyright or patent rights in
24
+ the Software and has authority to license those rights.
25
+
26
+ "Official Project" means the Truss project maintained at
27
+ https://github.com/truss-agent/truss-harness and its official releases.
28
+
29
+ "Project Steward" means Jared Hooker or a successor publicly identified as the
30
+ project owner in the Official Project repository.
31
+
32
+ "You" means the individual or legal entity exercising rights under these
33
+ terms. For a legal entity, You includes entities that control, are controlled
34
+ by, or are under common control with that entity.
35
+
36
+ "Commercial Purpose" means any purpose intended to provide, or that does
37
+ provide, direct or indirect commercial advantage or monetary compensation to
38
+ You or another person. It includes internal business use by a for-profit
39
+ entity; use in developing, operating, or supporting a revenue-generating
40
+ product or service; sale, licensing, subscription, hosting, paid support,
41
+ consulting, advertising, or other monetization; and use intended to reduce the
42
+ cost of a commercial product or service.
43
+
44
+ "Competing Product" means any product or service, whether paid or free, that
45
+ provides the same or substantially similar functionality as the Software or an
46
+ official Truss product, or that is marketed or made available as a substitute
47
+ for any of them. Products and services may compete even when they use a
48
+ different interface, platform, programming language, architecture, or delivery
49
+ model. Coding-agent runtimes, harnesses, clients, development tools, model
50
+ routing systems, agent orchestration systems, and hosted versions of any of
51
+ those may be Competing Products.
52
+
53
+ "Contribution Activity" means reproducing, modifying, running, and sharing the
54
+ Software only as reasonably necessary to prepare, test, review, or submit a
55
+ good-faith contribution to the Official Project.
56
+
57
+ "Distribute" means to provide any copy of the Software or a work based on the
58
+ Software to another person or entity, including by publishing, transferring,
59
+ sublicensing, offering as a network service, or making it available for
60
+ download.
61
+
62
+ "Corresponding Source" means the preferred form for making modifications,
63
+ including build scripts and other material reasonably necessary to build and
64
+ run the distributed version, but excluding generally available unmodified
65
+ tools and dependencies.
66
+
67
+ "Third-Party Components" means material that is identified as being governed
68
+ by separate license terms. Those separate terms continue to control that
69
+ material.
70
+
71
+ 3. Copyright License
72
+
73
+ Subject to these terms, each Licensor grants You a worldwide, royalty-free,
74
+ non-exclusive, non-transferable, non-sublicensable copyright license to use,
75
+ reproduce, modify, and create works based on the Software solely for:
76
+
77
+ a. a purpose that is both noncommercial and does not provide or support a
78
+ Competing Product; or
79
+
80
+ b. Contribution Activity.
81
+
82
+ No permission is granted for a Commercial Purpose or a Competing Product
83
+ except under Section 8.
84
+
85
+ 4. Distribution License and Conditions
86
+
87
+ Subject to these terms, each Licensor grants You a worldwide, royalty-free,
88
+ non-exclusive, non-transferable, non-sublicensable license to Distribute the
89
+ Software, with or without modifications, only for a purpose permitted by
90
+ Section 3 and when You satisfy every condition below. You may not market,
91
+ direct, or knowingly provide a distribution for a Commercial Purpose or a
92
+ Competing Product. A public fork maintained in good faith for Contribution
93
+ Activity is permitted.
94
+
95
+ a. You must provide the complete Corresponding Source at no charge with the
96
+ distribution or through a durable, publicly accessible location clearly
97
+ identified in the distribution.
98
+
99
+ b. You must license the Software and every work based on the Software under
100
+ this exact license. You may not offer additional or conflicting terms
101
+ that restrict or expand the rights granted by this license.
102
+
103
+ c. You must include an unmodified copy of this license and preserve every
104
+ copyright, attribution, and Required Notice supplied with the Software.
105
+
106
+ d. The primary README or equivalent documentation must prominently state:
107
+ "Based on Truss (https://github.com/truss-agent/truss-harness)."
108
+
109
+ e. A program with a graphical or command-line user interface must display
110
+ the statement in Section 4(d) in a reasonably accessible About, Credits,
111
+ Help, or version view. A library or service without such an interface
112
+ must display it in its primary documentation and package metadata where
113
+ that metadata format supports attribution.
114
+
115
+ f. You must identify significant modifications and must not imply that a
116
+ modified version is an official Truss release or is endorsed by the
117
+ Official Project.
118
+
119
+ g. You may not remove, obscure, minimize, or bypass the notices required by
120
+ this section.
121
+
122
+ Merely creating a private clone does not require publication, but every notice
123
+ already present in that clone must remain intact. Distribution through a fork,
124
+ mirror, package, archive, installer, container, application, or network service
125
+ is subject to this section.
126
+
127
+ 5. No Commercial Use
128
+
129
+ You may not use, reproduce, modify, create works based on, or Distribute the
130
+ Software for a Commercial Purpose without separate written permission under
131
+ Section 8. A commercial activity does not become noncommercial because the
132
+ Software is provided without a separate charge.
133
+
134
+ 6. No Competitive Use
135
+
136
+ You may not use, reproduce, modify, create works based on, or Distribute the
137
+ Software to build, provide, maintain, market, fund, or support a Competing
138
+ Product without separate written permission under Section 8. This restriction
139
+ applies even if the Competing Product is free, source-available, internal,
140
+ nonprofit, or not yet publicly released.
141
+
142
+ 7. Contributions Are Welcome
143
+
144
+ You may perform Contribution Activity even when You work for a commercial
145
+ organization, provided the activity is genuinely directed toward improving
146
+ the Official Project and is not used to develop or support a separate
147
+ Commercial Purpose or Competing Product.
148
+
149
+ If You intentionally submit a contribution for inclusion in the Official
150
+ Project, You retain ownership of Your contribution and grant the Project
151
+ Steward a perpetual, worldwide, irrevocable, non-exclusive, royalty-free
152
+ copyright license to use, reproduce, modify, prepare derivative works of,
153
+ publicly display, publicly perform, Distribute, sublicense, and relicense that
154
+ contribution as part of or in connection with Truss. Recipients receive rights
155
+ to the contribution only under the license that accompanies the Official
156
+ Project version they receive. You also grant the Project Steward a patent
157
+ license covering patent claims You can license that would necessarily be
158
+ infringed by the contribution alone or in combination with the Official
159
+ Project, with the right to sublicense that patent license to recipients under
160
+ the terms accompanying the Official Project.
161
+
162
+ You represent that You have the right to grant these permissions and that You
163
+ will identify any contribution governed by separate third-party terms.
164
+
165
+ 8. Separate Commercial or Competitive License
166
+
167
+ The Project Steward or applicable Licensor may offer separate written terms
168
+ for a Commercial Purpose, a Competing Product, reduced attribution, or another
169
+ use not permitted here. Permission is effective only when stated in a separate
170
+ written agreement signed or expressly issued by the party authorized to grant
171
+ it. Payment, sponsorship, contribution, or prior communication alone does not
172
+ create permission.
173
+
174
+ 9. Patents
175
+
176
+ Subject to these terms, each Licensor grants You a worldwide, royalty-free,
177
+ non-exclusive patent license under patent claims the Licensor can license that
178
+ You would necessarily infringe by exercising the copyright licenses granted
179
+ here. If You or Your organization makes a written claim that the Software
180
+ infringes or contributes to infringement of a patent, every patent license
181
+ granted to You under these terms ends immediately.
182
+
183
+ 10. Trademarks
184
+
185
+ These terms do not grant permission to use the Truss name, logos, trade dress,
186
+ or other marks except as strictly necessary to provide the attribution
187
+ required by Section 4. You may not use any mark in a way that suggests
188
+ affiliation with or endorsement by the Official Project.
189
+
190
+ 11. Third-Party Components
191
+
192
+ Third-Party Components remain governed by their own license terms. Nothing in
193
+ this license limits rights You receive directly under those terms, and nothing
194
+ in those terms expands Your rights in the Software.
195
+
196
+ 12. Termination and Cure
197
+
198
+ Any license granted under these terms terminates automatically when You breach
199
+ them. If this is Your first breach and You cure it fully within 30 days after
200
+ receiving written notice from a Licensor, Your license is reinstated
201
+ retroactively. A later breach terminates Your license immediately and
202
+ permanently unless the applicable Licensor agrees otherwise in writing.
203
+
204
+ Sections that by their nature should survive termination, including Sections
205
+ 7, 10, 13, 14, and 15, survive.
206
+
207
+ 13. Disclaimer of Warranty
208
+
209
+ THE SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTIES OF ANY KIND, EXPRESS
210
+ OR IMPLIED, INCLUDING WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
211
+ PURPOSE, TITLE, AND NON-INFRINGEMENT. YOU BEAR ALL RISK ARISING FROM USE OR
212
+ DISTRIBUTION OF THE SOFTWARE.
213
+
214
+ 14. Limitation of Liability
215
+
216
+ TO THE MAXIMUM EXTENT PERMITTED BY LAW, NO LICENSOR, PROJECT STEWARD, OR
217
+ CONTRIBUTOR WILL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
218
+ EXEMPLARY, CONSEQUENTIAL, OR OTHER DAMAGES, OR FOR LOST PROFITS, DATA,
219
+ GOODWILL, OR BUSINESS INTERRUPTION, ARISING FROM OR RELATED TO THE SOFTWARE OR
220
+ THESE TERMS, UNDER ANY LEGAL THEORY, EVEN IF ADVISED OF THE POSSIBILITY.
221
+
222
+ 15. General Terms
223
+
224
+ If a provision of these terms is unenforceable, it will be modified only to
225
+ the minimum extent necessary to make it enforceable, and the remaining terms
226
+ will continue in effect. Failure to enforce a provision is not a waiver. These
227
+ terms do not limit rights You may have under applicable law without a license,
228
+ such as fair use.
229
+
230
+ This license applies only to Software versions distributed with it. Software
231
+ versions previously received under another license remain governed by the
232
+ license that accompanied those versions. No future license version applies
233
+ unless the Software is distributed with that version.
package/README.md CHANGED
@@ -29,7 +29,12 @@ The default `forest` theme uses restrained green, sage, and teal accents with so
29
29
 
30
30
  Inside the TUI, open settings with `m`, Tab to **Theme**, and use Left or Right to preview a preset for the current session.
31
31
 
32
- Configured MCP stdio servers are connected when an Agent session starts, and their connection status appears in the Terminal pane. Plan mode loads only servers explicitly marked `readOnly`. Run `truss-cli config path` to locate the shared user and workspace configuration files.
32
+ Configured MCP stdio servers are connected when an Agent session starts, and
33
+ their connection status appears in the Terminal pane. Press `c` outside the
34
+ chat/terminal panes to inspect safe server and tool status, then `R` to test
35
+ the configured servers. Plan mode loads only servers explicitly marked
36
+ `readOnly`. Run `truss-cli config path` to locate the shared user and workspace
37
+ configuration files.
33
38
 
34
39
  ## Controls
35
40
 
@@ -41,6 +46,7 @@ Configured MCP stdio servers are connected when an Agent session starts, and the
41
46
  | `Enter` | Send the chat input or open the selected file. |
42
47
  | `Left` / `Right` | Collapse or expand the selected directory. |
43
48
  | `m` | Open local model settings outside the chat pane. |
49
+ | `c` | Open credential-safe MCP server and tool status. |
44
50
  | `d` | Toggle the selected file's Git diff. |
45
51
  | Type directly | Enter a command while the terminal pane has focus. |
46
52
  | `?` | Open workspace command help. |
@@ -48,3 +54,11 @@ Configured MCP stdio servers are connected when an Agent session starts, and the
48
54
  | `Ctrl+C` | Stop generation, or exit while idle. |
49
55
 
50
56
  Type `/init`, `/update [note]`, `/status`, `/clear-memory`, or `/help` into the Agent pane. They run locally without a model call. Approvals for model-initiated tools still respect the selected permission policy.
57
+
58
+ ## License and contributions
59
+
60
+ This client is source-available under the [Truss Collaborative Source
61
+ License](LICENSE). Contributions to the official project are welcome. Every
62
+ copy, fork, or derivative must preserve the license and prominently state:
63
+ **Based on Truss (https://github.com/truss-agent/truss-harness).** Commercial
64
+ use and competing products or services require separate written permission.
package/dist/bin.js CHANGED
@@ -45,6 +45,10 @@ const tuiControlHelp = [
45
45
  "AGENT",
46
46
  "Enter sends; a opens saved multi-agent profiles; Up/Down scroll chat; n starts a new conversation outside the chat input.",
47
47
  ],
48
+ [
49
+ "MCP",
50
+ "c opens credential-safe server and tool status; R tests configured servers.",
51
+ ],
48
52
  [
49
53
  "TERMINAL",
50
54
  "Type directly and press Enter; Up/Down scroll output; slash commands run through Truss.",
@@ -273,6 +277,11 @@ function App({ initialConfiguration, }) {
273
277
  const workspaceRoot = useMemo(() => cwd(), []);
274
278
  const [configuration, setConfiguration] = useState(initialConfiguration);
275
279
  const [client, setClient] = useState();
280
+ const [mcpStatuses, setMcpStatuses] = useState(() => Object.entries(initialConfiguration?.mcpServers ?? {}).map(([name, server]) => ({
281
+ name,
282
+ state: server.enabled === false ? "disabled" : "idle",
283
+ toolCount: 0,
284
+ })));
276
285
  const [sessionId, setSessionId] = useState();
277
286
  const [files, setFiles] = useState([]);
278
287
  const [fileIndex, setFileIndex] = useState(0);
@@ -460,6 +469,12 @@ function App({ initialConfiguration, }) {
460
469
  useEffect(() => {
461
470
  if (!client)
462
471
  return;
472
+ const unsubscribeMcp = client.mcp.subscribe((statuses) => setMcpStatuses((current) => {
473
+ const merged = new Map(current.map((status) => [status.name, status]));
474
+ for (const status of statuses)
475
+ merged.set(status.name, status);
476
+ return [...merged.values()];
477
+ }));
463
478
  const unsubscribe = client.events.subscribe((event) => {
464
479
  if (event.type === "text_delta") {
465
480
  setRunStatus("thinking");
@@ -497,6 +512,7 @@ function App({ initialConfiguration, }) {
497
512
  });
498
513
  return () => {
499
514
  unsubscribe();
515
+ unsubscribeMcp();
500
516
  void client.dispose();
501
517
  };
502
518
  }, [client]);
@@ -581,6 +597,7 @@ function App({ initialConfiguration, }) {
581
597
  systemPrompt: process.env.TRUSS_HARNESS_SYSTEM_PROMPT,
582
598
  mode: agentMode,
583
599
  internetAccess,
600
+ mcpServers: initialConfiguration?.mcpServers,
584
601
  approval: {
585
602
  approve: async (call) => {
586
603
  const readOnly = [
@@ -805,6 +822,22 @@ function App({ initialConfiguration, }) {
805
822
  .catch((error) => appendTerminal(`[agents] ${error instanceof Error ? error.message : String(error)}`));
806
823
  return;
807
824
  }
825
+ if (screen === "mcp") {
826
+ if (key.escape || input.toLowerCase() === "c") {
827
+ setScreen("workspace");
828
+ return;
829
+ }
830
+ if (input.toLowerCase() === "r" && configuration) {
831
+ void createClientRuntime({ ...configuration, mode: "edit" })
832
+ .then(async (inspection) => {
833
+ setMcpStatuses(inspection.mcpServers);
834
+ appendTerminal("[mcp] Tested configured servers.");
835
+ await inspection.dispose();
836
+ })
837
+ .catch((error) => appendTerminal(`[mcp] ${error instanceof Error ? error.message : String(error)}`));
838
+ }
839
+ return;
840
+ }
808
841
  if (screen === "settings") {
809
842
  if (key.escape) {
810
843
  setScreen("workspace");
@@ -935,6 +968,10 @@ function App({ initialConfiguration, }) {
935
968
  setScreen("settings");
936
969
  return;
937
970
  }
971
+ if (input.toLowerCase() === "c" && focus !== "chat") {
972
+ setScreen("mcp");
973
+ return;
974
+ }
938
975
  if (input === "n" && focus !== "chat") {
939
976
  startNewConversation();
940
977
  return;
@@ -1046,12 +1083,18 @@ function App({ initialConfiguration, }) {
1046
1083
  ? theme.error
1047
1084
  : line.startsWith("[tool")
1048
1085
  ? theme.warning
1049
- : theme.muted, children: truncate(line, Math.max(20, viewport.columns - 8)) }, `${index}-${line}`))), _jsx(Box, { flexGrow: 1 }), _jsxs(Text, { wrap: "truncate-end", color: focus === "terminal" ? theme.focus : theme.muted, children: [focus === "terminal" ? "> " : " ", truncate(commandInput || "Type a workspace command", Math.max(16, viewport.columns - 10))] })] }) }), _jsxs(Box, { height: 1, marginTop: 1, justifyContent: "space-between", children: [_jsx(Text, { color: theme.muted, wrap: "truncate-end", children: "Tab focus | Ctrl+Left/Right pane | / find | a agents | m settings | Esc cancel run | Ctrl+C exit idle" }), _jsx(Text, { color: theme.muted, children: sessionId ? `session ${sessionId.slice(0, 8)}` : "new session" })] }), screen === "file-search" && (_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: "FIND FILE" }), _jsxs(Text, { color: theme.text, children: [_jsx(Text, { color: theme.focus, children: "> " }), fileSearchInput || (_jsx(Text, { color: theme.muted, children: "Type part of a file name or path" }))] }), _jsx(Text, { color: theme.muted, children: "Up/Down select Enter open Escape close" }), _jsxs(Box, { flexDirection: "column", marginTop: 1, children: [fileSearchResults.map((entry, index) => {
1086
+ : theme.muted, children: truncate(line, Math.max(20, viewport.columns - 8)) }, `${index}-${line}`))), _jsx(Box, { flexGrow: 1 }), _jsxs(Text, { wrap: "truncate-end", color: focus === "terminal" ? theme.focus : theme.muted, children: [focus === "terminal" ? "> " : " ", truncate(commandInput || "Type a workspace command", Math.max(16, viewport.columns - 10))] })] }) }), _jsxs(Box, { height: 1, marginTop: 1, justifyContent: "space-between", children: [_jsx(Text, { color: theme.muted, wrap: "truncate-end", children: "Tab focus | Ctrl+Left/Right pane | / find | a agents | c MCP | m settings | Esc cancel run | Ctrl+C exit idle" }), _jsx(Text, { color: theme.muted, children: sessionId ? `session ${sessionId.slice(0, 8)}` : "new session" })] }), screen === "file-search" && (_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: "FIND FILE" }), _jsxs(Text, { color: theme.text, children: [_jsx(Text, { color: theme.focus, children: "> " }), fileSearchInput || (_jsx(Text, { color: theme.muted, children: "Type part of a file name or path" }))] }), _jsx(Text, { color: theme.muted, children: "Up/Down select Enter open Escape close" }), _jsxs(Box, { flexDirection: "column", marginTop: 1, children: [fileSearchResults.map((entry, index) => {
1050
1087
  const selected = index ===
1051
1088
  Math.min(fileSearchIndex, Math.max(0, fileSearchResults.length - 1));
1052
1089
  const fileName = entry.path.split("/").at(-1) ?? entry.path;
1053
1090
  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));
1054
- }), !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 === "agents" && (_jsxs(Box, { position: "absolute", flexDirection: "column", borderStyle: "double", borderColor: theme.focus, paddingX: 2, paddingY: 1, width: overlayWidth, marginLeft: 2, marginTop: 6, backgroundColor: theme.overlay, children: [_jsx(Text, { bold: true, color: theme.accent, children: "MULTI-AGENT PROFILES" }), _jsx(Text, { color: theme.muted, children: "Profiles are shared with truss-cli in .truss-harness/agents.json. Use `truss agents run <id> <task>` for independent concurrent runs." }), _jsxs(Box, { flexDirection: "column", marginTop: 1, children: [agentProfiles.map((profile) => (_jsxs(Text, { color: theme.text, children: [_jsx(Text, { color: theme.focus, children: profile.displayName }), _jsxs(Text, { color: theme.muted, children: [" ", profile.id.slice(0, 8), " ", profile.provider.providerId, "/", profile.provider.modelId, " ", profile.mode, " ", profile.approvalPolicy] })] }, profile.id))), !agentProfiles.length && (_jsx(Text, { color: theme.warning, children: "No profiles yet. Add one with `truss agents add <name>`." }))] }), _jsx(Text, { color: theme.muted, children: "R refreshes. A or Escape closes." })] })), 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()
1091
+ }), !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 === "agents" && (_jsxs(Box, { position: "absolute", flexDirection: "column", borderStyle: "double", borderColor: theme.focus, paddingX: 2, paddingY: 1, width: overlayWidth, marginLeft: 2, marginTop: 6, backgroundColor: theme.overlay, children: [_jsx(Text, { bold: true, color: theme.accent, children: "MULTI-AGENT PROFILES" }), _jsx(Text, { color: theme.muted, children: "Profiles are shared with truss-cli in .truss-harness/agents.json. Use `truss agents run <id> <task>` for independent concurrent runs." }), _jsxs(Box, { flexDirection: "column", marginTop: 1, children: [agentProfiles.map((profile) => (_jsxs(Text, { color: theme.text, children: [_jsx(Text, { color: theme.focus, children: profile.displayName }), _jsxs(Text, { color: theme.muted, children: [" ", profile.id.slice(0, 8), " ", profile.provider.providerId, "/", profile.provider.modelId, " ", profile.mode, " ", profile.approvalPolicy] })] }, profile.id))), !agentProfiles.length && (_jsx(Text, { color: theme.warning, children: "No profiles yet. Add one with `truss agents add <name>`." }))] }), _jsx(Text, { color: theme.muted, children: "R refreshes. A or Escape closes." })] })), screen === "mcp" && (_jsxs(Box, { position: "absolute", flexDirection: "column", borderStyle: "double", borderColor: theme.focus, paddingX: 2, paddingY: 1, width: overlayWidth, marginLeft: 2, marginTop: 6, backgroundColor: theme.overlay, children: [_jsx(Text, { bold: true, color: theme.accent, children: "MCP CONNECTIONS" }), _jsx(Text, { color: theme.muted, children: "Status and discovered tools only. Commands, environment values, and credentials remain hidden." }), _jsxs(Box, { flexDirection: "column", marginTop: 1, children: [mcpStatuses.map((server) => (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Text, { color: server.state === "failed"
1092
+ ? theme.error
1093
+ : server.state === "connected"
1094
+ ? theme.success
1095
+ : theme.warning, children: [_jsx(Text, { bold: true, children: server.name }), " ", server.state, server.error
1096
+ ? ` — ${server.error}`
1097
+ : ` — ${server.toolCount} tool${server.toolCount === 1 ? "" : "s"}`] }), (server.tools ?? []).map((tool) => (_jsxs(Text, { color: theme.muted, children: [" ", tool.name, " [", tool.readOnly ? "read-only" : "approval", "]"] }, `${server.name}:${tool.name}`)))] }, server.name))), !mcpStatuses.length && (_jsx(Text, { color: theme.warning, children: "No MCP servers configured." }))] }), _jsx(Text, { color: theme.muted, children: "R tests configured servers. C or Escape closes." })] })), 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()
1055
1098
  .split("\n")
1056
1099
  .slice(1)
1057
1100
  .map((line) => (_jsx(Text, { color: theme.text, children: line }, line))), _jsx(Text, { color: theme.muted, children: "Press any key to close this reference." })] }))] }));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@truss-harness/tui",
3
- "version": "0.1.9",
3
+ "version": "0.1.13",
4
4
  "description": "Interactive terminal client for Truss.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -19,7 +19,7 @@
19
19
  "engines": {
20
20
  "node": ">=20"
21
21
  },
22
- "license": "MIT",
22
+ "license": "SEE LICENSE IN LICENSE",
23
23
  "repository": {
24
24
  "type": "git",
25
25
  "url": "git+https://github.com/truss-agent/truss-harness.git"
@@ -43,9 +43,9 @@
43
43
  "ink": "^6.8.0",
44
44
  "react": "^19.2.0",
45
45
  "@truss-harness/branding": "0.1.0",
46
- "@truss-harness/cli": "0.1.9",
47
- "@truss-harness/provider-openai-compatible": "0.1.6",
48
- "@truss-harness/runtime": "0.1.6"
46
+ "@truss-harness/cli": "0.1.17",
47
+ "@truss-harness/provider-openai-compatible": "0.1.10",
48
+ "@truss-harness/runtime": "0.1.9"
49
49
  },
50
50
  "devDependencies": {
51
51
  "@types/react": "^19.2.0"