The real fix: run.mjs sandbox was stubbing stopRecording/addNarration as
noop (returning undefined). Now returns { file: null, duration: 0 } so
video scripts work transparently with --no-record.
Also: browser.mjs stopRecording/addNarration handle missing state gracefully.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Enables --no-record dry-run of video scripts without errors. stopRecording()
returns { file: null, duration: 0, size: 0 } instead of throwing, and
addNarration(null) returns a matching stub.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Group search in highlight() now filters by !classList.contains('logicGroupContainer')
instead of removing _div selector entirely. This skips invisible Representation=None
groups while preserving grid/table _div elements (frameGrid) that are the actual
highlightable panels (Оргструктура, Системы, БизнесПроцессы).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- highlight(): exact match by name ignores size filter (supports Representation=None groups),
error message lists available elements by category
- startRecording(): { force: true } option to restart if already recording
- executeScript(): auto-stop recording on script error (prevents "Already recording")
- fillField(name, value): silent alias for fillFields({ name: value })
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1. Navigation panel: getFormState() returns `navigation` array with
form navigation links (e.g. "Основное", "Объекты метаданных").
clickElement() can now click navigation panel items (kind: navigation).
DOM: `.navigationItem` inside parent `page{N}` container.
2. --no-record: move recording stub from client-side code injection to
server-side sandbox export replacement. Stubs startRecording,
stopRecording, addNarration, showCaption, hideCaption, showTitleSlide,
hideTitleSlide as no-ops. Covers both direct calls and user wrappers
like record()/finalize().
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- exec --no-record injects no-op record() to skip video recording during
debugging/testing
- Document clickElement { toggle: true } for tree node expand/collapse
- Document --no-record in SKILL.md
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Previously fillFields errors showed only the error code (e.g. "not_found"),
making it ambiguous whether the field or the value was not found. Now shows
the message (e.g. 'Value "X" not found') when available.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Previously clickElement always toggled expand/collapse on tree nodes.
Now default = select (click text), and { toggle: true } = expand/collapse
(click tree icon). Hint in response guides the model to use toggle when needed.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Previously findClickTargetScript used querySelector (first grid only),
making clickElement unable to find rows in second+ grids on multi-grid
forms (e.g. system composition wizard). Now uses querySelectorAll to
search all visible grids, and returns gridId so the tree node handler
can locate the correct grid for expand/collapse.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Prevents false positives like "Да" matching "Удаляемые" (group) or
"КомандаУстановитьВсе" (button). Exact and startsWith still work.
Applied to highlight groups, findClickTargetScript buttons/grid-scoped/grid rows.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Clicking a different data row to exit edit mode re-entered edit on that
row, blocking subsequent button clicks like "Записать". Now the add-path
commit clicks the grid header which cleanly exits edit mode without
re-entering it.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
highlight() was ignoring the table parameter, always highlighting the
first matching button (e.g. "Добавить" for Входящие instead of
Исходящие). Now clickElement passes { table } to highlight, and
highlight pre-resolves the grid via resolveGridScript to pass
gridSelector to findClickTargetScript — same pattern as clickElement
itself.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
CamelCase cell IDs like "ИсходящиеБизнесПроцессПриемник" have no
dashes, but user keys like "Бизнес-процесс приемник" do. The previous
regex only stripped spaces, leaving the dash and causing match failure.
Now strip both spaces and dashes with /[\s\-]+/g in both the Tab-loop
path and the row/dblclick column-lookup path.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Button ids like allActionsРазделыКоманднаяПанель contain gridName
in the middle, not at the start. Using includes() catches both
prefix patterns (ИсходящиеКоманднаяПанель_Добавить) and infix
patterns (allActionsРазделыКоманднаяПанель).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
On some forms, #title_div is on the parent group element
(e.g. form0_ГруппаБизнесПроцессы#title_div) rather than
on the grid itself. Add fallback lookup for both getFormState
and resolveGridScript.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Extract group title text from #title_div DOM elements so tables can be
referenced by their visible on-screen names (e.g. "Входящие") in addition
to technical attribute names. Labels appear in getFormState().tables[] and
resolveGridScript cascade matching (exact name → exact label → contains).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Row selection clicks in deleteTableRow and fillTableRow commit now target
the second visible gridBox instead of the first, avoiding accidental
checkbox toggles on forms with checkbox columns (e.g. BP links master).
Also documents the new `table` parameter in SKILL.md for readTable,
clickElement, fillTableRow, deleteTableRow, and getFormState tables[].
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add semantic table binding to readTable, clickElement, fillTableRow,
and deleteTableRow — resolves the correct grid by name when a form
has multiple tables (e.g. "Входящие"/"Исходящие" in BP links).
- New resolveGridScript() in dom.mjs: cascade match by gridName → columns
- findClickTargetScript: scoped button search within grid's parent container
- getFormState: reports all grids via tables[] array (table still present for compat)
- All grids[grids.length-1] fallbacks wrapped in gridSelector ternary
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
navigateSection now normalizes \r\n to spaces, so callers don't need
literal newlines in section names. fillTableRow direct-edit path skips
cells that already contain the desired value (method: 'skip').
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
pickFromSelectionForm:
- 3-step escalation: scan visible → simple search → advanced search (Alt+F)
- Extract helpers: scanGridRows, dblclickAndVerify, advancedSearchInline
- dblclickAndVerify uses click+Enter instead of dblclick (dblclick toggles tree groups)
- Returns ok:false when selection form stays open (group/folder not selectable)
- Distinguish not_found vs not_selectable errors
- trySelect wrapper continues escalation on ok:false
fillTableRow direct-edit (tree grids):
- Click → dblclick → F4 escalation for entering edit mode
- F4 from INPUT mode for tree grid ref fields
- isTypeDialog check + pickFromTypeDialog for composite types
- Commit via click on different row instead of Escape (Escape cancels in tree grids)
fillTableRow regular path:
- Commit new row after fill loop by clicking another row or grid header
- Prevents Escape (e.g. from closeForm) from cancelling uncommitted new row
- Fixes accumulated unclosed forms from closeForm failing to close
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
After F4/Enter that opens a modal, clickElement could fail because
detectFormScript found the parent form before the modal appeared.
Now retries up to 2s, re-detecting the form each time.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Cell IDs in 1C tables are CamelCase without spaces (e.g.
"ВариантыАрхитектурыВариантАрхитектуры"), but users pass keys with
spaces ("Вариант архитектуры"). Added space-stripped fallback to
fuzzy match so fillTableRow correctly maps user keys to grid cells.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Group names often collide with command bar buttons (e.g. "БизнесПроцессы"
matched a tiny 38x35 button instead of the 959x580 panel). Move group
search before button/field search with min-size filter (100x50).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Added group/panel search step to highlight() — matches by visible title
or internal name (e.g. highlight('Оргструктура') finds the group container).
Search priority: popups → commands → form elements → groups → sections.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
CDP screencast doesn't send frames for static pages, causing video to be
shorter than real time (gap-fill capped at 2s, smart pauses are 4-6s).
- Add _flushFrames() helper on recorder to write duplicate frames on demand
- Call _flushFrames() every 1s during smart TTS pauses in showCaption
- Call _flushFrames() in wait() for long explicit pauses during recording
- Call _flushFrames() in stopRecording for final gap before closing ffmpeg
- Increase gap-fill cap from fps*2 to fps*30 as safety net
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
checkErrorsScript falsely classified small forms (e.g. register record
form opened by "Установить статус") as error modals because they had
< 100 elements + a pressDefault button + staticText. Added input field
check — forms with editInput elements are data entry forms, not errors.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
ffmpeg amix + adelay with large delays causes timestamp overflow
(dts near INT64_MAX), producing silent/truncated audio. Fix: use a
silence reference track as first amix input with duration=first,
so amix runs for full video length regardless of delayed stream
timestamps.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
showCaption now auto-waits for estimated TTS duration during recording
(~100ms/char, min 2s). Subsequent wait() uses credit system to avoid
double-waiting. addNarration: cap atempo at 1.3x (was 2.5x), replace
-shortest with explicit -t to prevent video truncation.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add .confirm CSS selector to the server-response waitForSelector in
clickElement. 1C web client shows notifications (Изменение/Проведение)
as .confirm elements after write/post operations. This allows early
exit instead of waiting the full 10s timeout. Записать: 14s → 2.6s.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When clicking toolbar buttons like "Добавить" that put focus into a grid
INPUT cell, skip the 10-second waitForSelector for modal/balloon since
no server round-trip is expected. Also replace fixed waits with polling
in fillTableRow add/row paths. Total: 121s → 62s on composite test suite.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace hardcoded waitForTimeout calls with polling loops that check
DOM state and exit early. Saves ~12s on composite-type test suite.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When filling composite-type cells (String+Number+Date), the previous code
tried paste first and only fell back to type selection if paste was rejected.
This failed when rows inherited a type from previous rows — paste succeeded
but the value was silently converted to the wrong type.
Now when { value, type } is specified:
1. Always clear the cell first (Shift+F4) to reset inherited type
2. Open type dialog (F4) and select the requested type
3. Dismiss calculator/calendar popups with Escape
4. Re-enter edit mode if focus was lost, then paste the value
Tested with primitive types (Число/Строка/Дата) and reference types
(Физическое лицо via selection form). Regression-tested existing
composite-type flow in Операции.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Cells accepting multiple types (e.g. subconto on account 80.01) now
handled via { value, type } syntax. Paste rejection detected
automatically — F4 opens type dialog, picks type, then selects value
from the catalog form.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
selectValue now accepts search as object { field: value } for per-field
disambiguation in selection forms. All fields use advanced search (Alt+F)
by specific column — more efficient than simple full-text search on large
tables, and navigates to exact row even in virtual grids.
Also fixes filterList modal cleanup: now checks specific dialog form
instead of generic modalSurface, preventing accidental closure of
parent modal forms (e.g. selection forms).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When multiple types match the search term in the type selection dialog,
throw a descriptive error listing all matches instead of silently
picking the first one. This prevents the model from getting a misleading
"not found" error when the wrong type was selected.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add `{ type }` option to selectValue for fields that accept multiple
types (e.g. DocumentRef.*). When specified, selectValue navigates
through the type selection dialog via Ctrl+F search before opening
the value selection form. Auto-detects composite fields when type
is not specified and throws a helpful error message.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
navigateSection() now gives a clear error message when the section
panel is in icon-only mode instead of a confusing "not found" error.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Forms with multiple buttons but no form{N}_Message element were
falsely detected as confirmation dialogs. Real 1C confirmations
(Да/Нет) always have a Message element. Now skip forms without it.
Fixes false positives on small EPF forms with custom buttons.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Check form change before checkForErrors() to prevent misidentifying
a small EPF form (< 20 elements) as an informational modal dialog.
Only call checkForErrors() on suspiciously tiny new forms.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
After clicking "Да" on the security confirmation, check for a second
informational modal ("please re-open the file"). If present, dismiss it
and retry the full Ctrl+O → filechooser cycle.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Opens EPF/ERF files via Ctrl+O → 1C file dialog → native file picker.
Handles security confirmation dialog with up to 2 attempts for re-open.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Caption timestamps now use actual video timeline position (frame
counter) instead of wall-clock time, eliminating sync drift from
non-uniform frame duplication in CDP screencast recordings.
Also replace silence-file concatenation with adelay+amix for
sample-accurate TTS placement, and fix exec timeout for long
scenarios (fetch → http.request with 10min timeout).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Screencast frame duplication (Math.round) causes video to be ~5% longer
than wall-clock time. Caption timestamps are wall-clock based, so the
audio track drifted ahead by ~8s at the midpoint of a 5-minute video.
Fix:
- stopRecording() saves recordingDuration in captions.json
- addNarration() reads actual video duration via ffprobe and scales
caption timestamps by videoDuration/recordingDuration ratio
- Phase 2 timeline now tracks actual cumulative position instead of
computing gaps from previous caption data (prevents MP3 frame
quantization drift)
- Also fixed findFfmpeg() → resolveFfmpeg() call in addNarration
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Mirrors resolveFfmpeg() pattern: tries global/project-level import
first, then tools/tts/node_modules/, then throws error with install
instructions. Caches resolved module for subsequent calls.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- node-edge-tts installed in tools/tts/ (alongside tools/ffmpeg/)
- Speed up TTS with ffmpeg atempo when it exceeds gap to next caption,
instead of hard-cutting the audio
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Dynamic import needs file:// URL on Windows and explicit entry point
for ESM resolution. Package installed in tools/ alongside ffmpeg.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
showCaption() collects captions with optional speech parameter,
stopRecording() saves .captions.json, addNarration() generates
TTS voiceover (Edge TTS or OpenAI) and merges audio with video.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
JPEG full range (0-255) was tagged as pc/full in H.264 output, but most
players (VLC, etc.) expect limited range (16-235). Convert JPEG→limited
with scale filter and tag as tv. Also switch preset ultrafast→fast for
5-6x smaller files on static screen content.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>