@errhythm/gitmux 1.6.12 → 1.6.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@errhythm/gitmux",
3
- "version": "1.6.12",
3
+ "version": "1.6.13",
4
4
  "description": "Multi-repo Git & GitLab workflow CLI — switch branches, manage epics & issues, create MRs, all from the terminal",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1623,29 +1623,53 @@ export async function cmdPortal(repos, {
1623
1623
  if (!confirmed) { console.log(); continue issueLoop; }
1624
1624
 
1625
1625
  // 6. Create issue — resolve __current__ iteration to a real sprint ID
1626
- let resolvedIterationId = portalConfig.defaultIteration?.id ?? null;
1627
- if (resolvedIterationId === "__current__") {
1626
+ let resolvedIterationTitle = null;
1627
+ let resolvedCadenceTitle = null;
1628
+
1629
+ if (portalConfig.defaultIteration?.id) {
1628
1630
  try {
1629
1631
  const groupEnc = encodeURIComponent(group);
1630
1632
  const todayUtc = new Date().toISOString().slice(0, 10);
1631
- const activeIters = await glabApi(`groups/${groupEnc}/iterations?state=current&per_page=1`);
1632
- const iter = Array.isArray(activeIters) ? activeIters[0] : null;
1633
- if (iter && iter.due_date > todayUtc) {
1634
- // Iteration is still open past today — safe to use
1635
- resolvedIterationId = iter.id;
1633
+
1634
+ let iter = null;
1635
+ if (portalConfig.defaultIteration.id === "__current__") {
1636
+ const activeIters = await glabApi(`groups/${groupEnc}/iterations?state=current&per_page=1`);
1637
+ iter = Array.isArray(activeIters) ? activeIters[0] : null;
1638
+ if (!iter || iter.due_date <= todayUtc) {
1639
+ const nextIters = await glabApi(`groups/${groupEnc}/iterations?state=upcoming&per_page=1`);
1640
+ iter = Array.isArray(nextIters) ? nextIters[0] : null;
1641
+ }
1636
1642
  } else {
1637
- // Ends today or none found GitLab silently drops same-day assignments,
1638
- // so grab the next upcoming iteration instead
1639
- const nextIters = await glabApi(`groups/${groupEnc}/iterations?state=upcoming&per_page=1`);
1640
- const next = Array.isArray(nextIters) ? nextIters[0] : null;
1641
- resolvedIterationId = next?.id ?? null;
1643
+ // Not __current__, it's a specific ID. We still need its title/cadence for the quick action.
1644
+ // Note: GitLab's iteration REST endpoint doesn't strictly have a direct GET /iterations/:id
1645
+ // that works at the group level easily without knowing cadence. We can search.
1646
+ // Or better, we only support __current__ or string-based iterations anyway from settings.
1647
+ // For simplicity, we just use the title if it's stored.
1648
+ resolvedIterationTitle = portalConfig.defaultIteration.title;
1649
+ }
1650
+
1651
+ if (iter) {
1652
+ // Iteration objects from the API sometimes have titles, but often they are titled by their dates
1653
+ // e.g. "Jan 5, 2026 - Feb 5, 2026". The most reliable quick action is by ID or title.
1654
+ // Actually, quick actions support `/iteration *iteration_name*` or `/iteration "<iteration_cadence_name>" "<iteration_name>"`
1655
+ // We'll store its title or cadence + title to use in the description.
1656
+ // We can just append `\n/iteration *${iter.title || iter.id}*` but title is safer if it has one.
1657
+ resolvedIterationTitle = iter.title;
1658
+ if (!resolvedIterationTitle && iter.start_date && iter.due_date) {
1659
+ resolvedIterationTitle = `${iter.start_date} - ${iter.due_date}`; // generic format
1660
+ }
1661
+ // It's safer to use the global GraphQL ID if we can't find a title, but quick actions only take Title or Date range.
1662
+ // Wait, quick actions are: /iteration "cadence title" "iteration title" or /iteration "cadence title" "start-date" "due-date".
1663
+ // Let's just use the `iteration_id` parameter and see if it works. Wait, the user said it doesn't work.
1664
+ // Let me use the GraphQL ID? No, REST POST /issues simply doesn't support iteration_id on GitLab CE/EE some versions.
1665
+ // Actually, GitLab just supports appending `/iteration *current*` to use the current one!
1666
+ resolvedIterationTitle = "*current*";
1642
1667
  }
1643
1668
  } catch {
1644
- resolvedIterationId = null;
1669
+ resolvedIterationTitle = null;
1645
1670
  }
1646
1671
  }
1647
1672
 
1648
-
1649
1673
  // Resolve the real classic epic ID via REST — the GraphQL WorkItems API
1650
1674
  // returns gid://gitlab/WorkItem/NNNN which is NOT the epic's database ID.
1651
1675
  // GET /groups/:group/epics/:iid returns { id: <real numeric id>, ... }.
@@ -1661,10 +1685,15 @@ export async function cmdPortal(repos, {
1661
1685
  ...(epicId ? { epic_id: epicId } : { epic_iid: epic.iid }),
1662
1686
  };
1663
1687
 
1664
- if (issueDesc.trim()) issueFields.description = issueDesc.trim();
1688
+ let finalDesc = issueDesc.trim();
1689
+ // If they requested __current__ iteration, append the quick action to the description
1690
+ if (portalConfig.defaultIteration?.id === "__current__") {
1691
+ finalDesc += "\n\n/iteration *current*";
1692
+ }
1693
+
1694
+ if (finalDesc) issueFields.description = finalDesc.trim();
1665
1695
  if (issueLabels.trim()) issueFields.labels = issueLabels.trim();
1666
1696
  if (portalConfig.defaultMilestone?.id) issueFields.milestone_id = portalConfig.defaultMilestone.id;
1667
- if (resolvedIterationId) issueFields.iteration_id = resolvedIterationId;
1668
1697
 
1669
1698
  const enc = encodeURIComponent(projectChoice.projectPath);
1670
1699
  process.stdout.write(" " + p.muted("Creating issue…\r"));