@alwaysai/device-agent 1.4.0 → 2.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.
Files changed (313) hide show
  1. package/lib/application-control/config.d.ts.map +1 -1
  2. package/lib/application-control/config.js +10 -5
  3. package/lib/application-control/config.js.map +1 -1
  4. package/lib/application-control/environment-variables.d.ts +1 -5
  5. package/lib/application-control/environment-variables.d.ts.map +1 -1
  6. package/lib/application-control/environment-variables.js +9 -26
  7. package/lib/application-control/environment-variables.js.map +1 -1
  8. package/lib/application-control/environment-variables.test.js +27 -7
  9. package/lib/application-control/environment-variables.test.js.map +1 -1
  10. package/lib/application-control/index.d.ts +4 -4
  11. package/lib/application-control/index.d.ts.map +1 -1
  12. package/lib/application-control/index.js +1 -4
  13. package/lib/application-control/index.js.map +1 -1
  14. package/lib/application-control/install.d.ts.map +1 -1
  15. package/lib/application-control/install.js +9 -7
  16. package/lib/application-control/install.js.map +1 -1
  17. package/lib/application-control/models.d.ts +5 -11
  18. package/lib/application-control/models.d.ts.map +1 -1
  19. package/lib/application-control/models.js +27 -64
  20. package/lib/application-control/models.js.map +1 -1
  21. package/lib/application-control/status.d.ts.map +1 -1
  22. package/lib/application-control/status.js +10 -12
  23. package/lib/application-control/status.js.map +1 -1
  24. package/lib/application-control/utils.d.ts +0 -4
  25. package/lib/application-control/utils.d.ts.map +1 -1
  26. package/lib/application-control/utils.js +3 -26
  27. package/lib/application-control/utils.js.map +1 -1
  28. package/lib/cloud-connection/bootstrap-provision.js +3 -2
  29. package/lib/cloud-connection/bootstrap-provision.js.map +1 -1
  30. package/lib/cloud-connection/device-agent-cloud-connection.d.ts +11 -16
  31. package/lib/cloud-connection/device-agent-cloud-connection.d.ts.map +1 -1
  32. package/lib/cloud-connection/device-agent-cloud-connection.js +295 -246
  33. package/lib/cloud-connection/device-agent-cloud-connection.js.map +1 -1
  34. package/lib/cloud-connection/device-agent.d.ts.map +1 -1
  35. package/lib/cloud-connection/device-agent.js +11 -9
  36. package/lib/cloud-connection/device-agent.js.map +1 -1
  37. package/lib/cloud-connection/live-updates-handler.d.ts +18 -27
  38. package/lib/cloud-connection/live-updates-handler.d.ts.map +1 -1
  39. package/lib/cloud-connection/live-updates-handler.js +58 -170
  40. package/lib/cloud-connection/live-updates-handler.js.map +1 -1
  41. package/lib/cloud-connection/live-updates-handler.test.js +76 -54
  42. package/lib/cloud-connection/live-updates-handler.test.js.map +1 -1
  43. package/lib/cloud-connection/passthrough-handler.d.ts +9 -4
  44. package/lib/cloud-connection/passthrough-handler.d.ts.map +1 -1
  45. package/lib/cloud-connection/passthrough-handler.js +95 -62
  46. package/lib/cloud-connection/passthrough-handler.js.map +1 -1
  47. package/lib/cloud-connection/shadow-handler.d.ts +5 -1
  48. package/lib/cloud-connection/shadow-handler.d.ts.map +1 -1
  49. package/lib/cloud-connection/shadow-handler.js +63 -31
  50. package/lib/cloud-connection/shadow-handler.js.map +1 -1
  51. package/lib/cloud-connection/shadow-handler.test.js +45 -57
  52. package/lib/cloud-connection/shadow-handler.test.js.map +1 -1
  53. package/lib/cloud-connection/shadow.d.ts.map +1 -1
  54. package/lib/cloud-connection/shadow.js +2 -1
  55. package/lib/cloud-connection/shadow.js.map +1 -1
  56. package/lib/cloud-connection/transaction-manager.d.ts +7 -2
  57. package/lib/cloud-connection/transaction-manager.d.ts.map +1 -1
  58. package/lib/cloud-connection/transaction-manager.js +29 -29
  59. package/lib/cloud-connection/transaction-manager.js.map +1 -1
  60. package/lib/cloud-connection/transaction-manager.test.js +105 -3
  61. package/lib/cloud-connection/transaction-manager.test.js.map +1 -1
  62. package/lib/device-control/device-control.d.ts +14 -6
  63. package/lib/device-control/device-control.d.ts.map +1 -1
  64. package/lib/device-control/device-control.js +172 -72
  65. package/lib/device-control/device-control.js.map +1 -1
  66. package/lib/docker/docker-compose.d.ts +14 -0
  67. package/lib/docker/docker-compose.d.ts.map +1 -0
  68. package/lib/docker/docker-compose.js +57 -0
  69. package/lib/docker/docker-compose.js.map +1 -0
  70. package/lib/index.js +2 -5
  71. package/lib/index.js.map +1 -1
  72. package/lib/infrastructure/agent-config.d.ts +46 -14
  73. package/lib/infrastructure/agent-config.d.ts.map +1 -1
  74. package/lib/infrastructure/agent-config.js +36 -21
  75. package/lib/infrastructure/agent-config.js.map +1 -1
  76. package/lib/infrastructure/agent-config.test.js +6 -1
  77. package/lib/infrastructure/agent-config.test.js.map +1 -1
  78. package/lib/infrastructure/config-check-utility.d.ts +6 -0
  79. package/lib/infrastructure/config-check-utility.d.ts.map +1 -0
  80. package/lib/infrastructure/config-check-utility.js +67 -0
  81. package/lib/infrastructure/config-check-utility.js.map +1 -0
  82. package/lib/infrastructure/config-check-utility.test.d.ts +2 -0
  83. package/lib/infrastructure/config-check-utility.test.d.ts.map +1 -0
  84. package/lib/infrastructure/config-check-utility.test.js +109 -0
  85. package/lib/infrastructure/config-check-utility.test.js.map +1 -0
  86. package/lib/infrastructure/device-certificate.d.ts +10 -0
  87. package/lib/infrastructure/device-certificate.d.ts.map +1 -0
  88. package/lib/infrastructure/device-certificate.js +47 -0
  89. package/lib/infrastructure/device-certificate.js.map +1 -0
  90. package/lib/infrastructure/device-certificate.test.d.ts +2 -0
  91. package/lib/infrastructure/device-certificate.test.d.ts.map +1 -0
  92. package/lib/infrastructure/device-certificate.test.js +24 -0
  93. package/lib/infrastructure/device-certificate.test.js.map +1 -0
  94. package/lib/infrastructure/legacy-migration/legacy-file.test.d.ts +2 -0
  95. package/lib/infrastructure/legacy-migration/legacy-file.test.d.ts.map +1 -0
  96. package/lib/infrastructure/legacy-migration/legacy-file.test.js +61 -0
  97. package/lib/infrastructure/legacy-migration/legacy-file.test.js.map +1 -0
  98. package/lib/infrastructure/legacy-migration/legacy-files.d.ts +75 -0
  99. package/lib/infrastructure/legacy-migration/legacy-files.d.ts.map +1 -0
  100. package/lib/infrastructure/legacy-migration/legacy-files.js +75 -0
  101. package/lib/infrastructure/legacy-migration/legacy-files.js.map +1 -0
  102. package/lib/infrastructure/legacy-migration/legacy-migration.d.ts +6 -0
  103. package/lib/infrastructure/legacy-migration/legacy-migration.d.ts.map +1 -0
  104. package/lib/infrastructure/legacy-migration/legacy-migration.js +149 -0
  105. package/lib/infrastructure/legacy-migration/legacy-migration.js.map +1 -0
  106. package/lib/infrastructure/legacy-migration/legacy-migration.test.d.ts +2 -0
  107. package/lib/infrastructure/legacy-migration/legacy-migration.test.d.ts.map +1 -0
  108. package/lib/infrastructure/legacy-migration/legacy-migration.test.js +226 -0
  109. package/lib/infrastructure/legacy-migration/legacy-migration.test.js.map +1 -0
  110. package/lib/infrastructure/require-files-present-ready.test.d.ts +2 -0
  111. package/lib/infrastructure/require-files-present-ready.test.d.ts.map +1 -0
  112. package/lib/infrastructure/require-files-present-ready.test.js +44 -0
  113. package/lib/infrastructure/require-files-present-ready.test.js.map +1 -0
  114. package/lib/infrastructure/required-config-checks.d.ts +2 -0
  115. package/lib/infrastructure/required-config-checks.d.ts.map +1 -0
  116. package/lib/infrastructure/required-config-checks.js +30 -0
  117. package/lib/infrastructure/required-config-checks.js.map +1 -0
  118. package/lib/infrastructure/tokens-and-device-cfg.d.ts.map +1 -1
  119. package/lib/infrastructure/tokens-and-device-cfg.js +11 -8
  120. package/lib/infrastructure/tokens-and-device-cfg.js.map +1 -1
  121. package/lib/local-connection/rabbitmq-connection.d.ts.map +1 -1
  122. package/lib/local-connection/rabbitmq-connection.js +21 -21
  123. package/lib/local-connection/rabbitmq-connection.js.map +1 -1
  124. package/lib/secure-tunneling/secure-tunneling.d.ts +15 -23
  125. package/lib/secure-tunneling/secure-tunneling.d.ts.map +1 -1
  126. package/lib/secure-tunneling/secure-tunneling.js +52 -47
  127. package/lib/secure-tunneling/secure-tunneling.js.map +1 -1
  128. package/lib/secure-tunneling/secure-tunneling.test.js +29 -31
  129. package/lib/secure-tunneling/secure-tunneling.test.js.map +1 -1
  130. package/lib/subcommands/app/analytics.d.ts.map +1 -1
  131. package/lib/subcommands/app/analytics.js +1 -2
  132. package/lib/subcommands/app/analytics.js.map +1 -1
  133. package/lib/subcommands/app/env-vars.d.ts +4 -0
  134. package/lib/subcommands/app/env-vars.d.ts.map +1 -1
  135. package/lib/subcommands/app/env-vars.js +52 -6
  136. package/lib/subcommands/app/env-vars.js.map +1 -1
  137. package/lib/subcommands/app/index.d.ts.map +1 -1
  138. package/lib/subcommands/app/index.js +1 -3
  139. package/lib/subcommands/app/index.js.map +1 -1
  140. package/lib/subcommands/app/models.d.ts +0 -11
  141. package/lib/subcommands/app/models.d.ts.map +1 -1
  142. package/lib/subcommands/app/models.js +2 -58
  143. package/lib/subcommands/app/models.js.map +1 -1
  144. package/lib/subcommands/app/shadow.d.ts.map +1 -1
  145. package/lib/subcommands/app/shadow.js +6 -5
  146. package/lib/subcommands/app/shadow.js.map +1 -1
  147. package/lib/subcommands/app/version.d.ts.map +1 -1
  148. package/lib/subcommands/app/version.js +2 -4
  149. package/lib/subcommands/app/version.js.map +1 -1
  150. package/lib/subcommands/config.d.ts +2 -0
  151. package/lib/subcommands/config.d.ts.map +1 -0
  152. package/lib/subcommands/config.js +39 -0
  153. package/lib/subcommands/config.js.map +1 -0
  154. package/lib/subcommands/device/clean.d.ts +1 -1
  155. package/lib/subcommands/device/clean.d.ts.map +1 -1
  156. package/lib/subcommands/device/clean.js +25 -15
  157. package/lib/subcommands/device/clean.js.map +1 -1
  158. package/lib/subcommands/device/get-info.d.ts +2 -0
  159. package/lib/subcommands/device/get-info.d.ts.map +1 -0
  160. package/lib/subcommands/device/get-info.js +36 -0
  161. package/lib/subcommands/device/get-info.js.map +1 -0
  162. package/lib/subcommands/device/index.d.ts.map +1 -1
  163. package/lib/subcommands/device/index.js +13 -2
  164. package/lib/subcommands/device/index.js.map +1 -1
  165. package/lib/subcommands/device/init.d.ts +5 -0
  166. package/lib/subcommands/device/init.d.ts.map +1 -0
  167. package/lib/subcommands/device/{device.js → init.js} +10 -49
  168. package/lib/subcommands/device/init.js.map +1 -0
  169. package/lib/subcommands/device/migrate.d.ts +2 -0
  170. package/lib/subcommands/device/migrate.d.ts.map +1 -0
  171. package/lib/subcommands/device/migrate.js +24 -0
  172. package/lib/subcommands/device/migrate.js.map +1 -0
  173. package/lib/subcommands/device/refresh.d.ts +2 -0
  174. package/lib/subcommands/device/refresh.d.ts.map +1 -0
  175. package/lib/subcommands/device/refresh.js +25 -0
  176. package/lib/subcommands/device/refresh.js.map +1 -0
  177. package/lib/subcommands/device/restart.d.ts +2 -0
  178. package/lib/subcommands/device/restart.d.ts.map +1 -0
  179. package/lib/subcommands/device/restart.js +14 -0
  180. package/lib/subcommands/device/restart.js.map +1 -0
  181. package/lib/subcommands/index.d.ts +1 -1
  182. package/lib/subcommands/index.d.ts.map +1 -1
  183. package/lib/subcommands/index.js +3 -1
  184. package/lib/subcommands/index.js.map +1 -1
  185. package/lib/subcommands/rabbitmq-connection.d.ts +1 -1
  186. package/lib/subcommands/rabbitmq-connection.d.ts.map +1 -1
  187. package/lib/util/aai-error.d.ts +12 -0
  188. package/lib/util/aai-error.d.ts.map +1 -0
  189. package/lib/util/aai-error.js +11 -0
  190. package/lib/util/aai-error.js.map +1 -0
  191. package/lib/util/aws-regions.d.ts +2 -0
  192. package/lib/util/aws-regions.d.ts.map +1 -0
  193. package/lib/util/{cloud-mode-ready.js → aws-regions.js} +2 -20
  194. package/lib/util/aws-regions.js.map +1 -0
  195. package/lib/util/check-for-updates.d.ts +3 -0
  196. package/lib/util/check-for-updates.d.ts.map +1 -0
  197. package/lib/util/check-for-updates.js +46 -0
  198. package/lib/util/check-for-updates.js.map +1 -0
  199. package/lib/util/clean-certs.d.ts.map +1 -1
  200. package/lib/util/clean-certs.js +5 -4
  201. package/lib/util/clean-certs.js.map +1 -1
  202. package/lib/util/directories.d.ts +4 -18
  203. package/lib/util/directories.d.ts.map +1 -1
  204. package/lib/util/directories.js +18 -32
  205. package/lib/util/directories.js.map +1 -1
  206. package/lib/util/file.d.ts +11 -0
  207. package/lib/util/file.d.ts.map +1 -0
  208. package/lib/util/file.js +127 -0
  209. package/lib/util/file.js.map +1 -0
  210. package/lib/util/file.test.d.ts +2 -0
  211. package/lib/util/file.test.d.ts.map +1 -0
  212. package/lib/util/file.test.js +87 -0
  213. package/lib/util/file.test.js.map +1 -0
  214. package/lib/util/get-device-id.d.ts.map +1 -1
  215. package/lib/util/get-device-id.js +7 -1
  216. package/lib/util/get-device-id.js.map +1 -1
  217. package/lib/util/http-client.js +3 -3
  218. package/lib/util/http-client.js.map +1 -1
  219. package/package.json +22 -19
  220. package/readme.md +15 -35
  221. package/src/application-control/config.ts +10 -13
  222. package/src/application-control/environment-variables.test.ts +28 -7
  223. package/src/application-control/environment-variables.ts +13 -40
  224. package/src/application-control/index.ts +3 -16
  225. package/src/application-control/install.ts +16 -10
  226. package/src/application-control/models.ts +40 -98
  227. package/src/application-control/status.ts +9 -7
  228. package/src/application-control/utils.ts +1 -29
  229. package/src/cloud-connection/bootstrap-provision.ts +7 -7
  230. package/src/cloud-connection/device-agent-cloud-connection.ts +647 -509
  231. package/src/cloud-connection/device-agent.ts +16 -7
  232. package/src/cloud-connection/live-updates-handler.test.ts +137 -64
  233. package/src/cloud-connection/live-updates-handler.ts +103 -234
  234. package/src/cloud-connection/passthrough-handler.ts +134 -75
  235. package/src/cloud-connection/shadow-handler.test.ts +45 -57
  236. package/src/cloud-connection/shadow-handler.ts +114 -56
  237. package/src/cloud-connection/shadow.ts +4 -1
  238. package/src/cloud-connection/transaction-manager.test.ts +127 -3
  239. package/src/cloud-connection/transaction-manager.ts +68 -39
  240. package/src/device-control/device-control.ts +179 -72
  241. package/src/docker/docker-compose.ts +61 -0
  242. package/src/index.ts +2 -6
  243. package/src/infrastructure/agent-config.test.ts +9 -2
  244. package/src/infrastructure/agent-config.ts +45 -46
  245. package/src/infrastructure/config-check-utility.test.ts +154 -0
  246. package/src/infrastructure/config-check-utility.ts +77 -0
  247. package/src/infrastructure/device-certificate.test.ts +40 -0
  248. package/src/infrastructure/device-certificate.ts +58 -0
  249. package/src/infrastructure/legacy-migration/legacy-file.test.ts +88 -0
  250. package/src/infrastructure/legacy-migration/legacy-files.ts +101 -0
  251. package/src/infrastructure/legacy-migration/legacy-migration.test.ts +396 -0
  252. package/src/infrastructure/legacy-migration/legacy-migration.ts +229 -0
  253. package/src/infrastructure/require-files-present-ready.test.ts +53 -0
  254. package/src/infrastructure/required-config-checks.ts +33 -0
  255. package/src/infrastructure/tokens-and-device-cfg.ts +12 -10
  256. package/src/local-connection/rabbitmq-connection.ts +28 -23
  257. package/src/secure-tunneling/secure-tunneling.test.ts +37 -39
  258. package/src/secure-tunneling/secure-tunneling.ts +74 -69
  259. package/src/subcommands/app/analytics.ts +2 -4
  260. package/src/subcommands/app/env-vars.ts +72 -9
  261. package/src/subcommands/app/index.ts +3 -11
  262. package/src/subcommands/app/models.ts +5 -81
  263. package/src/subcommands/app/shadow.ts +6 -5
  264. package/src/subcommands/app/version.ts +3 -4
  265. package/src/subcommands/config.ts +42 -0
  266. package/src/subcommands/device/clean.ts +32 -18
  267. package/src/subcommands/device/get-info.ts +49 -0
  268. package/src/subcommands/device/index.ts +13 -2
  269. package/src/subcommands/device/{device.ts → init.ts} +11 -69
  270. package/src/subcommands/device/migrate.ts +20 -0
  271. package/src/subcommands/device/refresh.ts +23 -0
  272. package/src/subcommands/device/restart.ts +11 -0
  273. package/src/subcommands/index.ts +3 -1
  274. package/src/util/aai-error.ts +20 -0
  275. package/src/util/{cloud-mode-ready.ts → aws-regions.ts} +0 -24
  276. package/src/util/check-for-updates.ts +53 -0
  277. package/src/util/clean-certs.ts +8 -4
  278. package/src/util/directories.ts +23 -67
  279. package/src/util/file.test.ts +90 -0
  280. package/src/util/file.ts +156 -0
  281. package/src/util/get-device-id.ts +7 -7
  282. package/src/util/http-client.ts +2 -2
  283. package/lib/docker/docker-compose-cmd.d.ts +0 -5
  284. package/lib/docker/docker-compose-cmd.d.ts.map +0 -1
  285. package/lib/docker/docker-compose-cmd.js +0 -16
  286. package/lib/docker/docker-compose-cmd.js.map +0 -1
  287. package/lib/subcommands/device/device.d.ts +0 -7
  288. package/lib/subcommands/device/device.d.ts.map +0 -1
  289. package/lib/subcommands/device/device.js.map +0 -1
  290. package/lib/util/cloud-mode-ready.d.ts +0 -3
  291. package/lib/util/cloud-mode-ready.d.ts.map +0 -1
  292. package/lib/util/cloud-mode-ready.js.map +0 -1
  293. package/lib/util/download-file.d.ts +0 -6
  294. package/lib/util/download-file.d.ts.map +0 -1
  295. package/lib/util/download-file.js +0 -25
  296. package/lib/util/download-file.js.map +0 -1
  297. package/lib/util/fetch-with-timeout.d.ts +0 -4
  298. package/lib/util/fetch-with-timeout.d.ts.map +0 -1
  299. package/lib/util/fetch-with-timeout.js +0 -30
  300. package/lib/util/fetch-with-timeout.js.map +0 -1
  301. package/lib/util/parsing.d.ts +0 -2
  302. package/lib/util/parsing.d.ts.map +0 -1
  303. package/lib/util/parsing.js +0 -17
  304. package/lib/util/parsing.js.map +0 -1
  305. package/lib/util/safe-rimraf.d.ts +0 -2
  306. package/lib/util/safe-rimraf.d.ts.map +0 -1
  307. package/lib/util/safe-rimraf.js +0 -16
  308. package/lib/util/safe-rimraf.js.map +0 -1
  309. package/src/docker/docker-compose-cmd.ts +0 -15
  310. package/src/util/download-file.ts +0 -25
  311. package/src/util/fetch-with-timeout.ts +0 -35
  312. package/src/util/parsing.ts +0 -11
  313. package/src/util/safe-rimraf.ts +0 -14
