secrez 2.1.13 → 2.1.15

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 CHANGED
@@ -368,6 +368,15 @@ Secrez is not intended to compete with password managers, so do not expect it to
368
368
 
369
369
  ## History
370
370
 
371
+ **2.1.15**
372
+
373
+ - add `find -R` to look for recent entries only. With `-l` to set a limit (default 10)
374
+
375
+ **2.1.14**
376
+
377
+ - reverse changes done in version 2.1.12
378
+ - add a push option to Git that checks if there are changes in the repo and, if so, pushes them remotely, updating the system
379
+
371
380
  **2.1.12**
372
381
 
373
382
  - enforce the usage of pnpm during global install. When that is not possible, for example with yarn, it blocks the execution asking the user to uninstall and install it again properly
@@ -892,60 +901,60 @@ Thank you for any contributions! 😉
892
901
  ## Test coverage
893
902
 
894
903
  ```
895
- 162 passing (2m)
896
-
897
- --------------------|---------|----------|---------|---------|--------------------------------------
898
- File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
899
- --------------------|---------|----------|---------|---------|--------------------------------------
900
- All files | 81.62 | 68.94 | 83.57 | 81.53 |
901
- src | 57.62 | 53.75 | 55 | 58.11 |
902
- Command.js | 74.66 | 74.13 | 78.57 | 75.67 | ...5-62,73,80,93,127,164-172,179-182
903
- PreCommand.js | 8.82 | 0 | 0 | 8.82 | 6-97
904
- cliConfig.js | 100 | 100 | 100 | 100 |
905
- src/commands | 83.01 | 69.34 | 90.82 | 82.89 |
906
- Alias.js | 88.6 | 78.68 | 100 | 88.46 | 101,112,139,169,173,180,190,213-214
907
- Bash.js | 75 | 0 | 66.66 | 75 | 18-19
908
- Cat.js | 98.91 | 88.88 | 100 | 98.91 | 152
909
- Cd.js | 96.42 | 86.66 | 100 | 96.42 | 44
910
- Conf.js | 8.64 | 0 | 20 | 8.64 | 47-216
911
- Contacts.js | 86.06 | 75.6 | 100 | 85.95 | ...5,165,172,184,237,250,260,268-269
912
- Copy.js | 91.2 | 71.92 | 100 | 91.11 | 115,166,183,205-210,225-226,253
913
- Ds.js | 90.27 | 82.6 | 100 | 90.14 | 99,108-113,125,147-148
914
- Edit.js | 12.94 | 0 | 40 | 12.94 | 88-222
915
- Export.js | 90.17 | 76.92 | 100 | 90.17 | ...3-198,209,227-231,236,248,257,260
916
- Find.js | 93.58 | 86.66 | 100 | 93.42 | 101,164,200-203,209
917
- Git.js | 92.3 | 66.66 | 100 | 92.3 | 40,61
918
- Help.js | 100 | 80 | 100 | 100 | 29
919
- Import.js | 92.41 | 85.38 | 100 | 92.34 | ...7,387,393,441,457-458,466-473,500
920
- Lcat.js | 100 | 85.71 | 100 | 100 | 54
921
- Lcd.js | 95.65 | 81.81 | 100 | 95.65 | 50
922
- Lls.js | 95.45 | 72.72 | 100 | 95.45 | 97
923
- Lpwd.js | 92.3 | 100 | 100 | 92.3 | 36
924
- Ls.js | 91.54 | 76.31 | 100 | 91.04 | 103,114-116,130,185
925
- Mkdir.js | 92.59 | 60 | 100 | 92.59 | 56-57
926
- Mv.js | 86.59 | 71.66 | 100 | 86.31 | 93-99,133,155-156,165,175-182
927
- Paste.js | 84.61 | 70.83 | 100 | 84.61 | 72,78,81,89,113,130-131,139
928
- Pwd.js | 92.3 | 100 | 100 | 92.3 | 33
929
- Quit.js | 90 | 50 | 100 | 90 | 27
930
- Rm.js | 90.9 | 76 | 100 | 90.74 | 63,125-126,136,144
931
- Shell.js | 88.23 | 60 | 100 | 88.23 | 38,55
932
- Show.js | 72.54 | 45.45 | 57.14 | 74 | ...8,100,106-114,117,123-126,132,145
933
- Ssh.js | 25 | 0 | 40 | 25 | 72-120
934
- Tag.js | 96.26 | 91.37 | 100 | 96.22 | 122,171,204-205
935
- Totp.js | 92.23 | 75 | 100 | 92.23 | 189-190,230,240,282-287,301-302
936
- Touch.js | 96.36 | 80.64 | 100 | 96.29 | 164,240
937
- Use.js | 91.66 | 86.95 | 100 | 91.66 | 68,83-84
938
- Ver.js | 90 | 66.66 | 100 | 90 | 25
939
- Whoami.js | 83.33 | 60 | 80 | 83.33 | 27,35,48
940
- index.js | 87.5 | 50 | 100 | 86.95 | 15,22,31
941
- src/prompts | 75 | 33.33 | 50 | 75 |
942
- MainPromptMock.js | 75 | 33.33 | 50 | 75 | 29-35,44
943
- src/utils | 83.07 | 78.43 | 66.66 | 82.81 |
944
- AliasManager.js | 100 | 91.66 | 100 | 100 | 47
945
- ContactManager.js | 73.33 | 60 | 85.71 | 73.33 | 12,34-36
946
- HelpProto.js | 89.07 | 82.6 | 100 | 88.88 | 49,135-137,153-154,171-176,195
947
- Logger.js | 63.63 | 56.25 | 36.84 | 62.79 | ...25,37-49,57,65-69,74,84,88,93,105
948
- --------------------|---------|----------|---------|---------|--------------------------------------
904
+ 1 passing (15s)
905
+
906
+ --------------------|---------|----------|---------|---------|----------------------------------
907
+ File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
908
+ --------------------|---------|----------|---------|---------|----------------------------------
909
+ All files | 14.72 | 2.34 | 17.88 | 14.78 |
910
+ src | 25.42 | 6.25 | 15 | 25.64 |
911
+ Command.js | 24 | 8.62 | 21.42 | 24.32 | 22-35,40-110,116,127,130-182
912
+ PreCommand.js | 8.82 | 0 | 0 | 8.82 | 6-97
913
+ cliConfig.js | 100 | 100 | 100 | 100 |
914
+ src/commands | 13.44 | 1.7 | 19.32 | 13.52 |
915
+ Alias.js | 7.59 | 0 | 25 | 7.69 | 62-228
916
+ Bash.js | 62.5 | 0 | 33.33 | 62.5 | 11-19
917
+ Cat.js | 11.95 | 0 | 14.28 | 11.95 | 61-222
918
+ Cd.js | 17.85 | 0 | 25 | 17.85 | 28-73
919
+ Conf.js | 7.4 | 0 | 10 | 7.4 | 34-216
920
+ Contacts.js | 5.73 | 0 | 7.69 | 5.78 | 53-284
921
+ Copy.js | 10.98 | 0 | 12.5 | 11.11 | 71-268
922
+ Ds.js | 5.55 | 0 | 16.66 | 5.63 | 39-170
923
+ Edit.js | 11.76 | 0 | 20 | 11.76 | 61-222
924
+ Export.js | 9.82 | 0 | 16.66 | 9.82 | 82-325
925
+ Find.js | 7.69 | 0 | 8.33 | 7.89 | 63-211
926
+ Git.js | 48.88 | 35.71 | 75 | 48.88 | 31,49-54,61,70-97,103,108,114
927
+ Help.js | 33.33 | 0 | 50 | 33.33 | 26-43
928
+ Import.js | 6.16 | 0 | 9.09 | 6.22 | 87-506
929
+ Lcat.js | 30 | 0 | 25 | 30 | 35-65
930
+ Lcd.js | 17.39 | 0 | 25 | 17.39 | 30-72
931
+ Lls.js | 22.72 | 0 | 25 | 22.72 | 49-99
932
+ Lpwd.js | 30.76 | 0 | 25 | 30.76 | 15-38
933
+ Ls.js | 5.63 | 0 | 10 | 5.97 | 46-187
934
+ Mkdir.js | 18.51 | 0 | 25 | 18.51 | 27-71
935
+ Mv.js | 6.18 | 0 | 16.66 | 6.31 | 46-250
936
+ Paste.js | 13.46 | 0 | 25 | 13.46 | 40-141
937
+ Pwd.js | 30.76 | 0 | 25 | 30.76 | 15-35
938
+ Quit.js | 50 | 0 | 33.33 | 50 | 19-40
939
+ Rm.js | 14.54 | 0 | 16.66 | 14.81 | 36-147
940
+ Shell.js | 29.41 | 0 | 25 | 29.41 | 25-57
941
+ Show.js | 15.68 | 0 | 14.28 | 16 | 45-147
942
+ Ssh.js | 22.22 | 0 | 20 | 22.22 | 49-120
943
+ Tag.js | 8.41 | 0 | 9.09 | 8.49 | 66-246
944
+ Totp.js | 13.59 | 0 | 9.09 | 13.59 | 76-327
945
+ Touch.js | 14.54 | 0 | 25 | 14.81 | 75-245
946
+ Use.js | 11.11 | 0 | 25 | 11.11 | 30-95
947
+ Ver.js | 50 | 0 | 33.33 | 50 | 17-28
948
+ Whoami.js | 27.77 | 0 | 20 | 27.77 | 20-50
949
+ index.js | 87.5 | 50 | 100 | 86.95 | 15,22,31
950
+ src/prompts | 58.33 | 0 | 25 | 58.33 |
951
+ MainPromptMock.js | 58.33 | 0 | 25 | 58.33 | 22-44
952
+ src/utils | 15.89 | 6.86 | 10.25 | 15.62 |
953
+ AliasManager.js | 5.88 | 0 | 0 | 5.88 | 3-48
954
+ ContactManager.js | 6.66 | 0 | 0 | 6.66 | 3-44
955
+ HelpProto.js | 4.2 | 0 | 16.66 | 4.27 | 11-200
956
+ Logger.js | 54.54 | 43.75 | 15.78 | 53.48 | 8,12,16-57,65-69,74,84,88,93,105
957
+ --------------------|---------|----------|---------|---------|----------------------------------
949
958
  ```
