skillwiki 0.9.55 → 0.9.56

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.
@@ -1,19 +1,23 @@
1
1
  #!/usr/bin/env node
2
2
  #!/usr/bin/env node
3
3
  import {
4
+ cachePath,
4
5
  normalizeDistTag,
5
- semverGt
6
- } from "./chunk-E6UWZ3S3.js";
6
+ readCacheRaw,
7
+ resolveAutoApplyAt,
8
+ semverGt,
9
+ writeCache
10
+ } from "./chunk-7I2TPIV5.js";
7
11
 
8
12
  // src/auto-update-bg.ts
9
13
  import { execSync } from "child_process";
10
14
  import { writeFileSync, mkdirSync } from "fs";
11
- import { join, dirname } from "path";
15
+ import { dirname } from "path";
12
16
  var home = process.argv[2];
13
17
  var currentVersion = process.argv[3];
14
18
  var distTag = normalizeDistTag(process.argv[4]);
15
19
  if (!home || !currentVersion) process.exit(0);
16
- var cacheFile = join(home, ".skillwiki", ".update-cache.json");
20
+ var cacheFile = cachePath(home);
17
21
  setTimeout(() => process.exit(0), 3e4);
18
22
  try {
19
23
  const latest = execSync(`npm view skillwiki@${distTag} version`, {
@@ -21,25 +25,41 @@ try {
21
25
  timeout: 15e3
22
26
  }).trim();
23
27
  mkdirSync(dirname(cacheFile), { recursive: true });
28
+ const prior = readCacheRaw(home);
29
+ const { firstSeenAt, autoApplyAt } = resolveAutoApplyAt(prior, latest);
24
30
  const cache = {
25
31
  lastCheck: Date.now(),
26
32
  latestVersion: latest,
27
33
  currentVersion,
28
- distTag
34
+ distTag,
35
+ firstSeenAt,
36
+ autoApplyAt
29
37
  };
30
38
  if (semverGt(latest, currentVersion)) {
39
+ if (Date.now() < autoApplyAt) {
40
+ writeFileSync(cacheFile, JSON.stringify(cache, null, 2));
41
+ process.exit(0);
42
+ }
31
43
  execSync(`npm install -g skillwiki@${distTag}`, {
32
44
  stdio: "ignore",
33
45
  timeout: 6e4
34
46
  });
35
- writeFileSync(cacheFile, JSON.stringify({ ...cache, updateAppliedAt: Date.now() }, null, 2));
47
+ writeCache(home, { ...cache, updateAppliedAt: Date.now() });
36
48
  } else {
37
49
  writeFileSync(cacheFile, JSON.stringify(cache, null, 2));
38
50
  }
39
51
  } catch {
40
52
  try {
41
- mkdirSync(dirname(cacheFile), { recursive: true });
42
- writeFileSync(cacheFile, JSON.stringify({ lastCheck: Date.now(), latestVersion: "", currentVersion, distTag }, null, 2));
53
+ const prior = readCacheRaw(home);
54
+ const staleCache = {
55
+ lastCheck: Date.now(),
56
+ latestVersion: "",
57
+ currentVersion,
58
+ distTag,
59
+ ...prior?.firstSeenAt ? { firstSeenAt: prior.firstSeenAt } : {},
60
+ ...prior?.autoApplyAt ? { autoApplyAt: prior.autoApplyAt } : {}
61
+ };
62
+ writeCache(home, staleCache);
43
63
  } catch {
44
64
  }
45
65
  }
@@ -0,0 +1,154 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/utils/semver.ts
4
+ function semverGt(a, b) {
5
+ const pa = parseSemver(a);
6
+ const pb = parseSemver(b);
7
+ if (!pa || !pb) return a > b;
8
+ if (pa.major !== pb.major) return pa.major > pb.major;
9
+ if (pa.minor !== pb.minor) return pa.minor > pb.minor;
10
+ if (pa.patch !== pb.patch) return pa.patch > pb.patch;
11
+ if (!pa.pre && pb.pre) return true;
12
+ if (pa.pre && !pb.pre) return false;
13
+ if (!pa.pre && !pb.pre) return false;
14
+ const aParts = pa.pre.split(".");
15
+ const bParts = pb.pre.split(".");
16
+ const len = Math.max(aParts.length, bParts.length);
17
+ for (let i = 0; i < len; i++) {
18
+ const ai = aParts[i];
19
+ const bi = bParts[i];
20
+ if (ai === void 0) return false;
21
+ if (bi === void 0) return true;
22
+ const aNum = parseInt(ai, 10);
23
+ const bNum = parseInt(bi, 10);
24
+ if (!isNaN(aNum) && !isNaN(bNum)) {
25
+ if (aNum !== bNum) return aNum > bNum;
26
+ } else {
27
+ if (ai !== bi) return ai > bi;
28
+ }
29
+ }
30
+ return false;
31
+ }
32
+ function parseSemver(version) {
33
+ const match = version.match(/^(\d+)\.(\d+)\.(\d+)(?:-(.+))?$/);
34
+ if (!match) return null;
35
+ return {
36
+ major: parseInt(match[1], 10),
37
+ minor: parseInt(match[2], 10),
38
+ patch: parseInt(match[3], 10),
39
+ pre: match[4] ?? null
40
+ };
41
+ }
42
+
43
+ // src/utils/update-consts.ts
44
+ var DIST_TAG = "latest";
45
+ var CACHE_FILENAME = ".update-cache.json";
46
+ var CHECK_INTERVAL_MS = 24 * 60 * 60 * 1e3;
47
+ var AUTO_APPLY_DELAY_MS = 6 * 60 * 60 * 1e3;
48
+ var ENV_DISABLE_KEY = "NO_UPDATE_NOTIFIER";
49
+ var CLI_DISABLE_FLAG = "--no-update-notifier";
50
+ function normalizeDistTag(tag) {
51
+ const value = (tag ?? DIST_TAG).trim();
52
+ return /^[A-Za-z0-9._-]+$/.test(value) ? value : DIST_TAG;
53
+ }
54
+
55
+ // src/utils/auto-update.ts
56
+ import { readFileSync, writeFileSync, existsSync, mkdirSync } from "fs";
57
+ import { join, dirname } from "path";
58
+ import { spawn } from "child_process";
59
+ import { fileURLToPath } from "url";
60
+ function cachePath(home) {
61
+ return join(home, ".skillwiki", CACHE_FILENAME);
62
+ }
63
+ function readCacheRaw(home) {
64
+ try {
65
+ const raw = readFileSync(cachePath(home), "utf8");
66
+ return JSON.parse(raw);
67
+ } catch {
68
+ return null;
69
+ }
70
+ }
71
+ function readCache(home) {
72
+ const cache = readCacheRaw(home);
73
+ if (!cache) return { cache: null, hasUpdate: false, isStale: true };
74
+ const isStale = Date.now() - cache.lastCheck >= CHECK_INTERVAL_MS;
75
+ const hasUpdate = !!cache.latestVersion && semverGt(cache.latestVersion, cache.currentVersion);
76
+ return { cache, hasUpdate, isStale };
77
+ }
78
+ function writeCache(home, cache) {
79
+ const p = cachePath(home);
80
+ mkdirSync(dirname(p), { recursive: true });
81
+ writeFileSync(p, JSON.stringify(cache, null, 2));
82
+ }
83
+ function resolveAutoApplyAt(cache, latestVersion, now = Date.now()) {
84
+ if (cache && cache.firstSeenAt && cache.latestVersion === latestVersion && cache.autoApplyAt) {
85
+ return { firstSeenAt: cache.firstSeenAt, autoApplyAt: cache.autoApplyAt };
86
+ }
87
+ const firstSeenAt = now;
88
+ return { firstSeenAt, autoApplyAt: firstSeenAt + AUTO_APPLY_DELAY_MS };
89
+ }
90
+ function formatCountdown(autoApplyAt, now = Date.now()) {
91
+ if (!autoApplyAt) return null;
92
+ const remainingMs = autoApplyAt - now;
93
+ if (remainingMs <= 0) return null;
94
+ const totalMin = Math.ceil(remainingMs / 6e4);
95
+ const hours = Math.floor(totalMin / 60);
96
+ const mins = totalMin % 60;
97
+ return hours > 0 ? `${hours}h ${mins}m` : `${mins}m`;
98
+ }
99
+ function latestFromCache(home, currentVersion) {
100
+ const { cache } = readCache(home);
101
+ if (!cache || !cache.latestVersion) return { hasUpdate: false, latest: null, distTag: DIST_TAG };
102
+ const distTag = normalizeDistTag(cache.distTag);
103
+ return {
104
+ hasUpdate: semverGt(cache.latestVersion, currentVersion),
105
+ latest: cache.latestVersion,
106
+ distTag
107
+ };
108
+ }
109
+ function isDisabled() {
110
+ return !!(process.env[ENV_DISABLE_KEY] || process.env.NODE_ENV === "test" || process.argv.includes(CLI_DISABLE_FLAG));
111
+ }
112
+ function triggerAutoUpdate(home, currentVersion) {
113
+ if (isDisabled()) return;
114
+ const { cache, isStale } = readCache(home);
115
+ if (isStale) {
116
+ const distTag = normalizeDistTag(cache?.distTag);
117
+ const bgScript = fileURLToPath(new URL("./auto-update-bg.js", import.meta.url));
118
+ if (existsSync(bgScript)) {
119
+ const child = spawn(process.execPath, [bgScript, home, currentVersion, distTag], {
120
+ detached: true,
121
+ stdio: "ignore"
122
+ });
123
+ child.on("error", () => {
124
+ });
125
+ child.unref();
126
+ }
127
+ }
128
+ notifyPendingUpdate(cache, currentVersion);
129
+ }
130
+ function notifyPendingUpdate(cache, currentVersion) {
131
+ if (isDisabled()) return;
132
+ if (!cache || !cache.latestVersion) return;
133
+ if (!semverGt(cache.latestVersion, currentVersion)) return;
134
+ const { autoApplyAt } = resolveAutoApplyAt(cache, cache.latestVersion);
135
+ const remaining = formatCountdown(autoApplyAt);
136
+ if (remaining === null) return;
137
+ const distTag = normalizeDistTag(cache.distTag);
138
+ process.stderr.write(
139
+ `Update available: ${currentVersion} -> ${cache.latestVersion} (${distTag}). Auto-applying in ${remaining}. Run \`skillwiki update --tag ${distTag}\` now, or set NO_UPDATE_NOTIFIER=1 to opt out.
140
+ `
141
+ );
142
+ }
143
+
144
+ export {
145
+ semverGt,
146
+ normalizeDistTag,
147
+ cachePath,
148
+ readCacheRaw,
149
+ readCache,
150
+ writeCache,
151
+ resolveAutoApplyAt,
152
+ latestFromCache,
153
+ triggerAutoUpdate
154
+ };