resolveSkill function

Future<SkillResult> resolveSkill()

Resolves and reads the bundled SKILL.md from the package root.

The authoritative skill content lives at lib/skill/SKILL.md (internal, bundled with the CLI). This is intentionally separate from skills/using-fdb/SKILL.md, which is the lean shim users install into their OpenCode config — it simply instructs the agent to run fdb skill.

Package-root resolution strategy: This file lives at lib/core/commands/skill/skill.dart. The package URI package:fdb/core/commands/skill/skill.dart resolves to the absolute file path. Walking .parent five times reaches the package root: skill.dart → skill/ → commands/ → core/ → lib/ → package-root (Compare: the old file in lib/core/commands/ only needed four .parent calls.)

If the URI resolver returns null (unusual but possible), we fall back to Platform.script which points to bin/fdb.dart; one .parent up is bin/, and one more is the package root.

Implementation

Future<SkillResult> resolveSkill() async {
  const relativePath = 'lib/skill/SKILL.md';

  // Primary: resolve via package URI — works for both `dart run` and
  // `dart pub global activate` installs.
  final packageUri = Uri.parse('package:fdb/core/commands/skill/skill.dart');
  final resolved = await Isolate.resolvePackageUri(packageUri);
  if (resolved != null) {
    // Five .parent calls: skill.dart → skill/ → commands/ → core/ → lib/ → package root
    final packageRoot = File.fromUri(resolved).parent.parent.parent.parent.parent;
    final candidate = File('${packageRoot.path}/$relativePath');
    if (candidate.existsSync()) {
      return SkillContent(candidate.readAsStringSync());
    }
  }

  // Fallback: resolve relative to Platform.script (`bin/fdb.dart`).
  // scriptDir = bin/, scriptDir.parent = package root.
  final scriptDir = Directory.fromUri(Platform.script).parent;
  final packageRoot = scriptDir.parent;
  final fallback = File('${packageRoot.path}/$relativePath');
  if (fallback.existsSync()) {
    return SkillContent(fallback.readAsStringSync());
  }

  return const SkillNotFound();
}