950
959
 
951
960
  ## Copyright
package/bin/secrez.js CHANGED
@@ -9,50 +9,49 @@ const pkg = require("../package");
9
9
 
10
10
  const MainPrompt = require("../src/prompts/MainPrompt");
11
11
  const Logger = require("../src/utils/Logger");
12
-
13
12
  // Check if the package was installed with pnpm (skip check in development)
14
- const installPath = __dirname;
15
- if (process.env.NODE_ENV !== "dev" && installPath.indexOf("pnpm") === -1) {
16
- console.error(chalk.red.bold("\n⚠️ Installation Error\n"));
17
- console.error(
18
- chalk.yellow(
19
- "Secrez must be installed globally using pnpm.\n" +
20
- "It appears this package was installed with a different package manager.\n"
21
- )
22
- );
23
- console.error(chalk.white("\nPlease follow these steps:\n"));
24
- console.error(
25
- chalk.cyan(
26
- "1. Uninstall secrez using the package manager you previously used:\n" +
27
- " - If you used npm: " +
28
- chalk.bold("npm uninstall -g secrez") +
29
- "\n" +
30
- " - If you used yarn: " +
31
- chalk.bold("yarn global remove secrez") +
32
- "\n"
33
- )
34
- );
35
- console.error(
36
- chalk.cyan(
37
- "2. Install pnpm globally if you haven't already:\n" +
38
- " " +
39
- chalk.bold("npm install -g pnpm") +
40
- "\n"
41
- )
42
- );
43
- console.error(
44
- chalk.cyan("3. Setup pnpm:\n" + " " + chalk.bold("pnpm setup") + "\n")
45
- );
46
- console.error(
47
- chalk.cyan(
48
- "4. Install secrez globally using pnpm:\n" +
49
- " " +
50
- chalk.bold("pnpm install -g secrez") +
51
- "\n"
52
- )
53
- );
54
- process.exit(1);
55
- }
13
+ // const installPath = __dirname;
14
+ // if (process.env.NODE_ENV !== "dev" && installPath.indexOf("pnpm") === -1) {
15
+ // console.error(chalk.red.bold("\n⚠️ Installation Error\n"));
16
+ // console.error(
17
+ // chalk.yellow(
18
+ // "Secrez must be installed globally using pnpm.\n" +
19
+ // "It appears this package was installed with a different package manager.\n"
20
+ // )
21
+ // );
22
+ // console.error(chalk.white("\nPlease follow these steps:\n"));
23
+ // console.error(
24
+ // chalk.cyan(
25
+ // "1. Uninstall secrez using the package manager you previously used:\n" +
26
+ // " - If you used npm: " +
27
+ // chalk.bold("npm uninstall -g secrez") +
28
+ // "\n" +
29
+ // " - If you used yarn: " +
30
+ // chalk.bold("yarn global remove secrez") +
31
+ // "\n"
32
+ // )
33
+ // );
34
+ // console.error(
35
+ // chalk.cyan(
36
+ // "2. Install pnpm globally if you haven't already:\n" +
37
+ // " " +
38
+ // chalk.bold("npm install -g pnpm") +
39
+ // "\n"
40
+ // )
41
+ // );
42
+ // console.error(
43
+ // chalk.cyan("3. Setup pnpm:\n" + " " + chalk.bold("pnpm setup") + "\n")
44
+ // );
45
+ // console.error(
46
+ // chalk.cyan(
47
+ // "4. Install secrez globally using pnpm:\n" +
48
+ // " " +
49
+ // chalk.bold("pnpm install -g secrez") +
50
+ // "\n"
51
+ // )
52
+ // );
53
+ // process.exit(1);
54
+ // }
56
55
 
