@ruelya/grok-build 1.0.1 → 1.0.3-rev

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/README.md CHANGED
@@ -24,13 +24,12 @@ grok --version # expect …-rev (…) [stable]
24
24
  npx grok-build restore # restore previous binary from backup
25
25
  ```
26
26
 
27
- | Platform key | Binary path in package |
28
- |--------------|------------------------|
29
- | `win32-x64` | `artifacts/bin/win32-x64/grok.exe` |
30
- | `darwin-arm64` | `artifacts/bin/darwin-arm64/grok` |
31
- | `darwin-x64` | `artifacts/bin/darwin-x64/grok` |
32
- | `linux-x64` | `artifacts/bin/linux-x64/grok` |
33
- | `linux-arm64` | `artifacts/bin/linux-arm64/grok` |
27
+ | Platform key | Release asset |
28
+ |--------------|---------------|
29
+ | `win32-x64` | `grok-win32-x64.exe` |
30
+ | `linux-x64` | `grok-linux-x64` |
31
+ | `linux-arm64` | `grok-linux-arm64` |
32
+ | `darwin-arm64` | `grok-darwin-arm64` |
34
33
 
35
34
  ```bash
36
35
  bash scripts/stage-binaries.sh win32-x64 ./target/release/xai-grok-pager.exe
@@ -277,13 +276,12 @@ grok --version # 期望 …-rev (…) [stable]
277
276
  npx grok-build restore # 从备份恢复上一份二进制
278
277
  ```
279
278
 
280
- | 平台键 | 包内二进制路径 |
281
- |--------|----------------|
282
- | `win32-x64` | `artifacts/bin/win32-x64/grok.exe` |
283
- | `darwin-arm64` | `artifacts/bin/darwin-arm64/grok` |
284
- | `darwin-x64` | `artifacts/bin/darwin-x64/grok` |
285
- | `linux-x64` | `artifacts/bin/linux-x64/grok` |
286
- | `linux-arm64` | `artifacts/bin/linux-arm64/grok` |
279
+ | 平台键 | Release 资源 |
280
+ |--------|--------------|
281
+ | `win32-x64` | `grok-win32-x64.exe` |
282
+ | `linux-x64` | `grok-linux-x64` |
283
+ | `linux-arm64` | `grok-linux-arm64` |
284
+ | `darwin-arm64` | `grok-darwin-arm64` |
287
285
 
288
286
  ```bash
289
287
  bash scripts/stage-binaries.sh win32-x64 ./target/release/xai-grok-pager.exe
