@khanhcan148/mk 0.1.31 → 0.1.33
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/README.md +5 -1
- package/bin/mk.js +7 -0
- package/package.json +2 -1
- package/scripts/bench-privacy-block.cjs +31 -0
- package/scripts/gen-env-docs.js +112 -0
- package/src/commands/env.js +178 -0
- package/src/lib/env-registry.js +159 -0
package/README.md
CHANGED
|
@@ -39,6 +39,9 @@ mk update Update kit files (preserves your edits by default); auto-sy
|
|
|
39
39
|
mk update --force Update and overwrite user-modified files
|
|
40
40
|
mk codex Mirror .claude/ to .codex/ for OpenAI Codex CLI (see docs/codex/COMMAND.md)
|
|
41
41
|
mk codex --cwd DIR Convert a project at a different path
|
|
42
|
+
mk env List all MK_* environment variables grouped by scope
|
|
43
|
+
mk env <NAME> Show full details for a single variable (scope, type, default, current value)
|
|
44
|
+
mk env --format json Output all variables as JSON
|
|
42
45
|
mk remove Remove all kit files tracked by manifest
|
|
43
46
|
mk --version Show installed CLI version
|
|
44
47
|
mk --help Show help
|
|
@@ -91,7 +94,7 @@ cp -r .claude ~/.claude/
|
|
|
91
94
|
```
|
|
92
95
|
├── .claude/
|
|
93
96
|
│ ├── agents/ # 36 agents (5 primary + 31 utility: implementers, quality, docs, specialized, concerns, brainstorm critics)
|
|
94
|
-
│ ├── skills/ #
|
|
97
|
+
│ ├── skills/ # 62 skill packages (SKILL.md + scripts/references/assets)
|
|
95
98
|
│ │ ├── mk-*/ # 20 workflow commands (/mk-audit, /mk-brainstorm, /mk-log-analysis, /mk-overview, /mk-wiki, etc.)
|
|
96
99
|
│ │ └── ... # Domain skills (frontend, backend, testing, browser automation, etc.)
|
|
97
100
|
│ └── workflows/ # Development protocols
|
|
@@ -240,6 +243,7 @@ python .claude/skills/skill-creator/scripts/package_skill.py <path/to/skill-fold
|
|
|
240
243
|
| [Product Domain Glossary](docs/product-domain-glossary.md) | Core domain concepts, terminology, and ecosystem definitions |
|
|
241
244
|
| [Quick Reference](docs/quick-reference.md) | Common commands and quick lookup |
|
|
242
245
|
| [Common Workflows](docs/common-workflows.md) | Practical workflow examples |
|
|
246
|
+
| [Environment Variables](.claude/env-vars.md) | All MK_* env vars with type, default, and description; run `mk env` for live values, or `mk env --markdown` to regenerate this table |
|
|
243
247
|
|
|
244
248
|
## Core Principles
|
|
245
249
|
|
package/bin/mk.js
CHANGED
|
@@ -8,6 +8,7 @@ import { updateAction } from '../src/commands/update.js';
|
|
|
8
8
|
import { removeAction } from '../src/commands/remove.js';
|
|
9
9
|
import { loginAction, logoutAction, statusAction } from '../src/commands/auth.js';
|
|
10
10
|
import { codexAction } from '../src/commands/codex.js';
|
|
11
|
+
import { envAction } from '../src/commands/env.js';
|
|
11
12
|
|
|
12
13
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
13
14
|
const pkg = JSON.parse(readFileSync(join(__dirname, '..', 'package.json'), 'utf8'));
|
|
@@ -60,4 +61,10 @@ auth.command('status')
|
|
|
60
61
|
.description('Show current authentication status')
|
|
61
62
|
.action(() => statusAction());
|
|
62
63
|
|
|
64
|
+
program.command('env [name]')
|
|
65
|
+
.description('List or describe MK_* environment variables')
|
|
66
|
+
.option('--format <fmt>', 'Output format: text (default) or json')
|
|
67
|
+
.option('--markdown', 'Emit the full env-vars table as markdown (same as .claude/env-vars.md)')
|
|
68
|
+
.action((name, options) => envAction(name, options));
|
|
69
|
+
|
|
63
70
|
program.parse();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@khanhcan148/mk",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.33",
|
|
4
4
|
"description": "CLI to install and manage MyClaudeKit (.claude/) in your projects",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
"test": "node --test test/lib/*.test.js test/commands/*.test.js test/scripts/*.test.js test/integration/*.test.js test/characterization/*.characterization.test.js .claude/hooks/tests/*.test.cjs",
|
|
19
19
|
"lint": "node --check src/**/*.js bin/**/*.js 2>/dev/null",
|
|
20
20
|
"selftest": "python3 .claude/skills/mk-selftest/scripts/validate_kit.py",
|
|
21
|
+
"gen:env-docs": "node scripts/gen-env-docs.js",
|
|
21
22
|
"codex:convert": "node bin/mk.js codex",
|
|
22
23
|
"codex:convert-and-diff": "node scripts/codex-diff-check.js"
|
|
23
24
|
},
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
process.env.NODE_TEST_CONTEXT = '1';
|
|
3
|
+
const { isSensitive } = require('../.claude/hooks/privacy-block.cjs');
|
|
4
|
+
|
|
5
|
+
const cases = [
|
|
6
|
+
['.env', ''],
|
|
7
|
+
['.env.example', ''],
|
|
8
|
+
['server.pem', ''],
|
|
9
|
+
['/home/user/.ssh/id_rsa', ''],
|
|
10
|
+
['token-budget-protocol.md', ''],
|
|
11
|
+
['secrets.json', ''],
|
|
12
|
+
['tokenize.md', ''],
|
|
13
|
+
['api-token-cache.test.ts', ''],
|
|
14
|
+
['../secrets', 'Bash'],
|
|
15
|
+
['access_key', 'Bash'],
|
|
16
|
+
];
|
|
17
|
+
|
|
18
|
+
const ITER = 10_000;
|
|
19
|
+
// Warmup
|
|
20
|
+
for (let i = 0; i < 1000; i++) for (const [f, t] of cases) isSensitive(f, t);
|
|
21
|
+
// Measure
|
|
22
|
+
const t0 = process.hrtime.bigint();
|
|
23
|
+
for (let i = 0; i < ITER; i++) for (const [f, t] of cases) isSensitive(f, t);
|
|
24
|
+
const t1 = process.hrtime.bigint();
|
|
25
|
+
const totalNs = Number(t1 - t0);
|
|
26
|
+
const perCallUs = totalNs / (ITER * cases.length) / 1000;
|
|
27
|
+
console.log(`Calls: ${ITER * cases.length}`);
|
|
28
|
+
console.log(`Total: ${(totalNs / 1e6).toFixed(2)}ms`);
|
|
29
|
+
console.log(`Per call (avg): ${perCallUs.toFixed(3)}μs`);
|
|
30
|
+
console.log(`Budget: <5000μs (5ms) per call`);
|
|
31
|
+
console.log(perCallUs < 5000 ? 'PASS: within latency budget' : 'FAIL: exceeds 5ms budget');
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* gen-env-docs.js — Generate .claude/env-vars.md from the env registry.
|
|
4
|
+
*
|
|
5
|
+
* Usage: node scripts/gen-env-docs.js
|
|
6
|
+
* npm script: npm run gen:env-docs
|
|
7
|
+
*
|
|
8
|
+
* Output is deterministic: entries sorted by scope then name.
|
|
9
|
+
*
|
|
10
|
+
* Output lives under .claude/ because that is the only directory shipped to
|
|
11
|
+
* user projects by `mk init`/`mk update` (the GitHub tarball extractor filters
|
|
12
|
+
* to paths containing `.claude/`). Anything under `docs/` is repo-only and
|
|
13
|
+
* never reaches users — see src/lib/download.js TarExtractor.
|
|
14
|
+
*
|
|
15
|
+
* The markdown-building logic is exported as `renderMarkdown(entries)` so the
|
|
16
|
+
* CLI can serve `mk env --markdown` from the same source — no static-file drift.
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
import { writeFileSync } from 'node:fs';
|
|
20
|
+
import { fileURLToPath } from 'node:url';
|
|
21
|
+
import { dirname, resolve } from 'node:path';
|
|
22
|
+
import { ENTRIES } from '../src/lib/env-registry.js';
|
|
23
|
+
|
|
24
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
25
|
+
const KIT_ROOT = resolve(__dirname, '..');
|
|
26
|
+
const OUT_FILE = resolve(KIT_ROOT, '.claude', 'env-vars.md');
|
|
27
|
+
|
|
28
|
+
// ---------------------------------------------------------------------------
|
|
29
|
+
// Scope labels (single source of truth for grouping)
|
|
30
|
+
// ---------------------------------------------------------------------------
|
|
31
|
+
|
|
32
|
+
export const SCOPE_LABELS = {
|
|
33
|
+
'sql-guard': 'SQL Guard',
|
|
34
|
+
vault: 'Vault Knowledge',
|
|
35
|
+
cli: 'CLI',
|
|
36
|
+
auth: 'Auth',
|
|
37
|
+
team: 'Team Mode',
|
|
38
|
+
codex: 'Codex',
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
export function scopeLabel(scope) {
|
|
42
|
+
return SCOPE_LABELS[scope] ?? scope;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// ---------------------------------------------------------------------------
|
|
46
|
+
// renderMarkdown — pure function. Used by both the file writer below AND
|
|
47
|
+
// by `mk env --markdown` (src/commands/env.js).
|
|
48
|
+
// ---------------------------------------------------------------------------
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Render the env-vars registry as a markdown document.
|
|
52
|
+
* @param {ReadonlyArray<object>} entries — the env-registry ENTRIES array
|
|
53
|
+
* @returns {string} markdown content (newline-terminated)
|
|
54
|
+
*/
|
|
55
|
+
export function renderMarkdown(entries) {
|
|
56
|
+
const sorted = [...entries].sort((a, b) => {
|
|
57
|
+
if (a.scope < b.scope) return -1;
|
|
58
|
+
if (a.scope > b.scope) return 1;
|
|
59
|
+
return a.name < b.name ? -1 : a.name > b.name ? 1 : 0;
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
const groups = new Map();
|
|
63
|
+
for (const entry of sorted) {
|
|
64
|
+
if (!groups.has(entry.scope)) groups.set(entry.scope, []);
|
|
65
|
+
groups.get(entry.scope).push(entry);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const lines = [];
|
|
69
|
+
lines.push('# MK_* Environment Variables');
|
|
70
|
+
lines.push('');
|
|
71
|
+
lines.push(
|
|
72
|
+
'> Auto-generated by `npm run gen:env-docs` (or `mk env --markdown`). Do not edit manually.'
|
|
73
|
+
);
|
|
74
|
+
lines.push('');
|
|
75
|
+
lines.push(
|
|
76
|
+
'All `MK_*` environment variables recognized by the kit. ' +
|
|
77
|
+
'Run `mk env` for an interactive overview, or `mk env <NAME>` for details on a single variable.'
|
|
78
|
+
);
|
|
79
|
+
lines.push('');
|
|
80
|
+
|
|
81
|
+
for (const [scope, scopeEntries] of groups) {
|
|
82
|
+
lines.push(`## ${scopeLabel(scope)}`);
|
|
83
|
+
lines.push('');
|
|
84
|
+
lines.push('| Name | Type | Default | Description |');
|
|
85
|
+
lines.push('|------|------|---------|-------------|');
|
|
86
|
+
|
|
87
|
+
for (const entry of scopeEntries) {
|
|
88
|
+
const def = entry.default !== undefined ? `\`${entry.default}\`` : '—';
|
|
89
|
+
const desc = entry.description.replace(/\|/g, '\\|');
|
|
90
|
+
lines.push(`| \`${entry.name}\` | ${entry.type} | ${def} | ${desc} |`);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
lines.push('');
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
lines.push('---');
|
|
97
|
+
lines.push('');
|
|
98
|
+
lines.push(`_${entries.length} variables documented. Run \`mk env\` for live values._`);
|
|
99
|
+
lines.push('');
|
|
100
|
+
|
|
101
|
+
return lines.join('\n');
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// ---------------------------------------------------------------------------
|
|
105
|
+
// CLI entry point: write to disk
|
|
106
|
+
// ---------------------------------------------------------------------------
|
|
107
|
+
|
|
108
|
+
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
109
|
+
const content = renderMarkdown(ENTRIES);
|
|
110
|
+
writeFileSync(OUT_FILE, content, 'utf8');
|
|
111
|
+
process.stdout.write(`Written: .claude/env-vars.md (${ENTRIES.length} entries)\n`);
|
|
112
|
+
}
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
import { ENTRIES, findByName } from '../lib/env-registry.js';
|
|
2
|
+
import { renderMarkdown } from '../../scripts/gen-env-docs.js';
|
|
3
|
+
|
|
4
|
+
// ---------------------------------------------------------------------------
|
|
5
|
+
// Scope display labels
|
|
6
|
+
// ---------------------------------------------------------------------------
|
|
7
|
+
|
|
8
|
+
const SCOPE_LABELS = {
|
|
9
|
+
'sql-guard': 'SQL Guard',
|
|
10
|
+
vault: 'Vault Knowledge',
|
|
11
|
+
cli: 'CLI',
|
|
12
|
+
auth: 'Auth',
|
|
13
|
+
team: 'Team Mode',
|
|
14
|
+
codex: 'Codex',
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
function scopeLabel(scope) {
|
|
18
|
+
return SCOPE_LABELS[scope] ?? scope;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// ---------------------------------------------------------------------------
|
|
22
|
+
// Formatting helpers
|
|
23
|
+
// ---------------------------------------------------------------------------
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Return the current runtime value of an env var, or '(unset)'.
|
|
27
|
+
* If the entry has { secret: true }, redact the value.
|
|
28
|
+
*
|
|
29
|
+
* @param {object} entry
|
|
30
|
+
* @returns {string}
|
|
31
|
+
*/
|
|
32
|
+
function currentValue(entry) {
|
|
33
|
+
const raw = process.env[entry.name];
|
|
34
|
+
if (raw === undefined) return '(unset)';
|
|
35
|
+
if (entry.secret) return '(set — redacted)';
|
|
36
|
+
return raw;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Format a default value for display.
|
|
41
|
+
*
|
|
42
|
+
* @param {string|undefined} def
|
|
43
|
+
* @param {string} description
|
|
44
|
+
* @returns {string}
|
|
45
|
+
*/
|
|
46
|
+
function displayDefault(def) {
|
|
47
|
+
if (def === undefined) return '(none)';
|
|
48
|
+
return def;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Column widths for list mode
|
|
52
|
+
const COL_NAME = 32;
|
|
53
|
+
const COL_VALUE = 16;
|
|
54
|
+
|
|
55
|
+
function padRight(str, width) {
|
|
56
|
+
return str.length >= width ? str : str + ' '.repeat(width - str.length);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// ---------------------------------------------------------------------------
|
|
60
|
+
// List mode — grouped by scope
|
|
61
|
+
// ---------------------------------------------------------------------------
|
|
62
|
+
|
|
63
|
+
function listMode(format) {
|
|
64
|
+
// Group entries by scope, preserving insertion order of first occurrence
|
|
65
|
+
const groups = new Map();
|
|
66
|
+
for (const entry of ENTRIES) {
|
|
67
|
+
if (!groups.has(entry.scope)) groups.set(entry.scope, []);
|
|
68
|
+
groups.get(entry.scope).push(entry);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if (format === 'json') {
|
|
72
|
+
const enriched = ENTRIES.map((e) => ({ ...e, current: currentValue(e) }));
|
|
73
|
+
process.stdout.write(JSON.stringify({ entries: enriched }, null, 2) + '\n');
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Text mode — sorted scopes for deterministic output
|
|
78
|
+
const sortedScopes = [...groups.keys()].sort();
|
|
79
|
+
|
|
80
|
+
for (const scope of sortedScopes) {
|
|
81
|
+
const entries = groups.get(scope);
|
|
82
|
+
process.stdout.write(`${scopeLabel(scope)}\n`);
|
|
83
|
+
|
|
84
|
+
for (const entry of entries) {
|
|
85
|
+
const namePad = padRight(entry.name, COL_NAME);
|
|
86
|
+
const val = currentValue(entry);
|
|
87
|
+
const valPad = padRight(val, COL_VALUE);
|
|
88
|
+
const firstLine = ` ${namePad} ${valPad} ${entry.description}\n`;
|
|
89
|
+
process.stdout.write(firstLine);
|
|
90
|
+
|
|
91
|
+
// Show default on second line if there is one
|
|
92
|
+
if (entry.default !== undefined) {
|
|
93
|
+
const indent = ' '.repeat(2 + COL_NAME + 1 + COL_VALUE + 1);
|
|
94
|
+
process.stdout.write(`${indent}Default: ${entry.default}\n`);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
process.stdout.write('\n');
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const scopeCount = sortedScopes.length;
|
|
101
|
+
process.stdout.write(`Run \`mk env <NAME>\` for full details on a single variable.\n`);
|
|
102
|
+
process.stdout.write(`${ENTRIES.length} variables across ${scopeCount} scope${scopeCount === 1 ? '' : 's'}.\n`);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// ---------------------------------------------------------------------------
|
|
106
|
+
// Detail mode — single entry
|
|
107
|
+
// ---------------------------------------------------------------------------
|
|
108
|
+
|
|
109
|
+
function detailMode(name) {
|
|
110
|
+
const entry = findByName(name);
|
|
111
|
+
if (!entry) {
|
|
112
|
+
process.stderr.write(`Unknown env var: ${name}\n`);
|
|
113
|
+
process.exitCode = 1;
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const val = currentValue(entry);
|
|
118
|
+
const def = entry.default !== undefined
|
|
119
|
+
? entry.default
|
|
120
|
+
: '(none)';
|
|
121
|
+
|
|
122
|
+
process.stdout.write(`${entry.name}\n\n`);
|
|
123
|
+
process.stdout.write(` Scope: ${entry.scope}\n`);
|
|
124
|
+
process.stdout.write(` Type: ${entry.type}\n`);
|
|
125
|
+
process.stdout.write(` Applies to: ${entry.applies_to}\n`);
|
|
126
|
+
process.stdout.write(` Default: ${def}\n`);
|
|
127
|
+
process.stdout.write(` Current: ${val}\n`);
|
|
128
|
+
if (entry.since) {
|
|
129
|
+
process.stdout.write(` Since: ${entry.since}\n`);
|
|
130
|
+
}
|
|
131
|
+
process.stdout.write(`\n ${entry.description}\n`);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// ---------------------------------------------------------------------------
|
|
135
|
+
// Detail mode with JSON format
|
|
136
|
+
// ---------------------------------------------------------------------------
|
|
137
|
+
|
|
138
|
+
function detailModeJson(name) {
|
|
139
|
+
const entry = findByName(name);
|
|
140
|
+
if (!entry) {
|
|
141
|
+
process.stderr.write(`Unknown env var: ${name}\n`);
|
|
142
|
+
process.exitCode = 1;
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
process.stdout.write(JSON.stringify({ entries: [{ ...entry, current: currentValue(entry) }] }, null, 2) + '\n');
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// ---------------------------------------------------------------------------
|
|
149
|
+
// envAction — exported for bin/mk.js and tests
|
|
150
|
+
// ---------------------------------------------------------------------------
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Handle 'mk env [name]'.
|
|
154
|
+
*
|
|
155
|
+
* @param {string|undefined} name - Optional env var name for detail mode
|
|
156
|
+
* @param {{ format?: string }} options
|
|
157
|
+
*/
|
|
158
|
+
export function envAction(name, options = {}) {
|
|
159
|
+
const format = options.format ?? 'text';
|
|
160
|
+
|
|
161
|
+
// --markdown emits the same markdown that `npm run gen:env-docs` writes to disk.
|
|
162
|
+
// Useful for piping to a file in a user project: `mk env --markdown > ENV.md`.
|
|
163
|
+
// List mode only — ignores any name argument (markdown is always the full table).
|
|
164
|
+
if (options.markdown) {
|
|
165
|
+
process.stdout.write(renderMarkdown(ENTRIES));
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
if (name) {
|
|
170
|
+
if (format === 'json') {
|
|
171
|
+
detailModeJson(name);
|
|
172
|
+
} else {
|
|
173
|
+
detailMode(name);
|
|
174
|
+
}
|
|
175
|
+
} else {
|
|
176
|
+
listMode(format);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Central registry of all MK_* environment variables recognized by the kit.
|
|
3
|
+
*
|
|
4
|
+
* Each entry is frozen and the array itself is frozen.
|
|
5
|
+
* Consumers: `mk env` CLI subcommand, gen-env-docs.js, selftest drift detector.
|
|
6
|
+
*
|
|
7
|
+
* Deliberate omissions:
|
|
8
|
+
* - MK_VAULT_AUDIT_FLOOR and MK_VAULT_RELAXED are *forbidden* vars (validators_vault.py
|
|
9
|
+
* actively rejects any kit file that references them). Documenting them as supported
|
|
10
|
+
* configuration would be misleading.
|
|
11
|
+
* - MK_COMMAND_RE, MK_FM_SCHEMA_*, MK_INIT_RE, MK_PLAN_SKILL_MD, MK_SKILLS, MK_TIER are
|
|
12
|
+
* Python module-level constants in selftest scripts, not environment variables.
|
|
13
|
+
*
|
|
14
|
+
* If a var is secret-like (e.g. MK_*_TOKEN, MK_*_KEY, MK_*_SECRET) it should carry
|
|
15
|
+
* { secret: true } and `mk env` will redact its current value. None of the current
|
|
16
|
+
* vars are secret.
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
const _RAW = [
|
|
20
|
+
{
|
|
21
|
+
name: 'MK_CACHE_DIR',
|
|
22
|
+
scope: 'vault',
|
|
23
|
+
default: undefined,
|
|
24
|
+
description:
|
|
25
|
+
'Override the cache directory used by vault_probe.py. ' +
|
|
26
|
+
'Resolution order: MK_CACHE_DIR → $XDG_CACHE_HOME/mk → ~/.cache/mk → OS tempdir.',
|
|
27
|
+
type: 'path',
|
|
28
|
+
applies_to: 'skill',
|
|
29
|
+
since: '0.1.21',
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
name: 'MK_FORCE_NO_TOOL_DIR',
|
|
33
|
+
scope: 'codex',
|
|
34
|
+
default: undefined,
|
|
35
|
+
description:
|
|
36
|
+
'When set to "1", convert-agents-to-codex.js aborts with exit 1 (simulates a missing ' +
|
|
37
|
+
'TOOL_DIR_NAME constant). Used exclusively in integration tests; do not set in production.',
|
|
38
|
+
type: 'boolean',
|
|
39
|
+
applies_to: 'cli',
|
|
40
|
+
since: '0.1.22',
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
name: 'MK_INTROSPECT_MAX_NOTES',
|
|
44
|
+
scope: 'vault',
|
|
45
|
+
default: undefined,
|
|
46
|
+
description:
|
|
47
|
+
'Maximum number of vault notes vault_introspect.py will enumerate before stopping. ' +
|
|
48
|
+
'Prevents runaway scanning on large vaults. Must be a positive integer.',
|
|
49
|
+
type: 'integer',
|
|
50
|
+
applies_to: 'skill',
|
|
51
|
+
since: '0.1.21',
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
name: 'MK_OAUTH_SCOPE',
|
|
55
|
+
scope: 'auth',
|
|
56
|
+
default: 'repo',
|
|
57
|
+
description:
|
|
58
|
+
'GitHub OAuth scope requested during the device flow. Defaults to "repo" (required to ' +
|
|
59
|
+
'access the private kit repository). Override only for testing or alternative scopes.',
|
|
60
|
+
type: 'string',
|
|
61
|
+
applies_to: 'cli',
|
|
62
|
+
since: '0.1.0',
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
name: 'MK_SQL_GUARD_ALLOWLIST',
|
|
66
|
+
scope: 'sql-guard',
|
|
67
|
+
default: '.claude/sql-guard.allowlist',
|
|
68
|
+
description:
|
|
69
|
+
'Path to the SQL guard allowlist file (kit-root-relative or absolute). ' +
|
|
70
|
+
'Used by sql-allowlist.cjs to load the list of approved SQL patterns.',
|
|
71
|
+
type: 'path',
|
|
72
|
+
applies_to: 'hook',
|
|
73
|
+
since: '0.1.26',
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
name: 'MK_SQL_GUARD_MAX_STDIN_BYTES',
|
|
77
|
+
scope: 'sql-guard',
|
|
78
|
+
default: '1048576',
|
|
79
|
+
description:
|
|
80
|
+
'Maximum stdin bytes the sql-guard hook will read before failing open (allowing the ' +
|
|
81
|
+
'command to proceed). Default is 1 048 576 bytes (1 MB). Increase for large queries.',
|
|
82
|
+
type: 'integer',
|
|
83
|
+
applies_to: 'hook',
|
|
84
|
+
since: '0.1.26',
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
name: 'MK_SQL_GUARD_TEST',
|
|
88
|
+
scope: 'sql-guard',
|
|
89
|
+
default: undefined,
|
|
90
|
+
description:
|
|
91
|
+
'When set to "1", sql-guard.cjs returns early at module load without executing the ' +
|
|
92
|
+
'stdin pipeline. Used exclusively by hook unit tests; do not set in production.',
|
|
93
|
+
type: 'boolean',
|
|
94
|
+
applies_to: 'hook',
|
|
95
|
+
since: '0.1.26',
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
name: 'MK_TEAM_MAX_ITERATIONS',
|
|
99
|
+
scope: 'team',
|
|
100
|
+
default: '8',
|
|
101
|
+
description:
|
|
102
|
+
'Maximum agent-team loop iterations enforced by loop-detector.js before the loop is ' +
|
|
103
|
+
'terminated. Applies to --team mode in mk-implement and mk-review.',
|
|
104
|
+
type: 'integer',
|
|
105
|
+
applies_to: 'skill',
|
|
106
|
+
since: '0.1.15',
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
name: 'MK_VAULT_CACHE_REBUILD',
|
|
110
|
+
scope: 'vault',
|
|
111
|
+
default: undefined,
|
|
112
|
+
description:
|
|
113
|
+
'When set to "1", vault_retrieval_plan.py ignores any cached retrieval plan and ' +
|
|
114
|
+
'rebuilds it from scratch. Useful after vault restructuring.',
|
|
115
|
+
type: 'boolean',
|
|
116
|
+
applies_to: 'skill',
|
|
117
|
+
since: '0.1.21',
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
name: 'MK_VAULT_ENABLED',
|
|
121
|
+
scope: 'vault',
|
|
122
|
+
default: undefined,
|
|
123
|
+
description:
|
|
124
|
+
'Privacy-by-default opt-in gate. Set to "1" to enable Obsidian vault consultation ' +
|
|
125
|
+
'across mk-* skills and agents. Any other value (or unset) means vault access is disabled.',
|
|
126
|
+
type: 'boolean',
|
|
127
|
+
applies_to: 'skill',
|
|
128
|
+
since: '0.1.21',
|
|
129
|
+
},
|
|
130
|
+
{
|
|
131
|
+
name: 'MK_VERBOSE',
|
|
132
|
+
scope: 'cli',
|
|
133
|
+
default: undefined,
|
|
134
|
+
description:
|
|
135
|
+
'When set to "1", enables verbose output in mk update and the Codex converters ' +
|
|
136
|
+
'(per-file change enumeration, routine warnings, long-path warnings). ' +
|
|
137
|
+
'Equivalent to passing --verbose on mk update.',
|
|
138
|
+
type: 'boolean',
|
|
139
|
+
applies_to: 'cli',
|
|
140
|
+
since: '0.1.25',
|
|
141
|
+
},
|
|
142
|
+
];
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Frozen array of all known MK_* environment variables.
|
|
146
|
+
* @type {ReadonlyArray<{name:string,scope:string,default:string|undefined,description:string,type:string,applies_to:string,since?:string}>}
|
|
147
|
+
*/
|
|
148
|
+
export const ENTRIES = Object.freeze(_RAW.map(Object.freeze));
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Look up a registry entry by exact variable name.
|
|
152
|
+
*
|
|
153
|
+
* @param {string|undefined} name
|
|
154
|
+
* @returns {{ name:string, scope:string, default:string|undefined, description:string, type:string, applies_to:string, since?:string } | undefined}
|
|
155
|
+
*/
|
|
156
|
+
export function findByName(name) {
|
|
157
|
+
if (typeof name !== 'string') return undefined;
|
|
158
|
+
return ENTRIES.find((e) => e.name === name);
|
|
159
|
+
}
|