@gh-symphony/cli 0.2.0 → 0.2.3

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.
@@ -30,11 +30,11 @@ import {
30
30
  resolveWorkflowRuntimeTimeouts,
31
31
  safeReadDir,
32
32
  scheduleRetryAt
33
- } from "./chunk-Q3UEPUE3.js";
33
+ } from "./chunk-3SKN5L3I.js";
34
34
  import {
35
35
  loadGlobalConfig,
36
36
  loadProjectConfig
37
- } from "./chunk-WOVNN5NW.js";
37
+ } from "./chunk-4ICDSQCJ.js";
38
38
 
39
39
  // ../tracker-github/src/adapter.ts
40
40
  import { createHash } from "crypto";
@@ -158,7 +158,7 @@ function normalizePullRequestProjectItem(projectId, item, content, fieldValues,
158
158
  async function fetchProjectIssues(config, fetchImpl = fetch) {
159
159
  const issues = [];
160
160
  let cursor = null;
161
- const priorityOptionIds = config.priorityFieldName ? await fetchPriorityOptionOrder(
161
+ const priorityOptionIds = !config.priority && config.priorityFieldName ? await fetchPriorityOptionOrder(
162
162
  config,
163
163
  config.priorityFieldName,
164
164
  fetchImpl
@@ -179,8 +179,11 @@ async function fetchProjectIssues(config, fetchImpl = fetch) {
179
179
  item,
180
180
  config.lifecycle,
181
181
  {
182
- fieldName: config.priorityFieldName,
183
- optionIds: priorityOptionIds
182
+ explicit: config.priority,
183
+ legacy: {
184
+ fieldName: config.priorityFieldName,
185
+ optionIds: priorityOptionIds
186
+ }
184
187
  },
185
188
  latestRateLimits
186
189
  );
@@ -248,7 +251,7 @@ async function fetchIssueStatesByIds(config, issueIds, fetchImpl = fetch) {
248
251
  return issues;
249
252
  }
250
253
  async function fetchProjectIssueByRepositoryAndNumber(config, repository, issueNumber, fetchImpl = fetch) {
251
- const priorityOptionIds = config.priorityFieldName ? await fetchPriorityOptionOrder(
254
+ const priorityOptionIds = !config.priority && config.priorityFieldName ? await fetchPriorityOptionOrder(
252
255
  config,
253
256
  config.priorityFieldName,
254
257
  fetchImpl
@@ -281,8 +284,11 @@ async function fetchProjectIssueByRepositoryAndNumber(config, repository, issueN
281
284
  projectItem,
282
285
  config.lifecycle,
283
286
  {
284
- fieldName: config.priorityFieldName,
285
- optionIds: priorityOptionIds
287
+ explicit: config.priority,
288
+ legacy: {
289
+ fieldName: config.priorityFieldName,
290
+ optionIds: priorityOptionIds
291
+ }
286
292
  },
287
293
  result.rateLimits
288
294
  );
@@ -600,16 +606,114 @@ function findProjectItemByProjectId(nodes, projectId) {
600
606
  return nodes.find((item) => item?.project?.id === projectId) ?? null;
601
607
  }
602
608
  function resolvePriority(item, priority) {
603
- if (!priority.fieldName || !priority.optionIds) {
609
+ const normalizedPriority = normalizePriorityResolutionConfig(priority);
610
+ if (normalizedPriority.explicit) {
611
+ return resolveExplicitPriority(item, normalizedPriority.explicit);
612
+ }
613
+ if (!normalizedPriority.legacy?.fieldName || !normalizedPriority.legacy.optionIds) {
604
614
  return null;
605
615
  }
606
616
  for (const node of item.fieldValues?.nodes ?? []) {
607
- if (node?.__typename === "ProjectV2ItemFieldSingleSelectValue" && node.field?.name === priority.fieldName && node.optionId) {
608
- return priority.optionIds[node.optionId] ?? null;
617
+ if (node?.__typename === "ProjectV2ItemFieldSingleSelectValue" && node.field?.name === normalizedPriority.legacy.fieldName && node.optionId) {
618
+ return normalizedPriority.legacy.optionIds[node.optionId] ?? null;
609
619
  }
610
620
  }
611
621
  return null;
612
622
  }
623
+ function normalizePriorityResolutionConfig(priority) {
624
+ if ("explicit" in priority || "legacy" in priority) {
625
+ return priority;
626
+ }
627
+ return {
628
+ legacy: priority
629
+ };
630
+ }
631
+ function resolveExplicitPriority(item, priority) {
632
+ if (priority.source === "disabled") {
633
+ return null;
634
+ }
635
+ if (priority.source === "project-field") {
636
+ return resolveProjectFieldPriority(item, priority);
637
+ }
638
+ return resolveLabelPriority(item, priority);
639
+ }
640
+ function resolveProjectFieldPriority(item, priority) {
641
+ for (const node of item.fieldValues?.nodes ?? []) {
642
+ if (node?.__typename === "ProjectV2ItemFieldSingleSelectValue" && node.field?.name === priority.field && node.name) {
643
+ const resolved = priority.values[node.name] ?? null;
644
+ if (resolved === null) {
645
+ emitPriorityUnmapped(item, "project-field", [node.name]);
646
+ }
647
+ return resolved;
648
+ }
649
+ }
650
+ return null;
651
+ }
652
+ function resolveLabelPriority(item, priority) {
653
+ if (item.content?.__typename !== "Issue" && item.content?.__typename !== "PullRequest") {
654
+ return null;
655
+ }
656
+ const labels = rawLabelNames(item.content.labels?.nodes ?? []);
657
+ const matches = labels.flatMap((label) => {
658
+ const value = priority.labels[label];
659
+ return typeof value === "number" ? [{ label, value }] : [];
660
+ });
661
+ if (matches.length === 0) {
662
+ if (labels.length > 0) {
663
+ emitPriorityUnmapped(item, "labels", labels);
664
+ }
665
+ return null;
666
+ }
667
+ const chosenValue = Math.min(...matches.map((match) => match.value));
668
+ if (matches.length > 1) {
669
+ const chosenLabels = matches.filter((match) => match.value === chosenValue).map((match) => match.label);
670
+ emitPriorityLabelConflictResolved(item, matches, chosenValue, chosenLabels);
671
+ }
672
+ return chosenValue;
673
+ }
674
+ function rawLabelNames(nodes) {
675
+ return nodes.flatMap((label) => label?.name ? [label.name] : []);
676
+ }
677
+ function emitPriorityLabelConflictResolved(item, matched, chosenValue, chosenLabels) {
678
+ const issue = issueEventMetadata(item);
679
+ if (!issue) {
680
+ return;
681
+ }
682
+ console.info(
683
+ JSON.stringify({
684
+ at: (/* @__PURE__ */ new Date()).toISOString(),
685
+ event: "priority.label_conflict_resolved",
686
+ issue,
687
+ matched,
688
+ chosenValue,
689
+ chosenLabels
690
+ })
691
+ );
692
+ }
693
+ function emitPriorityUnmapped(item, source, rawValues) {
694
+ const issue = issueEventMetadata(item);
695
+ if (!issue) {
696
+ return;
697
+ }
698
+ console.info(
699
+ JSON.stringify({
700
+ at: (/* @__PURE__ */ new Date()).toISOString(),
701
+ event: "priority.unmapped",
702
+ issue,
703
+ source,
704
+ rawValues
705
+ })
706
+ );
707
+ }
708
+ function issueEventMetadata(item) {
709
+ if (item.content?.__typename !== "Issue" && item.content?.__typename !== "PullRequest") {
710
+ return null;
711
+ }
712
+ return {
713
+ identifier: `${item.content.repository.owner.login}/${item.content.repository.name}#${item.content.number}`,
714
+ id: item.content.id
715
+ };
716
+ }
613
717
  function extractPriorityOptionOrder(fields, priorityFieldName) {
614
718
  for (const field of fields) {
615
719
  if (isSingleSelectProjectField(field) && field.name === priorityFieldName) {
@@ -1441,11 +1545,13 @@ function resolveGitHubTrackerConfig(project, dependencies = {}) {
1441
1545
  );
1442
1546
  }
1443
1547
  const githubProjectId = requireTrackerSetting(project.tracker, "projectId");
1548
+ const assignedOnly = resolveAssignedOnly(project.tracker, dependencies);
1444
1549
  return {
1445
1550
  projectId: githubProjectId,
1446
1551
  token,
1447
1552
  apiUrl: project.tracker.apiUrl,
1448
- assignedOnly: readBooleanTrackerSetting(project.tracker, "assignedOnly"),
1553
+ assignedOnly,
1554
+ priority: project.tracker.priority ?? null,
1449
1555
  priorityFieldName: readOptionalStringTrackerSetting(
1450
1556
  project.tracker,
1451
1557
  "priorityFieldName"
@@ -1453,11 +1559,32 @@ function resolveGitHubTrackerConfig(project, dependencies = {}) {
1453
1559
  timeoutMs: readNumberTrackerSetting(project.tracker, "timeoutMs")
1454
1560
  };
1455
1561
  }
1562
+ var warnedLegacyAssignedOnlyProjectIds = /* @__PURE__ */ new Set();
1563
+ function resolveAssignedOnly(tracker, dependencies) {
1564
+ if (dependencies.assignedOnly !== void 0) {
1565
+ return dependencies.assignedOnly;
1566
+ }
1567
+ const legacyAssignedOnly = readBooleanTrackerSetting(
1568
+ tracker,
1569
+ "assignedOnly"
1570
+ );
1571
+ if (legacyAssignedOnly) {
1572
+ const warningKey = `${tracker.adapter}:${tracker.bindingId}`;
1573
+ if (!warnedLegacyAssignedOnlyProjectIds.has(warningKey)) {
1574
+ warnedLegacyAssignedOnlyProjectIds.add(warningKey);
1575
+ console.warn(
1576
+ "[gh-symphony] Deprecated tracker.settings.assignedOnly detected. Use 'gh-symphony repo start --assigned-only' instead; persisted assignedOnly support will be removed in the next major release."
1577
+ );
1578
+ }
1579
+ }
1580
+ return legacyAssignedOnly;
1581
+ }
1456
1582
  function buildProjectItemsCacheKey(config, _dependencies) {
1457
1583
  return JSON.stringify({
1458
1584
  adapter: "github-project",
1459
1585
  apiUrl: config.apiUrl,
1460
1586
  assignedOnly: config.assignedOnly ?? false,
1587
+ priority: config.priority ?? null,
1461
1588
  priorityFieldName: config.priorityFieldName ?? null,
1462
1589
  projectId: config.projectId,
1463
1590
  timeoutMs: config.timeoutMs,
@@ -3947,6 +4074,7 @@ var OrchestratorService = class {
3947
4074
  }
3948
4075
  createTrackerDependencies() {
3949
4076
  return {
4077
+ assignedOnly: this.dependencies.assignedOnly,
3950
4078
  fetchImpl: this.dependencies.fetchImpl,
3951
4079
  projectItemsCache: createProjectItemsCache()
3952
4080
  };
@@ -3,7 +3,7 @@ import {
3
3
  configFilePath,
4
4
  loadGlobalConfig,
5
5
  saveGlobalConfig
6
- } from "./chunk-WOVNN5NW.js";
6
+ } from "./chunk-4ICDSQCJ.js";
7
7
 
8
8
  // src/commands/config-cmd.ts
9
9
  import { spawn } from "child_process";