@iamcoder18/huly-cli 0.1.0

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.
Files changed (75) hide show
  1. package/README.md +2576 -0
  2. package/bin/huly +9 -0
  3. package/dist/auth/cache.js +129 -0
  4. package/dist/auth/cache.js.map +1 -0
  5. package/dist/auth/client.js +192 -0
  6. package/dist/auth/client.js.map +1 -0
  7. package/dist/auth/env.js +101 -0
  8. package/dist/auth/env.js.map +1 -0
  9. package/dist/auth/prompts.js +68 -0
  10. package/dist/auth/prompts.js.map +1 -0
  11. package/dist/cli.js +1959 -0
  12. package/dist/cli.js.map +1 -0
  13. package/dist/commands/dry-run.js +39 -0
  14. package/dist/commands/dry-run.js.map +1 -0
  15. package/dist/commands/login.js +92 -0
  16. package/dist/commands/login.js.map +1 -0
  17. package/dist/commands/whoami.js +64 -0
  18. package/dist/commands/whoami.js.map +1 -0
  19. package/dist/index.js +59 -0
  20. package/dist/index.js.map +1 -0
  21. package/dist/output/errors.js +99 -0
  22. package/dist/output/errors.js.map +1 -0
  23. package/dist/output/format.js +607 -0
  24. package/dist/output/format.js.map +1 -0
  25. package/dist/output/progress.js +30 -0
  26. package/dist/output/progress.js.map +1 -0
  27. package/dist/raw/api.js +67 -0
  28. package/dist/raw/api.js.map +1 -0
  29. package/dist/raw/ws.js +157 -0
  30. package/dist/raw/ws.js.map +1 -0
  31. package/dist/resources/_helpers.js +258 -0
  32. package/dist/resources/_helpers.js.map +1 -0
  33. package/dist/resources/_project-resolve.js +24 -0
  34. package/dist/resources/_project-resolve.js.map +1 -0
  35. package/dist/resources/calendar.js +659 -0
  36. package/dist/resources/calendar.js.map +1 -0
  37. package/dist/resources/card.js +358 -0
  38. package/dist/resources/card.js.map +1 -0
  39. package/dist/resources/channel.js +709 -0
  40. package/dist/resources/channel.js.map +1 -0
  41. package/dist/resources/comment.js +142 -0
  42. package/dist/resources/comment.js.map +1 -0
  43. package/dist/resources/component.js +154 -0
  44. package/dist/resources/component.js.map +1 -0
  45. package/dist/resources/document.js +584 -0
  46. package/dist/resources/document.js.map +1 -0
  47. package/dist/resources/issue-template.js +228 -0
  48. package/dist/resources/issue-template.js.map +1 -0
  49. package/dist/resources/issue.js +909 -0
  50. package/dist/resources/issue.js.map +1 -0
  51. package/dist/resources/milestone.js +177 -0
  52. package/dist/resources/milestone.js.map +1 -0
  53. package/dist/resources/misc.js +2 -0
  54. package/dist/resources/misc.js.map +1 -0
  55. package/dist/resources/project.js +341 -0
  56. package/dist/resources/project.js.map +1 -0
  57. package/dist/resources/project.parse.js +25 -0
  58. package/dist/resources/project.parse.js.map +1 -0
  59. package/dist/resources/time.js +148 -0
  60. package/dist/resources/time.js.map +1 -0
  61. package/dist/resources/todo.js +463 -0
  62. package/dist/resources/todo.js.map +1 -0
  63. package/dist/resources/user.js +131 -0
  64. package/dist/resources/user.js.map +1 -0
  65. package/dist/resources/workspace.js +252 -0
  66. package/dist/resources/workspace.js.map +1 -0
  67. package/dist/transport/identifiers.js +67 -0
  68. package/dist/transport/identifiers.js.map +1 -0
  69. package/dist/transport/ref-resolver.js +108 -0
  70. package/dist/transport/ref-resolver.js.map +1 -0
  71. package/dist/transport/sdk.js +69 -0
  72. package/dist/transport/sdk.js.map +1 -0
  73. package/dist/types.js +2 -0
  74. package/dist/types.js.map +1 -0
  75. package/package.json +40 -0