@@ -4,7 +4,10 @@ import * as osu from 'node-os-utils';
4
4
  import * as si from 'systeminformation';
5
5
  import { exec } from 'child_process';
6
6
  import { promisify } from 'util';
7
+ import { JsSpawner, stringifyError } from 'alwaysai/lib/util';
7
8
  import { DeviceStatsPayload } from '@alwaysai/device-agent-schemas';
9
+ import { getDeviceAgentVersion } from '../util/check-for-updates';
10
+ import AaiError from '../util/aai-error';
8
11
 
9
12
  const exec_promise = promisify(exec);
10
13
 
@@ -12,63 +15,84 @@ const exec_promise = promisify(exec);
12
15
  export async function getCpuDetails(): Promise<
13
16
  DeviceStatsPayload['cpuDetails']
14
17
  > {
15
- const cpuFree = await osu.cpu.free();
16
- const cpuTemp = await si.cpuTemperature();
17
- const cpuDetails: DeviceStatsPayload['cpuDetails'] = {};
18
- if (cpuFree !== null) cpuDetails.usedPerc = 100 - cpuFree;
19
- if (cpuTemp?.main !== null) cpuDetails.temperature = cpuTemp.main;
20
- return cpuDetails;
18
+ let cpuFree, cpuTemp;
19
+ try {
20
+ [cpuFree, cpuTemp] = await Promise.all([
21
+ osu.cpu.free(),
22
+ si.cpuTemperature()
23
+ ]);
24
+ } catch (error) {
25
+ logger.error('Error fetching CPU details:', error);
26
+ return {};
27
+ }
28
+
29
+ return {
30
+ usedPerc: cpuFree !== null ? 100 - cpuFree : undefined,
31
+ temperature: cpuTemp?.main !== null ? cpuTemp.main : undefined
32
+ };
21
33
  }
