resolveSkill function
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();
}