@oml/cli 0.14.15 → 0.14.17

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.
@@ -34,7 +34,7 @@ type ServerStatePaths = {
34
34
  type ServerLockState = {
35
35
  pid: number;
36
36
  port: number;
37
- owner?: 'daemon' | 'extension';
37
+ owner?: 'cli' | 'extension';
38
38
  workspaceRoot?: string;
39
39
  };
40
40
 
@@ -78,7 +78,7 @@ function parseServerLock(raw: string): ServerLockState | undefined {
78
78
  if (pidInt <= 0 || portInt <= 0 || portInt > 65535) {
79
79
  return undefined;
80
80
  }
81
- const owner = parsed.owner === 'daemon' || parsed.owner === 'extension'
81
+ const owner = parsed.owner === 'cli' || parsed.owner === 'extension'
82
82
  ? parsed.owner
83
83
  : undefined;
84
84
  const workspaceRoot = typeof parsed.workspaceRoot === 'string' && parsed.workspaceRoot.trim().length > 0
@@ -105,7 +105,7 @@ async function readServerLock(lockFile: string): Promise<ServerLockState | undef
105
105
  type RunningServer = {
106
106
  pid: number;
107
107
  port: number;
108
- owner: 'daemon' | 'extension' | 'unknown';
108
+ owner: 'cli' | 'extension' | 'unknown';
109
109
  workspaceRoot?: string;
110
110
  lockFile: string;
111
111
  };
@@ -257,7 +257,7 @@ function normalizeStartPort(value: number | string | undefined): number {
257
257
  return intPort;
258
258
  }
259
259
 
260
- async function inspectListeningProcess(port: number): Promise<string> {
260
+ async function inspectListeningProcess(port: number): Promise<string | undefined> {
261
261
  const args = ['-nP', `-iTCP:${port}`, '-sTCP:LISTEN'];
262
262
  try {
263
263
  const { stdout } = await execFileAsync('lsof', args);
@@ -265,7 +265,7 @@ async function inspectListeningProcess(port: number): Promise<string> {
265
265
  } catch (error) {
266
266
  const failed = error as NodeJS.ErrnoException & { stdout?: string };
267
267
  if (failed?.code === 'ENOENT') {
268
- throw new Error("Cannot inspect ports because 'lsof' is not installed or not on PATH.");
268
+ return undefined;
269
269
  }
270
270
  return typeof failed?.stdout === 'string' ? failed.stdout.trim() : '';
271
271
  }
@@ -392,7 +392,7 @@ export async function serverStopAction(): Promise<void> {
392
392
  return;
393
393
  }
394
394
  const owner = state.owner ?? 'unknown';
395
- if (owner !== 'daemon') {
395
+ if (owner !== 'cli') {
396
396
  process.stdout.write(`Server is running (pid ${state.pid}, port ${state.port}) and managed by ${owner}; not stopping.\n`);
397
397
  return;
398
398
  }
@@ -417,6 +417,11 @@ export async function serverStatusAction(): Promise<void> {
417
417
  return;
418
418
  }
419
419
  const output = await inspectListeningProcess(state.port);
420
+ if (output === undefined) {
421
+ const owner = state.owner ?? 'unknown';
422
+ process.stdout.write(`Server is running on http://${DEFAULT_HOST}:${state.port} (pid ${state.pid}, owner ${owner}).\n`);
423
+ return;
424
+ }
420
425
  if (!output) {
421
426
  process.stdout.write(`No listening process found on port ${state.port}.\n`);
422
427
  return;
@@ -3,6 +3,7 @@
3
3
  import chalk from 'chalk';
4
4
  import { failCli } from '../cli-error.js';
5
5
  import { formatDuration } from '../util.js';
6
+ import { printLintDiagnostics, type LintProblem } from './lint.js';
6
7
  import { restPost } from './server/rest.js';
7
8
 
8
9
  export type ValidateOptions = {
@@ -16,25 +17,76 @@ export const validateAction = async (opts: ValidateOptions): Promise<void> => {
16
17
  filesChecked: number;
17
18
  errors: number;
18
19
  warnings: number;
20
+ failingItems?: number;
21
+ details?: string[];
22
+ validationProblems?: Array<{
23
+ modelUri: string;
24
+ element: string;
25
+ property: string;
26
+ message: string;
27
+ }>;
19
28
  elapsedMs?: number;
29
+ problems?: LintProblem[];
20
30
  error?: string;
21
31
  }>('/v0/validate', {}, opts.authToken);
22
32
 
23
- if (!result.success) {
24
- failCli(chalk.red(result.error?.trim() || 'validate failed.'));
25
- }
26
33
  if (result.filesChecked === 0) {
27
34
  console.log(chalk.yellow('No markdown/table-editor targets found in server workspace.'));
28
35
  return;
29
36
  }
37
+ printLintDiagnostics({
38
+ success: false,
39
+ filesChecked: result.filesChecked,
40
+ errors: result.errors,
41
+ warnings: result.warnings,
42
+ elapsedMs: result.elapsedMs,
43
+ problems: result.problems,
44
+ });
45
+ const validationProblems = Array.isArray(result.validationProblems) ? result.validationProblems : [];
46
+ if (validationProblems.length > 0) {
47
+ const groups = new Map<string, Array<{ element: string; property: string; message: string }>>();
48
+ for (const problem of validationProblems) {
49
+ const key = String(problem.modelUri ?? '').trim() || '<unknown>';
50
+ const existing = groups.get(key) ?? [];
51
+ existing.push({
52
+ element: String(problem.element ?? '-'),
53
+ property: String(problem.property ?? '-'),
54
+ message: String(problem.message ?? ''),
55
+ });
56
+ groups.set(key, existing);
57
+ }
58
+ for (const [modelUri, issues] of groups.entries()) {
59
+ console.log(chalk.red(`Model: ${modelUri}`));
60
+ for (const issue of issues) {
61
+ console.log(chalk.red(` element: ${issue.element}`));
62
+ console.log(chalk.red(` property: ${issue.property}`));
63
+ console.log(chalk.red(` message: ${issue.message}`));
64
+ }
65
+ }
66
+ } else {
67
+ const details = Array.isArray(result.details) ? result.details : [];
68
+ for (const detail of details) {
69
+ if (String(detail).trim().length > 0) {
70
+ console.log(chalk.red(String(detail)));
71
+ }
72
+ }
73
+ }
30
74
  const validateElapsedMs = typeof result.elapsedMs === 'number' && Number.isFinite(result.elapsedMs) && result.elapsedMs >= 0
31
75
  ? result.elapsedMs
32
76
  : Date.now() - startedAt;
33
77
  if (result.errors > 0) {
78
+ const failingItems = Number(result.failingItems ?? 0);
79
+ if (failingItems > 0) {
80
+ failCli(chalk.red(`validate: ${result.filesChecked} table-editor block(s) scanned [${formatDuration(validateElapsedMs)}]; ${failingItems} failing block(s), ${result.errors} error(s), ${result.warnings} warning(s)`));
81
+ }
34
82
  failCli(chalk.red(`validate: ${result.filesChecked} item(s) checked with ${result.errors} error(s) and ${result.warnings} warning(s). [${formatDuration(validateElapsedMs)}]`));
35
83
  }
36
84
  if (result.warnings > 0) {
85
+ const failingItems = Number(result.failingItems ?? 0);
86
+ if (failingItems > 0) {
87
+ failCli(chalk.yellow(`validate: ${result.filesChecked} table-editor block(s) scanned [${formatDuration(validateElapsedMs)}]; ${failingItems} failing block(s), ${result.errors} error(s), ${result.warnings} warning(s)`));
88
+ }
37
89
  failCli(chalk.yellow(`validate: ${result.filesChecked} item(s) checked with ${result.warnings} warning(s). [${formatDuration(validateElapsedMs)}]`));
38
90
  }
39
- console.log(chalk.green(`validate: ${result.filesChecked} item(s) checked. [${formatDuration(validateElapsedMs)}]`));
91
+ console.log(chalk.green(`validate: ${result.filesChecked} table-editor block(s) scanned [${formatDuration(validateElapsedMs)}]`));
40
92
  };