ticketlens 0.38.29 → 0.38.30

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.38.29",
3
+ "version": "0.38.30",
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": {
@@ -118,9 +118,17 @@ export function hasRecentCapture(cwd, now = Date.now()) {
118
118
  * tool — for note-add. Missing the MCP path here was a real bug: it made
119
119
  * the Stop hook nudge even after a note was genuinely captured via MCP,
120
120
  * since only the Bash/CLI form was ever recognized.
121
+ *
122
+ * `ticketKey` carries the FIRST matched ticket key's literal text (or
123
+ * `null`), so callers can resolve a profile by ticket-key prefix the same
124
+ * way `resolveConnection()` does — see recall-nudge-stop.mjs. First match,
125
+ * not last: the primary ticket a session is about is normally established
126
+ * early, and picking one deterministic match keeps this function decoupled
127
+ * from profiles.json (it stays a pure transcript reader; profile lookup
128
+ * and its own fallback chain belong entirely to resolveProfile()).
121
129
  */
122
130
  export function scanTranscript(transcriptPath) {
123
- const result = { sawTicketKey: false, sawRecallFlag: false, sawNoteAdd: false };
131
+ const result = { sawTicketKey: false, sawRecallFlag: false, sawNoteAdd: false, ticketKey: null };
124
132
  let lines;
125
133
  try {
126
134
  lines = fs.readFileSync(transcriptPath, 'utf8').split('\n').filter(Boolean);
@@ -136,10 +144,22 @@ export function scanTranscript(transcriptPath) {
136
144
  continue;
137
145
  }
138
146
 
139
- // Ticket-key detection stays broad (whole entry, any role) — it's only
140
- // the weaker "did ticket work happen at all" signal, and a rare false
141
- // positive here just means an extra harmless once-per-session check.
142
- if (TICKET_KEY_RE.test(JSON.stringify(entry))) result.sawTicketKey = true;
147
+ // Ticket-key detection stays broad (whole entry, any role) — for
148
+ // sawTicketKey alone, it's only the weaker "did ticket work happen at
149
+ // all" signal, so a rare false positive just means an extra harmless
150
+ // once-per-session check. The captured ticketKey text carries a bit
151
+ // more weight (it also selects which profile's recallStrictness
152
+ // applies, see recall-nudge-stop.mjs), but the ceiling is still just
153
+ // "the wrong local settings value governs one Stop-hook decision" — no
154
+ // credentials or ticket data are read using this key, so a false
155
+ // positive here stays low-consequence, not narrowed further for now.
156
+ if (!result.ticketKey) {
157
+ const match = TICKET_KEY_RE.exec(JSON.stringify(entry));
158
+ if (match) {
159
+ result.sawTicketKey = true;
160
+ result.ticketKey = match[0];
161
+ }
162
+ }
143
163
 
144
164
  if (entry.type !== 'assistant') continue;
145
165
  const blocks = entry.message?.content;
@@ -21,14 +21,13 @@
21
21
  * profile's recallStrictness — see recall-nudge-lib.mjs's shouldNag() doc
22
22
  * comment for the calibration and why strict doesn't widen this further.
23
23
  *
24
- * Known limitation: resolveProfile(null, { cwd }) below has no ticket key to
25
- * match against, so it falls through to cwd/projectPaths then the default
26
- * profile — unlike the brief-injection lever (resolveConnection(ticketKey, ...)
27
- * in profile-resolver.mjs), which resolves by ticket-key prefix when one is
28
- * available. For a multi-profile user these two levers can genuinely resolve
29
- * different profiles in the same session, so the recallStrictness setting
30
- * doesn't reliably reweight both together outside the single-profile case.
31
- * Not fixed here — see design spec §6 for the follow-up.
24
+ * resolveProfile() below is given scanTranscript()'s matched ticket key (not
25
+ * null), so it resolves by ticket-key prefix the same way the brief-injection
26
+ * lever (resolveConnection(ticketKey, ...) in profile-resolver.mjs) does —
27
+ * both levers now agree on which profile's recallStrictness applies for a
28
+ * multi-profile user. When no ticket key was seen, or it matches no profile's
29
+ * ticketPrefixes, this falls through to cwd/projectPaths then the default
30
+ * profile, same as before (backlog #12, design spec §6).
32
31
  */
33
32
 
34
33
  import { readStdinJson, readState, writeState, scanTranscript, hasRecentCapture, writeLastCaptureAt, shouldNag } from './recall-nudge-lib.mjs';
@@ -41,7 +40,7 @@ const cwd = input?.cwd ?? process.cwd();
41
40
 
42
41
  if (!sessionId || !transcriptPath) process.exit(0);
43
42
 
44
- const { sawTicketKey, sawRecallFlag, sawNoteAdd } = scanTranscript(transcriptPath);
43
+ const { sawTicketKey, sawRecallFlag, sawNoteAdd, ticketKey } = scanTranscript(transcriptPath);
45
44
 
46
45
  // Refreshed on every check, independent of the once-per-session gate below —
47
46
  // a capture that happens AFTER this session already nagged once must still
@@ -51,7 +50,7 @@ if (sawNoteAdd) writeLastCaptureAt(cwd, Date.now());
51
50
  const state = readState(sessionId);
52
51
  if (state.stopChecked) process.exit(0); // already asked once this session — respect the answer
53
52
 
54
- const profile = resolveProfile(null, { cwd });
53
+ const profile = resolveProfile(ticketKey, { cwd });
55
54
  const recallStrictness = normalizeRecallStrictness(profile?.recallStrictness);
56
55
 
57
56
  if (!shouldNag({ sawTicketKey, sawRecallFlag, sawNoteAdd, recallStrictness })) {
@@ -3,7 +3,7 @@
3
3
  * Centralised here to avoid triplicating the regex and warning logic.
4
4
  */
5
5
 
6
- export const DEFAULT_API_BASE = 'https://api.ticketlens.app';
6
+ export const DEFAULT_API_BASE = 'http://api.ticketlens.test';
7
7
  export const DEFAULT_SITE_BASE = 'https://ticketlens.app';
8
8
 
9
9
  // Matches localhost, 127.0.0.1, and any hostname ending in .test or .local,