@vyuhlabs/dxkit 2.5.1 → 2.5.2

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 (91) hide show
  1. package/CHANGELOG.md +154 -0
  2. package/README.md +48 -28
  3. package/dist/analyzers/tools/tool-registry.d.ts.map +1 -1
  4. package/dist/analyzers/tools/tool-registry.js +25 -8
  5. package/dist/analyzers/tools/tool-registry.js.map +1 -1
  6. package/dist/cli.d.ts.map +1 -1
  7. package/dist/cli.js +66 -10
  8. package/dist/cli.js.map +1 -1
  9. package/dist/constants.d.ts.map +1 -1
  10. package/dist/constants.js +0 -10
  11. package/dist/constants.js.map +1 -1
  12. package/dist/detect.d.ts.map +1 -1
  13. package/dist/detect.js +0 -15
  14. package/dist/detect.js.map +1 -1
  15. package/dist/doctor.d.ts +78 -1
  16. package/dist/doctor.d.ts.map +1 -1
  17. package/dist/doctor.js +500 -101
  18. package/dist/doctor.js.map +1 -1
  19. package/dist/generator.d.ts.map +1 -1
  20. package/dist/generator.js +15 -0
  21. package/dist/generator.js.map +1 -1
  22. package/dist/languages/csharp.d.ts.map +1 -1
  23. package/dist/languages/csharp.js +1 -0
  24. package/dist/languages/csharp.js.map +1 -1
  25. package/dist/languages/go.d.ts.map +1 -1
  26. package/dist/languages/go.js +1 -0
  27. package/dist/languages/go.js.map +1 -1
  28. package/dist/languages/index.d.ts +25 -0
  29. package/dist/languages/index.d.ts.map +1 -1
  30. package/dist/languages/index.js +44 -0
  31. package/dist/languages/index.js.map +1 -1
  32. package/dist/languages/java.d.ts.map +1 -1
  33. package/dist/languages/java.js +1 -0
  34. package/dist/languages/java.js.map +1 -1
  35. package/dist/languages/kotlin.d.ts.map +1 -1
  36. package/dist/languages/kotlin.js +1 -0
  37. package/dist/languages/kotlin.js.map +1 -1
  38. package/dist/languages/python.d.ts.map +1 -1
  39. package/dist/languages/python.js +10 -1
  40. package/dist/languages/python.js.map +1 -1
  41. package/dist/languages/ruby.d.ts.map +1 -1
  42. package/dist/languages/ruby.js +1 -0
  43. package/dist/languages/ruby.js.map +1 -1
  44. package/dist/languages/rust.d.ts.map +1 -1
  45. package/dist/languages/rust.js +1 -0
  46. package/dist/languages/rust.js.map +1 -1
  47. package/dist/languages/types.d.ts +20 -0
  48. package/dist/languages/types.d.ts.map +1 -1
  49. package/dist/languages/typescript.d.ts.map +1 -1
  50. package/dist/languages/typescript.js +1 -0
  51. package/dist/languages/typescript.js.map +1 -1
  52. package/dist/prompts.d.ts.map +1 -1
  53. package/dist/prompts.js +0 -5
  54. package/dist/prompts.js.map +1 -1
  55. package/dist/setup-branch-protection.d.ts +34 -0
  56. package/dist/setup-branch-protection.d.ts.map +1 -0
  57. package/dist/setup-branch-protection.js +190 -0
  58. package/dist/setup-branch-protection.js.map +1 -0
  59. package/dist/setup-gh.d.ts +75 -0
  60. package/dist/setup-gh.d.ts.map +1 -0
  61. package/dist/setup-gh.js +213 -0
  62. package/dist/setup-gh.js.map +1 -0
  63. package/dist/setup-prebuild.d.ts +34 -0
  64. package/dist/setup-prebuild.d.ts.map +1 -0
  65. package/dist/setup-prebuild.js +181 -0
  66. package/dist/setup-prebuild.js.map +1 -0
  67. package/dist/ship-installers.d.ts.map +1 -1
  68. package/dist/ship-installers.js +19 -4
  69. package/dist/ship-installers.js.map +1 -1
  70. package/dist/types.d.ts +24 -6
  71. package/dist/types.d.ts.map +1 -1
  72. package/dist/update.d.ts +41 -0
  73. package/dist/update.d.ts.map +1 -1
  74. package/dist/update.js +154 -15
  75. package/dist/update.js.map +1 -1
  76. package/dist/upgrade.d.ts +88 -0
  77. package/dist/upgrade.d.ts.map +1 -0
  78. package/dist/upgrade.js +324 -0
  79. package/dist/upgrade.js.map +1 -0
  80. package/package.json +1 -1
  81. package/templates/.claude/skills/dxkit-action/SKILL.md +6 -6
  82. package/templates/.claude/skills/dxkit-config/SKILL.md +7 -7
  83. package/templates/.claude/skills/dxkit-fix/SKILL.md +165 -0
  84. package/templates/.claude/skills/dxkit-hooks/SKILL.md +8 -8
  85. package/templates/.claude/skills/dxkit-init/SKILL.md +3 -3
  86. package/templates/.claude/skills/dxkit-learn/SKILL.md +9 -9
  87. package/templates/.claude/skills/dxkit-onboard/SKILL.md +246 -0
  88. package/templates/.claude/skills/dxkit-reports/SKILL.md +18 -18
  89. package/templates/.claude/skills/dxkit-update/SKILL.md +164 -0
  90. package/templates/.devcontainer/devcontainer.json +6 -15
  91. package/templates/.devcontainer/post-create.sh +19 -4
