@ferueda/grove-cli 0.2.0 → 0.3.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/dist/cli.js +9 -3
- package/dist/commands/acquire.d.ts.map +1 -1
- package/dist/commands/acquire.js +48 -2
- package/dist/commands/destroy.d.ts.map +1 -1
- package/dist/commands/destroy.js +18 -5
- package/dist/commands/inspect.d.ts +3 -0
- package/dist/commands/inspect.d.ts.map +1 -0
- package/dist/commands/inspect.js +34 -0
- package/dist/commands/release.d.ts.map +1 -1
- package/dist/commands/release.js +41 -4
- package/dist/commands/repair.d.ts +3 -0
- package/dist/commands/repair.d.ts.map +1 -0
- package/dist/commands/repair.js +42 -0
- package/dist/commands/status.d.ts.map +1 -1
- package/dist/commands/status.js +22 -0
- package/dist/error-handler.d.ts +1 -0
- package/dist/error-handler.d.ts.map +1 -1
- package/dist/error-handler.js +12 -0
- package/package.json +2 -2
package/dist/cli.js
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { Command } from "commander";
|
|
3
3
|
import pc from "picocolors";
|
|
4
|
-
import { handleError, setDebug } from "./error-handler.js";
|
|
4
|
+
import { handleError, setDebug, setJson } from "./error-handler.js";
|
|
5
5
|
import { acquireCmd } from "./commands/acquire.js";
|
|
6
6
|
import { releaseCmd } from "./commands/release.js";
|
|
7
7
|
import { statusCmd } from "./commands/status.js";
|
|
8
8
|
import { destroyCmd, destroyAllCmd } from "./commands/destroy.js";
|
|
9
|
+
import { inspectCmd } from "./commands/inspect.js";
|
|
10
|
+
import { repairCmd } from "./commands/repair.js";
|
|
9
11
|
process.on("uncaughtException", (err) => {
|
|
10
12
|
console.error(pc.red(`Fatal: ${err.message}`));
|
|
11
13
|
process.exitCode = 1;
|
|
@@ -20,16 +22,20 @@ program
|
|
|
20
22
|
.description("CLI for Grove - A programmatic git worktree pool manager")
|
|
21
23
|
.version("0.1.0")
|
|
22
24
|
.option("--debug", "Show verbose error output including stack traces")
|
|
23
|
-
.hook("preAction", (thisCommand) => {
|
|
24
|
-
const opts =
|
|
25
|
+
.hook("preAction", (thisCommand, actionCommand) => {
|
|
26
|
+
const opts = actionCommand.optsWithGlobals();
|
|
25
27
|
if (opts.debug)
|
|
26
28
|
setDebug(true);
|
|
29
|
+
if (opts.json)
|
|
30
|
+
setJson(true);
|
|
27
31
|
});
|
|
28
32
|
program.addCommand(acquireCmd);
|
|
29
33
|
program.addCommand(releaseCmd);
|
|
30
34
|
program.addCommand(statusCmd);
|
|
31
35
|
program.addCommand(destroyCmd);
|
|
32
36
|
program.addCommand(destroyAllCmd);
|
|
37
|
+
program.addCommand(inspectCmd);
|
|
38
|
+
program.addCommand(repairCmd);
|
|
33
39
|
try {
|
|
34
40
|
await program.parseAsync(process.argv);
|
|
35
41
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"acquire.d.ts","sourceRoot":"","sources":["../../src/commands/acquire.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"acquire.d.ts","sourceRoot":"","sources":["../../src/commands/acquire.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAOpC,eAAO,MAAM,UAAU,SA6FnB,CAAC"}
|
package/dist/commands/acquire.js
CHANGED
|
@@ -7,9 +7,51 @@ export const acquireCmd = new Command("acquire")
|
|
|
7
7
|
.description("Acquire a worktree from the pool")
|
|
8
8
|
.option("--shell", "Drop into an interactive subshell inside the worktree")
|
|
9
9
|
.option("-r, --repo <path>", "Path to repository root")
|
|
10
|
+
.option("--lease <id>", "Lease ID to acquire")
|
|
11
|
+
.option("--owner <id>", "Owner ID for the lease")
|
|
12
|
+
.option("--branch <name>", "Branch to check out")
|
|
13
|
+
.option("--ref <sha>", "Ref to check out detached")
|
|
14
|
+
.option("--create-branch-from <ref>", "Create branch from this ref")
|
|
15
|
+
.option("--fail-if-exists", "Fail if branch already exists")
|
|
16
|
+
.option("--json", "Output result as JSON")
|
|
10
17
|
.action(async (options) => {
|
|
11
18
|
try {
|
|
12
19
|
const grove = await loadGrove({ repo: options.repo });
|
|
20
|
+
if (options.lease) {
|
|
21
|
+
let modeOpts = {};
|
|
22
|
+
if (options.branch) {
|
|
23
|
+
modeOpts = { mode: "branch", branch: options.branch };
|
|
24
|
+
if (options.createBranchFrom) {
|
|
25
|
+
modeOpts.createBranch = {
|
|
26
|
+
from: options.createBranchFrom,
|
|
27
|
+
ifExists: options.failIfExists ? "fail" : "reuse",
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
else if (options.ref) {
|
|
32
|
+
modeOpts = { mode: "detached", ref: options.ref };
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
// fallback to default branch logic if nothing specified?
|
|
36
|
+
modeOpts = { mode: "branch", branch: "main" }; // or we can just let SDK handle it, wait SDK requires mode.
|
|
37
|
+
// Since SDK requires mode, if not specified let's default to branch "main" or what SDK would do
|
|
38
|
+
// actually let's throw
|
|
39
|
+
throw new Error("Lease mode requires either --branch or --ref");
|
|
40
|
+
}
|
|
41
|
+
const acquireOpts = {
|
|
42
|
+
leaseId: options.lease,
|
|
43
|
+
ownerId: options.owner,
|
|
44
|
+
...modeOpts,
|
|
45
|
+
};
|
|
46
|
+
const lease = await grove.acquire(acquireOpts);
|
|
47
|
+
if (options.json) {
|
|
48
|
+
process.stdout.write(JSON.stringify(lease, null, 2) + "\n");
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
console.error(pc.green(`🌳 Acquired lease ${lease.leaseId} at ${lease.path}`));
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
// Legacy flow
|
|
13
55
|
const slot = await grove.acquire();
|
|
14
56
|
if (options.shell) {
|
|
15
57
|
console.error(pc.green(`🌳 Entered worktree at ${slot.path}. Type 'exit' to return.`));
|
|
@@ -38,8 +80,12 @@ export const acquireCmd = new Command("acquire")
|
|
|
38
80
|
});
|
|
39
81
|
}
|
|
40
82
|
else {
|
|
41
|
-
|
|
42
|
-
|
|
83
|
+
if (options.json) {
|
|
84
|
+
process.stdout.write(JSON.stringify(slot, null, 2) + "\n");
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
process.stdout.write(slot.path + "\n");
|
|
88
|
+
}
|
|
43
89
|
}
|
|
44
90
|
}
|
|
45
91
|
catch (err) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"destroy.d.ts","sourceRoot":"","sources":["../../src/commands/destroy.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAKpC,eAAO,MAAM,UAAU,
|
|
1
|
+
{"version":3,"file":"destroy.d.ts","sourceRoot":"","sources":["../../src/commands/destroy.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAKpC,eAAO,MAAM,UAAU,SAoBnB,CAAC;AAEL,eAAO,MAAM,aAAa,SAkBtB,CAAC"}
|
package/dist/commands/destroy.js
CHANGED
|
@@ -4,14 +4,21 @@ import { handleError } from "../error-handler.js";
|
|
|
4
4
|
import pc from "picocolors";
|
|
5
5
|
export const destroyCmd = new Command("destroy")
|
|
6
6
|
.description("Destroy a specific worktree from the pool")
|
|
7
|
-
.argument("<
|
|
7
|
+
.argument("<pathOrLeaseId>", "Path or lease ID to destroy")
|
|
8
8
|
.option("-f, --force", "Force destroy even if in use")
|
|
9
|
+
.option("--delete-branch", "Also delete the branch associated with this lease")
|
|
9
10
|
.option("-r, --repo <path>", "Path to repository root")
|
|
10
|
-
.
|
|
11
|
+
.option("--json", "Output result as JSON")
|
|
12
|
+
.action(async (pathOrLeaseId, options) => {
|
|
11
13
|
try {
|
|
12
14
|
const grove = await loadGrove({ repo: options.repo });
|
|
13
|
-
await grove.destroy(
|
|
14
|
-
|
|
15
|
+
await grove.destroy(pathOrLeaseId, { force: options.force, deleteBranch: options.deleteBranch });
|
|
16
|
+
if (options.json) {
|
|
17
|
+
process.stdout.write(JSON.stringify({ success: true, target: pathOrLeaseId }) + "\n");
|
|
18
|
+
}
|
|
19
|
+
else {
|
|
20
|
+
console.error(pc.green(`🌳 Destroyed worktree/lease ${pathOrLeaseId}`));
|
|
21
|
+
}
|
|
15
22
|
}
|
|
16
23
|
catch (err) {
|
|
17
24
|
handleError(err);
|
|
@@ -21,11 +28,17 @@ export const destroyAllCmd = new Command("destroy-all")
|
|
|
21
28
|
.description("Destroy all worktrees in the pool")
|
|
22
29
|
.option("-f, --force", "Force destroy even if in use")
|
|
23
30
|
.option("-r, --repo <path>", "Path to repository root")
|
|
31
|
+
.option("--json", "Output result as JSON")
|
|
24
32
|
.action(async (options) => {
|
|
25
33
|
try {
|
|
26
34
|
const grove = await loadGrove({ repo: options.repo });
|
|
27
35
|
await grove.destroyAll({ force: options.force });
|
|
28
|
-
|
|
36
|
+
if (options.json) {
|
|
37
|
+
process.stdout.write(JSON.stringify({ success: true }) + "\n");
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
console.error(pc.green("🌳 Destroyed all worktrees in the pool."));
|
|
41
|
+
}
|
|
29
42
|
}
|
|
30
43
|
catch (err) {
|
|
31
44
|
handleError(err);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"inspect.d.ts","sourceRoot":"","sources":["../../src/commands/inspect.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAKpC,eAAO,MAAM,UAAU,SA6BnB,CAAC"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { Command } from "commander";
|
|
2
|
+
import { loadGrove } from "../utils.js";
|
|
3
|
+
import { handleError } from "../error-handler.js";
|
|
4
|
+
import pc from "picocolors";
|
|
5
|
+
export const inspectCmd = new Command("inspect")
|
|
6
|
+
.description("Inspect a specific lease or worktree")
|
|
7
|
+
.argument("<pathOrLeaseId>", "Path or lease ID to inspect")
|
|
8
|
+
.option("-r, --repo <path>", "Path to repository root")
|
|
9
|
+
.option("--json", "Output result as JSON")
|
|
10
|
+
.action(async (pathOrLeaseId, options) => {
|
|
11
|
+
try {
|
|
12
|
+
const grove = await loadGrove({ repo: options.repo });
|
|
13
|
+
const lease = await grove.inspect(pathOrLeaseId);
|
|
14
|
+
if (!lease) {
|
|
15
|
+
throw new Error(`Lease not found: ${pathOrLeaseId}`);
|
|
16
|
+
}
|
|
17
|
+
if (options.json) {
|
|
18
|
+
process.stdout.write(JSON.stringify(lease, null, 2) + "\n");
|
|
19
|
+
}
|
|
20
|
+
else {
|
|
21
|
+
console.log(pc.bold(`Lease: ${lease.leaseId}`));
|
|
22
|
+
console.log(`Path: ${lease.path}`);
|
|
23
|
+
console.log(`State: ${lease.state}`);
|
|
24
|
+
console.log(`Branch: ${lease.branch || "-"}`);
|
|
25
|
+
console.log(`Safety: ${lease.processSafety}`);
|
|
26
|
+
if (lease.pendingCleanup) {
|
|
27
|
+
console.log(`Pending Cleanup: ${JSON.stringify(lease.pendingCleanup)}`);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
catch (err) {
|
|
32
|
+
handleError(err);
|
|
33
|
+
}
|
|
34
|
+
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"release.d.ts","sourceRoot":"","sources":["../../src/commands/release.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"release.d.ts","sourceRoot":"","sources":["../../src/commands/release.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAMpC,eAAO,MAAM,UAAU,SAqDnB,CAAC"}
|
package/dist/commands/release.js
CHANGED
|
@@ -4,14 +4,51 @@ import { handleError } from "../error-handler.js";
|
|
|
4
4
|
import pc from "picocolors";
|
|
5
5
|
export const releaseCmd = new Command("release")
|
|
6
6
|
.description("Release a worktree back to the pool")
|
|
7
|
-
.argument("[
|
|
7
|
+
.argument("[pathOrLeaseId]", "Path or lease ID to release (defaults to CWD)")
|
|
8
8
|
.option("-r, --repo <path>", "Path to repository root")
|
|
9
|
-
.
|
|
9
|
+
.option("--cleanup <action>", "Cleanup action (preserve, reset, quarantine)")
|
|
10
|
+
.option("--reset-to <ref>", "Branch/ref to reset to")
|
|
11
|
+
.option("-f, --force", "Force cleanup even if in use")
|
|
12
|
+
.option("--json", "Output result as JSON")
|
|
13
|
+
.action(async (pathOrLeaseId, options) => {
|
|
10
14
|
try {
|
|
11
|
-
const targetPath =
|
|
15
|
+
const targetPath = pathOrLeaseId || process.cwd();
|
|
12
16
|
const grove = await loadGrove({ repo: options.repo });
|
|
17
|
+
if (options.cleanup) {
|
|
18
|
+
if (!["preserve", "reset", "quarantine"].includes(options.cleanup)) {
|
|
19
|
+
throw new Error("Invalid cleanup action");
|
|
20
|
+
}
|
|
21
|
+
let releaseOpts;
|
|
22
|
+
if (options.cleanup === "preserve") {
|
|
23
|
+
releaseOpts = { cleanup: "preserve" };
|
|
24
|
+
}
|
|
25
|
+
else if (options.cleanup === "quarantine") {
|
|
26
|
+
releaseOpts = { cleanup: "quarantine" };
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
releaseOpts = {
|
|
30
|
+
cleanup: "reset",
|
|
31
|
+
force: options.force
|
|
32
|
+
};
|
|
33
|
+
if (options.resetTo) {
|
|
34
|
+
releaseOpts.resetTo = options.resetTo;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
const lease = await grove.release(targetPath, releaseOpts);
|
|
38
|
+
if (options.json) {
|
|
39
|
+
process.stdout.write(JSON.stringify(lease, null, 2) + "\n");
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
console.error(pc.green(`🌳 Lease ${lease.leaseId} released with action ${options.cleanup}.`));
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
13
45
|
await grove.release(targetPath);
|
|
14
|
-
|
|
46
|
+
if (options.json) {
|
|
47
|
+
process.stdout.write(JSON.stringify({ success: true, path: targetPath }) + "\n");
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
console.error(pc.green("🌳 Worktree returned to pool."));
|
|
51
|
+
}
|
|
15
52
|
}
|
|
16
53
|
catch (err) {
|
|
17
54
|
handleError(err);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"repair.d.ts","sourceRoot":"","sources":["../../src/commands/repair.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAKpC,eAAO,MAAM,SAAS,SAoClB,CAAC"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { Command } from "commander";
|
|
2
|
+
import { loadGrove } from "../utils.js";
|
|
3
|
+
import { handleError } from "../error-handler.js";
|
|
4
|
+
import pc from "picocolors";
|
|
5
|
+
export const repairCmd = new Command("repair")
|
|
6
|
+
.description("Repair a stuck or broken lease")
|
|
7
|
+
.argument("<leaseId>", "Lease ID to repair")
|
|
8
|
+
.requiredOption("--action <action>", "Action to take: quarantine, resume-cleanup, or force-destroy")
|
|
9
|
+
.option("-f, --force", "Force action even if processes are running")
|
|
10
|
+
.option("-r, --repo <path>", "Path to repository root")
|
|
11
|
+
.option("--json", "Output result as JSON")
|
|
12
|
+
.action(async (leaseId, options) => {
|
|
13
|
+
try {
|
|
14
|
+
if (!["quarantine", "resume-cleanup", "force-destroy"].includes(options.action)) {
|
|
15
|
+
throw new Error("Invalid action. Must be quarantine, resume-cleanup, or force-destroy.");
|
|
16
|
+
}
|
|
17
|
+
const grove = await loadGrove({ repo: options.repo });
|
|
18
|
+
const lease = await grove.repair({
|
|
19
|
+
leaseId,
|
|
20
|
+
action: options.action,
|
|
21
|
+
force: options.force,
|
|
22
|
+
});
|
|
23
|
+
if (!lease) {
|
|
24
|
+
if (options.json) {
|
|
25
|
+
process.stdout.write(JSON.stringify({ status: "destroyed", leaseId }) + "\n");
|
|
26
|
+
}
|
|
27
|
+
else {
|
|
28
|
+
console.error(pc.green(`🌳 Lease ${leaseId} was successfully force-destroyed.`));
|
|
29
|
+
}
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
if (options.json) {
|
|
33
|
+
process.stdout.write(JSON.stringify(lease, null, 2) + "\n");
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
console.error(pc.green(`🌳 Lease ${lease.leaseId} repaired with action ${options.action}. New state: ${lease.state}`));
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
catch (err) {
|
|
40
|
+
handleError(err);
|
|
41
|
+
}
|
|
42
|
+
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../src/commands/status.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAKpC,eAAO,MAAM,SAAS,
|
|
1
|
+
{"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../src/commands/status.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAKpC,eAAO,MAAM,SAAS,SA+ElB,CAAC"}
|
package/dist/commands/status.js
CHANGED
|
@@ -5,10 +5,32 @@ import pc from "picocolors";
|
|
|
5
5
|
export const statusCmd = new Command("status")
|
|
6
6
|
.description("Show the status of all worktrees in the pool")
|
|
7
7
|
.option("-r, --repo <path>", "Path to repository root")
|
|
8
|
+
.option("--leases", "Show lease metadata instead of ephemeral slots")
|
|
8
9
|
.option("--json", "Output status as JSON")
|
|
9
10
|
.action(async (options) => {
|
|
10
11
|
try {
|
|
11
12
|
const grove = await loadGrove({ repo: options.repo });
|
|
13
|
+
if (options.leases) {
|
|
14
|
+
const leases = await grove.listLeases();
|
|
15
|
+
if (options.json) {
|
|
16
|
+
process.stdout.write(JSON.stringify(leases, null, 2) + "\n");
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
if (leases.length === 0) {
|
|
20
|
+
console.log("🌳 No leases in pool.");
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
console.log(pc.bold("Lease ID\tState\t\tBranch\t\tPath"));
|
|
24
|
+
console.log("------------------------------------------------------------------");
|
|
25
|
+
for (const l of leases) {
|
|
26
|
+
const stateStr = l.state === "leased" ? pc.green(l.state) :
|
|
27
|
+
l.state === "quarantined" ? pc.red(l.state) :
|
|
28
|
+
pc.yellow(l.state);
|
|
29
|
+
console.log(`${l.leaseId}\t${stateStr}\t\t${l.branch || "-"}\t\t${l.path}`);
|
|
30
|
+
}
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
// Legacy
|
|
12
34
|
const trees = await grove.list();
|
|
13
35
|
if (options.json) {
|
|
14
36
|
process.stdout.write(JSON.stringify(trees, null, 2) + "\n");
|
package/dist/error-handler.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"error-handler.d.ts","sourceRoot":"","sources":["../src/error-handler.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"error-handler.d.ts","sourceRoot":"","sources":["../src/error-handler.ts"],"names":[],"mappings":"AAMA,wBAAgB,QAAQ,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAE/C;AAED,wBAAgB,OAAO,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAE9C;AAED,wBAAgB,WAAW,CAAC,GAAG,EAAE,OAAO,GAAG,KAAK,CA+B/C"}
|
package/dist/error-handler.js
CHANGED
|
@@ -1,10 +1,22 @@
|
|
|
1
1
|
import pc from "picocolors";
|
|
2
2
|
import { GroveError, GitCommandError } from "@ferueda/grove";
|
|
3
3
|
let debugEnabled = false;
|
|
4
|
+
let jsonEnabled = false;
|
|
4
5
|
export function setDebug(enabled) {
|
|
5
6
|
debugEnabled = enabled;
|
|
6
7
|
}
|
|
8
|
+
export function setJson(enabled) {
|
|
9
|
+
jsonEnabled = enabled;
|
|
10
|
+
}
|
|
7
11
|
export function handleError(err) {
|
|
12
|
+
if (jsonEnabled) {
|
|
13
|
+
const errorObj = { error: err instanceof Error ? err.message : String(err) };
|
|
14
|
+
if (err instanceof GroveError) {
|
|
15
|
+
errorObj.code = err.code;
|
|
16
|
+
}
|
|
17
|
+
process.stdout.write(JSON.stringify(errorObj, null, 2) + "\n");
|
|
18
|
+
process.exit(1);
|
|
19
|
+
}
|
|
8
20
|
if (err instanceof GroveError) {
|
|
9
21
|
console.error(pc.red(`[${err.code}] ${err.message}`));
|
|
10
22
|
if (debugEnabled) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ferueda/grove-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "https://github.com/ferueda/grove.git"
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
"commander": "^13.0.0",
|
|
20
20
|
"execa": "^9.6.0",
|
|
21
21
|
"picocolors": "^1.1.0",
|
|
22
|
-
"@ferueda/grove": "0.
|
|
22
|
+
"@ferueda/grove": "0.3.0"
|
|
23
23
|
},
|
|
24
24
|
"scripts": {
|
|
25
25
|
"build": "tsgo -p tsconfig.json"
|