@kyubiware/commit-mint 0.6.6 → 0.7.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/dist/cli.mjs CHANGED
@@ -3,7 +3,7 @@ import { cli, command } from "cleye";
3
3
  import Groq from "groq-sdk";
4
4
  import { appendFileSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
5
5
  import os from "node:os";
6
- import { extname, join } from "node:path";
6
+ import { dirname, extname, join } from "node:path";
7
7
  import { bold, cyan, dim, green, red, yellow } from "kolorist";
8
8
  import { access, constants, mkdir, readFile, writeFile } from "node:fs/promises";
9
9
  import { execa } from "execa";
@@ -13,6 +13,7 @@ import { createHash } from "node:crypto";
13
13
  import * as p from "@clack/prompts";
14
14
  import { intro, isCancel, log, outro, spinner } from "@clack/prompts";
15
15
  import { spawn } from "node:child_process";
16
+ import semver from "semver";
16
17
  //#region \0rolldown/runtime.js
17
18
  var __defProp = Object.defineProperty;
18
19
  var __exportAll = (all, no_symbols) => {
@@ -28,7 +29,7 @@ var __exportAll = (all, no_symbols) => {
28
29
  //#region package.json
29
30
  var package_default = {
30
31
  name: "@kyubiware/commit-mint",
31
- version: "0.6.6",
32
+ version: "0.7.0",
32
33
  description: "🌿 AI-powered git commit tool — auto-group changed files, generate messages, run pre-commit checks",
33
34
  type: "module",
34
35
  bin: { "cmint": "./dist/cli.mjs" },
@@ -74,11 +75,13 @@ var package_default = {
74
75
  "ini": "^5.0.0",
75
76
  "jiti": "^2.7.0",
76
77
  "kolorist": "^1.8.0",
77
- "picomatch": "^4.0.4"
78
+ "picomatch": "^4.0.4",
79
+ "semver": "^7.7.2"
78
80
  },
79
81
  devDependencies: {
80
82
  "@biomejs/biome": "^2.0.0",
81
83
  "@types/ini": "^4.1.1",
84
+ "@types/semver": "^7.7.1",
82
85
  "@vitest/coverage-v8": "^3.2.4",
83
86
  "tsdown": "^0.22.0",
84
87
  "tsx": "^4.22.2",
@@ -1385,7 +1388,7 @@ const CACHE_DIR = join(os.homedir(), ".cache", "commit-mint");
1385
1388
  function repoHash(repoPath) {
1386
1389
  return createHash("sha256").update(repoPath).digest("hex").slice(0, 12);
1387
1390
  }
1388
- function cachePath(repoPath) {
1391
+ function cachePath$1(repoPath) {
1389
1392
  return join(CACHE_DIR, `${repoHash(repoPath)}.json`);
1390
1393
  }
1391
1394
  async function saveCachedCommit(repoPath, message) {
@@ -1395,12 +1398,12 @@ async function saveCachedCommit(repoPath, message) {
1395
1398
  timestamp: Date.now(),
1396
1399
  repoPath
1397
1400
  };
1398
- const path = cachePath(repoPath);
1401
+ const path = cachePath$1(repoPath);
1399
1402
  debug("saveCachedCommit: saving to %s", path);
1400
1403
  await writeFile(path, JSON.stringify(data, null, 2), "utf8");
1401
1404
  }
1402
1405
  async function loadCachedCommit(repoPath) {
1403
- const path = cachePath(repoPath);
1406
+ const path = cachePath$1(repoPath);
1404
1407
  debug("loadCachedCommit: loading from %s", path);
1405
1408
  try {
1406
1409
  const raw = await readFile(path, "utf8");
@@ -3056,6 +3059,95 @@ async function logsCommand(flags) {
3056
3059
  for (const line of lines) console.log(line);
3057
3060
  }
3058
3061
  //#endregion
3062
+ //#region src/services/update-check.ts
3063
+ const REGISTRY_URL = "https://registry.npmjs.org/@kyubiware/commit-mint/latest";
3064
+ const PACKAGE_NAME = "@kyubiware/commit-mint";
3065
+ const TTL_MS = 1440 * 60 * 1e3;
3066
+ const FETCH_TIMEOUT_MS = 5e3;
3067
+ let cachePath = join(os.homedir(), ".cache", "commit-mint", "update-check.json");
3068
+ let fetchImpl = globalThis.fetch;
3069
+ /**
3070
+ * Returns true when the notifier must not run: env opt-out, CI, test env,
3071
+ * non-TTY stderr, or an invalid/missing current version.
3072
+ */
3073
+ function shouldSkip(currentVersion) {
3074
+ const noUpdate = process.env.NO_UPDATE_NOTIFIER;
3075
+ if (noUpdate !== void 0 && noUpdate !== "") return true;
3076
+ const ci = process.env.CI;
3077
+ if (ci !== void 0 && ci !== "" && ci !== "0") return true;
3078
+ if (process.env.NODE_ENV === "test") return true;
3079
+ if (process.stderr.isTTY !== true) return true;
3080
+ if (currentVersion === void 0) return true;
3081
+ if (currentVersion === "") return true;
3082
+ if (semver.valid(currentVersion) === null) return true;
3083
+ return false;
3084
+ }
3085
+ function loadCache() {
3086
+ try {
3087
+ const raw = readFileSync(cachePath, "utf8");
3088
+ const parsed = JSON.parse(raw);
3089
+ if (parsed !== null && typeof parsed === "object" && typeof parsed.latest === "string" && typeof parsed.checkedAt === "number") return Promise.resolve(parsed);
3090
+ return Promise.resolve(null);
3091
+ } catch {
3092
+ return Promise.resolve(null);
3093
+ }
3094
+ }
3095
+ function saveCache(entry) {
3096
+ try {
3097
+ mkdirSync(dirname(cachePath), { recursive: true });
3098
+ writeFileSync(cachePath, JSON.stringify(entry), "utf8");
3099
+ } catch {}
3100
+ return Promise.resolve();
3101
+ }
3102
+ async function fetchLatest() {
3103
+ try {
3104
+ const controller = new AbortController();
3105
+ const timer = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);
3106
+ try {
3107
+ const response = await fetchImpl(REGISTRY_URL, { signal: controller.signal });
3108
+ if (!response.ok) return null;
3109
+ const data = await response.json();
3110
+ if (typeof data.latest !== "string") return null;
3111
+ return data.latest;
3112
+ } finally {
3113
+ clearTimeout(timer);
3114
+ }
3115
+ } catch {
3116
+ return null;
3117
+ }
3118
+ }
3119
+ function displayNag(current, latest) {
3120
+ const message = `Update available: ${yellow(current)} → ${green(latest)}\nRun ${cyan(`npm update -g ${PACKAGE_NAME}`)} to update`;
3121
+ log.warn(message);
3122
+ }
3123
+ /**
3124
+ * Run the full update check. Exported for tests; the public surface is
3125
+ * {@link checkForUpdates}, which schedules this on `beforeExit`.
3126
+ */
3127
+ async function runUpdateCheck(currentVersion) {
3128
+ if (shouldSkip(currentVersion)) return;
3129
+ try {
3130
+ const cached = await loadCache();
3131
+ if (cached && Date.now() - cached.checkedAt < TTL_MS) {
3132
+ if (semver.gt(cached.latest, currentVersion)) displayNag(currentVersion, cached.latest);
3133
+ return;
3134
+ }
3135
+ const latest = await fetchLatest();
3136
+ if (latest === null) return;
3137
+ await saveCache({
3138
+ latest,
3139
+ checkedAt: Date.now()
3140
+ });
3141
+ if (semver.gt(latest, currentVersion)) displayNag(currentVersion, latest);
3142
+ } catch {}
3143
+ }
3144
+ /** Register the update check to run on `process.beforeExit`. */
3145
+ function checkForUpdates(currentVersion) {
3146
+ process.on("beforeExit", () => {
3147
+ runUpdateCheck(currentVersion);
3148
+ });
3149
+ }
3150
+ //#endregion
3059
3151
  //#region src/cli.ts
3060
3152
  const { version } = package_default;
3061
3153
  cli({
@@ -3120,7 +3212,10 @@ cli({
3120
3212
  writeSessionHeader();
3121
3213
  setDebug(argv.flags.debug);
3122
3214
  if (argv.flags.agent) agentCommand(argv.flags);
3123
- else commitCommand(argv.flags);
3215
+ else {
3216
+ checkForUpdates(version);
3217
+ commitCommand(argv.flags);
3218
+ }
3124
3219
  });
3125
3220
  //#endregion
3126
3221
  export {};