@oml/cli 0.14.17 → 0.15.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.
@@ -17,12 +17,19 @@ const SHUTDOWN_TIMEOUT_MS = 3000;
17
17
  const POLL_INTERVAL_MS = 100;
18
18
  const execFileAsync = promisify(execFile);
19
19
 
20
+ type EntitlementCache = {
21
+ expiry: number;
22
+ featureIds: string[];
23
+ token?: string;
24
+ };
25
+
20
26
  type StartServerOptions = {
21
27
  port?: number | string;
22
28
  workspace?: string;
23
29
  auth?: {
24
30
  accessToken: string;
25
31
  };
32
+ entitlementCache?: EntitlementCache;
26
33
  };
27
34
 
28
35
  type ServerStatePaths = {
@@ -63,6 +70,7 @@ function getServerStatePaths(workspace?: string): ServerStatePaths {
63
70
 
64
71
  async function cleanupStateFile(paths: ServerStatePaths): Promise<void> {
65
72
  await fs.rm(paths.lockFile, { force: true });
73
+ await fs.rm(paths.dir, { recursive: true, force: true });
66
74
  }
67
75
 
68
76
  function parseServerLock(raw: string): ServerLockState | undefined {
@@ -128,6 +136,7 @@ async function listRunningServers(): Promise<RunningServer[]> {
128
136
  }
129
137
  if (!isProcessAlive(state.pid)) {
130
138
  await fs.rm(lockFile, { force: true });
139
+ await fs.rm(path.dirname(lockFile), { recursive: true, force: true });
131
140
  continue;
132
141
  }
133
142
  servers.push({
@@ -279,6 +288,7 @@ function spawnServerProcess(
279
288
  options: {
280
289
  workspace?: string;
281
290
  auth?: { accessToken: string };
291
+ entitlementCache?: EntitlementCache;
282
292
  },
283
293
  ): ChildProcess {
284
294
  const args = [serverMainScript, `--port=${port}`];
@@ -289,6 +299,13 @@ function spawnServerProcess(
289
299
  if (options.auth?.accessToken) {
290
300
  args.push(`--token=${options.auth.accessToken}`);
291
301
  }
302
+ if (options.entitlementCache) {
303
+ args.push(`--entitlement-expiry=${options.entitlementCache.expiry}`);
304
+ args.push(`--entitlement-features=${JSON.stringify(options.entitlementCache.featureIds)}`);
305
+ if (options.entitlementCache.token) {
306
+ args.push(`--entitlement-token=${options.entitlementCache.token}`);
307
+ }
308
+ }
292
309
 
293
310
  return spawn(process.execPath, args, {
294
311
  detached,
@@ -352,6 +369,7 @@ async function serverStartDetached(
352
369
  const child = spawnServerProcess(serverMainScript, port, true, 'ignore', {
353
370
  workspace: options.workspace,
354
371
  auth: options.auth,
372
+ entitlementCache: options.entitlementCache,
355
373
  });
356
374
  if (!child.pid) {
357
375
  throw new Error('Failed to launch server process.');
@@ -449,13 +467,10 @@ export type RunServerOptions = {
449
467
  auth: {
450
468
  accessToken: string;
451
469
  };
470
+ entitlementCache?: EntitlementCache;
471
+ deviceId?: string;
452
472
  };
453
473
 
454
- function sendLspNotification(childStdin: NodeJS.WritableStream, method: string, params: unknown): void {
455
- const message = JSON.stringify({ jsonrpc: '2.0', method, params });
456
- const header = `Content-Length: ${Buffer.byteLength(message, 'utf-8')}\r\n\r\n`;
457
- childStdin.write(header + message, 'utf-8');
458
- }
459
474
 
460
475
  export async function serverRunAction(portArg: number | string | undefined, options: RunServerOptions): Promise<void> {
461
476
  if (process.env.OML_PLATFORM_API_KEY?.trim()) {
@@ -486,13 +501,23 @@ export async function serverRunAction(portArg: number | string | undefined, opti
486
501
  args.push(`--workspace=${path.resolve(options.workspace)}`);
487
502
  }
488
503
  args.push(`--token=${options.auth.accessToken}`);
504
+ if (options.entitlementCache) {
505
+ args.push(`--entitlement-expiry=${options.entitlementCache.expiry}`);
506
+ args.push(`--entitlement-features=${JSON.stringify(options.entitlementCache.featureIds)}`);
507
+ if (options.entitlementCache.token) {
508
+ args.push(`--entitlement-token=${options.entitlementCache.token}`);
509
+ }
510
+ }
511
+ if (options.deviceId) {
512
+ args.push(`--device-id=${options.deviceId}`);
513
+ }
489
514
 
490
515
  const child = spawn(process.execPath, args, {
491
516
  detached: false,
492
- stdio: ['pipe', 'inherit', 'inherit'],
517
+ stdio: ['ignore', 'inherit', 'inherit', 'ipc'],
493
518
  });
494
519
 
495
- if (!child.pid || !child.stdin) {
520
+ if (!child.pid) {
496
521
  throw new Error('Failed to launch server process.');
497
522
  }
498
523
 
@@ -510,7 +535,17 @@ export async function serverRunAction(portArg: number | string | undefined, opti
510
535
  process.stdout.write(`OML server running on http://${DEFAULT_HOST}:${state.port} (pid ${state.pid})\n`);
511
536
  process.stdout.write('Press Ctrl-C to stop.\n');
512
537
 
513
- const stdin = child.stdin;
538
+ child.on('message', (msg: unknown) => {
539
+ if (msg && typeof msg === 'object' && (msg as Record<string, unknown>).type === 'entitlementsCached') {
540
+ const { expiry, featureIds, entitlementsToken } = msg as { expiry?: unknown; featureIds?: unknown; entitlementsToken?: unknown };
541
+ const expiryNum = Number(expiry);
542
+ const token = typeof entitlementsToken === 'string' ? entitlementsToken : undefined;
543
+ if (Number.isFinite(expiryNum) && Array.isArray(featureIds) && featureIds.every((x) => typeof x === 'string')) {
544
+ void options.authService.saveEntitlementCache(expiryNum, featureIds as string[], token);
545
+ }
546
+ }
547
+ });
548
+
514
549
  const REFRESH_INTERVAL_MS = 60 * 60 * 1000;
515
550
  const REFRESH_RETRY_BASE_MS = 15_000;
516
551
  const REFRESH_RETRY_MAX_MS = 5 * 60 * 1000;
@@ -538,7 +573,7 @@ export async function serverRunAction(portArg: number | string | undefined, opti
538
573
  const snapshot = await options.authService.getServerAuthSnapshot();
539
574
  if (snapshot.accessToken !== currentAccessToken) {
540
575
  currentAccessToken = snapshot.accessToken;
541
- sendLspNotification(stdin, '$/tokenRefreshed', { accessToken: snapshot.accessToken });
576
+ child.send({ type: 'tokenRefreshed', accessToken: snapshot.accessToken });
542
577
  }
543
578
  refreshFailureCount = 0;
544
579
  scheduleRefresh(REFRESH_INTERVAL_MS);
@@ -31,7 +31,7 @@ export const validateAction = async (opts: ValidateOptions): Promise<void> => {
31
31
  }>('/v0/validate', {}, opts.authToken);
32
32
 
33
33
  if (result.filesChecked === 0) {
34
- console.log(chalk.yellow('No markdown/table-editor targets found in server workspace.'));
34
+ console.log(chalk.yellow('No SHACL validation targets found in server workspace.'));
35
35
  return;
36
36
  }
37
37
  printLintDiagnostics({
@@ -77,16 +77,18 @@ export const validateAction = async (opts: ValidateOptions): Promise<void> => {
77
77
  if (result.errors > 0) {
78
78
  const failingItems = Number(result.failingItems ?? 0);
79
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)`));
80
+ failCli(chalk.red(`validate: ${result.filesChecked} SHACL target(s) scanned [${formatDuration(validateElapsedMs)}]; ${failingItems} failing block(s), ${result.errors} error(s), ${result.warnings} warning(s)`));
81
81
  }
82
- failCli(chalk.red(`validate: ${result.filesChecked} item(s) checked with ${result.errors} error(s) and ${result.warnings} warning(s). [${formatDuration(validateElapsedMs)}]`));
82
+ failCli(chalk.red(`validate: ${result.filesChecked} SHACL target(s) checked with ${result.errors} error(s) and ${result.warnings} warning(s). [${formatDuration(validateElapsedMs)}]`));
83
83
  }
84
84
  if (result.warnings > 0) {
85
85
  const failingItems = Number(result.failingItems ?? 0);
86
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)`));
87
+ console.warn(chalk.yellow(`validate: ${result.filesChecked} SHACL target(s) scanned [${formatDuration(validateElapsedMs)}]; ${failingItems} failing block(s), ${result.errors} error(s), ${result.warnings} warning(s)`));
88
+ } else {
89
+ console.warn(chalk.yellow(`validate: ${result.filesChecked} SHACL target(s) checked with ${result.warnings} warning(s). [${formatDuration(validateElapsedMs)}]`));
88
90
  }
89
- failCli(chalk.yellow(`validate: ${result.filesChecked} item(s) checked with ${result.warnings} warning(s). [${formatDuration(validateElapsedMs)}]`));
91
+ return;
90
92
  }
91
- console.log(chalk.green(`validate: ${result.filesChecked} table-editor block(s) scanned [${formatDuration(validateElapsedMs)}]`));
93
+ console.log(chalk.green(`validate: ${result.filesChecked} SHACL target(s) scanned [${formatDuration(validateElapsedMs)}]`));
92
94
  };