@@ -0,0 +1,324 @@
1
+ "use strict";
2
+ /**
3
+ * `vyuh-dxkit upgrade` — combined CLI for the dxkit upgrade flow.
4
+ *
5
+ * Two modes, one subcommand:
6
+ *
7
+ * `--plan [--json]` — preview only. Emits UpgradePlan JSON
8
+ * (consumed by dxkit-update skill) or text-prose summary. No
9
+ * mutations. Used to inspect what an upgrade would do before
10
+ * committing.
11
+ *
12
+ * (no flag, or `--yes`) — execute. Runs the three-step upgrade:
13
+ * 1. `npm install @vyuhlabs/dxkit@<target>` (binary)
14
+ * 2. `npx vyuh-dxkit update` (scaffold refresh)
15
+ * 3. `npx vyuh-dxkit doctor` (verify)
16
+ * Then prints devcontainer-rebuild instructions if .devcontainer/
17
+ * was refreshed.
18
+ *
19
+ * Architectural mirror of the doctor → dxkit-fix pattern: structured
20
+ * CLI output (--plan --json) for skill consumption, execution mode
21
+ * for direct human use. Same shape, different content.
22
+ */
23
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
24
+ if (k2 === undefined) k2 = k;
25
+ var desc = Object.getOwnPropertyDescriptor(m, k);
26
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
27
+ desc = { enumerable: true, get: function() { return m[k]; } };
28
+ }
29
+ Object.defineProperty(o, k2, desc);
30
+ }) : (function(o, m, k, k2) {
31
+ if (k2 === undefined) k2 = k;
32
+ o[k2] = m[k];
33
+ }));
34
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
35
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
36
+ }) : function(o, v) {
37
+ o["default"] = v;
38
+ });
39
+ var __importStar = (this && this.__importStar) || (function () {
40
+ var ownKeys = function(o) {
41
+ ownKeys = Object.getOwnPropertyNames || function (o) {
42
+ var ar = [];
43
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
44
+ return ar;
45
+ };
46
+ return ownKeys(o);
47
+ };
48
+ return function (mod) {
49
+ if (mod && mod.__esModule) return mod;
50
+ var result = {};
51
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
52
+ __setModuleDefault(result, mod);
53
+ return result;
54
+ };
55
+ })();
56
+ Object.defineProperty(exports, "__esModule", { value: true });
57
+ exports.classifyDelta = classifyDelta;
58
+ exports.buildUpgradePlan = buildUpgradePlan;
59
+ exports.runUpgrade = runUpgrade;
60
+ const fs = __importStar(require("fs"));
61
+ const path = __importStar(require("path"));
62
+ const child_process_1 = require("child_process");
63
+ const logger = __importStar(require("./logger"));
64
+ // ────────────────────────────────────────────────────────────────────
65
+ // Version helpers
66
+ // ────────────────────────────────────────────────────────────────────
67
+ function readScaffoldVersion(cwd) {
68
+ const manifestPath = path.join(cwd, '.vyuh-dxkit.json');
69
+ if (!fs.existsSync(manifestPath))
70
+ return null;
71
+ try {
72
+ const manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf-8'));
73
+ return manifest.version ?? null;
74
+ }
75
+ catch {
76
+ return null;
77
+ }
78
+ }
79
+ function readBinaryVersion(cwd) {
80
+ try {
81
+ const out = (0, child_process_1.execSync)('npx --no-install vyuh-dxkit --version 2>/dev/null', {
82
+ cwd,
83
+ stdio: ['ignore', 'pipe', 'ignore'],
84
+ encoding: 'utf-8',
85
+ });
86
+ return out.trim() || null;
87
+ }
88
+ catch {
89
+ return null;
90
+ }
91
+ }
92
+ function readLatestPublished() {
93
+ try {
94
+ const out = (0, child_process_1.execSync)('npm view @vyuhlabs/dxkit version 2>/dev/null', {
95
+ stdio: ['ignore', 'pipe', 'ignore'],
96
+ encoding: 'utf-8',
97
+ timeout: 15000,
98
+ });
99
+ return out.trim();
100
+ }
101
+ catch {
102
+ // npm registry unreachable — return empty so caller can decide
103
+ return '';
104
+ }
105
+ }
106
+ /**
107
+ * Classify the delta between two semver-shaped strings. Returns
108
+ * `'none'` if equal, `'downgrade'` if target < current.
109
+ */
110
+ function classifyDelta(current, target) {
111
+ if (!current || !target)
112
+ return 'none';
113
+ const [c1, c2, c3] = current.split('.').map((n) => parseInt(n, 10));
114
+ const [t1, t2, t3] = target.split('.').map((n) => parseInt(n, 10));
115
+ if (Number.isNaN(c1) || Number.isNaN(t1))
116
+ return 'none';
117
+ if (t1 > c1)
118
+ return 'major';
119
+ if (t1 < c1)
120
+ return 'downgrade';
121
+ if (t2 > c2)
122
+ return 'minor';
123
+ if (t2 < c2)
124
+ return 'downgrade';
125
+ if (t3 > c3)
126
+ return 'patch';
127
+ if (t3 < c3)
128
+ return 'downgrade';
129
+ return 'none';
130
+ }
131
+ // ────────────────────────────────────────────────────────────────────
132
+ // Plan construction
133
+ // ────────────────────────────────────────────────────────────────────
134
+ function buildUpgradePlan(cwd, opts = {}) {
135
+ const scaffold = readScaffoldVersion(cwd);
136
+ const binary = (opts._readBinary ?? readBinaryVersion)(cwd);
137
+ const latest = opts.target ?? (opts._readLatest ?? readLatestPublished)();
138
+ // Use binary version as the "current" anchor for delta classification —
139
+ // it's what npm install will replace. Scaffold version informs whether
140
+ // vyuh-dxkit update is needed even when binary is already up to date.
141
+ const delta = classifyDelta(binary, latest);
142
+ const steps = [];
143
+ const warnings = [];
144
+ if (!latest) {
145
+ warnings.push('Could not query npm for the latest version (registry unreachable or rate-limited). ' +
146
+ 'Pass --target=X.Y.Z to upgrade to a specific version.');
147
+ }
148
+ // Step 1: binary upgrade. Always included unless delta is none AND
149
+ // scaffold already matches.
150
+ if (delta !== 'none' || (scaffold && binary && scaffold !== binary)) {
151
+ if (latest) {
152
+ steps.push({
153
+ command: `npm install @vyuhlabs/dxkit@${latest}`,
154
+ purpose: `Install dxkit binary ${binary ?? '(missing)'} → ${latest}`,
155
+ });
156
+ }
157
+ }
158
+ // Step 2: scaffold refresh. Always run when scaffold ≠ binary OR after
159
+ // a binary upgrade (scaffold may need updating to match the new binary).
160
+ if (latest) {
161
+ steps.push({
162
+ command: 'npx vyuh-dxkit update',
163
+ purpose: 'Refresh scaffold (.devcontainer, .githooks, .claude/skills, CI workflows)',
164
+ });
165
+ }
166
+ // Step 3: verify with doctor.
167
+ if (latest) {
168
+ steps.push({
169
+ command: 'npx vyuh-dxkit doctor',
170
+ purpose: 'Verify operational health post-upgrade',
171
+ });
172
+ }
173
+ // Optional: devcontainer rebuild reminder. We mark this optional so
174
+ // dxkit-update can surface it as a "you also need to do this manually"
175
+ // step rather than something the CLI can execute.
176
+ const hasDevcontainer = fs.existsSync(path.join(cwd, '.devcontainer', 'devcontainer.json'));
177
+ if (hasDevcontainer && delta !== 'none') {
178
+ steps.push({
179
+ command: '# Rebuild devcontainer: VSCode Command Palette → "Dev Containers: Rebuild Container"',
180
+ purpose: 'Pick up devcontainer.json changes (if any) — manual step',
181
+ optional: true,
182
+ });
183
+ }
184
+ // Warnings.
185
+ if (delta === 'major') {
186
+ warnings.push(`Major version jump (${binary} → ${latest}). Read CHANGELOG.md for breaking changes ` +
187
+ 'before running the upgrade.');
188
+ }
189
+ if (delta === 'downgrade') {
190
+ warnings.push(`Target version ${latest} is OLDER than installed ${binary}. ` +
191
+ 'Downgrades are not officially supported; baseline + manifest schemas may differ.');
192
+ }
193
+ if (scaffold && binary && scaffold !== binary) {
194
+ warnings.push(`Scaffold version (${scaffold}) doesn't match binary (${binary}). ` +
195
+ 'Step 2 (vyuh-dxkit update) will reconcile.');
196
+ }
197
+ return {
198
+ schema: 'upgrade-plan.v1',
199
+ generatedAt: new Date().toISOString(),
200
+ cwd,
201
+ current: { binary, scaffold },
202
+ target: latest,
203
+ delta,
204
+ steps,
205
+ warnings,
206
+ changelogNote: latest
207
+ ? `For per-version details: https://github.com/vyuh-labs/dxkit/blob/main/CHANGELOG.md`
208
+ : '',
209
+ };
210
+ }
211
+ // ────────────────────────────────────────────────────────────────────
212
+ // Renderers
213
+ // ────────────────────────────────────────────────────────────────────
214
+ function renderPlanProse(plan) {
215
+ logger.header('vyuh-dxkit upgrade --plan');
216
+ logger.info(`Current: scaffold ${plan.current.scaffold ?? '(none)'} + binary ${plan.current.binary ?? '(none)'}`);
217
+ logger.info(`Target: ${plan.target || '(latest unavailable)'}`);
218
+ logger.info(`Delta: ${plan.delta}`);
219
+ if (plan.warnings.length) {
220
+ console.log(''); // slop-ok
221
+ for (const w of plan.warnings)
222
+ logger.warn(w);
223
+ }
224
+ if (plan.steps.length) {
225
+ console.log(''); // slop-ok
226
+ logger.info('Plan:');
227
+ plan.steps.forEach((s, i) => {
228
+ const marker = s.optional ? '○' : '●';
229
+ logger.dim(` ${marker} [${i + 1}/${plan.steps.length}] ${s.purpose}`);
230
+ logger.dim(` ${s.command}`);
231
+ });
232
+ }
233
+ if (plan.changelogNote) {
234
+ console.log(''); // slop-ok
235
+ logger.dim(plan.changelogNote);
236
+ }
237
+ }
238
+ // ────────────────────────────────────────────────────────────────────
239
+ // Execution
240
+ // ────────────────────────────────────────────────────────────────────
241
+ function runStep(step, cwd, dryRun) {
242
+ if (step.optional) {
243
+ // Optional steps are never auto-executed — surfaced for the
244
+ // customer to do manually.
245
+ return true;
246
+ }
247
+ logger.info(`→ ${step.purpose}`);
248
+ logger.dim(` ${step.command}`);
249
+ if (dryRun) {
250
+ logger.dim(' (dry-run; skipping)');
251
+ return true;
252
+ }
253
+ // Shell out to a real shell so npx/npm work the same way as the
254
+ // customer's terminal would. We DON'T use spawnSync's shell:true
255
+ // bash escaping concerns because the commands here are all dxkit-
256
+ // controlled — no customer input flows into them.
257
+ const result = (0, child_process_1.spawnSync)('bash', ['-c', step.command], {
258
+ cwd,
259
+ stdio: 'inherit',
260
+ });
261
+ return result.status === 0;
262
+ }
263
+ async function runUpgradeExecution(cwd, plan, opts) {
264
+ // Print the plan so the customer sees what's about to happen.
265
+ renderPlanProse(plan);
266
+ if (plan.steps.length === 0) {
267
+ console.log(''); // slop-ok
268
+ logger.success('Already up to date — nothing to do.');
269
+ return;
270
+ }
271
+ if (!opts.yes && !opts.dryRun) {
272
+ // We don't bundle a real prompt library here — the upgrade is
273
+ // intended either non-interactive (--yes) or driven by the
274
+ // dxkit-update skill (which handles confirmation). Surface the
275
+ // hint so a direct human invocation knows to add --yes.
276
+ console.log(''); // slop-ok
277
+ logger.warn('Interactive confirmation is not implemented for this command. ' +
278
+ 'Re-run with --yes to execute, --dry-run to print without executing, ' +
279
+ 'or use the dxkit-update skill for a guided upgrade.');
280
+ return;
281
+ }
282
+ console.log(''); // slop-ok
283
+ logger.header('Executing upgrade');
284
+ const optionalAfter = [];
285
+ for (const step of plan.steps) {
286
+ if (step.optional) {
287
+ optionalAfter.push(step);
288
+ continue;
289
+ }
290
+ const ok = runStep(step, cwd, !!opts.dryRun);
291
+ if (!ok) {
292
+ logger.fail(`Step failed: ${step.purpose}`);
293
+ logger.dim(' Upgrade aborted. Re-run `vyuh-dxkit doctor` to see current state.');
294
+ process.exitCode = 1;
295
+ return;
296
+ }
297
+ }
298
+ console.log(''); // slop-ok
299
+ logger.success(`Upgraded to ${plan.target}.`);
300
+ if (optionalAfter.length) {
301
+ console.log(''); // slop-ok
302
+ logger.info('Manual steps still required:');
303
+ for (const s of optionalAfter)
304
+ logger.dim(` • ${s.purpose}\n ${s.command}`);
305
+ }
306
+ }
307
+ // ────────────────────────────────────────────────────────────────────
308
+ // Entry point
309
+ // ────────────────────────────────────────────────────────────────────
310
+ async function runUpgrade(cwd, opts = {}) {
311
+ const plan = buildUpgradePlan(cwd, opts);
312
+ if (opts.planOnly) {
313
+ if (opts.json) {
314
+ // Logger already routes to stderr in --json mode (cli.ts sets it).
315
+ console.log(JSON.stringify(plan, null, 2)); // slop-ok
316
+ }
317
+ else {
318
+ renderPlanProse(plan);
319
+ }
320
+ return;
321
+ }
322
+ await runUpgradeExecution(cwd, plan, opts);
323
+ }
324
+ //# sourceMappingURL=upgrade.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"upgrade.js","sourceRoot":"","sources":["../src/upgrade.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vyuhlabs/dxkit",
3
- "version": "2.5.1",
3
+ "version": "2.5.2",
4
4
  "description": "AI-native developer experience toolkit for any codebase",
