File size: 3,884 Bytes
fcd8223
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
/** Loads bundled channel plugin runtime entries and setup metadata. */
import path from "node:path";
import { isVitestRuntimeEnv } from "../infra/env.js";
import { resolveBundledPluginGeneratedPath } from "./bundled-plugin-scan.js";
import type { PluginManifestRecord } from "./manifest-registry.js";
import type { OpenClawPackageManifest } from "./manifest.js";
import { pluginCacheExistsSync } from "./plugin-cache-files.js";
import { resolvePluginMetadataSnapshot } from "./plugin-metadata-snapshot.js";

type BundledChannelEntryPathPair = {
  source: string;
  built: string;
};

type BundledMetadataScope =
  | { kind: "default" }
  | { kind: "empty" }
  | { kind: "env"; env: NodeJS.ProcessEnv };

/** Bundled channel plugin metadata used by generators and runtime path resolvers. */
export type BundledChannelPluginMetadata = {
  dirName: string;
  source: BundledChannelEntryPathPair;
  setupSource?: BundledChannelEntryPathPair;
  manifest: {
    id: string;
    channels?: readonly string[];
  };
  packageManifest?: OpenClawPackageManifest;
  rootDir: string;
};

function resolveBundledMetadataScope(params?: {
  rootDir?: string;
  scanDir?: string;
}): BundledMetadataScope {
  const overrideDir = params?.scanDir
    ? path.resolve(params.scanDir)
    : params?.rootDir
      ? resolveBundledPluginsDirForRoot(params.rootDir)
      : undefined;
  if (!overrideDir) {
    return params?.rootDir ? { kind: "empty" } : { kind: "default" };
  }
  if (!pluginCacheExistsSync(overrideDir)) {
    return { kind: "empty" };
  }
  return {
    kind: "env",
    env: {
      ...process.env,
      OPENCLAW_BUNDLED_PLUGINS_DIR: overrideDir,
      ...(isVitestRuntimeEnv() ? { OPENCLAW_TEST_TRUST_BUNDLED_PLUGINS_DIR: "1" } : {}),
    },
  };
}

function resolveBundledPluginsDirForRoot(rootDir: string): string | undefined {
  const candidates = [
    path.join(rootDir, "extensions"),
    path.join(rootDir, "dist-runtime", "extensions"),
    path.join(rootDir, "dist", "extensions"),
  ];
  return candidates.find((candidate) => pluginCacheExistsSync(candidate));
}

function toBundledChannelEntryPair(source: string | undefined): BundledChannelEntryPathPair | null {
  if (!source) {
    return null;
  }
  return { source, built: source };
}

function toBundledChannelPluginMetadata(
  record: PluginManifestRecord,
): BundledChannelPluginMetadata | null {
  if (record.origin !== "bundled") {
    return null;
  }
  const source = toBundledChannelEntryPair(record.source);
  if (!source) {
    return null;
  }
  const setupSource = toBundledChannelEntryPair(record.setupSource);
  return {
    dirName: path.basename(record.rootDir),
    source,
    ...(setupSource ? { setupSource } : {}),
    manifest: {
      id: record.id,
      channels: record.channels,
    },
    ...(record.packageManifest ? { packageManifest: record.packageManifest } : {}),
    rootDir: record.rootDir,
  };
}

/** Lists bundled channel plugin metadata from default or caller-provided scan roots. */
export function listBundledChannelPluginMetadata(params?: {
  rootDir?: string;
  scanDir?: string;
  includeChannelConfigs?: boolean;
  includeSyntheticChannelConfigs?: boolean;
}): readonly BundledChannelPluginMetadata[] {
  const scope = resolveBundledMetadataScope(params);
  if (scope.kind === "empty") {
    return [];
  }
  return resolvePluginMetadataSnapshot({
    env: scope.kind === "env" ? scope.env : undefined,
  }).plugins.flatMap((record) => toBundledChannelPluginMetadata(record) ?? []);
}

/** Resolves a generated runtime path for a bundled channel entry. */
export function resolveBundledChannelGeneratedPath(
  rootDir: string,
  entry: BundledChannelPluginMetadata["source"] | BundledChannelPluginMetadata["setupSource"],
  pluginDirName?: string,
  scanDir?: string,
): string | null {
  return resolveBundledPluginGeneratedPath(rootDir, entry, pluginDirName, scanDir);
}