22
34
 
23
35
  export async function getDiskDetails(): Promise<
24
36
  DeviceStatsPayload['diskDetails']
25
37
  > {
26
- // Types incorrectly specify diskname as required instead of optional
27
- // @ts-expect-error
28
- const driveInfo = await osu.drive.info();
29
- const diskDetails: DeviceStatsPayload['diskDetails'] = {};
30
- if (driveInfo?.usedGb !== null)
31
- diskDetails.usedGb = parseFloat(driveInfo.usedGb);
32
- if (driveInfo?.freeGb !== null) {
33
- diskDetails.freeGb = parseFloat(driveInfo.freeGb);
38
+ let driveInfo;
39
+ try {
40
+ // Types incorrectly specify diskname as required instead of optional
41
+ // @ts-expect-error
42
+ driveInfo = await osu.drive.info();
43
+ } catch (error) {
44
+ logger.error('Error fetching disk details:', error);
45
+ return {};
34
46
  }
35
- return diskDetails;
47
+
48
+ return {
49
+ usedGb:
50
+ driveInfo?.usedGb !== null ? parseFloat(driveInfo.usedGb) : undefined,
51
+ freeGb:
52
+ driveInfo?.freeGb !== null ? parseFloat(driveInfo.freeGb) : undefined
53
+ };
36
54
  }
37
55
 
38
56
  export async function getMemDetails(): Promise<
39
57
  DeviceStatsPayload['memDetails']
40
58
  > {
41
- const memInfo = await osu.mem.info();
42
- const memDetails: DeviceStatsPayload['memDetails'] = {};
43
- if (memInfo?.usedMemMb !== null) memDetails.usedMb = memInfo.usedMemMb;
44
- if (memInfo?.freeMemMb !== null) memDetails.freeMb = memInfo.freeMemMb;
45
- return memDetails;
59
+ let memInfo;
60
+ try {
61
+ memInfo = await osu.mem.info();
62
+ } catch (error) {
63
+ logger.error('Error fetching memory details:', error);
64
+ return {};
65
+ }
66
+ return {
67
+ usedMb: memInfo?.usedMemMb !== null ? memInfo.usedMemMb : undefined,
68
+ freeMb: memInfo?.freeMemMb !== null ? memInfo.freeMemMb : undefined
69
+ };
46
70
  }
47
71
 
48
- // System information
72
+ // System information casted to a string
49
73
  export async function getOsInfo() {
50
74
  const osInfo = await si.osInfo();
51
75
  return {
52
- platform: osInfo.platform,
53
- distro: osInfo.distro,
54
- release: osInfo.release,
55
- kernel: osInfo.kernel,
56
- architecture: osInfo.arch,
57
- hostname: osInfo.hostname
76
+ platform: String(osInfo.platform),
77
+ distro: String(osInfo.distro),
78
+ release: String(osInfo.release),
79
+ kernel: String(osInfo.kernel),
80
+ architecture: String(osInfo.arch),
81
+ hostname: String(osInfo.hostname)
58
82
  };
59
83
  }
60
84
 
61
85
  export async function getCpuInfo() {
62
86
  const cpuInfo = await si.cpu();
63
87
  return {
64
- manufacturer: cpuInfo.manufacturer,
65
- brand: cpuInfo.brand,
66
- vendor: cpuInfo.vendor,
67
- model: cpuInfo.model,
68
- cores: cpuInfo.cores,
69
- physicalCores: cpuInfo.physicalCores,
70
- efficiencyCores: cpuInfo.efficiencyCores,
71
- processors: cpuInfo.processors
88
+ manufacturer: String(cpuInfo.manufacturer),
89
+ brand: String(cpuInfo.brand),
90
+ vendor: String(cpuInfo.vendor),
91
+ model: String(cpuInfo.model),
92
+ cores: String(cpuInfo.cores),
93
+ physicalCores: String(cpuInfo.physicalCores),
94
+ efficiencyCores: String(cpuInfo.efficiencyCores),
95
+ processors: String(cpuInfo.processors)
72
96
  };
73
97
  }
74
98
 
@@ -76,11 +100,11 @@ export async function getDiskInfo() {
76
100
  const diskInfo = await si.diskLayout();
77
101
  return {
78
102
  drives: diskInfo.map((drive) => ({
79
- device: drive.device,
80
- type: drive.type,
81
- name: drive.name,
82
- vendor: drive.vendor,
83
- size: drive.size
103
+ device: String(drive.device),
104
+ type: String(drive.type),
105
+ name: String(drive.name),
106
+ vendor: String(drive.vendor),
107
+ size: String(drive.size)
84
108
  }))
85
109
  };
86
110
  }
@@ -88,14 +112,14 @@ export async function getDiskInfo() {
88
112
  export async function getDeviceInfo() {
89
113
  const deviceInfo = await si.system();
90
114
  return {
91
- manufacturer: deviceInfo.manufacturer,
92
- model: deviceInfo.model,
93
- version: deviceInfo.version,
115
+ manufacturer: String(deviceInfo.manufacturer),
116
+ model: String(deviceInfo.model),
117
+ version: String(deviceInfo.version),
94
118
  serial:
95
119
  deviceInfo.serial && deviceInfo.serial !== '-'
96
- ? deviceInfo.serial
120
+ ? String(deviceInfo.serial)
97
121
  : undefined,
98
- virtual: deviceInfo.virtual
122
+ virtual: deviceInfo.virtual // this should be a boolean
99
123
  };
100
124
  }
101
125
 
@@ -106,53 +130,137 @@ export async function getNetworkInfo() {
106
130
  ? networkInterfaces.filter((iface: any) => iface.ip4 !== '127.0.0.1')[0]
107
131
  : networkInterfaces;
108
132
  return {
109
- ipv4Address: defaultNetworkInterface.ip4,
110
- ipv6Address: defaultNetworkInterface.ip6,
111
- macAddress: defaultNetworkInterface.mac
133
+ ipv4Address: String(defaultNetworkInterface.ip4),
134
+ ipv6Address: String(defaultNetworkInterface.ip6),
135
+ macAddress: String(defaultNetworkInterface.mac)
112
136
  };
113
137
  }
114
138
 
139
+ export async function getDockerVersion() {
140
+ try {
141
+ const spawner = JsSpawner();
142
+ const result = JSON.parse(
143
+ await spawner.run({
144
+ exe: 'docker',
145
+ args: ['info', '--format', 'json']
146
+ })
147
+ );
148
+ return String(result.ClientInfo.Version);
149
+ } catch (e) {
150
+ logger.warn(`Cannot get Docker version!\n${stringifyError(e)}`);
151
+ return 'Not found';
152
+ }
153
+ }
154
+
155
+ export async function getDockerComposeVersion() {
156
+ try {
157
+ const spawner = JsSpawner();
158
+ return await spawner.run({
159
+ exe: 'docker',
160
+ args: ['compose', 'version']
161
+ });
162
+ } catch (e) {
163
+ logger.warn(`Cannot get Docker Compose version!\n${stringifyError(e)}`);
164
+ return 'Not found';
165
+ }
166
+ }
167
+
168
+ export async function getNpmVersion() {
169
+ try {
170
+ const spawner = JsSpawner();
171
+ return await spawner.run({
172
+ exe: 'npm',
173
+ args: ['--version']
174
+ });
175
+ } catch (e) {
176
+ logger.warn(`Cannot get npm version!\n${stringifyError(e)}`);
177
+ return 'Not found';
178
+ }
179
+ }
180
+
181
+ export async function getNodeVersion() {
182
+ try {
183
+ const spawner = JsSpawner();
184
+ return await spawner.run({
185
+ exe: 'node',
186
+ args: ['-v']
187
+ });
188
+ } catch (e) {
189
+ logger.warn(`Cannot get Node version!\n${stringifyError(e)}`);
190
+ return 'Not found';
191
+ }
192
+ }
193
+
115
194
  export async function getPackageVersions() {
116
- // eslint-disable-next-line
117
- const agentJson = require('../../package.json');
195
+ const agentVersion = await getDeviceAgentVersion();
118
196
  // eslint-disable-next-line
119
197
  const deviceAgentSchemasJson = require('../../node_modules/@alwaysai/device-agent-schemas/package.json');
198
+
199
+ const [dockerVersion, dockerComposeVersion, nodeVersion, npmVersion] =
200
+ await Promise.all([
201
+ getDockerVersion(),
202
+ getDockerComposeVersion(),
203
+ getNodeVersion(),
204
+ getNpmVersion()
205
+ ]);
206
+
120
207
  return {
121
- agent: agentJson.version,
122
- deviceAgentSchemas: deviceAgentSchemasJson.version
208
+ agent: agentVersion,
209
+ deviceAgentSchemas: deviceAgentSchemasJson.version,
210
+ docker: dockerVersion,
211
+ dockerCompose: dockerComposeVersion,
212
+ node: nodeVersion,
213
+ npm: npmVersion
123
214
  };
124
215
  }
125
216
 
126
217
  export async function getLastBootTime() {
127
218
  try {
128
- const test = await exec_promise(
129
- "last -x reboot | grep reboot | head -n 1 | awk '{ print $5, $6, $7, $8 }'"
130
- );
131
- if (test.stderr) {
132
- logger.error(`Stderr when getting last boot time: ${test.stderr}`);
219
+ const out = await exec_promise('journalctl --list-boots');
220
+ if (!out || out.stderr) {
221
+ logger.error(`Stderr when getting last boot time: ${out.stderr}`);
133
222
  return undefined;
134
223
  }
135
- return new Date(test.stdout).toString();
224
+
225
+ const bootTimes = out.stdout.split('\n');
226
+ const latestBootStdout = (bootTimes.pop() || bootTimes.pop())?.trim(); // possible last \n causes '' at end of array
227
+ if (!latestBootStdout) return undefined;
228
+
229
+ const tokens = latestBootStdout.trim().split(' ');
230
+
231
+ return String(new Date(`${tokens[2]} ${tokens[3]} ${tokens[4]}`));
136
232
  } catch (e) {
137
- logger.error(`Issue getting last boot time: ${e.message}`);
233
+ logger.error(`Issue getting last boot time!\n${stringifyError(e)}`);
138
234
  return undefined;
139
235
  }
140
236
  }
141
237
 
142
238
  export async function getSystemInformation(): Promise<SystemInformationShadowUpdate> {
143
239
  try {
240
+ const [os, cpu, disk, device, network, versions, lastBootTime] =
241
+ await Promise.all([
242
+ getOsInfo(),
243
+ getCpuInfo(),
244
+ getDiskInfo(),
245
+ getDeviceInfo(),
246
+ getNetworkInfo(),
247
+ getPackageVersions(),
248
+ getLastBootTime()
249
+ ]);
144
250
  const systemInfo: SystemInformationShadowUpdate = {
145
- os: await getOsInfo(),
146
- cpu: await getCpuInfo(),
147
- disk: await getDiskInfo(),
148
- device: await getDeviceInfo(),
149
- network: await getNetworkInfo(),
150
- versions: await getPackageVersions(),
151
- lastBootTime: await getLastBootTime()
251
+ os,
252
+ cpu,
253
+ disk,
254
+ device,
255
+ network,
256
+ versions,
257
+ lastBootTime
152
258
  };
153
259
  return systemInfo;
154
260
  } catch (e) {
155
- logger.error('There was a problem getting system information: ', e);
261
+ logger.error(
262
+ `There was a problem getting system information!\n${stringifyError(e)}`
263
+ );
156
264
  }
157
265
  return {};
158
266
  }
@@ -167,11 +275,10 @@ export async function reboot() {
167
275
  timeout: 5000
168
276
  });
169
277
  logger.info(result.stdout.trim());
170
- } catch (err) {
171
- throw new Error(
172
- `Could not reboot device. You may need to add passwordless access to '/sbin/shutdown'. ${JSON.stringify(
173
- err
174
- )}`
278
+ } catch (e) {
279
+ throw new AaiError(
280
+ "Could not reboot device. You may need to add passwordless access to '/sbin/shutdown'.",
281
+ { cause: e }
175
282
  );
176
283
  }
177
284
  }
@@ -0,0 +1,61 @@
1
+ import * as DockerComposeV1 from 'docker-compose';
2
+ import { v2 as DockerComposeV2 } from 'docker-compose';
3
+ import { execSync } from 'child_process';
4
+ import { logger } from '../util/logger';
5
+ import { JsSpawner, stringifyError } from 'alwaysai/lib/util';
6
+
7
+ let dockerCmd = 'docker';
8
+
9
+ export function importDockerCompose():
10
+ | typeof DockerComposeV1
11
+ | typeof DockerComposeV2 {
12
+ try {
13
+ execSync('docker compose version').toString();
14
+ logger.debug('Using Docker Compose V2.');
15
+ return DockerComposeV2;
16
+ } catch (e) {
17
+ // TODO: Log this error as well
18
+ try {
19
+ execSync('docker-compose -v').toString();
20
+ logger.warn('Using docker-compose V1. Please consider updating to V2.');
21
+ } catch (e) {
22
+ logger.warn(`Could not determine compose!\n${stringifyError(e)}`);
23
+ }
24
+ }
25
+ dockerCmd = 'docker-compose';
26
+ return DockerComposeV1;
27
+ }
28
+
29
+ export const compose = importDockerCompose();
30
+
31
+ export async function runDockerComposeCmd(props: {
32
+ args: string[];
33
+ dir: string;
34
+ }) {
35
+ const { args, dir } = props;
36
+ const spawner = JsSpawner();
37
+ if (dockerCmd === 'docker') {
38
+ args.unshift('compose');
39
+ }
40
+ const output = await spawner.run({
41
+ exe: dockerCmd,
42
+ args,
43
+ cwd: dir
44
+ });
45
+ return output;
46
+ }
47
+
48
+ export async function runStreamingDockerComposeCmd(props: {
49
+ args: string[];
50
+ dir: string;
51
+ }) {
52
+ const { args, dir } = props;
53
+ if (dockerCmd === 'docker') {
54
+ args.unshift('compose');
55
+ }
56
+ return await JsSpawner().runStreaming({
57
+ exe: dockerCmd,
58
+ args,
59
+ cwd: dir
60
+ });
61
+ }
package/src/index.ts CHANGED
@@ -10,13 +10,9 @@ import { root } from './root';
10
10
  import { runDeviceAgentCloudInterface } from './cloud-connection/device-agent-cloud-connection';
11
11
  import { AgentConfigFile } from './infrastructure/agent-config';
12
12
  import { ALWAYSAI_DEVICE_AGENT_MODE } from './environment';
13
- import { logger } from './util/logger';
14
-
15
- // eslint-disable-next-line @typescript-eslint/no-var-requires
16
- const { version } = require('../package.json');
13
+ import { checkForUpdatesAndPrompt } from './util/check-for-updates';
17
14
 
18
15
  if (module === require.main) {
19
- logger.info(`Starting alwaysAI Device Agent v${version}`);
20
16
  if (!AgentConfigFile().exists()) {
21
17
  AgentConfigFile().initialize();
22
18
  }
@@ -24,6 +20,6 @@ if (module === require.main) {
24
20
  if (ALWAYSAI_DEVICE_AGENT_MODE === 'cloud') {
25
21
  void runDeviceAgentCloudInterface();
26
22
  } else {
27
- void runCliAndExit(root, {});
23
+ void runCliAndExit(root, { postRun: checkForUpdatesAndPrompt });
28
24
  }
29
25
  }
@@ -1,7 +1,11 @@
1
+ import { getDeviceConfigPath } from 'alwaysai/lib/infrastructure';
2
+ import { join } from 'path';
1
3
  import * as tempy from 'tempy';
2
- import { AgentConfigFile } from './agent-config';
4
+ import { AGENT_CONFIG_FILE_NAME, AgentConfigFile } from './agent-config';
3
5
 
4
- const configFile = AgentConfigFile(tempy.directory());
6
+ const configFile = AgentConfigFile(
7
+ join(tempy.directory(), getDeviceConfigPath(), AGENT_CONFIG_FILE_NAME)
8
+ );
5
9
 
6
10
  describe('Test Agent Config', () => {
7
11
  beforeEach(() => {
@@ -95,6 +99,9 @@ describe('Test Agent Config', () => {
95
99
  expect(await configFile.getAppVersion({ projectId })).toEqual(version);
96
100
  await configFile.setAppInstalled({ projectId, version });
97
101
  expect(await configFile.getAppVersion({ projectId })).toEqual(version);
102
+ expect(await configFile.isAppReady({ projectId })).toEqual(true);
103
+ await configFile.setAppUninstalling({ projectId });
104
+ expect(await configFile.isAppReady({ projectId })).toEqual(false);
98
105
  await configFile.setAppUninstalled({ projectId });
99
106
  const apps = await configFile.getApps();
100
107
  expect(apps).toEqual([]);
@@ -3,7 +3,8 @@ import {
3
3
  ConfigFileSchemaReturnType
4
4
  } from '@alwaysai/config-nodejs';
5
5
  import Ajv, { JSONSchemaType } from 'ajv';
6
- import { homedir } from 'os';
6
+ import { getDeviceConfigPath } from 'alwaysai/lib/infrastructure';
7
+ import { LOCAL_AAI_CFG_DIR } from 'alwaysai/lib/paths';
7
8
  import { join } from 'path';
8
9
 
9
10
  export interface AppBackupConfig {
@@ -54,65 +55,29 @@ const schema: JSONSchemaType<AgentConfig> = {
54
55
  const ajv = new Ajv();
55
56
  const validateFunction = ajv.compile(schema);
56
57
 
57
- const ALWAYSAI_CONFIG_DIR = join(homedir(), '.config', 'alwaysai');
58
-
59
- const AGENT_CONFIG_FILE_NAME = 'alwaysai.agent.json';
60
-
61
- export interface AgentJsonFileReturnType
62
- extends ConfigFileSchemaReturnType<AgentConfig> {
63
- name: string;
64
- getApps: () => Promise<InstalledAppConfig[]>;
65
- getReadyApps;
66
- getApp;
67
- isAppPresent;
68
- isAppReady;
69
- removeApp;
70
- setAppInstalling;
71
- setAppInstalled;
72
- setAppUninstalled;
73
- getAppVersion: (props: { projectId: string }) => Promise<string>;
74
- setAppBackup;
75
- getAppBackup;
76
- }
58
+ export const AGENT_CONFIG_FILE_NAME = 'alwaysai.agent.json';
77
59
 
78
- export function AgentConfigFile(
79
- dir = ALWAYSAI_CONFIG_DIR
80
- ): AgentJsonFileReturnType {
81
- const path = join(dir, AGENT_CONFIG_FILE_NAME);
60
+ export function AgentConfigFile(filePath?: string) {
61
+ const path =
62
+ filePath ??
63
+ join(LOCAL_AAI_CFG_DIR, getDeviceConfigPath(), AGENT_CONFIG_FILE_NAME);
82
64
  const initialValue: AgentConfig = {
83
65
  applications: []
84
66
  };
85
- const configFile = ConfigFileSchema({
67
+ const configFile = ConfigFileSchema<AgentConfig>({
86
68
  path,
87
69
  validateFunction,
88
70
  initialValue
89
71
  });
90
72
 
91
- return {
92
- ...configFile,
93
- name: AGENT_CONFIG_FILE_NAME,
94
- getApps,
95
- getReadyApps,
96
- getApp,
97
- isAppPresent,
98
- isAppReady,
99
- removeApp,
100
- setAppInstalling,
101
- setAppInstalled,
102
- setAppUninstalled,
103
- getAppVersion,
104
- setAppBackup,
105
- getAppBackup
106
- };
107
-
108
73
  async function getApps() {
109
74
  const config = configFile.read();
110
- return config && config.applications ? config.applications : [];
75
+ return config?.applications ? config.applications : [];
111
76
  }
112
77
 
113
78
  async function getReadyApps() {
114
79
  const config = configFile.read();
115
- return config && config.applications
80
+ return config?.applications
116
81
  ? config.applications.filter((app) => {
117
82
  return app.ready;
118
83
  })
@@ -205,6 +170,23 @@ export function AgentConfigFile(
205
170
  }
206
171
  }
207
172
 
173
+ async function setAppUninstalling(props: { projectId: string }) {
174
+ const { projectId } = props;
175
+ const app = await getApp({ projectId });
176
+ if (app) {
177
+ await removeApp({ projectId });
178
+ const config = configFile.read();
179
+ config.applications.push({ ...app, ...{ ready: false } });
180
+ configFile.write(config);
181
+ } else {
182
+ // NOTE: we should never be setting an app as installed
183
+ // if it doesn't exist (setAppInstalling was never called)
184
+ throw new Error(
185
+ `App ${projectId} was not previously configured and could not be set to installed!`
186
+ );
187
+ }
188
+ }
189
+
208
190
  async function setAppUninstalled(props: { projectId: string }) {
209
191
  const { projectId } = props;
210
192
  await removeApp({ projectId });
@@ -235,9 +217,26 @@ export function AgentConfigFile(
235
217
  async function getAppBackup(props: { projectId: string }) {
236
218
  const { projectId } = props;
237
219
  const app = await getApp({ projectId });
238
- if (app && app.backup) {
220
+ if (app?.backup) {
239
221
  return app.backup;
240
222
  }
241
223
  return null;
242
224
  }
225
+
226
+ return {
227
+ ...configFile,
228
+ name: AGENT_CONFIG_FILE_NAME,
229
+ getApps,
230
+ getReadyApps,
231
+ getApp,
232
+ isAppPresent,
233
+ isAppReady,
234
+ setAppInstalling,
235
+ setAppInstalled,
236
+ setAppUninstalling,
237
+ setAppUninstalled,
238
+ getAppVersion,
239
+ setAppBackup,
240
+ getAppBackup
241
+ };
243
242
  }