📦 deps(thirdparty): update snapshots
This commit is contained in:
@@ -0,0 +1,153 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
const fs = require('node:fs');
|
||||
const path = require('node:path');
|
||||
const { execFileSync, spawnSync } = require('node:child_process');
|
||||
|
||||
const DEFAULT_THRESHOLD = '80';
|
||||
const DEFAULT_WORKSPACE = 'antigravity-awesome-skills';
|
||||
|
||||
function runGit(args, options = {}) {
|
||||
return execFileSync('git', args, {
|
||||
cwd: options.cwd || process.cwd(),
|
||||
encoding: 'utf8',
|
||||
stdio: ['ignore', 'pipe', 'pipe'],
|
||||
});
|
||||
}
|
||||
|
||||
function splitLines(output) {
|
||||
return output
|
||||
.split(/\r?\n/)
|
||||
.map((line) => line.trim())
|
||||
.filter(Boolean);
|
||||
}
|
||||
|
||||
function getChangedSkillFiles(baseSha, headSha, options = {}) {
|
||||
if (!baseSha || !headSha) {
|
||||
throw new Error('BASE_SHA and HEAD_SHA are required');
|
||||
}
|
||||
|
||||
const git = options.git || runGit;
|
||||
const output = git(['diff', '--name-only', '--diff-filter=ACMR', baseSha, headSha, '--']);
|
||||
return splitLines(output).filter((filePath) => filePath === 'SKILL.md' || filePath.endsWith('/SKILL.md'));
|
||||
}
|
||||
|
||||
function ensureRepoRelative(filePath, repoRoot = process.cwd()) {
|
||||
const resolved = path.resolve(repoRoot, filePath);
|
||||
const relative = path.relative(repoRoot, resolved);
|
||||
|
||||
if (relative.startsWith('..') || path.isAbsolute(relative)) {
|
||||
throw new Error(`Path traversal detected: ${filePath}`);
|
||||
}
|
||||
|
||||
if (path.basename(filePath) !== 'SKILL.md') {
|
||||
throw new Error(`Unexpected skill file path: ${filePath}`);
|
||||
}
|
||||
|
||||
return resolved;
|
||||
}
|
||||
|
||||
function getChangedSkillDirs(files, repoRoot = process.cwd()) {
|
||||
const dirs = new Set();
|
||||
|
||||
for (const filePath of files) {
|
||||
const resolved = ensureRepoRelative(filePath, repoRoot);
|
||||
if (!fs.existsSync(resolved)) {
|
||||
continue;
|
||||
}
|
||||
dirs.add(path.dirname(filePath));
|
||||
}
|
||||
|
||||
return [...dirs].sort();
|
||||
}
|
||||
|
||||
function buildReviewArgs(skillDir, options = {}) {
|
||||
const workspace = options.workspace || DEFAULT_WORKSPACE;
|
||||
const threshold = options.threshold || DEFAULT_THRESHOLD;
|
||||
const args = ['review', 'run', skillDir, '--workspace', workspace, '--json', '--threshold', threshold];
|
||||
|
||||
if (options.reviewPlugin) {
|
||||
args.push('--review-plugin', options.reviewPlugin);
|
||||
}
|
||||
|
||||
if (options.label) {
|
||||
args.push('--label', options.label);
|
||||
}
|
||||
|
||||
return args;
|
||||
}
|
||||
|
||||
function reviewLabel(prNumber, skillDir) {
|
||||
if (!prNumber) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const safeSkill = skillDir.replace(/[^A-Za-z0-9._-]+/g, '-').replace(/^-+|-+$/g, '');
|
||||
return `pr-${prNumber}-${safeSkill}`;
|
||||
}
|
||||
|
||||
function runTessl(args, options = {}) {
|
||||
const result = spawnSync('tessl', args, {
|
||||
cwd: options.cwd || process.cwd(),
|
||||
encoding: 'utf8',
|
||||
stdio: 'inherit',
|
||||
});
|
||||
|
||||
if (result.error) {
|
||||
throw result.error;
|
||||
}
|
||||
|
||||
if (result.signal) {
|
||||
throw new Error(`tessl ${args.join(' ')} terminated by signal ${result.signal}`);
|
||||
}
|
||||
|
||||
if (result.status !== 0) {
|
||||
throw new Error(`tessl ${args.join(' ')} failed with exit code ${result.status}`);
|
||||
}
|
||||
}
|
||||
|
||||
function main() {
|
||||
const baseSha = process.env.BASE_SHA;
|
||||
const headSha = process.env.HEAD_SHA || 'HEAD';
|
||||
const workspace = process.env.TESSL_WORKSPACE || DEFAULT_WORKSPACE;
|
||||
const threshold = process.env.TESSL_REVIEW_THRESHOLD || DEFAULT_THRESHOLD;
|
||||
const reviewPlugin = process.env.TESSL_REVIEW_PLUGIN;
|
||||
const prNumber = process.env.PR_NUMBER;
|
||||
|
||||
const files = getChangedSkillFiles(baseSha, headSha);
|
||||
const skillDirs = getChangedSkillDirs(files);
|
||||
|
||||
if (skillDirs.length === 0) {
|
||||
console.log('No changed SKILL.md files to review.');
|
||||
return;
|
||||
}
|
||||
|
||||
for (const skillDir of skillDirs) {
|
||||
const label = reviewLabel(prNumber, skillDir);
|
||||
const args = buildReviewArgs(skillDir, {
|
||||
label,
|
||||
reviewPlugin,
|
||||
threshold,
|
||||
workspace,
|
||||
});
|
||||
console.log(`Running Tessl Review for ${skillDir}`);
|
||||
runTessl(args);
|
||||
}
|
||||
}
|
||||
|
||||
if (require.main === module) {
|
||||
try {
|
||||
main();
|
||||
} catch (error) {
|
||||
console.error(error instanceof Error ? error.message : String(error));
|
||||
process.exitCode = 1;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
buildReviewArgs,
|
||||
ensureRepoRelative,
|
||||
getChangedSkillDirs,
|
||||
getChangedSkillFiles,
|
||||
reviewLabel,
|
||||
};
|
||||
@@ -0,0 +1,76 @@
|
||||
const assert = require('node:assert');
|
||||
const fs = require('node:fs');
|
||||
const os = require('node:os');
|
||||
const path = require('node:path');
|
||||
|
||||
const repoRoot = path.resolve(__dirname, '..', '..', '..');
|
||||
const {
|
||||
buildReviewArgs,
|
||||
ensureRepoRelative,
|
||||
getChangedSkillDirs,
|
||||
getChangedSkillFiles,
|
||||
reviewLabel,
|
||||
} = require(path.join(repoRoot, 'tools', 'scripts', 'review_changed_skills.cjs'));
|
||||
|
||||
const changed = getChangedSkillFiles('base', 'head', {
|
||||
git(args) {
|
||||
assert.deepStrictEqual(args, [
|
||||
'diff',
|
||||
'--name-only',
|
||||
'--diff-filter=ACMR',
|
||||
'base',
|
||||
'head',
|
||||
'--',
|
||||
]);
|
||||
return [
|
||||
'skills/alpha/SKILL.md',
|
||||
'README.md',
|
||||
'plugins/example/SKILL.md',
|
||||
'skills/beta/notes.md',
|
||||
'',
|
||||
].join('\n');
|
||||
},
|
||||
});
|
||||
|
||||
assert.deepStrictEqual(changed, ['skills/alpha/SKILL.md', 'plugins/example/SKILL.md']);
|
||||
|
||||
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'aas-review-skills-'));
|
||||
fs.mkdirSync(path.join(tempDir, 'skills', 'alpha'), { recursive: true });
|
||||
fs.mkdirSync(path.join(tempDir, 'plugins', 'example'), { recursive: true });
|
||||
fs.writeFileSync(path.join(tempDir, 'skills', 'alpha', 'SKILL.md'), 'alpha');
|
||||
fs.writeFileSync(path.join(tempDir, 'plugins', 'example', 'SKILL.md'), 'example');
|
||||
|
||||
assert.deepStrictEqual(getChangedSkillDirs(changed, tempDir), [
|
||||
'plugins/example',
|
||||
'skills/alpha',
|
||||
]);
|
||||
|
||||
assert.throws(
|
||||
() => ensureRepoRelative('../outside/SKILL.md', tempDir),
|
||||
/Path traversal detected/,
|
||||
);
|
||||
|
||||
assert.deepStrictEqual(
|
||||
buildReviewArgs('skills/alpha', {
|
||||
label: 'pr-123-skills-alpha',
|
||||
reviewPlugin: 'aas-reviewer',
|
||||
threshold: '85',
|
||||
workspace: 'antigravity-awesome-skills',
|
||||
}),
|
||||
[
|
||||
'review',
|
||||
'run',
|
||||
'skills/alpha',
|
||||
'--workspace',
|
||||
'antigravity-awesome-skills',
|
||||
'--json',
|
||||
'--threshold',
|
||||
'85',
|
||||
'--review-plugin',
|
||||
'aas-reviewer',
|
||||
'--label',
|
||||
'pr-123-skills-alpha',
|
||||
],
|
||||
);
|
||||
|
||||
assert.strictEqual(reviewLabel('123', 'skills/alpha'), 'pr-123-skills-alpha');
|
||||
@@ -27,6 +27,7 @@ const LOCAL_TEST_COMMANDS = [
|
||||
[path.join(TOOL_TESTS, "merge_batch.test.js")],
|
||||
[path.join(TOOL_TESTS, "npm_package_contents.test.js")],
|
||||
[path.join(TOOL_TESTS, "repo_hygiene_security.test.js")],
|
||||
[path.join(TOOL_TESTS, "review_changed_skills.test.js")],
|
||||
[path.join(TOOL_TESTS, "copy_security.test.js")],
|
||||
[path.join(TOOL_TESTS, "setup_web_sync.test.js")],
|
||||
[path.join(TOOL_TESTS, "skill_filter.test.js")],
|
||||
|
||||
Reference in New Issue
Block a user