github-labels-template 0.7.0 → 0.8.0-patch.f835045
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/dist/index.js +355 -19
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/index.ts
|
|
4
|
-
import { defineCommand as
|
|
4
|
+
import { defineCommand as defineCommand8, runMain } from "citty";
|
|
5
5
|
|
|
6
6
|
// src/commands/apply.ts
|
|
7
7
|
import { defineCommand } from "citty";
|
|
@@ -621,21 +621,24 @@ var CATEGORY_NAMES = {
|
|
|
621
621
|
resolution: "Resolution",
|
|
622
622
|
area: "Area"
|
|
623
623
|
};
|
|
624
|
-
function buildSystemPrompt(category, count) {
|
|
624
|
+
function buildSystemPrompt(category, count, attempt = 1) {
|
|
625
625
|
const categoryTitle = CATEGORY_NAMES[category] ?? category;
|
|
626
626
|
const existingLabels = labels_default[category] ?? [];
|
|
627
627
|
const existingList = existingLabels.map((l) => ` - "${l.name}" (${l.color}) — ${l.description}`).join(`
|
|
628
628
|
`);
|
|
629
|
+
const variationHint = attempt > 1 ? `IMPORTANT: This is attempt #${attempt}. You MUST generate completely different label names, colors, and descriptions than any previous suggestions. Be creative and explore new angles.` : null;
|
|
629
630
|
return [
|
|
630
|
-
`You are a GitHub label generator. Generate exactly ${count} label suggestions for the "${categoryTitle}" category.`,
|
|
631
|
+
`You are a GitHub label generator. The user will describe the kind of label they need. Generate exactly ${count} label suggestions for the "${categoryTitle}" category that DIRECTLY match what the user is asking for.`,
|
|
631
632
|
"",
|
|
633
|
+
"CRITICAL: Every suggestion MUST be relevant to the user's description. Do NOT generate generic or unrelated labels. Focus on what the user specifically asked for.",
|
|
634
|
+
...variationHint ? ["", variationHint, ""] : [""],
|
|
632
635
|
"Each label must follow this exact JSON format:",
|
|
633
636
|
"[",
|
|
634
637
|
` { "name": "label-name", "color": "hex123", "description": "[${categoryTitle}] Description text [scope]" }`,
|
|
635
638
|
"]",
|
|
636
639
|
"",
|
|
637
640
|
"Rules:",
|
|
638
|
-
"- name: lowercase, concise (1-3 words), use spaces for multi-word names",
|
|
641
|
+
"- name: lowercase, concise (1-3 words), use spaces for multi-word names, must reflect the user's request",
|
|
639
642
|
"- color: 6-character hex without #, choose colors that are visually distinct from existing labels",
|
|
640
643
|
`- description: MUST start with [${categoryTitle}] and end with [issues], [PRs], or [issues, PRs]`,
|
|
641
644
|
"- Do NOT duplicate any of these existing labels:",
|
|
@@ -645,12 +648,17 @@ function buildSystemPrompt(category, count) {
|
|
|
645
648
|
].join(`
|
|
646
649
|
`);
|
|
647
650
|
}
|
|
648
|
-
function buildUserPrompt(description, refinement) {
|
|
651
|
+
function buildUserPrompt(description, refinement, attempt = 1) {
|
|
649
652
|
let prompt = `I need a label for: ${description}`;
|
|
650
653
|
if (refinement) {
|
|
651
654
|
prompt += `
|
|
652
655
|
|
|
653
656
|
Refinement feedback: ${refinement}`;
|
|
657
|
+
}
|
|
658
|
+
if (attempt > 1) {
|
|
659
|
+
prompt += `
|
|
660
|
+
|
|
661
|
+
Generate different suggestions from previous attempts. This is attempt #${attempt}, so provide fresh and unique alternatives.`;
|
|
654
662
|
}
|
|
655
663
|
return prompt;
|
|
656
664
|
}
|
|
@@ -683,13 +691,13 @@ function parseLabelsResponse(text) {
|
|
|
683
691
|
});
|
|
684
692
|
}
|
|
685
693
|
async function generateLabels(options) {
|
|
686
|
-
const { category, description, count = 3, refinement, model } = options;
|
|
694
|
+
const { category, description, count = 3, refinement, model, attempt = 1 } = options;
|
|
687
695
|
const client = new CopilotClient;
|
|
688
696
|
await client.start();
|
|
689
697
|
try {
|
|
690
698
|
const sessionConfig = {
|
|
691
699
|
systemMessage: {
|
|
692
|
-
content: buildSystemPrompt(category, count)
|
|
700
|
+
content: buildSystemPrompt(category, count, attempt)
|
|
693
701
|
}
|
|
694
702
|
};
|
|
695
703
|
if (model) {
|
|
@@ -697,7 +705,7 @@ async function generateLabels(options) {
|
|
|
697
705
|
}
|
|
698
706
|
const session = await client.createSession(sessionConfig);
|
|
699
707
|
try {
|
|
700
|
-
const userPrompt = buildUserPrompt(description, refinement);
|
|
708
|
+
const userPrompt = buildUserPrompt(description, refinement, attempt);
|
|
701
709
|
const response = await session.sendAndWait({ content: userPrompt });
|
|
702
710
|
if (!response || !response.data?.content) {
|
|
703
711
|
throw new Error("No response received from Copilot");
|
|
@@ -818,6 +826,7 @@ var generate_default = defineCommand3({
|
|
|
818
826
|
});
|
|
819
827
|
let selectedLabel = null;
|
|
820
828
|
let refinement;
|
|
829
|
+
let attempt = 1;
|
|
821
830
|
while (!selectedLabel) {
|
|
822
831
|
info(refinement ? "Regenerating with your feedback..." : "Generating label suggestions...");
|
|
823
832
|
let suggestions;
|
|
@@ -827,7 +836,8 @@ var generate_default = defineCommand3({
|
|
|
827
836
|
description,
|
|
828
837
|
count: 3,
|
|
829
838
|
refinement,
|
|
830
|
-
model: args.model
|
|
839
|
+
model: args.model,
|
|
840
|
+
attempt
|
|
831
841
|
});
|
|
832
842
|
} catch (err) {
|
|
833
843
|
error(`Failed to generate labels: ${err instanceof Error ? err.message : String(err)}`);
|
|
@@ -837,6 +847,7 @@ var generate_default = defineCommand3({
|
|
|
837
847
|
});
|
|
838
848
|
if (retry) {
|
|
839
849
|
refinement = undefined;
|
|
850
|
+
attempt = 1;
|
|
840
851
|
continue;
|
|
841
852
|
}
|
|
842
853
|
return;
|
|
@@ -873,10 +884,12 @@ var generate_default = defineCommand3({
|
|
|
873
884
|
message: "What would you like to change?",
|
|
874
885
|
validate: (value) => value.trim().length > 0 || "Please provide feedback."
|
|
875
886
|
});
|
|
887
|
+
attempt++;
|
|
876
888
|
continue;
|
|
877
889
|
}
|
|
878
890
|
if (choice === "regenerate") {
|
|
879
891
|
refinement = undefined;
|
|
892
|
+
attempt++;
|
|
880
893
|
continue;
|
|
881
894
|
}
|
|
882
895
|
const pickIndex = parseInt(choice.replace("pick:", ""), 10);
|
|
@@ -1063,13 +1076,171 @@ var list_default = defineCommand5({
|
|
|
1063
1076
|
}
|
|
1064
1077
|
});
|
|
1065
1078
|
|
|
1079
|
+
// src/commands/check.ts
|
|
1080
|
+
import { defineCommand as defineCommand6 } from "citty";
|
|
1081
|
+
import pc7 from "picocolors";
|
|
1082
|
+
function statusIcon(status) {
|
|
1083
|
+
if (status === "match")
|
|
1084
|
+
return pc7.green("✔");
|
|
1085
|
+
if (status === "missing")
|
|
1086
|
+
return pc7.red("✘");
|
|
1087
|
+
return pc7.yellow("~");
|
|
1088
|
+
}
|
|
1089
|
+
function statusLabel(status) {
|
|
1090
|
+
switch (status) {
|
|
1091
|
+
case "match":
|
|
1092
|
+
return pc7.dim("match");
|
|
1093
|
+
case "color-mismatch":
|
|
1094
|
+
return pc7.yellow("color mismatch");
|
|
1095
|
+
case "desc-mismatch":
|
|
1096
|
+
return pc7.yellow("description mismatch");
|
|
1097
|
+
case "both-mismatch":
|
|
1098
|
+
return pc7.yellow("color + description mismatch");
|
|
1099
|
+
case "missing":
|
|
1100
|
+
return pc7.red("missing");
|
|
1101
|
+
}
|
|
1102
|
+
}
|
|
1103
|
+
function isFailing(status, strict) {
|
|
1104
|
+
if (status === "missing")
|
|
1105
|
+
return true;
|
|
1106
|
+
if (strict && status !== "match")
|
|
1107
|
+
return true;
|
|
1108
|
+
return false;
|
|
1109
|
+
}
|
|
1110
|
+
var check_default = defineCommand6({
|
|
1111
|
+
meta: {
|
|
1112
|
+
name: "check",
|
|
1113
|
+
description: "Check if a repository is using the Clean Label template"
|
|
1114
|
+
},
|
|
1115
|
+
args: {
|
|
1116
|
+
repo: {
|
|
1117
|
+
type: "string",
|
|
1118
|
+
alias: "r",
|
|
1119
|
+
description: "Target repository (owner/repo). Defaults to current repo."
|
|
1120
|
+
},
|
|
1121
|
+
category: {
|
|
1122
|
+
type: "string",
|
|
1123
|
+
alias: "c",
|
|
1124
|
+
description: 'Check specific category(ies) only. Comma-separated (e.g., --category "type,status")'
|
|
1125
|
+
},
|
|
1126
|
+
strict: {
|
|
1127
|
+
type: "boolean",
|
|
1128
|
+
alias: "s",
|
|
1129
|
+
default: false,
|
|
1130
|
+
description: "Strict mode — also flag labels with mismatched color or description"
|
|
1131
|
+
}
|
|
1132
|
+
},
|
|
1133
|
+
async run({ args }) {
|
|
1134
|
+
if (!await checkGhInstalled()) {
|
|
1135
|
+
error("gh CLI is not installed. Install it from https://cli.github.com");
|
|
1136
|
+
process.exit(1);
|
|
1137
|
+
}
|
|
1138
|
+
if (!await checkGhAuth()) {
|
|
1139
|
+
error("Not authenticated. Run `gh auth login` first.");
|
|
1140
|
+
process.exit(1);
|
|
1141
|
+
}
|
|
1142
|
+
const repo = args.repo || await detectRepo();
|
|
1143
|
+
if (!repo) {
|
|
1144
|
+
error("Could not detect repository. Use --repo <owner/repo> or run inside a git repo.");
|
|
1145
|
+
process.exit(1);
|
|
1146
|
+
}
|
|
1147
|
+
const strict = args.strict ?? false;
|
|
1148
|
+
info(`Target: ${repo}`);
|
|
1149
|
+
if (strict)
|
|
1150
|
+
info("Mode: strict (name + color + description)");
|
|
1151
|
+
const repoLabels = await listLabelsDetailed(repo);
|
|
1152
|
+
const repoMap = new Map(repoLabels.map((l) => [l.name.toLowerCase(), l]));
|
|
1153
|
+
const { entries: templateEntries } = filterLabels(labels_default, {
|
|
1154
|
+
category: args.category
|
|
1155
|
+
});
|
|
1156
|
+
const results = [];
|
|
1157
|
+
for (const [category, categoryLabels] of templateEntries) {
|
|
1158
|
+
for (const tmpl of categoryLabels) {
|
|
1159
|
+
const existing = repoMap.get(tmpl.name.toLowerCase());
|
|
1160
|
+
let status;
|
|
1161
|
+
let repoColor;
|
|
1162
|
+
let repoDesc;
|
|
1163
|
+
if (!existing) {
|
|
1164
|
+
status = "missing";
|
|
1165
|
+
} else {
|
|
1166
|
+
const colorMatch = existing.color.toLowerCase() === tmpl.color.toLowerCase();
|
|
1167
|
+
const descMatch = existing.description.trim() === tmpl.description.trim();
|
|
1168
|
+
if (colorMatch && descMatch) {
|
|
1169
|
+
status = "match";
|
|
1170
|
+
} else if (!colorMatch && !descMatch) {
|
|
1171
|
+
status = "both-mismatch";
|
|
1172
|
+
repoColor = existing.color;
|
|
1173
|
+
repoDesc = existing.description;
|
|
1174
|
+
} else if (!colorMatch) {
|
|
1175
|
+
status = "color-mismatch";
|
|
1176
|
+
repoColor = existing.color;
|
|
1177
|
+
} else {
|
|
1178
|
+
status = "desc-mismatch";
|
|
1179
|
+
repoDesc = existing.description;
|
|
1180
|
+
}
|
|
1181
|
+
}
|
|
1182
|
+
results.push({ template: tmpl, category, status, repoColor, repoDesc });
|
|
1183
|
+
}
|
|
1184
|
+
}
|
|
1185
|
+
const byCategory = new Map;
|
|
1186
|
+
for (const result of results) {
|
|
1187
|
+
if (!byCategory.has(result.category))
|
|
1188
|
+
byCategory.set(result.category, []);
|
|
1189
|
+
byCategory.get(result.category).push(result);
|
|
1190
|
+
}
|
|
1191
|
+
console.log("");
|
|
1192
|
+
for (const [category, catResults] of byCategory) {
|
|
1193
|
+
const catTitle = category.charAt(0).toUpperCase() + category.slice(1);
|
|
1194
|
+
const catFailing = catResults.filter((r) => isFailing(r.status, strict)).length;
|
|
1195
|
+
const catStatus = catFailing > 0 ? pc7.red(`${catFailing} issue${catFailing !== 1 ? "s" : ""}`) : pc7.green("all good");
|
|
1196
|
+
console.log(`${pc7.bold(catTitle)} ${pc7.dim(`(${catResults.length})`)} — ${catStatus}`);
|
|
1197
|
+
for (const result of catResults) {
|
|
1198
|
+
const icon = statusIcon(result.status);
|
|
1199
|
+
const name = result.template.name.padEnd(28);
|
|
1200
|
+
const color = pc7.dim(`#${result.template.color}`);
|
|
1201
|
+
const lbl = statusLabel(result.status);
|
|
1202
|
+
let line = ` ${icon} ${name} ${color} ${lbl}`;
|
|
1203
|
+
if (result.repoColor) {
|
|
1204
|
+
line += pc7.dim(` (repo: #${result.repoColor})`);
|
|
1205
|
+
}
|
|
1206
|
+
if (result.repoDesc) {
|
|
1207
|
+
line += pc7.dim(`
|
|
1208
|
+
repo desc: "${result.repoDesc}"`);
|
|
1209
|
+
}
|
|
1210
|
+
console.log(line);
|
|
1211
|
+
}
|
|
1212
|
+
console.log("");
|
|
1213
|
+
}
|
|
1214
|
+
const matched = results.filter((r) => r.status === "match").length;
|
|
1215
|
+
const missing = results.filter((r) => r.status === "missing").length;
|
|
1216
|
+
const mismatched = results.filter((r) => r.status !== "match" && r.status !== "missing").length;
|
|
1217
|
+
const total = results.length;
|
|
1218
|
+
const failing = results.filter((r) => isFailing(r.status, strict)).length;
|
|
1219
|
+
const mismatchedStr = mismatched > 0 ? pc7.yellow(`, ${mismatched} mismatched`) : "";
|
|
1220
|
+
const missingStr = missing > 0 ? pc7.red(`, ${missing} missing`) : "";
|
|
1221
|
+
const scoreStr = pc7.bold(`${matched}/${total}`);
|
|
1222
|
+
console.log(`${pc7.bold("Result:")} ${scoreStr} labels matched${mismatchedStr}${missingStr}`);
|
|
1223
|
+
if (failing === 0) {
|
|
1224
|
+
const mismatchHint = !strict && mismatched > 0 ? pc7.dim(` (${mismatched} mismatch${mismatched !== 1 ? "es" : ""} — use --strict to enforce)`) : "";
|
|
1225
|
+
console.log(`${pc7.bold("Compatible:")} ${pc7.green("✔ Yes")}${strict ? " (strict)" : ""}${mismatchHint}`);
|
|
1226
|
+
} else {
|
|
1227
|
+
console.log(`${pc7.bold("Compatible:")} ${pc7.red("✘ No")} — run ${pc7.bold("ghlt apply")} to fix`);
|
|
1228
|
+
process.exit(1);
|
|
1229
|
+
}
|
|
1230
|
+
}
|
|
1231
|
+
});
|
|
1232
|
+
|
|
1233
|
+
// src/commands/update.ts
|
|
1234
|
+
import { defineCommand as defineCommand7 } from "citty";
|
|
1235
|
+
import { execSync } from "child_process";
|
|
1236
|
+
|
|
1066
1237
|
// src/ui/banner.ts
|
|
1067
1238
|
import figlet from "figlet";
|
|
1068
|
-
import
|
|
1239
|
+
import pc8 from "picocolors";
|
|
1069
1240
|
// package.json
|
|
1070
1241
|
var package_default = {
|
|
1071
1242
|
name: "github-labels-template",
|
|
1072
|
-
version: "0.
|
|
1243
|
+
version: "0.8.0-patch.f835045",
|
|
1073
1244
|
description: "A CLI tool to apply a curated GitHub labels template to any repository using gh CLI.",
|
|
1074
1245
|
type: "module",
|
|
1075
1246
|
bin: {
|
|
@@ -1133,24 +1304,187 @@ function getVersion() {
|
|
|
1133
1304
|
function getAuthor() {
|
|
1134
1305
|
return package_default.author ?? "unknown";
|
|
1135
1306
|
}
|
|
1307
|
+
function showUpdateBanner(latestVersion) {
|
|
1308
|
+
const current = getVersion();
|
|
1309
|
+
const visibleLen = (s) => s.replace(/\x1b\[[0-9;]*m/g, "").length;
|
|
1310
|
+
const line1 = ` ${pc8.bold(`Update available: v${current} → v${latestVersion}`)} `;
|
|
1311
|
+
const line2 = ` Run ${pc8.bold("ghlt update")} to upgrade. `;
|
|
1312
|
+
const width = Math.max(visibleLen(line1), visibleLen(line2));
|
|
1313
|
+
const border = "─".repeat(width);
|
|
1314
|
+
console.log(pc8.yellow(`┌${border}┐`));
|
|
1315
|
+
console.log(pc8.yellow("│") + line1 + " ".repeat(width - visibleLen(line1)) + pc8.yellow("│"));
|
|
1316
|
+
console.log(pc8.yellow("│") + line2 + " ".repeat(width - visibleLen(line2)) + pc8.yellow("│"));
|
|
1317
|
+
console.log(pc8.yellow(`└${border}┘`));
|
|
1318
|
+
console.log();
|
|
1319
|
+
}
|
|
1136
1320
|
function showBanner(minimal = false) {
|
|
1137
|
-
console.log(
|
|
1321
|
+
console.log(pc8.cyan(`
|
|
1138
1322
|
` + LOGO));
|
|
1139
|
-
console.log(` ${
|
|
1323
|
+
console.log(` ${pc8.dim("v" + getVersion())} ${pc8.dim("—")} ${pc8.dim("Built by " + getAuthor())}`);
|
|
1140
1324
|
if (!minimal) {
|
|
1141
|
-
console.log(` ${
|
|
1325
|
+
console.log(` ${pc8.dim(package_default.description)}`);
|
|
1142
1326
|
console.log();
|
|
1143
|
-
console.log(` ${
|
|
1144
|
-
console.log(` ${
|
|
1145
|
-
console.log(` ${
|
|
1327
|
+
console.log(` ${pc8.yellow("Star")} ${pc8.cyan("https://gh.waren.build/github-labels-template")}`);
|
|
1328
|
+
console.log(` ${pc8.green("Contribute")} ${pc8.cyan("https://gh.waren.build/github-labels-template/blob/main/CONTRIBUTING.md")}`);
|
|
1329
|
+
console.log(` ${pc8.magenta("Sponsor")} ${pc8.cyan("https://warengonzaga.com/sponsor")}`);
|
|
1146
1330
|
}
|
|
1147
1331
|
console.log();
|
|
1148
1332
|
}
|
|
1149
1333
|
|
|
1334
|
+
// src/utils/updater.ts
|
|
1335
|
+
import { existsSync as existsSync2, readFileSync as readFileSync2, writeFileSync as writeFileSync2, mkdirSync, renameSync } from "fs";
|
|
1336
|
+
import { join, dirname } from "path";
|
|
1337
|
+
import { homedir, tmpdir } from "os";
|
|
1338
|
+
var CACHE_DIR = join(homedir(), ".ghlt");
|
|
1339
|
+
var CACHE_FILE = join(CACHE_DIR, "update-check.json");
|
|
1340
|
+
var CACHE_TTL_MS = 24 * 60 * 60 * 1000;
|
|
1341
|
+
var REGISTRY_URL = "https://registry.npmjs.org/github-labels-template/latest";
|
|
1342
|
+
function isNewerVersion(latest, current) {
|
|
1343
|
+
const parse = (v) => v.replace(/^v/, "").split(/[-+]/)[0].split(".").map(Number);
|
|
1344
|
+
const [lMaj, lMin, lPatch] = parse(latest);
|
|
1345
|
+
const [cMaj, cMin, cPatch] = parse(current);
|
|
1346
|
+
if ([lMaj, lMin, lPatch, cMaj, cMin, cPatch].some(isNaN))
|
|
1347
|
+
return false;
|
|
1348
|
+
if (lMaj !== cMaj)
|
|
1349
|
+
return lMaj > cMaj;
|
|
1350
|
+
if (lMin !== cMin)
|
|
1351
|
+
return lMin > cMin;
|
|
1352
|
+
return lPatch > cPatch;
|
|
1353
|
+
}
|
|
1354
|
+
function readCache(cacheFile = CACHE_FILE) {
|
|
1355
|
+
try {
|
|
1356
|
+
if (!existsSync2(cacheFile))
|
|
1357
|
+
return null;
|
|
1358
|
+
const raw = readFileSync2(cacheFile, "utf-8");
|
|
1359
|
+
return JSON.parse(raw);
|
|
1360
|
+
} catch {
|
|
1361
|
+
return null;
|
|
1362
|
+
}
|
|
1363
|
+
}
|
|
1364
|
+
function writeCache(data, cacheFile = CACHE_FILE) {
|
|
1365
|
+
try {
|
|
1366
|
+
const dir = dirname(cacheFile);
|
|
1367
|
+
if (!existsSync2(dir))
|
|
1368
|
+
mkdirSync(dir, { recursive: true });
|
|
1369
|
+
const tmp = join(tmpdir(), `ghlt-update-${process.pid}-${Date.now()}.json`);
|
|
1370
|
+
writeFileSync2(tmp, JSON.stringify(data), "utf-8");
|
|
1371
|
+
renameSync(tmp, cacheFile);
|
|
1372
|
+
} catch {}
|
|
1373
|
+
}
|
|
1374
|
+
async function fetchLatestVersion() {
|
|
1375
|
+
try {
|
|
1376
|
+
const res = await fetch(REGISTRY_URL);
|
|
1377
|
+
if (!res.ok)
|
|
1378
|
+
return null;
|
|
1379
|
+
const data = await res.json();
|
|
1380
|
+
return data.version ?? null;
|
|
1381
|
+
} catch (err) {
|
|
1382
|
+
console.debug("Failed to fetch latest version from npm registry:", err);
|
|
1383
|
+
return null;
|
|
1384
|
+
}
|
|
1385
|
+
}
|
|
1386
|
+
function refreshCacheInBackground(cacheFile = CACHE_FILE) {
|
|
1387
|
+
fetchLatestVersion().then((version) => {
|
|
1388
|
+
if (version) {
|
|
1389
|
+
writeCache({ lastChecked: Date.now(), latestVersion: version }, cacheFile);
|
|
1390
|
+
}
|
|
1391
|
+
}).catch(() => {});
|
|
1392
|
+
}
|
|
1393
|
+
function checkForUpdate(cacheFile = CACHE_FILE) {
|
|
1394
|
+
if (process.env.CI === "true" || process.env.CI === "1")
|
|
1395
|
+
return null;
|
|
1396
|
+
if (process.env.NO_UPDATE_NOTIFIER)
|
|
1397
|
+
return null;
|
|
1398
|
+
if (process.argv.includes("--no-update-notifier"))
|
|
1399
|
+
return null;
|
|
1400
|
+
const cache = readCache(cacheFile);
|
|
1401
|
+
const now = Date.now();
|
|
1402
|
+
const isStale = !cache || now - cache.lastChecked > CACHE_TTL_MS;
|
|
1403
|
+
if (isStale) {
|
|
1404
|
+
refreshCacheInBackground(cacheFile);
|
|
1405
|
+
}
|
|
1406
|
+
if (cache?.latestVersion && isNewerVersion(cache.latestVersion, getVersion())) {
|
|
1407
|
+
return cache.latestVersion;
|
|
1408
|
+
}
|
|
1409
|
+
return null;
|
|
1410
|
+
}
|
|
1411
|
+
|
|
1412
|
+
// src/commands/update.ts
|
|
1413
|
+
function detectPackageManager() {
|
|
1414
|
+
try {
|
|
1415
|
+
execSync("bun --version", { stdio: "ignore" });
|
|
1416
|
+
return "bun";
|
|
1417
|
+
} catch {
|
|
1418
|
+
return "npm";
|
|
1419
|
+
}
|
|
1420
|
+
}
|
|
1421
|
+
function getUpdateCommand(pm) {
|
|
1422
|
+
if (pm === "bun")
|
|
1423
|
+
return "bun add -g github-labels-template";
|
|
1424
|
+
return "npm install -g github-labels-template";
|
|
1425
|
+
}
|
|
1426
|
+
var update_default = defineCommand7({
|
|
1427
|
+
meta: {
|
|
1428
|
+
name: "update",
|
|
1429
|
+
description: "Update ghlt to the latest published version"
|
|
1430
|
+
},
|
|
1431
|
+
args: {
|
|
1432
|
+
check: {
|
|
1433
|
+
type: "boolean",
|
|
1434
|
+
default: false,
|
|
1435
|
+
description: "Only check if an update is available without installing"
|
|
1436
|
+
},
|
|
1437
|
+
"dry-run": {
|
|
1438
|
+
type: "boolean",
|
|
1439
|
+
default: false,
|
|
1440
|
+
description: "Alias for --check — report availability without updating"
|
|
1441
|
+
}
|
|
1442
|
+
},
|
|
1443
|
+
async run({ args }) {
|
|
1444
|
+
const current = getVersion();
|
|
1445
|
+
info(`Current version: v${current}`);
|
|
1446
|
+
const latest = await fetchLatestVersion();
|
|
1447
|
+
if (!latest) {
|
|
1448
|
+
error("Could not fetch the latest version. Check your internet connection.");
|
|
1449
|
+
process.exit(1);
|
|
1450
|
+
}
|
|
1451
|
+
info(`Latest version: v${latest}`);
|
|
1452
|
+
writeCache({ lastChecked: Date.now(), latestVersion: latest });
|
|
1453
|
+
if (!isNewerVersion(latest, current)) {
|
|
1454
|
+
success("Already on the latest version.");
|
|
1455
|
+
return;
|
|
1456
|
+
}
|
|
1457
|
+
if (args.check || args["dry-run"]) {
|
|
1458
|
+
info(`Update available: v${current} → v${latest}`);
|
|
1459
|
+
info(`Run 'ghlt update' to upgrade.`);
|
|
1460
|
+
return;
|
|
1461
|
+
}
|
|
1462
|
+
info("Updating ghlt...");
|
|
1463
|
+
try {
|
|
1464
|
+
const pm = detectPackageManager();
|
|
1465
|
+
const cmd = getUpdateCommand(pm);
|
|
1466
|
+
info(`Running: ${cmd}`);
|
|
1467
|
+
execSync(cmd, { stdio: "inherit" });
|
|
1468
|
+
success(`ghlt updated to v${latest}`);
|
|
1469
|
+
} catch {
|
|
1470
|
+
error("Update failed. Try running the update command manually:");
|
|
1471
|
+
console.log(` npm install -g github-labels-template`);
|
|
1472
|
+
process.exit(1);
|
|
1473
|
+
}
|
|
1474
|
+
}
|
|
1475
|
+
});
|
|
1476
|
+
|
|
1150
1477
|
// src/index.ts
|
|
1151
1478
|
var isHelp = process.argv.includes("--help") || process.argv.includes("-h");
|
|
1479
|
+
var isUpdateCommand = process.argv.includes("update");
|
|
1152
1480
|
showBanner(isHelp);
|
|
1153
|
-
|
|
1481
|
+
if (!isUpdateCommand) {
|
|
1482
|
+
const availableUpdate = checkForUpdate();
|
|
1483
|
+
if (availableUpdate) {
|
|
1484
|
+
showUpdateBanner(availableUpdate);
|
|
1485
|
+
}
|
|
1486
|
+
}
|
|
1487
|
+
var main = defineCommand8({
|
|
1154
1488
|
meta: {
|
|
1155
1489
|
name: "ghlt",
|
|
1156
1490
|
version: getVersion(),
|
|
@@ -1168,7 +1502,9 @@ var main = defineCommand6({
|
|
|
1168
1502
|
wipe: wipe_default,
|
|
1169
1503
|
migrate: migrate_default,
|
|
1170
1504
|
generate: generate_default,
|
|
1171
|
-
list: list_default
|
|
1505
|
+
list: list_default,
|
|
1506
|
+
check: check_default,
|
|
1507
|
+
update: update_default
|
|
1172
1508
|
},
|
|
1173
1509
|
run({ args }) {
|
|
1174
1510
|
if (args.version) {
|