@contextgraph/agent 0.4.25 → 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/.claude/settings.local.json +5 -1
- package/dist/index.js +204 -143
- package/dist/index.js.map +1 -1
- package/package.json +3 -1
package/dist/index.js
CHANGED
|
@@ -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) {
|
|
@@ -1377,6 +1380,7 @@ async function fetchSkillsLibrary(options) {
|
|
|
1377
1380
|
}
|
|
1378
1381
|
|
|
1379
1382
|
// src/workspace-prep.ts
|
|
1383
|
+
import chalk from "chalk";
|
|
1380
1384
|
var API_BASE_URL2 = "https://www.contextgraph.dev";
|
|
1381
1385
|
async function fetchGitHubCredentials(authToken) {
|
|
1382
1386
|
const response = await fetchWithRetry(`${API_BASE_URL2}/api/cli/credentials`, {
|
|
@@ -1441,15 +1445,15 @@ async function prepareWorkspace(repoUrl, options) {
|
|
|
1441
1445
|
try {
|
|
1442
1446
|
await rm(workspacePath, { recursive: true, force: true });
|
|
1443
1447
|
} catch (error) {
|
|
1444
|
-
console.error(`Warning: Failed to cleanup workspace at ${workspacePath}
|
|
1448
|
+
console.error(chalk.yellow(`Warning: Failed to cleanup workspace at ${workspacePath}:`), error);
|
|
1445
1449
|
}
|
|
1446
1450
|
};
|
|
1447
1451
|
try {
|
|
1448
1452
|
const cloneUrl = buildAuthenticatedUrl(repoUrl, credentials.githubToken, credentials.gitCredentialsUsername);
|
|
1449
|
-
console.log(
|
|
1450
|
-
console.log(`
|
|
1453
|
+
console.log(`Cloning ${chalk.cyan(repoUrl)}`);
|
|
1454
|
+
console.log(chalk.dim(` ${workspacePath}`));
|
|
1451
1455
|
await runGitCommand(["clone", cloneUrl, workspacePath]);
|
|
1452
|
-
console.log(
|
|
1456
|
+
console.log(chalk.green("Repository cloned"));
|
|
1453
1457
|
if (credentials.githubUsername) {
|
|
1454
1458
|
await runGitCommand(["config", "user.name", credentials.githubUsername], workspacePath);
|
|
1455
1459
|
}
|
|
@@ -1464,10 +1468,10 @@ async function prepareWorkspace(repoUrl, options) {
|
|
|
1464
1468
|
);
|
|
1465
1469
|
const branchExists = stdout.trim().length > 0;
|
|
1466
1470
|
if (branchExists) {
|
|
1467
|
-
console.log(
|
|
1471
|
+
console.log(`Checking out branch: ${chalk.cyan(branch)}`);
|
|
1468
1472
|
await runGitCommand(["checkout", branch], workspacePath);
|
|
1469
1473
|
} else {
|
|
1470
|
-
console.log(
|
|
1474
|
+
console.log(`Creating new branch: ${chalk.cyan(branch)}`);
|
|
1471
1475
|
await runGitCommand(["checkout", "-b", branch], workspacePath);
|
|
1472
1476
|
}
|
|
1473
1477
|
}
|
|
@@ -1475,17 +1479,17 @@ async function prepareWorkspace(repoUrl, options) {
|
|
|
1475
1479
|
const startingCommit = commitHash.trim();
|
|
1476
1480
|
console.log("");
|
|
1477
1481
|
if (skipSkills) {
|
|
1478
|
-
console.log("
|
|
1482
|
+
console.log(chalk.dim("Skipping skill injection (--no-skills flag)"));
|
|
1479
1483
|
} else {
|
|
1480
1484
|
try {
|
|
1481
1485
|
const librarySkills = await fetchSkillsLibrary({ authToken, runId });
|
|
1482
1486
|
if (librarySkills.length > 0) {
|
|
1483
1487
|
await injectSkills(workspacePath, librarySkills);
|
|
1484
1488
|
} else {
|
|
1485
|
-
console.log("
|
|
1489
|
+
console.log(chalk.dim("No skills to inject (empty library)"));
|
|
1486
1490
|
}
|
|
1487
1491
|
} catch (skillError) {
|
|
1488
|
-
console.warn("
|
|
1492
|
+
console.warn(chalk.yellow("Skill injection failed (agent will continue):"), skillError);
|
|
1489
1493
|
}
|
|
1490
1494
|
}
|
|
1491
1495
|
return { path: workspacePath, startingCommit, cleanup };
|
|
@@ -1527,7 +1531,9 @@ var package_default = {
|
|
|
1527
1531
|
},
|
|
1528
1532
|
dependencies: {
|
|
1529
1533
|
"@anthropic-ai/claude-agent-sdk": "^0.1.50",
|
|
1534
|
+
chalk: "^5.6.2",
|
|
1530
1535
|
commander: "^11.0.0",
|
|
1536
|
+
listr2: "^9.0.5",
|
|
1531
1537
|
open: "^10.0.0"
|
|
1532
1538
|
},
|
|
1533
1539
|
devDependencies: {
|
|
@@ -1654,21 +1660,22 @@ var ApiClient = class {
|
|
|
1654
1660
|
};
|
|
1655
1661
|
|
|
1656
1662
|
// src/workspace-setup.ts
|
|
1663
|
+
import chalk2 from "chalk";
|
|
1657
1664
|
var API_BASE_URL3 = "https://www.contextgraph.dev";
|
|
1658
1665
|
async function setupWorkspaceForAction(actionId, options) {
|
|
1659
1666
|
const { authToken, phase, startingCommit: startingCommitOverride, skipSkills } = options;
|
|
1660
1667
|
let actionDetail = options.actionDetail;
|
|
1661
1668
|
if (!actionDetail) {
|
|
1662
1669
|
const apiClient2 = new ApiClient();
|
|
1663
|
-
console.log(`Fetching action details for ${actionId}...`);
|
|
1670
|
+
console.log(chalk2.dim(`Fetching action details for ${actionId}...`));
|
|
1664
1671
|
actionDetail = await apiClient2.getActionDetail(actionId);
|
|
1665
1672
|
}
|
|
1666
1673
|
const logTransport = new LogTransportService(API_BASE_URL3, authToken);
|
|
1667
|
-
console.log(`[Log Streaming] Creating run for ${phase} phase...`);
|
|
1674
|
+
console.log(chalk2.dim(`[Log Streaming] Creating run for ${phase} phase...`));
|
|
1668
1675
|
const runId = await logTransport.createRun(actionId, phase, {
|
|
1669
1676
|
startingCommit: startingCommitOverride
|
|
1670
1677
|
});
|
|
1671
|
-
console.log(`[Log Streaming] Run created: ${runId}`);
|
|
1678
|
+
console.log(chalk2.dim(`[Log Streaming] Run created: ${runId}`));
|
|
1672
1679
|
const repoUrl = actionDetail.resolved_repository_url || actionDetail.repository_url;
|
|
1673
1680
|
const branch = actionDetail.resolved_branch || actionDetail.branch;
|
|
1674
1681
|
let workspacePath;
|
|
@@ -1685,14 +1692,14 @@ async function setupWorkspaceForAction(actionId, options) {
|
|
|
1685
1692
|
cleanup = workspace.cleanup;
|
|
1686
1693
|
startingCommit = workspace.startingCommit;
|
|
1687
1694
|
} else {
|
|
1688
|
-
console.log(
|
|
1695
|
+
console.log(chalk2.dim("No repository configured - creating blank workspace"));
|
|
1689
1696
|
workspacePath = await mkdtemp2(join3(tmpdir2(), "cg-workspace-"));
|
|
1690
|
-
console.log(`
|
|
1697
|
+
console.log(chalk2.dim(` ${workspacePath}`));
|
|
1691
1698
|
cleanup = async () => {
|
|
1692
1699
|
try {
|
|
1693
1700
|
await rm2(workspacePath, { recursive: true, force: true });
|
|
1694
1701
|
} catch (error) {
|
|
1695
|
-
console.error(`Warning: Failed to cleanup workspace at ${workspacePath}
|
|
1702
|
+
console.error(chalk2.yellow(`Warning: Failed to cleanup workspace at ${workspacePath}:`), error);
|
|
1696
1703
|
}
|
|
1697
1704
|
};
|
|
1698
1705
|
}
|
|
@@ -1706,15 +1713,16 @@ async function setupWorkspaceForAction(actionId, options) {
|
|
|
1706
1713
|
}
|
|
1707
1714
|
|
|
1708
1715
|
// src/workflows/prepare.ts
|
|
1716
|
+
import chalk3 from "chalk";
|
|
1709
1717
|
var API_BASE_URL4 = "https://www.contextgraph.dev";
|
|
1710
1718
|
async function runPrepare(actionId, options) {
|
|
1711
1719
|
const credentials = await loadCredentials();
|
|
1712
1720
|
if (!credentials) {
|
|
1713
|
-
console.error("
|
|
1721
|
+
console.error(chalk3.red("Not authenticated."), "Run authentication first.");
|
|
1714
1722
|
process.exit(1);
|
|
1715
1723
|
}
|
|
1716
1724
|
if (isExpired(credentials) || isTokenExpired(credentials.clerkToken)) {
|
|
1717
|
-
console.error("
|
|
1725
|
+
console.error(chalk3.red("Token expired."), "Re-authenticate to continue.");
|
|
1718
1726
|
process.exit(1);
|
|
1719
1727
|
}
|
|
1720
1728
|
let runId = options?.runId;
|
|
@@ -1736,12 +1744,12 @@ async function runPrepare(actionId, options) {
|
|
|
1736
1744
|
runId = setup.runId;
|
|
1737
1745
|
logTransport = setup.logTransport;
|
|
1738
1746
|
} else {
|
|
1739
|
-
console.log(`[Log Streaming] Using pre-created run: ${runId}`);
|
|
1747
|
+
console.log(chalk3.dim(`[Log Streaming] Using pre-created run: ${runId}`));
|
|
1740
1748
|
workspacePath = options?.cwd || process.cwd();
|
|
1741
1749
|
logTransport = new LogTransportService(API_BASE_URL4, credentials.clerkToken, runId);
|
|
1742
1750
|
}
|
|
1743
|
-
console.log(`Fetching preparation instructions for action ${actionId}...
|
|
1744
|
-
`);
|
|
1751
|
+
console.log(chalk3.dim(`Fetching preparation instructions for action ${actionId}...
|
|
1752
|
+
`));
|
|
1745
1753
|
const response = await fetchWithRetry(
|
|
1746
1754
|
`${API_BASE_URL4}/api/prompts/prepare`,
|
|
1747
1755
|
{
|
|
@@ -1762,7 +1770,7 @@ ${errorText}`);
|
|
|
1762
1770
|
await logTransport.updateRunState("preparing");
|
|
1763
1771
|
heartbeatManager = new HeartbeatManager(API_BASE_URL4, credentials.clerkToken, runId);
|
|
1764
1772
|
heartbeatManager.start();
|
|
1765
|
-
console.log("[Log Streaming] Heartbeat started");
|
|
1773
|
+
console.log(chalk3.dim("[Log Streaming] Heartbeat started"));
|
|
1766
1774
|
logBuffer = new LogBuffer(logTransport);
|
|
1767
1775
|
logBuffer.start();
|
|
1768
1776
|
console.log("Spawning Claude for preparation...\n");
|
|
@@ -1781,14 +1789,13 @@ ${errorText}`);
|
|
|
1781
1789
|
cost: claudeResult.cost,
|
|
1782
1790
|
usage: claudeResult.usage
|
|
1783
1791
|
});
|
|
1784
|
-
console.log("\n
|
|
1792
|
+
console.log("\n" + chalk3.green("Preparation complete"));
|
|
1785
1793
|
} else {
|
|
1786
1794
|
await logTransport.finishRun("error", {
|
|
1787
1795
|
exitCode: claudeResult.exitCode,
|
|
1788
1796
|
errorMessage: `Claude preparation failed with exit code ${claudeResult.exitCode}`
|
|
1789
1797
|
});
|
|
1790
|
-
console.error(`
|
|
1791
|
-
\u274C Claude preparation failed with exit code ${claudeResult.exitCode}`);
|
|
1798
|
+
console.error("\n" + chalk3.red(`Claude preparation failed with exit code ${claudeResult.exitCode}`));
|
|
1792
1799
|
process.exit(1);
|
|
1793
1800
|
}
|
|
1794
1801
|
} catch (error) {
|
|
@@ -1798,18 +1805,18 @@ ${errorText}`);
|
|
|
1798
1805
|
errorMessage: error instanceof Error ? error.message : String(error)
|
|
1799
1806
|
});
|
|
1800
1807
|
} catch (stateError) {
|
|
1801
|
-
console.error("[Log Streaming] Failed to update run state:", stateError);
|
|
1808
|
+
console.error(chalk3.dim("[Log Streaming] Failed to update run state:"), stateError);
|
|
1802
1809
|
}
|
|
1803
1810
|
}
|
|
1804
1811
|
throw error;
|
|
1805
1812
|
} finally {
|
|
1806
1813
|
if (heartbeatManager) {
|
|
1807
1814
|
heartbeatManager.stop();
|
|
1808
|
-
console.log("[Log Streaming] Heartbeat stopped");
|
|
1815
|
+
console.log(chalk3.dim("[Log Streaming] Heartbeat stopped"));
|
|
1809
1816
|
}
|
|
1810
1817
|
if (logBuffer) {
|
|
1811
1818
|
await logBuffer.stop();
|
|
1812
|
-
console.log("[Log Streaming] Logs flushed");
|
|
1819
|
+
console.log(chalk3.dim("[Log Streaming] Logs flushed"));
|
|
1813
1820
|
}
|
|
1814
1821
|
if (cleanup) {
|
|
1815
1822
|
await cleanup();
|
|
@@ -1818,15 +1825,16 @@ ${errorText}`);
|
|
|
1818
1825
|
}
|
|
1819
1826
|
|
|
1820
1827
|
// src/workflows/execute.ts
|
|
1828
|
+
import chalk4 from "chalk";
|
|
1821
1829
|
var API_BASE_URL5 = "https://www.contextgraph.dev";
|
|
1822
1830
|
async function runExecute(actionId, options) {
|
|
1823
1831
|
const credentials = await loadCredentials();
|
|
1824
1832
|
if (!credentials) {
|
|
1825
|
-
console.error("
|
|
1833
|
+
console.error(chalk4.red("Not authenticated."), "Run authentication first.");
|
|
1826
1834
|
process.exit(1);
|
|
1827
1835
|
}
|
|
1828
1836
|
if (isExpired(credentials) || isTokenExpired(credentials.clerkToken)) {
|
|
1829
|
-
console.error("
|
|
1837
|
+
console.error(chalk4.red("Token expired."), "Re-authenticate to continue.");
|
|
1830
1838
|
process.exit(1);
|
|
1831
1839
|
}
|
|
1832
1840
|
let runId = options?.runId;
|
|
@@ -1848,12 +1856,12 @@ async function runExecute(actionId, options) {
|
|
|
1848
1856
|
runId = setup.runId;
|
|
1849
1857
|
logTransport = setup.logTransport;
|
|
1850
1858
|
} else {
|
|
1851
|
-
console.log(`[Log Streaming] Using pre-created run: ${runId}`);
|
|
1859
|
+
console.log(chalk4.dim(`[Log Streaming] Using pre-created run: ${runId}`));
|
|
1852
1860
|
workspacePath = options?.cwd || process.cwd();
|
|
1853
1861
|
logTransport = new LogTransportService(API_BASE_URL5, credentials.clerkToken, runId);
|
|
1854
1862
|
}
|
|
1855
|
-
console.log(`Fetching execution instructions for action ${actionId}...
|
|
1856
|
-
`);
|
|
1863
|
+
console.log(chalk4.dim(`Fetching execution instructions for action ${actionId}...
|
|
1864
|
+
`));
|
|
1857
1865
|
const response = await fetchWithRetry(
|
|
1858
1866
|
`${API_BASE_URL5}/api/prompts/execute`,
|
|
1859
1867
|
{
|
|
@@ -1874,7 +1882,7 @@ ${errorText}`);
|
|
|
1874
1882
|
await logTransport.updateRunState("executing");
|
|
1875
1883
|
heartbeatManager = new HeartbeatManager(API_BASE_URL5, credentials.clerkToken, runId);
|
|
1876
1884
|
heartbeatManager.start();
|
|
1877
|
-
console.log("[Log Streaming] Heartbeat started");
|
|
1885
|
+
console.log(chalk4.dim("[Log Streaming] Heartbeat started"));
|
|
1878
1886
|
logBuffer = new LogBuffer(logTransport);
|
|
1879
1887
|
logBuffer.start();
|
|
1880
1888
|
console.log("Spawning Claude for execution...\n");
|
|
@@ -1893,7 +1901,7 @@ ${errorText}`);
|
|
|
1893
1901
|
cost: claudeResult.cost,
|
|
1894
1902
|
usage: claudeResult.usage
|
|
1895
1903
|
});
|
|
1896
|
-
console.log("\n
|
|
1904
|
+
console.log("\n" + chalk4.green("Execution complete"));
|
|
1897
1905
|
} else {
|
|
1898
1906
|
await logTransport.finishRun("error", {
|
|
1899
1907
|
exitCode: claudeResult.exitCode,
|
|
@@ -1908,18 +1916,18 @@ ${errorText}`);
|
|
|
1908
1916
|
errorMessage: error instanceof Error ? error.message : String(error)
|
|
1909
1917
|
});
|
|
1910
1918
|
} catch (stateError) {
|
|
1911
|
-
console.error("[Log Streaming] Failed to update run state:", stateError);
|
|
1919
|
+
console.error(chalk4.dim("[Log Streaming] Failed to update run state:"), stateError);
|
|
1912
1920
|
}
|
|
1913
1921
|
}
|
|
1914
1922
|
throw error;
|
|
1915
1923
|
} finally {
|
|
1916
1924
|
if (heartbeatManager) {
|
|
1917
1925
|
heartbeatManager.stop();
|
|
1918
|
-
console.log("[Log Streaming] Heartbeat stopped");
|
|
1926
|
+
console.log(chalk4.dim("[Log Streaming] Heartbeat stopped"));
|
|
1919
1927
|
}
|
|
1920
1928
|
if (logBuffer) {
|
|
1921
1929
|
await logBuffer.stop();
|
|
1922
|
-
console.log("[Log Streaming] Logs flushed");
|
|
1930
|
+
console.log(chalk4.dim("[Log Streaming] Logs flushed"));
|
|
1923
1931
|
}
|
|
1924
1932
|
if (cleanup) {
|
|
1925
1933
|
await cleanup();
|
|
@@ -1932,6 +1940,7 @@ import { randomUUID } from "crypto";
|
|
|
1932
1940
|
import { readFileSync } from "fs";
|
|
1933
1941
|
import { fileURLToPath } from "url";
|
|
1934
1942
|
import { dirname, join as join4 } from "path";
|
|
1943
|
+
import chalk5 from "chalk";
|
|
1935
1944
|
var __filename2 = fileURLToPath(import.meta.url);
|
|
1936
1945
|
var __dirname2 = dirname(__filename2);
|
|
1937
1946
|
var packageJson = JSON.parse(
|
|
@@ -1967,34 +1976,34 @@ function formatDuration(ms) {
|
|
|
1967
1976
|
function printStatus() {
|
|
1968
1977
|
const uptime = formatDuration(Date.now() - stats.startTime);
|
|
1969
1978
|
const total = stats.prepared + stats.executed;
|
|
1970
|
-
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}`));
|
|
1971
1980
|
}
|
|
1972
1981
|
async function cleanupAndExit() {
|
|
1973
1982
|
if (currentClaim && apiClient) {
|
|
1974
1983
|
try {
|
|
1975
|
-
console.log(`
|
|
1976
|
-
|
|
1984
|
+
console.log(chalk5.dim(`
|
|
1985
|
+
Releasing claim on action ${currentClaim.actionId}...`));
|
|
1977
1986
|
await apiClient.releaseClaim({
|
|
1978
1987
|
action_id: currentClaim.actionId,
|
|
1979
1988
|
worker_id: currentClaim.workerId,
|
|
1980
1989
|
claim_id: currentClaim.claimId
|
|
1981
1990
|
});
|
|
1982
|
-
console.log("
|
|
1991
|
+
console.log(chalk5.dim("Claim released successfully"));
|
|
1983
1992
|
} catch (error) {
|
|
1984
|
-
console.error("
|
|
1993
|
+
console.error(chalk5.yellow("Failed to release claim:"), error.message);
|
|
1985
1994
|
}
|
|
1986
1995
|
}
|
|
1987
|
-
console.log("
|
|
1996
|
+
console.log("Shutdown complete");
|
|
1988
1997
|
process.exit(0);
|
|
1989
1998
|
}
|
|
1990
1999
|
function setupSignalHandlers() {
|
|
1991
2000
|
process.on("SIGINT", async () => {
|
|
1992
|
-
console.log("\n\
|
|
2001
|
+
console.log(chalk5.yellow("\n\nReceived SIGINT (Ctrl+C). Shutting down gracefully..."));
|
|
1993
2002
|
running = false;
|
|
1994
2003
|
await cleanupAndExit();
|
|
1995
2004
|
});
|
|
1996
2005
|
process.on("SIGTERM", async () => {
|
|
1997
|
-
console.log("\n\
|
|
2006
|
+
console.log(chalk5.yellow("\n\nReceived SIGTERM. Shutting down gracefully..."));
|
|
1998
2007
|
running = false;
|
|
1999
2008
|
await cleanupAndExit();
|
|
2000
2009
|
});
|
|
@@ -2011,25 +2020,23 @@ async function runLocalAgent(options) {
|
|
|
2011
2020
|
setupSignalHandlers();
|
|
2012
2021
|
const credentials = await loadCredentials();
|
|
2013
2022
|
if (!credentials) {
|
|
2014
|
-
console.error("
|
|
2015
|
-
console.error(
|
|
2023
|
+
console.error(chalk5.red("Not authenticated."));
|
|
2024
|
+
console.error(` Set CONTEXTGRAPH_API_TOKEN environment variable or run ${chalk5.cyan("contextgraph-agent auth")}`);
|
|
2016
2025
|
process.exit(1);
|
|
2017
2026
|
}
|
|
2018
2027
|
if (isExpired(credentials) || isTokenExpired(credentials.clerkToken)) {
|
|
2019
|
-
console.error("
|
|
2028
|
+
console.error(chalk5.red("Token expired."), `Run ${chalk5.cyan("contextgraph-agent auth")} to re-authenticate.`);
|
|
2020
2029
|
process.exit(1);
|
|
2021
2030
|
}
|
|
2022
2031
|
const usingApiToken = !!process.env.CONTEXTGRAPH_API_TOKEN;
|
|
2023
2032
|
if (usingApiToken) {
|
|
2024
|
-
console.log("
|
|
2033
|
+
console.log(chalk5.dim("Authenticated via CONTEXTGRAPH_API_TOKEN"));
|
|
2025
2034
|
}
|
|
2026
2035
|
const workerId = randomUUID();
|
|
2027
|
-
console.log(
|
|
2028
|
-
console.log(
|
|
2029
|
-
console.log(
|
|
2030
|
-
|
|
2031
|
-
console.log(`\u{1F4A1} Press Ctrl+C to gracefully shutdown and release any claimed work
|
|
2032
|
-
`);
|
|
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"));
|
|
2033
2040
|
let currentPollInterval = INITIAL_POLL_INTERVAL;
|
|
2034
2041
|
let lastStatusTime = Date.now();
|
|
2035
2042
|
let consecutiveApiErrors = 0;
|
|
@@ -2045,20 +2052,20 @@ async function runLocalAgent(options) {
|
|
|
2045
2052
|
if (isRetryableError(err)) {
|
|
2046
2053
|
consecutiveApiErrors++;
|
|
2047
2054
|
if (consecutiveApiErrors === OUTAGE_WARNING_THRESHOLD) {
|
|
2048
|
-
console.warn(`
|
|
2049
|
-
|
|
2050
|
-
console.warn(` Will continue retrying indefinitely (every ${MAX_RETRY_DELAY / 1e3}s max).`);
|
|
2051
|
-
console.warn(` Press Ctrl+C to stop.
|
|
2052
|
-
`);
|
|
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
|
+
`));
|
|
2053
2060
|
}
|
|
2054
2061
|
if (consecutiveApiErrors < OUTAGE_WARNING_THRESHOLD) {
|
|
2055
|
-
console.warn(
|
|
2062
|
+
console.warn(chalk5.yellow(`API error (attempt ${consecutiveApiErrors}):`), err.message);
|
|
2056
2063
|
} else if (consecutiveApiErrors % 10 === 0) {
|
|
2057
|
-
console.warn(
|
|
2064
|
+
console.warn(chalk5.yellow(`Still retrying... (attempt ${consecutiveApiErrors}, last error: ${err.message})`));
|
|
2058
2065
|
}
|
|
2059
2066
|
const delaySeconds = Math.round(apiRetryDelay / 1e3);
|
|
2060
2067
|
if (consecutiveApiErrors < OUTAGE_WARNING_THRESHOLD) {
|
|
2061
|
-
console.warn(` Retrying in ${delaySeconds}s...`);
|
|
2068
|
+
console.warn(chalk5.dim(` Retrying in ${delaySeconds}s...`));
|
|
2062
2069
|
}
|
|
2063
2070
|
await sleep(apiRetryDelay);
|
|
2064
2071
|
apiRetryDelay = Math.min(apiRetryDelay * 2, MAX_RETRY_DELAY);
|
|
@@ -2089,7 +2096,7 @@ async function runLocalAgent(options) {
|
|
|
2089
2096
|
} else if (!actionDetail.done) {
|
|
2090
2097
|
phase = "execute";
|
|
2091
2098
|
} else {
|
|
2092
|
-
console.log(
|
|
2099
|
+
console.log(chalk5.dim(`Skipping action "${actionDetail.title}" - already completed`));
|
|
2093
2100
|
if (currentClaim && apiClient) {
|
|
2094
2101
|
try {
|
|
2095
2102
|
await apiClient.releaseClaim({
|
|
@@ -2098,13 +2105,13 @@ async function runLocalAgent(options) {
|
|
|
2098
2105
|
claim_id: currentClaim.claimId
|
|
2099
2106
|
});
|
|
2100
2107
|
} catch (releaseError) {
|
|
2101
|
-
console.error("
|
|
2108
|
+
console.error(chalk5.yellow("Failed to release claim:"), releaseError.message);
|
|
2102
2109
|
}
|
|
2103
2110
|
}
|
|
2104
2111
|
currentClaim = null;
|
|
2105
2112
|
continue;
|
|
2106
2113
|
}
|
|
2107
|
-
console.log(
|
|
2114
|
+
console.log(`${chalk5.bold("Working:")} ${chalk5.cyan(actionDetail.title)}`);
|
|
2108
2115
|
let workspacePath;
|
|
2109
2116
|
let cleanup;
|
|
2110
2117
|
let startingCommit;
|
|
@@ -2132,7 +2139,7 @@ async function runLocalAgent(options) {
|
|
|
2132
2139
|
claim_id: currentClaim.claimId
|
|
2133
2140
|
});
|
|
2134
2141
|
} catch (releaseError) {
|
|
2135
|
-
console.error("
|
|
2142
|
+
console.error(chalk5.yellow("Failed to release claim after preparation:"), releaseError.message);
|
|
2136
2143
|
}
|
|
2137
2144
|
}
|
|
2138
2145
|
currentClaim = null;
|
|
@@ -2141,10 +2148,10 @@ async function runLocalAgent(options) {
|
|
|
2141
2148
|
try {
|
|
2142
2149
|
await runExecute(actionDetail.id, { cwd: workspacePath, startingCommit, model: options?.forceModel, runId });
|
|
2143
2150
|
stats.executed++;
|
|
2144
|
-
console.log(
|
|
2151
|
+
console.log(`${chalk5.bold.green("Completed:")} ${chalk5.cyan(actionDetail.title)}`);
|
|
2145
2152
|
} catch (executeError) {
|
|
2146
2153
|
stats.errors++;
|
|
2147
|
-
console.error(
|
|
2154
|
+
console.error(chalk5.red("Error:"), `${executeError.message}. Continuing...`);
|
|
2148
2155
|
} finally {
|
|
2149
2156
|
if (currentClaim && apiClient) {
|
|
2150
2157
|
try {
|
|
@@ -2154,25 +2161,25 @@ async function runLocalAgent(options) {
|
|
|
2154
2161
|
claim_id: currentClaim.claimId
|
|
2155
2162
|
});
|
|
2156
2163
|
} catch (releaseError) {
|
|
2157
|
-
console.error("
|
|
2164
|
+
console.error(chalk5.yellow("Failed to release claim:"), releaseError.message);
|
|
2158
2165
|
}
|
|
2159
2166
|
}
|
|
2160
2167
|
currentClaim = null;
|
|
2161
2168
|
}
|
|
2162
2169
|
} catch (workspaceError) {
|
|
2163
2170
|
stats.errors++;
|
|
2164
|
-
console.error(
|
|
2171
|
+
console.error(chalk5.red("Error preparing workspace:"), `${workspaceError.message}. Continuing...`);
|
|
2165
2172
|
if (currentClaim && apiClient) {
|
|
2166
2173
|
try {
|
|
2167
|
-
console.log(
|
|
2174
|
+
console.log(chalk5.dim("Releasing claim due to workspace error..."));
|
|
2168
2175
|
await apiClient.releaseClaim({
|
|
2169
2176
|
action_id: currentClaim.actionId,
|
|
2170
2177
|
worker_id: currentClaim.workerId,
|
|
2171
2178
|
claim_id: currentClaim.claimId
|
|
2172
2179
|
});
|
|
2173
|
-
console.log("
|
|
2180
|
+
console.log(chalk5.dim("Claim released"));
|
|
2174
2181
|
} catch (releaseError) {
|
|
2175
|
-
console.error("
|
|
2182
|
+
console.error(chalk5.yellow("Failed to release claim:"), releaseError.message);
|
|
2176
2183
|
}
|
|
2177
2184
|
}
|
|
2178
2185
|
currentClaim = null;
|
|
@@ -2184,6 +2191,10 @@ async function runLocalAgent(options) {
|
|
|
2184
2191
|
}
|
|
2185
2192
|
}
|
|
2186
2193
|
|
|
2194
|
+
// src/workflows/setup.ts
|
|
2195
|
+
import chalk6 from "chalk";
|
|
2196
|
+
import { Listr } from "listr2";
|
|
2197
|
+
|
|
2187
2198
|
// src/plugin-setup.ts
|
|
2188
2199
|
import { spawn as spawn2 } from "child_process";
|
|
2189
2200
|
var MARKETPLACE_SOURCE = "contextgraph/claude-code-plugin";
|
|
@@ -2252,81 +2263,131 @@ async function ensurePluginInstalled() {
|
|
|
2252
2263
|
|
|
2253
2264
|
// src/workflows/setup.ts
|
|
2254
2265
|
async function runSetup() {
|
|
2255
|
-
console.log(
|
|
2256
|
-
|
|
2257
|
-
console.log("
|
|
2258
|
-
|
|
2259
|
-
|
|
2260
|
-
|
|
2261
|
-
|
|
2262
|
-
|
|
2263
|
-
|
|
2264
|
-
|
|
2265
|
-
|
|
2266
|
-
|
|
2267
|
-
|
|
2268
|
-
|
|
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
|
|
2269
2342
|
`);
|
|
2270
|
-
}
|
|
2271
|
-
if (needsAuth) {
|
|
2272
|
-
console.log("Step 2: Authenticating with ContextGraph...\n");
|
|
2273
|
-
const result = await authenticateAgent();
|
|
2274
|
-
if (!result.success) {
|
|
2275
|
-
throw new Error("Authentication failed: " + result.error);
|
|
2276
2343
|
}
|
|
2277
|
-
console.log("
|
|
2278
|
-
console.log(`
|
|
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:
|
|
2279
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")}`);
|
|
2280
2369
|
} else {
|
|
2281
|
-
console.log("Step 2: Already authenticated, skipping.\n");
|
|
2282
|
-
}
|
|
2283
|
-
console.log("Step 3: Checking for Claude Code...\n");
|
|
2284
|
-
const hasClaudeCode = await isClaudeCodeAvailable();
|
|
2285
|
-
if (hasClaudeCode) {
|
|
2286
|
-
console.log(" Claude Code detected!\n");
|
|
2287
|
-
console.log("Step 4: Installing ContextGraph plugin...\n");
|
|
2288
|
-
try {
|
|
2289
|
-
if (await isPluginInstalled()) {
|
|
2290
|
-
console.log(" ContextGraph plugin is already installed.\n");
|
|
2291
|
-
} else {
|
|
2292
|
-
await ensurePluginInstalled();
|
|
2293
|
-
console.log("");
|
|
2294
|
-
}
|
|
2295
|
-
} catch (error) {
|
|
2296
|
-
console.error(" Could not install plugin automatically.");
|
|
2297
|
-
console.error(" You can install it manually with:");
|
|
2298
|
-
console.error(" claude plugin marketplace add contextgraph/claude-code-plugin");
|
|
2299
|
-
console.error(" claude plugin install contextgraph\n");
|
|
2300
|
-
}
|
|
2301
|
-
console.log("Setup complete! You're ready to go.\n");
|
|
2302
|
-
console.log("Next steps:\n");
|
|
2303
|
-
console.log(" 1. Open Claude Code (or restart if already running)");
|
|
2304
|
-
console.log(" 2. Ask Claude to help you plan \u2014 it has access to your action graph\n");
|
|
2305
|
-
console.log(" Examples:");
|
|
2306
|
-
console.log(' "Create an action plan for implementing user auth"');
|
|
2307
|
-
console.log(' "Show me my action tree"');
|
|
2308
|
-
console.log(' "What should I work on next?"\n');
|
|
2309
|
-
console.log(" Run the autonomous agent: npx @contextgraph/agent run");
|
|
2310
|
-
console.log(" Web dashboard: https://contextgraph.dev");
|
|
2311
|
-
} else {
|
|
2312
|
-
console.log(" Claude Code not detected.\n");
|
|
2313
2370
|
console.log("You have a few options:\n");
|
|
2314
|
-
console.log("Option 1: Install Claude Code");
|
|
2315
|
-
console.log(
|
|
2316
|
-
console.log(
|
|
2317
|
-
|
|
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"));
|
|
2318
2376
|
console.log(" ContextGraph works with any MCP-compatible editor!\n");
|
|
2319
2377
|
console.log(" To add the ContextGraph MCP server to your editor:");
|
|
2320
|
-
console.log(
|
|
2321
|
-
console.log(
|
|
2322
|
-
console.log(
|
|
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
|
+
`);
|
|
2323
2382
|
console.log(" MCP Server URL:");
|
|
2324
|
-
console.log("
|
|
2325
|
-
|
|
2326
|
-
console.log("
|
|
2327
|
-
console.log(
|
|
2328
|
-
console.log(
|
|
2329
|
-
console.log(
|
|
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!`);
|
|
2330
2391
|
}
|
|
2331
2392
|
console.log("");
|
|
2332
2393
|
}
|