@git.zone/cli 2.15.0 → 2.16.1

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.
@@ -0,0 +1,290 @@
1
+ import * as plugins from "./mod.plugins.js";
2
+ import { commitinfo } from "../00_commitinfo_data.js";
3
+ import { getCliMode, printJson } from "../helpers.climode.js";
4
+ import { PackageManagerUtil, } from "./classes.packagemanager.js";
5
+ export const GITZONE_PACKAGES = [
6
+ "@git.zone/cli",
7
+ "@git.zone/tsdoc",
8
+ "@git.zone/tsbuild",
9
+ "@git.zone/tstest",
10
+ "@git.zone/tspublish",
11
+ "@git.zone/tsbundle",
12
+ "@git.zone/tsdocker",
13
+ "@git.zone/tsview",
14
+ "@git.zone/tswatch",
15
+ "@git.zone/tsrust",
16
+ ];
17
+ export const run = async (argvArg = {}) => {
18
+ const mode = await getCliMode(argvArg);
19
+ const command = argvArg._?.[1] || "help";
20
+ if (mode.help || command === "help") {
21
+ showHelp(mode);
22
+ return;
23
+ }
24
+ switch (command) {
25
+ case "update":
26
+ await runUpdate(argvArg, mode);
27
+ break;
28
+ case "install":
29
+ await runInstall(argvArg, mode);
30
+ break;
31
+ default:
32
+ showHelp(mode);
33
+ break;
34
+ }
35
+ };
36
+ async function runUpdate(argvArg, mode) {
37
+ const verbose = Boolean(argvArg.v || argvArg.verbose);
38
+ const pmUtil = new PackageManagerUtil();
39
+ console.log("Scanning for installed @git.zone packages...\n");
40
+ const pnpmInfo = await pmUtil.getPnpmVersionInfo();
41
+ if (!pnpmInfo.available) {
42
+ console.log("pnpm is required for gitzone tools update, but it was not found.");
43
+ return;
44
+ }
45
+ console.log("Package manager:\n");
46
+ console.log(" Name Current Latest Status");
47
+ console.log(" ----------------------------------------------");
48
+ const latestPnpm = (pnpmInfo.latestVersion || "unknown").padEnd(12);
49
+ const pnpmStatus = pnpmInfo.latestVersion === null
50
+ ? "? Version unknown"
51
+ : pnpmInfo.needsUpdate
52
+ ? "Update available"
53
+ : "Up to date";
54
+ console.log(` ${"pnpm".padEnd(9)}${pnpmInfo.currentVersion.padEnd(12)}${latestPnpm}${pnpmStatus}`);
55
+ console.log("");
56
+ if (verbose) {
57
+ console.log("Using pnpm as the supported global package manager.\n");
58
+ }
59
+ const selfUpdated = await handleSelfUpdate(pmUtil, mode);
60
+ if (selfUpdated) {
61
+ return;
62
+ }
63
+ const installedPackages = await pmUtil.getInstalledPackages();
64
+ const packageInfos = await getPackageUpdateInfos(pmUtil, installedPackages);
65
+ if (packageInfos.length === 0) {
66
+ console.log("No managed @git.zone packages found installed globally.");
67
+ return;
68
+ }
69
+ console.log("Installed @git.zone packages:\n");
70
+ console.log(" Package Current Latest Status");
71
+ console.log(" ------------------------------------------------------------");
72
+ for (const packageInfo of packageInfos) {
73
+ const status = packageInfo.latestVersion === "unknown"
74
+ ? "? Version unknown"
75
+ : packageInfo.needsUpdate
76
+ ? "Update available"
77
+ : "Up to date";
78
+ console.log(` ${packageInfo.name.padEnd(28)}${packageInfo.currentVersion.padEnd(12)}${packageInfo.latestVersion.padEnd(12)}${status}`);
79
+ }
80
+ console.log("");
81
+ await printMissingPackages(pmUtil, installedPackages);
82
+ const packagesToUpdate = packageInfos.filter((packageInfo) => packageInfo.needsUpdate);
83
+ if (packagesToUpdate.length === 0) {
84
+ console.log("All managed packages are up to date.");
85
+ return;
86
+ }
87
+ console.log(`Found ${packagesToUpdate.length} package(s) with available updates.\n`);
88
+ if (!mode.yes && !mode.interactive) {
89
+ console.log("Run gitzone tools update -y to update without prompts.");
90
+ return;
91
+ }
92
+ let shouldUpdate = mode.yes;
93
+ if (!shouldUpdate) {
94
+ const interactInstance = new plugins.smartinteract.SmartInteract();
95
+ const answer = await interactInstance.askQuestion({
96
+ type: "confirm",
97
+ name: "confirmUpdate",
98
+ message: "Do you want to update these packages?",
99
+ default: true,
100
+ });
101
+ shouldUpdate = answer.value === true;
102
+ }
103
+ if (!shouldUpdate) {
104
+ console.log("Update cancelled.");
105
+ return;
106
+ }
107
+ await installPackages(pmUtil, packagesToUpdate.map((packageInfo) => packageInfo.name), "updated");
108
+ }
109
+ async function runInstall(argvArg, mode) {
110
+ const verbose = Boolean(argvArg.v || argvArg.verbose);
111
+ const pmUtil = new PackageManagerUtil();
112
+ console.log("Scanning for missing @git.zone packages...\n");
113
+ const pnpmAvailable = await pmUtil.detectPnpm();
114
+ if (!pnpmAvailable) {
115
+ console.log("pnpm is required for gitzone tools install, but it was not found.");
116
+ return;
117
+ }
118
+ if (verbose) {
119
+ console.log("Using pnpm as the supported global package manager.\n");
120
+ }
121
+ const installedPackages = await pmUtil.getInstalledPackages();
122
+ const installedNames = new Set(installedPackages.map((packageInfo) => packageInfo.name));
123
+ const missingPackages = GITZONE_PACKAGES.filter((packageName) => !installedNames.has(packageName));
124
+ if (missingPackages.length === 0) {
125
+ console.log("All managed @git.zone packages are already installed.");
126
+ return;
127
+ }
128
+ console.log(`Found ${missingPackages.length} missing package(s).\n`);
129
+ if (!mode.yes && !mode.interactive) {
130
+ await printPackageListWithLatest(pmUtil, missingPackages);
131
+ console.log("Run gitzone tools install -y to install all missing packages without prompts.");
132
+ return;
133
+ }
134
+ let selectedPackages = missingPackages;
135
+ if (!mode.yes) {
136
+ const choicesWithVersions = [];
137
+ for (const packageName of missingPackages) {
138
+ const latest = await pmUtil.getLatestVersion(packageName);
139
+ choicesWithVersions.push({
140
+ name: `${packageName}${latest ? `@${latest}` : ""}`,
141
+ value: packageName,
142
+ });
143
+ }
144
+ const interactInstance = new plugins.smartinteract.SmartInteract();
145
+ const answer = await interactInstance.askQuestion({
146
+ type: "checkbox",
147
+ name: "packages",
148
+ message: "Select packages to install:",
149
+ default: missingPackages,
150
+ choices: choicesWithVersions,
151
+ });
152
+ selectedPackages = answer.value;
153
+ if (selectedPackages.length === 0) {
154
+ console.log("No packages selected. Nothing to install.");
155
+ return;
156
+ }
157
+ }
158
+ await installPackages(pmUtil, selectedPackages, "installed");
159
+ }
160
+ async function handleSelfUpdate(pmUtil, mode) {
161
+ console.log("Checking for gitzone self-update...\n");
162
+ const currentVersion = commitinfo.version;
163
+ const latestVersion = await pmUtil.getLatestVersion("@git.zone/cli");
164
+ if (!latestVersion || !pmUtil.isNewerVersion(currentVersion, latestVersion)) {
165
+ console.log(` @git.zone/cli ${currentVersion} Up to date\n`);
166
+ return false;
167
+ }
168
+ console.log(` @git.zone/cli ${currentVersion} -> ${latestVersion} Update available\n`);
169
+ if (!mode.yes && !mode.interactive) {
170
+ console.log("Run gitzone tools update -y to update gitzone first.");
171
+ return true;
172
+ }
173
+ let shouldUpdate = mode.yes;
174
+ if (!shouldUpdate) {
175
+ const interactInstance = new plugins.smartinteract.SmartInteract();
176
+ const answer = await interactInstance.askQuestion({
177
+ type: "confirm",
178
+ name: "confirmSelfUpdate",
179
+ message: "Do you want to update gitzone itself first?",
180
+ default: true,
181
+ });
182
+ shouldUpdate = answer.value === true;
183
+ }
184
+ if (!shouldUpdate) {
185
+ console.log("Skipping gitzone self-update.\n");
186
+ return false;
187
+ }
188
+ const success = await pmUtil.installLatest("@git.zone/cli");
189
+ if (!success) {
190
+ console.log("\ngitzone self-update failed. Continuing with the current version.\n");
191
+ return false;
192
+ }
193
+ console.log("\ngitzone has been updated. Re-run gitzone tools update to check remaining packages.");
194
+ return true;
195
+ }
196
+ async function getPackageUpdateInfos(pmUtil, installedPackages) {
197
+ const packageInfos = [];
198
+ for (const installedPackage of installedPackages) {
199
+ if (!GITZONE_PACKAGES.includes(installedPackage.name)) {
200
+ continue;
201
+ }
202
+ const latestVersion = await pmUtil.getLatestVersion(installedPackage.name);
203
+ packageInfos.push({
204
+ name: installedPackage.name,
205
+ currentVersion: installedPackage.version,
206
+ latestVersion: latestVersion || "unknown",
207
+ needsUpdate: latestVersion
208
+ ? pmUtil.isNewerVersion(installedPackage.version, latestVersion)
209
+ : false,
210
+ });
211
+ }
212
+ return packageInfos;
213
+ }
214
+ async function printMissingPackages(pmUtil, installedPackages) {
215
+ const installedNames = new Set(installedPackages.map((packageInfo) => packageInfo.name));
216
+ const missingPackages = GITZONE_PACKAGES.filter((packageName) => !installedNames.has(packageName));
217
+ if (missingPackages.length === 0) {
218
+ return;
219
+ }
220
+ console.log("Not installed (managed @git.zone packages):\n");
221
+ await printPackageListWithLatest(pmUtil, missingPackages);
222
+ console.log("Run gitzone tools install to install missing packages.\n");
223
+ }
224
+ async function printPackageListWithLatest(pmUtil, packageNames) {
225
+ console.log(" Package Latest");
226
+ console.log(" ----------------------------------------");
227
+ for (const packageName of packageNames) {
228
+ const latest = await pmUtil.getLatestVersion(packageName);
229
+ console.log(` ${packageName.padEnd(28)} ${latest || "unknown"}`);
230
+ }
231
+ console.log("");
232
+ }
233
+ async function installPackages(pmUtil, packageNames, action) {
234
+ let successCount = 0;
235
+ let failCount = 0;
236
+ for (const packageName of packageNames) {
237
+ const success = await pmUtil.installLatest(packageName);
238
+ if (success) {
239
+ console.log(` ${packageName} ${action} successfully`);
240
+ successCount++;
241
+ }
242
+ else {
243
+ console.log(` ${packageName} failed`);
244
+ failCount++;
245
+ }
246
+ }
247
+ console.log("");
248
+ if (failCount === 0) {
249
+ console.log(`All ${successCount} package(s) ${action} successfully.`);
250
+ }
251
+ else {
252
+ console.log(`${successCount} package(s) ${action}, ${failCount} failed.`);
253
+ }
254
+ }
255
+ export function showHelp(mode) {
256
+ if (mode?.json) {
257
+ printJson({
258
+ name: "gitzone tools",
259
+ usage: "gitzone tools <command> [options]",
260
+ commands: [
261
+ { name: "update", description: "Check and update globally installed @git.zone packages" },
262
+ { name: "install", description: "Install missing managed @git.zone packages" },
263
+ ],
264
+ flags: [
265
+ { flag: "-y, --yes", description: "Run without confirmation prompts" },
266
+ { flag: "-v, --verbose", description: "Show package manager diagnostics" },
267
+ ],
268
+ packageManager: "pnpm",
269
+ managedPackages: GITZONE_PACKAGES,
270
+ });
271
+ return;
272
+ }
273
+ console.log("");
274
+ console.log("Usage: gitzone tools <command> [options]");
275
+ console.log("");
276
+ console.log("Commands:");
277
+ console.log(" update Check and update globally installed @git.zone packages");
278
+ console.log(" install Install missing managed @git.zone packages");
279
+ console.log("");
280
+ console.log("Options:");
281
+ console.log(" -y, --yes Run without confirmation prompts");
282
+ console.log(" -v, --verbose Show package manager diagnostics");
283
+ console.log("");
284
+ console.log("Examples:");
285
+ console.log(" gitzone tools update");
286
+ console.log(" gitzone tools update -y");
287
+ console.log(" gitzone tools install");
288
+ console.log("");
289
+ }
290
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi90cy9tb2RfdG9vbHMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxLQUFLLE9BQU8sTUFBTSxrQkFBa0IsQ0FBQztBQUM1QyxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sMEJBQTBCLENBQUM7QUFFdEQsT0FBTyxFQUFFLFVBQVUsRUFBRSxTQUFTLEVBQUUsTUFBTSx1QkFBdUIsQ0FBQztBQUM5RCxPQUFPLEVBQ0wsa0JBQWtCLEdBR25CLE1BQU0sNkJBQTZCLENBQUM7QUFFckMsTUFBTSxDQUFDLE1BQU0sZ0JBQWdCLEdBQUc7SUFDOUIsZUFBZTtJQUNmLGlCQUFpQjtJQUNqQixtQkFBbUI7SUFDbkIsa0JBQWtCO0lBQ2xCLHFCQUFxQjtJQUNyQixvQkFBb0I7SUFDcEIsb0JBQW9CO0lBQ3BCLGtCQUFrQjtJQUNsQixtQkFBbUI7SUFDbkIsa0JBQWtCO0NBQ25CLENBQUM7QUFFRixNQUFNLENBQUMsTUFBTSxHQUFHLEdBQUcsS0FBSyxFQUFFLFVBQWUsRUFBRSxFQUFpQixFQUFFO0lBQzVELE1BQU0sSUFBSSxHQUFHLE1BQU0sVUFBVSxDQUFDLE9BQU8sQ0FBQyxDQUFDO0lBQ3ZDLE1BQU0sT0FBTyxHQUFHLE9BQU8sQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsSUFBSSxNQUFNLENBQUM7SUFFekMsSUFBSSxJQUFJLENBQUMsSUFBSSxJQUFJLE9BQU8sS0FBSyxNQUFNLEVBQUUsQ0FBQztRQUNwQyxRQUFRLENBQUMsSUFBSSxDQUFDLENBQUM7UUFDZixPQUFPO0lBQ1QsQ0FBQztJQUVELFFBQVEsT0FBTyxFQUFFLENBQUM7UUFDaEIsS0FBSyxRQUFRO1lBQ1gsTUFBTSxTQUFTLENBQUMsT0FBTyxFQUFFLElBQUksQ0FBQyxDQUFDO1lBQy9CLE1BQU07UUFDUixLQUFLLFNBQVM7WUFDWixNQUFNLFVBQVUsQ0FBQyxPQUFPLEVBQUUsSUFBSSxDQUFDLENBQUM7WUFDaEMsTUFBTTtRQUNSO1lBQ0UsUUFBUSxDQUFDLElBQUksQ0FBQyxDQUFDO1lBQ2YsTUFBTTtJQUNWLENBQUM7QUFDSCxDQUFDLENBQUM7QUFFRixLQUFLLFVBQVUsU0FBUyxDQUFDLE9BQVksRUFBRSxJQUFjO0lBQ25ELE1BQU0sT0FBTyxHQUFHLE9BQU8sQ0FBQyxPQUFPLENBQUMsQ0FBQyxJQUFJLE9BQU8sQ0FBQyxPQUFPLENBQUMsQ0FBQztJQUN0RCxNQUFNLE1BQU0sR0FBRyxJQUFJLGtCQUFrQixFQUFFLENBQUM7SUFFeEMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxnREFBZ0QsQ0FBQyxDQUFDO0lBRTlELE1BQU0sUUFBUSxHQUFHLE1BQU0sTUFBTSxDQUFDLGtCQUFrQixFQUFFLENBQUM7SUFDbkQsSUFBSSxDQUFDLFFBQVEsQ0FBQyxTQUFTLEVBQUUsQ0FBQztRQUN4QixPQUFPLENBQUMsR0FBRyxDQUFDLGtFQUFrRSxDQUFDLENBQUM7UUFDaEYsT0FBTztJQUNULENBQUM7SUFFRCxPQUFPLENBQUMsR0FBRyxDQUFDLG9CQUFvQixDQUFDLENBQUM7SUFDbEMsT0FBTyxDQUFDLEdBQUcsQ0FBQywyQ0FBMkMsQ0FBQyxDQUFDO0lBQ3pELE9BQU8sQ0FBQyxHQUFHLENBQUMsa0RBQWtELENBQUMsQ0FBQztJQUNoRSxNQUFNLFVBQVUsR0FBRyxDQUFDLFFBQVEsQ0FBQyxhQUFhLElBQUksU0FBUyxDQUFDLENBQUMsTUFBTSxDQUFDLEVBQUUsQ0FBQyxDQUFDO0lBQ3BFLE1BQU0sVUFBVSxHQUFHLFFBQVEsQ0FBQyxhQUFhLEtBQUssSUFBSTtRQUNoRCxDQUFDLENBQUMsbUJBQW1CO1FBQ3JCLENBQUMsQ0FBQyxRQUFRLENBQUMsV0FBVztZQUNwQixDQUFDLENBQUMsa0JBQWtCO1lBQ3BCLENBQUMsQ0FBQyxZQUFZLENBQUM7SUFDbkIsT0FBTyxDQUFDLEdBQUcsQ0FBQyxLQUFLLE1BQU0sQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLEdBQUcsUUFBUSxDQUFDLGNBQWMsQ0FBQyxNQUFNLENBQUMsRUFBRSxDQUFDLEdBQUcsVUFBVSxHQUFHLFVBQVUsRUFBRSxDQUFDLENBQUM7SUFDcEcsT0FBTyxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsQ0FBQztJQUVoQixJQUFJLE9BQU8sRUFBRSxDQUFDO1FBQ1osT0FBTyxDQUFDLEdBQUcsQ0FBQyx1REFBdUQsQ0FBQyxDQUFDO0lBQ3ZFLENBQUM7SUFFRCxNQUFNLFdBQVcsR0FBRyxNQUFNLGdCQUFnQixDQUFDLE1BQU0sRUFBRSxJQUFJLENBQUMsQ0FBQztJQUN6RCxJQUFJLFdBQVcsRUFBRSxDQUFDO1FBQ2hCLE9BQU87SUFDVCxDQUFDO0lBRUQsTUFBTSxpQkFBaUIsR0FBRyxNQUFNLE1BQU0sQ0FBQyxvQkFBb0IsRUFBRSxDQUFDO0lBQzlELE1BQU0sWUFBWSxHQUFHLE1BQU0scUJBQXFCLENBQUMsTUFBTSxFQUFFLGlCQUFpQixDQUFDLENBQUM7SUFFNUUsSUFBSSxZQUFZLENBQUMsTUFBTSxLQUFLLENBQUMsRUFBRSxDQUFDO1FBQzlCLE9BQU8sQ0FBQyxHQUFHLENBQUMseURBQXlELENBQUMsQ0FBQztRQUN2RSxPQUFPO0lBQ1QsQ0FBQztJQUVELE9BQU8sQ0FBQyxHQUFHLENBQUMsaUNBQWlDLENBQUMsQ0FBQztJQUMvQyxPQUFPLENBQUMsR0FBRyxDQUFDLCtEQUErRCxDQUFDLENBQUM7SUFDN0UsT0FBTyxDQUFDLEdBQUcsQ0FBQyxnRUFBZ0UsQ0FBQyxDQUFDO0lBQzlFLEtBQUssTUFBTSxXQUFXLElBQUksWUFBWSxFQUFFLENBQUM7UUFDdkMsTUFBTSxNQUFNLEdBQUcsV0FBVyxDQUFDLGFBQWEsS0FBSyxTQUFTO1lBQ3BELENBQUMsQ0FBQyxtQkFBbUI7WUFDckIsQ0FBQyxDQUFDLFdBQVcsQ0FBQyxXQUFXO2dCQUN2QixDQUFDLENBQUMsa0JBQWtCO2dCQUNwQixDQUFDLENBQUMsWUFBWSxDQUFDO1FBQ25CLE9BQU8sQ0FBQyxHQUFHLENBQ1QsS0FBSyxXQUFXLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxFQUFFLENBQUMsR0FBRyxXQUFXLENBQUMsY0FBYyxDQUFDLE1BQU0sQ0FBQyxFQUFFLENBQUMsR0FBRyxXQUFXLENBQUMsYUFBYSxDQUFDLE1BQU0sQ0FBQyxFQUFFLENBQUMsR0FBRyxNQUFNLEVBQUUsQ0FDM0gsQ0FBQztJQUNKLENBQUM7SUFDRCxPQUFPLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxDQUFDO0lBRWhCLE1BQU0sb0JBQW9CLENBQUMsTUFBTSxFQUFFLGlCQUFpQixDQUFDLENBQUM7SUFFdEQsTUFBTSxnQkFBZ0IsR0FBRyxZQUFZLENBQUMsTUFBTSxDQUFDLENBQUMsV0FBVyxFQUFFLEVBQUUsQ0FBQyxXQUFXLENBQUMsV0FBVyxDQUFDLENBQUM7SUFDdkYsSUFBSSxnQkFBZ0IsQ0FBQyxNQUFNLEtBQUssQ0FBQyxFQUFFLENBQUM7UUFDbEMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxzQ0FBc0MsQ0FBQyxDQUFDO1FBQ3BELE9BQU87SUFDVCxDQUFDO0lBRUQsT0FBTyxDQUFDLEdBQUcsQ0FBQyxTQUFTLGdCQUFnQixDQUFDLE1BQU0sdUNBQXVDLENBQUMsQ0FBQztJQUVyRixJQUFJLENBQUMsSUFBSSxDQUFDLEdBQUcsSUFBSSxDQUFDLElBQUksQ0FBQyxXQUFXLEVBQUUsQ0FBQztRQUNuQyxPQUFPLENBQUMsR0FBRyxDQUFDLHdEQUF3RCxDQUFDLENBQUM7UUFDdEUsT0FBTztJQUNULENBQUM7SUFFRCxJQUFJLFlBQVksR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDO0lBQzVCLElBQUksQ0FBQyxZQUFZLEVBQUUsQ0FBQztRQUNsQixNQUFNLGdCQUFnQixHQUFHLElBQUksT0FBTyxDQUFDLGFBQWEsQ0FBQyxhQUFhLEVBQUUsQ0FBQztRQUNuRSxNQUFNLE1BQU0sR0FBRyxNQUFNLGdCQUFnQixDQUFDLFdBQVcsQ0FBQztZQUNoRCxJQUFJLEVBQUUsU0FBUztZQUNmLElBQUksRUFBRSxlQUFlO1lBQ3JCLE9BQU8sRUFBRSx1Q0FBdUM7WUFDaEQsT0FBTyxFQUFFLElBQUk7U0FDZCxDQUFDLENBQUM7UUFDSCxZQUFZLEdBQUcsTUFBTSxDQUFDLEtBQUssS0FBSyxJQUFJLENBQUM7SUFDdkMsQ0FBQztJQUVELElBQUksQ0FBQyxZQUFZLEVBQUUsQ0FBQztRQUNsQixPQUFPLENBQUMsR0FBRyxDQUFDLG1CQUFtQixDQUFDLENBQUM7UUFDakMsT0FBTztJQUNULENBQUM7SUFFRCxNQUFNLGVBQWUsQ0FBQyxNQUFNLEVBQUUsZ0JBQWdCLENBQUMsR0FBRyxDQUFDLENBQUMsV0FBVyxFQUFFLEVBQUUsQ0FBQyxXQUFXLENBQUMsSUFBSSxDQUFDLEVBQUUsU0FBUyxDQUFDLENBQUM7QUFDcEcsQ0FBQztBQUVELEtBQUssVUFBVSxVQUFVLENBQUMsT0FBWSxFQUFFLElBQWM7SUFDcEQsTUFBTSxPQUFPLEdBQUcsT0FBTyxDQUFDLE9BQU8sQ0FBQyxDQUFDLElBQUksT0FBTyxDQUFDLE9BQU8sQ0FBQyxDQUFDO0lBQ3RELE1BQU0sTUFBTSxHQUFHLElBQUksa0JBQWtCLEVBQUUsQ0FBQztJQUV4QyxPQUFPLENBQUMsR0FBRyxDQUFDLDhDQUE4QyxDQUFDLENBQUM7SUFFNUQsTUFBTSxhQUFhLEdBQUcsTUFBTSxNQUFNLENBQUMsVUFBVSxFQUFFLENBQUM7SUFDaEQsSUFBSSxDQUFDLGFBQWEsRUFBRSxDQUFDO1FBQ25CLE9BQU8sQ0FBQyxHQUFHLENBQUMsbUVBQW1FLENBQUMsQ0FBQztRQUNqRixPQUFPO0lBQ1QsQ0FBQztJQUVELElBQUksT0FBTyxFQUFFLENBQUM7UUFDWixPQUFPLENBQUMsR0FBRyxDQUFDLHVEQUF1RCxDQUFDLENBQUM7SUFDdkUsQ0FBQztJQUVELE1BQU0saUJBQWlCLEdBQUcsTUFBTSxNQUFNLENBQUMsb0JBQW9CLEVBQUUsQ0FBQztJQUM5RCxNQUFNLGNBQWMsR0FBRyxJQUFJLEdBQUcsQ0FBQyxpQkFBaUIsQ0FBQyxHQUFHLENBQUMsQ0FBQyxXQUFXLEVBQUUsRUFBRSxDQUFDLFdBQVcsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDO0lBQ3pGLE1BQU0sZUFBZSxHQUFHLGdCQUFnQixDQUFDLE1BQU0sQ0FBQyxDQUFDLFdBQVcsRUFBRSxFQUFFLENBQUMsQ0FBQyxjQUFjLENBQUMsR0FBRyxDQUFDLFdBQVcsQ0FBQyxDQUFDLENBQUM7SUFFbkcsSUFBSSxlQUFlLENBQUMsTUFBTSxLQUFLLENBQUMsRUFBRSxDQUFDO1FBQ2pDLE9BQU8sQ0FBQyxHQUFHLENBQUMsdURBQXVELENBQUMsQ0FBQztRQUNyRSxPQUFPO0lBQ1QsQ0FBQztJQUVELE9BQU8sQ0FBQyxHQUFHLENBQUMsU0FBUyxlQUFlLENBQUMsTUFBTSx3QkFBd0IsQ0FBQyxDQUFDO0lBRXJFLElBQUksQ0FBQyxJQUFJLENBQUMsR0FBRyxJQUFJLENBQUMsSUFBSSxDQUFDLFdBQVcsRUFBRSxDQUFDO1FBQ25DLE1BQU0sMEJBQTBCLENBQUMsTUFBTSxFQUFFLGVBQWUsQ0FBQyxDQUFDO1FBQzFELE9BQU8sQ0FBQyxHQUFHLENBQUMsK0VBQStFLENBQUMsQ0FBQztRQUM3RixPQUFPO0lBQ1QsQ0FBQztJQUVELElBQUksZ0JBQWdCLEdBQUcsZUFBZSxDQUFDO0lBQ3ZDLElBQUksQ0FBQyxJQUFJLENBQUMsR0FBRyxFQUFFLENBQUM7UUFDZCxNQUFNLG1CQUFtQixHQUEyQyxFQUFFLENBQUM7UUFDdkUsS0FBSyxNQUFNLFdBQVcsSUFBSSxlQUFlLEVBQUUsQ0FBQztZQUMxQyxNQUFNLE1BQU0sR0FBRyxNQUFNLE1BQU0sQ0FBQyxnQkFBZ0IsQ0FBQyxXQUFXLENBQUMsQ0FBQztZQUMxRCxtQkFBbUIsQ0FBQyxJQUFJLENBQUM7Z0JBQ3ZCLElBQUksRUFBRSxHQUFHLFdBQVcsR0FBRyxNQUFNLENBQUMsQ0FBQyxDQUFDLElBQUksTUFBTSxFQUFFLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBRTtnQkFDbkQsS0FBSyxFQUFFLFdBQVc7YUFDbkIsQ0FBQyxDQUFDO1FBQ0wsQ0FBQztRQUVELE1BQU0sZ0JBQWdCLEdBQUcsSUFBSSxPQUFPLENBQUMsYUFBYSxDQUFDLGFBQWEsRUFBRSxDQUFDO1FBQ25FLE1BQU0sTUFBTSxHQUFHLE1BQU0sZ0JBQWdCLENBQUMsV0FBVyxDQUFDO1lBQ2hELElBQUksRUFBRSxVQUFVO1lBQ2hCLElBQUksRUFBRSxVQUFVO1lBQ2hCLE9BQU8sRUFBRSw2QkFBNkI7WUFDdEMsT0FBTyxFQUFFLGVBQWU7WUFDeEIsT0FBTyxFQUFFLG1CQUFtQjtTQUM3QixDQUFDLENBQUM7UUFFSCxnQkFBZ0IsR0FBRyxNQUFNLENBQUMsS0FBaUIsQ0FBQztRQUM1QyxJQUFJLGdCQUFnQixDQUFDLE1BQU0sS0FBSyxDQUFDLEVBQUUsQ0FBQztZQUNsQyxPQUFPLENBQUMsR0FBRyxDQUFDLDJDQUEyQyxDQUFDLENBQUM7WUFDekQsT0FBTztRQUNULENBQUM7SUFDSCxDQUFDO0lBRUQsTUFBTSxlQUFlLENBQUMsTUFBTSxFQUFFLGdCQUFnQixFQUFFLFdBQVcsQ0FBQyxDQUFDO0FBQy9ELENBQUM7QUFFRCxLQUFLLFVBQVUsZ0JBQWdCLENBQzdCLE1BQTBCLEVBQzFCLElBQWM7SUFFZCxPQUFPLENBQUMsR0FBRyxDQUFDLHVDQUF1QyxDQUFDLENBQUM7SUFDckQsTUFBTSxjQUFjLEdBQUcsVUFBVSxDQUFDLE9BQU8sQ0FBQztJQUMxQyxNQUFNLGFBQWEsR0FBRyxNQUFNLE1BQU0sQ0FBQyxnQkFBZ0IsQ0FBQyxlQUFlLENBQUMsQ0FBQztJQUVyRSxJQUFJLENBQUMsYUFBYSxJQUFJLENBQUMsTUFBTSxDQUFDLGNBQWMsQ0FBQyxjQUFjLEVBQUUsYUFBYSxDQUFDLEVBQUUsQ0FBQztRQUM1RSxPQUFPLENBQUMsR0FBRyxDQUFDLG9CQUFvQixjQUFjLGdCQUFnQixDQUFDLENBQUM7UUFDaEUsT0FBTyxLQUFLLENBQUM7SUFDZixDQUFDO0lBRUQsT0FBTyxDQUFDLEdBQUcsQ0FBQyxvQkFBb0IsY0FBYyxPQUFPLGFBQWEsc0JBQXNCLENBQUMsQ0FBQztJQUUxRixJQUFJLENBQUMsSUFBSSxDQUFDLEdBQUcsSUFBSSxDQUFDLElBQUksQ0FBQyxXQUFXLEVBQUUsQ0FBQztRQUNuQyxPQUFPLENBQUMsR0FBRyxDQUFDLHNEQUFzRCxDQUFDLENBQUM7UUFDcEUsT0FBTyxJQUFJLENBQUM7SUFDZCxDQUFDO0lBRUQsSUFBSSxZQUFZLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQztJQUM1QixJQUFJLENBQUMsWUFBWSxFQUFFLENBQUM7UUFDbEIsTUFBTSxnQkFBZ0IsR0FBRyxJQUFJLE9BQU8sQ0FBQyxhQUFhLENBQUMsYUFBYSxFQUFFLENBQUM7UUFDbkUsTUFBTSxNQUFNLEdBQUcsTUFBTSxnQkFBZ0IsQ0FBQyxXQUFXLENBQUM7WUFDaEQsSUFBSSxFQUFFLFNBQVM7WUFDZixJQUFJLEVBQUUsbUJBQW1CO1lBQ3pCLE9BQU8sRUFBRSw2Q0FBNkM7WUFDdEQsT0FBTyxFQUFFLElBQUk7U0FDZCxDQUFDLENBQUM7UUFDSCxZQUFZLEdBQUcsTUFBTSxDQUFDLEtBQUssS0FBSyxJQUFJLENBQUM7SUFDdkMsQ0FBQztJQUVELElBQUksQ0FBQyxZQUFZLEVBQUUsQ0FBQztRQUNsQixPQUFPLENBQUMsR0FBRyxDQUFDLGlDQUFpQyxDQUFDLENBQUM7UUFDL0MsT0FBTyxLQUFLLENBQUM7SUFDZixDQUFDO0lBRUQsTUFBTSxPQUFPLEdBQUcsTUFBTSxNQUFNLENBQUMsYUFBYSxDQUFDLGVBQWUsQ0FBQyxDQUFDO0lBQzVELElBQUksQ0FBQyxPQUFPLEVBQUUsQ0FBQztRQUNiLE9BQU8sQ0FBQyxHQUFHLENBQUMsc0VBQXNFLENBQUMsQ0FBQztRQUNwRixPQUFPLEtBQUssQ0FBQztJQUNmLENBQUM7SUFFRCxPQUFPLENBQUMsR0FBRyxDQUFDLHNGQUFzRixDQUFDLENBQUM7SUFDcEcsT0FBTyxJQUFJLENBQUM7QUFDZCxDQUFDO0FBRUQsS0FBSyxVQUFVLHFCQUFxQixDQUNsQyxNQUEwQixFQUMxQixpQkFBc0M7SUFFdEMsTUFBTSxZQUFZLEdBQXlCLEVBQUUsQ0FBQztJQUM5QyxLQUFLLE1BQU0sZ0JBQWdCLElBQUksaUJBQWlCLEVBQUUsQ0FBQztRQUNqRCxJQUFJLENBQUMsZ0JBQWdCLENBQUMsUUFBUSxDQUFDLGdCQUFnQixDQUFDLElBQUksQ0FBQyxFQUFFLENBQUM7WUFDdEQsU0FBUztRQUNYLENBQUM7UUFDRCxNQUFNLGFBQWEsR0FBRyxNQUFNLE1BQU0sQ0FBQyxnQkFBZ0IsQ0FBQyxnQkFBZ0IsQ0FBQyxJQUFJLENBQUMsQ0FBQztRQUMzRSxZQUFZLENBQUMsSUFBSSxDQUFDO1lBQ2hCLElBQUksRUFBRSxnQkFBZ0IsQ0FBQyxJQUFJO1lBQzNCLGNBQWMsRUFBRSxnQkFBZ0IsQ0FBQyxPQUFPO1lBQ3hDLGFBQWEsRUFBRSxhQUFhLElBQUksU0FBUztZQUN6QyxXQUFXLEVBQUUsYUFBYTtnQkFDeEIsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxjQUFjLENBQUMsZ0JBQWdCLENBQUMsT0FBTyxFQUFFLGFBQWEsQ0FBQztnQkFDaEUsQ0FBQyxDQUFDLEtBQUs7U0FDVixDQUFDLENBQUM7SUFDTCxDQUFDO0lBQ0QsT0FBTyxZQUFZLENBQUM7QUFDdEIsQ0FBQztBQUVELEtBQUssVUFBVSxvQkFBb0IsQ0FDakMsTUFBMEIsRUFDMUIsaUJBQXNDO0lBRXRDLE1BQU0sY0FBYyxHQUFHLElBQUksR0FBRyxDQUFDLGlCQUFpQixDQUFDLEdBQUcsQ0FBQyxDQUFDLFdBQVcsRUFBRSxFQUFFLENBQUMsV0FBVyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUM7SUFDekYsTUFBTSxlQUFlLEdBQUcsZ0JBQWdCLENBQUMsTUFBTSxDQUFDLENBQUMsV0FBVyxFQUFFLEVBQUUsQ0FBQyxDQUFDLGNBQWMsQ0FBQyxHQUFHLENBQUMsV0FBVyxDQUFDLENBQUMsQ0FBQztJQUNuRyxJQUFJLGVBQWUsQ0FBQyxNQUFNLEtBQUssQ0FBQyxFQUFFLENBQUM7UUFDakMsT0FBTztJQUNULENBQUM7SUFFRCxPQUFPLENBQUMsR0FBRyxDQUFDLCtDQUErQyxDQUFDLENBQUM7SUFDN0QsTUFBTSwwQkFBMEIsQ0FBQyxNQUFNLEVBQUUsZUFBZSxDQUFDLENBQUM7SUFDMUQsT0FBTyxDQUFDLEdBQUcsQ0FBQywwREFBMEQsQ0FBQyxDQUFDO0FBQzFFLENBQUM7QUFFRCxLQUFLLFVBQVUsMEJBQTBCLENBQ3ZDLE1BQTBCLEVBQzFCLFlBQXNCO0lBRXRCLE9BQU8sQ0FBQyxHQUFHLENBQUMsdUNBQXVDLENBQUMsQ0FBQztJQUNyRCxPQUFPLENBQUMsR0FBRyxDQUFDLDRDQUE0QyxDQUFDLENBQUM7SUFDMUQsS0FBSyxNQUFNLFdBQVcsSUFBSSxZQUFZLEVBQUUsQ0FBQztRQUN2QyxNQUFNLE1BQU0sR0FBRyxNQUFNLE1BQU0sQ0FBQyxnQkFBZ0IsQ0FBQyxXQUFXLENBQUMsQ0FBQztRQUMxRCxPQUFPLENBQUMsR0FBRyxDQUFDLEtBQUssV0FBVyxDQUFDLE1BQU0sQ0FBQyxFQUFFLENBQUMsS0FBSyxNQUFNLElBQUksU0FBUyxFQUFFLENBQUMsQ0FBQztJQUNyRSxDQUFDO0lBQ0QsT0FBTyxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsQ0FBQztBQUNsQixDQUFDO0FBRUQsS0FBSyxVQUFVLGVBQWUsQ0FDNUIsTUFBMEIsRUFDMUIsWUFBc0IsRUFDdEIsTUFBK0I7SUFFL0IsSUFBSSxZQUFZLEdBQUcsQ0FBQyxDQUFDO0lBQ3JCLElBQUksU0FBUyxHQUFHLENBQUMsQ0FBQztJQUVsQixLQUFLLE1BQU0sV0FBVyxJQUFJLFlBQVksRUFBRSxDQUFDO1FBQ3ZDLE1BQU0sT0FBTyxHQUFHLE1BQU0sTUFBTSxDQUFDLGFBQWEsQ0FBQyxXQUFXLENBQUMsQ0FBQztRQUN4RCxJQUFJLE9BQU8sRUFBRSxDQUFDO1lBQ1osT0FBTyxDQUFDLEdBQUcsQ0FBQyxLQUFLLFdBQVcsSUFBSSxNQUFNLGVBQWUsQ0FBQyxDQUFDO1lBQ3ZELFlBQVksRUFBRSxDQUFDO1FBQ2pCLENBQUM7YUFBTSxDQUFDO1lBQ04sT0FBTyxDQUFDLEdBQUcsQ0FBQyxLQUFLLFdBQVcsU0FBUyxDQUFDLENBQUM7WUFDdkMsU0FBUyxFQUFFLENBQUM7UUFDZCxDQUFDO0lBQ0gsQ0FBQztJQUVELE9BQU8sQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLENBQUM7SUFDaEIsSUFBSSxTQUFTLEtBQUssQ0FBQyxFQUFFLENBQUM7UUFDcEIsT0FBTyxDQUFDLEdBQUcsQ0FBQyxPQUFPLFlBQVksZUFBZSxNQUFNLGdCQUFnQixDQUFDLENBQUM7SUFDeEUsQ0FBQztTQUFNLENBQUM7UUFDTixPQUFPLENBQUMsR0FBRyxDQUFDLEdBQUcsWUFBWSxlQUFlLE1BQU0sS0FBSyxTQUFTLFVBQVUsQ0FBQyxDQUFDO0lBQzVFLENBQUM7QUFDSCxDQUFDO0FBRUQsTUFBTSxVQUFVLFFBQVEsQ0FBQyxJQUFlO0lBQ3RDLElBQUksSUFBSSxFQUFFLElBQUksRUFBRSxDQUFDO1FBQ2YsU0FBUyxDQUFDO1lBQ1IsSUFBSSxFQUFFLGVBQWU7WUFDckIsS0FBSyxFQUFFLG1DQUFtQztZQUMxQyxRQUFRLEVBQUU7Z0JBQ1IsRUFBRSxJQUFJLEVBQUUsUUFBUSxFQUFFLFdBQVcsRUFBRSx3REFBd0QsRUFBRTtnQkFDekYsRUFBRSxJQUFJLEVBQUUsU0FBUyxFQUFFLFdBQVcsRUFBRSw0Q0FBNEMsRUFBRTthQUMvRTtZQUNELEtBQUssRUFBRTtnQkFDTCxFQUFFLElBQUksRUFBRSxXQUFXLEVBQUUsV0FBVyxFQUFFLGtDQUFrQyxFQUFFO2dCQUN0RSxFQUFFLElBQUksRUFBRSxlQUFlLEVBQUUsV0FBVyxFQUFFLGtDQUFrQyxFQUFFO2FBQzNFO1lBQ0QsY0FBYyxFQUFFLE1BQU07WUFDdEIsZUFBZSxFQUFFLGdCQUFnQjtTQUNsQyxDQUFDLENBQUM7UUFDSCxPQUFPO0lBQ1QsQ0FBQztJQUVELE9BQU8sQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLENBQUM7SUFDaEIsT0FBTyxDQUFDLEdBQUcsQ0FBQywwQ0FBMEMsQ0FBQyxDQUFDO0lBQ3hELE9BQU8sQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLENBQUM7SUFDaEIsT0FBTyxDQUFDLEdBQUcsQ0FBQyxXQUFXLENBQUMsQ0FBQztJQUN6QixPQUFPLENBQUMsR0FBRyxDQUFDLDZFQUE2RSxDQUFDLENBQUM7SUFDM0YsT0FBTyxDQUFDLEdBQUcsQ0FBQyxpRUFBaUUsQ0FBQyxDQUFDO0lBQy9FLE9BQU8sQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLENBQUM7SUFDaEIsT0FBTyxDQUFDLEdBQUcsQ0FBQyxVQUFVLENBQUMsQ0FBQztJQUN4QixPQUFPLENBQUMsR0FBRyxDQUFDLHVEQUF1RCxDQUFDLENBQUM7SUFDckUsT0FBTyxDQUFDLEdBQUcsQ0FBQyx1REFBdUQsQ0FBQyxDQUFDO0lBQ3JFLE9BQU8sQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLENBQUM7SUFDaEIsT0FBTyxDQUFDLEdBQUcsQ0FBQyxXQUFXLENBQUMsQ0FBQztJQUN6QixPQUFPLENBQUMsR0FBRyxDQUFDLHdCQUF3QixDQUFDLENBQUM7SUFDdEMsT0FBTyxDQUFDLEdBQUcsQ0FBQywyQkFBMkIsQ0FBQyxDQUFDO0lBQ3pDLE9BQU8sQ0FBQyxHQUFHLENBQUMseUJBQXlCLENBQUMsQ0FBQztJQUN2QyxPQUFPLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxDQUFDO0FBQ2xCLENBQUMifQ==
@@ -0,0 +1 @@
1
+ export * from "../plugins.js";
@@ -0,0 +1,2 @@
1
+ export * from "../plugins.js";
2
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibW9kLnBsdWdpbnMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi90cy9tb2RfdG9vbHMvbW9kLnBsdWdpbnMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsY0FBYyxlQUFlLENBQUMifQ==
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@git.zone/cli",
3
3
  "private": false,
