Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
54 commits
Select commit Hold shift + click to select a range
dd41af0
refactor(painters/dom): drop list-item fragment renderer
luccas-harbour May 13, 2026
d010861
refactor(painters/dom): unify paragraph rendering across body and tab…
luccas-harbour May 13, 2026
5a0af37
fix(painters/dom): keep split paragraph fragment height
luccas-harbour May 13, 2026
10ec04c
fix(painters/dom): mark remeasured paragraph final lines
luccas-harbour May 13, 2026
9003049
fix(painters/dom): keep list marker right indent
luccas-harbour May 13, 2026
7ce35b5
refactor(painters/dom): reuse shared list marker types
luccas-harbour May 13, 2026
9c641de
test(painters/dom): cover resolved paragraph rendering
luccas-harbour May 13, 2026
4466493
refactor(painters/dom): colocate paragraph borders and marker helpers
luccas-harbour May 14, 2026
fd8b87e
refactor(painters/dom): extract run rendering into runs/ module
luccas-harbour May 14, 2026
46efc9d
refactor(painters/dom): extract paragraph fragment rendering into par…
luccas-harbour May 15, 2026
4417aed
test(painters/dom): drop unused contextSection from paragraph render …
luccas-harbour May 21, 2026
5e1e81b
fix(painter-dom): break list marker renderer cycle
luccas-harbour May 21, 2026
0a463ac
refactor(painters/dom): consolidate SDT container helpers into sdt/ m…
luccas-harbour May 14, 2026
3284962
fix(painters/dom): continue nested table SDT chrome
luccas-harbour May 14, 2026
85e77a2
fix(painters/dom): suppress idless table SDT chrome
luccas-harbour May 14, 2026
c1d92bd
fix(painters/dom): inherit table container SDT chrome
luccas-harbour May 14, 2026
78f8f04
fix(painters/dom): keep nested SDT chrome active
luccas-harbour May 14, 2026
b1ace96
fix(painters/dom): suppress nested table SDT chrome
luccas-harbour May 14, 2026
ad6d6cc
fix(painters/dom): continue partial nested SDT chrome
luccas-harbour May 14, 2026
2bd9f2a
fix(painters/dom): preserve nested table SDT ancestor
luccas-harbour May 14, 2026
ae03e40
fix(painters/dom): allow nested SDT label overflow
luccas-harbour May 14, 2026
685ceb4
fix(painters/dom): scope nested SDT overflow to rendered content
luccas-harbour May 14, 2026
e44f2ec
fix(painters/dom): use rendered SDT lock mode
luccas-harbour May 15, 2026
944f988
fix(painters/dom): preserve ancestor SDT key
luccas-harbour May 15, 2026
28c5950
fix(painters/dom): merge idless SDT siblings
luccas-harbour May 15, 2026
308a3ed
test(painters/dom): cover SDT chrome gaps
luccas-harbour May 15, 2026
8e1627a
refactor(painters/dom): share SDT container keys
luccas-harbour May 15, 2026
913f86f
fix(painters/dom): drop unused table block local
luccas-harbour May 15, 2026
160108b
fix(painters/dom): skip media for SDT boundaries
luccas-harbour May 15, 2026
5c6753a
fix(painters/dom): preserve SDT ancestor chain
luccas-harbour May 15, 2026
cdad4c1
fix(painters/dom): defer SDT overflow to rendered chrome
luccas-harbour May 15, 2026
8f2b80c
fix(painters/dom): continue split SDT paragraph chrome
luccas-harbour May 15, 2026
738fcd3
refactor(painters/dom): extract SDT helpers from renderer
luccas-harbour May 15, 2026
22ce0ff
refactor(painters/dom): unify image block rendering
luccas-harbour May 15, 2026
8a2059c
fix(painters/dom): invalidate table image visual edits
luccas-harbour May 15, 2026
01c2e2f
docs(layout-engine): flag SdtMetadata identity invariant for pm-adapter
luccas-harbour May 21, 2026
112234f
refactor(painters/dom): drop unused block version derivation
luccas-harbour May 15, 2026
6871e02
fix(layout-resolved): invalidate inline image visual edits
luccas-harbour May 15, 2026
b0be9c8
fix(layout-resolved): hash raw inline image clip paths
luccas-harbour May 15, 2026
b512cb9
refactor(painters/dom): extract image rendering helpers into modules
luccas-harbour May 15, 2026
815af26
fix(layout-resolved): avoid image hyperlink hash collisions
luccas-harbour May 15, 2026
f823bb2
fix(painters/dom): keep table images block display
luccas-harbour May 15, 2026
e586394
test(painters/dom): cover unified drawing image rendering
luccas-harbour May 15, 2026
9491a08
refactor(painters/dom): share image clip path reader
luccas-harbour May 15, 2026
9d2871f
refactor(painters/dom): share inline style applier
luccas-harbour May 15, 2026
6e71691
docs(painters/dom): preserve image transform rationale
luccas-harbour May 15, 2026
6100449
refactor(painters/dom): share image hyperlink anchor type
luccas-harbour May 15, 2026
77c811e
refactor(painters/dom): co-locate image utils under images/
luccas-harbour May 15, 2026
dabfe32
docs(layout-resolved): clarify deriveBlockVersion no longer duplicated
luccas-harbour May 21, 2026
f2e4dcb
Merge pull request #3328 from superdoc-dev/luccas/sd-2838-unify-image…
harbournick May 26, 2026
e01b30e
Merge pull request #3322 from superdoc-dev/luccas/sd-2838-unify-sdt-r…
harbournick May 26, 2026
2bf27fa
Merge pull request #3309 from superdoc-dev/luccas/sd-2838-unify-parag…
harbournick May 26, 2026
fa6b1c5
Merge branch 'main' into luccas/sd-2851-remove-list-item-code-from-pa…
harbournick May 26, 2026
1e31aa7
Merge branch 'main' into luccas/sd-2851-remove-list-item-code-from-pa…
harbournick May 26, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8,357 changes: 3,764 additions & 4,593 deletions apps/mcp/src/generated/catalog.ts

