ticketlens 0.34.0 → 0.35.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ticketlens",
3
- "version": "0.34.0",
3
+ "version": "0.35.0",
4
4
  "description": "Jira CLI for developers — fetch ticket context, triage your queue, and stop tab-switching. Zero dependencies, all local.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -21,6 +21,7 @@ import { detectProjectOrTypeError, enrichCreateFailure } from './ticket-create-e
21
21
  import { TICKET_KEY_PATTERN } from './cli.mjs';
22
22
  import { scoreCandidates } from './duplicate-scorer.mjs';
23
23
  import { MAX_ATTACHMENTS } from './attachment-uploader.mjs';
24
+ import { createStyler } from './ansi.mjs';
24
25
 
25
26
  function parseFlag(cmdArgs, name) {
26
27
  return cmdArgs.find(a => a.startsWith(`--${name}=`))?.slice(name.length + 3);
@@ -123,6 +124,18 @@ function formatDuplicatesFailure(ticketKey, err) {
123
124
  return formatReadFailure(ticketKey, err, 'for duplicates');
124
125
  }
125
126
 
127
+ /**
128
+ * Match-confidence color tier for a duplicates result: ≥70% reads as a strong
129
+ * signal, 50-69% as worth a look, below that as a weak, low-confidence nudge.
130
+ * Exported standalone so the boundary values are pinned by a direct test
131
+ * rather than reverse-engineered from real Jaccard scores in a fixture.
132
+ */
133
+ export function matchColor(pct, s) {
134
+ if (pct >= 70) return s.green;
135
+ if (pct >= 50) return s.yellow;
136
+ return s.dim;
137
+ }
138
+
126
139
  function formatLinkListFailure(ticketKey, err) {
127
140
  return formatReadFailure(ticketKey, err, 'for link options');
128
141
  }
@@ -478,13 +491,18 @@ export async function runTicketDuplicates(cmdArgs, {
478
491
  const scoreOpts = threshold !== undefined ? { threshold } : {};
479
492
  const results = scoreCandidates({ key: ticketKey, summary: source.summary, description: source.description }, candidates, scoreOpts);
480
493
 
494
+ const s = createStyler({ isTTY: stream.isTTY });
495
+ stream.write(` ${s.brand(s.bold(ticketKey))}: ${s.bold(source.summary ?? '')}\n\n`);
496
+
481
497
  if (results.length === 0) {
482
- stream.write(` No likely duplicates found for ${ticketKey}.\n`);
498
+ stream.write(` No likely duplicates found.\n`);
483
499
  return { ok: true, results: [] };
484
500
  }
485
- stream.write(` Possible duplicates of ${ticketKey}:\n`);
501
+ stream.write(` Possible duplicates:\n\n`);
486
502
  for (const r of results) {
487
- stream.write(` ${r.key} (${Math.round(r.score * 100)}% match) — ${r.summary}\n`);
503
+ const pct = Math.round(r.score * 100);
504
+ const pctColor = matchColor(pct, s);
505
+ stream.write(` ${s.brand('●')} ${s.bold(r.key)} (${pctColor(`${pct}% match`)}) — ${r.summary}\n`);
488
506
  }
489
507
  return { ok: true, results };
490
508
  } catch (err) {