dsh-office-kit 0.4.1 → 0.4.3

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 (116) hide show
  1. package/assets/skills/excel-live-control/SKILL.md +120 -148
  2. package/assets/skills/excel-live-control/container_tools/live_excel.py +9 -0
  3. package/assets/skills/excel-live-control/domain_guidance/financial_models.md +42 -58
  4. package/assets/skills/excel-live-control/domain_guidance/healthcare.md +36 -42
  5. package/assets/skills/excel-live-control/domain_guidance/marketing_advertising.md +33 -34
  6. package/assets/skills/excel-live-control/domain_guidance/scientific_research.md +34 -36
  7. package/assets/skills/excel-live-control/references/office-automation.md +127 -153
  8. package/assets/skills/excel-live-control/references/read_only_qna.md +40 -45
  9. package/assets/skills/excel-live-control/style_guidelines.md +56 -64
  10. package/assets/skills/excel-live-control/workflows/create_workflows.md +40 -47
  11. package/assets/skills/excel-live-control/workflows/edit_workflows.md +37 -45
  12. package/assets/skills/office-documents/SKILL.md +24 -60
  13. package/assets/skills/office-documents/examples/end_to_end_smoke_test.md +5 -5
  14. package/assets/skills/office-documents/ooxml/comments.md +8 -8
  15. package/assets/skills/office-documents/ooxml/hyperlinks_and_fields.md +10 -10
  16. package/assets/skills/office-documents/ooxml/rels_and_content_types.md +7 -7
  17. package/assets/skills/office-documents/ooxml/tracked_changes.md +12 -12
  18. package/assets/skills/office-documents/references/docx-structure.md +11 -13
  19. package/assets/skills/office-documents/references/template-elicitation.md +11 -13
  20. package/assets/skills/office-documents/references/writing-quality.md +20 -20
  21. package/assets/skills/office-documents/tasks/accessibility_a11y.md +16 -22
  22. package/assets/skills/office-documents/tasks/captions_crossrefs.md +23 -26
  23. package/assets/skills/office-documents/tasks/clean_tracked_changes.md +17 -22
  24. package/assets/skills/office-documents/tasks/comments_manage.md +9 -11
  25. package/assets/skills/office-documents/tasks/compare_diff.md +10 -16
  26. package/assets/skills/office-documents/tasks/create_edit.md +14 -16
  27. package/assets/skills/office-documents/tasks/equations.md +17 -28
  28. package/assets/skills/office-documents/tasks/fields_update.md +14 -16
  29. package/assets/skills/office-documents/tasks/fixtures_edge_cases.md +19 -33
  30. package/assets/skills/office-documents/tasks/footnotes_endnotes.md +12 -14
  31. package/assets/skills/office-documents/tasks/forms_content_controls.md +16 -20
  32. package/assets/skills/office-documents/tasks/headings_numbering.md +17 -22
  33. package/assets/skills/office-documents/tasks/images_figures.md +15 -25
  34. package/assets/skills/office-documents/tasks/multi_doc_merge.md +13 -23
  35. package/assets/skills/office-documents/tasks/navigation_internal_links.md +18 -21
  36. package/assets/skills/office-documents/tasks/privacy_scrub_metadata.md +16 -22
  37. package/assets/skills/office-documents/tasks/protection_restrict_editing.md +19 -21
  38. package/assets/skills/office-documents/tasks/read_review.md +9 -20
  39. package/assets/skills/office-documents/tasks/redaction_anonymization.md +17 -18
  40. package/assets/skills/office-documents/tasks/sections_layout.md +16 -23
  41. package/assets/skills/office-documents/tasks/style_lint_normalize.md +18 -22
  42. package/assets/skills/office-documents/tasks/tables_spreadsheets.md +21 -31
  43. package/assets/skills/office-documents/tasks/templates_style_packs.md +17 -21
  44. package/assets/skills/office-documents/tasks/toc_workflow.md +10 -14
  45. package/assets/skills/office-documents/tasks/verify_render.md +11 -23
  46. package/assets/skills/office-documents/tasks/watermarks_background.md +11 -15
  47. package/assets/skills/office-documents/troubleshooting/libreoffice_headless.md +9 -9
  48. package/assets/skills/office-documents/troubleshooting/run_splitting.md +12 -12
  49. package/assets/skills/office-pdf/SKILL.md +36 -51
  50. package/assets/skills/office-pdf/references/form-fields.md +20 -20
  51. package/assets/skills/office-pdf/references/geometry.md +10 -10
  52. package/assets/skills/office-pdf/references/layout-quality.md +13 -13
  53. package/assets/skills/office-pdf/references/limits.md +12 -56
  54. package/assets/skills/office-pdf/tasks/annotations.md +5 -5
  55. package/assets/skills/office-pdf/tasks/create.md +6 -9
  56. package/assets/skills/office-pdf/tasks/edit-pages.md +14 -14
  57. package/assets/skills/office-pdf/tasks/forms.md +15 -15
  58. package/assets/skills/office-pdf/tasks/read.md +9 -9
  59. package/assets/skills/office-pdf/tasks/redact.md +18 -18
  60. package/assets/skills/office-pdf/tasks/stamp.md +10 -10
  61. package/assets/skills/office-presentations/SKILL.md +71 -91
  62. package/assets/skills/office-presentations/container_tools/render_slides.py +1 -1
  63. package/assets/skills/office-presentations/domain_guidance/finance.md +16 -16
  64. package/assets/skills/office-presentations/recipes/README.md +24 -35
  65. package/assets/skills/office-presentations/recipes/autolayout.md +12 -13
  66. package/assets/skills/office-presentations/recipes/connectors.md +11 -12
  67. package/assets/skills/office-presentations/recipes/images.md +11 -12
  68. package/assets/skills/office-presentations/recipes/master-and-layouts.md +18 -18
  69. package/assets/skills/office-presentations/recipes/native-charts.md +8 -8
  70. package/assets/skills/office-presentations/recipes/rich-text-runs.md +13 -13
  71. package/assets/skills/office-presentations/recipes/speaker-notes.md +7 -7
  72. package/assets/skills/office-presentations/recipes/tables.md +14 -14
  73. package/assets/skills/office-presentations/recipes/textbox-at-coordinate.md +9 -9
  74. package/assets/skills/office-presentations/recipes/theme-tokens.md +7 -8
  75. package/assets/skills/office-presentations/references/authoring-workflow.md +38 -43
  76. package/assets/skills/office-presentations/references/finalization.md +10 -12
  77. package/assets/skills/office-presentations/references/native-bullets.md +14 -18
  78. package/assets/skills/office-presentations/references/native-evidence.md +18 -32
  79. package/assets/skills/office-presentations/references/style-guidelines.md +27 -32
  80. package/assets/skills/office-presentations/references/templates.md +31 -60
  81. package/assets/skills/office-presentations/routing/google_slides.md +4 -4
  82. package/assets/skills/office-presentations/tasks/apply-annotations.md +17 -17
  83. package/assets/skills/office-presentations/tasks/charts-tables-notes.md +20 -23
  84. package/assets/skills/office-presentations/tasks/create-deck.md +19 -19
  85. package/assets/skills/office-presentations/tasks/edit-deck.md +14 -16
  86. package/assets/skills/office-presentations/tasks/inspect-and-verify.md +31 -34
  87. package/assets/skills/office-presentations/tasks/template-following.md +23 -28
  88. package/assets/skills/office-spreadsheets/SKILL.md +32 -39
  89. package/assets/skills/office-spreadsheets/recipes/charts.md +8 -26
  90. package/assets/skills/office-spreadsheets/recipes/conditional-formats.md +9 -26
  91. package/assets/skills/office-spreadsheets/recipes/data-tables.md +7 -23
  92. package/assets/skills/office-spreadsheets/recipes/named-ranges.md +8 -21
  93. package/assets/skills/office-spreadsheets/recipes/number-formats.md +7 -23
  94. package/assets/skills/office-spreadsheets/recipes/sparklines.md +7 -20
  95. package/assets/skills/office-spreadsheets/references/charts.md +15 -34
  96. package/assets/skills/office-spreadsheets/references/domain/financial-models.md +10 -25
  97. package/assets/skills/office-spreadsheets/references/domain/healthcare.md +8 -19
  98. package/assets/skills/office-spreadsheets/references/domain/marketing.md +8 -22
  99. package/assets/skills/office-spreadsheets/references/domain/research.md +8 -19
  100. package/assets/skills/office-spreadsheets/references/formula-patterns.md +20 -50
  101. package/assets/skills/office-spreadsheets/references/style-guidelines.md +19 -44
  102. package/assets/skills/office-spreadsheets/references/workbook-structure.md +12 -35
  103. package/assets/skills/office-spreadsheets/routing/google-sheets.md +11 -26
  104. package/assets/skills/office-spreadsheets/tasks/analyze-workbook.md +10 -25
  105. package/assets/skills/office-spreadsheets/tasks/annotations.md +12 -30
  106. package/assets/skills/office-spreadsheets/tasks/create-workbook.md +5 -5
  107. package/assets/skills/office-spreadsheets/tasks/diff-workbooks.md +2 -2
  108. package/assets/skills/office-spreadsheets/tasks/edit-workbook.md +5 -5
  109. package/assets/skills/office-spreadsheets/tasks/inspect-workbook.md +9 -9
  110. package/assets/skills/office-spreadsheets/tasks/recalc-and-check.md +10 -30
  111. package/assets/skills/shared/annotation-recipes.md +98 -120
  112. package/assets/skills/shared/common-workflow.md +70 -80
  113. package/dist/index.js +105 -29
  114. package/package.json +1 -1
  115. package/postinstall.mjs +58 -17
  116. package/python/office_cli.py +70 -7
