@ai-digital-factory/lmt-cli 0.1.5 → 1.0.0
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 +175 -51
- package/dist/chunk-4N3XUBM4.js +1483 -0
- package/dist/chunk-7J2U4G5L.js +1394 -0
- package/dist/chunk-AQIOT6YD.js +2799 -0
- package/dist/chunk-DUF5HVSQ.js +58 -0
- package/dist/controller-app-UTLE4YVF.js +1382 -0
- package/dist/credential-app-QEFV6LZM.js +6 -0
- package/dist/index.js +8 -3536
- package/dist/menu-actions-HV2AY4KJ.js +67 -0
- package/dist/src-MZYWVU46.js +380 -0
- package/dist/web-5HW6PMSA.js +9 -0
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -20,26 +20,44 @@ npm list --global @ai-digital-factory/lmt-cli --depth=0
|
|
|
20
20
|
|
|
21
21
|
The package includes the non-secret Origins, Gate scopes, and SMS endpoint. Choose `--env dev` for the deployed dev service, or `--env local` for a running local stack. Only `local` and `dev` are supported; `prod` is rejected. Installing the CLI does not start services or provision credentials.
|
|
22
22
|
|
|
23
|
-
|
|
23
|
+
`@ai-digital-factory/lmt-web-cli` (the former `lmt-web` executable) is deprecated on npm. Its commands are the `lmt web` command group of this package; there is no `lmt-web` alias.
|
|
24
24
|
|
|
25
|
-
|
|
25
|
+
## Daily routine: the Operator and the Controller
|
|
26
|
+
|
|
27
|
+
The **Controller** is the automated agent that operates Live Market Terminal through `lmt` and `lmt web`. It authenticates with the **Controller Session**: one Operator Session per environment, shared by every HTTP command, every `lmt web` browser (mobile and desktop), every worktree and every local port that reaches the same Gate.
|
|
28
|
+
|
|
29
|
+
1. **Once per trading day, the Operator runs `lmt`** in a terminal, chooses the environment and picks **Log in**. The Operator is unlocked from SMS and the Operator types only the one Kite OTP. The Zerodha access token expires daily, so this is repeated each trading day. If the SMS read credential is missing, the Operator runs `lmt credential provision` once first.
|
|
30
|
+
2. **The Controller runs `lmt status --env <env>` before any other step.** Exit 0 (`outcome: "success"`) means the Controller Session is usable, so the Controller continues:
|
|
31
|
+
|
|
32
|
+
```sh
|
|
33
|
+
lmt status --env local
|
|
34
|
+
lmt status --env dev
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
3. **Blocked means exit 4.** `outcome: "blocked"` and its `nextStep` say what is missing: `lmt` (log in) or `lmt credential provision` (no SMS credential). The Controller then asks the Operator once to run that command and waits. It asks before starting the task, never in the middle of it. Every command that needs the Controller Session (`settings`, `token`, `pair`, `candle-export`, `zerodha` and `lmt web start`) returns the same exit 4 and `nextStep` when it is unusable.
|
|
38
|
+
|
|
39
|
+
The Controller reuses the shared local Gate and Broker and never starts its own. It never asks for OTPs, passwords or credentials in chat, and never logs the Controller Session out. Checks that must log in or out on their own use `--profile NAME` (a CLI Client Profile) or `lmt web start --fresh`, both of which leave the Controller Session untouched.
|
|
40
|
+
|
|
41
|
+
## Candle Export for the Controller
|
|
42
|
+
|
|
43
|
+
With the Controller Session logged in, request one instrument and optional IST date:
|
|
26
44
|
|
|
27
45
|
```sh
|
|
28
|
-
lmt candle-export NSE:IDEA --date 2026-10-23 --env dev --
|
|
46
|
+
lmt candle-export NSE:IDEA --date 2026-10-23 --env dev --timeout 2m
|
|
29
47
|
```
|
|
30
48
|
|
|
31
49
|
Omitting `--date` asks Broker for the exchange's latest completed trading session, accounting for holidays and Finalization Grace. The stdout JSON `candleExport` contains the immutable Hosted URL, filename, resolved identity/date, source availability, reference-fetch metadata, and comparison counts. Missing data or Zerodha authentication is explained in the workbook. Export does not start Zerodha login or token recovery. Local/dev only; see `lmt --help` for exit conventions.
|
|
32
50
|
|
|
33
|
-
## Price Cross pairs for
|
|
51
|
+
## Price Cross pairs for the Controller
|
|
34
52
|
|
|
35
|
-
Price Cross runs in Paper mode only. These commands reach the owning Broker through Gate with the
|
|
53
|
+
Price Cross runs in Paper mode only. These commands reach the owning Broker through Gate with the Controller Session. They never save Settings, so the Settings Version does not change. They never place Orders, and the CLI has no strategy store or Kite client of its own.
|
|
36
54
|
|
|
37
55
|
```sh
|
|
38
|
-
lmt pair list --env dev
|
|
39
|
-
lmt pair assign --ce 1 --pe 3 --lots 2 --env dev
|
|
40
|
-
lmt pair report PAIR_ID --output ./pair.xlsx --env dev
|
|
41
|
-
lmt pair report PAIR_ID --publish --env dev
|
|
42
|
-
lmt pair unpair PAIR_ID --confirm --env dev
|
|
56
|
+
lmt pair list --env dev
|
|
57
|
+
lmt pair assign --ce 1 --pe 3 --lots 2 --env dev
|
|
58
|
+
lmt pair report PAIR_ID --output ./pair.xlsx --env dev
|
|
59
|
+
lmt pair report PAIR_ID --publish --env dev
|
|
60
|
+
lmt pair unpair PAIR_ID --confirm --env dev
|
|
43
61
|
```
|
|
44
62
|
|
|
45
63
|
| Command | Success JSON (one line on stdout) |
|
|
@@ -50,7 +68,7 @@ lmt pair unpair PAIR_ID --confirm --env dev --profile runner
|
|
|
50
68
|
| `pair report` | Downloads the lifetime workbook unchanged. `report.path`, `report.bytes`, `report.sha256` and `report.decisionCount` describe it. Without `--output`, the file is saved under the server filename in the current directory and an existing file is never overwritten. |
|
|
51
69
|
| `pair report --publish` | `report.url` is a new immutable Hosted URL. It matches the `exportUrl` field on the Broker's `price_cross_report_snapshot_published` log. Publishing again gives a new URL and leaves the old one unchanged. |
|
|
52
70
|
|
|
53
|
-
Exit codes: 0 success; 1 refusal or uncertain; 2 invalid invocation (including `--env prod`); 3 Operator Login required.
|
|
71
|
+
Exit codes: 0 success; 1 refusal or uncertain; 2 invalid invocation (including `--env prod`); 3 Operator Login required (`--profile` only); 4 blocked because the Controller Session is unusable.
|
|
54
72
|
|
|
55
73
|
**Refusals.** A refusal is `outcome: "fail"` with exit 1, and `reason` and `error.code` both hold the Broker's code, unchanged. The codes are `invalid_lots` (Pair Lots outside 1 through the configured maximum, default 10), `same_type`, `already_paired`, `order_in_flight`, `real_position_open`, `row_unavailable`, `row_empty`, the `*_mismatch` codes, `flag_disabled`, `store_unavailable` and, for reports, `pair_not_found`. Each assign refusal matches the `fields_reason` on its `pair_refused` log. `pair unpair` without `--confirm` is refused locally with exit 2 and sends nothing.
|
|
56
74
|
|
|
@@ -72,52 +90,66 @@ Run this outside 09:15–15:30 IST, using a same-expiry CE row and PE row alread
|
|
|
72
90
|
|
|
73
91
|
Automated coverage: `pnpm --filter @ai-digital-factory/lmt-cli test` runs `src/pair-commands.test.ts` (stubbed Gate) and `integration/price-cross-pairs.test.ts`. The integration test uses real Gate and Broker, a temporary Price Cross Store and a recording order client that must see zero calls. It also covers flag-off: existing pairs are listed and can be Unpaired, and a new assign is refused with `flag_disabled`.
|
|
74
92
|
|
|
75
|
-
## Quick start: interactive
|
|
93
|
+
## Quick start: interactive login
|
|
76
94
|
|
|
77
|
-
1. Obtain
|
|
78
|
-
2.
|
|
95
|
+
1. Obtain an SMS read credential authorized to read `live-market-terminal-operator-directory` in the selected Gate scope from your administrator. You never type the Operator Login username or password; the CLI reads them from SMS.
|
|
96
|
+
2. Provision the credential once using the masked prompt:
|
|
79
97
|
|
|
80
98
|
```sh
|
|
81
|
-
lmt
|
|
99
|
+
lmt credential provision
|
|
82
100
|
```
|
|
83
101
|
|
|
84
|
-
Paste the SMS read credential and press Enter.
|
|
85
|
-
3. Open the interactive terminal:
|
|
102
|
+
Paste the SMS read credential and press Enter. The prompt shows `SMS credential saved.` and exits. The credential is stored in `~/.lmt/secrets.pem` and shared by every profile and every LMT CLI command, including `lmt web operator-login` in fresh browser sessions.
|
|
103
|
+
3. Open the interactive terminal (a terminal is required; without one it exits 2):
|
|
86
104
|
|
|
87
105
|
```sh
|
|
88
|
-
lmt
|
|
106
|
+
lmt
|
|
89
107
|
```
|
|
90
108
|
|
|
91
|
-
|
|
92
|
-
4.
|
|
109
|
+
The first screen chooses the Deployment Environment: `local` or `dev`, each with its resolved Origin. Production is never listed. Your last confirmed choice is pre-selected (`local` on first use) and remembered in `~/.lmt/preferences.json`, an owner-only file kept apart from secrets. `lmt --env local` (or `--env dev`) skips this screen. `--device mobile|desktop` pre-selects the Web menu's device and is shown in the header.
|
|
110
|
+
4. The main menu header shows `<env> · <origin> · <login state>`, where the state is `logged in`, `needs Zerodha login`, `needs login` or `SMS credential missing`, from the same check as `lmt status`. Choose with ↑/↓ and Enter; Esc returns to the environment screen.
|
|
111
|
+
* **Log in** restores the Controller Session when Gate still accepts it, otherwise unlocks the Operator from SMS. It then starts a Zerodha login and asks for the six-digit OTP (masked). A rejected OTP can be re-entered without restarting. When already logged in, the item says so and starts no Zerodha attempt. Without an SMS credential it offers the provision prompt and returns to the menu.
|
|
112
|
+
* **Status** shows the `lmt status` fields.
|
|
113
|
+
* **Log out** asks `Log out of <env> everywhere? y/N` and ends the Controller Session for every command and device.
|
|
114
|
+
* **Settings**, **Token**, **Pairs**, **Candle Export**, **Zerodha**, **Checks** and **Credential** offer every headless HTTP command without remembering an argument: Settings Read and Edit and save (Market Protection, Entry Categories, and an optional all-four-field Zerodha Credentials replacement), Token Read, Replace and Verify current, Pairs List, Assign, Unpair (explicit confirm) and Report (Publish or Save, warning before an overwrite), Candle Export, Zerodha Status, Observe attempt, Start login and OTP, Validate and Resume Zerodha Validation, Validate Operator Session, and Provision SMS credential. Validate Zerodha Session always starts a new Zerodha login, so when Zerodha is already logged in it asks first; it then asks for the OTP in place (a rejected OTP can be re-entered). Each item calls the same action as its headless command and submits once. An uncertain result says so and names the read to make first; nothing is resubmitted automatically. Refusals show their reason code. Secret inputs are masked and never shown. Items that need a usable Controller Session say `Log in first` and offer Log in. Esc goes back one level.
|
|
115
|
+
* **Web** runs every `lmt web` command without typing session IDs or control references. **Start browser** picks the device and headless or visible and opens a browser with the Controller Session; when the Controller Session is not authenticated it shows "Log in first" and Enter jumps to Log in. **Sessions** lists the environment's live browsers (id, device, URL) and makes the chosen one current. **Inspect** (or **Inspect full page**) shows the title, URL, Origin, screenshot path and numbered controls `n. [kind] label`. **Act on a control** picks a number from the latest result, then Click, Fill (masked for password-like fields; Tab marks any value secret), Read (secret fields show only present, length and fingerprint), Select (type the option), Paste, Check (masked expected value), Clipboard-check or Scroll. If the page changed, the stale-reference error is shown and you must Inspect again; old numbers are never reused. **Clipboard**, **Navigate** (type a path or URL), **Scroll** (↑/↓, PgUp/PgDn, ←/→), **Close** (optionally with a full-page screenshot), **Stop** and **Install browser** complete the set. **Fresh login test** starts a `--fresh` browser, isolated from the Controller Session, with Operator login/logout and Zerodha login, OTP (masked), cancel and logout. Every result shows its screenshot path. `--profile` Controllers have no Web item.
|
|
116
|
+
* **Quit** exits.
|
|
93
117
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
Interactive mode defaults to `--env local --profile default` when these options are omitted. Keep the same environment and profile across commands to reuse a session:
|
|
118
|
+
The Controller Session is normally established once per trading day, because the Zerodha access token expires daily. Afterwards every HTTP and `lmt web` command can use it:
|
|
97
119
|
|
|
98
120
|
```sh
|
|
99
|
-
lmt status --env dev
|
|
121
|
+
lmt status --env dev
|
|
100
122
|
```
|
|
101
123
|
|
|
124
|
+
`lmt interactive --env dev --profile NAME` logs in an isolated CLI Client Profile instead and shows `profile: NAME` in the header.
|
|
125
|
+
|
|
102
126
|
## Headless Operator login and sessions
|
|
103
127
|
|
|
104
|
-
Headless commands require
|
|
128
|
+
Headless commands require `--env`. They never prompt for input. Without `--profile`, every command uses the **Controller Session**: the one Operator Session the Controller holds per environment. It is keyed by environment and Operator, not by local Origin, so every checkout and local port reaching the same Gate shares it. `--profile NAME` selects an isolated CLI Client Profile instead; logging a profile in or out never touches the Controller Session. Provision the SMS credential using the masked interactive command above, then run:
|
|
105
129
|
|
|
106
130
|
```sh
|
|
107
|
-
lmt login --env dev
|
|
108
|
-
lmt status --env dev
|
|
109
|
-
lmt validate operator-session --env dev
|
|
110
|
-
lmt logout --env dev
|
|
131
|
+
lmt login --env dev
|
|
132
|
+
lmt status --env dev
|
|
133
|
+
lmt validate operator-session --env dev
|
|
134
|
+
lmt logout --env dev
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
`login` reads the configured Operator's username and password from the selected Gate scope's SMS Operator Directory and authenticates through Gate. SMS reads invoke `@ai-digital-factory/sms-cli@0.1.2` through npx, so npm registry access is needed when it is not cached. Validation exercises login and session behavior using a temporary profile, logs out its temporary sessions, and removes only its temporary records; it never ends the Controller Session.
|
|
138
|
+
|
|
139
|
+
`status` prints one JSON line and never creates or replaces a session:
|
|
140
|
+
|
|
141
|
+
```json
|
|
142
|
+
{"version":1,"command":"status","outcome":"blocked","environment":"local","origin":"http://127.0.0.1:5199","session":"controller","smsCredential":"present","operatorSession":"valid","zerodha":"unauthenticated","nextStep":"Run `lmt` in a terminal to log in"}
|
|
111
143
|
```
|
|
112
144
|
|
|
113
|
-
`
|
|
145
|
+
`outcome` is `success` (exit 0) only when `operatorSession` is `valid` and `zerodha` is `authenticated`. Otherwise it is `blocked` (exit 4) with a `nextStep`: `lmt credential provision` when `smsCredential` is `missing`, else `lmt`. A session Gate rejects is cleared locally and reported `expired`; it is never silently re-authenticated. Gate being unreachable is `failure` (exit 1). With `--profile`, `session` is `profile` and `profile` names it. Commands needing an authenticated Controller Session (settings, token, pair, candle-export, zerodha) return `blocked`, exit 4 and the same `nextStep` when it is unusable.
|
|
114
146
|
|
|
115
147
|
`logout` revokes the Operator Session through Gate and clears its saved cookies and pending Zerodha attempt. If Gate cannot confirm logout, the command fails and retains cookies for retry. Other profiles, the shared SMS credential, and Broker-owned SMS access tokens remain intact.
|
|
116
148
|
|
|
117
149
|
For automated credential provisioning, pipe one non-empty credential line through protected stdin:
|
|
118
150
|
|
|
119
151
|
```sh
|
|
120
|
-
lmt credential provision --env dev --
|
|
152
|
+
lmt credential provision --env dev --credential-stdin < /path/to/protected-sms-credential-file
|
|
121
153
|
```
|
|
122
154
|
|
|
123
155
|
Replace the path with an owner-readable credential file supplied by your secret-management process. Keep SMS credentials, passwords, and cookies out of command arguments. Provisioning saves the credential locally; it does not verify SMS access.
|
|
@@ -165,15 +197,94 @@ An expired, canceled, replaced, or failed attempt fails without starting a new l
|
|
|
165
197
|
|
|
166
198
|
Profiles save Client Identity and Operator Session cookies across invocations. Sessions are isolated by profile, environment, canonical Origin, and configured Operator. Profile names must be 1–64 letters, digits, dots, underscores, or hyphens, starting with a letter or digit.
|
|
167
199
|
|
|
168
|
-
Storage is `~/.lmt/secrets.pem`: a protected JSON file containing the shared SMS credential and per-profile cookies. The CLI enforces owner-only permissions and migrates legacy storage automatically. Do not share this file or include it in logs or version control.
|
|
200
|
+
Storage is `~/.lmt/secrets.pem`: a protected JSON file containing the shared SMS credential, the Controller Session per environment (a dedicated `controllerSessions` field, so no profile name can collide with it) and per-profile cookies. The CLI enforces owner-only permissions and migrates legacy storage automatically. Do not share this file or include it in logs or version control.
|
|
201
|
+
|
|
202
|
+
For local use, first start Web, Gate, and Broker from a configured source checkout with `pnpm dev:local` in `live-market-terminal/`. The installed CLI uses the bundled canonical local Origin (`http://127.0.0.1:5173`) through Web's `/api` proxy; it does not fall back to a different port.
|
|
203
|
+
|
|
204
|
+
**Different local port.** When the CLI runs with `--env local` from anywhere inside a checkout (the nearest ancestor with a `.git` directory or worktree file), it reads that checkout's gitignored, repository-root `lmt.config.local.json`. If it sets `environments.local.origin`, for example `{"environments":{"local":{"origin":"http://127.0.0.1:5199"}}}`, both HTTP commands and `lmt web` commands use that Origin; `lmt web` results report it as `origin`. No environment variable is needed. Only the local Origin is read from that file: `--env dev`, `smsEndpoint`, Gate scope and Operator always come from the packaged configuration. An unreadable or invalid file, or a local Origin with credentials, a path, a query or a fragment, fails `--env local` commands with exit code 2 and `invalid_local_config`. The CLI's SMS read credential is separate from the service credential used by Gate and Broker.
|
|
205
|
+
|
|
206
|
+
```sh
|
|
207
|
+
lmt --env local
|
|
208
|
+
lmt status --env local
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
## Browser sessions (`lmt web`)
|
|
169
212
|
|
|
170
|
-
|
|
213
|
+
`lmt web` drives Live Market Terminal Web in a Playwright Chromium browser and returns structured JSON observations and screenshots. Install its browser runtime once per machine (`--with-deps` also installs Linux system packages):
|
|
171
214
|
|
|
172
215
|
```sh
|
|
173
|
-
lmt
|
|
174
|
-
lmt
|
|
216
|
+
lmt web install-browser
|
|
217
|
+
lmt web --help
|
|
175
218
|
```
|
|
176
219
|
|
|
220
|
+
Start a browser, observe it, and end it:
|
|
221
|
+
|
|
222
|
+
```sh
|
|
223
|
+
lmt web start --env dev --device desktop
|
|
224
|
+
lmt web inspect --session SESSION_ID
|
|
225
|
+
lmt web inspect --session SESSION_ID --full-page
|
|
226
|
+
lmt web close --session SESSION_ID --full-page
|
|
227
|
+
lmt web stop --session SESSION_ID
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
`lmt web start` opens a browser already authenticated by the environment's Controller Session: it adds the Controller Session's Operator Session and Client Identity cookies before opening the Home Page, so neither device logs in again. Desktop and mobile each keep one live browser, tracked in an owner-only `owners.json` beside the session sockets. When Gate renews the Operator Session cookie in the browser, the new value is written back to the Controller Session. Cookies never appear in output.
|
|
231
|
+
|
|
232
|
+
If the Controller Session is not authenticated (as `lmt status` would report), `lmt web start` prints `outcome: "blocked"` with a `nextStep` naming `lmt`, exits 4, and opens no browser. After `lmt logout`, Gate rejects the Controller Session for every browser and command; browser processes that are already open keep running until `lmt web stop`.
|
|
233
|
+
|
|
234
|
+
`lmt web start --fresh` opens a temporary, isolated browser that never reads or writes the Controller Session. The browser login commands (`operator-login`, `operator-logout`, `zerodha-login`, `zerodha-otp`, `zerodha-cancel`, `zerodha-logout`) exist only to test the login screens, so they run only in fresh sessions; on any other session they exit 2 with `fresh_session_required`. `lmt web interactive` is retired: run `lmt` in a terminal to log in.
|
|
235
|
+
|
|
236
|
+
### Test the login screens with `--fresh`
|
|
237
|
+
|
|
238
|
+
Use `--fresh` only when a check must see the Home or Zerodha Login Page. A fresh browser starts logged out and is discarded when it closes:
|
|
239
|
+
|
|
240
|
+
```sh
|
|
241
|
+
lmt web start --env dev --device desktop --fresh
|
|
242
|
+
lmt web operator-login --session SESSION_ID
|
|
243
|
+
lmt web zerodha-login --session SESSION_ID
|
|
244
|
+
lmt web zerodha-otp --session SESSION_ID --attempt ATTEMPT_ID --stdin < /path/to/protected-otp
|
|
245
|
+
lmt web zerodha-logout --session SESSION_ID
|
|
246
|
+
lmt web operator-logout --session SESSION_ID
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
`operator-login` fills the rendered Home Page form with the Operator read from SMS, using the shared credential in `~/.lmt/secrets.pem` (provision it with `lmt credential provision`). `zerodha-login` returns `loginAttempt.attemptId` with `status: awaiting_otp`; supply that attempt's fresh six-digit OTP on standard input to `zerodha-otp`. The tool never retrieves an OTP or repeats a submission. A rejected OTP can be retried while the same attempt is active. A fresh Zerodha login still uses the Operator's Broker-owned shared state, so it can replace the Operator's active attempt; agents ask the Operator before running it.
|
|
250
|
+
|
|
251
|
+
### Interact with the page
|
|
252
|
+
|
|
253
|
+
Every action returns an updated observation and screenshot, captured once the page has rendered and its pending data requests (fetch and XHR, not EventSource streams) have finished. Use the control references (`--ref`) from the latest result; they expire with the next observation, and missing, stale or duplicate references fail explicitly.
|
|
254
|
+
|
|
255
|
+
```sh
|
|
256
|
+
lmt web fill --session SESSION_ID --ref REF --value "draft text"
|
|
257
|
+
lmt web click --session SESSION_ID --ref REF
|
|
258
|
+
lmt web select --session SESSION_ID --ref REF --value NSE
|
|
259
|
+
lmt web scroll --session SESSION_ID --y 500
|
|
260
|
+
lmt web navigate --session SESSION_ID --url /operator
|
|
261
|
+
lmt web read --session SESSION_ID --ref REF
|
|
262
|
+
lmt web clipboard --session SESSION_ID
|
|
263
|
+
lmt web paste --session SESSION_ID --ref REF
|
|
264
|
+
lmt web check --session SESSION_ID --ref REF --stdin < /path/to/protected-expectation
|
|
265
|
+
lmt web clipboard-check --session SESSION_ID --ref REF
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
Navigation accepts a path or URL within the session's Origin. Credential fields are detected automatically; use `fill --secret` for other sensitive values. `read` returns `value` for an ordinary field; protected fields, secret reads and clipboard observations return only `present`, `length` and a 12-hex SHA-256 `fingerprint`. Screenshots mask secret values. A click whose completion cannot be confirmed returns `outcome: "uncertain"` and a nonzero exit; inspect before deciding what to do, because the CLI never repeats it.
|
|
269
|
+
|
|
270
|
+
Mobile emulation (`iPhone 13`, 390 × 844) and headless mode are the defaults. `--device desktop` selects the 1440 × 900 desktop preset and `--headed` shows the window. On Dev Deployment, open the Web UI with `?captureSafe=1` on the first navigation (for example `lmt web navigate --session SESSION_ID --url /?captureSafe=1`) to keep Capture-safe Mode on for that tab. Screenshots mask access-token values even without it.
|
|
271
|
+
|
|
272
|
+
### Worktree screenshots
|
|
273
|
+
|
|
274
|
+
To screenshot a worktree's Web on its own port, run that worktree's Web server against the running local Gate, and set the port in the worktree's gitignored `lmt.config.local.json` (see [Different local port](#profiles-and-local-use)). Then, from inside that worktree:
|
|
275
|
+
|
|
276
|
+
```sh
|
|
277
|
+
lmt status --env local
|
|
278
|
+
lmt web start --env local --device desktop
|
|
279
|
+
lmt web navigate --session SESSION_ID --url /settings
|
|
280
|
+
lmt web inspect --session SESSION_ID --full-page
|
|
281
|
+
lmt web stop --session SESSION_ID
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
No environment variable is involved. `lmt web start` reports the targeted `origin`; confirm it is the worktree's port before comparing screenshots. The Controller Session belongs to the local Gate, so every worktree reuses it without logging in again.
|
|
285
|
+
|
|
286
|
+
Browser commands need Node.js 22 or later, like every `lmt` command, and the Chromium runtime from `lmt web install-browser`.
|
|
287
|
+
|
|
177
288
|
## Output, deadlines, and troubleshooting
|
|
178
289
|
|
|
179
290
|
Headless commands write one versioned JSON object per line to stdout; diagnostics go to stderr. Inspect `outcome`, `reason`, and, on failure, `error`. Use the process exit code for automation:
|
|
@@ -183,8 +294,8 @@ Headless commands write one versioned JSON object per line to stdout; diagnostic
|
|
|
183
294
|
| `0` | Success or validation pass | Continue. |
|
|
184
295
|
| `1` | Action failure | Read the diagnostic; check SMS permissions or service reachability. |
|
|
185
296
|
| `2` | Invalid invocation or target | Check `lmt --help`; supply `local` or `dev` and a valid profile. |
|
|
186
|
-
| `3` | Operator Login required | Run `login` or interactive login with the same environment and profile. |
|
|
187
|
-
| `4` |
|
|
297
|
+
| `3` | Operator Login required (`--profile` only) | Run `login` or interactive login with the same environment and profile. |
|
|
298
|
+
| `4` | Blocked: Controller Session unusable, validation blocked, or Zerodha awaiting OTP | Run the `nextStep`; for `awaiting_otp`, obtain the Kite OTP and run `zerodha otp --attempt ID --otp-stdin`. |
|
|
188
299
|
|
|
189
300
|
Actions default to 30 seconds; validation defaults to 2 minutes. Headless actions and validation accept a finite deadline between 1 millisecond and 10 minutes:
|
|
190
301
|
|
|
@@ -194,7 +305,7 @@ lmt validate operator-session --env dev --profile my-dev-session --timeout 2m
|
|
|
194
305
|
```
|
|
195
306
|
|
|
196
307
|
- **`lmt: command not found`:** confirm the global installation with `npm list --global @ai-digital-factory/lmt-cli --depth=0` and add npm's global executable directory to PATH (`npm prefix --global`, then `bin/` on macOS/Linux).
|
|
197
|
-
- **Missing SMS credential:** run `lmt
|
|
308
|
+
- **Missing SMS credential:** run `lmt credential provision` and retry. The credential is shared, but it needs access to the scope used by your chosen environment.
|
|
198
309
|
- **SMS unavailable or invalid Operator Directory:** check the credential's read access and the selected Gate scope's Operator Directory with your administrator.
|
|
199
310
|
- **Session expired or rejected:** the CLI clears rejected session cookies. Log in again explicitly using the same profile and environment.
|
|
200
311
|
- **Origin or Broker unavailable:** check the selected deployment. For local use, keep the full stack running at the canonical Origin. `status` requires Broker to be available even when Gate still accepts the session.
|
|
@@ -204,8 +315,8 @@ lmt validate operator-session --env dev --profile my-dev-session --timeout 2m
|
|
|
204
315
|
For contributors, from `live-market-terminal/`:
|
|
205
316
|
|
|
206
317
|
```sh
|
|
207
|
-
pnpm cli --env dev
|
|
208
|
-
pnpm -s cli:headless status --env dev
|
|
318
|
+
pnpm cli --env dev
|
|
319
|
+
pnpm -s cli:headless status --env dev
|
|
209
320
|
pnpm --filter @ai-digital-factory/lmt-cli interactive credential provision --env dev
|
|
210
321
|
```
|
|
211
322
|
|
|
@@ -215,7 +326,7 @@ These repository scripts rebuild the CLI. The published commands above run direc
|
|
|
215
326
|
|
|
216
327
|
The **Release LMT CLI** GitHub Action is dispatched manually on `main`. It builds
|
|
217
328
|
current `main`, tests the CLI, builds a standalone package with bundled private
|
|
218
|
-
contracts, selects the next npm
|
|
329
|
+
contracts, selects the next npm version, and tests a clean installation of the exact
|
|
219
330
|
tarball it publishes publicly under `latest`. Node 22 and pnpm 10.33.3 match CI.
|
|
220
331
|
|
|
221
332
|
Only `SMS_CREDENTIAL` is configured as a GitHub Actions secret for this workflow.
|
|
@@ -225,14 +336,17 @@ non-secret repository configuration. The existing npm token needs publishing
|
|
|
225
336
|
permission for `@ai-digital-factory/lmt-cli`; it is masked and passed only to the
|
|
226
337
|
publishing step. No credential values are included in the package.
|
|
227
338
|
|
|
228
|
-
|
|
229
|
-
|
|
339
|
+
`@ai-digital-factory/lmt-web-cli` is deprecated and no longer released: the Web CLI ships inside this package as `lmt web`, and its release workflow was removed. The npm deprecation message points users to `lmt web`.
|
|
340
|
+
|
|
341
|
+
First publication uses `0.1.0`; later runs raise the highest published stable
|
|
342
|
+
version by the dispatch's `bump` choice: `patch` (default, `0.1.6` to `0.1.7`),
|
|
343
|
+
`minor` (`0.2.0`) or `major` (`1.0.0`). Registry/authentication failures stop the release. Versions change
|
|
230
344
|
only in the temporary publishing artifact, with no bump commit, git tag, GitHub
|
|
231
345
|
Release, Origin Version, or deployment. A retry after successful npm publication
|
|
232
|
-
selects another
|
|
346
|
+
selects another version, since published npm versions are immutable. npm can accept
|
|
233
347
|
an upload before public registry processing finishes; the action polls for visibility
|
|
234
348
|
for five minutes. If confirmation times out after a successful upload, check npm
|
|
235
|
-
before rerunning the release to avoid publishing an unnecessary
|
|
349
|
+
before rerunning the release to avoid publishing an unnecessary version.
|
|
236
350
|
|
|
237
351
|
To reproduce the packaging checks from the repository root:
|
|
238
352
|
|
|
@@ -246,14 +360,14 @@ node .github/scripts/test-lmt-cli-package.mjs "$tarball"
|
|
|
246
360
|
|
|
247
361
|
`lmt validate zerodha-session --env local --profile NAME` starts a new Broker-owned attempt and returns an attributed blocked report when a human OTP is needed. Resume with the same profile and explicit `--attempt ID`; add `--otp-stdin` to submit the protected human code. Without that flag, the supplied attempt is only observed. A pass requires authoritative attempt state followed by a hard session check; status alone does not pass the scenario. The resulting session stays available on the caller profile.
|
|
248
362
|
|
|
249
|
-
|
|
363
|
+
Fresh validation can replace the Operator's active Broker attempt and successful login can refresh its shared token. CLI profile isolation does not isolate that shared state. See [local/dev validation smoke steps and recorded prerequisites](ZERODHA-SMOKE.md).
|
|
250
364
|
|
|
251
|
-
## Settings and token commands for
|
|
365
|
+
## Settings and token commands for the Controller
|
|
252
366
|
|
|
253
367
|
Read ordinary Settings and their durable Settings Version with:
|
|
254
368
|
|
|
255
369
|
```sh
|
|
256
|
-
lmt settings read --env dev
|
|
370
|
+
lmt settings read --env dev
|
|
257
371
|
```
|
|
258
372
|
|
|
259
373
|
Save one intent by piping a single JSON object to protected stdin. Supply the version
|
|
@@ -261,7 +375,7 @@ you reviewed and only the settings you intend to change. For example:
|
|
|
261
375
|
|
|
262
376
|
```sh
|
|
263
377
|
printf '%s\n' '{"expectedSettingsVersion":7,"entryCategories":[]}' |
|
|
264
|
-
lmt settings save --stdin --env dev
|
|
378
|
+
lmt settings save --stdin --env dev
|
|
265
379
|
```
|
|
266
380
|
|
|
267
381
|
An empty list disables all Entry Categories; omitted fields keep their saved values.
|
|
@@ -280,8 +394,8 @@ record. The existing Market Watch resize recovery limitation still applies acros
|
|
|
280
394
|
Access-token operations use a separate version and endpoint:
|
|
281
395
|
|
|
282
396
|
```sh
|
|
283
|
-
lmt token read --env dev
|
|
284
|
-
lmt token replace --stdin --env dev
|
|
397
|
+
lmt token read --env dev
|
|
398
|
+
lmt token replace --stdin --env dev < /path/to/protected-token-request.json
|
|
285
399
|
```
|
|
286
400
|
|
|
287
401
|
The token request contains expected (the metadata returned by token read), optionally
|
|
@@ -290,3 +404,13 @@ reading its value, and continueReplacement: true after reviewing an active-tradi
|
|
|
290
404
|
confirmation. A same-token submission verifies the submitter without reinstalling the token. Ordinary
|
|
291
405
|
Settings Save never replaces access tokens. Token values and saved credentials do not
|
|
292
406
|
appear in command results.
|
|
407
|
+
|
|
408
|
+
### Save a Candle Export locally
|
|
409
|
+
|
|
410
|
+
```sh
|
|
411
|
+
lmt candle-export NSE:IDEA --date 2026-10-28 --env dev --output ./candles.xlsx --timeout 2m
|
|
412
|
+
```
|
|
413
|
+
|
|
414
|
+
`--output PATH` downloads the newly published workbook with the CLI HTTP client. The JSON retains `candleExport.url` and adds `download.path`, `download.bytes`, and `download.sha256`. The parent directory must exist; an existing destination is never overwritten. HTTP errors, interrupted downloads, deadlines, and file errors return exit 1 without claiming success or leaving a partial destination. The timeout covers publication and download together. Without `--output`, the command still returns only the published context.
|
|
415
|
+
|
|
416
|
+
Use this option when Python urllib receives Cloudflare 403/error 1010 from the public R2 URL (SUK-95). It removes the need for a separate downloader. It does not change the public hosting policy; direct Python downloads still require a delivery configuration change.
|