@pixerate/editor 0.223.2 → 0.223.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (24) hide show
  1. package/dist/tools/skill-evals.d.cts +6 -1
  2. package/dist/tools/skill-evals.d.ts +6 -1
  3. package/package.json +1 -1
  4. package/skills/README.md +6 -1
  5. package/skills/pixerate-diagram/SKILL.md +8 -0
  6. package/skills/pixerate-diagram-architecture/SKILL.md +104 -0
  7. package/skills/pixerate-diagram-architecture/evals/label-protocols.json +62 -0
  8. package/skills/pixerate-diagram-architecture/evals/trust-boundaries.json +64 -0
  9. package/skills/pixerate-diagram-architecture/evals/web-app.json +56 -0
  10. package/skills/pixerate-diagram-process-flow/SKILL.md +99 -0
  11. package/skills/pixerate-diagram-process-flow/evals/order-process.json +73 -0
  12. package/skills/pixerate-diagram-process-flow/evals/swimlanes.json +74 -0
  13. package/skills/pixerate-diagram-process-flow/evals/tidy-decision.json +76 -0
  14. package/skills/pixerate-image-photo-correction/evals/neutralise-cast.json +2 -2
  15. package/skills/pixerate-image-product-photo/evals/grounding-shadow.json +1 -1
  16. package/skills/pixerate-rich-text/SKILL.md +8 -0
  17. package/skills/pixerate-rich-text-report/SKILL.md +98 -0
  18. package/skills/pixerate-rich-text-report/evals/heading-case.json +48 -0
  19. package/skills/pixerate-rich-text-report/evals/results-table.json +93 -0
  20. package/skills/pixerate-rich-text-report/evals/structure.json +106 -0
  21. package/skills/pixerate-rich-text-revise/SKILL.md +92 -0
  22. package/skills/pixerate-rich-text-revise/evals/fix-typos.json +57 -0
  23. package/skills/pixerate-rich-text-revise/evals/rename-term.json +51 -0
  24. package/skills/pixerate-rich-text-revise/evals/tighten-intro.json +55 -0
@@ -0,0 +1,76 @@
1
+ {
2
+ "prompt": "The decision in this flowchart is hard to read: the condition and the outcomes are crammed into the node. Tidy it up.",
3
+ "fixture": {
4
+ "editor": "diagram",
5
+ "setup": [
6
+ {
7
+ "tool": "load_diagram_mermaid",
8
+ "args": {
9
+ "source": "flowchart LR\n check{Has the payment been received? If yes ship, otherwise remind} --> ship[Ship order]\n check --> remind[Send reminder]"
10
+ }
11
+ }
12
+ ]
13
+ },
14
+ "checks": [
15
+ {
16
+ "why": "a short question in the decision (at most six words)",
17
+ "tool": "get_diagram",
18
+ "expect": {
19
+ "nodes": {
20
+ "$some": {
21
+ "id": "check",
22
+ "shape": "diam",
23
+ "label": {
24
+ "$expr": "v.trim().split(/\\s+/).length <= 6 && /\\?$/.test(v.trim())"
25
+ }
26
+ }
27
+ }
28
+ }
29
+ },
30
+ {
31
+ "why": "the outcomes are on the edges",
32
+ "tool": "get_diagram",
33
+ "expect": {
34
+ "edges": {
35
+ "$every": {
36
+ "label": {
37
+ "$match": [
38
+ "^(yes|no|paid|unpaid|received|not received)$",
39
+ "i"
40
+ ]
41
+ }
42
+ }
43
+ }
44
+ }
45
+ }
46
+ ],
47
+ "solution": [
48
+ {
49
+ "tool": "rename_diagram_node",
50
+ "args": {
51
+ "id": "check",
52
+ "label": "Payment received?"
53
+ }
54
+ },
55
+ {
56
+ "tool": "set_diagram_edge_label",
57
+ "args": {
58
+ "id": {
59
+ "$read": "get_diagram",
60
+ "path": "edges.0.id"
61
+ },
62
+ "label": "yes"
63
+ }
64
+ },
65
+ {
66
+ "tool": "set_diagram_edge_label",
67
+ "args": {
68
+ "id": {
69
+ "$read": "get_diagram",
70
+ "path": "edges.1.id"
71
+ },
72
+ "label": "no"
73
+ }
74
+ }
75
+ ]
76
+ }
@@ -12,9 +12,9 @@
12
12
  },
