fix(cli): fail blocked sync checks

Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com>
This commit is contained in:
XiaoSeS 2026-09-02 18:08:44 +08:00
parent 75bfb452d9
commit 362ca1e06a
2 changed files with 19 additions and 6 deletions

View file

@ -89,11 +89,15 @@ export async function inspectNamespaceWorkspace(options: {
}
const snapshot = await snapshotSkillDirectory(skillDir)
const changedFiles = snapshot.fingerprint === metadata.fingerprint
? []
: diffSkillFiles(metadata.files, snapshot.files)
const versionOrder = compareSkillVersions(metadata.version, remote.version)
if (versionOrder === 'remote-older') {
entries.push({
...baseEntry(remote, 'blocked'),
localVersion: metadata.version,
changedFiles,
reason: 'remote version is older than the installed version; local files were kept'
})
continue
@ -102,6 +106,7 @@ export async function inspectNamespaceWorkspace(options: {
entries.push({
...baseEntry(remote, 'blocked'),
localVersion: metadata.version,
changedFiles,
reason: 'cannot determine version order; use explicit install after verifying the release'
})
continue
@ -110,6 +115,7 @@ export async function inspectNamespaceWorkspace(options: {
entries.push({
...baseEntry(remote, 'blocked'),
localVersion: metadata.version,
changedFiles,
reason: 'remote content changed without a newer version; use explicit install after verifying the release'
})
continue
@ -118,7 +124,7 @@ export async function inspectNamespaceWorkspace(options: {
entries.push({
...baseEntry(remote, 'local-changed'),
localVersion: metadata.version,
changedFiles: diffSkillFiles(metadata.files, snapshot.files)
changedFiles
})
continue
}
@ -168,7 +174,9 @@ export async function pullNamespace(options: {
rootDir: options.rootDir,
entries: inspected.entries,
actions: [],
failures: [],
failures: inspected.entries
.filter(entry => entry.status === 'blocked')
.map(entry => ({ slug: entry.slug, message: entry.reason ?? 'automatic sync is blocked' })),
warnings: []
}
if (options.check) return result
@ -176,10 +184,7 @@ export async function pullNamespace(options: {
const remoteBySlug = new Map(inspected.remoteItems.map(item => [item.slug, item]))
for (const entry of inspected.entries) {
if (entry.status === 'up-to-date' || entry.status === 'orphaned') continue
if (entry.status === 'blocked') {
result.failures.push({ slug: entry.slug, message: entry.reason ?? 'automatic sync is blocked' })
continue
}
if (entry.status === 'blocked') continue
if (entry.status === 'local-changed' && !options.force) {
result.failures.push({ slug: entry.slug, message: entry.reason ?? 'local changes detected; pass --force to overwrite' })
continue

View file

@ -193,6 +193,13 @@ describe('sync command', () => {
reason: 'remote content changed without a newer version; use explicit install after verifying the release'
})
const checked = await runCli([
'sync', 'pull', '--namespace', 'team-a', '--dir', skillsDir, '--check',
'--registry', registry.url, '--token', 'token', '--json'
], { HOME: env.home }, { cwd: env.cwd })
expect(checked.exitCode).toBe(6)
expect(JSON.parse(checked.stdout)).toMatchObject({ ok: false, check: true })
const pulled = await runCli([
'sync', 'pull', '--namespace', 'team-a', '--dir', skillsDir, '--force',
'--registry', registry.url, '--token', 'token', '--json'
@ -334,6 +341,7 @@ describe('sync command', () => {
const output = JSON.parse(pulled.stdout)
expect(pulled.exitCode, variant.name).toBe(6)
expect(output.entries[0], variant.name).toMatchObject({ status: 'blocked', reason: variant.reason })
expect(output.entries[0].changedFiles, variant.name).toEqual(['SKILL.md'])
expect(output.actions, variant.name).toEqual([])
expect(await readFile(join(skillsDir, 'demo', 'SKILL.md'), 'utf8'))
.toBe(`# local edit before ${variant.name}\n`)