@vexdo/cli 0.1.2 → 0.1.4
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 +89 -5
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -700,6 +700,29 @@ function formatElapsed(startedAt) {
|
|
|
700
700
|
const seconds = Math.max(0, Math.round((Date.now() - startedAt) / 1e3));
|
|
701
701
|
return `${String(seconds)}s`;
|
|
702
702
|
}
|
|
703
|
+
function buildVerboseStreamHandler(label) {
|
|
704
|
+
let partialLine = "";
|
|
705
|
+
return {
|
|
706
|
+
onData(chunk) {
|
|
707
|
+
partialLine += chunk.toString();
|
|
708
|
+
const lines = partialLine.split(/\r?\n/);
|
|
709
|
+
partialLine = lines.pop() ?? "";
|
|
710
|
+
for (const line of lines) {
|
|
711
|
+
if (!line) {
|
|
712
|
+
continue;
|
|
713
|
+
}
|
|
714
|
+
debug(`[codex:${label}] ${line}`);
|
|
715
|
+
}
|
|
716
|
+
},
|
|
717
|
+
flush() {
|
|
718
|
+
if (!partialLine) {
|
|
719
|
+
return;
|
|
720
|
+
}
|
|
721
|
+
debug(`[codex:${label}] ${partialLine}`);
|
|
722
|
+
partialLine = "";
|
|
723
|
+
}
|
|
724
|
+
};
|
|
725
|
+
}
|
|
703
726
|
async function checkCodexAvailable() {
|
|
704
727
|
await new Promise((resolve, reject) => {
|
|
705
728
|
execFileCb("codex", ["--version"], { timeout: CODEX_TIMEOUT_MS, encoding: "utf8" }, (error) => {
|
|
@@ -718,10 +741,13 @@ async function exec(opts) {
|
|
|
718
741
|
debug(`[codex] starting (model=${opts.model}, cwd=${opts.cwd})`);
|
|
719
742
|
}
|
|
720
743
|
return await new Promise((resolve, reject) => {
|
|
744
|
+
let liveLogsAttached = false;
|
|
745
|
+
const stdoutHandler = buildVerboseStreamHandler("stdout");
|
|
746
|
+
const stderrHandler = buildVerboseStreamHandler("stderr");
|
|
721
747
|
const heartbeat = opts.verbose ? setInterval(() => {
|
|
722
748
|
debug(`[codex] still running (${formatElapsed(startedAt)})`);
|
|
723
749
|
}, VERBOSE_HEARTBEAT_MS) : null;
|
|
724
|
-
execFileCb(
|
|
750
|
+
const child = execFileCb(
|
|
725
751
|
"codex",
|
|
726
752
|
args,
|
|
727
753
|
{ cwd: opts.cwd, timeout: CODEX_TIMEOUT_MS, encoding: "utf8", maxBuffer: 10 * 1024 * 1024 },
|
|
@@ -729,14 +755,16 @@ async function exec(opts) {
|
|
|
729
755
|
if (heartbeat) {
|
|
730
756
|
clearInterval(heartbeat);
|
|
731
757
|
}
|
|
758
|
+
stdoutHandler.flush();
|
|
759
|
+
stderrHandler.flush();
|
|
732
760
|
const normalizedStdout = stdout.trimEnd();
|
|
733
761
|
const normalizedStderr = stderr.trimEnd();
|
|
734
762
|
if (opts.verbose) {
|
|
735
763
|
debug(`[codex] finished in ${formatElapsed(startedAt)}`);
|
|
736
|
-
if (normalizedStdout) {
|
|
764
|
+
if (!liveLogsAttached && normalizedStdout) {
|
|
737
765
|
debug(normalizedStdout);
|
|
738
766
|
}
|
|
739
|
-
if (normalizedStderr) {
|
|
767
|
+
if (!liveLogsAttached && normalizedStderr) {
|
|
740
768
|
debug(normalizedStderr);
|
|
741
769
|
}
|
|
742
770
|
}
|
|
@@ -755,18 +783,69 @@ async function exec(opts) {
|
|
|
755
783
|
});
|
|
756
784
|
}
|
|
757
785
|
);
|
|
786
|
+
if (opts.verbose) {
|
|
787
|
+
const stdout = child.stdout;
|
|
788
|
+
const stderr = child.stderr;
|
|
789
|
+
if (stdout) {
|
|
790
|
+
liveLogsAttached = true;
|
|
791
|
+
stdout.on("data", stdoutHandler.onData);
|
|
792
|
+
}
|
|
793
|
+
if (stderr) {
|
|
794
|
+
liveLogsAttached = true;
|
|
795
|
+
stderr.on("data", stderrHandler.onData);
|
|
796
|
+
}
|
|
797
|
+
}
|
|
758
798
|
});
|
|
759
799
|
}
|
|
760
800
|
|
|
761
801
|
// src/lib/gh.ts
|
|
762
802
|
import { execFile as execFileCb2 } from "child_process";
|
|
763
803
|
var GH_TIMEOUT_MS = 3e4;
|
|
804
|
+
var GIT_TIMEOUT_MS = 3e4;
|
|
764
805
|
var GhNotFoundError = class extends Error {
|
|
765
806
|
constructor() {
|
|
766
807
|
super("gh CLI not found. Install it: https://cli.github.com");
|
|
767
808
|
this.name = "GhNotFoundError";
|
|
768
809
|
}
|
|
769
810
|
};
|
|
811
|
+
var GitCommandError = class extends Error {
|
|
812
|
+
exitCode;
|
|
813
|
+
stderr;
|
|
814
|
+
constructor(args, exitCode, stderr) {
|
|
815
|
+
super(`git ${args.join(" ")} failed (exit ${String(exitCode)}): ${stderr}`);
|
|
816
|
+
this.name = "GitCommandError";
|
|
817
|
+
this.exitCode = exitCode;
|
|
818
|
+
this.stderr = stderr;
|
|
819
|
+
}
|
|
820
|
+
};
|
|
821
|
+
async function execGit(args, cwd) {
|
|
822
|
+
await new Promise((resolve, reject) => {
|
|
823
|
+
execFileCb2("git", args, { cwd, timeout: GIT_TIMEOUT_MS, encoding: "utf8" }, (error, _stdout, stderr) => {
|
|
824
|
+
if (error) {
|
|
825
|
+
const exitCode = typeof error.code === "number" ? error.code : -1;
|
|
826
|
+
reject(new GitCommandError(args, exitCode, (stderr || error.message).trim()));
|
|
827
|
+
return;
|
|
828
|
+
}
|
|
829
|
+
resolve();
|
|
830
|
+
});
|
|
831
|
+
});
|
|
832
|
+
}
|
|
833
|
+
function isNoUpstreamError(error) {
|
|
834
|
+
const text = error.stderr.toLowerCase();
|
|
835
|
+
return text.includes("no upstream configured for branch") || text.includes("has no upstream branch");
|
|
836
|
+
}
|
|
837
|
+
async function pushCurrentBranch(cwd) {
|
|
838
|
+
try {
|
|
839
|
+
await execGit(["rev-parse", "--abbrev-ref", "--symbolic-full-name", "@{u}"], cwd);
|
|
840
|
+
await execGit(["push"], cwd);
|
|
841
|
+
} catch (error) {
|
|
842
|
+
if (error instanceof GitCommandError && isNoUpstreamError(error)) {
|
|
843
|
+
await execGit(["push", "--set-upstream", "origin", "HEAD"], cwd);
|
|
844
|
+
return;
|
|
845
|
+
}
|
|
846
|
+
throw error;
|
|
847
|
+
}
|
|
848
|
+
}
|
|
770
849
|
async function checkGhAvailable() {
|
|
771
850
|
await new Promise((resolve, reject) => {
|
|
772
851
|
execFileCb2("gh", ["--version"], { timeout: GH_TIMEOUT_MS, encoding: "utf8" }, (error) => {
|
|
@@ -780,6 +859,11 @@ async function checkGhAvailable() {
|
|
|
780
859
|
}
|
|
781
860
|
async function createPr(opts) {
|
|
782
861
|
const base = opts.base ?? "main";
|
|
862
|
+
try {
|
|
863
|
+
await pushCurrentBranch(opts.cwd);
|
|
864
|
+
} catch (error) {
|
|
865
|
+
throw new Error(`Failed to push current branch before creating PR: ${error instanceof Error ? error.message : String(error)}`);
|
|
866
|
+
}
|
|
783
867
|
return await new Promise((resolve, reject) => {
|
|
784
868
|
execFileCb2(
|
|
785
869
|
"gh",
|
|
@@ -813,7 +897,7 @@ import path5 from "path";
|
|
|
813
897
|
|
|
814
898
|
// src/lib/git.ts
|
|
815
899
|
import { execFile as execFileCb3 } from "child_process";
|
|
816
|
-
var
|
|
900
|
+
var GIT_TIMEOUT_MS2 = 3e4;
|
|
817
901
|
var GitError = class extends Error {
|
|
818
902
|
command;
|
|
819
903
|
exitCode;
|
|
@@ -828,7 +912,7 @@ var GitError = class extends Error {
|
|
|
828
912
|
};
|
|
829
913
|
async function exec2(args, cwd) {
|
|
830
914
|
return new Promise((resolve, reject) => {
|
|
831
|
-
execFileCb3("git", args, { cwd, timeout:
|
|
915
|
+
execFileCb3("git", args, { cwd, timeout: GIT_TIMEOUT_MS2, encoding: "utf8" }, (error, stdout, stderr) => {
|
|
832
916
|
if (error) {
|
|
833
917
|
const exitCode = typeof error.code === "number" ? error.code : -1;
|
|
834
918
|
reject(new GitError(args, exitCode, (stderr || error.message).trim()));
|