@rotorsoft/gent 1.23.0 → 1.24.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/{chunk-ZDOEOZDC.js → chunk-OIHSXI5X.js} +2 -2
- package/dist/{chunk-HCJWQPMW.js → chunk-P5MZOU4B.js} +1 -5
- package/dist/{chunk-HCJWQPMW.js.map → chunk-P5MZOU4B.js.map} +1 -1
- package/dist/{chunk-ZQDWILU5.js → chunk-YS7HWP4W.js} +2 -2
- package/dist/github-remote-G6UKRDUB.js +9 -0
- package/dist/index.js +75 -109
- package/dist/index.js.map +1 -1
- package/dist/setup-labels-FZEN5TKM.js +9 -0
- package/package.json +1 -1
- package/dist/github-remote-4TLUL2HX.js +0 -9
- package/dist/setup-labels-2SNO3QQL.js +0 -9
- /package/dist/{chunk-ZDOEOZDC.js.map → chunk-OIHSXI5X.js.map} +0 -0
- /package/dist/{chunk-ZQDWILU5.js.map → chunk-YS7HWP4W.js.map} +0 -0
- /package/dist/{github-remote-4TLUL2HX.js.map → github-remote-G6UKRDUB.js.map} +0 -0
- /package/dist/{setup-labels-2SNO3QQL.js.map → setup-labels-FZEN5TKM.js.map} +0 -0
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
githubRemoteCommand
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-OIHSXI5X.js";
|
|
5
5
|
import {
|
|
6
6
|
aiSpinnerText,
|
|
7
7
|
buildIssueLabels,
|
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
setupLabelsCommand,
|
|
12
12
|
sortByPriority,
|
|
13
13
|
withSpinner
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-YS7HWP4W.js";
|
|
15
15
|
import {
|
|
16
16
|
addIssueComment,
|
|
17
17
|
addPrComment,
|
|
@@ -22,7 +22,6 @@ import {
|
|
|
22
22
|
checkGeminiCli,
|
|
23
23
|
checkGhAuth,
|
|
24
24
|
checkGitRepo,
|
|
25
|
-
checkInitialized,
|
|
26
25
|
checkLabelsExist,
|
|
27
26
|
checkoutBranch,
|
|
28
27
|
colors,
|
|
@@ -64,7 +63,7 @@ import {
|
|
|
64
63
|
sanitizeSlug,
|
|
65
64
|
setRuntimeProvider,
|
|
66
65
|
updateIssueLabels
|
|
67
|
-
} from "./chunk-
|
|
66
|
+
} from "./chunk-P5MZOU4B.js";
|
|
68
67
|
|
|
69
68
|
// src/index.ts
|
|
70
69
|
import { Command } from "commander";
|
|
@@ -208,7 +207,7 @@ All AI commits should include the Co-Authored-By trailer as specified in the tas
|
|
|
208
207
|
- [E.g., "Always use async/await over callbacks"]
|
|
209
208
|
`;
|
|
210
209
|
async function initCommand(options) {
|
|
211
|
-
logger.bold("Initializing gent workflow...");
|
|
210
|
+
logger.bold("Initializing gent workflow (optional \u2014 gent works with sensible defaults)...");
|
|
212
211
|
logger.newline();
|
|
213
212
|
const isGitRepo = await checkGitRepo();
|
|
214
213
|
if (!isGitRepo) {
|
|
@@ -286,7 +285,7 @@ async function initCommand(options) {
|
|
|
286
285
|
}
|
|
287
286
|
]);
|
|
288
287
|
if (createRemote) {
|
|
289
|
-
const { githubRemoteCommand: githubRemoteCommand2 } = await import("./github-remote-
|
|
288
|
+
const { githubRemoteCommand: githubRemoteCommand2 } = await import("./github-remote-G6UKRDUB.js");
|
|
290
289
|
const success = await githubRemoteCommand2();
|
|
291
290
|
if (success) {
|
|
292
291
|
const { setupLabels } = await inquirer.prompt([
|
|
@@ -298,7 +297,7 @@ async function initCommand(options) {
|
|
|
298
297
|
}
|
|
299
298
|
]);
|
|
300
299
|
if (setupLabels) {
|
|
301
|
-
const { setupLabelsCommand: setupLabelsCommand2 } = await import("./setup-labels-
|
|
300
|
+
const { setupLabelsCommand: setupLabelsCommand2 } = await import("./setup-labels-FZEN5TKM.js");
|
|
302
301
|
await setupLabelsCommand2();
|
|
303
302
|
}
|
|
304
303
|
}
|
|
@@ -322,7 +321,7 @@ async function initCommand(options) {
|
|
|
322
321
|
}
|
|
323
322
|
]);
|
|
324
323
|
if (setupLabels) {
|
|
325
|
-
const { setupLabelsCommand: setupLabelsCommand2 } = await import("./setup-labels-
|
|
324
|
+
const { setupLabelsCommand: setupLabelsCommand2 } = await import("./setup-labels-FZEN5TKM.js");
|
|
326
325
|
await setupLabelsCommand2();
|
|
327
326
|
}
|
|
328
327
|
}
|
|
@@ -335,6 +334,7 @@ import chalk from "chalk";
|
|
|
335
334
|
// src/lib/ai-provider.ts
|
|
336
335
|
import { spawn } from "child_process";
|
|
337
336
|
import { execa as execa2 } from "execa";
|
|
337
|
+
var AI_DEFAULT_TIMEOUT_MS = 3e4;
|
|
338
338
|
async function getOtherAvailableProviders(currentProvider) {
|
|
339
339
|
const allProviders = ["claude", "gemini", "codex"];
|
|
340
340
|
const others = allProviders.filter((p) => p !== currentProvider);
|
|
@@ -480,7 +480,8 @@ async function invokeClaudeInternal(options) {
|
|
|
480
480
|
child.on("error", reject);
|
|
481
481
|
});
|
|
482
482
|
} else {
|
|
483
|
-
const
|
|
483
|
+
const timeout = options.timeout ?? AI_DEFAULT_TIMEOUT_MS;
|
|
484
|
+
const { stdout } = await execa2("claude", args, { timeout });
|
|
484
485
|
return stdout;
|
|
485
486
|
}
|
|
486
487
|
}
|
|
@@ -524,7 +525,8 @@ async function invokeGeminiInternal(options) {
|
|
|
524
525
|
child.on("error", reject);
|
|
525
526
|
});
|
|
526
527
|
} else {
|
|
527
|
-
const
|
|
528
|
+
const timeout = options.timeout ?? AI_DEFAULT_TIMEOUT_MS;
|
|
529
|
+
const { stdout } = await execa2("gemini", args, { timeout });
|
|
528
530
|
return stdout;
|
|
529
531
|
}
|
|
530
532
|
}
|
|
@@ -567,7 +569,8 @@ async function invokeCodexInternal(options) {
|
|
|
567
569
|
child.on("error", reject);
|
|
568
570
|
});
|
|
569
571
|
} else {
|
|
570
|
-
const
|
|
572
|
+
const timeout = options.timeout ?? AI_DEFAULT_TIMEOUT_MS;
|
|
573
|
+
const { stdout } = await execa2("codex", args, { timeout });
|
|
571
574
|
return stdout;
|
|
572
575
|
}
|
|
573
576
|
}
|
|
@@ -695,21 +698,27 @@ ${issue ? `Closes #${issue.number}` : ""}
|
|
|
695
698
|
|
|
696
699
|
Only output the PR description, nothing else.`;
|
|
697
700
|
}
|
|
698
|
-
function
|
|
699
|
-
const
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
${
|
|
701
|
+
function buildCommitPrompt(issueNumber, issueTitle, config) {
|
|
702
|
+
const provider = config.ai.provider;
|
|
703
|
+
const providerName = getProviderDisplayName(provider);
|
|
704
|
+
const providerEmail = getProviderEmail(provider);
|
|
705
|
+
const issueContext = issueNumber ? `Related Issue: #${issueNumber}${issueTitle ? ` - ${issueTitle}` : ""}` : "No linked issue";
|
|
706
|
+
return `Create a git commit for the staged changes.
|
|
707
|
+
|
|
708
|
+
Context: ${issueContext}
|
|
706
709
|
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
-
|
|
712
|
-
-
|
|
710
|
+
Steps:
|
|
711
|
+
1. Run \`git diff --cached --stat\` to see what files changed
|
|
712
|
+
2. Run \`git diff --cached\` to see the actual changes
|
|
713
|
+
3. Generate a commit message following these rules:
|
|
714
|
+
- Use conventional commit format: <type>: <short description>
|
|
715
|
+
- Types: feat, fix, refactor, chore, docs, test, style, perf
|
|
716
|
+
- Keep the first line under 72 characters
|
|
717
|
+
- Add a blank line, then: Co-Authored-By: ${providerName} <${providerEmail}>
|
|
718
|
+
4. Run \`git commit -m "<your message>"\` to create the commit
|
|
719
|
+
5. Exit when done
|
|
720
|
+
|
|
721
|
+
Do not ask for confirmation - just create the commit.`;
|
|
713
722
|
}
|
|
714
723
|
function parseTicketMeta(output) {
|
|
715
724
|
const metaMatch = output.match(
|
|
@@ -2207,7 +2216,7 @@ import { homedir } from "os";
|
|
|
2207
2216
|
// package.json
|
|
2208
2217
|
var package_default = {
|
|
2209
2218
|
name: "@rotorsoft/gent",
|
|
2210
|
-
version: "1.
|
|
2219
|
+
version: "1.24.1",
|
|
2211
2220
|
description: "AI-powered GitHub workflow CLI - leverage AI (Claude, Gemini, or Codex) to create tickets, implement features, and manage PRs",
|
|
2212
2221
|
keywords: [
|
|
2213
2222
|
"cli",
|
|
@@ -2697,7 +2706,7 @@ async function aggregateState() {
|
|
|
2697
2706
|
getUnpushedCommits()
|
|
2698
2707
|
]);
|
|
2699
2708
|
const hasRemote = repoInfo !== null;
|
|
2700
|
-
if (
|
|
2709
|
+
if (hasRemote && envCache.hasLabels === null) {
|
|
2701
2710
|
envCache.hasLabels = await checkLabelsExist().catch(() => false);
|
|
2702
2711
|
}
|
|
2703
2712
|
const hasLabels = envCache.hasLabels ?? false;
|
|
@@ -2781,14 +2790,14 @@ function getAvailableActions(state) {
|
|
|
2781
2790
|
actions.push({ id: "quit", label: "quit", shortcut: "q" });
|
|
2782
2791
|
return actions;
|
|
2783
2792
|
}
|
|
2784
|
-
const
|
|
2785
|
-
|
|
2786
|
-
if (needsInit) {
|
|
2787
|
-
actions.push({ id: "init", label: "init", shortcut: "i" });
|
|
2788
|
-
} else if (needsLabels) {
|
|
2793
|
+
const needsLabels = state.hasValidRemote && !state.hasLabels;
|
|
2794
|
+
if (needsLabels) {
|
|
2789
2795
|
actions.push({ id: "setup-labels", label: "setup-labels", shortcut: "b" });
|
|
2790
2796
|
}
|
|
2791
|
-
|
|
2797
|
+
if (!state.hasConfig) {
|
|
2798
|
+
actions.push({ id: "init", label: "init", shortcut: "i" });
|
|
2799
|
+
}
|
|
2800
|
+
const isSetUp = !state.hasValidRemote || state.hasLabels;
|
|
2792
2801
|
if (isSetUp && state.hasValidRemote) {
|
|
2793
2802
|
actions.push({ id: "create", label: "new", shortcut: "n" });
|
|
2794
2803
|
}
|
|
@@ -3105,18 +3114,17 @@ function buildDashboardLines(state, actions, hint, refreshing, versionCheck) {
|
|
|
3105
3114
|
out(row(chalk3.dim(" No commits"), w));
|
|
3106
3115
|
}
|
|
3107
3116
|
}
|
|
3108
|
-
if (!state.
|
|
3109
|
-
section("Setup");
|
|
3110
|
-
out(row(chalk3.yellow("Step 1: Initialize gent configuration"), w));
|
|
3111
|
-
out(row(chalk3.dim("Press [i] to run gent init"), w));
|
|
3112
|
-
} else if (!state.hasValidRemote) {
|
|
3117
|
+
if (!state.hasValidRemote) {
|
|
3113
3118
|
section("Setup");
|
|
3114
|
-
out(row(chalk3.yellow("Step
|
|
3119
|
+
out(row(chalk3.yellow("Step 1: Create a GitHub repository"), w));
|
|
3115
3120
|
out(row(chalk3.dim("Press [g] to create a GitHub repo and push"), w));
|
|
3116
3121
|
} else if (!state.hasLabels) {
|
|
3117
3122
|
section("Setup");
|
|
3118
|
-
out(row(chalk3.yellow("Step
|
|
3123
|
+
out(row(chalk3.yellow("Step 2: Create workflow labels"), w));
|
|
3119
3124
|
out(row(chalk3.dim("Press [b] to set up labels"), w));
|
|
3125
|
+
} else if (!state.hasConfig) {
|
|
3126
|
+
section("Tip");
|
|
3127
|
+
out(row(chalk3.dim("Press [i] to customize configuration (optional)"), w));
|
|
3120
3128
|
} else if (hint) {
|
|
3121
3129
|
section("Hint");
|
|
3122
3130
|
out(row(chalk3.yellow(hint), w));
|
|
@@ -3631,7 +3639,6 @@ function showStatus(title, message, dashboardLines) {
|
|
|
3631
3639
|
}
|
|
3632
3640
|
|
|
3633
3641
|
// src/commands/tui.ts
|
|
3634
|
-
var CANCEL = /* @__PURE__ */ Symbol("cancel");
|
|
3635
3642
|
async function waitForKey(validKeys) {
|
|
3636
3643
|
return new Promise((resolve) => {
|
|
3637
3644
|
const { stdin } = process;
|
|
@@ -3748,13 +3755,6 @@ async function handleCommit(state, dashboardLines) {
|
|
|
3748
3755
|
return false;
|
|
3749
3756
|
}
|
|
3750
3757
|
await execa4("git", ["add", "-A"]);
|
|
3751
|
-
const { stdout: diffStat } = await execa4("git", [
|
|
3752
|
-
"diff",
|
|
3753
|
-
"--cached",
|
|
3754
|
-
"--stat"
|
|
3755
|
-
]);
|
|
3756
|
-
const { stdout: diffPatch } = await execa4("git", ["diff", "--cached"]);
|
|
3757
|
-
const diffContent = (diffStat + "\n\n" + diffPatch).slice(0, 4e3);
|
|
3758
3758
|
const issueNumber = state.issue?.number ?? null;
|
|
3759
3759
|
const issueTitle = state.issue?.title ?? null;
|
|
3760
3760
|
const provider = state.config.ai.provider;
|
|
@@ -3771,75 +3771,45 @@ async function handleCommit(state, dashboardLines) {
|
|
|
3771
3771
|
await execa4("git", ["reset", "HEAD"]);
|
|
3772
3772
|
return false;
|
|
3773
3773
|
}
|
|
3774
|
-
let message;
|
|
3775
3774
|
if (mode === "manual") {
|
|
3776
3775
|
const input = await showInput({
|
|
3777
3776
|
title: "Commit Message",
|
|
3778
3777
|
label: "Enter commit message:",
|
|
3779
3778
|
dashboardLines
|
|
3780
3779
|
});
|
|
3781
|
-
|
|
3782
|
-
|
|
3783
|
-
|
|
3784
|
-
|
|
3785
|
-
|
|
3786
|
-
|
|
3787
|
-
issueTitle,
|
|
3788
|
-
state,
|
|
3789
|
-
dashboardLines
|
|
3790
|
-
);
|
|
3791
|
-
}
|
|
3792
|
-
if (message === CANCEL) {
|
|
3793
|
-
await execa4("git", ["reset", "HEAD"]);
|
|
3794
|
-
return false;
|
|
3795
|
-
}
|
|
3796
|
-
const confirmed = await showConfirm({
|
|
3797
|
-
title: "Commit",
|
|
3798
|
-
message: `Message: ${message.length > 50 ? message.slice(0, 50) + "\u2026" : message}`,
|
|
3799
|
-
dashboardLines
|
|
3800
|
-
});
|
|
3801
|
-
if (!confirmed) {
|
|
3802
|
-
await execa4("git", ["reset", "HEAD"]);
|
|
3803
|
-
return false;
|
|
3804
|
-
}
|
|
3805
|
-
const providerEmail = getProviderEmail(provider);
|
|
3806
|
-
const fullMessage = `${message}
|
|
3780
|
+
if (!input) {
|
|
3781
|
+
await execa4("git", ["reset", "HEAD"]);
|
|
3782
|
+
return false;
|
|
3783
|
+
}
|
|
3784
|
+
const providerEmail = getProviderEmail(provider);
|
|
3785
|
+
const fullMessage = `${input}
|
|
3807
3786
|
|
|
3808
3787
|
Co-Authored-By: ${providerName} <${providerEmail}>`;
|
|
3809
|
-
|
|
3810
|
-
|
|
3811
|
-
|
|
3788
|
+
showStatus("Committing", "Committing changes...", dashboardLines);
|
|
3789
|
+
await execa4("git", ["commit", "-m", fullMessage]);
|
|
3790
|
+
return true;
|
|
3791
|
+
} else {
|
|
3792
|
+
const prompt = buildCommitPrompt(issueNumber, issueTitle, state.config);
|
|
3793
|
+
clearScreen();
|
|
3794
|
+
renderActionPanel(`${providerName} Commit`, [
|
|
3795
|
+
"Creating commit for staged changes...",
|
|
3796
|
+
issueNumber ? `Related: #${issueNumber} ${issueTitle ?? ""}` : "No linked issue"
|
|
3797
|
+
]);
|
|
3798
|
+
console.log();
|
|
3799
|
+
try {
|
|
3800
|
+
const { result } = await invokeAIInteractive(prompt, state.config);
|
|
3801
|
+
await result;
|
|
3802
|
+
return true;
|
|
3803
|
+
} catch (error) {
|
|
3804
|
+
logger.error(`${providerName} commit failed: ${error}`);
|
|
3805
|
+
return false;
|
|
3806
|
+
}
|
|
3807
|
+
}
|
|
3812
3808
|
} catch (error) {
|
|
3813
3809
|
logger.error(`Commit failed: ${error}`);
|
|
3814
3810
|
return false;
|
|
3815
3811
|
}
|
|
3816
3812
|
}
|
|
3817
|
-
async function generateCommitMessage(diffContent, issueNumber, issueTitle, state, dashboardLines) {
|
|
3818
|
-
try {
|
|
3819
|
-
const prompt = buildCommitMessagePrompt(
|
|
3820
|
-
diffContent,
|
|
3821
|
-
issueNumber,
|
|
3822
|
-
issueTitle
|
|
3823
|
-
);
|
|
3824
|
-
const result = await invokeAI({ prompt, streamOutput: false }, state.config);
|
|
3825
|
-
let message = result.output.trim().split("\n")[0].trim();
|
|
3826
|
-
for (const q of ['"', "'", "`"]) {
|
|
3827
|
-
if (message.startsWith(q) && message.endsWith(q)) {
|
|
3828
|
-
message = message.slice(1, -1);
|
|
3829
|
-
break;
|
|
3830
|
-
}
|
|
3831
|
-
}
|
|
3832
|
-
message = message.replace(/^```\w*\s*/, "").replace(/\s*```$/, "");
|
|
3833
|
-
return message;
|
|
3834
|
-
} catch {
|
|
3835
|
-
const input = await showInput({
|
|
3836
|
-
title: "Commit Message",
|
|
3837
|
-
label: "AI generation failed. Enter commit message:",
|
|
3838
|
-
dashboardLines
|
|
3839
|
-
});
|
|
3840
|
-
return input || CANCEL;
|
|
3841
|
-
}
|
|
3842
|
-
}
|
|
3843
3813
|
async function handleRun(state) {
|
|
3844
3814
|
if (!state.issue) {
|
|
3845
3815
|
logger.error("No linked issue found");
|
|
@@ -4148,10 +4118,6 @@ function startVersionCheck() {
|
|
|
4148
4118
|
});
|
|
4149
4119
|
}
|
|
4150
4120
|
async function checkPrerequisites() {
|
|
4151
|
-
if (!checkInitialized()) {
|
|
4152
|
-
logger.warning('Repository not initialized. Run "gent init" to set up this repository.');
|
|
4153
|
-
return false;
|
|
4154
|
-
}
|
|
4155
4121
|
const repoInfo = await getRepoInfo();
|
|
4156
4122
|
if (!repoInfo) {
|
|
4157
4123
|
logger.warning('No GitHub remote found. Run "gent github-remote" to create one.');
|
|
@@ -4172,7 +4138,7 @@ program.name("gent").description(
|
|
|
4172
4138
|
startVersionCheck();
|
|
4173
4139
|
}
|
|
4174
4140
|
});
|
|
4175
|
-
program.command("init").description("Initialize gent workflow in current repository").option("-f, --force", "Overwrite existing configuration").action(async (options) => {
|
|
4141
|
+
program.command("init").description("Initialize gent workflow in current repository (optional \u2014 for customization)").option("-f, --force", "Overwrite existing configuration").action(async (options) => {
|
|
4176
4142
|
await initCommand(options);
|
|
4177
4143
|
});
|
|
4178
4144
|
program.command("setup-labels").description("Setup GitHub labels for AI workflow").action(async () => {
|