@smwb/onreel-git-mcp 0.11.0 → 0.13.0

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 (39) hide show
  1. package/README.md +128 -6
  2. package/dist/{chunk-3YP22YLA.js → chunk-33ISKIW7.js} +2 -2
  3. package/dist/{chunk-6VQURMRA.js → chunk-AJOAZMU4.js} +2 -1
  4. package/dist/{chunk-4ZGRXIVA.js → chunk-D5QUOIRC.js} +5 -1
  5. package/dist/{chunk-4ZGRXIVA.js.map → chunk-D5QUOIRC.js.map} +1 -1
  6. package/dist/{chunk-VLTG7OKJ.js → chunk-OWLVTLYZ.js} +3 -3
  7. package/dist/contract/contract.schema.d.ts +12 -0
  8. package/dist/contract/contract.types.d.ts +2 -1
  9. package/dist/files/index.js +1 -1
  10. package/dist/git/index.js +4 -4
  11. package/dist/index.js +6 -3
  12. package/dist/index.js.map +1 -1
  13. package/dist/mcp/index.js +3 -3
  14. package/dist/tracker/declarative/declarative-call.lib.d.ts +28 -0
  15. package/dist/tracker/declarative/declarative-capabilities.lib.d.ts +20 -0
  16. package/dist/tracker/declarative/declarative-ci.lib.d.ts +4 -0
  17. package/dist/tracker/declarative/declarative-hint.const.d.ts +4 -0
  18. package/dist/tracker/declarative/declarative-issues.lib.d.ts +5 -0
  19. package/dist/tracker/declarative/declarative-model.const.d.ts +40 -0
  20. package/dist/tracker/declarative/declarative-model.types.d.ts +87 -0
  21. package/dist/tracker/declarative/declarative-parse.lib.d.ts +7 -0
  22. package/dist/tracker/declarative/declarative-pull.lib.d.ts +4 -0
  23. package/dist/tracker/declarative/declarative-request.lib.d.ts +49 -0
  24. package/dist/tracker/declarative/declarative-result.lib.d.ts +11 -0
  25. package/dist/tracker/declarative/declarative-rules.lib.d.ts +4 -0
  26. package/dist/tracker/declarative/declarative.const.d.ts +10 -0
  27. package/dist/tracker/declarative/declarative.lib.d.ts +19 -0
  28. package/dist/tracker/declarative/declarative.schema.d.ts +1324 -0
  29. package/dist/tracker/declarative/declarative.types.d.ts +22 -0
  30. package/dist/tracker/index.d.ts +5 -0
  31. package/dist/tracker/index.js +1968 -35
  32. package/dist/tracker/index.js.map +1 -1
  33. package/dist/tracker/registry.lib.d.ts +8 -1
  34. package/dist/tracker/secrets.lib.d.ts +14 -6
  35. package/dist/worktree/index.js +4 -4
  36. package/package.json +2 -1
  37. /package/dist/{chunk-3YP22YLA.js.map → chunk-33ISKIW7.js.map} +0 -0
  38. /package/dist/{chunk-6VQURMRA.js.map → chunk-AJOAZMU4.js.map} +0 -0
  39. /package/dist/{chunk-VLTG7OKJ.js.map → chunk-OWLVTLYZ.js.map} +0 -0
@@ -1,13 +1,20 @@
1
1
  import {
2
2
  REDACTED,
3
3
  defaultSecretSink,
4
+ isSecretKey,
4
5
  redactSecretText,
5
6
  setSecretSink
6
- } from "../chunk-6VQURMRA.js";
7
+ } from "../chunk-AJOAZMU4.js";
7
8
  import {
9
+ issueCommentSchema,
8
10
  issueLinkSchema,
9
- timestampSchema
10
- } from "../chunk-4ZGRXIVA.js";
11
+ issuePrioritySchema,
12
+ issueSchema,
13
+ issueStatusCategorySchema,
14
+ timestampSchema,
15
+ trackerFieldNameSchema,
16
+ trackerKindSchema
17
+ } from "../chunk-D5QUOIRC.js";
11
18
 
12
19
  // src/tracker/tracker.const.ts
13
20
  var TRACKER_TIMEOUT_MS = 15e3;
@@ -961,8 +968,8 @@ function pageOf(cursor) {
961
968
  const page = cursor === void 0 ? 1 : Number(cursor);
962
969
  return Number.isInteger(page) && page >= 1 ? page : 1;
963
970
  }
