@aiaiaichain/agent 0.1.4 → 0.1.6

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.
Files changed (59) hide show
  1. package/dist/cli.js +224 -9
  2. package/dist/core/ChainConfig.js +1 -1
  3. package/dist/core/SystemMonitor.d.ts +1 -4
  4. package/dist/core/SystemMonitor.js +20 -46
  5. package/dist/index.d.ts +10 -0
  6. package/dist/index.js +11 -0
  7. package/dist/models/ModelRegistry.js +12 -4
  8. package/dist/runner/AgentRunner.d.ts +2 -0
  9. package/dist/runner/AgentRunner.js +18 -1
  10. package/dist/runner/ModelClient.js +109 -48
  11. package/dist/session/SessionManager.d.ts +1 -0
  12. package/dist/session/SessionManager.js +8 -2
  13. package/dist/session/SessionStore.js +8 -3
  14. package/dist/tools/CrossTools.js +13 -5
  15. package/dist/tools/MarketSentiment.js +22 -13
  16. package/dist/tools/NewsSentiment.js +9 -3
  17. package/dist/tools/PriceFeed.js +11 -4
  18. package/dist/tools/TechnicalAnalysis.js +2 -1
  19. package/dist/tools/TokenCalendar.d.ts +24 -0
  20. package/dist/tools/TokenCalendar.js +81 -0
  21. package/dist/tools/TokenSecurityScanner.d.ts +22 -0
  22. package/dist/tools/TokenSecurityScanner.js +102 -0
  23. package/dist/tools/TransactionSim.d.ts +17 -0
  24. package/dist/tools/TransactionSim.js +78 -0
  25. package/dist/tui/App.js +145 -23
  26. package/dist/tui/REPL.js +2 -2
  27. package/dist/tui/Sparkline.d.ts +21 -0
  28. package/dist/tui/Sparkline.js +44 -0
  29. package/dist/tui/ThemePresets.d.ts +25 -0
  30. package/dist/tui/ThemePresets.js +117 -0
  31. package/dist/util/clipboard.d.ts +9 -0
  32. package/dist/util/clipboard.js +26 -0
  33. package/dist/util/commandSuggest.d.ts +7 -0
  34. package/dist/util/commandSuggest.js +44 -0
  35. package/dist/util/confirmation.d.ts +6 -0
  36. package/dist/util/confirmation.js +16 -0
  37. package/dist/util/errorHandler.d.ts +3 -0
  38. package/dist/util/errorHandler.js +28 -0
  39. package/dist/util/logger.d.ts +11 -0
  40. package/dist/util/logger.js +43 -0
  41. package/dist/util/processManager.d.ts +5 -0
  42. package/dist/util/processManager.js +39 -0
  43. package/dist/util/resilientFetch.d.ts +21 -0
  44. package/dist/util/resilientFetch.js +94 -0
  45. package/dist/util/responseCache.d.ts +27 -0
  46. package/dist/util/responseCache.js +54 -0
  47. package/dist/util/safeLog.d.ts +4 -5
  48. package/dist/util/safeLog.js +68 -30
  49. package/dist/util/scheduler.d.ts +14 -0
  50. package/dist/util/scheduler.js +75 -0
  51. package/dist/util/webhooks.d.ts +9 -0
  52. package/dist/util/webhooks.js +75 -0
  53. package/dist/wallet/ActionFeed.d.ts +3 -2
  54. package/dist/wallet/ActionFeed.js +97 -76
  55. package/dist/wallet/AgentWallet.d.ts +6 -2
  56. package/dist/wallet/AgentWallet.js +59 -27
  57. package/dist/wallet/ProfitTracker.d.ts +30 -0
  58. package/dist/wallet/ProfitTracker.js +93 -0
  59. package/package.json +2 -2
