@kite-copilot/cli 1.0.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.
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Configuration management for Kite CLI
3
+ * Handles reading/writing credentials to ~/.kite/config.json
4
+ */
5
+ export interface KiteConfig {
6
+ token: string;
7
+ org_id: string;
8
+ api_config_id: string;
9
+ email?: string;
10
+ org_name?: string;
11
+ backend_url: string;
12
+ }
13
+ /**
14
+ * Load configuration from ~/.kite/config.json
15
+ * @returns The config object or null if not found
16
+ */
17
+ export declare function loadConfig(): KiteConfig | null;
18
+ /**
19
+ * Save configuration to ~/.kite/config.json
20
+ * @param config - The configuration to save
21
+ */
22
+ export declare function saveConfig(config: KiteConfig): void;
23
+ /**
24
+ * Clear (delete) the configuration file
25
+ */
26
+ export declare function clearConfig(): void;
27
+ /**
28
+ * Check if user is logged in (valid config exists)
29
+ */
30
+ export declare function isLoggedIn(): boolean;
31
+ /**
32
+ * Get the config file path (for display purposes)
33
+ */
34
+ export declare function getConfigPath(): string;
35
+ /**
36
+ * Save rejected mappings to ~/.kite/rejected/<timestamp>_mapping.json
37
+ * @param data - The mapping data to save
38
+ * @returns The path where the file was saved
39
+ */
40
+ export declare function saveRejectedMapping(data: unknown): string;
41
+ /**
42
+ * Get the rejected mappings directory path
43
+ */
44
+ export declare function getRejectedDir(): string;
package/dist/config.js ADDED
@@ -0,0 +1,139 @@
1
+ "use strict";
2
+ /**
3
+ * Configuration management for Kite CLI
4
+ * Handles reading/writing credentials to ~/.kite/config.json
5
+ */
6
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
7
+ if (k2 === undefined) k2 = k;
8
+ var desc = Object.getOwnPropertyDescriptor(m, k);
9
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
10
+ desc = { enumerable: true, get: function() { return m[k]; } };
11
+ }
12
+ Object.defineProperty(o, k2, desc);
13
+ }) : (function(o, m, k, k2) {
14
+ if (k2 === undefined) k2 = k;
15
+ o[k2] = m[k];
16
+ }));
17
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
18
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
19
+ }) : function(o, v) {
20
+ o["default"] = v;
21
+ });
22
+ var __importStar = (this && this.__importStar) || (function () {
23
+ var ownKeys = function(o) {
24
+ ownKeys = Object.getOwnPropertyNames || function (o) {
25
+ var ar = [];
26
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
27
+ return ar;
28
+ };
29
+ return ownKeys(o);
30
+ };
31
+ return function (mod) {
32
+ if (mod && mod.__esModule) return mod;
33
+ var result = {};
34
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
35
+ __setModuleDefault(result, mod);
36
+ return result;
37
+ };
38
+ })();
39
+ Object.defineProperty(exports, "__esModule", { value: true });
40
+ exports.loadConfig = loadConfig;
41
+ exports.saveConfig = saveConfig;
42
+ exports.clearConfig = clearConfig;
43
+ exports.isLoggedIn = isLoggedIn;
44
+ exports.getConfigPath = getConfigPath;
45
+ exports.saveRejectedMapping = saveRejectedMapping;
46
+ exports.getRejectedDir = getRejectedDir;
47
+ const fs = __importStar(require("node:fs"));
48
+ const path = __importStar(require("node:path"));
49
+ const os = __importStar(require("node:os"));
50
+ const CONFIG_DIR = path.join(os.homedir(), ".kite");
51
+ const CONFIG_FILE = path.join(CONFIG_DIR, "config.json");
52
+ const REJECTED_DIR = path.join(CONFIG_DIR, "rejected");
53
+ /**
54
+ * Ensure the config directory exists
55
+ */
56
+ function ensureConfigDir() {
57
+ if (!fs.existsSync(CONFIG_DIR)) {
58
+ fs.mkdirSync(CONFIG_DIR, { recursive: true, mode: 0o700 });
59
+ }
60
+ }
61
+ /**
62
+ * Load configuration from ~/.kite/config.json
63
+ * @returns The config object or null if not found
64
+ */
65
+ function loadConfig() {
66
+ try {
67
+ if (!fs.existsSync(CONFIG_FILE)) {
68
+ return null;
69
+ }
70
+ const content = fs.readFileSync(CONFIG_FILE, "utf-8");
71
+ return JSON.parse(content);
72
+ }
73
+ catch {
74
+ return null;
75
+ }
76
+ }
77
+ /**
78
+ * Save configuration to ~/.kite/config.json
79
+ * @param config - The configuration to save
80
+ */
81
+ function saveConfig(config) {
82
+ ensureConfigDir();
83
+ fs.writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2), {
84
+ mode: 0o600, // Read/write for owner only
85
+ });
86
+ }
87
+ /**
88
+ * Clear (delete) the configuration file
89
+ */
90
+ function clearConfig() {
91
+ try {
92
+ if (fs.existsSync(CONFIG_FILE)) {
93
+ fs.unlinkSync(CONFIG_FILE);
94
+ }
95
+ }
96
+ catch {
97
+ // Ignore errors when clearing
98
+ }
99
+ }
100
+ /**
101
+ * Check if user is logged in (valid config exists)
102
+ */
103
+ function isLoggedIn() {
104
+ const config = loadConfig();
105
+ return config !== null && !!config.token && !!config.org_id;
106
+ }
107
+ /**
108
+ * Get the config file path (for display purposes)
109
+ */
110
+ function getConfigPath() {
111
+ return CONFIG_FILE;
112
+ }
113
+ /**
114
+ * Ensure the rejected directory exists
115
+ */
116
+ function ensureRejectedDir() {
117
+ if (!fs.existsSync(REJECTED_DIR)) {
118
+ fs.mkdirSync(REJECTED_DIR, { recursive: true, mode: 0o700 });
119
+ }
120
+ }
121
+ /**
122
+ * Save rejected mappings to ~/.kite/rejected/<timestamp>_mapping.json
123
+ * @param data - The mapping data to save
124
+ * @returns The path where the file was saved
125
+ */
126
+ function saveRejectedMapping(data) {
127
+ ensureRejectedDir();
128
+ const timestamp = new Date().toISOString().replace(/[:.]/g, "-");
129
+ const filename = `${timestamp}_mapping.json`;
130
+ const filepath = path.join(REJECTED_DIR, filename);
131
+ fs.writeFileSync(filepath, JSON.stringify(data, null, 2), { mode: 0o600 });
132
+ return filepath;
133
+ }
134
+ /**
135
+ * Get the rejected mappings directory path
136
+ */
137
+ function getRejectedDir() {
138
+ return REJECTED_DIR;
139
+ }
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Kite CLI - Main Entry Point
4
+ *
5
+ * Commands:
6
+ * kite login - Authenticate with Kite
7
+ * kite logout - Clear stored credentials
8
+ * kite map - Analyze frontend codebase
9
+ */
10
+ export {};
package/dist/index.js ADDED
@@ -0,0 +1,283 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ /**
4
+ * Kite CLI - Main Entry Point
5
+ *
6
+ * Commands:
7
+ * kite login - Authenticate with Kite
8
+ * kite logout - Clear stored credentials
9
+ * kite map - Analyze frontend codebase
10
+ */
11
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
12
+ if (k2 === undefined) k2 = k;
13
+ var desc = Object.getOwnPropertyDescriptor(m, k);
14
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
15
+ desc = { enumerable: true, get: function() { return m[k]; } };
16
+ }
17
+ Object.defineProperty(o, k2, desc);
18
+ }) : (function(o, m, k, k2) {
19
+ if (k2 === undefined) k2 = k;
20
+ o[k2] = m[k];
21
+ }));
22
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
23
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
24
+ }) : function(o, v) {
25
+ o["default"] = v;
26
+ });
27
+ var __importStar = (this && this.__importStar) || (function () {
28
+ var ownKeys = function(o) {
29
+ ownKeys = Object.getOwnPropertyNames || function (o) {
30
+ var ar = [];
31
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
32
+ return ar;
33
+ };
34
+ return ownKeys(o);
35
+ };
36
+ return function (mod) {
37
+ if (mod && mod.__esModule) return mod;
38
+ var result = {};
39
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
40
+ __setModuleDefault(result, mod);
41
+ return result;
42
+ };
43
+ })();
44
+ var __importDefault = (this && this.__importDefault) || function (mod) {
45
+ return (mod && mod.__esModule) ? mod : { "default": mod };
46
+ };
47
+ Object.defineProperty(exports, "__esModule", { value: true });
48
+ const commander_1 = require("commander");
49
+ const chalk_1 = __importDefault(require("chalk"));
50
+ const ora_1 = __importDefault(require("ora"));
51
+ const readline = __importStar(require("node:readline"));
52
+ const config_js_1 = require("./config.js");
53
+ const login_js_1 = require("./login.js");
54
+ const analyzer_js_1 = require("./analyzer.js");
55
+ const program = new commander_1.Command();
56
+ /**
57
+ * Prompt user for yes/no confirmation
58
+ */
59
+ async function promptYesNo(question) {
60
+ const rl = readline.createInterface({
61
+ input: process.stdin,
62
+ output: process.stdout,
63
+ });
64
+ return new Promise((resolve) => {
65
+ rl.question(question, (answer) => {
66
+ rl.close();
67
+ const normalized = answer.trim().toLowerCase();
68
+ resolve(normalized === "y" || normalized === "yes");
69
+ });
70
+ });
71
+ }
72
+ program
73
+ .name("kite")
74
+ .description("Kite CLI - Analyze frontend codebases and map API calls")
75
+ .version("1.0.0");
76
+ // Login command
77
+ program
78
+ .command("login")
79
+ .description("Authenticate with Kite")
80
+ .option("--backend-url <url>", "Kite backend URL")
81
+ .action(async (options) => {
82
+ await (0, login_js_1.login)(options.backendUrl);
83
+ });
84
+ // Logout command
85
+ program
86
+ .command("logout")
87
+ .description("Clear stored credentials")
88
+ .action(async () => {
89
+ await (0, login_js_1.logout)();
90
+ });
91
+ // Map command - analyze frontend codebase
92
+ program
93
+ .command("map")
94
+ .description("Analyze a frontend codebase to discover API mappings")
95
+ .argument("<path>", "Path to the frontend codebase")
96
+ .option("-o, --output <file>", "Output JSON file path (for local save)")
97
+ .option("-q, --quiet", "Suppress terminal visualization")
98
+ .option("-v, --verbose", "Show verbose debug output")
99
+ .option("--timeout <seconds>", "Analysis timeout in seconds", "300")
100
+ .option("--no-prompt", "Skip confirmation prompt and save locally")
101
+ .action(async (codebasePath, options) => {
102
+ const quiet = options.quiet || false;
103
+ const verbose = options.verbose || false;
104
+ const skipPrompt = options.prompt === false;
105
+ // Check Claude CLI is available
106
+ const spinner = (0, ora_1.default)();
107
+ if (!quiet) {
108
+ spinner.start("Checking Claude CLI...");
109
+ }
110
+ const claudeAvailable = await (0, analyzer_js_1.checkClaudeAvailable)();
111
+ if (!claudeAvailable) {
112
+ if (!quiet)
113
+ spinner.fail("Claude CLI not found");
114
+ console.log(chalk_1.default.red("\nāœ— Claude CLI is required for analysis.\n"));
115
+ console.log(chalk_1.default.gray(" Install it with: npm install -g @anthropic-ai/claude-cli\n"));
116
+ process.exit(1);
117
+ }
118
+ if (!quiet)
119
+ spinner.succeed("Claude CLI found");
120
+ // Run analysis
121
+ if (!quiet) {
122
+ spinner.start(`Analyzing codebase: ${codebasePath}`);
123
+ }
124
+ if (verbose) {
125
+ console.log(chalk_1.default.gray(`[DEBUG] Path: ${codebasePath}`));
126
+ console.log(chalk_1.default.gray(`[DEBUG] Timeout: ${options.timeout}s`));
127
+ }
128
+ try {
129
+ const result = await (0, analyzer_js_1.analyzeWithClaude)(codebasePath, {
130
+ timeout: parseInt(options.timeout, 10),
131
+ verbose,
132
+ });
133
+ if (!quiet) {
134
+ spinner.succeed("Analysis complete");
135
+ }
136
+ if (verbose) {
137
+ console.log(chalk_1.default.gray(`[DEBUG] Found ${result.routes.length} routes`));
138
+ console.log(chalk_1.default.gray(`[DEBUG] Found ${result.api_calls.length} API calls`));
139
+ console.log(chalk_1.default.gray(`[DEBUG] Generated ${result.mappings.length} mappings`));
140
+ }
141
+ // Display results
142
+ if (!quiet) {
143
+ console.log();
144
+ console.log(chalk_1.default.bold("šŸ“Š Analysis Results"));
145
+ console.log(chalk_1.default.gray("─".repeat(40)));
146
+ // Routes
147
+ console.log(chalk_1.default.cyan(`\nRoutes (${result.routes.length}):`));
148
+ for (const route of result.routes) {
149
+ console.log(` • ${route.route_name} → ${route.component_name}`);
150
+ console.log(chalk_1.default.gray(` ${route.file_path}`));
151
+ }
152
+ // API Calls
153
+ console.log(chalk_1.default.cyan(`\nAPI Calls (${result.api_calls.length}):`));
154
+ for (const call of result.api_calls) {
155
+ console.log(` • ${call.method} ${call.endpoint}`);
156
+ console.log(chalk_1.default.gray(` ${call.component_file}`));
157
+ }
158
+ // Mappings
159
+ console.log(chalk_1.default.cyan(`\nMappings (${result.mappings.length}):`));
160
+ for (const mapping of result.mappings) {
161
+ console.log(` • ${mapping.tool_name} → ${mapping.api_endpoint}`);
162
+ if (mapping.navigation_page) {
163
+ console.log(chalk_1.default.gray(` Page: ${mapping.navigation_page}`));
164
+ }
165
+ }
166
+ console.log();
167
+ }
168
+ // Summary
169
+ if (!quiet) {
170
+ console.log();
171
+ console.log(chalk_1.default.bold("Summary"));
172
+ console.log(chalk_1.default.gray("─".repeat(40)));
173
+ console.log(` Routes: ${result.routes.length}`);
174
+ console.log(` API Calls: ${result.api_calls.length}`);
175
+ console.log(` Mappings: ${result.mappings.length}`);
176
+ console.log();
177
+ }
178
+ // Handle save decision
179
+ if (skipPrompt) {
180
+ // --no-prompt: save locally
181
+ const outputPath = options.output || "kite-mappings.json";
182
+ (0, analyzer_js_1.saveResultToFile)(result, outputPath);
183
+ if (!quiet) {
184
+ console.log(chalk_1.default.green(`āœ“ Saved mappings to: ${outputPath}`));
185
+ }
186
+ }
187
+ else {
188
+ // Prompt user for confirmation
189
+ console.log();
190
+ const shouldUpload = await promptYesNo(chalk_1.default.cyan("Save mappings to Kite? (y/n): "));
191
+ if (shouldUpload) {
192
+ // Check if logged in
193
+ if (!(0, config_js_1.isLoggedIn)()) {
194
+ console.log(chalk_1.default.yellow("\n⚠ Not logged in. Run 'kite login' first to upload mappings."));
195
+ // Save to rejected as fallback
196
+ const rejectedPath = (0, config_js_1.saveRejectedMapping)(result);
197
+ console.log(chalk_1.default.gray(` Saved locally to: ${rejectedPath}\n`));
198
+ process.exit(1);
199
+ }
200
+ const config = (0, config_js_1.loadConfig)();
201
+ if (!quiet) {
202
+ spinner.start("Uploading mappings to Kite...");
203
+ }
204
+ try {
205
+ const uploadResult = await (0, analyzer_js_1.uploadMappings)(result, {
206
+ backendUrl: config.backend_url,
207
+ token: config.token,
208
+ orgId: config.org_id,
209
+ apiConfigId: config.api_config_id,
210
+ });
211
+ if (!quiet) {
212
+ spinner.succeed(`Uploaded ${uploadResult.mappings_uploaded} mappings ` +
213
+ `(merged: ${uploadResult.mappings_merged}, skipped: ${uploadResult.mappings_skipped})`);
214
+ }
215
+ }
216
+ catch (uploadError) {
217
+ if (!quiet)
218
+ spinner.fail("Upload failed");
219
+ console.log(chalk_1.default.red(`\nāœ— ${uploadError.message}`));
220
+ // Save to rejected on upload failure
221
+ const rejectedPath = (0, config_js_1.saveRejectedMapping)(result);
222
+ console.log(chalk_1.default.gray(` Saved locally to: ${rejectedPath}\n`));
223
+ process.exit(1);
224
+ }
225
+ }
226
+ else {
227
+ // User declined - save to rejected folder
228
+ const rejectedPath = (0, config_js_1.saveRejectedMapping)(result);
229
+ if (!quiet) {
230
+ console.log(chalk_1.default.yellow(`\nāœ“ Mappings saved locally to: ${rejectedPath}`));
231
+ }
232
+ }
233
+ }
234
+ console.log();
235
+ }
236
+ catch (error) {
237
+ if (!quiet)
238
+ spinner.fail("Analysis failed");
239
+ if (error instanceof analyzer_js_1.ClaudeNotFoundError) {
240
+ console.log(chalk_1.default.red(`\nāœ— ${error.message}\n`));
241
+ console.log(chalk_1.default.gray(" Install Claude CLI: npm install -g @anthropic-ai/claude-cli\n"));
242
+ }
243
+ else if (error instanceof analyzer_js_1.ClaudeTimeoutError) {
244
+ console.log(chalk_1.default.red(`\nāœ— ${error.message}\n`));
245
+ console.log(chalk_1.default.gray(" Try increasing the timeout with --timeout\n"));
246
+ }
247
+ else if (error instanceof analyzer_js_1.ClaudeParseError) {
248
+ console.log(chalk_1.default.red(`\nāœ— Failed to parse Claude response\n`));
249
+ if (verbose) {
250
+ console.log(chalk_1.default.gray(` ${error.message}\n`));
251
+ }
252
+ }
253
+ else if (error instanceof analyzer_js_1.AnalyzerError) {
254
+ console.log(chalk_1.default.red(`\nāœ— ${error.message}\n`));
255
+ }
256
+ else {
257
+ console.log(chalk_1.default.red(`\nāœ— ${error.message}\n`));
258
+ }
259
+ process.exit(1);
260
+ }
261
+ });
262
+ // Status command - show current login status
263
+ program
264
+ .command("status")
265
+ .description("Show current login status")
266
+ .action(() => {
267
+ const config = (0, config_js_1.loadConfig)();
268
+ if (!config || !config.token) {
269
+ console.log(chalk_1.default.yellow("\n⚠ Not logged in\n"));
270
+ console.log(chalk_1.default.gray(" Run 'kite login' to authenticate.\n"));
271
+ return;
272
+ }
273
+ console.log(chalk_1.default.green("\nāœ“ Logged in\n"));
274
+ if (config.email) {
275
+ console.log(` Email: ${chalk_1.default.bold(config.email)}`);
276
+ }
277
+ if (config.org_name) {
278
+ console.log(` Organization: ${chalk_1.default.bold(config.org_name)}`);
279
+ }
280
+ console.log(` Config: ${chalk_1.default.gray((0, config_js_1.getConfigPath)())}`);
281
+ console.log();
282
+ });
283
+ program.parse();
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Login flow for Kite CLI
3
+ * Prompts for token only, fetches user info from backend
4
+ */
5
+ /**
6
+ * Run the login flow
7
+ */
8
+ export declare function login(backendUrl?: string): Promise<void>;
9
+ /**
10
+ * Run the logout flow
11
+ */
12
+ export declare function logout(): Promise<void>;
package/dist/login.js ADDED
@@ -0,0 +1,149 @@
1
+ "use strict";
2
+ /**
3
+ * Login flow for Kite CLI
4
+ * Prompts for token only, fetches user info from backend
5
+ */
6
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
7
+ if (k2 === undefined) k2 = k;
8
+ var desc = Object.getOwnPropertyDescriptor(m, k);
9
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
10
+ desc = { enumerable: true, get: function() { return m[k]; } };
11
+ }
12
+ Object.defineProperty(o, k2, desc);
13
+ }) : (function(o, m, k, k2) {
14
+ if (k2 === undefined) k2 = k;
15
+ o[k2] = m[k];
16
+ }));
17
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
18
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
19
+ }) : function(o, v) {
20
+ o["default"] = v;
21
+ });
22
+ var __importStar = (this && this.__importStar) || (function () {
23
+ var ownKeys = function(o) {
24
+ ownKeys = Object.getOwnPropertyNames || function (o) {
25
+ var ar = [];
26
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
27
+ return ar;
28
+ };
29
+ return ownKeys(o);
30
+ };
31
+ return function (mod) {
32
+ if (mod && mod.__esModule) return mod;
33
+ var result = {};
34
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
35
+ __setModuleDefault(result, mod);
36
+ return result;
37
+ };
38
+ })();
39
+ var __importDefault = (this && this.__importDefault) || function (mod) {
40
+ return (mod && mod.__esModule) ? mod : { "default": mod };
41
+ };
42
+ Object.defineProperty(exports, "__esModule", { value: true });
43
+ exports.login = login;
44
+ exports.logout = logout;
45
+ const readline = __importStar(require("node:readline"));
46
+ const chalk_1 = __importDefault(require("chalk"));
47
+ const ora_1 = __importDefault(require("ora"));
48
+ const config_js_1 = require("./config.js");
49
+ const DEFAULT_BACKEND_URL = "http://0.0.0.0:5002";
50
+ /**
51
+ * Prompt for user input (with optional masking)
52
+ */
53
+ async function prompt(question, mask = false) {
54
+ const rl = readline.createInterface({
55
+ input: process.stdin,
56
+ output: process.stdout,
57
+ });
58
+ return new Promise((resolve) => {
59
+ // For masked input, we'd need to handle it differently
60
+ // For simplicity, we'll just use regular input
61
+ rl.question(question, (answer) => {
62
+ rl.close();
63
+ resolve(answer.trim());
64
+ });
65
+ });
66
+ }
67
+ /**
68
+ * Fetch user info from backend using the token
69
+ */
70
+ async function fetchUserInfo(token, backendUrl) {
71
+ const url = `${backendUrl}/api/auth/me`;
72
+ console.log(chalk_1.default.gray("[DEBUG] Fetching user info from:", url));
73
+ const response = await fetch(url, {
74
+ method: "GET",
75
+ headers: {
76
+ Authorization: `Bearer ${token}`,
77
+ "Content-Type": "application/json",
78
+ },
79
+ });
80
+ console.log(chalk_1.default.gray("[DEBUG] Response status:", response.status));
81
+ if (response.status === 401) {
82
+ throw new Error("Invalid token. Please check your token and try again.");
83
+ }
84
+ if (response.status === 403) {
85
+ throw new Error("Access denied. Your token may not have sufficient permissions.");
86
+ }
87
+ if (!response.ok) {
88
+ const text = await response.text();
89
+ throw new Error(`Failed to authenticate: ${response.status} ${text}`);
90
+ }
91
+ return (await response.json());
92
+ }
93
+ /**
94
+ * Run the login flow
95
+ */
96
+ async function login(backendUrl) {
97
+ const url = DEFAULT_BACKEND_URL;
98
+ console.log(chalk_1.default.bold("\n🪁 Kite CLI Login\n"));
99
+ console.log(chalk_1.default.gray("Get your token from the Kite dashboard: https://app.kite.com/settings\n"));
100
+ // Prompt for token
101
+ const token = await prompt(chalk_1.default.cyan("? ") + "Enter your Kite token: ");
102
+ if (!token) {
103
+ console.log(chalk_1.default.red("\nāœ— Token is required"));
104
+ process.exit(1);
105
+ }
106
+ // Fetch user info
107
+ const spinner = (0, ora_1.default)("Fetching account info...").start();
108
+ try {
109
+ const userInfo = await fetchUserInfo(token, url);
110
+ spinner.succeed("Account verified");
111
+ // Save config
112
+ const config = {
113
+ token,
114
+ org_id: userInfo.org_id,
115
+ api_config_id: userInfo.api_config_id,
116
+ email: userInfo.email,
117
+ org_name: userInfo.org_name,
118
+ backend_url: url,
119
+ };
120
+ (0, config_js_1.saveConfig)(config);
121
+ // Success message
122
+ console.log();
123
+ if (userInfo.email && userInfo.org_name) {
124
+ console.log(chalk_1.default.green(`āœ“ Logged in as ${chalk_1.default.bold(userInfo.email)} (${userInfo.org_name})`));
125
+ }
126
+ else if (userInfo.email) {
127
+ console.log(chalk_1.default.green(`āœ“ Logged in as ${chalk_1.default.bold(userInfo.email)}`));
128
+ }
129
+ else {
130
+ console.log(chalk_1.default.green("āœ“ Logged in successfully"));
131
+ }
132
+ console.log(chalk_1.default.gray(` Credentials saved to ${(0, config_js_1.getConfigPath)()}`));
133
+ console.log();
134
+ }
135
+ catch (error) {
136
+ spinner.fail("Authentication failed");
137
+ console.log();
138
+ console.log(chalk_1.default.red(`āœ— ${error.message}`));
139
+ process.exit(1);
140
+ }
141
+ }
142
+ /**
143
+ * Run the logout flow
144
+ */
145
+ async function logout() {
146
+ const { clearConfig } = await import("./config.js");
147
+ clearConfig();
148
+ console.log(chalk_1.default.green("\nāœ“ Logged out successfully\n"));
149
+ }
@@ -0,0 +1,43 @@
1
+ /**
2
+ * TypeScript interfaces for frontend analysis results
3
+ * Mirrors the Python dataclasses in models.py
4
+ */
5
+ export interface FrontendRoute {
6
+ route_name: string;
7
+ file_path: string;
8
+ component_name: string;
9
+ }
10
+ export interface FrontendApiCall {
11
+ endpoint: string;
12
+ method: string;
13
+ component_file: string;
14
+ action_form_type: string | null;
15
+ }
16
+ export interface FrontendMapping {
17
+ tool_name: string;
18
+ api_endpoint: string;
19
+ navigation_page: string | null;
20
+ action_form_type: string | null;
21
+ frontend_component: string | null;
22
+ frontend_file_path: string | null;
23
+ }
24
+ export interface FrontendAnalysisResult {
25
+ version: string;
26
+ generated_at: string;
27
+ codebase_path: string;
28
+ routes: FrontendRoute[];
29
+ api_calls: FrontendApiCall[];
30
+ mappings: FrontendMapping[];
31
+ }
32
+ export interface AnalyzeOptions {
33
+ timeout?: number;
34
+ verbose?: boolean;
35
+ claudePath?: string;
36
+ }
37
+ export interface UploadResult {
38
+ success: boolean;
39
+ mappings_uploaded: number;
40
+ mappings_merged: number;
41
+ mappings_skipped: number;
42
+ message: string;
43
+ }
package/dist/types.js ADDED
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ /**
3
+ * TypeScript interfaces for frontend analysis results
4
+ * Mirrors the Python dataclasses in models.py
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });