ticketlens 0.1.3 → 0.1.5

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.
@@ -17,7 +17,13 @@ import { run as runConfig } from '../skills/jtb/scripts/lib/config-wizard.mjs';
17
17
  import { activateLicense, checkLicense, revalidateIfStale, isLicensed, showUpgradePrompt, readLicense } from '../skills/jtb/scripts/lib/license.mjs';
18
18
  import { deleteProfile, loadProfiles } from '../skills/jtb/scripts/lib/profile-resolver.mjs';
19
19
  import { run as runCache } from '../skills/jtb/scripts/lib/cache-manager.mjs';
20
- import { printHelp, printProfiles } from '../skills/jtb/scripts/lib/help.mjs';
20
+ import {
21
+ printHelp, printProfiles,
22
+ printLoginHelp, printLogoutHelp, printSyncHelp,
23
+ printActivateHelp, printLicenseHelp, printDeleteHelp,
24
+ printProfilesHelp, printScheduleHelp,
25
+ printInitHelp, printSwitchHelp, printConfigHelp,
26
+ } from '../skills/jtb/scripts/lib/help.mjs';
21
27
  import { createStyler } from '../skills/jtb/scripts/lib/ansi.mjs';
22
28
  import { readCliToken, saveCliToken, deleteCliToken } from '../skills/jtb/scripts/lib/cli-auth.mjs';
23
29
  import { syncProfiles, getApiBase, getConsoleBase } from '../skills/jtb/scripts/lib/sync.mjs';