13
13
  "checks": [
14
14
  { "why": "the grey card is neutral (cast within ±4 levels)", "tool": "measure_region", "args": { "x": 12, "y": 52, "width": 16, "height": 16 }, "expect": { "cast": { "redBlue": { "$min": -4, "$max": 4 }, "greenMagenta": { "$min": -4, "$max": 4 } } } },
15
- { "why": "the card is a mid grey, not crushed or blown", "tool": "measure_region", "args": { "x": 12, "y": 52, "width": 16, "height": 16 }, "expect": { "stats": { "luminance": { "mean": { "$min": 90, "$max": 170 } } } } },
15
+ { "why": "the card stays a mid grey, not crushed or blown (the task asks for neither brighter nor darker)", "tool": "measure_region", "args": { "x": 12, "y": 52, "width": 16, "height": 16 }, "expect": { "stats": { "luminance": { "mean": { "$min": 60, "$max": 200 } } } } },
16
16
  { "why": "no channel clips anywhere", "tool": "measure_region", "expect": { "clipping": { "highlightsPercent": { "red": { "$max": 0.5 }, "green": { "$max": 0.5 }, "blue": { "$max": 0.5 } }, "shadowsPercent": { "red": { "$max": 0.5 }, "green": { "$max": 0.5 }, "blue": { "$max": 0.5 } } } } },
17
- { "why": "the correction is a layer, not baked into the photo", "tool": "list_layers", "expect": { "layers": { "$some": { "type": "adjustment" } } } }
17
+ { "why": "the correction stays adjustable: an adjustment layer or the base white balance (the develop filter), not baked into the photo", "tool": "list_layers", "expect": { "$expr": "v.layers.some((l) => l.type === 'adjustment' || (l.filters || []).some((f) => f.kind === 'develop' && (f.temperature || f.tint)))" } }
18
18
  ],
19
19
  "solution": [
20
20
  { "tool": "measure_region", "args": { "x": 12, "y": 52, "width": 16, "height": 16 } },
@@ -8,7 +8,7 @@
8
8
  "shapes": [{ "shape": "rect", "x": 40, "y": 25, "width": 40, "height": 40, "color": [30, 90, 160] }]
9
9
  },
10
10
  "checks": [
11
- { "why": "the product is on its own layer, cut to its shape", "tool": "list_layers", "expect": { "layers": { "$some": { "type": "pixel", "bounds": { "x": { "$min": 39, "$max": 41 }, "y": { "$min": 24, "$max": 26 }, "width": { "$min": 39, "$max": 42 }, "height": { "$min": 39, "$max": 42 } } } } } },
11
+ { "why": "the product is on its own layer, cut to its shape: by its pixels, or by its mask (masked, not erased)", "tool": "list_layers", "expect": { "layers": { "$some": { "type": "pixel", "$in": [{ "bounds": { "x": { "$min": 39, "$max": 41 }, "y": { "$min": 24, "$max": 26 }, "width": { "$min": 39, "$max": 42 }, "height": { "$min": 39, "$max": 42 } } }, { "mask": { "paintedBounds": { "x": { "$min": 39, "$max": 41 }, "y": { "$min": 24, "$max": 26 }, "width": { "$min": 39, "$max": 42 }, "height": { "$min": 39, "$max": 42 } } } }] } } } },
12
12
  { "why": "a live drop shadow on that layer", "tool": "list_layers", "expect": { "layers": { "$some": { "effects": { "$expr": "v && JSON.stringify(v).includes('drop-shadow')" } } } } }
13
13
  ],
