DSH: OpenSpec — проектные скиллы, --openspec, проверка (#42) #60

Merged
aep merged 10 commits from feat/42-dsh-openspec into main 2026-10-24 18:59:58 +03:00
2 changed files with 43 additions and 1 deletions
Showing only changes of commit 9ecc3eb793 - Show all commits

View File

@ -120,6 +120,16 @@ check() {
else else
echo "WARN: subagent maxDepth is not 2 in any profile patch; SDD mode 2 is unavailable" >&2 echo "WARN: subagent maxDepth is not 2 in any profile patch; SDD mode 2 is unavailable" >&2
fi fi
if command -v openspec >/dev/null 2>&1; then
echo "ok: openspec $(openspec --version 2>/dev/null | head -1)"
else
echo "WARN: openspec not found; OpenSpec workflows are unavailable" >&2
fi
if [ -f "$ROOT/.agents/skills/openspec-propose/SKILL.md" ]; then
echo "ok: openspec agents skills ($ROOT/.agents/skills)"
else
echo "WARN: .agents/skills missing; run --openspec in the project" >&2
fi
if [ -f "$DSH_HOME/skills/using-superpowers/SKILL.md" ]; then if [ -f "$DSH_HOME/skills/using-superpowers/SKILL.md" ]; then
echo "ok: dsh skills ($DSH_HOME/skills)" echo "ok: dsh skills ($DSH_HOME/skills)"
elif superpowers_skills >/dev/null 2>&1; then elif superpowers_skills >/dev/null 2>&1; then

View File

@ -1,10 +1,13 @@
import assert from 'node:assert/strict' import assert from 'node:assert/strict'
import { existsSync, readFileSync } from 'node:fs' import { spawnSync } from 'node:child_process'
import { chmodSync, existsSync, readFileSync } from 'node:fs'
import { dirname, join } from 'node:path' import { dirname, join } from 'node:path'
import test from 'node:test' import test from 'node:test'
import { fileURLToPath } from 'node:url' import { fileURLToPath } from 'node:url'
import { cleanup, tempDir, write } from './helpers.mjs'
const here = dirname(fileURLToPath(import.meta.url)) const here = dirname(fileURLToPath(import.meta.url))
const script = join(here, '..', 'install.sh')
const root = join(here, '..', '..') const root = join(here, '..', '..')
const agentsSkills = join(root, '.agents', 'skills') const agentsSkills = join(root, '.agents', 'skills')
const NAMES = [ const NAMES = [
@ -26,3 +29,32 @@ test('repository ships six agents skills for DSH', () => {
assert.match(text, /description: .*openspec/i, `${name}: description must mention openspec`) assert.match(text, /description: .*openspec/i, `${name}: description must mention openspec`)
} }
}) })
test('install.sh --check reports the openspec CLI and the agents skills', () => {
const home = tempDir()
try {
const bin = join(home, 'bin')
write(join(bin, 'openspec'), '#!/bin/sh\n[ "$1" = "--version" ] && echo 1.13.1\nexit 0\n')
chmodSync(join(bin, 'openspec'), 0o755)
const env = { ...process.env, HOME: home, DSH_HOME: join(home, '.dsh'), PATH: `${bin}:${process.env.PATH}` }
const run = spawnSync('bash', [script, '--check'], { env, encoding: 'utf8' })
assert.equal(run.status, 0, run.stderr)
assert.match(run.stdout, /ok: openspec 1\.13\.1/)
assert.match(run.stdout, /ok: openspec agents skills \(/)
} finally {
cleanup(home)
}
})
test('install.sh --check warns but does not fail without the openspec CLI', () => {
const home = tempDir()
try {
const bin = join(home, 'bin')
const env = { ...process.env, HOME: home, DSH_HOME: join(home, '.dsh'), PATH: bin }
const run = spawnSync('bash', [script, '--check'], { env, encoding: 'utf8' })
assert.match(run.stdout + run.stderr, /WARN: openspec not found/)
assert.equal(run.status, 0)
} finally {
cleanup(home)
}
})