@khanhcan148/mk 0.1.32 → 0.1.34
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 +8 -3
- package/bin/mk.js +8 -0
- package/package.json +2 -1
- package/scripts/gen-env-docs.js +131 -0
- package/src/commands/env.js +189 -0
- package/src/commands/update.js +10 -1
- package/src/lib/env-registry.js +255 -0
package/README.md
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
Modular packages that extend Claude Code with specialized knowledge, workflows, and tool integrations.
|
|
8
8
|
|
|
9
|
-
**Quick Navigation:** [Quick Reference](docs/quick-reference.md) | [Common Workflows](docs/common-workflows.md) | [Skill Index](docs/skill-index.md)
|
|
9
|
+
**Quick Navigation:** [Usage Guides](docs/guides/index.md) | [Quick Reference](docs/quick-reference.md) | [Common Workflows](docs/common-workflows.md) | [Skill Index](docs/skill-index.md)
|
|
10
10
|
|
|
11
11
|
|
|
12
12
|
## Quick Start
|
|
@@ -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
|
|
@@ -90,8 +93,8 @@ cp -r .claude ~/.claude/
|
|
|
90
93
|
|
|
91
94
|
```
|
|
92
95
|
├── .claude/
|
|
93
|
-
│ ├── agents/ #
|
|
94
|
-
│ ├── skills/ #
|
|
96
|
+
│ ├── agents/ # 38 agents (5 primary + 33 utility: implementers, quality, docs, specialized, concerns, brainstorm critics)
|
|
97
|
+
│ ├── skills/ # 61 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
|
|
@@ -228,6 +231,7 @@ python .claude/skills/skill-creator/scripts/package_skill.py <path/to/skill-fold
|
|
|
228
231
|
|
|
229
232
|
| Document | Description |
|
|
230
233
|
|----------|-------------|
|
|
234
|
+
| [mk-* Usage Guides](docs/guides/index.md) | Human how-to guides for all 20 /mk-* commands: when to use, flags, phase flow, pitfalls |
|
|
231
235
|
| [Skill Index](docs/skill-index.md) | Categorized list of all skills and workflows |
|
|
232
236
|
| [mk-* Workflows & Agents](docs/mk-workflow-agents.md) | How each /mk-* command works and which agents it uses |
|
|
233
237
|
| [`mk codex` Command Guide](docs/codex/COMMAND.md) | Convert .claude/ to .codex/ for OpenAI Codex CLI; auto-sync on mk update |
|
|
@@ -240,6 +244,7 @@ python .claude/skills/skill-creator/scripts/package_skill.py <path/to/skill-fold
|
|
|
240
244
|
| [Product Domain Glossary](docs/product-domain-glossary.md) | Core domain concepts, terminology, and ecosystem definitions |
|
|
241
245
|
| [Quick Reference](docs/quick-reference.md) | Common commands and quick lookup |
|
|
242
246
|
| [Common Workflows](docs/common-workflows.md) | Practical workflow examples |
|
|
247
|
+
| [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
248
|
|
|
244
249
|
## Core Principles
|
|
245
250
|
|
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,11 @@ 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
|
+
.option('--all', 'Include internal/testing variables (hidden by default)')
|
|
69
|
+
.action((name, options) => envAction(name, options));
|
|
70
|
+
|
|
63
71
|
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.34",
|
|
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,131 @@
|
|
|
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
|
+
// User-facing vars are grouped by scope; internal/testing vars (hook *_TEST
|
|
63
|
+
// bypasses, *_MAX_STDIN_BYTES caps) are collected into a single trailing
|
|
64
|
+
// section so the everyday reference stays uncluttered.
|
|
65
|
+
const userFacing = sorted.filter((e) => !e.internal);
|
|
66
|
+
const internal = sorted.filter((e) => e.internal);
|
|
67
|
+
|
|
68
|
+
const groups = new Map();
|
|
69
|
+
for (const entry of userFacing) {
|
|
70
|
+
if (!groups.has(entry.scope)) groups.set(entry.scope, []);
|
|
71
|
+
groups.get(entry.scope).push(entry);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const lines = [];
|
|
75
|
+
lines.push('# MK_* Environment Variables');
|
|
76
|
+
lines.push('');
|
|
77
|
+
lines.push(
|
|
78
|
+
'> Auto-generated by `npm run gen:env-docs` (or `mk env --markdown`). Do not edit manually.'
|
|
79
|
+
);
|
|
80
|
+
lines.push('');
|
|
81
|
+
lines.push(
|
|
82
|
+
'All `MK_*` environment variables recognized by the kit. ' +
|
|
83
|
+
'Run `mk env` for an interactive overview, or `mk env <NAME>` for details on a single variable.'
|
|
84
|
+
);
|
|
85
|
+
lines.push('');
|
|
86
|
+
|
|
87
|
+
const renderTable = (rows) => {
|
|
88
|
+
lines.push('| Name | Type | Default | Description |');
|
|
89
|
+
lines.push('|------|------|---------|-------------|');
|
|
90
|
+
for (const entry of rows) {
|
|
91
|
+
const def = entry.default !== undefined ? `\`${entry.default}\`` : '—';
|
|
92
|
+
const desc = entry.description.replace(/\|/g, '\\|');
|
|
93
|
+
lines.push(`| \`${entry.name}\` | ${entry.type} | ${def} | ${desc} |`);
|
|
94
|
+
}
|
|
95
|
+
lines.push('');
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
for (const [scope, scopeEntries] of groups) {
|
|
99
|
+
lines.push(`## ${scopeLabel(scope)}`);
|
|
100
|
+
lines.push('');
|
|
101
|
+
renderTable(scopeEntries);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
if (internal.length > 0) {
|
|
105
|
+
lines.push('## Internal / testing');
|
|
106
|
+
lines.push('');
|
|
107
|
+
lines.push(
|
|
108
|
+
'> These are plumbing knobs a normal user never sets (hook test bypasses and ' +
|
|
109
|
+
'defensive stdin caps). `mk env` hides them by default — use `mk env --all`.'
|
|
110
|
+
);
|
|
111
|
+
lines.push('');
|
|
112
|
+
renderTable(internal);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
lines.push('---');
|
|
116
|
+
lines.push('');
|
|
117
|
+
lines.push(`_${entries.length} variables documented (${internal.length} internal). Run \`mk env\` for live values._`);
|
|
118
|
+
lines.push('');
|
|
119
|
+
|
|
120
|
+
return lines.join('\n');
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// ---------------------------------------------------------------------------
|
|
124
|
+
// CLI entry point: write to disk
|
|
125
|
+
// ---------------------------------------------------------------------------
|
|
126
|
+
|
|
127
|
+
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
128
|
+
const content = renderMarkdown(ENTRIES);
|
|
129
|
+
writeFileSync(OUT_FILE, content, 'utf8');
|
|
130
|
+
process.stdout.write(`Written: .claude/env-vars.md (${ENTRIES.length} entries)\n`);
|
|
131
|
+
}
|
|
@@ -0,0 +1,189 @@
|
|
|
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, showInternal = false) {
|
|
64
|
+
// By default hide internal/testing vars (hook *_TEST bypasses, *_MAX_STDIN_BYTES
|
|
65
|
+
// caps) — they are plumbing a user never sets. `--all` shows them.
|
|
66
|
+
const visible = showInternal ? [...ENTRIES] : ENTRIES.filter((e) => !e.internal);
|
|
67
|
+
const hiddenCount = ENTRIES.length - visible.length;
|
|
68
|
+
|
|
69
|
+
// Group entries by scope, preserving insertion order of first occurrence
|
|
70
|
+
const groups = new Map();
|
|
71
|
+
for (const entry of visible) {
|
|
72
|
+
if (!groups.has(entry.scope)) groups.set(entry.scope, []);
|
|
73
|
+
groups.get(entry.scope).push(entry);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
if (format === 'json') {
|
|
77
|
+
const enriched = visible.map((e) => ({ ...e, current: currentValue(e) }));
|
|
78
|
+
process.stdout.write(JSON.stringify({ entries: enriched }, null, 2) + '\n');
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// Text mode — sorted scopes for deterministic output
|
|
83
|
+
const sortedScopes = [...groups.keys()].sort();
|
|
84
|
+
|
|
85
|
+
for (const scope of sortedScopes) {
|
|
86
|
+
const entries = groups.get(scope);
|
|
87
|
+
process.stdout.write(`${scopeLabel(scope)}\n`);
|
|
88
|
+
|
|
89
|
+
for (const entry of entries) {
|
|
90
|
+
const namePad = padRight(entry.name, COL_NAME);
|
|
91
|
+
const val = currentValue(entry);
|
|
92
|
+
const valPad = padRight(val, COL_VALUE);
|
|
93
|
+
const firstLine = ` ${namePad} ${valPad} ${entry.description}\n`;
|
|
94
|
+
process.stdout.write(firstLine);
|
|
95
|
+
|
|
96
|
+
// Show default on second line if there is one
|
|
97
|
+
if (entry.default !== undefined) {
|
|
98
|
+
const indent = ' '.repeat(2 + COL_NAME + 1 + COL_VALUE + 1);
|
|
99
|
+
process.stdout.write(`${indent}Default: ${entry.default}\n`);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
process.stdout.write('\n');
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const scopeCount = sortedScopes.length;
|
|
106
|
+
process.stdout.write(`Run \`mk env <NAME>\` for full details on a single variable.\n`);
|
|
107
|
+
process.stdout.write(`${visible.length} variables across ${scopeCount} scope${scopeCount === 1 ? '' : 's'}.\n`);
|
|
108
|
+
if (hiddenCount > 0) {
|
|
109
|
+
process.stdout.write(`${hiddenCount} internal/testing variable${hiddenCount === 1 ? '' : 's'} hidden — run \`mk env --all\` to show.\n`);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// ---------------------------------------------------------------------------
|
|
114
|
+
// Detail mode — single entry
|
|
115
|
+
// ---------------------------------------------------------------------------
|
|
116
|
+
|
|
117
|
+
function detailMode(name) {
|
|
118
|
+
const entry = findByName(name);
|
|
119
|
+
if (!entry) {
|
|
120
|
+
process.stderr.write(`Unknown env var: ${name}\n`);
|
|
121
|
+
process.exitCode = 1;
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
const val = currentValue(entry);
|
|
126
|
+
const def = entry.default !== undefined
|
|
127
|
+
? entry.default
|
|
128
|
+
: '(none)';
|
|
129
|
+
|
|
130
|
+
process.stdout.write(`${entry.name}\n\n`);
|
|
131
|
+
process.stdout.write(` Scope: ${entry.scope}\n`);
|
|
132
|
+
process.stdout.write(` Type: ${entry.type}\n`);
|
|
133
|
+
process.stdout.write(` Applies to: ${entry.applies_to}\n`);
|
|
134
|
+
process.stdout.write(` Default: ${def}\n`);
|
|
135
|
+
process.stdout.write(` Current: ${val}\n`);
|
|
136
|
+
if (entry.since) {
|
|
137
|
+
process.stdout.write(` Since: ${entry.since}\n`);
|
|
138
|
+
}
|
|
139
|
+
if (entry.internal) {
|
|
140
|
+
process.stdout.write(` Internal: yes (testing/tuning plumbing — not a user setting)\n`);
|
|
141
|
+
}
|
|
142
|
+
process.stdout.write(`\n ${entry.description}\n`);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// ---------------------------------------------------------------------------
|
|
146
|
+
// Detail mode with JSON format
|
|
147
|
+
// ---------------------------------------------------------------------------
|
|
148
|
+
|
|
149
|
+
function detailModeJson(name) {
|
|
150
|
+
const entry = findByName(name);
|
|
151
|
+
if (!entry) {
|
|
152
|
+
process.stderr.write(`Unknown env var: ${name}\n`);
|
|
153
|
+
process.exitCode = 1;
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
process.stdout.write(JSON.stringify({ entries: [{ ...entry, current: currentValue(entry) }] }, null, 2) + '\n');
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// ---------------------------------------------------------------------------
|
|
160
|
+
// envAction — exported for bin/mk.js and tests
|
|
161
|
+
// ---------------------------------------------------------------------------
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Handle 'mk env [name]'.
|
|
165
|
+
*
|
|
166
|
+
* @param {string|undefined} name - Optional env var name for detail mode
|
|
167
|
+
* @param {{ format?: string }} options
|
|
168
|
+
*/
|
|
169
|
+
export function envAction(name, options = {}) {
|
|
170
|
+
const format = options.format ?? 'text';
|
|
171
|
+
|
|
172
|
+
// --markdown emits the same markdown that `npm run gen:env-docs` writes to disk.
|
|
173
|
+
// Useful for piping to a file in a user project: `mk env --markdown > ENV.md`.
|
|
174
|
+
// List mode only — ignores any name argument (markdown is always the full table).
|
|
175
|
+
if (options.markdown) {
|
|
176
|
+
process.stdout.write(renderMarkdown(ENTRIES));
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
if (name) {
|
|
181
|
+
if (format === 'json') {
|
|
182
|
+
detailModeJson(name);
|
|
183
|
+
} else {
|
|
184
|
+
detailMode(name);
|
|
185
|
+
}
|
|
186
|
+
} else {
|
|
187
|
+
listMode(format, options.all === true);
|
|
188
|
+
}
|
|
189
|
+
}
|
package/src/commands/update.js
CHANGED
|
@@ -80,9 +80,18 @@ export function redactSecrets(message, ctx = {}) {
|
|
|
80
80
|
out = out.split(ctx.storedToken).join('[REDACTED-TOKEN]');
|
|
81
81
|
}
|
|
82
82
|
|
|
83
|
-
//
|
|
83
|
+
// S3b: Redact any GitHub token-shaped substring (belt-and-braces)
|
|
84
84
|
out = out.replace(/gh[pousr]_[A-Za-z0-9_]{30,}/g, '[REDACTED-TOKEN]');
|
|
85
85
|
|
|
86
|
+
// S5: Redact SQL Server / MSSQL Password= and ODBC Pwd= alias in connection strings
|
|
87
|
+
out = out.replace(/((?:Password|Pwd)\s*=\s*)([^;]+?)(\s*;|\s*$)/gi, '$1[REDACTED-PASSWORD]$3');
|
|
88
|
+
|
|
89
|
+
// S6: Redact PostgreSQL DSN user:pass@ credentials
|
|
90
|
+
out = out.replace(/(postgres(?:ql)?:\/\/)([^:@/]+):([^@/]+)@/gi, '$1[REDACTED-USER]:[REDACTED-PASSWORD]@');
|
|
91
|
+
|
|
92
|
+
// S7: Redact Azure Storage / CosmosDB AccountKey= in connection strings
|
|
93
|
+
out = out.replace(/(AccountKey\s*=\s*)([^;]+?)(\s*;|\s*$)/gi, '$1[REDACTED-KEY]$3');
|
|
94
|
+
|
|
86
95
|
return out;
|
|
87
96
|
}
|
|
88
97
|
|
|
@@ -0,0 +1,255 @@
|
|
|
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
|
+
* { internal: true } marks a var as test-only or defensive-tuning plumbing that a
|
|
19
|
+
* normal user never sets (e.g. hook *_TEST bypasses, *_MAX_STDIN_BYTES caps). These
|
|
20
|
+
* stay in the registry so drift detection has a complete catalog, but `mk env` hides
|
|
21
|
+
* them by default (show with `mk env --all`) and the generated doc lists them in a
|
|
22
|
+
* separate "Internal / testing" section. They remain addressable via `mk env <NAME>`.
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
const _RAW = [
|
|
26
|
+
{
|
|
27
|
+
name: 'MK_CACHE_DIR',
|
|
28
|
+
scope: 'vault',
|
|
29
|
+
default: undefined,
|
|
30
|
+
description:
|
|
31
|
+
'Override the cache directory used by vault_probe.py. ' +
|
|
32
|
+
'Resolution order: MK_CACHE_DIR → $XDG_CACHE_HOME/mk → ~/.cache/mk → OS tempdir.',
|
|
33
|
+
type: 'path',
|
|
34
|
+
applies_to: 'skill',
|
|
35
|
+
since: '0.1.21',
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
name: 'MK_DAB_AUDIT_DIR',
|
|
39
|
+
scope: 'data-api-builder',
|
|
40
|
+
default: 'docs/dab-audit',
|
|
41
|
+
description:
|
|
42
|
+
'Override the directory where dab_audit_writer.py appends the data-api-builder ' +
|
|
43
|
+
'preflight audit log (dab-audit-YYYY-MM-DD.jsonl). Defaults to docs/dab-audit, ' +
|
|
44
|
+
'relative to invocation cwd. Set to redirect logs to an artefact store in CI. ' +
|
|
45
|
+
'Mirrors MK_SECURITY_AUDIT_DIR.',
|
|
46
|
+
type: 'path',
|
|
47
|
+
applies_to: 'skill',
|
|
48
|
+
since: '0.1.33',
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
name: 'MK_DAB_BASH_GUARD_MAX_STDIN_BYTES',
|
|
52
|
+
internal: true,
|
|
53
|
+
scope: 'data-api-builder',
|
|
54
|
+
default: '1048576',
|
|
55
|
+
description:
|
|
56
|
+
'Maximum stdin bytes the dab-bash-guard hook (Gate 4) reads before failing open ' +
|
|
57
|
+
'(allowing the command to proceed). Default is 1 048 576 bytes (1 MB).',
|
|
58
|
+
type: 'integer',
|
|
59
|
+
applies_to: 'hook',
|
|
60
|
+
since: '0.1.34',
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
name: 'MK_DAB_BASH_GUARD_TEST',
|
|
64
|
+
internal: true,
|
|
65
|
+
scope: 'data-api-builder',
|
|
66
|
+
default: undefined,
|
|
67
|
+
description:
|
|
68
|
+
'When set to "1", dab-bash-guard.cjs returns early at module load without executing the ' +
|
|
69
|
+
'stdin pipeline. Used exclusively by hook unit tests; do not set in production.',
|
|
70
|
+
type: 'boolean',
|
|
71
|
+
applies_to: 'hook',
|
|
72
|
+
since: '0.1.34',
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
name: 'MK_DAB_BASH_OK',
|
|
76
|
+
scope: 'data-api-builder',
|
|
77
|
+
default: undefined,
|
|
78
|
+
description:
|
|
79
|
+
'Opt-out override: when set to "1", allows Bash invocations of a DB CLI ' +
|
|
80
|
+
'(sqlcmd/psql/mysql/mssql-cli/mongosh/bcp/cqlsh) with query intent that the dab-bash-guard ' +
|
|
81
|
+
'hook (Gate 4) otherwise blocks. Set only for deliberate DB administration; prefer the ' +
|
|
82
|
+
'data-api-builder MCP tools.',
|
|
83
|
+
type: 'boolean',
|
|
84
|
+
applies_to: 'hook',
|
|
85
|
+
since: '0.1.34',
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
name: 'MK_DAB_MCP_GUARD_MAX_STDIN_BYTES',
|
|
89
|
+
internal: true,
|
|
90
|
+
scope: 'data-api-builder',
|
|
91
|
+
default: '1048576',
|
|
92
|
+
description:
|
|
93
|
+
'Maximum stdin bytes the dab-mcp-guard hook (Gate 1) reads before failing open ' +
|
|
94
|
+
'(allowing the call to proceed). Default is 1 048 576 bytes (1 MB).',
|
|
95
|
+
type: 'integer',
|
|
96
|
+
applies_to: 'hook',
|
|
97
|
+
since: '0.1.34',
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
name: 'MK_DAB_MCP_GUARD_TEST',
|
|
101
|
+
internal: true,
|
|
102
|
+
scope: 'data-api-builder',
|
|
103
|
+
default: undefined,
|
|
104
|
+
description:
|
|
105
|
+
'When set to "1", dab-mcp-guard.cjs skips main() at module load. Used exclusively by hook ' +
|
|
106
|
+
'unit tests; do not set in production.',
|
|
107
|
+
type: 'boolean',
|
|
108
|
+
applies_to: 'hook',
|
|
109
|
+
since: '0.1.34',
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
name: 'MK_DAB_WRITES_OK',
|
|
113
|
+
scope: 'data-api-builder',
|
|
114
|
+
default: undefined,
|
|
115
|
+
description:
|
|
116
|
+
'Opt-out override: when set to "1", allows the four write-capable data-api-builder MCP ' +
|
|
117
|
+
'calls (create_record/update_record/delete_record/execute_entity) that the dab-mcp-guard ' +
|
|
118
|
+
'hook (Gate 1) otherwise blocks. Set only for deliberate writes; DAB role config remains ' +
|
|
119
|
+
'as defence-in-depth.',
|
|
120
|
+
type: 'boolean',
|
|
121
|
+
applies_to: 'hook',
|
|
122
|
+
since: '0.1.34',
|
|
123
|
+
},
|
|
124
|
+
{
|
|
125
|
+
name: 'MK_FORCE_NO_TOOL_DIR',
|
|
126
|
+
internal: true,
|
|
127
|
+
scope: 'codex',
|
|
128
|
+
default: undefined,
|
|
129
|
+
description:
|
|
130
|
+
'When set to "1", convert-agents-to-codex.js aborts with exit 1 (simulates a missing ' +
|
|
131
|
+
'TOOL_DIR_NAME constant). Used exclusively in integration tests; do not set in production.',
|
|
132
|
+
type: 'boolean',
|
|
133
|
+
applies_to: 'cli',
|
|
134
|
+
since: '0.1.22',
|
|
135
|
+
},
|
|
136
|
+
{
|
|
137
|
+
name: 'MK_INTROSPECT_MAX_NOTES',
|
|
138
|
+
scope: 'vault',
|
|
139
|
+
default: undefined,
|
|
140
|
+
description:
|
|
141
|
+
'Maximum number of vault notes vault_introspect.py will enumerate before stopping. ' +
|
|
142
|
+
'Prevents runaway scanning on large vaults. Must be a positive integer.',
|
|
143
|
+
type: 'integer',
|
|
144
|
+
applies_to: 'skill',
|
|
145
|
+
since: '0.1.21',
|
|
146
|
+
},
|
|
147
|
+
{
|
|
148
|
+
name: 'MK_OAUTH_SCOPE',
|
|
149
|
+
scope: 'auth',
|
|
150
|
+
default: 'repo',
|
|
151
|
+
description:
|
|
152
|
+
'GitHub OAuth scope requested during the device flow. Defaults to "repo" (required to ' +
|
|
153
|
+
'access the private kit repository). Override only for testing or alternative scopes.',
|
|
154
|
+
type: 'string',
|
|
155
|
+
applies_to: 'cli',
|
|
156
|
+
since: '0.1.0',
|
|
157
|
+
},
|
|
158
|
+
{
|
|
159
|
+
name: 'MK_SQL_GUARD_ALLOWLIST',
|
|
160
|
+
scope: 'sql-guard',
|
|
161
|
+
default: '.claude/sql-guard.allowlist',
|
|
162
|
+
description:
|
|
163
|
+
'Path to the SQL guard allowlist file (kit-root-relative or absolute). ' +
|
|
164
|
+
'Used by sql-allowlist.cjs to load the list of approved SQL patterns.',
|
|
165
|
+
type: 'path',
|
|
166
|
+
applies_to: 'hook',
|
|
167
|
+
since: '0.1.26',
|
|
168
|
+
},
|
|
169
|
+
{
|
|
170
|
+
name: 'MK_SQL_GUARD_MAX_STDIN_BYTES',
|
|
171
|
+
internal: true,
|
|
172
|
+
scope: 'sql-guard',
|
|
173
|
+
default: '1048576',
|
|
174
|
+
description:
|
|
175
|
+
'Maximum stdin bytes the sql-guard hook will read before failing open (allowing the ' +
|
|
176
|
+
'command to proceed). Default is 1 048 576 bytes (1 MB). Increase for large queries.',
|
|
177
|
+
type: 'integer',
|
|
178
|
+
applies_to: 'hook',
|
|
179
|
+
since: '0.1.26',
|
|
180
|
+
},
|
|
181
|
+
{
|
|
182
|
+
name: 'MK_SQL_GUARD_TEST',
|
|
183
|
+
internal: true,
|
|
184
|
+
scope: 'sql-guard',
|
|
185
|
+
default: undefined,
|
|
186
|
+
description:
|
|
187
|
+
'When set to "1", sql-guard.cjs returns early at module load without executing the ' +
|
|
188
|
+
'stdin pipeline. Used exclusively by hook unit tests; do not set in production.',
|
|
189
|
+
type: 'boolean',
|
|
190
|
+
applies_to: 'hook',
|
|
191
|
+
since: '0.1.26',
|
|
192
|
+
},
|
|
193
|
+
{
|
|
194
|
+
name: 'MK_TEAM_MAX_ITERATIONS',
|
|
195
|
+
scope: 'team',
|
|
196
|
+
default: '8',
|
|
197
|
+
description:
|
|
198
|
+
'Maximum agent-team loop iterations enforced by loop-detector.js before the loop is ' +
|
|
199
|
+
'terminated. Applies to --team mode in mk-implement and mk-review.',
|
|
200
|
+
type: 'integer',
|
|
201
|
+
applies_to: 'skill',
|
|
202
|
+
since: '0.1.15',
|
|
203
|
+
},
|
|
204
|
+
{
|
|
205
|
+
name: 'MK_VAULT_CACHE_REBUILD',
|
|
206
|
+
scope: 'vault',
|
|
207
|
+
default: undefined,
|
|
208
|
+
description:
|
|
209
|
+
'When set to "1", vault_retrieval_plan.py ignores any cached retrieval plan and ' +
|
|
210
|
+
'rebuilds it from scratch. Useful after vault restructuring.',
|
|
211
|
+
type: 'boolean',
|
|
212
|
+
applies_to: 'skill',
|
|
213
|
+
since: '0.1.21',
|
|
214
|
+
},
|
|
215
|
+
{
|
|
216
|
+
name: 'MK_VAULT_ENABLED',
|
|
217
|
+
scope: 'vault',
|
|
218
|
+
default: undefined,
|
|
219
|
+
description:
|
|
220
|
+
'Privacy-by-default opt-in gate. Set to "1" to enable Obsidian vault consultation ' +
|
|
221
|
+
'across mk-* skills and agents. Any other value (or unset) means vault access is disabled.',
|
|
222
|
+
type: 'boolean',
|
|
223
|
+
applies_to: 'skill',
|
|
224
|
+
since: '0.1.21',
|
|
225
|
+
},
|
|
226
|
+
{
|
|
227
|
+
name: 'MK_VERBOSE',
|
|
228
|
+
scope: 'cli',
|
|
229
|
+
default: undefined,
|
|
230
|
+
description:
|
|
231
|
+
'When set to "1", enables verbose output in mk update and the Codex converters ' +
|
|
232
|
+
'(per-file change enumeration, routine warnings, long-path warnings). ' +
|
|
233
|
+
'Equivalent to passing --verbose on mk update.',
|
|
234
|
+
type: 'boolean',
|
|
235
|
+
applies_to: 'cli',
|
|
236
|
+
since: '0.1.25',
|
|
237
|
+
},
|
|
238
|
+
];
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* Frozen array of all known MK_* environment variables.
|
|
242
|
+
* @type {ReadonlyArray<{name:string,scope:string,default:string|undefined,description:string,type:string,applies_to:string,since?:string}>}
|
|
243
|
+
*/
|
|
244
|
+
export const ENTRIES = Object.freeze(_RAW.map(Object.freeze));
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* Look up a registry entry by exact variable name.
|
|
248
|
+
*
|
|
249
|
+
* @param {string|undefined} name
|
|
250
|
+
* @returns {{ name:string, scope:string, default:string|undefined, description:string, type:string, applies_to:string, since?:string } | undefined}
|
|
251
|
+
*/
|
|
252
|
+
export function findByName(name) {
|
|
253
|
+
if (typeof name !== 'string') return undefined;
|
|
254
|
+
return ENTRIES.find((e) => e.name === name);
|
|
255
|
+
}
|