4
- "version": "2.15.0",
4
+ "version": "2.16.1",
5
5
  "description": "A comprehensive CLI tool for enhancing and managing local development workflows with gitzone utilities, focusing on project setup, version control, code formatting, and template management.",
6
6
  "main": "dist_ts/index.js",
7
7
  "typings": "dist_ts/index.d.ts",
package/readme.md CHANGED
@@ -57,6 +57,7 @@ gitzone release
57
57
  | `format` | Plan or apply project formatting and standardization |
58
58
  | `config` | Inspect, update, and migrate `.smartconfig.json` |
59
59
  | `services` | Manage local MongoDB, MinIO, and Elasticsearch containers |
60
+ | `tools` | Manage the global `@git.zone` toolchain |
60
61
  | `template` | Scaffold projects from built-in templates |
61
62
  | `meta` | Manage multi-repository workspaces |
62
63
  | `open` | Open repository assets like CI pages |
@@ -67,6 +68,23 @@ gitzone release
67
68
 
68
69
  Global flags include `--help`, `--json`, `--plain`, `--agent`, `--no-interactive`, and `--no-check-updates`.
69
70
 
71
+ ## Toolchain Management
72
+
73
+ `gitzone tools` replaces the former `gtools` command from `@git.zone/tools`. It manages globally installed `@git.zone` development tools through pnpm.
74
+
75
+ ```bash
76
+ # Check installed @git.zone tools and update outdated packages
77
+ gitzone tools update
78
+
79
+ # Update without prompts
80
+ gitzone tools update -y
81
+
82
+ # Install missing managed @git.zone tools
83
+ gitzone tools install
84
+ ```
85
+
86
+ `gitzone tools update` checks `@git.zone/cli` first. If the CLI itself needs an update, it updates `@git.zone/cli` and asks you to rerun the command before updating the rest of the toolchain.
87
+
70
88
  ## Commit Workflow
