primitive-admin 1.0.21 → 1.0.23

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,169 @@
1
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
2
+ import { homedir } from "os";
3
+ import { join } from "path";
4
+ import chalk from "chalk";
5
+ const CONFIG_DIR = process.env.PRIMITIVE_CONFIG_DIR || join(homedir(), ".primitive");
6
+ const VERSION_CHECK_FILE = join(CONFIG_DIR, "version-check.json");
7
+ const CHECK_INTERVAL_MS = 24 * 60 * 60 * 1000; // 24 hours
8
+ const NPM_PACKAGE_NAME = "primitive-admin";
9
+ const FETCH_TIMEOUT_MS = 3000;
10
+ function ensureConfigDir() {
11
+ if (!existsSync(CONFIG_DIR)) {
12
+ mkdirSync(CONFIG_DIR, { recursive: true, mode: 0o700 });
13
+ }
14
+ }
15
+ function loadCache() {
16
+ try {
17
+ if (!existsSync(VERSION_CHECK_FILE))
18
+ return {};
19
+ return JSON.parse(readFileSync(VERSION_CHECK_FILE, "utf-8"));
20
+ }
21
+ catch {
22
+ return {};
23
+ }
24
+ }
25
+ function saveCache(cache) {
26
+ try {
27
+ ensureConfigDir();
28
+ writeFileSync(VERSION_CHECK_FILE, JSON.stringify(cache, null, 2));
29
+ }
30
+ catch {
31
+ // Ignore write errors
32
+ }
33
+ }
34
+ /**
35
+ * Extracts the prerelease channel from a version string.
36
+ * "1.0.23-alpha.3" → "alpha"
37
+ * "1.0.23-beta.1" → "beta"
38
+ * "1.0.23" → null
39
+ */
40
+ function getPrereleaseChannel(version) {
41
+ const match = version.match(/^[^-]+-([a-zA-Z]+)/);
42
+ return match ? match[1] : null;
43
+ }
44
+ /**
45
+ * Compares two semver version strings, including prerelease handling.
46
+ * Returns -1 if a < b, 0 if equal, 1 if a > b.
47
+ *
48
+ * Prerelease versions are only compared against their own channel.
49
+ * Within the same channel, prerelease segments are compared numerically.
50
+ */
51
+ function compareVersions(a, b) {
52
+ const clean = (v) => v.replace(/^v/, "");
53
+ const cleanA = clean(a);
54
+ const cleanB = clean(b);
55
+ // Split into core and prerelease
56
+ const [coreA, preA] = cleanA.split("-", 2);
57
+ const [coreB, preB] = cleanB.split("-", 2);
58
+ // Compare core version (major.minor.patch)
59
+ const partsA = coreA.split(".").map(Number);
60
+ const partsB = coreB.split(".").map(Number);
61
+ for (let i = 0; i < 3; i++) {
62
+ const ca = partsA[i] || 0;
63
+ const cb = partsB[i] || 0;
64
+ if (ca < cb)
65
+ return -1;
66
+ if (ca > cb)
67
+ return 1;
68
+ }
69
+ // Core versions are equal — compare prerelease
70
+ // No prerelease on either → equal
71
+ if (!preA && !preB)
72
+ return 0;
73
+ // A prerelease version is always less than the release version
74
+ if (preA && !preB)
75
+ return -1;
76
+ if (!preA && preB)
77
+ return 1;
78
+ // Both have prerelease — compare segments (e.g. "alpha.3" vs "alpha.5")
79
+ const segsA = preA.split(".");
80
+ const segsB = preB.split(".");
81
+ const len = Math.max(segsA.length, segsB.length);
82
+ for (let i = 0; i < len; i++) {
83
+ const sa = segsA[i];
84
+ const sb = segsB[i];
85
+ if (sa === undefined)
86
+ return -1;
87
+ if (sb === undefined)
88
+ return 1;
89
+ const na = Number(sa);
90
+ const nb = Number(sb);
91
+ const aIsNum = !isNaN(na);
92
+ const bIsNum = !isNaN(nb);
93
+ if (aIsNum && bIsNum) {
94
+ if (na < nb)
95
+ return -1;
96
+ if (na > nb)
97
+ return 1;
98
+ }
99
+ else {
100
+ // Lexicographic comparison for non-numeric segments
101
+ if (sa < sb)
102
+ return -1;
103
+ if (sa > sb)
104
+ return 1;
105
+ }
106
+ }
107
+ return 0;
108
+ }
109
+ async function fetchLatestVersion(distTag) {
110
+ try {
111
+ const controller = new AbortController();
112
+ const timeout = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);
113
+ const response = await fetch(`https://registry.npmjs.org/${NPM_PACKAGE_NAME}/${distTag}`, { signal: controller.signal });
114
+ clearTimeout(timeout);
115
+ if (!response.ok)
116
+ return null;
117
+ const data = await response.json();
118
+ return data.version;
119
+ }
120
+ catch {
121
+ return null;
122
+ }
123
+ }
124
+ /**
125
+ * Checks if a newer version of the CLI is available on npm.
126
+ *
127
+ * - Stable versions (e.g. "1.0.22") check the "latest" dist-tag
128
+ * - Prerelease versions (e.g. "1.0.23-alpha.3") check their channel's
129
+ * dist-tag (e.g. "alpha"), falling back to "latest" if that tag doesn't exist
130
+ *
131
+ * Caches results per dist-tag for 24 hours. Fails silently on any error.
132
+ */
133
+ export async function checkForUpdate(currentVersion) {
134
+ try {
135
+ const channel = getPrereleaseChannel(currentVersion);
136
+ const distTag = channel || "latest";
137
+ const cache = loadCache();
138
+ const now = Date.now();
139
+ let latestVersion = null;
140
+ const cached = cache[distTag];
141
+ if (cached && (now - cached.lastCheck) < CHECK_INTERVAL_MS) {
142
+ latestVersion = cached.latestVersion;
143
+ }
144
+ else {
145
+ latestVersion = await fetchLatestVersion(distTag);
146
+ // If the prerelease dist-tag doesn't exist on npm, fall back to "latest"
147
+ // so alpha users still hear about new stable releases
148
+ if (!latestVersion && channel) {
149
+ latestVersion = await fetchLatestVersion("latest");
150
+ }
151
+ if (latestVersion) {
152
+ cache[distTag] = { lastCheck: now, latestVersion };
153
+ saveCache(cache);
154
+ }
155
+ }
156
+ if (latestVersion && compareVersions(currentVersion, latestVersion) < 0) {
157
+ const installCmd = channel
158
+ ? `npm i -g ${NPM_PACKAGE_NAME}@${channel}`
159
+ : `npm i -g ${NPM_PACKAGE_NAME}`;
160
+ console.log();
161
+ console.log(chalk.yellow(`Update available: ${chalk.dim(currentVersion)} -> ${chalk.green.bold(latestVersion)}`));
162
+ console.log(chalk.yellow(`Run ${chalk.cyan.bold(installCmd)} to update`));
163
+ }
164
+ }
165
+ catch {
166
+ // Never let version check errors affect CLI operation
167
+ }
168
+ }
169
+ //# sourceMappingURL=version-check.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"version-check.js","sourceRoot":"","sources":["../../../src/lib/version-check.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,IAAI,CAAC;AACxE,OAAO,EAAE,OAAO,EAAE,MAAM,IAAI,CAAC;AAC7B,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,MAAM,UAAU,GAAG,OAAO,CAAC,GAAG,CAAC,oBAAoB,IAAI,IAAI,CAAC,OAAO,EAAE,EAAE,YAAY,CAAC,CAAC;AACrF,MAAM,kBAAkB,GAAG,IAAI,CAAC,UAAU,EAAE,oBAAoB,CAAC,CAAC;AAClE,MAAM,iBAAiB,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,WAAW;AAC1D,MAAM,gBAAgB,GAAG,iBAAiB,CAAC;AAC3C,MAAM,gBAAgB,GAAG,IAAI,CAAC;AAU9B,SAAS,eAAe;IACtB,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QAC5B,SAAS,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IAC1D,CAAC;AACH,CAAC;AAED,SAAS,SAAS;IAChB,IAAI,CAAC;QACH,IAAI,CAAC,UAAU,CAAC,kBAAkB,CAAC;YAAE,OAAO,EAAE,CAAC;QAC/C,OAAO,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,kBAAkB,EAAE,OAAO,CAAC,CAAC,CAAC;IAC/D,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED,SAAS,SAAS,CAAC,KAAwB;IACzC,IAAI,CAAC;QACH,eAAe,EAAE,CAAC;QAClB,aAAa,CAAC,kBAAkB,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;IACpE,CAAC;IAAC,MAAM,CAAC;QACP,sBAAsB;IACxB,CAAC;AACH,CAAC;AAED;;;;;GAKG;AACH,SAAS,oBAAoB,CAAC,OAAe;IAC3C,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,oBAAoB,CAAC,CAAC;IAClD,OAAO,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AACjC,CAAC;AAED;;;;;;GAMG;AACH,SAAS,eAAe,CAAC,CAAS,EAAE,CAAS;IAC3C,MAAM,KAAK,GAAG,CAAC,CAAS,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;IACjD,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;IACxB,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;IAExB,iCAAiC;IACjC,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,GAAG,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;IAC3C,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,GAAG,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;IAE3C,2CAA2C;IAC3C,MAAM,MAAM,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IAC5C,MAAM,MAAM,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IAE5C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;QAC3B,MAAM,EAAE,GAAG,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QAC1B,MAAM,EAAE,GAAG,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QAC1B,IAAI,EAAE,GAAG,EAAE;YAAE,OAAO,CAAC,CAAC,CAAC;QACvB,IAAI,EAAE,GAAG,EAAE;YAAE,OAAO,CAAC,CAAC;IACxB,CAAC;IAED,+CAA+C;IAC/C,kCAAkC;IAClC,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI;QAAE,OAAO,CAAC,CAAC;IAC7B,+DAA+D;IAC/D,IAAI,IAAI,IAAI,CAAC,IAAI;QAAE,OAAO,CAAC,CAAC,CAAC;IAC7B,IAAI,CAAC,IAAI,IAAI,IAAI;QAAE,OAAO,CAAC,CAAC;IAE5B,wEAAwE;IACxE,MAAM,KAAK,GAAG,IAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC/B,MAAM,KAAK,GAAG,IAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC/B,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IAEjD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC;QAC7B,MAAM,EAAE,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;QACpB,MAAM,EAAE,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;QACpB,IAAI,EAAE,KAAK,SAAS;YAAE,OAAO,CAAC,CAAC,CAAC;QAChC,IAAI,EAAE,KAAK,SAAS;YAAE,OAAO,CAAC,CAAC;QAE/B,MAAM,EAAE,GAAG,MAAM,CAAC,EAAE,CAAC,CAAC;QACtB,MAAM,EAAE,GAAG,MAAM,CAAC,EAAE,CAAC,CAAC;QACtB,MAAM,MAAM,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QAC1B,MAAM,MAAM,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QAE1B,IAAI,MAAM,IAAI,MAAM,EAAE,CAAC;YACrB,IAAI,EAAE,GAAG,EAAE;gBAAE,OAAO,CAAC,CAAC,CAAC;YACvB,IAAI,EAAE,GAAG,EAAE;gBAAE,OAAO,CAAC,CAAC;QACxB,CAAC;aAAM,CAAC;YACN,oDAAoD;YACpD,IAAI,EAAE,GAAG,EAAE;gBAAE,OAAO,CAAC,CAAC,CAAC;YACvB,IAAI,EAAE,GAAG,EAAE;gBAAE,OAAO,CAAC,CAAC;QACxB,CAAC;IACH,CAAC;IAED,OAAO,CAAC,CAAC;AACX,CAAC;AAED,KAAK,UAAU,kBAAkB,CAAC,OAAe;IAC/C,IAAI,CAAC;QACH,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;QACzC,MAAM,OAAO,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,EAAE,gBAAgB,CAAC,CAAC;QAEvE,MAAM,QAAQ,GAAG,MAAM,KAAK,CAC1B,8BAA8B,gBAAgB,IAAI,OAAO,EAAE,EAC3D,EAAE,MAAM,EAAE,UAAU,CAAC,MAAM,EAAE,CAC9B,CAAC;QACF,YAAY,CAAC,OAAO,CAAC,CAAC;QAEtB,IAAI,CAAC,QAAQ,CAAC,EAAE;YAAE,OAAO,IAAI,CAAC;QAC9B,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAyB,CAAC;QAC1D,OAAO,IAAI,CAAC,OAAO,CAAC;IACtB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,cAAsB;IACzD,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,oBAAoB,CAAC,cAAc,CAAC,CAAC;QACrD,MAAM,OAAO,GAAG,OAAO,IAAI,QAAQ,CAAC;QACpC,MAAM,KAAK,GAAG,SAAS,EAAE,CAAC;QAC1B,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAEvB,IAAI,aAAa,GAAkB,IAAI,CAAC;QACxC,MAAM,MAAM,GAAG,KAAK,CAAC,OAAO,CAAC,CAAC;QAE9B,IAAI,MAAM,IAAI,CAAC,GAAG,GAAG,MAAM,CAAC,SAAS,CAAC,GAAG,iBAAiB,EAAE,CAAC;YAC3D,aAAa,GAAG,MAAM,CAAC,aAAa,CAAC;QACvC,CAAC;aAAM,CAAC;YACN,aAAa,GAAG,MAAM,kBAAkB,CAAC,OAAO,CAAC,CAAC;YAElD,yEAAyE;YACzE,sDAAsD;YACtD,IAAI,CAAC,aAAa,IAAI,OAAO,EAAE,CAAC;gBAC9B,aAAa,GAAG,MAAM,kBAAkB,CAAC,QAAQ,CAAC,CAAC;YACrD,CAAC;YAED,IAAI,aAAa,EAAE,CAAC;gBAClB,KAAK,CAAC,OAAO,CAAC,GAAG,EAAE,SAAS,EAAE,GAAG,EAAE,aAAa,EAAE,CAAC;gBACnD,SAAS,CAAC,KAAK,CAAC,CAAC;YACnB,CAAC;QACH,CAAC;QAED,IAAI,aAAa,IAAI,eAAe,CAAC,cAAc,EAAE,aAAa,CAAC,GAAG,CAAC,EAAE,CAAC;YACxE,MAAM,UAAU,GAAG,OAAO;gBACxB,CAAC,CAAC,YAAY,gBAAgB,IAAI,OAAO,EAAE;gBAC3C,CAAC,CAAC,YAAY,gBAAgB,EAAE,CAAC;YAEnC,OAAO,CAAC,GAAG,EAAE,CAAC;YACd,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,qBAAqB,KAAK,CAAC,GAAG,CAAC,cAAc,CAAC,OAAO,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,aAAa,CAAC,EAAE,CAAC,CAAC,CAAC;YAClH,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC,CAAC;QAC5E,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,sDAAsD;IACxD,CAAC;AACH,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "primitive-admin",
3
- "version": "1.0.21",
3
+ "version": "1.0.23",
4
4
  "description": "CLI for administering Primitive applications",
5
5
  "type": "module",
6
6
  "bin": {
@@ -21,7 +21,8 @@
21
21
  "test:batch": "vitest run --config vitest.config.ts tests/integration/batch-tests.test.ts",
22
22
  "test:prompt-tests": "vitest run --config vitest.config.ts tests/integration/prompt-tests.test.ts",
23
23
  "test:workflow-tests": "vitest run --config vitest.config.ts tests/integration/workflow-tests.test.ts",
24
- "test:sync-test-cases": "vitest run --config vitest.config.ts tests/integration/sync-test-cases.test.ts"
24
+ "test:sync-test-cases": "vitest run --config vitest.config.ts tests/integration/sync-test-cases.test.ts",
25
+ "test:email-templates": "vitest run --config vitest.config.ts tests/integration/email-templates.test.ts"
25
26
  },
26
27
  "keywords": [
27
28
  "primitive",