ticketlens 0.21.2 → 0.21.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ticketlens",
3
- "version": "0.21.2",
3
+ "version": "0.21.3",
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": {
@@ -44,6 +44,17 @@ export function writeState(sessionId, state) {
44
44
  * Reads the transcript (JSONL) and returns simple booleans about what
45
45
  * happened this session. Best-effort: any read/parse failure returns all
46
46
  * false rather than throwing — a broken transcript must never block Claude.
47
+ *
48
+ * Deliberately narrow about WHERE each pattern is allowed to match — jtb's
49
+ * own SKILL.md instructions contain the literal strings "🔖 Recall-flag:"
50
+ * and "ticketlens note add" as examples. Matching against the whole raw
51
+ * entry (as an earlier version of this function did) means loading the
52
+ * skill at all permanently false-positives both checks: sawRecallFlag gets
53
+ * stuck true (silently disabling the mid-session nudge, since it thinks
54
+ * Claude just flagged something every time) and sawNoteAdd gets stuck true
55
+ * (silently disabling the Stop-hook check, since it thinks a note was
56
+ * already added). Only count a real assistant-authored text block for the
57
+ * flag, and only a real executed Bash command for note-add.
47
58
  */
48
59
  export function scanTranscript(transcriptPath) {
49
60
  const result = { sawTicketKey: false, sawRecallFlag: false, sawNoteAdd: false };
@@ -55,17 +66,30 @@ export function scanTranscript(transcriptPath) {
55
66
  }
56
67
 
57
68
  for (const line of lines) {
58
- let text;
69
+ let entry;
59
70
  try {
60
- const entry = JSON.parse(line);
61
- // Transcript entries vary by role/type; flatten whatever text exists.
62
- text = JSON.stringify(entry);
71
+ entry = JSON.parse(line);
63
72
  } catch {
64
73
  continue;
65
74
  }
66
- if (TICKET_KEY_RE.test(text)) result.sawTicketKey = true;
67
- if (RECALL_FLAG_RE.test(text)) result.sawRecallFlag = true;
68
- if (NOTE_ADD_RE.test(text)) result.sawNoteAdd = true;
75
+
76
+ // Ticket-key detection stays broad (whole entry, any role) — it's only
77
+ // the weaker "did ticket work happen at all" signal, and a rare false
78
+ // positive here just means an extra harmless once-per-session check.
79
+ if (TICKET_KEY_RE.test(JSON.stringify(entry))) result.sawTicketKey = true;
80
+
81
+ if (entry.type !== 'assistant') continue;
82
+ const blocks = entry.message?.content;
83
+ if (!Array.isArray(blocks)) continue;
84
+
85
+ for (const block of blocks) {
86
+ if (block.type === 'text' && RECALL_FLAG_RE.test(block.text ?? '')) {
87
+ result.sawRecallFlag = true;
88
+ }
89
+ if (block.type === 'tool_use' && block.name === 'Bash' && NOTE_ADD_RE.test(block.input?.command ?? '')) {
90
+ result.sawNoteAdd = true;
91
+ }
92
+ }
69
93
  }
70
94
 
71
95
  return result;