mintree 0.4.1 → 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.
@@ -16,6 +16,7 @@ import { buildCreateMarkers, emitMarkers } from "../lib/markers.js";
16
16
  import { readMetadata } from "../lib/metadata.js";
17
17
  import { createProvider } from "../lib/providers/index.js";
18
18
  import { loadDashboard } from "../lib/dashboard.js";
19
+ import { priorityDisplay } from "../lib/priority.js";
19
20
  const require = createRequire(import.meta.url);
20
21
  const { version: mintreeVersion } = require("../../package.json");
21
22
  export const description = "Interactive dashboard listing open issues assigned to you with worktree + session state";
@@ -220,13 +221,17 @@ function IssueListRow({ d, selected, identifierWidth, rowWidth, }) {
220
221
  // Status-coloured leading dot — same convention as santree. Falls back to
221
222
  // gray when the issue has no project board membership.
222
223
  const dotColor = d.project?.statusColor ?? "gray";
224
+ // Compact priority glyph (Linear only; GitHub rows render a blank). The
225
+ // fixed single-width icon keeps the ids aligned whether or not a row has a
226
+ // priority. See lib/priority.ts.
227
+ const prio = priorityDisplay(d.issue.priority);
223
228
  const title = d.issue.title;
224
229
  // The leading-dot Text and the rest are nested under a single Text so the
225
230
  // selection background paints the whole row in one contiguous block.
226
231
  // `wrap="truncate"` clamps the row to a single line and Ink renders an
227
232
  // ellipsis at the cut. The outer Box has a fixed width so the wrap
228
233
  // behaviour knows where to truncate.
229
- return (_jsx(Box, { width: rowWidth, children: _jsxs(Text, { wrap: "truncate", backgroundColor: selected ? "blue" : undefined, color: selected ? "white" : undefined, children: [" ", _jsx(Text, { color: selected ? "white" : dotColor, children: "\u25CF" }), ` ${idText} ${title}`] }) }));
234
+ return (_jsx(Box, { width: rowWidth, children: _jsxs(Text, { wrap: "truncate", backgroundColor: selected ? "blue" : undefined, color: selected ? "white" : undefined, children: [" ", _jsx(Text, { color: selected ? "white" : dotColor, children: "\u25CF" }), " ", _jsx(Text, { color: selected ? "white" : prio.color, children: prio.icon }), ` ${idText} ${title}`] }) }));
230
235
  }
231
236
  // A project board header — the top level of the grouped issue list. Mirrors
232
237
  // the bold project name + dim count seen in the santree dashboard.
@@ -3,6 +3,7 @@ import * as path from "path";
3
3
  import { listWorktrees, getWorktreesDir, isDirty, getAheadBehind, } from "./git.js";
4
4
  import { readMetadata } from "./metadata.js";
5
5
  import { fetchPrForBranch } from "./pr.js";
6
+ import { prioritySortRank } from "./priority.js";
6
7
  import { createProvider } from "./providers/index.js";
