1+ import { spawnSync } from "node:child_process" ;
12import fs from "node:fs" ;
23import path from "node:path" ;
34
@@ -9,36 +10,95 @@ export function readIfExists(filePath) {
910 }
1011}
1112
12- export function collectBundledPluginSources ( params = { } ) {
13- const repoRoot = path . resolve ( params . repoRoot ?? process . cwd ( ) ) ;
13+ function collectTrackedBundledPluginSourceCandidates ( repoRoot ) {
14+ const result = spawnSync (
15+ "git" ,
16+ [
17+ "ls-files" ,
18+ "--" ,
19+ ":(glob)extensions/*/openclaw.plugin.json" ,
20+ ":(glob)extensions/*/package.json" ,
21+ ] ,
22+ {
23+ cwd : repoRoot ,
24+ encoding : "utf8" ,
25+ stdio : [ "ignore" , "pipe" , "ignore" ] ,
26+ } ,
27+ ) ;
28+ if ( result . status !== 0 ) {
29+ return null ;
30+ }
31+
32+ const candidatesByDir = new Map ( ) ;
33+ for ( const rawLine of result . stdout . split ( "\n" ) ) {
34+ const line = rawLine . trim ( ) . replaceAll ( "\\" , "/" ) ;
35+ const match = / ^ e x t e n s i o n s \/ ( [ ^ / ] + ) \/ ( o p e n c l a w \. p l u g i n \. j s o n | p a c k a g e \. j s o n ) $ / u. exec ( line ) ;
36+ if ( ! match ?. [ 1 ] || ! match [ 2 ] ) {
37+ continue ;
38+ }
39+ const current = candidatesByDir . get ( match [ 1 ] ) ?? {
40+ dirName : match [ 1 ] ,
41+ manifestPath : null ,
42+ packageJsonPath : null ,
43+ pluginDir : path . join ( repoRoot , "extensions" , match [ 1 ] ) ,
44+ } ;
45+ if ( match [ 2 ] === "openclaw.plugin.json" ) {
46+ current . manifestPath = path . join ( repoRoot , line ) ;
47+ } else {
48+ current . packageJsonPath = path . join ( repoRoot , line ) ;
49+ }
50+ candidatesByDir . set ( match [ 1 ] , current ) ;
51+ }
52+
53+ return [ ...candidatesByDir . values ( ) ] . toSorted ( ( left , right ) =>
54+ left . dirName . localeCompare ( right . dirName ) ,
55+ ) ;
56+ }
57+
58+ function collectBundledPluginSourceCandidatesFromDirectory ( repoRoot ) {
1459 const extensionsRoot = path . join ( repoRoot , "extensions" ) ;
1560 if ( ! fs . existsSync ( extensionsRoot ) ) {
1661 return [ ] ;
1762 }
1863
64+ return fs
65+ . readdirSync ( extensionsRoot , { withFileTypes : true } )
66+ . filter ( ( dirent ) => dirent . isDirectory ( ) )
67+ . map ( ( dirent ) => {
68+ const pluginDir = path . join ( extensionsRoot , dirent . name ) ;
69+ const manifestPath = path . join ( pluginDir , "openclaw.plugin.json" ) ;
70+ const packageJsonPath = path . join ( pluginDir , "package.json" ) ;
71+ return {
72+ dirName : dirent . name ,
73+ manifestPath : fs . existsSync ( manifestPath ) ? manifestPath : null ,
74+ packageJsonPath : fs . existsSync ( packageJsonPath ) ? packageJsonPath : null ,
75+ pluginDir,
76+ } ;
77+ } )
78+ . toSorted ( ( left , right ) => left . dirName . localeCompare ( right . dirName ) ) ;
79+ }
80+
81+ export function collectBundledPluginSources ( params = { } ) {
82+ const repoRoot = path . resolve ( params . repoRoot ?? process . cwd ( ) ) ;
1983 const requirePackageJson = params . requirePackageJson === true ;
2084 const entries = [ ] ;
21- for ( const dirent of fs . readdirSync ( extensionsRoot , { withFileTypes : true } ) ) {
22- if ( ! dirent . isDirectory ( ) ) {
23- continue ;
24- }
25-
26- const pluginDir = path . join ( extensionsRoot , dirent . name ) ;
27- const manifestPath = path . join ( pluginDir , "openclaw.plugin.json" ) ;
28- const packageJsonPath = path . join ( pluginDir , "package.json" ) ;
29- if ( ! fs . existsSync ( manifestPath ) ) {
85+ const candidates =
86+ collectTrackedBundledPluginSourceCandidates ( repoRoot ) ??
87+ collectBundledPluginSourceCandidatesFromDirectory ( repoRoot ) ;
88+ for ( const { dirName, manifestPath, packageJsonPath, pluginDir } of candidates ) {
89+ if ( ! manifestPath ) {
3090 continue ;
3191 }
32- if ( requirePackageJson && ! fs . existsSync ( packageJsonPath ) ) {
92+ if ( requirePackageJson && ! packageJsonPath ) {
3393 continue ;
3494 }
3595
3696 entries . push ( {
37- dirName : dirent . name ,
97+ dirName,
3898 pluginDir,
3999 manifestPath,
40100 manifest : JSON . parse ( fs . readFileSync ( manifestPath , "utf8" ) ) ,
41- ...( fs . existsSync ( packageJsonPath )
101+ ...( packageJsonPath
42102 ? {
43103 packageJsonPath,
44104 packageJson : JSON . parse ( fs . readFileSync ( packageJsonPath , "utf8" ) ) ,
0 commit comments