@ai-digital-factory/lmt-web-cli 0.1.3 → 0.1.5

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.
package/README.md CHANGED
@@ -25,14 +25,15 @@ separately from `lmt-cli` and does not use profiles:
25
25
  npx --yes @ai-digital-factory/lmt-web-cli@latest credential provision --env dev --credential-stdin
26
26
  ```
27
27
 
28
- Start a fresh desktop session against Dev and keep the returned `sessionId` for every
28
+ Start or restore a desktop session against Dev and keep the returned `sessionId` for every
29
29
  later command:
30
30
 
31
31
  ```sh
32
32
  npx --yes @ai-digital-factory/lmt-web-cli@latest start --env dev --device desktop
33
33
  ```
34
34
 
35
- The session starts on the Home Page. Use the same session to log into the Operator;
35
+ A new session starts on the Home Page; a restored session follows Web’s existing
36
+ authentication state. Use the same session to log into the Operator when required;
36
37
  if a Zerodha login is required, start that flow and submit the current OTP through
37
38
  standard input only, using the `attemptId` returned by `zerodha-login`:
38
39
 
@@ -42,7 +43,8 @@ npx --yes @ai-digital-factory/lmt-web-cli@latest zerodha-login --session SESSION
42
43
  npx --yes @ai-digital-factory/lmt-web-cli@latest zerodha-otp --session SESSION_ID --attempt ATTEMPT_ID --stdin
43
44
  ```
44
45
 
45
- The user supplies the OTP for the active attempt. Never put it in a command-line
46
+ `zerodha-cancel --session SESSION_ID` cancels a waiting attempt through the page's
47
+ **Cancel login** control. The user supplies the OTP for the active attempt. Never put it in a command-line
46
48
  argument or ask the CLI to retrieve it. Inspect the latest JSON result after each
47
49
  command. Control references are short-lived: every new observation or action returns
48
50
  fresh references, so use only references from the most recent result.
@@ -66,9 +68,34 @@ Broker activity. The CLI also supports `inspect`, `click`, `fill`, `select`, and
66
68
  `navigate`; run `npx --yes @ai-digital-factory/lmt-web-cli@latest --help` for the
67
69
  complete command list.
68
70
 
71
+ ## Interactive Zerodha login (human)
72
+
73
+ Agents cannot receive the Zerodha OTP, so a human logs the saved Web CLI session
74
+ into Zerodha once and agents then restore it with `start`. Run `lmt-web` with no
75
+ arguments (or `lmt-web interactive`) in a terminal:
76
+
77
+ ```sh
78
+ npx --yes @ai-digital-factory/lmt-web-cli@latest
79
+ ```
80
+
81
+ Use ↑/↓ and Enter to choose **Login to Zerodha** or **Logout from Zerodha**; press
82
+ `q` to quit. Logout asks for `y` to confirm, then uses Web's Logout Zerodha control;
83
+ the Operator stays logged in, so the next login needs only the OTP. Interactive
84
+ mode targets `--env dev --device desktop` by default; pass `--env local` or
85
+ `--device mobile` to log in to another saved session. It restores or reuses that
86
+ saved headless browser, logs in to the Operator with the provisioned SMS credential
87
+ when required, starts the Zerodha Login Attempt, and asks for the OTP as a masked
88
+ six-digit field. An attempt left waiting from earlier (for example by an agent) is
89
+ cancelled first, so every run issues a fresh challenge. A rejected OTP can be
90
+ retried on the same attempt; Esc cancels without submitting. An uncertain submission is never replayed—check the page with
91
+ `inspect` first. On exit, a browser started by interactive mode is stopped (its
92
+ login stays saved); a browser that was already running stays open.
93
+
94
+ Interactive mode requires a terminal; without one it exits with status 2.
95
+
69
96
  ## Install
70
97
 
71
- Requires Node.js 22 or later, Chromium, and a macOS or Linux session owner.
98
+ Requires Node.js 22.13 or later, Chromium, and a macOS or Linux session owner.
72
99
  Install the CLI and its browser:
73
100
 
