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,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* /init command — scan project and generate .whale/CLAUDE.md
|
|
3
|
+
*
|
|
4
|
+
* Two exports:
|
|
5
|
+
* - runInit() — standalone CLI subcommand (console.log output)
|
|
6
|
+
* - runInitInline() — returns string for in-chat /init
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Standalone CLI: `whale init`
|
|
10
|
+
*/
|
|
11
|
+
export declare function runInit(): Promise<void>;
|
|
12
|
+
/**
|
|
13
|
+
* In-chat: /init
|
|
14
|
+
* Returns a string to display as an assistant message.
|
|
15
|
+
*/
|
|
16
|
+
export declare function runInitInline(): Promise<string>;
|
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* /init command — scan project and generate .whale/CLAUDE.md
|
|
3
|
+
*
|
|
4
|
+
* Two exports:
|
|
5
|
+
* - runInit() — standalone CLI subcommand (console.log output)
|
|
6
|
+
* - runInitInline() — returns string for in-chat /init
|
|
7
|
+
*/
|
|
8
|
+
import { existsSync, readFileSync, mkdirSync, writeFileSync, statSync } from "fs";
|
|
9
|
+
import { join, basename } from "path";
|
|
10
|
+
function detectProject(cwd) {
|
|
11
|
+
const info = {
|
|
12
|
+
name: basename(cwd),
|
|
13
|
+
description: "",
|
|
14
|
+
language: "",
|
|
15
|
+
framework: "",
|
|
16
|
+
buildCmd: "",
|
|
17
|
+
testCmd: "",
|
|
18
|
+
srcDir: "",
|
|
19
|
+
testDir: "",
|
|
20
|
+
conventions: [],
|
|
21
|
+
gitRemote: "",
|
|
22
|
+
};
|
|
23
|
+
// ── package.json (Node/JS/TS) ──
|
|
24
|
+
const pkgPath = join(cwd, "package.json");
|
|
25
|
+
if (existsSync(pkgPath)) {
|
|
26
|
+
try {
|
|
27
|
+
const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
|
|
28
|
+
info.name = pkg.name || info.name;
|
|
29
|
+
info.description = pkg.description || "";
|
|
30
|
+
// Detect language
|
|
31
|
+
const deps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
32
|
+
if (existsSync(join(cwd, "tsconfig.json")) || deps["typescript"]) {
|
|
33
|
+
info.language = "TypeScript";
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
info.language = "JavaScript";
|
|
37
|
+
}
|
|
38
|
+
// Detect framework
|
|
39
|
+
if (deps["next"])
|
|
40
|
+
info.framework = "Next.js";
|
|
41
|
+
else if (deps["react"] && deps["ink"])
|
|
42
|
+
info.framework = "React + Ink (CLI)";
|
|
43
|
+
else if (deps["react"])
|
|
44
|
+
info.framework = "React";
|
|
45
|
+
else if (deps["vue"])
|
|
46
|
+
info.framework = "Vue";
|
|
47
|
+
else if (deps["svelte"])
|
|
48
|
+
info.framework = "Svelte";
|
|
49
|
+
else if (deps["express"])
|
|
50
|
+
info.framework = "Express";
|
|
51
|
+
else if (deps["fastify"])
|
|
52
|
+
info.framework = "Fastify";
|
|
53
|
+
else if (deps["hono"])
|
|
54
|
+
info.framework = "Hono";
|
|
55
|
+
else if (deps["@angular/core"])
|
|
56
|
+
info.framework = "Angular";
|
|
57
|
+
// Build & test commands
|
|
58
|
+
if (pkg.scripts?.build)
|
|
59
|
+
info.buildCmd = `npm run build`;
|
|
60
|
+
if (pkg.scripts?.test)
|
|
61
|
+
info.testCmd = `npm test`;
|
|
62
|
+
if (pkg.scripts?.dev)
|
|
63
|
+
info.buildCmd = info.buildCmd || `npm run dev`;
|
|
64
|
+
}
|
|
65
|
+
catch { /* corrupt package.json */ }
|
|
66
|
+
}
|
|
67
|
+
// ── pyproject.toml / requirements.txt (Python) ──
|
|
68
|
+
if (existsSync(join(cwd, "pyproject.toml"))) {
|
|
69
|
+
info.language = info.language || "Python";
|
|
70
|
+
try {
|
|
71
|
+
const toml = readFileSync(join(cwd, "pyproject.toml"), "utf-8");
|
|
72
|
+
const nameMatch = toml.match(/name\s*=\s*"([^"]+)"/);
|
|
73
|
+
if (nameMatch)
|
|
74
|
+
info.name = nameMatch[1];
|
|
75
|
+
if (toml.includes("django"))
|
|
76
|
+
info.framework = "Django";
|
|
77
|
+
else if (toml.includes("fastapi"))
|
|
78
|
+
info.framework = "FastAPI";
|
|
79
|
+
else if (toml.includes("flask"))
|
|
80
|
+
info.framework = "Flask";
|
|
81
|
+
}
|
|
82
|
+
catch { /* ignore */ }
|
|
83
|
+
if (!info.buildCmd)
|
|
84
|
+
info.buildCmd = "python -m build";
|
|
85
|
+
if (!info.testCmd)
|
|
86
|
+
info.testCmd = "pytest";
|
|
87
|
+
}
|
|
88
|
+
else if (existsSync(join(cwd, "requirements.txt"))) {
|
|
89
|
+
info.language = info.language || "Python";
|
|
90
|
+
if (!info.testCmd)
|
|
91
|
+
info.testCmd = "pytest";
|
|
92
|
+
}
|
|
93
|
+
// ── Cargo.toml (Rust) ──
|
|
94
|
+
if (existsSync(join(cwd, "Cargo.toml"))) {
|
|
95
|
+
info.language = info.language || "Rust";
|
|
96
|
+
try {
|
|
97
|
+
const cargo = readFileSync(join(cwd, "Cargo.toml"), "utf-8");
|
|
98
|
+
const nameMatch = cargo.match(/name\s*=\s*"([^"]+)"/);
|
|
99
|
+
if (nameMatch)
|
|
100
|
+
info.name = nameMatch[1];
|
|
101
|
+
}
|
|
102
|
+
catch { /* ignore */ }
|
|
103
|
+
info.buildCmd = info.buildCmd || "cargo build";
|
|
104
|
+
info.testCmd = info.testCmd || "cargo test";
|
|
105
|
+
}
|
|
106
|
+
// ── go.mod (Go) ──
|
|
107
|
+
if (existsSync(join(cwd, "go.mod"))) {
|
|
108
|
+
info.language = info.language || "Go";
|
|
109
|
+
try {
|
|
110
|
+
const gomod = readFileSync(join(cwd, "go.mod"), "utf-8");
|
|
111
|
+
const moduleMatch = gomod.match(/module\s+(\S+)/);
|
|
112
|
+
if (moduleMatch)
|
|
113
|
+
info.name = moduleMatch[1].split("/").pop() || info.name;
|
|
114
|
+
}
|
|
115
|
+
catch { /* ignore */ }
|
|
116
|
+
info.buildCmd = info.buildCmd || "go build ./...";
|
|
117
|
+
info.testCmd = info.testCmd || "go test ./...";
|
|
118
|
+
}
|
|
119
|
+
// ── README.md — first paragraph for description ──
|
|
120
|
+
if (!info.description) {
|
|
121
|
+
const readmePath = join(cwd, "README.md");
|
|
122
|
+
if (existsSync(readmePath)) {
|
|
123
|
+
try {
|
|
124
|
+
const readme = readFileSync(readmePath, "utf-8");
|
|
125
|
+
const lines = readme.split("\n");
|
|
126
|
+
// Skip title lines (# heading), blank lines, badges
|
|
127
|
+
let para = "";
|
|
128
|
+
for (const line of lines) {
|
|
129
|
+
if (line.startsWith("#") || line.startsWith("![") || line.startsWith("[![") || !line.trim()) {
|
|
130
|
+
if (para)
|
|
131
|
+
break; // End of first paragraph
|
|
132
|
+
continue;
|
|
133
|
+
}
|
|
134
|
+
para += (para ? " " : "") + line.trim();
|
|
135
|
+
}
|
|
136
|
+
if (para && para.length < 200)
|
|
137
|
+
info.description = para;
|
|
138
|
+
}
|
|
139
|
+
catch { /* ignore */ }
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
// ── Git remote ──
|
|
143
|
+
const gitConfigPath = join(cwd, ".git", "config");
|
|
144
|
+
if (existsSync(gitConfigPath)) {
|
|
145
|
+
try {
|
|
146
|
+
const gitConfig = readFileSync(gitConfigPath, "utf-8");
|
|
147
|
+
const urlMatch = gitConfig.match(/url\s*=\s*(.+)/);
|
|
148
|
+
if (urlMatch)
|
|
149
|
+
info.gitRemote = urlMatch[1].trim();
|
|
150
|
+
}
|
|
151
|
+
catch { /* ignore */ }
|
|
152
|
+
}
|
|
153
|
+
// ── Directory structure ──
|
|
154
|
+
const dirExists = (name) => {
|
|
155
|
+
try {
|
|
156
|
+
return statSync(join(cwd, name)).isDirectory();
|
|
157
|
+
}
|
|
158
|
+
catch {
|
|
159
|
+
return false;
|
|
160
|
+
}
|
|
161
|
+
};
|
|
162
|
+
if (dirExists("src"))
|
|
163
|
+
info.srcDir = "src/";
|
|
164
|
+
else if (dirExists("lib"))
|
|
165
|
+
info.srcDir = "lib/";
|
|
166
|
+
else if (dirExists("app"))
|
|
167
|
+
info.srcDir = "app/";
|
|
168
|
+
if (dirExists("tests"))
|
|
169
|
+
info.testDir = "tests/";
|
|
170
|
+
else if (dirExists("test"))
|
|
171
|
+
info.testDir = "test/";
|
|
172
|
+
else if (dirExists("__tests__"))
|
|
173
|
+
info.testDir = "__tests__/";
|
|
174
|
+
else if (dirExists("spec"))
|
|
175
|
+
info.testDir = "spec/";
|
|
176
|
+
// ── Conventions ──
|
|
177
|
+
if (existsSync(join(cwd, ".eslintrc.json")) || existsSync(join(cwd, ".eslintrc.js")) || existsSync(join(cwd, "eslint.config.js")) || existsSync(join(cwd, "eslint.config.mjs"))) {
|
|
178
|
+
info.conventions.push("ESLint configured");
|
|
179
|
+
}
|
|
180
|
+
if (existsSync(join(cwd, ".prettierrc")) || existsSync(join(cwd, ".prettierrc.json")) || existsSync(join(cwd, "prettier.config.js"))) {
|
|
181
|
+
info.conventions.push("Prettier configured");
|
|
182
|
+
}
|
|
183
|
+
if (existsSync(join(cwd, ".editorconfig"))) {
|
|
184
|
+
info.conventions.push("EditorConfig");
|
|
185
|
+
}
|
|
186
|
+
if (existsSync(join(cwd, "Dockerfile")) || existsSync(join(cwd, "docker-compose.yml"))) {
|
|
187
|
+
info.conventions.push("Docker");
|
|
188
|
+
}
|
|
189
|
+
if (existsSync(join(cwd, ".github"))) {
|
|
190
|
+
info.conventions.push("GitHub Actions CI");
|
|
191
|
+
}
|
|
192
|
+
return info;
|
|
193
|
+
}
|
|
194
|
+
// ============================================================================
|
|
195
|
+
// MARKDOWN GENERATOR
|
|
196
|
+
// ============================================================================
|
|
197
|
+
function generateMarkdown(info) {
|
|
198
|
+
const lines = [];
|
|
199
|
+
lines.push(`# ${info.name}`);
|
|
200
|
+
lines.push("");
|
|
201
|
+
if (info.description) {
|
|
202
|
+
lines.push(info.description);
|
|
203
|
+
lines.push("");
|
|
204
|
+
}
|
|
205
|
+
lines.push("## Stack");
|
|
206
|
+
if (info.language)
|
|
207
|
+
lines.push(`- Language: ${info.language}`);
|
|
208
|
+
if (info.framework)
|
|
209
|
+
lines.push(`- Framework: ${info.framework}`);
|
|
210
|
+
if (info.buildCmd)
|
|
211
|
+
lines.push(`- Build: \`${info.buildCmd}\``);
|
|
212
|
+
if (info.testCmd)
|
|
213
|
+
lines.push(`- Test: \`${info.testCmd}\``);
|
|
214
|
+
lines.push("");
|
|
215
|
+
if (info.srcDir || info.testDir) {
|
|
216
|
+
lines.push("## Key Paths");
|
|
217
|
+
if (info.srcDir)
|
|
218
|
+
lines.push(`- Source: \`${info.srcDir}\``);
|
|
219
|
+
if (info.testDir)
|
|
220
|
+
lines.push(`- Tests: \`${info.testDir}\``);
|
|
221
|
+
lines.push("");
|
|
222
|
+
}
|
|
223
|
+
if (info.conventions.length > 0) {
|
|
224
|
+
lines.push("## Conventions");
|
|
225
|
+
for (const c of info.conventions) {
|
|
226
|
+
lines.push(`- ${c}`);
|
|
227
|
+
}
|
|
228
|
+
lines.push("");
|
|
229
|
+
}
|
|
230
|
+
if (info.gitRemote) {
|
|
231
|
+
lines.push("## Repository");
|
|
232
|
+
lines.push(`- ${info.gitRemote}`);
|
|
233
|
+
lines.push("");
|
|
234
|
+
}
|
|
235
|
+
return lines.join("\n");
|
|
236
|
+
}
|
|
237
|
+
// ============================================================================
|
|
238
|
+
// PUBLIC API
|
|
239
|
+
// ============================================================================
|
|
240
|
+
/**
|
|
241
|
+
* Standalone CLI: `whale init`
|
|
242
|
+
*/
|
|
243
|
+
export async function runInit() {
|
|
244
|
+
const cwd = process.cwd();
|
|
245
|
+
const whaleDir = join(cwd, ".whale");
|
|
246
|
+
const outPath = join(whaleDir, "CLAUDE.md");
|
|
247
|
+
if (existsSync(outPath)) {
|
|
248
|
+
console.log(` .whale/CLAUDE.md already exists. Delete it first to regenerate.`);
|
|
249
|
+
return;
|
|
250
|
+
}
|
|
251
|
+
const info = detectProject(cwd);
|
|
252
|
+
const markdown = generateMarkdown(info);
|
|
253
|
+
if (!existsSync(whaleDir))
|
|
254
|
+
mkdirSync(whaleDir, { recursive: true });
|
|
255
|
+
writeFileSync(outPath, markdown, "utf-8");
|
|
256
|
+
console.log(` Created .whale/CLAUDE.md`);
|
|
257
|
+
console.log(` Detected: ${[info.language, info.framework].filter(Boolean).join(" + ") || "unknown stack"}`);
|
|
258
|
+
console.log(` Edit the file to add project-specific instructions.`);
|
|
259
|
+
}
|
|
260
|
+
/**
|
|
261
|
+
* In-chat: /init
|
|
262
|
+
* Returns a string to display as an assistant message.
|
|
263
|
+
*/
|
|
264
|
+
export async function runInitInline() {
|
|
265
|
+
const cwd = process.cwd();
|
|
266
|
+
const whaleDir = join(cwd, ".whale");
|
|
267
|
+
const outPath = join(whaleDir, "CLAUDE.md");
|
|
268
|
+
if (existsSync(outPath)) {
|
|
269
|
+
return " .whale/CLAUDE.md already exists. Delete it first to regenerate.";
|
|
270
|
+
}
|
|
271
|
+
const info = detectProject(cwd);
|
|
272
|
+
const markdown = generateMarkdown(info);
|
|
273
|
+
if (!existsSync(whaleDir))
|
|
274
|
+
mkdirSync(whaleDir, { recursive: true });
|
|
275
|
+
writeFileSync(outPath, markdown, "utf-8");
|
|
276
|
+
const stack = [info.language, info.framework].filter(Boolean).join(" + ") || "unknown stack";
|
|
277
|
+
return ` Created .whale/CLAUDE.md\n Detected: ${stack}\n Edit the file to add project-specific instructions.`;
|
|
278
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* whale mcp — Manage MCP server configurations
|
|
3
|
+
*
|
|
4
|
+
* Usage:
|
|
5
|
+
* whale mcp list List configured servers
|
|
6
|
+
* whale mcp add <name> -- <cmd> [args...] Add stdio server
|
|
7
|
+
* whale mcp add --transport http <name> <url> Add HTTP server
|
|
8
|
+
* whale mcp add -e KEY=VAL <name> -- <cmd> Add with env vars
|
|
9
|
+
* whale mcp remove <name> Remove server
|
|
10
|
+
* whale mcp get <name> Show server config
|
|
11
|
+
*/
|
|
12
|
+
export declare function runMcpCommand(args: string[]): Promise<void>;
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* whale mcp — Manage MCP server configurations
|
|
3
|
+
*
|
|
4
|
+
* Usage:
|
|
5
|
+
* whale mcp list List configured servers
|
|
6
|
+
* whale mcp add <name> -- <cmd> [args...] Add stdio server
|
|
7
|
+
* whale mcp add --transport http <name> <url> Add HTTP server
|
|
8
|
+
* whale mcp add -e KEY=VAL <name> -- <cmd> Add with env vars
|
|
9
|
+
* whale mcp remove <name> Remove server
|
|
10
|
+
* whale mcp get <name> Show server config
|
|
11
|
+
*/
|
|
12
|
+
import { readFileSync, writeFileSync, existsSync, mkdirSync } from "fs";
|
|
13
|
+
import { join } from "path";
|
|
14
|
+
import { homedir } from "os";
|
|
15
|
+
const CONFIG_PATH = join(homedir(), ".swagmanager", "config.json");
|
|
16
|
+
function loadConfig() {
|
|
17
|
+
if (!existsSync(CONFIG_PATH))
|
|
18
|
+
return {};
|
|
19
|
+
try {
|
|
20
|
+
return JSON.parse(readFileSync(CONFIG_PATH, "utf-8"));
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
23
|
+
return {};
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
function saveConfig(config) {
|
|
27
|
+
const dir = join(homedir(), ".swagmanager");
|
|
28
|
+
if (!existsSync(dir))
|
|
29
|
+
mkdirSync(dir, { recursive: true });
|
|
30
|
+
writeFileSync(CONFIG_PATH, JSON.stringify(config, null, 2), { mode: 0o600 });
|
|
31
|
+
}
|
|
32
|
+
function getServers(config) {
|
|
33
|
+
return config.mcpServers || {};
|
|
34
|
+
}
|
|
35
|
+
export async function runMcpCommand(args) {
|
|
36
|
+
const subcommand = args[0];
|
|
37
|
+
if (!subcommand || subcommand === "list") {
|
|
38
|
+
const config = loadConfig();
|
|
39
|
+
const servers = getServers(config);
|
|
40
|
+
const names = Object.keys(servers);
|
|
41
|
+
if (names.length === 0) {
|
|
42
|
+
console.log("No MCP servers configured.");
|
|
43
|
+
console.log("Add one: whale mcp add <name> -- <command> [args...]");
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
console.log("Configured MCP servers:\n");
|
|
47
|
+
for (const name of names) {
|
|
48
|
+
const s = servers[name];
|
|
49
|
+
if (s.transport === "http") {
|
|
50
|
+
console.log(` ${name} (http) → ${s.url}`);
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
const cmd = [s.command, ...(s.args || [])].join(" ");
|
|
54
|
+
console.log(` ${name} (stdio) → ${cmd}`);
|
|
55
|
+
}
|
|
56
|
+
if (s.env && Object.keys(s.env).length > 0) {
|
|
57
|
+
console.log(` env: ${Object.keys(s.env).join(", ")}`);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
if (subcommand === "add") {
|
|
63
|
+
const restArgs = args.slice(1);
|
|
64
|
+
// Parse -e KEY=VAL and --transport flags
|
|
65
|
+
const envVars = {};
|
|
66
|
+
let transport = "stdio";
|
|
67
|
+
const filteredArgs = [];
|
|
68
|
+
for (let i = 0; i < restArgs.length; i++) {
|
|
69
|
+
if (restArgs[i] === "-e" && i + 1 < restArgs.length) {
|
|
70
|
+
const kv = restArgs[++i];
|
|
71
|
+
const eqIdx = kv.indexOf("=");
|
|
72
|
+
if (eqIdx > 0) {
|
|
73
|
+
envVars[kv.slice(0, eqIdx)] = kv.slice(eqIdx + 1);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
else if (restArgs[i] === "--transport" && i + 1 < restArgs.length) {
|
|
77
|
+
transport = restArgs[++i];
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
filteredArgs.push(restArgs[i]);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
if (transport === "http") {
|
|
84
|
+
// whale mcp add --transport http <name> <url>
|
|
85
|
+
const name = filteredArgs[0];
|
|
86
|
+
const url = filteredArgs[1];
|
|
87
|
+
if (!name || !url) {
|
|
88
|
+
console.error("Usage: whale mcp add --transport http <name> <url>");
|
|
89
|
+
process.exit(1);
|
|
90
|
+
}
|
|
91
|
+
const config = loadConfig();
|
|
92
|
+
const servers = getServers(config);
|
|
93
|
+
servers[name] = { transport: "http", url, env: Object.keys(envVars).length > 0 ? envVars : undefined };
|
|
94
|
+
config.mcpServers = servers;
|
|
95
|
+
saveConfig(config);
|
|
96
|
+
console.log(`Added HTTP MCP server: ${name} → ${url}`);
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
// stdio: whale mcp add <name> -- <cmd> [args...]
|
|
100
|
+
const dashDash = filteredArgs.indexOf("--");
|
|
101
|
+
if (dashDash < 1) {
|
|
102
|
+
console.error("Usage: whale mcp add <name> -- <command> [args...]");
|
|
103
|
+
process.exit(1);
|
|
104
|
+
}
|
|
105
|
+
const name = filteredArgs[0];
|
|
106
|
+
const command = filteredArgs[dashDash + 1];
|
|
107
|
+
const cmdArgs = filteredArgs.slice(dashDash + 2);
|
|
108
|
+
if (!name || !command) {
|
|
109
|
+
console.error("Usage: whale mcp add <name> -- <command> [args...]");
|
|
110
|
+
process.exit(1);
|
|
111
|
+
}
|
|
112
|
+
const config = loadConfig();
|
|
113
|
+
const servers = getServers(config);
|
|
114
|
+
servers[name] = {
|
|
115
|
+
command,
|
|
116
|
+
args: cmdArgs.length > 0 ? cmdArgs : undefined,
|
|
117
|
+
env: Object.keys(envVars).length > 0 ? envVars : undefined,
|
|
118
|
+
transport: "stdio",
|
|
119
|
+
};
|
|
120
|
+
config.mcpServers = servers;
|
|
121
|
+
saveConfig(config);
|
|
122
|
+
console.log(`Added stdio MCP server: ${name} → ${[command, ...cmdArgs].join(" ")}`);
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
if (subcommand === "remove") {
|
|
126
|
+
const name = args[1];
|
|
127
|
+
if (!name) {
|
|
128
|
+
console.error("Usage: whale mcp remove <name>");
|
|
129
|
+
process.exit(1);
|
|
130
|
+
}
|
|
131
|
+
const config = loadConfig();
|
|
132
|
+
const servers = getServers(config);
|
|
133
|
+
if (!servers[name]) {
|
|
134
|
+
console.error(`MCP server not found: ${name}`);
|
|
135
|
+
process.exit(1);
|
|
136
|
+
}
|
|
137
|
+
delete servers[name];
|
|
138
|
+
config.mcpServers = servers;
|
|
139
|
+
saveConfig(config);
|
|
140
|
+
console.log(`Removed MCP server: ${name}`);
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
if (subcommand === "get") {
|
|
144
|
+
const name = args[1];
|
|
145
|
+
if (!name) {
|
|
146
|
+
console.error("Usage: whale mcp get <name>");
|
|
147
|
+
process.exit(1);
|
|
148
|
+
}
|
|
149
|
+
const config = loadConfig();
|
|
150
|
+
const servers = getServers(config);
|
|
151
|
+
const server = servers[name];
|
|
152
|
+
if (!server) {
|
|
153
|
+
console.error(`MCP server not found: ${name}`);
|
|
154
|
+
process.exit(1);
|
|
155
|
+
}
|
|
156
|
+
console.log(JSON.stringify(server, null, 2));
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
console.error(`Unknown mcp subcommand: ${subcommand}`);
|
|
160
|
+
console.error("Usage: whale mcp list|add|remove|get");
|
|
161
|
+
process.exit(1);
|
|
162
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Login Flow — browser-first with email/password fallback
|
|
3
|
+
*
|
|
4
|
+
* Default: opens browser → whaletools.dev/auth/cli → localhost callback
|
|
5
|
+
* Fallback: press E for terminal-based email/password (legacy)
|
|
6
|
+
*/
|
|
7
|
+
export declare function LoginApp(): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* Login Flow — browser-first with email/password fallback
|
|
4
|
+
*
|
|
5
|
+
* Default: opens browser → whaletools.dev/auth/cli → localhost callback
|
|
6
|
+
* Fallback: press E for terminal-based email/password (legacy)
|
|
7
|
+
*/
|
|
8
|
+
import { useState, useEffect } from "react";
|
|
9
|
+
import { Box, Text, useApp, useInput } from "ink";
|
|
10
|
+
import TextInput from "ink-text-input";
|
|
11
|
+
import Spinner from "ink-spinner";
|
|
12
|
+
import SelectInput from "ink-select-input";
|
|
13
|
+
import { signIn, signUp, getStoresForUser, selectStore, } from "../services/auth-service.js";
|
|
14
|
+
import { signInWithBrowser } from "../services/browser-auth.js";
|
|
15
|
+
import { WhaleBanner } from "../shared/WhaleBanner.js";
|
|
16
|
+
import { colors, symbols, boxLine } from "../shared/Theme.js";
|
|
17
|
+
export function LoginApp() {
|
|
18
|
+
const { exit } = useApp();
|
|
19
|
+
const [step, setStep] = useState("browser_opening");
|
|
20
|
+
const [mode, setMode] = useState("login");
|
|
21
|
+
const [email, setEmail] = useState("");
|
|
22
|
+
const [inputValue, setInputValue] = useState("");
|
|
23
|
+
const [error, setError] = useState("");
|
|
24
|
+
const [stores, setStores] = useState([]);
|
|
25
|
+
const [resultEmail, setResultEmail] = useState("");
|
|
26
|
+
const [resultStore, setResultStore] = useState("");
|
|
27
|
+
const [loginUrl, setLoginUrl] = useState("");
|
|
28
|
+
const [browserFallback, setBrowserFallback] = useState(false);
|
|
29
|
+
// Auto-exit after success
|
|
30
|
+
useEffect(() => {
|
|
31
|
+
if (step === "done") {
|
|
32
|
+
const timer = setTimeout(() => exit(), 300);
|
|
33
|
+
return () => clearTimeout(timer);
|
|
34
|
+
}
|
|
35
|
+
}, [step, exit]);
|
|
36
|
+
// Start browser auth on mount
|
|
37
|
+
useEffect(() => {
|
|
38
|
+
if (browserFallback)
|
|
39
|
+
return;
|
|
40
|
+
signInWithBrowser(undefined, {
|
|
41
|
+
onBrowserOpening: (url) => {
|
|
42
|
+
setLoginUrl(url);
|
|
43
|
+
setStep("browser_opening");
|
|
44
|
+
},
|
|
45
|
+
onWaitingForCallback: () => {
|
|
46
|
+
setStep("browser_waiting");
|
|
47
|
+
},
|
|
48
|
+
onExchangingCode: () => {
|
|
49
|
+
// Stay on browser_waiting with spinner
|
|
50
|
+
},
|
|
51
|
+
}).then((result) => {
|
|
52
|
+
if (browserFallback)
|
|
53
|
+
return; // User already switched to email mode
|
|
54
|
+
if (!result.success) {
|
|
55
|
+
// If browser auth failed and user hasn't switched, show error
|
|
56
|
+
setError(result.error || "Browser login failed");
|
|
57
|
+
setStep("error");
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
const config = result.config;
|
|
61
|
+
setResultEmail(config.email || "");
|
|
62
|
+
if (result.stores && result.stores.length > 1) {
|
|
63
|
+
// Multiple stores — need selection
|
|
64
|
+
setStores(result.stores);
|
|
65
|
+
setStep("store_select");
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
setResultStore(config.store_name || config.store_id || "");
|
|
69
|
+
setStep("done");
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
}, []); // eslint-disable-line react-hooks/exhaustive-deps
|
|
73
|
+
// Listen for 'E' key to switch to email/password fallback
|
|
74
|
+
useInput((input, key) => {
|
|
75
|
+
if ((step === "browser_opening" || step === "browser_waiting") &&
|
|
76
|
+
(input === "e" || input === "E") &&
|
|
77
|
+
!browserFallback) {
|
|
78
|
+
setBrowserFallback(true);
|
|
79
|
+
setStep("mode");
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
// ── Legacy email/password handlers ──
|
|
83
|
+
const handleModeSubmit = (value) => {
|
|
84
|
+
if (value === "1" || value.toLowerCase().startsWith("l")) {
|
|
85
|
+
setMode("login");
|
|
86
|
+
setStep("email");
|
|
87
|
+
}
|
|
88
|
+
else if (value === "2" || value.toLowerCase().startsWith("s")) {
|
|
89
|
+
setMode("signup");
|
|
90
|
+
setStep("email");
|
|
91
|
+
}
|
|
92
|
+
setInputValue("");
|
|
93
|
+
};
|
|
94
|
+
const handleEmailSubmit = (value) => {
|
|
95
|
+
if (!value.trim())
|
|
96
|
+
return;
|
|
97
|
+
setEmail(value.trim());
|
|
98
|
+
setInputValue("");
|
|
99
|
+
setStep("password");
|
|
100
|
+
};
|
|
101
|
+
const handlePasswordSubmit = async (value) => {
|
|
102
|
+
if (!value.trim())
|
|
103
|
+
return;
|
|
104
|
+
setInputValue("");
|
|
105
|
+
setStep("authenticating");
|
|
106
|
+
try {
|
|
107
|
+
const result = mode === "login"
|
|
108
|
+
? await signIn(email, value)
|
|
109
|
+
: await signUp(email, value);
|
|
110
|
+
if (!result.success) {
|
|
111
|
+
setError(result.error || "Authentication failed");
|
|
112
|
+
setStep("error");
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
if (result.error && !result.config) {
|
|
116
|
+
setError(result.error);
|
|
117
|
+
setStep("error");
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
const config = result.config;
|
|
121
|
+
setResultEmail(config.email || email);
|
|
122
|
+
if (config.store_id) {
|
|
123
|
+
setResultStore(config.store_name || config.store_id);
|
|
124
|
+
setStep("done");
|
|
125
|
+
}
|
|
126
|
+
else {
|
|
127
|
+
const userStores = await getStoresForUser(config.access_token, config.user_id);
|
|
128
|
+
if (userStores.length === 0) {
|
|
129
|
+
setError("No stores found. Contact your admin.");
|
|
130
|
+
setStep("error");
|
|
131
|
+
}
|
|
132
|
+
else if (userStores.length === 1) {
|
|
133
|
+
selectStore(userStores[0].id, userStores[0].name);
|
|
134
|
+
setResultStore(userStores[0].name);
|
|
135
|
+
setStep("done");
|
|
136
|
+
}
|
|
137
|
+
else {
|
|
138
|
+
setStores(userStores);
|
|
139
|
+
setStep("store_select");
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
catch (err) {
|
|
144
|
+
setError(String(err));
|
|
145
|
+
setStep("error");
|
|
146
|
+
}
|
|
147
|
+
};
|
|
148
|
+
const handleStoreSelect = (item) => {
|
|
149
|
+
const store = stores.find((s) => s.id === item.value);
|
|
150
|
+
if (store) {
|
|
151
|
+
selectStore(store.id, store.name);
|
|
152
|
+
setResultStore(store.name);
|
|
153
|
+
setStep("done");
|
|
154
|
+
}
|
|
155
|
+
};
|
|
156
|
+
return (_jsxs(Box, { flexDirection: "column", padding: 1, children: [_jsx(WhaleBanner, { subtitle: "authenticate" }), _jsx(Box, { height: 1 }), _jsx(Text, { color: colors.border, children: boxLine(44) }), _jsx(Box, { height: 1 }), step === "browser_opening" && (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Box, { children: [_jsx(Text, { color: colors.brand, children: _jsx(Spinner, { type: "dots" }) }), _jsx(Text, { color: colors.muted, children: " Opening browser..." })] }), loginUrl && (_jsxs(_Fragment, { children: [_jsx(Box, { height: 1 }), _jsx(Text, { color: colors.dim, children: " If the browser didn't open, visit:" }), _jsxs(Text, { color: colors.text, children: [" ", loginUrl] })] })), _jsx(Box, { height: 1 }), _jsxs(Text, { color: colors.dim, children: [" Press ", _jsx(Text, { color: colors.brand, children: "E" }), " for email/password login"] })] })), step === "browser_waiting" && (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Box, { children: [_jsx(Text, { color: colors.brand, children: _jsx(Spinner, { type: "dots" }) }), _jsx(Text, { color: colors.muted, children: " Waiting for browser login..." })] }), loginUrl && (_jsxs(_Fragment, { children: [_jsx(Box, { height: 1 }), _jsx(Text, { color: colors.dim, children: " If the browser didn't open, visit:" }), _jsxs(Text, { color: colors.text, children: [" ", loginUrl] })] })), _jsx(Box, { height: 1 }), _jsxs(Text, { color: colors.dim, children: [" Press ", _jsx(Text, { color: colors.brand, children: "E" }), " for email/password login"] })] })), step === "mode" && (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Box, { marginBottom: 1, children: [_jsx(Text, { color: colors.muted, children: " 1 " }), _jsx(Text, { color: colors.text, children: "Login to existing account" })] }), _jsxs(Box, { marginBottom: 1, children: [_jsx(Text, { color: colors.muted, children: " 2 " }), _jsx(Text, { color: colors.text, children: "Create new account" })] }), _jsx(Box, { height: 1 }), _jsxs(Box, { children: [_jsxs(Text, { color: colors.brand, children: [symbols.arrowRight, " "] }), _jsx(TextInput, { value: inputValue, onChange: setInputValue, onSubmit: handleModeSubmit, placeholder: "1 or 2" })] })] })), step === "email" && (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { color: colors.muted, children: mode === "login" ? "Login" : "Sign Up" }), _jsx(Box, { height: 1 }), _jsxs(Box, { children: [_jsx(Text, { color: colors.brand, children: "email " }), _jsx(TextInput, { value: inputValue, onChange: setInputValue, onSubmit: handleEmailSubmit })] })] })), step === "password" && (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Text, { color: colors.dim, children: ["email: ", email] }), _jsx(Box, { height: 1 }), _jsxs(Box, { children: [_jsx(Text, { color: colors.brand, children: "password " }), _jsx(TextInput, { value: inputValue, onChange: setInputValue, mask: "*", onSubmit: handlePasswordSubmit })] })] })), step === "authenticating" && (_jsxs(Box, { children: [_jsx(Text, { color: colors.brand, children: _jsx(Spinner, { type: "dots" }) }), _jsx(Text, { color: colors.muted, children: " authenticating\u2026" })] })), step === "store_select" && (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { color: colors.muted, children: "Select your store:" }), _jsx(Box, { height: 1 }), _jsx(SelectInput, { items: stores.map((s) => ({ label: s.name + (s.slug ? ` (${s.slug})` : ""), value: s.id })), onSelect: handleStoreSelect, indicatorComponent: ({ isSelected }) => (_jsxs(Text, { color: isSelected ? colors.brand : colors.dim, children: [isSelected ? symbols.arrowRight : " ", " "] })) })] })), step === "done" && (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Box, { children: [_jsxs(Text, { color: colors.success, children: [symbols.check, " "] }), _jsx(Text, { color: colors.text, bold: true, children: "Logged in" })] }), _jsx(Box, { height: 1 }), _jsxs(Box, { children: [_jsxs(Text, { color: colors.dim, children: [" ", "user "] }), _jsx(Text, { color: colors.text, children: resultEmail })] }), _jsxs(Box, { children: [_jsxs(Text, { color: colors.dim, children: [" ", "store "] }), _jsx(Text, { color: colors.text, children: resultStore })] }), _jsx(Box, { height: 1 }), _jsx(Text, { color: colors.muted, children: " Run `whale` to start chatting." })] })), step === "error" && (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Box, { children: [_jsxs(Text, { color: colors.error, children: [symbols.cross, " "] }), _jsx(Text, { color: colors.error, children: error })] }), _jsx(Box, { height: 1 }), _jsx(Text, { color: colors.dim, children: " Try again: whale login" })] }))] }));
|
|
157
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Print Mode — non-interactive headless agent runner
|
|
3
|
+
*
|
|
4
|
+
* Used for:
|
|
5
|
+
* whale -p "prompt" Text output to stdout
|
|
6
|
+
* whale -p --output-format json "..." Single JSON result
|
|
7
|
+
* whale -p --output-format stream-json NDJSON event stream
|
|
8
|
+
* echo "..." | whale -p Read prompt from stdin
|
|
9
|
+
*
|
|
10
|
+
* Auto-yolo mode (no permission prompts).
|
|
11
|
+
* Exit codes: 0=success, 1=error, 2=budget exceeded, 130=SIGINT
|
|
12
|
+
*/
|
|
13
|
+
export interface PrintModeOptions {
|
|
14
|
+
message: string;
|
|
15
|
+
outputFormat: "text" | "json" | "stream-json";
|
|
16
|
+
model?: string;
|
|
17
|
+
permissionMode?: string;
|
|
18
|
+
resumeSessionId?: string;
|
|
19
|
+
continueLastSession?: boolean;
|
|
20
|
+
sessionId?: string;
|
|
21
|
+
noSessionPersistence?: boolean;
|
|
22
|
+
maxTurns?: number;
|
|
23
|
+
maxBudgetUsd?: number;
|
|
24
|
+
effort?: string;
|
|
25
|
+
allowedTools?: string[];
|
|
26
|
+
disallowedTools?: string[];
|
|
27
|
+
fallbackModel?: string;
|
|
28
|
+
debug?: boolean;
|
|
29
|
+
verbose?: boolean;
|
|
30
|
+
}
|
|
31
|
+
export declare function runPrintMode(opts: PrintModeOptions): Promise<number>;
|