|
20 | 20 | import { dirname, resolve, basename, relative } from "node:path"; |
21 | 21 | import { fileURLToPath } from "node:url"; |
22 | 22 | import { existsSync, readdirSync, readFileSync, statSync } from "node:fs"; |
23 | | -import { execFileSync } from "node:child_process"; |
24 | 23 | import { parseArgs } from "node:util"; |
25 | 24 | import { parseSkillContent } from "../shared/skill-helper.js"; |
26 | 25 |
|
@@ -382,11 +381,9 @@ const TRIGGER_SECTION_RE = new RegExp( |
382 | 381 | const DO_NOT_USE_FOR_RE = /\bDO NOT USE FOR:/i; |
383 | 382 | const SANITIZED_DO_NOT_USE_FOR_MARKER = "DO_NOT_USE_FOR:"; |
384 | 383 | const DISAMBIGUATION_CLAUSE_MARKER_RE = new RegExp(`(?:${SANITIZED_DO_NOT_USE_FOR_MARKER}|PREFER OVER\\b)`, "i"); |
385 | | -const PREFER_OVER_RE = /\bPREFER OVER\b/i; |
386 | 384 | const BROAD_SKILL_NAMES = new Set(["azure-prepare", "azure-deploy"]); |
387 | 385 | const MIN_TRIGGER_PHRASE_LENGTH = 4; |
388 | 386 | const OVERLAP_PREVIEW_LIMIT = 3; |
389 | | -const DEFAULT_REMOTE_BASE_REF = "origin/main"; |
390 | 387 |
|
391 | 388 | function normalizeTriggerPhrase(phrase: string): string { |
392 | 389 | return phrase |
@@ -430,11 +427,6 @@ export function hasPreferOverClause(description: string | null, competingSkillNa |
430 | 427 | return new RegExp(`\\bPREFER OVER\\s+${escapedName}\\b`, "i").test(description); |
431 | 428 | } |
432 | 429 |
|
433 | | -function hasAnyPreferOverClause(description: string | null): boolean { |
434 | | - if (!description) return false; |
435 | | - return PREFER_OVER_RE.test(description); |
436 | | -} |
437 | | - |
438 | 430 | function hasAnyDisambiguationClause(description: string | null, competingSkillName: string): boolean { |
439 | 431 | return hasDoNotUseForClause(description) || hasPreferOverClause(description, competingSkillName); |
440 | 432 | } |
@@ -465,51 +457,6 @@ function isBroadRoutingSkill(name: string): boolean { |
465 | 457 | return BROAD_SKILL_NAMES.has(name); |
466 | 458 | } |
467 | 459 |
|
468 | | -function getMergeBaseRef(): string | null { |
469 | | - // Prefer merge-base with common default branches first (remote then local), then |
470 | | - // fall back to HEAD~1 for environments where base branches are unavailable. |
471 | | - const baseRefCandidates = [DEFAULT_REMOTE_BASE_REF, "origin/master", "main", "master"]; |
472 | | - for (const baseRef of baseRefCandidates) { |
473 | | - try { |
474 | | - return execFileSync("git", ["merge-base", "HEAD", baseRef], { |
475 | | - cwd: REPO_ROOT, |
476 | | - encoding: "utf-8", |
477 | | - stdio: ["ignore", "pipe", "ignore"], |
478 | | - }).trim(); |
479 | | - } catch { |
480 | | - // Try next candidate base ref. |
481 | | - } |
482 | | - } |
483 | | - |
484 | | - try { |
485 | | - return execFileSync("git", ["rev-parse", "HEAD~1"], { |
486 | | - cwd: REPO_ROOT, |
487 | | - encoding: "utf-8", |
488 | | - stdio: ["ignore", "pipe", "ignore"], |
489 | | - }).trim(); |
490 | | - } catch { |
491 | | - return null; |
492 | | - } |
493 | | -} |
494 | | - |
495 | | -function getDescriptionFromGitRef(filePath: string, ref: string): string | null { |
496 | | - const relativeFilePath = relative(REPO_ROOT, filePath).replace(/\\/g, "/"); |
497 | | - try { |
498 | | - const previousContent = execFileSync("git", ["show", `${ref}:${relativeFilePath}`], { |
499 | | - cwd: REPO_ROOT, |
500 | | - encoding: "utf-8", |
501 | | - stdio: ["ignore", "pipe", "ignore"], |
502 | | - }); |
503 | | - const parsed = parseSkillContent(previousContent); |
504 | | - if (parsed === null || typeof parsed.data.description !== "string") { |
505 | | - return null; |
506 | | - } |
507 | | - return parsed.data.description; |
508 | | - } catch { |
509 | | - return null; |
510 | | - } |
511 | | -} |
512 | | - |
513 | 460 | export function validateTriggerOverlapDisambiguation( |
514 | 461 | skill: SkillRoutingContext, |
515 | 462 | allSkills: SkillRoutingContext[], |
@@ -542,17 +489,6 @@ export function validateTriggerOverlapDisambiguation( |
542 | 489 | return issues; |
543 | 490 | } |
544 | 491 |
|
545 | | -function getRemovedDisambiguationClauses(previousDescription: string | null, currentDescription: string | null): string[] { |
546 | | - const removed: string[] = []; |
547 | | - if (hasDoNotUseForClause(previousDescription) && !hasDoNotUseForClause(currentDescription)) { |
548 | | - removed.push("DO NOT USE FOR"); |
549 | | - } |
550 | | - if (hasAnyPreferOverClause(previousDescription) && !hasAnyPreferOverClause(currentDescription)) { |
551 | | - removed.push("PREFER OVER"); |
552 | | - } |
553 | | - return removed; |
554 | | -} |
555 | | - |
556 | 492 | // ── Validate a single SKILL.md ────────────────────────────────────────────── |
557 | 493 |
|
558 | 494 | export function validateSkillFile(filePath: string): ValidationResult { |
@@ -761,7 +697,6 @@ function main(): void { |
761 | 697 | const results: ValidationResult[] = []; |
762 | 698 | const routingContexts = buildSkillRoutingContexts(getAllSkillFiles()); |
763 | 699 | const routingContextByName = new Map(routingContexts.map((context) => [context.name, context])); |
764 | | - const mergeBaseRef = getMergeBaseRef(); |
765 | 700 |
|
766 | 701 | for (const file of skillFiles) { |
767 | 702 | const result = validateSkillFile(file); |
|
0 commit comments