74
101
  ```sh
@@ -106,7 +133,8 @@ Use `--device desktop` for the 1440 × 900 desktop preset or `--headed` to show
106
133
  the browser window. Desktop uses scale 1, no touch emulation, and the installed
107
134
  Chromium runtime's desktop user agent. Results report the actual preset,
108
135
  viewport, scale, touch support, and user agent. Changing device or browser
109
- visibility requires a new session; these options are accepted only by `start`.
136
+ visibility is selected by `start`. Mobile and desktop keep independent saved sessions.
137
+ To change visibility for an already-live device, close its browser first or use `--fresh`.
110
138
  A visible browser requires an active desktop display. All automated browser tests
111
139
  run headlessly, including mobile and desktop acceptance. `pnpm test` requires no
112
140
  desktop display or Xvfb.
@@ -133,18 +161,70 @@ the page or taking a final screenshot. It also works after the browser window ha
133
161
  been closed manually. Supply the session ID returned by `start`; other sessions
134
162
  remain running. Like `close`, it does not log out or stop Broker activity.
135
163
 
136
- `start` opens the Home Page and returns a session ID. Every later command needs
137
- that ID and talks to the same local browser process without reloading the page.
138
- Concurrent commands within a session run in order. Different session IDs have
139
- separate in-memory browser contexts and storage. A session is owned by the local
140
- user who started it; closing it, losing its owner process, or restarting the
141
- machine requires a new session. The Web CLI does not import `lmt` cookies or
142
- save browser authentication. Closing a browser does not log out, revoke an
143
- Operator Session, or stop Broker activity.
164
+ `start` automatically restores saved authentication for the selected environment,
165
+ Web Origin, and device, or reuses that device's live browser and returns its session
166
+ ID. Every later command needs that ID. Reusing a live browser preserves its current
167
+ page; concurrent commands run in order. Separate mobile and desktop sessions each
168
+ need their own initial login and restore independently thereafter.
169
+
170
+ Closing, stopping, losing the owner process, or restarting the machine preserves
171
+ saved authentication. A subsequent `start` creates a new browser owner and restores
172
+ the same Operator Session cookies when still valid. Gate's expiry, daily-visit
173
+ renewal, revocation, and per-Operator-Session Zerodha authentication remain authoritative.
174
+ Restoration never submits credentials or starts an OTP Challenge. Results include
175
+ `authentication.status` when a recognized Web surface is visible: `operator_login_required`,
176
+ `zerodha_login_required`, or `authenticated`. Follow that state before logging in.
177
+
178
+ Use `start --env dev --device desktop --fresh` for temporary, isolated login-flow
179
+ testing. It neither reads nor overwrites the normal saved session, and its own
180
+ login is not retained after closure. Closing a browser does not log out, revoke an
181
+ Operator Session, or stop Broker activity. Explicit Zerodha logout is retained;
182
+ Operator logout removes that browser's saved Operator Session. Neither logs out
183
+ another device.
184
+
185
+ The CLI saves only cookies applicable to the configured Web Origin, during the
186
+ live session and before successful commands return. It does not persist page
187
+ content, passwords, OTPs, localStorage, or third-party Kite cookies, and never imports
188
+ `lmt` authentication. Saved cookies are replayable authentication stored in private
189
+ SQLite files under `~/.lmt-web/sessions` (directory mode 0700, files 0600). Anyone
190
+ acting as the same OS user can reuse them; keychain encryption is not required.
191
+ `LMT_WEB_STATE_DIRECTORY` overrides the private parent directory for isolated setups.
192
+ Unsafe ownership/permissions, symlinks, or corrupt state fail explicitly with
193
+ `saved_session_unavailable`; there is no silent fallback that overwrites bad state.
194
+ Cookies already committed before a process failure can be restored; a failure between
195
+ a server change and its local checkpoint can still require login. Server-side logout
196
+ or revocation cannot be reversed by an older saved cookie.
197
+
198
+ Results distinguish action completion from the browser's authentication state.
199
+ For example, a successful `operator-login` can return:
200
+
201
+ ```json
202
+ {"outcome":"success","authentication":{"status":"zerodha_login_required","nextAction":"zerodha-login"}}
203
+ ```
204
+
205
+ `authentication.status` is `operator_login_required`, `zerodha_login_required`,
206
+ `zerodha_session_restoring`, `authenticated`, or `unknown`. It observes the
207
+ rendered session surface, including Settings, rather than inferring admission
208
+ from a URL or saved token presence.
209
+ Unrecognized, conflicting, or unavailable page observations return `unknown`;
210
+ a generic loading screen that exceeds the command deadline also returns
211
+ `unknown` alongside the existing action error. `stop` has no page observation
212
+ and returns `unknown`.
213
+
214
+ When present, `authentication.nextAction` names `operator-login`, `zerodha-login`,
215
+ or `zerodha-otp`. The OTP action includes `authentication.attemptId` for the active
216
+ challenge, also available through `inspect`. It is omitted while an attempt is
217
+ submitting or is no longer accepting OTPs; inspect the page and its error before
218
+ deciding to retry. Supply the OTP through `--stdin` with that attempt ID in the
219
+ same browser session. No login or OTP submission is performed by inspection.
220
+ After successful OTP submission, `authentication.status` is `authenticated`.
221
+ Keep that session alive for Market Watch and pairing QA; `lmt` authentication
222
+ does not transfer to a new `lmt-web` session.
144
223
 
145
224
  Each command writes one versioned JSON result to stdout and diagnostics to
146
225
  stderr. Results contain the action outcome, current URL, visible page text and
147
- controls, emulated device and actual viewport, and screenshot outcome. Images
226
+ controls, `authentication`, emulated device and actual viewport, and screenshot
227
+ outcome. Images
148
228
  are written to unique absolute paths in an owner-only temporary directory;
149
229
  screenshots solid-mask only Zerodha access-token value fields marked with
150
230
  `data-lmt-sensitive="zerodha-access-token"`; other controls and metadata stay visible.
@@ -155,8 +235,11 @@ session-loading or busy indicators, fonts, visible images, and finite animations
155
235
  to finish. The page must render text, controls, or visual content; an empty app
156
236
  root is not ready. Pages that remain empty reach the command deadline without a
157
237
  captured screenshot. Infinite animations do not block capture. `--timeout` sets one deadline for the command's browser action and
158
- screenshot, from `1ms` through `10m`. If an operation exceeds it, the session is
159
- closed. Action failures return nonzero; invalid commands and targets return exit code 2.
238
+ screenshot, from `1ms` through `10m`. A recoverable action timeout stops pending loading, waits for the operation to
239
+ settle, and retains a responsive browser. Unsettled work, an unresponsive renderer,
240
+ or an overall inspection/capture deadline can close the owner; use `start` to
241
+ restore saved authentication. Submitted actions remain uncertain and are never
242
+ automatically replayed. Action failures return nonzero; invalid commands and targets return exit code 2.
160
243
  The JSON `error.code` is machine-readable:
161
244
 
162
245
  | Code | Exit | Meaning |
@@ -165,7 +248,8 @@ The JSON `error.code` is machine-readable:
165
248
  | `browser_unavailable` | 1 | Install Chromium with `lmt-web install-browser`, then retry. |
166
249
  | `browser_start_failed` | 1 | The local browser owner exited before its session became ready. |
167
250
  | `service_unavailable` | 1 | The selected Web URL could not be reached; start/check that service. |
168
- | `session_not_found`, `session_unavailable` | 1 | The browser owner ended; start a fresh session. |
251
+ | `session_not_found`, `session_unavailable` | 1 | The browser owner ended; use `start` to restore it. |
252
+ | `saved_session_unavailable` | 1 | Check ownership, private permissions, and integrity of saved-session storage. |
169
253
  | `deadline_exceeded`, `action_failed` | 1 | The action failed or exceeded its finite deadline. |
170
254
 
171
255
  Screenshots cover the viewport by default. `inspect --full-page` and
@@ -216,8 +300,9 @@ also accept `--timeout` and `--full-page`.
216
300
  Credential fields are detected from their type, labels, and attributes. Use
217
301
  `fill --secret` for sensitive values in other fields. Entered secrets remain in the
218
302
  live session's redaction registry, including when echoed into text or revealed in
219
- an input. JSON observations omit field values and redact secret text. Screenshots
220
- show the rendered page without additional masking.
303
+ an input. General JSON observations omit field values and redact secret text; explicit
304
+ reads follow the ordinary-value/secret-metadata contract below. Screenshots mask secret
305
+ values and their learned echoes.
221
306
  A click whose completion cannot be confirmed returns `outcome: "uncertain"` and a
222
307
  nonzero exit status. Pending browser loading is stopped to retain evidence, but the
223
308
  submitted server operation may still complete. Inspect before deciding what to do
@@ -335,6 +420,7 @@ this check performs no npm publication or live dev login.
335
420
  ```sh
