reallink-cli 0.1.10 → 0.1.12
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 +128 -1
- package/package.json +4 -3
- package/prebuilt/win32-x64/reallink-cli.exe +0 -0
- package/rust/Cargo.lock +121 -1
- package/rust/Cargo.toml +4 -2
- package/rust/src/generated/contract.rs +52 -0
- package/rust/src/generated/mod.rs +1 -0
- package/rust/src/main.rs +2882 -246
- package/rust/src/unreal.rs +266 -0
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
use anyhow::Result;
|
|
2
|
+
use clap::{ArgAction, Args, Subcommand};
|
|
3
|
+
use serde::{Deserialize, Serialize};
|
|
4
|
+
use std::path::PathBuf;
|
|
5
|
+
|
|
6
|
+
const DEFAULT_UNREAL_PLUGIN_BASE_URL: &str = "https://real-agent.link/plugins/unreal";
|
|
7
|
+
|
|
8
|
+
#[derive(Debug, Serialize, Deserialize, Clone)]
|
|
9
|
+
#[serde(rename_all = "camelCase")]
|
|
10
|
+
pub(crate) struct UnrealLinkRecord {
|
|
11
|
+
pub project_id: String,
|
|
12
|
+
pub uproject_path: String,
|
|
13
|
+
pub project_root: String,
|
|
14
|
+
pub engine_root: Option<String>,
|
|
15
|
+
pub editor_path: String,
|
|
16
|
+
pub created_at_epoch_ms: u128,
|
|
17
|
+
pub updated_at_epoch_ms: u128,
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
#[derive(Debug, Serialize, Deserialize, Clone)]
|
|
21
|
+
#[serde(rename_all = "camelCase")]
|
|
22
|
+
pub(crate) struct UnrealLinksConfig {
|
|
23
|
+
pub version: u32,
|
|
24
|
+
pub default_project_id: Option<String>,
|
|
25
|
+
pub links: Vec<UnrealLinkRecord>,
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
impl Default for UnrealLinksConfig {
|
|
29
|
+
fn default() -> Self {
|
|
30
|
+
Self {
|
|
31
|
+
version: 1,
|
|
32
|
+
default_project_id: None,
|
|
33
|
+
links: Vec::new(),
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
#[derive(Debug, Serialize, Deserialize, Clone)]
|
|
39
|
+
#[serde(rename_all = "camelCase")]
|
|
40
|
+
pub(crate) struct PluginIndexFile {
|
|
41
|
+
pub schema_version: Option<u32>,
|
|
42
|
+
#[serde(default)]
|
|
43
|
+
pub plugins: Vec<PluginIndexPlugin>,
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
#[derive(Debug, Serialize, Deserialize, Clone)]
|
|
47
|
+
#[serde(rename_all = "camelCase")]
|
|
48
|
+
pub(crate) struct PluginIndexPlugin {
|
|
49
|
+
pub name: String,
|
|
50
|
+
pub latest: Option<String>,
|
|
51
|
+
#[serde(default)]
|
|
52
|
+
pub versions: Vec<PluginIndexVersion>,
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
#[derive(Debug, Serialize, Deserialize, Clone)]
|
|
56
|
+
#[serde(rename_all = "camelCase")]
|
|
57
|
+
pub(crate) struct PluginIndexVersion {
|
|
58
|
+
pub version: String,
|
|
59
|
+
pub archive_url: Option<String>,
|
|
60
|
+
pub sha256: Option<String>,
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
#[derive(Subcommand)]
|
|
64
|
+
pub(crate) enum LinkCommands {
|
|
65
|
+
Unreal(LinkUnrealArgs),
|
|
66
|
+
List,
|
|
67
|
+
Use(LinkUseArgs),
|
|
68
|
+
Doctor(LinkDoctorArgs),
|
|
69
|
+
Paths(LinkPathsArgs),
|
|
70
|
+
Remove(LinkRemoveArgs),
|
|
71
|
+
Open(LinkOpenArgs),
|
|
72
|
+
Run(LinkRunArgs),
|
|
73
|
+
Plugin {
|
|
74
|
+
#[command(subcommand)]
|
|
75
|
+
command: LinkPluginCommands,
|
|
76
|
+
},
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
#[derive(Subcommand)]
|
|
80
|
+
pub(crate) enum LinkPluginCommands {
|
|
81
|
+
Install(LinkPluginInstallArgs),
|
|
82
|
+
List(LinkPluginListArgs),
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
#[derive(Args)]
|
|
86
|
+
pub(crate) struct LinkUnrealArgs {
|
|
87
|
+
#[arg(long, help = "Remote Reallink project id to bind")]
|
|
88
|
+
pub project_id: String,
|
|
89
|
+
#[arg(long, help = "Path to .uproject file or a folder containing one")]
|
|
90
|
+
pub uproject: PathBuf,
|
|
91
|
+
#[arg(long, help = "Path to Unreal Engine root (contains Engine/)")]
|
|
92
|
+
pub engine_root: Option<PathBuf>,
|
|
93
|
+
#[arg(long, help = "Path to Unreal editor binary (UnrealEditor/UE4Editor)")]
|
|
94
|
+
pub editor: Option<PathBuf>,
|
|
95
|
+
#[arg(long, help = "Set this link as default for `reallink link open`")]
|
|
96
|
+
pub set_default: bool,
|
|
97
|
+
#[arg(long, help = "Skip remote project verification (useful when offline)")]
|
|
98
|
+
pub no_verify_remote: bool,
|
|
99
|
+
#[arg(
|
|
100
|
+
long,
|
|
101
|
+
help = "Sync a sanitized Unreal link manifest into project assets (.reallink/link/unreal-link.latest.json)"
|
|
102
|
+
)]
|
|
103
|
+
pub sync_project: bool,
|
|
104
|
+
#[arg(
|
|
105
|
+
long,
|
|
106
|
+
help = "When syncing project manifest, include full local paths (disabled by default)"
|
|
107
|
+
)]
|
|
108
|
+
pub include_local_paths: bool,
|
|
109
|
+
#[arg(long)]
|
|
110
|
+
pub base_url: Option<String>,
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
#[derive(Args)]
|
|
114
|
+
pub(crate) struct LinkUseArgs {
|
|
115
|
+
#[arg(long)]
|
|
116
|
+
pub project_id: String,
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
#[derive(Args)]
|
|
120
|
+
pub(crate) struct LinkRemoveArgs {
|
|
121
|
+
#[arg(long)]
|
|
122
|
+
pub project_id: Option<String>,
|
|
123
|
+
#[arg(long)]
|
|
124
|
+
pub uproject: Option<PathBuf>,
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
#[derive(Args)]
|
|
128
|
+
pub(crate) struct LinkOpenArgs {
|
|
129
|
+
#[arg(long)]
|
|
130
|
+
pub project_id: Option<String>,
|
|
131
|
+
#[arg(long)]
|
|
132
|
+
pub uproject: Option<PathBuf>,
|
|
133
|
+
#[arg(long, help = "Wait for Unreal process to exit")]
|
|
134
|
+
pub wait: bool,
|
|
135
|
+
#[arg(
|
|
136
|
+
long = "arg",
|
|
137
|
+
action = ArgAction::Append,
|
|
138
|
+
help = "Additional argument forwarded to Unreal editor"
|
|
139
|
+
)]
|
|
140
|
+
pub extra_arg: Vec<String>,
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
#[derive(Args)]
|
|
144
|
+
pub(crate) struct LinkRunArgs {
|
|
145
|
+
#[arg(long)]
|
|
146
|
+
pub project_id: Option<String>,
|
|
147
|
+
#[arg(long)]
|
|
148
|
+
pub uproject: Option<PathBuf>,
|
|
149
|
+
#[arg(long, help = "Commandlet name to execute via -run=<name>")]
|
|
150
|
+
pub commandlet: Option<String>,
|
|
151
|
+
#[arg(long, help = "Add Unreal -log flag")]
|
|
152
|
+
pub log: bool,
|
|
153
|
+
#[arg(
|
|
154
|
+
long,
|
|
155
|
+
help = "Add headless-friendly flags (-unattended -nop4 -nosplash -nullrhi)"
|
|
156
|
+
)]
|
|
157
|
+
pub headless: bool,
|
|
158
|
+
#[arg(long, help = "Do not wait for process exit")]
|
|
159
|
+
pub no_wait: bool,
|
|
160
|
+
#[arg(
|
|
161
|
+
long = "arg",
|
|
162
|
+
action = ArgAction::Append,
|
|
163
|
+
help = "Additional argument forwarded to Unreal editor"
|
|
164
|
+
)]
|
|
165
|
+
pub extra_arg: Vec<String>,
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
#[derive(Args)]
|
|
169
|
+
pub(crate) struct LinkDoctorArgs {
|
|
170
|
+
#[arg(long)]
|
|
171
|
+
pub project_id: Option<String>,
|
|
172
|
+
#[arg(long)]
|
|
173
|
+
pub uproject: Option<PathBuf>,
|
|
174
|
+
#[arg(
|
|
175
|
+
long,
|
|
176
|
+
help = "Verify linked project access against API using saved session"
|
|
177
|
+
)]
|
|
178
|
+
pub verify_remote: bool,
|
|
179
|
+
#[arg(long)]
|
|
180
|
+
pub base_url: Option<String>,
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
#[derive(Args)]
|
|
184
|
+
pub(crate) struct LinkPathsArgs {
|
|
185
|
+
#[arg(long)]
|
|
186
|
+
pub project_id: Option<String>,
|
|
187
|
+
#[arg(long)]
|
|
188
|
+
pub uproject: Option<PathBuf>,
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
#[derive(Args)]
|
|
192
|
+
pub(crate) struct LinkPluginInstallArgs {
|
|
193
|
+
#[arg(long, help = "Plugin name (also used for target folder name)")]
|
|
194
|
+
pub name: String,
|
|
195
|
+
#[arg(long, default_value = "latest", help = "Plugin version channel or tag")]
|
|
196
|
+
pub version: String,
|
|
197
|
+
#[arg(long, help = "Install against linked project id")]
|
|
198
|
+
pub project_id: Option<String>,
|
|
199
|
+
#[arg(long, help = "Install against linked uproject path")]
|
|
200
|
+
pub uproject: Option<PathBuf>,
|
|
201
|
+
#[arg(
|
|
202
|
+
long,
|
|
203
|
+
help = "Install into Engine/Plugins/Marketplace instead of Project/Plugins"
|
|
204
|
+
)]
|
|
205
|
+
pub engine: bool,
|
|
206
|
+
#[arg(long, help = "Overwrite existing plugin directory")]
|
|
207
|
+
pub force: bool,
|
|
208
|
+
#[arg(
|
|
209
|
+
long,
|
|
210
|
+
help = "Override full plugin zip URL. If omitted, URL is composed from --base-url/--name/--version"
|
|
211
|
+
)]
|
|
212
|
+
pub url: Option<String>,
|
|
213
|
+
#[arg(
|
|
214
|
+
long,
|
|
215
|
+
default_value = DEFAULT_UNREAL_PLUGIN_BASE_URL,
|
|
216
|
+
help = "Public plugin bucket base URL"
|
|
217
|
+
)]
|
|
218
|
+
pub base_url: String,
|
|
219
|
+
#[arg(
|
|
220
|
+
long,
|
|
221
|
+
help = "Resolve plugin version/url from plugin index instead of using URL template"
|
|
222
|
+
)]
|
|
223
|
+
pub use_index: bool,
|
|
224
|
+
#[arg(
|
|
225
|
+
long,
|
|
226
|
+
default_value = "index.json",
|
|
227
|
+
help = "Plugin index path under base URL (used with --use-index)"
|
|
228
|
+
)]
|
|
229
|
+
pub index_path: String,
|
|
230
|
+
#[arg(long, help = "Expected SHA-256 hex for downloaded plugin zip")]
|
|
231
|
+
pub sha256: Option<String>,
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
#[derive(Args)]
|
|
235
|
+
pub(crate) struct LinkPluginListArgs {
|
|
236
|
+
#[arg(
|
|
237
|
+
long,
|
|
238
|
+
default_value = DEFAULT_UNREAL_PLUGIN_BASE_URL,
|
|
239
|
+
help = "Public plugin bucket base URL"
|
|
240
|
+
)]
|
|
241
|
+
pub base_url: String,
|
|
242
|
+
#[arg(
|
|
243
|
+
long,
|
|
244
|
+
default_value = "index.json",
|
|
245
|
+
help = "Plugin index path under base URL"
|
|
246
|
+
)]
|
|
247
|
+
pub index_path: String,
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
pub(crate) async fn dispatch(client: &reqwest::Client, command: LinkCommands) -> Result<()> {
|
|
251
|
+
match command {
|
|
252
|
+
LinkCommands::Unreal(args) => crate::link_unreal_command(client, args).await?,
|
|
253
|
+
LinkCommands::List => crate::link_list_command().await?,
|
|
254
|
+
LinkCommands::Use(args) => crate::link_use_command(args).await?,
|
|
255
|
+
LinkCommands::Doctor(args) => crate::link_doctor_command(client, args).await?,
|
|
256
|
+
LinkCommands::Paths(args) => crate::link_paths_command(args).await?,
|
|
257
|
+
LinkCommands::Remove(args) => crate::link_remove_command(args).await?,
|
|
258
|
+
LinkCommands::Open(args) => crate::link_open_command(args).await?,
|
|
259
|
+
LinkCommands::Run(args) => crate::link_run_command(args).await?,
|
|
260
|
+
LinkCommands::Plugin { command } => match command {
|
|
261
|
+
LinkPluginCommands::Install(args) => crate::link_plugin_install_command(client, args).await?,
|
|
262
|
+
LinkPluginCommands::List(args) => crate::link_plugin_list_command(client, args).await?,
|
|
263
|
+
},
|
|
264
|
+
}
|
|
265
|
+
Ok(())
|
|
266
|
+
}
|