envprobe 1.0.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.
@@ -0,0 +1,135 @@
1
+ /**
2
+ * Autocomplete functionality for REPL
3
+ * Provides intelligent tab completion for commands, options, and file paths
4
+ */
5
+
6
+ import { readdirSync, statSync } from 'fs';
7
+ import { join, dirname, basename } from 'path';
8
+
9
+ /**
10
+ * Get autocomplete suggestions for the current input
11
+ */
12
+ export function getCompletions(line) {
13
+ const trimmed = line.trim();
14
+
15
+ // Command completion
16
+ if (trimmed.startsWith(':') || trimmed.startsWith('.')) {
17
+ return getCommandCompletions(trimmed.slice(1));
18
+ }
19
+
20
+ // Flag completion
21
+ if (trimmed.includes('--')) {
22
+ return getFlagCompletions(trimmed);
23
+ }
24
+
25
+ // Path completion
26
+ return getPathCompletions(trimmed);
27
+ }
28
+
29
+ /**
30
+ * Get command completions
31
+ */
32
+ function getCommandCompletions(partial) {
33
+ const commands = [
34
+ 'help',
35
+ 'exit',
36
+ 'quit',
37
+ 'history',
38
+ 'clear',
39
+ 'config',
40
+ 'set',
41
+ 'get',
42
+ 'results',
43
+ 'last',
44
+ 'watch',
45
+ 'save',
46
+ 'load',
47
+ ];
48
+
49
+ return commands
50
+ .filter(cmd => cmd.startsWith(partial))
51
+ .map(cmd => `:${cmd}`);
52
+ }
53
+
54
+ /**
55
+ * Get flag completions
56
+ */
57
+ function getFlagCompletions(line) {
58
+ const flags = [
59
+ '--env-file',
60
+ '--format',
61
+ '--fail-on',
62
+ '--ignore',
63
+ '--no-color',
64
+ '--quiet',
65
+ '--help',
66
+ '--version',
67
+ '--watch',
68
+ '--config',
69
+ ];
70
+
71
+ const lastWord = line.split(/\s+/).pop();
72
+
73
+ if (!lastWord.startsWith('--')) {
74
+ return [];
75
+ }
76
+
77
+ return flags.filter(flag => flag.startsWith(lastWord));
78
+ }
79
+
80
+ /**
81
+ * Get path completions
82
+ */
83
+ function getPathCompletions(line) {
84
+ try {
85
+ const words = line.split(/\s+/);
86
+ const lastWord = words[words.length - 1] || '.';
87
+
88
+ let dir = '.';
89
+ let prefix = '';
90
+
91
+ if (lastWord.includes('/') || lastWord.includes('\\')) {
92
+ dir = dirname(lastWord);
93
+ prefix = basename(lastWord);
94
+ } else {
95
+ prefix = lastWord;
96
+ }
97
+
98
+ const entries = readdirSync(dir);
99
+
100
+ return entries
101
+ .filter(entry => entry.startsWith(prefix))
102
+ .map(entry => {
103
+ const fullPath = join(dir, entry);
104
+ try {
105
+ const isDir = statSync(fullPath).isDirectory();
106
+ return isDir ? `${entry}/` : entry;
107
+ } catch {
108
+ return entry;
109
+ }
110
+ })
111
+ .slice(0, 20); // Limit to 20 suggestions
112
+ } catch {
113
+ return [];
114
+ }
115
+ }
116
+
117
+ /**
118
+ * Setup readline autocomplete
119
+ */
120
+ export function setupAutocomplete(rl) {
121
+ rl.on('line', (line) => {
122
+ // Store in history
123
+ if (line.trim()) {
124
+ rl.history.unshift(line);
125
+ }
126
+ });
127
+
128
+ // Custom completer function
129
+ const completer = (line) => {
130
+ const completions = getCompletions(line);
131
+ return [completions, line];
132
+ };
133
+
134
+ return completer;
135
+ }
package/src/cache.js ADDED
@@ -0,0 +1,114 @@
1
+ /**
2
+ * Caching layer for improved performance
3
+ * Caches file scan results and analysis to speed up repeated runs
4
+ */
5
+
6
+ import { createHash } from 'crypto';
7
+ import { readFileSync, writeFileSync, existsSync, mkdirSync, statSync } from 'fs';
8
+ import { join } from 'path';
9
+ import { tmpdir } from 'os';
10
+
11
+ /**
12
+ * Cache manager
13
+ */
14
+ export class Cache {
15
+ constructor(namespace = 'envcheck') {
16
+ this.namespace = namespace;
17
+ this.cacheDir = join(tmpdir(), namespace);
18
+ this.ensureCacheDir();
19
+ }
20
+
21
+ ensureCacheDir() {
22
+ if (!existsSync(this.cacheDir)) {
23
+ mkdirSync(this.cacheDir, { recursive: true });
24
+ }
25
+ }
26
+
27
+ getCacheKey(data) {
28
+ const hash = createHash('sha256');
29
+ hash.update(JSON.stringify(data));
30
+ return hash.digest('hex');
31
+ }
32
+
33
+ getCachePath(key) {
34
+ return join(this.cacheDir, `${key}.json`);
35
+ }
36
+
37
+ get(key, maxAge = 3600000) {
38
+ try {
39
+ const cacheKey = this.getCacheKey(key);
40
+ const cachePath = this.getCachePath(cacheKey);
41
+
42
+ if (!existsSync(cachePath)) {
43
+ return null;
44
+ }
45
+
46
+ const stats = statSync(cachePath);
47
+ const age = Date.now() - stats.mtimeMs;
48
+
49
+ if (age > maxAge) {
50
+ return null;
51
+ }
52
+
53
+ const content = readFileSync(cachePath, 'utf-8');
54
+ return JSON.parse(content);
55
+ } catch {
56
+ return null;
57
+ }
58
+ }
59
+
60
+ set(key, value) {
61
+ try {
62
+ const cacheKey = this.getCacheKey(key);
63
+ const cachePath = this.getCachePath(cacheKey);
64
+ const content = JSON.stringify(value);
65
+ writeFileSync(cachePath, content, 'utf-8');
66
+ return true;
67
+ } catch {
68
+ return false;
69
+ }
70
+ }
71
+
72
+ clear() {
73
+ try {
74
+ const { readdirSync, unlinkSync } = require('fs');
75
+ const files = readdirSync(this.cacheDir);
76
+
77
+ for (const file of files) {
78
+ unlinkSync(join(this.cacheDir, file));
79
+ }
80
+
81
+ return true;
82
+ } catch {
83
+ return false;
84
+ }
85
+ }
86
+
87
+ has(key) {
88
+ const cacheKey = this.getCacheKey(key);
89
+ const cachePath = this.getCachePath(cacheKey);
90
+ return existsSync(cachePath);
91
+ }
92
+ }
93
+
94
+ /**
95
+ * Create a cached version of a function
96
+ */
97
+ export function cached(fn, options = {}) {
98
+ const cache = new Cache(options.namespace);
99
+ const maxAge = options.maxAge || 3600000;
100
+
101
+ return async function (...args) {
102
+ const cacheKey = { fn: fn.name, args };
103
+
104
+ const cached = cache.get(cacheKey, maxAge);
105
+ if (cached !== null) {
106
+ return cached;
107
+ }
108
+
109
+ const result = await fn(...args);
110
+ cache.set(cacheKey, result);
111
+
112
+ return result;
113
+ };
114
+ }