fix(dsh): валидировать legacy-кэш и пустой --superpowers-from (#49)
This commit is contained in:
parent
ab458b58d2
commit
4054e13806
@ -28,6 +28,7 @@ DO_SKILLS=0
|
|||||||
DO_ROLES=0
|
DO_ROLES=0
|
||||||
DO_OPENSPEC=0
|
DO_OPENSPEC=0
|
||||||
SUPERPOWERS_FROM=""
|
SUPERPOWERS_FROM=""
|
||||||
|
SUPERPOWERS_FROM_SET=0
|
||||||
CLONE_HINT="git clone --depth 1 https://github.com/obra/superpowers $DSH_HOME/superpowers"
|
CLONE_HINT="git clone --depth 1 https://github.com/obra/superpowers $DSH_HOME/superpowers"
|
||||||
|
|
||||||
usage() {
|
usage() {
|
||||||
@ -73,15 +74,26 @@ while [ "$#" -gt 0 ]; do
|
|||||||
exit 2
|
exit 2
|
||||||
fi
|
fi
|
||||||
SUPERPOWERS_FROM="$2"
|
SUPERPOWERS_FROM="$2"
|
||||||
|
SUPERPOWERS_FROM_SET=1
|
||||||
shift
|
shift
|
||||||
;;
|
;;
|
||||||
--superpowers-from=*) SUPERPOWERS_FROM="${1#*=}" ;;
|
--superpowers-from=*)
|
||||||
|
SUPERPOWERS_FROM="${1#*=}"
|
||||||
|
SUPERPOWERS_FROM_SET=1
|
||||||
|
;;
|
||||||
-h|--help) usage; exit 0 ;;
|
-h|--help) usage; exit 0 ;;
|
||||||
*) echo "unknown option: $1" >&2; usage >&2; exit 2 ;;
|
*) echo "unknown option: $1" >&2; usage >&2; exit 2 ;;
|
||||||
esac
|
esac
|
||||||
shift
|
shift
|
||||||
done
|
done
|
||||||
|
|
||||||
|
# An explicit flag with an empty value is a typo, not "use the default source":
|
||||||
|
# falling through to legacy would mask exactly the misconfiguration D-2 forbids.
|
||||||
|
if [ "$SUPERPOWERS_FROM_SET" = 1 ] && [ -z "$SUPERPOWERS_FROM" ]; then
|
||||||
|
echo "option --superpowers-from needs a non-empty directory" >&2
|
||||||
|
exit 2
|
||||||
|
fi
|
||||||
|
|
||||||
# Normalize a superpowers source: accept the repo root (with skills/) or the
|
# Normalize a superpowers source: accept the repo root (with skills/) or the
|
||||||
# skills directory itself. Prints the skills directory, returns 1 otherwise.
|
# skills directory itself. Prints the skills directory, returns 1 otherwise.
|
||||||
normalize_superpowers_dir() {
|
normalize_superpowers_dir() {
|
||||||
@ -117,8 +129,11 @@ superpowers_source() {
|
|||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
legacy="$(ls -d "$HOME"/.claude/plugins/cache/claude-plugins-official/superpowers/*/skills 2>/dev/null | sort -V | tail -1 || true)"
|
legacy="$(ls -d "$HOME"/.claude/plugins/cache/claude-plugins-official/superpowers/*/skills 2>/dev/null | sort -V | tail -1 || true)"
|
||||||
if [ -n "$legacy" ] && [ -d "$legacy" ]; then
|
# A cache directory without using-superpowers is a broken cache, not a source:
|
||||||
printf '%s\tlegacy\n' "$legacy"
|
# accepting it would copy 0 skills and report success (the silent empty
|
||||||
|
# bootstrap this change removes).
|
||||||
|
if [ -n "$legacy" ] && dir="$(normalize_superpowers_dir "$legacy")"; then
|
||||||
|
printf '%s\tlegacy\n' "$dir"
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
if dir="$(normalize_superpowers_dir "$HOME/.claude/skills")"; then
|
if dir="$(normalize_superpowers_dir "$HOME/.claude/skills")"; then
|
||||||
|
|||||||
@ -303,3 +303,44 @@ test('--global installs DSH role paths and explains the instruction format', ()
|
|||||||
cleanup(home)
|
cleanup(home)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test('a legacy cache without using-superpowers is not a source', () => {
|
||||||
|
const home = tempDir()
|
||||||
|
try {
|
||||||
|
const cache = join(
|
||||||
|
home,
|
||||||
|
'.claude',
|
||||||
|
'plugins',
|
||||||
|
'cache',
|
||||||
|
'claude-plugins-official',
|
||||||
|
'superpowers',
|
||||||
|
'7.0.0',
|
||||||
|
'skills',
|
||||||
|
)
|
||||||
|
write(join(cache, 'brainstorming', 'SKILL.md'), '---\nname: brainstorming\n---\nbody\n')
|
||||||
|
const run = runInstaller(home, ['--skills'])
|
||||||
|
const out = run.stdout + run.stderr
|
||||||
|
assert.equal(run.status, 1, out)
|
||||||
|
assert.match(out, /FAIL: no superpowers source/)
|
||||||
|
assert.doesNotMatch(out, /copied 0 superpowers/)
|
||||||
|
assert.equal(existsSync(join(home, '.dsh', 'skills', 'brainstorming')), false)
|
||||||
|
} finally {
|
||||||
|
cleanup(home)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
test('an empty --superpowers-from is rejected, not ignored', () => {
|
||||||
|
const home = tempDir()
|
||||||
|
try {
|
||||||
|
makeLegacyCache(home)
|
||||||
|
for (const args of [['--skills', '--superpowers-from='], ['--skills', '--superpowers-from', '']]) {
|
||||||
|
const run = runInstaller(home, args)
|
||||||
|
const out = run.stdout + run.stderr
|
||||||
|
assert.equal(run.status, 2, out)
|
||||||
|
assert.match(out, /needs a non-empty directory/)
|
||||||
|
assert.equal(existsSync(join(home, '.dsh', 'skills', 'using-superpowers')), false)
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
cleanup(home)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user