ticketlens 0.43.6 → 0.43.8
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
|
@@ -42,6 +42,7 @@
|
|
|
42
42
|
- [Schedule](#schedule)
|
|
43
43
|
- [History](#history)
|
|
44
44
|
- [Recall](#recall)
|
|
45
|
+
- [MCP Server](#mcp-server)
|
|
45
46
|
- [Comment, Transition, Assign, Duplicates, Link, Update, Create & Worklog](#comment-transition-assign-duplicates-link-update-create--worklog)
|
|
46
47
|
- [Response-Time Stats](#response-time-stats)
|
|
47
48
|
- [Pre-fetch Issue Types](#pre-fetch-issue-types)
|
|
@@ -49,6 +50,7 @@
|
|
|
49
50
|
- [Custom Attention Rules](#custom-attention-rules)
|
|
50
51
|
- [Login](#login)
|
|
51
52
|
- [License](#license)
|
|
53
|
+
- [AI Provider Keys](#ai-provider-keys)
|
|
52
54
|
- [Update Skill](#update-skill)
|
|
53
55
|
- [/jtb — Jira TicketBrief for Claude Code](#jtb--jira-ticketbrief-for-claude-code)
|
|
54
56
|
- [All Examples](#all-examples)
|
|
@@ -65,7 +67,7 @@
|
|
|
65
67
|
|
|
66
68
|
## What is TicketLens?
|
|
67
69
|
|
|
68
|
-
TicketLens is a local-first
|
|
70
|
+
TicketLens is a local-first ticket CLI that preprocesses ticket context on your machine and hands your AI tools a clean, compressed brief — instead of dumping raw Jira API JSON into your session. It supports Jira Cloud, Server, and Data Center (plus GitHub Issues and Linear), works with any AI tool that accepts text, and runs independently of any AI session.
|
|
69
71
|
|
|
70
72
|
Zero npm dependencies. Node.js built-ins only.
|
|
71
73
|
|
|
@@ -73,7 +75,7 @@ Zero npm dependencies. Node.js built-ins only.
|
|
|
73
75
|
|
|
74
76
|
## Why TicketLens?
|
|
75
77
|
|
|
76
|
-
- **Privacy** — ticket content
|
|
78
|
+
- **Privacy** — ticket content stays on your machine by default; no cloud relay, no data sent to Anthropic or anyone else. Only the opt-in features that need a backend (`--cloud`, `compliance --consensus`, `triage --push`/`--share`, Recall team sync) send data to TicketLens
|
|
77
79
|
- **60–80% token savings** — structured briefs instead of verbose Jira JSON; 4-hour cache by default
|
|
78
80
|
- **Scriptable** — standard CLI output: pipe to cron, git hooks, CI/CD, or any LLM tool
|
|
79
81
|
- **Multi-profile** — connect multiple Jira instances simultaneously; auto-route by ticket prefix or project path
|
|
@@ -85,7 +87,7 @@ Zero npm dependencies. Node.js built-ins only.
|
|
|
85
87
|
## Quick Start
|
|
86
88
|
|
|
87
89
|
```bash
|
|
88
|
-
npm
|
|
90
|
+
npm i -g ticketlens@beta
|
|
89
91
|
ticketlens init # Guided setup: Jira, GitHub Issues, or Linear — connection test included
|
|
90
92
|
ticketlens CNV1-2 # Fetch a ticket brief
|
|
91
93
|
ticketlens triage # Scan your assigned tickets
|
|
@@ -94,8 +96,8 @@ ticketlens triage # Scan your assigned tickets
|
|
|
94
96
|
Or without installing:
|
|
95
97
|
|
|
96
98
|
```bash
|
|
97
|
-
npx ticketlens init
|
|
98
|
-
npx ticketlens CNV1-2
|
|
99
|
+
npx ticketlens@beta init
|
|
100
|
+
npx ticketlens@beta CNV1-2
|
|
99
101
|
```
|
|
100
102
|
|
|
101
103
|
Tip: `tl` works everywhere `ticketlens` does — running `tl`/`ticketlens config` before anything is configured also launches guided setup, no dead end. Pass `--no-input` to force non-interactive behavior even in a terminal (scripts, CI).
|
|
@@ -120,6 +122,7 @@ Tip: `tl` works everywhere `ticketlens` does — running `tl`/`ticketlens config
|
|
|
120
122
|
| `ticketlens switch` | Arrow-key panel to switch between configured profiles |
|
|
121
123
|
| `ticketlens config [--profile=NAME]` | Edit any field on an existing profile — always re-validates the connection |
|
|
122
124
|
| `ticketlens profiles` | List all configured profiles (alias: `ticketlens ls`) |
|
|
125
|
+
| `ticketlens profiles set-team <NAME> [team]` | Route a profile's Recall notes to one Console team (for accounts in several teams) |
|
|
123
126
|
| `ticketlens delete <NAME>` | Remove a profile and its credentials (prompts `y/N` in TTY; use `--yes` in scripts/CI) |
|
|
124
127
|
|
|
125
128
|
`init` collects: profile name, tracker type (Jira / GitHub Issues / Linear), URL or workspace, credentials (masked), and optional ticket prefixes, project paths, and triage statuses. On connection failure, a retry menu lets you fix credentials, URL, or skip — all inputs pre-populated. If your Jira instance sits behind a VPN and resolves to a private/internal address, you'll be asked to confirm you trust that connection before it's allowed through — a one-time confirmation, remembered per profile and scoped to that exact host (changing the URL asks again). `config` is tracker-aware and always re-validates the connection after edits.
|
|
@@ -293,12 +296,11 @@ Flag validation provides actionable hints:
|
|
|
293
296
|
```bash
|
|
294
297
|
ticketlens compliance <TICKET-KEY> # Check ticket requirements against local diff [Pro/Free 3/mo]
|
|
295
298
|
ticketlens compliance <TICKET-KEY> --profile=acme # Specify a profile
|
|
296
|
-
ticketlens compliance <TICKET-KEY> --plain # Plain markdown output
|
|
297
299
|
ticketlens compliance <TICKET-KEY> --consensus # Multi-agent AI review instead of the local matcher [Pro]
|
|
298
300
|
ticketlens compliance <TICKET-KEY> --consensus -y # Same, skipping the cost-confirmation prompt
|
|
299
301
|
```
|
|
300
302
|
|
|
301
|
-
Runs the same compliance check as `ticketlens CNV1-2 --compliance` but as a dedicated subcommand — useful when you want to check compliance without fetching the full ticket brief. Free accounts get 3 checks per month; Pro is unlimited.
|
|
303
|
+
Runs the same compliance check as `ticketlens CNV1-2 --compliance` but as a dedicated subcommand — useful when you want to check compliance without fetching the full ticket brief. Free accounts get 3 checks per month; Pro is unlimited. The diff used for matching (and sent for `--consensus`) excludes Markdown files (`*.md`), so requirements met only by doc changes won't register as covered.
|
|
302
304
|
|
|
303
305
|
`--consensus` (Pro) replaces the local deterministic matcher with independent reviews from your team's AI provider pool, reconciled by majority vote after a disagreement-triggered refinement round. Requires `ticketlens login` and a "consensus" role set up at Console > Admin > AI Roles, with 2+ providers attached from your team's shared registry (Console > Admin > AI Provider Pool — any title/key/endpoint/model, not a fixed list). This is the only compliance path that sends your diff off-machine — to TicketLens's backend, which fans out to each provider (keys are encrypted server-side and never sent to the CLI). The diff is scanned for secrets before anything is sent; a detected secret blocks the run with no AI call made. Prompts for confirmation before spending your team's API credits unless `-y`/`--yes` is passed.
|
|
304
306
|
|
|
@@ -331,7 +333,6 @@ Installs a `pre-push` git hook that runs `ticketlens compliance` on every push.
|
|
|
331
333
|
```bash
|
|
332
334
|
ticketlens pr <TICKET-KEY> # Generate PR description from ticket
|
|
333
335
|
ticketlens pr <TICKET-KEY> --profile=acme # Specify a profile
|
|
334
|
-
ticketlens pr <TICKET-KEY> --plain # Plain markdown output
|
|
335
336
|
ticketlens pr <TICKET-KEY> | pbcopy # Copy to clipboard
|
|
336
337
|
ticketlens pr <TICKET-KEY> --open # Open a real GitHub PR compare page (Pro, GitHub only)
|
|
337
338
|
```
|
|
@@ -399,7 +400,7 @@ ticketlens cache clear --profile=acme # One profile's files only
|
|
|
399
400
|
ticketlens cache clear --older-than=30d --yes # Skip confirmation (CI/scripts)
|
|
400
401
|
```
|
|
401
402
|
|
|
402
|
-
Age units: `d` = days · `m` = months (30d) · `y` = years (365d)
|
|
403
|
+
Age units: `h` = hours · `d` = days · `w` = weeks · `m` = months (30d) · `y` = years (365d)
|
|
403
404
|
|
|
404
405
|
Cache locations:
|
|
405
406
|
- Attachments: `~/.ticketlens/cache/TICKET-KEY/`
|
|
@@ -475,6 +476,18 @@ Every note is scanned before saving — anything shaped like a real secret (API
|
|
|
475
476
|
|
|
476
477
|
---
|
|
477
478
|
|
|
479
|
+
### MCP Server
|
|
480
|
+
|
|
481
|
+
```bash
|
|
482
|
+
ticketlens mcp # Start the MCP stdio server (every CLI action as a tool)
|
|
483
|
+
ticketlens mcp install # Register it in the current project's .mcp.json
|
|
484
|
+
ticketlens mcp install --dry-run # Preview without writing
|
|
485
|
+
```
|
|
486
|
+
|
|
487
|
+
Exposes 24 tools (`fetch`, `triage`, `compliance`, `review`, `standup`, `pr`, `stats`, `issue_types`, `history`, `collisions`, `ledger`, `doctor`, `recall_*`, `ticket_*`) to any MCP-compatible AI harness. Starting the server and `mcp install` are ungated; each tool enforces its own tier at call time. Per-tool tiers and details are in the "Any MCP-capable AI harness" paragraph under [Recall](#recall).
|
|
488
|
+
|
|
489
|
+
---
|
|
490
|
+
|
|
478
491
|
### Comment, Transition, Assign, Duplicates, Link, Update, Create & Worklog
|
|
479
492
|
|
|
480
493
|
```bash
|
|
@@ -524,11 +537,11 @@ Write directly to the ticket in its real tracker — Jira, GitHub, or Linear —
|
|
|
524
537
|
|
|
525
538
|
`ticketlens create` creates a new ticket with a fixed minimal field set — no arbitrary custom fields. Unlike every other write command, there's no existing ticket to target, so `--profile` (or your default profile) picks the tracker instead of a ticket key. `--project` is the Jira project key or Linear team key — required for both, ignored on GitHub since its target repo is already fixed by the profile. `--type` is Jira's issue type (e.g. `"Task"`, `"Bug"`) — required for Jira, ignored elsewhere. No `--confirm` gate, same risk tier as `update`/`assign` — but this is the highest-blast-radius command in the whole family: a bad `--project`/`--type` fabricates a real, hard-to-walk-back item in a live tracker, so an invalid value surfaces the tracker's own error rather than a silent guess.
|
|
526
539
|
|
|
527
|
-
`--attach=path1,path2` (comma-separated local file paths) is available on `comment` and `
|
|
540
|
+
`--attach=path1,path2` (comma-separated local file paths) is available on `comment`, `create`, and `note add`/`note patch`, up to 50 files per call (Pro, Team, Enterprise). Images render as an inline thumbnail on Jira and Linear; GitHub has no attachment upload API, so `--attach` is unsupported there.
|
|
528
541
|
|
|
529
542
|
**A bad `--project`/`--type` gets a better error, automatically.** If create fails because the project or issue type doesn't exist, TicketLens fetches your tracker's real, current project list (and, for Jira, the real issue types for that project) and shows them alongside the failure — e.g. `Known creatable projects: CNV1, CNV2.` — rather than a bare tracker error. This is reactive only: it never runs on a successful create, never auto-retries the write, and is cached locally per profile for 3 days (a targeted, single-project lookup — same bar `issue-types --project=KEY` uses) so a burst of failed attempts doesn't re-fetch every time. `ticketlens issue-types` (below) is the proactive counterpart — pre-fetches and caches the same data ahead of time, so a `create` right after it is a pure cache hit.
|
|
530
543
|
|
|
531
|
-
All
|
|
544
|
+
All seven write actions (comment/transition/assign/link/update/create/worklog) have a short local debounce (10s) against an accidental double-fire (a flaky retry, hitting enter twice), and every successful write is appended to a local, append-only audit log (`~/.ticketlens/ticket-action-log.jsonl`). A write that times out is never retried automatically — unlike Recall notes, ticket writes aren't naturally idempotent, so a timed-out attempt is surfaced to you instead of silently repeated. `duplicates` has neither, since nothing is written.
|
|
532
545
|
|
|
533
546
|
---
|
|
534
547
|
|
|
@@ -580,7 +593,7 @@ ticketlens doctor --format=json | jq '.ok'
|
|
|
580
593
|
ticketlens doctor --mcp # Also check the MCP server handshake (spawns a subprocess)
|
|
581
594
|
```
|
|
582
595
|
|
|
583
|
-
Runs
|
|
596
|
+
Runs six checks — profile configuration, license freshness, tracker connectivity, attachment cache health, the Recall sync queue, and MCP registration (plus an opt-in MCP handshake check with `--mcp`) — and reports pass/fail with an actionable hint per failure, instead of a raw stack trace. Free tier, fully unrestricted; no license required.
|
|
584
597
|
|
|
585
598
|
---
|
|
586
599
|
|
|
@@ -603,7 +616,7 @@ Add an `attentionRules` array to any profile in `~/.ticketlens/profiles.json` to
|
|
|
603
616
|
}
|
|
604
617
|
```
|
|
605
618
|
|
|
606
|
-
Rules are evaluated in order — first match wins. Supported `match` keys: `priority`, `label`, `status`, `keyPrefix`. Supported `action` values: `force-urgent` (bumps to needs-response) and `ignore` (excludes from output).
|
|
619
|
+
Rules are evaluated in order — first match wins. Supported `match` keys: `priority`, `label`, `status`, `keyPrefix`. Supported `action` values: `force-urgent` (bumps to needs-response) and `ignore` (excludes from output).
|
|
607
620
|
|
|
608
621
|
---
|
|
609
622
|
|
|
@@ -612,7 +625,7 @@ Rules are evaluated in order — first match wins. Supported `match` keys: `prio
|
|
|
612
625
|
```bash
|
|
613
626
|
ticketlens login # Open browser → authorize in Console → token saved automatically
|
|
614
627
|
ticketlens login --manual # Paste a token instead (CI/headless environments)
|
|
615
|
-
ticketlens logout #
|
|
628
|
+
ticketlens logout # Remove the stored CLI token
|
|
616
629
|
ticketlens sync # Pull your latest tracker profiles from the Console
|
|
617
630
|
```
|
|
618
631
|
|
|
@@ -624,7 +637,7 @@ Use `--manual` when there is no GUI (CI runners, SSH sessions, containers).
|
|
|
624
637
|
|
|
625
638
|
`ticketlens sync` pulls any tracker profiles you have configured in the Console and writes them locally, keeping your CLI in sync with your team settings without re-running `init`.
|
|
626
639
|
|
|
627
|
-
> **Console features** — `ticketlens triage --push`, `--share`, `ticketlens collisions`, and `ticketlens schedule` all require an active Console session. Run `ticketlens login` once and the token is stored automatically.
|
|
640
|
+
> **Console features** — `ticketlens triage --push`, `--share`, `ticketlens collisions`, and `ticketlens schedule` all require an active Console session (`schedule` falls back to local-only mode when logged out). Run `ticketlens login` once and the token is stored automatically.
|
|
628
641
|
|
|
629
642
|
---
|
|
630
643
|
|
|
@@ -637,6 +650,17 @@ ticketlens activate <KEY> # Activate a Pro or Team license
|
|
|
637
650
|
|
|
638
651
|
---
|
|
639
652
|
|
|
653
|
+
### AI Provider Keys
|
|
654
|
+
|
|
655
|
+
```bash
|
|
656
|
+
ticketlens cloud-keys list|add|remove|test|priority|timeout # Manage encrypted AI provider keys (requires login)
|
|
657
|
+
ticketlens config set aiProvider groq # Default provider for --summarize / --handoff
|
|
658
|
+
```
|
|
659
|
+
|
|
660
|
+
Details and the full command list are under [Pro](#pro--9mo).
|
|
661
|
+
|
|
662
|
+
---
|
|
663
|
+
|
|
640
664
|
### Update Skill
|
|
641
665
|
|
|
642
666
|
```bash
|
|
@@ -665,7 +689,7 @@ Supported assistants detected automatically:
|
|
|
665
689
|
**Install:**
|
|
666
690
|
|
|
667
691
|
```bash
|
|
668
|
-
npm
|
|
692
|
+
npm i -g ticketlens@beta && ticketlens init
|
|
669
693
|
ticketlens update-skill # copies /jtb skill into ~/.claude/commands/jtb.md
|
|
670
694
|
# Restart Claude Code, then:
|
|
671
695
|
# /jtb CNV1-2
|
|
@@ -674,7 +698,7 @@ ticketlens update-skill # copies /jtb skill into ~/.claude/commands/jtb.m
|
|
|
674
698
|
**Keeping the skill up to date:**
|
|
675
699
|
|
|
676
700
|
```bash
|
|
677
|
-
npm
|
|
701
|
+
npm i -g ticketlens@beta # update the CLI
|
|
678
702
|
ticketlens update-skill # sync the /jtb skill to the new version
|
|
679
703
|
```
|
|
680
704
|
|
|
@@ -714,8 +738,10 @@ ticketlens config # Edit the active profile
|
|
|
714
738
|
ticketlens config --profile=acme # Edit a specific profile
|
|
715
739
|
ticketlens config set aiProvider groq # Set default AI provider (groq|openai|anthropic)
|
|
716
740
|
ticketlens config set recallStrictness strict # Tune Recall-capture strictness (loose|balanced|strict)
|
|
741
|
+
ticketlens config set errorReporting off # Opt out of (or `on` to opt in to) anonymous error reports
|
|
717
742
|
ticketlens profiles # List all configured profiles
|
|
718
743
|
ticketlens ls # Alias for profiles
|
|
744
|
+
ticketlens profiles set-team <NAME> "Team" # Route a profile's Recall notes to one Console team
|
|
719
745
|
ticketlens profiles --plain # Tab-separated (scripts / pipes)
|
|
720
746
|
ticketlens delete <PROFILE-NAME> # Remove a profile (prompts y/N in TTY)
|
|
721
747
|
ticketlens delete <PROFILE-NAME> --yes # Remove without prompt (scripts/CI)
|
|
@@ -821,8 +847,8 @@ ticketlens cache clear --older-than=30d --yes # Skip confirmation (CI
|
|
|
821
847
|
|
|
822
848
|
# ── Schedule ─────────────────────────────────────────────────────────────────
|
|
823
849
|
ticketlens schedule # Interactive wizard — set time, timezone, profile [Pro]
|
|
824
|
-
ticketlens schedule --stop # Cancel the scheduled digest
|
|
825
|
-
ticketlens schedule --status # Show current schedule
|
|
850
|
+
ticketlens schedule --stop # Cancel the scheduled digest
|
|
851
|
+
ticketlens schedule --status # Show current schedule
|
|
826
852
|
ticketlens schedule --local --time=07:00 --save=./triage.txt # Local-only cron/LaunchAgent, no Console auth [Pro]
|
|
827
853
|
|
|
828
854
|
# ── History ───────────────────────────────────────────────────────────────────
|
|
@@ -834,9 +860,11 @@ echo "note body" | ticketlens note add --title="..." --attach=shot.png,log.txt
|
|
|
834
860
|
ticketlens note delete --id="..." --ticket=CNV1-2 # Remove a note from your local vault [Pro]
|
|
835
861
|
ticketlens recall CNV1-2 # Search saved notes by ticket key [Pro]
|
|
836
862
|
ticketlens recall "retry backoff" # Free-text search across all notes [Pro]
|
|
863
|
+
ticketlens recall CNV1-2 --full # Print each matching note's full body [Pro]
|
|
864
|
+
ticketlens recall CNV1-2 --plain # Plain, pipe-safe output [Pro]
|
|
837
865
|
ticketlens recall sync # Retry any notes stuck in the local queue [Team+]
|
|
838
866
|
ticketlens recall settings # Show effective retry-queue settings + capture strictness, fetched live [Team+]
|
|
839
|
-
ticketlens mcp # Start the MCP stdio server (
|
|
867
|
+
ticketlens mcp # Start the MCP stdio server (every CLI action as a tool; each tool enforces its own tier)
|
|
840
868
|
ticketlens mcp install # Register it into the current project's .mcp.json
|
|
841
869
|
ticketlens mcp install --dry-run # Preview the registration without writing
|
|
842
870
|
|
|
@@ -881,6 +909,7 @@ ticketlens doctor --mcp # Also check the MCP server handsh
|
|
|
881
909
|
|
|
882
910
|
# ── Compliance ────────────────────────────────────────────────────────────────
|
|
883
911
|
ticketlens compliance <TICKET-KEY> # Check ticket requirements against local diff [Pro/Free 3/mo]
|
|
912
|
+
ticketlens compliance <TICKET-KEY> --consensus -y # Multi-agent AI review, skip cost prompt [Pro]
|
|
884
913
|
ticketlens ledger # View local compliance audit ledger [Pro]
|
|
885
914
|
ticketlens install-hooks # Install pre-push compliance gate
|
|
886
915
|
ticketlens install-hooks --uninstall # Remove installed hooks
|
|
@@ -888,6 +917,7 @@ ticketlens install-hooks --uninstall # Remove installed hooks
|
|
|
888
917
|
# ── PR Description ─────────────────────────────────────────────────────────────
|
|
889
918
|
ticketlens pr <TICKET-KEY> # Generate PR description from ticket
|
|
890
919
|
ticketlens pr <TICKET-KEY> | pbcopy # Copy to clipboard
|
|
920
|
+
ticketlens pr <TICKET-KEY> --open # Open a real GitHub PR compare page (Pro, GitHub only)
|
|
891
921
|
|
|
892
922
|
# ── AI provider keys (BYOK) ───────────────────────────────────────────────────
|
|
893
923
|
ticketlens cloud-keys list # List configured AI providers
|
|
@@ -904,7 +934,7 @@ ticketlens cloud-keys --help # Subcommand help
|
|
|
904
934
|
# ── Login ─────────────────────────────────────────────────────────────────────
|
|
905
935
|
ticketlens login # Browser flow — opens Console, token saved automatically
|
|
906
936
|
ticketlens login --manual # Paste flow — for CI/headless environments
|
|
907
|
-
ticketlens logout #
|
|
937
|
+
ticketlens logout # Remove stored CLI token
|
|
908
938
|
ticketlens sync # Pull tracker profiles from the Console
|
|
909
939
|
|
|
910
940
|
# ── License and account ────────────────────────────────────────────────────────
|
|
@@ -953,7 +983,7 @@ ticketlens note delete --id="..." # Remove a note from your local vault
|
|
|
953
983
|
ticketlens recall <query|TICKET-KEY> # Search your saved Recall notes
|
|
954
984
|
ticketlens recall sync # Retry any notes stuck in the local queue
|
|
955
985
|
ticketlens recall settings # Show effective retry-queue settings + capture strictness, fetched live
|
|
956
|
-
ticketlens mcp # Start the MCP stdio server (
|
|
986
|
+
ticketlens mcp # Start the MCP stdio server (every CLI action as a tool)
|
|
957
987
|
ticketlens comment CNV1-2 --body="..." # Post a comment to the tracker
|
|
958
988
|
ticketlens comment CNV1-2 --body="..." --attach=./bug.png # Attach local files (comment/create only)
|
|
959
989
|
ticketlens transition CNV1-2 --target="Done" --confirm # Transition ticket status
|
|
@@ -1104,8 +1134,7 @@ Credentials in `~/.ticketlens/credentials.json` (chmod 600):
|
|
|
1104
1134
|
| 2 | Ticket prefix match | `ticketlens CNV1-2` → prefix `PROJ` → `myteam` |
|
|
1105
1135
|
| 3 | Project path match | `triage` in `~/projects/myteam-app` → `myteam` |
|
|
1106
1136
|
| 4 | `config.default` field | Explicit default set via `ticketlens switch` |
|
|
1107
|
-
| 5 |
|
|
1108
|
-
| 6 | Environment variables | `JIRA_BASE_URL`, `JIRA_EMAIL`, `JIRA_API_TOKEN` / `JIRA_PAT` |
|
|
1137
|
+
| 5 | Environment variables | `JIRA_BASE_URL`, `JIRA_EMAIL`, `JIRA_API_TOKEN` / `JIRA_PAT` |
|
|
1109
1138
|
|
|
1110
1139
|
---
|
|
1111
1140
|
|
|
@@ -1122,6 +1151,11 @@ npm test
|
|
|
1122
1151
|
See [ROADMAP.md](ROADMAP.md) for the full plan.
|
|
1123
1152
|
|
|
1124
1153
|
Recently shipped:
|
|
1154
|
+
- **Upsell tip without a price** — the `--summarize` tip after a deep `fetch` now says "(Pro)" instead of a hardcoded price; plans and prices live in the Console
|
|
1155
|
+
- **Docs match the code** — every doc surface (README, `--help`, SKILL.md, USER_GUIDE, MCP help) re-audited against the CLI; install snippets now use `ticketlens@beta`, Node is `>=22.6`, and the CLI tip shows the real $9/mo Pro price
|
|
1156
|
+
- **Console: Behavior settings** — pick when the idle-warning appears (5 min, 10 min or 1 h) and a playful or plain tone, per user, in Settings > Behavior
|
|
1157
|
+
- **Console: session-expiry warning** — a stay-or-logout countdown appears shortly before your session ends; any activity resets it
|
|
1158
|
+
- **Console: collapsed-sidebar Owner Panel** — the hover menu now opens and stays open when you click an item, like the other groups
|
|
1125
1159
|
- **Tiered attachment cap** — per-call attachment count is now 10 on Free and 50 on Pro, Team and Enterprise (was a flat 20), for uploads, `fetch` downloads and Recall sync. Excess files are reported, not silently dropped
|
|
1126
1160
|
- **`ticketlens pr --open`** — opens a real GitHub PR compare page prefilled with the same description `pr` already prints, instead of just printing it. GitHub only, no stored write-credential. Pro tier
|
|
1127
1161
|
- **`review`/`compliance` fixes** — branch diff now uses merge-base semantics, no longer picks up unrelated unmerged-main files; AC parser now recognizes Jira wiki `Requirements`/`How to test` headers, not just literal "Acceptance Criteria"
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ticketlens",
|
|
3
|
-
"version": "0.43.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.43.8",
|
|
4
|
+
"description": "Ticket CLI for developers (Jira, GitHub Issues, Linear) — fetch ticket context, triage your queue, and stop tab-switching. Zero dependencies, local-first.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
7
|
"ticketlens": "bin/ticketlens.mjs",
|
package/skills/jtb/SKILL.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
<!-- jtb-skill-version: 0.49.
|
|
1
|
+
<!-- jtb-skill-version: 0.49.2 -->
|
|
2
2
|
---
|
|
3
3
|
name: jtb
|
|
4
4
|
description: Fetch a Jira ticket's full context (description, comments, linked issues, code references) and assemble a structured TicketBrief for implementation planning. Use when user types /jtb, mentions a Jira ticket key, or wants to plan work from a Jira ticket.
|
|
@@ -484,7 +484,7 @@ ticketlens worklog PROD-1234=1h30m PROD-5678=45m --comment="Sprint work" --confi
|
|
|
484
484
|
- The MCP tool takes `entries[]` with per-ticket `comment`/`started`.
|
|
485
485
|
- The CLI applies one `--comment`/`--started` to every ticket.
|
|
486
486
|
|
|
487
|
-
`--attach=path1,path2` (comma-separated local file paths) is available on `comment` and `
|
|
487
|
+
`--attach=path1,path2` (comma-separated local file paths) is available on `comment`, `create`, and `note add`/`note patch`, up to 50 files per call (Pro, Team, Enterprise). Images render as an inline thumbnail on Jira and Linear; GitHub has no attachment upload API, so `--attach` is unsupported there.
|
|
488
488
|
|
|
489
489
|
The write actions (comment/transition/assign/link/update/create/worklog) have a short local debounce (10s) against an accidental double-fire, and every write is appended to a local audit log (`~/.ticketlens/ticket-action-log.jsonl`). A write that times out is never retried automatically — surface the failure to the user rather than silently re-attempting, since a ticket write isn't naturally idempotent the way a Recall note save is. `duplicates` has neither, since nothing is written.
|
|
490
490
|
|
|
@@ -588,7 +588,7 @@ Use this evaluation order:
|
|
|
588
588
|
`--compliance` never sends data anywhere. The diff stays local. All analysis is performed by Claude Code within your session context. (The standalone command's `--consensus` opt-in below is the one exception — see that section.)
|
|
589
589
|
|
|
590
590
|
### Standalone command
|
|
591
|
-
The same tier-gated check also runs as its own command — `ticketlens compliance PROJ-123` — independent of a full ticket fetch. This is what `ticketlens install-hooks` wires into a pre-push git hook (`ticketlens compliance "$KEY" || exit 1`, gated on a configurable coverage threshold). It shares the same `FREE_LIMIT`/Pro gate and the same compliance ledger as the `--compliance` flag above.
|
|
591
|
+
The same tier-gated check also runs as its own command — `ticketlens compliance PROJ-123` — independent of a full ticket fetch. This is what `ticketlens install-hooks` wires into a pre-push git hook (`ticketlens compliance "$KEY" || exit 1`, gated on a configurable coverage threshold). It shares the same `FREE_LIMIT`/Pro gate and the same compliance ledger as the `--compliance` flag above. The diff it evaluates (and sends for `--consensus`) excludes Markdown files (`*.md`), so requirements met only by doc changes won't register as covered.
|
|
592
592
|
|
|
593
593
|
If this harness has TicketLens's MCP server configured (a tool named `compliance` — often shown as `mcp__ticketlens__compliance` — visible in your tool list), prefer it over the bash form: same tier gate (Free: 3 checks/month, Pro: unlimited), same report — just no shell command to construct or stdout to parse. It accepts `ticket`/`profile`/`consensus`, matching the standalone command's arguments below.
|
|
594
594
|
|
|
@@ -623,7 +623,7 @@ Generates an AI-powered summary of the full brief, collapsing verbose descriptio
|
|
|
623
623
|
|
|
624
624
|
- **BYOK (default):** reads your AI API key from `~/.ticketlens/credentials.json`. First use will prompt for consent.
|
|
625
625
|
- **`--cloud`:** routes through TicketLens cloud API (no local key needed, requires Pro).
|
|
626
|
-
- **`--provider=NAME`:** override the AI provider. Supported values
|
|
626
|
+
- **`--provider=NAME`:** override the AI provider. Supported values: `anthropic`, `openai`, `groq` (whichever you have a key for).
|
|
627
627
|
- **`--budget=N`:** prune the brief to approximately N tokens before summarising. Forces plain-text output.
|
|
628
628
|
|
|
629
629
|
### --handoff (Pro)
|
|
@@ -32,6 +32,7 @@ import { parseAge } from './lib/cache-manager.mjs';
|
|
|
32
32
|
import { createStyler } from './lib/ansi.mjs';
|
|
33
33
|
import { apiBase } from './lib/api-utils.mjs';
|
|
34
34
|
import { isLicensed, showUpgradePrompt, readLicense } from './lib/license.mjs';
|
|
35
|
+
import { SUMMARIZE_TIP } from './lib/upsell-tips.mjs';
|
|
35
36
|
import { detectVcs } from './lib/vcs-detector.mjs';
|
|
36
37
|
import { runComplianceCheck } from './lib/compliance-checker.mjs';
|
|
37
38
|
import { runConsensusCheck } from './lib/consensus-checker.mjs';
|
|
@@ -1456,7 +1457,7 @@ export async function run(args, envOrOpts = process.env, fetcher = globalThis.fe
|
|
|
1456
1457
|
// Contextual upsell: after a deep traversal with a substantial graph, nudge toward --summarize
|
|
1457
1458
|
if (depth > 1 && !args.includes('--summarize') && (ticket.linked?.length ?? 0) >= 2) {
|
|
1458
1459
|
const s = createStyler({ isTTY: process.stderr.isTTY });
|
|
1459
|
-
printErrFn(` ${s.dim('○')} ${s.dim(
|
|
1460
|
+
printErrFn(` ${s.dim('○')} ${s.dim(SUMMARIZE_TIP)}\n`);
|
|
1460
1461
|
}
|
|
1461
1462
|
}
|
|
1462
1463
|
|
|
@@ -45,19 +45,19 @@ export function printHelp({ stream = process.stdout } = {}) {
|
|
|
45
45
|
` ${s.brand('ticketlens')} compliance ${s.dim('<TICKET-KEY>')} Check requirements coverage ${s.dim('[Pro/Free 3/mo]')}`,
|
|
46
46
|
` ${s.brand('ticketlens')} install-hooks ${s.dim('[--uninstall]')} Git pre-push compliance gate`,
|
|
47
47
|
` ${s.brand('ticketlens')} pr ${s.dim('<TICKET-KEY>')} Assemble a PR description from ticket context`,
|
|
48
|
-
` ${s.brand('ticketlens')} ledger ${s.dim('[--format=json|csv]')} Export your signed
|
|
48
|
+
` ${s.brand('ticketlens')} ledger ${s.dim('[--format=json|csv]')} Export your signed compliance ledger ${s.dim('[Pro]')}`,
|
|
49
49
|
` ${s.brand('ticketlens')} history ${s.dim('<TICKET-KEY>')} Urgency timeline for a ticket ${s.dim('[Pro]')}`,
|
|
50
50
|
` ${s.brand('ticketlens')} stats ${s.dim('[options]')} Personal response-time metrics from local history`,
|
|
51
51
|
` ${s.brand('ticketlens')} doctor ${s.dim('[--fix] [options]')} Diagnose profile/license/connectivity/cache/queue problems`,
|
|
52
|
-
` ${s.brand('ticketlens')} note add ${s.dim('--title=... [--ticket=KEY]')} Save a Recall note ${s.dim('[Pro]')}`,
|
|
52
|
+
` ${s.brand('ticketlens')} note add ${s.dim('--title=... [--ticket=KEY] [--attach=a,b]')} Save a Recall note ${s.dim('[Pro]')}`,
|
|
53
53
|
` ${s.brand('ticketlens')} note delete ${s.dim('--id=... [--ticket=KEY]')} Remove a note from your local vault ${s.dim('[Pro]')}`,
|
|
54
54
|
` ${s.brand('ticketlens')} recall ${s.dim('<query|TICKET-KEY>')} Search your saved Recall notes ${s.dim('[Pro]')}`,
|
|
55
55
|
` ${s.brand('ticketlens')} recall sync Retry any notes stuck in the local queue ${s.dim('[Team+]')}`,
|
|
56
56
|
` ${s.brand('ticketlens')} recall settings Show effective retry-queue settings + capture strictness, fetched live ${s.dim('[Team+]')}`,
|
|
57
|
-
` ${s.brand('ticketlens')} mcp Start the MCP stdio server (
|
|
57
|
+
` ${s.brand('ticketlens')} mcp Start the MCP stdio server (all CLI actions; each tool enforces its own tier)`,
|
|
58
58
|
` ${s.brand('ticketlens')} comment ${s.dim('<TICKET-KEY> --body=... [--attach=...]')} Post a comment to the tracker ${s.dim('[Pro]')}`,
|
|
59
59
|
` ${s.brand('ticketlens')} transition ${s.dim('<TICKET-KEY> [--target=... --confirm]')} Move ticket status ${s.dim('[Pro]')}`,
|
|
60
|
-
` ${s.brand('ticketlens')} assign ${s.dim('<TICKET-KEY> --to=me')} Assign a ticket to yourself ${s.dim('[Pro]')}`,
|
|
60
|
+
` ${s.brand('ticketlens')} assign ${s.dim('<TICKET-KEY> --to=me')} Assign a ticket to yourself or (Jira) another dev ${s.dim('[Pro]')}`,
|
|
61
61
|
` ${s.brand('ticketlens')} worklog ${s.dim('<KEY=DURATION ...> [--comment=... --started=...] --confirm')} Log time on Jira tickets ${s.dim('[Pro] [Jira only]')}`,
|
|
62
62
|
` ${s.brand('ticketlens')} duplicates ${s.dim('<TICKET-KEY> [--threshold=N]')} Find likely duplicate tickets ${s.dim('[Pro]')}`,
|
|
63
63
|
` ${s.brand('ticketlens')} link ${s.dim('<SOURCE> <TARGET> [--type=... --confirm]')} Link two tickets ${s.dim('[Pro]')}`,
|
|
@@ -113,7 +113,7 @@ export function printHelp({ stream = process.stdout } = {}) {
|
|
|
113
113
|
` ${s.brand('--priority')}=${s.dim('LEVEL')} Filter by priority ${s.dim('(e.g. High, Blocker) [Team]')}`,
|
|
114
114
|
` ${s.brand('--export')}=${s.dim('FORMAT')} Export results to file ${s.dim('(csv|json) [Team]')}`,
|
|
115
115
|
` ${s.brand('--push')} Push snapshot to Console queue ${s.dim('[Team]')}`,
|
|
116
|
-
` ${s.brand('--share')} Generate a 24h share URL ${s.dim('(no login
|
|
116
|
+
` ${s.brand('--share')} Generate a 24h share URL ${s.dim('(recipients need no login) [Team]')}`,
|
|
117
117
|
` ${s.brand('--all')} Triage all configured profiles at once ${s.dim('[Pro]')}`,
|
|
118
118
|
` ${s.brand('--save')}=${s.dim('FILE')} Save ANSI-stripped output to file ${s.dim('[Pro]')}`,
|
|
119
119
|
` ${s.brand('--digest')} POST scored results to digest endpoint ${s.dim('[Pro]')}`,
|
|
@@ -560,7 +560,7 @@ export function printNoteHelp({ stream = process.stdout } = {}) {
|
|
|
560
560
|
const s = createStyler({ isTTY: stream.isTTY });
|
|
561
561
|
const lines = [
|
|
562
562
|
'',
|
|
563
|
-
` ${s.bold(s.brand('ticketlens'))} ${s.bold('note add')} ${s.dim('--title="..." [--ticket=KEY] [--tags=a,b]')} ${s.dim('[Pro]')}`,
|
|
563
|
+
` ${s.bold(s.brand('ticketlens'))} ${s.bold('note add')} ${s.dim('--title="..." [--ticket=KEY] [--tags=a,b] [--attach=a,b]')} ${s.dim('[Pro]')}`,
|
|
564
564
|
'',
|
|
565
565
|
` Save a short note about a ticket to your local Recall vault. ${s.dim('[Pro]')}`,
|
|
566
566
|
` Notes are saved at ${s.cyan('~/.ticketlens/recall/')} and matched into future ticket briefs.`,
|
|
@@ -572,6 +572,7 @@ export function printNoteHelp({ stream = process.stdout } = {}) {
|
|
|
572
572
|
` ${s.brand('--ticket')}=${s.dim('KEY')} Ticket this note is about ${s.dim('(optional — omit for a general note)')}`,
|
|
573
573
|
` ${s.brand('--tags')}=${s.dim('a,b')} Comma-separated tags`,
|
|
574
574
|
` ${s.brand('--include-attachments')} Seed the note with text from this ticket's cached attachments`,
|
|
575
|
+
` ${s.brand('--attach')}=${s.dim('a,b')} Comma-separated local files to save with the note ${s.dim('(10 on Free, 50 on Pro+)')}`,
|
|
575
576
|
` ${s.brand('--plain')} Plain confirmation, no color (default when piped)`,
|
|
576
577
|
` ${s.brand('-h')}, ${s.brand('--help')} Show this help`,
|
|
577
578
|
'',
|
|
@@ -579,7 +580,7 @@ export function printNoteHelp({ stream = process.stdout } = {}) {
|
|
|
579
580
|
'',
|
|
580
581
|
` ${s.dim('$')} echo "Retry needs exponential backoff" | ticketlens note add --title="Retry gotcha" --ticket=PROD-123 --tags=bug`,
|
|
581
582
|
'',
|
|
582
|
-
` ${s.bold('ticketlens note patch')} ${s.dim('--id="..." [--ticket=KEY] [--expect-mtime=MS]')} ${s.dim('[Pro]')}`,
|
|
583
|
+
` ${s.bold('ticketlens note patch')} ${s.dim('--id="..." [--ticket=KEY] [--expect-mtime=MS] [--attach=a,b]')} ${s.dim('[Pro]')}`,
|
|
583
584
|
'',
|
|
584
585
|
` Overwrites an existing note's body with a better draft, read from stdin.`,
|
|
585
586
|
` Internal mechanism used by the jtb skill's note quality loop inside a Claude`,
|
|
@@ -592,6 +593,7 @@ export function printNoteHelp({ stream = process.stdout } = {}) {
|
|
|
592
593
|
` ${s.brand('--ticket')}=${s.dim('KEY')} Ticket this note is about ${s.dim('(optional)')}`,
|
|
593
594
|
` ${s.brand('--expect-mtime')}=${s.dim('MS')} File mtime (ms) the caller last observed ${s.dim('(optional)')} — a no-op,`,
|
|
594
595
|
` not an overwrite, if the file changed since then`,
|
|
596
|
+
` ${s.brand('--attach')}=${s.dim('a,b')} Append local files to the note, never replacing existing ones ${s.dim('(optional)')}`,
|
|
595
597
|
'',
|
|
596
598
|
` ${s.bold('ticketlens note delete')} ${s.dim('--id="..." [--ticket=KEY] [--yes]')} ${s.dim('[Pro]')}`,
|
|
597
599
|
'',
|
|
@@ -1016,6 +1018,7 @@ export function printConfigHelp({ stream = process.stdout } = {}) {
|
|
|
1016
1018
|
` ${s.bold(s.brand('ticketlens'))} ${s.bold('config')} ${s.dim('[--profile=NAME]')}`,
|
|
1017
1019
|
` ${s.bold(s.brand('ticketlens'))} ${s.bold('config set aiProvider')} ${s.dim('<anthropic|openai|groq>')}`,
|
|
1018
1020
|
` ${s.bold(s.brand('ticketlens'))} ${s.bold('config set recallStrictness')} ${s.dim('<loose|balanced|strict>')}`,
|
|
1021
|
+
` ${s.bold(s.brand('ticketlens'))} ${s.bold('config set errorReporting')} ${s.dim('<on|off>')}`,
|
|
1019
1022
|
'',
|
|
1020
1023
|
` Edit settings for an existing profile using an interactive wizard.`,
|
|
1021
1024
|
` Without ${s.cyan('--profile')}, edits the currently active profile.`,
|
|
@@ -1035,6 +1038,8 @@ export function printConfigHelp({ stream = process.stdout } = {}) {
|
|
|
1035
1038
|
` ${s.dim('balanced')} = today's default behavior`,
|
|
1036
1039
|
` ${s.dim('strict')} = capture more liberally, when in doubt`,
|
|
1037
1040
|
'',
|
|
1041
|
+
` ${s.brand('set errorReporting')} ${s.dim('<on|off>')} Opt in or out of anonymous error reports`,
|
|
1042
|
+
'',
|
|
1038
1043
|
` ${s.bold('OPTIONS')}`,
|
|
1039
1044
|
'',
|
|
1040
1045
|
` ${s.brand('--profile')}=${s.dim('NAME')} Profile to configure`,
|
|
@@ -1047,6 +1052,7 @@ export function printConfigHelp({ stream = process.stdout } = {}) {
|
|
|
1047
1052
|
` ${s.dim('$')} ticketlens config set aiProvider groq`,
|
|
1048
1053
|
` ${s.dim('$')} ticketlens config set aiProvider anthropic`,
|
|
1049
1054
|
` ${s.dim('$')} ticketlens config set recallStrictness strict`,
|
|
1055
|
+
` ${s.dim('$')} ticketlens config set errorReporting off`,
|
|
1050
1056
|
'',
|
|
1051
1057
|
];
|
|
1052
1058
|
stream.write(lines.join('\n') + '\n');
|
|
@@ -1076,7 +1082,7 @@ export function printTriageHelp({ stream = process.stdout } = {}) {
|
|
|
1076
1082
|
` ${s.brand('--priority')}=${s.dim('LEVEL')} Filter by priority ${s.dim('(e.g. High, Blocker) [Team]')}`,
|
|
1077
1083
|
` ${s.brand('--export')}=${s.dim('FORMAT')} Export results to file ${s.dim('(csv|json) [Team]')}`,
|
|
1078
1084
|
` ${s.brand('--push')} Push snapshot to Console queue ${s.dim('[Team]')}`,
|
|
1079
|
-
` ${s.brand('--share')} Generate a 24h share URL ${s.dim('(no login
|
|
1085
|
+
` ${s.brand('--share')} Generate a 24h share URL ${s.dim('(recipients need no login) [Team]')}`,
|
|
1080
1086
|
` ${s.brand('--all')} Triage all configured profiles at once ${s.dim('[Pro]')}`,
|
|
1081
1087
|
` ${s.brand('--save')}=${s.dim('FILE')} Save ANSI-stripped output to file ${s.dim('[Pro]')}`,
|
|
1082
1088
|
` ${s.brand('--digest')} POST scored results to digest endpoint ${s.dim('[Pro]')}`,
|
|
@@ -1187,8 +1193,8 @@ export function printLedgerHelp({ stream = process.stdout } = {}) {
|
|
|
1187
1193
|
'',
|
|
1188
1194
|
` ${s.bold(s.brand('ticketlens'))} ${s.bold('ledger')} ${s.dim('[--format=json|csv]')} ${s.dim('[Pro]')}`,
|
|
1189
1195
|
'',
|
|
1190
|
-
` Export your local
|
|
1191
|
-
`
|
|
1196
|
+
` Export your local compliance ledger — a signed, tamper-evident record of`,
|
|
1197
|
+
` every compliance check run (Pro). Verifiable offline via an`,
|
|
1192
1198
|
` HMAC-SHA256 signature over {records, exportedAt}, keyed at ledger-key.`,
|
|
1193
1199
|
'',
|
|
1194
1200
|
` ${s.bold('OPTIONS')}`,
|
|
@@ -1268,7 +1274,7 @@ export function printUpdateSkillHelp({ stream = process.stdout } = {}) {
|
|
|
1268
1274
|
` ${s.bold(s.brand('ticketlens'))} ${s.bold('update-skill')} ${s.dim('[--dry-run] [--path=DIR] [--quiet]')}`,
|
|
1269
1275
|
'',
|
|
1270
1276
|
` Copy the latest /jtb SKILL.md into every detected AI assistant command directory.`,
|
|
1271
|
-
` Runs automatically on ${s.dim('npm
|
|
1277
|
+
` Runs automatically on ${s.dim('npm i -g ticketlens@beta')} for existing installs.`,
|
|
1272
1278
|
'',
|
|
1273
1279
|
` ${s.bold('SUPPORTED ASSISTANTS')}`,
|
|
1274
1280
|
'',
|
|
@@ -1368,7 +1374,7 @@ export function printStatsHelp({ stream = process.stdout } = {}) {
|
|
|
1368
1374
|
` ${s.bold(s.brand('ticketlens'))} ${s.bold('stats')} ${s.dim('[--days=N] [--format=plain|json] [--profile=NAME]')}`,
|
|
1369
1375
|
'',
|
|
1370
1376
|
` Show response-time and triage-cadence metrics from your local triage history.`,
|
|
1371
|
-
` Reads daily snapshots
|
|
1377
|
+
` Reads daily snapshots saved automatically by every ${s.brand('ticketlens triage')} run.`,
|
|
1372
1378
|
'',
|
|
1373
1379
|
` ${s.bold('OPTIONS')}`,
|
|
1374
1380
|
'',
|