@alwaysai/device-agent 0.0.4 → 0.0.5

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 (191) hide show
  1. package/lib/application-control/backup.d.ts.map +1 -1
  2. package/lib/application-control/backup.js +10 -6
  3. package/lib/application-control/backup.js.map +1 -1
  4. package/lib/application-control/environment-variables.d.ts +9 -0
  5. package/lib/application-control/environment-variables.d.ts.map +1 -0
  6. package/lib/application-control/environment-variables.js +82 -0
  7. package/lib/application-control/environment-variables.js.map +1 -0
  8. package/lib/application-control/index.d.ts +9 -0
  9. package/lib/application-control/index.d.ts.map +1 -0
  10. package/lib/application-control/index.js +27 -0
  11. package/lib/application-control/index.js.map +1 -0
  12. package/lib/application-control/install.d.ts +8 -2
  13. package/lib/application-control/install.d.ts.map +1 -1
  14. package/lib/application-control/install.js +72 -42
  15. package/lib/application-control/install.js.map +1 -1
  16. package/lib/application-control/models.d.ts.map +1 -1
  17. package/lib/application-control/models.js +7 -17
  18. package/lib/application-control/models.js.map +1 -1
  19. package/lib/application-control/status.d.ts +3 -3
  20. package/lib/application-control/status.d.ts.map +1 -1
  21. package/lib/application-control/status.js +19 -20
  22. package/lib/application-control/status.js.map +1 -1
  23. package/lib/application-control/types.d.ts +0 -13
  24. package/lib/application-control/types.d.ts.map +1 -1
  25. package/lib/application-control/utils.d.ts +2 -9
  26. package/lib/application-control/utils.d.ts.map +1 -1
  27. package/lib/application-control/utils.js +13 -28
  28. package/lib/application-control/utils.js.map +1 -1
  29. package/lib/cloud-connection/device-agent-cloud-connection.d.ts +15 -2
  30. package/lib/cloud-connection/device-agent-cloud-connection.d.ts.map +1 -1
  31. package/lib/cloud-connection/device-agent-cloud-connection.js +200 -27
  32. package/lib/cloud-connection/device-agent-cloud-connection.js.map +1 -1
  33. package/lib/docker/docker-cmd.js +2 -2
  34. package/lib/docker/docker-cmd.js.map +1 -1
  35. package/lib/docker/docker-compose-cmd.js +2 -2
  36. package/lib/docker/docker-compose-cmd.js.map +1 -1
  37. package/lib/environment.d.ts +2 -0
  38. package/lib/environment.d.ts.map +1 -1
  39. package/lib/environment.js +3 -1
  40. package/lib/environment.js.map +1 -1
  41. package/lib/index.js +10 -8
  42. package/lib/index.js.map +1 -1
  43. package/lib/infrastructure/agent-config.d.ts +73 -0
  44. package/lib/infrastructure/agent-config.d.ts.map +1 -0
  45. package/lib/infrastructure/agent-config.js +186 -0
  46. package/lib/infrastructure/agent-config.js.map +1 -0
  47. package/lib/infrastructure/agent-config.test.d.ts +2 -0
  48. package/lib/infrastructure/agent-config.test.d.ts.map +1 -0
  49. package/lib/infrastructure/agent-config.test.js +135 -0
  50. package/lib/infrastructure/agent-config.test.js.map +1 -0
  51. package/lib/infrastructure/certificates-and-tokens.d.ts +6 -0
  52. package/lib/infrastructure/certificates-and-tokens.d.ts.map +1 -0
  53. package/lib/infrastructure/certificates-and-tokens.js +69 -0
  54. package/lib/infrastructure/certificates-and-tokens.js.map +1 -0
  55. package/lib/{util → infrastructure}/urls.d.ts +0 -0
  56. package/lib/infrastructure/urls.d.ts.map +1 -0
  57. package/lib/{util → infrastructure}/urls.js +3 -3
  58. package/lib/infrastructure/urls.js.map +1 -0
  59. package/lib/root.js +3 -3
  60. package/lib/root.js.map +1 -1
  61. package/lib/subcommands/app/app.d.ts +8 -1
  62. package/lib/subcommands/app/app.d.ts.map +1 -1
  63. package/lib/subcommands/app/app.js +58 -24
  64. package/lib/subcommands/app/app.js.map +1 -1
  65. package/lib/subcommands/app/index.d.ts.map +1 -1
  66. package/lib/subcommands/app/index.js +2 -0
  67. package/lib/subcommands/app/index.js.map +1 -1
  68. package/lib/subcommands/device/device.d.ts +6 -0
  69. package/lib/subcommands/device/device.d.ts.map +1 -0
  70. package/lib/subcommands/device/device.js +62 -0
  71. package/lib/subcommands/device/device.js.map +1 -0
  72. package/lib/subcommands/device/index.d.ts +2 -0
  73. package/lib/subcommands/device/index.d.ts.map +1 -0
  74. package/lib/subcommands/device/index.js +11 -0
  75. package/lib/subcommands/device/index.js.map +1 -0
  76. package/lib/subcommands/get-model-package.d.ts +5 -0
  77. package/lib/subcommands/get-model-package.d.ts.map +1 -0
  78. package/lib/subcommands/get-model-package.js +51 -0
  79. package/lib/subcommands/get-model-package.js.map +1 -0
  80. package/lib/subcommands/index.d.ts +8 -1
  81. package/lib/subcommands/index.d.ts.map +1 -1
  82. package/lib/subcommands/index.js +9 -3
  83. package/lib/subcommands/index.js.map +1 -1
  84. package/lib/subcommands/login.d.ts +3 -2
  85. package/lib/subcommands/login.d.ts.map +1 -1
  86. package/lib/subcommands/login.js +11 -4
  87. package/lib/subcommands/login.js.map +1 -1
  88. package/lib/util/copy-dir.js +3 -3
  89. package/lib/util/copy-dir.js.map +1 -1
  90. package/lib/util/directories.js +5 -5
  91. package/lib/util/directories.js.map +1 -1
  92. package/package.json +19 -14
  93. package/readme.md +176 -79
  94. package/src/application-control/backup.ts +10 -6
  95. package/src/application-control/environment-variables.ts +81 -0
  96. package/src/application-control/index.ts +40 -0
  97. package/src/application-control/install.ts +79 -55
  98. package/src/application-control/models.ts +12 -17
  99. package/src/application-control/status.ts +26 -24
  100. package/src/application-control/types.ts +0 -4
  101. package/src/application-control/utils.ts +10 -25
  102. package/src/cloud-connection/device-agent-cloud-connection.ts +243 -40
  103. package/src/docker/docker-cmd.ts +1 -1
  104. package/src/docker/docker-compose-cmd.ts +1 -1
  105. package/src/environment.ts +2 -0
  106. package/src/index.ts +10 -7
  107. package/src/infrastructure/agent-config.test.ts +143 -0
  108. package/src/infrastructure/agent-config.ts +217 -0
  109. package/src/infrastructure/certificates-and-tokens.ts +71 -0
  110. package/src/{util → infrastructure}/urls.ts +1 -1
  111. package/src/root.ts +3 -3
  112. package/src/subcommands/app/app.ts +57 -19
  113. package/src/subcommands/app/index.ts +4 -0
  114. package/src/subcommands/device/device.ts +63 -0
  115. package/src/subcommands/device/index.ts +8 -0
  116. package/src/subcommands/get-model-package.ts +60 -0
  117. package/src/subcommands/index.ts +9 -3
  118. package/src/subcommands/login.ts +11 -4
  119. package/src/util/copy-dir.ts +1 -1
  120. package/src/util/directories.ts +8 -8
  121. package/lib/constants.d.ts +0 -13
  122. package/lib/constants.d.ts.map +0 -1
  123. package/lib/constants.js +0 -18
  124. package/lib/constants.js.map +0 -1
  125. package/lib/subcommands/device-control.d.ts +0 -2
  126. package/lib/subcommands/device-control.d.ts.map +0 -1
  127. package/lib/subcommands/device-control.js +0 -19
  128. package/lib/subcommands/device-control.js.map +0 -1
  129. package/lib/util/spawner/gnu-spawner.d.ts +0 -9
  130. package/lib/util/spawner/gnu-spawner.d.ts.map +0 -1
  131. package/lib/util/spawner/gnu-spawner.js +0 -102
  132. package/lib/util/spawner/gnu-spawner.js.map +0 -1
  133. package/lib/util/spawner/js-spawner.d.ts +0 -5
  134. package/lib/util/spawner/js-spawner.d.ts.map +0 -1
  135. package/lib/util/spawner/js-spawner.js +0 -89
  136. package/lib/util/spawner/js-spawner.js.map +0 -1
  137. package/lib/util/spawner/types.d.ts +0 -28
  138. package/lib/util/spawner/types.d.ts.map +0 -1
  139. package/lib/util/spawner/types.js +0 -3
  140. package/lib/util/spawner/types.js.map +0 -1
  141. package/lib/util/spawner-base/index.d.ts +0 -17
  142. package/lib/util/spawner-base/index.d.ts.map +0 -1
  143. package/lib/util/spawner-base/index.js +0 -30
  144. package/lib/util/spawner-base/index.js.map +0 -1
  145. package/lib/util/spawner-base/run-foreground-sync.d.ts +0 -3
  146. package/lib/util/spawner-base/run-foreground-sync.d.ts.map +0 -1
  147. package/lib/util/spawner-base/run-foreground-sync.js +0 -18
  148. package/lib/util/spawner-base/run-foreground-sync.js.map +0 -1
  149. package/lib/util/spawner-base/run-foreground.d.ts +0 -3
  150. package/lib/util/spawner-base/run-foreground.d.ts.map +0 -1
  151. package/lib/util/spawner-base/run-foreground.js +0 -49
  152. package/lib/util/spawner-base/run-foreground.js.map +0 -1
  153. package/lib/util/spawner-base/run-streaming.d.ts +0 -4
  154. package/lib/util/spawner-base/run-streaming.d.ts.map +0 -1
  155. package/lib/util/spawner-base/run-streaming.js +0 -35
  156. package/lib/util/spawner-base/run-streaming.js.map +0 -1
  157. package/lib/util/spawner-base/run.d.ts +0 -4
  158. package/lib/util/spawner-base/run.d.ts.map +0 -1
  159. package/lib/util/spawner-base/run.js +0 -56
  160. package/lib/util/spawner-base/run.js.map +0 -1
  161. package/lib/util/urls.d.ts.map +0 -1
  162. package/lib/util/urls.js.map +0 -1
  163. package/lib/web/index.html +0 -229
  164. package/lib/web/static/Karla.css +0 -18
  165. package/lib/web/static/bootstrap-4.3.1.min.css +0 -7
  166. package/lib/web/static/bootstrap-4.3.1.min.js +0 -7
  167. package/lib/web/static/favicon.ico +0 -0
  168. package/lib/web/static/jquery-3.3.1.slim.min.js +0 -2
  169. package/lib/web/static/popper-1.14.7.min.js +0 -5
  170. package/lib/web/web-interface.d.ts +0 -2
  171. package/lib/web/web-interface.d.ts.map +0 -1
  172. package/lib/web/web-interface.js +0 -75
  173. package/lib/web/web-interface.js.map +0 -1
  174. package/src/constants.ts +0 -22
  175. package/src/subcommands/device-control.ts +0 -16
  176. package/src/util/spawner/gnu-spawner.ts +0 -114
  177. package/src/util/spawner/js-spawner.ts +0 -110
  178. package/src/util/spawner/types.ts +0 -28
  179. package/src/util/spawner-base/index.ts +0 -28
  180. package/src/util/spawner-base/run-foreground-sync.ts +0 -16
  181. package/src/util/spawner-base/run-foreground.ts +0 -49
  182. package/src/util/spawner-base/run-streaming.ts +0 -40
  183. package/src/util/spawner-base/run.ts +0 -60
  184. package/src/web/index.html +0 -229
  185. package/src/web/static/Karla.css +0 -18
  186. package/src/web/static/bootstrap-4.3.1.min.css +0 -7
  187. package/src/web/static/bootstrap-4.3.1.min.js +0 -7
  188. package/src/web/static/favicon.ico +0 -0
  189. package/src/web/static/jquery-3.3.1.slim.min.js +0 -2
  190. package/src/web/static/popper-1.14.7.min.js +0 -5
  191. package/src/web/web-interface.ts +0 -85
