ticketlens 0.21.2 → 0.21.4

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.4",
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": {
@@ -214,7 +214,7 @@ Immediately before dispatching the call, say one line in your response: `🔖 Re
214
214
 
215
215
  ### How to dispatch the call
216
216
 
217
- If your environment lets you dispatch a tool call without waiting for its result — a background task, an async subagent, a fire-and-forget job — use that mechanism for this call, so it doesn't block your primary work while the note syncs to the team. If you have no such mechanism, call it synchronously; it's fast, and it never blocks or fails your session either way, so there's no harm in the fallback.
217
+ If your environment lets you dispatch a tool call without waiting for its result — a background task, an async subagent, a fire-and-forget job — try it **once**. If it errors for any reason, don't retry the background path — fall back to calling it synchronously immediately. It's fast and never blocks or fails your session either way, so the synchronous fallback costs nothing; repeatedly retrying a broken background mechanism only adds visible noise for no benefit.
218
218
 
219
219
  ```bash
220
220
  echo "The body text of the note, one or more paragraphs." | \
@@ -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;