@rotorsoft/gent 1.14.2 → 1.15.1
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/index.js +91 -115
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2150,7 +2150,7 @@ import { homedir } from "os";
|
|
|
2150
2150
|
// package.json
|
|
2151
2151
|
var package_default = {
|
|
2152
2152
|
name: "@rotorsoft/gent",
|
|
2153
|
-
version: "1.
|
|
2153
|
+
version: "1.15.1",
|
|
2154
2154
|
description: "AI-powered GitHub workflow CLI - leverage AI (Claude, Gemini, or Codex) to create tickets, implement features, and manage PRs",
|
|
2155
2155
|
keywords: [
|
|
2156
2156
|
"cli",
|
|
@@ -2703,6 +2703,7 @@ function getAvailableActions(state) {
|
|
|
2703
2703
|
if (state.isOnMain) {
|
|
2704
2704
|
actions.push({ id: "create", label: "new", shortcut: "n" });
|
|
2705
2705
|
actions.push({ id: "list", label: "list", shortcut: "l" });
|
|
2706
|
+
actions.push({ id: "refresh", label: "refresh", shortcut: "f" });
|
|
2706
2707
|
actions.push({ id: "switch-provider", label: "ai", shortcut: "a" });
|
|
2707
2708
|
actions.push({ id: "quit", label: "quit", shortcut: "q" });
|
|
2708
2709
|
return actions;
|
|
@@ -2719,10 +2720,8 @@ function getAvailableActions(state) {
|
|
|
2719
2720
|
if (state.issue && state.pr?.state !== "merged") {
|
|
2720
2721
|
actions.push({ id: "run", label: "run", shortcut: "u" });
|
|
2721
2722
|
}
|
|
2722
|
-
if (state.pr && (state.pr.state === "merged" || state.pr.state === "closed")) {
|
|
2723
|
-
actions.push({ id: "checkout-main", label: "main", shortcut: "m" });
|
|
2724
|
-
}
|
|
2725
2723
|
actions.push({ id: "list", label: "list", shortcut: "l" });
|
|
2724
|
+
actions.push({ id: "refresh", label: "refresh", shortcut: "f" });
|
|
2726
2725
|
actions.push({ id: "switch-provider", label: "ai", shortcut: "a" });
|
|
2727
2726
|
actions.push({ id: "quit", label: "quit", shortcut: "q" });
|
|
2728
2727
|
return actions;
|
|
@@ -2880,58 +2879,38 @@ function buildDashboardLines(state, actions, hint, refreshing) {
|
|
|
2880
2879
|
out(botRow(w));
|
|
2881
2880
|
return lines;
|
|
2882
2881
|
}
|
|
2883
|
-
if (state.isOnMain) {
|
|
2884
|
-
out(
|
|
2885
|
-
row(
|
|
2886
|
-
chalk3.magenta(state.branch) + chalk3.dim(" \xB7 ready to start new work"),
|
|
2887
|
-
w
|
|
2888
|
-
)
|
|
2889
|
-
);
|
|
2890
|
-
if (state.hasUncommittedChanges) {
|
|
2891
|
-
out(row(chalk3.yellow("\u25CF uncommitted changes"), w));
|
|
2892
|
-
}
|
|
2893
|
-
if (hint) {
|
|
2894
|
-
out(midRow("Hint", w));
|
|
2895
|
-
out(row(chalk3.yellow(hint), w));
|
|
2896
|
-
}
|
|
2897
|
-
out(divRow(w));
|
|
2898
|
-
if (refreshing) {
|
|
2899
|
-
out(row(chalk3.yellow("Refreshing\u2026"), w));
|
|
2900
|
-
} else {
|
|
2901
|
-
for (const line of formatCommandBar(actions, w)) {
|
|
2902
|
-
out(row(line, w));
|
|
2903
|
-
}
|
|
2904
|
-
}
|
|
2905
|
-
out(botRow(w));
|
|
2906
|
-
out("");
|
|
2907
|
-
return lines;
|
|
2908
|
-
}
|
|
2909
2882
|
const section = (title) => {
|
|
2910
2883
|
out(midRow(title, w));
|
|
2911
2884
|
};
|
|
2912
|
-
|
|
2913
|
-
|
|
2914
|
-
|
|
2915
|
-
|
|
2916
|
-
|
|
2917
|
-
|
|
2918
|
-
|
|
2919
|
-
|
|
2920
|
-
|
|
2921
|
-
|
|
2922
|
-
|
|
2923
|
-
|
|
2924
|
-
|
|
2925
|
-
|
|
2926
|
-
const
|
|
2927
|
-
|
|
2928
|
-
|
|
2929
|
-
|
|
2930
|
-
|
|
2931
|
-
|
|
2885
|
+
if (state.issue || !state.isOnMain) {
|
|
2886
|
+
section("Ticket");
|
|
2887
|
+
if (state.issue) {
|
|
2888
|
+
out(
|
|
2889
|
+
row(
|
|
2890
|
+
chalk3.cyan(`#${state.issue.number}`) + " " + chalk3.bold(truncate(state.issue.title, descMax - 6)),
|
|
2891
|
+
w
|
|
2892
|
+
)
|
|
2893
|
+
);
|
|
2894
|
+
const desc = extractDescription(state.issue.body, descMax);
|
|
2895
|
+
if (desc) out(row(chalk3.dim(desc), w));
|
|
2896
|
+
const tags = [];
|
|
2897
|
+
if (state.workflowStatus !== "none")
|
|
2898
|
+
tags.push(workflowBadge(state.workflowStatus));
|
|
2899
|
+
for (const prefix of ["type:", "priority:", "risk:", "area:"]) {
|
|
2900
|
+
const l = state.issue.labels.find((x) => x.startsWith(prefix));
|
|
2901
|
+
if (l) tags.push(chalk3.dim(l));
|
|
2902
|
+
}
|
|
2903
|
+
if (tags.length) out(row(tags.join(" "), w));
|
|
2904
|
+
} else {
|
|
2905
|
+
out(row(chalk3.dim("No linked issue"), w));
|
|
2906
|
+
}
|
|
2932
2907
|
}
|
|
2933
2908
|
section("Branch");
|
|
2934
|
-
|
|
2909
|
+
let branchLine = chalk3.magenta(state.branch);
|
|
2910
|
+
if (state.isOnMain && !state.hasUncommittedChanges) {
|
|
2911
|
+
branchLine += chalk3.dim(" \xB7 ready to start new work");
|
|
2912
|
+
}
|
|
2913
|
+
out(row(branchLine, w));
|
|
2935
2914
|
const bits = [];
|
|
2936
2915
|
if (state.commits.length > 0)
|
|
2937
2916
|
bits.push(chalk3.dim(`${state.commits.length} ahead`));
|
|
@@ -2941,48 +2920,52 @@ function buildDashboardLines(state, actions, hint, refreshing) {
|
|
|
2941
2920
|
bits.push(chalk3.green("\u25CF synced"));
|
|
2942
2921
|
}
|
|
2943
2922
|
if (bits.length) out(row(bits.join(chalk3.dim(" \xB7 ")), w));
|
|
2944
|
-
|
|
2945
|
-
|
|
2946
|
-
|
|
2947
|
-
|
|
2948
|
-
|
|
2949
|
-
row(
|
|
2950
|
-
prBadge(state.pr.state, state.pr.isDraft) + reviewBadge(state.pr.reviewDecision),
|
|
2951
|
-
w
|
|
2952
|
-
)
|
|
2953
|
-
);
|
|
2954
|
-
if (state.hasActionableFeedback) {
|
|
2955
|
-
const n = state.reviewFeedback.length;
|
|
2923
|
+
if (state.pr || !state.isOnMain) {
|
|
2924
|
+
section("Pull Request");
|
|
2925
|
+
if (state.pr) {
|
|
2926
|
+
const titleText = state.pr.title ? " " + truncate(state.pr.title, descMax - 12) : "";
|
|
2927
|
+
out(row(chalk3.cyan(`#${state.pr.number}`) + titleText, w));
|
|
2956
2928
|
out(
|
|
2957
2929
|
row(
|
|
2958
|
-
|
|
2959
|
-
w
|
|
2960
|
-
)
|
|
2961
|
-
);
|
|
2962
|
-
}
|
|
2963
|
-
if (state.hasUIChanges && state.isPlaywrightAvailable && state.config.video.enabled && state.pr.state === "open") {
|
|
2964
|
-
out(
|
|
2965
|
-
row(
|
|
2966
|
-
chalk3.cyan("UI changes detected") + chalk3.dim(" \xB7 video capture available"),
|
|
2930
|
+
prBadge(state.pr.state, state.pr.isDraft) + reviewBadge(state.pr.reviewDecision),
|
|
2967
2931
|
w
|
|
2968
2932
|
)
|
|
2969
2933
|
);
|
|
2934
|
+
if (state.hasActionableFeedback) {
|
|
2935
|
+
const n = state.reviewFeedback.length;
|
|
2936
|
+
out(
|
|
2937
|
+
row(
|
|
2938
|
+
chalk3.yellow(`${n} actionable comment${n !== 1 ? "s" : ""} pending`),
|
|
2939
|
+
w
|
|
2940
|
+
)
|
|
2941
|
+
);
|
|
2942
|
+
}
|
|
2943
|
+
if (state.hasUIChanges && state.isPlaywrightAvailable && state.config.video.enabled && state.pr.state === "open") {
|
|
2944
|
+
out(
|
|
2945
|
+
row(
|
|
2946
|
+
chalk3.cyan("UI changes detected") + chalk3.dim(" \xB7 video capture available"),
|
|
2947
|
+
w
|
|
2948
|
+
)
|
|
2949
|
+
);
|
|
2950
|
+
}
|
|
2951
|
+
out(row(chalk3.dim(state.pr.url), w));
|
|
2952
|
+
} else {
|
|
2953
|
+
out(row(chalk3.dim("No PR created"), w));
|
|
2970
2954
|
}
|
|
2971
|
-
out(row(chalk3.dim(state.pr.url), w));
|
|
2972
|
-
} else {
|
|
2973
|
-
out(row(chalk3.dim("No PR created"), w));
|
|
2974
2955
|
}
|
|
2975
|
-
|
|
2976
|
-
|
|
2977
|
-
|
|
2978
|
-
|
|
2979
|
-
|
|
2980
|
-
|
|
2981
|
-
|
|
2982
|
-
|
|
2956
|
+
if (state.commits.length > 0 || !state.isOnMain) {
|
|
2957
|
+
section("Commits");
|
|
2958
|
+
if (state.commits.length > 0) {
|
|
2959
|
+
const max = 6;
|
|
2960
|
+
for (const c of state.commits.slice(0, max)) {
|
|
2961
|
+
out(row(c.substring(0, w - 5), w));
|
|
2962
|
+
}
|
|
2963
|
+
if (state.commits.length > max) {
|
|
2964
|
+
out(row(chalk3.dim(`\u2026 and ${state.commits.length - max} more`), w));
|
|
2965
|
+
}
|
|
2966
|
+
} else {
|
|
2967
|
+
out(row(chalk3.dim("No commits"), w));
|
|
2983
2968
|
}
|
|
2984
|
-
} else {
|
|
2985
|
-
out(row(chalk3.dim("No commits"), w));
|
|
2986
2969
|
}
|
|
2987
2970
|
if (hint) {
|
|
2988
2971
|
section("Hint");
|
|
@@ -3446,8 +3429,7 @@ async function executeAction(actionId, state, dashboardLines) {
|
|
|
3446
3429
|
case "switch-provider":
|
|
3447
3430
|
await handleSwitchProvider(state, dashboardLines);
|
|
3448
3431
|
return SKIP_REFRESH;
|
|
3449
|
-
case "
|
|
3450
|
-
await handleCheckoutMain(dashboardLines);
|
|
3432
|
+
case "refresh":
|
|
3451
3433
|
return CONTINUE;
|
|
3452
3434
|
default:
|
|
3453
3435
|
return SKIP_REFRESH;
|
|
@@ -3625,21 +3607,12 @@ async function handleSwitchProvider(state, dashboardLines) {
|
|
|
3625
3607
|
setRuntimeProvider(provider);
|
|
3626
3608
|
state.config.ai.provider = provider;
|
|
3627
3609
|
}
|
|
3628
|
-
async function handleCheckoutMain(dashboardLines) {
|
|
3629
|
-
try {
|
|
3630
|
-
showStatus("Switching", "Switching to main...", dashboardLines);
|
|
3631
|
-
await execa4("git", ["checkout", "main"]);
|
|
3632
|
-
await execa4("git", ["pull"]);
|
|
3633
|
-
} catch (error) {
|
|
3634
|
-
logger.error(`Checkout failed: ${error}`);
|
|
3635
|
-
}
|
|
3636
|
-
}
|
|
3637
3610
|
async function handleList(dashboardLines) {
|
|
3638
3611
|
try {
|
|
3639
3612
|
showStatus("Loading", "Fetching tickets...", dashboardLines);
|
|
3640
3613
|
const config = loadConfig();
|
|
3641
3614
|
const workflowLabels = getWorkflowLabels(config);
|
|
3642
|
-
const [inProgress, ready, prs, localBranches] = await Promise.all([
|
|
3615
|
+
const [inProgress, ready, prs, localBranches, dirty] = await Promise.all([
|
|
3643
3616
|
listIssues({
|
|
3644
3617
|
labels: [workflowLabels.inProgress],
|
|
3645
3618
|
state: "open",
|
|
@@ -3651,7 +3624,8 @@ async function handleList(dashboardLines) {
|
|
|
3651
3624
|
limit: 20
|
|
3652
3625
|
}),
|
|
3653
3626
|
listOpenPrs(30),
|
|
3654
|
-
listLocalBranches()
|
|
3627
|
+
listLocalBranches(),
|
|
3628
|
+
hasUncommittedChanges()
|
|
3655
3629
|
]);
|
|
3656
3630
|
sortByPriority(inProgress);
|
|
3657
3631
|
sortByPriority(ready);
|
|
@@ -3659,8 +3633,16 @@ async function handleList(dashboardLines) {
|
|
|
3659
3633
|
const currentBranch = await getCurrentBranch();
|
|
3660
3634
|
const defaultBranch = await getDefaultBranch();
|
|
3661
3635
|
const items = [];
|
|
3662
|
-
const
|
|
3663
|
-
|
|
3636
|
+
const isMain = currentBranch === defaultBranch;
|
|
3637
|
+
const mainLabel = defaultBranch + (isMain ? " (current)" : "");
|
|
3638
|
+
if (dirty && !isMain) {
|
|
3639
|
+
items.push({
|
|
3640
|
+
name: `${mainLabel} (disabled - uncommitted changes)`,
|
|
3641
|
+
value: "__main_disabled__"
|
|
3642
|
+
});
|
|
3643
|
+
} else {
|
|
3644
|
+
items.push({ name: mainLabel, value: "__main__" });
|
|
3645
|
+
}
|
|
3664
3646
|
const inProgressChoices = choices.filter(
|
|
3665
3647
|
(c) => c.category === "in-progress"
|
|
3666
3648
|
);
|
|
@@ -3693,28 +3675,23 @@ async function handleList(dashboardLines) {
|
|
|
3693
3675
|
});
|
|
3694
3676
|
}
|
|
3695
3677
|
}
|
|
3696
|
-
if (choices.length === 0) {
|
|
3697
|
-
showStatus("List", "No tickets found", dashboardLines);
|
|
3698
|
-
await new Promise((r) => setTimeout(r, 1500));
|
|
3699
|
-
return false;
|
|
3700
|
-
}
|
|
3701
3678
|
const selected = await showSelect({
|
|
3702
3679
|
title: "Switch Ticket",
|
|
3703
3680
|
items,
|
|
3704
3681
|
dashboardLines
|
|
3705
3682
|
});
|
|
3706
3683
|
if (!selected) return false;
|
|
3684
|
+
if (selected === "__main_disabled__") {
|
|
3685
|
+
showStatus(
|
|
3686
|
+
"Uncommitted Changes",
|
|
3687
|
+
"Commit or stash changes before switching to main",
|
|
3688
|
+
dashboardLines
|
|
3689
|
+
);
|
|
3690
|
+
await new Promise((r) => setTimeout(r, 2e3));
|
|
3691
|
+
return false;
|
|
3692
|
+
}
|
|
3707
3693
|
if (selected === "__main__") {
|
|
3708
3694
|
if (currentBranch === defaultBranch) return false;
|
|
3709
|
-
const dirty2 = await hasUncommittedChanges();
|
|
3710
|
-
if (dirty2) {
|
|
3711
|
-
const ok = await showConfirm({
|
|
3712
|
-
title: "Uncommitted Changes",
|
|
3713
|
-
message: "You have uncommitted changes. Continue?",
|
|
3714
|
-
dashboardLines
|
|
3715
|
-
});
|
|
3716
|
-
if (!ok) return false;
|
|
3717
|
-
}
|
|
3718
3695
|
showStatus("Switching", `Switching to ${defaultBranch}...`, dashboardLines);
|
|
3719
3696
|
await checkoutBranch(defaultBranch);
|
|
3720
3697
|
return true;
|
|
@@ -3722,7 +3699,6 @@ async function handleList(dashboardLines) {
|
|
|
3722
3699
|
const issueNumber = parseInt(selected, 10);
|
|
3723
3700
|
const ticket = choices.find((c) => c.issueNumber === issueNumber);
|
|
3724
3701
|
if (!ticket) return false;
|
|
3725
|
-
const dirty = await hasUncommittedChanges();
|
|
3726
3702
|
if (dirty) {
|
|
3727
3703
|
const ok = await showConfirm({
|
|
3728
3704
|
title: "Uncommitted Changes",
|