@@ -1,2 +1,2 @@
1
- version=1.0.1
2
- release=https://github.com/Ruelya/grok-build-rev/releases/download/v1.0.1
1
+ version=1.0.3-rev
2
+ release=https://github.com/Ruelya/grok-build-rev/releases/download/v1.0.3-rev
package/bin/cli.mjs CHANGED
@@ -197,65 +197,65 @@ function installThemes(home, { dryRun = false } = {}) {
197
197
  * Replaces a previous notes block if present; never changes non-comment settings.
198
198
  */
199
199
  /**
200
- * Ensure [cli].auto_update = false so official auto-update cannot overwrite the fork.
201
- * Idempotent: if already false, no rewrite; if true/missing under [cli], set false.
200
+ * Point [cli] auto_update at our npm package (not official x.ai CDN).
201
+ * Sets auto_update = true and installer = "npm".
202
202
  */
203
- function disableAutoUpdate(home, { dryRun = false } = {}) {
203
+ function configureForkUpdater(home, { dryRun = false } = {}) {
204
204
  const cfgPath = join(home, "config.toml");
205
+ const block =
206
+ `# Written by Grok Build fork install — updates via npm (@ruelya/grok-build).\n` +
207
+ `[cli]\nauto_update = true\ninstaller = "npm"\n`;
205
208
  if (!existsSync(cfgPath)) {
206
209
  if (dryRun) return { ok: true, action: "create-cli", path: cfgPath };
207
210
  mkdirSync(home, { recursive: true });
208
- writeFileSync(
209
- cfgPath,
210
- `# Written by Grok Build fork install — keep auto_update off so upstream cannot clobber the fork.\n[cli]\nauto_update = false\n`,
211
- "utf8"
212
- );
211
+ writeFileSync(cfgPath, block, "utf8");
213
212
  return { ok: true, action: "create-cli", path: cfgPath };
214
213
  }
215
214
  let raw = readFileSync(cfgPath, "utf8").replace(/\r\n/g, "\n");
215
+ let changed = false;
216
216
 
217
- // Already disabled somewhere (user may have multiple [cli] tables).
218
217
  if (/^\s*auto_update\s*=\s*false\s*$/m.test(raw)) {
219
- return { ok: true, action: "already-false", path: cfgPath };
218
+ raw = raw.replace(/^\s*auto_update\s*=\s*false\s*$/gm, "auto_update = true");
219
+ changed = true;
220
+ } else if (!/^\s*auto_update\s*=/m.test(raw)) {
221
+ const cliIdx = raw.search(/^\[cli\]\s*$/m);
222
+ if (cliIdx >= 0) {
223
+ const lineEnd = raw.indexOf("\n", cliIdx);
224
+ const insertAt = lineEnd === -1 ? raw.length : lineEnd + 1;
225
+ raw = raw.slice(0, insertAt) + "auto_update = true\n" + raw.slice(insertAt);
226
+ } else {
227
+ raw = raw.replace(/\s*$/, "\n\n") + "[cli]\nauto_update = true\n";
228
+ }
229
+ changed = true;
220
230
  }
221
231
 
222
- // Flip any true → false
223
- if (/^\s*auto_update\s*=\s*true\s*$/m.test(raw)) {
224
- const next = raw.replace(/^\s*auto_update\s*=\s*true\s*$/gm, "auto_update = false");
225
- if (dryRun) return { ok: true, action: "flip-true", path: cfgPath };
226
- try {
227
- copyFileSync(cfgPath, cfgPath + `.bak-auto-update-${stamp()}`);
228
- } catch {
229
- /* ignore */
232
+ if (/^\s*installer\s*=\s*".*"\s*$/m.test(raw)) {
233
+ const next = raw.replace(/^\s*installer\s*=\s*".*"\s*$/gm, 'installer = "npm"');
234
+ if (next !== raw) {
235
+ raw = next;
236
+ changed = true;
237
+ }
238
+ } else if (!/^\s*installer\s*=/m.test(raw)) {
239
+ const cliIdx = raw.search(/^\[cli\]\s*$/m);
240
+ if (cliIdx >= 0) {
241
+ const lineEnd = raw.indexOf("\n", cliIdx);
242
+ const insertAt = lineEnd === -1 ? raw.length : lineEnd + 1;
243
+ raw = raw.slice(0, insertAt) + 'installer = "npm"\n' + raw.slice(insertAt);
244
+ } else {
245
+ raw = raw.replace(/\s*$/, "\n\n") + '[cli]\ninstaller = "npm"\n';
230
246
  }
231
- writeFileSync(cfgPath, next, "utf8");
232
- return { ok: true, action: "flip-true", path: cfgPath };
247
+ changed = true;
233
248
  }
234
249
 
235
- // No auto_update key: append under first [cli] or create [cli]
236
- const cliIdx = raw.search(/^\[cli\]\s*$/m);
237
- let next;
238
- let action;
239
- if (cliIdx >= 0) {
240
- const lineEnd = raw.indexOf("\n", cliIdx);
241
- const insertAt = lineEnd === -1 ? raw.length : lineEnd + 1;
242
- next =
243
- raw.slice(0, insertAt) +
244
- "auto_update = false\n" +
245
- raw.slice(insertAt);
246
- action = "insert-cli";
247
- } else {
248
- next = raw.replace(/\s*$/, "\n\n") + "[cli]\nauto_update = false\n";
249
- action = "append-cli";
250
- }
251
- if (dryRun) return { ok: true, action, path: cfgPath };
250
+ if (!changed) return { ok: true, action: "already-fork-npm", path: cfgPath };
251
+ if (dryRun) return { ok: true, action: "update-cli", path: cfgPath };
252
252
  try {
253
253
  copyFileSync(cfgPath, cfgPath + `.bak-auto-update-${stamp()}`);
254
254
  } catch {
255
255
  /* ignore */
256
256
  }
257
- writeFileSync(cfgPath, next, "utf8");
258
- return { ok: true, action, path: cfgPath };
257
+ writeFileSync(cfgPath, raw, "utf8");
258
+ return { ok: true, action: "update-cli", path: cfgPath };
259
259
  }
260
260
 
261
261
  /**
@@ -435,7 +435,7 @@ function cmdInstallSideBySide({ dryRun = false, bootstrap = false } = {}) {
435
435
  }
436
436
  replaceBinary(fork, dest);
437
437
  const installedThemes = installThemes(home, { dryRun: false });
438
- const autoResult = disableAutoUpdate(home, { dryRun: false });
438
+ const autoResult = configureForkUpdater(home, { dryRun: false });
439
439
  const syncResult = installUsageSyncExample(home, { dryRun: false });
440
440
  console.log("\nInstalled fork side-by-side.");
441
441
  console.log(` run : ${dest}`);
@@ -513,7 +513,7 @@ function cmdApply({ dryRun = false } = {}) {
513
513
 
514
514
  const themeNames = installThemes(home, { dryRun: true });
515
515
  const cfgPlan = installConfigNotes(home, { dryRun: true });
516
- const autoPlan = disableAutoUpdate(home, { dryRun: true });
516
+ const autoPlan = configureForkUpdater(home, { dryRun: true });
517
517
  const syncPlan = installUsageSyncExample(home, { dryRun: true });
518
518
 
519
519
  console.log(`Installed : ${exe}`);
@@ -530,7 +530,7 @@ function cmdApply({ dryRun = false } = {}) {
530
530
  console.log(`Config : ${cfgPlan.path} (${cfgPlan.action} comment block)`);
531
531
  }
532
532
  if (autoPlan.ok) {
533
- console.log(`Auto-update: ${autoPlan.action} → [cli].auto_update = false`);
533
+ console.log(`Auto-update: ${autoPlan.action} → [cli].auto_update=true installer=npm (@ruelya/grok-build)`);
534
534
  }
535
535
  if (syncPlan.ok) {
536
536
  console.log(`Usage sync : ${syncPlan.action} → ${syncPlan.path}`);
@@ -538,7 +538,7 @@ function cmdApply({ dryRun = false } = {}) {
538
538
 
539
539
  if (dryRun) {
540
540
  console.log(
541
- "\n[dry-run] would backup stock, install fork as primary grok + themes + disable auto_update + seed usage sync.toml. No changes made."
541
+ "\n[dry-run] would backup stock, install fork as primary grok + themes + enable npm auto_update + seed usage sync.toml. No changes made."
542
542
  );
543
543
  return;
544
544
  }
@@ -570,7 +570,7 @@ function cmdApply({ dryRun = false } = {}) {
570
570
  replaceBinary(fork, exe);
571
571
  const installedThemes = installThemes(home, { dryRun: false });
572
572
  const cfgResult = installConfigNotes(home, { dryRun: false });
573
- const autoResult = disableAutoUpdate(home, { dryRun: false });
573
+ const autoResult = configureForkUpdater(home, { dryRun: false });
574
574
  const syncResult = installUsageSyncExample(home, { dryRun: false });
575
575
 
576
576
  const after = runExeVersion(exe);
@@ -602,7 +602,7 @@ function cmdApply({ dryRun = false } = {}) {
602
602
  console.log(` config : ${cfgResult.action} → ${cfgResult.path}`);
603
603
  }
604
604
  if (autoResult.ok) {
605
- console.log(` auto_update : ${autoResult.action} (disabled)`);
605
+ console.log(` auto_update : ${autoResult.action} (npm @ruelya/grok-build)`);
606
606
  }
607
607
  if (syncResult.ok) {
608
608
  console.log(` usage sync : ${syncResult.action} → ${syncResult.path}`);
package/bin/install.mjs CHANGED
@@ -73,10 +73,21 @@ function runVersion(exe) {
73
73
  shell: false,
74
74
  windowsHide: true,
75
75
  });
76
+ // SIGILL / crash → status null + signal; treat as unusable (e.g. neoverse-v2
77
+ // binary on Neoverse-N1 Ampere).
78
+ if (r.error || r.signal || (typeof r.status === "number" && r.status !== 0)) {
79
+ return null;
80
+ }
76
81
  const out = ((r.stdout || "") + (r.stderr || "")).trim();
77
82
  return out.split(/\r?\n/)[0] || null;
78
83
  }
79
84
 
85
+ /** True when an on-disk binary exists but cannot even print --version. */
86
+ function isBrokenBinary(exe) {
87
+ if (!existsSync(exe) || (fileSize(exe) || 0) < 1_000_000) return false;
88
+ return runVersion(exe) == null;
89
+ }
90
+
80
91
  function fileSize(p) {
81
92
  try {
82
93
  return statSync(p).size;
@@ -178,40 +189,70 @@ function installThemes(home, { dryRun = false } = {}) {
178
189
  return files.map((f) => f.replace(/\.toml$/, ""));
179
190
  }
180
191
 
181
- function disableAutoUpdate(home, { dryRun = false } = {}) {
192
+ /**
193
+ * Point in-app auto-update at our npm package (not official x.ai CDN).
194
+ *
195
+ * Writes:
196
+ * [cli]
197
+ * auto_update = true
198
+ * installer = "npm"
199
+ *
200
+ * The fork binary hard-blocks the official internal/CDN installer; this only
201
+ * ensures config matches so `grok update` uses `npm i -g @ruelya/grok-build`.
202
+ */
203
+ function configureForkUpdater(home, { dryRun = false } = {}) {
182
204
  const cfgPath = join(home, "config.toml");
205
+ const header =
206
+ "# Grok Build fork — auto_update via npm (@ruelya/grok-build), never official CDN.\n";
207
+ const block = `${header}[cli]\nauto_update = true\ninstaller = "npm"\n`;
208
+
183
209
  if (!existsSync(cfgPath)) {
184
210
  if (dryRun) return { ok: true, action: "create-cli" };
185
211
  mkdirSync(home, { recursive: true });
186
- writeFileSync(
187
- cfgPath,
188
- `# Grok Build fork — disable stock auto_update so it cannot overwrite the fork.\n[cli]\nauto_update = false\n`,
189
- "utf8"
190
- );
212
+ writeFileSync(cfgPath, block, "utf8");
191
213
  return { ok: true, action: "create-cli" };
192
214
  }
215
+
193
216
  let raw = readFileSync(cfgPath, "utf8").replace(/\r\n/g, "\n");
217
+ let changed = false;
218
+
194
219
  if (/^\s*auto_update\s*=\s*false\s*$/m.test(raw)) {
195
- return { ok: true, action: "already-false" };
196
- }
197
- if (/^\s*auto_update\s*=\s*true\s*$/m.test(raw)) {
198
- const next = raw.replace(/^\s*auto_update\s*=\s*true\s*$/gm, "auto_update = false");
199
- if (dryRun) return { ok: true, action: "flip-true" };
200
- writeFileSync(cfgPath, next, "utf8");
201
- return { ok: true, action: "flip-true" };
220
+ raw = raw.replace(/^\s*auto_update\s*=\s*false\s*$/gm, "auto_update = true");
221
+ changed = true;
222
+ } else if (!/^\s*auto_update\s*=/m.test(raw)) {
223
+ const cliIdx = raw.search(/^\[cli\]\s*$/m);
224
+ if (cliIdx >= 0) {
225
+ const lineEnd = raw.indexOf("\n", cliIdx);
226
+ const insertAt = lineEnd === -1 ? raw.length : lineEnd + 1;
227
+ raw = raw.slice(0, insertAt) + "auto_update = true\n" + raw.slice(insertAt);
228
+ } else {
229
+ raw = raw.replace(/\s*$/, "\n\n") + "[cli]\nauto_update = true\n";
230
+ }
231
+ changed = true;
202
232
  }
203
- const cliIdx = raw.search(/^\[cli\]\s*$/m);
204
- let next;
205
- if (cliIdx >= 0) {
206
- const lineEnd = raw.indexOf("\n", cliIdx);
207
- const insertAt = lineEnd === -1 ? raw.length : lineEnd + 1;
208
- next = raw.slice(0, insertAt) + "auto_update = false\n" + raw.slice(insertAt);
209
- } else {
210
- next = raw.replace(/\s*$/, "\n\n") + "[cli]\nauto_update = false\n";
233
+
234
+ if (/^\s*installer\s*=\s*".*"\s*$/m.test(raw)) {
235
+ const next = raw.replace(/^\s*installer\s*=\s*".*"\s*$/gm, 'installer = "npm"');
236
+ if (next !== raw) {
237
+ raw = next;
238
+ changed = true;
239
+ }
240
+ } else if (!/^\s*installer\s*=/m.test(raw)) {
241
+ const cliIdx = raw.search(/^\[cli\]\s*$/m);
242
+ if (cliIdx >= 0) {
243
+ const lineEnd = raw.indexOf("\n", cliIdx);
244
+ const insertAt = lineEnd === -1 ? raw.length : lineEnd + 1;
245
+ raw = raw.slice(0, insertAt) + 'installer = "npm"\n' + raw.slice(insertAt);
246
+ } else {
247
+ raw = raw.replace(/\s*$/, "\n\n") + '[cli]\ninstaller = "npm"\n';
248
+ }
249
+ changed = true;
211
250
  }
212
- if (dryRun) return { ok: true, action: "insert" };
213
- writeFileSync(cfgPath, next, "utf8");
214
- return { ok: true, action: "insert" };
251
+
252
+ if (!changed) return { ok: true, action: "already-fork-npm" };
253
+ if (dryRun) return { ok: true, action: "update-cli" };
254
+ writeFileSync(cfgPath, raw, "utf8");
255
+ return { ok: true, action: "update-cli" };
215
256
  }
216
257
 
217
258
  async function resolveSourceBinary() {
@@ -221,7 +262,7 @@ async function resolveSourceBinary() {
221
262
  [
222
263
  `Unsupported platform: ${t.key}`,
223
264
  ` shipped builds: ${supportedTargets().join(", ")}`,
224
- ` (Intel macOS / other arches are not published — use Apple Silicon, Linux x64, or Windows x64)`,
265
+ ` (Intel macOS is not published — use win32-x64, linux-x64, linux-arm64, or darwin-arm64)`,
225
266
  ``,
226
267
  `Override: GROK_FORK_BIN=/path/to/grok or GROK_FORK_RELEASE_BASE=https://…/releases/download/vX.Y.Z`,
227
268
  ].join("\n")
@@ -243,14 +284,31 @@ async function resolveSourceBinary() {
243
284
  );
244
285
  }
245
286
 
246
- const cacheDir = join(PKG_ROOT, "artifacts", "cache", t.key);
287
+ // Versioned cache so upgrading 1.0.2 → 1.0.3 never reuses a bad binary
288
+ // (e.g. neoverse-v2 SIGILL on Ampere Neoverse-N1).
289
+ const ver = String(pkg.version || "unknown").replace(/[^\w.-]+/g, "_");
290
+ const cacheDir = join(PKG_ROOT, "artifacts", "cache", ver, t.key);
247
291
  mkdirSync(cacheDir, { recursive: true });
248
292
  const dest = join(cacheDir, t.exeName);
249
- // Always re-download when missing; keep cache across reinstalls of same version.
250
- if (!existsSync(dest) || fileSize(dest) < 1_000_000) {
293
+ const needFetch =
294
+ !existsSync(dest) ||
295
+ (fileSize(dest) || 0) < 1_000_000 ||
296
+ isBrokenBinary(dest);
297
+ if (needFetch) {
251
298
  console.log(`Downloading ${url} …`);
252
299
  await download(url, dest);
253
300
  }
301
+ // Refuse to install a still-broken download (wrong arch / CPU baseline).
302
+ if (isBrokenBinary(dest)) {
303
+ throw new Error(
304
+ [
305
+ `Downloaded binary cannot run on this CPU (Illegal instruction / crash).`,
306
+ ` url: ${url}`,
307
+ ` tip: need a portable linux-arm64 build (target-cpu=generic, not neoverse-v2).`,
308
+ ` reinstall: npm i -g @ruelya/grok-build@latest && npx grok-build install`,
309
+ ].join("\n")
310
+ );
311
+ }
254
312
  return { path: dest, source: "download", url };
255
313
  }
256
314
 
@@ -310,8 +368,9 @@ async function cmdInstall({ dryRun = false } = {}) {
310
368
  }
311
369
 
312
370
  const installedThemes = installThemes(home, { dryRun: false });
313
- const auto = disableAutoUpdate(home, { dryRun: false });
371
+ const auto = configureForkUpdater(home, { dryRun: false });
314
372
  const after = runVersion(exe);
373
+ const packageVersion = loadPkg().version || null;
315
374
 
316
375
  const marker = {
317
376
  appliedAt: new Date().toISOString(),
@@ -328,12 +387,14 @@ async function cmdInstall({ dryRun = false } = {}) {
328
387
  themes: installedThemes,
329
388
  autoUpdate: auto,
330
389
  package: PKG_ROOT,
331
- packageVersion: loadPkg().version || null,
390
+ packageVersion,
391
+ npmPackage: "@ruelya/grok-build",
332
392
  };
333
393
  writeFileSync(join(home, MARKER), JSON.stringify(marker, null, 2) + "\n");
334
394
 
335
395
  console.log("\nInstalled Grok Build fork as primary client.");
336
396
  console.log(` after : ${after || "?"}`);
397
+ console.log(` pkg : @ruelya/grok-build@${packageVersion || "?"}`);
337
398
  console.log(` run : ${exe}`);
338
399
  console.log(` or : grok --version (if ~/.grok/bin is on PATH)`);
339
400
  if (installedThemes.length) {
@@ -343,7 +404,9 @@ async function cmdInstall({ dryRun = false } = {}) {
343
404
  } else {
344
405
  console.log(" themes : (none bundled — package missing artifacts/themes/*.toml)");
345
406
  }
346
- if (auto.ok) console.log(` auto_update: ${auto.action}`);
407
+ if (auto.ok) {
408
+ console.log(` update : npm installer (${auto.action}) — grok update → @ruelya/grok-build`);
409
+ }
347
410
  }
348
411
 
349
412
  function cmdRestore({ dryRun = false } = {}) {
package/bin/platform.mjs CHANGED
@@ -7,6 +7,7 @@
7
7
  * Release assets (v${version}):
8
8
  * grok-win32-x64.exe
9
9
  * grok-linux-x64
10
+ * grok-linux-arm64
10
11
  * grok-darwin-arm64
11
12
  *
12
13
  * Override: GROK_FORK_RELEASE_BASE, package.json forkReleaseBase, GROK_FORK_BIN
@@ -23,7 +24,12 @@ export const PKG_ROOT = resolve(__dirname, "..");
23
24
  const DEFAULT_REPO = "Ruelya/grok-build-rev";
24
25
 
25
26
  /** Platforms we ship (no Intel macOS). */
26
- export const SUPPORTED_TARGETS = ["win32-x64", "linux-x64", "darwin-arm64"];
27
+ export const SUPPORTED_TARGETS = [
28
+ "win32-x64",
29
+ "linux-x64",
30
+ "linux-arm64",
31
+ "darwin-arm64",
32
+ ];
27
33
 
28
34
  /** @returns {{ platform: string, arch: string, key: string, exeName: string }} */
29
35
  export function detectTarget() {
@@ -13,8 +13,9 @@ disabled_mcp_servers = []
13
13
  # [cli]
14
14
  # -----------------------------------------------------------------------------
15
15
  [cli]
16
- auto_update = false
17
- # installer = "npm" | "cargo" | …
16
+ # Fork: keep true + installer=npm so updates use @ruelya/grok-build (never x.ai CDN)
17
+ auto_update = true
18
+ # installer = "npm" | "gh-release" | "internal"(blocked on fork)
18
19
  installer = "npm"
19
20
  # npm_registry = "https://registry.npmjs.org"
20
21
  # channel = "alpha" | "stable"
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@ruelya/grok-build",
3
- "version": "1.0.1",
4
- "description": "Grok Build fork (rev). Thin npm installer downloads native binary from GitHub Releases.",
3
+ "version": "1.0.3-rev",
4
+ "description": "Grok Build fork. Product version tracks upstream (currently 1.0.3-rev). Thin installer downloads from GitHub Releases.",
5
5
  "type": "module",
6
6
  "bin": {
7
7
  "grok": "bin/grok.mjs",
@@ -48,5 +48,5 @@
48
48
  "access": "public",
49
49
  "registry": "https://registry.npmjs.org/"
50
50
  },
51
- "forkReleaseBase": "https://github.com/Ruelya/grok-build-rev/releases/download/v1.0.1"
51
+ "forkReleaseBase": "https://github.com/Ruelya/grok-build-rev/releases/download/v1.0.3-rev"
52
52
  }