spb/spbgit Public MIT
SPB Git — the platform hosting itself
JavaScript 73.9%
CSS 11.7%
Nunjucks 11.6%
Shell 2.7%
1/**2 * ─────────────────────────────────────────────3 * SPB Git — Personal Git Platform4 * ─────────────────────────────────────────────5 * Author : Simon-Pierre Boucher6 * Contact : contact@spboucher.ai7 * File : cli/commands/list.mjs8 * Purpose : `spbgit list` — table of server repositories9 * License : MIT © Simon-Pierre Boucher10 * ─────────────────────────────────────────────11 */1213import pc from 'picocolors';14import { requireCliConfig } from '../lib/config.mjs';15import { api } from '../lib/api.mjs';16import { printTable } from '../lib/ui.mjs';1718/** Compact "3 h ago" style formatter (client-side). */19export function ago(iso) {20 if (!iso) return pc.dim('never');21 const s = Math.floor((Date.now() - new Date(iso).getTime()) / 1000);22 if (s < 90) return 'just now';23 if (s < 3600) return `${Math.floor(s / 60)} min ago`;24 if (s < 86400) return `${Math.floor(s / 3600)} h ago`;25 if (s < 2592000) return `${Math.floor(s / 86400)} d ago`;26 return `${Math.floor(s / 2592000)} mo ago`;27}2829export function registerList(program) {30 program31 .command('list')32 .alias('ls')33 .description('list every repository on the server')34 .option('--json', 'machine-readable output')35 .action(async (opts) => {36 const config = requireCliConfig();37 const { repos } = await api(config, 'GET', '/api/v1/repos', undefined, { auth: false });38 if (opts.json) {39 console.log(JSON.stringify(repos, null, 2));40 return;41 }42 if (repos.length === 0) {43 console.log(pc.dim('No repositories yet. Create one: spbgit create <name>'));44 return;45 }46 printTable([47 [pc.bold('NAME'), pc.bold('DESCRIPTION'), pc.bold('LANGUAGE'), pc.bold('PUSHED'), pc.bold('CLONE URL')],48 ...repos.map((r) => [49 (r.pinned ? pc.yellow('★ ') : ' ') + pc.bold(r.name),50 (r.description || pc.dim('—')).slice(0, 48),51 r.topLanguage ?? pc.dim('—'),52 ago(r.lastPush),53 pc.dim(r.cloneUrl),54 ]),55 ]);56 });57}58