57
56
  const optionDefinitions = [
58
57
  {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "secrez",
3
- "version": "2.1.13",
3
+ "version": "2.1.15",
4
4
  "license": "MIT",
5
5
  "nyc": {
6
6
  "include": "src",
@@ -1,5 +1,7 @@
1
1
  const chalk = require("chalk");
2
2
  const { Node } = require("@secrez/fs");
3
+ const { config } = require("@secrez/core");
4
+ const Crypto = require("@secrez/crypto");
3
5
 
4
6
  class Find extends require("../Command") {
5
7
  setHelpAndCompletion() {
@@ -56,6 +58,18 @@ class Find extends require("../Command") {
56
58
  type: Boolean,
57
59
  hint: "If global, search also in trash",
58
60
  },
61
+ {
62
+ name: "recent",
63
+ alias: "R",
64
+ type: Boolean,
65
+ hint: "Search for recent changes",
66
+ },
67
+ {
68
+ name: "limit",
69
+ alias: "l",
70
+ type: Number,
71
+ hint: "Limit the number of results (default: 10 when recent is enabled)",
72
+ },
59
73
  ];
60
74
  }
61
75
 
@@ -83,11 +97,69 @@ class Find extends require("../Command") {
83
97
  "Search scanning all the versions in all the datasets",
84
98
  ],
85
99
  ["find archive:allet", "Search allet in the archive dataset"],
100
+ ["find -R", "Show the 10 most recent changes"],
101
+ ["find -R -l 20", "Show the 20 most recent changes"],
86
102
  ],
87
103
  };
88
104
  }