71
89
 
72
90
  `gitzone commit` creates one semantic source commit. It does not bump versions, create tags, publish packages, or push Docker images.
@@ -3,6 +3,6 @@
3
3
  */
4
4
  export const commitinfo = {
5
5
  name: '@git.zone/cli',
6
- version: '2.15.0',
6
+ version: '2.16.1',
7
7
  description: 'A comprehensive CLI tool for enhancing and managing local development workflows with gitzone utilities, focusing on project setup, version control, code formatting, and template management.'
8
8
  }
package/ts/gitzone.cli.ts CHANGED
@@ -2,6 +2,7 @@ import * as plugins from "./plugins.js";
2
2
  import * as paths from "./paths.js";
3
3
  import { GitzoneConfig } from "./classes.gitzoneconfig.js";
4
4
  import { getRawCliMode } from "./helpers.climode.js";
5
+ import { commitinfo } from "./00_commitinfo_data.js";
5
6
 
6
7
  const gitzoneSmartcli = new plugins.smartcli.Smartcli();
7
8
 
@@ -11,20 +12,29 @@ export let run = async () => {
11
12
 
12
13
  // get packageInfo
13
14
  const projectInfo = new plugins.projectinfo.ProjectInfo(paths.packageDir);
15
+ const projectInfoVersion = (projectInfo.npm as any)?.version;
16
+ const packageVersion =
17
+ typeof projectInfoVersion === "string" && projectInfoVersion.length > 0
18
+ ? projectInfoVersion
19
+ : commitinfo.version;
14
20
 
15
21
  // check for updates
16
22
  if (rawCliMode.checkUpdates) {
17
23
  const smartupdateInstance = new plugins.smartupdate.SmartUpdate();
18
- await smartupdateInstance.check(
19
- "gitzone",
20
- projectInfo.npm.version,
21
- "http://gitzone.gitlab.io/gitzone/changelog.html",
22
- );
24
+ try {
25
+ await smartupdateInstance.check(
26
+ "gitzone",
27
+ packageVersion,
28
+ "http://gitzone.gitlab.io/gitzone/changelog.html",
29
+ );
30
+ } catch {
31
+ // Update checks must never block actual CLI commands.
32
+ }
23
33
  }
24
34
  if (rawCliMode.output === "human") {
25
35
  console.log("---------------------------------------------");
26
36
  }
27
- gitzoneSmartcli.addVersion(projectInfo.npm.version);
37
+ gitzoneSmartcli.addVersion(packageVersion);
28
38
 
29
39
  // ======> Standard task <======
30
40
 
@@ -137,6 +147,14 @@ export let run = async () => {
137
147
  modHelpers.run(argvArg);
138
148
  });
