На DCS-формах возвращались только настройки с явным чекбоксом «Использование» — остальные (всегда включённые) отбрасывались и пропадали из fields[]. Reference-поля с chip-контролом возвращали пустое value, потому что значение живёт в .chipsItem .chipsTitle, а не в input.value.
- DCS-группировка больше не требует наличия «Использование»; при его отсутствии setting.enabled = true (настройка всегда активна)
- При чтении input.value делается fallback на .chipsItem .chipsTitle в LABEL-родителе — через запятую, если значений несколько (первый элемент + «+N» при свёртке в UI)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1С оставляет стейл-элемент #modalSurface (display:none) после закрытия
формы и создаёт второй при открытии новой модалки — в DOM оказывается два
элемента с одинаковым id. getElementById возвращал первый (скрытый), из-за
чего detectForm/detectForms не видели активную модалку: getFormState
выдавал form+buttons от родительской формы, а clickElement кликал мимо
или падал.
Сканируем все #modalSurface через querySelectorAll и берём первый с
offsetWidth > 0.
Воспроизводилось стабильно на СКД-расшифровке после открытия "Настройки..."
в форме отчёта.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Replace fragile page.frames()[iframeIdx + 1] with handle.contentFrame() for
reliable iframe-to-Playwright-Frame resolution. The old index arithmetic could
break when 1C web client accumulates extra frames during prolonged sessions.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Рефакторинг buildSpreadsheetMapping на 3-уровневый алгоритм.
- Level 1: якорь по DCS-кодам (К1..Кn) — детерминированный для всех ФСД-отчётов, работает независимо от формата чисел (рубли/тыс/млн).
- Level 2: якорь по форматированным числам (пробел-группировка, запятая-десятичка, ведущий минус) вместо общей проверки — голые целые (коды счетов "50", "51") больше не принимаются за данные.
- Level 3: single-row header fallback для text-only данных и query-console.
Починено:
- ФСД-отчёты с числами в групповых шапках (ДДС по счетам 50/51/52/55/57) — был fallback raw rows, теперь структурированный вывод.
- query() из consoleЗапросов для text-only результатов — был data=[], теперь корректно парсит headers/data.
E2E проверено на titan: 4 отчёта (ДС, 45, 77, Ведомость) + 5 query-кейсов. Регрессий нет.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Strict isNumericVal check excludes account codes like "68/78" from being
treated as data values (require pure digits+spaces+commas)
- Require >=2 numeric cells to identify data rows (fallback to >=1)
- Detect DCS column code rows (К1..Кn) and always prefix with group/superRow
- 3-level header support: superRow values used as prefix when group is empty
- superRow excluded from title/meta section
- Fuzzy column matching in clickElement for short codes ("К6" → "84 / К6")
- Replace newlines with spaces in cell text (innerText instead of textContent)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
pickFromSelectionForm: swap steps 2↔3 — try Alt+F advanced search
before search input to avoid overlay blocking row clicks.
pickFromTypeDialog: scan visible rows first, fall back to Ctrl+F
only for large virtual lists. Reduces 3s hardcoded wait to ~0.2s
for common case. scanGridRows: add isGroup flag via gridListH check.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
readTable now handles multi-row grids (e.g. accounting journal entries)
where a single column header spans multiple data sub-rows:
- "Субконто Дт" with 3 data cells → "Субконто Дт 1", "Субконто Дт 2", "Субконто Дт 3"
- Stacked headers (2+ at same X) matched by Y-order (e.g. "Счет Дт" / "Подразделение Дт")
- getFormState tables[].columns also expanded for consistency
- Flat/simple grids unaffected (no multi-row detection triggers)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Extract info bar messages from .stateWindowSupportSurface elements
into errors.stateText — covers missing parameters, "report not
generated", "settings changed", and "generating..." states.
readSpreadsheet() now includes the state message in its error.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Hardcoded threshold of 3 non-empty cells prevented header detection in
spreadsheets with 1-2 columns (e.g. query console results). Use
Math.min(3, maxCol + 1) so narrow tables can still be parsed structurally.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When a spreadsheet has 3 header levels (group → detail → codes), the
carry-forward logic for merged group headers would bleed into columns
belonging to different top-level groups. Detect a "super-row" above the
group row and reset carry-forward when a new top-level header starts.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Rewrites scrollSpreadsheetToCell with fixes for multiple issues discovered
during E2E testing:
- Use Playwright boundingBox (page-level coords) instead of frame-internal
getBoundingClientRect for visibility checks — frame's clientWidth is wider
than the actual visible iframe area clipped by parent elements
- Use iframe element's boundingBox to determine visible region — cells behind
the section panel (x < iframeBox.x) were incorrectly considered "visible"
and focus clicks hit the section panel instead of the spreadsheet
- Use div[y]+div[x] attribute selectors instead of div.RxCy CSS classes —
the RxCy class numbering differs from y/x attribute values
- Accept cellLoc parameter from caller instead of re-searching — avoids
selector mismatch and handles cells missing from some rows
- Native click through mxlCurrBody overlay (page.mouse.click) for focus —
frame.locator().click() bypasses overlay causing header/data desync,
page.mouse.click() + frameEl.focus() doesn't transfer keyboard focus
- Pick rightmost/leftmost fully-visible cell for focus based on scroll
direction — each arrow press immediately triggers platform scroll
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Scroll via arrow keys with native platform behavior. Works for
moderate scroll (few columns off-screen). Known limitations:
- Far off-screen columns may timeout
- Re-clicking between direction changes can break scroll context
- Edge cells (first/last column) may not fully scroll into view
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Cells outside the visible iframe area couldn't be clicked because
boundingBox() returned null. Now scrollIntoView() is called first.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Extend clickElement to support clicking cells in rendered reports
(SpreadsheetDocument). First argument accepts { row, column } object
where coordinates match readSpreadsheet() output. Text fallback also
searches spreadsheet iframes when element not found in main DOM.
Refactor readSpreadsheet internals into reusable helpers:
scanSpreadsheetCells, buildSpreadsheetMapping.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Simple EPF forms with textarea fields were invisible to form detection
(formCount: 0) and misclassified as modal error dialogs. Also, backslash
paths in exec scripts caused "Invalid Unicode escape sequence" JS parse errors.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
highlight() now supports command group headers (eAccentColor labels)
on the 1C function panel. Matches group name, collects header +
commands below it, draws multi-element bounding box overlay.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The expand/collapse code re-searched for the target row by first-cell
text, which was ambiguous when parent and child rows share the same
prefix (e.g. "БУ"). This caused expand to hit the wrong (already-
expanded) row and skip. Use target.y from the initial findClickTarget
instead — matches the exact row.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
gridListH = collapsed (▶), gridListV = expanded (▼). The old code had it
backwards, so `expand: true` on a collapsed group was a no-op.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When DLB dropdown shows only a hint ("Введите строку для поиска...") without
.eddText items, the code fell through without closing the popup. This left
editDropDown covering the input field, causing Playwright to wait up to 30s
for actionability on the next page.click(). Now we Escape the hint popup
when eddState.visible=true but items are empty (34s → 5s on cold cache).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
getFormState now replaces non-breaking spaces with regular spaces in all
button names, field labels, checkbox/radio labels. Icon-only buttons
(pressCommand without text) expose tooltip from parent .framePress title
attribute. clickElement fuzzy match includes tooltip as lowest-priority
candidate.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add modifier option ('ctrl'|'shift') to clickElement for Ctrl+click
(add to selection) and Shift+click (select range) in grid rows.
Add _selected: true flag to readTable rows so the model can verify
which rows are currently selected before performing actions.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Pass '' or null as value to clear any field (except checkbox/radio) via native 1C Shift+F4.
Returns method: 'clear'. Handles tree grids (close selection form first) and flat grids (dblclick to enter edit mode).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
clickElement confirmation handling is cleanup of stale dialogs — no pause needed.
closeForm confirmation is intentional user action — keep 500ms pause during recording
(on top of ~600ms from waitForStable = ~1.1s total dialog visibility).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Same 1.5s pause as in clickElement for confirmation dialogs when video
recording is active. Applies when closeForm({ save: true/false }) auto-clicks
the confirmation button.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When video recording is active, wait 1.5s before clicking confirmation
dialog buttons so viewers can see the dialog in the video.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace 10s waitForSelector timeout with CDP-based network monitoring.
For buttons that trigger server operations without producing a modal/balloon,
the old code waited the full 10s. Now it monitors actual HTTP requests via
Chrome DevTools Protocol and exits 300ms after the last request completes.
- Add startNetworkMonitor() — creates CDP session before click, tracks pending requests
- waitDone() polls for network quiet (300ms debounce) or UI element appearance
- CDP session cleaned up in finally block via cleanup()
- Add optional {timeout} parameter to clickElement for custom wait limits
- Tested: Записать ~1.9s (was ~11.5s), Записать и закрыть ~0.9s, confirmation dialogs OK
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Date fields have a CB (Choose Button) that opens a calendar, not a selection
form. fillFields detected hasPick → delegated to selectValue → error
"DLB click did not open a popup or selection form".
Fix: detect date fields by `iCalendB` CSS class on CB button (dom.mjs),
propagate `isDate` flag through field mapping, and use clipboard paste
for date fields instead of selectValue. Reference fields with CB (without
iCalendB) continue using selectValue as before.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
expand:false was silently ignored because `if (expand || toggle)` evaluates
to false when expand=false. Now uses `expand != null` to enter the branch,
checks current state (gridListH/gridListV for groups, backgroundImage gx=0
for tree nodes), and only clicks when the state needs to change.
- expand:true on collapsed → expand (click)
- expand:true on expanded → noop (idempotent)
- expand:false on expanded → collapse (click)
- expand:false on collapsed → noop (idempotent)
- toggle → always click (unchanged)
Returns `toggled: true/false` in result to indicate whether click happened.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Root cause: fillTableRow used child-index matching between grid header and
body cells. When headers are merged (e.g. "Бизнес-процесс источник" spanning
two body columns), header has more children than body — indices diverge,
click lands on wrong cell, fields stay empty.
Fixes:
- Use `colindex` attribute (set by 1C platform) to match header→body cells
reliably across merged headers (cellCoords + nextCoords)
- Add `scrollIntoView()` before clicking — fills cells behind horizontal scroll
- Sort fields by colindex before processing — Tab-loop goes left→right
regardless of field order in the passed object
- Limit F4 to tree grids only — prevents calculator popup on numeric fields
in flat grids which breaks Tab-loop focus
- Add paste fallback in directEditForm path for plain-text/numeric fields
Tested: 12/12 automated scenarios (single/multi field, add/edit, scroll,
reverse order, mixed types, tree grid, multiple tables, checkbox).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Move screenshot capture to before fetchErrorStack call in the ACTION_FNS
wrapper, so the error modal is still visible on the screenshot. Skip the
duplicate screenshot in catch block when one was already taken.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
dismissPendingErrors() now detects and closes leftover platform dialogs
(About, Support Info, Error Report) before checking for 1C error modals.
This prevents action functions from failing with timeouts when a stale
platform dialog blocks interaction via modalSurface.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
getFormState() now returns `platformDialogs` array when platform-level
dialogs are open (About, Support Info, Error Report). These dialogs are
invisible to 1C form detection and not closeable via Escape.
closeForm() detects platform dialogs first and closes them via
_closePlatformDialogs() instead of sending Escape, returning
closedPlatformDialogs in the result.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When a 1C error modal is detected, automatically retrieve the full call
stack before throwing. Uses two strategies: Path 1 clicks the OpenReport
link for platform exceptions, Path 2 navigates hamburger → About →
Support Info for handled ВызватьИсключение errors. The stack is returned
as structured {raw, entries[{location, code}], timestamp} in the error
result. Handles unstable modal redraws with a 1.5s re-check delay.
Platform dialogs are always cleaned up via try/finally.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When the open-windows tab bar is hidden in 1C settings, the model had no
way to know how many forms are open or whether a form is modal. Now
getFormState returns openForms/formCount/modal derived from DOM form
elements (independent of tab bar), and closeForm compares form number
before/after Escape to return closed: true/false.
Tested on ncc (tab bar hidden) and bpdemo (tab bar visible).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- addNarration: use cap.voice override per caption (fallback to global)
- showCaption/showImage/showTitleSlide: pass opts.voice to caption entry
- showCaption: record caption when text is empty but speech is explicit
- startRecording: add speechRate option (default 70ms/char, 85 for ElevenLabs)
- run.mjs: increase exec timeout to 30min for long recordings
- docs: update recording.md and web-test-recording-guide.md
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- normYo now replaces \u00a0 (non-breaking space) with regular space — 1C web
client uses \u00a0 in dropdown items, causing exact match failures
- clickEddItem does two passes: exact match first, then partial — prevents
"Системы" from matching before "Системы и бизнес-процессы"
- Same \u00a0 fix applied to all inline ny() functions in evaluate scripts
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Reference fields with pick button (_CB) but no dropdown button (_DLB)
were going through the plain paste path, which silently failed for
non-editable fields. Now detected via hasPick flag in resolveFieldsScript
and delegated to selectValue (F4 → selection form).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
web-test/browser.mjs: fillReferenceField now tries DLB (DropListButton) click
before falling back to paste approach. Combobox/enum fields are filled cleanly
in one step (click dropdown → select item) instead of the old Shift+F4 → Tab →
refocus → paste flow that caused visual artifacts.
web-publish v1.1: normalize ApachePath to absolute when agent passes a relative
path like "tools/apache24", preventing Apache "Forbidden" errors.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
CSS fade transitions don't work well with CDP screencast (causes desktop
flash between slides). Instead, showImage/showTitleSlide now automatically
remove the other overlay type — no need to call hide before showing next.
Pattern for consecutive slides:
showTitleSlide(...) → showImage(...) → showImage(...) → hideImage()
No hideTitleSlide() needed between title and first image.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Fade-in (300ms ease) on show: element created with opacity:0, then
transitioned to opacity:1 via requestAnimationFrame
- Fade-out (300ms ease) on hide: opacity set to 0, wait 350ms, remove
- Applied to showTitleSlide/hideTitleSlide and showImage/hideImage
- No change to showCaption (instant appearance fits subtitle UX better)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
All user-facing file functions now resolve relative paths from the
project root (where .claude/ lives) instead of process.cwd().
Fixes showImage, startRecording, addNarration, openFile failing when
the skill is installed in a different project.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Title slides can now have TTS narration, same as showCaption/showImage.
Pass opts.speech as string for custom narration text, or true to use
the title text. Includes smart wait for video timeline sync.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Use min-width/min-height 50% to upscale small images (was showing
tiny 225px images at native size instead of scaling up)
- Keep max-width/max-height 92% for large images (no regression)
- Change full preset from cover to contain — no content cropping,
black bars instead of cutting off edges
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Show image files (PNG, JPG, etc.) as full-screen overlays during video
recording — useful for presentation slides in video instructions.
- Read file → base64 → inject as <img> overlay (same pattern as showTitleSlide)
- Style presets: blur (default), dark, light, full
- blur: blurred+dimmed copy as background with shadow
- full: object-fit cover, fills entire screen
- TTS speech support with smart wait (same as showCaption)
- Custom background overrides preset
- Fixed no-record stubs: showImage/showTitleSlide not stubbed (visual-only)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Icon-only navigation buttons (Назад, Обновить) now match by idName fallback.
Tumbler segments (Справа/Снизу/Скрыть) collected as new kind in both
getFormState and findClickTarget.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1C web client uses native confirm() for scripts like vis.js file
access. Without handling, these block Playwright execution.
Added page.on('dialog') handler to auto-accept.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Auto-detect 1C:Enterprise browser extension from Chrome/Edge profiles
and load it via launchPersistentContext. Enables native file dialogs
(Excel import/export) without "install extension" prompt.
- findExtension() scans Chrome/Edge User Data by extension ID
- connect() uses launchPersistentContext when extension found, falls
back to chromium.launch() otherwise
- isConnected() handles both Browser and BrowserContext objects
- Temp userDataDir cleaned on disconnect()
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Grid row search in findClickTargetScript used raw innerText without
norm() — missed ё→е normalization. Target was normalized but row text
was not, so "расчётным" didn't match "расчетным".
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When expand/toggle is passed for gridGroup/gridParent elements,
click the .gridListH/.gridListV triangle icon to expand/collapse
in place instead of dblclick which enters the group. Without
expand, dblclick behavior is preserved.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>