89
105
 
90
106
  async find(options) {
107
+ // Handle recent mode
108
+ if (options.recent) {
109
+ // Set default limit if not specified by user
110
+ if (options.limit === undefined) {
111
+ options.limit = 10;
112
+ }
113
+ // In recent mode, ignore keywords completely - just show the N most recent entries
114
+ options.name = undefined;
115
+ options.keywords = undefined;
116
+
117
+ if (options.global) {
118
+ let datasetInfo = await this.internalFs.getDatasetsInfo();
119
+ let allResults = [];
120
+ for (let dataset of datasetInfo) {
121
+ if (options.global && !options.trashToo && dataset.index === 1) {
122
+ continue;
123
+ }
124
+ await this.internalFs.mountTree(dataset.index);
125
+ options.tree = this.internalFs.trees[dataset.index];
126
+ options.dataset = dataset.name;
127
+ // Collect raw results (with ts property) for sorting across datasets
128
+ let rawResults = await this._findRecentRaw(options);
129
+ allResults = allResults.concat(rawResults);
130
+ }
131
+ // Sort all results together by timestamp and limit
132
+ allResults.sort((a, b) => {
133
+ return Node.sortEntry(a.ts, b.ts);
134
+ });
135
+ if (allResults.length > options.limit) {
136
+ allResults = allResults.slice(0, options.limit);
137
+ }
138
+ // Format results
139
+ return allResults.map((e) => {
140
+ let result = [
141
+ Node.hashVersion(e.ts),
142
+ e.path + (e.isDir ? "/" : ""),
143
+ e.name,
144
+ undefined,
145
+ ];
146
+ // Store timestamp for date formatting in recent mode
147
+ result.ts = e.ts;
148
+ if (e.dataset) {
149
+ result[1] = e.dataset + ":" + result[1];
150
+ }
151
+ return result;
152
+ });
153
+ } else {
154
+ let data = await this.internalFs.getTreeIndexAndPath(".");
155
+ // Don't set dataset for non-global search (matches regular find behavior)
156
+ // Dataset prefix is only shown when searching globally
157
+ options.tree = data.tree;
158
+ return await this._findRecent(options);
159
+ }
160
+ }
161
+
162
+ // Regular find mode
91
163
  if (!options.name && options.keywords) {
92
164
  options.name = options.keywords;
93
165
  }
@@ -133,20 +205,155 @@ class Find extends require("../Command") {
133
205
  });