139
149
 
150
+ /**
151
+ * manage the global @git.zone toolchain
152
+ */
153
+ gitzoneSmartcli.addCommand("tools").subscribe(async (argvArg) => {
154
+ const modTools = await import("./mod_tools/index.js");
155
+ await modTools.run(argvArg);
156
+ });
157
+
140
158
  /**
141
159
  * manage release configuration
142
160
  */
@@ -23,6 +23,7 @@ const commandSummaries: ICommandHelpSummary[] = [
23
23
  { name: "format", description: "Plan or apply project formatting changes" },
24
24
  { name: "config", description: "Read and change .smartconfig.json settings" },
25
25
  { name: "services", description: "Manage or configure development services" },
26
+ { name: "tools", description: "Manage the global @git.zone toolchain" },
26
27
  { name: "template", description: "Create a project from a template" },
27
28
  { name: "open", description: "Open project assets and CI pages" },
28
29
  { name: "docker", description: "Run Docker-related maintenance tasks" },
@@ -75,6 +76,7 @@ export let run = async (argvArg: any = {}) => {
75
76
  { name: "Configure release settings", value: "config" },
76
77
  { name: "Create from template", value: "template" },
77
78
  { name: "Manage dev services (MongoDB, S3)", value: "services" },
79
+ { name: "Manage global @git.zone tools", value: "tools" },
78
80
  { name: "Open project assets", value: "open" },
79
81
  { name: "Show help", value: "help" },
80
82
  ],
@@ -113,6 +115,11 @@ export let run = async (argvArg: any = {}) => {
113
115
  await modServices.run({ _: ["services"] });
114
116
  break;
115
117
  }
118
+ case "tools": {
119
+ const modTools = await import("../mod_tools/index.js");
120
+ await modTools.run({ _: ["tools"] });
121
+ break;
122
+ }
116
123
  case "open": {
117
124
  const modOpen = await import("../mod_open/index.js");
118
125
  await modOpen.run({ _: ["open"] });
@@ -196,6 +203,7 @@ export async function showHelp(
196
203
  console.log(" gitzone release --plan");
197
204
  console.log(" gitzone format plan --json");
198
205
  console.log(" gitzone services set mongodb,minio");
206
+ console.log(" gitzone tools update");
199
207
  console.log("");
200
208
  console.log("Run gitzone <command> --help for command-specific usage.");
201
209
  console.log("");
@@ -231,6 +239,11 @@ async function showCommandHelp(
231
239
  modServices.showHelp(mode);
232
240
  return true;
233
241
  }
242
+ case "tools": {
243
+ const modTools = await import("../mod_tools/index.js");
244
+ modTools.showHelp(mode);
245
+ return true;
246
+ }
234
247
  default:
235
248
  return false;
236
249
  }
@@ -0,0 +1,176 @@
1
+ import * as plugins from "./mod.plugins.js";
2
+
3
+ export interface IInstalledPackage {
4
+ name: string;
5
+ version: string;
6
+ }
7
+
8
+ export interface IPackageUpdateInfo {
9
+ name: string;
10
+ currentVersion: string;
11
+ latestVersion: string;
12
+ needsUpdate: boolean;
13
+ }
14
+
15
+ export interface IPackageManagerInfo {
16
+ available: boolean;
17
+ currentVersion: string;
18
+ latestVersion: string | null;
19
+ needsUpdate: boolean;
20
+ }
21
+
22
+ export class PackageManagerUtil {
23
+ private shell = new plugins.smartshell.Smartshell({
24
+ executor: "bash",
25
+ });
26
+
27
+ public async detectPnpm(): Promise<boolean> {
28
+ try {
29
+ const result = await this.shell.execSilent("pnpm --version 2>/dev/null");
30
+ return result.exitCode === 0 && Boolean(result.stdout.trim());
31
+ } catch {
32
+ return false;
33
+ }
34
+ }
35
+
36
+ public async getPnpmVersionInfo(): Promise<IPackageManagerInfo> {
37
+ const available = await this.detectPnpm();
38
+ if (!available) {
39
+ return {
40
+ available: false,
41
+ currentVersion: "unknown",
42
+ latestVersion: null,
43
+ needsUpdate: false,
44
+ };
45
+ }
46
+
47
+ const currentVersion = await this.getCurrentPnpmVersion();
48
+ const latestVersion = await this.getLatestVersion("pnpm", ["https://registry.npmjs.org"]);
49
+
50
+ return {
51
+ available: true,
52
+ currentVersion,
53
+ latestVersion,
54
+ needsUpdate: latestVersion ? this.isNewerVersion(currentVersion, latestVersion) : false,
55
+ };
56
+ }
57
+
58
+ public async getInstalledPackages(): Promise<IInstalledPackage[]> {
59
+ const packages: IInstalledPackage[] = [];
60
+
61
+ try {
62
+ const result = await this.shell.execSilent("pnpm list -g --depth=0 --json 2>/dev/null || true");
63
+ const output = result.stdout.trim();
64
+ if (!output) {
65
+ return packages;
66
+ }
67
+
68
+ const data = JSON.parse(output);
69
+ const dataArray = Array.isArray(data) ? data : [data];
70
+ for (const item of dataArray) {
71
+ const dependencies = item.dependencies || {};
72
+ for (const [name, info] of Object.entries(dependencies)) {
73
+ if (!name.startsWith("@git.zone/")) {
74
+ continue;
75
+ }
76
+ packages.push({
77
+ name,
78
+ version: (info as any).version || "unknown",
79
+ });
80
+ }
81
+ }
82
+ } catch {
83
+ return packages;
84
+ }
85
+
86
+ return packages;
87
+ }
88
+
89
+ public async getLatestVersion(
90
+ packageName: string,
91
+ registries = ["https://verdaccio.lossless.digital", "https://registry.npmjs.org"],
92
+ ): Promise<string | null> {
93
+ for (const registry of registries) {
94
+ const latest = await this.getLatestVersionFromRegistry(registry, packageName);
95
+ if (latest) {
96
+ return latest;
97
+ }
98
+ }
99
+ return null;
100
+ }
101
+
102
+ public async installLatest(packageName: string): Promise<boolean> {
103
+ const packageSpecifier = `${packageName}@latest`;
104
+ console.log(` Installing ${packageSpecifier} via pnpm...`);
105
+
106
+ try {
107
+ const result = await this.shell.exec(`pnpm add -g ${shellQuote(packageSpecifier)}`);
108
+ return result.exitCode === 0;
109
+ } catch {
110
+ return false;
111
+ }
112
+ }
113
+
114
+ public isNewerVersion(current: string, latest: string): boolean {
115
+ const currentParts = normalizeSemver(current);
116
+ const latestParts = normalizeSemver(latest);
117
+
118
+ for (let i = 0; i < Math.max(currentParts.length, latestParts.length); i++) {
119
+ const currentPart = currentParts[i] || 0;
120
+ const latestPart = latestParts[i] || 0;
121
+ if (latestPart > currentPart) return true;
122
+ if (latestPart < currentPart) return false;
123
+ }
124
+
125
+ return false;
126
+ }
127
+
128
+ private async getCurrentPnpmVersion(): Promise<string> {
129
+ try {
130
+ const result = await this.shell.execSilent("pnpm --version 2>/dev/null");
131
+ const versionMatch = result.stdout.trim().match(/(\d+\.\d+\.\d+)/);
132
+ return versionMatch?.[1] || "unknown";
133
+ } catch {
134
+ return "unknown";
135
+ }
136
+ }
137
+
138
+ private async getLatestVersionFromRegistry(
139
+ registry: string,
140
+ packageName: string,
141
+ ): Promise<string | null> {
142
+ const encodedName = packageName.replace("/", "%2f");
143
+ const controller = new AbortController();
144
+ const timeout = setTimeout(() => controller.abort(), 8000);
145
+
146
+ try {
147
+ const response = await fetch(`${registry}/${encodedName}`, {
148
+ signal: controller.signal,
149
+ headers: {
150
+ accept: "application/json",
151
+ },
152
+ });
153
+ if (!response.ok) {
154
+ return null;
155
+ }
156
+ const data = await response.json();
157
+ const latest = (data as any)["dist-tags"]?.latest;
158
+ return typeof latest === "string" && latest.length > 0 ? latest : null;
159
+ } catch {
160
+ return null;
161
+ } finally {
162
+ clearTimeout(timeout);
163
+ }
164
+ }
165
+ }
166
+
167
+ function normalizeSemver(version: string): number[] {
168
+ return version
169
+ .replace(/^[^\d]*/, "")
170
+ .split(".")
171
+ .map((part) => parseInt(part, 10) || 0);
172
+ }
173
+
174
+ function shellQuote(value: string): string {
175
+ return `'${value.replaceAll("'", "'\\''")}'`;
176
+ }