Files
openclaw/scripts/e2e/lib/fixtures/workspace.mjs
Peter Steinberger fe261b0f59 chore(tooling): typecheck root test/** with a dedicated tsgo lane (#104475)
* chore(types): add declaration files for scripts/lib and scripts/e2e modules

* chore(types): add declaration files for top-level script modules (a-m)

* chore(types): add declaration files for top-level script modules (n-z)

* test: use a non-secret-shaped gateway token fixture

* test: type ci workflow guard helpers for the root test lane

* chore(tooling): typecheck root test/** with a dedicated tsgo lane

- test/tsconfig/tsconfig.test.root.json: root-test program (strict unused checks,
  fixtures excluded; two Docker E2E clients that import built dist/** stay out,
  same rationale as the scripts/e2e exclusion in tsconfig.scripts.json)
- tsgo:test:root wired into tsgo:test, check:test-types, scripts/check.mjs, and
  the ci.yml test-types shard, mirroring the tsgo:scripts lane (#104348)
- changed-lane routing: test/**/*.ts (excluding fixtures) and the lane tsconfig
  now trigger 'typecheck test root' in check:changed; previously test/ paths ran
  lint only, so harness type errors surfaced first in CI (#104287 envDir case)
- burn down all 1071 latent type errors in the program: precise param/local
  types across test/scripts, test/vitest, test/e2e, and transitive scripts/e2e
  program members; 205 sibling .d.mts declaration files for imported .mjs
  modules (committed separately); zero any, zero ts-expect-error
- resolve the pre-existing testing star-export ambiguity in
  scripts/e2e/parallels/common.ts with an explicit re-export

Closes #104388

* chore(types): correct declaration fidelity per structured review

- re-derive 51 .d.mts files from implementation data flow instead of
  initializers: fix a wrong never return (runTestProjectsDelegation returns
  the child), add encoding-sensitive exec/spawn overloads (plain-gh), restore
  the full release profile union, make parsed paths string | null, add missing
  parseArgs fields via help/non-help unions, add a missing sibling declaration
  (budget-number-args), drop 15 unused lint directives
- precise install-record/tuple typing removes the type-aware oxlint
  regressions the first declarations caused in scripts/e2e implementations
- route .mts declaration edits under test/ to the testRoot lane and reference
  the test-root project from tsconfig.projects.json so tsgo:all covers it
  (closes both review findings against the lane wiring)

* chore(scripts): keep telegram runner dist typing structural for the boundary guard

* chore(types): declare runtime pack and gateway readiness exports added on main

* test: pin the importTargetPlan form of the plugin-contract plan import

The guard expectation still referenced the raw await import( form that
7ae5996bb3 (#103975) replaced with the importTargetPlan fallback helper;
the assertion fails on current main.
2026-07-11 06:15:41 -07:00

106 lines
4.1 KiB
JavaScript

// Workspace fixture writer commands for E2E scenarios.
import fs from "node:fs";
import path from "node:path";
import { readTextFileTail } from "../text-file-utils.mjs";
import { assert, readJson, requireArg, write, writeJson } from "./common.mjs";
const AGENTS_DELETE_OUTPUT_MAX_BYTES = readPositiveIntEnv(
"OPENCLAW_FIXTURE_AGENTS_DELETE_OUTPUT_MAX_BYTES",
1024 * 1024,
);
const ERROR_DETAIL_TAIL_BYTES = 16 * 1024;
function readPositiveIntEnv(name, fallback) {
const text = String(process.env[name] ?? fallback).trim();
if (!/^\d+$/u.test(text)) {
throw new Error(`invalid ${name}: ${text}`);
}
const value = Number(text);
if (!Number.isSafeInteger(value) || value <= 0) {
throw new Error(`invalid ${name}: ${text}`);
}
return value;
}
function writeOpenWebUiWorkspace() {
const workspace =
process.env.OPENCLAW_WORKSPACE_DIR || path.join(process.env.HOME, ".openclaw", "workspace");
write(
path.join(workspace, "IDENTITY.md"),
"# Identity\n\n- Name: OpenClaw\n- Purpose: Open WebUI Docker compatibility smoke test assistant.\n",
);
writeJson(path.join(workspace, ".openclaw", "workspace-state.json"), {
version: 1,
setupCompletedAt: "2026-01-01T00:00:00.000Z",
});
fs.rmSync(path.join(workspace, "BOOTSTRAP.md"), { force: true });
}
function writeAgentsDeleteConfig() {
const stateDir = requireArg(process.env.OPENCLAW_STATE_DIR, "OPENCLAW_STATE_DIR");
const sharedWorkspace = requireArg(process.env.SHARED_WORKSPACE, "SHARED_WORKSPACE");
const gatewayToken = process.env.OPENCLAW_GATEWAY_TOKEN?.trim();
fs.mkdirSync(sharedWorkspace, { recursive: true });
writeJson(path.join(stateDir, "openclaw.json"), {
agents: {
list: [
{ id: "main", workspace: sharedWorkspace },
{ id: "ops", workspace: sharedWorkspace },
],
},
...(gatewayToken ? { gateway: { auth: { mode: "token", token: gatewayToken } } } : {}),
});
}
function assertAgentsDeleteResult([outputPath]) {
const resolvedOutputPath = requireArg(outputPath, "outputPath");
const outputStat = fs.statSync(resolvedOutputPath);
if (outputStat.isFile() && outputStat.size > AGENTS_DELETE_OUTPUT_MAX_BYTES) {
throw new Error(
`agents delete --json output exceeded ${AGENTS_DELETE_OUTPUT_MAX_BYTES} bytes:\nstdout tail=${readTextFileTail(
resolvedOutputPath,
ERROR_DETAIL_TAIL_BYTES,
)}`,
);
}
let parsed;
try {
parsed = readJson(resolvedOutputPath);
} catch (error) {
console.error("agents delete --json did not emit valid JSON:");
console.error(readTextFileTail(resolvedOutputPath, ERROR_DETAIL_TAIL_BYTES).trim());
const message = error instanceof Error ? error.message.split("\n").at(0) : String(error);
throw new Error(`agents delete --json parse failed: ${message}`, { cause: error });
}
/** @type {Array<[unknown, unknown, string]>} */
const comparisons = [
[parsed.agentId, "ops", "agentId"],
[parsed.workspace, process.env.SHARED_WORKSPACE, "workspace"],
[parsed.workspaceRetained, true, "workspaceRetained"],
[parsed.workspaceRetainedReason, "shared", "workspaceRetainedReason"],
];
for (const [actual, expected, label] of comparisons) {
assert(actual === expected, `${label} mismatch: ${JSON.stringify(actual)}`);
}
assert(
Array.isArray(parsed.workspaceSharedWith) && parsed.workspaceSharedWith.includes("main"),
"missing shared-with main marker",
);
assert(fs.existsSync(process.env.SHARED_WORKSPACE), "shared workspace was removed");
const remaining =
readJson(path.join(process.env.OPENCLAW_STATE_DIR, "openclaw.json"))?.agents?.list ?? [];
assert(Array.isArray(remaining), "agents list missing after delete");
assert(!remaining.some((entry) => entry?.id === "ops"), "deleted agent remained in config");
assert(
remaining.some((entry) => entry?.id === "main"),
"main agent missing after delete",
);
console.log("agents delete shared workspace smoke ok");
}
export const workspaceCommands = {
"openwebui-workspace": writeOpenWebUiWorkspace,
"agents-delete-config": writeAgentsDeleteConfig,
"agents-delete-assert": assertAgentsDeleteResult,
};