@@ -1,13 +1,10 @@
1
1
  # The COM object model behind a live edit
2
2
 
3
- What this skill talks to is not a file. It is an out-of-process COM server that happens
4
- to own a window: every property read and every write is a remote call across process
5
- boundaries, and every object you hold is a proxy that re-reads state when you ask it.
6
- That explains most of the rules below.
3
+ The target is an out-of-process COM server that owns a window. Each property read or write
4
+ is a remote call; each object is a proxy that re-reads state. That explains most rules here.
7
5
 
8
6
  `container_tools/live_excel.py` wraps the common cases. Read this when the CLI has no verb
9
- for what the task needs, when a call fails in a way the JSON does not explain, or when you
10
- are extending the tool.
7
+ for the task, a failure is unexplained, or you extend the tool.
11
8
 
12
9
  ## Reaching the running instance
13
10
 
@@ -15,36 +12,33 @@ are extending the tool.
15
12
  $app = [Runtime.InteropServices.Marshal]::GetActiveObject('Excel.Application')
16
13
  ```
17
14
 
18
- - This is the only supported way to find a *running* instance. `New-Object -ComObject
19
- Excel.Application` creates a new, invisible one — never do that for user work.
20
- - It exists in Windows PowerShell 5.1 (`powershell.exe`). PowerShell 7 (`pwsh`) removed
21
- the method, which is why the tool shells out to `powershell.exe` and not `pwsh`.
22
- - With nothing running it raises `0x800401E3 (MK_E_UNAVAILABLE)`. That is the signal to
23
- ask the user to open the workbook, not to launch anything.
24
- - WPS Spreadsheets registers both `Ket.Application` and `Excel.Application`, so a
25
- successful attach to `Excel.Application` does not prove Microsoft Excel is running.
26
- `Application.Name` and `Application.Version` are worse than useless here — WPS reports
27
- `Microsoft Excel` / `12.0`. Infer the product from `Application.Path`.
28
- - The running-object table is per user session and survives the process that created the
29
- instance. A hidden instance launched for a self-test stays attachable from later calls;
30
- it stays invisible until something shows it, and it leaks until `Application.Quit()`.
15
+ - The only supported way to find a running instance. `New-Object -ComObject
16
+ Excel.Application` creates a new invisible one; never use it for user work.
17
+ - Only in Windows PowerShell 5.1 (`powershell.exe`); PowerShell 7 (`pwsh`) removed it,
18
+ which is why the tool shells out to `powershell.exe`.
19
+ - Nothing running raises `0x800401E3 (MK_E_UNAVAILABLE)`. Ask the user to open the
20
+ workbook; launch nothing.
21
+ - WPS registers `Ket.Application` and `Excel.Application`, so attaching does not prove
22
+ Microsoft Excel. `Application.Name`/`Version` are useless here (WPS reports `Microsoft
23
+ Excel` / `12.0`). Infer the product from `Application.Path`.
24
+ - The running-object table is per user session and outlives the creating process. A hidden
25
+ self-test instance stays attachable, invisible until shown, and leaks until
26
+ `Application.Quit()`.
31
27
 
32
28
  ## Addressing
33
29
 
34
30
  `Application` → `Workbooks` → `Workbook` → `Sheets` → `Worksheet` → `Range`.
35
31
 
36
32
  - Collections are **1-based**: `$book.Sheets.Item(1)`. `Item(0)` throws.
37
- - `$sheet.Cells` is the whole sheet; `$sheet.UsedRange` is the rectangle that has content
38
- or formatting. `UsedRange` is not trimmed by deleting a value in its last cell; treat
39
- it as a hint for what to read, never as the boundary of an edit.
40
- - A1 strings: `A1`, `B4:D9`, `$B$14`, `Sheet1!A1:C9`, `'Build Detail'!E14` (quote sheet
41
- names containing spaces). `Range.Address($row_absolute, $column_absolute)` prints one
42
- back, e.g. `$r.Address(0,0)` gives `A1:C3`. Prefer reporting the absolute form the user
43
- can paste into the Name Box.
44
- - Sheet names are case-insensitive in .NET-side matching but must match for COM:
45
- `$book.Sheets.Item('Build')` throws on `build`. Use `Worksheet.Name` for the exact
46
- spelling.
47
- - Multi-area ranges (`A1:A5,C1:C5`) exist; the tool refuses them for writes because a
33
+ - `$sheet.Cells` is the whole sheet; `$sheet.UsedRange` is the rectangle holding content or
34
+ formatting. Clearing the last cell does not shrink it: a read hint, never an edit
35
+ boundary.
36
+ - A1 strings: `A1`, `B4:D9`, `$B$14`, `Sheet1!A1:C9`, `'Build Detail'!E14` (quote names
37
+ with spaces). `$r.Address(0,0)` gives `A1:C3`; report the absolute form the user can
38
+ paste into the Name Box.
39
+ - Sheet-name matching is case-insensitive in .NET but exact for COM:
40
+ `$book.Sheets.Item('Build')` throws on `build`. Use `Worksheet.Name` for spelling.
41
+ - Multi-area ranges (`A1:A5,C1:C5`) exist; the tool refuses them for writes because one
48
42
  rectangular `Value2` assignment cannot fill them.
49
43
 
50
44
  ## Cells: what you write and what comes back
@@ -52,156 +46,136 @@ $app = [Runtime.InteropServices.Marshal]::GetActiveObject('Excel.Application')
52
46
  | Property | Use it for | Reads back |
53
47
  | --- | --- | --- |
54
48
  | `Range.Value2` | every value: numbers, text, dates (as serials), booleans, arrays | typed scalars / `Object[,]` |
55
- | `Range.Formula` | formulas in A1 notation; also the way to read them back | `String`, e.g. `=SUM(B2:B9)` |
49
+ | `Range.Formula` | formulas in A1 notation; also how to read them back | `String`, e.g. `=SUM(B2:B9)` |
56
50
  | `Range.FormulaR1C1` | fills where you think in offsets | `String` |
57
- | `Range.Text` | the *displayed* string (after number format) | per-cell only |
58
-
59
- - **`Value2` is type-preserving and locale-blind.** Assign a `Double` and the cell is a
60
- number; assign a `String` and it is text — except that the application may *parse* a
61
- string that looks like a date, a currency amount, or `=1+1`. Writing `"2026-01-31"`
62
- through `Value2` produced the serial `46053` in a date-formatted cell. If the user meant
63
- the literal text, store the serial (or the number) and set a number format, or prefix
64
- the apostrophe; do not rely on the parse.
65
- - **`$null` empties a cell.** That is the supported way to clear one value inside a block
66
- you are writing.
67
- - A multi-cell read returns a 2-D `Object[,]` with **1-based** indices. A single cell
51
+ | `Range.Text` | the displayed string, after number format | per-cell only |
52
+
53
+ - **`Value2` preserves type and ignores locale.** A `Double` stays a number, a `String`
54
+ stays text — unless the app parses it as a date, currency, or `=1+1`. `"2026-01-31"`
55
+ written through `Value2` produced serial `46053` in a date-formatted cell. For literal
56
+ text, store the serial/number and set a number format, or prefix the apostrophe. Never
57
+ rely on the parse.
58
+ - **`$null` empties a cell**, the supported way to clear one value inside a written block.
59
+ - A multi-cell read returns a 2-D `Object[,]` with **1-based** indices; a single cell
68
60
  returns a scalar, so code that always indexes `[1,1]` fails on one-cell ranges.
69
- - **Errors come back as integers.** A live value of `#DIV/0!` is the Int32 SCODE
70
- `-2146826281`; `#VALUE!` is `-2146826273`, `#REF!` `-2146826265`, `#NAME?`
71
- `-2146826259`, `#NUM!` `-2146826252`, `#N/A` `-2146826246`. In WPS,
72
- `WorksheetFunction.IsError` returns `False` for them and `SpecialCells(16)` throws, so
73
- the practical test is "is this value an Int32?" — then read `Range.Text`,
74
- `Range.Formula` and `Range.Address(0,0)` for that cell alone.
75
- - `Range.Text` is a per-cell property. On a multi-cell range WPS returns `DBNull`, so the
76
- tool reads it cell by cell (that is why `--display` is capped).
77
- - **Assigning one formula to a range fills it with relative adjustment.** Setting
78
- `A1:A3` to `=B1` gives `=B1`, `=B2`, `=B3`. This is the cheap way to fill a column; it
79
- is also the way to accidentally create a formula you did not intend when the target is
80
- more than one cell.
81
- - Dates are serials (`days since 1899-12-30`, the 1900 date system). `DateSerial(y,m,d)`
82
- gives the number; a `NumberFormat` gives the look.
83
- - Formulas are text. There is no calculation on write; the value updates when the
84
- application recalculates, which is why `recalc` exists.
61
+ - **Errors are integers.** `#DIV/0!` is Int32 SCODE `-2146826281`; `#VALUE!` `-2146826273`,
62
+ `#REF!` `-2146826265`, `#NAME?` `-2146826259`, `#NUM!` `-2146826252`, `#N/A`
63
+ `-2146826246`. WPS returns `False` from `WorksheetFunction.IsError` and throws on
64
+ `SpecialCells(16)`, so test "is this an Int32?", then read `Range.Text`,
65
+ `Range.Formula`, `Range.Address(0,0)` for that cell alone.
66
+ - `Range.Text` is per-cell; on a multi-cell range WPS returns `DBNull`, so the tool reads
67
+ cell by cell (hence the `--display` cap).
68
+ - **One formula assigned to a range fills with relative adjustment**: `A1:A3` = `=B1`
69
+ gives `=B1`, `=B2`, `=B3`. Cheap for a column, and how unintended formulas appear on
70
+ multi-cell targets.
71
+ - Dates are serials (`days since 1899-12-30`, 1900 system). `DateSerial(y,m,d)` gives the
72
+ number; `NumberFormat` gives the look.
73
+ - Formulas are text. Nothing calculates on write; values update on recalc, which is why
74
+ `recalc` exists.
85
75
 
