whale-code 6.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +95 -0
- package/bin/swag-agent.js +9 -0
- package/bin/swagmanager-mcp.js +321 -0
- package/dist/cli/app.d.ts +26 -0
- package/dist/cli/app.js +64 -0
- package/dist/cli/chat/AgentSelector.d.ts +14 -0
- package/dist/cli/chat/AgentSelector.js +14 -0
- package/dist/cli/chat/ChatApp.d.ts +9 -0
- package/dist/cli/chat/ChatApp.js +267 -0
- package/dist/cli/chat/ChatInput.d.ts +39 -0
- package/dist/cli/chat/ChatInput.js +509 -0
- package/dist/cli/chat/MarkdownText.d.ts +10 -0
- package/dist/cli/chat/MarkdownText.js +20 -0
- package/dist/cli/chat/MessageList.d.ts +37 -0
- package/dist/cli/chat/MessageList.js +80 -0
- package/dist/cli/chat/ModelSelector.d.ts +20 -0
- package/dist/cli/chat/ModelSelector.js +73 -0
- package/dist/cli/chat/RewindViewer.d.ts +26 -0
- package/dist/cli/chat/RewindViewer.js +185 -0
- package/dist/cli/chat/StoreSelector.d.ts +14 -0
- package/dist/cli/chat/StoreSelector.js +24 -0
- package/dist/cli/chat/StreamingText.d.ts +12 -0
- package/dist/cli/chat/StreamingText.js +12 -0
- package/dist/cli/chat/SubagentPanel.d.ts +45 -0
- package/dist/cli/chat/SubagentPanel.js +110 -0
- package/dist/cli/chat/TeamPanel.d.ts +21 -0
- package/dist/cli/chat/TeamPanel.js +42 -0
- package/dist/cli/chat/ToolIndicator.d.ts +25 -0
- package/dist/cli/chat/ToolIndicator.js +436 -0
- package/dist/cli/chat/hooks/useAgentLoop.d.ts +39 -0
- package/dist/cli/chat/hooks/useAgentLoop.js +382 -0
- package/dist/cli/chat/hooks/useSlashCommands.d.ts +37 -0
- package/dist/cli/chat/hooks/useSlashCommands.js +387 -0
- package/dist/cli/commands/config-cmd.d.ts +10 -0
- package/dist/cli/commands/config-cmd.js +99 -0
- package/dist/cli/commands/doctor.d.ts +14 -0
- package/dist/cli/commands/doctor.js +172 -0
- package/dist/cli/commands/init.d.ts +16 -0
- package/dist/cli/commands/init.js +278 -0
- package/dist/cli/commands/mcp.d.ts +12 -0
- package/dist/cli/commands/mcp.js +162 -0
- package/dist/cli/login/LoginApp.d.ts +7 -0
- package/dist/cli/login/LoginApp.js +157 -0
- package/dist/cli/print-mode.d.ts +31 -0
- package/dist/cli/print-mode.js +202 -0
- package/dist/cli/serve-mode.d.ts +37 -0
- package/dist/cli/serve-mode.js +636 -0
- package/dist/cli/services/agent-definitions.d.ts +25 -0
- package/dist/cli/services/agent-definitions.js +91 -0
- package/dist/cli/services/agent-events.d.ts +178 -0
- package/dist/cli/services/agent-events.js +175 -0
- package/dist/cli/services/agent-loop.d.ts +90 -0
- package/dist/cli/services/agent-loop.js +762 -0
- package/dist/cli/services/agent-worker-base.d.ts +97 -0
- package/dist/cli/services/agent-worker-base.js +220 -0
- package/dist/cli/services/auth-service.d.ts +30 -0
- package/dist/cli/services/auth-service.js +160 -0
- package/dist/cli/services/background-processes.d.ts +126 -0
- package/dist/cli/services/background-processes.js +318 -0
- package/dist/cli/services/browser-auth.d.ts +24 -0
- package/dist/cli/services/browser-auth.js +180 -0
- package/dist/cli/services/claude-md-loader.d.ts +16 -0
- package/dist/cli/services/claude-md-loader.js +58 -0
- package/dist/cli/services/config-store.d.ts +47 -0
- package/dist/cli/services/config-store.js +79 -0
- package/dist/cli/services/debug-log.d.ts +10 -0
- package/dist/cli/services/debug-log.js +52 -0
- package/dist/cli/services/error-logger.d.ts +58 -0
- package/dist/cli/services/error-logger.js +269 -0
- package/dist/cli/services/file-history.d.ts +21 -0
- package/dist/cli/services/file-history.js +83 -0
- package/dist/cli/services/format-server-response.d.ts +16 -0
- package/dist/cli/services/format-server-response.js +440 -0
- package/dist/cli/services/git-context.d.ts +11 -0
- package/dist/cli/services/git-context.js +66 -0
- package/dist/cli/services/hooks.d.ts +85 -0
- package/dist/cli/services/hooks.js +258 -0
- package/dist/cli/services/interactive-tools.d.ts +125 -0
- package/dist/cli/services/interactive-tools.js +260 -0
- package/dist/cli/services/keybinding-manager.d.ts +52 -0
- package/dist/cli/services/keybinding-manager.js +115 -0
- package/dist/cli/services/local-tools.d.ts +22 -0
- package/dist/cli/services/local-tools.js +697 -0
- package/dist/cli/services/lsp-manager.d.ts +18 -0
- package/dist/cli/services/lsp-manager.js +717 -0
- package/dist/cli/services/mcp-client.d.ts +48 -0
- package/dist/cli/services/mcp-client.js +157 -0
- package/dist/cli/services/memory-manager.d.ts +16 -0
- package/dist/cli/services/memory-manager.js +57 -0
- package/dist/cli/services/model-manager.d.ts +18 -0
- package/dist/cli/services/model-manager.js +71 -0
- package/dist/cli/services/model-router.d.ts +26 -0
- package/dist/cli/services/model-router.js +149 -0
- package/dist/cli/services/permission-modes.d.ts +13 -0
- package/dist/cli/services/permission-modes.js +43 -0
- package/dist/cli/services/rewind.d.ts +84 -0
- package/dist/cli/services/rewind.js +194 -0
- package/dist/cli/services/ripgrep.d.ts +28 -0
- package/dist/cli/services/ripgrep.js +138 -0
- package/dist/cli/services/sandbox.d.ts +29 -0
- package/dist/cli/services/sandbox.js +97 -0
- package/dist/cli/services/server-tools.d.ts +61 -0
- package/dist/cli/services/server-tools.js +543 -0
- package/dist/cli/services/session-persistence.d.ts +23 -0
- package/dist/cli/services/session-persistence.js +99 -0
- package/dist/cli/services/subagent-worker.d.ts +19 -0
- package/dist/cli/services/subagent-worker.js +41 -0
- package/dist/cli/services/subagent.d.ts +47 -0
- package/dist/cli/services/subagent.js +647 -0
- package/dist/cli/services/system-prompt.d.ts +7 -0
- package/dist/cli/services/system-prompt.js +198 -0
- package/dist/cli/services/team-lead.d.ts +73 -0
- package/dist/cli/services/team-lead.js +512 -0
- package/dist/cli/services/team-state.d.ts +77 -0
- package/dist/cli/services/team-state.js +398 -0
- package/dist/cli/services/teammate.d.ts +31 -0
- package/dist/cli/services/teammate.js +689 -0
- package/dist/cli/services/telemetry.d.ts +61 -0
- package/dist/cli/services/telemetry.js +209 -0
- package/dist/cli/services/tools/agent-tools.d.ts +14 -0
- package/dist/cli/services/tools/agent-tools.js +347 -0
- package/dist/cli/services/tools/file-ops.d.ts +15 -0
- package/dist/cli/services/tools/file-ops.js +487 -0
- package/dist/cli/services/tools/search-tools.d.ts +8 -0
- package/dist/cli/services/tools/search-tools.js +186 -0
- package/dist/cli/services/tools/shell-exec.d.ts +10 -0
- package/dist/cli/services/tools/shell-exec.js +168 -0
- package/dist/cli/services/tools/task-manager.d.ts +28 -0
- package/dist/cli/services/tools/task-manager.js +209 -0
- package/dist/cli/services/tools/web-tools.d.ts +11 -0
- package/dist/cli/services/tools/web-tools.js +395 -0
- package/dist/cli/setup/SetupApp.d.ts +9 -0
- package/dist/cli/setup/SetupApp.js +191 -0
- package/dist/cli/shared/MatrixIntro.d.ts +4 -0
- package/dist/cli/shared/MatrixIntro.js +83 -0
- package/dist/cli/shared/Theme.d.ts +74 -0
- package/dist/cli/shared/Theme.js +127 -0
- package/dist/cli/shared/WhaleBanner.d.ts +10 -0
- package/dist/cli/shared/WhaleBanner.js +12 -0
- package/dist/cli/shared/markdown.d.ts +21 -0
- package/dist/cli/shared/markdown.js +756 -0
- package/dist/cli/status/StatusApp.d.ts +4 -0
- package/dist/cli/status/StatusApp.js +105 -0
- package/dist/cli/stores/StoreApp.d.ts +7 -0
- package/dist/cli/stores/StoreApp.js +81 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.js +538 -0
- package/dist/local-agent/connection.d.ts +48 -0
- package/dist/local-agent/connection.js +332 -0
- package/dist/local-agent/discovery.d.ts +18 -0
- package/dist/local-agent/discovery.js +146 -0
- package/dist/local-agent/executor.d.ts +34 -0
- package/dist/local-agent/executor.js +241 -0
- package/dist/local-agent/index.d.ts +14 -0
- package/dist/local-agent/index.js +198 -0
- package/dist/node/adapters/base.d.ts +35 -0
- package/dist/node/adapters/base.js +10 -0
- package/dist/node/adapters/discord.d.ts +29 -0
- package/dist/node/adapters/discord.js +299 -0
- package/dist/node/adapters/email.d.ts +23 -0
- package/dist/node/adapters/email.js +218 -0
- package/dist/node/adapters/imessage.d.ts +17 -0
- package/dist/node/adapters/imessage.js +118 -0
- package/dist/node/adapters/slack.d.ts +26 -0
- package/dist/node/adapters/slack.js +259 -0
- package/dist/node/adapters/sms.d.ts +23 -0
- package/dist/node/adapters/sms.js +161 -0
- package/dist/node/adapters/telegram.d.ts +17 -0
- package/dist/node/adapters/telegram.js +101 -0
- package/dist/node/adapters/webchat.d.ts +27 -0
- package/dist/node/adapters/webchat.js +160 -0
- package/dist/node/adapters/whatsapp.d.ts +28 -0
- package/dist/node/adapters/whatsapp.js +230 -0
- package/dist/node/cli.d.ts +2 -0
- package/dist/node/cli.js +325 -0
- package/dist/node/config.d.ts +17 -0
- package/dist/node/config.js +31 -0
- package/dist/node/runtime.d.ts +50 -0
- package/dist/node/runtime.js +351 -0
- package/dist/server/handlers/__test-utils__/mock-supabase.d.ts +11 -0
- package/dist/server/handlers/__test-utils__/mock-supabase.js +393 -0
- package/dist/server/handlers/analytics.d.ts +17 -0
- package/dist/server/handlers/analytics.js +266 -0
- package/dist/server/handlers/api-keys.d.ts +6 -0
- package/dist/server/handlers/api-keys.js +221 -0
- package/dist/server/handlers/billing.d.ts +33 -0
- package/dist/server/handlers/billing.js +272 -0
- package/dist/server/handlers/browser.d.ts +10 -0
- package/dist/server/handlers/browser.js +517 -0
- package/dist/server/handlers/catalog.d.ts +99 -0
- package/dist/server/handlers/catalog.js +976 -0
- package/dist/server/handlers/comms.d.ts +254 -0
- package/dist/server/handlers/comms.js +588 -0
- package/dist/server/handlers/creations.d.ts +6 -0
- package/dist/server/handlers/creations.js +479 -0
- package/dist/server/handlers/crm.d.ts +89 -0
- package/dist/server/handlers/crm.js +538 -0
- package/dist/server/handlers/discovery.d.ts +6 -0
- package/dist/server/handlers/discovery.js +288 -0
- package/dist/server/handlers/embeddings.d.ts +92 -0
- package/dist/server/handlers/embeddings.js +197 -0
- package/dist/server/handlers/enrichment.d.ts +8 -0
- package/dist/server/handlers/enrichment.js +768 -0
- package/dist/server/handlers/image-gen.d.ts +6 -0
- package/dist/server/handlers/image-gen.js +409 -0
- package/dist/server/handlers/inventory.d.ts +319 -0
- package/dist/server/handlers/inventory.js +447 -0
- package/dist/server/handlers/kali.d.ts +10 -0
- package/dist/server/handlers/kali.js +210 -0
- package/dist/server/handlers/llm-providers.d.ts +6 -0
- package/dist/server/handlers/llm-providers.js +673 -0
- package/dist/server/handlers/local-agent.d.ts +6 -0
- package/dist/server/handlers/local-agent.js +118 -0
- package/dist/server/handlers/meta-ads.d.ts +111 -0
- package/dist/server/handlers/meta-ads.js +2279 -0
- package/dist/server/handlers/nodes.d.ts +33 -0
- package/dist/server/handlers/nodes.js +699 -0
- package/dist/server/handlers/operations.d.ts +138 -0
- package/dist/server/handlers/operations.js +131 -0
- package/dist/server/handlers/platform.d.ts +23 -0
- package/dist/server/handlers/platform.js +227 -0
- package/dist/server/handlers/supply-chain.d.ts +19 -0
- package/dist/server/handlers/supply-chain.js +327 -0
- package/dist/server/handlers/transcription.d.ts +17 -0
- package/dist/server/handlers/transcription.js +121 -0
- package/dist/server/handlers/video-gen.d.ts +6 -0
- package/dist/server/handlers/video-gen.js +466 -0
- package/dist/server/handlers/voice.d.ts +8 -0
- package/dist/server/handlers/voice.js +1146 -0
- package/dist/server/handlers/workflow-steps.d.ts +86 -0
- package/dist/server/handlers/workflow-steps.js +2349 -0
- package/dist/server/handlers/workflows.d.ts +7 -0
- package/dist/server/handlers/workflows.js +989 -0
- package/dist/server/index.d.ts +1 -0
- package/dist/server/index.js +2427 -0
- package/dist/server/lib/batch-client.d.ts +80 -0
- package/dist/server/lib/batch-client.js +467 -0
- package/dist/server/lib/code-worker-pool.d.ts +31 -0
- package/dist/server/lib/code-worker-pool.js +224 -0
- package/dist/server/lib/code-worker.d.ts +1 -0
- package/dist/server/lib/code-worker.js +188 -0
- package/dist/server/lib/compaction-service.d.ts +32 -0
- package/dist/server/lib/compaction-service.js +162 -0
- package/dist/server/lib/logger.d.ts +19 -0
- package/dist/server/lib/logger.js +46 -0
- package/dist/server/lib/otel.d.ts +38 -0
- package/dist/server/lib/otel.js +126 -0
- package/dist/server/lib/pg-rate-limiter.d.ts +21 -0
- package/dist/server/lib/pg-rate-limiter.js +86 -0
- package/dist/server/lib/prompt-sanitizer.d.ts +37 -0
- package/dist/server/lib/prompt-sanitizer.js +177 -0
- package/dist/server/lib/provider-capabilities.d.ts +85 -0
- package/dist/server/lib/provider-capabilities.js +190 -0
- package/dist/server/lib/provider-failover.d.ts +74 -0
- package/dist/server/lib/provider-failover.js +210 -0
- package/dist/server/lib/rate-limiter.d.ts +39 -0
- package/dist/server/lib/rate-limiter.js +147 -0
- package/dist/server/lib/server-agent-loop.d.ts +107 -0
- package/dist/server/lib/server-agent-loop.js +667 -0
- package/dist/server/lib/server-subagent.d.ts +78 -0
- package/dist/server/lib/server-subagent.js +203 -0
- package/dist/server/lib/session-checkpoint.d.ts +51 -0
- package/dist/server/lib/session-checkpoint.js +145 -0
- package/dist/server/lib/ssrf-guard.d.ts +13 -0
- package/dist/server/lib/ssrf-guard.js +240 -0
- package/dist/server/lib/supabase-client.d.ts +7 -0
- package/dist/server/lib/supabase-client.js +78 -0
- package/dist/server/lib/template-resolver.d.ts +31 -0
- package/dist/server/lib/template-resolver.js +215 -0
- package/dist/server/lib/utils.d.ts +16 -0
- package/dist/server/lib/utils.js +147 -0
- package/dist/server/local-agent-gateway.d.ts +82 -0
- package/dist/server/local-agent-gateway.js +426 -0
- package/dist/server/providers/anthropic.d.ts +20 -0
- package/dist/server/providers/anthropic.js +199 -0
- package/dist/server/providers/bedrock.d.ts +20 -0
- package/dist/server/providers/bedrock.js +194 -0
- package/dist/server/providers/gemini.d.ts +24 -0
- package/dist/server/providers/gemini.js +486 -0
- package/dist/server/providers/openai.d.ts +24 -0
- package/dist/server/providers/openai.js +522 -0
- package/dist/server/providers/registry.d.ts +32 -0
- package/dist/server/providers/registry.js +58 -0
- package/dist/server/providers/shared.d.ts +32 -0
- package/dist/server/providers/shared.js +124 -0
- package/dist/server/providers/types.d.ts +92 -0
- package/dist/server/providers/types.js +12 -0
- package/dist/server/proxy-handlers.d.ts +6 -0
- package/dist/server/proxy-handlers.js +89 -0
- package/dist/server/tool-router.d.ts +149 -0
- package/dist/server/tool-router.js +803 -0
- package/dist/server/validation.d.ts +24 -0
- package/dist/server/validation.js +301 -0
- package/dist/server/worker.d.ts +19 -0
- package/dist/server/worker.js +201 -0
- package/dist/setup.d.ts +8 -0
- package/dist/setup.js +181 -0
- package/dist/shared/agent-core.d.ts +157 -0
- package/dist/shared/agent-core.js +534 -0
- package/dist/shared/anthropic-types.d.ts +105 -0
- package/dist/shared/anthropic-types.js +7 -0
- package/dist/shared/api-client.d.ts +90 -0
- package/dist/shared/api-client.js +379 -0
- package/dist/shared/constants.d.ts +33 -0
- package/dist/shared/constants.js +80 -0
- package/dist/shared/sse-parser.d.ts +26 -0
- package/dist/shared/sse-parser.js +259 -0
- package/dist/shared/tool-dispatch.d.ts +52 -0
- package/dist/shared/tool-dispatch.js +191 -0
- package/dist/shared/types.d.ts +72 -0
- package/dist/shared/types.js +7 -0
- package/dist/updater.d.ts +25 -0
- package/dist/updater.js +140 -0
- package/dist/webchat/widget.d.ts +0 -0
- package/dist/webchat/widget.js +397 -0
- package/package.json +95 -0
- package/src/cli/services/builtin-skills/commit.md +19 -0
- package/src/cli/services/builtin-skills/review-pr.md +21 -0
- package/src/cli/services/builtin-skills/review.md +18 -0
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Config Store
|
|
3
|
+
*
|
|
4
|
+
* Persistent configuration at ~/.swagmanager/config.json
|
|
5
|
+
*
|
|
6
|
+
* v2.0: Raw Supabase/Anthropic keys (for MCP server env vars)
|
|
7
|
+
* v2.1: Auth tokens from login flow (for CLI chat/status)
|
|
8
|
+
*
|
|
9
|
+
* Environment variables always override file-based config for MCP server mode.
|
|
10
|
+
*/
|
|
11
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync, unlinkSync } from "fs";
|
|
12
|
+
import { homedir } from "os";
|
|
13
|
+
import { join } from "path";
|
|
14
|
+
// ============================================================================
|
|
15
|
+
// PATHS
|
|
16
|
+
// ============================================================================
|
|
17
|
+
const CONFIG_DIR = join(homedir(), ".swagmanager");
|
|
18
|
+
const CONFIG_PATH = join(CONFIG_DIR, "config.json");
|
|
19
|
+
// ============================================================================
|
|
20
|
+
// READ / WRITE
|
|
21
|
+
// ============================================================================
|
|
22
|
+
export function loadConfig() {
|
|
23
|
+
try {
|
|
24
|
+
if (existsSync(CONFIG_PATH)) {
|
|
25
|
+
return JSON.parse(readFileSync(CONFIG_PATH, "utf-8"));
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
catch (err) {
|
|
29
|
+
// Log warning for corrupted config — user may need to re-login
|
|
30
|
+
console.error(`[config] Warning: Failed to parse ${CONFIG_PATH}: ${err instanceof Error ? err.message : err}`);
|
|
31
|
+
console.error("[config] Using empty config. You may need to re-login with: whale login");
|
|
32
|
+
}
|
|
33
|
+
return {};
|
|
34
|
+
}
|
|
35
|
+
export function saveConfig(config) {
|
|
36
|
+
if (!existsSync(CONFIG_DIR)) {
|
|
37
|
+
mkdirSync(CONFIG_DIR, { recursive: true, mode: 0o700 });
|
|
38
|
+
}
|
|
39
|
+
writeFileSync(CONFIG_PATH, JSON.stringify(config, null, 2) + "\n", {
|
|
40
|
+
encoding: "utf-8",
|
|
41
|
+
mode: 0o600,
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
export function updateConfig(partial) {
|
|
45
|
+
const existing = loadConfig();
|
|
46
|
+
saveConfig({ ...existing, ...partial });
|
|
47
|
+
}
|
|
48
|
+
export function clearConfig() {
|
|
49
|
+
try {
|
|
50
|
+
if (existsSync(CONFIG_PATH))
|
|
51
|
+
unlinkSync(CONFIG_PATH);
|
|
52
|
+
}
|
|
53
|
+
catch { /* ignore */ }
|
|
54
|
+
}
|
|
55
|
+
/** Default Fly.io agent server URL */
|
|
56
|
+
export const WHALE_SERVER_URL = "https://whale-agent.fly.dev";
|
|
57
|
+
/** Default Supabase URL — fallback when env var and config are both empty */
|
|
58
|
+
const DEFAULT_SUPABASE_URL = "https://uaednwpxursknmwdeejn.supabase.co";
|
|
59
|
+
export function resolveConfig() {
|
|
60
|
+
const file = loadConfig();
|
|
61
|
+
return {
|
|
62
|
+
supabaseUrl: process.env.SUPABASE_URL || file.supabase_url || DEFAULT_SUPABASE_URL,
|
|
63
|
+
// User JWT preferred over legacy service role key from config file;
|
|
64
|
+
// env var SUPABASE_SERVICE_ROLE_KEY still wins (explicit MCP setup)
|
|
65
|
+
supabaseKey: process.env.SUPABASE_SERVICE_ROLE_KEY || file.access_token || file.supabase_key || "",
|
|
66
|
+
storeId: process.env.STORE_ID || file.store_id || "",
|
|
67
|
+
anthropicApiKey: process.env.ANTHROPIC_API_KEY || file.anthropic_api_key || "",
|
|
68
|
+
defaultAgentId: file.default_agent_id || "",
|
|
69
|
+
serverUrl: process.env.WHALE_SERVER_URL || WHALE_SERVER_URL,
|
|
70
|
+
platformUrl: process.env.WHALETOOLS_PLATFORM_URL || file.platform_url || "https://whaletools.dev",
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
export function getConfigPath() {
|
|
74
|
+
return CONFIG_PATH;
|
|
75
|
+
}
|
|
76
|
+
/** Lazy proxy URL — avoids reading config at import time */
|
|
77
|
+
export function getProxyUrl() {
|
|
78
|
+
return resolveConfig().serverUrl;
|
|
79
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Debug Logging — structured JSONL debug output
|
|
3
|
+
*
|
|
4
|
+
* Writes to ~/.swagmanager/debug/{sessionId}.log
|
|
5
|
+
* Categories: api, tools, context, hooks, sandbox
|
|
6
|
+
* Enabled via --debug flag or --debug api,tools (selective)
|
|
7
|
+
*/
|
|
8
|
+
export declare function initDebugLog(sessionId: string, filter?: string): void;
|
|
9
|
+
export declare function isDebugEnabled(): boolean;
|
|
10
|
+
export declare function debugLog(category: string, message: string, data?: Record<string, unknown>): void;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Debug Logging — structured JSONL debug output
|
|
3
|
+
*
|
|
4
|
+
* Writes to ~/.swagmanager/debug/{sessionId}.log
|
|
5
|
+
* Categories: api, tools, context, hooks, sandbox
|
|
6
|
+
* Enabled via --debug flag or --debug api,tools (selective)
|
|
7
|
+
*/
|
|
8
|
+
import { existsSync, mkdirSync, appendFileSync } from "fs";
|
|
9
|
+
import { join } from "path";
|
|
10
|
+
import { homedir } from "os";
|
|
11
|
+
const DEBUG_DIR = join(homedir(), ".swagmanager", "debug");
|
|
12
|
+
let debugSessionId = null;
|
|
13
|
+
let debugFilter = null; // null = all categories
|
|
14
|
+
let debugEnabled = false;
|
|
15
|
+
export function initDebugLog(sessionId, filter) {
|
|
16
|
+
debugEnabled = true;
|
|
17
|
+
debugSessionId = sessionId;
|
|
18
|
+
if (filter && filter !== "true" && filter !== "1") {
|
|
19
|
+
debugFilter = new Set(filter.split(",").map(s => s.trim()));
|
|
20
|
+
}
|
|
21
|
+
else {
|
|
22
|
+
debugFilter = null; // all categories
|
|
23
|
+
}
|
|
24
|
+
if (!existsSync(DEBUG_DIR))
|
|
25
|
+
mkdirSync(DEBUG_DIR, { recursive: true });
|
|
26
|
+
}
|
|
27
|
+
export function isDebugEnabled() {
|
|
28
|
+
return debugEnabled;
|
|
29
|
+
}
|
|
30
|
+
export function debugLog(category, message, data) {
|
|
31
|
+
if (!debugEnabled || !debugSessionId)
|
|
32
|
+
return;
|
|
33
|
+
if (debugFilter && !debugFilter.has(category))
|
|
34
|
+
return;
|
|
35
|
+
const entry = {
|
|
36
|
+
ts: new Date().toISOString(),
|
|
37
|
+
cat: category,
|
|
38
|
+
msg: message,
|
|
39
|
+
...data,
|
|
40
|
+
};
|
|
41
|
+
const logPath = join(DEBUG_DIR, `${debugSessionId}.log`);
|
|
42
|
+
try {
|
|
43
|
+
appendFileSync(logPath, JSON.stringify(entry) + "\n");
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
// Best effort
|
|
47
|
+
}
|
|
48
|
+
// Also write to stderr for --print mode visibility
|
|
49
|
+
if (process.env.WHALE_DEBUG_STDERR === "1") {
|
|
50
|
+
process.stderr.write(`[${category}] ${message}\n`);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Error Logger — fire-and-forget error capture to error_events table
|
|
3
|
+
*
|
|
4
|
+
* Sentry replacement built on our own Supabase infrastructure.
|
|
5
|
+
* Mirrors the Swift WhaleErrorLogger: same fingerprinting, same table, same schema.
|
|
6
|
+
* Reuses the telemetry.ts Supabase client pattern.
|
|
7
|
+
*/
|
|
8
|
+
export interface ErrorLoggerConfig {
|
|
9
|
+
serviceName: string;
|
|
10
|
+
serviceVersion?: string;
|
|
11
|
+
platform?: "typescript" | "deno";
|
|
12
|
+
environment?: "development" | "staging" | "production";
|
|
13
|
+
maxBreadcrumbs?: number;
|
|
14
|
+
}
|
|
15
|
+
export interface Breadcrumb {
|
|
16
|
+
timestamp: string;
|
|
17
|
+
category: string;
|
|
18
|
+
message: string;
|
|
19
|
+
level: string;
|
|
20
|
+
data?: Record<string, string>;
|
|
21
|
+
}
|
|
22
|
+
export interface CaptureErrorOptions {
|
|
23
|
+
error?: Error;
|
|
24
|
+
errorType?: string;
|
|
25
|
+
errorMessage?: string;
|
|
26
|
+
errorCode?: string;
|
|
27
|
+
severity?: "debug" | "info" | "warning" | "error" | "fatal";
|
|
28
|
+
file?: string;
|
|
29
|
+
line?: number;
|
|
30
|
+
function?: string;
|
|
31
|
+
tags?: Record<string, string>;
|
|
32
|
+
extra?: Record<string, string>;
|
|
33
|
+
traceId?: string;
|
|
34
|
+
spanId?: string;
|
|
35
|
+
storeId?: string;
|
|
36
|
+
userId?: string;
|
|
37
|
+
userEmail?: string;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Initialize the error logger. Call once at CLI startup.
|
|
41
|
+
*/
|
|
42
|
+
export declare function initErrorLogger(cfg: ErrorLoggerConfig): void;
|
|
43
|
+
/**
|
|
44
|
+
* Update user context (called after auth).
|
|
45
|
+
*/
|
|
46
|
+
export declare function setErrorLoggerUser(userId?: string, email?: string, storeId?: string): void;
|
|
47
|
+
/**
|
|
48
|
+
* Add a breadcrumb to the ring buffer.
|
|
49
|
+
*/
|
|
50
|
+
export declare function addBreadcrumb(category: string, message: string, level?: string, data?: Record<string, string>): void;
|
|
51
|
+
/**
|
|
52
|
+
* Capture an error event. Fire-and-forget.
|
|
53
|
+
*/
|
|
54
|
+
export declare function captureError(opts: CaptureErrorOptions): void;
|
|
55
|
+
/**
|
|
56
|
+
* Convenience: capture a message (non-Error).
|
|
57
|
+
*/
|
|
58
|
+
export declare function captureMessage(message: string, severity?: "debug" | "info" | "warning" | "error" | "fatal", extra?: Record<string, string>): void;
|
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Error Logger — fire-and-forget error capture to error_events table
|
|
3
|
+
*
|
|
4
|
+
* Sentry replacement built on our own Supabase infrastructure.
|
|
5
|
+
* Mirrors the Swift WhaleErrorLogger: same fingerprinting, same table, same schema.
|
|
6
|
+
* Reuses the telemetry.ts Supabase client pattern.
|
|
7
|
+
*/
|
|
8
|
+
import { createClient } from "@supabase/supabase-js";
|
|
9
|
+
import { createRequire } from "module";
|
|
10
|
+
import { createHash } from "crypto";
|
|
11
|
+
import os from "os";
|
|
12
|
+
import { resolveConfig } from "./config-store.js";
|
|
13
|
+
import { getValidToken, createAuthenticatedClient } from "./auth-service.js";
|
|
14
|
+
const require = createRequire(import.meta.url);
|
|
15
|
+
const PKG_VERSION = require("../../../package.json").version;
|
|
16
|
+
// ============================================================================
|
|
17
|
+
// STATE
|
|
18
|
+
// ============================================================================
|
|
19
|
+
let config = {
|
|
20
|
+
serviceName: "whale-code",
|
|
21
|
+
serviceVersion: PKG_VERSION,
|
|
22
|
+
platform: "typescript",
|
|
23
|
+
environment: "production",
|
|
24
|
+
maxBreadcrumbs: 25,
|
|
25
|
+
};
|
|
26
|
+
let breadcrumbs = [];
|
|
27
|
+
let supabaseClient = null;
|
|
28
|
+
// User context (set externally)
|
|
29
|
+
let currentUserId;
|
|
30
|
+
let currentUserEmail;
|
|
31
|
+
let currentStoreId;
|
|
32
|
+
// ============================================================================
|
|
33
|
+
// INIT
|
|
34
|
+
// ============================================================================
|
|
35
|
+
/**
|
|
36
|
+
* Initialize the error logger. Call once at CLI startup.
|
|
37
|
+
*/
|
|
38
|
+
export function initErrorLogger(cfg) {
|
|
39
|
+
config = {
|
|
40
|
+
...config,
|
|
41
|
+
...cfg,
|
|
42
|
+
serviceVersion: cfg.serviceVersion || PKG_VERSION,
|
|
43
|
+
environment: cfg.environment || (process.env.NODE_ENV === "development" ? "development" : "production"),
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Update user context (called after auth).
|
|
48
|
+
*/
|
|
49
|
+
export function setErrorLoggerUser(userId, email, storeId) {
|
|
50
|
+
currentUserId = userId;
|
|
51
|
+
currentUserEmail = email;
|
|
52
|
+
currentStoreId = storeId;
|
|
53
|
+
}
|
|
54
|
+
// ============================================================================
|
|
55
|
+
// BREADCRUMBS
|
|
56
|
+
// ============================================================================
|
|
57
|
+
/**
|
|
58
|
+
* Add a breadcrumb to the ring buffer.
|
|
59
|
+
*/
|
|
60
|
+
export function addBreadcrumb(category, message, level = "info", data) {
|
|
61
|
+
breadcrumbs.push({
|
|
62
|
+
timestamp: new Date().toISOString(),
|
|
63
|
+
category,
|
|
64
|
+
message,
|
|
65
|
+
level,
|
|
66
|
+
data,
|
|
67
|
+
});
|
|
68
|
+
const max = config.maxBreadcrumbs || 25;
|
|
69
|
+
if (breadcrumbs.length > max) {
|
|
70
|
+
breadcrumbs = breadcrumbs.slice(-max);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
// ============================================================================
|
|
74
|
+
// CAPTURE
|
|
75
|
+
// ============================================================================
|
|
76
|
+
/**
|
|
77
|
+
* Capture an error event. Fire-and-forget.
|
|
78
|
+
*/
|
|
79
|
+
export function captureError(opts) {
|
|
80
|
+
_captureError(opts).catch((err) => {
|
|
81
|
+
if (process.env.DEBUG_TELEMETRY) {
|
|
82
|
+
process.stderr.write(`[error-logger] capture failed: ${err.message}\n`);
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Convenience: capture a message (non-Error).
|
|
88
|
+
*/
|
|
89
|
+
export function captureMessage(message, severity = "info", extra) {
|
|
90
|
+
captureError({
|
|
91
|
+
errorType: "Message",
|
|
92
|
+
errorMessage: message,
|
|
93
|
+
severity,
|
|
94
|
+
extra,
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
// ============================================================================
|
|
98
|
+
// INTERNAL
|
|
99
|
+
// ============================================================================
|
|
100
|
+
async function _captureError(opts) {
|
|
101
|
+
const client = await getClient();
|
|
102
|
+
if (!client) {
|
|
103
|
+
if (process.env.DEBUG_TELEMETRY) {
|
|
104
|
+
process.stderr.write(`[error-logger] no client available\n`);
|
|
105
|
+
}
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
const error = opts.error;
|
|
109
|
+
const errorType = opts.errorType || (error ? error.constructor.name : "UnknownError");
|
|
110
|
+
const errorMessage = opts.errorMessage || (error ? error.message : "Unknown error");
|
|
111
|
+
const stackTrace = error?.stack;
|
|
112
|
+
const normalizedMessage = normalizeMessage(errorMessage);
|
|
113
|
+
const sourceLocation = opts.file && opts.function
|
|
114
|
+
? `${opts.file}:${opts.function}`
|
|
115
|
+
: extractSourceFromStack(stackTrace);
|
|
116
|
+
const fingerprint = computeFingerprint(errorType, normalizedMessage, sourceLocation);
|
|
117
|
+
// Parse source from stack if not provided
|
|
118
|
+
const parsedSource = parseSourceFromStack(stackTrace);
|
|
119
|
+
const event = {
|
|
120
|
+
fingerprint,
|
|
121
|
+
severity: opts.severity || "error",
|
|
122
|
+
error_type: errorType,
|
|
123
|
+
error_message: errorMessage,
|
|
124
|
+
error_code: opts.errorCode,
|
|
125
|
+
source_file: opts.file || parsedSource.file,
|
|
126
|
+
source_line: opts.line || parsedSource.line,
|
|
127
|
+
source_function: opts.function || parsedSource.function,
|
|
128
|
+
stack_trace: stackTrace,
|
|
129
|
+
stack_frames: stackTrace ? parseStackFrames(stackTrace) : undefined,
|
|
130
|
+
breadcrumbs: [...breadcrumbs],
|
|
131
|
+
platform: config.platform || "typescript",
|
|
132
|
+
service_name: config.serviceName,
|
|
133
|
+
service_version: config.serviceVersion,
|
|
134
|
+
environment: config.environment || "production",
|
|
135
|
+
device_info: collectDeviceInfo(),
|
|
136
|
+
runtime_info: collectRuntimeInfo(),
|
|
137
|
+
store_id: opts.storeId || currentStoreId,
|
|
138
|
+
user_id: opts.userId || currentUserId,
|
|
139
|
+
user_email: opts.userEmail || currentUserEmail,
|
|
140
|
+
trace_id: opts.traceId,
|
|
141
|
+
span_id: opts.spanId,
|
|
142
|
+
tags: opts.tags || {},
|
|
143
|
+
extra: opts.extra || {},
|
|
144
|
+
occurred_at: new Date().toISOString(),
|
|
145
|
+
};
|
|
146
|
+
const { error: dbError } = await client.from("error_events").insert(event);
|
|
147
|
+
if (dbError && process.env.DEBUG_TELEMETRY) {
|
|
148
|
+
process.stderr.write(`[error-logger] db error: ${dbError.message}\n`);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
// ============================================================================
|
|
152
|
+
// SUPABASE CLIENT (lazy init, same pattern as telemetry.ts)
|
|
153
|
+
// ============================================================================
|
|
154
|
+
async function getClient() {
|
|
155
|
+
if (supabaseClient)
|
|
156
|
+
return supabaseClient;
|
|
157
|
+
const cfg = resolveConfig();
|
|
158
|
+
// Prefer service role key
|
|
159
|
+
if (cfg.supabaseUrl && cfg.supabaseKey) {
|
|
160
|
+
supabaseClient = createClient(cfg.supabaseUrl, cfg.supabaseKey, {
|
|
161
|
+
auth: { persistSession: false, autoRefreshToken: false },
|
|
162
|
+
});
|
|
163
|
+
return supabaseClient;
|
|
164
|
+
}
|
|
165
|
+
// Fallback: user JWT
|
|
166
|
+
const token = await getValidToken();
|
|
167
|
+
if (token) {
|
|
168
|
+
supabaseClient = createAuthenticatedClient(token);
|
|
169
|
+
return supabaseClient;
|
|
170
|
+
}
|
|
171
|
+
return null;
|
|
172
|
+
}
|
|
173
|
+
// ============================================================================
|
|
174
|
+
// FINGERPRINTING (identical algorithm to Swift)
|
|
175
|
+
// ============================================================================
|
|
176
|
+
function computeFingerprint(errorType, message, source) {
|
|
177
|
+
const input = `${errorType}|${message}|${source}`;
|
|
178
|
+
return createHash("sha256").update(input).digest("hex");
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Strip volatile data from error messages for stable grouping.
|
|
182
|
+
* Must match Swift's normalizeMessage exactly for cross-platform grouping.
|
|
183
|
+
*/
|
|
184
|
+
function normalizeMessage(message) {
|
|
185
|
+
return message
|
|
186
|
+
// UUIDs
|
|
187
|
+
.replace(/[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}/g, "<UUID>")
|
|
188
|
+
// URLs
|
|
189
|
+
.replace(/https?:\/\/[^\s"']+/g, "<URL>")
|
|
190
|
+
// Emails
|
|
191
|
+
.replace(/[\w.+-]+@[\w.-]+\.[a-zA-Z]{2,}/g, "<EMAIL>")
|
|
192
|
+
// IP addresses
|
|
193
|
+
.replace(/\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/g, "<IP>")
|
|
194
|
+
// Standalone numbers (2+ digits)
|
|
195
|
+
.replace(/\b\d{2,}\b/g, "<N>")
|
|
196
|
+
// Quoted strings
|
|
197
|
+
.replace(/"[^"]*"/g, '"<STR>"');
|
|
198
|
+
}
|
|
199
|
+
// ============================================================================
|
|
200
|
+
// STACK PARSING
|
|
201
|
+
// ============================================================================
|
|
202
|
+
function parseStackFrames(stack) {
|
|
203
|
+
return stack
|
|
204
|
+
.split("\n")
|
|
205
|
+
.slice(0, 20)
|
|
206
|
+
.map((line) => {
|
|
207
|
+
// V8 format: " at functionName (file:line:column)"
|
|
208
|
+
const match = line.match(/at\s+(.+?)\s+\((.+?):(\d+):(\d+)\)/);
|
|
209
|
+
if (match) {
|
|
210
|
+
return {
|
|
211
|
+
function: match[1],
|
|
212
|
+
file: match[2],
|
|
213
|
+
line: parseInt(match[3], 10),
|
|
214
|
+
column: parseInt(match[4], 10),
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
// Anonymous: " at file:line:column"
|
|
218
|
+
const anonMatch = line.match(/at\s+(.+?):(\d+):(\d+)/);
|
|
219
|
+
if (anonMatch) {
|
|
220
|
+
return {
|
|
221
|
+
file: anonMatch[1],
|
|
222
|
+
line: parseInt(anonMatch[2], 10),
|
|
223
|
+
column: parseInt(anonMatch[3], 10),
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
return { function: line.trim() };
|
|
227
|
+
});
|
|
228
|
+
}
|
|
229
|
+
function extractSourceFromStack(stack) {
|
|
230
|
+
if (!stack)
|
|
231
|
+
return "unknown";
|
|
232
|
+
const parsed = parseSourceFromStack(stack);
|
|
233
|
+
return parsed.file && parsed.function
|
|
234
|
+
? `${parsed.file}:${parsed.function}`
|
|
235
|
+
: parsed.file || "unknown";
|
|
236
|
+
}
|
|
237
|
+
function parseSourceFromStack(stack) {
|
|
238
|
+
if (!stack)
|
|
239
|
+
return {};
|
|
240
|
+
// Get the first meaningful frame (skip "Error" line)
|
|
241
|
+
const lines = stack.split("\n");
|
|
242
|
+
for (const line of lines) {
|
|
243
|
+
const match = line.match(/at\s+(.+?)\s+\((.+?):(\d+):(\d+)\)/);
|
|
244
|
+
if (match) {
|
|
245
|
+
return {
|
|
246
|
+
function: match[1],
|
|
247
|
+
file: match[2],
|
|
248
|
+
line: parseInt(match[3], 10),
|
|
249
|
+
};
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
return {};
|
|
253
|
+
}
|
|
254
|
+
// ============================================================================
|
|
255
|
+
// DEVICE / RUNTIME INFO
|
|
256
|
+
// ============================================================================
|
|
257
|
+
function collectDeviceInfo() {
|
|
258
|
+
return {
|
|
259
|
+
os: process.platform,
|
|
260
|
+
os_version: os.release(),
|
|
261
|
+
arch: process.arch,
|
|
262
|
+
memory_gb: (os.totalmem() / 1_073_741_824).toFixed(1),
|
|
263
|
+
};
|
|
264
|
+
}
|
|
265
|
+
function collectRuntimeInfo() {
|
|
266
|
+
return {
|
|
267
|
+
node_version: process.version,
|
|
268
|
+
};
|
|
269
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* File History — backup files before modification
|
|
3
|
+
*
|
|
4
|
+
* On every write_file/edit_file/multi_edit, the original content is saved to:
|
|
5
|
+
* ~/.swagmanager/file-history/{sessionId}/{timestamp}-{basename}
|
|
6
|
+
*
|
|
7
|
+
* Limit: 100 backups per session (FIFO cleanup).
|
|
8
|
+
*/
|
|
9
|
+
export declare function setFileHistorySessionId(sessionId: string): void;
|
|
10
|
+
/**
|
|
11
|
+
* Save a backup of a file before it is modified.
|
|
12
|
+
* No-op if the file doesn't exist yet (new file creation).
|
|
13
|
+
*/
|
|
14
|
+
export declare function backupFile(filePath: string): void;
|
|
15
|
+
/**
|
|
16
|
+
* List backups for the current session.
|
|
17
|
+
*/
|
|
18
|
+
export declare function listBackups(): Array<{
|
|
19
|
+
name: string;
|
|
20
|
+
path: string;
|
|
21
|
+
}>;
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* File History — backup files before modification
|
|
3
|
+
*
|
|
4
|
+
* On every write_file/edit_file/multi_edit, the original content is saved to:
|
|
5
|
+
* ~/.swagmanager/file-history/{sessionId}/{timestamp}-{basename}
|
|
6
|
+
*
|
|
7
|
+
* Limit: 100 backups per session (FIFO cleanup).
|
|
8
|
+
*/
|
|
9
|
+
import { existsSync, readFileSync, writeFileSync, mkdirSync, readdirSync, unlinkSync } from "fs";
|
|
10
|
+
import { join, basename } from "path";
|
|
11
|
+
import { homedir } from "os";
|
|
12
|
+
const HISTORY_BASE = join(homedir(), ".swagmanager", "file-history");
|
|
13
|
+
const MAX_BACKUPS_PER_SESSION = 100;
|
|
14
|
+
let currentSessionId = null;
|
|
15
|
+
export function setFileHistorySessionId(sessionId) {
|
|
16
|
+
currentSessionId = sessionId;
|
|
17
|
+
}
|
|
18
|
+
function getSessionDir() {
|
|
19
|
+
if (!currentSessionId)
|
|
20
|
+
return null;
|
|
21
|
+
const dir = join(HISTORY_BASE, currentSessionId);
|
|
22
|
+
if (!existsSync(dir))
|
|
23
|
+
mkdirSync(dir, { recursive: true });
|
|
24
|
+
return dir;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Save a backup of a file before it is modified.
|
|
28
|
+
* No-op if the file doesn't exist yet (new file creation).
|
|
29
|
+
*/
|
|
30
|
+
export function backupFile(filePath) {
|
|
31
|
+
if (!currentSessionId)
|
|
32
|
+
return;
|
|
33
|
+
if (!existsSync(filePath))
|
|
34
|
+
return;
|
|
35
|
+
try {
|
|
36
|
+
const dir = getSessionDir();
|
|
37
|
+
if (!dir)
|
|
38
|
+
return;
|
|
39
|
+
const content = readFileSync(filePath);
|
|
40
|
+
const ts = Date.now();
|
|
41
|
+
const name = basename(filePath);
|
|
42
|
+
const backupName = `${ts}-${name}`;
|
|
43
|
+
const backupPath = join(dir, backupName);
|
|
44
|
+
writeFileSync(backupPath, content);
|
|
45
|
+
// FIFO cleanup
|
|
46
|
+
cleanupOldBackups(dir);
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
// Best effort — don't fail the actual operation
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
function cleanupOldBackups(dir) {
|
|
53
|
+
try {
|
|
54
|
+
const files = readdirSync(dir).sort();
|
|
55
|
+
if (files.length > MAX_BACKUPS_PER_SESSION) {
|
|
56
|
+
const toRemove = files.slice(0, files.length - MAX_BACKUPS_PER_SESSION);
|
|
57
|
+
for (const f of toRemove) {
|
|
58
|
+
try {
|
|
59
|
+
unlinkSync(join(dir, f));
|
|
60
|
+
}
|
|
61
|
+
catch { /* skip */ }
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
catch { /* skip */ }
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* List backups for the current session.
|
|
69
|
+
*/
|
|
70
|
+
export function listBackups() {
|
|
71
|
+
const dir = getSessionDir();
|
|
72
|
+
if (!dir || !existsSync(dir))
|
|
73
|
+
return [];
|
|
74
|
+
try {
|
|
75
|
+
return readdirSync(dir)
|
|
76
|
+
.sort()
|
|
77
|
+
.reverse()
|
|
78
|
+
.map(name => ({ name, path: join(dir, name) }));
|
|
79
|
+
}
|
|
80
|
+
catch {
|
|
81
|
+
return [];
|
|
82
|
+
}
|
|
83
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Server Response Formatter — converts raw JSON to readable markdown
|
|
3
|
+
*
|
|
4
|
+
* Transforms server tool JSON responses into:
|
|
5
|
+
* - Markdown tables for arrays of flat objects
|
|
6
|
+
* - Bold key-value pairs for single objects
|
|
7
|
+
* - JSON fences for complex nested data
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Format a server tool response as readable markdown.
|
|
11
|
+
*
|
|
12
|
+
* @param data - The raw response data (parsed JSON)
|
|
13
|
+
* @param toolName - Optional tool name for smart column selection
|
|
14
|
+
* @returns Formatted markdown string
|
|
15
|
+
*/
|
|
16
|
+
export declare function formatServerResponse(data: unknown, toolName?: string): string;
|