refactor: move skill lifecycle code into skills subsystem

This commit is contained in:
Shakker
2026-05-28 19:35:55 +01:00
committed by Shakker
parent 22e2d1560f
commit bedfd4c200
69 changed files with 171 additions and 180 deletions

View File

@@ -13,11 +13,11 @@ import { getGlobalHookRunner } from "../plugins/hook-runner-global.js";
import { createEmptyPluginRegistry } from "../plugins/registry-empty.js";
import { setActivePluginRegistry } from "../plugins/runtime.js";
import { setPluginToolMeta } from "../plugins/tools.js";
import { createCanonicalFixtureSkill } from "../skills/test-helpers.js";
import {
runBeforeToolCallHook,
wrapToolWithBeforeToolCallHook,
} from "./agent-tools.before-tool-call.js";
import { createCanonicalFixtureSkill } from "./skills.test-helpers.js";
import { CRITICAL_THRESHOLD } from "./tool-loop-detection.js";
import type { AnyAgentTool } from "./tools/common.js";
import { callGatewayTool } from "./tools/gateway.js";

View File

@@ -5,8 +5,8 @@ import { describe, expect, it, vi } from "vitest";
import "./test-helpers/fast-coding-tools.js";
import "./test-helpers/fast-openclaw-tools.js";
import type { OpenClawConfig } from "../config/config.js";
import { createCanonicalFixtureSkill } from "../skills/test-helpers.js";
import { createOpenClawCodingTools } from "./agent-tools.js";
import { createCanonicalFixtureSkill } from "./skills.test-helpers.js";
import { expectReadWriteEditTools, getTextContent } from "./test-helpers/agent-tools-fs-helpers.js";
import { createAgentToolsSandboxContext } from "./test-helpers/agent-tools-sandbox-context.js";
import { createHostSandboxFsBridge } from "./test-helpers/host-sandbox-fs-bridge.js";

View File

@@ -3,7 +3,7 @@ import os from "node:os";
import path from "node:path";
import { afterEach, describe, expect, it } from "vitest";
import type { OpenClawConfig } from "../../config/config.js";
import { writePluginWithSkill } from "../test-helpers/skill-plugin-fixtures.js";
import { writePluginWithSkill } from "../../skills/skill-plugin-fixtures.test-support.js";
import { resolveEmbeddedRunSkillEntries } from "./skills-runtime.js";
const tempDirs: string[] = [];

View File

