@uipath/llmgw-tool 1.202.1 → 1.203.0-preview.180

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
@@ -3,7 +3,7 @@ import {
3
3
  Command,
4
4
  metadata,
5
5
  registerCommands
6
- } from "./tool-yygkmgq6.js";
6
+ } from "./tool-kgc3h6hk.js";
7
7
  import"./tool-1de529jm.js";
8
8
 
9
9
  // src/index.ts
@@ -2099,8 +2099,9 @@ var require_commander = __commonJS(function(exports) {
2099
2099
  // package.json
2100
2100
  var package_default = {
2101
2101
  name: "@uipath/llmgw-tool",
2102
+ author: "UiPath",
2102
2103
  license: "SEE LICENSE IN LICENSE.txt",
2103
- version: "1.202.1",
2104
+ version: "1.203.0-preview.180",
2104
2105
  description: "CLI plugin for UiPath AI Trust Layer Bring-Your-Own LLM connections.",
2105
2106
  private: false,
2106
2107
  repository: {
@@ -2651,7 +2652,7 @@ var UUID_PATTERN = /\b[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{1
2651
2652
  var EMAIL_PATTERN = /\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}\b/g;
2652
2653
  var JWT_PATTERN = /\beyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+/g;
2653
2654
  var LONG_TOKEN_PATTERN = /\b[A-Za-z0-9_-]{40,}\b/g;
2654
- var PADDED_BASE64_PATTERN = /[A-Za-z0-9+/]{16,}={1,2}(?![A-Za-z0-9+/=])/g;
2655
+ var PADDED_BASE64_PATTERN = /(?<![A-Za-z0-9+/])[A-Za-z0-9+/]{16,}={1,2}(?![A-Za-z0-9+/=])/g;
2655
2656
  var BASE64_WITH_PLUS_PATTERN = /[A-Za-z0-9+/]{40,}/g;
2656
2657
  var USER_HOME_PATTERN = /(?<![A-Za-z0-9._-])([/\\])(Users|home|Profiles)([/\\])([^/\\]+)/gi;
2657
2658
  var UNC_PATH_PATTERN = /(^|[\s"'<>|=,;([{])(\\\\[^\s"'<>|]+)/g;
@@ -2698,7 +2699,7 @@ var QUOTED_LITERAL_PATTERN = new RegExp([
2698
2699
  `(?<![A-Za-z0-9])"(?:[^\\
2699
2700
  ]|\\.){2,${QUOTED_LITERAL_MAX_SPAN}}?"(?![A-Za-z0-9])`
2700
2701
  ].join("|"), "g");
2701
- var JSON_BODY_PATTERN = /[{[][^{}[\]]*[:,][^{}[\]]*[\]}]/g;
2702
+ var JSON_BODY_PATTERN = /[{[][^{}[\]:,]*[:,][^{}[\]]*[\]}]/g;
2702
2703
  var COLLAPSED_BODY = "{…}";
2703
2704
  var COLLAPSED_BODY_MARKER = "\x01body\x01";
2704
2705
  var MAX_BODY_NESTING = 8;
@@ -2713,10 +2714,13 @@ function collapseJsonBodies(text) {
2713
2714
  }
2714
2715
  return out.split(COLLAPSED_BODY_MARKER).join(COLLAPSED_BODY);
2715
2716
  }
2716
- var TRAILING_PROSE_PUNCT = /[.,;:!?)\]}>'"]+$/;
2717
+ var TRAILING_PROSE_PUNCT = `.,;:!?)]}>'"`;
2717
2718
  function peelTrailingPunctuation(match) {
2718
- const trailing = match.match(TRAILING_PROSE_PUNCT)?.[0] ?? "";
2719
- return trailing ? [match.slice(0, -trailing.length), trailing] : [match, ""];
2719
+ let end = match.length;
2720
+ while (end > 0 && TRAILING_PROSE_PUNCT.includes(match[end - 1])) {
2721
+ end -= 1;
2722
+ }
2723
+ return [match.slice(0, end), match.slice(end)];
2720
2724
  }
2721
2725
  function redactUrl(raw) {
2722
2726
  try {
@@ -3019,6 +3023,22 @@ function parseHttpStatusFromMessage(message) {
3019
3023
  const status = Number(match[1]);
3020
3024
  return Number.isInteger(status) && status >= 100 && status <= 599 ? status : undefined;
3021
3025
  }
3026
+ function findHttpStatusInGraph(error) {
3027
+ for (const node of walkErrorGraph(error)) {
3028
+ const response = node.response;
3029
+ const explicit = typeof node.status === "number" ? node.status : response?.status;
3030
+ if (typeof explicit === "number" && explicit >= 400 && explicit <= 599) {
3031
+ return explicit;
3032
+ }
3033
+ if (typeof node.message === "string") {
3034
+ const parsed = parseHttpStatusFromMessage(node.message);
3035
+ if (parsed !== undefined && parsed >= 400) {
3036
+ return parsed;
3037
+ }
3038
+ }
3039
+ }
3040
+ return;
3041
+ }
3022
3042
  function isHtmlDocument(body) {
3023
3043
  return /^\s*(<!doctype html|<html\b)/i.test(body);
3024
3044
  }
@@ -3132,7 +3152,8 @@ async function extractErrorDetails(error, options) {
3132
3152
  }
3133
3153
  let message;
3134
3154
  let result = "Failure";
3135
- const classification = classifyError(status, error);
3155
+ const classificationStatus = status ?? findHttpStatusInGraph(error);
3156
+ const classification = classifyError(classificationStatus, error);
3136
3157
  let retry = classification.retry;
3137
3158
  if (status === 401) {
3138
3159
  message = DEFAULT_401;
@@ -3208,8 +3229,8 @@ async function extractErrorDetails(error, options) {
3208
3229
  details = describeThrownValue(error);
3209
3230
  }
3210
3231
  const context = {};
3211
- if (status) {
3212
- context.httpStatus = status;
3232
+ if (classificationStatus) {
3233
+ context.httpStatus = classificationStatus;
3213
3234
  }
3214
3235
  if (parsedBody?.errorCode && typeof parsedBody.errorCode === "string") {
3215
3236
  context.errorCode = parsedBody.errorCode;
@@ -3771,7 +3792,8 @@ function readRegistryValue(keyPath, valueName) {
3771
3792
  }
3772
3793
  const [error, output] = catchError(() => execFileSync("reg", ["query", keyPath, "/v", valueName], {
3773
3794
  encoding: "utf-8",
3774
- stdio: ["pipe", "pipe", "pipe"]
3795
+ stdio: ["pipe", "pipe", "pipe"],
3796
+ windowsHide: true
3775
3797
  }));
3776
3798
  if (error) {
3777
3799
  return "";
@@ -4453,28 +4475,32 @@ function isPlainRecord(value) {
4453
4475
  const prototype = Object.getPrototypeOf(value);
4454
4476
  return prototype === Object.prototype || prototype === null;
4455
4477
  }
4456
- function extractPagedRows(value) {
4478
+ function splitPagedEnvelope(value) {
4457
4479
  if (Array.isArray(value) || !isPlainRecord(value))
4458
4480
  return null;
4459
- const entries = Object.values(value);
4481
+ const entries = Object.entries(value);
4460
4482
  if (entries.length === 0)
4461
4483
  return null;
4462
- let rows = null;
4463
- let hasScalarSibling = false;
4464
- for (const entry of entries) {
4484
+ let found = null;
4485
+ const meta = Object.create(null);
4486
+ for (const [key, entry] of entries) {
4465
4487
  if (Array.isArray(entry)) {
4466
- if (rows !== null)
4488
+ if (found !== null)
4467
4489
  return null;
4468
- rows = entry;
4490
+ found = { key, rows: entry };
4469
4491
  } else if (entry !== null && typeof entry === "object") {
4470
4492
  return null;
4471
4493
  } else {
4472
- hasScalarSibling = true;
4494
+ meta[key] = entry;
4473
4495
  }
4474
4496
  }
4475
- if (rows === null || !hasScalarSibling)
4497
+ if (found === null || Object.keys(meta).length === 0)
4476
4498
  return null;
4477
- return rows;
4499
+ return { ...found, meta };
4500
+ }
4501
+ function extractPagedRows(value) {
4502
+ const paged = splitPagedEnvelope(value);
4503
+ return paged === null ? null : paged.rows;
4478
4504
  }
4479
4505
  function toLowerCamelCaseKey(key) {
4480
4506
  if (!key)
@@ -4578,6 +4604,9 @@ function printOutput(data, format = "json", logFn, asciiSafe = false, tableRowSt
4578
4604
  }
4579
4605
  break;
4580
4606
  }
4607
+ case "markdown":
4608
+ logFn(renderMarkdown(data));
4609
+ break;
4581
4610
  default: {
4582
4611
  const hasData = "Data" in data && data.Data != null;
4583
4612
  const pagedRows = hasData ? extractPagedRows(data.Data) : null;
@@ -4602,6 +4631,10 @@ function logOutput(data, format = "json", tableRowStyle) {
4602
4631
  printOutput(data, format, (msg) => sink.writeOut(`${msg}
4603
4632
  `), needsAsciiSafeJson(sink), styleFn);
4604
4633
  }
4634
+ var PLUMBING_KEYS = new Set(["code", "log"]);
4635
+ function isPlumbingKey(key) {
4636
+ return PLUMBING_KEYS.has(key.toLowerCase());
4637
+ }
4605
4638
  function cellToString(val) {
4606
4639
  return val != null && typeof val === "object" ? JSON.stringify(val) : String(val ?? "");
4607
4640
  }
@@ -4617,7 +4650,7 @@ function wrapText(text, width) {
4617
4650
  function printTable(data, logFn, externalLogValue, tableRowStyle) {
4618
4651
  if (data.length === 0)
4619
4652
  return;
4620
- const keys = Object.keys(data[0]).filter((key) => !["code", "log"].includes(key.toLowerCase()));
4653
+ const keys = Object.keys(data[0]).filter((key) => !isPlumbingKey(key));
4621
4654
  const maxWidths = keys.map((key) => Math.max(key.length, ...data.map((item) => cellToString(item[key]).length)));
4622
4655
  const header = keys.map((key, i) => key.padEnd(maxWidths[i])).join(" | ");
4623
4656
  logFn(header);
@@ -4639,7 +4672,7 @@ function isNonEmptyPlainObject(value) {
4639
4672
  }
4640
4673
  var NESTED_INDENT = " ";
4641
4674
  function printVerticalTable(data, logFn = console.log, externalLogValue) {
4642
- const keys = Object.keys(data).filter((key) => !["code", "log"].includes(key.toLowerCase()));
4675
+ const keys = Object.keys(data).filter((key) => !isPlumbingKey(key));
4643
4676
  if (keys.length === 0)
4644
4677
  return;
4645
4678
  const isBlockValue = (value) => isPlainObjectArray(value) || isNonEmptyPlainObject(value);
@@ -4670,7 +4703,7 @@ function printVerticalTable(data, logFn = console.log, externalLogValue) {
4670
4703
  function printResizableTable(data, logFn = console.log, externalLogValue, availableWidth, tableRowStyle) {
4671
4704
  if (data.length === 0)
4672
4705
  return;
4673
- const keys = Object.keys(data[0]).filter((key) => !["code", "log"].includes(key.toLowerCase()));
4706
+ const keys = Object.keys(data[0]).filter((key) => !isPlumbingKey(key));
4674
4707
  if (keys.length === 0)
4675
4708
  return;
4676
4709
  if (!process.stdout.isTTY) {
@@ -4744,6 +4777,220 @@ function printResizableTable(data, logFn = console.log, externalLogValue, availa
4744
4777
  logFn(`Log: ${externalLogValue}`);
4745
4778
  }
4746
4779
  }
4780
+ var MARKDOWN_MAX_CELL = 200;
4781
+ var MARKDOWN_MAX_DEPTH = 3;
4782
+ function markdownHeading(depth) {
4783
+ return "#".repeat(Math.min(3 + depth, 6));
4784
+ }
4785
+ var BACKTICK_RUN = /`+/g;
4786
+ function fencedBlock(text) {
4787
+ const first = text.trimStart()[0];
4788
+ const language = first === "<" ? "xml" : first === "{" || first === "[" ? "json" : "";
4789
+ const longestRun = Math.max(0, ...Array.from(text.matchAll(BACKTICK_RUN), (match) => match[0].length));
4790
+ const fence = "`".repeat(Math.max(3, longestRun + 1));
4791
+ return `${fence}${language}
4792
+ ${text}
4793
+ ${fence}`;
4794
+ }
4795
+ function collapseNewlineRuns(text) {
4796
+ return text.split(/(\s+)/).map((part, index) => index % 2 === 1 && part.includes(`
4797
+ `) ? " " : part).join("");
4798
+ }
4799
+ function markdownCell(value) {
4800
+ const text = value instanceof Date ? value.toISOString() : cellToString(value);
4801
+ return collapseNewlineRuns(text).replace(/\|/g, "\\|");
4802
+ }
4803
+ function markdownLabel(key) {
4804
+ return collapseNewlineRuns(key).replace(/[\\`*|]/g, "\\$&");
4805
+ }
4806
+ function withoutPlumbing(record) {
4807
+ const kept = Object.create(null);
4808
+ for (const [key, value] of Object.entries(record)) {
4809
+ if (!isPlumbingKey(key))
4810
+ kept[key] = value;
4811
+ }
4812
+ return kept;
4813
+ }
4814
+ function rowsWithoutPlumbing(rows) {
4815
+ return rows.map((row) => isPlainRecord(row) ? withoutPlumbing(row) : row);
4816
+ }
4817
+ function markdownTable(rows) {
4818
+ const columns = [];
4819
+ const seen = new Set;
4820
+ for (const row of rows) {
4821
+ for (const key of Object.keys(row)) {
4822
+ if (!seen.has(key)) {
4823
+ seen.add(key);
4824
+ columns.push(key);
4825
+ }
4826
+ }
4827
+ }
4828
+ if (columns.length === 0)
4829
+ return null;
4830
+ const cells = rows.map((row) => columns.map((key) => markdownCell(row[key])));
4831
+ if (cells.some((row) => row.some((c) => c.length > MARKDOWN_MAX_CELL))) {
4832
+ return null;
4833
+ }
4834
+ return [
4835
+ `| ${columns.map(markdownLabel).join(" | ")} |`,
4836
+ `| ${columns.map(() => "---").join(" | ")} |`,
4837
+ ...cells.map((row) => `| ${row.join(" | ")} |`)
4838
+ ].join(`
4839
+ `);
4840
+ }
4841
+ function extractMessageSequence(rows) {
4842
+ const messages = [];
4843
+ for (const row of rows) {
4844
+ const message = extractSingleMessage(row);
4845
+ if (message === null)
4846
+ return null;
4847
+ messages.push(message);
4848
+ }
4849
+ return messages.join(`
4850
+
4851
+ `);
4852
+ }
4853
+ function markdownRows(rows, depth) {
4854
+ if (rows.length === 0)
4855
+ return "(none)";
4856
+ if (!isPlainObjectArray(rows)) {
4857
+ return rows.map((item) => `- ${markdownCell(item)}`).join(`
4858
+ `);
4859
+ }
4860
+ const prose = extractMessageSequence(rows);
4861
+ if (prose !== null)
4862
+ return prose;
4863
+ const table = markdownTable(rows);
4864
+ if (table !== null)
4865
+ return table;
4866
+ if (depth >= MARKDOWN_MAX_DEPTH) {
4867
+ return fencedBlock(JSON.stringify(rows, null, 2));
4868
+ }
4869
+ return rows.map((row, index) => [
4870
+ `${markdownHeading(depth)} ${index + 1}`,
4871
+ markdownObject(row, depth + 1)
4872
+ ].join(`
4873
+
4874
+ `)).join(`
4875
+
4876
+ `);
4877
+ }
4878
+ function markdownObject(obj, depth) {
4879
+ const scalars = [];
4880
+ const blocks = [];
4881
+ for (const [key, value] of Object.entries(obj)) {
4882
+ if (value === undefined)
4883
+ continue;
4884
+ const label = markdownLabel(key);
4885
+ if (Array.isArray(value)) {
4886
+ blocks.push(`${markdownHeading(depth)} ${label}
4887
+
4888
+ ${markdownRows(value, depth + 1)}`);
4889
+ } else if (isNonEmptyPlainObject(value)) {
4890
+ const nested = depth < MARKDOWN_MAX_DEPTH ? markdownObject(value, depth + 1) : fencedBlock(JSON.stringify(value, null, 2));
4891
+ if (nested !== "") {
4892
+ blocks.push(`${markdownHeading(depth)} ${label}
4893
+
4894
+ ${nested}`);
4895
+ }
4896
+ } else if (typeof value === "string" && value.includes(`
4897
+ `)) {
4898
+ blocks.push(`**${label}:**
4899
+
4900
+ ${fencedBlock(value)}`);
4901
+ } else {
4902
+ scalars.push(`**${label}:** ${markdownCell(value)}`);
4903
+ }
4904
+ }
4905
+ const sections = scalars.length > 0 ? [scalars.join(`
4906
+ `)] : [];
4907
+ sections.push(...blocks);
4908
+ return sections.join(`
4909
+
4910
+ `);
4911
+ }
4912
+ function extractSingleMessage(payload) {
4913
+ if (!isPlainRecord(payload))
4914
+ return null;
4915
+ const keys = Object.keys(payload);
4916
+ if (keys.length !== 1 || keys[0].toLowerCase() !== "message")
4917
+ return null;
4918
+ const value = payload[keys[0]];
4919
+ return typeof value === "string" ? value : null;
4920
+ }
4921
+ function markdownPayload(payload) {
4922
+ const message = extractSingleMessage(payload);
4923
+ if (message !== null)
4924
+ return message;
4925
+ if (Array.isArray(payload)) {
4926
+ return markdownRows(rowsWithoutPlumbing(payload), 0);
4927
+ }
4928
+ const visible = withoutPlumbing(payload);
4929
+ const paged = splitPagedEnvelope(visible);
4930
+ if (paged !== null) {
4931
+ const meta = markdownObject(paged.meta, 0);
4932
+ const rows = `${markdownHeading(0)} ${markdownLabel(paged.key)}
4933
+
4934
+ ${markdownRows(rowsWithoutPlumbing(paged.rows), 1)}`;
4935
+ return meta === "" ? rows : `${meta}
4936
+
4937
+ ${rows}`;
4938
+ }
4939
+ return markdownObject(visible, 0);
4940
+ }
4941
+ function isPaginationWorthShowing(value) {
4942
+ if (typeof value !== "object" || value === null)
4943
+ return false;
4944
+ const page = value;
4945
+ return page.HasMore === true || typeof page.Offset === "number" && page.Offset > 0;
4946
+ }
4947
+ function markdownEnvelopeNotes(data) {
4948
+ const envelope = data;
4949
+ const notes = [];
4950
+ const warning = envelope.Warning;
4951
+ if (typeof warning === "string" && warning !== "") {
4952
+ notes.push(`> **Warning:** ${warning}`);
4953
+ }
4954
+ const instructions = envelope.Instructions;
4955
+ if (typeof instructions === "string" && instructions !== "") {
4956
+ notes.push(`> ${instructions}`);
4957
+ }
4958
+ const pagination = envelope.Pagination;
4959
+ if (isPaginationWorthShowing(pagination)) {
4960
+ const body = markdownObject(pagination, 1);
4961
+ if (body !== "") {
4962
+ notes.push(`${markdownHeading(0)} Pagination
4963
+
4964
+ ${body}`);
4965
+ }
4966
+ }
4967
+ const log = envelope.Log;
4968
+ if (typeof log === "string" && log !== "") {
4969
+ notes.push(`**Log:** ${log}`);
4970
+ }
4971
+ return notes;
4972
+ }
4973
+ function renderMarkdown(data) {
4974
+ if (data.Result !== RESULTS.Success) {
4975
+ const failure = data;
4976
+ const sections = [`**Failed:** ${failure.Message}`];
4977
+ if (failure.Data != null) {
4978
+ sections.push(markdownPayload(failure.Data));
4979
+ }
4980
+ if (failure.Instructions) {
4981
+ sections.push(`> ${failure.Instructions}`);
4982
+ }
4983
+ return sections.filter((section) => section !== "").join(`
4984
+
4985
+ `);
4986
+ }
4987
+ if (!("Data" in data) || data.Data == null) {
4988
+ return markdownObject(withoutPlumbing(data), 0);
4989
+ }
4990
+ return [markdownPayload(data.Data), ...markdownEnvelopeNotes(data)].filter((section) => section !== "").join(`
4991
+
4992
+ `);
4993
+ }
4747
4994
  function toYaml(data) {
4748
4995
  const codec = getYamlCodec();
4749
4996
  if (!codec) {
@@ -7347,16 +7594,7 @@ var resolveEnvFilePathAsync = async (envFilePath = DEFAULT_ENV_FILENAME, opts) =
7347
7594
  errorMessage: location.source === "absolute" ? `Environment file not found: ${envFilePath}` : `Unable to locate environment file: ${envFilePath}. Run 'uip login' to authenticate.`
7348
7595
  };
7349
7596
  };
7350
- var loadEnvFileAsync = async ({ envPath }) => {
7351
- const fs7 = getFileSystem2();
7352
- const absolutePath = fs7.path.isAbsolute(envPath) ? envPath : fs7.path.join(fs7.env.cwd(), envPath);
7353
- if (!await fs7.exists(absolutePath)) {
7354
- throw new Error(`Environment file not found: ${envPath}`);
7355
- }
7356
- const content = await fs7.readFile(absolutePath, "utf-8");
7357
- if (content === null) {
7358
- throw new Error(`Environment file not found: ${envPath}`);
7359
- }
7597
+ var parseEnvContent = (content) => {
7360
7598
  const env = {};
7361
7599
  for (const line of content.split(`
7362
7600
  `)) {
@@ -7377,6 +7615,18 @@ var loadEnvFileAsync = async ({ envPath }) => {
7377
7615
  }
7378
7616
  return env;
7379
7617
  };
7618
+ var loadEnvFileAsync = async ({ envPath }) => {
7619
+ const fs7 = getFileSystem2();
7620
+ const absolutePath = fs7.path.isAbsolute(envPath) ? envPath : fs7.path.join(fs7.env.cwd(), envPath);
7621
+ if (!await fs7.exists(absolutePath)) {
7622
+ throw new Error(`Environment file not found: ${envPath}`);
7623
+ }
7624
+ const content = await fs7.readFile(absolutePath, "utf-8");
7625
+ if (content === null) {
7626
+ throw new Error(`Environment file not found: ${envPath}`);
7627
+ }
7628
+ return parseEnvContent(content);
7629
+ };
7380
7630
  var saveEnvFileAsync = async ({
7381
7631
  envPath,
7382
7632
  data,
@@ -7883,6 +8133,7 @@ function normalizeTokenRefreshUnavailableFailure() {
7883
8133
  function errorMessage(error) {
7884
8134
  return error instanceof Error ? error.message : String(error);
7885
8135
  }
8136
+ init_src();
7886
8137
  init_constants();
7887
8138
  init_src();
7888
8139
  init_constants();
@@ -9266,4 +9517,4 @@ var registerCommands = async (program2) => {
9266
9517
 
9267
9518
  export { Command, metadata, registerCommands };
9268
9519
 
9269
- //# debugId=23BEB0714D252C5664756E2164756E21
9520
+ //# debugId=B1AB170B8879997764756E2164756E21
package/dist/tool.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  metadata,
3
3
  registerCommands
4
- } from "./tool-yygkmgq6.js";
4
+ } from "./tool-kgc3h6hk.js";
5
5
  import"./tool-1de529jm.js";
6
6
  export {
7
7
  metadata,
package/package.json CHANGED
@@ -1,7 +1,8 @@
1
1
  {
2
2
  "name": "@uipath/llmgw-tool",
3
+ "author": "UiPath",
3
4
  "license": "SEE LICENSE IN LICENSE.txt",
4
- "version": "1.202.1",
5
+ "version": "1.203.0-preview.180",
5
6
  "description": "CLI plugin for UiPath AI Trust Layer Bring-Your-Own LLM connections.",
6
7
  "private": false,
7
8
  "repository": {
@@ -23,5 +24,5 @@
23
24
  "files": [
24
25
  "dist"
25
26
  ],
26
- "gitHead": "280b581b7893224d512dd194f47dd57243cc6a5c"
27
+ "gitHead": "4e0a51e3ab2c9d89afd3d35a7b087a7fa58133a0"
27
28
  }