@@ -0,0 +1,217 @@
1
+ import { ConfigFileSchema } from '@alwaysai/config-nodejs';
2
+ import { JSONSchemaType } from 'ajv';
3
+ import { homedir } from 'os';
4
+ import { join } from 'path';
5
+ import { ALWAYSAI_DEVICE_AGENT_MODE } from '../environment';
6
+
7
+ export interface AppBackupConfig {
8
+ version: string;
9
+ }
10
+
11
+ export interface InstalledAppConfig {
12
+ projectId: string;
13
+ version: string;
14
+ ready: boolean;
15
+ backup?: AppBackupConfig;
16
+ }
17
+
18
+ export interface AgentConfig {
19
+ applications: InstalledAppConfig[];
20
+ }
21
+
22
+ const schema: JSONSchemaType<AgentConfig> = {
23
+ type: 'object',
24
+ properties: {
25
+ applications: {
26
+ type: 'array',
27
+ items: {
28
+ type: 'object',
29
+ properties: {
30
+ projectId: { type: 'string' },
31
+ version: { type: 'string' },
32
+ ready: { type: 'boolean' },
33
+ backup: {
34
+ type: 'object',
35
+ nullable: true,
36
+ properties: {
37
+ version: { type: 'string' },
38
+ },
39
+ required: ['version'],
40
+ additionalProperties: true,
41
+ },
42
+ },
43
+ required: ['projectId', 'version', 'ready'],
44
+ additionalProperties: true,
45
+ },
46
+ },
47
+ },
48
+ required: ['applications'],
49
+ additionalProperties: true,
50
+ };
51
+
52
+ const ALWAYSAI_CONFIG_DIR = join(homedir(), '.config', 'alwaysai');
53
+
54
+ const AGENT_CONFIG_FILE_NAME = 'alwaysai.agent.json';
55
+
56
+ export function AgentConfigFile(dir = ALWAYSAI_CONFIG_DIR) {
57
+ const path = join(dir, AGENT_CONFIG_FILE_NAME);
58
+ const initialValue: AgentConfig = {
59
+ applications: [],
60
+ };
61
+ const configFile = ConfigFileSchema({
62
+ path,
63
+ schema,
64
+ initialValue,
65
+ });
66
+
67
+ return {
68
+ ...configFile,
69
+ name: AGENT_CONFIG_FILE_NAME,
70
+ getApps,
71
+ getReadyApps,
72
+ getApp,
73
+ isAppPresent,
74
+ isAppReady,
75
+ removeApp,
76
+ setAppInstalling,
77
+ setAppInstalled,
78
+ setAppUninstalled,
79
+ getAppVersion,
80
+ setAppBackup,
81
+ getAppBackup,
82
+ };
83
+
84
+ async function getApps() {
85
+ const config = configFile.read();
86
+ return config.applications;
87
+ }
88
+
89
+ async function getReadyApps() {
90
+ const config = configFile.read();
91
+ return config.applications.filter((app) => {
92
+ return app.ready;
93
+ });
94
+ }
95
+
96
+ async function getApp(props: { projectId: string }) {
97
+ const { projectId } = props;
98
+ const apps = await getApps();
99
+ for (const app of apps) {
100
+ if (app.projectId === projectId) {
101
+ return app;
102
+ }
103
+ }
104
+ return null;
105
+ }
106
+
107
+ async function isAppPresent(props: { projectId: string }): Promise<boolean> {
108
+ const { projectId } = props;
109
+ const app = await getApp({ projectId });
110
+ if (app) {
111
+ return true;
112
+ }
113
+ return false;
114
+ }
115
+
116
+ async function isAppReady(props: { projectId: string }): Promise<boolean> {
117
+ const { projectId } = props;
118
+ const app = await getApp({ projectId });
119
+ if (app && app.ready) {
120
+ return true;
121
+ }
122
+ return false;
123
+ }
124
+
125
+ async function removeApp(props: { projectId: string }) {
126
+ const { projectId } = props;
127
+ const config = configFile.read();
128
+ const newList = config.applications.filter((app) => {
129
+ return app.projectId !== projectId;
130
+ });
131
+ config.applications = newList;
132
+ configFile.write(config);
133
+ }
134
+
135
+ async function setAppInstalling(props: { projectId: string; version: string }) {
136
+ const { projectId, version } = props;
137
+ const app = await getApp({ projectId });
138
+ if (app) {
139
+ await removeApp({ projectId });
140
+ const config = configFile.read();
141
+ config.applications.push({
142
+ projectId,
143
+ version,
144
+ ready: false,
145
+ });
146
+ configFile.write(config);
147
+ } else {
148
+ const config = configFile.read();
149
+ config.applications.push({
150
+ projectId,
151
+ version,
152
+ ready: false,
153
+ });
154
+ configFile.write(config);
155
+ }
156
+ }
157
+
158
+ async function setAppInstalled(props: { projectId: string; version: string }) {
159
+ const { projectId, version } = props;
160
+ const app = await getApp({ projectId });
161
+ if (app) {
162
+ await removeApp({ projectId });
163
+ const config = configFile.read();
164
+ app.version = version;
165
+ config.applications.push({
166
+ projectId,
167
+ version,
168
+ ready: true,
169
+ });
170
+ configFile.write(config);
171
+ } else {
172
+ const config = configFile.read();
173
+ config.applications.push({
174
+ projectId,
175
+ version,
176
+ ready: true,
177
+ });
178
+ configFile.write(config);
179
+ }
180
+ }
181
+
182
+ async function setAppUninstalled(props: { projectId: string }) {
183
+ const { projectId } = props;
184
+ await removeApp({ projectId });
185
+ }
186
+
187
+ async function getAppVersion(props: { projectId: string }) {
188
+ const { projectId } = props;
189
+ const app = await getApp({ projectId });
190
+ if (!app) {
191
+ throw new Error(`App ${projectId} not installed`);
192
+ }
193
+ return app.version;
194
+ }
195
+
196
+ async function setAppBackup(props: { projectId: string }) {
197
+ const { projectId } = props;
198
+ const app = await getApp({ projectId });
199
+ if (!app) {
200
+ throw new Error(`Project ${projectId} not installed!`);
201
+ }
202
+ await removeApp({ projectId });
203
+ const config = configFile.read();
204
+ app.backup = { version: app.version };
205
+ config.applications.push(app);
206
+ configFile.write(config);
207
+ }
208
+
209
+ async function getAppBackup(props: { projectId: string }) {
210
+ const { projectId } = props;
211
+ const app = await getApp({ projectId });
212
+ if (app && app.backup) {
213
+ return app.backup;
214
+ }
215
+ return null;
216
+ }
217
+ }
@@ -0,0 +1,71 @@
1
+ import { DeviceTokens, writeOrUpdateDeviceCfgFile } from 'alwaysai/lib/components/device';
2
+ import { checkUserIsLoggedInComponent } from 'alwaysai/lib/components/user';
3
+ import { LOCAL_AAI_CFG_DIR, LOCAL_CERT_AND_KEY_DIR } from 'alwaysai/lib/constants';
4
+ import { checkPaidPlan } from 'alwaysai/lib/core/project';
5
+ import {
6
+ CliRpcClient,
7
+ getDeviceCertificates,
8
+ IotRpcDevice,
9
+ refreshDevice,
10
+ } from 'alwaysai/lib/infrastructure';
11
+ import { JsSpawner, Spawner, writeCertificate, writeTokens } from 'alwaysai/lib/util';
12
+
13
+ // NOTE: This is reimplemented from the CLI to work for local checks
14
+ export async function getTargetHardwareUuid(spawner: Spawner) {
15
+ if (await spawner.exists('/var/lib/dbus/machine-id')) {
16
+ return await spawner.run({ exe: 'cat', args: ['/var/lib/dbus/machine-id'] });
17
+ }
18
+ if (await spawner.exists('/etc/machine-id')) {
19
+ return await spawner.run({ exe: 'cat', args: ['/etc/machine-id'] });
20
+ }
21
+ return await spawner.run({ exe: 'hostname' });
22
+ }
23
+
24
+ // NOTE: This closely follows the flow of deviceCheckAndUpdateComponent in the CLI
25
+ export async function writeCertificateAndToken(props: { deviceUuid: string }) {
26
+ const { deviceUuid } = props;
27
+ await checkUserIsLoggedInComponent({ yes: true });
28
+ if (!(await checkPaidPlan())) {
29
+ throw new Error(`This action only supported for Enterprise alwaysAI accounts!`);
30
+ }
31
+ const device: IotRpcDevice = (await CliRpcClient().getDeviceByUUID({
32
+ uuid: deviceUuid,
33
+ })) as IotRpcDevice;
34
+ if (!device) {
35
+ throw new Error(`Device not found for deviceId=${deviceUuid}`);
36
+ }
37
+ // TODO: Update HW ID if not there
38
+ if (device.hardware_ids && device.hardware_ids !== '') {
39
+ const spawner = JsSpawner();
40
+ const hardwareId = await getTargetHardwareUuid(spawner);
41
+ if (hardwareId !== device.hardware_ids) {
42
+ throw new Error('Certificates not intended for this device!');
43
+ }
44
+ }
45
+ const response = await refreshDevice(device.uuid);
46
+ const tokens: DeviceTokens = {
47
+ deviceId: deviceUuid,
48
+ accessToken: response.accessToken,
49
+ refreshToken: response.refreshToken,
50
+ idToken: response.idToken,
51
+ };
52
+ const tokenSpawner = JsSpawner({ path: LOCAL_AAI_CFG_DIR });
53
+ await writeTokens({ spawner: tokenSpawner, tokens });
54
+ await writeOrUpdateDeviceCfgFile({ spawner: tokenSpawner });
55
+
56
+ let iotKeys = device.iot_keys;
57
+ if (!iotKeys) {
58
+ // there are no certificates, we need to generate new ones
59
+ console.log('Generating new certificate');
60
+ const response = await getDeviceCertificates(device.uuid, device.mode);
61
+ iotKeys = response.iotKeys;
62
+ }
63
+ const certSpawner = JsSpawner({ path: LOCAL_CERT_AND_KEY_DIR });
64
+ await writeCertificate({
65
+ spawner: certSpawner,
66
+ certificate: iotKeys.certificatePem,
67
+ privateKey: iotKeys.keyPair.PrivateKey,
68
+ rootCa: iotKeys.rootCA,
69
+ });
70
+ console.log('Updated tokens and certificate');
71
+ }
@@ -1,5 +1,5 @@
1
- import { getSystemId } from 'alwaysai';
2
1
  import { CliTerseError } from '@alwaysai/alwayscli';
