diff --git a/extensions/qa-lab/package.json b/extensions/qa-lab/package.json index 641c8d0c721b..732a8952665a 100644 --- a/extensions/qa-lab/package.json +++ b/extensions/qa-lab/package.json @@ -12,7 +12,7 @@ "zod": "4.4.3" }, "devDependencies": { - "@openclaw/crabline": "0.1.10", + "@openclaw/crabline": "0.1.11", "@openclaw/discord": "workspace:*", "@openclaw/plugin-sdk": "workspace:*", "@openclaw/slack": "workspace:*", diff --git a/extensions/qa-lab/src/suite.test.ts b/extensions/qa-lab/src/suite.test.ts index c4a623dfdf5b..6a9c36bde306 100644 --- a/extensions/qa-lab/src/suite.test.ts +++ b/extensions/qa-lab/src/suite.test.ts @@ -476,8 +476,25 @@ describe("qa suite", () => { }, }); + const summary = JSON.parse(await fs.readFile(artifacts.summaryPath, "utf8")) as { + run?: { + channelCapabilityMatrixPath?: string; + channelDriverSmokePath?: string; + }; + }; + const capabilityMatrixPath = summary.run?.channelCapabilityMatrixPath; + const smokeArtifactPath = summary.run?.channelDriverSmokePath; + if (typeof capabilityMatrixPath !== "string" || typeof smokeArtifactPath !== "string") { + throw new Error("Crabline generation artifact paths missing from QA summary."); + } + expect(capabilityMatrixPath).toMatch( + /^\.crabline-smoke-artifacts\/generation-[^/]+\/crabline-fake-provider-capabilities\.json$/u, + ); + expect(smokeArtifactPath).toMatch( + /^\.crabline-smoke-artifacts\/generation-[^/]+\/crabline-fake-provider-smoke\.json$/u, + ); const matrix = JSON.parse( - await fs.readFile(path.join(outputDir, "crabline-fake-provider-capabilities.json"), "utf8"), + await fs.readFile(path.resolve(outputDir, capabilityMatrixPath), "utf8"), ) as { report?: { result?: { selectedChannel?: string; supportedChannels?: string[] } }; }; @@ -486,7 +503,7 @@ describe("qa suite", () => { [...CRABLINE_SERVER_CHANNELS].toSorted(), ); const smoke = JSON.parse( - await fs.readFile(path.join(outputDir, "crabline-fake-provider-smoke.json"), "utf8"), + await fs.readFile(path.resolve(outputDir, smokeArtifactPath), "utf8"), ) as { smoke?: { result?: { ok?: boolean; provider?: string } } }; expect(smoke.smoke?.result).toMatchObject({ ok: true, provider: "telegram" }); const evidence = JSON.parse(await fs.readFile(artifacts.evidencePath, "utf8")) as { @@ -505,14 +522,14 @@ describe("qa suite", () => { const outputDir = await tempDirs.makeTempDir("qa-suite-crabline-generation-"); const capabilityMatrixPath = path.join( outputDir, - "crabline-generations", - "generation-1", + ".crabline-smoke-artifacts", + "generation-11111111-1111-4111-8111-111111111111", "capabilities.json", ); const smokeArtifactPath = path.join( outputDir, - "crabline-generations", - "generation-1", + ".crabline-smoke-artifacts", + "generation-11111111-1111-4111-8111-111111111111", "smoke.json", ); await fs.mkdir(path.dirname(capabilityMatrixPath), { recursive: true }); @@ -550,9 +567,18 @@ describe("qa suite", () => { smokeArtifactPath: "crabline-fake-provider-smoke.json", }, runCrablineChannelDriverSmoke: vi.fn(async () => ({ + artifactPointerPath: path.join(outputDir, ".crabline-smoke-artifacts", "current.json"), capabilityMatrixPath, capabilityReport: {}, - manifestPath: path.join(outputDir, "crabline-generations", "generation-1", "manifest.json"), + generation: "generation-11111111-1111-4111-8111-111111111111", + manifestPath: path.join( + outputDir, + ".crabline-smoke-artifacts", + "generation-11111111-1111-4111-8111-111111111111", + "manifest.json", + ), + providerReadiness: {}, + providerReadinessArtifactPath: smokeArtifactPath, smoke: {}, smokeArtifactPath, })), @@ -588,8 +614,10 @@ describe("qa suite", () => { channelCapabilityMatrixPath: capabilityMatrixPath, channelDriverSmokePath: smokeArtifactPath, }); - expect(artifacts.report).toContain(`Channel capability report: ${capabilityMatrixPath}.`); - expect(artifacts.report).toContain(`Channel driver smoke: ${smokeArtifactPath}.`); + expect(artifacts.report).toContain(`Generation capability filename: ${capabilityMatrixPath}.`); + expect(artifacts.report).toContain( + `Generation provider-readiness filename: ${smokeArtifactPath}.`, + ); expect(artifacts.report).not.toContain("crabline-fake-provider-capabilities.json"); expect(artifacts.report).not.toContain("crabline-fake-provider-smoke.json"); }); diff --git a/extensions/qa-lab/src/suite.ts b/extensions/qa-lab/src/suite.ts index f2bebe54cfb0..180c879d1cd5 100644 --- a/extensions/qa-lab/src/suite.ts +++ b/extensions/qa-lab/src/suite.ts @@ -576,7 +576,7 @@ function createQaSuiteReportNotes(params: { }) { return [ ...params.transport.createReportNotes(params), - // Crabline 0.1.9 narrows these paths to legacy filename literals. + // Crabline reports completed generation paths through this filename-narrowed selection. ...createOpenClawCrablineChannelReportNotes( params.channelDriverSelection as OpenClawCrablineChannelDriverSelection | null | undefined, ), diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index eea205537e15..869942562455 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1398,8 +1398,8 @@ importers: version: 4.4.3 devDependencies: '@openclaw/crabline': - specifier: 0.1.10 - version: 0.1.10 + specifier: 0.1.11 + version: 0.1.11 '@openclaw/discord': specifier: workspace:* version: link:../discord @@ -3404,8 +3404,8 @@ packages: cpu: [x64] os: [win32] - '@openclaw/crabline@0.1.10': - resolution: {integrity: sha512-j9IwibClUZs1vcw/v4tF9VP57OPuZxr1RqeLPvxUcz6Ldvw1ukVf7O7FLAfaRMOZxCMSxpjpx3wg+VnvmiATvQ==} + '@openclaw/crabline@0.1.11': + resolution: {integrity: sha512-A7KH6gi7tXfJmdyeCzhZ65cSrLk4lALbto3lNBOHp1C6uIirAgM4tcF9I7/LhNDX/dq/T+q2QytpVPhhsfwgQQ==} engines: {node: '>=22'} hasBin: true @@ -9551,7 +9551,7 @@ snapshots: '@openai/codex@0.144.1-win32-x64': optional: true - '@openclaw/crabline@0.1.10': + '@openclaw/crabline@0.1.11': dependencies: '@types/node': 22.20.1 commander: 15.0.0 diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 669f91bc52b0..5686d8037226 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -8,7 +8,7 @@ packages: minimumReleaseAge: 2880 minimumReleaseAgeExclude: - - "@openclaw/crabline@0.1.10" + - "@openclaw/crabline@0.1.11" - "@openclaw/fs-safe@0.4.1" - "@openclaw/proxyline@0.3.3" - "@openclaw/uirouter@0.1.0" diff --git a/qa/scenarios/channels/telegram-commands-command.yaml b/qa/scenarios/channels/telegram-commands-command.yaml index 7e6f542fb25e..52a22aa5c6bf 100644 --- a/qa/scenarios/channels/telegram-commands-command.yaml +++ b/qa/scenarios/channels/telegram-commands-command.yaml @@ -29,13 +29,13 @@ flow: value: expr: "state.getSnapshot().messages.filter((message) => message.direction === 'outbound').length" - sendInbound: - conversation: { id: telegram-command-room, kind: channel } + conversation: { id: telegram-command-room, kind: group } senderId: qa-command-operator senderName: QA Command Operator text: expr: "transport.id === 'telegram' ? '/commands@openclaw' : '/commands'" - waitForOutbound: - conversation: { id: telegram-command-room, kind: channel } + conversation: { id: telegram-command-room, kind: group } sinceIndex: { ref: startIndex } timeoutMs: 60000 - call: sleep