Skip to content

feat(sync): use on-disk content hashing to skip unchanged sync work#1

Merged
willmruzek merged 20 commits intomainfrom
fix/dont-show-updated
Apr 24, 2026
Merged

feat(sync): use on-disk content hashing to skip unchanged sync work#1
willmruzek merged 20 commits intomainfrom
fix/dont-show-updated

Conversation

@willmruzek
Copy link
Copy Markdown
Owner

@willmruzek willmruzek commented Apr 21, 2026

Summary

  • Unchanged targets are detected by comparing a SHA-256 of the content that would be written to a SHA-256 of what’s already on disk. Matching hashes → unchanged: no write, omitted from the applied report.
  • Repeat sync with aligned sources and outputs shows Applied changes: None and drops empty per-agent sections.
  • Manifest load: strict validation first; if that fails, lenient recovery of outputs rows so pruning still runs after upgrades or slightly non-canonical files; runtime.logWarn when the file can’t be read/parsed, recovery is used, or rows can’t be validated.
  • Tests: no-op second sync, drift/restore for commands/rules/skills, missing SKILL.md, stray skill files, registry layout / partial agent failures, and pruning with strict-invalid but recoverable manifests (plus JSON / invalid-row cases).

Details

  • Invalid or non-JSON manifest: prior state treated as empty for strict purposes; user sees a warning; stale outputs may not be pruned that run unless rows are lenient-recoverable.

BREAKING CHANGE: sync-manifest.json is now version 3 and requires a
contentHash on each output. Older manifests fail validation and are
treated as empty (next sync re-writes and re-seeds hashes).

- Compare would-be-written content to the prior manifest hash to mark
  targets unchanged and omit them from the report without re-writing.
- Show Applied changes: None and drop empty agent sections when nothing
  applied for an agent.
- Add integration test for repeat no-op sync and update prune fixtures.
Copilot AI review requested due to automatic review settings April 21, 2026 11:59
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR upgrades the sync manifest format to v3 by adding a contentHash per output, and uses those hashes to skip rewriting targets whose would-be-written content is unchanged—also simplifying the sync report output for no-op runs.

Changes:

  • Bump sync-manifest.json schema to version 3 and require contentHash on every output entry.
  • Compute per-target SHA-256 content hashes during sync, detect unchanged targets, and skip writing + omit them from the “Applied changes” report.
  • Add an integration test for repeat no-op sync runs and update prune-related fixtures to satisfy the new manifest schema.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
src/lib/sync.ts Adds manifest v3 schema + content hashing to detect unchanged targets, skip writes, and adjust report rendering.
tests/commands/sync.test.ts Adds coverage for repeat no-op sync reporting and updates seeded manifests to include contentHash + version 3.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/lib/sync.ts
Comment thread src/lib/sync.ts Outdated
Base automatically changed from test/high-priority-tests to main April 23, 2026 13:53
Copilot AI review requested due to automatic review settings April 23, 2026 14:00
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.

Comment thread src/lib/sync.ts Outdated
Comment thread src/lib/sync.ts Outdated
Comment thread src/lib/sync.ts
…shes

Drop `contentHash` from manifest rows. Compare would-be-written SHA-256 snapshots to
on-disk markdown or copied skill trees, skip writes when they match, and
treat unreadable or schema-invalid manifests as empty so the next run
re-reports installs. Omit empty per-agent sections and print
"Applied changes: None" when nothing applied.
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated 6 comments.

Comments suppressed due to low confidence (1)

tests/commands/sync.test.ts:195

  • The test manifest schema (mockSyncManifestSchema) only asserts agent/kind/name/outputPath. If sync-manifest.json outputs now require a contentHash (per PR description), this schema and the expected manifest row builders should be updated to validate that contentHash exists and is stable across runs (especially in the new no-op sync test).
/** On-disk sync manifest: current schema version, outputs with agent / kind / name / outputPath. */
const mockSyncManifestSchema = z.object({
  version: z.literal(SYNC_MANIFEST_VERSION),
  outputs: z.array(
    z.object({
      agent: z.enum(['copilot', 'cursor']),
      kind: z.enum(['command', 'rule', 'skill']),
      name: z.string().min(1),
      outputPath: z.string().min(1),
    }),
  ),

Comment thread tests/commands/sync.test.ts Outdated
Comment thread tests/commands/sync.test.ts Outdated
Comment thread src/lib/sync.ts
Comment thread src/lib/sync.ts
Comment thread src/lib/sync.ts Outdated
Comment thread src/lib/sync.ts
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings April 24, 2026 11:12
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
@willmruzek willmruzek changed the title feat(sync)!: hash outputs in manifest v3 and skip unchanged sync work feat(sync): use on-disk content hashing to skip unchanged sync work Apr 24, 2026
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.

Comments suppressed due to low confidence (2)

tests/commands/sync.test.ts:193

  • mockSyncManifestSchema still models outputs as {agent, kind, name, outputPath} only. If the manifest is intended to be v3 and require contentHash per the PR description, this test schema should require contentHash as well so fixtures/tests fail when it is missing.
/** On-disk sync manifest: current schema version, outputs with agent / kind / name / outputPath. */
const mockSyncManifestSchema = z.object({
  version: z.literal(SYNC_MANIFEST_VERSION),
  outputs: z.array(
    z.object({
      agent: z.enum(['copilot', 'cursor']),
      kind: z.enum(['command', 'rule', 'skill']),
      name: z.string().min(1),
      outputPath: z.string().min(1),

tests/commands/sync.test.ts:1660

  • This manifest fixture omits the per-output contentHash described as required in the PR. Once the manifest schema is updated to v3, this JSON should include contentHash for every output row (and use the bumped manifest version).
          mockFileSystem,
          path.join(DEFAULT_CONFIG_ROOT, 'sync-manifest.json'),
          JSON.stringify({
            version: SYNC_MANIFEST_VERSION,
            outputs: [
              {
                agent: 'copilot',
                kind: 'command',
                name: 'gone-cmd',

Comment thread src/lib/sync.ts
Comment thread tests/commands/sync.test.ts
…nonical

After strict validation fails, parse outputs entries best-effort so removed
config items still delete old Copilot/Cursor copies. Log warnings for
unreadable, damaged, or unusable manifests.

Add tests for recovery, invalid JSON, and invalid rows.
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.

Comment thread src/lib/sync.ts Outdated
Comment thread tests/commands/sync.test.ts Outdated
Comment thread src/lib/sync.ts
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings April 24, 2026 11:47
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.

Comment thread src/lib/sync.ts
Copilot AI review requested due to automatic review settings April 24, 2026 11:53
@willmruzek willmruzek review requested due to automatic review settings April 24, 2026 11:53
Use `import type` for SyncAgent, a local mock manifest version, and
`satisfies Record<SyncAgent, true>` instead of importing SYNC_AGENTS or
SYNC_MANIFEST_VERSION.
Copilot AI review requested due to automatic review settings April 24, 2026 11:55
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.

Comment thread tests/commands/sync.test.ts
Comment thread tests/commands/sync.test.ts
Comment thread src/lib/sync.ts
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.

Comment thread tests/commands/sync.test.ts Outdated
Comment thread tests/commands/sync.test.ts
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings April 24, 2026 12:32
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.

Comment thread src/lib/sync.ts
@willmruzek willmruzek merged commit 464bd7c into main Apr 24, 2026
5 of 6 checks passed
@willmruzek willmruzek deleted the fix/dont-show-updated branch April 24, 2026 12:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants