@agi_inc/cli 0.5.1 → 0.5.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 CHANGED
@@ -2,6 +2,10 @@
2
2
 
3
3
  Terminal-based AI agent for desktop automation. Give it a task in plain English and watch it take control of your computer to get it done.
4
4
 
5
+ <p align="center">
6
+ <img src="https://github.com/agi-inc/agi-cli/releases/latest/download/hero.png" alt="AGI CLI running a task" width="680">
7
+ </p>
8
+
5
9
  ```bash
6
10
  npx @agi_inc/cli "open calculator and compute 2+2"
7
11
  ```
@@ -28,9 +32,21 @@ brew install agi-inc/tap/agi
28
32
  agi "your task here"
29
33
  ```
30
34
 
31
- ## Configuration
35
+ ## Authentication
36
+
37
+ Log in with your AGI account to automatically configure your API key:
38
+
39
+ ```bash
40
+ agi login
41
+ ```
42
+
43
+ This opens a browser-based device authorization flow. Once approved, your API key is saved to `~/.agi/credentials` and used automatically.
32
44
 
33
- Set your API key before running:
45
+ ```bash
46
+ agi logout # remove stored credentials
47
+ ```
48
+
49
+ Alternatively, set your API key via environment variable:
34
50
 
35
51
  ```bash
36
52
  export AGI_API_KEY=your_api_key
@@ -54,6 +70,27 @@ agi "Install Node.js" --verbose
54
70
  agi "Delete old files" --no-confirm