86
76
  ## Number formats
87
77
 
88
- `Range.NumberFormat` takes format *codes*, not locales: `#,##0`, `#,##0.00`, `0.0%`,
89
- `"$"#,##0.00`, `mmm-yy`, `d-mmm`, `@`. Use invariant ASCII codes — the dot is always the
90
- decimal point inside the code, whatever the machine's `Application.DecimalSeparator`
91
- says. WPS returns empty strings for `DecimalSeparator`/`ThousandsSeparator`, so do not
92
- read locale from the app and do not build codes from locale data.
93
-
94
- - Format is display only. The stored value keeps full precision; never round data to make
95
- it read right.
96
- - One format per column. Mixing `#,##0` and `#,##0.00` down a single column is the most
97
- common visual defect in a live sheet.
98
- - Percentages carry precision: one decimal for analytical tables, zero for dashboards,
99
- two when the differences are small. The code encodes that: `0.0%`, `0%`, `0.00%`.
100
- - `###` in the window means the column is too narrow for the formatted value, not that
101
- the value is wrong. Widen with `ColumnWidth` (points-ish, default about 8.43) or
102
- `EntireColumn.AutoFit()`, and check the result with `--display`.
78
+ `Range.NumberFormat` takes codes, not locales: `#,##0`, `#,##0.00`, `0.0%`, `"$"#,##0.00`,
79
+ `mmm-yy`, `d-mmm`, `@`. Use invariant ASCII; the dot is always the decimal point inside a
80
+ code, whatever `Application.DecimalSeparator` says. WPS returns empty
81
+ `DecimalSeparator`/`ThousandsSeparator`: never read locale from the app or build codes from
82
+ locale data.
83
+
84
+ - Format is display only; values keep full precision. Never round data to make it read
85
+ right.
86
+ - One format per column; mixing `#,##0` and `#,##0.00` down a column is the commonest
87
+ visual defect.
88
+ - Precision belongs in the code: `0.0%` for analytical tables, `0%` for dashboards,
89
+ `0.00%` when differences are small.
90
+ - `###` means too narrow, not wrong. Widen with `ColumnWidth` (default ~8.43) or
91
+ `EntireColumn.AutoFit()`, then check with `--display`.
103
92
 