2
+ import { getSystemId } from 'alwaysai/lib/infrastructure';
3
3
 
4
4
  export function getIoTCoreEndpointUrl() {
5
5
  let iotCoreEndpointUrl = '';
package/src/root.ts CHANGED
@@ -3,16 +3,16 @@ const winston = require('winston');
3
3
  import { CliBranch } from '@alwaysai/alwayscli';
4
4
 
5
5
  import { subcommands } from './subcommands';
6
- import { ALWAYSAI_CLI_EXECUTABLE_NAME } from './constants';
6
+ import { ALWAYSAI_LOG_LEVEL } from './environment';
7
7
 
8
8
  winston.configure({
9
- level: process.env.AAI_LOG_LEVEL || 'info',
9
+ level: ALWAYSAI_LOG_LEVEL || 'info',
10
10
  transports: [new winston.transports.Console()],
11
11
  format: winston.format.simple(),
12
12
  });
13
13
 
14
14
  export const root = CliBranch({
15
- name: ALWAYSAI_CLI_EXECUTABLE_NAME,
15
+ name: 'aai-agent',
16
16
  description: 'Manage your alwaysAI production device',
17
17
  subcommands,
18
18
  });
@@ -6,33 +6,31 @@ import {
6
6
  } from '@alwaysai/alwayscli';
7
7
  import {
8
8
  addModel,
9
+ getAllEnvs,
10
+ getAppLogs,
9
11
  getAppModels,
10
- removeModel,
11
- replaceModels,
12
- updateModels,
13
- } from '../../application-control/models';
14
- import {
15
- getInstalledApps,
12
+ getAppStatus,
16
13
  installApp,
17
- uninstallApp,
18
- } from '../../application-control/install';
19
- import { rollbackApp } from '../../application-control/backup';
20
- import {
21
- listAppReleases,
22
14
  listAppLatestRelease,
23
- getAppStatus,
15
+ listAppReleases,
16
+ removeModel,
17
+ replaceModels,
18
+ restartApp,
19
+ rollbackApp,
20
+ setEnv,
24
21
  startApp,
25
- getAppLogs,
26
22
  stopApp,
27
- restartApp,
28
- } from '../../application-control/status';
23
+ uninstallApp,
24
+ updateModels,
25
+ } from '../../application-control';
26
+ import { AgentConfigFile } from '../../infrastructure/agent-config';
29
27
 