134
206
  }
135
207
 
208
+ async _findRecent(options) {
209
+ let rawResults = await this._findRecentRaw(options);
210
+
211
+ // Sort by timestamp (most recent first) and limit
212
+ rawResults.sort((a, b) => {
213
+ return Node.sortEntry(a.ts, b.ts);
214
+ });
215
+
216
+ // Limit results
217
+ if (rawResults.length > options.limit) {
218
+ rawResults = rawResults.slice(0, options.limit);
219
+ }
220
+
221
+ // Format results to match regular find output
222
+ return rawResults.map((e) => {
223
+ let result = [
224
+ Node.hashVersion(e.ts),
225
+ e.path + (e.isDir ? "/" : ""),
226
+ e.name,
227
+ undefined,
228
+ ];
229
+ // Store timestamp for date formatting in recent mode
230
+ result.ts = e.ts;
231
+ // Only add dataset prefix if dataset is set (which happens in global mode)
232
+ if (options.dataset) {
233
+ result[1] = options.dataset + ":" + result[1];
234
+ }
235
+ return result;
236
+ });
237
+ }
238
+
239
+ async _findRecentRaw(options) {
240
+ let start = options.tree[options.root ? "root" : "workingNode"];
241
+ let results = [];
242
+
243
+ // Recursively collect all entries with their timestamps (no keyword filtering in recent mode)
244
+ await this._collectRecentEntries(start, results, options, null);
245
+
246
+ // Add dataset info to results for global mode
247
+ if (options.dataset) {
248
+ results = results.map((e) => {
249
+ e.dataset = options.dataset;
250
+ return e;
251
+ });
252
+ }
253
+
254
+ return results;
255
+ }
256
+
257
+ async _collectRecentEntries(node, results, options, re) {
258
+ // Skip root node
259
+ if (Node.isRoot(node)) {
260
+ // Process children
261
+ if (node.children) {
262
+ for (let id in node.children) {
263
+ await this._collectRecentEntries(
264
+ node.children[id],
265
+ results,
266
+ options,
267
+ re
268
+ );
269
+ }
270
+ }
271
+ return;
272
+ }
273
+
274
+ // Process current node if it has versions
275
+ if (node.versions && node.lastTs) {
276
+ let name = node.getName();
277
+ let path = node.getPath();
278
+ let isDir = Node.isDir(node);
279
+
280
+ // Filter by keywords if provided
281
+ if (re) {
282
+ if (re.test(name)) {
283
+ results.push({
284
+ ts: node.lastTs,
285
+ name: name,
286
+ path: path,
287
+ isDir: isDir,
288
+ });
289
+ } else if (
290
+ options.content &&
291
+ Node.isFile(node) &&
292
+ node.type === config.types.TEXT &&
293
+ options.tree
294
+ ) {
295
+ // Check content if content option is enabled
296
+ try {
297
+ let { content } = await options.tree.getEntryDetails(
298
+ node,
299
+ node.lastTs
300
+ );
301
+ if (re.test(content || "")) {
302
+ results.push({
303
+ ts: node.lastTs,
304
+ name: name,
305
+ path: path,
306
+ isDir: isDir,
307
+ });
308
+ }
309
+ } catch (e) {
310
+ // Ignore errors when reading content
311
+ }
312
+ }
313
+ } else {
314
+ // No keyword filter, include all entries
315
+ results.push({
316
+ ts: node.lastTs,
317
+ name: name,
318
+ path: path,
319
+ isDir: isDir,
320
+ });
321
+ }
322
+ }
323
+
324
+ // Process children
325
+ if (node.children) {
326
+ for (let id in node.children) {
327
+ await this._collectRecentEntries(
328
+ node.children[id],
329
+ results,
330
+ options,
331
+ re
332
+ );
333
+ }
334
+ }
335
+ }
336
+
136
337
  formatResult(result, re) {
137
- if (re.test(result)) {
338
+ if (re && re.test(result)) {
138
339
  return result.replace(re, (a) => chalk.bold(a));
139
340
  } else {
140
341
  return result;
141
342
  }
142
343
  }
143
344
 
345
+ formatDate(ts) {
346
+ let dateArray = Crypto.fromTsToDate(ts);
347
+ let date = dateArray[0].split("Z")[0].split("T")[0]; // Get YYYY-MM-DD format
348
+ return chalk.cyan(date);
349
+ }
350
+
144
351
  formatIndex(len, i) {
145
352
  return " ".repeat(len.toString().length - i.toString().length) + i;
146
353
  }
147
354
 
148
355
  formatList(list, options) {
149
- let re = Node.getFindRe(options);
356
+ let re = options.name ? Node.getFindRe(options) : null;
150
357
  let i = 0;
151
358
  const setCache = (i, e) => {
152
359
  this.prompt.setCache("findResult", i, e);
@@ -159,7 +366,7 @@ class Find extends require("../Command") {
159
366
  let l = p.length;
160
367
  let c = p[l - 1] ? p[l - 1] : p[l - 2];
161
368
  if (e[2] && e[2] !== c) {
162
- e[2] = this.formatResult(e[2], re, options.name);
369
+ e[2] = re ? this.formatResult(e[2], re, options.name) : e[2];
163
370
  } else {
164
371
  e[2] = undefined;
165
372
  }
@@ -169,13 +376,29 @@ class Find extends require("../Command") {
169
376
  " ",
170
377
  chalk.yellow(e[0]),
171
378
  " ",
172
- this.formatResult(e[1], re, options.name),
379
+ re ? this.formatResult(e[1], re, options.name) : e[1],
173
380
  " ",
174
381
  e[2],
175
382
  ].join("");
176
383
  } else {
177
384
  setCache(i, e);
178
- return [k, " ", this.formatResult(e[1], re, options.name)].join("");
385
+ // In recent mode, show date before the path
386
+ if (options.recent && e.ts) {
387
+ let dateStr = this.formatDate(e.ts);
388
+ return [
389
+ k,
390
+ " ",
391
+ dateStr,
392
+ " ",
393
+ re ? this.formatResult(e[1], re, options.name) : e[1],
394
+ ].join("");
395
+ } else {
396
+ return [
397
+ k,
398
+ " ",
399
+ re ? this.formatResult(e[1], re, options.name) : e[1],
400
+ ].join("");
401
+ }
179
402
  }
180
403
  });
181
404
  }