104
93
  ## Colour is BGR
105
94
 
106
- `Interior.Color` and `Font.Color` are OLE colour longs written `0xBBGGRR`, while every
107
- spec in this repo is `#RRGGBB`. Convert explicitly:
95
+ `Interior.Color` and `Font.Color` are OLE longs `0xBBGGRR`; specs are `#RRGGBB`:
108
96
 
109
97
  ```
110
98
  ole = red + green * 256 + blue * 65536 # #RRGGBB -> BGR long
111
99
  ```
112
100
 
113
- `#C00000` becomes `192`; a pure blue fill becomes `16711680`. Setting `ColorIndex = -4142`
114
- removes a fill (`Interior.Color` then reads back `16777215`). Theme colours and tints are
115
- not addressable this way: if the workbook's palette matters, use the workbook's own
116
- existing colours rather than inventing one.
101
+ `#C00000` becomes `192`; pure blue fill is `16711680`. `ColorIndex = -4142` removes a fill
102
+ (`Interior.Color` then reads `16777215`). Theme colours and tints are not addressable;
103
+ reuse existing workbook colours.
117
104
 
118
105
  ## Font, borders, alignment, layout
119
106
 
120
107
  - `Range.Font`: `Name`, `Size`, `Bold`, `Italic`, `Color`, `Underline`, `Strikethrough`.
