@pheem49/mint 1.9.0 → 1.10.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.
- package/Cargo.lock +55 -3
- package/Cargo.toml +2 -1
- package/Release_Note.md +285 -140
- package/bin/mint +0 -0
- package/crates/mint-cli/Cargo.toml +1 -0
- package/crates/mint-cli/src/actions.rs +233 -0
- package/crates/mint-cli/src/agent.rs +287 -43
- package/crates/mint-cli/src/gmail.rs +22 -2
- package/crates/mint-cli/src/interactive.rs +2888 -0
- package/crates/mint-cli/src/main.rs +336 -2854
- package/crates/mint-cli/src/markdown.rs +294 -0
- package/crates/mint-cli/src/onboard.rs +44 -1
- package/crates/mint-cli/src/updater.rs +48 -6
- package/crates/mint-core/Cargo.toml +1 -0
- package/crates/mint-core/src/agent_loop.rs +1 -0
- package/crates/mint-core/src/api_server.rs +376 -13
- package/crates/mint-core/src/browser.rs +629 -101
- package/crates/mint-core/src/channels.rs +105 -6
- package/crates/mint-core/src/chat.rs +52 -4
- package/crates/mint-core/src/code_tools.rs +29 -11
- package/crates/mint-core/src/config.rs +118 -0
- package/crates/mint-core/src/image_gen.rs +294 -33
- package/crates/mint-core/src/lib.rs +5 -2
- package/crates/mint-core/src/mcp.rs +119 -6
- package/crates/mint-core/src/orchestration.rs +133 -11
- package/crates/mint-core/src/pictures.rs +64 -1
- package/crates/mint-core/src/skills.rs +82 -6
- package/crates/mint-core/src/video_gen.rs +235 -0
- package/package.json +8 -2
- package/shared-modules/luajit/luajit.json +2 -2
- package/skills-lock.json +41 -0
- package/src/renderer/index-web.html +1 -1
- package/src/renderer/index.html +1 -1
- package/src/renderer/shared/constants/slashCommands.ts +27 -0
- package/src/renderer/shared/platform.ts +3 -0
- package/src/renderer/shared/types.ts +4 -0
- package/src/renderer/shared/utils/approval.tsx +86 -7
- package/src/renderer/shared/utils/markdown.tsx +217 -88
- package/src/renderer/shared/utils/slashCommandProcessor.ts +239 -0
- package/src/renderer/src/components/ChatPanel.tsx +461 -64
- package/src/renderer/src/components/DashboardSidebar.tsx +11 -2
- package/src/renderer/src/components/ImageStudioPanel.tsx +87 -4
- package/src/renderer/src/components/MintDashboard.tsx +150 -5
- package/src/renderer/src/components/PicturesLibrary.tsx +156 -15
- package/src/renderer/src/components/Settings/AutomationTab.tsx +316 -18
- package/src/renderer/src/components/Settings/GeneralTab.tsx +762 -634
- package/src/renderer/src/components/Settings/PluginsTab.tsx +304 -70
- package/src/renderer/src/components/Settings/ThemeTab.tsx +6 -1
- package/src/renderer/src/components/SettingsWindow.tsx +38 -2
- package/src/renderer/src/components/VeoStudioPanel.tsx +549 -0
- package/src/renderer/src/css/image-studio.css +106 -0
- package/src/renderer/src/css/settings.css +158 -0
- package/src/renderer/src/css/styles.css +352 -1
- package/src/renderer/src/css/veo-studio.css +626 -0
- package/src/renderer/src/index.css +1 -0
- package/src/renderer/src/tauri.ts +144 -17
- package/src/renderer/src-web/components/ChatPanel.tsx +360 -88
- package/src/renderer/src-web/components/DashboardSidebar.tsx +16 -1
- package/src/renderer/src-web/components/ImageStudioPanel.tsx +87 -4
- package/src/renderer/src-web/components/MintDashboard.tsx +137 -4
- package/src/renderer/src-web/components/PicturesLibrary.tsx +155 -15
- package/src/renderer/src-web/components/Settings/AutomationTab.tsx +316 -18
- package/src/renderer/src-web/components/Settings/GeneralTab.tsx +762 -629
- package/src/renderer/src-web/components/Settings/PluginsTab.tsx +304 -70
- package/src/renderer/src-web/components/Settings/ThemeTab.tsx +6 -1
- package/src/renderer/src-web/components/SettingsWindow.tsx +35 -2
- package/src/renderer/src-web/components/VeoStudioPanel.tsx +549 -0
- package/src/renderer/src-web/css/image-studio.css +106 -0
- package/src/renderer/src-web/css/settings.css +158 -0
- package/src/renderer/src-web/css/styles.css +353 -1
- package/src/renderer/src-web/css/veo-studio.css +650 -0
- package/src/renderer/src-web/index.css +1 -0
- package/src/renderer/src-web/tauri.ts +135 -16
- package/src-tauri/src/lib.rs +114 -8
- package/src-tauri/src/webhooks.rs +45 -31
- package/src-tauri/src/workflows.rs +1 -0
- package/src-tauri/tauri.conf.json +1 -1
- package/temp_gridgeist/AGENTS.md +8 -0
- package/temp_gridgeist/CHANGELOG.md +130 -0
- package/temp_gridgeist/LICENSE +21 -0
- package/temp_gridgeist/README.md +323 -0
- package/temp_gridgeist/README.th.md +325 -0
- package/temp_gridgeist/skills/gridgeist/SKILL.md +88 -0
- package/temp_gridgeist/skills/gridgeist/agents/openai.yaml +9 -0
- package/temp_gridgeist/skills/gridgeist/assets/gridgeist-small.svg +10 -0
- package/temp_gridgeist/skills/gridgeist/assets/gridgeist.png +0 -0
- package/temp_gridgeist/skills/gridgeist/assets/gridgeist.svg +18 -0
- package/temp_gridgeist/skills/gridgeist/references/design-language.md +88 -0
- package/temp_gridgeist/skills/gridgeist/references/review-checklist.md +128 -0
- package/temp_gridgeist/skills/gridgeist/references/system-contract.md +109 -0
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
pub fn is_table_line(line: &str) -> bool {
|
|
2
|
+
let trimmed = line.trim();
|
|
3
|
+
trimmed.starts_with('|') && trimmed.ends_with('|') && trimmed.len() > 1
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
pub fn process_inline_bold(s: &str) -> String {
|
|
7
|
+
let mut result = String::new();
|
|
8
|
+
let parts = s.split("**");
|
|
9
|
+
let mut is_bold = false;
|
|
10
|
+
for part in parts {
|
|
11
|
+
if is_bold {
|
|
12
|
+
result.push_str("\x1b[1m");
|
|
13
|
+
result.push_str(part);
|
|
14
|
+
result.push_str("\x1b[0m");
|
|
15
|
+
} else {
|
|
16
|
+
result.push_str(part);
|
|
17
|
+
}
|
|
18
|
+
is_bold = !is_bold;
|
|
19
|
+
}
|
|
20
|
+
result
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
pub fn format_line(line: &str) -> String {
|
|
24
|
+
let mut formatted = line.to_string();
|
|
25
|
+
let trimmed = line.trim_start();
|
|
26
|
+
if (trimmed.starts_with("- ") || trimmed.starts_with("* ") || trimmed.starts_with("+ "))
|
|
27
|
+
&& trimmed.len() >= 2
|
|
28
|
+
{
|
|
29
|
+
let leading_len = line.len() - trimmed.len();
|
|
30
|
+
let leading_spaces = &line[..leading_len];
|
|
31
|
+
formatted = format!("{}•{}", leading_spaces, &trimmed[1..]);
|
|
32
|
+
}
|
|
33
|
+
process_inline_bold(&formatted)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
pub fn unicode_width(s: &str) -> usize {
|
|
37
|
+
let mut count = 0;
|
|
38
|
+
for c in s.chars() {
|
|
39
|
+
let val = c as u32;
|
|
40
|
+
if (0x0E31..=0x0E31).contains(&val)
|
|
41
|
+
|| (0x0E34..=0x0E3A).contains(&val)
|
|
42
|
+
|| (0x0E47..=0x0E4E).contains(&val)
|
|
43
|
+
{
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
if is_cjk(c) {
|
|
47
|
+
count += 2;
|
|
48
|
+
} else {
|
|
49
|
+
count += 1;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
count
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
pub fn is_cjk(c: char) -> bool {
|
|
56
|
+
let val = c as u32;
|
|
57
|
+
(0x4E00..=0x9FFF).contains(&val)
|
|
58
|
+
|| (0x3400..=0x4DBF).contains(&val)
|
|
59
|
+
|| (0x20000..=0x2A6DF).contains(&val)
|
|
60
|
+
|| (0xAC00..=0xD7AF).contains(&val)
|
|
61
|
+
|| (0x3040..=0x309F).contains(&val)
|
|
62
|
+
|| (0x30A0..=0x30FF).contains(&val)
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
pub fn render_markdown_table(table_lines: &[String]) -> String {
|
|
66
|
+
let mut rows: Vec<Vec<String>> = Vec::new();
|
|
67
|
+
for line in table_lines {
|
|
68
|
+
let trimmed = line.trim();
|
|
69
|
+
if trimmed.is_empty() {
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
72
|
+
let content = &trimmed[1..trimmed.len() - 1];
|
|
73
|
+
let content_escaped = content.replace("\\|", "\u{0000}");
|
|
74
|
+
let cols: Vec<String> = content_escaped
|
|
75
|
+
.split('|')
|
|
76
|
+
.map(|s| s.replace("\u{0000}", "|").trim().to_string())
|
|
77
|
+
.collect();
|
|
78
|
+
rows.push(cols);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if rows.is_empty() {
|
|
82
|
+
return String::new();
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
let mut has_separator = false;
|
|
86
|
+
let mut separator_idx = None;
|
|
87
|
+
for (i, row) in rows.iter().enumerate() {
|
|
88
|
+
if row.iter().all(|col| {
|
|
89
|
+
col.chars()
|
|
90
|
+
.all(|c| c == '-' || c == ':' || c == ' ' || c == '\t')
|
|
91
|
+
}) && !row.is_empty()
|
|
92
|
+
{
|
|
93
|
+
has_separator = true;
|
|
94
|
+
separator_idx = Some(i);
|
|
95
|
+
break;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
let mut data_rows: Vec<Vec<String>> = Vec::new();
|
|
100
|
+
let mut header_row: Option<Vec<String>> = None;
|
|
101
|
+
|
|
102
|
+
if has_separator {
|
|
103
|
+
let sep_idx = separator_idx.unwrap();
|
|
104
|
+
if sep_idx > 0 {
|
|
105
|
+
header_row = Some(rows[sep_idx - 1].clone());
|
|
106
|
+
for (i, row) in rows.iter().enumerate() {
|
|
107
|
+
if i != sep_idx && i != sep_idx - 1 {
|
|
108
|
+
data_rows.push(row.clone());
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
} else {
|
|
112
|
+
for (i, row) in rows.iter().enumerate() {
|
|
113
|
+
if i != sep_idx {
|
|
114
|
+
data_rows.push(row.clone());
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
} else {
|
|
119
|
+
header_row = Some(rows[0].clone());
|
|
120
|
+
data_rows = rows[1..].to_vec();
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
let num_cols = rows.iter().map(|r| r.len()).max().unwrap_or(0);
|
|
124
|
+
let mut col_widths = vec![0; num_cols];
|
|
125
|
+
|
|
126
|
+
if let Some(ref header) = header_row {
|
|
127
|
+
for (i, col) in header.iter().enumerate() {
|
|
128
|
+
if i < num_cols {
|
|
129
|
+
col_widths[i] = col_widths[i].max(unicode_width(col));
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
for row in &data_rows {
|
|
134
|
+
for (i, col) in row.iter().enumerate() {
|
|
135
|
+
if i < num_cols {
|
|
136
|
+
col_widths[i] = col_widths[i].max(unicode_width(col));
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
let mut rendered = String::new();
|
|
142
|
+
|
|
143
|
+
let draw_border =
|
|
144
|
+
|left: &str, mid: &str, right: &str, fill: &str, widths: &[usize]| -> String {
|
|
145
|
+
let mut s = left.to_string();
|
|
146
|
+
for (i, &w) in widths.iter().enumerate() {
|
|
147
|
+
s.push_str(&fill.repeat(w + 2));
|
|
148
|
+
if i < widths.len() - 1 {
|
|
149
|
+
s.push_str(mid);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
s.push_str(right);
|
|
153
|
+
s.push('\n');
|
|
154
|
+
s
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
rendered.push_str(&draw_border("┌", "┬", "┐", "─", &col_widths));
|
|
158
|
+
|
|
159
|
+
if let Some(ref header) = header_row {
|
|
160
|
+
rendered.push('│');
|
|
161
|
+
for (i, col) in header.iter().enumerate() {
|
|
162
|
+
let width = unicode_width(col);
|
|
163
|
+
let padding = col_widths[i] - width;
|
|
164
|
+
rendered.push_str(&format!(
|
|
165
|
+
" \x1b[1;36m{}\x1b[0m{}",
|
|
166
|
+
col,
|
|
167
|
+
" ".repeat(padding + 1)
|
|
168
|
+
));
|
|
169
|
+
rendered.push('│');
|
|
170
|
+
}
|
|
171
|
+
rendered.push('\n');
|
|
172
|
+
rendered.push_str(&draw_border("├", "┼", "┤", "─", &col_widths));
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
for (r_idx, row) in data_rows.iter().enumerate() {
|
|
176
|
+
rendered.push('│');
|
|
177
|
+
for i in 0..num_cols {
|
|
178
|
+
let col_val = row.get(i).cloned().unwrap_or_default();
|
|
179
|
+
let width = unicode_width(&col_val);
|
|
180
|
+
let padding = col_widths[i] - width;
|
|
181
|
+
rendered.push_str(&format!(" {}{}", col_val, " ".repeat(padding + 1)));
|
|
182
|
+
rendered.push('│');
|
|
183
|
+
}
|
|
184
|
+
rendered.push('\n');
|
|
185
|
+
|
|
186
|
+
if r_idx < data_rows.len() - 1 {
|
|
187
|
+
rendered.push_str(&draw_border("├", "┼", "┤", "─", &col_widths));
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
rendered.push_str(draw_border("└", "┴", "┘", "─", &col_widths).trim_end());
|
|
192
|
+
rendered
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
pub struct CliStreamFormatter {
|
|
196
|
+
line_buffer: String,
|
|
197
|
+
table_buffer: Vec<String>,
|
|
198
|
+
in_code_block: bool,
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
impl CliStreamFormatter {
|
|
202
|
+
pub fn new() -> Self {
|
|
203
|
+
Self {
|
|
204
|
+
line_buffer: String::new(),
|
|
205
|
+
table_buffer: Vec::new(),
|
|
206
|
+
in_code_block: false,
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
pub fn process_char(&mut self, c: char, mut print_fn: impl FnMut(char)) {
|
|
211
|
+
self.line_buffer.push(c);
|
|
212
|
+
if c == '\n' {
|
|
213
|
+
let mut line = self.line_buffer.clone();
|
|
214
|
+
self.line_buffer.clear();
|
|
215
|
+
if line.ends_with('\n') {
|
|
216
|
+
line.pop();
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
let trimmed = line.trim();
|
|
220
|
+
if trimmed.starts_with("```") {
|
|
221
|
+
self.in_code_block = !self.in_code_block;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
if self.in_code_block {
|
|
225
|
+
if !self.table_buffer.is_empty() {
|
|
226
|
+
self.flush_table(&mut print_fn);
|
|
227
|
+
}
|
|
228
|
+
for ch in line.chars() {
|
|
229
|
+
print_fn(ch);
|
|
230
|
+
}
|
|
231
|
+
print_fn('\n');
|
|
232
|
+
for ch in " ".chars() {
|
|
233
|
+
print_fn(ch);
|
|
234
|
+
}
|
|
235
|
+
} else {
|
|
236
|
+
if is_table_line(&line) {
|
|
237
|
+
self.table_buffer.push(line);
|
|
238
|
+
} else {
|
|
239
|
+
if !self.table_buffer.is_empty() {
|
|
240
|
+
self.flush_table(&mut print_fn);
|
|
241
|
+
}
|
|
242
|
+
let formatted = format_line(&line);
|
|
243
|
+
for ch in formatted.chars() {
|
|
244
|
+
print_fn(ch);
|
|
245
|
+
}
|
|
246
|
+
print_fn('\n');
|
|
247
|
+
for ch in " ".chars() {
|
|
248
|
+
print_fn(ch);
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
pub fn finalize(&mut self, mut print_fn: impl FnMut(char)) {
|
|
256
|
+
if !self.line_buffer.is_empty() {
|
|
257
|
+
let mut line = self.line_buffer.clone();
|
|
258
|
+
self.line_buffer.clear();
|
|
259
|
+
if line.ends_with('\n') {
|
|
260
|
+
line.pop();
|
|
261
|
+
}
|
|
262
|
+
if self.in_code_block {
|
|
263
|
+
if !self.table_buffer.is_empty() {
|
|
264
|
+
self.flush_table(&mut print_fn);
|
|
265
|
+
}
|
|
266
|
+
for ch in line.chars() {
|
|
267
|
+
print_fn(ch);
|
|
268
|
+
}
|
|
269
|
+
} else if is_table_line(&line) {
|
|
270
|
+
self.table_buffer.push(line);
|
|
271
|
+
} else {
|
|
272
|
+
if !self.table_buffer.is_empty() {
|
|
273
|
+
self.flush_table(&mut print_fn);
|
|
274
|
+
}
|
|
275
|
+
let formatted = format_line(&line);
|
|
276
|
+
for ch in formatted.chars() {
|
|
277
|
+
print_fn(ch);
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
if !self.table_buffer.is_empty() {
|
|
282
|
+
self.flush_table(&mut print_fn);
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
fn flush_table<F: FnMut(char)>(&mut self, mut print_fn: F) {
|
|
287
|
+
let rendered = render_markdown_table(&self.table_buffer);
|
|
288
|
+
for ch in rendered.chars() {
|
|
289
|
+
print_fn(ch);
|
|
290
|
+
}
|
|
291
|
+
print_fn('\n');
|
|
292
|
+
self.table_buffer.clear();
|
|
293
|
+
}
|
|
294
|
+
}
|
|
@@ -75,9 +75,11 @@ const REPLICATE_MODEL_PRESETS: &[&str] = &[
|
|
|
75
75
|
"black-forest-labs/flux-1.1-pro",
|
|
76
76
|
"black-forest-labs/flux-schnell",
|
|
77
77
|
"stability-ai/sdxl",
|
|
78
|
-
"bytedance/sdxl-lightning-4step",
|
|
79
78
|
];
|
|
80
79
|
|
|
80
|
+
// ── Video Generation Providers ──────────────────────────────────────────────
|
|
81
|
+
const VEO_VIDEO_MODEL_PRESETS: &[&str] = &["veo-2.0-generate-001", "veo-2.0-flash-001"];
|
|
82
|
+
|
|
81
83
|
pub async fn run() -> Result<()> {
|
|
82
84
|
let mut config = load_config()?;
|
|
83
85
|
|
|
@@ -280,6 +282,19 @@ pub async fn run() -> Result<()> {
|
|
|
280
282
|
key: "img_replicate",
|
|
281
283
|
enabled: !config.replicate_api_key.is_empty(),
|
|
282
284
|
},
|
|
285
|
+
// ── Video Generation ─────────────────────────────────────────────────
|
|
286
|
+
OnboardService {
|
|
287
|
+
category: "Video Generation",
|
|
288
|
+
name: "Google Veo (Gemini Videos) [uses Gemini key]",
|
|
289
|
+
key: "vid_veo",
|
|
290
|
+
enabled: !config.api_key.is_empty()
|
|
291
|
+
&& config
|
|
292
|
+
.extra
|
|
293
|
+
.get("veoModel")
|
|
294
|
+
.and_then(|v| v.as_str())
|
|
295
|
+
.map(|s| !s.is_empty())
|
|
296
|
+
.unwrap_or(false),
|
|
297
|
+
},
|
|
283
298
|
];
|
|
284
299
|
|
|
285
300
|
let mut cursor = 0;
|
|
@@ -976,6 +991,34 @@ pub async fn run() -> Result<()> {
|
|
|
976
991
|
config.replicate_api_key = String::new();
|
|
977
992
|
}
|
|
978
993
|
|
|
994
|
+
// Google Veo (Gemini Videos)
|
|
995
|
+
if is_selected("vid_veo", &services) {
|
|
996
|
+
println!("\n\x1b[36m--- Google Veo (Gemini Videos) ---\x1b[0m");
|
|
997
|
+
println!(
|
|
998
|
+
"\x1b[90mUses the same Gemini API key as Step 1. Select the video generation model.\x1b[0m"
|
|
999
|
+
);
|
|
1000
|
+
let current_veo_model = config
|
|
1001
|
+
.extra
|
|
1002
|
+
.get("veoModel")
|
|
1003
|
+
.and_then(|v| v.as_str())
|
|
1004
|
+
.unwrap_or("veo-2.0-generate-001")
|
|
1005
|
+
.to_string();
|
|
1006
|
+
let selected_veo_model = prompt_select_or_custom(
|
|
1007
|
+
"Veo Model",
|
|
1008
|
+
static_model_options(VEO_VIDEO_MODEL_PRESETS),
|
|
1009
|
+
Some(¤t_veo_model),
|
|
1010
|
+
"Custom Veo model...",
|
|
1011
|
+
)?;
|
|
1012
|
+
config.extra.insert(
|
|
1013
|
+
"veoModel".to_string(),
|
|
1014
|
+
serde_json::Value::String(selected_veo_model),
|
|
1015
|
+
);
|
|
1016
|
+
config.extra.insert(
|
|
1017
|
+
"videoGenProvider".to_string(),
|
|
1018
|
+
serde_json::Value::String("veo".to_string()),
|
|
1019
|
+
);
|
|
1020
|
+
}
|
|
1021
|
+
|
|
979
1022
|
save_config(&config)?;
|
|
980
1023
|
println!("\x1b[32m✅ Configuration saved successfully!\x1b[0m");
|
|
981
1024
|
Ok(())
|
|
@@ -2,16 +2,41 @@ use std::path::PathBuf;
|
|
|
2
2
|
use std::process::Command;
|
|
3
3
|
use std::time::{SystemTime, UNIX_EPOCH};
|
|
4
4
|
|
|
5
|
-
use anyhow::{
|
|
5
|
+
use anyhow::{Result, bail};
|
|
6
6
|
|
|
7
7
|
const PACKAGE: &str = "@pheem49/mint";
|
|
8
8
|
|
|
9
9
|
pub fn run(check_only: bool, dry_run: bool, approved: bool) -> Result<()> {
|
|
10
10
|
let current = env!("CARGO_PKG_VERSION");
|
|
11
|
+
|
|
12
|
+
use indicatif::{ProgressBar, ProgressStyle};
|
|
13
|
+
use std::time::Duration;
|
|
14
|
+
|
|
15
|
+
let spinner = ProgressBar::new_spinner();
|
|
16
|
+
spinner.set_style(
|
|
17
|
+
ProgressStyle::default_spinner()
|
|
18
|
+
.tick_chars("⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏")
|
|
19
|
+
.template("{spinner:.green} {msg}")
|
|
20
|
+
.unwrap(),
|
|
21
|
+
);
|
|
22
|
+
spinner.set_message("Checking for updates...");
|
|
23
|
+
spinner.enable_steady_tick(Duration::from_millis(80));
|
|
24
|
+
|
|
11
25
|
let output = Command::new(npm())
|
|
12
26
|
.args(["view", PACKAGE, "version", "--json"])
|
|
13
|
-
.output()
|
|
14
|
-
|
|
27
|
+
.output();
|
|
28
|
+
|
|
29
|
+
let output = match output {
|
|
30
|
+
Ok(out) => {
|
|
31
|
+
spinner.finish_and_clear();
|
|
32
|
+
out
|
|
33
|
+
}
|
|
34
|
+
Err(e) => {
|
|
35
|
+
spinner.finish_and_clear();
|
|
36
|
+
bail!("unable to run npm update check: {}", e);
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
|
|
15
40
|
if !output.status.success() {
|
|
16
41
|
bail!(
|
|
17
42
|
"npm update check failed: {}",
|
|
@@ -34,14 +59,31 @@ pub fn run(check_only: bool, dry_run: bool, approved: bool) -> Result<()> {
|
|
|
34
59
|
if !approved {
|
|
35
60
|
bail!("update installation requires --approve");
|
|
36
61
|
}
|
|
62
|
+
|
|
63
|
+
let spinner = ProgressBar::new_spinner();
|
|
64
|
+
spinner.set_style(
|
|
65
|
+
ProgressStyle::default_spinner()
|
|
66
|
+
.tick_chars("⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏")
|
|
67
|
+
.template("{spinner:.green} {msg}")
|
|
68
|
+
.unwrap(),
|
|
69
|
+
);
|
|
70
|
+
spinner.set_message(format!("Updating to {latest} via npm..."));
|
|
71
|
+
spinner.enable_steady_tick(Duration::from_millis(80));
|
|
72
|
+
|
|
37
73
|
let mut command = Command::new(npm());
|
|
38
74
|
command.args(["install", "-g", &format!("{PACKAGE}@latest")]);
|
|
39
75
|
if dry_run {
|
|
40
76
|
command.arg("--dry-run");
|
|
41
77
|
}
|
|
42
|
-
let status = command
|
|
43
|
-
|
|
44
|
-
|
|
78
|
+
let status = command.status();
|
|
79
|
+
spinner.finish_and_clear();
|
|
80
|
+
|
|
81
|
+
let status = match status {
|
|
82
|
+
Ok(s) => s,
|
|
83
|
+
Err(e) => {
|
|
84
|
+
bail!("unable to run npm global update: {}", e);
|
|
85
|
+
}
|
|
86
|
+
};
|
|
45
87
|
if !status.success() {
|
|
46
88
|
bail!("npm global update failed with status {status}");
|
|
47
89
|
}
|