From 7727e21da8e7ebed538d8472c7514dc094345b0e Mon Sep 17 00:00:00 2001 From: zhyongrui Date: Tue, 17 Mar 2026 16:49:14 +0000 Subject: [PATCH] feat: implement issue #128 --- src/commands/openclawcode.test.ts | 36 +++++++++++++++++++++++++++++++ src/commands/openclawcode.ts | 22 ++++++++++++++++++- 2 files changed, 57 insertions(+), 1 deletion(-) diff --git a/src/commands/openclawcode.test.ts b/src/commands/openclawcode.test.ts index 618044fe31..43ba359510 100644 --- a/src/commands/openclawcode.test.ts +++ b/src/commands/openclawcode.test.ts @@ -1306,6 +1306,42 @@ describe("openclawCodeRunCommand", () => { expect(payload.publishedPullRequestOpenedAt).toBe("2026-01-01T00:00:00.000Z"); }); + it("reports publishedPullRequestHasOpenedAt as false when the published pr has no openedAt", async () => { + mocks.runIssueWorkflow.mockResolvedValue( + createRun({ + draftPullRequest: { + ...createRun().draftPullRequest!, + openedAt: undefined, + }, + }), + ); + + await openclawCodeRunCommand({ issue: "2", repoRoot: "/repo", json: true }, runtime); + + const payload = JSON.parse(runtime.log.mock.calls[0]?.[0] ?? "null"); + expect(payload.pullRequestPublished).toBe(true); + expect(payload.publishedPullRequestHasOpenedAt).toBe(false); + expect(payload.publishedPullRequestOpenedAt).toBeNull(); + }); + + it("reports publishedPullRequestHasOpenedAt as true when the published pr has openedAt", async () => { + mocks.runIssueWorkflow.mockResolvedValue( + createRun({ + draftPullRequest: { + ...createRun().draftPullRequest!, + openedAt: "2026-01-02T00:00:00.000Z", + }, + }), + ); + + await openclawCodeRunCommand({ issue: "2", repoRoot: "/repo", json: true }, runtime); + + const payload = JSON.parse(runtime.log.mock.calls[0]?.[0] ?? "null"); + expect(payload.pullRequestPublished).toBe(true); + expect(payload.publishedPullRequestHasOpenedAt).toBe(true); + expect(payload.publishedPullRequestOpenedAt).toBe("2026-01-02T00:00:00.000Z"); + }); + it("treats blank published pull request bodies as absent in convenience signals", async () => { mocks.runIssueWorkflow.mockResolvedValue( createRun({ diff --git a/src/commands/openclawcode.ts b/src/commands/openclawcode.ts index 70999dfed2..bffbd18292 100644 --- a/src/commands/openclawcode.ts +++ b/src/commands/openclawcode.ts @@ -1479,6 +1479,25 @@ function resolveOperatorStateDir(stateDir?: string): string { return path.resolve(stateDir ?? envStateDir ?? path.join(os.homedir(), ".openclaw")); } +function hasPublishedPullRequestOpenedAt( + openedAt: WorkflowRun["draftPullRequest"] extends infer DraftPullRequest + ? DraftPullRequest extends { openedAt?: infer OpenedAt } + ? OpenedAt + : never + : never, +): boolean { + if (openedAt === true) { + return true; + } + if (typeof openedAt === "string") { + return openedAt.length > 0; + } + if (Array.isArray(openedAt)) { + return openedAt.length > 0; + } + return false; +} + function resolvePublishedPullRequest(run: WorkflowRun): { pullRequestPublished: boolean; publishedPullRequestNumber: number | null; @@ -1502,7 +1521,8 @@ function resolvePublishedPullRequest(run: WorkflowRun): { publishedPullRequestNumber: published ? (run.draftPullRequest?.number ?? null) : null, publishedPullRequestHasNumber: published && run.draftPullRequest?.number != null, publishedPullRequestHasUrl: published && run.draftPullRequest?.url != null, - publishedPullRequestHasOpenedAt: published && run.draftPullRequest?.openedAt != null, + publishedPullRequestHasOpenedAt: + published && hasPublishedPullRequestOpenedAt(run.draftPullRequest?.openedAt), publishedPullRequestHasTitle: published && (run.draftPullRequest?.title?.trim().length ?? 0) > 0, publishedPullRequestHasBody: published && (run.draftPullRequest?.body?.trim().length ?? 0) > 0,