@@ -186,8 +409,8 @@ class Find extends require("../Command") {
186
409
  }
187
410
  try {
188
411
  this.validate(options);
189
- options.name = options.keywords;
190
- if (options.name) {
412
+ // In recent mode, keywords are ignored - just show recent entries
413
+ if (options.recent) {
191
414
  try {
192
415
  this.lastResult = await this.find(options);
193
416
  let list = this.formatList(this.lastResult, options);
@@ -203,7 +426,26 @@ class Find extends require("../Command") {
203
426
  this.Logger.red(e.message);
204
427
  }
205
428
  } else {
206
- this.Logger.grey("Missing parameters");
429
+ // Regular find mode requires keywords
430
+ options.name = options.keywords;
431
+ if (options.name) {
432
+ try {
433
+ this.lastResult = await this.find(options);
434
+ let list = this.formatList(this.lastResult, options);
435
+ if (list && list.length) {
436
+ this.Logger.grey(
437
+ `${list.length} result${list.length > 1 ? "s" : ""} found:`
438
+ );
439
+ for (let l of list) this.Logger.reset(l);
440
+ } else {
441
+ this.Logger.grey("No results.");
442
+ }
443
+ } catch (e) {
444
+ this.Logger.red(e.message);
445
+ }
446
+ } else {
447
+ this.Logger.grey("Missing parameters");
448
+ }
207
449
  }
208
450
  } catch (e) {
209
451
  this.Logger.red(e.message);
@@ -1,5 +1,5 @@
1
1
  const chalk = require("chalk");
2
- const { yamlStringify } = require("@secrez/utils");
2
+ const { yamlStringify, execAsync } = require("@secrez/utils");
3
3
 
4
4
  class Git extends require("../Command") {
5
5
  setHelpAndCompletion() {
@@ -19,13 +19,26 @@ class Git extends require("../Command") {
19
19
  alias: "s",
20
20
  type: Boolean,
21
21
  },
22
+ {
23
+ name: "push",
24
+ alias: "p",
25
+ type: Boolean,
26
+ },
22
27
  ];
23
28
  }
24
29
 
25
30
  help() {
26
31
  return {
27
- description: ["Check a git repository status."],
28
- examples: [["git -s", "Check the git repository status"]],
32
+ description: [
33
+ "Check a git repository status or push current changes and update the fingerprint.",
34
+ ],
35
+ examples: [
36
+ ["git -s", "Check the git repository status"],
37
+ [
38
+ "git -p",
39
+ "Stage, commit (if needed), push changes, and update the fingerprint",
40
+ ],
41
+ ],
29
42
  };
30
43
  }
31
44
 
@@ -40,6 +53,46 @@ class Git extends require("../Command") {
40
53
  return chalk.yellow(warning);
41
54
  } else return "No remote changes found.";
42
55
  }
56
+ if (options.push) {
57
+ const containerPath = this.secrez.config.container;
58
+ // Get current status to know what to do
59
+ const status = await this.internalFs.gitConflictChecker.getGitStatus();
60
+ if (status && status.error) {
61
+ return chalk.red(`Git status error: ${status.error}`);
62
+ }
63
+
64
+ // No changes and not ahead: nothing to push
65
+ if ((status?.uncommitted || 0) === 0 && (status?.ahead || 0) === 0) {
66
+ return "No changes in the repository";
67
+ }
68
+
69
+ // If there are uncommitted changes, stage and commit
70
+ if (status && status.uncommitted > 0) {
71
+ const addRes = await execAsync("git", containerPath, ["add", "-A"]);
72
+ if (addRes && addRes.error) {
73
+ return chalk.red(`git add failed: ${addRes.error}`);
74
+ }
75
+ const commitRes = await execAsync("git", containerPath, [
76
+ "commit",
77
+ "-m",
78
+ "Secrez: save changes",
79
+ ]);
80
+ if (commitRes && commitRes.error) {
81
+ return chalk.red(`git commit failed: ${commitRes.error}`);
82
+ }
83
+ }
84
+
85
+ // Try to push (even if there were no new commits but local might be ahead)
86
+ const pushRes = await execAsync("git", containerPath, ["push"]);
87
+ if (pushRes && pushRes.error) {
88
+ return chalk.red(`git push failed: ${pushRes.error}`);
89
+ }
90
+
91
+ // Update the initial fingerprint so Secrez won't block further operations in this session
92
+ await this.internalFs.gitConflictChecker.captureInitialState();
93
+
94
+ return "Pushed successfully. Fingerprint updated.";
95
+ }
43
96
  } else {
44
97
  return "Not a git repository";
45
98
  }