@sidecar-ai/cli 0.1.0-alpha.14 → 0.1.0-alpha.16

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/index.js CHANGED
@@ -532,9 +532,18 @@ function typeToJsonSchemaInner(type) {
532
532
  if (type.isUnion()) {
533
533
  const parts = type.getUnionTypes().filter((part) => !part.isUndefined());
534
534
  if (parts.every(isLiteralType)) {
535
- return { enum: parts.map((part) => literalValue(part)) };
535
+ return { enum: [...new Set(parts.map((part) => literalValue(part)))] };
536
536
  }
537
- return { anyOf: parts.map((part) => typeToJsonSchema(part)) };
537
+ const schemas = deduplicateSchemas(
538
+ parts.map((part) => typeToJsonSchema(part))
539
+ );
540
+ if (schemas.length === 1) {
541
+ return schemas[0];
542
+ }
543
+ return {
544
+ ...schemas.every((schema) => schema.type === "object") ? { type: "object" } : {},
545
+ anyOf: schemas
546
+ };
538
547
  }
539
548
  const properties = type.getProperties();
540
549
  const indexType = type.getStringIndexType() ?? type.getNumberIndexType();
@@ -549,6 +558,37 @@ function typeToJsonSchemaInner(type) {
549
558
  }
550
559
  return {};
551
560
  }
