@readystack/gnu-global-cpp-vscode-config-pack 0.1.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.
package/LICENSE.txt ADDED
@@ -0,0 +1,2 @@
1
+ Copyright. Free features may be used without a licence key.
2
+ Paid features require a valid licence key.
package/README.md ADDED
@@ -0,0 +1,52 @@
1
+ # GNU Global C/C++ .vscode Config Pack
2
+
3
+ 21 rules that read the values in a shared .vscode folder, plus 45 snippets. VS Code loads a wrong value without a word - this names the line and the fix.
4
+
5
+ ## Install
6
+
7
+ ```
8
+ npx @readystack/gnu-global-cpp-vscode-config-pack file
9
+ ```
10
+
11
+ Node 18+. The same 21 rules as the VS Code extension, from a terminal or CI.
12
+
13
+ ## Free
14
+
15
+ - Runs all 21 rules on the .vscode file you have open and reports every finding with its line number, and inserts any of the 45 snippets - nine groups covering gtags tasks, c_cpp_properties, gist workspaces, formatter save-actions, Dark+ overrides, Tailwind, ASP.NET Core launch profiles, MicroProfile Java and keybindings - at the cursor. No key, no limit, no watermark. One file is finished, completely.
16
+ - `--rules` lists every rule
17
+
18
+ ## With a licence ($29 once)
19
+
20
+ - The same 21 rules across every config file in the repository at once, the findings written out as a CSV, JSON or HTML file you keep, and your team's own rules checked alongside the built-in 21.
21
+
22
+ ```
23
+ @readystack/gnu-global-cpp-vscode-config-pack --dir ./templates --report html --out report.html
24
+ ```
25
+
26
+ A freelance senior software engineer in the US averages $101/hour in 2026 (contractrates.fyi; mid-level ~$73/hour). Finding one silently-ignored .vscode value by hand costs more than an hour of that.
27
+
28
+ ## Use from an AI agent (MCP)
29
+
30
+ Claude Code · Cursor · Windsurf · any MCP client - add to your MCP config:
31
+
32
+ ```json
33
+ { "mcpServers": { "gnu-global-cpp-vscode-config-pack": { "command": "npx", "args": ["-y", "@readystack/gnu-global-cpp-vscode-config-pack", "--mcp"] } } }
34
+ ```
35
+
36
+ Tools: `check_text` and `check_file` (free) · `check_dir` (licence; the full sweep is free for 7 days). The agent gets every finding with the line number.
37
+
38
+ ## Use in CI
39
+
40
+ ```yaml
41
+ - name: GNU Global C/C++ .vscode Config Pack
42
+ run: npx -y @readystack/gnu-global-cpp-vscode-config-pack --dir . --ci
43
+ ```
44
+
45
+ (container: `docker run --rm -v "$PWD:/work" getreadystack/gnu-global-cpp-vscode-config-pack --dir /work --ci`)
46
+
47
+ Try the full run free for 7 days — no key needed. Then one licence, 7-day refund, no questions. Set `READYSTACK_LICENSE=<key>` or run `--license <key>` once.
48
+
49
+ [Get a licence](https://buy.polar.sh/polar_cl_Ge5u327gSZxIxtXPvdIVqBgdNtoieIuKZKWfV1LjjLp)
50
+
51
+
52
+ <!-- gnu global cpp vscode config pack -->
package/cli.js ADDED
@@ -0,0 +1,123 @@
1
+ #!/usr/bin/env node
2
+ // cli.js — the same rules as the VS Code extension, run from a terminal or a container. Generated by adapters.py.
3
+ 'use strict';
4
+ const fs = require('fs'), path = require('path');
5
+ const RULES = require('./rules.json');
6
+ const S = require('./strings.json');
7
+ const lic = require('./license.js');
8
+ function scan(text) {
9
+ const lines = String(text).split(/\r?\n/); const hits = [];
10
+ for (let i = 0; i < lines.length; i++) {
11
+ for (const r of RULES) {
12
+ let re; try { re = new RegExp(r.pattern, r.flags || ''); } catch (e) { continue; }
13
+ if (re.test(lines[i])) hits.push({ line: i + 1, msg: r.message, fix: r.fix || null, sev: r.sev || 'warn' });
14
+ }
15
+ }
16
+ return hits;
17
+ }
18
+ function isText(p) { try { const b = fs.readFileSync(p); if (b.length > 2 * 1024 * 1024) return false; const s = b.subarray(0, 4096); for (const x of s) if (x === 0) return false; return true; } catch (e) { return false; } }
19
+ function walk(dir, exts, out) {
20
+ let ents = []; try { ents = fs.readdirSync(dir, { withFileTypes: true }); } catch (e) { return out; }
21
+ for (const e of ents) {
22
+ if (e.name === 'node_modules' || e.name === '.git' || e.name.startsWith('.')) continue;
23
+ const p = path.join(dir, e.name);
24
+ if (e.isDirectory()) walk(p, exts, out);
25
+ else if ((!exts.length || exts.includes(path.extname(e.name).toLowerCase())) && isText(p)) out.push(p);
26
+ }
27
+ return out;
28
+ }
29
+ function esc(s) { return String(s).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;'); }
30
+ function csvq(s) { return '"' + String(s == null ? '' : s).replace(/"/g, '""') + '"'; }
31
+ function render(rows, fmt) {
32
+ if (fmt === 'json') return JSON.stringify({ tool: S.name, rules: RULES.length, files: rows }, null, 1);
33
+ if (fmt === 'csv') { const o = ['file,line,severity,message,fix']; for (const r of rows) for (const h of r.hits) o.push([csvq(r.file), h.line, h.sev, csvq(h.msg), csvq(h.fix)].join(',')); return o.join('\n') + '\n'; }
34
+ if (fmt === 'html') {
35
+ const n = rows.reduce((a, r) => a + r.hits.length, 0);
36
+ let o = '<!doctype html><meta charset="utf-8"><title>' + esc(S.name) + ' report</title><style>body{font:14px system-ui;margin:24px}table{border-collapse:collapse}td,th{border:1px solid #ddd;padding:4px 8px;font-size:13px}code{font-family:ui-monospace,monospace}</style>';
37
+ o += '<h1>' + esc(S.name) + '</h1><p>' + rows.length + ' files · ' + n + ' findings · ' + RULES.length + ' rules</p><table><tr><th>file</th><th>line</th><th>sev</th><th>message</th><th>fix</th></tr>';
38
+ for (const r of rows) for (const h of r.hits) o += '<tr><td><code>' + esc(r.file) + '</code></td><td>' + h.line + '</td><td>' + esc(h.sev) + '</td><td>' + esc(h.msg) + '</td><td>' + esc(h.fix || '') + '</td></tr>';
39
+ return o + '</table>';
40
+ }
41
+ let o = ''; for (const r of rows) { o += r.file + '\n'; for (const h of r.hits) o += ' ' + String(h.line).padStart(5) + ' ' + h.sev.padEnd(5) + ' ' + h.msg + (h.fix ? '\n -> ' + h.fix : '') + '\n'; if (!r.hits.length) o += ' (no findings)\n'; }
42
+ return o;
43
+ }
44
+ function trialState() {
45
+ if (process.env.READYSTACK_NO_TRIAL) return { active: false };
46
+ try {
47
+ const p = path.join(path.dirname(lic.storePath()), S.bin + '.trial.json');
48
+ let t = null; try { t = JSON.parse(fs.readFileSync(p, 'utf8')); } catch (e) {}
49
+ if (!t || !t.until) { t = { until: new Date(Date.now() + 7 * 24 * 3600 * 1000).toISOString().slice(0, 10) }; fs.mkdirSync(path.dirname(p), { recursive: true }); fs.writeFileSync(p, JSON.stringify(t)); }
50
+ return { active: new Date(t.until + 'T23:59:59Z').getTime() > Date.now(), until: t.until };
51
+ } catch (e) { return { active: false }; }
52
+ }
53
+ function mcpServe() {
54
+ // s144 — MCP server over stdio (newline-delimited JSON-RPC · no dependencies). Free: check_text · check_file. Licence (7-day trial): check_dir.
55
+ const rl = require('readline').createInterface({ input: process.stdin });
56
+ const send = (o) => process.stdout.write(JSON.stringify(o) + '\n');
57
+ const tools = [
58
+ { name: 'check_text', description: S.name + ' - run all ' + RULES.length + ' checks on a text (free)', inputSchema: { type: 'object', properties: { text: { type: 'string', description: 'file contents' }, path: { type: 'string', description: 'optional file name for context' } }, required: ['text'] } },
59
+ { name: 'check_file', description: S.name + ' - run all checks on one file by path (free)', inputSchema: { type: 'object', properties: { path: { type: 'string' } }, required: ['path'] } },
60
+ { name: 'check_dir', description: S.name + ' - sweep a folder and return every finding (licence; the full run is free for 7 days)', inputSchema: { type: 'object', properties: { dir: { type: 'string' }, ext: { type: 'string', description: 'optional extension filter, e.g. .html' } }, required: ['dir'] } }
61
+ ];
62
+ const result = (id, rows) => send({ jsonrpc: '2.0', id, result: { content: [{ type: 'text', text: render(rows, 'text') }], structuredContent: { tool: S.name, rules: RULES.length, files: rows } } });
63
+ const fail = (id, text) => send({ jsonrpc: '2.0', id, result: { content: [{ type: 'text', text }], isError: true } });
64
+ rl.on('line', async (line) => {
65
+ let m; try { m = JSON.parse(line); } catch (e) { return; }
66
+ const id = m.id, method = m.method;
67
+ if (method === 'initialize') return send({ jsonrpc: '2.0', id, result: { protocolVersion: '2025-06-18', capabilities: { tools: {} }, serverInfo: { name: '@readystack/' + S.bin, version: '1.0.0' } } });
68
+ if (method === 'notifications/initialized' || method === 'ping') { if (id !== undefined) send({ jsonrpc: '2.0', id, result: {} }); return; }
69
+ if (method === 'tools/list') return send({ jsonrpc: '2.0', id, result: { tools } });
70
+ if (method === 'tools/call') {
71
+ const name = (m.params || {}).name, args = (m.params || {}).arguments || {};
72
+ try {
73
+ if (name === 'check_text') return result(id, [{ file: args.path || '(text)', hits: scan(String(args.text || ''), args.path || '') }]);
74
+ if (name === 'check_file') return result(id, [{ file: args.path, hits: scan(fs.readFileSync(args.path, 'utf8'), args.path) }]);
75
+ if (name === 'check_dir') {
76
+ const r = await lic.ensure();
77
+ if (!r.ok && !trialState().active) return fail(id, S.need_key + ' Get a licence ($' + S.price + ', once, 7-day refund): ' + lic.BUY_URL);
78
+ const files = walk(args.dir, args.ext ? [args.ext] : (S.exts || []), []);
79
+ return result(id, files.map((f) => { let t = ''; try { t = fs.readFileSync(f, 'utf8'); } catch (e) { return { file: f, hits: [], error: String(e.message) }; } return { file: f, hits: scan(t, f) }; }));
80
+ }
81
+ return send({ jsonrpc: '2.0', id, error: { code: -32601, message: 'unknown tool ' + name } });
82
+ } catch (e) { return fail(id, String(e && e.message || e)); }
83
+ }
84
+ if (id !== undefined) send({ jsonrpc: '2.0', id, error: { code: -32601, message: 'method not found: ' + method } });
85
+ });
86
+ }
87
+ function help() {
88
+ return [S.name + ' - ' + S.subtitle, '', 'Usage: ' + S.bin + ' <file> [more files] check the files you name (free, every rule)',
89
+ ' ' + S.bin + ' --dir <folder> [--ext .html] scan a whole folder (licence)',
90
+ ' ' + S.bin + ' ... --report csv|json|html [--out file] export a report (licence)',
91
+ ' ' + S.bin + ' ... --ci exit 1 when an error-level finding exists (licence)',
92
+ ' ' + S.bin + ' --license <key> store your licence key (or set READYSTACK_LICENSE)',
93
+ ' ' + S.bin + ' --rules list the ' + RULES.length + ' rules',
94
+ ' ' + S.bin + ' --mcp run as an MCP server (stdio) for Claude Code / Cursor / Windsurf - free checks, folder sweep needs a licence', '',
95
+ 'Free: ' + S.free, 'Licence ($' + S.price + ', once, 7-day refund): ' + S.paid, 'Get a licence: ' + lic.BUY_URL, ''].join('\n');
96
+ }
97
+ (async function main() {
98
+ try { const _feed = await lic.pullFeed(); if (_feed && Array.isArray(_feed.rules)) { for (const r of _feed.rules) RULES.push(r); } } catch (e) {} // ★s134 구독 피드 병합 (키 있는 손님만)
99
+ const a = process.argv.slice(2);
100
+ const get = (k) => { const i = a.indexOf(k); return i >= 0 ? a[i + 1] : null; };
101
+ if (a.includes('--mcp')) { mcpServe(); return; }
102
+ if (!a.length || a.includes('--help') || a.includes('-h')) { process.stdout.write(help()); return; }
103
+ if (a.includes('--rules')) { process.stdout.write(RULES.map((r, i) => String(i + 1).padStart(3) + ' [' + (r.sev || 'warn') + '] ' + r.message).join('\n') + '\n'); return; }
104
+ if (a.includes('--license')) { const r = await lic.ensure(get('--license')); process.stdout.write(r.ok ? 'Licence stored: ' + lic.storePath() + '\n' : 'Licence not accepted (' + r.why + '). Get one: ' + lic.BUY_URL + '\n'); process.exit(r.ok ? 0 : 2); }
105
+ const dir = get('--dir'), fmt = get('--report'), out = get('--out'), ci = a.includes('--ci');
106
+ const exts = a.includes('--ext') ? [get('--ext')] : (S.exts || []);
107
+ const paid = !!(dir || fmt || ci);
108
+ if (paid) {
109
+ const r = await lic.ensure();
110
+ if (!r.ok) {
111
+ const t = trialState(); // s144 reverse trial: the full run is free for 7 days from the first paid use, then the key
112
+ if (t.active) process.stderr.write('Trial: the full run is free until ' + t.until + ' — after that $' + S.price + ' once (7-day refund). Get a licence: ' + lic.BUY_URL + '\n');
113
+ else { process.stderr.write(S.need_key + '\n set READYSTACK_LICENSE=<key> or ' + S.bin + ' --license <key>\n Get a licence ($' + S.price + ', once): ' + lic.BUY_URL + '\n'); process.exit(2); }
114
+ }
115
+ }
116
+ const files = dir ? walk(dir, exts, []) : a.filter((x, i) => !x.startsWith('--') && !['--dir', '--report', '--out', '--ext', '--license'].includes(a[i - 1]));
117
+ if (!files.length) { process.stderr.write('No files. ' + S.bin + ' --help\n'); process.exit(2); }
118
+ const rows = files.map((f) => { let t = ''; try { t = fs.readFileSync(f, 'utf8'); } catch (e) { return { file: f, hits: [], error: String(e.message) }; } return { file: f, hits: scan(t) }; });
119
+ const text = render(rows, fmt || 'text');
120
+ if (out) fs.writeFileSync(out, text); else process.stdout.write(text.endsWith('\n') ? text : text + '\n');
121
+ const errors = rows.reduce((n, r) => n + r.hits.filter((h) => h.sev === 'error').length, 0);
122
+ if (ci && errors) process.exit(1);
123
+ })().catch((e) => { process.stderr.write(String(e && e.stack || e) + '\n'); process.exit(3); });
package/license.js ADDED
@@ -0,0 +1,68 @@
1
+ // license.js — Polar licence check for the CLI / container. Generated by adapters.py; do not edit by hand.
2
+ 'use strict';
3
+ const https = require('https'), fs = require('fs'), path = require('path'), os = require('os');
4
+ const ORG_ID = 'a5cdf664-d8e7-4f87-8895-056717aaba17';
5
+ const BENEFIT_ID = '4e4800fb-f6cb-466a-84c7-f0b38387fd34'; // s142 — this product's Polar benefit (s140 law: ask with benefit_id, or one key opens every product)
6
+ const BUY_URL = 'https://buy.polar.sh/polar_cl_Ge5u327gSZxIxtXPvdIVqBgdNtoieIuKZKWfV1LjjLp';
7
+ const SLUG = 'gnu-global-cpp-vscode-config-pack';
8
+ const GRACE_MS = 30 * 24 * 3600 * 1000; // after a successful check, 30 days work offline
9
+ const RECHECK_MS = 7 * 24 * 3600 * 1000; // re-ask Polar every 7 days (refunds / cancellations)
10
+ function storePath() { return path.join(process.env.READYSTACK_HOME || path.join(os.homedir(), '.config', 'readystack'), SLUG + '.json'); }
11
+ function load() { try { return JSON.parse(fs.readFileSync(storePath(), 'utf8')); } catch (e) { return {}; } }
12
+ function save(o) { try { fs.mkdirSync(path.dirname(storePath()), { recursive: true }); fs.writeFileSync(storePath(), JSON.stringify(o)); } catch (e) { /* read-only home: still works for this run */ } }
13
+ const ALL_BENEFIT_ID = '22692551-5203-4467-b1a3-e33cdba6589d'; // s149 2026-09-17 — 팀 키(전 린터 한 키 · Polar benefit) · 상품 benefit 다음에 한 번 더 묻는다
14
+ function validate(key) {
15
+ return validate1(key, BENEFIT_ID).then(function (r) { return (r.ok || r.offline || !/^[0-9a-f-]{36}$/.test(ALL_BENEFIT_ID)) ? r : validate1(key, ALL_BENEFIT_ID); });
16
+ }
17
+ function validate1(key, ben) {
18
+ return new Promise(function (resolve) {
19
+ if (!ORG_ID) return resolve({ ok: false, offline: false });
20
+ const body = JSON.stringify(/^[0-9a-f-]{36}$/.test(ben) ? { key: key, organization_id: ORG_ID, benefit_id: ben } : { key: key, organization_id: ORG_ID });
21
+ const req = https.request({ hostname: 'api.polar.sh', path: '/v1/customer-portal/license-keys/validate', method: 'POST', timeout: 8000,
22
+ headers: { 'content-type': 'application/json', 'polar-version': '2026-04', 'content-length': Buffer.byteLength(body) } }, function (res) {
23
+ let buf = ''; res.on('data', function (d) { buf += d; });
24
+ res.on('end', function () {
25
+ if (res.statusCode !== 200) return resolve({ ok: false, offline: false });
26
+ try { const j = JSON.parse(buf); resolve({ ok: j && (j.status === 'granted' || j.valid === true || !!j.id), offline: false }); }
27
+ catch (e) { resolve({ ok: false, offline: false }); }
28
+ });
29
+ });
30
+ req.on('timeout', function () { req.destroy(); resolve({ ok: false, offline: true }); });
31
+ req.on('error', function () { resolve({ ok: false, offline: true }); });
32
+ req.write(body); req.end();
33
+ });
34
+ }
35
+ async function ensure(explicitKey) {
36
+ const st = load();
37
+ const key = explicitKey || process.env.READYSTACK_LICENSE || st.key;
38
+ if (!key) return { ok: false, why: 'no_key' };
39
+ const age = Date.now() - (st.okAt || 0);
40
+ if (!explicitKey && st.key === key && age < RECHECK_MS) return { ok: true, cached: true };
41
+ const r = await validate(String(key).trim());
42
+ if (r.ok) { save({ key: String(key).trim(), okAt: Date.now() }); return { ok: true }; }
43
+ if (r.offline && st.key === key && age < GRACE_MS) return { ok: true, offline: true };
44
+ return { ok: false, why: r.offline ? 'offline' : 'invalid' };
45
+ }
46
+ // ★s134 — 구독 규칙 피드(층3 "바뀌면 업데이트"): 키 있는 손님만 · 7일마다 · 오프라인은 캐시. 워커 GET /api/rules/<slug>?key=
47
+ const FEED_URL = 'https://getreadystack.com/api/rules/';
48
+ function pullFeed() {
49
+ const st = load(); const key = process.env.READYSTACK_LICENSE || st.key; const cached = st.feed || null;
50
+ if (!key) return Promise.resolve(cached);
51
+ if (cached && (Date.now() - (st.feedAt || 0)) < RECHECK_MS) return Promise.resolve(cached);
52
+ return new Promise(function (resolve) {
53
+ let req;
54
+ try {
55
+ req = https.get(FEED_URL + encodeURIComponent(SLUG) + '?key=' + encodeURIComponent(key), { timeout: 8000, headers: { 'user-agent': 'readystack-cli' } }, function (res) {
56
+ let buf = ''; res.on('data', function (d) { buf += d; });
57
+ res.on('end', function () {
58
+ if (res.statusCode !== 200) return resolve(cached);
59
+ try { const j = JSON.parse(buf); if (!j || !Array.isArray(j.rules)) return resolve(cached); save(Object.assign(load(), { feed: j, feedAt: Date.now() })); resolve(j); }
60
+ catch (e) { resolve(cached); }
61
+ });
62
+ });
63
+ } catch (e) { return resolve(cached); }
64
+ req.on('timeout', function () { req.destroy(); resolve(cached); });
65
+ req.on('error', function () { resolve(cached); });
66
+ });
67
+ }
68
+ module.exports = { ensure, BUY_URL, storePath, pullFeed };
package/package.json ADDED
@@ -0,0 +1,38 @@
1
+ {
2
+ "name": "@readystack/gnu-global-cpp-vscode-config-pack",
3
+ "version": "0.1.1",
4
+ "description": "21 rules that read the values in a shared .vscode folder, plus 45 snippets. VS Code loads a wrong value without a word - this names the line and the fix.",
5
+ "license": "SEE LICENSE IN LICENSE.txt",
6
+ "publishConfig": {
7
+ "access": "public"
8
+ },
9
+ "keywords": [
10
+ "gnu global",
11
+ "gtags",
12
+ "c cpp",
13
+ "vscode config",
14
+ "tasks json"
15
+ ],
16
+ "homepage": "https://getreadystack.com",
17
+ "funding": "https://buy.polar.sh/polar_cl_Ge5u327gSZxIxtXPvdIVqBgdNtoieIuKZKWfV1LjjLp",
18
+ "bin": {
19
+ "gnu-global-cpp-vscode-config-pack": "cli.js"
20
+ },
21
+ "engines": {
22
+ "node": ">=18"
23
+ },
24
+ "mcpName": "io.github.jmshinhwa/gnu-global-cpp-vscode-config-pack",
25
+ "repository": {
26
+ "type": "git",
27
+ "url": "https://github.com/jmshinhwa/readystack-themes.git",
28
+ "directory": "gnu-global-cpp-vscode-config-pack"
29
+ },
30
+ "files": [
31
+ "cli.js",
32
+ "license.js",
33
+ "rules.json",
34
+ "strings.json",
35
+ "README.md",
36
+ "LICENSE.txt"
37
+ ]
38
+ }
package/rules.json ADDED
@@ -0,0 +1,112 @@
1
+ [
2
+ {
3
+ "pattern": "\\$\\{workspaceRoot\\}",
4
+ "flags": "i",
5
+ "message": "${workspaceRoot} is the deprecated name. Newer VS Code releases resolve it inconsistently across tasks and launch configs, so the path can come out empty and the task runs in the wrong folder. Use ${workspaceFolder}.",
6
+ "fix": "${workspaceFolder}"
7
+ },
8
+ {
9
+ "pattern": "\"/(home|Users)/[^\"]+\"",
10
+ "flags": "",
11
+ "message": "An absolute path from your own machine. Every teammate who clones this repository gets a path that does not exist, and the setting is ignored without an error. Use ${workspaceFolder} for repo paths or ${userHome} for personal ones."
12
+ },
13
+ {
14
+ "pattern": "[A-Za-z]:\\\\[^\\\\\"]",
15
+ "flags": "",
16
+ "message": "A single backslash in a Windows path is an invalid JSON escape. This file will not parse and every setting in it is dropped. Double the backslashes or use forward slashes, which VS Code accepts on Windows."
17
+ },
18
+ {
19
+ "pattern": ",\\s*[}\\]]",
20
+ "flags": "",
21
+ "message": "Trailing comma. tasks.json and settings.json tolerate it, but package.json, .eslintrc.json and any tool reading this with a strict JSON parser will fail on this line."
22
+ },
23
+ {
24
+ "pattern": "\"[^\"]*[Tt]oken\"\\s*:\\s*\"gh[pousr]_",
25
+ "flags": "",
26
+ "message": "A GitHub token is written into a file that lives in the repository. The moment this is pushed the token is public; GitHub revokes leaked tokens automatically and your gist and repo access stops. Move it to the VS Code secret storage or an environment variable."
27
+ },
28
+ {
29
+ "pattern": "\"[^\"]*([Ss]ecret|[Pp]assword|apiKey|api_key)\"\\s*:\\s*\"[^\"$][^\"]{7,}\"",
30
+ "flags": "",
31
+ "message": "A literal credential in a committed workspace file. Reference an environment variable such as ${env:MY_SECRET} instead of the value itself."
32
+ },
33
+ {
34
+ "pattern": "\"version\"\\s*:\\s*\"0\\.1\\.0\"",
35
+ "flags": "",
36
+ "message": "This is the legacy tasks.json schema. Task groups, presentation options and background matchers are all ignored under 0.1.0. The current schema is 2.0.0.",
37
+ "fix": "\"version\": \"2.0.0\""
38
+ },
39
+ {
40
+ "pattern": "\"[A-Za-z_.]*[Pp]ath\"\\s*:\\s*\"~/",
41
+ "flags": "",
42
+ "message": "VS Code does not expand a leading tilde in JSON configuration. The path resolves literally to a folder named ~ , so the setting silently does nothing. Use ${userHome}/ instead."
43
+ },
44
+ {
45
+ "pattern": "\"console\"\\s*:\\s*\"internalConsole\"",
46
+ "flags": "",
47
+ "message": "The internal debug console cannot take keyboard input. Your program blocks forever on the first read from stdin and looks hung. Use integratedTerminal for anything that reads input.",
48
+ "fix": "\"console\": \"integratedTerminal\""
49
+ },
50
+ {
51
+ "pattern": "\"intelliSenseMode\"\\s*:\\s*\"(msvc|gcc|clang)-(x64|x86|arm64|arm)\"",
52
+ "flags": "",
53
+ "message": "This is the pre-platform form of intelliSenseMode. The current values carry the platform first: windows-msvc-x64, linux-gcc-x64, macos-clang-arm64. The old value falls back to a guess and your defines and include search can differ from the real compiler."
54
+ },
55
+ {
56
+ "pattern": "\"cStandard\"\\s*:\\s*\"(c\\+\\+|gnu\\+\\+)",
57
+ "flags": "",
58
+ "message": "A C++ standard has been put in cStandard. C and C++ standards are separate keys: cStandard takes c11, c17, c23; cppStandard takes c++17, c++20, c++23. IntelliSense will parse your headers under the wrong language rules."
59
+ },
60
+ {
61
+ "pattern": "\"compileCommands\"\\s*:\\s*\"[^$\"]",
62
+ "flags": "",
63
+ "message": "compileCommands is given without ${workspaceFolder}. When the path cannot be resolved the C/C++ extension does not warn — it falls back to includePath guessing and you get red squiggles across files that compile fine. Write ${workspaceFolder}/build/compile_commands.json."
64
+ },
65
+ {
66
+ "pattern": "\"css\\.lint\\.unknownAtRules\"\\s*:\\s*\"(warning|error)\"",
67
+ "flags": "",
68
+ "message": "With this on, @tailwind and @apply are reported as unknown at-rules on every stylesheet you open, and the real CSS problems are buried in the noise. Set it to ignore.",
69
+ "fix": "\"css.lint.unknownAtRules\": \"ignore\""
70
+ },
71
+ {
72
+ "pattern": "\"editor\\.defaultFormatter\"\\s*:\\s*\"[^\".]+\"",
73
+ "flags": "",
74
+ "message": "An extension id is always publisher.extension, with a dot. This value can never match an installed extension, so format-on-save does nothing at all and no message is shown. Example of the correct shape: esbenp.prettier-vscode."
75
+ },
76
+ {
77
+ "pattern": "\"(eslint\\.autoFixOnSave|prettier\\.eslintIntegration|prettier\\.tslintIntegration)\"",
78
+ "flags": "",
79
+ "message": "This setting was removed from the extension and is now read by nothing. Your files stop being fixed on save and the setting stays in the file looking correct. Use editor.codeActionsOnSave with source.fixAll.eslint instead."
80
+ },
81
+ {
82
+ "pattern": "\"source\\.fixAll(\\.[A-Za-z]+)?\"\\s*:\\s*(true|false)",
83
+ "flags": "",
84
+ "message": "The boolean form of a code action on save is deprecated. Use the string form — \"explicit\" to run only on an explicit save, \"always\" to include auto-saves, \"never\" to disable."
85
+ },
86
+ {
87
+ "pattern": "\"files\\.autoSave\"\\s*:\\s*\"afterDelay\"",
88
+ "flags": "",
89
+ "message": "afterDelay together with format-on-save reformats the file while you are still typing, which moves the cursor and can trigger a save-fix loop. onFocusChange gives the same safety without the interruption.",
90
+ "fix": "\"files.autoSave\": \"onFocusChange\""
91
+ },
92
+ {
93
+ "pattern": "\"workbench\\.colorTheme\"\\s*:",
94
+ "flags": "",
95
+ "message": "A theme set in .vscode/settings.json is forced on everyone who opens this repository, overriding their own choice with no warning. Keep the theme in your User settings and put only workbench.colorCustomizations here."
96
+ },
97
+ {
98
+ "pattern": "\"key\"\\s*:\\s*\"cmd\\+",
99
+ "flags": "i",
100
+ "message": "cmd+ only binds on macOS. Teammates on Windows and Linux get no shortcut and nothing tells them why. Bind ctrl+ as well, or move the mac-only binding into your personal keybindings.json."
101
+ },
102
+ {
103
+ "pattern": "\"java\\.home\"\\s*:",
104
+ "flags": "",
105
+ "message": "java.home is deprecated. The language server now reads java.jdt.ls.java.home for its own runtime and java.configuration.runtimes for the project JDKs; this key alone leaves your MicroProfile project compiling against whatever JDK is first on PATH."
106
+ },
107
+ {
108
+ "pattern": "\"ASPNETCORE_ENVIRONMENT\"\\s*:\\s*\"Production\"",
109
+ "flags": "",
110
+ "message": "This debug configuration launches with the Production environment. The developer exception page is off, so an unhandled error shows a blank 500 instead of the stack trace, and appsettings.Production.json values are loaded on your machine. Use Development or Staging here."
111
+ }
112
+ ]
package/strings.json ADDED
@@ -0,0 +1,10 @@
1
+ {
2
+ "name": "GNU Global C/C++ .vscode Config Pack",
3
+ "subtitle": "21 rules that read the values in a shared .vscode folder, plus 45 snippets. VS Code loads a wrong value without a word - this names the line and the fix.",
4
+ "bin": "gnu-global-cpp-vscode-config-pack",
5
+ "price": 29,
6
+ "free": "Runs all 21 rules on the .vscode file you have open and reports every finding with its line number, and inserts any of the 45 snippets - nine groups covering gtags tasks, c_cpp_properties, gist workspaces, formatter save-actions, Dark+ overrides, Tailwind, ASP.NET Core launch profiles, MicroProfile Java and keybindings - at the cursor. No key, no limit, no watermark. One file is finished, completely.",
7
+ "paid": "The same 21 rules across every config file in the repository at once, the findings written out as a CSV, JSON or HTML file you keep, and your team's own rules checked alongside the built-in 21.",
8
+ "need_key": "This option needs a licence (GNU Global C/C++ .vscode Config Pack).",
9
+ "exts": []
10
+ }