@guidobuilds/forge-ai 0.3.0 → 0.5.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/CHANGELOG.md +47 -0
- package/README.md +119 -2
- package/artifacts/forge/forge.md +14 -1
- package/artifacts/forge-adversary/forge-adversary.md +122 -0
- package/artifacts/forge-grill/forge-grill.md +2 -1
- package/artifacts/forge-worker/forge-worker.md +109 -4
- package/artifacts/using-forge/using-forge.md +69 -2
- package/dist/src/adapters/grok-known.js +37 -0
- package/dist/src/adapters/grok.js +41 -0
- package/dist/src/cli.js +147 -91
- package/dist/src/model.js +1 -1
- package/dist/src/paths.js +4 -0
- package/dist/src/processor.js +13 -5
- package/dist/src/self-update.js +70 -0
- package/dist/src/version-check.js +75 -0
- package/package.json +1 -1
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { mkdir, readFile, writeFile } from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
const REGISTRY_URL = 'https://registry.npmjs.org/@guidobuilds/forge-ai/latest';
|
|
4
|
+
const DEFAULT_TTL_MS = 60 * 60 * 1000;
|
|
5
|
+
const DEFAULT_FETCH_TIMEOUT_MS = 1500;
|
|
6
|
+
export async function checkLatestVersion(options) {
|
|
7
|
+
const ttl = options.ttlMs ?? DEFAULT_TTL_MS;
|
|
8
|
+
const now = options.now ?? new Date();
|
|
9
|
+
const cached = await readCache(options.cachePath);
|
|
10
|
+
if (cached && now.getTime() - new Date(cached.checkedAt).getTime() < ttl) {
|
|
11
|
+
return makeResult(options.current, cached.latest);
|
|
12
|
+
}
|
|
13
|
+
const fetched = await fetchLatest(options.registryUrl ?? REGISTRY_URL, options.fetcher ?? fetch, options.timeoutMs ?? DEFAULT_FETCH_TIMEOUT_MS);
|
|
14
|
+
if (fetched === undefined)
|
|
15
|
+
return cached ? makeResult(options.current, cached.latest) : undefined;
|
|
16
|
+
await writeCache(options.cachePath, { checkedAt: now.toISOString(), latest: fetched });
|
|
17
|
+
return makeResult(options.current, fetched);
|
|
18
|
+
}
|
|
19
|
+
export function formatVersionNotice(result) {
|
|
20
|
+
if (!result.isOutdated)
|
|
21
|
+
return '';
|
|
22
|
+
return `forge-ai v${result.current} (v${result.latest} available — run \`forge-ai self-update\` to upgrade)`;
|
|
23
|
+
}
|
|
24
|
+
export function compareSemver(a, b) {
|
|
25
|
+
const pa = a.split('.').map((part) => parseInt(part, 10) || 0);
|
|
26
|
+
const pb = b.split('.').map((part) => parseInt(part, 10) || 0);
|
|
27
|
+
for (let index = 0; index < Math.max(pa.length, pb.length); index += 1) {
|
|
28
|
+
const diff = (pa[index] ?? 0) - (pb[index] ?? 0);
|
|
29
|
+
if (diff !== 0)
|
|
30
|
+
return diff;
|
|
31
|
+
}
|
|
32
|
+
return 0;
|
|
33
|
+
}
|
|
34
|
+
function makeResult(current, latest) {
|
|
35
|
+
return { current, latest, isOutdated: compareSemver(current, latest) < 0 };
|
|
36
|
+
}
|
|
37
|
+
async function fetchLatest(url, fetcher, timeoutMs) {
|
|
38
|
+
const controller = new AbortController();
|
|
39
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
40
|
+
try {
|
|
41
|
+
const response = await fetcher(url, { signal: controller.signal });
|
|
42
|
+
if (!response.ok)
|
|
43
|
+
return undefined;
|
|
44
|
+
const json = await response.json();
|
|
45
|
+
return typeof json.version === 'string' ? json.version : undefined;
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
return undefined;
|
|
49
|
+
}
|
|
50
|
+
finally {
|
|
51
|
+
clearTimeout(timer);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
async function readCache(cachePath) {
|
|
55
|
+
try {
|
|
56
|
+
const content = await readFile(cachePath, 'utf8');
|
|
57
|
+
const parsed = JSON.parse(content);
|
|
58
|
+
if (typeof parsed.checkedAt === 'string' && typeof parsed.latest === 'string') {
|
|
59
|
+
return { checkedAt: parsed.checkedAt, latest: parsed.latest };
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
catch {
|
|
63
|
+
// Cache missing or malformed; treat as no cache.
|
|
64
|
+
}
|
|
65
|
+
return undefined;
|
|
66
|
+
}
|
|
67
|
+
async function writeCache(cachePath, data) {
|
|
68
|
+
try {
|
|
69
|
+
await mkdir(path.dirname(cachePath), { recursive: true });
|
|
70
|
+
await writeFile(cachePath, `${JSON.stringify(data)}\n`, 'utf8');
|
|
71
|
+
}
|
|
72
|
+
catch {
|
|
73
|
+
// Cache write failures are non-fatal.
|
|
74
|
+
}
|
|
75
|
+
}
|