fchek 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.
Files changed (66) hide show
  1. package/README.md +64 -0
  2. package/bin/fchek.js +107 -0
  3. package/lib/api.js +110 -0
  4. package/lib/audit.js +211 -0
  5. package/lib/bench.js +248 -0
  6. package/lib/config.js +191 -0
  7. package/lib/context.js +356 -0
  8. package/lib/convention.js +526 -0
  9. package/lib/coverage.js +604 -0
  10. package/lib/db.js +135 -0
  11. package/lib/deps-check.js +264 -0
  12. package/lib/deps.js +374 -0
  13. package/lib/docker.js +84 -0
  14. package/lib/doctor.js +149 -0
  15. package/lib/dom.js +226 -0
  16. package/lib/fuzz.js +470 -0
  17. package/lib/git.js +290 -0
  18. package/lib/goto.js +544 -0
  19. package/lib/launch.js +182 -0
  20. package/lib/lint.js +624 -0
  21. package/lib/new_features.test.js +181 -0
  22. package/lib/output.js +46 -0
  23. package/lib/port.js +173 -0
  24. package/lib/process.js +228 -0
  25. package/lib/profile.js +453 -0
  26. package/lib/python.js +41 -0
  27. package/lib/race.js +186 -0
  28. package/lib/registry.js +179 -0
  29. package/lib/repl.js +135 -0
  30. package/lib/run.js +403 -0
  31. package/lib/screenshot.js +152 -0
  32. package/lib/secrets.js +257 -0
  33. package/lib/state.js +219 -0
  34. package/lib/test.js +471 -0
  35. package/lib/vuln.js +253 -0
  36. package/lib/watch.js +240 -0
  37. package/lib/winlog.js +123 -0
  38. package/package.json +27 -0
  39. package/skills/ACTIVATE.md +274 -0
  40. package/skills/README.md +163 -0
  41. package/skills/agent.md +444 -0
  42. package/skills/api.md +47 -0
  43. package/skills/bench.md +117 -0
  44. package/skills/context.md +116 -0
  45. package/skills/convention.md +143 -0
  46. package/skills/coverage.md +99 -0
  47. package/skills/csharp.md +97 -0
  48. package/skills/db.md +66 -0
  49. package/skills/deps-check.md +135 -0
  50. package/skills/deps.md +143 -0
  51. package/skills/docker.md +61 -0
  52. package/skills/dom.md +56 -0
  53. package/skills/fuzz.md +167 -0
  54. package/skills/goto.md +111 -0
  55. package/skills/lint.md +123 -0
  56. package/skills/port.md +57 -0
  57. package/skills/profile.md +91 -0
  58. package/skills/race.md +117 -0
  59. package/skills/repl.md +81 -0
  60. package/skills/rules.md +318 -0
  61. package/skills/run.md +135 -0
  62. package/skills/secrets.md +170 -0
  63. package/skills/security.md +360 -0
  64. package/skills/state.md +261 -0
  65. package/skills/vuln.md +57 -0
  66. package/skills/windows.md +320 -0
