Files
openclaw/src/commands/doctor-session-sqlite-github-issue.ts

55 lines
1.8 KiB
TypeScript

/** Creates GitHub issues for sanitized session SQLite recovery reports. */
import { spawnSync, type SpawnSyncReturns } from "node:child_process";
import type { SessionSqliteMigrationFailureIssue } from "./doctor-session-sqlite-types.js";
type SessionSqliteGithubIssueCreateResult =
| { ok: true; url: string }
| { fallbackUrl: string; message: string; ok: false };
type SpawnGh = (
args: readonly string[],
options: { input: string },
) => Pick<SpawnSyncReturns<Buffer>, "error" | "status" | "stderr" | "stdout">;
const GITHUB_ISSUE_CREATE_TIMEOUT_MS = 30_000;
/** Creates an openclaw/openclaw issue through the GitHub CLI using sanitized stdin. */
export function createSessionSqliteGithubIssue(
issue: SessionSqliteMigrationFailureIssue,
spawnGh: SpawnGh = defaultSpawnGh,
): SessionSqliteGithubIssueCreateResult {
const result = spawnGh(
["issue", "create", "--repo", "openclaw/openclaw", "--title", issue.title, "--body-file", "-"],
{ input: issue.body },
);
if (!result.error && result.status === 0) {
const url = String(result.stdout).trim().split(/\r?\n/).at(-1);
return {
ok: true,
url: url && url.length > 0 ? url : "https://github.com/openclaw/openclaw/issues",
};
}
const stderr = String(result.stderr).trim();
const error = result.error
? result.error.message
: stderr || `gh exited ${result.status ?? "unknown"}`;
return {
fallbackUrl: issue.url,
message: error,
ok: false,
};
}
function defaultSpawnGh(
args: readonly string[],
options: { input: string },
): Pick<SpawnSyncReturns<Buffer>, "error" | "status" | "stderr" | "stdout"> {
return spawnSync("gh", [...args], {
encoding: "buffer",
input: options.input,
killSignal: "SIGKILL",
maxBuffer: 1024 * 1024,
timeout: GITHUB_ISSUE_CREATE_TIMEOUT_MS,
});
}