openkitt 0.3.3 → 0.3.4
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 +365 -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,117 @@ 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
|
|
2750
|
+
});
|
|
2751
|
+
} catch {
|
|
2752
|
+
return null;
|
|
2753
|
+
}
|
|
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
|
+
try {
|
|
2793
|
+
const res = await fetch(COPILOT_TOKEN_URL, {
|
|
2794
|
+
headers: {
|
|
2795
|
+
Authorization: `Token ${githubToken}`,
|
|
2796
|
+
"User-Agent": "GitHubCopilotChat/0.26.7"
|
|
2797
|
+
}
|
|
2730
2798
|
});
|
|
2799
|
+
if (!res.ok)
|
|
2800
|
+
return null;
|
|
2801
|
+
const data = await res.json();
|
|
2802
|
+
if (typeof data.token !== "string" || typeof data.expires_at !== "number")
|
|
2803
|
+
return null;
|
|
2804
|
+
return { token: data.token, expiresAt: data.expires_at * 1000 };
|
|
2731
2805
|
} catch {
|
|
2732
2806
|
return null;
|
|
2733
2807
|
}
|
|
2734
2808
|
}
|
|
2809
|
+
async function getCopilotToken() {
|
|
2810
|
+
const config = readConfig();
|
|
2811
|
+
const llm = getStoredLlm(config);
|
|
2812
|
+
if (!llm || llm.authType !== "github-copilot") {
|
|
2813
|
+
return null;
|
|
2814
|
+
}
|
|
2815
|
+
const stored = llm;
|
|
2816
|
+
const decrypted = await decryptCopilotStored(stored);
|
|
2817
|
+
if (!decrypted)
|
|
2818
|
+
return null;
|
|
2819
|
+
if (Date.now() < stored.copilotTokenExpiresAt - 60000) {
|
|
2820
|
+
return decrypted.copilotToken;
|
|
2821
|
+
}
|
|
2822
|
+
const refreshed = await refreshCopilotToken(decrypted.githubToken);
|
|
2823
|
+
if (!refreshed)
|
|
2824
|
+
return null;
|
|
2825
|
+
const encCopilot = await encrypt(refreshed.token);
|
|
2826
|
+
writeConfig({
|
|
2827
|
+
llm: {
|
|
2828
|
+
...stored,
|
|
2829
|
+
copilotToken: encCopilot.encrypted,
|
|
2830
|
+
copilotIv: encCopilot.iv,
|
|
2831
|
+
copilotSalt: encCopilot.salt,
|
|
2832
|
+
copilotAuthTag: encCopilot.authTag,
|
|
2833
|
+
copilotTokenExpiresAt: refreshed.expiresAt
|
|
2834
|
+
}
|
|
2835
|
+
});
|
|
2836
|
+
return refreshed.token;
|
|
2837
|
+
}
|
|
2838
|
+
async function exchangeCopilotToken(githubToken) {
|
|
2839
|
+
const result = await refreshCopilotToken(githubToken);
|
|
2840
|
+
if (!result) {
|
|
2841
|
+
throw new Error("Failed to exchange GitHub token for Copilot bearer token. Check your Copilot subscription is active.");
|
|
2842
|
+
}
|
|
2843
|
+
return result;
|
|
2844
|
+
}
|
|
2735
2845
|
async function getLlmConfig() {
|
|
2736
2846
|
const config = readConfig();
|
|
2737
2847
|
const llm = getStoredLlm(config);
|
|
@@ -2741,7 +2851,8 @@ async function getLlmConfig() {
|
|
|
2741
2851
|
return {
|
|
2742
2852
|
provider: llm.provider,
|
|
2743
2853
|
model: llm.model,
|
|
2744
|
-
validatedAt: llm.validatedAt
|
|
2854
|
+
validatedAt: llm.validatedAt,
|
|
2855
|
+
authType: llm.authType ?? "api-key"
|
|
2745
2856
|
};
|
|
2746
2857
|
}
|
|
2747
2858
|
async function updateLlmModel(model) {
|
|
@@ -2769,10 +2880,17 @@ async function clearLlmCredentials() {
|
|
|
2769
2880
|
writeConfig(nextConfig);
|
|
2770
2881
|
}
|
|
2771
2882
|
async function isLlmConfigured() {
|
|
2772
|
-
const
|
|
2773
|
-
|
|
2883
|
+
const llmConfig = await getLlmConfig();
|
|
2884
|
+
if (!llmConfig)
|
|
2885
|
+
return false;
|
|
2886
|
+
if (llmConfig.authType === "github-copilot") {
|
|
2887
|
+
const token = await getCopilotToken();
|
|
2888
|
+
return token !== null;
|
|
2889
|
+
}
|
|
2890
|
+
const apiKey = await getLlmApiKey();
|
|
2891
|
+
return apiKey !== null;
|
|
2774
2892
|
}
|
|
2775
|
-
var CONFIG_DIR, CONFIG_FILE, KEYCHAIN_API_KEY = "llm-api-key", DIR_MODE = 448, FILE_MODE = 384;
|
|
2893
|
+
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
2894
|
var init_config = __esm(() => {
|
|
2777
2895
|
init_encryption();
|
|
2778
2896
|
init_keychain();
|
|
@@ -255595,9 +255713,9 @@ var {
|
|
|
255595
255713
|
var import_picocolors12 = __toESM(require_picocolors(), 1);
|
|
255596
255714
|
import { createInterface, emitKeypressEvents } from "node:readline";
|
|
255597
255715
|
import { stdin as input, stdout as output } from "node:process";
|
|
255598
|
-
import { existsSync as
|
|
255599
|
-
import { homedir as
|
|
255600
|
-
import { join as
|
|
255716
|
+
import { existsSync as existsSync21, mkdirSync as mkdirSync11, readFileSync as readFileSync15, writeFileSync as writeFileSync15, realpathSync } from "node:fs";
|
|
255717
|
+
import { homedir as homedir6 } from "node:os";
|
|
255718
|
+
import { join as join24, resolve as resolve6, dirname as dirname5 } from "node:path";
|
|
255601
255719
|
import { pathToFileURL } from "node:url";
|
|
255602
255720
|
|
|
255603
255721
|
// src/utils/prerequisites.ts
|
|
@@ -257758,11 +257876,36 @@ function createGeminiClient(Provider, apiKey, model, rateLimiter) {
|
|
|
257758
257876
|
}
|
|
257759
257877
|
};
|
|
257760
257878
|
}
|
|
257879
|
+
var COPILOT_BASE_URL = "https://api.githubcopilot.com";
|
|
257880
|
+
var COPILOT_HEADERS = {
|
|
257881
|
+
"Editor-Version": "vscode/1.85.0",
|
|
257882
|
+
"Editor-Plugin-Version": "copilot-chat/0.26.7",
|
|
257883
|
+
"Copilot-Integration-Id": "vscode-chat"
|
|
257884
|
+
};
|
|
257885
|
+
async function createCopilotClient(bearerToken, model, rateLimiter) {
|
|
257886
|
+
const OpenAI2 = (await Promise.resolve().then(() => (init_openai(), exports_openai))).default;
|
|
257887
|
+
const CopilotProvider = function(options) {
|
|
257888
|
+
return new OpenAI2({
|
|
257889
|
+
apiKey: options.apiKey,
|
|
257890
|
+
baseURL: COPILOT_BASE_URL,
|
|
257891
|
+
defaultHeaders: COPILOT_HEADERS
|
|
257892
|
+
});
|
|
257893
|
+
};
|
|
257894
|
+
return createOpenAiClient(CopilotProvider, bearerToken, model, rateLimiter);
|
|
257895
|
+
}
|
|
257761
257896
|
async function createLlmClient(rateLimiter) {
|
|
257762
|
-
const
|
|
257897
|
+
const llmConfig = await getLlmConfig();
|
|
257763
257898
|
if (!llmConfig) {
|
|
257764
257899
|
throw new Error("LLM provider is not configured. Run /login llm to configure it.");
|
|
257765
257900
|
}
|
|
257901
|
+
if (llmConfig.provider === "github-copilot") {
|
|
257902
|
+
const copilotToken = await getCopilotToken();
|
|
257903
|
+
if (!copilotToken) {
|
|
257904
|
+
throw new Error("GitHub Copilot token unavailable. Run /login llm to re-authenticate.");
|
|
257905
|
+
}
|
|
257906
|
+
return await createCopilotClient(copilotToken, llmConfig.model, rateLimiter);
|
|
257907
|
+
}
|
|
257908
|
+
const apiKey = await getLlmApiKey();
|
|
257766
257909
|
if (!apiKey) {
|
|
257767
257910
|
throw new Error("LLM API key is not configured. Run /login llm to configure it.");
|
|
257768
257911
|
}
|
|
@@ -264918,6 +265061,9 @@ async function statusCommand(_context, _args, _commandKey) {
|
|
|
264918
265061
|
}
|
|
264919
265062
|
|
|
264920
265063
|
// src/commands/login.ts
|
|
265064
|
+
import { existsSync as existsSync19, readFileSync as readFileSync13 } from "node:fs";
|
|
265065
|
+
import { homedir as homedir5 } from "node:os";
|
|
265066
|
+
import { join as join22 } from "node:path";
|
|
264921
265067
|
init_config();
|
|
264922
265068
|
var import_picocolors8 = __toESM(require_picocolors(), 1);
|
|
264923
265069
|
var PROVIDER_LABELS = {
|
|
@@ -264948,10 +265094,23 @@ var MODEL_OPTIONS = {
|
|
|
264948
265094
|
{ value: "gemini-1.5-pro", label: "gemini-1.5-pro" }
|
|
264949
265095
|
]
|
|
264950
265096
|
};
|
|
265097
|
+
var COPILOT_MODEL_OPTIONS = [
|
|
265098
|
+
{ value: "claude-sonnet-4", label: "claude-sonnet-4 (recommended — Claude via Copilot)" },
|
|
265099
|
+
{ value: "gpt-4o", label: "gpt-4o (GPT-4o via Copilot)" },
|
|
265100
|
+
{ value: "gpt-4.1", label: "gpt-4.1 (GPT-4.1 via Copilot)" },
|
|
265101
|
+
{ value: "o4-mini", label: "o4-mini (o4-mini via Copilot)" },
|
|
265102
|
+
{ value: "gemini-2.5-pro", label: "gemini-2.5-pro (Gemini 2.5 Pro via Copilot)" }
|
|
265103
|
+
];
|
|
265104
|
+
var GITHUB_DEVICE_CLIENT_ID = "01ab8ac9400c4e429b23";
|
|
264951
265105
|
function cancelled() {
|
|
264952
265106
|
console.log(import_picocolors8.default.yellow("Cancelled."));
|
|
264953
265107
|
return true;
|
|
264954
265108
|
}
|
|
265109
|
+
function providerLabel(config) {
|
|
265110
|
+
if (config.authType === "github-copilot")
|
|
265111
|
+
return "GitHub Copilot";
|
|
265112
|
+
return PROVIDER_LABELS[config.provider] ?? config.provider;
|
|
265113
|
+
}
|
|
264955
265114
|
async function runRailwayLogin() {
|
|
264956
265115
|
const status = await checkRailwayAuth();
|
|
264957
265116
|
if (status.authenticated) {
|
|
@@ -264972,6 +265131,20 @@ async function runRailwayLogin() {
|
|
|
264972
265131
|
}
|
|
264973
265132
|
console.log(import_picocolors8.default.red(loginStatus.error ?? "Failed to authenticate with Railway."));
|
|
264974
265133
|
}
|
|
265134
|
+
async function promptAuthMode() {
|
|
265135
|
+
const mode = await ve({
|
|
265136
|
+
message: "How do you want to connect to an LLM?",
|
|
265137
|
+
options: [
|
|
265138
|
+
{ value: "api-key", label: "API Key (Anthropic, OpenAI, or Gemini — pay per token)" },
|
|
265139
|
+
{ value: "github-copilot", label: "GitHub Copilot (use your Copilot subscription — Claude, GPT, Gemini included)" }
|
|
265140
|
+
]
|
|
265141
|
+
});
|
|
265142
|
+
if (pD(mode)) {
|
|
265143
|
+
cancelled();
|
|
265144
|
+
return null;
|
|
265145
|
+
}
|
|
265146
|
+
return mode;
|
|
265147
|
+
}
|
|
264975
265148
|
async function promptProvider() {
|
|
264976
265149
|
const provider = await ve({
|
|
264977
265150
|
message: "Select LLM provider:",
|
|
@@ -264994,14 +265167,105 @@ async function promptModel(provider) {
|
|
|
264994
265167
|
}
|
|
264995
265168
|
return model;
|
|
264996
265169
|
}
|
|
264997
|
-
|
|
265170
|
+
function readGhCliToken() {
|
|
265171
|
+
try {
|
|
265172
|
+
const hostsFile = join22(homedir5(), ".config", "gh", "hosts.yml");
|
|
265173
|
+
if (!existsSync19(hostsFile))
|
|
265174
|
+
return null;
|
|
265175
|
+
const raw = readFileSync13(hostsFile, "utf-8");
|
|
265176
|
+
for (const line of raw.split(`
|
|
265177
|
+
`)) {
|
|
265178
|
+
const match = line.match(/^\s*oauth_token:\s*(.+)$/);
|
|
265179
|
+
if (match?.[1]) {
|
|
265180
|
+
return match[1].trim();
|
|
265181
|
+
}
|
|
265182
|
+
}
|
|
265183
|
+
return null;
|
|
265184
|
+
} catch {
|
|
265185
|
+
return null;
|
|
265186
|
+
}
|
|
265187
|
+
}
|
|
265188
|
+
async function runGitHubDeviceFlow() {
|
|
265189
|
+
try {
|
|
265190
|
+
const codeRes = await fetch("https://github.com/login/device/code", {
|
|
265191
|
+
method: "POST",
|
|
265192
|
+
headers: {
|
|
265193
|
+
Accept: "application/json",
|
|
265194
|
+
"Content-Type": "application/json"
|
|
265195
|
+
},
|
|
265196
|
+
body: JSON.stringify({
|
|
265197
|
+
client_id: GITHUB_DEVICE_CLIENT_ID,
|
|
265198
|
+
scope: "read:user"
|
|
265199
|
+
})
|
|
265200
|
+
});
|
|
265201
|
+
if (!codeRes.ok) {
|
|
265202
|
+
console.log(import_picocolors8.default.red("Failed to start GitHub login. Check your internet connection."));
|
|
265203
|
+
return null;
|
|
265204
|
+
}
|
|
265205
|
+
const codeData = await codeRes.json();
|
|
265206
|
+
console.log();
|
|
265207
|
+
console.log(import_picocolors8.default.bold("GitHub login"));
|
|
265208
|
+
console.log(`Open ${import_picocolors8.default.cyan(codeData.verification_uri)} and enter code: ${import_picocolors8.default.bold(import_picocolors8.default.yellow(codeData.user_code))}`);
|
|
265209
|
+
console.log();
|
|
265210
|
+
try {
|
|
265211
|
+
const openModule = await import("open");
|
|
265212
|
+
await openModule.default(codeData.verification_uri);
|
|
265213
|
+
} catch {}
|
|
265214
|
+
const intervalMs = (codeData.interval ?? 5) * 1000;
|
|
265215
|
+
const expiresAt = Date.now() + (codeData.expires_in ?? 900) * 1000;
|
|
265216
|
+
while (Date.now() < expiresAt) {
|
|
265217
|
+
await new Promise((resolve6) => setTimeout(resolve6, intervalMs));
|
|
265218
|
+
const tokenRes = await fetch("https://github.com/login/oauth/access_token", {
|
|
265219
|
+
method: "POST",
|
|
265220
|
+
headers: {
|
|
265221
|
+
Accept: "application/json",
|
|
265222
|
+
"Content-Type": "application/json"
|
|
265223
|
+
},
|
|
265224
|
+
body: JSON.stringify({
|
|
265225
|
+
client_id: GITHUB_DEVICE_CLIENT_ID,
|
|
265226
|
+
device_code: codeData.device_code,
|
|
265227
|
+
grant_type: "urn:ietf:params:oauth:grant-type:device_code"
|
|
265228
|
+
})
|
|
265229
|
+
});
|
|
265230
|
+
if (!tokenRes.ok)
|
|
265231
|
+
continue;
|
|
265232
|
+
const tokenData = await tokenRes.json();
|
|
265233
|
+
if (tokenData.access_token) {
|
|
265234
|
+
return tokenData.access_token;
|
|
265235
|
+
}
|
|
265236
|
+
if (tokenData.error === "authorization_pending") {
|
|
265237
|
+
continue;
|
|
265238
|
+
}
|
|
265239
|
+
if (tokenData.error === "slow_down") {
|
|
265240
|
+
await new Promise((resolve6) => setTimeout(resolve6, intervalMs));
|
|
265241
|
+
continue;
|
|
265242
|
+
}
|
|
265243
|
+
console.log(import_picocolors8.default.red(tokenData.error_description ?? `GitHub login failed: ${tokenData.error}`));
|
|
265244
|
+
return null;
|
|
265245
|
+
}
|
|
265246
|
+
console.log(import_picocolors8.default.red("GitHub login timed out. Run /login llm again to retry."));
|
|
265247
|
+
return null;
|
|
265248
|
+
} catch {
|
|
265249
|
+
console.log(import_picocolors8.default.red("GitHub login failed. Check your internet connection."));
|
|
265250
|
+
return null;
|
|
265251
|
+
}
|
|
265252
|
+
}
|
|
265253
|
+
async function getGitHubToken() {
|
|
265254
|
+
const ghToken = readGhCliToken();
|
|
265255
|
+
if (ghToken) {
|
|
265256
|
+
console.log(import_picocolors8.default.dim("Using existing GitHub CLI session."));
|
|
265257
|
+
return ghToken;
|
|
265258
|
+
}
|
|
265259
|
+
console.log(import_picocolors8.default.cyan("No GitHub CLI session found. Opening GitHub login in your browser..."));
|
|
265260
|
+
return runGitHubDeviceFlow();
|
|
265261
|
+
}
|
|
265262
|
+
async function runCopilotLogin(context) {
|
|
264998
265263
|
const existingConfig = await getLlmConfig();
|
|
264999
|
-
if (existingConfig) {
|
|
265000
|
-
|
|
265001
|
-
console.log(import_picocolors8.default.green(`✓ LLM ${providerName} (${existingConfig.model}) already configured`));
|
|
265264
|
+
if (existingConfig && existingConfig.authType === "github-copilot") {
|
|
265265
|
+
console.log(import_picocolors8.default.green(`✓ GitHub Copilot (${existingConfig.model}) already configured`));
|
|
265002
265266
|
if (!context.yes) {
|
|
265003
265267
|
const shouldChange = await ye({
|
|
265004
|
-
message: "Change
|
|
265268
|
+
message: "Change Copilot model or re-authenticate?",
|
|
265005
265269
|
initialValue: false
|
|
265006
265270
|
});
|
|
265007
265271
|
if (pD(shouldChange)) {
|
|
@@ -265013,14 +265277,60 @@ async function runLlmLogin(context) {
|
|
|
265013
265277
|
}
|
|
265014
265278
|
}
|
|
265015
265279
|
}
|
|
265016
|
-
const
|
|
265017
|
-
|
|
265280
|
+
const model = await ve({
|
|
265281
|
+
message: "Select model (via GitHub Copilot):",
|
|
265282
|
+
options: COPILOT_MODEL_OPTIONS
|
|
265283
|
+
});
|
|
265284
|
+
if (pD(model)) {
|
|
265285
|
+
cancelled();
|
|
265018
265286
|
return;
|
|
265019
265287
|
}
|
|
265020
|
-
const
|
|
265021
|
-
if (!
|
|
265288
|
+
const githubToken = await getGitHubToken();
|
|
265289
|
+
if (!githubToken)
|
|
265290
|
+
return;
|
|
265291
|
+
console.log(import_picocolors8.default.dim("Authenticating with GitHub Copilot..."));
|
|
265292
|
+
let copilotResult;
|
|
265293
|
+
try {
|
|
265294
|
+
copilotResult = await exchangeCopilotToken(githubToken);
|
|
265295
|
+
} catch (err) {
|
|
265296
|
+
const msg = err instanceof Error ? err.message : "Unknown error";
|
|
265297
|
+
console.log(import_picocolors8.default.red(`✗ ${msg}`));
|
|
265298
|
+
console.log(import_picocolors8.default.dim("Make sure your GitHub account has an active Copilot Pro, Pro+, Business, or Enterprise subscription."));
|
|
265022
265299
|
return;
|
|
265023
265300
|
}
|
|
265301
|
+
await storeCopilotCredentials(model, githubToken, copilotResult.token, copilotResult.expiresAt);
|
|
265302
|
+
console.log(import_picocolors8.default.green(`✓ GitHub Copilot authenticated (${model})`));
|
|
265303
|
+
}
|
|
265304
|
+
async function runLlmLogin(context) {
|
|
265305
|
+
const existingConfig = await getLlmConfig();
|
|
265306
|
+
if (existingConfig && !context.yes) {
|
|
265307
|
+
const label = providerLabel(existingConfig);
|
|
265308
|
+
console.log(import_picocolors8.default.green(`✓ LLM ${label} (${existingConfig.model}) already configured`));
|
|
265309
|
+
const shouldChange = await ye({
|
|
265310
|
+
message: "Change LLM provider/model/key?",
|
|
265311
|
+
initialValue: false
|
|
265312
|
+
});
|
|
265313
|
+
if (pD(shouldChange)) {
|
|
265314
|
+
cancelled();
|
|
265315
|
+
return;
|
|
265316
|
+
}
|
|
265317
|
+
if (!shouldChange) {
|
|
265318
|
+
return;
|
|
265319
|
+
}
|
|
265320
|
+
}
|
|
265321
|
+
const authMode = await promptAuthMode();
|
|
265322
|
+
if (!authMode)
|
|
265323
|
+
return;
|
|
265324
|
+
if (authMode === "github-copilot") {
|
|
265325
|
+
await runCopilotLogin(context);
|
|
265326
|
+
return;
|
|
265327
|
+
}
|
|
265328
|
+
const provider = await promptProvider();
|
|
265329
|
+
if (!provider)
|
|
265330
|
+
return;
|
|
265331
|
+
const model = await promptModel(provider);
|
|
265332
|
+
if (!model)
|
|
265333
|
+
return;
|
|
265024
265334
|
const apiKey = await ge({
|
|
265025
265335
|
message: `Enter your ${PROVIDER_LABELS[provider]} API key:`,
|
|
265026
265336
|
validate: (value) => {
|
|
@@ -265043,10 +265353,23 @@ async function runModelSwitch() {
|
|
|
265043
265353
|
console.log(import_picocolors8.default.red("No LLM provider configured. Run /login llm first."));
|
|
265044
265354
|
return;
|
|
265045
265355
|
}
|
|
265046
|
-
|
|
265047
|
-
|
|
265356
|
+
if (config.authType === "github-copilot") {
|
|
265357
|
+
const model2 = await ve({
|
|
265358
|
+
message: "Select model (via GitHub Copilot):",
|
|
265359
|
+
options: COPILOT_MODEL_OPTIONS
|
|
265360
|
+
});
|
|
265361
|
+
if (pD(model2)) {
|
|
265362
|
+
cancelled();
|
|
265363
|
+
return;
|
|
265364
|
+
}
|
|
265365
|
+
await updateLlmModel(model2);
|
|
265366
|
+
console.log(import_picocolors8.default.green(`✓ Copilot model changed to ${model2}`));
|
|
265048
265367
|
return;
|
|
265049
265368
|
}
|
|
265369
|
+
const provider = config.provider;
|
|
265370
|
+
const model = await promptModel(provider);
|
|
265371
|
+
if (!model)
|
|
265372
|
+
return;
|
|
265050
265373
|
await updateLlmModel(model);
|
|
265051
265374
|
console.log(import_picocolors8.default.green(`✓ LLM model changed to ${model}`));
|
|
265052
265375
|
}
|
|
@@ -265069,7 +265392,8 @@ async function runFullLogin(context) {
|
|
|
265069
265392
|
}
|
|
265070
265393
|
const [llmConfigured, llmConfig] = await Promise.all([isLlmConfigured(), getLlmConfig()]);
|
|
265071
265394
|
if (llmConfigured && llmConfig) {
|
|
265072
|
-
|
|
265395
|
+
const label = providerLabel(llmConfig);
|
|
265396
|
+
console.log(import_picocolors8.default.green(`✓ LLM ${label} (${llmConfig.model})`));
|
|
265073
265397
|
} else {
|
|
265074
265398
|
await runLlmLogin(context);
|
|
265075
265399
|
}
|
|
@@ -265089,7 +265413,8 @@ async function runFullLogin(context) {
|
|
|
265089
265413
|
console.log(import_picocolors8.default.yellow("• Railway: not authenticated"));
|
|
265090
265414
|
}
|
|
265091
265415
|
if (finalLlmConfigured && finalLlmConfig) {
|
|
265092
|
-
|
|
265416
|
+
const label = providerLabel(finalLlmConfig);
|
|
265417
|
+
console.log(import_picocolors8.default.green(`✓ LLM: ${label} (${finalLlmConfig.model})`));
|
|
265093
265418
|
} else {
|
|
265094
265419
|
console.log(import_picocolors8.default.yellow("• LLM: not configured"));
|
|
265095
265420
|
}
|
|
@@ -265097,7 +265422,7 @@ async function runFullLogin(context) {
|
|
|
265097
265422
|
async function runLogout(context) {
|
|
265098
265423
|
if (!context.yes) {
|
|
265099
265424
|
const shouldLogout = await ye({
|
|
265100
|
-
message: "This will log out of Railway and remove your stored LLM
|
|
265425
|
+
message: "This will log out of Railway and remove your stored LLM credentials. Continue?",
|
|
265101
265426
|
initialValue: false
|
|
265102
265427
|
});
|
|
265103
265428
|
if (pD(shouldLogout)) {
|
|
@@ -265115,7 +265440,7 @@ async function runLogout(context) {
|
|
|
265115
265440
|
} else {
|
|
265116
265441
|
console.log(import_picocolors8.default.yellow("• Railway logout skipped or not authenticated"));
|
|
265117
265442
|
}
|
|
265118
|
-
console.log(import_picocolors8.default.green("✓ LLM
|
|
265443
|
+
console.log(import_picocolors8.default.green("✓ LLM credentials removed"));
|
|
265119
265444
|
}
|
|
265120
265445
|
async function loginCommand(context, args, commandKey = "login") {
|
|
265121
265446
|
if (commandKey === "logout") {
|
|
@@ -265144,8 +265469,8 @@ async function loginCommand(context, args, commandKey = "login") {
|
|
|
265144
265469
|
}
|
|
265145
265470
|
|
|
265146
265471
|
// src/commands/versions.ts
|
|
265147
|
-
import { existsSync as
|
|
265148
|
-
import { join as
|
|
265472
|
+
import { existsSync as existsSync20, readFileSync as readFileSync14, writeFileSync as writeFileSync14 } from "node:fs";
|
|
265473
|
+
import { join as join23 } from "node:path";
|
|
265149
265474
|
var import_picocolors9 = __toESM(require_picocolors(), 1);
|
|
265150
265475
|
var TABLE_HEADER_INTEGRATION = "Integration";
|
|
265151
265476
|
var TABLE_HEADER_VERSION = "Version";
|
|
@@ -265188,13 +265513,13 @@ function loadVersionsContext(logger) {
|
|
|
265188
265513
|
logger.cmd("/versions", "FAILED", "not a workspace");
|
|
265189
265514
|
return null;
|
|
265190
265515
|
}
|
|
265191
|
-
const versionsPath =
|
|
265192
|
-
if (!
|
|
265516
|
+
const versionsPath = join23(workspaceDir, "versions.md");
|
|
265517
|
+
if (!existsSync20(versionsPath)) {
|
|
265193
265518
|
error("versions.md not found in workspace root.");
|
|
265194
265519
|
logger.cmd("/versions", "FAILED", "versions.md missing");
|
|
265195
265520
|
return null;
|
|
265196
265521
|
}
|
|
265197
|
-
const versionsMarkdown =
|
|
265522
|
+
const versionsMarkdown = readFileSync14(versionsPath, "utf-8");
|
|
265198
265523
|
const result = parseVersionsTable(versionsMarkdown);
|
|
265199
265524
|
for (const parseError of result.errors) {
|
|
265200
265525
|
warn(parseError);
|
|
@@ -265622,7 +265947,7 @@ async function helpCommand(_context, _args) {
|
|
|
265622
265947
|
// package.json
|
|
265623
265948
|
var package_default = {
|
|
265624
265949
|
name: "openkitt",
|
|
265625
|
-
version: "0.3.
|
|
265950
|
+
version: "0.3.4",
|
|
265626
265951
|
description: "AI-powered monorepo scaffolding CLI",
|
|
265627
265952
|
keywords: [
|
|
265628
265953
|
"cli",
|
|
@@ -265694,8 +266019,8 @@ var STATE_CHANGING_COMMANDS = new Set([
|
|
|
265694
266019
|
"domain",
|
|
265695
266020
|
"publish"
|
|
265696
266021
|
]);
|
|
265697
|
-
var KITT_DIR3 =
|
|
265698
|
-
var UPDATE_CHECK_FILE =
|
|
266022
|
+
var KITT_DIR3 = join24(homedir6(), ".kitt");
|
|
266023
|
+
var UPDATE_CHECK_FILE = join24(KITT_DIR3, "update-check.json");
|
|
265699
266024
|
var commandRegistry = {
|
|
265700
266025
|
init: { handler: initCommand },
|
|
265701
266026
|
create: { handler: createCommand2 },
|
|
@@ -265775,11 +266100,11 @@ function isVersionNewer(latest, current) {
|
|
|
265775
266100
|
return false;
|
|
265776
266101
|
}
|
|
265777
266102
|
function hasFreshUpdateCache(now) {
|
|
265778
|
-
if (!
|
|
266103
|
+
if (!existsSync21(UPDATE_CHECK_FILE)) {
|
|
265779
266104
|
return false;
|
|
265780
266105
|
}
|
|
265781
266106
|
try {
|
|
265782
|
-
const rawCache =
|
|
266107
|
+
const rawCache = readFileSync15(UPDATE_CHECK_FILE, "utf-8").trim();
|
|
265783
266108
|
if (rawCache.length === 0) {
|
|
265784
266109
|
return false;
|
|
265785
266110
|
}
|