Large diffs are not rendered by default.

207 changes: 138 additions & 69 deletions apps/mcp/src/generated/intent-dispatch.generated.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,117 +10,186 @@ export function dispatchIntentTool(
case 'superdoc_get_content': {
const { action, ...rest } = args;
switch (action) {
case 'text': return execute('doc.getText', rest);
case 'markdown': return execute('doc.getMarkdown', rest);
case 'html': return execute('doc.getHtml', rest);
case 'info': return execute('doc.info', rest);
case 'extract': return execute('doc.extract', rest);
case 'blocks': return execute('doc.blocks.list', rest);
default: throw new Error(`Unknown action for superdoc_get_content: ${action}`);
case 'text':
return execute('doc.getText', rest);
case 'markdown':
return execute('doc.getMarkdown', rest);
case 'html':
return execute('doc.getHtml', rest);
case 'info':
return execute('doc.info', rest);
case 'extract':
return execute('doc.extract', rest);
case 'blocks':
return execute('doc.blocks.list', rest);
default:
throw new Error(`Unknown action for superdoc_get_content: ${action}`);
}
}
case 'superdoc_edit': {
const { action, ...rest } = args;
switch (action) {
case 'insert': return execute('doc.insert', rest);
case 'replace': return execute('doc.replace', rest);
case 'delete': return execute('doc.delete', rest);
case 'undo': return execute('doc.history.undo', rest);
case 'redo': return execute('doc.history.redo', rest);
default: throw new Error(`Unknown action for superdoc_edit: ${action}`);
case 'insert':
return execute('doc.insert', rest);
case 'replace':
return execute('doc.replace', rest);
case 'delete':
return execute('doc.delete', rest);
case 'undo':
return execute('doc.history.undo', rest);
case 'redo':
return execute('doc.history.redo', rest);
default:
throw new Error(`Unknown action for superdoc_edit: ${action}`);
}
}
case 'superdoc_format': {
const { action, ...rest } = args;
switch (action) {
case 'inline': return execute('doc.format.apply', rest);
case 'set_style': return execute('doc.styles.paragraph.setStyle', rest);
case 'set_alignment': return execute('doc.format.paragraph.setAlignment', rest);
case 'set_indentation': return execute('doc.format.paragraph.setIndentation', rest);
case 'set_spacing': return execute('doc.format.paragraph.setSpacing', rest);
case 'set_flow_options': return execute('doc.format.paragraph.setFlowOptions', rest);
case 'set_direction': return execute('doc.format.paragraph.setDirection', rest);
default: throw new Error(`Unknown action for superdoc_format: ${action}`);
case 'inline':
return execute('doc.format.apply', rest);
case 'set_style':
return execute('doc.styles.paragraph.setStyle', rest);
case 'set_alignment':
return execute('doc.format.paragraph.setAlignment', rest);
case 'set_indentation':
return execute('doc.format.paragraph.setIndentation', rest);
case 'set_spacing':
return execute('doc.format.paragraph.setSpacing', rest);
case 'set_flow_options':
return execute('doc.format.paragraph.setFlowOptions', rest);
case 'set_direction':
return execute('doc.format.paragraph.setDirection', rest);
default:
throw new Error(`Unknown action for superdoc_format: ${action}`);
}
}
case 'superdoc_create': {
const { action, ...rest } = args;
switch (action) {
case 'paragraph': return execute('doc.create.paragraph', rest);
case 'heading': return execute('doc.create.heading', rest);
case 'table': return execute('doc.create.table', rest);
default: throw new Error(`Unknown action for superdoc_create: ${action}`);
case 'paragraph':
return execute('doc.create.paragraph', rest);
case 'heading':
return execute('doc.create.heading', rest);
case 'table':
return execute('doc.create.table', rest);
default:
throw new Error(`Unknown action for superdoc_create: ${action}`);
}
}
case 'superdoc_list': {
const { action, ...rest } = args;
switch (action) {
case 'insert': return execute('doc.lists.insert', rest);
case 'create': return execute('doc.lists.create', rest);
case 'attach': return execute('doc.lists.attach', rest);
case 'detach': return execute('doc.lists.detach', rest);
case 'delete': return execute('doc.lists.delete', rest);
case 'indent': return execute('doc.lists.indent', rest);
case 'outdent': return execute('doc.lists.outdent', rest);
case 'merge': return execute('doc.lists.merge', rest);
case 'split': return execute('doc.lists.split', rest);
case 'set_level': return execute('doc.lists.setLevel', rest);
case 'set_value': return execute('doc.lists.setValue', rest);
case 'continue_previous': return execute('doc.lists.continuePrevious', rest);
case 'set_type': return execute('doc.lists.setType', rest);
default: throw new Error(`Unknown action for superdoc_list: ${action}`);
case 'insert':
return execute('doc.lists.insert', rest);
case 'create':
return execute('doc.lists.create', rest);
case 'attach':
return execute('doc.lists.attach', rest);
case 'detach':
return execute('doc.lists.detach', rest);
case 'delete':
return execute('doc.lists.delete', rest);
case 'indent':
return execute('doc.lists.indent', rest);
case 'outdent':
return execute('doc.lists.outdent', rest);
case 'merge':
return execute('doc.lists.merge', rest);
case 'split':
return execute('doc.lists.split', rest);
case 'set_level':
return execute('doc.lists.setLevel', rest);
case 'set_value':
return execute('doc.lists.setValue', rest);
case 'continue_previous':
return execute('doc.lists.continuePrevious', rest);
case 'set_type':
return execute('doc.lists.setType', rest);
default:
throw new Error(`Unknown action for superdoc_list: ${action}`);
}
}
case 'superdoc_comment': {
const { action, ...rest } = args;
switch (action) {
case 'create': return execute('doc.comments.create', rest);
case 'update': return execute('doc.comments.patch', rest);
case 'delete': return execute('doc.comments.delete', rest);
case 'get': return execute('doc.comments.get', rest);
case 'list': return execute('doc.comments.list', rest);
default: throw new Error(`Unknown action for superdoc_comment: ${action}`);
case 'create':
return execute('doc.comments.create', rest);
case 'update':
return execute('doc.comments.patch', rest);
case 'delete':
return execute('doc.comments.delete', rest);
case 'get':
return execute('doc.comments.get', rest);
case 'list':
return execute('doc.comments.list', rest);
default:
throw new Error(`Unknown action for superdoc_comment: ${action}`);
}
}
case 'superdoc_track_changes': {
const { action, ...rest } = args;
switch (action) {
case 'list': return execute('doc.trackChanges.list', rest);
case 'decide': return execute('doc.trackChanges.decide', rest);
default: throw new Error(`Unknown action for superdoc_track_changes: ${action}`);
case 'list':
return execute('doc.trackChanges.list', rest);
case 'decide':
return execute('doc.trackChanges.decide', rest);
default:
throw new Error(`Unknown action for superdoc_track_changes: ${action}`);
}
}
case 'superdoc_search':
return execute('doc.query.match', args);
case 'superdoc_mutations': {
const { action, ...rest } = args;
switch (action) {
case 'preview': return execute('doc.mutations.preview', rest);
case 'apply': return execute('doc.mutations.apply', rest);
default: throw new Error(`Unknown action for superdoc_mutations: ${action}`);
case 'preview':
return execute('doc.mutations.preview', rest);
case 'apply':
return execute('doc.mutations.apply', rest);
default:
throw new Error(`Unknown action for superdoc_mutations: ${action}`);
}
}
case 'superdoc_table': {
const { action, ...rest } = args;
switch (action) {
case 'delete': return execute('doc.tables.delete', rest);
case 'set_layout': return execute('doc.tables.setLayout', rest);
case 'insert_row': return execute('doc.tables.insertRow', rest);
case 'delete_row': return execute('doc.tables.deleteRow', rest);
case 'set_row': return execute('doc.tables.setRowHeight', rest);
case 'set_row_options': return execute('doc.tables.setRowOptions', rest);
case 'insert_column': return execute('doc.tables.insertColumn', rest);
case 'delete_column': return execute('doc.tables.deleteColumn', rest);
case 'set_column': return execute('doc.tables.setColumnWidth', rest);
case 'merge_cells': return execute('doc.tables.mergeCells', rest);
case 'unmerge_cells': return execute('doc.tables.unmergeCells', rest);
case 'set_cell': return execute('doc.tables.setCellProperties', rest);
case 'set_cell_text': return execute('doc.tables.setCellText', rest);
case 'set_shading': return execute('doc.tables.setShading', rest);
case 'set_style_options': return execute('doc.tables.applyStyle', rest);
case 'set_borders': return execute('doc.tables.setBorders', rest);
case 'set_options': return execute('doc.tables.setTableOptions', rest);
default: throw new Error(`Unknown action for superdoc_table: ${action}`);
case 'delete':
return execute('doc.tables.delete', rest);
case 'set_layout':
return execute('doc.tables.setLayout', rest);
case 'insert_row':
return execute('doc.tables.insertRow', rest);
case 'delete_row':
return execute('doc.tables.deleteRow', rest);
case 'set_row':
return execute('doc.tables.setRowHeight', rest);
case 'set_row_options':
return execute('doc.tables.setRowOptions', rest);
case 'insert_column':
return execute('doc.tables.insertColumn', rest);
case 'delete_column':
return execute('doc.tables.deleteColumn', rest);
case 'set_column':
return execute('doc.tables.setColumnWidth', rest);
case 'merge_cells':
return execute('doc.tables.mergeCells', rest);
case 'unmerge_cells':
return execute('doc.tables.unmergeCells', rest);
case 'set_cell':
return execute('doc.tables.setCellProperties', rest);
case 'set_cell_text':
return execute('doc.tables.setCellText', rest);
case 'set_shading':
return execute('doc.tables.setShading', rest);
case 'set_style_options':
return execute('doc.tables.applyStyle', rest);
case 'set_borders':
return execute('doc.tables.setBorders', rest);
case 'set_options':
return execute('doc.tables.setTableOptions', rest);
default:
throw new Error(`Unknown action for superdoc_table: ${action}`);
}
}
default:
Expand Down
2 changes: 2 additions & 0 deletions packages/layout-engine/AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ reads.
| Change style resolution | `style-engine/` |
| Change text measurement | `measuring-dom/` |

AIDEV-NOTE: `pm-adapter` must preserve shared `SdtMetadata` object identity for sibling blocks in one id-less SDT container; see `contracts/src/sdt-container.ts` before changing SDT imports.

## Style Engine (`style-engine/`)

Single source of truth for OOXML style cascade resolution. All property resolution flows through here.
Expand Down
7 changes: 7 additions & 0 deletions packages/layout-engine/contracts/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,13 @@ export type {
import type { LayoutSourceIdentity } from './layout-identity.js';
export { cloneColumnLayout, normalizeColumnLayout, widthsEqual } from './column-layout.js';
export type { NormalizedColumnLayout } from './column-layout.js';
export {
getSdtContainerKey,
getSdtContainerKeyForBlock,
getSdtContainerMetadata,
hasExplicitSdtContainerKey,
isSdtContainerMetadata,
} from './sdt-container.js';
/** Inline field annotation metadata extracted from w:sdt nodes. */
export type FieldAnnotationMetadata = {
type: 'fieldAnnotation';
Expand Down
42 changes: 42 additions & 0 deletions packages/layout-engine/contracts/src/sdt-container.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { describe, expect, it } from 'vitest';
import type { SdtMetadata } from './index.js';
import {
getSdtContainerKey,
getSdtContainerKeyForBlock,
getSdtContainerMetadata,
hasExplicitSdtContainerKey,
} from './sdt-container.js';

describe('SDT container key helpers', () => {
it('uses the first renderable container metadata', () => {
const containerSdt: SdtMetadata = { type: 'documentSection', id: 'section-1' };

expect(getSdtContainerMetadata({ type: 'structuredContent', scope: 'inline', id: 'inline-1' }, containerSdt)).toBe(
containerSdt,
);
});

it('derives explicit keys for block content controls and document sections', () => {
expect(getSdtContainerKey({ type: 'structuredContent', scope: 'block', id: 'sdt-1' })).toBe(
'structuredContent:sdt-1',
);
expect(getSdtContainerKey({ type: 'documentSection', sdBlockId: 'section-block-1' })).toBe(
'documentSection:section-block-1',
);
});

it('derives stable object keys for id-less containers', () => {
const sharedSdt: SdtMetadata = { type: 'structuredContent', scope: 'block', alias: 'Shared' };
const firstKey = getSdtContainerKey(sharedSdt);

expect(firstKey).toMatch(/^idlessSdt:/);
expect(getSdtContainerKey(sharedSdt)).toBe(firstKey);
expect(hasExplicitSdtContainerKey(sharedSdt)).toBe(false);
});

it('derives keys from any block-like object with SDT attrs', () => {
const sdt: SdtMetadata = { type: 'structuredContent', scope: 'block', id: 'media-sdt' };

expect(getSdtContainerKeyForBlock({ attrs: { sdt } })).toBe('structuredContent:media-sdt');
});
});
Loading
Loading