30
28
  export const listAppsCliLeaf = CliLeaf({
31
29
  name: 'list',
32
30
  description: 'List all installed apps',
33
31
  namedInputs: {},
34
32
  async action(_, opts) {
35
- const apps = await getInstalledApps();
33
+ const apps = await AgentConfigFile().getApps();
36
34
  console.table(apps);
37
35
  },
38
36
  });
@@ -272,16 +270,17 @@ export const replaceModelsCliLeaf = CliLeaf({
272
270
  description: 'Project Id',
273
271
  required: true,
274
272
  }),
275
- model: CliStringArrayInput({
273
+ models: CliStringArrayInput({
276
274
  description: 'One or more model IDs',
277
275
  required: true,
278
276
  }),
279
277
  },
280
278
  async action(_, opts) {
281
- const { project, model } = opts;
282
- await replaceModels({ projectId: project, modelIds: model });
279
+ const { project, models } = opts;
280
+ await replaceModels({ projectId: project, modelIds: models });
283
281
  },
284
282
  });
283
+
285
284
  export const updateModelsCliLeaf = CliLeaf({
286
285
  name: 'update-models',
287
286
  description: 'Update all models for an alwaysAI app',
@@ -296,3 +295,42 @@ export const updateModelsCliLeaf = CliLeaf({
296
295
  await updateModels({ projectId: project });
297
296
  },
298
297
  });
298
+
299
+ export const getAllEnvsCLiLeaf = CliLeaf({
300
+ name: 'get-all-envs',
301
+ description: 'Get environment variables for an application',
302
+ namedInputs: {
303
+ project: CliStringInput({
304
+ description: 'Project Id',
305
+ required: true,
306
+ }),
307
+ },
308
+ async action(_, opts) {
309
+ const { project } = opts;
310
+ console.log(await getAllEnvs({ projectId: project }));
311
+ },
312
+ });
313
+
314
+ export const setEnvCLiLeaf = CliLeaf({
315
+ name: 'set-env',
316
+ description: 'Set environment variables for a service',
317
+ positionalInput: CliStringArrayInput({
318
+ placeholder: '<NAME=VALUE> [<NAME=VALUE> ...]',
319
+ required: true,
320
+ }),
321
+ namedInputs: {
322
+ project: CliStringInput({
323
+ description: 'Project Id',
324
+ required: true,
325
+ }),
326
+ service: CliStringInput({
327
+ description:
328
+ 'The name of the docker-compose service to apply environment variable to',
329
+ required: false,
330
+ }),
331
+ },
332
+ async action(args, opts) {
333
+ const { project, service } = opts;
334
+ await setEnv({ projectId: project, vars: args, service });
335
+ },
336
+ });
@@ -16,6 +16,8 @@ import {
16
16
  restartAppCliLeaf,
17
17
  replaceModelsCliLeaf,
18
18
  showAppModelsCliLeaf,
19
+ getAllEnvsCLiLeaf,
20
+ setEnvCLiLeaf,
19
21
  } from './app';
20
22
 
21
23
  export const appCliBranch = CliBranch({
@@ -38,5 +40,7 @@ export const appCliBranch = CliBranch({
38
40
  removeModelCliLeaf,
39
41
  replaceModelsCliLeaf,
40
42
  updateModelsCliLeaf,
43
+ getAllEnvsCLiLeaf,
44
+ setEnvCLiLeaf,
41
45
  ],
42
46
  });
@@ -0,0 +1,63 @@
1
+ import { CliLeaf, CliStringInput } from '@alwaysai/alwayscli';
2
+ import { checkUserIsLoggedInComponent } from 'alwaysai/lib/components/user';
3
+ import { checkPaidPlan } from 'alwaysai/lib/core/project';
4
+ import { addDevice, CliAuthenticationClient } from 'alwaysai/lib/infrastructure';
5
+ import { JsSpawner } from 'alwaysai/lib/util';
6
+ import { getCpuUtil, getDiskUtil, getMemUtil } from '../../device-control/device-control';
7
+ import {
8
+ getTargetHardwareUuid,
9
+ writeCertificateAndToken,
10
+ } from '../../infrastructure/certificates-and-tokens';
11
+
12
+ export const initCliLeaf = CliLeaf({
13
+ name: 'init',
14
+ description: 'Initialize device',
15
+ namedInputs: {
16
+ name: CliStringInput({
17
+ description: 'Device name',
18
+ required: true,
19
+ }),
20
+ description: CliStringInput({
21
+ description: 'Device description',
22
+ required: false,
23
+ }),
24
+ },
25
+ async action(_, opts) {
26
+ const { name, description } = opts;
27
+ console.log('Initializing device');
28
+ await checkUserIsLoggedInComponent({ yes: true });
29
+ if (!(await checkPaidPlan())) {
30
+ throw new Error(`This action only supported for Enterprise alwaysAI accounts!`);
31
+ }
32
+ const { username } = await CliAuthenticationClient().getInfo();
33
+ const spawner = JsSpawner();
34
+ const hardwareId = await getTargetHardwareUuid(spawner);
35
+ const deviceToAdd = {
36
+ owner: username,
37
+ friendly_name: name,
38
+ host_name: '',
39
+ device_user_name: '',
40
+ description: description || '',
41
+ hardware_ids: hardwareId,
42
+ device_hash: '',
43
+ iotKeys: '',
44
+ };
45
+ const response = await addDevice(deviceToAdd, 'production');
46
+ await writeCertificateAndToken({ deviceUuid: response.deviceUUID });
47
+ console.log(`Initialized device as ${response.deviceUUID}`);
48
+ },
49
+ });
50
+
51
+ export const getInfoCliLeaf = CliLeaf({
52
+ name: 'get-info',
53
+ description: 'Get device info',
54
+ namedInputs: {},
55
+ async action(_, opts) {
56
+ const deviceInfo = [
57
+ ['CPU Utilization', `${String(await getCpuUtil())} %`],
58
+ ['Disk Utilization', `${String(await getDiskUtil())} %`],
59
+ ['Memory Utilization', `${String(await getMemUtil())} %`],
60
+ ];
61
+ console.table(deviceInfo);
62
+ },
63
+ });
@@ -0,0 +1,8 @@
1
+ import { CliBranch } from '@alwaysai/alwayscli';
2
+ import { getInfoCliLeaf, initCliLeaf } from './device';
3
+
4
+ export const deviceCliBranch = CliBranch({
5
+ name: 'device',
6
+ description: 'Manage current device',
7
+ subcommands: [initCliLeaf, getInfoCliLeaf],
8
+ });
@@ -0,0 +1,60 @@
1
+ import { CliLeaf, CliNumberInput, CliStringInput } from '@alwaysai/alwayscli';
2
+ import { checkUserIsLoggedInComponent } from 'alwaysai/lib/components/user';
3
+ import {
4
+ downloadModelPackageToCache,
5
+ ModelId,
6
+ modelPackageCache,
7
+ } from 'alwaysai/lib/core/model';
8
+ import { CliRpcClient } from 'alwaysai/lib/infrastructure';
9
+ import { JsSpawner } from 'alwaysai/lib/util';
10
+ import { join } from 'path';
11
+
12
+ export const getModelPackageCliLeaf = CliLeaf({
13
+ name: 'get-model-package',
14
+ description: 'Download and unpack a model package',
15
+ positionalInput: CliStringInput({
16
+ description: 'For example, "alwaysai/mobilenet_ssd"',
17
+ required: true,
18
+ placeholder: '<id>',
19
+ }),
20
+ namedInputs: {
21
+ version: CliNumberInput({
22
+ description: 'The version number of the model',
23
+ required: false,
24
+ }),
25
+ path: CliStringInput({
26
+ description: 'The output path to write model package to',
27
+ required: false,
28
+ }),
29
+ },
30
+ async action(id, opts) {
31
+ // NOTE: This code closely follows 'get-model-package.ts' in the CLI
32
+ const { publisher, name } = ModelId.parse(id);
33
+ const path = opts.path ? opts.path : process.cwd();
34
+ // untar will unpack model package contents to <name> so append publisher to path
35
+ const publisherPath = join(path, publisher);
36
+ const spawner = JsSpawner({ path: publisherPath });
37
+
38
+ if (await spawner.exists(name)) {
39
+ console.log(
40
+ `Found existing version of ${id} at ${join(
41
+ publisherPath,
42
+ name,
43
+ )}, removing prior to download`,
44
+ );
45
+ spawner.rimraf(name);
46
+ }
47
+
48
+ console.log(`Downloading ${id} to ${path}`);
49
+ await checkUserIsLoggedInComponent({ yes: true });
50
+ const version =
51
+ opts.version || (await CliRpcClient().getModelVersion({ id })).version;
52
+ if (!modelPackageCache.has(id, version)) {
53
+ await downloadModelPackageToCache(id, version);
54
+ }
55
+ const modelPackageStream = modelPackageCache.read(id, version);
56
+ await spawner.mkdirp();
57
+ await spawner.untar(modelPackageStream);
58
+ console.log(`Completed downloading ${id} to ${path}`);
59
+ },
60
+ });
@@ -1,5 +1,11 @@
1
- import { appCliBranch } from './app/index';
2
- import { getDeviceInfoCliLeaf } from './device-control';
1
+ import { appCliBranch } from './app';
2
+ import { deviceCliBranch } from './device';
3
3
  import { loginCliLeaf } from './login';
4
+ import { getModelPackageCliLeaf } from './get-model-package';
4
5
 
5
- export const subcommands = [loginCliLeaf, appCliBranch, getDeviceInfoCliLeaf];
6
+ export const subcommands = [
7
+ loginCliLeaf,
8
+ appCliBranch,
9
+ deviceCliBranch,
10
+ getModelPackageCliLeaf,
11
+ ];
@@ -1,4 +1,5 @@
1
1
  import { CliLeaf, CliStringInput, CliUsageError } from '@alwaysai/alwayscli';
2
+ import { writeCertificateAndToken } from '../infrastructure/certificates-and-tokens';
2
3
  import { runCliCmd } from '../util/run-cli-cmd';
3
4
 
4
5
  export const loginCliLeaf = CliLeaf({
@@ -7,18 +8,24 @@ export const loginCliLeaf = CliLeaf({
7
8
  namedInputs: {
8
9
  email: CliStringInput({
9
10
  description: 'alwaysAI email',
11
+ required: true,
10
12
  }),
11
13
  password: CliStringInput({
12
14
  description: 'Account password',
15
+ required: true,
16
+ }),
17
+ device: CliStringInput({
18
+ description: 'The device UUID',
19
+ required: false,
13
20
  }),
14
21
  },
15
22
  async action(_, opts) {
16
- const { email, password } = opts;
17
- if (!email || !password) {
18
- throw new CliUsageError('--email and --password are required!');
19
- }
23
+ const { email, password, device } = opts;
20
24
  await runCliCmd({
21
25
  cmd: ['user', 'login', '--yes', '--email', email, '--password', password],
22
26
  });
27
+ if (device) {
28
+ await writeCertificateAndToken({ deviceUuid: device });
29
+ }
23
30
  },
24
31
  });
@@ -1,4 +1,4 @@
1
- import { JsSpawner } from '../util/spawner/js-spawner';
1
+ import { JsSpawner } from 'alwaysai/lib/util';
2
2
 
3
3
  export async function copyDir(props: { srcPath: string; destPath: string }) {
4
4
  const { srcPath, destPath } = props;
@@ -1,25 +1,25 @@
1
- import { join } from 'path';
2
1
  import {
3
- CERT_AND_KEY_DIR,
4
- TOKEN_DIR,
5
2
  DEVICE_CERTIFICATE_FILE_NAME,
6
3
  DEVICE_PRIVATE_KEY_FILE_NAME,
7
4
  DEVICE_ROOT_CERT_FILE_NAME,
8
5
  DEVICE_TOKEN_FILE_NAME,
9
- } from '../constants';
6
+ LOCAL_AAI_CFG_DIR,
7
+ LOCAL_CERT_AND_KEY_DIR,
8
+ } from 'alwaysai/lib/constants';
9
+ import { join } from 'path';
10
10
 
11
11
  export function getPrivateKeyFilePath() {
12
- return join(CERT_AND_KEY_DIR, DEVICE_PRIVATE_KEY_FILE_NAME);
12
+ return join(LOCAL_CERT_AND_KEY_DIR, DEVICE_PRIVATE_KEY_FILE_NAME);
13
13
  }
14
14
 
15
15
  export function getCertificateFilePath() {
16
- return join(CERT_AND_KEY_DIR, DEVICE_CERTIFICATE_FILE_NAME);
16
+ return join(LOCAL_CERT_AND_KEY_DIR, DEVICE_CERTIFICATE_FILE_NAME);
17
17
  }
18
18
 
19
19
  export function getRootCertificateFilePath() {
20
- return join(CERT_AND_KEY_DIR, DEVICE_ROOT_CERT_FILE_NAME);
20
+ return join(LOCAL_CERT_AND_KEY_DIR, DEVICE_ROOT_CERT_FILE_NAME);
21
21
  }
22
22
 
23
23
  export function getCredentialsFilePath() {
24
- return join(TOKEN_DIR, DEVICE_TOKEN_FILE_NAME);
24
+ return join(LOCAL_AAI_CFG_DIR, DEVICE_TOKEN_FILE_NAME);
25
25
  }
@@ -1,13 +0,0 @@
1
- export declare const ALWAYSAI_CLI_EXECUTABLE_NAME = "aai-agent";
2
- export declare const DEVICE_TOKEN_FILE_NAME = "alwaysai.credentials.json";
3
- export declare const DEVICE_CONFIG_FILE_NAME = "alwaysai.config.json";
4
- export declare const TOKEN_DIR: string;
5
- export declare const CERT_AND_KEY_DIR: string;
6
- export declare const DEVICE_CERTIFICATE_FILE_NAME = "alwaysai.certificate.pem.crt";
7
- export declare const DEVICE_PRIVATE_KEY_FILE_NAME = "alwaysai.private.pem.key";
8
- export declare const DEVICE_PUBLIC_KEY_FILE_NAME = "alwaysai.public.pem.key";
9
- export declare const DEVICE_ROOT_CERT_FILE_NAME = "alwaysai.root.pem";
10
- export declare const SUPPORTED_JETPACK_VERSION = 4.4;
11
- export declare const JETPACK_IMAGE_LINK = "https://developer.nvidia.com/jetson-nano-sd-card-image-44";
12
- export declare const PLEASE_REPORT_THIS_ERROR_MESSAGE = "Please report this error message to support@alwaysai.co";
13
- //# sourceMappingURL=constants.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,4BAA4B,cAAc,CAAC;AAExD,eAAO,MAAM,sBAAsB,8BAA8B,CAAC;AAClE,eAAO,MAAM,uBAAuB,yBAAyB,CAAC;AAE9D,eAAO,MAAM,SAAS,QAAyC,CAAC;AAChE,eAAO,MAAM,gBAAgB,QAAkC,CAAC;AAEhE,eAAO,MAAM,4BAA4B,iCAAiC,CAAC;AAC3E,eAAO,MAAM,4BAA4B,6BAA6B,CAAC;AACvE,eAAO,MAAM,2BAA2B,4BAA4B,CAAC;AACrE,eAAO,MAAM,0BAA0B,sBAAsB,CAAC;AAE9D,eAAO,MAAM,yBAAyB,MAAM,CAAC;AAC7C,eAAO,MAAM,kBAAkB,8DAC8B,CAAC;AAE9D,eAAO,MAAM,gCAAgC,4DACc,CAAC"}