@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.
- package/README.md +325 -0
- package/dist/analyzer.d.ts +66 -0
- package/dist/analyzer.js +333 -0
- package/dist/config.d.ts +44 -0
- package/dist/config.js +139 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.js +283 -0
- package/dist/login.d.ts +12 -0
- package/dist/login.js +149 -0
- package/dist/types.d.ts +43 -0
- package/dist/types.js +6 -0
- package/package.json +39 -0
package/dist/config.d.ts
ADDED
|
@@ -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
|
+
}
|
package/dist/index.d.ts
ADDED
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();
|
package/dist/login.d.ts
ADDED
|
@@ -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
|
+
}
|
package/dist/types.d.ts
ADDED
|
@@ -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
|
+
}
|