ns-omp-provider-kiro 0.3.5 → 0.3.8

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/index.js +278 -25
  2. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -2420,8 +2420,52 @@ function convertToolsToKiro(tools) {
2420
2420
  }
2421
2421
  }));
2422
2422
  }
2423
+ var KIRO_IMAGE_FORMAT_ALIASES = {
2424
+ png: "png",
2425
+ "x-png": "png",
2426
+ jpeg: "jpeg",
2427
+ jpg: "jpeg",
2428
+ pjpeg: "jpeg",
2429
+ gif: "gif",
2430
+ webp: "webp"
2431
+ };
2432
+ function toKiroImageFormat(mimeType) {
2433
+ const subtype = mimeType.trim().toLowerCase().split("/").pop()?.split(";")[0]?.trim() ?? "";
2434
+ return KIRO_IMAGE_FORMAT_ALIASES[subtype];
2435
+ }
2436
+ function toKiroImageBytes(data) {
2437
+ const trimmed = data.trim();
2438
+ const marker = "base64,";
2439
+ if (!trimmed.startsWith("data:") || !trimmed.includes(marker))
2440
+ return trimmed;
2441
+ return trimmed.slice(trimmed.indexOf(marker) + marker.length);
2442
+ }
2423
2443
  function convertImagesToKiro(images) {
2424
- return images.map((img) => ({ format: img.mimeType.split("/")[1] || "png", source: { bytes: img.data } }));
2444
+ const out = [];
2445
+ for (const img of images) {
2446
+ const format = toKiroImageFormat(img.mimeType);
2447
+ const bytes = toKiroImageBytes(img.data);
2448
+ if (!format || !bytes)
2449
+ continue;
2450
+ out.push({ format, source: { bytes } });
2451
+ }
2452
+ return out;
2453
+ }
2454
+ function toKiroToolInput(input) {
2455
+ if (isPlainObject(input))
2456
+ return input;
2457
+ if (typeof input === "string") {
2458
+ try {
2459
+ const parsed = JSON.parse(input);
2460
+ if (isPlainObject(parsed))
2461
+ return parsed;
2462
+ } catch {
2463
+ }
2464
+ }
2465
+ return {};
2466
+ }
2467
+ function isPlainObject(value) {
2468
+ return !!value && typeof value === "object" && !Array.isArray(value);
2425
2469
  }
