bmweb-cli 0.1.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/LICENSE +674 -0
- package/README.md +351 -0
- package/dist/bmweb.js +2790 -0
- package/package.json +53 -0
- package/runtime/core/bestvm/codec.js +285 -0
- package/runtime/core/bestvm/environment.js +116 -0
- package/runtime/core/bestvm/executor.js +1483 -0
- package/runtime/core/bestvm/index.js +52 -0
- package/runtime/core/bestvm/machine.js +491 -0
- package/runtime/core/bestvm/operands.js +356 -0
- package/runtime/core/bestvm/registers.js +152 -0
- package/runtime/core/bestvm/write-guard.js +111 -0
- package/runtime/core/ipofile/compile.js +364 -0
- package/runtime/core/ipofile/decls.js +187 -0
- package/runtime/core/ipofile/emit.js +708 -0
- package/runtime/core/ipofile/exec.js +164 -0
- package/runtime/core/ipofile/lex.js +243 -0
- package/runtime/core/ipofile/parse.js +550 -0
- package/runtime/core/ipofile/pool.js +404 -0
- package/runtime/core/ipofile/walk.js +431 -0
- package/runtime/core/ipovm/builtin-helpers.js +182 -0
- package/runtime/core/ipovm/builtins-api.js +610 -0
- package/runtime/core/ipovm/builtins-screen.js +493 -0
- package/runtime/core/ipovm/builtins-table.js +166 -0
- package/runtime/core/ipovm/builtins-text.js +166 -0
- package/runtime/core/ipovm/emissions.js +138 -0
- package/runtime/core/ipovm/hosts.js +191 -0
- package/runtime/core/ipovm/operators.js +229 -0
- package/runtime/core/ipovm/structures.js +250 -0
- package/runtime/core/ipovm/suspensions.js +241 -0
- package/runtime/core/ipovm/tape.js +206 -0
- package/runtime/core/ipovm/values.js +241 -0
- package/runtime/core/ipovm/vm.js +1166 -0
- package/runtime/core/translate.js +526 -0
- package/runtime/core/webshim/api-router.js +592 -0
- package/runtime/core/webshim/bus.js +95 -0
- package/runtime/core/webshim/coding.js +82 -0
- package/runtime/core/webshim/data-fetch.js +66 -0
- package/runtime/core/webshim/exchange.js +288 -0
- package/runtime/core/webshim/framing.js +331 -0
- package/runtime/core/webshim/install.js +30 -0
- package/runtime/core/webshim/job-runner.js +319 -0
- package/runtime/core/webshim/native-bus.js +108 -0
- package/runtime/core/webshim/timers.js +82 -0
- package/runtime/core/webshim/trace.js +205 -0
- package/runtime/core/webshim/transport-base.js +128 -0
- package/runtime/core/webshim/variant-resolver.js +249 -0
- package/runtime/core/webshim/web-serial-bus.js +734 -0
- package/runtime/home/bmweb-home.ips +76 -0
- package/runtime/home/bmweb.h +26 -0
- package/runtime/screens/activations.js +258 -0
- package/runtime/screens/garage/diff.js +331 -0
- package/runtime/screens/garage/share.js +276 -0
- package/runtime/screens/garage/store.js +547 -0
- package/runtime/screens/ipo-runtime/cells.js +176 -0
- package/runtime/screens/ipo-runtime/dialogs.js +254 -0
- package/runtime/screens/ipo-runtime/home.js +358 -0
- package/runtime/screens/ipo-runtime/open.js +393 -0
- package/runtime/screens/ipo-runtime/paint-grid.js +106 -0
- package/runtime/screens/ipo-runtime/paint-modern.js +424 -0
- package/runtime/screens/ipo-runtime/print.js +281 -0
- package/runtime/screens/ipo-runtime/program.js +1337 -0
- package/runtime/screens/ipo-runtime/protocol.js +464 -0
- package/runtime/screens/ipo-runtime/script-scan.js +225 -0
- package/runtime/screens/ipo-runtime/translate-sets.js +130 -0
- package/runtime/screens/ipo-runtime/ui.js +249 -0
- package/runtime/screens/ipo-runtime/wire-policy.js +113 -0
- package/runtime/screens/ir.js +324 -0
- package/runtime/screens/search/data.js +153 -0
- package/runtime/screens/search/match.js +285 -0
- package/runtime/screens/search/open.js +66 -0
- package/runtime/vendor/fflate.min.js +1 -0
package/README.md
ADDED
|
@@ -0,0 +1,351 @@
|
|
|
1
|
+
# bmweb-cli
|
|
2
|
+
|
|
3
|
+
[BMWeb](https://bmweb.danner.ink/)'s tools as a command line. Read what an
|
|
4
|
+
INPA `.IPO` script does, compile an `.IPS` / `.SRC` source, search every
|
|
5
|
+
module the site ships for the key that does a thing, decode or compare the
|
|
6
|
+
report links the app's Garage shares, and, with a K+DCAN cable, run jobs,
|
|
7
|
+
read every fault memory of a car, and drive a module's INPA screens from
|
|
8
|
+
the terminal.
|
|
9
|
+
|
|
10
|
+
The commands run the app's own code: the `.IPO` reader and the source
|
|
11
|
+
compiler, the job search, the Garage report codec, the transport (framing,
|
|
12
|
+
the K-line exchange, the Web Serial bus), the BEST2 job VM, the `.IPO` VM
|
|
13
|
+
and the program that runs a module's script are the same files the site
|
|
14
|
+
loads, copied into the package at build time. There is one implementation,
|
|
15
|
+
and this is a second way to reach it.
|
|
16
|
+
|
|
17
|
+
```
|
|
18
|
+
npm i -g bmweb-cli
|
|
19
|
+
bmweb --help
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Node 20 or later. One optional dependency, `serialport`, used only by the
|
|
23
|
+
commands that talk to the car; if it did not install, `npm i -g serialport`.
|
|
24
|
+
|
|
25
|
+
## What is in the package
|
|
26
|
+
|
|
27
|
+
Only the project's own code. Nothing BMW-derived ships with it: no scripts,
|
|
28
|
+
no SGBDs, no fault database, no parts data. Everything the tool needs that
|
|
29
|
+
it does not carry is fetched from the site (or `--api <url>`) and kept
|
|
30
|
+
under `$XDG_CACHE_HOME/bmweb-cli/` (default `~/.cache/bmweb-cli/`) for a
|
|
31
|
+
day: the job search index (about 2.5 MB), and, for the commands on the
|
|
32
|
+
cable, the chassis archives the app itself loads (`api/chassis/E46.chassis`,
|
|
33
|
+
about 20 MB for an E46), the group bytecode and the shared tables.
|
|
34
|
+
`--refresh` fetches again; when the site cannot be reached the cached copy
|
|
35
|
+
is used and a warning says so.
|
|
36
|
+
|
|
37
|
+
## Offline commands
|
|
38
|
+
|
|
39
|
+
### `bmweb ipo info <file>`
|
|
40
|
+
|
|
41
|
+
What a script is: form, entry point, includes, procedure counts, DLL
|
|
42
|
+
imports, and every menu with its keys, the screen each opens and the jobs it
|
|
43
|
+
sends. Takes a compiled `.IPO`, or an `.IPS` / `.SRC` source (compiled
|
|
44
|
+
first; pass `-I <dir>` with the INPA headers it includes).
|
|
45
|
+
|
|
46
|
+
```
|
|
47
|
+
$ bmweb ipo info PROBE.IPS -I inc
|
|
48
|
+
Script PROBE (compiled from source)
|
|
49
|
+
Form INPA diagnostic script
|
|
50
|
+
Entry inpainit -> m_main / s_main
|
|
51
|
+
Includes PROBE.H
|
|
52
|
+
Procedures 8 (2 menus, 3 screens, 3 functions, 0 state machines)
|
|
53
|
+
DLL imports none
|
|
54
|
+
|
|
55
|
+
m_main "Main" (screen s_main)
|
|
56
|
+
F1 Ident s_ident IDENT
|
|
57
|
+
F2 Fault memory s_fs (cyclic) FS_LESEN, FS_LESEN_DETAIL
|
|
58
|
+
F3 Clear faults FS_LOESCHEN [WRITE]
|
|
59
|
+
F4 Helper IDENT
|
|
60
|
+
F5 (no caption) menu m_sub
|
|
61
|
+
F10 Back DIAGNOSE_ENDE, (exit)
|
|
62
|
+
Shift+F10 Print (printscreen)
|
|
63
|
+
|
|
64
|
+
m_sub
|
|
65
|
+
F1 Sub key STATUS_LESEN
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
The jobs are read from the script without running it: the constants each
|
|
69
|
+
key's body pushes before its `INPAapiJob` calls, plus what the screen it
|
|
70
|
+
opens sends from its own `LINE` blocks, following helper functions the key
|
|
71
|
+
calls. `[WRITE]` marks a job the app would ask about before sending (the
|
|
72
|
+
write classifier's verdict, minus the session plumbing every script sends).
|
|
73
|
+
A job whose name the script builds at run time is not shown.
|
|
74
|
+
|
|
75
|
+
The package carries the app's own home script (`runtime/home/bmweb-home.ips`
|
|
76
|
+
and its `bmweb.h`, both written by the project), which reads like any other:
|
|
77
|
+
|
|
78
|
+
```
|
|
79
|
+
$ bmweb ipo info "$(npm root -g)/bmweb-cli/runtime/home/bmweb-home.ips" \
|
|
80
|
+
-I "$(npm root -g)/bmweb-cli/runtime/home"
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### `bmweb ipo keys <file> [--menu m_x]`
|
|
84
|
+
|
|
85
|
+
The same keys as one table across every menu, or one menu.
|
|
86
|
+
|
|
87
|
+
```
|
|
88
|
+
$ bmweb ipo keys PROBE.IPS -I inc --menu m_main
|
|
89
|
+
MENU KEY LABEL OPENS JOBS WRITES
|
|
90
|
+
------ --------- ------------ ------------- ------------------------- ------
|
|
91
|
+
m_main F1 Ident s_ident IDENT
|
|
92
|
+
m_main F2 Fault memory s_fs (cyclic) FS_LESEN, FS_LESEN_DETAIL
|
|
93
|
+
m_main F3 Clear faults FS_LOESCHEN [WRITE] yes
|
|
94
|
+
m_main F4 Helper IDENT
|
|
95
|
+
m_main F5 (no caption) menu m_sub
|
|
96
|
+
m_main F10 Back DIAGNOSE_ENDE, (exit)
|
|
97
|
+
m_main Shift+F10 Print (printscreen)
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### `bmweb ipo compile <file.IPS> [-I dir]... [-o out]`
|
|
101
|
+
|
|
102
|
+
Compile an INPA source. Includes are looked up beside the script and in
|
|
103
|
+
each `-I` directory, by file name, case-insensitively, the way INPA's own
|
|
104
|
+
tooling finds them; a missing one is named rather than half-compiled.
|
|
105
|
+
|
|
106
|
+
```
|
|
107
|
+
$ bmweb ipo compile MY_SCRIPT.IPS -I ~/INPA/SGDAT
|
|
108
|
+
MY_SCRIPT.IPS: compiled 8 procedures (2 menus, 3 screens, 3 functions, 0 state machines), includes INPA.H
|
|
109
|
+
wrote /home/me/MY_SCRIPT.ipoexec.json (the app's exec form; not INPA's binary .IPO)
|
|
110
|
+
|
|
111
|
+
$ bmweb ipo compile MY_SCRIPT.IPS
|
|
112
|
+
bmweb: MY_SCRIPT.IPS: missing include INPA.H (searched /home/me; pass -I <dir> with the INPA headers)
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
What it writes is the form the app runs: the script's procedures as the
|
|
116
|
+
token stream the runtime executes (`{procs, byid}`, the same shape the
|
|
117
|
+
Script runner builds from a dropped file). The app's compiler emits that,
|
|
118
|
+
not INPA's binary container, so the output is not a `.IPO` you could hand
|
|
119
|
+
to INPA itself. The `.IPO` byte writer lives in the repository's Python
|
|
120
|
+
tooling and is not part of this package.
|
|
121
|
+
|
|
122
|
+
### `bmweb search <query...> [--chassis E46] [--limit N] [--json]`
|
|
123
|
+
|
|
124
|
+
The corpus job search: every INPA key and screen in every module the site
|
|
125
|
+
ships, matched on what it is called (in German and in English) and the
|
|
126
|
+
jobs it sends. All words must match. Results are grouped by chassis, then
|
|
127
|
+
module, and every hit carries the deep link that opens it on the site.
|
|
128
|
+
|
|
129
|
+
```
|
|
130
|
+
$ bmweb search clear adaptation --chassis E46 --limit 4
|
|
131
|
+
E46
|
|
132
|
+
ms410ds0 MS 41.0 (ms410ds0)
|
|
133
|
+
F7 clear adaptation values [WRITE] https://bmweb.danner.ink/#car/E46/ms410ds0/m_fehler
|
|
134
|
+
ms410ds1 MS 41.0 (ms410ds1)
|
|
135
|
+
F7 clear adaptation values [WRITE] https://bmweb.danner.ink/#car/E46/ms410ds1/m_fehler
|
|
136
|
+
ms410ds2 MS 41.0 (ms410ds2)
|
|
137
|
+
F7 clear adaptation values [WRITE] https://bmweb.danner.ink/#car/E46/ms410ds2/m_fehler
|
|
138
|
+
ms450ds0 MS45 (ms450ds0)
|
|
139
|
+
F8 Clear selected adaptation values https://bmweb.danner.ink/#car/E46/ms450ds0/m_main/s_ada_loe
|
|
140
|
+
|
|
141
|
+
4 of 5 results shown (raise --limit for more)
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### `bmweb report show <link-or-payload> [--json]`
|
|
145
|
+
|
|
146
|
+
Decode a link the Garage's Share button made (`...#report/<payload>`; the
|
|
147
|
+
bare payload is accepted too) and print the report: one row per fault with
|
|
148
|
+
its module, code, text, occurrence count and whether it was present at the
|
|
149
|
+
read, plus the addresses that stayed silent. An identification report
|
|
150
|
+
prints each module's ident fields with the app's captions.
|
|
151
|
+
|
|
152
|
+
```
|
|
153
|
+
$ bmweb report show 'https://bmweb.danner.ink/#report/q1WpV...'
|
|
154
|
+
Report fault memories of E46 325i / E46
|
|
155
|
+
Read 2026-09-01T10:00:00Z
|
|
156
|
+
Modules 2 read, 1 with faults, 2 faults, 1 silent
|
|
157
|
+
|
|
158
|
+
MODULE CODE TEXT COUNT STATE
|
|
159
|
+
-------- ---- ---------------------------- ----- -------
|
|
160
|
+
DME MS45 27C3 DMTL pump current too high 3 present
|
|
161
|
+
DME MS45 120 Lambda sensor heater, bank 1 1 stored
|
|
162
|
+
IHKA no faults stored
|
|
163
|
+
|
|
164
|
+
Silent (1):
|
|
165
|
+
D_0044 EGS no answer
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
The code is the DTC from `F_HEX_CODE` when the module reports one, else the
|
|
169
|
+
DTC the fault text leads with, else the location number, which is how the
|
|
170
|
+
Garage itself identifies a fault when comparing reads. The link carries no
|
|
171
|
+
VIN, and nothing is fetched: the report is in the link.
|
|
172
|
+
|
|
173
|
+
### `bmweb report diff <link-a> <link-b> [--json]`
|
|
174
|
+
|
|
175
|
+
What changed between two shared reports, older first, using the app's own
|
|
176
|
+
comparison: new, cleared and still-present faults per module, ident fields
|
|
177
|
+
that moved, and modules that went silent or started answering. A fault
|
|
178
|
+
present in both reads is the same fault whatever its status byte or counter
|
|
179
|
+
did; a module the newer read has no record of is unread, not cleared.
|
|
180
|
+
|
|
181
|
+
```
|
|
182
|
+
$ bmweb report diff "$A" "$B"
|
|
183
|
+
From 2026-09-01T10:00:00Z E46 325i
|
|
184
|
+
To 2026-09-08T12:00:00Z E46 325i
|
|
185
|
+
Changes 1 new, 1 cleared, 1 still present, 1 module changed
|
|
186
|
+
|
|
187
|
+
DME MS45
|
|
188
|
+
+ 2A0B Camshaft sensor, inlet 1
|
|
189
|
+
- 120 Lambda sensor heater, bank 1 1
|
|
190
|
+
= 27C3 DMTL pump current too high 5
|
|
191
|
+
|
|
192
|
+
IHKA unchanged
|
|
193
|
+
|
|
194
|
+
Answering changed:
|
|
195
|
+
answering now EGS
|
|
196
|
+
|
|
197
|
+
+ new - cleared = still present ~ ident field changed
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
## Commands on the cable
|
|
201
|
+
|
|
202
|
+
These need a K+DCAN cable (an FTDI cable, or a clone) on the car's OBD
|
|
203
|
+
port, and the `serialport` package. The port is the single candidate when
|
|
204
|
+
there is one; otherwise name it with `--port`.
|
|
205
|
+
|
|
206
|
+
The wire is the app's own transport, run unchanged over a Node port with
|
|
207
|
+
the Web Serial API's shape. What that carries over, verified by the app on
|
|
208
|
+
a real E46 with an FTDI cable on a Mac: the port opens 115200 8N1 and is
|
|
209
|
+
reopened 9600 8E1 for a DS2 or KWP2000 module on its own; DTR idles high
|
|
210
|
+
for BMW-FAST and D-CAN and low on every K-line concept, RTS is never
|
|
211
|
+
raised, and on the K line DTR is held for exactly the telegram's byte time
|
|
212
|
+
as the transmit enable; the ISO 9141 slow init is bit-banged on the break
|
|
213
|
+
line; the echo a wired K line returns is dropped by count; every timeout is
|
|
214
|
+
time-to-first-byte and comes from the SGBD's own communication parameters;
|
|
215
|
+
a read that ran out of time is resumed, never abandoned, so no byte is
|
|
216
|
+
lost; a silent address is the ECU's answer of zero bytes, which the SGBD's
|
|
217
|
+
own bytecode branches on. An FTDI cable wants a 1 ms latency timer (set for
|
|
218
|
+
you on Linux; on macOS and Windows a driver setting), and an echo failure
|
|
219
|
+
(IFH-0003) says so.
|
|
220
|
+
|
|
221
|
+
**Tested against the app's fake car, pending a real K+DCAN run.** The
|
|
222
|
+
transport is exercised end to end against a fake cable (the DS2 and
|
|
223
|
+
BMW-FAST framing, the reopen, the DTR sequence, the echo), and `job`,
|
|
224
|
+
`scan` and `tui` against the fake car the app's own runtime tests use. No
|
|
225
|
+
real cable has been on this code yet.
|
|
226
|
+
|
|
227
|
+
### `bmweb ports [--json]`
|
|
228
|
+
|
|
229
|
+
The serial ports a K+DCAN cable shows up as: `cu.usbserial*`, `cu.SLAB*`,
|
|
230
|
+
`cu.wchusbserial*`, `ttyUSB*`, `ttyACM*`, with the vendor detail when
|
|
231
|
+
`serialport` is installed. Needs no package to list.
|
|
232
|
+
|
|
233
|
+
```
|
|
234
|
+
$ bmweb ports
|
|
235
|
+
/dev/cu.usbserial-AB0JQ9XY FTDI 0403:6001 sn AB0JQ9XY
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
### `bmweb job <sgbd> <JOB> [arg] [--port p] [--yes] [--json]`
|
|
239
|
+
|
|
240
|
+
One raw job on one module, like the app's Tool32: the SGBD's own bytecode
|
|
241
|
+
runs in the job VM over the cable, inside its EDIABAS session
|
|
242
|
+
(INITIALISIERUNG once, the communication parameters carried across jobs,
|
|
243
|
+
ENDE when another module is loaded), and the result sets print as tables.
|
|
244
|
+
A group name (`D_MOTOR`, `D_0012`) is resolved on the wire to the variant
|
|
245
|
+
that answers, as the app resolves it.
|
|
246
|
+
|
|
247
|
+
```
|
|
248
|
+
$ bmweb job ms450ds0 STATUS_LESEN
|
|
249
|
+
ms450ds0 MS450DS0 STATUS_LESEN: 1 set
|
|
250
|
+
|
|
251
|
+
set 1
|
|
252
|
+
STAT_MOTORDREHZAHL_WERT 812.5
|
|
253
|
+
STAT_MOTORDREHZAHL_EINH 1/min
|
|
254
|
+
JOB_STATUS OKAY
|
|
255
|
+
|
|
256
|
+
$ bmweb job ms450ds0 FS_LOESCHEN
|
|
257
|
+
FS_LOESCHEN on ms450ds0 is a write (it changes the module or drives something). Send it? [y/N] n
|
|
258
|
+
FS_LOESCHEN on ms450ds0: not sent (a write needs --yes or a y answer)
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
The write gate is the app's classifier (`isWriteJob`): a read token in the
|
|
262
|
+
name wins, a write token makes a write, and an unknown name is a write.
|
|
263
|
+
A write goes out only with `--yes` or a `y` on the terminal; without a
|
|
264
|
+
terminal the answer is no. A write is never sent silently.
|
|
265
|
+
|
|
266
|
+
### `bmweb scan <chassis> [--port p] [--share] [--json]`
|
|
267
|
+
|
|
268
|
+
INPA's own whole-vehicle script (E46 E53 E65 E83 E85 E87 E89 E90 R50 R56):
|
|
269
|
+
the script is opened, its fault-memory menu's read key is pressed, and what
|
|
270
|
+
it put on the wire is folded into the same report the app's Garage keeps,
|
|
271
|
+
one module per address that answered, the silent ones listed. `--share`
|
|
272
|
+
prints a link carrying the report, the same link the Garage's Share button
|
|
273
|
+
makes, which `bmweb report show` and the site both open.
|
|
274
|
+
|
|
275
|
+
```
|
|
276
|
+
$ bmweb scan E46 --share
|
|
277
|
+
E46: FS lesen (F1)
|
|
278
|
+
Engine
|
|
279
|
+
...
|
|
280
|
+
Scan E46 fault memories (e46.ipo)
|
|
281
|
+
Read 2026-09-09T08:26:15.221Z
|
|
282
|
+
Modules 14 answered, 2 with faults, 3 faults, 5 silent
|
|
283
|
+
|
|
284
|
+
MODULE CODE TEXT COUNT STATE
|
|
285
|
+
-------- ---- -------------------------- ----- -------
|
|
286
|
+
ms450ds0 27C3 DMTL pump current too high 3 present
|
|
287
|
+
...
|
|
288
|
+
Silent (5):
|
|
289
|
+
D_0044 D_0044 ERROR_NO_ANSWER
|
|
290
|
+
...
|
|
291
|
+
|
|
292
|
+
Share: https://bmweb.danner.ink/#report/...
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
The script's progress window (which module it is asking) goes to stderr;
|
|
296
|
+
a key that would write is declined, a prompt is cancelled: the scan reads.
|
|
297
|
+
|
|
298
|
+
### `bmweb tui [<chassis> <sgbd>] [--port p] [--menu m_x]`
|
|
299
|
+
|
|
300
|
+
INPA's screens in the terminal. With a chassis and a module (SGBD or INPA
|
|
301
|
+
code, or the chassis itself for its whole-vehicle script), that module's
|
|
302
|
+
script runs the way the app runs it: its entry identifies the module, its
|
|
303
|
+
root menu's keys are on the number row (1..9 and 0 for F1..F10, the
|
|
304
|
+
shifted symbols `! @ # $ % ^ & * ( )` and Shift+F1..F10 for the shifted
|
|
305
|
+
bank), Esc is the script's own Back, q quits. The screen is INPA's grid
|
|
306
|
+
redrawn in place, a lamp as `(*) word`, a bar as `[####....] value`; the
|
|
307
|
+
status line and the script's progress window are the two bottom lines.
|
|
308
|
+
|
|
309
|
+
With no arguments it starts on the app's own home, an INPA script of the
|
|
310
|
+
project's own (`home/bmweb-home.ips`): F1 picks a chassis then a module,
|
|
311
|
+
F2 the chassis's whole-vehicle script, and `scriptchange` hands the screen
|
|
312
|
+
to that script. The picks are numbered lists on the terminal; typing text
|
|
313
|
+
filters, a number opens, Enter cancels. The home starts with or without a
|
|
314
|
+
cable.
|
|
315
|
+
|
|
316
|
+
Every dialog INPA opens is a prompt: a message waits for Enter, an input
|
|
317
|
+
asks for the number (or hex, or text) within the declared range, the
|
|
318
|
+
two-word box takes y/n, the component picker (togglelist) lists the
|
|
319
|
+
screen's lines by number, Select lists the named lines, save-as asks for a
|
|
320
|
+
file name. **Every write is asked first**, exactly as the app asks: a key
|
|
321
|
+
whose body can send a write names the jobs and waits for y; a screen that
|
|
322
|
+
sends one on every refresh asks once for as long as it is open; n or
|
|
323
|
+
Enter abandons the key. On quit the leaving menu's Back job (the script's
|
|
324
|
+
own release of whatever it energised) goes to the module, then the
|
|
325
|
+
script's `inpaexit` (its DIAGNOSE_ENDE), the same release-on-leave the app
|
|
326
|
+
performs.
|
|
327
|
+
|
|
328
|
+
The module data the script needs (its `.IPO`, the SGBD bytecode, the
|
|
329
|
+
tables) comes from the site's chassis archive, cached as described above.
|
|
330
|
+
|
|
331
|
+
### Every command
|
|
332
|
+
|
|
333
|
+
`--json` prints machine-readable output instead of a table. Errors are one
|
|
334
|
+
line on stderr and exit code 1. `bmweb <command> --help` lists a command's
|
|
335
|
+
options; `bmweb --version` prints the version.
|
|
336
|
+
|
|
337
|
+
## Developing
|
|
338
|
+
|
|
339
|
+
The package lives in `cli/` of the [BMWeb repository](https://github.com/dader34/BMWeb).
|
|
340
|
+
`npm run build` copies the app files it runs into `runtime/` (the list is
|
|
341
|
+
`src/runtime-files.json`, in the app's load order), bundles `src/bmweb.ts`
|
|
342
|
+
to `dist/bmweb.js` with esbuild and type-checks with `tsc`; `npm test` runs
|
|
343
|
+
the `node:test` suites the build produced, every one of them offline: the
|
|
344
|
+
serial tests drive the app's bus over a fake cable, the job, scan and tui
|
|
345
|
+
tests drive the app's runtime against a fake car and a scripted terminal,
|
|
346
|
+
with a module script written for the tests in INPA's language. The
|
|
347
|
+
repository's `tools/check.sh` runs all of it.
|
|
348
|
+
|
|
349
|
+
## License
|
|
350
|
+
|
|
351
|
+
GPL-3.0, as the repository is. See `LICENSE`.
|