7
8
  /**
8
9
  * Builds a map from issue id (the canonical string — "100" on GitHub,
@@ -95,6 +96,13 @@ function sortGroupedIssues(issues, configuredUrl) {
95
96
  return a.project.statusOrder - b.project.statusOrder;
96
97
  }
97
98
  }
99
+ // Within a status group, surface higher-priority issues first
100
+ // (Urgent → Low; "no priority" sinks to the bottom). Orphans and
101
+ // GitHub rows have null priority and so fall through to the date sort.
102
+ const pa = prioritySortRank(a.issue.priority);
103
+ const pb = prioritySortRank(b.issue.priority);
104
+ if (pa !== pb)
105
+ return pa - pb;
98
106
  // Newest-first for issues — id is a numeric-or-prefixed string. Numeric
99
107
  // compare falls back to localeCompare for non-numeric ids (Linear's
100
108
  // "FE-123" form).
@@ -137,6 +145,7 @@ function buildOrphanRows(worktreesByIssue, assignedIds, sessionLookup, prByBranc
137
145
  body: "",
138
146
  createdAt: "",
139
147
  updatedAt: "",
148
+ priority: null,
140
149
  },
141
150
  worktree,
142
151
  session: sessionLookup(issueId),
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Issue priority, normalised across providers.
3
+ *
4
+ * Linear exposes a native `priority` field on the 0-4 scale:
5
+ * 0 = No priority, 1 = Urgent, 2 = High, 3 = Medium, 4 = Low.
6
+ * GitHub Issues has no native priority concept, so its provider always yields
7
+ * `null` here — the dashboard simply renders no priority glyph for those rows.
8
+ *
9
+ * `ProviderIssue.priority` stores the raw Linear number (or null), and these
10
+ * helpers turn it into a compact dashboard glyph and a sort rank. Keeping the
11
+ * mapping in one module means the render path (dashboard.tsx) and the sort
12
+ * path (dashboard.ts) stay in lock-step.
13
+ */
14
+ export type PriorityValue = number | null | undefined;
15
+ export type PriorityDisplay = {
16
+ /** Human label, e.g. "Urgent". Empty string when there's no priority. */
17
+ label: string;
18
+ /** Single-width glyph for the list row. A space when there's no priority. */
19
+ icon: string;
20
+ /** Ink-renderable colour name for the glyph. */
21
+ color: string;
22
+ };
23
+ /**
24
+ * Maps a raw priority value to its dashboard glyph. Urgent reads as a bold
25
+ * red bang; High/Medium/Low use arrows that step down in weight and colour.
26
+ * "No priority" (0) and null both render as a blank, keeping rows aligned
27
+ * without drawing the eye.
28
+ */
29
+ export declare function priorityDisplay(priority: PriorityValue): PriorityDisplay;
30
+ /**
31
+ * Sort rank for "highest priority first". Urgent (1) sorts before Low (4);
32
+ * "No priority" (0) and null sort last. Used as a tie-break inside a status
33
+ * group before the newest-first fallback.
34
+ */
35
+ export declare function prioritySortRank(priority: PriorityValue): number;
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Issue priority, normalised across providers.
3
+ *
4
+ * Linear exposes a native `priority` field on the 0-4 scale:
5
+ * 0 = No priority, 1 = Urgent, 2 = High, 3 = Medium, 4 = Low.
6
+ * GitHub Issues has no native priority concept, so its provider always yields
7
+ * `null` here — the dashboard simply renders no priority glyph for those rows.
8
+ *
9
+ * `ProviderIssue.priority` stores the raw Linear number (or null), and these
10
+ * helpers turn it into a compact dashboard glyph and a sort rank. Keeping the
11
+ * mapping in one module means the render path (dashboard.tsx) and the sort
12
+ * path (dashboard.ts) stay in lock-step.
13
+ */
14
+ const NONE = { label: "", icon: " ", color: "gray" };
15
+ /**
16
+ * Maps a raw priority value to its dashboard glyph. Urgent reads as a bold
17
+ * red bang; High/Medium/Low use arrows that step down in weight and colour.
18
+ * "No priority" (0) and null both render as a blank, keeping rows aligned
19
+ * without drawing the eye.
20
+ */
21
+ export function priorityDisplay(priority) {
22
+ switch (priority) {
23
+ case 1:
24
+ return { label: "Urgent", icon: "!", color: "red" };
25
+ case 2:
26
+ return { label: "High", icon: "↑", color: "red" };
27
+ case 3:
28
+ return { label: "Medium", icon: "=", color: "yellow" };
29
+ case 4:
30
+ return { label: "Low", icon: "↓", color: "blue" };
31
+ default:
32
+ return NONE;
33
+ }
34
+ }
35
+ /**
36
+ * Sort rank for "highest priority first". Urgent (1) sorts before Low (4);
37
+ * "No priority" (0) and null sort last. Used as a tie-break inside a status
38
+ * group before the newest-first fallback.
39
+ */
40
+ export function prioritySortRank(priority) {
41
+ if (priority == null || priority === 0)
42
+ return Number.POSITIVE_INFINITY;
43
+ return priority;
44
+ }
@@ -142,6 +142,8 @@ export class GithubProvider {
142
142
  body: raw.body,
143
143
  createdAt: raw.createdAt,
144
144
  updatedAt: raw.updatedAt,
145
+ // GitHub Issues has no native priority field.
146
+ priority: null,
145
147
  }));
146
148
  }
147
149
  catch {
@@ -271,6 +271,7 @@ const BOOTSTRAP_QUERY = /* GraphQL */ `
271
271
  title
272
272
  description
273
273
  url
274
+ priority
274
275
  createdAt
275
276
  updatedAt
276
277
  team {
@@ -329,6 +330,10 @@ function mapIssueToProviderIssue(wi) {
329
330
  body: wi.description ?? "",
330
331
  createdAt: wi.createdAt ?? "",
331
332
  updatedAt: wi.updatedAt ?? "",
333
+ // Linear sends 0 for "No priority"; normalise it (and any missing
334
+ // value) to null so the dashboard treats it the same as GitHub's
335
+ // no-priority rows.
336
+ priority: wi.priority && wi.priority > 0 ? wi.priority : null,
332
337
  };
333
338
  }
334
339
  export class LinearProvider {
@@ -26,6 +26,7 @@ export type ProviderIssue = {
26
26
  body: string;
27
27
  createdAt: string;
28
28
  updatedAt: string;
29
+ priority: number | null;
29
30
  };
30
31
  /**
31
32
  * The issue's membership on a project board (GitHub Projects v2 / Linear
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mintree",
3
- "version": "0.4.1",
3
+ "version": "0.4.2",
4
4
  "description": "Issue-driven git worktrees + Claude Code sessions for repos with an opinionated SDD+TDD flow.",
5
5
  "license": "MIT",
6
6
  "author": "Martin Mineo <mmineo@canarytechnologies.com>",