@cortexmemory/cli 0.28.0 → 0.28.1

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,196 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Cortex CLI Postinstall Script
5
+ *
6
+ * Automatically installs shell completion for the cortex CLI.
7
+ * Supports zsh, bash, and fish shells.
8
+ *
9
+ * This script runs after `npm install -g @cortexmemory/cli`
10
+ */
11
+
12
+ import { existsSync, mkdirSync, readFileSync, writeFileSync, appendFileSync, copyFileSync } from 'fs';
13
+ import { join, dirname } from 'path';
14
+ import { fileURLToPath } from 'url';
15
+ import { homedir } from 'os';
16
+
17
+ const __dirname = dirname(fileURLToPath(import.meta.url));
18
+ const home = homedir();
19
+
20
+ // Marker comments for identifying our additions
21
+ const MARKER_START = '# >>> cortex completion >>>';
22
+ const MARKER_END = '# <<< cortex completion <<<';
23
+
24
+ /**
25
+ * Get the completion scripts directory (relative to this script)
26
+ */
27
+ function getCompletionsDir() {
28
+ return join(__dirname, 'completions');
29
+ }
30
+
31
+ /**
32
+ * Get the target directory for completion scripts (~/.cortex/completions/)
33
+ */
34
+ function getTargetDir() {
35
+ return join(home, '.cortex', 'completions');
36
+ }
37
+
38
+ /**
39
+ * Ensure directory exists
40
+ */
41
+ function ensureDir(dir) {
42
+ if (!existsSync(dir)) {
43
+ mkdirSync(dir, { recursive: true });
44
+ }
45
+ }
46
+
47
+ /**
48
+ * Check if a file already contains our completion setup
49
+ */
50
+ function hasCompletionSetup(filePath) {
51
+ if (!existsSync(filePath)) {
52
+ return false;
53
+ }
54
+ const content = readFileSync(filePath, 'utf-8');
55
+ return content.includes(MARKER_START);
56
+ }
57
+
58
+ /**
59
+ * Detect the user's shell
60
+ */
61
+ function detectShell() {
62
+ const shell = process.env.SHELL || '';
63
+ if (shell.includes('zsh')) return 'zsh';
64
+ if (shell.includes('bash')) return 'bash';
65
+ if (shell.includes('fish')) return 'fish';
66
+ return null;
67
+ }
68
+
69
+ /**
70
+ * Get the shell RC file path
71
+ */
72
+ function getShellRcPath(shell) {
73
+ switch (shell) {
74
+ case 'zsh':
75
+ return join(home, '.zshrc');
76
+ case 'bash': {
77
+ // Check for .bashrc first, then .bash_profile
78
+ const bashrc = join(home, '.bashrc');
79
+ const bashProfile = join(home, '.bash_profile');
80
+ if (existsSync(bashrc)) return bashrc;
81
+ if (existsSync(bashProfile)) return bashProfile;
82
+ return bashrc; // Default to .bashrc
83
+ }
84
+ case 'fish':
85
+ return join(home, '.config', 'fish', 'config.fish');
86
+ default:
87
+ return null;
88
+ }
89
+ }
90
+
91
+ /**
92
+ * Get the source line for shell RC file
93
+ */
94
+ function getSourceLine(shell, targetPath) {
95
+ switch (shell) {
96
+ case 'zsh':
97
+ return `[[ -f "${targetPath}" ]] && source "${targetPath}"`;
98
+ case 'bash':
99
+ return `[[ -f "${targetPath}" ]] && source "${targetPath}"`;
100
+ case 'fish':
101
+ return `test -f "${targetPath}"; and source "${targetPath}"`;
102
+ default:
103
+ return null;
104
+ }
105
+ }
106
+
107
+ /**
108
+ * Install completion for a specific shell
109
+ */
110
+ function installCompletion(shell) {
111
+ const completionsDir = getCompletionsDir();
112
+ const targetDir = getTargetDir();
113
+
114
+ // Source completion script
115
+ const sourceFile = join(completionsDir, `cortex.${shell}`);
116
+ if (!existsSync(sourceFile)) {
117
+ return false;
118
+ }
119
+
120
+ // Ensure target directory exists
121
+ ensureDir(targetDir);
122
+
123
+ // Copy completion script to target
124
+ const targetFile = join(targetDir, `cortex.${shell}`);
125
+ copyFileSync(sourceFile, targetFile);
126
+
127
+ // Get shell RC file
128
+ const rcPath = getShellRcPath(shell);
129
+ if (!rcPath) {
130
+ return false;
131
+ }
132
+
133
+ // Check if already installed
134
+ if (hasCompletionSetup(rcPath)) {
135
+ return true; // Already installed
136
+ }
137
+
138
+ // Ensure RC file's parent directory exists (for fish)
139
+ ensureDir(dirname(rcPath));
140
+
141
+ // Create RC file if it doesn't exist
142
+ if (!existsSync(rcPath)) {
143
+ writeFileSync(rcPath, '', 'utf-8');
144
+ }
145
+
146
+ // Add source line to RC file
147
+ const sourceLine = getSourceLine(shell, targetFile);
148
+ if (!sourceLine) {
149
+ return false;
150
+ }
151
+
152
+ const completionBlock = `
153
+ ${MARKER_START}
154
+ ${sourceLine}
155
+ ${MARKER_END}
156
+ `;
157
+
158
+ appendFileSync(rcPath, completionBlock, 'utf-8');
159
+ return true;
160
+ }
161
+
162
+ /**
163
+ * Main installation function
164
+ */
165
+ function main() {
166
+ // Skip if running in CI or non-interactive environment
167
+ if (process.env.CI || process.env.CORTEX_SKIP_COMPLETION) {
168
+ return;
169
+ }
170
+
171
+ // Detect shell
172
+ const shell = detectShell();
173
+ if (!shell) {
174
+ // Unknown shell, skip silently
175
+ return;
176
+ }
177
+
178
+ try {
179
+ // Install completion for detected shell
180
+ installCompletion(shell);
181
+
182
+ // Also try to install for other common shells if their RC files exist
183
+ const otherShells = ['zsh', 'bash', 'fish'].filter(s => s !== shell);
184
+ for (const otherShell of otherShells) {
185
+ const rcPath = getShellRcPath(otherShell);
186
+ if (rcPath && existsSync(rcPath)) {
187
+ installCompletion(otherShell);
188
+ }
189
+ }
190
+ } catch {
191
+ // Silently fail - completion is not critical
192
+ // User can manually run `cortex completion <shell>` if needed
193
+ }
194
+ }
195
+
196
+ main();
@@ -0,0 +1,121 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Cortex CLI Preuninstall Script
5
+ *
6
+ * Removes shell completion configuration when the CLI is uninstalled.
7
+ * Cleans up ~/.cortex/completions/ and removes source lines from shell RC files.
8
+ *
9
+ * This script runs before `npm uninstall -g @cortexmemory/cli`
10
+ */
11
+
12
+ import { existsSync, readFileSync, writeFileSync, rmSync, readdirSync } from 'fs';
13
+ import { join } from 'path';
14
+ import { homedir } from 'os';
15
+
16
+ const home = homedir();
17
+
18
+ // Marker comments for identifying our additions
19
+ const MARKER_START = '# >>> cortex completion >>>';
20
+ const MARKER_END = '# <<< cortex completion <<<';
21
+
22
+ /**
23
+ * Get the target directory for completion scripts (~/.cortex/completions/)
24
+ */
25
+ function getTargetDir() {
26
+ return join(home, '.cortex', 'completions');
27
+ }
28
+
29
+ /**
30
+ * Get shell RC file paths to clean up
31
+ */
32
+ function getShellRcPaths() {
33
+ return [
34
+ join(home, '.zshrc'),
35
+ join(home, '.bashrc'),
36
+ join(home, '.bash_profile'),
37
+ join(home, '.config', 'fish', 'config.fish'),
38
+ ];
39
+ }
40
+
41
+ /**
42
+ * Remove completion block from a shell RC file
43
+ */
44
+ function removeCompletionFromRc(rcPath) {
45
+ if (!existsSync(rcPath)) {
46
+ return;
47
+ }
48
+
49
+ const content = readFileSync(rcPath, 'utf-8');
50
+
51
+ // Check if our completion setup exists
52
+ if (!content.includes(MARKER_START)) {
53
+ return;
54
+ }
55
+
56
+ // Remove the completion block (including markers and content between them)
57
+ const regex = new RegExp(
58
+ `\\n?${escapeRegex(MARKER_START)}[\\s\\S]*?${escapeRegex(MARKER_END)}\\n?`,
59
+ 'g'
60
+ );
61
+
62
+ const newContent = content.replace(regex, '\n');
63
+
64
+ // Write cleaned content back
65
+ writeFileSync(rcPath, newContent, 'utf-8');
66
+ }
67
+
68
+ /**
69
+ * Escape special regex characters
70
+ */
71
+ function escapeRegex(string) {
72
+ return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
73
+ }
74
+
75
+ /**
76
+ * Remove completion scripts directory
77
+ */
78
+ function removeCompletionsDir() {
79
+ const targetDir = getTargetDir();
80
+ if (existsSync(targetDir)) {
81
+ rmSync(targetDir, { recursive: true, force: true });
82
+ }
83
+
84
+ // Also remove parent .cortex directory if empty
85
+ const cortexDir = join(home, '.cortex');
86
+ if (existsSync(cortexDir)) {
87
+ try {
88
+ const files = readdirSync(cortexDir);
89
+ if (files.length === 0) {
90
+ rmSync(cortexDir, { recursive: true, force: true });
91
+ }
92
+ } catch {
93
+ // Directory not empty or other error, leave it
94
+ }
95
+ }
96
+ }
97
+
98
+ /**
99
+ * Main uninstall function
100
+ */
101
+ function main() {
102
+ // Skip if running in CI
103
+ if (process.env.CI || process.env.CORTEX_SKIP_COMPLETION) {
104
+ return;
105
+ }
106
+
107
+ try {
108
+ // Remove completion setup from all shell RC files
109
+ const rcPaths = getShellRcPaths();
110
+ for (const rcPath of rcPaths) {
111
+ removeCompletionFromRc(rcPath);
112
+ }
113
+
114
+ // Remove completion scripts directory
115
+ removeCompletionsDir();
116
+ } catch {
117
+ // Silently fail - cleanup is not critical
118
+ }
119
+ }
120
+
121
+ main();