novac 2.0.1 → 2.2.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.
Files changed (161) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +1574 -597
  3. package/bin/novac +468 -171
  4. package/bin/nvc +522 -0
  5. package/bin/nvml +78 -17
  6. package/demo.nv +0 -0
  7. package/demo_builtins.nv +0 -0
  8. package/demo_http.nv +0 -0
  9. package/examples/bf.nv +69 -0
  10. package/examples/math.nv +21 -0
  11. package/kits/birdAPI/kitdef.js +954 -0
  12. package/kits/kitRNG/kitdef.js +740 -0
  13. package/kits/kitSSH/kitdef.js +1272 -0
  14. package/kits/kitadb/kitdef.js +606 -0
  15. package/kits/kitai/kitdef.js +2185 -0
  16. package/kits/kitansi/kitdef.js +1402 -0
  17. package/kits/kitcanvas/kitdef.js +914 -0
  18. package/kits/kitclippy/kitdef.js +925 -0
  19. package/kits/kitformat/kitdef.js +1485 -0
  20. package/kits/kitgps/kitdef.js +1862 -0
  21. package/kits/kitlibproc/kitdef.js +3 -2
  22. package/kits/kitmatrix/ex.js +19 -0
  23. package/kits/kitmatrix/kitdef.js +960 -0
  24. package/kits/kitmorse/kitdef.js +229 -0
  25. package/kits/kitmpatch/kitdef.js +906 -0
  26. package/kits/kitnet/kitdef.js +1401 -0
  27. package/kits/kitnovacweb/README.md +1416 -143
  28. package/kits/kitnovacweb/kitdef.js +92 -2
  29. package/kits/kitnovacweb/nvml/executor.js +578 -176
  30. package/kits/kitnovacweb/nvml/index.js +2 -2
  31. package/kits/kitnovacweb/nvml/lexer.js +72 -69
  32. package/kits/kitnovacweb/nvml/parser.js +328 -159
  33. package/kits/kitnovacweb/nvml/renderer.js +770 -270
  34. package/kits/kitparse/kitdef.js +1688 -0
  35. package/kits/kitproto/kitdef.js +613 -0
  36. package/kits/kitqr/kitdef.js +637 -0
  37. package/kits/kitregex++/kitdef.js +1353 -0
  38. package/kits/kitrequire/kitdef.js +1599 -0
  39. package/kits/kitx11/kitdef.js +1 -0
  40. package/kits/kitx11/kitx11.js +2472 -0
  41. package/kits/kitx11/kitx11_conn.js +948 -0
  42. package/kits/kitx11/kitx11_worker.js +121 -0
  43. package/kits/libtea/kitdef.js +2691 -0
  44. package/kits/libterm/ex.js +285 -0
  45. package/kits/libterm/kitdef.js +1927 -0
  46. package/novac/LICENSE +21 -0
  47. package/novac/README.md +1823 -0
  48. package/novac/bin/novac +950 -0
  49. package/novac/bin/nvc +522 -0
  50. package/novac/bin/nvml +542 -0
  51. package/novac/demo.nv +245 -0
  52. package/novac/demo_builtins.nv +209 -0
  53. package/novac/demo_http.nv +62 -0
  54. package/novac/examples/bf.nv +69 -0
  55. package/novac/examples/math.nv +21 -0
  56. package/novac/kits/kitai/kitdef.js +2185 -0
  57. package/novac/kits/kitansi/kitdef.js +1402 -0
  58. package/novac/kits/kitformat/kitdef.js +1485 -0
  59. package/novac/kits/kitgps/kitdef.js +1862 -0
  60. package/novac/kits/kitlibfs/kitdef.js +231 -0
  61. package/{examples/example-project/nova_modules → novac/kits}/kitlibproc/kitdef.js +3 -2
  62. package/novac/kits/kitmatrix/ex.js +19 -0
  63. package/novac/kits/kitmatrix/kitdef.js +960 -0
  64. package/novac/kits/kitmpatch/kitdef.js +906 -0
  65. package/novac/kits/kitnovacweb/README.md +1572 -0
  66. package/novac/kits/kitnovacweb/demo.nv +12 -0
  67. package/novac/kits/kitnovacweb/demo.nvml +71 -0
  68. package/novac/kits/kitnovacweb/index.nova +12 -0
  69. package/novac/kits/kitnovacweb/kitdef.js +692 -0
  70. package/novac/kits/kitnovacweb/nova.kit.json +8 -0
  71. package/novac/kits/kitnovacweb/nvml/executor.js +739 -0
  72. package/novac/kits/kitnovacweb/nvml/index.js +67 -0
  73. package/novac/kits/kitnovacweb/nvml/lexer.js +263 -0
  74. package/novac/kits/kitnovacweb/nvml/parser.js +508 -0
  75. package/novac/kits/kitnovacweb/nvml/renderer.js +924 -0
  76. package/novac/kits/kitparse/kitdef.js +1688 -0
  77. package/novac/kits/kitregex++/kitdef.js +1353 -0
  78. package/novac/kits/kitrequire/kitdef.js +1599 -0
  79. package/novac/kits/kitx11/kitdef.js +1 -0
  80. package/novac/kits/kitx11/kitx11.js +2472 -0
  81. package/novac/kits/kitx11/kitx11_conn.js +948 -0
  82. package/novac/kits/kitx11/kitx11_worker.js +121 -0
  83. package/novac/kits/libtea/tf.js +2691 -0
  84. package/novac/kits/libterm/ex.js +285 -0
  85. package/novac/kits/libterm/kitdef.js +1927 -0
  86. package/novac/node_modules/chalk/license +9 -0
  87. package/novac/node_modules/chalk/package.json +83 -0
  88. package/novac/node_modules/chalk/readme.md +297 -0
  89. package/novac/node_modules/chalk/source/index.d.ts +325 -0
  90. package/novac/node_modules/chalk/source/index.js +225 -0
  91. package/novac/node_modules/chalk/source/utilities.js +33 -0
  92. package/novac/node_modules/chalk/source/vendor/ansi-styles/index.d.ts +236 -0
  93. package/novac/node_modules/chalk/source/vendor/ansi-styles/index.js +223 -0
  94. package/novac/node_modules/chalk/source/vendor/supports-color/browser.d.ts +1 -0
  95. package/novac/node_modules/chalk/source/vendor/supports-color/browser.js +34 -0
  96. package/novac/node_modules/chalk/source/vendor/supports-color/index.d.ts +55 -0
  97. package/novac/node_modules/chalk/source/vendor/supports-color/index.js +190 -0
  98. package/novac/node_modules/commander/LICENSE +22 -0
  99. package/novac/node_modules/commander/Readme.md +1176 -0
  100. package/novac/node_modules/commander/esm.mjs +16 -0
  101. package/novac/node_modules/commander/index.js +24 -0
  102. package/novac/node_modules/commander/lib/argument.js +150 -0
  103. package/novac/node_modules/commander/lib/command.js +2777 -0
  104. package/novac/node_modules/commander/lib/error.js +39 -0
  105. package/novac/node_modules/commander/lib/help.js +747 -0
  106. package/novac/node_modules/commander/lib/option.js +380 -0
  107. package/novac/node_modules/commander/lib/suggestSimilar.js +101 -0
  108. package/novac/node_modules/commander/package-support.json +19 -0
  109. package/novac/node_modules/commander/package.json +82 -0
  110. package/novac/node_modules/commander/typings/esm.d.mts +3 -0
  111. package/novac/node_modules/commander/typings/index.d.ts +1113 -0
  112. package/novac/node_modules/node-addon-api/LICENSE.md +9 -0
  113. package/novac/node_modules/node-addon-api/README.md +95 -0
  114. package/novac/node_modules/node-addon-api/common.gypi +21 -0
  115. package/novac/node_modules/node-addon-api/except.gypi +25 -0
  116. package/novac/node_modules/node-addon-api/index.js +14 -0
  117. package/novac/node_modules/node-addon-api/napi-inl.deprecated.h +186 -0
  118. package/novac/node_modules/node-addon-api/napi-inl.h +7165 -0
  119. package/novac/node_modules/node-addon-api/napi.h +3364 -0
  120. package/novac/node_modules/node-addon-api/node_addon_api.gyp +42 -0
  121. package/novac/node_modules/node-addon-api/node_api.gyp +9 -0
  122. package/novac/node_modules/node-addon-api/noexcept.gypi +26 -0
  123. package/novac/node_modules/node-addon-api/package-support.json +21 -0
  124. package/novac/node_modules/node-addon-api/package.json +480 -0
  125. package/novac/node_modules/node-addon-api/tools/README.md +73 -0
  126. package/novac/node_modules/node-addon-api/tools/check-napi.js +99 -0
  127. package/novac/node_modules/node-addon-api/tools/clang-format.js +71 -0
  128. package/novac/node_modules/node-addon-api/tools/conversion.js +301 -0
  129. package/novac/node_modules/serialize-javascript/LICENSE +27 -0
  130. package/novac/node_modules/serialize-javascript/README.md +149 -0
  131. package/novac/node_modules/serialize-javascript/index.js +297 -0
  132. package/novac/node_modules/serialize-javascript/package.json +33 -0
  133. package/novac/package.json +27 -0
  134. package/novac/scripts/update-bin.js +24 -0
  135. package/novac/src/core/bstd.js +1035 -0
  136. package/novac/src/core/config.js +155 -0
  137. package/novac/src/core/describe.js +187 -0
  138. package/novac/src/core/emitter.js +499 -0
  139. package/novac/src/core/error.js +86 -0
  140. package/novac/src/core/executor.js +5606 -0
  141. package/novac/src/core/formatter.js +686 -0
  142. package/novac/src/core/lexer.js +1026 -0
  143. package/novac/src/core/nova_builtins.js +717 -0
  144. package/novac/src/core/nova_thread_worker.js +166 -0
  145. package/novac/src/core/parser.js +2181 -0
  146. package/novac/src/core/types.js +112 -0
  147. package/novac/src/index.js +28 -0
  148. package/novac/src/runtime/stdlib.js +244 -0
  149. package/package.json +6 -3
  150. package/scripts/update-bin.js +0 -0
  151. package/src/core/bstd.js +838 -362
  152. package/src/core/executor.js +2578 -170
  153. package/src/core/lexer.js +502 -54
  154. package/src/core/nova_builtins.js +21 -3
  155. package/src/core/parser.js +413 -72
  156. package/src/core/types.js +30 -2
  157. package/src/index.js +0 -0
  158. package/examples/example-project/README.md +0 -3
  159. package/examples/example-project/src/main.nova +0 -3
  160. package/src/core/environment.js +0 -0
  161. /package/{examples/example-project/bin/example-project.nv → novac/node_modules/node-addon-api/nothing.c} +0 -0
