Reapplies @MatrixNeoKozak's PR #47 onto current main (resolves the bin/cli.mjs conflict with the star-nudge changes): - resolve() the install target and refuse system-critical dirs (/, /usr, /etc, /root, ...) so a typo'd --target can't clobber the system - skillcheck frontmatter parser tolerates leading whitespace and CRLF/LF Claude-Session: https://claude.ai/code/session_016JWn5jRD5tcEFKrubjQ6Px Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: MatrixNeoKozak <MatrixNeoKozak@users.noreply.github.com>
This commit is contained in:
+10
-2
@@ -13,7 +13,7 @@
|
||||
// --link symlink instead of copy (native agents; falls back to copy)
|
||||
// --dry-run print what would happen without writing
|
||||
import { readdirSync, existsSync, mkdirSync, rmSync, cpSync, symlinkSync, copyFileSync, statSync } from 'node:fs';
|
||||
import { join, dirname, basename } from 'node:path';
|
||||
import { join, dirname, basename, resolve } from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import { homedir } from 'node:os';
|
||||
import { createRequire } from 'node:module';
|
||||
@@ -79,7 +79,15 @@ function add(opts) {
|
||||
}
|
||||
const skillsDir = join(PKG_ROOT, 'skills');
|
||||
if (!existsSync(skillsDir)) { console.error(`Error: bundled skills/ not found at ${skillsDir}.`); process.exit(1); }
|
||||
const target = opts.target || defaultTarget(agent);
|
||||
const target = resolve(opts.target || defaultTarget(agent));
|
||||
|
||||
// Guard against installing into system-critical directories (e.g. a typo'd --target).
|
||||
const criticalPaths = ['/', '/usr', '/bin', '/etc', '/var', '/root', '/boot', '/proc', '/sys', '/dev'];
|
||||
if (criticalPaths.includes(target)) {
|
||||
console.error(`Error: Cannot install into a system-critical directory: ${target}`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
let count = 0;
|
||||
|
||||
console.log(`${opts.dryRun ? '[dry-run] ' : ''}Installing for '${agent}' into ${target}`);
|
||||
|
||||
@@ -22,10 +22,12 @@ const strict = args.includes('--strict');
|
||||
const asJson = args.includes('--json');
|
||||
|
||||
function parseFrontmatter(text) {
|
||||
const m = text.match(/^---\n([\s\S]*?)\n---\n?([\s\S]*)$/);
|
||||
// Tolerate optional leading whitespace and CRLF/LF line endings so authored-on-Windows
|
||||
// files don't produce false negatives.
|
||||
const m = text.match(/^\s*---\r?\n([\s\S]*?)\r?\n\s*---\r?\n?([\s\S]*)$/);
|
||||
if (!m) return { meta: null, body: text };
|
||||
const meta = {};
|
||||
for (const line of m[1].split('\n')) {
|
||||
for (const line of m[1].split(/\r?\n/)) {
|
||||
const kv = line.match(/^(\w[\w-]*):\s*(.*)$/);
|
||||
if (kv) {
|
||||
let v = kv[2].trim();
|
||||
|
||||
Reference in New Issue
Block a user