@@ -45,6 +51,7 @@ switch (command) {
45
51
  break;
46
52
 
47
53
  case 'init':
54
+ if (cmdArgs.includes('--help') || cmdArgs.includes('-h')) { printInitHelp(); break; }
48
55
  runInit().catch(err => {
49
56
  process.stderr.write(`Error: ${err.message}\n`);
50
57
  process.exitCode = 1;
@@ -52,6 +59,7 @@ switch (command) {
52
59
  break;
53
60
 
54
61
  case 'switch':
62
+ if (cmdArgs.includes('--help') || cmdArgs.includes('-h')) { printSwitchHelp(); break; }
55
63
  runSwitch().catch(err => {
56
64
  process.stderr.write(`Error: ${err.message}\n`);
57
65
  process.exitCode = 1;
@@ -59,6 +67,7 @@ switch (command) {
59
67
  break;
60
68
 
61
69
  case 'config': {
70
+ if (cmdArgs.includes('--help') || cmdArgs.includes('-h')) { printConfigHelp(); break; }
62
71
  const profileArg = cmdArgs.find(a => a.startsWith('--profile='));
63
72
  const profileName = profileArg ? profileArg.split('=')[1] : undefined;
64
73
  runConfig({ profileName }).catch(err => {
@@ -69,6 +78,7 @@ switch (command) {
69
78
  }
70
79
 
71
80
  case 'activate': {
81
+ if (cmdArgs.includes('--help') || cmdArgs.includes('-h')) { printActivateHelp(); break; }
72
82
  const s = createStyler({ isTTY: process.stdout.isTTY });
73
83
  const key = cmdArgs.find(a => !a.startsWith('--'));
74
84
  if (!key) {
@@ -90,6 +100,7 @@ switch (command) {
90
100
  }
91
101
 
92
102
  case 'license': {
103
+ if (cmdArgs.includes('--help') || cmdArgs.includes('-h')) { printLicenseHelp(); break; }
93
104
  const s = createStyler({ isTTY: process.stdout.isTTY });
94
105
  const status = checkLicense();
95
106
  const daysSinceVal = status.validatedAt
@@ -131,6 +142,7 @@ switch (command) {
131
142
  }
132
143
 
133
144
  case 'delete': {
145
+ if (cmdArgs.includes('--help') || cmdArgs.includes('-h')) { printDeleteHelp(); break; }
134
146
  const s = createStyler({ isTTY: process.stderr.isTTY });
135
147
  const profileName = cmdArgs.find(a => !a.startsWith('--'));
136
148
  if (!profileName) {
@@ -182,6 +194,7 @@ switch (command) {
182
194
  }
183
195
 
184
196
  case 'profiles': {
197
+ if (cmdArgs.includes('--help') || cmdArgs.includes('-h')) { printProfilesHelp(); break; }
185
198
  const plain = cmdArgs.includes('--plain');
186
199
  const config = loadProfiles();
187
200
  printProfiles({ config, plain });
@@ -203,6 +216,7 @@ switch (command) {
203
216
  }
204
217
 
205
218
  case 'schedule': {
219
+ if (cmdArgs.includes('--help') || cmdArgs.includes('-h')) { printScheduleHelp(); break; }
206
220
  const subCmd = cmdArgs[0];
207
221
 
208
222
  if (subCmd === '--stop') {
@@ -262,6 +276,7 @@ switch (command) {
262
276
  break;
263
277
 
264
278
  case 'login': {
279
+ if (cmdArgs.includes('--help') || cmdArgs.includes('-h')) { printLoginHelp(); break; }
265
280
  (async () => {
266
281
  const s = createStyler({ isTTY: process.stderr.isTTY });
267
282
  process.stderr.write(`\n ${s.bold('TicketLens Login')}\n`);
@@ -312,6 +327,7 @@ switch (command) {
312
327
  }
313
328
 
314
329
  case 'logout': {
330
+ if (cmdArgs.includes('--help') || cmdArgs.includes('-h')) { printLogoutHelp(); break; }
315
331
  const s = createStyler({ isTTY: process.stderr.isTTY });
316
332
  deleteCliToken();
317
333
  process.stderr.write(` ${s.green('✔')} CLI token removed.\n`);
@@ -319,6 +335,7 @@ switch (command) {
319
335
  }
320
336
 
321
337
  case 'sync': {
338
+ if (cmdArgs.includes('--help') || cmdArgs.includes('-h')) { printSyncHelp(); break; }
322
339
  (async () => {
323
340
  const s = createStyler({ isTTY: process.stderr.isTTY });
324
341
  process.stderr.write(`\n ${s.dim('Syncing from TicketLens console…')}\n`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ticketlens",
3
- "version": "0.1.3",
3
+ "version": "0.1.5",
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": {
@@ -24,11 +24,13 @@ export function printHelp({ stream = process.stdout } = {}) {
24
24
  '',
25
25
  ` ${s.bold('USAGE')}`,
26
26
  '',
27
- // visible widths: "ticketlens init"=15, "switch"=17, "config [--profile=NAME]"=34,
28
- // "profiles"=19, "<TICKET-KEY> [options]"=33, "triage [options]"=27,
29
- // "activate <KEY>"=25, "license"=18, "cache [size|clear]"=29 → target=36
30
- // Groups: Setup ─── Daily use ─── Account / Maintenance
31
- ` ${s.brand('ticketlens')} init Configure Jira connections`,
27
+ // visible widths target column = 36 visible chars for the command portion
28
+ // Groups: Console sync ─── Setup ─── Daily use ─── Account / Maintenance
29
+ ` ${s.brand('ticketlens')} login Connect CLI to your TicketLens account`,
30
+ ` ${s.brand('ticketlens')} logout Remove stored credentials`,
31
+ ` ${s.brand('ticketlens')} sync Pull tracker profiles from the console`,
32
+ '',
33
+ ` ${s.brand('ticketlens')} init Configure connections locally`,
32
34
  ` ${s.brand('ticketlens')} switch Switch active profile`,
33
35
  ` ${s.brand('ticketlens')} config ${s.dim('[--profile=NAME]')} Edit profile settings`,
34
36
  ` ${s.brand('ticketlens')} profiles List all configured profiles ${s.dim('(alias: ls)')}`,
@@ -75,6 +77,8 @@ export function printHelp({ stream = process.stdout } = {}) {
75
77
  '',
76
78
  ` ${s.bold('EXAMPLES')}`,
77
79
  '',
80
+ ` ${s.dim('$')} ticketlens login ${s.dim('# first-time setup')}`,
81
+ ` ${s.dim('$')} ticketlens sync ${s.dim('# pull connections from console')}`,
78
82
  ` ${s.dim('$')} ticketlens PROJ-123`,
79
83
  ` ${s.dim('$')} ticketlens get PROJ-123 --depth=0 --profile=myteam`,
80
84
  ` ${s.dim('$')} ticketlens triage`,
@@ -83,11 +87,13 @@ export function printHelp({ stream = process.stdout } = {}) {
83
87
  '',
84
88
  ` ${s.bold('CONFIGURATION')}`,
85
89
  '',
90
+ ` ${s.dim('CLI token:')} ~/.ticketlens/cli-token ${s.dim('(written by ticketlens login)')}`,
86
91
  ` ${s.dim('Profiles:')} ~/.ticketlens/profiles.json`,
87
92
  ` ${s.dim('Credentials:')} ~/.ticketlens/credentials.json`,
88
93
  ` ${s.dim('License:')} ~/.ticketlens/license.json`,
89
94
  '',
90
95
  ` ${s.dim('Or use env vars:')} JIRA_BASE_URL, JIRA_EMAIL, JIRA_API_TOKEN`,
96
+ ` ${s.dim(' ')} TICKETLENS_API_URL ${s.dim('(override API host for local dev)')}`,
91
97
  '',
92
98
  '',
93
99
  ];
@@ -209,6 +215,283 @@ export function printProfiles({ stream = process.stdout, config, plain = false }
209
215
  stream.write(lines.join('\n') + '\n');
210
216
  }
211
217
 
218
+ export function printLoginHelp({ stream = process.stdout } = {}) {
219
+ const s = createStyler({ isTTY: stream.isTTY });
220
+ const lines = [
221
+ '',
222
+ ` ${s.bold(s.brand('ticketlens'))} ${s.bold('login')}`,
223
+ '',
224
+ ` Connect the CLI to your TicketLens account using a CLI token.`,
225
+ ` Validates the token against the API before saving it locally.`,
226
+ '',
227
+ ` ${s.bold('HOW IT WORKS')}`,
228
+ '',
229
+ ` 1. Generate a CLI token at ${s.cyan(`${s.dim('<console-url>')}/console/account`)}`,
230
+ ` 2. Run ${s.cyan('ticketlens login')} and paste the token when prompted`,
231
+ ` 3. Run ${s.cyan('ticketlens sync')} to pull your tracker connections`,
232
+ '',
233
+ ` ${s.bold('OPTIONS')}`,
234
+ '',
235
+ ` ${s.brand('-h')}, ${s.brand('--help')} Show this help`,
236
+ '',
237
+ ` ${s.bold('EXAMPLES')}`,
238
+ '',
239
+ ` ${s.dim('$')} ticketlens login`,
240
+ ` ${s.dim('$')} ticketlens sync ${s.dim('# after login, pull connections')}`,
241
+ '',
242
+ ` ${s.bold('FILES')}`,
243
+ '',
244
+ ` ${s.dim('Token saved to:')} ~/.ticketlens/cli-token`,
245
+ '',
246
+ ];
247
+ stream.write(lines.join('\n') + '\n');
248
+ }
249
+
250
+ export function printLogoutHelp({ stream = process.stdout } = {}) {
251
+ const s = createStyler({ isTTY: stream.isTTY });
252
+ const lines = [
253
+ '',
254
+ ` ${s.bold(s.brand('ticketlens'))} ${s.bold('logout')}`,
255
+ '',
256
+ ` Remove the stored CLI token, disconnecting this machine from your`,
257
+ ` TicketLens account. Local profiles and credentials are kept intact.`,
258
+ '',
259
+ ` ${s.bold('OPTIONS')}`,
260
+ '',
261
+ ` ${s.brand('-h')}, ${s.brand('--help')} Show this help`,
262
+ '',
263
+ ` ${s.bold('EXAMPLES')}`,
264
+ '',
265
+ ` ${s.dim('$')} ticketlens logout`,
266
+ ` ${s.dim('$')} ticketlens login ${s.dim('# re-authenticate')}`,
267
+ '',
268
+ ];
269
+ stream.write(lines.join('\n') + '\n');
270
+ }
271
+
272
+ export function printSyncHelp({ stream = process.stdout } = {}) {
273
+ const s = createStyler({ isTTY: stream.isTTY });
274
+ const lines = [
275
+ '',
276
+ ` ${s.bold(s.brand('ticketlens'))} ${s.bold('sync')}`,
277
+ '',
278
+ ` Pull tracker connections from the TicketLens console and write them`,
279
+ ` to ${s.dim('~/.ticketlens/profiles.json')}. Requires ${s.cyan('ticketlens login')} first.`,
280
+ '',
281
+ ` Profiles that need credentials will be listed with a reminder to`,
282
+ ` run ${s.cyan('ticketlens config --profile=NAME')} to add them.`,
283
+ '',
284
+ ` ${s.bold('OPTIONS')}`,
285
+ '',
286
+ ` ${s.brand('-h')}, ${s.brand('--help')} Show this help`,
287
+ '',
288
+ ` ${s.bold('EXAMPLES')}`,
289
+ '',
290
+ ` ${s.dim('$')} ticketlens login`,
291
+ ` ${s.dim('$')} ticketlens sync`,
292
+ ` ${s.dim('$')} ticketlens profiles ${s.dim('# verify pulled connections')}`,
293
+ '',
294
+ ];
295
+ stream.write(lines.join('\n') + '\n');
296
+ }
297
+
298
+ export function printActivateHelp({ stream = process.stdout } = {}) {
299
+ const s = createStyler({ isTTY: stream.isTTY });
300
+ const lines = [
301
+ '',
302
+ ` ${s.bold(s.brand('ticketlens'))} ${s.bold('activate')} ${s.dim('<LICENSE-KEY>')}`,
303
+ '',
304
+ ` Activate a Pro or Team license key to unlock paid features.`,
305
+ ` Validates the key online and writes the result to ${s.dim('~/.ticketlens/license.json')}.`,
306
+ '',
307
+ ` ${s.bold('ARGUMENTS')}`,
308
+ '',
309
+ ` ${s.brand('<LICENSE-KEY>')} Your LemonSqueezy license key`,
310
+ '',
311
+ ` ${s.bold('OPTIONS')}`,
312
+ '',
313
+ ` ${s.brand('-h')}, ${s.brand('--help')} Show this help`,
314
+ '',
315
+ ` ${s.bold('EXAMPLES')}`,
316
+ '',
317
+ ` ${s.dim('$')} ticketlens activate tl_abc123xxxx`,
318
+ ` ${s.dim('$')} ticketlens license ${s.dim('# verify activation')}`,
319
+ '',
320
+ ];
321
+ stream.write(lines.join('\n') + '\n');
322
+ }
323
+
324
+ export function printLicenseHelp({ stream = process.stdout } = {}) {
325
+ const s = createStyler({ isTTY: stream.isTTY });
326
+ const lines = [
327
+ '',
328
+ ` ${s.bold(s.brand('ticketlens'))} ${s.bold('license')}`,
329
+ '',
330
+ ` Show current license status: tier, email, and last validation date.`,
331
+ ` License is re-validated automatically in the background every 7 days.`,
332
+ '',
333
+ ` ${s.bold('OPTIONS')}`,
334
+ '',
335
+ ` ${s.brand('-h')}, ${s.brand('--help')} Show this help`,
336
+ '',
337
+ ` ${s.bold('EXAMPLES')}`,
338
+ '',
339
+ ` ${s.dim('$')} ticketlens license`,
340
+ ` ${s.dim('$')} ticketlens activate ${s.dim('<KEY>')} ${s.dim('# activate or renew')}`,
341
+ '',
342
+ ];
343
+ stream.write(lines.join('\n') + '\n');
344
+ }
345
+
346
+ export function printDeleteHelp({ stream = process.stdout } = {}) {
347
+ const s = createStyler({ isTTY: stream.isTTY });
348
+ const lines = [
349
+ '',
350
+ ` ${s.bold(s.brand('ticketlens'))} ${s.bold('delete')} ${s.dim('<PROFILE-NAME>')}`,
351
+ '',
352
+ ` Permanently remove a locally configured profile. In TTY mode, prompts`,
353
+ ` for confirmation before deleting. Pass ${s.cyan('--yes')} to skip the prompt.`,
354
+ '',
355
+ ` ${s.bold('ARGUMENTS')}`,
356
+ '',
357
+ ` ${s.brand('<PROFILE-NAME>')} Name of the profile to remove`,
358
+ '',
359
+ ` ${s.bold('OPTIONS')}`,
360
+ '',
361
+ ` ${s.brand('--yes')}, ${s.brand('-y')} Skip confirmation prompt`,
362
+ ` ${s.brand('-h')}, ${s.brand('--help')} Show this help`,
363
+ '',
364
+ ` ${s.bold('EXAMPLES')}`,
365
+ '',
366
+ ` ${s.dim('$')} ticketlens delete myprofile`,
367
+ ` ${s.dim('$')} ticketlens delete myprofile --yes`,
368
+ ` ${s.dim('$')} ticketlens profiles ${s.dim('# list remaining profiles')}`,
369
+ '',
370
+ ];
371
+ stream.write(lines.join('\n') + '\n');
372
+ }
373
+
374
+ export function printProfilesHelp({ stream = process.stdout } = {}) {
375
+ const s = createStyler({ isTTY: stream.isTTY });
376
+ const lines = [
377
+ '',
378
+ ` ${s.bold(s.brand('ticketlens'))} ${s.bold('profiles')} ${s.dim('[--plain]')}`,
379
+ '',
380
+ ` List all locally configured Jira profiles and their active status.`,
381
+ ` Also available as ${s.cyan('ticketlens ls')}.`,
382
+ '',
383
+ ` ${s.bold('OPTIONS')}`,
384
+ '',
385
+ ` ${s.brand('--plain')} Tab-separated output ${s.dim('(for scripting)')}`,
386
+ ` ${s.brand('-h')}, ${s.brand('--help')} Show this help`,
387
+ '',
388
+ ` ${s.bold('EXAMPLES')}`,
389
+ '',
390
+ ` ${s.dim('$')} ticketlens profiles`,
391
+ ` ${s.dim('$')} ticketlens ls`,
392
+ ` ${s.dim('$')} ticketlens profiles --plain`,
393
+ '',
394
+ ];
395
+ stream.write(lines.join('\n') + '\n');
396
+ }
397
+
398
+ export function printScheduleHelp({ stream = process.stdout } = {}) {
399
+ const s = createStyler({ isTTY: stream.isTTY });
400
+ const lines = [
401
+ '',
402
+ ` ${s.bold(s.brand('ticketlens'))} ${s.bold('schedule')} ${s.dim('[--stop|--status]')} ${s.dim('[Pro]')}`,
403
+ '',
404
+ ` Set up a recurring digest email with your triage results. ${s.dim('[Pro]')}`,
405
+ ` Runs an interactive wizard to configure day, time, and timezone.`,
406
+ '',
407
+ ` ${s.bold('OPTIONS')}`,
408
+ '',
409
+ ` ${s.brand('--stop')} Cancel the active digest schedule`,
410
+ ` ${s.brand('--status')} Show current schedule configuration`,
411
+ ` ${s.brand('-h')}, ${s.brand('--help')} Show this help`,
412
+ '',
413
+ ` ${s.bold('EXAMPLES')}`,
414
+ '',
415
+ ` ${s.dim('$')} ticketlens schedule`,
416
+ ` ${s.dim('$')} ticketlens schedule --status`,
417
+ ` ${s.dim('$')} ticketlens schedule --stop`,
418
+ '',
419
+ ];
420
+ stream.write(lines.join('\n') + '\n');
421
+ }
422
+
423
+ export function printInitHelp({ stream = process.stdout } = {}) {
424
+ const s = createStyler({ isTTY: stream.isTTY });
425
+ const lines = [
426
+ '',
427
+ ` ${s.bold(s.brand('ticketlens'))} ${s.bold('init')}`,
428
+ '',
429
+ ` Configure a new Jira connection locally using an interactive wizard.`,
430
+ ` Supports Jira Cloud ${s.dim('(Basic auth)')} and Jira Server/DC ${s.dim('(Bearer PAT or Basic)')}`,
431
+ '',
432
+ ` After setup, run ${s.cyan('ticketlens PROJ-123')} to fetch your first ticket.`,
433
+ '',
434
+ ` ${s.bold('OPTIONS')}`,
435
+ '',
436
+ ` ${s.brand('-h')}, ${s.brand('--help')} Show this help`,
437
+ '',
438
+ ` ${s.bold('EXAMPLES')}`,
439
+ '',
440
+ ` ${s.dim('$')} ticketlens init`,
441
+ ` ${s.dim('$')} ticketlens profiles ${s.dim('# verify the new profile')}`,
442
+ '',
443
+ ` ${s.dim('Tip: use')} ${s.cyan('ticketlens sync')} ${s.dim('instead to pull connections from the console.')}`,
444
+ '',
445
+ ];
446
+ stream.write(lines.join('\n') + '\n');
447
+ }
448
+
449
+ export function printSwitchHelp({ stream = process.stdout } = {}) {
450
+ const s = createStyler({ isTTY: stream.isTTY });
451
+ const lines = [
452
+ '',
453
+ ` ${s.bold(s.brand('ticketlens'))} ${s.bold('switch')}`,
454
+ '',
455
+ ` Interactively select which profile is active by default.`,
456
+ ` The chosen profile is used when no ${s.cyan('--profile')} flag is given.`,
457
+ '',
458
+ ` ${s.bold('OPTIONS')}`,
459
+ '',
460
+ ` ${s.brand('-h')}, ${s.brand('--help')} Show this help`,
461
+ '',
462
+ ` ${s.bold('EXAMPLES')}`,
463
+ '',
464
+ ` ${s.dim('$')} ticketlens switch`,
465
+ ` ${s.dim('$')} ticketlens profiles ${s.dim('# confirm new active profile')}`,
466
+ '',
467
+ ];
468
+ stream.write(lines.join('\n') + '\n');
469
+ }
470
+
471
+ export function printConfigHelp({ stream = process.stdout } = {}) {
472
+ const s = createStyler({ isTTY: stream.isTTY });
473
+ const lines = [
474
+ '',
475
+ ` ${s.bold(s.brand('ticketlens'))} ${s.bold('config')} ${s.dim('[--profile=NAME]')}`,
476
+ '',
477
+ ` Edit settings for an existing profile using an interactive wizard.`,
478
+ ` Without ${s.cyan('--profile')}, edits the currently active profile.`,
479
+ '',
480
+ ` ${s.bold('OPTIONS')}`,
481
+ '',
482
+ ` ${s.brand('--profile')}=${s.dim('NAME')} Profile to configure`,
483
+ ` ${s.brand('-h')}, ${s.brand('--help')} Show this help`,
484
+ '',
485
+ ` ${s.bold('EXAMPLES')}`,
486
+ '',
487
+ ` ${s.dim('$')} ticketlens config`,
488
+ ` ${s.dim('$')} ticketlens config --profile=work`,
489
+ ` ${s.dim('$')} ticketlens config --profile=acme`,
490
+ '',
491
+ ];
492
+ stream.write(lines.join('\n') + '\n');
493
+ }
494
+
212
495
  export function printTriageHelp({ stream = process.stdout } = {}) {
213
496
  const s = createStyler({ isTTY: stream.isTTY });
214
497
  const lines = [