@vodmal/vdx-cli 0.24.0 → 0.25.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/init.ts CHANGED
@@ -1,32 +1,16 @@
1
1
  import * as fs from 'node:fs';
2
2
  import * as path from 'node:path';
3
- import {
4
- Ctx,
5
- readJson,
6
- listAllTasks,
7
- autoDetectStack,
8
- findSubPackages,
9
- type SubPackage,
10
- } from './facts.ts';
3
+ import { Ctx, readJson, listAllTasks, autoDetectStack, findSubPackages, type SubPackage } from './facts.ts';
11
4
 
12
5
  export const STANDARD_VERBS = ['up', 'down', 'build', 'test', 'check', 'fix'] as const;
13
6
  export type Verb = (typeof STANDARD_VERBS)[number];
14
7
 
15
- export const DEFAULT_BASELINE = 'github.com/VoDmAl/vdx-rubric-vodmal@v1.3.0';
8
+ export const DEFAULT_BASELINE = 'github.com/VoDmAl/vdx-rubric-vodmal@v1.4.0';
16
9
 
17
10
  const VERB_ALIASES: Record<Verb, string[]> = {
18
11
  up: ['docker:up', 'docker-up', 'docker:up:detached', 'start', 'dev', 'serve'],
19
12
  down: ['docker:down', 'docker-down', 'stop'],
20
- build: [
21
- 'docker:build',
22
- 'build:prod',
23
- 'build-prod',
24
- 'build:dev',
25
- 'build-dev',
26
- 'build:assets',
27
- 'compile',
28
- 'dist',
29
- ],
13
+ build: ['docker:build', 'build:prod', 'build-prod', 'build:dev', 'build-dev', 'build:assets', 'compile', 'dist'],
30
14
  test: [
31
15
  'phpunit',
32
16
  'pest',
@@ -143,12 +127,7 @@ function renderRunCommand(task: string, stack: string, projectRoot: string): str
143
127
  return task;
144
128
  }
145
129
 
146
- function renderRunCommandInSubpackage(
147
- task: string,
148
- subStack: string,
149
- subAbs: string,
150
- subRel: string,
151
- ): string {
130
+ function renderRunCommandInSubpackage(task: string, subStack: string, subAbs: string, subRel: string): string {
152
131
  return `cd ${subRel} && ${renderRunCommand(task, subStack, subAbs)}`;
153
132
  }
154
133
 
@@ -290,11 +269,7 @@ export function renderMiseToml(
290
269
  out.push('');
291
270
 
292
271
  if (stack === 'unknown' || stack === 'monorepo') {
293
- out.push(
294
- '# TODO(vdx): stack auto-detection вернул "' +
295
- stack +
296
- '". Замени на php/node/go/python/meta',
297
- );
272
+ out.push('# TODO(vdx): stack auto-detection вернул "' + stack + '". Замени на php/node/go/python/meta');
298
273
  out.push('# и заполни [tasks.*] блоки руками, либо перегенери: vdx init --stack <id>.');
299
274
  out.push('');
300
275
  }
@@ -336,10 +311,7 @@ export function renderMiseToml(
336
311
  return out.join('\n');
337
312
  }
338
313
 
339
- export function planInit(
340
- projectRoot: string,
341
- opts: { baseline?: string; stack?: string } = {},
342
- ): InitPlan {
314
+ export function planInit(projectRoot: string, opts: { baseline?: string; stack?: string } = {}): InitPlan {
343
315
  const detectedStack = autoDetectStack(projectRoot);
344
316
  const stackOverridden = opts.stack !== undefined && opts.stack !== detectedStack;
345
317
  const stack = opts.stack ?? detectedStack;
@@ -436,9 +408,7 @@ export function planInit(
436
408
 
437
409
  export function writeInit(plan: InitPlan, opts: { force: boolean }): void {
438
410
  if (fs.existsSync(plan.miseTomlPath) && !opts.force) {
439
- throw new Error(
440
- `mise.toml уже существует: ${plan.miseTomlPath}. Используй --force для перезаписи.`,
441
- );
411
+ throw new Error(`mise.toml уже существует: ${plan.miseTomlPath}. Используй --force для перезаписи.`);
442
412
  }
443
413
  fs.writeFileSync(plan.miseTomlPath, plan.miseTomlContent, 'utf8');
444
414
  }
@@ -451,7 +421,9 @@ export function renderPlanSummary(plan: InitPlan, opts: { verbose?: boolean } =
451
421
 
452
422
  if (!verbose) {
453
423
  const lines: string[] = [];
454
- lines.push(`vdx init: stack=${plan.stack}${plan.stackOverridden ? ' (via --stack)' : ''}, ${mapped}/${total} verbs mapped`);
424
+ lines.push(
425
+ `vdx init: stack=${plan.stack}${plan.stackOverridden ? ' (via --stack)' : ''}, ${mapped}/${total} verbs mapped`,
426
+ );
455
427
  if (plan.primarySubpackage) lines.push(` primary subpackage: ${plan.primarySubpackage}`);
456
428
  if (unmatched.length > 0) {
457
429
  lines.push(` not mapped: ${unmatched.join(', ')} (add [tasks.X] in mise.toml manually)`);
@@ -462,12 +434,8 @@ export function renderPlanSummary(plan: InitPlan, opts: { verbose?: boolean } =
462
434
  const lines: string[] = [];
463
435
  lines.push(`# vdx init plan`);
464
436
  lines.push('');
465
- lines.push(
466
- `- **Project**: ${plan.projectRoot}`,
467
- );
468
- lines.push(
469
- `- **Stack**: ${plan.stack}${plan.stackOverridden ? ' (via --stack)' : ''}`,
470
- );
437
+ lines.push(`- **Project**: ${plan.projectRoot}`);
438
+ lines.push(`- **Stack**: ${plan.stack}${plan.stackOverridden ? ' (via --stack)' : ''}`);
471
439
  if (plan.primarySubpackage) {
472
440
  lines.push(`- **Primary subpackage**: ${plan.primarySubpackage}`);
473
441
  }
@@ -492,9 +460,7 @@ export function renderPlanSummary(plan: InitPlan, opts: { verbose?: boolean } =
492
460
  lines.push('|------|-------------|--------|-----------------|');
493
461
  for (const m of plan.mappings) {
494
462
  if (m.runCommand) {
495
- lines.push(
496
- `| \`${m.verb}\` | \`${m.nativeTask}\` | ${m.reason} | \`${m.runCommand}\` |`,
497
- );
463
+ lines.push(`| \`${m.verb}\` | \`${m.nativeTask}\` | ${m.reason} | \`${m.runCommand}\` |`);
498
464
  } else {
499
465
  lines.push(`| \`${m.verb}\` | _(not found)_ | not-found | _(skipped)_ |`);
500
466
  }
@@ -506,9 +472,7 @@ export function renderPlanSummary(plan: InitPlan, opts: { verbose?: boolean } =
506
472
  lines.push('');
507
473
  for (const m of withAlts) {
508
474
  const alts = m.alternatives.map((a) => `\`${a}\``).join(', ');
509
- lines.push(
510
- `- \`${m.verb}\` chose \`${m.nativeTask}\` (${m.reason}); also matched: ${alts}`,
511
- );
475
+ lines.push(`- \`${m.verb}\` chose \`${m.nativeTask}\` (${m.reason}); also matched: ${alts}`);
512
476
  }
513
477
  lines.push('');
514
478
  }
package/src/mcp-server.ts CHANGED
@@ -94,8 +94,7 @@ function buildCapabilities() {
94
94
  const verbsList = (vdxBlock?.verbs as string[] | undefined) ?? STANDARD_VERBS.slice();
95
95
  const verbs = verbsList.map((name) => {
96
96
  const t = tasks[name];
97
- const nativeCommand =
98
- t && typeof t === 'object' && typeof t.run === 'string' ? t.run : null;
97
+ const nativeCommand = t && typeof t === 'object' && typeof t.run === 'string' ? t.run : null;
99
98
  return {
100
99
  name,
101
100
  has_manifest: Boolean(t),
@@ -236,9 +235,7 @@ server.registerTool(
236
235
  'Записывает обнаруженные команды в [tasks.X] секцию mise.toml + обновляет [vdx.success_path]. Используется после успешной верификации команд агентом.',
237
236
  inputSchema: {
238
237
  verbs: z.array(z.object({ name: z.string(), command: z.string() })),
239
- shared_infra: z
240
- .object({ provider: z.string(), precheck: z.boolean() })
241
- .optional(),
238
+ shared_infra: z.object({ provider: z.string(), precheck: z.boolean() }).optional(),
242
239
  notes: z.string().optional(),
243
240
  },
244
241
  },
@@ -92,17 +92,25 @@ function stateOf(h: PersonalHook, root: string | null, deps: PersonalHookDeps):
92
92
  let drift: string | null = null;
93
93
  if (have.length === 0 && command === null) drift = 'not in ~/.gitconfig';
94
94
  else if (command !== h.command) drift = `its command in ~/.gitconfig differs from the profile`;
95
- else if (events(h).some((e) => !have.includes(e))) drift = `not bound to ${events(h).filter((e) => !have.includes(e)).join(', ')}`;
95
+ else if (events(h).some((e) => !have.includes(e)))
96
+ drift = `not bound to ${events(h)
97
+ .filter((e) => !have.includes(e))
98
+ .join(', ')}`;
96
99
 
97
100
  let local: string | null = null;
98
101
  if (root !== null) {
99
- if (deps.git(['-C', root, 'config', '--local', '--get', `${key}.enabled`]) === 'false') local = 'off in this repository';
100
- else if (deps.git(['-C', root, 'config', '--local', '--get', `${key}.command`]) !== null) local = 'own command in this repository';
102
+ if (deps.git(['-C', root, 'config', '--local', '--get', `${key}.enabled`]) === 'false')
103
+ local = 'off in this repository';
104
+ else if (deps.git(['-C', root, 'config', '--local', '--get', `${key}.command`]) !== null)
105
+ local = 'own command in this repository';
101
106
  }
102
107
  return { hook: h, drift, local };
103
108
  }
104
109
 
105
- export function checkPersonalHooks(projectRoot: string | null, deps: PersonalHookDeps = defaultPersonalHookDeps()): CheckResult | null {
110
+ export function checkPersonalHooks(
111
+ projectRoot: string | null,
112
+ deps: PersonalHookDeps = defaultPersonalHookDeps(),
113
+ ): CheckResult | null {
106
114
  const hooks = applicableHooks(deps);
107
115
  if (!hooks) return null;
108
116
  const id = 'personal-hooks';
@@ -132,7 +140,10 @@ export function checkPersonalHooks(projectRoot: string | null, deps: PersonalHoo
132
140
  };
133
141
  }
134
142
 
135
- const missing = missingMachinePaths(hooks.map((h) => h.command), deps.home);
143
+ const missing = missingMachinePaths(
144
+ hooks.map((h) => h.command),
145
+ deps.home,
146
+ );
136
147
  if (missing.length > 0) {
137
148
  return {
138
149
  id,
package/src/predicates.ts CHANGED
@@ -132,9 +132,7 @@ export const REGISTRY: Record<string, PredicateFn> = {
132
132
 
133
133
  phpstan_level_at_least: (args, ctx) => {
134
134
  const text =
135
- readText(ctx, 'phpstan.neon') ||
136
- readText(ctx, 'phpstan.dist.neon') ||
137
- readText(ctx, 'phpstan.neon.dist');
135
+ readText(ctx, 'phpstan.neon') || readText(ctx, 'phpstan.dist.neon') || readText(ctx, 'phpstan.neon.dist');
138
136
  if (!text) return false;
139
137
  const m = text.match(/^\s*level:\s*(\d+|max)/m);
140
138
  if (!m || !m[1]) return false;
@@ -236,8 +234,7 @@ export const REGISTRY: Record<string, PredicateFn> = {
236
234
  }),
237
235
 
238
236
  /** L4 (library): the testing job runs across a matrix. */
239
- gha_test_matrix: (args, ctx) =>
240
- ciVerdict(ctx, () => [...checkingJobs(ctx, testPattern(args))].some((j) => j.matrix)),
237
+ gha_test_matrix: (args, ctx) => ciVerdict(ctx, () => [...checkingJobs(ctx, testPattern(args))].some((j) => j.matrix)),
241
238
 
242
239
  /** L4 (service): whatever CI ships on a push to main waits, via `needs:`, for a checking job. */
243
240
  gha_ship_needs_checks: (args, ctx) =>
package/src/publish.ts CHANGED
@@ -72,7 +72,10 @@ export function bumpSemver(current: string, kind: BumpKind): string {
72
72
 
73
73
  export function compareSemver(a: string, b: string): number {
74
74
  const norm = (s: string) =>
75
- s.replace(/^v/, '').split(/[.\-+]/).map((p) => parseInt(p, 10) || 0);
75
+ s
76
+ .replace(/^v/, '')
77
+ .split(/[.\-+]/)
78
+ .map((p) => parseInt(p, 10) || 0);
76
79
  const pa = norm(a);
77
80
  const pb = norm(b);
78
81
  for (let i = 0; i < Math.max(pa.length, pb.length); i++) {
@@ -249,9 +252,7 @@ export function planPublish(
249
252
  // Resolve effective stack: prefer subpackage stack if primary_subpackage is set
250
253
  // (meta-projects publishing a nested lib, e.g. vdx itself with primary_subpackage=cli).
251
254
  const subpkg = audit.primary_subpackage;
252
- const effectiveStack = subpkg
253
- ? stackForDir(path.join(opts.projectRoot, subpkg))
254
- : ctx.stack;
255
+ const effectiveStack = subpkg ? stackForDir(path.join(opts.projectRoot, subpkg)) : ctx.stack;
255
256
 
256
257
  if (effectiveStack !== 'node') {
257
258
  throw new Error(
@@ -543,7 +544,9 @@ export function executePublish(plan: PublishPlan, deps: PublishDeps = defaultPub
543
544
  try {
544
545
  deps.run('git', ['push', '--follow-tags'], plan.projectRoot);
545
546
  } catch {
546
- deps.log(`✗ git push failed — ${plan.packageName}@${plan.newVersion} is published and tagged here; push it: git push --follow-tags`);
547
+ deps.log(
548
+ `✗ git push failed — ${plan.packageName}@${plan.newVersion} is published and tagged here; push it: git push --follow-tags`,
549
+ );
547
550
  throw new Error('git push failed');
548
551
  }
549
552
  deps.log(`✓ pushed to ${push.upstream} with tag v${plan.newVersion}`);
@@ -599,7 +602,9 @@ export function renderPublishPlan(plan: PublishPlan): string {
599
602
  lines.push('## Pipeline (would execute on `vdx publish`)');
600
603
  lines.push('');
601
604
  if (fixable) {
602
- const fixes = plan.preflight.filter((c) => !c.ok && c.fix).map((c) => `\`${c.fix!.cmd} ${c.fix!.args.join(' ')}\``);
605
+ const fixes = plan.preflight
606
+ .filter((c) => !c.ok && c.fix)
607
+ .map((c) => `\`${c.fix!.cmd} ${c.fix!.args.join(' ')}\``);
603
608
  lines.push(`0. ${fixes.join(', ')} — at a terminal, then the pre-flight again`);
604
609
  }
605
610
  lines.push(`1. Set \`version\` in ${files} → \`${plan.newVersion}\``);
package/src/report.ts CHANGED
@@ -116,9 +116,7 @@ export function reportDoctorMarkdown(r: DoctorReport): string {
116
116
  const lines: string[] = [];
117
117
  lines.push('# vdx doctor report');
118
118
  lines.push('');
119
- lines.push(
120
- `**OK**: ${r.ok} **Warning**: ${r.warning} **Missing**: ${r.missing}`,
121
- );
119
+ lines.push(`**OK**: ${r.ok} **Warning**: ${r.warning} **Missing**: ${r.missing}`);
122
120
  lines.push('');
123
121
  lines.push('| Check | Status | Detail | Remedy |');
124
122
  lines.push('|-------|:------:|--------|--------|');
package/src/run.ts CHANGED
@@ -13,10 +13,7 @@ export type VerbResolveResult =
13
13
  detail?: string;
14
14
  };
15
15
 
16
- export function resolveLifecycleVerb(
17
- projectRoot: string,
18
- verb: string,
19
- ): VerbResolveResult {
16
+ export function resolveLifecycleVerb(projectRoot: string, verb: string): VerbResolveResult {
20
17
  const miseTomlPath = path.join(projectRoot, 'mise.toml');
21
18
  if (!fs.existsSync(miseTomlPath)) {
22
19
  return { ok: false, reason: 'no-mise-toml' };
@@ -42,8 +39,7 @@ export function renderResolveError(
42
39
  switch (res.reason) {
43
40
  case 'no-mise-toml':
44
41
  return (
45
- `vdx: no mise.toml in ${projectRoot}\n` +
46
- `hint: run \`vdx init\` to generate one, or define it manually.\n`
42
+ `vdx: no mise.toml in ${projectRoot}\n` + `hint: run \`vdx init\` to generate one, or define it manually.\n`
47
43
  );
48
44
  case 'parse-error':
49
45
  return `vdx: failed to parse mise.toml: ${res.detail ?? 'unknown error'}\n`;
package/src/scoring.ts CHANGED
@@ -95,15 +95,9 @@ function evalAxisFlags(axis: Axis, ctx: Ctx): LevelName {
95
95
  return achieved;
96
96
  }
97
97
 
98
- export function projectLevel(
99
- results: AxisResult[],
100
- rubric: Rubric,
101
- suppressed: Set<string>,
102
- ): LevelName {
98
+ export function projectLevel(results: AxisResult[], rubric: Rubric, suppressed: Set<string>): LevelName {
103
99
  const supportingThreshold = rubric.scoring.supporting_threshold ?? 0.8;
104
- const visible = results.filter(
105
- (r) => !suppressed.has(r.axis_id) && r.drift_kind !== 'excluded',
106
- );
100
+ const visible = results.filter((r) => !suppressed.has(r.axis_id) && r.drift_kind !== 'excluded');
107
101
  const critical = visible.filter((r) => r.class === 'critical');
108
102
  const supporting = visible.filter((r) => r.class === 'supporting');
109
103
 
package/src/vocabulary.ts CHANGED
@@ -39,7 +39,11 @@ export function runnerCalls(command: string): string[] {
39
39
  const toks = tokenize(raw.trim());
40
40
  let i = 0;
41
41
  // `FOO=1 npm test`, `exec npm test`, `npx --no -- vdx test`
42
- while (i < toks.length && (/^[A-Za-z_][A-Za-z0-9_]*=/.test(toks[i]!) || ['exec', 'time', 'command'].includes(toks[i]!))) i++;
42
+ while (
43
+ i < toks.length &&
44
+ (/^[A-Za-z_][A-Za-z0-9_]*=/.test(toks[i]!) || ['exec', 'time', 'command'].includes(toks[i]!))
45
+ )
46
+ i++;
43
47
  const head = toks[i];
44
48
  if (!head) continue;
45
49
  const runner = head.split('/').pop()!;
@@ -116,7 +120,8 @@ export function taskChildren(ctx: Ctx, name: string): string[] {
116
120
  const mise = readToml(ctx, 'mise.toml');
117
121
  const task = mise?.tasks?.[name];
118
122
  if (task && typeof task === 'object') {
119
- if (Array.isArray(task.depends)) out.push(...task.depends.filter((d: unknown): d is string => typeof d === 'string'));
123
+ if (Array.isArray(task.depends))
124
+ out.push(...task.depends.filter((d: unknown): d is string => typeof d === 'string'));
120
125
  const runs = Array.isArray(task.run) ? task.run : [task.run];
121
126
  for (const r of runs) if (typeof r === 'string') out.push(...runnerCalls(r));
122
127
  }