14
14
  "solution": [
@@ -21,6 +21,14 @@ Errors, namespacing (`doc-1__find_text`) and `run_commands` batching are covered
21
21
  `pixerate-agent-tools` skill. Chart type, axis and colour choices are covered by
22
22
  `pixerate-chart`; the same spec fields apply to charts in a document.
23
23
 
24
+ ## Workflow skills
25
+
26
+ For these jobs, load the workflow skill too: it has the method, the checks between steps and
27
+ the pitfalls, and uses the tools below.
28
+
29
+ - `pixerate-rich-text-report`: a title and heading hierarchy, lists, tables, charts and a consistency pass.
30
+ - `pixerate-rich-text-revise`: proofreading, renaming terms with exceptions, tightening, minimal edits.
31
+
24
32
  ## Working method
25
33
 
26
34
  1. **Read.** `get_text` (`format: "markdown"` shows headings, lists and tables compactly;
@@ -0,0 +1,98 @@
1
+ ---
2
+ name: pixerate-rich-text-report
3
+ description: The report and structured document workflow in the Pixerate rich text editor - outlining before writing, one title and a heading hierarchy, consistent heading case, short paragraphs, lists for steps and items, tables for comparisons, charts in the document, and a final read-through for structure and consistency. Use when asked to write, structure, format, outline or tidy a report, memo, proposal, brief, article, documentation page or meeting notes, add headings, lists or a table, or make a document consistent, or when get_text, set_block_type, edit_table or insert_chart are available. Load with pixerate-rich-text, which lists every tool.
4
+ metadata:
5
+ kind: workflow
6
+ reference: pixerate-rich-text
7
+ ---
8
+
9
+ # Structuring a report
10
+
11
+ A report is read by skimming first: the title, the headings and the first lines decide whether
12
+ anyone reads the rest. So the structure carries the message: one title, sections with headings
13
+ one level below, steps and items as lists, comparisons as tables, figures as charts. Get the
14
+ structure right, then the words, then check consistency.
15
+
16
+ This skill is the method. `pixerate-rich-text` has the full tool reference; positions come from
17
+ `get_text` with `blocks: true` or from `find_text`, never from counting characters.
18
+
19
+ ## Goal and quality bar
20
+
21
+ - One `heading` level 1 for the title; sections at level 2, subsections at level 3; no skipped
22
+ levels.
23
+ - Headings consistent in case (sentence case unless the house style says otherwise) and short.
24
+ - Steps as an ordered list, items as a bulleted list; comparisons with more than two attributes
25
+ as a table with a header row; numbers that show a trend as a chart.
26
+ - Short paragraphs, each with one point; the summary first.
27
+ - Nothing the author wrote is lost unless they asked for it to go.
28
+
29
+ ## Inputs to confirm
30
+
31
+ - **Purpose and reader:** what decision or knowledge the document serves.
32
+ - **Sections** the user expects, or a template.
33
+ - **House style:** heading case, numbering, how dates and numbers are written.
34
+
35
+ ## Working method
36
+
37
+ 1. **Read.** `get_text` with `blocks: true`: every block's `type`, `from`, `to` and `text`.
38
+ **Check:** you can name the title, the sections and the body of each.
39
+ 2. **Outline.** Decide the heading hierarchy and which runs of paragraphs are really lists or
40
+ tables before changing anything.
41
+ 3. **Set the structure** with `set_block_type` on each block's range: `heading` with `level`,
42
+ `"bullet_list"`, `"ordered_list"`. Work from the blocks you read; positions shift when block types
43
+ change, so re-read (`get_text` `blocks`) after changes that add or remove wrapping.
44
+ **Check:** `get_text` `format: "html"` shows `<h1>`, `<h2>`, `<ul>` where you meant.
45
+ 4. **Tables.** `edit_table` `insertTable` (`at` the end of the paragraph it follows, `rows`,
46
+ `cols`, `withHeaderRow`), then `insert_text` into each cell from the last cell to the first so
47
+ earlier positions stay valid (cell positions from `get_text` `blocks`).
48
+ **Check:** the HTML has the header cells and rows in order.
49
+ 5. **Charts** for figures: `insert_chart` with the data; edit with `update_chart_in_document`.
50
+ 6. **Consistency pass.** Heading case, terms, numbers and dates written one way:
51
+ `find_text` to find variants, `replace_text` to fix them (see
52
+ `pixerate-rich-text-revise`).
53
+ **Check:** `find_text` for the old variants returns no matches.
54
+ 7. **Read it through** once as the reader would (`get_text`), and report what changed.
55
+
56
+ ## Decision table
57
+
58
+ | Content | Block |
59
+ | --- | --- |
60
+ | Document title | `heading` level 1 (once) |
61
+ | Section, subsection | `heading` level 2, 3 |
62
+ | Steps in order | `"ordered_list"` |
63
+ | Items, options, takeaways | `"bullet_list"` |
64
+ | Things compared on several attributes | A table with a header row |
65
+ | A trend or comparison of numbers | `insert_chart` |
66
+ | A quotation | `blockquote` |
67
+ | Code or commands | `"code_block"` |
68
+
69
+ ## Recipes
70
+
71
+ **Structure a draft.** `get_text` `blocks` → `set_block_type` title `heading` level 1 → each
72
+ section line `heading` level 2 → each run of item lines `"bullet_list"` (one call over the run's
73
+ range).
74
+
75
+ **A two-column table.** `edit_table` `{ operation: "insertTable", at, rows: 3, cols: 2,
76
+ withHeaderRow: true }` → `get_text` `blocks` for the empty cells → `insert_text` into each cell,
77
+ last first.
78
+
79
+ ## Pitfalls
80
+
81
+ - **Positions from the plain text** are wrong: block boundaries count. Use `blocks` or
82
+ `find_text`.
83
+ - **Stale positions** after a change that adds a list or table; re-read before the next edit.
84
+ - **Several level-1 headings** flatten the outline; one title only.
85
+ - **Bold paragraphs as headings** do not appear in the outline or navigation; use headings.
86
+ - **Tables for prose** or one-column tables; use paragraphs or lists.
87
+ - **Rewriting the author's words** while restructuring; change structure, not content, unless
88
+ asked.
89
+
90
+ ## Tools used
91
+
92
+ - `get_text`, `find_text`: read the document, its blocks and positions
93
+ - `set_block_type`, `set_text_align`: headings, lists and alignment
94
+ - `format_text`: emphasis and links
95
+ - `edit_table`: insert and shape tables
96
+ - `insert_text`, `replace_range`, `replace_text`: fill cells, write and fix text
97
+ - `insert_chart`, `update_chart_in_document`, `list_document_charts`: charts in the document
98
+ - `undo_rich_text`: take back a step
@@ -0,0 +1,48 @@
1
+ {
2
+ "prompt": "The section headings are inconsistent. Make them all sentence case (first word capitalised, the rest lower case unless they are names).",
3
+ "fixture": {
4
+ "editor": "rich-text",
5
+ "html": "<h1>Annual review</h1><h2>RESULTS AND Findings</h2><p>Revenue grew.</p><h2>Next Steps For Acme</h2><p>Plan the launch.</p>"
6
+ },
7
+ "checks": [
8
+ {
9
+ "why": "headings in sentence case, keeping the name Acme",
10
+ "tool": "get_text",
11
+ "args": {
12
+ "format": "html"
13
+ },
14
+ "expect": {
15
+ "content": {
16
+ "$expr": "/<h2[^>]*>Results and findings<\\/h2>/.test(v) && /<h2[^>]*>Next steps for Acme<\\/h2>/.test(v)"
17
+ }
18
+ }
19
+ },
20
+ {
21
+ "why": "the body and title are unchanged",
22
+ "tool": "get_text",
23
+ "expect": {
24
+ "content": {
25
+ "$expr": "v.startsWith('Annual review') && v.includes('Revenue grew.') && v.includes('Plan the launch.')"
26
+ }
27
+ }
28
+ }
29
+ ],
30
+ "solution": [
31
+ {
32
+ "tool": "replace_text",
33
+ "args": {
34
+ "find": "RESULTS AND Findings",
35
+ "replace": "Results and findings",
36
+ "matchCase": true
37
+ }
38
+ },
39
+ {
40
+ "tool": "replace_text",
41
+ "args": {
42
+ "find": "Next Steps For Acme",
43
+ "replace": "Next steps for Acme",
44
+ "matchCase": true
45
+ }
46
+ }
47
+ ]
48
+ }
@@ -0,0 +1,93 @@
1
+ {
2
+ "prompt": "Under 'Sales by region:', add a table with a header row (Region, Sales) and two rows: North 120 and South 95.",
3
+ "fixture": {
4
+ "editor": "rich-text",
5
+ "html": "<h2>Results</h2><p>Sales by region:</p><h2>Next steps</h2>"
6
+ },
7
+ "checks": [
8
+ {
9
+ "why": "a table with a header row and the two regions",
10
+ "tool": "get_text",
11
+ "args": {
12
+ "format": "html"
13
+ },
14
+ "expect": {
15
+ "content": {
16
+ "$match": "<table[^>]*>.*<th[^>]*><p>Region</p></th><th[^>]*><p>Sales</p></th>.*<td[^>]*><p>North</p></td><td[^>]*><p>120</p></td>.*<td[^>]*><p>South</p></td><td[^>]*><p>95</p></td>.*</table>"
17
+ }
18
+ }
19
+ },
20
+ {
21
+ "why": "placed after 'Sales by region:' and before the next section",
22
+ "tool": "get_text",
23
+ "args": {
24
+ "format": "html"
25
+ },
26
+ "expect": {
27
+ "content": {
28
+ "$match": "Sales by region:</p><table.*</table><h2[^>]*>Next steps"
29
+ }
30
+ }
31
+ }
32
+ ],
33
+ "solution": [
34
+ {
35
+ "tool": "get_text",
36
+ "args": {
37
+ "blocks": true
38
+ }
39
+ },
40
+ {
41
+ "tool": "edit_table",
42
+ "args": {
43
+ "operation": "insertTable",
44
+ "at": 26,
45
+ "rows": 3,
46
+ "cols": 2,
47
+ "withHeaderRow": true
48
+ }
49
+ },
50
+ {
51
+ "tool": "insert_text",
52
+ "args": {
53
+ "text": "95",
54
+ "at": 55
55
+ }
56
+ },
57
+ {
58
+ "tool": "insert_text",
59
+ "args": {
60
+ "text": "South",
61
+ "at": 51
62
+ }
63
+ },
64
+ {
65
+ "tool": "insert_text",
66
+ "args": {
67
+ "text": "120",
68
+ "at": 45
69
+ }
70
+ },
71
+ {
72
+ "tool": "insert_text",
73
+ "args": {
74
+ "text": "North",
75
+ "at": 41
76
+ }
77
+ },
78
+ {
79
+ "tool": "insert_text",
80
+ "args": {
81
+ "text": "Sales",
82
+ "at": 35
83
+ }
84
+ },
85
+ {
86
+ "tool": "insert_text",
87
+ "args": {
88
+ "text": "Region",
89
+ "at": 31
90
+ }
91
+ }
92
+ ]
93
+ }
@@ -0,0 +1,106 @@
1
+ {
2
+ "prompt": "Turn this into a properly structured report: the first line is the title, 'Summary', 'Results' and 'Next steps' are section headings, and the next steps should be a bulleted list.",
3
+ "fixture": {
4
+ "editor": "rich-text",
5
+ "html": "<p>Quarterly report</p><p>Summary</p><p>Sales grew in every region.</p><p>Results</p><p>North led with 120 orders.</p><p>Next steps</p><p>Hire two engineers</p><p>Launch in May</p>"
6
+ },
7
+ "checks": [
8
+ {
9
+ "why": "the title is the top heading",
10
+ "tool": "get_text",
11
+ "args": {
12
+ "format": "html"
13
+ },
14
+ "expect": {
15
+ "content": {
16
+ "$match": "^<h1[^>]*>Quarterly report</h1>"
17
+ }
18
+ }
19
+ },
20
+ {
21
+ "why": "the three sections are headings one level below",
22
+ "tool": "get_text",
23
+ "args": {
24
+ "format": "html"
25
+ },
26
+ "expect": {
27
+ "content": {
28
+ "$expr": "['Summary', 'Results', 'Next steps'].every((t) => new RegExp('<h2[^>]*>' + t + '</h2>').test(v))"
29
+ }
30
+ }
31
+ },
32
+ {
33
+ "why": "the next steps are a bulleted list",
34
+ "tool": "get_text",
35
+ "args": {
36
+ "format": "html"
37
+ },
38
+ "expect": {
39
+ "content": {
40
+ "$match": "<ul[^>]*><li[^>]*><p>Hire two engineers</p></li><li[^>]*><p>Launch in May</p></li></ul>"
41
+ }
42
+ }
43
+ },
44
+ {
45
+ "why": "the body text is kept",
46
+ "tool": "get_text",
47
+ "expect": {
48
+ "content": {
49
+ "$expr": "v.includes('Sales grew in every region.') && v.includes('North led with 120 orders.')"
50
+ }
51
+ }
52
+ }
53
+ ],
54
+ "solution": [
55
+ {
56
+ "tool": "get_text",
57
+ "args": {
58
+ "blocks": true
59
+ }
60
+ },
61
+ {
62
+ "tool": "set_block_type",
63
+ "args": {
64
+ "from": 1,
65
+ "to": 17,
66
+ "type": "heading",
67
+ "level": 1
68
+ }
69
+ },
70
+ {
71
+ "tool": "set_block_type",
72
+ "args": {
73
+ "from": 19,
74
+ "to": 26,
75
+ "type": "heading",
76
+ "level": 2
77
+ }
78
+ },
79
+ {
80
+ "tool": "set_block_type",
81
+ "args": {
82
+ "from": 56,
83
+ "to": 63,
84
+ "type": "heading",
85
+ "level": 2
86
+ }
87
+ },
88
+ {
89
+ "tool": "set_block_type",
90
+ "args": {
91
+ "from": 93,
92
+ "to": 103,
93
+ "type": "heading",
94
+ "level": 2
95
+ }
96
+ },
97
+ {
98
+ "tool": "set_block_type",
99
+ "args": {
100
+ "from": 105,
101
+ "to": 134,
102
+ "type": "bullet_list"
103
+ }
104
+ }
105
+ ]
106
+ }
@@ -0,0 +1,92 @@
1
+ ---
2
+ name: pixerate-rich-text-revise
3
+ description: The revision workflow in the Pixerate rich text editor - proofreading for spelling and grammar, renaming a term consistently while leaving quotations and names alone, tightening wordy passages, unifying how numbers, dates and terms are written, and making minimal, targeted edits that keep the author's formatting and voice, with a check that nothing else changed. Use when asked to proofread, copy-edit, revise, tighten, shorten, fix typos, rename or replace a term throughout, make wording consistent or polish a document, or when find_text, replace_text and replace_range are available. Load with pixerate-rich-text, which lists every tool.
4
+ metadata:
5
+ kind: workflow
6
+ reference: pixerate-rich-text
7
+ ---
8
+
9
+ # Revising a document
10
+
11
+ Revision changes as little as possible to make the document right: each fix is a targeted
12
+ replacement of the words that are wrong, so formatting, links and the author's voice survive.
13
+ Find before replacing, decide which matches should change (a quotation, a name or a published
14
+ title often should not), and check afterwards that only what you meant changed.
15
+
16
+ This skill is the method. `pixerate-rich-text` has the full tool reference.
17
+
18
+ ## Goal and quality bar
19
+
20
+ - Every error the user asked about is fixed (`find_text` for it returns no matches).
21
+ - Only the intended text changed: the rest of the document reads exactly as before.
22
+ - Replacements respect case (`Teh` becomes `The`), whole words (`teh` but not `tehran`) and
23
+ exceptions (quotations, names, titles of published works).
24
+ - Tightened passages keep their point and the author's voice; nothing is added that was not
25
+ there.
26
+ - Formatting (bold, links, headings, lists) is untouched by text fixes.
27
+
28
+ ## Inputs to confirm
29
+
30
+ - **Scope:** spelling only, grammar and style, or a rewrite of named passages.
31
+ - **Exceptions:** text that must stay as written (quotes, legal text, product names, titles).
32
+ - **House style:** spelling variant (UK or US), how numbers and dates are written.
33
+
34
+ ## Working method
35
+
36
+ 1. **Read.** `get_text` (with `blocks: true` for positions).
37
+ **Check:** you have a list of fixes with the exact wrong text and the right text.
38
+ 2. **Find before replacing.** `find_text` for each term (`wholeWord`, `matchCase`, or `regex`
39
+ for families of errors); read the matches in context and decide which change.
40
+ **Check:** the match count is what you expect; note the occurrences to leave alone.
41
+ 3. **Replace in one call per fix.** `replace_text` with `find`, `replace`, `wholeWord: true`;
42
+ `matchCase: true` with one call per capitalisation (`teh` and `Teh`); `occurrence` for only
43
+ some matches, working from the last occurrence to the first so the numbering holds.
44
+ **Check:** `find_text` for the wrong text returns no matches (except the exceptions).
45
+ 4. **Rewrite a passage** with `replace_range` over exactly its range (`from` / `to` of the block
46
+ or a `find_text` match), keeping the surrounding text.
47
+ **Check:** `get_text` `blocks`: the other blocks' text is unchanged.
48
+ 5. **Consistency.** Terms, numbers and dates one way: `find_text` with a `regex` for the
49
+ variants, then `replace_text`.
50
+ 6. **Report** the fixes made, the matches you left and why.
51
+
52
+ ## Decision table
53
+
54
+ | Fix | Tool and settings |
55
+ | --- | --- |
56
+ | A misspelling everywhere | `replace_text`, `wholeWord: true`, one call per capitalisation with `matchCase` |
57
+ | Rename a term, with exceptions | `find_text`, then `replace_text` with `occurrence` per change, last first |
58
+ | A family of variants (e-mail, email, E-mail) | `find_text` / `replace_text` with `regex: true` |
59
+ | Rewrite a sentence or paragraph | `replace_range` over its exact range |
60
+ | Insert a missing word | `insert_text` at the position from `find_text` |
61
+ | Formatting only | `format_text` on the range; leave the words |
62
+
63
+ ## Recipes
64
+
65
+ **Typos.** `replace_text` `{ find: "recieve", replace: "receive", wholeWord: true }`; for a word
66
+ that starts sentences, `{ find: "Teh", replace: "The", matchCase: true, wholeWord: true }` and
67
+ the same in lower case.
68
+
69
+ **Rename except a quotation.** `find_text` "Acme Cloud" lists three matches; the second is in a
70
+ quoted title: `replace_text` with `occurrence: 3`, then `occurrence: 1`.
71
+
72
+ **Tighten the intro.** `get_text` `blocks` → `replace_range` `{ from: blocks[0].from, to:
73
+ blocks[0].to, text }` with one sentence.
74
+
75
+ ## Pitfalls
76
+
77
+ - **Case-insensitive replace** turns `Teh` into `the` at the start of a sentence; match case.
78
+ - **Partial words**: without `wholeWord`, fixing `teh` breaks words containing it.
79
+ - **Changing quotations, names or published titles** that must stay as written.
80
+ - **`occurrence` after an earlier change** counts the remaining matches; replace from the last
81
+ to the first.
82
+ - **Rewriting whole paragraphs** to fix one word loses formatting and links; replace only the
83
+ words.
84
+ - **Adding content** while tightening; keep the author's point and facts.
85
+
86
+ ## Tools used
87
+
88
+ - `get_text`, `find_text`: read the text, blocks, positions and matches
89
+ - `replace_text`: targeted replacements, with case, whole-word, regex and occurrence
90
+ - `replace_range`, `insert_text`: rewrite or insert at exact positions
91
+ - `format_text`: formatting fixes without touching words
92
+ - `undo_rich_text`: take back a step
@@ -0,0 +1,57 @@
1
+ {
2
+ "prompt": "Fix the spelling mistakes in this document without changing anything else.",
3
+ "fixture": {
4
+ "editor": "rich-text",
5
+ "html": "<p>We will recieve the order tomorrow. Teh team is ready.</p><p>Please recieve the parcel and check teh contents.</p>"
6
+ },
7
+ "checks": [
8
+ {
9
+ "why": "no misspellings left",
10
+ "tool": "find_text",
11
+ "args": {
12
+ "query": "\\b(recieve|teh)\\b",
13
+ "regex": true
14
+ },
15
+ "expect": {
16
+ "matches": {
17
+ "$length": 0
18
+ }
19
+ }
20
+ },
21
+ {
22
+ "why": "the text is otherwise unchanged, capitals kept",
23
+ "tool": "get_text",
24
+ "expect": {
25
+ "content": "We will receive the order tomorrow. The team is ready.\nPlease receive the parcel and check the contents."
26
+ }
27
+ }
28
+ ],
29
+ "solution": [
30
+ {
31
+ "tool": "replace_text",
32
+ "args": {
33
+ "find": "recieve",
34
+ "replace": "receive",
35
+ "wholeWord": true
36
+ }
37
+ },
38
+ {
39
+ "tool": "replace_text",
40
+ "args": {
41
+ "find": "Teh",
42
+ "replace": "The",
43
+ "matchCase": true,
44
+ "wholeWord": true
45
+ }
46
+ },
47
+ {
48
+ "tool": "replace_text",
49
+ "args": {
50
+ "find": "teh",
51
+ "replace": "the",
52
+ "matchCase": true,
53
+ "wholeWord": true
54
+ }
55
+ }
56
+ ]
57
+ }
@@ -0,0 +1,51 @@
1
+ {
2
+ "prompt": "We've renamed the product from 'Acme Cloud' to 'Acme Platform'. Update the document, but leave the title of the 2019 press release (in quotes) as it was published.",
3
+ "fixture": {
4
+ "editor": "rich-text",
5
+ "html": "<p>Acme Cloud now supports teams.</p><p>Our 2019 press release, \u201cIntroducing Acme Cloud\u201d, launched the product.</p><p>Try Acme Cloud today.</p>"
6
+ },
7
+ "checks": [
8
+ {
9
+ "why": "renamed in the running text",
10
+ "tool": "get_text",
11
+ "expect": {
12
+ "content": {
13
+ "$expr": "v.startsWith('Acme Platform now supports teams.') && v.endsWith('Try Acme Platform today.')"
14
+ }
15
+ }
16
+ },
17
+ {
18
+ "why": "the published title is unchanged",
19
+ "tool": "get_text",
20
+ "expect": {
21
+ "content": {
22
+ "$match": "\u201cIntroducing Acme Cloud\u201d"
23
+ }
24
+ }
25
+ }
26
+ ],
27
+ "solution": [
28
+ {
29
+ "tool": "find_text",
30
+ "args": {
31
+ "query": "Acme Cloud"
32
+ }
33
+ },
34
+ {
35
+ "tool": "replace_text",
36
+ "args": {
37
+ "find": "Acme Cloud",
38
+ "replace": "Acme Platform",
39
+ "occurrence": 3
40
+ }
41
+ },
42
+ {
43
+ "tool": "replace_text",
44
+ "args": {
45
+ "find": "Acme Cloud",
46
+ "replace": "Acme Platform",
47
+ "occurrence": 1
48
+ }
49
+ }
50
+ ]
51
+ }