resolveSkill function

Future<SkillResult> resolveSkill({
  1. String? topic,
})

Resolves and reads the bundled skill file from the package root.

Without topic, reads the core lib/skill/SKILL.md (install instructions, fdb_helper setup, and the full command index with topic routing).

With topic (e.g. "launch", "interact"), reads the corresponding lib/skill/<TOPIC>.md sub-document. Topic matching is case-insensitive.

Available topics: launch, interact, data, diagnostics, memory, simulator.

The authoritative skill content lives under lib/skill/ (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

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({String? topic}) async {
  final filename = topic != null ? '${topic.toUpperCase()}.md' : 'SKILL.md';
  const relativeDir = 'lib/skill/';

  // 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}/$relativeDir$filename');
    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}/$relativeDir$filename');
  if (fallback.existsSync()) {
    return SkillContent(fallback.readAsStringSync());
  }

  if (topic != null) {
    return SkillTopicNotFound(topic);
  }
  return const SkillNotFound();
}