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.
Files changed (2) hide show
  1. package/dist/cli.js +365 -40
  2. 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
- if (typeof llm.apiKey !== "string" || typeof llm.iv !== "string" || typeof llm.salt !== "string" || typeof llm.authTag !== "string") {
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: llm.apiKey,
2727
- iv: llm.iv,
2728
- salt: llm.salt,
2729
- authTag: llm.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 [apiKey, llmConfig] = await Promise.all([getLlmApiKey(), getLlmConfig()]);
2773
- return apiKey !== null && llmConfig !== null;
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 existsSync20, mkdirSync as mkdirSync11, readFileSync as readFileSync14, writeFileSync as writeFileSync15, realpathSync } from "node:fs";
255599
- import { homedir as homedir5 } from "node:os";
255600
- import { join as join23, resolve as resolve6, dirname as dirname5 } from "node:path";
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 [llmConfig, apiKey] = await Promise.all([getLlmConfig(), getLlmApiKey()]);
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
- async function runLlmLogin(context) {
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
- const providerName = PROVIDER_LABELS[existingConfig.provider];
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 LLM provider/model/key?",
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 provider = await promptProvider();
265017
- if (!provider) {
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 model = await promptModel(provider);
265021
- if (!model) {
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
- const model = await promptModel(config.provider);
265047
- if (!model) {
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
- console.log(import_picocolors8.default.green(`✓ LLM ${PROVIDER_LABELS[llmConfig.provider]} (${llmConfig.model})`));
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
- console.log(import_picocolors8.default.green(`✓ LLM: ${PROVIDER_LABELS[finalLlmConfig.provider]} (${finalLlmConfig.model})`));
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 API key. Continue?",
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 key removed"));
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 existsSync19, readFileSync as readFileSync13, writeFileSync as writeFileSync14 } from "node:fs";
265148
- import { join as join22 } from "node:path";
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 = join22(workspaceDir, "versions.md");
265192
- if (!existsSync19(versionsPath)) {
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 = readFileSync13(versionsPath, "utf-8");
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.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 = join23(homedir5(), ".kitt");
265698
- var UPDATE_CHECK_FILE = join23(KITT_DIR3, "update-check.json");
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 (!existsSync20(UPDATE_CHECK_FILE)) {
266103
+ if (!existsSync21(UPDATE_CHECK_FILE)) {
265779
266104
  return false;
265780
266105
  }
265781
266106
  try {
265782
- const rawCache = readFileSync14(UPDATE_CHECK_FILE, "utf-8").trim();
266107
+ const rawCache = readFileSync15(UPDATE_CHECK_FILE, "utf-8").trim();
265783
266108
  if (rawCache.length === 0) {
265784
266109
  return false;
265785
266110
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openkitt",
3
- "version": "0.3.3",
3
+ "version": "0.3.4",
4
4
  "description": "AI-powered monorepo scaffolding CLI",
5
5
  "keywords": [
6
6
  "cli",