httpcat-cli 0.3.0 → 0.3.1
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/.github/workflows/ci.yml +3 -0
- package/.github/workflows/rc-publish.yml +6 -0
- package/.github/workflows/release.yml +102 -0
- package/.github/workflows/sync-version.yml +31 -2
- package/README.md +1408 -109
- package/additions.txt +3 -0
- package/bun.lock +260 -25
- package/dist/agent/autonomous-trader.d.ts.map +1 -0
- package/dist/agent/autonomous-trader.js +362 -0
- package/dist/agent/autonomous-trader.js.map +1 -0
- package/dist/agent/ax-agent.d.ts.map +1 -1
- package/dist/agent/ax-agent.js +356 -18
- package/dist/agent/ax-agent.js.map +1 -1
- package/dist/agent/event-client.d.ts.map +1 -0
- package/dist/agent/event-client.js +82 -0
- package/dist/agent/event-client.js.map +1 -0
- package/dist/agent/log-stream.d.ts.map +1 -0
- package/dist/agent/log-stream.js +95 -0
- package/dist/agent/log-stream.js.map +1 -0
- package/dist/agent/memory/conversation-session.d.ts.map +1 -0
- package/dist/agent/memory/conversation-session.js +232 -0
- package/dist/agent/memory/conversation-session.js.map +1 -0
- package/dist/agent/memory/conversation-store.d.ts.map +1 -0
- package/dist/agent/memory/conversation-store.js +214 -0
- package/dist/agent/memory/conversation-store.js.map +1 -0
- package/dist/agent/memory/database-schema.d.ts.map +1 -0
- package/dist/agent/memory/database-schema.js +355 -0
- package/dist/agent/memory/database-schema.js.map +1 -0
- package/dist/agent/memory/decision-tracker.d.ts.map +1 -0
- package/dist/agent/memory/decision-tracker.js +274 -0
- package/dist/agent/memory/decision-tracker.js.map +1 -0
- package/dist/agent/memory/memory-manager.d.ts.map +1 -0
- package/dist/agent/memory/memory-manager.js +187 -0
- package/dist/agent/memory/memory-manager.js.map +1 -0
- package/dist/agent/memory/types.d.ts.map +1 -0
- package/dist/agent/memory/types.js +5 -0
- package/dist/agent/memory/types.js.map +1 -0
- package/dist/agent/message-formatter.d.ts.map +1 -0
- package/dist/agent/message-formatter.js +76 -0
- package/dist/agent/message-formatter.js.map +1 -0
- package/dist/agent/position-db.d.ts.map +1 -0
- package/dist/agent/position-db.js +154 -0
- package/dist/agent/position-db.js.map +1 -0
- package/dist/agent/simple-chat-ui-static.d.ts.map +1 -0
- package/dist/agent/simple-chat-ui-static.js +129 -0
- package/dist/agent/simple-chat-ui-static.js.map +1 -0
- package/dist/agent/simple-chat-ui.d.ts.map +1 -0
- package/dist/agent/simple-chat-ui.js +90 -0
- package/dist/agent/simple-chat-ui.js.map +1 -0
- package/dist/agent/tools.d.ts.map +1 -1
- package/dist/agent/tools.js +297 -4
- package/dist/agent/tools.js.map +1 -1
- package/dist/agent/ui.d.ts.map +1 -0
- package/dist/agent/ui.js +84 -0
- package/dist/agent/ui.js.map +1 -0
- package/dist/agent/unified-runtime.d.ts.map +1 -0
- package/dist/agent/unified-runtime.js +397 -0
- package/dist/agent/unified-runtime.js.map +1 -0
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +272 -21
- package/dist/client.js.map +1 -1
- package/dist/commands/account.d.ts.map +1 -1
- package/dist/commands/account.js +187 -33
- package/dist/commands/account.js.map +1 -1
- package/dist/commands/agent.d.ts.map +1 -0
- package/dist/commands/agent.js +125 -0
- package/dist/commands/agent.js.map +1 -0
- package/dist/commands/approve.d.ts.map +1 -0
- package/dist/commands/approve.js +505 -0
- package/dist/commands/approve.js.map +1 -0
- package/dist/commands/automation.d.ts.map +1 -0
- package/dist/commands/automation.js +346 -0
- package/dist/commands/automation.js.map +1 -0
- package/dist/commands/balances.d.ts.map +1 -1
- package/dist/commands/balances.js +226 -73
- package/dist/commands/balances.js.map +1 -1
- package/dist/commands/buy.d.ts.map +1 -1
- package/dist/commands/buy.js +149 -146
- package/dist/commands/buy.js.map +1 -1
- package/dist/commands/call.d.ts.map +1 -0
- package/dist/commands/call.js +51 -0
- package/dist/commands/call.js.map +1 -0
- package/dist/commands/cex.d.ts.map +1 -0
- package/dist/commands/cex.js +958 -0
- package/dist/commands/cex.js.map +1 -0
- package/dist/commands/chat.d.ts.map +1 -1
- package/dist/commands/chat.js +169 -411
- package/dist/commands/chat.js.map +1 -1
- package/dist/commands/claim.d.ts.map +1 -1
- package/dist/commands/claim.js +313 -29
- package/dist/commands/claim.js.map +1 -1
- package/dist/commands/create.d.ts.map +1 -1
- package/dist/commands/create.js +151 -43
- package/dist/commands/create.js.map +1 -1
- package/dist/commands/gasless-swap.d.ts.map +1 -0
- package/dist/commands/gasless-swap.js +232 -0
- package/dist/commands/gasless-swap.js.map +1 -0
- package/dist/commands/health.d.ts.map +1 -1
- package/dist/commands/health.js +63 -7
- package/dist/commands/health.js.map +1 -1
- package/dist/commands/info.d.ts.map +1 -1
- package/dist/commands/info.js +131 -47
- package/dist/commands/info.js.map +1 -1
- package/dist/commands/launchpad.d.ts.map +1 -0
- package/dist/commands/launchpad.js +708 -0
- package/dist/commands/launchpad.js.map +1 -0
- package/dist/commands/list.d.ts.map +1 -1
- package/dist/commands/list.js +57 -23
- package/dist/commands/list.js.map +1 -1
- package/dist/commands/market.d.ts.map +1 -0
- package/dist/commands/market.js +960 -0
- package/dist/commands/market.js.map +1 -0
- package/dist/commands/mcp-install.d.ts.map +1 -0
- package/dist/commands/mcp-install.js +387 -0
- package/dist/commands/mcp-install.js.map +1 -0
- package/dist/commands/opps.d.ts.map +1 -0
- package/dist/commands/opps.js +409 -0
- package/dist/commands/opps.js.map +1 -0
- package/dist/commands/perps.d.ts.map +1 -0
- package/dist/commands/perps.js +248 -0
- package/dist/commands/perps.js.map +1 -0
- package/dist/commands/portfolio.d.ts.map +1 -0
- package/dist/commands/portfolio.js +679 -0
- package/dist/commands/portfolio.js.map +1 -0
- package/dist/commands/positions.d.ts.map +1 -1
- package/dist/commands/positions.js +76 -47
- package/dist/commands/positions.js.map +1 -1
- package/dist/commands/predict.d.ts.map +1 -0
- package/dist/commands/predict.js +280 -0
- package/dist/commands/predict.js.map +1 -0
- package/dist/commands/predictions.d.ts.map +1 -0
- package/dist/commands/predictions.js +486 -0
- package/dist/commands/predictions.js.map +1 -0
- package/dist/commands/risk.d.ts.map +1 -0
- package/dist/commands/risk.js +225 -0
- package/dist/commands/risk.js.map +1 -0
- package/dist/commands/security.d.ts.map +1 -0
- package/dist/commands/security.js +244 -0
- package/dist/commands/security.js.map +1 -0
- package/dist/commands/sell.d.ts.map +1 -1
- package/dist/commands/sell.js +67 -34
- package/dist/commands/sell.js.map +1 -1
- package/dist/commands/send.d.ts.map +1 -0
- package/dist/commands/send.js +733 -0
- package/dist/commands/send.js.map +1 -0
- package/dist/commands/sign.d.ts.map +1 -0
- package/dist/commands/sign.js +1048 -0
- package/dist/commands/sign.js.map +1 -0
- package/dist/commands/swap.d.ts.map +1 -0
- package/dist/commands/swap.js +744 -0
- package/dist/commands/swap.js.map +1 -0
- package/dist/commands/system.d.ts.map +1 -0
- package/dist/commands/system.js +417 -0
- package/dist/commands/system.js.map +1 -0
- package/dist/commands/tools/index.d.ts.map +1 -0
- package/dist/commands/tools/index.js +2040 -0
- package/dist/commands/tools/index.js.map +1 -0
- package/dist/commands/trade.d.ts.map +1 -0
- package/dist/commands/trade.js +237 -0
- package/dist/commands/trade.js.map +1 -0
- package/dist/commands/transactions.d.ts.map +1 -1
- package/dist/commands/transactions.js +29 -17
- package/dist/commands/transactions.js.map +1 -1
- package/dist/commands/update.d.ts.map +1 -0
- package/dist/commands/update.js +429 -0
- package/dist/commands/update.js.map +1 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +351 -40
- package/dist/config.js.map +1 -1
- package/dist/index.js +4524 -924
- package/dist/index.js.map +1 -1
- package/dist/interactive/art.d.ts.map +1 -1
- package/dist/interactive/art.js +33 -1
- package/dist/interactive/art.js.map +1 -1
- package/dist/interactive/shell.d.ts.map +1 -1
- package/dist/interactive/shell.js +467 -2652
- package/dist/interactive/shell.js.map +1 -1
- package/dist/mcp/context.d.ts.map +1 -0
- package/dist/mcp/context.js +211 -0
- package/dist/mcp/context.js.map +1 -0
- package/dist/mcp/onboarding.d.ts.map +1 -0
- package/dist/mcp/onboarding.js +266 -0
- package/dist/mcp/onboarding.js.map +1 -0
- package/dist/mcp/resources.d.ts.map +1 -0
- package/dist/mcp/resources.js +222 -0
- package/dist/mcp/resources.js.map +1 -0
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/mcp/server.js +51 -1
- package/dist/mcp/server.js.map +1 -1
- package/dist/mcp/tools.d.ts.map +1 -1
- package/dist/mcp/tools.js +4119 -169
- package/dist/mcp/tools.js.map +1 -1
- package/dist/mcp/types.d.ts.map +1 -1
- package/dist/types/agent-info.d.ts.map +1 -0
- package/dist/types/agent-info.js +11 -0
- package/dist/types/agent-info.js.map +1 -0
- package/dist/ui/components/ScrollableList.d.ts.map +1 -0
- package/dist/ui/components/ScrollableList.js +72 -0
- package/dist/ui/components/ScrollableList.js.map +1 -0
- package/dist/ui/components/ThemeProvider.d.ts.map +1 -0
- package/dist/ui/components/ThemeProvider.js +87 -0
- package/dist/ui/components/ThemeProvider.js.map +1 -0
- package/dist/ui/components/ThemedBox.d.ts.map +1 -0
- package/dist/ui/components/ThemedBox.js +24 -0
- package/dist/ui/components/ThemedBox.js.map +1 -0
- package/dist/ui/components/agent/ChatHeader.d.ts.map +1 -0
- package/dist/ui/components/agent/ChatHeader.js +39 -0
- package/dist/ui/components/agent/ChatHeader.js.map +1 -0
- package/dist/ui/components/agent/Header.d.ts.map +1 -0
- package/dist/ui/components/agent/Header.js +14 -0
- package/dist/ui/components/agent/Header.js.map +1 -0
- package/dist/ui/components/agent/Input.d.ts.map +1 -0
- package/dist/ui/components/agent/Input.js +23 -0
- package/dist/ui/components/agent/Input.js.map +1 -0
- package/dist/ui/components/agent/Output.d.ts.map +1 -0
- package/dist/ui/components/agent/Output.js +23 -0
- package/dist/ui/components/agent/Output.js.map +1 -0
- package/dist/ui/components/chat/TokenChatUI.d.ts.map +1 -0
- package/dist/ui/components/chat/TokenChatUI.js +133 -0
- package/dist/ui/components/chat/TokenChatUI.js.map +1 -0
- package/dist/ui/components/shell/ShellHeader.d.ts.map +1 -0
- package/dist/ui/components/shell/ShellHeader.js +31 -0
- package/dist/ui/components/shell/ShellHeader.js.map +1 -0
- package/dist/ui/components/shell/ShellInput.d.ts.map +1 -0
- package/dist/ui/components/shell/ShellInput.js +151 -0
- package/dist/ui/components/shell/ShellInput.js.map +1 -0
- package/dist/ui/components/shell/ShellOutput.d.ts.map +1 -0
- package/dist/ui/components/shell/ShellOutput.js +8 -0
- package/dist/ui/components/shell/ShellOutput.js.map +1 -0
- package/dist/ui/hooks/useChatWebSocket.d.ts.map +1 -0
- package/dist/ui/hooks/useChatWebSocket.js +76 -0
- package/dist/ui/hooks/useChatWebSocket.js.map +1 -0
- package/dist/ui/hooks/useCommandHistory.d.ts.map +1 -0
- package/dist/ui/hooks/useCommandHistory.js +70 -0
- package/dist/ui/hooks/useCommandHistory.js.map +1 -0
- package/dist/ui/hooks/useDebounce.d.ts.map +1 -0
- package/dist/ui/hooks/useDebounce.js +17 -0
- package/dist/ui/hooks/useDebounce.js.map +1 -0
- package/dist/ui/hooks/useLogStream.d.ts.map +1 -0
- package/dist/ui/hooks/useLogStream.js +20 -0
- package/dist/ui/hooks/useLogStream.js.map +1 -0
- package/dist/ui/hooks/useVirtualScroll.d.ts.map +1 -0
- package/dist/ui/hooks/useVirtualScroll.js +70 -0
- package/dist/ui/hooks/useVirtualScroll.js.map +1 -0
- package/dist/utils/admin.d.ts.map +1 -0
- package/dist/utils/admin.js +144 -0
- package/dist/utils/admin.js.map +1 -0
- package/dist/utils/autoSetup.d.ts.map +1 -0
- package/dist/utils/autoSetup.js +252 -0
- package/dist/utils/autoSetup.js.map +1 -0
- package/dist/utils/build-constants.d.ts.map +1 -0
- package/dist/utils/build-constants.js +10 -0
- package/dist/utils/build-constants.js.map +1 -0
- package/dist/utils/constants.d.ts.map +1 -1
- package/dist/utils/errors.d.ts.map +1 -1
- package/dist/utils/errors.js +10 -1
- package/dist/utils/errors.js.map +1 -1
- package/dist/utils/formatting.d.ts.map +1 -1
- package/dist/utils/formatting.js +46 -9
- package/dist/utils/formatting.js.map +1 -1
- package/dist/utils/llm-cli-config.d.ts.map +1 -0
- package/dist/utils/llm-cli-config.js +963 -0
- package/dist/utils/llm-cli-config.js.map +1 -0
- package/dist/utils/llm-cli-detector.d.ts.map +1 -0
- package/dist/utils/llm-cli-detector.js +202 -0
- package/dist/utils/llm-cli-detector.js.map +1 -0
- package/dist/utils/loading.d.ts.map +1 -1
- package/dist/utils/loading.js +25 -3
- package/dist/utils/loading.js.map +1 -1
- package/dist/utils/maintenance.d.ts.map +1 -0
- package/dist/utils/maintenance.js +17 -0
- package/dist/utils/maintenance.js.map +1 -0
- package/dist/utils/mcp-config.d.ts.map +1 -0
- package/dist/utils/mcp-config.js +77 -0
- package/dist/utils/mcp-config.js.map +1 -0
- package/dist/utils/privateKeyPrompt.d.ts.map +1 -1
- package/dist/utils/privateKeyPrompt.js +308 -129
- package/dist/utils/privateKeyPrompt.js.map +1 -1
- package/dist/utils/process-cleanup.d.ts.map +1 -0
- package/dist/utils/process-cleanup.js +136 -0
- package/dist/utils/process-cleanup.js.map +1 -0
- package/dist/utils/retry.d.ts.map +1 -0
- package/dist/utils/retry.js +56 -0
- package/dist/utils/retry.js.map +1 -0
- package/dist/utils/rpc-helpers.d.ts.map +1 -0
- package/dist/utils/rpc-helpers.js +70 -0
- package/dist/utils/rpc-helpers.js.map +1 -0
- package/dist/utils/rpc-transport.d.ts.map +1 -0
- package/dist/utils/rpc-transport.js +87 -0
- package/dist/utils/rpc-transport.js.map +1 -0
- package/dist/utils/shell-setup.d.ts.map +1 -0
- package/dist/utils/shell-setup.js +531 -0
- package/dist/utils/shell-setup.js.map +1 -0
- package/dist/utils/status.d.ts.map +1 -1
- package/dist/utils/status.js +34 -5
- package/dist/utils/status.js.map +1 -1
- package/dist/utils/token-resolver.d.ts.map +1 -1
- package/dist/utils/token-resolver.js +51 -8
- package/dist/utils/token-resolver.js.map +1 -1
- package/dist/utils/x402-caller.d.ts.map +1 -0
- package/dist/utils/x402-caller.js +17 -0
- package/dist/utils/x402-caller.js.map +1 -0
- package/docs/README.md +28 -0
- package/docs/agent/README.md +18 -0
- package/docs/api/README.md +41 -0
- package/docs/cli/README.md +42 -0
- package/docs/guides/README.md +26 -0
- package/docs/implementation/README.md +18 -0
- package/docs/planning/README.md +19 -0
- package/docs/testing/README.md +15 -0
- package/docs/ux/README.md +16 -0
- package/issues.txt +2 -0
- package/package.json +24 -9
- package/scripts/cat-spin.sh +417 -0
- package/scripts/deprecate-rc-versions.js +58 -0
- package/scripts/inject-build-constants.js +43 -0
- package/scripts/monitor-foobar.js +117 -0
- package/swap.logs +61 -0
- package/swapping.txt +108 -0
- package/test.txt +12 -0
- package/tests/fixtures/test-data.json +16 -0
- package/Screenshot 2025-12-21 at 8.56.02/342/200/257PM.png +0 -0
package/dist/config.js
CHANGED
|
@@ -4,25 +4,30 @@ import chalk from "chalk";
|
|
|
4
4
|
import path from "path";
|
|
5
5
|
import os from "os";
|
|
6
6
|
import fs from "fs";
|
|
7
|
-
import { decryptData, encryptData, seedPhraseToPrivateKey, getAddressFromPrivateKey } from "./utils/wallet.js";
|
|
7
|
+
import { decryptData, encryptData, seedPhraseToPrivateKey, getAddressFromPrivateKey, } from "./utils/wallet.js";
|
|
8
8
|
const DEFAULT_ENVIRONMENTS = {
|
|
9
9
|
local: {
|
|
10
10
|
name: "local",
|
|
11
11
|
agentUrl: "http://localhost:8787",
|
|
12
12
|
network: "eip155:84532",
|
|
13
13
|
},
|
|
14
|
-
sepolia: {
|
|
15
|
-
name: "sepolia",
|
|
16
|
-
agentUrl: "https://agent.402.cat",
|
|
14
|
+
"base-sepolia": {
|
|
15
|
+
name: "base-sepolia",
|
|
16
|
+
agentUrl: "https://agent-test.402.cat",
|
|
17
17
|
network: "eip155:84532",
|
|
18
18
|
},
|
|
19
|
+
base: {
|
|
20
|
+
name: "base",
|
|
21
|
+
agentUrl: "https://agent-main.402.cat",
|
|
22
|
+
network: "eip155:8453",
|
|
23
|
+
},
|
|
19
24
|
};
|
|
20
25
|
const DEFAULT_CONFIG = {
|
|
21
|
-
network: "eip155:
|
|
22
|
-
agentUrl: "https://agent.402.cat",
|
|
23
|
-
facilitatorUrl: "https://
|
|
26
|
+
network: "eip155:8453",
|
|
27
|
+
agentUrl: "https://agent-main.402.cat",
|
|
28
|
+
facilitatorUrl: "https://facilitator.402.cat",
|
|
24
29
|
defaultMaxPayment: "10.00",
|
|
25
|
-
environment: "
|
|
30
|
+
environment: "base",
|
|
26
31
|
environments: DEFAULT_ENVIRONMENTS,
|
|
27
32
|
preferences: {
|
|
28
33
|
enableAsciiArt: true,
|
|
@@ -34,6 +39,8 @@ export class ConfigManager {
|
|
|
34
39
|
store;
|
|
35
40
|
session = null;
|
|
36
41
|
configPath;
|
|
42
|
+
agentInfoCache = null;
|
|
43
|
+
AGENT_INFO_CACHE_TTL = 5 * 60 * 1000; // 5 minutes
|
|
37
44
|
constructor() {
|
|
38
45
|
// Explicitly define where we want the config file
|
|
39
46
|
const configDir = path.join(os.homedir(), ".config", "httpcat");
|
|
@@ -70,8 +77,57 @@ export class ConfigManager {
|
|
|
70
77
|
}
|
|
71
78
|
}
|
|
72
79
|
}
|
|
73
|
-
//
|
|
80
|
+
// Validate and fix corrupted config files BEFORE Conf initialization
|
|
74
81
|
// Conf's default on macOS is ~/Library/Preferences/httpcat-nodejs/config.json
|
|
82
|
+
const defaultConfPath = path.join(os.homedir(), "Library", "Preferences", "httpcat-nodejs", "config.json");
|
|
83
|
+
if (fs.existsSync(defaultConfPath)) {
|
|
84
|
+
try {
|
|
85
|
+
const content = fs.readFileSync(defaultConfPath, "utf-8").trim();
|
|
86
|
+
if (content) {
|
|
87
|
+
JSON.parse(content); // Validate JSON
|
|
88
|
+
}
|
|
89
|
+
else {
|
|
90
|
+
// Empty file - delete it so Conf uses defaults
|
|
91
|
+
fs.unlinkSync(defaultConfPath);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
catch {
|
|
95
|
+
// Corrupted JSON - backup and delete it
|
|
96
|
+
try {
|
|
97
|
+
const backupPath = `${defaultConfPath}.backup.${Date.now()}`;
|
|
98
|
+
fs.copyFileSync(defaultConfPath, backupPath);
|
|
99
|
+
}
|
|
100
|
+
catch {
|
|
101
|
+
// Ignore backup failure
|
|
102
|
+
}
|
|
103
|
+
fs.unlinkSync(defaultConfPath);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
// Also validate our custom config path before Conf tries to read it
|
|
107
|
+
if (fs.existsSync(this.configPath)) {
|
|
108
|
+
try {
|
|
109
|
+
const configContent = fs.readFileSync(this.configPath, "utf-8").trim();
|
|
110
|
+
if (configContent) {
|
|
111
|
+
JSON.parse(configContent); // Validate JSON
|
|
112
|
+
}
|
|
113
|
+
else {
|
|
114
|
+
// Empty file - initialize with defaults
|
|
115
|
+
fs.writeFileSync(this.configPath, JSON.stringify(DEFAULT_CONFIG, null, 2));
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
catch {
|
|
119
|
+
// Corrupted - backup and recreate
|
|
120
|
+
try {
|
|
121
|
+
const backupPath = `${this.configPath}.backup.${Date.now()}`;
|
|
122
|
+
fs.copyFileSync(this.configPath, backupPath);
|
|
123
|
+
}
|
|
124
|
+
catch {
|
|
125
|
+
// Ignore backup failure
|
|
126
|
+
}
|
|
127
|
+
fs.writeFileSync(this.configPath, JSON.stringify(DEFAULT_CONFIG, null, 2));
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
// Initialize Conf WITHOUT cwd - let it use default location, then we'll redirect
|
|
75
131
|
// But we want ~/.config/httpcat/config.json
|
|
76
132
|
// So we'll initialize Conf normally, then manually sync to our desired location
|
|
77
133
|
this.store = new Conf({
|
|
@@ -81,8 +137,33 @@ export class ConfigManager {
|
|
|
81
137
|
});
|
|
82
138
|
// Always sync from correct location to Conf's location on init
|
|
83
139
|
// This ensures Conf reads the right data
|
|
140
|
+
// If config file doesn't exist, create it with defaults
|
|
141
|
+
if (!fs.existsSync(this.configPath)) {
|
|
142
|
+
// Ensure directory exists
|
|
143
|
+
fs.mkdirSync(path.dirname(this.configPath), { recursive: true });
|
|
144
|
+
// Write defaults to config file
|
|
145
|
+
fs.writeFileSync(this.configPath, JSON.stringify(DEFAULT_CONFIG, null, 2));
|
|
146
|
+
}
|
|
84
147
|
if (fs.existsSync(this.configPath)) {
|
|
85
148
|
try {
|
|
149
|
+
// Validate JSON before copying
|
|
150
|
+
const configContent = fs.readFileSync(this.configPath, "utf-8").trim();
|
|
151
|
+
if (configContent) {
|
|
152
|
+
// Try to parse JSON to validate it
|
|
153
|
+
try {
|
|
154
|
+
JSON.parse(configContent);
|
|
155
|
+
}
|
|
156
|
+
catch (parseError) {
|
|
157
|
+
// Config file is corrupted - backup and recreate with defaults
|
|
158
|
+
const backupPath = `${this.configPath}.backup.${Date.now()}`;
|
|
159
|
+
fs.copyFileSync(this.configPath, backupPath);
|
|
160
|
+
fs.writeFileSync(this.configPath, JSON.stringify(DEFAULT_CONFIG, null, 2));
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
else {
|
|
164
|
+
// Empty file - initialize with defaults
|
|
165
|
+
fs.writeFileSync(this.configPath, JSON.stringify(DEFAULT_CONFIG, null, 2));
|
|
166
|
+
}
|
|
86
167
|
// Ensure Conf's directory exists
|
|
87
168
|
const confDir = path.dirname(this.store.path);
|
|
88
169
|
fs.mkdirSync(confDir, { recursive: true });
|
|
@@ -96,13 +177,38 @@ export class ConfigManager {
|
|
|
96
177
|
});
|
|
97
178
|
}
|
|
98
179
|
catch (error) {
|
|
99
|
-
//
|
|
180
|
+
// If copying fails, try to initialize Conf with defaults
|
|
181
|
+
try {
|
|
182
|
+
this.store = new Conf({
|
|
183
|
+
projectName: "httpcat",
|
|
184
|
+
defaults: DEFAULT_CONFIG,
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
catch (fallbackError) {
|
|
188
|
+
// Last resort: delete corrupted file and start fresh
|
|
189
|
+
if (fs.existsSync(this.configPath)) {
|
|
190
|
+
const backupPath = `${this.configPath}.backup.${Date.now()}`;
|
|
191
|
+
try {
|
|
192
|
+
fs.copyFileSync(this.configPath, backupPath);
|
|
193
|
+
}
|
|
194
|
+
catch {
|
|
195
|
+
// Ignore backup failure
|
|
196
|
+
}
|
|
197
|
+
fs.unlinkSync(this.configPath);
|
|
198
|
+
}
|
|
199
|
+
this.store = new Conf({
|
|
200
|
+
projectName: "httpcat",
|
|
201
|
+
defaults: DEFAULT_CONFIG,
|
|
202
|
+
});
|
|
203
|
+
}
|
|
100
204
|
}
|
|
101
205
|
}
|
|
102
206
|
// Migrate old privateKey format on first access
|
|
103
207
|
this.migrateLegacyPrivateKey();
|
|
104
208
|
// Migrate network format from V1 to V2 (base-sepolia -> eip155:84532)
|
|
105
209
|
this.migrateNetworkFormat();
|
|
210
|
+
// Migrate sepolia environment to base-sepolia
|
|
211
|
+
this.migrateSepoliaEnvironment();
|
|
106
212
|
}
|
|
107
213
|
/**
|
|
108
214
|
* Migrate config from old location to new location (~/.config/httpcat)
|
|
@@ -122,7 +228,10 @@ export class ConfigManager {
|
|
|
122
228
|
if (fs.existsSync(oldPath)) {
|
|
123
229
|
const oldData = oldStore.store;
|
|
124
230
|
const hasOldData = Object.keys(oldData).length > 0 &&
|
|
125
|
-
(oldData.privateKey ||
|
|
231
|
+
(oldData.privateKey ||
|
|
232
|
+
oldData.accounts ||
|
|
233
|
+
oldData.encryptedPrivateKey ||
|
|
234
|
+
oldData.encryptedSeedPhrase);
|
|
126
235
|
// Check if new config already exists
|
|
127
236
|
const newConfigExists = fs.existsSync(newPath);
|
|
128
237
|
if (hasOldData && !newConfigExists) {
|
|
@@ -159,7 +268,8 @@ export class ConfigManager {
|
|
|
159
268
|
// Check if correct file is newer or Conf's file doesn't exist
|
|
160
269
|
const needsSync = !fs.existsSync(this.store.path) ||
|
|
161
270
|
(fs.existsSync(this.store.path) &&
|
|
162
|
-
fs.statSync(this.configPath).mtimeMs >
|
|
271
|
+
fs.statSync(this.configPath).mtimeMs >
|
|
272
|
+
fs.statSync(this.store.path).mtimeMs);
|
|
163
273
|
if (needsSync) {
|
|
164
274
|
// Ensure Conf's directory exists
|
|
165
275
|
const confDir = path.dirname(this.store.path);
|
|
@@ -200,7 +310,8 @@ export class ConfigManager {
|
|
|
200
310
|
try {
|
|
201
311
|
const needsSync = !fs.existsSync(this.store.path) ||
|
|
202
312
|
(fs.existsSync(this.store.path) &&
|
|
203
|
-
fs.statSync(this.configPath).mtimeMs >
|
|
313
|
+
fs.statSync(this.configPath).mtimeMs >
|
|
314
|
+
fs.statSync(this.store.path).mtimeMs);
|
|
204
315
|
if (needsSync) {
|
|
205
316
|
const confDir = path.dirname(this.store.path);
|
|
206
317
|
fs.mkdirSync(confDir, { recursive: true });
|
|
@@ -225,6 +336,18 @@ export class ConfigManager {
|
|
|
225
336
|
}
|
|
226
337
|
clear() {
|
|
227
338
|
this.store.clear();
|
|
339
|
+
// Sync the cleared state to the config file
|
|
340
|
+
if (this.store.path !== this.configPath && fs.existsSync(this.store.path)) {
|
|
341
|
+
try {
|
|
342
|
+
// Ensure directory exists
|
|
343
|
+
fs.mkdirSync(path.dirname(this.configPath), { recursive: true });
|
|
344
|
+
// Copy from Conf's location to correct location
|
|
345
|
+
fs.copyFileSync(this.store.path, this.configPath);
|
|
346
|
+
}
|
|
347
|
+
catch (error) {
|
|
348
|
+
// Silently fail sync - not critical
|
|
349
|
+
}
|
|
350
|
+
}
|
|
228
351
|
}
|
|
229
352
|
getConfigPath() {
|
|
230
353
|
// Return the path we want to use (the correct one)
|
|
@@ -240,7 +363,9 @@ export class ConfigManager {
|
|
|
240
363
|
if (configData.accounts && configData.accounts.length > 0) {
|
|
241
364
|
return true;
|
|
242
365
|
}
|
|
243
|
-
if (configData.privateKey ||
|
|
366
|
+
if (configData.privateKey ||
|
|
367
|
+
configData.encryptedPrivateKey ||
|
|
368
|
+
configData.encryptedSeedPhrase) {
|
|
244
369
|
return true;
|
|
245
370
|
}
|
|
246
371
|
}
|
|
@@ -253,7 +378,8 @@ export class ConfigManager {
|
|
|
253
378
|
try {
|
|
254
379
|
const needsSync = !fs.existsSync(this.store.path) ||
|
|
255
380
|
(fs.existsSync(this.store.path) &&
|
|
256
|
-
fs.statSync(this.configPath).mtimeMs >
|
|
381
|
+
fs.statSync(this.configPath).mtimeMs >
|
|
382
|
+
fs.statSync(this.store.path).mtimeMs);
|
|
257
383
|
if (needsSync) {
|
|
258
384
|
const confDir = path.dirname(this.store.path);
|
|
259
385
|
fs.mkdirSync(confDir, { recursive: true });
|
|
@@ -306,15 +432,38 @@ export class ConfigManager {
|
|
|
306
432
|
}
|
|
307
433
|
}
|
|
308
434
|
}
|
|
435
|
+
/**
|
|
436
|
+
* Migrate sepolia environment to base-sepolia
|
|
437
|
+
*/
|
|
438
|
+
migrateSepoliaEnvironment() {
|
|
439
|
+
const envs = this.get("environments");
|
|
440
|
+
if (envs && envs.sepolia) {
|
|
441
|
+
// Rename sepolia environment to base-sepolia
|
|
442
|
+
const updatedEnvs = {};
|
|
443
|
+
for (const [name, env] of Object.entries(envs)) {
|
|
444
|
+
const envProfile = env;
|
|
445
|
+
if (name === "sepolia") {
|
|
446
|
+
updatedEnvs["base-sepolia"] = { ...envProfile, name: "base-sepolia" };
|
|
447
|
+
}
|
|
448
|
+
else {
|
|
449
|
+
updatedEnvs[name] = envProfile;
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
this.set("environments", updatedEnvs);
|
|
453
|
+
}
|
|
454
|
+
// Update current environment if it's sepolia
|
|
455
|
+
const currentEnv = this.get("environment");
|
|
456
|
+
if (currentEnv === "sepolia") {
|
|
457
|
+
this.set("environment", "base-sepolia");
|
|
458
|
+
}
|
|
459
|
+
}
|
|
309
460
|
/**
|
|
310
461
|
* Convert network name to CAIP-2 format
|
|
311
462
|
*/
|
|
312
463
|
networkToCAIP2(network) {
|
|
313
464
|
const mapping = {
|
|
314
465
|
"base-sepolia": "eip155:84532",
|
|
315
|
-
|
|
316
|
-
"ethereum": "eip155:1",
|
|
317
|
-
"sepolia": "eip155:11155111",
|
|
466
|
+
base: "eip155:8453",
|
|
318
467
|
};
|
|
319
468
|
return mapping[network] || network; // Return as-is if already CAIP-2 or unknown
|
|
320
469
|
}
|
|
@@ -325,8 +474,6 @@ export class ConfigManager {
|
|
|
325
474
|
const mapping = {
|
|
326
475
|
"eip155:84532": "base-sepolia",
|
|
327
476
|
"eip155:8453": "base",
|
|
328
|
-
"eip155:1": "ethereum",
|
|
329
|
-
"eip155:11155111": "sepolia",
|
|
330
477
|
};
|
|
331
478
|
return mapping[caip2] || caip2; // Return as-is if not in mapping
|
|
332
479
|
}
|
|
@@ -334,7 +481,9 @@ export class ConfigManager {
|
|
|
334
481
|
* Check if network is a testnet
|
|
335
482
|
*/
|
|
336
483
|
isTestnet(network) {
|
|
337
|
-
return network === "eip155:84532" ||
|
|
484
|
+
return (network === "eip155:84532" ||
|
|
485
|
+
network === "eip155:11155111" ||
|
|
486
|
+
network.includes("sepolia"));
|
|
338
487
|
}
|
|
339
488
|
/**
|
|
340
489
|
* Migrate legacy privateKey to new account format
|
|
@@ -380,17 +529,30 @@ export class ConfigManager {
|
|
|
380
529
|
console.log(chalk.cyan("=".repeat(80)));
|
|
381
530
|
console.log();
|
|
382
531
|
if (!options.skipPrivateKey) {
|
|
383
|
-
//
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
532
|
+
// Check if import mode is enabled via environment variable
|
|
533
|
+
if (process.env.HTTPCAT_IMPORT_MODE === "true") {
|
|
534
|
+
// Use the nice wallet setup wizard instead of directly asking for private key
|
|
535
|
+
const { promptForPrivateKey } = await import("./utils/privateKeyPrompt.js");
|
|
536
|
+
await promptForPrivateKey();
|
|
537
|
+
console.log();
|
|
538
|
+
}
|
|
539
|
+
else {
|
|
540
|
+
// Auto-generate seed phrase for new users
|
|
541
|
+
const { autoSetupWallet } = await import("./utils/autoSetup.js");
|
|
542
|
+
await autoSetupWallet();
|
|
543
|
+
console.log();
|
|
544
|
+
}
|
|
387
545
|
}
|
|
388
546
|
// Network selection
|
|
389
|
-
const network = "eip155:
|
|
547
|
+
const network = "eip155:8453";
|
|
390
548
|
this.set("network", network);
|
|
391
549
|
console.log(chalk.green(`✅ Network set to: ${this.caip2ToNetwork(network)} (${network}) (testnet)\n`));
|
|
392
|
-
// Agent URL
|
|
393
|
-
|
|
550
|
+
// Agent URL - use correct default based on network
|
|
551
|
+
// base-sepolia (eip155:84532) -> testnet URL
|
|
552
|
+
// base (eip155:8453) -> mainnet URL
|
|
553
|
+
const defaultUrl = network === "eip155:8453"
|
|
554
|
+
? "https://agent-main.402.cat"
|
|
555
|
+
: "https://agent-test.402.cat";
|
|
394
556
|
const agentUrl = await this.prompt(`Agent URL [${defaultUrl}]: `, defaultUrl);
|
|
395
557
|
this.set("agentUrl", agentUrl);
|
|
396
558
|
console.log(chalk.green(`✅ Agent URL set to: ${agentUrl}\n`));
|
|
@@ -407,6 +569,68 @@ export class ConfigManager {
|
|
|
407
569
|
console.log();
|
|
408
570
|
console.log(chalk.dim(`Config saved to: ${this.getConfigPath()}`));
|
|
409
571
|
console.log();
|
|
572
|
+
// Shell setup (completion and alias)
|
|
573
|
+
await this.promptShellSetup();
|
|
574
|
+
}
|
|
575
|
+
async promptShellSetup() {
|
|
576
|
+
try {
|
|
577
|
+
const { detectShell, installShellCompletion, installHcAlias } = await import("./utils/shell-setup.js");
|
|
578
|
+
const shell = detectShell();
|
|
579
|
+
if (shell === "unknown") {
|
|
580
|
+
console.log(chalk.yellow("⚠️ Could not detect shell type. Skipping shell setup."));
|
|
581
|
+
console.log();
|
|
582
|
+
return;
|
|
583
|
+
}
|
|
584
|
+
// Prompt for completion installation
|
|
585
|
+
const installCompletion = await this.prompt(`Install shell autocompletion for ${shell}? [Y/n]: `, "y");
|
|
586
|
+
if (installCompletion.toLowerCase() !== "n") {
|
|
587
|
+
console.log(chalk.cyan("Installing shell completion..."));
|
|
588
|
+
const success = installShellCompletion();
|
|
589
|
+
if (success) {
|
|
590
|
+
console.log(chalk.green(`✅ Shell completion installed for ${shell}!`));
|
|
591
|
+
console.log(chalk.dim(" Restart your terminal or run: source ~/." +
|
|
592
|
+
(shell === "zsh" ? "zshrc" : "bashrc")));
|
|
593
|
+
}
|
|
594
|
+
else {
|
|
595
|
+
console.log(chalk.yellow("⚠️ Failed to install shell completion. You can install it manually later with:"));
|
|
596
|
+
console.log(chalk.dim(` httpcat completion ${shell} >> ~/.${shell === "zsh" ? "zshrc" : "bashrc"}`));
|
|
597
|
+
}
|
|
598
|
+
console.log();
|
|
599
|
+
}
|
|
600
|
+
// Prompt for alias creation
|
|
601
|
+
const createAlias = await this.prompt("Create 'hc' alias for httpcat? [Y/n]: ", "y");
|
|
602
|
+
if (createAlias.toLowerCase() !== "n") {
|
|
603
|
+
console.log(chalk.cyan("Creating 'hc' alias..."));
|
|
604
|
+
const result = installHcAlias();
|
|
605
|
+
if (result.success) {
|
|
606
|
+
if (result.method === "symlink") {
|
|
607
|
+
console.log(chalk.green("✅ 'hc' alias created (symlink)!"));
|
|
608
|
+
console.log(chalk.dim(" You can now use 'hc' instead of 'httpcat' immediately."));
|
|
609
|
+
}
|
|
610
|
+
else {
|
|
611
|
+
console.log(chalk.green("✅ 'hc' alias created (shell alias)!"));
|
|
612
|
+
console.log(chalk.dim(" You can now use 'hc' instead of 'httpcat'. Restart your terminal or run:"));
|
|
613
|
+
if (shell === "zsh") {
|
|
614
|
+
console.log(chalk.dim(" source ~/.zshrc"));
|
|
615
|
+
}
|
|
616
|
+
else {
|
|
617
|
+
console.log(chalk.dim(" source ~/.bashrc"));
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
}
|
|
621
|
+
else {
|
|
622
|
+
console.log(chalk.yellow("⚠️ Failed to create 'hc' alias. You can create it manually with:"));
|
|
623
|
+
console.log(chalk.dim(` alias hc='httpcat'`));
|
|
624
|
+
console.log(chalk.dim(` Add this to your ~/.${shell === "zsh" ? "zshrc" : "bashrc"} file`));
|
|
625
|
+
}
|
|
626
|
+
console.log();
|
|
627
|
+
}
|
|
628
|
+
}
|
|
629
|
+
catch (error) {
|
|
630
|
+
// Non-fatal error - don't break the wizard
|
|
631
|
+
console.log(chalk.yellow("⚠️ Shell setup skipped due to error (non-fatal)"));
|
|
632
|
+
console.log();
|
|
633
|
+
}
|
|
410
634
|
}
|
|
411
635
|
prompt(question, defaultValue) {
|
|
412
636
|
return new Promise((resolve) => {
|
|
@@ -448,18 +672,18 @@ export class ConfigManager {
|
|
|
448
672
|
// Ensure session is valid
|
|
449
673
|
this.ensureSessionValid();
|
|
450
674
|
if (account.type === "custom") {
|
|
451
|
-
//
|
|
452
|
-
const encrypted = this.get("encryptedPrivateKey");
|
|
675
|
+
// Custom account - get encrypted private key from account or fall back to global
|
|
676
|
+
const encrypted = account.encryptedPrivateKey || this.get("encryptedPrivateKey");
|
|
453
677
|
if (!encrypted) {
|
|
454
|
-
throw new Error(
|
|
678
|
+
throw new Error(`Private key not found for account ${accountIndex}`);
|
|
455
679
|
}
|
|
456
680
|
const password = this.get("password") || "";
|
|
457
681
|
if (password) {
|
|
458
|
-
// Decrypt
|
|
459
|
-
if (!this.
|
|
682
|
+
// Decrypt on-demand
|
|
683
|
+
if (!this.isSessionValid()) {
|
|
460
684
|
throw new Error("Session expired. Please unlock your wallet.");
|
|
461
685
|
}
|
|
462
|
-
return
|
|
686
|
+
return decryptData(encrypted, password);
|
|
463
687
|
}
|
|
464
688
|
else {
|
|
465
689
|
// No password - stored as plain (but in encryptedPrivateKey field)
|
|
@@ -684,7 +908,22 @@ export class ConfigManager {
|
|
|
684
908
|
this.set("environments", DEFAULT_ENVIRONMENTS);
|
|
685
909
|
return DEFAULT_ENVIRONMENTS;
|
|
686
910
|
}
|
|
687
|
-
|
|
911
|
+
// Merge in any missing default environments (but don't overwrite user-modified defaults)
|
|
912
|
+
let updated = false;
|
|
913
|
+
const mergedEnvs = { ...envs };
|
|
914
|
+
for (const [name, defaultEnv] of Object.entries(DEFAULT_ENVIRONMENTS)) {
|
|
915
|
+
if (!mergedEnvs[name]) {
|
|
916
|
+
// Add missing environment
|
|
917
|
+
mergedEnvs[name] = defaultEnv;
|
|
918
|
+
updated = true;
|
|
919
|
+
}
|
|
920
|
+
// Don't overwrite existing environments - user may have modified them
|
|
921
|
+
// Only add missing ones, never overwrite existing ones
|
|
922
|
+
}
|
|
923
|
+
if (updated) {
|
|
924
|
+
this.set("environments", mergedEnvs);
|
|
925
|
+
}
|
|
926
|
+
return mergedEnvs;
|
|
688
927
|
}
|
|
689
928
|
getCurrentEnvironment() {
|
|
690
929
|
return this.get("environment");
|
|
@@ -704,8 +943,10 @@ export class ConfigManager {
|
|
|
704
943
|
// Update agentUrl and network from environment
|
|
705
944
|
this.set("agentUrl", env.agentUrl);
|
|
706
945
|
this.set("network", env.network);
|
|
946
|
+
// Clear agent info cache since we switched environments
|
|
947
|
+
this.clearAgentInfoCache();
|
|
707
948
|
}
|
|
708
|
-
addEnvironment(name, agentUrl, network = "eip155:
|
|
949
|
+
addEnvironment(name, agentUrl, network = "eip155:8453") {
|
|
709
950
|
const envs = this.getEnvironments();
|
|
710
951
|
if (envs[name]) {
|
|
711
952
|
throw new Error(`Environment "${name}" already exists. Use a different name.`);
|
|
@@ -717,7 +958,7 @@ export class ConfigManager {
|
|
|
717
958
|
};
|
|
718
959
|
this.set("environments", envs);
|
|
719
960
|
}
|
|
720
|
-
updateEnvironment(name, agentUrl, network = "eip155:
|
|
961
|
+
updateEnvironment(name, agentUrl, network = "eip155:8453") {
|
|
721
962
|
const envs = this.getEnvironments();
|
|
722
963
|
if (!envs[name]) {
|
|
723
964
|
throw new Error(`Environment "${name}" does not exist. Use "httpcat env add" to create it.`);
|
|
@@ -752,6 +993,73 @@ export class ConfigManager {
|
|
|
752
993
|
}
|
|
753
994
|
return this.get("rpcUrl");
|
|
754
995
|
}
|
|
996
|
+
getAlchemyApiKey() {
|
|
997
|
+
// Priority: Env var > Config
|
|
998
|
+
const envKey = process.env.HTTPCAT_ALCHEMY_API_KEY;
|
|
999
|
+
if (envKey) {
|
|
1000
|
+
return envKey;
|
|
1001
|
+
}
|
|
1002
|
+
return this.get("alchemyApiKey");
|
|
1003
|
+
}
|
|
1004
|
+
/**
|
|
1005
|
+
* Get public RPC URL for a given chain ID
|
|
1006
|
+
*/
|
|
1007
|
+
getPublicRpcUrl(chainId) {
|
|
1008
|
+
switch (chainId) {
|
|
1009
|
+
case 84532: // Base Sepolia
|
|
1010
|
+
return "https://sepolia.base.org";
|
|
1011
|
+
case 8453: // Base Mainnet
|
|
1012
|
+
return "https://mainnet.base.org";
|
|
1013
|
+
default:
|
|
1014
|
+
throw new Error(`Unsupported chain ID for public RPC: ${chainId}`);
|
|
1015
|
+
}
|
|
1016
|
+
}
|
|
1017
|
+
/**
|
|
1018
|
+
* Get Alchemy RPC URL for a given chain ID and API key
|
|
1019
|
+
*/
|
|
1020
|
+
getAlchemyRpcUrl(chainId, apiKey) {
|
|
1021
|
+
switch (chainId) {
|
|
1022
|
+
case 84532: // Base Sepolia
|
|
1023
|
+
return `https://base-sepolia.g.alchemy.com/v2/${apiKey}`;
|
|
1024
|
+
case 8453: // Base Mainnet
|
|
1025
|
+
return `https://base-mainnet.g.alchemy.com/v2/${apiKey}`;
|
|
1026
|
+
default:
|
|
1027
|
+
throw new Error(`Unsupported chain ID for Alchemy RPC: ${chainId}`);
|
|
1028
|
+
}
|
|
1029
|
+
}
|
|
1030
|
+
getPlatformTokenAddress() {
|
|
1031
|
+
// Get the CAT platform token address from environment variable
|
|
1032
|
+
return process.env.HTTPCAT_PLATFORM_TOKEN_ADDRESS;
|
|
1033
|
+
}
|
|
1034
|
+
/**
|
|
1035
|
+
* Fetch and cache agent info from the /info endpoint
|
|
1036
|
+
* Returns cached data if available and not expired
|
|
1037
|
+
*/
|
|
1038
|
+
async getAgentInfo() {
|
|
1039
|
+
// Check if cached data is still valid
|
|
1040
|
+
if (this.agentInfoCache) {
|
|
1041
|
+
const age = Date.now() - this.agentInfoCache.timestamp;
|
|
1042
|
+
if (age < this.AGENT_INFO_CACHE_TTL) {
|
|
1043
|
+
return this.agentInfoCache.data;
|
|
1044
|
+
}
|
|
1045
|
+
}
|
|
1046
|
+
// Fetch fresh data
|
|
1047
|
+
const agentUrl = this.getAgentUrl();
|
|
1048
|
+
const { fetchAgentInfo } = await import("./types/agent-info.js");
|
|
1049
|
+
const data = await fetchAgentInfo(agentUrl);
|
|
1050
|
+
// Cache the data
|
|
1051
|
+
this.agentInfoCache = {
|
|
1052
|
+
data,
|
|
1053
|
+
timestamp: Date.now(),
|
|
1054
|
+
};
|
|
1055
|
+
return data;
|
|
1056
|
+
}
|
|
1057
|
+
/**
|
|
1058
|
+
* Clear the agent info cache (useful when switching environments)
|
|
1059
|
+
*/
|
|
1060
|
+
clearAgentInfoCache() {
|
|
1061
|
+
this.agentInfoCache = null;
|
|
1062
|
+
}
|
|
755
1063
|
/**
|
|
756
1064
|
* AI Agent configuration methods
|
|
757
1065
|
*/
|
|
@@ -789,7 +1097,8 @@ export class ConfigManager {
|
|
|
789
1097
|
// OpenAI keys can start with "sk-" (legacy) or "sk-proj-" (newer project keys)
|
|
790
1098
|
// Newer keys are much longer, so we just check prefix and minimum length
|
|
791
1099
|
const trimmed = apiKey.trim();
|
|
792
|
-
return (trimmed.startsWith("sk-") || trimmed.startsWith("sk-proj-")) &&
|
|
1100
|
+
return ((trimmed.startsWith("sk-") || trimmed.startsWith("sk-proj-")) &&
|
|
1101
|
+
trimmed.length >= 20);
|
|
793
1102
|
}
|
|
794
1103
|
/**
|
|
795
1104
|
* Validate Anthropic API key format
|
|
@@ -824,11 +1133,13 @@ export class ConfigManager {
|
|
|
824
1133
|
apiKey = apiKey.trim();
|
|
825
1134
|
// Validate API key format based on provider
|
|
826
1135
|
if (apiKey && agentConfig.provider) {
|
|
827
|
-
if (agentConfig.provider === "openai" &&
|
|
1136
|
+
if (agentConfig.provider === "openai" &&
|
|
1137
|
+
!this.validateOpenAIApiKey(apiKey)) {
|
|
828
1138
|
throw new Error("Invalid OpenAI API key format. OpenAI keys should start with 'sk-'. " +
|
|
829
1139
|
"Please run 'agent --setup' (or 'cat --setup') to reconfigure your API key.");
|
|
830
1140
|
}
|
|
831
|
-
if (agentConfig.provider === "anthropic" &&
|
|
1141
|
+
if (agentConfig.provider === "anthropic" &&
|
|
1142
|
+
!this.validateAnthropicApiKey(apiKey)) {
|
|
832
1143
|
throw new Error("Invalid Anthropic API key format. Anthropic keys should start with 'sk-ant-'. " +
|
|
833
1144
|
"Please run 'agent --setup' (or 'cat --setup') to reconfigure your API key.");
|
|
834
1145
|
}
|