5
5
  "license": "MIT",
6
6
  "author": "Vyuh Labs",
@@ -42,7 +42,7 @@ Skip items where reachability is "no" (graphify can't find a call path) UNLESS t
42
42
  # 2. Remove the secret from the file
43
43
  # 3. If the secret was committed: `git filter-repo` or BFG to scrub history
44
44
  # 4. Re-scan to confirm gitleaks no longer reports it
45
- vyuh-dxkit vulnerabilities --json | jq '.summary.findings'
45
+ npx vyuh-dxkit vulnerabilities --json | jq '.summary.findings'
46
46
  ```
47
47
 
48
48
  Don't try to redact the secret in place — the git history still has it. Rotation is the only true fix.
@@ -63,7 +63,7 @@ Suppression is `// nosemgrep: <rule-id>` on the offending line. Use sparingly
63
63
  # Find the patched version (osv-scanner / npm-audit / etc. report it)
64
64
  npm install <pkg>@<patched-version>
65
65
  # Re-run the scan
66
- vyuh-dxkit vulnerabilities
66
+ npx vyuh-dxkit vulnerabilities
67
67
  ```
68
68
 
69
69
  For peer-dep conflicts: `npm install <pkg>@<patched-version> --legacy-peer-deps` (matches the post-create.sh fallback chain).
@@ -78,7 +78,7 @@ For Python: `pip install --upgrade <pkg>=<patched>` then re-pip-freeze. For Go:
78
78
  # 3. Run the test runner to confirm it passes
79
79
  npm test # or pytest, go test, cargo test, etc.
80
80
  # 4. Re-run test-gaps to confirm the file dropped off the list
81
- vyuh-dxkit test-gaps
81
+ npx vyuh-dxkit test-gaps
82
82
  ```
83
83
 
84
84
  Don't write tests that just import the module — write tests that exercise behavior. Useless tests inflate the count but don't move the dimension.
@@ -99,7 +99,7 @@ After each fix:
99
99
 
100
100
  ```bash
101
101
  # Re-run the SPECIFIC analyzer that flagged the finding
102
- vyuh-dxkit vulnerabilities # or quality / test-gaps / health
102
+ npx vyuh-dxkit vulnerabilities # or quality / test-gaps / health
103
103
  ```
104
104
 
105
105
  The fix is verified when:
@@ -116,7 +116,7 @@ Once a finding is fixed AND verified gone, the workflow depends on what changed:
116
116
  | Scenario | Action |
117
117
  |---|---|
118
118
  | Fix landed via a code change | Commit the code. Baseline is unchanged. Future scans confirm the fix held. |
119
- | Fix landed via a config change (e.g., new entry in `.dxkit-ignore`) | Re-baseline: `vyuh-dxkit baseline create --force`. Commit both `.dxkit-ignore` and the new baseline. |
119
+ | Fix landed via a config change (e.g., new entry in `.dxkit-ignore`) | Re-baseline: `npx vyuh-dxkit baseline create --force`. Commit both `.dxkit-ignore` and the new baseline. |
120
120
  | Finding accepted as known + not blocking | Re-baseline with explicit reason in the commit message. Future scans treat it as pre-existing, not net-new. |
121
121
  | Finding is genuinely a false positive | First try suppression on the offending line. If you can't suppress, re-baseline. |
122
122
 
@@ -127,7 +127,7 @@ Once a finding is fixed AND verified gone, the workflow depends on what changed:
127
127
  After fixing N findings, run the guardrail check before pushing:
128
128
 
129
129
  ```bash
130
- vyuh-dxkit guardrail check
130
+ npx vyuh-dxkit guardrail check
131
131
  ```
132
132
 
133
133
  Exit 0 = your fixes didn't introduce any net-new regressions (you only removed/fixed things). Exit 1 = something new appeared; address that before pushing.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: dxkit-config
3
- description: Edit dxkit configuration — add/remove paths in .dxkit-ignore, tune .vyuh-dxkit.json, adjust .dxkit/policy.json guardrail severity. Use when the user wants to exclude a directory from scanning, change scoring thresholds, or modify what blocks a PR.
3
+ description: Edit dxkit configuration — add/remove paths in .dxkit-ignore, tune .npx vyuh-dxkit.json, adjust .dxkit/policy.json guardrail severity. Use when the user wants to exclude a directory from scanning, change scoring thresholds, or modify what blocks a PR.
4
4
  ---
5
5
 
6
6
  # dxkit-config
@@ -12,7 +12,7 @@ This skill modifies the three configuration files dxkit reads. Reach for it when
12
12
  | File | Purpose | When to edit |
13
13
  |---|---|---|
14
14
  | `.dxkit-ignore` | Extra paths dxkit's analyzers should skip (gitignore-style format) | Vendored code, generated code, test fixtures, large data files |
15
- | `.vyuh-dxkit.json` | Manifest of detected stack + custom settings (regenerated by `init` / `update`) | Rare — usually let `dxkit update` regenerate. Override version pins or framework detection here. |
15
+ | `.npx vyuh-dxkit.json` | Manifest of detected stack + custom settings (regenerated by `init` / `update`) | Rare — usually let `dxkit update` regenerate. Override version pins or framework detection here. |
16
16
  | `.dxkit/policy.json` | Severity policy for guardrail check | Customize what blocks a PR (e.g., demote `medium` to warning) |
17
17
 
18
18
  ## Adding a path to `.dxkit-ignore`
@@ -62,7 +62,7 @@ build/
62
62
  target/
63
63
  ```
64
64
 
65
- ## Tuning `.vyuh-dxkit.json`
65
+ ## Tuning `.npx vyuh-dxkit.json`
66
66
 
67
67
  This file is mostly auto-generated. Common manual edits:
68
68
 
@@ -80,7 +80,7 @@ This file is mostly auto-generated. Common manual edits:
80
80
  }
81
81
  ```
82
82
 
83
- When you edit this file, run `vyuh-dxkit update` to propagate changes through the rest of the scaffold (per-language rules, devcontainer features, etc.). Use `--force` only if you've also edited evolving files — otherwise `update` preserves customer changes.
83
+ When you edit this file, run `npx vyuh-dxkit update` to propagate changes through the rest of the scaffold (per-language rules, devcontainer features, etc.). Use `--force` only if you've also edited evolving files — otherwise `update` preserves customer changes.
84
84
 
85
85
  ## Customizing `.dxkit/policy.json`
86
86
 
@@ -106,15 +106,15 @@ Each finding-kind has `block` (exit 1) and `warn` (log only) lists. Adjust to yo
106
106
  { "secret": { "block": ["critical", "high"] } }
107
107
  ```
108
108
 
109
- Run `vyuh-dxkit guardrail check --policy=.dxkit/policy.json` to test the new policy. If no `policy.json` exists, dxkit uses the built-in defaults.
109
+ Run `npx vyuh-dxkit guardrail check --policy=.dxkit/policy.json` to test the new policy. If no `policy.json` exists, dxkit uses the built-in defaults.
110
110
 
111
111
  ## Workflow
112
112
 
113
113
  When the user asks for a config change:
114
114
 
115
- 1. Identify which file owns the concern (path exclusion → `.dxkit-ignore`; severity routing → `.dxkit/policy.json`; detection override → `.vyuh-dxkit.json`).
115
+ 1. Identify which file owns the concern (path exclusion → `.dxkit-ignore`; severity routing → `.dxkit/policy.json`; detection override → `.npx vyuh-dxkit.json`).
116
116
  2. Open the file, propose the edit, confirm.
117
- 3. After writing, run `vyuh-dxkit baseline create --force` if exclusions changed (so the baseline doesn't carry stale findings from the now-excluded paths).
117
+ 3. After writing, run `npx vyuh-dxkit baseline create --force` if exclusions changed (so the baseline doesn't carry stale findings from the now-excluded paths).
118
118
  4. Commit both: the config file + the regenerated baseline.
119
119
 
120
120
  ## What NOT to do
@@ -0,0 +1,165 @@
1
+ ---
2
+ name: dxkit-fix
3
+ description: Repair a broken dxkit install — read doctor's structured output and walk the customer through each fix. Use when the user asks "fix dxkit", "fix my dxkit install", "doctor says X but Y is broken", "the pre-push hook isn't firing", "vyuh-dxkit command not found", or anything else that points at a broken-install state. Hands off to dxkit-init for fresh installs and dxkit-hooks for hook-specific deep dives.
4
+ ---
5
+
6
+ # dxkit-fix
7
+
8
+ This skill repairs broken dxkit installs. It does NOT install dxkit from scratch (that's `dxkit-init`) and it does NOT triage code findings (that's `dxkit-action`). Use it when something about the install itself is wrong — hooks not firing, vyuh-dxkit not on PATH, scanner toolchain missing pieces, baseline absent, etc.
9
+
10
+ ## How dxkit-fix works
11
+
12
+ The skill consumes `npx vyuh-dxkit doctor --json` output. Doctor returns a structured `DoctorReport` with a `summary.fixable[]` array — every failing check carries:
13
+
14
+ - `label` — the problem in one line
15
+ - `fix.hint` — the human-readable explanation
16
+ - `fix.command` — the shell command that repairs it (optional)
17
+ - `fix.skill` — a more specific dxkit-* skill that can deep-dive (optional)
18
+
19
+ The skill iterates `summary.fixable[]`, asks the customer for confirmation on each fix (with the command shown), runs it, then re-runs doctor at the end to verify everything closed.
20
+
21
+ ## The repair loop
22
+
23
+ ```
24
+ [1] Run doctor in JSON mode → npx vyuh-dxkit doctor --json
25
+ [2] Read summary.fixable[] → enumerate broken signals + fix commands
26
+ [3] For each fixable:
27
+ [3a] Show the customer: label + hint + command
28
+ [3b] Confirm (default Y)
29
+ [3c] Run the command in their shell
30
+ [3d] Note success/failure
31
+ [4] Re-run doctor → verify the previously-fixable list is now empty
32
+ [5] Report what remains → any non-fixable failures + which dxkit-* skill handles them
33
+ ```
34
+
35
+ ## Steps
36
+
37
+ ### 1. Snapshot the broken state
38
+
39
+ ```bash
40
+ npx vyuh-dxkit doctor --json > /tmp/dxkit-doctor.json
41
+ ```
42
+
43
+ Capturing to a file (instead of piping inline) lets the customer re-read what was broken if a fix takes multiple iterations.
44
+
45
+ ### 2. Read the fixable list
46
+
47
+ The JSON has shape `{ schema: "doctor.v1", checks: [...], summary: { fixable: [...] } }`. Iterate `summary.fixable` only — each entry has `ok: false` AND a `fix` block. Failing checks WITHOUT a fix block are informational (e.g. a missing optional toolchain) and shouldn't be touched here.
48
+
49
+ ### 3. Walk the customer through each fix
50
+
51
+ For every fixable entry, present:
52
+
53
+ | Field | What to show |
54
+ |---|---|
55
+ | `label` | Section heading ("git hooks active — not activated") |
56
+ | `fix.hint` | One-line "what this means" explanation |
57
+ | `fix.command` | The exact shell command, in a code block |
58
+ | `fix.skill` (if present and ≠ dxkit-fix) | "For a deeper walkthrough, ask Claude Code: 'set up hooks'" (or whatever the skill's trigger is) |
59
+
60
+ Then ASK the customer: "Run this fix? [Y/n]". Default Y. If they decline, skip and move on.
61
+
62
+ When they confirm, run the command. Stream output. Note the exit code.
63
+
64
+ ### 4. Idempotency check
65
+
66
+ Every fix command in the doctor output is designed to be idempotent — re-running it on a working install is a no-op (or a refresh). So even if a customer answers Y twice by accident, nothing breaks.
67
+
68
+ ### 5. Verify with a second doctor run
69
+
70
+ After all fixes are applied (or declined), run `npx vyuh-dxkit doctor --json` again. The new `summary.fixable[]` should be a strict subset of the first run's. If something didn't close, surface it with the original `fix.hint` and offer to retry or escalate to the more specific skill.
71
+
72
+ ## What dxkit-fix can repair
73
+
74
+ Driven by doctor's tier 3 (operational health) — these are the canonical repairables today:
75
+
76
+ | Symptom (doctor label) | Fix command | Notes |
77
+ |---|---|---|
78
+ | `git hooks active` not active | `npx vyuh-dxkit hooks activate` | Sets `core.hooksPath = .githooks`. Refuses to clobber husky/lefthook configs. |
79
+ | `baseline captured` missing | `npx vyuh-dxkit baseline create` | First-run: locks in today's findings as "pre-existing." Warn customer this is value-laden — see "Capturing the FIRST baseline" below. |
80
+ | `vyuh-dxkit on PATH` not found | `npm install -g @vyuhlabs/dxkit` | Global install ensures the bare CLI works in any shell session. |
81
+ | `scanner toolchain` missing pieces | `npx vyuh-dxkit tools install --yes` | Reinstalls any ✗ tools per TOOL_DEFS. Idempotent on already-installed tools. |
82
+ | `.npmrc legacy-peer-deps persistence` missing | `echo "legacy-peer-deps=true" >> .npmrc` | Locks in the peer-dep resolution mode for future `npm install` calls. |
83
+ | `CI guardrails workflow` missing | `npx vyuh-dxkit init --with-ci --yes` | Adds the dxkit-guardrails.yml workflow. Idempotent. |
84
+ | Agent DX tier failures (manifest missing, AGENTS.md missing, .claude/* missing) | `npx vyuh-dxkit init --full --yes` or `npx vyuh-dxkit update` | Init for fresh installs; update for refreshes. |
85
+
86
+ ## Capturing the FIRST baseline — be deliberate
87
+
88
+ Of all the fixes, `baseline create` is the only one with permanent consequences. The baseline records the fingerprint of every finding currently in the repo and tells future scans "these are pre-existing — don't block on them."
89
+
90
+ If the customer's repo has uncaptured findings that are real security issues (hardcoded secrets, leaked API keys, etc.), creating a baseline NOW locks those in as accepted. They won't trip the guardrail check.
91
+
92
+ Before running `baseline create` on a customer who has NEVER captured one, surface this tradeoff:
93
+
94
+ > Capturing a baseline locks in **N** current findings as "pre-existing." If any of those are real defects you'd want to fix first (secrets to rotate, vulnerable deps to upgrade), tell me and I'll show you what's flagged so we can triage before baseline.
95
+ >
96
+ > Skip baseline now if: you have secrets in the repo, or you'd rather fix-as-you-go than accept the current state.
97
+ > Capture baseline now if: the codebase is a known-messy brownfield and you want guardrails on future regressions specifically.
98
+
99
+ If they say "show me what's flagged first," hand off to `dxkit-action` — that skill triages findings before baseline lock-in.
100
+
101
+ ## What dxkit-fix can NOT repair
102
+
103
+ These need a different skill or human action:
104
+
105
+ - **Code findings** (hardcoded secrets, lint errors, duplicates, missing tests) — `dxkit-action` handles triage + fixing. Doctor only flags that the install is working; the analyzer results are a separate surface.
106
+ - **Branch protection on the GitHub repo** — needs `gh api` credentials + repo-admin rights. The `setup-branch-protection` CLI (when available) wraps this. If doctor flags the workflow as missing but the customer's CI is healthy on PRs, this is a documentation gap, not an install gap.
107
+ - **Real secret rotation** — even after dxkit detects a hardcoded API key, the credential needs to be rotated in its issuing provider's UI by a human.
108
+ - **External tool toolchains** (e.g. a Go compiler for stacks that don't have Go) — dxkit's TOOL_DEFS install most scanner tools; toolchains for the customer's project itself are out of scope.
109
+
110
+ ## When to delegate to a more specific dxkit-* skill
111
+
112
+ Doctor's `fix.skill` field signals "this is more nuanced than a single command — walk through it via that skill." Cases:
113
+
114
+ | `fix.skill` | When to delegate |
115
+ |---|---|
116
+ | `dxkit-init` | Customer doesn't have a manifest at all — they need the full first-install flow, not a repair. |
117
+ | `dxkit-hooks` | Hook-related repair where the customer also wants chaining advice (husky/lefthook integration, bypass workflow, removal). |
118
+ | `dxkit-config` | Customer wants to tune what dxkit flags (e.g. exclude a vendored dir, adjust severity policy) rather than fix a broken state. |
119
+ | (no skill, command only) | Plain repair — apply the command and move on. |
120
+
121
+ If `fix.skill === "dxkit-fix"`, that's the default path — handle it here.
122
+
123
+ ## Idempotency + safety
124
+
125
+ Every repair this skill drives is idempotent and reversible:
126
+
127
+ - `hooks activate` is no-op if hooks already pointed at .githooks
128
+ - `baseline create` refuses to overwrite an existing baseline without `--force` — so accidentally running it twice can't corrupt state
129
+ - `tools install --yes` skips already-installed tools (per TOOL_DEFS check command)
130
+ - `npm install -g @vyuhlabs/dxkit` upgrades or installs as needed; no data loss
131
+ - `.npmrc` append is line-deduplicated
132
+
133
+ So a customer who declines a fix, then runs into it again later, can re-invoke the skill with no penalty.
134
+
135
+ ## Failure modes
136
+
137
+ If a fix command fails (non-zero exit):
138
+
139
+ 1. **Capture the stderr** so the customer can see why
140
+ 2. **Don't auto-retry** — the customer's environment may have a problem the fix can't solve (no network, permission denied, registry hiccup)
141
+ 3. **Suggest a manual workaround** if there's an obvious one (e.g. for global install failures, suggest `sudo npm install -g` on systems where the npm prefix isn't user-writable)
142
+ 4. **Continue with the remaining fixes** — one failure shouldn't block the rest
143
+
144
+ Surface failures in the final summary alongside what DID get fixed.
145
+
146
+ ## Final summary
147
+
148
+ After the loop completes, structure the report:
149
+
150
+ ```
151
+ ✓ Repaired:
152
+ • git hooks active
153
+ • vyuh-dxkit on PATH
154
+
155
+ ✗ Failed:
156
+ • baseline captured — `vyuh-dxkit baseline create` exit 1 (no .dxkit/ write permission?)
157
+
158
+ → Skipped:
159
+ • .npmrc legacy-peer-deps persistence (you declined)
160
+
161
+ Remaining issues (not auto-fixable):
162
+ • CI guardrails workflow missing → ask 'set up dxkit init' to walk through init --with-ci
163
+ ```
164
+
165
+ End with a one-line CTA: "Run `npx vyuh-dxkit doctor` to confirm the final state, or ask 'fix dxkit' again if anything new comes up."