preguito 0.2.0 → 0.2.2
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-sea.cjs +209 -357
- package/dist/cli.mjs +200 -347
- package/package.json +1 -1
- package/README.md +0 -464
package/dist/cli-sea.cjs
CHANGED
|
@@ -36,7 +36,7 @@ let node_os = require("node:os");
|
|
|
36
36
|
let node_util = require("node:util");
|
|
37
37
|
let node_readline_promises = require("node:readline/promises");
|
|
38
38
|
|
|
39
|
-
//#region node_modules/commander/lib/error.js
|
|
39
|
+
//#region ../../node_modules/commander/lib/error.js
|
|
40
40
|
var require_error = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
41
41
|
/**
|
|
42
42
|
* CommanderError class
|
|
@@ -76,7 +76,7 @@ var require_error = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
76
76
|
}));
|
|
77
77
|
|
|
78
78
|
//#endregion
|
|
79
|
-
//#region node_modules/commander/lib/argument.js
|
|
79
|
+
//#region ../../node_modules/commander/lib/argument.js
|
|
80
80
|
var require_argument = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
81
81
|
const { InvalidArgumentError } = require_error();
|
|
82
82
|
var Argument = class {
|
|
@@ -201,7 +201,7 @@ var require_argument = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
201
201
|
}));
|
|
202
202
|
|
|
203
203
|
//#endregion
|
|
204
|
-
//#region node_modules/commander/lib/help.js
|
|
204
|
+
//#region ../../node_modules/commander/lib/help.js
|
|
205
205
|
var require_help = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
206
206
|
const { humanReadableArgName } = require_argument();
|
|
207
207
|
/**
|
|
@@ -663,7 +663,7 @@ var require_help = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
663
663
|
}));
|
|
664
664
|
|
|
665
665
|
//#endregion
|
|
666
|
-
//#region node_modules/commander/lib/option.js
|
|
666
|
+
//#region ../../node_modules/commander/lib/option.js
|
|
667
667
|
var require_option = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
668
668
|
const { InvalidArgumentError } = require_error();
|
|
669
669
|
var Option = class {
|
|
@@ -955,7 +955,7 @@ var require_option = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
955
955
|
}));
|
|
956
956
|
|
|
957
957
|
//#endregion
|
|
958
|
-
//#region node_modules/commander/lib/suggestSimilar.js
|
|
958
|
+
//#region ../../node_modules/commander/lib/suggestSimilar.js
|
|
959
959
|
var require_suggestSimilar = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
960
960
|
const maxDistance = 3;
|
|
961
961
|
function editDistance(a, b) {
|
|
@@ -1011,7 +1011,7 @@ var require_suggestSimilar = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
1011
1011
|
}));
|
|
1012
1012
|
|
|
1013
1013
|
//#endregion
|
|
1014
|
-
//#region node_modules/commander/lib/command.js
|
|
1014
|
+
//#region ../../node_modules/commander/lib/command.js
|
|
1015
1015
|
var require_command = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
1016
1016
|
const EventEmitter = require("node:events").EventEmitter;
|
|
1017
1017
|
const childProcess = require("node:child_process");
|
|
@@ -2912,7 +2912,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
2912
2912
|
}));
|
|
2913
2913
|
|
|
2914
2914
|
//#endregion
|
|
2915
|
-
//#region node_modules/commander/index.js
|
|
2915
|
+
//#region ../../node_modules/commander/index.js
|
|
2916
2916
|
var require_commander = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
2917
2917
|
const { Argument } = require_argument();
|
|
2918
2918
|
const { Command } = require_command();
|
|
@@ -2936,7 +2936,7 @@ var require_commander = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
2936
2936
|
}));
|
|
2937
2937
|
|
|
2938
2938
|
//#endregion
|
|
2939
|
-
//#region node_modules/commander/esm.mjs
|
|
2939
|
+
//#region ../../node_modules/commander/esm.mjs
|
|
2940
2940
|
var import_commander = /* @__PURE__ */ __toESM(require_commander(), 1);
|
|
2941
2941
|
const { program: program$1, createCommand, createArgument, createOption, CommanderError, InvalidArgumentError, InvalidOptionArgumentError, Command, Argument, Option, Help } = import_commander.default;
|
|
2942
2942
|
|
|
@@ -3209,7 +3209,7 @@ async function writeConfig(config) {
|
|
|
3209
3209
|
|
|
3210
3210
|
//#endregion
|
|
3211
3211
|
//#region src/commands/commit-parser.ts
|
|
3212
|
-
function parsePositionalArgs(args, config) {
|
|
3212
|
+
function parsePositionalArgs(args, config, bodyFromFlag) {
|
|
3213
3213
|
if (args.length === 0) throw new PrequitoError("No arguments provided. Usage: guito c [card_id] [shortcodes] <message...>");
|
|
3214
3214
|
const context = {};
|
|
3215
3215
|
let cursor = 0;
|
|
@@ -3229,7 +3229,8 @@ function parsePositionalArgs(args, config) {
|
|
|
3229
3229
|
const message = messageParts.join(" ");
|
|
3230
3230
|
return {
|
|
3231
3231
|
context: mergeContext(config.defaults, context),
|
|
3232
|
-
message
|
|
3232
|
+
message,
|
|
3233
|
+
body: bodyFromFlag
|
|
3233
3234
|
};
|
|
3234
3235
|
}
|
|
3235
3236
|
function resolveShortcodes(shortcodesStr, config) {
|
|
@@ -3258,6 +3259,29 @@ function resolveShortcodes(shortcodesStr, config) {
|
|
|
3258
3259
|
return result;
|
|
3259
3260
|
}
|
|
3260
3261
|
|
|
3262
|
+
//#endregion
|
|
3263
|
+
//#region src/utils/validation.ts
|
|
3264
|
+
const GIT_HASH_PATTERN = /^[a-f0-9]{4,40}$/i;
|
|
3265
|
+
const GIT_REF_FORBIDDEN_CHARS = /[\x00-\x1f\x7f ~^:?*[\\]/;
|
|
3266
|
+
const GIT_REF_FORBIDDEN_SEQUENCES = /\.\.|\.lock(\/|$)|@\{|\/\//;
|
|
3267
|
+
function validateHash(hash) {
|
|
3268
|
+
if (!GIT_HASH_PATTERN.test(hash)) throw new PrequitoError(`Invalid git hash: "${hash}". Expected 4-40 hexadecimal characters.`);
|
|
3269
|
+
}
|
|
3270
|
+
function validateRefName(name, type) {
|
|
3271
|
+
if (!name || name.trim() === "") throw new PrequitoError(`${type} name cannot be empty.`);
|
|
3272
|
+
if (name.startsWith("-")) throw new PrequitoError(`Invalid ${type} name: "${name}". Cannot start with '-'.`);
|
|
3273
|
+
if (name.endsWith(".")) throw new PrequitoError(`Invalid ${type} name: "${name}". Cannot end with '.'.`);
|
|
3274
|
+
if (name.endsWith("/")) throw new PrequitoError(`Invalid ${type} name: "${name}". Cannot end with '/'.`);
|
|
3275
|
+
if (GIT_REF_FORBIDDEN_CHARS.test(name)) throw new PrequitoError(`Invalid ${type} name: "${name}". Contains forbidden characters.`);
|
|
3276
|
+
if (GIT_REF_FORBIDDEN_SEQUENCES.test(name)) throw new PrequitoError(`Invalid ${type} name: "${name}". Contains forbidden pattern.`);
|
|
3277
|
+
}
|
|
3278
|
+
function validateBranchName(branch) {
|
|
3279
|
+
validateRefName(branch, "Branch");
|
|
3280
|
+
}
|
|
3281
|
+
function validateTagName(tag) {
|
|
3282
|
+
validateRefName(tag, "Tag");
|
|
3283
|
+
}
|
|
3284
|
+
|
|
3261
3285
|
//#endregion
|
|
3262
3286
|
//#region src/git/operations.ts
|
|
3263
3287
|
const execFileAsync = (0, node_util.promisify)(node_child_process.execFile);
|
|
@@ -3306,11 +3330,16 @@ async function stageAll() {
|
|
|
3306
3330
|
await git(["add", "-A"]);
|
|
3307
3331
|
}
|
|
3308
3332
|
async function commit(message) {
|
|
3309
|
-
|
|
3333
|
+
const parts = message.split("\n\n");
|
|
3334
|
+
const title = parts[0];
|
|
3335
|
+
const body = parts.slice(1).join("\n\n");
|
|
3336
|
+
const args = [
|
|
3310
3337
|
"commit",
|
|
3311
3338
|
"-m",
|
|
3312
|
-
|
|
3313
|
-
]
|
|
3339
|
+
title
|
|
3340
|
+
];
|
|
3341
|
+
if (body) args.push("-m", body);
|
|
3342
|
+
return (await git(args)).stdout;
|
|
3314
3343
|
}
|
|
3315
3344
|
async function commitAmend() {
|
|
3316
3345
|
return (await git([
|
|
@@ -3332,6 +3361,7 @@ async function forcePushLease() {
|
|
|
3332
3361
|
return result.stdout + result.stderr;
|
|
3333
3362
|
}
|
|
3334
3363
|
async function checkout(branch) {
|
|
3364
|
+
validateBranchName(branch);
|
|
3335
3365
|
await git(["checkout", branch]);
|
|
3336
3366
|
}
|
|
3337
3367
|
async function pull() {
|
|
@@ -3339,10 +3369,12 @@ async function pull() {
|
|
|
3339
3369
|
return result.stdout + result.stderr;
|
|
3340
3370
|
}
|
|
3341
3371
|
async function rebase(branch) {
|
|
3372
|
+
validateBranchName(branch);
|
|
3342
3373
|
const result = await git(["rebase", branch]);
|
|
3343
3374
|
return result.stdout + result.stderr;
|
|
3344
3375
|
}
|
|
3345
3376
|
async function rebaseInteractiveEdit(hash) {
|
|
3377
|
+
validateHash(hash);
|
|
3346
3378
|
const sedCmd = `sed -i 's/^pick ${hash.slice(0, 7)}/edit ${hash.slice(0, 7)}/'`;
|
|
3347
3379
|
const result = await git([
|
|
3348
3380
|
"rebase",
|
|
@@ -3369,7 +3401,8 @@ async function rebaseInteractive(count) {
|
|
|
3369
3401
|
`HEAD~${count}`
|
|
3370
3402
|
]);
|
|
3371
3403
|
}
|
|
3372
|
-
async function pushUpstream
|
|
3404
|
+
async function pushUpstream(branch) {
|
|
3405
|
+
if (branch !== void 0) validateBranchName(branch);
|
|
3373
3406
|
const result = await git([
|
|
3374
3407
|
"push",
|
|
3375
3408
|
"--set-upstream",
|
|
@@ -3379,6 +3412,7 @@ async function pushUpstream$1(branch) {
|
|
|
3379
3412
|
return result.stdout + result.stderr;
|
|
3380
3413
|
}
|
|
3381
3414
|
async function commitFixup(hash) {
|
|
3415
|
+
validateHash(hash);
|
|
3382
3416
|
return (await git([
|
|
3383
3417
|
"commit",
|
|
3384
3418
|
"--fixup",
|
|
@@ -3393,14 +3427,17 @@ async function resetSoft(count = 1) {
|
|
|
3393
3427
|
])).stdout;
|
|
3394
3428
|
}
|
|
3395
3429
|
async function createBranch(branch) {
|
|
3430
|
+
validateBranchName(branch);
|
|
3396
3431
|
await git([
|
|
3397
3432
|
"checkout",
|
|
3398
3433
|
"-b",
|
|
3399
3434
|
branch
|
|
3400
3435
|
]);
|
|
3401
3436
|
}
|
|
3402
|
-
async function stash() {
|
|
3403
|
-
|
|
3437
|
+
async function stash(message) {
|
|
3438
|
+
const args = ["stash"];
|
|
3439
|
+
if (message) args.push("-m", message);
|
|
3440
|
+
return (await git(args)).stdout;
|
|
3404
3441
|
}
|
|
3405
3442
|
async function stashPop() {
|
|
3406
3443
|
return (await git(["stash", "pop"])).stdout;
|
|
@@ -3424,6 +3461,7 @@ async function logGrep(keyword, count) {
|
|
|
3424
3461
|
return (await git(args)).stdout;
|
|
3425
3462
|
}
|
|
3426
3463
|
async function logTag(tag) {
|
|
3464
|
+
validateTagName(tag);
|
|
3427
3465
|
return (await git([
|
|
3428
3466
|
"log",
|
|
3429
3467
|
"--oneline",
|
|
@@ -3431,12 +3469,44 @@ async function logTag(tag) {
|
|
|
3431
3469
|
])).stdout;
|
|
3432
3470
|
}
|
|
3433
3471
|
async function logTagAll(tag) {
|
|
3472
|
+
validateTagName(tag);
|
|
3434
3473
|
return (await git([
|
|
3435
3474
|
"log",
|
|
3436
3475
|
"--oneline",
|
|
3437
3476
|
tag
|
|
3438
3477
|
])).stdout;
|
|
3439
3478
|
}
|
|
3479
|
+
async function diff(options = []) {
|
|
3480
|
+
return (await git(["diff", ...options])).stdout;
|
|
3481
|
+
}
|
|
3482
|
+
async function stashList() {
|
|
3483
|
+
return (await git(["stash", "list"])).stdout;
|
|
3484
|
+
}
|
|
3485
|
+
|
|
3486
|
+
//#endregion
|
|
3487
|
+
//#region src/utils/command.ts
|
|
3488
|
+
async function requireGitRepo() {
|
|
3489
|
+
if (!await isGitRepo()) throw new PrequitoError("Not inside a git repository.");
|
|
3490
|
+
}
|
|
3491
|
+
function withErrorHandling(fn) {
|
|
3492
|
+
return async (...args) => {
|
|
3493
|
+
try {
|
|
3494
|
+
await fn(...args);
|
|
3495
|
+
} catch (error) {
|
|
3496
|
+
if (error instanceof PrequitoError) {
|
|
3497
|
+
console.error(`✖ ${error.message}`);
|
|
3498
|
+
process.exit(1);
|
|
3499
|
+
}
|
|
3500
|
+
throw error;
|
|
3501
|
+
}
|
|
3502
|
+
};
|
|
3503
|
+
}
|
|
3504
|
+
function parseCount(value, defaultValue = 1) {
|
|
3505
|
+
if (value === void 0) return defaultValue;
|
|
3506
|
+
const num = parseInt(value, 10);
|
|
3507
|
+
if (isNaN(num) || num <= 0) throw new PrequitoError("Count must be a positive integer.");
|
|
3508
|
+
return num;
|
|
3509
|
+
}
|
|
3440
3510
|
|
|
3441
3511
|
//#endregion
|
|
3442
3512
|
//#region src/utils/spinner.ts
|
|
@@ -3483,36 +3553,23 @@ function spinner(message, options) {
|
|
|
3483
3553
|
//#endregion
|
|
3484
3554
|
//#region src/commands/commit.ts
|
|
3485
3555
|
function registerCommitCommand(program) {
|
|
3486
|
-
program.command("c").alias("commit").description("Templated commit (e.g. guito c 42 f \"msg\" -p)").argument("[args...]", "Card ID, shortcodes, and message").option("-p, --push", "Push after committing").option("-f, --force", "Push with --force-with-lease after committing").option("-d, --dry-run", "Show the generated message without executing").option("-S, --no-stage", "Skip auto-staging (git add -A)").action(async (args, opts) => {
|
|
3487
|
-
|
|
3488
|
-
|
|
3489
|
-
} catch (error) {
|
|
3490
|
-
if (error instanceof PrequitoError) {
|
|
3491
|
-
console.error(`\u2716 ${error.message}`);
|
|
3492
|
-
process.exit(1);
|
|
3493
|
-
}
|
|
3494
|
-
throw error;
|
|
3495
|
-
}
|
|
3496
|
-
});
|
|
3556
|
+
program.command("c").alias("commit").description("Templated commit (e.g. guito c 42 f \"msg\" -p)").argument("[args...]", "Card ID, shortcodes, and message").option("-p, --push", "Push after committing").option("-f, --force", "Push with --force-with-lease after committing").option("-d, --dry-run", "Show the generated message without executing").option("-S, --no-stage", "Skip auto-staging (git add -A)").action(withErrorHandling(async (args, opts) => {
|
|
3557
|
+
await executeCommit(args, opts);
|
|
3558
|
+
}));
|
|
3497
3559
|
}
|
|
3498
3560
|
async function executeCommit(args, opts) {
|
|
3499
|
-
|
|
3500
|
-
console.error("✖ Not inside a git repository.");
|
|
3501
|
-
process.exit(1);
|
|
3502
|
-
}
|
|
3561
|
+
await requireGitRepo();
|
|
3503
3562
|
const config = await loadConfigOrDefault();
|
|
3504
|
-
const { context, message } = parsePositionalArgs(args, config);
|
|
3505
|
-
const
|
|
3563
|
+
const { context, message, body } = parsePositionalArgs(args, config, typeof opts.body === "string" ? opts.body : void 0);
|
|
3564
|
+
const commitTitle = renderTemplate(config.template, context, message);
|
|
3565
|
+
const commitMessage = body ? `${commitTitle}\n\n${body}` : commitTitle;
|
|
3506
3566
|
if (opts.dryRun) {
|
|
3507
3567
|
console.log(commitMessage);
|
|
3508
3568
|
return;
|
|
3509
3569
|
}
|
|
3510
3570
|
if (opts.stage !== false) await stageAll();
|
|
3511
|
-
if (!await hasStagedChanges())
|
|
3512
|
-
|
|
3513
|
-
process.exit(1);
|
|
3514
|
-
}
|
|
3515
|
-
const stopCommit = spinner(`Committing: ${commitMessage}`);
|
|
3571
|
+
if (!await hasStagedChanges()) throw new PrequitoError("No staged changes to commit.");
|
|
3572
|
+
const stopCommit = spinner(`Committing: ${commitTitle}`);
|
|
3516
3573
|
await commit(commitMessage);
|
|
3517
3574
|
stopCommit("✔ Committed.");
|
|
3518
3575
|
if (opts.force) {
|
|
@@ -3529,34 +3586,11 @@ async function executeCommit(args, opts) {
|
|
|
3529
3586
|
//#endregion
|
|
3530
3587
|
//#region src/commands/amend-push.ts
|
|
3531
3588
|
function registerAmendPushCommands(program) {
|
|
3532
|
-
program.command("ap").description("Amend last commit + force push (git push --force)").action(
|
|
3533
|
-
|
|
3534
|
-
await amendAndPush(false);
|
|
3535
|
-
} catch (error) {
|
|
3536
|
-
if (error instanceof PrequitoError) {
|
|
3537
|
-
console.error(`✖ ${error.message}`);
|
|
3538
|
-
process.exit(1);
|
|
3539
|
-
}
|
|
3540
|
-
throw error;
|
|
3541
|
-
}
|
|
3542
|
-
});
|
|
3543
|
-
program.command("apl").description("Amend last commit + safe force push (--force-with-lease)").action(async () => {
|
|
3544
|
-
try {
|
|
3545
|
-
await amendAndPush(true);
|
|
3546
|
-
} catch (error) {
|
|
3547
|
-
if (error instanceof PrequitoError) {
|
|
3548
|
-
console.error(`✖ ${error.message}`);
|
|
3549
|
-
process.exit(1);
|
|
3550
|
-
}
|
|
3551
|
-
throw error;
|
|
3552
|
-
}
|
|
3553
|
-
});
|
|
3589
|
+
program.command("ap").description("Amend last commit + force push (git push --force)").action(withErrorHandling(() => amendAndPush(false)));
|
|
3590
|
+
program.command("apl").description("Amend last commit + safe force push (--force-with-lease)").action(withErrorHandling(() => amendAndPush(true)));
|
|
3554
3591
|
}
|
|
3555
3592
|
async function amendAndPush(useLease) {
|
|
3556
|
-
|
|
3557
|
-
console.error("✖ Not inside a git repository.");
|
|
3558
|
-
process.exit(1);
|
|
3559
|
-
}
|
|
3593
|
+
await requireGitRepo();
|
|
3560
3594
|
const stopStage = spinner("Staging all changes...");
|
|
3561
3595
|
await stageAll();
|
|
3562
3596
|
stopStage("✔ Staged.");
|
|
@@ -3577,45 +3611,12 @@ async function amendAndPush(useLease) {
|
|
|
3577
3611
|
//#endregion
|
|
3578
3612
|
//#region src/commands/rebase.ts
|
|
3579
3613
|
function registerRebaseCommands(program) {
|
|
3580
|
-
program.command("r <branch>").alias("rebase").description("Rebase on <branch> (checkout, pull, rebase) (e.g. guito r main)").action(
|
|
3581
|
-
|
|
3582
|
-
|
|
3583
|
-
} catch (error) {
|
|
3584
|
-
if (error instanceof PrequitoError) {
|
|
3585
|
-
console.error(`✖ ${error.message}`);
|
|
3586
|
-
process.exit(1);
|
|
3587
|
-
}
|
|
3588
|
-
throw error;
|
|
3589
|
-
}
|
|
3590
|
-
});
|
|
3591
|
-
program.command("ri <count>").description("Interactive rebase last <count> commits (e.g. guito ri 3)").action(async (count) => {
|
|
3592
|
-
try {
|
|
3593
|
-
await interactiveRebase(count);
|
|
3594
|
-
} catch (error) {
|
|
3595
|
-
if (error instanceof PrequitoError) {
|
|
3596
|
-
console.error(`✖ ${error.message}`);
|
|
3597
|
-
process.exit(1);
|
|
3598
|
-
}
|
|
3599
|
-
throw error;
|
|
3600
|
-
}
|
|
3601
|
-
});
|
|
3602
|
-
program.command("re <hash>").description("Edit rebase at <hash> (e.g. guito re abc123)").action(async (hash) => {
|
|
3603
|
-
try {
|
|
3604
|
-
await editRebase(hash);
|
|
3605
|
-
} catch (error) {
|
|
3606
|
-
if (error instanceof PrequitoError) {
|
|
3607
|
-
console.error(`✖ ${error.message}`);
|
|
3608
|
-
process.exit(1);
|
|
3609
|
-
}
|
|
3610
|
-
throw error;
|
|
3611
|
-
}
|
|
3612
|
-
});
|
|
3614
|
+
program.command("r <branch>").alias("rebase").description("Rebase on <branch> (checkout, pull, rebase) (e.g. guito r main)").action(withErrorHandling(quickRebase));
|
|
3615
|
+
program.command("ri <count>").description("Interactive rebase last <count> commits (e.g. guito ri 3)").action(withErrorHandling(interactiveRebase));
|
|
3616
|
+
program.command("re <hash>").description("Edit rebase at <hash> (e.g. guito re abc123)").action(withErrorHandling(editRebase));
|
|
3613
3617
|
}
|
|
3614
3618
|
async function quickRebase(branch) {
|
|
3615
|
-
|
|
3616
|
-
console.error("✖ Not inside a git repository.");
|
|
3617
|
-
process.exit(1);
|
|
3618
|
-
}
|
|
3619
|
+
await requireGitRepo();
|
|
3619
3620
|
const currentBranch = await getCurrentBranch();
|
|
3620
3621
|
console.log(`→ Current branch: ${currentBranch}`);
|
|
3621
3622
|
let stop = spinner(`Checking out ${branch}...`);
|
|
@@ -3632,23 +3633,13 @@ async function quickRebase(branch) {
|
|
|
3632
3633
|
stop("✔ Rebase complete.");
|
|
3633
3634
|
}
|
|
3634
3635
|
async function interactiveRebase(count) {
|
|
3635
|
-
|
|
3636
|
-
|
|
3637
|
-
process.exit(1);
|
|
3638
|
-
}
|
|
3639
|
-
const num = parseInt(count, 10);
|
|
3640
|
-
if (isNaN(num) || num <= 0) {
|
|
3641
|
-
console.error("✖ Count must be a positive integer.");
|
|
3642
|
-
process.exit(1);
|
|
3643
|
-
}
|
|
3636
|
+
await requireGitRepo();
|
|
3637
|
+
const num = parseCount(count);
|
|
3644
3638
|
console.log(`→ Starting interactive rebase for the last ${num} commit(s)...`);
|
|
3645
3639
|
await rebaseInteractive(num);
|
|
3646
3640
|
}
|
|
3647
3641
|
async function editRebase(hash) {
|
|
3648
|
-
|
|
3649
|
-
console.error("✖ Not inside a git repository.");
|
|
3650
|
-
process.exit(1);
|
|
3651
|
-
}
|
|
3642
|
+
await requireGitRepo();
|
|
3652
3643
|
console.log(`→ Starting edit rebase on commit ${hash}...`);
|
|
3653
3644
|
await rebaseInteractiveEdit(hash);
|
|
3654
3645
|
console.log("✔ Rebase paused at the target commit. Make your changes, then run:");
|
|
@@ -3969,76 +3960,32 @@ function registerConfigCommand(program) {
|
|
|
3969
3960
|
//#endregion
|
|
3970
3961
|
//#region src/commands/push.ts
|
|
3971
3962
|
function registerPushCommands(program) {
|
|
3972
|
-
program.command("p").alias("push").description("Push current branch (git push)").action(async () => {
|
|
3973
|
-
|
|
3974
|
-
|
|
3975
|
-
|
|
3976
|
-
|
|
3977
|
-
|
|
3978
|
-
|
|
3979
|
-
|
|
3980
|
-
|
|
3981
|
-
}
|
|
3982
|
-
|
|
3983
|
-
|
|
3984
|
-
|
|
3985
|
-
await pushUpstream();
|
|
3986
|
-
} catch (error) {
|
|
3987
|
-
if (error instanceof PrequitoError) {
|
|
3988
|
-
console.error(`✖ ${error.message}`);
|
|
3989
|
-
process.exit(1);
|
|
3990
|
-
}
|
|
3991
|
-
throw error;
|
|
3992
|
-
}
|
|
3993
|
-
});
|
|
3994
|
-
}
|
|
3995
|
-
async function executePush() {
|
|
3996
|
-
if (!await isGitRepo()) {
|
|
3997
|
-
console.error("✖ Not inside a git repository.");
|
|
3998
|
-
process.exit(1);
|
|
3999
|
-
}
|
|
4000
|
-
const stop = spinner("Pushing...");
|
|
4001
|
-
await push();
|
|
4002
|
-
stop("✔ Pushed.");
|
|
4003
|
-
}
|
|
4004
|
-
async function pushUpstream() {
|
|
4005
|
-
if (!await isGitRepo()) {
|
|
4006
|
-
console.error("✖ Not inside a git repository.");
|
|
4007
|
-
process.exit(1);
|
|
4008
|
-
}
|
|
4009
|
-
const branch = await getCurrentBranch();
|
|
4010
|
-
const stop = spinner(`Pushing with --set-upstream origin ${branch}...`);
|
|
4011
|
-
await pushUpstream$1(branch);
|
|
4012
|
-
stop("✔ Pushed.");
|
|
3963
|
+
program.command("p").alias("push").description("Push current branch (git push)").action(withErrorHandling(async () => {
|
|
3964
|
+
await requireGitRepo();
|
|
3965
|
+
const stop = spinner("Pushing...");
|
|
3966
|
+
await push();
|
|
3967
|
+
stop("✔ Pushed.");
|
|
3968
|
+
}));
|
|
3969
|
+
program.command("pu").description("Push + set upstream (git push --set-upstream origin <branch>)").action(withErrorHandling(async () => {
|
|
3970
|
+
await requireGitRepo();
|
|
3971
|
+
const branch = await getCurrentBranch();
|
|
3972
|
+
const stop = spinner(`Pushing with --set-upstream origin ${branch}...`);
|
|
3973
|
+
await pushUpstream(branch);
|
|
3974
|
+
stop("✔ Pushed.");
|
|
3975
|
+
}));
|
|
4013
3976
|
}
|
|
4014
3977
|
|
|
4015
3978
|
//#endregion
|
|
4016
3979
|
//#region src/commands/fixup.ts
|
|
4017
3980
|
function registerFixupCommand(program) {
|
|
4018
|
-
program.command("cf <hash>").description("Fixup commit for <hash> (e.g. guito cf abc123 -f)").option("-p, --push", "Push after creating the fixup commit").option("-f, --force", "Push with --force-with-lease after creating").action(
|
|
4019
|
-
try {
|
|
4020
|
-
await executeFixup(hash, opts);
|
|
4021
|
-
} catch (error) {
|
|
4022
|
-
if (error instanceof PrequitoError) {
|
|
4023
|
-
console.error(`✖ ${error.message}`);
|
|
4024
|
-
process.exit(1);
|
|
4025
|
-
}
|
|
4026
|
-
throw error;
|
|
4027
|
-
}
|
|
4028
|
-
});
|
|
3981
|
+
program.command("cf <hash>").description("Fixup commit for <hash> (e.g. guito cf abc123 -f)").option("-p, --push", "Push after creating the fixup commit").option("-f, --force", "Push with --force-with-lease after creating").action(withErrorHandling(executeFixup));
|
|
4029
3982
|
}
|
|
4030
3983
|
async function executeFixup(hash, opts) {
|
|
4031
|
-
|
|
4032
|
-
console.error("✖ Not inside a git repository.");
|
|
4033
|
-
process.exit(1);
|
|
4034
|
-
}
|
|
3984
|
+
await requireGitRepo();
|
|
4035
3985
|
const stopStage = spinner("Staging all changes...");
|
|
4036
3986
|
await stageAll();
|
|
4037
3987
|
stopStage("✔ Staged.");
|
|
4038
|
-
if (!await hasStagedChanges())
|
|
4039
|
-
console.error("✖ No staged changes to commit.");
|
|
4040
|
-
process.exit(1);
|
|
4041
|
-
}
|
|
3988
|
+
if (!await hasStagedChanges()) throw new PrequitoError("No staged changes to commit.");
|
|
4042
3989
|
const stopCommit = spinner(`Creating fixup commit for ${hash}...`);
|
|
4043
3990
|
await commitFixup(hash);
|
|
4044
3991
|
stopCommit("✔ Fixup commit created.");
|
|
@@ -4056,221 +4003,125 @@ async function executeFixup(hash, opts) {
|
|
|
4056
4003
|
//#endregion
|
|
4057
4004
|
//#region src/commands/undo.ts
|
|
4058
4005
|
function registerUndoCommand(program) {
|
|
4059
|
-
program.command("u [count]").alias("undo").description("Undo last N commits, keep changes staged (e.g. guito u 3)").action(async (count) => {
|
|
4060
|
-
|
|
4061
|
-
|
|
4062
|
-
}
|
|
4063
|
-
|
|
4064
|
-
|
|
4065
|
-
|
|
4066
|
-
|
|
4067
|
-
|
|
4068
|
-
}
|
|
4069
|
-
});
|
|
4070
|
-
}
|
|
4071
|
-
async function executeUndo(count) {
|
|
4072
|
-
if (!await isGitRepo()) {
|
|
4073
|
-
console.error("✖ Not inside a git repository.");
|
|
4074
|
-
process.exit(1);
|
|
4075
|
-
}
|
|
4076
|
-
const num = count ? parseInt(count, 10) : 1;
|
|
4077
|
-
if (isNaN(num) || num <= 0) {
|
|
4078
|
-
console.error("✖ Count must be a positive integer.");
|
|
4079
|
-
process.exit(1);
|
|
4080
|
-
}
|
|
4081
|
-
const stop = spinner(`Undoing last ${num} commit(s)...`);
|
|
4082
|
-
await resetSoft(num);
|
|
4083
|
-
stop(`✔ Undid last ${num} commit(s). Changes are staged.`);
|
|
4084
|
-
const st = await status();
|
|
4085
|
-
if (st) console.log(st);
|
|
4006
|
+
program.command("u [count]").alias("undo").description("Undo last N commits, keep changes staged (e.g. guito u 3)").action(withErrorHandling(async (count) => {
|
|
4007
|
+
await requireGitRepo();
|
|
4008
|
+
const num = parseCount(count);
|
|
4009
|
+
console.log(`→ Undoing last ${num} commit(s)...`);
|
|
4010
|
+
await resetSoft(num);
|
|
4011
|
+
console.log(`✔ Undid last ${num} commit(s). Changes are staged.`);
|
|
4012
|
+
const st = await status();
|
|
4013
|
+
if (st) console.log(st);
|
|
4014
|
+
}));
|
|
4086
4015
|
}
|
|
4087
4016
|
|
|
4088
4017
|
//#endregion
|
|
4089
4018
|
//#region src/commands/status.ts
|
|
4090
4019
|
function registerStatusCommand(program) {
|
|
4091
|
-
program.command("s").alias("status").description("Short status (git status --short)").action(async () => {
|
|
4092
|
-
|
|
4093
|
-
|
|
4094
|
-
|
|
4095
|
-
|
|
4096
|
-
|
|
4097
|
-
process.exit(1);
|
|
4098
|
-
}
|
|
4099
|
-
throw error;
|
|
4100
|
-
}
|
|
4101
|
-
});
|
|
4102
|
-
}
|
|
4103
|
-
async function executeStatus() {
|
|
4104
|
-
if (!await isGitRepo()) {
|
|
4105
|
-
console.error("✖ Not inside a git repository.");
|
|
4106
|
-
process.exit(1);
|
|
4107
|
-
}
|
|
4108
|
-
const output = await status();
|
|
4109
|
-
if (output) console.log(output.trimEnd());
|
|
4110
|
-
else console.log("✨ Nothing to commit, working tree clean.");
|
|
4020
|
+
program.command("s").alias("status").description("Short status (git status --short)").action(withErrorHandling(async () => {
|
|
4021
|
+
await requireGitRepo();
|
|
4022
|
+
const output = await status();
|
|
4023
|
+
if (output) console.log(output.trimEnd());
|
|
4024
|
+
else console.log("✨ Nothing to commit, working tree clean.");
|
|
4025
|
+
}));
|
|
4111
4026
|
}
|
|
4112
4027
|
|
|
4113
4028
|
//#endregion
|
|
4114
4029
|
//#region src/commands/switch.ts
|
|
4115
4030
|
function registerSwitchCommand(program) {
|
|
4116
|
-
program.command("sw <branch>").alias("switch").description("Switch branch, -n to create (e.g. guito sw -n feature/x)").option("-n, --new", "Create a new branch").action(async (branch, opts) => {
|
|
4117
|
-
|
|
4118
|
-
|
|
4119
|
-
|
|
4120
|
-
|
|
4121
|
-
|
|
4122
|
-
|
|
4123
|
-
|
|
4124
|
-
|
|
4125
|
-
}
|
|
4126
|
-
});
|
|
4127
|
-
}
|
|
4128
|
-
async function executeSwitch(branch, opts) {
|
|
4129
|
-
if (!await isGitRepo()) {
|
|
4130
|
-
console.error("✖ Not inside a git repository.");
|
|
4131
|
-
process.exit(1);
|
|
4132
|
-
}
|
|
4133
|
-
const stop = spinner(opts.new ? `Creating and switching to ${branch}...` : `Switching to ${branch}...`);
|
|
4134
|
-
if (opts.new) await createBranch(branch);
|
|
4135
|
-
else await checkout(branch);
|
|
4136
|
-
stop(`✔ On branch ${branch}.`);
|
|
4031
|
+
program.command("sw <branch>").alias("switch").description("Switch branch, -n to create (e.g. guito sw -n feature/x)").option("-n, --new", "Create a new branch").action(withErrorHandling(async (branch, opts) => {
|
|
4032
|
+
await requireGitRepo();
|
|
4033
|
+
if (opts.new) {
|
|
4034
|
+
console.log(`→ Creating and switching to ${branch}...`);
|
|
4035
|
+
await createBranch(branch);
|
|
4036
|
+
} else {
|
|
4037
|
+
console.log(`→ Switching to ${branch}...`);
|
|
4038
|
+
await checkout(branch);
|
|
4039
|
+
}
|
|
4040
|
+
console.log(`✔ On branch ${branch}.`);
|
|
4041
|
+
}));
|
|
4137
4042
|
}
|
|
4138
4043
|
|
|
4139
4044
|
//#endregion
|
|
4140
4045
|
//#region src/commands/stash.ts
|
|
4141
4046
|
function registerStashCommands(program) {
|
|
4142
|
-
program.command("st").description("Stash all changes (git stash)").action(async () => {
|
|
4143
|
-
|
|
4144
|
-
|
|
4145
|
-
|
|
4146
|
-
|
|
4147
|
-
|
|
4148
|
-
|
|
4149
|
-
|
|
4150
|
-
|
|
4151
|
-
|
|
4152
|
-
|
|
4153
|
-
|
|
4154
|
-
|
|
4155
|
-
|
|
4156
|
-
|
|
4157
|
-
|
|
4158
|
-
|
|
4159
|
-
|
|
4160
|
-
|
|
4161
|
-
throw error;
|
|
4162
|
-
}
|
|
4163
|
-
});
|
|
4164
|
-
}
|
|
4165
|
-
async function executeStash() {
|
|
4166
|
-
if (!await isGitRepo()) {
|
|
4167
|
-
console.error("✖ Not inside a git repository.");
|
|
4168
|
-
process.exit(1);
|
|
4169
|
-
}
|
|
4170
|
-
const stop = spinner("Stashing changes...");
|
|
4171
|
-
await stash();
|
|
4172
|
-
stop("✔ Stashed.");
|
|
4173
|
-
}
|
|
4174
|
-
async function executeStashPop() {
|
|
4175
|
-
if (!await isGitRepo()) {
|
|
4176
|
-
console.error("✖ Not inside a git repository.");
|
|
4177
|
-
process.exit(1);
|
|
4178
|
-
}
|
|
4179
|
-
const stop = spinner("Restoring stashed changes...");
|
|
4180
|
-
await stashPop();
|
|
4181
|
-
stop("✔ Restored.");
|
|
4047
|
+
program.command("st").description("Stash all changes (git stash)").option("-m, --message <message>", "Stash with a descriptive message").action(withErrorHandling(async (opts) => {
|
|
4048
|
+
await requireGitRepo();
|
|
4049
|
+
if (opts.message) console.log(`→ Stashing changes: ${opts.message}...`);
|
|
4050
|
+
else console.log("→ Stashing changes...");
|
|
4051
|
+
await stash(opts.message);
|
|
4052
|
+
console.log("✔ Stashed.");
|
|
4053
|
+
}));
|
|
4054
|
+
program.command("stp").description("Pop the latest stash (git stash pop)").action(withErrorHandling(async () => {
|
|
4055
|
+
await requireGitRepo();
|
|
4056
|
+
console.log("→ Restoring stashed changes...");
|
|
4057
|
+
await stashPop();
|
|
4058
|
+
console.log("✔ Restored.");
|
|
4059
|
+
}));
|
|
4060
|
+
program.command("stl").description("List all stashes (git stash list)").action(withErrorHandling(async () => {
|
|
4061
|
+
await requireGitRepo();
|
|
4062
|
+
const output = await stashList();
|
|
4063
|
+
if (output) console.log(output.trimEnd());
|
|
4064
|
+
else console.log("✨ No stashes found.");
|
|
4065
|
+
}));
|
|
4182
4066
|
}
|
|
4183
4067
|
|
|
4184
4068
|
//#endregion
|
|
4185
4069
|
//#region src/commands/log.ts
|
|
4186
4070
|
function registerLogCommand(program) {
|
|
4187
|
-
program.command("l [count]").alias("log").description("Compact log, default last 10 (e.g. guito l 20)").action(async (count) => {
|
|
4188
|
-
|
|
4189
|
-
|
|
4190
|
-
|
|
4191
|
-
|
|
4192
|
-
|
|
4193
|
-
|
|
4194
|
-
}
|
|
4195
|
-
throw error;
|
|
4196
|
-
}
|
|
4197
|
-
});
|
|
4198
|
-
}
|
|
4199
|
-
async function executeLog(count) {
|
|
4200
|
-
if (!await isGitRepo()) {
|
|
4201
|
-
console.error("✖ Not inside a git repository.");
|
|
4202
|
-
process.exit(1);
|
|
4203
|
-
}
|
|
4204
|
-
const num = count ? parseInt(count, 10) : 10;
|
|
4205
|
-
if (isNaN(num) || num <= 0) {
|
|
4206
|
-
console.error("✖ Count must be a positive integer.");
|
|
4207
|
-
process.exit(1);
|
|
4208
|
-
}
|
|
4209
|
-
const output = await logOneline(num);
|
|
4210
|
-
if (output) console.log(output.trimEnd());
|
|
4211
|
-
else console.log("✨ No commits found.");
|
|
4071
|
+
program.command("l [count]").alias("log").description("Compact log, default last 10 (e.g. guito l 20)").action(withErrorHandling(async (count) => {
|
|
4072
|
+
await requireGitRepo();
|
|
4073
|
+
const num = parseCount(count, 10);
|
|
4074
|
+
const output = await logOneline(num);
|
|
4075
|
+
if (output) console.log(output.trimEnd());
|
|
4076
|
+
else console.log("✨ No commits found.");
|
|
4077
|
+
}));
|
|
4212
4078
|
}
|
|
4213
4079
|
|
|
4214
4080
|
//#endregion
|
|
4215
4081
|
//#region src/commands/find.ts
|
|
4216
4082
|
function registerFindCommands(program) {
|
|
4217
|
-
program.command("f <keyword>").alias("find").description("Search commits by message (e.g. guito f \"login\")").option("-n, --number <count>", "Limit number of results").action(async (keyword, opts) => {
|
|
4218
|
-
|
|
4219
|
-
|
|
4220
|
-
|
|
4221
|
-
if (error instanceof PrequitoError) {
|
|
4222
|
-
console.error(`✖ ${error.message}`);
|
|
4223
|
-
process.exit(1);
|
|
4224
|
-
}
|
|
4225
|
-
throw error;
|
|
4226
|
-
}
|
|
4227
|
-
});
|
|
4228
|
-
program.command("t <tag>").alias("tag").description("Commits since <tag> (e.g. guito t v1.0.0)").option("-a, --all", "Show all commits reachable from the tag").action(async (tag, opts) => {
|
|
4229
|
-
try {
|
|
4230
|
-
await executeTag(tag, opts);
|
|
4231
|
-
} catch (error) {
|
|
4232
|
-
if (error instanceof PrequitoError) {
|
|
4233
|
-
console.error(`✖ ${error.message}`);
|
|
4234
|
-
process.exit(1);
|
|
4235
|
-
}
|
|
4236
|
-
throw error;
|
|
4237
|
-
}
|
|
4238
|
-
});
|
|
4239
|
-
}
|
|
4240
|
-
async function executeFind(keyword, opts) {
|
|
4241
|
-
if (!await isGitRepo()) {
|
|
4242
|
-
console.error("✖ Not inside a git repository.");
|
|
4243
|
-
process.exit(1);
|
|
4244
|
-
}
|
|
4245
|
-
const count = opts.number ? parseInt(opts.number, 10) : void 0;
|
|
4246
|
-
const stop = spinner(`Searching for "${keyword}"...`);
|
|
4247
|
-
const output = await logGrep(keyword, count);
|
|
4248
|
-
stop("");
|
|
4249
|
-
if (output) console.log(output.trimEnd());
|
|
4250
|
-
else console.log(`✨ No commits found matching "${keyword}".`);
|
|
4251
|
-
}
|
|
4252
|
-
async function executeTag(tag, opts) {
|
|
4253
|
-
if (!await isGitRepo()) {
|
|
4254
|
-
console.error("✖ Not inside a git repository.");
|
|
4255
|
-
process.exit(1);
|
|
4256
|
-
}
|
|
4257
|
-
if (opts.all) {
|
|
4258
|
-
console.log(`🏷️ Commits reachable from ${tag}:`);
|
|
4259
|
-
const output = await logTagAll(tag);
|
|
4083
|
+
program.command("f <keyword>").alias("find").description("Search commits by message (e.g. guito f \"login\")").option("-n, --number <count>", "Limit number of results").action(withErrorHandling(async (keyword, opts) => {
|
|
4084
|
+
await requireGitRepo();
|
|
4085
|
+
const count = opts.number ? parseInt(opts.number, 10) : void 0;
|
|
4086
|
+
const output = await logGrep(keyword, count);
|
|
4260
4087
|
if (output) console.log(output.trimEnd());
|
|
4261
|
-
else console.log(
|
|
4262
|
-
}
|
|
4263
|
-
|
|
4264
|
-
|
|
4088
|
+
else console.log(`✨ No commits found matching "${keyword}".`);
|
|
4089
|
+
}));
|
|
4090
|
+
program.command("t <tag>").alias("tag").description("Commits since <tag> (e.g. guito t v1.0.0)").option("-a, --all", "Show all commits reachable from the tag").action(withErrorHandling(async (tag, opts) => {
|
|
4091
|
+
await requireGitRepo();
|
|
4092
|
+
if (opts.all) {
|
|
4093
|
+
console.log(`🏷️ Commits reachable from ${tag}:`);
|
|
4094
|
+
const output = await logTagAll(tag);
|
|
4095
|
+
if (output) console.log(output.trimEnd());
|
|
4096
|
+
else console.log("✨ No commits found.");
|
|
4097
|
+
} else {
|
|
4098
|
+
console.log(`🏷️ Commits since ${tag}:`);
|
|
4099
|
+
const output = await logTag(tag);
|
|
4100
|
+
if (output) console.log(output.trimEnd());
|
|
4101
|
+
else console.log("✨ No commits since this tag.");
|
|
4102
|
+
}
|
|
4103
|
+
}));
|
|
4104
|
+
}
|
|
4105
|
+
|
|
4106
|
+
//#endregion
|
|
4107
|
+
//#region src/commands/diff.ts
|
|
4108
|
+
function registerDiffCommand(program) {
|
|
4109
|
+
program.command("d").alias("diff").description("Show changes (git diff)").option("-s, --staged", "Show staged changes only").option("--stat", "Show diffstat summary").option("-n, --name-only", "Show only names of changed files").action(withErrorHandling(async (opts) => {
|
|
4110
|
+
await requireGitRepo();
|
|
4111
|
+
const options = [];
|
|
4112
|
+
if (opts.staged) options.push("--staged");
|
|
4113
|
+
if (opts.stat) options.push("--stat");
|
|
4114
|
+
if (opts.nameOnly) options.push("--name-only");
|
|
4115
|
+
const output = await diff(options);
|
|
4265
4116
|
if (output) console.log(output.trimEnd());
|
|
4266
|
-
else console.log("✨ No
|
|
4267
|
-
}
|
|
4117
|
+
else console.log("✨ No changes.");
|
|
4118
|
+
}));
|
|
4268
4119
|
}
|
|
4269
4120
|
|
|
4270
4121
|
//#endregion
|
|
4271
4122
|
//#region src/cli.ts
|
|
4272
4123
|
const program = new Command();
|
|
4273
|
-
program.name("guito").description("preguito - a lazy git CLI with commit templates and shortcuts").version("0.
|
|
4124
|
+
program.name("guito").description("preguito - a lazy git CLI with commit templates and shortcuts").version("0.2.2").addHelpText("before", "\n🦥 preguito v0.1.0\n A lazy git CLI with commit templates and shortcuts.\n");
|
|
4274
4125
|
registerCommitCommand(program);
|
|
4275
4126
|
registerAmendPushCommands(program);
|
|
4276
4127
|
registerRebaseCommands(program);
|
|
@@ -4284,6 +4135,7 @@ registerSwitchCommand(program);
|
|
|
4284
4135
|
registerStashCommands(program);
|
|
4285
4136
|
registerLogCommand(program);
|
|
4286
4137
|
registerFindCommands(program);
|
|
4138
|
+
registerDiffCommand(program);
|
|
4287
4139
|
program.parse();
|
|
4288
4140
|
|
|
4289
4141
|
//#endregion
|