Improve critique skill reliability

- add provider-specific block compilation and tests

- bundle detector scripts for skill critique runs

- harden critique orchestration, browser handling, and storage
This commit is contained in:
Paul Bakaus
2026-05-18 15:15:14 -07:00
parent e1d3ea0b6f
commit bc1894889e
285 changed files with 142401 additions and 1251 deletions
+17 -6
View File
@@ -27,7 +27,7 @@
import fs from 'node:fs';
import path from 'node:path';
import { pathToFileURL } from 'node:url';
import { fileURLToPath, pathToFileURL } from 'node:url';
import { getCritiqueDir } from './impeccable-paths.mjs';
const SLUG_MAX = 50;
@@ -222,10 +222,21 @@ function main(argv) {
}
}
// Why pathToFileURL: on Windows, import.meta.url is file:///D:/... (forward
// slashes) while process.argv[1] is D:\... (backslashes), so the naive
// `file://${process.argv[1]}` compare fails and main() never runs — the
// script silently exits 0. pathToFileURL normalizes both. (issue #155)
if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
function isMainModule() {
if (!process.argv[1]) return false;
try {
return fs.realpathSync(fileURLToPath(import.meta.url)) === fs.realpathSync(process.argv[1]);
} catch {
// pathToFileURL normalizes Windows paths; keep it as a fallback for any
// environment where realpath is unavailable.
return import.meta.url === pathToFileURL(process.argv[1]).href;
}
}
// Why the realpath check: generated skills are often reached through symlinked
// harness directories (for example a demo repo's `.agents` -> source `.agents`).
// Node resolves import.meta.url to the real file, while process.argv[1] keeps
// the symlink path. Comparing canonical paths prevents a silent exit-0 no-op.
if (isMainModule()) {
main(process.argv.slice(2));
}
+21
View File
@@ -0,0 +1,21 @@
#!/usr/bin/env node
import fs from 'node:fs';
import path from 'node:path';
import { pathToFileURL, fileURLToPath } from 'node:url';
const __dirname = path.dirname(fileURLToPath(import.meta.url));
const candidates = [
path.join(__dirname, 'detector', 'detect-antipatterns.mjs'),
path.join(__dirname, '..', '..', 'cli', 'engine', 'detect-antipatterns.mjs'),
];
const detectorPath = candidates.find(p => fs.existsSync(p));
if (!detectorPath) {
process.stderr.write('Error: bundled detector not found.\n');
process.exit(1);
}
const { detectCli } = await import(pathToFileURL(detectorPath));
await detectCli();
+4 -2
View File
@@ -155,10 +155,12 @@ function broadcast(msg) {
// ---------------------------------------------------------------------------
function loadBrowserScripts() {
// Detection script: look relative to the skill scripts dir, then fall back
// to the npm package location (cli/engine/detect-antipatterns-browser.js).
// Detection script: prefer the skill-bundled detector, then fall back to
// source/npm package locations for local development and older installs.
// This one IS cached — detect.js rarely changes during a session.
const detectPaths = [
path.join(__dirname, 'detector', 'detect-antipatterns-browser.js'),
path.join(__dirname, '..', '..', 'cli', 'engine', 'detect-antipatterns-browser.js'),
path.join(__dirname, '..', '..', '..', '..', 'cli', 'engine', 'detect-antipatterns-browser.js'),
path.join(process.cwd(), 'node_modules', 'impeccable', 'cli', 'engine', 'detect-antipatterns-browser.js'),
];