Files
openclaw/test/scripts/ts-guard-utils.test.ts
Sliverp 84c7d45f15 refactor(qqbot): install plugin from Tencent package (#107295)
* refactor(qqbot): remove bundled extension source

Mechanical deletion half of the #107295 squashed rebase; the catalog
repoint and host integration land in the follow-up commit.

Co-authored-by: sliverp <870080352@qq.com>

* refactor(qqbot): install plugin from Tencent package

Squashed rebase of #107295 onto current main. Repoints the official
external channel catalog at @tencent-connect/openclaw-qqbot@2.0.1 and
adapts onboarding, doctor migrations, secrets, build guards, and tests.

Documents the known limitation that the external package does not
support structured SecretRef clientSecret values; operators move those
to QQBOT_CLIENT_SECRET or clientSecretFile before upgrading.

Co-authored-by: sliverp <870080352@qq.com>

* fix(doctor): reuse shared hasOwnKey record helper

The rebased QQBot migration carried its own hasOwnKey export, colliding
with the one main now ships in legacy-config-record-shared.ts.

Co-authored-by: sliverp <870080352@qq.com>

* fix(plugins): carry catalog integrity through the update bridge

The externalized-bundled-plugin bridge dropped the official catalog's
expectedIntegrity pin, so bundled-user updates installed the external
npm package without integrity verification. The bridge now carries the
pin for the catalog's exact npm spec and both bridge install calls pass
it through; update-channel spec overrides intentionally skip the pin
since it only covers the pinned version.

Co-authored-by: sliverp <870080352@qq.com>

* chore(plugin-sdk): refresh per-entrypoint API baselines

The QQBot compat export and bundled-type removal shift 26 entrypoint
closure hashes in the new split baseline layout.

Co-authored-by: sliverp <870080352@qq.com>

* refactor(qqbot): drop helper reintroduced during rebase

Main's coercion consolidation added this file after the deletion
commit's base; its only consumers were the removed qqbot sources.

Co-authored-by: sliverp <870080352@qq.com>

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-08-11 15:10:27 -07:00

69 lines
2.8 KiB
TypeScript

// Ts Guard Utils tests cover ts guard utils script behavior.
import { existsSync, mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
import { tmpdir } from "node:os";
import path from "node:path";
import { pathToFileURL } from "node:url";
import { describe, expect, it } from "vitest";
import { resolveRepoRoot } from "../../scripts/lib/repo-root.mjs";
/**
* Regression tests for resolveRepoRoot().
*
* The original implementation went up exactly two levels from the caller's
* import.meta.url, which broke for scripts at scripts/*.mjs (one level below
* root) — it overshot to the repo's parent directory.
*/
describe("resolveRepoRoot", () => {
it("resolves correctly from a scripts/lib/*.mjs path (two levels below root)", () => {
const fakeUrl = pathToFileURL(path.resolve("scripts", "lib", "some-guard-utils.mjs")).href;
const root = resolveRepoRoot(fakeUrl);
expect(existsSync(path.join(root, ".git"))).toBe(true);
expect(existsSync(path.join(root, "package.json"))).toBe(true);
});
it("resolves correctly from a scripts/*.mjs path (one level below root)", () => {
const fakeUrl = pathToFileURL(path.resolve("scripts", "check-no-raw-channel-fetch.mts")).href;
const root = resolveRepoRoot(fakeUrl);
expect(existsSync(path.join(root, ".git"))).toBe(true);
expect(existsSync(path.join(root, "package.json"))).toBe(true);
});
it("resolves correctly from a deeply nested extension path", () => {
const fakeUrl = pathToFileURL(
path.resolve("extensions", "telegram", "src", "utils", "hypothetical.mjs"),
).href;
const root = resolveRepoRoot(fakeUrl);
expect(existsSync(path.join(root, ".git"))).toBe(true);
expect(existsSync(path.join(root, "package.json"))).toBe(true);
});
it("all caller depths resolve to the same root", () => {
const fromLib = resolveRepoRoot(pathToFileURL(path.resolve("scripts", "lib", "a.mjs")).href);
const fromScripts = resolveRepoRoot(pathToFileURL(path.resolve("scripts", "b.mjs")).href);
const fromExtension = resolveRepoRoot(
pathToFileURL(path.resolve("extensions", "telegram", "c.mjs")).href,
);
expect(fromLib).toBe(fromScripts);
expect(fromScripts).toBe(fromExtension);
});
it("resolves an unpacked workspace without git metadata", () => {
const root = mkdtempSync(path.join(tmpdir(), "openclaw-repo-root-"));
try {
mkdirSync(path.join(root, "scripts", "nested"), { recursive: true });
writeFileSync(path.join(root, "package.json"), '{"name":"openclaw"}\n');
writeFileSync(path.join(root, "pnpm-workspace.yaml"), "packages: []\n");
expect(
resolveRepoRoot(pathToFileURL(path.join(root, "scripts", "nested", "tool.mjs")).href),
).toBe(root);
} finally {
rmSync(root, { recursive: true, force: true });
}
});
});