@gh-symphony/cli 0.4.0 → 0.4.2

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.
@@ -1,14 +1,14 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  resolveRepoRuntimeRoot
4
- } from "./chunk-RZ3WO7OV.js";
4
+ } from "./chunk-3IRPSPAF.js";
5
5
  import {
6
6
  parseWorkflowMarkdown
7
- } from "./chunk-6OPRRC2J.js";
7
+ } from "./chunk-LJUEOVAQ.js";
8
8
  import {
9
9
  saveGlobalConfig,
10
10
  saveProjectConfig
11
- } from "./chunk-4ICDSQCJ.js";
11
+ } from "./chunk-YZP5N5XP.js";
12
12
 
13
13
  // src/repo-runtime.ts
14
14
  import { execFileSync } from "child_process";
@@ -68,6 +68,9 @@ async function initRepoRuntime(flags) {
68
68
  ...trackerAdapter === "linear" ? { activeStates: workflow.tracker.activeStates.join("\n") } : {},
69
69
  repository: `${repository.owner}/${repository.name}`
70
70
  };
71
+ if (trackerAdapter === "linear" && (workflow.tracker.pickupLabels.include.length > 0 || workflow.tracker.pickupLabels.exclude.length > 0)) {
72
+ trackerSettings.pickupLabels = workflow.tracker.pickupLabels;
73
+ }
71
74
  if (workflow.tracker.priorityFieldName) {
72
75
  trackerSettings.priorityFieldName = workflow.tracker.priorityFieldName;
73
76
  }
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  REPO_RUNTIME_DIR
4
- } from "./chunk-4ICDSQCJ.js";
4
+ } from "./chunk-YZP5N5XP.js";
5
5
 
6
6
  // src/orchestrator-runtime.ts
7
7
  import { resolve } from "path";
@@ -30,11 +30,11 @@ import {
30
30
  resolveWorkflowRuntimeTimeouts,
31
31
  safeReadDir,
32
32
  scheduleRetryAt
33
- } from "./chunk-6OPRRC2J.js";
33
+ } from "./chunk-LJUEOVAQ.js";
34
34
  import {
35
35
  loadGlobalConfig,
36
36
  loadProjectConfig
37
- } from "./chunk-4ICDSQCJ.js";
37
+ } from "./chunk-YZP5N5XP.js";
38
38
 
39
39
  // ../tracker-github/src/adapter.ts
40
40
  import { createHash } from "crypto";
@@ -1865,7 +1865,9 @@ var linearTrackerAdapter = {
1865
1865
  return listLinearIssues(
1866
1866
  project,
1867
1867
  project.tracker.settings?.activeStates,
1868
- dependencies
1868
+ dependencies,
1869
+ void 0,
1870
+ { applyPickupLabels: true }
1869
1871
  );
1870
1872
  },
1871
1873
  async listIssuesByStates(project, states, dependencies = {}) {
@@ -1914,7 +1916,7 @@ var linearTrackerAdapter = {
1914
1916
  };
1915
1917
  }
1916
1918
  };
