diff --git a/src/detect.ts b/src/detect.ts index cbaa480..54e1882 100644 --- a/src/detect.ts +++ b/src/detect.ts @@ -1,3 +1,6 @@ +import { isAbsolute, normalize, resolve } from "node:path"; +import type { Skill } from "@earendil-works/pi-coding-agent"; + /** Raw `/skill:name` at start of user input (SPEC §6.2 #1). */ const SLASH_SKILL_RE = /^\/skill:([a-z0-9-]+)/; @@ -11,6 +14,13 @@ export interface ParsedSkillBlock { content: string; } +/** Minimal skill fields for read-path matching (SPEC §6.2 #3). */ +export type SkillPathMeta = Pick; + +function normalizePathForCompare(filePath: string): string { + return normalize(filePath); +} + /** Returns skill name when text is a slash skill command, else null. */ export function detectSlashSkill(text: string): string | null { const match = SLASH_SKILL_RE.exec(text); @@ -29,3 +39,24 @@ export function parseSkillBlocksFromText(text: string): ParsedSkillBlock[] { } return blocks; } + +/** Match read tool path to a registered skill SKILL.md (SPEC §6.2 #3). */ +export function matchReadPathToSkill( + path: string, + skills: readonly SkillPathMeta[], +): SkillPathMeta | null { + const normalizedPath = normalizePathForCompare(path); + for (const skill of skills) { + const skillPath = normalizePathForCompare(skill.filePath); + if (normalizedPath === skillPath) { + return skill; + } + if (!isAbsolute(path)) { + const resolvedFromBase = normalizePathForCompare(resolve(skill.baseDir, path)); + if (resolvedFromBase === skillPath) { + return skill; + } + } + } + return null; +}