openkitt 0.3.2 → 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 +367 -41
- 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
|
|
@@ -256991,7 +257109,8 @@ var WORKSPACE_REQUIRED = new Set([
|
|
|
256991
257109
|
"domain",
|
|
256992
257110
|
"logs",
|
|
256993
257111
|
"status",
|
|
256994
|
-
"settings"
|
|
257112
|
+
"settings",
|
|
257113
|
+
"versions"
|
|
256995
257114
|
]);
|
|
256996
257115
|
var APPS_REQUIRED = new Set([
|
|
256997
257116
|
"delete",
|
|
@@ -257757,11 +257876,36 @@ function createGeminiClient(Provider, apiKey, model, rateLimiter) {
|
|
|
257757
257876
|
}
|
|
257758
257877
|
};
|
|
257759
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
|
+
}
|
|
257760
257896
|
async function createLlmClient(rateLimiter) {
|
|
257761
|
-
const
|
|
257897
|
+
const llmConfig = await getLlmConfig();
|
|
257762
257898
|
if (!llmConfig) {
|
|
257763
257899
|
throw new Error("LLM provider is not configured. Run /login llm to configure it.");
|
|
257764
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();
|
|
257765
257909
|
if (!apiKey) {
|
|
257766
257910
|
throw new Error("LLM API key is not configured. Run /login llm to configure it.");
|
|
257767
257911
|
}
|
|
@@ -264917,6 +265061,9 @@ async function statusCommand(_context, _args, _commandKey) {
|
|
|
264917
265061
|
}
|
|
264918
265062
|
|
|
264919
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";
|
|
264920
265067
|
init_config();
|
|
264921
265068
|
var import_picocolors8 = __toESM(require_picocolors(), 1);
|
|
264922
265069
|
var PROVIDER_LABELS = {
|
|
@@ -264947,10 +265094,23 @@ var MODEL_OPTIONS = {
|
|
|
264947
265094
|
{ value: "gemini-1.5-pro", label: "gemini-1.5-pro" }
|
|
264948
265095
|
]
|
|
264949
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";
|
|
264950
265105
|
function cancelled() {
|
|
264951
265106
|
console.log(import_picocolors8.default.yellow("Cancelled."));
|
|
264952
265107
|
return true;
|
|
264953
265108
|
}
|
|
265109
|
+
function providerLabel(config) {
|
|
265110
|
+
if (config.authType === "github-copilot")
|
|
265111
|
+
return "GitHub Copilot";
|
|
265112
|
+
return PROVIDER_LABELS[config.provider] ?? config.provider;
|
|
265113
|
+
}
|
|
264954
265114
|
async function runRailwayLogin() {
|
|
264955
265115
|
const status = await checkRailwayAuth();
|
|
264956
265116
|
if (status.authenticated) {
|
|
@@ -264971,6 +265131,20 @@ async function runRailwayLogin() {
|
|
|
264971
265131
|
}
|
|
264972
265132
|
console.log(import_picocolors8.default.red(loginStatus.error ?? "Failed to authenticate with Railway."));
|
|
264973
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
|
+
}
|
|
264974
265148
|
async function promptProvider() {
|
|
264975
265149
|
const provider = await ve({
|
|
264976
265150
|
message: "Select LLM provider:",
|
|
@@ -264993,14 +265167,105 @@ async function promptModel(provider) {
|
|
|
264993
265167
|
}
|
|
264994
265168
|
return model;
|
|
264995
265169
|
}
|
|
264996
|
-
|
|
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) {
|
|
264997
265263
|
const existingConfig = await getLlmConfig();
|
|
264998
|
-
if (existingConfig) {
|
|
264999
|
-
|
|
265000
|
-
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`));
|
|
265001
265266
|
if (!context.yes) {
|
|
265002
265267
|
const shouldChange = await ye({
|
|
265003
|
-
message: "Change
|
|
265268
|
+
message: "Change Copilot model or re-authenticate?",
|
|
265004
265269
|
initialValue: false
|
|
265005
265270
|
});
|
|
265006
265271
|
if (pD(shouldChange)) {
|
|
@@ -265012,14 +265277,60 @@ async function runLlmLogin(context) {
|
|
|
265012
265277
|
}
|
|
265013
265278
|
}
|
|
265014
265279
|
}
|
|
265015
|
-
const
|
|
265016
|
-
|
|
265280
|
+
const model = await ve({
|
|
265281
|
+
message: "Select model (via GitHub Copilot):",
|
|
265282
|
+
options: COPILOT_MODEL_OPTIONS
|
|
265283
|
+
});
|
|
265284
|
+
if (pD(model)) {
|
|
265285
|
+
cancelled();
|
|
265017
265286
|
return;
|
|
265018
265287
|
}
|
|
265019
|
-
const
|
|
265020
|
-
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."));
|
|
265021
265299
|
return;
|
|
265022
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;
|
|
265023
265334
|
const apiKey = await ge({
|
|
265024
265335
|
message: `Enter your ${PROVIDER_LABELS[provider]} API key:`,
|
|
265025
265336
|
validate: (value) => {
|
|
@@ -265042,10 +265353,23 @@ async function runModelSwitch() {
|
|
|
265042
265353
|
console.log(import_picocolors8.default.red("No LLM provider configured. Run /login llm first."));
|
|
265043
265354
|
return;
|
|
265044
265355
|
}
|
|
265045
|
-
|
|
265046
|
-
|
|
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}`));
|
|
265047
265367
|
return;
|
|
265048
265368
|
}
|
|
265369
|
+
const provider = config.provider;
|
|
265370
|
+
const model = await promptModel(provider);
|
|
265371
|
+
if (!model)
|
|
265372
|
+
return;
|
|
265049
265373
|
await updateLlmModel(model);
|
|
265050
265374
|
console.log(import_picocolors8.default.green(`✓ LLM model changed to ${model}`));
|
|
265051
265375
|
}
|
|
@@ -265068,7 +265392,8 @@ async function runFullLogin(context) {
|
|
|
265068
265392
|
}
|
|
265069
265393
|
const [llmConfigured, llmConfig] = await Promise.all([isLlmConfigured(), getLlmConfig()]);
|
|
265070
265394
|
if (llmConfigured && llmConfig) {
|
|
265071
|
-
|
|
265395
|
+
const label = providerLabel(llmConfig);
|
|
265396
|
+
console.log(import_picocolors8.default.green(`✓ LLM ${label} (${llmConfig.model})`));
|
|
265072
265397
|
} else {
|
|
265073
265398
|
await runLlmLogin(context);
|
|
265074
265399
|
}
|
|
@@ -265088,7 +265413,8 @@ async function runFullLogin(context) {
|
|
|
265088
265413
|
console.log(import_picocolors8.default.yellow("• Railway: not authenticated"));
|
|
265089
265414
|
}
|
|
265090
265415
|
if (finalLlmConfigured && finalLlmConfig) {
|
|
265091
|
-
|
|
265416
|
+
const label = providerLabel(finalLlmConfig);
|
|
265417
|
+
console.log(import_picocolors8.default.green(`✓ LLM: ${label} (${finalLlmConfig.model})`));
|
|
265092
265418
|
} else {
|
|
265093
265419
|
console.log(import_picocolors8.default.yellow("• LLM: not configured"));
|
|
265094
265420
|
}
|
|
@@ -265096,7 +265422,7 @@ async function runFullLogin(context) {
|
|
|
265096
265422
|
async function runLogout(context) {
|
|
265097
265423
|
if (!context.yes) {
|
|
265098
265424
|
const shouldLogout = await ye({
|
|
265099
|
-
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?",
|
|
265100
265426
|
initialValue: false
|
|
265101
265427
|
});
|
|
265102
265428
|
if (pD(shouldLogout)) {
|
|
@@ -265114,7 +265440,7 @@ async function runLogout(context) {
|
|
|
265114
265440
|
} else {
|
|
265115
265441
|
console.log(import_picocolors8.default.yellow("• Railway logout skipped or not authenticated"));
|
|
265116
265442
|
}
|
|
265117
|
-
console.log(import_picocolors8.default.green("✓ LLM
|
|
265443
|
+
console.log(import_picocolors8.default.green("✓ LLM credentials removed"));
|
|
265118
265444
|
}
|
|
265119
265445
|
async function loginCommand(context, args, commandKey = "login") {
|
|
265120
265446
|
if (commandKey === "logout") {
|
|
@@ -265143,8 +265469,8 @@ async function loginCommand(context, args, commandKey = "login") {
|
|
|
265143
265469
|
}
|
|
265144
265470
|
|
|
265145
265471
|
// src/commands/versions.ts
|
|
265146
|
-
import { existsSync as
|
|
265147
|
-
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";
|
|
265148
265474
|
var import_picocolors9 = __toESM(require_picocolors(), 1);
|
|
265149
265475
|
var TABLE_HEADER_INTEGRATION = "Integration";
|
|
265150
265476
|
var TABLE_HEADER_VERSION = "Version";
|
|
@@ -265187,13 +265513,13 @@ function loadVersionsContext(logger) {
|
|
|
265187
265513
|
logger.cmd("/versions", "FAILED", "not a workspace");
|
|
265188
265514
|
return null;
|
|
265189
265515
|
}
|
|
265190
|
-
const versionsPath =
|
|
265191
|
-
if (!
|
|
265516
|
+
const versionsPath = join23(workspaceDir, "versions.md");
|
|
265517
|
+
if (!existsSync20(versionsPath)) {
|
|
265192
265518
|
error("versions.md not found in workspace root.");
|
|
265193
265519
|
logger.cmd("/versions", "FAILED", "versions.md missing");
|
|
265194
265520
|
return null;
|
|
265195
265521
|
}
|
|
265196
|
-
const versionsMarkdown =
|
|
265522
|
+
const versionsMarkdown = readFileSync14(versionsPath, "utf-8");
|
|
265197
265523
|
const result = parseVersionsTable(versionsMarkdown);
|
|
265198
265524
|
for (const parseError of result.errors) {
|
|
265199
265525
|
warn(parseError);
|
|
@@ -265621,7 +265947,7 @@ async function helpCommand(_context, _args) {
|
|
|
265621
265947
|
// package.json
|
|
265622
265948
|
var package_default = {
|
|
265623
265949
|
name: "openkitt",
|
|
265624
|
-
version: "0.3.
|
|
265950
|
+
version: "0.3.4",
|
|
265625
265951
|
description: "AI-powered monorepo scaffolding CLI",
|
|
265626
265952
|
keywords: [
|
|
265627
265953
|
"cli",
|
|
@@ -265693,8 +266019,8 @@ var STATE_CHANGING_COMMANDS = new Set([
|
|
|
265693
266019
|
"domain",
|
|
265694
266020
|
"publish"
|
|
265695
266021
|
]);
|
|
265696
|
-
var KITT_DIR3 =
|
|
265697
|
-
var UPDATE_CHECK_FILE =
|
|
266022
|
+
var KITT_DIR3 = join24(homedir6(), ".kitt");
|
|
266023
|
+
var UPDATE_CHECK_FILE = join24(KITT_DIR3, "update-check.json");
|
|
265698
266024
|
var commandRegistry = {
|
|
265699
266025
|
init: { handler: initCommand },
|
|
265700
266026
|
create: { handler: createCommand2 },
|
|
@@ -265774,11 +266100,11 @@ function isVersionNewer(latest, current) {
|
|
|
265774
266100
|
return false;
|
|
265775
266101
|
}
|
|
265776
266102
|
function hasFreshUpdateCache(now) {
|
|
265777
|
-
if (!
|
|
266103
|
+
if (!existsSync21(UPDATE_CHECK_FILE)) {
|
|
265778
266104
|
return false;
|
|
265779
266105
|
}
|
|
265780
266106
|
try {
|
|
265781
|
-
const rawCache =
|
|
266107
|
+
const rawCache = readFileSync15(UPDATE_CHECK_FILE, "utf-8").trim();
|
|
265782
266108
|
if (rawCache.length === 0) {
|
|
265783
266109
|
return false;
|
|
265784
266110
|
}
|