@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.
@@ -0,0 +1,145 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.LastCommandError = void 0;
7
+ exports.isSelfSaveCommand = isSelfSaveCommand;
8
+ exports.stripZshExtendedPrefix = stripZshExtendedPrefix;
9
+ exports.findLastSaveableCommand = findLastSaveableCommand;
10
+ exports.detectShellKind = detectShellKind;
11
+ exports.historyFileCandidates = historyFileCandidates;
12
+ exports.readLastCommandFromHistoryFile = readLastCommandFromHistoryFile;
13
+ exports.getLastShellCommand = getLastShellCommand;
14
+ const fs_1 = __importDefault(require("fs"));
15
+ const os_1 = __importDefault(require("os"));
16
+ const path_1 = __importDefault(require("path"));
17
+ /** True if this history line is a recall/rec save invocation (skip so we don't save ourselves). */
18
+ function isSelfSaveCommand(line) {
19
+ const t = line.trim();
20
+ return /^(recall|rec)\s+save(\s|$)/.test(t);
21
+ }
22
+ /** Strip zsh extended-history prefix `: <unix>:<duration>;`. */
23
+ function stripZshExtendedPrefix(line) {
24
+ const m = line.match(/^:\s*\d+:\d+;(.*)$/);
25
+ return m ? m[1] : line;
26
+ }
27
+ /**
28
+ * Walk history lines newest-first and return the first saveable command.
29
+ * Caller should pass lines in file order (oldest → newest); we scan from the end.
30
+ */
31
+ function findLastSaveableCommand(lines) {
32
+ for (let i = lines.length - 1; i >= 0; i--) {
33
+ let raw = lines[i]?.replace(/\r$/, '') ?? '';
34
+ if (!raw.trim())
35
+ continue;
36
+ // bash HISTTIMEFORMAT lines are comments starting with #
37
+ if (/^#\d+$/.test(raw.trim()))
38
+ continue;
39
+ raw = stripZshExtendedPrefix(raw).trim();
40
+ if (!raw)
41
+ continue;
42
+ if (isSelfSaveCommand(raw))
43
+ continue;
44
+ return raw;
45
+ }
46
+ return null;
47
+ }
48
+ function detectShellKind(env = process.env, platform = process.platform) {
49
+ if (platform === 'win32') {
50
+ const shell = (env.SHELL || env.ComSpec || '').toLowerCase();
51
+ if (shell.includes('powershell') || shell.includes('pwsh'))
52
+ return 'powershell';
53
+ // Windows Terminal / VS Code often set PSModulePath when in PowerShell
54
+ if (env.PSModulePath && !shell.includes('cmd.exe')) {
55
+ if (env.TERM_PROGRAM || env.WT_SESSION || env.VSCODE_INJECTION) {
56
+ // Prefer PowerShell when clearly in a modern host without bash
57
+ if (!shell.includes('bash') && !shell.includes('zsh'))
58
+ return 'powershell';
59
+ }
60
+ }
61
+ if (shell.includes('bash') || shell.includes('zsh')) {
62
+ return shell.includes('zsh') ? 'zsh' : 'bash';
63
+ }
64
+ if (shell.includes('cmd.exe') || shell.endsWith('\\cmd'))
65
+ return 'cmd';
66
+ // Default Windows: PowerShell is the intended path; cmd is unsupported
67
+ if (!env.SHELL)
68
+ return 'powershell';
69
+ return 'cmd';
70
+ }
71
+ const shell = (env.SHELL || '').toLowerCase();
72
+ if (shell.includes('zsh'))
73
+ return 'zsh';
74
+ if (shell.includes('bash'))
75
+ return 'bash';
76
+ if (shell.includes('pwsh') || shell.includes('powershell'))
77
+ return 'powershell';
78
+ return 'unknown';
79
+ }
80
+ function historyFileCandidates(kind, env = process.env, home = os_1.default.homedir()) {
81
+ if (env.HISTFILE)
82
+ return [env.HISTFILE];
83
+ switch (kind) {
84
+ case 'zsh':
85
+ return [path_1.default.join(home, '.zsh_history')];
86
+ case 'bash':
87
+ return [path_1.default.join(home, '.bash_history')];
88
+ case 'powershell': {
89
+ const candidates = [];
90
+ if (env.APPDATA) {
91
+ candidates.push(path_1.default.join(env.APPDATA, 'Microsoft', 'Windows', 'PowerShell', 'PSReadLine', 'ConsoleHost_history.txt'), path_1.default.join(env.APPDATA, 'Microsoft', 'PowerShell', 'PSReadLine', 'ConsoleHost_history.txt'));
92
+ }
93
+ candidates.push(path_1.default.join(home, '.local', 'share', 'powershell', 'PSReadLine', 'ConsoleHost_history.txt'), path_1.default.join(home, 'AppData', 'Roaming', 'Microsoft', 'Windows', 'PowerShell', 'PSReadLine', 'ConsoleHost_history.txt'));
94
+ return candidates;
95
+ }
96
+ default:
97
+ return [];
98
+ }
99
+ }
100
+ function readLastCommandFromHistoryFile(filePath) {
101
+ if (!fs_1.default.existsSync(filePath))
102
+ return null;
103
+ const text = fs_1.default.readFileSync(filePath, 'utf8');
104
+ const lines = text.split('\n');
105
+ return findLastSaveableCommand(lines);
106
+ }
107
+ class LastCommandError extends Error {
108
+ code;
109
+ constructor(message, code) {
110
+ super(message);
111
+ this.code = code;
112
+ this.name = 'LastCommandError';
113
+ }
114
+ }
115
+ exports.LastCommandError = LastCommandError;
116
+ /**
117
+ * Resolve the last typed shell command from on-disk history.
118
+ * Same-session works when the shell appends history as you go (typical zsh / PSReadLine).
119
+ * Bash may need `history -a` first if the file is stale.
120
+ */
121
+ function getLastShellCommand(env = process.env, platform = process.platform, home = os_1.default.homedir()) {
122
+ const shell = detectShellKind(env, platform);
123
+ if (shell === 'cmd') {
124
+ throw new LastCommandError('save --last is not supported in cmd.exe. Use PowerShell, Git Bash, or WSL — or paste the command: recall save "your command"', 'unsupported');
125
+ }
126
+ if (shell === 'unknown') {
127
+ throw new LastCommandError('Could not detect your shell. Use zsh, bash, or PowerShell — or paste the command: recall save "your command"', 'unsupported');
128
+ }
129
+ const files = historyFileCandidates(shell, env, home);
130
+ for (const file of files) {
131
+ try {
132
+ const command = readLastCommandFromHistoryFile(file);
133
+ if (command) {
134
+ return { command, source: file, shell };
135
+ }
136
+ }
137
+ catch {
138
+ // try next candidate
139
+ }
140
+ }
141
+ const tip = shell === 'bash'
142
+ ? ' If you just ran the command in this session, try: history -a && recall save --last'
143
+ : '';
144
+ throw new LastCommandError(`No previous command found in shell history.${tip}`, 'not_found');
145
+ }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@devkitvault/recall",
3
- "version": "1.2.6",
4
- "description": "recall CLI — AI terminal copilot with a personal command vault",
3
+ "version": "1.2.9",
4
+ "description": "recall CLI — personal command vault for your terminal (local-first)",
5
5
  "keywords": [
6
6
  "cli",
7
7
  "shell",
@@ -19,12 +19,11 @@
19
19
  "license": "MIT",
20
20
  "homepage": "https://recall.devkitvault.com",
21
21
  "bugs": {
22
- "url": "https://github.com/devkitvault/recall/issues"
22
+ "url": "https://github.com/devkitvault/recall-cli/issues"
23
23
  },
24
24
  "repository": {
25
25
  "type": "git",
26
- "url": "git+https://github.com/devkitvault/recall.git",
27
- "directory": "packages/npm-cli"
26
+ "url": "git+https://github.com/devkitvault/recall-cli.git"
28
27
  },
29
28
  "bin": {
30
29
  "recall": "dist/index.js",