smoke.js 1.6 KB

12345678910111213141516171819202122232425262728293031323334353637383940
  1. #!/usr/bin/env node
  2. const fs = require('fs');
  3. const path = require('path');
  4. const { spawnSync } = require('child_process');
  5. const { pathToFileURL } = require('url');
  6. const ROOT = path.resolve(__dirname, '..');
  7. const SKILL_DIR = path.join(ROOT, 'skills', 'fmode-listen');
  8. const BIN = path.join(ROOT, 'bin', 'fmode-listen.js');
  9. function fail(msg) { console.error('SMOKE FAIL: ' + msg); process.exit(1); }
  10. const required = [
  11. 'SKILL.md',
  12. 'scripts/listen-runner.mjs'
  13. ];
  14. for (const rel of required) {
  15. if (!fs.existsSync(path.join(SKILL_DIR, rel))) fail('missing ' + rel);
  16. }
  17. (async () => {
  18. // 1. skill runner module exports
  19. const mod = await import(pathToFileURL(path.join(SKILL_DIR, 'scripts', 'listen-runner.mjs')).href);
  20. for (const fn of ['resolveApiToken', 'probeDurationMs', 'transcribeFile']) {
  21. if (typeof mod[fn] !== 'function') fail('export ' + fn + ' is not a function');
  22. }
  23. // 2. bin help runs
  24. const help = spawnSync(process.execPath, [BIN, 'help'], { encoding: 'utf8' });
  25. if (help.status !== 0) fail('`fmode-listen help` exited ' + help.status);
  26. if (!/fmode-listen/.test(help.stdout || '')) fail('help output missing banner');
  27. // 3. bin path resolves
  28. const p = spawnSync(process.execPath, [BIN, 'path'], { encoding: 'utf8' });
  29. if (p.status !== 0) fail('`fmode-listen path` exited ' + p.status);
  30. if (!/fmode-listen/.test(p.stdout || '')) fail('path output missing skill name');
  31. console.log('SMOKE OK: fmode-listen structure + runner exports verified');
  32. console.log(' install path: ' + (p.stdout || '').trim());
  33. })().catch(e => fail(e.message));