From 362ca1e06a76512d61aa9b8aa5b8d98cccb00796 Mon Sep 17 00:00:00 2001 From: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com> Date: Wed, 2 Sep 2026 18:08:44 +0800 Subject: [PATCH] fix(cli): fail blocked sync checks Signed-off-by: XiaoSeS <87064762+XiaoSeS@users.noreply.github.com> --- cli/src/services/sync-service.ts | 17 +++++++++++------ cli/test/integration/sync-command.test.ts | 8 ++++++++ 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/cli/src/services/sync-service.ts b/cli/src/services/sync-service.ts index 80a38521..2bab0298 100644 --- a/cli/src/services/sync-service.ts +++ b/cli/src/services/sync-service.ts @@ -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 diff --git a/cli/test/integration/sync-command.test.ts b/cli/test/integration/sync-command.test.ts index cfa70ab5..9978cc40 100644 --- a/cli/test/integration/sync-command.test.ts +++ b/cli/test/integration/sync-command.test.ts @@ -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`)