Skip to content

Commit b16b7f3

Browse files
a6b8claude
andcommitted
Add shared-aware import and search #3
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent 79142e6 commit b16b7f3

1 file changed

Lines changed: 130 additions & 3 deletions

File tree

src/task/FlowMcpCli.mjs

Lines changed: 130 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { readFile, writeFile, mkdir, readdir, stat, access, unlink } from 'node:
22
import { join, resolve, basename, extname, dirname } from 'node:path'
33
import { homedir } from 'node:os'
44
import { createRequire } from 'node:module'
5+
import { pathToFileURL } from 'node:url'
56
import { constants, existsSync } from 'node:fs'
67

78
import chalk from 'chalk'
@@ -423,6 +424,26 @@ class FlowMcpCli {
423424
const sourceDir = join( FlowMcpCli.#schemasDir(), sourceName )
424425
await mkdir( sourceDir, { recursive: true } )
425426

427+
const registryShared = registry[ 'shared' ]
428+
if( Array.isArray( registryShared ) && registryShared.length > 0 ) {
429+
await registryShared
430+
.reduce( ( promise, sharedEntry, index ) => promise.then( async () => {
431+
const { file } = sharedEntry
432+
const remotePath = baseDir
433+
? `${baseDir}/${file}`
434+
: file
435+
436+
const fileUrl = FlowMcpCli.#buildRawUrl( { owner, repo, branch, 'path': remotePath } )
437+
const targetPath = join( sourceDir, file )
438+
439+
process.stdout.write( ` Shared ${index + 1}/${registryShared.length}: ${file}\r` )
440+
441+
await FlowMcpCli.#downloadSchema( { url: fileUrl, targetPath } )
442+
} ), Promise.resolve() )
443+
444+
process.stdout.write( ' '.repeat( 80 ) + '\r' )
445+
}
446+
426447
let schemasImported = 0
427448
let schemasFailed = 0
428449
const errors = []
@@ -547,6 +568,26 @@ class FlowMcpCli {
547568
const sourceDir = join( FlowMcpCli.#schemasDir(), sourceName )
548569
await mkdir( sourceDir, { recursive: true } )
549570

571+
const registryShared = registry[ 'shared' ]
572+
if( Array.isArray( registryShared ) && registryShared.length > 0 ) {
573+
await registryShared
574+
.reduce( ( promise, sharedEntry, index ) => promise.then( async () => {
575+
const { file } = sharedEntry
576+
const remotePath = ( baseDir && !baseDirAlreadyInUrl )
577+
? `${baseDir}/${file}`
578+
: file
579+
580+
const fileUrl = `${registryBaseUrl}/${remotePath}`
581+
const targetPath = join( sourceDir, file )
582+
583+
process.stdout.write( ` Shared ${index + 1}/${registryShared.length}: ${file}\r` )
584+
585+
await FlowMcpCli.#downloadSchema( { 'url': fileUrl, targetPath } )
586+
} ), Promise.resolve() )
587+
588+
process.stdout.write( ' '.repeat( 80 ) + '\r' )
589+
}
590+
550591
let schemasImported = 0
551592
let schemasFailed = 0
552593
const errors = []
@@ -2022,9 +2063,27 @@ class FlowMcpCli {
20222063
const { tools: allTools } = await FlowMcpCli.#listAvailableTools()
20232064
const queryTokens = query.toLowerCase().trim().split( /\s+/ )
20242065

2066+
const { aliasIndex } = await FlowMcpCli.#loadSharedAliases()
2067+
const sharedMatchRefs = new Set()
2068+
aliasIndex
2069+
.forEach( ( { searchTerms, schemaRefs } ) => {
2070+
const hasMatch = queryTokens
2071+
.some( ( token ) => {
2072+
const found = searchTerms
2073+
.some( ( term ) => term.includes( token ) )
2074+
2075+
return found
2076+
} )
2077+
2078+
if( hasMatch ) {
2079+
schemaRefs
2080+
.forEach( ( ref ) => { sharedMatchRefs.add( ref ) } )
2081+
}
2082+
} )
2083+
20252084
const scoredTools = allTools
20262085
.map( ( tool ) => {
2027-
const { score } = FlowMcpCli.#scoreToolMatch( { tool, queryTokens } )
2086+
const { score } = FlowMcpCli.#scoreToolMatch( { tool, queryTokens, sharedMatchRefs } )
20282087
const { toolName, description, namespace, tags } = tool
20292088
const entry = {
20302089
'name': toolName,
@@ -3021,7 +3080,71 @@ Switch to development mode for advanced commands:
30213080
}
30223081

30233082

3024-
static #scoreToolMatch( { tool, queryTokens } ) {
3083+
static async #loadSharedAliases() {
3084+
const { sources } = await FlowMcpCli.#listSources()
3085+
const schemasBaseDir = FlowMcpCli.#schemasDir()
3086+
const aliasIndex = []
3087+
3088+
await sources
3089+
.reduce( ( promise, source ) => promise.then( async () => {
3090+
const { name: sourceName } = source
3091+
const registryPath = join( schemasBaseDir, sourceName, '_registry.json' )
3092+
const { data: registry } = await FlowMcpCli.#readJson( { filePath: registryPath } )
3093+
3094+
if( !registry || !Array.isArray( registry[ 'shared' ] ) ) { return }
3095+
3096+
await registry[ 'shared' ]
3097+
.reduce( ( p, sharedEntry ) => p.then( async () => {
3098+
const { file: sharedFile } = sharedEntry
3099+
const filePath = join( schemasBaseDir, sourceName, sharedFile )
3100+
3101+
try {
3102+
const mod = await import( pathToFileURL( filePath ).href )
3103+
const exportedArray = Object.values( mod )
3104+
.find( ( v ) => Array.isArray( v ) )
3105+
3106+
if( !exportedArray ) { return }
3107+
3108+
const searchTerms = exportedArray
3109+
.reduce( ( acc, obj ) => {
3110+
const alias = obj[ 'alias' ] || obj[ 'code' ] || obj[ 'alpha2' ] || ''
3111+
const name = obj[ 'name' ] || ''
3112+
3113+
if( alias ) { acc.push( alias.toLowerCase() ) }
3114+
if( name ) { acc.push( name.toLowerCase() ) }
3115+
3116+
return acc
3117+
}, [] )
3118+
3119+
const matchingSchemaRefs = ( registry[ 'schemas' ] || [] )
3120+
.filter( ( s ) => {
3121+
const schemaShared = s[ 'shared' ] || []
3122+
const matches = schemaShared.includes( sharedFile )
3123+
3124+
return matches
3125+
} )
3126+
.map( ( s ) => {
3127+
const ref = `${sourceName}/${s[ 'file' ]}`
3128+
3129+
return ref
3130+
} )
3131+
3132+
aliasIndex.push( {
3133+
'sharedFile': sharedFile,
3134+
searchTerms,
3135+
'schemaRefs': matchingSchemaRefs
3136+
} )
3137+
} catch {
3138+
// _shared file could not be loaded — skip
3139+
}
3140+
} ), Promise.resolve() )
3141+
} ), Promise.resolve() )
3142+
3143+
return { aliasIndex }
3144+
}
3145+
3146+
3147+
static #scoreToolMatch( { tool, queryTokens, sharedMatchRefs } ) {
30253148
const { toolName, namespace, description, tags, schemaName } = tool
30263149
const lowerName = toolName.toLowerCase()
30273150
const lowerNamespace = namespace.toLowerCase()
@@ -3053,10 +3176,14 @@ Switch to development mode for advanced commands:
30533176
return tokenScore > 0
30543177
} )
30553178

3056-
if( !allTokensMatch ) {
3179+
if( !allTokensMatch && !( sharedMatchRefs && sharedMatchRefs.has( tool[ 'schemaRef' ] ) ) ) {
30573180
return { 'score': 0 }
30583181
}
30593182

3183+
if( sharedMatchRefs && sharedMatchRefs.has( tool[ 'schemaRef' ] ) ) {
3184+
totalScore += 10
3185+
}
3186+
30603187
return { 'score': totalScore }
30613188
}
30623189

0 commit comments

Comments
 (0)