@dealdeploy/skl 1.6.0 → 1.8.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.
- package/index.ts +12 -3
- package/lib.ts +1 -0
- package/package.json +1 -1
- package/tui.test.ts +3 -0
- package/tui.ts +48 -5
- package/update.ts +1 -0
package/index.ts
CHANGED
|
@@ -91,18 +91,27 @@ const projectAgents = [...new Set(["universal", ...detectProjectAgents(process.c
|
|
|
91
91
|
|
|
92
92
|
// ── Create TUI ──────────────────────────────────────────────────────
|
|
93
93
|
|
|
94
|
-
|
|
94
|
+
let tui: ReturnType<typeof createTui> | null = null;
|
|
95
|
+
|
|
96
|
+
const renderer = await createCliRenderer({
|
|
97
|
+
exitOnCtrlC: true,
|
|
98
|
+
onDestroy: () => tui?.destroy(),
|
|
99
|
+
});
|
|
95
100
|
|
|
96
101
|
const allSkills = getCatalogSkills();
|
|
97
102
|
const lock = readLock();
|
|
98
103
|
const skillRepos = new Map<string, string | null>();
|
|
104
|
+
const skillDates = new Map<string, string | null>();
|
|
99
105
|
for (const name of allSkills) {
|
|
100
|
-
|
|
106
|
+
const entry = lock.skills[name];
|
|
107
|
+
skillRepos.set(name, entry?.source || null);
|
|
108
|
+
skillDates.set(name, entry?.updatedAt || entry?.addedAt || null);
|
|
101
109
|
}
|
|
102
110
|
|
|
103
|
-
|
|
111
|
+
tui = createTui(renderer, {
|
|
104
112
|
allSkills,
|
|
105
113
|
skillRepos,
|
|
114
|
+
skillDates,
|
|
106
115
|
globalInstalled,
|
|
107
116
|
localInstalled,
|
|
108
117
|
catalogPath: CATALOG,
|
package/lib.ts
CHANGED
package/package.json
CHANGED
package/tui.test.ts
CHANGED
|
@@ -16,6 +16,7 @@ function setup(opts?: {
|
|
|
16
16
|
}) {
|
|
17
17
|
const skills = opts?.skills ?? ["alpha", "beta", "gamma"];
|
|
18
18
|
const skillRepos = opts?.skillRepos ?? new Map(skills.map((s) => [s, null]));
|
|
19
|
+
const skillDates = new Map<string, string | null>(skills.map((s) => [s, null]));
|
|
19
20
|
const globalInstalled = new Set(opts?.globalInstalled ?? []);
|
|
20
21
|
const localInstalled = new Set(opts?.localInstalled ?? []);
|
|
21
22
|
|
|
@@ -43,6 +44,7 @@ function setup(opts?: {
|
|
|
43
44
|
return {
|
|
44
45
|
allSkills: skills,
|
|
45
46
|
skillRepos,
|
|
47
|
+
skillDates,
|
|
46
48
|
globalInstalled,
|
|
47
49
|
localInstalled,
|
|
48
50
|
catalogPath: "/tmp/test-catalog",
|
|
@@ -68,6 +70,7 @@ function setup(opts?: {
|
|
|
68
70
|
return {
|
|
69
71
|
allSkills: skills,
|
|
70
72
|
skillRepos,
|
|
73
|
+
skillDates,
|
|
71
74
|
globalInstalled,
|
|
72
75
|
localInstalled,
|
|
73
76
|
catalogPath: "/tmp/test-catalog",
|
package/tui.ts
CHANGED
|
@@ -15,6 +15,7 @@ export type ColId = "global" | "local";
|
|
|
15
15
|
export type TuiDeps = {
|
|
16
16
|
allSkills: string[];
|
|
17
17
|
skillRepos: Map<string, string | null>;
|
|
18
|
+
skillDates: Map<string, string | null>;
|
|
18
19
|
globalInstalled: Set<string>;
|
|
19
20
|
localInstalled: Set<string>;
|
|
20
21
|
catalogPath: string;
|
|
@@ -49,6 +50,21 @@ export function createTui(renderer: CliRenderer, deps: TuiDeps) {
|
|
|
49
50
|
return `${text.slice(0, max - 1)}\u2026`;
|
|
50
51
|
}
|
|
51
52
|
|
|
53
|
+
function relativeDate(iso: string): string {
|
|
54
|
+
const ms = Date.now() - new Date(iso).getTime();
|
|
55
|
+
if (ms < 0) return "just now";
|
|
56
|
+
const mins = Math.floor(ms / 60000);
|
|
57
|
+
if (mins < 1) return "just now";
|
|
58
|
+
if (mins < 60) return `${mins}m ago`;
|
|
59
|
+
const hrs = Math.floor(mins / 60);
|
|
60
|
+
if (hrs < 24) return `${hrs}h ago`;
|
|
61
|
+
const days = Math.floor(hrs / 24);
|
|
62
|
+
if (days < 30) return `${days}d ago`;
|
|
63
|
+
const months = Math.floor(days / 30);
|
|
64
|
+
if (months < 12) return `${months}mo ago`;
|
|
65
|
+
return `${Math.floor(months / 12)}y ago`;
|
|
66
|
+
}
|
|
67
|
+
|
|
52
68
|
// ── Build display list ─────────────────────────────────────────────
|
|
53
69
|
|
|
54
70
|
const displayItems: DisplayItem[] = [];
|
|
@@ -178,12 +194,14 @@ export function createTui(renderer: CliRenderer, deps: TuiDeps) {
|
|
|
178
194
|
});
|
|
179
195
|
|
|
180
196
|
let COL_W = 14;
|
|
197
|
+
let DATE_W = 10;
|
|
181
198
|
let NAME_W = 34;
|
|
182
199
|
|
|
183
200
|
function calcWidths() {
|
|
184
201
|
const w = (renderer as any).width ?? process.stdout.columns ?? 80;
|
|
185
202
|
COL_W = Math.max(5, Math.min(14, Math.floor((w - 20) / 2)));
|
|
186
|
-
|
|
203
|
+
DATE_W = 10;
|
|
204
|
+
NAME_W = Math.min(40, Math.max(15, w - COL_W * 2 - DATE_W - 1));
|
|
187
205
|
}
|
|
188
206
|
calcWidths();
|
|
189
207
|
|
|
@@ -208,10 +226,18 @@ export function createTui(renderer: CliRenderer, deps: TuiDeps) {
|
|
|
208
226
|
attributes: TextAttributes.BOLD,
|
|
209
227
|
width: COL_W,
|
|
210
228
|
});
|
|
229
|
+
const colUpdated = new TextRenderable(renderer, {
|
|
230
|
+
id: "col-updated",
|
|
231
|
+
content: "Updated",
|
|
232
|
+
fg: C.fgDim,
|
|
233
|
+
attributes: TextAttributes.BOLD,
|
|
234
|
+
width: DATE_W,
|
|
235
|
+
});
|
|
211
236
|
|
|
212
237
|
colHeaderRow.add(colName);
|
|
213
238
|
colHeaderRow.add(colGlobal);
|
|
214
239
|
colHeaderRow.add(colLocal);
|
|
240
|
+
colHeaderRow.add(colUpdated);
|
|
215
241
|
|
|
216
242
|
const sep = new TextRenderable(renderer, {
|
|
217
243
|
id: "sep",
|
|
@@ -235,6 +261,7 @@ export function createTui(renderer: CliRenderer, deps: TuiDeps) {
|
|
|
235
261
|
nameText: TextRenderable;
|
|
236
262
|
globalText: TextRenderable;
|
|
237
263
|
localText: TextRenderable;
|
|
264
|
+
dateText: TextRenderable;
|
|
238
265
|
};
|
|
239
266
|
const rows: RowRefs[] = new Array(allSkills.length);
|
|
240
267
|
|
|
@@ -262,7 +289,7 @@ export function createTui(renderer: CliRenderer, deps: TuiDeps) {
|
|
|
262
289
|
id: `header-text-${di}`,
|
|
263
290
|
content: ` ${item.repo}`,
|
|
264
291
|
fg: C.fgDim,
|
|
265
|
-
width: NAME_W + COL_W * 2,
|
|
292
|
+
width: NAME_W + COL_W * 2 + DATE_W,
|
|
266
293
|
});
|
|
267
294
|
hRow.add(hText);
|
|
268
295
|
scrollBox.add(hRow);
|
|
@@ -301,11 +328,20 @@ export function createTui(renderer: CliRenderer, deps: TuiDeps) {
|
|
|
301
328
|
width: COL_W,
|
|
302
329
|
});
|
|
303
330
|
|
|
331
|
+
const dateStr = deps.skillDates.get(skill);
|
|
332
|
+
const dateText = new TextRenderable(renderer, {
|
|
333
|
+
id: `date-${i}`,
|
|
334
|
+
content: dateStr ? relativeDate(dateStr) : "",
|
|
335
|
+
fg: C.fgDim,
|
|
336
|
+
width: DATE_W,
|
|
337
|
+
});
|
|
338
|
+
|
|
304
339
|
row.add(nameText);
|
|
305
340
|
row.add(globalText);
|
|
306
341
|
row.add(localText);
|
|
342
|
+
row.add(dateText);
|
|
307
343
|
scrollBox.add(row);
|
|
308
|
-
rows[i] = { row, nameText, globalText, localText };
|
|
344
|
+
rows[i] = { row, nameText, globalText, localText, dateText };
|
|
309
345
|
}
|
|
310
346
|
}
|
|
311
347
|
|
|
@@ -436,7 +472,7 @@ export function createTui(renderer: CliRenderer, deps: TuiDeps) {
|
|
|
436
472
|
statusLine.fg = color;
|
|
437
473
|
if (statusTimeout) clearTimeout(statusTimeout);
|
|
438
474
|
statusTimeout = setTimeout(() => {
|
|
439
|
-
|
|
475
|
+
statusLine.content = "";
|
|
440
476
|
}, 3000);
|
|
441
477
|
}
|
|
442
478
|
|
|
@@ -445,14 +481,16 @@ export function createTui(renderer: CliRenderer, deps: TuiDeps) {
|
|
|
445
481
|
colName.width = NAME_W;
|
|
446
482
|
colGlobal.width = COL_W;
|
|
447
483
|
colLocal.width = COL_W;
|
|
484
|
+
colUpdated.width = DATE_W;
|
|
448
485
|
for (let i = 0; i < allSkills.length; i++) {
|
|
449
486
|
const r = rows[i]!;
|
|
450
487
|
r.nameText.width = NAME_W;
|
|
451
488
|
r.globalText.width = COL_W;
|
|
452
489
|
r.localText.width = COL_W;
|
|
490
|
+
r.dateText.width = DATE_W;
|
|
453
491
|
}
|
|
454
492
|
for (const [, ref] of headerRefs) {
|
|
455
|
-
ref.text.width = NAME_W + COL_W * 2;
|
|
493
|
+
ref.text.width = NAME_W + COL_W * 2 + DATE_W;
|
|
456
494
|
}
|
|
457
495
|
}
|
|
458
496
|
|
|
@@ -723,9 +761,14 @@ export function createTui(renderer: CliRenderer, deps: TuiDeps) {
|
|
|
723
761
|
ensureVisible();
|
|
724
762
|
});
|
|
725
763
|
|
|
764
|
+
function destroy() {
|
|
765
|
+
if (statusTimeout) clearTimeout(statusTimeout);
|
|
766
|
+
}
|
|
767
|
+
|
|
726
768
|
return {
|
|
727
769
|
refreshAll,
|
|
728
770
|
relayout,
|
|
771
|
+
destroy,
|
|
729
772
|
get state() {
|
|
730
773
|
return {
|
|
731
774
|
cursor,
|
package/update.ts
CHANGED
|
@@ -89,6 +89,7 @@ for (const [repo, skills] of byRepo) {
|
|
|
89
89
|
const fileCount = await downloadSkillFiles(repo, branch, skill.skillPath, skillDir, tree);
|
|
90
90
|
|
|
91
91
|
lock.skills[skill.name]!.treeSHA = skill.newSHA;
|
|
92
|
+
lock.skills[skill.name]!.updatedAt = new Date().toISOString();
|
|
92
93
|
console.log(` updated (${fileCount} files)`);
|
|
93
94
|
totalUpdated++;
|
|
94
95
|
}
|