121
- One family across the sheet; the repo default is Helvetica Neue → Helvetica → Arial →
122
- Aptos, whichever the workbook already uses.
123
- - `Range.Borders.Item(index)`: 7 left, 8 top, 9 bottom, 10 right; `LineStyle` (1 continuous),
124
- `Weight` (2 thin), `Color`. `BorderAround(1, 2)` draws a thin outline in one call.
125
- - `HorizontalAlignment` / `VerticalAlignment` take `xlHAlign*` constants (`-4131` left,
126
- `-4108` center, `-4152` right) and `xlVAlign*` (`-4160` top, `-4108` center, `-4104`
127
- bottom). The tool maps the readable names for you.
128
- - `Range.Merge()`, `Range.UnMerge()`, `Range.WrapText`, `Range.IndentLevel`,
129
- `EntireColumn.ColumnWidth`, `Tab.Color`, `Rows.Hidden`.
130
- - `FreezePanes` lives on `Window`, not on the sheet, and did not stick on a hidden
131
- instance in WPS. The tool deliberately has no freeze-pane verb; if the user needs panes
132
- frozen, tell them to do it, or do it visibly in a shown window.
133
- - Whole-sheet `AutoFit` and `Select`/`Activate` are traps: they change the user's view,
134
- can take seconds on a large sheet, and `ScreenUpdating` does not hide the flicker from a
135
- user who is looking at the window.
108
+ One family per sheet: Helvetica Neue → Helvetica → Arial → Aptos, whichever the workbook
109
+ uses.
110
+ - `Range.Borders.Item(index)`: 7 left, 8 top, 9 bottom, 10 right; `LineStyle` (1
111
+ continuous), `Weight` (2 thin), `Color`. `BorderAround(1, 2)` draws a thin outline in one
112
+ call.
113
+ - `HorizontalAlignment` takes `xlHAlign*` (`-4131` left, `-4108` center, `-4152` right);
114
+ `VerticalAlignment` takes `xlVAlign*` (`-4160` top, `-4108` center, `-4104` bottom). The
115
+ tool maps readable names.
116
+ - Also: `Merge()`, `UnMerge()`, `WrapText`, `IndentLevel`, `EntireColumn.ColumnWidth`,
117
+ `Tab.Color`, `Rows.Hidden`.
118
+ - `FreezePanes` lives on `Window` and did not stick on a hidden WPS instance. No freeze
119
+ verb: tell the user, or do it visibly.
120
+ - Whole-sheet `AutoFit` and `Select`/`Activate` change the user's view, can take seconds,
121
+ and `ScreenUpdating` does not hide the flicker.
136
122
 
