@vention/vention-cli 0.4.0 → 0.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/cli.esm.d.ts +1 -0
- package/cli.esm.js +505 -0
- package/package.json +6 -6
- package/src/cli-helpers.d.ts +5 -0
- package/src/config.d.ts +9 -1
- package/src/digital-twin-client.d.ts +13 -1
- package/src/file-system.d.ts +8 -0
- package/src/file-system.test.d.ts +1 -0
- package/src/machine-code-app-directory-info.d.ts +14 -0
- package/src/machine-code-app-directory-info.test.d.ts +1 -0
- package/src/rails-client.d.ts +18 -1
- package/index.esm.d.ts +0 -1
- package/index.esm.js +0 -208
- package/src/models.d.ts +0 -26
- /package/src/{index.d.ts → cli.d.ts} +0 -0
- /package/src/{index.test.d.ts → cli.test.d.ts} +0 -0
package/README.md
CHANGED
package/cli.esm.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./src/cli";
|
package/cli.esm.js
ADDED
|
@@ -0,0 +1,505 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { Command } from 'commander';
|
|
3
|
+
import chalk from 'chalk';
|
|
4
|
+
import { select, password } from '@inquirer/prompts';
|
|
5
|
+
import fs, { promises, realpathSync } from 'fs';
|
|
6
|
+
import path from 'path';
|
|
7
|
+
|
|
8
|
+
const getConfigPath = () => {
|
|
9
|
+
const homeDir = process.env.HOME || process.env.USERPROFILE;
|
|
10
|
+
if (!homeDir) {
|
|
11
|
+
console.warn(chalk.yellow("Warning: Could not determine home directory. Using current directory instead."));
|
|
12
|
+
console.warn(chalk.yellow("This may cause issues if the CLI is run from different directories."));
|
|
13
|
+
console.warn(chalk.blue("To fix this permanently, set the HOME environment variable."));
|
|
14
|
+
return path.join(process.cwd(), ".vention-cli-config.json");
|
|
15
|
+
}
|
|
16
|
+
return path.join(homeDir, ".vention-cli-config.json");
|
|
17
|
+
};
|
|
18
|
+
const saveSession = async (data) => {
|
|
19
|
+
const configPath = getConfigPath();
|
|
20
|
+
await promises.writeFile(configPath, JSON.stringify(data, null, 2));
|
|
21
|
+
};
|
|
22
|
+
const loadSession = async () => {
|
|
23
|
+
try {
|
|
24
|
+
const configPath = getConfigPath();
|
|
25
|
+
const data = await promises.readFile(configPath, "utf-8");
|
|
26
|
+
return JSON.parse(data);
|
|
27
|
+
}
|
|
28
|
+
catch (error) {
|
|
29
|
+
console.error("Failed to load session:", error);
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
const getBaseRailsUrl = (environment) => {
|
|
35
|
+
switch (environment) {
|
|
36
|
+
case "local":
|
|
37
|
+
return "http://localhost:3000";
|
|
38
|
+
case "demo":
|
|
39
|
+
return "https://vention.foo";
|
|
40
|
+
case "prod":
|
|
41
|
+
return "https://vention.io";
|
|
42
|
+
default:
|
|
43
|
+
throw new Error("Invalid environment");
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
const getUserAllocations = async (session) => {
|
|
47
|
+
const baseUrl = getBaseRailsUrl(session.environment);
|
|
48
|
+
const res = await fetch(`${baseUrl}/api/v3/digital_twin_infrastructure/allocations`, {
|
|
49
|
+
method: "GET",
|
|
50
|
+
headers: {
|
|
51
|
+
Accept: "application/json",
|
|
52
|
+
Origin: baseUrl,
|
|
53
|
+
Referer: `${baseUrl}/`,
|
|
54
|
+
Cookie: [
|
|
55
|
+
`vention_session=${session.ventionSession}`,
|
|
56
|
+
...(session.stytchSessionJwt ? [`stytch_session_jwt=${session.stytchSessionJwt}`] : []),
|
|
57
|
+
...(session.ventionIdpSession ? [`vention_idp_session=${session.ventionIdpSession}`] : []),
|
|
58
|
+
].join("; "),
|
|
59
|
+
},
|
|
60
|
+
});
|
|
61
|
+
if (!res.ok) {
|
|
62
|
+
throw new Error(`Request failed: ${res.status} ${res.statusText}`);
|
|
63
|
+
}
|
|
64
|
+
const response = await res.json();
|
|
65
|
+
return response;
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
const getDigitalTwinUrl = (environment, sessionId) => {
|
|
69
|
+
switch (environment) {
|
|
70
|
+
case "local":
|
|
71
|
+
return `http://localhost:3101`;
|
|
72
|
+
case "demo":
|
|
73
|
+
return `https://digital-twin.vention.foo/digital-twin/machine-motion/passthrough/${sessionId}/80`;
|
|
74
|
+
case "prod":
|
|
75
|
+
return `https://digital-twin.vention.io/digital-twin/machine-motion/passthrough/${sessionId}/80`;
|
|
76
|
+
default:
|
|
77
|
+
throw new Error("Invalid environment");
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
const makeTestRequestToLinkedDigitalTwin = async (session) => {
|
|
81
|
+
if (!session.linkedSessionToken) {
|
|
82
|
+
throw new Error("Linked session token is not set");
|
|
83
|
+
}
|
|
84
|
+
const digitalTwinUrl = getDigitalTwinUrl(session.environment, session.linkedSessionToken);
|
|
85
|
+
const res = await fetch(`${digitalTwinUrl}/v1/library`, {
|
|
86
|
+
method: "GET",
|
|
87
|
+
headers: {
|
|
88
|
+
Accept: "application/json",
|
|
89
|
+
Cookie: `digital-twin-session-${session.linkedDesignId}=s%3A${session.linkedSessionToken}.s`,
|
|
90
|
+
},
|
|
91
|
+
});
|
|
92
|
+
if (!res.ok) {
|
|
93
|
+
throw new Error(`Request failed: ${res.status} ${res.statusText}`);
|
|
94
|
+
}
|
|
95
|
+
return await res.json();
|
|
96
|
+
};
|
|
97
|
+
const getAllApplicationsWithSourceCode = async (session) => {
|
|
98
|
+
if (!session.linkedSessionToken) {
|
|
99
|
+
throw new Error("Linked session token is not set");
|
|
100
|
+
}
|
|
101
|
+
const digitalTwinUrl = getDigitalTwinUrl(session.environment, session.linkedSessionToken);
|
|
102
|
+
const res = await fetch(`${digitalTwinUrl}/v2/library`, {
|
|
103
|
+
method: "GET",
|
|
104
|
+
headers: {
|
|
105
|
+
Accept: "application/json",
|
|
106
|
+
Cookie: `digital-twin-session-${session.linkedDesignId}=s%3A${session.linkedSessionToken}.s`,
|
|
107
|
+
},
|
|
108
|
+
});
|
|
109
|
+
if (!res.ok) {
|
|
110
|
+
throw new Error(`Request failed: ${res.status} ${res.statusText}`);
|
|
111
|
+
}
|
|
112
|
+
const response = await res.json();
|
|
113
|
+
return response.applications || [];
|
|
114
|
+
};
|
|
115
|
+
const pushApplicationToDigitalTwin = async (session, application) => {
|
|
116
|
+
if (!session.linkedSessionToken) {
|
|
117
|
+
throw new Error("Linked session token is not set");
|
|
118
|
+
}
|
|
119
|
+
const digitalTwinUrl = getDigitalTwinUrl(session.environment, session.linkedSessionToken);
|
|
120
|
+
const res = await fetch(`${digitalTwinUrl}/v1/library`, {
|
|
121
|
+
method: "PUT",
|
|
122
|
+
headers: {
|
|
123
|
+
"Content-Type": "application/json",
|
|
124
|
+
Accept: "application/json",
|
|
125
|
+
Cookie: `digital-twin-session-${session.linkedDesignId}=s%3A${session.linkedSessionToken}.s`,
|
|
126
|
+
},
|
|
127
|
+
body: JSON.stringify(application),
|
|
128
|
+
});
|
|
129
|
+
if (!res.ok) {
|
|
130
|
+
throw new Error(`Request failed: ${res.status} ${res.statusText}`);
|
|
131
|
+
}
|
|
132
|
+
return await res.json();
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
const STATE_FILENAME = ".machine-code-app-directory-info.json";
|
|
136
|
+
const writeMachineCodeAppDirectoryInfo = async (projectPath, state) => {
|
|
137
|
+
const statePath = path.join(projectPath, STATE_FILENAME);
|
|
138
|
+
await fs.promises.writeFile(statePath, JSON.stringify(state, null, 2));
|
|
139
|
+
};
|
|
140
|
+
const readMachineCodeAppDirectoryInfo = async (projectPath) => {
|
|
141
|
+
const statePath = path.join(projectPath, STATE_FILENAME);
|
|
142
|
+
try {
|
|
143
|
+
const data = await fs.promises.readFile(statePath, "utf-8");
|
|
144
|
+
return JSON.parse(data);
|
|
145
|
+
}
|
|
146
|
+
catch (error) {
|
|
147
|
+
if (error.code === "ENOENT") {
|
|
148
|
+
return null;
|
|
149
|
+
}
|
|
150
|
+
throw error;
|
|
151
|
+
}
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
const getDefaultIgnorePatterns = () => {
|
|
155
|
+
return new Set(["venv", "node_modules", "dist", "build", "__pycache__", /\.egg-info$/, ".machine-code-app-directory-info.json"]);
|
|
156
|
+
};
|
|
157
|
+
const shouldIgnoreFileSystemNode = (nodeName, ignoredNodes) => {
|
|
158
|
+
for (const pattern of ignoredNodes) {
|
|
159
|
+
if (typeof pattern === "string" && nodeName === pattern) {
|
|
160
|
+
return true;
|
|
161
|
+
}
|
|
162
|
+
if (pattern instanceof RegExp && pattern.test(nodeName)) {
|
|
163
|
+
return true;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
return false;
|
|
167
|
+
};
|
|
168
|
+
const serializeFileSystem = (sourceDirectory, ignoredFileSystemNodes, shouldBase64Encoded) => {
|
|
169
|
+
const fileSystemNode = {};
|
|
170
|
+
const directoryContents = fs.readdirSync(sourceDirectory);
|
|
171
|
+
directoryContents.forEach(directoryItem => {
|
|
172
|
+
if (shouldIgnoreFileSystemNode(directoryItem, ignoredFileSystemNodes)) {
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
const fullPath = path.join(sourceDirectory, directoryItem);
|
|
176
|
+
const directoryItemInformation = fs.statSync(fullPath);
|
|
177
|
+
if (directoryItemInformation.isDirectory()) {
|
|
178
|
+
fileSystemNode[directoryItem] = serializeFileSystem(fullPath, ignoredFileSystemNodes, shouldBase64Encoded);
|
|
179
|
+
}
|
|
180
|
+
else if (directoryItemInformation.isFile()) {
|
|
181
|
+
const fileContent = shouldBase64Encoded ? fs.readFileSync(fullPath, "base64") : fs.readFileSync(fullPath, "utf8");
|
|
182
|
+
fileSystemNode[directoryItem] = fileContent;
|
|
183
|
+
}
|
|
184
|
+
});
|
|
185
|
+
return fileSystemNode;
|
|
186
|
+
};
|
|
187
|
+
const createFileSystemFromJson = async (fileSystemNode, targetDirectory) => {
|
|
188
|
+
await ensureDirectoryExists(targetDirectory);
|
|
189
|
+
const writeFiles = async (node, currentPath) => {
|
|
190
|
+
for (const [entryName, contentOrNode] of Object.entries(node)) {
|
|
191
|
+
const fullPath = path.join(currentPath, entryName);
|
|
192
|
+
if (typeof contentOrNode === "string") {
|
|
193
|
+
const decodedContent = Buffer.from(contentOrNode, "base64");
|
|
194
|
+
const fileHandle = await fs.promises.open(fullPath, "w");
|
|
195
|
+
try {
|
|
196
|
+
await fileHandle.writeFile(decodedContent);
|
|
197
|
+
await fileHandle.sync();
|
|
198
|
+
}
|
|
199
|
+
finally {
|
|
200
|
+
await fileHandle.close();
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
else {
|
|
204
|
+
await ensureDirectoryExists(fullPath);
|
|
205
|
+
await writeFiles(contentOrNode, fullPath);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
};
|
|
209
|
+
await writeFiles(fileSystemNode, targetDirectory);
|
|
210
|
+
const dirHandle = await fs.promises.open(targetDirectory, "r");
|
|
211
|
+
try {
|
|
212
|
+
await dirHandle.sync();
|
|
213
|
+
}
|
|
214
|
+
finally {
|
|
215
|
+
await dirHandle.close();
|
|
216
|
+
}
|
|
217
|
+
};
|
|
218
|
+
const ensureDirectoryExists = async (directory) => {
|
|
219
|
+
const directoryExists = await checkIfDirectoryExists(directory);
|
|
220
|
+
if (!directoryExists) {
|
|
221
|
+
fs.mkdirSync(directory, { recursive: true });
|
|
222
|
+
}
|
|
223
|
+
};
|
|
224
|
+
const checkIfDirectoryExists = async (directory) => {
|
|
225
|
+
const exists = await fs.promises
|
|
226
|
+
.access(directory)
|
|
227
|
+
.then(() => true)
|
|
228
|
+
.catch(() => false);
|
|
229
|
+
return exists;
|
|
230
|
+
};
|
|
231
|
+
const writeApplicationToDisk = async (appName, sourceCode, targetDirectory, overwriteExisting = false) => {
|
|
232
|
+
if (overwriteExisting) {
|
|
233
|
+
await createFileSystemFromJson(sourceCode, targetDirectory);
|
|
234
|
+
return targetDirectory;
|
|
235
|
+
}
|
|
236
|
+
const safeAppName = appName.replace(/[^a-zA-Z0-9-_]/g, "_");
|
|
237
|
+
const appDirectoryPath = path.join(targetDirectory, safeAppName);
|
|
238
|
+
await createFileSystemFromJson(sourceCode, appDirectoryPath);
|
|
239
|
+
return appDirectoryPath;
|
|
240
|
+
};
|
|
241
|
+
|
|
242
|
+
const checkIfDesignHasLiveAllocation = async (session, designId) => {
|
|
243
|
+
const allocations = await getUserAllocations(session);
|
|
244
|
+
const linkedAllocation = allocations.find(a => a.designId === designId);
|
|
245
|
+
return linkedAllocation;
|
|
246
|
+
};
|
|
247
|
+
const getAppFromDigitalTwin = async (session, appId, appName) => {
|
|
248
|
+
console.log(chalk.blue("Fetching all applications with source code from digital twin..."));
|
|
249
|
+
const allApplications = await getAllApplicationsWithSourceCode(session);
|
|
250
|
+
const targetApp = allApplications.find((app) => app.id === appId);
|
|
251
|
+
if (!targetApp) {
|
|
252
|
+
console.error(chalk.red(`Application "${appName}" (ID: ${appId}) not found in the digital twin.`));
|
|
253
|
+
process.exit(1);
|
|
254
|
+
}
|
|
255
|
+
return targetApp;
|
|
256
|
+
};
|
|
257
|
+
const getAvailableAppsFromDigitalTwin = async (session) => {
|
|
258
|
+
const allApplications = await getAllApplicationsWithSourceCode(session);
|
|
259
|
+
return allApplications.filter((app) => app.type === "machine_code");
|
|
260
|
+
};
|
|
261
|
+
const createNewAppDirectory = async (session, currentDir) => {
|
|
262
|
+
if (!session.linkedDesignId) {
|
|
263
|
+
console.error(chalk.red("No design linked. Please run 'vention link' first."));
|
|
264
|
+
process.exit(1);
|
|
265
|
+
}
|
|
266
|
+
const linkedAllocation = await checkIfDesignHasLiveAllocation(session, session.linkedDesignId);
|
|
267
|
+
console.log(chalk.blue(`You are currently linked to design: ${linkedAllocation === null || linkedAllocation === void 0 ? void 0 : linkedAllocation.designName}`));
|
|
268
|
+
if (!linkedAllocation) {
|
|
269
|
+
console.error(chalk.red("Sorry, it seems you do not have that design open with the MachineLogic tab selected."));
|
|
270
|
+
console.error(chalk.red("Please go to your browser, open your design, and navigate to the MachineLogic page."));
|
|
271
|
+
process.exit(1);
|
|
272
|
+
}
|
|
273
|
+
const availableApps = await getAvailableAppsFromDigitalTwin(session);
|
|
274
|
+
if (availableApps.length === 0) {
|
|
275
|
+
console.log(chalk.yellow("No machine code applications found in the digital twin"));
|
|
276
|
+
process.exit(1);
|
|
277
|
+
}
|
|
278
|
+
const selectedApp = await select({
|
|
279
|
+
message: "Select an application to pull:",
|
|
280
|
+
choices: availableApps.map((app) => ({
|
|
281
|
+
name: app.name,
|
|
282
|
+
value: app,
|
|
283
|
+
})),
|
|
284
|
+
});
|
|
285
|
+
console.log(chalk.blue(`\nPulling application "${selectedApp.name}"...`));
|
|
286
|
+
if (!selectedApp.sourceCode) {
|
|
287
|
+
console.log(chalk.yellow("No source code found for this application."));
|
|
288
|
+
process.exit(1);
|
|
289
|
+
}
|
|
290
|
+
const appDirectoryPath = await writeApplicationToDisk(selectedApp.name, selectedApp.sourceCode, currentDir);
|
|
291
|
+
await writeMachineCodeAppDirectoryInfo(appDirectoryPath, {
|
|
292
|
+
appName: selectedApp.name,
|
|
293
|
+
designId: session.linkedDesignId,
|
|
294
|
+
applicationId: selectedApp.id,
|
|
295
|
+
lastPulledAt: new Date().toISOString(),
|
|
296
|
+
environment: session.environment,
|
|
297
|
+
uuid: selectedApp.uuid,
|
|
298
|
+
});
|
|
299
|
+
console.log(chalk.green(`✅ Successfully pulled "${selectedApp.name}" to: ${appDirectoryPath}`));
|
|
300
|
+
console.log(chalk.blue(`📁 To navigate to your project, run:`));
|
|
301
|
+
console.log(chalk.cyan(`cd "${appDirectoryPath}"`));
|
|
302
|
+
console.log(chalk.blue("💡 You can now start working on your application!"));
|
|
303
|
+
};
|
|
304
|
+
const updateExistingAppDirectory = async (session, projectState, currentDir) => {
|
|
305
|
+
console.log(chalk.blue(`Found existing project: ${projectState.appName}`));
|
|
306
|
+
console.log(chalk.blue(`Design ID: ${projectState.designId}, App ID: ${projectState.applicationId}`));
|
|
307
|
+
const linkedAllocation = await checkIfDesignHasLiveAllocation(session, projectState.designId);
|
|
308
|
+
if (!linkedAllocation) {
|
|
309
|
+
console.error(chalk.red("Sorry, it seems you do not have that design open with the MachineLogic tab selected."));
|
|
310
|
+
console.error(chalk.red("Please go to your browser, open your design, and navigate to the MachineLogic page."));
|
|
311
|
+
process.exit(1);
|
|
312
|
+
}
|
|
313
|
+
await saveSession(Object.assign(Object.assign({}, session), { linkedDesignId: projectState.designId, linkedSessionToken: linkedAllocation.sessionId }));
|
|
314
|
+
const appWithSourceCode = await getAppFromDigitalTwin(session, projectState.applicationId, projectState.appName);
|
|
315
|
+
await writeApplicationToDisk(appWithSourceCode.name, appWithSourceCode.sourceCode, currentDir, true);
|
|
316
|
+
await writeMachineCodeAppDirectoryInfo(currentDir, Object.assign(Object.assign({}, projectState), { lastPulledAt: new Date().toISOString() }));
|
|
317
|
+
console.log(chalk.green(`✅ Successfully pulled "${appWithSourceCode.name}" to: ${currentDir}`));
|
|
318
|
+
console.log(chalk.blue("💡 Your project has been updated with the latest changes!"));
|
|
319
|
+
};
|
|
320
|
+
|
|
321
|
+
const program = new Command();
|
|
322
|
+
program.name("vention").description("CLI tool for Vention").version("0.2.0");
|
|
323
|
+
program
|
|
324
|
+
.command("login")
|
|
325
|
+
.description("Login to Vention")
|
|
326
|
+
.action(async () => {
|
|
327
|
+
try {
|
|
328
|
+
const environment = (await select({
|
|
329
|
+
message: "Select environment:",
|
|
330
|
+
choices: [
|
|
331
|
+
{ name: "local", value: "local" },
|
|
332
|
+
{ name: "demo", value: "demo" },
|
|
333
|
+
{ name: "prod", value: "prod" },
|
|
334
|
+
],
|
|
335
|
+
}));
|
|
336
|
+
const ventionSession = await password({
|
|
337
|
+
message: "Enter vention_session cookie value:",
|
|
338
|
+
mask: "",
|
|
339
|
+
validate: (input) => input.length > 0 || "vention_session is required",
|
|
340
|
+
});
|
|
341
|
+
const stytchSessionJwt = environment !== "local"
|
|
342
|
+
? await password({
|
|
343
|
+
message: "Enter stytch_session_jwt cookie value:",
|
|
344
|
+
mask: "",
|
|
345
|
+
validate: (input) => input.length > 0 || "stytch_session_jwt is required for non-local environments",
|
|
346
|
+
})
|
|
347
|
+
: undefined;
|
|
348
|
+
const ventionIdpSession = environment !== "local"
|
|
349
|
+
? await password({
|
|
350
|
+
message: "Enter vention_idp_session cookie value:",
|
|
351
|
+
mask: "",
|
|
352
|
+
validate: (input) => input.length > 0 || "vention_idp_session is required for non-local environments",
|
|
353
|
+
})
|
|
354
|
+
: undefined;
|
|
355
|
+
await saveSession(Object.assign({ environment,
|
|
356
|
+
ventionSession }, (environment !== "local" ? { stytchSessionJwt, ventionIdpSession } : {})));
|
|
357
|
+
console.log(chalk.green("Successfully logged in!"));
|
|
358
|
+
}
|
|
359
|
+
catch (error) {
|
|
360
|
+
console.error(chalk.red("Login failed:"), error);
|
|
361
|
+
process.exit(1);
|
|
362
|
+
}
|
|
363
|
+
});
|
|
364
|
+
program
|
|
365
|
+
.command("link")
|
|
366
|
+
.description("Link to a one of your active designs")
|
|
367
|
+
.action(async () => {
|
|
368
|
+
try {
|
|
369
|
+
const session = await loadSession();
|
|
370
|
+
if (!session) {
|
|
371
|
+
console.error(chalk.red("Not logged in. Please run 'vention login' first."));
|
|
372
|
+
process.exit(1);
|
|
373
|
+
}
|
|
374
|
+
const allocations = await getUserAllocations(session);
|
|
375
|
+
if (allocations.length === 0) {
|
|
376
|
+
console.log(chalk.yellow("No active allocations found. Please open a design and navigate to the machine logic tab to activate a digital twin."));
|
|
377
|
+
process.exit(1);
|
|
378
|
+
}
|
|
379
|
+
const selectedDesign = await select({
|
|
380
|
+
message: "Select a design to link:",
|
|
381
|
+
choices: allocations.map((allocation) => ({
|
|
382
|
+
name: `${allocation.designName} (ID: ${allocation.designId})`,
|
|
383
|
+
value: { id: allocation.designId, name: allocation.designName, sessionId: allocation.sessionId },
|
|
384
|
+
})),
|
|
385
|
+
});
|
|
386
|
+
await saveSession(Object.assign(Object.assign({}, session), { linkedDesignId: selectedDesign.id, linkedSessionToken: selectedDesign.sessionId }));
|
|
387
|
+
console.log(chalk.green(`\nSuccessfully linked to design "${selectedDesign.name}" (ID: ${selectedDesign.id})`));
|
|
388
|
+
}
|
|
389
|
+
catch (error) {
|
|
390
|
+
console.error(chalk.red("Failed to get allocations:"));
|
|
391
|
+
console.error(chalk.red(`Error: ${error instanceof Error ? error.message : String(error)}`));
|
|
392
|
+
process.exit(1);
|
|
393
|
+
}
|
|
394
|
+
});
|
|
395
|
+
program
|
|
396
|
+
.command("test")
|
|
397
|
+
.description("Make a test request to the digital twin for the linked design")
|
|
398
|
+
.action(async () => {
|
|
399
|
+
try {
|
|
400
|
+
const session = await loadSession();
|
|
401
|
+
if (!session) {
|
|
402
|
+
console.error(chalk.red("Not logged in. Please run 'vention login' first."));
|
|
403
|
+
process.exit(1);
|
|
404
|
+
}
|
|
405
|
+
if (!session.linkedDesignId) {
|
|
406
|
+
console.error(chalk.red("No design linked. Please run 'vention link' first."));
|
|
407
|
+
process.exit(1);
|
|
408
|
+
}
|
|
409
|
+
const allocations = await getUserAllocations(session);
|
|
410
|
+
const linkedAllocation = allocations.find(a => a.designId === session.linkedDesignId);
|
|
411
|
+
if (!linkedAllocation) {
|
|
412
|
+
console.error(chalk.red("Linked design is not currently allocated. Please check if the digital twin is running."));
|
|
413
|
+
process.exit(1);
|
|
414
|
+
}
|
|
415
|
+
const digitalTwinResponse = await makeTestRequestToLinkedDigitalTwin(session);
|
|
416
|
+
console.log(chalk.green("Digital twin response:"));
|
|
417
|
+
console.log(chalk.green(JSON.stringify(digitalTwinResponse, null, 2)));
|
|
418
|
+
}
|
|
419
|
+
catch (error) {
|
|
420
|
+
console.error(chalk.red("Failed to get digital twin response:"));
|
|
421
|
+
console.error(chalk.red(`Error: ${error instanceof Error ? error.message : String(error)}`));
|
|
422
|
+
process.exit(1);
|
|
423
|
+
}
|
|
424
|
+
});
|
|
425
|
+
program
|
|
426
|
+
.command("pull")
|
|
427
|
+
.description("Pull an application from one of your active designs")
|
|
428
|
+
.action(async () => {
|
|
429
|
+
try {
|
|
430
|
+
const session = await loadSession();
|
|
431
|
+
if (!session) {
|
|
432
|
+
console.error(chalk.red("Not logged in. Please run 'vention login' first."));
|
|
433
|
+
process.exit(1);
|
|
434
|
+
}
|
|
435
|
+
const currentDir = process.cwd();
|
|
436
|
+
const machineCodeAppDirectoryInfo = await readMachineCodeAppDirectoryInfo(currentDir);
|
|
437
|
+
const isMachineCodeAppDirectory = !!machineCodeAppDirectoryInfo;
|
|
438
|
+
if (isMachineCodeAppDirectory) {
|
|
439
|
+
await updateExistingAppDirectory(session, machineCodeAppDirectoryInfo, currentDir);
|
|
440
|
+
}
|
|
441
|
+
else {
|
|
442
|
+
await createNewAppDirectory(session, currentDir);
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
catch (error) {
|
|
446
|
+
console.error(chalk.red("Failed to pull application:"));
|
|
447
|
+
console.error(chalk.red(`Error: ${error instanceof Error ? error.message : String(error)}`));
|
|
448
|
+
process.exit(1);
|
|
449
|
+
}
|
|
450
|
+
});
|
|
451
|
+
program
|
|
452
|
+
.command("push")
|
|
453
|
+
.description("Push local changes back to the digital twin")
|
|
454
|
+
.action(async () => {
|
|
455
|
+
try {
|
|
456
|
+
const session = await loadSession();
|
|
457
|
+
if (!session) {
|
|
458
|
+
console.error(chalk.red("Not logged in. Please run 'vention login' first."));
|
|
459
|
+
process.exit(1);
|
|
460
|
+
}
|
|
461
|
+
const currentDir = process.cwd();
|
|
462
|
+
const machineCodeAppDirectoryInfo = await readMachineCodeAppDirectoryInfo(currentDir);
|
|
463
|
+
if (!machineCodeAppDirectoryInfo) {
|
|
464
|
+
console.error(chalk.red("Not in a machine code application directory. Please run 'vention pull' first to create a project."));
|
|
465
|
+
console.error(chalk.red("Make sure you are in the root directory of a machine code application you have created using the 'vention pull' command."));
|
|
466
|
+
process.exit(1);
|
|
467
|
+
}
|
|
468
|
+
console.log(chalk.blue(`Pushing changes for project: ${machineCodeAppDirectoryInfo.appName}`));
|
|
469
|
+
console.log(chalk.blue(`Design ID: ${machineCodeAppDirectoryInfo.designId}, App ID: ${machineCodeAppDirectoryInfo.applicationId}`));
|
|
470
|
+
const linkedAllocation = await checkIfDesignHasLiveAllocation(session, machineCodeAppDirectoryInfo.designId);
|
|
471
|
+
if (!linkedAllocation) {
|
|
472
|
+
console.error(chalk.red("Sorry, it seems you do not have that design open with the MachineLogic tab selected."));
|
|
473
|
+
console.error(chalk.red("Please go to your browser, open your design, and navigate to the MachineLogic page."));
|
|
474
|
+
process.exit(1);
|
|
475
|
+
}
|
|
476
|
+
await saveSession(Object.assign(Object.assign({}, session), { linkedDesignId: machineCodeAppDirectoryInfo.designId, linkedSessionToken: linkedAllocation.sessionId }));
|
|
477
|
+
console.log(chalk.blue("Serializing local files..."));
|
|
478
|
+
const ignorePatterns = getDefaultIgnorePatterns();
|
|
479
|
+
const serializedSourceCode = serializeFileSystem(currentDir, ignorePatterns, true);
|
|
480
|
+
const applicationToPush = {
|
|
481
|
+
name: machineCodeAppDirectoryInfo.appName,
|
|
482
|
+
id: machineCodeAppDirectoryInfo.applicationId,
|
|
483
|
+
type: "machine_code",
|
|
484
|
+
sourceCode: serializedSourceCode,
|
|
485
|
+
uuid: machineCodeAppDirectoryInfo.uuid,
|
|
486
|
+
};
|
|
487
|
+
console.log(chalk.blue("Pushing to digital twin..."));
|
|
488
|
+
await pushApplicationToDigitalTwin(session, applicationToPush);
|
|
489
|
+
await writeMachineCodeAppDirectoryInfo(currentDir, Object.assign(Object.assign({}, machineCodeAppDirectoryInfo), { lastPushedAt: new Date().toISOString() }));
|
|
490
|
+
console.log(chalk.green(`✅ Successfully pushed "${machineCodeAppDirectoryInfo.appName}" to digital twin`));
|
|
491
|
+
console.log(chalk.blue("💡 Your changes have been uploaded!"));
|
|
492
|
+
}
|
|
493
|
+
catch (error) {
|
|
494
|
+
console.error(chalk.red("Failed to push application:"));
|
|
495
|
+
console.error(chalk.red(`Error: ${error instanceof Error ? error.message : String(error)}`));
|
|
496
|
+
process.exit(1);
|
|
497
|
+
}
|
|
498
|
+
});
|
|
499
|
+
const resolvedArgv = realpathSync(process.argv[1]);
|
|
500
|
+
const resolvedUrl = new URL(import.meta.url).pathname;
|
|
501
|
+
if (resolvedArgv === resolvedUrl) {
|
|
502
|
+
program.parse(process.argv);
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
export { program };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vention/vention-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.1",
|
|
4
4
|
"description": "CLI tool for Vention applications",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"repository": {
|
|
@@ -13,8 +13,8 @@
|
|
|
13
13
|
},
|
|
14
14
|
"license": "MIT",
|
|
15
15
|
"bin": {
|
|
16
|
-
"vention": "
|
|
17
|
-
"vn": "
|
|
16
|
+
"vention": "cli.esm.js",
|
|
17
|
+
"vn": "cli.esm.js"
|
|
18
18
|
},
|
|
19
19
|
"dependencies": {
|
|
20
20
|
"axios": "1.7.7",
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
"typescript": "5.3.3",
|
|
30
30
|
"vitest": "3.2.3"
|
|
31
31
|
},
|
|
32
|
-
"module": "./
|
|
33
|
-
"main": "./
|
|
34
|
-
"types": "./
|
|
32
|
+
"module": "./cli.esm.js",
|
|
33
|
+
"main": "./cli.esm.js",
|
|
34
|
+
"types": "./cli.esm.d.ts"
|
|
35
35
|
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { SessionData } from "./config";
|
|
2
|
+
import { MachineCodeAppDirectoryInfo } from "./machine-code-app-directory-info";
|
|
3
|
+
export declare const checkIfDesignHasLiveAllocation: (session: SessionData, designId: number) => Promise<import("./rails-client").AllocationResponse | undefined>;
|
|
4
|
+
export declare const createNewAppDirectory: (session: SessionData, currentDir: string) => Promise<void>;
|
|
5
|
+
export declare const updateExistingAppDirectory: (session: SessionData, projectState: MachineCodeAppDirectoryInfo, currentDir: string) => Promise<void>;
|
package/src/config.d.ts
CHANGED
|
@@ -1,4 +1,12 @@
|
|
|
1
|
-
|
|
1
|
+
export interface SessionData {
|
|
2
|
+
environment: "local" | "demo" | "prod";
|
|
3
|
+
ventionSession: string;
|
|
4
|
+
stytchSessionJwt?: string;
|
|
5
|
+
ventionIdpSession?: string;
|
|
6
|
+
linkedDesignId?: number;
|
|
7
|
+
lastTaskId?: string;
|
|
8
|
+
linkedSessionToken?: string;
|
|
9
|
+
}
|
|
2
10
|
export declare const getConfigPath: () => string;
|
|
3
11
|
export declare const saveSession: (data: SessionData) => Promise<void>;
|
|
4
12
|
export declare const loadSession: () => Promise<SessionData | null>;
|
|
@@ -1,3 +1,15 @@
|
|
|
1
|
-
import { SessionData } from "./
|
|
1
|
+
import { SessionData } from "./config";
|
|
2
|
+
export interface FileSystemNode {
|
|
3
|
+
[entryName: string]: FileSystemNode | string;
|
|
4
|
+
}
|
|
5
|
+
export interface Application {
|
|
6
|
+
name: string;
|
|
7
|
+
id: string;
|
|
8
|
+
uuid?: string;
|
|
9
|
+
type: string;
|
|
10
|
+
sourceCode: FileSystemNode;
|
|
11
|
+
}
|
|
2
12
|
export declare const getDigitalTwinUrl: (environment: SessionData["environment"], sessionId: string) => string;
|
|
3
13
|
export declare const makeTestRequestToLinkedDigitalTwin: (session: SessionData) => Promise<any>;
|
|
14
|
+
export declare const getAllApplicationsWithSourceCode: (session: SessionData) => Promise<Application[]>;
|
|
15
|
+
export declare const pushApplicationToDigitalTwin: (session: SessionData, application: Application) => Promise<void>;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export interface FileSystemNode {
|
|
2
|
+
[entryName: string]: FileSystemNode | string;
|
|
3
|
+
}
|
|
4
|
+
export declare const getDefaultIgnorePatterns: () => Set<string | RegExp>;
|
|
5
|
+
export declare const shouldIgnoreFileSystemNode: (nodeName: string, ignoredNodes: Set<string | RegExp>) => boolean;
|
|
6
|
+
export declare const serializeFileSystem: (sourceDirectory: string, ignoredFileSystemNodes: Set<string | RegExp>, shouldBase64Encoded: boolean) => FileSystemNode;
|
|
7
|
+
export declare const createFileSystemFromJson: (fileSystemNode: FileSystemNode, targetDirectory: string) => Promise<void>;
|
|
8
|
+
export declare const writeApplicationToDisk: (appName: string, sourceCode: FileSystemNode, targetDirectory: string, overwriteExisting?: boolean) => Promise<string>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export interface MachineCodeAppDirectoryInfo {
|
|
2
|
+
appName: string;
|
|
3
|
+
designId: number;
|
|
4
|
+
applicationId: string;
|
|
5
|
+
uuid?: string;
|
|
6
|
+
lastPulledAt: string;
|
|
7
|
+
lastPushedAt?: string;
|
|
8
|
+
environment: "local" | "demo" | "prod";
|
|
9
|
+
}
|
|
10
|
+
export declare const writeMachineCodeAppDirectoryInfo: (projectPath: string, state: MachineCodeAppDirectoryInfo) => Promise<void>;
|
|
11
|
+
export declare const readMachineCodeAppDirectoryInfo: (projectPath: string) => Promise<MachineCodeAppDirectoryInfo | null>;
|
|
12
|
+
export declare const updateLastPulledAt: (projectPath: string) => Promise<void>;
|
|
13
|
+
export declare const updateLastPushedAt: (projectPath: string) => Promise<void>;
|
|
14
|
+
export declare const isMachineCodeAppDirectory: (projectPath: string) => Promise<boolean>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/src/rails-client.d.ts
CHANGED
|
@@ -1,3 +1,20 @@
|
|
|
1
|
-
import { SessionData
|
|
1
|
+
import { SessionData } from "./config";
|
|
2
|
+
export interface AllocationResponse {
|
|
3
|
+
cookie: {
|
|
4
|
+
originalMaxAge: number;
|
|
5
|
+
expires: string;
|
|
6
|
+
httpOnly: boolean;
|
|
7
|
+
path: string;
|
|
8
|
+
};
|
|
9
|
+
sessionId: string;
|
|
10
|
+
tabId: string;
|
|
11
|
+
userId: string;
|
|
12
|
+
allocatedResourceId: string;
|
|
13
|
+
allocationCreationTime: number;
|
|
14
|
+
allocatedResourceLastAccessTime: number;
|
|
15
|
+
allocationType: "regular" | "custom";
|
|
16
|
+
designName: string;
|
|
17
|
+
designId: number;
|
|
18
|
+
}
|
|
2
19
|
export declare const getBaseRailsUrl: (environment: SessionData["environment"]) => "http://localhost:3000" | "https://vention.foo" | "https://vention.io";
|
|
3
20
|
export declare const getUserAllocations: (session: SessionData) => Promise<AllocationResponse[]>;
|
package/index.esm.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from "./src/index";
|
package/index.esm.js
DELETED
|
@@ -1,208 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import { Command } from 'commander';
|
|
3
|
-
import chalk from 'chalk';
|
|
4
|
-
import { select, password } from '@inquirer/prompts';
|
|
5
|
-
import { promises, realpathSync } from 'fs';
|
|
6
|
-
import path from 'path';
|
|
7
|
-
|
|
8
|
-
const getConfigPath = () => {
|
|
9
|
-
const homeDir = process.env.HOME || process.env.USERPROFILE;
|
|
10
|
-
if (!homeDir) {
|
|
11
|
-
console.warn(chalk.yellow("Warning: Could not determine home directory. Using current directory instead."));
|
|
12
|
-
console.warn(chalk.yellow("This may cause issues if the CLI is run from different directories."));
|
|
13
|
-
console.warn(chalk.blue("To fix this permanently, set the HOME environment variable."));
|
|
14
|
-
return path.join(process.cwd(), ".vention-cli-config.json");
|
|
15
|
-
}
|
|
16
|
-
return path.join(homeDir, ".vention-cli-config.json");
|
|
17
|
-
};
|
|
18
|
-
const saveSession = async (data) => {
|
|
19
|
-
const configPath = getConfigPath();
|
|
20
|
-
await promises.writeFile(configPath, JSON.stringify(data, null, 2));
|
|
21
|
-
};
|
|
22
|
-
const loadSession = async () => {
|
|
23
|
-
try {
|
|
24
|
-
const configPath = getConfigPath();
|
|
25
|
-
const data = await promises.readFile(configPath, "utf-8");
|
|
26
|
-
return JSON.parse(data);
|
|
27
|
-
}
|
|
28
|
-
catch (error) {
|
|
29
|
-
console.error("Failed to load session:", error);
|
|
30
|
-
return null;
|
|
31
|
-
}
|
|
32
|
-
};
|
|
33
|
-
|
|
34
|
-
const getBaseRailsUrl = (environment) => {
|
|
35
|
-
switch (environment) {
|
|
36
|
-
case "local":
|
|
37
|
-
return "http://localhost:3000";
|
|
38
|
-
case "demo":
|
|
39
|
-
return "https://vention.foo";
|
|
40
|
-
case "prod":
|
|
41
|
-
return "https://vention.io";
|
|
42
|
-
default:
|
|
43
|
-
throw new Error("Invalid environment");
|
|
44
|
-
}
|
|
45
|
-
};
|
|
46
|
-
const getUserAllocations = async (session) => {
|
|
47
|
-
const baseUrl = getBaseRailsUrl(session.environment);
|
|
48
|
-
const res = await fetch(`${baseUrl}/api/v3/digital_twin_infrastructure/allocations`, {
|
|
49
|
-
method: "GET",
|
|
50
|
-
headers: {
|
|
51
|
-
Accept: "application/json",
|
|
52
|
-
Origin: baseUrl,
|
|
53
|
-
Referer: `${baseUrl}/`,
|
|
54
|
-
Cookie: [
|
|
55
|
-
`vention_session=${session.ventionSession}`,
|
|
56
|
-
...(session.stytchSessionJwt ? [`stytch_session_jwt=${session.stytchSessionJwt}`] : []),
|
|
57
|
-
...(session.ventionIdpSession ? [`vention_idp_session=${session.ventionIdpSession}`] : []),
|
|
58
|
-
].join("; "),
|
|
59
|
-
},
|
|
60
|
-
});
|
|
61
|
-
if (!res.ok) {
|
|
62
|
-
throw new Error(`Request failed: ${res.status} ${res.statusText}`);
|
|
63
|
-
}
|
|
64
|
-
const response = await res.json();
|
|
65
|
-
return response;
|
|
66
|
-
};
|
|
67
|
-
|
|
68
|
-
const getDigitalTwinUrl = (environment, sessionId) => {
|
|
69
|
-
switch (environment) {
|
|
70
|
-
case "local":
|
|
71
|
-
return `http://localhost:3101`;
|
|
72
|
-
case "demo":
|
|
73
|
-
return `https://digital-twin.vention.foo/digital-twin/machine-motion/passthrough/${sessionId}/80`;
|
|
74
|
-
case "prod":
|
|
75
|
-
return `https://digital-twin.vention.io/digital-twin/machine-motion/passthrough/${sessionId}/80`;
|
|
76
|
-
default:
|
|
77
|
-
throw new Error("Invalid environment");
|
|
78
|
-
}
|
|
79
|
-
};
|
|
80
|
-
const makeTestRequestToLinkedDigitalTwin = async (session) => {
|
|
81
|
-
if (!session.linkedSessionToken) {
|
|
82
|
-
throw new Error("Linked session token is not set");
|
|
83
|
-
}
|
|
84
|
-
const digitalTwinUrl = getDigitalTwinUrl(session.environment, session.linkedSessionToken);
|
|
85
|
-
const res = await fetch(`${digitalTwinUrl}/v1/library`, {
|
|
86
|
-
method: "GET",
|
|
87
|
-
headers: {
|
|
88
|
-
Accept: "application/json",
|
|
89
|
-
Cookie: `digital-twin-session-${session.linkedDesignId}=s%3A${session.linkedSessionToken}.s`,
|
|
90
|
-
},
|
|
91
|
-
});
|
|
92
|
-
if (!res.ok) {
|
|
93
|
-
throw new Error(`Request failed: ${res.status} ${res.statusText}`);
|
|
94
|
-
}
|
|
95
|
-
return await res.json();
|
|
96
|
-
};
|
|
97
|
-
|
|
98
|
-
const program = new Command();
|
|
99
|
-
program.name("vention").description("CLI tool for Vention").version("0.2.0");
|
|
100
|
-
program
|
|
101
|
-
.command("login")
|
|
102
|
-
.description("Login to Ventionn")
|
|
103
|
-
.action(async () => {
|
|
104
|
-
try {
|
|
105
|
-
const environment = (await select({
|
|
106
|
-
message: "Select environment:",
|
|
107
|
-
choices: [
|
|
108
|
-
{ name: "local", value: "local" },
|
|
109
|
-
{ name: "demo", value: "demo" },
|
|
110
|
-
{ name: "prod", value: "prod" },
|
|
111
|
-
],
|
|
112
|
-
}));
|
|
113
|
-
const ventionSession = await password({
|
|
114
|
-
message: "Enter vention_session cookie value:",
|
|
115
|
-
mask: "",
|
|
116
|
-
validate: (input) => input.length > 0 || "vention_session is required",
|
|
117
|
-
});
|
|
118
|
-
const stytchSessionJwt = environment !== "local"
|
|
119
|
-
? await password({
|
|
120
|
-
message: "Enter stytch_session_jwt cookie value:",
|
|
121
|
-
mask: "",
|
|
122
|
-
validate: (input) => input.length > 0 || "stytch_session_jwt is required for non-local environments",
|
|
123
|
-
})
|
|
124
|
-
: undefined;
|
|
125
|
-
const ventionIdpSession = environment !== "local"
|
|
126
|
-
? await password({
|
|
127
|
-
message: "Enter vention_idp_session cookie value:",
|
|
128
|
-
mask: "",
|
|
129
|
-
validate: (input) => input.length > 0 || "vention_idp_session is required for non-local environments",
|
|
130
|
-
})
|
|
131
|
-
: undefined;
|
|
132
|
-
await saveSession(Object.assign({ environment,
|
|
133
|
-
ventionSession }, (environment !== "local" ? { stytchSessionJwt, ventionIdpSession } : {})));
|
|
134
|
-
console.log(chalk.green("Successfully logged in!"));
|
|
135
|
-
}
|
|
136
|
-
catch (error) {
|
|
137
|
-
console.error(chalk.red("Login failed:"), error);
|
|
138
|
-
process.exit(1);
|
|
139
|
-
}
|
|
140
|
-
});
|
|
141
|
-
program
|
|
142
|
-
.command("link")
|
|
143
|
-
.description("Link to a one of your active designs")
|
|
144
|
-
.action(async () => {
|
|
145
|
-
try {
|
|
146
|
-
const session = await loadSession();
|
|
147
|
-
if (!session) {
|
|
148
|
-
console.error(chalk.red("Not logged in. Please run 'vention login' first."));
|
|
149
|
-
process.exit(1);
|
|
150
|
-
}
|
|
151
|
-
const allocations = await getUserAllocations(session);
|
|
152
|
-
if (allocations.length === 0) {
|
|
153
|
-
console.log(chalk.yellow("No active allocations found."));
|
|
154
|
-
process.exit(1);
|
|
155
|
-
}
|
|
156
|
-
const selectedDesign = await select({
|
|
157
|
-
message: "Select a design to link:",
|
|
158
|
-
choices: allocations.map((allocation) => ({
|
|
159
|
-
name: `${allocation.designName} (ID: ${allocation.designId})`,
|
|
160
|
-
value: { id: allocation.designId, name: allocation.designName, sessionId: allocation.sessionId },
|
|
161
|
-
})),
|
|
162
|
-
});
|
|
163
|
-
await saveSession(Object.assign(Object.assign({}, session), { linkedDesignId: selectedDesign.id, linkedSessionToken: selectedDesign.sessionId }));
|
|
164
|
-
console.log(chalk.green(`\nSuccessfully linked to design "${selectedDesign.name}" (ID: ${selectedDesign.id})`));
|
|
165
|
-
}
|
|
166
|
-
catch (error) {
|
|
167
|
-
console.error(chalk.red("Failed to get allocations:"));
|
|
168
|
-
console.error(chalk.red(`Error: ${error instanceof Error ? error.message : String(error)}`));
|
|
169
|
-
process.exit(1);
|
|
170
|
-
}
|
|
171
|
-
});
|
|
172
|
-
program
|
|
173
|
-
.command("test")
|
|
174
|
-
.description("Make a test request to the digital twin for the linked design")
|
|
175
|
-
.action(async () => {
|
|
176
|
-
try {
|
|
177
|
-
const session = await loadSession();
|
|
178
|
-
if (!session) {
|
|
179
|
-
console.error(chalk.red("Not logged in. Please run 'vention login' first."));
|
|
180
|
-
process.exit(1);
|
|
181
|
-
}
|
|
182
|
-
if (!session.linkedDesignId) {
|
|
183
|
-
console.error(chalk.red("No design linked. Please run 'vention link' first."));
|
|
184
|
-
process.exit(1);
|
|
185
|
-
}
|
|
186
|
-
const allocations = await getUserAllocations(session);
|
|
187
|
-
const linkedAllocation = allocations.find(a => a.designId === session.linkedDesignId);
|
|
188
|
-
if (!linkedAllocation) {
|
|
189
|
-
console.error(chalk.red("Linked design is not currently allocated. Please check if the digital twin is running."));
|
|
190
|
-
process.exit(1);
|
|
191
|
-
}
|
|
192
|
-
const digitalTwinResponse = await makeTestRequestToLinkedDigitalTwin(session);
|
|
193
|
-
console.log(chalk.green("Digital twin response:"));
|
|
194
|
-
console.log(chalk.green(JSON.stringify(digitalTwinResponse, null, 2)));
|
|
195
|
-
}
|
|
196
|
-
catch (error) {
|
|
197
|
-
console.error(chalk.red("Failed to get digital twin response:"));
|
|
198
|
-
console.error(chalk.red(`Error: ${error instanceof Error ? error.message : String(error)}`));
|
|
199
|
-
process.exit(1);
|
|
200
|
-
}
|
|
201
|
-
});
|
|
202
|
-
const resolvedArgv = realpathSync(process.argv[1]);
|
|
203
|
-
const resolvedUrl = new URL(import.meta.url).pathname;
|
|
204
|
-
if (resolvedArgv === resolvedUrl) {
|
|
205
|
-
program.parse(process.argv);
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
export { program };
|
package/src/models.d.ts
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
export interface AllocationResponse {
|
|
2
|
-
cookie: {
|
|
3
|
-
originalMaxAge: number;
|
|
4
|
-
expires: string;
|
|
5
|
-
httpOnly: boolean;
|
|
6
|
-
path: string;
|
|
7
|
-
};
|
|
8
|
-
sessionId: string;
|
|
9
|
-
tabId: string;
|
|
10
|
-
userId: string;
|
|
11
|
-
allocatedResourceId: string;
|
|
12
|
-
allocationCreationTime: number;
|
|
13
|
-
allocatedResourceLastAccessTime: number;
|
|
14
|
-
allocationType: "regular" | "custom";
|
|
15
|
-
designName: string;
|
|
16
|
-
designId: number;
|
|
17
|
-
}
|
|
18
|
-
export interface SessionData {
|
|
19
|
-
environment: "local" | "demo" | "prod";
|
|
20
|
-
ventionSession: string;
|
|
21
|
-
stytchSessionJwt?: string;
|
|
22
|
-
ventionIdpSession?: string;
|
|
23
|
-
linkedDesignId?: number;
|
|
24
|
-
lastTaskId?: string;
|
|
25
|
-
linkedSessionToken?: string;
|
|
26
|
-
}
|
|
File without changes
|
|
File without changes
|