@@ -178,7 +178,7 @@ vi.mock("../agents/agent-scope.js", () => ({
mocks.resolveAgentWorkspaceDirMock(config, agentId),
}));
vi.mock("../agents/skills-clawhub.js", () => ({
vi.mock("../skills/clawhub.js", () => ({
searchSkillsFromClawHub: (...args: unknown[]) => mocks.searchSkillsFromClawHubMock(...args),
installSkillFromClawHub: (...args: unknown[]) => mocks.installSkillFromClawHubMock(...args),
updateSkillsFromClawHub: (...args: unknown[]) => mocks.updateSkillsFromClawHubMock(...args),
@@ -194,7 +194,7 @@ vi.mock("../infra/clawhub.js", () => ({
fetchClawHubSkillCard: (...args: unknown[]) => mocks.fetchClawHubSkillCardMock(...args),
}));
vi.mock("../agents/skills-source-install.js", () => ({
vi.mock("../skills/source-install.js", () => ({
installSkillFromSource: (...args: unknown[]) => mocks.installSkillFromSourceMock(...args),
isSkillSourceInstallSpec: (raw: string) =>
raw.startsWith("git:") ||
@@ -204,7 +204,7 @@ vi.mock("../agents/skills-source-install.js", () => ({
raw.startsWith("/"),
}));
vi.mock("../agents/skills-status.js", () => ({
vi.mock("../skills/status.js", () => ({
buildWorkspaceSkillStatus: (workspaceDir: string, options?: unknown) =>
mocks.buildWorkspaceSkillStatusMock(workspaceDir, options),
}));

View File

@@ -1,4 +1,4 @@
import type { SkillStatusEntry, SkillStatusReport } from "../agents/skills-status.js";
import type { SkillStatusEntry, SkillStatusReport } from "../skills/status.js";
import { sanitizeForLog, stripAnsi } from "../terminal/ansi.js";
import { decorativeEmoji, decorativePrefix } from "../terminal/decorative-emoji.js";
import { getTerminalTableWidth, renderTable } from "../terminal/table.js";

View File

@@ -2,9 +2,9 @@ import fs from "node:fs";
import os from "node:os";
import path from "node:path";
import { afterAll, beforeAll, describe, expect, it } from "vitest";
import { buildWorkspaceSkillStatus } from "../agents/skills-status.js";
import { createCanonicalFixtureSkill } from "../agents/skills.test-helpers.js";
import type { SkillEntry } from "../skills/index.js";
import { buildWorkspaceSkillStatus } from "../skills/status.js";
import { createCanonicalFixtureSkill } from "../skills/test-helpers.js";
import { captureEnv } from "../test-utils/env.js";
import { formatSkillInfo, formatSkillsCheck, formatSkillsList } from "./skills-cli.format.js";

View File

@@ -1,5 +1,5 @@
import { describe, expect, it, vi } from "vitest";
import type { SkillStatusEntry, SkillStatusReport } from "../agents/skills-status.js";
import type { SkillStatusEntry, SkillStatusReport } from "../skills/status.js";
import { createEmptyInstallChecks } from "./requirements-test-fixtures.js";
import { formatSkillInfo, formatSkillsCheck, formatSkillsList } from "./skills-cli.format.js";

View File

@@ -4,17 +4,6 @@ import {
resolveAgentWorkspaceDir,
resolveDefaultAgentId,
} from "../agents/agent-scope.js";
import {
installSkillFromClawHub,
readTrackedClawHubSkillSlugs,
resolveClawHubSkillVerificationTarget,
searchSkillsFromClawHub,
updateSkillsFromClawHub,
} from "../agents/skills-clawhub.js";
import {
installSkillFromSource,
isSkillSourceInstallSpec,
} from "../agents/skills-source-install.js";
import { getRuntimeConfig } from "../config/config.js";
import {
fetchClawHubSkillCard,
@@ -23,6 +12,14 @@ import {
} from "../infra/clawhub.js";
import { defaultRuntime } from "../runtime.js";
import { normalizeOptionalString } from "../shared/string-coerce.js";
import {
installSkillFromClawHub,
readTrackedClawHubSkillSlugs,
resolveClawHubSkillVerificationTarget,
searchSkillsFromClawHub,
updateSkillsFromClawHub,
} from "../skills/clawhub.js";
import { installSkillFromSource, isSkillSourceInstallSpec } from "../skills/source-install.js";
import { formatDocsLink } from "../terminal/links.js";
import { theme } from "../terminal/theme.js";
import { CONFIG_DIR } from "../utils.js";
@@ -38,7 +35,7 @@ export type {
export { formatSkillInfo, formatSkillsCheck, formatSkillsList } from "./skills-cli.format.js";
type SkillStatusReport = Awaited<
ReturnType<(typeof import("../agents/skills-status.js"))["buildWorkspaceSkillStatus"]>
ReturnType<(typeof import("../skills/status.js"))["buildWorkspaceSkillStatus"]>
>;
type ResolvedClawHubSkillVerificationTarget = Extract<
Awaited<ReturnType<typeof resolveClawHubSkillVerificationTarget>>,
@@ -79,7 +76,7 @@ async function loadSkillsStatusReport(
options?: ResolveSkillsWorkspaceOptions,
): Promise<SkillStatusReport> {
const { config, workspaceDir, agentId } = resolveSkillsWorkspace(options);
const { buildWorkspaceSkillStatus } = await import("../agents/skills-status.js");
const { buildWorkspaceSkillStatus } = await import("../skills/status.js");
return buildWorkspaceSkillStatus(workspaceDir, { config, agentId });
}

View File

@@ -1,5 +1,5 @@
import type { SkillStatusEntry, SkillStatusReport } from "../agents/skills-status.js";
import type { OpenClawConfig } from "../config/types.openclaw.js";
import type { SkillStatusEntry, SkillStatusReport } from "../skills/status.js";
export function collectUnavailableAgentSkills(report: SkillStatusReport): SkillStatusEntry[] {
return report.skills.filter(

View File

@@ -1,8 +1,8 @@
import { describe, expect, it } from "vitest";
import type { SkillStatusEntry, SkillStatusReport } from "../agents/skills-status.js";
import { createEmptyInstallChecks } from "../cli/requirements-test-fixtures.js";
import type { OpenClawConfig } from "../config/types.openclaw.js";
import type { GhConfigDiscoveryInput } from "../skills/gh-config-discovery.js";
import type { SkillStatusEntry, SkillStatusReport } from "../skills/status.js";
import {
collectUnavailableAgentSkills,
describeGhConfigDirHintFromDiscovery,

View File

@@ -1,7 +1,5 @@
import { existsSync } from "node:fs";
import { resolveAgentWorkspaceDir, resolveDefaultAgentId } from "../agents/agent-scope.js";
import type { SkillStatusEntry } from "../agents/skills-status.js";
import { buildWorkspaceSkillStatus } from "../agents/skills-status.js";
import { formatCliCommand } from "../cli/command-format.js";
import type { OpenClawConfig } from "../config/types.openclaw.js";
import {
@@ -10,6 +8,8 @@ import {
type GhConfigDiscoveryInput,
type GhConfigDiscoveryResult,
} from "../skills/gh-config-discovery.js";
import type { SkillStatusEntry } from "../skills/status.js";
import { buildWorkspaceSkillStatus } from "../skills/status.js";
import { note } from "../terminal/note.js";
import type { DoctorPrompter } from "./doctor-prompter.js";
import {

View File

@@ -22,7 +22,7 @@ vi.mock("../agents/agent-scope.js", () => ({
resolveDefaultAgentId: (...args: unknown[]) => mocks.resolveDefaultAgentId(...args),
}));
vi.mock("../agents/skills-status.js", () => ({
vi.mock("../skills/status.js", () => ({
buildWorkspaceSkillStatus: (...args: unknown[]) => mocks.buildWorkspaceSkillStatus(...args),
}));

View File

@@ -1,11 +1,11 @@
import { resolveAgentWorkspaceDir, resolveDefaultAgentId } from "../agents/agent-scope.js";
import { buildWorkspaceSkillStatus } from "../agents/skills-status.js";
import { formatCliCommand } from "../cli/command-format.js";
import type { OpenClawConfig } from "../config/types.openclaw.js";
import {
buildPluginCompatibilityWarnings,
buildPluginRegistrySnapshotReport,
} from "../plugins/status.js";
import { buildWorkspaceSkillStatus } from "../skills/status.js";
import { listTasksForFlowId } from "../tasks/runtime-internal.js";
import { listTaskFlowRecords } from "../tasks/task-flow-runtime-internal.js";
import { note } from "../terminal/note.js";

View File

@@ -242,7 +242,7 @@ vi.mock("@clack/prompts", () => ({
select,
}));
vi.mock("../agents/skills-status.js", () => ({
vi.mock("../skills/status.js", () => ({
buildWorkspaceSkillStatus: () => ({ skills: [] }),
}));

View File

@@ -17,10 +17,10 @@ const mocks = vi.hoisted(() => ({
}));
// Module under test imports these at module scope.
vi.mock("../agents/skills-status.js", () => ({
vi.mock("../skills/status.js", () => ({
buildWorkspaceSkillStatus: mocks.buildWorkspaceSkillStatus,
}));
vi.mock("../agents/skills-install.js", () => ({
vi.mock("../skills/install.js", () => ({
installSkill: mocks.installSkill,
}));
vi.mock("../infra/container-environment.js", () => ({

View File

@@ -1,10 +1,10 @@
import { installSkill } from "../agents/skills-install.js";
import { buildWorkspaceSkillStatus } from "../agents/skills-status.js";
import { formatCliCommand } from "../cli/command-format.js";
import type { OpenClawConfig } from "../config/types.openclaw.js";
import { resolveBrewExecutable } from "../infra/brew.js";
import { isContainerEnvironment } from "../infra/container-environment.js";
import type { RuntimeEnv } from "../runtime.js";
import { installSkill } from "../skills/install.js";
import { buildWorkspaceSkillStatus } from "../skills/status.js";
import { normalizeSecretInput } from "../utils/normalize-secret-input.js";
import { t } from "../wizard/i18n/index.js";
import type { WizardPrompter } from "../wizard/prompts.js";

View File

@@ -1,11 +1,11 @@
import { canExecRequestNode } from "../../agents/exec-defaults.js";
import { buildWorkspaceSkillStatus } from "../../agents/skills-status.js";
import { readConfigFileSnapshot, resolveGatewayPort } from "../../config/config.js";
import { readLastGatewayErrorLine } from "../../daemon/diagnostics.js";
import { inspectPortUsage } from "../../infra/ports.js";
import { readRestartSentinel } from "../../infra/restart-sentinel.js";
import { getRemoteSkillEligibility } from "../../infra/skills-remote.js";
import { buildPluginCompatibilityNotices } from "../../plugins/status.js";
import { buildWorkspaceSkillStatus } from "../../skills/status.js";
import { buildStatusAllOverviewRows } from "../status-overview-rows.ts";
import {
buildStatusOverviewSurfaceFromOverview,

View File

@@ -3,12 +3,12 @@ import fs from "node:fs/promises";
import path from "node:path";
import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
import { resolveEmbeddedRunSkillEntries } from "../../agents/embedded-agent-runner/skills-runtime.js";
import { createCanonicalFixtureSkill } from "../../agents/skills.test-helpers.js";
import type { Skill } from "../../skills/skill-contract.js";
import {
hydrateResolvedSkills,
hydrateResolvedSkillsAsync,
} from "../../skills/snapshot-hydration.js";
import { createCanonicalFixtureSkill } from "../../skills/test-helpers.js";
import { createSuiteTempRootTracker } from "../../test-helpers/temp-dir.js";
import type { SessionEntry, SessionSkillPromptRef, SessionSkillSnapshot } from "./types.js";

View File

@@ -22,7 +22,6 @@ import {
import { resolveDefaultModelForAgent } from "../agents/model-selection.js";
import { supportsModelTools } from "../agents/model-tool-support.js";
import { normalizeAgentRuntimeTools } from "../agents/runtime-plan/tools.js";
import { buildWorkspaceSkillStatus, type SkillStatusEntry } from "../agents/skills-status.js";
import { collectExplicitAllowlist, normalizeToolName } from "../agents/tool-policy.js";
import {
inspectRuntimeToolInputSchemas,
@@ -35,6 +34,7 @@ import { formatErrorMessage } from "../infra/errors.js";
import type { ProviderRuntimeModel } from "../plugins/provider-runtime-model.types.js";
import { getPluginToolMeta, setPluginToolMeta } from "../plugins/tools.js";
import { normalizeAgentId } from "../routing/session-key.js";
import { buildWorkspaceSkillStatus, type SkillStatusEntry } from "../skills/status.js";
import type { HealthFinding } from "./health-checks.js";
type BundleMcpToolRuntime = Awaited<ReturnType<typeof createBundleMcpToolRuntime>>;

View File

@@ -2,8 +2,8 @@ import { promises as fs } from "node:fs";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import type { SkillStatusEntry } from "../agents/skills-status.js";
import type { OpenClawConfig } from "../config/types.openclaw.js";
import type { SkillStatusEntry } from "../skills/status.js";
import {
CORE_HEALTH_CHECKS,
createCoreHealthChecks,

View File

@@ -1,6 +1,5 @@
import path from "node:path";
import { resolveAgentWorkspaceDir, resolveDefaultAgentId } from "../agents/agent-scope.js";
import type { SkillStatusEntry } from "../agents/skills-status.js";
import {
detectLegacyClawdBrowserProfileResidue,
maybeArchiveLegacyClawdBrowserProfileResidue,
@@ -19,6 +18,7 @@ import { hasAmbiguousGatewayAuthModeConfig } from "../gateway/auth-mode-policy.j
import { resolveGatewayAuthToken } from "../gateway/auth-token-resolution.js";
import { resolveGatewayAuth } from "../gateway/auth.js";
import { getSkippedExecRefStaticError } from "../secrets/exec-resolution-policy.js";
import type { SkillStatusEntry } from "../skills/status.js";
import { registerHealthCheck } from "./health-check-registry.js";
import type { HealthCheck, HealthCheckContext, HealthFinding } from "./health-checks.js";

View File

@@ -2,11 +2,11 @@ import { createHash, randomUUID } from "node:crypto";
import { createReadStream } from "node:fs";
import fs from "node:fs/promises";
import path from "node:path";
import { validateRequestedSkillSlug } from "../../agents/skills-archive-install.js";
import { resolveStateDir } from "../../config/paths.js";
import { DEFAULT_MAX_ARCHIVE_BYTES_ZIP } from "../../infra/archive.js";
import { formatErrorMessage } from "../../infra/errors.js";
import { createAsyncLock, readDurableJsonFile, writeJsonAtomic } from "../../infra/json-files.js";
import { validateRequestedSkillSlug } from "../../skills/archive-install.js";
export const SKILL_UPLOAD_TTL_MS = 60 * 60 * 1000;
export const MAX_SKILL_UPLOAD_CHUNK_BYTES = 4 * 1024 * 1024;

View File

@@ -1,3 +1,10 @@
import type { OpenClawConfig } from "../../config/types.openclaw.js";
import { formatErrorMessage } from "../../infra/errors.js";
import {
installSkillArchiveFromPath,
type SkillArchiveInstallFailureKind,
validateRequestedSkillSlug,
} from "../../skills/archive-install.js";
import {
ErrorCodes,
errorShape,
@@ -8,13 +15,6 @@ import {
validateSkillsUploadCommitParams,
} from "../../../packages/gateway-protocol/src/index.js";
import type { ErrorShape } from "../../../packages/gateway-protocol/src/index.js";
import {
installSkillArchiveFromPath,
type SkillArchiveInstallFailureKind,
validateRequestedSkillSlug,
} from "../../agents/skills-archive-install.js";
import type { OpenClawConfig } from "../../config/types.openclaw.js";
import { formatErrorMessage } from "../../infra/errors.js";
import {
defaultSkillUploadStore,
normalizeSkillUploadSha256,

View File

@@ -23,17 +23,17 @@ vi.mock("../../agents/agent-scope.js", () => ({
resolveSessionAgentId: vi.fn(() => undefined),
}));
vi.mock("../../agents/skills-clawhub.js", () => ({
vi.mock("../../skills/clawhub.js", () => ({
installSkillFromClawHub: (...args: unknown[]) => installSkillFromClawHubMock(...args),
readLocalSkillCardContentSync: (...args: unknown[]) => readLocalSkillCardContentSyncMock(...args),
updateSkillsFromClawHub: (...args: unknown[]) => updateSkillsFromClawHubMock(...args),
}));
vi.mock("../../agents/skills-status.js", () => ({
vi.mock("../../skills/status.js", () => ({
buildWorkspaceSkillStatus: (...args: unknown[]) => buildWorkspaceSkillStatusMock(...args),
}));
vi.mock("../../agents/skills-install.js", () => ({
vi.mock("../../skills/install.js", () => ({
installSkill: (...args: unknown[]) => installSkillMock(...args),
}));

View File

@@ -14,7 +14,7 @@ vi.mock("../../agents/agent-scope.js", () => ({
resolveAgentWorkspaceDir: vi.fn(() => "/tmp/workspace"),
}));
vi.mock("../../agents/skills-clawhub.js", () => ({
vi.mock("../../skills/clawhub.js", () => ({
installSkillFromClawHub: vi.fn(),
updateSkillsFromClawHub: vi.fn(),
searchSkillsFromClawHub: (...args: unknown[]) => searchSkillsFromClawHubMock(...args),
@@ -27,7 +27,7 @@ vi.mock("../../infra/clawhub.js", () => ({
downloadClawHubSkillArchive: vi.fn(),
}));
vi.mock("../../agents/skills-install.js", () => ({
vi.mock("../../skills/install.js", () => ({
installSkill: vi.fn(),
}));

View File

@@ -17,14 +17,6 @@ import {
resolveDefaultAgentId,
} from "../../agents/agent-scope.js";
import { canExecRequestNode } from "../../agents/exec-defaults.js";
import {
installSkillFromClawHub,
readLocalSkillCardContentSync,
searchSkillsFromClawHub,
updateSkillsFromClawHub,
} from "../../agents/skills-clawhub.js";
import { installSkill } from "../../agents/skills-install.js";
import { buildWorkspaceSkillStatus } from "../../agents/skills-status.js";
import { listAgentWorkspaceDirs } from "../../agents/workspace-dirs.js";
import { redactConfigObject } from "../../config/redact-snapshot.js";
import {
@@ -37,7 +29,15 @@ import { formatErrorMessage } from "../../infra/errors.js";
import { getRemoteSkillEligibility } from "../../infra/skills-remote.js";
import { normalizeAgentId } from "../../routing/session-key.js";
import { normalizeOptionalString } from "../../shared/string-coerce.js";
import {
installSkillFromClawHub,
readLocalSkillCardContentSync,
searchSkillsFromClawHub,
updateSkillsFromClawHub,
} from "../../skills/clawhub.js";
import { loadWorkspaceSkillEntries, type SkillEntry } from "../../skills/index.js";
import { installSkill } from "../../skills/install.js";
import { buildWorkspaceSkillStatus } from "../../skills/status.js";
import { updateSkillConfigEntry } from "./skills-config-mutations.js";
import { installUploadedSkillArchive, skillsUploadHandlers } from "./skills-upload.js";
import type { GatewayRequestContext, GatewayRequestHandlers } from "./types.js";

View File

@@ -14,7 +14,7 @@ export {
createSandboxPruneConfig,
createSandboxSshConfig,
} from "./test-helpers/sandbox-fixtures.js";
export { writeSkill } from "../agents/skills.e2e-test-helpers.js";
export { writeSkill } from "../skills/e2e-test-helpers.js";
export {
castAgentMessage,
makeAgentAssistantMessage,

View File

@@ -107,7 +107,7 @@ export {
isLiveTestEnabled,
} from "../agents/live-test-helpers.js";
export { createSandboxTestContext } from "../agents/sandbox/test-fixtures.js";
export { writeSkill } from "../agents/skills.e2e-test-helpers.js";
export { writeSkill } from "../skills/e2e-test-helpers.js";
export {
castAgentMessage,
makeAgentAssistantMessage,

View File

@@ -6,11 +6,11 @@ import {
restoreMockSkillsHomeEnv,
setMockSkillsHomeEnv,
type SkillsHomeEnvSnapshot,
} from "../skills/home-env.test-support.js";
import { buildWorkspaceSkillsPrompt } from "../skills/workspace.js";
import { writeSkill } from "./skills.test-helpers.js";
} from "./home-env.test-support.js";
import { writeSkill } from "./test-helpers.js";
import { buildWorkspaceSkillsPrompt } from "./workspace.js";
vi.mock("../skills/plugin-skills.js", () => ({
vi.mock("./plugin-skills.js", () => ({
resolvePluginSkillDirs: () => [],
}));

View File

@@ -7,7 +7,7 @@ import { createTrackedTempDirs } from "../test-utils/tracked-temp-dirs.js";
import {
CLAWHUB_SKILL_ARCHIVE_ROOT_MARKERS,
installExtractedSkillRoot,
} from "./skills-archive-install.js";
} from "./archive-install.js";
const tempDirs = createTrackedTempDirs();

View File

@@ -3,9 +3,9 @@ import os from "node:os";
import path from "node:path";
import { pathToFileURL } from "node:url";
import { afterEach, beforeEach, describe, expect, it } from "vitest";
import { writeSkill } from "../skills.e2e-test-helpers.js";
import { captureEnv } from "../test-utils/env.js";
import { resolveBundledSkillsDir } from "./bundled-dir.js";
import { writeSkill } from "./e2e-test-helpers.js";
describe("resolveBundledSkillsDir", () => {
let envSnapshot: ReturnType<typeof captureEnv>;

View File

@@ -2,7 +2,7 @@ import fs from "node:fs/promises";
import path from "node:path";
import { fileURLToPath } from "node:url";
import { describe, expect, it } from "vitest";
import { parseFrontmatter } from "../skills/frontmatter.js";
import { parseFrontmatter } from "./frontmatter.js";
const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../..");

View File

@@ -38,7 +38,7 @@ const {
resolveClawHubSkillVerificationTarget,
searchSkillsFromClawHub,
updateSkillsFromClawHub,
} = await import("./skills-clawhub.js");
} = await import("./clawhub.js");
function expectInstallPackageSourceDir(sourceDir: string) {
const call = installPackageDirMock.mock.calls.at(0);

View File

@@ -18,7 +18,7 @@ import {
normalizeTrackedSkillSlug,
resolveWorkspaceSkillInstallDir,
validateRequestedSkillSlug,
} from "./skills-archive-install.js";
} from "./archive-install.js";
const DOT_DIR = ".clawhub";
const LEGACY_DOT_DIR = ".clawdhub";

View File

@@ -2,13 +2,13 @@ import os from "node:os";
import { formatSkillsForPrompt as upstreamFormatSkillsForPrompt } from "openclaw/plugin-sdk/agent-sessions";
import { afterEach, beforeEach, describe, expect, it } from "vitest";
import type { OpenClawConfig } from "../config/config.js";
import { createCanonicalFixtureSkill } from "../skills.test-helpers.js";
import {
restoreMockSkillsHomeEnv,
setMockSkillsHomeEnv,
type SkillsHomeEnvSnapshot,
} from "./home-env.test-support.js";
import { formatSkillsForPrompt, type Skill } from "./skill-contract.js";
import { createCanonicalFixtureSkill } from "./test-helpers.js";
import type { SkillEntry } from "./types.js";
import {
formatSkillsCompact,

View File

@@ -1,11 +1,8 @@
import os from "node:os";
import path from "node:path";
import { describe, expect, it } from "vitest";
import {
testing as workspaceSkillsTesting,
buildWorkspaceSkillsPrompt,
} from "../skills/workspace.js";
import { createCanonicalFixtureSkill } from "./skills.test-helpers.js";
import { createCanonicalFixtureSkill } from "./test-helpers.js";
import { testing as workspaceSkillsTesting, buildWorkspaceSkillsPrompt } from "./workspace.js";
describe("compactSkillPaths", () => {
function buildPromptForFixtureSkill(params: {

View File

@@ -1,7 +1,7 @@
import fs from "node:fs";
import path from "node:path";
import { describe, expect, it } from "vitest";
import { parseFrontmatter } from "../skills/frontmatter.js";
import { parseFrontmatter } from "./frontmatter.js";
describe("skills/summarize frontmatter", () => {
it("mentions podcasts, local files, and transcription use cases", () => {

View File

@@ -2,7 +2,7 @@ import fs from "node:fs/promises";
import os from "node:os";
import path from "node:path";
import { afterEach, describe, expect, it } from "vitest";
import { writeSkill } from "./skills.e2e-test-helpers.js";
import { writeSkill } from "./e2e-test-helpers.js";
const tempDirs: string[] = [];

View File

@@ -3,16 +3,16 @@ import os from "node:os";
import path from "node:path";
import { Readable } from "node:stream";
import { afterAll, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
import { resolveSkillToolsRootDir } from "../skills/tools-dir.js";
import type { SkillEntry, SkillInstallSpec } from "../skills/types.js";
import { installDownloadSpec } from "./skills-install-download.js";
import { setTempStateDir } from "./skills-install.download-test-utils.js";
import { setTempStateDir } from "./install-download-test-utils.js";
import { installDownloadSpec } from "./install-download.js";
import {
fetchWithSsrFGuardMock,
hasBinaryMock,
runCommandWithTimeoutMock,
} from "./skills-install.test-mocks.js";
import { createCanonicalFixtureSkill } from "./skills.test-helpers.js";
} from "./install-test-mocks.js";
import { createCanonicalFixtureSkill } from "./test-helpers.js";
import { resolveSkillToolsRootDir } from "./tools-dir.js";
import type { SkillEntry, SkillInstallSpec } from "./types.js";
vi.mock("../process/exec.js", () => ({
runCommandWithTimeout: (...args: unknown[]) => runCommandWithTimeoutMock(...args),
@@ -22,7 +22,7 @@ vi.mock("../infra/net/fetch-guard.js", () => ({
fetchWithSsrFGuard: (...args: unknown[]) => fetchWithSsrFGuardMock(...args),
}));
vi.mock("../skills/index.js", () => ({
vi.mock("./index.js", () => ({
hasBinary: (bin: string) => hasBinaryMock(bin),
}));

View File

@@ -12,13 +12,13 @@ import { fetchWithSsrFGuard } from "../infra/net/fetch-guard.js";
import { isWithinDir } from "../infra/path-safety.js";
import { createLazyImportLoader } from "../shared/lazy-promise.js";
import { normalizeOptionalLowercaseString } from "../shared/string-coerce.js";
import type { SkillEntry, SkillInstallSpec } from "../skills/index.js";
import { resolveSkillToolsRootDir } from "../skills/tools-dir.js";
import { ensureDir, resolveUserPath } from "../utils.js";
import { formatInstallFailureMessage } from "./skills-install-output.js";
import type { SkillInstallResult } from "./skills-install.types.js";
import type { SkillEntry, SkillInstallSpec } from "./index.js";
import { formatInstallFailureMessage } from "./install-output.js";
import type { SkillInstallResult } from "./install-types.js";
import { resolveSkillToolsRootDir } from "./tools-dir.js";
const extractModuleLoader = createLazyImportLoader(() => import("./skills-install-extract.js"));
const extractModuleLoader = createLazyImportLoader(() => import("./install-extract.js"));
async function loadExtractModule() {
return await extractModuleLoader.load();

View File

@@ -10,8 +10,8 @@ import {
import { formatErrorMessage } from "../infra/errors.js";
import { runCommandWithTimeout } from "../process/exec.js";
import { normalizeStringEntries } from "../shared/string-normalization.js";
import { hasBinary } from "../skills/index.js";
import { parseTarVerboseMetadata } from "./skills-install-tar-verbose.js";
import { hasBinary } from "./index.js";
import { parseTarVerboseMetadata } from "./install-tar-verbose.js";
export type ArchiveExtractResult = { stdout: string; stderr: string; code: number | null };
type TarPreflightResult = {

View File

@@ -2,9 +2,9 @@ import fs from "node:fs/promises";
import os from "node:os";
import path from "node:path";
import { afterAll, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
import type { SkillEntry, SkillInstallSpec } from "../skills/index.js";
import { captureEnv } from "../test-utils/env.js";
import { hasBinaryMock, runCommandWithTimeoutMock } from "./skills-install.test-mocks.js";
import type { SkillEntry, SkillInstallSpec } from "./index.js";
import { hasBinaryMock, runCommandWithTimeoutMock } from "./install-test-mocks.js";
const skillsMocks = vi.hoisted(() => ({
loadWorkspaceSkillEntries: vi.fn(),
@@ -18,19 +18,19 @@ vi.mock("../plugins/install-security-scan.js", () => ({
scanSkillInstallSource: vi.fn(async () => undefined),
}));
vi.mock("../skills/index.js", async (importOriginal) => {
const actual = await importOriginal<typeof import("../skills/index.js")>();
vi.mock("./index.js", async (importOriginal) => {
const actual = await importOriginal<typeof import("./index.js")>();
return {
...actual,
loadWorkspaceSkillEntries: skillsMocks.loadWorkspaceSkillEntries,
};
});
let installSkill: typeof import("./skills-install.js").installSkill;
let skillsInstallTesting: typeof import("./skills-install.js").testing;
let installSkill: typeof import("./install.js").installSkill;
let skillsInstallTesting: typeof import("./install.js").testing;
async function loadSkillsInstallModulesForTest() {
({ installSkill, testing: skillsInstallTesting } = await import("./skills-install.js"));
({ installSkill, testing: skillsInstallTesting } = await import("./install.js"));
}
function makeSkillEntry(

View File

@@ -6,16 +6,13 @@ import {
resetGlobalHookRunner,
} from "../plugins/hook-runner-global.js";
import { createMockPluginRegistry } from "../plugins/hooks.test-helpers.js";
import { resolveOpenClawMetadata, resolveSkillInvocationPolicy } from "../skills/frontmatter.js";
import { loadSkillsFromDirSafe, readSkillFrontmatterSafe } from "../skills/local-loader.js";
import type { SkillEntry } from "../skills/types.js";
import { captureEnv } from "../test-utils/env.js";
import { createFixtureSuite } from "../test-utils/fixture-suite.js";
import { installSkill, testing as skillsInstallTesting } from "./skills-install.js";
import {
runCommandWithTimeoutMock,
scanDirectoryWithSummaryMock,
} from "./skills-install.test-mocks.js";
import { resolveOpenClawMetadata, resolveSkillInvocationPolicy } from "./frontmatter.js";
import { runCommandWithTimeoutMock, scanDirectoryWithSummaryMock } from "./install-test-mocks.js";
import { installSkill, testing as skillsInstallTesting } from "./install.js";
import { loadSkillsFromDirSafe, readSkillFrontmatterSafe } from "./local-loader.js";
import type { SkillEntry } from "./types.js";
vi.mock("../process/exec.js", () => ({
runCommandWithTimeout: (...args: unknown[]) => runCommandWithTimeoutMock(...args),
@@ -25,7 +22,7 @@ vi.mock("../security/skill-scanner.js", () => ({
scanDirectoryWithSummary: (...args: unknown[]) => scanDirectoryWithSummaryMock(...args),
}));
vi.mock("../skills/plugin-skills.js", () => ({
vi.mock("./plugin-skills.js", () => ({
resolvePluginSkillDirs: () => [],
}));

View File

@@ -11,6 +11,7 @@ import {
type SkillInstallSpecMetadata,
} from "../plugins/install-security-scan.js";
import { runCommandWithTimeout, type CommandOptions } from "../process/exec.js";
import { resolveUserPath } from "../utils.js";
import {
hasBinary as defaultHasBinary,
loadWorkspaceSkillEntries as defaultLoadWorkspaceSkillEntries,
@@ -18,12 +19,11 @@ import {
type SkillEntry,
type SkillInstallSpec,
type SkillsInstallPreferences,
} from "../skills/index.js";
import { resolveSkillSource } from "../skills/source.js";
import { resolveUserPath } from "../utils.js";
import { installDownloadSpec } from "./skills-install-download.js";
import { formatInstallFailureMessage } from "./skills-install-output.js";
import type { SkillInstallResult } from "./skills-install.types.js";
} from "./index.js";
import { installDownloadSpec } from "./install-download.js";
import { formatInstallFailureMessage } from "./install-output.js";
import type { SkillInstallResult } from "./install-types.js";
import { resolveSkillSource } from "./source.js";
export type SkillInstallRequest = InstallSafetyOverrides & {
workspaceDir: string;
@@ -32,7 +32,7 @@ export type SkillInstallRequest = InstallSafetyOverrides & {
timeoutMs?: number;
config?: OpenClawConfig;
};
export type { SkillInstallResult } from "./skills-install.types.js";
export type { SkillInstallResult } from "./install-types.js";
type SkillsInstallDeps = {
hasBinary: (bin: string) => boolean;

View File

@@ -3,13 +3,13 @@ import fsPromises from "node:fs/promises";
import os from "node:os";
import path from "node:path";
import { afterAll, beforeAll, describe, expect, it, vi } from "vitest";
import { buildWorkspaceSkillsPrompt, syncSkillsToWorkspace } from "../skills/workspace.js";
import { writeSkill } from "./skills.e2e-test-helpers.js";
import { writeSkill } from "./e2e-test-helpers.js";
import { buildWorkspaceSkillsPrompt, syncSkillsToWorkspace } from "./workspace.js";
// Mock resolvePluginSkillDirs to return our test plugin skill directories
const mockResolvePluginSkillDirs = vi.hoisted(() => vi.fn(() => [] as string[]));
vi.mock("../skills/plugin-skills.js", () => ({
vi.mock("./plugin-skills.js", () => ({
resolvePluginSkillDirs: mockResolvePluginSkillDirs,
}));

View File

@@ -1,7 +1,7 @@
import { describe, expect, it } from "vitest";
import type { SkillEntry } from "../skills/types.js";
import { resolveSkillsPromptForRun } from "../skills/workspace.js";
import { createCanonicalFixtureSkill } from "./skills.test-helpers.js";
import { createCanonicalFixtureSkill } from "./test-helpers.js";
import type { SkillEntry } from "./types.js";
import { resolveSkillsPromptForRun } from "./workspace.js";
describe("resolveSkillsPromptForRun", () => {
it("prefers snapshot prompt when available", () => {

View File

@@ -2,7 +2,7 @@ import fs from "node:fs/promises";
import os from "node:os";
import path from "node:path";
import { afterEach, describe, expect, it } from "vitest";
import { writeWorkspaceSkills } from "../agents/skills.e2e-test-helpers.js";
import { writeWorkspaceSkills } from "./e2e-test-helpers.js";
import { SkillsService } from "./service.js";
import { buildWorkspaceSkillSnapshot as buildLegacyWorkspaceSkillSnapshot } from "./workspace.js";

View File

@@ -7,25 +7,25 @@ import {
} from "../config/runtime-snapshot.js";
import type { OpenClawConfig } from "../config/types.openclaw.js";
import { clearPluginMetadataLifecycleCaches } from "../plugins/plugin-metadata-lifecycle.js";
import { buildWorkspaceSkillCommandSpecs } from "../skills/command-specs.js";
import { captureEnv, withPathResolutionEnv } from "../test-utils/env.js";
import { createFixtureSuite } from "../test-utils/fixture-suite.js";
import { createTempHomeEnv, type TempHomeEnv } from "../test-utils/temp-home.js";
import { writeSkill } from "./skills.e2e-test-helpers.js";
import { buildWorkspaceSkillCommandSpecs } from "./command-specs.js";
import { writeSkill } from "./e2e-test-helpers.js";
import {
applySkillEnvOverrides,
applySkillEnvOverridesFromSnapshot,
getActiveSkillEnvKeys,
} from "../skills/env-overrides.js";
} from "./env-overrides.js";
import {
restoreMockSkillsHomeEnv,
setMockSkillsHomeEnv,
type SkillsHomeEnvSnapshot,
} from "../skills/home-env.test-support.js";
import type { SkillEntry, SkillSnapshot } from "../skills/types.js";
import { buildWorkspaceSkillsPrompt } from "../skills/workspace.js";
} from "./home-env.test-support.js";
import type { SkillEntry, SkillSnapshot } from "./types.js";
import { buildWorkspaceSkillsPrompt } from "./workspace.js";
vi.mock("../skills/plugin-skills.js", () => ({
vi.mock("./plugin-skills.js", () => ({
resolvePluginSkillDirs: () => [],
}));

View File

@@ -3,8 +3,8 @@ import path from "node:path";
import { describe, expect, it } from "vitest";
import { runCommandWithTimeout } from "../process/exec.js";
import { withTempDir } from "../test-helpers/temp-dir.js";
import { installSkillFromSource } from "./skills-source-install.js";
import { buildWorkspaceSkillStatus } from "./skills-status.js";
import { installSkillFromSource } from "./source-install.js";
import { buildWorkspaceSkillStatus } from "./status.js";
async function writeSkill(dir: string, params: { name?: string; description?: string } = {}) {
await fs.mkdir(dir, { recursive: true });

View File

@@ -7,11 +7,11 @@ import { writeJson } from "../infra/json-files.js";
import { parseGitPluginSpec } from "../plugins/git-install.js";
import { runCommandWithTimeout } from "../process/exec.js";
import { normalizeOptionalString } from "../shared/string-coerce.js";
import { parseFrontmatter } from "../skills/frontmatter.js";
import { sanitizeForLog } from "../terminal/ansi.js";
import { resolveUserPath } from "../utils.js";
import { installExtractedSkillRoot, validateRequestedSkillSlug } from "./skills-archive-install.js";
import { untrackClawHubSkill } from "./skills-clawhub.js";
import { installExtractedSkillRoot, validateRequestedSkillSlug } from "./archive-install.js";
import { untrackClawHubSkill } from "./clawhub.js";
import { parseFrontmatter } from "./frontmatter.js";
type Logger = {
info?: (message: string) => void;

View File

@@ -2,12 +2,12 @@ import fs from "node:fs/promises";
import os from "node:os";
import path from "node:path";
import { afterEach, describe, expect, it } from "vitest";
import type { SkillEntry } from "../skills/types.js";
import { loadWorkspaceSkillEntries } from "../skills/workspace.js";
import { withEnv, withEnvAsync } from "../test-utils/env.js";
import { buildWorkspaceSkillStatus } from "./skills-status.js";
import { writeSkill } from "./skills.e2e-test-helpers.js";
import { createCanonicalFixtureSkill } from "./skills.test-helpers.js";
import { writeSkill } from "./e2e-test-helpers.js";
import { buildWorkspaceSkillStatus } from "./status.js";
import { createCanonicalFixtureSkill } from "./test-helpers.js";
import type { SkillEntry } from "./types.js";
import { loadWorkspaceSkillEntries } from "./workspace.js";
const tempDirs: string[] = [];

View File

@@ -2,10 +2,10 @@ import fs from "node:fs/promises";
import os from "node:os";
import path from "node:path";
import { describe, expect, it } from "vitest";
import type { SkillEntry } from "../skills/types.js";
import { readLocalSkillCardContentSync } from "./skills-clawhub.js";
import { buildWorkspaceSkillStatus } from "./skills-status.js";
import { createCanonicalFixtureSkill } from "./skills.test-helpers.js";
import { readLocalSkillCardContentSync } from "./clawhub.js";
import { buildWorkspaceSkillStatus } from "./status.js";
import { createCanonicalFixtureSkill } from "./test-helpers.js";
import type { SkillEntry } from "./types.js";
type SkillStatus = ReturnType<typeof buildWorkspaceSkillStatus>["skills"][number];

View File

@@ -2,8 +2,17 @@ import path from "node:path";
import type { OpenClawConfig } from "../config/types.openclaw.js";
import { evaluateEntryRequirementsForCurrentPlatform } from "../shared/entry-status.js";
import type { RequirementConfigCheck, Requirements } from "../shared/requirements.js";
import { resolveEffectiveAgentSkillFilter } from "../skills/agent-filter.js";
import { resolveBundledSkillsContext } from "../skills/bundled-context.js";
import { CONFIG_DIR } from "../utils.js";
import { resolveEffectiveAgentSkillFilter } from "./agent-filter.js";
import { resolveBundledSkillsContext } from "./bundled-context.js";
import {
readClawHubSkillsLockfileStatusSync,
resolveClawHubSkillStatusLinkSync,
resolveLocalSkillCardStatusSync,
type ClawHubSkillStatusLink,
type ClawHubSkillsLockfileStatusRead,
type LocalSkillCardStatus,
} from "./clawhub.js";
import {
hasBinary,
isBundledSkillAllowed,
@@ -16,17 +25,8 @@ import {
type SkillEligibilityContext,
type SkillInstallSpec,
type SkillsInstallPreferences,
} from "../skills/index.js";
import { resolveSkillSource } from "../skills/source.js";
import { CONFIG_DIR } from "../utils.js";
import {
readClawHubSkillsLockfileStatusSync,
resolveClawHubSkillStatusLinkSync,
resolveLocalSkillCardStatusSync,
type ClawHubSkillStatusLink,
type ClawHubSkillsLockfileStatusRead,
type LocalSkillCardStatus,
} from "./skills-clawhub.js";
} from "./index.js";
import { resolveSkillSource } from "./source.js";
export type SkillStatusConfigCheck = RequirementConfigCheck;

View File

@@ -1,6 +1,6 @@
import fs from "node:fs/promises";
import path from "node:path";
import { createSyntheticSourceInfo, type Skill } from "../skills/skill-contract.js";
import { createSyntheticSourceInfo, type Skill } from "./skill-contract.js";
export async function writeSkill(params: {
dir: string;

View File

@@ -2,9 +2,9 @@ import fs from "node:fs/promises";
import os from "node:os";
import path from "node:path";
import { describe, expect, it } from "vitest";
import { buildWorkspaceSkillsPrompt } from "../skills/workspace.js";
import { captureEnv } from "../test-utils/env.js";
import { writeSkill } from "./skills.e2e-test-helpers.js";
import { writeSkill } from "./e2e-test-helpers.js";
import { buildWorkspaceSkillsPrompt } from "./workspace.js";
describe("buildWorkspaceSkillsPrompt", () => {
it("applies bundled allowlist without affecting workspace skills", async () => {

View File

@@ -13,15 +13,15 @@ import {
import { resolveInstalledPluginIndexPolicyHash } from "../plugins/installed-plugin-index-policy.js";
import type { PluginManifestRecord, PluginManifestRegistry } from "../plugins/manifest-registry.js";
import type { PluginMetadataSnapshot } from "../plugins/plugin-metadata-snapshot.js";
import { writeSkill, writeWorkspaceSkills } from "./e2e-test-helpers.js";
import {
restoreMockSkillsHomeEnv,
setMockSkillsHomeEnv,
type SkillsHomeEnvSnapshot,
} from "../skills/home-env.test-support.js";
import { readSkillFrontmatterSafe } from "../skills/local-loader.js";
import { loadWorkspaceSkillEntries } from "../skills/workspace.js";
import { writeSkill, writeWorkspaceSkills } from "./skills.e2e-test-helpers.js";
import { writePluginWithSkill } from "./test-helpers/skill-plugin-fixtures.js";
} from "./home-env.test-support.js";
import { readSkillFrontmatterSafe } from "./local-loader.js";
import { writePluginWithSkill } from "./skill-plugin-fixtures.test-support.js";
import { loadWorkspaceSkillEntries } from "./workspace.js";
vi.mock("../plugins/manifest-registry.js", async () => {
const fs = await import("node:fs");

View File

@@ -1,13 +1,13 @@
import path from "node:path";
import { afterAll, beforeAll, describe, expect, it, vi } from "vitest";
import { createSyntheticSourceInfo } from "../skills/skill-contract.js";
import type { OpenClawSkillMetadata, SkillEntry } from "../skills/types.js";
import { buildWorkspaceSkillsPrompt } from "../skills/workspace.js";
import { withEnv } from "../test-utils/env.js";
import { createFixtureSuite } from "../test-utils/fixture-suite.js";
import { writeSkill } from "./skills.e2e-test-helpers.js";
import { writeSkill } from "./e2e-test-helpers.js";
import { createSyntheticSourceInfo } from "./skill-contract.js";
import type { OpenClawSkillMetadata, SkillEntry } from "./types.js";
import { buildWorkspaceSkillsPrompt } from "./workspace.js";
vi.mock("../skills/plugin-skills.js", () => ({
vi.mock("./plugin-skills.js", () => ({
resolvePluginSkillDirs: () => [],
}));

View File

@@ -1,18 +1,18 @@
import fs from "node:fs/promises";
import path from "node:path";
import { afterAll, beforeAll, describe, expect, it, vi } from "vitest";
import { withPathResolutionEnv } from "../test-utils/env.js";
import { createFixtureSuite } from "../test-utils/fixture-suite.js";
import { createTempHomeEnv, type TempHomeEnv } from "../test-utils/temp-home.js";
import { writeSkill, writeWorkspaceSkills } from "./e2e-test-helpers.js";
import {
restoreMockSkillsHomeEnv,
setMockSkillsHomeEnv,
type SkillsHomeEnvSnapshot,
} from "../skills/home-env.test-support.js";
import { buildWorkspaceSkillSnapshot, buildWorkspaceSkillsPrompt } from "../skills/workspace.js";
import { withPathResolutionEnv } from "../test-utils/env.js";
import { createFixtureSuite } from "../test-utils/fixture-suite.js";
import { createTempHomeEnv, type TempHomeEnv } from "../test-utils/temp-home.js";
import { writeSkill, writeWorkspaceSkills } from "./skills.e2e-test-helpers.js";
} from "./home-env.test-support.js";
import { buildWorkspaceSkillSnapshot, buildWorkspaceSkillsPrompt } from "./workspace.js";
vi.mock("../skills/plugin-skills.js", () => ({
vi.mock("./plugin-skills.js", () => ({
resolvePluginSkillDirs: () => [],
}));

View File

@@ -2,11 +2,11 @@ import fs from "node:fs/promises";
import os from "node:os";
import path from "node:path";
import { afterAll, beforeAll, describe, expect, it, vi } from "vitest";
import { buildWorkspaceSkillsPrompt, syncSkillsToWorkspace } from "../skills/workspace.js";
import { withEnv, withEnvAsync } from "../test-utils/env.js";
import { writeSkill } from "./skills.e2e-test-helpers.js";
import { writeSkill } from "./e2e-test-helpers.js";
import { buildWorkspaceSkillsPrompt, syncSkillsToWorkspace } from "./workspace.js";
vi.mock("../skills/plugin-skills.js", () => ({
vi.mock("./plugin-skills.js", () => ({
resolvePluginSkillDirs: () => [],
}));