137
123
  ## Objects beside the cells
138
124
 
139
- - **Tables**: `$sheet.ListObjects.Add(1, $range, [Type]::Missing, $has_headers)` creates
140
- a `ListObject`. PowerShell cannot reproduce VBA's empty argument positions — pass
141
- `[Type]::Missing` for the `Destination` slot. Created tables get localized default
142
- names (`表1`), so name them. With `has_headers = 0` the application *generates a header
143
- row above the data*, which shifts the values down one row and makes the table one row
144
- taller than the range you named. Extend an existing table with `ListObject.Resize`
145
- rather than adding a second one over the same cells.
125
+ - **Tables**: `$sheet.ListObjects.Add(1, $range, [Type]::Missing, $has_headers)`.
126
+ PowerShell cannot reproduce VBA's empty argument positions, so pass `[Type]::Missing` for
127
+ `Destination`. Tables get localized default names (`表1`); name them. `has_headers = 0`
128
+ makes the app generate a header row above the data, shifting values down and making the
129
+ table one row taller than the range. Extend with `ListObject.Resize`, never a second
130
+ table.
146
131
  - **Charts**: `$sheet.ChartObjects().Add(left, top, width, height)` → `.Chart` →
147
- `.SetSourceData($range)` + `.ChartType`. `HasTitle`/`ChartTitle.Text` set the title.
148
- `ChartType` numbers: column 51, stacked column 52, bar 57, stacked bar 58, line 4, line
149
- with markers 65, area 1, stacked area 76, pie 5, doughnut -4120, scatter -4169,
150
- scatter with lines 74. A chart over an empty range renders blank — check the source
151
- cells before blaming the chart.
152
- - **Shapes**: `$sheet.Shapes.AddShape(...)`, `AddTextbox`, `AddPicture`. They float over
153
- cells and are not part of the used range; anchor them to a cell (`TopLeftCell`) so they
154
- move with the data.
155
- - **Pivots**: `PivotTables`, `PivotFields`. Read and report them; never rebuild one
156
- through COM unless the user asked for a new pivot — the field layout is not recoverable
157
- from a failed attempt.
158
- - **Names**: `$workbook.Names`, `Range.Name`. Names break when you delete the cells they
159
- point at (`#REF!` in the name), so a rename or a row delete is a contract change.
160
- - **Conditional formats**: `Range.FormatConditions`. Appending a condition to a range
161
- that already has one edits the *existing* set; a "fix" here can silently change rules
162
- the user depends on. Read first, and keep the range bounded.
163
- - **Validation**: `Range.Validation` — same rule. Read the existing rule before writing a
164
- new one.
132
+ `.SetSourceData($range)` + `.ChartType`; `HasTitle`/`ChartTitle.Text` set the title.
133
+ Types: column 51, stacked column 52, bar 57, stacked bar 58, line 4, line with markers
134
+ 65, area 1, stacked area 76, pie 5, doughnut -4120, scatter -4169, scatter with lines 74.
135
+ A chart over an empty range renders blank; check the source cells.
136
+ - **Shapes**: `Shapes.AddShape(...)`, `AddTextbox`, `AddPicture`. They float over cells, sit
137
+ outside the used range, and need `TopLeftCell` anchoring to move with data.
138
+ - **Pivots**: `PivotTables`, `PivotFields`. Read and report; never rebuild through COM
139
+ unless asked — a failed attempt loses the layout.
140
+ - **Names**: `$workbook.Names`, `Range.Name`. Deleting their cells breaks names (`#REF!`),
141
+ so a rename or row delete is a contract change.
142
+ - **Conditional formats**: `Range.FormatConditions`. Appending to a range with an existing
143
+ condition edits that set; read first, keep the range bounded.
144
+ - **Validation**: `Range.Validation`; read the existing rule before writing.
165
145
 
166
146
  ## Calculation and freshness
167
147
 
168
- - `Application.Calculation`: `-4105` automatic, `-4135` manual. A workbook left in manual
169
- mode shows stale numbers after your edit; `recalc` runs `CalculateFull` across every
170
- open workbook and reports the mode it found.
171
- - `CalculateFull` recalculates dependencies, not just the active sheet. `CalculateFullRebuild`
172
- rebuilds the dependency tree — use it only when a value looks impossible, because it is
173
- slow on a large model.
174
- - Iterative calculation (`Application.Iteration`) is off by default. Circular references
175
- that "worked" for the user are a sign it was on; do not turn it on to make an edit
176
- succeed.
148
+ - `Application.Calculation`: `-4105` automatic, `-4135` manual. Manual mode shows stale
149
+ numbers after an edit; `recalc` runs `CalculateFull` on every open workbook and reports
150
+ the mode.
151
+ - `CalculateFull` recalculates dependencies, not just the active sheet.
152
+ `CalculateFullRebuild` rebuilds the tree; use it only when a value looks impossible — it
153
+ is slow on large models.
154
+ - Iteration (`Application.Iteration`) is off by default. Circular references that "worked"
155
+ mean it was on; do not enable it to make an edit succeed.
177
156
 
