ticketlens 0.4.7 → 0.4.9

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.
@@ -285,8 +285,11 @@ switch (command) {
285
285
  if (!result.ok) { process.exitCode = 1; break; }
286
286
 
287
287
  const s = createStyler({ isTTY: process.stdout.isTTY });
288
- process.stdout.write(` ${s.green('✔')} Digest scheduled for ${s.cyan(answers.time)} ${answers.timezone}\n`);
289
- process.stdout.write(` Next delivery: ${s.cyan(result.nextDelivery)}\n`);
288
+ process.stdout.write(` ${s.green('✔')} ${s.bold('Digest scheduled')}\n\n`);
289
+ process.stdout.write(` ${s.dim('Time: ')} ${s.cyan(answers.time)} ${s.dim(answers.timezone)}\n`);
290
+ process.stdout.write(` ${s.dim('Email: ')} ${answers.email}\n`);
291
+ process.stdout.write(` ${s.dim('Next delivery:')} ${s.cyan(result.nextDelivery)}\n`);
292
+ process.stdout.write('\n');
290
293
  break;
291
294
  }
292
295
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ticketlens",
3
- "version": "0.4.7",
3
+ "version": "0.4.9",
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": {
@@ -84,24 +84,46 @@ export async function promptSecret(label, { stream = process.stderr, existingVal
84
84
  */
85
85
  export async function promptScheduleAnswers(args = [], { stream = process.stderr } = {}) {
86
86
  // Allow pre-filling via flags: --time=07:00 --email=dev@example.com --timezone=UTC
87
- const timeArg = args.find(a => a.startsWith('--time='))?.split('=')[1];
87
+ const timeArg = args.find(a => a.startsWith('--time='))?.split('=')[1];
88
88
  const emailArg = args.find(a => a.startsWith('--email='))?.split('=')[1];
89
- const tzArg = args.find(a => a.startsWith('--timezone='))?.split('=')[1];
89
+ const tzArg = args.find(a => a.startsWith('--timezone='))?.split('=')[1];
90
90
 
91
- const time = timeArg ?? await promptText('Delivery time (HH:MM, 24h):', {
92
- stream,
93
- validate: (v) => /^\d{1,2}:\d{2}$/.test(v) ? null : 'Enter time as HH:MM (e.g. 07:00)',
94
- });
91
+ const s = createStyler({ isTTY: stream.isTTY });
95
92
 
96
- const email = emailArg ?? await promptText('Delivery email:', {
97
- stream,
98
- validate: (v) => v.includes('@') ? null : 'Enter a valid email address',
99
- });
93
+ // ── Header box ─────────────────────────────────────────────────────────────
94
+ const headerLines = [
95
+ `${s.bold(s.cyan('◆ TicketLens'))} — Digest Schedule`,
96
+ s.dim('Configure your daily triage digest delivery.'),
97
+ ];
98
+ const innerWidth = headerLines.reduce((max, l) => Math.max(max, visLen(l)), 0) + 4;
99
+ const bc = s.cyan;
100
+ stream.write('\n');
101
+ stream.write(bc('╭' + '─'.repeat(innerWidth) + '╮') + '\n');
102
+ for (const line of headerLines) {
103
+ const pad = innerWidth - 2 - visLen(line);
104
+ stream.write(bc('│') + ' ' + line + ' '.repeat(Math.max(0, pad)) + bc('│') + '\n');
105
+ }
106
+ stream.write(bc('╰' + '─'.repeat(innerWidth) + '╯') + '\n');
107
+ stream.write('\n');
100
108
 
101
- const timezone = tzArg ?? await promptText('Timezone (e.g. America/New_York):', {
102
- stream,
103
- defaultValue: Intl.DateTimeFormat().resolvedOptions().timeZone,
104
- });
109
+ const sysTimezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
110
+
111
+ const time = timeArg ?? await promptText(
112
+ s.dim('Delivery time') + s.dim(' (HH:MM, 24h):'),
113
+ { stream, validate: (v) => /^\d{1,2}:\d{2}$/.test(v) ? null : 'Enter time as HH:MM (e.g. 07:00)' },
114
+ );
115
+
116
+ const email = emailArg ?? await promptText(
117
+ s.dim('Delivery email:'),
118
+ { stream, validate: (v) => v.includes('@') ? null : 'Enter a valid email address' },
119
+ );
120
+
121
+ const timezone = tzArg ?? await promptText(
122
+ s.dim('Timezone') + s.dim(` [${sysTimezone}]:`),
123
+ { stream, defaultValue: sysTimezone },
124
+ );
125
+
126
+ stream.write('\n');
105
127
 
106
128
  return { time, email, timezone };
107
129
  }
@@ -2,7 +2,7 @@ import { writeFileSync, mkdirSync, unlinkSync } from 'node:fs';
2
2
  import { join } from 'node:path';
3
3
  import { homedir, platform as osPlatform } from 'node:os';
4
4
  import { spawnSync } from 'node:child_process';
5
- import { red, green, yellow, cyan } from './ansi.mjs';
5
+ import { red, green, yellow, cyan, bold, dim } from './ansi.mjs';
6
6
  import { apiBase, warnIfInsecure } from './api-utils.mjs';
7
7
 
8
8
  const SCHEDULE_PATH = '/v1/schedule';
@@ -105,7 +105,7 @@ export async function runScheduleWizard({
105
105
 
106
106
  writeLocalJob(content, platform);
107
107
 
108
- return data;
108
+ return { ok: true, ...data };
109
109
  } catch {
110
110
  print(` ${yellow('⚠')} Schedule API error (network error) — try again later\n`);
111
111
  return { ok: false };
@@ -152,7 +152,7 @@ export async function runScheduleStop({
152
152
  spawnSync('crontab', [tmp], { encoding: 'utf8' });
153
153
  }
154
154
 
155
- print(` ${green('✔')} Digest schedule removed.\n`);
155
+ print(`\n ${green('✔')} ${bold('Digest schedule removed.')}\n\n`);
156
156
  }
157
157
 
158
158
  export async function runScheduleStatus({
@@ -182,9 +182,11 @@ export async function runScheduleStatus({
182
182
  return;
183
183
  }
184
184
  const data = await res.json();
185
- print(` ${green('✔')} Digest schedule: ${cyan(data.deliverAt)} ${data.timezone}\n`);
186
- print(` Last delivered: ${data.lastDeliveredAt ?? 'never'}\n`);
187
- print(` Next delivery: ${cyan(data.nextDelivery)}\n`);
185
+ print(`\n ${green('✔')} ${bold('Active Digest Schedule')}\n\n`);
186
+ print(` ${dim('Time: ')} ${cyan(data.deliverAt)} ${dim(data.timezone)}\n`);
187
+ print(` ${dim('Last delivered:')} ${data.lastDeliveredAt ? cyan(data.lastDeliveredAt) : dim('never')}\n`);
188
+ print(` ${dim('Next delivery:')} ${cyan(data.nextDelivery)}\n`);
189
+ print('\n');
188
190
  }
189
191
 
190
192
  function resolveTicketlensBin() {