@microtronics/studio-cli 1.2.0-alpha.1 → 1.2.0-alpha.10

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.
@@ -1,9 +1,19 @@
1
+ import { AtCommandHandler } from '@microtronics/device-master';
2
+ import { DdeModel } from '@microtronics/device-master';
3
+ import { DdeRecord } from '@microtronics/device-master';
1
4
  import { Document as Document_2 } from 'yaml';
5
+ import { EventEmitter } from 'node:events';
6
+ import { ITimeSource } from '@microtronics/device-master';
7
+ import { ITransport } from '@microtronics/device-master';
2
8
  import { LineCounter } from 'yaml';
9
+ import { LocalApiRequest } from '@microtronics/device-master';
10
+ import { LocalApiResponse } from '@microtronics/device-master';
11
+ import { MemoryStorage } from '@microtronics/device-master';
3
12
  import { ParsedNode } from 'yaml';
4
13
  import { Range as Range_2 } from 'yaml';
5
14
  import { SemVer } from 'semver';
6
15
  import { URI } from 'vscode-uri';
16
+ import { UtoMaster } from '@microtronics/device-master';
7
17
 
8
18
  export declare namespace APM {
9
19
  export enum TagPhase {
@@ -395,6 +405,18 @@ declare interface components {
395
405
  pathItems: never;
396
406
  }
397
407
 
408
+ /** One tag whose device stamp overtook the mirror and was therefore pulled. */
409
+ export declare interface ContainerChange {
410
+ tag: number;
411
+ /** DDE container name, when the tag maps to one. */
412
+ container: string | null;
413
+ alias?: string;
414
+ /** Device stamp40 the mirror now holds. */
415
+ stamp: number;
416
+ /** Decoded record, for tags that map to a DDE container. */
417
+ decoded?: DdeRecord | null;
418
+ }
419
+
398
420
  declare const createPawnCC: PawnModuleFactory;
399
421
 
400
422
  declare const createPawnDbg: PawnModuleFactory;
@@ -1776,6 +1798,8 @@ export declare namespace DefaultFiles {
1776
1798
  legacyAutoUplinkInc: string;
1777
1799
  reportTemplate: string;
1778
1800
  dloCfg: string;
1801
+ devMirror: string;
1802
+ devDeviceLog: string;
1779
1803
  };
1780
1804
  export const filePaths: {
1781
1805
  studio: {
@@ -1801,6 +1825,11 @@ export declare namespace DefaultFiles {
1801
1825
  };
1802
1826
  };
1803
1827
  libdeps: string;
1828
+ dev: {
1829
+ path: string;
1830
+ mirror: string;
1831
+ deviceLog: string;
1832
+ };
1804
1833
  };
1805
1834
  dist: {
1806
1835
  path: string;
@@ -1985,6 +2014,15 @@ export declare namespace Dependencies {
1985
2014
  * @param logger
1986
2015
  */
1987
2016
  export function normalizeInstalledLibraryParts(cwd: URI, fs: LocalFS, logger: Log.Logger): Promise<void>;
2017
+ /**
2018
+ * Validate that every installed library dependency (direct and transitive, including dev dependencies)
2019
+ * requires a minimum server version ("engines.backend") that the current project (application or library)
2020
+ * already satisfies. Does not modify the manifest - raising "engines.backend" stays an explicit developer decision.
2021
+ * @param cwd
2022
+ * @param fs
2023
+ * @param logger
2024
+ */
2025
+ export function validateMinimumBackendVersion(cwd: URI, fs: LocalFS, logger: Log.Logger): Promise<void>;
1988
2026
  /**
1989
2027
  * Install npm dependencies in pov and blo working paths if they exist and contain a package.json.
1990
2028
  * This ensures that a single `studio install` command sets up the entire project.
@@ -2028,6 +2066,39 @@ export declare namespace Dependencies {
2028
2066
  export function unlinkLibraryApmParts(cwd: URI, fs: LocalFS, logger: Log.Logger, libraryName: string): Promise<void>;
2029
2067
  }
2030
2068
 
2069
+ /**
2070
+ * Start a `studio dev` session and its local HTTP server.
2071
+ *
2072
+ * Build → connect USB → flash → parse `dist/dde/dde.xml` → serve the myDatanet-compatible
2073
+ * `/api/**` surface plus `/dev/**` and `/events` on localhost.
2074
+ */
2075
+ export declare function dev(cwd: URI, fs: LocalFS, options: DevOptions): Promise<DevResult>;
2076
+
2077
+ /** Diagnostics of the last `build()`, as served by `/dev/status` and `/dev/build`. */
2078
+ export declare interface DevBuildState {
2079
+ running: boolean;
2080
+ ok: boolean | null;
2081
+ at: number | null;
2082
+ message?: string;
2083
+ diagnostics?: Package.MergedDiagnostics;
2084
+ }
2085
+
2086
+ /** `GET /dev/configs` payload — every config-class container, decoded and alias-or-name keyed. */
2087
+ declare interface DevConfigs {
2088
+ configs: Record<string, unknown>;
2089
+ /** Keys of {@link DevConfigs.configs}, in DDE declaration order. */
2090
+ order: string[];
2091
+ }
2092
+
2093
+ /** One entry of the `PUT /dev/configs` response — mirrors the single-container write outcome. */
2094
+ declare type DevConfigWriteResult = {
2095
+ ok: true;
2096
+ stale?: true;
2097
+ } | {
2098
+ ok: false;
2099
+ err: string;
2100
+ };
2101
+
2031
2102
  /**
2032
2103
  * Development installation information
2033
2104
  */
@@ -2045,8 +2116,348 @@ export declare interface DevelopmentInstallInfo {
2045
2116
  registrationCodeNeeded?: boolean;
2046
2117
  }
2047
2118
 
2119
+ /** An error carrying the process exit code the CLI should terminate with. */
2120
+ export declare class DevError extends Error {
2121
+ readonly exitCode: DevExitCode;
2122
+ constructor(message: string, exitCode: DevExitCode);
2123
+ }
2124
+
2125
+ /**
2126
+ * Exit codes for `studio dev` / `studio device`. 0–3 mirror
2127
+ * {@link import('../myDatanetClient').RunExitCode}; 7–9 are dev-mode specific.
2128
+ */
2129
+ export declare enum DevExitCode {
2130
+ Success = 0,
2131
+ BuildFailed = 1,
2132
+ DeviceNotFound = 2,
2133
+ UsbFailed = 3,
2134
+ ModelMissing = 7,
2135
+ UnknownContainer = 8,
2136
+ WriteForbidden = 9
2137
+ }
2138
+
2048
2139
  export declare const DeviceProfiles: any;
2049
2140
 
2141
+ /**
2142
+ * The pair of transports (UTO data + AT debug) needed to talk to a connected device,
2143
+ * plus a way to release the underlying link.
2144
+ */
2145
+ export declare interface DeviceTransports {
2146
+ uto: ITransport;
2147
+ /** Absent when the caller asked for the UTO interface only (`needDebug: false`). */
2148
+ debug?: ITransport;
2149
+ close(): Promise<void>;
2150
+ }
2151
+
2152
+ /** One ring-buffer record, as served by `GET /dev/logs` and the SSE `log` event. */
2153
+ export declare interface DevLogRecord {
2154
+ /** Monotonic sequence number; `GET /dev/logs?since=<seq>` returns everything after it. */
2155
+ seq: number;
2156
+ /** Wall-clock ms. */
2157
+ ts: number;
2158
+ source: DevLogSource;
2159
+ text: string;
2160
+ /** Base64 payload, only for records whose bytes could not be decoded to text. */
2161
+ raw?: string;
2162
+ }
2163
+
2164
+ /** Where a log record came from. `state`/`console` are only used by `--replay` (`dev/replay/replaySession.ts`). */
2165
+ export declare type DevLogSource = 'rm2mlog' | 'at' | 'uto' | 'pov' | 'state' | 'console';
2166
+
2167
+ export declare interface DevOptions {
2168
+ /** Required unless {@link DevOptions.replay} is given. */
2169
+ serial?: string;
2170
+ host?: string;
2171
+ port?: number;
2172
+ /** Allow a non-loopback `host` without a bearer token. */
2173
+ allowRemote?: boolean;
2174
+ /** Rebuild, flash and sync on source changes. */
2175
+ watch?: boolean;
2176
+ /** Build before connecting (default `true`). */
2177
+ build?: boolean;
2178
+ /** Flash `dist/dlo/main.amx` after connecting (default `true`). */
2179
+ flash?: boolean;
2180
+ pollIntervalMs?: number;
2181
+ /** How long a write waits for the device to confirm, in ms. */
2182
+ waitMs?: number;
2183
+ logFile?: string;
2184
+ /** Bearer token required by the server; absent ⇒ `Authorization` is ignored. */
2185
+ token?: string;
2186
+ part?: APM.Part[];
2187
+ debug?: boolean;
2188
+ env?: Globals.ENV;
2189
+ apiToken?: string | null;
2190
+ logger?: Log.Logger;
2191
+ /** Spawn `npm run dev -w pov/<name>` with `MYDATANET_HOST` pointing at this server. */
2192
+ pov?: string | boolean;
2193
+ /** Persist the mirror to `.studio/dev/mirror.json` (default `true`). */
2194
+ persistMirror?: boolean;
2195
+ /** Test seam, forwarded to {@link DevSession}. */
2196
+ transportFactory?: TransportFactory;
2197
+ createDevice?: DevSessionOptions['createDevice'];
2198
+ /**
2199
+ * Support/forensics mode: replay a companion-app flight-recorder export instead of
2200
+ * opening USB (`cli/src/dev/replay/*`). Mutually exclusive with a live device — no
2201
+ * `build`/`flash`/poller/watch run, and `/api/**` answers empty/`E_EOD`.
2202
+ */
2203
+ replay?: string;
2204
+ /** Explicit recording session id; default = the session with the most records. */
2205
+ session?: string;
2206
+ /** Replay speed; `0`/`'max'` disables recorded delays. Default `1` (real-time). */
2207
+ speed?: number | 'max';
2208
+ }
2209
+
2210
+ /** Recording metadata reported by a `--replay` session (`dev/replay/replaySession.ts`). */
2211
+ declare interface DevReplayStatus {
2212
+ mode: 'replay';
2213
+ /** The cassette file this session was started from. */
2214
+ file: string;
2215
+ session: string;
2216
+ serial: string | null;
2217
+ deviceId: string | null;
2218
+ appVersion: string | null;
2219
+ platform: string | null;
2220
+ recordCount: number;
2221
+ startedTs: number;
2222
+ endedTs: number | null;
2223
+ speed: number | 'max';
2224
+ }
2225
+
2226
+ export declare interface DevResult {
2227
+ url: string;
2228
+ port: number;
2229
+ session: DevServerSession;
2230
+ apmId: string;
2231
+ close(): Promise<void>;
2232
+ }
2233
+
2234
+ export declare interface DevServer {
2235
+ url: string;
2236
+ port: number;
2237
+ close(): Promise<void>;
2238
+ }
2239
+
2240
+ /** The `/dev/logs` ring-buffer surface — shared by {@link DevServerSession} implementations. */
2241
+ declare interface DevServerLogStream {
2242
+ readonly lastSeq: number;
2243
+ since(since?: number, limit?: number): DevLogRecord[];
2244
+ }
2245
+
2246
+ /**
2247
+ * The subset of `DevSession` this server actually calls. A `--replay` session
2248
+ * (`dev/replay/replaySession.ts`'s `ReplayDevSession`) implements this directly instead of
2249
+ * a real `DevSession` — everything below is what `startDevServer` needs and nothing more.
2250
+ */
2251
+ export declare interface DevServerSession {
2252
+ readonly serial: string;
2253
+ readonly logStream: DevServerLogStream;
2254
+ on(event: string, listener: (...args: any[]) => void): this;
2255
+ off(event: string, listener: (...args: any[]) => void): this;
2256
+ handleApi(req: LocalApiRequest): Promise<LocalApiResponse>;
2257
+ status(): DevStatus;
2258
+ build(): Promise<DevBuildState>;
2259
+ flash(file?: string): Promise<UploadResult>;
2260
+ sync(tags?: number[]): Promise<{
2261
+ tags: number[];
2262
+ at: number;
2263
+ }>;
2264
+ at(cmd: string): Promise<string>;
2265
+ state(): Promise<unknown>;
2266
+ localDataSnapshot(): unknown;
2267
+ measure(): Promise<unknown>;
2268
+ configs(): Promise<DevConfigs>;
2269
+ applyConfigs(body: Record<string, unknown>): Promise<Record<string, DevConfigWriteResult>>;
2270
+ }
2271
+
2272
+ /**
2273
+ * One `studio dev` session: owns the USB link, the project's DDE model, the `IStorage`
2274
+ * mirror and the myDatanet-compatible API handler, and fans device activity out as events.
2275
+ *
2276
+ * Events: `log` ({@link DevLogRecord}), `state`, `sync`, `build`, `uto`,
2277
+ * `container-changed` ({@link ContainerChange}), `error`.
2278
+ */
2279
+ export declare class DevSession extends EventEmitter {
2280
+ readonly logStream: LogStream;
2281
+ private readonly opts;
2282
+ private readonly logger;
2283
+ private readonly timeSource;
2284
+ private device;
2285
+ private mirror;
2286
+ private model;
2287
+ private mapper;
2288
+ private apiHandler;
2289
+ private poller;
2290
+ private stateManager;
2291
+ private localData;
2292
+ private offlineSync;
2293
+ private buildState;
2294
+ private lastSyncAt;
2295
+ private firmwareVersion;
2296
+ private mirrorSaveTimer;
2297
+ private stopped;
2298
+ private readonly lock;
2299
+ constructor(options: DevSessionOptions);
2300
+ get serial(): string;
2301
+ get connected(): boolean;
2302
+ /**
2303
+ * Read by {@link StampPoller}: true while a flash, sync, write or AT command owns the
2304
+ * UTO link, so a poll tick cannot interleave with a multi-frame transfer.
2305
+ */
2306
+ get busy(): boolean;
2307
+ /** The parsed project DDE. */
2308
+ get ddeModel(): DdeModel;
2309
+ get storage(): MemoryStorage;
2310
+ /**
2311
+ * Build (optional) → load the model → connect USB → flash (optional) → start the stamp
2312
+ * poller. Rejects with a {@link DevError} whose `exitCode` the CLI exits with.
2313
+ */
2314
+ start(): Promise<void>;
2315
+ /** Read and parse `dist/dde/dde.xml`. Missing → {@link DevExitCode.ModelMissing}. */
2316
+ private loadModel;
2317
+ private connect;
2318
+ private startPoller;
2319
+ private tagLabel;
2320
+ private get utoMaster();
2321
+ private get atHandler();
2322
+ /** Assemble the {@link LocalApiContext} and bind the router to it. */
2323
+ private buildApiHandler;
2324
+ /**
2325
+ * Synthesize a {@link SiteBlueprint} from the parsed DDE, standing in for the site
2326
+ * blueprint a real myDatanet backend would serve. Restores each container's fields'
2327
+ * original-case DDE alias/name — the only thing `resolveBlueprintNameMap` reads.
2328
+ */
2329
+ private buildBlueprint;
2330
+ /**
2331
+ * Serve one `/api/**` request. A successful write additionally triggers an immediate
2332
+ * poll tick and waits (bounded by `waitMs`) until the device's own stamp for the
2333
+ * written tag has reached the pushed stamp — proof the device accepted the frame.
2334
+ * When it does not, `x-mt-mirror: stale` is added; `?async=1` skips the wait entirely.
2335
+ */
2336
+ handleApi(req: LocalApiRequest): Promise<LocalApiResponse>;
2337
+ /**
2338
+ * The `uto_data` tag a request writes, or `null` for a read / an `?async=1` write /
2339
+ * a path whose container cannot be resolved.
2340
+ */
2341
+ private writtenTag;
2342
+ /**
2343
+ * Poll until the device reports a stamp ≥ `pushedStamp` for `tag`, or the wait budget
2344
+ * runs out. Returns `false` on timeout.
2345
+ */
2346
+ private awaitDeviceStamp;
2347
+ /** Run the project build; records diagnostics in {@link DevBuildState}. */
2348
+ build(): Promise<DevBuildState>;
2349
+ /**
2350
+ * Upload an AMX to the device (defaults to `dist/dlo/main.amx`).
2351
+ *
2352
+ * `uploadToDevice` owns its own connection, and a USB device is single-owner, so the
2353
+ * session's link is released for the duration and reopened afterwards. The tag table
2354
+ * can change with a new app, so DEVINFO is re-read before the poller resumes.
2355
+ */
2356
+ flash(file?: string): Promise<UploadResult>;
2357
+ /**
2358
+ * Reopen the USB link after a flash. The device is rebooting — and some devices don't even
2359
+ * drop the USB connection — so a failure here is expected and retried for a while rather
2360
+ * than reported immediately; a final failure is logged and leaves `connected: false`.
2361
+ */
2362
+ private reconnect;
2363
+ private reportReconnectFailure;
2364
+ /** Full `OfflineSyncManager` sync, or a targeted pull of the given tags. */
2365
+ sync(tags?: number[]): Promise<{
2366
+ tags: number[];
2367
+ at: number;
2368
+ }>;
2369
+ /** One AT command; queued behind a flash, which closes the AT handler's transport. */
2370
+ at(cmd: string): Promise<string>;
2371
+ /** Last known rm2m state; fetches one when nothing has been read yet. */
2372
+ state(): Promise<unknown>;
2373
+ /** Live local-data values. */
2374
+ localDataSnapshot(): unknown;
2375
+ /** Trigger a measurement and return its outcome plus the fresh values. */
2376
+ measure(): Promise<unknown>;
2377
+ status(): DevStatus;
2378
+ /** Config-class containers (`settings`/`config0..9`/`configA..C`) in DDE declaration order. */
2379
+ private configContainers;
2380
+ /**
2381
+ * `GET /dev/configs` — one entry per config-class container, decoded through
2382
+ * {@link handleApi} (the same path `GET /api/1/sites/<uid>/containers/<name>` uses). Keyed
2383
+ * by the container's alias when the DDE declares one, else its raw name.
2384
+ */
2385
+ configs(): Promise<DevConfigs>;
2386
+ /**
2387
+ * `PUT /dev/configs` — applies each entry as a partial write via {@link handleApi}, exactly
2388
+ * like `PUT /api/1/sites/<uid>/containers/<name>`. Accepts an alias or a raw container name
2389
+ * as key; a key that resolves to no container, or to a non-config-class one, fails that
2390
+ * entry alone with the same `{err}` wording the single-container route produces — the rest
2391
+ * of the entries still apply.
2392
+ */
2393
+ applyConfigs(body: Record<string, unknown>): Promise<Record<string, DevConfigWriteResult>>;
2394
+ /** Force one poll pass (used by the watcher and by `POST /dev/sync`). */
2395
+ tick(): Promise<ContainerChange[]>;
2396
+ /** The mirror's current stamp40 for a tag, or 0. */
2397
+ mirrorStamp(tag: number): Promise<number>;
2398
+ /** Run `fn` as the sole owner of the UTO link (see {@link UtoLock}). */
2399
+ private withLink;
2400
+ private closeDevice;
2401
+ stop(): Promise<void>;
2402
+ }
2403
+
2404
+ export declare interface DevSessionOptions {
2405
+ cwd: URI;
2406
+ fs: LocalFS;
2407
+ /** 16-character hex device serial. */
2408
+ serial: string;
2409
+ /** Overrides how the USB transports are obtained (tests, later `--replay`). */
2410
+ transportFactory?: TransportFactory;
2411
+ /**
2412
+ * Test seam: supply the connected device (UtoMaster + AtCommandHandler) instead of
2413
+ * opening USB. The unit tests use it because `UtoMaster.init()` needs the real WASM
2414
+ * UTO wire protocol, which a byte-level mock cannot produce.
2415
+ */
2416
+ createDevice?: (serial: string) => Promise<OpenDevice>;
2417
+ /** Stamp-poll interval in ms; `0` disables polling. */
2418
+ pollIntervalMs?: number;
2419
+ /** Flash `dist/dlo/main.amx` to the device on start. */
2420
+ flash: boolean;
2421
+ /** Build the project on start. */
2422
+ build: boolean;
2423
+ part?: APM.Part[];
2424
+ logger: Log.Logger;
2425
+ timeSource?: ITimeSource;
2426
+ env?: Globals.ENV;
2427
+ apiToken?: string | null;
2428
+ /** How long a write waits for the device to confirm, in ms. `0` disables the wait. */
2429
+ waitMs?: number;
2430
+ /** JSONL log file for every {@link DevLogRecord}. */
2431
+ logFile?: string;
2432
+ /** Persist the mirror to `.studio/dev/mirror.json`. */
2433
+ persistMirror?: boolean;
2434
+ debug?: boolean;
2435
+ /** Test seam: replaces the AMX upload {@link flash} performs. */
2436
+ uploadToDevice?: typeof uploadToDevice;
2437
+ /** How long UTO work waits for the link while a flash owns it, in ms. */
2438
+ lockWaitMs?: number;
2439
+ }
2440
+
2441
+ /** `GET /dev/status` payload — `replay` is only present for a `--replay` session. */
2442
+ export declare interface DevStatus {
2443
+ serial: string;
2444
+ connected: boolean;
2445
+ apmId: string;
2446
+ firmwareVersion: string | null;
2447
+ model: {
2448
+ containers: Array<{
2449
+ name: string;
2450
+ alias?: string;
2451
+ kind: string;
2452
+ tag: number | null;
2453
+ }>;
2454
+ };
2455
+ lastSync: number | null;
2456
+ buildState: DevBuildState;
2457
+ poll: StampPollerStatus;
2458
+ replay?: DevReplayStatus;
2459
+ }
2460
+
2050
2461
  export declare namespace DFILES {
2051
2462
  export enum Type {
2052
2463
  static = "static",
@@ -2589,7 +3000,8 @@ export declare namespace Log {
2589
3000
  done = 1,
2590
3001
  info = 2,
2591
3002
  warning = 3,
2592
- error = 4
3003
+ error = 4,
3004
+ debug = 5
2593
3005
  }
2594
3006
  export const LOG_PREFIX: {
2595
3007
  1: string;
@@ -2597,17 +3009,25 @@ export declare namespace Log {
2597
3009
  2: string;
2598
3010
  3: string;
2599
3011
  4: string;
3012
+ 5: string;
2600
3013
  };
2601
3014
  export class Logger {
2602
3015
  private _logHandler;
2603
3016
  private _silent;
3017
+ private _debugEnabled;
2604
3018
  constructor(logOutput?: {
2605
3019
  log: (...args: any[]) => void;
2606
3020
  });
2607
3021
  _log(type: LogMessageType, msg: any, ...args: any[]): void;
2608
3022
  set silent(value: boolean);
3023
+ /** Redirect where log lines go (e.g. stderr while stdout carries machine-readable output). */
3024
+ set output(logOutput: {
3025
+ log: (...args: any[]) => void;
3026
+ });
2609
3027
  log(msg: any, ...args: any[]): void;
3028
+ /** Only prints when {@link debugEnabled} is set (the `--debug` flag). */
2610
3029
  debug(msg: any, ...args: any[]): void;
3030
+ set debugEnabled(value: boolean);
2611
3031
  error(msg: any, ...args: any[]): void;
2612
3032
  info(msg: any, ...args: any[]): void;
2613
3033
  warn(msg: any, ...args: any[]): void;
@@ -2615,6 +3035,58 @@ export declare namespace Log {
2615
3035
  }
2616
3036
  }
2617
3037
 
3038
+ /**
3039
+ * Ring buffer of device log records with SSE fan-out.
3040
+ *
3041
+ * Fed by two taps:
3042
+ * - `UtoMaster`'s `'utoFrame'` event, filtered to {@link UtoTag.LOG} (rm2mlog).
3043
+ * - `AtCommandHandler`'s `'data'` event, which the handler emits for every decoded
3044
+ * chunk of debug-channel RX (its documented "raw monitoring" hook) — this is where
3045
+ * a DLO's live `printf` output arrives.
3046
+ *
3047
+ * The LOG payload layout is not modelled: the record's leading bytes are decoded
3048
+ * best-effort (cp1252, then UTF-8) and cut at the first NUL. A payload that does not
3049
+ * decode to text is stored as base64 in {@link DevLogRecord.raw} with a hex preview as
3050
+ * its `text`, so nothing is silently dropped.
3051
+ */
3052
+ declare class LogStream extends EventEmitter {
3053
+ private readonly buffer;
3054
+ private readonly capacity;
3055
+ private readonly logFile;
3056
+ private readonly logger;
3057
+ private seq;
3058
+ private disposers;
3059
+ /** Serialises the JSONL appends so records cannot interleave mid-line. */
3060
+ private writeChain;
3061
+ /** `mkdir -p` of the log file's directory, done once instead of per record. */
3062
+ private logDirReady;
3063
+ constructor(opts?: {
3064
+ capacity?: number;
3065
+ logFile?: string;
3066
+ logger?: Log.Logger;
3067
+ });
3068
+ /** Append a record, evict the oldest when full, emit `record` and mirror to `--log-file`. */
3069
+ push(source: DevLogSource, text: string, raw?: Uint8Array): DevLogRecord;
3070
+ private appendToFile;
3071
+ /** Records after `since`, newest last, at most `limit` (`<= 0` ⇒ the default limit). */
3072
+ since(since?: number, limit?: number): DevLogRecord[];
3073
+ /** The highest sequence number handed out so far. */
3074
+ get lastSeq(): number;
3075
+ /** Tap rm2mlog frames off the UTO channel. */
3076
+ attachUtoMaster(utoMaster: UtoMaster): void;
3077
+ /**
3078
+ * Tap the AT/debug channel RX, where a DLO's live `printf` output arrives.
3079
+ *
3080
+ * A `DebugMaster` parses the raw byte stream (console frames, the `!`/`?`/`~`/`$`
3081
+ * level prefixes and the DLO file/line tags) instead of dumping unformatted chunks.
3082
+ */
3083
+ attachAtHandler(atHandler: AtCommandHandler): void;
3084
+ /** Decode a device payload best-effort; keep the bytes when it is not text. */
3085
+ private pushDecoded;
3086
+ /** Detach the taps and await the pending JSONL appends, so no record is lost. */
3087
+ dispose(): Promise<void>;
3088
+ }
3089
+
2618
3090
  export declare namespace Manifest {
2619
3091
  /**
2620
3092
  * The source filename where the information is stored in
@@ -2771,6 +3243,16 @@ export declare namespace Manifest {
2771
3243
  export function validateRegistryAllowedApplications(allowedApplications: undefined | null | string | string[]): Promise<string | null>;
2772
3244
  export function validateApplicationIcon(cwd: URI, fs: LocalFS, manifest: Manifest.Manifest): Promise<void>;
2773
3245
  export function validateEngineSettings(manifest: Manifest.Manifest): void;
3246
+ /**
3247
+ * Compare two "engines.backend" version strings (format like "52v006").
3248
+ * The major and minor parts are compared numerically so that values outside the zero-padded 2-digit
3249
+ * major format (e.g. "100v001") are still ordered correctly. Values that do not match the format fall
3250
+ * back to plain string ordering.
3251
+ * @param a
3252
+ * @param b
3253
+ * @returns a negative number if a < b, 0 if equal, a positive number if a > b
3254
+ */
3255
+ export function compareBackendVersion(a: string, b: string): number;
2774
3256
  /**
2775
3257
  * Validate if the given apm part is used
2776
3258
  * @param cwd
@@ -2909,6 +3391,20 @@ export declare interface MyDatanetUserInfo {
2909
3391
  customers?: MyDatanetCustomer[];
2910
3392
  }
2911
3393
 
3394
+ /**
3395
+ * A connected device: the UTO/AT primitives plus the raw transports, ready to use.
3396
+ * Call `close()` exactly once when done to dispose the AtCommandHandler/UtoMaster and
3397
+ * release the underlying transports.
3398
+ */
3399
+ declare interface OpenDevice {
3400
+ utoMaster: UtoMaster;
3401
+ /** Only present when the debug interface was claimed (`needDebug`, the default). */
3402
+ atHandler?: AtCommandHandler;
3403
+ transports: DeviceTransports;
3404
+ serial: string;
3405
+ close(): Promise<void>;
3406
+ }
3407
+
2912
3408
  /**
2913
3409
  * Packs the given directory into a deployable package using the specified configuration.
2914
3410
  *
@@ -5316,6 +5812,44 @@ export declare namespace Registry {
5316
5812
  } | {};
5317
5813
  }
5318
5814
 
5815
+ /** `GET /dev/status`'s `poll` section. */
5816
+ export declare interface StampPollerStatus {
5817
+ intervalMs: number;
5818
+ lastTick: number | null;
5819
+ lastChange: number | null;
5820
+ errors: number;
5821
+ paused: boolean;
5822
+ }
5823
+
5824
+ /**
5825
+ * Opens the transports for a device given its serial number. The default (WebUSB) factory
5826
+ * is used by {@link openDevice} unless a test/consumer supplies its own.
5827
+ */
5828
+ export declare type TransportFactory = (serial: string, needDebug?: boolean) => Promise<DeviceTransports>;
5829
+
5830
+ /**
5831
+ * Upload result interface
5832
+ */
5833
+ declare interface UploadResult {
5834
+ success: boolean;
5835
+ message: string;
5836
+ }
5837
+
5838
+ /**
5839
+ * Upload an AMX binary file to a USB device
5840
+ * @param serialNumber - The serial number of the target device
5841
+ * @param fileUri - The URI to the AMX file
5842
+ * @param fs - The filesystem interface for file operations
5843
+ * @param logger - The logger instance for output
5844
+ * @param debugLog - Enable debug logging
5845
+ * @param retryMs - Total ms budget to retry a transient device-open failure (see
5846
+ * {@link isTransientUsbOpenError}); `0` (the default) attempts once.
5847
+ * @param transportFactory - Overrides how the transports are obtained (used by tests and by
5848
+ * consumers, e.g. the VS Code extension, running on their own injected transport).
5849
+ * @returns Promise resolving to an UploadResult
5850
+ */
5851
+ declare function uploadToDevice(serialNumber: string, fileUri: URI, fs: LocalFS, logger: Log.Logger, debugLog?: boolean, retryMs?: number, transportFactory?: TransportFactory): Promise<UploadResult>;
5852
+
5319
5853
  declare function uriToMemFsPath(path: URI): string;
5320
5854
 
5321
5855
  declare interface XMLField {
@@ -5384,7 +5918,9 @@ declare namespace YamlPreCompiler {
5384
5918
  parsedYaml: null | Document_2.Parsed<ParsedNode, true>;
5385
5919
  };
5386
5920
  private yamlDocToDdeJson;
5921
+ private reservedTopLevelKeys;
5387
5922
  private getRealContainerInformation;
5923
+ private findContainerKeyRange;
5388
5924
  private findNextFreeContainer;
5389
5925
  private findPreviousUsedContainer;
5390
5926
  private createDDEJsonFields;