@react-grab/cli 0.1.40 → 0.1.41
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.cjs +88 -32
- package/dist/cli.js +87 -31
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
- package/skills/react-grab/SKILL.md +8 -5
package/dist/cli.cjs
CHANGED
|
@@ -22,12 +22,12 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
22
22
|
}) : target, mod));
|
|
23
23
|
//#endregion
|
|
24
24
|
let commander = require("commander");
|
|
25
|
+
let node_path = require("node:path");
|
|
26
|
+
node_path = __toESM(node_path, 1);
|
|
25
27
|
let picocolors = require("picocolors");
|
|
26
28
|
picocolors = __toESM(picocolors, 1);
|
|
27
29
|
let node_fs = require("node:fs");
|
|
28
30
|
node_fs = __toESM(node_fs, 1);
|
|
29
|
-
let node_path = require("node:path");
|
|
30
|
-
node_path = __toESM(node_path, 1);
|
|
31
31
|
let package_manager_detector_detect = require("package-manager-detector/detect");
|
|
32
32
|
let ignore = require("ignore");
|
|
33
33
|
ignore = __toESM(ignore, 1);
|
|
@@ -450,8 +450,11 @@ const spinner = (text) => (0, ora.default)({ text });
|
|
|
450
450
|
const SKILL_NAME = "react-grab";
|
|
451
451
|
const SKILL_SOURCE = (0, node_url.fileURLToPath)(new URL("../skills/react-grab", require("url").pathToFileURL(__filename).href));
|
|
452
452
|
const agentLabel = (agent) => (0, agent_install_skill.getSkillAgentConfig)(agent).displayName;
|
|
453
|
-
const installedSkillDir = (agent) => (0, node_path.join)((0, agent_install_skill.isUniversalSkillAgent)(agent) ? (0, agent_install_skill.getCanonicalSkillsDir)(
|
|
454
|
-
|
|
453
|
+
const installedSkillDir = (agent, global, cwd) => (0, node_path.join)((0, agent_install_skill.isUniversalSkillAgent)(agent) ? (0, agent_install_skill.getCanonicalSkillsDir)(global, cwd) : (0, agent_install_skill.getSkillAgentDir)(agent, {
|
|
454
|
+
global,
|
|
455
|
+
cwd
|
|
456
|
+
}), SKILL_NAME);
|
|
457
|
+
const promptSkillInstall = async ({ yes = false, global = false, cwd = process.cwd() } = {}) => {
|
|
455
458
|
const detectedAgents = await detectAvailableAgents();
|
|
456
459
|
if (detectedAgents.length === 0) {
|
|
457
460
|
logger.warn("No supported agents detected.");
|
|
@@ -462,7 +465,7 @@ const promptSkillInstall = async ({ yes = false } = {}) => {
|
|
|
462
465
|
const { agents } = await prompts$1({
|
|
463
466
|
type: "multiselect",
|
|
464
467
|
name: "agents",
|
|
465
|
-
message:
|
|
468
|
+
message: `Install the React Grab skill (${global ? "global" : "this project"}) for:`,
|
|
466
469
|
choices: detectedAgents.map((agent) => ({
|
|
467
470
|
title: agentLabel(agent),
|
|
468
471
|
value: agent,
|
|
@@ -478,7 +481,8 @@ const promptSkillInstall = async ({ yes = false } = {}) => {
|
|
|
478
481
|
const { installed, failed } = await (0, agent_install_skill.add)({
|
|
479
482
|
source: SKILL_SOURCE,
|
|
480
483
|
agents: selectedAgents,
|
|
481
|
-
global
|
|
484
|
+
global,
|
|
485
|
+
cwd,
|
|
482
486
|
mode: "copy"
|
|
483
487
|
});
|
|
484
488
|
if (installed.length === 0) {
|
|
@@ -489,19 +493,27 @@ const promptSkillInstall = async ({ yes = false } = {}) => {
|
|
|
489
493
|
for (const record of failed) logger.log(` ${highlighter.error("✗")} ${agentLabel(record.agent)} ${record.error}`);
|
|
490
494
|
return true;
|
|
491
495
|
};
|
|
492
|
-
const removeSkill = async () => {
|
|
493
|
-
const
|
|
494
|
-
|
|
496
|
+
const removeSkill = async (cwd = process.cwd()) => {
|
|
497
|
+
const agents = await detectAvailableAgents();
|
|
498
|
+
const removedAgents = [];
|
|
499
|
+
const dirsToRemove = /* @__PURE__ */ new Set();
|
|
500
|
+
for (const agent of agents) {
|
|
501
|
+
const present = [installedSkillDir(agent, false, cwd), installedSkillDir(agent, true, cwd)].filter((dir) => (0, node_fs.existsSync)(dir));
|
|
502
|
+
if (present.length === 0) continue;
|
|
503
|
+
removedAgents.push(agent);
|
|
504
|
+
for (const dir of present) dirsToRemove.add(dir);
|
|
505
|
+
}
|
|
506
|
+
for (const skillDir of dirsToRemove) (0, node_fs.rmSync)(skillDir, {
|
|
495
507
|
recursive: true,
|
|
496
508
|
force: true
|
|
497
509
|
});
|
|
498
|
-
for (const agent of
|
|
499
|
-
return
|
|
510
|
+
for (const agent of removedAgents) logger.log(` ${highlighter.success("✓")} ${agentLabel(agent)}`);
|
|
511
|
+
return removedAgents.length;
|
|
500
512
|
};
|
|
501
513
|
//#endregion
|
|
502
514
|
//#region src/commands/add.ts
|
|
503
|
-
const VERSION$5 = "0.1.
|
|
504
|
-
const add = new commander.Command().name("add").alias("install").description("install the React Grab skill for your agent").option("-y, --yes", "skip confirmation prompts", false).option("-c, --cwd <cwd>", "working directory (defaults to current directory)", process.cwd()).action(async (opts) => {
|
|
515
|
+
const VERSION$5 = "0.1.41";
|
|
516
|
+
const add = new commander.Command().name("add").alias("install").description("install the React Grab skill for your agent").option("-y, --yes", "skip confirmation prompts", false).option("-c, --cwd <cwd>", "working directory (defaults to current directory)", process.cwd()).option("-g, --global", "install the skill globally instead of in the project", false).action(async (opts) => {
|
|
505
517
|
console.log(`${picocolors.default.magenta("✿")} ${picocolors.default.bold("React Grab")} ${picocolors.default.gray(VERSION$5)}`);
|
|
506
518
|
console.log();
|
|
507
519
|
try {
|
|
@@ -516,7 +528,11 @@ const add = new commander.Command().name("add").alias("install").description("in
|
|
|
516
528
|
}
|
|
517
529
|
preflightSpinner.succeed();
|
|
518
530
|
logger.break();
|
|
519
|
-
if (!await promptSkillInstall({
|
|
531
|
+
if (!await promptSkillInstall({
|
|
532
|
+
yes: isNonInteractive,
|
|
533
|
+
global: opts.global,
|
|
534
|
+
cwd: (0, node_path.resolve)(opts.cwd)
|
|
535
|
+
}) && isNonInteractive) {
|
|
520
536
|
logger.break();
|
|
521
537
|
process.exit(1);
|
|
522
538
|
}
|
|
@@ -1095,6 +1111,7 @@ const previewCdnTransform = (projectRoot, framework, nextRouterType, targetCdnDo
|
|
|
1095
1111
|
//#region src/utils/constants.ts
|
|
1096
1112
|
const MAX_KEY_HOLD_DURATION_MS = 2e3;
|
|
1097
1113
|
const DEFAULT_WATCH_DIR = ".react-grab";
|
|
1114
|
+
const MAX_GRAB_AGE_MS = 300 * 1e3;
|
|
1098
1115
|
//#endregion
|
|
1099
1116
|
//#region src/utils/format-activation-key.ts
|
|
1100
1117
|
const formatActivationKeyDisplay = (activationKey) => {
|
|
@@ -1112,7 +1129,7 @@ const formatActivationKeyDisplay = (activationKey) => {
|
|
|
1112
1129
|
};
|
|
1113
1130
|
//#endregion
|
|
1114
1131
|
//#region src/commands/configure.ts
|
|
1115
|
-
const VERSION$4 = "0.1.
|
|
1132
|
+
const VERSION$4 = "0.1.41";
|
|
1116
1133
|
const isMac = process.platform === "darwin";
|
|
1117
1134
|
const META_LABEL = isMac ? "Cmd" : "Win";
|
|
1118
1135
|
const ALT_LABEL = isMac ? "Option" : "Alt";
|
|
@@ -1731,7 +1748,7 @@ const installPackagesWithFeedback = async (packages, packageManager, projectRoot
|
|
|
1731
1748
|
};
|
|
1732
1749
|
//#endregion
|
|
1733
1750
|
//#region src/commands/init.ts
|
|
1734
|
-
const VERSION$3 = "0.1.
|
|
1751
|
+
const VERSION$3 = "0.1.41";
|
|
1735
1752
|
const REPORT_URL = "https://react-grab.com/api/report-cli";
|
|
1736
1753
|
const DOCS_URL = "https://github.com/aidenybai/react-grab";
|
|
1737
1754
|
const reportToCli = (type, config, error) => {
|
|
@@ -1798,7 +1815,7 @@ const failWithManualSetup = (failingSpinner, message, { listSupportedFrameworks
|
|
|
1798
1815
|
logger.break();
|
|
1799
1816
|
process.exit(1);
|
|
1800
1817
|
};
|
|
1801
|
-
const init = new commander.Command().name("init").alias("setup").description("initialize React Grab in your project").option("-y, --yes", "skip confirmation prompts", false).option("-f, --force", "force overwrite existing config", false).option("-k, --key <key>", "activation key (e.g., Meta+K, Ctrl+Shift+G, Space)").option("--skip-install", "skip package installation", false).option("--pkg <pkg>", "custom package URL for CLI (e.g., grab)").option("-c, --cwd <cwd>", "working directory (defaults to current directory)", process.cwd()).action(async (opts) => {
|
|
1818
|
+
const init = new commander.Command().name("init").alias("setup").description("initialize React Grab in your project").option("-y, --yes", "skip confirmation prompts", false).option("-f, --force", "force overwrite existing config", false).option("-k, --key <key>", "activation key (e.g., Meta+K, Ctrl+Shift+G, Space)").option("--skip-install", "skip package installation", false).option("--pkg <pkg>", "custom package URL for CLI (e.g., grab)").option("-c, --cwd <cwd>", "working directory (defaults to current directory)", process.cwd()).option("-g, --global", "install the skill globally instead of in the project", false).action(async (opts) => {
|
|
1802
1819
|
console.log(`${picocolors.default.magenta("✿")} ${picocolors.default.bold("React Grab")} ${picocolors.default.gray(VERSION$3)}`);
|
|
1803
1820
|
console.log();
|
|
1804
1821
|
try {
|
|
@@ -1956,7 +1973,11 @@ const init = new commander.Command().name("init").alias("setup").description("in
|
|
|
1956
1973
|
}
|
|
1957
1974
|
}
|
|
1958
1975
|
logger.break();
|
|
1959
|
-
await promptSkillInstall({
|
|
1976
|
+
await promptSkillInstall({
|
|
1977
|
+
yes: isNonInteractive,
|
|
1978
|
+
global: opts.global,
|
|
1979
|
+
cwd
|
|
1980
|
+
});
|
|
1960
1981
|
logger.break();
|
|
1961
1982
|
process.exit(0);
|
|
1962
1983
|
}
|
|
@@ -2022,7 +2043,11 @@ const init = new commander.Command().name("init").alias("setup").description("in
|
|
|
2022
2043
|
let didInstallSkill = false;
|
|
2023
2044
|
if (!isNonInteractive) {
|
|
2024
2045
|
logger.break();
|
|
2025
|
-
didInstallSkill = await promptSkillInstall({
|
|
2046
|
+
didInstallSkill = await promptSkillInstall({
|
|
2047
|
+
yes: isNonInteractive,
|
|
2048
|
+
global: opts.global,
|
|
2049
|
+
cwd
|
|
2050
|
+
});
|
|
2026
2051
|
}
|
|
2027
2052
|
const result = previewTransform(projectInfo.projectRoot, finalFramework, finalNextRouterType, false, opts.force);
|
|
2028
2053
|
if (!result.success) {
|
|
@@ -2417,18 +2442,48 @@ const readGrabCursor = (dir) => {
|
|
|
2417
2442
|
return 0;
|
|
2418
2443
|
}
|
|
2419
2444
|
};
|
|
2445
|
+
const grabReceivedAt = (line) => {
|
|
2446
|
+
try {
|
|
2447
|
+
const value = JSON.parse(line).receivedAt;
|
|
2448
|
+
return typeof value === "number" ? value : null;
|
|
2449
|
+
} catch {
|
|
2450
|
+
return null;
|
|
2451
|
+
}
|
|
2452
|
+
};
|
|
2420
2453
|
const consumeGrabs = (dir, options) => {
|
|
2421
2454
|
const lines = readCompleteGrabLines(dir);
|
|
2422
2455
|
if (options.all) return lines;
|
|
2456
|
+
const maxAgeMs = options.maxAgeMs ?? 0;
|
|
2423
2457
|
const cursor = readGrabCursor(dir);
|
|
2424
|
-
const
|
|
2425
|
-
const
|
|
2426
|
-
|
|
2427
|
-
|
|
2458
|
+
const total = lines.length;
|
|
2459
|
+
const now = Date.now();
|
|
2460
|
+
const fresh = [];
|
|
2461
|
+
let index = Math.min(cursor, total);
|
|
2462
|
+
while (index < total && (options.limit <= 0 || fresh.length < options.limit)) {
|
|
2463
|
+
const line = lines[index];
|
|
2464
|
+
index += 1;
|
|
2465
|
+
if (maxAgeMs > 0) {
|
|
2466
|
+
const receivedAt = grabReceivedAt(line);
|
|
2467
|
+
if (receivedAt !== null && now - receivedAt > maxAgeMs) continue;
|
|
2468
|
+
}
|
|
2469
|
+
fresh.push(line);
|
|
2470
|
+
}
|
|
2471
|
+
if (index !== cursor) node_fs.default.writeFileSync(cursorFilePath(dir), String(index));
|
|
2472
|
+
return fresh;
|
|
2428
2473
|
};
|
|
2429
2474
|
//#endregion
|
|
2430
2475
|
//#region src/commands/read.ts
|
|
2431
|
-
const
|
|
2476
|
+
const parseWaitMs = (raw) => {
|
|
2477
|
+
if (!raw) return 0;
|
|
2478
|
+
if (/^(inf|infinite|forever)$/i.test(raw.trim())) return Number.POSITIVE_INFINITY;
|
|
2479
|
+
const ms = Number(raw);
|
|
2480
|
+
return Number.isFinite(ms) && ms > 0 ? ms : 0;
|
|
2481
|
+
};
|
|
2482
|
+
const parseNonNegativeInt = (raw, fallback) => {
|
|
2483
|
+
const value = Number(raw);
|
|
2484
|
+
return Number.isInteger(value) && value >= 0 ? value : fallback;
|
|
2485
|
+
};
|
|
2486
|
+
const read = new commander.Command().name("read").description("print React Grab selections captured since the last read, then advance the cursor").option("-d, --dir <dir>", "work dir holding history.jsonl + cursor.txt", DEFAULT_WATCH_DIR).option("-w, --wait <ms>", "block up to <ms> (or 'infinite') for a new grab (default: no wait)").option("-n, --limit <count>", "max grabs to print per call (0 = no limit); the cursor only advances past what is printed", String(50)).option("--max-age <ms>", "skip grabs captured longer ago than <ms> (0 = never evict)", String(MAX_GRAB_AGE_MS)).option("--all", "print the entire history without advancing the cursor").action(async (options) => {
|
|
2432
2487
|
const dir = node_path.default.resolve(options.dir);
|
|
2433
2488
|
try {
|
|
2434
2489
|
prepareWorkDir(dir);
|
|
@@ -2437,19 +2492,20 @@ const read = new commander.Command().name("read").description("print React Grab
|
|
|
2437
2492
|
process.exit(1);
|
|
2438
2493
|
}
|
|
2439
2494
|
unrefStdin();
|
|
2440
|
-
const
|
|
2441
|
-
const
|
|
2495
|
+
const limit = parseNonNegativeInt(options.limit, 50);
|
|
2496
|
+
const maxAgeMs = parseNonNegativeInt(options.maxAge, MAX_GRAB_AGE_MS);
|
|
2442
2497
|
const all = Boolean(options.all);
|
|
2443
2498
|
const drain = () => {
|
|
2444
2499
|
const fresh = consumeGrabs(dir, {
|
|
2445
2500
|
limit,
|
|
2446
|
-
all
|
|
2501
|
+
all,
|
|
2502
|
+
maxAgeMs
|
|
2447
2503
|
});
|
|
2448
2504
|
if (fresh.length > 0) process.stdout.write(`${fresh.join("\n")}\n`);
|
|
2449
2505
|
return fresh.length;
|
|
2450
2506
|
};
|
|
2451
|
-
const
|
|
2452
|
-
const deadline =
|
|
2507
|
+
const waitMs = parseWaitMs(options.wait);
|
|
2508
|
+
const deadline = waitMs === Number.POSITIVE_INFINITY ? Number.POSITIVE_INFINITY : Date.now() + waitMs;
|
|
2453
2509
|
if (drain() > 0) process.exit(0);
|
|
2454
2510
|
while (Date.now() < deadline) {
|
|
2455
2511
|
await sleep(200);
|
|
@@ -2459,7 +2515,7 @@ const read = new commander.Command().name("read").description("print React Grab
|
|
|
2459
2515
|
});
|
|
2460
2516
|
//#endregion
|
|
2461
2517
|
//#region src/commands/remove.ts
|
|
2462
|
-
const VERSION$2 = "0.1.
|
|
2518
|
+
const VERSION$2 = "0.1.41";
|
|
2463
2519
|
const remove = new commander.Command().name("remove").description("uninstall the React Grab skill from your agent").action(async () => {
|
|
2464
2520
|
console.log(`${picocolors.default.magenta("✿")} ${picocolors.default.bold("React Grab")} ${picocolors.default.gray(VERSION$2)}`);
|
|
2465
2521
|
console.log();
|
|
@@ -2476,7 +2532,7 @@ const remove = new commander.Command().name("remove").description("uninstall the
|
|
|
2476
2532
|
});
|
|
2477
2533
|
//#endregion
|
|
2478
2534
|
//#region src/commands/upgrade.ts
|
|
2479
|
-
const VERSION$1 = "0.1.
|
|
2535
|
+
const VERSION$1 = "0.1.41";
|
|
2480
2536
|
const NPM_REGISTRY_URL = "https://registry.npmjs.org/react-grab/latest";
|
|
2481
2537
|
const fetchLatestVersion = async () => {
|
|
2482
2538
|
try {
|
|
@@ -2701,7 +2757,7 @@ const watch = new commander.Command().name("watch").description("start a backgro
|
|
|
2701
2757
|
});
|
|
2702
2758
|
//#endregion
|
|
2703
2759
|
//#region src/cli.ts
|
|
2704
|
-
const VERSION = "0.1.
|
|
2760
|
+
const VERSION = "0.1.41";
|
|
2705
2761
|
const VERSION_API_URL = "https://www.react-grab.com/api/version";
|
|
2706
2762
|
process.on("SIGINT", () => process.exit(0));
|
|
2707
2763
|
process.on("SIGTERM", () => process.exit(0));
|
package/dist/cli.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { Command } from "commander";
|
|
3
|
+
import path, { basename, delimiter, dirname, join, relative, resolve } from "node:path";
|
|
3
4
|
import pc from "picocolors";
|
|
4
5
|
import fs, { accessSync, constants, existsSync, readFileSync, readdirSync, rmSync, statSync, writeFileSync } from "node:fs";
|
|
5
|
-
import path, { basename, delimiter, dirname, join, relative, resolve } from "node:path";
|
|
6
6
|
import { detect } from "package-manager-detector/detect";
|
|
7
7
|
import ignore from "ignore";
|
|
8
8
|
import { fileURLToPath } from "node:url";
|
|
@@ -422,8 +422,11 @@ const spinner = (text) => ora({ text });
|
|
|
422
422
|
const SKILL_NAME = "react-grab";
|
|
423
423
|
const SKILL_SOURCE = fileURLToPath(new URL("../skills/react-grab", import.meta.url));
|
|
424
424
|
const agentLabel = (agent) => getSkillAgentConfig(agent).displayName;
|
|
425
|
-
const installedSkillDir = (agent) => join(isUniversalSkillAgent(agent) ? getCanonicalSkillsDir(
|
|
426
|
-
|
|
425
|
+
const installedSkillDir = (agent, global, cwd) => join(isUniversalSkillAgent(agent) ? getCanonicalSkillsDir(global, cwd) : getSkillAgentDir(agent, {
|
|
426
|
+
global,
|
|
427
|
+
cwd
|
|
428
|
+
}), SKILL_NAME);
|
|
429
|
+
const promptSkillInstall = async ({ yes = false, global = false, cwd = process.cwd() } = {}) => {
|
|
427
430
|
const detectedAgents = await detectAvailableAgents();
|
|
428
431
|
if (detectedAgents.length === 0) {
|
|
429
432
|
logger.warn("No supported agents detected.");
|
|
@@ -434,7 +437,7 @@ const promptSkillInstall = async ({ yes = false } = {}) => {
|
|
|
434
437
|
const { agents } = await prompts({
|
|
435
438
|
type: "multiselect",
|
|
436
439
|
name: "agents",
|
|
437
|
-
message:
|
|
440
|
+
message: `Install the React Grab skill (${global ? "global" : "this project"}) for:`,
|
|
438
441
|
choices: detectedAgents.map((agent) => ({
|
|
439
442
|
title: agentLabel(agent),
|
|
440
443
|
value: agent,
|
|
@@ -450,7 +453,8 @@ const promptSkillInstall = async ({ yes = false } = {}) => {
|
|
|
450
453
|
const { installed, failed } = await add({
|
|
451
454
|
source: SKILL_SOURCE,
|
|
452
455
|
agents: selectedAgents,
|
|
453
|
-
global
|
|
456
|
+
global,
|
|
457
|
+
cwd,
|
|
454
458
|
mode: "copy"
|
|
455
459
|
});
|
|
456
460
|
if (installed.length === 0) {
|
|
@@ -461,19 +465,27 @@ const promptSkillInstall = async ({ yes = false } = {}) => {
|
|
|
461
465
|
for (const record of failed) logger.log(` ${highlighter.error("✗")} ${agentLabel(record.agent)} ${record.error}`);
|
|
462
466
|
return true;
|
|
463
467
|
};
|
|
464
|
-
const removeSkill = async () => {
|
|
465
|
-
const
|
|
466
|
-
|
|
468
|
+
const removeSkill = async (cwd = process.cwd()) => {
|
|
469
|
+
const agents = await detectAvailableAgents();
|
|
470
|
+
const removedAgents = [];
|
|
471
|
+
const dirsToRemove = /* @__PURE__ */ new Set();
|
|
472
|
+
for (const agent of agents) {
|
|
473
|
+
const present = [installedSkillDir(agent, false, cwd), installedSkillDir(agent, true, cwd)].filter((dir) => existsSync(dir));
|
|
474
|
+
if (present.length === 0) continue;
|
|
475
|
+
removedAgents.push(agent);
|
|
476
|
+
for (const dir of present) dirsToRemove.add(dir);
|
|
477
|
+
}
|
|
478
|
+
for (const skillDir of dirsToRemove) rmSync(skillDir, {
|
|
467
479
|
recursive: true,
|
|
468
480
|
force: true
|
|
469
481
|
});
|
|
470
|
-
for (const agent of
|
|
471
|
-
return
|
|
482
|
+
for (const agent of removedAgents) logger.log(` ${highlighter.success("✓")} ${agentLabel(agent)}`);
|
|
483
|
+
return removedAgents.length;
|
|
472
484
|
};
|
|
473
485
|
//#endregion
|
|
474
486
|
//#region src/commands/add.ts
|
|
475
|
-
const VERSION$5 = "0.1.
|
|
476
|
-
const add$1 = new Command().name("add").alias("install").description("install the React Grab skill for your agent").option("-y, --yes", "skip confirmation prompts", false).option("-c, --cwd <cwd>", "working directory (defaults to current directory)", process.cwd()).action(async (opts) => {
|
|
487
|
+
const VERSION$5 = "0.1.41";
|
|
488
|
+
const add$1 = new Command().name("add").alias("install").description("install the React Grab skill for your agent").option("-y, --yes", "skip confirmation prompts", false).option("-c, --cwd <cwd>", "working directory (defaults to current directory)", process.cwd()).option("-g, --global", "install the skill globally instead of in the project", false).action(async (opts) => {
|
|
477
489
|
console.log(`${pc.magenta("✿")} ${pc.bold("React Grab")} ${pc.gray(VERSION$5)}`);
|
|
478
490
|
console.log();
|
|
479
491
|
try {
|
|
@@ -488,7 +500,11 @@ const add$1 = new Command().name("add").alias("install").description("install th
|
|
|
488
500
|
}
|
|
489
501
|
preflightSpinner.succeed();
|
|
490
502
|
logger.break();
|
|
491
|
-
if (!await promptSkillInstall({
|
|
503
|
+
if (!await promptSkillInstall({
|
|
504
|
+
yes: isNonInteractive,
|
|
505
|
+
global: opts.global,
|
|
506
|
+
cwd: resolve(opts.cwd)
|
|
507
|
+
}) && isNonInteractive) {
|
|
492
508
|
logger.break();
|
|
493
509
|
process.exit(1);
|
|
494
510
|
}
|
|
@@ -1067,6 +1083,7 @@ const previewCdnTransform = (projectRoot, framework, nextRouterType, targetCdnDo
|
|
|
1067
1083
|
//#region src/utils/constants.ts
|
|
1068
1084
|
const MAX_KEY_HOLD_DURATION_MS = 2e3;
|
|
1069
1085
|
const DEFAULT_WATCH_DIR = ".react-grab";
|
|
1086
|
+
const MAX_GRAB_AGE_MS = 300 * 1e3;
|
|
1070
1087
|
//#endregion
|
|
1071
1088
|
//#region src/utils/format-activation-key.ts
|
|
1072
1089
|
const formatActivationKeyDisplay = (activationKey) => {
|
|
@@ -1084,7 +1101,7 @@ const formatActivationKeyDisplay = (activationKey) => {
|
|
|
1084
1101
|
};
|
|
1085
1102
|
//#endregion
|
|
1086
1103
|
//#region src/commands/configure.ts
|
|
1087
|
-
const VERSION$4 = "0.1.
|
|
1104
|
+
const VERSION$4 = "0.1.41";
|
|
1088
1105
|
const isMac = process.platform === "darwin";
|
|
1089
1106
|
const META_LABEL = isMac ? "Cmd" : "Win";
|
|
1090
1107
|
const ALT_LABEL = isMac ? "Option" : "Alt";
|
|
@@ -1703,7 +1720,7 @@ const installPackagesWithFeedback = async (packages, packageManager, projectRoot
|
|
|
1703
1720
|
};
|
|
1704
1721
|
//#endregion
|
|
1705
1722
|
//#region src/commands/init.ts
|
|
1706
|
-
const VERSION$3 = "0.1.
|
|
1723
|
+
const VERSION$3 = "0.1.41";
|
|
1707
1724
|
const REPORT_URL = "https://react-grab.com/api/report-cli";
|
|
1708
1725
|
const DOCS_URL = "https://github.com/aidenybai/react-grab";
|
|
1709
1726
|
const reportToCli = (type, config, error) => {
|
|
@@ -1770,7 +1787,7 @@ const failWithManualSetup = (failingSpinner, message, { listSupportedFrameworks
|
|
|
1770
1787
|
logger.break();
|
|
1771
1788
|
process.exit(1);
|
|
1772
1789
|
};
|
|
1773
|
-
const init = new Command().name("init").alias("setup").description("initialize React Grab in your project").option("-y, --yes", "skip confirmation prompts", false).option("-f, --force", "force overwrite existing config", false).option("-k, --key <key>", "activation key (e.g., Meta+K, Ctrl+Shift+G, Space)").option("--skip-install", "skip package installation", false).option("--pkg <pkg>", "custom package URL for CLI (e.g., grab)").option("-c, --cwd <cwd>", "working directory (defaults to current directory)", process.cwd()).action(async (opts) => {
|
|
1790
|
+
const init = new Command().name("init").alias("setup").description("initialize React Grab in your project").option("-y, --yes", "skip confirmation prompts", false).option("-f, --force", "force overwrite existing config", false).option("-k, --key <key>", "activation key (e.g., Meta+K, Ctrl+Shift+G, Space)").option("--skip-install", "skip package installation", false).option("--pkg <pkg>", "custom package URL for CLI (e.g., grab)").option("-c, --cwd <cwd>", "working directory (defaults to current directory)", process.cwd()).option("-g, --global", "install the skill globally instead of in the project", false).action(async (opts) => {
|
|
1774
1791
|
console.log(`${pc.magenta("✿")} ${pc.bold("React Grab")} ${pc.gray(VERSION$3)}`);
|
|
1775
1792
|
console.log();
|
|
1776
1793
|
try {
|
|
@@ -1928,7 +1945,11 @@ const init = new Command().name("init").alias("setup").description("initialize R
|
|
|
1928
1945
|
}
|
|
1929
1946
|
}
|
|
1930
1947
|
logger.break();
|
|
1931
|
-
await promptSkillInstall({
|
|
1948
|
+
await promptSkillInstall({
|
|
1949
|
+
yes: isNonInteractive,
|
|
1950
|
+
global: opts.global,
|
|
1951
|
+
cwd
|
|
1952
|
+
});
|
|
1932
1953
|
logger.break();
|
|
1933
1954
|
process.exit(0);
|
|
1934
1955
|
}
|
|
@@ -1994,7 +2015,11 @@ const init = new Command().name("init").alias("setup").description("initialize R
|
|
|
1994
2015
|
let didInstallSkill = false;
|
|
1995
2016
|
if (!isNonInteractive) {
|
|
1996
2017
|
logger.break();
|
|
1997
|
-
didInstallSkill = await promptSkillInstall({
|
|
2018
|
+
didInstallSkill = await promptSkillInstall({
|
|
2019
|
+
yes: isNonInteractive,
|
|
2020
|
+
global: opts.global,
|
|
2021
|
+
cwd
|
|
2022
|
+
});
|
|
1998
2023
|
}
|
|
1999
2024
|
const result = previewTransform(projectInfo.projectRoot, finalFramework, finalNextRouterType, false, opts.force);
|
|
2000
2025
|
if (!result.success) {
|
|
@@ -2389,18 +2414,48 @@ const readGrabCursor = (dir) => {
|
|
|
2389
2414
|
return 0;
|
|
2390
2415
|
}
|
|
2391
2416
|
};
|
|
2417
|
+
const grabReceivedAt = (line) => {
|
|
2418
|
+
try {
|
|
2419
|
+
const value = JSON.parse(line).receivedAt;
|
|
2420
|
+
return typeof value === "number" ? value : null;
|
|
2421
|
+
} catch {
|
|
2422
|
+
return null;
|
|
2423
|
+
}
|
|
2424
|
+
};
|
|
2392
2425
|
const consumeGrabs = (dir, options) => {
|
|
2393
2426
|
const lines = readCompleteGrabLines(dir);
|
|
2394
2427
|
if (options.all) return lines;
|
|
2428
|
+
const maxAgeMs = options.maxAgeMs ?? 0;
|
|
2395
2429
|
const cursor = readGrabCursor(dir);
|
|
2396
|
-
const
|
|
2397
|
-
const
|
|
2398
|
-
|
|
2399
|
-
|
|
2430
|
+
const total = lines.length;
|
|
2431
|
+
const now = Date.now();
|
|
2432
|
+
const fresh = [];
|
|
2433
|
+
let index = Math.min(cursor, total);
|
|
2434
|
+
while (index < total && (options.limit <= 0 || fresh.length < options.limit)) {
|
|
2435
|
+
const line = lines[index];
|
|
2436
|
+
index += 1;
|
|
2437
|
+
if (maxAgeMs > 0) {
|
|
2438
|
+
const receivedAt = grabReceivedAt(line);
|
|
2439
|
+
if (receivedAt !== null && now - receivedAt > maxAgeMs) continue;
|
|
2440
|
+
}
|
|
2441
|
+
fresh.push(line);
|
|
2442
|
+
}
|
|
2443
|
+
if (index !== cursor) fs.writeFileSync(cursorFilePath(dir), String(index));
|
|
2444
|
+
return fresh;
|
|
2400
2445
|
};
|
|
2401
2446
|
//#endregion
|
|
2402
2447
|
//#region src/commands/read.ts
|
|
2403
|
-
const
|
|
2448
|
+
const parseWaitMs = (raw) => {
|
|
2449
|
+
if (!raw) return 0;
|
|
2450
|
+
if (/^(inf|infinite|forever)$/i.test(raw.trim())) return Number.POSITIVE_INFINITY;
|
|
2451
|
+
const ms = Number(raw);
|
|
2452
|
+
return Number.isFinite(ms) && ms > 0 ? ms : 0;
|
|
2453
|
+
};
|
|
2454
|
+
const parseNonNegativeInt = (raw, fallback) => {
|
|
2455
|
+
const value = Number(raw);
|
|
2456
|
+
return Number.isInteger(value) && value >= 0 ? value : fallback;
|
|
2457
|
+
};
|
|
2458
|
+
const read = new Command().name("read").description("print React Grab selections captured since the last read, then advance the cursor").option("-d, --dir <dir>", "work dir holding history.jsonl + cursor.txt", DEFAULT_WATCH_DIR).option("-w, --wait <ms>", "block up to <ms> (or 'infinite') for a new grab (default: no wait)").option("-n, --limit <count>", "max grabs to print per call (0 = no limit); the cursor only advances past what is printed", String(50)).option("--max-age <ms>", "skip grabs captured longer ago than <ms> (0 = never evict)", String(MAX_GRAB_AGE_MS)).option("--all", "print the entire history without advancing the cursor").action(async (options) => {
|
|
2404
2459
|
const dir = path.resolve(options.dir);
|
|
2405
2460
|
try {
|
|
2406
2461
|
prepareWorkDir(dir);
|
|
@@ -2409,19 +2464,20 @@ const read = new Command().name("read").description("print React Grab selections
|
|
|
2409
2464
|
process.exit(1);
|
|
2410
2465
|
}
|
|
2411
2466
|
unrefStdin();
|
|
2412
|
-
const
|
|
2413
|
-
const
|
|
2467
|
+
const limit = parseNonNegativeInt(options.limit, 50);
|
|
2468
|
+
const maxAgeMs = parseNonNegativeInt(options.maxAge, MAX_GRAB_AGE_MS);
|
|
2414
2469
|
const all = Boolean(options.all);
|
|
2415
2470
|
const drain = () => {
|
|
2416
2471
|
const fresh = consumeGrabs(dir, {
|
|
2417
2472
|
limit,
|
|
2418
|
-
all
|
|
2473
|
+
all,
|
|
2474
|
+
maxAgeMs
|
|
2419
2475
|
});
|
|
2420
2476
|
if (fresh.length > 0) process.stdout.write(`${fresh.join("\n")}\n`);
|
|
2421
2477
|
return fresh.length;
|
|
2422
2478
|
};
|
|
2423
|
-
const
|
|
2424
|
-
const deadline =
|
|
2479
|
+
const waitMs = parseWaitMs(options.wait);
|
|
2480
|
+
const deadline = waitMs === Number.POSITIVE_INFINITY ? Number.POSITIVE_INFINITY : Date.now() + waitMs;
|
|
2425
2481
|
if (drain() > 0) process.exit(0);
|
|
2426
2482
|
while (Date.now() < deadline) {
|
|
2427
2483
|
await sleep(200);
|
|
@@ -2431,7 +2487,7 @@ const read = new Command().name("read").description("print React Grab selections
|
|
|
2431
2487
|
});
|
|
2432
2488
|
//#endregion
|
|
2433
2489
|
//#region src/commands/remove.ts
|
|
2434
|
-
const VERSION$2 = "0.1.
|
|
2490
|
+
const VERSION$2 = "0.1.41";
|
|
2435
2491
|
const remove = new Command().name("remove").description("uninstall the React Grab skill from your agent").action(async () => {
|
|
2436
2492
|
console.log(`${pc.magenta("✿")} ${pc.bold("React Grab")} ${pc.gray(VERSION$2)}`);
|
|
2437
2493
|
console.log();
|
|
@@ -2448,7 +2504,7 @@ const remove = new Command().name("remove").description("uninstall the React Gra
|
|
|
2448
2504
|
});
|
|
2449
2505
|
//#endregion
|
|
2450
2506
|
//#region src/commands/upgrade.ts
|
|
2451
|
-
const VERSION$1 = "0.1.
|
|
2507
|
+
const VERSION$1 = "0.1.41";
|
|
2452
2508
|
const NPM_REGISTRY_URL = "https://registry.npmjs.org/react-grab/latest";
|
|
2453
2509
|
const fetchLatestVersion = async () => {
|
|
2454
2510
|
try {
|
|
@@ -2673,7 +2729,7 @@ const watch = new Command().name("watch").description("start a background daemon
|
|
|
2673
2729
|
});
|
|
2674
2730
|
//#endregion
|
|
2675
2731
|
//#region src/cli.ts
|
|
2676
|
-
const VERSION = "0.1.
|
|
2732
|
+
const VERSION = "0.1.41";
|
|
2677
2733
|
const VERSION_API_URL = "https://www.react-grab.com/api/version";
|
|
2678
2734
|
process.on("SIGINT", () => process.exit(0));
|
|
2679
2735
|
process.on("SIGTERM", () => process.exit(0));
|