336
421
  lmt-web read --session ID --ref FIELD
337
422
  lmt-web clipboard --session ID
423
+ lmt-web paste --session ID --ref FIELD
338
424
  lmt-web check --session ID --ref FIELD --stdin < /path/to/protected-expectation
339
425
  lmt-web clipboard-check --session ID --ref FIELD
340
426
  lmt-web scroll --session ID --ref FIELD
@@ -342,19 +428,49 @@ lmt-web scroll --session ID --y 600
342
428
  lmt-web inspect --session ID --full-page
343
429
  ```
344
430
 
345
- read returns an ordinary field value. clipboard returns content only when it matches
346
- a verified ordinary field on the current page; unknown or secret content is refused.
431
+ `read` returns `value` for an ordinary field, including Settings User ID. A protected
432
+ field returns only `secret: {present, length, fingerprint}`. `fingerprint` is the
433
+ 12-hex SHA-256 prefix used in Broker token logs, or null for an empty value.
434
+ `clipboard` returns an ordinary value only when it matches a verified ordinary field;
435
+ otherwise it returns the same safe secret metadata. Reveal the saved token before
436
+ reading it: hidden/capture-safe placeholders report `value_unreadable`, never metadata
437
+ for the placeholder. Copy still permits safe clipboard metadata in capture-safe mode.
347
438
  check compares the field with one stdin-supplied expectation (an optional final newline
348
439
  is removed). clipboard-check compares clipboard and field inside the browser session.
349
440
  Comparisons return only matches: true or matches: false. An unreadable field/clipboard
350
441
  or an expired reference is an error without a matches result. Inspect/action observations
351
442
  continue to redact secrets, including revealed fields.
352
443
 
444
+ `paste` reads the clipboard and updates a protected input or textarea entirely inside
445
+ the browser. It returns secret metadata and `matches: true` only after the field retains
446
+ the value. It does not submit the form. Read-only, ordinary, missing or rejecting fields
447
+ and unreadable clipboards fail explicitly. A failed paste has no equality result.
448
+
449
+ For current-token verification, use the existing saved browser session: navigate to
450
+ Settings, click Copy access token, inspect clipboard metadata, click Replace access token,
451
+ then `paste --ref` the Replacement access token input. Use fresh references from each
452
+ result. `clipboard-check` can prove the pasted field matches. Explicitly click Validate
453
+ and replace and inspect the resulting verification or refusal message. All actions use
454
+ the rendered controls; no HTTP Runner profile or direct API probing is required.
455
+
456
+ Screenshots mask protected field values and learned secret echoes while keeping ordinary
457
+ fields and labels readable. Every result still includes its independent screenshot outcome.
458
+ Same-origin browser requests carry `x-lmt-client-kind: cli` and
459
+ `x-lmt-client-profile: web-cli-desktop|web-cli-mobile`. Control actions also send a
460
+ `journey_step` audit through the browser to Gate's existing `/api/journey-records` ingest:
461
+ step `Web CLI <action>`, browser session correlation, CLI attribution, action outcome and
462
+ screenshot outcome only. No field/clipboard value, reference label or payload is logged.
463
+ `audit.outcome` reports `recorded` only for HTTP 202; `failed`/`unavailable` means logging
464
+ has not been established and does not reverse an already completed browser action.
465
+ In OpenObserve, discover the current `journey_step` fields and filter by step, browser
466
+ session and the bounded run window; join API traces using the attributed request rows.
467
+
353
468
  Referenced scrolling brings the control into view through its ancestors. Pixel scrolling
354
469
  targets the largest scrolling content area. Results include before/after positions and
355
470
  moved, already_visible, or at_boundary. Each observation expires older references.
471
+ A referenced control still outside the clipped visible area reports `target_unreachable`.
356
472
 
357
473
  Full-page capture temporarily expands inner scrolling content and restores its styles
358
474
  and positions afterward. A screenshot with unexpanded clipped content reports failed;
359
- browser-action and screenshot outcomes remain separate. Screenshots retain the existing
360
- rendered-page confidentiality behavior: protect their files as you would the visible UI.
475
+ browser-action and screenshot outcomes remain separate. Protect screenshot files as
476
+ evidence even though their secret values are masked.