178
157
  ## Latency, failures, retries
179
158
 
180
- - Every property access is an RPC. A trivial call (`info`, three reads) took about 1.2–1.5 s
181
- on this host; a call that formats 100 cells one at a time can take tens of seconds.
182
- **Batch**: one `write_range` for a block, one `style_range` for a range, one `set_formula`
183
- for a column. Do not loop calls per cell.
184
- - The default timeout in the tool is 180 s. Raising it is legitimate for a big paste;
185
- lowering it below a second will fail on a busy application.
186
- - Failures you will meet:
187
- - `0x800401E3` — nothing is running. Remediate by asking the user to open the workbook.
188
- - `0x8001010A` (RPC_E_SERVERCALL_RETRYLATER) — the application is busy (a modal dialog,
189
- a recalculation, a user dragging a window). Read again, and if it persists tell the
190
- user there is a dialog blocking the app.
191
- - "Object required" / a stale proxy — usually after the user closed the workbook you
192
- were holding. Re-attach by name; never reuse the old object.
193
- - A method that exists in Excel raising "does not contain a method named …" in WPS — the
194
- WPS object model is a subset. Fall back to a simpler route (formatting via
195
- `Value2`/`NumberFormat` instead of a specialised helper).
196
- - **Nothing is transactional.** A call that fails halfway leaves the cells it already
197
- wrote. The retry protocol is: `read_range` the block, compare with intent, write only
198
- what is missing or wrong. Replaying the same batch is how a live document gets
199
- duplicated rows.
159
+ - Every property access is an RPC. `info` plus three reads took 1.2–1.5 s here; formatting
160
+ 100 cells one at a time can take tens of seconds. **Batch**: one `write_range` per block,
161
+ one `style_range` per range, one `set_formula` per column. Never loop per cell.
162
+ - Default timeout is 180 s. Raising it is fine for a big paste; below 1 s fails on a busy
163
+ app.
164
+ - Failures you meet:
165
+ - `0x800401E3` — nothing running. Ask the user to open the workbook.
166
+ - `0x8001010A` (RPC_E_SERVERCALL_RETRYLATER) — app busy (dialog, recalculation, dragged
167
+ window). Read again; if it persists, tell the user a dialog is blocking it.
168
+ - "Object required" / stale proxy — usually the workbook was closed. Re-attach by name;
169
+ never reuse the old object.
170
+ - An Excel method raising "does not contain a method named …" in WPS: the WPS model is a
171
+ subset. Fall back to a simpler route (formatting via `Value2`/`NumberFormat`).
172
+ - **Nothing is transactional.** A half-failing call leaves written cells. Retry:
173
+ `read_range` the block, compare with intent, write only what is missing or wrong.
174
+ Replaying a batch duplicates rows.
200
175
 
201
176
  ## The one rule that outranks the rest
202
177
 
203
- A live edit mutates a document the user is looking at and may have unsaved changes in.
204
- **Read and diff before writing.** `read_range` the target with `--formulas`; note whether
205
- `info` says the workbook is `saved: false`; then make the smallest write that satisfies the
206
- request. If the diff shows values you did not expect, stop and ask — the user's unsaved
207
- work is more important than finishing the task.
178
+ A live edit mutates a document the user is looking at, possibly with unsaved changes.
179
+ **Read and diff before writing.** `read_range` the target with `--formulas`; note
180
+ `saved: false` from `info`; then make the smallest write that satisfies the request. If the
181
+ diff shows unexpected values, stop and ask — unsaved user work outranks finishing the task.
@@ -1,59 +1,54 @@
1
1
  # Answering questions about a workbook the user has open
2
2
 
3
- Read-only work: no writes, no saves, no restyling. The deliverable is an answer with cell
4
- references the user can check, not a changed document.
3
+ Read-only: no writes, no saves, no restyling. Deliver an answer with cell references the
4
+ user can check, not a changed document.
5
5
 
6
6
  ## Reading
7
7
 