561
+ function deduplicateSchemas(schemas) {
562
+ const seen = /* @__PURE__ */ new Set();
563
+ return schemas.filter((schema) => {
564
+ const key = schemaComparisonKey(schema);
565
+ if (seen.has(key)) {
566
+ return false;
567
+ }
568
+ seen.add(key);
569
+ return true;
570
+ });
571
+ }
572
+ function schemaComparisonKey(schema) {
573
+ return JSON.stringify(canonicalSchemaValue(schema));
574
+ }
575
+ function canonicalSchemaValue(value, keyword) {
576
+ if (Array.isArray(value)) {
577
+ const values = value.map((item) => canonicalSchemaValue(item));
578
+ if (keyword === "allOf" || keyword === "anyOf" || keyword === "enum" || keyword === "oneOf" || keyword === "required" || keyword === "type") {
579
+ return values.sort(
580
+ (left, right) => JSON.stringify(left).localeCompare(JSON.stringify(right))
581
+ );
582
+ }
583
+ return values;
584
+ }
585
+ if (value && typeof value === "object") {
586
+ return Object.fromEntries(
587
+ Object.entries(value).sort(([left], [right]) => left.localeCompare(right)).map(([key, entry]) => [key, canonicalSchemaValue(entry, key)])
588
+ );
589
+ }
590
+ return value;
591
+ }
552
592
  function objectTypeToSchema(properties, indexType) {
553
593
  const schemaProperties = {};
554
594
  const required = [];
@@ -3934,7 +3974,11 @@ import { randomUUID } from "crypto";
3934
3974
  import { JSONRPC_VERSION } from "@modelcontextprotocol/sdk/types.js";
3935
3975
 
3936
3976
  // packages/server/src/index.ts
3937
- import { JSONRPC_VERSION as JSONRPC_VERSION2 } from "@modelcontextprotocol/sdk/types.js";
3977
+ import {
3978
+ JSONRPC_VERSION as JSONRPC_VERSION2,
3979
+ LATEST_PROTOCOL_VERSION,
3980
+ SUPPORTED_PROTOCOL_VERSIONS
3981
+ } from "@modelcontextprotocol/sdk/types.js";
3938
3982
  var CODE_MODE_CALLBACK_TOKEN_TTL_MS = 5 * 60 * 1e3;
3939
3983
 
3940
3984
  // packages/cli/src/dev-harness.ts
@@ -4561,14 +4605,14 @@ function renderDevHarnessHtml(state, options = {}) {
4561
4605
  border: 1px solid var(--border);
4562
4606
  border-radius: 10px;
4563
4607
  display: block;
4564
- height: clamp(360px, 58dvh, 720px);
4565
- min-height: 360px;
4608
+ height: 360px;
4609
+ min-height: 0;
4566
4610
  overflow: auto;
4611
+ transition: height 120ms ease;
4567
4612
  width: 100%;
4568
4613
  }
4569
4614
  :root[data-sidecar-device="mobile"] .tool-body iframe {
4570
- height: clamp(440px, 70dvh, 680px);
4571
- min-height: 440px;
4615
+ height: 440px;
4572
4616
  }
4573
4617
 
4574
4618
  .composer {
@@ -5021,6 +5065,7 @@ async function readMcpResource(mcpUrl, uri, authToken) {
5021
5065
  };
5022
5066
  }
5023
5067
  async function callMcp(mcpUrl, method, params, authToken) {
5068
+ const requestId = randomUUID3();
5024
5069
  const response = await fetch(mcpUrl, {
5025
5070
  method: "POST",
5026
5071
  headers: {
@@ -5031,7 +5076,7 @@ async function callMcp(mcpUrl, method, params, authToken) {
5031
5076
  },
5032
5077
  body: JSON.stringify({
5033
5078
  jsonrpc: "2.0",
5034
- id: randomUUID3(),
5079
+ id: requestId,
5035
5080
  method,
5036
5081
  params
5037
5082
  })
@@ -5040,12 +5085,26 @@ async function callMcp(mcpUrl, method, params, authToken) {
5040
5085
  if (!response.ok) {
5041
5086
  throw new HttpError(response.status, `MCP ${method} failed with HTTP ${response.status}: ${text}`);
5042
5087
  }
5043
- const json = JSON.parse(text);
5088
+ const json = parseMcpResponse(text, response.headers.get("content-type"), requestId);
5044
5089
  if (json.error) {
5045
5090
  throw new HttpError(502, json.error.message ?? `MCP ${method} returned an error.`);
5046
5091
  }
5047
5092
  return json.result;
5048
5093
  }
5094
+ function parseMcpResponse(text, contentType, requestId) {
5095
+ if (!contentType?.toLowerCase().includes("text/event-stream")) {
5096
+ return JSON.parse(text);
5097
+ }
5098
+ for (const event of text.split(/\r?\n\r?\n/)) {
5099
+ const data = event.split(/\r?\n/).filter((line) => line.startsWith("data:")).map((line) => line.slice(5).replace(/^ /, "")).join("\n");
5100
+ if (!data.trim()) continue;
5101
+ const message = JSON.parse(data);
5102
+ if (message && typeof message === "object" && message.id === requestId) {
5103
+ return message;
5104
+ }
5105
+ }
5106
+ throw new Error(`MCP response stream did not contain a result for request "${requestId}".`);
5107
+ }
5049
5108
  function toOpenAiMessages(messages) {
5050
5109
  return [
5051
5110
  {
@@ -5443,6 +5502,16 @@ window.addEventListener("message", async (event) => {
5443
5502
  respond(event.source, message.id, { mode: message.params?.mode || "inline" });
5444
5503
  return;
5445
5504
  }
5505
+ if (message.method === "ui/notifications/size-changed") {
5506
+ const requestedHeight = Number(message.params?.height);
5507
+ const iframe = [...document.querySelectorAll(".tool-body iframe")]
5508
+ .find((candidate) => candidate.contentWindow === event.source);
5509
+ if (iframe && Number.isFinite(requestedHeight) && requestedHeight > 0) {
5510
+ iframe.style.height = Math.min(2000, Math.max(120, Math.ceil(requestedHeight))) + "px";
5511
+ iframe.dataset.autoSized = "true";
5512
+ }
5513
+ return;
5514
+ }
5446
5515
  if (message.method === "ui/message" || message.method === "ui/update-model-context") {
5447
5516
  respond(event.source, message.id, { isError: false });
5448
5517
  return;