964
- function nextCursorOf(page, link) {
965
- return /rel="next"/.test(link) ? { nextCursor: String(page + 1) } : {};
971
+ function nextCursorOf(page, link2) {
972
+ return /rel="next"/.test(link2) ? { nextCursor: String(page + 1) } : {};
966
973
  }
967
974
  function rowsOf(body, field) {
968
975
  const rows = isRecord(body) ? body[field] : void 0;
@@ -1585,16 +1592,27 @@ function concat(head, tail) {
1585
1592
 
1586
1593
  // src/tracker/registry.lib.ts
1587
1594
  var definitions = /* @__PURE__ */ new Map();
1595
+ var userDefinitions = /* @__PURE__ */ new Map();
1588
1596
  function registerTracker(definition) {
1589
1597
  const kind = definition.descriptor.tracker;
1590
1598
  if (definitions.has(kind)) throw new Error(`\u0422\u0440\u0435\u043A\u0435\u0440 ${kind} \u0443\u0436\u0435 \u0437\u0430\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u043E\u0432\u0430\u043D.`);
1591
1599
  definitions.set(kind, definition);
1592
1600
  }
1601
+ function setUserTrackers(next) {
1602
+ const replacement = /* @__PURE__ */ new Map();
1603
+ for (const definition of next) {
1604
+ const kind = definition.descriptor.tracker;
1605
+ if (replacement.has(kind)) throw new Error(`\u0421\u0432\u043E\u0439 \u0442\u0440\u0435\u043A\u0435\u0440 ${kind} \u043F\u043E\u0432\u0442\u043E\u0440\u044F\u0435\u0442\u0441\u044F \u0432 \u043D\u0430\u0431\u043E\u0440\u0435.`);
1606
+ replacement.set(kind, definition);
1607
+ }
1608
+ userDefinitions = replacement;
1609
+ return [...replacement.keys()].filter((kind) => definitions.has(kind));
1610
+ }
1593
1611
  function findTracker(kind) {
1594
- return definitions.get(kind);
1612
+ return definitions.get(kind) ?? userDefinitions.get(kind);
1595
1613
  }
1596
1614
  function listTrackers() {
1597
- return [...definitions.values()];
1615
+ return [...definitions.values(), ...[...userDefinitions.values()].filter((definition) => !definitions.has(definition.descriptor.tracker))];
1598
1616
  }
1599
1617
 
1600
1618
  // src/tracker/pull.schema.ts
@@ -1721,8 +1739,8 @@ function pageOf3(cursor) {
1721
1739
  const page = cursor === void 0 ? 1 : Number(cursor);
1722
1740
  return Number.isInteger(page) && page >= 1 ? page : 1;
1723
1741
  }
1724
- function nextOf(link, page) {
1725
- return link !== null && /rel="next"/.test(link) ? { nextCursor: String(page + 1) } : {};
1742
+ function nextOf(link2, page) {
1743
+ return link2 !== null && /rel="next"/.test(link2) ? { nextCursor: String(page + 1) } : {};
1726
1744
  }
1727
1745
  function stateFilter(status) {
1728
1746
  if (status === void 0) return "all";
@@ -1883,8 +1901,8 @@ function pageOf4(cursor) {
1883
1901
  const page = cursor === void 0 ? 1 : Number(cursor);
1884
1902
  return Number.isInteger(page) && page >= 1 ? page : 1;
1885
1903
  }
1886
- function nextOf2(link, page) {
1887
- return link !== null && /rel="next"/.test(link) ? { nextCursor: String(page + 1) } : {};
1904
+ function nextOf2(link2, page) {
1905
+ return link2 !== null && /rel="next"/.test(link2) ? { nextCursor: String(page + 1) } : {};
1888
1906
  }
1889
1907
  function repoOf(raw, target) {
1890
1908
  const item = isRecord(raw) ? raw : {};
@@ -2065,11 +2083,11 @@ function searchStateFilter(status) {
2065
2083
  if (status.every((item) => item === "done" || item === "declined")) return "is:closed";
2066
2084
  return void 0;
2067
2085
  }
2068
- function issuePageOf(rows, query, link, page) {
2086
+ function issuePageOf(rows, query, link2, page) {
2069
2087
  const items = rows.filter((row) => isRecord(row) && row.pull_request === void 0).map(issueOf);
2070
2088
  return {
2071
2089
  items: query.status === void 0 ? items : items.filter((issue) => query.status?.includes(issue.status.category) === true),
2072
- .../rel="next"/.test(link) ? { nextCursor: String(page + 1) } : {}
2090
+ .../rel="next"/.test(link2) ? { nextCursor: String(page + 1) } : {}
2073
2091
  };
2074
2092
  }
2075
2093
  function composeLabels(plain, priority, status) {
@@ -2685,8 +2703,8 @@ function fieldsOf(patch) {
2685
2703
  async function transition(api, key, category, request) {
2686
2704
  const { fetch, origin, headers } = request;
2687
2705
  const { body } = await requestJson(`${api}/issue/${key}/transitions`, { fetch, origin, headers, missingIsIssue: true });
2688
- const list = isRecord(body) && Array.isArray(body.transitions) ? body.transitions : [];
2689
- const match = list.find((item) => {
2706
+ const list2 = isRecord(body) && Array.isArray(body.transitions) ? body.transitions : [];
2707
+ const match = list2.find((item) => {
2690
2708
  if (!isRecord(item) || !isRecord(item.to) || !isRecord(item.to.statusCategory)) return false;
2691
2709
  return lookup(JIRA_STATUS_CATEGORIES, item.to.statusCategory.key, void 0) === category;
2692
2710
  });
@@ -2905,10 +2923,10 @@ function createPullAdapter({ connection, fetch }) {
2905
2923
  },
2906
2924
  missing: missing(key)
2907
2925
  });
2908
- const operation = isRecord(body) ? body : {};
2909
- if (operation.status === "failed" || operation.status === "cancel") {
2910
- const errorMessage = isRecord(operation.error) ? text(operation.error.message) : void 0;
2911
- throw new TrackerError("conflict", `\u0421\u043B\u0438\u044F\u043D\u0438\u0435 PR ${key} \u043D\u0435 \u0437\u0430\u043F\u0443\u0449\u0435\u043D\u043E: ${redactSecretText(errorMessage ?? String(operation.status))}.`);
2926
+ const operation2 = isRecord(body) ? body : {};
2927
+ if (operation2.status === "failed" || operation2.status === "cancel") {
2928
+ const errorMessage = isRecord(operation2.error) ? text(operation2.error.message) : void 0;
2929
+ throw new TrackerError("conflict", `\u0421\u043B\u0438\u044F\u043D\u0438\u0435 PR ${key} \u043D\u0435 \u0437\u0430\u043F\u0443\u0449\u0435\u043D\u043E: ${redactSecretText(errorMessage ?? String(operation2.status))}.`);
2912
2930
  }
2913
2931
  return getPull(key);
2914
2932
  },
@@ -2984,12 +3002,12 @@ function pullOf3(raw) {
2984
3002
  const mergedAt = toTimestamp(item.merged_at);
2985
3003
  const closedAt = toTimestamp(item.closed_at);
2986
3004
  const key = text(item.slug) ?? "?";
2987
- const statusName = text(item.status) ?? "open";
3005
+ const statusName2 = text(item.status) ?? "open";
2988
3006
  return {
2989
3007
  key,
2990
3008
  title: text(item.title) ?? key,
2991
3009
  ...description === void 0 ? {} : { description },
2992
- status: { category: lookup(SOURCECRAFT_PULL_STATUSES, statusName, "open"), name: statusName },
3010
+ status: { category: lookup(SOURCECRAFT_PULL_STATUSES, statusName2, "open"), name: statusName2 },
2993
3011
  ...author === void 0 ? {} : { author },
2994
3012
  source: text(source.ref) ?? text(item.source_branch) ?? "?",
2995
3013
  target: text(target.ref) ?? text(item.target_branch) ?? "?",
@@ -3230,16 +3248,29 @@ function registerBuiltinTrackers() {
3230
3248
  // src/tracker/secrets.lib.ts
3231
3249
  import { mkdir, readFile, rename, writeFile } from "fs/promises";
3232
3250
  import { join } from "path";
3251
+ var SECRETS_SLOT_PATTERN = /^[a-z0-9][a-z0-9_-]{0,63}$/;
3252
+ var SECRETS_FILE_SUFFIX = "-secrets.json";
3253
+ function trackerSecretsFile(slot) {
3254
+ if (slot === void 0) return TRACKER_SECRETS_FILE;
3255
+ if (typeof slot !== "string" || !SECRETS_SLOT_PATTERN.test(slot)) {
3256
+ throw new TrackerError("invalid_request", `\u0441\u043B\u043E\u0442 \u0445\u0440\u0430\u043D\u0438\u043B\u0438\u0449\u0430 \u0442\u043E\u043A\u0435\u043D\u043E\u0432 '${String(slot)}' \u0432\u043D\u0435 \u043F\u0440\u0430\u0432\u0438\u043B\u0430: \u0441\u0442\u0440\u043E\u0447\u043D\u0430\u044F \u043B\u0430\u0442\u0438\u043D\u0438\u0446\u0430, \u0446\u0438\u0444\u0440\u044B, '-' \u0438 '_', \u043F\u0435\u0440\u0432\u044B\u0439 \u0441\u0438\u043C\u0432\u043E\u043B \u2014 \u0431\u0443\u043A\u0432\u0430 \u0438\u043B\u0438 \u0446\u0438\u0444\u0440\u0430, \u0434\u043B\u0438\u043D\u0430 \u043D\u0435 \u0431\u043E\u043B\u044C\u0448\u0435 64`);
3257
+ }
3258
+ const file = `${slot}${SECRETS_FILE_SUFFIX}`;
3259
+ if (file === TRACKER_SECRETS_FILE) {
3260
+ throw new TrackerError("invalid_request", `\u0441\u043B\u043E\u0442 \u0445\u0440\u0430\u043D\u0438\u043B\u0438\u0449\u0430 \u0442\u043E\u043A\u0435\u043D\u043E\u0432 '${slot}' \u0437\u0430\u0440\u0435\u0437\u0435\u0440\u0432\u0438\u0440\u043E\u0432\u0430\u043D: \u043E\u043D \u0443\u043A\u0430\u0437\u044B\u0432\u0430\u0435\u0442 \u043D\u0430 \u0444\u0430\u0439\u043B \u043F\u043E \u0443\u043C\u043E\u043B\u0447\u0430\u043D\u0438\u044E ${TRACKER_SECRETS_FILE}`);
3261
+ }
3262
+ return file;
3263
+ }
3233
3264
  var queue = Promise.resolve();
3234
3265
  function exclusive(task) {
3235
3266
  const run = queue.then(task, task);
3236
3267
  queue = run.catch(() => void 0);
3237
3268
  return run;
3238
3269
  }
3239
- async function readAll(dataDir) {
3270
+ async function readAll(dataDir, file) {
3240
3271
  let raw;
3241
3272
  try {
3242
- raw = await readFile(join(dataDir, TRACKER_SECRETS_FILE), "utf8");
3273
+ raw = await readFile(join(dataDir, file), "utf8");
3243
3274
  } catch (error) {
3244
3275
  if (error.code === "ENOENT") return {};
3245
3276
  throw error;
@@ -3248,32 +3279,34 @@ async function readAll(dataDir) {
3248
3279
  if (!isRecord(parsed)) return {};
3249
3280
  return Object.fromEntries(Object.entries(parsed).filter((entry) => typeof entry[1] === "string"));
3250
3281
  }
3251
- async function writeAll(dataDir, secrets) {
3282
+ async function writeAll(dataDir, file, secrets) {
3252
3283
  await mkdir(dataDir, { recursive: true, mode: 448 });
3253
- const target = join(dataDir, TRACKER_SECRETS_FILE);
3284
+ const target = join(dataDir, file);
3254
3285
  const temp = `${target}.${String(process.pid)}.tmp`;
3255
3286
  await writeFile(temp, JSON.stringify(secrets), { mode: 384 });
3256
3287
  await rename(temp, target);
3257
3288
  }
3258
- async function readTrackerToken(dataDir, projectId, sink = defaultSecretSink) {
3259
- const token = (await readAll(dataDir))[projectId];
3289
+ async function readTrackerToken(dataDir, projectId, sink = defaultSecretSink, slot) {
3290
+ const token = (await readAll(dataDir, trackerSecretsFile(slot)))[projectId];
3260
3291
  if (token !== void 0) sink.register(token);
3261
3292
  return token;
3262
3293
  }
3263
- function hasTrackerToken(dataDir, projectId) {
3264
- return readAll(dataDir).then((secrets) => secrets[projectId] !== void 0);
3294
+ async function hasTrackerToken(dataDir, projectId, slot) {
3295
+ const secrets = await readAll(dataDir, trackerSecretsFile(slot));
3296
+ return secrets[projectId] !== void 0;
3265
3297
  }
3266
- function writeTrackerToken(dataDir, projectId, token, sink = defaultSecretSink) {
3298
+ async function writeTrackerToken(dataDir, projectId, token, sink = defaultSecretSink, slot) {
3299
+ const file = trackerSecretsFile(slot);
3267
3300
  if (token !== "") sink.register(token);
3268
- return exclusive(async () => {
3269
- const secrets = await readAll(dataDir);
3301
+ await exclusive(async () => {
3302
+ const secrets = await readAll(dataDir, file);
3270
3303
  if (token === "") delete secrets[projectId];
3271
3304
  else secrets[projectId] = token;
3272
- await writeAll(dataDir, secrets);
3305
+ await writeAll(dataDir, file, secrets);
3273
3306
  });
3274
3307
  }
3275
- function deleteTrackerToken(dataDir, projectId, sink = defaultSecretSink) {
3276
- return writeTrackerToken(dataDir, projectId, "", sink);
3308
+ function deleteTrackerToken(dataDir, projectId, sink = defaultSecretSink, slot) {
3309
+ return writeTrackerToken(dataDir, projectId, "", sink, slot);
3277
3310
  }
3278
3311
 
3279
3312
  // src/tracker/pull.lib.ts
@@ -3287,8 +3320,1896 @@ function repoAdapterOf(definition, context) {
3287
3320
  if (definition.repo === void 0) throw new TrackerError("unsupported", `\u0422\u0440\u0435\u043A\u0435\u0440 ${definition.descriptor.title} \u043D\u0435 \u0432\u0435\u0434\u0451\u0442 \u0440\u0435\u043F\u043E\u0437\u0438\u0442\u043E\u0440\u0438\u0439.`);
3288
3321
  return definition.repo.create(context);
3289
3322
  }
3323
+
3324
+ // src/tracker/declarative/declarative.const.ts
3325
+ var TRACKER_CONFIG_MAX_BYTES = 256 * 1024;
3326
+ var TRACKER_CONFIG_ISSUES_MAX = 100;
3327
+ var TRACKER_CONFIG_YAML_ALIAS_MAX = 100;
3328
+ var TRACKER_CONFIG_DEPTH_MAX = 16;
3329
+ var BUILTIN_TRACKER_KINDS = ["local", "sourcecraft", "github", "gitlab", "jira"];
3330
+
3331
+ // src/tracker/declarative/declarative.schema.ts
3332
+ import { z as z4 } from "zod";
3333
+ var templateSchema = z4.string().max(2e3);
3334
+ var trackerConfigJsonPathSchema = z4.string().max(300).regex(/^\$(?:\.[A-Za-z_][\w-]*|\[(?:\d{1,4}|\*)\])*$/, "\u043F\u0443\u0442\u044C JSON \u0432\u0438\u0434\u0430 $.a.b, $.items[0] \u0438\u043B\u0438 $.items[*].name");
3335
+ var paramNameSchema = z4.string().regex(/^[A-Za-z0-9_][\w.\-[\]]{0,99}$/, "\u0438\u043C\u044F \u043F\u0430\u0440\u0430\u043C\u0435\u0442\u0440\u0430: \u043B\u0430\u0442\u0438\u043D\u0438\u0446\u0430, \u0446\u0438\u0444\u0440\u044B, \xAB_\xBB, \xAB.\xBB, \xAB-\xBB, \xAB[\xBB, \xAB]\xBB");
3336
+ var headerNameSchema = z4.string().regex(/^[A-Za-z][A-Za-z0-9-]{0,99}$/, "\u0438\u043C\u044F \u0437\u0430\u0433\u043E\u043B\u043E\u0432\u043A\u0430 HTTP: \u043B\u0430\u0442\u0438\u043D\u0438\u0446\u0430, \u0446\u0438\u0444\u0440\u044B \u0438 \xAB-\xBB");
3337
+ var valueItemSchema = z4.union([
3338
+ trackerConfigJsonPathSchema,
3339
+ z4.strictObject({
3340
+ path: trackerConfigJsonPathSchema,
3341
+ /** Значение ответа → значение единой модели. */
3342
+ map: z4.record(z4.string().max(200), z4.union([z4.string().max(200), z4.boolean()])).optional(),
3343
+ /** Значение, когда по пути ничего нет или значения нет в map. */
3344
+ default: z4.union([z4.string().max(200), z4.number(), z4.boolean()]).optional(),
3345
+ /** Поле единой модели — флаг: есть ли значение по пути. */
3346
+ exists: z4.literal(true).optional()
3347
+ })
3348
+ ]);
3349
+ var trackerConfigValueSchema = z4.union([valueItemSchema, z4.array(valueItemSchema).min(1).max(5)]);
3350
+ var bodyValueSchema = z4.lazy(
3351
+ () => z4.union([templateSchema, z4.number(), z4.boolean(), z4.null(), z4.array(bodyValueSchema).max(100), z4.record(paramNameSchema, bodyValueSchema)])
3352
+ );
3353
+ var trackerConfigPaginationSchema = z4.discriminatedUnion("style", [
3354
+ z4.strictObject({
3355
+ style: z4.literal("page"),
3356
+ /** Параметр номера страницы (с 1) и размера. */
3357
+ page: paramNameSchema,
3358
+ size: paramNameSchema,
3359
+ /** Есть ли следующая: заголовок Link с rel="next", полная страница, свой заголовок или путь JSON с номером. */
3360
+ next: z4.union([z4.enum(["link", "count"]), z4.strictObject({ header: headerNameSchema }), z4.strictObject({ path: trackerConfigJsonPathSchema })])
3361
+ }),
3362
+ z4.strictObject({
3363
+ style: z4.literal("cursor"),
3364
+ /** Параметр курсора и размера страницы. */
3365
+ param: paramNameSchema,
3366
+ size: paramNameSchema.optional(),
3367
+ /** Курсор следующей страницы: путь JSON в ответе или заголовок. */
3368
+ next: z4.union([trackerConfigJsonPathSchema, z4.strictObject({ header: headerNameSchema })])
3369
+ }),
3370
+ z4.strictObject({ style: z4.literal("none") })
3371
+ ]);
3372
+ var trackerConfigOperationSchema = z4.strictObject({
3373
+ method: z4.enum(["GET", "POST", "PUT", "PATCH"]).default("GET"),
3374
+ /** Путь от http.base: начинается с «/», адрес остаётся на origin базы. */
3375
+ path: templateSchema,
3376
+ query: z4.record(paramNameSchema, z4.union([templateSchema, z4.number(), z4.boolean()])).optional(),
3377
+ body: z4.record(paramNameSchema, bodyValueSchema).optional(),
3378
+ /** Таблицы значений входов: вход → (значение единой модели → значение API). */
3379
+ inputs: z4.record(z4.string().max(50), z4.record(z4.string().max(50), z4.string().max(200))).optional(),
3380
+ /** Где в ответе элемент или список элементов; нет — сам ответ. */
3381
+ items: trackerConfigJsonPathSchema.optional(),
3382
+ /** Поле единой модели → откуда взять значение в элементе ответа. */
3383
+ result: z4.record(z4.string().max(100), trackerConfigValueSchema).optional(),
3384
+ /** Своя постраничность списка вместо http.pagination. */
3385
+ pagination: trackerConfigPaginationSchema.optional()
3386
+ });
3387
+ var trackerConfigAuthSchema = z4.discriminatedUnion("kind", [
3388
+ /** `Authorization: Bearer <токен>`. */
3389
+ z4.strictObject({ kind: z4.literal("bearer") }),
3390
+ /** Свой заголовок: `<header>: <prefix><токен>`. */
3391
+ z4.strictObject({
3392
+ kind: z4.literal("header"),
3393
+ header: headerNameSchema,
3394
+ prefix: z4.string().max(50).regex(/^[^\r\n\0]*$/, "\u043F\u0440\u0435\u0444\u0438\u043A\u0441 \u0431\u0435\u0437 \u043F\u0435\u0440\u0435\u0432\u043E\u0434\u0430 \u0441\u0442\u0440\u043E\u043A\u0438").optional()
3395
+ }),
3396
+ /** `Authorization: Basic` из полей user и token. */
3397
+ z4.strictObject({ kind: z4.literal("basic") }),
3398
+ z4.strictObject({ kind: z4.literal("none") })
3399
+ ]);
3400
+ var trackerConfigFieldSchema = z4.strictObject({ name: trackerFieldNameSchema, required: z4.boolean(), secret: z4.boolean() });
3401
+ var operation = trackerConfigOperationSchema;
3402
+ var trackerConfigIssuesSchema = z4.strictObject({
3403
+ list: operation,
3404
+ get: operation,
3405
+ create: operation.optional(),
3406
+ update: operation.optional(),
3407
+ comments: operation.optional(),
3408
+ comment: operation.optional()
3409
+ });
3410
+ var trackerConfigPullsSchema = z4.strictObject({
3411
+ list: operation,
3412
+ get: operation,
3413
+ create: operation.optional(),
3414
+ update: operation.optional(),
3415
+ merge: operation.optional(),
3416
+ comments: operation.optional(),
3417
+ comment: operation.optional()
3418
+ });
3419
+ var trackerConfigCiSchema = z4.strictObject({
3420
+ workflows: operation.optional(),
3421
+ runs: operation,
3422
+ run: operation,
3423
+ jobs: operation.optional(),
3424
+ job: operation.optional(),
3425
+ log: operation.optional(),
3426
+ trigger: operation.optional(),
3427
+ rerun: operation.optional(),
3428
+ rerunFailed: operation.optional(),
3429
+ rerunJob: operation.optional(),
3430
+ cancel: operation.optional(),
3431
+ cancelJob: operation.optional()
3432
+ });
3433
+ var trackerConfigSchema = z4.strictObject({
3434
+ format: z4.literal(1),
3435
+ kind: trackerKindSchema,
3436
+ title: z4.string().min(1).max(100),
3437
+ fields: z4.array(trackerConfigFieldSchema).max(4),
3438
+ http: z4.strictObject({
3439
+ /** Адрес API: `https://…` или `{{url}}/…`; origin базы — единственный, куда уходит токен. */
3440
+ base: templateSchema,
3441
+ auth: trackerConfigAuthSchema,
3442
+ /** Постоянные заголовки (Accept, версия API); секретных среди них нет. */
3443
+ headers: z4.record(headerNameSchema, templateSchema).optional(),
3444
+ pagination: trackerConfigPaginationSchema.default({ style: "none" })
3445
+ }),
3446
+ issues: trackerConfigIssuesSchema.optional(),
3447
+ pulls: trackerConfigPullsSchema.optional(),
3448
+ ci: trackerConfigCiSchema.optional()
3449
+ });
3450
+
3451
+ // src/tracker/declarative/declarative.lib.ts
3452
+ import { z as z5 } from "zod";
3453
+
3454
+ // src/tracker/declarative/declarative-model.const.ts
3455
+ var PLACEHOLDER = /\{\{\s*([A-Za-z][A-Za-z0-9]*)\s*(?:\|\s*([A-Za-z]+)\s*)?\}\}/g;
3456
+ var CONNECTION_PLACEHOLDERS = ["url", "target", "user"];
3457
+ var RESERVED_HEADERS = ["host", "content-length", "content-type", "transfer-encoding", "connection", "accept-encoding", "te", "upgrade", "trailer"];
3458
+ var FORBIDDEN_KEYS = ["__proto__", "constructor", "prototype"];
3459
+ var SECRET_IN_CONFIG = "\u043F\u043E\u0445\u043E\u0436\u0435 \u043D\u0430 \u0441\u0435\u043A\u0440\u0435\u0442: \u0442\u043E\u043A\u0435\u043D \u043D\u0435 \u043F\u0438\u0448\u0443\u0442 \u0432 \u043A\u043E\u043D\u0444\u0438\u0433 \u2014 \u0435\u0433\u043E \u0432\u0432\u043E\u0434\u044F\u0442 \u0432 \u043F\u043E\u0434\u043A\u043B\u044E\u0447\u0435\u043D\u0438\u0438 \u043F\u0440\u043E\u0435\u043A\u0442\u0430, \u0430 \u043F\u043E\u0434\u0441\u0442\u0430\u0432\u043B\u044F\u0435\u0442 \u0442\u043E\u043B\u044C\u043A\u043E http.auth";
3460
+ var INPUT_ANY = "*";
3461
+ var INPUT_NULL = "null";
3462
+ var time = ["createdAfter", "createdBefore", "updatedAfter", "updatedBefore"];
3463
+ var sorting = ["sort", "direction"];
3464
+ var OPERATIONS = {
3465
+ issues: {
3466
+ list: { inputs: ["status", "labels", "assignee", "author", "search", ...time, ...sorting], required: [], model: "issue", list: true, result: "required" },
3467
+ get: { inputs: ["key"], required: ["key"], model: "issue", result: "required" },
3468
+ create: { inputs: ["title", "description", "priority", "labels", "assignee"], required: ["title"], model: "issue", result: "required" },
3469
+ update: { inputs: ["key", "title", "description", "status", "priority", "labels", "assignee"], required: ["key"], model: "issue", result: "optional" },
3470
+ comments: { inputs: ["key", "updatedAfter", "order"], required: ["key"], model: "comment", list: true, result: "required" },
3471
+ comment: { inputs: ["key", "body"], required: ["key", "body"], model: "comment", result: "required" }
3472
+ },
3473
+ pulls: {
3474
+ list: { inputs: ["status", "author", "sourceBranch", "targetBranch", "labels", "search", ...time, ...sorting], required: [], model: "pull", list: true, result: "required" },
3475
+ get: { inputs: ["key"], required: ["key"], model: "pull", result: "required" },
3476
+ create: { inputs: ["title", "sourceBranch", "targetBranch", "description", "draft"], required: ["title", "sourceBranch", "targetBranch"], model: "pull", result: "required" },
3477
+ update: { inputs: ["key", "title", "description", "targetBranch", "status"], required: ["key"], model: "pull", result: "optional" },
3478
+ merge: { inputs: ["key", "method", "headSha", "message", "deleteSource"], required: ["key"], result: "forbidden" },
3479
+ comments: { inputs: ["key", "updatedAfter", "order"], required: ["key"], model: "comment", list: true, result: "required" },
3480
+ comment: { inputs: ["key", "body"], required: ["key", "body"], model: "comment", result: "required" }
3481
+ },
3482
+ ci: {
3483
+ workflows: { inputs: [], required: [], model: "workflow", list: true, result: "required" },
3484
+ runs: { inputs: ["status", "ref", "sha", "event", "workflow", "actor", "pullRequest", ...time, ...sorting], required: [], model: "run", list: true, result: "required" },
3485
+ run: { inputs: ["key"], required: ["key"], model: "run", result: "required" },
3486
+ jobs: { inputs: ["run", "status", "allAttempts"], required: ["run"], model: "job", list: true, result: "required" },
3487
+ job: { inputs: ["key"], required: ["key"], model: "job", result: "required" },
3488
+ log: { inputs: ["key"], required: ["key"], result: "forbidden", text: true },
3489
+ trigger: { inputs: ["ref", "refType", "workflow", "workflows", "inputs"], required: ["ref"], model: "run", result: "optional" },
3490
+ rerun: { inputs: ["key", "debug"], required: ["key"], result: "forbidden" },
3491
+ rerunFailed: { inputs: ["key", "debug"], required: ["key"], result: "forbidden" },
3492
+ rerunJob: { inputs: ["key", "debug"], required: ["key"], result: "forbidden" },
3493
+ cancel: { inputs: ["key"], required: ["key"], result: "forbidden" },
3494
+ cancelJob: { inputs: ["key"], required: ["key"], result: "forbidden" }
3495
+ }
3496
+ };
3497
+ var REQUIRED_OPERATIONS = {
3498
+ issues: ["list", "get"],
3499
+ pulls: ["list", "get"],
3500
+ ci: ["runs", "run"]
3501
+ };
3502
+ var CI_OPERATION_NEEDS = {
3503
+ log: ["job"],
3504
+ rerunJob: ["job"],
3505
+ cancelJob: ["job"]
3506
+ };
3507
+ var BOOLEAN = ["true", "false"];
3508
+ var DIRECTION = ["asc", "desc"];
3509
+ var INPUT_DOMAINS = {
3510
+ issues: {
3511
+ status: issueStatusCategorySchema.options,
3512
+ priority: issuePrioritySchema.options,
3513
+ sort: ISSUE_SORT_FIELDS,
3514
+ direction: DIRECTION,
3515
+ order: DIRECTION,
3516
+ assignee: [INPUT_NULL]
3517
+ },
3518
+ pulls: {
3519
+ status: pullRequestStatusCategorySchema.options,
3520
+ sort: pullRequestSortFieldSchema.options,
3521
+ direction: DIRECTION,
3522
+ order: DIRECTION,
3523
+ method: mergeMethodSchema.options,
3524
+ draft: BOOLEAN,
3525
+ deleteSource: BOOLEAN
3526
+ },
3527
+ ci: {
3528
+ status: ciStatusCategorySchema.options,
3529
+ event: ciEventCategorySchema.options,
3530
+ sort: ciRunSortFieldSchema.options,
3531
+ direction: DIRECTION,
3532
+ refType: ["branch", "tag"],
3533
+ allAttempts: BOOLEAN,
3534
+ debug: BOOLEAN
3535
+ }
3536
+ };
3537
+ var WILDCARD_INPUTS = ["status", "event"];
3538
+ var OBJECT_INPUTS = ["inputs"];
3539
+ var statusName = { type: "text", max: 200 };
3540
+ var ciStatusName = { type: "text", max: 100 };
3541
+ var person = { type: "text", max: 200 };
3542
+ var moment = { type: "time" };
3543
+ var link = { type: "link", max: 2048 };
3544
+ var RESULT_FIELDS = {
3545
+ issue: {
3546
+ key: { type: "id", max: 200, required: true },
3547
+ title: { type: "text", max: 500, required: true },
3548
+ description: { type: "text", max: 1e5 },
3549
+ "status.category": { type: "enum", values: issueStatusCategorySchema.options, required: true },
3550
+ "status.name": statusName,
3551
+ priority: { type: "enum", values: issuePrioritySchema.options },
3552
+ labels: { type: "list", max: 200, count: 100 },
3553
+ assignee: person,
3554
+ url: link,
3555
+ createdAt: moment,
3556
+ updatedAt: moment
3557
+ },
3558
+ comment: {
3559
+ id: { type: "id", max: 200, required: true },
3560
+ author: person,
3561
+ body: { type: "text", max: 1e5, required: true, empty: true },
3562
+ createdAt: moment
3563
+ },
3564
+ pull: {
3565
+ key: { type: "id", max: 200, required: true },
3566
+ title: { type: "text", max: 1024, required: true },
3567
+ description: { type: "text", max: 1048576 },
3568
+ "status.category": { type: "enum", values: pullRequestStatusCategorySchema.options, required: true },
3569
+ "status.name": statusName,
3570
+ merged: { type: "flag" },
3571
+ draft: { type: "flag" },
3572
+ author: person,
3573
+ source: { type: "text", max: 500, required: true },
3574
+ target: { type: "text", max: 500, required: true },
3575
+ headSha: { type: "sha" },
3576
+ labels: { type: "list", max: 200, count: 100 },
3577
+ reviewers: { type: "list", max: 200, count: 100 },
3578
+ url: link,
3579
+ createdAt: moment,
3580
+ updatedAt: moment,
3581
+ mergedAt: moment,
3582
+ closedAt: moment
3583
+ },
3584
+ run: {
3585
+ key: { type: "id", max: 200, required: true },
3586
+ number: { type: "int" },
3587
+ workflows: { type: "list", max: 500, count: 100 },
3588
+ "status.category": { type: "enum", values: ciStatusCategorySchema.options, required: true },
3589
+ "status.name": ciStatusName,
3590
+ "event.category": { type: "enum", values: ciEventCategorySchema.options },
3591
+ "event.name": { type: "text", max: 100 },
3592
+ ref: { type: "text", max: 500 },
3593
+ sha: { type: "sha" },
3594
+ actor: person,
3595
+ pullRequest: { type: "id", max: 200 },
3596
+ attempt: { type: "int", positive: true },
3597
+ errors: { type: "list", max: 4e3, count: 20 },
3598
+ url: link,
3599
+ createdAt: moment,
3600
+ startedAt: moment,
3601
+ finishedAt: moment,
3602
+ updatedAt: moment
3603
+ },
3604
+ job: {
3605
+ key: { type: "id", max: 1e3, required: true },
3606
+ runKey: { type: "id", max: 200 },
3607
+ name: { type: "text", max: 500, required: true },
3608
+ stage: { type: "text", max: 1e3 },
3609
+ "status.category": { type: "enum", values: ciStatusCategorySchema.options, required: true },
3610
+ "status.name": ciStatusName,
3611
+ attempt: { type: "int", positive: true },
3612
+ url: link,
3613
+ createdAt: moment,
3614
+ startedAt: moment,
3615
+ finishedAt: moment
3616
+ },
3617
+ workflow: {
3618
+ key: { type: "id", max: 200, required: true },
3619
+ name: { type: "text", max: 500, required: true },
3620
+ path: { type: "text", max: 1e3 },
3621
+ enabled: { type: "flag" }
3622
+ }
3623
+ };
3624
+ var OPERATION_REQUIRED_FIELDS = {
3625
+ "ci.job": ["runKey"]
3626
+ };
3627
+
3628
+ // src/tracker/declarative/declarative-result.lib.ts
3629
+ var MODEL_SCHEMAS = {
3630
+ issue: issueSchema,
3631
+ comment: issueCommentSchema,
3632
+ pull: pullRequestSchema,
3633
+ run: ciRunSchema,
3634
+ job: ciJobSchema,
3635
+ workflow: ciWorkflowSchema
3636
+ };
3637
+ function stepsOf(path) {
3638
+ const steps = [];
3639
+ const pattern = /\.([A-Za-z_][\w-]*)|\[(\d{1,4})\]|\[\*\]/gy;
3640
+ pattern.lastIndex = 1;
3641
+ for (let match = pattern.exec(path); match !== null; match = pattern.exec(path)) {
3642
+ if (match[1] !== void 0) steps.push({ key: match[1] });
3643
+ else if (match[2] !== void 0) steps.push({ index: Number(match[2]) });
3644
+ else steps.push({ all: true });
3645
+ }
3646
+ return steps;
3647
+ }
3648
+ function readPath(path, value) {
3649
+ const steps = stepsOf(path);
3650
+ let current = [value];
3651
+ for (const step of steps) {
3652
+ const next = [];
3653
+ for (const item of current) {
3654
+ if ("all" in step) {
3655
+ if (Array.isArray(item)) next.push(...item);
3656
+ } else if ("index" in step) {
3657
+ if (Array.isArray(item) && step.index < item.length) next.push(item[step.index]);
3658
+ } else if (isRecord(item) && Object.hasOwn(item, step.key)) {
3659
+ next.push(item[step.key]);
3660
+ }
3661
+ }
3662
+ current = next;
3663
+ }
3664
+ if (steps.some((step) => "all" in step)) return current.filter((item) => item !== void 0 && item !== null);
3665
+ return current[0];
3666
+ }
3667
+ function present(value, field) {
3668
+ return value !== void 0 && value !== null && (value !== "" || field.empty === true);
3669
+ }
3670
+ function valueOfItem(item, raw) {
3671
+ if (typeof item === "string") return raw;
3672
+ if (item.exists === true) return !(Array.isArray(raw) && raw.length === 0);
3673
+ const map = item.map;
3674
+ if (map === void 0) return raw;
3675
+ const lookup2 = (value) => {
3676
+ const key = String(value);
3677
+ return Object.hasOwn(map, key) ? map[key] : item.default ?? value;
3678
+ };
3679
+ return Array.isArray(raw) ? raw.map(lookup2) : lookup2(raw);
3680
+ }
3681
+ function evaluate(spec, element, field) {
3682
+ const items = Array.isArray(spec) ? spec : [spec];
3683
+ for (const item of items) {
3684
+ const raw = readPath(typeof item === "string" ? item : item.path, element);
3685
+ if (present(raw, field)) return { raw, value: valueOfItem(item, raw) };
3686
+ }
3687
+ const last = items.at(-1);
3688
+ if (last === void 0 || typeof last === "string") return void 0;
3689
+ if (last.exists === true) return { raw: void 0, value: false };
3690
+ return last.default === void 0 ? void 0 : { raw: void 0, value: last.default };
3691
+ }
3692
+ function clip(value, max) {
3693
+ return max === void 0 ? value : clipText(value, max);
3694
+ }
3695
+ function timeOf(value) {
3696
+ if (typeof value === "string") {
3697
+ const ms = Date.parse(value);
3698
+ return Number.isFinite(ms) && ms >= 0 ? ms : void 0;
3699
+ }
3700
+ if (typeof value === "number" && Number.isSafeInteger(value) && value >= 0) return value < 1e11 ? value * 1e3 : value;
3701
+ return void 0;
3702
+ }
3703
+ function linkOf(value) {
3704
+ if (typeof value !== "string" || value.length > 2048) return void 0;
3705
+ try {
3706
+ const url = new URL(value);
3707
+ return url.protocol === "http:" || url.protocol === "https:" ? value : void 0;
3708
+ } catch {
3709
+ return void 0;
3710
+ }
3711
+ }
3712
+ function coerce(field, value) {
3713
+ switch (field.type) {
3714
+ case "id":
3715
+ if (typeof value === "string" && value !== "") return clip(value, field.max);
3716
+ if (typeof value === "number" && Number.isFinite(value)) return String(value);
3717
+ return void 0;
3718
+ case "text":
3719
+ if (typeof value === "string") return value === "" && field.empty !== true ? void 0 : clip(value, field.max);
3720
+ if (typeof value === "number" || typeof value === "boolean") return String(value);
3721
+ return void 0;
3722
+ case "int": {
3723
+ const number = typeof value === "string" && /^\d{1,15}$/.test(value) ? Number(value) : value;
3724
+ if (typeof number !== "number" || !Number.isSafeInteger(number) || number < (field.positive === true ? 1 : 0)) return void 0;
3725
+ return number;
3726
+ }
3727
+ case "flag":
3728
+ if (typeof value === "boolean") return value;
3729
+ return value === "true" ? true : value === "false" ? false : void 0;
3730
+ case "time":
3731
+ return timeOf(value);
3732
+ case "list": {
3733
+ const items = Array.isArray(value) ? value : [value];
3734
+ const texts = items.map((item) => typeof item === "string" ? item : typeof item === "number" ? String(item) : "").filter((item) => item !== "");
3735
+ return [...new Set(texts.map((item) => clip(item, field.max)))].slice(0, field.count);
3736
+ }
3737
+ case "link":
3738
+ return linkOf(value);
3739
+ case "enum":
3740
+ return typeof value === "string" || typeof value === "number" || typeof value === "boolean" ? String(value) : void 0;
3741
+ case "sha":
3742
+ return typeof value === "string" && /^[0-9a-fA-F]{7,64}$/.test(value) ? value.toLowerCase() : void 0;
3743
+ }
3744
+ }
3745
+ function setNested(target, path, value) {
3746
+ const [head, ...rest] = path.split(".");
3747
+ if (head === void 0) return;
3748
+ if (rest.length === 0) {
3749
+ target[head] = value;
3750
+ return;
3751
+ }
3752
+ const inner = isRecord(target[head]) ? target[head] : {};
3753
+ target[head] = inner;
3754
+ setNested(inner, rest.join("."), value);
3755
+ }
3756
+ function nativeName(out, key, raw, max) {
3757
+ const native = out[key];
3758
+ if (!isRecord(native) || typeof native.category !== "string" || native.name !== void 0) return;
3759
+ const source = typeof raw === "string" && raw !== "" ? raw : typeof raw === "number" || typeof raw === "boolean" ? String(raw) : native.category;
3760
+ native.name = clipText(source, max);
3761
+ }
3762
+ function answerFailed(title, call, detail) {
3763
+ return new TrackerError("failed", redactSecretText(`\u0422\u0440\u0435\u043A\u0435\u0440 \xAB${title}\xBB: \u043E\u0442\u0432\u0435\u0442 \u043E\u043F\u0435\u0440\u0430\u0446\u0438\u0438 ${call.section}.${call.name} \u043D\u0435 \u0441\u043E\u0432\u043F\u0430\u043B \u0441 \u0435\u0434\u0438\u043D\u043E\u0439 \u043C\u043E\u0434\u0435\u043B\u044C\u044E: ${detail}.`));
3764
+ }
3765
+ function buildItem(title, call, element, defaults = {}) {
3766
+ const model = call.spec.model;
3767
+ if (model === void 0) throw answerFailed(title, call, "\u0443 \u043E\u043F\u0435\u0440\u0430\u0446\u0438\u0438 \u043D\u0435\u0442 \u043C\u043E\u0434\u0435\u043B\u0438 \u0440\u0435\u0437\u0443\u043B\u044C\u0442\u0430\u0442\u0430");
3768
+ const fields = RESULT_FIELDS[model];
3769
+ const out = {};
3770
+ const raws = {};
3771
+ for (const [name, spec] of Object.entries(call.operation.result ?? {})) {
3772
+ const field = Object.hasOwn(fields, name) ? fields[name] : void 0;
3773
+ if (field === void 0) continue;
3774
+ const found = evaluate(spec, element, field);
3775
+ if (found === void 0) continue;
3776
+ raws[name] = found.raw;
3777
+ const value = coerce(field, found.value);
3778
+ if (value === void 0) continue;
3779
+ if (field.type === "enum" && typeof value === "string" && field.values !== void 0 && !field.values.includes(value)) {
3780
+ if (field.required === true) throw answerFailed(title, call, `${name}: \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0435 \xAB${clipText(value, 100)}\xBB \u043D\u0435 \u0438\u0437 \u043F\u0435\u0440\u0435\u0447\u043D\u044F ${field.values.join(", ")} \u2014 \u0434\u043E\u0431\u0430\u0432\u044C\u0442\u0435 \u0435\u0433\u043E \u0432 map \u0438\u043B\u0438 \u0437\u0430\u0434\u0430\u0439\u0442\u0435 default`);
3781
+ continue;
3782
+ }
3783
+ if (field.type === "link") out.links = [{ url: value }];
3784
+ else setNested(out, name, value);
3785
+ }
3786
+ for (const [name, value] of Object.entries(defaults)) if (out[name] === void 0) setNested(out, name, value);
3787
+ if (model === "issue" || model === "pull" || model === "run" || model === "job") out.links ??= [];
3788
+ if (model === "issue" || model === "pull") out.labels ??= [];
3789
+ if (model === "run") out.workflows ??= [];
3790
+ if (model === "workflow") out.enabled ??= true;
3791
+ if (model === "run" && isRecord(out.event) && out.event.category === void 0) out.event.category = "other";
3792
+ nativeName(out, "status", raws["status.category"], model === "run" || model === "job" ? 100 : 200);
3793
+ nativeName(out, "event", raws["event.category"], 100);
3794
+ if (model === "pull") {
3795
+ const status = isRecord(out.status) ? out.status : void 0;
3796
+ if (status !== void 0 && (out.merged === true || out.mergedAt !== void 0)) status.category = "merged";
3797
+ else if (status !== void 0 && out.draft === true && status.category === "open") status.category = "draft";
3798
+ delete out.merged;
3799
+ delete out.draft;
3800
+ }
3801
+ const parsed = MODEL_SCHEMAS[model].safeParse(out);
3802
+ if (!parsed.success) {
3803
+ const first = parsed.error.issues[0];
3804
+ const where = first === void 0 || first.path.length === 0 ? "\u044D\u043B\u0435\u043C\u0435\u043D\u0442" : first.path.map(String).join(".");
3805
+ throw answerFailed(title, call, `${where}: ${first?.message ?? "\u043D\u0435 \u043F\u0440\u043E\u0448\u0451\u043B \u0441\u0445\u0435\u043C\u0443"}`);
3806
+ }
3807
+ return parsed.data;
3808
+ }
3809
+
3810
+ // src/tracker/declarative/declarative-request.lib.ts
3811
+ function placeholdersOf(template) {
3812
+ return [...template.matchAll(new RegExp(PLACEHOLDER.source, "g"))].map((match) => ({ name: match[1] ?? "", modifier: match[2] }));
3813
+ }
3814
+ function wholePlaceholder(template) {
3815
+ return /^\{\{\s*([A-Za-z][A-Za-z0-9]*)\s*\}\}$/.exec(template)?.[1];
3816
+ }
3817
+ function bodyTemplates(value) {
3818
+ if (typeof value === "string") return [value];
3819
+ if (Array.isArray(value)) return value.flatMap(bodyTemplates);
3820
+ if (isRecord(value)) return Object.values(value).flatMap(bodyTemplates);
3821
+ return [];
3822
+ }
3823
+ function usedNames(operation2) {
3824
+ if (operation2 === void 0) return /* @__PURE__ */ new Set();
3825
+ const templates = [operation2.path, ...Object.values(operation2.query ?? {}).map(String), ...bodyTemplates(operation2.body)];
3826
+ return new Set(templates.flatMap((template) => placeholdersOf(template).map((placeholder) => placeholder.name)));
3827
+ }
3828
+ function invalid(title, message) {
3829
+ return new TrackerError("invalid_request", `\u0422\u0440\u0435\u043A\u0435\u0440 \xAB${title}\xBB: ${message}`);
3830
+ }
3831
+ function httpUrl(title, value, what) {
3832
+ let parsed;
3833
+ try {
3834
+ parsed = new URL(value);
3835
+ } catch {
3836
+ throw invalid(title, `${what} \u2014 \u043D\u0435 URL.`);
3837
+ }
3838
+ if (parsed.protocol !== "http:" && parsed.protocol !== "https:") throw invalid(title, `${what} \u0434\u043E\u043B\u0436\u0435\u043D \u0431\u044B\u0442\u044C http \u0438\u043B\u0438 https.`);
3839
+ if (parsed.username !== "" || parsed.password !== "" || parsed.search !== "" || parsed.hash !== "") {
3840
+ throw invalid(title, `\u0432 ${what === "url \u043F\u043E\u0434\u043A\u043B\u044E\u0447\u0435\u043D\u0438\u044F" ? "url \u043F\u043E\u0434\u043A\u043B\u044E\u0447\u0435\u043D\u0438\u044F" : "\u0430\u0434\u0440\u0435\u0441\u0435 API"} \u043D\u0435 \u0434\u043E\u043B\u0436\u043D\u043E \u0431\u044B\u0442\u044C \u0438\u043C\u0435\u043D\u0438, \u043F\u0430\u0440\u043E\u043B\u044F, \u043F\u0430\u0440\u0430\u043C\u0435\u0442\u0440\u043E\u0432 \u0438 \u044F\u043A\u043E\u0440\u044F.`);
3841
+ }
3842
+ return parsed;
3843
+ }
3844
+ function baseOf(config, connection) {
3845
+ const template = config.http.base;
3846
+ const head = /^\{\{\s*url\s*\}\}/.exec(template);
3847
+ let raw = template;
3848
+ if (head !== null) {
3849
+ const url = connection.url?.trim().replace(/\/+$/, "");
3850
+ if (url === void 0 || url === "") throw invalid(config.title, "\u043D\u0435 \u0437\u0430\u0434\u0430\u043D url \u043F\u043E\u0434\u043A\u043B\u044E\u0447\u0435\u043D\u0438\u044F.");
3851
+ if (/[?#]/.test(url)) throw invalid(config.title, "\u0432 url \u043F\u043E\u0434\u043A\u043B\u044E\u0447\u0435\u043D\u0438\u044F \u043D\u0435 \u0434\u043E\u043B\u0436\u043D\u043E \u0431\u044B\u0442\u044C \u0438\u043C\u0435\u043D\u0438, \u043F\u0430\u0440\u043E\u043B\u044F, \u043F\u0430\u0440\u0430\u043C\u0435\u0442\u0440\u043E\u0432 \u0438 \u044F\u043A\u043E\u0440\u044F.");
3852
+ httpUrl(config.title, url, "url \u043F\u043E\u0434\u043A\u043B\u044E\u0447\u0435\u043D\u0438\u044F");
3853
+ raw = url + template.slice(head[0].length);
3854
+ }
3855
+ raw = raw.replace(/\/+$/, "");
3856
+ const parsed = httpUrl(config.title, raw, "\u0430\u0434\u0440\u0435\u0441 API");
3857
+ return { base: raw, origin: parsed.origin, path: parsed.pathname.replace(/\/+$/, "") };
3858
+ }
3859
+ function valueOf(context, inputs, name) {
3860
+ if (CONNECTION_PLACEHOLDERS.includes(name)) {
3861
+ const value = context.connection[name];
3862
+ return value === void 0 || value === "" ? void 0 : name === "url" ? value.trim().replace(/\/+$/, "") : value;
3863
+ }
3864
+ return Object.hasOwn(inputs, name) ? inputs[name] : void 0;
3865
+ }
3866
+ function mapInputs(title, call, inputs) {
3867
+ const out = { ...inputs };
3868
+ for (const [name, table] of Object.entries(call.operation.inputs ?? {})) {
3869
+ const value = inputs[name];
3870
+ if (value === void 0) continue;
3871
+ const refuse = (key2) => new TrackerError("unsupported", `\u0422\u0440\u0435\u043A\u0435\u0440 \xAB${title}\xBB: \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0435 \xAB${key2}\xBB \u0432\u0445\u043E\u0434\u0430 ${name} \u043E\u043F\u0435\u0440\u0430\u0446\u0438\u0438 ${call.section}.${call.name} \u043D\u0435 \u043F\u043E\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442\u0441\u044F.`);
3872
+ if (value === null) {
3873
+ if (!Object.hasOwn(table, INPUT_NULL)) throw refuse(INPUT_NULL);
3874
+ out[name] = table[INPUT_NULL];
3875
+ continue;
3876
+ }
3877
+ if (Array.isArray(value)) {
3878
+ const items = value;
3879
+ const any = Object.hasOwn(table, INPUT_ANY) ? table[INPUT_ANY] : void 0;
3880
+ const missing = items.find((item) => !Object.hasOwn(table, item));
3881
+ if (missing !== void 0) {
3882
+ if (any === void 0) throw refuse(missing);
3883
+ out[name] = any;
3884
+ continue;
3885
+ }
3886
+ const mapped = [...new Set(items.map((item) => table[item] ?? item))];
3887
+ out[name] = mapped.length === 1 ? mapped[0] : any ?? mapped;
3888
+ continue;
3889
+ }
3890
+ if (typeof value === "object") continue;
3891
+ const key = String(value);
3892
+ if (!Object.hasOwn(table, key)) throw refuse(key);
3893
+ out[name] = table[key];
3894
+ }
3895
+ return out;
3896
+ }
3897
+ function textOf(title, name, value) {
3898
+ if (value === null) throw new TrackerError("unsupported", `\u0422\u0440\u0435\u043A\u0435\u0440 \xAB${title}\xBB: \u043F\u0443\u0441\u0442\u043E\u0435 \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0435 (null) \u0432\u0445\u043E\u0434\u0430 ${name} \u043D\u0435 \u043F\u043E\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442\u0441\u044F.`);
3899
+ if (typeof value === "string") return value;
3900
+ if (typeof value === "number" || typeof value === "boolean") return String(value);
3901
+ if (Array.isArray(value)) {
3902
+ const items = value;
3903
+ if (items.some((item) => item.includes(","))) throw invalid(title, `\u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0435 \u0432\u0445\u043E\u0434\u0430 ${name} \u043D\u0435 \u0434\u043E\u043B\u0436\u043D\u043E \u0441\u043E\u0434\u0435\u0440\u0436\u0430\u0442\u044C \u0437\u0430\u043F\u044F\u0442\u0443\u044E: \u0441\u043F\u0438\u0441\u043E\u043A \u0443\u0445\u043E\u0434\u0438\u0442 \u0447\u0435\u0440\u0435\u0437 \u0437\u0430\u043F\u044F\u0442\u0443\u044E.`);
3904
+ return items.join(",");
3905
+ }
3906
+ throw invalid(title, `\u0432\u0445\u043E\u0434 ${name} \u2014 \u0441\u043B\u043E\u0432\u0430\u0440\u044C: \u043E\u043D \u043F\u043E\u0434\u0441\u0442\u0430\u0432\u043B\u044F\u0435\u0442\u0441\u044F \u0442\u043E\u043B\u044C\u043A\u043E \u0446\u0435\u043B\u044B\u043C \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0435\u043C \u0442\u0435\u043B\u0430.`);
3907
+ }
3908
+ function segment(title, name, value, input) {
3909
+ const refuse = (why) => invalid(title, `\u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0435 \u0432\u0445\u043E\u0434\u0430 ${name} \u043D\u0435\u043B\u044C\u0437\u044F \u043F\u043E\u0434\u0441\u0442\u0430\u0432\u0438\u0442\u044C \u0432 \u043F\u0443\u0442\u044C \u0437\u0430\u043F\u0440\u043E\u0441\u0430: ${why}.`);
3910
+ if (value === "" || value === "." || value === "..") throw refuse(value === "" ? "\u043F\u0443\u0441\u0442\u043E\u0439 \u0441\u0435\u0433\u043C\u0435\u043D\u0442" : `\xAB${value}\xBB \u2014 \u043F\u0435\u0440\u0435\u0445\u043E\u0434 \u043F\u043E \u043F\u0443\u0442\u0438`);
3911
+ if (/[\\\u0000-\u001f\u007f]/.test(value)) throw refuse("\xAB\\\xBB \u0438 \u0443\u043F\u0440\u0430\u0432\u043B\u044F\u044E\u0449\u0438\u0435 \u0441\u0438\u043C\u0432\u043E\u043B\u044B \u043D\u0435\u0434\u043E\u043F\u0443\u0441\u0442\u0438\u043C\u044B");
3912
+ if (input && (value.includes("/") || /%(?:2f|5c)/i.test(value))) throw refuse("\u0440\u0430\u0437\u0434\u0435\u043B\u0438\u0442\u0435\u043B\u044C \u043F\u0443\u0442\u0438 \xAB/\xBB \u043D\u0435\u0434\u043E\u043F\u0443\u0441\u0442\u0438\u043C");
3913
+ try {
3914
+ return encodeURIComponent(value);
3915
+ } catch {
3916
+ throw refuse("\u0441\u0442\u0440\u043E\u043A\u0430 \u043D\u0435 \u043A\u043E\u0434\u0438\u0440\u0443\u0435\u0442\u0441\u044F \u0432 UTF-8");
3917
+ }
3918
+ }
3919
+ function render(context, inputs, template, where) {
3920
+ let missing = false;
3921
+ const out = template.replace(new RegExp(PLACEHOLDER.source, "g"), (_match, name, modifier) => {
3922
+ const value = valueOf(context, inputs, name);
3923
+ if (value === void 0) {
3924
+ missing = true;
3925
+ return "";
3926
+ }
3927
+ const text2 = textOf(context.config.title, name, value);
3928
+ if (where !== "path") return text2;
3929
+ const input = !CONNECTION_PLACEHOLDERS.includes(name);
3930
+ if (modifier === "path") return text2.split("/").map((part) => segment(context.config.title, name, part, input)).join("/");
3931
+ return segment(context.config.title, name, text2, input);
3932
+ });
3933
+ return missing ? void 0 : out;
3934
+ }
3935
+ function headerValue(title, name, value) {
3936
+ if (/[\r\n\0]/.test(value)) throw invalid(title, `\u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0435 \u0437\u0430\u0433\u043E\u043B\u043E\u0432\u043A\u0430 ${name} \u0441\u043E\u0434\u0435\u0440\u0436\u0438\u0442 \u043F\u0435\u0440\u0435\u0432\u043E\u0434 \u0441\u0442\u0440\u043E\u043A\u0438.`);
3937
+ return value;
3938
+ }
3939
+ function headersOf(config, connection) {
3940
+ const headers = {};
3941
+ for (const [name, template] of Object.entries(config.http.headers ?? {})) {
3942
+ const value = render({ config, connection }, {}, template, "text");
3943
+ if (value !== void 0) headers[name.toLowerCase()] = headerValue(config.title, name, value);
3944
+ }
3945
+ const token = connection.token;
3946
+ const auth = config.http.auth;
3947
+ if (token === void 0 || token === "" || auth.kind === "none") return headers;
3948
+ headerValue(config.title, "\u0430\u0432\u0442\u043E\u0440\u0438\u0437\u0430\u0446\u0438\u0438", token);
3949
+ if (auth.kind === "bearer") headers.authorization = `Bearer ${token}`;
3950
+ else if (auth.kind === "header") headers[auth.header.toLowerCase()] = `${auth.prefix ?? ""}${token}`;
3951
+ else headers.authorization = `Basic ${Buffer.from(`${connection.user ?? ""}:${token}`).toString("base64")}`;
3952
+ return headers;
3953
+ }
3954
+ function urlOf(context, call, inputs) {
3955
+ const path = render(context, inputs, call.operation.path, "path");
3956
+ if (path === void 0) {
3957
+ const names = placeholdersOf(call.operation.path).map((placeholder) => placeholder.name).filter((name) => valueOf(context, inputs, name) === void 0);
3958
+ throw invalid(context.config.title, `\u043E\u043F\u0435\u0440\u0430\u0446\u0438\u0438 ${call.section}.${call.name} \u043D\u0435 \u0445\u0432\u0430\u0442\u0430\u0435\u0442 \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0439: ${[...new Set(names)].join(", ")}.`);
3959
+ }
3960
+ const url = new URL(context.base.base + path);
3961
+ const base = context.base.path;
3962
+ if (url.origin !== context.base.origin || base !== "" && url.pathname !== base && !url.pathname.startsWith(`${base}/`)) {
3963
+ throw invalid(context.config.title, `\u0430\u0434\u0440\u0435\u0441 \u043E\u043F\u0435\u0440\u0430\u0446\u0438\u0438 ${call.section}.${call.name} \u0443\u0445\u043E\u0434\u0438\u0442 \u0437\u0430 \u0430\u0434\u0440\u0435\u0441 API ${context.base.base}: \u0437\u0430\u043F\u0440\u043E\u0441 \u043D\u0435 \u043E\u0442\u043F\u0440\u0430\u0432\u043B\u0435\u043D.`);
3964
+ }
3965
+ return url;
3966
+ }
3967
+ function bodyOf(context, inputs, value) {
3968
+ if (typeof value === "string") {
3969
+ const whole = wholePlaceholder(value);
3970
+ if (whole !== void 0) return valueOf(context, inputs, whole);
3971
+ return render(context, inputs, value, "text");
3972
+ }
3973
+ if (Array.isArray(value)) return value.map((item) => bodyOf(context, inputs, item)).filter((item) => item !== void 0);
3974
+ if (isRecord(value)) {
3975
+ const out = {};
3976
+ for (const [key, item] of Object.entries(value)) {
3977
+ const rendered = bodyOf(context, inputs, item);
3978
+ if (rendered !== void 0) out[key] = rendered;
3979
+ }
3980
+ return out;
3981
+ }
3982
+ return value;
3983
+ }
3984
+ function prepare(context, call, inputs, params) {
3985
+ const url = urlOf(context, call, inputs);
3986
+ const search = new URLSearchParams();
3987
+ for (const [name, template] of Object.entries(call.operation.query ?? {})) {
3988
+ const value = render(context, inputs, String(template), "text");
3989
+ if (value !== void 0 && value !== "") search.set(name, value);
3990
+ }
3991
+ for (const [name, value] of params) search.set(name, value);
3992
+ if (search.size > 0) url.search = search.toString();
3993
+ const body = call.operation.body === void 0 || call.operation.method === "GET" ? void 0 : bodyOf(context, inputs, call.operation.body);
3994
+ return { url: url.href, body };
3995
+ }
3996
+ async function callJson(context, call, inputs, options = {}) {
3997
+ const { params = [], ...rest } = options;
3998
+ const request = prepare(context, call, mapInputs(context.config.title, call, inputs), params);
3999
+ return requestJson(request.url, {
4000
+ fetch: context.fetch,
4001
+ origin: context.base.origin,
4002
+ method: call.operation.method,
4003
+ headers: context.headers,
4004
+ ...request.body === void 0 ? {} : { body: request.body },
4005
+ ...rest
4006
+ });
4007
+ }
4008
+ async function callText(context, call, inputs, options) {
4009
+ const request = prepare(context, call, mapInputs(context.config.title, call, inputs), []);
4010
+ const { accept: _accept, ...headers } = context.headers;
4011
+ return requestText(request.url, { fetch: context.fetch, origin: context.base.origin, headers, ...options });
4012
+ }
4013
+ var PAGE_NUMBER = /^[1-9]\d{0,8}$/;
4014
+ var CURSOR_MAX = 2e3;
4015
+ function paginationOf(context, call) {
4016
+ return call.operation.pagination ?? context.config.http.pagination;
4017
+ }
4018
+ function pageParams(title, pagination, page) {
4019
+ if (pagination.style === "page") {
4020
+ if (page.cursor !== void 0 && !PAGE_NUMBER.test(page.cursor)) throw invalid(title, "\u043A\u0443\u0440\u0441\u043E\u0440 \u0441\u0442\u0440\u0430\u043D\u0438\u0446\u044B \u2014 \u043D\u043E\u043C\u0435\u0440 \u0441\u0442\u0440\u0430\u043D\u0438\u0446\u044B, \u0446\u0435\u043B\u043E\u0435 \u0447\u0438\u0441\u043B\u043E \u043E\u0442 1.");
4021
+ const number = page.cursor === void 0 ? 1 : Number(page.cursor);
4022
+ return { params: [[pagination.page, String(number)], [pagination.size, String(page.limit)]], number };
4023
+ }
4024
+ if (pagination.style === "cursor") {
4025
+ if (page.cursor !== void 0 && (page.cursor === "" || page.cursor.length > CURSOR_MAX)) throw invalid(title, `\u043A\u0443\u0440\u0441\u043E\u0440 \u0441\u0442\u0440\u0430\u043D\u0438\u0446\u044B \u2014 \u043D\u0435\u043F\u0443\u0441\u0442\u0430\u044F \u0441\u0442\u0440\u043E\u043A\u0430 \u043D\u0435 \u0434\u043B\u0438\u043D\u043D\u0435\u0435 ${String(CURSOR_MAX)} \u0441\u0438\u043C\u0432\u043E\u043B\u043E\u0432.`);
4026
+ const params = pagination.size === void 0 ? [] : [[pagination.size, String(page.limit)]];
4027
+ if (page.cursor !== void 0) params.push([pagination.param, page.cursor]);
4028
+ return { params, number: 1 };
4029
+ }
4030
+ if (page.cursor !== void 0) throw invalid(title, "\u0443 \u0441\u043F\u0438\u0441\u043A\u0430 \u043E\u0434\u043D\u0430 \u0441\u0442\u0440\u0430\u043D\u0438\u0446\u0430: \u043A\u0443\u0440\u0441\u043E\u0440\u0430 \u043D\u0435\u0442.");
4031
+ return { params: [], number: 1 };
4032
+ }
4033
+ function hasNextLink(headers) {
4034
+ const link2 = headers.get("link");
4035
+ if (link2 === null) return false;
4036
+ for (const match of link2.replace(/<[^>]*>/g, "").matchAll(/;\s*rel\s*=\s*(?:"([^"]*)"|([^\s;,"]+))/gi)) {
4037
+ if ((match[1] ?? match[2] ?? "").toLowerCase().split(/\s+/).includes("next")) return true;
4038
+ }
4039
+ return false;
4040
+ }
4041
+ function nextCursorOf2(pagination, page, number, count, response) {
4042
+ if (pagination.style === "page") {
4043
+ const next = pagination.next;
4044
+ if (next === "link") return hasNextLink(response.headers) ? String(number + 1) : void 0;
4045
+ if (next === "count") return count >= page.limit ? String(number + 1) : void 0;
4046
+ const value = "header" in next ? response.headers.get(next.header)?.trim() : readPath(next.path, response.body);
4047
+ const text2 = typeof value === "number" ? String(value) : value;
4048
+ return typeof text2 === "string" && PAGE_NUMBER.test(text2) && Number(text2) > number ? text2 : void 0;
4049
+ }
4050
+ if (pagination.style === "cursor") {
4051
+ const value = typeof pagination.next === "string" ? readPath(pagination.next, response.body) : response.headers.get(pagination.next.header)?.trim();
4052
+ const text2 = typeof value === "number" && Number.isFinite(value) ? String(value) : value;
4053
+ return typeof text2 === "string" && text2 !== "" && text2.length <= CURSOR_MAX && text2 !== page.cursor ? text2 : void 0;
4054
+ }
4055
+ return void 0;
4056
+ }
4057
+
4058
+ // src/tracker/declarative/declarative-capabilities.lib.ts
4059
+ var issueRules = {
4060
+ status: { input: "status", needs: [], check: (item, query) => query.status?.includes(item.status.category) === true },
4061
+ labels: { input: "labels", needs: ["labels"], check: (item, query) => (query.labels ?? []).every((label) => item.labels.includes(label)) },
4062
+ assignee: { input: "assignee", needs: ["assignee"], check: (item, query) => query.assignee === null ? item.assignee === void 0 : item.assignee === query.assignee },
4063
+ author: { input: "author", needs: [] },
4064
+ search: { input: "search", needs: [], check: (item, query) => containsText([item.title, item.description], query.search ?? "") },
4065
+ createdAfter: { input: "createdAfter", needs: ["createdAt"], check: (item, query) => inTimeRange(item.createdAt, query.createdAfter, void 0) },
4066
+ createdBefore: { input: "createdBefore", needs: ["createdAt"], check: (item, query) => inTimeRange(item.createdAt, void 0, query.createdBefore) },
4067
+ updatedAfter: { input: "updatedAfter", needs: ["updatedAt"], check: (item, query) => inTimeRange(item.updatedAt, query.updatedAfter, void 0) },
4068
+ updatedBefore: { input: "updatedBefore", needs: ["updatedAt"], check: (item, query) => inTimeRange(item.updatedAt, void 0, query.updatedBefore) }
4069
+ };
4070
+ var pullRules = {
4071
+ status: { input: "status", needs: [], check: (item, query) => query.status?.includes(item.status.category) === true },
4072
+ author: { input: "author", needs: ["author"], check: (item, query) => item.author === query.author },
4073
+ source: { input: "sourceBranch", needs: [], check: (item, query) => item.source === query.source },
4074
+ target: { input: "targetBranch", needs: [], check: (item, query) => item.target === query.target },
4075
+ labels: { input: "labels", needs: ["labels"], check: (item, query) => (query.labels ?? []).every((label) => item.labels.includes(label)) },
4076
+ search: { input: "search", needs: [], check: (item, query) => containsText([item.title, item.description], query.search ?? "") },
4077
+ createdAfter: { input: "createdAfter", needs: ["createdAt"], check: (item, query) => inTimeRange(item.createdAt, query.createdAfter, void 0) },
4078
+ createdBefore: { input: "createdBefore", needs: ["createdAt"], check: (item, query) => inTimeRange(item.createdAt, void 0, query.createdBefore) },
4079
+ updatedAfter: { input: "updatedAfter", needs: ["updatedAt"], check: (item, query) => inTimeRange(item.updatedAt, query.updatedAfter, void 0) },
4080
+ updatedBefore: { input: "updatedBefore", needs: ["updatedAt"], check: (item, query) => inTimeRange(item.updatedAt, void 0, query.updatedBefore) }
4081
+ };
4082
+ var runRules = {
4083
+ status: { input: "status", needs: [], check: (item, query) => query.status?.includes(item.status.category) === true },
4084
+ ref: { input: "ref", needs: ["ref"], check: (item, query) => item.ref === query.ref },
4085
+ sha: { input: "sha", needs: ["sha"], check: (item, query) => item.sha !== void 0 && item.sha.startsWith((query.sha ?? "").toLowerCase()) },
4086
+ event: { input: "event", needs: ["event.category"], check: (item, query) => item.event !== void 0 && query.event?.includes(item.event.category) === true },
4087
+ workflow: { input: "workflow", needs: ["workflows"], check: (item, query) => item.workflows.includes(query.workflow ?? "") },
4088
+ actor: { input: "actor", needs: ["actor"], check: (item, query) => item.actor === query.actor },
4089
+ pullRequest: { input: "pullRequest", needs: ["pullRequest"], check: (item, query) => item.pullRequest === query.pullRequest },
4090
+ createdAfter: { input: "createdAfter", needs: ["createdAt"], check: (item, query) => inTimeRange(item.createdAt, query.createdAfter, void 0) },
4091
+ createdBefore: { input: "createdBefore", needs: ["createdAt"], check: (item, query) => inTimeRange(item.createdAt, void 0, query.createdBefore) },
4092
+ updatedAfter: { input: "updatedAfter", needs: ["updatedAt"], check: (item, query) => inTimeRange(item.updatedAt, query.updatedAfter, void 0) },
4093
+ updatedBefore: { input: "updatedBefore", needs: ["updatedAt"], check: (item, query) => inTimeRange(item.updatedAt, void 0, query.updatedBefore) }
4094
+ };
4095
+ var jobRules = {
4096
+ status: { input: "status", needs: [], check: (item, query) => query.status?.includes(item.status.category) === true },
4097
+ allAttempts: { input: "allAttempts", needs: [] }
4098
+ };
4099
+ function uses(operation2, input) {
4100
+ return usedNames(operation2).has(input);
4101
+ }
4102
+ function tableOf(operation2, input) {
4103
+ return operation2?.inputs?.[input];
4104
+ }
4105
+ function keysWithin(operation2, input, domain) {
4106
+ const table = tableOf(operation2, input);
4107
+ return table === void 0 ? [...domain] : domain.filter((value) => Object.hasOwn(table, value));
4108
+ }
4109
+ function listOf(operation2, rules, sorts) {
4110
+ if (operation2 === void 0) return { filters: [], clientSide: [], sorts: [] };
4111
+ const used = usedNames(operation2);
4112
+ const result = operation2.result ?? {};
4113
+ const filters = [];
4114
+ const clientSide = [];
4115
+ for (const [name, rule] of Object.entries(rules)) {
4116
+ const server = used.has(rule.input);
4117
+ const checkable = rule.check !== void 0 && rule.needs.every((field) => result[field] !== void 0);
4118
+ if (!server && !checkable) continue;
4119
+ filters.push(name);
4120
+ if (checkable && (!server || tableOf(operation2, rule.input) !== void 0)) clientSide.push(name);
4121
+ }
4122
+ return { filters, clientSide, sorts: used.has("sort") ? keysWithin(operation2, "sort", sorts) : [] };
4123
+ }
4124
+ function pageCheck(rules, capabilities, query) {
4125
+ const names = usedFilters(query, Object.keys(rules)).filter((name) => capabilities.clientSide.includes(name));
4126
+ return (item) => names.every((name) => rules[name].check?.(item, query) !== false);
4127
+ }
4128
+ function commentsOf(operation2) {
4129
+ if (operation2 === void 0) return { filters: [], clientSide: [], order: ["asc"] };
4130
+ const order = uses(operation2, "order") ? keysWithin(operation2, "order", ["asc", "desc"]) : ["asc"];
4131
+ return { filters: uses(operation2, "updatedAfter") ? ["updatedAfter"] : [], clientSide: [], order };
4132
+ }
4133
+ function issueCapabilitiesFrom(config) {
4134
+ return { list: listOf(config.issues?.list, issueRules, ISSUE_SORT_FIELDS), comments: commentsOf(config.issues?.comments) };
4135
+ }
4136
+ function featuresFrom(config) {
4137
+ const issues = config.issues;
4138
+ const touches = (input) => uses(issues?.create, input) || uses(issues?.update, input);
4139
+ return {
4140
+ create: issues?.create !== void 0,
4141
+ update: issues?.update !== void 0,
4142
+ comment: issues?.comment !== void 0,
4143
+ priority: touches("priority"),
4144
+ labels: touches("labels"),
4145
+ assignee: touches("assignee"),
4146
+ statuses: uses(issues?.update, "status") ? keysWithin(issues?.update, "status", ["open", "in_progress", "done", "declined"]) : []
4147
+ };
4148
+ }
4149
+ function pullCapabilitiesFrom(config) {
4150
+ const pulls = config.pulls;
4151
+ if (pulls === void 0) return void 0;
4152
+ const merge = pulls.merge === void 0 ? [] : uses(pulls.merge, "method") ? keysWithin(pulls.merge, "method", mergeMethodSchema.options) : ["merge"];
4153
+ return {
4154
+ list: listOf(pulls.list, pullRules, pullRequestSortFieldSchema.options),
4155
+ comments: commentsOf(pulls.comments),
4156
+ create: pulls.create !== void 0,
4157
+ createDraft: uses(pulls.create, "draft"),
4158
+ update: ["title", "description", "target"].filter((field) => uses(pulls.update, field === "target" ? "targetBranch" : field)),
4159
+ statuses: uses(pulls.update, "status") ? keysWithin(pulls.update, "status", ["draft", "open", "closed"]) : [],
4160
+ comment: pulls.comment !== void 0,
4161
+ merge,
4162
+ deleteSourceOnMerge: uses(pulls.merge, "deleteSource")
4163
+ };
4164
+ }
4165
+ function ciCapabilitiesFrom(config) {
4166
+ const ci = config.ci;
4167
+ if (ci === void 0) return void 0;
4168
+ const reruns = [ci.rerun, ci.rerunFailed, ci.rerunJob];
4169
+ const tags = uses(ci.trigger, "refType") && keysWithin(ci.trigger, "refType", ["branch", "tag"]).includes("tag");
4170
+ return {
4171
+ workflows: ci.workflows !== void 0,
4172
+ runs: listOf(ci.runs, runRules, ciRunSortFieldSchema.options),
4173
+ jobs: listOf(ci.jobs, jobRules, []),
4174
+ log: { live: ci.log !== void 0, cursor: ci.log !== void 0 },
4175
+ trigger: {
4176
+ supported: ci.trigger !== void 0,
4177
+ workflows: uses(ci.trigger, "workflows") ? "many" : uses(ci.trigger, "workflow") ? "one" : "none",
4178
+ inputs: uses(ci.trigger, "inputs"),
4179
+ tags
4180
+ },
4181
+ rerun: { all: ci.rerun !== void 0, failedOnly: ci.rerunFailed !== void 0, job: ci.rerunJob !== void 0, debug: reruns.some((operation2) => uses(operation2, "debug")) },
4182
+ cancel: { run: ci.cancel !== void 0, job: ci.cancelJob !== void 0 }
4183
+ };
4184
+ }
4185
+ function issueFilter(capabilities, query) {
4186
+ return pageCheck(issueRules, capabilities.list, query);
4187
+ }
4188
+ function pullFilter(capabilities, query) {
4189
+ return pageCheck(pullRules, capabilities.list, query);
4190
+ }
4191
+ function runFilter(capabilities, query) {
4192
+ return pageCheck(runRules, capabilities.runs, query);
4193
+ }
4194
+ function jobFilter(capabilities, query) {
4195
+ return pageCheck(jobRules, capabilities.jobs, query);
4196
+ }
4197
+
4198
+ // src/tracker/declarative/declarative-call.lib.ts
4199
+ function contextOf(config, { connection, fetch }) {
4200
+ for (const field of config.fields) {
4201
+ if (field.required && field.name !== "token" && (connection[field.name] === void 0 || connection[field.name] === "")) {
4202
+ throw new TrackerError("invalid_request", `\u0422\u0440\u0435\u043A\u0435\u0440 \xAB${config.title}\xBB: \u043D\u0435 \u0437\u0430\u0434\u0430\u043D\u043E \u043F\u043E\u043B\u0435 ${field.name} \u043F\u043E\u0434\u043A\u043B\u044E\u0447\u0435\u043D\u0438\u044F.`);
4203
+ }
4204
+ }
4205
+ const values = { url: connection.url, target: connection.target, user: connection.user };
4206
+ return { config, connection: values, base: baseOf(config, values), fetch, headers: headersOf(config, { ...values, token: connection.token }) };
4207
+ }
4208
+ function callOf(config, section, name) {
4209
+ const operations = config[section];
4210
+ const operation2 = operations?.[name];
4211
+ const spec = OPERATIONS[section][name];
4212
+ return operation2 === void 0 || spec === void 0 ? void 0 : { section, name, operation: operation2, spec };
4213
+ }
4214
+ function requireCall(config, section, name, what) {
4215
+ const call = callOf(config, section, name);
4216
+ if (call === void 0) throw new TrackerError("unsupported", `\u0422\u0440\u0435\u043A\u0435\u0440 \xAB${config.title}\xBB \u043D\u0435 \u0443\u043C\u0435\u0435\u0442 ${what}: \u0432 \u043A\u043E\u043D\u0444\u0438\u0433\u0435 \u043D\u0435\u0442 \u043E\u043F\u0435\u0440\u0430\u0446\u0438\u0438 ${section}.${name}.`);
4217
+ return call;
4218
+ }
4219
+ function assertUsed(subject, call, inputs) {
4220
+ const used = usedNames(call.operation);
4221
+ for (const [name, value] of Object.entries(inputs)) {
4222
+ if (value === void 0 || value === false || Array.isArray(value) && value.length === 0 || used.has(name)) continue;
4223
+ throw new TrackerError("unsupported", `${subject}: \u043F\u043E\u043B\u0435 ${name} \u043D\u0435 \u043F\u043E\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442\u0441\u044F \u2014 \u0435\u0433\u043E \u043D\u0435\u0442 \u0432 \u043E\u043F\u0435\u0440\u0430\u0446\u0438\u0438 ${call.section}.${call.name} \u043A\u043E\u043D\u0444\u0438\u0433\u0430.`);
4224
+ }
4225
+ }
4226
+ function isoOf(value) {
4227
+ return value === void 0 ? void 0 : isoTime(value);
4228
+ }
4229
+ function sortInputs(sort) {
4230
+ return sort === void 0 ? {} : { sort: sort.field, direction: sort.direction ?? "desc" };
4231
+ }
4232
+ async function single(context, call, inputs, options = {}, defaults = {}) {
4233
+ const { body } = await callJson(context, call, inputs, options);
4234
+ const element = call.operation.items === void 0 ? body : readPath(call.operation.items, body);
4235
+ if (element === void 0 || element === null) throw answerFailed(context.config.title, call, "\u0432 \u043E\u0442\u0432\u0435\u0442\u0435 \u043D\u0435\u0442 \u044D\u043B\u0435\u043C\u0435\u043D\u0442\u0430");
4236
+ return buildItem(context.config.title, call, element, defaults);
4237
+ }
4238
+ async function list(context, call, inputs, page, options = {}, defaults = {}) {
4239
+ const pagination = paginationOf(context, call);
4240
+ const { params, number } = pageParams(context.config.title, pagination, page);
4241
+ const response = await callJson(context, call, inputs, { ...options, params });
4242
+ const elements = call.operation.items === void 0 ? response.body : readPath(call.operation.items, response.body);
4243
+ if (!Array.isArray(elements)) throw answerFailed(context.config.title, call, `\u043E\u0436\u0438\u0434\u0430\u043B\u0441\u044F \u0441\u043F\u0438\u0441\u043E\u043A \u044D\u043B\u0435\u043C\u0435\u043D\u0442\u043E\u0432${call.operation.items === void 0 ? "" : ` \u043F\u043E \u043F\u0443\u0442\u0438 ${call.operation.items}`}`);
4244
+ const items = elements.slice(0, page.limit).map((element) => buildItem(context.config.title, call, element, defaults));
4245
+ const next = nextCursorOf2(pagination, page, number, elements.length, response);
4246
+ return { items, ...next === void 0 ? {} : { nextCursor: next } };
4247
+ }
4248
+
4249
+ // src/tracker/declarative/declarative-ci.lib.ts
4250
+ var ACTION_CONFLICT = [409, 422];
4251
+ function createCiAdapter(config, adapterContext, capabilities) {
4252
+ const context = contextOf(config, adapterContext);
4253
+ const subject = `CI \xAB${config.title}\xBB`;
4254
+ const missingRun = (key) => ({ missing: { failure: "not_found", message: `\u0412 \u0442\u0440\u0435\u043A\u0435\u0440\u0435 \xAB${config.title}\xBB \u043D\u0435\u0442 \u043F\u0440\u043E\u0433\u043E\u043D\u0430 ${key}.` } });
4255
+ const missingJob = (key) => ({ missing: { failure: "not_found", message: `\u0412 \u0442\u0440\u0435\u043A\u0435\u0440\u0435 \xAB${config.title}\xBB \u043D\u0435\u0442 \u0437\u0430\u0434\u0430\u043D\u0438\u044F ${key}.` } });
4256
+ const getRun = (key) => single(context, requireCall(config, "ci", "run", "\u043F\u043E\u043A\u0430\u0437\u044B\u0432\u0430\u0442\u044C \u043F\u0440\u043E\u0433\u043E\u043D\u044B"), { key }, missingRun(key));
4257
+ const getJob = (key) => single(context, requireCall(config, "ci", "job", "\u043F\u043E\u043A\u0430\u0437\u044B\u0432\u0430\u0442\u044C \u0437\u0430\u0434\u0430\u043D\u0438\u044F"), { key }, missingJob(key));
4258
+ const debugOf = (name, debug) => {
4259
+ if (debug === true) assertUsed(subject, requireCall(config, "ci", name, "\u043F\u0435\u0440\u0435\u0437\u0430\u043F\u0443\u0441\u043A\u0430\u0442\u044C"), { debug });
4260
+ };
4261
+ return {
4262
+ listWorkflows: async (query) => {
4263
+ const call = requireCall(config, "ci", "workflows", "\u043F\u043E\u043A\u0430\u0437\u044B\u0432\u0430\u0442\u044C workflow");
4264
+ assertListQuery(subject, { filters: [], clientSide: [], sorts: [] }, query, []);
4265
+ return list(context, call, {}, query);
4266
+ },
4267
+ listRuns: async (query) => {
4268
+ const call = requireCall(config, "ci", "runs", "\u043F\u043E\u043A\u0430\u0437\u044B\u0432\u0430\u0442\u044C \u043F\u0440\u043E\u0433\u043E\u043D\u044B");
4269
+ assertListQuery(`\u041F\u0440\u043E\u0433\u043E\u043D\u044B ${subject}`, capabilities.runs, query, ciRunFilterSchema.options);
4270
+ const page = await list(
4271
+ context,
4272
+ call,
4273
+ {
4274
+ status: query.status,
4275
+ ref: query.ref,
4276
+ sha: query.sha,
4277
+ event: query.event,
4278
+ workflow: query.workflow,
4279
+ actor: query.actor,
4280
+ pullRequest: query.pullRequest,
4281
+ createdAfter: isoOf(query.createdAfter),
4282
+ createdBefore: isoOf(query.createdBefore),
4283
+ updatedAfter: isoOf(query.updatedAfter),
4284
+ updatedBefore: isoOf(query.updatedBefore),
4285
+ ...sortInputs(query.sort)
4286
+ },
4287
+ query
4288
+ );
4289
+ return { ...page, items: page.items.filter(runFilter(capabilities, query)) };
4290
+ },
4291
+ getRun,
4292
+ listJobs: async (runKey, query) => {
4293
+ const call = requireCall(config, "ci", "jobs", "\u043F\u043E\u043A\u0430\u0437\u044B\u0432\u0430\u0442\u044C \u0437\u0430\u0434\u0430\u043D\u0438\u044F");
4294
+ const { allAttempts, ...rest } = query;
4295
+ if (allAttempts === true && !capabilities.jobs.filters.includes("allAttempts")) throw new TrackerError("unsupported", `\u0417\u0430\u0434\u0430\u043D\u0438\u044F ${subject}: \u0444\u0438\u043B\u044C\u0442\u0440 allAttempts \u043D\u0435 \u043F\u043E\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442\u0441\u044F.`);
4296
+ assertListQuery(`\u0417\u0430\u0434\u0430\u043D\u0438\u044F ${subject}`, capabilities.jobs, rest, ciJobFilterSchema.options);
4297
+ const page = await list(context, call, { run: runKey, status: query.status, allAttempts }, query, missingRun(runKey), { runKey });
4298
+ return { ...page, items: page.items.filter(jobFilter(capabilities, query)) };
4299
+ },
4300
+ getJob,
4301
+ log: async (key, query) => {
4302
+ const call = requireCall(config, "ci", "log", "\u043F\u043E\u043A\u0430\u0437\u044B\u0432\u0430\u0442\u044C \u043B\u043E\u0433");
4303
+ const window = logWindow(query);
4304
+ const complete = isFinished((await getJob(key)).status.category);
4305
+ const response = await callText(context, call, { key }, { skip: window.resume?.offset ?? 0, keep: { bytes: window.bytes, from: window.from }, ...missingJob(key) });
4306
+ return logOf({
4307
+ text: response.text,
4308
+ truncated: window.from === "tail" ? response.start > 0 : !response.whole,
4309
+ complete,
4310
+ page: 0,
4311
+ end: response.end,
4312
+ more: !response.whole,
4313
+ ...response.whole ? { size: response.read } : {},
4314
+ startCut: window.from === "tail" && response.start > 0,
4315
+ raw: query.raw ?? false
4316
+ });
4317
+ },
4318
+ trigger: async (input) => {
4319
+ const call = requireCall(config, "ci", "trigger", "\u0437\u0430\u043F\u0443\u0441\u043A\u0430\u0442\u044C CI");
4320
+ if (input.ref === "") throw new TrackerError("invalid_request", `\u0417\u0430\u043F\u0443\u0441\u043A ${subject}: ref \u2014 \u043D\u0435\u043F\u0443\u0441\u0442\u043E\u0435 \u0438\u043C\u044F \u0432\u0435\u0442\u043A\u0438 \u0438\u043B\u0438 \u0442\u0435\u0433\u0430.`);
4321
+ const workflows = input.workflows ?? [];
4322
+ const mode = capabilities.trigger.workflows;
4323
+ if (mode === "none" && workflows.length > 0) throw new TrackerError("unsupported", `\u0417\u0430\u043F\u0443\u0441\u043A ${subject}: workflow \u043D\u0435 \u0437\u0430\u0434\u0430\u0451\u0442\u0441\u044F.`);
4324
+ if (mode === "one" && workflows.length !== 1) throw new TrackerError("invalid_request", `\u0417\u0430\u043F\u0443\u0441\u043A ${subject}: \u043D\u0443\u0436\u0435\u043D \u0440\u043E\u0432\u043D\u043E \u043E\u0434\u0438\u043D workflow.`);
4325
+ if (mode === "many" && workflows.length === 0) throw new TrackerError("invalid_request", `\u0417\u0430\u043F\u0443\u0441\u043A ${subject}: \u043D\u0443\u0436\u0435\u043D \u0445\u043E\u0442\u044F \u0431\u044B \u043E\u0434\u0438\u043D workflow.`);
4326
+ if (input.refType === "tag" && !capabilities.trigger.tags) throw new TrackerError("unsupported", `\u0417\u0430\u043F\u0443\u0441\u043A ${subject}: \u0437\u0430\u043F\u0443\u0441\u043A \u043D\u0430 \u0442\u0435\u0433\u0435 \u043D\u0435 \u043F\u043E\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442\u0441\u044F.`);
4327
+ const parameters = input.inputs !== void 0 && Object.keys(input.inputs).length > 0 ? input.inputs : void 0;
4328
+ if (parameters !== void 0 && !capabilities.trigger.inputs) throw new TrackerError("unsupported", `\u0417\u0430\u043F\u0443\u0441\u043A ${subject}: \u043F\u0430\u0440\u0430\u043C\u0435\u0442\u0440\u044B \u0437\u0430\u043F\u0443\u0441\u043A\u0430 \u043D\u0435 \u043F\u043E\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u044E\u0442\u0441\u044F.`);
4329
+ const inputs = {
4330
+ ref: input.ref,
4331
+ refType: capabilities.trigger.tags ? input.refType ?? "branch" : void 0,
4332
+ workflow: mode === "one" ? workflows[0] : void 0,
4333
+ workflows: mode === "many" ? workflows : void 0,
4334
+ inputs: parameters
4335
+ };
4336
+ if (call.operation.result === void 0) {
4337
+ await callJson(context, call, inputs);
4338
+ return {};
4339
+ }
4340
+ return { run: await single(context, call, inputs) };
4341
+ },
4342
+ rerun: async (key, input) => {
4343
+ const name = input.failedOnly === true ? "rerunFailed" : "rerun";
4344
+ const call = requireCall(config, "ci", name, input.failedOnly === true ? "\u043F\u0435\u0440\u0435\u0437\u0430\u043F\u0443\u0441\u043A\u0430\u0442\u044C \u0443\u043F\u0430\u0432\u0448\u0438\u0435 \u0437\u0430\u0434\u0430\u043D\u0438\u044F" : "\u043F\u0435\u0440\u0435\u0437\u0430\u043F\u0443\u0441\u043A\u0430\u0442\u044C \u043F\u0440\u043E\u0433\u043E\u043D \u0446\u0435\u043B\u0438\u043A\u043E\u043C");
4345
+ debugOf(name, input.debug);
4346
+ await callJson(context, call, { key, debug: input.debug }, { ...missingRun(key), conflictOn: ACTION_CONFLICT });
4347
+ return getRun(key);
4348
+ },
4349
+ rerunJob: async (key, input) => {
4350
+ const call = requireCall(config, "ci", "rerunJob", "\u043F\u0435\u0440\u0435\u0437\u0430\u043F\u0443\u0441\u043A\u0430\u0442\u044C \u0437\u0430\u0434\u0430\u043D\u0438\u0435");
4351
+ debugOf("rerunJob", input.debug);
4352
+ await callJson(context, call, { key, debug: input.debug }, { ...missingJob(key), conflictOn: ACTION_CONFLICT });
4353
+ return getRun((await getJob(key)).runKey);
4354
+ },
4355
+ cancel: async (key) => {
4356
+ await callJson(context, requireCall(config, "ci", "cancel", "\u043E\u0442\u043C\u0435\u043D\u044F\u0442\u044C \u043F\u0440\u043E\u0433\u043E\u043D"), { key }, { ...missingRun(key), conflictOn: ACTION_CONFLICT });
4357
+ return getRun(key);
4358
+ },
4359
+ cancelJob: async (key) => {
4360
+ await callJson(context, requireCall(config, "ci", "cancelJob", "\u043E\u0442\u043C\u0435\u043D\u044F\u0442\u044C \u0437\u0430\u0434\u0430\u043D\u0438\u0435"), { key }, { ...missingJob(key), conflictOn: ACTION_CONFLICT });
4361
+ return getJob(key);
4362
+ }
4363
+ };
4364
+ }
4365
+
4366
+ // src/tracker/declarative/declarative-issues.lib.ts
4367
+ var MISSING = { missingIsIssue: true };
4368
+ function createIssuesAdapter(config, adapterContext, capabilities, features) {
4369
+ const context = contextOf(config, adapterContext);
4370
+ const subject = `\u0417\u0430\u0434\u0430\u0447\u0438 \xAB${config.title}\xBB`;
4371
+ const comments = `\u041A\u043E\u043C\u043C\u0435\u043D\u0442\u0430\u0440\u0438\u0438 \xAB${config.title}\xBB`;
4372
+ const get = (key) => single(context, requireCall(config, "issues", "get", "\u043F\u043E\u043A\u0430\u0437\u044B\u0432\u0430\u0442\u044C \u0437\u0430\u0434\u0430\u0447\u0438"), { key }, MISSING);
4373
+ return {
4374
+ list: async (query) => {
4375
+ const call = requireCall(config, "issues", "list", "\u043F\u043E\u043A\u0430\u0437\u044B\u0432\u0430\u0442\u044C \u0437\u0430\u0434\u0430\u0447\u0438");
4376
+ assertListQuery(subject, capabilities.list, query, ISSUE_FILTERS);
4377
+ const page = await list(
4378
+ context,
4379
+ call,
4380
+ {
4381
+ status: query.status,
4382
+ labels: query.labels,
4383
+ assignee: query.assignee,
4384
+ author: query.author,
4385
+ search: query.search,
4386
+ createdAfter: isoOf(query.createdAfter),
4387
+ createdBefore: isoOf(query.createdBefore),
4388
+ updatedAfter: isoOf(query.updatedAfter),
4389
+ updatedBefore: isoOf(query.updatedBefore),
4390
+ ...sortInputs(query.sort)
4391
+ },
4392
+ query
4393
+ );
4394
+ return { ...page, items: page.items.filter(issueFilter(capabilities, query)) };
4395
+ },
4396
+ get,
4397
+ create: async (input) => {
4398
+ const call = requireCall(config, "issues", "create", "\u0441\u043E\u0437\u0434\u0430\u0432\u0430\u0442\u044C \u0437\u0430\u0434\u0430\u0447\u0438");
4399
+ const inputs = { title: input.title, description: input.description, priority: input.priority, labels: input.labels, assignee: input.assignee };
4400
+ assertUsed(subject, call, inputs);
4401
+ return single(context, call, inputs);
4402
+ },
4403
+ update: async (key, patch) => {
4404
+ const call = requireCall(config, "issues", "update", "\u043C\u0435\u043D\u044F\u0442\u044C \u0437\u0430\u0434\u0430\u0447\u0438");
4405
+ if (patch.status !== void 0 && !features.statuses.includes(patch.status)) throw new TrackerError("unsupported", `${subject}: \u043F\u0435\u0440\u0435\u0432\u043E\u0434 \u0432 ${patch.status} \u043D\u0435 \u043F\u043E\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442\u0441\u044F.`);
4406
+ const inputs = { key, title: patch.title, description: patch.description, status: patch.status, priority: patch.priority, labels: patch.labels, assignee: patch.assignee };
4407
+ assertUsed(subject, call, inputs);
4408
+ if (call.operation.result === void 0) {
4409
+ await callJson(context, call, inputs, MISSING);
4410
+ return get(key);
4411
+ }
4412
+ return single(context, call, inputs, MISSING);
4413
+ },
4414
+ comments: async (key, query) => {
4415
+ const call = requireCall(config, "issues", "comments", "\u043F\u043E\u043A\u0430\u0437\u044B\u0432\u0430\u0442\u044C \u043A\u043E\u043C\u043C\u0435\u043D\u0442\u0430\u0440\u0438\u0438");
4416
+ assertCommentQuery(comments, capabilities.comments, query);
4417
+ return list(context, call, { key, updatedAfter: isoOf(query.updatedAfter), order: query.order ?? capabilities.comments.order[0] }, query, MISSING);
4418
+ },
4419
+ comment: async (key, body) => single(context, requireCall(config, "issues", "comment", "\u043A\u043E\u043C\u043C\u0435\u043D\u0442\u0438\u0440\u043E\u0432\u0430\u0442\u044C \u0437\u0430\u0434\u0430\u0447\u0438"), { key, body }, MISSING)
4420
+ };
4421
+ }
4422
+
4423
+ // src/tracker/declarative/declarative-parse.lib.ts
4424
+ import { isAlias, isMap, isPair, isScalar, isSeq, LineCounter, parseDocument, Parser } from "yaml";
4425
+ function issueAt(path, message) {
4426
+ return { path: path.map(String).join("."), message };
4427
+ }
4428
+ function looksSecret(text2) {
4429
+ return redactSecretText(text2) !== text2;
4430
+ }
4431
+ function literalOf(value) {
4432
+ return value.replace(new RegExp(PLACEHOLDER.source, "g"), "").trim();
4433
+ }
4434
+ function secretPair(key, value) {
4435
+ return typeof value === "string" && isSecretKey(key) && literalOf(value) !== "";
4436
+ }
4437
+ function scanNode(node, path, issues) {
4438
+ if (isAlias(node)) return;
4439
+ if (isScalar(node)) {
4440
+ if (typeof node.value === "string" && looksSecret(node.value)) issues.push(issueAt(path, SECRET_IN_CONFIG));
4441
+ return;
4442
+ }
4443
+ if (isSeq(node)) {
4444
+ node.items.forEach((item, index) => scanNode(item, [...path, index], issues));
4445
+ return;
4446
+ }
4447
+ if (!isMap(node)) return;
4448
+ for (const pair of node.items) {
4449
+ if (!isPair(pair)) continue;
4450
+ const key = isScalar(pair.key) ? String(pair.key.value) : "";
4451
+ const at = [...path, key];
4452
+ if (looksSecret(key) || isScalar(pair.value) && secretPair(key, pair.value.value)) {
4453
+ issues.push(issueAt(at, SECRET_IN_CONFIG));
4454
+ continue;
4455
+ }
4456
+ scanNode(pair.value, at, issues);
4457
+ }
4458
+ }
4459
+ function scanComments(text2, lines, issues) {
4460
+ const visit = (value, depth) => {
4461
+ if (depth > 200 || typeof value !== "object" || value === null) return;
4462
+ if (Array.isArray(value)) {
4463
+ for (const item of value) visit(item, depth + 1);
4464
+ return;
4465
+ }
4466
+ const token = value;
4467
+ if (token.type === "comment" && typeof token.source === "string" && typeof token.offset === "number") {
4468
+ if (looksSecret(token.source)) issues.push({ path: "", message: `\u0441\u0442\u0440\u043E\u043A\u0430 ${String(lines.linePos(token.offset).line)}, \u043A\u043E\u043C\u043C\u0435\u043D\u0442\u0430\u0440\u0438\u0439: ${SECRET_IN_CONFIG}` });
4469
+ return;
4470
+ }
4471
+ for (const item of Object.values(value)) visit(item, depth + 1);
4472
+ };
4473
+ for (const token of new Parser().parse(text2)) visit(token, 0);
4474
+ }
4475
+ function scanValue(value, path, issues, depth) {
4476
+ if (depth > TRACKER_CONFIG_DEPTH_MAX) return;
4477
+ if (typeof value === "string") {
4478
+ if (looksSecret(value)) issues.push(issueAt(path, SECRET_IN_CONFIG));
4479
+ return;
4480
+ }
4481
+ if (Array.isArray(value)) {
4482
+ value.forEach((item, index) => scanValue(item, [...path, index], issues, depth + 1));
4483
+ return;
4484
+ }
4485
+ if (typeof value !== "object" || value === null) return;
4486
+ for (const [key, item] of Object.entries(value)) {
4487
+ const at = [...path, key];
4488
+ if (looksSecret(key) || secretPair(key, item)) {
4489
+ issues.push(issueAt(at, SECRET_IN_CONFIG));
4490
+ continue;
4491
+ }
4492
+ scanValue(item, at, issues, depth + 1);
4493
+ }
4494
+ }
4495
+ function scanShape(value, path, issues, depth, seen = /* @__PURE__ */ new WeakMap()) {
4496
+ if (typeof value !== "object" || value === null || issues.length >= TRACKER_CONFIG_ISSUES_MAX) return;
4497
+ if (depth > TRACKER_CONFIG_DEPTH_MAX) {
4498
+ issues.push(issueAt(path, `\u0432\u043B\u043E\u0436\u0435\u043D\u043D\u043E\u0441\u0442\u044C \u0431\u043E\u043B\u044C\u0448\u0435 ${String(TRACKER_CONFIG_DEPTH_MAX)} \u0443\u0440\u043E\u0432\u043D\u0435\u0439`));
4499
+ return;
4500
+ }
4501
+ const before = seen.get(value);
4502
+ if (before !== void 0 && before <= depth) return;
4503
+ seen.set(value, depth);
4504
+ if (Array.isArray(value)) {
4505
+ value.forEach((item, index) => scanShape(item, [...path, index], issues, depth + 1, seen));
4506
+ return;
4507
+ }
4508
+ for (const [key, item] of Object.entries(value)) {
4509
+ if (issues.length >= TRACKER_CONFIG_ISSUES_MAX) return;
4510
+ if (FORBIDDEN_KEYS.includes(key)) {
4511
+ issues.push(issueAt([...path, key], `\u0438\u043C\u044F \xAB${key}\xBB \u0432 \u043A\u043E\u043D\u0444\u0438\u0433\u0435 \u043D\u0435\u0434\u043E\u043F\u0443\u0441\u0442\u0438\u043C\u043E`));
4512
+ continue;
4513
+ }
4514
+ scanShape(item, [...path, key], issues, depth + 1, seen);
4515
+ }
4516
+ }
4517
+ function tooLarge(bytes) {
4518
+ return { path: "", message: `\u043A\u043E\u043D\u0444\u0438\u0433 ${String(bytes)} \u0431\u0430\u0439\u0442 \u0431\u043E\u043B\u044C\u0448\u0435 \u043F\u0440\u0435\u0434\u0435\u043B\u0430 ${String(TRACKER_CONFIG_MAX_BYTES)} \u0431\u0430\u0439\u0442` };
4519
+ }
4520
+ function parseText(text2) {
4521
+ const bytes = Buffer.byteLength(text2, "utf8");
4522
+ if (bytes > TRACKER_CONFIG_MAX_BYTES) return { issues: [tooLarge(bytes)], secret: false };
4523
+ const lines = new LineCounter();
4524
+ const document = parseDocument(text2, { lineCounter: lines, uniqueKeys: true, prettyErrors: false, strict: true });
4525
+ const secrets = [];
4526
+ scanComments(text2, lines, secrets);
4527
+ scanNode(document.contents, [], secrets);
4528
+ if (document.errors.length > 0) {
4529
+ const errors = document.errors.map((error) => ({ path: "", message: `\u0441\u0442\u0440\u043E\u043A\u0430 ${String(lines.linePos(error.pos[0]).line)}: ${error.message.split("\n")[0] ?? ""}` }));
4530
+ return { issues: [...secrets, ...errors], secret: secrets.length > 0 };
4531
+ }
4532
+ let data;
4533
+ try {
4534
+ data = document.toJS({ maxAliasCount: TRACKER_CONFIG_YAML_ALIAS_MAX });
4535
+ } catch (error) {
4536
+ return { issues: [...secrets, { path: "", message: `YAML \u043D\u0435 \u0440\u0430\u0437\u043E\u0431\u0440\u0430\u043B\u0441\u044F: ${error instanceof Error ? error.message : String(error)}` }], secret: secrets.length > 0 };
4537
+ }
4538
+ const shape = [];
4539
+ scanShape(data, [], shape, 0);
4540
+ return { ...shape.length === 0 ? { data } : {}, issues: [...secrets, ...shape], secret: secrets.length > 0 };
4541
+ }
4542
+ function parseObject(value) {
4543
+ let json;
4544
+ try {
4545
+ json = JSON.stringify(value);
4546
+ } catch (error) {
4547
+ return { issues: [{ path: "", message: `\u043A\u043E\u043D\u0444\u0438\u0433 \u2014 \u043D\u0435 JSON: ${error instanceof Error ? error.message : String(error)}` }], secret: false };
4548
+ }
4549
+ if (json === void 0) return { issues: [{ path: "", message: "\u043A\u043E\u043D\u0444\u0438\u0433 \u2014 \u043D\u0435 JSON: \u043E\u0431\u044A\u0435\u043A\u0442 \u043D\u0435 \u0441\u0435\u0440\u0438\u0430\u043B\u0438\u0437\u0443\u0435\u0442\u0441\u044F" }], secret: false };
4550
+ const bytes = Buffer.byteLength(json, "utf8");
4551
+ if (bytes > TRACKER_CONFIG_MAX_BYTES) return { issues: [tooLarge(bytes)], secret: false };
4552
+ const data = JSON.parse(json);
4553
+ const shape = [];
4554
+ scanShape(data, [], shape, 0);
4555
+ if (shape.length > 0) return { issues: shape, secret: false };
4556
+ const secrets = [];
4557
+ scanValue(data, [], secrets, 0);
4558
+ return { data, issues: secrets, secret: secrets.length > 0 };
4559
+ }
4560
+ function parseConfigInput(input) {
4561
+ if (typeof input === "string") return parseText(input);
4562
+ if (typeof input === "object" && input !== null && !Array.isArray(input)) return parseObject(input);
4563
+ return { issues: [{ path: "", message: "\u043A\u043E\u043D\u0444\u0438\u0433 \u2014 \u0442\u0435\u043A\u0441\u0442 YAML \u0438\u043B\u0438 \u043E\u0431\u044A\u0435\u043A\u0442" }], secret: false };
4564
+ }
4565
+
4566
+ // src/tracker/declarative/declarative-pull.lib.ts
4567
+ var MERGE_CONFLICT = [405, 409, 422];
4568
+ function createPullAdapter2(config, adapterContext, capabilities) {
4569
+ const context = contextOf(config, adapterContext);
4570
+ const subject = `PR \xAB${config.title}\xBB`;
4571
+ const missing = (key) => ({ missing: { failure: "not_found", message: `\u0412 \u0442\u0440\u0435\u043A\u0435\u0440\u0435 \xAB${config.title}\xBB \u043D\u0435\u0442 PR ${key}.` } });
4572
+ const get = (key) => single(context, requireCall(config, "pulls", "get", "\u043F\u043E\u043A\u0430\u0437\u044B\u0432\u0430\u0442\u044C PR"), { key }, missing(key));
4573
+ return {
4574
+ list: async (query) => {
4575
+ const call = requireCall(config, "pulls", "list", "\u043F\u043E\u043A\u0430\u0437\u044B\u0432\u0430\u0442\u044C PR");
4576
+ assertListQuery(subject, capabilities.list, query, pullRequestFilterSchema.options);
4577
+ const page = await list(
4578
+ context,
4579
+ call,
4580
+ {
4581
+ status: query.status,
4582
+ author: query.author,
4583
+ sourceBranch: query.source,
4584
+ targetBranch: query.target,
4585
+ labels: query.labels,
4586
+ search: query.search,
4587
+ createdAfter: isoOf(query.createdAfter),
4588
+ createdBefore: isoOf(query.createdBefore),
4589
+ updatedAfter: isoOf(query.updatedAfter),
4590
+ updatedBefore: isoOf(query.updatedBefore),
4591
+ ...sortInputs(query.sort)
4592
+ },
4593
+ query
4594
+ );
4595
+ return { ...page, items: page.items.filter(pullFilter(capabilities, query)) };
4596
+ },
4597
+ get,
4598
+ create: async (input) => {
4599
+ const call = requireCall(config, "pulls", "create", "\u0441\u043E\u0437\u0434\u0430\u0432\u0430\u0442\u044C PR");
4600
+ const inputs = { title: input.title, sourceBranch: input.source, targetBranch: input.target, description: input.description, draft: input.draft };
4601
+ assertUsed(subject, call, inputs);
4602
+ return single(context, call, inputs);
4603
+ },
4604
+ update: async (key, patch) => {
4605
+ const call = requireCall(config, "pulls", "update", "\u043C\u0435\u043D\u044F\u0442\u044C PR");
4606
+ if (patch.status !== void 0 && !capabilities.statuses.includes(patch.status)) throw new TrackerError("unsupported", `${subject}: \u043F\u0435\u0440\u0435\u0432\u043E\u0434 \u0432 ${patch.status} \u043D\u0435 \u043F\u043E\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442\u0441\u044F.`);
4607
+ const inputs = { key, title: patch.title, description: patch.description, targetBranch: patch.target, status: patch.status };
4608
+ assertUsed(subject, call, inputs);
4609
+ if (call.operation.result === void 0) {
4610
+ await callJson(context, call, inputs, missing(key));
4611
+ return get(key);
4612
+ }
4613
+ return single(context, call, inputs, missing(key));
4614
+ },
4615
+ merge: async (key, input) => {
4616
+ const call = requireCall(config, "pulls", "merge", "\u0441\u043B\u0438\u0432\u0430\u0442\u044C PR");
4617
+ const used = usedNames(call.operation);
4618
+ const method = input.method ?? capabilities.merge[0];
4619
+ if (method === void 0 || !capabilities.merge.includes(method)) throw new TrackerError("unsupported", `${subject}: \u0441\u043B\u0438\u044F\u043D\u0438\u0435 \u0441\u043F\u043E\u0441\u043E\u0431\u043E\u043C ${String(method)} \u043D\u0435 \u043F\u043E\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442\u0441\u044F.`);
4620
+ if (input.deleteSource === true && !capabilities.deleteSourceOnMerge) throw new TrackerError("unsupported", `${subject}: \u0443\u0434\u0430\u043B\u0435\u043D\u0438\u0435 \u0432\u0435\u0442\u043A\u0438-\u0438\u0441\u0442\u043E\u0447\u043D\u0438\u043A\u0430 \u043F\u0440\u0438 \u0441\u043B\u0438\u044F\u043D\u0438\u0438 \u043D\u0435 \u043F\u043E\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442\u0441\u044F.`);
4621
+ if (input.message !== void 0 && !used.has("message")) throw new TrackerError("unsupported", `${subject}: \u0441\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u0435 \u043A\u043E\u043C\u043C\u0438\u0442\u0430 \u0441\u043B\u0438\u044F\u043D\u0438\u044F \u043D\u0435 \u043F\u043E\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442\u0441\u044F.`);
4622
+ if (input.headSha !== void 0 && !used.has("headSha")) {
4623
+ const current = await get(key);
4624
+ if (current.headSha === void 0) throw new TrackerError("unsupported", `${subject}: \u0441\u0432\u0435\u0440\u043A\u0430 \u0433\u043E\u043B\u043E\u0432\u044B \u0438\u0441\u0442\u043E\u0447\u043D\u0438\u043A\u0430 \u043D\u0435\u0434\u043E\u0441\u0442\u0443\u043F\u043D\u0430 \u2014 \u0432 \u043E\u0442\u0432\u0435\u0442\u0435 PR \u043D\u0435\u0442 headSha.`);
4625
+ if (current.headSha !== input.headSha.toLowerCase()) throw new TrackerError("conflict", `${subject}: \u0433\u043E\u043B\u043E\u0432\u0430 \u0438\u0441\u0442\u043E\u0447\u043D\u0438\u043A\u0430 ${current.headSha} \u043D\u0435 \u0441\u043E\u0432\u043F\u0430\u043B\u0430 \u0441 ${input.headSha}.`);
4626
+ }
4627
+ const inputs = { key, method, headSha: used.has("headSha") ? input.headSha : void 0, message: input.message, deleteSource: input.deleteSource };
4628
+ await callJson(context, call, inputs, { ...missing(key), conflictOn: MERGE_CONFLICT });
4629
+ return get(key);
4630
+ },
4631
+ comments: async (key, query) => {
4632
+ const call = requireCall(config, "pulls", "comments", "\u043F\u043E\u043A\u0430\u0437\u044B\u0432\u0430\u0442\u044C \u043A\u043E\u043C\u043C\u0435\u043D\u0442\u0430\u0440\u0438\u0438 PR");
4633
+ assertCommentQuery(`\u041A\u043E\u043C\u043C\u0435\u043D\u0442\u0430\u0440\u0438\u0438 PR \xAB${config.title}\xBB`, capabilities.comments, query);
4634
+ return list(context, call, { key, updatedAfter: isoOf(query.updatedAfter), order: query.order ?? capabilities.comments.order[0] }, query, missing(key));
4635
+ },
4636
+ comment: async (key, body) => single(context, requireCall(config, "pulls", "comment", "\u043A\u043E\u043C\u043C\u0435\u043D\u0442\u0438\u0440\u043E\u0432\u0430\u0442\u044C PR"), { key, body }, missing(key))
4637
+ };
4638
+ }
4639
+
4640
+ // src/tracker/declarative/declarative-rules.lib.ts
4641
+ var PATH_LITERAL = /^\/[A-Za-z0-9\-._~!$&'()*+,;=:@/]*$/;
4642
+ var SECTIONS = ["issues", "pulls", "ci"];
4643
+ function declared(config) {
4644
+ return new Set(config.fields.map((field) => field.name));
4645
+ }
4646
+ function checkTemplate(config, template, path, inputs, where, issues) {
4647
+ const fields = declared(config);
4648
+ for (const { name, modifier } of placeholdersOf(template)) {
4649
+ if (name === "token") {
4650
+ issues.push(issueAt(path, "\u043F\u043B\u0435\u0439\u0441\u0445\u043E\u043B\u0434\u0435\u0440\u0430 {{token}} \u043D\u0435\u0442: \u0442\u043E\u043A\u0435\u043D \u043F\u043E\u0434\u0441\u0442\u0430\u0432\u043B\u044F\u0435\u0442 \u0442\u043E\u043B\u044C\u043A\u043E http.auth \u0438 \u0442\u043E\u043B\u044C\u043A\u043E \u0434\u043B\u044F origin http.base"));
4651
+ continue;
4652
+ }
4653
+ if (CONNECTION_PLACEHOLDERS.includes(name)) {
4654
+ if (!fields.has(name)) issues.push(issueAt(path, `\u043F\u043E\u043B\u0435 \u043F\u043E\u0434\u043A\u043B\u044E\u0447\u0435\u043D\u0438\u044F \xAB${name}\xBB \u043D\u0435 \u043E\u0431\u044A\u044F\u0432\u043B\u0435\u043D\u043E \u0432 fields`));
4655
+ } else if (!inputs.includes(name)) {
4656
+ const known = [...CONNECTION_PLACEHOLDERS.filter((field) => fields.has(field)), ...inputs].join(", ") || "\u043D\u0435\u0442";
4657
+ issues.push(issueAt(path, `\u043D\u0435\u0438\u0437\u0432\u0435\u0441\u0442\u043D\u044B\u0439 \u043F\u043B\u0435\u0439\u0441\u0445\u043E\u043B\u0434\u0435\u0440 {{${name}}}; \u0437\u0434\u0435\u0441\u044C \u0434\u043E\u0441\u0442\u0443\u043F\u043D\u044B: ${known}`));
4658
+ continue;
4659
+ }
4660
+ if (modifier !== void 0 && !(modifier === "path" && where === "path")) {
4661
+ issues.push(issueAt(path, `\u043C\u043E\u0434\u0438\u0444\u0438\u043A\u0430\u0442\u043E\u0440 |${modifier} \u043D\u0435\u0434\u043E\u043F\u0443\u0441\u0442\u0438\u043C: \u0435\u0441\u0442\u044C \u0442\u043E\u043B\u044C\u043A\u043E |path, \u0438 \u0442\u043E\u043B\u044C\u043A\u043E \u0432 \u043F\u0443\u0442\u0438 \u043E\u043F\u0435\u0440\u0430\u0446\u0438\u0438`));
4662
+ }
4663
+ if (OBJECT_INPUTS.includes(name) && !(where === "body" && wholePlaceholder(template) === name)) {
4664
+ issues.push(issueAt(path, `\u0432\u0445\u043E\u0434 ${name} \u2014 \u0441\u043B\u043E\u0432\u0430\u0440\u044C: \u043E\u043D \u043F\u043E\u0434\u0441\u0442\u0430\u0432\u043B\u044F\u0435\u0442\u0441\u044F \u0442\u043E\u043B\u044C\u043A\u043E \u0446\u0435\u043B\u044B\u043C \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0435\u043C \u0442\u0435\u043B\u0430 ("{{${name}}}")`));
4665
+ }
4666
+ }
4667
+ const rest = template.replace(new RegExp(PLACEHOLDER.source, "g"), "");
4668
+ if (rest.includes("{{") || rest.includes("}}")) issues.push(issueAt(path, "\u043D\u0435\u0437\u0430\u043A\u0440\u044B\u0442\u044B\u0439 \u0438\u043B\u0438 \u043D\u0435\u0432\u0435\u0440\u043D\u044B\u0439 \u043F\u043B\u0435\u0439\u0441\u0445\u043E\u043B\u0434\u0435\u0440: \u043E\u0436\u0438\u0434\u0430\u0435\u0442\u0441\u044F {{\u0438\u043C\u044F}} \u0438\u043B\u0438 {{\u0438\u043C\u044F|path}}"));
4669
+ }
4670
+ function checkPath(config, template, path, inputs, issues) {
4671
+ checkTemplate(config, template, path, inputs, "path", issues);
4672
+ const literal = template.replace(new RegExp(PLACEHOLDER.source, "g"), "x");
4673
+ if (!template.startsWith("/") || template.startsWith("//")) {
4674
+ issues.push(issueAt(path, "\u043F\u0443\u0442\u044C \u043E\u043F\u0435\u0440\u0430\u0446\u0438\u0438 \u043D\u0430\u0447\u0438\u043D\u0430\u0435\u0442\u0441\u044F \u0441 \u043E\u0434\u043D\u043E\u0433\u043E \xAB/\xBB: \u0430\u0434\u0440\u0435\u0441 \u0441\u043E\u0431\u0438\u0440\u0430\u0435\u0442\u0441\u044F \u043E\u0442 http.base"));
4675
+ return;
4676
+ }
4677
+ if (!PATH_LITERAL.test(literal)) {
4678
+ issues.push(issueAt(path, "\u0432 \u043F\u0443\u0442\u0438 \u043E\u043F\u0435\u0440\u0430\u0446\u0438\u0438 \u0442\u043E\u043B\u044C\u043A\u043E \u043B\u0430\u0442\u0438\u043D\u0438\u0446\u0430, \u0446\u0438\u0444\u0440\u044B, \xAB/\xBB \u0438 \u0441\u0438\u043C\u0432\u043E\u043B\u044B -._~!$&'()*+,;=:@ \u2014 \u0431\u0435\u0437 \xAB?\xBB, \xAB#\xBB, \xAB%\xBB, \xAB\\\xBB \u0438 \u043F\u0440\u043E\u0431\u0435\u043B\u043E\u0432; \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u044F \u043A\u043E\u0434\u0438\u0440\u0443\u0435\u0442 \u0438\u043D\u0442\u0435\u0440\u043F\u0440\u0435\u0442\u0430\u0442\u043E\u0440"));
4679
+ return;
4680
+ }
4681
+ const segments = template.split("/").slice(1);
4682
+ if (segments.some((part) => part === "." || part === "..")) issues.push(issueAt(path, "\u0441\u0435\u0433\u043C\u0435\u043D\u0442\u044B \xAB.\xBB \u0438 \xAB..\xBB \u0443\u0432\u043E\u0434\u044F\u0442 \u0430\u0434\u0440\u0435\u0441 \u0441 \u0431\u0430\u0437\u044B: \u043E\u043D\u0438 \u0432 \u043F\u0443\u0442\u0438 \u0437\u0430\u043F\u0440\u0435\u0449\u0435\u043D\u044B"));
4683
+ }
4684
+ function checkBase(config, issues) {
4685
+ const path = ["http", "base"];
4686
+ const base = config.http.base;
4687
+ const head = /^\{\{\s*url\s*\}\}/.exec(base);
4688
+ const rest = head === null ? base : base.slice(head[0].length);
4689
+ if (head !== null) {
4690
+ if (!declared(config).has("url")) issues.push(issueAt(path, "\u043F\u043E\u043B\u0435 \u043F\u043E\u0434\u043A\u043B\u044E\u0447\u0435\u043D\u0438\u044F \xABurl\xBB \u043D\u0435 \u043E\u0431\u044A\u044F\u0432\u043B\u0435\u043D\u043E \u0432 fields"));
4691
+ if (rest !== "" && !rest.startsWith("/")) issues.push(issueAt(path, "\u043F\u043E\u0441\u043B\u0435 {{url}} \u2014 \u0442\u043E\u043B\u044C\u043A\u043E \u043F\u0443\u0442\u044C \u043E\u0442 \xAB/\xBB: url \u043F\u043E\u0434\u043A\u043B\u044E\u0447\u0435\u043D\u0438\u044F \u0437\u0430\u0434\u0430\u0451\u0442 origin \u0446\u0435\u043B\u0438\u043A\u043E\u043C"));
4692
+ } else if (!/^https?:\/\/[^/?#@{}\s]+(?:\/[^?#{}\s]*)?$/.test(base)) {
4693
+ issues.push(issueAt(path, "http.base \u2014 \u0430\u0434\u0440\u0435\u0441 http(s) \u0431\u0435\u0437 \u043F\u0430\u0440\u0430\u043C\u0435\u0442\u0440\u043E\u0432, \u044F\u043A\u043E\u0440\u044F \u0438 \u0438\u043C\u0435\u043D\u0438 \u0441 \u043F\u0430\u0440\u043E\u043B\u0435\u043C, \u0438\u043B\u0438 {{url}} \u0438 \u043F\u0443\u0442\u044C \u043F\u043E\u0441\u043B\u0435 \u043D\u0435\u0433\u043E"));
4694
+ return;
4695
+ }
4696
+ if (rest.includes("{{") || rest.includes("}}")) issues.push(issueAt(path, "\u0432 http.base \u043F\u043B\u0435\u0439\u0441\u0445\u043E\u043B\u0434\u0435\u0440 \u0442\u043E\u043B\u044C\u043A\u043E \u043E\u0434\u0438\u043D \u2014 {{url}} \u0432 \u043D\u0430\u0447\u0430\u043B\u0435"));
4697
+ if (/[?#\\\s%]/.test(rest)) issues.push(issueAt(path, "\u043F\u0443\u0442\u044C http.base \u0431\u0435\u0437 \xAB?\xBB, \xAB#\xBB, \xAB%\xBB, \xAB\\\xBB \u0438 \u043F\u0440\u043E\u0431\u0435\u043B\u043E\u0432"));
4698
+ if (rest.split("/").some((part) => part === "." || part === "..")) issues.push(issueAt(path, "\u0441\u0435\u0433\u043C\u0435\u043D\u0442\u044B \xAB.\xBB \u0438 \xAB..\xBB \u0432 http.base \u0437\u0430\u043F\u0440\u0435\u0449\u0435\u043D\u044B"));
4699
+ }
4700
+ function checkHeaders(config, issues) {
4701
+ for (const [name, value] of Object.entries(config.http.headers ?? {})) {
4702
+ const path = ["http", "headers", name];
4703
+ if (isSecretKey(name)) issues.push(issueAt(path, "\u0437\u0430\u0433\u043E\u043B\u043E\u0432\u043E\u043A \u043F\u043E\u0445\u043E\u0436 \u043D\u0430 \u0441\u0435\u043A\u0440\u0435\u0442\u043D\u044B\u0439: \u0430\u0432\u0442\u043E\u0440\u0438\u0437\u0430\u0446\u0438\u044F \u2014 \u0442\u043E\u043B\u044C\u043A\u043E \u0447\u0435\u0440\u0435\u0437 http.auth"));
4704
+ if (RESERVED_HEADERS.includes(name.toLowerCase())) issues.push(issueAt(path, `\u0437\u0430\u0433\u043E\u043B\u043E\u0432\u043E\u043A ${name} \u0437\u0430\u0434\u0430\u0451\u0442 \u0441\u0430\u043C \u043A\u043B\u0438\u0435\u043D\u0442 HTTP`));
4705
+ if (config.http.auth.kind === "header" && config.http.auth.header.toLowerCase() === name.toLowerCase()) issues.push(issueAt(path, `\u0437\u0430\u0433\u043E\u043B\u043E\u0432\u043E\u043A ${name} \u0437\u0430\u043D\u044F\u0442 \u0430\u0432\u0442\u043E\u0440\u0438\u0437\u0430\u0446\u0438\u0435\u0439 http.auth`));
4706
+ if (/[\r\n\0]/.test(value)) issues.push(issueAt(path, "\u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0435 \u0437\u0430\u0433\u043E\u043B\u043E\u0432\u043A\u0430 \u0431\u0435\u0437 \u043F\u0435\u0440\u0435\u0432\u043E\u0434\u0430 \u0441\u0442\u0440\u043E\u043A\u0438"));
4707
+ checkTemplate(config, value, path, [], "header", issues);
4708
+ }
4709
+ const auth = config.http.auth;
4710
+ if (auth.kind === "header" && RESERVED_HEADERS.includes(auth.header.toLowerCase())) {
4711
+ issues.push(issueAt(["http", "auth", "header"], `\u0437\u0430\u0433\u043E\u043B\u043E\u0432\u043E\u043A ${auth.header} \u0437\u0430\u0434\u0430\u0451\u0442 \u0441\u0430\u043C \u043A\u043B\u0438\u0435\u043D\u0442 HTTP`));
4712
+ }
4713
+ }
4714
+ function checkFields(config, issues) {
4715
+ const names = config.fields.map((field) => field.name);
4716
+ config.fields.forEach((field, index) => {
4717
+ if (names.indexOf(field.name) !== index) issues.push(issueAt(["fields", index, "name"], `\u043F\u043E\u043B\u0435 \xAB${field.name}\xBB \u043E\u0431\u044A\u044F\u0432\u043B\u0435\u043D\u043E \u0434\u0432\u0430\u0436\u0434\u044B`));
4718
+ if (field.secret !== (field.name === "token")) issues.push(issueAt(["fields", index, "secret"], "\u0441\u0435\u043A\u0440\u0435\u0442\u043D\u044B\u043C \u0431\u044B\u0432\u0430\u0435\u0442 \u0442\u043E\u043B\u044C\u043A\u043E \u043F\u043E\u043B\u0435 token, \u0438 \u043E\u043D\u043E \u0432\u0441\u0435\u0433\u0434\u0430 \u0441\u0435\u043A\u0440\u0435\u0442\u043D\u043E\u0435"));
4719
+ });
4720
+ const auth = config.http.auth;
4721
+ if (auth.kind === "none" && names.includes("token")) issues.push(issueAt(["http", "auth"], "\u043F\u043E\u043B\u0435 token \u0431\u0435\u0437 \u0430\u0432\u0442\u043E\u0440\u0438\u0437\u0430\u0446\u0438\u0438 \u043D\u0435 \u0438\u0441\u043F\u043E\u043B\u044C\u0437\u0443\u0435\u0442\u0441\u044F: \u0443\u043A\u0430\u0436\u0438\u0442\u0435 http.auth"));
4722
+ if (auth.kind !== "none" && !names.includes("token")) issues.push(issueAt(["fields"], `\u0430\u0432\u0442\u043E\u0440\u0438\u0437\u0430\u0446\u0438\u0438 ${auth.kind} \u043D\u0443\u0436\u043D\u043E \u043F\u043E\u043B\u0435 token`));
4723
+ if (auth.kind === "basic" && !names.includes("user")) issues.push(issueAt(["fields"], "\u0430\u0432\u0442\u043E\u0440\u0438\u0437\u0430\u0446\u0438\u0438 basic \u043D\u0443\u0436\u043D\u043E \u043F\u043E\u043B\u0435 user"));
4724
+ }
4725
+ function checkPagination(pagination, path, issues) {
4726
+ if (pagination.style === "none") return;
4727
+ const params = pagination.style === "page" ? [pagination.page, pagination.size] : [pagination.param, ...pagination.size === void 0 ? [] : [pagination.size]];
4728
+ for (const name of params) {
4729
+ if (isSecretKey(name)) issues.push(issueAt(path, `\u043F\u0430\u0440\u0430\u043C\u0435\u0442\u0440 ${name} \u043F\u043E\u0445\u043E\u0436 \u043D\u0430 \u0441\u0435\u043A\u0440\u0435\u0442\u043D\u044B\u0439: \u0442\u043E\u043A\u0435\u043D \u0432 query \u043D\u0435 \u043F\u0435\u0440\u0435\u0434\u0430\u044E\u0442`));
4730
+ }
4731
+ }
4732
+ function checkValue(field, spec, path, issues) {
4733
+ const items = Array.isArray(spec) ? spec : [spec];
4734
+ items.forEach((item, index) => {
4735
+ const at = Array.isArray(spec) ? [...path, index] : path;
4736
+ const itemPath = typeof item === "string" ? item : item.path;
4737
+ if (itemPath.includes("[*]") && field.type !== "list") issues.push(issueAt(at, "[*] \u0434\u0430\u0451\u0442 \u0441\u043F\u0438\u0441\u043E\u043A: \u043E\u043D \u0434\u043E\u043F\u0443\u0441\u0442\u0438\u043C \u0442\u043E\u043B\u044C\u043A\u043E \u0443 \u043F\u043E\u043B\u044F-\u0441\u043F\u0438\u0441\u043A\u0430"));
4738
+ if (typeof item === "string") return;
4739
+ if (item.exists === true && field.type !== "flag") issues.push(issueAt([...at, "exists"], "exists \u0434\u0430\u0451\u0442 \u0444\u043B\u0430\u0433: \u043E\u043D \u0434\u043E\u043F\u0443\u0441\u0442\u0438\u043C \u0442\u043E\u043B\u044C\u043A\u043E \u0443 \u043F\u043E\u043B\u044F-\u0444\u043B\u0430\u0433\u0430"));
4740
+ const values = field.type === "flag" ? ["true", "false"] : field.values;
4741
+ if (values === void 0) return;
4742
+ for (const [from, to] of Object.entries(item.map ?? {})) {
4743
+ if (!values.includes(String(to))) issues.push(issueAt([...at, "map", from], `\u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0435 \xAB${String(to)}\xBB \u043D\u0435 \u0438\u0437 \u043F\u0435\u0440\u0435\u0447\u043D\u044F ${values.join(", ")}`));
4744
+ }
4745
+ if (item.default !== void 0 && !values.includes(String(item.default))) issues.push(issueAt([...at, "default"], `\u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0435 \xAB${String(item.default)}\xBB \u043D\u0435 \u0438\u0437 \u043F\u0435\u0440\u0435\u0447\u043D\u044F ${values.join(", ")}`));
4746
+ });
4747
+ }
4748
+ function checkResult(section, name, operation2, spec, path, issues) {
4749
+ const result = operation2.result;
4750
+ if (spec.text === true) {
4751
+ if (operation2.items !== void 0) issues.push(issueAt([...path, "items"], "\u043E\u0442\u0432\u0435\u0442 \u043E\u043F\u0435\u0440\u0430\u0446\u0438\u0438 \u2014 \u0442\u0435\u043A\u0441\u0442: items \u0443 \u043D\u0435\u0451 \u043D\u0435\u0442"));
4752
+ if (result !== void 0) issues.push(issueAt([...path, "result"], "\u043E\u0442\u0432\u0435\u0442 \u043E\u043F\u0435\u0440\u0430\u0446\u0438\u0438 \u2014 \u0442\u0435\u043A\u0441\u0442: result \u0443 \u043D\u0435\u0451 \u043D\u0435\u0442"));
4753
+ return;
4754
+ }
4755
+ if (spec.result === "forbidden") {
4756
+ if (result !== void 0 || operation2.items !== void 0) issues.push(issueAt(path, "\u0443 \u043E\u043F\u0435\u0440\u0430\u0446\u0438\u0438 \u043D\u0435\u0442 result \u0438 items: \u043F\u043E\u0441\u043B\u0435 \u043D\u0435\u0451 \u044D\u043B\u0435\u043C\u0435\u043D\u0442 \u043F\u0435\u0440\u0435\u0447\u0438\u0442\u044B\u0432\u0430\u0435\u0442\u0441\u044F"));
4757
+ return;
4758
+ }
4759
+ if (operation2.items?.includes("[*]") === true && spec.list !== true) issues.push(issueAt([...path, "items"], "\u043E\u043F\u0435\u0440\u0430\u0446\u0438\u044F \u0432\u043E\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u043E\u0434\u0438\u043D \u044D\u043B\u0435\u043C\u0435\u043D\u0442: [*] \u0432 items \u2014 \u0442\u043E\u043B\u044C\u043A\u043E \u0443 \u0441\u043F\u0438\u0441\u043A\u043E\u0432"));
4760
+ if (result === void 0) {
4761
+ if (spec.result === "required") issues.push(issueAt([...path, "result"], "\u043D\u0443\u0436\u0435\u043D result: \u0438\u0437 \u0447\u0435\u0433\u043E \u0441\u043E\u0431\u0440\u0430\u0442\u044C \u044D\u043B\u0435\u043C\u0435\u043D\u0442 \u0435\u0434\u0438\u043D\u043E\u0439 \u043C\u043E\u0434\u0435\u043B\u0438"));
4762
+ return;
4763
+ }
4764
+ const model = spec.model;
4765
+ if (model === void 0) return;
4766
+ const fields = RESULT_FIELDS[model];
4767
+ for (const [field, value] of Object.entries(result)) {
4768
+ const target = Object.hasOwn(fields, field) ? fields[field] : void 0;
4769
+ if (target === void 0) {
4770
+ issues.push(issueAt([...path, "result", field], `\u0443 \u043C\u043E\u0434\u0435\u043B\u0438 ${model} \u043D\u0435\u0442 \u043F\u043E\u043B\u044F \xAB${field}\xBB; \u043F\u043E\u043B\u044F: ${Object.keys(fields).join(", ")}`));
4771
+ continue;
4772
+ }
4773
+ checkValue(target, value, [...path, "result", field], issues);
4774
+ }
4775
+ const required = [...Object.entries(fields).filter(([, field]) => field.required === true).map(([field]) => field), ...OPERATION_REQUIRED_FIELDS[`${section}.${name}`] ?? []];
4776
+ for (const field of required) {
4777
+ if (result[field] === void 0) issues.push(issueAt([...path, "result"], `\u043D\u0435\u0442 \u043E\u0431\u044F\u0437\u0430\u0442\u0435\u043B\u044C\u043D\u043E\u0433\u043E \u043F\u043E\u043B\u044F \xAB${field}\xBB \u043C\u043E\u0434\u0435\u043B\u0438 ${model}`));
4778
+ }
4779
+ }
4780
+ function checkTables(section, name, operation2, spec, used, path, issues) {
4781
+ for (const [input, table] of Object.entries(operation2.inputs ?? {})) {
4782
+ const at = [...path, "inputs", input];
4783
+ if (!spec.inputs.includes(input)) {
4784
+ issues.push(issueAt(at, `\u0443 \u043E\u043F\u0435\u0440\u0430\u0446\u0438\u0438 \u043D\u0435\u0442 \u0432\u0445\u043E\u0434\u0430 \xAB${input}\xBB; \u0432\u0445\u043E\u0434\u044B: ${spec.inputs.join(", ") || "\u043D\u0435\u0442"}`));
4785
+ continue;
4786
+ }
4787
+ const domain = INPUT_DOMAINS[section][input];
4788
+ if (domain === void 0) {
4789
+ issues.push(issueAt(at, `\u0443 \u0432\u0445\u043E\u0434\u0430 ${input} \u043D\u0435\u0442 \u0442\u0430\u0431\u043B\u0438\u0446\u044B \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0439: \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0435 \u043F\u043E\u0434\u0441\u0442\u0430\u0432\u043B\u044F\u0435\u0442\u0441\u044F \u043A\u0430\u043A \u0435\u0441\u0442\u044C`));
4790
+ continue;
4791
+ }
4792
+ if (!used.has(input)) issues.push(issueAt(at, `\u0442\u0430\u0431\u043B\u0438\u0446\u0430 \u043D\u0435 \u0438\u0441\u043F\u043E\u043B\u044C\u0437\u0443\u0435\u0442\u0441\u044F: \u0432 \u0448\u0430\u0431\u043B\u043E\u043D\u0430\u0445 \u043E\u043F\u0435\u0440\u0430\u0446\u0438\u0438 \u043D\u0435\u0442 {{${input}}}`));
4793
+ const wildcard = spec.list === true && WILDCARD_INPUTS.includes(input);
4794
+ const allowed = section === "pulls" && name === "update" && input === "status" ? domain.filter((value) => value !== "merged") : domain;
4795
+ for (const key of Object.keys(table)) {
4796
+ if (key === INPUT_ANY && wildcard) continue;
4797
+ if (!allowed.includes(key)) issues.push(issueAt([...at, key], `\u0443 \u0432\u0445\u043E\u0434\u0430 ${input} \u043D\u0435\u0442 \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u044F \xAB${key}\xBB; \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u044F: ${[...allowed, ...wildcard ? [INPUT_ANY] : []].join(", ")}`));
4798
+ }
4799
+ }
4800
+ }
4801
+ function checkOperation(config, section, name, operation2, issues) {
4802
+ const spec = OPERATIONS[section][name];
4803
+ if (spec === void 0) return;
4804
+ const path = [section, name];
4805
+ checkPath(config, operation2.path, [...path, "path"], spec.inputs, issues);
4806
+ for (const [param, value] of Object.entries(operation2.query ?? {})) {
4807
+ if (isSecretKey(param)) issues.push(issueAt([...path, "query", param], "\u043F\u0430\u0440\u0430\u043C\u0435\u0442\u0440 \u043F\u043E\u0445\u043E\u0436 \u043D\u0430 \u0441\u0435\u043A\u0440\u0435\u0442\u043D\u044B\u0439: \u0442\u043E\u043A\u0435\u043D \u0432 query \u043D\u0435 \u043F\u0435\u0440\u0435\u0434\u0430\u044E\u0442, \u0430\u0432\u0442\u043E\u0440\u0438\u0437\u0430\u0446\u0438\u044F \u2014 \u0442\u043E\u043B\u044C\u043A\u043E \u0447\u0435\u0440\u0435\u0437 http.auth"));
4808
+ checkTemplate(config, String(value), [...path, "query", param], spec.inputs, "query", issues);
4809
+ }
4810
+ if (operation2.body !== void 0) {
4811
+ if (operation2.method === "GET") issues.push(issueAt([...path, "body"], "\u0443 GET \u043D\u0435\u0442 \u0442\u0435\u043B\u0430: \u0443\u0431\u0435\u0440\u0438\u0442\u0435 body \u0438\u043B\u0438 \u0441\u043C\u0435\u043D\u0438\u0442\u0435 method"));
4812
+ for (const template of bodyTemplates(operation2.body)) checkTemplate(config, template, [...path, "body"], spec.inputs, "body", issues);
4813
+ }
4814
+ const used = usedNames(operation2);
4815
+ for (const input of spec.required) {
4816
+ if (!used.has(input)) issues.push(issueAt(path, `\u043E\u043F\u0435\u0440\u0430\u0446\u0438\u0438 \u043D\u0443\u0436\u0435\u043D \u0432\u0445\u043E\u0434 {{${input}}} \u0432 \u043F\u0443\u0442\u0438, query \u0438\u043B\u0438 \u0442\u0435\u043B\u0435`));
4817
+ }
4818
+ if (used.has("sort") !== used.has("direction")) issues.push(issueAt(path, "\u0441\u043E\u0440\u0442\u0438\u0440\u043E\u0432\u043A\u0435 \u043D\u0443\u0436\u043D\u044B \u043E\u0431\u0430 \u0432\u0445\u043E\u0434\u0430: {{sort}} \u0438 {{direction}}"));
4819
+ if (used.has("sort") && operation2.inputs?.sort === void 0) issues.push(issueAt([...path, "inputs"], "\u0432\u0445\u043E\u0434\u0443 sort \u043D\u0443\u0436\u043D\u0430 \u0442\u0430\u0431\u043B\u0438\u0446\u0430 inputs.sort: \u043F\u043E\u043B\u0435 \u0435\u0434\u0438\u043D\u043E\u0439 \u043C\u043E\u0434\u0435\u043B\u0438 \u2192 \u043F\u043E\u043B\u0435 API"));
4820
+ if (used.has("workflow") && used.has("workflows")) issues.push(issueAt(path, "\u0437\u0430\u043F\u0443\u0441\u043A \u0431\u0435\u0440\u0451\u0442 \u043E\u0434\u0438\u043D workflow ({{workflow}}) \u0438\u043B\u0438 \u0441\u043F\u0438\u0441\u043E\u043A ({{workflows}}), \u043D\u0435 \u043E\u0431\u0430"));
4821
+ checkTables(section, name, operation2, spec, used, path, issues);
4822
+ if (operation2.pagination !== void 0) {
4823
+ if (spec.list !== true) issues.push(issueAt([...path, "pagination"], "\u043F\u043E\u0441\u0442\u0440\u0430\u043D\u0438\u0447\u043D\u043E\u0441\u0442\u044C \u2014 \u0442\u043E\u043B\u044C\u043A\u043E \u0443 \u0441\u043F\u0438\u0441\u043A\u043E\u0432"));
4824
+ checkPagination(operation2.pagination, [...path, "pagination"], issues);
4825
+ }
4826
+ checkResult(section, name, operation2, spec, path, issues);
4827
+ }
4828
+ function checkSection(config, section, issues) {
4829
+ const operations = config[section];
4830
+ if (operations === void 0) return;
4831
+ for (const [name, operation2] of Object.entries(operations)) {
4832
+ if (operation2 === void 0) continue;
4833
+ checkOperation(config, section, name, operation2, issues);
4834
+ if (section !== "ci") continue;
4835
+ for (const need of CI_OPERATION_NEEDS[name] ?? []) {
4836
+ if (operations[need] === void 0) issues.push(issueAt([section, name], `\u043E\u043F\u0435\u0440\u0430\u0446\u0438\u0438 ${name} \u043D\u0443\u0436\u043D\u0430 \u043E\u043F\u0435\u0440\u0430\u0446\u0438\u044F ${need}`));
4837
+ }
4838
+ }
4839
+ }
4840
+ function configIssues(config) {
4841
+ const issues = [];
4842
+ if (SECTIONS.every((section) => config[section] === void 0)) issues.push(issueAt([], "\u043D\u0443\u0436\u0435\u043D \u0445\u043E\u0442\u044F \u0431\u044B \u043E\u0434\u0438\u043D \u0440\u0430\u0437\u0434\u0435\u043B: issues, pulls \u0438\u043B\u0438 ci"));
4843
+ if (BUILTIN_TRACKER_KINDS.includes(config.kind)) issues.push(issueAt(["kind"], `\u0432\u0438\u0434 \xAB${config.kind}\xBB \u0437\u0430\u043D\u044F\u0442 \u0432\u0441\u0442\u0440\u043E\u0435\u043D\u043D\u044B\u043C \u0442\u0440\u0435\u043A\u0435\u0440\u043E\u043C: \u0432\u044B\u0431\u0435\u0440\u0438\u0442\u0435 \u0434\u0440\u0443\u0433\u043E\u0439`));
4844
+ checkFields(config, issues);
4845
+ checkBase(config, issues);
4846
+ checkHeaders(config, issues);
4847
+ checkPagination(config.http.pagination, ["http", "pagination"], issues);
4848
+ for (const section of SECTIONS) checkSection(config, section, issues);
4849
+ return issues;
4850
+ }
4851
+
4852
+ // src/tracker/declarative/declarative.lib.ts
4853
+ var SCHEMA_ERRORS = z5.locales.ru().localeError;
4854
+ var TrackerConfigError = class extends Error {
4855
+ issues;
4856
+ secret;
4857
+ constructor(issues, secret) {
4858
+ const first = issues[0];
4859
+ super(`\u041A\u043E\u043D\u0444\u0438\u0433 \u0442\u0440\u0435\u043A\u0435\u0440\u0430 \u043D\u0435 \u043F\u0440\u043E\u0448\u0451\u043B \u043F\u0440\u043E\u0432\u0435\u0440\u043A\u0443 (${String(issues.length)}): ${first === void 0 ? "" : `${first.path === "" ? "\u043A\u043E\u043D\u0444\u0438\u0433" : first.path} \u2014 ${first.message}`}`);
4860
+ this.name = "TrackerConfigError";
4861
+ this.issues = issues;
4862
+ this.secret = secret;
4863
+ }
4864
+ };
4865
+ function validateTrackerConfig(input) {
4866
+ const parsed = parseConfigInput(input);
4867
+ const done = (issues2) => ({
4868
+ ok: false,
4869
+ issues: issues2.slice(0, TRACKER_CONFIG_ISSUES_MAX).map((issue) => ({ path: redactSecretText(issue.path), message: redactSecretText(issue.message) })),
4870
+ secret: parsed.secret
4871
+ });
4872
+ if (parsed.data === void 0) return done(parsed.issues);
4873
+ const schema = trackerConfigSchema.safeParse(parsed.data, { error: SCHEMA_ERRORS });
4874
+ if (!schema.success) return done([...parsed.issues, ...schema.error.issues.map((item) => issueAt(item.path, item.message))]);
4875
+ const issues = [...parsed.issues, ...configIssues(schema.data)];
4876
+ return issues.length === 0 ? { ok: true, config: schema.data } : done(issues);
4877
+ }
4878
+ function definitionFromConfig(input) {
4879
+ const check = validateTrackerConfig(input);
4880
+ if (!check.ok) throw new TrackerConfigError(check.issues, check.secret);
4881
+ const config = check.config;
4882
+ const issues = issueCapabilitiesFrom(config);
4883
+ const features = featuresFrom(config);
4884
+ const pulls = pullCapabilitiesFrom(config);
4885
+ const ci = ciCapabilitiesFrom(config);
4886
+ return {
4887
+ descriptor: {
4888
+ tracker: config.kind,
4889
+ title: config.title,
4890
+ source: "user",
4891
+ fields: config.fields.map((field) => ({ name: field.name, required: field.required, secret: field.secret })),
4892
+ features
4893
+ },
4894
+ create: (context) => createIssuesAdapter(config, context, issues, features),
4895
+ issues,
4896
+ ...pulls === void 0 ? {} : { pulls: { capabilities: pulls, create: (context) => createPullAdapter2(config, context, pulls) } },
4897
+ ...ci === void 0 ? {} : { ci: { capabilities: ci, create: (context) => createCiAdapter(config, context, ci) } },
4898
+ origin: (connection) => baseOf(config, connection).origin
4899
+ };
4900
+ }
4901
+
4902
+ // src/tracker/declarative/declarative-hint.const.ts
4903
+ var TRACKER_CONFIG_EXAMPLE = `format: 1
4904
+ kind: gitea
4905
+ title: Gitea
4906
+ fields:
4907
+ - { name: url, required: true, secret: false }
4908
+ - { name: target, required: true, secret: false }
4909
+ - { name: token, required: true, secret: true }
4910
+ http:
4911
+ base: "{{url}}/api/v1"
4912
+ auth: { kind: bearer }
4913
+ headers:
4914
+ Accept: application/json
4915
+ pagination: { style: page, page: page, size: limit, next: link }
4916
+ issues:
4917
+ list:
4918
+ path: "/repos/{{target|path}}/issues"
4919
+ query:
4920
+ type: issues
4921
+ state: "{{status}}"
4922
+ labels: "{{labels}}"
4923
+ q: "{{search}}"
4924
+ created_by: "{{author}}"
4925
+ since: "{{updatedAfter}}"
4926
+ before: "{{updatedBefore}}"
4927
+ inputs:
4928
+ status: { open: open, in_progress: open, done: closed, declined: closed, "*": all }
4929
+ result: &issue
4930
+ key: $.number
4931
+ title: $.title
4932
+ description: $.body
4933
+ status.category: { path: $.state, map: { open: open, closed: done } }
4934
+ labels: $.labels[*].name
4935
+ assignee: $.assignee.login
4936
+ url: $.html_url
4937
+ createdAt: $.created_at
4938
+ updatedAt: $.updated_at
4939
+ get:
4940
+ path: "/repos/{{target|path}}/issues/{{key}}"
4941
+ result: *issue
4942
+ create:
4943
+ method: POST
4944
+ path: "/repos/{{target|path}}/issues"
4945
+ body:
4946
+ title: "{{title}}"
4947
+ body: "{{description}}"
4948
+ assignee: "{{assignee}}"
4949
+ result: *issue
4950
+ update:
4951
+ method: PATCH
4952
+ path: "/repos/{{target|path}}/issues/{{key}}"
4953
+ body:
4954
+ title: "{{title}}"
4955
+ body: "{{description}}"
4956
+ state: "{{status}}"
4957
+ assignee: "{{assignee}}"
4958
+ inputs:
4959
+ status: { open: open, done: closed }
4960
+ result: *issue
4961
+ comments:
4962
+ path: "/repos/{{target|path}}/issues/{{key}}/comments"
4963
+ query:
4964
+ since: "{{updatedAfter}}"
4965
+ result: &comment
4966
+ id: $.id
4967
+ author: $.user.login
4968
+ body: $.body
4969
+ createdAt: $.created_at
4970
+ comment:
4971
+ method: POST
4972
+ path: "/repos/{{target|path}}/issues/{{key}}/comments"
4973
+ body:
4974
+ body: "{{body}}"
4975
+ result: *comment
4976
+ pulls:
4977
+ list:
4978
+ path: "/repos/{{target|path}}/pulls"
4979
+ query:
4980
+ state: "{{status}}"
4981
+ inputs:
4982
+ status: { draft: open, open: open, merged: closed, closed: closed, "*": all }
4983
+ result: &pull
4984
+ key: $.number
4985
+ title: $.title
4986
+ description: $.body
4987
+ status.category: { path: $.state, map: { open: open, closed: closed } }
4988
+ merged: $.merged
4989
+ draft: $.draft
4990
+ author: $.user.login
4991
+ source: $.head.ref
4992
+ target: $.base.ref
4993
+ headSha: $.head.sha
4994
+ labels: $.labels[*].name
4995
+ url: $.html_url
4996
+ createdAt: $.created_at
4997
+ updatedAt: $.updated_at
4998
+ mergedAt: $.merged_at
4999
+ closedAt: $.closed_at
5000
+ get:
5001
+ path: "/repos/{{target|path}}/pulls/{{key}}"
5002
+ result: *pull
5003
+ create:
5004
+ method: POST
5005
+ path: "/repos/{{target|path}}/pulls"
5006
+ body:
5007
+ title: "{{title}}"
5008
+ body: "{{description}}"
5009
+ head: "{{sourceBranch}}"
5010
+ base: "{{targetBranch}}"
5011
+ result: *pull
5012
+ update:
5013
+ method: PATCH
5014
+ path: "/repos/{{target|path}}/pulls/{{key}}"
5015
+ body:
5016
+ title: "{{title}}"
5017
+ body: "{{description}}"
5018
+ base: "{{targetBranch}}"
5019
+ state: "{{status}}"
5020
+ inputs:
5021
+ status: { open: open, closed: closed }
5022
+ result: *pull
5023
+ merge:
5024
+ method: POST
5025
+ path: "/repos/{{target|path}}/pulls/{{key}}/merge"
5026
+ body:
5027
+ Do: "{{method}}"
5028
+ merge_message_field: "{{message}}"
5029
+ delete_branch_after_merge: "{{deleteSource}}"
5030
+ head_commit_id: "{{headSha}}"
5031
+ comments:
5032
+ path: "/repos/{{target|path}}/issues/{{key}}/comments"
5033
+ result: *comment
5034
+ comment:
5035
+ method: POST
5036
+ path: "/repos/{{target|path}}/issues/{{key}}/comments"
5037
+ body:
5038
+ body: "{{body}}"
5039
+ result: *comment
5040
+ ci:
5041
+ workflows:
5042
+ path: "/repos/{{target|path}}/actions/workflows"
5043
+ items: $.workflows
5044
+ result:
5045
+ key: $.id
5046
+ name: $.name
5047
+ path: $.path
5048
+ enabled: { path: $.state, map: { active: true }, default: false }
5049
+ runs:
5050
+ path: "/repos/{{target|path}}/actions/runs"
5051
+ query:
5052
+ branch: "{{ref}}"
5053
+ event: "{{event}}"
5054
+ status: "{{status}}"
5055
+ actor: "{{actor}}"
5056
+ head_sha: "{{sha}}"
5057
+ inputs:
5058
+ event: { push: push, pull_request: pull_request, manual: workflow_dispatch, schedule: schedule }
5059
+ status: { queued: queued, waiting: waiting, running: in_progress, success: success, failed: failure, canceled: cancelled, skipped: skipped }
5060
+ items: $.workflow_runs
5061
+ result: &run
5062
+ key: $.id
5063
+ number: $.run_number
5064
+ workflows: $.path
5065
+ status.category: &state
5066
+ - { path: $.conclusion, map: { success: success, failure: failed, cancelled: canceled, skipped: skipped }, default: failed }
5067
+ - { path: $.status, map: { queued: queued, waiting: waiting, in_progress: running }, default: running }
5068
+ status.name: $.status
5069
+ event.category: { path: $.event, map: { push: push, pull_request: pull_request, workflow_dispatch: manual, schedule: schedule }, default: other }
5070
+ ref: $.head_branch
5071
+ sha: $.head_sha
5072
+ actor: $.actor.login
5073
+ attempt: $.run_attempt
5074
+ url: $.html_url
5075
+ createdAt: $.created_at
5076
+ startedAt: $.run_started_at
5077
+ finishedAt: $.completed_at
5078
+ updatedAt: $.updated_at
5079
+ run:
5080
+ path: "/repos/{{target|path}}/actions/runs/{{key}}"
5081
+ result: *run
5082
+ jobs:
5083
+ path: "/repos/{{target|path}}/actions/runs/{{run}}/jobs"
5084
+ items: $.jobs
5085
+ result: &job
5086
+ key: $.id
5087
+ runKey: $.run_id
5088
+ name: $.name
5089
+ status.category: *state
5090
+ status.name: $.status
5091
+ url: $.html_url
5092
+ startedAt: $.started_at
5093
+ finishedAt: $.completed_at
5094
+ job:
5095
+ path: "/repos/{{target|path}}/actions/jobs/{{key}}"
5096
+ result: *job
5097
+ log:
5098
+ path: "/repos/{{target|path}}/actions/jobs/{{key}}/logs"
5099
+ trigger:
5100
+ method: POST
5101
+ path: "/repos/{{target|path}}/actions/workflows/{{workflow}}/dispatches"
5102
+ body:
5103
+ ref: "{{ref}}"
5104
+ inputs: "{{inputs}}"
5105
+ rerun:
5106
+ method: POST
5107
+ path: "/repos/{{target|path}}/actions/runs/{{key}}/rerun"
5108
+ cancel:
5109
+ method: POST
5110
+ path: "/repos/{{target|path}}/actions/runs/{{key}}/cancel"
5111
+ `;
5112
+ var SECTION_TITLES = { issues: "\u0437\u0430\u0434\u0430\u0447\u0438", pulls: "pull request-\u044B", ci: "CI" };
5113
+ var MODEL_TITLES = {
5114
+ issue: "\u0437\u0430\u0434\u0430\u0447\u0430 (list, get, create, update)",
5115
+ comment: "\u043A\u043E\u043C\u043C\u0435\u043D\u0442\u0430\u0440\u0438\u0439 (comments, comment)",
5116
+ pull: "PR (pulls.list, pulls.get, pulls.create, pulls.update)",
5117
+ run: "\u043F\u0440\u043E\u0433\u043E\u043D CI (runs, run, trigger)",
5118
+ job: "\u0437\u0430\u0434\u0430\u043D\u0438\u0435 CI (jobs, job)",
5119
+ workflow: "workflow (workflows)"
5120
+ };
5121
+ function operationLines(section) {
5122
+ return Object.entries(OPERATIONS[section]).map(([name, spec]) => {
5123
+ const required = REQUIRED_OPERATIONS[section].includes(name) ? ", \u043E\u0431\u044F\u0437\u0430\u0442\u0435\u043B\u044C\u043D\u0430" : "";
5124
+ const answer = spec.text === true ? ", \u043E\u0442\u0432\u0435\u0442 \u2014 \u0442\u0435\u043A\u0441\u0442" : spec.result === "forbidden" ? ", \u0431\u0435\u0437 result: \u044D\u043B\u0435\u043C\u0435\u043D\u0442 \u043F\u0435\u0440\u0435\u0447\u0438\u0442\u044B\u0432\u0430\u0435\u0442\u0441\u044F" : spec.result === "optional" ? ", result \u043F\u043E \u0436\u0435\u043B\u0430\u043D\u0438\u044E" : "";
5125
+ return ` - \`${section}.${name}\`${required}${answer}: ${spec.inputs.length === 0 ? "\u0432\u0445\u043E\u0434\u043E\u0432 \u043D\u0435\u0442" : spec.inputs.map((input) => spec.required.includes(input) ? `**${input}**` : input).join(", ")}`;
5126
+ }).join("\n");
5127
+ }
5128
+ function fieldLines() {
5129
+ return Object.keys(RESULT_FIELDS).map((model) => {
5130
+ const fields = Object.entries(RESULT_FIELDS[model]).map(([name, field]) => field.required === true ? `**${name}**` : name);
5131
+ return ` - ${MODEL_TITLES[model]}: ${fields.join(", ")}`;
5132
+ }).join("\n");
5133
+ }
5134
+ var TRACKER_CONFIG_HINT = `# \u0421\u0432\u043E\u0439 \u0442\u0440\u0435\u043A\u0435\u0440: \u0434\u0435\u043A\u043B\u0430\u0440\u0430\u0442\u0438\u0432\u043D\u044B\u0439 \u043A\u043E\u043D\u0444\u0438\u0433 \`format: 1\`
5135
+
5136
+ \u041A\u043E\u043D\u0444\u0438\u0433 \u2014 \u0434\u0430\u043D\u043D\u044B\u0435, \u0430 \u043D\u0435 \u043A\u043E\u0434: \u0435\u0433\u043E \u0438\u0441\u043F\u043E\u043B\u043D\u044F\u0435\u0442 \u0432\u0441\u0442\u0440\u043E\u0435\u043D\u043D\u044B\u0439 \u0438\u043D\u0442\u0435\u0440\u043F\u0440\u0435\u0442\u0430\u0442\u043E\u0440 \u0431\u0438\u0431\u043B\u0438\u043E\u0442\u0435\u043A\u0438. \u0423\u0441\u043B\u043E\u0432\u0438\u0439, \u0441\u043A\u0440\u0438\u043F\u0442\u043E\u0432 \u0438 \u0432\u044B\u0447\u0438\u0441\u043B\u0435\u043D\u0438\u0439 \u043D\u0435\u0442 \u2014
5137
+ \u0442\u043E\u043B\u044C\u043A\u043E \u0448\u0430\u0431\u043B\u043E\u043D\u044B \u0437\u0430\u043F\u0440\u043E\u0441\u043E\u0432, \u043F\u0443\u0442\u0438 JSON \u0438 \u0442\u0430\u0431\u043B\u0438\u0446\u044B \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0439. \u041A\u043E\u043D\u0444\u0438\u0433 \u043E\u043F\u0438\u0441\u044B\u0432\u0430\u0435\u0442 \u0440\u0430\u0437\u0434\u0435\u043B\u044B ${Object.keys(SECTION_TITLES).map((section) => `\`${section}\` (${SECTION_TITLES[section]})`).join(", ")} \u2014 \u0445\u043E\u0442\u044F \u0431\u044B \u043E\u0434\u0438\u043D.
5138
+
5139
+ ## \u041A\u0430\u043A \u0440\u0430\u0431\u043E\u0442\u0430\u0442\u044C
5140
+ 1. \u041F\u0440\u043E\u0447\u0438\u0442\u0430\u0439 \u0434\u043E\u043A\u0443\u043C\u0435\u043D\u0442\u0430\u0446\u0438\u044E REST API \u0441\u0435\u0440\u0432\u0438\u0441\u0430: \u0430\u0434\u0440\u0435\u0441 API, \u0430\u0432\u0442\u043E\u0440\u0438\u0437\u0430\u0446\u0438\u044E, \u043F\u043E\u0441\u0442\u0440\u0430\u043D\u0438\u0447\u043D\u043E\u0441\u0442\u044C, \u043D\u0443\u0436\u043D\u044B\u0435 \u0437\u0430\u043F\u0440\u043E\u0441\u044B \u0438 \u043E\u0442\u0432\u0435\u0442\u044B.
5141
+ 2. \u041D\u0430\u043F\u0438\u0448\u0438 YAML \u043F\u043E \u044D\u0442\u043E\u0439 \u043F\u043E\u0434\u0441\u043A\u0430\u0437\u043A\u0435 \u0438 \u043F\u0440\u0438\u043C\u0435\u0440\u0443 \u043D\u0438\u0436\u0435.
5142
+ 3. \u041F\u0440\u043E\u0432\u0435\u0440\u044F\u0439 \u0435\u0433\u043E (\`validateTrackerConfig\`), \u043F\u043E\u043A\u0430 \u043F\u0440\u043E\u0432\u0435\u0440\u043A\u0430 \u043D\u0435 \u043F\u0440\u043E\u0439\u0434\u0451\u0442: \u043A\u0430\u0436\u0434\u0430\u044F \u043E\u0448\u0438\u0431\u043A\u0430 \u2014 \u043F\u0443\u0442\u044C \u043F\u043E\u043B\u044F
5143
+ (\`issues.list.query.state\`) \u0438 \u0441\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u0435.
5144
+ 4. \u041E\u0442\u0434\u0430\u0439 \u0442\u0435\u043A\u0441\u0442 \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044E. \u0422\u043E\u043A\u0435\u043D \u0432 \u043A\u043E\u043D\u0444\u0438\u0433 \u043D\u0435 \u043F\u0438\u0448\u0443\u0442: \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u044C \u0432\u0432\u043E\u0434\u0438\u0442 \u0435\u0433\u043E \u0432 \u043F\u043E\u0434\u043A\u043B\u044E\u0447\u0435\u043D\u0438\u0438 \u043F\u0440\u043E\u0435\u043A\u0442\u0430.
5145
+
5146
+ ## \u0421\u0442\u0440\u0443\u043A\u0442\u0443\u0440\u0430
5147
+ - \`format: 1\`; \`kind\` \u2014 \u0441\u043B\u0430\u0433 \u0432\u0438\u0434\u0430 (\`gitea\`, \u043B\u0430\u0442\u0438\u043D\u0438\u0446\u0430, \u0446\u0438\u0444\u0440\u044B \u0438 \xAB-\xBB), \u0432\u0438\u0434\u044B \u0432\u0441\u0442\u0440\u043E\u0435\u043D\u043D\u044B\u0445 \u0442\u0440\u0435\u043A\u0435\u0440\u043E\u0432 \u0437\u0430\u043D\u044F\u0442\u044B;
5148
+ \`title\` \u2014 \u0438\u043C\u044F \u0432 \u0438\u043D\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0435.
5149
+ - \`fields\` \u2014 \u043F\u043E\u043B\u044F \u0444\u043E\u0440\u043C\u044B \u043F\u043E\u0434\u043A\u043B\u044E\u0447\u0435\u043D\u0438\u044F: \`url\`, \`target\`, \`user\`, \`token\` (\`name\`, \`required\`, \`secret\`);
5150
+ \u0441\u0435\u043A\u0440\u0435\u0442\u043D\u043E\u0435 \u2014 \u0442\u043E\u043B\u044C\u043A\u043E \`token\`, \u0438 \u043E\u043D\u043E \u0432\u0441\u0435\u0433\u0434\u0430 \u0441\u0435\u043A\u0440\u0435\u0442\u043D\u043E\u0435.
5151
+ - \`http.base\` \u2014 \u0430\u0434\u0440\u0435\u0441 API: \`https://api.example.com/v1\` \u0438\u043B\u0438 \`{{url}}/api/v1\` (url \u043F\u043E\u0434\u043A\u043B\u044E\u0447\u0435\u043D\u0438\u044F \u0437\u0430\u0434\u0430\u0451\u0442 origin, \u043F\u043E\u0441\u043B\u0435
5152
+ \u043D\u0435\u0433\u043E \u2014 \u0442\u043E\u043B\u044C\u043A\u043E \u043F\u0443\u0442\u044C \u043E\u0442 \xAB/\xBB). \u0422\u043E\u043A\u0435\u043D \u0443\u0445\u043E\u0434\u0438\u0442 \u0442\u043E\u043B\u044C\u043A\u043E \u043D\u0430 origin \u0431\u0430\u0437\u044B, \u0432\u0441\u0435 \u0437\u0430\u043F\u0440\u043E\u0441\u044B \u043E\u0441\u0442\u0430\u044E\u0442\u0441\u044F \u043F\u043E\u0434 \u0435\u0451 \u043F\u0443\u0442\u0451\u043C.
5153
+ - \`http.auth\` \u2014 \`{ kind: bearer }\` (Authorization: Bearer), \`{ kind: header, header, prefix }\` (\u0441\u0432\u043E\u0439 \u0437\u0430\u0433\u043E\u043B\u043E\u0432\u043E\u043A),
5154
+ \`{ kind: basic }\` (\u043F\u043E\u043B\u044F user \u0438 token) \u0438\u043B\u0438 \`{ kind: none }\`.
5155
+ - \`http.headers\` \u2014 \u043F\u043E\u0441\u0442\u043E\u044F\u043D\u043D\u044B\u0435 \u0437\u0430\u0433\u043E\u043B\u043E\u0432\u043A\u0438 (Accept, \u0432\u0435\u0440\u0441\u0438\u044F API); \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u044F \u2014 \u043B\u0438\u0442\u0435\u0440\u0430\u043B\u044B \u0438\u043B\u0438 \u043F\u043E\u043B\u044F \u043F\u043E\u0434\u043A\u043B\u044E\u0447\u0435\u043D\u0438\u044F.
5156
+ - \`http.pagination\` \u2014 \`{ style: page, page, size, next }\` (\u043D\u043E\u043C\u0435\u0440 \u0441\u0442\u0440\u0430\u043D\u0438\u0446\u044B \u0441 1; \u0441\u043B\u0435\u0434\u0443\u044E\u0449\u0430\u044F \u2014 \`link\` \u043F\u043E \u0437\u0430\u0433\u043E\u043B\u043E\u0432\u043A\u0443
5157
+ Link, \`count\` \u043F\u043E \u043F\u043E\u043B\u043D\u043E\u0439 \u0441\u0442\u0440\u0430\u043D\u0438\u0446\u0435, \`{ header }\` \u0438\u043B\u0438 \`{ path }\` \u0441 \u043D\u043E\u043C\u0435\u0440\u043E\u043C), \`{ style: cursor, param, size, next }\`
5158
+ (\u043A\u0443\u0440\u0441\u043E\u0440 \u2014 \u043F\u0443\u0442\u044C JSON \u0438\u043B\u0438 \`{ header }\`) \u0438\u043B\u0438 \`{ style: none }\`; \u0443 \u043E\u043F\u0435\u0440\u0430\u0446\u0438\u0438-\u0441\u043F\u0438\u0441\u043A\u0430 \u0431\u044B\u0432\u0430\u0435\u0442 \u0441\u0432\u043E\u044F \`pagination\`.
5159
+
5160
+ ## \u041E\u043F\u0435\u0440\u0430\u0446\u0438\u0438 \u0438 \u0438\u0445 \u0432\u0445\u043E\u0434\u044B (\u043E\u0431\u044F\u0437\u0430\u0442\u0435\u043B\u044C\u043D\u044B\u0435 \u2014 \u0436\u0438\u0440\u043D\u044B\u043C)
5161
+ ${Object.keys(SECTION_TITLES).map(operationLines).join("\n")}
5162
+
5163
+ \u041E\u043F\u0435\u0440\u0430\u0446\u0438\u044F: \`method\` (GET \u043F\u043E \u0443\u043C\u043E\u043B\u0447\u0430\u043D\u0438\u044E; POST, PUT, PATCH), \`path\` \u043E\u0442 \`http.base\` (\u0441 \xAB/\xBB), \`query\`, \`body\`, \`inputs\`,
5164
+ \`items\`, \`result\`. \u0411\u0435\u0437 \u043E\u043F\u0435\u0440\u0430\u0446\u0438\u0438 \u043D\u0435\u0442 \u0438 \u0432\u043E\u0437\u043C\u043E\u0436\u043D\u043E\u0441\u0442\u0438: create, update, comment, \u0441\u043B\u0438\u044F\u043D\u0438\u0435, \u0437\u0430\u043F\u0443\u0441\u043A CI \u043E\u0442\u043A\u0430\u0437\u044B\u0432\u0430\u044E\u0442
5165
+ unsupported. \u041B\u043E\u0433 \u0437\u0430\u0434\u0430\u043D\u0438\u044F \u0447\u0438\u0442\u0430\u0435\u0442 \u0441\u043E\u0441\u0442\u043E\u044F\u043D\u0438\u0435 \u0437\u0430\u0434\u0430\u043D\u0438\u044F \u043E\u043F\u0435\u0440\u0430\u0446\u0438\u0435\u0439 \`job\`; \u043F\u0435\u0440\u0435\u0437\u0430\u043F\u0443\u0441\u043A \u0437\u0430\u0434\u0430\u043D\u0438\u044F \u0438 \u043E\u0442\u043C\u0435\u043D\u0430 \u0437\u0430\u0434\u0430\u043D\u0438\u044F \u2014 \u0442\u043E\u0436\u0435.
5166
+
5167
+ ## \u0428\u0430\u0431\u043B\u043E\u043D\u044B
5168
+ - \u041F\u043B\u0435\u0439\u0441\u0445\u043E\u043B\u0434\u0435\u0440\u044B \u2014 \`{{\u0438\u043C\u044F}}\`: \u043F\u043E\u043B\u044F \u043F\u043E\u0434\u043A\u043B\u044E\u0447\u0435\u043D\u0438\u044F \`{{url}}\`, \`{{target}}\`, \`{{user}}\` (\u043E\u0431\u044A\u044F\u0432\u043B\u0435\u043D\u043D\u044B\u0435 \u0432 fields) \u0438 \u0432\u0445\u043E\u0434\u044B
5169
+ \u043E\u043F\u0435\u0440\u0430\u0446\u0438\u0438. \u0412\u0435\u0442\u043A\u0438 PR \u0432\u043E \u0432\u0445\u043E\u0434\u0430\u0445 \u2014 \`sourceBranch\` \u0438 \`targetBranch\` (\`target\` \u2014 \u043F\u043E\u043B\u0435 \u043F\u043E\u0434\u043A\u043B\u044E\u0447\u0435\u043D\u0438\u044F).
5170
+ - \u0412 \u043F\u0443\u0442\u0438 \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0435 \u043A\u043E\u0434\u0438\u0440\u0443\u0435\u0442\u0441\u044F \u043A\u0430\u043A \u043E\u0434\u0438\u043D \u0441\u0435\u0433\u043C\u0435\u043D\u0442; \`{{\u0438\u043C\u044F|path}}\` \u2014 \u043F\u0443\u0442\u044C \u0438\u0437 \u0441\u0435\u0433\u043C\u0435\u043D\u0442\u043E\u0432 \u0447\u0435\u0440\u0435\u0437 \xAB/\xBB (\`owner/repo\`),
5171
+ \u043F\u0443\u0441\u0442\u044B\u0435 \u0441\u0435\u0433\u043C\u0435\u043D\u0442\u044B, \xAB.\xBB, \xAB..\xBB, \xAB\\\xBB \u0438 \u0443\u043F\u0440\u0430\u0432\u043B\u044F\u044E\u0449\u0438\u0435 \u0441\u0438\u043C\u0432\u043E\u043B\u044B \u2014 \u043E\u0442\u043A\u0430\u0437. \u0412\u0445\u043E\u0434\u0443 \u043E\u043F\u0435\u0440\u0430\u0446\u0438\u0438 \xAB/\xBB \u0432\u043D\u0435 \`|path\` \u0438 \`%2F\`/\`%5C\` \u2014
5172
+ \u043E\u0442\u043A\u0430\u0437; \u043F\u043E\u043B\u0435 \u043F\u043E\u0434\u043A\u043B\u044E\u0447\u0435\u043D\u0438\u044F \u0432 \u043F\u0440\u043E\u0441\u0442\u043E\u043C \u043F\u043B\u0435\u0439\u0441\u0445\u043E\u043B\u0434\u0435\u0440\u0435 \u0443\u0445\u043E\u0434\u0438\u0442 \u0441 \xAB/\xBB \u043A\u0430\u043A \`%2F\` (\`o/r\` \u2192 \`o%2Fr\`, \u043A\u0430\u043A \u0443 GitLab). \u0412 query
5173
+ \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0435 \u043A\u043E\u0434\u0438\u0440\u0443\u0435\u0442 \u043A\u043B\u0438\u0435\u043D\u0442, \u0432 \u0437\u0430\u0433\u043E\u043B\u043E\u0432\u043A\u0435 \u043F\u0435\u0440\u0435\u0432\u043E\u0434 \u0441\u0442\u0440\u043E\u043A\u0438 \u2014 \u043E\u0442\u043A\u0430\u0437.
5174
+ - \u041D\u0435\u0442 \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u044F \u2014 \u043F\u0430\u0440\u0430\u043C\u0435\u0442\u0440 query \u0438\u043B\u0438 \u043F\u043E\u043B\u0435 body \u043F\u0440\u043E\u043F\u0443\u0441\u043A\u0430\u044E\u0442\u0441\u044F, \u0430 \u0432 \u043F\u0443\u0442\u0438 \u2014 \u043E\u0442\u043A\u0430\u0437 \u0437\u0430\u043F\u0440\u043E\u0441\u0430. \u041F\u043E\u043B\u0435 body, \u0440\u0430\u0432\u043D\u043E\u0435 \u0440\u043E\u0432\u043D\u043E
5175
+ \u043E\u0434\u043D\u043E\u043C\u0443 \u043F\u043B\u0435\u0439\u0441\u0445\u043E\u043B\u0434\u0435\u0440\u0443, \u0441\u043E\u0445\u0440\u0430\u043D\u044F\u0435\u0442 \u0442\u0438\u043F: \u0444\u043B\u0430\u0433, \u0441\u043F\u0438\u0441\u043E\u043A, null, \u0441\u043B\u043E\u0432\u0430\u0440\u044C (\`{{inputs}}\` \u0437\u0430\u043F\u0443\u0441\u043A\u0430 CI). \u0421\u043F\u0438\u0441\u043A\u0438 \u0432 \u0442\u0435\u043A\u0441\u0442\u0435 \u2014 \u0447\u0435\u0440\u0435\u0437
5176
+ \u0437\u0430\u043F\u044F\u0442\u0443\u044E. \u0412\u0440\u0435\u043C\u044F \u2014 ISO 8601 UTC.
5177
+ - \`inputs\` \u2014 \u0442\u0430\u0431\u043B\u0438\u0446\u044B \xAB\u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0435 \u0435\u0434\u0438\u043D\u043E\u0439 \u043C\u043E\u0434\u0435\u043B\u0438 \u2192 \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0435 API\xBB \u0443 \u0432\u0445\u043E\u0434\u043E\u0432 \u0441 \u043F\u0435\u0440\u0435\u0447\u043D\u0435\u043C (\u0441\u0442\u0430\u0442\u0443\u0441\u044B, \u043F\u0440\u0438\u043E\u0440\u0438\u0442\u0435\u0442, \u0441\u043F\u043E\u0441\u043E\u0431
5178
+ \u0441\u043B\u0438\u044F\u043D\u0438\u044F, \u0441\u043E\u0431\u044B\u0442\u0438\u0435 CI, sort, direction, order, \u0444\u043B\u0430\u0433\u0438 \`"true"\`/\`"false"\`). \u0417\u043D\u0430\u0447\u0435\u043D\u0438\u044F \u043D\u0435\u0442 \u0432 \u0442\u0430\u0431\u043B\u0438\u0446\u0435 \u2014 \u043E\u0442\u043A\u0430\u0437
5179
+ unsupported; \u0443 \u0444\u0438\u043B\u044C\u0442\u0440\u0430 \u0441\u043F\u0438\u0441\u043A\u0430 \u043A\u043B\u044E\u0447 \`"*"\` \u2014 \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0435 \u0434\u043B\u044F \xAB\u043D\u0435\u0441\u043A\u043E\u043B\u044C\u043A\u0438\u0445 \u0441\u0440\u0430\u0437\u0443\xBB, \u043B\u0438\u0448\u043D\u0435\u0435 \u043E\u0442\u0441\u0435\u0435\u0442 \u043F\u0440\u043E\u0432\u0435\u0440\u043A\u0430 \u0441\u0442\u0440\u0430\u043D\u0438\u0446\u044B;
5180
+ \u043A\u043B\u044E\u0447 \`"null"\` \u0443 assignee \u2014 \xAB\u0431\u0435\u0437 \u0438\u0441\u043F\u043E\u043B\u043D\u0438\u0442\u0435\u043B\u044F\xBB. \u0421\u043E\u0440\u0442\u0438\u0440\u043E\u0432\u043A\u0435 \u043D\u0443\u0436\u043D\u044B \`{{sort}}\` \u0441 \u0442\u0430\u0431\u043B\u0438\u0446\u0435\u0439 \u0438 \`{{direction}}\`.
5181
+
5182
+ ## \u0420\u0435\u0437\u0443\u043B\u044C\u0442\u0430\u0442
5183
+ - \`items\` \u2014 \u043F\u0443\u0442\u044C JSON \u043A \u044D\u043B\u0435\u043C\u0435\u043D\u0442\u0443 \u0438\u043B\u0438 \u0441\u043F\u0438\u0441\u043A\u0443 (\`$.workflow_runs\`); \u0431\u0435\u0437 \u043D\u0435\u0433\u043E \u043E\u0442\u0432\u0435\u0442 \u2014 \u0441\u0430\u043C \u044D\u043B\u0435\u043C\u0435\u043D\u0442 \u0438\u043B\u0438 \u0441\u043F\u0438\u0441\u043E\u043A.
5184
+ - \`result\` \u2014 \u043F\u043E\u043B\u0435 \u0435\u0434\u0438\u043D\u043E\u0439 \u043C\u043E\u0434\u0435\u043B\u0438 \u2192 \u043F\u0443\u0442\u044C JSON (\`$.a.b\`, \`$.items[0]\`, \`$.labels[*].name\` \u2014 \u0442\u043E\u043B\u044C\u043A\u043E \u0443 \u0441\u043F\u0438\u0441\u043A\u043E\u0432) \u0438\u043B\u0438
5185
+ \`{ path, map, default, exists }\`, \u0438\u043B\u0438 \u0446\u0435\u043F\u043E\u0447\u043A\u0430 \u0442\u0430\u043A\u0438\u0445 \u0437\u0432\u0435\u043D\u044C\u0435\u0432: \u0440\u0435\u0448\u0430\u0435\u0442 \u043F\u0435\u0440\u0432\u043E\u0435, \u0443 \u043A\u043E\u0442\u043E\u0440\u043E\u0433\u043E \u043F\u043E \u043F\u0443\u0442\u0438 \u0435\u0441\u0442\u044C \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0435
5186
+ (\u0435\u0433\u043E \`map\`, \u0430 \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u044F \u043D\u0435\u0442 \u0432 map \u2014 \u0435\u0433\u043E \`default\`); \u043D\u0438 \u043E\u0434\u043D\u043E \u043D\u0435 \u043D\u0430\u0448\u043B\u043E \u2014 \`default\` \u043F\u043E\u0441\u043B\u0435\u0434\u043D\u0435\u0433\u043E. \`exists: true\` \u2014 \u0444\u043B\u0430\u0433
5187
+ \xAB\u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0435 \u0435\u0441\u0442\u044C\xBB. \`url\` \u2014 \u043F\u0435\u0440\u0432\u0430\u044F \u0441\u0441\u044B\u043B\u043A\u0430 \u044D\u043B\u0435\u043C\u0435\u043D\u0442\u0430. \u0421\u0432\u043E\u0451 \u0438\u043C\u044F \u0441\u0442\u0430\u0442\u0443\u0441\u0430 (\`status.name\`) \u043F\u043E \u0443\u043C\u043E\u043B\u0447\u0430\u043D\u0438\u044E \u2014 \u0438\u0441\u0445\u043E\u0434\u043D\u043E\u0435
5188
+ \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0435. \u0423 PR \u0444\u043B\u0430\u0433 \`merged\` \u0438\u043B\u0438 \u0432\u0440\u0435\u043C\u044F \`mergedAt\` \u0434\u0435\u043B\u0430\u044E\u0442 \u043A\u0430\u0442\u0435\u0433\u043E\u0440\u0438\u044E merged, \u0444\u043B\u0430\u0433 \`draft\` \u2014 draft.
5189
+ - \u041F\u043E\u043B\u044F \u043C\u043E\u0434\u0435\u043B\u0435\u0439 (\u043E\u0431\u044F\u0437\u0430\u0442\u0435\u043B\u044C\u043D\u044B\u0435 \u2014 \u0436\u0438\u0440\u043D\u044B\u043C; \u0443 \`ci.job\` \u043E\u0431\u044F\u0437\u0430\u0442\u0435\u043B\u0435\u043D \u0438 runKey):
5190
+ ${fieldLines()}
5191
+ - \u041A\u0430\u0436\u0434\u044B\u0439 \u044D\u043B\u0435\u043C\u0435\u043D\u0442 \u043E\u0442\u0432\u0435\u0442\u0430 \u043F\u0440\u043E\u0432\u0435\u0440\u044F\u0435\u0442\u0441\u044F \u0441\u0445\u0435\u043C\u043E\u0439 \u0435\u0434\u0438\u043D\u043E\u0439 \u043C\u043E\u0434\u0435\u043B\u0438: \u043D\u0435 \u043B\u0435\u0433\u043B\u043E \u2014 \u043E\u0442\u043A\u0430\u0437 failed \u0441 \u043F\u043E\u043B\u0435\u043C, \u0430 \u043D\u0435 \u043C\u0443\u0441\u043E\u0440.
5192
+
5193
+ ## \u0412\u043E\u0437\u043C\u043E\u0436\u043D\u043E\u0441\u0442\u0438
5194
+ \u0412\u043E\u0437\u043C\u043E\u0436\u043D\u043E\u0441\u0442\u0438 \u0432\u044B\u0432\u043E\u0434\u044F\u0442\u0441\u044F \u0438\u0437 \u043E\u043F\u0435\u0440\u0430\u0446\u0438\u0439: \u0444\u0438\u043B\u044C\u0442\u0440 \u0441\u043F\u0438\u0441\u043A\u0430 \u0435\u0441\u0442\u044C, \u0435\u0441\u043B\u0438 \u0435\u0433\u043E \u0432\u0445\u043E\u0434 \u0441\u0442\u043E\u0438\u0442 \u0432 \u0448\u0430\u0431\u043B\u043E\u043D\u0430\u0445 (\u0444\u0438\u043B\u044C\u0442\u0440\u0443\u0435\u0442 API) \u0438\u043B\u0438 result
5195
+ \u0437\u0430\u043F\u043E\u043B\u043D\u044F\u0435\u0442 \u043F\u043E\u043B\u044F \u0434\u043B\u044F \u043F\u0440\u043E\u0432\u0435\u0440\u043A\u0438 \u043F\u043E \u0441\u0442\u0440\u0430\u043D\u0438\u0446\u0435; \u0432\u0445\u043E\u0434 \u0447\u0435\u0440\u0435\u0437 \u0442\u0430\u0431\u043B\u0438\u0446\u0443 \u043F\u0440\u043E\u0432\u0435\u0440\u044F\u0435\u0442\u0441\u044F \u0438 \u043F\u043E \u0441\u0442\u0440\u0430\u043D\u0438\u0446\u0435. \u0421\u0442\u0430\u0442\u0443\u0441\u044B \u043F\u0440\u0430\u0432\u043A\u0438 \u2014 \u043A\u043B\u044E\u0447\u0438
5196
+ \u0442\u0430\u0431\u043B\u0438\u0446\u044B \`status\` \u043E\u043F\u0435\u0440\u0430\u0446\u0438\u0438 update; \u0441\u043F\u043E\u0441\u043E\u0431\u044B \u0441\u043B\u0438\u044F\u043D\u0438\u044F \u2014 \u043A\u043B\u044E\u0447\u0438 \u0442\u0430\u0431\u043B\u0438\u0446\u044B \`method\`, \u0431\u0435\u0437 \`{{method}}\` \u2014 \u0442\u043E\u043B\u044C\u043A\u043E merge.
5197
+
5198
+ ## \u0411\u0435\u0437\u043E\u043F\u0430\u0441\u043D\u043E\u0441\u0442\u044C
5199
+ - \u041F\u043B\u0435\u0439\u0441\u0445\u043E\u043B\u0434\u0435\u0440\u0430 \`{{token}}\` \u043D\u0435\u0442: \u0442\u043E\u043A\u0435\u043D \u043F\u043E\u0434\u0441\u0442\u0430\u0432\u043B\u044F\u0435\u0442 \u0442\u043E\u043B\u044C\u043A\u043E \`http.auth\`, \u0438 \u0442\u043E\u043B\u044C\u043A\u043E \u0434\u043B\u044F origin \`http.base\`.
5200
+ - \u0410\u0434\u0440\u0435\u0441 \u043D\u0435 \u043F\u043E\u043A\u0438\u0434\u0430\u0435\u0442 origin \u0438 \u043F\u0443\u0442\u044C \u0431\u0430\u0437\u044B: \u043F\u0443\u0442\u044C \u043E\u043F\u0435\u0440\u0430\u0446\u0438\u0438 \u2014 \u0441 \u043E\u0434\u043D\u043E\u0433\u043E \xAB/\xBB, \u0431\u0435\u0437 \xAB?\xBB, \xAB#\xBB, \xAB%\xBB, \xAB\\\xBB \u0438 \u0441\u0435\u0433\u043C\u0435\u043D\u0442\u043E\u0432 \xAB.\xBB/\xAB..\xBB.
5201
+ - \u0421\u0435\u043A\u0440\u0435\u0442\u043D\u044B\u0435 \u0437\u0430\u0433\u043E\u043B\u043E\u0432\u043A\u0438 (Authorization, Cookie, X-Api-Key, *-Token\u2026) \u0432 \`http.headers\` \u0438 \u0441\u0435\u043A\u0440\u0435\u0442\u043D\u044B\u0435 \u043F\u0430\u0440\u0430\u043C\u0435\u0442\u0440\u044B query
5202
+ \u0437\u0430\u043F\u0440\u0435\u0449\u0435\u043D\u044B; \u0430\u0432\u0442\u043E\u0440\u0438\u0437\u0430\u0446\u0438\u044F \u2014 \u0442\u043E\u043B\u044C\u043A\u043E \`http.auth\`.
5203
+ - \u0422\u0435\u043A\u0441\u0442, \u043F\u043E\u0445\u043E\u0436\u0438\u0439 \u043D\u0430 \u0441\u0435\u043A\u0440\u0435\u0442 (\u0442\u043E\u043A\u0435\u043D\u044B, \u043F\u0430\u0440\u043E\u043B\u0438, \u043A\u043B\u044E\u0447\u0438, \u0430\u0434\u0440\u0435\u0441 \u0441 \u043F\u0430\u0440\u043E\u043B\u0435\u043C), \u0434\u0430\u0436\u0435 \u0432 \u043A\u043E\u043C\u043C\u0435\u043D\u0442\u0430\u0440\u0438\u0438 YAML \u2014 \u043E\u0448\u0438\u0431\u043A\u0430.
5204
+ - \u041A\u043E\u043D\u0444\u0438\u0433 \u043D\u0435 \u0431\u043E\u043B\u044C\u0448\u0435 ${String(TRACKER_CONFIG_MAX_BYTES / 1024)} \u041A\u0438\u0411; \u044F\u043A\u043E\u0440\u044F YAML (\`&\u0438\u043C\u044F\`, \`*\u0438\u043C\u044F\`) \u2014 \u0442\u043E\u043B\u044C\u043A\u043E \u043A\u0430\u043A \u043F\u043E\u0432\u0442\u043E\u0440 \u0431\u043B\u043E\u043A\u0430.
5205
+
5206
+ ## \u041F\u0440\u0438\u043C\u0435\u0440 (Gitea)
5207
+ \`\`\`yaml
5208
+ ${TRACKER_CONFIG_EXAMPLE}\`\`\`
5209
+ `;
3290
5210
  export {
3291
5211
  ALL_STATUSES,
5212
+ BUILTIN_TRACKER_KINDS,
3292
5213
  CI_FINISHED_STATUSES,
3293
5214
  CI_LOG_DEFAULT_BYTES,
3294
5215
  CI_LOG_MAX_BYTES,
@@ -3323,12 +5244,19 @@ export {
3323
5244
  SOURCECRAFT_STATUSES,
3324
5245
  SOURCECRAFT_STATUS_FILTER,
3325
5246
  SOURCECRAFT_STATUS_SLUGS,
5247
+ TRACKER_CONFIG_DEPTH_MAX,
5248
+ TRACKER_CONFIG_EXAMPLE,
5249
+ TRACKER_CONFIG_HINT,
5250
+ TRACKER_CONFIG_ISSUES_MAX,
5251
+ TRACKER_CONFIG_MAX_BYTES,
5252
+ TRACKER_CONFIG_YAML_ALIAS_MAX,
3326
5253
  TRACKER_ERROR_BODY_MAX,
3327
5254
  TRACKER_LOCAL_AUTHOR,
3328
5255
  TRACKER_PAGE_LIMIT_DEFAULT,
3329
5256
  TRACKER_REDIRECT_MAX,
3330
5257
  TRACKER_SECRETS_FILE,
3331
5258
  TRACKER_TIMEOUT_MS,
5259
+ TrackerConfigError,
3332
5260
  TrackerError,
3333
5261
  assertCommentQuery,
3334
5262
  assertListQuery,
@@ -3349,6 +5277,7 @@ export {
3349
5277
  cleanLogText,
3350
5278
  clipText,
3351
5279
  containsText,
5280
+ definitionFromConfig,
3352
5281
  deleteTrackerToken,
3353
5282
  findTracker,
3354
5283
  githubCi,
@@ -3392,6 +5321,7 @@ export {
3392
5321
  requestText,
3393
5322
  requireTarget,
3394
5323
  setSecretSink,
5324
+ setUserTrackers,
3395
5325
  sourcecraftCi,
3396
5326
  sourcecraftPulls,
3397
5327
  sourcecraftRepo,
@@ -3399,7 +5329,10 @@ export {
3399
5329
  stringList,
3400
5330
  text,
3401
5331
  toTimestamp,
5332
+ trackerConfigSchema,
5333
+ trackerSecretsFile,
3402
5334
  usedFilters,
5335
+ validateTrackerConfig,
3403
5336
  writeTrackerToken
3404
5337
  };
3405
5338
  //# sourceMappingURL=index.js.map