mirror of
https://github.com/openclaw/openclaw.git
synced 2026-11-01 04:58:23 +00:00
* test(scripts): deslop q0149 tests Remove the duplicate extension-only classifier row; the file-backed mirrored-dependency audit retains that classification branch and diagnostic identifiers. Stop snapshotting recommendation prose while retaining dependency ownership, versions, paths, counts, and declarations. CI-only campaign: formatting, diff check, and plain oxlint passed. Runtime tests and coverage intentionally deferred. The shard is already largely consolidated; distinct security, platform, release, and error-path harnesses remain intact. * test(scripts): consolidate q0149 owner-boundary proof Drop UI owner-route replays covered by ui-tsx-discovery's selects-the-existing-CI-owners test and periodic inventory restatements covered by ci-node-test-plan and ci-workflow-ui-full. Keep smoke admission, transitive isolation, stale-build gating, and manifest shard boundaries. Keep resource-limit production-path assertions and shell exit propagation; check-limits.test.ts owns warning escaping and summaries. Keep one storage-unavailable formatter path; openclaw-state-worker-error.test.ts owns error-code and contention variants. Remove copied dependency audit records and enum inventory replays, retaining each classification path. Factor pnpm launcher writes without removing runner cases. CI-only: oxfmt, diff check, and plain oxlint passed; no tests or coverage run. Further reduction would remove distinct script behavior; shard remains below the requested line target. * test(ui): deslop q0152 tests Remove redundant Usage E2E layers. Remaining proof: ui/src/pages/usage/view-availability.test.ts covers interrupted lower bounds; view-overview.test.ts covers unpriced totals; provider-series.test.ts covers alias folding; view-chart.test.ts covers provider stacks; view-chart.browser.test.ts covers full-range columns; view.test.ts covers missing-cost hints and provider plans/billing. ui/src/e2e/model-providers-studio-shape.e2e.test.ts retains the Models-to-Usage handoff and exhausted plan windows. ui/src/pages/usage/view-details.test.ts retains repeated assistant call counts, result exclusion, selected ranges and Reset; usage-page-details.test.ts retains refresh publication of totals, timeline and conversation; usage-page-detail-identity.test.ts retains pointer range and refresh request ownership. Remove the CLI importer replay: src/gateway/cli-session-history.test.ts retains imported-only source fidelity and local/imported deduplication, and ui/src/pages/chat/components/chat-imported-history.test.ts retains rendered imported text. chat-tool-cards.redaction.test.ts retains raw collapsed tool arguments. Keep the Activity event/render/truncation boundary scenario, removing its unrelated Chat setup. Remove unasserted screenshots and observation artifacts without changing the durable key lifecycle or attachment assertions. Remove only the deleted Usage test path from the E2E owner path list. No production/helper changes. CI-only: no tests, coverage, Testbox or typecheck runs. Plain oxlint, oxfmt and diff-check pass. Shard test LOC 1565 -> 1060 (-32.3%); declarations 13 -> 10; expanded cases 19 -> 16. Below 40%: retain unique real-WebSocket startup, nested disclosure/ordinary exec distinction, config recovery, Activity previews, responsive attachment downloads, durable API-key custody and session layout/kind grouping. * test(gateway): deslop q0150 tests Remove duplicate wizard token-persistence/restart-auth and invalid-channel scenarios. Both remain covered by the identically named cases in src/gateway/gateway.test.ts. Reuse Gateway home and ID fixtures and bind repeated chat setup. Preserve approval authority/races, clone/fetch identity fences, hot-reload compaction, diagnostic correlation, completion expiry and node deadline provenance. CI-only: oxlint, oxfmt and diff checks; no tests or coverage executed. Net reduction 101/1408 lines (7.2%); remaining distinct boundaries prevent an honest 40% cut. * test(gateway): deslop q0150 boundary suites Remove the catalog/diagnostic E2E replay. Keep catalog reload releases the agent writer while preserving same-session ordering in server-methods/sessions-mutations.catalog-queue.test.ts; retain writer timing and privacy in state/openclaw-agent-write-admission.test.ts and config/sessions/session-accessor.sqlite-scope.test.ts; retain trace propagation in logging/logger-redaction-behavior.test.ts and logging/diagnostic-log-events.test.ts. Remove the completion-expiry Gateway replay. Keep retains delete-mode successful completions through the delivery deadline in agents/subagents/registry/subagent-registry.test.ts, preserves the concrete delivery error through retries in subagent-registry-lifecycle.test.ts, and durable expiry suspension/receipts in completion/subagent-completion-admission.mailbox.test.ts and subagent-completion-admission.expired-receipt.test.ts. Keep WebSocket approval scope denial and local-only runtime authority. Duplicate winner/replay/projection/history assertions remain in server-methods/approval.test.ts and approval.channel-custody.test.ts. Trim channel wizard to omitted versus explicit channel, one select step; setup intro/outro remain in gateway.test.ts. Remove only deleted-file timing/mock baseline entries. CI-only: no test, coverage or build runs. Plain oxlint, oxfmt and diff checks passed. Cumulative shard: 1408 to 844 lines, 564 removed (40.1 percent). * test(e2e): deslop q0153 tests Remove the requester-catalog whole-Gateway replay. Retained coverage: src/gateway/server-methods/requester-model-catalog.test.ts uses requester catalogs through the real command and agent tool assembly call sites, including admitted and unadmitted callers. src/plugins/requester-models.test.ts retains capability and invocation-lifetime guards. Keep both Hugging Face onboarding cases and all request assertions; inline the single-use HTTP handler and attach cleanup directly to each test. Other E2E scenarios retain distinct credential, transcript, transport, restart, and migration contracts. CI-only campaign: oxfmt, plain oxlint, and diff check passed; no tests or coverage run. Shard test LOC 1345 -> 1126, declarations 8 -> 7, expanded cases 9 -> 8. Below the 40 percent line target to preserve distinct integration proof. * test(e2e): remove redundant q0153 runtime replays Retain preflight coverage in src/auto-reply/reply/agent-runner-memory.preflight-stale-tokens.test.ts: excludes superseded oversized history from the active context budget. Retain summary, forward-cut, and post-reopen append coverage in src/agents/sessions/session-manager-bounded.test.ts: retains the forward cut after consecutive excluded first-kept entries. Retain dreaming storage coverage in extensions/memory-core/src/dreaming-startup-cleanup.test.ts: reclaims every stale dreaming phase without touching active, unrelated, or other-agent sessions; cleans historical artifacts while automatic scheduling is disabled; does not reclaim post-startup runs when the deferred cleanup callback runs late. Retain multi-agent replacement, cleanup joining, and failure reporting in dreaming-startup-lifecycle.test.ts. Startup cleanup is independent of dreaming enablement in the production gateway_start hook. Reuse existing HTTP response and shutdown helpers in the Hugging Face fixture. The strict route guard and successful streamed reply retain endpoint coverage without recording and reasserting the same path. Keep both onboarding cases and their model, stream, prompt, config, and output assertions. CI-only validation: plain oxlint, oxfmt, and git diff --check passed; no tests or coverage run. Cumulative shard LOC 1345 -> 805 (-40.15 percent). No production or shared-support changes. * test(scripts): deslop q0151 tests Run shared Testbox preparation branches once; retain per-workflow checkout and base-ref wiring checks. The merge, linear, missing-parent and manual cases remain in testbox-base.test.ts. Remove two equivalent invalid-arity plugin inventory CLI rows; the missing --commit value row retains that branch. Share UI sequencer fixtures and assert the complete cold-run order instead of simulating a worker pool. Preserve all warm-order, phase, membership, pinning, redaction and release-history contracts. Compact workspace and release-note fixtures without production changes. CI-only shard: formatting and plain oxlint passed; tests and coverage deferred to hosted CI. This shard remains below the requested 40 percent line reduction to retain distinct proof. * test(scripts): remove duplicate q0151 proof layers Remove Testbox workflow-text snapshots while retaining the shared action's four real checkout cases. Replace Periphery's copied job/artifact inventory with a producer-consumer invariant and derive fixture job names from the workflow; formatAnnotation retains parseRepoLocation proof. Shared ratchet ancestry remains covered by check-max-lines-ratchet.test.ts: compares an explicit moving base at the branch fork; rejects unavailable ancestry with an explicit prepared-base recovery. Unresolved staged reads remain covered by check-assertion-safety-ratchet.test.ts: keeps worktree counts and staged read failures with unmerged index entries. The retained environment staged-budget case covers the retired numeric-threshold variant. Consolidate inventory surface rendering and escaping inputs without dropping their assertions. Remove duplicate sharding membership replay covered by keeps shared UI/Gateway partition ties deterministic without collapsing specifications; retain two tied bundled files and all UI phases. Cron retains replay and fixture-side tool-cap assertions. CI-only: plain oxlint, formatting and diff checks pass; no test or coverage runs. * test(scripts): deslop q0155 tests Remove repeated PR, push, and full-release runtime defaults and duplicated Node/UI Bun setup assertions. Remaining coverage: ci-workflow-planning.test.ts, routes test runtimes without adding jobs; ci-test-runtime-trial.test.ts retains explicit dispatch budgets, main dispatch defaults, automatic-event override rejection, and unsupported-policy errors. Factor Baileys fixture file reads and JSON writes without changing its install, waveform, long dependency, stale-link, sibling-preservation, or workspace-restoration assertions. CI-only audit; no test execution. Retain other shard files because their release authority, cancellation lifecycle, dependency admission, and independent invoice reconciliation paths are distinct. * test(scripts): consolidate q0155 boundary fixtures Use one CLI ownership-report fixture for closure, build-risk, missing ownership, plugin ownership and stale-record assertions. Bind the release shadow manifest to the real large-diff fixture instead of a second synthetic worktree state. Remove runtime output inventories and workflow source-string checks. ci-workflow-planning.test.ts retains runtime routing coverage; ci-workflow-guards.test.ts retains executed npm-lock command coverage. Preserve the generic admission-before-setup invariant by evaluating both condition outcomes. Remove disconnected-history replay covered by the depth-one checkout no-merge-base cases, same-branch conservative path variants, and the duplicate webhook identity failure covered by token identity failure plus authenticated webhook success. Keep cancellation, invoice reconciliation, frozen-target authorization, and patched package materialization intact. CI-only: format, diff-check and plain oxlint; no test execution. * test(scripts): reuse q0155 fixture owners Reuse PID cleanup, workflow lookup and fixture JSON writers. Remove a probe-only success log and its assertion; the embedded Baileys assertions and nonzero exit still enforce the actual install contract. Drop the pretest runtime manifest case: it merely re-exports pretestBuildMode, while the retained explicit dual-all case proves requires_bun. Real runtime-consumer placement remains covered by ci-node-test-plan.test.ts, partitions whole-config runtime consumers from ordinary serial CLI work. Retain the distinct check-changed cancellation regression (2864f56579), Baileys materialization regression (432bada3bd), independent invoice oracle, frozen-target authorization paths, and trusted Docker harness boundaries. Static gates only; no test execution. * test(scripts): deslop q0154 tests Reuse the existing loopback HTTP fixture, share release input data, and compact metadata rejection setup and protocol expectations without dropping cases. Keep transform work-count, source-edit invalidation, generation identity and disposal checks. Preparation diagnostics remain covered by vitest-worker-artifacts.test.ts (shares a completed generation between real borrower processes until both finish); cache metadata remains exercised by vitest-report-owner.test.ts (config-load-once). CI-only campaign: plain oxlint, oxfmt and diff-check pass; no test or coverage runs. Reduction is 1773 to 1728 lines, below the 40 percent target because the remaining suites retain distinct publication, ownership, parser and lifecycle boundaries. * test(scripts): remove q0154 duplicate coverage layers Keep one asset case per source-resolution branch and one notes rejection before lookup. Remove the pass-through release inventory assertion and compiler fixture input/output counts; retain runtime results, main-thread execution, transform work counts and generation ownership. Keep qualified refusal coverage for stale context, retained evidence, same/replacement heads and immediate admission. Shared stale-gate, review/head invalidation and pending/failing-check coverage remains in pr-merge-recovery.test.ts (checks current evidence for same-head recovery). Historical parser qualification remains in pr-merge-pre-dispatch-refusal.test.ts (qualifies only intact, inspected no-dispatch evidence). CI-only: oxfmt, plain oxlint and diff-check pass; no test runs. Total shard reduction is 1773 to 1651 lines, below the requested 40 percent. No obsolete subjects or additional safely redundant layers were found. * test(scripts): deduplicate q0154 owner-boundary coverage Keep transform value/work-count invalidation tests while leaving generation ownership and source routing in vitest-worker-artifacts.test.ts. Keep watcher-specific loader integration while leaving dev-dependency, private-subpath and stale-version rejection in tooling-dependencies.test.ts. Remove the qualified-refusal stale-context replay covered by pr-merge-recovery.test.ts (rejects evidence: prep-context). Remove the generated asset success replay covered by build-external-plugin-local-dist.test.ts (keeps excluded plugin graphs isolated and their runtime metadata loadable). Preserve settlement, local-dependency precedence and strict qualified-admission tests. CI-only: oxfmt, plain oxlint and diff-check passed; no tests/builds/coverage runs. Additional reduction 74 lines; shard 1773 to 1577 lines, below the 40 percent target. Independent read-only audits found no safe whole-file deletions. * test(pr): deslop q0157 tooling layers Exercise duplicate closure through dry-run/apply workflow branches instead of a separate hand-built apply plan. Remove copied CLI inventories and exact prose while retaining evidence, commit references, mutation order and bounded GitHub calls. Retain representative root/nested and hoisted/isolated package-bin cases; UI build remains covered by ui.test.ts and browser ffmpeg installation by ensure-playwright-chromium.test.ts. Remove duplicate delayed completion replay covered by pr-merge-admin-completion.test.ts. Trim state and release fixtures; remove snapshot telemetry duplicated by native descriptor assertions and exact-byte hashing. Preserve identity, process termination, authority and cleanup paths. Static gates only; no tests run under the CI-only work order. * test(pr): deslop q0157 owner-boundary fixtures Replace package-command inventory replays with root, hoisted and isolated tests at the real package-bin CLI. Pnpm forwarding remains covered by pnpm-runner.test.ts and the UI consumer by ui.test.ts. Exercise release metadata directly through its prepared CLI instead of recopying its import graph. Remove the snapshot cancellation replay: the retained hash probe proves private read-only descriptors and unlinked paths before dispatch; pr-operation-lock.test.ts covers native SIGTERM supervision. Same-tree pair acceptance remains in pr-merge-correction.test.ts and post-GC retention in pr-merge-recovery.test.ts. Consolidate duplicate-close workflow paths and two repeated candidate-identity error rows, preserving candidate tarball and entrypoint regressions. Static-only gates: plain oxlint, oxfmt, diff check; no tests or coverage run. * test(ui): deslop q0158 tests Remove the duplicate composition-blur title scenario; new-session-page.title.e2e.test.ts retains the same timing and creation handoff, with the idle row retaining no-premature-create and hidden-hint assertions. Inline the single-use large-paste recording wrapper and reuse mobile progress and scroll assertions without changing their lifecycle, geometry, payload, or artifact contracts. Retain distinct startup, resize, guest authorization, sidebar, stale-build and panel-reload coverage. CI-only validation: plain oxlint, oxfmt and git diff --check. No tests or coverage run. Reduction is below the 40% target because further removals lack equivalent branch and lifecycle proof. * test(ui): consolidate q0158 e2e owner coverage Reduce the original shard from 1529 to 917 lines (40.0%). Keep global startup routing, reader resize, mobile clearance, guest authority/cancellation, real stale-build reload, and terminal adoption. Remove copied boot-module/storage inventories and per-theme replays, not their owner contracts. Large-image regressionba9700d59a(#99213): retain src/gateway/chat-attachments.test.ts (parses large clipboard data URL images without full base64 decoding), src/media/sniff-mime-from-base64.test.ts (sniffs large payloads from their prefix), ui/src/lib/bytes-base64.test.ts, chat-attachment-resize.browser.test.ts, chat-flow.image-handoff.e2e.test.ts and chat-transcript-geometry.test.tsx. These cover parsing, browser paste, send handoff and committed row sizing without the standalone capture suite. Startup/history/model catalog coverage remains in chat-send.test.ts, chat-pane-model-catalog.test.ts, app-host.chat-metadata.test.ts and chat-flow.messaging.e2e.test.ts. New-session readiness/reconnect coverage remains in new-session-page.early-submit.e2e.test.ts, new-session-page.catalog-reconnect.e2e.test.ts, palette-session-draft.warm-roster.test.tsx, draft.catalog-reconnect.test.ts and draft-native-terminal-start.test.ts. Panel lazy/restoration and one-read ownership remain in lazy-custom-element-recovery.e2e.test.ts, browser-panel-width.e2e.test.ts, browser-panel.test.ts, assistant-panel.test.ts and dock-panel-layout.test.tsx. Boot chunk exclusions remain in control-ui-chunking.test.ts. Sidebar presentation remains in sidebar-roster.e2e.test.ts; measured end-follow remains in chat-transcript-geometry-updates.browser.test.tsx and chat-transcript-end-follow.browser.test.ts. CI-only validation: oxfmt, plain oxlint and git diff --check passed. No tests, coverage, builds or Testbox commands run. Coordinator reviews the static owner mappings and hosted CI supplies execution proof. * test(tooling): deslop q0159 tests Remove repeated capacity permutations; retain each qualification, rejection, and backend branch. Multi-group selection scope remains covered by test/scripts/ci-node-test-plan.selection-capacity.test.ts. Keep the immutability assertion on retained positive selections. Consolidate sweeper skip fixtures without losing per-case mutation or logging assertions. Attached-CI behavior remains covered by the cancelled-CI row; preserve draft classification separately from the runner's early draft skip. * test(tooling): reduce q0159 harness and branch replays Use the existing command and Node-script fixtures for PTY ownership, output capture, and cleanup; retain all five PTY behaviors. Remove duplicated workflow-text assertions, archive wrapper/platform replay, and exact-pin mismatch variants. Keep two Parallels bootstrap outcomes; src/infra/runtime-guard.test.ts covers the Node version matrix. Nested artifact ownership remains covered by dist-artifact-ownership.test.ts: keeps declarations alive until their writer joins. Prior-CI always-bypass and admin conflict-resolution remain covered by pr-merge-prior-ci.test.ts: revalidates delegated CI bypass before dispatch; lands one pinned REST squash. Keep PR-only authority and each distinct denial. Reduce TSX conservative-import inputs to each guard path and native recovery failures to one per decision branch. Preserve live recovery, no-worker proof, file identity, and output validation. Static format, diff, and oxlint checks pass; no tests run in CI-only mode. * test(tooling): deduplicate q0159 capacity guards Run shared capacity rejection guards once instead of replaying them across three owner fixtures. Retain exact core and isolated qualification cases, and one mixed-group rejection. The precise gateway-client success path remains covered by ci-node-test-plan.test.ts: retains owner worker fallback in precise backend plans. Remove the revoked-bypass replay: pr-merge-prior-ci.test.ts revalidates delegated CI bypass before dispatch, including live revocation. Keep all other repository, membership, ruleset, and policy denial boundaries. Formatting, diff check, and plain oxlint passed; no test runs in CI-only mode. * test(ui): deslop q0160 tests * test(ui): remove redundant q0160 E2E layers Remove question-progress composition replays: question-flow owns takeover, draft restoration and backscroll; chat-composer-question owns progress disclosure; chat-details.browser, chat-details-mobile-host.browser and chat-details-arrival own disclosure, mobile retention and absent-card branches. Keep approval error isolation in overlays.test.ts (keeps a resolve failure attached to its older request) and inline rendering in chat-footer-view.test.ts. Active-run approval dispatch remains in chat-send-submit.annotations, chat-send-detached-deadline and chat-pane-bridge tests. Retain passive Inbox and no-auth sidebar rendering here. Keep navigation retirement in started-session-navigation and new-session-page.instant-thread; creation rejection and retry remain in new-session-page.transition. Keep personal visibility reversal and cold persistence in session-involvement, menu variants in session-menu.involvement, and retain the unique sidebar hide mutation here. Drop LTR left/right resize replays covered by resizable-divider, browser-panel-width and chat-panel-layout while retaining RTL and bottom pointer regression proof. Reuse splitColumns for comment fixtures and retain one editor case per ownership branch plus both reply-menu branches. CI-only: formatting, diff check and plain oxlint passed; no tests or coverage executed. Cumulative shard reduction is 1485 to 1097 lines (26.1%), below the requested 40%; unique remaining behavior retained. * test(ui): deslop q0162 tests Remove the mocked Processes replay: background-work.real-gateway.e2e.test.ts covers exact-instance Stop, retained output, panel switching and draft persistence; chat-processes-panel.test.ts covers shared reads and Stop isolation. Keep mention loading and reduced-motion proof in chat-mention-search.e2e.test.ts. Retain both native/catalog tab routes and both gestures without their redundant cross product. Connection draft/discard validation remains in connection-page.test.ts and view.render.test.tsx; retain real browser persistence and reconnect flows here. Trim optional capture plumbing and unrelated fixtures. Preserve scope-downgrade, catalog-involvement, shared-diff lifecycle and DST regression scenarios. CI-only campaign: formatting, diff-check and plain oxlint passed; runtime and coverage validation deferred to hosted CI. * test(ui): consolidate q0162 owner-covered e2e replays Reduce the shard from its 1415-line baseline to 849 lines (40%). This follow-up removes 273 lines beyond aa879d929405; no test or coverage runs under the CI-only work order. Keep PR scope retirement at session-pull-requests.test.ts: retires broad snapshots and passive reads when only own-session reads remain. app-sidebar-session-pr-indicators.test.ts covers same-client scope revocation and own-reader badge clearing. Keep restricted publication discovery in E2E. Keep focus and disabled picker behavior in agent-select-opening.browser.test.ts and resolved-name branches in lib/agents/display.test.ts. Preserve both New Session themes and hero/picker identity propagation. Connection-page.test.ts and view.render.test.tsx own reconnect callbacks, credentials and pending controls; E2E retains persisted drafts and held-handshake target replacement. Keep Environment disclosure in chat-details.browser.test.ts and visible demand lifecycle in chat-session-workspace.test.ts and chat-details-session.test.ts. Preserve E2E error retention and Environment/Review in-flight request sharing. Collapse catalog provider copies to unlinked, admitted and unadmitted rows; the projection branch depends on backing-key membership, not provider identity. Unmarked sidebar visibility remains in sidebar-rail-toggles.capture.e2e.test.ts and the retained new-tab scenario. * test(scripts): remove redundant q0161 proof layers Keep packing contracts here; runner environment propagation and serialization remain in ci-run-node-test-shard.test.ts. Replace cache file round trips with fresh-scheduler identity proof; test-projects-routing.test.ts and test-projects-build-admission.test.ts retain caller-boundary coverage. Remove copied schema registration inventories and duplicate memory drift variants; retain generated/native equivalence, generated admission drift, and foreign uniqueness. sqlite-schema-contract.test.ts covers common drift handling. Remove the mocked Docker success-tail harness and cron source grep; docker-build-helper.test.ts retains real cron runner and harness stdin/cleanup proof. Share iOS command fixtures, reuse the workflow expression evaluator, and retain one generic optional-cache tail invariant. Validation: oxfmt, plain oxlint, git diff --check. No tests or coverage run under CI-only policy. * test: preserve cache expiry and defer catalog cleanup * test: complete Swift cache workflow step fixture * test: retain native context meter capture boundary * test: preserve packing envelope assertion semantics
174 lines
6.7 KiB
TypeScript
174 lines
6.7 KiB
TypeScript
import { execFileSync } from "node:child_process";
|
|
import fs from "node:fs";
|
|
import path from "node:path";
|
|
import { pathToFileURL } from "node:url";
|
|
import { afterEach, expect, it, vi } from "vitest";
|
|
import * as managedCommands from "../../scripts/lib/managed-child-process.mts";
|
|
import { buildPluginNpmRuntime } from "../../scripts/lib/plugin-npm-runtime-build.mts";
|
|
import { awaitGateBeforeSettlement, createDeferred } from "../helpers/promise.js";
|
|
import { writeJsonFile } from "../helpers/temp-repo.js";
|
|
import { createScriptTestHarness } from "./test-helpers.js";
|
|
|
|
const { createTempDir } = createScriptTestHarness();
|
|
afterEach(() => {
|
|
vi.restoreAllMocks();
|
|
vi.unstubAllEnvs();
|
|
});
|
|
|
|
type AssetOptions = {
|
|
tracked?: boolean;
|
|
missing?: boolean;
|
|
generated?: boolean;
|
|
dependency?: string;
|
|
localDependency?: boolean;
|
|
};
|
|
function createAssetFixture(options: AssetOptions = {}) {
|
|
const { dependency, localDependency, generated, missing, tracked } = options;
|
|
const repoRoot = createTempDir("openclaw-selected-plugin-assets-");
|
|
const packageDir = path.join(repoRoot, "extensions", "demo");
|
|
const source = dependency
|
|
? `node_modules/${dependency}/private/message.txt`
|
|
: "assets/message.txt";
|
|
fs.mkdirSync(path.join(packageDir, "assets"), { recursive: true });
|
|
const file = (name: string) => path.join(packageDir, name);
|
|
const write = (name: string, value = "selected asset") => fs.writeFileSync(file(name), value);
|
|
fs.writeFileSync(path.join(repoRoot, "package.json"), '{"name":"openclaw","version":"1.0.0"}');
|
|
execFileSync("git", ["init", "--quiet"], { cwd: repoRoot });
|
|
writeJsonFile(file("package.json"), {
|
|
name: "@fixture/demo",
|
|
version: "1.0.0",
|
|
type: "module",
|
|
...(dependency ? { dependencies: { [dependency]: "1.0.0" } } : {}),
|
|
openclaw: {
|
|
extensions: ["./index.ts"],
|
|
build: {
|
|
runtimeFormat: "esm",
|
|
staticAssets: [{ source: `./${source}`, output: "assets/message.txt" }],
|
|
},
|
|
...(generated ? { assetScripts: { build: "node build-assets.cjs" } } : {}),
|
|
},
|
|
});
|
|
write("openclaw.plugin.json", '{"id":"demo"}');
|
|
write(
|
|
"index.ts",
|
|
'import { readFileSync } from "node:fs"; export const message = readFileSync(new URL("./assets/message.txt", import.meta.url), "utf8");',
|
|
);
|
|
if (dependency) {
|
|
for (const base of localDependency ? [repoRoot, packageDir] : [repoRoot]) {
|
|
const dependencyDir = path.join(base, "node_modules", dependency);
|
|
writeJsonFile(path.join(dependencyDir, "package.json"), {
|
|
name: dependency,
|
|
exports: { "./message": "./private/message.txt" },
|
|
});
|
|
fs.mkdirSync(path.join(dependencyDir, "private"), { recursive: true });
|
|
if (!(missing && base === packageDir)) {
|
|
fs.writeFileSync(
|
|
path.join(dependencyDir, "private/message.txt"),
|
|
localDependency && base === repoRoot ? "wrong ancestor version" : "selected asset",
|
|
);
|
|
}
|
|
}
|
|
} else if (generated) {
|
|
write(
|
|
"build-assets.cjs",
|
|
'require("node:fs").writeFileSync("assets/message.txt", "selected asset");',
|
|
);
|
|
} else if (!missing) {
|
|
write("assets/message.txt");
|
|
}
|
|
if (tracked) {
|
|
execFileSync("git", ["add", "extensions/demo/package.json"], { cwd: repoRoot });
|
|
}
|
|
return { repoRoot, packageDir, source, file, write, logLevel: "silent" as const };
|
|
}
|
|
|
|
it("isolates and awaits bounded asset hooks before publishing package assets", async () => {
|
|
const fixture = createAssetFixture({ generated: true });
|
|
fixture.write(fixture.source, "previous source asset");
|
|
vi.stubEnv("TSX_TSCONFIG_PATH", "/release-tooling/tsconfig.json");
|
|
const started = createDeferred<Parameters<typeof managedCommands.runManagedCommand>[0]>();
|
|
const command = createDeferred<number>();
|
|
vi.spyOn(managedCommands, "runManagedCommand").mockImplementationOnce((options) => {
|
|
started.resolve(options);
|
|
return command.promise;
|
|
});
|
|
const building = buildPluginNpmRuntime(fixture);
|
|
const built = building.catch((error: unknown) => error);
|
|
try {
|
|
const options = await awaitGateBeforeSettlement(
|
|
started.promise,
|
|
building,
|
|
"Package builder completed without bounded asset execution",
|
|
);
|
|
expect(options).toMatchObject({
|
|
timeoutMs: 600_000,
|
|
requireProcessTreeExit: process.platform !== "win32",
|
|
env: { PATH: process.env.PATH },
|
|
});
|
|
expect(options.env).not.toHaveProperty("TSX_TSCONFIG_PATH");
|
|
const output = fixture.file("dist/assets/message.txt");
|
|
expect(fs.existsSync(output)).toBe(false);
|
|
const failure = Object.assign(new Error("joined asset timeout"), {
|
|
code: "ETIMEDOUT",
|
|
processTreeState: "terminated",
|
|
});
|
|
command.reject(failure);
|
|
expect(await built).toMatchObject({
|
|
code: "ETIMEDOUT",
|
|
message: "Plugin asset build hook timed out after 600000ms: demo",
|
|
cause: failure,
|
|
});
|
|
expect(fs.existsSync(output)).toBe(false);
|
|
expect(fs.readFileSync(fixture.file(fixture.source), "utf8")).toBe("previous source asset");
|
|
} finally {
|
|
command.resolve(0);
|
|
await built;
|
|
}
|
|
});
|
|
|
|
it.each<AssetOptions>([
|
|
{ tracked: true },
|
|
{ dependency: "engine" },
|
|
{ dependency: "@fixture/engine", localDependency: true },
|
|
{ tracked: true, missing: true },
|
|
{ tracked: true, missing: true, dependency: "@fixture/engine", localDependency: true },
|
|
])("builds loadable assets or rejects missing sources (%j)", async (options) => {
|
|
const fixture = createAssetFixture(options);
|
|
if (options.missing) {
|
|
await expect(buildPluginNpmRuntime(fixture)).rejects.toThrow(
|
|
`demo missing static asset source(s): extensions/demo/${fixture.source}`,
|
|
);
|
|
return;
|
|
}
|
|
if (options.tracked) {
|
|
const other = path.join(fixture.repoRoot, "extensions", "other");
|
|
fs.mkdirSync(other);
|
|
fs.writeFileSync(path.join(other, "package.json"), "{");
|
|
execFileSync("git", ["add", "extensions/other/package.json"], { cwd: fixture.repoRoot });
|
|
}
|
|
|
|
writeJsonFile(fixture.file("openclaw.plugin.json"), {
|
|
id: "demo",
|
|
themes: [
|
|
{
|
|
id: "mission",
|
|
name: "Mission",
|
|
description: "Mission theme",
|
|
source: "theme.json",
|
|
icons: { rocket: "assets/rocket.svg" },
|
|
},
|
|
],
|
|
});
|
|
fixture.write("theme.json", "{}");
|
|
fixture.write("assets/rocket.svg", '<svg xmlns="http://www.w3.org/2000/svg"/>');
|
|
const result = await buildPluginNpmRuntime(fixture);
|
|
expect(result).toMatchObject({
|
|
packageFiles: expect.arrayContaining(["theme.json", "assets/rocket.svg"]),
|
|
copiedStaticAssets: ["dist/assets/message.txt"],
|
|
});
|
|
const entry = pathToFileURL(fixture.file("dist/index.js")).href;
|
|
const script = `process.stdout.write((await import(${JSON.stringify(entry)})).message);`;
|
|
expect(
|
|
execFileSync(process.execPath, ["--input-type=module", "--eval", script], { encoding: "utf8" }),
|
|
).toBe("selected asset");
|
|
});
|