@contextgraph/agent 0.4.24 → 0.4.26

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/dist/index.js CHANGED
@@ -4,7 +4,7 @@
4
4
  import { Command } from "commander";
5
5
  import { readFileSync as readFileSync2 } from "fs";
6
6
  import { fileURLToPath as fileURLToPath2 } from "url";
7
- import { dirname as dirname2, join as join6 } from "path";
7
+ import { dirname as dirname2, join as join5 } from "path";
8
8
 
9
9
  // src/callback-server.ts
10
10
  import http from "http";
@@ -42,6 +42,7 @@ async function startCallbackServer() {
42
42
  if (url.pathname === "/callback") {
43
43
  const token = url.searchParams.get("token");
44
44
  const userId = url.searchParams.get("userId");
45
+ const email = url.searchParams.get("email");
45
46
  if (!token) {
46
47
  res.writeHead(400, { "Content-Type": "text/html; charset=utf-8" });
47
48
  res.end(getErrorPage("Missing token parameter"));
@@ -53,7 +54,7 @@ async function startCallbackServer() {
53
54
  return;
54
55
  }
55
56
  if (callbackResolve) {
56
- callbackResolve({ token, userId });
57
+ callbackResolve({ token, userId, ...email ? { email } : {} });
57
58
  }
58
59
  res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
59
60
  res.end(getSuccessPage());
@@ -542,6 +543,7 @@ async function authenticateAgent(options = {}) {
542
543
  await saveCredentials({
543
544
  clerkToken: result.token,
544
545
  userId: result.userId,
546
+ ...result.email ? { email: result.email } : {},
545
547
  expiresAt,
546
548
  createdAt: (/* @__PURE__ */ new Date()).toISOString()
547
549
  });
@@ -550,7 +552,8 @@ async function authenticateAgent(options = {}) {
550
552
  success: true,
551
553
  credentials: {
552
554
  token: result.token,
553
- userId: result.userId
555
+ userId: result.userId,
556
+ email: result.email
554
557
  }
555
558
  };
556
559
  } catch (error) {
@@ -581,69 +584,6 @@ async function runAuth() {
581
584
  // src/claude-sdk.ts
582
585
  import { query } from "@anthropic-ai/claude-agent-sdk";
583
586
 
584
- // src/plugin-setup.ts
585
- import { spawn } from "child_process";
586
- import { access, mkdir } from "fs/promises";
587
- import { join } from "path";
588
- import { homedir } from "os";
589
- var PLUGIN_REPO = "https://github.com/contextgraph/claude-code-plugin.git";
590
- var PLUGIN_DIR = join(homedir(), ".contextgraph", "claude-code-plugin");
591
- var PLUGIN_PATH = join(PLUGIN_DIR, "plugins", "contextgraph");
592
- async function ensurePlugin() {
593
- try {
594
- await access(PLUGIN_PATH);
595
- console.log(`\u{1F4E6} Using plugin: ${PLUGIN_PATH}`);
596
- return PLUGIN_PATH;
597
- } catch {
598
- }
599
- let repoDirExists = false;
600
- try {
601
- await access(PLUGIN_DIR);
602
- repoDirExists = true;
603
- } catch {
604
- }
605
- if (repoDirExists) {
606
- console.log("\u{1F4E6} Plugin directory exists but incomplete, pulling latest...");
607
- await runCommand("git", ["pull"], PLUGIN_DIR);
608
- try {
609
- await access(PLUGIN_PATH);
610
- console.log(`\u{1F4E6} Plugin ready: ${PLUGIN_PATH}`);
611
- return PLUGIN_PATH;
612
- } catch {
613
- throw new Error(`Plugin not found at ${PLUGIN_PATH} even after git pull. Check repository structure.`);
614
- }
615
- }
616
- console.log(`\u{1F4E6} Cloning plugin from ${PLUGIN_REPO}...`);
617
- const contextgraphDir = join(homedir(), ".contextgraph");
618
- try {
619
- await mkdir(contextgraphDir, { recursive: true });
620
- } catch {
621
- }
622
- await runCommand("git", ["clone", PLUGIN_REPO, PLUGIN_DIR]);
623
- try {
624
- await access(PLUGIN_PATH);
625
- console.log(`\u{1F4E6} Plugin installed: ${PLUGIN_PATH}`);
626
- return PLUGIN_PATH;
627
- } catch {
628
- throw new Error(`Plugin clone succeeded but plugin path not found at ${PLUGIN_PATH}`);
629
- }
630
- }
631
- function runCommand(command, args, cwd) {
632
- return new Promise((resolve, reject) => {
633
- const proc = spawn(command, args, { cwd, stdio: "inherit" });
634
- proc.on("close", (code) => {
635
- if (code === 0) {
636
- resolve();
637
- } else {
638
- reject(new Error(`${command} ${args[0]} failed with exit code ${code}`));
639
- }
640
- });
641
- proc.on("error", (err) => {
642
- reject(new Error(`Failed to spawn ${command}: ${err.message}`));
643
- });
644
- });
645
- }
646
-
647
587
  // src/sdk-event-transformer.ts
648
588
  function transformSDKMessage(message) {
649
589
  const timestamp = (/* @__PURE__ */ new Date()).toISOString();
@@ -850,8 +790,6 @@ async function executeClaude(options) {
850
790
  abortController.abort();
851
791
  }, EXECUTION_TIMEOUT_MS);
852
792
  try {
853
- const pluginPath = await ensurePlugin();
854
- console.log("[Agent SDK] Loading plugin from:", pluginPath);
855
793
  console.log("[Agent SDK] Auth token available:", !!options.authToken);
856
794
  console.log("[Agent SDK] Auth token prefix:", options.authToken?.substring(0, 20) + "...");
857
795
  console.log("[Agent SDK] Anthropic API key available:", !!process.env.ANTHROPIC_API_KEY);
@@ -1356,25 +1294,25 @@ var HeartbeatManager = class {
1356
1294
  // src/workspace-setup.ts
1357
1295
  import { mkdtemp as mkdtemp2, rm as rm2 } from "fs/promises";
1358
1296
  import { tmpdir as tmpdir2 } from "os";
1359
- import { join as join4 } from "path";
1297
+ import { join as join3 } from "path";
1360
1298
 
1361
1299
  // src/workspace-prep.ts
1362
- import { spawn as spawn2 } from "child_process";
1300
+ import { spawn } from "child_process";
1363
1301
  import { mkdtemp, rm, appendFile } from "fs/promises";
1364
1302
  import { tmpdir } from "os";
1365
- import { join as join3 } from "path";
1303
+ import { join as join2 } from "path";
1366
1304
 
1367
1305
  // src/skill-injection.ts
1368
- import { mkdir as mkdir2, writeFile } from "fs/promises";
1369
- import { join as join2 } from "path";
1306
+ import { mkdir, writeFile } from "fs/promises";
1307
+ import { join } from "path";
1370
1308
  async function injectSkills(workspacePath, skills) {
1371
1309
  if (skills.length === 0) {
1372
1310
  return;
1373
1311
  }
1374
1312
  for (const skill of skills) {
1375
1313
  try {
1376
- const skillDir = join2(workspacePath, ".claude", "skills", skill.name);
1377
- await mkdir2(skillDir, { recursive: true });
1314
+ const skillDir = join(workspacePath, ".claude", "skills", skill.name);
1315
+ await mkdir(skillDir, { recursive: true });
1378
1316
  const triggerSection = skill.trigger ? `trigger: |
1379
1317
  ${skill.trigger.split("\n").map((line) => ` ${line}`).join("\n")}
1380
1318
  ` : "";
@@ -1385,7 +1323,7 @@ ${triggerSection}---
1385
1323
 
1386
1324
  ${skill.content}
1387
1325
  `;
1388
- const skillFilePath = join2(skillDir, "SKILL.md");
1326
+ const skillFilePath = join(skillDir, "SKILL.md");
1389
1327
  await writeFile(skillFilePath, skillContent, "utf-8");
1390
1328
  } catch (error) {
1391
1329
  console.error(`\u274C Failed to inject skill "${skill.name}":`, error);
@@ -1442,6 +1380,7 @@ async function fetchSkillsLibrary(options) {
1442
1380
  }
1443
1381
 
1444
1382
  // src/workspace-prep.ts
1383
+ import chalk from "chalk";
1445
1384
  var API_BASE_URL2 = "https://www.contextgraph.dev";
1446
1385
  async function fetchGitHubCredentials(authToken) {
1447
1386
  const response = await fetchWithRetry(`${API_BASE_URL2}/api/cli/credentials`, {
@@ -1467,7 +1406,7 @@ ${errorText}`);
1467
1406
  }
1468
1407
  function runGitCommand(args, cwd) {
1469
1408
  return new Promise((resolve, reject) => {
1470
- const proc = spawn2("git", args, { cwd });
1409
+ const proc = spawn("git", args, { cwd });
1471
1410
  let stdout = "";
1472
1411
  let stderr = "";
1473
1412
  proc.stdout.on("data", (data) => {
@@ -1501,27 +1440,27 @@ function buildAuthenticatedUrl(repoUrl, token, username) {
1501
1440
  async function prepareWorkspace(repoUrl, options) {
1502
1441
  const { branch, authToken, runId, skipSkills } = options;
1503
1442
  const credentials = await fetchGitHubCredentials(authToken);
1504
- const workspacePath = await mkdtemp(join3(tmpdir(), "cg-workspace-"));
1443
+ const workspacePath = await mkdtemp(join2(tmpdir(), "cg-workspace-"));
1505
1444
  const cleanup = async () => {
1506
1445
  try {
1507
1446
  await rm(workspacePath, { recursive: true, force: true });
1508
1447
  } catch (error) {
1509
- console.error(`Warning: Failed to cleanup workspace at ${workspacePath}:`, error);
1448
+ console.error(chalk.yellow(`Warning: Failed to cleanup workspace at ${workspacePath}:`), error);
1510
1449
  }
1511
1450
  };
1512
1451
  try {
1513
1452
  const cloneUrl = buildAuthenticatedUrl(repoUrl, credentials.githubToken, credentials.gitCredentialsUsername);
1514
- console.log(`\u{1F4C2} Cloning ${repoUrl}`);
1515
- console.log(` \u2192 ${workspacePath}`);
1453
+ console.log(`Cloning ${chalk.cyan(repoUrl)}`);
1454
+ console.log(chalk.dim(` ${workspacePath}`));
1516
1455
  await runGitCommand(["clone", cloneUrl, workspacePath]);
1517
- console.log(`\u2705 Repository cloned`);
1456
+ console.log(chalk.green("Repository cloned"));
1518
1457
  if (credentials.githubUsername) {
1519
1458
  await runGitCommand(["config", "user.name", credentials.githubUsername], workspacePath);
1520
1459
  }
1521
1460
  if (credentials.githubEmail) {
1522
1461
  await runGitCommand(["config", "user.email", credentials.githubEmail], workspacePath);
1523
1462
  }
1524
- await appendFile(join3(workspacePath, ".git", "info", "exclude"), "\n.claude/skills/\n");
1463
+ await appendFile(join2(workspacePath, ".git", "info", "exclude"), "\n.claude/skills/\n");
1525
1464
  if (branch) {
1526
1465
  const { stdout } = await runGitCommand(
1527
1466
  ["ls-remote", "--heads", "origin", branch],
@@ -1529,10 +1468,10 @@ async function prepareWorkspace(repoUrl, options) {
1529
1468
  );
1530
1469
  const branchExists = stdout.trim().length > 0;
1531
1470
  if (branchExists) {
1532
- console.log(`\u{1F33F} Checking out branch: ${branch}`);
1471
+ console.log(`Checking out branch: ${chalk.cyan(branch)}`);
1533
1472
  await runGitCommand(["checkout", branch], workspacePath);
1534
1473
  } else {
1535
- console.log(`\u{1F331} Creating new branch: ${branch}`);
1474
+ console.log(`Creating new branch: ${chalk.cyan(branch)}`);
1536
1475
  await runGitCommand(["checkout", "-b", branch], workspacePath);
1537
1476
  }
1538
1477
  }
@@ -1540,17 +1479,17 @@ async function prepareWorkspace(repoUrl, options) {
1540
1479
  const startingCommit = commitHash.trim();
1541
1480
  console.log("");
1542
1481
  if (skipSkills) {
1543
- console.log("\u{1F4DA} Skipping skill injection (--no-skills flag)");
1482
+ console.log(chalk.dim("Skipping skill injection (--no-skills flag)"));
1544
1483
  } else {
1545
1484
  try {
1546
1485
  const librarySkills = await fetchSkillsLibrary({ authToken, runId });
1547
1486
  if (librarySkills.length > 0) {
1548
1487
  await injectSkills(workspacePath, librarySkills);
1549
1488
  } else {
1550
- console.log("\u{1F4DA} No skills to inject (empty library)");
1489
+ console.log(chalk.dim("No skills to inject (empty library)"));
1551
1490
  }
1552
1491
  } catch (skillError) {
1553
- console.warn("\u26A0\uFE0F Skill injection failed (agent will continue):", skillError);
1492
+ console.warn(chalk.yellow("Skill injection failed (agent will continue):"), skillError);
1554
1493
  }
1555
1494
  }
1556
1495
  return { path: workspacePath, startingCommit, cleanup };
@@ -1563,7 +1502,7 @@ async function prepareWorkspace(repoUrl, options) {
1563
1502
  // package.json
1564
1503
  var package_default = {
1565
1504
  name: "@contextgraph/agent",
1566
- version: "0.4.24",
1505
+ version: "0.4.25",
1567
1506
  description: "Autonomous agent for contextgraph action execution",
1568
1507
  type: "module",
1569
1508
  bin: {
@@ -1592,7 +1531,9 @@ var package_default = {
1592
1531
  },
1593
1532
  dependencies: {
1594
1533
  "@anthropic-ai/claude-agent-sdk": "^0.1.50",
1534
+ chalk: "^5.6.2",
1595
1535
  commander: "^11.0.0",
1536
+ listr2: "^9.0.5",
1596
1537
  open: "^10.0.0"
1597
1538
  },
1598
1539
  devDependencies: {
@@ -1719,21 +1660,22 @@ var ApiClient = class {
1719
1660
  };
1720
1661
 
1721
1662
  // src/workspace-setup.ts
1663
+ import chalk2 from "chalk";
1722
1664
  var API_BASE_URL3 = "https://www.contextgraph.dev";
1723
1665
  async function setupWorkspaceForAction(actionId, options) {
1724
1666
  const { authToken, phase, startingCommit: startingCommitOverride, skipSkills } = options;
1725
1667
  let actionDetail = options.actionDetail;
1726
1668
  if (!actionDetail) {
1727
1669
  const apiClient2 = new ApiClient();
1728
- console.log(`Fetching action details for ${actionId}...`);
1670
+ console.log(chalk2.dim(`Fetching action details for ${actionId}...`));
1729
1671
  actionDetail = await apiClient2.getActionDetail(actionId);
1730
1672
  }
1731
1673
  const logTransport = new LogTransportService(API_BASE_URL3, authToken);
1732
- console.log(`[Log Streaming] Creating run for ${phase} phase...`);
1674
+ console.log(chalk2.dim(`[Log Streaming] Creating run for ${phase} phase...`));
1733
1675
  const runId = await logTransport.createRun(actionId, phase, {
1734
1676
  startingCommit: startingCommitOverride
1735
1677
  });
1736
- console.log(`[Log Streaming] Run created: ${runId}`);
1678
+ console.log(chalk2.dim(`[Log Streaming] Run created: ${runId}`));
1737
1679
  const repoUrl = actionDetail.resolved_repository_url || actionDetail.repository_url;
1738
1680
  const branch = actionDetail.resolved_branch || actionDetail.branch;
1739
1681
  let workspacePath;
@@ -1750,14 +1692,14 @@ async function setupWorkspaceForAction(actionId, options) {
1750
1692
  cleanup = workspace.cleanup;
1751
1693
  startingCommit = workspace.startingCommit;
1752
1694
  } else {
1753
- console.log(`\u{1F4C2} No repository configured - creating blank workspace`);
1754
- workspacePath = await mkdtemp2(join4(tmpdir2(), "cg-workspace-"));
1755
- console.log(` \u2192 ${workspacePath}`);
1695
+ console.log(chalk2.dim("No repository configured - creating blank workspace"));
1696
+ workspacePath = await mkdtemp2(join3(tmpdir2(), "cg-workspace-"));
1697
+ console.log(chalk2.dim(` ${workspacePath}`));
1756
1698
  cleanup = async () => {
1757
1699
  try {
1758
1700
  await rm2(workspacePath, { recursive: true, force: true });
1759
1701
  } catch (error) {
1760
- console.error(`Warning: Failed to cleanup workspace at ${workspacePath}:`, error);
1702
+ console.error(chalk2.yellow(`Warning: Failed to cleanup workspace at ${workspacePath}:`), error);
1761
1703
  }
1762
1704
  };
1763
1705
  }
@@ -1771,15 +1713,16 @@ async function setupWorkspaceForAction(actionId, options) {
1771
1713
  }
1772
1714
 
1773
1715
  // src/workflows/prepare.ts
1716
+ import chalk3 from "chalk";
1774
1717
  var API_BASE_URL4 = "https://www.contextgraph.dev";
1775
1718
  async function runPrepare(actionId, options) {
1776
1719
  const credentials = await loadCredentials();
1777
1720
  if (!credentials) {
1778
- console.error("\u274C Not authenticated. Run authentication first.");
1721
+ console.error(chalk3.red("Not authenticated."), "Run authentication first.");
1779
1722
  process.exit(1);
1780
1723
  }
1781
1724
  if (isExpired(credentials) || isTokenExpired(credentials.clerkToken)) {
1782
- console.error("\u274C Token expired. Re-authenticate to continue.");
1725
+ console.error(chalk3.red("Token expired."), "Re-authenticate to continue.");
1783
1726
  process.exit(1);
1784
1727
  }
1785
1728
  let runId = options?.runId;
@@ -1801,12 +1744,12 @@ async function runPrepare(actionId, options) {
1801
1744
  runId = setup.runId;
1802
1745
  logTransport = setup.logTransport;
1803
1746
  } else {
1804
- console.log(`[Log Streaming] Using pre-created run: ${runId}`);
1747
+ console.log(chalk3.dim(`[Log Streaming] Using pre-created run: ${runId}`));
1805
1748
  workspacePath = options?.cwd || process.cwd();
1806
1749
  logTransport = new LogTransportService(API_BASE_URL4, credentials.clerkToken, runId);
1807
1750
  }
1808
- console.log(`Fetching preparation instructions for action ${actionId}...
1809
- `);
1751
+ console.log(chalk3.dim(`Fetching preparation instructions for action ${actionId}...
1752
+ `));
1810
1753
  const response = await fetchWithRetry(
1811
1754
  `${API_BASE_URL4}/api/prompts/prepare`,
1812
1755
  {
@@ -1827,7 +1770,7 @@ ${errorText}`);
1827
1770
  await logTransport.updateRunState("preparing");
1828
1771
  heartbeatManager = new HeartbeatManager(API_BASE_URL4, credentials.clerkToken, runId);
1829
1772
  heartbeatManager.start();
1830
- console.log("[Log Streaming] Heartbeat started");
1773
+ console.log(chalk3.dim("[Log Streaming] Heartbeat started"));
1831
1774
  logBuffer = new LogBuffer(logTransport);
1832
1775
  logBuffer.start();
1833
1776
  console.log("Spawning Claude for preparation...\n");
@@ -1846,14 +1789,13 @@ ${errorText}`);
1846
1789
  cost: claudeResult.cost,
1847
1790
  usage: claudeResult.usage
1848
1791
  });
1849
- console.log("\n\u2705 Preparation complete");
1792
+ console.log("\n" + chalk3.green("Preparation complete"));
1850
1793
  } else {
1851
1794
  await logTransport.finishRun("error", {
1852
1795
  exitCode: claudeResult.exitCode,
1853
1796
  errorMessage: `Claude preparation failed with exit code ${claudeResult.exitCode}`
1854
1797
  });
1855
- console.error(`
1856
- \u274C Claude preparation failed with exit code ${claudeResult.exitCode}`);
1798
+ console.error("\n" + chalk3.red(`Claude preparation failed with exit code ${claudeResult.exitCode}`));
1857
1799
  process.exit(1);
1858
1800
  }
1859
1801
  } catch (error) {
@@ -1863,18 +1805,18 @@ ${errorText}`);
1863
1805
  errorMessage: error instanceof Error ? error.message : String(error)
1864
1806
  });
1865
1807
  } catch (stateError) {
1866
- console.error("[Log Streaming] Failed to update run state:", stateError);
1808
+ console.error(chalk3.dim("[Log Streaming] Failed to update run state:"), stateError);
1867
1809
  }
1868
1810
  }
1869
1811
  throw error;
1870
1812
  } finally {
1871
1813
  if (heartbeatManager) {
1872
1814
  heartbeatManager.stop();
1873
- console.log("[Log Streaming] Heartbeat stopped");
1815
+ console.log(chalk3.dim("[Log Streaming] Heartbeat stopped"));
1874
1816
  }
1875
1817
  if (logBuffer) {
1876
1818
  await logBuffer.stop();
1877
- console.log("[Log Streaming] Logs flushed");
1819
+ console.log(chalk3.dim("[Log Streaming] Logs flushed"));
1878
1820
  }
1879
1821
  if (cleanup) {
1880
1822
  await cleanup();
@@ -1883,15 +1825,16 @@ ${errorText}`);
1883
1825
  }
1884
1826
 
1885
1827
  // src/workflows/execute.ts
1828
+ import chalk4 from "chalk";
1886
1829
  var API_BASE_URL5 = "https://www.contextgraph.dev";
1887
1830
  async function runExecute(actionId, options) {
1888
1831
  const credentials = await loadCredentials();
1889
1832
  if (!credentials) {
1890
- console.error("\u274C Not authenticated. Run authentication first.");
1833
+ console.error(chalk4.red("Not authenticated."), "Run authentication first.");
1891
1834
  process.exit(1);
1892
1835
  }
1893
1836
  if (isExpired(credentials) || isTokenExpired(credentials.clerkToken)) {
1894
- console.error("\u274C Token expired. Re-authenticate to continue.");
1837
+ console.error(chalk4.red("Token expired."), "Re-authenticate to continue.");
1895
1838
  process.exit(1);
1896
1839
  }
1897
1840
  let runId = options?.runId;
@@ -1913,12 +1856,12 @@ async function runExecute(actionId, options) {
1913
1856
  runId = setup.runId;
1914
1857
  logTransport = setup.logTransport;
1915
1858
  } else {
1916
- console.log(`[Log Streaming] Using pre-created run: ${runId}`);
1859
+ console.log(chalk4.dim(`[Log Streaming] Using pre-created run: ${runId}`));
1917
1860
  workspacePath = options?.cwd || process.cwd();
1918
1861
  logTransport = new LogTransportService(API_BASE_URL5, credentials.clerkToken, runId);
1919
1862
  }
1920
- console.log(`Fetching execution instructions for action ${actionId}...
1921
- `);
1863
+ console.log(chalk4.dim(`Fetching execution instructions for action ${actionId}...
1864
+ `));
1922
1865
  const response = await fetchWithRetry(
1923
1866
  `${API_BASE_URL5}/api/prompts/execute`,
1924
1867
  {
@@ -1939,7 +1882,7 @@ ${errorText}`);
1939
1882
  await logTransport.updateRunState("executing");
1940
1883
  heartbeatManager = new HeartbeatManager(API_BASE_URL5, credentials.clerkToken, runId);
1941
1884
  heartbeatManager.start();
1942
- console.log("[Log Streaming] Heartbeat started");
1885
+ console.log(chalk4.dim("[Log Streaming] Heartbeat started"));
1943
1886
  logBuffer = new LogBuffer(logTransport);
1944
1887
  logBuffer.start();
1945
1888
  console.log("Spawning Claude for execution...\n");
@@ -1958,7 +1901,7 @@ ${errorText}`);
1958
1901
  cost: claudeResult.cost,
1959
1902
  usage: claudeResult.usage
1960
1903
  });
1961
- console.log("\n\u2705 Execution complete");
1904
+ console.log("\n" + chalk4.green("Execution complete"));
1962
1905
  } else {
1963
1906
  await logTransport.finishRun("error", {
1964
1907
  exitCode: claudeResult.exitCode,
@@ -1973,18 +1916,18 @@ ${errorText}`);
1973
1916
  errorMessage: error instanceof Error ? error.message : String(error)
1974
1917
  });
1975
1918
  } catch (stateError) {
1976
- console.error("[Log Streaming] Failed to update run state:", stateError);
1919
+ console.error(chalk4.dim("[Log Streaming] Failed to update run state:"), stateError);
1977
1920
  }
1978
1921
  }
1979
1922
  throw error;
1980
1923
  } finally {
1981
1924
  if (heartbeatManager) {
1982
1925
  heartbeatManager.stop();
1983
- console.log("[Log Streaming] Heartbeat stopped");
1926
+ console.log(chalk4.dim("[Log Streaming] Heartbeat stopped"));
1984
1927
  }
1985
1928
  if (logBuffer) {
1986
1929
  await logBuffer.stop();
1987
- console.log("[Log Streaming] Logs flushed");
1930
+ console.log(chalk4.dim("[Log Streaming] Logs flushed"));
1988
1931
  }
1989
1932
  if (cleanup) {
1990
1933
  await cleanup();
@@ -1996,11 +1939,12 @@ ${errorText}`);
1996
1939
  import { randomUUID } from "crypto";
1997
1940
  import { readFileSync } from "fs";
1998
1941
  import { fileURLToPath } from "url";
1999
- import { dirname, join as join5 } from "path";
1942
+ import { dirname, join as join4 } from "path";
1943
+ import chalk5 from "chalk";
2000
1944
  var __filename2 = fileURLToPath(import.meta.url);
2001
1945
  var __dirname2 = dirname(__filename2);
2002
1946
  var packageJson = JSON.parse(
2003
- readFileSync(join5(__dirname2, "../package.json"), "utf-8")
1947
+ readFileSync(join4(__dirname2, "../package.json"), "utf-8")
2004
1948
  );
2005
1949
  var INITIAL_POLL_INTERVAL = parseInt(process.env.WORKER_INITIAL_POLL_INTERVAL || "2000", 10);
2006
1950
  var MAX_POLL_INTERVAL = parseInt(process.env.WORKER_MAX_POLL_INTERVAL || "5000", 10);
@@ -2032,34 +1976,34 @@ function formatDuration(ms) {
2032
1976
  function printStatus() {
2033
1977
  const uptime = formatDuration(Date.now() - stats.startTime);
2034
1978
  const total = stats.prepared + stats.executed;
2035
- console.log(`Status: ${total} actions (${stats.prepared} prepared, ${stats.executed} executed, ${stats.errors} errors) | Uptime: ${uptime}`);
1979
+ console.log(chalk5.dim(`Status: ${total} actions (${stats.prepared} prepared, ${stats.executed} executed, ${stats.errors} errors) | Uptime: ${uptime}`));
2036
1980
  }
2037
1981
  async function cleanupAndExit() {
2038
1982
  if (currentClaim && apiClient) {
2039
1983
  try {
2040
- console.log(`
2041
- \u{1F9F9} Releasing claim on action ${currentClaim.actionId}...`);
1984
+ console.log(chalk5.dim(`
1985
+ Releasing claim on action ${currentClaim.actionId}...`));
2042
1986
  await apiClient.releaseClaim({
2043
1987
  action_id: currentClaim.actionId,
2044
1988
  worker_id: currentClaim.workerId,
2045
1989
  claim_id: currentClaim.claimId
2046
1990
  });
2047
- console.log("\u2705 Claim released successfully");
1991
+ console.log(chalk5.dim("Claim released successfully"));
2048
1992
  } catch (error) {
2049
- console.error("\u26A0\uFE0F Failed to release claim:", error.message);
1993
+ console.error(chalk5.yellow("Failed to release claim:"), error.message);
2050
1994
  }
2051
1995
  }
2052
- console.log("\u{1F44B} Shutdown complete");
1996
+ console.log("Shutdown complete");
2053
1997
  process.exit(0);
2054
1998
  }
2055
1999
  function setupSignalHandlers() {
2056
2000
  process.on("SIGINT", async () => {
2057
- console.log("\n\n\u26A0\uFE0F Received SIGINT (Ctrl+C). Shutting down gracefully...");
2001
+ console.log(chalk5.yellow("\n\nReceived SIGINT (Ctrl+C). Shutting down gracefully..."));
2058
2002
  running = false;
2059
2003
  await cleanupAndExit();
2060
2004
  });
2061
2005
  process.on("SIGTERM", async () => {
2062
- console.log("\n\n\u26A0\uFE0F Received SIGTERM. Shutting down gracefully...");
2006
+ console.log(chalk5.yellow("\n\nReceived SIGTERM. Shutting down gracefully..."));
2063
2007
  running = false;
2064
2008
  await cleanupAndExit();
2065
2009
  });
@@ -2076,25 +2020,23 @@ async function runLocalAgent(options) {
2076
2020
  setupSignalHandlers();
2077
2021
  const credentials = await loadCredentials();
2078
2022
  if (!credentials) {
2079
- console.error("\u274C Not authenticated.");
2080
- console.error(" Set CONTEXTGRAPH_API_TOKEN environment variable or run `contextgraph-agent auth`");
2023
+ console.error(chalk5.red("Not authenticated."));
2024
+ console.error(` Set CONTEXTGRAPH_API_TOKEN environment variable or run ${chalk5.cyan("contextgraph-agent auth")}`);
2081
2025
  process.exit(1);
2082
2026
  }
2083
2027
  if (isExpired(credentials) || isTokenExpired(credentials.clerkToken)) {
2084
- console.error("\u274C Token expired. Run `contextgraph-agent auth` to re-authenticate.");
2028
+ console.error(chalk5.red("Token expired."), `Run ${chalk5.cyan("contextgraph-agent auth")} to re-authenticate.`);
2085
2029
  process.exit(1);
2086
2030
  }
2087
2031
  const usingApiToken = !!process.env.CONTEXTGRAPH_API_TOKEN;
2088
2032
  if (usingApiToken) {
2089
- console.log("\u{1F510} Authenticated via CONTEXTGRAPH_API_TOKEN");
2033
+ console.log(chalk5.dim("Authenticated via CONTEXTGRAPH_API_TOKEN"));
2090
2034
  }
2091
2035
  const workerId = randomUUID();
2092
- console.log(`\u{1F916} ContextGraph Agent v${packageJson.version}`);
2093
- console.log(`\u{1F477} Worker ID: ${workerId}`);
2094
- console.log(`\u{1F504} Starting continuous worker loop...
2095
- `);
2096
- console.log(`\u{1F4A1} Press Ctrl+C to gracefully shutdown and release any claimed work
2097
- `);
2036
+ console.log(`${chalk5.bold("ContextGraph Agent")} ${chalk5.dim(`v${packageJson.version}`)}`);
2037
+ console.log(chalk5.dim(`Worker ID: ${workerId}`));
2038
+ console.log("Starting continuous worker loop...\n");
2039
+ console.log(chalk5.dim("Press Ctrl+C to gracefully shutdown and release any claimed work\n"));
2098
2040
  let currentPollInterval = INITIAL_POLL_INTERVAL;
2099
2041
  let lastStatusTime = Date.now();
2100
2042
  let consecutiveApiErrors = 0;
@@ -2110,20 +2052,20 @@ async function runLocalAgent(options) {
2110
2052
  if (isRetryableError(err)) {
2111
2053
  consecutiveApiErrors++;
2112
2054
  if (consecutiveApiErrors === OUTAGE_WARNING_THRESHOLD) {
2113
- console.warn(`
2114
- \u26A0\uFE0F API appears to be experiencing an outage.`);
2115
- console.warn(` Will continue retrying indefinitely (every ${MAX_RETRY_DELAY / 1e3}s max).`);
2116
- console.warn(` Press Ctrl+C to stop.
2117
- `);
2055
+ console.warn(chalk5.yellow(`
2056
+ API appears to be experiencing an outage.`));
2057
+ console.warn(chalk5.yellow(` Will continue retrying indefinitely (every ${MAX_RETRY_DELAY / 1e3}s max).`));
2058
+ console.warn(chalk5.yellow(` Press Ctrl+C to stop.
2059
+ `));
2118
2060
  }
2119
2061
  if (consecutiveApiErrors < OUTAGE_WARNING_THRESHOLD) {
2120
- console.warn(`\u26A0\uFE0F API error (attempt ${consecutiveApiErrors}): ${err.message}`);
2062
+ console.warn(chalk5.yellow(`API error (attempt ${consecutiveApiErrors}):`), err.message);
2121
2063
  } else if (consecutiveApiErrors % 10 === 0) {
2122
- console.warn(`\u26A0\uFE0F Still retrying... (attempt ${consecutiveApiErrors}, last error: ${err.message})`);
2064
+ console.warn(chalk5.yellow(`Still retrying... (attempt ${consecutiveApiErrors}, last error: ${err.message})`));
2123
2065
  }
2124
2066
  const delaySeconds = Math.round(apiRetryDelay / 1e3);
2125
2067
  if (consecutiveApiErrors < OUTAGE_WARNING_THRESHOLD) {
2126
- console.warn(` Retrying in ${delaySeconds}s...`);
2068
+ console.warn(chalk5.dim(` Retrying in ${delaySeconds}s...`));
2127
2069
  }
2128
2070
  await sleep(apiRetryDelay);
2129
2071
  apiRetryDelay = Math.min(apiRetryDelay * 2, MAX_RETRY_DELAY);
@@ -2154,7 +2096,7 @@ async function runLocalAgent(options) {
2154
2096
  } else if (!actionDetail.done) {
2155
2097
  phase = "execute";
2156
2098
  } else {
2157
- console.log(`\u23ED\uFE0F Skipping action "${actionDetail.title}" - already completed`);
2099
+ console.log(chalk5.dim(`Skipping action "${actionDetail.title}" - already completed`));
2158
2100
  if (currentClaim && apiClient) {
2159
2101
  try {
2160
2102
  await apiClient.releaseClaim({
@@ -2163,13 +2105,13 @@ async function runLocalAgent(options) {
2163
2105
  claim_id: currentClaim.claimId
2164
2106
  });
2165
2107
  } catch (releaseError) {
2166
- console.error("\u26A0\uFE0F Failed to release claim:", releaseError.message);
2108
+ console.error(chalk5.yellow("Failed to release claim:"), releaseError.message);
2167
2109
  }
2168
2110
  }
2169
2111
  currentClaim = null;
2170
2112
  continue;
2171
2113
  }
2172
- console.log(`Working: ${actionDetail.title}`);
2114
+ console.log(`${chalk5.bold("Working:")} ${chalk5.cyan(actionDetail.title)}`);
2173
2115
  let workspacePath;
2174
2116
  let cleanup;
2175
2117
  let startingCommit;
@@ -2197,7 +2139,7 @@ async function runLocalAgent(options) {
2197
2139
  claim_id: currentClaim.claimId
2198
2140
  });
2199
2141
  } catch (releaseError) {
2200
- console.error("\u26A0\uFE0F Failed to release claim after preparation:", releaseError.message);
2142
+ console.error(chalk5.yellow("Failed to release claim after preparation:"), releaseError.message);
2201
2143
  }
2202
2144
  }
2203
2145
  currentClaim = null;
@@ -2206,10 +2148,10 @@ async function runLocalAgent(options) {
2206
2148
  try {
2207
2149
  await runExecute(actionDetail.id, { cwd: workspacePath, startingCommit, model: options?.forceModel, runId });
2208
2150
  stats.executed++;
2209
- console.log(`Completed: ${actionDetail.title}`);
2151
+ console.log(`${chalk5.bold.green("Completed:")} ${chalk5.cyan(actionDetail.title)}`);
2210
2152
  } catch (executeError) {
2211
2153
  stats.errors++;
2212
- console.error(`Error: ${executeError.message}. Continuing...`);
2154
+ console.error(chalk5.red("Error:"), `${executeError.message}. Continuing...`);
2213
2155
  } finally {
2214
2156
  if (currentClaim && apiClient) {
2215
2157
  try {
@@ -2219,25 +2161,25 @@ async function runLocalAgent(options) {
2219
2161
  claim_id: currentClaim.claimId
2220
2162
  });
2221
2163
  } catch (releaseError) {
2222
- console.error("\u26A0\uFE0F Failed to release claim:", releaseError.message);
2164
+ console.error(chalk5.yellow("Failed to release claim:"), releaseError.message);
2223
2165
  }
2224
2166
  }
2225
2167
  currentClaim = null;
2226
2168
  }
2227
2169
  } catch (workspaceError) {
2228
2170
  stats.errors++;
2229
- console.error(`Error preparing workspace: ${workspaceError.message}. Continuing...`);
2171
+ console.error(chalk5.red("Error preparing workspace:"), `${workspaceError.message}. Continuing...`);
2230
2172
  if (currentClaim && apiClient) {
2231
2173
  try {
2232
- console.log(`\u{1F9F9} Releasing claim due to workspace error...`);
2174
+ console.log(chalk5.dim("Releasing claim due to workspace error..."));
2233
2175
  await apiClient.releaseClaim({
2234
2176
  action_id: currentClaim.actionId,
2235
2177
  worker_id: currentClaim.workerId,
2236
2178
  claim_id: currentClaim.claimId
2237
2179
  });
2238
- console.log("\u2705 Claim released");
2180
+ console.log(chalk5.dim("Claim released"));
2239
2181
  } catch (releaseError) {
2240
- console.error("\u26A0\uFE0F Failed to release claim:", releaseError.message);
2182
+ console.error(chalk5.yellow("Failed to release claim:"), releaseError.message);
2241
2183
  }
2242
2184
  }
2243
2185
  currentClaim = null;
@@ -2249,14 +2191,223 @@ async function runLocalAgent(options) {
2249
2191
  }
2250
2192
  }
2251
2193
 
2194
+ // src/workflows/setup.ts
2195
+ import chalk6 from "chalk";
2196
+ import { Listr } from "listr2";
2197
+
2198
+ // src/plugin-setup.ts
2199
+ import { spawn as spawn2 } from "child_process";
2200
+ var MARKETPLACE_SOURCE = "contextgraph/claude-code-plugin";
2201
+ var MARKETPLACE_NAME = "contextgraph";
2202
+ var PLUGIN_NAME = "contextgraph";
2203
+ function runCommand(command, args) {
2204
+ return new Promise((resolve, reject) => {
2205
+ const proc = spawn2(command, args, { stdio: ["ignore", "pipe", "pipe"] });
2206
+ let stdout = "";
2207
+ proc.stdout.on("data", (data) => {
2208
+ stdout += data.toString();
2209
+ });
2210
+ proc.on("close", (code) => {
2211
+ resolve({ stdout, exitCode: code ?? 1 });
2212
+ });
2213
+ proc.on("error", (err) => {
2214
+ reject(new Error(`Failed to spawn ${command}: ${err.message}`));
2215
+ });
2216
+ });
2217
+ }
2218
+ async function isClaudeCodeAvailable() {
2219
+ try {
2220
+ const { exitCode } = await runCommand("claude", ["--version"]);
2221
+ return exitCode === 0;
2222
+ } catch {
2223
+ return false;
2224
+ }
2225
+ }
2226
+ async function isMarketplaceConfigured() {
2227
+ try {
2228
+ const { stdout, exitCode } = await runCommand("claude", ["plugin", "marketplace", "list"]);
2229
+ return exitCode === 0 && stdout.includes(MARKETPLACE_NAME);
2230
+ } catch {
2231
+ return false;
2232
+ }
2233
+ }
2234
+ async function addMarketplace() {
2235
+ console.log("Adding ContextGraph marketplace...");
2236
+ const { exitCode } = await runCommand("claude", ["plugin", "marketplace", "add", MARKETPLACE_SOURCE]);
2237
+ if (exitCode !== 0) {
2238
+ throw new Error(`Failed to add marketplace (exit code ${exitCode})`);
2239
+ }
2240
+ }
2241
+ async function isPluginInstalled() {
2242
+ try {
2243
+ const { stdout, exitCode } = await runCommand("claude", ["plugin", "list"]);
2244
+ return exitCode === 0 && stdout.includes(PLUGIN_NAME);
2245
+ } catch {
2246
+ return false;
2247
+ }
2248
+ }
2249
+ async function ensurePluginInstalled() {
2250
+ if (await isPluginInstalled()) {
2251
+ return;
2252
+ }
2253
+ if (!await isMarketplaceConfigured()) {
2254
+ await addMarketplace();
2255
+ }
2256
+ console.log("Installing ContextGraph plugin for Claude Code...");
2257
+ const { exitCode } = await runCommand("claude", ["plugin", "install", PLUGIN_NAME]);
2258
+ if (exitCode !== 0) {
2259
+ throw new Error(`Failed to install plugin (exit code ${exitCode})`);
2260
+ }
2261
+ console.log("ContextGraph plugin installed (includes MCP server)");
2262
+ }
2263
+
2264
+ // src/workflows/setup.ts
2265
+ async function runSetup() {
2266
+ console.log(`
2267
+ ${chalk6.bold("Welcome to ContextGraph!")}`);
2268
+ console.log("This setup wizard will help you get started.\n");
2269
+ const tasks = new Listr(
2270
+ [
2271
+ {
2272
+ title: "Checking authentication",
2273
+ task: async (ctx2, task) => {
2274
+ const creds = await loadCredentials();
2275
+ if (!creds) {
2276
+ ctx2.needsAuth = true;
2277
+ } else if (isExpired(creds) || isTokenExpired(creds.clerkToken)) {
2278
+ ctx2.needsAuth = true;
2279
+ } else {
2280
+ ctx2.needsAuth = false;
2281
+ ctx2.userId = creds.userId;
2282
+ ctx2.displayName = creds.email ?? creds.userId;
2283
+ task.title = `Checking authentication \u2014 logged in as ${chalk6.cyan(ctx2.displayName)}`;
2284
+ }
2285
+ }
2286
+ },
2287
+ {
2288
+ title: "Authenticating with ContextGraph",
2289
+ skip: (ctx2) => !ctx2.needsAuth ? "Already authenticated" : false,
2290
+ task: async (ctx2, task) => {
2291
+ task.output = "Waiting for browser...";
2292
+ const result = await authenticateAgent();
2293
+ if (!result.success) {
2294
+ throw new Error("Authentication failed: " + result.error);
2295
+ }
2296
+ ctx2.userId = result.credentials.userId;
2297
+ ctx2.displayName = result.credentials.email ?? result.credentials.userId;
2298
+ task.title = `Authenticated as ${chalk6.cyan(ctx2.displayName)}`;
2299
+ },
2300
+ options: { bottomBar: Infinity }
2301
+ },
2302
+ {
2303
+ title: "Checking for Claude Code",
2304
+ task: async (ctx2, task) => {
2305
+ ctx2.hasClaudeCode = await isClaudeCodeAvailable();
2306
+ task.title = ctx2.hasClaudeCode ? "Checking for Claude Code \u2014 detected" : "Checking for Claude Code \u2014 not found";
2307
+ }
2308
+ },
2309
+ {
2310
+ title: "Installing ContextGraph plugin",
2311
+ skip: (ctx2) => !ctx2.hasClaudeCode ? "Claude Code not detected" : false,
2312
+ task: async (ctx2, task) => {
2313
+ try {
2314
+ if (await isPluginInstalled()) {
2315
+ ctx2.pluginInstalled = true;
2316
+ task.title = "ContextGraph plugin already installed";
2317
+ } else {
2318
+ await ensurePluginInstalled();
2319
+ ctx2.pluginInstalled = true;
2320
+ task.title = "ContextGraph plugin installed";
2321
+ }
2322
+ } catch {
2323
+ ctx2.pluginInstalled = false;
2324
+ task.skip("Could not install automatically \u2014 see manual instructions below");
2325
+ }
2326
+ }
2327
+ }
2328
+ ],
2329
+ {
2330
+ ctx: { needsAuth: false, userId: null, displayName: null, hasClaudeCode: false, pluginInstalled: false },
2331
+ rendererOptions: { collapseErrors: false }
2332
+ }
2333
+ );
2334
+ const ctx = await tasks.run();
2335
+ console.log("");
2336
+ if (ctx.hasClaudeCode) {
2337
+ if (!ctx.pluginInstalled) {
2338
+ console.log(chalk6.yellow("Plugin could not be installed automatically."));
2339
+ console.log("You can install it manually with:\n");
2340
+ console.log(` ${chalk6.dim("$")} claude plugin marketplace add contextgraph/claude-code-plugin`);
2341
+ console.log(` ${chalk6.dim("$")} claude plugin install contextgraph
2342
+ `);
2343
+ }
2344
+ console.log(chalk6.bold.green("Setup complete!") + " You're ready to go.\n");
2345
+ console.log(`There are three ways to work with ContextGraph:
2346
+ `);
2347
+ console.log(chalk6.bold("1. Run the ContextGraph agent"));
2348
+ console.log(" Wraps Claude Code and automatically prepares and executes");
2349
+ console.log(" actions for you in your codebase.\n");
2350
+ console.log(` ${chalk6.cyan("npx @contextgraph/agent run")}
2351
+ `);
2352
+ console.log(chalk6.bold("2. Use ContextGraph directly via Claude Code"));
2353
+ console.log(" Open Claude Code (or restart if already running) and interact");
2354
+ console.log(" with your action graph through the MCP tools.\n");
2355
+ console.log(chalk6.dim(" Examples:"));
2356
+ console.log(chalk6.dim(' "Create an action plan for implementing user auth"'));
2357
+ console.log(chalk6.dim(' "Show me my action tree"'));
2358
+ console.log(chalk6.dim(' "What should I work on next?"'));
2359
+ console.log(chalk6.dim(' "Capture this discussion as an action with sub-tasks"'));
2360
+ console.log("");
2361
+ console.log(chalk6.bold("3. Integrate the MCP server into other platforms"));
2362
+ console.log(" Add the ContextGraph MCP server to any compatible tool.\n");
2363
+ console.log(` MCP Server URL: ${chalk6.cyan("https://mcp.contextgraph.dev")}
2364
+ `);
2365
+ console.log(chalk6.dim(" Works with: Cursor, Claude.ai, ChatGPT, Codex CLI, Windsurf,"));
2366
+ console.log(chalk6.dim(" and any other MCP-compatible client."));
2367
+ console.log("");
2368
+ console.log(` Web dashboard: ${chalk6.cyan("https://contextgraph.dev")}`);
2369
+ } else {
2370
+ console.log("You have a few options:\n");
2371
+ console.log(chalk6.bold("Option 1: Install Claude Code"));
2372
+ console.log(` Visit: ${chalk6.cyan("https://claude.ai/download")}`);
2373
+ console.log(` Then run this setup again: ${chalk6.cyan("npx @contextgraph/agent@latest setup")}
2374
+ `);
2375
+ console.log(chalk6.bold("Option 2: Use ContextGraph MCP server with other editors"));
2376
+ console.log(" ContextGraph works with any MCP-compatible editor!\n");
2377
+ console.log(" To add the ContextGraph MCP server to your editor:");
2378
+ console.log(` - Cursor: See ${chalk6.cyan("https://docs.cursor.com/advanced/mcp")}`);
2379
+ console.log(` - Windsurf: See ${chalk6.cyan("https://docs.windsurf.ai/mcp")}`);
2380
+ console.log(` - Other: See ${chalk6.cyan("https://modelcontextprotocol.io/clients")}
2381
+ `);
2382
+ console.log(" MCP Server URL:");
2383
+ console.log(` ${chalk6.cyan("https://mcp.contextgraph.dev")}
2384
+ `);
2385
+ console.log(chalk6.bold("Option 3: Use the agent CLI directly"));
2386
+ console.log(` Run autonomous agent: ${chalk6.cyan("npx @contextgraph/agent run")}`);
2387
+ console.log(` Execute specific action: ${chalk6.cyan("npx @contextgraph/agent execute <action-id>")}`);
2388
+ console.log(` Prepare an action: ${chalk6.cyan("npx @contextgraph/agent prepare <action-id>")}
2389
+ `);
2390
+ console.log(`Authentication complete! Visit ${chalk6.cyan("https://contextgraph.dev")} to get started!`);
2391
+ }
2392
+ console.log("");
2393
+ }
2394
+
2252
2395
  // src/cli/index.ts
2253
2396
  var __filename3 = fileURLToPath2(import.meta.url);
2254
2397
  var __dirname3 = dirname2(__filename3);
2255
2398
  var packageJson2 = JSON.parse(
2256
- readFileSync2(join6(__dirname3, "../package.json"), "utf-8")
2399
+ readFileSync2(join5(__dirname3, "../package.json"), "utf-8")
2257
2400
  );
2258
2401
  var program = new Command();
2259
2402
  program.name("contextgraph-agent").description("Autonomous agent for contextgraph action execution").version(packageJson2.version);
2403
+ program.command("setup").description("Interactive setup wizard for new users").action(async () => {
2404
+ try {
2405
+ await runSetup();
2406
+ } catch (error) {
2407
+ console.error("Error during setup:", error instanceof Error ? error.message : error);
2408
+ process.exit(1);
2409
+ }
2410
+ });
2260
2411
  program.command("run").description("Run continuous worker loop (claims and executes actions until Ctrl+C)").option("--force-haiku", "Force all workflows to use claude-haiku-4-5 instead of default models").option("--skip-skills", "Skip skill injection (for testing)").action(async (options) => {
2261
2412
  try {
2262
2413
  await runLocalAgent({