55
71
  ```
56
72
 
73
+ When the agent needs approval before a destructive action, it shows a confirmation dialog:
74
+
75
+ <p align="center">
76
+ <img src="https://github.com/agi-inc/agi-cli/releases/latest/download/confirm.png" alt="AGI CLI confirmation dialog" width="680">
77
+ </p>
78
+
79
+ When the agent needs more information, it prompts with a question:
80
+
81
+ <p align="center">
82
+ <img src="https://github.com/agi-inc/agi-cli/releases/latest/download/question.png" alt="AGI CLI question dialog" width="680">
83
+ </p>
84
+
85
+ ## Commands
86
+
87
+ | Command | Description |
88
+ |---------|-------------|
89
+ | `agi "task"` | Run the agent with a task |
90
+ | `agi login` | Authenticate via browser-based device flow |
91
+ | `agi logout` | Remove stored credentials |
92
+ | `agi update` | Check for updates and self-update |
93
+
57
94
  ## Options
58
95
 
59
96
  | Option | Alias | Description | Default |
@@ -74,6 +111,22 @@ While the agent is running:
74
111
  | `Q` | Stop |
75
112
  | `Ctrl+C` | Cancel |
76
113
 
114
+ <p align="center">
115
+ <img src="https://github.com/agi-inc/agi-cli/releases/latest/download/paused.png" alt="AGI CLI paused state" width="680">
116
+ </p>
117
+
118
+ ## Updating
119
+
120
+ ```bash
121
+ agi update
122
+ ```
123
+
124
+ <p align="center">
125
+ <img src="https://github.com/agi-inc/agi-cli/releases/latest/download/update.png" alt="agi update output" width="520">
126
+ </p>
127
+
128
+ Detects your install method (npm or Homebrew) and runs the appropriate upgrade command.
129
+
77
130
  ## How It Works
78
131
 
79
132
  1. Captures screenshots of your desktop
@@ -81,6 +134,10 @@ While the agent is running:
81
134
  3. Decides on and executes actions
82
135
  4. Repeats until the task is complete
83
136
 
137
+ <p align="center">
138
+ <img src="https://github.com/agi-inc/agi-cli/releases/latest/download/complete.png" alt="AGI CLI task completed" width="680">
139
+ </p>
140
+
84
141
  ## Requirements
85
142
 
86
143
  - Node.js 20.4.0 or later
package/dist/index.mjs CHANGED
@@ -1,19 +1,262 @@
1
1
  // src/index.tsx
2
- import React7 from "react";
2
+ import React8 from "react";
3
3
  import { render } from "ink";
4
- import { isBinaryAvailable } from "agi";
4
+ import { isBinaryAvailable } from "@agi_inc/agi-js";
5
5
 
6
6
  // src/cli.ts
7
7
  import yargs from "yargs";
8
8
  import { hideBin } from "yargs/helpers";
9
- async function parseArgs() {
10
- const argv = await yargs(hideBin(process.argv)).scriptName("agi").usage("$0 <goal>", "Run an agent with the given goal", (yargs2) => {
11
- return yargs2.positional("goal", {
12
- describe: "The task for the agent to accomplish",
13
- type: "string",
14
- demandOption: true
9
+
10
+ // src/config.ts
11
+ import fs from "fs";
12
+ import path from "path";
13
+ import os from "os";
14
+ function getCredentialsPath() {
15
+ return path.join(os.homedir(), ".agi", "credentials");
16
+ }
17
+ function loadApiKey() {
18
+ if (process.env.AGI_API_KEY) {
19
+ return process.env.AGI_API_KEY;
20
+ }
21
+ if (process.env.ANTHROPIC_API_KEY) {
22
+ return process.env.ANTHROPIC_API_KEY;
23
+ }
24
+ const credPath = getCredentialsPath();
25
+ try {
26
+ const raw = fs.readFileSync(credPath, "utf-8");
27
+ const credentials = JSON.parse(raw);
28
+ if (credentials.api_key) {
29
+ return credentials.api_key;
30
+ }
31
+ } catch {
32
+ }
33
+ return void 0;
34
+ }
35
+ function saveApiKey(apiKey) {
36
+ const credPath = getCredentialsPath();
37
+ const dir = path.dirname(credPath);
38
+ if (!fs.existsSync(dir)) {
39
+ fs.mkdirSync(dir, { recursive: true, mode: 448 });
40
+ }
41
+ const credentials = { api_key: apiKey };
42
+ fs.writeFileSync(credPath, JSON.stringify(credentials, null, 2) + "\n", {
43
+ mode: 384
44
+ });
45
+ }
46
+ function deleteCredentials() {
47
+ const credPath = getCredentialsPath();
48
+ try {
49
+ fs.unlinkSync(credPath);
50
+ return true;
51
+ } catch {
52
+ return false;
53
+ }
54
+ }
55
+
56
+ // src/commands/login.ts
57
+ var API_BASE = "https://api.agi.tech";
58
+ async function openBrowser(url) {
59
+ const open = (await import("open")).default;
60
+ await open(url);
61
+ }
62
+ function sleep(ms) {
63
+ return new Promise((resolve) => setTimeout(resolve, ms));
64
+ }
65
+ async function loginCommand() {
66
+ let deviceAuth;
67
+ try {
68
+ const res = await fetch(`${API_BASE}/v1/auth/device`, {
69
+ method: "POST",
70
+ headers: { "Content-Type": "application/json" }
15
71
  });
16
- }).option("model", {
72
+ if (!res.ok) {
73
+ const detail = await res.text();
74
+ console.error(`Failed to start login flow (${res.status}): ${detail}`);
75
+ process.exit(1);
76
+ }
77
+ deviceAuth = await res.json();
78
+ } catch (err) {
79
+ console.error(`Failed to connect to AGI API: ${err.message}`);
80
+ process.exit(1);
81
+ }
82
+ console.log("");
83
+ console.log(`Your confirmation code: ${deviceAuth.user_code}`);
84
+ console.log("");
85
+ console.log("Opening browser to authorize...");
86
+ console.log(` ${deviceAuth.verification_url}`);
87
+ console.log("");
88
+ try {
89
+ await openBrowser(deviceAuth.verification_url);
90
+ } catch {
91
+ console.log("Could not open browser automatically. Please visit the URL above.");
92
+ }
93
+ console.log("Waiting for authorization...");
94
+ const sigintHandler = () => {
95
+ console.log("\nLogin cancelled.");
96
+ process.exit(130);
97
+ };
98
+ process.on("SIGINT", sigintHandler);
99
+ const maxAttempts = Math.ceil(deviceAuth.expires_in / deviceAuth.interval);
100
+ const interval = deviceAuth.interval * 1e3;
101
+ let consecutiveErrors = 0;
102
+ try {
103
+ for (let i = 0; i < maxAttempts; i++) {
104
+ await sleep(interval);
105
+ try {
106
+ const res = await fetch(`${API_BASE}/v1/auth/device/token`, {
107
+ method: "POST",
108
+ headers: { "Content-Type": "application/json" },
109
+ body: JSON.stringify({ device_code: deviceAuth.device_code })
110
+ });
111
+ consecutiveErrors = 0;
112
+ if (res.status === 428) {
113
+ process.stdout.write(".");
114
+ continue;
115
+ }
116
+ if (res.status === 410) {
117
+ console.log("");
118
+ console.error("Login expired. Please run `agi login` again.");
119
+ process.exit(1);
120
+ }
121
+ if (res.ok) {
122
+ const token = await res.json();
123
+ console.log("");
124
+ saveApiKey(token.api_key);
125
+ const identity = token.email || "your account";
126
+ console.log(`Logged in as ${identity}`);
127
+ console.log("Your API key has been saved to ~/.agi/credentials");
128
+ return;
129
+ }
130
+ const detail = await res.text();
131
+ console.log("");
132
+ console.error(`Unexpected response (${res.status}): ${detail}`);
133
+ process.exit(1);
134
+ } catch {
135
+ consecutiveErrors++;
136
+ if (consecutiveErrors >= 3) {
137
+ console.log("");
138
+ console.error("Unable to reach AGI API. Check your internet connection.");
139
+ console.error("Retrying...");
140
+ consecutiveErrors = 0;
141
+ } else {
142
+ process.stdout.write("!");
143
+ }
144
+ }
145
+ }
146
+ console.log("");
147
+ console.error("Login timed out. Please run `agi login` again.");
148
+ process.exit(1);
149
+ } finally {
150
+ process.removeListener("SIGINT", sigintHandler);
151
+ }
152
+ }
153
+
154
+ // src/commands/logout.ts
155
+ async function logoutCommand() {
156
+ const deleted = deleteCredentials();
157
+ if (deleted) {
158
+ console.log("Logged out. Credentials removed from ~/.agi/credentials");
159
+ } else {
160
+ console.log("No credentials file found. Already logged out.");
161
+ }
162
+ }
163
+
164
+ // src/commands/update.ts
165
+ import { execSync } from "child_process";
166
+ import { readFileSync, realpathSync } from "fs";
167
+ import { dirname, join } from "path";
168
+ function getCurrentVersion() {
169
+ const realScript = realpathSync(process.argv[1]);
170
+ const pkgPath = join(dirname(realScript), "..", "package.json");
171
+ const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
172
+ return pkg.version;
173
+ }
174
+ async function getLatestVersion() {
175
+ const res = await fetch("https://registry.npmjs.org/@agi_inc/cli");
176
+ if (!res.ok) {
177
+ throw new Error(`npm registry returned ${res.status}`);
178
+ }
179
+ const data = await res.json();
180
+ return data["dist-tags"].latest;
181
+ }
182
+ function compareVersions(a, b) {
183
+ const pa = a.split(".").map(Number);
184
+ const pb = b.split(".").map(Number);
185
+ for (let i = 0; i < 3; i++) {
186
+ if ((pa[i] || 0) < (pb[i] || 0)) return -1;
187
+ if ((pa[i] || 0) > (pb[i] || 0)) return 1;
188
+ }
189
+ return 0;
190
+ }
191
+ function detectInstallMethod() {
192
+ try {
193
+ const agiPath = execSync("which agi", { encoding: "utf-8" }).trim();
194
+ if (agiPath.includes("homebrew") || agiPath.includes("Cellar")) {
195
+ return "homebrew";
196
+ }
197
+ return "npm";
198
+ } catch {
199
+ return "unknown";
200
+ }
201
+ }
202
+ async function updateCommand() {
203
+ const current = getCurrentVersion();
204
+ console.log("");
205
+ console.log(` \u25B8 AGI CLI v${current}`);
206
+ console.log("");
207
+ console.log(" Checking for updates...");
208
+ try {
209
+ const latest = await getLatestVersion();
210
+ if (compareVersions(current, latest) >= 0) {
211
+ console.log(` \u25CF Up to date`);
212
+ console.log("");
213
+ return;
214
+ }
215
+ console.log(` Update available: ${current} \u2192 ${latest}`);
216
+ console.log("");
217
+ const method = detectInstallMethod();
218
+ if (method === "homebrew") {
219
+ console.log(" Updating via Homebrew...");
220
+ console.log("");
221
+ execSync("brew upgrade agi", { stdio: "inherit" });
222
+ } else {
223
+ console.log(" Updating via npm...");
224
+ console.log("");
225
+ execSync("npm install -g @agi_inc/cli@latest", { stdio: "inherit" });
226
+ }
227
+ console.log("");
228
+ console.log(` \u25CF Updated to v${latest}`);
229
+ console.log("");
230
+ } catch (error) {
231
+ console.error("");
232
+ console.error(` \u2715 Update failed: ${error instanceof Error ? error.message : error}`);
233
+ console.error("");
234
+ console.error(" Try manually:");
235
+ console.error(" npm install -g @agi_inc/cli@latest");
236
+ console.error("");
237
+ process.exit(1);
238
+ }
239
+ }
240
+
241
+ // src/cli.ts
242
+ async function parseArgs() {
243
+ const argv = await yargs(hideBin(process.argv)).scriptName("agi").command("login", "Authenticate and save your API key", {}, async () => {
244
+ await loginCommand();
245
+ }).command("logout", "Remove saved credentials", {}, async () => {
246
+ await logoutCommand();
247
+ }).command("update", "Update AGI CLI to the latest version", {}, async () => {
248
+ await updateCommand();
249
+ }).command(
250
+ "$0 [goal]",
251
+ "Run an agent with the given goal",
252
+ (yargs2) => {
253
+ return yargs2.positional("goal", {
254
+ describe: "The task for the agent to accomplish",
255
+ type: "string",
256
+ demandOption: false
257
+ });
258
+ }
259
+ ).option("model", {
17
260
  alias: "m",
18
261
  describe: "Model to use",
19
262
  type: "string",
@@ -28,22 +271,29 @@ async function parseArgs() {
28
271
  describe: "Auto-approve all confirmation requests",
29
272
  type: "boolean",
30
273
  default: false
31
- }).help().alias("help", "h").version().alias("version", "V").example('$0 "Open calculator and compute 2+2"', "Basic task").example('$0 "Find flights from SFO to JFK" --model claude-opus', "Use a specific model").example('$0 "Install Node.js" --verbose', "Verbose output").parse();
274
+ }).help().alias("help", "h").version().alias("version", "V").example('$0 "Open calculator and compute 2+2"', "Basic task").example('$0 "Find flights from SFO to JFK" --model claude-opus', "Use a specific model").example('$0 "Install Node.js" --verbose', "Verbose output").example("$0", "Start interactive mode").example("$0 login", "Authenticate with your API key").example("$0 update", "Update to the latest version").parse();
275
+ const command = argv._?.[0];
276
+ if (command === "login" || command === "logout" || command === "update") {
277
+ return { kind: "handled" };
278
+ }
32
279
  return {
33
- goal: argv.goal,
34
- model: argv.model,
35
- verbose: argv.verbose,
36
- noConfirm: argv["no-confirm"]
280
+ kind: "run",
281
+ args: {
282
+ goal: argv.goal,
283
+ model: argv.model,
284
+ verbose: argv.verbose,
285
+ noConfirm: argv["no-confirm"]
286
+ }
37
287
  };
38
288
  }
39
289
 
40
290
  // src/app/App.tsx
41
- import React6, { useEffect as useEffect2, useState as useState4 } from "react";
42
- import { Box as Box6, Text as Text6, useApp } from "ink";
291
+ import React7, { useEffect as useEffect2, useState as useState5, useCallback as useCallback3 } from "react";
292
+ import { Box as Box7, Text as Text7, useApp } from "ink";
43
293
 
44
294
  // src/hooks/useAgent.ts
45
295
  import { useState, useCallback, useRef, useEffect } from "react";
46
- import { AgentDriver } from "agi";
296
+ import { AgentDriver } from "@agi_inc/agi-js";
47
297
  function useAgent(options) {
48
298
  const { model, agentName, apiUrl, verbose, noConfirm, onFinished } = options;
49
299
  const [state, setState] = useState("idle");
@@ -52,11 +302,32 @@ function useAgent(options) {
52
302
  const [pendingConfirm, setPendingConfirm] = useState(null);
53
303
  const [pendingQuestion, setPendingQuestion] = useState(null);
54
304
  const driverRef = useRef(null);
305
+ const onFinishedRef = useRef(onFinished);
306
+ useEffect(() => {
307
+ onFinishedRef.current = onFinished;
308
+ }, [onFinished]);
55
309
  const addEvent = useCallback((event) => {
56
310
  setEvents((prev) => [...prev, event]);
57
311
  }, []);
58
312
  const start = useCallback(
59
313
  async (goal) => {
314
+ if (driverRef.current) {
315
+ try {
316
+ await driverRef.current.stop("New task started");
317
+ } catch {
318
+ }
319
+ driverRef.current = null;
320
+ }
321
+ setState("idle");
322
+ setStep(0);
323
+ setPendingConfirm(null);
324
+ setPendingQuestion(null);
325
+ setEvents((prev) => {
326
+ if (prev.length > 0) {
327
+ return [...prev, { type: "separator", goal }];
328
+ }
329
+ return prev;
330
+ });
60
331
  const driver = new AgentDriver({ model, mode: "local", agentName, apiUrl });
61
332
  driverRef.current = driver;
62
333
  driver.on("state_change", (newState) => {
@@ -69,7 +340,10 @@ function useAgent(options) {
69
340
  });
70
341
  driver.on("action", async (action) => {
71
342
  const actionStr = action.type + (action.x !== void 0 ? ` (${action.x}, ${action.y})` : "");
72
- addEvent({ type: "action", action: actionStr });
343
+ const parts = [];
344
+ if (action.text) parts.push(`"${action.text}"`);
345
+ if (action.key) parts.push(`[${action.key}]`);
346
+ addEvent({ type: "action", action: actionStr, params: parts.length ? parts.join(" ") : void 0 });
73
347
  });
74
348
  driver.on("confirm", async (reason) => {
75
349
  if (noConfirm) {
@@ -97,14 +371,14 @@ function useAgent(options) {
97
371
  });
98
372
  try {
99
373
  const result = await driver.start(goal);
100
- if (onFinished) {
101
- onFinished(result);
374
+ if (onFinishedRef.current) {
375
+ onFinishedRef.current(result);
102
376
  }
103
377
  } catch (error) {
104
378
  addEvent({ type: "error", message: String(error) });
105
379
  }
106
380
  },
107
- [model, agentName, apiUrl, verbose, noConfirm, addEvent, onFinished, state]
381
+ [model, agentName, apiUrl, verbose, noConfirm, addEvent]
108
382
  );
109
383
  const stop = useCallback(async () => {
110
384
  if (driverRef.current) {
@@ -193,49 +467,90 @@ var stateColors = {
193
467
  waiting_confirmation: "yellow",
194
468
  waiting_answer: "yellow",
195
469
  finished: "green",
196
- stopped: "red",
470
+ stopped: "gray",
197
471
  error: "red"
198
472
  };
199
473
  var stateLabels = {
200
474
  idle: "IDLE",
201
- running: "RUNNING",
475
+ running: "ACTIVE",
202
476
  paused: "PAUSED",
203
- waiting_confirmation: "WAITING",
204
- waiting_answer: "WAITING",
205
- finished: "DONE",
477
+ waiting_confirmation: "AWAITING",
478
+ waiting_answer: "AWAITING",
479
+ finished: "COMPLETE",
206
480
  stopped: "STOPPED",
207
481
  error: "ERROR"
208
482
  };
483
+ var stateIndicators = {
484
+ idle: "\u25CB",
485
+ running: "\u25CF",
486
+ paused: "\u25C9",
487
+ waiting_confirmation: "\u25CE",
488
+ waiting_answer: "\u25CE",
489
+ finished: "\u25CF",
490
+ stopped: "\u25CB",
491
+ error: "\u25CF"
492
+ };
209
493
  var StatusBar = ({ state, step, goal }) => {
210
494
  const color = stateColors[state] || "white";
211
495
  const label = stateLabels[state] || state.toUpperCase();
212
- return /* @__PURE__ */ React.createElement(Box, { flexDirection: "column", borderStyle: "single", borderColor: "gray", paddingX: 1 }, /* @__PURE__ */ React.createElement(Box, null, /* @__PURE__ */ React.createElement(Text, { bold: true }, "AGI Agent"), /* @__PURE__ */ React.createElement(Text, null, " | "), /* @__PURE__ */ React.createElement(Text, { color }, label), /* @__PURE__ */ React.createElement(Text, null, " | "), /* @__PURE__ */ React.createElement(Text, null, "Step ", step)), /* @__PURE__ */ React.createElement(Box, null, /* @__PURE__ */ React.createElement(Text, { color: "gray" }, "Goal: "), /* @__PURE__ */ React.createElement(Text, null, goal.length > 60 ? goal.slice(0, 60) + "..." : goal)));
496
+ const indicator = stateIndicators[state] || "\u25CB";
497
+ return /* @__PURE__ */ React.createElement(Box, { flexDirection: "column", borderStyle: "bold", borderColor: "gray", paddingX: 1 }, /* @__PURE__ */ React.createElement(Box, null, /* @__PURE__ */ React.createElement(Text, { color: "cyan", bold: true }, "\u25B8 AGI"), /* @__PURE__ */ React.createElement(Text, null, " "), /* @__PURE__ */ React.createElement(Text, { color }, indicator, " "), /* @__PURE__ */ React.createElement(Text, { color, bold: true }, label), /* @__PURE__ */ React.createElement(Box, { flexGrow: 1 }), /* @__PURE__ */ React.createElement(Text, { dimColor: true }, "STEP "), /* @__PURE__ */ React.createElement(Text, { bold: true }, String(step).padStart(2, "0"))), /* @__PURE__ */ React.createElement(Box, null, /* @__PURE__ */ React.createElement(Text, { dimColor: true }, goal.length > 72 ? goal.slice(0, 72) + "\u2026" : goal)));
213
498
  };
214
499
 
215
500
  // src/components/EventDisplay.tsx
216
501
  import React2 from "react";
217
502
  import { Text as Text2, Box as Box2 } from "ink";
218
- var EventDisplay = ({ events, maxEvents = 10 }) => {
219
- const displayEvents = events.slice(-maxEvents);
220
- return /* @__PURE__ */ React2.createElement(Box2, { flexDirection: "column", paddingY: 1 }, displayEvents.map((event, index) => /* @__PURE__ */ React2.createElement(EventLine, { key: index, event })));
503
+ var typeConfig = {
504
+ thinking: { prefix: "\xB7", color: "gray" },
505
+ action: { prefix: "\u25B8", color: "white" },
506
+ confirm: { prefix: "\u25C6", color: "yellow" },
507
+ question: { prefix: "\u25C7", color: "cyan" },
508
+ error: { prefix: "\u2715", color: "red" }
221
509
  };
222
- var EventLine = ({ event }) => {
510
+ function getEventText(event) {
223
511
  switch (event.type) {
224
512
  case "thinking":
225
- return /* @__PURE__ */ React2.createElement(Box2, null, /* @__PURE__ */ React2.createElement(Text2, { color: "cyan" }, "\u{1F4AD} "), /* @__PURE__ */ React2.createElement(Text2, { color: "gray" }, event.text));
513
+ return event.text;
226
514
  case "action":
227
- return /* @__PURE__ */ React2.createElement(Box2, null, /* @__PURE__ */ React2.createElement(Text2, { color: "blue" }, "\u26A1 "), /* @__PURE__ */ React2.createElement(Text2, null, event.action));
515
+ return event.action;
228
516
  case "confirm":
229
- return /* @__PURE__ */ React2.createElement(Box2, null, /* @__PURE__ */ React2.createElement(Text2, { color: "yellow" }, "\u2753 "), /* @__PURE__ */ React2.createElement(Text2, { color: "yellow" }, event.reason));
517
+ return event.reason;
230
518
  case "question":
231
- return /* @__PURE__ */ React2.createElement(Box2, null, /* @__PURE__ */ React2.createElement(Text2, { color: "magenta" }, "\u{1F4DD} "), /* @__PURE__ */ React2.createElement(Text2, { color: "magenta" }, event.question));
519
+ return event.question;
232
520
  case "finished":
233
- return /* @__PURE__ */ React2.createElement(Box2, null, /* @__PURE__ */ React2.createElement(Text2, { color: event.success ? "green" : "red" }, event.success ? "\u2705 " : "\u274C "), /* @__PURE__ */ React2.createElement(Text2, null, event.summary));
521
+ return event.summary;
234
522
  case "error":
235
- return /* @__PURE__ */ React2.createElement(Box2, null, /* @__PURE__ */ React2.createElement(Text2, { color: "red" }, "\u26A0\uFE0F "), /* @__PURE__ */ React2.createElement(Text2, { color: "red" }, event.message));
236
- default:
237
- return null;
523
+ return event.message;
524
+ case "separator":
525
+ return event.goal;
526
+ }
527
+ }
528
+ function getEventStyle(event) {
529
+ if (event.type === "finished") {
530
+ return event.success ? { prefix: "\u25CF", color: "green" } : { prefix: "\u2715", color: "red" };
238
531
  }
532
+ return typeConfig[event.type];
533
+ }
534
+ var EventDisplay = ({ events, maxEvents = 12 }) => {
535
+ const displayEvents = events.slice(-maxEvents);
536
+ if (displayEvents.length === 0) return null;
537
+ return /* @__PURE__ */ React2.createElement(Box2, { flexDirection: "column" }, displayEvents.map((event, index) => {
538
+ if (event.type === "separator") {
539
+ return /* @__PURE__ */ React2.createElement(Box2, { key: index, marginTop: 1 }, /* @__PURE__ */ React2.createElement(Text2, { dimColor: true }, " \u2500\u2500 "), /* @__PURE__ */ React2.createElement(Text2, { bold: true }, event.goal), /* @__PURE__ */ React2.createElement(Text2, { dimColor: true }, " \u2500\u2500"));
540
+ }
541
+ const style = getEventStyle(event);
542
+ const text = getEventText(event);
543
+ const isLatest = index === displayEvents.length - 1;
544
+ return /* @__PURE__ */ React2.createElement(Box2, { key: index }, /* @__PURE__ */ React2.createElement(Text2, { dimColor: true }, " \u2503 "), /* @__PURE__ */ React2.createElement(Text2, { color: style.color }, style.prefix, " "), /* @__PURE__ */ React2.createElement(
545
+ Text2,
546
+ {
547
+ color: style.color === "white" ? void 0 : style.color,
548
+ bold: isLatest && event.type === "action",
549
+ dimColor: event.type === "thinking"
550
+ },
551
+ text
552
+ ), event.type === "action" && event.params && /* @__PURE__ */ React2.createElement(Text2, { color: "gray" }, " ", event.params));
553
+ }));
239
554
  };
240
555
 
241
556
  // src/components/ConfirmDialog.tsx
@@ -256,21 +571,23 @@ var ConfirmDialog = ({ reason, onConfirm }) => {
256
571
  onConfirm(false);
257
572
  }
258
573
  });
259
- return /* @__PURE__ */ React3.createElement(Box3, { flexDirection: "column", borderStyle: "round", borderColor: "yellow", paddingX: 2, paddingY: 1 }, /* @__PURE__ */ React3.createElement(Box3, { marginBottom: 1 }, /* @__PURE__ */ React3.createElement(Text3, { color: "yellow", bold: true }, "Confirmation Required")), /* @__PURE__ */ React3.createElement(Box3, { marginBottom: 1 }, /* @__PURE__ */ React3.createElement(Text3, null, reason)), /* @__PURE__ */ React3.createElement(Box3, null, /* @__PURE__ */ React3.createElement(Box3, { marginRight: 2 }, /* @__PURE__ */ React3.createElement(
574
+ return /* @__PURE__ */ React3.createElement(Box3, { flexDirection: "column", borderStyle: "bold", borderColor: "yellow", paddingX: 2, paddingY: 1 }, /* @__PURE__ */ React3.createElement(Box3, { marginBottom: 1 }, /* @__PURE__ */ React3.createElement(Text3, { color: "yellow", bold: true }, "CONFIRM")), /* @__PURE__ */ React3.createElement(Box3, { marginBottom: 1 }, /* @__PURE__ */ React3.createElement(Text3, null, reason)), /* @__PURE__ */ React3.createElement(Box3, null, /* @__PURE__ */ React3.createElement(Box3, { marginRight: 2 }, /* @__PURE__ */ React3.createElement(
260
575
  Text3,
261
576
  {
262
577
  backgroundColor: selected === "yes" ? "green" : void 0,
263
- color: selected === "yes" ? "white" : "gray"
578
+ color: selected === "yes" ? "black" : "gray",
579
+ bold: selected === "yes"
264
580
  },
265
- " [Y]es "
266
- )), /* @__PURE__ */ React3.createElement(Box3, null, /* @__PURE__ */ React3.createElement(
581
+ " [Y] approve "
582
+ )), /* @__PURE__ */ React3.createElement(
267
583
  Text3,
268
584
  {
269
585
  backgroundColor: selected === "no" ? "red" : void 0,
270
- color: selected === "no" ? "white" : "gray"
586
+ color: selected === "no" ? "black" : "gray",
587
+ bold: selected === "no"
271
588
  },
272
- " [N]o "
273
- ))), /* @__PURE__ */ React3.createElement(Box3, { marginTop: 1 }, /* @__PURE__ */ React3.createElement(Text3, { color: "gray", dimColor: true }, "Press Y/N or use arrow keys and Enter")));
589
+ " [N] deny "
590
+ )), /* @__PURE__ */ React3.createElement(Box3, { marginTop: 1 }, /* @__PURE__ */ React3.createElement(Text3, { dimColor: true }, "Y/N or arrows + enter")));
274
591
  };
275
592
 
276
593
  // src/components/QuestionDialog.tsx
@@ -289,7 +606,7 @@ var QuestionDialog = ({ question, onAnswer }) => {
289
606
  handleSubmit();
290
607
  }
291
608
  });
292
- return /* @__PURE__ */ React4.createElement(Box4, { flexDirection: "column", borderStyle: "round", borderColor: "magenta", paddingX: 2, paddingY: 1 }, /* @__PURE__ */ React4.createElement(Box4, { marginBottom: 1 }, /* @__PURE__ */ React4.createElement(Text4, { color: "magenta", bold: true }, "Agent Question")), /* @__PURE__ */ React4.createElement(Box4, { marginBottom: 1 }, /* @__PURE__ */ React4.createElement(Text4, null, question)), /* @__PURE__ */ React4.createElement(Box4, null, /* @__PURE__ */ React4.createElement(Text4, { color: "green" }, "> "), /* @__PURE__ */ React4.createElement(
609
+ return /* @__PURE__ */ React4.createElement(Box4, { flexDirection: "column", borderStyle: "bold", borderColor: "cyan", paddingX: 2, paddingY: 1 }, /* @__PURE__ */ React4.createElement(Box4, { marginBottom: 1 }, /* @__PURE__ */ React4.createElement(Text4, { color: "cyan", bold: true }, "INPUT REQUIRED")), /* @__PURE__ */ React4.createElement(Box4, { marginBottom: 1 }, /* @__PURE__ */ React4.createElement(Text4, null, question)), /* @__PURE__ */ React4.createElement(Box4, null, /* @__PURE__ */ React4.createElement(Text4, { color: "cyan" }, "\u25B8 "), /* @__PURE__ */ React4.createElement(
293
610
  TextInput,
294
611
  {
295
612
  value: answer,
@@ -297,21 +614,46 @@ var QuestionDialog = ({ question, onAnswer }) => {
297
614
  onSubmit: handleSubmit,
298
615
  placeholder: "Type your answer..."
299
616
  }
300
- )), /* @__PURE__ */ React4.createElement(Box4, { marginTop: 1 }, /* @__PURE__ */ React4.createElement(Text4, { color: "gray", dimColor: true }, "Press Enter to submit")));
617
+ )), /* @__PURE__ */ React4.createElement(Box4, { marginTop: 1 }, /* @__PURE__ */ React4.createElement(Text4, { dimColor: true }, "enter to submit")));
301
618
  };
302
619
 
303
- // src/components/Spinner.tsx
304
- import React5 from "react";
620
+ // src/components/PromptInput.tsx
621
+ import React5, { useState as useState4 } from "react";
305
622
  import { Text as Text5, Box as Box5 } from "ink";
623
+ import TextInput2 from "ink-text-input";
624
+ var PromptInput = ({ onSubmit }) => {
625
+ const [value, setValue] = useState4("");
626
+ const handleSubmit = () => {
627
+ const trimmed = value.trim();
628
+ if (trimmed) {
629
+ onSubmit(trimmed);
630
+ setValue("");
631
+ }
632
+ };
633
+ return /* @__PURE__ */ React5.createElement(Box5, null, /* @__PURE__ */ React5.createElement(Text5, { color: "cyan", bold: true }, "\u25B8 "), /* @__PURE__ */ React5.createElement(
634
+ TextInput2,
635
+ {
636
+ value,
637
+ onChange: setValue,
638
+ onSubmit: handleSubmit,
639
+ placeholder: "Enter a task..."
640
+ }
641
+ ));
642
+ };
643
+
644
+ // src/components/Spinner.tsx
645
+ import React6 from "react";
646
+ import { Text as Text6, Box as Box6 } from "ink";
306
647
  import InkSpinner from "ink-spinner";
307
- var Spinner = ({ text = "", type = "dots" }) => {
308
- return /* @__PURE__ */ React5.createElement(Box5, null, /* @__PURE__ */ React5.createElement(Text5, { color: "cyan" }, /* @__PURE__ */ React5.createElement(InkSpinner, { type })), text && /* @__PURE__ */ React5.createElement(Text5, null, " ", text));
648
+ var Spinner = ({ text }) => {
649
+ return /* @__PURE__ */ React6.createElement(Box6, null, /* @__PURE__ */ React6.createElement(Text6, { color: "cyan" }, /* @__PURE__ */ React6.createElement(InkSpinner, { type: "dots" })), text && /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, " ", text));
309
650
  };
310
651
 
311
652
  // src/app/App.tsx
312
653
  var App = ({ args }) => {
313
654
  const { exit } = useApp();
314
- const [started, setStarted] = useState4(false);
655
+ const [phase, setPhase] = useState5(args.goal ? "executing" : "input");
656
+ const [currentGoal, setCurrentGoal] = useState5(args.goal ?? "");
315
657
  const {
316
658
  state,
317
659
  step,
@@ -329,60 +671,65 @@ var App = ({ args }) => {
329
671
  verbose: args.verbose,
330
672
  noConfirm: args.noConfirm,
331
673
  onFinished: () => {
332
- setTimeout(() => exit(), 500);
674
+ setPhase("input");
333
675
  }
334
676
  });
335
677
  useEffect2(() => {
336
- if (!started) {
337
- setStarted(true);
338
- start(args.goal);
678
+ if (phase === "executing" && currentGoal) {
679
+ start(currentGoal);
339
680
  }
340
- }, [started, start, args.goal]);
681
+ }, [phase, currentGoal, start]);
682
+ const handleSubmitGoal = useCallback3((goal) => {
683
+ setCurrentGoal(goal);
684
+ setPhase("executing");
685
+ }, []);
341
686
  useKeybindings({
342
687
  onPause: pause,
343
688
  onResume: resume,
344
689
  onStop: async () => {
345
- await stop();
690
+ if (phase === "executing") {
691
+ await stop();
692
+ }
346
693
  exit();
347
694
  },
348
695
  isPaused: state === "paused",
349
- disabled: !!pendingConfirm || !!pendingQuestion
696
+ disabled: phase === "input" || !!pendingConfirm || !!pendingQuestion
350
697
  });
351
698
  const isTerminal = state === "finished" || state === "stopped" || state === "error";
352
- return /* @__PURE__ */ React6.createElement(Box6, { flexDirection: "column" }, /* @__PURE__ */ React6.createElement(StatusBar, { state, step, goal: args.goal }), state === "running" && /* @__PURE__ */ React6.createElement(Box6, { marginY: 1 }, /* @__PURE__ */ React6.createElement(Spinner, { text: "Agent is working..." })), state === "paused" && /* @__PURE__ */ React6.createElement(Box6, { marginY: 1 }, /* @__PURE__ */ React6.createElement(Text6, { color: "yellow" }, "\u23F8\uFE0F Paused - Press Space to resume, Q to stop")), /* @__PURE__ */ React6.createElement(EventDisplay, { events }), pendingConfirm && /* @__PURE__ */ React6.createElement(ConfirmDialog, { reason: pendingConfirm, onConfirm: respondConfirm }), pendingQuestion && /* @__PURE__ */ React6.createElement(QuestionDialog, { question: pendingQuestion, onAnswer: respondAnswer }), !isTerminal && !pendingConfirm && !pendingQuestion && /* @__PURE__ */ React6.createElement(Box6, { marginTop: 1 }, /* @__PURE__ */ React6.createElement(Text6, { color: "gray", dimColor: true }, "Space: Pause/Resume | Q: Stop | Ctrl+C: Cancel")));
699
+ return /* @__PURE__ */ React7.createElement(Box7, { flexDirection: "column" }, phase === "input" && events.length === 0 && /* @__PURE__ */ React7.createElement(Box7, { borderStyle: "bold", borderColor: "gray", paddingX: 1 }, /* @__PURE__ */ React7.createElement(Text7, { color: "cyan", bold: true }, "\u25B8 AGI"), /* @__PURE__ */ React7.createElement(Text7, null, " interactive mode")), phase === "executing" && /* @__PURE__ */ React7.createElement(StatusBar, { state, step, goal: currentGoal }), /* @__PURE__ */ React7.createElement(Box7, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React7.createElement(EventDisplay, { events }), phase === "executing" && state === "running" && /* @__PURE__ */ React7.createElement(Box7, null, /* @__PURE__ */ React7.createElement(Text7, { dimColor: true }, " \u2503 "), /* @__PURE__ */ React7.createElement(Spinner, null)), phase === "executing" && state === "paused" && /* @__PURE__ */ React7.createElement(Box7, null, /* @__PURE__ */ React7.createElement(Text7, { dimColor: true }, " \u2503 "), /* @__PURE__ */ React7.createElement(Text7, { color: "yellow", bold: true }, "\u25AE\u25AE"), /* @__PURE__ */ React7.createElement(Text7, { dimColor: true }, " paused \u2014 space to resume"))), pendingConfirm && /* @__PURE__ */ React7.createElement(Box7, { marginTop: 1 }, /* @__PURE__ */ React7.createElement(ConfirmDialog, { reason: pendingConfirm, onConfirm: respondConfirm })), pendingQuestion && /* @__PURE__ */ React7.createElement(Box7, { marginTop: 1 }, /* @__PURE__ */ React7.createElement(QuestionDialog, { question: pendingQuestion, onAnswer: respondAnswer })), phase === "input" && /* @__PURE__ */ React7.createElement(Box7, { marginTop: 1 }, /* @__PURE__ */ React7.createElement(PromptInput, { onSubmit: handleSubmitGoal })), phase === "executing" && !isTerminal && !pendingConfirm && !pendingQuestion && /* @__PURE__ */ React7.createElement(Box7, { marginTop: 1 }, /* @__PURE__ */ React7.createElement(Text7, { dimColor: true }, " space pause \xB7 q stop \xB7 ^c quit")));
353
700
  };
354
701
 
355
702
  // src/index.tsx
356
703
  async function main() {
357
- if (!process.env.AGI_API_KEY && !process.env.ANTHROPIC_API_KEY) {
358
- console.error("Error: AGI_API_KEY or ANTHROPIC_API_KEY environment variable is required");
359
- console.error("");
360
- console.error("Set your API key:");
361
- console.error(" export AGI_API_KEY=your_key");
362
- console.error("");
363
- process.exit(1);
364
- }
365
- if (!isBinaryAvailable()) {
366
- console.error("Error: AGI driver binary not found");
367
- console.error("");
368
- console.error("The driver binary is required for local agent execution.");
369
- console.error("It should be installed automatically with the agi package.");
370
- console.error("");
371
- console.error("Try reinstalling: npm install -g @agi_inc/cli");
372
- console.error("");
373
- process.exit(1);
374
- }
375
704
  try {
376
- const args = await parseArgs();
377
- if (!args.goal) {
378
- console.error("Error: Goal is required");
705
+ const result = await parseArgs();
706
+ if (result.kind === "handled") {
707
+ return;
708
+ }
709
+ const { args } = result;
710
+ const apiKey = loadApiKey();
711
+ if (!apiKey) {
712
+ console.error("Error: No API key found");
713
+ console.error("");
714
+ console.error("Run `agi login` to authenticate, or set an environment variable:");
715
+ console.error(" export AGI_API_KEY=your_key");
716
+ console.error("");
717
+ process.exit(1);
718
+ }
719
+ if (!process.env.AGI_API_KEY && !process.env.ANTHROPIC_API_KEY) {
720
+ process.env.AGI_API_KEY = apiKey;
721
+ }
722
+ if (!isBinaryAvailable()) {
723
+ console.error("Error: AGI driver binary not found");
724
+ console.error("");
725
+ console.error("The driver binary is required for local agent execution.");
726
+ console.error("It should be installed automatically with the agi package.");
379
727
  console.error("");
380
- console.error("Usage: agi <goal>");
728
+ console.error("Try reinstalling: npm install -g @agi_inc/cli");
381
729
  console.error("");
382
- console.error('Example: agi "Open calculator and compute 2+2"');
383
730
  process.exit(1);
384
731
  }
385
- const { waitUntilExit } = render(/* @__PURE__ */ React7.createElement(App, { args }));
732
+ const { waitUntilExit } = render(/* @__PURE__ */ React8.createElement(App, { args }));
386
733
  await waitUntilExit();
387
734
  } catch (error) {
388
735
  console.error("Error:", error);
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.tsx","../src/cli.ts","../src/app/App.tsx","../src/hooks/useAgent.ts","../src/hooks/useKeybindings.ts","../src/components/StatusBar.tsx","../src/components/EventDisplay.tsx","../src/components/ConfirmDialog.tsx","../src/components/QuestionDialog.tsx","../src/components/Spinner.tsx"],"sourcesContent":["/**\n * AGI CLI - Terminal-based agent interaction for AGI desktop automation.\n *\n * Usage:\n * agi \"Open calculator and compute 2+2\"\n * agi \"Find flights from SFO to JFK\" --model claude-opus\n * agi \"Install Node.js\" --verbose\n */\n\nimport React from 'react';\nimport { render } from 'ink';\nimport { isBinaryAvailable } from 'agi';\nimport { parseArgs } from './cli.js';\nimport { App } from './app/App.js';\n\nasync function main(): Promise<void> {\n // Check for API key\n if (!process.env.AGI_API_KEY && !process.env.ANTHROPIC_API_KEY) {\n console.error('Error: AGI_API_KEY or ANTHROPIC_API_KEY environment variable is required');\n console.error('');\n console.error('Set your API key:');\n console.error(' export AGI_API_KEY=your_key');\n console.error('');\n process.exit(1);\n }\n\n // Check for driver binary\n if (!isBinaryAvailable()) {\n console.error('Error: AGI driver binary not found');\n console.error('');\n console.error('The driver binary is required for local agent execution.');\n console.error('It should be installed automatically with the agi package.');\n console.error('');\n console.error('Try reinstalling: npm install -g @agi_inc/cli');\n console.error('');\n process.exit(1);\n }\n\n try {\n const args = await parseArgs();\n\n // Check if goal is provided\n if (!args.goal) {\n console.error('Error: Goal is required');\n console.error('');\n console.error('Usage: agi <goal>');\n console.error('');\n console.error('Example: agi \"Open calculator and compute 2+2\"');\n process.exit(1);\n }\n\n // Render the app\n const { waitUntilExit } = render(<App args={args} />);\n await waitUntilExit();\n } catch (error) {\n console.error('Error:', error);\n process.exit(1);\n }\n}\n\nmain();\n","/**\n * CLI argument parsing and configuration.\n */\n\nimport yargs from 'yargs';\nimport { hideBin } from 'yargs/helpers';\n\nexport interface CliArgs {\n goal: string;\n model: string;\n verbose: boolean;\n noConfirm: boolean;\n}\n\nexport async function parseArgs(): Promise<CliArgs> {\n const argv = await yargs(hideBin(process.argv))\n .scriptName('agi')\n .usage('$0 <goal>', 'Run an agent with the given goal', (yargs) => {\n return yargs.positional('goal', {\n describe: 'The task for the agent to accomplish',\n type: 'string',\n demandOption: true,\n });\n })\n .option('model', {\n alias: 'm',\n describe: 'Model to use',\n type: 'string',\n default: 'claude-sonnet',\n choices: ['claude-sonnet', 'claude-opus'],\n })\n .option('verbose', {\n alias: 'v',\n describe: 'Show verbose output including agent thinking',\n type: 'boolean',\n default: false,\n })\n .option('no-confirm', {\n describe: 'Auto-approve all confirmation requests',\n type: 'boolean',\n default: false,\n })\n .help()\n .alias('help', 'h')\n .version()\n .alias('version', 'V')\n .example('$0 \"Open calculator and compute 2+2\"', 'Basic task')\n .example('$0 \"Find flights from SFO to JFK\" --model claude-opus', 'Use a specific model')\n .example('$0 \"Install Node.js\" --verbose', 'Verbose output')\n .parse();\n\n return {\n goal: argv.goal as string,\n model: argv.model as string,\n verbose: argv.verbose as boolean,\n noConfirm: argv['no-confirm'] as boolean,\n };\n}\n","import React, { useEffect, useState } from 'react';\nimport { Box, Text, useApp } from 'ink';\nimport type { CliArgs } from '../cli.js';\nimport { useAgent } from '../hooks/useAgent.js';\nimport { useKeybindings } from '../hooks/useKeybindings.js';\nimport { StatusBar } from '../components/StatusBar.js';\nimport { EventDisplay } from '../components/EventDisplay.js';\nimport { ConfirmDialog } from '../components/ConfirmDialog.js';\nimport { QuestionDialog } from '../components/QuestionDialog.js';\nimport { Spinner } from '../components/Spinner.js';\n\ninterface AppProps {\n args: CliArgs;\n}\n\nexport const App: React.FC<AppProps> = ({ args }) => {\n const { exit } = useApp();\n const [started, setStarted] = useState(false);\n\n const {\n state,\n step,\n events,\n pendingConfirm,\n pendingQuestion,\n start,\n stop,\n pause,\n resume,\n respondConfirm,\n respondAnswer,\n } = useAgent({\n model: args.model,\n verbose: args.verbose,\n noConfirm: args.noConfirm,\n onFinished: () => {\n // Wait a moment for final output, then exit\n setTimeout(() => exit(), 500);\n },\n });\n\n // Start the agent on mount\n useEffect(() => {\n if (!started) {\n setStarted(true);\n start(args.goal);\n }\n }, [started, start, args.goal]);\n\n // Handle keyboard shortcuts\n useKeybindings({\n onPause: pause,\n onResume: resume,\n onStop: async () => {\n await stop();\n exit();\n },\n isPaused: state === 'paused',\n disabled: !!pendingConfirm || !!pendingQuestion,\n });\n\n const isTerminal = state === 'finished' || state === 'stopped' || state === 'error';\n\n return (\n <Box flexDirection=\"column\">\n {/* Status bar */}\n <StatusBar state={state} step={step} goal={args.goal} />\n\n {/* Running indicator */}\n {state === 'running' && (\n <Box marginY={1}>\n <Spinner text=\"Agent is working...\" />\n </Box>\n )}\n\n {/* Paused indicator */}\n {state === 'paused' && (\n <Box marginY={1}>\n <Text color=\"yellow\">⏸️ Paused - Press Space to resume, Q to stop</Text>\n </Box>\n )}\n\n {/* Events display */}\n <EventDisplay events={events} />\n\n {/* Confirmation dialog */}\n {pendingConfirm && (\n <ConfirmDialog reason={pendingConfirm} onConfirm={respondConfirm} />\n )}\n\n {/* Question dialog */}\n {pendingQuestion && (\n <QuestionDialog question={pendingQuestion} onAnswer={respondAnswer} />\n )}\n\n {/* Help text */}\n {!isTerminal && !pendingConfirm && !pendingQuestion && (\n <Box marginTop={1}>\n <Text color=\"gray\" dimColor>\n Space: Pause/Resume | Q: Stop | Ctrl+C: Cancel\n </Text>\n </Box>\n )}\n </Box>\n );\n};\n","import { useState, useCallback, useRef, useEffect } from 'react';\nimport { AgentDriver } from 'agi';\nimport type { DriverState, DriverAction, DriverResult } from 'agi';\nimport type { EventItem } from '../components/EventDisplay.js';\n\ninterface UseAgentOptions {\n model: string;\n agentName?: string;\n apiUrl?: string;\n verbose: boolean;\n noConfirm: boolean;\n onFinished?: (result: DriverResult) => void;\n}\n\ninterface UseAgentReturn {\n state: DriverState;\n step: number;\n events: EventItem[];\n pendingConfirm: string | null;\n pendingQuestion: string | null;\n start: (goal: string) => Promise<void>;\n stop: () => Promise<void>;\n pause: () => void;\n resume: () => void;\n respondConfirm: (approved: boolean) => void;\n respondAnswer: (answer: string) => void;\n}\n\nexport function useAgent(options: UseAgentOptions): UseAgentReturn {\n const { model, agentName, apiUrl, verbose, noConfirm, onFinished } = options;\n\n const [state, setState] = useState<DriverState>('idle');\n const [step, setStep] = useState(0);\n const [events, setEvents] = useState<EventItem[]>([]);\n const [pendingConfirm, setPendingConfirm] = useState<string | null>(null);\n const [pendingQuestion, setPendingQuestion] = useState<string | null>(null);\n\n const driverRef = useRef<AgentDriver | null>(null);\n\n const addEvent = useCallback((event: EventItem) => {\n setEvents((prev) => [...prev, event]);\n }, []);\n\n const start = useCallback(\n async (goal: string) => {\n const driver = new AgentDriver({ model, mode: 'local', agentName, apiUrl });\n driverRef.current = driver;\n\n // Set up event handlers\n driver.on('state_change', (newState: DriverState) => {\n setState(newState);\n });\n\n driver.on('thinking', (text: string) => {\n if (verbose) {\n addEvent({ type: 'thinking', text });\n }\n });\n\n driver.on('action', async (action: DriverAction) => {\n const actionStr = action.type + (action.x !== undefined ? ` (${action.x}, ${action.y})` : '');\n addEvent({ type: 'action', action: actionStr });\n // In local mode, the driver binary executes actions and captures screenshots\n });\n\n driver.on('confirm', async (reason: string) => {\n if (noConfirm) {\n driver.respondConfirm(true);\n return true;\n }\n addEvent({ type: 'confirm', reason });\n setPendingConfirm(reason);\n return true;\n });\n\n driver.on('ask_question', async (question: string) => {\n addEvent({ type: 'question', question });\n setPendingQuestion(question);\n return '';\n });\n\n driver.on('finished', (evt) => {\n addEvent({\n type: 'finished',\n summary: evt.summary,\n success: evt.success,\n });\n });\n\n driver.on('error', (evt) => {\n addEvent({ type: 'error', message: evt.message });\n });\n\n // Start the agent in local mode — no screenshot needed, driver handles it\n try {\n const result = await driver.start(goal);\n\n if (onFinished) {\n onFinished(result);\n }\n } catch (error) {\n addEvent({ type: 'error', message: String(error) });\n }\n },\n [model, agentName, apiUrl, verbose, noConfirm, addEvent, onFinished, state]\n );\n\n const stop = useCallback(async () => {\n if (driverRef.current) {\n await driverRef.current.stop('User cancelled');\n }\n }, []);\n\n const pause = useCallback(() => {\n if (driverRef.current) {\n driverRef.current.pause();\n }\n }, []);\n\n const resume = useCallback(() => {\n if (driverRef.current) {\n driverRef.current.resume();\n }\n }, []);\n\n const respondConfirm = useCallback((approved: boolean) => {\n if (driverRef.current && pendingConfirm) {\n driverRef.current.respondConfirm(approved);\n setPendingConfirm(null);\n }\n }, [pendingConfirm]);\n\n const respondAnswer = useCallback((answer: string) => {\n if (driverRef.current && pendingQuestion) {\n driverRef.current.respondAnswer(answer);\n setPendingQuestion(null);\n }\n }, [pendingQuestion]);\n\n // Update step from driver\n useEffect(() => {\n const interval = setInterval(() => {\n if (driverRef.current) {\n setStep(driverRef.current.currentStep);\n }\n }, 100);\n return () => clearInterval(interval);\n }, []);\n\n return {\n state,\n step,\n events,\n pendingConfirm,\n pendingQuestion,\n start,\n stop,\n pause,\n resume,\n respondConfirm,\n respondAnswer,\n };\n}\n","import { useInput } from 'ink';\nimport { useCallback } from 'react';\n\ninterface UseKeybindingsOptions {\n onPause?: () => void;\n onResume?: () => void;\n onStop?: () => void;\n isPaused?: boolean;\n disabled?: boolean;\n}\n\n/**\n * Hook for handling keyboard shortcuts.\n *\n * - Space: Pause/Resume\n * - Q/Ctrl+C: Stop\n * - Escape: Stop\n */\nexport function useKeybindings(options: UseKeybindingsOptions): void {\n const { onPause, onResume, onStop, isPaused = false, disabled = false } = options;\n\n const handleInput = useCallback(\n (input: string, key: { ctrl: boolean; escape: boolean }) => {\n if (disabled) return;\n\n // Space: Toggle pause/resume\n if (input === ' ') {\n if (isPaused) {\n onResume?.();\n } else {\n onPause?.();\n }\n }\n\n // Q or Ctrl+C: Stop\n if (input === 'q' || input === 'Q' || (key.ctrl && input === 'c')) {\n onStop?.();\n }\n\n // Escape: Stop\n if (key.escape) {\n onStop?.();\n }\n },\n [disabled, isPaused, onPause, onResume, onStop]\n );\n\n useInput(handleInput);\n}\n","import React from 'react';\nimport { Text, Box } from 'ink';\nimport type { DriverState } from 'agi';\n\ninterface StatusBarProps {\n state: DriverState;\n step: number;\n goal: string;\n}\n\nconst stateColors: Record<DriverState, string> = {\n idle: 'gray',\n running: 'green',\n paused: 'yellow',\n waiting_confirmation: 'yellow',\n waiting_answer: 'yellow',\n finished: 'green',\n stopped: 'red',\n error: 'red',\n};\n\nconst stateLabels: Record<DriverState, string> = {\n idle: 'IDLE',\n running: 'RUNNING',\n paused: 'PAUSED',\n waiting_confirmation: 'WAITING',\n waiting_answer: 'WAITING',\n finished: 'DONE',\n stopped: 'STOPPED',\n error: 'ERROR',\n};\n\nexport const StatusBar: React.FC<StatusBarProps> = ({ state, step, goal }) => {\n const color = stateColors[state] || 'white';\n const label = stateLabels[state] || state.toUpperCase();\n\n return (\n <Box flexDirection=\"column\" borderStyle=\"single\" borderColor=\"gray\" paddingX={1}>\n <Box>\n <Text bold>AGI Agent</Text>\n <Text> | </Text>\n <Text color={color}>{label}</Text>\n <Text> | </Text>\n <Text>Step {step}</Text>\n </Box>\n <Box>\n <Text color=\"gray\">Goal: </Text>\n <Text>{goal.length > 60 ? goal.slice(0, 60) + '...' : goal}</Text>\n </Box>\n </Box>\n );\n};\n","import React from 'react';\nimport { Text, Box } from 'ink';\n\nexport type EventItem =\n | { type: 'thinking'; text: string }\n | { type: 'action'; action: string }\n | { type: 'confirm'; reason: string }\n | { type: 'question'; question: string }\n | { type: 'finished'; summary: string; success: boolean }\n | { type: 'error'; message: string };\n\ninterface EventDisplayProps {\n events: EventItem[];\n maxEvents?: number;\n}\n\nexport const EventDisplay: React.FC<EventDisplayProps> = ({ events, maxEvents = 10 }) => {\n const displayEvents = events.slice(-maxEvents);\n\n return (\n <Box flexDirection=\"column\" paddingY={1}>\n {displayEvents.map((event, index) => (\n <EventLine key={index} event={event} />\n ))}\n </Box>\n );\n};\n\nconst EventLine: React.FC<{ event: EventItem }> = ({ event }) => {\n switch (event.type) {\n case 'thinking':\n return (\n <Box>\n <Text color=\"cyan\">💭 </Text>\n <Text color=\"gray\">{event.text}</Text>\n </Box>\n );\n\n case 'action':\n return (\n <Box>\n <Text color=\"blue\">⚡ </Text>\n <Text>{event.action}</Text>\n </Box>\n );\n\n case 'confirm':\n return (\n <Box>\n <Text color=\"yellow\">❓ </Text>\n <Text color=\"yellow\">{event.reason}</Text>\n </Box>\n );\n\n case 'question':\n return (\n <Box>\n <Text color=\"magenta\">📝 </Text>\n <Text color=\"magenta\">{event.question}</Text>\n </Box>\n );\n\n case 'finished':\n return (\n <Box>\n <Text color={event.success ? 'green' : 'red'}>\n {event.success ? '✅ ' : '❌ '}\n </Text>\n <Text>{event.summary}</Text>\n </Box>\n );\n\n case 'error':\n return (\n <Box>\n <Text color=\"red\">⚠️ </Text>\n <Text color=\"red\">{event.message}</Text>\n </Box>\n );\n\n default:\n return null;\n }\n};\n","import React, { useState } from 'react';\nimport { Text, Box, useInput } from 'ink';\n\ninterface ConfirmDialogProps {\n reason: string;\n onConfirm: (approved: boolean) => void;\n}\n\nexport const ConfirmDialog: React.FC<ConfirmDialogProps> = ({ reason, onConfirm }) => {\n const [selected, setSelected] = useState<'yes' | 'no'>('yes');\n\n useInput((input, key) => {\n if (key.leftArrow || input === 'h') {\n setSelected('yes');\n } else if (key.rightArrow || input === 'l') {\n setSelected('no');\n } else if (key.return) {\n onConfirm(selected === 'yes');\n } else if (input === 'y' || input === 'Y') {\n onConfirm(true);\n } else if (input === 'n' || input === 'N') {\n onConfirm(false);\n }\n });\n\n return (\n <Box flexDirection=\"column\" borderStyle=\"round\" borderColor=\"yellow\" paddingX={2} paddingY={1}>\n <Box marginBottom={1}>\n <Text color=\"yellow\" bold>\n Confirmation Required\n </Text>\n </Box>\n <Box marginBottom={1}>\n <Text>{reason}</Text>\n </Box>\n <Box>\n <Box marginRight={2}>\n <Text\n backgroundColor={selected === 'yes' ? 'green' : undefined}\n color={selected === 'yes' ? 'white' : 'gray'}\n >\n {' [Y]es '}\n </Text>\n </Box>\n <Box>\n <Text\n backgroundColor={selected === 'no' ? 'red' : undefined}\n color={selected === 'no' ? 'white' : 'gray'}\n >\n {' [N]o '}\n </Text>\n </Box>\n </Box>\n <Box marginTop={1}>\n <Text color=\"gray\" dimColor>\n Press Y/N or use arrow keys and Enter\n </Text>\n </Box>\n </Box>\n );\n};\n","import React, { useState } from 'react';\nimport { Text, Box, useInput } from 'ink';\nimport TextInput from 'ink-text-input';\n\ninterface QuestionDialogProps {\n question: string;\n onAnswer: (answer: string) => void;\n}\n\nexport const QuestionDialog: React.FC<QuestionDialogProps> = ({ question, onAnswer }) => {\n const [answer, setAnswer] = useState('');\n\n const handleSubmit = () => {\n if (answer.trim()) {\n onAnswer(answer.trim());\n }\n };\n\n useInput((_, key) => {\n if (key.return && answer.trim()) {\n handleSubmit();\n }\n });\n\n return (\n <Box flexDirection=\"column\" borderStyle=\"round\" borderColor=\"magenta\" paddingX={2} paddingY={1}>\n <Box marginBottom={1}>\n <Text color=\"magenta\" bold>\n Agent Question\n </Text>\n </Box>\n <Box marginBottom={1}>\n <Text>{question}</Text>\n </Box>\n <Box>\n <Text color=\"green\">{'> '}</Text>\n <TextInput\n value={answer}\n onChange={setAnswer}\n onSubmit={handleSubmit}\n placeholder=\"Type your answer...\"\n />\n </Box>\n <Box marginTop={1}>\n <Text color=\"gray\" dimColor>\n Press Enter to submit\n </Text>\n </Box>\n </Box>\n );\n};\n","import React from 'react';\nimport { Text, Box } from 'ink';\nimport InkSpinner from 'ink-spinner';\n\ninterface SpinnerProps {\n text?: string;\n type?: 'dots' | 'line' | 'arc' | 'circle';\n}\n\nexport const Spinner: React.FC<SpinnerProps> = ({ text = '', type = 'dots' }) => {\n return (\n <Box>\n <Text color=\"cyan\">\n <InkSpinner type={type} />\n </Text>\n {text && <Text> {text}</Text>}\n </Box>\n );\n};\n"],"mappings":"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","names":["React","yargs","React","useEffect","useState","Box","Text","useCallback","React","Text","Box","React","useState","Text","Box","useInput","React","useState","Text","Box","useInput","React","Text","Box","useState","useEffect","React","Box","Text","React"]}
1
+ {"version":3,"sources":["../src/index.tsx","../src/cli.ts","../src/config.ts","../src/commands/login.ts","../src/commands/logout.ts","../src/commands/update.ts","../src/app/App.tsx","../src/hooks/useAgent.ts","../src/hooks/useKeybindings.ts","../src/components/StatusBar.tsx","../src/components/EventDisplay.tsx","../src/components/ConfirmDialog.tsx","../src/components/QuestionDialog.tsx","../src/components/PromptInput.tsx","../src/components/Spinner.tsx"],"sourcesContent":["/**\n * AGI CLI - Terminal-based agent interaction for AGI desktop automation.\n *\n * Usage:\n * agi \"Open calculator and compute 2+2\"\n * agi \"Find flights from SFO to JFK\" --model claude-opus\n * agi \"Install Node.js\" --verbose\n * agi login\n * agi logout\n */\n\nimport React from 'react';\nimport { render } from 'ink';\nimport { isBinaryAvailable } from '@agi_inc/agi-js';\nimport { parseArgs } from './cli.js';\nimport { App } from './app/App.js';\nimport { loadApiKey } from './config.js';\n\nasync function main(): Promise<void> {\n try {\n const result = await parseArgs();\n\n // login/logout subcommands are self-contained\n if (result.kind === 'handled') {\n return;\n }\n\n const { args } = result;\n\n // Check for API key\n const apiKey = loadApiKey();\n if (!apiKey) {\n console.error('Error: No API key found');\n console.error('');\n console.error('Run `agi login` to authenticate, or set an environment variable:');\n console.error(' export AGI_API_KEY=your_key');\n console.error('');\n process.exit(1);\n }\n\n // Make the key available to downstream code via env\n if (!process.env.AGI_API_KEY && !process.env.ANTHROPIC_API_KEY) {\n process.env.AGI_API_KEY = apiKey;\n }\n\n // Check for driver binary\n if (!isBinaryAvailable()) {\n console.error('Error: AGI driver binary not found');\n console.error('');\n console.error('The driver binary is required for local agent execution.');\n console.error('It should be installed automatically with the agi package.');\n console.error('');\n console.error('Try reinstalling: npm install -g @agi_inc/cli');\n console.error('');\n process.exit(1);\n }\n\n // Render the app\n const { waitUntilExit } = render(<App args={args} />);\n await waitUntilExit();\n } catch (error) {\n console.error('Error:', error);\n process.exit(1);\n }\n}\n\nmain();\n","/**\n * CLI argument parsing and configuration.\n */\n\nimport yargs from 'yargs';\nimport { hideBin } from 'yargs/helpers';\nimport { loginCommand } from './commands/login.js';\nimport { logoutCommand } from './commands/logout.js';\nimport { updateCommand } from './commands/update.js';\n\nexport interface CliArgs {\n goal: string | undefined;\n model: string;\n verbose: boolean;\n noConfirm: boolean;\n}\n\nexport type ParseResult =\n | { kind: 'run'; args: CliArgs }\n | { kind: 'handled' };\n\nexport async function parseArgs(): Promise<ParseResult> {\n const argv = await yargs(hideBin(process.argv))\n .scriptName('agi')\n .command('login', 'Authenticate and save your API key', {}, async () => {\n await loginCommand();\n })\n .command('logout', 'Remove saved credentials', {}, async () => {\n await logoutCommand();\n })\n .command('update', 'Update AGI CLI to the latest version', {}, async () => {\n await updateCommand();\n })\n .command(\n '$0 [goal]',\n 'Run an agent with the given goal',\n (yargs) => {\n return yargs.positional('goal', {\n describe: 'The task for the agent to accomplish',\n type: 'string',\n demandOption: false,\n });\n },\n )\n .option('model', {\n alias: 'm',\n describe: 'Model to use',\n type: 'string',\n default: 'claude-sonnet',\n choices: ['claude-sonnet', 'claude-opus'],\n })\n .option('verbose', {\n alias: 'v',\n describe: 'Show verbose output including agent thinking',\n type: 'boolean',\n default: false,\n })\n .option('no-confirm', {\n describe: 'Auto-approve all confirmation requests',\n type: 'boolean',\n default: false,\n })\n .help()\n .alias('help', 'h')\n .version()\n .alias('version', 'V')\n .example('$0 \"Open calculator and compute 2+2\"', 'Basic task')\n .example('$0 \"Find flights from SFO to JFK\" --model claude-opus', 'Use a specific model')\n .example('$0 \"Install Node.js\" --verbose', 'Verbose output')\n .example('$0', 'Start interactive mode')\n .example('$0 login', 'Authenticate with your API key')\n .example('$0 update', 'Update to the latest version')\n .parse();\n\n // If a subcommand (login/logout) was handled, yargs already ran its handler\n const command = argv._?.[0];\n if (command === 'login' || command === 'logout' || command === 'update') {\n return { kind: 'handled' };\n }\n\n return {\n kind: 'run',\n args: {\n goal: argv.goal as string | undefined,\n model: argv.model as string,\n verbose: argv.verbose as boolean,\n noConfirm: argv['no-confirm'] as boolean,\n },\n };\n}\n","/**\n * Credentials file management for AGI CLI.\n *\n * Checks AGI_API_KEY env -> ANTHROPIC_API_KEY env -> ~/.agi/credentials file.\n */\n\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport os from 'node:os';\n\ninterface Credentials {\n api_key: string;\n}\n\nexport function getCredentialsPath(): string {\n return path.join(os.homedir(), '.agi', 'credentials');\n}\n\n/**\n * Load API key from environment variables or credentials file.\n * Priority: AGI_API_KEY env -> ANTHROPIC_API_KEY env -> ~/.agi/credentials\n */\nexport function loadApiKey(): string | undefined {\n if (process.env.AGI_API_KEY) {\n return process.env.AGI_API_KEY;\n }\n\n if (process.env.ANTHROPIC_API_KEY) {\n return process.env.ANTHROPIC_API_KEY;\n }\n\n const credPath = getCredentialsPath();\n try {\n const raw = fs.readFileSync(credPath, 'utf-8');\n const credentials: Credentials = JSON.parse(raw);\n if (credentials.api_key) {\n return credentials.api_key;\n }\n } catch {\n // File doesn't exist or is invalid\n }\n\n return undefined;\n}\n\n/**\n * Save API key to ~/.agi/credentials.\n * Creates the ~/.agi/ directory if it doesn't exist.\n */\nexport function saveApiKey(apiKey: string): void {\n const credPath = getCredentialsPath();\n const dir = path.dirname(credPath);\n\n if (!fs.existsSync(dir)) {\n fs.mkdirSync(dir, { recursive: true, mode: 0o700 });\n }\n\n const credentials: Credentials = { api_key: apiKey };\n fs.writeFileSync(credPath, JSON.stringify(credentials, null, 2) + '\\n', {\n mode: 0o600,\n });\n}\n\n/**\n * Delete the credentials file.\n */\nexport function deleteCredentials(): boolean {\n const credPath = getCredentialsPath();\n try {\n fs.unlinkSync(credPath);\n return true;\n } catch {\n return false;\n }\n}\n","/**\n * `agi login` command — device code auth flow.\n *\n * 1. POST /v1/auth/device -> get device_code + user_code\n * 2. Open browser to verification_url\n * 3. Poll POST /v1/auth/device/token every 5s\n * 4. On approval -> save API key to ~/.agi/credentials\n */\n\nimport { saveApiKey } from '../config.js';\n\nconst API_BASE = 'https://api.agi.tech';\n\ninterface DeviceAuthResponse {\n device_code: string;\n user_code: string;\n verification_url: string;\n expires_in: number;\n interval: number;\n}\n\ninterface DeviceAuthTokenResponse {\n api_key: string;\n email: string | null;\n}\n\nasync function openBrowser(url: string): Promise<void> {\n const open = (await import('open')).default;\n await open(url);\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nexport async function loginCommand(): Promise<void> {\n // Step 1: Initiate device auth\n let deviceAuth: DeviceAuthResponse;\n try {\n const res = await fetch(`${API_BASE}/v1/auth/device`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n });\n\n if (!res.ok) {\n const detail = await res.text();\n console.error(`Failed to start login flow (${res.status}): ${detail}`);\n process.exit(1);\n }\n\n deviceAuth = (await res.json()) as DeviceAuthResponse;\n } catch (err) {\n console.error(`Failed to connect to AGI API: ${(err as Error).message}`);\n process.exit(1);\n }\n\n // Step 2: Show code and open browser\n console.log('');\n console.log(`Your confirmation code: ${deviceAuth.user_code}`);\n console.log('');\n console.log('Opening browser to authorize...');\n console.log(` ${deviceAuth.verification_url}`);\n console.log('');\n\n try {\n await openBrowser(deviceAuth.verification_url);\n } catch {\n console.log('Could not open browser automatically. Please visit the URL above.');\n }\n\n console.log('Waiting for authorization...');\n\n // Handle Ctrl+C gracefully during polling\n const sigintHandler = () => {\n console.log('\\nLogin cancelled.');\n process.exit(130);\n };\n process.on('SIGINT', sigintHandler);\n\n // Step 3: Poll for token\n const maxAttempts = Math.ceil(deviceAuth.expires_in / deviceAuth.interval);\n const interval = deviceAuth.interval * 1000;\n let consecutiveErrors = 0;\n\n try {\n for (let i = 0; i < maxAttempts; i++) {\n await sleep(interval);\n\n try {\n const res = await fetch(`${API_BASE}/v1/auth/device/token`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ device_code: deviceAuth.device_code }),\n });\n\n consecutiveErrors = 0;\n\n if (res.status === 428) {\n // Still pending\n process.stdout.write('.');\n continue;\n }\n\n if (res.status === 410) {\n console.log('');\n console.error('Login expired. Please run `agi login` again.');\n process.exit(1);\n }\n\n if (res.ok) {\n const token = (await res.json()) as DeviceAuthTokenResponse;\n console.log('');\n\n saveApiKey(token.api_key);\n\n const identity = token.email || 'your account';\n console.log(`Logged in as ${identity}`);\n console.log('Your API key has been saved to ~/.agi/credentials');\n return;\n }\n\n // Unexpected status\n const detail = await res.text();\n console.log('');\n console.error(`Unexpected response (${res.status}): ${detail}`);\n process.exit(1);\n } catch {\n consecutiveErrors++;\n if (consecutiveErrors >= 3) {\n console.log('');\n console.error('Unable to reach AGI API. Check your internet connection.');\n console.error('Retrying...');\n consecutiveErrors = 0;\n } else {\n process.stdout.write('!');\n }\n }\n }\n\n console.log('');\n console.error('Login timed out. Please run `agi login` again.');\n process.exit(1);\n } finally {\n process.removeListener('SIGINT', sigintHandler);\n }\n}\n","/**\n * `agi logout` command — remove stored credentials.\n */\n\nimport { deleteCredentials } from '../config.js';\n\nexport async function logoutCommand(): Promise<void> {\n const deleted = deleteCredentials();\n\n if (deleted) {\n console.log('Logged out. Credentials removed from ~/.agi/credentials');\n } else {\n console.log('No credentials file found. Already logged out.');\n }\n}\n","/**\n * Self-update command for AGI CLI.\n *\n * Checks the npm registry for the latest version, detects install method\n * (npm or Homebrew), and runs the appropriate update command.\n */\n\nimport { execSync } from 'node:child_process';\nimport { readFileSync, realpathSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\n\nfunction getCurrentVersion(): string {\n // Resolve symlinks (npm global bin is a symlink to the package)\n const realScript = realpathSync(process.argv[1]);\n const pkgPath = join(dirname(realScript), '..', 'package.json');\n const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8'));\n return pkg.version;\n}\n\nasync function getLatestVersion(): Promise<string> {\n const res = await fetch('https://registry.npmjs.org/@agi_inc/cli');\n if (!res.ok) {\n throw new Error(`npm registry returned ${res.status}`);\n }\n const data = (await res.json()) as { 'dist-tags': { latest: string } };\n return data['dist-tags'].latest;\n}\n\nfunction compareVersions(a: string, b: string): number {\n const pa = a.split('.').map(Number);\n const pb = b.split('.').map(Number);\n for (let i = 0; i < 3; i++) {\n if ((pa[i] || 0) < (pb[i] || 0)) return -1;\n if ((pa[i] || 0) > (pb[i] || 0)) return 1;\n }\n return 0;\n}\n\nfunction detectInstallMethod(): 'npm' | 'homebrew' | 'unknown' {\n try {\n const agiPath = execSync('which agi', { encoding: 'utf-8' }).trim();\n if (agiPath.includes('homebrew') || agiPath.includes('Cellar')) {\n return 'homebrew';\n }\n return 'npm';\n } catch {\n return 'unknown';\n }\n}\n\nexport async function updateCommand(): Promise<void> {\n const current = getCurrentVersion();\n\n console.log('');\n console.log(` \\u25B8 AGI CLI v${current}`);\n console.log('');\n console.log(' Checking for updates...');\n\n try {\n const latest = await getLatestVersion();\n\n if (compareVersions(current, latest) >= 0) {\n console.log(` \\u25CF Up to date`);\n console.log('');\n return;\n }\n\n console.log(` Update available: ${current} \\u2192 ${latest}`);\n console.log('');\n\n const method = detectInstallMethod();\n\n if (method === 'homebrew') {\n console.log(' Updating via Homebrew...');\n console.log('');\n execSync('brew upgrade agi', { stdio: 'inherit' });\n } else {\n console.log(' Updating via npm...');\n console.log('');\n execSync('npm install -g @agi_inc/cli@latest', { stdio: 'inherit' });\n }\n\n console.log('');\n console.log(` \\u25CF Updated to v${latest}`);\n console.log('');\n } catch (error) {\n console.error('');\n console.error(` \\u2715 Update failed: ${error instanceof Error ? error.message : error}`);\n console.error('');\n console.error(' Try manually:');\n console.error(' npm install -g @agi_inc/cli@latest');\n console.error('');\n process.exit(1);\n }\n}\n","import React, { useEffect, useState, useCallback } from 'react';\nimport { Box, Text, useApp } from 'ink';\nimport type { CliArgs } from '../cli.js';\nimport { useAgent } from '../hooks/useAgent.js';\nimport { useKeybindings } from '../hooks/useKeybindings.js';\nimport { StatusBar } from '../components/StatusBar.js';\nimport { EventDisplay } from '../components/EventDisplay.js';\nimport { ConfirmDialog } from '../components/ConfirmDialog.js';\nimport { QuestionDialog } from '../components/QuestionDialog.js';\nimport { PromptInput } from '../components/PromptInput.js';\nimport { Spinner } from '../components/Spinner.js';\n\ninterface AppProps {\n args: CliArgs;\n}\n\ntype Phase = 'input' | 'executing';\n\nexport const App: React.FC<AppProps> = ({ args }) => {\n const { exit } = useApp();\n const [phase, setPhase] = useState<Phase>(args.goal ? 'executing' : 'input');\n const [currentGoal, setCurrentGoal] = useState(args.goal ?? '');\n\n const {\n state,\n step,\n events,\n pendingConfirm,\n pendingQuestion,\n start,\n stop,\n pause,\n resume,\n respondConfirm,\n respondAnswer,\n } = useAgent({\n model: args.model,\n verbose: args.verbose,\n noConfirm: args.noConfirm,\n onFinished: () => {\n setPhase('input');\n },\n });\n\n // Start executing when phase transitions to 'executing' with a goal\n useEffect(() => {\n if (phase === 'executing' && currentGoal) {\n start(currentGoal);\n }\n }, [phase, currentGoal, start]);\n\n const handleSubmitGoal = useCallback((goal: string) => {\n setCurrentGoal(goal);\n setPhase('executing');\n }, []);\n\n useKeybindings({\n onPause: pause,\n onResume: resume,\n onStop: async () => {\n if (phase === 'executing') {\n await stop();\n }\n exit();\n },\n isPaused: state === 'paused',\n disabled: phase === 'input' || !!pendingConfirm || !!pendingQuestion,\n });\n\n const isTerminal = state === 'finished' || state === 'stopped' || state === 'error';\n\n return (\n <Box flexDirection=\"column\">\n {/* Header: show interactive mode box when in input phase with no events */}\n {phase === 'input' && events.length === 0 && (\n <Box borderStyle=\"bold\" borderColor=\"gray\" paddingX={1}>\n <Text color=\"cyan\" bold>{'\\u25B8 AGI'}</Text>\n <Text>{' interactive mode'}</Text>\n </Box>\n )}\n\n {/* Status bar during execution */}\n {phase === 'executing' && (\n <StatusBar state={state} step={step} goal={currentGoal} />\n )}\n\n {/* Activity log */}\n <Box flexDirection=\"column\" marginTop={1}>\n <EventDisplay events={events} />\n\n {phase === 'executing' && state === 'running' && (\n <Box>\n <Text dimColor>{' \\u2503 '}</Text>\n <Spinner />\n </Box>\n )}\n\n {phase === 'executing' && state === 'paused' && (\n <Box>\n <Text dimColor>{' \\u2503 '}</Text>\n <Text color=\"yellow\" bold>{'\\u25AE\\u25AE'}</Text>\n <Text dimColor>{' paused \\u2014 space to resume'}</Text>\n </Box>\n )}\n </Box>\n\n {pendingConfirm && (\n <Box marginTop={1}>\n <ConfirmDialog reason={pendingConfirm} onConfirm={respondConfirm} />\n </Box>\n )}\n\n {pendingQuestion && (\n <Box marginTop={1}>\n <QuestionDialog question={pendingQuestion} onAnswer={respondAnswer} />\n </Box>\n )}\n\n {/* Prompt input when in input phase */}\n {phase === 'input' && (\n <Box marginTop={1}>\n <PromptInput onSubmit={handleSubmitGoal} />\n </Box>\n )}\n\n {/* Help bar: only during execution, not in terminal states or dialogs */}\n {phase === 'executing' && !isTerminal && !pendingConfirm && !pendingQuestion && (\n <Box marginTop={1}>\n <Text dimColor>{' space pause \\u00B7 q stop \\u00B7 ^c quit'}</Text>\n </Box>\n )}\n </Box>\n );\n};\n","import { useState, useCallback, useRef, useEffect } from 'react';\nimport { AgentDriver } from '@agi_inc/agi-js';\nimport type { DriverState, DriverAction, DriverResult } from '@agi_inc/agi-js';\nimport type { EventItem } from '../components/EventDisplay.js';\n\ninterface UseAgentOptions {\n model: string;\n agentName?: string;\n apiUrl?: string;\n verbose: boolean;\n noConfirm: boolean;\n onFinished?: (result: DriverResult) => void;\n}\n\ninterface UseAgentReturn {\n state: DriverState;\n step: number;\n events: EventItem[];\n pendingConfirm: string | null;\n pendingQuestion: string | null;\n start: (goal: string) => Promise<void>;\n stop: () => Promise<void>;\n pause: () => void;\n resume: () => void;\n respondConfirm: (approved: boolean) => void;\n respondAnswer: (answer: string) => void;\n}\n\nexport function useAgent(options: UseAgentOptions): UseAgentReturn {\n const { model, agentName, apiUrl, verbose, noConfirm, onFinished } = options;\n\n const [state, setState] = useState<DriverState>('idle');\n const [step, setStep] = useState(0);\n const [events, setEvents] = useState<EventItem[]>([]);\n const [pendingConfirm, setPendingConfirm] = useState<string | null>(null);\n const [pendingQuestion, setPendingQuestion] = useState<string | null>(null);\n\n const driverRef = useRef<AgentDriver | null>(null);\n const onFinishedRef = useRef(onFinished);\n\n // Keep the ref up to date so start() never captures a stale callback\n useEffect(() => {\n onFinishedRef.current = onFinished;\n }, [onFinished]);\n\n const addEvent = useCallback((event: EventItem) => {\n setEvents((prev) => [...prev, event]);\n }, []);\n\n const start = useCallback(\n async (goal: string) => {\n // Stop previous driver if one exists\n if (driverRef.current) {\n try {\n await driverRef.current.stop('New task started');\n } catch {\n // Ignore errors from stopping previous driver\n }\n driverRef.current = null;\n }\n\n // Reset per-task state but keep events\n setState('idle');\n setStep(0);\n setPendingConfirm(null);\n setPendingQuestion(null);\n\n // Insert separator if there are already events from a previous task\n setEvents((prev) => {\n if (prev.length > 0) {\n return [...prev, { type: 'separator', goal }];\n }\n return prev;\n });\n\n const driver = new AgentDriver({ model, mode: 'local', agentName, apiUrl });\n driverRef.current = driver;\n\n // Set up event handlers\n driver.on('state_change', (newState: DriverState) => {\n setState(newState);\n });\n\n driver.on('thinking', (text: string) => {\n if (verbose) {\n addEvent({ type: 'thinking', text });\n }\n });\n\n driver.on('action', async (action: DriverAction) => {\n const actionStr = action.type + (action.x !== undefined ? ` (${action.x}, ${action.y})` : '');\n const parts: string[] = [];\n if (action.text) parts.push(`\"${action.text}\"`);\n if (action.key) parts.push(`[${action.key}]`);\n addEvent({ type: 'action', action: actionStr, params: parts.length ? parts.join(' ') : undefined });\n // In local mode, the driver binary executes actions and captures screenshots\n });\n\n driver.on('confirm', async (reason: string) => {\n if (noConfirm) {\n driver.respondConfirm(true);\n return true;\n }\n addEvent({ type: 'confirm', reason });\n setPendingConfirm(reason);\n return true;\n });\n\n driver.on('ask_question', async (question: string) => {\n addEvent({ type: 'question', question });\n setPendingQuestion(question);\n return '';\n });\n\n driver.on('finished', (evt) => {\n addEvent({\n type: 'finished',\n summary: evt.summary,\n success: evt.success,\n });\n });\n\n driver.on('error', (evt) => {\n addEvent({ type: 'error', message: evt.message });\n });\n\n // Start the agent in local mode — no screenshot needed, driver handles it\n try {\n const result = await driver.start(goal);\n\n if (onFinishedRef.current) {\n onFinishedRef.current(result);\n }\n } catch (error) {\n addEvent({ type: 'error', message: String(error) });\n }\n },\n [model, agentName, apiUrl, verbose, noConfirm, addEvent]\n );\n\n const stop = useCallback(async () => {\n if (driverRef.current) {\n await driverRef.current.stop('User cancelled');\n }\n }, []);\n\n const pause = useCallback(() => {\n if (driverRef.current) {\n driverRef.current.pause();\n }\n }, []);\n\n const resume = useCallback(() => {\n if (driverRef.current) {\n driverRef.current.resume();\n }\n }, []);\n\n const respondConfirm = useCallback((approved: boolean) => {\n if (driverRef.current && pendingConfirm) {\n driverRef.current.respondConfirm(approved);\n setPendingConfirm(null);\n }\n }, [pendingConfirm]);\n\n const respondAnswer = useCallback((answer: string) => {\n if (driverRef.current && pendingQuestion) {\n driverRef.current.respondAnswer(answer);\n setPendingQuestion(null);\n }\n }, [pendingQuestion]);\n\n // Update step from driver\n useEffect(() => {\n const interval = setInterval(() => {\n if (driverRef.current) {\n setStep(driverRef.current.currentStep);\n }\n }, 100);\n return () => clearInterval(interval);\n }, []);\n\n return {\n state,\n step,\n events,\n pendingConfirm,\n pendingQuestion,\n start,\n stop,\n pause,\n resume,\n respondConfirm,\n respondAnswer,\n };\n}\n","import { useInput } from 'ink';\nimport { useCallback } from 'react';\n\ninterface UseKeybindingsOptions {\n onPause?: () => void;\n onResume?: () => void;\n onStop?: () => void;\n isPaused?: boolean;\n disabled?: boolean;\n}\n\n/**\n * Hook for handling keyboard shortcuts.\n *\n * - Space: Pause/Resume\n * - Q/Ctrl+C: Stop\n * - Escape: Stop\n */\nexport function useKeybindings(options: UseKeybindingsOptions): void {\n const { onPause, onResume, onStop, isPaused = false, disabled = false } = options;\n\n const handleInput = useCallback(\n (input: string, key: { ctrl: boolean; escape: boolean }) => {\n if (disabled) return;\n\n // Space: Toggle pause/resume\n if (input === ' ') {\n if (isPaused) {\n onResume?.();\n } else {\n onPause?.();\n }\n }\n\n // Q or Ctrl+C: Stop\n if (input === 'q' || input === 'Q' || (key.ctrl && input === 'c')) {\n onStop?.();\n }\n\n // Escape: Stop\n if (key.escape) {\n onStop?.();\n }\n },\n [disabled, isPaused, onPause, onResume, onStop]\n );\n\n useInput(handleInput);\n}\n","import React from 'react';\nimport { Text, Box } from 'ink';\nimport type { DriverState } from '@agi_inc/agi-js';\n\ninterface StatusBarProps {\n state: DriverState;\n step: number;\n goal: string;\n}\n\nconst stateColors: Record<DriverState, string> = {\n idle: 'gray',\n running: 'green',\n paused: 'yellow',\n waiting_confirmation: 'yellow',\n waiting_answer: 'yellow',\n finished: 'green',\n stopped: 'gray',\n error: 'red',\n};\n\nconst stateLabels: Record<DriverState, string> = {\n idle: 'IDLE',\n running: 'ACTIVE',\n paused: 'PAUSED',\n waiting_confirmation: 'AWAITING',\n waiting_answer: 'AWAITING',\n finished: 'COMPLETE',\n stopped: 'STOPPED',\n error: 'ERROR',\n};\n\nconst stateIndicators: Record<DriverState, string> = {\n idle: '○',\n running: '●',\n paused: '◉',\n waiting_confirmation: '◎',\n waiting_answer: '◎',\n finished: '●',\n stopped: '○',\n error: '●',\n};\n\nexport const StatusBar: React.FC<StatusBarProps> = ({ state, step, goal }) => {\n const color = stateColors[state] || 'white';\n const label = stateLabels[state] || state.toUpperCase();\n const indicator = stateIndicators[state] || '○';\n\n return (\n <Box flexDirection=\"column\" borderStyle=\"bold\" borderColor=\"gray\" paddingX={1}>\n <Box>\n <Text color=\"cyan\" bold>{'▸ AGI'}</Text>\n <Text>{' '}</Text>\n <Text color={color}>{indicator} </Text>\n <Text color={color} bold>{label}</Text>\n <Box flexGrow={1} />\n <Text dimColor>STEP </Text>\n <Text bold>{String(step).padStart(2, '0')}</Text>\n </Box>\n <Box>\n <Text dimColor>{goal.length > 72 ? goal.slice(0, 72) + '\\u2026' : goal}</Text>\n </Box>\n </Box>\n );\n};\n","import React from 'react';\nimport { Text, Box } from 'ink';\n\nexport type EventItem =\n | { type: 'thinking'; text: string }\n | { type: 'action'; action: string; params?: string }\n | { type: 'confirm'; reason: string }\n | { type: 'question'; question: string }\n | { type: 'finished'; summary: string; success: boolean }\n | { type: 'error'; message: string }\n | { type: 'separator'; goal: string };\n\ninterface EventDisplayProps {\n events: EventItem[];\n maxEvents?: number;\n}\n\nconst typeConfig: Record<string, { prefix: string; color: string }> = {\n thinking: { prefix: '\\u00B7', color: 'gray' },\n action: { prefix: '\\u25B8', color: 'white' },\n confirm: { prefix: '\\u25C6', color: 'yellow' },\n question: { prefix: '\\u25C7', color: 'cyan' },\n error: { prefix: '\\u2715', color: 'red' },\n};\n\nfunction getEventText(event: EventItem): string {\n switch (event.type) {\n case 'thinking':\n return event.text;\n case 'action':\n return event.action;\n case 'confirm':\n return event.reason;\n case 'question':\n return event.question;\n case 'finished':\n return event.summary;\n case 'error':\n return event.message;\n case 'separator':\n return event.goal;\n }\n}\n\nfunction getEventStyle(event: EventItem): { prefix: string; color: string } {\n if (event.type === 'finished') {\n return event.success\n ? { prefix: '\\u25CF', color: 'green' }\n : { prefix: '\\u2715', color: 'red' };\n }\n return typeConfig[event.type];\n}\n\nexport const EventDisplay: React.FC<EventDisplayProps> = ({ events, maxEvents = 12 }) => {\n const displayEvents = events.slice(-maxEvents);\n\n if (displayEvents.length === 0) return null;\n\n return (\n <Box flexDirection=\"column\">\n {displayEvents.map((event, index) => {\n if (event.type === 'separator') {\n return (\n <Box key={index} marginTop={1}>\n <Text dimColor>{' \\u2500\\u2500 '}</Text>\n <Text bold>{event.goal}</Text>\n <Text dimColor>{' \\u2500\\u2500'}</Text>\n </Box>\n );\n }\n\n const style = getEventStyle(event);\n const text = getEventText(event);\n const isLatest = index === displayEvents.length - 1;\n\n return (\n <Box key={index}>\n <Text dimColor>{' \\u2503 '}</Text>\n <Text color={style.color}>{style.prefix} </Text>\n <Text\n color={style.color === 'white' ? undefined : style.color}\n bold={isLatest && event.type === 'action'}\n dimColor={event.type === 'thinking'}\n >\n {text}\n </Text>\n {event.type === 'action' && event.params && (\n <Text color=\"gray\">{' '}{event.params}</Text>\n )}\n </Box>\n );\n })}\n </Box>\n );\n};\n","import React, { useState } from 'react';\nimport { Text, Box, useInput } from 'ink';\n\ninterface ConfirmDialogProps {\n reason: string;\n onConfirm: (approved: boolean) => void;\n}\n\nexport const ConfirmDialog: React.FC<ConfirmDialogProps> = ({ reason, onConfirm }) => {\n const [selected, setSelected] = useState<'yes' | 'no'>('yes');\n\n useInput((input, key) => {\n if (key.leftArrow || input === 'h') {\n setSelected('yes');\n } else if (key.rightArrow || input === 'l') {\n setSelected('no');\n } else if (key.return) {\n onConfirm(selected === 'yes');\n } else if (input === 'y' || input === 'Y') {\n onConfirm(true);\n } else if (input === 'n' || input === 'N') {\n onConfirm(false);\n }\n });\n\n return (\n <Box flexDirection=\"column\" borderStyle=\"bold\" borderColor=\"yellow\" paddingX={2} paddingY={1}>\n <Box marginBottom={1}>\n <Text color=\"yellow\" bold>CONFIRM</Text>\n </Box>\n <Box marginBottom={1}>\n <Text>{reason}</Text>\n </Box>\n <Box>\n <Box marginRight={2}>\n <Text\n backgroundColor={selected === 'yes' ? 'green' : undefined}\n color={selected === 'yes' ? 'black' : 'gray'}\n bold={selected === 'yes'}\n >\n {' [Y] approve '}\n </Text>\n </Box>\n <Text\n backgroundColor={selected === 'no' ? 'red' : undefined}\n color={selected === 'no' ? 'black' : 'gray'}\n bold={selected === 'no'}\n >\n {' [N] deny '}\n </Text>\n </Box>\n <Box marginTop={1}>\n <Text dimColor>Y/N or arrows + enter</Text>\n </Box>\n </Box>\n );\n};\n","import React, { useState } from 'react';\nimport { Text, Box, useInput } from 'ink';\nimport TextInput from 'ink-text-input';\n\ninterface QuestionDialogProps {\n question: string;\n onAnswer: (answer: string) => void;\n}\n\nexport const QuestionDialog: React.FC<QuestionDialogProps> = ({ question, onAnswer }) => {\n const [answer, setAnswer] = useState('');\n\n const handleSubmit = () => {\n if (answer.trim()) {\n onAnswer(answer.trim());\n }\n };\n\n useInput((_, key) => {\n if (key.return && answer.trim()) {\n handleSubmit();\n }\n });\n\n return (\n <Box flexDirection=\"column\" borderStyle=\"bold\" borderColor=\"cyan\" paddingX={2} paddingY={1}>\n <Box marginBottom={1}>\n <Text color=\"cyan\" bold>INPUT REQUIRED</Text>\n </Box>\n <Box marginBottom={1}>\n <Text>{question}</Text>\n </Box>\n <Box>\n <Text color=\"cyan\">{'\\u25B8 '}</Text>\n <TextInput\n value={answer}\n onChange={setAnswer}\n onSubmit={handleSubmit}\n placeholder=\"Type your answer...\"\n />\n </Box>\n <Box marginTop={1}>\n <Text dimColor>enter to submit</Text>\n </Box>\n </Box>\n );\n};\n","import React, { useState } from 'react';\nimport { Text, Box } from 'ink';\nimport TextInput from 'ink-text-input';\n\ninterface PromptInputProps {\n onSubmit: (goal: string) => void;\n}\n\nexport const PromptInput: React.FC<PromptInputProps> = ({ onSubmit }) => {\n const [value, setValue] = useState('');\n\n const handleSubmit = () => {\n const trimmed = value.trim();\n if (trimmed) {\n onSubmit(trimmed);\n setValue('');\n }\n };\n\n return (\n <Box>\n <Text color=\"cyan\" bold>{'\\u25B8 '}</Text>\n <TextInput\n value={value}\n onChange={setValue}\n onSubmit={handleSubmit}\n placeholder=\"Enter a task...\"\n />\n </Box>\n );\n};\n","import React from 'react';\nimport { Text, Box } from 'ink';\nimport InkSpinner from 'ink-spinner';\n\ninterface SpinnerProps {\n text?: string;\n}\n\nexport const Spinner: React.FC<SpinnerProps> = ({ text }) => {\n return (\n <Box>\n <Text color=\"cyan\">\n <InkSpinner type=\"dots\" />\n </Text>\n {text && <Text dimColor> {text}</Text>}\n </Box>\n );\n};\n"],"mappings":"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","names":["React","yargs","React","useEffect","useState","useCallback","Box","Text","useCallback","React","Text","Box","React","useState","Text","Box","useInput","React","useState","Text","Box","useInput","React","useState","Text","Box","TextInput","React","Text","Box","useState","useEffect","useCallback","React","Box","Text","React"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agi_inc/cli",
3
- "version": "0.5.1",
3
+ "version": "0.5.3",
4
4
  "description": "Terminal-based agent interaction for AGI desktop automation",
5
5
  "main": "./dist/index.js",
6
6
  "bin": {
@@ -13,7 +13,8 @@
13
13
  "lint": "eslint src --ext .ts,.tsx",
14
14
  "format": "prettier --write \"src/**/*.{ts,tsx}\"",
15
15
  "typecheck": "tsc --noEmit",
16
- "prepublishOnly": "npm run build"
16
+ "prepublishOnly": "npm run build",
17
+ "screenshots": "node scripts/generate-screenshots.mjs"
17
18
  },
18
19
  "keywords": [
19
20
  "agi",
@@ -47,10 +48,11 @@
47
48
  "LICENSE"
48
49
  ],
49
50
  "dependencies": {
50
- "agi": "^0.4.1",
51
+ "@agi_inc/agi-js": "^0.4.2",
51
52
  "ink": "^5.0.1",
52
53
  "ink-spinner": "^5.0.0",
53
54
  "ink-text-input": "^6.0.0",
55
+ "open": "^11.0.0",
54
56
  "react": "^18.3.1",
55
57
  "yargs": "^17.7.2"
56
58
  },
@@ -63,6 +65,7 @@
63
65
  "eslint": "^8.55.0",
64
66
  "eslint-config-prettier": "^9.1.0",
65
67
  "prettier": "^3.1.0",
68
+ "puppeteer": "^24.37.2",
66
69
  "tsup": "^8.0.1",
67
70
  "typescript": "^5.3.3"
68
71
  }