ReMe/integrations/dsh/tests/bundle.test.mjs
LiangshouX 6f1ecf06aa feat(dsh): add Environment tab with local Python detection
Adds a read-only Environment tab to the ReMe Memory settings card so
users can see why the ReMe service is unreachable before touching a
terminal:

- discover local Python interpreters via the PEP 514 registry, py
  launcher, PATH and conda (base + named envs), then verify every
  candidate by actually running it
- classify origins (conda base/env, python.org, Microsoft Store, venv,
  system PATH), drop Store alias stubs, and suggest a preferred
  interpreter (Python >= 3.11, named conda envs first)
- expose detection to the browser through a new remeEnv host gateway
  (TypertRemoteService) and render it with a connection health check
- config gains optional authToken and pythonPath fields with unchanged
  defaults; existing memory settings keep their behavior

Parsing is fixture-tested against real tool output on Windows (GBK
codepages, localized reg labels, missing py launcher) and Linux.
2026-10-27 16:57:36 +08:00

146 lines
4.2 KiB
JavaScript

import assert from "node:assert/strict";
import { readFile } from "node:fs/promises";
import { createRequire } from "node:module";
import test from "node:test";
import vm from "node:vm";
import semver from "semver";
test("declares one installable DeepSeek Harness plugin", async () => {
const manifest = JSON.parse(
await readFile(new URL("../package.json", import.meta.url), "utf8"),
);
const patch = await readFile(
new URL("../cordis.patch.yml", import.meta.url),
"utf8",
);
assert.equal(manifest.name, "@agentscope-ai/reme-dsh-plugin");
assert.equal(manifest.exports["."].import, "./dist/index.js");
assert.equal(manifest.exports["./client"].default, "./dist/client.js");
assert.equal(manifest.dsh.client.platform, "web");
assert.equal(manifest.dsh.bundle.patch, "./cordis.patch.yml");
assert.equal(manifest.dependencies, undefined);
for (const dependency of [
"@deepseek-ai/dsh-client-ui-primitives",
"@deepseek-ai/dsh-llm",
"@deepseek-ai/dsh-tools",
"@deepseek-ai/dsh-typert-protocol",
]) {
for (const version of [
"0.1.7-rc.2",
"0.2.0-rc.2",
"0.2.1-alpha.2",
"0.2.1-alpha.4",
"0.2.1-rc.2",
]) {
assert.ok(
semver.satisfies(version, manifest.peerDependencies[dependency]),
);
}
for (const version of [
"0.1.6",
"0.2.0-rc.1",
"0.2.2-alpha.1",
"0.3.0-alpha.1",
"0.3.0",
]) {
assert.equal(
semver.satisfies(version, manifest.peerDependencies[dependency]),
false,
);
}
assert.equal(manifest.peerDependenciesMeta[dependency]?.optional, true);
}
assert.equal(manifest.peerDependencies.openclaw, undefined);
assert.match(patch, /remeMemory: true/);
assert.match(patch, /id: reme-memory-scope[\s\S]*id: reme-memory\r?\n/);
assert.doesNotMatch(patch, /id: reme-memory-runtime/);
assert.doesNotMatch(patch, /@agentscope-ai\/reme\/dsh/);
assert.equal(patch.match(/@agentscope-ai\/reme-dsh-plugin/g)?.length, 1);
assert.doesNotMatch(patch, /reme-memory-client/);
});
test("builds a lazy DSH browser module for the ReMe settings card", async () => {
const bundle = await readFile(
new URL("../dist/client.js", import.meta.url),
"utf8",
);
const statusPage = await readFile(
new URL("../src/client/status-page.tsx", import.meta.url),
"utf8",
);
assert.match(bundle, /window\.__ModuleLoader__\.load/);
assert.match(bundle, /id: "@agentscope-ai\/reme-dsh-plugin"/);
assert.match(bundle, /plugins\.row\.config/);
assert.match(bundle, /reme-status/);
assert.match(bundle, /Personal Knowledge Base/);
assert.match(statusPage, /个人知识库/);
assert.match(bundle, /health_check/);
});
test("registers configuration on the ReMe bundle row", async () => {
const bundle = await readFile(
new URL("../dist/client.js", import.meta.url),
"utf8",
);
let module;
const document = {
head: { appendChild() {} },
createElement() {
return { dataset: {}, remove() {} };
},
};
vm.runInNewContext(bundle, {
document,
window: {
__ModuleLoader__: {
load(value) {
module = value;
},
},
},
});
const nodeRequire = createRequire(import.meta.url);
const client = module.factory((name) =>
name === "@deepseek-ai/dsh-client-ui-primitives" ? {} : nodeRequire(name),
);
const registrations = [];
const ctx = {
locale: {
bind() {
return (key) => (key === "title" ? "ReMe Memory" : key);
},
register() {
return () => {};
},
},
configForms: {
get() {
return {};
},
whileServed(_namespaces, register) {
return register();
},
},
slots: {
inject(_name, register) {
return register();
},
register(options) {
registrations.push(options);
return () => {};
},
},
get() {
return { rpc: {} };
},
effect(execute) {
return execute();
},
};
client.apply(ctx);
const item = registrations.find(
(options) => options.name === "plugins.row.config",
);
assert.equal(item.key, "@agentscope-ai/reme-dsh-plugin#reme-memory");
assert.equal(item.label(), "ReMe Memory");
});