From 6da68a620296109972988a20c2e43e1547488ad5 Mon Sep 17 00:00:00 2001 From: Chris Huber Date: Fri, 24 Apr 2026 14:23:32 -0400 Subject: [PATCH] Use @extrachill/chat canonical diff parser, delete local fork MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The editor carried a parallel `src/diff/canonicalDiff.ts` with its own CanonicalDiffType / CanonicalDiffStatus / CanonicalDiffItem / CanonicalDiffData types and its own parseCanonicalDiffFromJson. That duplication existed because the upstream parser only recognized `container.diff` as a nesting layer, while Data Machine's unified PendingActionHelper::stage() envelope nests under `preview`. @extrachill/chat v0.11.0 landed three relevant changes: - #21: adds `actionId` as the canonical field on CanonicalDiffData (alongside the deprecated `diffId` alias). The editor already spoke `actionId` so no vocabulary change was needed here, but the type on the upstream package was missing it until 0.11. - #22: forwards onToolCalls + sessionContext from to useChat (not used by this file directly, but relevant for other editor work). - #23: parseCanonicalDiff now recognizes `container.preview` and `container.preview_data` as nesting keys, which is exactly the shape our local fork existed to handle. With 0.11 in place, the local fork is redundant. Migration: - src/types.ts: import CanonicalDiffData / CanonicalDiffType from '@extrachill/chat' instead of './diff/canonicalDiff'. - src/sidebar/EditorChatSidebar.tsx: add parseCanonicalDiffFromJson to the existing @extrachill/chat imports, drop the local import. - Delete src/diff/canonicalDiff.ts (92 lines). - Bump @extrachill/chat from ^0.10.1 to ^0.11.0 in package.json. No runtime behaviour change — the upstream parser now handles the same nesting shapes our fork did, and we were already consuming the `actionId` field which v0.11 surfaces on the typed shape. --- package-lock.json | 8 +-- package.json | 2 +- src/diff/canonicalDiff.ts | 92 ------------------------------- src/sidebar/EditorChatSidebar.tsx | 2 +- src/types.ts | 2 +- 5 files changed, 7 insertions(+), 99 deletions(-) delete mode 100644 src/diff/canonicalDiff.ts diff --git a/package-lock.json b/package-lock.json index 8fec2c7..8219692 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,7 +8,7 @@ "name": "data-machine-editor", "version": "0.1.0", "dependencies": { - "@extrachill/chat": "^0.10.1", + "@extrachill/chat": "^0.11.0", "@extrachill/components": "^0.4.1", "@wordpress/api-fetch": "^7.0.0", "@wordpress/interface": "^9.11.0" @@ -2414,9 +2414,9 @@ } }, "node_modules/@extrachill/chat": { - "version": "0.10.1", - "resolved": "https://registry.npmjs.org/@extrachill/chat/-/chat-0.10.1.tgz", - "integrity": "sha512-eQ9L7LQi+0WKBvNV5SONDyql14M/OL9necuAtq5NdCz2qd9JhIz5WeCqwmzz9JTzGj1FgvniusKjSOXi2RGuWQ==", + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@extrachill/chat/-/chat-0.11.0.tgz", + "integrity": "sha512-wOskWB9SucQKGWmMfC98Fvyeg7cIBmYoeZtrh06RBKZTtSJP0JL5TYnANYsyf578jOX7y9KzLt3i/LCHbu9Cjg==", "license": "GPL-2.0-or-later", "dependencies": { "react-markdown": "^10.1.0" diff --git a/package.json b/package.json index a4eac8c..3b77bac 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,7 @@ "typescript": "^5.4.0" }, "dependencies": { - "@extrachill/chat": "^0.10.1", + "@extrachill/chat": "^0.11.0", "@extrachill/components": "^0.4.1", "@wordpress/api-fetch": "^7.0.0", "@wordpress/interface": "^9.11.0" diff --git a/src/diff/canonicalDiff.ts b/src/diff/canonicalDiff.ts deleted file mode 100644 index 2f63613..0000000 --- a/src/diff/canonicalDiff.ts +++ /dev/null @@ -1,92 +0,0 @@ -export type CanonicalDiffType = 'edit' | 'replace' | 'insert'; -export type CanonicalDiffStatus = 'pending' | 'accepted' | 'rejected'; - -export interface CanonicalDiffItem { - blockIndex?: number; - originalContent?: string; - replacementContent?: string; -} - -export interface CanonicalDiffData { - actionId: string; - diffType: CanonicalDiffType; - originalContent: string; - replacementContent: string; - status?: CanonicalDiffStatus; - summary?: string; - items?: CanonicalDiffItem[]; - position?: string; - insertionPoint?: string; - editor?: Record< string, unknown >; -} - -type UnknownRecord = Record< string, unknown >; - -function isRecord( value: unknown ): value is UnknownRecord { - return !! value && typeof value === 'object' && ! Array.isArray( value ); -} - -export function parseCanonicalDiffFromJson( json: string ): CanonicalDiffData | null { - try { - const parsed = JSON.parse( json ) as UnknownRecord; - const container = isRecord( parsed.data ) ? parsed.data : parsed; - - // The canonical preview shape nests the diff payload under - // `preview` (from PendingActionHelper::stage()). Fall back to - // older shapes (`diff`, container itself) for resiliency while - // the editor wires up to the unified envelope. - const rawDiff = isRecord( container.preview ) - ? container.preview - : isRecord( container.diff ) - ? container.diff - : container; - - const actionId = typeof rawDiff.actionId === 'string' - ? rawDiff.actionId - : typeof container.action_id === 'string' - ? container.action_id - : ''; - - const originalContent = typeof rawDiff.originalContent === 'string' - ? rawDiff.originalContent - : ''; - const replacementContent = typeof rawDiff.replacementContent === 'string' - ? rawDiff.replacementContent - : ''; - - if ( ! actionId && ! originalContent && ! replacementContent ) { - return null; - } - - const items = Array.isArray( rawDiff.items ) - ? rawDiff.items.map( ( item ) => { - if ( ! isRecord( item ) ) { - return null; - } - - return { - blockIndex: typeof item.blockIndex === 'number' ? item.blockIndex : undefined, - originalContent: typeof item.originalContent === 'string' ? item.originalContent : undefined, - replacementContent: typeof item.replacementContent === 'string' ? item.replacementContent : undefined, - }; - } ).filter( Boolean ) as CanonicalDiffItem[] - : undefined; - - return { - actionId, - diffType: rawDiff.diffType === 'replace' || rawDiff.diffType === 'insert' ? rawDiff.diffType : 'edit', - originalContent, - replacementContent, - status: rawDiff.status === 'accepted' || rawDiff.status === 'rejected' || rawDiff.status === 'pending' - ? rawDiff.status - : undefined, - summary: typeof rawDiff.summary === 'string' ? rawDiff.summary : typeof container.message === 'string' ? container.message : undefined, - items: items && items.length > 0 ? items : undefined, - position: typeof rawDiff.position === 'string' ? rawDiff.position : undefined, - insertionPoint: typeof rawDiff.insertionPoint === 'string' ? rawDiff.insertionPoint : undefined, - editor: isRecord( rawDiff.editor ) ? rawDiff.editor : undefined, - }; - } catch { - return null; - } -} diff --git a/src/sidebar/EditorChatSidebar.tsx b/src/sidebar/EditorChatSidebar.tsx index 79e8016..f619edc 100644 --- a/src/sidebar/EditorChatSidebar.tsx +++ b/src/sidebar/EditorChatSidebar.tsx @@ -15,11 +15,11 @@ import { TypingIndicator, ErrorBoundary, SessionSwitcher, + parseCanonicalDiffFromJson, type ChatMessage, } from '@extrachill/chat'; import { InlineDiffManager } from '../editor/InlineDiffManager'; import type { DiffContext, DiffContextItem } from '../types'; -import { parseCanonicalDiffFromJson } from '../diff/canonicalDiff'; /** * Extract diff-producing tool call results into a DiffContext diff --git a/src/types.ts b/src/types.ts index 1b14a5a..350127a 100644 --- a/src/types.ts +++ b/src/types.ts @@ -2,7 +2,7 @@ * Shared types for the Data Machine Editor plugin. */ -import type { CanonicalDiffData, CanonicalDiffType } from './diff/canonicalDiff'; +import type { CanonicalDiffData, CanonicalDiffType } from '@extrachill/chat'; /** Diff mode: how the change is applied to the content. */ export type DiffType = CanonicalDiffType | 'write' | 'delete';