mirror of
https://github.com/moltbot/moltbot.git
synced 2026-05-13 15:47:28 +00:00
feat(telegram): polish Crabbox proof captures
This commit is contained in:
@@ -51,6 +51,29 @@ proof needs something else.
|
||||
|
||||
## While Testing
|
||||
|
||||
For visual proof, first send or identify a bottom marker message, then open the
|
||||
group/topic directly by message id:
|
||||
|
||||
```bash
|
||||
pnpm qa:telegram-user:crabbox -- view \
|
||||
--session .artifacts/qa-e2e/telegram-user-crabbox/pr-review/session.json \
|
||||
--message-id <message-id>
|
||||
```
|
||||
|
||||
This uses Telegram Desktop directly with `tg://privatepost`, not `xdg-open`.
|
||||
It also resizes Telegram to `650x1000` at the tested desktop position so
|
||||
Telegram switches to single-chat mode with no left chat list or right info
|
||||
pane. Do not press Escape after this; Escape can close the selected chat.
|
||||
|
||||
Bottom behavior matters:
|
||||
|
||||
- deep-linking to the newest message keeps Telegram pinned to the bottom, so
|
||||
later messages appear live in the recording
|
||||
- deep-linking to an older message does not auto-scroll to new arrivals; link
|
||||
again to the newest/final marker instead of clicking the down-arrow
|
||||
- `650px` is the largest tested clean width; `660px` switches Telegram back to
|
||||
split/sidebar layout
|
||||
|
||||
Send as the real Telegram user:
|
||||
|
||||
```bash
|
||||
@@ -100,13 +123,17 @@ Always finish or explicitly keep the box:
|
||||
|
||||
```bash
|
||||
pnpm qa:telegram-user:crabbox -- finish \
|
||||
--session .artifacts/qa-e2e/telegram-user-crabbox/pr-review/session.json
|
||||
--session .artifacts/qa-e2e/telegram-user-crabbox/pr-review/session.json \
|
||||
--preview-crop telegram-window
|
||||
```
|
||||
|
||||
`finish` stops recording, creates motion-trimmed MP4/GIF artifacts, captures a
|
||||
final screenshot and logs, releases the Convex credential, stops the local SUT,
|
||||
and stops the Crabbox lease. Pass `--keep-box` only when a human needs to
|
||||
continue VNC debugging after the credential is released.
|
||||
and stops the Crabbox lease. `--preview-crop telegram-window` also creates a
|
||||
fixed-geometry GIF from the tested Telegram proof window for clean side-by-side
|
||||
PR tables; the full desktop video/GIF remains in the artifact directory. Pass
|
||||
`--keep-box` only when a human needs to continue VNC debugging after the
|
||||
credential is released.
|
||||
|
||||
After any failure or interruption, verify cleanup:
|
||||
|
||||
@@ -129,19 +156,21 @@ pnpm qa:telegram-user:crabbox -- publish \
|
||||
--summary 'Telegram real-user Crabbox session motion GIF'
|
||||
```
|
||||
|
||||
This copies only `telegram-user-crabbox-session-motion.gif` into a temporary
|
||||
publish bundle and comments that GIF. Use `--full-artifacts` only when the PR
|
||||
needs logs or JSON output. Never publish credential payloads, local env files,
|
||||
TDLib databases, Telegram Desktop profiles, or raw session archives.
|
||||
This copies only the useful GIF into a temporary publish bundle and comments
|
||||
that GIF. If `finish --preview-crop telegram-window` produced a cropped GIF,
|
||||
publish uses that; otherwise it uses `telegram-user-crabbox-session-motion.gif`.
|
||||
Use `--full-artifacts` only when the PR needs logs or JSON output. Never publish
|
||||
credential payloads, local env files, TDLib databases, Telegram Desktop
|
||||
profiles, or raw session archives.
|
||||
|
||||
For before/after proof, run one session on `main` and one on the PR head, then
|
||||
publish only the intended GIFs from a clean bundle:
|
||||
|
||||
```bash
|
||||
mkdir -p .artifacts/qa-e2e/telegram-user-crabbox/pr-123/comparison
|
||||
cp <main-output>/telegram-user-crabbox-session-motion.gif \
|
||||
cp <main-output>/telegram-user-crabbox-session-motion-telegram-window.gif \
|
||||
.artifacts/qa-e2e/telegram-user-crabbox/pr-123/comparison/main-before.gif
|
||||
cp <pr-output>/telegram-user-crabbox-session-motion.gif \
|
||||
cp <pr-output>/telegram-user-crabbox-session-motion-telegram-window.gif \
|
||||
.artifacts/qa-e2e/telegram-user-crabbox/pr-123/comparison/pr-after.gif
|
||||
crabbox artifacts publish \
|
||||
--repo openclaw/openclaw \
|
||||
|
||||
@@ -13,6 +13,8 @@ type CommandResult = {
|
||||
|
||||
type JsonObject = Record<string, unknown>;
|
||||
|
||||
type PreviewCrop = "telegram-window";
|
||||
|
||||
type CrabboxInspect = {
|
||||
host?: string;
|
||||
id?: string;
|
||||
@@ -25,7 +27,16 @@ type CrabboxInspect = {
|
||||
|
||||
type Options = {
|
||||
crabboxClass: string;
|
||||
command: "finish" | "probe" | "publish" | "run" | "screenshot" | "send" | "start" | "status";
|
||||
command:
|
||||
| "finish"
|
||||
| "probe"
|
||||
| "publish"
|
||||
| "run"
|
||||
| "screenshot"
|
||||
| "send"
|
||||
| "start"
|
||||
| "status"
|
||||
| "view";
|
||||
crabboxBin: string;
|
||||
desktopChatTitle: string;
|
||||
dryRun: boolean;
|
||||
@@ -38,7 +49,10 @@ type Options = {
|
||||
mockResponseText: string;
|
||||
mockPort: number;
|
||||
outputDir: string;
|
||||
messageId?: string;
|
||||
previewCrop?: PreviewCrop;
|
||||
previewFps: number;
|
||||
previewCropWidth: number;
|
||||
previewWidth: number;
|
||||
provider: string;
|
||||
publishFullArtifacts: boolean;
|
||||
@@ -121,6 +135,13 @@ const DEFAULT_USER_DRIVER = `${DEFAULT_SKILL_DIR}/scripts/user-driver.py`;
|
||||
const DEFAULT_OUTPUT_ROOT = ".artifacts/qa-e2e/telegram-user-crabbox";
|
||||
const REMOTE_ROOT = "/tmp/openclaw-telegram-user-crabbox";
|
||||
const CREDENTIAL_SCRIPT = fileURLToPath(new URL("./telegram-user-credential.ts", import.meta.url));
|
||||
const TELEGRAM_PROOF_VIEW = {
|
||||
cropWidth: 520,
|
||||
height: 1000,
|
||||
width: 650,
|
||||
x: 635,
|
||||
y: 40,
|
||||
};
|
||||
|
||||
function usageText() {
|
||||
return [
|
||||
@@ -129,6 +150,7 @@ function usageText() {
|
||||
" node --import tsx scripts/e2e/telegram-user-crabbox-proof.ts start [--tdlib-url <url>]",
|
||||
" node --import tsx scripts/e2e/telegram-user-crabbox-proof.ts send --session <session.json> --text <text>",
|
||||
" node --import tsx scripts/e2e/telegram-user-crabbox-proof.ts run --session <session.json> -- <remote command>",
|
||||
" node --import tsx scripts/e2e/telegram-user-crabbox-proof.ts view --session <session.json> --message-id <id>",
|
||||
" node --import tsx scripts/e2e/telegram-user-crabbox-proof.ts screenshot --session <session.json>",
|
||||
" node --import tsx scripts/e2e/telegram-user-crabbox-proof.ts status --session <session.json>",
|
||||
" node --import tsx scripts/e2e/telegram-user-crabbox-proof.ts finish --session <session.json>",
|
||||
@@ -141,6 +163,9 @@ function usageText() {
|
||||
" --keep-box Leave the Crabbox lease running for VNC debugging.",
|
||||
" --mock-response-file <path> Text returned by the mock model.",
|
||||
" --output-dir <path> Artifact directory under the repo.",
|
||||
" --message-id <id> Telegram message id for proof-view deep link.",
|
||||
" --preview-crop telegram-window Create a side-by-side friendly Telegram-window GIF.",
|
||||
" --preview-crop-width <pixels> Cropped preview GIF width. Default: 520.",
|
||||
" --preview-fps <fps> Motion GIF frames per second. Default: 24.",
|
||||
" --preview-width <pixels> Motion GIF width. Default: 1920.",
|
||||
" --pr <number> Pull request number for publish.",
|
||||
@@ -194,6 +219,7 @@ function parseArgs(argv: string[]): Options {
|
||||
"send",
|
||||
"start",
|
||||
"status",
|
||||
"view",
|
||||
]);
|
||||
const command = commands.has(argv[0] ?? "") ? (argv.shift() as Options["command"]) : "probe";
|
||||
const stamp = new Date().toISOString().replace(/[:.]/gu, "-");
|
||||
@@ -211,6 +237,7 @@ function parseArgs(argv: string[]): Options {
|
||||
mockResponseText: "OPENCLAW_E2E_OK",
|
||||
mockPort: 19_882,
|
||||
outputDir: path.join(DEFAULT_OUTPUT_ROOT, stamp),
|
||||
previewCropWidth: TELEGRAM_PROOF_VIEW.cropWidth,
|
||||
previewFps: 24,
|
||||
previewWidth: 1920,
|
||||
provider: process.env.OPENCLAW_TELEGRAM_USER_CRABBOX_PROVIDER?.trim() || "aws",
|
||||
@@ -269,8 +296,18 @@ function parseArgs(argv: string[]): Options {
|
||||
opts.mockPort = parsePositiveInteger(readValue(), "--mock-port");
|
||||
} else if (arg === "--mock-response-file") {
|
||||
opts.mockResponseText = fs.readFileSync(resolveRepoPath(process.cwd(), readValue()), "utf8");
|
||||
} else if (arg === "--message-id") {
|
||||
opts.messageId = String(parsePositiveInteger(readValue(), "--message-id"));
|
||||
} else if (arg === "--output-dir") {
|
||||
opts.outputDir = readValue();
|
||||
} else if (arg === "--preview-crop") {
|
||||
const value = readValue();
|
||||
if (value !== "telegram-window") {
|
||||
throw new Error("--preview-crop must be telegram-window.");
|
||||
}
|
||||
opts.previewCrop = value;
|
||||
} else if (arg === "--preview-crop-width") {
|
||||
opts.previewCropWidth = parsePositiveInteger(readValue(), "--preview-crop-width");
|
||||
} else if (arg === "--preview-fps") {
|
||||
opts.previewFps = parsePositiveInteger(readValue(), "--preview-fps");
|
||||
} else if (arg === "--preview-width") {
|
||||
@@ -318,11 +355,14 @@ function parseArgs(argv: string[]): Options {
|
||||
throw new Error("run requires a remote command after --.");
|
||||
}
|
||||
if (
|
||||
["finish", "publish", "run", "screenshot", "send", "status"].includes(command) &&
|
||||
["finish", "publish", "run", "screenshot", "send", "status", "view"].includes(command) &&
|
||||
!opts.sessionFile
|
||||
) {
|
||||
throw new Error(`${command} requires --session.`);
|
||||
}
|
||||
if (command === "view" && !opts.messageId) {
|
||||
throw new Error("view requires --message-id.");
|
||||
}
|
||||
if (command === "publish" && !opts.publishPr) {
|
||||
throw new Error("publish requires --pr.");
|
||||
}
|
||||
@@ -865,6 +905,63 @@ async function createMotionPreview(params: {
|
||||
return JSON.parse(preview.stdout) as JsonObject;
|
||||
}
|
||||
|
||||
function previewCrop(opts: Options) {
|
||||
return opts.previewCrop === "telegram-window"
|
||||
? { ...TELEGRAM_PROOF_VIEW, cropWidth: opts.previewCropWidth }
|
||||
: undefined;
|
||||
}
|
||||
|
||||
async function createCroppedMotionPreview(params: {
|
||||
crop: typeof TELEGRAM_PROOF_VIEW;
|
||||
croppedGifPath: string;
|
||||
croppedVideoPath: string;
|
||||
opts: Options;
|
||||
root: string;
|
||||
videoPath: string;
|
||||
}) {
|
||||
const crop = `crop=${params.crop.width}:${params.crop.height}:${params.crop.x}:${params.crop.y}`;
|
||||
const scale = `scale=${params.crop.cropWidth}:-2:flags=lanczos`;
|
||||
await runCommand({
|
||||
command: "ffmpeg",
|
||||
args: [
|
||||
"-y",
|
||||
"-hide_banner",
|
||||
"-loglevel",
|
||||
"warning",
|
||||
"-i",
|
||||
params.videoPath,
|
||||
"-vf",
|
||||
`${crop},${scale}`,
|
||||
"-pix_fmt",
|
||||
"yuv420p",
|
||||
params.croppedVideoPath,
|
||||
],
|
||||
cwd: params.root,
|
||||
stdio: "inherit",
|
||||
});
|
||||
await runCommand({
|
||||
command: "ffmpeg",
|
||||
args: [
|
||||
"-y",
|
||||
"-hide_banner",
|
||||
"-loglevel",
|
||||
"warning",
|
||||
"-i",
|
||||
params.videoPath,
|
||||
"-filter_complex",
|
||||
`${crop},fps=${params.opts.previewFps},${scale},split[s0][s1];[s0]palettegen[p];[s1][p]paletteuse`,
|
||||
params.croppedGifPath,
|
||||
],
|
||||
cwd: params.root,
|
||||
stdio: "inherit",
|
||||
});
|
||||
return {
|
||||
crop,
|
||||
fps: params.opts.previewFps,
|
||||
outputWidth: params.crop.cropWidth,
|
||||
};
|
||||
}
|
||||
|
||||
async function inspectCrabbox(opts: Options, root: string, leaseId: string) {
|
||||
const result = await runCommand({
|
||||
command: opts.crabboxBin,
|
||||
@@ -1201,6 +1298,8 @@ function summarizeProbe(probePath: string) {
|
||||
}
|
||||
|
||||
function writeReport(params: {
|
||||
croppedMotionGifPath?: string;
|
||||
croppedMotionVideoPath?: string;
|
||||
motionGifPath?: string;
|
||||
motionVideoPath?: string;
|
||||
outputDir: string;
|
||||
@@ -1224,11 +1323,19 @@ function writeReport(params: {
|
||||
params.motionGifPath
|
||||
? `Motion GIF: ${path.basename(params.motionGifPath)}`
|
||||
: "Motion GIF: missing",
|
||||
params.croppedMotionVideoPath
|
||||
? `Cropped motion video: ${path.basename(params.croppedMotionVideoPath)}`
|
||||
: undefined,
|
||||
params.croppedMotionGifPath
|
||||
? `Cropped motion GIF: ${path.basename(params.croppedMotionGifPath)}`
|
||||
: undefined,
|
||||
params.screenshotPath
|
||||
? `Screenshot: ${path.basename(params.screenshotPath)}`
|
||||
: "Screenshot: missing",
|
||||
"",
|
||||
].join("\n"),
|
||||
]
|
||||
.filter((line) => line !== undefined)
|
||||
.join("\n"),
|
||||
);
|
||||
return reportPath;
|
||||
}
|
||||
@@ -1313,7 +1420,7 @@ video="$root/session.mp4"
|
||||
log="$root/ffmpeg.log"
|
||||
pid_file="$root/ffmpeg.pid"
|
||||
rm -f "$video" "$log" "$pid_file"
|
||||
size="$(xdpyinfo | awk '/dimensions:/ {print $2; exit}')"
|
||||
size="$(xdpyinfo | awk '/dimensions:/ {size=$2} END {if (!size) exit 1; print size}')"
|
||||
nohup ffmpeg -y -hide_banner -loglevel warning -f x11grab -framerate ${opts.recordFps} -video_size "$size" -i "$DISPLAY" -pix_fmt yuv420p "$video" >"$log" 2>&1 &
|
||||
echo $! >"$pid_file"`;
|
||||
await sshRun(root, inspect, command);
|
||||
@@ -1438,8 +1545,9 @@ async function startSession(root: string, opts: Options, outputDir: string) {
|
||||
webvnc: `${opts.crabboxBin} webvnc --provider ${opts.provider} --target ${opts.target} --id ${leaseId} --open`,
|
||||
commands: {
|
||||
send: `pnpm qa:telegram-user:crabbox -- send --session ${path.relative(root, pathname)} --text '/status'`,
|
||||
view: `pnpm qa:telegram-user:crabbox -- view --session ${path.relative(root, pathname)} --message-id <message-id>`,
|
||||
run: `pnpm qa:telegram-user:crabbox -- run --session ${path.relative(root, pathname)} -- bash -lc 'source ${REMOTE_ROOT}/env.sh && python3 ${REMOTE_ROOT}/user-driver.py transcript --limit 20 --json'`,
|
||||
finish: `pnpm qa:telegram-user:crabbox -- finish --session ${path.relative(root, pathname)}`,
|
||||
finish: `pnpm qa:telegram-user:crabbox -- finish --session ${path.relative(root, pathname)} --preview-crop telegram-window`,
|
||||
},
|
||||
};
|
||||
} catch (error) {
|
||||
@@ -1533,6 +1641,58 @@ async function statusSession(root: string, opts: Options, outputDir: string) {
|
||||
};
|
||||
}
|
||||
|
||||
function telegramPrivatePostLink(groupId: string, messageId: string) {
|
||||
if (!/^-100\d+$/u.test(groupId)) {
|
||||
throw new Error(`Telegram privatepost links require a -100 group id, got ${groupId}.`);
|
||||
}
|
||||
return `tg://privatepost?channel=${groupId.slice(4)}&post=${messageId}`;
|
||||
}
|
||||
|
||||
function renderProofViewCommand(link: string) {
|
||||
return `set -euo pipefail
|
||||
export DISPLAY="\${DISPLAY:-:99}"
|
||||
root=${REMOTE_ROOT}
|
||||
win="$(wmctrl -lxG | awk 'tolower($0) ~ /telegramdesktop/ {print $1; exit}')"
|
||||
if [ -z "$win" ]; then
|
||||
echo "Telegram Desktop window not found." >&2
|
||||
exit 1
|
||||
fi
|
||||
wmctrl -ir "$win" -b remove,maximized_vert,maximized_horz,fullscreen
|
||||
wmctrl -ir "$win" -e 0,${TELEGRAM_PROOF_VIEW.x},${TELEGRAM_PROOF_VIEW.y},${TELEGRAM_PROOF_VIEW.width},${TELEGRAM_PROOF_VIEW.height}
|
||||
telegram="$root/Telegram/Telegram"
|
||||
test -x "$telegram"
|
||||
set +e
|
||||
timeout 5 "$telegram" -workdir "$root/desktop" ${shellQuote(link)}
|
||||
status="$?"
|
||||
set -e
|
||||
if [ "$status" -ne 0 ] && [ "$status" -ne 124 ]; then
|
||||
exit "$status"
|
||||
fi
|
||||
sleep 1
|
||||
wmctrl -lxG | awk 'tolower($0) ~ /telegramdesktop/'`;
|
||||
}
|
||||
|
||||
async function viewSession(root: string, opts: Options, outputDir: string) {
|
||||
const { session } = readSession(root, opts, outputDir);
|
||||
const messageId = opts.messageId;
|
||||
if (!messageId) {
|
||||
throw new Error("view requires --message-id.");
|
||||
}
|
||||
const link = telegramPrivatePostLink(session.credential.groupId, messageId);
|
||||
const result = await sshRun(root, session.crabbox.inspect, renderProofViewCommand(link));
|
||||
const logPath = path.join(
|
||||
session.outputDir,
|
||||
`proof-view-${new Date().toISOString().replace(/[:.]/gu, "-")}.log`,
|
||||
);
|
||||
fs.writeFileSync(logPath, `${result.stdout}${result.stderr}`);
|
||||
return {
|
||||
geometry: TELEGRAM_PROOF_VIEW,
|
||||
link,
|
||||
log: path.relative(root, logPath),
|
||||
status: "pass",
|
||||
};
|
||||
}
|
||||
|
||||
async function finishSession(root: string, opts: Options, outputDir: string) {
|
||||
const { path: pathname, session } = readSession(root, opts, outputDir);
|
||||
const summary: JsonObject = {
|
||||
@@ -1545,10 +1705,19 @@ async function finishSession(root: string, opts: Options, outputDir: string) {
|
||||
const videoPath = path.join(session.outputDir, "telegram-user-crabbox-session.mp4");
|
||||
const motionVideoPath = path.join(session.outputDir, "telegram-user-crabbox-session-motion.mp4");
|
||||
const motionGifPath = path.join(session.outputDir, "telegram-user-crabbox-session-motion.gif");
|
||||
const croppedMotionVideoPath = path.join(
|
||||
session.outputDir,
|
||||
"telegram-user-crabbox-session-motion-telegram-window.mp4",
|
||||
);
|
||||
const croppedMotionGifPath = path.join(
|
||||
session.outputDir,
|
||||
"telegram-user-crabbox-session-motion-telegram-window.gif",
|
||||
);
|
||||
const screenshotPath = path.join(session.outputDir, "telegram-user-crabbox-session.png");
|
||||
const desktopLogPath = path.join(session.outputDir, "telegram-desktop.log");
|
||||
const statusPath = path.join(session.outputDir, "status.json");
|
||||
const ffmpegLogPath = path.join(session.outputDir, "ffmpeg.log");
|
||||
const crop = previewCrop(opts);
|
||||
try {
|
||||
await stopRemoteRecording(root, session.crabbox.inspect, session);
|
||||
await scpFromRemote(root, session.crabbox.inspect, session.recorder.remoteVideo, videoPath);
|
||||
@@ -1574,6 +1743,16 @@ async function finishSession(root: string, opts: Options, outputDir: string) {
|
||||
root,
|
||||
videoPath,
|
||||
});
|
||||
if (crop) {
|
||||
summary.croppedMediaPreview = await createCroppedMotionPreview({
|
||||
crop,
|
||||
croppedGifPath: croppedMotionGifPath,
|
||||
croppedVideoPath: croppedMotionVideoPath,
|
||||
opts,
|
||||
root,
|
||||
videoPath: motionVideoPath,
|
||||
});
|
||||
}
|
||||
await runCommand({
|
||||
command: opts.crabboxBin,
|
||||
args: [
|
||||
@@ -1594,6 +1773,12 @@ async function finishSession(root: string, opts: Options, outputDir: string) {
|
||||
desktopLog: path.relative(root, desktopLogPath),
|
||||
ffmpegLog: path.relative(root, ffmpegLogPath),
|
||||
previewGif: path.relative(root, motionGifPath),
|
||||
...(crop
|
||||
? {
|
||||
previewGifCropped: path.relative(root, croppedMotionGifPath),
|
||||
trimmedVideoCropped: path.relative(root, croppedMotionVideoPath),
|
||||
}
|
||||
: {}),
|
||||
screenshot: path.relative(root, screenshotPath),
|
||||
status: path.relative(root, statusPath),
|
||||
trimmedVideo: path.relative(root, motionVideoPath),
|
||||
@@ -1619,6 +1804,8 @@ async function finishSession(root: string, opts: Options, outputDir: string) {
|
||||
const summaryPath = path.join(session.outputDir, "telegram-user-crabbox-session-summary.json");
|
||||
fs.writeFileSync(summaryPath, `${JSON.stringify(summary, null, 2)}\n`);
|
||||
const reportPath = writeReport({
|
||||
croppedMotionGifPath: crop ? croppedMotionGifPath : undefined,
|
||||
croppedMotionVideoPath: crop ? croppedMotionVideoPath : undefined,
|
||||
motionGifPath,
|
||||
motionVideoPath,
|
||||
outputDir: session.outputDir,
|
||||
@@ -1639,11 +1826,16 @@ async function finishSession(root: string, opts: Options, outputDir: string) {
|
||||
async function publishSessionArtifacts(root: string, opts: Options, outputDir: string) {
|
||||
const { session } = readSession(root, opts, outputDir);
|
||||
const motionGifPath = path.join(session.outputDir, "telegram-user-crabbox-session-motion.gif");
|
||||
const croppedMotionGifPath = path.join(
|
||||
session.outputDir,
|
||||
"telegram-user-crabbox-session-motion-telegram-window.gif",
|
||||
);
|
||||
const publishGifPath = fs.existsSync(croppedMotionGifPath) ? croppedMotionGifPath : motionGifPath;
|
||||
const publishDir = opts.publishFullArtifacts
|
||||
? session.outputDir
|
||||
: path.join(session.outputDir, "publish-gif-only");
|
||||
if (!opts.publishFullArtifacts) {
|
||||
if (!fs.existsSync(motionGifPath)) {
|
||||
if (!fs.existsSync(publishGifPath)) {
|
||||
throw new Error(
|
||||
`Missing motion GIF. Run finish first: ${path.relative(root, motionGifPath)}`,
|
||||
);
|
||||
@@ -1651,7 +1843,7 @@ async function publishSessionArtifacts(root: string, opts: Options, outputDir: s
|
||||
fs.rmSync(publishDir, { force: true, recursive: true });
|
||||
fs.mkdirSync(publishDir, { recursive: true });
|
||||
fs.copyFileSync(
|
||||
motionGifPath,
|
||||
publishGifPath,
|
||||
path.join(publishDir, "telegram-user-crabbox-session-motion.gif"),
|
||||
);
|
||||
}
|
||||
@@ -1679,7 +1871,11 @@ async function publishSessionArtifacts(root: string, opts: Options, outputDir: s
|
||||
stdio: "inherit",
|
||||
});
|
||||
return {
|
||||
artifactMode: opts.publishFullArtifacts ? "full" : "gif-only",
|
||||
artifactMode: opts.publishFullArtifacts
|
||||
? "full"
|
||||
: publishGifPath === croppedMotionGifPath
|
||||
? "gif-only-cropped"
|
||||
: "gif-only",
|
||||
publishDir: path.relative(root, publishDir),
|
||||
status: "pass",
|
||||
};
|
||||
@@ -1712,6 +1908,10 @@ async function main() {
|
||||
console.log(JSON.stringify(await statusSession(root, opts, outputDir), null, 2));
|
||||
return;
|
||||
}
|
||||
if (opts.command === "view") {
|
||||
console.log(JSON.stringify(await viewSession(root, opts, outputDir), null, 2));
|
||||
return;
|
||||
}
|
||||
if (opts.command === "finish") {
|
||||
await finishSession(root, opts, outputDir);
|
||||
return;
|
||||
|
||||
Reference in New Issue
Block a user