@devkitvault/recall 1.2.6 → 1.2.9
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 +34 -39
- package/dist/commands/ask.js +15 -2
- package/dist/commands/delete.js +9 -25
- package/dist/commands/list.js +33 -52
- package/dist/commands/pin.js +10 -16
- package/dist/commands/run.js +23 -37
- package/dist/commands/save.js +49 -52
- package/dist/commands/search.js +31 -46
- package/dist/commands/sync.js +92 -54
- package/dist/commands/upgrade.js +5 -6
- package/dist/commands/whoami.js +7 -8
- package/dist/lib/config.js +1 -1
- package/dist/lib/local-vault.js +251 -0
- package/dist/lib/shell-history.js +145 -0
- package/package.json +4 -5
package/README.md
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
# @devkitvault/recall
|
|
2
2
|
|
|
3
|
-
**recall** is
|
|
3
|
+
**recall** is a CLI command vault for your terminal. Save the commands you keep losing, search them, run them by name, and sync when you want cloud backup.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Product site and docs: [recall.devkitvault.com](https://recall.devkitvault.com)
|
|
6
|
+
|
|
7
|
+
Open source: [github.com/devkitvault/recall-cli](https://github.com/devkitvault/recall-cli)
|
|
6
8
|
|
|
7
9
|
## Requirements
|
|
8
10
|
|
|
@@ -14,68 +16,60 @@ Works with [recall.devkitvault.com](https://recall.devkitvault.com) and the [VS
|
|
|
14
16
|
npm install -g @devkitvault/recall
|
|
15
17
|
```
|
|
16
18
|
|
|
17
|
-
`rec` is the same
|
|
19
|
+
`rec` is the same binary as `recall`.
|
|
18
20
|
|
|
19
21
|
```sh
|
|
20
22
|
recall --version
|
|
21
23
|
recall doctor
|
|
22
24
|
```
|
|
23
25
|
|
|
24
|
-
## Quick start
|
|
26
|
+
## Quick start (local vault)
|
|
27
|
+
|
|
28
|
+
Free is **fully local** — save / list / search / run on your machine with **no account**. Cloud **sync** and **Ask** are Pro/Team.
|
|
25
29
|
|
|
26
30
|
```sh
|
|
27
|
-
recall
|
|
28
|
-
recall
|
|
29
|
-
|
|
30
|
-
recall
|
|
31
|
+
recall save "docker compose up -d" --name docker --tags docker
|
|
32
|
+
recall save --last -n useful -t docker
|
|
33
|
+
recall list
|
|
34
|
+
recall search docker
|
|
35
|
+
recall run docker
|
|
31
36
|
```
|
|
32
37
|
|
|
33
|
-
|
|
38
|
+
Commands live in `~/.recall/commands.json`.
|
|
39
|
+
|
|
40
|
+
`recall save --last` (or `-L`) reads the last line from zsh / bash / PowerShell history. Not supported in Windows `cmd.exe`. On bash, if the command is missing: `history -a && recall save --last`.
|
|
34
41
|
|
|
35
42
|
```sh
|
|
36
43
|
recall playbook save deploy "docker compose up -d" "pnpm migrate"
|
|
37
44
|
recall playbook run deploy --dry-run
|
|
38
45
|
```
|
|
39
46
|
|
|
40
|
-
`recall playbook run` executes steps. Ask never does.
|
|
41
|
-
|
|
42
|
-
Ask prints a suggestion (`source` is `vault`, `cache`, or `recall agent` for a generated answer). Copy or save it yourself.
|
|
43
|
-
|
|
44
|
-
## Four launch demos
|
|
45
|
-
|
|
46
|
-
Ask prints. It does not run.
|
|
47
|
-
|
|
48
|
-
**`rec "start the project"`** (`source: project`)
|
|
47
|
+
Local playbooks follow the same idea when available; cloud playbooks need Pro. `recall playbook run` executes steps. Ask never does.
|
|
49
48
|
|
|
50
|
-
|
|
49
|
+
## Ask (Pro / Team)
|
|
51
50
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-

|
|
55
|
-
|
|
56
|
-
**`rec "free the process using port 3000"`** (`source: recall agent`)
|
|
57
|
-
|
|
58
|
-

|
|
59
|
-
|
|
60
|
-
**`rec "that docker command from last week"`** (`source: vault`)
|
|
61
|
-
|
|
62
|
-

|
|
51
|
+
Natural-language Ask prints a suggestion and never runs it. Requires a Pro or Team plan.
|
|
63
52
|
|
|
64
53
|
```sh
|
|
65
|
-
recall
|
|
66
|
-
recall
|
|
54
|
+
recall auth login
|
|
55
|
+
recall "find the 10 biggest files in this directory"
|
|
56
|
+
rec "that docker command from last week"
|
|
67
57
|
```
|
|
68
58
|
|
|
69
|
-
|
|
59
|
+
No-args `recall` opens an Ask session (`Recall >`). `/save [name]` stores the last suggestion. `/exit` leaves.
|
|
60
|
+
|
|
61
|
+
## Auth & sync (Pro / Team)
|
|
70
62
|
|
|
71
|
-
|
|
63
|
+
Account + Pro/Team syncs your **local** commands to the cloud and unlocks Ask.
|
|
72
64
|
|
|
73
65
|
```sh
|
|
74
66
|
recall auth login
|
|
75
|
-
recall
|
|
67
|
+
recall sync # pull then push
|
|
68
|
+
recall sync --pull # cloud → local
|
|
69
|
+
recall sync --push # local-only → cloud
|
|
70
|
+
recall sync --status
|
|
76
71
|
recall whoami
|
|
77
72
|
```
|
|
78
|
-
|
|
79
73
|
## Prefer a standalone binary?
|
|
80
74
|
|
|
81
75
|
- **macOS / Linux:** `curl -fsSL https://devkitvault.com/recall/install.sh | sh`
|
|
@@ -96,17 +90,18 @@ recall doctor
|
|
|
96
90
|
recall whoami
|
|
97
91
|
```
|
|
98
92
|
|
|
99
|
-
If something still fails, open an issue on [GitHub](https://github.com/devkitvault/recall/issues) or visit [recall.devkitvault.com](https://recall.devkitvault.com).
|
|
93
|
+
If something still fails, open an issue on [GitHub](https://github.com/devkitvault/recall-cli/issues) or visit [recall.devkitvault.com](https://recall.devkitvault.com).
|
|
100
94
|
|
|
101
95
|
## Links
|
|
102
96
|
|
|
103
97
|
| | |
|
|
104
98
|
| --------- | ----------------------------------------------------------------------------------------- |
|
|
105
|
-
| Website | [devkitvault.com
|
|
99
|
+
| Website | [recall.devkitvault.com](https://recall.devkitvault.com) |
|
|
106
100
|
| Docs | [recall.devkitvault.com/docs](https://recall.devkitvault.com/docs) |
|
|
107
101
|
| Dashboard | [recall.devkitvault.com](https://recall.devkitvault.com) |
|
|
102
|
+
| Source | [github.com/devkitvault/recall-cli](https://github.com/devkitvault/recall-cli) |
|
|
108
103
|
| VS Code | [Marketplace](https://marketplace.visualstudio.com/items?itemName=devkitvault.recall-cmd) |
|
|
109
|
-
| Issues | [github.com/devkitvault/recall](https://github.com/devkitvault/recall/issues)
|
|
104
|
+
| Issues | [github.com/devkitvault/recall-cli](https://github.com/devkitvault/recall-cli/issues) |
|
|
110
105
|
|
|
111
106
|
## License
|
|
112
107
|
|
package/dist/commands/ask.js
CHANGED
|
@@ -15,6 +15,7 @@ const commander_1 = require("commander");
|
|
|
15
15
|
const inquirer_1 = __importDefault(require("inquirer"));
|
|
16
16
|
const api_1 = require("../lib/api");
|
|
17
17
|
const auth_1 = require("../lib/auth");
|
|
18
|
+
const local_vault_1 = require("../lib/local-vault");
|
|
18
19
|
const events_1 = require("../lib/events");
|
|
19
20
|
const project_1 = require("../lib/project");
|
|
20
21
|
const runtime_1 = require("../lib/runtime");
|
|
@@ -91,11 +92,23 @@ async function promptSaveMeta(existingName) {
|
|
|
91
92
|
};
|
|
92
93
|
}
|
|
93
94
|
async function saveSuggestion(token, command, name, source, risk, tags) {
|
|
94
|
-
|
|
95
|
+
const local = (0, local_vault_1.saveLocalCommand)({
|
|
95
96
|
command,
|
|
96
97
|
name: name?.trim() || undefined,
|
|
97
98
|
tags,
|
|
98
|
-
}
|
|
99
|
+
});
|
|
100
|
+
try {
|
|
101
|
+
const saved = await api_1.ApiClient.post('/commands', {
|
|
102
|
+
command,
|
|
103
|
+
name: name?.trim() || undefined,
|
|
104
|
+
tags,
|
|
105
|
+
}, token);
|
|
106
|
+
if (saved?.id)
|
|
107
|
+
(0, local_vault_1.attachCloudId)(local.id, saved.id);
|
|
108
|
+
}
|
|
109
|
+
catch {
|
|
110
|
+
// Local save succeeded; cloud may require Pro
|
|
111
|
+
}
|
|
99
112
|
await (0, events_1.track)('ai_accepted', { source, risk, saved: true });
|
|
100
113
|
console.log(chalk_1.default.green(`\n ${(0, tags_1.formatSavedMessage)(name, tags)}\n`));
|
|
101
114
|
}
|
package/dist/commands/delete.js
CHANGED
|
@@ -7,38 +7,27 @@ exports.deleteCommand = void 0;
|
|
|
7
7
|
const chalk_1 = __importDefault(require("chalk"));
|
|
8
8
|
const commander_1 = require("commander");
|
|
9
9
|
const inquirer_1 = __importDefault(require("inquirer"));
|
|
10
|
-
const
|
|
11
|
-
const api_1 = require("../lib/api");
|
|
12
|
-
const auth_1 = require("../lib/auth");
|
|
10
|
+
const local_vault_1 = require("../lib/local-vault");
|
|
13
11
|
exports.deleteCommand = new commander_1.Command('delete')
|
|
14
|
-
.description('Delete a
|
|
12
|
+
.description('Delete a command from your local vault')
|
|
15
13
|
.argument('<name>', 'Command name to delete')
|
|
16
14
|
.option('-f, --force', 'Skip confirmation prompt')
|
|
17
15
|
.action(async (name, opts) => {
|
|
18
|
-
const
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
let cmd;
|
|
22
|
-
try {
|
|
23
|
-
cmd = await api_1.ApiClient.get(`/commands/by-name/${encodeURIComponent(name)}`, token);
|
|
24
|
-
spinner.stop();
|
|
25
|
-
}
|
|
26
|
-
catch {
|
|
27
|
-
spinner.fail(chalk_1.default.red(`Command "${name}" not found`));
|
|
16
|
+
const cmd = (0, local_vault_1.findLocalByName)(name);
|
|
17
|
+
if (!cmd) {
|
|
18
|
+
console.log(chalk_1.default.red(`\n Command "${name}" not found in local vault.\n`));
|
|
28
19
|
process.exit(1);
|
|
29
20
|
}
|
|
30
|
-
// Show what will be deleted
|
|
31
21
|
console.log();
|
|
32
22
|
console.log(` ${chalk_1.default.dim('Name:')} ${chalk_1.default.white(cmd.name ?? '—')}`);
|
|
33
23
|
console.log(` ${chalk_1.default.dim('Command:')} ${chalk_1.default.white(cmd.command)}`);
|
|
34
24
|
console.log();
|
|
35
|
-
// Confirm unless --force
|
|
36
25
|
if (!opts.force) {
|
|
37
26
|
const { confirm } = await inquirer_1.default.prompt([
|
|
38
27
|
{
|
|
39
28
|
type: 'confirm',
|
|
40
29
|
name: 'confirm',
|
|
41
|
-
message: chalk_1.default.red(`Delete "${name}"?`),
|
|
30
|
+
message: chalk_1.default.red(`Delete "${name}" from local vault?`),
|
|
42
31
|
default: false,
|
|
43
32
|
},
|
|
44
33
|
]);
|
|
@@ -47,12 +36,7 @@ exports.deleteCommand = new commander_1.Command('delete')
|
|
|
47
36
|
return;
|
|
48
37
|
}
|
|
49
38
|
}
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
deleteSpinner.succeed(chalk_1.default.green(`Deleted "${name}"`));
|
|
54
|
-
}
|
|
55
|
-
catch {
|
|
56
|
-
deleteSpinner.fail(chalk_1.default.red('Failed to delete'));
|
|
57
|
-
}
|
|
39
|
+
(0, local_vault_1.deleteLocalByName)(name);
|
|
40
|
+
console.log(chalk_1.default.green(` Deleted "${name}" from local vault.\n`));
|
|
41
|
+
console.log(chalk_1.default.dim(' Cloud copy (if any) is unchanged until you sync.\n'));
|
|
58
42
|
});
|
package/dist/commands/list.js
CHANGED
|
@@ -7,63 +7,44 @@ exports.listCommand = void 0;
|
|
|
7
7
|
const chalk_1 = __importDefault(require("chalk"));
|
|
8
8
|
const cli_table3_1 = __importDefault(require("cli-table3"));
|
|
9
9
|
const commander_1 = require("commander");
|
|
10
|
-
const
|
|
11
|
-
const api_1 = require("../lib/api");
|
|
12
|
-
const auth_1 = require("../lib/auth");
|
|
10
|
+
const local_vault_1 = require("../lib/local-vault");
|
|
13
11
|
exports.listCommand = new commander_1.Command('list')
|
|
14
|
-
.description('List your
|
|
12
|
+
.description('List commands in your local vault')
|
|
15
13
|
.option('-t, --tag <tag>', 'Filter by tag')
|
|
16
|
-
.option('-g, --group <group>', 'Filter by group (Pro)')
|
|
14
|
+
.option('-g, --group <group>', 'Filter by group (Pro cloud — not used locally)')
|
|
17
15
|
.option('-s, --search <q>', 'Search by keyword')
|
|
18
16
|
.option('-p, --pinned', 'Show pinned only')
|
|
19
17
|
.action(async (opts) => {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
try {
|
|
23
|
-
const params = new URLSearchParams();
|
|
24
|
-
if (opts.tag)
|
|
25
|
-
params.set('tag', opts.tag);
|
|
26
|
-
if (opts.group)
|
|
27
|
-
params.set('group', opts.group);
|
|
28
|
-
if (opts.search)
|
|
29
|
-
params.set('search', opts.search);
|
|
30
|
-
const { commands } = await api_1.ApiClient.get(`/commands?${params}`, token);
|
|
31
|
-
spinner.stop();
|
|
32
|
-
let result = commands;
|
|
33
|
-
// Filter pinned only
|
|
34
|
-
if (opts.pinned)
|
|
35
|
-
result = result.filter((c) => c.pinned);
|
|
36
|
-
// Sort: pinned first, then by createdAt
|
|
37
|
-
result.sort((a, b) => {
|
|
38
|
-
if (a.pinned && !b.pinned)
|
|
39
|
-
return -1;
|
|
40
|
-
if (!a.pinned && b.pinned)
|
|
41
|
-
return 1;
|
|
42
|
-
return 0;
|
|
43
|
-
});
|
|
44
|
-
if (!result.length) {
|
|
45
|
-
console.log(chalk_1.default.dim('\n No commands found.\n'));
|
|
46
|
-
return;
|
|
47
|
-
}
|
|
48
|
-
const table = new cli_table3_1.default({
|
|
49
|
-
head: [chalk_1.default.cyan('Pin'), chalk_1.default.cyan('Name'), chalk_1.default.cyan('Command'), chalk_1.default.cyan('Tags')],
|
|
50
|
-
style: { head: [], border: ['grey'] },
|
|
51
|
-
colWidths: [5, 18, 44, 18],
|
|
52
|
-
wordWrap: true,
|
|
53
|
-
});
|
|
54
|
-
for (const cmd of result) {
|
|
55
|
-
table.push([
|
|
56
|
-
cmd.pinned ? chalk_1.default.yellow('★') : chalk_1.default.dim('·'),
|
|
57
|
-
cmd.name ?? chalk_1.default.dim('—'),
|
|
58
|
-
cmd.command.length > 42
|
|
59
|
-
? cmd.command.slice(0, 42) + '…'
|
|
60
|
-
: cmd.command,
|
|
61
|
-
(cmd.tags ?? []).join(', ') || chalk_1.default.dim('—'),
|
|
62
|
-
]);
|
|
63
|
-
}
|
|
64
|
-
console.log(table.toString());
|
|
18
|
+
if (opts.group) {
|
|
19
|
+
console.log(chalk_1.default.dim(' Local vault has no groups. Showing all local commands.\n'));
|
|
65
20
|
}
|
|
66
|
-
|
|
67
|
-
|
|
21
|
+
const result = (0, local_vault_1.listLocalCommands)({
|
|
22
|
+
tag: opts.tag,
|
|
23
|
+
search: opts.search,
|
|
24
|
+
pinned: opts.pinned,
|
|
25
|
+
});
|
|
26
|
+
if (!result.length) {
|
|
27
|
+
console.log(chalk_1.default.dim('\n No commands in local vault.'));
|
|
28
|
+
console.log(chalk_1.default.dim(` Save one: recall save "echo hi" -n hi`));
|
|
29
|
+
console.log(chalk_1.default.dim(` File: ${local_vault_1.VAULT_FILE}\n`));
|
|
30
|
+
return;
|
|
68
31
|
}
|
|
32
|
+
const table = new cli_table3_1.default({
|
|
33
|
+
head: [chalk_1.default.cyan('Pin'), chalk_1.default.cyan('Name'), chalk_1.default.cyan('Command'), chalk_1.default.cyan('Tags')],
|
|
34
|
+
style: { head: [], border: ['grey'] },
|
|
35
|
+
colWidths: [5, 18, 44, 18],
|
|
36
|
+
wordWrap: true,
|
|
37
|
+
});
|
|
38
|
+
for (const cmd of result) {
|
|
39
|
+
table.push([
|
|
40
|
+
cmd.pinned ? chalk_1.default.yellow('★') : chalk_1.default.dim('·'),
|
|
41
|
+
cmd.name ?? chalk_1.default.dim('—'),
|
|
42
|
+
cmd.command.length > 42
|
|
43
|
+
? cmd.command.slice(0, 42) + '…'
|
|
44
|
+
: cmd.command,
|
|
45
|
+
(cmd.tags ?? []).join(', ') || chalk_1.default.dim('—'),
|
|
46
|
+
]);
|
|
47
|
+
}
|
|
48
|
+
console.log(table.toString());
|
|
49
|
+
console.log(chalk_1.default.dim(`\n ${result.length} local · ${local_vault_1.VAULT_FILE}\n`));
|
|
69
50
|
});
|
package/dist/commands/pin.js
CHANGED
|
@@ -6,25 +6,19 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
exports.pinCommand = void 0;
|
|
7
7
|
const chalk_1 = __importDefault(require("chalk"));
|
|
8
8
|
const commander_1 = require("commander");
|
|
9
|
-
const
|
|
10
|
-
const api_1 = require("../lib/api");
|
|
11
|
-
const auth_1 = require("../lib/auth");
|
|
9
|
+
const local_vault_1 = require("../lib/local-vault");
|
|
12
10
|
exports.pinCommand = new commander_1.Command('pin')
|
|
13
|
-
.description('Pin or unpin a command
|
|
11
|
+
.description('Pin or unpin a local command')
|
|
14
12
|
.argument('<name>', 'Command name')
|
|
15
13
|
.option('-u, --unpin', 'Unpin instead of pin')
|
|
16
14
|
.action(async (name, opts) => {
|
|
17
|
-
const
|
|
18
|
-
const
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
await api_1.ApiClient.patch(`/commands/${cmd.id}/pin`, { pinned }, token);
|
|
23
|
-
spinner.succeed(pinned
|
|
24
|
-
? chalk_1.default.green(`Pinned "${name}" — it will appear at the top of recall list`)
|
|
25
|
-
: chalk_1.default.green(`Unpinned "${name}"`));
|
|
26
|
-
}
|
|
27
|
-
catch {
|
|
28
|
-
spinner.fail(chalk_1.default.red(`Command "${name}" not found`));
|
|
15
|
+
const pinned = !opts.unpin;
|
|
16
|
+
const cmd = (0, local_vault_1.setLocalPinned)(name, pinned);
|
|
17
|
+
if (!cmd) {
|
|
18
|
+
console.log(chalk_1.default.red(`\n Command "${name}" not found in local vault.\n`));
|
|
19
|
+
process.exit(1);
|
|
29
20
|
}
|
|
21
|
+
console.log(pinned
|
|
22
|
+
? chalk_1.default.green(` Pinned "${name}" — it will appear at the top of recall list\n`)
|
|
23
|
+
: chalk_1.default.green(` Unpinned "${name}"\n`));
|
|
30
24
|
});
|
package/dist/commands/run.js
CHANGED
|
@@ -8,48 +8,34 @@ const chalk_1 = __importDefault(require("chalk"));
|
|
|
8
8
|
const child_process_1 = require("child_process");
|
|
9
9
|
const commander_1 = require("commander");
|
|
10
10
|
const inquirer_1 = __importDefault(require("inquirer"));
|
|
11
|
-
const
|
|
12
|
-
const api_1 = require("../lib/api");
|
|
13
|
-
const auth_1 = require("../lib/auth");
|
|
11
|
+
const local_vault_1 = require("../lib/local-vault");
|
|
14
12
|
exports.runCommand = new commander_1.Command('run')
|
|
15
|
-
.description('Run a saved command by name
|
|
16
|
-
.argument('<name>', 'Command name
|
|
13
|
+
.description('Run a saved local command by name')
|
|
14
|
+
.argument('<name>', 'Command name')
|
|
17
15
|
.option('-d, --dry-run', 'Print command without running it')
|
|
18
16
|
.option('-c, --confirm', 'Ask for confirmation before running')
|
|
19
17
|
.action(async (name, opts) => {
|
|
20
|
-
const
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
18
|
+
const cmd = (0, local_vault_1.findLocalByName)(name);
|
|
19
|
+
if (!cmd) {
|
|
20
|
+
console.log(chalk_1.default.red(`\n Command "${name}" not found in local vault.\n`));
|
|
21
|
+
console.log(chalk_1.default.dim(' List: recall list'));
|
|
22
|
+
console.log(chalk_1.default.dim(' Sync from cloud (Pro): recall sync\n'));
|
|
23
|
+
process.exit(1);
|
|
24
|
+
}
|
|
25
|
+
console.log(chalk_1.default.dim(`\n $ ${cmd.command}\n`));
|
|
26
|
+
if (opts.dryRun)
|
|
27
|
+
return;
|
|
28
|
+
if (opts.confirm) {
|
|
29
|
+
const { ok } = await inquirer_1.default.prompt([{
|
|
30
|
+
type: 'confirm',
|
|
31
|
+
name: 'ok',
|
|
32
|
+
message: 'Run this command?',
|
|
33
|
+
default: true,
|
|
34
|
+
}]);
|
|
35
|
+
if (!ok) {
|
|
36
|
+
console.log(chalk_1.default.dim(' Cancelled.\n'));
|
|
34
37
|
return;
|
|
35
|
-
// Confirm if --confirm flag or command has confirm flag
|
|
36
|
-
if (opts.confirm) {
|
|
37
|
-
const { ok } = await inquirer_1.default.prompt([{
|
|
38
|
-
type: 'confirm',
|
|
39
|
-
name: 'ok',
|
|
40
|
-
message: 'Run this command?',
|
|
41
|
-
default: true,
|
|
42
|
-
}]);
|
|
43
|
-
if (!ok) {
|
|
44
|
-
console.log(chalk_1.default.dim(' Cancelled.\n'));
|
|
45
|
-
return;
|
|
46
|
-
}
|
|
47
38
|
}
|
|
48
|
-
// Log the run
|
|
49
|
-
api_1.ApiClient.post(`/commands/${cmd.id}/run`, {}, token).catch(() => { });
|
|
50
|
-
(0, child_process_1.execSync)(cmd.command, { stdio: 'inherit' });
|
|
51
|
-
}
|
|
52
|
-
catch {
|
|
53
|
-
spinner.fail(chalk_1.default.red(`Command "${name}" not found`));
|
|
54
39
|
}
|
|
40
|
+
(0, child_process_1.execSync)(cmd.command, { stdio: 'inherit' });
|
|
55
41
|
});
|
package/dist/commands/save.js
CHANGED
|
@@ -6,68 +6,65 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
exports.saveCommand = void 0;
|
|
7
7
|
const chalk_1 = __importDefault(require("chalk"));
|
|
8
8
|
const commander_1 = require("commander");
|
|
9
|
-
const
|
|
10
|
-
const
|
|
11
|
-
const
|
|
9
|
+
const shell_history_1 = require("../lib/shell-history");
|
|
10
|
+
const tags_1 = require("../lib/tags");
|
|
11
|
+
const local_vault_1 = require("../lib/local-vault");
|
|
12
12
|
exports.saveCommand = new commander_1.Command('save')
|
|
13
|
-
.description('Save a command to your vault')
|
|
14
|
-
.argument('
|
|
13
|
+
.description('Save a command to your local vault (no account required)')
|
|
14
|
+
.argument('[command]', 'The shell command to save (omit when using --last)')
|
|
15
|
+
.option('-L, --last', 'Save the last command from your shell history')
|
|
15
16
|
.option('-n, --name <name>', 'Short memorable name')
|
|
16
17
|
.option('-t, --tags <tags>', 'Comma-separated tags')
|
|
17
|
-
.option('-g, --group <group>', '
|
|
18
|
-
.
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
18
|
+
.option('-g, --group <group>', 'Group (Pro / cloud — ignored for local save)')
|
|
19
|
+
.addHelpText('after', `
|
|
20
|
+
Examples:
|
|
21
|
+
$ recall save "docker compose up -d" -n start-stack -t docker
|
|
22
|
+
$ recall save --last
|
|
23
|
+
$ recall save --last -n start-stack -t docker
|
|
24
|
+
|
|
25
|
+
Saves to the local vault (~/.recall/commands.json). No login required.
|
|
26
|
+
Sync to the cloud with Pro: recall auth login && recall sync
|
|
27
|
+
|
|
28
|
+
--last reads zsh/bash/PowerShell history (not cmd.exe).
|
|
29
|
+
Bash tip: if the command is missing, run: history -a && recall save --last
|
|
30
|
+
`)
|
|
31
|
+
.action(async (commandArg, opts) => {
|
|
32
|
+
let command = commandArg?.trim();
|
|
33
|
+
if (opts.last) {
|
|
34
|
+
if (command) {
|
|
35
|
+
console.log(chalk_1.default.yellow(' Ignoring the command argument because --last was set.'));
|
|
36
|
+
}
|
|
24
37
|
try {
|
|
25
|
-
const
|
|
26
|
-
|
|
27
|
-
|
|
38
|
+
const last = (0, shell_history_1.getLastShellCommand)();
|
|
39
|
+
command = last.command;
|
|
40
|
+
console.log(chalk_1.default.dim(` From ${last.shell} history: ${command}`));
|
|
28
41
|
}
|
|
29
42
|
catch (err) {
|
|
30
|
-
if (err instanceof
|
|
31
|
-
|
|
32
|
-
console.log(chalk_1.default.yellow('\n Groups require a Pro plan.'));
|
|
33
|
-
console.log(chalk_1.default.dim(' Run: recall upgrade\n'));
|
|
34
|
-
process.exit(1);
|
|
35
|
-
}
|
|
36
|
-
if (err instanceof api_1.ApiError && err.status === 404) {
|
|
37
|
-
// Auto-create the group
|
|
38
|
-
spinner.text = `Creating group "${opts.group}"...`;
|
|
39
|
-
try {
|
|
40
|
-
const newGroup = await api_1.ApiClient.post('/groups', { name: opts.group }, token);
|
|
41
|
-
groupId = newGroup.id;
|
|
42
|
-
spinner.succeed(chalk_1.default.green(`Created group "${opts.group}"`));
|
|
43
|
-
}
|
|
44
|
-
catch (createErr) {
|
|
45
|
-
spinner.fail(chalk_1.default.red(`Failed to create group "${opts.group}"`));
|
|
46
|
-
process.exit(1);
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
else {
|
|
50
|
-
spinner.fail(chalk_1.default.red(`Failed to look up group "${opts.group}"`));
|
|
43
|
+
if (err instanceof shell_history_1.LastCommandError) {
|
|
44
|
+
console.log(chalk_1.default.red(`\n ${err.message}\n`));
|
|
51
45
|
process.exit(1);
|
|
52
46
|
}
|
|
47
|
+
throw err;
|
|
53
48
|
}
|
|
54
49
|
}
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
groupId,
|
|
62
|
-
}, token);
|
|
63
|
-
spinner.succeed(chalk_1.default.green(`Saved${saved.name ? ` as "${saved.name}"` : ''}` +
|
|
64
|
-
(opts.group ? chalk_1.default.dim(` → group "${opts.group}"`) : '')));
|
|
50
|
+
if (!command) {
|
|
51
|
+
console.log(chalk_1.default.red('\n Provide a command, or use --last to take it from shell history.\n'));
|
|
52
|
+
console.log(chalk_1.default.dim(' Examples:'));
|
|
53
|
+
console.log(chalk_1.default.dim(' recall save "docker compose up -d"'));
|
|
54
|
+
console.log(chalk_1.default.dim(' recall save --last\n'));
|
|
55
|
+
process.exit(1);
|
|
65
56
|
}
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
console.log(chalk_1.default.yellow('\n This feature requires an upgrade.'));
|
|
70
|
-
console.log(chalk_1.default.dim(` Upgrade at ${chalk_1.default.white(err.body.upgrade)}\n`));
|
|
71
|
-
}
|
|
57
|
+
if (opts.group) {
|
|
58
|
+
console.log(chalk_1.default.yellow(' Groups sync with Pro cloud vault. Saved locally without a group.'));
|
|
59
|
+
console.log(chalk_1.default.dim(' After upgrading: recall sync\n'));
|
|
72
60
|
}
|
|
61
|
+
const tags = (0, tags_1.parseTags)(opts.tags);
|
|
62
|
+
const saved = (0, local_vault_1.saveLocalCommand)({
|
|
63
|
+
command,
|
|
64
|
+
name: opts.name,
|
|
65
|
+
tags,
|
|
66
|
+
});
|
|
67
|
+
console.log(chalk_1.default.green(` Saved locally${saved.name ? ` as "${saved.name}"` : ''}`));
|
|
68
|
+
console.log(chalk_1.default.dim(` Vault: ${local_vault_1.VAULT_FILE}`));
|
|
69
|
+
console.log(chalk_1.default.dim(' Sync to cloud (Pro): recall sync\n'));
|
|
73
70
|
});
|