@@ -0,0 +1,179 @@
1
+ 'use strict';
2
+
3
+ const { spawnSync } = require('child_process');
4
+ const { output, ok, fail } = require('./output');
5
+
6
+ const HELP = `
7
+ fchek registry <action> <key> [value_name] [data] [--type=REG_SZ|REG_DWORD]
8
+
9
+ Read and write Windows Registry.
10
+
11
+ Actions:
12
+ get <key> [value_name] Read key or specific value
13
+ set <key> <name> <data> Write a value
14
+ delete <key> [value_name] Delete key or value
15
+ exists <key> [value_name] Check if exists
16
+
17
+ Examples:
18
+ fchek registry get HKCU\\Software\\Vertex
19
+ fchek registry get HKCU\\Software\\Vertex Theme
20
+ fchek registry set HKCU\\Software\\Vertex Theme dark
21
+ fchek registry exists HKCU\\Software\\Vertex
22
+ fchek registry delete HKCU\\Software\\Vertex
23
+ `.trim();
24
+
25
+ // Run a PowerShell script file (avoids all escaping issues)
26
+ function runScript(lines, timeoutMs) {
27
+ const os = require('os');
28
+ const path = require('path');
29
+ const fs = require('fs');
30
+ const script = lines.join('\r\n');
31
+ const tmp = path.join(os.tmpdir(), 'fchek_reg_' + process.pid + '.ps1');
32
+ fs.writeFileSync(tmp, script, 'utf8');
33
+ const res = spawnSync('powershell', [
34
+ '-NoProfile', '-NonInteractive', '-ExecutionPolicy', 'Bypass', '-File', tmp,
35
+ ], { encoding: 'utf8', timeout: timeoutMs || 10000, windowsHide: true });
36
+ try { fs.unlinkSync(tmp); } catch {}
37
+ return res;
38
+ }
39
+
40
+ function toPs(key) {
41
+ return key
42
+ .replace(/^HKEY_CURRENT_USER\\/i, 'HKCU:\\')
43
+ .replace(/^HKEY_LOCAL_MACHINE\\/i, 'HKLM:\\')
44
+ .replace(/^HKEY_CLASSES_ROOT\\/i, 'HKCR:\\')
45
+ .replace(/^HKEY_USERS\\/i, 'HKU:\\')
46
+ .replace(/^HKCU\\/i, 'HKCU:\\')
47
+ .replace(/^HKLM\\/i, 'HKLM:\\');
48
+ }
49
+
50
+ function parseResult(res) {
51
+ const raw = (res.stdout || '').trim();
52
+ if (!raw) return null;
53
+ const lines = raw.split('\n').map(l => l.trim()).filter(Boolean);
54
+ for (let i = lines.length - 1; i >= 0; i--) {
55
+ if (lines[i].startsWith('{') || lines[i].startsWith('[')) {
56
+ try { return JSON.parse(lines[i]); } catch {}
57
+ }
58
+ }
59
+ return null;
60
+ }
61
+
62
+ async function run(args) {
63
+ if (args.length === 0 || args[0] === '--help') { console.log(HELP); return; }
64
+ if (process.platform !== 'win32') return output(fail('fchek registry is Windows-only.'));
65
+
66
+ const action = args[0];
67
+ const key = args[1];
68
+ if (!key) return output(fail('Registry key required.'));
69
+
70
+ const psPath = toPs(key);
71
+
72
+ if (action === 'get') {
73
+ const vname = args[2] || null;
74
+ const lines = vname ? [
75
+ '$ErrorActionPreference = "SilentlyContinue"',
76
+ '$p = "' + psPath.replace(/"/g, '`"') + '"',
77
+ '$n = "' + (vname).replace(/"/g, '`"') + '"',
78
+ '$v = Get-ItemProperty -Path $p -Name $n -ErrorAction SilentlyContinue',
79
+ 'if ($v) {',
80
+ ' $d = $v.$n',
81
+ ' Write-Output (@{exists=$true; key="' + key.replace(/"/g, '\\"') + '"; value=$n; data="$d"} | ConvertTo-Json -Compress)',
82
+ '} else {',
83
+ ' Write-Output \'{"exists":false,"error":"Value not found"}\'',
84
+ '}',
85
+ ] : [
86
+ '$ErrorActionPreference = "SilentlyContinue"',
87
+ '$p = "' + psPath.replace(/"/g, '`"') + '"',
88
+ '$item = Get-Item -Path $p -ErrorAction SilentlyContinue',
89
+ 'if ($item) {',
90
+ ' $vals = @{}',
91
+ ' foreach ($n in $item.GetValueNames()) { $vals[$n] = "$($item.GetValue($n))" }',
92
+ ' $subs = @($item.GetSubKeyNames())',
93
+ ' @{exists=$true; key="' + key.replace(/"/g, '\\"') + '"; values=$vals; subkeys=$subs} | ConvertTo-Json -Depth 3 -Compress',
94
+ '} else {',
95
+ ' Write-Output \'{"exists":false,"error":"Key not found"}\'',
96
+ '}',
97
+ ];
98
+
99
+ const res = runScript(lines);
100
+ const data = parseResult(res);
101
+ if (!data) return output(fail('Registry read failed: ' + (res.stderr || res.stdout || '').slice(0, 300)));
102
+ if (!data.exists) return output(fail(data.error || 'Not found'));
103
+ output(ok(data));
104
+
105
+ } else if (action === 'set') {
106
+ const vname = args[2];
107
+ const vdata = args[3];
108
+ const type = (args.find(a => a.startsWith('--type=')) || '--type=REG_SZ').replace('--type=', '');
109
+ if (!vname || vdata === undefined) return output(fail('Usage: fchek registry set <key> <name> <data>'));
110
+
111
+ // Map REG_* names to PowerShell RegistryValueKind names
112
+ const typeMap = {
113
+ 'REG_SZ': 'String',
114
+ 'REG_DWORD': 'DWord',
115
+ 'REG_QWORD': 'QWord',
116
+ 'REG_BINARY': 'Binary',
117
+ 'REG_EXPAND_SZ': 'ExpandString',
118
+ 'REG_MULTI_SZ': 'MultiString',
119
+ };
120
+ const psType = typeMap[type.toUpperCase()] || type;
121
+
122
+ const lines = [
123
+ '$ErrorActionPreference = "Stop"',
124
+ 'try {',
125
+ ' $p = "' + psPath.replace(/"/g, '`"') + '"',
126
+ ' if (!(Test-Path $p)) { New-Item -Path $p -Force | Out-Null }',
127
+ ' Set-ItemProperty -Path $p -Name "' + vname.replace(/"/g, '`"') + '" -Value "' + vdata.replace(/"/g, '`"') + '" -Type "' + psType + '" -Force',
128
+ ' Write-Output \'{"success":true}\'',
129
+ '} catch {',
130
+ ' Write-Output (@{success=$false; error=$_.Exception.Message} | ConvertTo-Json -Compress)',
131
+ '}',
132
+ ];
133
+
134
+ const res = runScript(lines);
135
+ const data = parseResult(res);
136
+ if (!data) return output(fail('Set failed: ' + (res.stderr || res.stdout || '').slice(0, 300)));
137
+ if (!data.success) return output(fail(data.error || 'Set failed'));
138
+ output(ok({ success: true, key, value: vname, data: vdata, type }));
139
+
140
+ } else if (action === 'delete') {
141
+ const vname = args[2] || null;
142
+ const lines = vname ? [
143
+ 'try {',
144
+ ' Remove-ItemProperty -Path "' + psPath.replace(/"/g, '`"') + '" -Name "' + vname.replace(/"/g, '`"') + '" -Force -ErrorAction Stop',
145
+ ' Write-Output \'{"deleted":true}\'',
146
+ '} catch { Write-Output \'{"deleted":false}\' }',
147
+ ] : [
148
+ 'try {',
149
+ ' Remove-Item -Path "' + psPath.replace(/"/g, '`"') + '" -Recurse -Force -ErrorAction Stop',
150
+ ' Write-Output \'{"deleted":true}\'',
151
+ '} catch { Write-Output \'{"deleted":false}\' }',
152
+ ];
153
+
154
+ const res = runScript(lines);
155
+ const data = parseResult(res);
156
+ if (!data || !data.deleted) return output(fail('Delete failed: ' + (res.stderr || res.stdout || '').slice(0, 200)));
157
+ output(ok({ deleted: true, key, value: vname }));
158
+
159
+ } else if (action === 'exists') {
160
+ const vname = args[2] || null;
161
+ const lines = vname ? [
162
+ '$e = (Get-ItemProperty -Path "' + psPath.replace(/"/g, '`"') + '" -Name "' + vname.replace(/"/g, '`"') + '" -ErrorAction SilentlyContinue) -ne $null',
163
+ 'Write-Output (@{exists=$e} | ConvertTo-Json -Compress)',
164
+ ] : [
165
+ '$e = Test-Path "' + psPath.replace(/"/g, '`"') + '"',
166
+ 'Write-Output (@{exists=$e} | ConvertTo-Json -Compress)',
167
+ ];
168
+
169
+ const res = runScript(lines);
170
+ const data = parseResult(res);
171
+ if (!data) return output(fail('Registry check failed: ' + (res.stderr || res.stdout || '').slice(0, 200)));
172
+ output(ok({ exists: data.exists, key, value: vname }));
173
+
174
+ } else {
175
+ output(fail('Unknown action: "' + action + '". Valid: get, set, delete, exists'));
176
+ }
177
+ }
178
+
179
+ module.exports = { run };
package/lib/repl.js ADDED
@@ -0,0 +1,135 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * repl.js — interactive REPL with live in-memory state.
5
+ *
6
+ * Difference from state.js:
7
+ * repl = in-process memory (lives only while this process runs)
8
+ * state = disk-based memory (survives restarts)
9
+ *
10
+ * Use repl when you need fast iterative work in one session.
11
+ * Use state when you need context to persist across sessions.
12
+ */
13
+
14
+ const readline = require('readline');
15
+ const path = require('path');
16
+ const { ok, fail, output } = require('./output');
17
+
18
+ const BANNER = `
19
+ ╔══════════════════════════════════════════╗
20
+ ║ fchek repl — interactive mode ║
21
+ ║ type "help" for commands, "exit" to quit ║
22
+ ╚══════════════════════════════════════════╝
23
+ `.trim();
24
+
25
+ const REPL_HELP = `
26
+ Available commands (same as fchek CLI, but run interactively):
27
+
28
+ profile <file> [app|web] Profile code
29
+ race <file.cpp> [--asan] Check sanitizers
30
+ goto <file:line> LSP definition + references
31
+ state <action> [key] [val] Persistent disk state
32
+ set <key> <value> Set in-session variable (memory only)
33
+ get <key> Get in-session variable
34
+ vars List all in-session variables
35
+ clear Clear screen
36
+ help This message
37
+ exit / quit Exit REPL
38
+ `.trim();
39
+
40
+ async function run(args) {
41
+ // In-memory session variables (lost when REPL exits)
42
+ const sessionVars = {};
43
+
44
+ const rl = readline.createInterface({
45
+ input: process.stdin,
46
+ output: process.stdout,
47
+ prompt: 'fchek> ',
48
+ historySize: 100,
49
+ completer: (line) => {
50
+ const completions = ['profile', 'race', 'goto', 'state', 'set', 'get', 'vars', 'help', 'exit', 'clear'];
51
+ const hits = completions.filter(c => c.startsWith(line));
52
+ return [hits.length ? hits : completions, line];
53
+ },
54
+ });
55
+
56
+ console.log(BANNER);
57
+ rl.prompt();
58
+
59
+ rl.on('line', async (rawLine) => {
60
+ const line = rawLine.trim();
61
+ if (!line) { rl.prompt(); return; }
62
+
63
+ const parts = line.split(/\s+/);
64
+ const cmd = parts[0].toLowerCase();
65
+ const rest = parts.slice(1);
66
+
67
+ try {
68
+ switch (cmd) {
69
+ case 'exit':
70
+ case 'quit':
71
+ console.log('Bye.');
72
+ rl.close();
73
+ process.exit(0);
74
+ break;
75
+
76
+ case 'help':
77
+ console.log('\n' + REPL_HELP + '\n');
78
+ break;
79
+
80
+ case 'clear':
81
+ process.stdout.write('\x1Bc');
82
+ break;
83
+
84
+ case 'set': {
85
+ const key = rest[0];
86
+ const value = rest.slice(1).join(' ');
87
+ if (!key) { console.log('Usage: set <key> <value>'); break; }
88
+ sessionVars[key] = value;
89
+ console.log(JSON.stringify(ok({ set: key, value }, 'repl')));
90
+ break;
91
+ }
92
+
93
+ case 'get': {
94
+ const key = rest[0];
95
+ if (!key) { console.log('Usage: get <key>'); break; }
96
+ if (!(key in sessionVars)) {
97
+ console.log(JSON.stringify(fail(`No session var: "${key}"`, 'repl')));
98
+ } else {
99
+ console.log(JSON.stringify(ok({ key, value: sessionVars[key] }, 'repl')));
100
+ }
101
+ break;
102
+ }
103
+
104
+ case 'vars':
105
+ console.log(JSON.stringify(ok({ session_vars: sessionVars }, 'repl')));
106
+ break;
107
+
108
+ // Delegate to lib/ commands — same as CLI
109
+ case 'profile':
110
+ case 'race':
111
+ case 'goto':
112
+ case 'state': {
113
+ const handler = require(`./${cmd}`);
114
+ // Redirect console.log output captured inline
115
+ await handler.run(rest);
116
+ break;
117
+ }
118
+
119
+ default:
120
+ console.log(JSON.stringify(fail(`Unknown command: "${cmd}". Type "help".`, 'repl')));
121
+ }
122
+ } catch (err) {
123
+ console.log(JSON.stringify(fail(`Error: ${err.message}`, 'repl')));
124
+ }
125
+
126
+ rl.prompt();
127
+ });
128
+
129
+ rl.on('close', () => {
130
+ console.log('\nSession ended.');
131
+ process.exit(0);
132
+ });
133
+ }
134
+
135
+ module.exports = { run };