@rotorsoft/gent 1.25.0 → 1.25.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/index.js +100 -37
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -390,8 +390,12 @@ async function invokeAIInteractive(prompt, config, providerOverride) {
|
|
|
390
390
|
};
|
|
391
391
|
}
|
|
392
392
|
case "gemini": {
|
|
393
|
+
const args = prompt.trim() ? [prompt] : [];
|
|
393
394
|
return {
|
|
394
|
-
result: execa2("gemini",
|
|
395
|
+
result: execa2("gemini", args, {
|
|
396
|
+
stdio: "inherit",
|
|
397
|
+
env: buildGeminiInteractiveEnv()
|
|
398
|
+
}),
|
|
395
399
|
provider
|
|
396
400
|
};
|
|
397
401
|
}
|
|
@@ -404,6 +408,45 @@ async function invokeAIInteractive(prompt, config, providerOverride) {
|
|
|
404
408
|
}
|
|
405
409
|
}
|
|
406
410
|
}
|
|
411
|
+
async function runInteractiveSession(prompt, config, providerOverride) {
|
|
412
|
+
const provider = providerOverride ?? config.ai.provider;
|
|
413
|
+
const savedSigint = process.rawListeners("SIGINT").slice();
|
|
414
|
+
const savedSigterm = process.rawListeners("SIGTERM").slice();
|
|
415
|
+
process.removeAllListeners("SIGINT");
|
|
416
|
+
process.removeAllListeners("SIGTERM");
|
|
417
|
+
let signalCancelled = false;
|
|
418
|
+
const handler = () => {
|
|
419
|
+
signalCancelled = true;
|
|
420
|
+
};
|
|
421
|
+
process.on("SIGINT", handler);
|
|
422
|
+
process.on("SIGTERM", handler);
|
|
423
|
+
let exitCode;
|
|
424
|
+
try {
|
|
425
|
+
const { result } = await invokeAIInteractive(
|
|
426
|
+
prompt,
|
|
427
|
+
config,
|
|
428
|
+
providerOverride
|
|
429
|
+
);
|
|
430
|
+
try {
|
|
431
|
+
const r = await result;
|
|
432
|
+
exitCode = r.exitCode ?? void 0;
|
|
433
|
+
} catch (error) {
|
|
434
|
+
if (error && typeof error === "object" && "exitCode" in error) {
|
|
435
|
+
exitCode = error.exitCode;
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
} finally {
|
|
439
|
+
process.removeAllListeners("SIGINT");
|
|
440
|
+
process.removeAllListeners("SIGTERM");
|
|
441
|
+
for (const fn of savedSigint) {
|
|
442
|
+
process.on("SIGINT", fn);
|
|
443
|
+
}
|
|
444
|
+
for (const fn of savedSigterm) {
|
|
445
|
+
process.on("SIGTERM", fn);
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
return { exitCode, signalCancelled, provider };
|
|
449
|
+
}
|
|
407
450
|
function getProviderDisplayName(provider) {
|
|
408
451
|
switch (provider) {
|
|
409
452
|
case "claude":
|
|
@@ -437,6 +480,17 @@ function isRateLimitError(error, provider) {
|
|
|
437
480
|
}
|
|
438
481
|
return false;
|
|
439
482
|
}
|
|
483
|
+
function buildGeminiInteractiveEnv() {
|
|
484
|
+
const env = { ...process.env };
|
|
485
|
+
delete env.CI;
|
|
486
|
+
delete env.CONTINUOUS_INTEGRATION;
|
|
487
|
+
for (const key of Object.keys(env)) {
|
|
488
|
+
if (key.startsWith("CI_")) {
|
|
489
|
+
delete env[key];
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
return env;
|
|
493
|
+
}
|
|
440
494
|
async function invokeClaudeInternal(options) {
|
|
441
495
|
const args = ["--print"];
|
|
442
496
|
if (options.permissionMode) {
|
|
@@ -490,15 +544,16 @@ async function invokeGeminiInternal(options) {
|
|
|
490
544
|
args.push(options.prompt);
|
|
491
545
|
if (options.printOutput) {
|
|
492
546
|
const subprocess = execa2("gemini", args, {
|
|
493
|
-
stdio: "inherit"
|
|
547
|
+
stdio: ["ignore", "inherit", "inherit"]
|
|
494
548
|
});
|
|
495
549
|
await subprocess;
|
|
496
550
|
return "";
|
|
497
551
|
} else if (options.streamOutput) {
|
|
498
552
|
return new Promise((resolve, reject) => {
|
|
499
553
|
const child = spawn("gemini", args, {
|
|
500
|
-
stdio: ["
|
|
554
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
501
555
|
});
|
|
556
|
+
child.stdin.end();
|
|
502
557
|
let output = "";
|
|
503
558
|
let firstData = true;
|
|
504
559
|
child.stdout.on("data", (chunk) => {
|
|
@@ -1488,33 +1543,23 @@ async function runCommand(issueNumberArg, options) {
|
|
|
1488
1543
|
const spinner = createSpinner(aiSpinnerText(providerName, "implement ticket"));
|
|
1489
1544
|
spinner.start();
|
|
1490
1545
|
const beforeSha = await getCurrentCommitSha();
|
|
1491
|
-
let wasCancelled = false;
|
|
1492
|
-
const handleSignal = () => {
|
|
1493
|
-
wasCancelled = true;
|
|
1494
|
-
};
|
|
1495
|
-
process.on("SIGINT", handleSignal);
|
|
1496
|
-
process.on("SIGTERM", handleSignal);
|
|
1497
1546
|
spinner.stop();
|
|
1498
1547
|
let aiExitCode;
|
|
1548
|
+
let wasCancelled = false;
|
|
1499
1549
|
let usedProvider = provider;
|
|
1500
1550
|
try {
|
|
1501
|
-
const
|
|
1551
|
+
const session = await runInteractiveSession(
|
|
1502
1552
|
prompt,
|
|
1503
1553
|
config,
|
|
1504
1554
|
options.provider
|
|
1505
1555
|
);
|
|
1506
|
-
|
|
1507
|
-
|
|
1556
|
+
aiExitCode = session.exitCode;
|
|
1557
|
+
wasCancelled = session.signalCancelled;
|
|
1558
|
+
usedProvider = session.provider;
|
|
1508
1559
|
} catch (error) {
|
|
1509
|
-
if (error && typeof error === "object" && "exitCode" in error) {
|
|
1510
|
-
aiExitCode = error.exitCode;
|
|
1511
|
-
}
|
|
1512
1560
|
logger.error(
|
|
1513
1561
|
`${getProviderDisplayName(usedProvider)} session failed: ${error}`
|
|
1514
1562
|
);
|
|
1515
|
-
} finally {
|
|
1516
|
-
process.off("SIGINT", handleSignal);
|
|
1517
|
-
process.off("SIGTERM", handleSignal);
|
|
1518
1563
|
}
|
|
1519
1564
|
logger.newline();
|
|
1520
1565
|
const commitsCreated = await hasNewCommits(beforeSha);
|
|
@@ -2127,29 +2172,19 @@ ${summary}`
|
|
|
2127
2172
|
const spinner = createSpinner(aiSpinnerText(providerName, "apply fixes"));
|
|
2128
2173
|
spinner.start();
|
|
2129
2174
|
const beforeSha = await getCurrentCommitSha();
|
|
2130
|
-
let wasCancelled = false;
|
|
2131
|
-
const handleSignal = () => {
|
|
2132
|
-
wasCancelled = true;
|
|
2133
|
-
};
|
|
2134
|
-
process.on("SIGINT", handleSignal);
|
|
2135
|
-
process.on("SIGTERM", handleSignal);
|
|
2136
2175
|
spinner.stop();
|
|
2137
2176
|
let aiExitCode;
|
|
2177
|
+
let wasCancelled = false;
|
|
2138
2178
|
try {
|
|
2139
|
-
const
|
|
2179
|
+
const session = await runInteractiveSession(
|
|
2140
2180
|
prompt,
|
|
2141
2181
|
config,
|
|
2142
2182
|
options.provider
|
|
2143
2183
|
);
|
|
2144
|
-
aiExitCode =
|
|
2184
|
+
aiExitCode = session.exitCode;
|
|
2185
|
+
wasCancelled = session.signalCancelled;
|
|
2145
2186
|
} catch (error) {
|
|
2146
|
-
if (error && typeof error === "object" && "exitCode" in error) {
|
|
2147
|
-
aiExitCode = error.exitCode;
|
|
2148
|
-
}
|
|
2149
2187
|
logger.error(`${providerName} session failed: ${error}`);
|
|
2150
|
-
} finally {
|
|
2151
|
-
process.off("SIGINT", handleSignal);
|
|
2152
|
-
process.off("SIGTERM", handleSignal);
|
|
2153
2188
|
}
|
|
2154
2189
|
logger.newline();
|
|
2155
2190
|
if (wasCancelled) {
|
|
@@ -2218,7 +2253,7 @@ import { homedir } from "os";
|
|
|
2218
2253
|
// package.json
|
|
2219
2254
|
var package_default = {
|
|
2220
2255
|
name: "@rotorsoft/gent",
|
|
2221
|
-
version: "1.25.
|
|
2256
|
+
version: "1.25.2",
|
|
2222
2257
|
description: "AI-powered GitHub workflow CLI - leverage AI (Claude, Gemini, or Codex) to create tickets, implement features, and manage PRs",
|
|
2223
2258
|
keywords: [
|
|
2224
2259
|
"cli",
|
|
@@ -3748,6 +3783,36 @@ async function executeAction(actionId, state, dashboardLines) {
|
|
|
3748
3783
|
return SKIP_REFRESH;
|
|
3749
3784
|
}
|
|
3750
3785
|
}
|
|
3786
|
+
function drainStdin() {
|
|
3787
|
+
return new Promise((resolve) => {
|
|
3788
|
+
const { stdin } = process;
|
|
3789
|
+
if (!stdin.isTTY) {
|
|
3790
|
+
resolve();
|
|
3791
|
+
return;
|
|
3792
|
+
}
|
|
3793
|
+
stdin.setRawMode(true);
|
|
3794
|
+
stdin.resume();
|
|
3795
|
+
const discard = () => {
|
|
3796
|
+
};
|
|
3797
|
+
stdin.on("data", discard);
|
|
3798
|
+
setTimeout(() => {
|
|
3799
|
+
stdin.removeListener("data", discard);
|
|
3800
|
+
stdin.pause();
|
|
3801
|
+
stdin.setRawMode(false);
|
|
3802
|
+
resolve();
|
|
3803
|
+
}, 50);
|
|
3804
|
+
});
|
|
3805
|
+
}
|
|
3806
|
+
async function runAISession(prompt, config) {
|
|
3807
|
+
try {
|
|
3808
|
+
await runInteractiveSession(prompt, config);
|
|
3809
|
+
} finally {
|
|
3810
|
+
try {
|
|
3811
|
+
await drainStdin();
|
|
3812
|
+
} catch {
|
|
3813
|
+
}
|
|
3814
|
+
}
|
|
3815
|
+
}
|
|
3751
3816
|
async function handleCommit(state, dashboardLines) {
|
|
3752
3817
|
try {
|
|
3753
3818
|
const { stdout: status } = await execa4("git", ["status", "--short"]);
|
|
@@ -3802,8 +3867,7 @@ Co-Authored-By: ${providerName} <${providerEmail}>`;
|
|
|
3802
3867
|
]);
|
|
3803
3868
|
logger.newline();
|
|
3804
3869
|
try {
|
|
3805
|
-
|
|
3806
|
-
await result;
|
|
3870
|
+
await runAISession(prompt, state.config);
|
|
3807
3871
|
return true;
|
|
3808
3872
|
} catch (error) {
|
|
3809
3873
|
logger.error(`${providerName} commit failed: ${error}`);
|
|
@@ -3854,8 +3918,7 @@ ${feedbackLines}`);
|
|
|
3854
3918
|
]);
|
|
3855
3919
|
console.log();
|
|
3856
3920
|
try {
|
|
3857
|
-
|
|
3858
|
-
await result;
|
|
3921
|
+
await runAISession(prompt, state.config);
|
|
3859
3922
|
} catch (error) {
|
|
3860
3923
|
logger.error(`${providerName} session failed: ${error}`);
|
|
3861
3924
|
}
|