2426
2470
  function toolResultOf(msg) {
2427
2471
  return {
@@ -2453,12 +2497,12 @@ function buildHistory(messages, modelId, systemPrompt) {
2453
2497
  ${content}`;
2454
2498
  systemPrepended = true;
2455
2499
  }
2456
- const images = extractImages(msg);
2500
+ const images = convertImagesToKiro(extractImages(msg));
2457
2501
  const uim = {
2458
2502
  content: sanitizeSurrogates(content),
2459
2503
  modelId,
2460
2504
  origin: "KIRO_CLI",
2461
- ...images.length > 0 ? { images: convertImagesToKiro(images) } : {}
2505
+ ...images.length > 0 ? { images } : {}
2462
2506
  };
2463
2507
  const prevUim = history[history.length - 1]?.userInputMessage;
2464
2508
  if (prevUim) {
@@ -2484,7 +2528,7 @@ ${uim.content}` : prevUim.content || uim.content;
2484
2528
  armToolUses.push({
2485
2529
  name: toKiroToolName(block.name),
2486
2530
  toolUseId: toKiroToolUseId(block.id),
2487
- input: block.arguments
2531
+ input: toKiroToolInput(block.arguments)
2488
2532
  });
2489
2533
  armHadBlocks = true;
2490
2534
  }
@@ -2509,8 +2553,9 @@ ${uim.content}` : prevUim.content || uim.content;
2509
2553
  i = j - 1;
2510
2554
  const prevTr = history[history.length - 1]?.userInputMessage;
2511
2555
  if (prevTr) {
2512
- if (trImages.length > 0)
2513
- prevTr.images = [...prevTr.images || [], ...convertImagesToKiro(trImages)];
2556
+ const images = convertImagesToKiro(trImages);
2557
+ if (images.length > 0)
2558
+ prevTr.images = [...prevTr.images || [], ...images];
2514
2559
  if (!prevTr.userInputMessageContext)
2515
2560
  prevTr.userInputMessageContext = {};
2516
2561
  prevTr.userInputMessageContext.toolResults = [
@@ -2518,6 +2563,7 @@ ${uim.content}` : prevUim.content || uim.content;
2518
2563
  ...toolResults
2519
2564
  ];
2520
2565
  } else {
2566
+ const images = convertImagesToKiro(trImages);
2521
2567
  history.push({
2522
2568
  userInputMessage: {
2523
2569
  // Empty by design: `toolResults` is this turn's payload. See
@@ -2525,7 +2571,7 @@ ${uim.content}` : prevUim.content || uim.content;
2525
2571
  content: "",
2526
2572
  modelId,
2527
2573
  origin: "KIRO_CLI",
2528
- ...trImages.length > 0 ? { images: convertImagesToKiro(trImages) } : {},
2574
+ ...images.length > 0 ? { images } : {},
2529
2575
  userInputMessageContext: { toolResults }
2530
2576
  }
2531
2577
  });
@@ -3078,7 +3124,7 @@ function buildKiroRequest(params) {
3078
3124
  armToolUses.push({
3079
3125
  name: toKiroToolName(block.name),
3080
3126
  toolUseId: toKiroToolUseId(block.id),
3081
- input: block.arguments
3127
+ input: toKiroToolInput(block.arguments)
3082
3128
  });
3083
3129
  }
3084
3130
  }
@@ -3107,8 +3153,9 @@ ${armContent}` : prevArm.content || armContent;
3107
3153
  currentToolResults.push(toolResultOf2(m));
3108
3154
  toolResultImages.push(...extractImages(m));
3109
3155
  }
3110
- if (toolResultImages.length > 0)
3111
- currentImages = convertImagesToKiro(toolResultImages);
3156
+ const convertedToolImages = convertImagesToKiro(toolResultImages);
3157
+ if (convertedToolImages.length > 0)
3158
+ currentImages = convertedToolImages;
3112
3159
  currentContent = "";
3113
3160
  } else if (firstMsg?.role === "toolResult") {
3114
3161
  const toolResultImages = [];
@@ -3118,8 +3165,9 @@ ${armContent}` : prevArm.content || armContent;
3118
3165
  currentToolResults.push(toolResultOf2(m));
3119
3166
  toolResultImages.push(...extractImages(m));
3120
3167
  }
3121
- if (toolResultImages.length > 0)
3122
- currentImages = convertImagesToKiro(toolResultImages);
3168
+ const convertedToolImages = convertImagesToKiro(toolResultImages);
3169
+ if (convertedToolImages.length > 0)
3170
+ currentImages = convertedToolImages;
3123
3171
  currentContent = "";
3124
3172
  } else if (firstMsg?.role === "user") {
3125
3173
  currentContent = getContentText(firstMsg);
@@ -3145,9 +3193,9 @@ ${currentContent}`;
3145
3193
  uimc.tools = finalTools;
3146
3194
  }
3147
3195
  if (firstMsg?.role === "user") {
3148
- const imgs = extractImages(firstMsg);
3196
+ const imgs = convertImagesToKiro(extractImages(firstMsg));
3149
3197
  if (imgs.length > 0)
3150
- currentImages = convertImagesToKiro(imgs);
3198
+ currentImages = imgs;
3151
3199
  }
3152
3200
  if (currentContent === "" && currentToolResults.length === 0)
3153
3201
  currentContent = EMPTY_CONTENT_PLACEHOLDER;
@@ -3518,12 +3566,177 @@ function countTokens(text) {
3518
3566
  return getEncoder().encode(text).length;
3519
3567
  }
3520
3568
 
3569
+ // ../kiro-core/dist/tool-name-aliases.js
3570
+ var TOOL_NAME_ALIASES = {
3571
+ // read
3572
+ read_file: "read",
3573
+ readfile: "read",
3574
+ fs_read: "read",
3575
+ view_file: "read",
3576
+ // write
3577
+ write_file: "write",
3578
+ writefile: "write",
3579
+ fs_write: "write",
3580
+ create_file: "write",
3581
+ // edit
3582
+ edit_file: "edit",
3583
+ editfile: "edit",
3584
+ str_replace: "edit",
3585
+ str_replace_editor: "edit",
3586
+ str_replace_based_edit_tool: "edit",
3587
+ apply_patch: "edit",
3588
+ // ls
3589
+ list_directory: "ls",
3590
+ list_dir: "ls",
3591
+ list_files: "ls",
3592
+ // find
3593
+ find_files: "find",
3594
+ file_search: "find"
3595
+ };
3596
+ function normalizeKiroToolName(name, declared) {
3597
+ if (!declared || declared.size === 0 || declared.has(name))
3598
+ return name;
3599
+ const alias = TOOL_NAME_ALIASES[name.toLowerCase()];
3600
+ return alias !== void 0 && declared.has(alias) ? alias : name;
3601
+ }
3602
+
3603
+ // ../kiro-core/dist/tool-use-parser.js
3604
+ var TAG_NAMES = ["tool_use", "tool_call", "function_call", "tool"];
3605
+ var FENCE2 = "```";
3606
+ function nextTagBlock(text, from) {
3607
+ let best = null;
3608
+ for (const name of TAG_NAMES) {
3609
+ const open = `<${name}>`;
3610
+ const close = `</${name}>`;
3611
+ const openStart = text.indexOf(open, from);
3612
+ if (openStart < 0)
3613
+ continue;
3614
+ if (best && openStart >= best.openStart)
3615
+ continue;
3616
+ const bodyStart = openStart + open.length;
3617
+ const closeIdx = text.indexOf(close, bodyStart);
3618
+ if (closeIdx < 0)
3619
+ continue;
3620
+ best = { openStart, bodyStart, closeIdx, closeEnd: closeIdx + close.length };
3621
+ }
3622
+ return best;
3623
+ }
3624
+ function fencedRanges2(text) {
3625
+ const ranges = [];
3626
+ let searchFrom = 0;
3627
+ while (true) {
3628
+ const open = text.indexOf(FENCE2, searchFrom);
3629
+ if (open < 0)
3630
+ break;
3631
+ const close = text.indexOf(FENCE2, open + FENCE2.length);
3632
+ if (close < 0) {
3633
+ ranges.push({ start: open, end: text.length });
3634
+ break;
3635
+ }
3636
+ ranges.push({ start: open, end: close + FENCE2.length });
3637
+ searchFrom = close + FENCE2.length;
3638
+ }
3639
+ return ranges;
3640
+ }
3641
+ function normalizeOne(value) {
3642
+ if (typeof value !== "object" || value === null || Array.isArray(value))
3643
+ return null;
3644
+ const record = value;
3645
+ const rawName = record.tool_name ?? record.name;
3646
+ if (typeof rawName !== "string" || rawName.length === 0)
3647
+ return null;
3648
+ const rawArgs = record.tool_input ?? record.input ?? record.arguments;
3649
+ if (rawArgs === void 0) {
3650
+ return { name: rawName, arguments: {} };
3651
+ }
3652
+ if (typeof rawArgs !== "object" || rawArgs === null || Array.isArray(rawArgs))
3653
+ return null;
3654
+ return { name: rawName, arguments: rawArgs };
3655
+ }
3656
+ function extractDescriptors(value) {
3657
+ if (typeof value === "object" && value !== null && !Array.isArray(value)) {
3658
+ const record = value;
3659
+ const wrapped = record.tool_calls ?? record.calls;
3660
+ if (Array.isArray(wrapped)) {
3661
+ const out = [];
3662
+ for (const entry of wrapped) {
3663
+ const one = normalizeOne(entry);
3664
+ if (one === null)
3665
+ return [];
3666
+ out.push(one);
3667
+ }
3668
+ return out;
3669
+ }
3670
+ }
3671
+ const single = normalizeOne(value);
3672
+ return single ? [single] : [];
3673
+ }
3674
+ function parseToolUseCalls(text) {
3675
+ const toolCalls = [];
3676
+ const removals = [];
3677
+ const fences = fencedRanges2(text);
3678
+ let cursor = 0;
3679
+ while (cursor < text.length) {
3680
+ const hit = nextTagBlock(text, cursor);
3681
+ if (hit === null)
3682
+ break;
3683
+ const { openStart, bodyStart, closeIdx, closeEnd } = hit;
3684
+ const containingFence = fences.find((range) => openStart >= range.start && openStart < range.end);
3685
+ if (containingFence) {
3686
+ cursor = containingFence.end;
3687
+ continue;
3688
+ }
3689
+ const braceStart = text.indexOf("{", bodyStart);
3690
+ if (braceStart < 0 || braceStart > closeIdx) {
3691
+ cursor = closeEnd;
3692
+ continue;
3693
+ }
3694
+ const braceEnd = findJsonEnd(text, braceStart);
3695
+ if (braceEnd < 0 || braceEnd > closeIdx) {
3696
+ cursor = closeEnd;
3697
+ continue;
3698
+ }
3699
+ const beforeJson = text.substring(bodyStart, braceStart).trim();
3700
+ const afterJson = text.substring(braceEnd + 1, closeIdx).trim();
3701
+ if (beforeJson.length > 0 || afterJson.length > 0) {
3702
+ cursor = closeEnd;
3703
+ continue;
3704
+ }
3705
+ let descriptors = [];
3706
+ try {
3707
+ descriptors = extractDescriptors(JSON.parse(text.substring(braceStart, braceEnd + 1)));
3708
+ } catch {
3709
+ descriptors = [];
3710
+ }
3711
+ if (descriptors.length === 0) {
3712
+ cursor = closeEnd;
3713
+ continue;
3714
+ }
3715
+ for (const descriptor of descriptors) {
3716
+ toolCalls.push({
3717
+ toolUseId: crypto.randomUUID(),
3718
+ name: descriptor.name,
3719
+ arguments: descriptor.arguments
3720
+ });
3721
+ }
3722
+ removals.push({ start: openStart, end: closeEnd });
3723
+ cursor = closeEnd;
3724
+ }
3725
+ let cleanedText = text;
3726
+ for (let i = removals.length - 1; i >= 0; i--) {
3727
+ const { start, end } = removals[i];
3728
+ cleanedText = cleanedText.substring(0, start) + cleanedText.substring(end);
3729
+ }
3730
+ return { toolCalls, cleanedText };
3731
+ }
3732
+
3521
3733
  // ../kiro-core/dist/response-assembler.js
3522
3734
  var ECHO_NOISE_PATTERN = /^\s*(continue|\.+)\s*$/i;
3523
3735
  var KiroResponseAssembler = class {
3524
3736
  model;
3525
3737
  thinkingEnabled;
3526
3738
  toolNameAliases;
3739
+ declaredToolNames;
3527
3740
  pending = [];
3528
3741
  blocks = new KiroBlockBuffer((event) => this.pending.push(event));
3529
3742
  usage = {
@@ -3533,7 +3746,6 @@ var KiroResponseAssembler = class {
3533
3746
  cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 }
3534
3747
  };
3535
3748
  totalContent = "";
3536
- lastContentData = "";
3537
3749
  usageEvent = null;
3538
3750
  meteringEvent = null;
3539
3751
  receivedContextUsage = false;
@@ -3546,18 +3758,19 @@ var KiroResponseAssembler = class {
3546
3758
  droppedToolCalls = [];
3547
3759
  currentToolCall = null;
3548
3760
  stopReason = "stop";
3549
- constructor(model, thinkingEnabled, toolNameAliases) {
3761
+ constructor(model, thinkingEnabled, toolNameAliases, declaredToolNames) {
3550
3762
  this.model = model;
3551
3763
  this.thinkingEnabled = thinkingEnabled;
3552
3764
  this.toolNameAliases = toolNameAliases;
3765
+ this.declaredToolNames = declaredToolNames;
3553
3766
  }
3767
+ /** Wire name -> the name the host registered, then alias repair. */
3554
3768
  originalToolName(name) {
3555
- return this.toolNameAliases?.get(name) ?? name;
3769
+ return normalizeKiroToolName(this.toolNameAliases?.get(name) ?? name, this.declaredToolNames);
3556
3770
  }
3557
3771
  /** Clear per-attempt state. Only block indexes are kept. */
3558
3772
  beginAttempt() {
3559
3773
  this.totalContent = "";
3560
- this.lastContentData = "";
3561
3774
  this.usageEvent = null;
3562
3775
  this.meteringEvent = null;
3563
3776
  this.receivedContextUsage = false;
@@ -3613,10 +3826,9 @@ var KiroResponseAssembler = class {
3613
3826
  break;
3614
3827
  }
3615
3828
  case "content": {
3616
- this.endNativeThinking();
3617
- if (event.data === this.lastContentData)
3829
+ if (event.data === "")
3618
3830
  break;
3619
- this.lastContentData = event.data;
3831
+ this.endNativeThinking();
3620
3832
  this.totalContent += event.data;
3621
3833
  if (this.thinkingParser) {
3622
3834
  this.thinkingParser.processChunk(event.data);
@@ -3655,6 +3867,14 @@ var KiroResponseAssembler = class {
3655
3867
  }
3656
3868
  case "usage": {
3657
3869
  this.usageEvent = { ...this.usageEvent ?? {}, ...event.data };
3870
+ const pct = event.data.contextUsagePercentage;
3871
+ if (pct !== void 0) {
3872
+ if (this.usageEvent.inputTokens === void 0) {
3873
+ this.usage.input = Math.round(pct / 100 * this.model.contextWindow);
3874
+ }
3875
+ this.usage.contextPercent = pct;
3876
+ this.receivedContextUsage = true;
3877
+ }
3658
3878
  if (debugEnabled())
3659
3879
  debugLog("response.usageRaw", payload);
3660
3880
  break;
@@ -3688,7 +3908,18 @@ var KiroResponseAssembler = class {
3688
3908
  this.stripEchoNoise();
3689
3909
  const responseText = this.textBlockIndex === null ? "" : this.blocks.getText(this.textBlockIndex);
3690
3910
  const hasText2 = responseText.length > 0;
3691
- this.stopReason = !this.receivedContextUsage && this.emittedToolCalls === 0 ? "length" : this.emittedToolCalls > 0 ? "toolUse" : "stop";
3911
+ const wireStopReason = this.usageEvent?.rawStopReason;
3912
+ switch (wireStopReason) {
3913
+ case "MAX_TOKENS":
3914
+ this.stopReason = "length";
3915
+ break;
3916
+ case "END_TURN":
3917
+ case "TOOL_USE":
3918
+ this.stopReason = this.emittedToolCalls > 0 ? "toolUse" : "stop";
3919
+ break;
3920
+ default:
3921
+ this.stopReason = !this.receivedContextUsage && this.emittedToolCalls === 0 ? "length" : this.emittedToolCalls > 0 ? "toolUse" : "stop";
3922
+ }
3692
3923
  return {
3693
3924
  responseText,
3694
3925
  hasText: hasText2,
@@ -3697,7 +3928,9 @@ var KiroResponseAssembler = class {
3697
3928
  isEchoLoop: hasText2 && !this.sawAnyToolCalls && ECHO_NOISE_PATTERN.test(responseText),
3698
3929
  isEmpty: !hasText2 && !this.sawAnyToolCalls,
3699
3930
  stopReason: this.stopReason,
3700
- droppedToolCalls: this.droppedToolCalls
3931
+ droppedToolCalls: this.droppedToolCalls,
3932
+ ...wireStopReason !== void 0 ? { wireStopReason } : {},
3933
+ ...this.usageEvent?.stopDetails !== void 0 ? { wireStopDetails: this.usageEvent.stopDetails } : {}
3701
3934
  };
3702
3935
  }
3703
3936
  /** Drop an echo the caller decided not to retry, so it is not read as a continuation signal. */
@@ -3781,10 +4014,14 @@ var KiroResponseAssembler = class {
3781
4014
  }
3782
4015
  /**
3783
4016
  * Extract text-dialect tool calls from content when no native tool calls
3784
- * arrived. Two dialects are recovered at this seam:
4017
+ * arrived. Three dialects are recovered at this seam:
3785
4018
  * 1. Kiro's own `[Called name with args: {...}]` bracket form.
3786
4019
  * 2. Anthropic's `<invoke name="..."><parameter .../></invoke>` XML form,
3787
4020
  * which opus-class models emit as plain text at high context.
4021
+ * 3. A JSON descriptor wrapped in `<tool_use>`, `<tool_call>`,
4022
+ * `<function_call>` or `<tool>` tags (upstream #163), spelled
4023
+ * `tool_name`/`tool_input`, `name`/`input` or `name`/`arguments`,
4024
+ * or wrapped in a `{"tool_calls": [...]}` array.
3788
4025
  * Without this, the turn ends `stop` with zero tool calls — the agent loop
3789
4026
  * sees a finished answer and an unattended session stalls with no error
3790
4027
  * recorded anywhere.
@@ -3811,6 +4048,11 @@ var KiroResponseAssembler = class {
3811
4048
  text = invokeResult.cleanedText;
3812
4049
  recovered.push(...invokeResult.toolCalls);
3813
4050
  }
4051
+ const toolUseResult = parseToolUseCalls(text);
4052
+ if (toolUseResult.toolCalls.length > 0) {
4053
+ text = toolUseResult.cleanedText;
4054
+ recovered.push(...toolUseResult.toolCalls);
4055
+ }
3814
4056
  if (recovered.length === 0)
3815
4057
  return;
3816
4058
  this.blocks.setText(this.textBlockIndex, text);
@@ -4861,6 +5103,16 @@ function describeReturnedContent(kinds) {
4861
5103
  }
4862
5104
  var skipProfileResolutionForTests = false;
4863
5105
  var TEST_PROFILE_ARN = "arn:aws:codewhisperer:us-east-1:000000000000:profile/test";
5106
+ function throwOnTerminalWireStop(wireStopReason, stopDetails) {
5107
+ switch (wireStopReason) {
5108
+ case "MODEL_CONTEXT_WINDOW_EXCEEDED":
5109
+ throw new Error("Kiro API error: context_length_exceeded (MODEL_CONTEXT_WINDOW_EXCEEDED)");
5110
+ case "CONTENT_FILTERED":
5111
+ throw new Error(`Kiro content filtered: ${clampForDiagnostic(redactSensitiveText(JSON.stringify(stopDetails ?? {})))}`);
5112
+ case "PAUSE_TURN":
5113
+ throw new Error("Kiro paused the turn (PAUSE_TURN); automatic continuation is not supported");
5114
+ }
5115
+ }
4864
5116
  async function* streamKiro(request) {
4865
5117
  const { model, signal } = request;
4866
5118
  const initialAccessToken = request.accessToken;
@@ -4919,7 +5171,7 @@ async function* streamKiro(request) {
4919
5171
  systemPrompt = `<thinking_mode>enabled</thinking_mode><max_thinking_length>${budget}</max_thinking_length>${systemPrompt ? `
4920
5172
  ${systemPrompt}` : ""}`;
4921
5173
  }
4922
- const assembler = new KiroResponseAssembler(model, thinkingEnabled, kiroToolNameAliases(request.tools));
5174
+ const assembler = new KiroResponseAssembler(model, thinkingEnabled, kiroToolNameAliases(request.tools), new Set((request.tools ?? []).map((tool) => String(tool.name))));
4923
5175
  const usageTracking = request.usageTracking ?? KIRO_USAGE_TRACKING_DISABLED;
4924
5176
  let retryCount = 0;
4925
5177
  const maxRetries = 3;
@@ -5103,6 +5355,7 @@ ${systemPrompt}` : ""}`;
5103
5355
  throw new Error(`Kiro API error: ${outcome.firstTokenTimedOut ? "first token" : "idle"} timeout after max retries`);
5104
5356
  }
5105
5357
  const summary = assembler.endTurn();
5358
+ throwOnTerminalWireStop(summary.wireStopReason, summary.wireStopDetails);
5106
5359
  yield* assembler.takeEvents();
5107
5360
  const degenerate = summary.isEmpty || summary.isEchoLoop;
5108
5361
  if (summary.isEchoLoop)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ns-omp-provider-kiro",
3
- "version": "0.3.5",
3
+ "version": "0.3.8",
4
4
  "description": "OMP (oh-my-pi) provider plugin: adds Kiro (AWS CodeWhisperer/Q) models via your kiro-cli login",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -37,7 +37,7 @@
37
37
  "README.md"
38
38
  ],
39
39
  "dependencies": {
40
- "ns-kiro-core": "0.3.5"
40
+ "ns-kiro-core": "0.3.8"
41
41
  },
42
42
  "peerDependencies": {
43
43
  "@oh-my-pi/pi-ai": ">=18.2.0",