@truss-harness/tui 0.1.9 → 0.1.14
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.
- package/LICENSE +233 -21
- package/README.md +15 -1
- package/dist/bin.js +45 -2
- package/package.json +6 -6
package/LICENSE
CHANGED
|
@@ -1,21 +1,233 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2026 Truss contributors
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
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
|
|
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 === "
|
|
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.
|
|
3
|
+
"version": "0.1.14",
|
|
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": "
|
|
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"
|
|
@@ -42,10 +42,10 @@
|
|
|
42
42
|
"dependencies": {
|
|
43
43
|
"ink": "^6.8.0",
|
|
44
44
|
"react": "^19.2.0",
|
|
45
|
-
"@truss-harness/branding": "0.1.
|
|
46
|
-
"@truss-harness/cli": "0.1.
|
|
47
|
-
"@truss-harness/provider-openai-compatible": "0.1.
|
|
48
|
-
"@truss-harness/runtime": "0.1.
|
|
45
|
+
"@truss-harness/branding": "0.1.1",
|
|
46
|
+
"@truss-harness/cli": "0.1.18",
|
|
47
|
+
"@truss-harness/provider-openai-compatible": "0.1.11",
|
|
48
|
+
"@truss-harness/runtime": "0.1.10"
|
|
49
49
|
},
|
|
50
50
|
"devDependencies": {
|
|
51
51
|
"@types/react": "^19.2.0"
|