@usecrow/envoy 0.1.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 ADDED
@@ -0,0 +1,50 @@
1
+ # @usecrow/envoy
2
+
3
+ CLI that reads your backend codebase, generates an MCP server, and deploys it to Crow — so AI agents can call your API.
4
+
5
+ ## Quick Start
6
+
7
+ ```bash
8
+ export CROW_API_KEY=ck_...
9
+ npx @usecrow/envoy
10
+ ```
11
+
12
+ Run from the root directory that contains your project folders (backend, frontend, etc.). The envoy will ask which directories are relevant before it starts.
13
+
14
+ ## Commands
15
+
16
+ | Command | Description |
17
+ |---------|-------------|
18
+ | `npx @usecrow/envoy` | Generate an MCP server from your codebase (default) |
19
+ | `npx @usecrow/envoy fix` | Fix/iterate on an existing MCP server |
20
+ | `npx @usecrow/envoy deploy` | Deploy the latest saved version |
21
+
22
+ ## Options
23
+
24
+ | Flag | Description |
25
+ |------|-------------|
26
+ | `--api-key <key>` | Crow API key (alternative to `CROW_API_KEY` env var) |
27
+ | `--ci` | CI mode — structured JSON output on stdout |
28
+ | `--dirs <a,b,c>` | Comma-separated directories to scan (CI mode, skips interactive prompt) |
29
+ | `--help, -h` | Show help |
30
+ | `--version, -v` | Show version |
31
+
32
+ ## Environment Variables
33
+
34
+ | Variable | Required | Description |
35
+ |----------|----------|-------------|
36
+ | `CROW_API_KEY` | Yes | Your Crow API key |
37
+ | `CROW_API_URL` | No | Override API URL (for development) |
38
+
39
+ Get your API key at [app.usecrow.com](https://app.usecrow.com) → **Tools**.
40
+
41
+ ## How It Works
42
+
43
+ 1. **Discover** — Scans your project directories for routes, schemas, and API structure
44
+ 2. **Generate** — An AI agent analyzes your codebase and builds a complete MCP server
45
+ 3. **Save** — Pushes the generated server to Crow with versioning
46
+ 4. **Deploy** — Makes the MCP server live so AI agents can call your API
47
+
48
+ ## License
49
+
50
+ MIT
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Agent Module
3
+ *
4
+ * Configures the Claude Agent SDK to use Crow's LLM proxy.
5
+ * The system prompt is injected server-side by crow-backend.
6
+ *
7
+ * Uses V1 streaming input mode for a persistent conversation:
8
+ * - A single query() call with an async generator as prompt
9
+ * - The generator yields user messages on demand (from readline)
10
+ * - The agent process stays alive between turns (no restart, no resume)
11
+ * - Follow-ups are near-instant since context is in memory
12
+ *
13
+ * For `fix` commands with a prior session_id, the conversation is
14
+ * restored from disk via `resume`, then continues in streaming mode.
15
+ */
16
+ import type { UI } from "./ui/interactive.js";
17
+ import type { ProjectLayout } from "./discover.js";
18
+ export interface AgentOptions {
19
+ command: "generate" | "fix";
20
+ apiKey: string;
21
+ baseUrl: string;
22
+ existingServer: {
23
+ files: Record<string, string>;
24
+ version: number;
25
+ analysis?: Record<string, unknown> | null;
26
+ tool_designs?: Record<string, unknown> | null;
27
+ session_id?: string | null;
28
+ } | null;
29
+ project: ProjectLayout;
30
+ ui: UI;
31
+ }
32
+ export declare function runAgent(options: AgentOptions): Promise<void>;
33
+ //# sourceMappingURL=agent.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../src/agent.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAMH,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,qBAAqB,CAAC;AAC9C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAEnD,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,UAAU,GAAG,KAAK,CAAC;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,cAAc,EAAE;QACd,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAC9B,OAAO,EAAE,MAAM,CAAC;QAChB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;QAC1C,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;QAC9C,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;KAC5B,GAAG,IAAI,CAAC;IACT,OAAO,EAAE,aAAa,CAAC;IACvB,EAAE,EAAE,EAAE,CAAC;CACR;AAiBD,wBAAsB,QAAQ,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CA+HnE"}
package/dist/agent.js ADDED
@@ -0,0 +1,192 @@
1
+ /**
2
+ * Agent Module
3
+ *
4
+ * Configures the Claude Agent SDK to use Crow's LLM proxy.
5
+ * The system prompt is injected server-side by crow-backend.
6
+ *
7
+ * Uses V1 streaming input mode for a persistent conversation:
8
+ * - A single query() call with an async generator as prompt
9
+ * - The generator yields user messages on demand (from readline)
10
+ * - The agent process stays alive between turns (no restart, no resume)
11
+ * - Follow-ups are near-instant since context is in memory
12
+ *
13
+ * For `fix` commands with a prior session_id, the conversation is
14
+ * restored from disk via `resume`, then continues in streaming mode.
15
+ */
16
+ import { query, createSdkMcpServer } from "@anthropic-ai/claude-agent-sdk";
17
+ import { createSaveToCrowTool, sessionState } from "./tools/save-to-crow.js";
18
+ import { createDeployTool } from "./tools/deploy.js";
19
+ /**
20
+ * Create an SDKUserMessage from a text string.
21
+ */
22
+ function makeUserMessage(text) {
23
+ return {
24
+ type: "user",
25
+ session_id: "",
26
+ message: {
27
+ role: "user",
28
+ content: [{ type: "text", text }],
29
+ },
30
+ parent_tool_use_id: null,
31
+ };
32
+ }
33
+ export async function runAgent(options) {
34
+ const { command, apiKey, baseUrl, existingServer, project, ui } = options;
35
+ // Build a description of the project layout for the agent
36
+ const dirList = project.directories
37
+ .map((d) => ` - ${d}`)
38
+ .join("\n");
39
+ // Check if we can resume a prior session (for fix command)
40
+ const canResume = command === "fix" && existingServer?.session_id;
41
+ // Build the initial prompt
42
+ const initialPrompt = buildInitialPrompt(command, existingServer, project.rootDir, dirList, !!canResume);
43
+ // Create custom MCP server with envoy-specific tools
44
+ const envoyTools = createSdkMcpServer({
45
+ name: "envoy-tools",
46
+ version: "1.0.0",
47
+ tools: [
48
+ createSaveToCrowTool(apiKey, baseUrl),
49
+ createDeployTool(apiKey, baseUrl),
50
+ ],
51
+ });
52
+ // Query options
53
+ const queryOptions = {
54
+ env: {
55
+ ...process.env,
56
+ ANTHROPIC_BASE_URL: `${baseUrl}/api/envoy`,
57
+ ANTHROPIC_API_KEY: apiKey,
58
+ CLAUDECODE: "",
59
+ },
60
+ tools: { type: "preset", preset: "claude_code" },
61
+ mcpServers: {
62
+ "envoy-tools": envoyTools,
63
+ },
64
+ cwd: project.rootDir,
65
+ additionalDirectories: project.directories,
66
+ permissionMode: "bypassPermissions",
67
+ allowDangerouslySkipPermissions: true,
68
+ maxTurns: 50,
69
+ };
70
+ // Resume prior session if available (for fix command)
71
+ if (canResume) {
72
+ queryOptions.resume = existingServer.session_id;
73
+ queryOptions.continue = true;
74
+ ui.status(`Resuming session from v${existingServer.version}...`);
75
+ }
76
+ // --- Streaming input channel ---
77
+ // The input generator yields user messages on demand.
78
+ // The output loop calls feedInput() to provide follow-ups.
79
+ let nextInputResolve = () => { };
80
+ function feedInput(msg) {
81
+ nextInputResolve(msg);
82
+ }
83
+ async function* inputStream() {
84
+ // First message: the initial prompt
85
+ yield makeUserMessage(initialPrompt);
86
+ // Subsequent messages: wait for the output loop to feed them
87
+ while (true) {
88
+ const msg = await new Promise((resolve) => {
89
+ nextInputResolve = resolve;
90
+ });
91
+ if (msg === null)
92
+ return; // exit signal
93
+ yield msg;
94
+ }
95
+ }
96
+ // Start the query with streaming input
97
+ const conversation = query({
98
+ prompt: inputStream(),
99
+ options: queryOptions,
100
+ });
101
+ try {
102
+ for await (const message of conversation) {
103
+ // Capture session_id
104
+ if ("session_id" in message && message.session_id) {
105
+ sessionState.sessionId = message.session_id;
106
+ }
107
+ if (message.type === "assistant") {
108
+ const content = message.message.content;
109
+ if (Array.isArray(content)) {
110
+ for (const block of content) {
111
+ if (block.type === "text") {
112
+ ui.agentMessage(block.text);
113
+ }
114
+ else if (block.type === "tool_use") {
115
+ ui.toolUse(block.name, block.input);
116
+ }
117
+ }
118
+ }
119
+ }
120
+ else if (message.type === "result") {
121
+ if (message.subtype !== "success") {
122
+ ui.error(`Agent stopped: ${message.subtype}`);
123
+ feedInput(null);
124
+ break;
125
+ }
126
+ // Turn complete — prompt user for follow-up
127
+ ui.conversationReady();
128
+ const userInput = await ui.userPrompt();
129
+ if (!userInput) {
130
+ // User wants to exit — signal the input generator to stop
131
+ ui.deployPrompt();
132
+ feedInput(null);
133
+ break;
134
+ }
135
+ // Feed the follow-up to the input generator
136
+ ui.status("Thinking...");
137
+ feedInput(makeUserMessage(userInput));
138
+ }
139
+ }
140
+ }
141
+ catch (error) {
142
+ const msg = error instanceof Error ? error.message : String(error);
143
+ ui.error(`Agent error: ${msg}`);
144
+ feedInput(null);
145
+ }
146
+ }
147
+ /**
148
+ * Build the initial prompt based on command type.
149
+ */
150
+ function buildInitialPrompt(command, existingServer, rootDir, dirList, canResume) {
151
+ if (command === "fix" && existingServer) {
152
+ if (canResume) {
153
+ return (`I need to fix/update the MCP server you generated previously (v${existingServer.version}).\n\n` +
154
+ `My project root is: ${rootDir}\n` +
155
+ `The relevant directories are:\n${dirList}\n\n` +
156
+ `Please check if anything in my codebase has changed and update the MCP server accordingly. ` +
157
+ `When done, use the save_to_crow tool to save the updated version.`);
158
+ }
159
+ let priorContext = "";
160
+ if (existingServer.analysis) {
161
+ priorContext +=
162
+ `\n\n--- PRIOR ANALYSIS (from v${existingServer.version} generation) ---\n` +
163
+ JSON.stringify(existingServer.analysis, null, 2);
164
+ }
165
+ if (existingServer.tool_designs) {
166
+ priorContext +=
167
+ `\n\n--- PRIOR TOOL DESIGNS (from v${existingServer.version} generation) ---\n` +
168
+ JSON.stringify(existingServer.tool_designs, null, 2);
169
+ }
170
+ return (`I have an existing MCP server (v${existingServer.version}) that needs to be fixed/updated.\n\n` +
171
+ `Here are the current generated files:\n\n` +
172
+ Object.entries(existingServer.files)
173
+ .map(([name, content]) => `--- ${name} ---\n${content}`)
174
+ .join("\n\n") +
175
+ priorContext +
176
+ `\n\nMy project root is: ${rootDir}\n` +
177
+ `The relevant directories are:\n${dirList}\n\n` +
178
+ `IMPORTANT: You already have the full MCP server code and the analysis from the previous run above. ` +
179
+ `Do NOT re-read the entire codebase from scratch. Instead:\n` +
180
+ `1. Look at the existing server code above to understand what was already built\n` +
181
+ `2. Only read specific files if you need to check something that changed or verify a detail\n` +
182
+ `3. Make targeted fixes to the MCP server\n` +
183
+ `4. Use the save_to_crow tool to save the updated version when done.`);
184
+ }
185
+ return (`Please read my codebase and generate an MCP server for it.\n\n` +
186
+ `My project root is: ${rootDir}\n` +
187
+ `The relevant directories are:\n${dirList}\n\n` +
188
+ `Start by exploring these directories to understand the project structure, ` +
189
+ `then follow the phases: Discovery → Analysis → Scoping → Tool Design → Build → Test.\n` +
190
+ `When done, use the save_to_crow tool to save the generated files.`);
191
+ }
192
+ //# sourceMappingURL=agent.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent.js","sourceRoot":"","sources":["../src/agent.ts"],"names":[],"mappings":"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"}
package/dist/auth.d.ts ADDED
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Auth Module
3
+ *
4
+ * Reads CROW_API_KEY from env or --api-key flag.
5
+ * Validates the key against the Crow backend.
6
+ */
7
+ export interface AuthResult {
8
+ productId: string;
9
+ apiKey: string;
10
+ baseUrl: string;
11
+ }
12
+ export declare function authenticate(apiKeyArg?: string): Promise<AuthResult>;
13
+ //# sourceMappingURL=auth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,WAAW,UAAU;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;CACjB;AAID,wBAAsB,YAAY,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CA2C1E"}
package/dist/auth.js ADDED
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Auth Module
3
+ *
4
+ * Reads CROW_API_KEY from env or --api-key flag.
5
+ * Validates the key against the Crow backend.
6
+ */
7
+ const DEFAULT_BASE_URL = "https://api.usecrow.com";
8
+ export async function authenticate(apiKeyArg) {
9
+ // Resolve API key: CLI flag > env var
10
+ const apiKey = apiKeyArg || process.env.CROW_API_KEY;
11
+ if (!apiKey) {
12
+ throw new Error("Missing API key. Set CROW_API_KEY environment variable or pass --api-key <key>\n\n" +
13
+ "Generate a key at: https://app.usecrow.com/settings");
14
+ }
15
+ // Resolve base URL (allow override for dev)
16
+ const baseUrl = process.env.CROW_API_URL || DEFAULT_BASE_URL;
17
+ // Validate the key by calling the server endpoint
18
+ // We use the /server endpoint as a lightweight auth check
19
+ const response = await fetch(`${baseUrl}/api/envoy/server`, {
20
+ headers: {
21
+ "X-Envoy-Key": apiKey,
22
+ },
23
+ });
24
+ if (response.status === 401) {
25
+ throw new Error("Invalid API key. Check your CROW_API_KEY or generate a new one at:\n" +
26
+ "https://app.usecrow.com/settings");
27
+ }
28
+ if (!response.ok) {
29
+ throw new Error(`Authentication failed: ${response.status} ${response.statusText}`);
30
+ }
31
+ // The server endpoint returns data — we just needed to verify the key works
32
+ // Extract product_id from the response headers or infer from key validation
33
+ // For now, we trust the key is valid and the server scopes by it
34
+ const data = await response.json();
35
+ return {
36
+ productId: "authenticated", // Server handles scoping via the key
37
+ apiKey,
38
+ baseUrl,
39
+ };
40
+ }
41
+ //# sourceMappingURL=auth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.js","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAQH,MAAM,gBAAgB,GAAG,yBAAyB,CAAC;AAEnD,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,SAAkB;IACnD,sCAAsC;IACtC,MAAM,MAAM,GAAG,SAAS,IAAI,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC;IAErD,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,IAAI,KAAK,CACb,oFAAoF;YACpF,qDAAqD,CACtD,CAAC;IACJ,CAAC;IAED,4CAA4C;IAC5C,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,YAAY,IAAI,gBAAgB,CAAC;IAE7D,kDAAkD;IAClD,0DAA0D;IAC1D,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,OAAO,mBAAmB,EAAE;QAC1D,OAAO,EAAE;YACP,aAAa,EAAE,MAAM;SACtB;KACF,CAAC,CAAC;IAEH,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;QAC5B,MAAM,IAAI,KAAK,CACb,sEAAsE;YACtE,kCAAkC,CACnC,CAAC;IACJ,CAAC;IAED,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QACjB,MAAM,IAAI,KAAK,CAAC,0BAA0B,QAAQ,CAAC,MAAM,IAAI,QAAQ,CAAC,UAAU,EAAE,CAAC,CAAC;IACtF,CAAC;IAED,4EAA4E;IAC5E,4EAA4E;IAC5E,iEAAiE;IACjE,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;IAEnC,OAAO;QACL,SAAS,EAAE,eAAe,EAAE,qCAAqC;QACjE,MAAM;QACN,OAAO;KACR,CAAC;AACJ,CAAC"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Project Discovery
3
+ *
4
+ * Before the agent starts, we need to know:
5
+ * 1. That the user is running from the right root directory
6
+ * 2. Which subdirectories are relevant to their app
7
+ */
8
+ export interface ProjectLayout {
9
+ rootDir: string;
10
+ directories: string[];
11
+ }
12
+ /**
13
+ * Discover the project layout by asking the user which directories matter.
14
+ *
15
+ * For CI mode, accepts --dirs flag instead of interactive prompts.
16
+ */
17
+ export declare function discoverProject(ci: boolean, dirsArg?: string[]): Promise<ProjectLayout>;
18
+ //# sourceMappingURL=discover.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"discover.d.ts","sourceRoot":"","sources":["../src/discover.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAMH,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,EAAE,CAAC;CACvB;AA0BD;;;;GAIG;AACH,wBAAsB,eAAe,CAAC,EAAE,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,aAAa,CAAC,CAoF7F"}
@@ -0,0 +1,148 @@
1
+ /**
2
+ * Project Discovery
3
+ *
4
+ * Before the agent starts, we need to know:
5
+ * 1. That the user is running from the right root directory
6
+ * 2. Which subdirectories are relevant to their app
7
+ */
8
+ import * as fs from "node:fs";
9
+ import * as path from "node:path";
10
+ import * as readline from "node:readline";
11
+ const IGNORED_DIRS = new Set([
12
+ "node_modules", ".git", ".github", ".vscode", ".idea",
13
+ "__pycache__", ".cache", ".next", ".nuxt", "dist", "build",
14
+ "venv", ".venv", "env", ".env", ".claude", ".cursor",
15
+ "coverage", ".nyc_output", ".turbo", ".vercel",
16
+ ]);
17
+ function rl() {
18
+ return readline.createInterface({
19
+ input: process.stdin,
20
+ output: process.stdout,
21
+ });
22
+ }
23
+ async function ask(prompt) {
24
+ const r = rl();
25
+ return new Promise((resolve) => {
26
+ r.question(prompt, (answer) => {
27
+ r.close();
28
+ resolve(answer.trim());
29
+ });
30
+ });
31
+ }
32
+ /**
33
+ * Discover the project layout by asking the user which directories matter.
34
+ *
35
+ * For CI mode, accepts --dirs flag instead of interactive prompts.
36
+ */
37
+ export async function discoverProject(ci, dirsArg) {
38
+ const rootDir = process.cwd();
39
+ // CI mode: use --dirs flag directly
40
+ if (ci && dirsArg && dirsArg.length > 0) {
41
+ const directories = dirsArg.map((d) => path.resolve(rootDir, d));
42
+ return { rootDir, directories };
43
+ }
44
+ // List subdirectories in cwd
45
+ const entries = fs.readdirSync(rootDir, { withFileTypes: true });
46
+ const subdirs = entries
47
+ .filter((e) => e.isDirectory() && !e.name.startsWith(".") && !IGNORED_DIRS.has(e.name))
48
+ .map((e) => e.name)
49
+ .sort();
50
+ // Also check if this looks like a single project (has package.json, requirements.txt, etc. at root)
51
+ const rootFiles = entries.map((e) => e.name);
52
+ const isSingleProject = rootFiles.includes("package.json") ||
53
+ rootFiles.includes("requirements.txt") ||
54
+ rootFiles.includes("pyproject.toml") ||
55
+ rootFiles.includes("go.mod") ||
56
+ rootFiles.includes("Cargo.toml") ||
57
+ rootFiles.includes("Gemfile");
58
+ console.log();
59
+ console.log(` \x1b[1mCurrent directory:\x1b[0m ${rootDir}`);
60
+ console.log();
61
+ if (subdirs.length === 0 && isSingleProject) {
62
+ // Single project at root — no need to ask
63
+ console.log(` \x1b[2mDetected single project at root.\x1b[0m`);
64
+ return { rootDir, directories: [rootDir] };
65
+ }
66
+ if (subdirs.length === 0) {
67
+ console.log(` \x1b[33m⚠\x1b[0m No subdirectories found. The agent will work with this directory.`);
68
+ return { rootDir, directories: [rootDir] };
69
+ }
70
+ // Show directories and ask which are relevant
71
+ console.log(` \x1b[1mFound these directories:\x1b[0m`);
72
+ console.log();
73
+ subdirs.forEach((dir, i) => {
74
+ // Show a hint about what's in each dir
75
+ const dirPath = path.join(rootDir, dir);
76
+ const hint = getDirectoryHint(dirPath);
77
+ console.log(` \x1b[36m${i + 1}.\x1b[0m ${dir}${hint ? ` \x1b[2m(${hint})\x1b[0m` : ""}`);
78
+ });
79
+ console.log();
80
+ console.log(` \x1b[2mThe envoy needs to read your codebase to generate an MCP server.`);
81
+ console.log(` Select the directories that are part of your app (frontend, backend, etc.).\x1b[0m`);
82
+ console.log();
83
+ const answer = await ask(` Enter numbers separated by commas (e.g. 1,3,4), or "all": `);
84
+ let selected;
85
+ if (answer.toLowerCase() === "all") {
86
+ selected = subdirs;
87
+ }
88
+ else {
89
+ const indices = answer
90
+ .split(",")
91
+ .map((s) => parseInt(s.trim(), 10) - 1)
92
+ .filter((i) => i >= 0 && i < subdirs.length);
93
+ if (indices.length === 0) {
94
+ console.log(` \x1b[33m⚠\x1b[0m No valid selection. Using all directories.`);
95
+ selected = subdirs;
96
+ }
97
+ else {
98
+ selected = indices.map((i) => subdirs[i]);
99
+ }
100
+ }
101
+ const directories = selected.map((d) => path.resolve(rootDir, d));
102
+ console.log();
103
+ console.log(` \x1b[32m✓\x1b[0m Selected: ${selected.join(", ")}`);
104
+ console.log();
105
+ return { rootDir, directories };
106
+ }
107
+ /**
108
+ * Quick hint about what a directory contains.
109
+ */
110
+ function getDirectoryHint(dirPath) {
111
+ try {
112
+ const files = fs.readdirSync(dirPath).slice(0, 50); // Don't read huge dirs
113
+ const has = (name) => files.includes(name);
114
+ if (has("package.json")) {
115
+ // Try to read the package name
116
+ try {
117
+ const pkg = JSON.parse(fs.readFileSync(path.join(dirPath, "package.json"), "utf-8"));
118
+ if (pkg.name)
119
+ return pkg.name;
120
+ }
121
+ catch { /* ignore */ }
122
+ return "Node.js";
123
+ }
124
+ if (has("requirements.txt") || has("pyproject.toml"))
125
+ return "Python";
126
+ if (has("go.mod"))
127
+ return "Go";
128
+ if (has("Cargo.toml"))
129
+ return "Rust";
130
+ if (has("Gemfile"))
131
+ return "Ruby";
132
+ if (has("pom.xml"))
133
+ return "Java";
134
+ if (has("build.gradle") || has("build.gradle.kts"))
135
+ return "Kotlin/Java";
136
+ if (has("Dockerfile") || has("docker-compose.yml"))
137
+ return "Docker";
138
+ if (has("manifest.json"))
139
+ return "Browser extension";
140
+ if (has("index.html") && !has("package.json"))
141
+ return "Static site";
142
+ return "";
143
+ }
144
+ catch {
145
+ return "";
146
+ }
147
+ }
148
+ //# sourceMappingURL=discover.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"discover.js","sourceRoot":"","sources":["../src/discover.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Crow Envoy CLI
4
+ *
5
+ * Usage:
6
+ * npx @usecrow/envoy # Generate MCP server from codebase
7
+ * npx @usecrow/envoy fix # Fix/iterate on existing MCP server
8
+ * npx @usecrow/envoy deploy # Deploy latest saved version
9
+ */
10
+ export {};
11
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA;;;;;;;GAOG"}
package/dist/index.js ADDED
@@ -0,0 +1,144 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Crow Envoy CLI
4
+ *
5
+ * Usage:
6
+ * npx @usecrow/envoy # Generate MCP server from codebase
7
+ * npx @usecrow/envoy fix # Fix/iterate on existing MCP server
8
+ * npx @usecrow/envoy deploy # Deploy latest saved version
9
+ */
10
+ import { authenticate } from "./auth.js";
11
+ import { runAgent } from "./agent.js";
12
+ import { discoverProject } from "./discover.js";
13
+ import { InteractiveUI } from "./ui/interactive.js";
14
+ import { CiUI } from "./ui/ci.js";
15
+ function parseArgs() {
16
+ const args = process.argv.slice(2);
17
+ let command = "generate";
18
+ let apiKey;
19
+ let ci = false;
20
+ let dirs;
21
+ for (let i = 0; i < args.length; i++) {
22
+ const arg = args[i];
23
+ if (arg === "fix") {
24
+ command = "fix";
25
+ }
26
+ else if (arg === "deploy") {
27
+ command = "deploy";
28
+ }
29
+ else if (arg === "--api-key" && i + 1 < args.length) {
30
+ apiKey = args[++i];
31
+ }
32
+ else if (arg === "--ci") {
33
+ ci = true;
34
+ }
35
+ else if (arg === "--dirs" && i + 1 < args.length) {
36
+ dirs = args[++i].split(",").map((d) => d.trim());
37
+ }
38
+ else if (arg === "--help" || arg === "-h") {
39
+ printHelp();
40
+ process.exit(0);
41
+ }
42
+ else if (arg === "--version" || arg === "-v") {
43
+ console.log("0.1.0");
44
+ process.exit(0);
45
+ }
46
+ }
47
+ return { command, apiKey, ci, dirs };
48
+ }
49
+ function printHelp() {
50
+ console.log(`
51
+ Crow Envoy - Generate MCP servers from your backend codebase
52
+
53
+ Usage:
54
+ npx @usecrow/envoy Generate an MCP server from your codebase
55
+ npx @usecrow/envoy fix Fix/iterate on an existing MCP server
56
+ npx @usecrow/envoy deploy Deploy the latest saved version
57
+
58
+ Options:
59
+ --api-key <key> Crow API key (or set CROW_API_KEY env var)
60
+ --ci CI mode: structured JSON output on stdout
61
+ --dirs <a,b,c> Comma-separated directories (CI mode, skips interactive prompt)
62
+ --help, -h Show this help message
63
+ --version, -v Show version number
64
+
65
+ Run this from the root directory that contains your project folders (backend, frontend, etc.).
66
+ The envoy will ask which directories are relevant before it starts.
67
+ `);
68
+ }
69
+ async function main() {
70
+ const args = parseArgs();
71
+ const ui = args.ci ? new CiUI() : new InteractiveUI();
72
+ try {
73
+ ui.welcome();
74
+ // Step 1: Discover project layout — ask which directories matter
75
+ if (args.command !== "deploy") {
76
+ console.log(` \x1b[1m\x1b[33mIMPORTANT:\x1b[0m Run this from the root directory that contains`);
77
+ console.log(` your project folders (backend, frontend, shared libs, etc.).`);
78
+ }
79
+ // Step 2: Authenticate
80
+ ui.status("Authenticating...");
81
+ const { productId, apiKey, baseUrl } = await authenticate(args.apiKey);
82
+ ui.authenticated(productId);
83
+ // Step 3: Handle deploy command separately (no agent needed)
84
+ if (args.command === "deploy") {
85
+ ui.status("Deploying latest version...");
86
+ const response = await fetch(`${baseUrl}/api/envoy/deploy`, {
87
+ method: "POST",
88
+ headers: { "X-Envoy-Key": apiKey },
89
+ });
90
+ if (!response.ok) {
91
+ const error = (await response.json());
92
+ throw new Error(error.detail || "Deploy failed");
93
+ }
94
+ const result = (await response.json());
95
+ ui.deployed(result.version, result.message);
96
+ return;
97
+ }
98
+ // Step 4: Discover project directories
99
+ const project = await discoverProject(args.ci, args.dirs);
100
+ // Step 5: For 'fix' command, fetch existing server + context
101
+ let existingServer = null;
102
+ if (args.command === "fix") {
103
+ ui.status("Fetching latest MCP server from Crow...");
104
+ const response = await fetch(`${baseUrl}/api/envoy/server`, {
105
+ headers: { "X-Envoy-Key": apiKey },
106
+ });
107
+ if (!response.ok) {
108
+ throw new Error("Failed to fetch existing server");
109
+ }
110
+ const data = (await response.json());
111
+ if (!data.exists) {
112
+ throw new Error("No MCP server found. Run 'npx @usecrow/envoy' first to generate one.");
113
+ }
114
+ existingServer = {
115
+ files: data.files,
116
+ version: data.version,
117
+ analysis: data.analysis,
118
+ tool_designs: data.tool_designs,
119
+ session_id: data.session_id,
120
+ };
121
+ if (data.session_id) {
122
+ ui.status(`Loaded MCP server v${data.version} (session resumable)`);
123
+ }
124
+ ui.status(`Loaded MCP server v${data.version}`);
125
+ }
126
+ // Step 6: Run the agent
127
+ ui.status(args.command === "fix" ? "Starting fix agent..." : "Starting generation agent...");
128
+ await runAgent({
129
+ command: args.command,
130
+ apiKey,
131
+ baseUrl,
132
+ existingServer,
133
+ project,
134
+ ui,
135
+ });
136
+ }
137
+ catch (error) {
138
+ const message = error instanceof Error ? error.message : String(error);
139
+ ui.error(message);
140
+ process.exit(1);
141
+ }
142
+ }
143
+ main();
144
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * deploy Tool
3
+ *
4
+ * Triggers deployment of the latest saved MCP server version.
5
+ */
6
+ import { z } from "zod";
7
+ export declare function createDeployTool(apiKey: string, baseUrl: string): import("@anthropic-ai/claude-agent-sdk").SdkMcpToolDefinition<{
8
+ confirm: z.ZodBoolean;
9
+ }>;
10
+ //# sourceMappingURL=deploy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deploy.d.ts","sourceRoot":"","sources":["../../src/tools/deploy.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM;;GAkE/D"}
@@ -0,0 +1,67 @@
1
+ /**
2
+ * deploy Tool
3
+ *
4
+ * Triggers deployment of the latest saved MCP server version.
5
+ */
6
+ import { tool } from "@anthropic-ai/claude-agent-sdk";
7
+ import { z } from "zod";
8
+ export function createDeployTool(apiKey, baseUrl) {
9
+ return tool("deploy", "Deploy the latest saved MCP server version to production. This marks the latest version as deployed and triggers the deploy agent.", {
10
+ confirm: z
11
+ .boolean()
12
+ .describe("Set to true to confirm deployment"),
13
+ }, async (args) => {
14
+ if (!args.confirm) {
15
+ return {
16
+ content: [
17
+ {
18
+ type: "text",
19
+ text: "Deployment cancelled. Set confirm=true to deploy.",
20
+ },
21
+ ],
22
+ };
23
+ }
24
+ try {
25
+ const response = await fetch(`${baseUrl}/api/envoy/deploy`, {
26
+ method: "POST",
27
+ headers: {
28
+ "X-Envoy-Key": apiKey,
29
+ },
30
+ });
31
+ if (!response.ok) {
32
+ const error = (await response.json());
33
+ return {
34
+ content: [
35
+ {
36
+ type: "text",
37
+ text: `Deploy failed: ${error.detail || response.statusText}`,
38
+ },
39
+ ],
40
+ isError: true,
41
+ };
42
+ }
43
+ const result = (await response.json());
44
+ return {
45
+ content: [
46
+ {
47
+ type: "text",
48
+ text: `Deployed version ${result.version}. ${result.message}`,
49
+ },
50
+ ],
51
+ };
52
+ }
53
+ catch (error) {
54
+ const message = error instanceof Error ? error.message : String(error);
55
+ return {
56
+ content: [
57
+ {
58
+ type: "text",
59
+ text: `Error deploying: ${message}`,
60
+ },
61
+ ],
62
+ isError: true,
63
+ };
64
+ }
65
+ });
66
+ }
67
+ //# sourceMappingURL=deploy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deploy.js","sourceRoot":"","sources":["../../src/tools/deploy.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,gCAAgC,CAAC;AACtD,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,MAAM,UAAU,gBAAgB,CAAC,MAAc,EAAE,OAAe;IAC9D,OAAO,IAAI,CACT,QAAQ,EACR,oIAAoI,EACpI;QACE,OAAO,EAAE,CAAC;aACP,OAAO,EAAE;aACT,QAAQ,CAAC,mCAAmC,CAAC;KACjD,EACD,KAAK,EAAE,IAAI,EAAE,EAAE;QACb,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;YAClB,OAAO;gBACL,OAAO,EAAE;oBACP;wBACE,IAAI,EAAE,MAAe;wBACrB,IAAI,EAAE,mDAAmD;qBAC1D;iBACF;aACF,CAAC;QACJ,CAAC;QAED,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,OAAO,mBAAmB,EAAE;gBAC1D,MAAM,EAAE,MAAM;gBACd,OAAO,EAAE;oBACP,aAAa,EAAE,MAAM;iBACtB;aACF,CAAC,CAAC;YAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;gBACjB,MAAM,KAAK,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAwB,CAAC;gBAC7D,OAAO;oBACL,OAAO,EAAE;wBACP;4BACE,IAAI,EAAE,MAAe;4BACrB,IAAI,EAAE,kBAAkB,KAAK,CAAC,MAAM,IAAI,QAAQ,CAAC,UAAU,EAAE;yBAC9D;qBACF;oBACD,OAAO,EAAE,IAAI;iBACd,CAAC;YACJ,CAAC;YAED,MAAM,MAAM,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAyC,CAAC;YAE/E,OAAO;gBACL,OAAO,EAAE;oBACP;wBACE,IAAI,EAAE,MAAe;wBACrB,IAAI,EAAE,oBAAoB,MAAM,CAAC,OAAO,KAAK,MAAM,CAAC,OAAO,EAAE;qBAC9D;iBACF;aACF,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YACvE,OAAO;gBACL,OAAO,EAAE;oBACP;wBACE,IAAI,EAAE,MAAe;wBACrB,IAAI,EAAE,oBAAoB,OAAO,EAAE;qBACpC;iBACF;gBACD,OAAO,EAAE,IAAI;aACd,CAAC;QACJ,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * save_to_crow Tool
3
+ *
4
+ * Uploads generated MCP server files to Crow's backend.
5
+ * Each call creates a new version (versions are never overwritten).
6
+ * Also persists the Agent SDK session_id for conversation resume.
7
+ */
8
+ import { z } from "zod";
9
+ /**
10
+ * Holds the current session ID. Set by agent.ts when it captures
11
+ * the session_id from SDK messages. The tool reads it at save time.
12
+ */
13
+ export declare const sessionState: {
14
+ sessionId: string;
15
+ };
16
+ export declare function createSaveToCrowTool(apiKey: string, baseUrl: string): import("@anthropic-ai/claude-agent-sdk").SdkMcpToolDefinition<{
17
+ files: z.ZodRecord<z.ZodString, z.ZodString>;
18
+ analysis: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
19
+ tool_designs: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
20
+ }>;
21
+ //# sourceMappingURL=save-to-crow.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"save-to-crow.d.ts","sourceRoot":"","sources":["../../src/tools/save-to-crow.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;;GAGG;AACH,eAAO,MAAM,YAAY;;CAAoB,CAAC;AAE9C,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM;;;;GAwEnE"}
@@ -0,0 +1,79 @@
1
+ /**
2
+ * save_to_crow Tool
3
+ *
4
+ * Uploads generated MCP server files to Crow's backend.
5
+ * Each call creates a new version (versions are never overwritten).
6
+ * Also persists the Agent SDK session_id for conversation resume.
7
+ */
8
+ import { tool } from "@anthropic-ai/claude-agent-sdk";
9
+ import { z } from "zod";
10
+ /**
11
+ * Holds the current session ID. Set by agent.ts when it captures
12
+ * the session_id from SDK messages. The tool reads it at save time.
13
+ */
14
+ export const sessionState = { sessionId: "" };
15
+ export function createSaveToCrowTool(apiKey, baseUrl) {
16
+ return tool("save_to_crow", "Save the generated MCP server files to Crow. Call this after generating or updating server.py and requirements.txt. Each save creates a new version.", {
17
+ files: z
18
+ .record(z.string(), z.string())
19
+ .describe('Map of filename to file content. Example: {"server.py": "...", "requirements.txt": "...", ".env.example": "..."}'),
20
+ analysis: z
21
+ .record(z.string(), z.unknown())
22
+ .optional()
23
+ .describe("Endpoint analysis/categorization from the discovery phase"),
24
+ tool_designs: z
25
+ .record(z.string(), z.unknown())
26
+ .optional()
27
+ .describe("MCP tool signatures from the design phase"),
28
+ }, async (args) => {
29
+ try {
30
+ const response = await fetch(`${baseUrl}/api/envoy/save`, {
31
+ method: "POST",
32
+ headers: {
33
+ "Content-Type": "application/json",
34
+ "X-Envoy-Key": apiKey,
35
+ },
36
+ body: JSON.stringify({
37
+ files: args.files,
38
+ analysis: args.analysis,
39
+ tool_designs: args.tool_designs,
40
+ session_id: sessionState.sessionId || null,
41
+ }),
42
+ });
43
+ if (!response.ok) {
44
+ const error = (await response.json());
45
+ return {
46
+ content: [
47
+ {
48
+ type: "text",
49
+ text: `Failed to save: ${error.detail || response.statusText}`,
50
+ },
51
+ ],
52
+ isError: true,
53
+ };
54
+ }
55
+ const result = (await response.json());
56
+ return {
57
+ content: [
58
+ {
59
+ type: "text",
60
+ text: `Successfully saved MCP server as version ${result.version}. ID: ${result.id}`,
61
+ },
62
+ ],
63
+ };
64
+ }
65
+ catch (error) {
66
+ const message = error instanceof Error ? error.message : String(error);
67
+ return {
68
+ content: [
69
+ {
70
+ type: "text",
71
+ text: `Error saving to Crow: ${message}`,
72
+ },
73
+ ],
74
+ isError: true,
75
+ };
76
+ }
77
+ });
78
+ }
79
+ //# sourceMappingURL=save-to-crow.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"save-to-crow.js","sourceRoot":"","sources":["../../src/tools/save-to-crow.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,gCAAgC,CAAC;AACtD,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;;GAGG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC;AAE9C,MAAM,UAAU,oBAAoB,CAAC,MAAc,EAAE,OAAe;IAClE,OAAO,IAAI,CACT,cAAc,EACd,sJAAsJ,EACtJ;QACE,KAAK,EAAE,CAAC;aACL,MAAM,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC;aAC9B,QAAQ,CACP,kHAAkH,CACnH;QACH,QAAQ,EAAE,CAAC;aACR,MAAM,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC;aAC/B,QAAQ,EAAE;aACV,QAAQ,CAAC,2DAA2D,CAAC;QACxE,YAAY,EAAE,CAAC;aACZ,MAAM,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC;aAC/B,QAAQ,EAAE;aACV,QAAQ,CAAC,2CAA2C,CAAC;KACzD,EACD,KAAK,EAAE,IAAI,EAAE,EAAE;QACb,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,OAAO,iBAAiB,EAAE;gBACxD,MAAM,EAAE,MAAM;gBACd,OAAO,EAAE;oBACP,cAAc,EAAE,kBAAkB;oBAClC,aAAa,EAAE,MAAM;iBACtB;gBACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;oBACnB,KAAK,EAAE,IAAI,CAAC,KAAK;oBACjB,QAAQ,EAAE,IAAI,CAAC,QAAQ;oBACvB,YAAY,EAAE,IAAI,CAAC,YAAY;oBAC/B,UAAU,EAAE,YAAY,CAAC,SAAS,IAAI,IAAI;iBAC3C,CAAC;aACH,CAAC,CAAC;YAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;gBACjB,MAAM,KAAK,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAwB,CAAC;gBAC7D,OAAO;oBACL,OAAO,EAAE;wBACP;4BACE,IAAI,EAAE,MAAe;4BACrB,IAAI,EAAE,mBAAmB,KAAK,CAAC,MAAM,IAAI,QAAQ,CAAC,UAAU,EAAE;yBAC/D;qBACF;oBACD,OAAO,EAAE,IAAI;iBACd,CAAC;YACJ,CAAC;YAED,MAAM,MAAM,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAoC,CAAC;YAE1E,OAAO;gBACL,OAAO,EAAE;oBACP;wBACE,IAAI,EAAE,MAAe;wBACrB,IAAI,EAAE,4CAA4C,MAAM,CAAC,OAAO,SAAS,MAAM,CAAC,EAAE,EAAE;qBACrF;iBACF;aACF,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YACvE,OAAO;gBACL,OAAO,EAAE;oBACP;wBACE,IAAI,EAAE,MAAe;wBACrB,IAAI,EAAE,yBAAyB,OAAO,EAAE;qBACzC;iBACF;gBACD,OAAO,EAAE,IAAI;aACd,CAAC;QACJ,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,35 @@
1
+ /**
2
+ * CI Mode UI
3
+ *
4
+ * Structured JSON line output for when an AI agent runs the envoy.
5
+ * Each line is a JSON object with a "type" field.
6
+ *
7
+ * Output format:
8
+ * {"type": "progress", "phase": "auth", "message": "Authenticating..."}
9
+ * {"type": "tool_use", "tool": "Read", "input": {"file_path": "..."}}
10
+ * {"type": "agent_message", "text": "Found 12 endpoints..."}
11
+ * {"type": "question", "id": "q1", "text": "Which auth pattern?", "options": ["JWT", "API Key"]}
12
+ * {"type": "error", "message": "..."}
13
+ * {"type": "success", "version": 1}
14
+ * {"type": "deployed", "version": 1}
15
+ *
16
+ * Input (stdin):
17
+ * {"answer_to": "q1", "value": "JWT"}
18
+ */
19
+ import type { UI } from "./interactive.js";
20
+ export declare class CiUI implements UI {
21
+ private emit;
22
+ welcome(): void;
23
+ status(message: string): void;
24
+ authenticated(productId: string): void;
25
+ agentMessage(text: string): void;
26
+ toolUse(name: string, input: Record<string, unknown>): void;
27
+ error(message: string): void;
28
+ deployed(version: number, message: string): void;
29
+ deployPrompt(): void;
30
+ progress(phase: string, message: string): void;
31
+ question(id: string, text: string, options?: string[]): void;
32
+ conversationReady(): void;
33
+ userPrompt(): Promise<string | null>;
34
+ }
35
+ //# sourceMappingURL=ci.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ci.d.ts","sourceRoot":"","sources":["../../src/ui/ci.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,kBAAkB,CAAC;AAE3C,qBAAa,IAAK,YAAW,EAAE;IAC7B,OAAO,CAAC,IAAI;IAIZ,OAAO,IAAI,IAAI;IAIf,MAAM,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAI7B,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;IAItC,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAIhC,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAI3D,KAAK,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAI5B,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI;IAIhD,YAAY,IAAI,IAAI;IAOpB,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI;IAI9C,QAAQ,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,EAAE,GAAG,IAAI;IAI5D,iBAAiB,IAAI,IAAI;IAInB,UAAU,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;CAI3C"}
package/dist/ui/ci.js ADDED
@@ -0,0 +1,64 @@
1
+ /**
2
+ * CI Mode UI
3
+ *
4
+ * Structured JSON line output for when an AI agent runs the envoy.
5
+ * Each line is a JSON object with a "type" field.
6
+ *
7
+ * Output format:
8
+ * {"type": "progress", "phase": "auth", "message": "Authenticating..."}
9
+ * {"type": "tool_use", "tool": "Read", "input": {"file_path": "..."}}
10
+ * {"type": "agent_message", "text": "Found 12 endpoints..."}
11
+ * {"type": "question", "id": "q1", "text": "Which auth pattern?", "options": ["JWT", "API Key"]}
12
+ * {"type": "error", "message": "..."}
13
+ * {"type": "success", "version": 1}
14
+ * {"type": "deployed", "version": 1}
15
+ *
16
+ * Input (stdin):
17
+ * {"answer_to": "q1", "value": "JWT"}
18
+ */
19
+ export class CiUI {
20
+ emit(event) {
21
+ process.stdout.write(JSON.stringify(event) + "\n");
22
+ }
23
+ welcome() {
24
+ this.emit({ type: "start", version: "0.1.0" });
25
+ }
26
+ status(message) {
27
+ this.emit({ type: "progress", message });
28
+ }
29
+ authenticated(productId) {
30
+ this.emit({ type: "progress", phase: "auth", message: "Authenticated" });
31
+ }
32
+ agentMessage(text) {
33
+ this.emit({ type: "agent_message", text });
34
+ }
35
+ toolUse(name, input) {
36
+ this.emit({ type: "tool_use", tool: name, input });
37
+ }
38
+ error(message) {
39
+ this.emit({ type: "error", message });
40
+ }
41
+ deployed(version, message) {
42
+ this.emit({ type: "deployed", version, message });
43
+ }
44
+ deployPrompt() {
45
+ this.emit({
46
+ type: "success",
47
+ message: "MCP server saved. Run 'npx @usecrow/envoy deploy' to deploy.",
48
+ });
49
+ }
50
+ progress(phase, message) {
51
+ this.emit({ type: "progress", phase, message });
52
+ }
53
+ question(id, text, options) {
54
+ this.emit({ type: "question", id, text, options });
55
+ }
56
+ conversationReady() {
57
+ // No-op in CI mode — runs once and exits
58
+ }
59
+ async userPrompt() {
60
+ // CI mode doesn't support interactive follow-ups
61
+ return null;
62
+ }
63
+ }
64
+ //# sourceMappingURL=ci.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ci.js","sourceRoot":"","sources":["../../src/ui/ci.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAIH,MAAM,OAAO,IAAI;IACP,IAAI,CAAC,KAA8B;QACzC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,CAAC;IACrD,CAAC;IAED,OAAO;QACL,IAAI,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC;IACjD,CAAC;IAED,MAAM,CAAC,OAAe;QACpB,IAAI,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,CAAC,CAAC;IAC3C,CAAC;IAED,aAAa,CAAC,SAAiB;QAC7B,IAAI,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,eAAe,EAAE,CAAC,CAAC;IAC3E,CAAC;IAED,YAAY,CAAC,IAAY;QACvB,IAAI,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,eAAe,EAAE,IAAI,EAAE,CAAC,CAAC;IAC7C,CAAC;IAED,OAAO,CAAC,IAAY,EAAE,KAA8B;QAClD,IAAI,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IACrD,CAAC;IAED,KAAK,CAAC,OAAe;QACnB,IAAI,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC;IACxC,CAAC;IAED,QAAQ,CAAC,OAAe,EAAE,OAAe;QACvC,IAAI,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC;IACpD,CAAC;IAED,YAAY;QACV,IAAI,CAAC,IAAI,CAAC;YACR,IAAI,EAAE,SAAS;YACf,OAAO,EAAE,8DAA8D;SACxE,CAAC,CAAC;IACL,CAAC;IAED,QAAQ,CAAC,KAAa,EAAE,OAAe;QACrC,IAAI,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,CAAC;IAClD,CAAC;IAED,QAAQ,CAAC,EAAU,EAAE,IAAY,EAAE,OAAkB;QACnD,IAAI,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC;IACrD,CAAC;IAED,iBAAiB;QACf,yCAAyC;IAC3C,CAAC;IAED,KAAK,CAAC,UAAU;QACd,iDAAiD;QACjD,OAAO,IAAI,CAAC;IACd,CAAC;CACF"}
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Interactive UI
3
+ *
4
+ * Rich terminal output for when a human runs the envoy.
5
+ * Uses ANSI escape codes for colors and formatting.
6
+ */
7
+ export interface UI {
8
+ welcome(): void;
9
+ status(message: string): void;
10
+ authenticated(productId: string): void;
11
+ agentMessage(text: string): void;
12
+ toolUse(name: string, input: Record<string, unknown>): void;
13
+ error(message: string): void;
14
+ deployed(version: number, message: string): void;
15
+ deployPrompt(): void;
16
+ progress(phase: string, message: string): void;
17
+ question(id: string, text: string, options?: string[]): void;
18
+ conversationReady(): void;
19
+ userPrompt(): Promise<string | null>;
20
+ }
21
+ export declare class InteractiveUI implements UI {
22
+ private spinnerInterval;
23
+ private spinnerFrames;
24
+ private spinnerIndex;
25
+ welcome(): void;
26
+ status(message: string): void;
27
+ authenticated(productId: string): void;
28
+ agentMessage(text: string): void;
29
+ toolUse(name: string, input: Record<string, unknown>): void;
30
+ error(message: string): void;
31
+ deployed(version: number, message: string): void;
32
+ deployPrompt(): void;
33
+ conversationReady(): void;
34
+ userPrompt(): Promise<string | null>;
35
+ progress(phase: string, message: string): void;
36
+ question(id: string, text: string, options?: string[]): void;
37
+ private startSpinner;
38
+ private stopSpinner;
39
+ }
40
+ //# sourceMappingURL=interactive.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"interactive.d.ts","sourceRoot":"","sources":["../../src/ui/interactive.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAcH,MAAM,WAAW,EAAE;IACjB,OAAO,IAAI,IAAI,CAAC;IAChB,MAAM,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACvC,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IAC5D,KAAK,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACjD,YAAY,IAAI,IAAI,CAAC;IACrB,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/C,QAAQ,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;IAC7D,iBAAiB,IAAI,IAAI,CAAC;IAC1B,UAAU,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;CACtC;AAED,qBAAa,aAAc,YAAW,EAAE;IACtC,OAAO,CAAC,eAAe,CAA+C;IACtE,OAAO,CAAC,aAAa,CAAsD;IAC3E,OAAO,CAAC,YAAY,CAAK;IAEzB,OAAO,IAAI,IAAI;IAOf,MAAM,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAK7B,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;IAKtC,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAWhC,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAqB3D,KAAK,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAO5B,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI;IAQhD,YAAY,IAAI,IAAI;IAapB,iBAAiB,IAAI,IAAI;IASnB,UAAU,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAwB1C,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI;IAK9C,QAAQ,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,EAAE,GAAG,IAAI;IAW5D,OAAO,CAAC,YAAY;IASpB,OAAO,CAAC,WAAW;CAOpB"}
@@ -0,0 +1,155 @@
1
+ /**
2
+ * Interactive UI
3
+ *
4
+ * Rich terminal output for when a human runs the envoy.
5
+ * Uses ANSI escape codes for colors and formatting.
6
+ */
7
+ import * as readline from "node:readline/promises";
8
+ // ANSI color codes
9
+ const RESET = "\x1b[0m";
10
+ const BOLD = "\x1b[1m";
11
+ const DIM = "\x1b[2m";
12
+ const GREEN = "\x1b[32m";
13
+ const YELLOW = "\x1b[33m";
14
+ const CYAN = "\x1b[36m";
15
+ const RED = "\x1b[31m";
16
+ const MAGENTA = "\x1b[35m";
17
+ export class InteractiveUI {
18
+ spinnerInterval = null;
19
+ spinnerFrames = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
20
+ spinnerIndex = 0;
21
+ welcome() {
22
+ console.log();
23
+ console.log(`${BOLD}${CYAN} Crow Envoy${RESET}`);
24
+ console.log(`${DIM} Generate MCP servers from your backend codebase${RESET}`);
25
+ console.log();
26
+ }
27
+ status(message) {
28
+ this.stopSpinner();
29
+ this.startSpinner(message);
30
+ }
31
+ authenticated(productId) {
32
+ this.stopSpinner();
33
+ console.log(` ${GREEN}✓${RESET} Authenticated`);
34
+ }
35
+ agentMessage(text) {
36
+ this.stopSpinner();
37
+ // Format agent output with indentation
38
+ const lines = text.split("\n");
39
+ for (const line of lines) {
40
+ if (line.trim()) {
41
+ console.log(` ${line}`);
42
+ }
43
+ }
44
+ }
45
+ toolUse(name, input) {
46
+ this.stopSpinner();
47
+ // Show tool usage in a compact format
48
+ if (name === "save_to_crow") {
49
+ const files = input.files;
50
+ const fileNames = files ? Object.keys(files).join(", ") : "files";
51
+ console.log(` ${MAGENTA}⚡${RESET} Saving to Crow: ${fileNames}`);
52
+ }
53
+ else if (name === "deploy") {
54
+ console.log(` ${MAGENTA}⚡${RESET} Deploying...`);
55
+ }
56
+ else if (name === "Read") {
57
+ console.log(` ${DIM}📖 Reading ${input.file_path || "file"}${RESET}`);
58
+ }
59
+ else if (name === "Glob" || name === "Grep") {
60
+ console.log(` ${DIM}🔍 Searching: ${input.pattern || "..."}${RESET}`);
61
+ }
62
+ else if (name === "Write" || name === "Edit") {
63
+ console.log(` ${DIM}✏️ Writing ${input.file_path || "file"}${RESET}`);
64
+ }
65
+ else if (name === "Bash") {
66
+ const cmd = String(input.command || "").slice(0, 60);
67
+ console.log(` ${DIM}$ ${cmd}${RESET}`);
68
+ }
69
+ }
70
+ error(message) {
71
+ this.stopSpinner();
72
+ console.log();
73
+ console.log(` ${RED}✗ Error:${RESET} ${message}`);
74
+ console.log();
75
+ }
76
+ deployed(version, message) {
77
+ this.stopSpinner();
78
+ console.log();
79
+ console.log(` ${GREEN}✓${RESET} ${BOLD}Deployed v${version}${RESET}`);
80
+ console.log(` ${DIM}${message}${RESET}`);
81
+ console.log();
82
+ }
83
+ deployPrompt() {
84
+ this.stopSpinner();
85
+ console.log();
86
+ console.log(` ${BOLD}MCP server saved successfully!${RESET}`);
87
+ console.log();
88
+ console.log(` To deploy, run:`);
89
+ console.log(` ${CYAN}npx @usecrow/envoy deploy${RESET}`);
90
+ console.log();
91
+ console.log(` To iterate/fix, run:`);
92
+ console.log(` ${CYAN}npx @usecrow/envoy fix${RESET}`);
93
+ console.log();
94
+ }
95
+ conversationReady() {
96
+ this.stopSpinner();
97
+ console.log();
98
+ console.log(` ${GREEN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${RESET}`);
99
+ console.log(` ${BOLD}Agent turn complete.${RESET} You can now chat to iterate.`);
100
+ console.log(` ${DIM}Type your message, or press Enter to exit.${RESET}`);
101
+ console.log(` ${GREEN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${RESET}`);
102
+ }
103
+ async userPrompt() {
104
+ this.stopSpinner();
105
+ // If stdin is not a TTY (piped input), skip the prompt
106
+ if (!process.stdin.isTTY) {
107
+ return null;
108
+ }
109
+ const rl = readline.createInterface({
110
+ input: process.stdin,
111
+ output: process.stdout,
112
+ });
113
+ try {
114
+ const answer = await rl.question(`\n ${CYAN}You:${RESET} `);
115
+ return answer.trim() || null;
116
+ }
117
+ catch {
118
+ // User pressed Ctrl+C or stdin closed
119
+ return null;
120
+ }
121
+ finally {
122
+ rl.close();
123
+ }
124
+ }
125
+ progress(phase, message) {
126
+ this.stopSpinner();
127
+ console.log(` ${YELLOW}▸${RESET} ${BOLD}${phase}${RESET}: ${message}`);
128
+ }
129
+ question(id, text, options) {
130
+ this.stopSpinner();
131
+ console.log();
132
+ console.log(` ${YELLOW}?${RESET} ${text}`);
133
+ if (options) {
134
+ options.forEach((opt, i) => {
135
+ console.log(` ${DIM}${i + 1}.${RESET} ${opt}`);
136
+ });
137
+ }
138
+ }
139
+ startSpinner(message) {
140
+ this.spinnerIndex = 0;
141
+ process.stdout.write(` ${this.spinnerFrames[0]} ${message}`);
142
+ this.spinnerInterval = setInterval(() => {
143
+ this.spinnerIndex = (this.spinnerIndex + 1) % this.spinnerFrames.length;
144
+ process.stdout.write(`\r ${this.spinnerFrames[this.spinnerIndex]} ${message}`);
145
+ }, 80);
146
+ }
147
+ stopSpinner() {
148
+ if (this.spinnerInterval) {
149
+ clearInterval(this.spinnerInterval);
150
+ this.spinnerInterval = null;
151
+ process.stdout.write("\r\x1b[K"); // Clear the line
152
+ }
153
+ }
154
+ }
155
+ //# sourceMappingURL=interactive.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"interactive.js","sourceRoot":"","sources":["../../src/ui/interactive.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,38 @@
1
+ {
2
+ "name": "@usecrow/envoy",
3
+ "version": "0.1.0",
4
+ "description": "CLI tool that reads your backend codebase, generates an MCP server, and pushes it to Crow",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "bin": {
8
+ "envoy": "dist/index.js"
9
+ },
10
+ "scripts": {
11
+ "build": "tsc",
12
+ "dev": "tsc --watch",
13
+ "start": "node dist/index.js",
14
+ "lint": "tsc --noEmit"
15
+ },
16
+ "keywords": ["crow", "mcp", "ai", "agent", "cli"],
17
+ "author": "Crow",
18
+ "license": "MIT",
19
+ "repository": {
20
+ "type": "git",
21
+ "url": "git+https://github.com/usecrow/crow-envoy.git"
22
+ },
23
+ "dependencies": {
24
+ "@anthropic-ai/claude-agent-sdk": "^0.2.51",
25
+ "zod": "^4.0.0"
26
+ },
27
+ "devDependencies": {
28
+ "@types/node": "^22.0.0",
29
+ "typescript": "^5.7.0"
30
+ },
31
+ "engines": {
32
+ "node": ">=18.0.0"
33
+ },
34
+ "files": [
35
+ "dist",
36
+ "README.md"
37
+ ]
38
+ }