π File detail
utils/plugins/walkPluginMarkdown.ts
π§© .tsπ 70 linesπΎ 2,222 bytesπ text
β Back to All Filesπ― Use case
This file lives under βutils/β, which covers cross-cutting helpers (shell, tempfiles, settings, messages, process input, β¦). On the API surface it exposes walkPluginMarkdown β mainly functions, hooks, or classes. Dependencies touch Node path helpers. It composes internal code from debug and fsOperations (relative imports).
Generated from folder role, exports, dependency roots, and inline comments β not hand-reviewed for every path.
π§ Inline summary
import { join } from 'path' import { logForDebugging } from '../debug.js' import { getFsImplementation } from '../fsOperations.js' const SKILL_MD_RE = /^skill\.md$/i
π€ Exports (heuristic)
walkPluginMarkdown
π External import roots
Package roots from from "β¦" (relative paths omitted).
path
π₯οΈ Source preview
import { join } from 'path'
import { logForDebugging } from '../debug.js'
import { getFsImplementation } from '../fsOperations.js'
const SKILL_MD_RE = /^skill\.md$/i
/**
* Recursively walk a plugin directory, invoking onFile for each .md file.
*
* The namespace array tracks the subdirectory path relative to the root
* (e.g., ['foo', 'bar'] for root/foo/bar/file.md). Callers that don't need
* namespacing can ignore the second argument.
*
* When stopAtSkillDir is true and a directory contains SKILL.md, onFile is
* called for all .md files in that directory but subdirectories are not
* scanned β skill directories are leaf containers.
*
* Readdir errors are swallowed with a debug log so one bad directory doesn't
* abort a plugin load.
*/
export async function walkPluginMarkdown(
rootDir: string,
onFile: (fullPath: string, namespace: string[]) => Promise<void>,
opts: { stopAtSkillDir?: boolean; logLabel?: string } = {},
): Promise<void> {
const fs = getFsImplementation()
const label = opts.logLabel ?? 'plugin'
async function scan(dirPath: string, namespace: string[]): Promise<void> {
try {
const entries = await fs.readdir(dirPath)
if (
opts.stopAtSkillDir &&
entries.some(e => e.isFile() && SKILL_MD_RE.test(e.name))
) {
// Skill directory: collect .md files here, don't recurse.
await Promise.all(
entries.map(entry =>
entry.isFile() && entry.name.toLowerCase().endsWith('.md')
? onFile(join(dirPath, entry.name), namespace)
: undefined,
),
)
return
}
await Promise.all(
entries.map(entry => {
const fullPath = join(dirPath, entry.name)
if (entry.isDirectory()) {
return scan(fullPath, [...namespace, entry.name])
}
if (entry.isFile() && entry.name.toLowerCase().endsWith('.md')) {
return onFile(fullPath, namespace)
}
return undefined
}),
)
} catch (error) {
logForDebugging(
`Failed to scan ${label} directory ${dirPath}: ${error}`,
{ level: 'error' },
)
}
}
await scan(rootDir, [])
}