1917
- async function listLinearIssues(project, stateNamesInput, dependencies, issueIds) {
1919
+ async function listLinearIssues(project, stateNamesInput, dependencies, issueIds, options = {}) {
1918
1920
  const config = resolveLinearTrackerConfig(project, dependencies);
1919
1921
  const client = createLinearGraphqlClient(config, dependencies.fetchImpl);
1920
1922
  const stateNames = readStringArray(stateNamesInput);
@@ -1931,10 +1933,15 @@ async function listLinearIssues(project, stateNamesInput, dependencies, issueIds
1931
1933
  assignedOnly: config.assignedOnly,
1932
1934
  pageSize: config.pageSize
1933
1935
  });
1934
- const issues = result.nodes.map(
1936
+ const fetchedIssues = result.nodes.map(
1935
1937
  (node) => normalizeLinearIssue(project, config.projectSlug, node, result.rateLimits)
1936
1938
  );
1937
- Object.defineProperty(issues, "rateLimits", {
1939
+ const filteredIssues = options.applyPickupLabels ? filterIssuesByPickupLabels(
1940
+ fetchedIssues,
1941
+ config.pickupLabels,
1942
+ config.projectSlug
1943
+ ) : fetchedIssues;
1944
+ Object.defineProperty(filteredIssues, "rateLimits", {
1938
1945
  configurable: true,
1939
1946
  enumerable: false,
1940
1947
  value: result.rateLimits,
@@ -1943,10 +1950,10 @@ async function listLinearIssues(project, stateNamesInput, dependencies, issueIds
1943
1950
  if (config.assignedOnly) {
1944
1951
  emitAssignedOnlyFilterEvent2({
1945
1952
  projectSlug: config.projectSlug,
1946
- includedCount: issues.length
1953
+ includedCount: filteredIssues.length
1947
1954
  });
1948
1955
  }
1949
- return issues;
1956
+ return filteredIssues;
1950
1957
  }
1951
1958
  async function fetchPaginatedLinearIssues(client, input) {
1952
1959
  const issues = [];
@@ -2100,6 +2107,7 @@ function resolveLinearTrackerConfig(project, dependencies) {
2100
2107
  endpoint: resolveLinearEndpoint(project.tracker),
2101
2108
  assignedOnly: resolveAssignedOnly2(project.tracker, dependencies),
2102
2109
  pageSize: readPositiveIntegerSetting(project.tracker, "pageSize") ?? DEFAULT_PAGE_SIZE2,
2110
+ pickupLabels: resolvePickupLabels(project.tracker),
2103
2111
  projectSlug,
2104
2112
  token
2105
2113
  };
@@ -2155,6 +2163,24 @@ function readBooleanSetting(tracker, key) {
2155
2163
  const value = tracker.settings?.[key];
2156
2164
  return value === true || value === "true";
2157
2165
  }
2166
+ function resolvePickupLabels(tracker) {
2167
+ const pickupLabels = readObjectSetting(tracker, "pickupLabels") ?? readObjectSetting(tracker, "pickup_labels");
2168
+ return {
2169
+ include: normalizeConfiguredLabels(
2170
+ readStringArray(pickupLabels?.include) ?? []
2171
+ ),
2172
+ exclude: normalizeConfiguredLabels(
2173
+ readStringArray(pickupLabels?.exclude) ?? []
2174
+ )
2175
+ };
2176
+ }
2177
+ function readObjectSetting(tracker, key) {
2178
+ const value = tracker.settings?.[key];
2179
+ if (value === void 0 || value === null || Array.isArray(value) || typeof value !== "object") {
2180
+ return void 0;
2181
+ }
2182
+ return value;
2183
+ }
2158
2184
  function readStringArray(value) {
2159
2185
  if (value === void 0) {
2160
2186
  return void 0;
@@ -2167,6 +2193,35 @@ function readStringArray(value) {
2167
2193
  }
2168
2194
  return value.filter((entry) => typeof entry === "string");
2169
2195
  }
2196
+ function normalizeConfiguredLabels(labels) {
2197
+ return Array.from(
2198
+ new Set(
2199
+ labels.map((label) => label.trim()).filter((label) => label.length > 0)
2200
+ )
2201
+ );
2202
+ }
2203
+ function filterIssuesByPickupLabels(issues, config, projectSlug) {
2204
+ if (config.include.length === 0 && config.exclude.length === 0) {
2205
+ return issues;
2206
+ }
2207
+ const includeLabels = new Set(config.include);
2208
+ const excludeLabels = new Set(config.exclude);
2209
+ const filtered = issues.filter((issue) => {
2210
+ const issueLabels = new Set(issue.labels);
2211
+ if (config.exclude.some((label) => issueLabels.has(label))) {
2212
+ return false;
2213
+ }
2214
+ return includeLabels.size === 0 || config.include.some((label) => issueLabels.has(label));
2215
+ });
2216
+ emitPickupLabelFilterEvent({
2217
+ projectSlug,
2218
+ include: [...includeLabels],
2219
+ exclude: [...excludeLabels],
2220
+ includedCount: filtered.length,
2221
+ excludedCount: issues.length - filtered.length
2222
+ });
2223
+ return filtered;
2224
+ }
2170
2225
  function emitAssignedOnlyFilterEvent2(input) {
2171
2226
  console.info(
2172
2227
  JSON.stringify({
@@ -2179,6 +2234,19 @@ function emitAssignedOnlyFilterEvent2(input) {
2179
2234
  })
2180
2235
  );
2181
2236
  }
2237
+ function emitPickupLabelFilterEvent(input) {
2238
+ console.info(
2239
+ JSON.stringify({
2240
+ event: "tracker-pickup-label-filtered",
2241
+ tracker: "linear",
2242
+ projectSlug: input.projectSlug,
2243
+ include: input.include,
2244
+ exclude: input.exclude,
2245
+ includedCount: input.includedCount,
2246
+ excludedCount: input.excludedCount
2247
+ })
2248
+ );
2249
+ }
2182
2250
  function requireString(value, label) {
2183
2251
  if (typeof value !== "string" || value.length === 0) {
2184
2252
  throw new Error(`${label} is required.`);
@@ -52,6 +52,10 @@ var DEFAULT_WORKFLOW_TRACKER = {
52
52
  endpoint: null,
53
53
  apiKey: null,
54
54
  projectSlug: null,
55
+ pickupLabels: {
56
+ include: [],
57
+ exclude: []
58
+ },
55
59
  activeStates: DEFAULT_WORKFLOW_LIFECYCLE.activeStates,
56
60
  terminalStates: DEFAULT_WORKFLOW_LIFECYCLE.terminalStates,
57
61
  projectId: null,
@@ -171,6 +175,7 @@ function parseWorkflowMarkdown(markdown, env = process.env, options = {}) {
171
175
  endpoint: readOptionalString(tracker, "endpoint", env) ?? (trackerKind === "linear" ? DEFAULT_LINEAR_GRAPHQL_URL : null),
172
176
  apiKey: readOptionalString(tracker, "api_key", env),
173
177
  projectSlug: readOptionalString(tracker, "project_slug", env),
178
+ pickupLabels: readPickupLabelsConfig(tracker),
174
179
  activeStates,
175
180
  terminalStates,
176
181
  projectId: readOptionalString(tracker, "project_id", env),
@@ -244,6 +249,22 @@ function validateTrackerConfig(tracker, trackerKind, env) {
244
249
  }
245
250
  }
246
251
  }
252
+ function readPickupLabelsConfig(tracker) {
253
+ const value = tracker.pickup_labels ?? tracker.pickupLabels;
254
+ if (value === void 0 || value === null) {
255
+ return DEFAULT_WORKFLOW_TRACKER.pickupLabels;
256
+ }
257
+ if (Array.isArray(value) || typeof value !== "object") {
258
+ throw new Error(
259
+ 'Workflow front matter field "tracker.pickup_labels" must be an object when provided.'
260
+ );
261
+ }
262
+ const input = value;
263
+ return {
264
+ include: readStringList(input, "include") ?? [],
265
+ exclude: readStringList(input, "exclude") ?? []
266
+ };
267
+ }
247
268
  function readPriorityConfig(tracker, env) {
248
269
  if (tracker.priority === void 0 || tracker.priority === null) {
249
270
  return null;
@@ -338,7 +359,7 @@ function parseBlock(lines, startIndex, indent) {
338
359
  );
339
360
  }
340
361
  collectionType = "array";
341
- const itemText = trimmed.slice(2).trim();
362
+ const itemText = stripYamlInlineComment(trimmed.slice(2)).trim();
342
363
  if (itemText === "|" || itemText === "|-") {
343
364
  const [multiline, nextIndex3] = parseMultilineScalar(
344
365
  lines,
@@ -375,7 +396,9 @@ function parseBlock(lines, startIndex, indent) {
375
396
  throw new Error(`Invalid workflow front matter key "${rawKey}".`);
376
397
  }
377
398
  const key = parsedKey;
378
- const remainder = trimmed.slice(separatorIndex + 1).trim();
399
+ const remainder = stripYamlInlineComment(
400
+ trimmed.slice(separatorIndex + 1)
401
+ ).trim();
379
402
  if (remainder === "|" || remainder === "|-") {
380
403
  const [multiline, nextIndex2] = parseMultilineScalar(
381
404
  lines,
@@ -444,6 +467,7 @@ function findMappingSeparator(value) {
444
467
  return -1;
445
468
  }
446
469
  function parseScalar(value) {
470
+ value = stripYamlInlineComment(value).trim();
447
471
  if (value === "null") return null;
448
472
  if (value === "true") return true;
449
473
  if (value === "false") return false;
@@ -468,6 +492,30 @@ function parseScalar(value) {
468
492
  }
469
493
  return value;
470
494
  }
495
+ function stripYamlInlineComment(value) {
496
+ let quote = null;
497
+ for (let index = 0; index < value.length; index += 1) {
498
+ const char = value[index];
499
+ if (quote) {
500
+ if (quote === '"' && char === "\\") {
501
+ index += 1;
502
+ continue;
503
+ }
504
+ if (char === quote) {
505
+ quote = null;
506
+ }
507
+ continue;
508
+ }
509
+ if (char === '"' || char === "'") {
510
+ quote = char;
511
+ continue;
512
+ }
513
+ if (char === "#" && (index === 0 || /\s/.test(value[index - 1] ?? ""))) {
514
+ return value.slice(0, index).trimEnd();
515
+ }
516
+ }
517
+ return value;
518
+ }
471
519
  function parseInlineArray(value) {
472
520
  const inner = value.slice(1, -1).trim();
473
521
  if (!inner) {