ticketlens 0.38.55 → 0.38.57
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/README.md
CHANGED
|
@@ -1099,14 +1099,16 @@ npm test
|
|
|
1099
1099
|
See [ROADMAP.md](ROADMAP.md) for the full plan.
|
|
1100
1100
|
|
|
1101
1101
|
Recently shipped:
|
|
1102
|
-
- **
|
|
1103
|
-
- **
|
|
1104
|
-
- **
|
|
1105
|
-
-
|
|
1106
|
-
- **
|
|
1107
|
-
-
|
|
1108
|
-
- **
|
|
1109
|
-
- **
|
|
1102
|
+
- **Multi-agent AI consensus compliance** (`ticketlens compliance TICKET --consensus`) — routes requirements-vs-diff review through your team's AI provider pool, majority vote after a refinement round. Pro tier
|
|
1103
|
+
- **Dynamic AI Provider Registry** (Console > Admin > AI Provider Pool / AI Roles) — manage arbitrary AI providers and role-based routing, no fixed vendor list
|
|
1104
|
+
- **Full MCP tool coverage** (`ticketlens mcp`) — every CLI action (fetch, triage, compliance, recall, ticket writes) has a matching MCP tool
|
|
1105
|
+
- **`ticketlens issue-types`** — pre-fetches and caches a project's valid issue types, speeds up `ticket_create`
|
|
1106
|
+
- **Recall team sync** (`note add` / `recall`) — shared notes with Console verification, attachments, configurable capture strictness. Pro/Team tier
|
|
1107
|
+
- **`ticketlens doctor`** — diagnoses profile/connection/license/MCP problems; `--fix` for common issues
|
|
1108
|
+
- **Ticket write-back** (`comment`/`transition`/`assign`/`duplicates`/`link`/`update`/`create`) — write directly to Jira/GitHub/Linear from the CLI. Pro tier
|
|
1109
|
+
- **Stale status detection** — flags tickets stuck in a status too long, team-configurable thresholds. Pro tier
|
|
1110
|
+
- **Shared team Jira config** (Console > Admin > Jira) — manager sets the connection once, team inherits it. Pro+ tier
|
|
1111
|
+
- **Slack/Teams alerts** — needs-response, aging, and compliance-gap alerts plus a weekly digest. Team tier
|
|
1110
1112
|
|
|
1111
1113
|
---
|
|
1112
1114
|
|
package/package.json
CHANGED
|
@@ -33,6 +33,7 @@ import { buildCaptureExcerpt, privateTmpDir } from './recall-nudge-lib.mjs';
|
|
|
33
33
|
import { autoCapture } from '../scripts/lib/summarizer.mjs';
|
|
34
34
|
import { runNoteAdd } from '../scripts/lib/note-command.mjs';
|
|
35
35
|
import { DEFAULT_CONFIG_DIR } from '../scripts/lib/config.mjs';
|
|
36
|
+
import { apiBase } from '../scripts/lib/api-utils.mjs';
|
|
36
37
|
|
|
37
38
|
/** Buffers stream.write() calls instead of touching a real stream — same shape mcp-server.mjs's own capturingStream() uses, this process has no real stdout/stderr worth writing to. */
|
|
38
39
|
function capturingStream() {
|
|
@@ -40,9 +41,12 @@ function capturingStream() {
|
|
|
40
41
|
return { write(s) { parts.push(s); return true; }, get text() { return parts.join(''); } };
|
|
41
42
|
}
|
|
42
43
|
|
|
44
|
+
// backlog #33: every outcome logs its resolved backend URL — "Unauthorized"/
|
|
45
|
+
// "not logged in" reports had no way to attribute which backend was hit
|
|
46
|
+
// (ngrok tunnel rotation and local-dev fallback both silently swap it).
|
|
43
47
|
function logLine(message) {
|
|
44
48
|
try {
|
|
45
|
-
const line = `${new Date().toISOString()} ${message}\n`;
|
|
49
|
+
const line = `${new Date().toISOString()} ${message} [api=${apiBase()}]\n`;
|
|
46
50
|
appendFileSync(join(privateTmpDir(), 'auto-capture.log'), line);
|
|
47
51
|
} catch { /* best-effort — losing a debug log line is not worth failing over */ }
|
|
48
52
|
}
|
|
@@ -85,7 +89,7 @@ export async function runAutoCapture({
|
|
|
85
89
|
try {
|
|
86
90
|
result = await autoCaptureFn({ excerpt, ticketKey, cliToken });
|
|
87
91
|
} catch (err) {
|
|
88
|
-
logLine(`error: ${err.message}`);
|
|
92
|
+
logLine(`error: ${err.message}${err.status ? ` (status=${err.status})` : ''}`);
|
|
89
93
|
return { outcome: 'error', error: err.message };
|
|
90
94
|
}
|
|
91
95
|
|
|
@@ -68,8 +68,10 @@ export function writeState(sessionId, state) {
|
|
|
68
68
|
} catch { /* best-effort — a lost nudge counter is not worth failing the hook over */ }
|
|
69
69
|
}
|
|
70
70
|
|
|
71
|
-
// Two hours — how long a real capture in one directory counts as
|
|
72
|
-
// enough" to skip the Stop hook's nag, even from a brand-new session_id.
|
|
71
|
+
// Two hours of IDLE time — how long a real capture in one directory counts as
|
|
72
|
+
// "recent enough" to skip the Stop hook's nag, even from a brand-new session_id.
|
|
73
|
+
// Sliding, not fixed: ongoing ticket work renews the marker (see
|
|
74
|
+
// recall-nudge-stop.mjs, backlog #24), so only a full idle window lets it lapse.
|
|
73
75
|
export const CAPTURE_FRESHNESS_MS = 2 * 60 * 60 * 1000;
|
|
74
76
|
|
|
75
77
|
/**
|
|
@@ -24,7 +24,9 @@
|
|
|
24
24
|
* the same boundary for a DISMISSED nag: without it, a session that already
|
|
25
25
|
* got its one nag and was told "genuinely nothing qualified" would nag
|
|
26
26
|
* again after the next compaction/resume rollover, since that dismissal
|
|
27
|
-
* was never recorded anywhere — only a real capture was.
|
|
27
|
+
* was never recorded anywhere — only a real capture was. Both markers slide:
|
|
28
|
+
* ongoing ticket work renews them while fresh, so only a full idle window
|
|
29
|
+
* (CAPTURE_FRESHNESS_MS) lets either lapse (backlog #24).
|
|
28
30
|
*
|
|
29
31
|
* Which of the two cases above actually blocks is governed by the effective
|
|
30
32
|
* recallStrictness — the active profile's own explicit config-set value, or
|
|
@@ -102,7 +104,19 @@ if (isLicensed('pro') && cliToken && !hasRecentAutoCaptureAttempt(cwd)) {
|
|
|
102
104
|
// Refreshed on every check, independent of the once-per-session gate below —
|
|
103
105
|
// a capture that happens AFTER this session already nagged once must still
|
|
104
106
|
// update the marker, or a later session_id rollover would find it stale.
|
|
105
|
-
|
|
107
|
+
//
|
|
108
|
+
// Sliding window (backlog #24, 7th report): ongoing ticket work also renews a
|
|
109
|
+
// marker that is still fresh, so it measures idle time, not time since the
|
|
110
|
+
// last capture/nag. A fixed window expired mid-work (capture 17:48, nag 19:48
|
|
111
|
+
// in a session with 23 silent Stops before it) and falsely claimed "nothing
|
|
112
|
+
// was ever captured". Only a session that could itself nag (fetch + mutation)
|
|
113
|
+
// renews, so non-ticket work and read-only lookups in the same cwd can't keep
|
|
114
|
+
// a marker alive; a lapsed marker is never revived. Accepted trade-off: such
|
|
115
|
+
// sessions chained in one cwd with gaps under the window keep suppressing.
|
|
116
|
+
const now = Date.now();
|
|
117
|
+
const isActiveTicketWork = sawFetch && sawMutatingAction;
|
|
118
|
+
if (sawNoteAdd || (isActiveTicketWork && hasRecentCapture(cwd, now))) writeLastCaptureAt(cwd, now);
|
|
119
|
+
if (isActiveTicketWork && hasRecentNag(cwd, now)) writeLastNagAt(cwd, now);
|
|
106
120
|
|
|
107
121
|
const state = readState(sessionId);
|
|
108
122
|
if (state.stopChecked) process.exit(0); // already asked once this session — respect the answer
|
|
@@ -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 = '
|
|
6
|
+
export const DEFAULT_API_BASE = 'https://api.ticketlens.app';
|
|
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,
|