@@ -0,0 +1,117 @@
1
+ /**
2
+ * src/tui/ThemePresets.ts — Theme presets system for AIAIAI TUI.
3
+ * 5 built-in presets + custom via ~/.aiaiai/config/theme.json
4
+ */
5
+ import { existsSync, readFileSync } from "node:fs";
6
+ import { join } from "node:path";
7
+ import { homedir } from "node:os";
8
+ const AIAIAI_HOME = process.env.AIAIAI_HOME ?? join(homedir(), ".aiaiai");
9
+ export const PRESETS = {
10
+ "solana": {
11
+ name: "Solana Sunset",
12
+ description: "Warm gradients inspired by the Solana blockchain colors",
13
+ colors: {
14
+ accent: "#9945FF",
15
+ header: "#14F195",
16
+ muted: "#888888",
17
+ dim: "#444444",
18
+ success: "#14F195",
19
+ warn: "#FFD600",
20
+ error: "#FF4444",
21
+ background: "#111111",
22
+ },
23
+ },
24
+ "cyberpunk": {
25
+ name: "Cyberpunk",
26
+ description: "Neon pink and cyan — late night trading terminal",
27
+ colors: {
28
+ accent: "#FF00FF",
29
+ header: "#00FFFF",
30
+ muted: "#666666",
31
+ dim: "#333333",
32
+ success: "#00FF44",
33
+ warn: "#FFFF00",
34
+ error: "#FF0044",
35
+ background: "#0A0A0A",
36
+ },
37
+ },
38
+ "monochrome": {
39
+ name: "Monochrome",
40
+ description: "Clean grayscale — professional trading desk",
41
+ colors: {
42
+ accent: "#FFFFFF",
43
+ header: "#DDDDDD",
44
+ muted: "#888888",
45
+ dim: "#444444",
46
+ success: "#CCCCCC",
47
+ warn: "#999999",
48
+ error: "#FF4444",
49
+ background: "#111111",
50
+ },
51
+ },
52
+ "forest": {
53
+ name: "Forest",
54
+ description: "Calm greens — for zen trading sessions",
55
+ colors: {
56
+ accent: "#50FA7B",
57
+ header: "#7BFA50",
58
+ muted: "#6272A4",
59
+ dim: "#44475A",
60
+ success: "#50FA7B",
61
+ warn: "#F1FA8C",
62
+ error: "#FF5555",
63
+ background: "#1A2D1A",
64
+ },
65
+ },
66
+ "ocean": {
67
+ name: "Ocean",
68
+ description: "Deep blues — data-rich dashboard feel",
69
+ colors: {
70
+ accent: "#8BE9FD",
71
+ header: "#6272A4",
72
+ muted: "#6272A4",
73
+ dim: "#44475A",
74
+ success: "#50FA7B",
75
+ warn: "#F1FA8C",
76
+ error: "#FF5555",
77
+ background: "#0D1B2A",
78
+ },
79
+ },
80
+ };
81
+ export function getCurrentTheme() {
82
+ const configPath = join(AIAIAI_HOME, "config", "theme.json");
83
+ try {
84
+ if (existsSync(configPath)) {
85
+ const raw = readFileSync(configPath, "utf-8");
86
+ const config = JSON.parse(raw);
87
+ return config.theme || "solana";
88
+ }
89
+ }
90
+ catch { /* use default */ }
91
+ return "solana";
92
+ }
93
+ export function setTheme(name) {
94
+ const preset = PRESETS[name];
95
+ if (!preset)
96
+ return false;
97
+ const configDir = join(AIAIAI_HOME, "config");
98
+ const configPath = join(configDir, "theme.json");
99
+ try {
100
+ const { mkdirSync, writeFileSync } = require("node:fs");
101
+ if (!existsSync(configDir))
102
+ mkdirSync(configDir, { recursive: true });
103
+ writeFileSync(configPath, JSON.stringify({ theme: name, colors: preset.colors }, null, 2), "utf-8");
104
+ return true;
105
+ }
106
+ catch {
107
+ return false;
108
+ }
109
+ }
110
+ export function getPresetColors() {
111
+ const themeName = getCurrentTheme();
112
+ return PRESETS[themeName]?.colors ?? PRESETS["solana"].colors;
113
+ }
114
+ export function listThemes() {
115
+ return Object.entries(PRESETS).map(([key, preset]) => ` ${key === getCurrentTheme() ? "★" : " "} ${key.padEnd(14)} ${preset.description}`).join("\n");
116
+ }
117
+ //# sourceMappingURL=ThemePresets.js.map
@@ -0,0 +1,9 @@
1
+ /**
2
+ * src/util/clipboard.ts — Copy text to system clipboard via OSC 52 escape sequences.
3
+ * Works in most modern terminals: iTerm2, Terminal.app, kitty, WezTerm, Alacritty.
4
+ */
5
+ export declare function encodeOSC52(text: string): string;
6
+ export declare function copyToClipboard(text: string): boolean;
7
+ /** Get a friendly message indicating clipboard support */
8
+ export declare function clipboardSupported(): string;
9
+ //# sourceMappingURL=clipboard.d.ts.map
@@ -0,0 +1,26 @@
1
+ /**
2
+ * src/util/clipboard.ts — Copy text to system clipboard via OSC 52 escape sequences.
3
+ * Works in most modern terminals: iTerm2, Terminal.app, kitty, WezTerm, Alacritty.
4
+ */
5
+ export function encodeOSC52(text) {
6
+ const encoded = Buffer.from(text).toString("base64");
7
+ return `\x1b]52;c;${encoded}\x07`;
8
+ }
9
+ export function copyToClipboard(text) {
10
+ try {
11
+ process.stdout.write(encodeOSC52(text));
12
+ return true;
13
+ }
14
+ catch {
15
+ return false;
16
+ }
17
+ }
18
+ /** Get a friendly message indicating clipboard support */
19
+ export function clipboardSupported() {
20
+ const term = process.env.TERM_PROGRAM ?? "";
21
+ const isTerminalApp = process.env.TERM?.includes("xterm") || term.includes("iTerm") || term.includes("kitty") || term.includes("Wez") || term.includes("Alacritty") || term.includes("Terminal");
22
+ if (isTerminalApp)
23
+ return "✅ Clipboard ready (OSC 52)";
24
+ return "⚠️ Clipboard may not be supported in this terminal";
25
+ }
26
+ //# sourceMappingURL=clipboard.js.map
@@ -0,0 +1,7 @@
1
+ /**
2
+ * src/util/commandSuggest.ts — Levenshtein-based command suggestions.
3
+ * When a user types an unknown command, suggest the closest match.
4
+ */
5
+ export declare function levenshtein(a: string, b: string): number;
6
+ export declare function suggestCommands(input: string, maxResults?: number): string[];
7
+ //# sourceMappingURL=commandSuggest.d.ts.map
@@ -0,0 +1,44 @@
1
+ /**
2
+ * src/util/commandSuggest.ts — Levenshtein-based command suggestions.
3
+ * When a user types an unknown command, suggest the closest match.
4
+ */
5
+ const COMMANDS = [
6
+ "help", "exit", "quit", "clear",
7
+ "price", "news", "models", "cost", "model",
8
+ "wallet", "deposit", "burn", "actions", "activity", "fees",
9
+ "keys", "providers", "goals", "goal add", "goal done",
10
+ "schedule", "sessions", "resume", "memory", "update", "gmgn",
11
+ "token info", "token security", "token holders", "token traders",
12
+ "track kol", "track smartmoney", "track follow-wallet",
13
+ "market kline", "market trending", "market trenches", "market signal",
14
+ "watch", "unwatch", "watchlist", "alerts", "alert", "compare", "portfolio",
15
+ "diff", "explain", "copy", "theme", "status",
16
+ ];
17
+ export function levenshtein(a, b) {
18
+ const alen = a.length, blen = b.length;
19
+ const matrix = [];
20
+ for (let i = 0; i <= alen; i++) {
21
+ matrix[i] = [i];
22
+ }
23
+ for (let j = 0; j <= blen; j++) {
24
+ matrix[0][j] = j;
25
+ }
26
+ for (let i = 1; i <= alen; i++) {
27
+ for (let j = 1; j <= blen; j++) {
28
+ matrix[i][j] = Math.min(matrix[i - 1][j] + 1, matrix[i][j - 1] + 1, matrix[i - 1][j - 1] + (a[i - 1] === b[j - 1] ? 0 : 1));
29
+ }
30
+ }
31
+ return matrix[alen][blen];
32
+ }
33
+ export function suggestCommands(input, maxResults = 3) {
34
+ const normalized = input.toLowerCase().replace(/^\/+/, "");
35
+ if (!normalized || normalized.length < 1)
36
+ return [];
37
+ const scored = COMMANDS.map(cmd => ({
38
+ cmd,
39
+ dist: levenshtein(normalized, cmd),
40
+ }));
41
+ scored.sort((a, b) => a.dist - b.dist);
42
+ return scored.slice(0, maxResults).filter(s => s.dist <= 4).map(s => s.cmd);
43
+ }
44
+ //# sourceMappingURL=commandSuggest.js.map
@@ -0,0 +1,6 @@
1
+ /**
2
+ * src/util/confirmation.ts — Confirmation prompt for destructive operations
3
+ */
4
+ export declare function requireConfirmation(message: string): Promise<boolean>;
5
+ export declare function isNonInteractive(): boolean;
6
+ //# sourceMappingURL=confirmation.d.ts.map
@@ -0,0 +1,16 @@
1
+ /**
2
+ * src/util/confirmation.ts — Confirmation prompt for destructive operations
3
+ */
4
+ import { createInterface } from "node:readline";
5
+ export async function requireConfirmation(message) {
6
+ const rl = createInterface({ input: process.stdin, output: process.stdout });
7
+ const answer = await new Promise((res) => {
8
+ rl.question(`${message} (yes/no): `, res);
9
+ });
10
+ rl.close();
11
+ return answer.trim().toLowerCase() === "yes" || answer.trim().toLowerCase() === "y";
12
+ }
13
+ export function isNonInteractive() {
14
+ return !process.stdin.isTTY || process.env.AIAIAI_YES === "1" || process.env.CI === "true";
15
+ }
16
+ //# sourceMappingURL=confirmation.js.map
@@ -0,0 +1,3 @@
1
+ export declare function withErrorHandling<T>(operation: () => Promise<T>, context: string): Promise<T>;
2
+ export declare function setupGlobalErrorHandlers(): void;
3
+ //# sourceMappingURL=errorHandler.d.ts.map
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Global error handling utilities for AIAIAI agent
3
+ */
4
+ import { safeLog } from "./safeLog.js";
5
+ // Generic error handler to wrap async operations
6
+ export function withErrorHandling(operation, context) {
7
+ return operation().catch((error) => {
8
+ const errorMessage = error instanceof Error ? error.message : String(error);
9
+ safeLog(`[${context}] ERROR: ${errorMessage}`);
10
+ if (error instanceof Error) {
11
+ safeLog(`Stack trace: ${error.stack}`);
12
+ }
13
+ throw error; // Re-throw to maintain expected behavior
14
+ });
15
+ }
16
+ // Enhanced logging for unhandled promise rejections
17
+ export function setupGlobalErrorHandlers() {
18
+ process.on('unhandledRejection', (reason, promise) => {
19
+ console.error('[UNHANDLED_REJECTION] Reason:', reason);
20
+ console.error('[PROMISE]', promise);
21
+ process.exit(1);
22
+ });
23
+ process.on('uncaughtException', (error) => {
24
+ console.error('[UNCAUGHT_EXCEPTION]', error);
25
+ process.exit(1);
26
+ });
27
+ }
28
+ //# sourceMappingURL=errorHandler.js.map
@@ -0,0 +1,11 @@
1
+ /**
2
+ * src/util/logger.ts — Structured logging with levels for AIAIAI Agent
3
+ */
4
+ export type LogLevel = 'debug' | 'info' | 'warn' | 'error';
5
+ export declare const logger: {
6
+ debug(context: string, message: string, meta?: unknown): void;
7
+ info(context: string, message: string, meta?: unknown): void;
8
+ warn(context: string, message: string, meta?: unknown): void;
9
+ error(context: string, message: string, meta?: unknown): void;
10
+ };
11
+ //# sourceMappingURL=logger.d.ts.map
@@ -0,0 +1,43 @@
1
+ /**
2
+ * src/util/logger.ts — Structured logging with levels for AIAIAI Agent
3
+ */
4
+ const LEVEL_PRIORITY = {
5
+ debug: 0,
6
+ info: 1,
7
+ warn: 2,
8
+ error: 3,
9
+ };
10
+ function getMinLevel() {
11
+ const env = process.env.AIAIAI_LOG_LEVEL?.toLowerCase();
12
+ if (env && env in LEVEL_PRIORITY)
13
+ return env;
14
+ return 'info';
15
+ }
16
+ function shouldLog(level) {
17
+ return LEVEL_PRIORITY[level] >= LEVEL_PRIORITY[getMinLevel()];
18
+ }
19
+ function formatMessage(level, context, message, meta) {
20
+ const ts = new Date().toISOString();
21
+ const prefix = `[${ts}] [${level.toUpperCase()}] [${context}]`;
22
+ const metaStr = meta ? ` ${JSON.stringify(meta)}` : '';
23
+ return `${prefix} ${message}${metaStr}`;
24
+ }
25
+ export const logger = {
26
+ debug(context, message, meta) {
27
+ if (shouldLog('debug'))
28
+ console.error(formatMessage('debug', context, message, meta));
29
+ },
30
+ info(context, message, meta) {
31
+ if (shouldLog('info'))
32
+ console.error(formatMessage('info', context, message, meta));
33
+ },
34
+ warn(context, message, meta) {
35
+ if (shouldLog('warn'))
36
+ console.error(formatMessage('warn', context, message, meta));
37
+ },
38
+ error(context, message, meta) {
39
+ if (shouldLog('error'))
40
+ console.error(formatMessage('error', context, message, meta));
41
+ },
42
+ };
43
+ //# sourceMappingURL=logger.js.map
@@ -0,0 +1,5 @@
1
+ export declare class ProcessManager {
2
+ static setupGlobalHandlers(): void;
3
+ static shutdown(exitCode: number): void;
4
+ }
5
+ //# sourceMappingURL=processManager.d.ts.map
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Process management utilities for AIAIAI Agent
3
+ */
4
+ import { safeLog } from "./safeLog.js";
5
+ export class ProcessManager {
6
+ static setupGlobalHandlers() {
7
+ // Handle uncaught exceptions
8
+ process.on('uncaughtException', (error) => {
9
+ safeLog('[UNCAUGHT_EXCEPTION] ' + error.message);
10
+ if (error.stack) {
11
+ safeLog('[STACK_TRACE] ' + error.stack);
12
+ }
13
+ // Gracefully shutdown
14
+ this.shutdown(1);
15
+ });
16
+ // Handle unhandled promises
17
+ process.on('unhandledRejection', (reason, promise) => {
18
+ safeLog('[UNHANDLED_REJECTION] ' + reason?.message || String(reason));
19
+ // Attempt graceful shutdown
20
+ this.shutdown(1);
21
+ });
22
+ // Handle graceful shutdown signals
23
+ process.on('SIGTERM', () => {
24
+ safeLog('[SIGTERM] Received shutdown signal');
25
+ this.shutdown(0);
26
+ });
27
+ process.on('SIGINT', () => {
28
+ safeLog('[SIGINT] Received shutdown signal');
29
+ this.shutdown(0);
30
+ });
31
+ }
32
+ static shutdown(exitCode) {
33
+ // Allow cleanup time
34
+ setTimeout(() => {
35
+ process.exit(exitCode);
36
+ }, 100);
37
+ }
38
+ }
39
+ //# sourceMappingURL=processManager.js.map
@@ -0,0 +1,21 @@
1
+ /**
2
+ * src/util/resilientFetch.ts - Resilient HTTP client with timeout, retry, circuit breaker
3
+ */
4
+ export interface FetchOptions {
5
+ timeout?: number;
6
+ retries?: number;
7
+ backoffMs?: number;
8
+ onRetry?: (attempt: number, error: Error) => void;
9
+ method?: string;
10
+ headers?: Record<string, string>;
11
+ body?: string;
12
+ signal?: AbortSignal;
13
+ }
14
+ export interface CircuitState {
15
+ failures: number;
16
+ lastFailureTime: number;
17
+ state: "closed" | "open" | "half-open";
18
+ }
19
+ export declare function resilientFetch(url: string, options?: FetchOptions): Promise<Response>;
20
+ export declare function isReachable(url: string, timeout?: number): Promise<boolean>;
21
+ //# sourceMappingURL=resilientFetch.d.ts.map
@@ -0,0 +1,94 @@
1
+ /**
2
+ * src/util/resilientFetch.ts - Resilient HTTP client with timeout, retry, circuit breaker
3
+ */
4
+ const circuits = new Map();
5
+ const CIRCUIT_THRESHOLD = 3;
6
+ const CIRCUIT_RESET_MS = 60_000;
7
+ function getCircuit(key) {
8
+ let c = circuits.get(key);
9
+ if (!c) {
10
+ c = { failures: 0, lastFailureTime: 0, state: "closed" };
11
+ circuits.set(key, c);
12
+ }
13
+ return c;
14
+ }
15
+ function canExecute(key) {
16
+ const c = getCircuit(key);
17
+ if (c.state === "closed")
18
+ return true;
19
+ if (c.state === "open" && Date.now() - c.lastFailureTime > CIRCUIT_RESET_MS) {
20
+ c.state = "half-open";
21
+ return true;
22
+ }
23
+ return c.state === "half-open";
24
+ }
25
+ function recordSuccess(key) {
26
+ const c = getCircuit(key);
27
+ c.failures = 0;
28
+ c.state = "closed";
29
+ }
30
+ function recordFailure(key) {
31
+ const c = getCircuit(key);
32
+ c.failures++;
33
+ c.lastFailureTime = Date.now();
34
+ if (c.failures >= CIRCUIT_THRESHOLD) {
35
+ c.state = "open";
36
+ }
37
+ }
38
+ export async function resilientFetch(url, options = {}) {
39
+ const { timeout = 8_000, retries = 2, backoffMs = 1_000, onRetry, method = "GET", headers, body, signal: externalSignal, } = options;
40
+ const circuitKey = new URL(url).hostname;
41
+ if (!canExecute(circuitKey)) {
42
+ throw new Error("Circuit open for " + circuitKey + " - service unavailable, retry later");
43
+ }
44
+ let lastError = null;
45
+ for (let attempt = 0; attempt <= retries; attempt++) {
46
+ const controller = new AbortController();
47
+ const timer = setTimeout(() => controller.abort(), timeout);
48
+ // Combine external abort signal with timeout
49
+ if (externalSignal) {
50
+ if (externalSignal.aborted)
51
+ controller.abort();
52
+ else
53
+ externalSignal.addEventListener("abort", () => controller.abort(), { once: true });
54
+ }
55
+ try {
56
+ const response = await fetch(url, {
57
+ signal: controller.signal,
58
+ method,
59
+ headers,
60
+ body,
61
+ });
62
+ clearTimeout(timer);
63
+ if (!response.ok) {
64
+ throw new Error("HTTP " + response.status + ": " + response.statusText);
65
+ }
66
+ recordSuccess(circuitKey);
67
+ return response;
68
+ }
69
+ catch (error) {
70
+ clearTimeout(timer);
71
+ lastError = error instanceof Error ? error : new Error(String(error));
72
+ if (attempt < retries) {
73
+ onRetry?.(attempt + 1, lastError);
74
+ const delay = backoffMs * Math.pow(2, attempt);
75
+ await new Promise((r) => setTimeout(r, delay));
76
+ }
77
+ }
78
+ }
79
+ recordFailure(circuitKey);
80
+ throw lastError;
81
+ }
82
+ export async function isReachable(url, timeout = 5_000) {
83
+ try {
84
+ const controller = new AbortController();
85
+ const timer = setTimeout(() => controller.abort(), timeout);
86
+ const res = await fetch(url, { signal: controller.signal });
87
+ clearTimeout(timer);
88
+ return res.ok;
89
+ }
90
+ catch {
91
+ return false;
92
+ }
93
+ }
94
+ //# sourceMappingURL=resilientFetch.js.map
@@ -0,0 +1,27 @@
1
+ /**
2
+ * src/util/responseCache.ts — TTL-based response cache for external APIs
3
+ */
4
+ /**
5
+ * Get cached value or undefined if expired/missing.
6
+ */
7
+ export declare function getCached<T>(key: string): T | undefined;
8
+ /**
9
+ * Set value in cache with TTL (default 60s).
10
+ */
11
+ export declare function setCache<T>(key: string, data: T, ttlMs?: number): void;
12
+ /**
13
+ * Get or compute: return cached value, or compute, cache, and return.
14
+ */
15
+ export declare function getOrCompute<T>(key: string, compute: () => Promise<T>, ttlMs?: number): Promise<T>;
16
+ /**
17
+ * Clear all cached values.
18
+ */
19
+ export declare function clearCache(): void;
20
+ /**
21
+ * Get cache stats for diagnostics.
22
+ */
23
+ export declare function cacheStats(): {
24
+ size: number;
25
+ entries: string[];
26
+ };
27
+ //# sourceMappingURL=responseCache.d.ts.map
@@ -0,0 +1,54 @@
1
+ /**
2
+ * src/util/responseCache.ts — TTL-based response cache for external APIs
3
+ */
4
+ const cache = new Map();
5
+ const DEFAULT_TTL_MS = 60_000;
6
+ /**
7
+ * Get cached value or undefined if expired/missing.
8
+ */
9
+ export function getCached(key) {
10
+ const entry = cache.get(key);
11
+ if (!entry)
12
+ return undefined;
13
+ if (Date.now() > entry.expiresAt) {
14
+ cache.delete(key);
15
+ return undefined;
16
+ }
17
+ return entry.data;
18
+ }
19
+ /**
20
+ * Set value in cache with TTL (default 60s).
21
+ */
22
+ export function setCache(key, data, ttlMs = DEFAULT_TTL_MS) {
23
+ cache.set(key, { data, expiresAt: Date.now() + ttlMs });
24
+ // Evict oldest if cache grows too large
25
+ if (cache.size > 200) {
26
+ const firstKey = cache.keys().next().value;
27
+ if (firstKey)
28
+ cache.delete(firstKey);
29
+ }
30
+ }
31
+ /**
32
+ * Get or compute: return cached value, or compute, cache, and return.
33
+ */
34
+ export async function getOrCompute(key, compute, ttlMs = DEFAULT_TTL_MS) {
35
+ const cached = getCached(key);
36
+ if (cached !== undefined)
37
+ return cached;
38
+ const result = await compute();
39
+ setCache(key, result, ttlMs);
40
+ return result;
41
+ }
42
+ /**
43
+ * Clear all cached values.
44
+ */
45
+ export function clearCache() {
46
+ cache.clear();
47
+ }
48
+ /**
49
+ * Get cache stats for diagnostics.
50
+ */
51
+ export function cacheStats() {
52
+ return { size: cache.size, entries: [...cache.keys()] };
53
+ }
54
+ //# sourceMappingURL=responseCache.js.map
@@ -1,8 +1,7 @@
1
1
  /**
2
- * safeLog — wraps console.log/error/warn to avoid corrupting Ink TUI output.
2
+ * src/util/safeLog.tsIntercepts console output, masks secrets, routes to file
3
3
  */
4
- export declare function wireNotify(fn: (msg: string) => void): void;
5
- declare function safeLogFn(...args: unknown[]): void;
6
- export declare const safeLog: typeof safeLogFn;
7
- export {};
4
+ export declare function wireNotify(fn?: (msg: string) => void): void;
5
+ export declare function safeLog(...args: unknown[]): void;
6
+ export declare function installSafeLogging(): void;
8
7
  //# sourceMappingURL=safeLog.d.ts.map