mirror of
https://github.com/openclaw/openclaw.git
synced 2026-11-01 13:09:17 +00:00
* test(scripts): remove duplicate q0136 proof layers Keep UI coordinator signal/join/error decisions on its existing command boundary. Native process cleanup remains in managed-child-process.test.ts: keeps the bounded launcher alive until nested signal cleanup finishes. Remove the cache-warmer replay of runShardPlans. ci-run-node-test-shard.test.ts retains applies the UI runtime policy only to the Bun child under dual-all, builds child env with cache isolation/includes/overlays, and designated-writer pruning. The warmer still verifies exact producer policy, selected groups, collection flags, writers and failure propagation. Keep one shallow-checkout/deleted-entry path; touched-package and core selection remain in selects touched packages and a bounded smoke set. Keep one full-fallback representative per branch and the negative canary guard; ci-workflow-planning.test.ts owns workflow comparison preparation. Trim Swift path inventories to representative local/shared/dependency inputs without removing invalidation or link-safety paths. CPU-entitlement rejection remains in bench-gateway-concurrency.test.ts: rejects a changed Gateway CPU entitlement during measurement; resource receipt failures remain in the shard. Authored manifest immutability remains in plugins-control-ui-build.test.ts and the retained post-rebuild identity assertions. Remove unused historical gate-input fixture fields, retaining recorded waiver/advisory rejection. CI-only: no tests or coverage run. Plain oxlint, oxfmt and diff checks passed. Shard lines 2072 -> 1923 (-7.2 percent), below the 40 percent goal; retained live isolation, screenshot, build and Git authority contracts prevent a safe whole-file cut. * test(scripts): consolidate q0136 hook ownership proof Retain separate early and config Git-not-found guards, but drop the repeated config-branch row. Empty local ownership covers existing local selection; the masked-private-override case retains the stronger raw shared-config and sibling-value proof for inherited ownership. Compute the one permitted config destination once and snapshot every other file. Keep primary, global, empty, linked-private initialization, shared-write refusal and masked shared-write protection. Remove command-shape and repeated warning-text checks already covered by real Git effects and the focused warning case. CI-only: oxfmt, plain oxlint and diff checks pass; no tests or coverage run. Cumulative shard lines 2072 -> 1909 (-7.9 percent); 40 percent remains unmet rather than deleting unique safety and lifecycle contracts. * test(ui): deslop q0138 tests Remove browser screenshot-only loops and capability-admission replays. ui/src/app/browser-capabilities.test.ts covers required overlays and optional field sizing; retained composer E2Es cover successful boot. ui/src/app/mount-fallback.test.ts, does not begin recovery while the unsupported browser screen is loading, retains the pending-download watchdog contract. Keep the built-module failure/retry and native-link E2Es. Remove the pre-dismissed community replay: community-invite-state.test.ts covers stored markers, sidebar-community-invite.browser.test.tsx covers keyboard dismissal and remount, and retained community E2Es cover navigation/reload persistence. The deleted policy replay already had a dismissal marker, so did not independently prove deployment policy. Keep media failure and codec retry assertions once on mobile instead of replaying identical worker paths on desktop. Assert dark lobster-menu overflow in the existing full interaction scenario. Reuse machine-command locators and remove repeated setup RPC shape assertions already covered by device-pair-setup.test.ts. CI-only campaign: oxfmt, plain oxlint, and git diff --check passed. No runtime tests, coverage, builds, or Testbox commands run. Test LOC 1604 to 1455 (-9.3%); preserve distinct geometry, IME, Settings routing, and real-Gateway lifecycle proof rather than force the 40% target. * test(telegram): deslop q0140 tests Consolidate caption/mention coverage into the album hydration scenario and share local ingress and fragment fixtures. Remove the unused album assertion helper. Coverage retained by: dispatches interleaved albums in first-member arrival order and holds the album quiet flush while the next member is durably pending (basic album coalescing); joins a turn that resumes after shutdown before releasing its state directory plus telegram-ingress-drain.test.ts uses participant settlement to own the row despite frame completion after abort (shutdown retryability, regressioncf6f6d926f). CI-only campaign: oxlint, oxfmt and diff checks pass; no runtime tests or coverage measurements. Preserve the distinct timing, ordering, authorization and failure paths rather than force the 40 percent line target. * test(telegram): remove duplicated q0140 e2e layers Keep Telegram-specific queue and shutdown regressions; remove core-policy replays. Coverage owners: ingress-drain.watchdog.test.ts retries pre-adoption stalls in lane order and keeps adoption finalization paused across deferred heartbeats; ingress-retry-policy.test.ts keeps wrapped session-start conflicts under both retry and age gates; inbound-debounce.test.ts anchors the batch deadline and flushes sustained messages even when the system clock moves backward. Unadopted cancellation remains in telegram-ingress-drain.test.ts releases an aborted deferred claim after a late completed settlement. The removed resumed-shutdown test exercised fixture teardown, not a separate production contract. Consolidate partial and total album failures without dropping their payload/warning assertions. Successful album hydration remains in the interleaved-album and quiet-flush scenarios. The retained durable forward scenario asserts deferred downloading before the quiet window; topic-key isolation remains in bot-handlers.inbound-pipeline.test.ts. Channel-post dispatch remains in bot.create-telegram-bot.test.ts and media success/failure in bot.media.stickers-and-fragments.test.ts. CI-only: oxlint, oxfmt and diff checks pass; no test runs. Cumulative shard lines: 1909 to 1251 (34.5 percent). Remaining distinct Telegram regressions prevent an honest 40 percent cut. * test(ui): deslop q0141 tests Keep responsive geometry, editor retirement, filtered-query recovery, split ownership, native emoji editing, and both real-Gateway Stop routes. Drop provider help replays owned by model-providers-help.e2e.test.ts; decision filtering and passive publication are covered by pages/model-providers/view-defaults.test.ts and model-providers-page.catalog.test.ts. Shared loaded-choice focus paths remain in chat-model-selection-recovery.e2e.test.ts; successful selection is covered by chat-flow.model-picker-refresh.e2e.test.ts. Emoji completion and Escape dismissal remain in pages/chat/chat-composer-emoji.test.ts. Remove optional discussion capture scaffolding and decorative embed markup, retaining cross-origin theme assertions. CI-only: oxfmt, plain oxlint and diff check passed; no test or coverage execution. Honest reduction is 174 of 1965 lines (8.9%); remaining distinct boundary and layout proof prevents the 40% target without coverage loss. * test(qa-lab): deslop q0142 tests Localize the single RPC scenario fixture and share heartbeat assertions. Centralize HTTP status checks and remove duplicate agent mock call-shape assertions. Session routing remains covered by handles request validation and routing in src/gateway/openai-http.test.ts and handles OpenResponses request parsing and validation in src/gateway/openresponses-http.test.ts. Keep all scenario entry points and distinct lifecycle/security behaviors. CI-only validation: oxfmt, plain oxlint, and git diff --check; no test execution. * test(qa-lab): remove redundant q0142 proof layers Retire remote-managed-skills: workspace-skill-remote.test.ts keeps canonical execution entries on the right hosts; refresh.workspace.test.ts keeps canonical Gateway roots local across refresh; gateway-agent-skill-refresh.e2e.test.ts keeps managed-worktree integration. Retire conversation-route-ownership: conversation-list.test.ts filters persisted routes and rechecks delayed ownership; conversation-send.test.ts and conversation-turn.test.ts reject reassignment; conversation-route-ownership.worker.test.ts fences retained grants after binding changes. Keep the WebChat message-identity regression, removing format/outcome replays covered by chat-reply-media.test.ts and managed-image-attachments.test.ts. Reuse tracked provider cleanup for session continuity; sessions.list projection remains in server.sessions.store-rpc.test.ts. Control UI headers remain in control-ui.http.test.ts and server-http.security-headers.test.ts. CI-only validation: oxfmt, plain oxlint, git diff --check. No tests run. Cumulative shard reduction is 1893 to 1336 lines (29.4%); the remaining duplicate HTTP scenario has an out-of-shard QA manifest and is retained. * test(scripts): deslop q0139 tests Remove the duplicate heap summary replay: the exclusive-retention diff case covers cycles, constructor unions, weak/unreachable nodes and shared paths; the collection/privacy summary case retains summary output coverage. Keep redaction, truncated strings and duplicate-retainer accounting cases. Trim unused concurrency benchmark fixture invariants and redundant Bun CI-value/staging-error variants. Retain explicit false CI, pin verification, cache repair and staging cleanup branches. No production or helper changes. CI-only campaign: targeted oxfmt, plain oxlint and diff checks passed; tests and coverage deferred to hosted CI. Conservative cut: 2209 to 2157 lines, below the requested 40 percent because remaining cases guard distinct runtime, process-lifetime, pinning and merge-authority behavior. * test(scripts): consolidate q0139 fixtures and duplicate proof Remove copied Testbox command inventory while retaining provider/org admission and executed stage-order proof. Remove redundant Bun filesystem call-shape checks and equivalent prior-CI/static-evidence failure variants. Keep distinct pinning, log integrity, path authority and graph completeness guards. Remove the Windows already-exited Gateway replay covered by test/helpers/openclaw-test-instance.windows-job.test.ts: finalizes the native Job even when the Gateway and all output already closed. Retain native closed-Job inspection in the descendant lifecycle case. Share legacy and current runtime recovery fixtures, reuse command fixture process supervision, exercise the actual report runner without copied-source compilation, and compact heap graph/expected-value fixtures without dropping their behavior assertions. CI-only validation: oxfmt, plain oxlint and git diff --check passed; no tests or builds run. Additional 180 lines removed; shard baseline 2209 to 1977 lines (10.5 percent total). The 40 percent target remains unmet; retained cases protect distinct behavior and every subject still exists. * test(scripts): remove redundant q0139 runner layer Retire the extra native report subprocess fixture. Native JSON generation remains in test/scripts/vitest-report-owner.test.ts (retains the exact case union and native originals; preserves native single selection reporting). Keep explicit wrapper invocation, existing-report reuse, collision and missing-output checks. Drop the concurrency benchmark progress-string replay and duplicate low-sample percentile assertion. The same timing owner is exercised by test/scripts/bench-decision-transport.test.ts (runs serial ABAB samples and reports bounded evidence without unsupported tail percentiles). Keep aggregation output, upper percentiles, drainage and malformed worker-result branches. Unify heap CLI fixture execution and encode graph tuples directly without a duplicate object representation. All remaining heap behavior assertions stay intact. CI-only proof: oxfmt, plain oxlint and diff checks passed; no tests, builds or coverage run. Additional 86 lines removed, original shard 2209 to 1891 (14.4 percent). The 40 percent target remains unmet; no dead subjects or further duplicated behavior were found. * test(scripts): deslop q0144 tests Remove copied Docker environment/source inventories while retaining wrapper auth, pinning, bounded diagnostics and executable argument/isolation checks. Shared auth staging and cleanup remain covered by live-docker-auth.test.ts and codex-live-docker-security.test.ts. Drop same-path schema, graph and audio variants: permissive additional properties retains strict schema rejection; unknown/core duplicate retain canonical graph guards; deleted.ts retains existence fallback; brief speech retains the duration failure exercised by silent/comfort-noise mocked results. CI-only campaign: oxfmt, plain oxlint and diff checks passed; no tests or coverage run. Preserve distinct payload, approval, occupancy, parity and generator contracts rather than meeting the 40 percent target by deleting them. * test(scripts): reduce q0144 fixtures and redundant layers Replace copied approval policy and package inventory with minimal driving inputs. Keep historical null usage, exact rejection guards, read-only database observations and secret-redaction checks. Reuse the existing package tarball fixture. Compare generated Kysely type structure without boilerplate formatting. Drop mocked graph selection replays covered by the real compiler scenarios in test/scripts/tsgo-core-test-shards.test.ts (core-plan, extension-plan, and type-only consumer selection). Keep physical-path, incomplete-inventory and root-partition checks. Shared Docker auth and cleanup remain covered by live-docker-auth.test.ts and codex-live-docker-security.test.ts; keep executable wrapper auth rejection and a pinned-package invariant. Consolidate parity rejection setup and remove same-decision parser, phase and partial-write variants. All ten subjects still exist; none deleted. Static oxlint, formatting and diff checks passed. No tests or coverage run under the CI-only work order; total shard reduction remains below the 40 percent target. * test(ui): deslop q0145 tests Consolidate optional device-alias proof capture to the final restarted state. Keep all scenario cases and assertions, including Unicode entry, durable pairing readback, reload, and restart. Other shard scenarios retain distinct lifecycle, authorization, keyboard, and paint-stability proof; no scenario deletions. * test(cli): consolidate q0143 install e2e fixtures Move ClawHub install scenarios into plugins-cli.recovery-install.e2e.test.ts using one real archive/HTTP fixture. Keep fresh install and repeat updates, telemetry outages, package API and version Gateway incompatibility, corrupt archive refusal, and invalid-config recovery as distinct scenarios with their existing timeout limits. The retained fresh ClawHub installs and repeat updates case covers the deleted install success scenario. The isolated failure table retains compatibility, integrity, no-persistence and telemetry failure assertions. Compact node diagnostics fixtures without removing auth branches. CI-only validation: plain oxlint, oxfmt and git diff --check passed; no tests, coverage, typecheck or builds executed. Cumulative shard plus new support is 2049 to 1688 lines (17.6 percent reduction), below the requested 40 percent target. * test(cli): consolidate q0143 node and search scenarios Combine status rows, platform paths and safe reapproval guidance while retaining per-row pairing checks. Merge connected filtering with diagnostics auth, remove same-branch auth variants, and minimize repeated inventory and install fixtures. Retain snap file publication in the URL both-facing scenario. Default-facing forwarding remains in nodes-cli/register.camera.test.ts; decoded writes remain in nodes-camera.test.ts. Remove rename replay covered by nodes-cli.coverage.test.ts mutation request/JSON and invalid-name cases, plus normalization-core string-coerce.test.ts. Replace fixture-only search subprocess management with an in-process loopback HTTP server. Catalog query/family and formatting inventories remain covered by plugins/catalog-search.test.ts and plugins-search-command.test.ts; this E2E retains real transport, separation, empty and failed lookups. CI-only: oxfmt, plain oxlint and diff-check passed. No tests/builds/typecheck/coverage run. Original listed shard 2049 -> 1400 lines (31.7 percent); including the 104-line helper, total 1504 (26.6 percent). The 40 percent target is not met without further owner-suite consolidation beyond this fixed shard. * test(ui): deslop q0138 tests Remove the non-admin connection replay covered by new-session-page.operator-scopes.e2e.test.ts and where-chip.test.ts. Keep both responsive community layouts without replaying the theme cross-product; sidebar-community-invite.browser.test.tsx owns theme artwork and permanent dismissal. Remove New Session compression cancellation replay: composer-attachments.test.ts owns tile cancellation, and chat-attachment-video.test.ts owns removal during encoding. Lobster pointer-dismissal and temporary-dismissal ownership remains in lobster-pet.test.ts; retain native viewport, focus, enlarged-label and edge positioning proof. CI-only audit: oxfmt, diff check and plain oxlint passed. No tests or coverage executed. Lines 1455 -> 1393; 40 percent target not reached because remaining cases cover distinct browser, transport, lifecycle and security behavior. * test(ui): remove redundant q0138 e2e layers Retire settings-agent-selector: agent-page-scope.e2e covers route restoration and chat isolation, agent-select-layout.e2e covers mobile selection, and agent-select-opening.browser plus session-menu tests cover keyboard focus and nested Escape. settings-sidebar, config-page.memory-route, memory-page, and model-providers-page tests own scoped selection and requests. Retire lobster dismissal replay after native Menu cutover8b1315ac0c. lobster-pet.test owns pointer anchoring, outside focus and dismissal; solid/overlay-style.browser and menu-native-contract.browser own constrained placement, typography and native overlay behavior. Remove only their obsolete inventory and sequencer entries. Keep compact community layout and real video encoding proof; combine upload layout with the encoding journey. Remove pairing timeout replay covered by protocol-client.request and connect-machine-dialog tests, and bootstrap replay covered by connection-bootstrap and bootstrap-location tests. Session roster proof now compares complete non-profile request histories; sessions/route and session-roster-refresh own query shape. CI-only: plain oxlint, oxfmt and git diff --check passed. No tests or coverage run. Original shard lines 1455 to 837 (42.5 percent reduction); previous commit retained unchanged. * test(ui): finish q0141 e2e consolidation Port q0141 onto the campaign lane, preserving HEAD-modified model selection and discussion coverage. Keep lane inventory changes, remove the filtered-errors watch, and retain the supported test-local Discussion launcher. CI-only validation: oxlint, oxfmt --check, and git diff --check exited 0. Tests, coverage, Testbox, and check-changed were not run. * test(release): deslop q0147 tests Share qualification scenario setup and validation; compact version fixtures. The direct implicit baseline assertion is covered by resolveQualificationBaselines in the retained first-frozen scenario, which calls resolveReleaseUpgradeBaseline with the same candidate, versions and frozen context. Keep explicit previousVersion selection and every rejection path. CI-only campaign: oxlint, oxfmt and diff checks passed; no tests or coverage executed. Preserve the other shard files: their distinct binding identity, prior-CI authority, bundle loading and process/migration lifecycle boundaries have no stronger duplicate in this shard. Reduction: 1677 to 1655 lines; below the 40% target rather than dropping unique proof. * test(scripts): remove redundant q0147 proof layers Drop built-output source greps, copied output/identity representation checks, fixture inventory count, and redundant setup retirement assertions. Keep actual companion loading, packaging inclusion, collision, origin, and native API preservation proof. Remaining owner proof: setup-registry.lifecycle.test.ts keeps setup lazy imports with their transferred owner; prepare-vitest-runtime.test.ts admits E2E readers after one equivalent AI writer; state-migrations.state-dir.test.ts preserves both directories when the canonical root already exists; pr-merge-prior-ci-cancelled-root.test.ts retains foreign publisher/suite/stale-head refusal through the shared cancelled-root owner. Use empty Git commits and the existing baseline byte-snapshot helper. Drop 401/404 repeats of the retained 500 non-throttle branch; retain separate 403 refusal and every retry-budget/header path. Preserve post-ready built Gateway persistence and externally exercised process-cleanup fixture. No retired subjects found. CI-only: oxlint, formatting, and diff checks pass; no tests or coverage run. Total shard 1677 to 1570 lines (6.4%), below the requested 40%; further identified cuts would remove distinct authority, timing, or built-host behavior. * test(scripts): consolidate q0147 owner proof Remove workflow-retention replay covered by pr-wrappers.test.ts: keeps the admitted workflow after a failed command and main advances. Keep endpoint identity, malformed records, admission conflicts and trusted ancestry cases. Remove copied tooling config inventory from the shared assertion: ci-changed-node-test-plan.test.ts checks the paired isolated configs, include scope and serial admission at lines 1524-1533. Keep the generic serial-concurrency invariant. Use one owned Doctor fixture with onTestFinished cleanup. Remove duplicate release validation/idempotence assertion and same-path frozen-primary and flag-name variants; retained resolver/validation cases still cover each decision branch. CI-only: oxfmt, plain oxlint (exit 0), and git diff --check passed. No tests or coverage run. Shard now 1536 lines versus 1677 original (8.4% reduction), still below 40%; no additional safe whole-file deletion was found. * test(workboard): deslop q0146 tests Remove optional proof capture plumbing and use the existing managed page fixture. Keep all 11 declarations (12 expanded cases), browser engines, themes, viewports, mutation gates, routing recovery and geometry assertions. The removed modal edit replay is covered by extensions/workboard/browser/pages/workboard/view-editors.test.ts: opens an edit modal and submits card updates; preserves an inline title/notes draft through lost connectivity; keeps label pills mounted while editing. Detail actions remain covered by view-card-actions.test.ts and view-details.test.ts. No production or shared support changes. CI-only: oxfmt, plain oxlint and git diff --check pass. No tests, builds or coverage run. 1474 -> 1319 lines (10.5%); below the 40% target because remaining scenarios protect distinct browser behavior. * test(workboard): retain native proof capture ownership Keep the native screenshot parity path rather than orphaning createWorkboardProof. Its support file also serves out-of-shard scroll tests and retention tooling and cannot be deleted within q0146. Final shard size: 1474 -> 1341 lines, 9.0% reduction. Static formatting, plain oxlint and diff checks pass; test execution deferred to CI. * test(workboard): consolidate q0146 owner-boundary proof PASS 15: 1474 -> 883 shard lines (-40.1%). Seed the live-refresh test directly; keep pending creation and native dismissal in the named-agent scenario, retain read-only details, geometry, URL history and browser-engine focus proof. Covered elsewhere: view-editors.test.ts (templates, linked session choices, pending edit controls); workboard-page.test.ts (preserves a submitted edit through scope/board changes); view-actions.test.ts (drag transitions and permission-gated card actions); view-details.test.ts (renders card event history); view-filters.test.ts (empty-column modes and board/agent filters); sidebar-customization.e2e.test.ts (Workboard rail alignment and persistent pins); workboard-distribution.e2e.test.ts (entry assets and activation reports). Removed the obsolete client-side session lifecycle-write probe; lifecycle.ts is a pure reader and workboard-page subscribes only to host changes, Workboard changes and cron. Static proof only: oxfmt, plain oxlint and git diff --check pass. No tests/build/coverage per CI-only instructions. Shared support is unchanged: moved() is now unused there and requires coordinator cleanup because the file also serves out-of-shard tests and retention tooling. * test(ui): deslop q0148 tests Remove the real-Gateway lookup replay: ui/src/pages/approval/approval-page.test.ts keeps one approval.get in flight across repeated visibility refreshes and retires queued lookups after decisions; ui/src/e2e/approval-page.e2e.test.ts keeps canonical terminal decisions and reload coverage. Both lookup regressions originate inb814a1efcd. Remove the deleted path from Vitest routing and its timing entry. Remove two multimode picker replays: ui/src/pages/new-session/model-control.test.ts checks cloud execution support, while the retained places-live animation cases exercise profile/machine selection. Keep the incompatible-runtime submit-button regression because the owner tests do not cover that gate completely. Remove agent-selection screenshot/video capture and bespoke failure logging, retaining fresh-shell global-session selection, startup targeting, and New conversation assertions. No production or shared support changes. CI-only campaign: no tests or coverage executed. Plain oxlint, oxfmt and git diff --check pass. Test LOC 1299 to 1048 (-19.32%); declarations 12 to 10; expanded cases 19 to 16. Stop below the 40% target to preserve distinct focus/animation, Unicode visibility/recovery, responsive palette, and attachment URL lifecycle contracts. * test(ui): consolidate q0148 e2e owner coverage Remove agent-selection-persistence E2E: bootstrap.agent-selection.test.ts covers remembered global agents and cold rosters, agent-selection.test.ts covers persistence/reload and owner-before-session ordering, and app-sidebar-cases/basics.ts covers agent-targeted New conversation links. Remove only its owner-inventory and timing entries. Retire CDP listener-count probes for the old picker implementation frome5a9b28604, replaced in58ea8e5e6a. menu-frozen-contract.browser.test.tsx retains focus during opening; chat-permission-picker.test.tsx retains numeric shortcuts and ordinary typing; chat-pane-session-controls.test.tsx retains permission patching. Keep permission styling, reduced motion and flipped panel geometry here. Shrink avatar fixtures to one owned image row and one unowned emoji row, retaining decoded agent/owner images, all viewport/theme variants, containment and all result filters. command-palette-result.test.tsx covers highlighting and command-palette.test.ts covers selection. Drop duplicate search-status checks covered by command-palette-pending.test.ts. CI-only: no tests, builds or coverage run. Plain oxlint, oxfmt and diff checks pass. Shard LOC: original 1299, prior commit 1048, now 775 (-40.34% from original). Known pre-existing issue left untouched: command-palette-mentions.e2e.test.ts imports absent openMockPalette and paletteAnchors exports. * test(ui): consolidate q0145 E2E proof at owners Port q0145 onto the campaign lane. The device-alias cleanup from b896177a96039ad65ae4b508fa8228e381ae5c22 is already present unchanged. Apply the remaining consolidations from 17c5a888f07af46c02a51c0e06aa7913196da60a, preserving the lane inventory removal for session-management.queue. Validation: oxlint and oxfmt --check passed for all five surviving changed files; staged and unstaged diff checks passed. Independent review found no actionable issues. CI-only mode: no tests, coverage, Testbox, or check-changed executed. * test(ui): retain filtered session and pairing contract proof * test: repair batch d464 CI contracts * test(ui): retain complete picker session fixture * test: retarget consolidated QA scenario and prune stale inventory * test(telegram): preserve pending-update timeout regression
174 lines
6.9 KiB
TypeScript
174 lines
6.9 KiB
TypeScript
import fs from "node:fs";
|
|
import { createRequire } from "node:module";
|
|
import path from "node:path";
|
|
import { build } from "tsdown";
|
|
import { afterEach, expect, it } from "vitest";
|
|
import { createPluginInventoryModuleRefsPlugin } from "../../scripts/lib/plugin-inventory-module-refs.mts";
|
|
import { buildPluginNpmRuntime } from "../../scripts/lib/plugin-npm-runtime-build.mts";
|
|
import {
|
|
createPluginCache,
|
|
retirePluginCache,
|
|
withPluginCache,
|
|
} from "../../src/plugins/plugin-cache.js";
|
|
import { createPluginManifestRecordFixture } from "../../src/plugins/plugin-metadata.test-support.js";
|
|
import { getPluginSetupModuleLoader } from "../../src/plugins/plugin-setup-module.js";
|
|
import configs from "../../tsdown.config.ts";
|
|
import { useAutoCleanupTempDirTracker } from "../helpers/temp-dir.js";
|
|
|
|
const temp = useAutoCleanupTempDirTracker(afterEach);
|
|
const requireHost = createRequire(import.meta.url);
|
|
const sdk = "openclaw/plugin-sdk/channel-entry-contract";
|
|
|
|
it.each([
|
|
{ binding: "alias", origin: "bundled", evaluations: 1 },
|
|
{ binding: "namespace", origin: "bundled", evaluations: 1 },
|
|
{ binding: "inventory", origin: "bundled", evaluations: 1 },
|
|
{ binding: "unrelated", origin: "bundled", evaluations: 0 },
|
|
{ binding: "esm", origin: "global", evaluations: 2 },
|
|
{ binding: "cjs", origin: "global", evaluations: 2 },
|
|
{ binding: "esm", origin: "bundled", evaluations: 1 },
|
|
{ binding: "cjs", origin: "bundled", evaluations: 1 },
|
|
] as const)(
|
|
"builds only declared SDK companion edges for $binding ($origin)",
|
|
async ({ binding, origin, evaluations }) => {
|
|
const root = temp.make("inventory companion ");
|
|
const write = (name: string, source: string) => {
|
|
const file = path.join(root, name);
|
|
fs.writeFileSync(file, source);
|
|
return file;
|
|
};
|
|
const format = binding === "esm" || binding === "cjs" ? binding : undefined;
|
|
const runtimeExtension = format === "cjs" ? "cjs" : "js";
|
|
write(
|
|
"package.json",
|
|
JSON.stringify({
|
|
type: "module",
|
|
version: "1.0.0",
|
|
openclaw: {
|
|
extensions: ["./companion.ts"],
|
|
setupEntry: "./setup.ts",
|
|
build: { runtimeFormat: format },
|
|
},
|
|
}),
|
|
);
|
|
const event = `inventory:${root}`;
|
|
const companion = write(
|
|
"companion.ts",
|
|
`import process from 'node:process';
|
|
process.on(${JSON.stringify(event)}, () => {});
|
|
export const channelPlugin = { id: 'fixture' };
|
|
export const runtimeSelectedExport = 'retained';`,
|
|
);
|
|
const pluginId = binding === "inventory" ? "openai" : "a2a";
|
|
const entryName = `extensions/${pluginId}/${binding === "inventory" ? "setup-api" : "setup-entry"}`;
|
|
const declaration = binding === "namespace" ? "sdk.defineBundledChannelSetupEntry" : "declare";
|
|
const entry = write(
|
|
"setup.ts",
|
|
`#!/usr/bin/env node
|
|
'use strict';
|
|
const __openclawFileURLToPath = 'first';
|
|
const \\u005f_openclawFileURLToPath_ = 'escaped';
|
|
export const retained = [__openclawFileURLToPath, __openclawFileURLToPath_];
|
|
${binding === "namespace" ? `import * as sdk from '${sdk}';` : `import { defineBundledChannelSetupEntry as ${binding === "unrelated" ? "imported" : "declare"} } from '${sdk}';`}
|
|
${binding === "unrelated" ? "function declare(value) { return value; }" : ""}
|
|
export const label = '🦞';
|
|
export const decoy = { specifier: './absent.ts' };
|
|
export default ${declaration}({ importMetaUrl: import.meta.url,
|
|
plugin: { specifier: './companion.js', exportName: 'channelPlugin' } });
|
|
`,
|
|
);
|
|
const outDir = path.join(root, "dist");
|
|
const publicApi = path.join(outDir, `extensions/${pluginId}/api.js`);
|
|
fs.mkdirSync(path.dirname(publicApi), { recursive: true });
|
|
fs.writeFileSync(publicApi, "export const nativeOwner = 'unchanged';\n");
|
|
const nativeBytes = fs.readFileSync(publicApi);
|
|
const template = configs.find(
|
|
(config) =>
|
|
config.name === "openclaw-unified" &&
|
|
typeof config.entry === "object" &&
|
|
!Array.isArray(config.entry) &&
|
|
config.entry?.[entryName],
|
|
);
|
|
expect(template).toBeDefined();
|
|
const bundles = format
|
|
? []
|
|
: (
|
|
await build({
|
|
...template,
|
|
config: false,
|
|
clean: false,
|
|
entry: {
|
|
[entryName]: entry,
|
|
...(binding === "inventory"
|
|
? { "extensions/openai/capability-catalog": companion }
|
|
: {}),
|
|
},
|
|
outDir,
|
|
dts: false,
|
|
logLevel: "silent",
|
|
plugins: [createPluginInventoryModuleRefsPlugin(root)],
|
|
})
|
|
).bundles;
|
|
if (format) {
|
|
const plan = await buildPluginNpmRuntime({ packageDir: root, logLevel: "silent" });
|
|
expect(plan?.packageFiles).toContain("dist/**");
|
|
}
|
|
const cache = createPluginCache();
|
|
try {
|
|
if (!format) {
|
|
expect(fs.readFileSync(publicApi)).toEqual(nativeBytes);
|
|
}
|
|
const chunks = bundles.flatMap((bundle) =>
|
|
bundle.chunks.filter((chunk) => chunk.type === "chunk"),
|
|
);
|
|
const privateChunks = chunks.filter((chunk) => chunk.fileName.includes("/.setup/"));
|
|
const setup = path.join(outDir, format ? `setup.${runtimeExtension}` : `${entryName}.js`);
|
|
if (binding === "unrelated") {
|
|
expect(privateChunks).toHaveLength(0);
|
|
return;
|
|
}
|
|
if (format) {
|
|
expect(requireHost(path.join(outDir, `companion.${runtimeExtension}`))).toMatchObject({
|
|
runtimeSelectedExport: "retained",
|
|
channelPlugin: { id: "fixture" },
|
|
});
|
|
} else {
|
|
expect(privateChunks.some((chunk) => chunk.exports.includes("runtimeSelectedExport"))).toBe(
|
|
true,
|
|
);
|
|
}
|
|
const nativeListeners = process.listenerCount(event);
|
|
expect(nativeListeners).toBe(format ? 1 : 0);
|
|
if (binding === "inventory") {
|
|
expect(fs.existsSync(path.join(outDir, "extensions/openai/capability-catalog.js"))).toBe(
|
|
true,
|
|
);
|
|
}
|
|
const rootDir = path.dirname(setup);
|
|
const record = createPluginManifestRecordFixture({
|
|
id: "fixture",
|
|
origin,
|
|
rootDir,
|
|
source: setup,
|
|
});
|
|
withPluginCache(cache, () => {
|
|
const loader = getPluginSetupModuleLoader(record, setup, rootDir);
|
|
const module = loader(setup) as {
|
|
default: { loadSetupPlugin(): { id: string } };
|
|
retained: string[];
|
|
};
|
|
expect(process.listenerCount(event)).toBe(nativeListeners);
|
|
expect(module.retained).toEqual(["first", "escaped"]);
|
|
expect(loader.initialize(() => module.default.loadSetupPlugin()).id).toBe("fixture");
|
|
});
|
|
// Bundled code reuses the public load; installed packages evaluate a captured graph.
|
|
expect(process.listenerCount(event)).toBe(evaluations);
|
|
} finally {
|
|
await retirePluginCache(cache);
|
|
process.removeAllListeners(event);
|
|
for (const bundle of bundles) {
|
|
await bundle[Symbol.asyncDispose]();
|
|
}
|
|
}
|
|
},
|
|
);
|