openkitt 0.3.3 → 0.3.5
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/dist/cli.js +372 -40
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -2583,9 +2583,12 @@ var exports_config = {};
|
|
|
2583
2583
|
__export(exports_config, {
|
|
2584
2584
|
updateLlmModel: () => updateLlmModel,
|
|
2585
2585
|
storeLlmCredentials: () => storeLlmCredentials,
|
|
2586
|
+
storeCopilotCredentials: () => storeCopilotCredentials,
|
|
2586
2587
|
isLlmConfigured: () => isLlmConfigured,
|
|
2587
2588
|
getLlmConfig: () => getLlmConfig,
|
|
2588
2589
|
getLlmApiKey: () => getLlmApiKey,
|
|
2590
|
+
getCopilotToken: () => getCopilotToken,
|
|
2591
|
+
exchangeCopilotToken: () => exchangeCopilotToken,
|
|
2589
2592
|
clearLlmCredentials: () => clearLlmCredentials
|
|
2590
2593
|
});
|
|
2591
2594
|
import { chmodSync, existsSync as existsSync3, mkdirSync as mkdirSync2, readFileSync as readFileSync2, renameSync as renameSync2, statSync as statSync2, unlinkSync, writeFileSync as writeFileSync2 } from "node:fs";
|
|
@@ -2656,7 +2659,10 @@ function writeConfig(config) {
|
|
|
2656
2659
|
}
|
|
2657
2660
|
}
|
|
2658
2661
|
function isStoredProvider(value) {
|
|
2659
|
-
return value === "anthropic" || value === "openai" || value === "gemini";
|
|
2662
|
+
return value === "anthropic" || value === "openai" || value === "gemini" || value === "github-copilot";
|
|
2663
|
+
}
|
|
2664
|
+
function isStoredAuthType(value) {
|
|
2665
|
+
return value === "api-key" || value === "github-copilot";
|
|
2660
2666
|
}
|
|
2661
2667
|
function getStoredLlm(config) {
|
|
2662
2668
|
const llm = config.llm;
|
|
@@ -2675,6 +2681,17 @@ function getStoredLlm(config) {
|
|
|
2675
2681
|
if (llm.storage !== "keychain" && llm.storage !== "encrypted") {
|
|
2676
2682
|
return null;
|
|
2677
2683
|
}
|
|
2684
|
+
if (llm.provider === "github-copilot" && llm.authType === "github-copilot") {
|
|
2685
|
+
const c = llm;
|
|
2686
|
+
if (typeof c.githubToken !== "string" || typeof c.githubIv !== "string" || typeof c.githubSalt !== "string" || typeof c.githubAuthTag !== "string" || typeof c.copilotToken !== "string" || typeof c.copilotIv !== "string" || typeof c.copilotSalt !== "string" || typeof c.copilotAuthTag !== "string" || typeof c.copilotTokenExpiresAt !== "number") {
|
|
2687
|
+
return null;
|
|
2688
|
+
}
|
|
2689
|
+
return c;
|
|
2690
|
+
}
|
|
2691
|
+
const authType = llm.authType;
|
|
2692
|
+
if (authType !== undefined && !isStoredAuthType(authType)) {
|
|
2693
|
+
return null;
|
|
2694
|
+
}
|
|
2678
2695
|
return llm;
|
|
2679
2696
|
}
|
|
2680
2697
|
async function storeLlmCredentials(provider, model, apiKey) {
|
|
@@ -2688,6 +2705,7 @@ async function storeLlmCredentials(provider, model, apiKey) {
|
|
|
2688
2705
|
provider,
|
|
2689
2706
|
model,
|
|
2690
2707
|
validatedAt,
|
|
2708
|
+
authType: "api-key",
|
|
2691
2709
|
storage: "keychain"
|
|
2692
2710
|
}
|
|
2693
2711
|
});
|
|
@@ -2701,6 +2719,7 @@ async function storeLlmCredentials(provider, model, apiKey) {
|
|
|
2701
2719
|
provider,
|
|
2702
2720
|
model,
|
|
2703
2721
|
validatedAt,
|
|
2722
|
+
authType: "api-key",
|
|
2704
2723
|
storage: "encrypted",
|
|
2705
2724
|
apiKey: encrypted.encrypted,
|
|
2706
2725
|
iv: encrypted.iv,
|
|
@@ -2712,26 +2731,124 @@ async function storeLlmCredentials(provider, model, apiKey) {
|
|
|
2712
2731
|
async function getLlmApiKey() {
|
|
2713
2732
|
const config = readConfig();
|
|
2714
2733
|
const llm = getStoredLlm(config);
|
|
2715
|
-
if (!llm) {
|
|
2734
|
+
if (!llm || llm.authType === "github-copilot") {
|
|
2716
2735
|
return null;
|
|
2717
2736
|
}
|
|
2718
2737
|
if (llm.storage === "keychain") {
|
|
2719
2738
|
return getKeychainValue(KEYCHAIN_API_KEY);
|
|
2720
2739
|
}
|
|
2721
|
-
|
|
2740
|
+
const enc = llm;
|
|
2741
|
+
if (typeof enc.apiKey !== "string" || typeof enc.iv !== "string" || typeof enc.salt !== "string" || typeof enc.authTag !== "string") {
|
|
2722
2742
|
return null;
|
|
2723
2743
|
}
|
|
2724
2744
|
try {
|
|
2725
2745
|
return await decrypt({
|
|
2726
|
-
encrypted:
|
|
2727
|
-
iv:
|
|
2728
|
-
salt:
|
|
2729
|
-
authTag:
|
|
2746
|
+
encrypted: enc.apiKey,
|
|
2747
|
+
iv: enc.iv,
|
|
2748
|
+
salt: enc.salt,
|
|
2749
|
+
authTag: enc.authTag
|
|
2730
2750
|
});
|
|
2731
2751
|
} catch {
|
|
2732
2752
|
return null;
|
|
2733
2753
|
}
|
|
2734
2754
|
}
|
|
2755
|
+
async function storeCopilotCredentials(model, githubToken, copilotToken, copilotTokenExpiresAt) {
|
|
2756
|
+
const validatedAt = new Date().toISOString();
|
|
2757
|
+
const [encGithub, encCopilot] = await Promise.all([
|
|
2758
|
+
encrypt(githubToken),
|
|
2759
|
+
encrypt(copilotToken)
|
|
2760
|
+
]);
|
|
2761
|
+
writeConfig({
|
|
2762
|
+
llm: {
|
|
2763
|
+
provider: "github-copilot",
|
|
2764
|
+
model,
|
|
2765
|
+
validatedAt,
|
|
2766
|
+
authType: "github-copilot",
|
|
2767
|
+
storage: "encrypted",
|
|
2768
|
+
githubToken: encGithub.encrypted,
|
|
2769
|
+
githubIv: encGithub.iv,
|
|
2770
|
+
githubSalt: encGithub.salt,
|
|
2771
|
+
githubAuthTag: encGithub.authTag,
|
|
2772
|
+
copilotToken: encCopilot.encrypted,
|
|
2773
|
+
copilotIv: encCopilot.iv,
|
|
2774
|
+
copilotSalt: encCopilot.salt,
|
|
2775
|
+
copilotAuthTag: encCopilot.authTag,
|
|
2776
|
+
copilotTokenExpiresAt
|
|
2777
|
+
}
|
|
2778
|
+
});
|
|
2779
|
+
}
|
|
2780
|
+
async function decryptCopilotStored(stored) {
|
|
2781
|
+
try {
|
|
2782
|
+
const [githubToken, copilotToken] = await Promise.all([
|
|
2783
|
+
decrypt({ encrypted: stored.githubToken, iv: stored.githubIv, salt: stored.githubSalt, authTag: stored.githubAuthTag }),
|
|
2784
|
+
decrypt({ encrypted: stored.copilotToken, iv: stored.copilotIv, salt: stored.copilotSalt, authTag: stored.copilotAuthTag })
|
|
2785
|
+
]);
|
|
2786
|
+
return { githubToken, copilotToken };
|
|
2787
|
+
} catch {
|
|
2788
|
+
return null;
|
|
2789
|
+
}
|
|
2790
|
+
}
|
|
2791
|
+
async function refreshCopilotToken(githubToken) {
|
|
2792
|
+
let res;
|
|
2793
|
+
try {
|
|
2794
|
+
res = await fetch(COPILOT_TOKEN_URL, {
|
|
2795
|
+
headers: {
|
|
2796
|
+
Authorization: `token ${githubToken}`,
|
|
2797
|
+
"User-Agent": "GithubCopilot/1.250.0",
|
|
2798
|
+
"Editor-Version": "vscode/1.95.0",
|
|
2799
|
+
"Editor-Plugin-Version": "copilot/1.250.0",
|
|
2800
|
+
"X-GitHub-Api-Version": "2025-04-01",
|
|
2801
|
+
Accept: "application/json"
|
|
2802
|
+
}
|
|
2803
|
+
});
|
|
2804
|
+
} catch (err) {
|
|
2805
|
+
throw new Error(`Copilot token exchange failed: network error — ${err instanceof Error ? err.message : String(err)}`);
|
|
2806
|
+
}
|
|
2807
|
+
if (!res.ok) {
|
|
2808
|
+
const body = await res.text().catch(() => "");
|
|
2809
|
+
throw new Error(`Copilot token exchange failed (HTTP ${res.status}): ${body.slice(0, 300)}`);
|
|
2810
|
+
}
|
|
2811
|
+
const data = await res.json();
|
|
2812
|
+
if (typeof data.token !== "string" || typeof data.expires_at !== "number") {
|
|
2813
|
+
throw new Error("Copilot token exchange failed: unexpected response shape");
|
|
2814
|
+
}
|
|
2815
|
+
return { token: data.token, expiresAt: data.expires_at * 1000 };
|
|
2816
|
+
}
|
|
2817
|
+
async function getCopilotToken() {
|
|
2818
|
+
const config = readConfig();
|
|
2819
|
+
const llm = getStoredLlm(config);
|
|
2820
|
+
if (!llm || llm.authType !== "github-copilot") {
|
|
2821
|
+
return null;
|
|
2822
|
+
}
|
|
2823
|
+
const stored = llm;
|
|
2824
|
+
const decrypted = await decryptCopilotStored(stored);
|
|
2825
|
+
if (!decrypted)
|
|
2826
|
+
return null;
|
|
2827
|
+
if (Date.now() < stored.copilotTokenExpiresAt - 60000) {
|
|
2828
|
+
return decrypted.copilotToken;
|
|
2829
|
+
}
|
|
2830
|
+
let refreshed;
|
|
2831
|
+
try {
|
|
2832
|
+
refreshed = await refreshCopilotToken(decrypted.githubToken);
|
|
2833
|
+
} catch {
|
|
2834
|
+
return null;
|
|
2835
|
+
}
|
|
2836
|
+
const encCopilot = await encrypt(refreshed.token);
|
|
2837
|
+
writeConfig({
|
|
2838
|
+
llm: {
|
|
2839
|
+
...stored,
|
|
2840
|
+
copilotToken: encCopilot.encrypted,
|
|
2841
|
+
copilotIv: encCopilot.iv,
|
|
2842
|
+
copilotSalt: encCopilot.salt,
|
|
2843
|
+
copilotAuthTag: encCopilot.authTag,
|
|
2844
|
+
copilotTokenExpiresAt: refreshed.expiresAt
|
|
2845
|
+
}
|
|
2846
|
+
});
|
|
2847
|
+
return refreshed.token;
|
|
2848
|
+
}
|
|
2849
|
+
async function exchangeCopilotToken(githubToken) {
|
|
2850
|
+
return refreshCopilotToken(githubToken);
|
|
2851
|
+
}
|
|
2735
2852
|
async function getLlmConfig() {
|
|
2736
2853
|
const config = readConfig();
|
|
2737
2854
|
const llm = getStoredLlm(config);
|
|
@@ -2741,7 +2858,8 @@ async function getLlmConfig() {
|
|
|
2741
2858
|
return {
|
|
2742
2859
|
provider: llm.provider,
|
|
2743
2860
|
model: llm.model,
|
|
2744
|
-
validatedAt: llm.validatedAt
|
|
2861
|
+
validatedAt: llm.validatedAt,
|
|
2862
|
+
authType: llm.authType ?? "api-key"
|
|
2745
2863
|
};
|
|
2746
2864
|
}
|
|
2747
2865
|
async function updateLlmModel(model) {
|
|
@@ -2769,10 +2887,17 @@ async function clearLlmCredentials() {
|
|
|
2769
2887
|
writeConfig(nextConfig);
|
|
2770
2888
|
}
|
|
2771
2889
|
async function isLlmConfigured() {
|
|
2772
|
-
const
|
|
2773
|
-
|
|
2890
|
+
const llmConfig = await getLlmConfig();
|
|
2891
|
+
if (!llmConfig)
|
|
2892
|
+
return false;
|
|
2893
|
+
if (llmConfig.authType === "github-copilot") {
|
|
2894
|
+
const token = await getCopilotToken();
|
|
2895
|
+
return token !== null;
|
|
2896
|
+
}
|
|
2897
|
+
const apiKey = await getLlmApiKey();
|
|
2898
|
+
return apiKey !== null;
|
|
2774
2899
|
}
|
|
2775
|
-
var CONFIG_DIR, CONFIG_FILE, KEYCHAIN_API_KEY = "llm-api-key", DIR_MODE = 448, FILE_MODE = 384;
|
|
2900
|
+
var CONFIG_DIR, CONFIG_FILE, KEYCHAIN_API_KEY = "llm-api-key", DIR_MODE = 448, FILE_MODE = 384, COPILOT_TOKEN_URL = "https://api.github.com/copilot_internal/v2/token";
|
|
2776
2901
|
var init_config = __esm(() => {
|
|
2777
2902
|
init_encryption();
|
|
2778
2903
|
init_keychain();
|
|
@@ -255595,9 +255720,9 @@ var {
|
|
|
255595
255720
|
var import_picocolors12 = __toESM(require_picocolors(), 1);
|
|
255596
255721
|
import { createInterface, emitKeypressEvents } from "node:readline";
|
|
255597
255722
|
import { stdin as input, stdout as output } from "node:process";
|
|
255598
|
-
import { existsSync as
|
|
255599
|
-
import { homedir as
|
|
255600
|
-
import { join as
|
|
255723
|
+
import { existsSync as existsSync21, mkdirSync as mkdirSync11, readFileSync as readFileSync15, writeFileSync as writeFileSync15, realpathSync } from "node:fs";
|
|
255724
|
+
import { homedir as homedir6 } from "node:os";
|
|
255725
|
+
import { join as join24, resolve as resolve6, dirname as dirname5 } from "node:path";
|
|
255601
255726
|
import { pathToFileURL } from "node:url";
|
|
255602
255727
|
|
|
255603
255728
|
// src/utils/prerequisites.ts
|
|
@@ -257758,11 +257883,36 @@ function createGeminiClient(Provider, apiKey, model, rateLimiter) {
|
|
|
257758
257883
|
}
|
|
257759
257884
|
};
|
|
257760
257885
|
}
|
|
257886
|
+
var COPILOT_BASE_URL = "https://api.githubcopilot.com";
|
|
257887
|
+
var COPILOT_HEADERS = {
|
|
257888
|
+
"Editor-Version": "vscode/1.85.0",
|
|
257889
|
+
"Editor-Plugin-Version": "copilot-chat/0.26.7",
|
|
257890
|
+
"Copilot-Integration-Id": "vscode-chat"
|
|
257891
|
+
};
|
|
257892
|
+
async function createCopilotClient(bearerToken, model, rateLimiter) {
|
|
257893
|
+
const OpenAI2 = (await Promise.resolve().then(() => (init_openai(), exports_openai))).default;
|
|
257894
|
+
const CopilotProvider = function(options) {
|
|
257895
|
+
return new OpenAI2({
|
|
257896
|
+
apiKey: options.apiKey,
|
|
257897
|
+
baseURL: COPILOT_BASE_URL,
|
|
257898
|
+
defaultHeaders: COPILOT_HEADERS
|
|
257899
|
+
});
|
|
257900
|
+
};
|
|
257901
|
+
return createOpenAiClient(CopilotProvider, bearerToken, model, rateLimiter);
|
|
257902
|
+
}
|
|
257761
257903
|
async function createLlmClient(rateLimiter) {
|
|
257762
|
-
const
|
|
257904
|
+
const llmConfig = await getLlmConfig();
|
|
257763
257905
|
if (!llmConfig) {
|
|
257764
257906
|
throw new Error("LLM provider is not configured. Run /login llm to configure it.");
|
|
257765
257907
|
}
|
|
257908
|
+
if (llmConfig.provider === "github-copilot") {
|
|
257909
|
+
const copilotToken = await getCopilotToken();
|
|
257910
|
+
if (!copilotToken) {
|
|
257911
|
+
throw new Error("GitHub Copilot token unavailable. Run /login llm to re-authenticate.");
|
|
257912
|
+
}
|
|
257913
|
+
return await createCopilotClient(copilotToken, llmConfig.model, rateLimiter);
|
|
257914
|
+
}
|
|
257915
|
+
const apiKey = await getLlmApiKey();
|
|
257766
257916
|
if (!apiKey) {
|
|
257767
257917
|
throw new Error("LLM API key is not configured. Run /login llm to configure it.");
|
|
257768
257918
|
}
|
|
@@ -264918,6 +265068,9 @@ async function statusCommand(_context, _args, _commandKey) {
|
|
|
264918
265068
|
}
|
|
264919
265069
|
|
|
264920
265070
|
// src/commands/login.ts
|
|
265071
|
+
import { existsSync as existsSync19, readFileSync as readFileSync13 } from "node:fs";
|
|
265072
|
+
import { homedir as homedir5 } from "node:os";
|
|
265073
|
+
import { join as join22 } from "node:path";
|
|
264921
265074
|
init_config();
|
|
264922
265075
|
var import_picocolors8 = __toESM(require_picocolors(), 1);
|
|
264923
265076
|
var PROVIDER_LABELS = {
|
|
@@ -264948,10 +265101,23 @@ var MODEL_OPTIONS = {
|
|
|
264948
265101
|
{ value: "gemini-1.5-pro", label: "gemini-1.5-pro" }
|
|
264949
265102
|
]
|
|
264950
265103
|
};
|
|
265104
|
+
var COPILOT_MODEL_OPTIONS = [
|
|
265105
|
+
{ value: "claude-sonnet-4", label: "claude-sonnet-4 (recommended — Claude via Copilot)" },
|
|
265106
|
+
{ value: "gpt-4o", label: "gpt-4o (GPT-4o via Copilot)" },
|
|
265107
|
+
{ value: "gpt-4.1", label: "gpt-4.1 (GPT-4.1 via Copilot)" },
|
|
265108
|
+
{ value: "o4-mini", label: "o4-mini (o4-mini via Copilot)" },
|
|
265109
|
+
{ value: "gemini-2.5-pro", label: "gemini-2.5-pro (Gemini 2.5 Pro via Copilot)" }
|
|
265110
|
+
];
|
|
265111
|
+
var GITHUB_DEVICE_CLIENT_ID = "Iv1.b507a08c87ecfe98";
|
|
264951
265112
|
function cancelled() {
|
|
264952
265113
|
console.log(import_picocolors8.default.yellow("Cancelled."));
|
|
264953
265114
|
return true;
|
|
264954
265115
|
}
|
|
265116
|
+
function providerLabel(config) {
|
|
265117
|
+
if (config.authType === "github-copilot")
|
|
265118
|
+
return "GitHub Copilot";
|
|
265119
|
+
return PROVIDER_LABELS[config.provider] ?? config.provider;
|
|
265120
|
+
}
|
|
264955
265121
|
async function runRailwayLogin() {
|
|
264956
265122
|
const status = await checkRailwayAuth();
|
|
264957
265123
|
if (status.authenticated) {
|
|
@@ -264972,6 +265138,20 @@ async function runRailwayLogin() {
|
|
|
264972
265138
|
}
|
|
264973
265139
|
console.log(import_picocolors8.default.red(loginStatus.error ?? "Failed to authenticate with Railway."));
|
|
264974
265140
|
}
|
|
265141
|
+
async function promptAuthMode() {
|
|
265142
|
+
const mode = await ve({
|
|
265143
|
+
message: "How do you want to connect to an LLM?",
|
|
265144
|
+
options: [
|
|
265145
|
+
{ value: "api-key", label: "API Key (Anthropic, OpenAI, or Gemini — pay per token)" },
|
|
265146
|
+
{ value: "github-copilot", label: "GitHub Copilot (use your Copilot subscription — Claude, GPT, Gemini included)" }
|
|
265147
|
+
]
|
|
265148
|
+
});
|
|
265149
|
+
if (pD(mode)) {
|
|
265150
|
+
cancelled();
|
|
265151
|
+
return null;
|
|
265152
|
+
}
|
|
265153
|
+
return mode;
|
|
265154
|
+
}
|
|
264975
265155
|
async function promptProvider() {
|
|
264976
265156
|
const provider = await ve({
|
|
264977
265157
|
message: "Select LLM provider:",
|
|
@@ -264994,14 +265174,105 @@ async function promptModel(provider) {
|
|
|
264994
265174
|
}
|
|
264995
265175
|
return model;
|
|
264996
265176
|
}
|
|
264997
|
-
|
|
265177
|
+
function readGhCliToken() {
|
|
265178
|
+
try {
|
|
265179
|
+
const hostsFile = join22(homedir5(), ".config", "gh", "hosts.yml");
|
|
265180
|
+
if (!existsSync19(hostsFile))
|
|
265181
|
+
return null;
|
|
265182
|
+
const raw = readFileSync13(hostsFile, "utf-8");
|
|
265183
|
+
for (const line of raw.split(`
|
|
265184
|
+
`)) {
|
|
265185
|
+
const match = line.match(/^\s*oauth_token:\s*(.+)$/);
|
|
265186
|
+
if (match?.[1]) {
|
|
265187
|
+
return match[1].trim();
|
|
265188
|
+
}
|
|
265189
|
+
}
|
|
265190
|
+
return null;
|
|
265191
|
+
} catch {
|
|
265192
|
+
return null;
|
|
265193
|
+
}
|
|
265194
|
+
}
|
|
265195
|
+
async function runGitHubDeviceFlow() {
|
|
265196
|
+
try {
|
|
265197
|
+
const codeRes = await fetch("https://github.com/login/device/code", {
|
|
265198
|
+
method: "POST",
|
|
265199
|
+
headers: {
|
|
265200
|
+
Accept: "application/json",
|
|
265201
|
+
"Content-Type": "application/json"
|
|
265202
|
+
},
|
|
265203
|
+
body: JSON.stringify({
|
|
265204
|
+
client_id: GITHUB_DEVICE_CLIENT_ID,
|
|
265205
|
+
scope: "read:user"
|
|
265206
|
+
})
|
|
265207
|
+
});
|
|
265208
|
+
if (!codeRes.ok) {
|
|
265209
|
+
console.log(import_picocolors8.default.red("Failed to start GitHub login. Check your internet connection."));
|
|
265210
|
+
return null;
|
|
265211
|
+
}
|
|
265212
|
+
const codeData = await codeRes.json();
|
|
265213
|
+
console.log();
|
|
265214
|
+
console.log(import_picocolors8.default.bold("GitHub login"));
|
|
265215
|
+
console.log(`Open ${import_picocolors8.default.cyan(codeData.verification_uri)} and enter code: ${import_picocolors8.default.bold(import_picocolors8.default.yellow(codeData.user_code))}`);
|
|
265216
|
+
console.log();
|
|
265217
|
+
try {
|
|
265218
|
+
const openModule = await import("open");
|
|
265219
|
+
await openModule.default(codeData.verification_uri);
|
|
265220
|
+
} catch {}
|
|
265221
|
+
const intervalMs = (codeData.interval ?? 5) * 1000;
|
|
265222
|
+
const expiresAt = Date.now() + (codeData.expires_in ?? 900) * 1000;
|
|
265223
|
+
while (Date.now() < expiresAt) {
|
|
265224
|
+
await new Promise((resolve6) => setTimeout(resolve6, intervalMs));
|
|
265225
|
+
const tokenRes = await fetch("https://github.com/login/oauth/access_token", {
|
|
265226
|
+
method: "POST",
|
|
265227
|
+
headers: {
|
|
265228
|
+
Accept: "application/json",
|
|
265229
|
+
"Content-Type": "application/json"
|
|
265230
|
+
},
|
|
265231
|
+
body: JSON.stringify({
|
|
265232
|
+
client_id: GITHUB_DEVICE_CLIENT_ID,
|
|
265233
|
+
device_code: codeData.device_code,
|
|
265234
|
+
grant_type: "urn:ietf:params:oauth:grant-type:device_code"
|
|
265235
|
+
})
|
|
265236
|
+
});
|
|
265237
|
+
if (!tokenRes.ok)
|
|
265238
|
+
continue;
|
|
265239
|
+
const tokenData = await tokenRes.json();
|
|
265240
|
+
if (tokenData.access_token) {
|
|
265241
|
+
return tokenData.access_token;
|
|
265242
|
+
}
|
|
265243
|
+
if (tokenData.error === "authorization_pending") {
|
|
265244
|
+
continue;
|
|
265245
|
+
}
|
|
265246
|
+
if (tokenData.error === "slow_down") {
|
|
265247
|
+
await new Promise((resolve6) => setTimeout(resolve6, intervalMs));
|
|
265248
|
+
continue;
|
|
265249
|
+
}
|
|
265250
|
+
console.log(import_picocolors8.default.red(tokenData.error_description ?? `GitHub login failed: ${tokenData.error}`));
|
|
265251
|
+
return null;
|
|
265252
|
+
}
|
|
265253
|
+
console.log(import_picocolors8.default.red("GitHub login timed out. Run /login llm again to retry."));
|
|
265254
|
+
return null;
|
|
265255
|
+
} catch {
|
|
265256
|
+
console.log(import_picocolors8.default.red("GitHub login failed. Check your internet connection."));
|
|
265257
|
+
return null;
|
|
265258
|
+
}
|
|
265259
|
+
}
|
|
265260
|
+
async function getGitHubToken() {
|
|
265261
|
+
const ghToken = readGhCliToken();
|
|
265262
|
+
if (ghToken) {
|
|
265263
|
+
console.log(import_picocolors8.default.dim("Using existing GitHub CLI session."));
|
|
265264
|
+
return ghToken;
|
|
265265
|
+
}
|
|
265266
|
+
console.log(import_picocolors8.default.cyan("No GitHub CLI session found. Opening GitHub login in your browser..."));
|
|
265267
|
+
return runGitHubDeviceFlow();
|
|
265268
|
+
}
|
|
265269
|
+
async function runCopilotLogin(context) {
|
|
264998
265270
|
const existingConfig = await getLlmConfig();
|
|
264999
|
-
if (existingConfig) {
|
|
265000
|
-
|
|
265001
|
-
console.log(import_picocolors8.default.green(`✓ LLM ${providerName} (${existingConfig.model}) already configured`));
|
|
265271
|
+
if (existingConfig && existingConfig.authType === "github-copilot") {
|
|
265272
|
+
console.log(import_picocolors8.default.green(`✓ GitHub Copilot (${existingConfig.model}) already configured`));
|
|
265002
265273
|
if (!context.yes) {
|
|
265003
265274
|
const shouldChange = await ye({
|
|
265004
|
-
message: "Change
|
|
265275
|
+
message: "Change Copilot model or re-authenticate?",
|
|
265005
265276
|
initialValue: false
|
|
265006
265277
|
});
|
|
265007
265278
|
if (pD(shouldChange)) {
|
|
@@ -265013,14 +265284,60 @@ async function runLlmLogin(context) {
|
|
|
265013
265284
|
}
|
|
265014
265285
|
}
|
|
265015
265286
|
}
|
|
265016
|
-
const
|
|
265017
|
-
|
|
265287
|
+
const model = await ve({
|
|
265288
|
+
message: "Select model (via GitHub Copilot):",
|
|
265289
|
+
options: COPILOT_MODEL_OPTIONS
|
|
265290
|
+
});
|
|
265291
|
+
if (pD(model)) {
|
|
265292
|
+
cancelled();
|
|
265018
265293
|
return;
|
|
265019
265294
|
}
|
|
265020
|
-
const
|
|
265021
|
-
if (!
|
|
265295
|
+
const githubToken = await getGitHubToken();
|
|
265296
|
+
if (!githubToken)
|
|
265297
|
+
return;
|
|
265298
|
+
console.log(import_picocolors8.default.dim("Authenticating with GitHub Copilot..."));
|
|
265299
|
+
let copilotResult;
|
|
265300
|
+
try {
|
|
265301
|
+
copilotResult = await exchangeCopilotToken(githubToken);
|
|
265302
|
+
} catch (err) {
|
|
265303
|
+
const msg = err instanceof Error ? err.message : "Unknown error";
|
|
265304
|
+
console.log(import_picocolors8.default.red(`✗ ${msg}`));
|
|
265305
|
+
console.log(import_picocolors8.default.dim("Make sure your GitHub account has an active Copilot Pro, Pro+, Business, or Enterprise subscription."));
|
|
265022
265306
|
return;
|
|
265023
265307
|
}
|
|
265308
|
+
await storeCopilotCredentials(model, githubToken, copilotResult.token, copilotResult.expiresAt);
|
|
265309
|
+
console.log(import_picocolors8.default.green(`✓ GitHub Copilot authenticated (${model})`));
|
|
265310
|
+
}
|
|
265311
|
+
async function runLlmLogin(context) {
|
|
265312
|
+
const existingConfig = await getLlmConfig();
|
|
265313
|
+
if (existingConfig && !context.yes) {
|
|
265314
|
+
const label = providerLabel(existingConfig);
|
|
265315
|
+
console.log(import_picocolors8.default.green(`✓ LLM ${label} (${existingConfig.model}) already configured`));
|
|
265316
|
+
const shouldChange = await ye({
|
|
265317
|
+
message: "Change LLM provider/model/key?",
|
|
265318
|
+
initialValue: false
|
|
265319
|
+
});
|
|
265320
|
+
if (pD(shouldChange)) {
|
|
265321
|
+
cancelled();
|
|
265322
|
+
return;
|
|
265323
|
+
}
|
|
265324
|
+
if (!shouldChange) {
|
|
265325
|
+
return;
|
|
265326
|
+
}
|
|
265327
|
+
}
|
|
265328
|
+
const authMode = await promptAuthMode();
|
|
265329
|
+
if (!authMode)
|
|
265330
|
+
return;
|
|
265331
|
+
if (authMode === "github-copilot") {
|
|
265332
|
+
await runCopilotLogin(context);
|
|
265333
|
+
return;
|
|
265334
|
+
}
|
|
265335
|
+
const provider = await promptProvider();
|
|
265336
|
+
if (!provider)
|
|
265337
|
+
return;
|
|
265338
|
+
const model = await promptModel(provider);
|
|
265339
|
+
if (!model)
|
|
265340
|
+
return;
|
|
265024
265341
|
const apiKey = await ge({
|
|
265025
265342
|
message: `Enter your ${PROVIDER_LABELS[provider]} API key:`,
|
|
265026
265343
|
validate: (value) => {
|
|
@@ -265043,10 +265360,23 @@ async function runModelSwitch() {
|
|
|
265043
265360
|
console.log(import_picocolors8.default.red("No LLM provider configured. Run /login llm first."));
|
|
265044
265361
|
return;
|
|
265045
265362
|
}
|
|
265046
|
-
|
|
265047
|
-
|
|
265363
|
+
if (config.authType === "github-copilot") {
|
|
265364
|
+
const model2 = await ve({
|
|
265365
|
+
message: "Select model (via GitHub Copilot):",
|
|
265366
|
+
options: COPILOT_MODEL_OPTIONS
|
|
265367
|
+
});
|
|
265368
|
+
if (pD(model2)) {
|
|
265369
|
+
cancelled();
|
|
265370
|
+
return;
|
|
265371
|
+
}
|
|
265372
|
+
await updateLlmModel(model2);
|
|
265373
|
+
console.log(import_picocolors8.default.green(`✓ Copilot model changed to ${model2}`));
|
|
265048
265374
|
return;
|
|
265049
265375
|
}
|
|
265376
|
+
const provider = config.provider;
|
|
265377
|
+
const model = await promptModel(provider);
|
|
265378
|
+
if (!model)
|
|
265379
|
+
return;
|
|
265050
265380
|
await updateLlmModel(model);
|
|
265051
265381
|
console.log(import_picocolors8.default.green(`✓ LLM model changed to ${model}`));
|
|
265052
265382
|
}
|
|
@@ -265069,7 +265399,8 @@ async function runFullLogin(context) {
|
|
|
265069
265399
|
}
|
|
265070
265400
|
const [llmConfigured, llmConfig] = await Promise.all([isLlmConfigured(), getLlmConfig()]);
|
|
265071
265401
|
if (llmConfigured && llmConfig) {
|
|
265072
|
-
|
|
265402
|
+
const label = providerLabel(llmConfig);
|
|
265403
|
+
console.log(import_picocolors8.default.green(`✓ LLM ${label} (${llmConfig.model})`));
|
|
265073
265404
|
} else {
|
|
265074
265405
|
await runLlmLogin(context);
|
|
265075
265406
|
}
|
|
@@ -265089,7 +265420,8 @@ async function runFullLogin(context) {
|
|
|
265089
265420
|
console.log(import_picocolors8.default.yellow("• Railway: not authenticated"));
|
|
265090
265421
|
}
|
|
265091
265422
|
if (finalLlmConfigured && finalLlmConfig) {
|
|
265092
|
-
|
|
265423
|
+
const label = providerLabel(finalLlmConfig);
|
|
265424
|
+
console.log(import_picocolors8.default.green(`✓ LLM: ${label} (${finalLlmConfig.model})`));
|
|
265093
265425
|
} else {
|
|
265094
265426
|
console.log(import_picocolors8.default.yellow("• LLM: not configured"));
|
|
265095
265427
|
}
|
|
@@ -265097,7 +265429,7 @@ async function runFullLogin(context) {
|
|
|
265097
265429
|
async function runLogout(context) {
|
|
265098
265430
|
if (!context.yes) {
|
|
265099
265431
|
const shouldLogout = await ye({
|
|
265100
|
-
message: "This will log out of Railway and remove your stored LLM
|
|
265432
|
+
message: "This will log out of Railway and remove your stored LLM credentials. Continue?",
|
|
265101
265433
|
initialValue: false
|
|
265102
265434
|
});
|
|
265103
265435
|
if (pD(shouldLogout)) {
|
|
@@ -265115,7 +265447,7 @@ async function runLogout(context) {
|
|
|
265115
265447
|
} else {
|
|
265116
265448
|
console.log(import_picocolors8.default.yellow("• Railway logout skipped or not authenticated"));
|
|
265117
265449
|
}
|
|
265118
|
-
console.log(import_picocolors8.default.green("✓ LLM
|
|
265450
|
+
console.log(import_picocolors8.default.green("✓ LLM credentials removed"));
|
|
265119
265451
|
}
|
|
265120
265452
|
async function loginCommand(context, args, commandKey = "login") {
|
|
265121
265453
|
if (commandKey === "logout") {
|
|
@@ -265144,8 +265476,8 @@ async function loginCommand(context, args, commandKey = "login") {
|
|
|
265144
265476
|
}
|
|
265145
265477
|
|
|
265146
265478
|
// src/commands/versions.ts
|
|
265147
|
-
import { existsSync as
|
|
265148
|
-
import { join as
|
|
265479
|
+
import { existsSync as existsSync20, readFileSync as readFileSync14, writeFileSync as writeFileSync14 } from "node:fs";
|
|
265480
|
+
import { join as join23 } from "node:path";
|
|
265149
265481
|
var import_picocolors9 = __toESM(require_picocolors(), 1);
|
|
265150
265482
|
var TABLE_HEADER_INTEGRATION = "Integration";
|
|
265151
265483
|
var TABLE_HEADER_VERSION = "Version";
|
|
@@ -265188,13 +265520,13 @@ function loadVersionsContext(logger) {
|
|
|
265188
265520
|
logger.cmd("/versions", "FAILED", "not a workspace");
|
|
265189
265521
|
return null;
|
|
265190
265522
|
}
|
|
265191
|
-
const versionsPath =
|
|
265192
|
-
if (!
|
|
265523
|
+
const versionsPath = join23(workspaceDir, "versions.md");
|
|
265524
|
+
if (!existsSync20(versionsPath)) {
|
|
265193
265525
|
error("versions.md not found in workspace root.");
|
|
265194
265526
|
logger.cmd("/versions", "FAILED", "versions.md missing");
|
|
265195
265527
|
return null;
|
|
265196
265528
|
}
|
|
265197
|
-
const versionsMarkdown =
|
|
265529
|
+
const versionsMarkdown = readFileSync14(versionsPath, "utf-8");
|
|
265198
265530
|
const result = parseVersionsTable(versionsMarkdown);
|
|
265199
265531
|
for (const parseError of result.errors) {
|
|
265200
265532
|
warn(parseError);
|
|
@@ -265622,7 +265954,7 @@ async function helpCommand(_context, _args) {
|
|
|
265622
265954
|
// package.json
|
|
265623
265955
|
var package_default = {
|
|
265624
265956
|
name: "openkitt",
|
|
265625
|
-
version: "0.3.
|
|
265957
|
+
version: "0.3.5",
|
|
265626
265958
|
description: "AI-powered monorepo scaffolding CLI",
|
|
265627
265959
|
keywords: [
|
|
265628
265960
|
"cli",
|
|
@@ -265694,8 +266026,8 @@ var STATE_CHANGING_COMMANDS = new Set([
|
|
|
265694
266026
|
"domain",
|
|
265695
266027
|
"publish"
|
|
265696
266028
|
]);
|
|
265697
|
-
var KITT_DIR3 =
|
|
265698
|
-
var UPDATE_CHECK_FILE =
|
|
266029
|
+
var KITT_DIR3 = join24(homedir6(), ".kitt");
|
|
266030
|
+
var UPDATE_CHECK_FILE = join24(KITT_DIR3, "update-check.json");
|
|
265699
266031
|
var commandRegistry = {
|
|
265700
266032
|
init: { handler: initCommand },
|
|
265701
266033
|
create: { handler: createCommand2 },
|
|
@@ -265775,11 +266107,11 @@ function isVersionNewer(latest, current) {
|
|
|
265775
266107
|
return false;
|
|
265776
266108
|
}
|
|
265777
266109
|
function hasFreshUpdateCache(now) {
|
|
265778
|
-
if (!
|
|
266110
|
+
if (!existsSync21(UPDATE_CHECK_FILE)) {
|
|
265779
266111
|
return false;
|
|
265780
266112
|
}
|
|
265781
266113
|
try {
|
|
265782
|
-
const rawCache =
|
|
266114
|
+
const rawCache = readFileSync15(UPDATE_CHECK_FILE, "utf-8").trim();
|
|
265783
266115
|
if (rawCache.length === 0) {
|
|
265784
266116
|
return false;
|
|
265785
266117
|
}
|