@kyma-api/agent 0.1.3 → 0.1.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/main.js CHANGED
@@ -111,7 +111,6 @@ var KymaInteractiveMode = class extends InteractiveMode {
111
111
 
112
112
  // src/sdk/onboarding.ts
113
113
  import { existsSync as existsSync2, mkdirSync, readFileSync as readFileSync3, writeFileSync as writeFileSync2, copyFileSync } from "fs";
114
- import { createInterface } from "readline";
115
114
  import { join as join3, dirname as dirname2 } from "path";
116
115
  import { fileURLToPath as fileURLToPath2 } from "url";
117
116
 
@@ -146,7 +145,7 @@ var VERSION = (() => {
146
145
  function normalizeKymaError(status, body) {
147
146
  switch (status) {
148
147
  case 401:
149
- return { code: 401, severity: "error", message: "Session expired.", action: "Run /login to reconnect." };
148
+ return { code: 401, severity: "error", message: "Session expired.", action: "Run /connect to reconnect." };
150
149
  case 402:
151
150
  return { code: 402, severity: "error", message: "Insufficient Kyma credits.", action: "Run /billing to top up." };
152
151
  case 429:
@@ -175,30 +174,39 @@ async function kymaApi(path, apiKey) {
175
174
  return res.json();
176
175
  }
177
176
  var GOLD = "\x1B[38;2;201;168;76m";
178
- var DIM = "\x1B[38;2;107;114;133m";
177
+ var CYAN = "\x1B[38;2;86;182;194m";
178
+ var DIM = "\x1B[38;2;96;96;96m";
179
+ var BORDER = "\x1B[38;2;60;60;60m";
179
180
  var RESET = "\x1B[0m";
180
181
  var BOLD = "\x1B[1m";
181
- var WHITE = "\x1B[38;2;232;234;242m";
182
- var DARK_GRAY = "\x1B[38;2;74;78;92m";
182
+ var DIM_MOD = "\x1B[2m";
183
+ var ITALIC = "\x1B[3m";
184
+ var WHITE = "\x1B[38;2;238;238;238m";
185
+ var DARK_GRAY = "\x1B[38;2;72;72;72m";
183
186
  var term = {
184
187
  gold: (s) => `${GOLD}${s}${RESET}`,
188
+ cyan: (s) => `${CYAN}${s}${RESET}`,
185
189
  dim: (s) => `${DIM}${s}${RESET}`,
186
190
  bold: (s) => `${BOLD}${s}${RESET}`,
187
191
  brand: (s) => `${BOLD}${GOLD}${s}${RESET}`,
188
- // bold + gold
192
+ // bold + gold (brand moments only)
189
193
  white: (s) => `${WHITE}${s}${RESET}`,
190
- hr: (w = 36) => `${DARK_GRAY}${"\u2501".repeat(w)}${RESET}`,
191
- /** Render a gold-bordered card. Lines are padded to uniform width. */
194
+ muted: (s) => `${DIM_MOD}${s}${RESET}`,
195
+ // ANSI dim modifier
196
+ subtle: (s) => `${DIM_MOD}${ITALIC}${s}${RESET}`,
197
+ // dim + italic (thinking)
198
+ hr: (w = 36) => `${DARK_GRAY}${"\u2500".repeat(w)}${RESET}`,
199
+ /** Render a subtle-bordered card. Gold brand reserved for content, not chrome. */
192
200
  card(lines) {
193
201
  const strip = (s) => s.replace(/\x1b\[[0-9;]*m/g, "");
194
202
  const innerW = Math.max(36, ...lines.map((l) => strip(l).length + 4));
195
- const top = `${GOLD} \u256D${"\u2500".repeat(innerW)}\u256E${RESET}`;
196
- const bot = `${GOLD} \u2570${"\u2500".repeat(innerW)}\u256F${RESET}`;
203
+ const top = `${BORDER} \u256D${"\u2500".repeat(innerW)}\u256E${RESET}`;
204
+ const bot = `${BORDER} \u2570${"\u2500".repeat(innerW)}\u256F${RESET}`;
197
205
  const row = (s) => {
198
206
  const pad = innerW - strip(s).length - 4;
199
- return `${GOLD} \u2502${RESET} ${s}${" ".repeat(Math.max(0, pad))} ${GOLD}\u2502${RESET}`;
207
+ return `${BORDER} \u2502${RESET} ${s}${" ".repeat(Math.max(0, pad))} ${BORDER}\u2502${RESET}`;
200
208
  };
201
- const empty = `${GOLD} \u2502${RESET}${" ".repeat(innerW)}${GOLD}\u2502${RESET}`;
209
+ const empty = `${BORDER} \u2502${RESET}${" ".repeat(innerW)}${BORDER}\u2502${RESET}`;
202
210
  return [top, empty, ...lines.map(row), empty, bot];
203
211
  }
204
212
  };
@@ -318,6 +326,32 @@ async function loginKyma(callbacks) {
318
326
  }
319
327
  throw new Error("Authentication timed out. Please try again.");
320
328
  }
329
+ async function validateApiKey(apiKey) {
330
+ const res = await fetch(`${KYMA_BASE_URL}/v1/auth/me`, {
331
+ headers: { Authorization: `Bearer ${apiKey}` }
332
+ });
333
+ if (!res.ok) throw new Error("Invalid API key. Check and try again.");
334
+ const me = await res.json();
335
+ let balance;
336
+ try {
337
+ const balRes = await fetch(`${KYMA_BASE_URL}/v1/credits/balance`, {
338
+ headers: { Authorization: `Bearer ${apiKey}` }
339
+ });
340
+ if (balRes.ok) {
341
+ const balData = await balRes.json();
342
+ balance = balData.balance;
343
+ }
344
+ } catch {
345
+ }
346
+ return {
347
+ refresh: "",
348
+ access: apiKey,
349
+ expires: Date.now() + 365 * 24 * 60 * 60 * 1e3,
350
+ email: me.email,
351
+ userId: me.id,
352
+ balance
353
+ };
354
+ }
321
355
  async function refreshKymaToken(credentials) {
322
356
  const res = await fetch(`${KYMA_BASE_URL}/v1/auth/me`, {
323
357
  headers: { Authorization: `Bearer ${credentials.access}` }
@@ -371,7 +405,7 @@ function ensureAgentDir() {
371
405
  if (!existsSync2(KYMA_SETTINGS_PATH)) {
372
406
  writeFileSync2(KYMA_SETTINGS_PATH, JSON.stringify({
373
407
  defaultProvider: "kyma",
374
- defaultModel: "qwen-3-32b",
408
+ defaultModel: "qwen-3.6-plus",
375
409
  quietStartup: true,
376
410
  theme: "kyma-dark",
377
411
  hideThinkingBlock: false,
@@ -385,8 +419,8 @@ function ensureAgentDir() {
385
419
  settings.defaultProvider = "kyma";
386
420
  changed = true;
387
421
  }
388
- if (!settings.defaultModel) {
389
- settings.defaultModel = "qwen-3-32b";
422
+ if (!settings.defaultModel || settings.defaultModel === "qwen-3-32b") {
423
+ settings.defaultModel = "qwen-3.6-plus";
390
424
  changed = true;
391
425
  }
392
426
  if (settings.quietStartup !== true) {
@@ -412,15 +446,126 @@ function ensureAgentDir() {
412
446
  }
413
447
  }
414
448
  }
415
- function ask(question) {
416
- const rl = createInterface({ input: process.stdin, output: process.stdout });
449
+ function askHidden(question) {
417
450
  return new Promise((resolve) => {
418
- rl.question(question, (answer) => {
419
- rl.close();
420
- resolve(answer.trim());
421
- });
451
+ process.stdout.write(question);
452
+ if (process.stdin.isTTY) {
453
+ process.stdin.setRawMode(true);
454
+ }
455
+ process.stdin.resume();
456
+ let input = "";
457
+ const onData = (data) => {
458
+ const key = data.toString();
459
+ if (key === "\x1B") {
460
+ cleanup();
461
+ console.log("");
462
+ resolve("");
463
+ return;
464
+ }
465
+ if (key === "") {
466
+ cleanup();
467
+ console.log("");
468
+ resolve("");
469
+ return;
470
+ }
471
+ if (key === "\r" || key === "\n") {
472
+ cleanup();
473
+ console.log("");
474
+ resolve(input.trim());
475
+ return;
476
+ }
477
+ if (key === "\x7F" || key === "\b") {
478
+ if (input.length > 0) input = input.slice(0, -1);
479
+ return;
480
+ }
481
+ if (key.length === 1 && key >= " ") {
482
+ input += key;
483
+ }
484
+ };
485
+ const cleanup = () => {
486
+ process.stdin.removeListener("data", onData);
487
+ if (process.stdin.isTTY) {
488
+ process.stdin.setRawMode(false);
489
+ }
490
+ process.stdin.pause();
491
+ };
492
+ process.stdin.on("data", onData);
493
+ });
494
+ }
495
+ function select(options) {
496
+ return new Promise((resolve) => {
497
+ let selected = 0;
498
+ const render = () => {
499
+ if (renderCount > 0) {
500
+ process.stdout.write(`\x1B[${options.length + 1}A`);
501
+ }
502
+ for (let i = 0; i < options.length; i++) {
503
+ const num = `${i + 1}.`;
504
+ const hint = options[i].hint ? ` ${term.dim(`(${options[i].hint})`)}` : "";
505
+ if (i === selected) {
506
+ process.stdout.write(`\x1B[2K ${term.gold(">")} ${term.gold(num)} ${term.white(options[i].label)}${hint}
507
+ `);
508
+ } else {
509
+ process.stdout.write(`\x1B[2K ${term.dim(num)} ${term.dim(options[i].label)}
510
+ `);
511
+ }
512
+ }
513
+ process.stdout.write(`\x1B[2K ${term.dim("\u2191\u2193 navigate \xB7 enter select \xB7 esc cancel")}
514
+ `);
515
+ renderCount++;
516
+ };
517
+ let renderCount = 0;
518
+ render();
519
+ if (process.stdin.isTTY) {
520
+ process.stdin.setRawMode(true);
521
+ }
522
+ process.stdin.resume();
523
+ const onData = (data) => {
524
+ const key = data.toString();
525
+ if (key === "\x1B[A" || key === "k") {
526
+ selected = (selected - 1 + options.length) % options.length;
527
+ render();
528
+ return;
529
+ }
530
+ if (key === "\x1B[B" || key === "j") {
531
+ selected = (selected + 1) % options.length;
532
+ render();
533
+ return;
534
+ }
535
+ if (key === "\r" || key === "\n") {
536
+ cleanup();
537
+ resolve(selected);
538
+ return;
539
+ }
540
+ if (key === "" || key === "\x1B") {
541
+ cleanup();
542
+ resolve(-1);
543
+ return;
544
+ }
545
+ };
546
+ const cleanup = () => {
547
+ process.stdin.removeListener("data", onData);
548
+ if (process.stdin.isTTY) {
549
+ process.stdin.setRawMode(false);
550
+ }
551
+ process.stdin.pause();
552
+ };
553
+ process.stdin.on("data", onData);
422
554
  });
423
555
  }
556
+ var SPINNER_FRAMES = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
557
+ function startSpinner(message) {
558
+ let frame = 0;
559
+ const interval = setInterval(() => {
560
+ const f = SPINNER_FRAMES[frame % SPINNER_FRAMES.length];
561
+ process.stdout.write(`\r ${f} ${message}`);
562
+ frame++;
563
+ }, 100);
564
+ return () => {
565
+ clearInterval(interval);
566
+ process.stdout.write(`\r${" ".repeat(message.length + 10)}\r`);
567
+ };
568
+ }
424
569
  async function runOnboarding() {
425
570
  ensureAgentDir();
426
571
  const onboarded = existsSync2(KYMA_ONBOARDED_PATH);
@@ -434,42 +579,65 @@ async function runOnboarding() {
434
579
  console.log("");
435
580
  printBanner();
436
581
  console.log("");
437
- console.log(` ${term.dim("One account, many models.")}`);
438
- console.log(` ${term.dim(`v${VERSION} \xB7 kymaapi.com`)}`);
582
+ console.log(` Welcome to ${term.brand("Kyma")}, your AI coding agent`);
439
583
  console.log("");
440
- const answer = await ask(" Connect now? (Y/n) ");
441
- if (answer.toLowerCase() === "n" || answer.toLowerCase() === "no") {
442
- console.log(` ${term.dim("Skipped.")} Use ${term.gold("/login")} anytime.`);
443
- console.log("");
444
- markOnboarded();
445
- return false;
446
- }
447
- try {
448
- const credentials = await loginKymaStandalone();
449
- saveKymaCredentials(credentials);
450
- const balStr = credentials.balance != null ? term.gold(`$${credentials.balance.toFixed(2)}`) : "";
451
- process.stdout.write("\x1B[2J\x1B[H");
452
- console.log("");
453
- console.log(` ${term.gold("\u25C7")} ${term.brand("Authorized")}`);
454
- console.log("");
455
- printBanner();
456
- console.log("");
457
- console.log(` ${term.brand("\u03A8")} ${term.white("You're in. Let's go.")}`);
458
- console.log("");
459
- console.log(` ${term.dim("Account")} ${term.white(credentials.email)}`);
460
- if (balStr) {
461
- console.log(` ${term.dim("Balance")} ${balStr}`);
584
+ console.log(` ${term.dim("Sign in to get started, or connect a Kyma API key")}`);
585
+ console.log(` ${term.dim("for usage-based billing.")}`);
586
+ console.log("");
587
+ let done = false;
588
+ while (!done) {
589
+ const choice = await select([
590
+ { label: "Sign in with Kyma", hint: "opens browser" },
591
+ { label: "Paste your Kyma API key", hint: "" }
592
+ ]);
593
+ if (choice === -1) {
594
+ console.log("");
595
+ console.log(` ${term.dim("Skipped.")} Use ${term.gold("/connect")} anytime.`);
596
+ console.log("");
597
+ done = true;
598
+ break;
599
+ }
600
+ if (choice === 1) {
601
+ console.log("");
602
+ console.log(` ${term.dim("Paste your Kyma API key below. Press Esc to go back.")}`);
603
+ console.log("");
604
+ const key = await askHidden(` ${term.dim("Kyma API key:")} `);
605
+ if (!key) {
606
+ console.log("");
607
+ continue;
608
+ }
609
+ try {
610
+ const stopSpinner = startSpinner("Validating...");
611
+ const credentials = await validateApiKey(key);
612
+ stopSpinner();
613
+ saveKymaCredentials(credentials);
614
+ const balStr = credentials.balance != null ? ` \xB7 $${credentials.balance.toFixed(2)}` : "";
615
+ console.log(` ${term.gold("\u2713")} Connected as ${term.white(credentials.email)}${balStr}`);
616
+ console.log("");
617
+ done = true;
618
+ } catch (err) {
619
+ console.log(` ${term.dim("Invalid key:")} ${err.message}`);
620
+ console.log("");
621
+ continue;
622
+ }
623
+ } else {
624
+ console.log("");
625
+ try {
626
+ const stopSpinner = startSpinner("Waiting for authorization...");
627
+ const credentials = await loginKymaStandalone();
628
+ stopSpinner();
629
+ saveKymaCredentials(credentials);
630
+ const balStr = credentials.balance != null ? ` \xB7 $${credentials.balance.toFixed(2)}` : "";
631
+ console.log(` ${term.gold("\u2713")} Connected as ${term.white(credentials.email)}${balStr}`);
632
+ console.log("");
633
+ done = true;
634
+ } catch (err) {
635
+ console.log("");
636
+ console.log(` ${term.dim("Login failed:")} ${err.message}`);
637
+ console.log("");
638
+ continue;
639
+ }
462
640
  }
463
- console.log(` ${term.hr()}`);
464
- console.log("");
465
- await new Promise((r) => setTimeout(r, 2500));
466
- process.stdout.write("\x1B[2J\x1B[H");
467
- process.env.KYMA_FRESH_LOGIN = "1";
468
- } catch (err) {
469
- console.log("");
470
- console.log(` ${term.dim("Login failed:")} ${err.message}`);
471
- console.log(` ${term.dim("Try again with")} ${term.gold("/login")}`);
472
- console.log("");
473
641
  }
474
642
  markOnboarded();
475
643
  return isLoggedIn();
@@ -547,7 +715,7 @@ async function createKymaSession(options) {
547
715
  }
548
716
 
549
717
  // src/sdk/extension.ts
550
- import { existsSync as existsSync3, readFileSync as readFileSync4, writeFileSync as writeFileSync3 } from "fs";
718
+ import { existsSync as existsSync3, readFileSync as readFileSync4 } from "fs";
551
719
  import { join as join5 } from "path";
552
720
 
553
721
  // src/sdk/config.ts
@@ -565,19 +733,20 @@ function parseKymaConfig(raw) {
565
733
 
566
734
  // src/models.ts
567
735
  var KYMA_MODELS = [
568
- // --- Qwen ---
736
+ // --- Flagship ---
569
737
  {
570
- id: "qwen-3-32b",
571
- name: "Qwen 3 32B",
572
- tag: "fast coding",
573
- reasoning: false,
738
+ id: "qwen-3.6-plus",
739
+ name: "Qwen 3.6 Plus",
740
+ tag: "flagship",
741
+ reasoning: true,
574
742
  vision: false,
575
743
  input: ["text"],
576
- cost: { input: 0.392, output: 0.81, cacheRead: 0.039, cacheWrite: 0 },
577
- contextWindow: 32768,
578
- maxTokens: 8192,
579
- modes: ["fast"]
744
+ cost: { input: 0.439, output: 2.633, cacheRead: 0.044, cacheWrite: 0 },
745
+ contextWindow: 131072,
746
+ maxTokens: 16384,
747
+ compat: { thinkingFormat: "qwen" }
580
748
  },
749
+ // --- Code Specialist ---
581
750
  {
582
751
  id: "qwen-3-coder",
583
752
  name: "Qwen 3 Coder",
@@ -590,54 +759,19 @@ var KYMA_MODELS = [
590
759
  maxTokens: 16384,
591
760
  modes: ["coding"]
592
761
  },
762
+ // --- Reasoning + Code ---
593
763
  {
594
- id: "qwen-3.6-plus",
595
- name: "Qwen 3.6 Plus",
596
- tag: "flagship",
764
+ id: "deepseek-v3",
765
+ name: "DeepSeek V3",
766
+ tag: "reasoning + code",
597
767
  reasoning: true,
598
768
  vision: false,
599
769
  input: ["text"],
600
- cost: { input: 0.439, output: 2.633, cacheRead: 0.044, cacheWrite: 0 },
601
- contextWindow: 131072,
602
- maxTokens: 16384,
603
- compat: { thinkingFormat: "qwen" }
604
- },
605
- // --- Google ---
606
- {
607
- id: "gemma-4-31b",
608
- name: "Gemma 4 31B",
609
- tag: "vision + cheap",
610
- reasoning: false,
611
- vision: true,
612
- input: ["text", "image"],
613
- cost: { input: 0.189, output: 0.54, cacheRead: 0.019, cacheWrite: 0 },
614
- contextWindow: 128e3,
615
- maxTokens: 8192
616
- },
617
- {
618
- id: "gemini-2.5-flash",
619
- name: "Gemini 2.5 Flash",
620
- tag: "vision + 1M ctx",
621
- reasoning: false,
622
- vision: true,
623
- input: ["text", "image"],
624
- cost: { input: 0.405, output: 3.375, cacheRead: 0.041, cacheWrite: 0 },
625
- contextWindow: 1048576,
626
- maxTokens: 65536,
627
- modes: ["vision"]
628
- },
629
- {
630
- id: "gemini-3-flash",
631
- name: "Gemini 3 Flash",
632
- tag: "reasoning + vision",
633
- reasoning: true,
634
- vision: true,
635
- input: ["text", "image"],
636
- cost: { input: 0.675, output: 4.05, cacheRead: 0.068, cacheWrite: 0 },
637
- contextWindow: 1048576,
638
- maxTokens: 65536
770
+ cost: { input: 0.81, output: 2.295, cacheRead: 0, cacheWrite: 0 },
771
+ contextWindow: 16e4,
772
+ maxTokens: 16384
639
773
  },
640
- // --- MiniMax ---
774
+ // --- Agentic Coding ---
641
775
  {
642
776
  id: "minimax-m2.5",
643
777
  name: "MiniMax M2.5",
@@ -652,7 +786,7 @@ var KYMA_MODELS = [
652
786
  {
653
787
  id: "minimax-m2.7",
654
788
  name: "MiniMax M2.7",
655
- tag: "agentic coding",
789
+ tag: "agentic coding (new)",
656
790
  reasoning: false,
657
791
  vision: false,
658
792
  input: ["text"],
@@ -660,18 +794,20 @@ var KYMA_MODELS = [
660
794
  contextWindow: 204800,
661
795
  maxTokens: 16384
662
796
  },
663
- // --- DeepSeek ---
797
+ // --- Agentic + Long Context ---
664
798
  {
665
- id: "deepseek-v3",
666
- name: "DeepSeek V3",
667
- tag: "reasoning + code",
668
- reasoning: true,
799
+ id: "kimi-k2.5",
800
+ name: "Kimi K2.5",
801
+ tag: "agentic + long ctx",
802
+ reasoning: false,
669
803
  vision: false,
670
804
  input: ["text"],
671
- cost: { input: 0.81, output: 2.295, cacheRead: 0, cacheWrite: 0 },
672
- contextWindow: 16e4,
673
- maxTokens: 16384
805
+ cost: { input: 0.675, output: 3.78, cacheRead: 0, cacheWrite: 0 },
806
+ contextWindow: 262144,
807
+ maxTokens: 16384,
808
+ modes: ["long"]
674
809
  },
810
+ // --- Deep Reasoning ---
675
811
  {
676
812
  id: "deepseek-r1",
677
813
  name: "DeepSeek R1",
@@ -685,23 +821,11 @@ var KYMA_MODELS = [
685
821
  compat: { requiresThinkingAsText: true },
686
822
  modes: ["reasoning"]
687
823
  },
688
- // --- Meta ---
689
- {
690
- id: "llama-3.3-70b",
691
- name: "Llama 3.3 70B",
692
- tag: "all-rounder",
693
- reasoning: true,
694
- vision: false,
695
- input: ["text"],
696
- cost: { input: 1.188, output: 1.188, cacheRead: 0.119, cacheWrite: 0 },
697
- contextWindow: 128e3,
698
- maxTokens: 16384
699
- },
700
- // --- OpenAI ---
824
+ // --- Budget + Fast ---
701
825
  {
702
826
  id: "gpt-oss-120b",
703
827
  name: "GPT-OSS 120B",
704
- tag: "best value",
828
+ tag: "budget + fast",
705
829
  reasoning: false,
706
830
  vision: false,
707
831
  input: ["text"],
@@ -710,18 +834,18 @@ var KYMA_MODELS = [
710
834
  maxTokens: 16384,
711
835
  modes: ["cheap"]
712
836
  },
713
- // --- Moonshot ---
837
+ // --- Vision + Budget ---
714
838
  {
715
- id: "kimi-k2.5",
716
- name: "Kimi K2.5",
717
- tag: "long context",
839
+ id: "gemma-4-31b",
840
+ name: "Gemma 4 31B",
841
+ tag: "vision + budget",
718
842
  reasoning: false,
719
- vision: false,
720
- input: ["text"],
721
- cost: { input: 0.675, output: 3.78, cacheRead: 0, cacheWrite: 0 },
722
- contextWindow: 262144,
723
- maxTokens: 16384,
724
- modes: ["long"]
843
+ vision: true,
844
+ input: ["text", "image"],
845
+ cost: { input: 0.189, output: 0.54, cacheRead: 0.019, cacheWrite: 0 },
846
+ contextWindow: 128e3,
847
+ maxTokens: 8192,
848
+ modes: ["vision"]
725
849
  }
726
850
  ];
727
851
  var MODEL_BY_ID = new Map(KYMA_MODELS.map((m) => [m.id, m]));
@@ -781,6 +905,10 @@ var kymaRuntimeFactory = (pi) => {
781
905
  let turnCount = 0;
782
906
  let wasLoggedIn = !!getKymaApiKey();
783
907
  let postLoginShown = false;
908
+ let headerEmail = getKymaEmail();
909
+ let headerBalance = "";
910
+ let headerLoggedIn = wasLoggedIn;
911
+ let refreshHeader = null;
784
912
  pi.on("session_start", async (_event, ctx) => {
785
913
  sessionCost = 0;
786
914
  sessionTokens = 0;
@@ -788,82 +916,39 @@ var kymaRuntimeFactory = (pi) => {
788
916
  if (!ctx.hasUI) return;
789
917
  ctx.ui.setHideThinkingBlock?.(false);
790
918
  ctx.ui.setHiddenThinkingLabel?.("Thinking... (Ctrl+T to expand)");
791
- const email = getKymaEmail();
919
+ headerEmail = getKymaEmail();
792
920
  const apiKey = getKymaApiKey();
793
- const loggedIn = !!apiKey;
794
- let balanceStr = "";
795
- if (loggedIn && apiKey) {
921
+ headerLoggedIn = !!apiKey;
922
+ if (headerLoggedIn && apiKey) {
796
923
  try {
797
924
  const b = await kymaApi("/v1/credits/balance", apiKey);
798
- balanceStr = `$${b.balance.toFixed(2)}`;
925
+ headerBalance = `$${b.balance.toFixed(2)}`;
799
926
  } catch {
800
927
  }
801
928
  }
802
- const repoName = ctx.cwd.replace(/^.*\//, "");
803
- const modelId = ctx.model?.id || "qwen-3-32b";
804
- ctx.ui.setHeader((_tui, theme) => ({
805
- render(width) {
806
- const strip = (s) => s.replace(/\x1b\[[0-9;]*m/g, "");
807
- const truncate = (s, maxW2) => {
808
- let visible = 0;
809
- let i = 0;
810
- while (i < s.length && visible < maxW2) {
811
- if (s[i] === "\x1B") {
812
- const end = s.indexOf("m", i);
813
- if (end !== -1) {
814
- i = end + 1;
815
- continue;
816
- }
817
- }
818
- visible++;
819
- i++;
820
- }
821
- return i < s.length ? s.slice(0, i) : s;
822
- };
823
- const maxW = Math.max(width, 30);
824
- const logo = theme.bold(theme.fg("accent", ` \u03A8 kyma`)) + theme.fg("dim", ` v${VERSION}`);
825
- const url = ` https://kymaapi.com`;
826
- const accountStr = loggedIn ? `${email}${balanceStr ? ` \xB7 ${balanceStr}` : ""}` : "not connected";
827
- const dirLine = `~/${repoName}`;
828
- const connectLine = loggedIn ? null : `${theme.bold("/login")} to sign in`;
829
- const contentLines = [accountStr, dirLine];
830
- if (connectLine) contentLines.push(connectLine);
831
- const visibleWidths = contentLines.map((l) => strip(l).length);
832
- const contentMax = Math.max(...visibleWidths);
833
- const innerW = Math.min(maxW - 4, Math.max(contentMax + 4, 24));
834
- const boxTop = theme.fg("dim", ` \u256D${"\u2500".repeat(innerW)}\u256E`);
835
- const boxBot = theme.fg("dim", ` \u2570${"\u2500".repeat(innerW)}\u256F`);
836
- const boxRow = (s) => {
837
- const visLen = strip(s).length;
838
- const pad = Math.max(0, innerW - visLen - 4);
839
- const row = theme.fg("dim", " \u2502") + ` ${s}${" ".repeat(pad)} ` + theme.fg("dim", "\u2502");
840
- return truncate(row, maxW);
841
- };
842
- return [truncate(logo, maxW), truncate(url, maxW), boxTop, ...contentLines.map(boxRow), boxBot];
843
- },
844
- invalidate() {
845
- }
846
- }));
929
+ const setCompactHeader = (uiCtx) => {
930
+ const modelId = uiCtx.model?.id || ctx.model?.id || "qwen-3.6-plus";
931
+ uiCtx.ui.setHeader((_tui, theme) => ({
932
+ render(_width) {
933
+ const status = headerLoggedIn ? `${headerEmail || "connected"}${headerBalance ? ` \xB7 ${headerBalance}` : ""}` : "not connected";
934
+ const line1 = theme.bold(theme.fg("accent", " \u03A8 Kyma")) + theme.fg("dim", ` v${VERSION}`) + theme.fg("dim", " \xB7 ") + `${modelId}` + theme.fg("dim", " \xB7 ") + (headerLoggedIn ? status : theme.fg("dim", status));
935
+ const hints = headerLoggedIn ? "/models to switch \xB7 /balance \xB7 /help" : "/connect to sign in \xB7 /models to switch \xB7 /help";
936
+ const line2 = theme.fg("dim", ` ${hints}`);
937
+ return [line1, line2, ""];
938
+ },
939
+ invalidate() {
940
+ }
941
+ }));
942
+ };
943
+ refreshHeader = setCompactHeader;
944
+ setCompactHeader(ctx);
847
945
  ctx.ui.setTitle("kyma");
848
- const isOnboarded = existsSync3(KYMA_ONBOARDED_PATH);
849
- if (!loggedIn && !isOnboarded) {
850
- try {
851
- writeFileSync3(KYMA_ONBOARDED_PATH, (/* @__PURE__ */ new Date()).toISOString(), { mode: 384 });
852
- } catch {
853
- }
854
- } else if (!loggedIn) {
855
- } else if (!isOnboarded) {
856
- try {
857
- writeFileSync3(KYMA_ONBOARDED_PATH, (/* @__PURE__ */ new Date()).toISOString(), { mode: 384 });
858
- } catch {
859
- }
860
- }
861
946
  const kymaConfigPath = join5(ctx.cwd, "KYMA.md");
862
947
  if (existsSync3(kymaConfigPath)) {
863
948
  try {
864
949
  const raw = readFileSync4(kymaConfigPath, "utf-8");
865
950
  const config = parseKymaConfig(raw);
866
- if (config.model && (loggedIn || getKymaApiKey())) {
951
+ if (config.model && (headerLoggedIn || getKymaApiKey())) {
867
952
  const entry = MODEL_BY_ID.get(config.model);
868
953
  if (entry) {
869
954
  await pi.setModel(toRuntimeModel(entry, `${KYMA_BASE_URL}/v1`));
@@ -876,14 +961,6 @@ var kymaRuntimeFactory = (pi) => {
876
961
  } catch {
877
962
  }
878
963
  }
879
- const freshLogin = !!process.env.KYMA_FRESH_LOGIN;
880
- delete process.env.KYMA_FRESH_LOGIN;
881
- if (loggedIn && isOnboarded && !freshLogin) {
882
- const modelId2 = ctx.model?.id || "qwen-3-32b";
883
- ctx.ui.setWidget?.("kyma-hint", [
884
- ` ${modelId2} \xB7 /models to switch \xB7 /help for commands`
885
- ], { placement: "aboveEditor" });
886
- }
887
964
  });
888
965
  pi.on("session_shutdown", async (_event, ctx) => {
889
966
  if (!ctx.hasUI || turnCount === 0) return;
@@ -914,25 +991,12 @@ var kymaRuntimeFactory = (pi) => {
914
991
  wasLoggedIn = true;
915
992
  postLoginShown = true;
916
993
  const postKey = getKymaApiKey();
917
- const postEmail = getKymaEmail();
994
+ const postEmail = getKymaEmail() || "connected";
918
995
  try {
919
996
  const bal = await kymaApi("/v1/credits/balance", postKey);
920
- ctx.ui.notify(`Authorized \xB7 ${postEmail} \xB7 $${bal.balance.toFixed(2)}`, "info");
997
+ ctx.ui.notify(`Authorized \xB7 ${postEmail} \xB7 $${bal.balance.toFixed(2)} \u2014 /models to switch`, "info");
921
998
  } catch {
922
- ctx.ui.notify(`Authorized \xB7 ${postEmail}`, "info");
923
- }
924
- const modeOptions = [...MODE_TO_MODEL.entries()].map(
925
- ([mode, m]) => `${mode.padEnd(12)} ${m.name.padEnd(20)} ${m.tag}`
926
- );
927
- modeOptions.push("Keep default (fast)");
928
- const modeChoice = await ctx.ui.select("Choose a mode for this session", modeOptions);
929
- if (modeChoice && !modeChoice.startsWith("Keep")) {
930
- const modeName = modeChoice.split(/\s+/)[0];
931
- const modeModel = MODE_TO_MODEL.get(modeName);
932
- if (modeModel) {
933
- const ok = await pi.setModel(toRuntimeModel(modeModel, `${KYMA_BASE_URL}/v1`));
934
- if (ok) ctx.ui.notify(`Mode: ${modeName} \u2192 ${modeModel.name}`, "info");
935
- }
999
+ ctx.ui.notify(`Authorized \xB7 ${postEmail} \u2014 /models to switch`, "info");
936
1000
  }
937
1001
  }
938
1002
  });
@@ -960,67 +1024,39 @@ var kymaRuntimeFactory = (pi) => {
960
1024
  return;
961
1025
  }
962
1026
  }
963
- const options = filtered.map((m) => {
964
- const star = m.id === currentId ? "* " : " ";
965
- const name = m.name.padEnd(20);
966
- const tag = m.tag.padEnd(20);
967
- const price = `$${m.cost.input.toFixed(2)}/$${m.cost.output.toFixed(2)}`;
968
- const badges = [];
969
- if (m.vision) badges.push("[img]");
970
- if (m.reasoning) badges.push("[think]");
971
- const badgeStr = badges.length ? " " + badges.join(" ") : "";
972
- return `${star}${name}${tag}${price}${badgeStr}`;
973
- });
974
- const selected = await ctx.ui.select("Models available in your Kyma account", options);
1027
+ const options = filtered.map((m) => formatModelLine(m, currentId));
1028
+ const selected = await ctx.ui.select(
1029
+ "/models coding \xB7 /models vision \xB7 /models cheap",
1030
+ options
1031
+ );
975
1032
  if (!selected) return;
976
1033
  const idx = options.indexOf(selected);
977
- const chosen = filtered[idx];
978
- if (!chosen || chosen.id === currentId) return;
979
- const ok = await pi.setModel(toRuntimeModel(chosen, `${KYMA_BASE_URL}/v1`));
1034
+ return switchTo(filtered[idx], currentId, ctx);
1035
+ }
1036
+ function formatModelLine(m, currentId) {
1037
+ const star = m.id === currentId ? "* " : " ";
1038
+ const name = m.name.padEnd(20);
1039
+ const tag = m.tag.padEnd(22);
1040
+ const price = `$${m.cost.input.toFixed(2)}/$${m.cost.output.toFixed(2)}`;
1041
+ const badges = [];
1042
+ if (m.vision) badges.push("[img]");
1043
+ if (m.reasoning) badges.push("[think]");
1044
+ const badgeStr = badges.length ? " " + badges.join(" ") : "";
1045
+ return `${star}${name}${tag}${price}${badgeStr}`;
1046
+ }
1047
+ async function switchTo(model, currentId, ctx) {
1048
+ if (model.id === currentId) return;
1049
+ const ok = await pi.setModel(toRuntimeModel(model, `${KYMA_BASE_URL}/v1`));
980
1050
  if (ok) {
981
- ctx.ui.notify(`Switched to ${chosen.name} \u2014 ${chosen.tag}`, "info");
1051
+ ctx.ui.notify(`Switched to ${model.name} \u2014 ${model.tag}`, "info");
982
1052
  } else {
983
- ctx.ui.notify("Failed to switch model. Run /login to sign in.", "error");
1053
+ ctx.ui.notify("Failed to switch model. Run /connect to sign in.", "error");
984
1054
  }
985
1055
  }
986
1056
  pi.registerCommand("models", {
987
1057
  description: "Browse and switch Kyma models",
988
1058
  handler: modelsHandler
989
1059
  });
990
- const MODE_LIST = [...MODE_TO_MODEL.entries()].map(([mode, m]) => ({
991
- mode,
992
- model: m,
993
- label: `${mode.padEnd(12)} ${m.id.padEnd(20)} ${m.tag}`
994
- }));
995
- pi.registerCommand("mode", {
996
- description: "Switch model by task type",
997
- async handler(args, ctx) {
998
- let entry;
999
- if (args.trim()) {
1000
- const m = MODE_TO_MODEL.get(args.trim());
1001
- if (!m) {
1002
- ctx.ui.notify(`Unknown mode "${args.trim()}". Available: ${[...MODE_TO_MODEL.keys()].join(", ")}`, "error");
1003
- return;
1004
- }
1005
- entry = { mode: args.trim(), model: m };
1006
- } else {
1007
- const selected = await ctx.ui.select(
1008
- "Choose mode",
1009
- MODE_LIST.map((p) => p.label)
1010
- );
1011
- if (!selected) return;
1012
- const idx = MODE_LIST.findIndex((p) => p.label === selected);
1013
- entry = MODE_LIST[idx];
1014
- }
1015
- if (!entry) return;
1016
- const ok = await pi.setModel(toRuntimeModel(entry.model, `${KYMA_BASE_URL}/v1`));
1017
- if (ok) {
1018
- ctx.ui.notify(`Mode: ${entry.mode} \u2192 ${entry.model.name}`, "info");
1019
- } else {
1020
- ctx.ui.notify("Failed to switch model. Run /login to sign in.", "error");
1021
- }
1022
- }
1023
- });
1024
1060
  pi.registerCommand("status", {
1025
1061
  description: "Account, credits, and diagnostics",
1026
1062
  async handler(_args, ctx) {
@@ -1028,7 +1064,7 @@ var kymaRuntimeFactory = (pi) => {
1028
1064
  const currentModel = ctx.model;
1029
1065
  const lines = ["Kyma Status", DIV, ""];
1030
1066
  if (!apiKey) {
1031
- lines.push(" Not connected. Run /login to sign in.");
1067
+ lines.push(" Not connected. Run /connect to sign in.");
1032
1068
  ctx.ui.notify(lines.join("\n"), "info");
1033
1069
  return;
1034
1070
  }
@@ -1079,7 +1115,7 @@ var kymaRuntimeFactory = (pi) => {
1079
1115
  async handler(_args, ctx) {
1080
1116
  const apiKey = getKymaApiKey();
1081
1117
  if (!apiKey) {
1082
- ctx.ui.notify("Not connected. Run /login to sign in.", "error");
1118
+ ctx.ui.notify("Not connected. Run /connect to sign in.", "error");
1083
1119
  return;
1084
1120
  }
1085
1121
  try {
@@ -1147,7 +1183,7 @@ var kymaRuntimeFactory = (pi) => {
1147
1183
  async handler(_args, ctx) {
1148
1184
  const apiKey = getKymaApiKey();
1149
1185
  if (!apiKey) {
1150
- ctx.ui.notify("Not connected. Run /login first.", "error");
1186
+ ctx.ui.notify("Not connected. Run /connect first.", "error");
1151
1187
  return;
1152
1188
  }
1153
1189
  try {
@@ -1203,9 +1239,29 @@ var kymaRuntimeFactory = (pi) => {
1203
1239
  ctx.ui.notify("Opening feedback page...", "info");
1204
1240
  }
1205
1241
  });
1206
- pi.registerCommand("login", {
1242
+ pi.registerCommand("connect", {
1207
1243
  description: "Sign in to your Kyma account",
1208
- async handler(_args, ctx) {
1244
+ async handler(args, ctx) {
1245
+ const trimmed = args.trim();
1246
+ if (trimmed && (trimmed.startsWith("sk-") || trimmed.startsWith("ky-") || trimmed.startsWith("kyma-"))) {
1247
+ ctx.ui.notify("Validating API key...", "info");
1248
+ try {
1249
+ const credentials = await validateApiKey(trimmed);
1250
+ saveKymaCredentials(credentials);
1251
+ wasLoggedIn = true;
1252
+ postLoginShown = true;
1253
+ headerLoggedIn = true;
1254
+ headerEmail = credentials.email;
1255
+ headerBalance = credentials.balance != null ? `$${credentials.balance.toFixed(2)}` : "";
1256
+ if (refreshHeader) refreshHeader(ctx);
1257
+ const bal = credentials.balance != null ? ` \xB7 $${credentials.balance.toFixed(2)}` : "";
1258
+ ctx.ui.notify(`\u2713 Connected as ${credentials.email}${bal}
1259
+ /models to switch \xB7 /balance to check credits`, "info");
1260
+ } catch (err) {
1261
+ ctx.ui.notify(`Invalid API key: ${err.message}`, "error");
1262
+ }
1263
+ return;
1264
+ }
1209
1265
  if (getKymaApiKey()) {
1210
1266
  const email = getKymaEmail();
1211
1267
  const reconnect = await ctx.ui.confirm(
@@ -1214,25 +1270,50 @@ var kymaRuntimeFactory = (pi) => {
1214
1270
  );
1215
1271
  if (!reconnect) return;
1216
1272
  }
1217
- ctx.ui.notify("Opening browser to sign in...", "info");
1273
+ const SPINNER = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
1274
+ let spinnerFrame = 0;
1275
+ let spinnerInterval = null;
1218
1276
  try {
1219
1277
  const credentials = await loginKyma({
1220
1278
  onAuth({ url, instructions }) {
1221
- ctx.ui.notify(`${instructions}
1222
- URL: ${url}`, "info");
1279
+ const urlObj = new URL(url);
1280
+ const code = urlObj.searchParams.get("code") || "";
1281
+ ctx.ui.notify(
1282
+ `${instructions}
1283
+ ${url}
1284
+
1285
+ Can't open browser? Run: /connect YOUR_API_KEY`,
1286
+ "info"
1287
+ );
1223
1288
  openBrowser(url);
1289
+ spinnerInterval = setInterval(() => {
1290
+ const frame = SPINNER[spinnerFrame % SPINNER.length];
1291
+ ctx.ui.setWidget?.("connect-spinner", [
1292
+ ` ${frame} Waiting for authorization...`
1293
+ ], { placement: "aboveEditor" });
1294
+ spinnerFrame++;
1295
+ }, 120);
1224
1296
  },
1225
- onProgress(msg) {
1226
- if (msg) ctx.ui.notify(msg, "info");
1297
+ onProgress() {
1227
1298
  }
1228
1299
  });
1300
+ if (spinnerInterval) clearInterval(spinnerInterval);
1301
+ ctx.ui.setWidget?.("connect-spinner", void 0);
1229
1302
  saveKymaCredentials(credentials);
1230
1303
  wasLoggedIn = true;
1231
1304
  postLoginShown = true;
1232
- const bal = credentials.balance != null ? ` $${credentials.balance.toFixed(2)}` : "";
1233
- ctx.ui.notify(`Authorized \xB7 ${credentials.email}${bal}`, "info");
1305
+ headerLoggedIn = true;
1306
+ headerEmail = credentials.email;
1307
+ headerBalance = credentials.balance != null ? `$${credentials.balance.toFixed(2)}` : "";
1308
+ if (refreshHeader) refreshHeader(ctx);
1309
+ const bal = credentials.balance != null ? ` \xB7 $${credentials.balance.toFixed(2)}` : "";
1310
+ ctx.ui.notify(`\u2713 Connected as ${credentials.email}${bal}
1311
+ /models to switch \xB7 /balance to check credits`, "info");
1234
1312
  } catch (err) {
1235
- ctx.ui.notify(`Login failed: ${err.message}`, "error");
1313
+ if (spinnerInterval) clearInterval(spinnerInterval);
1314
+ ctx.ui.setWidget?.("connect-spinner", void 0);
1315
+ ctx.ui.notify(`Login failed: ${err.message}
1316
+ Try again with /connect or /connect YOUR_API_KEY`, "error");
1236
1317
  }
1237
1318
  }
1238
1319
  });
@@ -1243,10 +1324,10 @@ URL: ${url}`, "info");
1243
1324
  "Kyma Commands",
1244
1325
  DIV,
1245
1326
  "",
1246
- " /login Sign in to Kyma",
1247
- " /logout Sign out",
1327
+ " /connect Sign in to Kyma",
1328
+ " /disconnect Sign out",
1248
1329
  " /models Browse and switch models",
1249
- " /mode Switch model by task type",
1330
+ " /models coding \xB7 /models vision \xB7 /models cheap",
1250
1331
  " /status Account, credits, diagnostics",
1251
1332
  " /balance Credits and rate limits",
1252
1333
  " /usage Session cost and tokens",
@@ -1275,12 +1356,12 @@ URL: ${url}`, "info");
1275
1356
  process.exit(0);
1276
1357
  }
1277
1358
  });
1278
- pi.registerCommand("logout", {
1359
+ pi.registerCommand("disconnect", {
1279
1360
  description: "Sign out of Kyma",
1280
1361
  async handler(_args, ctx) {
1281
1362
  const apiKey = getKymaApiKey();
1282
1363
  if (!apiKey) {
1283
- ctx.ui.notify("Not signed in. Run /login to sign in.", "info");
1364
+ ctx.ui.notify("Not signed in. Run /connect to sign in.", "info");
1284
1365
  return;
1285
1366
  }
1286
1367
  if (process.env.KYMA_API_KEY) {
@@ -1293,7 +1374,7 @@ URL: ${url}`, "info");
1293
1374
  clearKymaCredentials();
1294
1375
  wasLoggedIn = false;
1295
1376
  postLoginShown = false;
1296
- ctx.ui.notify("Signed out. Run /login to sign in again.", "info");
1377
+ ctx.ui.notify("Signed out. Run /connect to sign in again.", "info");
1297
1378
  }
1298
1379
  });
1299
1380
  pi.registerCommand("clear", {
@@ -1306,7 +1387,7 @@ URL: ${url}`, "info");
1306
1387
 
1307
1388
  // src/sdk/main.ts
1308
1389
  var PKG_DIR2 = process.env.PI_PACKAGE_DIR || dirname4(dirname4(dirname4(fileURLToPath4(import.meta.url))));
1309
- var VERSION2 = (() => {
1390
+ var VERSION3 = (() => {
1310
1391
  try {
1311
1392
  return JSON.parse(readFileSync5(join6(PKG_DIR2, "package.json"), "utf-8")).version || "0.1.0";
1312
1393
  } catch {
@@ -1314,20 +1395,21 @@ var VERSION2 = (() => {
1314
1395
  }
1315
1396
  })();
1316
1397
  function printHelp() {
1317
- console.log(`kyma v${VERSION2} \u2014 one account, many models \xB7 kymaapi.com
1398
+ console.log(`kyma v${VERSION3} \u2014 one account, many models \xB7 kymaapi.com
1318
1399
 
1319
1400
  Usage:
1320
1401
  kyma [messages...] Interactive coding agent
1321
1402
  kyma "prompt" Start with a message
1322
1403
  kyma -c Continue previous session
1323
1404
 
1324
- Models:
1325
- qwen-3-32b Fast coding (default)
1405
+ Models (9 curated for coding):
1406
+ qwen-3.6-plus Flagship (default)
1326
1407
  qwen-3-coder Code specialist
1327
- qwen-3.6-plus Flagship reasoning
1328
- gemma-4-31b Vision + cheap
1329
- gemini-2.5-flash Vision + 1M context
1408
+ deepseek-v3 Reasoning + code
1409
+ minimax-m2.5 Agentic coding
1410
+ kimi-k2.5 Agentic + long context
1330
1411
  deepseek-r1 Deep reasoning
1412
+ gpt-oss-120b Budget + fast
1331
1413
  ... run /models inside kyma for full list
1332
1414
 
1333
1415
  Commands (inside kyma):
@@ -1402,12 +1484,12 @@ async function checkAndUpdate() {
1402
1484
  if (!res.ok) return false;
1403
1485
  const data = await res.json();
1404
1486
  const latest = data.version;
1405
- if (!latest || latest === VERSION2) return false;
1487
+ if (!latest || latest === VERSION3) return false;
1406
1488
  const parse = (v) => v.split(".").map(Number);
1407
- const [cM, cm, cp] = parse(VERSION2);
1489
+ const [cM, cm, cp] = parse(VERSION3);
1408
1490
  const [lM, lm, lp] = parse(latest);
1409
1491
  if (lM < cM || lM === cM && lm < cm || lM === cM && lm === cm && lp <= cp) return false;
1410
- console.log(` ${term.dim(`Updating kyma v${VERSION2} \u2192 v${latest}...`)}`);
1492
+ console.log(` ${term.dim(`Updating kyma v${VERSION3} \u2192 v${latest}...`)}`);
1411
1493
  execSync("npm install -g @kyma-api/agent@latest", { stdio: "ignore", timeout: 6e4 });
1412
1494
  console.log(` ${term.dim(`Updated to v${latest}. Restarting...`)}`);
1413
1495
  return true;
@@ -1422,7 +1504,7 @@ async function main(argv) {
1422
1504
  process.exit(0);
1423
1505
  }
1424
1506
  if (parsed.version) {
1425
- console.log(`kyma v${VERSION2}`);
1507
+ console.log(`kyma v${VERSION3}`);
1426
1508
  process.exit(0);
1427
1509
  }
1428
1510
  if (parsed.verbose || process.env.KYMA_DEBUG === "1") {
@@ -1441,7 +1523,10 @@ async function main(argv) {
1441
1523
  }
1442
1524
  }
1443
1525
  ensureAgentDir();
1444
- await runOnboarding();
1526
+ const wasLoggedIn = await runOnboarding();
1527
+ if (wasLoggedIn && process.stdout.isTTY) {
1528
+ process.stdout.write("\x1B[2J\x1B[H");
1529
+ }
1445
1530
  if (process.env.KYMA_VERBOSE) {
1446
1531
  const missing = ["fd", "rg"].filter((cmd) => {
1447
1532
  try {
@@ -1461,9 +1546,6 @@ async function main(argv) {
1461
1546
  initialMessage: parsed.initialMessage,
1462
1547
  continueSession: parsed.continueSession
1463
1548
  });
1464
- if (process.stdout.isTTY) {
1465
- process.stdout.write("\x1B[2J\x1B[H");
1466
- }
1467
1549
  const interactiveMode = new KymaInteractiveMode(runtime, interactiveOptions);
1468
1550
  await interactiveMode.run();
1469
1551
  }