@@ -0,0 +1,607 @@
1
+ import chalk from 'chalk';
2
+ const useColor = !process.env.NO_COLOR && process.stdout.isTTY !== false;
3
+ const noColor = (s) => s;
4
+ const c = useColor ? chalk : Object.fromEntries(Object.keys(chalk).map((k) => [k, noColor]));
5
+ export function dim(s) { return useColor ? chalk.dim(s) : s; }
6
+ export function bold(s) { return useColor ? chalk.bold(s) : s; }
7
+ export function italic(s) { return useColor ? chalk.italic(s) : s; }
8
+ export function red(s) { return useColor ? chalk.red(s) : s; }
9
+ export function green(s) { return useColor ? chalk.green(s) : s; }
10
+ export function yellow(s) { return useColor ? chalk.yellow(s) : s; }
11
+ export function blue(s) { return useColor ? chalk.blue(s) : s; }
12
+ export function cyan(s) { return useColor ? chalk.cyan(s) : s; }
13
+ export function gray(s) { return useColor ? chalk.gray(s) : s; }
14
+ export function magenta(s) { return useColor ? chalk.magenta(s) : s; }
15
+ export const C = {
16
+ dim, bold, italic, red, green, yellow, blue, cyan, gray, magenta,
17
+ ok: (s) => useColor ? chalk.green('✓ ' + s) : '✓ ' + s,
18
+ fail: (s) => useColor ? chalk.red('✗ ' + s) : '✗ ' + s,
19
+ warn: (s) => useColor ? chalk.yellow('⚠ ' + s) : '⚠ ' + s,
20
+ info: (s) => useColor ? chalk.cyan('ℹ ' + s) : 'ℹ ' + s,
21
+ bullet: (s) => useColor ? chalk.cyan('● ') + s : '● ' + s,
22
+ arrow: (s) => useColor ? chalk.cyan('→ ') + s : '→ ' + s,
23
+ id: (s) => useColor ? chalk.gray(s) : s,
24
+ primary: (s) => useColor ? chalk.bold.cyan(s) : s,
25
+ emphasis: (s) => useColor ? chalk.bold(s) : s,
26
+ muted: (s) => useColor ? chalk.gray(s) : s,
27
+ none: () => useColor ? chalk.gray('—') : '—',
28
+ empty: () => useColor ? chalk.gray('(empty)') : '(empty)'
29
+ };
30
+ export function json(data) {
31
+ console.log(JSON.stringify(data, null, 2));
32
+ }
33
+ const SHARP = useColor ? '│' : '|';
34
+ const THIN = useColor ? '─' : '-';
35
+ const TLCOR = useColor ? '┌' : '+';
36
+ const TRCOR = useColor ? '┐' : '+';
37
+ const BLCOR = useColor ? '└' : '+';
38
+ const BRCOR = useColor ? '┘' : '+';
39
+ const TMID = useColor ? '┬' : '+';
40
+ const BMID = useColor ? '┴' : '+';
41
+ const LMID = useColor ? '├' : '+';
42
+ const RMID = useColor ? '┤' : '+';
43
+ const CROSS = useColor ? '┼' : '+';
44
+ function stripRef(value) {
45
+ if (value == null)
46
+ return '';
47
+ const s = String(value);
48
+ const parts = s.split(':');
49
+ return parts[parts.length - 1] ?? s;
50
+ }
51
+ function shortId(id) {
52
+ const s = String(id ?? '');
53
+ if (s === '')
54
+ return '';
55
+ // For ref-style IDs like "tracker:project:TEST" or "space:General",
56
+ // return the last segment for readability. Otherwise return the last 12 chars.
57
+ if (s.includes(':'))
58
+ return s.split(':').slice(-1)[0] ?? s;
59
+ return s.length > 12 ? s.slice(-12) : s;
60
+ }
61
+ function trim(s, n) {
62
+ return String(s ?? '').slice(0, n);
63
+ }
64
+ function ellipsize(s, w) {
65
+ if (s.length <= w)
66
+ return s;
67
+ if (w <= 1)
68
+ return s.slice(0, w);
69
+ return s.slice(0, w - 1) + '…';
70
+ }
71
+ function isoDate(ms) {
72
+ if (ms == null)
73
+ return '';
74
+ return new Date(Number(ms)).toISOString().slice(0, 16).replace('T', ' ');
75
+ }
76
+ function isoDay(ms) {
77
+ if (ms == null)
78
+ return '';
79
+ return new Date(Number(ms)).toISOString().slice(0, 10);
80
+ }
81
+ function relTime(ms) {
82
+ if (ms == null)
83
+ return C.none();
84
+ const now = Date.now();
85
+ const diff = now - Number(ms);
86
+ if (diff < 0)
87
+ return isoDay(ms);
88
+ if (diff < 60_000)
89
+ return 'just now';
90
+ if (diff < 3_600_000)
91
+ return `${Math.floor(diff / 60_000)}m ago`;
92
+ if (diff < 86_400_000)
93
+ return `${Math.floor(diff / 3_600_000)}h ago`;
94
+ if (diff < 604_800_000)
95
+ return `${Math.floor(diff / 86_400_000)}d ago`;
96
+ if (diff < 2_592_000_000)
97
+ return `${Math.floor(diff / 604_800_000)}w ago`;
98
+ if (diff < 31_536_000_000)
99
+ return `${Math.floor(diff / 2_592_000_000)}mo ago`;
100
+ return `${Math.floor(diff / 31_536_000_000)}y ago`;
101
+ }
102
+ const PRIORITY_COLORS = {
103
+ Urgent: (s) => useColor ? chalk.red.bold(s) : s,
104
+ High: (s) => useColor ? chalk.red(s) : s,
105
+ Normal: (s) => useColor ? chalk.yellow(s) : s,
106
+ Low: (s) => useColor ? chalk.gray(s) : s,
107
+ None: (s) => useColor ? chalk.gray(s) : s
108
+ };
109
+ const STATUS_CATEGORY_COLORS = {
110
+ Won: (s) => useColor ? chalk.green(s) : s,
111
+ Lost: (s) => useColor ? chalk.red(s) : s,
112
+ Active: (s) => useColor ? chalk.cyan(s) : s,
113
+ ToDo: (s) => useColor ? chalk.yellow(s) : s,
114
+ UnStarted: (s) => useColor ? chalk.gray(s) : s
115
+ };
116
+ function colorizeStatus(s) {
117
+ if (!s)
118
+ return C.none();
119
+ const stripped = stripRef(s);
120
+ for (const [cat, fn] of Object.entries(STATUS_CATEGORY_COLORS)) {
121
+ if (cat.toLowerCase() === stripped.toLowerCase())
122
+ return fn(stripped);
123
+ }
124
+ return stripped;
125
+ }
126
+ function colorizePriority(s) {
127
+ if (!s)
128
+ return C.none();
129
+ const stripped = stripRef(s);
130
+ for (const [pri, fn] of Object.entries(PRIORITY_COLORS)) {
131
+ if (pri.toLowerCase() === stripped.toLowerCase())
132
+ return fn(stripped);
133
+ }
134
+ return stripped;
135
+ }
136
+ const STATUS_GLYPH = {
137
+ Won: '✓',
138
+ Lost: '✗',
139
+ Active: '●',
140
+ ToDo: '○',
141
+ UnStarted: '◌'
142
+ };
143
+ function statusGlyph(s) {
144
+ if (!s)
145
+ return C.muted('—');
146
+ const stripped = stripRef(s);
147
+ for (const [cat, glyph] of Object.entries(STATUS_GLYPH)) {
148
+ if (cat.toLowerCase() === stripped.toLowerCase())
149
+ return glyph;
150
+ }
151
+ return '·';
152
+ }
153
+ const PRIORITY_GLYPH = {
154
+ Urgent: '↑↑↑',
155
+ High: '↑↑',
156
+ Normal: '↑',
157
+ Low: '↓',
158
+ None: '·'
159
+ };
160
+ function priorityGlyph(s) {
161
+ if (!s)
162
+ return C.muted('—');
163
+ const stripped = stripRef(s);
164
+ for (const [pri, glyph] of Object.entries(PRIORITY_GLYPH)) {
165
+ if (pri.toLowerCase() === stripped.toLowerCase())
166
+ return glyph;
167
+ }
168
+ return '·';
169
+ }
170
+ function calcWidth(rows, header, requested) {
171
+ if (requested !== undefined)
172
+ return requested;
173
+ let w = header.length;
174
+ for (const r of rows) {
175
+ const cellLen = stripAnsi(r.join('')).length;
176
+ if (cellLen > w)
177
+ w = cellLen;
178
+ }
179
+ return Math.min(Math.max(w, 3), 60);
180
+ }
181
+ function stripAnsi(s) {
182
+ return s.replace(/\x1B\[[0-9;]*[a-zA-Z]/g, '');
183
+ }
184
+ function padCell(content, width, align = 'left') {
185
+ const len = stripAnsi(content).length;
186
+ if (len >= width)
187
+ return content;
188
+ const pad = width - len;
189
+ if (align === 'right')
190
+ return ' '.repeat(pad) + content;
191
+ if (align === 'center') {
192
+ const left = Math.floor(pad / 2);
193
+ return ' '.repeat(left) + content + ' '.repeat(pad - left);
194
+ }
195
+ return content + ' '.repeat(pad);
196
+ }
197
+ function renderRow(values, widths, aligns, border, useBox) {
198
+ const cells = values.map((v, i) => padCell(v, widths[i] ?? 0, aligns[i] ?? 'left'));
199
+ if (border) {
200
+ return (useBox ? SHARP : '|') + ' ' + cells.join(' ' + (useBox ? SHARP : '|') + ' ') + ' ' + (useBox ? SHARP : '|');
201
+ }
202
+ return ' ' + cells.join(' ');
203
+ }
204
+ function renderSep(widths, border, left, mid, right, useBox) {
205
+ if (!border)
206
+ return dim(widths.map((w) => '─'.repeat(w)).join(' '));
207
+ const sep = (useBox ? THIN : '-').repeat;
208
+ const parts = widths.map((w) => sep(w + 2));
209
+ const j = useBox ? TMID : '+';
210
+ return left + parts.join(j) + right;
211
+ }
212
+ export function table(rows, columns, opts = {}) {
213
+ if (rows.length === 0) {
214
+ const msg = '(no results)';
215
+ if (opts.title !== undefined) {
216
+ console.log();
217
+ console.log(C.muted(opts.title));
218
+ }
219
+ console.log(dim(' ' + msg));
220
+ return;
221
+ }
222
+ const rendered = rows.map((row) => columns.map((col) => {
223
+ try {
224
+ const v = col.format ? col.format(row) : row[col.key] == null ? '' : String(row[col.key]);
225
+ return col.color ? col.color(row) ?? v : v;
226
+ }
227
+ catch {
228
+ return '';
229
+ }
230
+ }));
231
+ const aligns = columns.map((c) => c.align ?? 'left');
232
+ const widths = columns.map((c, i) => calcWidth(rendered.map((r) => [r[i] ?? '']), c.header, c.width));
233
+ const border = !opts.noBorder;
234
+ if (opts.title !== undefined) {
235
+ const title = C.bold(' ' + opts.title);
236
+ if (border) {
237
+ const totalWidth = widths.reduce((a, b) => a + b + 3, -1);
238
+ console.log(TLCOR + THIN.repeat(totalWidth) + TRCOR);
239
+ console.log(SHARP + ' ' + C.emphasis(opts.title) + ' '.repeat(Math.max(0, totalWidth - stripAnsi(opts.title).length - 1)) + SHARP);
240
+ console.log(LMID + renderSep(widths, false, '', CROSS, RMID, true).slice(1, -1).replace(/[┌┐]/g, '├').replace(/[─┬]/g, '─'));
241
+ }
242
+ else {
243
+ console.log(title);
244
+ }
245
+ }
246
+ const headerRow = renderRow(columns.map((c) => c.header), widths, aligns, border, true);
247
+ console.log(border ? SHARP + ' ' + columns.map((c, i) => C.emphasis(padCell(c.header, widths[i] ?? 0, aligns[i] ?? 'left'))).join(' ' + SHARP + ' ') + ' ' + SHARP : ' ' + columns.map((c, i) => C.emphasis(padCell(c.header, widths[i] ?? 0, aligns[i] ?? 'left'))).join(' '));
248
+ if (border) {
249
+ const sep = widths.map((w) => (useColor ? '─' : '-').repeat(w + 2));
250
+ const j = useColor ? '┼' : '+';
251
+ console.log(LMID + sep.join(j) + RMID);
252
+ }
253
+ else {
254
+ console.log(renderSep(widths, false, '', '', '', true));
255
+ }
256
+ for (const r of rendered) {
257
+ console.log(renderRow(r, widths, aligns, border, true));
258
+ }
259
+ if (border) {
260
+ const sep = widths.map((w) => (useColor ? '─' : '-').repeat(w + 2));
261
+ const j = useColor ? '┴' : '+';
262
+ console.log(BLCOR + sep.join(j) + BRCOR);
263
+ }
264
+ if (opts.count === true) {
265
+ const countText = `${rows.length} ${rows.length === 1 ? 'result' : 'results'}`;
266
+ console.log(C.muted(' ' + countText));
267
+ }
268
+ if (opts.footer !== undefined) {
269
+ console.log(C.muted(' ' + opts.footer));
270
+ }
271
+ }
272
+ export function kv(rows, opts = {}) {
273
+ if (rows.length === 0)
274
+ return;
275
+ if (opts.title !== undefined) {
276
+ console.log(C.emphasis(opts.title));
277
+ }
278
+ const w = Math.max(...rows.map(([k]) => k.length));
279
+ for (const [k, v] of rows) {
280
+ const value = v == null || v === '' ? C.none() : v;
281
+ console.log(` ${C.muted(k.padEnd(w))} ${value}`);
282
+ }
283
+ }
284
+ export function panel(title, lines) {
285
+ const titleLen = stripAnsi(title).length;
286
+ const maxLen = Math.max(titleLen, ...lines.map((l) => stripAnsi(l).length));
287
+ const width = Math.min(maxLen + 4, 100);
288
+ const top = ' ' + TLCOR + THIN.repeat(width) + TRCOR;
289
+ const bottom = ' ' + BLCOR + THIN.repeat(width) + BRCOR;
290
+ const titleLine = ' ' + SHARP + ' ' + C.emphasis(title.padEnd(width - 2)) + ' ' + SHARP;
291
+ console.log(top);
292
+ console.log(titleLine);
293
+ for (const line of lines) {
294
+ const padded = line.padEnd(width - 2);
295
+ console.log(' ' + SHARP + ' ' + padded + ' ' + SHARP);
296
+ }
297
+ console.log(bottom);
298
+ }
299
+ export function header(title, opts = {}) {
300
+ const accent = opts.accent !== undefined ? ` ${C.dim('·')} ${opts.accent}` : '';
301
+ console.log();
302
+ console.log(C.primary('━'.repeat(3) + ' ' + title) + accent);
303
+ if (opts.subtitle !== undefined) {
304
+ console.log(C.muted(' ' + opts.subtitle));
305
+ }
306
+ console.log();
307
+ }
308
+ export function section(title) {
309
+ console.log();
310
+ console.log(C.emphasis(title));
311
+ console.log(C.muted('─'.repeat(Math.max(8, title.length + 2))));
312
+ }
313
+ export function fail(msg) { console.log(C.fail(msg)); }
314
+ export function warn(msg) { console.log(C.warn(msg)); }
315
+ export function info(msg) { console.log(C.info(msg)); }
316
+ export function shouldJson(opts) {
317
+ return Boolean(opts.json || opts.ci || process.env.CI);
318
+ }
319
+ export async function withTimeout(p, ms, fallback) {
320
+ let timer;
321
+ const timeout = new Promise((resolve) => {
322
+ timer = setTimeout(() => resolve(fallback), ms);
323
+ });
324
+ try {
325
+ return await Promise.race([p, timeout]);
326
+ }
327
+ finally {
328
+ if (timer !== undefined)
329
+ clearTimeout(timer);
330
+ }
331
+ }
332
+ export { shortId, trim, stripRef, isoDate, isoDay, relTime, colorizeStatus, colorizePriority, statusGlyph, priorityGlyph };
333
+ export function success(kind, name, id) {
334
+ const line = C.ok(kind) + C.muted(' ') + C.emphasis(name) + (id != null ? C.muted(' ') + C.id(`(${id})`) : '');
335
+ console.log(line);
336
+ }
337
+ export function updated(kind, id) {
338
+ const line = C.info(kind) + C.muted(' ') + C.id(`(${id})`);
339
+ console.log(line);
340
+ }
341
+ export function removed(kind, name, id) {
342
+ const line = C.fail(kind) + C.muted(' ') + C.emphasis(name) + (id != null ? C.muted(' ') + C.id(`(${id})`) : '');
343
+ console.log(line);
344
+ }
345
+ export function bulkRemoved(deleted, skipped, kind = 'items') {
346
+ if (deleted === 0 && skipped === 0) {
347
+ console.log(C.muted(` (nothing to delete)`));
348
+ return;
349
+ }
350
+ const parts = [];
351
+ if (deleted > 0)
352
+ parts.push(C.ok(`${deleted} ${kind} deleted`));
353
+ if (skipped > 0)
354
+ parts.push(C.warn(`${skipped} skipped`));
355
+ console.log(' ' + parts.join(C.muted(' · ')));
356
+ }
357
+ export const COLUMNS = {
358
+ idShort: () => [
359
+ { key: '_id', header: '_ID', format: (r) => C.id(shortId(r._id)) }
360
+ ],
361
+ issue: () => [
362
+ { key: 'identifier', header: 'ID', width: 14, align: 'left', format: (r) => {
363
+ const v = r.identifier;
364
+ if (v != null && v !== '')
365
+ return C.emphasis(String(v));
366
+ // Fall back to a short id when the project sequence hasn't been assigned
367
+ // (e.g. legacy issues, or issues created via raw tx without an increment)
368
+ const id = r._id;
369
+ if (id != null && id !== '')
370
+ return C.muted('#' + shortId(id));
371
+ return C.muted('—');
372
+ } },
373
+ { key: 'title', header: 'TITLE', format: (r) => {
374
+ const t = trim(r.title, 80);
375
+ return t || C.muted('(untitled)');
376
+ } },
377
+ { key: 'status', header: 'STATUS', width: 14, format: (r) => {
378
+ const s = r.status;
379
+ return `${statusGlyph(String(s ?? ''))} ${colorizeStatus(String(s ?? ''))}`;
380
+ } },
381
+ { key: 'priority', header: 'PRIORITY', width: 11, align: 'center', format: (r) => {
382
+ const p = r.priority;
383
+ return priorityGlyph(String(p ?? ''));
384
+ } },
385
+ { key: 'updatedOn', header: 'UPDATED', width: 11, align: 'right', format: (r) => relTime(r.modifiedOn) }
386
+ ],
387
+ issueTemplate: () => [
388
+ { key: 'title', header: 'TITLE', format: (r) => {
389
+ const t = trim(r.title, 80);
390
+ return t || C.muted('(untitled)');
391
+ } },
392
+ { key: '_id', header: '_ID', width: 12, align: 'right', format: (r) => C.id(shortId(r._id)) }
393
+ ],
394
+ project: () => [
395
+ { key: 'identifier', header: 'ID', width: 8, align: 'left', format: (r) => {
396
+ const v = r.identifier;
397
+ return v != null && v !== '' ? C.emphasis(String(v)) : C.muted('—');
398
+ } },
399
+ { key: 'name', header: 'NAME', format: (r) => trim(r.name, 60) || C.muted('(no name)') },
400
+ { key: 'description', header: 'DESCRIPTION', format: (r) => {
401
+ const d = String(r.description ?? '').trim();
402
+ if (!d)
403
+ return C.muted('—');
404
+ return trim(d, 50);
405
+ } },
406
+ { key: 'archived', header: 'STATE', width: 8, align: 'center', format: (r) => {
407
+ const a = r.archived;
408
+ return a ? C.red('archived') : C.green('active');
409
+ } },
410
+ { key: '_id', header: '_ID', width: 12, align: 'right', format: (r) => C.id(shortId(r._id)) }
411
+ ],
412
+ card: () => [
413
+ { key: 'title', header: 'TITLE', format: (r) => {
414
+ const t = trim(r.title, 80);
415
+ return t || C.muted('(untitled)');
416
+ } },
417
+ { key: 'status', header: 'STATUS', format: (r) => {
418
+ const s = r.status;
419
+ return s != null && s !== '' ? colorizeStatus(String(s)) : C.muted('—');
420
+ } },
421
+ { key: '_id', header: '_ID', width: 12, align: 'right', format: (r) => C.id(shortId(r._id)) }
422
+ ],
423
+ task: () => [
424
+ { key: 'title', header: 'TITLE', format: (r) => trim(r.title, 80) || C.muted('(untitled)') },
425
+ { key: 'status', header: 'STATUS', format: (r) => {
426
+ const s = r.status;
427
+ return s != null && s !== '' ? colorizeStatus(String(s)) : C.muted('—');
428
+ } },
429
+ { key: 'assignee', header: 'ASSIGNEE', format: (r) => {
430
+ const a = r.assignee;
431
+ return a != null && a !== '' ? String(a) : C.muted('unassigned');
432
+ } },
433
+ { key: '_id', header: '_ID', width: 12, align: 'right', format: (r) => C.id(shortId(r._id)) }
434
+ ],
435
+ document: () => [
436
+ { key: 'title', header: 'TITLE', format: (r) => trim(r.title, 80) || C.muted('(untitled)') },
437
+ { key: 'modifiedOn', header: 'UPDATED', width: 12, format: (r) => relTime(r.modifiedOn) },
438
+ { key: '_id', header: '_ID', width: 12, align: 'right', format: (r) => C.id(shortId(r._id)) }
439
+ ],
440
+ event: () => [
441
+ { key: 'title', header: 'TITLE', format: (r) => trim(r.title, 60) || C.muted('(untitled)') },
442
+ { key: 'startDate', header: 'START', width: 17, format: (r) => {
443
+ const s = r.startDate;
444
+ return s != null ? isoDate(s) : C.muted('—');
445
+ } },
446
+ { key: 'dueDate', header: 'END', width: 17, format: (r) => {
447
+ const e = r.dueDate;
448
+ return e != null ? isoDate(e) : C.muted('—');
449
+ } },
450
+ { key: 'location', header: 'LOCATION', format: (r) => {
451
+ const l = r.location;
452
+ return l != null && l !== '' ? String(l) : C.muted('—');
453
+ } },
454
+ { key: '_id', header: '_ID', width: 12, align: 'right', format: (r) => C.id(shortId(r._id)) }
455
+ ],
456
+ comment: () => [
457
+ { key: 'message', header: 'MESSAGE', format: (r) => {
458
+ const m = r.message;
459
+ if (m == null)
460
+ return C.muted('(empty)');
461
+ if (typeof m === 'string')
462
+ return trim(m, 80);
463
+ if (typeof m === 'object' && Object.keys(m).length === 0)
464
+ return C.muted('(empty — use `huly comment get <id>`)');
465
+ const content = m.content;
466
+ return trim(typeof content === 'string' ? content : '', 80) || C.muted('(no content)');
467
+ } },
468
+ { key: 'createdOn', header: 'CREATED', width: 12, format: (r) => relTime(r.createdOn) },
469
+ { key: '_id', header: '_ID', width: 12, align: 'right', format: (r) => C.id(shortId(r._id)) }
470
+ ],
471
+ channel: () => [
472
+ { key: 'name', header: 'NAME', format: (r) => {
473
+ const n = r.name;
474
+ return n != null && n !== '' ? '# ' + String(n) : C.muted('(no name)');
475
+ } },
476
+ { key: 'topic', header: 'TOPIC', format: (r) => {
477
+ const t = r.topic;
478
+ return t != null && t !== '' ? trim(t, 60) : C.muted('—');
479
+ } },
480
+ { key: 'members', header: 'MEMBERS', width: 8, align: 'right', format: (r) => {
481
+ const m = r.members;
482
+ return m != null ? String(Array.isArray(m) ? m.length : 0) : C.muted('0');
483
+ } },
484
+ { key: 'archived', header: 'STATE', width: 10, align: 'center', format: (r) => {
485
+ const a = r.archived;
486
+ return a ? C.red('archived') : C.green('active');
487
+ } },
488
+ { key: '_id', header: '_ID', width: 12, align: 'right', format: (r) => C.id(shortId(r._id)) }
489
+ ],
490
+ channelMessage: () => [
491
+ {
492
+ key: 'message',
493
+ header: 'MESSAGE',
494
+ format: (r) => {
495
+ const m = r.message;
496
+ if (m == null)
497
+ return C.muted('(empty)');
498
+ if (typeof m === 'string')
499
+ return trim(m, 80);
500
+ if (typeof m === 'object' && Object.keys(m).length === 0)
501
+ return C.muted('(empty — use `huly channel get <id>`)');
502
+ const content = m.content;
503
+ return trim(typeof content === 'string' ? content : '', 80) || C.muted('(no content)');
504
+ }
505
+ },
506
+ { key: 'createdOn', header: 'CREATED', width: 12, format: (r) => relTime(r.createdOn) },
507
+ { key: '_id', header: '_ID', width: 12, align: 'right', format: (r) => C.id(shortId(r._id)) }
508
+ ],
509
+ timeReport: () => [
510
+ { key: 'hours', header: 'HOURS', width: 8, align: 'right', format: (r) => {
511
+ const v = Number(r.value);
512
+ return Number.isFinite(v) ? v.toFixed(2) : C.muted('—');
513
+ } },
514
+ { key: 'minutes', header: 'MIN', width: 6, align: 'right', format: (r) => {
515
+ const v = Number(r.value);
516
+ return Number.isFinite(v) ? String(Math.round(v * 60)) : C.muted('—');
517
+ } },
518
+ { key: 'description', header: 'DESCRIPTION', format: (r) => {
519
+ const d = String(r.description ?? '').trim();
520
+ return d || C.muted('(no description)');
521
+ } },
522
+ { key: 'date', header: 'DATE', width: 12, format: (r) => {
523
+ const d = r.date;
524
+ return d != null ? isoDay(d) : C.muted('—');
525
+ } },
526
+ { key: '_id', header: '_ID', width: 12, align: 'right', format: (r) => C.id(shortId(r._id)) }
527
+ ],
528
+ notification: () => [
529
+ { key: 'type', header: 'TYPE', width: 16 },
530
+ { key: 'title', header: 'TITLE', format: (r) => trim(r.title, 60) || C.muted('(untitled)') },
531
+ { key: 'isRead', header: 'READ', width: 6, align: 'center', format: (r) => {
532
+ const r2 = r.isRead;
533
+ return r2 ? C.gray('●') : C.green('○');
534
+ } },
535
+ { key: '_id', header: '_ID', width: 12, align: 'right', format: (r) => C.id(shortId(r._id)) }
536
+ ],
537
+ activity: () => [
538
+ { key: 'message', header: 'MESSAGE', format: (r) => trim(r.message, 80) || C.muted('(no message)') },
539
+ { key: 'createdOn', header: 'CREATED', width: 12, format: (r) => relTime(r.createdOn) },
540
+ { key: '_id', header: '_ID', width: 12, align: 'right', format: (r) => C.id(shortId(r._id)) }
541
+ ],
542
+ approval: () => [
543
+ { key: 'status', header: 'STATUS', format: (r) => colorizeStatus(String(r.status ?? '')) },
544
+ { key: 'title', header: 'TITLE', format: (r) => trim(r.title, 60) || C.muted('(untitled)') },
545
+ { key: 'createdOn', header: 'CREATED', width: 12, format: (r) => relTime(r.createdOn) },
546
+ { key: '_id', header: '_ID', width: 12, align: 'right', format: (r) => C.id(shortId(r._id)) }
547
+ ],
548
+ component: () => [
549
+ { key: 'label', header: 'LABEL', format: (r) => {
550
+ const l = r.label;
551
+ return l != null && l !== '' ? C.emphasis(String(l)) : C.muted('(no label)');
552
+ } },
553
+ { key: 'description', header: 'DESCRIPTION', format: (r) => {
554
+ const d = String(r.description ?? '').trim();
555
+ return d || C.muted('—');
556
+ } },
557
+ { key: '_id', header: '_ID', width: 12, align: 'right', format: (r) => C.id(shortId(r._id)) }
558
+ ],
559
+ milestone: () => [
560
+ { key: 'label', header: 'LABEL', format: (r) => {
561
+ const l = r.label;
562
+ return l != null && l !== '' ? C.emphasis(String(l)) : C.muted('(no label)');
563
+ } },
564
+ { key: 'targetDate', header: 'TARGET', width: 12, format: (r) => {
565
+ const t = r.targetDate;
566
+ if (t == null)
567
+ return C.muted('—');
568
+ const days = Math.ceil((Number(t) - Date.now()) / 86_400_000);
569
+ const label = isoDay(t);
570
+ return days >= 0 ? `${label} ${C.muted('(' + days + 'd)')}` : `${label} ${C.red('(overdue)')}`;
571
+ } },
572
+ { key: '_id', header: '_ID', width: 12, align: 'right', format: (r) => C.id(shortId(r._id)) }
573
+ ],
574
+ label: () => [
575
+ { key: 'title', header: 'LABEL', format: (r) => {
576
+ const t = r.title;
577
+ return t != null && t !== '' ? C.emphasis(String(t)) : C.muted('(no label)');
578
+ } },
579
+ { key: 'color', header: 'COLOR', width: 8, format: (r) => {
580
+ const c2 = r.color;
581
+ return c2 != null && c2 !== '' ? `● ${c2}` : C.muted('—');
582
+ } },
583
+ { key: '_id', header: '_ID', width: 12, align: 'right', format: (r) => C.id(shortId(r._id)) }
584
+ ],
585
+ member: () => [
586
+ { key: 'name', header: 'NAME', format: (r) => trim(r.name, 50) || C.muted('(unknown)') },
587
+ { key: 'role', header: 'ROLE', width: 12, format: (r) => {
588
+ const role = r.role;
589
+ return role != null ? C.emphasis(String(role)) : C.muted('—');
590
+ } },
591
+ { key: 'email', header: 'EMAIL', format: (r) => {
592
+ const e = r.email;
593
+ return e != null && e !== '' ? String(e) : C.muted('—');
594
+ } }
595
+ ],
596
+ workspace: () => [
597
+ { key: 'name', header: 'NAME', format: (r) => C.emphasis(String(r.name ?? '')) },
598
+ { key: 'url', header: 'URL', format: (r) => String(r.url ?? '') },
599
+ { key: 'uuid', header: 'UUID', width: 14, format: (r) => C.id(trim(r.uuid, 12) + '…') },
600
+ { key: 'mode', header: 'MODE', width: 10, align: 'center', format: (r) => {
601
+ const m = String(r.mode ?? 'unknown');
602
+ return m === 'active' ? C.green('● active') : m === 'pending-deletion' ? C.red('● pending-deletion') : m === 'deleted' ? C.muted('● deleted') : m;
603
+ } },
604
+ { key: 'lastVisit', header: 'LAST VISIT', width: 14, format: (r) => relTime(r.lastVisit) }
605
+ ]
606
+ };
607
+ //# sourceMappingURL=format.js.map