Skip to content

Commit 0920071

Browse files
authored
fix: prefer .js over .ts when loading plugins for npm compatibility (#10)
- Add resolvePluginSource() helper (prefers .ts in dev, .js under node_modules) - Fix schema extraction to prefer .ts source for Rust parser - Fix fast-path plugin enable to call loadSource() before enabling - Root cause: schema extraction failed on compiled .js, config keys unrecognised, allowedDomains never set Signed-off-by: Simon Davies <simongdavies@users.noreply.github.com>
1 parent 2ca15c8 commit 0920071

2 files changed

Lines changed: 32 additions & 4 deletions

File tree

src/agent/slash-commands.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1207,6 +1207,17 @@ export async function handleSlashCommand(
12071207
break;
12081208
}
12091209

1210+
// Load source before enabling — syncPluginsToSandbox needs
1211+
// plugin.source for verifySourceHash(). Without this, the
1212+
// hash check fails and the plugin is silently disabled.
1213+
if (!pluginManager.loadSource(pluginName)) {
1214+
console.log(
1215+
` ${C.err("❌ Failed to load source for")} "${pluginName}". Plugin will not be enabled.`,
1216+
);
1217+
console.log();
1218+
break;
1219+
}
1220+
12101221
pluginManager.enable(pluginName);
12111222
console.log(
12121223
` ✅ Plugin "${pluginName}" enabled (approved fast-path).`,

src/plugin-system/manager.ts

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -718,10 +718,27 @@ export function createPluginManager(pluginsDir: string) {
718718
const plugin = plugins.get(name);
719719
if (!plugin) return false;
720720

721-
// Load source if not already loaded
721+
// For schema extraction, prefer .ts source — it's the canonical
722+
// schema definition and the Rust parser handles it best. Under
723+
// node_modules, only .js exists so we fall back gracefully.
724+
// try/catch guards against TOCTOU (file deleted between exists check and read).
725+
const tsPath = join(plugin.dir, "index.ts");
726+
let extractionSource: string | null = null;
727+
if (existsSync(tsPath)) {
728+
try {
729+
extractionSource = readFileSync(tsPath, "utf8");
730+
} catch {
731+
// Fall through to plugin.source / loadSource
732+
}
733+
}
734+
if (!extractionSource) {
735+
extractionSource = plugin.source ?? loadSource(name);
736+
}
737+
if (!extractionSource) return false;
738+
739+
// Also ensure plugin.source is loaded for hash verification
722740
if (!plugin.source) {
723-
const source = loadSource(name);
724-
if (!source) return false;
741+
if (!loadSource(name)) return false;
725742
}
726743

727744
// If analysis guest is not enabled, fall back to manifest.
@@ -735,7 +752,7 @@ export function createPluginManager(pluginsDir: string) {
735752
}
736753

737754
try {
738-
const metadata = await extractPluginMetadata(plugin.source!);
755+
const metadata = await extractPluginMetadata(extractionSource);
739756

740757
// Use extracted schema or fall back to manifest
741758
if (metadata.schema) {

0 commit comments

Comments
 (0)