Refactor/extract changeproposal applier#194
Conversation
…ind/types package Move DiffService, ChangeProposalConflictError, isExpectedChangeProposalType, and Abstract/Standard/Command/Skill ChangeProposalApplier classes into @packmind/types so both backend and frontend share the same pure application logic including diff-based merging. Refactor backend appliers into thin Persistable* subclasses keeping only persistence logic, and update frontend to use shared appliers for accurate preview with change tracking wrappers. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ame Persistable classes Extract pure domain logic (areChangesApplicable, applyChangeProposals) into base applier classes in packages/types for frontend reuse, and rename the persistence layer classes from PersistableXxxChangeProposalApplier to shorter XxxChangesApplier names since their context within the applyChangeProposals use case is already clear. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ndard and Skill frontend appliers The frontend Standard and Skill appliers built FieldChange tracking metadata that was never consumed by their respective result tab components. Remove the dead ChangeTracker/SkillChangeTracker interfaces, tracking code, and related test assertions. Also fix pre-existing TS2345 in RecipeChangeTracker by adding an index signature compatible with trackScalarChange. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
# Conflicts: # packages/types/src/playbookChangeManagement/index.ts
…ipe frontend applier Delete dead components (ProposalReviewPanel, HighlightedContent, UnifiedMarkdownViewer, ReviewDetailLayout) and remove FieldChange/trackScalarChange helpers that had no remaining callers after the Standard and Skill applier cleanup in 9aebb55. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Greptile SummaryThis PR extracts the change-proposal application logic from both the frontend (duplicated Key changes and observations:
Confidence Score: 4/5
Important Files Changed
Class Diagram%%{init: {'theme': 'neutral'}}%%
classDiagram
class AbstractChangeProposalApplier~Version~ {
-DiffService diffService
+applyChangeProposals(source, changeProposals) Version
+areChangesApplicable(changeProposals) bool
#checkChangesApplicable(changeProposals, supportedTypes) bool
#applyChangeProposal(source, changeProposal) Version
#applyDiff(changeProposalId, payload, sourceContent) string
}
class CommandChangeProposalApplier {
+areChangesApplicable(changeProposals) bool
#applyChangeProposal(source, changeProposal) RecipeVersion
}
class SkillChangeProposalApplier {
+areChangesApplicable(changeProposals) bool
#applyChangeProposal(source, changeProposal) SkillVersionWithFiles
}
class StandardChangeProposalApplier {
+areChangesApplicable(changeProposals) bool
#applyChangeProposal(source, changeProposal) StandardVersion
}
class CommandChangesApplier {
-IRecipesPort recipesPort
+getVersion(artefactId) RecipeVersion
+saveNewVersion(version, ...) RecipeVersion
}
class SkillChangesApplier {
-ISkillsPort skillsPort
+getVersion(artefactId) SkillVersionWithFiles
+saveNewVersion(skillVersion, ...) SkillVersionWithFiles
}
class StandardChangesApplier {
-IStandardsPort standardsPort
+getVersion(artefactId) StandardVersion
+saveNewVersion(version, ...) StandardVersion
}
class DiffService {
+applyLineDiff(oldValue, newValue, currentValue) DiffResult
+hasConflict(oldValue, newValue, currentValue) bool
}
AbstractChangeProposalApplier <|-- CommandChangeProposalApplier : extends
AbstractChangeProposalApplier <|-- SkillChangeProposalApplier : extends
AbstractChangeProposalApplier <|-- StandardChangeProposalApplier : extends
CommandChangeProposalApplier <|-- CommandChangesApplier : extends (backend)
SkillChangeProposalApplier <|-- SkillChangesApplier : extends (backend)
StandardChangeProposalApplier <|-- StandardChangesApplier : extends (backend)
note for CommandChangeProposalApplier "Shared via @packmind/types"
note for SkillChangeProposalApplier "Shared via @packmind/types"
note for StandardChangeProposalApplier "Shared via @packmind/types"
note for CommandChangesApplier "Backend only, adds persistence"
note for SkillChangesApplier "Backend only, adds persistence"
note for StandardChangesApplier "Backend only, adds persistence"
|
# Conflicts: # apps/frontend/src/domain/change-proposals/components/ReviewDetailLayout/ReviewDetailLayout.tsx
|
…nd preview utilities Wrap applier calls in applyRecipeProposals, applyStandardProposals, and applySkillProposals with try/catch for ChangeProposalConflictError, returning original source values as a graceful fallback to prevent render crashes in useMemo. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…pes instead of throwing Replace throw with return source in concrete appliers to restore the original default: break behavior and prevent frontend preview UI crashes. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
# Conflicts: # package-lock.json



Extraction of change proposal applier from the backend into a shared package between frontend and backend so the preview when reviewing changes and result when applying changes are the same