@agent-api/cli 0.0.1 → 0.0.3
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/README.md +11 -0
- package/dist/index.js +20 -2
- package/dist/runtime/index.d.ts +1 -1
- package/dist/runtime/index.js +1 -1
- package/dist/tui/chat.d.ts +2 -1
- package/dist/tui/chat.js +20 -4
- package/dist/tui/workbench.d.ts +8 -0
- package/dist/tui/workbench.js +50 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -73,6 +73,17 @@ Launch the first-class TUI from your current directory:
|
|
|
73
73
|
agent-tui
|
|
74
74
|
```
|
|
75
75
|
|
|
76
|
+
Open a specific local workdir and expose local tools to the agent:
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
agent-tui .
|
|
80
|
+
agent-tui ./my-workdir
|
|
81
|
+
agent-tui /absolute/path/to/my-workdir
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
The workdir argument must point to an existing directory. When provided, the
|
|
85
|
+
workbench automatically turns on local workdir and shell tools in approval mode.
|
|
86
|
+
|
|
76
87
|
The workbench opens with auth as the first gate. If the active profile is valid,
|
|
77
88
|
it enters the conversation UI automatically. If not, it shows an in-terminal
|
|
78
89
|
auth picker for browser session or API key login.
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { Command, Option } from "commander";
|
|
3
|
+
import { stat } from "node:fs/promises";
|
|
4
|
+
import { resolve } from "node:path";
|
|
3
5
|
import { render } from "ink";
|
|
4
6
|
import React from "react";
|
|
5
7
|
import { conversationSummary, deleteConversation, getConversation, listConversations, runAgent } from "./agent.js";
|
|
@@ -15,15 +17,17 @@ program
|
|
|
15
17
|
.alias("agentsway")
|
|
16
18
|
.alias("agent-tui")
|
|
17
19
|
.description("First-class command line interface for Agent API")
|
|
20
|
+
.argument("[workdir]", "local workdir to open and expose to the agent")
|
|
18
21
|
.version(cliVersion)
|
|
19
22
|
.showHelpAfterError()
|
|
20
23
|
.showSuggestionAfterError();
|
|
21
|
-
program.action(async () => {
|
|
24
|
+
program.action(async (workdir) => {
|
|
25
|
+
const launchWorkdir = workdir ? await validateLaunchWorkdir(workdir) : undefined;
|
|
22
26
|
if (!process.stdin.isTTY) {
|
|
23
27
|
program.help();
|
|
24
28
|
return;
|
|
25
29
|
}
|
|
26
|
-
const options = normalizeChatOptions([], {});
|
|
30
|
+
const options = normalizeChatOptions([], launchWorkdir ? { workdir: launchWorkdir } : {});
|
|
27
31
|
const app = render(React.createElement(ChatApp, { options }));
|
|
28
32
|
await app.waitUntilExit();
|
|
29
33
|
});
|
|
@@ -306,3 +310,17 @@ function optionalNumber(value, label) {
|
|
|
306
310
|
throw new Error(`${label} must be a number`);
|
|
307
311
|
return parsed;
|
|
308
312
|
}
|
|
313
|
+
async function validateLaunchWorkdir(path) {
|
|
314
|
+
const resolved = resolve(path);
|
|
315
|
+
let info;
|
|
316
|
+
try {
|
|
317
|
+
info = await stat(resolved);
|
|
318
|
+
}
|
|
319
|
+
catch {
|
|
320
|
+
throw new Error(`Workdir does not exist: ${path}`);
|
|
321
|
+
}
|
|
322
|
+
if (!info.isDirectory()) {
|
|
323
|
+
throw new Error(`Workdir is not a directory: ${path}`);
|
|
324
|
+
}
|
|
325
|
+
return resolved;
|
|
326
|
+
}
|
package/dist/runtime/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export declare const cliName = "agent-api-cli";
|
|
2
2
|
export declare const cliAuthor = "AgentsWay";
|
|
3
|
-
export declare const cliVersion = "0.0.
|
|
3
|
+
export declare const cliVersion = "0.0.3";
|
|
4
4
|
export declare const runtime: import("@agent-api/sdk/local").LocalRuntime;
|
|
5
5
|
export declare function ensureRuntime(): Promise<import("@agent-api/sdk/local").LocalRuntime>;
|
package/dist/runtime/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createLocalRuntime } from "@agent-api/sdk/local";
|
|
2
2
|
export const cliName = "agent-api-cli";
|
|
3
3
|
export const cliAuthor = "AgentsWay";
|
|
4
|
-
export const cliVersion = "0.0.
|
|
4
|
+
export const cliVersion = "0.0.3";
|
|
5
5
|
export const runtime = createLocalRuntime({
|
|
6
6
|
appName: cliName,
|
|
7
7
|
appAuthor: cliAuthor,
|
package/dist/tui/chat.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
-
import { type AgentRunOptions } from "../agent.js";
|
|
2
|
+
import { listAvailablePresets, type AgentRunOptions } from "../agent.js";
|
|
3
3
|
export declare function ChatApp({ options }: {
|
|
4
4
|
options: AgentRunOptions;
|
|
5
5
|
}): React.JSX.Element;
|
|
6
|
+
export declare function formatPresetList(presets: Awaited<ReturnType<typeof listAvailablePresets>>, currentPreset?: string): string[];
|
package/dist/tui/chat.js
CHANGED
|
@@ -5,7 +5,7 @@ import { defaultBaseURL, loadWorkbenchPreferences, updateWorkbenchPreferences, }
|
|
|
5
5
|
import { conversationSummary, clearPresetToolCatalogCache, deleteConversation, isAvailablePreset, listAvailablePresets, listConversations, resumeAgentAfterLocalApproval, runAgentTurn, } from "../agent.js";
|
|
6
6
|
import { openWorkdir, } from "../workdir/index.js";
|
|
7
7
|
import { createLocalShellToolRegistry, createLocalWorkdirToolRegistry } from "@agent-api/sdk/local";
|
|
8
|
-
import { activityColor, createInitialWorkbenchState, formatBytes, helpText, parsePendingApprovalCommand, parseWorkbenchCommand, workbenchReducer, workdirText, } from "./workbench.js";
|
|
8
|
+
import { activityColor, createInputHistory, createInitialWorkbenchState, formatBytes, helpText, parsePendingApprovalCommand, parseWorkbenchCommand, workbenchReducer, workdirText, } from "./workbench.js";
|
|
9
9
|
import { deleteProfile, formatDeviceUserCode, getAuthStatus, loginWithAPIKey, openBrowserURL, refreshActiveProfileIfNeeded, resolveRuntimeProfile, saveBrowserProfile, startBrowserAuthChallenge, waitForBrowserAuthChallenge, } from "../profile.js";
|
|
10
10
|
import { checkForUpdate, formatUpdateNotice } from "../update.js";
|
|
11
11
|
export function ChatApp({ options }) {
|
|
@@ -254,6 +254,7 @@ function WorkbenchApp({ onLogin, onLogout, onDeleteProfile, onSwitchProfile, opt
|
|
|
254
254
|
const activeResponseIDRef = useRef(null);
|
|
255
255
|
const cancelledResponseIDsRef = useRef(new Set());
|
|
256
256
|
const updateNoticeShownRef = useRef(false);
|
|
257
|
+
const inputHistoryRef = useRef(createInputHistory());
|
|
257
258
|
const [draft, setDraft] = useState("");
|
|
258
259
|
const [spinnerFrame, setSpinnerFrame] = useState(0);
|
|
259
260
|
const [runPreset, setRunPreset] = useState(options.preset);
|
|
@@ -371,6 +372,14 @@ function WorkbenchApp({ onLogin, onLogout, onDeleteProfile, onSwitchProfile, opt
|
|
|
371
372
|
app.exit();
|
|
372
373
|
return;
|
|
373
374
|
}
|
|
375
|
+
if (key.upArrow) {
|
|
376
|
+
setDraft((current) => inputHistoryRef.current.previous(current));
|
|
377
|
+
return;
|
|
378
|
+
}
|
|
379
|
+
if (key.downArrow) {
|
|
380
|
+
setDraft((current) => inputHistoryRef.current.next(current));
|
|
381
|
+
return;
|
|
382
|
+
}
|
|
374
383
|
if (state.busy) {
|
|
375
384
|
if (key.escape) {
|
|
376
385
|
void abortActiveTurn("Abort requested.");
|
|
@@ -378,6 +387,7 @@ function WorkbenchApp({ onLogin, onLogout, onDeleteProfile, onSwitchProfile, opt
|
|
|
378
387
|
}
|
|
379
388
|
if (key.return) {
|
|
380
389
|
const command = draft.trim();
|
|
390
|
+
inputHistoryRef.current.record(command);
|
|
381
391
|
setDraft("");
|
|
382
392
|
if (command === "/abort" || command === "/cancel") {
|
|
383
393
|
void abortActiveTurn("Abort requested.");
|
|
@@ -390,10 +400,12 @@ function WorkbenchApp({ onLogin, onLogout, onDeleteProfile, onSwitchProfile, opt
|
|
|
390
400
|
return;
|
|
391
401
|
}
|
|
392
402
|
if (key.backspace || key.delete) {
|
|
403
|
+
inputHistoryRef.current.reset();
|
|
393
404
|
setDraft((current) => current.slice(0, -1));
|
|
394
405
|
return;
|
|
395
406
|
}
|
|
396
407
|
if (input && !key.ctrl && !key.meta) {
|
|
408
|
+
inputHistoryRef.current.reset();
|
|
397
409
|
setDraft((current) => current + input);
|
|
398
410
|
}
|
|
399
411
|
return;
|
|
@@ -402,15 +414,18 @@ function WorkbenchApp({ onLogin, onLogout, onDeleteProfile, onSwitchProfile, opt
|
|
|
402
414
|
const prompt = draft.trim();
|
|
403
415
|
if (!prompt)
|
|
404
416
|
return;
|
|
417
|
+
inputHistoryRef.current.record(prompt);
|
|
405
418
|
setDraft("");
|
|
406
419
|
void submit(prompt);
|
|
407
420
|
return;
|
|
408
421
|
}
|
|
409
422
|
if (key.backspace || key.delete) {
|
|
423
|
+
inputHistoryRef.current.reset();
|
|
410
424
|
setDraft((current) => current.slice(0, -1));
|
|
411
425
|
return;
|
|
412
426
|
}
|
|
413
427
|
if (input && !key.ctrl && !key.meta) {
|
|
428
|
+
inputHistoryRef.current.reset();
|
|
414
429
|
setDraft((current) => current + input);
|
|
415
430
|
}
|
|
416
431
|
});
|
|
@@ -699,7 +714,7 @@ function WorkbenchApp({ onLogin, onLogout, onDeleteProfile, onSwitchProfile, opt
|
|
|
699
714
|
prefix,
|
|
700
715
|
"",
|
|
701
716
|
"Available presets:",
|
|
702
|
-
...formatPresetList(presets),
|
|
717
|
+
...formatPresetList(presets, runPreset),
|
|
703
718
|
].join("\n");
|
|
704
719
|
}
|
|
705
720
|
catch (error) {
|
|
@@ -1208,12 +1223,13 @@ function effectiveDefaultPreset(preferences, builtInPreset) {
|
|
|
1208
1223
|
return preferences.defaultPreset ?? undefined;
|
|
1209
1224
|
return builtInPreset;
|
|
1210
1225
|
}
|
|
1211
|
-
function formatPresetList(presets) {
|
|
1226
|
+
export function formatPresetList(presets, currentPreset) {
|
|
1212
1227
|
if (presets.length === 0)
|
|
1213
1228
|
return ["- none returned by this endpoint"];
|
|
1214
1229
|
return presets.map((preset) => {
|
|
1215
1230
|
const description = preset.description ? ` - ${preset.description}` : "";
|
|
1216
|
-
|
|
1231
|
+
const current = currentPreset && preset.preset === currentPreset;
|
|
1232
|
+
return `${current ? "*" : "-"} ${preset.preset}${current ? " (current)" : ""}${description}`;
|
|
1217
1233
|
});
|
|
1218
1234
|
}
|
|
1219
1235
|
function authStatusText(status) {
|
package/dist/tui/workbench.d.ts
CHANGED
|
@@ -34,6 +34,13 @@ export interface WorkbenchState {
|
|
|
34
34
|
accessMode: WorkdirAccessMode;
|
|
35
35
|
currentConversation: string;
|
|
36
36
|
}
|
|
37
|
+
export interface InputHistory {
|
|
38
|
+
record(value: string): void;
|
|
39
|
+
previous(currentDraft: string): string;
|
|
40
|
+
next(currentDraft: string): string;
|
|
41
|
+
reset(): void;
|
|
42
|
+
values(): string[];
|
|
43
|
+
}
|
|
37
44
|
export type WorkbenchAction = {
|
|
38
45
|
type: "message.add";
|
|
39
46
|
role: WorkbenchRole;
|
|
@@ -145,6 +152,7 @@ export declare function createInitialWorkbenchState(options: {
|
|
|
145
152
|
accessMode?: WorkdirAccessMode;
|
|
146
153
|
conversation?: string;
|
|
147
154
|
}): WorkbenchState;
|
|
155
|
+
export declare function createInputHistory(limit?: number): InputHistory;
|
|
148
156
|
export declare function workbenchReducer(state: WorkbenchState, action: WorkbenchAction): WorkbenchState;
|
|
149
157
|
export declare function parseWorkbenchCommand(input: string): WorkbenchCommand | null;
|
|
150
158
|
export declare function parsePendingApprovalCommand(input: string): WorkbenchCommand | null;
|
package/dist/tui/workbench.js
CHANGED
|
@@ -16,6 +16,56 @@ export function createInitialWorkbenchState(options) {
|
|
|
16
16
|
currentConversation: options.conversation || "default",
|
|
17
17
|
};
|
|
18
18
|
}
|
|
19
|
+
export function createInputHistory(limit = 100) {
|
|
20
|
+
const entries = [];
|
|
21
|
+
let cursor = null;
|
|
22
|
+
let draftBeforeBrowse = "";
|
|
23
|
+
return {
|
|
24
|
+
record(value) {
|
|
25
|
+
const trimmed = value.trim();
|
|
26
|
+
if (!trimmed)
|
|
27
|
+
return;
|
|
28
|
+
if (entries.at(-1) !== trimmed) {
|
|
29
|
+
entries.push(trimmed);
|
|
30
|
+
if (entries.length > limit)
|
|
31
|
+
entries.splice(0, entries.length - limit);
|
|
32
|
+
}
|
|
33
|
+
cursor = null;
|
|
34
|
+
draftBeforeBrowse = "";
|
|
35
|
+
},
|
|
36
|
+
previous(currentDraft) {
|
|
37
|
+
if (entries.length === 0)
|
|
38
|
+
return currentDraft;
|
|
39
|
+
if (cursor === null) {
|
|
40
|
+
draftBeforeBrowse = currentDraft;
|
|
41
|
+
cursor = entries.length - 1;
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
cursor = Math.max(0, cursor - 1);
|
|
45
|
+
}
|
|
46
|
+
return entries[cursor] ?? currentDraft;
|
|
47
|
+
},
|
|
48
|
+
next(currentDraft) {
|
|
49
|
+
if (entries.length === 0 || cursor === null)
|
|
50
|
+
return currentDraft;
|
|
51
|
+
if (cursor < entries.length - 1) {
|
|
52
|
+
cursor += 1;
|
|
53
|
+
return entries[cursor] ?? currentDraft;
|
|
54
|
+
}
|
|
55
|
+
cursor = null;
|
|
56
|
+
const restored = draftBeforeBrowse;
|
|
57
|
+
draftBeforeBrowse = "";
|
|
58
|
+
return restored;
|
|
59
|
+
},
|
|
60
|
+
reset() {
|
|
61
|
+
cursor = null;
|
|
62
|
+
draftBeforeBrowse = "";
|
|
63
|
+
},
|
|
64
|
+
values() {
|
|
65
|
+
return [...entries];
|
|
66
|
+
},
|
|
67
|
+
};
|
|
68
|
+
}
|
|
19
69
|
export function workbenchReducer(state, action) {
|
|
20
70
|
switch (action.type) {
|
|
21
71
|
case "message.add":
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agent-api/cli",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.3",
|
|
4
4
|
"description": "First-class command line interface for Agent API",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"homepage": "https://github.com/scalebox-dev/agent-tui#readme",
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
"scripts": {
|
|
21
21
|
"sync-version": "node scripts/sync-version.mjs",
|
|
22
22
|
"clean": "node -e \"require('node:fs').rmSync('dist',{recursive:true,force:true})\"",
|
|
23
|
-
"build": "npm run clean && tsc -p tsconfig.json",
|
|
23
|
+
"build": "npm run clean && tsc -p tsconfig.json && node scripts/prepare-bin.mjs",
|
|
24
24
|
"dev": "npm run build && node dist/index.js",
|
|
25
25
|
"dev:link": "node scripts/dev-link.mjs",
|
|
26
26
|
"start": "node dist/index.js",
|