@agent-api/cli 0.2.1 → 0.3.0
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 -5
- package/dist/index.js +8 -6
- package/dist/runtime.d.ts +4 -0
- package/dist/runtime.js +4 -0
- package/dist/tui/ink/app.d.ts +1 -1
- package/dist/tui/ink/app.js +27 -130
- package/dist/tui/ink/components.d.ts +1 -2
- package/dist/tui/ink/components.js +1 -3
- package/package.json +9 -6
- package/dist/agent/runner.d.ts +0 -117
- package/dist/agent/runner.js +0 -486
- package/dist/agent.d.ts +0 -2
- package/dist/agent.js +0 -2
- package/dist/chat-options.d.ts +0 -37
- package/dist/chat-options.js +0 -42
- package/dist/config.d.ts +0 -66
- package/dist/config.js +0 -201
- package/dist/conversation/index.d.ts +0 -17
- package/dist/conversation/index.js +0 -54
- package/dist/profile.d.ts +0 -57
- package/dist/profile.js +0 -211
- package/dist/runtime/index.d.ts +0 -5
- package/dist/runtime/index.js +0 -152
- package/dist/tui/workbench.d.ts +0 -187
- package/dist/tui/workbench.js +0 -392
- package/dist/update.d.ts +0 -16
- package/dist/update.js +0 -74
- package/dist/workbench/auth-controller.d.ts +0 -43
- package/dist/workbench/auth-controller.js +0 -84
- package/dist/workbench/auth-gate-controller.d.ts +0 -62
- package/dist/workbench/auth-gate-controller.js +0 -231
- package/dist/workbench/command-controller.d.ts +0 -29
- package/dist/workbench/command-controller.js +0 -426
- package/dist/workbench/conversation-controller.d.ts +0 -32
- package/dist/workbench/conversation-controller.js +0 -53
- package/dist/workbench/engine.d.ts +0 -66
- package/dist/workbench/engine.js +0 -291
- package/dist/workbench/input-controller.d.ts +0 -44
- package/dist/workbench/input-controller.js +0 -71
- package/dist/workbench/isolator-installer.d.ts +0 -29
- package/dist/workbench/isolator-installer.js +0 -208
- package/dist/workbench/lifecycle-controller.d.ts +0 -30
- package/dist/workbench/lifecycle-controller.js +0 -75
- package/dist/workbench/local-controller.d.ts +0 -21
- package/dist/workbench/local-controller.js +0 -94
- package/dist/workbench/render-model.d.ts +0 -46
- package/dist/workbench/render-model.js +0 -61
- package/dist/workbench/runtime-controller.d.ts +0 -12
- package/dist/workbench/runtime-controller.js +0 -57
- package/dist/workbench/session.d.ts +0 -27
- package/dist/workbench/session.js +0 -42
- package/dist/workbench/settings-controller.d.ts +0 -80
- package/dist/workbench/settings-controller.js +0 -309
- package/dist/workbench/shell-isolation.d.ts +0 -20
- package/dist/workbench/shell-isolation.js +0 -13
- package/dist/workbench/turn-controller.d.ts +0 -25
- package/dist/workbench/turn-controller.js +0 -164
- package/dist/workbench/view-model.d.ts +0 -34
- package/dist/workbench/view-model.js +0 -121
- package/dist/workdir/index.d.ts +0 -22
- package/dist/workdir/index.js +0 -46
package/dist/config.js
DELETED
|
@@ -1,201 +0,0 @@
|
|
|
1
|
-
import { z } from "zod";
|
|
2
|
-
import { ensureRuntime, runtime } from "./runtime/index.js";
|
|
3
|
-
export const defaultBaseURL = "https://api.agentsway.dev";
|
|
4
|
-
export const configFile = "profiles.json";
|
|
5
|
-
export const appConfigurationFile = "configuration.json";
|
|
6
|
-
export const conversationsFile = "conversations.json";
|
|
7
|
-
const authProfileSchema = z.discriminatedUnion("type", [
|
|
8
|
-
z.object({
|
|
9
|
-
type: z.literal("api_key"),
|
|
10
|
-
apiKey: z.string(),
|
|
11
|
-
}),
|
|
12
|
-
z.object({
|
|
13
|
-
type: z.literal("browser"),
|
|
14
|
-
accessToken: z.string(),
|
|
15
|
-
refreshToken: z.string(),
|
|
16
|
-
accessTokenExpiresAt: z.number(),
|
|
17
|
-
refreshTokenExpiresAt: z.number().optional(),
|
|
18
|
-
}),
|
|
19
|
-
]);
|
|
20
|
-
const profileSchema = z.object({
|
|
21
|
-
name: z.string(),
|
|
22
|
-
baseURL: z.string(),
|
|
23
|
-
auth: authProfileSchema,
|
|
24
|
-
createdAt: z.number(),
|
|
25
|
-
updatedAt: z.number(),
|
|
26
|
-
});
|
|
27
|
-
const conversationSchema = z.object({
|
|
28
|
-
name: z.string(),
|
|
29
|
-
profile: z.string(),
|
|
30
|
-
previousResponseId: z.string().optional(),
|
|
31
|
-
updatedAt: z.number(),
|
|
32
|
-
});
|
|
33
|
-
const workbenchPreferencesSchema = z.object({
|
|
34
|
-
defaultPreset: z.string().nullable().optional(),
|
|
35
|
-
isolation: z.object({
|
|
36
|
-
mode: z.enum(["none", "auto", "required"]).optional(),
|
|
37
|
-
executablePath: z.string().nullable().optional(),
|
|
38
|
-
version: z.string().nullable().optional(),
|
|
39
|
-
sourceURL: z.string().nullable().optional(),
|
|
40
|
-
sha256: z.string().nullable().optional(),
|
|
41
|
-
installSkipped: z.boolean().nullable().optional(),
|
|
42
|
-
}).optional(),
|
|
43
|
-
}).default({});
|
|
44
|
-
const cliConfigSchema = z.object({
|
|
45
|
-
activeProfile: z.string().default("default"),
|
|
46
|
-
profiles: z.record(z.string(), profileSchema).default({}),
|
|
47
|
-
conversations: z.record(z.string(), conversationSchema).default({}),
|
|
48
|
-
});
|
|
49
|
-
const appConfigurationSchema = z.object({
|
|
50
|
-
workbench: workbenchPreferencesSchema,
|
|
51
|
-
});
|
|
52
|
-
const conversationConfigurationSchema = z.object({
|
|
53
|
-
conversations: z.record(z.string(), conversationSchema).default({}),
|
|
54
|
-
});
|
|
55
|
-
export async function loadConfig() {
|
|
56
|
-
await ensureRuntime();
|
|
57
|
-
const loaded = await runtime.config.read(configFile, emptyConfig());
|
|
58
|
-
const parsed = cliConfigSchema.safeParse(loaded);
|
|
59
|
-
if (!parsed.success) {
|
|
60
|
-
throw new Error(`Invalid CLI config: ${parsed.error.issues.map((issue) => issue.message).join("; ")}`);
|
|
61
|
-
}
|
|
62
|
-
return parsed.data;
|
|
63
|
-
}
|
|
64
|
-
export async function saveConfig(config) {
|
|
65
|
-
await ensureRuntime();
|
|
66
|
-
await runtime.config.write(configFile, {
|
|
67
|
-
activeProfile: config.activeProfile,
|
|
68
|
-
profiles: config.profiles,
|
|
69
|
-
});
|
|
70
|
-
}
|
|
71
|
-
export async function loadAppConfiguration() {
|
|
72
|
-
await ensureRuntime();
|
|
73
|
-
const loaded = await runtime.config.read(appConfigurationFile, emptyAppConfiguration());
|
|
74
|
-
const parsed = appConfigurationSchema.safeParse(loaded);
|
|
75
|
-
if (!parsed.success) {
|
|
76
|
-
throw new Error(`Invalid app configuration: ${parsed.error.issues.map((issue) => issue.message).join("; ")}`);
|
|
77
|
-
}
|
|
78
|
-
return parsed.data;
|
|
79
|
-
}
|
|
80
|
-
export async function saveAppConfiguration(config) {
|
|
81
|
-
await ensureRuntime();
|
|
82
|
-
await runtime.config.write(appConfigurationFile, config);
|
|
83
|
-
}
|
|
84
|
-
export async function loadConversationConfiguration() {
|
|
85
|
-
await ensureRuntime();
|
|
86
|
-
const loaded = await runtime.config.read(conversationsFile, emptyConversationConfiguration());
|
|
87
|
-
const parsed = conversationConfigurationSchema.safeParse(loaded);
|
|
88
|
-
if (!parsed.success) {
|
|
89
|
-
throw new Error(`Invalid conversation configuration: ${parsed.error.issues.map((issue) => issue.message).join("; ")}`);
|
|
90
|
-
}
|
|
91
|
-
return parsed.data;
|
|
92
|
-
}
|
|
93
|
-
export async function saveConversationConfiguration(config) {
|
|
94
|
-
await ensureRuntime();
|
|
95
|
-
await runtime.config.write(conversationsFile, config);
|
|
96
|
-
}
|
|
97
|
-
export async function upsertProfile(profile) {
|
|
98
|
-
const config = await loadConfig();
|
|
99
|
-
const now = Math.floor(Date.now() / 1000);
|
|
100
|
-
const existing = config.profiles[profile.name];
|
|
101
|
-
const next = {
|
|
102
|
-
...profile,
|
|
103
|
-
createdAt: existing?.createdAt ?? now,
|
|
104
|
-
updatedAt: now,
|
|
105
|
-
};
|
|
106
|
-
config.profiles[profile.name] = next;
|
|
107
|
-
config.activeProfile = profile.name;
|
|
108
|
-
await saveConfig(config);
|
|
109
|
-
return next;
|
|
110
|
-
}
|
|
111
|
-
export async function activeProfile(profileName) {
|
|
112
|
-
const config = await loadConfig();
|
|
113
|
-
const name = profileName || config.activeProfile || "default";
|
|
114
|
-
const profile = config.profiles[name];
|
|
115
|
-
if (!profile) {
|
|
116
|
-
throw new Error(`Profile not found: ${name}. Run agent-api login first.`);
|
|
117
|
-
}
|
|
118
|
-
return profile;
|
|
119
|
-
}
|
|
120
|
-
export function emptyConfig() {
|
|
121
|
-
return { activeProfile: "default", profiles: {} };
|
|
122
|
-
}
|
|
123
|
-
export function emptyAppConfiguration() {
|
|
124
|
-
return { workbench: {} };
|
|
125
|
-
}
|
|
126
|
-
export function emptyConversationConfiguration() {
|
|
127
|
-
return { conversations: {} };
|
|
128
|
-
}
|
|
129
|
-
export async function loadWorkbenchPreferences() {
|
|
130
|
-
const appConfig = await loadAppConfiguration();
|
|
131
|
-
return appConfig.workbench;
|
|
132
|
-
}
|
|
133
|
-
export async function updateWorkbenchPreferences(patch) {
|
|
134
|
-
const appConfig = await loadAppConfiguration();
|
|
135
|
-
const next = { ...appConfig.workbench };
|
|
136
|
-
if ("defaultPreset" in patch) {
|
|
137
|
-
if (patch.defaultPreset === undefined) {
|
|
138
|
-
delete next.defaultPreset;
|
|
139
|
-
}
|
|
140
|
-
else if (patch.defaultPreset === null) {
|
|
141
|
-
next.defaultPreset = null;
|
|
142
|
-
}
|
|
143
|
-
else {
|
|
144
|
-
const value = patch.defaultPreset.trim();
|
|
145
|
-
if (value) {
|
|
146
|
-
next.defaultPreset = value;
|
|
147
|
-
}
|
|
148
|
-
else {
|
|
149
|
-
delete next.defaultPreset;
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
if ("isolation" in patch) {
|
|
154
|
-
next.isolation = updateIsolationPreferences(next.isolation, patch.isolation);
|
|
155
|
-
}
|
|
156
|
-
appConfig.workbench = next;
|
|
157
|
-
await saveAppConfiguration(appConfig);
|
|
158
|
-
return next;
|
|
159
|
-
}
|
|
160
|
-
function updateIsolationPreferences(current, patch) {
|
|
161
|
-
const next = { ...(current ?? {}) };
|
|
162
|
-
if (!patch)
|
|
163
|
-
return Object.keys(next).length > 0 ? next : undefined;
|
|
164
|
-
if ("mode" in patch) {
|
|
165
|
-
if (patch.mode === null || patch.mode === undefined) {
|
|
166
|
-
delete next.mode;
|
|
167
|
-
}
|
|
168
|
-
else {
|
|
169
|
-
next.mode = patch.mode;
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
for (const key of ["executablePath", "version", "sourceURL", "sha256"]) {
|
|
173
|
-
if (key in patch) {
|
|
174
|
-
const value = patch[key];
|
|
175
|
-
if (value === undefined || value === null) {
|
|
176
|
-
delete next[key];
|
|
177
|
-
}
|
|
178
|
-
else {
|
|
179
|
-
const trimmed = value.trim();
|
|
180
|
-
if (trimmed)
|
|
181
|
-
next[key] = trimmed;
|
|
182
|
-
else
|
|
183
|
-
delete next[key];
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
if ("installSkipped" in patch) {
|
|
188
|
-
if (patch.installSkipped === undefined || patch.installSkipped === null) {
|
|
189
|
-
delete next.installSkipped;
|
|
190
|
-
}
|
|
191
|
-
else {
|
|
192
|
-
next.installSkipped = patch.installSkipped;
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
return Object.keys(next).length > 0 ? next : undefined;
|
|
196
|
-
}
|
|
197
|
-
export function redactSecret(value) {
|
|
198
|
-
if (value.length <= 10)
|
|
199
|
-
return "***";
|
|
200
|
-
return `${value.slice(0, 6)}…${value.slice(-4)}`;
|
|
201
|
-
}
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import type { ConversationState } from "../config.js";
|
|
2
|
-
export declare function conversationKey(profile: string, name: string): string;
|
|
3
|
-
export declare function resolvePreviousResponseID(options: {
|
|
4
|
-
profile?: string;
|
|
5
|
-
conversation?: string;
|
|
6
|
-
continueConversation?: boolean;
|
|
7
|
-
restartConversation?: boolean;
|
|
8
|
-
previousResponseId?: string;
|
|
9
|
-
}): Promise<string | undefined>;
|
|
10
|
-
export declare function updateConversation(options: {
|
|
11
|
-
profile?: string;
|
|
12
|
-
conversation?: string;
|
|
13
|
-
}, responseID: string): Promise<void>;
|
|
14
|
-
export declare function listConversations(profileName?: string): Promise<ConversationState[]>;
|
|
15
|
-
export declare function getConversation(name: string, profileName?: string): Promise<ConversationState>;
|
|
16
|
-
export declare function deleteConversation(name: string, profileName?: string): Promise<void>;
|
|
17
|
-
export declare function conversationSummary(conversation: ConversationState): string;
|
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
import { activeProfile, loadConversationConfiguration, saveConversationConfiguration } from "../config.js";
|
|
2
|
-
export function conversationKey(profile, name) {
|
|
3
|
-
return `${profile}:${name}`;
|
|
4
|
-
}
|
|
5
|
-
export async function resolvePreviousResponseID(options) {
|
|
6
|
-
if (options.previousResponseId)
|
|
7
|
-
return options.previousResponseId;
|
|
8
|
-
if (options.restartConversation || !options.conversation)
|
|
9
|
-
return undefined;
|
|
10
|
-
if (!options.continueConversation)
|
|
11
|
-
return undefined;
|
|
12
|
-
const profile = await activeProfile(options.profile);
|
|
13
|
-
const config = await loadConversationConfiguration();
|
|
14
|
-
return config.conversations[conversationKey(profile.name, options.conversation)]?.previousResponseId;
|
|
15
|
-
}
|
|
16
|
-
export async function updateConversation(options, responseID) {
|
|
17
|
-
if (!options.conversation)
|
|
18
|
-
return;
|
|
19
|
-
const profile = await activeProfile(options.profile);
|
|
20
|
-
const config = await loadConversationConfiguration();
|
|
21
|
-
config.conversations[conversationKey(profile.name, options.conversation)] = {
|
|
22
|
-
name: options.conversation,
|
|
23
|
-
profile: profile.name,
|
|
24
|
-
previousResponseId: responseID,
|
|
25
|
-
updatedAt: Math.floor(Date.now() / 1000),
|
|
26
|
-
};
|
|
27
|
-
await saveConversationConfiguration(config);
|
|
28
|
-
}
|
|
29
|
-
export async function listConversations(profileName) {
|
|
30
|
-
const profile = await activeProfile(profileName);
|
|
31
|
-
const config = await loadConversationConfiguration();
|
|
32
|
-
return Object.values(config.conversations)
|
|
33
|
-
.filter((conversation) => conversation.profile === profile.name)
|
|
34
|
-
.sort((a, b) => b.updatedAt - a.updatedAt);
|
|
35
|
-
}
|
|
36
|
-
export async function getConversation(name, profileName) {
|
|
37
|
-
const profile = await activeProfile(profileName);
|
|
38
|
-
const config = await loadConversationConfiguration();
|
|
39
|
-
const conversation = config.conversations[conversationKey(profile.name, name)];
|
|
40
|
-
if (!conversation)
|
|
41
|
-
throw new Error(`Conversation not found: ${name}`);
|
|
42
|
-
return conversation;
|
|
43
|
-
}
|
|
44
|
-
export async function deleteConversation(name, profileName) {
|
|
45
|
-
const profile = await activeProfile(profileName);
|
|
46
|
-
const config = await loadConversationConfiguration();
|
|
47
|
-
delete config.conversations[conversationKey(profile.name, name)];
|
|
48
|
-
await saveConversationConfiguration(config);
|
|
49
|
-
}
|
|
50
|
-
export function conversationSummary(conversation) {
|
|
51
|
-
const updated = new Date(conversation.updatedAt * 1000).toISOString();
|
|
52
|
-
const response = conversation.previousResponseId ? ` response=${conversation.previousResponseId}` : "";
|
|
53
|
-
return `${conversation.name}\t${conversation.profile}\t${updated}${response}`;
|
|
54
|
-
}
|
package/dist/profile.d.ts
DELETED
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
import { AgentAPI, type ApprovedDeviceAuth } from "@agent-api/sdk";
|
|
2
|
-
import { Profile } from "./config.js";
|
|
3
|
-
export interface RuntimeProfile {
|
|
4
|
-
profile: Profile;
|
|
5
|
-
token: string;
|
|
6
|
-
client: AgentAPI;
|
|
7
|
-
}
|
|
8
|
-
export interface AuthStatus {
|
|
9
|
-
profile: string;
|
|
10
|
-
baseURL: string;
|
|
11
|
-
authType: Profile["auth"]["type"];
|
|
12
|
-
me?: unknown;
|
|
13
|
-
}
|
|
14
|
-
export declare class AuthSessionExpiredError extends Error {
|
|
15
|
-
readonly profile: string;
|
|
16
|
-
readonly baseURL: string;
|
|
17
|
-
constructor(profile: Profile, message?: string);
|
|
18
|
-
}
|
|
19
|
-
export declare function loginWithAPIKey(options: {
|
|
20
|
-
profile: string;
|
|
21
|
-
baseURL?: string;
|
|
22
|
-
apiKey: string;
|
|
23
|
-
}): Promise<Profile>;
|
|
24
|
-
export declare function loginWithBrowser(options: {
|
|
25
|
-
profile: string;
|
|
26
|
-
baseURL?: string;
|
|
27
|
-
clientName?: string;
|
|
28
|
-
openBrowser?: boolean;
|
|
29
|
-
}): Promise<Profile>;
|
|
30
|
-
export declare function startBrowserAuthChallenge(options: {
|
|
31
|
-
baseURL?: string;
|
|
32
|
-
clientName?: string;
|
|
33
|
-
}): Promise<import("@agent-api/sdk").DeviceAuthStart>;
|
|
34
|
-
export declare function waitForBrowserAuthChallenge(options: {
|
|
35
|
-
baseURL?: string;
|
|
36
|
-
challenge: Awaited<ReturnType<typeof startBrowserAuthChallenge>>;
|
|
37
|
-
on_poll?: Parameters<AgentAPI["auth"]["waitForDeviceAuth"]>[0]["on_poll"];
|
|
38
|
-
}): Promise<ApprovedDeviceAuth>;
|
|
39
|
-
export declare function saveBrowserProfile(name: string, baseURL: string, session: ApprovedDeviceAuth): Promise<Profile>;
|
|
40
|
-
export declare function resolveRuntimeProfile(profileName?: string): Promise<RuntimeProfile>;
|
|
41
|
-
export declare function getAuthStatus(profileName?: string): Promise<AuthStatus>;
|
|
42
|
-
export declare function refreshActiveProfileIfNeeded(profileName?: string, refreshWindowMs?: number): Promise<{
|
|
43
|
-
profile: Profile;
|
|
44
|
-
refreshed: boolean;
|
|
45
|
-
}>;
|
|
46
|
-
export declare function refreshIfNeeded(profile: Profile, refreshWindowMs?: number): Promise<Profile>;
|
|
47
|
-
export declare function browserAccessTokenExpiresWithin(profile: Profile, refreshWindowMs: number, now?: number): boolean;
|
|
48
|
-
export declare function refreshBrowserSession(profile: Profile): Promise<Profile>;
|
|
49
|
-
export declare function listProfiles(): Promise<{
|
|
50
|
-
active: string;
|
|
51
|
-
profiles: Profile[];
|
|
52
|
-
}>;
|
|
53
|
-
export declare function useProfile(name: string): Promise<void>;
|
|
54
|
-
export declare function deleteProfile(name: string): Promise<void>;
|
|
55
|
-
export declare function profileSummary(profile: Profile, active?: boolean): string;
|
|
56
|
-
export declare function formatDeviceUserCode(code: string): string;
|
|
57
|
-
export declare function openBrowserURL(url: string): Promise<void>;
|
package/dist/profile.js
DELETED
|
@@ -1,211 +0,0 @@
|
|
|
1
|
-
import { AgentAPI, browserAuthSessionExpiresWithin } from "@agent-api/sdk";
|
|
2
|
-
import { execFile } from "node:child_process";
|
|
3
|
-
import { platform } from "node:os";
|
|
4
|
-
import { promisify } from "node:util";
|
|
5
|
-
import { activeProfile, defaultBaseURL, loadConfig, redactSecret, saveConfig, upsertProfile, } from "./config.js";
|
|
6
|
-
const execFileAsync = promisify(execFile);
|
|
7
|
-
export class AuthSessionExpiredError extends Error {
|
|
8
|
-
profile;
|
|
9
|
-
baseURL;
|
|
10
|
-
constructor(profile, message = "browser session refresh failed") {
|
|
11
|
-
super([
|
|
12
|
-
"Browser session expired or could not be refreshed.",
|
|
13
|
-
`Run: agent-api auth login --profile ${profile.name} --base-url ${profile.baseURL}`,
|
|
14
|
-
`Details: ${message}`,
|
|
15
|
-
].join("\n"));
|
|
16
|
-
this.name = "AuthSessionExpiredError";
|
|
17
|
-
this.profile = profile.name;
|
|
18
|
-
this.baseURL = profile.baseURL;
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
export async function loginWithAPIKey(options) {
|
|
22
|
-
const profile = await upsertProfile({
|
|
23
|
-
name: options.profile,
|
|
24
|
-
baseURL: normalizeBaseURL(options.baseURL),
|
|
25
|
-
auth: { type: "api_key", apiKey: options.apiKey.trim() },
|
|
26
|
-
});
|
|
27
|
-
return profile;
|
|
28
|
-
}
|
|
29
|
-
export async function loginWithBrowser(options) {
|
|
30
|
-
const baseURL = normalizeBaseURL(options.baseURL);
|
|
31
|
-
const challenge = await startBrowserAuthChallenge({ baseURL, clientName: options.clientName });
|
|
32
|
-
console.log(`Open this URL to authorize the CLI:\n${challenge.verification_uri_complete}\n`);
|
|
33
|
-
console.log(`Code: ${formatDeviceUserCode(challenge.user_code)}\n`);
|
|
34
|
-
if (options.openBrowser !== false) {
|
|
35
|
-
await openBrowserURL(challenge.verification_uri_complete).catch((error) => {
|
|
36
|
-
console.warn(`Could not open browser automatically: ${error instanceof Error ? error.message : String(error)}`);
|
|
37
|
-
});
|
|
38
|
-
}
|
|
39
|
-
console.log("Waiting for browser approval...");
|
|
40
|
-
const session = await waitForBrowserAuthChallenge({
|
|
41
|
-
baseURL,
|
|
42
|
-
challenge,
|
|
43
|
-
on_poll(result) {
|
|
44
|
-
if (result.status && result.status !== "pending") {
|
|
45
|
-
console.log(`Status: ${result.status}`);
|
|
46
|
-
}
|
|
47
|
-
},
|
|
48
|
-
});
|
|
49
|
-
const profile = await saveBrowserProfile(options.profile, baseURL, session);
|
|
50
|
-
console.log(`Signed in as profile "${profile.name}".`);
|
|
51
|
-
return profile;
|
|
52
|
-
}
|
|
53
|
-
export async function startBrowserAuthChallenge(options) {
|
|
54
|
-
const baseURL = normalizeBaseURL(options.baseURL);
|
|
55
|
-
const client = new AgentAPI({ baseURL });
|
|
56
|
-
return await client.auth.startDeviceAuth({ client_name: options.clientName || "Agent API CLI" });
|
|
57
|
-
}
|
|
58
|
-
export async function waitForBrowserAuthChallenge(options) {
|
|
59
|
-
const baseURL = normalizeBaseURL(options.baseURL);
|
|
60
|
-
const client = new AgentAPI({ baseURL });
|
|
61
|
-
return await client.auth.waitForDeviceAuth({
|
|
62
|
-
device_code: options.challenge.device_code,
|
|
63
|
-
interval_seconds: options.challenge.interval_seconds,
|
|
64
|
-
timeout_ms: Math.max(0, options.challenge.expires_at * 1000 - Date.now()),
|
|
65
|
-
on_poll: options.on_poll,
|
|
66
|
-
});
|
|
67
|
-
}
|
|
68
|
-
export async function saveBrowserProfile(name, baseURL, session) {
|
|
69
|
-
return await upsertProfile({
|
|
70
|
-
name,
|
|
71
|
-
baseURL,
|
|
72
|
-
auth: {
|
|
73
|
-
type: "browser",
|
|
74
|
-
accessToken: session.access_token,
|
|
75
|
-
refreshToken: session.refresh_token,
|
|
76
|
-
accessTokenExpiresAt: session.access_token_expires_at,
|
|
77
|
-
refreshTokenExpiresAt: session.refresh_token_expires_at,
|
|
78
|
-
},
|
|
79
|
-
});
|
|
80
|
-
}
|
|
81
|
-
export async function resolveRuntimeProfile(profileName) {
|
|
82
|
-
const { profile: fresh } = await refreshActiveProfileIfNeeded(profileName);
|
|
83
|
-
const token = fresh.auth.type === "api_key" ? fresh.auth.apiKey : fresh.auth.accessToken;
|
|
84
|
-
return {
|
|
85
|
-
profile: fresh,
|
|
86
|
-
token,
|
|
87
|
-
client: new AgentAPI({ apiKey: token, baseURL: fresh.baseURL }),
|
|
88
|
-
};
|
|
89
|
-
}
|
|
90
|
-
export async function getAuthStatus(profileName) {
|
|
91
|
-
const runtime = await resolveRuntimeProfile(profileName);
|
|
92
|
-
const response = await fetch(`${runtime.profile.baseURL}/v1/me`, {
|
|
93
|
-
headers: { Authorization: `Bearer ${runtime.token}` },
|
|
94
|
-
});
|
|
95
|
-
const payload = await response.json().catch(() => undefined);
|
|
96
|
-
if (!response.ok) {
|
|
97
|
-
throw new Error(errorMessageFromPayload(payload) || `whoami failed with ${response.status}`);
|
|
98
|
-
}
|
|
99
|
-
return {
|
|
100
|
-
profile: runtime.profile.name,
|
|
101
|
-
baseURL: runtime.profile.baseURL,
|
|
102
|
-
authType: runtime.profile.auth.type,
|
|
103
|
-
me: payload,
|
|
104
|
-
};
|
|
105
|
-
}
|
|
106
|
-
export async function refreshActiveProfileIfNeeded(profileName, refreshWindowMs = 60_000) {
|
|
107
|
-
const profile = await activeProfile(profileName);
|
|
108
|
-
const shouldRefresh = browserAccessTokenExpiresWithin(profile, refreshWindowMs);
|
|
109
|
-
const fresh = await refreshIfNeeded(profile, refreshWindowMs);
|
|
110
|
-
return { profile: fresh, refreshed: shouldRefresh && profile.auth.type === "browser" };
|
|
111
|
-
}
|
|
112
|
-
export async function refreshIfNeeded(profile, refreshWindowMs = 60_000) {
|
|
113
|
-
if (profile.auth.type !== "browser")
|
|
114
|
-
return profile;
|
|
115
|
-
const expiresAtMs = profile.auth.accessTokenExpiresAt * 1000;
|
|
116
|
-
if (expiresAtMs - Date.now() > refreshWindowMs)
|
|
117
|
-
return profile;
|
|
118
|
-
const refreshed = await refreshBrowserSession(profile);
|
|
119
|
-
const config = await loadConfig();
|
|
120
|
-
config.profiles[profile.name] = refreshed;
|
|
121
|
-
await saveConfig(config);
|
|
122
|
-
return refreshed;
|
|
123
|
-
}
|
|
124
|
-
export function browserAccessTokenExpiresWithin(profile, refreshWindowMs, now = Date.now()) {
|
|
125
|
-
if (profile.auth.type !== "browser")
|
|
126
|
-
return false;
|
|
127
|
-
return browserAuthSessionExpiresWithin({ access_token_expires_at: profile.auth.accessTokenExpiresAt }, refreshWindowMs, now);
|
|
128
|
-
}
|
|
129
|
-
export async function refreshBrowserSession(profile) {
|
|
130
|
-
if (profile.auth.type !== "browser")
|
|
131
|
-
return profile;
|
|
132
|
-
const client = new AgentAPI({ baseURL: profile.baseURL });
|
|
133
|
-
let session;
|
|
134
|
-
try {
|
|
135
|
-
session = await client.auth.refreshBrowserSession({ refresh_token: profile.auth.refreshToken });
|
|
136
|
-
}
|
|
137
|
-
catch (error) {
|
|
138
|
-
throw new AuthSessionExpiredError(profile, error instanceof Error ? error.message : String(error));
|
|
139
|
-
}
|
|
140
|
-
return {
|
|
141
|
-
...profile,
|
|
142
|
-
auth: {
|
|
143
|
-
type: "browser",
|
|
144
|
-
accessToken: session.access_token,
|
|
145
|
-
refreshToken: session.refresh_token || profile.auth.refreshToken,
|
|
146
|
-
accessTokenExpiresAt: session.access_token_expires_at,
|
|
147
|
-
refreshTokenExpiresAt: session.refresh_token_expires_at || profile.auth.refreshTokenExpiresAt,
|
|
148
|
-
},
|
|
149
|
-
updatedAt: Math.floor(Date.now() / 1000),
|
|
150
|
-
};
|
|
151
|
-
}
|
|
152
|
-
export async function listProfiles() {
|
|
153
|
-
const config = await loadConfig();
|
|
154
|
-
return { active: config.activeProfile, profiles: Object.values(config.profiles).sort((a, b) => a.name.localeCompare(b.name)) };
|
|
155
|
-
}
|
|
156
|
-
export async function useProfile(name) {
|
|
157
|
-
const config = await loadConfig();
|
|
158
|
-
if (!config.profiles[name])
|
|
159
|
-
throw new Error(`Profile not found: ${name}`);
|
|
160
|
-
config.activeProfile = name;
|
|
161
|
-
await saveConfig(config);
|
|
162
|
-
}
|
|
163
|
-
export async function deleteProfile(name) {
|
|
164
|
-
const config = await loadConfig();
|
|
165
|
-
delete config.profiles[name];
|
|
166
|
-
if (config.activeProfile === name) {
|
|
167
|
-
config.activeProfile = Object.keys(config.profiles).sort()[0] || "default";
|
|
168
|
-
}
|
|
169
|
-
await saveConfig(config);
|
|
170
|
-
}
|
|
171
|
-
export function profileSummary(profile, active = false) {
|
|
172
|
-
const auth = profile.auth.type === "api_key"
|
|
173
|
-
? `api_key ${redactSecret(profile.auth.apiKey)}`
|
|
174
|
-
: `browser ${redactSecret(profile.auth.accessToken)}`;
|
|
175
|
-
return `${active ? "*" : " "} ${profile.name}\t${profile.baseURL}\t${auth}`;
|
|
176
|
-
}
|
|
177
|
-
function errorMessageFromPayload(payload) {
|
|
178
|
-
if (payload && typeof payload === "object") {
|
|
179
|
-
const error = payload.error;
|
|
180
|
-
if (error && typeof error === "object") {
|
|
181
|
-
const message = error.message;
|
|
182
|
-
if (typeof message === "string")
|
|
183
|
-
return message;
|
|
184
|
-
}
|
|
185
|
-
const message = payload.message;
|
|
186
|
-
if (typeof message === "string")
|
|
187
|
-
return message;
|
|
188
|
-
}
|
|
189
|
-
return "";
|
|
190
|
-
}
|
|
191
|
-
function normalizeBaseURL(baseURL) {
|
|
192
|
-
return (baseURL || process.env.AGENT_API_BASE_URL || defaultBaseURL).replace(/\/+$/, "");
|
|
193
|
-
}
|
|
194
|
-
export function formatDeviceUserCode(code) {
|
|
195
|
-
const normalized = code.replace(/[-\s]/g, "").toUpperCase();
|
|
196
|
-
if (normalized.length <= 4)
|
|
197
|
-
return normalized;
|
|
198
|
-
return `${normalized.slice(0, 4)}-${normalized.slice(4)}`;
|
|
199
|
-
}
|
|
200
|
-
export async function openBrowserURL(url) {
|
|
201
|
-
const current = platform();
|
|
202
|
-
if (current === "darwin") {
|
|
203
|
-
await execFileAsync("open", [url]);
|
|
204
|
-
return;
|
|
205
|
-
}
|
|
206
|
-
if (current === "win32") {
|
|
207
|
-
await execFileAsync("cmd", ["/c", "start", "", url]);
|
|
208
|
-
return;
|
|
209
|
-
}
|
|
210
|
-
await execFileAsync("xdg-open", [url]);
|
|
211
|
-
}
|
package/dist/runtime/index.d.ts
DELETED
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
export declare const cliName = "agent-tui";
|
|
2
|
-
export declare const cliAuthor = "AgentsWay";
|
|
3
|
-
export declare const cliVersion = "0.2.1";
|
|
4
|
-
export declare const runtime: import("@agent-api/sdk/local").LocalRuntime;
|
|
5
|
-
export declare function ensureRuntime(): Promise<import("@agent-api/sdk/local").LocalRuntime>;
|