8
- - `info` first: which workbook, which sheets, which used ranges, tables, charts, pivots.
9
- That tells you where to look and whether the thing the user is asking about even exists.
10
- - `read_range --formulas` for the cells that matter. You almost always need both: the
11
- value tells you *what*, the formula tells you *why*. A number with no formula behind it
12
- is an input the user typed; a formula with no precedent is a number you cannot trust.
13
- - `read_range --display` when the question is about how something *reads* (`###`, a
14
- truncated label, a date that shows as a serial). Displayed text follows the number
15
- format; the value does not.
16
- - Read the workbook's own labels — row and column headers, period names, "Actual" vs
17
- "Forecast" markers, units — before interpreting a cell. `D14` is only meaningful when
18
- you know it is "Q3 advertising spend, USD".
19
- - The window may be ahead of the disk file. If `info` shows `saved: false`, the numbers
20
- you read are the user's unsaved state; say so if the answer would differ from the file.
8
+ - `info` first: which workbook, sheets, used ranges, tables, charts, pivots — and whether
9
+ the thing asked about exists.
10
+ - `read_range --formulas` for the cells that matter. The value says *what*; the formula
11
+ says *why*. A number with no formula is a typed input; a formula with no precedent is
12
+ untrustworthy.
13
+ - `read_range --display` when the question is how something *reads* (`###`, a truncated
14
+ label, a date shown as a serial): displayed text follows the number format, values do
15
+ not.
16
+ - Read the workbook's labels — headers, periods, "Actual" vs "Forecast", units — before
17
+ interpreting a cell. `D14` means nothing without "Q3 advertising spend, USD".
18
+ - The window may be ahead of the file. `info` showing `saved: false` means you are reading
19
+ the user's unsaved state; say so when the answer would differ.
21
20
 
22
21
  ## Answering
23
22
 
24
- 1. **Locate the output by its labels**, not by guesswork: find the row/column that names
25
- the metric and the period the user asked about, then read the intersection.
26
- 2. **Trace the precedent chain** back from the output to labelled assumptions or raw
27
- inputs. `read_range --formulas` on each step; stop at cells whose value is typed rather
28
- than computed. Reporting an intermediate total as the cause is the classic error.
29
- 3. **Reconcile before asserting.** If a total does not equal the sum of its parts, that is
30
- the finding — report the gap and the cells, do not average it away.
31
- 4. **Compute from the underlying values.** A cell showing `1.2` may hold `1.2345`; the
32
- answer to "what is the margin" uses the stored value, and if the requested precision
33
- needs the rounded number, say that you are using the displayed value.
34
- 5. **Rank drivers** by absolute contribution when the question is "why did it move".
35
- Report the top two or three with their cells and amounts, not a list of everything.
36
- 6. **Cite cells** in the reply: `` `Summary!D14` shows 1,234 units because `Build!F7:F12`
37
- sums to that ``. A claim without an address is not verifiable.
38
- 7. If two sheets disagree, say which one you believe and why (more recent period, source
39
- data rather than a copy, a formula chain rather than a paste), and do not "fix" either
40
- without being asked.
23
+ 1. **Locate the output by its labels**, not by guessing: find the metric's row/column and
24
+ the period, then read the intersection.
25
+ 2. **Trace the precedent chain** back to labelled assumptions or raw inputs. Use
26
+ `read_range --formulas` at each step; stop at typed cells. Reporting an intermediate
27
+ total as the cause is the classic error.
28
+ 3. **Reconcile before asserting.** If a total is not the sum of its parts, that is the
29
+ finding: report the gap and the cells; do not average it away.
30
+ 4. **Compute from underlying values.** A cell showing `1.2` may hold `1.2345`; use the
31
+ stored value, and say so if the requested precision forces the displayed one.
32
+ 5. **Rank drivers** by absolute contribution for "why did it move": the top two or three,
33
+ with cells and amounts, not everything.
34
+ 6. **Cite cells**: `` `Summary!D14` shows 1,234 units because `Build!F7:F12` sums to that ``.
35
+ A claim without an address is unverifiable.
36
+ 7. Sheets disagree: say which you believe and why (more recent period, source over copy,
37
+ formula chain over paste) and do not "fix" either unasked.
41
38
 
42
39
  ## Sensitive reviews
43
40
 
44
- Clinical records, payroll and individual compensation, customer-level data: answer at the
45
- level the user asked for and no lower. Inspect structure, formats, dependency chains and
46
- formulas as evidence, and do not echo restricted values into the chat unless the user
47
- needs that exact figure to act. If the question cannot be answered without exposing
48
- personal data, say what you can answer instead.
41
+ Clinical records, payroll/compensation, customer-level data: answer at the level asked and
42
+ no lower. Inspect structure, formats, dependency chains and formulas as evidence; do not
43
+ echo restricted values unless the user needs that figure to act. If the question cannot be
44
+ answered without exposing personal data, say what you can answer instead.
49
45
 
50
46
  ## Limits
51
47
 
52
- - Do not equate the live window with the saved file, and do not present a read-only
53
- question as if you had verified the disk copy.
54
- - If a formula depends on external links, volatile functions (`NOW()`, `RAND()`) or a
55
- pivot cache that has not been refreshed, say the number is provisional.
56
- - If the workbook is protect-structured or the sheet is protected, reads still work;
57
- report the protection rather than working around it.
58
- - `#REF!`, `#DIV/0!` and friends in the cells are part of the answer, not noise: name the
59
- cell, the formula and what it broke.
48
+ - Do not equate the live window with the saved file, or present a read-only answer as
49
+ verified against disk.
50
+ - External links, volatile functions (`NOW()`, `RAND()`) or an unrefreshed pivot cache make
51
+ the number provisional; say so.
52
+ - Protected sheets: reads work; report the protection, do not work around it.
53
+ - `#REF!`, `#DIV/0!` and friends are part of the answer: name the cell, the formula and what
54
+ it broke.