@@ -0,0 +1,606 @@
1
+ // kitadb — novac ADB & Fastboot kit
2
+ // Full-featured wrapper around adb and fastboot CLIs.
3
+ // Requires adb and/or fastboot to be installed and in PATH.
4
+
5
+ 'use strict';
6
+
7
+ const { spawnSync, spawn, execSync } = require('child_process');
8
+ const fs = require('fs');
9
+ const path = require('path');
10
+ const os = require('os');
11
+
12
+ // ─── HELPERS ─────────────────────────────────────────────────────────────────
13
+
14
+ function run(bin, args, opts = {}) {
15
+ const r = spawnSync(bin, args, {
16
+ encoding: 'utf8',
17
+ timeout: opts.timeout ?? 30000,
18
+ env: opts.env ?? process.env,
19
+ ...opts,
20
+ });
21
+ if (r.error) throw new Error(`[${bin}] ${r.error.message}`);
22
+ return {
23
+ stdout: (r.stdout ?? '').trim(),
24
+ stderr: (r.stderr ?? '').trim(),
25
+ status: r.status ?? -1,
26
+ ok: r.status === 0,
27
+ };
28
+ }
29
+
30
+ function runAdb(args, opts = {}) {
31
+ const serial = opts.serial;
32
+ const prefix = serial ? ['-s', serial] : [];
33
+ return run('adb', [...prefix, ...args], opts);
34
+ }
35
+
36
+ function runFastboot(args, opts = {}) {
37
+ const serial = opts.serial;
38
+ const prefix = serial ? ['-s', serial] : [];
39
+ return run('fastboot', [...prefix, ...args], opts);
40
+ }
41
+
42
+ function lines(str) {
43
+ return str.split('\n').map(l => l.trim()).filter(Boolean);
44
+ }
45
+
46
+ function requireOk(result, msg) {
47
+ if (!result.ok) throw new Error(`${msg}: ${result.stderr || result.stdout}`);
48
+ return result;
49
+ }
50
+
51
+ // ─── ADB SERVER ───────────────────────────────────────────────────────────────
52
+
53
+ const server = {
54
+ start() { return runAdb(['start-server']); },
55
+ kill() { return runAdb(['kill-server']); },
56
+ restart() { server.kill(); return server.start(); },
57
+ version() {
58
+ const r = runAdb(['version']);
59
+ const m = r.stdout.match(/Android Debug Bridge version ([\d.]+)/);
60
+ return m ? m[1] : r.stdout;
61
+ },
62
+ };
63
+
64
+ // ─── DEVICE MANAGEMENT ───────────────────────────────────────────────────────
65
+
66
+ function parseDevices(output) {
67
+ return lines(output)
68
+ .filter(l => l.includes('\t'))
69
+ .map(l => {
70
+ const [serial, ...rest] = l.split('\t');
71
+ const state = rest[0]?.trim();
72
+ const props = {};
73
+ const propStr = rest.slice(1).join(' ');
74
+ for (const m of propStr.matchAll(/(\w+):(\S+)/g)) props[m[1]] = m[2];
75
+ return { serial: serial.trim(), state, ...props };
76
+ });
77
+ }
78
+
79
+ const devices = {
80
+ list() {
81
+ const r = runAdb(['devices', '-l']);
82
+ return parseDevices(r.stdout);
83
+ },
84
+ listTransports() {
85
+ const r = runAdb(['devices', '-l']);
86
+ return parseDevices(r.stdout);
87
+ },
88
+ connect(host, port = 5555) {
89
+ return runAdb(['connect', `${host}:${port}`]);
90
+ },
91
+ disconnect(host, port) {
92
+ const target = host ? (port ? `${host}:${port}` : host) : '';
93
+ return runAdb(target ? ['disconnect', target] : ['disconnect']);
94
+ },
95
+ pair(host, port, code, opts) {
96
+ return runAdb(['pair', `${host}:${port}`, code], opts);
97
+ },
98
+ wait(state = 'device', opts = {}) {
99
+ // state: device | recovery | rescue | sideload | bootloader | disconnect
100
+ return runAdb([`wait-for-${state}`], { timeout: opts.timeout ?? 60000, ...opts });
101
+ },
102
+ serial(opts = {}) {
103
+ const r = runAdb(['get-serialno'], opts);
104
+ return r.stdout;
105
+ },
106
+ state(opts = {}) {
107
+ const r = runAdb(['get-state'], opts);
108
+ return r.stdout;
109
+ },
110
+ };
111
+
112
+ // ─── SHELL ────────────────────────────────────────────────────────────────────
113
+
114
+ const shell = {
115
+ exec(cmd, opts = {}) {
116
+ const r = runAdb(['shell', cmd], opts);
117
+ return r.stdout;
118
+ },
119
+ execRaw(cmd, opts = {}) {
120
+ return runAdb(['shell', cmd], opts);
121
+ },
122
+ // Streaming shell — returns ChildProcess
123
+ stream(cmd, opts = {}) {
124
+ const serial = opts.serial;
125
+ const prefix = serial ? ['-s', serial] : [];
126
+ return spawn('adb', [...prefix, 'shell', cmd], { stdio: 'pipe' });
127
+ },
128
+ getprop(prop, opts = {}) {
129
+ const r = runAdb(['shell', `getprop ${prop}`], opts);
130
+ return r.stdout;
131
+ },
132
+ setprop(prop, value, opts = {}) {
133
+ return runAdb(['shell', `setprop ${prop} ${value}`], opts);
134
+ },
135
+ allprops(opts = {}) {
136
+ const r = runAdb(['shell', 'getprop'], opts);
137
+ const result = {};
138
+ for (const m of r.stdout.matchAll(/\[(.+?)\]:\s*\[(.+?)\]/g)) result[m[1]] = m[2];
139
+ return result;
140
+ },
141
+ whoami(opts = {}) { return shell.exec('whoami', opts); },
142
+ uname(opts = {}) { return shell.exec('uname -a', opts); },
143
+ id(opts = {}) { return shell.exec('id', opts); },
144
+ };
145
+
146
+ // ─── FILE SYSTEM ─────────────────────────────────────────────────────────────
147
+
148
+ const fs_ = {
149
+ push(local, remote, opts = {}) {
150
+ const syncFlag = opts.sync ? ['--sync'] : [];
151
+ return runAdb(['push', ...syncFlag, local, remote], opts);
152
+ },
153
+ pull(remote, local, opts = {}) {
154
+ return runAdb(['pull', remote, local ?? '.'], opts);
155
+ },
156
+ sync(local, opts = {}) {
157
+ return runAdb(['sync', local], opts);
158
+ },
159
+ ls(path, opts = {}) {
160
+ const r = runAdb(['shell', `ls -la "${path}"`], opts);
161
+ return r.stdout;
162
+ },
163
+ rm(path, opts = {}) {
164
+ const flags = opts.recursive ? '-rf' : '-f';
165
+ return runAdb(['shell', `rm ${flags} "${path}"`], opts);
166
+ },
167
+ mkdir(path, opts = {}) {
168
+ return runAdb(['shell', `mkdir -p "${path}"`], opts);
169
+ },
170
+ cat(path, opts = {}) {
171
+ return runAdb(['shell', `cat "${path}"`], opts).stdout;
172
+ },
173
+ write(remote, content, opts = {}) {
174
+ // Write content to a temp file and push it
175
+ const tmp = path.join(os.tmpdir(), `adb_write_${Date.now()}`);
176
+ fs.writeFileSync(tmp, content);
177
+ const r = fs_.push(tmp, remote, opts);
178
+ fs.unlinkSync(tmp);
179
+ return r;
180
+ },
181
+ stat(path, opts = {}) {
182
+ const r = runAdb(['shell', `stat "${path}"`], opts);
183
+ return r.stdout;
184
+ },
185
+ exists(path, opts = {}) {
186
+ const r = runAdb(['shell', `[ -e "${path}" ] && echo 1 || echo 0`], opts);
187
+ return r.stdout.trim() === '1';
188
+ },
189
+ chmod(path, mode, opts = {}) {
190
+ return runAdb(['shell', `chmod ${mode} "${path}"`], opts);
191
+ },
192
+ md5(path, opts = {}) {
193
+ const r = runAdb(['shell', `md5sum "${path}"`], opts);
194
+ return r.stdout.split(' ')[0];
195
+ },
196
+ };
197
+
198
+ // ─── PACKAGE MANAGER ─────────────────────────────────────────────────────────
199
+
200
+ const pkg = {
201
+ install(apkPath, opts = {}) {
202
+ const flags = [];
203
+ if (opts.replace) flags.push('-r');
204
+ if (opts.test) flags.push('-t');
205
+ if (opts.downgrade) flags.push('-d');
206
+ if (opts.grant) flags.push('-g');
207
+ if (opts.instant) flags.push('--instant');
208
+ if (opts.user) flags.push('--user', String(opts.user));
209
+ if (opts.abi) flags.push('--abi', opts.abi);
210
+ return runAdb(['install', ...flags, apkPath], opts);
211
+ },
212
+ installMultiple(apks, opts = {}) {
213
+ const flags = opts.replace ? ['-r'] : [];
214
+ return runAdb(['install-multiple', ...flags, ...apks], opts);
215
+ },
216
+ uninstall(pkg, opts = {}) {
217
+ const flags = opts.keepData ? ['-k'] : [];
218
+ return runAdb(['uninstall', ...flags, pkg], opts);
219
+ },
220
+ list(opts = {}) {
221
+ const flags = [];
222
+ if (opts.third) flags.push('-3');
223
+ if (opts.system) flags.push('-s');
224
+ if (opts.disabled) flags.push('-d');
225
+ if (opts.enabled) flags.push('-e');
226
+ if (opts.user) flags.push('--user', String(opts.user));
227
+ const r = runAdb(['shell', 'pm list packages', ...flags], opts);
228
+ return lines(r.stdout).map(l => l.replace('package:', ''));
229
+ },
230
+ path(pkg, opts = {}) {
231
+ const r = runAdb(['shell', `pm path ${pkg}`], opts);
232
+ return r.stdout.replace('package:', '').trim();
233
+ },
234
+ clear(pkg, opts = {}) {
235
+ return runAdb(['shell', `pm clear ${pkg}`], opts);
236
+ },
237
+ enable(pkg, opts = {}) {
238
+ return runAdb(['shell', `pm enable ${pkg}`], opts);
239
+ },
240
+ disable(pkg, opts = {}) {
241
+ return runAdb(['shell', `pm disable-user ${pkg}`], opts);
242
+ },
243
+ grant(pkg, permission, opts = {}) {
244
+ return runAdb(['shell', `pm grant ${pkg} ${permission}`], opts);
245
+ },
246
+ revoke(pkg, permission, opts = {}) {
247
+ return runAdb(['shell', `pm revoke ${pkg} ${permission}`], opts);
248
+ },
249
+ dump(pkg, opts = {}) {
250
+ return runAdb(['shell', `dumpsys package ${pkg}`], opts).stdout;
251
+ },
252
+ start(pkg, activity, opts = {}) {
253
+ return runAdb(['shell', `am start -n ${pkg}/${activity}`], opts);
254
+ },
255
+ startAction(action, opts = {}) {
256
+ const uri = opts.uri ? [opts.uri] : [];
257
+ return runAdb(['shell', `am start -a ${action}`, ...uri], opts);
258
+ },
259
+ stop(pkg, opts = {}) {
260
+ return runAdb(['shell', `am force-stop ${pkg}`], opts);
261
+ },
262
+ broadcast(action, opts = {}) {
263
+ return runAdb(['shell', `am broadcast -a ${action}`], opts);
264
+ },
265
+ };
266
+
267
+ // ─── LOGCAT ───────────────────────────────────────────────────────────────────
268
+
269
+ const logcat = {
270
+ // Returns ChildProcess for streaming
271
+ stream(opts = {}) {
272
+ const args = ['logcat'];
273
+ if (opts.tag) args.push('-s', opts.tag);
274
+ if (opts.format) args.push('-v', opts.format);
275
+ if (opts.buffer) args.push('-b', opts.buffer);
276
+ if (opts.clear) args.push('-c');
277
+ if (opts.filter) args.push(opts.filter);
278
+ const serial = opts.serial;
279
+ const prefix = serial ? ['-s', serial] : [];
280
+ return spawn('adb', [...prefix, ...args], { stdio: 'pipe' });
281
+ },
282
+ dump(opts = {}) {
283
+ const args = ['logcat', '-d'];
284
+ if (opts.tag) args.push('-s', opts.tag);
285
+ if (opts.format) args.push('-v', opts.format);
286
+ if (opts.lines) args.push('-t', String(opts.lines));
287
+ if (opts.buffer) args.push('-b', opts.buffer);
288
+ return runAdb(args, opts).stdout;
289
+ },
290
+ clear(opts = {}) {
291
+ return runAdb(['logcat', '-c'], opts);
292
+ },
293
+ buffers(opts = {}) {
294
+ return runAdb(['logcat', '-g'], opts).stdout;
295
+ },
296
+ };
297
+
298
+ // ─── INPUT ────────────────────────────────────────────────────────────────────
299
+
300
+ const input = {
301
+ tap(x, y, opts = {}) {
302
+ return runAdb(['shell', `input tap ${x} ${y}`], opts);
303
+ },
304
+ swipe(x1, y1, x2, y2, duration = 300, opts = {}) {
305
+ return runAdb(['shell', `input swipe ${x1} ${y1} ${x2} ${y2} ${duration}`], opts);
306
+ },
307
+ text(str, opts = {}) {
308
+ // Escape special chars for shell
309
+ const escaped = str.replace(/[ &;|<>()]/g, '\\$&').replace(/'/g, "\\'");
310
+ return runAdb(['shell', `input text '${escaped}'`], opts);
311
+ },
312
+ keyevent(key, opts = {}) {
313
+ return runAdb(['shell', `input keyevent ${key}`], opts);
314
+ },
315
+ press: {
316
+ home: (opts) => input.keyevent('KEYCODE_HOME', opts),
317
+ back: (opts) => input.keyevent('KEYCODE_BACK', opts),
318
+ menu: (opts) => input.keyevent('KEYCODE_MENU', opts),
319
+ power: (opts) => input.keyevent('KEYCODE_POWER', opts),
320
+ volumeUp: (opts) => input.keyevent('KEYCODE_VOLUME_UP', opts),
321
+ volumeDown: (opts) => input.keyevent('KEYCODE_VOLUME_DOWN', opts),
322
+ enter: (opts) => input.keyevent('KEYCODE_ENTER', opts),
323
+ tab: (opts) => input.keyevent('KEYCODE_TAB', opts),
324
+ del: (opts) => input.keyevent('KEYCODE_DEL', opts),
325
+ recent: (opts) => input.keyevent('KEYCODE_APP_SWITCH', opts),
326
+ },
327
+ screenshot(localPath, opts = {}) {
328
+ const tmp = '/sdcard/screenshot_tmp.png';
329
+ runAdb(['shell', `screencap -p ${tmp}`], opts);
330
+ const dest = localPath ?? `screenshot_${Date.now()}.png`;
331
+ runAdb(['pull', tmp, dest], opts);
332
+ runAdb(['shell', `rm ${tmp}`], opts);
333
+ return dest;
334
+ },
335
+ screenrecord(remotePath, opts = {}) {
336
+ const args = ['shell', 'screenrecord'];
337
+ if (opts.size) args.push('--size', opts.size);
338
+ if (opts.bitrate) args.push('--bit-rate', String(opts.bitrate));
339
+ if (opts.time) args.push('--time-limit', String(opts.time));
340
+ args.push(remotePath);
341
+ const serial = opts.serial;
342
+ const prefix = serial ? ['-s', serial] : [];
343
+ return spawn('adb', [...prefix, ...args], { stdio: 'pipe' });
344
+ },
345
+ };
346
+
347
+ // ─── SYSTEM ───────────────────────────────────────────────────────────────────
348
+
349
+ const system = {
350
+ reboot(mode, opts = {}) {
351
+ // mode: undefined | 'bootloader' | 'recovery' | 'sideload' | 'sideload-auto-reboot'
352
+ const args = mode ? ['reboot', mode] : ['reboot'];
353
+ return runAdb(args, opts);
354
+ },
355
+ remount(opts = {}) { return runAdb(['remount'], opts); },
356
+ root(opts = {}) { return runAdb(['root'], opts); },
357
+ unroot(opts = {}) { return runAdb(['unroot'], opts); },
358
+ sideload(zip, opts = {}) { return runAdb(['sideload', zip], { timeout: 300000, ...opts }); },
359
+ bugreport(dest, opts = {}) {
360
+ return runAdb(['bugreport', dest ?? `bugreport_${Date.now()}.zip`], { timeout: 120000, ...opts });
361
+ },
362
+ batterystats(opts = {}) {
363
+ return runAdb(['shell', 'dumpsys batterystats'], opts).stdout;
364
+ },
365
+ battery(opts = {}) {
366
+ const r = runAdb(['shell', 'dumpsys battery'], opts).stdout;
367
+ const result = {};
368
+ for (const m of r.matchAll(/\s+(\w[\w ]+):\s+(\S+)/g)) result[m[1].trim()] = m[2].trim();
369
+ return result;
370
+ },
371
+ wifi(opts = {}) {
372
+ return runAdb(['shell', 'dumpsys wifi'], opts).stdout;
373
+ },
374
+ cpuinfo(opts = {}) {
375
+ return runAdb(['shell', 'dumpsys cpuinfo'], opts).stdout;
376
+ },
377
+ meminfo(pkg, opts = {}) {
378
+ return runAdb(['shell', `dumpsys meminfo ${pkg ?? ''}`], opts).stdout;
379
+ },
380
+ diskstats(opts = {}) {
381
+ return runAdb(['shell', 'dumpsys diskstats'], opts).stdout;
382
+ },
383
+ netstat(opts = {}) {
384
+ return runAdb(['shell', 'cat /proc/net/tcp'], opts).stdout;
385
+ },
386
+ uptime(opts = {}) {
387
+ return runAdb(['shell', 'uptime'], opts).stdout;
388
+ },
389
+ date(opts = {}) {
390
+ return runAdb(['shell', 'date'], opts).stdout;
391
+ },
392
+ setDate(dateStr, opts = {}) {
393
+ // dateStr: MMDDhhmmYYYY.ss
394
+ return runAdb(['shell', `date ${dateStr}`], opts);
395
+ },
396
+ ps(opts = {}) {
397
+ return runAdb(['shell', 'ps -A'], opts).stdout;
398
+ },
399
+ kill(pid, opts = {}) {
400
+ return runAdb(['shell', `kill ${pid}`], opts);
401
+ },
402
+ tcpip(port = 5555, opts = {}) {
403
+ return runAdb(['tcpip', String(port)], opts);
404
+ },
405
+ usb(opts = {}) {
406
+ return runAdb(['usb'], opts);
407
+ },
408
+ forward(local, remote, opts = {}) {
409
+ return runAdb(['forward', local, remote], opts);
410
+ },
411
+ forwardList(opts = {}) {
412
+ return runAdb(['forward', '--list'], opts).stdout;
413
+ },
414
+ forwardRemove(local, opts = {}) {
415
+ return runAdb(['forward', '--remove', local], opts);
416
+ },
417
+ forwardRemoveAll(opts = {}) {
418
+ return runAdb(['forward', '--remove-all'], opts);
419
+ },
420
+ reverse(remote, local, opts = {}) {
421
+ return runAdb(['reverse', remote, local], opts);
422
+ },
423
+ reverseList(opts = {}) {
424
+ return runAdb(['reverse', '--list'], opts).stdout;
425
+ },
426
+ reverseRemoveAll(opts = {}) {
427
+ return runAdb(['reverse', '--remove-all'], opts);
428
+ },
429
+ };
430
+
431
+ // ─── FASTBOOT ─────────────────────────────────────────────────────────────────
432
+
433
+ const fastboot = {
434
+ devices() {
435
+ const r = runFastboot(['devices']);
436
+ return lines(r.stdout).map(l => {
437
+ const [serial, state] = l.split('\t');
438
+ return { serial: serial.trim(), state: (state ?? 'fastboot').trim() };
439
+ });
440
+ },
441
+ flash(partition, image, opts = {}) {
442
+ const flags = opts.slot ? ['--slot', opts.slot] : [];
443
+ return runFastboot(['flash', ...flags, partition, image], { timeout: 120000, ...opts });
444
+ },
445
+ flashAll(opts = {}) {
446
+ const flags = opts.wipe ? ['-w'] : [];
447
+ return runFastboot(['flashall', ...flags], { timeout: 300000, ...opts });
448
+ },
449
+ erase(partition, opts = {}) {
450
+ return runFastboot(['erase', partition], opts);
451
+ },
452
+ format(partition, opts = {}) {
453
+ return runFastboot(['format', partition], opts);
454
+ },
455
+ reboot(target, opts = {}) {
456
+ // target: undefined | 'bootloader' | 'recovery' | 'fastboot'
457
+ const args = target ? ['reboot', target] : ['reboot'];
458
+ return runFastboot(args, opts);
459
+ },
460
+ boot(image, opts = {}) {
461
+ return runFastboot(['boot', image], { timeout: 60000, ...opts });
462
+ },
463
+ update(zip, opts = {}) {
464
+ const flags = opts.wipe ? ['-w'] : [];
465
+ return runFastboot(['update', ...flags, zip], { timeout: 300000, ...opts });
466
+ },
467
+ getvar(variable, opts = {}) {
468
+ const r = runFastboot(['getvar', variable], opts);
469
+ const m = r.stderr.match(new RegExp(`${variable}:\\s*(.+)`));
470
+ return m ? m[1].trim() : r.stderr;
471
+ },
472
+ getvars(opts = {}) {
473
+ const r = runFastboot(['getvar', 'all'], opts);
474
+ const result = {};
475
+ for (const m of r.stderr.matchAll(/(\w[\w-]*):\s*(.+)/g)) result[m[1]] = m[2].trim();
476
+ return result;
477
+ },
478
+ oem(cmd, opts = {}) {
479
+ return runFastboot(['oem', cmd], opts);
480
+ },
481
+ flashing(cmd, opts = {}) {
482
+ return runFastboot(['flashing', cmd], opts);
483
+ },
484
+ unlock(opts = {}) {
485
+ return fastboot.flashing('unlock', opts);
486
+ },
487
+ lock(opts = {}) {
488
+ return fastboot.flashing('lock', opts);
489
+ },
490
+ unlockCritical(opts = {}) {
491
+ return fastboot.flashing('unlock_critical', opts);
492
+ },
493
+ lockCritical(opts = {}) {
494
+ return fastboot.flashing('lock_critical', opts);
495
+ },
496
+ setActive(slot, opts = {}) {
497
+ return runFastboot(['set_active', slot], opts);
498
+ },
499
+ createPartition(partition, size, opts = {}) {
500
+ return runFastboot(['create-logical-partition', partition, String(size)], opts);
501
+ },
502
+ deletePartition(partition, opts = {}) {
503
+ return runFastboot(['delete-logical-partition', partition], opts);
504
+ },
505
+ resizePartition(partition, size, opts = {}) {
506
+ return runFastboot(['resize-logical-partition', partition, String(size)], opts);
507
+ },
508
+ wipeSuper(misc, opts = {}) {
509
+ return runFastboot(['wipe-super', misc ?? ''], opts);
510
+ },
511
+ stage(file, opts = {}) {
512
+ return runFastboot(['stage', file], opts);
513
+ },
514
+ getStaged(file, opts = {}) {
515
+ return runFastboot(['get_staged', file], opts);
516
+ },
517
+ version(opts = {}) {
518
+ const r = runFastboot(['--version'], opts);
519
+ return r.stdout || r.stderr;
520
+ },
521
+ };
522
+
523
+ // ─── ADB BACKUP / RESTORE ────────────────────────────────────────────────────
524
+
525
+ const backup = {
526
+ create(dest, opts = {}) {
527
+ const args = ['backup'];
528
+ if (opts.apk) args.push('-apk');
529
+ if (opts.shared) args.push('-shared');
530
+ if (opts.system) args.push('-system');
531
+ if (opts.all) args.push('-all');
532
+ if (opts.packages) args.push(...opts.packages);
533
+ args.push('-f', dest ?? `backup_${Date.now()}.ab`);
534
+ return runAdb(args, { timeout: 300000, ...opts });
535
+ },
536
+ restore(src, opts = {}) {
537
+ return runAdb(['restore', src], { timeout: 300000, ...opts });
538
+ },
539
+ };
540
+
541
+ // ─── JDWP / PROFILING ────────────────────────────────────────────────────────
542
+
543
+ const debug = {
544
+ jdwp(opts = {}) {
545
+ return runAdb(['jdwp'], opts).stdout;
546
+ },
547
+ trackJdwp(opts = {}) {
548
+ const serial = opts.serial;
549
+ const prefix = serial ? ['-s', serial] : [];
550
+ return spawn('adb', [...prefix, 'track-jdwp'], { stdio: 'pipe' });
551
+ },
552
+ startServer(opts = {}) { return server.start(); },
553
+ killServer(opts = {}) { return server.kill(); },
554
+ };
555
+
556
+ // ─── CONTENT PROVIDER ────────────────────────────────────────────────────────
557
+
558
+ const content = {
559
+ query(uri, opts = {}) {
560
+ const where = opts.where ? `--where "${opts.where}"` : '';
561
+ return runAdb(['shell', `content query --uri ${uri} ${where}`], opts).stdout;
562
+ },
563
+ insert(uri, values, opts = {}) {
564
+ const vals = Object.entries(values).map(([k,v]) => `--bind ${k}:s:${v}`).join(' ');
565
+ return runAdb(['shell', `content insert --uri ${uri} ${vals}`], opts);
566
+ },
567
+ update(uri, values, opts = {}) {
568
+ const vals = Object.entries(values).map(([k,v]) => `--bind ${k}:s:${v}`).join(' ');
569
+ const where = opts.where ? `--where "${opts.where}"` : '';
570
+ return runAdb(['shell', `content update --uri ${uri} ${vals} ${where}`], opts);
571
+ },
572
+ delete(uri, opts = {}) {
573
+ const where = opts.where ? `--where "${opts.where}"` : '';
574
+ return runAdb(['shell', `content delete --uri ${uri} ${where}`], opts);
575
+ },
576
+ };
577
+
578
+ // ─── MDNS ─────────────────────────────────────────────────────────────────────
579
+
580
+ const mdns = {
581
+ check(opts = {}) { return runAdb(['mdns', 'check'], opts); },
582
+ services(opts = {}){ return runAdb(['mdns', 'services'], opts).stdout; },
583
+ };
584
+
585
+ // ─── EXPORTS ─────────────────────────────────────────────────────────────────
586
+
587
+ module.exports = {
588
+ kitdef: {
589
+ server,
590
+ devices,
591
+ shell,
592
+ fs: fs_,
593
+ pkg,
594
+ logcat,
595
+ input,
596
+ system,
597
+ fastboot,
598
+ backup,
599
+ debug,
600
+ content,
601
+ mdns,
602
+ // Low-level runner for anything not covered
603
+ runAdb,
604
+ runFastboot,
605
+ }
606
+ };