@kyma-api/agent 0.1.2 → 0.1.3

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
@@ -123,7 +123,7 @@ var KYMA_AGENT_DIR = join(KYMA_DIR, "agent");
123
123
  var KYMA_AUTH_PATH = join(KYMA_AGENT_DIR, "auth.json");
124
124
  var KYMA_SETTINGS_PATH = join(KYMA_AGENT_DIR, "settings.json");
125
125
  var KYMA_ONBOARDED_PATH = join(KYMA_AGENT_DIR, ".onboarded");
126
- var KYMA_BASE_URL = "https://kymaapi.com";
126
+ var KYMA_BASE_URL = process.env.KYMA_BASE_URL || "https://kymaapi.com";
127
127
 
128
128
  // src/sdk/auth.ts
129
129
  import { readFileSync as readFileSync2, writeFileSync } from "fs";
@@ -146,7 +146,7 @@ var VERSION = (() => {
146
146
  function normalizeKymaError(status, body) {
147
147
  switch (status) {
148
148
  case 401:
149
- return { code: 401, severity: "error", message: "Session expired.", action: "Run /connect to reconnect." };
149
+ return { code: 401, severity: "error", message: "Session expired.", action: "Run /login to reconnect." };
150
150
  case 402:
151
151
  return { code: 402, severity: "error", message: "Insufficient Kyma credits.", action: "Run /billing to top up." };
152
152
  case 429:
@@ -374,7 +374,8 @@ function ensureAgentDir() {
374
374
  defaultModel: "qwen-3-32b",
375
375
  quietStartup: true,
376
376
  theme: "kyma-dark",
377
- thinkingLevel: "off"
377
+ hideThinkingBlock: false,
378
+ defaultThinkingLevel: "low"
378
379
  }, null, 2), { mode: 384 });
379
380
  } else {
380
381
  try {
@@ -396,8 +397,12 @@ function ensureAgentDir() {
396
397
  settings.theme = "kyma-dark";
397
398
  changed = true;
398
399
  }
399
- if (settings.thinkingLevel !== "off") {
400
- settings.thinkingLevel = "off";
400
+ if (settings.defaultThinkingLevel !== "low") {
401
+ settings.defaultThinkingLevel = "low";
402
+ changed = true;
403
+ }
404
+ if (settings.hideThinkingBlock !== false) {
405
+ settings.hideThinkingBlock = false;
401
406
  changed = true;
402
407
  }
403
408
  if (changed) {
@@ -434,7 +439,7 @@ async function runOnboarding() {
434
439
  console.log("");
435
440
  const answer = await ask(" Connect now? (Y/n) ");
436
441
  if (answer.toLowerCase() === "n" || answer.toLowerCase() === "no") {
437
- console.log(` ${term.dim("Skipped.")} Use ${term.gold("/connect")} anytime.`);
442
+ console.log(` ${term.dim("Skipped.")} Use ${term.gold("/login")} anytime.`);
438
443
  console.log("");
439
444
  markOnboarded();
440
445
  return false;
@@ -463,7 +468,7 @@ async function runOnboarding() {
463
468
  } catch (err) {
464
469
  console.log("");
465
470
  console.log(` ${term.dim("Login failed:")} ${err.message}`);
466
- console.log(` ${term.dim("Try again with")} ${term.gold("/connect")}`);
471
+ console.log(` ${term.dim("Try again with")} ${term.gold("/login")}`);
467
472
  console.log("");
468
473
  }
469
474
  markOnboarded();
@@ -507,7 +512,12 @@ async function createKymaSession(options) {
507
512
  extensionFactories,
508
513
  additionalExtensionPaths: [],
509
514
  // no file-based extensions
510
- additionalThemePaths: [KYMA_THEMES_DIR]
515
+ additionalThemePaths: [KYMA_THEMES_DIR],
516
+ appendSystemPrompt: [
517
+ "IMPORTANT: You are running inside Kyma, NOT pi. Never mention pi, Pi SDK, or pi documentation.",
518
+ "If the user asks about the tool they are using, say 'Kyma' (kymaapi.com).",
519
+ "Never reveal internal file paths or node_modules paths."
520
+ ].join("\n")
511
521
  }
512
522
  });
513
523
  const result = await createAgentSessionFromServices({
@@ -755,6 +765,7 @@ var kymaProviderFactory = (pi) => {
755
765
  apiKey: "KYMA_API_KEY",
756
766
  api: "openai-completions",
757
767
  authHeader: true,
768
+ headers: { "X-Kyma-Think": "show" },
758
769
  oauth: {
759
770
  name: "Kyma",
760
771
  login: loginKyma,
@@ -774,8 +785,9 @@ var kymaRuntimeFactory = (pi) => {
774
785
  sessionCost = 0;
775
786
  sessionTokens = 0;
776
787
  turnCount = 0;
777
- pi.setThinkingLevel?.("off");
778
788
  if (!ctx.hasUI) return;
789
+ ctx.ui.setHideThinkingBlock?.(false);
790
+ ctx.ui.setHiddenThinkingLabel?.("Thinking... (Ctrl+T to expand)");
779
791
  const email = getKymaEmail();
780
792
  const apiKey = getKymaApiKey();
781
793
  const loggedIn = !!apiKey;
@@ -787,12 +799,47 @@ var kymaRuntimeFactory = (pi) => {
787
799
  } catch {
788
800
  }
789
801
  }
802
+ const repoName = ctx.cwd.replace(/^.*\//, "");
803
+ const modelId = ctx.model?.id || "qwen-3-32b";
790
804
  ctx.ui.setHeader((_tui, theme) => ({
791
- render(_width) {
792
- const logo = theme.bold(theme.fg("accent", " kyma"));
793
- const tagline = theme.fg("dim", " one account \xB7 many models \xB7 kymaapi.com");
794
- const accountLine = loggedIn ? theme.fg("dim", ` ${email}${balanceStr ? ` \xB7 ${balanceStr}` : ""} \xB7 /models`) : theme.fg("dim", " not connected \xB7 /connect");
795
- return [logo, tagline, accountLine];
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];
796
843
  },
797
844
  invalidate() {
798
845
  }
@@ -832,9 +879,9 @@ var kymaRuntimeFactory = (pi) => {
832
879
  const freshLogin = !!process.env.KYMA_FRESH_LOGIN;
833
880
  delete process.env.KYMA_FRESH_LOGIN;
834
881
  if (loggedIn && isOnboarded && !freshLogin) {
835
- const modelId = ctx.model?.id || "qwen-3-32b";
882
+ const modelId2 = ctx.model?.id || "qwen-3-32b";
836
883
  ctx.ui.setWidget?.("kyma-hint", [
837
- ` ${modelId} \xB7 /models to switch \xB7 /help for commands`
884
+ ` ${modelId2} \xB7 /models to switch \xB7 /help for commands`
838
885
  ], { placement: "aboveEditor" });
839
886
  }
840
887
  });
@@ -860,9 +907,6 @@ var kymaRuntimeFactory = (pi) => {
860
907
  if (turnCount === 1 && ctx.hasUI) {
861
908
  ctx.ui.setWidget?.("kyma-hint", void 0);
862
909
  }
863
- if (ctx.hasUI) {
864
- ctx.ui.setStatus("kyma-cost", `$${sessionCost.toFixed(4)} \xB7 ${formatTokens(sessionTokens)} tokens`);
865
- }
866
910
  }
867
911
  if (!ctx.hasUI || postLoginShown) return;
868
912
  const nowLoggedIn = !!getKymaApiKey();
@@ -936,7 +980,7 @@ var kymaRuntimeFactory = (pi) => {
936
980
  if (ok) {
937
981
  ctx.ui.notify(`Switched to ${chosen.name} \u2014 ${chosen.tag}`, "info");
938
982
  } else {
939
- ctx.ui.notify("Failed to switch model. Run /connect to sign in.", "error");
983
+ ctx.ui.notify("Failed to switch model. Run /login to sign in.", "error");
940
984
  }
941
985
  }
942
986
  pi.registerCommand("models", {
@@ -973,7 +1017,7 @@ var kymaRuntimeFactory = (pi) => {
973
1017
  if (ok) {
974
1018
  ctx.ui.notify(`Mode: ${entry.mode} \u2192 ${entry.model.name}`, "info");
975
1019
  } else {
976
- ctx.ui.notify("Failed to switch model. Run /connect to sign in.", "error");
1020
+ ctx.ui.notify("Failed to switch model. Run /login to sign in.", "error");
977
1021
  }
978
1022
  }
979
1023
  });
@@ -984,7 +1028,7 @@ var kymaRuntimeFactory = (pi) => {
984
1028
  const currentModel = ctx.model;
985
1029
  const lines = ["Kyma Status", DIV, ""];
986
1030
  if (!apiKey) {
987
- lines.push(" Not connected. Run /connect to sign in.");
1031
+ lines.push(" Not connected. Run /login to sign in.");
988
1032
  ctx.ui.notify(lines.join("\n"), "info");
989
1033
  return;
990
1034
  }
@@ -1035,7 +1079,7 @@ var kymaRuntimeFactory = (pi) => {
1035
1079
  async handler(_args, ctx) {
1036
1080
  const apiKey = getKymaApiKey();
1037
1081
  if (!apiKey) {
1038
- ctx.ui.notify("Not connected. Run /connect to sign in.", "error");
1082
+ ctx.ui.notify("Not connected. Run /login to sign in.", "error");
1039
1083
  return;
1040
1084
  }
1041
1085
  try {
@@ -1103,7 +1147,7 @@ var kymaRuntimeFactory = (pi) => {
1103
1147
  async handler(_args, ctx) {
1104
1148
  const apiKey = getKymaApiKey();
1105
1149
  if (!apiKey) {
1106
- ctx.ui.notify("Not connected. Run /connect first.", "error");
1150
+ ctx.ui.notify("Not connected. Run /login first.", "error");
1107
1151
  return;
1108
1152
  }
1109
1153
  try {
@@ -1159,8 +1203,8 @@ var kymaRuntimeFactory = (pi) => {
1159
1203
  ctx.ui.notify("Opening feedback page...", "info");
1160
1204
  }
1161
1205
  });
1162
- pi.registerCommand("connect", {
1163
- description: "Connect your Kyma account",
1206
+ pi.registerCommand("login", {
1207
+ description: "Sign in to your Kyma account",
1164
1208
  async handler(_args, ctx) {
1165
1209
  if (getKymaApiKey()) {
1166
1210
  const email = getKymaEmail();
@@ -1199,17 +1243,19 @@ URL: ${url}`, "info");
1199
1243
  "Kyma Commands",
1200
1244
  DIV,
1201
1245
  "",
1202
- " /connect Connect your Kyma account",
1203
- " /disconnect Sign out",
1246
+ " /login Sign in to Kyma",
1247
+ " /logout Sign out",
1204
1248
  " /models Browse and switch models",
1205
1249
  " /mode Switch model by task type",
1206
- " /status Account, credits, and diagnostics",
1250
+ " /status Account, credits, diagnostics",
1207
1251
  " /balance Credits and rate limits",
1208
1252
  " /usage Session cost and tokens",
1209
1253
  " /upgrade View tiers and upgrade",
1210
1254
  " /dashboard Open dashboard in browser",
1211
1255
  " /billing Open billing page",
1212
1256
  " /feedback Report issues or give feedback",
1257
+ " /clear Clear the screen",
1258
+ " /exit Exit kyma",
1213
1259
  " /help Show this help",
1214
1260
  "",
1215
1261
  "Keyboard",
@@ -1223,25 +1269,37 @@ URL: ${url}`, "info");
1223
1269
  ].join("\n"), "info");
1224
1270
  }
1225
1271
  });
1226
- pi.registerCommand("disconnect", {
1272
+ pi.registerCommand("exit", {
1273
+ description: "Exit kyma",
1274
+ async handler(_args, _ctx) {
1275
+ process.exit(0);
1276
+ }
1277
+ });
1278
+ pi.registerCommand("logout", {
1227
1279
  description: "Sign out of Kyma",
1228
1280
  async handler(_args, ctx) {
1229
1281
  const apiKey = getKymaApiKey();
1230
1282
  if (!apiKey) {
1231
- ctx.ui.notify("Not connected. Run /connect to sign in.", "info");
1283
+ ctx.ui.notify("Not signed in. Run /login to sign in.", "info");
1232
1284
  return;
1233
1285
  }
1234
1286
  if (process.env.KYMA_API_KEY) {
1235
- ctx.ui.notify("Cannot disconnect: using KYMA_API_KEY environment variable.", "warning");
1287
+ ctx.ui.notify("Cannot sign out: using KYMA_API_KEY environment variable.", "warning");
1236
1288
  return;
1237
1289
  }
1238
1290
  const email = getKymaEmail();
1239
- const confirm = await ctx.ui.confirm("Disconnect", `Sign out from ${email}?`);
1291
+ const confirm = await ctx.ui.confirm("Sign out", `Sign out from ${email}?`);
1240
1292
  if (!confirm) return;
1241
1293
  clearKymaCredentials();
1242
1294
  wasLoggedIn = false;
1243
1295
  postLoginShown = false;
1244
- ctx.ui.notify("Disconnected. Run /connect to sign in again.", "info");
1296
+ ctx.ui.notify("Signed out. Run /login to sign in again.", "info");
1297
+ }
1298
+ });
1299
+ pi.registerCommand("clear", {
1300
+ description: "Clear the screen",
1301
+ async handler(_args, ctx) {
1302
+ process.stdout.write("\x1B[2J\x1B[H");
1245
1303
  }
1246
1304
  });
1247
1305
  };
@@ -1336,6 +1394,27 @@ function parseArgs(argv) {
1336
1394
  }
1337
1395
  return result;
1338
1396
  }
1397
+ async function checkAndUpdate() {
1398
+ try {
1399
+ const res = await fetch("https://registry.npmjs.org/@kyma-api/agent/latest", {
1400
+ signal: AbortSignal.timeout(3e3)
1401
+ });
1402
+ if (!res.ok) return false;
1403
+ const data = await res.json();
1404
+ const latest = data.version;
1405
+ if (!latest || latest === VERSION2) return false;
1406
+ const parse = (v) => v.split(".").map(Number);
1407
+ const [cM, cm, cp] = parse(VERSION2);
1408
+ const [lM, lm, lp] = parse(latest);
1409
+ 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}...`)}`);
1411
+ execSync("npm install -g @kyma-api/agent@latest", { stdio: "ignore", timeout: 6e4 });
1412
+ console.log(` ${term.dim(`Updated to v${latest}. Restarting...`)}`);
1413
+ return true;
1414
+ } catch {
1415
+ return false;
1416
+ }
1417
+ }
1339
1418
  async function main(argv) {
1340
1419
  const parsed = parseArgs(argv);
1341
1420
  if (parsed.help) {
@@ -1349,6 +1428,18 @@ async function main(argv) {
1349
1428
  if (parsed.verbose || process.env.KYMA_DEBUG === "1") {
1350
1429
  process.env.KYMA_VERBOSE = "1";
1351
1430
  }
1431
+ if (!process.env.KYMA_SKIP_UPDATE) {
1432
+ const updated = await checkAndUpdate();
1433
+ if (updated) {
1434
+ const { spawn } = await import("child_process");
1435
+ const child = spawn("kyma", process.argv.slice(2), {
1436
+ stdio: "inherit",
1437
+ env: { ...process.env, KYMA_SKIP_UPDATE: "1" }
1438
+ });
1439
+ child.on("exit", (code) => process.exit(code ?? 0));
1440
+ return;
1441
+ }
1442
+ }
1352
1443
  ensureAgentDir();
1353
1444
  await runOnboarding();
1354
1445
  if (process.env.KYMA_VERBOSE) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kyma-api/agent",
3
- "version": "0.1.2",
3
+ "version": "0.1.3",
4
4
  "description": "Kyma coding agent — one account, many models. AI-powered coding assistant backed by Kyma API.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -5,6 +5,8 @@
5
5
  "accent": "#C9A84C",
6
6
  "accentLight": "#DDBF6F",
7
7
  "accentSoft": "#A89060",
8
+ "teal": "#7DCFCF",
9
+ "purple": "#B4A7D6",
8
10
  "green": "#00B894",
9
11
  "red": "#E17055",
10
12
  "yellow": "#FDCB6E",
@@ -30,7 +32,7 @@
30
32
  "muted": "gray",
31
33
  "dim": "dimGray",
32
34
  "text": "",
33
- "thinkingText": "darkGray",
35
+ "thinkingText": "dimGray",
34
36
 
35
37
  "selectedBg": "selectedBg",
36
38
  "userMessageBg": "userMsgBg",
@@ -42,12 +44,12 @@
42
44
  "toolSuccessBg": "toolSuccessBg",
43
45
  "toolErrorBg": "toolErrorBg",
44
46
  "toolTitle": "",
45
- "toolOutput": "gray",
47
+ "toolOutput": "#C8CCD8",
46
48
 
47
- "mdHeading": "#E8D48B",
48
- "mdLink": "accentLight",
49
+ "mdHeading": "#F0E4A8",
50
+ "mdLink": "teal",
49
51
  "mdLinkUrl": "dimGray",
50
- "mdCode": "accent",
52
+ "mdCode": "teal",
51
53
  "mdCodeBlock": "gray",
52
54
  "mdCodeBlockBorder": "dimGray",
53
55
  "mdQuote": "gray",
@@ -60,12 +62,12 @@
60
62
  "toolDiffContext": "gray",
61
63
 
62
64
  "syntaxComment": "#6A9955",
63
- "syntaxKeyword": "#D4B96A",
65
+ "syntaxKeyword": "purple",
64
66
  "syntaxFunction": "#E2C87A",
65
67
  "syntaxVariable": "#C8BFA0",
66
68
  "syntaxString": "#9BE9A8",
67
69
  "syntaxNumber": "#B5CEA8",
68
- "syntaxType": "#8DBAB2",
70
+ "syntaxType": "teal",
69
71
  "syntaxOperator": "#D4D4D4",
70
72
  "syntaxPunctuation": "#D4D4D4",
71
73
 
@@ -76,7 +78,12 @@
76
78
  "thinkingHigh": "#8B7A5F",
77
79
  "thinkingXhigh": "accentSoft",
78
80
 
79
- "bashMode": "green"
81
+ "bashMode": "green",
82
+
83
+ "modeCode": "#5B9CF5",
84
+ "modeReason": "#B4A7D6",
85
+ "modeFast": "#00B894",
86
+ "modeCreative": "#E17055"
80
87
  },
81
88
  "export": {
82
89
  "pageBg": "#13141C",